refactor atheros system code - also add support for the reset button (sends netlink...
[openwrt/openwrt.git] / target / linux / atheros-2.6 / files / arch / mips / atheros / board.c
1 /*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
7 * Copyright (C) 2006 FON Technology, SL.
8 * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
9 * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
10 */
11
12 /*
13 * Platform devices for Atheros SoCs
14 */
15
16 #include <linux/autoconf.h>
17 #include <linux/init.h>
18 #include <linux/module.h>
19 #include <linux/types.h>
20 #include <linux/string.h>
21 #include <linux/platform_device.h>
22 #include <linux/kernel.h>
23 #include <linux/serial.h>
24 #include <linux/serial_core.h>
25 #include <asm/bootinfo.h>
26 #include <asm/irq_cpu.h>
27 #include <asm/io.h>
28 #include "ar531x.h"
29
30 char *board_config, *radio_config;
31
32 static u8 *find_board_config(char *flash_limit)
33 {
34 char *addr;
35 int found = 0;
36
37 for (addr = (char *) (flash_limit - 0x1000);
38 addr >= (char *) (flash_limit - 0x30000);
39 addr -= 0x1000) {
40
41 if ( *(int *)addr == 0x35333131) {
42 /* config magic found */
43 found = 1;
44 break;
45 }
46 }
47
48 if (!found) {
49 printk("WARNING: No board configuration data found!\n");
50 addr = NULL;
51 }
52
53 return addr;
54 }
55
56 static u8 *find_radio_config(char *flash_limit, char *board_config)
57 {
58 int dataFound;
59 u32 radio_config;
60
61 /*
62 * Now find the start of Radio Configuration data, using heuristics:
63 * Search forward from Board Configuration data by 0x1000 bytes
64 * at a time until we find non-0xffffffff.
65 */
66 dataFound = 0;
67 for (radio_config = (u32) board_config + 0x1000;
68 (radio_config < (u32) flash_limit);
69 radio_config += 0x1000) {
70 if (*(int *)radio_config != 0xffffffff) {
71 dataFound = 1;
72 break;
73 }
74 }
75
76 #ifdef CONFIG_ATHEROS_AR5315
77 if (!dataFound) { /* AR2316 relocates radio config to new location */
78 for (radio_config = (u32) board_config + 0xf8;
79 (radio_config < (u32) flash_limit - 0x1000 + 0xf8);
80 radio_config += 0x1000) {
81 if (*(int *)radio_config != 0xffffffff) {
82 dataFound = 1;
83 break;
84 }
85 }
86 }
87 #endif
88
89 if (!dataFound) {
90 printk("Could not find Radio Configuration data\n");
91 radio_config = 0;
92 }
93
94 return (u8 *) radio_config;
95 }
96
97 int __init ar531x_find_config(char *flash_limit)
98 {
99 unsigned int rcfg_size;
100 char *bcfg, *rcfg;
101
102 /* Copy the board and radio data to RAM, because with the new
103 * spiflash driver, accessing the mapped memory directly is no
104 * longer safe */
105
106 bcfg = find_board_config(flash_limit);
107 if (!bcfg)
108 return -ENODEV;
109
110 board_config = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL);
111 memcpy(board_config, bcfg, 0x100);
112
113 /* Radio config starts 0x100 bytes after board config, regardless
114 * of what the physical layout on the flash chip looks like */
115
116 rcfg = find_radio_config(flash_limit, bcfg);
117 if (!rcfg)
118 return -ENODEV;
119
120 radio_config = board_config + 0x100 + ((rcfg - bcfg) & 0xfff);
121 printk("Radio config found at offset 0x%x(0x%x)\n", rcfg - bcfg, radio_config - board_config);
122 rcfg_size = BOARD_CONFIG_BUFSZ - ((rcfg - bcfg) & (BOARD_CONFIG_BUFSZ - 1));
123 memcpy(radio_config, rcfg, rcfg_size);
124
125 return 0;
126 }
127
128 void __init serial_setup(unsigned long mapbase, unsigned int uartclk)
129 {
130 struct uart_port s;
131
132 memset(&s, 0, sizeof(s));
133
134 s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
135 s.iotype = UPIO_MEM;
136 s.irq = AR531X_MISC_IRQ_UART0;
137 s.regshift = 2;
138 s.mapbase = mapbase;
139 s.uartclk = uartclk;
140 s.membase = (void __iomem *)s.mapbase;
141
142 early_serial_setup(&s);
143 }
144
145 void __init plat_mem_setup(void)
146 {
147 DO_AR5312(ar5312_plat_setup();)
148 DO_AR5315(ar5315_plat_setup();)
149
150 /* Disable data watchpoints */
151 write_c0_watchlo0(0);
152 }
153
154 const char *get_system_type(void)
155 {
156 switch (mips_machtype) {
157 #ifdef CONFIG_ATHEROS_AR5312
158 case MACH_ATHEROS_AR5312:
159 return "Atheros AR5312";
160
161 case MACH_ATHEROS_AR2312:
162 return "Atheros AR2312";
163
164 case MACH_ATHEROS_AR2313:
165 return "Atheros AR2313";
166 #endif
167 #ifdef CONFIG_ATHEROS_AR5315
168 case MACH_ATHEROS_AR2315:
169 return "Atheros AR2315";
170 case MACH_ATHEROS_AR2316:
171 return "Atheros AR2316";
172 case MACH_ATHEROS_AR2317:
173 return "Atheros AR2317";
174 case MACH_ATHEROS_AR2318:
175 return "Atheros AR2318";
176 #endif
177 }
178 return "Atheros (unknown)";
179 }
180
181 void __init plat_timer_setup(struct irqaction *irq)
182 {
183 unsigned int count;
184
185 /* Usually irq is timer_irqaction (timer_interrupt) */
186 setup_irq(AR531X_IRQ_CPU_CLOCK, irq);
187
188 /* to generate the first CPU timer interrupt */
189 count = read_c0_count();
190 write_c0_compare(count + 1000);
191 }
192
193 asmlinkage void plat_irq_dispatch(void)
194 {
195 DO_AR5312(ar5312_irq_dispatch();)
196 DO_AR5315(ar5315_irq_dispatch();)
197 }
198
199 void __init arch_init_irq(void)
200 {
201 clear_c0_status(ST0_IM);
202 mips_cpu_irq_init();
203
204 /* Initialize interrupt controllers */
205 DO_AR5312(ar5312_misc_intr_init(AR531X_MISC_IRQ_BASE);)
206 DO_AR5315(ar5315_misc_intr_init(AR531X_MISC_IRQ_BASE);)
207 }