1 /* $NetBSD: ar5315.c,v 1.5 2008/01/23 05:23:59 dyoung Exp $ */
4 * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
5 * Copyright (c) 2006 Garrett D'Amore.
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
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
50 #include <sys/cdefs.h>
51 __KERNEL_RCSID(0, "$NetBSD: ar5315.c,v 1.5 2008/01/23 05:23:59 dyoung Exp $");
56 #include "opt_memsize.h"
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/kernel.h>
61 #include <sys/device.h>
63 #include <mips/cache.h>
64 #include <mips/locore.h>
65 #include <mips/cpuregs.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)
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
;
102 rw
= (memcfg
& AR5315_MEM_CFG_ROW_WIDTH_MASK
) >>
103 AR5315_MEM_CFG_ROW_WIDTH_SHIFT
;
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
;
112 /* not too sure about this math, but it _seems_ to add up */
113 memsize
= (1 << cw
) * (1 << rw
) * dw
;
115 printf("SDRAM_MEM_CFG =%x, cw=%d rw=%d dw=%d xmemsize=%d\n", memcfg
,
116 cw
, rw
, dw
, memsize
);
121 /* compile time value forced */
129 uint16_t rev
= GETSYSREG(AR5315_SYSREG_SREV
);
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");
146 ar531x_wdog(uint32_t period
)
150 PUTSYSREG(AR5315_SYSREG_WDOG_CTL
, AR5315_WDOG_CTL_IGNORE
);
151 PUTSYSREG(AR5315_SYSREG_WDOG_TIMER
, 0);
153 PUTSYSREG(AR5315_SYSREG_WDOG_TIMER
, period
);
154 PUTSYSREG(AR5315_SYSREG_WDOG_CTL
, AR5315_WDOG_CTL_RESET
);
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
);
172 get_freq(uint32_t clkreg
)
175 uint32_t clkctl
, pllc
, pllout
, refdiv
, fbdiv
, div2
, cpudiv
;
177 static const int pll_divide_table
[] = {
180 * these entries are bogus, but it avoids a possible
181 * bad table dereference
185 static const int pre_divide_table
[] = {
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
)) {
209 pllout
/= pll_divide_table
[AR5315_PLLC_CLKM(pllc
)];
213 pllout
/= pll_divide_table
[AR5315_PLLC_CLKC(pllc
)];
217 pllout
= 40000000; /* use original reference clock */
221 freq
= pllout
/(cpudiv
);
227 ar531x_cpu_freq(void)
229 static uint32_t freq
= 0;
231 freq
= get_freq(AR5315_SYSREG_CPUCLK
);
236 ar531x_bus_freq(void)
238 static uint32_t freq
= 0;
240 freq
= get_freq(AR5315_SYSREG_AMBACLK
);
245 addprop_data(struct device
*dev
, const char *name
, const uint8_t *data
,
249 pd
= prop_data_create_data(data
, len
);
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
);
259 addprop_integer(struct device
*dev
, const char *name
, uint32_t val
)
262 pn
= prop_number_create_integer(val
);
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
);
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();
279 /* nothing known about this board! */
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")) {
292 if (aa
->aa_addr
== AR5315_ENET_BASE
)
293 enet
= info
->enet0Mac
;
297 addprop_data(dev
, "mac-addr", enet
, ETHER_ADDR_LEN
);
300 if (device_is_a(dev
, "ath")) {
303 if (aa
->aa_addr
== AR5315_WLAN_BASE
)
304 enet
= info
->wlan0Mac
;
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",
330 const struct ar531x_device
*
331 ar531x_get_devices(void)
333 const static struct ar531x_device devices
[] = {
336 AR5315_UART_BASE
, 0x1000,
337 AR5315_CPU_IRQ_MISC
, AR5315_MISC_IRQ_UART
,
342 AR5315_ENET_BASE
, 0x100000,
343 AR5315_CPU_IRQ_ENET
, -1,
348 AR5315_WLAN_BASE
, 0x100000,
349 AR5315_CPU_IRQ_WLAN
, -1,
354 AR5315_SPI_BASE
, 0x10,
355 AR5315_CPU_IRQ_MISC
, AR5315_MISC_IRQ_SPI
,
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
);