powergate-bpmp.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  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. powergate->genpd.flags = GENPD_FLAG_NO_STAY_ON;
  150. err = pm_genpd_init(&powergate->genpd, NULL, off);
  151. if (err < 0) {
  152. kfree(powergate->genpd.name);
  153. return ERR_PTR(err);
  154. }
  155. return powergate;
  156. }
  157. static void tegra_powergate_remove(struct tegra_powergate *powergate)
  158. {
  159. struct generic_pm_domain *genpd = &powergate->genpd;
  160. struct tegra_bpmp *bpmp = powergate->bpmp;
  161. int err;
  162. err = pm_genpd_remove(genpd);
  163. if (err < 0)
  164. dev_err(bpmp->dev, "failed to remove power domain %s: %d\n",
  165. genpd->name, err);
  166. kfree(genpd->name);
  167. }
  168. static int
  169. tegra_bpmp_probe_powergates(struct tegra_bpmp *bpmp,
  170. struct tegra_powergate_info **powergatesp)
  171. {
  172. struct tegra_powergate_info *powergates;
  173. unsigned int max_id, id, count = 0;
  174. unsigned int num_holes = 0;
  175. int err;
  176. err = tegra_bpmp_powergate_get_max_id(bpmp);
  177. if (err < 0)
  178. return err;
  179. max_id = err;
  180. dev_dbg(bpmp->dev, "maximum powergate ID: %u\n", max_id);
  181. powergates = kzalloc_objs(*powergates, max_id + 1);
  182. if (!powergates)
  183. return -ENOMEM;
  184. for (id = 0; id <= max_id; id++) {
  185. struct tegra_powergate_info *info = &powergates[count];
  186. info->name = tegra_bpmp_powergate_get_name(bpmp, id);
  187. if (!info->name || info->name[0] == '\0') {
  188. num_holes++;
  189. continue;
  190. }
  191. info->id = id;
  192. count++;
  193. }
  194. dev_dbg(bpmp->dev, "holes: %u\n", num_holes);
  195. *powergatesp = powergates;
  196. return count;
  197. }
  198. static int tegra_bpmp_add_powergates(struct tegra_bpmp *bpmp,
  199. struct tegra_powergate_info *powergates,
  200. unsigned int count)
  201. {
  202. struct genpd_onecell_data *genpd = &bpmp->genpd;
  203. struct generic_pm_domain **domains;
  204. struct tegra_powergate *powergate;
  205. unsigned int i;
  206. int err;
  207. domains = kzalloc_objs(*domains, count);
  208. if (!domains)
  209. return -ENOMEM;
  210. for (i = 0; i < count; i++) {
  211. powergate = tegra_powergate_add(bpmp, &powergates[i]);
  212. if (IS_ERR(powergate)) {
  213. err = PTR_ERR(powergate);
  214. goto remove;
  215. }
  216. dev_dbg(bpmp->dev, "added power domain %s\n",
  217. powergate->genpd.name);
  218. domains[i] = &powergate->genpd;
  219. }
  220. genpd->num_domains = count;
  221. genpd->domains = domains;
  222. return 0;
  223. remove:
  224. while (i--) {
  225. powergate = to_tegra_powergate(domains[i]);
  226. tegra_powergate_remove(powergate);
  227. }
  228. kfree(domains);
  229. return err;
  230. }
  231. static void tegra_bpmp_remove_powergates(struct tegra_bpmp *bpmp)
  232. {
  233. struct genpd_onecell_data *genpd = &bpmp->genpd;
  234. unsigned int i = genpd->num_domains;
  235. struct tegra_powergate *powergate;
  236. while (i--) {
  237. dev_dbg(bpmp->dev, "removing power domain %s\n",
  238. genpd->domains[i]->name);
  239. powergate = to_tegra_powergate(genpd->domains[i]);
  240. tegra_powergate_remove(powergate);
  241. }
  242. }
  243. static struct generic_pm_domain *
  244. tegra_powergate_xlate(const struct of_phandle_args *spec, void *data)
  245. {
  246. struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
  247. struct genpd_onecell_data *genpd = data;
  248. unsigned int i;
  249. for (i = 0; i < genpd->num_domains; i++) {
  250. struct tegra_powergate *powergate;
  251. powergate = to_tegra_powergate(genpd->domains[i]);
  252. if (powergate->id == spec->args[0]) {
  253. domain = &powergate->genpd;
  254. break;
  255. }
  256. }
  257. return domain;
  258. }
  259. int tegra_bpmp_init_powergates(struct tegra_bpmp *bpmp)
  260. {
  261. struct device_node *np = bpmp->dev->of_node;
  262. struct tegra_powergate_info *powergates;
  263. struct device *dev = bpmp->dev;
  264. unsigned int count, i;
  265. int err;
  266. err = tegra_bpmp_probe_powergates(bpmp, &powergates);
  267. if (err < 0)
  268. return err;
  269. count = err;
  270. dev_dbg(dev, "%u power domains probed\n", count);
  271. err = tegra_bpmp_add_powergates(bpmp, powergates, count);
  272. if (err < 0)
  273. goto free;
  274. bpmp->genpd.xlate = tegra_powergate_xlate;
  275. err = of_genpd_add_provider_onecell(np, &bpmp->genpd);
  276. if (err < 0) {
  277. dev_err(dev, "failed to add power domain provider: %d\n", err);
  278. tegra_bpmp_remove_powergates(bpmp);
  279. }
  280. free:
  281. for (i = 0; i < count; i++)
  282. kfree(powergates[i].name);
  283. kfree(powergates);
  284. return err;
  285. }