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