clk-mb86s7x.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /*
  2. * Copyright (C) 2013-2015 FUJITSU SEMICONDUCTOR LIMITED
  3. * Copyright (C) 2015 Linaro Ltd.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, version 2 of the License.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include <linux/clkdev.h>
  15. #include <linux/err.h>
  16. #include <linux/io.h>
  17. #include <linux/of.h>
  18. #include <linux/cpu.h>
  19. #include <linux/clk-provider.h>
  20. #include <linux/spinlock.h>
  21. #include <linux/module.h>
  22. #include <linux/topology.h>
  23. #include <linux/mailbox_client.h>
  24. #include <linux/platform_device.h>
  25. #include <soc/mb86s7x/scb_mhu.h>
  26. #define to_crg_clk(p) container_of(p, struct crg_clk, hw)
  27. #define to_clc_clk(p) container_of(p, struct cl_clk, hw)
  28. struct mb86s7x_peri_clk {
  29. u32 payload_size;
  30. u32 cntrlr;
  31. u32 domain;
  32. u32 port;
  33. u32 en;
  34. u64 frequency;
  35. } __packed __aligned(4);
  36. struct hack_rate {
  37. unsigned clk_id;
  38. unsigned long rate;
  39. int gated;
  40. };
  41. struct crg_clk {
  42. struct clk_hw hw;
  43. u8 cntrlr, domain, port;
  44. };
  45. static int crg_gate_control(struct clk_hw *hw, int en)
  46. {
  47. struct crg_clk *crgclk = to_crg_clk(hw);
  48. struct mb86s7x_peri_clk cmd;
  49. int ret;
  50. cmd.payload_size = sizeof(cmd);
  51. cmd.cntrlr = crgclk->cntrlr;
  52. cmd.domain = crgclk->domain;
  53. cmd.port = crgclk->port;
  54. cmd.en = en;
  55. /* Port is UngatedCLK */
  56. if (cmd.port == 8)
  57. return en ? 0 : -EINVAL;
  58. pr_debug("%s:%d CMD Cntrlr-%u Dom-%u Port-%u En-%u}\n",
  59. __func__, __LINE__, cmd.cntrlr,
  60. cmd.domain, cmd.port, cmd.en);
  61. ret = mb86s7x_send_packet(CMD_PERI_CLOCK_GATE_SET_REQ,
  62. &cmd, sizeof(cmd));
  63. if (ret < 0) {
  64. pr_err("%s:%d failed!\n", __func__, __LINE__);
  65. return ret;
  66. }
  67. pr_debug("%s:%d REP Cntrlr-%u Dom-%u Port-%u En-%u}\n",
  68. __func__, __LINE__, cmd.cntrlr,
  69. cmd.domain, cmd.port, cmd.en);
  70. /* If the request was rejected */
  71. if (cmd.en != en)
  72. ret = -EINVAL;
  73. else
  74. ret = 0;
  75. return ret;
  76. }
  77. static int crg_port_prepare(struct clk_hw *hw)
  78. {
  79. return crg_gate_control(hw, 1);
  80. }
  81. static void crg_port_unprepare(struct clk_hw *hw)
  82. {
  83. crg_gate_control(hw, 0);
  84. }
  85. static int
  86. crg_rate_control(struct clk_hw *hw, int set, unsigned long *rate)
  87. {
  88. struct crg_clk *crgclk = to_crg_clk(hw);
  89. struct mb86s7x_peri_clk cmd;
  90. int code, ret;
  91. cmd.payload_size = sizeof(cmd);
  92. cmd.cntrlr = crgclk->cntrlr;
  93. cmd.domain = crgclk->domain;
  94. cmd.port = crgclk->port;
  95. cmd.frequency = *rate;
  96. if (set) {
  97. code = CMD_PERI_CLOCK_RATE_SET_REQ;
  98. pr_debug("%s:%d CMD Cntrlr-%u Dom-%u Port-%u Rate-SET %lluHz}\n",
  99. __func__, __LINE__, cmd.cntrlr,
  100. cmd.domain, cmd.port, cmd.frequency);
  101. } else {
  102. code = CMD_PERI_CLOCK_RATE_GET_REQ;
  103. pr_debug("%s:%d CMD Cntrlr-%u Dom-%u Port-%u Rate-GET}\n",
  104. __func__, __LINE__, cmd.cntrlr,
  105. cmd.domain, cmd.port);
  106. }
  107. ret = mb86s7x_send_packet(code, &cmd, sizeof(cmd));
  108. if (ret < 0) {
  109. pr_err("%s:%d failed!\n", __func__, __LINE__);
  110. return ret;
  111. }
  112. if (set)
  113. pr_debug("%s:%d REP Cntrlr-%u Dom-%u Port-%u Rate-SET %lluHz}\n",
  114. __func__, __LINE__, cmd.cntrlr,
  115. cmd.domain, cmd.port, cmd.frequency);
  116. else
  117. pr_debug("%s:%d REP Cntrlr-%u Dom-%u Port-%u Rate-GOT %lluHz}\n",
  118. __func__, __LINE__, cmd.cntrlr,
  119. cmd.domain, cmd.port, cmd.frequency);
  120. *rate = cmd.frequency;
  121. return 0;
  122. }
  123. static unsigned long
  124. crg_port_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
  125. {
  126. unsigned long rate;
  127. crg_rate_control(hw, 0, &rate);
  128. return rate;
  129. }
  130. static long
  131. crg_port_round_rate(struct clk_hw *hw,
  132. unsigned long rate, unsigned long *pr)
  133. {
  134. return rate;
  135. }
  136. static int
  137. crg_port_set_rate(struct clk_hw *hw,
  138. unsigned long rate, unsigned long parent_rate)
  139. {
  140. return crg_rate_control(hw, 1, &rate);
  141. }
  142. const struct clk_ops crg_port_ops = {
  143. .prepare = crg_port_prepare,
  144. .unprepare = crg_port_unprepare,
  145. .recalc_rate = crg_port_recalc_rate,
  146. .round_rate = crg_port_round_rate,
  147. .set_rate = crg_port_set_rate,
  148. };
  149. struct mb86s70_crg11 {
  150. struct mutex lock; /* protects CLK populating and searching */
  151. };
  152. static struct clk *crg11_get(struct of_phandle_args *clkspec, void *data)
  153. {
  154. struct mb86s70_crg11 *crg11 = data;
  155. struct clk_init_data init;
  156. u32 cntrlr, domain, port;
  157. struct crg_clk *crgclk;
  158. struct clk *clk;
  159. char clkp[20];
  160. if (clkspec->args_count != 3)
  161. return ERR_PTR(-EINVAL);
  162. cntrlr = clkspec->args[0];
  163. domain = clkspec->args[1];
  164. port = clkspec->args[2];
  165. if (port > 7)
  166. snprintf(clkp, 20, "UngatedCLK%d_%X", cntrlr, domain);
  167. else
  168. snprintf(clkp, 20, "CLK%d_%X_%d", cntrlr, domain, port);
  169. mutex_lock(&crg11->lock);
  170. clk = __clk_lookup(clkp);
  171. if (clk) {
  172. mutex_unlock(&crg11->lock);
  173. return clk;
  174. }
  175. crgclk = kzalloc(sizeof(*crgclk), GFP_KERNEL);
  176. if (!crgclk) {
  177. mutex_unlock(&crg11->lock);
  178. return ERR_PTR(-ENOMEM);
  179. }
  180. init.name = clkp;
  181. init.num_parents = 0;
  182. init.ops = &crg_port_ops;
  183. init.flags = CLK_IS_ROOT;
  184. crgclk->hw.init = &init;
  185. crgclk->cntrlr = cntrlr;
  186. crgclk->domain = domain;
  187. crgclk->port = port;
  188. clk = clk_register(NULL, &crgclk->hw);
  189. if (IS_ERR(clk))
  190. pr_err("%s:%d Error!\n", __func__, __LINE__);
  191. else
  192. pr_debug("Registered %s\n", clkp);
  193. clk_register_clkdev(clk, clkp, NULL);
  194. mutex_unlock(&crg11->lock);
  195. return clk;
  196. }
  197. static void __init crg_port_init(struct device_node *node)
  198. {
  199. struct mb86s70_crg11 *crg11;
  200. crg11 = kzalloc(sizeof(*crg11), GFP_KERNEL);
  201. if (!crg11)
  202. return;
  203. mutex_init(&crg11->lock);
  204. of_clk_add_provider(node, crg11_get, crg11);
  205. }
  206. CLK_OF_DECLARE(crg11_gate, "fujitsu,mb86s70-crg11", crg_port_init);
  207. struct cl_clk {
  208. struct clk_hw hw;
  209. int cluster;
  210. };
  211. struct mb86s7x_cpu_freq {
  212. u32 payload_size;
  213. u32 cluster_class;
  214. u32 cluster_id;
  215. u32 cpu_id;
  216. u64 frequency;
  217. };
  218. static void mhu_cluster_rate(struct clk_hw *hw, unsigned long *rate, int get)
  219. {
  220. struct cl_clk *clc = to_clc_clk(hw);
  221. struct mb86s7x_cpu_freq cmd;
  222. int code, ret;
  223. cmd.payload_size = sizeof(cmd);
  224. cmd.cluster_class = 0;
  225. cmd.cluster_id = clc->cluster;
  226. cmd.cpu_id = 0;
  227. cmd.frequency = *rate;
  228. if (get)
  229. code = CMD_CPU_CLOCK_RATE_GET_REQ;
  230. else
  231. code = CMD_CPU_CLOCK_RATE_SET_REQ;
  232. pr_debug("%s:%d CMD Cl_Class-%u CL_ID-%u CPU_ID-%u Freq-%llu}\n",
  233. __func__, __LINE__, cmd.cluster_class,
  234. cmd.cluster_id, cmd.cpu_id, cmd.frequency);
  235. ret = mb86s7x_send_packet(code, &cmd, sizeof(cmd));
  236. if (ret < 0) {
  237. pr_err("%s:%d failed!\n", __func__, __LINE__);
  238. return;
  239. }
  240. pr_debug("%s:%d REP Cl_Class-%u CL_ID-%u CPU_ID-%u Freq-%llu}\n",
  241. __func__, __LINE__, cmd.cluster_class,
  242. cmd.cluster_id, cmd.cpu_id, cmd.frequency);
  243. *rate = cmd.frequency;
  244. }
  245. static unsigned long
  246. clc_recalc_rate(struct clk_hw *hw, unsigned long unused)
  247. {
  248. unsigned long rate;
  249. mhu_cluster_rate(hw, &rate, 1);
  250. return rate;
  251. }
  252. static long
  253. clc_round_rate(struct clk_hw *hw, unsigned long rate,
  254. unsigned long *unused)
  255. {
  256. return rate;
  257. }
  258. static int
  259. clc_set_rate(struct clk_hw *hw, unsigned long rate,
  260. unsigned long unused)
  261. {
  262. unsigned long res = rate;
  263. mhu_cluster_rate(hw, &res, 0);
  264. return (res == rate) ? 0 : -EINVAL;
  265. }
  266. static struct clk_ops clk_clc_ops = {
  267. .recalc_rate = clc_recalc_rate,
  268. .round_rate = clc_round_rate,
  269. .set_rate = clc_set_rate,
  270. };
  271. struct clk *mb86s7x_clclk_register(struct device *cpu_dev)
  272. {
  273. struct clk_init_data init;
  274. struct cl_clk *clc;
  275. clc = kzalloc(sizeof(*clc), GFP_KERNEL);
  276. if (!clc)
  277. return ERR_PTR(-ENOMEM);
  278. clc->hw.init = &init;
  279. clc->cluster = topology_physical_package_id(cpu_dev->id);
  280. init.name = dev_name(cpu_dev);
  281. init.ops = &clk_clc_ops;
  282. init.flags = CLK_IS_ROOT | CLK_GET_RATE_NOCACHE;
  283. init.num_parents = 0;
  284. return devm_clk_register(cpu_dev, &clc->hw);
  285. }
  286. static int mb86s7x_clclk_of_init(void)
  287. {
  288. int cpu, ret = -ENODEV;
  289. struct device_node *np;
  290. struct clk *clk;
  291. np = of_find_compatible_node(NULL, NULL, "fujitsu,mb86s70-scb-1.0");
  292. if (!np || !of_device_is_available(np))
  293. goto exit;
  294. for_each_possible_cpu(cpu) {
  295. struct device *cpu_dev = get_cpu_device(cpu);
  296. if (!cpu_dev) {
  297. pr_err("failed to get cpu%d device\n", cpu);
  298. continue;
  299. }
  300. clk = mb86s7x_clclk_register(cpu_dev);
  301. if (IS_ERR(clk)) {
  302. pr_err("failed to register cpu%d clock\n", cpu);
  303. continue;
  304. }
  305. if (clk_register_clkdev(clk, NULL, dev_name(cpu_dev))) {
  306. pr_err("failed to register cpu%d clock lookup\n", cpu);
  307. continue;
  308. }
  309. pr_debug("registered clk for %s\n", dev_name(cpu_dev));
  310. }
  311. ret = 0;
  312. platform_device_register_simple("arm-bL-cpufreq-dt", -1, NULL, 0);
  313. exit:
  314. of_node_put(np);
  315. return ret;
  316. }
  317. module_init(mb86s7x_clclk_of_init);