122 lines
3.5 KiB
C
122 lines
3.5 KiB
C
/*
|
|
* Copyright 2022 NXP
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/*
|
|
* To be explicitly clear, the following set of functions
|
|
* cannot execute in place from flash and are instead
|
|
* relocated into internal SRAM.
|
|
*/
|
|
|
|
#include "fsl_power.h"
|
|
#include "flash_clock_setup.h"
|
|
|
|
#define FLEXSPI_DLL_LOCK_RETRY (10)
|
|
|
|
static void flash_deinit(FLEXSPI_Type *base)
|
|
{
|
|
/* Wait until FLEXSPI is not busy */
|
|
while (!((base->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) &&
|
|
(base->STS0 & FLEXSPI_STS0_SEQIDLE_MASK))) {
|
|
}
|
|
/* Disable module during the reset procedure */
|
|
base->MCR0 |= FLEXSPI_MCR0_MDIS_MASK;
|
|
}
|
|
|
|
static void flash_init(FLEXSPI_Type *base)
|
|
{
|
|
uint32_t status;
|
|
uint32_t lastStatus;
|
|
uint32_t retry;
|
|
uint32_t mask = 0;
|
|
|
|
/* Enable FLEXSPI module */
|
|
base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;
|
|
|
|
base->MCR0 |= FLEXSPI_MCR0_SWRESET_MASK;
|
|
while (base->MCR0 & FLEXSPI_MCR0_SWRESET_MASK) {
|
|
}
|
|
|
|
/* Need to wait DLL locked if DLL enabled */
|
|
if (0U != (base->DLLCR[0] & FLEXSPI_DLLCR_DLLEN_MASK)) {
|
|
lastStatus = base->STS2;
|
|
retry = FLEXSPI_DLL_LOCK_RETRY;
|
|
/* Flash on port A */
|
|
if (((base->FLSHCR0[0] & FLEXSPI_FLSHCR0_FLSHSZ_MASK) > 0) ||
|
|
((base->FLSHCR0[1] & FLEXSPI_FLSHCR0_FLSHSZ_MASK) > 0)) {
|
|
mask |= FLEXSPI_STS2_AREFLOCK_MASK | FLEXSPI_STS2_ASLVLOCK_MASK;
|
|
}
|
|
/* Flash on port B */
|
|
if (((base->FLSHCR0[2] & FLEXSPI_FLSHCR0_FLSHSZ_MASK) > 0) ||
|
|
((base->FLSHCR0[3] & FLEXSPI_FLSHCR0_FLSHSZ_MASK) > 0)) {
|
|
mask |= FLEXSPI_STS2_BREFLOCK_MASK | FLEXSPI_STS2_BSLVLOCK_MASK;
|
|
}
|
|
/* Wait slave delay line locked and slave reference delay line locked. */
|
|
do {
|
|
status = base->STS2;
|
|
if ((status & mask) == mask) {
|
|
/* Locked */
|
|
retry = 100;
|
|
break;
|
|
} else if (status == lastStatus) {
|
|
/* Same delay cell number in calibration */
|
|
retry--;
|
|
} else {
|
|
retry = FLEXSPI_DLL_LOCK_RETRY;
|
|
lastStatus = status;
|
|
}
|
|
} while (retry > 0);
|
|
/* According to ERR011377, need to delay at least 100 NOPs
|
|
* to ensure the DLL is locked.
|
|
*/
|
|
for (; retry > 0U; retry--) {
|
|
__NOP();
|
|
}
|
|
}
|
|
}
|
|
|
|
void flexspi_setup_clock(FLEXSPI_Type *base, uint32_t src, uint32_t divider)
|
|
{
|
|
if (base == FLEXSPI) {
|
|
if ((CLKCTL0->FLEXSPIFCLKSEL != CLKCTL0_FLEXSPIFCLKSEL_SEL(src)) ||
|
|
((CLKCTL0->FLEXSPIFCLKDIV & CLKCTL0_FLEXSPIFCLKDIV_DIV_MASK) !=
|
|
(divider - 1))) {
|
|
/* Always deinit FLEXSPI and init FLEXSPI for the flash to make sure the
|
|
* flash works correctly after the FLEXSPI root clock changed as the
|
|
* default FLEXSPI configuration may does not work for the new root
|
|
* clock frequency.
|
|
*/
|
|
flash_deinit(base);
|
|
|
|
/* Disable clock before changing clock source */
|
|
CLKCTL0->PSCCTL0_CLR = CLKCTL0_PSCCTL0_CLR_FLEXSPI_OTFAD_CLK_MASK;
|
|
/* Update flexspi clock */
|
|
CLKCTL0->FLEXSPIFCLKSEL = CLKCTL0_FLEXSPIFCLKSEL_SEL(src);
|
|
/* Reset the divider counter */
|
|
CLKCTL0->FLEXSPIFCLKDIV |= CLKCTL0_FLEXSPIFCLKDIV_RESET_MASK;
|
|
CLKCTL0->FLEXSPIFCLKDIV = CLKCTL0_FLEXSPIFCLKDIV_DIV(divider - 1);
|
|
while ((CLKCTL0->FLEXSPIFCLKDIV) & CLKCTL0_FLEXSPIFCLKDIV_REQFLAG_MASK) {
|
|
}
|
|
/* Enable FLEXSPI clock again */
|
|
CLKCTL0->PSCCTL0_SET = CLKCTL0_PSCCTL0_SET_FLEXSPI_OTFAD_CLK_MASK;
|
|
|
|
flash_init(base);
|
|
}
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* This function is used to change FlexSPI clock to a stable source before clock
|
|
* sources(Such as PLL and Main clock) updating in case XIP (execute code on
|
|
* FLEXSPI memory.)
|
|
*/
|
|
void flexspi_clock_safe_config(void)
|
|
{
|
|
/* Move FLEXSPI clock source from main clock to FRO192M / 2 to avoid instruction/data
|
|
* fetch issue in XIP when updating PLL and main clock.
|
|
*/
|
|
flexspi_setup_clock(FLEXSPI, 3U, 1U);
|
|
}
|