1ea66c0c1913cc398823fe6817f6c79db669629f
[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 }