diff --git a/drivers/clock_control/clock_control_mcux_ccm.c b/drivers/clock_control/clock_control_mcux_ccm.c index 355f85dfc3e..6245788961c 100644 --- a/drivers/clock_control/clock_control_mcux_ccm.c +++ b/drivers/clock_control/clock_control_mcux_ccm.c @@ -316,16 +316,64 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, / (CLOCK_GetDiv(kCLOCK_Sai3PreDiv) + 1) / (CLOCK_GetDiv(kCLOCK_Sai3Div) + 1); break; +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexspi), okay) + case IMX_CCM_FLEXSPI_CLK: + *rate = CLOCK_GetClockRootFreq(kCLOCK_FlexspiClkRoot); + break; +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexspi2), okay) + case IMX_CCM_FLEXSPI2_CLK: + *rate = CLOCK_GetClockRootFreq(kCLOCK_Flexspi2ClkRoot); + break; #endif } return 0; } +/* + * Since this function is used to reclock the FlexSPI when running in + * XIP, it must be located in RAM when MEMC Flexspi 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_RT10XX) && 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, }; static int mcux_ccm_init(const struct device *dev) diff --git a/drivers/flash/flash_mcux_flexspi_hyperflash.c b/drivers/flash/flash_mcux_flexspi_hyperflash.c index b0a04ee63ed..5c03febc29a 100644 --- a/drivers/flash/flash_mcux_flexspi_hyperflash.c +++ b/drivers/flash/flash_mcux_flexspi_hyperflash.c @@ -433,8 +433,9 @@ static int flash_flexspi_hyperflash_write(const struct device *dev, off_t offset key = irq_lock(); } + /* Clock FlexSPI at 84 MHZ (42MHz SCLK in DDR mode) */ (void)memc_flexspi_update_clock(&data->controller, &data->config, - data->port, MEMC_FLEXSPI_CLOCK_42M); + data->port, MHZ(84)); while (len) { /* Writing between two page sizes crashes the platform so we @@ -477,8 +478,9 @@ static int flash_flexspi_hyperflash_write(const struct device *dev, off_t offset len -= i; } + /* Clock FlexSPI at 332 MHZ (166 MHz SCLK in DDR mode) */ (void)memc_flexspi_update_clock(&data->controller, &data->config, - data->port, MEMC_FLEXSPI_CLOCK_166M); + data->port, MHZ(332)); #ifdef CONFIG_HAS_MCUX_CACHE DCACHE_InvalidateByRange((uint32_t) dst, size); diff --git a/drivers/memc/memc_mcux_flexspi.c b/drivers/memc/memc_mcux_flexspi.c index 84ab86a793a..e0c8f6faf96 100644 --- a/drivers/memc/memc_mcux_flexspi.c +++ b/drivers/memc/memc_mcux_flexspi.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -60,6 +61,8 @@ struct memc_flexspi_data { struct port_lut port_luts[kFLEXSPI_PortCount]; struct memc_flexspi_buf_cfg *buf_cfg; uint8_t buf_cfg_cnt; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; }; void memc_flexspi_wait_bus_idle(const struct device *dev) @@ -79,30 +82,56 @@ bool memc_flexspi_is_running_xip(const struct device *dev) int memc_flexspi_update_clock(const struct device *dev, flexspi_device_config_t *device_config, - flexspi_port_t port, enum memc_flexspi_clock_t clock) + flexspi_port_t port, uint32_t freq_hz) { -#if CONFIG_SOC_SERIES_IMX_RT10XX struct memc_flexspi_data *data = dev->data; + uint32_t rate; + uint32_t key; + int ret; + /* To reclock the FlexSPI, we should: + * - disable the module + * - set the new clock + * - reenable the module + * - reset the module + * We CANNOT XIP at any point during this process + */ + key = irq_lock(); memc_flexspi_wait_bus_idle(dev); - FLEXSPI_Enable(data->base, false); - - flexspi_clock_set_div(clock == MEMC_FLEXSPI_CLOCK_166M ? 0 : 3); - - FLEXSPI_Enable(data->base, true); + ret = clock_control_set_rate(data->clock_dev, data->clock_subsys, + (clock_control_subsys_rate_t)freq_hz); + if (ret < 0) { + irq_unlock(key); + return ret; + } + /* + * We need to update the DLL value before we call clock_control_get_rate, + * because this will cause XIP (flash reads) to occur. Although the + * true flash clock is not known, assume the set_rate function programmed + * a value close to what we requested. + */ + device_config->flexspiRootClk = freq_hz; + FLEXSPI_UpdateDllValue(data->base, device_config, port); memc_flexspi_reset(dev); - device_config->flexspiRootClk = flexspi_clock_get_freq(); + memc_flexspi_wait_bus_idle(dev); + ret = clock_control_get_rate(data->clock_dev, data->clock_subsys, &rate); + if (ret < 0) { + irq_unlock(key); + return ret; + } + + + device_config->flexspiRootClk = rate; FLEXSPI_UpdateDllValue(data->base, device_config, port); memc_flexspi_reset(dev); + irq_unlock(key); + return 0; -#else - return -ENOTSUP; -#endif } int memc_flexspi_set_device_config(const struct device *dev, @@ -332,6 +361,9 @@ static int memc_flexspi_pm_action(const struct device *dev, enum pm_device_actio .buf_cfg_cnt = sizeof(buf_cfg_##n) / \ sizeof(struct memc_flexspi_buf_cfg), \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .clock_subsys = (clock_control_subsys_t) \ + DT_INST_CLOCKS_CELL(n, name), \ }; \ \ PM_DEVICE_DT_INST_DEFINE(n, memc_flexspi_pm_action); \ diff --git a/drivers/memc/memc_mcux_flexspi.h b/drivers/memc/memc_mcux_flexspi.h index a8495fc9289..ee9fa463655 100644 --- a/drivers/memc/memc_mcux_flexspi.h +++ b/drivers/memc/memc_mcux_flexspi.h @@ -8,13 +8,6 @@ #include #include -enum memc_flexspi_clock_t { - /* Flexspi clock 332M, DDR mode, internal clock 166M. */ - MEMC_FLEXSPI_CLOCK_166M, - /* Flexspi clock 83M, DDR mode, internal clock 42M. */ - MEMC_FLEXSPI_CLOCK_42M, -}; - /* Size of a command in the LUT table */ #define MEMC_FLEXSPI_CMD_SIZE 4U @@ -43,17 +36,17 @@ bool memc_flexspi_is_running_xip(const struct device *dev); /** * @brief Update clock selection of the FlexSPI device * - * Updates clock selection of the FlexSPI device to a new clock speed. + * Updates clock frequency of FlexSPI to new clock speed. * * @param dev: FlexSPI device * @param device_config: External device configuration. * @param port: FlexSPI port to use for this external device - * @param clock: new clock selection to apply + * @param freq_hz: new clock frequency to apply * @return 0 on success, negative value on failure */ int memc_flexspi_update_clock(const struct device *dev, flexspi_device_config_t *device_config, - flexspi_port_t port, enum memc_flexspi_clock_t clock); + flexspi_port_t port, uint32_t freq_hz); /** * @brief configure new FlexSPI device diff --git a/dts/arm/nxp/nxp_rt10xx.dtsi b/dts/arm/nxp/nxp_rt10xx.dtsi index 73e108f1005..3bc5749f271 100644 --- a/dts/arm/nxp/nxp_rt10xx.dtsi +++ b/dts/arm/nxp/nxp_rt10xx.dtsi @@ -126,6 +126,7 @@ ahb-bufferable; ahb-cacheable; status = "disabled"; + clocks = <&ccm IMX_CCM_FLEXSPI_CLK 0x0 0x0>; }; flexspi2: spi@402a4000 { @@ -137,6 +138,7 @@ ahb-bufferable; ahb-cacheable; status = "disabled"; + clocks = <&ccm IMX_CCM_FLEXSPI2_CLK 0x0 0x0>; }; semc: semc0@402f0000 { diff --git a/dts/arm/nxp/nxp_rt11xx.dtsi b/dts/arm/nxp/nxp_rt11xx.dtsi index 9e92a3e0226..6216b32cb46 100644 --- a/dts/arm/nxp/nxp_rt11xx.dtsi +++ b/dts/arm/nxp/nxp_rt11xx.dtsi @@ -95,6 +95,7 @@ #address-cells = <1>; #size-cells = <0>; status = "disabled"; + clocks = <&ccm IMX_CCM_FLEXSPI_CLK 0x0 0>; }; flexspi2: spi@400d0000 { @@ -104,6 +105,7 @@ #address-cells = <1>; #size-cells = <0>; status = "disabled"; + clocks = <&ccm IMX_CCM_FLEXSPI2_CLK 0x0 0>; }; semc: semc0@400d4000 { diff --git a/dts/arm/nxp/nxp_rt5xx_common.dtsi b/dts/arm/nxp/nxp_rt5xx_common.dtsi index d84d89b8528..867d30cc8ee 100644 --- a/dts/arm/nxp/nxp_rt5xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt5xx_common.dtsi @@ -687,6 +687,7 @@ interrupts = <42 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clkctl1 MCUX_FLEXSPI_CLK>; }; &flexspi2 { @@ -695,6 +696,7 @@ interrupts = <42 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clkctl1 MCUX_FLEXSPI2_CLK>; }; &nvic { diff --git a/dts/arm/nxp/nxp_rt6xx_common.dtsi b/dts/arm/nxp/nxp_rt6xx_common.dtsi index 62e8865b731..170622b068c 100644 --- a/dts/arm/nxp/nxp_rt6xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt6xx_common.dtsi @@ -501,6 +501,7 @@ #address-cells = <1>; #size-cells = <0>; status = "disabled"; + clocks = <&clkctl1 MCUX_FLEXSPI_CLK>; }; &nvic { diff --git a/include/zephyr/dt-bindings/clock/imx_ccm.h b/include/zephyr/dt-bindings/clock/imx_ccm.h index 3535c06935e..b20d1e5aecb 100644 --- a/include/zephyr/dt-bindings/clock/imx_ccm.h +++ b/include/zephyr/dt-bindings/clock/imx_ccm.h @@ -58,4 +58,7 @@ #define IMX_CCM_ENET_CLK 0x0E00UL #define IMX_CCM_ENET_PLL 0x0E01UL +#define IMX_CCM_FLEXSPI_CLK 0x0F00UL +#define IMX_CCM_FLEXSPI2_CLK 0x0F01UL + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_IMX_CCM_H_ */ diff --git a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h index fe011525846..c36d140b534 100644 --- a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h +++ b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h @@ -92,5 +92,8 @@ #define IMX_CCM_ENET_CLK 0x3000UL #define IMX_CCM_ENET_PLL 0x3001UL +/* FLEXSPI */ +#define IMX_CCM_FLEXSPI_CLK 0x4000UL +#define IMX_CCM_FLEXSPI2_CLK 0x4001UL #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_IMX_CCM_REV2_H_ */ diff --git a/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h b/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h index e273288a37e..404ba96de96 100644 --- a/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h +++ b/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h @@ -53,6 +53,9 @@ #define MCUX_DMIC_CLK 35 +#define MCUX_FLEXSPI_CLK 36 +#define MCUX_FLEXSPI2_CLK 37 + #define MCUX_MRT_CLK 40 #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MCUX_LPC_SYSCON_H_ */ diff --git a/soc/arm/nxp_imx/rt/CMakeLists.txt b/soc/arm/nxp_imx/rt/CMakeLists.txt index 92ab665a0ef..e88fc46e28e 100644 --- a/soc/arm/nxp_imx/rt/CMakeLists.txt +++ b/soc/arm/nxp_imx/rt/CMakeLists.txt @@ -28,9 +28,11 @@ if(CONFIG_PM) zephyr_sources_ifdef(CONFIG_SOC_SERIES_IMX_RT11XX power_rt11xx.c) endif() -if (CONFIG_FLASH_MCUX_FLEXSPI_XIP AND CONFIG_SOC_SERIES_IMX_RT10XX AND CONFIG_MEMC) +if (CONFIG_SOC_SERIES_IMX_RT10XX AND CONFIG_MEMC_MCUX_FLEXSPI) zephyr_sources(flexspi_rt10xx.c) - zephyr_code_relocate(FILES flexspi_rt10xx.c LOCATION ITCM_TEXT) + if (CONFIG_FLASH_MCUX_FLEXSPI_XIP) + zephyr_code_relocate(FILES flexspi_rt10xx.c LOCATION ITCM_TEXT) + endif() endif () if (CONFIG_PM AND CONFIG_SOC_SERIES_IMX_RT10XX) diff --git a/soc/arm/nxp_imx/rt/flexspi_rt10xx.c b/soc/arm/nxp_imx/rt/flexspi_rt10xx.c index b6335f0c256..a6a6239e9e7 100644 --- a/soc/arm/nxp_imx/rt/flexspi_rt10xx.c +++ b/soc/arm/nxp_imx/rt/flexspi_rt10xx.c @@ -5,50 +5,63 @@ */ #include +#include #include +#include +#include +#include -/* reimplementation of non-inline CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk) */ -static uint32_t clock_get_usb1_pll_pfd0_clk(void) +uint32_t flexspi_clock_set_freq(uint32_t clock_name, uint32_t rate) { - uint32_t freq; + uint8_t divider; + uint32_t root_rate; + FLEXSPI_Type *flexspi; + clock_div_t div_sel; + clock_ip_name_t clk_name; - if (!CLOCK_IsPllEnabled(CCM_ANALOG, kCLOCK_PllUsb1)) { - return 0; + switch (clock_name) { + case IMX_CCM_FLEXSPI_CLK: + /* Get clock root frequency */ + root_rate = CLOCK_GetClockRootFreq(kCLOCK_FlexspiClkRoot) * + (CLOCK_GetDiv(kCLOCK_FlexspiDiv) + 1); + flexspi = (FLEXSPI_Type *)DT_REG_ADDR(DT_NODELABEL(flexspi)); + div_sel = kCLOCK_FlexspiDiv; + clk_name = kCLOCK_FlexSpi; + break; +#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexspi2), okay) + case IMX_CCM_FLEXSPI2_CLK: + /* Get clock root frequency */ + root_rate = CLOCK_GetClockRootFreq(kCLOCK_Flexspi2ClkRoot) * + (CLOCK_GetDiv(kCLOCK_Flexspi2Div) + 1); + flexspi = (FLEXSPI_Type *)DT_REG_ADDR(DT_NODELABEL(flexspi2)); + div_sel = kCLOCK_Flexspi2Div; + clk_name = kCLOCK_FlexSpi2; + break; +#endif + default: + return -ENOTSUP; } + /* Select a divider based on root frequency. + * if we can't get an exact divider, round down + */ + divider = ((root_rate + (rate - 1)) / rate) - 1; + /* Cap divider to max value */ + divider = MIN(divider, kCLOCK_FlexspiDivBy8); - freq = CLOCK_GetPllBypassRefClk(CCM_ANALOG, kCLOCK_PllUsb1); - - if (CLOCK_IsPllBypassed(CCM_ANALOG, kCLOCK_PllUsb1)) { - return freq; + while (FLEXSPI_GetBusIdleStatus(flexspi) == false) { + /* Spin */ } + FLEXSPI_Enable(flexspi, false); - freq *= ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK) != 0) ? 22 : 20; + CLOCK_DisableClock(clk_name); - /* get current USB1 PLL PFD output frequency */ - freq /= (CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD0_FRAC_MASK) >> - CCM_ANALOG_PFD_480_PFD0_FRAC_SHIFT; - freq *= 18; + CLOCK_SetDiv(div_sel, divider); - return freq; -} - -void flexspi_clock_set_div(uint32_t value) -{ - CLOCK_DisableClock(kCLOCK_FlexSpi); - - CLOCK_SetDiv(kCLOCK_FlexspiDiv, value); - - CLOCK_EnableClock(kCLOCK_FlexSpi); -} - -uint32_t flexspi_clock_get_freq(void) -{ - uint32_t divider; - uint32_t frequency; - - divider = CLOCK_GetDiv(kCLOCK_FlexspiDiv); - - frequency = clock_get_usb1_pll_pfd0_clk() / (divider + 1); - - return frequency; + CLOCK_EnableClock(clk_name); + + FLEXSPI_Enable(flexspi, true); + + FLEXSPI_SoftwareReset(flexspi); + + return 0; } diff --git a/soc/arm/nxp_imx/rt/soc.h b/soc/arm/nxp_imx/rt/soc.h index d7e52ba751d..e5129c947d0 100644 --- a/soc/arm/nxp_imx/rt/soc.h +++ b/soc/arm/nxp_imx/rt/soc.h @@ -32,8 +32,9 @@ void imxrt_pre_init_display_interface(void); void imxrt_post_init_display_interface(void); #endif -void flexspi_clock_set_div(uint32_t value); -uint32_t flexspi_clock_get_freq(void); +#ifdef CONFIG_MEMC +uint32_t flexspi_clock_set_freq(uint32_t clock_name, uint32_t rate); +#endif #ifdef __cplusplus }