powergate-bpmp.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved
  4. */
  5. #include <linux/of.h>
  6. #include <linux/platform_device.h>
  7. #include <linux/pm_domain.h>
  8. #include <linux/slab.h>
  9. #include <soc/tegra/bpmp.h>
  10. #include <soc/tegra/bpmp-abi.h>
  11. struct tegra_powergate_info {
  12. unsigned int id;
  13. char *name;
  14. };
  15. struct tegra_powergate {
  16. struct generic_pm_domain genpd;
  17. struct tegra_bpmp *bpmp;
  18. unsigned int id;
  19. };
  20. static inline struct tegra_powergate *
  21. to_tegra_powergate(struct generic_pm_domain *genpd)
  22. {
  23. return container_of(genpd, struct tegra_powergate, genpd);
  24. }
  25. static int tegra_bpmp_powergate_set_state(struct tegra_bpmp *bpmp,
  26. unsigned int id, u32 state)
  27. {
  28. struct mrq_pg_request request;
  29. struct tegra_bpmp_message msg;
  30. int err;
  31. memset(&request, 0, sizeof(request));
  32. request.cmd = CMD_PG_SET_STATE;
  33. request.id = id;
  34. request.set_state.state = state;
  35. memset(&msg, 0, sizeof(msg));
  36. msg.mrq = MRQ_PG;
  37. msg.tx.data = &request;
  38. msg.tx.size = sizeof(request);
  39. err = tegra_bpmp_transfer(bpmp, &msg);
  40. if (err < 0)
  41. return err;
  42. else if (msg.rx.ret < 0)
  43. return -EINVAL;
  44. return 0;
  45. }
  46. static int tegra_bpmp_powergate_get_state(struct tegra_bpmp *bpmp,
  47. unsigned int id)
  48. {
  49. struct mrq_pg_response response;
  50. struct mrq_pg_request request;
  51. struct tegra_bpmp_message msg;
  52. int err;
  53. memset(&request, 0, sizeof(request));
  54. request.cmd = CMD_PG_GET_STATE;
  55. request.id = id;
  56. memset(&response, 0, sizeof(response));
  57. memset(&msg, 0, sizeof(msg));
  58. msg.mrq = MRQ_PG;
  59. msg.tx.data = &request;
  60. msg.tx.size = sizeof(request);
  61. msg.rx.data = &response;
  62. msg.rx.size = sizeof(response);
  63. err = tegra_bpmp_transfer(bpmp, &msg);
  64. if (err < 0)
  65. return PG_STATE_OFF;
  66. else if (msg.rx.ret < 0)
  67. return -EINVAL;
  68. return response.get_state.state;
  69. }
  70. static int tegra_bpmp_powergate_get_max_id(struct tegra_bpmp *bpmp)
  71. {
  72. struct mrq_pg_response response;
  73. struct mrq_pg_request request;
  74. struct tegra_bpmp_message msg;
  75. int err;
  76. memset(&request, 0, sizeof(request));
  77. request.cmd = CMD_PG_GET_MAX_ID;
  78. memset(&response, 0, sizeof(response));
  79. memset(&msg, 0, sizeof(msg));
  80. msg.mrq = MRQ_PG;
  81. msg.tx.data = &request;
  82. msg.tx.size = sizeof(request);
  83. msg.rx.data = &response;
  84. msg.rx.size = sizeof(response);
  85. err = tegra_bpmp_transfer(bpmp, &msg);
  86. if (err < 0)
  87. return err;
  88. else if (msg.rx.ret < 0)
  89. return -EINVAL;
  90. return response.get_max_id.max_id;
  91. }
  92. static char *tegra_bpmp_powergate_get_name(struct tegra_bpmp *bpmp,
  93. unsigned int id)
  94. {
  95. struct mrq_pg_response response;
  96. struct mrq_pg_request request;
  97. struct tegra_bpmp_message msg;
  98. int err;
  99. memset(&request, 0, sizeof(request));
  100. request.cmd = CMD_PG_GET_NAME;
  101. request.id = id;
  102. memset(&response, 0, sizeof(response));
  103. memset(&msg, 0, sizeof(msg));
  104. msg.mrq = MRQ_PG;
  105. msg.tx.data = &request;
  106. msg.tx.size = sizeof(request);
  107. msg.rx.data = &response;
  108. msg.rx.size = sizeof(response);
  109. err = tegra_bpmp_transfer(bpmp, &msg);
  110. if (err < 0 || msg.rx.ret < 0)
  111. return NULL;
  112. return kstrdup(response.get_name.name, GFP_KERNEL);
  113. }
  114. static inline bool tegra_bpmp_powergate_is_powered(struct tegra_bpmp *bpmp,
  115. unsigned int id)
  116. {
  117. return tegra_bpmp_powergate_get_state(bpmp, id) != PG_STATE_OFF;
  118. }
  119. static int tegra_powergate_power_on(struct generic_pm_domain *domain)
  120. {
  121. struct tegra_powergate *powergate = to_tegra_powergate(domain);
  122. struct tegra_bpmp *bpmp = powergate->bpmp;
  123. return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
  124. PG_STATE_ON);
  125. }
  126. static int tegra_powergate_power_off(struct generic_pm_domain *domain)
  127. {
  128. struct tegra_powergate *powergate = to_tegra_powergate(domain);
  129. struct tegra_bpmp *bpmp = powergate->bpmp;
  130. return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
  131. PG_STATE_OFF);
  132. }
  133. static struct tegra_powergate *
  134. tegra_powergate_add(struct tegra_bpmp *bpmp,
  135. const struct tegra_powergate_info *info)
  136. {
  137. struct tegra_powergate *powergate;
  138. bool off;
  139. int err;
  140. off = !tegra_bpmp_powergate_is_powered(bpmp, info->id);
  141. powergate = devm_kzalloc(bpmp->dev, sizeof(*powergate), GFP_KERNEL);
  142. if (!powergate)
  143. return ERR_PTR(-ENOMEM);
  144. powergate->id = info->id;
  145. powergate->bpmp = bpmp;
  146. powergate->genpd.name = kstrdup(info->name, GFP_KERNEL);
  147. powergate->genpd.power_on = tegra_powergate_power_on;
  148. powergate->genpd.power_off = tegra_powergate_power_off;
  149. err = pm_genpd_init(&powergate->genpd, NULL, off);
  150. if (err < 0) {
  151. kfree(powergate->genpd.name);
  152. return ERR_PTR(err);
  153. }
  154. return powergate;
  155. }
  156. static void tegra_powergate_remove(struct tegra_powergate *powergate)
  157. {
  158. struct generic_pm_domain *genpd = &powergate->genpd;
  159. struct tegra_bpmp *bpmp = powergate->bpmp;
  160. int err;
  161. err = pm_genpd_remove(genpd);
  162. if (err < 0)
  163. dev_err(bpmp->dev, "failed to remove power domain %s: %d\n",
  164. genpd->name, err);
  165. kfree(genpd->name);
  166. }
  167. static int
  168. tegra_bpmp_probe_powergates(struct tegra_bpmp *bpmp,
  169. struct tegra_powergate_info **powergatesp)
  170. {
  171. struct tegra_powergate_info *powergates;
  172. unsigned int max_id, id, count = 0;
  173. unsigned int num_holes = 0;
  174. int err;
  175. err = tegra_bpmp_powergate_get_max_id(bpmp);
  176. if (err < 0)
  177. return err;
  178. max_id = err;
  179. dev_dbg(bpmp->dev, "maximum powergate ID: %u\n", max_id);
  180. powergates = kcalloc(max_id + 1, sizeof(*powergates), GFP_KERNEL);
  181. if (!powergates)
  182. return -ENOMEM;
  183. for (id = 0; id <= max_id; id++) {
  184. struct tegra_powergate_info *info = &powergates[count];
  185. info->name = tegra_bpmp_powergate_get_name(bpmp, id);
  186. if (!info->name || info->name[0] == '\0') {
  187. num_holes++;
  188. continue;
  189. }
  190. info->id = id;
  191. count++;
  192. }
  193. dev_dbg(bpmp->dev, "holes: %u\n", num_holes);
  194. *powergatesp = powergates;
  195. return count;
  196. }
  197. static int tegra_bpmp_add_powergates(struct tegra_bpmp *bpmp,
  198. struct tegra_powergate_info *powergates,
  199. unsigned int count)
  200. {
  201. struct genpd_onecell_data *genpd = &bpmp->genpd;
  202. struct generic_pm_domain **domains;
  203. struct tegra_powergate *powergate;
  204. unsigned int i;
  205. int err;
  206. domains = kcalloc(count, sizeof(*domains), GFP_KERNEL);
  207. if (!domains)
  208. return -ENOMEM;
  209. for (i = 0; i < count; i++) {
  210. powergate = tegra_powergate_add(bpmp, &powergates[i]);
  211. if (IS_ERR(powergate)) {
  212. err = PTR_ERR(powergate);
  213. goto remove;
  214. }
  215. dev_dbg(bpmp->dev, "added power domain %s\n",
  216. powergate->genpd.name);
  217. domains[i] = &powergate->genpd;
  218. }
  219. genpd->num_domains = count;
  220. genpd->domains = domains;
  221. return 0;
  222. remove:
  223. while (i--) {
  224. powergate = to_tegra_powergate(domains[i]);
  225. tegra_powergate_remove(powergate);
  226. }
  227. kfree(genpd->domains);
  228. return err;
  229. }
  230. static void tegra_bpmp_remove_powergates(struct tegra_bpmp *bpmp)
  231. {
  232. struct genpd_onecell_data *genpd = &bpmp->genpd;
  233. unsigned int i = genpd->num_domains;
  234. struct tegra_powergate *powergate;
  235. while (i--) {
  236. dev_dbg(bpmp->dev, "removing power domain %s\n",
  237. genpd->domains[i]->name);
  238. powergate = to_tegra_powergate(genpd->domains[i]);
  239. tegra_powergate_remove(powergate);
  240. }
  241. }
  242. static struct generic_pm_domain *
  243. tegra_powergate_xlate(struct of_phandle_args *spec, void *data)
  244. {
  245. struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
  246. struct genpd_onecell_data *genpd = data;
  247. unsigned int i;
  248. for (i = 0; i < genpd->num_domains; i++) {
  249. struct tegra_powergate *powergate;
  250. powergate = to_tegra_powergate(genpd->domains[i]);
  251. if (powergate->id == spec->args[0]) {
  252. domain = &powergate->genpd;
  253. break;
  254. }
  255. }
  256. return domain;
  257. }
  258. int tegra_bpmp_init_powergates(struct tegra_bpmp *bpmp)
  259. {
  260. struct device_node *np = bpmp->dev->of_node;
  261. struct tegra_powergate_info *powergates;
  262. struct device *dev = bpmp->dev;
  263. unsigned int count, i;
  264. int err;
  265. err = tegra_bpmp_probe_powergates(bpmp, &powergates);
  266. if (err < 0)
  267. return err;
  268. count = err;
  269. dev_dbg(dev, "%u power domains probed\n", count);
  270. err = tegra_bpmp_add_powergates(bpmp, powergates, count);
  271. if (err < 0)
  272. goto free;
  273. bpmp->genpd.xlate = tegra_powergate_xlate;
  274. err = of_genpd_add_provider_onecell(np, &bpmp->genpd);
  275. if (err < 0) {
  276. dev_err(dev, "failed to add power domain provider: %d\n", err);
  277. tegra_bpmp_remove_powergates(bpmp);
  278. }
  279. free:
  280. for (i = 0; i < count; i++)
  281. kfree(powergates[i].name);
  282. kfree(powergates);
  283. return err;
  284. }