r7s9210-cpg-mssr.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * R7S9210 Clock Pulse Generator / Module Standby
  4. *
  5. * Based on r8a7795-cpg-mssr.c
  6. *
  7. * Copyright (C) 2018 Chris Brandt
  8. * Copyright (C) 2018 Renesas Electronics Corp.
  9. *
  10. */
  11. #include <linux/clk.h>
  12. #include <linux/clk-provider.h>
  13. #include <linux/io.h>
  14. #include <dt-bindings/clock/r7s9210-cpg-mssr.h>
  15. #include "renesas-cpg-mssr.h"
  16. #define CPG_FRQCR 0x00
  17. static u8 cpg_mode;
  18. /* Internal Clock ratio table */
  19. static const struct {
  20. unsigned int i;
  21. unsigned int g;
  22. unsigned int b;
  23. unsigned int p1;
  24. /* p0 is always 32 */;
  25. } ratio_tab[5] = { /* I, G, B, P1 */
  26. { 2, 4, 8, 16}, /* FRQCR = 0x012 */
  27. { 4, 4, 8, 16}, /* FRQCR = 0x112 */
  28. { 8, 4, 8, 16}, /* FRQCR = 0x212 */
  29. { 16, 8, 16, 16}, /* FRQCR = 0x322 */
  30. { 16, 16, 32, 32}, /* FRQCR = 0x333 */
  31. };
  32. enum rz_clk_types {
  33. CLK_TYPE_RZA_MAIN = CLK_TYPE_CUSTOM,
  34. CLK_TYPE_RZA_PLL,
  35. };
  36. enum clk_ids {
  37. /* Core Clock Outputs exported to DT */
  38. LAST_DT_CORE_CLK = R7S9210_CLK_P0,
  39. /* External Input Clocks */
  40. CLK_EXTAL,
  41. /* Internal Core Clocks */
  42. CLK_MAIN,
  43. CLK_PLL,
  44. /* Module Clocks */
  45. MOD_CLK_BASE
  46. };
  47. static struct cpg_core_clk r7s9210_early_core_clks[] = {
  48. /* External Clock Inputs */
  49. DEF_INPUT("extal", CLK_EXTAL),
  50. /* Internal Core Clocks */
  51. DEF_BASE(".main", CLK_MAIN, CLK_TYPE_RZA_MAIN, CLK_EXTAL),
  52. DEF_BASE(".pll", CLK_PLL, CLK_TYPE_RZA_PLL, CLK_MAIN),
  53. /* Core Clock Outputs */
  54. DEF_FIXED("p1c", R7S9210_CLK_P1C, CLK_PLL, 16, 1),
  55. };
  56. static const struct mssr_mod_clk r7s9210_early_mod_clks[] __initconst = {
  57. DEF_MOD_STB("ostm2", 34, R7S9210_CLK_P1C),
  58. DEF_MOD_STB("ostm1", 35, R7S9210_CLK_P1C),
  59. DEF_MOD_STB("ostm0", 36, R7S9210_CLK_P1C),
  60. };
  61. static struct cpg_core_clk r7s9210_core_clks[] = {
  62. /* Core Clock Outputs */
  63. DEF_FIXED("i", R7S9210_CLK_I, CLK_PLL, 2, 1),
  64. DEF_FIXED("g", R7S9210_CLK_G, CLK_PLL, 4, 1),
  65. DEF_FIXED("b", R7S9210_CLK_B, CLK_PLL, 8, 1),
  66. DEF_FIXED("p1", R7S9210_CLK_P1, CLK_PLL, 16, 1),
  67. DEF_FIXED("p0", R7S9210_CLK_P0, CLK_PLL, 32, 1),
  68. };
  69. static const struct mssr_mod_clk r7s9210_mod_clks[] __initconst = {
  70. DEF_MOD_STB("scif4", 43, R7S9210_CLK_P1C),
  71. DEF_MOD_STB("scif3", 44, R7S9210_CLK_P1C),
  72. DEF_MOD_STB("scif2", 45, R7S9210_CLK_P1C),
  73. DEF_MOD_STB("scif1", 46, R7S9210_CLK_P1C),
  74. DEF_MOD_STB("scif0", 47, R7S9210_CLK_P1C),
  75. DEF_MOD_STB("usb1", 60, R7S9210_CLK_B),
  76. DEF_MOD_STB("usb0", 61, R7S9210_CLK_B),
  77. DEF_MOD_STB("ether1", 64, R7S9210_CLK_B),
  78. DEF_MOD_STB("ether0", 65, R7S9210_CLK_B),
  79. DEF_MOD_STB("spibsc", 83, R7S9210_CLK_P1),
  80. DEF_MOD_STB("i2c3", 84, R7S9210_CLK_P1),
  81. DEF_MOD_STB("i2c2", 85, R7S9210_CLK_P1),
  82. DEF_MOD_STB("i2c1", 86, R7S9210_CLK_P1),
  83. DEF_MOD_STB("i2c0", 87, R7S9210_CLK_P1),
  84. DEF_MOD_STB("spi2", 95, R7S9210_CLK_P1),
  85. DEF_MOD_STB("spi1", 96, R7S9210_CLK_P1),
  86. DEF_MOD_STB("spi0", 97, R7S9210_CLK_P1),
  87. DEF_MOD_STB("sdhi11", 100, R7S9210_CLK_B),
  88. DEF_MOD_STB("sdhi10", 101, R7S9210_CLK_B),
  89. DEF_MOD_STB("sdhi01", 102, R7S9210_CLK_B),
  90. DEF_MOD_STB("sdhi00", 103, R7S9210_CLK_B),
  91. };
  92. /* The clock dividers in the table vary based on DT and register settings */
  93. static void __init r7s9210_update_clk_table(struct clk *extal_clk,
  94. void __iomem *base)
  95. {
  96. int i;
  97. u16 frqcr;
  98. u8 index;
  99. /* If EXTAL is above 12MHz, then we know it is Mode 1 */
  100. if (clk_get_rate(extal_clk) > 12000000)
  101. cpg_mode = 1;
  102. frqcr = readl(base + CPG_FRQCR) & 0xFFF;
  103. if (frqcr == 0x012)
  104. index = 0;
  105. else if (frqcr == 0x112)
  106. index = 1;
  107. else if (frqcr == 0x212)
  108. index = 2;
  109. else if (frqcr == 0x322)
  110. index = 3;
  111. else if (frqcr == 0x333)
  112. index = 4;
  113. else
  114. BUG_ON(1); /* Illegal FRQCR value */
  115. for (i = 0; i < ARRAY_SIZE(r7s9210_core_clks); i++) {
  116. switch (r7s9210_core_clks[i].id) {
  117. case R7S9210_CLK_I:
  118. r7s9210_core_clks[i].div = ratio_tab[index].i;
  119. break;
  120. case R7S9210_CLK_G:
  121. r7s9210_core_clks[i].div = ratio_tab[index].g;
  122. break;
  123. case R7S9210_CLK_B:
  124. r7s9210_core_clks[i].div = ratio_tab[index].b;
  125. break;
  126. case R7S9210_CLK_P1:
  127. case R7S9210_CLK_P1C:
  128. r7s9210_core_clks[i].div = ratio_tab[index].p1;
  129. break;
  130. case R7S9210_CLK_P0:
  131. r7s9210_core_clks[i].div = 32;
  132. break;
  133. }
  134. }
  135. }
  136. static struct clk * __init rza2_cpg_clk_register(struct device *dev,
  137. const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
  138. struct clk **clks, void __iomem *base,
  139. struct raw_notifier_head *notifiers)
  140. {
  141. struct clk *parent;
  142. unsigned int mult = 1;
  143. unsigned int div = 1;
  144. parent = clks[core->parent];
  145. if (IS_ERR(parent))
  146. return ERR_CAST(parent);
  147. switch (core->id) {
  148. case CLK_MAIN:
  149. break;
  150. case CLK_PLL:
  151. if (cpg_mode)
  152. mult = 44; /* Divider 1 is 1/2 */
  153. else
  154. mult = 88; /* Divider 1 is 1 */
  155. break;
  156. default:
  157. return ERR_PTR(-EINVAL);
  158. }
  159. if (core->id == CLK_MAIN)
  160. r7s9210_update_clk_table(parent, base);
  161. return clk_register_fixed_factor(NULL, core->name,
  162. __clk_get_name(parent), 0, mult, div);
  163. }
  164. const struct cpg_mssr_info r7s9210_cpg_mssr_info __initconst = {
  165. /* Early Clocks */
  166. .early_core_clks = r7s9210_early_core_clks,
  167. .num_early_core_clks = ARRAY_SIZE(r7s9210_early_core_clks),
  168. .early_mod_clks = r7s9210_early_mod_clks,
  169. .num_early_mod_clks = ARRAY_SIZE(r7s9210_early_mod_clks),
  170. /* Core Clocks */
  171. .core_clks = r7s9210_core_clks,
  172. .num_core_clks = ARRAY_SIZE(r7s9210_core_clks),
  173. .last_dt_core_clk = LAST_DT_CORE_CLK,
  174. .num_total_core_clks = MOD_CLK_BASE,
  175. /* Module Clocks */
  176. .mod_clks = r7s9210_mod_clks,
  177. .num_mod_clks = ARRAY_SIZE(r7s9210_mod_clks),
  178. .num_hw_mod_clks = 11 * 32, /* includes STBCR0 which doesn't exist */
  179. /* Callbacks */
  180. .cpg_clk_register = rza2_cpg_clk_register,
  181. /* RZ/A2 has Standby Control Registers */
  182. .reg_layout = CLK_REG_LAYOUT_RZ_A,
  183. };
  184. static void __init r7s9210_cpg_mssr_early_init(struct device_node *np)
  185. {
  186. cpg_mssr_early_init(np, &r7s9210_cpg_mssr_info);
  187. }
  188. CLK_OF_DECLARE_DRIVER(cpg_mstp_clks, "renesas,r7s9210-cpg-mssr",
  189. r7s9210_cpg_mssr_early_init);