static int ar5312_enable_device(const struct atheros_device *adv) { const struct ar531x_boarddata * const info = atheros_get_board_info(); if (info != NULL && adv->adv_mask && ((adv->adv_mask & info->config) == 0)) { return -1; } if (adv->adv_reset) { /* put device into reset */ PUTSYSREG(AR5312_SYSREG_RESETCTL, GETSYSREG(AR5312_SYSREG_RESETCTL) | adv->adv_reset); delay(15000); /* XXX: tsleep? */ /* take it out of reset */ PUTSYSREG(AR5312_SYSREG_RESETCTL, GETSYSREG(AR5312_SYSREG_RESETCTL) & ~adv->adv_reset); delay(25); } if (adv->adv_enable) { PUTSYSREG(AR5312_SYSREG_ENABLE, GETSYSREG(AR5312_SYSREG_ENABLE) | adv->adv_enable); } return 0; }
int ar531x_enable_device(const struct ar531x_device *dev) { const struct ar531x_boarddata *info; info = ar531x_board_info(); if (dev->mask && ((dev->mask & info->config) == 0)) { return -1; } if (dev->reset) { /* put device into reset */ PUTSYSREG(AR5312_SYSREG_RESETCTL, GETSYSREG(AR5312_SYSREG_RESETCTL) | dev->reset); delay(15000); /* XXX: tsleep? */ /* take it out of reset */ PUTSYSREG(AR5312_SYSREG_RESETCTL, GETSYSREG(AR5312_SYSREG_RESETCTL) & ~dev->reset); delay(25); } if (dev->enable) { PUTSYSREG(AR5312_SYSREG_ENABLE, GETSYSREG(AR5312_SYSREG_ENABLE) | dev->enable); } return 0; }
uint32_t ar531x_cpu_freq(void) { static uint32_t cpufreq; uint32_t wisoc = GETSYSREG(AR5312_SYSREG_REVISION); uint32_t predivmask; uint32_t predivshift; uint32_t multmask; uint32_t multshift; uint32_t doublermask; uint32_t divisor; uint32_t multiplier; uint32_t clockctl; const int predivide_table[4] = { 1, 2, 4, 5 }; /* XXX: in theory we might be able to get clock from bootrom */ /* * This logic looks at the clock control register and * determines the actual CPU frequency. These parts lack any * kind of real-time clock on them, but the cpu clocks should * be very accurate -- WiFi requires usec resolution timers. */ if (cpufreq) { return cpufreq; } if (AR5312_REVISION_MAJOR(wisoc) == AR5312_REVISION_MAJ_AR2313) { predivmask = AR2313_CLOCKCTL_PREDIVIDE_MASK; predivshift = AR2313_CLOCKCTL_PREDIVIDE_SHIFT; multmask = AR2313_CLOCKCTL_MULTIPLIER_MASK; multshift = AR2313_CLOCKCTL_MULTIPLIER_SHIFT; doublermask = AR2313_CLOCKCTL_DOUBLER_MASK; } else { predivmask = AR5312_CLOCKCTL_PREDIVIDE_MASK; predivshift = AR5312_CLOCKCTL_PREDIVIDE_SHIFT; multmask = AR5312_CLOCKCTL_MULTIPLIER_MASK; multshift = AR5312_CLOCKCTL_MULTIPLIER_SHIFT; doublermask = AR5312_CLOCKCTL_DOUBLER_MASK; } /* * Note that the source clock involved here is a 40MHz. */ clockctl = GETSYSREG(AR5312_SYSREG_CLOCKCTL); divisor = predivide_table[(clockctl & predivmask) >> predivshift]; multiplier = (clockctl & multmask) >> multshift; if (clockctl & doublermask) multiplier <<= 1; cpufreq = (40000000 / divisor) * multiplier; return (cpufreq); }
static void ar5312_bus_init(void) { /* * Clear previous AHB errors */ GETSYSREG(AR5312_SYSREG_AHBPERR); GETSYSREG(AR5312_SYSREG_AHBDMAE); }
static void ar5312_get_freqs(struct arfreqs *freqs) { const uint32_t wisoc = GETSYSREG(AR5312_SYSREG_REVISION); uint32_t predivisor; uint32_t multiplier; /* * This logic looks at the clock control register and * determines the actual CPU frequency. These parts lack any * kind of real-time clock on them, but the cpu clocks should * be very accurate -- WiFi requires usec resolution timers. */ const uint32_t clockctl = GETSYSREG(AR5312_SYSREG_CLOCKCTL); if (AR5312_REVISION_MAJOR(wisoc) == AR5312_REVISION_MAJ_AR2313) { predivisor = __SHIFTOUT(clockctl, AR2313_CLOCKCTL_PREDIVIDE); multiplier = __SHIFTOUT(clockctl, AR2313_CLOCKCTL_MULTIPLIER); } else { predivisor = __SHIFTOUT(clockctl, AR5312_CLOCKCTL_PREDIVIDE); multiplier = __SHIFTOUT(clockctl, AR5312_CLOCKCTL_MULTIPLIER); if (clockctl & AR5312_CLOCKCTL_DOUBLER) multiplier <<= 1; } /* * Note that the source clock involved here is a 40MHz. */ const uint32_t divisor = (0x5421 >> (predivisor * 4)) & 15; const uint32_t cpufreq = (40000000 / divisor) * multiplier; freqs->freq_cpu = cpufreq; freqs->freq_bus = cpufreq / 4; freqs->freq_mem = 0; freqs->freq_ref = 40000000; freqs->freq_pll = 40000000; }
const char * ar531x_cpuname(void) { uint32_t revision; revision = GETSYSREG(AR5312_SYSREG_REVISION); switch (AR5312_REVISION_MAJOR(revision)) { case AR5312_REVISION_MAJ_AR5311: return ("Atheros AR5311"); case AR5312_REVISION_MAJ_AR5312: return ("Atheros AR5312"); case AR5312_REVISION_MAJ_AR2313: return ("Atheros AR2313"); case AR5312_REVISION_MAJ_AR5315: return ("Atheros AR5315"); default: return ("Atheros AR531X"); } }
void ar531x_device_register(struct device *dev, void *aux) { struct arbus_attach_args *aa = aux; const struct ar531x_boarddata *info; info = ar531x_board_info(); if (info == NULL) { /* nothing known about this board! */ return; } /* * We don't ever know the boot device. But that's because the * firmware only loads from the network. */ /* Fetch the MAC addresses. */ if (device_is_a(dev, "ae")) { const uint8_t *enet; if (aa->aa_addr == AR5312_ENET0_BASE) enet = info->enet0Mac; else if (aa->aa_addr == AR5312_ENET1_BASE) enet = info->enet1Mac; else return; addprop_data(dev, "mac-addr", enet, ETHER_ADDR_LEN); } if (device_is_a(dev, "ath")) { const uint8_t *enet; if (aa->aa_addr == AR5312_WLAN0_BASE) enet = info->wlan0Mac; else if (aa->aa_addr == AR5312_WLAN1_BASE) enet = info->wlan1Mac; else return; addprop_data(dev, "mac-addr", enet, ETHER_ADDR_LEN); addprop_integer(dev, "wmac-rev", AR5312_REVISION_WMAC(GETSYSREG(AR5312_SYSREG_REVISION))); } if (device_is_a(dev, "com")) { addprop_integer(dev, "frequency", ar531x_cpu_freq() / 4); } if (device_is_a(dev, "argpio")) { if (info->config & BD_RSTFACTORY) { addprop_integer(dev, "reset-pin", info->resetConfigGpio); } if (info->config & BD_SYSLED) { addprop_integer(dev, "sysled-pin", info->sysLedGpio); } } }