0032-clk-starfive-Add-StarFive-JH7110-PLL-clock-driver.patch 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. From 0bc7aa28dcdee75a52b1874a02dfbf0107c2d448 Mon Sep 17 00:00:00 2001
  2. From: Xingyu Wu <[email protected]>
  3. Date: Fri, 17 Feb 2023 17:30:09 +0800
  4. Subject: [PATCH 032/122] clk: starfive: Add StarFive JH7110 PLL clock driver
  5. Add driver for the StarFive JH7110 PLL clock controller
  6. and they work by reading and setting syscon registers.
  7. Signed-off-by: Xingyu Wu <[email protected]>
  8. ---
  9. MAINTAINERS | 6 +
  10. drivers/clk/starfive/Kconfig | 8 +
  11. drivers/clk/starfive/Makefile | 1 +
  12. .../clk/starfive/clk-starfive-jh7110-pll.c | 427 ++++++++++++++++++
  13. .../clk/starfive/clk-starfive-jh7110-pll.h | 293 ++++++++++++
  14. 5 files changed, 735 insertions(+)
  15. create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-pll.c
  16. create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-pll.h
  17. --- a/MAINTAINERS
  18. +++ b/MAINTAINERS
  19. @@ -19650,6 +19650,12 @@ M: Emil Renner Berthing <[email protected]
  20. S: Maintained
  21. F: arch/riscv/boot/dts/starfive/
  22. +STARFIVE JH7110 PLL CLOCK DRIVER
  23. +M: Xingyu Wu <[email protected]>
  24. +S: Supported
  25. +F: Documentation/devicetree/bindings/clock/starfive,jh7110-pll.yaml
  26. +F: drivers/clk/starfive/clk-starfive-jh7110-pll.*
  27. +
  28. STARFIVE JH71X0 CLOCK DRIVERS
  29. M: Emil Renner Berthing <[email protected]>
  30. M: Hal Feng <[email protected]>
  31. --- a/drivers/clk/starfive/Kconfig
  32. +++ b/drivers/clk/starfive/Kconfig
  33. @@ -21,6 +21,14 @@ config CLK_STARFIVE_JH7100_AUDIO
  34. Say Y or M here to support the audio clocks on the StarFive JH7100
  35. SoC.
  36. +config CLK_STARFIVE_JH7110_PLL
  37. + bool "StarFive JH7110 PLL clock support"
  38. + depends on ARCH_STARFIVE || COMPILE_TEST
  39. + default ARCH_STARFIVE
  40. + help
  41. + Say yes here to support the PLL clock controller on the
  42. + StarFive JH7110 SoC.
  43. +
  44. config CLK_STARFIVE_JH7110_SYS
  45. bool "StarFive JH7110 system clock support"
  46. depends on ARCH_STARFIVE || COMPILE_TEST
  47. --- a/drivers/clk/starfive/Makefile
  48. +++ b/drivers/clk/starfive/Makefile
  49. @@ -4,5 +4,6 @@ obj-$(CONFIG_CLK_STARFIVE_JH71X0) += clk
  50. obj-$(CONFIG_CLK_STARFIVE_JH7100) += clk-starfive-jh7100.o
  51. obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o
  52. +obj-$(CONFIG_CLK_STARFIVE_JH7110_PLL) += clk-starfive-jh7110-pll.o
  53. obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o
  54. obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
  55. --- /dev/null
  56. +++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.c
  57. @@ -0,0 +1,427 @@
  58. +// SPDX-License-Identifier: GPL-2.0
  59. +/*
  60. + * StarFive JH7110 PLL Clock Generator Driver
  61. + *
  62. + * Copyright (C) 2023 StarFive Technology Co., Ltd.
  63. + *
  64. + * This driver is about to register JH7110 PLL clock generator and support ops.
  65. + * The JH7110 have three PLL clock, PLL0, PLL1 and PLL2.
  66. + * Each PLL clocks work in integer mode or fraction mode by some dividers,
  67. + * and the configuration registers and dividers are set in several syscon registers.
  68. + * The formula for calculating frequency is:
  69. + * Fvco = Fref * (NI + NF) / M / Q1
  70. + * Fref: OSC source clock rate
  71. + * NI: integer frequency dividing ratio of feedback divider, set by fbdiv[11:0].
  72. + * NF: fractional frequency dividing ratio, set by frac[23:0]. NF = frac[23:0] / 2^24 = 0 ~ 0.999.
  73. + * M: frequency dividing ratio of pre-divider, set by prediv[5:0].
  74. + * Q1: frequency dividing ratio of post divider, set by postdiv1[1:0], Q1= 1,2,4,8.
  75. + */
  76. +
  77. +#include <linux/clk-provider.h>
  78. +#include <linux/debugfs.h>
  79. +#include <linux/device.h>
  80. +#include <linux/kernel.h>
  81. +#include <linux/mfd/syscon.h>
  82. +#include <linux/platform_device.h>
  83. +#include <linux/regmap.h>
  84. +
  85. +#include <dt-bindings/clock/starfive,jh7110-crg.h>
  86. +
  87. +#include "clk-starfive-jh7110-pll.h"
  88. +
  89. +static struct jh7110_clk_pll_data *jh7110_pll_data_from(struct clk_hw *hw)
  90. +{
  91. + return container_of(hw, struct jh7110_clk_pll_data, hw);
  92. +}
  93. +
  94. +static struct jh7110_clk_pll_priv *jh7110_pll_priv_from(struct jh7110_clk_pll_data *data)
  95. +{
  96. + return container_of(data, struct jh7110_clk_pll_priv, data[data->idx]);
  97. +}
  98. +
  99. +/* Read register value from syscon and calculate PLL(x) frequency */
  100. +static unsigned long jh7110_pll_get_freq(struct jh7110_clk_pll_data *data,
  101. + unsigned long parent_rate)
  102. +{
  103. + struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
  104. + struct jh7110_pll_syscon_offset *offset = &data->offset;
  105. + struct jh7110_pll_syscon_mask *mask = &data->mask;
  106. + struct jh7110_pll_syscon_shift *shift = &data->shift;
  107. + unsigned long freq = 0;
  108. + unsigned long frac_cal;
  109. + u32 dacpd;
  110. + u32 dsmpd;
  111. + u32 fbdiv;
  112. + u32 prediv;
  113. + u32 postdiv1;
  114. + u32 frac;
  115. + u32 reg_val;
  116. +
  117. + if (regmap_read(priv->syscon_regmap, offset->dacpd, &reg_val))
  118. + goto read_error;
  119. + dacpd = (reg_val & mask->dacpd) >> shift->dacpd;
  120. +
  121. + if (regmap_read(priv->syscon_regmap, offset->dsmpd, &reg_val))
  122. + goto read_error;
  123. + dsmpd = (reg_val & mask->dsmpd) >> shift->dsmpd;
  124. +
  125. + if (regmap_read(priv->syscon_regmap, offset->fbdiv, &reg_val))
  126. + goto read_error;
  127. + fbdiv = (reg_val & mask->fbdiv) >> shift->fbdiv;
  128. + /* fbdiv value should be 8 to 4095 */
  129. + if (fbdiv < 8)
  130. + goto read_error;
  131. +
  132. + if (regmap_read(priv->syscon_regmap, offset->prediv, &reg_val))
  133. + goto read_error;
  134. + prediv = (reg_val & mask->prediv) >> shift->prediv;
  135. +
  136. + if (regmap_read(priv->syscon_regmap, offset->postdiv1, &reg_val))
  137. + goto read_error;
  138. + /* postdiv1 = 2 ^ reg_val */
  139. + postdiv1 = 1 << ((reg_val & mask->postdiv1) >> shift->postdiv1);
  140. +
  141. + if (regmap_read(priv->syscon_regmap, offset->frac, &reg_val))
  142. + goto read_error;
  143. + frac = (reg_val & mask->frac) >> shift->frac;
  144. +
  145. + /*
  146. + * Integer Mode (Both 1) or Fraction Mode (Both 0).
  147. + * And the decimal places are counted by expanding them by
  148. + * a factor of STARFIVE_PLL_FRAC_PATR_SIZE.
  149. + */
  150. + if (dacpd == 1 && dsmpd == 1)
  151. + frac_cal = 0;
  152. + else if (dacpd == 0 && dsmpd == 0)
  153. + frac_cal = (unsigned long)frac * STARFIVE_PLL_FRAC_PATR_SIZE / (1 << 24);
  154. + else
  155. + goto read_error;
  156. +
  157. + /* Fvco = Fref * (NI + NF) / M / Q1 */
  158. + freq = parent_rate / STARFIVE_PLL_FRAC_PATR_SIZE *
  159. + (fbdiv * STARFIVE_PLL_FRAC_PATR_SIZE + frac_cal) / prediv / postdiv1;
  160. +
  161. +read_error:
  162. + return freq;
  163. +}
  164. +
  165. +static unsigned long jh7110_pll_rate_sub_fabs(unsigned long rate1, unsigned long rate2)
  166. +{
  167. + return rate1 > rate2 ? (rate1 - rate2) : (rate2 - rate1);
  168. +}
  169. +
  170. +/* Select the appropriate frequency from the already configured registers value */
  171. +static void jh7110_pll_select_near_freq_id(struct jh7110_clk_pll_data *data,
  172. + unsigned long rate)
  173. +{
  174. + const struct starfive_pll_syscon_value *syscon_val;
  175. + unsigned int id;
  176. + unsigned int pll_arry_size;
  177. + unsigned long rate_diff;
  178. +
  179. + if (data->idx == JH7110_CLK_PLL0_OUT)
  180. + pll_arry_size = ARRAY_SIZE(jh7110_pll0_syscon_freq);
  181. + else if (data->idx == JH7110_CLK_PLL1_OUT)
  182. + pll_arry_size = ARRAY_SIZE(jh7110_pll1_syscon_freq);
  183. + else
  184. + pll_arry_size = ARRAY_SIZE(jh7110_pll2_syscon_freq);
  185. +
  186. + /* compare the frequency one by one from small to large in order */
  187. + for (id = 0; id < pll_arry_size; id++) {
  188. + if (data->idx == JH7110_CLK_PLL0_OUT)
  189. + syscon_val = &jh7110_pll0_syscon_freq[id];
  190. + else if (data->idx == JH7110_CLK_PLL1_OUT)
  191. + syscon_val = &jh7110_pll1_syscon_freq[id];
  192. + else
  193. + syscon_val = &jh7110_pll2_syscon_freq[id];
  194. +
  195. + if (rate == syscon_val->freq)
  196. + goto match_end;
  197. +
  198. + /* select near frequency */
  199. + if (rate < syscon_val->freq) {
  200. + /* The last frequency is closer to the target rate than this time. */
  201. + if (id > 0)
  202. + if (rate_diff < jh7110_pll_rate_sub_fabs(rate, syscon_val->freq))
  203. + id--;
  204. +
  205. + goto match_end;
  206. + } else {
  207. + rate_diff = jh7110_pll_rate_sub_fabs(rate, syscon_val->freq);
  208. + }
  209. + }
  210. +
  211. +match_end:
  212. + data->freq_select_idx = id;
  213. +}
  214. +
  215. +static int jh7110_pll_set_freq_syscon(struct jh7110_clk_pll_data *data)
  216. +{
  217. + struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
  218. + struct jh7110_pll_syscon_offset *offset = &data->offset;
  219. + struct jh7110_pll_syscon_mask *mask = &data->mask;
  220. + struct jh7110_pll_syscon_shift *shift = &data->shift;
  221. + unsigned int freq_idx = data->freq_select_idx;
  222. + const struct starfive_pll_syscon_value *syscon_val;
  223. + int ret;
  224. +
  225. + if (data->idx == JH7110_CLK_PLL0_OUT)
  226. + syscon_val = &jh7110_pll0_syscon_freq[freq_idx];
  227. + else if (data->idx == JH7110_CLK_PLL1_OUT)
  228. + syscon_val = &jh7110_pll1_syscon_freq[freq_idx];
  229. + else
  230. + syscon_val = &jh7110_pll2_syscon_freq[freq_idx];
  231. +
  232. + ret = regmap_update_bits(priv->syscon_regmap, offset->dacpd, mask->dacpd,
  233. + (syscon_val->dacpd << shift->dacpd));
  234. + if (ret)
  235. + goto set_failed;
  236. +
  237. + ret = regmap_update_bits(priv->syscon_regmap, offset->dsmpd, mask->dsmpd,
  238. + (syscon_val->dsmpd << shift->dsmpd));
  239. + if (ret)
  240. + goto set_failed;
  241. +
  242. + ret = regmap_update_bits(priv->syscon_regmap, offset->prediv, mask->prediv,
  243. + (syscon_val->prediv << shift->prediv));
  244. + if (ret)
  245. + goto set_failed;
  246. +
  247. + ret = regmap_update_bits(priv->syscon_regmap, offset->fbdiv, mask->fbdiv,
  248. + (syscon_val->fbdiv << shift->fbdiv));
  249. + if (ret)
  250. + goto set_failed;
  251. +
  252. + ret = regmap_update_bits(priv->syscon_regmap, offset->postdiv1, mask->postdiv1,
  253. + ((syscon_val->postdiv1 >> 1) << shift->postdiv1));
  254. + if (ret)
  255. + goto set_failed;
  256. +
  257. + /* frac: Integer Mode (Both 1) or Fraction Mode (Both 0) */
  258. + if (syscon_val->dacpd == 0 && syscon_val->dsmpd == 0)
  259. + ret = regmap_update_bits(priv->syscon_regmap, offset->frac, mask->frac,
  260. + (syscon_val->frac << shift->frac));
  261. + else if (syscon_val->dacpd != syscon_val->dsmpd)
  262. + ret = -EINVAL;
  263. +
  264. +set_failed:
  265. + return ret;
  266. +}
  267. +
  268. +static unsigned long jh7110_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
  269. +{
  270. + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
  271. +
  272. + return jh7110_pll_get_freq(data, parent_rate);
  273. +}
  274. +
  275. +static int jh7110_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
  276. +{
  277. + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
  278. +
  279. + jh7110_pll_select_near_freq_id(data, req->rate);
  280. +
  281. + if (data->idx == JH7110_CLK_PLL0_OUT)
  282. + req->rate = jh7110_pll0_syscon_freq[data->freq_select_idx].freq;
  283. + else if (data->idx == JH7110_CLK_PLL1_OUT)
  284. + req->rate = jh7110_pll1_syscon_freq[data->freq_select_idx].freq;
  285. + else
  286. + req->rate = jh7110_pll2_syscon_freq[data->freq_select_idx].freq;
  287. +
  288. + return 0;
  289. +}
  290. +
  291. +static int jh7110_pll_set_rate(struct clk_hw *hw, unsigned long rate,
  292. + unsigned long parent_rate)
  293. +{
  294. + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
  295. +
  296. + return jh7110_pll_set_freq_syscon(data);
  297. +}
  298. +
  299. +#ifdef CONFIG_DEBUG_FS
  300. +static void jh7110_pll_debug_init(struct clk_hw *hw, struct dentry *dentry)
  301. +{
  302. + static const struct debugfs_reg32 jh7110_clk_pll_reg = {
  303. + .name = "CTRL",
  304. + .offset = 0,
  305. + };
  306. + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
  307. + struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
  308. + struct debugfs_regset32 *regset;
  309. +
  310. + regset = devm_kzalloc(priv->dev, sizeof(*regset), GFP_KERNEL);
  311. + if (!regset)
  312. + return;
  313. +
  314. + regset->regs = &jh7110_clk_pll_reg;
  315. + regset->nregs = 1;
  316. +
  317. + debugfs_create_regset32("registers", 0400, dentry, regset);
  318. +}
  319. +#else
  320. +#define jh7110_pll_debug_init NULL
  321. +#endif
  322. +
  323. +static const struct clk_ops jh7110_pll_ops = {
  324. + .recalc_rate = jh7110_pll_recalc_rate,
  325. + .determine_rate = jh7110_pll_determine_rate,
  326. + .set_rate = jh7110_pll_set_rate,
  327. + .debug_init = jh7110_pll_debug_init,
  328. +};
  329. +
  330. +/* get offset, mask and shift of PLL(x) syscon */
  331. +static int jh7110_pll_data_get(struct jh7110_clk_pll_data *data, int index)
  332. +{
  333. + struct jh7110_pll_syscon_offset *offset = &data->offset;
  334. + struct jh7110_pll_syscon_mask *mask = &data->mask;
  335. + struct jh7110_pll_syscon_shift *shift = &data->shift;
  336. +
  337. + if (index == JH7110_CLK_PLL0_OUT) {
  338. + offset->dacpd = STARFIVE_JH7110_PLL0_DACPD_OFFSET;
  339. + offset->dsmpd = STARFIVE_JH7110_PLL0_DSMPD_OFFSET;
  340. + offset->fbdiv = STARFIVE_JH7110_PLL0_FBDIV_OFFSET;
  341. + offset->frac = STARFIVE_JH7110_PLL0_FRAC_OFFSET;
  342. + offset->prediv = STARFIVE_JH7110_PLL0_PREDIV_OFFSET;
  343. + offset->postdiv1 = STARFIVE_JH7110_PLL0_POSTDIV1_OFFSET;
  344. +
  345. + mask->dacpd = STARFIVE_JH7110_PLL0_DACPD_MASK;
  346. + mask->dsmpd = STARFIVE_JH7110_PLL0_DSMPD_MASK;
  347. + mask->fbdiv = STARFIVE_JH7110_PLL0_FBDIV_MASK;
  348. + mask->frac = STARFIVE_JH7110_PLL0_FRAC_MASK;
  349. + mask->prediv = STARFIVE_JH7110_PLL0_PREDIV_MASK;
  350. + mask->postdiv1 = STARFIVE_JH7110_PLL0_POSTDIV1_MASK;
  351. +
  352. + shift->dacpd = STARFIVE_JH7110_PLL0_DACPD_SHIFT;
  353. + shift->dsmpd = STARFIVE_JH7110_PLL0_DSMPD_SHIFT;
  354. + shift->fbdiv = STARFIVE_JH7110_PLL0_FBDIV_SHIFT;
  355. + shift->frac = STARFIVE_JH7110_PLL0_FRAC_SHIFT;
  356. + shift->prediv = STARFIVE_JH7110_PLL0_PREDIV_SHIFT;
  357. + shift->postdiv1 = STARFIVE_JH7110_PLL0_POSTDIV1_SHIFT;
  358. +
  359. + } else if (index == JH7110_CLK_PLL1_OUT) {
  360. + offset->dacpd = STARFIVE_JH7110_PLL1_DACPD_OFFSET;
  361. + offset->dsmpd = STARFIVE_JH7110_PLL1_DSMPD_OFFSET;
  362. + offset->fbdiv = STARFIVE_JH7110_PLL1_FBDIV_OFFSET;
  363. + offset->frac = STARFIVE_JH7110_PLL1_FRAC_OFFSET;
  364. + offset->prediv = STARFIVE_JH7110_PLL1_PREDIV_OFFSET;
  365. + offset->postdiv1 = STARFIVE_JH7110_PLL1_POSTDIV1_OFFSET;
  366. +
  367. + mask->dacpd = STARFIVE_JH7110_PLL1_DACPD_MASK;
  368. + mask->dsmpd = STARFIVE_JH7110_PLL1_DSMPD_MASK;
  369. + mask->fbdiv = STARFIVE_JH7110_PLL1_FBDIV_MASK;
  370. + mask->frac = STARFIVE_JH7110_PLL1_FRAC_MASK;
  371. + mask->prediv = STARFIVE_JH7110_PLL1_PREDIV_MASK;
  372. + mask->postdiv1 = STARFIVE_JH7110_PLL1_POSTDIV1_MASK;
  373. +
  374. + shift->dacpd = STARFIVE_JH7110_PLL1_DACPD_SHIFT;
  375. + shift->dsmpd = STARFIVE_JH7110_PLL1_DSMPD_SHIFT;
  376. + shift->fbdiv = STARFIVE_JH7110_PLL1_FBDIV_SHIFT;
  377. + shift->frac = STARFIVE_JH7110_PLL1_FRAC_SHIFT;
  378. + shift->prediv = STARFIVE_JH7110_PLL1_PREDIV_SHIFT;
  379. + shift->postdiv1 = STARFIVE_JH7110_PLL1_POSTDIV1_SHIFT;
  380. +
  381. + } else if (index == JH7110_CLK_PLL2_OUT) {
  382. + offset->dacpd = STARFIVE_JH7110_PLL2_DACPD_OFFSET;
  383. + offset->dsmpd = STARFIVE_JH7110_PLL2_DSMPD_OFFSET;
  384. + offset->fbdiv = STARFIVE_JH7110_PLL2_FBDIV_OFFSET;
  385. + offset->frac = STARFIVE_JH7110_PLL2_FRAC_OFFSET;
  386. + offset->prediv = STARFIVE_JH7110_PLL2_PREDIV_OFFSET;
  387. + offset->postdiv1 = STARFIVE_JH7110_PLL2_POSTDIV1_OFFSET;
  388. +
  389. + mask->dacpd = STARFIVE_JH7110_PLL2_DACPD_MASK;
  390. + mask->dsmpd = STARFIVE_JH7110_PLL2_DSMPD_MASK;
  391. + mask->fbdiv = STARFIVE_JH7110_PLL2_FBDIV_MASK;
  392. + mask->frac = STARFIVE_JH7110_PLL2_FRAC_MASK;
  393. + mask->prediv = STARFIVE_JH7110_PLL2_PREDIV_MASK;
  394. + mask->postdiv1 = STARFIVE_JH7110_PLL2_POSTDIV1_MASK;
  395. +
  396. + shift->dacpd = STARFIVE_JH7110_PLL2_DACPD_SHIFT;
  397. + shift->dsmpd = STARFIVE_JH7110_PLL2_DSMPD_SHIFT;
  398. + shift->fbdiv = STARFIVE_JH7110_PLL2_FBDIV_SHIFT;
  399. + shift->frac = STARFIVE_JH7110_PLL2_FRAC_SHIFT;
  400. + shift->prediv = STARFIVE_JH7110_PLL2_PREDIV_SHIFT;
  401. + shift->postdiv1 = STARFIVE_JH7110_PLL2_POSTDIV1_SHIFT;
  402. +
  403. + } else {
  404. + return -ENOENT;
  405. + }
  406. +
  407. + return 0;
  408. +}
  409. +
  410. +static struct clk_hw *jh7110_pll_get(struct of_phandle_args *clkspec, void *data)
  411. +{
  412. + struct jh7110_clk_pll_priv *priv = data;
  413. + unsigned int idx = clkspec->args[0];
  414. +
  415. + if (idx < JH7110_PLLCLK_END)
  416. + return &priv->data[idx].hw;
  417. +
  418. + return ERR_PTR(-EINVAL);
  419. +}
  420. +
  421. +static int jh7110_pll_probe(struct platform_device *pdev)
  422. +{
  423. + const char *pll_name[JH7110_PLLCLK_END] = {
  424. + "pll0_out",
  425. + "pll1_out",
  426. + "pll2_out"
  427. + };
  428. + struct jh7110_clk_pll_priv *priv;
  429. + struct jh7110_clk_pll_data *data;
  430. + int ret;
  431. + unsigned int idx;
  432. +
  433. + priv = devm_kzalloc(&pdev->dev, struct_size(priv, data, JH7110_PLLCLK_END),
  434. + GFP_KERNEL);
  435. + if (!priv)
  436. + return -ENOMEM;
  437. +
  438. + priv->dev = &pdev->dev;
  439. + priv->syscon_regmap = syscon_node_to_regmap(priv->dev->of_node->parent);
  440. + if (IS_ERR(priv->syscon_regmap))
  441. + return PTR_ERR(priv->syscon_regmap);
  442. +
  443. + for (idx = 0; idx < JH7110_PLLCLK_END; idx++) {
  444. + struct clk_parent_data parents = {
  445. + .index = 0,
  446. + };
  447. + struct clk_init_data init = {
  448. + .name = pll_name[idx],
  449. + .ops = &jh7110_pll_ops,
  450. + .parent_data = &parents,
  451. + .num_parents = 1,
  452. + .flags = 0,
  453. + };
  454. +
  455. + data = &priv->data[idx];
  456. +
  457. + ret = jh7110_pll_data_get(data, idx);
  458. + if (ret)
  459. + return ret;
  460. +
  461. + data->hw.init = &init;
  462. + data->idx = idx;
  463. +
  464. + ret = devm_clk_hw_register(&pdev->dev, &data->hw);
  465. + if (ret)
  466. + return ret;
  467. + }
  468. +
  469. + return devm_of_clk_add_hw_provider(&pdev->dev, jh7110_pll_get, priv);
  470. +}
  471. +
  472. +static const struct of_device_id jh7110_pll_match[] = {
  473. + { .compatible = "starfive,jh7110-pll" },
  474. + { /* sentinel */ }
  475. +};
  476. +MODULE_DEVICE_TABLE(of, jh7110_pll_match);
  477. +
  478. +static struct platform_driver jh7110_pll_driver = {
  479. + .driver = {
  480. + .name = "clk-starfive-jh7110-pll",
  481. + .of_match_table = jh7110_pll_match,
  482. + },
  483. +};
  484. +builtin_platform_driver_probe(jh7110_pll_driver, jh7110_pll_probe);
  485. --- /dev/null
  486. +++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.h
  487. @@ -0,0 +1,293 @@
  488. +/* SPDX-License-Identifier: GPL-2.0 OR MIT */
  489. +/*
  490. + * StarFive JH7110 PLL Clock Generator Driver
  491. + *
  492. + * Copyright (C) 2023 StarFive Technology Co., Ltd.
  493. + */
  494. +
  495. +#ifndef _CLK_STARFIVE_JH7110_PLL_H_
  496. +#define _CLK_STARFIVE_JH7110_PLL_H_
  497. +
  498. +#include <linux/bits.h>
  499. +
  500. +/* The decimal places are counted by expanding them by a factor of STARFIVE_PLL_FRAC_PATR_SIZE */
  501. +#define STARFIVE_PLL_FRAC_PATR_SIZE 1000
  502. +
  503. +#define STARFIVE_JH7110_PLL0_DACPD_OFFSET 0x18
  504. +#define STARFIVE_JH7110_PLL0_DACPD_SHIFT 24
  505. +#define STARFIVE_JH7110_PLL0_DACPD_MASK BIT(24)
  506. +#define STARFIVE_JH7110_PLL0_DSMPD_OFFSET 0x18
  507. +#define STARFIVE_JH7110_PLL0_DSMPD_SHIFT 25
  508. +#define STARFIVE_JH7110_PLL0_DSMPD_MASK BIT(25)
  509. +#define STARFIVE_JH7110_PLL0_FBDIV_OFFSET 0x1c
  510. +#define STARFIVE_JH7110_PLL0_FBDIV_SHIFT 0
  511. +#define STARFIVE_JH7110_PLL0_FBDIV_MASK GENMASK(11, 0)
  512. +#define STARFIVE_JH7110_PLL0_FRAC_OFFSET 0x20
  513. +#define STARFIVE_JH7110_PLL0_FRAC_SHIFT 0
  514. +#define STARFIVE_JH7110_PLL0_FRAC_MASK GENMASK(23, 0)
  515. +#define STARFIVE_JH7110_PLL0_POSTDIV1_OFFSET 0x20
  516. +#define STARFIVE_JH7110_PLL0_POSTDIV1_SHIFT 28
  517. +#define STARFIVE_JH7110_PLL0_POSTDIV1_MASK GENMASK(29, 28)
  518. +#define STARFIVE_JH7110_PLL0_PREDIV_OFFSET 0x24
  519. +#define STARFIVE_JH7110_PLL0_PREDIV_SHIFT 0
  520. +#define STARFIVE_JH7110_PLL0_PREDIV_MASK GENMASK(5, 0)
  521. +
  522. +#define STARFIVE_JH7110_PLL1_DACPD_OFFSET 0x24
  523. +#define STARFIVE_JH7110_PLL1_DACPD_SHIFT 15
  524. +#define STARFIVE_JH7110_PLL1_DACPD_MASK BIT(15)
  525. +#define STARFIVE_JH7110_PLL1_DSMPD_OFFSET 0x24
  526. +#define STARFIVE_JH7110_PLL1_DSMPD_SHIFT 16
  527. +#define STARFIVE_JH7110_PLL1_DSMPD_MASK BIT(16)
  528. +#define STARFIVE_JH7110_PLL1_FBDIV_OFFSET 0x24
  529. +#define STARFIVE_JH7110_PLL1_FBDIV_SHIFT 17
  530. +#define STARFIVE_JH7110_PLL1_FBDIV_MASK GENMASK(28, 17)
  531. +#define STARFIVE_JH7110_PLL1_FRAC_OFFSET 0x28
  532. +#define STARFIVE_JH7110_PLL1_FRAC_SHIFT 0
  533. +#define STARFIVE_JH7110_PLL1_FRAC_MASK GENMASK(23, 0)
  534. +#define STARFIVE_JH7110_PLL1_POSTDIV1_OFFSET 0x28
  535. +#define STARFIVE_JH7110_PLL1_POSTDIV1_SHIFT 28
  536. +#define STARFIVE_JH7110_PLL1_POSTDIV1_MASK GENMASK(29, 28)
  537. +#define STARFIVE_JH7110_PLL1_PREDIV_OFFSET 0x2c
  538. +#define STARFIVE_JH7110_PLL1_PREDIV_SHIFT 0
  539. +#define STARFIVE_JH7110_PLL1_PREDIV_MASK GENMASK(5, 0)
  540. +
  541. +#define STARFIVE_JH7110_PLL2_DACPD_OFFSET 0x2c
  542. +#define STARFIVE_JH7110_PLL2_DACPD_SHIFT 15
  543. +#define STARFIVE_JH7110_PLL2_DACPD_MASK BIT(15)
  544. +#define STARFIVE_JH7110_PLL2_DSMPD_OFFSET 0x2c
  545. +#define STARFIVE_JH7110_PLL2_DSMPD_SHIFT 16
  546. +#define STARFIVE_JH7110_PLL2_DSMPD_MASK BIT(16)
  547. +#define STARFIVE_JH7110_PLL2_FBDIV_OFFSET 0x2c
  548. +#define STARFIVE_JH7110_PLL2_FBDIV_SHIFT 17
  549. +#define STARFIVE_JH7110_PLL2_FBDIV_MASK GENMASK(28, 17)
  550. +#define STARFIVE_JH7110_PLL2_FRAC_OFFSET 0x30
  551. +#define STARFIVE_JH7110_PLL2_FRAC_SHIFT 0
  552. +#define STARFIVE_JH7110_PLL2_FRAC_MASK GENMASK(23, 0)
  553. +#define STARFIVE_JH7110_PLL2_POSTDIV1_OFFSET 0x30
  554. +#define STARFIVE_JH7110_PLL2_POSTDIV1_SHIFT 28
  555. +#define STARFIVE_JH7110_PLL2_POSTDIV1_MASK GENMASK(29, 28)
  556. +#define STARFIVE_JH7110_PLL2_PREDIV_OFFSET 0x34
  557. +#define STARFIVE_JH7110_PLL2_PREDIV_SHIFT 0
  558. +#define STARFIVE_JH7110_PLL2_PREDIV_MASK GENMASK(5, 0)
  559. +
  560. +struct jh7110_pll_syscon_offset {
  561. + unsigned int dacpd;
  562. + unsigned int dsmpd;
  563. + unsigned int fbdiv;
  564. + unsigned int frac;
  565. + unsigned int prediv;
  566. + unsigned int postdiv1;
  567. +};
  568. +
  569. +struct jh7110_pll_syscon_mask {
  570. + u32 dacpd;
  571. + u32 dsmpd;
  572. + u32 fbdiv;
  573. + u32 frac;
  574. + u32 prediv;
  575. + u32 postdiv1;
  576. +};
  577. +
  578. +struct jh7110_pll_syscon_shift {
  579. + char dacpd;
  580. + char dsmpd;
  581. + char fbdiv;
  582. + char frac;
  583. + char prediv;
  584. + char postdiv1;
  585. +};
  586. +
  587. +struct jh7110_clk_pll_data {
  588. + struct clk_hw hw;
  589. + unsigned int idx;
  590. + unsigned int freq_select_idx;
  591. +
  592. + struct jh7110_pll_syscon_offset offset;
  593. + struct jh7110_pll_syscon_mask mask;
  594. + struct jh7110_pll_syscon_shift shift;
  595. +};
  596. +
  597. +struct jh7110_clk_pll_priv {
  598. + struct device *dev;
  599. + struct regmap *syscon_regmap;
  600. + struct jh7110_clk_pll_data data[];
  601. +};
  602. +
  603. +struct starfive_pll_syscon_value {
  604. + unsigned long freq;
  605. + u32 prediv;
  606. + u32 fbdiv;
  607. + u32 postdiv1;
  608. +/* Both daxpd and dsmpd set 1 while integer mode */
  609. +/* Both daxpd and dsmpd set 0 while fraction mode */
  610. + u32 dacpd;
  611. + u32 dsmpd;
  612. +/* frac value should be decimals multiplied by 2^24 */
  613. + u32 frac;
  614. +};
  615. +
  616. +enum starfive_pll0_freq_index {
  617. + PLL0_FREQ_375 = 0,
  618. + PLL0_FREQ_500,
  619. + PLL0_FREQ_625,
  620. + PLL0_FREQ_750,
  621. + PLL0_FREQ_875,
  622. + PLL0_FREQ_1000,
  623. + PLL0_FREQ_1250,
  624. + PLL0_FREQ_1375,
  625. + PLL0_FREQ_1500,
  626. + PLL0_FREQ_MAX
  627. +};
  628. +
  629. +enum starfive_pll1_freq_index {
  630. + PLL1_FREQ_1066 = 0,
  631. + PLL1_FREQ_1200,
  632. + PLL1_FREQ_1400,
  633. + PLL1_FREQ_1600,
  634. + PLL1_FREQ_MAX
  635. +};
  636. +
  637. +enum starfive_pll2_freq_index {
  638. + PLL2_FREQ_1188 = 0,
  639. + PLL2_FREQ_12288,
  640. + PLL2_FREQ_MAX
  641. +};
  642. +
  643. +/*
  644. + * Because the pll frequency is relatively fixed,
  645. + * it cannot be set arbitrarily, so it needs a specific configuration.
  646. + * PLL0 frequency should be multiple of 125MHz (USB frequency).
  647. + */
  648. +static const struct starfive_pll_syscon_value
  649. + jh7110_pll0_syscon_freq[PLL0_FREQ_MAX] = {
  650. + [PLL0_FREQ_375] = {
  651. + .freq = 375000000,
  652. + .prediv = 8,
  653. + .fbdiv = 125,
  654. + .postdiv1 = 1,
  655. + .dacpd = 1,
  656. + .dsmpd = 1,
  657. + },
  658. + [PLL0_FREQ_500] = {
  659. + .freq = 500000000,
  660. + .prediv = 6,
  661. + .fbdiv = 125,
  662. + .postdiv1 = 1,
  663. + .dacpd = 1,
  664. + .dsmpd = 1,
  665. + },
  666. + [PLL0_FREQ_625] = {
  667. + .freq = 625000000,
  668. + .prediv = 24,
  669. + .fbdiv = 625,
  670. + .postdiv1 = 1,
  671. + .dacpd = 1,
  672. + .dsmpd = 1,
  673. + },
  674. + [PLL0_FREQ_750] = {
  675. + .freq = 750000000,
  676. + .prediv = 4,
  677. + .fbdiv = 125,
  678. + .postdiv1 = 1,
  679. + .dacpd = 1,
  680. + .dsmpd = 1,
  681. + },
  682. + [PLL0_FREQ_875] = {
  683. + .freq = 875000000,
  684. + .prediv = 24,
  685. + .fbdiv = 875,
  686. + .postdiv1 = 1,
  687. + .dacpd = 1,
  688. + .dsmpd = 1,
  689. + },
  690. + [PLL0_FREQ_1000] = {
  691. + .freq = 1000000000,
  692. + .prediv = 3,
  693. + .fbdiv = 125,
  694. + .postdiv1 = 1,
  695. + .dacpd = 1,
  696. + .dsmpd = 1,
  697. + },
  698. + [PLL0_FREQ_1250] = {
  699. + .freq = 1250000000,
  700. + .prediv = 12,
  701. + .fbdiv = 625,
  702. + .postdiv1 = 1,
  703. + .dacpd = 1,
  704. + .dsmpd = 1,
  705. + },
  706. + [PLL0_FREQ_1375] = {
  707. + .freq = 1375000000,
  708. + .prediv = 24,
  709. + .fbdiv = 1375,
  710. + .postdiv1 = 1,
  711. + .dacpd = 1,
  712. + .dsmpd = 1,
  713. + },
  714. + [PLL0_FREQ_1500] = {
  715. + .freq = 1500000000,
  716. + .prediv = 2,
  717. + .fbdiv = 125,
  718. + .postdiv1 = 1,
  719. + .dacpd = 1,
  720. + .dsmpd = 1,
  721. + },
  722. +};
  723. +
  724. +static const struct starfive_pll_syscon_value
  725. + jh7110_pll1_syscon_freq[PLL1_FREQ_MAX] = {
  726. + [PLL1_FREQ_1066] = {
  727. + .freq = 1066000000,
  728. + .prediv = 12,
  729. + .fbdiv = 533,
  730. + .postdiv1 = 1,
  731. + .dacpd = 1,
  732. + .dsmpd = 1,
  733. + },
  734. + [PLL1_FREQ_1200] = {
  735. + .freq = 1200000000,
  736. + .prediv = 1,
  737. + .fbdiv = 50,
  738. + .postdiv1 = 1,
  739. + .dacpd = 1,
  740. + .dsmpd = 1,
  741. + },
  742. + [PLL1_FREQ_1400] = {
  743. + .freq = 1400000000,
  744. + .prediv = 6,
  745. + .fbdiv = 350,
  746. + .postdiv1 = 1,
  747. + .dacpd = 1,
  748. + .dsmpd = 1,
  749. + },
  750. + [PLL1_FREQ_1600] = {
  751. + .freq = 1600000000,
  752. + .prediv = 3,
  753. + .fbdiv = 200,
  754. + .postdiv1 = 1,
  755. + .dacpd = 1,
  756. + .dsmpd = 1,
  757. + },
  758. +};
  759. +
  760. +static const struct starfive_pll_syscon_value
  761. + jh7110_pll2_syscon_freq[PLL2_FREQ_MAX] = {
  762. + [PLL2_FREQ_1188] = {
  763. + .freq = 1188000000,
  764. + .prediv = 2,
  765. + .fbdiv = 99,
  766. + .postdiv1 = 1,
  767. + .dacpd = 1,
  768. + .dsmpd = 1,
  769. + },
  770. + [PLL2_FREQ_12288] = {
  771. + .freq = 1228800000,
  772. + .prediv = 5,
  773. + .fbdiv = 256,
  774. + .postdiv1 = 1,
  775. + .dacpd = 1,
  776. + .dsmpd = 1,
  777. + },
  778. +};
  779. +
  780. +#endif