1 /* $NetBSD: ar5312.c,v 1.9 2012/10/27 17:18:01 chs 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 * This file includes a bunch of implementation specific bits for 46 * AR5312, which differents these from other members of the AR5315 47 * family. 48 */ 49 #include "opt_ddb.h" 50 #include "opt_kgdb.h" 51 #define __INTR_PRIVATE 52 53 #include "opt_memsize.h" 54 #include <sys/param.h> 55 #include <sys/systm.h> 56 #include <sys/device.h> 57 #include <sys/kernel.h> 58 #include <sys/buf.h> 59 60 #include <mips/cache.h> 61 #include <mips/locore.h> 62 #include <mips/cpuregs.h> 63 64 #include <sys/socket.h> /* these three just to get ETHER_ADDR_LEN(!) */ 65 #include <net/if.h> 66 #include <net/if_ether.h> 67 68 #include <prop/proplib.h> 69 70 #include <ah_soc.h> 71 72 #include <mips/atheros/include/platform.h> 73 #include <mips/atheros/include/arbusvar.h> 74 #include <mips/atheros/include/ar5312reg.h> 75 #include "com.h" 76 77 static uint32_t 78 ar5312_get_memsize(void) 79 { 80 uint32_t memsize; 81 uint32_t memcfg, bank0, bank1; 82 83 /* 84 * Determine the memory size as established by system 85 * firmware. 86 * 87 * NB: we allow compile time override 88 */ 89 #if defined(MEMSIZE) 90 memsize = MEMSIZE; 91 #else 92 memcfg = GETSDRAMREG(AR5312_SDRAMCTL_MEM_CFG1); 93 bank0 = __SHIFTOUT(memcfg, AR5312_MEM_CFG1_BANK0); 94 bank1 = __SHIFTOUT(memcfg, AR5312_MEM_CFG1_BANK1); 95 96 memsize = (bank0 ? (1 << (bank0 + 1)) : 0) + 97 (bank1 ? (1 << (bank1 + 1)) : 0); 98 memsize <<= 20; 99 #endif 100 101 return (memsize); 102 } 103 104 static void 105 ar5312_wdog_reload(uint32_t period) 106 { 107 108 if (period == 0) { 109 PUTSYSREG(AR5312_SYSREG_WDOG_CTL, AR5312_WDOG_CTL_IGNORE); 110 PUTSYSREG(AR5312_SYSREG_WDOG_TIMER, 0); 111 } else { 112 PUTSYSREG(AR5312_SYSREG_WDOG_TIMER, period); 113 PUTSYSREG(AR5312_SYSREG_WDOG_CTL, AR5312_WDOG_CTL_RESET); 114 } 115 } 116 117 static void 118 ar5312_bus_init(void) 119 { 120 /* 121 * Clear previous AHB errors 122 */ 123 GETSYSREG(AR5312_SYSREG_AHBPERR); 124 GETSYSREG(AR5312_SYSREG_AHBDMAE); 125 } 126 127 static void 128 ar5312_reset(void) 129 { 130 PUTSYSREG(AR5312_SYSREG_RESETCTL, AR5312_RESET_SYSTEM); 131 } 132 133 static void 134 ar5312_get_freqs(struct arfreqs *freqs) 135 { 136 const uint32_t wisoc = GETSYSREG(AR5312_SYSREG_REVISION); 137 138 uint32_t predivisor; 139 uint32_t multiplier; 140 141 /* 142 * This logic looks at the clock control register and 143 * determines the actual CPU frequency. These parts lack any 144 * kind of real-time clock on them, but the cpu clocks should 145 * be very accurate -- WiFi requires usec resolution timers. 146 */ 147 148 const uint32_t clockctl = GETSYSREG(AR5312_SYSREG_CLOCKCTL); 149 150 if (AR5312_REVISION_MAJOR(wisoc) == AR5312_REVISION_MAJ_AR2313) { 151 predivisor = __SHIFTOUT(clockctl, AR2313_CLOCKCTL_PREDIVIDE); 152 multiplier = __SHIFTOUT(clockctl, AR2313_CLOCKCTL_MULTIPLIER); 153 } else { 154 predivisor = __SHIFTOUT(clockctl, AR5312_CLOCKCTL_PREDIVIDE); 155 multiplier = __SHIFTOUT(clockctl, AR5312_CLOCKCTL_MULTIPLIER); 156 if (clockctl & AR5312_CLOCKCTL_DOUBLER) 157 multiplier <<= 1; 158 } 159 160 /* 161 * Note that the source clock involved here is a 40MHz. 162 */ 163 164 const uint32_t divisor = (0x5421 >> (predivisor * 4)) & 15; 165 166 const uint32_t cpufreq = (40000000 / divisor) * multiplier; 167 168 freqs->freq_cpu = cpufreq; 169 freqs->freq_bus = cpufreq / 4; 170 freqs->freq_mem = 0; 171 freqs->freq_ref = 40000000; 172 freqs->freq_pll = 40000000; 173 } 174 175 176 static void 177 addprop_data(device_t dev, const char *name, const uint8_t *data, int len) 178 { 179 prop_data_t pd; 180 pd = prop_data_create_data(data, len); 181 KASSERT(pd != NULL); 182 if (prop_dictionary_set(device_properties(dev), name, pd) == false) { 183 printf("WARNING: unable to set %s property for %s\n", 184 name, device_xname(dev)); 185 } 186 prop_object_release(pd); 187 } 188 189 static void 190 addprop_integer(device_t dev, const char *name, uint32_t val) 191 { 192 prop_number_t pn; 193 pn = prop_number_create_integer(val); 194 KASSERT(pn != NULL); 195 if (prop_dictionary_set(device_properties(dev), name, pn) == false) { 196 printf("WARNING: unable to set %s property for %s", 197 name, device_xname(dev)); 198 } 199 prop_object_release(pn); 200 } 201 202 static void 203 ar5312_device_register(device_t dev, void *aux) 204 { 205 const struct arbus_attach_args * const aa = aux; 206 207 if (device_is_a(dev, "com")) { 208 addprop_integer(dev, "frequency", atheros_get_bus_freq()); 209 } 210 211 const struct ar531x_boarddata * const info = atheros_get_board_info(); 212 if (info == NULL) { 213 /* nothing known about this board! */ 214 return; 215 } 216 217 /* 218 * We don't ever know the boot device. But that's because the 219 * firmware only loads from the network. 220 */ 221 222 /* Fetch the MAC addresses. */ 223 if (device_is_a(dev, "ae")) { 224 const uint8_t *enet; 225 226 if (aa->aa_addr == AR5312_ENET0_BASE) 227 enet = info->enet0Mac; 228 else if (aa->aa_addr == AR5312_ENET1_BASE) 229 enet = info->enet1Mac; 230 else 231 return; 232 233 addprop_data(dev, "mac-address", enet, ETHER_ADDR_LEN); 234 } 235 236 if (device_is_a(dev, "ath")) { 237 const uint8_t *enet; 238 239 if (aa->aa_addr == AR5312_WLAN0_BASE) 240 enet = info->wlan0Mac; 241 else if (aa->aa_addr == AR5312_WLAN1_BASE) 242 enet = info->wlan1Mac; 243 else 244 return; 245 246 addprop_data(dev, "mac-address", enet, ETHER_ADDR_LEN); 247 248 addprop_integer(dev, "wmac-rev", 249 AR5312_REVISION_WMAC(GETSYSREG(AR5312_SYSREG_REVISION))); 250 251 } 252 253 if (device_is_a(dev, "argpio")) { 254 if (info->config & BD_RSTFACTORY) { 255 addprop_integer(dev, "reset-pin", 256 info->resetConfigGpio); 257 } 258 if (info->config & BD_SYSLED) { 259 addprop_integer(dev, "sysled-pin", 260 info->sysLedGpio); 261 } 262 } 263 } 264 265 static int 266 ar5312_enable_device(const struct atheros_device *adv) 267 { 268 const struct ar531x_boarddata * const info = atheros_get_board_info(); 269 270 if (info != NULL 271 && adv->adv_mask && ((adv->adv_mask & info->config) == 0)) { 272 return -1; 273 } 274 if (adv->adv_reset) { 275 /* put device into reset */ 276 PUTSYSREG(AR5312_SYSREG_RESETCTL, 277 GETSYSREG(AR5312_SYSREG_RESETCTL) | adv->adv_reset); 278 279 delay(15000); /* XXX: tsleep? */ 280 281 /* take it out of reset */ 282 PUTSYSREG(AR5312_SYSREG_RESETCTL, 283 GETSYSREG(AR5312_SYSREG_RESETCTL) & ~adv->adv_reset); 284 285 delay(25); 286 } 287 if (adv->adv_enable) { 288 PUTSYSREG(AR5312_SYSREG_ENABLE, 289 GETSYSREG(AR5312_SYSREG_ENABLE) | adv->adv_enable); 290 } 291 return 0; 292 } 293 294 static void 295 ar5312_intr_init(void) 296 { 297 atheros_intr_init(); 298 } 299 300 static const struct atheros_device ar5312_devices[] = { 301 { 302 .adv_name = "ae", 303 .adv_addr = AR5312_ENET0_BASE, 304 .adv_size = 0x100000, 305 .adv_cirq = AR5312_IRQ_ENET0, 306 .adv_mirq = -1, 307 .adv_mask = AR5312_BOARD_CONFIG_ENET0, 308 .adv_reset = AR5312_RESET_ENET0 | AR5312_RESET_PHY0, 309 .adv_enable = AR5312_ENABLE_ENET0 310 }, { 311 .adv_name = "ae", 312 .adv_addr = AR5312_ENET1_BASE, 313 .adv_size = 0x100000, 314 .adv_cirq = AR5312_IRQ_ENET1, 315 .adv_mirq = -1, 316 .adv_mask = AR5312_BOARD_CONFIG_ENET1, 317 .adv_reset = AR5312_RESET_ENET1 | AR5312_RESET_PHY1, 318 .adv_enable = AR5312_ENABLE_ENET1 319 }, { 320 .adv_name = "com", 321 .adv_addr = AR5312_UART0_BASE, 322 .adv_size = 0x1000, 323 .adv_cirq = AR5312_IRQ_MISC, 324 .adv_mirq = AR5312_MISC_IRQ_UART0, 325 .adv_mask = AR5312_BOARD_CONFIG_UART0, 326 }, { 327 .adv_name = "com", 328 .adv_addr = AR5312_UART1_BASE, 329 .adv_size = 0x1000, 330 .adv_cirq = -1, 331 .adv_mirq = -1, 332 .adv_mask = AR5312_BOARD_CONFIG_UART1, 333 }, { 334 .adv_name = "ath", 335 .adv_addr = AR5312_WLAN0_BASE, 336 .adv_size = 0x100000, 337 .adv_cirq = AR5312_IRQ_WLAN0, 338 .adv_mirq = -1, 339 .adv_mask = AR5312_BOARD_CONFIG_WLAN0, 340 .adv_reset = AR5312_RESET_WLAN0 | AR5312_RESET_WARM_WLAN0_MAC 341 | AR5312_RESET_WARM_WLAN0_BB, 342 .adv_enable = AR5312_ENABLE_WLAN0 343 }, { 344 .adv_name = "ath", 345 .adv_addr = AR5312_WLAN1_BASE, 346 .adv_size = 0x100000, 347 .adv_cirq = AR5312_IRQ_WLAN1, 348 .adv_mirq = -1, 349 .adv_mask = AR5312_BOARD_CONFIG_WLAN1, 350 .adv_reset = AR5312_RESET_WLAN1 | AR5312_RESET_WARM_WLAN1_MAC 351 | AR5312_RESET_WARM_WLAN1_BB, 352 .adv_enable = AR5312_ENABLE_WLAN1 353 }, { 354 .adv_name = "athflash", 355 .adv_addr = AR5312_FLASH_BASE, 356 .adv_size = 0, 357 .adv_cirq = -1, 358 .adv_mirq = -1, 359 }, { 360 .adv_name = "argpio", 361 .adv_addr = AR5312_GPIO_BASE, 362 .adv_size = 0x1000, 363 .adv_cirq = AR5312_IRQ_MISC, 364 .adv_mirq = AR5312_MISC_IRQ_GPIO, 365 }, { 366 .adv_name = NULL 367 } 368 }; 369 370 static const struct ipl_sr_map ar5312_ipl_sr_map = { 371 .sr_bits = { 372 [IPL_NONE] = 0, 373 [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0, 374 [IPL_SOFTBIO] = MIPS_SOFT_INT_MASK_0, 375 [IPL_SOFTNET] = MIPS_SOFT_INT_MASK, 376 [IPL_SOFTSERIAL] = MIPS_SOFT_INT_MASK, 377 [IPL_VM] = MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0 378 | MIPS_INT_MASK_1 | MIPS_INT_MASK_2 379 | MIPS_INT_MASK_3, 380 [IPL_SCHED] = MIPS_INT_MASK, 381 [IPL_DDB] = MIPS_INT_MASK, 382 [IPL_HIGH] = MIPS_INT_MASK, 383 }, 384 }; 385 386 static const char * const ar5312_cpu_intrnames[] = { 387 "int 0 (wlan0)", 388 "int 1 (enet0)", 389 "int 2 (enet1)", 390 "int 3 (wlan1)", 391 "int 4 (misc)", 392 "int 5 (timer)", 393 }; 394 395 static const char * const ar5312_misc_intrnames[] = { 396 "misc 0 (timer)", 397 "misc 1 (AHBproc error)", 398 "misc 2 (AHBdma error)", 399 "misc 3 (gpio)", 400 "misc 4 (uart)", 401 "misc 5 (uart dma)", 402 "misc 6 (watchdog)" 403 }; 404 405 406 const struct atheros_platformsw ar5312_platformsw = { 407 .apsw_intrsw = &atheros_intrsw, 408 .apsw_intr_init = ar5312_intr_init, 409 .apsw_cpu_intrnames = ar5312_cpu_intrnames, 410 .apsw_misc_intrnames = ar5312_misc_intrnames, 411 .apsw_cpu_nintrs = __arraycount(ar5312_cpu_intrnames), 412 .apsw_misc_nintrs = __arraycount(ar5312_misc_intrnames), 413 .apsw_cpuirq_misc = AR5312_IRQ_MISC, 414 .apsw_ipl_sr_map = &ar5312_ipl_sr_map, 415 416 .apsw_revision_id_addr = AR5312_SYSREG_BASE + AR5312_SYSREG_REVISION, 417 .apsw_uart0_base = AR5312_UART0_BASE, 418 .apsw_misc_intstat = AR5312_SYSREG_BASE + AR5312_SYSREG_MISC_INTSTAT, 419 .apsw_misc_intmask = AR5312_SYSREG_BASE + AR5312_SYSREG_MISC_INTMASK, 420 421 /* 422 * CPU specific routines. 423 */ 424 .apsw_get_memsize = ar5312_get_memsize, 425 .apsw_wdog_reload = ar5312_wdog_reload, 426 .apsw_bus_init = ar5312_bus_init, 427 .apsw_reset = ar5312_reset, 428 429 .apsw_get_freqs = ar5312_get_freqs, 430 .apsw_device_register = ar5312_device_register, 431 .apsw_enable_device = ar5312_enable_device, 432 .apsw_devices = ar5312_devices, 433 }; 434