diff options
Diffstat (limited to 'arch/mips/ath25/board.c')
-rw-r--r-- | arch/mips/ath25/board.c | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/arch/mips/ath25/board.c b/arch/mips/ath25/board.c new file mode 100644 index 000000000000..b8bb78282d6a --- /dev/null +++ b/arch/mips/ath25/board.c | |||
@@ -0,0 +1,234 @@ | |||
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-2009 Felix Fietkau <nbd@openwrt.org> | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <asm/irq_cpu.h> | ||
15 | #include <asm/reboot.h> | ||
16 | #include <asm/bootinfo.h> | ||
17 | #include <asm/time.h> | ||
18 | |||
19 | #include <ath25_platform.h> | ||
20 | #include "devices.h" | ||
21 | #include "ar5312.h" | ||
22 | #include "ar2315.h" | ||
23 | |||
24 | void (*ath25_irq_dispatch)(void); | ||
25 | |||
26 | static inline bool check_radio_magic(const void __iomem *addr) | ||
27 | { | ||
28 | addr += 0x7a; /* offset for flash magic */ | ||
29 | return (__raw_readb(addr) == 0x5a) && (__raw_readb(addr + 1) == 0xa5); | ||
30 | } | ||
31 | |||
32 | static inline bool check_notempty(const void __iomem *addr) | ||
33 | { | ||
34 | return __raw_readl(addr) != 0xffffffff; | ||
35 | } | ||
36 | |||
37 | static inline bool check_board_data(const void __iomem *addr, bool broken) | ||
38 | { | ||
39 | /* config magic found */ | ||
40 | if (__raw_readl(addr) == ATH25_BD_MAGIC) | ||
41 | return true; | ||
42 | |||
43 | if (!broken) | ||
44 | return false; | ||
45 | |||
46 | /* broken board data detected, use radio data to find the | ||
47 | * offset, user will fix this */ | ||
48 | |||
49 | if (check_radio_magic(addr + 0x1000)) | ||
50 | return true; | ||
51 | if (check_radio_magic(addr + 0xf8)) | ||
52 | return true; | ||
53 | |||
54 | return false; | ||
55 | } | ||
56 | |||
57 | static const void __iomem * __init find_board_config(const void __iomem *limit, | ||
58 | const bool broken) | ||
59 | { | ||
60 | const void __iomem *addr; | ||
61 | const void __iomem *begin = limit - 0x1000; | ||
62 | const void __iomem *end = limit - 0x30000; | ||
63 | |||
64 | for (addr = begin; addr >= end; addr -= 0x1000) | ||
65 | if (check_board_data(addr, broken)) | ||
66 | return addr; | ||
67 | |||
68 | return NULL; | ||
69 | } | ||
70 | |||
71 | static const void __iomem * __init find_radio_config(const void __iomem *limit, | ||
72 | const void __iomem *bcfg) | ||
73 | { | ||
74 | const void __iomem *rcfg, *begin, *end; | ||
75 | |||
76 | /* | ||
77 | * Now find the start of Radio Configuration data, using heuristics: | ||
78 | * Search forward from Board Configuration data by 0x1000 bytes | ||
79 | * at a time until we find non-0xffffffff. | ||
80 | */ | ||
81 | begin = bcfg + 0x1000; | ||
82 | end = limit; | ||
83 | for (rcfg = begin; rcfg < end; rcfg += 0x1000) | ||
84 | if (check_notempty(rcfg) && check_radio_magic(rcfg)) | ||
85 | return rcfg; | ||
86 | |||
87 | /* AR2316 relocates radio config to new location */ | ||
88 | begin = bcfg + 0xf8; | ||
89 | end = limit - 0x1000 + 0xf8; | ||
90 | for (rcfg = begin; rcfg < end; rcfg += 0x1000) | ||
91 | if (check_notempty(rcfg) && check_radio_magic(rcfg)) | ||
92 | return rcfg; | ||
93 | |||
94 | return NULL; | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * NB: Search region size could be larger than the actual flash size, | ||
99 | * but this shouldn't be a problem here, because the flash | ||
100 | * will simply be mapped multiple times. | ||
101 | */ | ||
102 | int __init ath25_find_config(phys_addr_t base, unsigned long size) | ||
103 | { | ||
104 | const void __iomem *flash_base, *flash_limit; | ||
105 | struct ath25_boarddata *config; | ||
106 | unsigned int rcfg_size; | ||
107 | int broken_boarddata = 0; | ||
108 | const void __iomem *bcfg, *rcfg; | ||
109 | u8 *board_data; | ||
110 | u8 *radio_data; | ||
111 | u8 *mac_addr; | ||
112 | u32 offset; | ||
113 | |||
114 | flash_base = ioremap_nocache(base, size); | ||
115 | flash_limit = flash_base + size; | ||
116 | |||
117 | ath25_board.config = NULL; | ||
118 | ath25_board.radio = NULL; | ||
119 | |||
120 | /* Copy the board and radio data to RAM, because accessing the mapped | ||
121 | * memory of the flash directly after booting is not safe */ | ||
122 | |||
123 | /* Try to find valid board and radio data */ | ||
124 | bcfg = find_board_config(flash_limit, false); | ||
125 | |||
126 | /* If that fails, try to at least find valid radio data */ | ||
127 | if (!bcfg) { | ||
128 | bcfg = find_board_config(flash_limit, true); | ||
129 | broken_boarddata = 1; | ||
130 | } | ||
131 | |||
132 | if (!bcfg) { | ||
133 | pr_warn("WARNING: No board configuration data found!\n"); | ||
134 | goto error; | ||
135 | } | ||
136 | |||
137 | board_data = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL); | ||
138 | ath25_board.config = (struct ath25_boarddata *)board_data; | ||
139 | memcpy_fromio(board_data, bcfg, 0x100); | ||
140 | if (broken_boarddata) { | ||
141 | pr_warn("WARNING: broken board data detected\n"); | ||
142 | config = ath25_board.config; | ||
143 | if (is_zero_ether_addr(config->enet0_mac)) { | ||
144 | pr_info("Fixing up empty mac addresses\n"); | ||
145 | config->reset_config_gpio = 0xffff; | ||
146 | config->sys_led_gpio = 0xffff; | ||
147 | random_ether_addr(config->wlan0_mac); | ||
148 | config->wlan0_mac[0] &= ~0x06; | ||
149 | random_ether_addr(config->enet0_mac); | ||
150 | random_ether_addr(config->enet1_mac); | ||
151 | } | ||
152 | } | ||
153 | |||
154 | /* Radio config starts 0x100 bytes after board config, regardless | ||
155 | * of what the physical layout on the flash chip looks like */ | ||
156 | |||
157 | rcfg = find_radio_config(flash_limit, bcfg); | ||
158 | if (!rcfg) { | ||
159 | pr_warn("WARNING: Could not find Radio Configuration data\n"); | ||
160 | goto error; | ||
161 | } | ||
162 | |||
163 | radio_data = board_data + 0x100 + ((rcfg - bcfg) & 0xfff); | ||
164 | ath25_board.radio = radio_data; | ||
165 | offset = radio_data - board_data; | ||
166 | pr_info("Radio config found at offset 0x%x (0x%x)\n", rcfg - bcfg, | ||
167 | offset); | ||
168 | rcfg_size = BOARD_CONFIG_BUFSZ - offset; | ||
169 | memcpy_fromio(radio_data, rcfg, rcfg_size); | ||
170 | |||
171 | mac_addr = &radio_data[0x1d * 2]; | ||
172 | if (is_broadcast_ether_addr(mac_addr)) { | ||
173 | pr_info("Radio MAC is blank; using board-data\n"); | ||
174 | ether_addr_copy(mac_addr, ath25_board.config->wlan0_mac); | ||
175 | } | ||
176 | |||
177 | iounmap(flash_base); | ||
178 | |||
179 | return 0; | ||
180 | |||
181 | error: | ||
182 | iounmap(flash_base); | ||
183 | return -ENODEV; | ||
184 | } | ||
185 | |||
186 | static void ath25_halt(void) | ||
187 | { | ||
188 | local_irq_disable(); | ||
189 | unreachable(); | ||
190 | } | ||
191 | |||
192 | void __init plat_mem_setup(void) | ||
193 | { | ||
194 | _machine_halt = ath25_halt; | ||
195 | pm_power_off = ath25_halt; | ||
196 | |||
197 | if (is_ar5312()) | ||
198 | ar5312_plat_mem_setup(); | ||
199 | else | ||
200 | ar2315_plat_mem_setup(); | ||
201 | |||
202 | /* Disable data watchpoints */ | ||
203 | write_c0_watchlo0(0); | ||
204 | } | ||
205 | |||
206 | asmlinkage void plat_irq_dispatch(void) | ||
207 | { | ||
208 | ath25_irq_dispatch(); | ||
209 | } | ||
210 | |||
211 | void __init plat_time_init(void) | ||
212 | { | ||
213 | if (is_ar5312()) | ||
214 | ar5312_plat_time_init(); | ||
215 | else | ||
216 | ar2315_plat_time_init(); | ||
217 | } | ||
218 | |||
219 | unsigned int __cpuinit get_c0_compare_int(void) | ||
220 | { | ||
221 | return CP0_LEGACY_COMPARE_IRQ; | ||
222 | } | ||
223 | |||
224 | void __init arch_init_irq(void) | ||
225 | { | ||
226 | clear_c0_status(ST0_IM); | ||
227 | mips_cpu_irq_init(); | ||
228 | |||
229 | /* Initialize interrupt controllers */ | ||
230 | if (is_ar5312()) | ||
231 | ar5312_arch_init_irq(); | ||
232 | else | ||
233 | ar2315_arch_init_irq(); | ||
234 | } | ||