0004-clk-starfive-Factor-out-common-JH7100-and-JH7110-cod.patch 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. From 6f14eb919e5b92076e17aec5388655348963eef7 Mon Sep 17 00:00:00 2001
  2. From: Emil Renner Berthing <[email protected]>
  3. Date: Sat, 1 Apr 2023 19:19:16 +0800
  4. Subject: [PATCH 004/122] clk: starfive: Factor out common JH7100 and JH7110
  5. code
  6. The clock control registers on the StarFive JH7100 and JH7110 work
  7. identically, so factor out the code then drivers for the two SoCs
  8. can share it without depending on each other. No functional change.
  9. Tested-by: Tommaso Merciai <[email protected]>
  10. Reviewed-by: Conor Dooley <[email protected]>
  11. Reviewed-by: Emil Renner Berthing <[email protected]>
  12. Signed-off-by: Emil Renner Berthing <[email protected]>
  13. Signed-off-by: Hal Feng <[email protected]>
  14. Signed-off-by: Conor Dooley <[email protected]>
  15. ---
  16. drivers/clk/starfive/Kconfig | 5 +
  17. drivers/clk/starfive/Makefile | 3 +-
  18. drivers/clk/starfive/clk-starfive-jh7100.c | 325 --------------------
  19. drivers/clk/starfive/clk-starfive-jh7100.h | 2 +
  20. drivers/clk/starfive/clk-starfive-jh71x0.c | 333 +++++++++++++++++++++
  21. 5 files changed, 342 insertions(+), 326 deletions(-)
  22. create mode 100644 drivers/clk/starfive/clk-starfive-jh71x0.c
  23. --- a/drivers/clk/starfive/Kconfig
  24. +++ b/drivers/clk/starfive/Kconfig
  25. @@ -1,8 +1,12 @@
  26. # SPDX-License-Identifier: GPL-2.0
  27. +config CLK_STARFIVE_JH71X0
  28. + bool
  29. +
  30. config CLK_STARFIVE_JH7100
  31. bool "StarFive JH7100 clock support"
  32. depends on ARCH_STARFIVE || COMPILE_TEST
  33. + select CLK_STARFIVE_JH71X0
  34. default ARCH_STARFIVE
  35. help
  36. Say yes here to support the clock controller on the StarFive JH7100
  37. @@ -11,6 +15,7 @@ config CLK_STARFIVE_JH7100
  38. config CLK_STARFIVE_JH7100_AUDIO
  39. tristate "StarFive JH7100 audio clock support"
  40. depends on CLK_STARFIVE_JH7100
  41. + select CLK_STARFIVE_JH71X0
  42. default m if ARCH_STARFIVE
  43. help
  44. Say Y or M here to support the audio clocks on the StarFive JH7100
  45. --- a/drivers/clk/starfive/Makefile
  46. +++ b/drivers/clk/starfive/Makefile
  47. @@ -1,4 +1,5 @@
  48. # SPDX-License-Identifier: GPL-2.0
  49. -# StarFive Clock
  50. +obj-$(CONFIG_CLK_STARFIVE_JH71X0) += clk-starfive-jh71x0.o
  51. +
  52. obj-$(CONFIG_CLK_STARFIVE_JH7100) += clk-starfive-jh7100.o
  53. obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o
  54. --- a/drivers/clk/starfive/clk-starfive-jh7100.c
  55. +++ b/drivers/clk/starfive/clk-starfive-jh7100.c
  56. @@ -7,15 +7,10 @@
  57. * Copyright (C) 2021 Emil Renner Berthing <[email protected]>
  58. */
  59. -#include <linux/bits.h>
  60. #include <linux/clk-provider.h>
  61. -#include <linux/debugfs.h>
  62. #include <linux/device.h>
  63. #include <linux/init.h>
  64. -#include <linux/io.h>
  65. -#include <linux/kernel.h>
  66. #include <linux/mod_devicetable.h>
  67. -#include <linux/module.h>
  68. #include <linux/platform_device.h>
  69. #include <dt-bindings/clock/starfive-jh7100.h>
  70. @@ -269,326 +264,6 @@ static const struct jh7100_clk_data jh71
  71. JH7100_GATE(JH7100_CLK_SYSERR_APB, "syserr_apb", 0, JH7100_CLK_APB2_BUS),
  72. };
  73. -static struct jh7100_clk *jh7100_clk_from(struct clk_hw *hw)
  74. -{
  75. - return container_of(hw, struct jh7100_clk, hw);
  76. -}
  77. -
  78. -static struct jh7100_clk_priv *jh7100_priv_from(struct jh7100_clk *clk)
  79. -{
  80. - return container_of(clk, struct jh7100_clk_priv, reg[clk->idx]);
  81. -}
  82. -
  83. -static u32 jh7100_clk_reg_get(struct jh7100_clk *clk)
  84. -{
  85. - struct jh7100_clk_priv *priv = jh7100_priv_from(clk);
  86. - void __iomem *reg = priv->base + 4 * clk->idx;
  87. -
  88. - return readl_relaxed(reg);
  89. -}
  90. -
  91. -static void jh7100_clk_reg_rmw(struct jh7100_clk *clk, u32 mask, u32 value)
  92. -{
  93. - struct jh7100_clk_priv *priv = jh7100_priv_from(clk);
  94. - void __iomem *reg = priv->base + 4 * clk->idx;
  95. - unsigned long flags;
  96. -
  97. - spin_lock_irqsave(&priv->rmw_lock, flags);
  98. - value |= readl_relaxed(reg) & ~mask;
  99. - writel_relaxed(value, reg);
  100. - spin_unlock_irqrestore(&priv->rmw_lock, flags);
  101. -}
  102. -
  103. -static int jh7100_clk_enable(struct clk_hw *hw)
  104. -{
  105. - struct jh7100_clk *clk = jh7100_clk_from(hw);
  106. -
  107. - jh7100_clk_reg_rmw(clk, JH7100_CLK_ENABLE, JH7100_CLK_ENABLE);
  108. - return 0;
  109. -}
  110. -
  111. -static void jh7100_clk_disable(struct clk_hw *hw)
  112. -{
  113. - struct jh7100_clk *clk = jh7100_clk_from(hw);
  114. -
  115. - jh7100_clk_reg_rmw(clk, JH7100_CLK_ENABLE, 0);
  116. -}
  117. -
  118. -static int jh7100_clk_is_enabled(struct clk_hw *hw)
  119. -{
  120. - struct jh7100_clk *clk = jh7100_clk_from(hw);
  121. -
  122. - return !!(jh7100_clk_reg_get(clk) & JH7100_CLK_ENABLE);
  123. -}
  124. -
  125. -static unsigned long jh7100_clk_recalc_rate(struct clk_hw *hw,
  126. - unsigned long parent_rate)
  127. -{
  128. - struct jh7100_clk *clk = jh7100_clk_from(hw);
  129. - u32 div = jh7100_clk_reg_get(clk) & JH7100_CLK_DIV_MASK;
  130. -
  131. - return div ? parent_rate / div : 0;
  132. -}
  133. -
  134. -static int jh7100_clk_determine_rate(struct clk_hw *hw,
  135. - struct clk_rate_request *req)
  136. -{
  137. - struct jh7100_clk *clk = jh7100_clk_from(hw);
  138. - unsigned long parent = req->best_parent_rate;
  139. - unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate);
  140. - unsigned long div = min_t(unsigned long, DIV_ROUND_UP(parent, rate), clk->max_div);
  141. - unsigned long result = parent / div;
  142. -
  143. - /*
  144. - * we want the result clamped by min_rate and max_rate if possible:
  145. - * case 1: div hits the max divider value, which means it's less than
  146. - * parent / rate, so the result is greater than rate and min_rate in
  147. - * particular. we can't do anything about result > max_rate because the
  148. - * divider doesn't go any further.
  149. - * case 2: div = DIV_ROUND_UP(parent, rate) which means the result is
  150. - * always lower or equal to rate and max_rate. however the result may
  151. - * turn out lower than min_rate, but then the next higher rate is fine:
  152. - * div - 1 = ceil(parent / rate) - 1 < parent / rate
  153. - * and thus
  154. - * min_rate <= rate < parent / (div - 1)
  155. - */
  156. - if (result < req->min_rate && div > 1)
  157. - result = parent / (div - 1);
  158. -
  159. - req->rate = result;
  160. - return 0;
  161. -}
  162. -
  163. -static int jh7100_clk_set_rate(struct clk_hw *hw,
  164. - unsigned long rate,
  165. - unsigned long parent_rate)
  166. -{
  167. - struct jh7100_clk *clk = jh7100_clk_from(hw);
  168. - unsigned long div = clamp(DIV_ROUND_CLOSEST(parent_rate, rate),
  169. - 1UL, (unsigned long)clk->max_div);
  170. -
  171. - jh7100_clk_reg_rmw(clk, JH7100_CLK_DIV_MASK, div);
  172. - return 0;
  173. -}
  174. -
  175. -static unsigned long jh7100_clk_frac_recalc_rate(struct clk_hw *hw,
  176. - unsigned long parent_rate)
  177. -{
  178. - struct jh7100_clk *clk = jh7100_clk_from(hw);
  179. - u32 reg = jh7100_clk_reg_get(clk);
  180. - unsigned long div100 = 100 * (reg & JH7100_CLK_INT_MASK) +
  181. - ((reg & JH7100_CLK_FRAC_MASK) >> JH7100_CLK_FRAC_SHIFT);
  182. -
  183. - return (div100 >= JH7100_CLK_FRAC_MIN) ? 100 * parent_rate / div100 : 0;
  184. -}
  185. -
  186. -static int jh7100_clk_frac_determine_rate(struct clk_hw *hw,
  187. - struct clk_rate_request *req)
  188. -{
  189. - unsigned long parent100 = 100 * req->best_parent_rate;
  190. - unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate);
  191. - unsigned long div100 = clamp(DIV_ROUND_CLOSEST(parent100, rate),
  192. - JH7100_CLK_FRAC_MIN, JH7100_CLK_FRAC_MAX);
  193. - unsigned long result = parent100 / div100;
  194. -
  195. - /* clamp the result as in jh7100_clk_determine_rate() above */
  196. - if (result > req->max_rate && div100 < JH7100_CLK_FRAC_MAX)
  197. - result = parent100 / (div100 + 1);
  198. - if (result < req->min_rate && div100 > JH7100_CLK_FRAC_MIN)
  199. - result = parent100 / (div100 - 1);
  200. -
  201. - req->rate = result;
  202. - return 0;
  203. -}
  204. -
  205. -static int jh7100_clk_frac_set_rate(struct clk_hw *hw,
  206. - unsigned long rate,
  207. - unsigned long parent_rate)
  208. -{
  209. - struct jh7100_clk *clk = jh7100_clk_from(hw);
  210. - unsigned long div100 = clamp(DIV_ROUND_CLOSEST(100 * parent_rate, rate),
  211. - JH7100_CLK_FRAC_MIN, JH7100_CLK_FRAC_MAX);
  212. - u32 value = ((div100 % 100) << JH7100_CLK_FRAC_SHIFT) | (div100 / 100);
  213. -
  214. - jh7100_clk_reg_rmw(clk, JH7100_CLK_DIV_MASK, value);
  215. - return 0;
  216. -}
  217. -
  218. -static u8 jh7100_clk_get_parent(struct clk_hw *hw)
  219. -{
  220. - struct jh7100_clk *clk = jh7100_clk_from(hw);
  221. - u32 value = jh7100_clk_reg_get(clk);
  222. -
  223. - return (value & JH7100_CLK_MUX_MASK) >> JH7100_CLK_MUX_SHIFT;
  224. -}
  225. -
  226. -static int jh7100_clk_set_parent(struct clk_hw *hw, u8 index)
  227. -{
  228. - struct jh7100_clk *clk = jh7100_clk_from(hw);
  229. - u32 value = (u32)index << JH7100_CLK_MUX_SHIFT;
  230. -
  231. - jh7100_clk_reg_rmw(clk, JH7100_CLK_MUX_MASK, value);
  232. - return 0;
  233. -}
  234. -
  235. -static int jh7100_clk_mux_determine_rate(struct clk_hw *hw,
  236. - struct clk_rate_request *req)
  237. -{
  238. - return clk_mux_determine_rate_flags(hw, req, 0);
  239. -}
  240. -
  241. -static int jh7100_clk_get_phase(struct clk_hw *hw)
  242. -{
  243. - struct jh7100_clk *clk = jh7100_clk_from(hw);
  244. - u32 value = jh7100_clk_reg_get(clk);
  245. -
  246. - return (value & JH7100_CLK_INVERT) ? 180 : 0;
  247. -}
  248. -
  249. -static int jh7100_clk_set_phase(struct clk_hw *hw, int degrees)
  250. -{
  251. - struct jh7100_clk *clk = jh7100_clk_from(hw);
  252. - u32 value;
  253. -
  254. - if (degrees == 0)
  255. - value = 0;
  256. - else if (degrees == 180)
  257. - value = JH7100_CLK_INVERT;
  258. - else
  259. - return -EINVAL;
  260. -
  261. - jh7100_clk_reg_rmw(clk, JH7100_CLK_INVERT, value);
  262. - return 0;
  263. -}
  264. -
  265. -#ifdef CONFIG_DEBUG_FS
  266. -static void jh7100_clk_debug_init(struct clk_hw *hw, struct dentry *dentry)
  267. -{
  268. - static const struct debugfs_reg32 jh7100_clk_reg = {
  269. - .name = "CTRL",
  270. - .offset = 0,
  271. - };
  272. - struct jh7100_clk *clk = jh7100_clk_from(hw);
  273. - struct jh7100_clk_priv *priv = jh7100_priv_from(clk);
  274. - struct debugfs_regset32 *regset;
  275. -
  276. - regset = devm_kzalloc(priv->dev, sizeof(*regset), GFP_KERNEL);
  277. - if (!regset)
  278. - return;
  279. -
  280. - regset->regs = &jh7100_clk_reg;
  281. - regset->nregs = 1;
  282. - regset->base = priv->base + 4 * clk->idx;
  283. -
  284. - debugfs_create_regset32("registers", 0400, dentry, regset);
  285. -}
  286. -#else
  287. -#define jh7100_clk_debug_init NULL
  288. -#endif
  289. -
  290. -static const struct clk_ops jh7100_clk_gate_ops = {
  291. - .enable = jh7100_clk_enable,
  292. - .disable = jh7100_clk_disable,
  293. - .is_enabled = jh7100_clk_is_enabled,
  294. - .debug_init = jh7100_clk_debug_init,
  295. -};
  296. -
  297. -static const struct clk_ops jh7100_clk_div_ops = {
  298. - .recalc_rate = jh7100_clk_recalc_rate,
  299. - .determine_rate = jh7100_clk_determine_rate,
  300. - .set_rate = jh7100_clk_set_rate,
  301. - .debug_init = jh7100_clk_debug_init,
  302. -};
  303. -
  304. -static const struct clk_ops jh7100_clk_fdiv_ops = {
  305. - .recalc_rate = jh7100_clk_frac_recalc_rate,
  306. - .determine_rate = jh7100_clk_frac_determine_rate,
  307. - .set_rate = jh7100_clk_frac_set_rate,
  308. - .debug_init = jh7100_clk_debug_init,
  309. -};
  310. -
  311. -static const struct clk_ops jh7100_clk_gdiv_ops = {
  312. - .enable = jh7100_clk_enable,
  313. - .disable = jh7100_clk_disable,
  314. - .is_enabled = jh7100_clk_is_enabled,
  315. - .recalc_rate = jh7100_clk_recalc_rate,
  316. - .determine_rate = jh7100_clk_determine_rate,
  317. - .set_rate = jh7100_clk_set_rate,
  318. - .debug_init = jh7100_clk_debug_init,
  319. -};
  320. -
  321. -static const struct clk_ops jh7100_clk_mux_ops = {
  322. - .determine_rate = jh7100_clk_mux_determine_rate,
  323. - .set_parent = jh7100_clk_set_parent,
  324. - .get_parent = jh7100_clk_get_parent,
  325. - .debug_init = jh7100_clk_debug_init,
  326. -};
  327. -
  328. -static const struct clk_ops jh7100_clk_gmux_ops = {
  329. - .enable = jh7100_clk_enable,
  330. - .disable = jh7100_clk_disable,
  331. - .is_enabled = jh7100_clk_is_enabled,
  332. - .determine_rate = jh7100_clk_mux_determine_rate,
  333. - .set_parent = jh7100_clk_set_parent,
  334. - .get_parent = jh7100_clk_get_parent,
  335. - .debug_init = jh7100_clk_debug_init,
  336. -};
  337. -
  338. -static const struct clk_ops jh7100_clk_mdiv_ops = {
  339. - .recalc_rate = jh7100_clk_recalc_rate,
  340. - .determine_rate = jh7100_clk_determine_rate,
  341. - .get_parent = jh7100_clk_get_parent,
  342. - .set_parent = jh7100_clk_set_parent,
  343. - .set_rate = jh7100_clk_set_rate,
  344. - .debug_init = jh7100_clk_debug_init,
  345. -};
  346. -
  347. -static const struct clk_ops jh7100_clk_gmd_ops = {
  348. - .enable = jh7100_clk_enable,
  349. - .disable = jh7100_clk_disable,
  350. - .is_enabled = jh7100_clk_is_enabled,
  351. - .recalc_rate = jh7100_clk_recalc_rate,
  352. - .determine_rate = jh7100_clk_determine_rate,
  353. - .get_parent = jh7100_clk_get_parent,
  354. - .set_parent = jh7100_clk_set_parent,
  355. - .set_rate = jh7100_clk_set_rate,
  356. - .debug_init = jh7100_clk_debug_init,
  357. -};
  358. -
  359. -static const struct clk_ops jh7100_clk_inv_ops = {
  360. - .get_phase = jh7100_clk_get_phase,
  361. - .set_phase = jh7100_clk_set_phase,
  362. - .debug_init = jh7100_clk_debug_init,
  363. -};
  364. -
  365. -const struct clk_ops *starfive_jh7100_clk_ops(u32 max)
  366. -{
  367. - if (max & JH7100_CLK_DIV_MASK) {
  368. - if (max & JH7100_CLK_MUX_MASK) {
  369. - if (max & JH7100_CLK_ENABLE)
  370. - return &jh7100_clk_gmd_ops;
  371. - return &jh7100_clk_mdiv_ops;
  372. - }
  373. - if (max & JH7100_CLK_ENABLE)
  374. - return &jh7100_clk_gdiv_ops;
  375. - if (max == JH7100_CLK_FRAC_MAX)
  376. - return &jh7100_clk_fdiv_ops;
  377. - return &jh7100_clk_div_ops;
  378. - }
  379. -
  380. - if (max & JH7100_CLK_MUX_MASK) {
  381. - if (max & JH7100_CLK_ENABLE)
  382. - return &jh7100_clk_gmux_ops;
  383. - return &jh7100_clk_mux_ops;
  384. - }
  385. -
  386. - if (max & JH7100_CLK_ENABLE)
  387. - return &jh7100_clk_gate_ops;
  388. -
  389. - return &jh7100_clk_inv_ops;
  390. -}
  391. -EXPORT_SYMBOL_GPL(starfive_jh7100_clk_ops);
  392. -
  393. static struct clk_hw *jh7100_clk_get(struct of_phandle_args *clkspec, void *data)
  394. {
  395. struct jh7100_clk_priv *priv = data;
  396. --- a/drivers/clk/starfive/clk-starfive-jh7100.h
  397. +++ b/drivers/clk/starfive/clk-starfive-jh7100.h
  398. @@ -4,6 +4,8 @@
  399. #include <linux/bits.h>
  400. #include <linux/clk-provider.h>
  401. +#include <linux/device.h>
  402. +#include <linux/spinlock.h>
  403. /* register fields */
  404. #define JH7100_CLK_ENABLE BIT(31)
  405. --- /dev/null
  406. +++ b/drivers/clk/starfive/clk-starfive-jh71x0.c
  407. @@ -0,0 +1,333 @@
  408. +// SPDX-License-Identifier: GPL-2.0
  409. +/*
  410. + * StarFive JH7100 Clock Generator Driver
  411. + *
  412. + * Copyright (C) 2021-2022 Emil Renner Berthing <[email protected]>
  413. + */
  414. +
  415. +#include <linux/clk-provider.h>
  416. +#include <linux/debugfs.h>
  417. +#include <linux/device.h>
  418. +#include <linux/io.h>
  419. +
  420. +#include "clk-starfive-jh7100.h"
  421. +
  422. +static struct jh7100_clk *jh7100_clk_from(struct clk_hw *hw)
  423. +{
  424. + return container_of(hw, struct jh7100_clk, hw);
  425. +}
  426. +
  427. +static struct jh7100_clk_priv *jh7100_priv_from(struct jh7100_clk *clk)
  428. +{
  429. + return container_of(clk, struct jh7100_clk_priv, reg[clk->idx]);
  430. +}
  431. +
  432. +static u32 jh7100_clk_reg_get(struct jh7100_clk *clk)
  433. +{
  434. + struct jh7100_clk_priv *priv = jh7100_priv_from(clk);
  435. + void __iomem *reg = priv->base + 4 * clk->idx;
  436. +
  437. + return readl_relaxed(reg);
  438. +}
  439. +
  440. +static void jh7100_clk_reg_rmw(struct jh7100_clk *clk, u32 mask, u32 value)
  441. +{
  442. + struct jh7100_clk_priv *priv = jh7100_priv_from(clk);
  443. + void __iomem *reg = priv->base + 4 * clk->idx;
  444. + unsigned long flags;
  445. +
  446. + spin_lock_irqsave(&priv->rmw_lock, flags);
  447. + value |= readl_relaxed(reg) & ~mask;
  448. + writel_relaxed(value, reg);
  449. + spin_unlock_irqrestore(&priv->rmw_lock, flags);
  450. +}
  451. +
  452. +static int jh7100_clk_enable(struct clk_hw *hw)
  453. +{
  454. + struct jh7100_clk *clk = jh7100_clk_from(hw);
  455. +
  456. + jh7100_clk_reg_rmw(clk, JH7100_CLK_ENABLE, JH7100_CLK_ENABLE);
  457. + return 0;
  458. +}
  459. +
  460. +static void jh7100_clk_disable(struct clk_hw *hw)
  461. +{
  462. + struct jh7100_clk *clk = jh7100_clk_from(hw);
  463. +
  464. + jh7100_clk_reg_rmw(clk, JH7100_CLK_ENABLE, 0);
  465. +}
  466. +
  467. +static int jh7100_clk_is_enabled(struct clk_hw *hw)
  468. +{
  469. + struct jh7100_clk *clk = jh7100_clk_from(hw);
  470. +
  471. + return !!(jh7100_clk_reg_get(clk) & JH7100_CLK_ENABLE);
  472. +}
  473. +
  474. +static unsigned long jh7100_clk_recalc_rate(struct clk_hw *hw,
  475. + unsigned long parent_rate)
  476. +{
  477. + struct jh7100_clk *clk = jh7100_clk_from(hw);
  478. + u32 div = jh7100_clk_reg_get(clk) & JH7100_CLK_DIV_MASK;
  479. +
  480. + return div ? parent_rate / div : 0;
  481. +}
  482. +
  483. +static int jh7100_clk_determine_rate(struct clk_hw *hw,
  484. + struct clk_rate_request *req)
  485. +{
  486. + struct jh7100_clk *clk = jh7100_clk_from(hw);
  487. + unsigned long parent = req->best_parent_rate;
  488. + unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate);
  489. + unsigned long div = min_t(unsigned long, DIV_ROUND_UP(parent, rate), clk->max_div);
  490. + unsigned long result = parent / div;
  491. +
  492. + /*
  493. + * we want the result clamped by min_rate and max_rate if possible:
  494. + * case 1: div hits the max divider value, which means it's less than
  495. + * parent / rate, so the result is greater than rate and min_rate in
  496. + * particular. we can't do anything about result > max_rate because the
  497. + * divider doesn't go any further.
  498. + * case 2: div = DIV_ROUND_UP(parent, rate) which means the result is
  499. + * always lower or equal to rate and max_rate. however the result may
  500. + * turn out lower than min_rate, but then the next higher rate is fine:
  501. + * div - 1 = ceil(parent / rate) - 1 < parent / rate
  502. + * and thus
  503. + * min_rate <= rate < parent / (div - 1)
  504. + */
  505. + if (result < req->min_rate && div > 1)
  506. + result = parent / (div - 1);
  507. +
  508. + req->rate = result;
  509. + return 0;
  510. +}
  511. +
  512. +static int jh7100_clk_set_rate(struct clk_hw *hw,
  513. + unsigned long rate,
  514. + unsigned long parent_rate)
  515. +{
  516. + struct jh7100_clk *clk = jh7100_clk_from(hw);
  517. + unsigned long div = clamp(DIV_ROUND_CLOSEST(parent_rate, rate),
  518. + 1UL, (unsigned long)clk->max_div);
  519. +
  520. + jh7100_clk_reg_rmw(clk, JH7100_CLK_DIV_MASK, div);
  521. + return 0;
  522. +}
  523. +
  524. +static unsigned long jh7100_clk_frac_recalc_rate(struct clk_hw *hw,
  525. + unsigned long parent_rate)
  526. +{
  527. + struct jh7100_clk *clk = jh7100_clk_from(hw);
  528. + u32 reg = jh7100_clk_reg_get(clk);
  529. + unsigned long div100 = 100 * (reg & JH7100_CLK_INT_MASK) +
  530. + ((reg & JH7100_CLK_FRAC_MASK) >> JH7100_CLK_FRAC_SHIFT);
  531. +
  532. + return (div100 >= JH7100_CLK_FRAC_MIN) ? 100 * parent_rate / div100 : 0;
  533. +}
  534. +
  535. +static int jh7100_clk_frac_determine_rate(struct clk_hw *hw,
  536. + struct clk_rate_request *req)
  537. +{
  538. + unsigned long parent100 = 100 * req->best_parent_rate;
  539. + unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate);
  540. + unsigned long div100 = clamp(DIV_ROUND_CLOSEST(parent100, rate),
  541. + JH7100_CLK_FRAC_MIN, JH7100_CLK_FRAC_MAX);
  542. + unsigned long result = parent100 / div100;
  543. +
  544. + /* clamp the result as in jh7100_clk_determine_rate() above */
  545. + if (result > req->max_rate && div100 < JH7100_CLK_FRAC_MAX)
  546. + result = parent100 / (div100 + 1);
  547. + if (result < req->min_rate && div100 > JH7100_CLK_FRAC_MIN)
  548. + result = parent100 / (div100 - 1);
  549. +
  550. + req->rate = result;
  551. + return 0;
  552. +}
  553. +
  554. +static int jh7100_clk_frac_set_rate(struct clk_hw *hw,
  555. + unsigned long rate,
  556. + unsigned long parent_rate)
  557. +{
  558. + struct jh7100_clk *clk = jh7100_clk_from(hw);
  559. + unsigned long div100 = clamp(DIV_ROUND_CLOSEST(100 * parent_rate, rate),
  560. + JH7100_CLK_FRAC_MIN, JH7100_CLK_FRAC_MAX);
  561. + u32 value = ((div100 % 100) << JH7100_CLK_FRAC_SHIFT) | (div100 / 100);
  562. +
  563. + jh7100_clk_reg_rmw(clk, JH7100_CLK_DIV_MASK, value);
  564. + return 0;
  565. +}
  566. +
  567. +static u8 jh7100_clk_get_parent(struct clk_hw *hw)
  568. +{
  569. + struct jh7100_clk *clk = jh7100_clk_from(hw);
  570. + u32 value = jh7100_clk_reg_get(clk);
  571. +
  572. + return (value & JH7100_CLK_MUX_MASK) >> JH7100_CLK_MUX_SHIFT;
  573. +}
  574. +
  575. +static int jh7100_clk_set_parent(struct clk_hw *hw, u8 index)
  576. +{
  577. + struct jh7100_clk *clk = jh7100_clk_from(hw);
  578. + u32 value = (u32)index << JH7100_CLK_MUX_SHIFT;
  579. +
  580. + jh7100_clk_reg_rmw(clk, JH7100_CLK_MUX_MASK, value);
  581. + return 0;
  582. +}
  583. +
  584. +static int jh7100_clk_mux_determine_rate(struct clk_hw *hw,
  585. + struct clk_rate_request *req)
  586. +{
  587. + return clk_mux_determine_rate_flags(hw, req, 0);
  588. +}
  589. +
  590. +static int jh7100_clk_get_phase(struct clk_hw *hw)
  591. +{
  592. + struct jh7100_clk *clk = jh7100_clk_from(hw);
  593. + u32 value = jh7100_clk_reg_get(clk);
  594. +
  595. + return (value & JH7100_CLK_INVERT) ? 180 : 0;
  596. +}
  597. +
  598. +static int jh7100_clk_set_phase(struct clk_hw *hw, int degrees)
  599. +{
  600. + struct jh7100_clk *clk = jh7100_clk_from(hw);
  601. + u32 value;
  602. +
  603. + if (degrees == 0)
  604. + value = 0;
  605. + else if (degrees == 180)
  606. + value = JH7100_CLK_INVERT;
  607. + else
  608. + return -EINVAL;
  609. +
  610. + jh7100_clk_reg_rmw(clk, JH7100_CLK_INVERT, value);
  611. + return 0;
  612. +}
  613. +
  614. +#ifdef CONFIG_DEBUG_FS
  615. +static void jh7100_clk_debug_init(struct clk_hw *hw, struct dentry *dentry)
  616. +{
  617. + static const struct debugfs_reg32 jh7100_clk_reg = {
  618. + .name = "CTRL",
  619. + .offset = 0,
  620. + };
  621. + struct jh7100_clk *clk = jh7100_clk_from(hw);
  622. + struct jh7100_clk_priv *priv = jh7100_priv_from(clk);
  623. + struct debugfs_regset32 *regset;
  624. +
  625. + regset = devm_kzalloc(priv->dev, sizeof(*regset), GFP_KERNEL);
  626. + if (!regset)
  627. + return;
  628. +
  629. + regset->regs = &jh7100_clk_reg;
  630. + regset->nregs = 1;
  631. + regset->base = priv->base + 4 * clk->idx;
  632. +
  633. + debugfs_create_regset32("registers", 0400, dentry, regset);
  634. +}
  635. +#else
  636. +#define jh7100_clk_debug_init NULL
  637. +#endif
  638. +
  639. +static const struct clk_ops jh7100_clk_gate_ops = {
  640. + .enable = jh7100_clk_enable,
  641. + .disable = jh7100_clk_disable,
  642. + .is_enabled = jh7100_clk_is_enabled,
  643. + .debug_init = jh7100_clk_debug_init,
  644. +};
  645. +
  646. +static const struct clk_ops jh7100_clk_div_ops = {
  647. + .recalc_rate = jh7100_clk_recalc_rate,
  648. + .determine_rate = jh7100_clk_determine_rate,
  649. + .set_rate = jh7100_clk_set_rate,
  650. + .debug_init = jh7100_clk_debug_init,
  651. +};
  652. +
  653. +static const struct clk_ops jh7100_clk_fdiv_ops = {
  654. + .recalc_rate = jh7100_clk_frac_recalc_rate,
  655. + .determine_rate = jh7100_clk_frac_determine_rate,
  656. + .set_rate = jh7100_clk_frac_set_rate,
  657. + .debug_init = jh7100_clk_debug_init,
  658. +};
  659. +
  660. +static const struct clk_ops jh7100_clk_gdiv_ops = {
  661. + .enable = jh7100_clk_enable,
  662. + .disable = jh7100_clk_disable,
  663. + .is_enabled = jh7100_clk_is_enabled,
  664. + .recalc_rate = jh7100_clk_recalc_rate,
  665. + .determine_rate = jh7100_clk_determine_rate,
  666. + .set_rate = jh7100_clk_set_rate,
  667. + .debug_init = jh7100_clk_debug_init,
  668. +};
  669. +
  670. +static const struct clk_ops jh7100_clk_mux_ops = {
  671. + .determine_rate = jh7100_clk_mux_determine_rate,
  672. + .set_parent = jh7100_clk_set_parent,
  673. + .get_parent = jh7100_clk_get_parent,
  674. + .debug_init = jh7100_clk_debug_init,
  675. +};
  676. +
  677. +static const struct clk_ops jh7100_clk_gmux_ops = {
  678. + .enable = jh7100_clk_enable,
  679. + .disable = jh7100_clk_disable,
  680. + .is_enabled = jh7100_clk_is_enabled,
  681. + .determine_rate = jh7100_clk_mux_determine_rate,
  682. + .set_parent = jh7100_clk_set_parent,
  683. + .get_parent = jh7100_clk_get_parent,
  684. + .debug_init = jh7100_clk_debug_init,
  685. +};
  686. +
  687. +static const struct clk_ops jh7100_clk_mdiv_ops = {
  688. + .recalc_rate = jh7100_clk_recalc_rate,
  689. + .determine_rate = jh7100_clk_determine_rate,
  690. + .get_parent = jh7100_clk_get_parent,
  691. + .set_parent = jh7100_clk_set_parent,
  692. + .set_rate = jh7100_clk_set_rate,
  693. + .debug_init = jh7100_clk_debug_init,
  694. +};
  695. +
  696. +static const struct clk_ops jh7100_clk_gmd_ops = {
  697. + .enable = jh7100_clk_enable,
  698. + .disable = jh7100_clk_disable,
  699. + .is_enabled = jh7100_clk_is_enabled,
  700. + .recalc_rate = jh7100_clk_recalc_rate,
  701. + .determine_rate = jh7100_clk_determine_rate,
  702. + .get_parent = jh7100_clk_get_parent,
  703. + .set_parent = jh7100_clk_set_parent,
  704. + .set_rate = jh7100_clk_set_rate,
  705. + .debug_init = jh7100_clk_debug_init,
  706. +};
  707. +
  708. +static const struct clk_ops jh7100_clk_inv_ops = {
  709. + .get_phase = jh7100_clk_get_phase,
  710. + .set_phase = jh7100_clk_set_phase,
  711. + .debug_init = jh7100_clk_debug_init,
  712. +};
  713. +
  714. +const struct clk_ops *starfive_jh7100_clk_ops(u32 max)
  715. +{
  716. + if (max & JH7100_CLK_DIV_MASK) {
  717. + if (max & JH7100_CLK_MUX_MASK) {
  718. + if (max & JH7100_CLK_ENABLE)
  719. + return &jh7100_clk_gmd_ops;
  720. + return &jh7100_clk_mdiv_ops;
  721. + }
  722. + if (max & JH7100_CLK_ENABLE)
  723. + return &jh7100_clk_gdiv_ops;
  724. + if (max == JH7100_CLK_FRAC_MAX)
  725. + return &jh7100_clk_fdiv_ops;
  726. + return &jh7100_clk_div_ops;
  727. + }
  728. +
  729. + if (max & JH7100_CLK_MUX_MASK) {
  730. + if (max & JH7100_CLK_ENABLE)
  731. + return &jh7100_clk_gmux_ops;
  732. + return &jh7100_clk_mux_ops;
  733. + }
  734. +
  735. + if (max & JH7100_CLK_ENABLE)
  736. + return &jh7100_clk_gate_ops;
  737. +
  738. + return &jh7100_clk_inv_ops;
  739. +}
  740. +EXPORT_SYMBOL_GPL(starfive_jh7100_clk_ops);