gpcv2.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2017 Impinj, Inc
  4. * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
  5. *
  6. * Based on the code of analogus driver:
  7. *
  8. * Copyright 2015-2017 Pengutronix, Lucas Stach <kernel@pengutronix.de>
  9. */
  10. #include <linux/clk.h>
  11. #include <linux/of_device.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/pm_domain.h>
  14. #include <linux/regmap.h>
  15. #include <linux/regulator/consumer.h>
  16. #include <linux/sizes.h>
  17. #include <dt-bindings/power/imx7-power.h>
  18. #include <dt-bindings/power/imx8mq-power.h>
  19. #define GPC_LPCR_A_CORE_BSC 0x000
  20. #define GPC_PGC_CPU_MAPPING 0x0ec
  21. #define IMX7_USB_HSIC_PHY_A_CORE_DOMAIN BIT(6)
  22. #define IMX7_USB_OTG2_PHY_A_CORE_DOMAIN BIT(5)
  23. #define IMX7_USB_OTG1_PHY_A_CORE_DOMAIN BIT(4)
  24. #define IMX7_PCIE_PHY_A_CORE_DOMAIN BIT(3)
  25. #define IMX7_MIPI_PHY_A_CORE_DOMAIN BIT(2)
  26. #define IMX8M_PCIE2_A53_DOMAIN BIT(15)
  27. #define IMX8M_MIPI_CSI2_A53_DOMAIN BIT(14)
  28. #define IMX8M_MIPI_CSI1_A53_DOMAIN BIT(13)
  29. #define IMX8M_DISP_A53_DOMAIN BIT(12)
  30. #define IMX8M_HDMI_A53_DOMAIN BIT(11)
  31. #define IMX8M_VPU_A53_DOMAIN BIT(10)
  32. #define IMX8M_GPU_A53_DOMAIN BIT(9)
  33. #define IMX8M_DDR2_A53_DOMAIN BIT(8)
  34. #define IMX8M_DDR1_A53_DOMAIN BIT(7)
  35. #define IMX8M_OTG2_A53_DOMAIN BIT(5)
  36. #define IMX8M_OTG1_A53_DOMAIN BIT(4)
  37. #define IMX8M_PCIE1_A53_DOMAIN BIT(3)
  38. #define IMX8M_MIPI_A53_DOMAIN BIT(2)
  39. #define GPC_PU_PGC_SW_PUP_REQ 0x0f8
  40. #define GPC_PU_PGC_SW_PDN_REQ 0x104
  41. #define IMX7_USB_HSIC_PHY_SW_Pxx_REQ BIT(4)
  42. #define IMX7_USB_OTG2_PHY_SW_Pxx_REQ BIT(3)
  43. #define IMX7_USB_OTG1_PHY_SW_Pxx_REQ BIT(2)
  44. #define IMX7_PCIE_PHY_SW_Pxx_REQ BIT(1)
  45. #define IMX7_MIPI_PHY_SW_Pxx_REQ BIT(0)
  46. #define IMX8M_PCIE2_SW_Pxx_REQ BIT(13)
  47. #define IMX8M_MIPI_CSI2_SW_Pxx_REQ BIT(12)
  48. #define IMX8M_MIPI_CSI1_SW_Pxx_REQ BIT(11)
  49. #define IMX8M_DISP_SW_Pxx_REQ BIT(10)
  50. #define IMX8M_HDMI_SW_Pxx_REQ BIT(9)
  51. #define IMX8M_VPU_SW_Pxx_REQ BIT(8)
  52. #define IMX8M_GPU_SW_Pxx_REQ BIT(7)
  53. #define IMX8M_DDR2_SW_Pxx_REQ BIT(6)
  54. #define IMX8M_DDR1_SW_Pxx_REQ BIT(5)
  55. #define IMX8M_OTG2_SW_Pxx_REQ BIT(3)
  56. #define IMX8M_OTG1_SW_Pxx_REQ BIT(2)
  57. #define IMX8M_PCIE1_SW_Pxx_REQ BIT(1)
  58. #define IMX8M_MIPI_SW_Pxx_REQ BIT(0)
  59. #define GPC_M4_PU_PDN_FLG 0x1bc
  60. #define GPC_PU_PWRHSK 0x1fc
  61. #define IMX8M_GPU_HSK_PWRDNREQN BIT(6)
  62. #define IMX8M_VPU_HSK_PWRDNREQN BIT(5)
  63. #define IMX8M_DISP_HSK_PWRDNREQN BIT(4)
  64. /*
  65. * The PGC offset values in Reference Manual
  66. * (Rev. 1, 01/2018 and the older ones) GPC chapter's
  67. * GPC_PGC memory map are incorrect, below offset
  68. * values are from design RTL.
  69. */
  70. #define IMX7_PGC_MIPI 16
  71. #define IMX7_PGC_PCIE 17
  72. #define IMX7_PGC_USB_HSIC 20
  73. #define IMX8M_PGC_MIPI 16
  74. #define IMX8M_PGC_PCIE1 17
  75. #define IMX8M_PGC_OTG1 18
  76. #define IMX8M_PGC_OTG2 19
  77. #define IMX8M_PGC_DDR1 21
  78. #define IMX8M_PGC_GPU 23
  79. #define IMX8M_PGC_VPU 24
  80. #define IMX8M_PGC_DISP 26
  81. #define IMX8M_PGC_MIPI_CSI1 27
  82. #define IMX8M_PGC_MIPI_CSI2 28
  83. #define IMX8M_PGC_PCIE2 29
  84. #define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40)
  85. #define GPC_PGC_SR(n) (GPC_PGC_CTRL(n) + 0xc)
  86. #define GPC_PGC_CTRL_PCR BIT(0)
  87. #define GPC_CLK_MAX 6
  88. struct imx_pgc_domain {
  89. struct generic_pm_domain genpd;
  90. struct regmap *regmap;
  91. struct regulator *regulator;
  92. struct clk *clk[GPC_CLK_MAX];
  93. int num_clks;
  94. unsigned int pgc;
  95. const struct {
  96. u32 pxx;
  97. u32 map;
  98. u32 hsk;
  99. } bits;
  100. const int voltage;
  101. struct device *dev;
  102. };
  103. struct imx_pgc_domain_data {
  104. const struct imx_pgc_domain *domains;
  105. size_t domains_num;
  106. const struct regmap_access_table *reg_access_table;
  107. };
  108. static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
  109. bool on)
  110. {
  111. struct imx_pgc_domain *domain = container_of(genpd,
  112. struct imx_pgc_domain,
  113. genpd);
  114. unsigned int offset = on ?
  115. GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ;
  116. const bool enable_power_control = !on;
  117. const bool has_regulator = !IS_ERR(domain->regulator);
  118. int i, ret = 0;
  119. u32 pxx_req;
  120. regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING,
  121. domain->bits.map, domain->bits.map);
  122. if (has_regulator && on) {
  123. ret = regulator_enable(domain->regulator);
  124. if (ret) {
  125. dev_err(domain->dev, "failed to enable regulator\n");
  126. goto unmap;
  127. }
  128. }
  129. /* Enable reset clocks for all devices in the domain */
  130. for (i = 0; i < domain->num_clks; i++)
  131. clk_prepare_enable(domain->clk[i]);
  132. if (enable_power_control)
  133. regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc),
  134. GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR);
  135. if (domain->bits.hsk)
  136. regmap_update_bits(domain->regmap, GPC_PU_PWRHSK,
  137. domain->bits.hsk, on ? domain->bits.hsk : 0);
  138. regmap_update_bits(domain->regmap, offset,
  139. domain->bits.pxx, domain->bits.pxx);
  140. /*
  141. * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
  142. * for PUP_REQ/PDN_REQ bit to be cleared
  143. */
  144. ret = regmap_read_poll_timeout(domain->regmap, offset, pxx_req,
  145. !(pxx_req & domain->bits.pxx),
  146. 0, USEC_PER_MSEC);
  147. if (ret) {
  148. dev_err(domain->dev, "failed to command PGC\n");
  149. /*
  150. * If we were in a process of enabling a
  151. * domain and failed we might as well disable
  152. * the regulator we just enabled. And if it
  153. * was the opposite situation and we failed to
  154. * power down -- keep the regulator on
  155. */
  156. on = !on;
  157. }
  158. if (enable_power_control)
  159. regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc),
  160. GPC_PGC_CTRL_PCR, 0);
  161. /* Disable reset clocks for all devices in the domain */
  162. for (i = 0; i < domain->num_clks; i++)
  163. clk_disable_unprepare(domain->clk[i]);
  164. if (has_regulator && !on) {
  165. int err;
  166. err = regulator_disable(domain->regulator);
  167. if (err)
  168. dev_err(domain->dev,
  169. "failed to disable regulator: %d\n", err);
  170. /* Preserve earlier error code */
  171. ret = ret ?: err;
  172. }
  173. unmap:
  174. regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING,
  175. domain->bits.map, 0);
  176. return ret;
  177. }
  178. static int imx_gpc_pu_pgc_sw_pup_req(struct generic_pm_domain *genpd)
  179. {
  180. return imx_gpc_pu_pgc_sw_pxx_req(genpd, true);
  181. }
  182. static int imx_gpc_pu_pgc_sw_pdn_req(struct generic_pm_domain *genpd)
  183. {
  184. return imx_gpc_pu_pgc_sw_pxx_req(genpd, false);
  185. }
  186. static const struct imx_pgc_domain imx7_pgc_domains[] = {
  187. [IMX7_POWER_DOMAIN_MIPI_PHY] = {
  188. .genpd = {
  189. .name = "mipi-phy",
  190. },
  191. .bits = {
  192. .pxx = IMX7_MIPI_PHY_SW_Pxx_REQ,
  193. .map = IMX7_MIPI_PHY_A_CORE_DOMAIN,
  194. },
  195. .voltage = 1000000,
  196. .pgc = IMX7_PGC_MIPI,
  197. },
  198. [IMX7_POWER_DOMAIN_PCIE_PHY] = {
  199. .genpd = {
  200. .name = "pcie-phy",
  201. },
  202. .bits = {
  203. .pxx = IMX7_PCIE_PHY_SW_Pxx_REQ,
  204. .map = IMX7_PCIE_PHY_A_CORE_DOMAIN,
  205. },
  206. .voltage = 1000000,
  207. .pgc = IMX7_PGC_PCIE,
  208. },
  209. [IMX7_POWER_DOMAIN_USB_HSIC_PHY] = {
  210. .genpd = {
  211. .name = "usb-hsic-phy",
  212. },
  213. .bits = {
  214. .pxx = IMX7_USB_HSIC_PHY_SW_Pxx_REQ,
  215. .map = IMX7_USB_HSIC_PHY_A_CORE_DOMAIN,
  216. },
  217. .voltage = 1200000,
  218. .pgc = IMX7_PGC_USB_HSIC,
  219. },
  220. };
  221. static const struct regmap_range imx7_yes_ranges[] = {
  222. regmap_reg_range(GPC_LPCR_A_CORE_BSC,
  223. GPC_M4_PU_PDN_FLG),
  224. regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_MIPI),
  225. GPC_PGC_SR(IMX7_PGC_MIPI)),
  226. regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_PCIE),
  227. GPC_PGC_SR(IMX7_PGC_PCIE)),
  228. regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_USB_HSIC),
  229. GPC_PGC_SR(IMX7_PGC_USB_HSIC)),
  230. };
  231. static const struct regmap_access_table imx7_access_table = {
  232. .yes_ranges = imx7_yes_ranges,
  233. .n_yes_ranges = ARRAY_SIZE(imx7_yes_ranges),
  234. };
  235. static const struct imx_pgc_domain_data imx7_pgc_domain_data = {
  236. .domains = imx7_pgc_domains,
  237. .domains_num = ARRAY_SIZE(imx7_pgc_domains),
  238. .reg_access_table = &imx7_access_table,
  239. };
  240. static const struct imx_pgc_domain imx8m_pgc_domains[] = {
  241. [IMX8M_POWER_DOMAIN_MIPI] = {
  242. .genpd = {
  243. .name = "mipi",
  244. },
  245. .bits = {
  246. .pxx = IMX8M_MIPI_SW_Pxx_REQ,
  247. .map = IMX8M_MIPI_A53_DOMAIN,
  248. },
  249. .pgc = IMX8M_PGC_MIPI,
  250. },
  251. [IMX8M_POWER_DOMAIN_PCIE1] = {
  252. .genpd = {
  253. .name = "pcie1",
  254. },
  255. .bits = {
  256. .pxx = IMX8M_PCIE1_SW_Pxx_REQ,
  257. .map = IMX8M_PCIE1_A53_DOMAIN,
  258. },
  259. .pgc = IMX8M_PGC_PCIE1,
  260. },
  261. [IMX8M_POWER_DOMAIN_USB_OTG1] = {
  262. .genpd = {
  263. .name = "usb-otg1",
  264. },
  265. .bits = {
  266. .pxx = IMX8M_OTG1_SW_Pxx_REQ,
  267. .map = IMX8M_OTG1_A53_DOMAIN,
  268. },
  269. .pgc = IMX8M_PGC_OTG1,
  270. },
  271. [IMX8M_POWER_DOMAIN_USB_OTG2] = {
  272. .genpd = {
  273. .name = "usb-otg2",
  274. },
  275. .bits = {
  276. .pxx = IMX8M_OTG2_SW_Pxx_REQ,
  277. .map = IMX8M_OTG2_A53_DOMAIN,
  278. },
  279. .pgc = IMX8M_PGC_OTG2,
  280. },
  281. [IMX8M_POWER_DOMAIN_DDR1] = {
  282. .genpd = {
  283. .name = "ddr1",
  284. },
  285. .bits = {
  286. .pxx = IMX8M_DDR1_SW_Pxx_REQ,
  287. .map = IMX8M_DDR2_A53_DOMAIN,
  288. },
  289. .pgc = IMX8M_PGC_DDR1,
  290. },
  291. [IMX8M_POWER_DOMAIN_GPU] = {
  292. .genpd = {
  293. .name = "gpu",
  294. },
  295. .bits = {
  296. .pxx = IMX8M_GPU_SW_Pxx_REQ,
  297. .map = IMX8M_GPU_A53_DOMAIN,
  298. .hsk = IMX8M_GPU_HSK_PWRDNREQN,
  299. },
  300. .pgc = IMX8M_PGC_GPU,
  301. },
  302. [IMX8M_POWER_DOMAIN_VPU] = {
  303. .genpd = {
  304. .name = "vpu",
  305. },
  306. .bits = {
  307. .pxx = IMX8M_VPU_SW_Pxx_REQ,
  308. .map = IMX8M_VPU_A53_DOMAIN,
  309. .hsk = IMX8M_VPU_HSK_PWRDNREQN,
  310. },
  311. .pgc = IMX8M_PGC_VPU,
  312. },
  313. [IMX8M_POWER_DOMAIN_DISP] = {
  314. .genpd = {
  315. .name = "disp",
  316. },
  317. .bits = {
  318. .pxx = IMX8M_DISP_SW_Pxx_REQ,
  319. .map = IMX8M_DISP_A53_DOMAIN,
  320. .hsk = IMX8M_DISP_HSK_PWRDNREQN,
  321. },
  322. .pgc = IMX8M_PGC_DISP,
  323. },
  324. [IMX8M_POWER_DOMAIN_MIPI_CSI1] = {
  325. .genpd = {
  326. .name = "mipi-csi1",
  327. },
  328. .bits = {
  329. .pxx = IMX8M_MIPI_CSI1_SW_Pxx_REQ,
  330. .map = IMX8M_MIPI_CSI1_A53_DOMAIN,
  331. },
  332. .pgc = IMX8M_PGC_MIPI_CSI1,
  333. },
  334. [IMX8M_POWER_DOMAIN_MIPI_CSI2] = {
  335. .genpd = {
  336. .name = "mipi-csi2",
  337. },
  338. .bits = {
  339. .pxx = IMX8M_MIPI_CSI2_SW_Pxx_REQ,
  340. .map = IMX8M_MIPI_CSI2_A53_DOMAIN,
  341. },
  342. .pgc = IMX8M_PGC_MIPI_CSI2,
  343. },
  344. [IMX8M_POWER_DOMAIN_PCIE2] = {
  345. .genpd = {
  346. .name = "pcie2",
  347. },
  348. .bits = {
  349. .pxx = IMX8M_PCIE2_SW_Pxx_REQ,
  350. .map = IMX8M_PCIE2_A53_DOMAIN,
  351. },
  352. .pgc = IMX8M_PGC_PCIE2,
  353. },
  354. };
  355. static const struct regmap_range imx8m_yes_ranges[] = {
  356. regmap_reg_range(GPC_LPCR_A_CORE_BSC,
  357. GPC_PU_PWRHSK),
  358. regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_MIPI),
  359. GPC_PGC_SR(IMX8M_PGC_MIPI)),
  360. regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_PCIE1),
  361. GPC_PGC_SR(IMX8M_PGC_PCIE1)),
  362. regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_OTG1),
  363. GPC_PGC_SR(IMX8M_PGC_OTG1)),
  364. regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_OTG2),
  365. GPC_PGC_SR(IMX8M_PGC_OTG2)),
  366. regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_DDR1),
  367. GPC_PGC_SR(IMX8M_PGC_DDR1)),
  368. regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_GPU),
  369. GPC_PGC_SR(IMX8M_PGC_GPU)),
  370. regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_VPU),
  371. GPC_PGC_SR(IMX8M_PGC_VPU)),
  372. regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_DISP),
  373. GPC_PGC_SR(IMX8M_PGC_DISP)),
  374. regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_MIPI_CSI1),
  375. GPC_PGC_SR(IMX8M_PGC_MIPI_CSI1)),
  376. regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_MIPI_CSI2),
  377. GPC_PGC_SR(IMX8M_PGC_MIPI_CSI2)),
  378. regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_PCIE2),
  379. GPC_PGC_SR(IMX8M_PGC_PCIE2)),
  380. };
  381. static const struct regmap_access_table imx8m_access_table = {
  382. .yes_ranges = imx8m_yes_ranges,
  383. .n_yes_ranges = ARRAY_SIZE(imx8m_yes_ranges),
  384. };
  385. static const struct imx_pgc_domain_data imx8m_pgc_domain_data = {
  386. .domains = imx8m_pgc_domains,
  387. .domains_num = ARRAY_SIZE(imx8m_pgc_domains),
  388. .reg_access_table = &imx8m_access_table,
  389. };
  390. static int imx_pgc_get_clocks(struct imx_pgc_domain *domain)
  391. {
  392. int i, ret;
  393. for (i = 0; ; i++) {
  394. struct clk *clk = of_clk_get(domain->dev->of_node, i);
  395. if (IS_ERR(clk))
  396. break;
  397. if (i >= GPC_CLK_MAX) {
  398. dev_err(domain->dev, "more than %d clocks\n",
  399. GPC_CLK_MAX);
  400. ret = -EINVAL;
  401. goto clk_err;
  402. }
  403. domain->clk[i] = clk;
  404. }
  405. domain->num_clks = i;
  406. return 0;
  407. clk_err:
  408. while (i--)
  409. clk_put(domain->clk[i]);
  410. return ret;
  411. }
  412. static void imx_pgc_put_clocks(struct imx_pgc_domain *domain)
  413. {
  414. int i;
  415. for (i = domain->num_clks - 1; i >= 0; i--)
  416. clk_put(domain->clk[i]);
  417. }
  418. static int imx_pgc_domain_probe(struct platform_device *pdev)
  419. {
  420. struct imx_pgc_domain *domain = pdev->dev.platform_data;
  421. int ret;
  422. domain->dev = &pdev->dev;
  423. domain->regulator = devm_regulator_get_optional(domain->dev, "power");
  424. if (IS_ERR(domain->regulator)) {
  425. if (PTR_ERR(domain->regulator) != -ENODEV)
  426. return dev_err_probe(domain->dev, PTR_ERR(domain->regulator),
  427. "Failed to get domain's regulator\n");
  428. } else if (domain->voltage) {
  429. regulator_set_voltage(domain->regulator,
  430. domain->voltage, domain->voltage);
  431. }
  432. ret = imx_pgc_get_clocks(domain);
  433. if (ret)
  434. return dev_err_probe(domain->dev, ret, "Failed to get domain's clocks\n");
  435. ret = pm_genpd_init(&domain->genpd, NULL, true);
  436. if (ret) {
  437. dev_err(domain->dev, "Failed to init power domain\n");
  438. imx_pgc_put_clocks(domain);
  439. return ret;
  440. }
  441. ret = of_genpd_add_provider_simple(domain->dev->of_node,
  442. &domain->genpd);
  443. if (ret) {
  444. dev_err(domain->dev, "Failed to add genpd provider\n");
  445. pm_genpd_remove(&domain->genpd);
  446. imx_pgc_put_clocks(domain);
  447. }
  448. return ret;
  449. }
  450. static int imx_pgc_domain_remove(struct platform_device *pdev)
  451. {
  452. struct imx_pgc_domain *domain = pdev->dev.platform_data;
  453. of_genpd_del_provider(domain->dev->of_node);
  454. pm_genpd_remove(&domain->genpd);
  455. imx_pgc_put_clocks(domain);
  456. return 0;
  457. }
  458. static const struct platform_device_id imx_pgc_domain_id[] = {
  459. { "imx-pgc-domain", },
  460. { },
  461. };
  462. static struct platform_driver imx_pgc_domain_driver = {
  463. .driver = {
  464. .name = "imx-pgc",
  465. },
  466. .probe = imx_pgc_domain_probe,
  467. .remove = imx_pgc_domain_remove,
  468. .id_table = imx_pgc_domain_id,
  469. };
  470. builtin_platform_driver(imx_pgc_domain_driver)
  471. static int imx_gpcv2_probe(struct platform_device *pdev)
  472. {
  473. const struct imx_pgc_domain_data *domain_data =
  474. of_device_get_match_data(&pdev->dev);
  475. struct regmap_config regmap_config = {
  476. .reg_bits = 32,
  477. .val_bits = 32,
  478. .reg_stride = 4,
  479. .rd_table = domain_data->reg_access_table,
  480. .wr_table = domain_data->reg_access_table,
  481. .max_register = SZ_4K,
  482. };
  483. struct device *dev = &pdev->dev;
  484. struct device_node *pgc_np, *np;
  485. struct regmap *regmap;
  486. void __iomem *base;
  487. int ret;
  488. pgc_np = of_get_child_by_name(dev->of_node, "pgc");
  489. if (!pgc_np) {
  490. dev_err(dev, "No power domains specified in DT\n");
  491. return -EINVAL;
  492. }
  493. base = devm_platform_ioremap_resource(pdev, 0);
  494. if (IS_ERR(base))
  495. return PTR_ERR(base);
  496. regmap = devm_regmap_init_mmio(dev, base, &regmap_config);
  497. if (IS_ERR(regmap)) {
  498. ret = PTR_ERR(regmap);
  499. dev_err(dev, "failed to init regmap (%d)\n", ret);
  500. return ret;
  501. }
  502. for_each_child_of_node(pgc_np, np) {
  503. struct platform_device *pd_pdev;
  504. struct imx_pgc_domain *domain;
  505. u32 domain_index;
  506. ret = of_property_read_u32(np, "reg", &domain_index);
  507. if (ret) {
  508. dev_err(dev, "Failed to read 'reg' property\n");
  509. of_node_put(np);
  510. return ret;
  511. }
  512. if (domain_index >= domain_data->domains_num) {
  513. dev_warn(dev,
  514. "Domain index %d is out of bounds\n",
  515. domain_index);
  516. continue;
  517. }
  518. pd_pdev = platform_device_alloc("imx-pgc-domain",
  519. domain_index);
  520. if (!pd_pdev) {
  521. dev_err(dev, "Failed to allocate platform device\n");
  522. of_node_put(np);
  523. return -ENOMEM;
  524. }
  525. ret = platform_device_add_data(pd_pdev,
  526. &domain_data->domains[domain_index],
  527. sizeof(domain_data->domains[domain_index]));
  528. if (ret) {
  529. platform_device_put(pd_pdev);
  530. of_node_put(np);
  531. return ret;
  532. }
  533. domain = pd_pdev->dev.platform_data;
  534. domain->regmap = regmap;
  535. domain->genpd.power_on = imx_gpc_pu_pgc_sw_pup_req;
  536. domain->genpd.power_off = imx_gpc_pu_pgc_sw_pdn_req;
  537. pd_pdev->dev.parent = dev;
  538. pd_pdev->dev.of_node = np;
  539. ret = platform_device_add(pd_pdev);
  540. if (ret) {
  541. platform_device_put(pd_pdev);
  542. of_node_put(np);
  543. return ret;
  544. }
  545. }
  546. return 0;
  547. }
  548. static const struct of_device_id imx_gpcv2_dt_ids[] = {
  549. { .compatible = "fsl,imx7d-gpc", .data = &imx7_pgc_domain_data, },
  550. { .compatible = "fsl,imx8mq-gpc", .data = &imx8m_pgc_domain_data, },
  551. { }
  552. };
  553. static struct platform_driver imx_gpc_driver = {
  554. .driver = {
  555. .name = "imx-gpcv2",
  556. .of_match_table = imx_gpcv2_dt_ids,
  557. },
  558. .probe = imx_gpcv2_probe,
  559. };
  560. builtin_platform_driver(imx_gpc_driver)