static int apb_filter(void *arg) { struct apb_softc *sc = arg; struct intr_event *event; uint32_t reg, irq; if(ar531x_soc >= AR531X_SOC_AR5315) reg = ATH_READ_REG(AR5315_SYSREG_BASE + AR5315_SYSREG_MISC_INTSTAT); else reg = ATH_READ_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_MISC_INTSTAT); for (irq = 0; irq < APB_NIRQS; irq++) { if (reg & (1 << irq)) { if(ar531x_soc >= AR531X_SOC_AR5315) { ATH_WRITE_REG(AR5315_SYSREG_BASE + AR5315_SYSREG_MISC_INTSTAT, reg & ~(1 << irq)); } else { ATH_WRITE_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_MISC_INTSTAT, reg & ~(1 << irq)); } event = sc->sc_eventstab[irq]; if (!event || TAILQ_EMPTY(&event->ie_handlers)) { if(irq == 1 && ar531x_soc < AR531X_SOC_AR5315) { ATH_READ_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_AHBPERR); ATH_READ_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_AHBDMAE); } /* Ignore non handle interrupts */ if (irq != 0 && irq != 6) printf("Stray APB IRQ %d\n", irq); continue; } intr_event_handle(event, PCPU_GET(curthread)->td_intr_frame); mips_intrcnt_inc(sc->sc_intr_counter[irq]); } } return (FILTER_HANDLED); }
static void ar5315_chip_detect_mem_size(void) { uint32_t memsize = 0; uint32_t memcfg, cw, rw, dw; /* * Determine the memory size. We query the board info. */ memcfg = ATH_READ_REG(AR5315_SDRAMCTL_BASE + AR5315_SDRAMCTL_MEM_CFG); cw = __SHIFTOUT(memcfg, AR5315_MEM_CFG_COL_WIDTH); cw += 1; rw = __SHIFTOUT(memcfg, AR5315_MEM_CFG_ROW_WIDTH); rw += 1; /* XXX: according to redboot, this could be wrong if DDR SDRAM */ dw = __SHIFTOUT(memcfg, AR5315_MEM_CFG_DATA_WIDTH); dw += 1; dw *= 8; /* bits */ /* not too sure about this math, but it _seems_ to add up */ memsize = (1 << cw) * (1 << rw) * dw; #if 0 printf("SDRAM_MEM_CFG =%x, cw=%d rw=%d dw=%d xmemsize=%d\n", memcfg, cw, rw, dw, memsize); #endif realmem = memsize; }
static int apb_filter(void *arg) { struct apb_softc *sc = arg; struct intr_event *event; uint32_t reg, irq; struct thread *td; struct trapframe *tf; reg = ATH_READ_REG(AR71XX_MISC_INTR_STATUS); for (irq = 0; irq < APB_NIRQS; irq++) { if (reg & (1 << irq)) { switch (ar71xx_soc) { case AR71XX_SOC_AR7240: case AR71XX_SOC_AR7241: case AR71XX_SOC_AR7242: case AR71XX_SOC_AR9330: case AR71XX_SOC_AR9331: case AR71XX_SOC_AR9341: case AR71XX_SOC_AR9342: case AR71XX_SOC_AR9344: case AR71XX_SOC_QCA9533: case AR71XX_SOC_QCA9533_V2: case AR71XX_SOC_QCA9556: case AR71XX_SOC_QCA9558: /* ACK/clear the given interrupt */ ATH_WRITE_REG(AR71XX_MISC_INTR_STATUS, (1 << irq)); break; default: /* fallthrough */ break; } event = sc->sc_eventstab[irq]; /* always count interrupts; spurious or otherwise */ mips_intrcnt_inc(sc->sc_intr_counter[irq]); if (!event || TAILQ_EMPTY(&event->ie_handlers)) { if (irq == APB_INTR_PMC) { td = PCPU_GET(curthread); tf = td->td_intr_frame; if (pmc_intr) (*pmc_intr)(PCPU_GET(cpuid), tf); continue; } /* Ignore timer interrupts */ if (irq != 0 && irq != 8 && irq != 9 && irq != 10) printf("Stray APB IRQ %d\n", irq); continue; } intr_event_handle(event, PCPU_GET(curthread)->td_intr_frame); } } return (FILTER_HANDLED); }
static int apb_filter(void *arg) { struct apb_softc *sc = arg; struct thread *td; uint32_t i, intr; td = curthread; /* Workaround: do not inflate intr nesting level */ td->td_intr_nesting_level--; if(ar531x_soc >= AR531X_SOC_AR5315) intr = ATH_READ_REG(AR5315_SYSREG_BASE + AR5315_SYSREG_MISC_INTSTAT); else intr = ATH_READ_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_MISC_INTSTAT); while ((i = fls(intr)) != 0) { i--; intr &= ~(1u << i); if(i == 1 && ar531x_soc < AR531X_SOC_AR5315) { ATH_READ_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_AHBPERR); ATH_READ_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_AHBDMAE); } if (intr_isrc_dispatch(PIC_INTR_ISRC(sc, i), curthread->td_intr_frame) != 0) { device_printf(sc->apb_dev, "Stray interrupt %u detected\n", i); apb_mask_irq((void*)i); continue; } } KASSERT(i == 0, ("all interrupts handled")); td->td_intr_nesting_level++; return (FILTER_HANDLED); }
static void apb_unmask_irq(void *source) { uint32_t reg; unsigned int irq = (unsigned int)source; reg = ATH_READ_REG(AR71XX_MISC_INTR_MASK); ATH_WRITE_REG(AR71XX_MISC_INTR_MASK, reg | (1 << irq)); }
static void apb_mask_irq(void *source) { unsigned int irq = (unsigned int)source; uint32_t reg; if(ar531x_soc >= AR531X_SOC_AR5315) { reg = ATH_READ_REG(AR5315_SYSREG_BASE + AR5315_SYSREG_MISC_INTMASK); ATH_WRITE_REG(AR5315_SYSREG_BASE + AR5315_SYSREG_MISC_INTMASK, reg & ~(1 << irq)); } else { reg = ATH_READ_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_MISC_INTMASK); ATH_WRITE_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_MISC_INTMASK, reg & ~(1 << irq)); } }
static void apb_pic_post_filter(device_t dev, struct intr_irqsrc *isrc) { uint32_t reg, irq; irq = ((struct apb_pic_irqsrc *)isrc)->irq; if(ar531x_soc >= AR531X_SOC_AR5315) { reg = ATH_READ_REG(AR5315_SYSREG_BASE + AR5315_SYSREG_MISC_INTSTAT); ATH_WRITE_REG(AR5315_SYSREG_BASE + AR5315_SYSREG_MISC_INTSTAT, reg & ~(1 << irq)); } else { reg = ATH_READ_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_MISC_INTSTAT); ATH_WRITE_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_MISC_INTSTAT, reg & ~(1 << irq)); } }
void platform_reset(void) { uint32_t reg = ATH_READ_REG(AR71XX_RST_RESET); ATH_WRITE_REG(AR71XX_RST_RESET, reg | RST_RESET_FULL_CHIP); /* Wait for reset */ while(1) ; }
static int apb_intr(void *arg) { struct apb_softc *sc = arg; struct intr_event *event; uint32_t reg, irq; reg = ATH_READ_REG(AR71XX_MISC_INTR_STATUS); for (irq = 0; irq < APB_NIRQS; irq++) { if (reg & (1 << irq)) { switch (ar71xx_soc) { case AR71XX_SOC_AR7240: case AR71XX_SOC_AR7241: case AR71XX_SOC_AR7242: /* Ack/clear the irq on status register for AR724x */ ATH_WRITE_REG(AR71XX_MISC_INTR_STATUS, reg & ~(1 << irq)); break; default: /* fallthrough */ break; } event = sc->sc_eventstab[irq]; if (!event || TAILQ_EMPTY(&event->ie_handlers)) { /* Ignore timer interrupts */ if (irq != 0) printf("Stray APB IRQ %d\n", irq); continue; } /* TODO: frame instead of NULL? */ intr_event_handle(event, NULL); mips_intrcnt_inc(sc->sc_intr_counter[irq]); } } return (FILTER_HANDLED); }
static void ar5315_chip_detect_sys_frequency(void) { uint32_t freq_ref, freq_pll; static const uint8_t pll_divide_table[] = { 2, 3, 4, 6, 3, /* * these entries are bogus, but it avoids a possible * bad table dereference */ 1, 1, 1 }; static const uint8_t pre_divide_table[] = { 1, 2, 4, 5 }; const uint32_t pllc = ATH_READ_REG(AR5315_SYSREG_BASE + AR5315_SYSREG_PLLC_CTL); const uint32_t refdiv = pre_divide_table[AR5315_PLLC_REF_DIV(pllc)]; const uint32_t fbdiv = AR5315_PLLC_FB_DIV(pllc); const uint32_t div2 = (AR5315_PLLC_DIV_2(pllc) + 1) * 2; /* results in 2 or 4 */ freq_ref = 40000000; /* 40MHz reference clk, reference and feedback dividers */ freq_pll = (freq_ref / refdiv) * div2 * fbdiv; const uint32_t pllout[4] = { /* CLKM select */ [0] = freq_pll / pll_divide_table[AR5315_PLLC_CLKM(pllc)], [1] = freq_pll / pll_divide_table[AR5315_PLLC_CLKM(pllc)], /* CLKC select */ [2] = freq_pll / pll_divide_table[AR5315_PLLC_CLKC(pllc)], /* ref_clk select */ [3] = freq_ref, /* use original reference clock */ };
void platform_start(__register_t a0 __unused, __register_t a1 __unused, __register_t a2 __unused, __register_t a3 __unused) { uint64_t platform_counter_freq; uint32_t reg; int argc, i, count = 0; char **argv, **envp; vm_offset_t kernend; /* * clear the BSS and SBSS segments, this should be first call in * the function */ kernend = (vm_offset_t)&end; memset(&edata, 0, kernend - (vm_offset_t)(&edata)); mips_postboot_fixup(); /* Initialize pcpu stuff */ mips_pcpu0_init(); argc = a0; argv = (char**)a1; envp = (char**)a2; /* * Protect ourselves from garbage in registers */ if (MIPS_IS_VALID_PTR(envp)) { for (i = 0; envp[i]; i += 2) { if (strcmp(envp[i], "memsize") == 0) realmem = btoc(strtoul(envp[i+1], NULL, 16)); else if (strcmp(envp[i], "ethaddr") == 0) { count = sscanf(envp[i+1], "%x.%x.%x.%x.%x.%x", &ar711_base_mac[0], &ar711_base_mac[1], &ar711_base_mac[2], &ar711_base_mac[3], &ar711_base_mac[4], &ar711_base_mac[5]); if (count < 6) memset(ar711_base_mac, 0, sizeof(ar711_base_mac)); } } } /* * Just wild guess. RedBoot let us down and didn't reported * memory size */ if (realmem == 0) realmem = btoc(32*1024*1024); /* phys_avail regions are in bytes */ phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); phys_avail[1] = ctob(realmem); physmem = realmem; /* * ns8250 uart code uses DELAY so ticker should be inititalized * before cninit. And tick_init_params refers to hz, so * init_param1 * should be called first. */ init_param1(); platform_counter_freq = ar71xx_cpu_freq(); mips_timer_init_params(platform_counter_freq, 1); cninit(); init_static_kenv(boot1_env, sizeof(boot1_env)); printf("platform frequency: %lld\n", platform_counter_freq); printf("arguments: \n"); printf(" a0 = %08x\n", a0); printf(" a1 = %08x\n", a1); printf(" a2 = %08x\n", a2); printf(" a3 = %08x\n", a3); printf("Cmd line:"); if (MIPS_IS_VALID_PTR(argv)) { for (i = 0; i < argc; i++) { printf(" %s", argv[i]); parse_argv(argv[i]); } } else printf ("argv is invalid"); printf("\n"); printf("Environment:\n"); if (MIPS_IS_VALID_PTR(envp)) { for (i = 0; envp[i]; i+=2) { printf(" %s = %s\n", envp[i], envp[i+1]); setenv(envp[i], envp[i+1]); } } else printf ("envp is invalid\n"); init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); mips_proc0_init(); mutex_init(); /* * Reset USB devices */ reg = ATH_READ_REG(AR71XX_RST_RESET); reg |= RST_RESET_USB_OHCI_DLL | RST_RESET_USB_HOST | RST_RESET_USB_PHY; ATH_WRITE_REG(AR71XX_RST_RESET, reg); DELAY(1000); reg &= ~(RST_RESET_USB_OHCI_DLL | RST_RESET_USB_HOST | RST_RESET_USB_PHY); ATH_WRITE_REG(AR71XX_RST_RESET, reg); ATH_WRITE_REG(AR71XX_USB_CTRL_CONFIG, USB_CTRL_CONFIG_OHCI_DES_SWAP | USB_CTRL_CONFIG_OHCI_BUF_SWAP | USB_CTRL_CONFIG_EHCI_DES_SWAP | USB_CTRL_CONFIG_EHCI_BUF_SWAP); ATH_WRITE_REG(AR71XX_USB_CTRL_FLADJ, (32 << USB_CTRL_FLADJ_HOST_SHIFT) | (3 << USB_CTRL_FLADJ_A5_SHIFT)); DELAY(1000); kdb_init(); #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif }
void ar71xx_detect_sys_type(void) { char *chip = "????"; uint32_t id; uint32_t major; uint32_t minor; uint32_t rev = 0; id = ATH_READ_REG(AR71XX_RST_RESET_REG_REV_ID); major = id & REV_ID_MAJOR_MASK; switch (major) { case REV_ID_MAJOR_AR71XX: minor = id & AR71XX_REV_ID_MINOR_MASK; rev = id >> AR71XX_REV_ID_REVISION_SHIFT; rev &= AR71XX_REV_ID_REVISION_MASK; ar71xx_cpu_ops = &ar71xx_chip_def; switch (minor) { case AR71XX_REV_ID_MINOR_AR7130: ar71xx_soc = AR71XX_SOC_AR7130; chip = "7130"; break; case AR71XX_REV_ID_MINOR_AR7141: ar71xx_soc = AR71XX_SOC_AR7141; chip = "7141"; break; case AR71XX_REV_ID_MINOR_AR7161: ar71xx_soc = AR71XX_SOC_AR7161; chip = "7161"; break; } break; case REV_ID_MAJOR_AR7240: ar71xx_soc = AR71XX_SOC_AR7240; chip = "7240"; ar71xx_cpu_ops = &ar724x_chip_def; rev = (id & AR724X_REV_ID_REVISION_MASK); break; case REV_ID_MAJOR_AR7241: ar71xx_soc = AR71XX_SOC_AR7241; chip = "7241"; ar71xx_cpu_ops = &ar724x_chip_def; rev = (id & AR724X_REV_ID_REVISION_MASK); break; case REV_ID_MAJOR_AR7242: ar71xx_soc = AR71XX_SOC_AR7242; chip = "7242"; ar71xx_cpu_ops = &ar724x_chip_def; rev = (id & AR724X_REV_ID_REVISION_MASK); break; case REV_ID_MAJOR_AR913X: minor = id & AR91XX_REV_ID_MINOR_MASK; rev = id >> AR91XX_REV_ID_REVISION_SHIFT; rev &= AR91XX_REV_ID_REVISION_MASK; ar71xx_cpu_ops = &ar91xx_chip_def; switch (minor) { case AR91XX_REV_ID_MINOR_AR9130: ar71xx_soc = AR71XX_SOC_AR9130; chip = "9130"; break; case AR91XX_REV_ID_MINOR_AR9132: ar71xx_soc = AR71XX_SOC_AR9132; chip = "9132"; break; } break; case REV_ID_MAJOR_AR9330: minor = 0; rev = (id & AR933X_REV_ID_REVISION_MASK); chip = "9330"; ar71xx_cpu_ops = &ar933x_chip_def; ar71xx_soc = AR71XX_SOC_AR9330; break; case REV_ID_MAJOR_AR9331: minor = 1; rev = (id & AR933X_REV_ID_REVISION_MASK); chip = "9331"; ar71xx_soc = AR71XX_SOC_AR9331; ar71xx_cpu_ops = &ar933x_chip_def; break; default: panic("ar71xx: unknown chip id:0x%08x\n", id); } sprintf(ar71xx_sys_type, "Atheros AR%s rev %u", chip, rev); }
/* 40MHz reference clk, reference and feedback dividers */ freq_pll = (freq_ref / refdiv) * div2 * fbdiv; const uint32_t pllout[4] = { /* CLKM select */ [0] = freq_pll / pll_divide_table[AR5315_PLLC_CLKM(pllc)], [1] = freq_pll / pll_divide_table[AR5315_PLLC_CLKM(pllc)], /* CLKC select */ [2] = freq_pll / pll_divide_table[AR5315_PLLC_CLKC(pllc)], /* ref_clk select */ [3] = freq_ref, /* use original reference clock */ }; const uint32_t amba_clkctl = ATH_READ_REG(AR5315_SYSREG_BASE + AR5315_SYSREG_AMBACLK); uint32_t ambadiv = AR5315_CLOCKCTL_DIV(amba_clkctl); ambadiv = ambadiv ? (ambadiv * 2) : 1; u_ar531x_ahb_freq = pllout[AR5315_CLOCKCTL_SELECT(amba_clkctl)] / ambadiv; const uint32_t cpu_clkctl = ATH_READ_REG(AR5315_SYSREG_BASE + AR5315_SYSREG_CPUCLK); uint32_t cpudiv = AR5315_CLOCKCTL_DIV(cpu_clkctl); cpudiv = cpudiv ? (cpudiv * 2) : 1; u_ar531x_cpu_freq = pllout[AR5315_CLOCKCTL_SELECT(cpu_clkctl)] / cpudiv; u_ar531x_ddr_freq = 0; } /* * This does not lock the CPU whilst doing the work!