Commit a10fee2d5e
(drivers: clock_control: ccm_rev2: add support for
reclocking FlexSPI) introduced the ability to set the FlexSPI
clock frequency at runtime on RT11xx series SOCs. However, this
implementation resulted in the clock frequency being rounded up, not
down. This can result in flash clock frequency violations on some
flash parts, causing the system to crash when running in XIP mode.
Fixes #69088
Signed-off-by: Daniel DeGrasse <daniel.degrasse@nxp.com>
65 lines
1.6 KiB
C
65 lines
1.6 KiB
C
/*
|
|
* Copyright (c) 2023, NXP
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <fsl_clock.h>
|
|
#include <fsl_flexspi.h>
|
|
#include <soc.h>
|
|
#include <errno.h>
|
|
#include <zephyr/irq.h>
|
|
#include <zephyr/dt-bindings/clock/imx_ccm_rev2.h>
|
|
|
|
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 clock frequency. We round the
|
|
* divider up, so that the resulting clock frequency is lower than
|
|
* requested when we can't output the exact requested frequency
|
|
*/
|
|
divider = ((root_rate + (rate - 1)) / rate);
|
|
/* Cap divider to max value */
|
|
divider = MIN(divider, 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;
|
|
}
|