clk.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /*
  2. * Copyright (c) 2014 MundoReader S.L.
  3. * Author: Heiko Stuebner <heiko@sntech.de>
  4. *
  5. * based on
  6. *
  7. * samsung/clk.c
  8. * Copyright (c) 2013 Samsung Electronics Co., Ltd.
  9. * Copyright (c) 2013 Linaro Ltd.
  10. * Author: Thomas Abraham <thomas.ab@samsung.com>
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation; either version 2 of the License, or
  15. * (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. */
  22. #include <linux/slab.h>
  23. #include <linux/clk.h>
  24. #include <linux/clk-provider.h>
  25. #include <linux/mfd/syscon.h>
  26. #include <linux/regmap.h>
  27. #include <linux/reboot.h>
  28. #include "clk.h"
  29. /**
  30. * Register a clock branch.
  31. * Most clock branches have a form like
  32. *
  33. * src1 --|--\
  34. * |M |--[GATE]-[DIV]-
  35. * src2 --|--/
  36. *
  37. * sometimes without one of those components.
  38. */
  39. static struct clk *rockchip_clk_register_branch(const char *name,
  40. const char **parent_names, u8 num_parents, void __iomem *base,
  41. int muxdiv_offset, u8 mux_shift, u8 mux_width, u8 mux_flags,
  42. u8 div_shift, u8 div_width, u8 div_flags,
  43. struct clk_div_table *div_table, int gate_offset,
  44. u8 gate_shift, u8 gate_flags, unsigned long flags,
  45. spinlock_t *lock)
  46. {
  47. struct clk *clk;
  48. struct clk_mux *mux = NULL;
  49. struct clk_gate *gate = NULL;
  50. struct clk_divider *div = NULL;
  51. const struct clk_ops *mux_ops = NULL, *div_ops = NULL,
  52. *gate_ops = NULL;
  53. if (num_parents > 1) {
  54. mux = kzalloc(sizeof(*mux), GFP_KERNEL);
  55. if (!mux)
  56. return ERR_PTR(-ENOMEM);
  57. mux->reg = base + muxdiv_offset;
  58. mux->shift = mux_shift;
  59. mux->mask = BIT(mux_width) - 1;
  60. mux->flags = mux_flags;
  61. mux->lock = lock;
  62. mux_ops = (mux_flags & CLK_MUX_READ_ONLY) ? &clk_mux_ro_ops
  63. : &clk_mux_ops;
  64. }
  65. if (gate_offset >= 0) {
  66. gate = kzalloc(sizeof(*gate), GFP_KERNEL);
  67. if (!gate)
  68. return ERR_PTR(-ENOMEM);
  69. gate->flags = gate_flags;
  70. gate->reg = base + gate_offset;
  71. gate->bit_idx = gate_shift;
  72. gate->lock = lock;
  73. gate_ops = &clk_gate_ops;
  74. }
  75. if (div_width > 0) {
  76. div = kzalloc(sizeof(*div), GFP_KERNEL);
  77. if (!div)
  78. return ERR_PTR(-ENOMEM);
  79. div->flags = div_flags;
  80. div->reg = base + muxdiv_offset;
  81. div->shift = div_shift;
  82. div->width = div_width;
  83. div->lock = lock;
  84. div->table = div_table;
  85. div_ops = (div_flags & CLK_DIVIDER_READ_ONLY)
  86. ? &clk_divider_ro_ops
  87. : &clk_divider_ops;
  88. }
  89. clk = clk_register_composite(NULL, name, parent_names, num_parents,
  90. mux ? &mux->hw : NULL, mux_ops,
  91. div ? &div->hw : NULL, div_ops,
  92. gate ? &gate->hw : NULL, gate_ops,
  93. flags);
  94. return clk;
  95. }
  96. static struct clk *rockchip_clk_register_frac_branch(const char *name,
  97. const char **parent_names, u8 num_parents, void __iomem *base,
  98. int muxdiv_offset, u8 div_flags,
  99. int gate_offset, u8 gate_shift, u8 gate_flags,
  100. unsigned long flags, spinlock_t *lock)
  101. {
  102. struct clk *clk;
  103. struct clk_gate *gate = NULL;
  104. struct clk_fractional_divider *div = NULL;
  105. const struct clk_ops *div_ops = NULL, *gate_ops = NULL;
  106. if (gate_offset >= 0) {
  107. gate = kzalloc(sizeof(*gate), GFP_KERNEL);
  108. if (!gate)
  109. return ERR_PTR(-ENOMEM);
  110. gate->flags = gate_flags;
  111. gate->reg = base + gate_offset;
  112. gate->bit_idx = gate_shift;
  113. gate->lock = lock;
  114. gate_ops = &clk_gate_ops;
  115. }
  116. if (muxdiv_offset < 0)
  117. return ERR_PTR(-EINVAL);
  118. div = kzalloc(sizeof(*div), GFP_KERNEL);
  119. if (!div)
  120. return ERR_PTR(-ENOMEM);
  121. div->flags = div_flags;
  122. div->reg = base + muxdiv_offset;
  123. div->mshift = 16;
  124. div->mmask = 0xffff0000;
  125. div->nshift = 0;
  126. div->nmask = 0xffff;
  127. div->lock = lock;
  128. div_ops = &clk_fractional_divider_ops;
  129. clk = clk_register_composite(NULL, name, parent_names, num_parents,
  130. NULL, NULL,
  131. &div->hw, div_ops,
  132. gate ? &gate->hw : NULL, gate_ops,
  133. flags);
  134. return clk;
  135. }
  136. static DEFINE_SPINLOCK(clk_lock);
  137. static struct clk **clk_table;
  138. static void __iomem *reg_base;
  139. static struct clk_onecell_data clk_data;
  140. static struct device_node *cru_node;
  141. static struct regmap *grf;
  142. void __init rockchip_clk_init(struct device_node *np, void __iomem *base,
  143. unsigned long nr_clks)
  144. {
  145. reg_base = base;
  146. cru_node = np;
  147. grf = ERR_PTR(-EPROBE_DEFER);
  148. clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL);
  149. if (!clk_table)
  150. pr_err("%s: could not allocate clock lookup table\n", __func__);
  151. clk_data.clks = clk_table;
  152. clk_data.clk_num = nr_clks;
  153. of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
  154. }
  155. struct regmap *rockchip_clk_get_grf(void)
  156. {
  157. if (IS_ERR(grf))
  158. grf = syscon_regmap_lookup_by_phandle(cru_node, "rockchip,grf");
  159. return grf;
  160. }
  161. void rockchip_clk_add_lookup(struct clk *clk, unsigned int id)
  162. {
  163. if (clk_table && id)
  164. clk_table[id] = clk;
  165. }
  166. void __init rockchip_clk_register_plls(struct rockchip_pll_clock *list,
  167. unsigned int nr_pll, int grf_lock_offset)
  168. {
  169. struct clk *clk;
  170. int idx;
  171. for (idx = 0; idx < nr_pll; idx++, list++) {
  172. clk = rockchip_clk_register_pll(list->type, list->name,
  173. list->parent_names, list->num_parents,
  174. reg_base, list->con_offset, grf_lock_offset,
  175. list->lock_shift, list->mode_offset,
  176. list->mode_shift, list->rate_table, &clk_lock);
  177. if (IS_ERR(clk)) {
  178. pr_err("%s: failed to register clock %s\n", __func__,
  179. list->name);
  180. continue;
  181. }
  182. rockchip_clk_add_lookup(clk, list->id);
  183. }
  184. }
  185. void __init rockchip_clk_register_branches(
  186. struct rockchip_clk_branch *list,
  187. unsigned int nr_clk)
  188. {
  189. struct clk *clk = NULL;
  190. unsigned int idx;
  191. unsigned long flags;
  192. for (idx = 0; idx < nr_clk; idx++, list++) {
  193. flags = list->flags;
  194. /* catch simple muxes */
  195. switch (list->branch_type) {
  196. case branch_mux:
  197. clk = clk_register_mux(NULL, list->name,
  198. list->parent_names, list->num_parents,
  199. flags, reg_base + list->muxdiv_offset,
  200. list->mux_shift, list->mux_width,
  201. list->mux_flags, &clk_lock);
  202. break;
  203. case branch_divider:
  204. if (list->div_table)
  205. clk = clk_register_divider_table(NULL,
  206. list->name, list->parent_names[0],
  207. flags, reg_base + list->muxdiv_offset,
  208. list->div_shift, list->div_width,
  209. list->div_flags, list->div_table,
  210. &clk_lock);
  211. else
  212. clk = clk_register_divider(NULL, list->name,
  213. list->parent_names[0], flags,
  214. reg_base + list->muxdiv_offset,
  215. list->div_shift, list->div_width,
  216. list->div_flags, &clk_lock);
  217. break;
  218. case branch_fraction_divider:
  219. /* keep all gates untouched for now */
  220. flags |= CLK_IGNORE_UNUSED;
  221. clk = rockchip_clk_register_frac_branch(list->name,
  222. list->parent_names, list->num_parents,
  223. reg_base, list->muxdiv_offset, list->div_flags,
  224. list->gate_offset, list->gate_shift,
  225. list->gate_flags, flags, &clk_lock);
  226. break;
  227. case branch_gate:
  228. flags |= CLK_SET_RATE_PARENT;
  229. /* keep all gates untouched for now */
  230. flags |= CLK_IGNORE_UNUSED;
  231. clk = clk_register_gate(NULL, list->name,
  232. list->parent_names[0], flags,
  233. reg_base + list->gate_offset,
  234. list->gate_shift, list->gate_flags, &clk_lock);
  235. break;
  236. case branch_composite:
  237. /* keep all gates untouched for now */
  238. flags |= CLK_IGNORE_UNUSED;
  239. clk = rockchip_clk_register_branch(list->name,
  240. list->parent_names, list->num_parents,
  241. reg_base, list->muxdiv_offset, list->mux_shift,
  242. list->mux_width, list->mux_flags,
  243. list->div_shift, list->div_width,
  244. list->div_flags, list->div_table,
  245. list->gate_offset, list->gate_shift,
  246. list->gate_flags, flags, &clk_lock);
  247. break;
  248. }
  249. /* none of the cases above matched */
  250. if (!clk) {
  251. pr_err("%s: unknown clock type %d\n",
  252. __func__, list->branch_type);
  253. continue;
  254. }
  255. if (IS_ERR(clk)) {
  256. pr_err("%s: failed to register clock %s: %ld\n",
  257. __func__, list->name, PTR_ERR(clk));
  258. continue;
  259. }
  260. rockchip_clk_add_lookup(clk, list->id);
  261. }
  262. }
  263. void __init rockchip_clk_register_armclk(unsigned int lookup_id,
  264. const char *name, const char **parent_names,
  265. u8 num_parents,
  266. const struct rockchip_cpuclk_reg_data *reg_data,
  267. const struct rockchip_cpuclk_rate_table *rates,
  268. int nrates)
  269. {
  270. struct clk *clk;
  271. clk = rockchip_clk_register_cpuclk(name, parent_names, num_parents,
  272. reg_data, rates, nrates, reg_base,
  273. &clk_lock);
  274. if (IS_ERR(clk)) {
  275. pr_err("%s: failed to register clock %s: %ld\n",
  276. __func__, name, PTR_ERR(clk));
  277. return;
  278. }
  279. rockchip_clk_add_lookup(clk, lookup_id);
  280. }
  281. void __init rockchip_clk_protect_critical(const char *clocks[], int nclocks)
  282. {
  283. int i;
  284. /* Protect the clocks that needs to stay on */
  285. for (i = 0; i < nclocks; i++) {
  286. struct clk *clk = __clk_lookup(clocks[i]);
  287. if (clk)
  288. clk_prepare_enable(clk);
  289. }
  290. }
  291. static unsigned int reg_restart;
  292. static int rockchip_restart_notify(struct notifier_block *this,
  293. unsigned long mode, void *cmd)
  294. {
  295. writel(0xfdb9, reg_base + reg_restart);
  296. return NOTIFY_DONE;
  297. }
  298. static struct notifier_block rockchip_restart_handler = {
  299. .notifier_call = rockchip_restart_notify,
  300. .priority = 128,
  301. };
  302. void __init rockchip_register_restart_notifier(unsigned int reg)
  303. {
  304. int ret;
  305. reg_restart = reg;
  306. ret = register_restart_handler(&rockchip_restart_handler);
  307. if (ret)
  308. pr_err("%s: cannot register restart handler, %d\n",
  309. __func__, ret);
  310. }