ar5315.c revision 1.4 1 /* $NetBSD: ar5315.c,v 1.4 2007/02/28 04:21:53 thorpej 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 /*
46 * This file includes a bunch of implementation specific bits for
47 * AR5315, which differs these from other members of the AR531X
48 * family.
49 */
50 #include <sys/cdefs.h>
51 __KERNEL_RCSID(0, "$NetBSD: ar5315.c,v 1.4 2007/02/28 04:21:53 thorpej Exp $");
52
53 #include "opt_ddb.h"
54 #include "opt_kgdb.h"
55
56 #include "opt_memsize.h"
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/kernel.h>
60 #include <sys/buf.h>
61
62 #include <mips/cache.h>
63 #include <mips/locore.h>
64 #include <mips/cpuregs.h>
65
66 #include <net/if.h>
67 #include <net/if_ether.h>
68
69 #include <contrib/dev/ath/ah_soc.h> /* XXX really doesn't belong in hal */
70
71 #include <mips/atheros/include/ar5315reg.h>
72 #include <mips/atheros/include/ar531xvar.h>
73 #include <mips/atheros/include/arbusvar.h>
74
75 #include <machine/locore.h>
76
77 /* helper macro for accessing system registers without bus space */
78 #define REGVAL(x) *((volatile uint32_t *)(MIPS_PHYS_TO_KSEG1((x))))
79 #define GETSYSREG(x) REGVAL((x) + AR5315_SYSREG_BASE)
80 #define PUTSYSREG(x,v) (REGVAL((x) + AR5315_SYSREG_BASE)) = (v)
81 #define GETPCIREG(x) REGVAL((x) + AR5315_PCI_BASE)
82 #define PUTPCIREG(x,v) (REGVAL((x) + AR5315_PCI_BASE)) = (v)
83 #define GETSDRAMREG(x) REGVAL((x) + AR5315_SDRAMCTL_BASE)
84
85 uint32_t
86 ar531x_memsize(void)
87 {
88 #ifndef MEMSIZE
89 uint32_t memsize = 0;
90 uint32_t memcfg, cw, rw, dw;
91
92 /*
93 * Determine the memory size. We query the board info.
94 */
95 memcfg = GETSDRAMREG(AR5315_SDRAMCTL_MEM_CFG);
96 cw = (memcfg & AR5315_MEM_CFG_COL_WIDTH_MASK) >>
97 AR5315_MEM_CFG_COL_WIDTH_SHIFT;
98 cw += 1;
99 rw = (memcfg & AR5315_MEM_CFG_ROW_WIDTH_MASK) >>
100 AR5315_MEM_CFG_ROW_WIDTH_SHIFT;
101 rw += 1;
102
103 /* XXX: according to redboot, this could be wrong if DDR SDRAM */
104 dw = (memcfg & AR5315_MEM_CFG_DATA_WIDTH_MASK) >>
105 AR5315_MEM_CFG_DATA_WIDTH_SHIFT;
106 dw += 1;
107 dw *= 8; /* bits */
108
109 /* not too sure about this math, but it _seems_ to add up */
110 memsize = (1 << cw) * (1 << rw) * dw;
111 #if 0
112 printf("SDRAM_MEM_CFG =%x, cw=%d rw=%d dw=%d xmemsize=%d\n", memcfg,
113 cw, rw, dw, memsize);
114 #endif
115
116 return (memsize);
117 #else
118 /* compile time value forced */
119 return MEMSIZE;
120 #endif
121 }
122
123 const char *
124 ar531x_cpuname(void)
125 {
126 uint16_t rev = GETSYSREG(AR5315_SYSREG_SREV);
127 switch (rev) {
128 case 0x52: /* AP30 */
129 case 0x57: /* AP31 */
130 return "Atheros AR5312";
131 case 0x58: /* AP43 */
132 return "Atheros AR2313";
133 case 0x86: /* AP51-Light */
134 case 0x87: /* AP51-Full */
135 return "Atheros AR2315";
136 case 0x91: /* AP61 */
137 return "Atheros AR2317";
138 }
139 return ("Atheros AR531X");
140 }
141
142 void
143 ar531x_wdog(uint32_t period)
144 {
145
146 if (period == 0) {
147 PUTSYSREG(AR5315_SYSREG_WDOG_CTL, AR5315_WDOG_CTL_IGNORE);
148 PUTSYSREG(AR5315_SYSREG_WDOG_TIMER, 0);
149 } else {
150 PUTSYSREG(AR5315_SYSREG_WDOG_TIMER, period);
151 PUTSYSREG(AR5315_SYSREG_WDOG_CTL, AR5315_WDOG_CTL_RESET);
152 }
153 }
154
155 void
156 ar531x_businit(void)
157 {
158 /*
159 * XXX: clear COP0 config bits 0 and 1 -- Linux sets KSEG0 to either
160 * 0 or 4. Why does it do this? It is implementation defined...
161 */
162 mips3_cp0_config_write(mips3_cp0_config_read() & ~0x3);
163
164 PUTSYSREG(AR5315_SYSREG_AHB_ERR0, AR5315_AHB_ERROR_DET);
165 GETSYSREG(AR5315_SYSREG_AHB_ERR1);
166 }
167
168 static uint32_t
169 get_freq(uint32_t clkreg)
170 {
171 uint32_t freq = 0;
172 uint32_t clkctl, pllc, pllout, refdiv, fbdiv, div2, cpudiv;
173
174 static const int pll_divide_table[] = {
175 2, 3, 4, 6, 3,
176 /*
177 * these entries are bogus, but it avoids a possible
178 * bad table dereference
179 */
180 1, 1, 1
181 };
182 static const int pre_divide_table[] = {
183 1, 2, 4, 5
184 };
185
186 if (freq)
187 return freq;
188
189 pllc = GETSYSREG(AR5315_SYSREG_PLLC_CTL);
190 clkctl = GETSYSREG(clkreg);
191
192 refdiv = pre_divide_table[AR5315_PLLC_REF_DIV(pllc)];
193 fbdiv = AR5315_PLLC_FB_DIV(pllc);
194 div2 = (AR5315_PLLC_DIV_2(pllc) + 1) * 2; /* results in 2 or 4 */
195
196 cpudiv = AR5315_CLOCKCTL_DIV(clkctl);
197 cpudiv = cpudiv ? (cpudiv * 2) : 1;
198
199 /* 40MHz reference clk, reference and feedback dividers */
200 pllout = (40000000 / refdiv) * div2 * fbdiv;
201
202 switch (AR5315_CLOCKCTL_SELECT(clkctl)) {
203 case 0:
204 case 1:
205 /* CLKM select */
206 pllout /= pll_divide_table[AR5315_PLLC_CLKM(pllc)];
207 break;
208 case 2:
209 /* CLKC select */
210 pllout /= pll_divide_table[AR5315_PLLC_CLKC(pllc)];
211 break;
212 default:
213 /* ref_clk select */
214 pllout = 40000000; /* use original reference clock */
215 break;
216 }
217
218 freq = pllout/(cpudiv);
219
220 return (freq);
221 }
222
223 uint32_t
224 ar531x_cpu_freq(void)
225 {
226 static uint32_t freq = 0;
227 if (freq == 0)
228 freq = get_freq(AR5315_SYSREG_CPUCLK);
229 return (freq);
230 }
231
232 uint32_t
233 ar531x_bus_freq(void)
234 {
235 static uint32_t freq = 0;
236 if (freq == 0)
237 freq = get_freq(AR5315_SYSREG_AMBACLK);
238 return (freq);
239 }
240
241 static void
242 addprop_data(struct device *dev, const char *name, const uint8_t *data,
243 int len)
244 {
245 prop_data_t pd;
246 pd = prop_data_create_data(data, len);
247 KASSERT(pd != NULL);
248 if (prop_dictionary_set(device_properties(dev), name, pd) == false) {
249 printf("WARNING: unable to set %s property for %s\n",
250 name, device_xname(dev));
251 }
252 prop_object_release(pd);
253 }
254
255 static void
256 addprop_integer(struct device *dev, const char *name, uint32_t val)
257 {
258 prop_number_t pn;
259 pn = prop_number_create_integer(val);
260 KASSERT(pn != NULL);
261 if (prop_dictionary_set(device_properties(dev), name, pn) == false) {
262 printf("WARNING: unable to set %s property for %s",
263 name, device_xname(dev));
264 }
265 prop_object_release(pn);
266 }
267
268 void
269 ar531x_device_register(struct device *dev, void *aux)
270 {
271 struct arbus_attach_args *aa = aux;
272 const struct ar531x_boarddata *info;
273
274 info = ar531x_board_info();
275 if (info == NULL) {
276 /* nothing known about this board! */
277 return;
278 }
279
280 /*
281 * We don't ever know the boot device. But that's because the
282 * firmware only loads from the network.
283 */
284
285 /* Fetch the MAC addresses. */
286 if (device_is_a(dev, "ae")) {
287 const uint8_t *enet;
288
289 if (aa->aa_addr == AR5315_ENET_BASE)
290 enet = info->enet0Mac;
291 else
292 return;
293
294 addprop_data(dev, "mac-addr", enet, ETHER_ADDR_LEN);
295 }
296
297 if (device_is_a(dev, "ath")) {
298 const uint8_t *enet;
299
300 if (aa->aa_addr == AR5315_WLAN_BASE)
301 enet = info->wlan0Mac;
302 else
303 return;
304
305 addprop_data(dev, "mac-addr", enet, ETHER_ADDR_LEN);
306
307 addprop_integer(dev, "wmac-rev",
308 GETSYSREG(AR5315_SYSREG_SREV));
309 }
310
311 if (device_is_a(dev, "com")) {
312 addprop_integer(dev, "frequency", ar531x_bus_freq());
313 }
314
315 if (device_is_a(dev, "argpio")) {
316 if (info->config & BD_RSTFACTORY) {
317 addprop_integer(dev, "reset-pin",
318 info->resetConfigGpio);
319 }
320 if (info->config & BD_SYSLED) {
321 addprop_integer(dev, "sysled-pin",
322 info->sysLedGpio);
323 }
324 }
325 }
326
327 const struct ar531x_device *
328 ar531x_get_devices(void)
329 {
330 const static struct ar531x_device devices[] = {
331 {
332 "com",
333 AR5315_UART_BASE, 0x1000,
334 AR5315_CPU_IRQ_MISC, AR5315_MISC_IRQ_UART,
335 0, 0, 0
336 },
337 {
338 "ae",
339 AR5315_ENET_BASE, 0x100000,
340 AR5315_CPU_IRQ_ENET, -1,
341 0, 0, 0
342 },
343 {
344 "ath",
345 AR5315_WLAN_BASE, 0x100000,
346 AR5315_CPU_IRQ_WLAN, -1,
347 0, 0, 0
348 },
349 {
350 "arspi",
351 AR5315_SPI_BASE, 0x10,
352 AR5315_CPU_IRQ_MISC, AR5315_MISC_IRQ_SPI,
353 0, 0, 0
354 },
355 { NULL }
356 };
357
358 return devices;
359 }
360
361 int
362 ar531x_enable_device(const struct ar531x_device *dev)
363 {
364 if (dev->addr == AR5315_WLAN_BASE) {
365 /* enable arbitration for wlan */
366 PUTSYSREG(AR5315_SYSREG_AHB_ARB_CTL,
367 GETSYSREG(AR5315_SYSREG_AHB_ARB_CTL) | AR5315_ARB_WLAN);
368
369 /* set WLAN for big endian */
370 PUTSYSREG(AR5315_SYSREG_ENDIAN,
371 GETSYSREG(AR5315_SYSREG_ENDIAN) | AR5315_ENDIAN_WLAN);
372
373 /* wake up the mac */
374 PUTPCIREG(AR5315_PCI_MAC_SCR,
375 (GETPCIREG(AR5315_PCI_MAC_SCR) & ~PCI_MAC_SCR_SLM_MASK) |
376 PCI_MAC_SCR_SLM_FWAKE);
377
378 /* wait for it to wake up */
379 while (GETPCIREG(AR5315_PCI_MAC_PCICFG) &
380 PCI_MAC_PCICFG_SPWR_DN);
381 }
382 return 0;
383 }
384