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