ar5315.c revision 1.1 1 /* $NetBSD: ar5315.c,v 1.1 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 /*
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.1 2006/09/26 06:37:32 gdamore 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
84 uint32_t
85 ar531x_memsize(void)
86 {
87 uint32_t memsize;
88
89 /*
90 * Determine the memory size.
91 *
92 * NB: we allow compile time override
93 */
94 #if defined(MEMSIZE)
95 memsize = MEMSIZE;
96 #else
97 /* assume default value, may or may not be reasonable */
98 /* XXX: it would be nice if this could autodetect */
99 memsize = (8 << 20);
100 #endif
101
102 return (memsize);
103 }
104
105 const char *
106 ar531x_cpuname(void)
107 {
108 uint16_t rev = GETSYSREG(AR5315_SYSREG_SREV);
109 switch (rev) {
110 case 0x52: /* AP30 */
111 case 0x57: /* AP31 */
112 return "Atheros AR5312";
113 case 0x58: /* AP43 */
114 return "Atheros AR2313";
115 case 0x86: /* AP51-Light */
116 case 0x87: /* AP51-Full */
117 return "Atheros AR2315";
118 case 0x91: /* AP61 */
119 return "Atheros AR2317";
120 }
121 return ("Atheros AR531X");
122 }
123
124 void
125 ar531x_wdog(uint32_t period)
126 {
127
128 if (period == 0) {
129 PUTSYSREG(AR5315_SYSREG_WDOG_CTL, AR5315_WDOG_CTL_IGNORE);
130 PUTSYSREG(AR5315_SYSREG_WDOG_TIMER, 0);
131 } else {
132 PUTSYSREG(AR5315_SYSREG_WDOG_TIMER, period);
133 PUTSYSREG(AR5315_SYSREG_WDOG_CTL, AR5315_WDOG_CTL_RESET);
134 }
135 }
136
137 void
138 ar531x_businit(void)
139 {
140 /*
141 * XXX: clear COP0 config bits 0 and 1 -- Linux sets KSEG0 to either
142 * 0 or 4. Why does it do this? It is implementation defined...
143 */
144 mips3_cp0_config_write(mips3_cp0_config_read() & ~0x3);
145
146 PUTSYSREG(AR5315_SYSREG_AHB_ERR0, AR5315_AHB_ERROR_DET);
147 GETSYSREG(AR5315_SYSREG_AHB_ERR1);
148 }
149
150 static uint32_t
151 get_freq(uint32_t clkreg)
152 {
153 uint32_t freq = 0;
154 uint32_t clkctl, pllc, pllout, refdiv, fbdiv, div2, cpudiv;
155
156 static const int pll_divide_table[] = {
157 2, 3, 4, 6, 3,
158 /*
159 * these entries are bogus, but it avoids a possible
160 * bad table dereference
161 */
162 1, 1, 1
163 };
164 static const int pre_divide_table[] = {
165 1, 2, 4, 5
166 };
167
168 if (freq)
169 return freq;
170
171 pllc = GETSYSREG(AR5315_SYSREG_PLLC_CTL);
172 clkctl = GETSYSREG(clkreg);
173
174 refdiv = pre_divide_table[AR5315_PLLC_REF_DIV(pllc)];
175 fbdiv = AR5315_PLLC_FB_DIV(pllc);
176 div2 = (AR5315_PLLC_DIV_2(pllc) + 1) * 2; /* results in 2 or 4 */
177
178 cpudiv = AR5315_CLOCKCTL_DIV(clkctl);
179 cpudiv = cpudiv ? (cpudiv * 2) : 1;
180
181 /* 40MHz reference clk, reference and feedback dividers */
182 pllout = (40000000 / refdiv) * div2 * fbdiv;
183
184 switch (AR5315_CLOCKCTL_SELECT(clkctl)) {
185 case 0:
186 case 1:
187 /* CLKM select */
188 pllout /= pll_divide_table[AR5315_PLLC_CLKM(pllc)];
189 break;
190 case 2:
191 /* CLKC select */
192 pllout /= pll_divide_table[AR5315_PLLC_CLKC(pllc)];
193 break;
194 default:
195 /* ref_clk select */
196 pllout = 40000000; /* use original reference clock */
197 break;
198 }
199
200 freq = pllout/(cpudiv);
201
202 return (freq);
203 }
204
205 uint32_t
206 ar531x_cpu_freq(void)
207 {
208 static uint32_t freq = 0;
209 if (freq == 0)
210 freq = get_freq(AR5315_SYSREG_CPUCLK);
211 return (freq);
212 }
213
214 uint32_t
215 ar531x_bus_freq(void)
216 {
217 static uint32_t freq = 0;
218 if (freq == 0)
219 freq = get_freq(AR5315_SYSREG_AMBACLK);
220 return (freq);
221 }
222
223 static void
224 addprop_data(struct device *dev, const char *name, const uint8_t *data,
225 int len)
226 {
227 prop_data_t pd;
228 pd = prop_data_create_data(data, len);
229 KASSERT(pd != NULL);
230 if (prop_dictionary_set(device_properties(dev), name, pd) == FALSE) {
231 printf("WARNING: unable to set %s property for %s\n",
232 name, device_xname(dev));
233 }
234 prop_object_release(pd);
235 }
236
237 static void
238 addprop_integer(struct device *dev, const char *name, uint32_t val)
239 {
240 prop_number_t pn;
241 pn = prop_number_create_integer(val);
242 KASSERT(pn != NULL);
243 if (prop_dictionary_set(device_properties(dev), name, pn) == FALSE) {
244 printf("WARNING: unable to set %s property for %s",
245 name, device_xname(dev));
246 }
247 prop_object_release(pn);
248 }
249
250 void
251 ar531x_device_register(struct device *dev, void *aux)
252 {
253 struct arbus_attach_args *aa = aux;
254 const struct ar531x_boarddata *info;
255
256 info = ar531x_board_info();
257 if (info == NULL) {
258 /* nothing known about this board! */
259 return;
260 }
261
262 /*
263 * We don't ever know the boot device. But that's because the
264 * firmware only loads from the network.
265 */
266
267 /* Fetch the MAC addresses. */
268 if (device_is_a(dev, "ae")) {
269 const uint8_t *enet;
270
271 if (aa->aa_addr == AR5315_ENET_BASE)
272 enet = info->enet0Mac;
273 else
274 return;
275
276 addprop_data(dev, "mac-addr", enet, ETHER_ADDR_LEN);
277 }
278
279 if (device_is_a(dev, "ath")) {
280 const uint8_t *enet;
281
282 if (aa->aa_addr == AR5315_WLAN_BASE)
283 enet = info->wlan0Mac;
284 else
285 return;
286
287 addprop_data(dev, "mac-addr", enet, ETHER_ADDR_LEN);
288
289 addprop_integer(dev, "wmac-rev",
290 GETSYSREG(AR5315_SYSREG_SREV));
291 }
292
293 if (device_is_a(dev, "com")) {
294 addprop_integer(dev, "frequency", ar531x_bus_freq());
295 }
296
297 if (device_is_a(dev, "argpio")) {
298 if (info->config & BD_RSTFACTORY) {
299 addprop_integer(dev, "reset-pin",
300 info->resetConfigGpio);
301 }
302 if (info->config & BD_SYSLED) {
303 addprop_integer(dev, "sysled-pin",
304 info->sysLedGpio);
305 }
306 }
307 }
308
309 const struct ar531x_device *
310 ar531x_get_devices(void)
311 {
312 const static struct ar531x_device devices[] = {
313 {
314 "com",
315 AR5315_UART_BASE, 0x1000,
316 AR5315_CPU_IRQ_MISC, AR5315_MISC_IRQ_UART,
317 0, 0, 0
318 },
319 {
320 "ae",
321 AR5315_ENET_BASE, 0x100000,
322 AR5315_CPU_IRQ_ENET, -1,
323 0, 0, 0
324 },
325 {
326 "ath",
327 AR5315_WLAN_BASE, 0x100000,
328 AR5315_CPU_IRQ_WLAN, -1,
329 0, 0, 0
330 },
331 { NULL }
332 };
333
334 return devices;
335 }
336
337 int
338 ar531x_enable_device(const struct ar531x_device *dev)
339 {
340 if (dev->addr == AR5315_WLAN_BASE) {
341 /* enable arbitration for wlan */
342 PUTSYSREG(AR5315_SYSREG_AHB_ARB_CTL,
343 GETSYSREG(AR5315_SYSREG_AHB_ARB_CTL) | AR5315_ARB_WLAN);
344
345 /* set WLAN for big endian */
346 PUTSYSREG(AR5315_SYSREG_ENDIAN,
347 GETSYSREG(AR5315_SYSREG_ENDIAN) | AR5315_ENDIAN_WLAN);
348
349 /* wake up the mac */
350 PUTPCIREG(AR5315_PCI_MAC_SCR,
351 (GETPCIREG(AR5315_PCI_MAC_SCR) & ~PCI_MAC_SCR_SLM_MASK) |
352 PCI_MAC_SCR_SLM_FWAKE);
353
354 /* wait for it to wake up */
355 while (GETPCIREG(AR5315_PCI_MAC_PCICFG) &
356 PCI_MAC_PCICFG_SPWR_DN);
357 }
358 return 0;
359 }
360