major cleanup of the ar531x code, improved hardware detection and support for multipl...
[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/io.h>
27 #include "ar531x.h"
28
29 char *board_config, *radio_config;
30
31 static u8 *find_board_config(char *flash_limit)
32 {
33         char *addr;
34         int found = 0;
35
36         for (addr = (char *) (flash_limit - 0x1000);
37                 addr >= (char *) (flash_limit - 0x30000);
38                 addr -= 0x1000) {
39
40                 if ( *(int *)addr == 0x35333131) {
41                         /* config magic found */
42                         found = 1;
43                         break;
44                 }
45         }
46
47         if (!found) {
48                 printk("WARNING: No board configuration data found!\n");
49                 addr = NULL;
50         }
51         
52         return addr;
53 }
54
55 static u8 *find_radio_config(char *flash_limit, char *board_config)
56 {
57         int dataFound;
58         u32 radio_config;
59         
60         /* 
61          * Now find the start of Radio Configuration data, using heuristics:
62          * Search forward from Board Configuration data by 0x1000 bytes
63          * at a time until we find non-0xffffffff.
64          */
65         dataFound = 0;
66         for (radio_config = (u32) board_config + 0x1000;
67              (radio_config < (u32) flash_limit);
68              radio_config += 0x1000) {
69                 if (*(int *)radio_config != 0xffffffff) {
70                         dataFound = 1;
71                         break;
72                 }
73         }
74
75 #ifdef CONFIG_ATHEROS_AR5315
76         if (!dataFound) { /* AR2316 relocates radio config to new location */
77             for (radio_config = (u32) board_config + 0xf8;
78                 (radio_config < (u32) flash_limit - 0x1000 + 0xf8);
79                          radio_config += 0x1000) {
80                         if (*(int *)radio_config != 0xffffffff) {
81                                 dataFound = 1;
82                                 break;
83                         }
84             }
85         }
86 #endif
87
88         if (!dataFound) {
89                 printk("Could not find Radio Configuration data\n");
90                 radio_config = 0;
91         }
92
93         return (u8 *) radio_config;
94 }
95
96 int __init ar531x_find_config(char *flash_limit)
97 {
98         unsigned int rcfg_size;
99         char *bcfg, *rcfg;
100
101         /* Copy the board and radio data to RAM, because with the new
102          * spiflash driver, accessing the mapped memory directly is no
103          * longer safe */
104
105         bcfg = find_board_config(flash_limit);
106         if (!bcfg)
107                 return -ENODEV;
108
109         board_config = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL);
110         memcpy(board_config, bcfg, 0x100);
111
112         /* Radio config starts 0x100 bytes after board config, regardless
113          * of what the physical layout on the flash chip looks like */
114
115         rcfg = find_radio_config(flash_limit, bcfg);
116         if (!rcfg)
117                 return -ENODEV;
118
119         radio_config = board_config + 0x100 + ((rcfg - bcfg) & 0xfff);
120         printk("Radio config found at offset 0x%x(0x%x)\n", rcfg - bcfg, radio_config - board_config);
121         rcfg_size = BOARD_CONFIG_BUFSZ - ((rcfg - bcfg) & (BOARD_CONFIG_BUFSZ - 1));
122         memcpy(radio_config, rcfg, rcfg_size);
123         
124         return 0;
125 }
126
127 void __init serial_setup(unsigned long mapbase, unsigned int uartclk)
128 {
129         struct uart_port s;
130         
131         memset(&s, 0, sizeof(s));
132
133         s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
134         s.iotype = UPIO_MEM;
135         s.irq = AR531X_MISC_IRQ_UART0;
136         s.regshift = 2;
137         s.mapbase = mapbase;
138         s.uartclk = uartclk;
139         s.membase = (void __iomem *)s.mapbase;
140
141         early_serial_setup(&s);
142 }
143
144 void __init plat_mem_setup(void)
145 {
146         DO_AR5312(ar5312_plat_setup();)
147         DO_AR5315(ar5315_plat_setup();)
148
149         /* Disable data watchpoints */
150         write_c0_watchlo0(0);
151 }
152
153 const char *get_system_type(void)
154 {
155         switch (mips_machtype) {
156 #ifdef CONFIG_ATHEROS_AR5312
157         case MACH_ATHEROS_AR5312:
158                 return "Atheros AR5312\n";
159
160         case MACH_ATHEROS_AR2312:
161                 return "Atheros AR2312\n";
162                 
163         case MACH_ATHEROS_AR2313:
164                 return "Atheros AR2313\n";
165 #endif
166 #ifdef CONFIG_ATHEROS_AR5315
167         case MACH_ATHEROS_AR2315:
168                 return "Atheros AR2315\n";
169         case MACH_ATHEROS_AR2316:
170                 return "Atheros AR2316\n";
171         case MACH_ATHEROS_AR2317:
172                 return "Atheros AR2317\n";
173         case MACH_ATHEROS_AR2318:
174                 return "Atheros AR2318\n";
175 #endif
176         }
177         return "Atheros (unknown)";
178 }
179
180 void __init plat_timer_setup(struct irqaction *irq)
181 {
182         unsigned int count;
183
184         /* Usually irq is timer_irqaction (timer_interrupt) */
185         setup_irq(AR531X_IRQ_CPU_CLOCK, irq);
186
187         /* to generate the first CPU timer interrupt */
188         count = read_c0_count();
189         write_c0_compare(count + 1000);
190 }
191
192