1 /* $NetBSD: ar9344.c,v 1.3 2011/07/10 23:13:22 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 /* 46 * This file includes a bunch of implementation specific bits for 47 * AR9344, which differs these from other members of the AR9344 48 * family. 49 */ 50 #include <sys/cdefs.h> 51 __KERNEL_RCSID(0, "$NetBSD: ar9344.c,v 1.3 2011/07/10 23:13:22 matt 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/device.h> 61 #include <sys/kernel.h> 62 #include <sys/systm.h> 63 64 #include <mips/locore.h> 65 66 #include <mips/atheros/include/ar9344reg.h> 67 #include <mips/atheros/include/platform.h> 68 #include <mips/atheros/include/arbusvar.h> 69 70 static uint32_t 71 ar9344_get_memsize(void) 72 { 73 #ifndef MEMSIZE 74 uint32_t memsize = 64*1024*1024; 75 76 uint32_t memcfg = GETDDRREG(AR9344_DDR_RD_DATA_THIS_CYCLE); 77 78 /* 79 * 32-bit means twice the memory. 80 */ 81 if (memcfg == 0xff) 82 memsize <<= 1; 83 84 return memsize; 85 #else 86 /* compile time value forced */ 87 return MEMSIZE; 88 #endif 89 } 90 91 static void 92 ar9344_wdog_reload(uint32_t period) 93 { 94 95 if (period == 0) { 96 PUTRESETREG(ARCHIP_RESET_WDOG_CTL, ARCHIP_WDOG_CTL_IGNORE); 97 PUTRESETREG(ARCHIP_RESET_WDOG_TIMER, 0); 98 } else { 99 PUTRESETREG(ARCHIP_RESET_WDOG_TIMER, period); 100 PUTRESETREG(ARCHIP_RESET_WDOG_CTL, ARCHIP_WDOG_CTL_RESET); 101 } 102 } 103 104 static void 105 ar9344_bus_init(void) 106 { 107 #if 0 108 PUTRESET(AR9344_RESET_AHB_ERR0, AR9344_AHB_ERROR_DET); 109 GETRESET(AR9344_RESET_AHB_ERR1); 110 #endif 111 } 112 113 static void 114 ar9344_reset(void) 115 { 116 PUTRESETREG(AR9344_RESET_RESETCTL, ARCHIP_RESETCTL_FULL_CHIP_RESET); 117 } 118 119 120 static void 121 ar9344_get_freqs(struct arfreqs *freqs) 122 { 123 uint32_t out_div, ref_div, nint, nfrac, post_div; 124 uint32_t pll; 125 uint32_t ref_clk; 126 127 if (GETRESETREG(AR9344_RESET_BOOTSTRAP) & AR9344_BOOTSTRAP_REF_CLK_40) { 128 ref_clk = 40 * 1000000; 129 } else { 130 ref_clk = 25 * 1000000; 131 } 132 133 freqs->freq_ref = ref_clk; 134 135 /* 136 * Let's figure out the CPU PLL frequency. 137 */ 138 pll = GETPLLREG(ARCHIP_PLL_CPU_PLL_CONFIG); 139 out_div = __SHIFTOUT(pll, AR9344_CPU_PLL_CONFIG_OUTDIV); 140 ref_div = __SHIFTOUT(pll, AR9344_CPU_PLL_CONFIG_REFDIV); 141 nint = __SHIFTOUT(pll, AR9344_CPU_PLL_CONFIG_NINT); 142 nfrac = __SHIFTOUT(pll, AR9344_CPU_PLL_CONFIG_NFRAC); 143 144 const uint32_t cpu_pll_freq = (nint * ref_clk / ref_div) >> out_div; 145 146 /* 147 * Now figure out the DDR PLL frequency. 148 */ 149 pll = GETPLLREG(ARCHIP_PLL_DDR_PLL_CONFIG); 150 out_div = __SHIFTOUT(pll, AR9344_DDR_PLL_CONFIG_OUTDIV); 151 ref_div = __SHIFTOUT(pll, AR9344_DDR_PLL_CONFIG_REFDIV); 152 nint = __SHIFTOUT(pll, AR9344_DDR_PLL_CONFIG_NINT); 153 nfrac = __SHIFTOUT(pll, AR9344_DDR_PLL_CONFIG_NFRAC); 154 155 const uint32_t ddr_pll_freq = (nint * ref_clk / ref_div) >> out_div; 156 157 /* 158 * Now we find out the various frequencies... 159 */ 160 uint32_t clk_ctl = GETPLLREG(ARCHIP_PLL_CPU_DDR_CLOCK_CONTROL); 161 post_div = __SHIFTOUT(clk_ctl, 162 AR9344_CPU_DDR_CLOCK_CONTROL_AHB_POST_DIV); 163 if (clk_ctl & AR9344_CPU_DDR_CLOCK_CONTROL_AHBCLK_FROM_DDRPLL) { 164 freqs->freq_bus = ddr_pll_freq / (post_div + 1); 165 } else { 166 freqs->freq_bus = cpu_pll_freq / (post_div + 1); 167 } 168 169 post_div = __SHIFTOUT(clk_ctl, 170 AR9344_CPU_DDR_CLOCK_CONTROL_CPU_POST_DIV); 171 if (clk_ctl & AR9344_CPU_DDR_CLOCK_CONTROL_CPUCLK_FROM_CPUPLL) { 172 freqs->freq_cpu = cpu_pll_freq / (post_div + 1); 173 freqs->freq_pll = cpu_pll_freq; 174 } else { 175 freqs->freq_cpu = ddr_pll_freq / (post_div + 1); 176 freqs->freq_pll = ddr_pll_freq; 177 } 178 179 post_div = __SHIFTOUT(clk_ctl, 180 AR9344_CPU_DDR_CLOCK_CONTROL_DDR_POST_DIV); 181 if (clk_ctl & AR9344_CPU_DDR_CLOCK_CONTROL_DDRCLK_FROM_DDRPLL) { 182 freqs->freq_mem = ddr_pll_freq / (post_div + 1); 183 } else { 184 freqs->freq_mem = cpu_pll_freq / (post_div + 1); 185 } 186 187 /* 188 * Console is off the reference clock, not the bus clock. 189 */ 190 freqs->freq_uart = freqs->freq_ref; 191 } 192 193 #if 0 194 static void 195 addprop_data(struct device *dev, const char *name, const uint8_t *data, 196 int len) 197 { 198 prop_data_t pd; 199 pd = prop_data_create_data(data, len); 200 KASSERT(pd != NULL); 201 if (prop_dictionary_set(device_properties(dev), name, pd) == FALSE) { 202 printf("WARNING: unable to set %s property for %s\n", 203 name, device_xname(dev)); 204 } 205 prop_object_release(pd); 206 } 207 #endif 208 209 static void 210 addprop_integer(struct device *dev, const char *name, uint32_t val) 211 { 212 prop_number_t pn; 213 pn = prop_number_create_integer(val); 214 KASSERT(pn != NULL); 215 if (prop_dictionary_set(device_properties(dev), name, pn) == FALSE) { 216 printf("WARNING: unable to set %s property for %s", 217 name, device_xname(dev)); 218 } 219 prop_object_release(pn); 220 } 221 222 static void 223 ar9344_device_register(device_t dev, void *aux) 224 { 225 226 if (device_is_a(dev, "com") 227 && device_is_a(device_parent(dev), "arbus")) { 228 addprop_integer(dev, "frequency", atheros_get_bus_freq()); 229 return; 230 } 231 232 #if 0 233 const struct arbus_attach_args * const aa = aux; 234 const struct ar9344_boarddata *info; 235 info = ar9344_board_info(); 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 uint8_t enaddr[ETHER_ADDR_LEN]; 249 250 memcpy(enaddr, info->enet0Mac, ETHER_ADDR_LEN); 251 if (aa->aa_addr == AR9344_GMAC0_BASE) { 252 ; 253 } else if (aa->aa_addr == AR9344_GMAC1_BASE) { 254 enaddr[5] ^= 1; 255 } else 256 return; 257 258 addprop_data(dev, "mac-addr", enaddr, ETHER_ADDR_LEN); 259 } 260 261 #if 0 262 if (device_is_a(dev, "ath")) { 263 const uint8_t *enet; 264 265 if (aa->aa_addr == AR9344_WLAN_BASE) 266 enet = info->wlan0Mac; 267 else 268 return; 269 270 addprop_data(dev, "mac-addr", enet, ETHER_ADDR_LEN); 271 272 addprop_integer(dev, "wmac-rev", 273 GETRESET(AR9344_RESET_SREV)); 274 } 275 #endif 276 277 if (device_is_a(dev, "argpio")) { 278 if (info->config & BD_RSTFACTORY) { 279 addprop_integer(dev, "reset-pin", 280 info->resetConfigGpio); 281 } 282 if (info->config & BD_SYSLED) { 283 addprop_integer(dev, "sysled-pin", 284 info->sysLedGpio); 285 } 286 } 287 #endif 288 } 289 290 static int 291 ar9344_enable_device(const struct atheros_device *adv) 292 { 293 if (adv->adv_reset) { 294 /* put device into reset */ 295 PUTRESETREG(AR9344_RESET_RESETCTL, 296 GETRESETREG(AR9344_RESET_RESETCTL) | adv->adv_reset); 297 298 delay(15000); /* XXX: tsleep? */ 299 300 /* take it out of reset */ 301 PUTRESETREG(AR9344_RESET_RESETCTL, 302 GETRESETREG(AR9344_RESET_RESETCTL) & ~adv->adv_reset); 303 304 delay(25); 305 } 306 if (adv->adv_enable) 307 panic("%s: %s: enable not supported!", __func__, adv->adv_name); 308 309 return 0; 310 } 311 312 static void 313 ar9344_intr_init(void) 314 { 315 atheros_intr_init(); 316 } 317 318 static const char * const ar9344_cpu_intrnames[] = { 319 [AR9344_CPU_IRQ_PCIERC] = "irq 0 (pcie rc)", 320 [ARCHIP_CPU_IRQ_USB] = "irq 1 (usb)", 321 [ARCHIP_CPU_IRQ_GMAC0] = "irq 2 (gmac0)", 322 [ARCHIP_CPU_IRQ_GMAC1] = "irq 3 (gmac1)", 323 [ARCHIP_CPU_IRQ_MISC] = "irq 4 (misc)", 324 [ARCHIP_CPU_IRQ_TIMER] = "irq 5 (timer)", 325 #if 0 326 [AR9344_CPU_IRQ_PCIEEP_HSTDMA] = "irq 6 (pcieep)", 327 #endif 328 }; 329 330 static const char * const ar9344_misc_intrnames[] = { 331 [AR9344_MISC_IRQ_TIMER] = "irq 0 (timer1)", 332 [AR9344_MISC_IRQ_ERROR] = "irq 1 (error)", 333 [AR9344_MISC_IRQ_GPIO] = "irq 2 (gpio)", 334 [AR9344_MISC_IRQ_UART0] = "irq 3 (uart0)", 335 [AR9344_MISC_IRQ_WDOG] = "irq 4 (wdog)", 336 [AR9344_MISC_IRQ_PC] = "irq 5 (pc)", 337 [AR9344_MISC_IRQ_UART1] = "irq 6 (uart1)", 338 [AR9344_MISC_IRQ_MBOX] = "irq 7 (mbox)", 339 [AR9344_MISC_IRQ_TIMER2] = "irq 8 (timer2)", 340 [AR9344_MISC_IRQ_TIMER3] = "irq 9 (timer3)", 341 [AR9344_MISC_IRQ_TIMER4] = "irq 10 (timer4)", 342 [AR9344_MISC_IRQ_DDR_PERF] = "irq 11 (ddr_perf)", 343 [AR9344_MISC_IRQ_SW_MAC] = "irq 12 (sw_mac)", 344 [AR9344_MISC_IRQ_LUTS_AGER] = "irq 13 (lut_ager)", 345 [AR9344_MISC_IRQ_CHKSUM_ACC] = "irq 15 (chksum_acc)", 346 [AR9344_MISC_IRQ_DDR_SF_ENTRY] = "irq 16 (ddr_sf_entry)", 347 [AR9344_MISC_IRQ_DDR_SF_EXIT] = "irq 17 (ddr_sf_exit)", 348 [AR9344_MISC_IRQ_DDR_ACT_IN_SF] = "irq 18 (ddr_act_in_sf)", 349 [AR9344_MISC_IRQ_SLIC] = "irq 19 (slic)", 350 [AR9344_MISC_IRQ_WOW] = "irq 20 (wow)", 351 [AR9344_MISC_IRQ_NANDF] = "irq 21 (nandf)", 352 }; 353 354 #if 0 355 static const char * const ar9344_misc2_intrnames[] = { 356 [AR9344_WMAC_IRQ_WMAC_MISC_INT] = "irq 0 (wmac misc)", 357 [AR9344_WMAC_IRQ_WMAC_TX_INT] = "irq 1 (wmac tx)", 358 [AR9344_WMAC_IRQ_WMAC_RXLP_INT] = "irq 2 (wmac rxlp)", 359 [AR9344_WMAC_IRQ_WMAC_RXHP_INT] = "irq 3 (wmac rxhp)", 360 [AR9344_WMAC_IRQ_PCIE_RC_INT] = "irq 4 (pcie rc int)", 361 [AR9344_WMAC_IRQ_PCIE_RC_INT0] = "irq 5 (pcie rc int 0)", 362 [AR9344_WMAC_IRQ_PCIE_RC_INT1] = "irq 6 (pcie rc int 1)", 363 [AR9344_WMAC_IRQ_PCIE_RC_INT2] = "irq 7 (pcie rc int 2)", 364 [AR9344_WMAC_IRQ_PCIE_RC_INT3] = "irq 8 (pcie rc int 3)", 365 }; 366 #endif 367 368 static const struct ipl_sr_map ar9344_ipl_sr_map = { 369 .sr_bits = { 370 [IPL_NONE] = 0, 371 [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0, 372 [IPL_SOFTBIO] = MIPS_SOFT_INT_MASK_0, 373 [IPL_SOFTNET] = MIPS_SOFT_INT_MASK_0, 374 [IPL_SOFTSERIAL] = MIPS_SOFT_INT_MASK_0, 375 [IPL_VM] = MIPS_SOFT_INT_MASK | 376 MIPS_INT_MASK_0 | /* PCIE RC */ 377 MIPS_INT_MASK_1 | /* USB */ 378 MIPS_INT_MASK_2 | /* GMAC0 */ 379 MIPS_INT_MASK_3 | /* GMAC1 */ 380 MIPS_INT_MASK_4, /* MISC */ 381 [IPL_SCHED] = MIPS_INT_MASK, /* EVERYTHING */ 382 [IPL_DDB] = MIPS_INT_MASK, /* EVERYTHING */ 383 [IPL_HIGH] = MIPS_INT_MASK, /* EVERYTHING */ 384 }, 385 }; 386 387 static const struct atheros_device ar9344_devices[] = { 388 { 389 .adv_name = "com", 390 .adv_addr = AR9344_UART0_BASE, 391 .adv_size = 0x1000, 392 .adv_cirq = ARCHIP_CPU_IRQ_MISC, 393 .adv_mirq = AR9344_MISC_IRQ_UART0, 394 }, { 395 .adv_name = "ehci", 396 .adv_addr = AR9344_USB_BASE + 0x100, 397 .adv_size = 0x1000, 398 .adv_cirq = ARCHIP_CPU_IRQ_USB, 399 .adv_mirq = -1, 400 .adv_reset = AR9344_RESETCTL_USB_PHY_SUSPEND_OVERRIDE 401 | ARCHIP_RESETCTL_USB_PHY_RESET 402 | ARCHIP_RESETCTL_USB_HOST_RESET, 403 }, { 404 .adv_name = "age", 405 .adv_addr = AR9344_GMAC0_BASE, 406 .adv_size = 0x1000, 407 .adv_cirq = ARCHIP_CPU_IRQ_GMAC0, 408 .adv_mirq = -1, 409 }, { 410 .adv_name = "age", 411 .adv_addr = AR9344_GMAC1_BASE, 412 .adv_size = 0x1000, 413 .adv_cirq = ARCHIP_CPU_IRQ_GMAC1, 414 .adv_mirq = -1, 415 }, { 416 .adv_name = "arpcie", 417 .adv_addr = AR9344_PCIE_RC_BASE, 418 .adv_size = 0x1000, 419 .adv_cirq = AR9344_CPU_IRQ_PCIERC, 420 .adv_mirq = -1, 421 }, 422 #if 0 423 { 424 .adv_name = "ath", 425 .adv_addr = AR9344_WLAN_BASE, 426 .adv_size = 0x100000, 427 .adv_cirq = AR9344_CPU_IRQ_WLAN, 428 .adv_mirq = -1, 429 }, { 430 .adv_name = "arspi", 431 .adv_addr = AR9344_SPI_BASE, 432 .adv_size = 0x20, 433 .adv_cirq = AR9344_CPU_IRQ_MISC, 434 .adv_mirq = AR9344_MISC_IRQ_SPI, 435 }, 436 #endif 437 { 438 .adv_name = NULL 439 } 440 }; 441 442 const struct atheros_platformsw ar9344_platformsw = { 443 .apsw_intrsw = &atheros_intrsw, 444 .apsw_intr_init = ar9344_intr_init, 445 .apsw_cpu_intrnames = ar9344_cpu_intrnames, 446 .apsw_misc_intrnames = ar9344_misc_intrnames, 447 .apsw_cpu_nintrs = __arraycount(ar9344_cpu_intrnames), 448 .apsw_misc_nintrs = __arraycount(ar9344_misc_intrnames), 449 .apsw_cpuirq_misc = ARCHIP_CPU_IRQ_MISC, 450 .apsw_ipl_sr_map = &ar9344_ipl_sr_map, 451 452 .apsw_revision_id_addr = ARCHIP_RESET_BASE + ARCHIP_RESET_REVISION, 453 .apsw_uart0_base = AR9344_UART0_BASE, 454 .apsw_misc_intstat = ARCHIP_RESET_BASE + ARCHIP_RESET_MISC_INTSTAT, 455 .apsw_misc_intmask = ARCHIP_RESET_BASE + ARCHIP_RESET_MISC_INTMASK, 456 457 /* 458 * CPU specific routines. 459 */ 460 .apsw_get_memsize = ar9344_get_memsize, 461 .apsw_wdog_reload = ar9344_wdog_reload, 462 .apsw_bus_init = ar9344_bus_init, 463 .apsw_reset = ar9344_reset, 464 465 .apsw_get_freqs = ar9344_get_freqs, 466 .apsw_device_register = ar9344_device_register, 467 .apsw_enable_device = ar9344_enable_device, 468 .apsw_devices = ar9344_devices, 469 }; 470