Beispiel #1
0
static void use_hfrosc(int div, int trim)
{
  // Make sure the HFROSC is running at its default setting
  PRCI_REG(PRCI_HFROSCCFG) = (ROSC_DIV(div) | ROSC_TRIM(trim) | ROSC_EN(1));
  while ((PRCI_REG(PRCI_HFROSCCFG) & ROSC_RDY(1)) == 0) ;
  PRCI_REG(PRCI_PLLCFG) &= ~PLL_SEL(1);
}
void
select_clock(const clock_config_t *cfg)
{
    uint32_t new_qspi_div = 0;
    uint32_t old_qspi_div = SPI0_REG(SPI_REG_SCKDIV);

    /* Clock based on external escilator */
    if (!cfg->xosc || cfg->pll) {
        /* Turn on internal oscillator */
        PRCI_REG(PRCI_HFROSCCFG) = ROSC_DIV(cfg->osc_div) |
                                   ROSC_TRIM(MYNEWT_VAL(HFROSC_DEFAULT_TRIM_VAL)) |
                                   ROSC_EN(1);
        while ((PRCI_REG(PRCI_HFROSCCFG) & ROSC_RDY(1)) == 0) {
        }
        /* Compute CPU frequency on demand */
        cpu_freq = 0;
    }

    if (cfg->xosc) {
        /* Turn on external oscillator if not ready yet */
        if ((PRCI_REG(PRCI_HFXOSCCFG) & XOSC_RDY(1)) == 0) {
            PRCI_REG(PRCI_HFXOSCCFG) = XOSC_EN(1);
            while ((PRCI_REG(PRCI_HFXOSCCFG) & XOSC_RDY(1)) == 0) {
            }
        }
        cpu_freq = cfg->frq;
    }

    /*
     * If reqested closk is higher then FLASH_MAX_CLOCK change divider so QSPI
     * clock is in rage.
     */
    if (cfg->frq >= MYNEWT_VAL(FLASH_MAX_CLOCK) * 2) {
        new_qspi_div = (cfg->frq + MYNEWT_VAL(FLASH_MAX_CLOCK) - 1) / (2 * MYNEWT_VAL(FLASH_MAX_CLOCK)) - 1;
    }

    /* New qspi divider is higher, reduce qspi clock before switching to higher clock */
    if (new_qspi_div > old_qspi_div) {
        SPI0_REG(SPI_REG_SCKDIV) = new_qspi_div;
    }

    PRCI_REG(PRCI_PLLDIV) = PLL_FINAL_DIV_BY_1(cfg->pll_outdiv1) |
                            PLL_FINAL_DIV(cfg->pll_out_div);

    if (cfg->pll) {
        uint32_t now;
        uint32_t pllcfg = PLL_REFSEL(cfg->xosc) |
                          PLL_R(cfg->pll_div_r) | PLL_F(cfg->pll_mul_f) | PLL_Q(cfg->pll_div_q);
        PRCI_REG(PRCI_PLLCFG) = PLL_BYPASS(1) | pllcfg;
        PRCI_REG(PRCI_PLLCFG) ^= PLL_BYPASS(1);

        /* 100us lock grace period */
        now = mtime_lo();
        while (mtime_lo() - now < 4) {
        }

        /* Now it is safe to check for PLL Lock */
        while ((PRCI_REG(PRCI_PLLCFG) & PLL_LOCK(1)) == 0) {
        }

        /* Select PLL as clock source */
        PRCI_REG(PRCI_PLLCFG) |= PLL_SEL(1) | pllcfg;
    } else {
        /* Select bypassed PLL as source signal, it allows to use HFXOSC */
        PRCI_REG(PRCI_PLLCFG) = PLL_BYPASS(1) | PLL_REFSEL(cfg->xosc) | PLL_SEL(1);
    }

    /*
     * Old qspi divider was higher, now it's safe to reduce divider, increasing
     * qspi clock for better performance
     */
    if (new_qspi_div < old_qspi_div) {
        SPI0_REG(SPI_REG_SCKDIV) = new_qspi_div;
    }
}