From 991b79b76842a807dbb682c30b1dbdfdf2f059cc Mon Sep 17 00:00:00 2001 From: Jay Goyal Date: Tue, 5 May 2026 12:10:40 +0530 Subject: [PATCH] Add SSC to MCU+SDK Signed-off-by: Jay Goyal --- .../rm_pm_hal/BuildConfigurationAM62AX.mk | 1 + .../rm_pm_hal/BuildConfigurations.mk | 3 + .../fw_caps/soc/am62ax/soc_capabilities.h | 4 +- .../include/lib/trace_protocol.h | 2 + .../include/tisci/pm/tisci_pm_clock.h | 124 ++++++++- .../rm_pm_hal_src/include/tisci/tisci_core.h | 2 + .../include/tisci/tisci_protocol.h | 2 + .../rm_pm_hal/rm_pm_hal_src/pm/Kconfig | 13 + .../rm_pm_hal_src/pm/drivers/clock/clk.c | 55 ++-- .../pm/drivers/clock/clk_pll_16fft.c | 255 ++++++++++++++++++ .../rm_pm_hal_src/pm/drivers/clock/clock.c | 149 +++++++++- .../pm/drivers/device/device_clk.c | 191 ++++++++----- .../rm_pm_hal/rm_pm_hal_src/pm/include/clk.h | 38 ++- .../rm_pm_hal_src/pm/include/device.h | 1 - .../rm_pm_hal_src/pm/include/device_clk.h | 55 ++-- .../rm_pm_hal/rm_pm_hal_src/pm/pm.h | 30 +++ .../rm_pm_hal_src/pm/soc/am62ax/clocks.c | 2 +- .../makefile.am62ax.r5f.ti-arm-clang | 1 + .../sciclient_direct/sciclient_direct.c | 13 +- .../makefile.am62ax.r5f.ti-arm-clang | 1 + .../device_manager/sciserver/sciserver.c | 12 + 21 files changed, 812 insertions(+), 142 deletions(-) diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/BuildConfigurationAM62AX.mk b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/BuildConfigurationAM62AX.mk index 66f0c538..c5daacc2 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/BuildConfigurationAM62AX.mk +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/BuildConfigurationAM62AX.mk @@ -15,6 +15,7 @@ CONFIG_PM=y CONFIG_PSC=y CONFIG_CLOCK=y CONFIG_CLK_PLL_16FFT=y +CONFIG_PM_CLK_SSC=y CONFIG_LPM_CLK=y CONFIG_LPM_LIMIT_IR_TRACKING=y CONFIG_RM=y diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/BuildConfigurations.mk b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/BuildConfigurations.mk index a8c6bd60..4bd9301b 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/BuildConfigurations.mk +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/BuildConfigurations.mk @@ -35,6 +35,9 @@ endif ifeq ($(CONFIG_CLK_PLL_16FFT_FRACF_CALIBRATION),y) CFLAGS_LOCAL_COMMON += -DCONFIG_CLK_PLL_16FFT_FRACF_CALIBRATION endif +ifeq ($(CONFIG_PM_CLK_SSC),y) +CFLAGS_LOCAL_COMMON += -DCONFIG_PM_CLK_SSC +endif ifeq ($(CONFIG_PSC_PD_MAX_COUNT_64),y) CFLAGS_LOCAL_COMMON += -DCONFIG_PSC_PD_MAX_COUNT_64 endif diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/common/fw_caps/soc/am62ax/soc_capabilities.h b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/common/fw_caps/soc/am62ax/soc_capabilities.h index 09c9883c..fed54909 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/common/fw_caps/soc/am62ax/soc_capabilities.h +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/common/fw_caps/soc/am62ax/soc_capabilities.h @@ -37,7 +37,7 @@ #include #include -#define TISCI_MSG_FLAG_FW_CAP_MAX (0x08U) +#define TISCI_MSG_FLAG_FW_CAP_MAX (0x0AU) const u64 soc_fw_caps[TISCI_MSG_FLAG_FW_CAP_MAX] = { TISCI_MSG_FLAG_FW_CAP_GENERIC_CAP, TISCI_MSG_FLAG_FW_CAP_LPM_DEEP_SLEEP, @@ -47,6 +47,8 @@ const u64 soc_fw_caps[TISCI_MSG_FLAG_FW_CAP_MAX] = { TISCI_MSG_FLAG_FW_CAP_LPM_IO_ONLY_PLUS_DDR, TISCI_MSG_FLAG_FW_CAP_IO_ISOLATION, TISCI_MSG_FLAG_FW_CAP_DM, + TISCI_MSG_FLAG_FW_CAP_LPM_ABORT, + TISCI_MSG_FLAG_FW_CAP_CLOCK_SSC, }; #endif /* SOC_AM62AX_CAPABILITIES_H */ diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/include/lib/trace_protocol.h b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/include/lib/trace_protocol.h index ae002c1b..6ef992c3 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/include/lib/trace_protocol.h +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/include/lib/trace_protocol.h @@ -328,6 +328,8 @@ #define TRACE_PM_ACTION_INVALID_STATE 0x7DU #define TRACE_PM_ACTION_BAD_DEVICE 0x7EU #define TRACE_PM_ACTION_MSG_PARAM_LATENCY 0x18U +#define TRACE_PM_ACTION_CLOCK_ENABLE_SSC 0x19U +#define TRACE_PM_ACTION_CLOCK_DISABLE_SSC 0x1AU #define TRACE_PM_VAL_CLOCK_VAL_SHIFT 10U #define TRACE_PM_VAL_CLOCK_VAL_MASK 0x0001FC00U diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/include/tisci/pm/tisci_pm_clock.h b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/include/tisci/pm/tisci_pm_clock.h index 8b4d2e72..dcd5e0d4 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/include/tisci/pm/tisci_pm_clock.h +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/include/tisci/pm/tisci_pm_clock.h @@ -64,10 +64,11 @@ /** Indicate hardware state of the clock is that it is running. */ #define TISCI_MSG_VALUE_CLOCK_HW_STATE_READY 1 -/** Allow this clock to be modified via spread spectrum clocking. - * \note: The SSC feature is currently not supported in System Firmware. - */ -#define TISCI_MSG_FLAG_CLOCK_ALLOW_SSC BIT(8) +/** Indicate that the spread spectrum clocking as down spread */ +#define TISCI_MSG_VALUE_CLOCK_SSC_SPREAD_DOWN 3U + +/** Indicate that the spread spectrum clocking as center spread */ +#define TISCI_MSG_VALUE_CLOCK_SSC_SPREAD_CENTER 1U /** * Allow this clock's frequency to be changed while it is running @@ -81,9 +82,7 @@ */ #define TISCI_MSG_FLAG_CLOCK_INPUT_TERM BIT(10) -/** Indicate that SSC is active for this clock. - * \note: The SSC feature is currently not supported in System Firmware. - */ +/** Indicate that SSC is active for this clock. */ #define TISCI_MSG_FLAG_CLOCK_SSC_ACTIVE BIT(11) /** @@ -93,8 +92,7 @@ * the IP. * * Certain flags can be set in the message header for device clocks: - * TISCI_MSG_FLAG_CLOCK_ALLOW_SSC, TISCI_MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE, - * TISCI_MSG_FLAG_CLOCK_INPUT_TERM. + * TISCI_MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE, TISCI_MSG_FLAG_CLOCK_INPUT_TERM. * * \param hdr TISCI header * @@ -544,4 +542,110 @@ struct tisci_msg_get_freq_resp { u64 freq_hz; } __attribute__((__packed__)); -#endif /* TISCI_PM_TISCI_CLOCK_H */ +/** + * \brief Set the spread spectrum clocking for a clock. + * + * Set the SSC for a clock with desired modulation frequency, spread + * type and modulation depth, all within their allowable range. SSC can only + * be enabled on clocks that have SSC support in the hardware. This message + * will fail if SSC is not supported by the hardware. + * + * \param hdr TISCI header + * + * \param device + * The device ID that the clock is connected to. + * + * \param clk + * Each device has its own set of clock inputs. This indexes which clock + * input to modify. + * + * \param modfreq_hz + * The desired modulation frequency in Hz. The modulation period is the time + * required to cycle the clock nominal frequency from an initial value through + * all the different values along the modulation profile and back to the + * initial value. The modulation frequency is the inverse of the period. The + * minimum allowable frequency is 32 kHz and maximum is fREFCLK / 200. For + * example, if the fREFCLK is 25 MHz, the maximum allowable modulation + * frequency would be 125 kHz. + * + * \param mod_depth + * The target modulation depth in "permyriad". The modulation depth refers to + * the maximum variation in frequency as a percentage of the clock center + * frequency. The minimum modulation depth is 0.1% and the maximum is 3.1%. + * Modulation depth can be adjusted in 0.1% increments. + * + * \param spread_type + * The target spread type. Both center and down spread are supported. + * + * \param enable + * Enable or disable SSC. + */ +struct tisci_msg_set_clock_ssc_req { + struct tisci_header hdr; + u32 device; + u32 clk; + u32 modfreq_hz; + u32 mod_depth; + u8 spread_type; + u8 enable; +} __attribute__((__packed__)); + +/** + * \brief Empty response for TISCI_MSG_SET_CLOCK_SSC + * + * Although this message is essentially empty and contains only a header + * a full data structure is created for consistency in implementation. + * + * \param hdr TISCI header to provide ACK/NAK flags to the host. + */ +struct tisci_msg_set_clock_ssc_resp { + struct tisci_header hdr; +} __attribute__((__packed__)); + +/** + * \brief Get the current SSC settings of a device's clock + * + * This message will only succeed if the clock is currently enabled, otherwise + * it returns nack. + * + * \param hdr TISCI header + * + * \param device + * The device ID that the clock is connected to. + * + * \param clk + * Each device has its own set of clock inputs. This indexes which clock + * input to query. + */ +struct tisci_msg_get_clock_ssc_req { + struct tisci_header hdr; + u32 device; + u32 clk; +} __attribute__((__packed__)); + +/** + * \brief Result of get SSC request + * + * \param hdr TISCI header + * + * \param modfreq_hz + * The current modulation frequency in Hz. + * + * \param mod_depth + * The current modulation depth in "permyriad". + * + * \param spread_type + * The current spread type. + * + * \param enable + * The current enable state. + */ +struct tisci_msg_get_clock_ssc_resp { + struct tisci_header hdr; + u32 modfreq_hz; + u32 mod_depth; + u8 spread_type; + u8 enable; +} __attribute__((__packed__)); + +#endif /* TISCI_PM_TISCI_CLOCK_H */ diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/include/tisci/tisci_core.h b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/include/tisci/tisci_core.h index 630280a3..82f57571 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/include/tisci/tisci_core.h +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/include/tisci/tisci_core.h @@ -51,6 +51,8 @@ #define TISCI_MSG_FLAG_FW_CAP_LPM_IO_ONLY_PLUS_DDR BIT(6) #define TISCI_MSG_FLAG_FW_CAP_IO_ISOLATION BIT(7) #define TISCI_MSG_FLAG_FW_CAP_DM BIT(8) +#define TISCI_MSG_FLAG_FW_CAP_LPM_ABORT BIT(9) +#define TISCI_MSG_FLAG_FW_CAP_CLOCK_SSC BIT(10) /** * \brief Notification message to indicate the DMSC is available. diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/include/tisci/tisci_protocol.h b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/include/tisci/tisci_protocol.h index 4a88fd4d..90da2a5b 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/include/tisci/tisci_protocol.h +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/include/tisci/tisci_protocol.h @@ -128,6 +128,8 @@ struct tisci_sec_header { #define TISCI_MSG_SET_CLOCK_PARENT (0x0102U) #define TISCI_MSG_GET_CLOCK_PARENT (0x0103U) #define TISCI_MSG_GET_NUM_CLOCK_PARENTS (0x0104U) +#define TISCI_MSG_SET_CLOCK_SSC (0x010aU) +#define TISCI_MSG_GET_CLOCK_SSC (0x010bU) #define TISCI_MSG_SET_FREQ (0x010cU) #define TISCI_MSG_QUERY_FREQ (0x010dU) #define TISCI_MSG_GET_FREQ (0x010eU) diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/Kconfig b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/Kconfig index 8a305bd0..1b7c6d91 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/Kconfig +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/Kconfig @@ -101,6 +101,19 @@ config CLK_PLL_16FFT_FRACF_CALIBRATION help Enable support for 16fft pllfracf calibration +config PM_CLK_SSC + bool "Enable support for Spread Spectrum Clocking (SSC)" + depends on CLK_PLL_16FFT + default n + default y if SOC_AM62 + default y if SOC_AM62A + default y if SOC_AM62P + help + Enable support for Spread Spectrum Clocking (SSC). SSC allows + modulation of the clock frequency to reduce electromagnetic + interference (EMI). This feature is only available on select + SoCs with hardware SSC support in their PLL controllers. + config CLK_PLL_DESKEW bool "Enable support for 16fft deskew PLL" depends on CLOCK diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/drivers/clock/clk.c b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/drivers/clock/clk.c index b428f05c..f7e94d26 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/drivers/clock/clk.c +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/drivers/clock/clk.c @@ -462,35 +462,46 @@ void clk_put(struct clk *clkp) } } -void clk_ssc_allow(struct clk *clkp) +#ifdef CONFIG_PM_CLK_SSC +u32 clk_set_ssc(struct clk *clkp, u32 modfreq_hz, u32 mod_depth, u8 spread_type, sbool enable) { - if (--clkp->ssc_block_count == 0U) { - const struct clk_parent *p; - p = clk_get_parent(clkp); - if (p != NULL) { - struct clk *clkp_parent; - clkp_parent = clk_lookup((clk_idx_t) p->clk); - if (clkp_parent != NULL) { - clk_ssc_allow(clkp_parent); - } - } + const struct clk_data *clk_data_p = clk_get_data(clkp); + u32 ret; + + if ((clkp->flags & CLK_FLAG_INITIALIZED) == 0U) { + ret = 1U; /* Fail: Clock not initialized */ + } else if ((clk_data_p->flags & CLK_DATA_FLAG_ALLOW_SSC_CHANGE) == 0U) { + ret = 1U; /* Fail: Hardware does not support SSC on this clock */ + } else if (clk_data_p->drv->set_ssc == NULL) { + ret = 1U; /* Fail: No driver support for SSC */ + } else { + /* Success: Call hardware-specific driver to set SSC parameters */ + ret = (clk_data_p->drv->set_ssc(clkp, modfreq_hz, mod_depth, + spread_type, enable) == 0) ? 0U : 1U; } + + return ret; } -void clk_ssc_block(struct clk *clkp) +u32 clk_get_ssc(struct clk *clkp, struct ssc_data *ssc_datap) { - if (0U == clkp->ssc_block_count++) { - const struct clk_parent *p; - p = clk_get_parent(clkp); - if (p != NULL) { - struct clk *clkp_parent; - clkp_parent = clk_lookup((clk_idx_t) p->clk); - if (clkp_parent != NULL) { - clk_ssc_block(clkp_parent); - } - } + const struct clk_data *clk_data_p = clk_get_data(clkp); + u32 ret = 0U; + + if ((clkp->flags & CLK_FLAG_INITIALIZED) == 0U) { + ret = 1U; /* Fail: Clock not initialized */ + } else if ((clk_data_p->flags & CLK_DATA_FLAG_ALLOW_SSC_CHANGE) == 0U) { + ret = 1U; /* Fail: Hardware does not support SSC on this clock */ + } else if (clk_data_p->drv->get_ssc == NULL) { + ret = 1U; /* Fail: No driver support for SSC */ + } else { + /* Success: Call hardware-specific driver to get SSC parameters */ + clk_data_p->drv->get_ssc(clkp, ssc_datap); } + + return ret; } +#endif void clk_freq_change_allow(struct clk *clkp) { diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/drivers/clock/clk_pll_16fft.c b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/drivers/clock/clk_pll_16fft.c index 84ae9637..b952ba10 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/drivers/clock/clk_pll_16fft.c +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/drivers/clock/clk_pll_16fft.c @@ -45,6 +45,7 @@ #include #include #include +#include #define PLL_16FFT_PID (idx) ((0x1000UL * (idx)) + 0x00UL) #define PLL_16FFT_CFG(idx) ((0x1000UL * (idx)) + 0x08UL) @@ -94,7 +95,22 @@ #define PLL_16FFT_DIV_CTRL_REF_DIV_MASK (0x3fUL << 0UL) #define PLL_16FFT_SS_CTRL(idx) ((0x1000UL * (idx)) + 0x40UL) +#define PLL_16FFT_SS_CTRL_DOWNSPREAD_EN BIT(4) +#define PLL_16FFT_SS_CTRL_BYPASS_EN BIT(31) + #define PLL_16FFT_SS_SPREAD(idx) ((0x1000UL * (idx)) + 0x44UL) +#define PLL_16FFT_SS_SPREAD_SPREAD_SHIFT 0UL +#define PLL_16FFT_SS_SPREAD_SPREAD_MASK (0x1fUL << 0UL) +#define PLL_16FFT_SS_SPREAD_MOD_DIV_SHIFT 16UL +#define PLL_16FFT_SS_SPREAD_MOD_DIV_MASK (0xfUL << 16UL) + +#define PLL_16FFT_SS_MOD_DEPTH_DIV 10U +#define PLL_16FFT_SS_MOD_DEPTH_MIN 10U +#define PLL_16FFT_SS_MOD_DEPTH_MAX 310U +#define PLL_16FFT_SS_MOD_DIV_FACTOR 128U +#define PLL_16FFT_SS_MOD_DIV_FACTOR_HALF 64U +#define PLL_16FFT_SS_MOD_FREQ_MIN_HZ 32000U +#define PLL_16FFT_SS_MOD_FREQ_MAX_DIV 200U #define PLL_16FFT_CAL_CTRL(idx) ((0x1000UL * (idx)) + 0x60UL) #define PLL_16FFT_CAL_CTRL_CAL_EN BIT(31) @@ -1350,12 +1366,251 @@ static s32 clk_pll_16fft_init(struct clk *clock_ptr) return ret; } +#ifdef CONFIG_PM_CLK_SSC +static s32 clk_pll_16fft_internal_disable_ssc(const struct clk_data_pll_16fft *pll) +{ + u32 ss_ctrl; + s32 ret = SUCCESS; + + /* Read the PLL's SS control register */ + ss_ctrl = readl(pll->base + (u32) PLL_16FFT_SS_CTRL(pll->idx)); + + /* Set the SS BYPASS enable bit if it is not already set */ + if ((ss_ctrl & PLL_16FFT_SS_CTRL_BYPASS_EN) == 0U) { + ss_ctrl |= PLL_16FFT_SS_CTRL_BYPASS_EN; + /* Write the PLL's SS control register */ + ret = pm_writel_verified(ss_ctrl, pll->base + (u32) PLL_16FFT_SS_CTRL(pll->idx)); + if (ret != SUCCESS) { + ret = -EFAIL; + } + } + + return ret; +} + +static s32 clk_pll_16fft_internal_enable_ssc(const struct clk_data_pll_16fft *pll, + u32 parent_freq_hz, + u32 modfreq_hz, + u32 mod_depth, + u8 spread_type) +{ + u32 ctrl; + u32 ss_ctrl; + u32 ss_spread; + u32 mod_div; + u32 spread; + s32 ret = SUCCESS; + sbool lock = SFALSE; + + /* + * The PLL needs to be locked before SSC can be enabled. + * Check if the PLL is locked. If not, return failure + */ + lock = clk_pll_16fft_check_lock(pll); + if (lock == SFALSE) { + ret = -EFAIL; + } + + if (ret == SUCCESS) { + /* Read the PLL's control register */ + ctrl = readl(pll->base + (u32) PLL_16FFT_CTRL(pll->idx)); + + /* + * The PLL needs to be in fractional mode, i.e DAC and DSM bits + * must be set before SSC can be enabled. + * Check if these bits are set. If not, return failure + */ + if ((ctrl & PLL_16FFT_CTRL_DAC_EN) == 0U) { + ret = -EFAIL; + } + if ((ctrl & PLL_16FFT_CTRL_DSM_EN) == 0U) { + ret = -EFAIL; + } + } + + if (ret == SUCCESS) { + /* Read the PLL's SS control register */ + ss_ctrl = readl(pll->base + (u32) PLL_16FFT_SS_CTRL(pll->idx)); + + /* Unset the SS BYPASS enable bit if it is not already unset */ + if ((ss_ctrl & PLL_16FFT_SS_CTRL_BYPASS_EN) != 0U) { + ss_ctrl &= ~PLL_16FFT_SS_CTRL_BYPASS_EN; + } + + /* Set the SS DOWNSPREAD enable bit if the spread_type is down or unset it if it is center */ + if (spread_type == TISCI_MSG_VALUE_CLOCK_SSC_SPREAD_DOWN) { + ss_ctrl |= PLL_16FFT_SS_CTRL_DOWNSPREAD_EN; + } else if (spread_type == TISCI_MSG_VALUE_CLOCK_SSC_SPREAD_CENTER) { + ss_ctrl &= ~PLL_16FFT_SS_CTRL_DOWNSPREAD_EN; + } else { + ret = -EINVAL; + } + + if (ret == SUCCESS) { + /* Write the PLL's SS spread register */ + ret = pm_writel_verified(ss_ctrl, pll->base + (u32) PLL_16FFT_SS_CTRL(pll->idx)); + if (ret != SUCCESS) { + ret = -EFAIL; + } + } + } + + if (ret == SUCCESS) { + /* Read the PLL's SS spread register */ + ss_spread = readl(pll->base + (u32) PLL_16FFT_SS_SPREAD(pll->idx)); + + /* if modfreq_hz is valid */ + if ((modfreq_hz >= PLL_16FFT_SS_MOD_FREQ_MIN_HZ) && + (modfreq_hz <= (parent_freq_hz / PLL_16FFT_SS_MOD_FREQ_MAX_DIV))) { + /* Calculate the modulation frequency divider value */ + mod_div = (parent_freq_hz + + (PLL_16FFT_SS_MOD_DIV_FACTOR_HALF * modfreq_hz)) / + (PLL_16FFT_SS_MOD_DIV_FACTOR * modfreq_hz); + ss_spread &= ~PLL_16FFT_SS_SPREAD_MOD_DIV_MASK; + ss_spread |= mod_div << PLL_16FFT_SS_SPREAD_MOD_DIV_SHIFT; + } else { + ret = -EINVAL; + } + + /* if spread is valid */ + if ((mod_depth >= PLL_16FFT_SS_MOD_DEPTH_MIN) && + (mod_depth <= PLL_16FFT_SS_MOD_DEPTH_MAX)) { + /* Calculate the spread modulation depth value */ + spread = mod_depth / PLL_16FFT_SS_MOD_DEPTH_DIV; + ss_spread &= ~PLL_16FFT_SS_SPREAD_SPREAD_MASK; + ss_spread |= spread << PLL_16FFT_SS_SPREAD_SPREAD_SHIFT; + } else { + ret = -EINVAL; + } + + if (ret == SUCCESS) { + /* Write the PLL's SS spread register */ + ret = pm_writel_verified(ss_spread, pll->base + (u32) PLL_16FFT_SS_SPREAD(pll->idx)); + if (ret != SUCCESS) { + ret = -EFAIL; + } + } + } + + /* If enable failed, disable SSC to clean up */ + if (ret != SUCCESS) { + s32 disable_ret; + disable_ret = clk_pll_16fft_internal_disable_ssc(pll); + /* Only overwrite ret if it's not a validation error */ + if ((disable_ret != SUCCESS) && (ret != -EINVAL)) { + ret = disable_ret; + } + } + + return ret; +} + +static s32 clk_pll_16fft_set_ssc(struct clk *clock_ptr, + u32 modfreq_hz, + u32 mod_depth, + u8 spread_type, + sbool enable) +{ + const struct clk_data *clock_data; + const struct clk_data_pll *data_pll; + const struct clk_data_pll_16fft *pll; + u32 parent_freq_hz; + s32 ret; + + clock_data = clk_get_data(clock_ptr); + data_pll = container_of(clock_data->data, const struct clk_data_pll, + data); + pll = container_of(data_pll, const struct clk_data_pll_16fft, + data_pll); + + if (enable) { + parent_freq_hz = clk_get_parent_freq(clock_ptr); + ret = clk_pll_16fft_internal_enable_ssc(pll, parent_freq_hz, modfreq_hz, + mod_depth, spread_type); + } else { + ret = clk_pll_16fft_internal_disable_ssc(pll); + } + + return ret; +} + +static void clk_pll_16fft_internal_get_ssc(const struct clk_data_pll_16fft *pll, + u32 parent_freq_hz, + struct ssc_data *ssc_datap) +{ + u32 ctrl; + u32 ss_ctrl; + u32 ss_spread; + u32 mod_div; + u32 spread; + u32 spread_type; + + /* Read the PLL's control register */ + ctrl = readl(pll->base + (u32) PLL_16FFT_CTRL(pll->idx)); + + /* + * Check if the DAC and DSM enable bits are set. + * If not, return SSC as disabled. + */ + if ((ctrl & PLL_16FFT_CTRL_DAC_EN) == 0U) { + ssc_datap->enable = 0U; + } + if ((ctrl & PLL_16FFT_CTRL_DSM_EN) == 0U) { + ssc_datap->enable = 0U; + } + + /* Read the PLL's SS control register */ + ss_ctrl = readl(pll->base + (u32) PLL_16FFT_SS_CTRL(pll->idx)); + + /* Check if the SS BYPASS enable bit is unset */ + ssc_datap->enable = ((ss_ctrl & PLL_16FFT_SS_CTRL_BYPASS_EN) == 0U) ? 1U : 0U; + + /* Get the spread type */ + spread_type = ss_ctrl & PLL_16FFT_SS_CTRL_DOWNSPREAD_EN; + ssc_datap->spread_type = (spread_type == 0U) ? TISCI_MSG_VALUE_CLOCK_SSC_SPREAD_CENTER : TISCI_MSG_VALUE_CLOCK_SSC_SPREAD_DOWN; + + /* Read the PLL's SS spread register */ + ss_spread = readl(pll->base + (u32) PLL_16FFT_SS_SPREAD(pll->idx)); + + /* Get the modulation frequency */ + mod_div = (ss_spread & PLL_16FFT_SS_SPREAD_MOD_DIV_MASK) >> + PLL_16FFT_SS_SPREAD_MOD_DIV_SHIFT; + ssc_datap->modfreq_hz = (parent_freq_hz / + (PLL_16FFT_SS_MOD_DIV_FACTOR * mod_div)); + + /* Get the modulation depth */ + spread = ss_spread & PLL_16FFT_SS_SPREAD_SPREAD_MASK; + ssc_datap->mod_depth = spread * PLL_16FFT_SS_MOD_DEPTH_DIV; +} + +static void clk_pll_16fft_get_ssc(struct clk *clock_ptr, struct ssc_data *ssc_datap) +{ + const struct clk_data *clock_data; + const struct clk_data_pll *data_pll; + const struct clk_data_pll_16fft *pll; + u32 parent_freq_hz; + + clock_data = clk_get_data(clock_ptr); + data_pll = container_of(clock_data->data, const struct clk_data_pll, + data); + pll = container_of(data_pll, const struct clk_data_pll_16fft, + data_pll); + parent_freq_hz = clk_get_parent_freq(clock_ptr); + + clk_pll_16fft_internal_get_ssc(pll, parent_freq_hz, ssc_datap); +} +#endif + const struct clk_drv clk_drv_pll_16fft = { .init = clk_pll_16fft_init, .get_freq = clk_pll_16fft_get_freq, .set_freq = clk_pll_16fft_set_freq, .get_state = clk_pll_16fft_get_state, .set_state = clk_pll_16fft_set_state, +#ifdef CONFIG_PM_CLK_SSC + .set_ssc = clk_pll_16fft_set_ssc, + .get_ssc = clk_pll_16fft_get_ssc, +#endif }; /* diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/drivers/clock/clock.c b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/drivers/clock/clock.c index 6c36c103..fc253a08 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/drivers/clock/clock.c +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/drivers/clock/clock.c @@ -98,12 +98,6 @@ s32 set_clock_handler(u32 *msg_recv) } if (ret == SUCCESS) { - if ((flags & TISCI_MSG_FLAG_CLOCK_ALLOW_SSC) != 0UL) { - device_clk_set_ssc(dev, clkidx, STRUE); - } else { - device_clk_set_ssc(dev, clkidx, SFALSE); - } - if ((flags & TISCI_MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE) != 0UL) { device_clk_set_freq_change(dev, clkidx, STRUE); } else { @@ -165,6 +159,9 @@ s32 get_clock_handler(u32 *msg_recv) if (ret == SUCCESS) { u8 prog; u8 state; +#ifdef CONFIG_PM_CLK_SSC + struct ssc_data current_ssc = { 0U }; +#endif prog = (u8) (device_clk_get_sw_gated(dev, clkidx) ? TISCI_MSG_VALUE_CLOCK_SW_STATE_UNREQ : @@ -174,14 +171,6 @@ s32 get_clock_handler(u32 *msg_recv) TISCI_MSG_VALUE_CLOCK_HW_STATE_READY : TISCI_MSG_VALUE_CLOCK_HW_STATE_NOT_READY); - if (device_clk_get_ssc(dev, clkidx)) { - resp->hdr.flags |= TISCI_MSG_FLAG_CLOCK_ALLOW_SSC; - } - - if (device_clk_get_hw_ssc(dev, clkidx)) { - resp->hdr.flags |= TISCI_MSG_FLAG_CLOCK_SSC_ACTIVE; - } - if (device_clk_get_freq_change(dev, clkidx)) { resp->hdr.flags |= TISCI_MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE; } @@ -190,6 +179,12 @@ s32 get_clock_handler(u32 *msg_recv) resp->hdr.flags |= TISCI_MSG_FLAG_CLOCK_INPUT_TERM; } +#ifdef CONFIG_PM_CLK_SSC + if (device_clk_get_ssc(dev, clkidx, ¤t_ssc) && (current_ssc.enable != 0U)) { + resp->hdr.flags |= TISCI_MSG_FLAG_CLOCK_SSC_ACTIVE; + } +#endif + resp->programmed_state = prog; resp->current_state = state; } @@ -386,6 +381,11 @@ s32 set_freq_handler(u32 *msg_recv) } if (ret == SUCCESS) { +#ifdef CONFIG_PM_CLK_SSC + struct ssc_data saved_ssc_data = { 0U }; + sbool ssc_was_enabled = SFALSE; +#endif + if (max_freq_hz > (u64) ULONG_MAX) { max_freq_hz = ULONG_MAX; } @@ -394,10 +394,31 @@ s32 set_freq_handler(u32 *msg_recv) target_freq_hz = ULONG_MAX; } +#ifdef CONFIG_PM_CLK_SSC + /* Save current SSC state if enabled */ + if (device_clk_get_ssc(dev, clkidx, &saved_ssc_data) && (saved_ssc_data.enable != 0U)) { + ssc_was_enabled = STRUE; + /* Disable SSC before frequency change */ + device_clk_set_ssc(dev, clkidx, saved_ssc_data.modfreq_hz, + saved_ssc_data.mod_depth, + saved_ssc_data.spread_type, SFALSE); + } +#endif + + /* Change the frequency */ if (!device_clk_set_freq(dev, clkidx, (u32) min_freq_hz, (u32) target_freq_hz, (u32) max_freq_hz)) { ret = -EINVAL; } + +#ifdef CONFIG_PM_CLK_SSC + /* Re-enable SSC if it was previously enabled */ + if ((ret == SUCCESS) && ssc_was_enabled) { + device_clk_set_ssc(dev, clkidx, saved_ssc_data.modfreq_hz, + saved_ssc_data.mod_depth, + saved_ssc_data.spread_type, STRUE); + } +#endif } mmr_lock_all(); @@ -517,3 +538,103 @@ s32 get_freq_handler(u32 *msg_recv) return ret; } + +#ifdef CONFIG_PM_CLK_SSC +s32 set_ssc_handler(u32 *msg_recv) +{ + struct tisci_msg_set_clock_ssc_req *req = + (struct tisci_msg_set_clock_ssc_req *) msg_recv; + struct tisci_msg_set_clock_ssc_resp *resp = + (struct tisci_msg_set_clock_ssc_resp *) msg_recv; + struct device *dev = NULL; + struct dev_clk *dev_clkp; + u32 id = req->device; + dev_clk_idx_t clkidx = (dev_clk_idx_t) req->clk; + u32 modfreq_hz = req->modfreq_hz; + u32 mod_depth = req->mod_depth; + u8 spread_type = req->spread_type; + sbool enable = (req->enable != 0U) ? STRUE : SFALSE; + s32 ret = SUCCESS; + + mmr_unlock_all(); + + pm_trace(TRACE_PM_ACTION_MSG_RECEIVED, TISCI_MSG_SET_CLOCK_SSC); + pm_trace(TRACE_PM_ACTION_MSG_PARAM_DEV_CLK_ID, + id | ((u32) clkidx << TRACE_PM_MSG_CLK_ID_SHIFT)); + pm_trace(TRACE_PM_ACTION_MSG_PARAM_VAL, modfreq_hz); + pm_trace(TRACE_PM_ACTION_MSG_PARAM_VAL, mod_depth); + pm_trace(TRACE_PM_ACTION_MSG_PARAM_VAL, spread_type); + pm_trace(TRACE_PM_ACTION_MSG_PARAM_VAL, (enable == STRUE) ? 1U : 0U); + + resp->hdr.flags = 0U; + + ret = device_prepare_exclusive(req->hdr.host, id, NULL, &dev); + if (ret == SUCCESS) { + /* Check if "clk_idx" is available on the device */ + dev_clkp = get_dev_clk(dev, clkidx); + if (dev_clkp == NULL) { + ret = -EFAIL; + } + } + + if (ret == SUCCESS) { + /* Forward SSC request to device clock layer. */ + if (!device_clk_set_ssc(dev, clkidx, modfreq_hz, + mod_depth, spread_type, enable)) { + ret = -EINVAL; + } + } + + mmr_lock_all(); + + return ret; +} + +s32 get_ssc_handler(u32 *msg_recv) +{ + struct tisci_msg_get_clock_ssc_req *req = + (struct tisci_msg_get_clock_ssc_req *) msg_recv; + struct tisci_msg_get_clock_ssc_resp *resp = + (struct tisci_msg_get_clock_ssc_resp *) msg_recv; + struct device *dev = NULL; + struct dev_clk *dev_clkp; + struct ssc_data data = { 0U }; + u32 id = req->device; + dev_clk_idx_t clkidx = (dev_clk_idx_t) req->clk; + s32 ret = SUCCESS; + + mmr_unlock_all(); + + pm_trace(TRACE_PM_ACTION_MSG_RECEIVED, TISCI_MSG_GET_CLOCK_SSC); + pm_trace(TRACE_PM_ACTION_MSG_PARAM_DEV_CLK_ID, + id | ((u32) clkidx << TRACE_PM_MSG_CLK_ID_SHIFT)); + + resp->hdr.flags = 0U; + + ret = device_prepare_nonexclusive(req->hdr.host, id, NULL, &dev); + if (ret == SUCCESS) { + /* Check if "clk_idx" is available on the device */ + dev_clkp = get_dev_clk(dev, clkidx); + if (dev_clkp == NULL) { + ret = -EFAIL; + } + } + + if (ret == SUCCESS) { + if (!device_clk_get_ssc(dev, clkidx, &data)) { + ret = -EINVAL; + } + } + + if (ret == SUCCESS) { + resp->mod_depth = data.mod_depth; + resp->modfreq_hz = data.modfreq_hz; + resp->spread_type = data.spread_type; + resp->enable = data.enable; + } + + mmr_lock_all(); + + return ret; +} +#endif diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/drivers/device/device_clk.c b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/drivers/device/device_clk.c index 3f5f51af..b97b2819 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/drivers/device/device_clk.c +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/drivers/device/device_clk.c @@ -113,10 +113,6 @@ sbool device_clk_set_gated(struct device *dev, dev_clk_idx_t clk_idx, sbool gate if (is_enabled) { clk_put(clkp); - if (0U == (dev_clkp->flags & DEV_CLK_FLAG_ALLOW_SSC)) { - clk_ssc_allow(clkp); - } - if (0U == (dev_clkp->flags & DEV_CLK_FLAG_ALLOW_FREQ_CHANGE)) { clk_freq_change_allow(clkp); @@ -126,10 +122,6 @@ sbool device_clk_set_gated(struct device *dev, dev_clk_idx_t clk_idx, sbool gate dev_clkp->flags &= (u8) ~DEV_CLK_FLAG_DISABLE; if (is_enabled) { if (clk_get(clkp)) { - if (0U == (dev_clkp->flags & DEV_CLK_FLAG_ALLOW_SSC)) { - clk_ssc_block(clkp); - } - if (0U == (dev_clkp->flags & DEV_CLK_FLAG_ALLOW_FREQ_CHANGE)) { clk_freq_change_block(clkp); @@ -193,55 +185,7 @@ sbool device_clk_get_sw_gated(struct device *dev, dev_clk_idx_t clk_idx) struct dev_clk *dev_clkp = get_dev_clk(dev, clk_idx); return dev_clkp && (dev_clkp->flags & DEV_CLK_FLAG_DISABLE); -} - -void device_clk_set_ssc(struct device *dev, dev_clk_idx_t clk_idx, sbool allow) -{ - struct dev_clk *dev_clkp = get_dev_clk(dev, clk_idx); - struct clk *clkp; - sbool is_allowed; - - if (!dev_clkp) { - /* Nothing to do */ - } else { - is_allowed = ((dev_clkp->flags & DEV_CLK_FLAG_ALLOW_SSC) > 0U) ? STRUE : SFALSE; - if (is_allowed == allow) { - /* Nothing to do */ - } else { - dev_clkp->flags ^= DEV_CLK_FLAG_ALLOW_SSC; - - if ((dev->flags & DEV_FLAG_ENABLED_MASK) == 0UL) { - /* Nothing to do */ - } else { - if ((dev_clkp->flags & DEV_CLK_FLAG_DISABLE) != 0U) { - /* Nothing to do */ - } else { - clkp = dev_get_clk(dev, clk_idx); - - if (!clkp) { - /* fail */ - } else if (allow) { - clk_ssc_allow(clkp); - } else { - clk_ssc_block(clkp); - } - } - } - } - } -} -sbool device_clk_get_ssc(struct device *dev, dev_clk_idx_t clk_idx) -{ - struct dev_clk *dev_clkp = get_dev_clk(dev, clk_idx); - - return dev_clkp && (dev_clkp->flags & DEV_CLK_FLAG_ALLOW_SSC); -} - -sbool device_clk_get_hw_ssc(struct device *dev __attribute__( - (unused)), dev_clk_idx_t clk_idx __attribute__((unused))) -{ - return SFALSE; } void device_clk_set_freq_change(struct device *dev, dev_clk_idx_t clk_idx, sbool allow) @@ -673,6 +617,132 @@ u32 device_clk_get_freq(struct device *dev, dev_clk_idx_t clk_idx) return freq_hz; } +#ifdef CONFIG_PM_CLK_SSC +sbool device_clk_set_ssc(struct device *dev, dev_clk_idx_t clk_idx, u32 modfreq_hz, u32 mod_depth, u8 spread_type, sbool enable) +{ + const struct dev_clk_data *clock_data; + const struct clk_parent *parent_clk = NULL; + struct clk *parent = NULL; + sbool done = SFALSE; + sbool ssc_set = SFALSE; + sbool search_complete = SFALSE; + dev_clk_idx_t clk_idx_val = clk_idx; + + /* Validate clock index on device */ + if (!done) { + clock_data = get_dev_clk_data(dev, clk_idx_val); + if (clock_data == NULL) { + /* Invalid clock idx */ + done = STRUE; + } + } + + /* Get the clock structure */ + if (!done) { + parent = dev_get_clk(dev, clk_idx_val); + if (parent == NULL) { + /* Parent not present */ + done = STRUE; + } + } + + /* + * For PARENT, MUX or INPUT type clocks, walk up the clock tree to find + * the actual PLL that supports SSC. Forward request to clk_set_ssc(). + */ + if (!done) { + if ((clock_data->type == DEV_CLK_TABLE_TYPE_PARENT) || + (clock_data->type == DEV_CLK_TABLE_TYPE_MUX) || + (clock_data->type == DEV_CLK_TABLE_TYPE_INPUT)) { + while ((ssc_set != STRUE) && (search_complete != STRUE)) { + /* Walk up to find parent PLL with SSC capability */ + parent_clk = clk_get_parent(parent); + if (parent_clk == NULL) { + search_complete = STRUE; + } else { + parent = clk_lookup(parent_clk->clk); + if (parent == NULL) { + search_complete = STRUE; + } else { + /* Call internal clock layer to set SSC on hardware */ + ssc_set = (clk_set_ssc(parent, modfreq_hz, mod_depth, + spread_type, enable) == 0U) ? STRUE : SFALSE; + if (ssc_set) { + if (enable) { + pm_trace(TRACE_PM_ACTION_CLOCK_ENABLE_SSC, + clk_id(parent)); + } else { + pm_trace(TRACE_PM_ACTION_CLOCK_DISABLE_SSC, + clk_id(parent)); + } + } + } + } + } + } + } + + return ssc_set; +} + +sbool device_clk_get_ssc(struct device *dev, dev_clk_idx_t clk_idx, struct ssc_data *ssc_datap) +{ + const struct dev_clk_data *clock_data; + const struct clk_parent *parent_clk = NULL; + struct clk *parent = NULL; + sbool ssc_found = SFALSE; + sbool done = SFALSE; + sbool search_complete = SFALSE; + dev_clk_idx_t clk_idx_val = clk_idx; + + /* Validate clock index on device */ + if (!done) { + clock_data = get_dev_clk_data(dev, clk_idx_val); + if (clock_data == NULL) { + /* Invalid clock idx */ + done = STRUE; + } + } + + /* Get the clock structure */ + if (!done) { + parent = dev_get_clk(dev, clk_idx_val); + if (parent == NULL) { + /* Parent not present */ + done = STRUE; + } + } + + /* + * For PARENT, MUX or INPUT type clocks, walk up the clock tree to find + * the actual PLL that supports SSC. Forward request to clk_get_ssc(). + */ + if (!done) { + if ((clock_data->type == DEV_CLK_TABLE_TYPE_PARENT) || + (clock_data->type == DEV_CLK_TABLE_TYPE_MUX) || + (clock_data->type == DEV_CLK_TABLE_TYPE_INPUT)) { + while ((ssc_found != STRUE) && (search_complete != STRUE)) { + /* Walk up to find parent PLL with SSC capability */ + parent_clk = clk_get_parent(parent); + if (parent_clk == NULL) { + search_complete = STRUE; + } else { + parent = clk_lookup(parent_clk->clk); + if (parent == NULL) { + search_complete = STRUE; + } else { + /* Call internal clock layer to get SSC configuration of hardware */ + ssc_found = (clk_get_ssc(parent, ssc_datap) == 0U) ? STRUE : SFALSE; + } + } + } + } + } + + return ssc_found; +} +#endif + void device_clk_enable(struct device *dev, dev_clk_idx_t clk_idx) { struct dev_clk *dev_clkp; @@ -685,10 +755,6 @@ void device_clk_enable(struct device *dev, dev_clk_idx_t clk_idx) if (clkp != NULL) { if (clk_get(clkp)) { - if (0U == (dev_clkp->flags & DEV_CLK_FLAG_ALLOW_SSC)) { - clk_ssc_block(clkp); - } - if (0U == (dev_clkp->flags & DEV_CLK_FLAG_ALLOW_FREQ_CHANGE)) { clk_freq_change_block(clkp); } @@ -709,10 +775,6 @@ void device_clk_disable(struct device *dev, dev_clk_idx_t clk_idx) if (clkp != NULL) { clk_put(clkp); - if (0U == (dev_clkp->flags & DEV_CLK_FLAG_ALLOW_SSC)) { - clk_ssc_allow(clkp); - } - if (0U == (dev_clkp->flags & DEV_CLK_FLAG_ALLOW_FREQ_CHANGE)) { clk_freq_change_allow(clkp); } @@ -732,7 +794,6 @@ void device_clk_init(struct device *dev, dev_clk_idx_t clk_idx) if ((dev_clk_datap != NULL) && (dev_clkp != NULL)) { if (dev_clk_datap->type == DEV_CLK_TABLE_TYPE_PARENT) { dev_clkp->flags |= DEV_CLK_FLAG_DISABLE | - DEV_CLK_FLAG_ALLOW_SSC | DEV_CLK_FLAG_ALLOW_FREQ_CHANGE; } } diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/include/clk.h b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/include/clk.h index c62f3a17..282a7231 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/include/clk.h +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/include/clk.h @@ -70,6 +70,7 @@ #define CLK_DATA_FLAG_ALLOW_FREQ_CHANGE BIT(1) #define CLK_DATA_FLAG_NO_HW_REINIT BIT(2) #define CLK_DATA_FLAG_BLOCK_FREQ_CHANGE BIT(3) +#define CLK_DATA_FLAG_ALLOW_SSC_CHANGE BIT(4) #define CLK_FLAG_PWR_UP_EN ((u8) BIT(0)) #define CLK_FLAG_PLL_BYPASS_FREQ ((u8) BIT(1)) /* For PLLs */ @@ -87,6 +88,13 @@ #define CLK_ID_NONE ((clk_idx_t) (0xFFFFFFFFU)) +struct ssc_data { + u32 modfreq_hz; + u32 mod_depth; + u8 spread_type; + u8 enable; +}; + struct clk_range { u32 min_hz; u32 max_hz; @@ -100,7 +108,6 @@ struct clk_default { struct clk { u8 ref_count; - u8 ssc_block_count; u8 freq_change_block_count; u8 flags; }; @@ -205,6 +212,31 @@ struct clk_drv { */ s32 (*resume_restore)(struct clk *clkp); #endif + +#ifdef CONFIG_PM_CLK_SSC + /** + * \brief Set the SSC state of a clock. + * + * \param clk The clock to modify + * \param modfreq_hz The modulation frequency in Hz + * \param mod_depth The modulation depth in "permyriad" + * \param spread_type The spread type + * \param enable True to enable, SFALSE to disable + * + * \return STRUE if the action succeeded + */ + s32 (*set_ssc)(struct clk *clkp, u32 modfreq_hz, u32 mod_depth, u8 spread_type, sbool enable); + + /** + * \brief Get the SSC state of a clock. + * + * \param clk The clock to query + * \param ssc_datap The ssc data structure to populate + * + * \return STRUE if the clock has SSC enabled + */ + void (*get_ssc)(struct clk *clkp, struct ssc_data *ssc_datap); +#endif }; struct clk_data_reg { @@ -332,8 +364,8 @@ u32 clk_get_state(struct clk *clkp); sbool clk_set_state(struct clk *clkp, sbool enable); sbool clk_get(struct clk *clkp); void clk_put(struct clk *clkp); -void clk_ssc_allow(struct clk *clkp); -void clk_ssc_block(struct clk *clkp); +u32 clk_set_ssc(struct clk *clkp, u32 modfreq_hz, u32 mod_depth, u8 spread_type, sbool enable); +u32 clk_get_ssc(struct clk *clkp, struct ssc_data *ssc_datap); void clk_freq_change_allow(struct clk *clkp); void clk_freq_change_block(struct clk *clkp); diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/include/device.h b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/include/device.h index 4143a037..bf7c7d77 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/include/device.h +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/include/device.h @@ -58,7 +58,6 @@ * clock. */ #define DEV_CLK_FLAG_DISABLE BIT(0) -#define DEV_CLK_FLAG_ALLOW_SSC BIT(1) #define DEV_CLK_FLAG_ALLOW_FREQ_CHANGE BIT(2) #define DEV_CLK_FLAG_INPUT_TERM BIT(3) diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/include/device_clk.h b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/include/device_clk.h index 19d2f9de..112138cc 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/include/device_clk.h +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/include/device_clk.h @@ -84,6 +84,8 @@ struct device; +struct ssc_data; + /** * \brief Const clock device data * @@ -280,11 +282,10 @@ sbool device_clk_get_hw_ready(struct device *dev, dev_clk_idx_t clk_idx); sbool device_clk_get_sw_gated(struct device *dev, dev_clk_idx_t clk_idx); /** - * \brief Allow or block SSC (Spread Spectrum Clocking) + * \brief Set the SSC for a device's clock * - * This allows or blocks SSC operation for this clock while it is running. - * If all clocks downsteam from a PLL are either disabled and/or allow SSC, - * SSC will be enabled for that PLL. + * This locates the correct clock and calls the internal clock API + * set function. Configures the SSC on the PLL. * * \param dev * The device ID that the clock is connected to. @@ -292,31 +293,34 @@ sbool device_clk_get_sw_gated(struct device *dev, dev_clk_idx_t clk_idx); * \param clk_idx * The index of the clock on this device. * - * \param allow - * True to allow SSC, SFALSE to block SSC while the clock is enabled. - */ -void device_clk_set_ssc(struct device *dev, dev_clk_idx_t clk_idx, sbool allow); - -/** - * \brief Get the current state of the SSC flag for this device clock. + * \param mod_freq_hz + * The desired modulation frequency in Hz. The modulation period is the time + * required to cycle the clock nominal frequency from an initial value through + * all the different values along the modulation profile and back to the + * initial value. The modulation frequency is the inverse of the period. The + * minimum allowable frequency is 32 kHz and maximum is fREFCLK / 200. For + * example, if the fREFCLK is 25 MHz, the maximum allowable modulation + * frequency would be 125 kHz. * - * \param dev - * The device ID that the clock is connected to. + * \param mod_depth + * The target modulation depth in "permyriad". The modulation depth refers to + * the maximum variation in frequency as a percentage of the clock center + * frequency. The minimum modulation depth is 0.1% and the maximum is 3.1%. + * Modulation depth can be adjusted in 0.1% increments. * - * \param clk_idx - * The index of the clock on this device. + * \param spread_type + * The target spread type. Both center and down spread are supported. + * + * \param enable + * Enable or Disable SSC * * \return - * True if SSC is allowed for this clock, SFALSE if SSC is blocked. + * True if the new SSC configuration was accepted, SFALSE otherwise. */ -sbool device_clk_get_ssc(struct device *dev, dev_clk_idx_t clk_idx); +sbool device_clk_set_ssc(struct device *dev, dev_clk_idx_t clk_idx, u32 modfreq_hz, u32 mod_depth, u8 spread_type, sbool enable); /** - * \brief Get the current SSC state of this clock. - * - * Although the device clock can allow SSC, SSC is not actually enabled unless - * it is allowed by all other users of the PLL. This call can be used to - * determine if SSC has actually been activated. + * \brief Get the current SSC configuration of a device clock. * * \param dev * The device ID that the clock is connected to. @@ -324,10 +328,13 @@ sbool device_clk_get_ssc(struct device *dev, dev_clk_idx_t clk_idx); * \param clk_idx * The index of the clock on this device. * + * \param ssc_data + * The current SSC configuration of the clock. + * * \return - * True if SSC is active. + * True if the SSC configuration was found, SFALSE otherwise. */ -sbool device_clk_get_hw_ssc(struct device *dev, dev_clk_idx_t clk_idx); +sbool device_clk_get_ssc(struct device *dev, dev_clk_idx_t clk_idx, struct ssc_data *ssc_datap); /** * \brief Allow or block frequency changes. diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/pm.h b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/pm.h index e6379c8d..47042349 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/pm.h +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/pm.h @@ -119,6 +119,26 @@ s32 query_freq_handler(u32 *msg_recv); */ s32 get_freq_handler(u32 *msg_recv); +/** + * \brief Set clock SSC Handler PM Function. + * + * \param msg_recv Pointer to the recieved and returned message. Same buffer + * used. + * \return ret SUCCESS if the API executed successfully. + * EFAIL if the API failed to execute. + */ +s32 set_ssc_handler(u32 *msg_recv); + +/** + * \brief Get clock SSC Handler PM Function. + * + * \param msg_recv Pointer to the recieved and returned message. Same buffer + * used. + * \return ret SUCCESS if the API executed successfully. + * EFAIL if the API failed to execute. + */ +s32 get_ssc_handler(u32 *msg_recv); + /** * \brief Set Device State Handler PM Function. * @@ -139,6 +159,16 @@ s32 set_device_handler(u32 *msg_recv); */ s32 get_device_handler(u32 *msg_recv); +/** + * \brief Get Multiple Device States Handler PM Function. + * + * \param msg_recv Pointer to the recieved and returned message. Same buffer + * used. + * \return ret SUCCESS if the API executed successfully. + * EFAIL if the API failed to execute. + */ +s32 get_device_multiple_handler(u32 *msg_recv); + /** * \brief Set Device Resets Handler PM Function. * diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/soc/am62ax/clocks.c b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/soc/am62ax/clocks.c index 086b1f05..91ded4e1 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/soc/am62ax/clocks.c +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/rm_pm_hal/rm_pm_hal_src/pm/soc/am62ax/clocks.c @@ -3722,7 +3722,7 @@ const struct clk_data soc_clock_data[260] = { .drv = &clk_drv_pll_16fft, .freq_idx = AM62AX_FREQ_VALUE_PLLFRACF2_SSMOD_16FFT_MAIN_17, .data = &clk_data_pllfracf2_ssmod_16fft_main_17.data_pll.data, - .flags = 0, + .flags = CLK_DATA_FLAG_ALLOW_SSC_CHANGE, }, [CLK_AM62AX_PLLFRACF2_SSMOD_16FFT_MAIN_2_FOUTVCOP_CLK] = { .parent = { diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/sciclient_direct/makefile.am62ax.r5f.ti-arm-clang b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/sciclient_direct/makefile.am62ax.r5f.ti-arm-clang index 38381610..8777321b 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/sciclient_direct/makefile.am62ax.r5f.ti-arm-clang +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/sciclient_direct/makefile.am62ax.r5f.ti-arm-clang @@ -61,6 +61,7 @@ DEFINES_common := \ -DCONFIG_CLOCK \ -DCONFIG_CLK_PLL_16FFT \ -DCONFIG_CLK_PLL_16FFT_FRACF_CALIBRATION \ + -DCONFIG_PM_CLK_SSC \ -DCONFIG_DM_BUILD \ -DCONFIG_RM \ -DCONFIG_RM_IRQ \ diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/sciclient_direct/sciclient_direct.c b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/sciclient_direct/sciclient_direct.c index 2b200e7a..13ef46d9 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/sciclient_direct/sciclient_direct.c +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/sciclient_direct/sciclient_direct.c @@ -45,7 +45,8 @@ #include //#include #include -#include +#include +#include #include #include #include @@ -280,6 +281,10 @@ int32_t Sciclient_service (const Sciclient_ReqPrm_t *pReqPrm, case TISCI_MSG_SET_CLOCK_PARENT: case TISCI_MSG_GET_CLOCK_PARENT: case TISCI_MSG_GET_NUM_CLOCK_PARENTS: +#ifdef CONFIG_PM_CLK_SSC + case TISCI_MSG_SET_CLOCK_SSC: + case TISCI_MSG_GET_CLOCK_SSC: +#endif case TISCI_MSG_SET_FREQ: case TISCI_MSG_QUERY_FREQ: case TISCI_MSG_GET_FREQ: @@ -714,6 +719,12 @@ int32_t Sciclient_ProcessPmMessage(const uint32_t reqFlags, void *tx_msg) ret = get_clock_parent_handler((uint32_t*)tx_msg); break; case TISCI_MSG_GET_NUM_CLOCK_PARENTS : ret = get_num_clock_parents_handler((uint32_t*)tx_msg); break; +#ifdef CONFIG_PM_CLK_SSC + case TISCI_MSG_SET_CLOCK_SSC : + ret = set_ssc_handler((uint32_t*)tx_msg); break; + case TISCI_MSG_GET_CLOCK_SSC : + ret = get_ssc_handler((uint32_t*)tx_msg); break; +#endif case TISCI_MSG_SET_FREQ : ret = set_freq_handler((uint32_t*)tx_msg); break; case TISCI_MSG_QUERY_FREQ : diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/sciserver/makefile.am62ax.r5f.ti-arm-clang b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/sciserver/makefile.am62ax.r5f.ti-arm-clang index 1c477d82..20f8dadd 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/sciserver/makefile.am62ax.r5f.ti-arm-clang +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/sciserver/makefile.am62ax.r5f.ti-arm-clang @@ -49,6 +49,7 @@ DEFINES_common := \ -DBUILD_DM_R5 \ -DBUILD_MCU1_0 \ -DBUILD_MCU \ + -DCONFIG_PM_CLK_SSC \ -DCONFIG_LPM_DM \ -DCONFIG_OSAL_MINIMAL_QUEUES \ -DMAKEFILE_BUILD \ diff --git a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/sciserver/sciserver.c b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/sciserver/sciserver.c index f97f1529..56d2300b 100644 --- a/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/sciserver/sciserver.c +++ b/mcu_plus_sdk_am62ax_11_01_00_16/source/drivers/device_manager/sciserver/sciserver.c @@ -44,6 +44,8 @@ #include #include #include +#include +#include #include #include #include @@ -564,6 +566,16 @@ static int32_t Sciserver_UserProcessMsg(uint32_t *msg_recv, reqMsgSize = sizeof(struct tisci_msg_get_freq_req); respMsgSize = sizeof(struct tisci_msg_get_freq_resp); break; +#ifdef CONFIG_PM_CLK_SSC + case TISCI_MSG_SET_CLOCK_SSC: + reqMsgSize = sizeof(struct tisci_msg_set_clock_ssc_req); + respMsgSize = sizeof(struct tisci_msg_set_clock_ssc_resp); + break; + case TISCI_MSG_GET_CLOCK_SSC: + reqMsgSize = sizeof(struct tisci_msg_get_clock_ssc_req); + respMsgSize = sizeof(struct tisci_msg_get_clock_ssc_resp); + break; +#endif case TISCI_MSG_SET_DEVICE: reqMsgSize = sizeof(struct tisci_msg_set_device_req); respMsgSize = sizeof(struct tisci_msg_set_device_resp); -- 2.54.0