1111#include <linux/device.h>
1212#include <linux/init.h>
1313#include <linux/kernel.h>
14+ #include <linux/math.h>
15+ #include <linux/types.h>
1416
1517#include <dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h>
1618#include <dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h>
4143#define GET_WIDTH (val ) FIELD_GET(WIDTH_MASK, val)
4244#define GET_REG_OFFSET (val ) FIELD_GET(OFFSET_MASK, val)
4345
46+ #define FSELXSPI0 CONF_PACK(SCKCR, 0, 3)
47+ #define FSELXSPI1 CONF_PACK(SCKCR, 8, 3)
48+ #define DIVSEL_XSPI0 CONF_PACK(SCKCR, 6, 1)
49+ #define DIVSEL_XSPI1 CONF_PACK(SCKCR, 14, 1)
50+ #define SEL_PLL CONF_PACK(SCKCR, 22, 1)
51+
4452#define DIVCA55C0 CONF_PACK(SCKCR2, 8, 1)
4553#define DIVCA55C1 CONF_PACK(SCKCR2, 9, 1)
4654#define DIVCA55C2 CONF_PACK(SCKCR2, 10, 1)
5866#define DIVSCI3ASYNC CONF_PACK(SCKCR3, 12, 2)
5967#define DIVSCI4ASYNC CONF_PACK(SCKCR3, 14, 2)
6068
61- #define SEL_PLL CONF_PACK(SCKCR, 22, 1)
62-
6369enum rzt2h_clk_types {
6470 CLK_TYPE_RZT2H_DIV = CLK_TYPE_CUSTOM , /* Clock with divider */
6571 CLK_TYPE_RZT2H_MUX , /* Clock with clock source selector */
72+ CLK_TYPE_RZT2H_FSELXSPI , /* Clock with FSELXSPIn source selector */
6673};
6774
6875#define DEF_DIV (_name , _id , _parent , _conf , _dtable ) \
@@ -72,10 +79,13 @@ enum rzt2h_clk_types {
7279 DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_MUX, .conf = _conf, \
7380 .parent_names = _parent_names, .num_parents = _num_parents, \
7481 .flag = 0, .mux_flags = _mux_flags)
82+ #define DEF_DIV_FSELXSPI (_name , _id , _parent , _conf , _dtable ) \
83+ DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_FSELXSPI, .conf = _conf, \
84+ .parent = _parent, .dtable = _dtable, .flag = 0)
7585
7686enum clk_ids {
7787 /* Core Clock Outputs exported to DT */
78- LAST_DT_CORE_CLK = R9A09G077_ETCLKE ,
88+ LAST_DT_CORE_CLK = R9A09G077_XSPI_CLK1 ,
7989
8090 /* External Input Clocks */
8191 CLK_EXTAL ,
@@ -91,6 +101,8 @@ enum clk_ids {
91101 CLK_SEL_CLK_PLL2 ,
92102 CLK_SEL_CLK_PLL4 ,
93103 CLK_PLL4D1 ,
104+ CLK_PLL4D1_DIV3 ,
105+ CLK_PLL4D1_DIV4 ,
94106 CLK_SCI0ASYNC ,
95107 CLK_SCI1ASYNC ,
96108 CLK_SCI2ASYNC ,
@@ -101,6 +113,8 @@ enum clk_ids {
101113 CLK_SPI1ASYNC ,
102114 CLK_SPI2ASYNC ,
103115 CLK_SPI3ASYNC ,
116+ CLK_DIVSELXSPI0_SCKCR ,
117+ CLK_DIVSELXSPI1_SCKCR ,
104118
105119 /* Module Clocks */
106120 MOD_CLK_BASE ,
@@ -112,6 +126,15 @@ static const struct clk_div_table dtable_1_2[] = {
112126 {0 , 0 },
113127};
114128
129+ static const struct clk_div_table dtable_6_8_16_32_64 [] = {
130+ {6 , 64 },
131+ {5 , 32 },
132+ {4 , 16 },
133+ {3 , 8 },
134+ {2 , 6 },
135+ {0 , 0 },
136+ };
137+
115138static const struct clk_div_table dtable_24_25_30_32 [] = {
116139 {0 , 32 },
117140 {1 , 30 },
@@ -126,6 +149,7 @@ static const char * const sel_clk_pll0[] = { ".loco", ".pll0" };
126149static const char * const sel_clk_pll1 [] = { ".loco" , ".pll1" };
127150static const char * const sel_clk_pll2 [] = { ".loco" , ".pll2" };
128151static const char * const sel_clk_pll4 [] = { ".loco" , ".pll4" };
152+ static const char * const sel_clk_pll4d1_div3_div4 [] = { ".pll4d1_div3" , ".pll4d1_div4" };
129153
130154static const struct cpg_core_clk r9a09g077_core_clks [] __initconst = {
131155 /* External Clock Inputs */
@@ -148,6 +172,9 @@ static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = {
148172 sel_clk_pll4 , ARRAY_SIZE (sel_clk_pll4 ), CLK_MUX_READ_ONLY ),
149173
150174 DEF_FIXED (".pll4d1" , CLK_PLL4D1 , CLK_SEL_CLK_PLL4 , 1 , 1 ),
175+ DEF_FIXED (".pll4d1_div3" , CLK_PLL4D1_DIV3 , CLK_PLL4D1 , 3 , 1 ),
176+ DEF_FIXED (".pll4d1_div4" , CLK_PLL4D1_DIV4 , CLK_PLL4D1 , 4 , 1 ),
177+
151178 DEF_DIV (".sci0async" , CLK_SCI0ASYNC , CLK_PLL4D1 , DIVSCI0ASYNC ,
152179 dtable_24_25_30_32 ),
153180 DEF_DIV (".sci1async" , CLK_SCI1ASYNC , CLK_PLL4D1 , DIVSCI1ASYNC ,
@@ -170,6 +197,13 @@ static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = {
170197 DEF_DIV (".spi3async" , CLK_SPI3ASYNC , CLK_PLL4D1 , DIVSPI3ASYNC ,
171198 dtable_24_25_30_32 ),
172199
200+ DEF_MUX (".divselxspi0" , CLK_DIVSELXSPI0_SCKCR , DIVSEL_XSPI0 ,
201+ sel_clk_pll4d1_div3_div4 ,
202+ ARRAY_SIZE (sel_clk_pll4d1_div3_div4 ), 0 ),
203+ DEF_MUX (".divselxspi1" , CLK_DIVSELXSPI1_SCKCR , DIVSEL_XSPI1 ,
204+ sel_clk_pll4d1_div3_div4 ,
205+ ARRAY_SIZE (sel_clk_pll4d1_div3_div4 ), 0 ),
206+
173207 /* Core output clk */
174208 DEF_DIV ("CA55C0" , R9A09G077_CLK_CA55C0 , CLK_SEL_CLK_PLL0 , DIVCA55C0 ,
175209 dtable_1_2 ),
@@ -194,9 +228,15 @@ static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = {
194228 DEF_FIXED ("ETCLKC" , R9A09G077_ETCLKC , CLK_SEL_CLK_PLL1 , 10 , 1 ),
195229 DEF_FIXED ("ETCLKD" , R9A09G077_ETCLKD , CLK_SEL_CLK_PLL1 , 20 , 1 ),
196230 DEF_FIXED ("ETCLKE" , R9A09G077_ETCLKE , CLK_SEL_CLK_PLL1 , 40 , 1 ),
231+ DEF_DIV_FSELXSPI ("XSPI_CLK0" , R9A09G077_XSPI_CLK0 , CLK_DIVSELXSPI0_SCKCR ,
232+ FSELXSPI0 , dtable_6_8_16_32_64 ),
233+ DEF_DIV_FSELXSPI ("XSPI_CLK1" , R9A09G077_XSPI_CLK1 , CLK_DIVSELXSPI1_SCKCR ,
234+ FSELXSPI1 , dtable_6_8_16_32_64 ),
197235};
198236
199237static const struct mssr_mod_clk r9a09g077_mod_clks [] __initconst = {
238+ DEF_MOD ("xspi0" , 4 , R9A09G077_CLK_PCLKH ),
239+ DEF_MOD ("xspi1" , 5 , R9A09G077_CLK_PCLKH ),
200240 DEF_MOD ("sci0fck" , 8 , CLK_SCI0ASYNC ),
201241 DEF_MOD ("sci1fck" , 9 , CLK_SCI1ASYNC ),
202242 DEF_MOD ("sci2fck" , 10 , CLK_SCI2ASYNC ),
@@ -284,6 +324,151 @@ r9a09g077_cpg_mux_clk_register(struct device *dev,
284324 return clk_hw -> clk ;
285325}
286326
327+ static unsigned int r9a09g077_cpg_fselxspi_get_divider (struct clk_hw * hw , unsigned long rate ,
328+ unsigned int num_parents )
329+ {
330+ struct clk_fixed_factor * ff ;
331+ struct clk_hw * parent_hw ;
332+ unsigned long best_rate ;
333+ unsigned int i ;
334+
335+ for (i = 0 ; i < num_parents ; i ++ ) {
336+ parent_hw = clk_hw_get_parent_by_index (hw , i );
337+ best_rate = clk_hw_round_rate (parent_hw , rate );
338+
339+ if (best_rate == rate ) {
340+ ff = to_clk_fixed_factor (parent_hw );
341+ return ff -> div ;
342+ }
343+ }
344+
345+ /* No parent could provide the exact rate - this should not happen */
346+ return 0 ;
347+ }
348+
349+ static int r9a09g077_cpg_fselxspi_determine_rate (struct clk_hw * hw ,
350+ struct clk_rate_request * req )
351+ {
352+ struct clk_divider * divider = to_clk_divider (hw );
353+ unsigned long parent_rate , best = 0 , now ;
354+ const struct clk_div_table * clkt ;
355+ unsigned long rate = req -> rate ;
356+ unsigned int num_parents ;
357+ unsigned int divselxspi ;
358+ unsigned int div = 0 ;
359+
360+ if (!rate )
361+ rate = 1 ;
362+
363+ /* Get the number of parents for FSELXSPIn */
364+ num_parents = clk_hw_get_num_parents (req -> best_parent_hw );
365+
366+ for (clkt = divider -> table ; clkt -> div ; clkt ++ ) {
367+ parent_rate = clk_hw_round_rate (req -> best_parent_hw , rate * clkt -> div );
368+ /* Skip if parent can't provide any valid rate */
369+ if (!parent_rate )
370+ continue ;
371+
372+ /* Determine which DIVSELXSPIn divider (3 or 4) provides this parent_rate */
373+ divselxspi = r9a09g077_cpg_fselxspi_get_divider (req -> best_parent_hw , parent_rate ,
374+ num_parents );
375+ if (!divselxspi )
376+ continue ;
377+
378+ /*
379+ * DIVSELXSPIx supports 800MHz and 600MHz operation.
380+ * When divselxspi is 4 (600MHz operation), only FSELXSPIn dividers of 8 and 16
381+ * are supported. Otherwise, when divselxspi is 3 (800MHz operation),
382+ * dividers of 6, 8, 16, 32, and 64 are supported. This check ensures that
383+ * FSELXSPIx is set correctly based on hardware limitations.
384+ */
385+ if (divselxspi == 4 && (clkt -> div != 8 && clkt -> div != 16 ))
386+ continue ;
387+
388+ now = DIV_ROUND_UP_ULL (parent_rate , clkt -> div );
389+ if (abs (rate - now ) < abs (rate - best )) {
390+ div = clkt -> div ;
391+ best = now ;
392+ req -> best_parent_rate = parent_rate ;
393+ }
394+ }
395+
396+ if (!div ) {
397+ req -> best_parent_rate = clk_hw_round_rate (req -> best_parent_hw , 1 );
398+ divselxspi = r9a09g077_cpg_fselxspi_get_divider (req -> best_parent_hw ,
399+ req -> best_parent_rate ,
400+ num_parents );
401+ /* default to divider 3 which will result DIVSELXSPIn = 800 MHz */
402+ if (!divselxspi )
403+ divselxspi = 3 ;
404+
405+ /*
406+ * Use the maximum divider based on the parent clock rate:
407+ * - 64 when DIVSELXSPIx is 800 MHz (divider = 3)
408+ * - 16 when DIVSELXSPIx is 600 MHz (divider = 4)
409+ */
410+ div = divselxspi == 3 ? 64 : 16 ;
411+ }
412+
413+ req -> rate = DIV_ROUND_UP_ULL (req -> best_parent_rate , div );
414+
415+ return 0 ;
416+ }
417+
418+ static struct clk * __init
419+ r9a09g077_cpg_fselxspi_div_clk_register (struct device * dev ,
420+ const struct cpg_core_clk * core ,
421+ void __iomem * addr ,
422+ struct cpg_mssr_pub * pub )
423+ {
424+ static struct clk_ops * xspi_div_ops ;
425+ struct clk_init_data init = {};
426+ const struct clk * parent ;
427+ const char * parent_name ;
428+ struct clk_divider * div ;
429+ struct clk_hw * hw ;
430+ int ret ;
431+
432+ parent = pub -> clks [core -> parent ];
433+ if (IS_ERR (parent ))
434+ return ERR_CAST (parent );
435+
436+ div = devm_kzalloc (dev , sizeof (* div ), GFP_KERNEL );
437+ if (!div )
438+ return ERR_PTR (- ENOMEM );
439+
440+ if (!xspi_div_ops ) {
441+ xspi_div_ops = devm_kzalloc (dev , sizeof (* xspi_div_ops ), GFP_KERNEL );
442+ if (!xspi_div_ops )
443+ return ERR_PTR (- ENOMEM );
444+ memcpy (xspi_div_ops , & clk_divider_ops ,
445+ sizeof (const struct clk_ops ));
446+ xspi_div_ops -> determine_rate = r9a09g077_cpg_fselxspi_determine_rate ;
447+ }
448+
449+ parent_name = __clk_get_name (parent );
450+ init .name = core -> name ;
451+ init .ops = xspi_div_ops ;
452+ init .flags = CLK_SET_RATE_PARENT ;
453+ init .parent_names = & parent_name ;
454+ init .num_parents = 1 ;
455+
456+ div -> reg = addr ;
457+ div -> shift = GET_SHIFT (core -> conf );
458+ div -> width = GET_WIDTH (core -> conf );
459+ div -> flags = core -> flag ;
460+ div -> lock = & pub -> rmw_lock ;
461+ div -> hw .init = & init ;
462+ div -> table = core -> dtable ;
463+
464+ hw = & div -> hw ;
465+ ret = devm_clk_hw_register (dev , hw );
466+ if (ret )
467+ return ERR_PTR (ret );
468+
469+ return hw -> clk ;
470+ }
471+
287472static struct clk * __init
288473r9a09g077_cpg_clk_register (struct device * dev , const struct cpg_core_clk * core ,
289474 const struct cpg_mssr_info * info ,
@@ -298,6 +483,8 @@ r9a09g077_cpg_clk_register(struct device *dev, const struct cpg_core_clk *core,
298483 return r9a09g077_cpg_div_clk_register (dev , core , addr , pub );
299484 case CLK_TYPE_RZT2H_MUX :
300485 return r9a09g077_cpg_mux_clk_register (dev , core , addr , pub );
486+ case CLK_TYPE_RZT2H_FSELXSPI :
487+ return r9a09g077_cpg_fselxspi_div_clk_register (dev , core , addr , pub );
301488 default :
302489 return ERR_PTR (- EINVAL );
303490 }
0 commit comments