1 /* $NetBSD: ar5312.c,v 1.8 2011/07/07 05:06:44 matt 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(struct device *dev, const char *name, const uint8_t *data, 178 int len) 179 { 180 prop_data_t pd; 181 pd = prop_data_create_data(data, len); 182 KASSERT(pd != NULL); 183 if (prop_dictionary_set(device_properties(dev), name, pd) == false) { 184 printf("WARNING: unable to set %s property for %s\n", 185 name, device_xname(dev)); 186 } 187 prop_object_release(pd); 188 } 189 190 static void 191 addprop_integer(struct device *dev, const char *name, uint32_t val) 192 { 193 prop_number_t pn; 194 pn = prop_number_create_integer(val); 195 KASSERT(pn != NULL); 196 if (prop_dictionary_set(device_properties(dev), name, pn) == false) { 197 printf("WARNING: unable to set %s property for %s", 198 name, device_xname(dev)); 199 } 200 prop_object_release(pn); 201 } 202 203 static void 204 ar5312_device_register(device_t dev, void *aux) 205 { 206 const struct arbus_attach_args * const aa = aux; 207 208 if (device_is_a(dev, "com")) { 209 addprop_integer(dev, "frequency", atheros_get_bus_freq()); 210 } 211 212 const struct ar531x_boarddata * const info = atheros_get_board_info(); 213 if (info == NULL) { 214 /* nothing known about this board! */ 215 return; 216 } 217 218 /* 219 * We don't ever know the boot device. But that's because the 220 * firmware only loads from the network. 221 */ 222 223 /* Fetch the MAC addresses. */ 224 if (device_is_a(dev, "ae")) { 225 const uint8_t *enet; 226 227 if (aa->aa_addr == AR5312_ENET0_BASE) 228 enet = info->enet0Mac; 229 else if (aa->aa_addr == AR5312_ENET1_BASE) 230 enet = info->enet1Mac; 231 else 232 return; 233 234 addprop_data(dev, "mac-address", enet, ETHER_ADDR_LEN); 235 } 236 237 if (device_is_a(dev, "ath")) { 238 const uint8_t *enet; 239 240 if (aa->aa_addr == AR5312_WLAN0_BASE) 241 enet = info->wlan0Mac; 242 else if (aa->aa_addr == AR5312_WLAN1_BASE) 243 enet = info->wlan1Mac; 244 else 245 return; 246 247 addprop_data(dev, "mac-address", enet, ETHER_ADDR_LEN); 248 249 addprop_integer(dev, "wmac-rev", 250 AR5312_REVISION_WMAC(GETSYSREG(AR5312_SYSREG_REVISION))); 251 252 } 253 254 if (device_is_a(dev, "argpio")) { 255 if (info->config & BD_RSTFACTORY) { 256 addprop_integer(dev, "reset-pin", 257 info->resetConfigGpio); 258 } 259 if (info->config & BD_SYSLED) { 260 addprop_integer(dev, "sysled-pin", 261 info->sysLedGpio); 262 } 263 } 264 } 265 266 static int 267 ar5312_enable_device(const struct atheros_device *adv) 268 { 269 const struct ar531x_boarddata * const info = atheros_get_board_info(); 270 271 if (info != NULL 272 && adv->adv_mask && ((adv->adv_mask & info->config) == 0)) { 273 return -1; 274 } 275 if (adv->adv_reset) { 276 /* put device into reset */ 277 PUTSYSREG(AR5312_SYSREG_RESETCTL, 278 GETSYSREG(AR5312_SYSREG_RESETCTL) | adv->adv_reset); 279 280 delay(15000); /* XXX: tsleep? */ 281 282 /* take it out of reset */ 283 PUTSYSREG(AR5312_SYSREG_RESETCTL, 284 GETSYSREG(AR5312_SYSREG_RESETCTL) & ~adv->adv_reset); 285 286 delay(25); 287 } 288 if (adv->adv_enable) { 289 PUTSYSREG(AR5312_SYSREG_ENABLE, 290 GETSYSREG(AR5312_SYSREG_ENABLE) | adv->adv_enable); 291 } 292 return 0; 293 } 294 295 static void 296 ar5312_intr_init(void) 297 { 298 atheros_intr_init(); 299 } 300 301 static const struct atheros_device ar5312_devices[] = { 302 { 303 .adv_name = "ae", 304 .adv_addr = AR5312_ENET0_BASE, 305 .adv_size = 0x100000, 306 .adv_cirq = AR5312_IRQ_ENET0, 307 .adv_mirq = -1, 308 .adv_mask = AR5312_BOARD_CONFIG_ENET0, 309 .adv_reset = AR5312_RESET_ENET0 | AR5312_RESET_PHY0, 310 .adv_enable = AR5312_ENABLE_ENET0 311 }, { 312 .adv_name = "ae", 313 .adv_addr = AR5312_ENET1_BASE, 314 .adv_size = 0x100000, 315 .adv_cirq = AR5312_IRQ_ENET1, 316 .adv_mirq = -1, 317 .adv_mask = AR5312_BOARD_CONFIG_ENET1, 318 .adv_reset = AR5312_RESET_ENET1 | AR5312_RESET_PHY1, 319 .adv_enable = AR5312_ENABLE_ENET1 320 }, { 321 .adv_name = "com", 322 .adv_addr = AR5312_UART0_BASE, 323 .adv_size = 0x1000, 324 .adv_cirq = AR5312_IRQ_MISC, 325 .adv_mirq = AR5312_MISC_IRQ_UART0, 326 .adv_mask = AR5312_BOARD_CONFIG_UART0, 327 }, { 328 .adv_name = "com", 329 .adv_addr = AR5312_UART1_BASE, 330 .adv_size = 0x1000, 331 .adv_cirq = -1, 332 .adv_mirq = -1, 333 .adv_mask = AR5312_BOARD_CONFIG_UART1, 334 }, { 335 .adv_name = "ath", 336 .adv_addr = AR5312_WLAN0_BASE, 337 .adv_size = 0x100000, 338 .adv_cirq = AR5312_IRQ_WLAN0, 339 .adv_mirq = -1, 340 .adv_mask = AR5312_BOARD_CONFIG_WLAN0, 341 .adv_reset = AR5312_RESET_WLAN0 | AR5312_RESET_WARM_WLAN0_MAC 342 | AR5312_RESET_WARM_WLAN0_BB, 343 .adv_enable = AR5312_ENABLE_WLAN0 344 }, { 345 .adv_name = "ath", 346 .adv_addr = AR5312_WLAN1_BASE, 347 .adv_size = 0x100000, 348 .adv_cirq = AR5312_IRQ_WLAN1, 349 .adv_mirq = -1, 350 .adv_mask = AR5312_BOARD_CONFIG_WLAN1, 351 .adv_reset = AR5312_RESET_WLAN1 | AR5312_RESET_WARM_WLAN1_MAC 352 | AR5312_RESET_WARM_WLAN1_BB, 353 .adv_enable = AR5312_ENABLE_WLAN1 354 }, { 355 .adv_name = "athflash", 356 .adv_addr = AR5312_FLASH_BASE, 357 .adv_size = 0, 358 .adv_cirq = -1, 359 .adv_mirq = -1, 360 }, { 361 .adv_name = "argpio", 362 .adv_addr = AR5312_GPIO_BASE, 363 .adv_size = 0x1000, 364 .adv_cirq = AR5312_IRQ_MISC, 365 .adv_mirq = AR5312_MISC_IRQ_GPIO, 366 }, { 367 .adv_name = NULL 368 } 369 }; 370 371 static const struct ipl_sr_map ar5312_ipl_sr_map = { 372 .sr_bits = { 373 [IPL_NONE] = 0, 374 [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0, 375 [IPL_SOFTBIO] = MIPS_SOFT_INT_MASK_0, 376 [IPL_SOFTNET] = MIPS_SOFT_INT_MASK, 377 [IPL_SOFTSERIAL] = MIPS_SOFT_INT_MASK, 378 [IPL_VM] = MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0 379 | MIPS_INT_MASK_1 | MIPS_INT_MASK_2 380 | MIPS_INT_MASK_3, 381 [IPL_SCHED] = MIPS_INT_MASK, 382 [IPL_DDB] = MIPS_INT_MASK, 383 [IPL_HIGH] = MIPS_INT_MASK, 384 }, 385 }; 386 387 static const char * const ar5312_cpu_intrnames[] = { 388 "int 0 (wlan0)", 389 "int 1 (enet0)", 390 "int 2 (enet1)", 391 "int 3 (wlan1)", 392 "int 4 (misc)", 393 "int 5 (timer)", 394 }; 395 396 static const char * const ar5312_misc_intrnames[] = { 397 "misc 0 (timer)", 398 "misc 1 (AHBproc error)", 399 "misc 2 (AHBdma error)", 400 "misc 3 (gpio)", 401 "misc 4 (uart)", 402 "misc 5 (uart dma)", 403 "misc 6 (watchdog)" 404 }; 405 406 407 const struct atheros_platformsw ar5312_platformsw = { 408 .apsw_intrsw = &atheros_intrsw, 409 .apsw_intr_init = ar5312_intr_init, 410 .apsw_cpu_intrnames = ar5312_cpu_intrnames, 411 .apsw_misc_intrnames = ar5312_misc_intrnames, 412 .apsw_cpu_nintrs = __arraycount(ar5312_cpu_intrnames), 413 .apsw_misc_nintrs = __arraycount(ar5312_misc_intrnames), 414 .apsw_cpuirq_misc = AR5312_IRQ_MISC, 415 .apsw_ipl_sr_map = &ar5312_ipl_sr_map, 416 417 .apsw_revision_id_addr = AR5312_SYSREG_BASE + AR5312_SYSREG_REVISION, 418 .apsw_uart0_base = AR5312_UART0_BASE, 419 .apsw_misc_intstat = AR5312_SYSREG_BASE + AR5312_SYSREG_MISC_INTSTAT, 420 .apsw_misc_intmask = AR5312_SYSREG_BASE + AR5312_SYSREG_MISC_INTMASK, 421 422 /* 423 * CPU specific routines. 424 */ 425 .apsw_get_memsize = ar5312_get_memsize, 426 .apsw_wdog_reload = ar5312_wdog_reload, 427 .apsw_bus_init = ar5312_bus_init, 428 .apsw_reset = ar5312_reset, 429 430 .apsw_get_freqs = ar5312_get_freqs, 431 .apsw_device_register = ar5312_device_register, 432 .apsw_enable_device = ar5312_enable_device, 433 .apsw_devices = ar5312_devices, 434 }; 435