| /* |
| * 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); |
| } |