[atheros]: Add initial kernel 2.6.28 support for atheros target.
[openwrt.git] / target / linux / atheros / files-2.6.28 / 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 <linux/random.h>
26 #include <asm/bootinfo.h>
27 #include <asm/irq_cpu.h>
28 #include <asm/io.h>
29 #include <ar531x.h>
30
31 char *board_config = NULL;
32 char *radio_config = NULL;
33 int broken_boarddata = 0;
34
35 extern int early_serial_setup(struct uart_port *port);
36
37 static inline bool
38 check_radio_magic(unsigned char *addr)
39 {
40         addr += 0x7a; /* offset for flash magic */
41         if ((addr[0] == 0x5a) && (addr[1] == 0xa5)) {
42                 return 1;
43         }
44         return 0;
45 }
46
47 static inline bool
48 check_board_data(unsigned char *flash_limit, unsigned char *addr, bool broken)
49 {
50         /* config magic found */
51         if ( *(int *)addr == 0x35333131)
52                 return 1;
53
54         if (!broken)
55                 return 0;
56
57         if (check_radio_magic(addr + 0xf8))
58                 radio_config = addr + 0xf8;
59         if ((addr < flash_limit + 0x10000) &&
60              check_radio_magic(addr + 0x10000))
61                 radio_config = addr + 0x10000;
62
63         if (radio_config) {
64                 /* broken board data detected, use radio data to find the offset,
65                  * user will fix this */
66                 broken_boarddata = 1;
67                 return 1;
68         }
69         return 0;
70 }
71
72 static u8 *find_board_config(char *flash_limit, bool broken)
73 {
74         char *addr;
75         int found = 0;
76
77         for (addr = (char *) (flash_limit - 0x1000);
78                 addr >= (char *) (flash_limit - 0x30000);
79                 addr -= 0x1000) {
80
81                 if (check_board_data(flash_limit, addr, broken)) {
82                         found = 1;
83                         break;
84                 }
85         }
86
87         if (!found)
88                 addr = NULL;
89
90         return addr;
91 }
92
93 static u8 *find_radio_config(char *flash_limit, char *board_config)
94 {
95         int dataFound;
96         char *radio_config;
97
98         /*
99          * Now find the start of Radio Configuration data, using heuristics:
100          * Search forward from Board Configuration data by 0x1000 bytes
101          * at a time until we find non-0xffffffff.
102          */
103         dataFound = 0;
104         for (radio_config = board_config + 0x1000;
105              (radio_config < flash_limit);
106              radio_config += 0x1000) {
107                 if ((*(u32 *)radio_config != 0xffffffff) &&
108                     check_radio_magic(radio_config)) {
109                         dataFound = 1;
110                         break;
111                 }
112         }
113
114 #ifdef CONFIG_ATHEROS_AR5315
115         if (!dataFound) { /* AR2316 relocates radio config to new location */
116             for (radio_config = board_config + 0xf8;
117                 (radio_config < flash_limit - 0x1000 + 0xf8);
118                          radio_config += 0x1000) {
119                         if ((*(u32 *)radio_config != 0xffffffff) &&
120                                 check_radio_magic(radio_config)) {
121                                 dataFound = 1;
122                                 break;
123                         }
124             }
125         }
126 #endif
127
128         if (!dataFound) {
129                 printk("Could not find Radio Configuration data\n");
130                 radio_config = 0;
131         }
132
133         return (u8 *) radio_config;
134 }
135
136 int __init ar531x_find_config(char *flash_limit)
137 {
138         struct ar531x_boarddata *bd;
139         unsigned int rcfg_size;
140         char *bcfg, *rcfg;
141
142         /* Copy the board and radio data to RAM, because with the new
143          * spiflash driver, accessing the mapped memory directly is no
144          * longer safe */
145
146         bcfg = find_board_config(flash_limit, false);
147         if (!bcfg)
148                 bcfg = find_board_config(flash_limit, true);
149         if (!bcfg) {
150                 printk("WARNING: No board configuration data found!\n");
151                 return -ENODEV;
152         }
153
154         board_config = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL);
155         memcpy(board_config, bcfg, 0x100);
156         if (broken_boarddata) {
157                 printk("WARNING: broken board data detected\n");
158                 bd = (struct ar531x_boarddata *)board_config;
159                 if (!memcmp(bd->enet0Mac, "\x00\x00\x00\x00\x00\x00", 6)) {
160                         printk("Fixing up empty mac addresses\n");
161                         bd->enet0Mac[1] = 0x13;
162                         bd->enet0Mac[2] = 0x37;
163                         get_random_bytes(bd->enet0Mac + 3, 3);
164                         bd->wlan0Mac[1] = 0x13;
165                         bd->wlan0Mac[2] = 0x37;
166                         get_random_bytes(bd->wlan0Mac + 3, 3);
167                 }
168         }
169
170
171         /* Radio config starts 0x100 bytes after board config, regardless
172          * of what the physical layout on the flash chip looks like */
173
174         if (radio_config)
175                 rcfg = radio_config;
176         else
177                 rcfg = find_radio_config(flash_limit, bcfg);
178
179         if (!rcfg)
180                 return -ENODEV;
181
182         radio_config = board_config + 0x100 + ((rcfg - bcfg) & 0xfff);
183         printk("Radio config found at offset 0x%x(0x%x)\n", rcfg - bcfg, radio_config - board_config);
184         rcfg_size = BOARD_CONFIG_BUFSZ - (radio_config - board_config);
185         memcpy(radio_config, rcfg, rcfg_size);
186
187         return 0;
188 }
189
190 void __init serial_setup(unsigned long mapbase, unsigned int uartclk)
191 {
192         struct uart_port s;
193
194         memset(&s, 0, sizeof(s));
195
196         s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
197         s.iotype = UPIO_MEM;
198         s.irq = AR531X_MISC_IRQ_UART0;
199         s.regshift = 2;
200         s.mapbase = mapbase;
201         s.uartclk = uartclk;
202         s.membase = (void __iomem *)s.mapbase;
203
204         early_serial_setup(&s);
205 }
206
207 void __init plat_mem_setup(void)
208 {
209         DO_AR5312(ar5312_plat_setup();)
210         DO_AR5315(ar5315_plat_setup();)
211
212         /* Disable data watchpoints */
213         write_c0_watchlo0(0);
214 }
215
216 const char *get_system_type(void)
217 {
218         switch (mips_machtype) {
219 #ifdef CONFIG_ATHEROS_AR5312
220         case MACH_ATHEROS_AR5312:
221                 return "Atheros AR5312";
222
223         case MACH_ATHEROS_AR2312:
224                 return "Atheros AR2312";
225
226         case MACH_ATHEROS_AR2313:
227                 return "Atheros AR2313";
228 #endif
229 #ifdef CONFIG_ATHEROS_AR5315
230         case MACH_ATHEROS_AR2315:
231                 return "Atheros AR2315";
232         case MACH_ATHEROS_AR2316:
233                 return "Atheros AR2316";
234         case MACH_ATHEROS_AR2317:
235                 return "Atheros AR2317";
236         case MACH_ATHEROS_AR2318:
237                 return "Atheros AR2318";
238 #endif
239         }
240         return "Atheros (unknown)";
241 }
242
243 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
244 void __init plat_timer_setup(struct irqaction *irq)
245 {
246         unsigned int count;
247
248         /* Usually irq is timer_irqaction (timer_interrupt) */
249         setup_irq(AR531X_IRQ_CPU_CLOCK, irq);
250
251         /* to generate the first CPU timer interrupt */
252         count = read_c0_count();
253         write_c0_compare(count + 1000);
254 }
255 #endif
256
257 asmlinkage void plat_irq_dispatch(void)
258 {
259         DO_AR5312(ar5312_irq_dispatch();)
260         DO_AR5315(ar5315_irq_dispatch();)
261 }
262
263 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
264 void (*board_time_init)(void);
265 void __init plat_time_init(void) {
266     board_time_init();
267 }
268 #endif
269
270 void __init arch_init_irq(void)
271 {
272         clear_c0_status(ST0_IM);
273         mips_cpu_irq_init();
274
275         /* Initialize interrupt controllers */
276         DO_AR5312(ar5312_misc_intr_init(AR531X_MISC_IRQ_BASE);)
277         DO_AR5315(ar5315_misc_intr_init(AR531X_MISC_IRQ_BASE);)
278 }
279
280 static int __init ar531x_register_gpiodev(void)
281 {
282         static struct resource res = {
283                 .start = 0xFFFFFFFF,
284         };
285         struct platform_device *pdev;
286
287         printk(KERN_INFO "ar531x: Registering GPIODEV device\n");
288
289         pdev = platform_device_register_simple("GPIODEV", 0, &res, 1);
290
291         if (!pdev) {
292                 printk(KERN_ERR "ar531x: GPIODEV init failed\n");
293                 return -ENODEV;
294         }
295
296         return 0;
297 }
298
299 device_initcall(ar531x_register_gpiodev);