ar5312.c revision 1.8 1 /* $NetBSD: ar5312.c,v 1.8 2011/07/07 05:06:44 matt Exp $ */
2
3 /*
4 * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
5 * Copyright (c) 2006 Garrett D'Amore.
6 * All rights reserved.
7 *
8 * Portions of this code were written by Garrett D'Amore for the
9 * Champaign-Urbana Community Wireless Network Project.
10 *
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
13 * conditions are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer in the documentation and/or other materials provided
19 * with the distribution.
20 * 3. All advertising materials mentioning features or use of this
21 * software must display the following acknowledgements:
22 * This product includes software developed by the Urbana-Champaign
23 * Independent Media Center.
24 * This product includes software developed by Garrett D'Amore.
25 * 4. Urbana-Champaign Independent Media Center's name and Garrett
26 * D'Amore's name may not be used to endorse or promote products
27 * derived from this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT
30 * MEDIA CENTER AND GARRETT D'AMORE ``AS IS'' AND ANY EXPRESS OR
31 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE URBANA-CHAMPAIGN INDEPENDENT
34 * MEDIA CENTER OR GARRETT D'AMORE BE LIABLE FOR ANY DIRECT, INDIRECT,
35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 */
43
44 /*
45 * This file includes a bunch of implementation specific bits for
46 * AR5312, which differents these from other members of the AR5315
47 * family.
48 */
49 #include "opt_ddb.h"
50 #include "opt_kgdb.h"
51 #define __INTR_PRIVATE
52
53 #include "opt_memsize.h"
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/device.h>
57 #include <sys/kernel.h>
58 #include <sys/buf.h>
59
60 #include <mips/cache.h>
61 #include <mips/locore.h>
62 #include <mips/cpuregs.h>
63
64 #include <sys/socket.h> /* these three just to get ETHER_ADDR_LEN(!) */
65 #include <net/if.h>
66 #include <net/if_ether.h>
67
68 #include <prop/proplib.h>
69
70 #include <ah_soc.h>
71
72 #include <mips/atheros/include/platform.h>
73 #include <mips/atheros/include/arbusvar.h>
74 #include <mips/atheros/include/ar5312reg.h>
75 #include "com.h"
76
77 static uint32_t
78 ar5312_get_memsize(void)
79 {
80 uint32_t memsize;
81 uint32_t memcfg, bank0, bank1;
82
83 /*
84 * Determine the memory size as established by system
85 * firmware.
86 *
87 * NB: we allow compile time override
88 */
89 #if defined(MEMSIZE)
90 memsize = MEMSIZE;
91 #else
92 memcfg = GETSDRAMREG(AR5312_SDRAMCTL_MEM_CFG1);
93 bank0 = __SHIFTOUT(memcfg, AR5312_MEM_CFG1_BANK0);
94 bank1 = __SHIFTOUT(memcfg, AR5312_MEM_CFG1_BANK1);
95
96 memsize = (bank0 ? (1 << (bank0 + 1)) : 0) +
97 (bank1 ? (1 << (bank1 + 1)) : 0);
98 memsize <<= 20;
99 #endif
100
101 return (memsize);
102 }
103
104 static void
105 ar5312_wdog_reload(uint32_t period)
106 {
107
108 if (period == 0) {
109 PUTSYSREG(AR5312_SYSREG_WDOG_CTL, AR5312_WDOG_CTL_IGNORE);
110 PUTSYSREG(AR5312_SYSREG_WDOG_TIMER, 0);
111 } else {
112 PUTSYSREG(AR5312_SYSREG_WDOG_TIMER, period);
113 PUTSYSREG(AR5312_SYSREG_WDOG_CTL, AR5312_WDOG_CTL_RESET);
114 }
115 }
116
117 static void
118 ar5312_bus_init(void)
119 {
120 /*
121 * Clear previous AHB errors
122 */
123 GETSYSREG(AR5312_SYSREG_AHBPERR);
124 GETSYSREG(AR5312_SYSREG_AHBDMAE);
125 }
126
127 static void
128 ar5312_reset(void)
129 {
130 PUTSYSREG(AR5312_SYSREG_RESETCTL, AR5312_RESET_SYSTEM);
131 }
132
133 static void
134 ar5312_get_freqs(struct arfreqs *freqs)
135 {
136 const uint32_t wisoc = GETSYSREG(AR5312_SYSREG_REVISION);
137
138 uint32_t predivisor;
139 uint32_t multiplier;
140
141 /*
142 * This logic looks at the clock control register and
143 * determines the actual CPU frequency. These parts lack any
144 * kind of real-time clock on them, but the cpu clocks should
145 * be very accurate -- WiFi requires usec resolution timers.
146 */
147
148 const uint32_t clockctl = GETSYSREG(AR5312_SYSREG_CLOCKCTL);
149
150 if (AR5312_REVISION_MAJOR(wisoc) == AR5312_REVISION_MAJ_AR2313) {
151 predivisor = __SHIFTOUT(clockctl, AR2313_CLOCKCTL_PREDIVIDE);
152 multiplier = __SHIFTOUT(clockctl, AR2313_CLOCKCTL_MULTIPLIER);
153 } else {
154 predivisor = __SHIFTOUT(clockctl, AR5312_CLOCKCTL_PREDIVIDE);
155 multiplier = __SHIFTOUT(clockctl, AR5312_CLOCKCTL_MULTIPLIER);
156 if (clockctl & AR5312_CLOCKCTL_DOUBLER)
157 multiplier <<= 1;
158 }
159
160 /*
161 * Note that the source clock involved here is a 40MHz.
162 */
163
164 const uint32_t divisor = (0x5421 >> (predivisor * 4)) & 15;
165
166 const uint32_t cpufreq = (40000000 / divisor) * multiplier;
167
168 freqs->freq_cpu = cpufreq;
169 freqs->freq_bus = cpufreq / 4;
170 freqs->freq_mem = 0;
171 freqs->freq_ref = 40000000;
172 freqs->freq_pll = 40000000;
173 }
174
175
176 static void
177 addprop_data(struct device *dev, const char *name, const uint8_t *data,
178 int len)
179 {
180 prop_data_t pd;
181 pd = prop_data_create_data(data, len);
182 KASSERT(pd != NULL);
183 if (prop_dictionary_set(device_properties(dev), name, pd) == false) {
184 printf("WARNING: unable to set %s property for %s\n",
185 name, device_xname(dev));
186 }
187 prop_object_release(pd);
188 }
189
190 static void
191 addprop_integer(struct device *dev, const char *name, uint32_t val)
192 {
193 prop_number_t pn;
194 pn = prop_number_create_integer(val);
195 KASSERT(pn != NULL);
196 if (prop_dictionary_set(device_properties(dev), name, pn) == false) {
197 printf("WARNING: unable to set %s property for %s",
198 name, device_xname(dev));
199 }
200 prop_object_release(pn);
201 }
202
203 static void
204 ar5312_device_register(device_t dev, void *aux)
205 {
206 const struct arbus_attach_args * const aa = aux;
207
208 if (device_is_a(dev, "com")) {
209 addprop_integer(dev, "frequency", atheros_get_bus_freq());
210 }
211
212 const struct ar531x_boarddata * const info = atheros_get_board_info();
213 if (info == NULL) {
214 /* nothing known about this board! */
215 return;
216 }
217
218 /*
219 * We don't ever know the boot device. But that's because the
220 * firmware only loads from the network.
221 */
222
223 /* Fetch the MAC addresses. */
224 if (device_is_a(dev, "ae")) {
225 const uint8_t *enet;
226
227 if (aa->aa_addr == AR5312_ENET0_BASE)
228 enet = info->enet0Mac;
229 else if (aa->aa_addr == AR5312_ENET1_BASE)
230 enet = info->enet1Mac;
231 else
232 return;
233
234 addprop_data(dev, "mac-address", enet, ETHER_ADDR_LEN);
235 }
236
237 if (device_is_a(dev, "ath")) {
238 const uint8_t *enet;
239
240 if (aa->aa_addr == AR5312_WLAN0_BASE)
241 enet = info->wlan0Mac;
242 else if (aa->aa_addr == AR5312_WLAN1_BASE)
243 enet = info->wlan1Mac;
244 else
245 return;
246
247 addprop_data(dev, "mac-address", enet, ETHER_ADDR_LEN);
248
249 addprop_integer(dev, "wmac-rev",
250 AR5312_REVISION_WMAC(GETSYSREG(AR5312_SYSREG_REVISION)));
251
252 }
253
254 if (device_is_a(dev, "argpio")) {
255 if (info->config & BD_RSTFACTORY) {
256 addprop_integer(dev, "reset-pin",
257 info->resetConfigGpio);
258 }
259 if (info->config & BD_SYSLED) {
260 addprop_integer(dev, "sysled-pin",
261 info->sysLedGpio);
262 }
263 }
264 }
265
266 static int
267 ar5312_enable_device(const struct atheros_device *adv)
268 {
269 const struct ar531x_boarddata * const info = atheros_get_board_info();
270
271 if (info != NULL
272 && adv->adv_mask && ((adv->adv_mask & info->config) == 0)) {
273 return -1;
274 }
275 if (adv->adv_reset) {
276 /* put device into reset */
277 PUTSYSREG(AR5312_SYSREG_RESETCTL,
278 GETSYSREG(AR5312_SYSREG_RESETCTL) | adv->adv_reset);
279
280 delay(15000); /* XXX: tsleep? */
281
282 /* take it out of reset */
283 PUTSYSREG(AR5312_SYSREG_RESETCTL,
284 GETSYSREG(AR5312_SYSREG_RESETCTL) & ~adv->adv_reset);
285
286 delay(25);
287 }
288 if (adv->adv_enable) {
289 PUTSYSREG(AR5312_SYSREG_ENABLE,
290 GETSYSREG(AR5312_SYSREG_ENABLE) | adv->adv_enable);
291 }
292 return 0;
293 }
294
295 static void
296 ar5312_intr_init(void)
297 {
298 atheros_intr_init();
299 }
300
301 static const struct atheros_device ar5312_devices[] = {
302 {
303 .adv_name = "ae",
304 .adv_addr = AR5312_ENET0_BASE,
305 .adv_size = 0x100000,
306 .adv_cirq = AR5312_IRQ_ENET0,
307 .adv_mirq = -1,
308 .adv_mask = AR5312_BOARD_CONFIG_ENET0,
309 .adv_reset = AR5312_RESET_ENET0 | AR5312_RESET_PHY0,
310 .adv_enable = AR5312_ENABLE_ENET0
311 }, {
312 .adv_name = "ae",
313 .adv_addr = AR5312_ENET1_BASE,
314 .adv_size = 0x100000,
315 .adv_cirq = AR5312_IRQ_ENET1,
316 .adv_mirq = -1,
317 .adv_mask = AR5312_BOARD_CONFIG_ENET1,
318 .adv_reset = AR5312_RESET_ENET1 | AR5312_RESET_PHY1,
319 .adv_enable = AR5312_ENABLE_ENET1
320 }, {
321 .adv_name = "com",
322 .adv_addr = AR5312_UART0_BASE,
323 .adv_size = 0x1000,
324 .adv_cirq = AR5312_IRQ_MISC,
325 .adv_mirq = AR5312_MISC_IRQ_UART0,
326 .adv_mask = AR5312_BOARD_CONFIG_UART0,
327 }, {
328 .adv_name = "com",
329 .adv_addr = AR5312_UART1_BASE,
330 .adv_size = 0x1000,
331 .adv_cirq = -1,
332 .adv_mirq = -1,
333 .adv_mask = AR5312_BOARD_CONFIG_UART1,
334 }, {
335 .adv_name = "ath",
336 .adv_addr = AR5312_WLAN0_BASE,
337 .adv_size = 0x100000,
338 .adv_cirq = AR5312_IRQ_WLAN0,
339 .adv_mirq = -1,
340 .adv_mask = AR5312_BOARD_CONFIG_WLAN0,
341 .adv_reset = AR5312_RESET_WLAN0 | AR5312_RESET_WARM_WLAN0_MAC
342 | AR5312_RESET_WARM_WLAN0_BB,
343 .adv_enable = AR5312_ENABLE_WLAN0
344 }, {
345 .adv_name = "ath",
346 .adv_addr = AR5312_WLAN1_BASE,
347 .adv_size = 0x100000,
348 .adv_cirq = AR5312_IRQ_WLAN1,
349 .adv_mirq = -1,
350 .adv_mask = AR5312_BOARD_CONFIG_WLAN1,
351 .adv_reset = AR5312_RESET_WLAN1 | AR5312_RESET_WARM_WLAN1_MAC
352 | AR5312_RESET_WARM_WLAN1_BB,
353 .adv_enable = AR5312_ENABLE_WLAN1
354 }, {
355 .adv_name = "athflash",
356 .adv_addr = AR5312_FLASH_BASE,
357 .adv_size = 0,
358 .adv_cirq = -1,
359 .adv_mirq = -1,
360 }, {
361 .adv_name = "argpio",
362 .adv_addr = AR5312_GPIO_BASE,
363 .adv_size = 0x1000,
364 .adv_cirq = AR5312_IRQ_MISC,
365 .adv_mirq = AR5312_MISC_IRQ_GPIO,
366 }, {
367 .adv_name = NULL
368 }
369 };
370
371 static const struct ipl_sr_map ar5312_ipl_sr_map = {
372 .sr_bits = {
373 [IPL_NONE] = 0,
374 [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0,
375 [IPL_SOFTBIO] = MIPS_SOFT_INT_MASK_0,
376 [IPL_SOFTNET] = MIPS_SOFT_INT_MASK,
377 [IPL_SOFTSERIAL] = MIPS_SOFT_INT_MASK,
378 [IPL_VM] = MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0
379 | MIPS_INT_MASK_1 | MIPS_INT_MASK_2
380 | MIPS_INT_MASK_3,
381 [IPL_SCHED] = MIPS_INT_MASK,
382 [IPL_DDB] = MIPS_INT_MASK,
383 [IPL_HIGH] = MIPS_INT_MASK,
384 },
385 };
386
387 static const char * const ar5312_cpu_intrnames[] = {
388 "int 0 (wlan0)",
389 "int 1 (enet0)",
390 "int 2 (enet1)",
391 "int 3 (wlan1)",
392 "int 4 (misc)",
393 "int 5 (timer)",
394 };
395
396 static const char * const ar5312_misc_intrnames[] = {
397 "misc 0 (timer)",
398 "misc 1 (AHBproc error)",
399 "misc 2 (AHBdma error)",
400 "misc 3 (gpio)",
401 "misc 4 (uart)",
402 "misc 5 (uart dma)",
403 "misc 6 (watchdog)"
404 };
405
406
407 const struct atheros_platformsw ar5312_platformsw = {
408 .apsw_intrsw = &atheros_intrsw,
409 .apsw_intr_init = ar5312_intr_init,
410 .apsw_cpu_intrnames = ar5312_cpu_intrnames,
411 .apsw_misc_intrnames = ar5312_misc_intrnames,
412 .apsw_cpu_nintrs = __arraycount(ar5312_cpu_intrnames),
413 .apsw_misc_nintrs = __arraycount(ar5312_misc_intrnames),
414 .apsw_cpuirq_misc = AR5312_IRQ_MISC,
415 .apsw_ipl_sr_map = &ar5312_ipl_sr_map,
416
417 .apsw_revision_id_addr = AR5312_SYSREG_BASE + AR5312_SYSREG_REVISION,
418 .apsw_uart0_base = AR5312_UART0_BASE,
419 .apsw_misc_intstat = AR5312_SYSREG_BASE + AR5312_SYSREG_MISC_INTSTAT,
420 .apsw_misc_intmask = AR5312_SYSREG_BASE + AR5312_SYSREG_MISC_INTMASK,
421
422 /*
423 * CPU specific routines.
424 */
425 .apsw_get_memsize = ar5312_get_memsize,
426 .apsw_wdog_reload = ar5312_wdog_reload,
427 .apsw_bus_init = ar5312_bus_init,
428 .apsw_reset = ar5312_reset,
429
430 .apsw_get_freqs = ar5312_get_freqs,
431 .apsw_device_register = ar5312_device_register,
432 .apsw_enable_device = ar5312_enable_device,
433 .apsw_devices = ar5312_devices,
434 };
435