1 /* $NetBSD: ar5315.c,v 1.11 2025/10/03 14:05:12 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 /* 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.11 2025/10/03 14:05:12 thorpej Exp $"); 52 53 #include "opt_ddb.h" 54 #include "opt_kgdb.h" 55 #include "opt_memsize.h" 56 57 #define __INTR_PRIVATE 58 59 #include <sys/param.h> 60 #include <sys/systm.h> 61 #include <sys/kernel.h> 62 #include <sys/buf.h> 63 #include <sys/device.h> 64 65 #include <mips/cache.h> 66 #include <mips/locore.h> 67 #include <mips/cpuregs.h> 68 69 #include <net/if.h> 70 #include <net/if_ether.h> 71 72 #include <prop/proplib.h> 73 74 #include <ah_soc.h> /* XXX really doesn't belong in hal */ 75 76 #include <mips/atheros/include/ar5315reg.h> 77 #include <mips/atheros/include/platform.h> 78 #include <mips/atheros/include/arbusvar.h> 79 80 #include <mips/locore.h> 81 82 /* helper macro for accessing system registers without bus space */ 83 #define REGVAL(x) *((volatile uint32_t *)(MIPS_PHYS_TO_KSEG1((x)))) 84 #define GETSYSREG(x) REGVAL((x) + AR5315_SYSREG_BASE) 85 #define PUTSYSREG(x,v) (REGVAL((x) + AR5315_SYSREG_BASE)) = (v) 86 #define GETPCIREG(x) REGVAL((x) + AR5315_PCI_BASE) 87 #define PUTPCIREG(x,v) (REGVAL((x) + AR5315_PCI_BASE)) = (v) 88 #define GETSDRAMREG(x) REGVAL((x) + AR5315_SDRAMCTL_BASE) 89 90 static uint32_t 91 ar5315_get_memsize(void) 92 { 93 #ifndef MEMSIZE 94 uint32_t memsize = 0; 95 uint32_t memcfg, cw, rw, dw; 96 97 /* 98 * Determine the memory size. We query the board info. 99 */ 100 memcfg = GETSDRAMREG(AR5315_SDRAMCTL_MEM_CFG); 101 cw = __SHIFTOUT(memcfg, AR5315_MEM_CFG_COL_WIDTH); 102 cw += 1; 103 rw = __SHIFTOUT(memcfg, AR5315_MEM_CFG_ROW_WIDTH); 104 rw += 1; 105 106 /* XXX: according to redboot, this could be wrong if DDR SDRAM */ 107 dw = __SHIFTOUT(memcfg, AR5315_MEM_CFG_DATA_WIDTH); 108 dw += 1; 109 dw *= 8; /* bits */ 110 111 /* not too sure about this math, but it _seems_ to add up */ 112 memsize = (1 << cw) * (1 << rw) * dw; 113 #if 0 114 printf("SDRAM_MEM_CFG =%x, cw=%d rw=%d dw=%d xmemsize=%d\n", memcfg, 115 cw, rw, dw, memsize); 116 #endif 117 118 return (memsize); 119 #else 120 /* compile time value forced */ 121 return MEMSIZE; 122 #endif 123 } 124 125 static void 126 ar5315_wdog_reload(uint32_t period) 127 { 128 129 if (period == 0) { 130 PUTSYSREG(AR5315_SYSREG_WDOG_CTL, AR5315_WDOG_CTL_IGNORE); 131 PUTSYSREG(AR5315_SYSREG_WDOG_TIMER, 0); 132 } else { 133 PUTSYSREG(AR5315_SYSREG_WDOG_TIMER, period); 134 PUTSYSREG(AR5315_SYSREG_WDOG_CTL, AR5315_WDOG_CTL_RESET); 135 } 136 } 137 138 static void 139 ar5315_bus_init(void) 140 { 141 /* 142 * Set CCA of KSEG0 access to 3 (actually any value other than 143 * 2 & 7 means that KSEG0 accesses are cached but 3 is standard 144 * value for writeback caching). 145 */ 146 mips3_cp0_config_write((mips3_cp0_config_read() & -8) | 3); 147 148 PUTSYSREG(AR5315_SYSREG_AHB_ERR0, AR5315_AHB_ERROR_DET); 149 GETSYSREG(AR5315_SYSREG_AHB_ERR1); 150 } 151 152 static void 153 ar5315_get_freqs(struct arfreqs *freqs) 154 { 155 static const uint8_t pll_divide_table[] = { 156 2, 3, 4, 6, 3, 157 /* 158 * these entries are bogus, but it avoids a possible 159 * bad table dereference 160 */ 161 1, 1, 1 162 }; 163 static const uint8_t pre_divide_table[] = { 164 1, 2, 4, 5 165 }; 166 167 const uint32_t pllc = GETSYSREG(AR5315_SYSREG_PLLC_CTL); 168 169 const uint32_t refdiv = pre_divide_table[AR5315_PLLC_REF_DIV(pllc)]; 170 const uint32_t fbdiv = AR5315_PLLC_FB_DIV(pllc); 171 const uint32_t div2 = (AR5315_PLLC_DIV_2(pllc) + 1) * 2; /* results in 2 or 4 */ 172 173 freqs->freq_ref = 40000000; 174 175 /* 40MHz reference clk, reference and feedback dividers */ 176 freqs->freq_pll = (freqs->freq_ref / refdiv) * div2 * fbdiv; 177 178 const uint32_t pllout[4] = { 179 /* CLKM select */ 180 [0] = freqs->freq_pll / pll_divide_table[AR5315_PLLC_CLKM(pllc)], 181 [1] = freqs->freq_pll / pll_divide_table[AR5315_PLLC_CLKM(pllc)], 182 183 /* CLKC select */ 184 [2] = freqs->freq_pll / pll_divide_table[AR5315_PLLC_CLKC(pllc)], 185 186 /* ref_clk select */ 187 [3] = freqs->freq_ref, /* use original reference clock */ 188 }; 189 190 const uint32_t amba_clkctl = GETSYSREG(AR5315_SYSREG_AMBACLK); 191 uint32_t ambadiv = AR5315_CLOCKCTL_DIV(amba_clkctl); 192 ambadiv = ambadiv ? (ambadiv * 2) : 1; 193 freqs->freq_bus = pllout[AR5315_CLOCKCTL_SELECT(amba_clkctl)] / ambadiv; 194 195 const uint32_t cpu_clkctl = GETSYSREG(AR5315_SYSREG_CPUCLK); 196 uint32_t cpudiv = AR5315_CLOCKCTL_DIV(cpu_clkctl); 197 cpudiv = cpudiv ? (cpudiv * 2) : 1; 198 freqs->freq_cpu = pllout[AR5315_CLOCKCTL_SELECT(cpu_clkctl)] / cpudiv; 199 200 freqs->freq_mem = 0; 201 } 202 203 static void 204 addprop_data(device_t dev, const char *name, const uint8_t *data, 205 int len) 206 { 207 if (! device_setprop_data(dev, name, data, len)) { 208 printf("WARNING: unable to set %s property for %s\n", 209 name, device_xname(dev)); 210 } 211 } 212 213 static void 214 addprop_integer(device_t dev, const char *name, uint32_t val) 215 { 216 prop_number_t pn; 217 pn = prop_number_create_integer(val); 218 KASSERT(pn != NULL); 219 if (prop_dictionary_set(device_properties(dev), name, pn) == false) { 220 printf("WARNING: unable to set %s property for %s", 221 name, device_xname(dev)); 222 } 223 prop_object_release(pn); 224 } 225 226 static void 227 ar5315_device_register(device_t dev, void *aux) 228 { 229 const struct arbus_attach_args * const aa = aux; 230 const struct ar531x_boarddata * const info = atheros_get_board_info(); 231 232 if (device_is_a(dev, "com")) { 233 addprop_integer(dev, "frequency", atheros_get_bus_freq()); 234 } 235 236 if (info == NULL) { 237 /* nothing known about this board! */ 238 return; 239 } 240 241 /* 242 * We don't ever know the boot device. But that's because the 243 * firmware only loads from the network. 244 */ 245 246 /* Fetch the MAC addresses. */ 247 if (device_is_a(dev, "ae")) { 248 const uint8_t *enet; 249 250 if (aa->aa_addr == AR5315_ENET_BASE) 251 enet = info->enet0Mac; 252 else 253 return; 254 255 addprop_data(dev, "mac-address", enet, ETHER_ADDR_LEN); 256 } 257 258 if (device_is_a(dev, "ath")) { 259 const uint8_t *enet; 260 261 if (aa->aa_addr == AR5315_WLAN_BASE) 262 enet = info->wlan0Mac; 263 else 264 return; 265 266 addprop_data(dev, "mac-address", enet, ETHER_ADDR_LEN); 267 268 addprop_integer(dev, "wmac-rev", 269 GETSYSREG(AR5315_SYSREG_SREV)); 270 } 271 272 if (device_is_a(dev, "argpio")) { 273 if (info->config & BD_RSTFACTORY) { 274 addprop_integer(dev, "reset-pin", 275 info->resetConfigGpio); 276 } 277 if (info->config & BD_SYSLED) { 278 addprop_integer(dev, "sysled-pin", 279 info->sysLedGpio); 280 } 281 } 282 } 283 284 static int 285 ar5315_enable_device(const struct atheros_device *adv) 286 { 287 if (adv->adv_addr == AR5315_WLAN_BASE) { 288 /* enable arbitration for wlan */ 289 PUTSYSREG(AR5315_SYSREG_AHB_ARB_CTL, 290 GETSYSREG(AR5315_SYSREG_AHB_ARB_CTL) | AR5315_ARB_WLAN); 291 292 /* set WLAN for big endian */ 293 PUTSYSREG(AR5315_SYSREG_ENDIAN, 294 GETSYSREG(AR5315_SYSREG_ENDIAN) | AR5315_ENDIAN_WLAN); 295 296 /* wake up the mac */ 297 PUTPCIREG(AR5315_PCI_MAC_SCR, 298 (GETPCIREG(AR5315_PCI_MAC_SCR) & ~PCI_MAC_SCR_SLM_MASK) | 299 PCI_MAC_SCR_SLM_FWAKE); 300 301 /* wait for it to wake up */ 302 while (GETPCIREG(AR5315_PCI_MAC_PCICFG) & 303 PCI_MAC_PCICFG_SPWR_DN); 304 } 305 return 0; 306 } 307 308 static void 309 ar5315_intr_init(void) 310 { 311 atheros_intr_init(); 312 } 313 314 static void 315 ar5315_reset(void) 316 { 317 PUTSYSREG(AR5315_SYSREG_COLDRESET, 318 AR5315_COLD_AHB | AR5315_COLD_APB | AR5315_COLD_CPU); 319 } 320 321 const static struct atheros_device ar5315_devices[] = { 322 { 323 .adv_name = "com", 324 .adv_addr = AR5315_UART_BASE, 325 .adv_size = 0x1000, 326 .adv_cirq = AR5315_CPU_IRQ_MISC, 327 .adv_mirq = AR5315_MISC_IRQ_UART, 328 }, { 329 .adv_name = "ae", 330 .adv_addr = AR5315_ENET_BASE, 331 .adv_size = 0x100000, 332 .adv_cirq = AR5315_CPU_IRQ_ENET, 333 .adv_mirq = -1, 334 }, { 335 .adv_name = "ath", 336 .adv_addr = AR5315_WLAN_BASE, 337 .adv_size = 0x100000, 338 .adv_cirq = AR5315_CPU_IRQ_WLAN, 339 .adv_mirq = -1, 340 }, { 341 .adv_name = "arspi", 342 .adv_addr = AR5315_SPI_BASE, 343 .adv_size = 0x10, 344 .adv_cirq = AR5315_CPU_IRQ_MISC, 345 .adv_mirq = AR5315_MISC_IRQ_SPI, 346 }, { 347 .adv_name = NULL 348 } 349 }; 350 351 static const struct ipl_sr_map ar5315_ipl_sr_map = { 352 .sr_bits = { 353 [IPL_NONE] = 0, 354 [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0, 355 [IPL_SOFTBIO] = MIPS_SOFT_INT_MASK_0, 356 [IPL_SOFTNET] = MIPS_SOFT_INT_MASK, 357 [IPL_SOFTSERIAL] = MIPS_SOFT_INT_MASK, 358 [IPL_VM] = MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0 359 | MIPS_INT_MASK_1 | MIPS_INT_MASK_2, 360 [IPL_SCHED] = MIPS_INT_MASK, 361 [IPL_DDB] = MIPS_INT_MASK, 362 [IPL_HIGH] = MIPS_INT_MASK, 363 }, 364 }; 365 366 static const char * const ar5315_cpu_intrnames[] = { 367 "int 0 (misc)", 368 "int 1 (wlan)", 369 "int 2 (enet)", 370 }; 371 372 static const char * const ar5315_misc_intrnames[] = { 373 "misc 0 (uart)", 374 "misc 1 (i2c)", 375 "misc 2 (spi)", 376 "misc 3 (ahb error)", 377 "misc 4 (apb error)", 378 "misc 5 (timer)", 379 "misc 6 (gpio)", 380 "misc 7 (watchdog)", 381 "misc 8 (ir)" 382 }; 383 384 const struct atheros_platformsw ar5315_platformsw = { 385 .apsw_intrsw = &atheros_intrsw, 386 .apsw_intr_init = ar5315_intr_init, 387 .apsw_cpu_intrnames = ar5315_cpu_intrnames, 388 .apsw_misc_intrnames = ar5315_misc_intrnames, 389 .apsw_cpu_nintrs = __arraycount(ar5315_cpu_intrnames), 390 .apsw_misc_nintrs = __arraycount(ar5315_misc_intrnames), 391 .apsw_cpuirq_misc = AR5315_CPU_IRQ_MISC, 392 .apsw_ipl_sr_map = &ar5315_ipl_sr_map, 393 394 .apsw_revision_id_addr = AR5315_SYSREG_BASE + AR5315_SYSREG_SREV, 395 .apsw_uart0_base = AR5315_UART_BASE, 396 .apsw_misc_intstat = AR5315_SYSREG_BASE + AR5315_SYSREG_MISC_INTSTAT, 397 .apsw_misc_intmask = AR5315_SYSREG_BASE + AR5315_SYSREG_MISC_INTMASK, 398 399 /* 400 * CPU specific routines. 401 */ 402 .apsw_get_memsize = ar5315_get_memsize, 403 .apsw_wdog_reload = ar5315_wdog_reload, 404 .apsw_bus_init = ar5315_bus_init, 405 .apsw_reset = ar5315_reset, 406 407 .apsw_get_freqs = ar5315_get_freqs, 408 .apsw_device_register = ar5315_device_register, 409 .apsw_enable_device = ar5315_enable_device, 410 .apsw_devices = ar5315_devices, 411 }; 412