ar5312.c revision 1.2 1 /* $NetBSD: ar5312.c,v 1.2 2006/09/04 05:17:26 gdamore 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
52 #include "opt_memsize.h"
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/kernel.h>
56 #include <sys/buf.h>
57
58 #include <mips/cache.h>
59 #include <mips/locore.h>
60 #include <mips/cpuregs.h>
61
62 #include <sys/socket.h> /* these three just to get ETHER_ADDR_LEN(!) */
63 #include <net/if.h>
64 #include <net/if_ether.h>
65
66 #include <mips/atheros/include/ar5312reg.h>
67 #include <mips/atheros/include/ar531xvar.h>
68 #include <mips/atheros/include/arbusvar.h>
69 #include "com.h"
70
71 uint32_t
72 ar531x_memsize(void)
73 {
74 uint32_t memsize;
75 uint32_t memcfg, bank0, bank1;
76
77 /*
78 * Determine the memory size as established by system
79 * firmware.
80 *
81 * NB: we allow compile time override
82 */
83 #if defined(MEMSIZE)
84 memsize = MEMSIZE;
85 #else
86 memcfg = GETSDRAMREG(AR5312_SDRAMCTL_MEM_CFG1);
87 bank0 = (memcfg & AR5312_MEM_CFG1_BANK0_MASK) >>
88 AR5312_MEM_CFG1_BANK0_SHIFT;
89 bank1 = (memcfg & AR5312_MEM_CFG1_BANK1_MASK) >>
90 AR5312_MEM_CFG1_BANK1_SHIFT;
91
92 memsize = (bank0 ? (1 << (bank0 + 1)) : 0) +
93 (bank1 ? (1 << (bank1 + 1)) : 0);
94 memsize <<= 20;
95 #endif
96
97 return (memsize);
98 }
99
100 void
101 ar531x_wdog(uint32_t period)
102 {
103
104 if (period == 0) {
105 PUTSYSREG(AR5312_SYSREG_WDOG_CTL, AR5312_WDOG_CTL_IGNORE);
106 PUTSYSREG(AR5312_SYSREG_WDOG_TIMER, 0);
107 } else {
108 PUTSYSREG(AR5312_SYSREG_WDOG_TIMER, period);
109 PUTSYSREG(AR5312_SYSREG_WDOG_CTL, AR5312_WDOG_CTL_RESET);
110 }
111 }
112
113 const char *
114 ar531x_cpuname(void)
115 {
116 uint32_t revision;
117
118 revision = GETSYSREG(AR5312_SYSREG_REVISION);
119 switch (AR5312_REVISION_MAJOR(revision)) {
120 case AR5312_REVISION_MAJ_AR5311:
121 return ("Atheros AR5311");
122 case AR5312_REVISION_MAJ_AR5312:
123 return ("Atheros AR5312");
124 case AR5312_REVISION_MAJ_AR2313:
125 return ("Atheros AR2313");
126 case AR5312_REVISION_MAJ_AR5315:
127 return ("Atheros AR5315");
128 default:
129 return ("Atheros AR531X");
130 }
131 }
132
133 void
134 ar531x_consinit(void)
135 {
136 /*
137 * Everything related to console initialization is done
138 * in mach_init().
139 */
140 #if NCOM > 0
141 /* Setup polled serial for early console I/O */
142 /* XXX: pass in CONSPEED? */
143 com_arbus_cnattach(AR5312_UART0_BASE, ar531x_bus_freq());
144 #else
145 panic("Not configured to use serial console!\n");
146 /* not going to see that message now, are we? */
147 #endif
148 }
149
150 void
151 ar531x_businit(void)
152
153 {
154 /*
155 * Clear previous AHB errors
156 */
157 GETSYSREG(AR5312_SYSREG_AHBPERR);
158 GETSYSREG(AR5312_SYSREG_AHBDMAE);
159 }
160
161 uint32_t
162 ar531x_cpu_freq(void)
163 {
164 static uint32_t cpufreq;
165 uint32_t wisoc = GETSYSREG(AR5312_SYSREG_REVISION);
166
167 uint32_t predivmask;
168 uint32_t predivshift;
169 uint32_t multmask;
170 uint32_t multshift;
171 uint32_t doublermask;
172 uint32_t divisor;
173 uint32_t multiplier;
174 uint32_t clockctl;
175
176 const int predivide_table[4] = { 1, 2, 4, 5 };
177
178 /* XXX: in theory we might be able to get clock from bootrom */
179
180 /*
181 * This logic looks at the clock control register and
182 * determines the actual CPU frequency. These parts lack any
183 * kind of real-time clock on them, but the cpu clocks should
184 * be very accurate -- WiFi requires usec resolution timers.
185 */
186
187 if (cpufreq) {
188 return cpufreq;
189 }
190
191 if (AR5312_REVISION_MAJOR(wisoc) == AR5312_REVISION_MAJ_AR2313) {
192 predivmask = AR2313_CLOCKCTL_PREDIVIDE_MASK;
193 predivshift = AR2313_CLOCKCTL_PREDIVIDE_SHIFT;
194 multmask = AR2313_CLOCKCTL_MULTIPLIER_MASK;
195 multshift = AR2313_CLOCKCTL_MULTIPLIER_SHIFT;
196 doublermask = AR2313_CLOCKCTL_DOUBLER_MASK;
197 } else {
198 predivmask = AR5312_CLOCKCTL_PREDIVIDE_MASK;
199 predivshift = AR5312_CLOCKCTL_PREDIVIDE_SHIFT;
200 multmask = AR5312_CLOCKCTL_MULTIPLIER_MASK;
201 multshift = AR5312_CLOCKCTL_MULTIPLIER_SHIFT;
202 doublermask = AR5312_CLOCKCTL_DOUBLER_MASK;
203 }
204
205 /*
206 * Note that the source clock involved here is a 40MHz.
207 */
208
209 clockctl = GETSYSREG(AR5312_SYSREG_CLOCKCTL);
210 divisor = predivide_table[(clockctl & predivmask) >> predivshift];
211 multiplier = (clockctl & multmask) >> multshift;
212
213 if (clockctl & doublermask)
214 multiplier <<= 1;
215
216 cpufreq = (40000000 / divisor) * multiplier;
217
218 return (cpufreq);
219 }
220
221 uint32_t
222 ar531x_bus_freq(void)
223 {
224 return (ar531x_cpu_freq() / 4);
225 }
226
227 static void
228 addprop_data(struct device *dev, const char *name, const uint8_t *data,
229 int len)
230 {
231 prop_data_t pd;
232 pd = prop_data_create_data(data, len);
233 KASSERT(pd != NULL);
234 if (prop_dictionary_set(device_properties(dev), name, pd) == FALSE) {
235 printf("WARNING: unable to set %s property for %s\n",
236 name, device_xname(dev));
237 }
238 prop_object_release(pd);
239 }
240
241 static void
242 addprop_integer(struct device *dev, const char *name, uint32_t val)
243 {
244 prop_number_t pn;
245 pn = prop_number_create_integer(val);
246 KASSERT(pn != NULL);
247 if (prop_dictionary_set(device_properties(dev), name, pn) == FALSE) {
248 printf("WARNING: unable to set %s property for %s",
249 name, device_xname(dev));
250 }
251 prop_object_release(pn);
252 }
253
254 void
255 ar531x_device_register(struct device *dev, void *aux)
256 {
257 struct arbus_attach_args *aa = aux;
258 const struct ar531x_boarddata *info;
259
260 info = ar531x_board_info();
261 if (info == NULL) {
262 /* nothing known about this board! */
263 return;
264 }
265
266 /*
267 * We don't ever know the boot device. But that's because the
268 * firmware only loads from the network.
269 */
270
271 /* Fetch the MAC addresses. */
272 if (device_is_a(dev, "ae")) {
273 const uint8_t *enet;
274
275 if (aa->aa_addr == AR5312_ENET0_BASE)
276 enet = info->enet0Mac;
277 else if (aa->aa_addr == AR5312_ENET1_BASE)
278 enet = info->enet1Mac;
279 else
280 return;
281
282 addprop_data(dev, "mac-addr", enet, ETHER_ADDR_LEN);
283 }
284
285 if (device_is_a(dev, "ath")) {
286 const uint8_t *enet;
287
288 if (aa->aa_addr == AR5312_WLAN0_BASE)
289 enet = info->wlan0Mac;
290 else if (aa->aa_addr == AR5312_WLAN1_BASE)
291 enet = info->wlan1Mac;
292 else
293 return;
294
295 addprop_data(dev, "mac-addr", enet, ETHER_ADDR_LEN);
296 }
297
298 if (device_is_a(dev, "com")) {
299 addprop_integer(dev, "frequency", ar531x_cpu_freq() / 4);
300 }
301
302 if (device_is_a(dev, "argpio")) {
303 if (info->config & BD_RSTFACTORY) {
304 addprop_integer(dev, "reset-pin",
305 info->resetConfigGpio);
306 }
307 if (info->config & BD_SYSLED) {
308 addprop_integer(dev, "sysled-pin",
309 info->sysLedGpio);
310 }
311 }
312 }
313
314 int
315 ar531x_enable_device(const struct ar531x_device *dev)
316 {
317 const struct ar531x_boarddata *info;
318
319 info = ar531x_board_info();
320 if (dev->mask && ((dev->mask & info->config) == 0)) {
321 return -1;
322 }
323 if (dev->reset) {
324 /* put device into reset */
325 PUTSYSREG(AR5312_SYSREG_RESETCTL,
326 GETSYSREG(AR5312_SYSREG_RESETCTL) | dev->reset);
327
328 delay(15000); /* XXX: tsleep? */
329
330 /* take it out of reset */
331 PUTSYSREG(AR5312_SYSREG_RESETCTL,
332 GETSYSREG(AR5312_SYSREG_RESETCTL) & ~dev->reset);
333
334 delay(25);
335 }
336 if (dev->enable) {
337 PUTSYSREG(AR5312_SYSREG_ENABLE,
338 GETSYSREG(AR5312_SYSREG_ENABLE) | dev->enable);
339 }
340 return 0;
341 }
342
343 const struct ar531x_device *
344 ar531x_get_devices(void)
345 {
346 static const struct ar531x_device devices[] = {
347 {
348 "ae",
349 AR5312_ENET0_BASE, 0x100000,
350 AR5312_IRQ_ENET0, -1,
351 AR5312_BOARD_CONFIG_ENET0,
352 AR5312_RESET_ENET0 | AR5312_RESET_PHY0,
353 AR5312_ENABLE_ENET0
354 },
355 {
356 "ae",
357 AR5312_ENET1_BASE, 0x100000,
358 AR5312_IRQ_ENET1, -1,
359 AR5312_BOARD_CONFIG_ENET1,
360 AR5312_RESET_ENET1 | AR5312_RESET_PHY1,
361 AR5312_ENABLE_ENET1
362 },
363 {
364 "com",
365 AR5312_UART0_BASE, 0x1000,
366 AR5312_IRQ_MISC, AR5312_MISC_IRQ_UART0,
367 AR5312_BOARD_CONFIG_UART0,
368 0,
369 0,
370 },
371 {
372 "com",
373 AR5312_UART1_BASE, 0x1000,
374 -1, -1,
375 AR5312_BOARD_CONFIG_UART1,
376 0,
377 0,
378 },
379 {
380 "ath",
381 AR5312_WLAN0_BASE, 0x100000,
382 AR5312_IRQ_WLAN0, -1,
383 AR5312_BOARD_CONFIG_WLAN0,
384 AR5312_RESET_WLAN0 |
385 AR5312_RESET_WARM_WLAN0_MAC |
386 AR5312_RESET_WARM_WLAN0_BB,
387 AR5312_ENABLE_WLAN0
388 },
389 {
390 "ath",
391 AR5312_WLAN1_BASE, 0x100000,
392 AR5312_IRQ_WLAN1, -1,
393 AR5312_BOARD_CONFIG_WLAN1,
394 AR5312_RESET_WLAN1 |
395 AR5312_RESET_WARM_WLAN1_MAC |
396 AR5312_RESET_WARM_WLAN1_BB,
397 AR5312_ENABLE_WLAN1
398 },
399 {
400 "athflash",
401 AR5312_FLASH_BASE, 0,
402 -1, -1,
403 0,
404 0,
405 0,
406 },
407 {
408 "argpio", 0x1000,
409 AR5312_GPIO_BASE,
410 AR5312_IRQ_MISC, AR5312_MISC_IRQ_GPIO,
411 0,
412 0,
413 0
414 },
415 { NULL }
416 };
417
418 return devices;
419 }
420
421
422