ar5312.c revision 1.3 1 /* $NetBSD: ar5312.c,v 1.3 2006/09/26 06:37:32 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_businit(void)
135
136 {
137 /*
138 * Clear previous AHB errors
139 */
140 GETSYSREG(AR5312_SYSREG_AHBPERR);
141 GETSYSREG(AR5312_SYSREG_AHBDMAE);
142 }
143
144 uint32_t
145 ar531x_cpu_freq(void)
146 {
147 static uint32_t cpufreq;
148 uint32_t wisoc = GETSYSREG(AR5312_SYSREG_REVISION);
149
150 uint32_t predivmask;
151 uint32_t predivshift;
152 uint32_t multmask;
153 uint32_t multshift;
154 uint32_t doublermask;
155 uint32_t divisor;
156 uint32_t multiplier;
157 uint32_t clockctl;
158
159 const int predivide_table[4] = { 1, 2, 4, 5 };
160
161 /* XXX: in theory we might be able to get clock from bootrom */
162
163 /*
164 * This logic looks at the clock control register and
165 * determines the actual CPU frequency. These parts lack any
166 * kind of real-time clock on them, but the cpu clocks should
167 * be very accurate -- WiFi requires usec resolution timers.
168 */
169
170 if (cpufreq) {
171 return cpufreq;
172 }
173
174 if (AR5312_REVISION_MAJOR(wisoc) == AR5312_REVISION_MAJ_AR2313) {
175 predivmask = AR2313_CLOCKCTL_PREDIVIDE_MASK;
176 predivshift = AR2313_CLOCKCTL_PREDIVIDE_SHIFT;
177 multmask = AR2313_CLOCKCTL_MULTIPLIER_MASK;
178 multshift = AR2313_CLOCKCTL_MULTIPLIER_SHIFT;
179 doublermask = AR2313_CLOCKCTL_DOUBLER_MASK;
180 } else {
181 predivmask = AR5312_CLOCKCTL_PREDIVIDE_MASK;
182 predivshift = AR5312_CLOCKCTL_PREDIVIDE_SHIFT;
183 multmask = AR5312_CLOCKCTL_MULTIPLIER_MASK;
184 multshift = AR5312_CLOCKCTL_MULTIPLIER_SHIFT;
185 doublermask = AR5312_CLOCKCTL_DOUBLER_MASK;
186 }
187
188 /*
189 * Note that the source clock involved here is a 40MHz.
190 */
191
192 clockctl = GETSYSREG(AR5312_SYSREG_CLOCKCTL);
193 divisor = predivide_table[(clockctl & predivmask) >> predivshift];
194 multiplier = (clockctl & multmask) >> multshift;
195
196 if (clockctl & doublermask)
197 multiplier <<= 1;
198
199 cpufreq = (40000000 / divisor) * multiplier;
200
201 return (cpufreq);
202 }
203
204 uint32_t
205 ar531x_bus_freq(void)
206 {
207 return (ar531x_cpu_freq() / 4);
208 }
209
210 static void
211 addprop_data(struct device *dev, const char *name, const uint8_t *data,
212 int len)
213 {
214 prop_data_t pd;
215 pd = prop_data_create_data(data, len);
216 KASSERT(pd != NULL);
217 if (prop_dictionary_set(device_properties(dev), name, pd) == FALSE) {
218 printf("WARNING: unable to set %s property for %s\n",
219 name, device_xname(dev));
220 }
221 prop_object_release(pd);
222 }
223
224 static void
225 addprop_integer(struct device *dev, const char *name, uint32_t val)
226 {
227 prop_number_t pn;
228 pn = prop_number_create_integer(val);
229 KASSERT(pn != NULL);
230 if (prop_dictionary_set(device_properties(dev), name, pn) == FALSE) {
231 printf("WARNING: unable to set %s property for %s",
232 name, device_xname(dev));
233 }
234 prop_object_release(pn);
235 }
236
237 void
238 ar531x_device_register(struct device *dev, void *aux)
239 {
240 struct arbus_attach_args *aa = aux;
241 const struct ar531x_boarddata *info;
242
243 info = ar531x_board_info();
244 if (info == NULL) {
245 /* nothing known about this board! */
246 return;
247 }
248
249 /*
250 * We don't ever know the boot device. But that's because the
251 * firmware only loads from the network.
252 */
253
254 /* Fetch the MAC addresses. */
255 if (device_is_a(dev, "ae")) {
256 const uint8_t *enet;
257
258 if (aa->aa_addr == AR5312_ENET0_BASE)
259 enet = info->enet0Mac;
260 else if (aa->aa_addr == AR5312_ENET1_BASE)
261 enet = info->enet1Mac;
262 else
263 return;
264
265 addprop_data(dev, "mac-addr", enet, ETHER_ADDR_LEN);
266 }
267
268 if (device_is_a(dev, "ath")) {
269 const uint8_t *enet;
270
271 if (aa->aa_addr == AR5312_WLAN0_BASE)
272 enet = info->wlan0Mac;
273 else if (aa->aa_addr == AR5312_WLAN1_BASE)
274 enet = info->wlan1Mac;
275 else
276 return;
277
278 addprop_data(dev, "mac-addr", enet, ETHER_ADDR_LEN);
279
280 addprop_integer(dev, "wmac-rev",
281 AR5312_REVISION_WMAC(GETSYSREG(AR5312_SYSREG_REVISION)));
282
283 }
284
285 if (device_is_a(dev, "com")) {
286 addprop_integer(dev, "frequency", ar531x_cpu_freq() / 4);
287 }
288
289 if (device_is_a(dev, "argpio")) {
290 if (info->config & BD_RSTFACTORY) {
291 addprop_integer(dev, "reset-pin",
292 info->resetConfigGpio);
293 }
294 if (info->config & BD_SYSLED) {
295 addprop_integer(dev, "sysled-pin",
296 info->sysLedGpio);
297 }
298 }
299 }
300
301 int
302 ar531x_enable_device(const struct ar531x_device *dev)
303 {
304 const struct ar531x_boarddata *info;
305
306 info = ar531x_board_info();
307 if (dev->mask && ((dev->mask & info->config) == 0)) {
308 return -1;
309 }
310 if (dev->reset) {
311 /* put device into reset */
312 PUTSYSREG(AR5312_SYSREG_RESETCTL,
313 GETSYSREG(AR5312_SYSREG_RESETCTL) | dev->reset);
314
315 delay(15000); /* XXX: tsleep? */
316
317 /* take it out of reset */
318 PUTSYSREG(AR5312_SYSREG_RESETCTL,
319 GETSYSREG(AR5312_SYSREG_RESETCTL) & ~dev->reset);
320
321 delay(25);
322 }
323 if (dev->enable) {
324 PUTSYSREG(AR5312_SYSREG_ENABLE,
325 GETSYSREG(AR5312_SYSREG_ENABLE) | dev->enable);
326 }
327 return 0;
328 }
329
330 const struct ar531x_device *
331 ar531x_get_devices(void)
332 {
333 static const struct ar531x_device devices[] = {
334 {
335 "ae",
336 AR5312_ENET0_BASE, 0x100000,
337 AR5312_IRQ_ENET0, -1,
338 AR5312_BOARD_CONFIG_ENET0,
339 AR5312_RESET_ENET0 | AR5312_RESET_PHY0,
340 AR5312_ENABLE_ENET0
341 },
342 {
343 "ae",
344 AR5312_ENET1_BASE, 0x100000,
345 AR5312_IRQ_ENET1, -1,
346 AR5312_BOARD_CONFIG_ENET1,
347 AR5312_RESET_ENET1 | AR5312_RESET_PHY1,
348 AR5312_ENABLE_ENET1
349 },
350 {
351 "com",
352 AR5312_UART0_BASE, 0x1000,
353 AR5312_IRQ_MISC, AR5312_MISC_IRQ_UART0,
354 AR5312_BOARD_CONFIG_UART0,
355 0,
356 0,
357 },
358 {
359 "com",
360 AR5312_UART1_BASE, 0x1000,
361 -1, -1,
362 AR5312_BOARD_CONFIG_UART1,
363 0,
364 0,
365 },
366 {
367 "ath",
368 AR5312_WLAN0_BASE, 0x100000,
369 AR5312_IRQ_WLAN0, -1,
370 AR5312_BOARD_CONFIG_WLAN0,
371 AR5312_RESET_WLAN0 |
372 AR5312_RESET_WARM_WLAN0_MAC |
373 AR5312_RESET_WARM_WLAN0_BB,
374 AR5312_ENABLE_WLAN0
375 },
376 {
377 "ath",
378 AR5312_WLAN1_BASE, 0x100000,
379 AR5312_IRQ_WLAN1, -1,
380 AR5312_BOARD_CONFIG_WLAN1,
381 AR5312_RESET_WLAN1 |
382 AR5312_RESET_WARM_WLAN1_MAC |
383 AR5312_RESET_WARM_WLAN1_BB,
384 AR5312_ENABLE_WLAN1
385 },
386 {
387 "athflash",
388 AR5312_FLASH_BASE, 0,
389 -1, -1,
390 0,
391 0,
392 0,
393 },
394 {
395 "argpio", 0x1000,
396 AR5312_GPIO_BASE,
397 AR5312_IRQ_MISC, AR5312_MISC_IRQ_GPIO,
398 0,
399 0,
400 0
401 },
402 { NULL }
403 };
404
405 return devices;
406 }
407
408