gpcv2.c 16 KB

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