Re: [PATCH 4/4] clk: ti: add am33xx spread spectrum clock support

From: Grygorii Strashko
Date: Tue Mar 16 2021 - 07:54:43 EST




On 14/03/2021 17:12, Dario Binacchi wrote:
The patch enables spread spectrum clocking (SSC) for MPU and LCD PLLs.
As reported by the TI spruh73x RM, SSC is only supported for the
DISP/LCD and MPU PLLs on am33xx device. SSC is not supported for DDR,
PER, and CORE PLLs.

Calculating the required values and setting the registers accordingly
was taken from the set_mpu_spreadspectrum routine contained in the
arch/arm/mach-omap2/am33xx/clock_am33xx.c file of the u-boot project.

In locked condition, DPLL output clock = CLKINP *[M/N]. In case of
SSC enabled, the AM335x reference manual explains that there is a
restriction of range of M values. Since the omap2_dpll_round_rate
routine attempts to select the minimum possible N, the value of M
obtained is not guaranteed to be within the range required. With the new
"ti,min-div" parameter it is possible to increase N and consequently M
to satisfy the constraint imposed by SSC.

Signed-off-by: Dario Binacchi <dariobin@xxxxxxxxx>

---

arch/arm/boot/dts/am33xx-clocks.dtsi | 4 +-
drivers/clk/ti/dpll.c | 41 ++++++++++++++
drivers/clk/ti/dpll3xxx.c | 85 ++++++++++++++++++++++++++++
include/linux/clk/ti.h | 24 ++++++++
4 files changed, 152 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/am33xx-clocks.dtsi b/arch/arm/boot/dts/am33xx-clocks.dtsi
index e7bbbf536a8c..a02e0b1229a4 100644
--- a/arch/arm/boot/dts/am33xx-clocks.dtsi
+++ b/arch/arm/boot/dts/am33xx-clocks.dtsi
@@ -164,7 +164,7 @@
#clock-cells = <0>;
compatible = "ti,am3-dpll-core-clock";
clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
- reg = <0x0490>, <0x045c>, <0x0468>, <0x0460>, <0x0464>;
+ reg = <0x0490>, <0x045c>, <0x0468>;
};
dpll_core_x2_ck: dpll_core_x2_ck {
@@ -204,7 +204,7 @@
#clock-cells = <0>;
compatible = "ti,am3-dpll-clock";
clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
- reg = <0x0488>, <0x0420>, <0x042c>;
+ reg = <0x0488>, <0x0420>, <0x042c>, <0x0424>, <0x0428>;
};

You can't mix DT vs code.

dpll_mpu_m2_ck: dpll_mpu_m2_ck@4a8 {
diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c
index d6f1ac5b53e1..2738417a47b7 100644
--- a/drivers/clk/ti/dpll.c
+++ b/drivers/clk/ti/dpll.c
@@ -290,7 +290,9 @@ static void __init of_ti_dpll_setup(struct device_node *node,
struct clk_init_data *init = NULL;
const char **parent_names = NULL;
struct dpll_data *dd = NULL;
+ int ssc_clk_index;
u8 dpll_mode = 0;
+ u32 min_div;
dd = kmemdup(ddt, sizeof(*dd), GFP_KERNEL);
clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
@@ -345,6 +347,27 @@ static void __init of_ti_dpll_setup(struct device_node *node,
if (dd->autoidle_mask) {
if (ti_clk_get_reg_addr(node, 3, &dd->autoidle_reg))
goto cleanup;
+
+ ssc_clk_index = 4;
+ } else {
+ ssc_clk_index = 3;
+ }
+
+ if (dd->ssc_deltam_int_mask && dd->ssc_deltam_frac_mask &&
+ dd->ssc_modfreq_mant_mask && dd->ssc_modfreq_exp_mask) {
+ if (ti_clk_get_reg_addr(node, ssc_clk_index++,
+ &dd->ssc_deltam_reg))
+ goto cleanup;
+
+ if (ti_clk_get_reg_addr(node, ssc_clk_index++,
+ &dd->ssc_modfreq_reg))
+ goto cleanup;
+
+ of_property_read_u32(node, "ti,ssc-modfreq", &dd->ssc_modfreq);
+ of_property_read_u32(node, "ti,ssc-deltam", &dd->ssc_deltam);
+ if (of_property_read_bool(node, "ti,ssc-downspread"))
+ dd->ssc_downspread = 1;

New bindings.

+
}
if (of_property_read_bool(node, "ti,low-power-stop"))
@@ -356,6 +379,10 @@ static void __init of_ti_dpll_setup(struct device_node *node,
if (of_property_read_bool(node, "ti,lock"))
dpll_mode |= 1 << DPLL_LOCKED;
+ if (!of_property_read_u32(node, "ti,min-div", &min_div) &&
+ min_div > dd->min_divider)
+ dd->min_divider = min_div;
+

New bindings.

[...]

--
Best regards,
grygorii