No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / mips / atheros / ar5315.c
blobe876f8818ef5af5b172949cb4726fb4b810cc05a
1 /* $NetBSD: ar5315.c,v 1.5 2008/01/23 05:23:59 dyoung Exp $ */
3 /*
4 * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
5 * Copyright (c) 2006 Garrett D'Amore.
6 * All rights reserved.
8 * Portions of this code were written by Garrett D'Amore for the
9 * Champaign-Urbana Community Wireless Network Project.
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.
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.
46 * This file includes a bunch of implementation specific bits for
47 * AR5315, which differs these from other members of the AR531X
48 * family.
50 #include <sys/cdefs.h>
51 __KERNEL_RCSID(0, "$NetBSD: ar5315.c,v 1.5 2008/01/23 05:23:59 dyoung Exp $");
53 #include "opt_ddb.h"
54 #include "opt_kgdb.h"
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 #include <sys/device.h>
63 #include <mips/cache.h>
64 #include <mips/locore.h>
65 #include <mips/cpuregs.h>
67 #include <net/if.h>
68 #include <net/if_ether.h>
70 #include <prop/proplib.h>
72 #include <ah_soc.h> /* XXX really doesn't belong in hal */
74 #include <mips/atheros/include/ar5315reg.h>
75 #include <mips/atheros/include/ar531xvar.h>
76 #include <mips/atheros/include/arbusvar.h>
78 #include <machine/locore.h>
80 /* helper macro for accessing system registers without bus space */
81 #define REGVAL(x) *((volatile uint32_t *)(MIPS_PHYS_TO_KSEG1((x))))
82 #define GETSYSREG(x) REGVAL((x) + AR5315_SYSREG_BASE)
83 #define PUTSYSREG(x,v) (REGVAL((x) + AR5315_SYSREG_BASE)) = (v)
84 #define GETPCIREG(x) REGVAL((x) + AR5315_PCI_BASE)
85 #define PUTPCIREG(x,v) (REGVAL((x) + AR5315_PCI_BASE)) = (v)
86 #define GETSDRAMREG(x) REGVAL((x) + AR5315_SDRAMCTL_BASE)
88 uint32_t
89 ar531x_memsize(void)
91 #ifndef MEMSIZE
92 uint32_t memsize = 0;
93 uint32_t memcfg, cw, rw, dw;
96 * Determine the memory size. We query the board info.
98 memcfg = GETSDRAMREG(AR5315_SDRAMCTL_MEM_CFG);
99 cw = (memcfg & AR5315_MEM_CFG_COL_WIDTH_MASK) >>
100 AR5315_MEM_CFG_COL_WIDTH_SHIFT;
101 cw += 1;
102 rw = (memcfg & AR5315_MEM_CFG_ROW_WIDTH_MASK) >>
103 AR5315_MEM_CFG_ROW_WIDTH_SHIFT;
104 rw += 1;
106 /* XXX: according to redboot, this could be wrong if DDR SDRAM */
107 dw = (memcfg & AR5315_MEM_CFG_DATA_WIDTH_MASK) >>
108 AR5315_MEM_CFG_DATA_WIDTH_SHIFT;
109 dw += 1;
110 dw *= 8; /* bits */
112 /* not too sure about this math, but it _seems_ to add up */
113 memsize = (1 << cw) * (1 << rw) * dw;
114 #if 0
115 printf("SDRAM_MEM_CFG =%x, cw=%d rw=%d dw=%d xmemsize=%d\n", memcfg,
116 cw, rw, dw, memsize);
117 #endif
119 return (memsize);
120 #else
121 /* compile time value forced */
122 return MEMSIZE;
123 #endif
126 const char *
127 ar531x_cpuname(void)
129 uint16_t rev = GETSYSREG(AR5315_SYSREG_SREV);
130 switch (rev) {
131 case 0x52: /* AP30 */
132 case 0x57: /* AP31 */
133 return "Atheros AR5312";
134 case 0x58: /* AP43 */
135 return "Atheros AR2313";
136 case 0x86: /* AP51-Light */
137 case 0x87: /* AP51-Full */
138 return "Atheros AR2315";
139 case 0x91: /* AP61 */
140 return "Atheros AR2317";
142 return ("Atheros AR531X");
145 void
146 ar531x_wdog(uint32_t period)
149 if (period == 0) {
150 PUTSYSREG(AR5315_SYSREG_WDOG_CTL, AR5315_WDOG_CTL_IGNORE);
151 PUTSYSREG(AR5315_SYSREG_WDOG_TIMER, 0);
152 } else {
153 PUTSYSREG(AR5315_SYSREG_WDOG_TIMER, period);
154 PUTSYSREG(AR5315_SYSREG_WDOG_CTL, AR5315_WDOG_CTL_RESET);
158 void
159 ar531x_businit(void)
162 * XXX: clear COP0 config bits 0 and 1 -- Linux sets KSEG0 to either
163 * 0 or 4. Why does it do this? It is implementation defined...
165 mips3_cp0_config_write(mips3_cp0_config_read() & ~0x3);
167 PUTSYSREG(AR5315_SYSREG_AHB_ERR0, AR5315_AHB_ERROR_DET);
168 GETSYSREG(AR5315_SYSREG_AHB_ERR1);
171 static uint32_t
172 get_freq(uint32_t clkreg)
174 uint32_t freq = 0;
175 uint32_t clkctl, pllc, pllout, refdiv, fbdiv, div2, cpudiv;
177 static const int pll_divide_table[] = {
178 2, 3, 4, 6, 3,
180 * these entries are bogus, but it avoids a possible
181 * bad table dereference
183 1, 1, 1
185 static const int pre_divide_table[] = {
186 1, 2, 4, 5
189 if (freq)
190 return freq;
192 pllc = GETSYSREG(AR5315_SYSREG_PLLC_CTL);
193 clkctl = GETSYSREG(clkreg);
195 refdiv = pre_divide_table[AR5315_PLLC_REF_DIV(pllc)];
196 fbdiv = AR5315_PLLC_FB_DIV(pllc);
197 div2 = (AR5315_PLLC_DIV_2(pllc) + 1) * 2; /* results in 2 or 4 */
199 cpudiv = AR5315_CLOCKCTL_DIV(clkctl);
200 cpudiv = cpudiv ? (cpudiv * 2) : 1;
202 /* 40MHz reference clk, reference and feedback dividers */
203 pllout = (40000000 / refdiv) * div2 * fbdiv;
205 switch (AR5315_CLOCKCTL_SELECT(clkctl)) {
206 case 0:
207 case 1:
208 /* CLKM select */
209 pllout /= pll_divide_table[AR5315_PLLC_CLKM(pllc)];
210 break;
211 case 2:
212 /* CLKC select */
213 pllout /= pll_divide_table[AR5315_PLLC_CLKC(pllc)];
214 break;
215 default:
216 /* ref_clk select */
217 pllout = 40000000; /* use original reference clock */
218 break;
221 freq = pllout/(cpudiv);
223 return (freq);
226 uint32_t
227 ar531x_cpu_freq(void)
229 static uint32_t freq = 0;
230 if (freq == 0)
231 freq = get_freq(AR5315_SYSREG_CPUCLK);
232 return (freq);
235 uint32_t
236 ar531x_bus_freq(void)
238 static uint32_t freq = 0;
239 if (freq == 0)
240 freq = get_freq(AR5315_SYSREG_AMBACLK);
241 return (freq);
244 static void
245 addprop_data(struct device *dev, const char *name, const uint8_t *data,
246 int len)
248 prop_data_t pd;
249 pd = prop_data_create_data(data, len);
250 KASSERT(pd != NULL);
251 if (prop_dictionary_set(device_properties(dev), name, pd) == false) {
252 printf("WARNING: unable to set %s property for %s\n",
253 name, device_xname(dev));
255 prop_object_release(pd);
258 static void
259 addprop_integer(struct device *dev, const char *name, uint32_t val)
261 prop_number_t pn;
262 pn = prop_number_create_integer(val);
263 KASSERT(pn != NULL);
264 if (prop_dictionary_set(device_properties(dev), name, pn) == false) {
265 printf("WARNING: unable to set %s property for %s",
266 name, device_xname(dev));
268 prop_object_release(pn);
271 void
272 ar531x_device_register(struct device *dev, void *aux)
274 struct arbus_attach_args *aa = aux;
275 const struct ar531x_boarddata *info;
277 info = ar531x_board_info();
278 if (info == NULL) {
279 /* nothing known about this board! */
280 return;
284 * We don't ever know the boot device. But that's because the
285 * firmware only loads from the network.
288 /* Fetch the MAC addresses. */
289 if (device_is_a(dev, "ae")) {
290 const uint8_t *enet;
292 if (aa->aa_addr == AR5315_ENET_BASE)
293 enet = info->enet0Mac;
294 else
295 return;
297 addprop_data(dev, "mac-addr", enet, ETHER_ADDR_LEN);
300 if (device_is_a(dev, "ath")) {
301 const uint8_t *enet;
303 if (aa->aa_addr == AR5315_WLAN_BASE)
304 enet = info->wlan0Mac;
305 else
306 return;
308 addprop_data(dev, "mac-addr", enet, ETHER_ADDR_LEN);
310 addprop_integer(dev, "wmac-rev",
311 GETSYSREG(AR5315_SYSREG_SREV));
314 if (device_is_a(dev, "com")) {
315 addprop_integer(dev, "frequency", ar531x_bus_freq());
318 if (device_is_a(dev, "argpio")) {
319 if (info->config & BD_RSTFACTORY) {
320 addprop_integer(dev, "reset-pin",
321 info->resetConfigGpio);
323 if (info->config & BD_SYSLED) {
324 addprop_integer(dev, "sysled-pin",
325 info->sysLedGpio);
330 const struct ar531x_device *
331 ar531x_get_devices(void)
333 const static struct ar531x_device devices[] = {
335 "com",
336 AR5315_UART_BASE, 0x1000,
337 AR5315_CPU_IRQ_MISC, AR5315_MISC_IRQ_UART,
338 0, 0, 0
341 "ae",
342 AR5315_ENET_BASE, 0x100000,
343 AR5315_CPU_IRQ_ENET, -1,
344 0, 0, 0
347 "ath",
348 AR5315_WLAN_BASE, 0x100000,
349 AR5315_CPU_IRQ_WLAN, -1,
350 0, 0, 0
353 "arspi",
354 AR5315_SPI_BASE, 0x10,
355 AR5315_CPU_IRQ_MISC, AR5315_MISC_IRQ_SPI,
356 0, 0, 0
358 { NULL }
361 return devices;
365 ar531x_enable_device(const struct ar531x_device *dev)
367 if (dev->addr == AR5315_WLAN_BASE) {
368 /* enable arbitration for wlan */
369 PUTSYSREG(AR5315_SYSREG_AHB_ARB_CTL,
370 GETSYSREG(AR5315_SYSREG_AHB_ARB_CTL) | AR5315_ARB_WLAN);
372 /* set WLAN for big endian */
373 PUTSYSREG(AR5315_SYSREG_ENDIAN,
374 GETSYSREG(AR5315_SYSREG_ENDIAN) | AR5315_ENDIAN_WLAN);
376 /* wake up the mac */
377 PUTPCIREG(AR5315_PCI_MAC_SCR,
378 (GETPCIREG(AR5315_PCI_MAC_SCR) & ~PCI_MAC_SCR_SLM_MASK) |
379 PCI_MAC_SCR_SLM_FWAKE);
381 /* wait for it to wake up */
382 while (GETPCIREG(AR5315_PCI_MAC_PCICFG) &
383 PCI_MAC_PCICFG_SPWR_DN);
385 return 0;