1 /* $NetBSD: ar5315.c,v 1.5 2008/01/23 05:23:59 dyoung 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.5 2008/01/23 05:23:59 dyoung 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 #include <sys/device.h> 62 63 #include <mips/cache.h> 64 #include <mips/locore.h> 65 #include <mips/cpuregs.h> 66 67 #include <net/if.h> 68 #include <net/if_ether.h> 69 70 #include <prop/proplib.h> 71 72 #include <contrib/dev/ath/ah_soc.h> /* XXX really doesn't belong in hal */ 73 74 #include <mips/atheros/include/ar5315reg.h> 75 #include <mips/atheros/include/ar531xvar.h> 76 #include <mips/atheros/include/arbusvar.h> 77 78 #include <machine/locore.h> 79 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) 87 88 uint32_t 89 ar531x_memsize(void) 90 { 91 #ifndef MEMSIZE 92 uint32_t memsize = 0; 93 uint32_t memcfg, cw, rw, dw; 94 95 /* 96 * Determine the memory size. We query the board info. 97 */ 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; 105 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 */ 111 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 118 119 return (memsize); 120 #else 121 /* compile time value forced */ 122 return MEMSIZE; 123 #endif 124 } 125 126 const char * 127 ar531x_cpuname(void) 128 { 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"; 141 } 142 return ("Atheros AR531X"); 143 } 144 145 void 146 ar531x_wdog(uint32_t period) 147 { 148 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); 155 } 156 } 157 158 void 159 ar531x_businit(void) 160 { 161 /* 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... 164 */ 165 mips3_cp0_config_write(mips3_cp0_config_read() & ~0x3); 166 167 PUTSYSREG(AR5315_SYSREG_AHB_ERR0, AR5315_AHB_ERROR_DET); 168 GETSYSREG(AR5315_SYSREG_AHB_ERR1); 169 } 170 171 static uint32_t 172 get_freq(uint32_t clkreg) 173 { 174 uint32_t freq = 0; 175 uint32_t clkctl, pllc, pllout, refdiv, fbdiv, div2, cpudiv; 176 177 static const int pll_divide_table[] = { 178 2, 3, 4, 6, 3, 179 /* 180 * these entries are bogus, but it avoids a possible 181 * bad table dereference 182 */ 183 1, 1, 1 184 }; 185 static const int pre_divide_table[] = { 186 1, 2, 4, 5 187 }; 188 189 if (freq) 190 return freq; 191 192 pllc = GETSYSREG(AR5315_SYSREG_PLLC_CTL); 193 clkctl = GETSYSREG(clkreg); 194 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 */ 198 199 cpudiv = AR5315_CLOCKCTL_DIV(clkctl); 200 cpudiv = cpudiv ? (cpudiv * 2) : 1; 201 202 /* 40MHz reference clk, reference and feedback dividers */ 203 pllout = (40000000 / refdiv) * div2 * fbdiv; 204 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; 219 } 220 221 freq = pllout/(cpudiv); 222 223 return (freq); 224 } 225 226 uint32_t 227 ar531x_cpu_freq(void) 228 { 229 static uint32_t freq = 0; 230 if (freq == 0) 231 freq = get_freq(AR5315_SYSREG_CPUCLK); 232 return (freq); 233 } 234 235 uint32_t 236 ar531x_bus_freq(void) 237 { 238 static uint32_t freq = 0; 239 if (freq == 0) 240 freq = get_freq(AR5315_SYSREG_AMBACLK); 241 return (freq); 242 } 243 244 static void 245 addprop_data(struct device *dev, const char *name, const uint8_t *data, 246 int len) 247 { 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)); 254 } 255 prop_object_release(pd); 256 } 257 258 static void 259 addprop_integer(struct device *dev, const char *name, uint32_t val) 260 { 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)); 267 } 268 prop_object_release(pn); 269 } 270 271 void 272 ar531x_device_register(struct device *dev, void *aux) 273 { 274 struct arbus_attach_args *aa = aux; 275 const struct ar531x_boarddata *info; 276 277 info = ar531x_board_info(); 278 if (info == NULL) { 279 /* nothing known about this board! */ 280 return; 281 } 282 283 /* 284 * We don't ever know the boot device. But that's because the 285 * firmware only loads from the network. 286 */ 287 288 /* Fetch the MAC addresses. */ 289 if (device_is_a(dev, "ae")) { 290 const uint8_t *enet; 291 292 if (aa->aa_addr == AR5315_ENET_BASE) 293 enet = info->enet0Mac; 294 else 295 return; 296 297 addprop_data(dev, "mac-addr", enet, ETHER_ADDR_LEN); 298 } 299 300 if (device_is_a(dev, "ath")) { 301 const uint8_t *enet; 302 303 if (aa->aa_addr == AR5315_WLAN_BASE) 304 enet = info->wlan0Mac; 305 else 306 return; 307 308 addprop_data(dev, "mac-addr", enet, ETHER_ADDR_LEN); 309 310 addprop_integer(dev, "wmac-rev", 311 GETSYSREG(AR5315_SYSREG_SREV)); 312 } 313 314 if (device_is_a(dev, "com")) { 315 addprop_integer(dev, "frequency", ar531x_bus_freq()); 316 } 317 318 if (device_is_a(dev, "argpio")) { 319 if (info->config & BD_RSTFACTORY) { 320 addprop_integer(dev, "reset-pin", 321 info->resetConfigGpio); 322 } 323 if (info->config & BD_SYSLED) { 324 addprop_integer(dev, "sysled-pin", 325 info->sysLedGpio); 326 } 327 } 328 } 329 330 const struct ar531x_device * 331 ar531x_get_devices(void) 332 { 333 const static struct ar531x_device devices[] = { 334 { 335 "com", 336 AR5315_UART_BASE, 0x1000, 337 AR5315_CPU_IRQ_MISC, AR5315_MISC_IRQ_UART, 338 0, 0, 0 339 }, 340 { 341 "ae", 342 AR5315_ENET_BASE, 0x100000, 343 AR5315_CPU_IRQ_ENET, -1, 344 0, 0, 0 345 }, 346 { 347 "ath", 348 AR5315_WLAN_BASE, 0x100000, 349 AR5315_CPU_IRQ_WLAN, -1, 350 0, 0, 0 351 }, 352 { 353 "arspi", 354 AR5315_SPI_BASE, 0x10, 355 AR5315_CPU_IRQ_MISC, AR5315_MISC_IRQ_SPI, 356 0, 0, 0 357 }, 358 { NULL } 359 }; 360 361 return devices; 362 } 363 364 int 365 ar531x_enable_device(const struct ar531x_device *dev) 366 { 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); 371 372 /* set WLAN for big endian */ 373 PUTSYSREG(AR5315_SYSREG_ENDIAN, 374 GETSYSREG(AR5315_SYSREG_ENDIAN) | AR5315_ENDIAN_WLAN); 375 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); 380 381 /* wait for it to wake up */ 382 while (GETPCIREG(AR5315_PCI_MAC_PCICFG) & 383 PCI_MAC_PCICFG_SPWR_DN); 384 } 385 return 0; 386 } 387