diff --git a/drivers/clock_control/clock_control_mcux_ccm_rev2.c b/drivers/clock_control/clock_control_mcux_ccm_rev2.c index 8edb33e379..c99741a78f 100644 --- a/drivers/clock_control/clock_control_mcux_ccm_rev2.c +++ b/drivers/clock_control/clock_control_mcux_ccm_rev2.c @@ -132,6 +132,14 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, *rate = 393216000 / divider; return 0; +#endif +#ifdef CONFIG_MEMC_MCUX_FLEXSPI + case IMX_CCM_FLEXSPI_CLK: + clock_root = kCLOCK_Root_Flexspi1; + break; + case IMX_CCM_FLEXSPI2_CLK: + clock_root = kCLOCK_Root_Flexspi2; + break; #endif default: return -EINVAL; @@ -144,10 +152,46 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, return 0; } +/* + * Since this function is used to reclock the FlexSPI when running in + * XIP, it must be located in RAM when MEMC driver is enabled. + */ +#ifdef CONFIG_MEMC_MCUX_FLEXSPI +#define CCM_SET_FUNC_ATTR __ramfunc +#else +#define CCM_SET_FUNC_ATTR +#endif + +static int CCM_SET_FUNC_ATTR mcux_ccm_set_subsys_rate(const struct device *dev, + clock_control_subsys_t subsys, + clock_control_subsys_rate_t rate) +{ + uint32_t clock_name = (uintptr_t)subsys; + uint32_t clock_rate = (uintptr_t)rate; + + switch (clock_name) { + case IMX_CCM_FLEXSPI_CLK: + __fallthrough; + case IMX_CCM_FLEXSPI2_CLK: +#if defined(CONFIG_SOC_SERIES_IMX_RT11XX) && defined(CONFIG_MEMC_MCUX_FLEXSPI) + /* The SOC is using the FlexSPI for XIP. Therefore, + * the FlexSPI itself must be managed within the function, + * which is SOC specific. + */ + return flexspi_clock_set_freq(clock_name, clock_rate); +#endif + default: + /* Silence unused variable warning */ + ARG_UNUSED(clock_rate); + return -ENOTSUP; + } +} + static const struct clock_control_driver_api mcux_ccm_driver_api = { .on = mcux_ccm_on, .off = mcux_ccm_off, .get_rate = mcux_ccm_get_subsys_rate, + .set_rate = mcux_ccm_set_subsys_rate, }; DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, PRE_KERNEL_1, diff --git a/soc/arm/nxp_imx/rt/CMakeLists.txt b/soc/arm/nxp_imx/rt/CMakeLists.txt index e88fc46e28..a8f1d00765 100644 --- a/soc/arm/nxp_imx/rt/CMakeLists.txt +++ b/soc/arm/nxp_imx/rt/CMakeLists.txt @@ -35,6 +35,14 @@ if (CONFIG_SOC_SERIES_IMX_RT10XX AND CONFIG_MEMC_MCUX_FLEXSPI) endif() endif () + +if (CONFIG_SOC_SERIES_IMX_RT11XX AND CONFIG_MEMC_MCUX_FLEXSPI) + zephyr_sources(flexspi_rt11xx.c) + if (CONFIG_FLASH_MCUX_FLEXSPI_XIP) + zephyr_code_relocate(FILES flexspi_rt11xx.c LOCATION ITCM_TEXT) + endif() +endif () + if (CONFIG_PM AND CONFIG_SOC_SERIES_IMX_RT10XX) zephyr_sources(power_rt10xx.c) zephyr_code_relocate(FILES power_rt10xx.c LOCATION ITCM_TEXT) diff --git a/soc/arm/nxp_imx/rt/flexspi_rt11xx.c b/soc/arm/nxp_imx/rt/flexspi_rt11xx.c new file mode 100644 index 0000000000..8b8b34d868 --- /dev/null +++ b/soc/arm/nxp_imx/rt/flexspi_rt11xx.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +uint32_t flexspi_clock_set_freq(uint32_t clock_name, uint32_t rate) +{ + clock_name_t root; + uint32_t root_rate; + FLEXSPI_Type *flexspi; + clock_root_t flexspi_clk; + clock_ip_name_t clk_gate; + uint32_t divider; + + switch (clock_name) { + case IMX_CCM_FLEXSPI_CLK: + flexspi_clk = kCLOCK_Root_Flexspi1; + flexspi = (FLEXSPI_Type *)DT_REG_ADDR(DT_NODELABEL(flexspi)); + clk_gate = kCLOCK_Flexspi1; + break; + case IMX_CCM_FLEXSPI2_CLK: + flexspi_clk = kCLOCK_Root_Flexspi2; + flexspi = (FLEXSPI_Type *)DT_REG_ADDR(DT_NODELABEL(flexspi2)); + clk_gate = kCLOCK_Flexspi2; + break; + default: + return -ENOTSUP; + } + root = CLOCK_GetRootClockSource(flexspi_clk, + CLOCK_GetRootClockMux(flexspi_clk)); + /* Get clock root frequency */ + root_rate = CLOCK_GetFreq(root); + /* Select a divider based on root frequency */ + divider = MIN((root_rate / rate), CCM_CLOCK_ROOT_CONTROL_DIV_MASK); + + while (FLEXSPI_GetBusIdleStatus(flexspi) == false) { + /* Spin */ + } + FLEXSPI_Enable(flexspi, false); + + CLOCK_DisableClock(clk_gate); + + CLOCK_SetRootClockDiv(flexspi_clk, divider); + + CLOCK_EnableClock(clk_gate); + + FLEXSPI_Enable(flexspi, true); + + FLEXSPI_SoftwareReset(flexspi); + + return 0; +}