예제 #1
0
파일: listcache.c 프로젝트: pscedu/pfl
/*
 * Remove list cache external access registration.
 * @plc: the list cache to unregister, must be UNLOCKED.
 */
void
lc_unregister(struct psc_listcache *plc)
{
	pfl_opstat_destroy(plc->plc_nseen);
	pfl_opstat_destroy(plc->plc_st_removes);

	PLL_LOCK(&psc_listcaches);
	LIST_CACHE_LOCK(plc);
	pll_remove(&psc_listcaches, plc);
	LIST_CACHE_ULOCK(plc);
	PLL_ULOCK(&psc_listcaches);
}
예제 #2
0
파일: listcache.c 프로젝트: pscedu/pfl
/*
 * Find a list cache by its registration name.
 * @name: name of list cache.
 * Notes: returns the list cache locked if found.
 */
struct psc_listcache *
lc_lookup(const char *name)
{
	struct psc_listcache *plc;

	PLL_LOCK(&psc_listcaches);
	PLL_FOREACH(plc, &psc_listcaches)
		if (strcmp(name, plc->plc_name) == 0) {
			LIST_CACHE_LOCK(plc);
			break;
		}
	PLL_ULOCK(&psc_listcaches);
	return (plc);
}
예제 #3
0
파일: listcache.c 프로젝트: pscedu/pfl
/*
 * Register a list cache for external access.
 * @plc: the list cache to register.
 * @name: printf(3) format of name for list.
 * @ap: variable argument list for printf(3) name argument.
 */
void
lc_vregister(struct psc_listcache *plc, const char *name, va_list ap)
{
	int rc;

	PLL_LOCK(&psc_listcaches);
	LIST_CACHE_LOCK(plc);

	rc = vsnprintf(plc->plc_name, sizeof(plc->plc_name), name, ap);
	if (rc == -1)
		psc_fatal("vsnprintf");
	if (rc > (int)sizeof(plc->plc_name))
		psc_fatalx("plc_name is too large (%s)", name);

	plc->plc_nseen = pfl_opstat_initf(OPSTF_BASE10,
	    "listcache.%s.adds", plc->plc_name);
	plc->plc_st_removes = pfl_opstat_initf(OPSTF_BASE10,
	    "listcache.%s.removes", plc->plc_name);
	pll_add_sorted(&psc_listcaches, plc, lc_cmp);

	LIST_CACHE_ULOCK(plc);
	PLL_ULOCK(&psc_listcaches);
}
예제 #4
0
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;
    }
}
예제 #5
0
void use_pll(int refsel, int bypass, int r, int f, int q)
{
  // Ensure that we aren't running off the PLL before we mess with it.
  if (PRCI_REG(PRCI_PLLCFG) & PLL_SEL(1)) {
    // Make sure the HFROSC is running at its default setting
    use_hfrosc(4, 16);
  }

  // Set PLL Source to be HFXOSC if available.
  uint32_t config_value = 0;

  config_value |= PLL_REFSEL(refsel);

  if (bypass) {
    // Bypass
    config_value |= PLL_BYPASS(1);

    PRCI_REG(PRCI_PLLCFG) = config_value;

    // If we don't have an HFXTAL, this doesn't really matter.
    // Set our Final output divide to divide-by-1:
    PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0));
  } else {
    // In case we are executing from QSPI,
    // (which is quite likely) we need to
    // set the QSPI clock divider appropriately
    // before boosting the clock frequency.

    // Div = f_sck/2
    SPI0_REG(SPI_REG_SCKDIV) = 8;

    // Set DIV Settings for PLL
    // Both HFROSC and HFXOSC are modeled as ideal
    // 16MHz sources (assuming dividers are set properly for
    // HFROSC).
    // (Legal values of f_REF are 6-48MHz)

    // Set DIVR to divide-by-2 to get 8MHz frequency
    // (legal values of f_R are 6-12 MHz)

    config_value |= PLL_BYPASS(1);
    config_value |= PLL_R(r);

    // Set DIVF to get 512Mhz frequncy
    // There is an implied multiply-by-2, 16Mhz.
    // So need to write 32-1
    // (legal values of f_F are 384-768 MHz)
    config_value |= PLL_F(f);

    // Set DIVQ to divide-by-2 to get 256 MHz frequency
    // (legal values of f_Q are 50-400Mhz)
    config_value |= PLL_Q(q);

    // Set our Final output divide to divide-by-1:
    PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0));

    PRCI_REG(PRCI_PLLCFG) = config_value;

    // Un-Bypass the PLL.
    PRCI_REG(PRCI_PLLCFG) &= ~PLL_BYPASS(1);

    // Wait for PLL Lock
    // Note that the Lock signal can be glitchy.
    // Need to wait 100 us
    // RTC is running at 32kHz.
    // So wait 4 ticks of RTC.
    uint32_t 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) ;
  }

  // Switch over to PLL Clock source
  PRCI_REG(PRCI_PLLCFG) |= PLL_SEL(1);
}