clk-bpmp.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2016 NVIDIA Corporation
  4. */
  5. #include <linux/clk-provider.h>
  6. #include <linux/device.h>
  7. #include <linux/seq_buf.h>
  8. #include <linux/slab.h>
  9. #include <soc/tegra/bpmp.h>
  10. #include <soc/tegra/bpmp-abi.h>
  11. #define TEGRA_BPMP_DUMP_CLOCK_INFO 0
  12. #define TEGRA_BPMP_CLK_HAS_MUX BIT(0)
  13. #define TEGRA_BPMP_CLK_HAS_SET_RATE BIT(1)
  14. #define TEGRA_BPMP_CLK_IS_ROOT BIT(2)
  15. struct tegra_bpmp_clk_info {
  16. unsigned int id;
  17. char name[MRQ_CLK_NAME_MAXLEN];
  18. unsigned int parents[MRQ_CLK_MAX_PARENTS];
  19. unsigned int num_parents;
  20. unsigned long flags;
  21. };
  22. struct tegra_bpmp_clk {
  23. struct clk_hw hw;
  24. struct tegra_bpmp *bpmp;
  25. unsigned int id;
  26. unsigned int num_parents;
  27. unsigned int *parents;
  28. };
  29. static inline struct tegra_bpmp_clk *to_tegra_bpmp_clk(struct clk_hw *hw)
  30. {
  31. return container_of(hw, struct tegra_bpmp_clk, hw);
  32. }
  33. struct tegra_bpmp_clk_message {
  34. unsigned int cmd;
  35. unsigned int id;
  36. struct {
  37. const void *data;
  38. size_t size;
  39. } tx;
  40. struct {
  41. void *data;
  42. size_t size;
  43. int ret;
  44. } rx;
  45. };
  46. static int tegra_bpmp_clk_transfer(struct tegra_bpmp *bpmp,
  47. const struct tegra_bpmp_clk_message *clk)
  48. {
  49. struct mrq_clk_request request;
  50. struct tegra_bpmp_message msg;
  51. void *req = &request;
  52. int err;
  53. memset(&request, 0, sizeof(request));
  54. request.cmd_and_id = (clk->cmd << 24) | clk->id;
  55. /*
  56. * The mrq_clk_request structure has an anonymous union at offset 4
  57. * that contains all possible sub-command structures. Copy the data
  58. * to that union. Ideally we'd be able to refer to it by name, but
  59. * doing so would require changing the ABI header and increase the
  60. * maintenance burden.
  61. */
  62. memcpy(req + 4, clk->tx.data, clk->tx.size);
  63. memset(&msg, 0, sizeof(msg));
  64. msg.mrq = MRQ_CLK;
  65. msg.tx.data = &request;
  66. msg.tx.size = sizeof(request);
  67. msg.rx.data = clk->rx.data;
  68. msg.rx.size = clk->rx.size;
  69. err = tegra_bpmp_transfer(bpmp, &msg);
  70. if (err < 0)
  71. return err;
  72. else if (msg.rx.ret < 0)
  73. return -EINVAL;
  74. return 0;
  75. }
  76. static int tegra_bpmp_clk_prepare(struct clk_hw *hw)
  77. {
  78. struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
  79. struct tegra_bpmp_clk_message msg;
  80. memset(&msg, 0, sizeof(msg));
  81. msg.cmd = CMD_CLK_ENABLE;
  82. msg.id = clk->id;
  83. return tegra_bpmp_clk_transfer(clk->bpmp, &msg);
  84. }
  85. static void tegra_bpmp_clk_unprepare(struct clk_hw *hw)
  86. {
  87. struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
  88. struct tegra_bpmp_clk_message msg;
  89. int err;
  90. memset(&msg, 0, sizeof(msg));
  91. msg.cmd = CMD_CLK_DISABLE;
  92. msg.id = clk->id;
  93. err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
  94. if (err < 0)
  95. dev_err(clk->bpmp->dev, "failed to disable clock %s: %d\n",
  96. clk_hw_get_name(hw), err);
  97. }
  98. static int tegra_bpmp_clk_is_prepared(struct clk_hw *hw)
  99. {
  100. struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
  101. struct cmd_clk_is_enabled_response response;
  102. struct tegra_bpmp_clk_message msg;
  103. int err;
  104. memset(&msg, 0, sizeof(msg));
  105. msg.cmd = CMD_CLK_IS_ENABLED;
  106. msg.id = clk->id;
  107. msg.rx.data = &response;
  108. msg.rx.size = sizeof(response);
  109. err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
  110. if (err < 0)
  111. return err;
  112. return response.state;
  113. }
  114. static unsigned long tegra_bpmp_clk_recalc_rate(struct clk_hw *hw,
  115. unsigned long parent_rate)
  116. {
  117. struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
  118. struct cmd_clk_get_rate_response response;
  119. struct cmd_clk_get_rate_request request;
  120. struct tegra_bpmp_clk_message msg;
  121. int err;
  122. memset(&msg, 0, sizeof(msg));
  123. msg.cmd = CMD_CLK_GET_RATE;
  124. msg.id = clk->id;
  125. msg.tx.data = &request;
  126. msg.tx.size = sizeof(request);
  127. msg.rx.data = &response;
  128. msg.rx.size = sizeof(response);
  129. err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
  130. if (err < 0)
  131. return err;
  132. return response.rate;
  133. }
  134. static long tegra_bpmp_clk_round_rate(struct clk_hw *hw, unsigned long rate,
  135. unsigned long *parent_rate)
  136. {
  137. struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
  138. struct cmd_clk_round_rate_response response;
  139. struct cmd_clk_round_rate_request request;
  140. struct tegra_bpmp_clk_message msg;
  141. int err;
  142. memset(&request, 0, sizeof(request));
  143. request.rate = rate;
  144. memset(&msg, 0, sizeof(msg));
  145. msg.cmd = CMD_CLK_ROUND_RATE;
  146. msg.id = clk->id;
  147. msg.tx.data = &request;
  148. msg.tx.size = sizeof(request);
  149. msg.rx.data = &response;
  150. msg.rx.size = sizeof(response);
  151. err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
  152. if (err < 0)
  153. return err;
  154. return response.rate;
  155. }
  156. static int tegra_bpmp_clk_set_parent(struct clk_hw *hw, u8 index)
  157. {
  158. struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
  159. struct cmd_clk_set_parent_response response;
  160. struct cmd_clk_set_parent_request request;
  161. struct tegra_bpmp_clk_message msg;
  162. int err;
  163. memset(&request, 0, sizeof(request));
  164. request.parent_id = clk->parents[index];
  165. memset(&msg, 0, sizeof(msg));
  166. msg.cmd = CMD_CLK_SET_PARENT;
  167. msg.id = clk->id;
  168. msg.tx.data = &request;
  169. msg.tx.size = sizeof(request);
  170. msg.rx.data = &response;
  171. msg.rx.size = sizeof(response);
  172. err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
  173. if (err < 0)
  174. return err;
  175. /* XXX check parent ID in response */
  176. return 0;
  177. }
  178. static u8 tegra_bpmp_clk_get_parent(struct clk_hw *hw)
  179. {
  180. struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
  181. struct cmd_clk_get_parent_response response;
  182. struct tegra_bpmp_clk_message msg;
  183. unsigned int i;
  184. int err;
  185. memset(&msg, 0, sizeof(msg));
  186. msg.cmd = CMD_CLK_GET_PARENT;
  187. msg.id = clk->id;
  188. msg.rx.data = &response;
  189. msg.rx.size = sizeof(response);
  190. err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
  191. if (err < 0) {
  192. dev_err(clk->bpmp->dev, "failed to get parent for %s: %d\n",
  193. clk_hw_get_name(hw), err);
  194. return U8_MAX;
  195. }
  196. for (i = 0; i < clk->num_parents; i++)
  197. if (clk->parents[i] == response.parent_id)
  198. return i;
  199. return U8_MAX;
  200. }
  201. static int tegra_bpmp_clk_set_rate(struct clk_hw *hw, unsigned long rate,
  202. unsigned long parent_rate)
  203. {
  204. struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
  205. struct cmd_clk_set_rate_response response;
  206. struct cmd_clk_set_rate_request request;
  207. struct tegra_bpmp_clk_message msg;
  208. memset(&request, 0, sizeof(request));
  209. request.rate = rate;
  210. memset(&msg, 0, sizeof(msg));
  211. msg.cmd = CMD_CLK_SET_RATE;
  212. msg.id = clk->id;
  213. msg.tx.data = &request;
  214. msg.tx.size = sizeof(request);
  215. msg.rx.data = &response;
  216. msg.rx.size = sizeof(response);
  217. return tegra_bpmp_clk_transfer(clk->bpmp, &msg);
  218. }
  219. static const struct clk_ops tegra_bpmp_clk_gate_ops = {
  220. .prepare = tegra_bpmp_clk_prepare,
  221. .unprepare = tegra_bpmp_clk_unprepare,
  222. .is_prepared = tegra_bpmp_clk_is_prepared,
  223. .recalc_rate = tegra_bpmp_clk_recalc_rate,
  224. };
  225. static const struct clk_ops tegra_bpmp_clk_mux_ops = {
  226. .prepare = tegra_bpmp_clk_prepare,
  227. .unprepare = tegra_bpmp_clk_unprepare,
  228. .is_prepared = tegra_bpmp_clk_is_prepared,
  229. .recalc_rate = tegra_bpmp_clk_recalc_rate,
  230. .set_parent = tegra_bpmp_clk_set_parent,
  231. .get_parent = tegra_bpmp_clk_get_parent,
  232. };
  233. static const struct clk_ops tegra_bpmp_clk_rate_ops = {
  234. .prepare = tegra_bpmp_clk_prepare,
  235. .unprepare = tegra_bpmp_clk_unprepare,
  236. .is_prepared = tegra_bpmp_clk_is_prepared,
  237. .recalc_rate = tegra_bpmp_clk_recalc_rate,
  238. .round_rate = tegra_bpmp_clk_round_rate,
  239. .set_rate = tegra_bpmp_clk_set_rate,
  240. };
  241. static const struct clk_ops tegra_bpmp_clk_mux_rate_ops = {
  242. .prepare = tegra_bpmp_clk_prepare,
  243. .unprepare = tegra_bpmp_clk_unprepare,
  244. .is_prepared = tegra_bpmp_clk_is_prepared,
  245. .recalc_rate = tegra_bpmp_clk_recalc_rate,
  246. .round_rate = tegra_bpmp_clk_round_rate,
  247. .set_parent = tegra_bpmp_clk_set_parent,
  248. .get_parent = tegra_bpmp_clk_get_parent,
  249. .set_rate = tegra_bpmp_clk_set_rate,
  250. };
  251. static int tegra_bpmp_clk_get_max_id(struct tegra_bpmp *bpmp)
  252. {
  253. struct cmd_clk_get_max_clk_id_response response;
  254. struct tegra_bpmp_clk_message msg;
  255. int err;
  256. memset(&msg, 0, sizeof(msg));
  257. msg.cmd = CMD_CLK_GET_MAX_CLK_ID;
  258. msg.rx.data = &response;
  259. msg.rx.size = sizeof(response);
  260. err = tegra_bpmp_clk_transfer(bpmp, &msg);
  261. if (err < 0)
  262. return err;
  263. if (response.max_id > INT_MAX)
  264. return -E2BIG;
  265. return response.max_id;
  266. }
  267. static int tegra_bpmp_clk_get_info(struct tegra_bpmp *bpmp, unsigned int id,
  268. struct tegra_bpmp_clk_info *info)
  269. {
  270. struct cmd_clk_get_all_info_response response;
  271. struct tegra_bpmp_clk_message msg;
  272. unsigned int i;
  273. int err;
  274. memset(&msg, 0, sizeof(msg));
  275. msg.cmd = CMD_CLK_GET_ALL_INFO;
  276. msg.id = id;
  277. msg.rx.data = &response;
  278. msg.rx.size = sizeof(response);
  279. err = tegra_bpmp_clk_transfer(bpmp, &msg);
  280. if (err < 0)
  281. return err;
  282. strlcpy(info->name, response.name, MRQ_CLK_NAME_MAXLEN);
  283. info->num_parents = response.num_parents;
  284. for (i = 0; i < info->num_parents; i++)
  285. info->parents[i] = response.parents[i];
  286. info->flags = response.flags;
  287. return 0;
  288. }
  289. static void tegra_bpmp_clk_info_dump(struct tegra_bpmp *bpmp,
  290. const char *level,
  291. const struct tegra_bpmp_clk_info *info)
  292. {
  293. const char *prefix = "";
  294. struct seq_buf buf;
  295. unsigned int i;
  296. char flags[64];
  297. seq_buf_init(&buf, flags, sizeof(flags));
  298. if (info->flags)
  299. seq_buf_printf(&buf, "(");
  300. if (info->flags & TEGRA_BPMP_CLK_HAS_MUX) {
  301. seq_buf_printf(&buf, "%smux", prefix);
  302. prefix = ", ";
  303. }
  304. if ((info->flags & TEGRA_BPMP_CLK_HAS_SET_RATE) == 0) {
  305. seq_buf_printf(&buf, "%sfixed", prefix);
  306. prefix = ", ";
  307. }
  308. if (info->flags & TEGRA_BPMP_CLK_IS_ROOT) {
  309. seq_buf_printf(&buf, "%sroot", prefix);
  310. prefix = ", ";
  311. }
  312. if (info->flags)
  313. seq_buf_printf(&buf, ")");
  314. dev_printk(level, bpmp->dev, "%03u: %s\n", info->id, info->name);
  315. dev_printk(level, bpmp->dev, " flags: %lx %s\n", info->flags, flags);
  316. dev_printk(level, bpmp->dev, " parents: %u\n", info->num_parents);
  317. for (i = 0; i < info->num_parents; i++)
  318. dev_printk(level, bpmp->dev, " %03u\n", info->parents[i]);
  319. }
  320. static int tegra_bpmp_probe_clocks(struct tegra_bpmp *bpmp,
  321. struct tegra_bpmp_clk_info **clocksp)
  322. {
  323. struct tegra_bpmp_clk_info *clocks;
  324. unsigned int max_id, id, count = 0;
  325. unsigned int holes = 0;
  326. int err;
  327. err = tegra_bpmp_clk_get_max_id(bpmp);
  328. if (err < 0)
  329. return err;
  330. max_id = err;
  331. dev_dbg(bpmp->dev, "maximum clock ID: %u\n", max_id);
  332. clocks = kcalloc(max_id + 1, sizeof(*clocks), GFP_KERNEL);
  333. if (!clocks)
  334. return -ENOMEM;
  335. for (id = 0; id <= max_id; id++) {
  336. struct tegra_bpmp_clk_info *info = &clocks[count];
  337. err = tegra_bpmp_clk_get_info(bpmp, id, info);
  338. if (err < 0)
  339. continue;
  340. if (info->num_parents >= U8_MAX) {
  341. dev_err(bpmp->dev,
  342. "clock %u has too many parents (%u, max: %u)\n",
  343. id, info->num_parents, U8_MAX);
  344. continue;
  345. }
  346. /* clock not exposed by BPMP */
  347. if (info->name[0] == '\0') {
  348. holes++;
  349. continue;
  350. }
  351. info->id = id;
  352. count++;
  353. if (TEGRA_BPMP_DUMP_CLOCK_INFO)
  354. tegra_bpmp_clk_info_dump(bpmp, KERN_DEBUG, info);
  355. }
  356. dev_dbg(bpmp->dev, "holes: %u\n", holes);
  357. *clocksp = clocks;
  358. return count;
  359. }
  360. static const struct tegra_bpmp_clk_info *
  361. tegra_bpmp_clk_find(const struct tegra_bpmp_clk_info *clocks,
  362. unsigned int num_clocks, unsigned int id)
  363. {
  364. unsigned int i;
  365. for (i = 0; i < num_clocks; i++)
  366. if (clocks[i].id == id)
  367. return &clocks[i];
  368. return NULL;
  369. }
  370. static struct tegra_bpmp_clk *
  371. tegra_bpmp_clk_register(struct tegra_bpmp *bpmp,
  372. const struct tegra_bpmp_clk_info *info,
  373. const struct tegra_bpmp_clk_info *clocks,
  374. unsigned int num_clocks)
  375. {
  376. struct tegra_bpmp_clk *clk;
  377. struct clk_init_data init;
  378. const char **parents;
  379. unsigned int i;
  380. int err;
  381. clk = devm_kzalloc(bpmp->dev, sizeof(*clk), GFP_KERNEL);
  382. if (!clk)
  383. return ERR_PTR(-ENOMEM);
  384. clk->id = info->id;
  385. clk->bpmp = bpmp;
  386. clk->parents = devm_kcalloc(bpmp->dev, info->num_parents,
  387. sizeof(*clk->parents), GFP_KERNEL);
  388. if (!clk->parents)
  389. return ERR_PTR(-ENOMEM);
  390. clk->num_parents = info->num_parents;
  391. /* hardware clock initialization */
  392. memset(&init, 0, sizeof(init));
  393. init.name = info->name;
  394. clk->hw.init = &init;
  395. if (info->flags & TEGRA_BPMP_CLK_HAS_MUX) {
  396. if (info->flags & TEGRA_BPMP_CLK_HAS_SET_RATE)
  397. init.ops = &tegra_bpmp_clk_mux_rate_ops;
  398. else
  399. init.ops = &tegra_bpmp_clk_mux_ops;
  400. } else {
  401. if (info->flags & TEGRA_BPMP_CLK_HAS_SET_RATE)
  402. init.ops = &tegra_bpmp_clk_rate_ops;
  403. else
  404. init.ops = &tegra_bpmp_clk_gate_ops;
  405. }
  406. init.num_parents = info->num_parents;
  407. parents = kcalloc(info->num_parents, sizeof(*parents), GFP_KERNEL);
  408. if (!parents)
  409. return ERR_PTR(-ENOMEM);
  410. for (i = 0; i < info->num_parents; i++) {
  411. const struct tegra_bpmp_clk_info *parent;
  412. /* keep a private copy of the ID to parent index map */
  413. clk->parents[i] = info->parents[i];
  414. parent = tegra_bpmp_clk_find(clocks, num_clocks,
  415. info->parents[i]);
  416. if (!parent) {
  417. dev_err(bpmp->dev, "no parent %u found for %u\n",
  418. info->parents[i], info->id);
  419. continue;
  420. }
  421. parents[i] = parent->name;
  422. }
  423. init.parent_names = parents;
  424. err = devm_clk_hw_register(bpmp->dev, &clk->hw);
  425. kfree(parents);
  426. if (err < 0)
  427. return ERR_PTR(err);
  428. return clk;
  429. }
  430. static int tegra_bpmp_register_clocks(struct tegra_bpmp *bpmp,
  431. struct tegra_bpmp_clk_info *infos,
  432. unsigned int count)
  433. {
  434. struct tegra_bpmp_clk *clk;
  435. unsigned int i;
  436. bpmp->num_clocks = count;
  437. bpmp->clocks = devm_kcalloc(bpmp->dev, count, sizeof(clk), GFP_KERNEL);
  438. if (!bpmp->clocks)
  439. return -ENOMEM;
  440. for (i = 0; i < count; i++) {
  441. struct tegra_bpmp_clk_info *info = &infos[i];
  442. clk = tegra_bpmp_clk_register(bpmp, info, infos, count);
  443. if (IS_ERR(clk)) {
  444. dev_err(bpmp->dev,
  445. "failed to register clock %u (%s): %ld\n",
  446. info->id, info->name, PTR_ERR(clk));
  447. continue;
  448. }
  449. bpmp->clocks[i] = clk;
  450. }
  451. return 0;
  452. }
  453. static void tegra_bpmp_unregister_clocks(struct tegra_bpmp *bpmp)
  454. {
  455. unsigned int i;
  456. for (i = 0; i < bpmp->num_clocks; i++)
  457. clk_hw_unregister(&bpmp->clocks[i]->hw);
  458. }
  459. static struct clk_hw *tegra_bpmp_clk_of_xlate(struct of_phandle_args *clkspec,
  460. void *data)
  461. {
  462. unsigned int id = clkspec->args[0], i;
  463. struct tegra_bpmp *bpmp = data;
  464. for (i = 0; i < bpmp->num_clocks; i++) {
  465. struct tegra_bpmp_clk *clk = bpmp->clocks[i];
  466. if (!clk)
  467. continue;
  468. if (clk->id == id)
  469. return &clk->hw;
  470. }
  471. return NULL;
  472. }
  473. int tegra_bpmp_init_clocks(struct tegra_bpmp *bpmp)
  474. {
  475. struct tegra_bpmp_clk_info *clocks;
  476. unsigned int count;
  477. int err;
  478. err = tegra_bpmp_probe_clocks(bpmp, &clocks);
  479. if (err < 0)
  480. return err;
  481. count = err;
  482. dev_dbg(bpmp->dev, "%u clocks probed\n", count);
  483. err = tegra_bpmp_register_clocks(bpmp, clocks, count);
  484. if (err < 0)
  485. goto free;
  486. err = of_clk_add_hw_provider(bpmp->dev->of_node,
  487. tegra_bpmp_clk_of_xlate,
  488. bpmp);
  489. if (err < 0) {
  490. tegra_bpmp_unregister_clocks(bpmp);
  491. goto free;
  492. }
  493. free:
  494. kfree(clocks);
  495. return err;
  496. }