1/* $NetBSD: ar5315.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/* 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.8 2011/07/07 05:06:44 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/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 90static uint32_t 91ar5315_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 125static void 126ar5315_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 138static void 139ar5315_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 152static void 153ar5315_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 203static void 204addprop_data(device_t dev, const char *name, const uint8_t *data, 205 int len) 206{ 207 prop_data_t pd; 208 pd = prop_data_create_data(data, len); 209 KASSERT(pd != NULL); 210 if (prop_dictionary_set(device_properties(dev), name, pd) == false) { 211 printf("WARNING: unable to set %s property for %s\n", 212 name, device_xname(dev)); 213 } 214 prop_object_release(pd); 215} 216 217static void 218addprop_integer(device_t dev, const char *name, uint32_t val) 219{ 220 prop_number_t pn; 221 pn = prop_number_create_integer(val); 222 KASSERT(pn != NULL); 223 if (prop_dictionary_set(device_properties(dev), name, pn) == false) { 224 printf("WARNING: unable to set %s property for %s", 225 name, device_xname(dev)); 226 } 227 prop_object_release(pn); 228} 229 230static void 231ar5315_device_register(struct device *dev, void *aux) 232{ 233 const struct arbus_attach_args * const aa = aux; 234 const struct ar531x_boarddata * const info = atheros_get_board_info(); 235 236 if (device_is_a(dev, "com")) { 237 addprop_integer(dev, "frequency", atheros_get_bus_freq()); 238 } 239 240 if (info == NULL) { 241 /* nothing known about this board! */ 242 return; 243 } 244 245 /* 246 * We don't ever know the boot device. But that's because the 247 * firmware only loads from the network. 248 */ 249 250 /* Fetch the MAC addresses. */ 251 if (device_is_a(dev, "ae")) { 252 const uint8_t *enet; 253 254 if (aa->aa_addr == AR5315_ENET_BASE) 255 enet = info->enet0Mac; 256 else 257 return; 258 259 addprop_data(dev, "mac-address", enet, ETHER_ADDR_LEN); 260 } 261 262 if (device_is_a(dev, "ath")) { 263 const uint8_t *enet; 264 265 if (aa->aa_addr == AR5315_WLAN_BASE) 266 enet = info->wlan0Mac; 267 else 268 return; 269 270 addprop_data(dev, "mac-address", enet, ETHER_ADDR_LEN); 271 272 addprop_integer(dev, "wmac-rev", 273 GETSYSREG(AR5315_SYSREG_SREV)); 274 } 275 276 if (device_is_a(dev, "argpio")) { 277 if (info->config & BD_RSTFACTORY) { 278 addprop_integer(dev, "reset-pin", 279 info->resetConfigGpio); 280 } 281 if (info->config & BD_SYSLED) { 282 addprop_integer(dev, "sysled-pin", 283 info->sysLedGpio); 284 } 285 } 286} 287 288static int 289ar5315_enable_device(const struct atheros_device *adv) 290{ 291 if (adv->adv_addr == AR5315_WLAN_BASE) { 292 /* enable arbitration for wlan */ 293 PUTSYSREG(AR5315_SYSREG_AHB_ARB_CTL, 294 GETSYSREG(AR5315_SYSREG_AHB_ARB_CTL) | AR5315_ARB_WLAN); 295 296 /* set WLAN for big endian */ 297 PUTSYSREG(AR5315_SYSREG_ENDIAN, 298 GETSYSREG(AR5315_SYSREG_ENDIAN) | AR5315_ENDIAN_WLAN); 299 300 /* wake up the mac */ 301 PUTPCIREG(AR5315_PCI_MAC_SCR, 302 (GETPCIREG(AR5315_PCI_MAC_SCR) & ~PCI_MAC_SCR_SLM_MASK) | 303 PCI_MAC_SCR_SLM_FWAKE); 304 305 /* wait for it to wake up */ 306 while (GETPCIREG(AR5315_PCI_MAC_PCICFG) & 307 PCI_MAC_PCICFG_SPWR_DN); 308 } 309 return 0; 310} 311 312static void 313ar5315_intr_init(void) 314{ 315 atheros_intr_init(); 316} 317 318static void 319ar5315_reset(void) 320{ 321 PUTSYSREG(AR5315_SYSREG_COLDRESET, 322 AR5315_COLD_AHB | AR5315_COLD_APB | AR5315_COLD_CPU); 323} 324 325const static struct atheros_device ar5315_devices[] = { 326 { 327 .adv_name = "com", 328 .adv_addr = AR5315_UART_BASE, 329 .adv_size = 0x1000, 330 .adv_cirq = AR5315_CPU_IRQ_MISC, 331 .adv_mirq = AR5315_MISC_IRQ_UART, 332 }, { 333 .adv_name = "ae", 334 .adv_addr = AR5315_ENET_BASE, 335 .adv_size = 0x100000, 336 .adv_cirq = AR5315_CPU_IRQ_ENET, 337 .adv_mirq = -1, 338 }, { 339 .adv_name = "ath", 340 .adv_addr = AR5315_WLAN_BASE, 341 .adv_size = 0x100000, 342 .adv_cirq = AR5315_CPU_IRQ_WLAN, 343 .adv_mirq = -1, 344 }, { 345 .adv_name = "arspi", 346 .adv_addr = AR5315_SPI_BASE, 347 .adv_size = 0x10, 348 .adv_cirq = AR5315_CPU_IRQ_MISC, 349 .adv_mirq = AR5315_MISC_IRQ_SPI, 350 }, { 351 .adv_name = NULL 352 } 353}; 354 355static const struct ipl_sr_map ar5315_ipl_sr_map = { 356 .sr_bits = { 357 [IPL_NONE] = 0, 358 [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0, 359 [IPL_SOFTBIO] = MIPS_SOFT_INT_MASK_0, 360 [IPL_SOFTNET] = MIPS_SOFT_INT_MASK, 361 [IPL_SOFTSERIAL] = MIPS_SOFT_INT_MASK, 362 [IPL_VM] = MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0 363 | MIPS_INT_MASK_1 | MIPS_INT_MASK_2, 364 [IPL_SCHED] = MIPS_INT_MASK, 365 [IPL_DDB] = MIPS_INT_MASK, 366 [IPL_HIGH] = MIPS_INT_MASK, 367 }, 368}; 369 370static const char * const ar5315_cpu_intrnames[] = { 371 "int 0 (misc)", 372 "int 1 (wlan)", 373 "int 2 (enet)", 374}; 375 376static const char * const ar5315_misc_intrnames[] = { 377 "misc 0 (uart)", 378 "misc 1 (i2c)", 379 "misc 2 (spi)", 380 "misc 3 (ahb error)", 381 "misc 4 (apb error)", 382 "misc 5 (timer)", 383 "misc 6 (gpio)", 384 "misc 7 (watchdog)", 385 "misc 8 (ir)" 386}; 387 388const struct atheros_platformsw ar5315_platformsw = { 389 .apsw_intrsw = &atheros_intrsw, 390 .apsw_intr_init = ar5315_intr_init, 391 .apsw_cpu_intrnames = ar5315_cpu_intrnames, 392 .apsw_misc_intrnames = ar5315_misc_intrnames, 393 .apsw_cpu_nintrs = __arraycount(ar5315_cpu_intrnames), 394 .apsw_misc_nintrs = __arraycount(ar5315_misc_intrnames), 395 .apsw_cpuirq_misc = AR5315_CPU_IRQ_MISC, 396 .apsw_ipl_sr_map = &ar5315_ipl_sr_map, 397 398 .apsw_revision_id_addr = AR5315_SYSREG_BASE + AR5315_SYSREG_SREV, 399 .apsw_uart0_base = AR5315_UART_BASE, 400 .apsw_misc_intstat = AR5315_SYSREG_BASE + AR5315_SYSREG_MISC_INTSTAT, 401 .apsw_misc_intmask = AR5315_SYSREG_BASE + AR5315_SYSREG_MISC_INTMASK, 402 403 /* 404 * CPU specific routines. 405 */ 406 .apsw_get_memsize = ar5315_get_memsize, 407 .apsw_wdog_reload = ar5315_wdog_reload, 408 .apsw_bus_init = ar5315_bus_init, 409 .apsw_reset = ar5315_reset, 410 411 .apsw_get_freqs = ar5315_get_freqs, 412 .apsw_device_register = ar5315_device_register, 413 .apsw_enable_device = ar5315_enable_device, 414 .apsw_devices = ar5315_devices, 415}; 416