mtk-power-domain.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2018 MediaTek Inc.
  4. * Author: Ryder Lee <ryder.lee@mediatek.com>
  5. */
  6. #include <clk.h>
  7. #include <common.h>
  8. #include <dm.h>
  9. #include <malloc.h>
  10. #include <power-domain-uclass.h>
  11. #include <regmap.h>
  12. #include <syscon.h>
  13. #include <asm/io.h>
  14. #include <asm/processor.h>
  15. #include <linux/bitops.h>
  16. #include <linux/err.h>
  17. #include <linux/iopoll.h>
  18. #include <dt-bindings/power/mt7623-power.h>
  19. #include <dt-bindings/power/mt7629-power.h>
  20. #define SPM_EN (0xb16 << 16 | 0x1)
  21. #define SPM_VDE_PWR_CON 0x0210
  22. #define SPM_MFG_PWR_CON 0x0214
  23. #define SPM_ISP_PWR_CON 0x0238
  24. #define SPM_DIS_PWR_CON 0x023c
  25. #define SPM_CONN_PWR_CON 0x0280
  26. #define SPM_BDP_PWR_CON 0x029c
  27. #define SPM_ETH_PWR_CON 0x02a0
  28. #define SPM_HIF_PWR_CON 0x02a4
  29. #define SPM_IFR_MSC_PWR_CON 0x02a8
  30. #define SPM_ETHSYS_PWR_CON 0x2e0
  31. #define SPM_HIF0_PWR_CON 0x2e4
  32. #define SPM_HIF1_PWR_CON 0x2e8
  33. #define SPM_PWR_STATUS 0x60c
  34. #define SPM_PWR_STATUS_2ND 0x610
  35. #define PWR_RST_B_BIT BIT(0)
  36. #define PWR_ISO_BIT BIT(1)
  37. #define PWR_ON_BIT BIT(2)
  38. #define PWR_ON_2ND_BIT BIT(3)
  39. #define PWR_CLK_DIS_BIT BIT(4)
  40. #define PWR_STATUS_CONN BIT(1)
  41. #define PWR_STATUS_DISP BIT(3)
  42. #define PWR_STATUS_MFG BIT(4)
  43. #define PWR_STATUS_ISP BIT(5)
  44. #define PWR_STATUS_VDEC BIT(7)
  45. #define PWR_STATUS_BDP BIT(14)
  46. #define PWR_STATUS_ETH BIT(15)
  47. #define PWR_STATUS_HIF BIT(16)
  48. #define PWR_STATUS_IFR_MSC BIT(17)
  49. #define PWR_STATUS_ETHSYS BIT(24)
  50. #define PWR_STATUS_HIF0 BIT(25)
  51. #define PWR_STATUS_HIF1 BIT(26)
  52. /* Infrasys configuration */
  53. #define INFRA_TOPDCM_CTRL 0x10
  54. #define INFRA_TOPAXI_PROT_EN 0x220
  55. #define INFRA_TOPAXI_PROT_STA1 0x228
  56. #define DCM_TOP_EN BIT(0)
  57. enum scp_domain_type {
  58. SCPSYS_MT7622,
  59. SCPSYS_MT7623,
  60. SCPSYS_MT7629,
  61. };
  62. struct scp_domain;
  63. struct scp_domain_data {
  64. struct scp_domain *scpd;
  65. u32 sta_mask;
  66. int ctl_offs;
  67. u32 sram_pdn_bits;
  68. u32 sram_pdn_ack_bits;
  69. u32 bus_prot_mask;
  70. };
  71. struct scp_domain {
  72. void __iomem *base;
  73. void __iomem *infracfg;
  74. enum scp_domain_type type;
  75. struct scp_domain_data *data;
  76. };
  77. static struct scp_domain_data scp_domain_mt7623[] = {
  78. [MT7623_POWER_DOMAIN_CONN] = {
  79. .sta_mask = PWR_STATUS_CONN,
  80. .ctl_offs = SPM_CONN_PWR_CON,
  81. .bus_prot_mask = BIT(8) | BIT(2),
  82. },
  83. [MT7623_POWER_DOMAIN_DISP] = {
  84. .sta_mask = PWR_STATUS_DISP,
  85. .ctl_offs = SPM_DIS_PWR_CON,
  86. .sram_pdn_bits = GENMASK(11, 8),
  87. .bus_prot_mask = BIT(2),
  88. },
  89. [MT7623_POWER_DOMAIN_MFG] = {
  90. .sta_mask = PWR_STATUS_MFG,
  91. .ctl_offs = SPM_MFG_PWR_CON,
  92. .sram_pdn_bits = GENMASK(11, 8),
  93. .sram_pdn_ack_bits = GENMASK(12, 12),
  94. },
  95. [MT7623_POWER_DOMAIN_VDEC] = {
  96. .sta_mask = PWR_STATUS_VDEC,
  97. .ctl_offs = SPM_VDE_PWR_CON,
  98. .sram_pdn_bits = GENMASK(11, 8),
  99. .sram_pdn_ack_bits = GENMASK(12, 12),
  100. },
  101. [MT7623_POWER_DOMAIN_ISP] = {
  102. .sta_mask = PWR_STATUS_ISP,
  103. .ctl_offs = SPM_ISP_PWR_CON,
  104. .sram_pdn_bits = GENMASK(11, 8),
  105. .sram_pdn_ack_bits = GENMASK(13, 12),
  106. },
  107. [MT7623_POWER_DOMAIN_BDP] = {
  108. .sta_mask = PWR_STATUS_BDP,
  109. .ctl_offs = SPM_BDP_PWR_CON,
  110. .sram_pdn_bits = GENMASK(11, 8),
  111. },
  112. [MT7623_POWER_DOMAIN_ETH] = {
  113. .sta_mask = PWR_STATUS_ETH,
  114. .ctl_offs = SPM_ETH_PWR_CON,
  115. .sram_pdn_bits = GENMASK(11, 8),
  116. .sram_pdn_ack_bits = GENMASK(15, 12),
  117. },
  118. [MT7623_POWER_DOMAIN_HIF] = {
  119. .sta_mask = PWR_STATUS_HIF,
  120. .ctl_offs = SPM_HIF_PWR_CON,
  121. .sram_pdn_bits = GENMASK(11, 8),
  122. .sram_pdn_ack_bits = GENMASK(15, 12),
  123. },
  124. [MT7623_POWER_DOMAIN_IFR_MSC] = {
  125. .sta_mask = PWR_STATUS_IFR_MSC,
  126. .ctl_offs = SPM_IFR_MSC_PWR_CON,
  127. },
  128. };
  129. static struct scp_domain_data scp_domain_mt7629[] = {
  130. [MT7629_POWER_DOMAIN_ETHSYS] = {
  131. .sta_mask = PWR_STATUS_ETHSYS,
  132. .ctl_offs = SPM_ETHSYS_PWR_CON,
  133. .sram_pdn_bits = GENMASK(11, 8),
  134. .sram_pdn_ack_bits = GENMASK(15, 12),
  135. .bus_prot_mask = (BIT(3) | BIT(17)),
  136. },
  137. [MT7629_POWER_DOMAIN_HIF0] = {
  138. .sta_mask = PWR_STATUS_HIF0,
  139. .ctl_offs = SPM_HIF0_PWR_CON,
  140. .sram_pdn_bits = GENMASK(11, 8),
  141. .sram_pdn_ack_bits = GENMASK(15, 12),
  142. .bus_prot_mask = GENMASK(25, 24),
  143. },
  144. [MT7629_POWER_DOMAIN_HIF1] = {
  145. .sta_mask = PWR_STATUS_HIF1,
  146. .ctl_offs = SPM_HIF1_PWR_CON,
  147. .sram_pdn_bits = GENMASK(11, 8),
  148. .sram_pdn_ack_bits = GENMASK(15, 12),
  149. .bus_prot_mask = GENMASK(28, 26),
  150. },
  151. };
  152. /**
  153. * This function enables the bus protection bits for disabled power
  154. * domains so that the system does not hang when some unit accesses the
  155. * bus while in power down.
  156. */
  157. static int mtk_infracfg_set_bus_protection(void __iomem *infracfg,
  158. u32 mask)
  159. {
  160. u32 val;
  161. clrsetbits_le32(infracfg + INFRA_TOPAXI_PROT_EN, mask, mask);
  162. return readl_poll_timeout(infracfg + INFRA_TOPAXI_PROT_STA1, val,
  163. (val & mask) == mask, 100);
  164. }
  165. static int mtk_infracfg_clear_bus_protection(void __iomem *infracfg,
  166. u32 mask)
  167. {
  168. u32 val;
  169. clrbits_le32(infracfg + INFRA_TOPAXI_PROT_EN, mask);
  170. return readl_poll_timeout(infracfg + INFRA_TOPAXI_PROT_STA1, val,
  171. !(val & mask), 100);
  172. }
  173. static int scpsys_domain_is_on(struct scp_domain_data *data)
  174. {
  175. struct scp_domain *scpd = data->scpd;
  176. u32 sta = readl(scpd->base + SPM_PWR_STATUS) &
  177. data->sta_mask;
  178. u32 sta2 = readl(scpd->base + SPM_PWR_STATUS_2ND) &
  179. data->sta_mask;
  180. /*
  181. * A domain is on when both status bits are set. If only one is set
  182. * return an error. This happens while powering up a domain
  183. */
  184. if (sta && sta2)
  185. return true;
  186. if (!sta && !sta2)
  187. return false;
  188. return -EINVAL;
  189. }
  190. static int scpsys_power_on(struct power_domain *power_domain)
  191. {
  192. struct scp_domain *scpd = dev_get_priv(power_domain->dev);
  193. struct scp_domain_data *data = &scpd->data[power_domain->id];
  194. void __iomem *ctl_addr = scpd->base + data->ctl_offs;
  195. u32 pdn_ack = data->sram_pdn_ack_bits;
  196. u32 val;
  197. int ret, tmp;
  198. writel(SPM_EN, scpd->base);
  199. val = readl(ctl_addr);
  200. val |= PWR_ON_BIT;
  201. writel(val, ctl_addr);
  202. val |= PWR_ON_2ND_BIT;
  203. writel(val, ctl_addr);
  204. ret = readx_poll_timeout(scpsys_domain_is_on, data, tmp, tmp > 0,
  205. 100);
  206. if (ret < 0)
  207. return ret;
  208. val &= ~PWR_CLK_DIS_BIT;
  209. writel(val, ctl_addr);
  210. val &= ~PWR_ISO_BIT;
  211. writel(val, ctl_addr);
  212. val |= PWR_RST_B_BIT;
  213. writel(val, ctl_addr);
  214. val &= ~data->sram_pdn_bits;
  215. writel(val, ctl_addr);
  216. ret = readl_poll_timeout(ctl_addr, tmp, !(tmp & pdn_ack), 100);
  217. if (ret < 0)
  218. return ret;
  219. if (data->bus_prot_mask) {
  220. ret = mtk_infracfg_clear_bus_protection(scpd->infracfg,
  221. data->bus_prot_mask);
  222. if (ret)
  223. return ret;
  224. }
  225. return 0;
  226. }
  227. static int scpsys_power_off(struct power_domain *power_domain)
  228. {
  229. struct scp_domain *scpd = dev_get_priv(power_domain->dev);
  230. struct scp_domain_data *data = &scpd->data[power_domain->id];
  231. void __iomem *ctl_addr = scpd->base + data->ctl_offs;
  232. u32 pdn_ack = data->sram_pdn_ack_bits;
  233. u32 val;
  234. int ret, tmp;
  235. if (data->bus_prot_mask) {
  236. ret = mtk_infracfg_set_bus_protection(scpd->infracfg,
  237. data->bus_prot_mask);
  238. if (ret)
  239. return ret;
  240. }
  241. val = readl(ctl_addr);
  242. val |= data->sram_pdn_bits;
  243. writel(val, ctl_addr);
  244. ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == pdn_ack,
  245. 100);
  246. if (ret < 0)
  247. return ret;
  248. val |= PWR_ISO_BIT;
  249. writel(val, ctl_addr);
  250. val &= ~PWR_RST_B_BIT;
  251. writel(val, ctl_addr);
  252. val |= PWR_CLK_DIS_BIT;
  253. writel(val, ctl_addr);
  254. val &= ~PWR_ON_BIT;
  255. writel(val, ctl_addr);
  256. val &= ~PWR_ON_2ND_BIT;
  257. writel(val, ctl_addr);
  258. ret = readx_poll_timeout(scpsys_domain_is_on, data, tmp, !tmp, 100);
  259. if (ret < 0)
  260. return ret;
  261. return 0;
  262. }
  263. static int scpsys_power_request(struct power_domain *power_domain)
  264. {
  265. struct scp_domain *scpd = dev_get_priv(power_domain->dev);
  266. struct scp_domain_data *data;
  267. data = &scpd->data[power_domain->id];
  268. data->scpd = scpd;
  269. return 0;
  270. }
  271. static int scpsys_power_free(struct power_domain *power_domain)
  272. {
  273. return 0;
  274. }
  275. static int mtk_power_domain_hook(struct udevice *dev)
  276. {
  277. struct scp_domain *scpd = dev_get_priv(dev);
  278. scpd->type = (enum scp_domain_type)dev_get_driver_data(dev);
  279. switch (scpd->type) {
  280. case SCPSYS_MT7623:
  281. scpd->data = scp_domain_mt7623;
  282. break;
  283. case SCPSYS_MT7622:
  284. case SCPSYS_MT7629:
  285. scpd->data = scp_domain_mt7629;
  286. break;
  287. default:
  288. return -EINVAL;
  289. }
  290. return 0;
  291. }
  292. static int mtk_power_domain_probe(struct udevice *dev)
  293. {
  294. struct ofnode_phandle_args args;
  295. struct scp_domain *scpd = dev_get_priv(dev);
  296. struct regmap *regmap;
  297. struct clk_bulk bulk;
  298. int err;
  299. scpd->base = dev_read_addr_ptr(dev);
  300. if (!scpd->base)
  301. return -ENOENT;
  302. err = mtk_power_domain_hook(dev);
  303. if (err)
  304. return err;
  305. /* get corresponding syscon phandle */
  306. err = dev_read_phandle_with_args(dev, "infracfg", NULL, 0, 0, &args);
  307. if (err)
  308. return err;
  309. regmap = syscon_node_to_regmap(args.node);
  310. if (IS_ERR(regmap))
  311. return PTR_ERR(regmap);
  312. scpd->infracfg = regmap_get_range(regmap, 0);
  313. if (!scpd->infracfg)
  314. return -ENOENT;
  315. /* enable Infra DCM */
  316. setbits_le32(scpd->infracfg + INFRA_TOPDCM_CTRL, DCM_TOP_EN);
  317. err = clk_get_bulk(dev, &bulk);
  318. if (err)
  319. return err;
  320. return clk_enable_bulk(&bulk);
  321. }
  322. static const struct udevice_id mtk_power_domain_ids[] = {
  323. {
  324. .compatible = "mediatek,mt7622-scpsys",
  325. .data = SCPSYS_MT7622,
  326. },
  327. {
  328. .compatible = "mediatek,mt7623-scpsys",
  329. .data = SCPSYS_MT7623,
  330. },
  331. {
  332. .compatible = "mediatek,mt7629-scpsys",
  333. .data = SCPSYS_MT7629,
  334. },
  335. { /* sentinel */ }
  336. };
  337. struct power_domain_ops mtk_power_domain_ops = {
  338. .rfree = scpsys_power_free,
  339. .off = scpsys_power_off,
  340. .on = scpsys_power_on,
  341. .request = scpsys_power_request,
  342. };
  343. U_BOOT_DRIVER(mtk_power_domain) = {
  344. .name = "mtk_power_domain",
  345. .id = UCLASS_POWER_DOMAIN,
  346. .ops = &mtk_power_domain_ops,
  347. .probe = mtk_power_domain_probe,
  348. .of_match = mtk_power_domain_ids,
  349. .priv_auto_alloc_size = sizeof(struct scp_domain),
  350. };