Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'imx-drivers-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into arm/drivers

i.MX drivers update for 5.19:

- A series from Lucas and Paul to update GPCv2 driver for i.MX8MP power
domains, and add HSIO and HDMI block control support.

* tag 'imx-drivers-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux:
soc: imx: fix semicolon.cocci warnings
soc: imx: add i.MX8MP HDMI blk-ctrl
soc: imx: imx8m-blk-ctrl: Add i.MX8MP media blk-ctrl
soc: imx: add i.MX8MP HSIO blk-ctrl
dt-bindings: power: imx8mp: add defines for HDMI blk-ctrl domains
dt-bindings: soc: Add i.MX8MP media block control DT bindings
soc: imx: imx8m-blk-ctrl: set power device name
soc: imx: gpcv2: add support for i.MX8MP power domains
soc: imx: gpcv2: add PGC control register indirection

Link: https://lore.kernel.org/r/20220508033843.2773685-2-shawnguo@kernel.org
Signed-off-by: Arnd Bergmann <arnd@arndb.de>

+1359 -14
+104
Documentation/devicetree/bindings/soc/imx/fsl,imx8mp-media-blk-ctrl.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/soc/imx/fsl,imx8mp-media-blk-ctrl.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: NXP i.MX8MP Media Block Control 8 + 9 + maintainers: 10 + - Paul Elder <paul.elder@ideasonboard.com> 11 + 12 + description: 13 + The i.MX8MP Media Block Control (MEDIA BLK_CTRL) is a top-level peripheral 14 + providing access to the NoC and ensuring proper power sequencing of the 15 + peripherals within the MEDIAMIX domain. 16 + 17 + properties: 18 + compatible: 19 + items: 20 + - const: fsl,imx8mp-media-blk-ctrl 21 + - const: syscon 22 + 23 + reg: 24 + maxItems: 1 25 + 26 + '#power-domain-cells': 27 + const: 1 28 + 29 + power-domains: 30 + maxItems: 10 31 + 32 + power-domain-names: 33 + items: 34 + - const: bus 35 + - const: mipi-dsi1 36 + - const: mipi-csi1 37 + - const: lcdif1 38 + - const: isi 39 + - const: mipi-csi2 40 + - const: lcdif2 41 + - const: isp 42 + - const: dwe 43 + - const: mipi-dsi2 44 + 45 + clocks: 46 + items: 47 + - description: The APB clock 48 + - description: The AXI clock 49 + - description: The pixel clock for the first CSI2 receiver (aclk) 50 + - description: The pixel clock for the second CSI2 receiver (aclk) 51 + - description: The pixel clock for the first LCDIF (pix_clk) 52 + - description: The pixel clock for the second LCDIF (pix_clk) 53 + - description: The core clock for the ISP (clk) 54 + - description: The MIPI-PHY reference clock used by DSI 55 + 56 + clock-names: 57 + items: 58 + - const: apb 59 + - const: axi 60 + - const: cam1 61 + - const: cam2 62 + - const: disp1 63 + - const: disp2 64 + - const: isp 65 + - const: phy 66 + 67 + required: 68 + - compatible 69 + - reg 70 + - '#power-domain-cells' 71 + - power-domains 72 + - power-domain-names 73 + - clocks 74 + - clock-names 75 + 76 + additionalProperties: false 77 + 78 + examples: 79 + - | 80 + #include <dt-bindings/clock/imx8mp-clock.h> 81 + #include <dt-bindings/power/imx8mp-power.h> 82 + 83 + media_blk_ctl: blk-ctl@32ec0000 { 84 + compatible = "fsl,imx8mp-media-blk-ctrl", "syscon"; 85 + reg = <0x32ec0000 0x138>; 86 + power-domains = <&mediamix_pd>, <&mipi_phy1_pd>, <&mipi_phy1_pd>, 87 + <&mediamix_pd>, <&mediamix_pd>, <&mipi_phy2_pd>, 88 + <&mediamix_pd>, <&ispdwp_pd>, <&ispdwp_pd>, 89 + <&mipi_phy2_pd>; 90 + power-domain-names = "bus", "mipi-dsi1", "mipi-csi1", "lcdif1", "isi", 91 + "mipi-csi2", "lcdif2", "isp1", "dwe", "mipi-dsi2"; 92 + clocks = <&clk IMX8MP_CLK_MEDIA_APB_ROOT>, 93 + <&clk IMX8MP_CLK_MEDIA_AXI_ROOT>, 94 + <&clk IMX8MP_CLK_MEDIA_CAM1_PIX_ROOT>, 95 + <&clk IMX8MP_CLK_MEDIA_CAM2_PIX_ROOT>, 96 + <&clk IMX8MP_CLK_MEDIA_DISP1_PIX_ROOT>, 97 + <&clk IMX8MP_CLK_MEDIA_DISP2_PIX_ROOT>, 98 + <&clk IMX8MP_CLK_MEDIA_ISP_ROOT>, 99 + <&clk IMX8MP_CLK_MEDIA_MIPI_PHY1_REF_ROOT>; 100 + clock-names = "apb", "axi", "cam1", "cam2", "disp1", "disp2", 101 + "isp", "phy"; 102 + #power-domain-cells = <1>; 103 + }; 104 + ...
+1
drivers/soc/imx/Makefile
··· 6 6 obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o 7 7 obj-$(CONFIG_SOC_IMX8M) += soc-imx8m.o 8 8 obj-$(CONFIG_SOC_IMX8M) += imx8m-blk-ctrl.o 9 + obj-$(CONFIG_SOC_IMX8M) += imx8mp-blk-ctrl.o
+418 -12
drivers/soc/imx/gpcv2.c
··· 21 21 #include <dt-bindings/power/imx8mq-power.h> 22 22 #include <dt-bindings/power/imx8mm-power.h> 23 23 #include <dt-bindings/power/imx8mn-power.h> 24 + #include <dt-bindings/power/imx8mp-power.h> 24 25 25 26 #define GPC_LPCR_A_CORE_BSC 0x000 26 27 27 28 #define GPC_PGC_CPU_MAPPING 0x0ec 29 + #define IMX8MP_GPC_PGC_CPU_MAPPING 0x1cc 28 30 29 31 #define IMX7_USB_HSIC_PHY_A_CORE_DOMAIN BIT(6) 30 32 #define IMX7_USB_OTG2_PHY_A_CORE_DOMAIN BIT(5) ··· 66 64 #define IMX8MN_DDR1_A53_DOMAIN BIT(7) 67 65 #define IMX8MN_OTG1_A53_DOMAIN BIT(4) 68 66 #define IMX8MN_MIPI_A53_DOMAIN BIT(2) 67 + 68 + #define IMX8MP_MEDIA_ISPDWP_A53_DOMAIN BIT(20) 69 + #define IMX8MP_HSIOMIX_A53_DOMAIN BIT(19) 70 + #define IMX8MP_MIPI_PHY2_A53_DOMAIN BIT(18) 71 + #define IMX8MP_HDMI_PHY_A53_DOMAIN BIT(17) 72 + #define IMX8MP_HDMIMIX_A53_DOMAIN BIT(16) 73 + #define IMX8MP_VPU_VC8000E_A53_DOMAIN BIT(15) 74 + #define IMX8MP_VPU_G2_A53_DOMAIN BIT(14) 75 + #define IMX8MP_VPU_G1_A53_DOMAIN BIT(13) 76 + #define IMX8MP_MEDIAMIX_A53_DOMAIN BIT(12) 77 + #define IMX8MP_GPU3D_A53_DOMAIN BIT(11) 78 + #define IMX8MP_VPUMIX_A53_DOMAIN BIT(10) 79 + #define IMX8MP_GPUMIX_A53_DOMAIN BIT(9) 80 + #define IMX8MP_GPU2D_A53_DOMAIN BIT(8) 81 + #define IMX8MP_AUDIOMIX_A53_DOMAIN BIT(7) 82 + #define IMX8MP_MLMIX_A53_DOMAIN BIT(6) 83 + #define IMX8MP_USB2_PHY_A53_DOMAIN BIT(5) 84 + #define IMX8MP_USB1_PHY_A53_DOMAIN BIT(4) 85 + #define IMX8MP_PCIE_PHY_A53_DOMAIN BIT(3) 86 + #define IMX8MP_MIPI_PHY1_A53_DOMAIN BIT(2) 87 + 88 + #define IMX8MP_GPC_PU_PGC_SW_PUP_REQ 0x0d8 89 + #define IMX8MP_GPC_PU_PGC_SW_PDN_REQ 0x0e4 69 90 70 91 #define GPC_PU_PGC_SW_PUP_REQ 0x0f8 71 92 #define GPC_PU_PGC_SW_PDN_REQ 0x104 ··· 132 107 #define IMX8MN_OTG1_SW_Pxx_REQ BIT(2) 133 108 #define IMX8MN_MIPI_SW_Pxx_REQ BIT(0) 134 109 110 + #define IMX8MP_DDRMIX_Pxx_REQ BIT(19) 111 + #define IMX8MP_MEDIA_ISP_DWP_Pxx_REQ BIT(18) 112 + #define IMX8MP_HSIOMIX_Pxx_REQ BIT(17) 113 + #define IMX8MP_MIPI_PHY2_Pxx_REQ BIT(16) 114 + #define IMX8MP_HDMI_PHY_Pxx_REQ BIT(15) 115 + #define IMX8MP_HDMIMIX_Pxx_REQ BIT(14) 116 + #define IMX8MP_VPU_VC8K_Pxx_REQ BIT(13) 117 + #define IMX8MP_VPU_G2_Pxx_REQ BIT(12) 118 + #define IMX8MP_VPU_G1_Pxx_REQ BIT(11) 119 + #define IMX8MP_MEDIMIX_Pxx_REQ BIT(10) 120 + #define IMX8MP_GPU_3D_Pxx_REQ BIT(9) 121 + #define IMX8MP_VPU_MIX_SHARE_LOGIC_Pxx_REQ BIT(8) 122 + #define IMX8MP_GPU_SHARE_LOGIC_Pxx_REQ BIT(7) 123 + #define IMX8MP_GPU_2D_Pxx_REQ BIT(6) 124 + #define IMX8MP_AUDIOMIX_Pxx_REQ BIT(5) 125 + #define IMX8MP_MLMIX_Pxx_REQ BIT(4) 126 + #define IMX8MP_USB2_PHY_Pxx_REQ BIT(3) 127 + #define IMX8MP_USB1_PHY_Pxx_REQ BIT(2) 128 + #define IMX8MP_PCIE_PHY_SW_Pxx_REQ BIT(1) 129 + #define IMX8MP_MIPI_PHY1_SW_Pxx_REQ BIT(0) 130 + 135 131 #define GPC_M4_PU_PDN_FLG 0x1bc 136 132 133 + #define IMX8MP_GPC_PU_PWRHSK 0x190 137 134 #define GPC_PU_PWRHSK 0x1fc 138 135 139 136 #define IMX8M_GPU_HSK_PWRDNACKN BIT(26) ··· 164 117 #define IMX8M_GPU_HSK_PWRDNREQN BIT(6) 165 118 #define IMX8M_VPU_HSK_PWRDNREQN BIT(5) 166 119 #define IMX8M_DISP_HSK_PWRDNREQN BIT(4) 167 - 168 120 169 121 #define IMX8MM_GPUMIX_HSK_PWRDNACKN BIT(29) 170 122 #define IMX8MM_GPU_HSK_PWRDNACKN (BIT(27) | BIT(28)) ··· 182 136 #define IMX8MN_GPUMIX_HSK_PWRDNREQN (BIT(11) | BIT(9)) 183 137 #define IMX8MN_DISPMIX_HSK_PWRDNREQN BIT(7) 184 138 #define IMX8MN_HSIO_HSK_PWRDNREQN BIT(5) 139 + 140 + #define IMX8MP_MEDIAMIX_PWRDNACKN BIT(30) 141 + #define IMX8MP_HDMIMIX_PWRDNACKN BIT(29) 142 + #define IMX8MP_HSIOMIX_PWRDNACKN BIT(28) 143 + #define IMX8MP_VPUMIX_PWRDNACKN BIT(26) 144 + #define IMX8MP_GPUMIX_PWRDNACKN BIT(25) 145 + #define IMX8MP_MLMIX_PWRDNACKN (BIT(23) | BIT(24)) 146 + #define IMX8MP_AUDIOMIX_PWRDNACKN (BIT(20) | BIT(31)) 147 + #define IMX8MP_MEDIAMIX_PWRDNREQN BIT(14) 148 + #define IMX8MP_HDMIMIX_PWRDNREQN BIT(13) 149 + #define IMX8MP_HSIOMIX_PWRDNREQN BIT(12) 150 + #define IMX8MP_VPUMIX_PWRDNREQN BIT(10) 151 + #define IMX8MP_GPUMIX_PWRDNREQN BIT(9) 152 + #define IMX8MP_MLMIX_PWRDNREQN (BIT(7) | BIT(8)) 153 + #define IMX8MP_AUDIOMIX_PWRDNREQN (BIT(4) | BIT(15)) 185 154 186 155 /* 187 156 * The PGC offset values in Reference Manual ··· 240 179 #define IMX8MN_PGC_GPUMIX 23 241 180 #define IMX8MN_PGC_DISPMIX 26 242 181 182 + #define IMX8MP_PGC_NOC 9 183 + #define IMX8MP_PGC_MIPI1 12 184 + #define IMX8MP_PGC_PCIE 13 185 + #define IMX8MP_PGC_USB1 14 186 + #define IMX8MP_PGC_USB2 15 187 + #define IMX8MP_PGC_MLMIX 16 188 + #define IMX8MP_PGC_AUDIOMIX 17 189 + #define IMX8MP_PGC_GPU2D 18 190 + #define IMX8MP_PGC_GPUMIX 19 191 + #define IMX8MP_PGC_VPUMIX 20 192 + #define IMX8MP_PGC_GPU3D 21 193 + #define IMX8MP_PGC_MEDIAMIX 22 194 + #define IMX8MP_PGC_VPU_G1 23 195 + #define IMX8MP_PGC_VPU_G2 24 196 + #define IMX8MP_PGC_VPU_VC8000E 25 197 + #define IMX8MP_PGC_HDMIMIX 26 198 + #define IMX8MP_PGC_HDMI 27 199 + #define IMX8MP_PGC_MIPI2 28 200 + #define IMX8MP_PGC_HSIOMIX 29 201 + #define IMX8MP_PGC_MEDIA_ISP_DWP 30 202 + #define IMX8MP_PGC_DDRMIX 31 203 + 243 204 #define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40) 244 205 #define GPC_PGC_SR(n) (GPC_PGC_CTRL(n) + 0xc) 245 206 246 207 #define GPC_PGC_CTRL_PCR BIT(0) 247 208 209 + struct imx_pgc_regs { 210 + u16 map; 211 + u16 pup; 212 + u16 pdn; 213 + u16 hsk; 214 + }; 215 + 248 216 struct imx_pgc_domain { 249 217 struct generic_pm_domain genpd; 250 218 struct regmap *regmap; 219 + const struct imx_pgc_regs *regs; 251 220 struct regulator *regulator; 252 221 struct reset_control *reset; 253 222 struct clk_bulk_data *clks; ··· 295 204 const int voltage; 296 205 const bool keep_clocks; 297 206 struct device *dev; 207 + 208 + unsigned int pgc_sw_pup_reg; 209 + unsigned int pgc_sw_pdn_reg; 298 210 }; 299 211 300 212 struct imx_pgc_domain_data { 301 213 const struct imx_pgc_domain *domains; 302 214 size_t domains_num; 303 215 const struct regmap_access_table *reg_access_table; 216 + const struct imx_pgc_regs *pgc_regs; 304 217 }; 305 218 306 219 static inline struct imx_pgc_domain * ··· 344 249 345 250 if (domain->bits.pxx) { 346 251 /* request the domain to power up */ 347 - regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PUP_REQ, 252 + regmap_update_bits(domain->regmap, domain->regs->pup, 348 253 domain->bits.pxx, domain->bits.pxx); 349 254 /* 350 255 * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait 351 256 * for PUP_REQ/PDN_REQ bit to be cleared 352 257 */ 353 258 ret = regmap_read_poll_timeout(domain->regmap, 354 - GPC_PU_PGC_SW_PUP_REQ, reg_val, 259 + domain->regs->pup, reg_val, 355 260 !(reg_val & domain->bits.pxx), 356 261 0, USEC_PER_MSEC); 357 262 if (ret) { ··· 373 278 374 279 /* request the ADB400 to power up */ 375 280 if (domain->bits.hskreq) { 376 - regmap_update_bits(domain->regmap, GPC_PU_PWRHSK, 281 + regmap_update_bits(domain->regmap, domain->regs->hsk, 377 282 domain->bits.hskreq, domain->bits.hskreq); 378 283 379 284 /* 380 - * ret = regmap_read_poll_timeout(domain->regmap, GPC_PU_PWRHSK, reg_val, 285 + * ret = regmap_read_poll_timeout(domain->regmap, domain->regs->hsk, reg_val, 381 286 * (reg_val & domain->bits.hskack), 0, 382 287 * USEC_PER_MSEC); 383 288 * Technically we need the commented code to wait handshake. But that needs ··· 424 329 425 330 /* request the ADB400 to power down */ 426 331 if (domain->bits.hskreq) { 427 - regmap_clear_bits(domain->regmap, GPC_PU_PWRHSK, 332 + regmap_clear_bits(domain->regmap, domain->regs->hsk, 428 333 domain->bits.hskreq); 429 334 430 - ret = regmap_read_poll_timeout(domain->regmap, GPC_PU_PWRHSK, 335 + ret = regmap_read_poll_timeout(domain->regmap, domain->regs->hsk, 431 336 reg_val, 432 337 !(reg_val & domain->bits.hskack), 433 338 0, USEC_PER_MSEC); ··· 445 350 } 446 351 447 352 /* request the domain to power down */ 448 - regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PDN_REQ, 353 + regmap_update_bits(domain->regmap, domain->regs->pdn, 449 354 domain->bits.pxx, domain->bits.pxx); 450 355 /* 451 356 * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait 452 357 * for PUP_REQ/PDN_REQ bit to be cleared 453 358 */ 454 359 ret = regmap_read_poll_timeout(domain->regmap, 455 - GPC_PU_PGC_SW_PDN_REQ, reg_val, 360 + domain->regs->pdn, reg_val, 456 361 !(reg_val & domain->bits.pxx), 457 362 0, USEC_PER_MSEC); 458 363 if (ret) { ··· 537 442 .n_yes_ranges = ARRAY_SIZE(imx7_yes_ranges), 538 443 }; 539 444 445 + static const struct imx_pgc_regs imx7_pgc_regs = { 446 + .map = GPC_PGC_CPU_MAPPING, 447 + .pup = GPC_PU_PGC_SW_PUP_REQ, 448 + .pdn = GPC_PU_PGC_SW_PDN_REQ, 449 + .hsk = GPC_PU_PWRHSK, 450 + }; 451 + 540 452 static const struct imx_pgc_domain_data imx7_pgc_domain_data = { 541 453 .domains = imx7_pgc_domains, 542 454 .domains_num = ARRAY_SIZE(imx7_pgc_domains), 543 455 .reg_access_table = &imx7_access_table, 456 + .pgc_regs = &imx7_pgc_regs, 544 457 }; 545 458 546 459 static const struct imx_pgc_domain imx8m_pgc_domains[] = { ··· 717 614 .domains = imx8m_pgc_domains, 718 615 .domains_num = ARRAY_SIZE(imx8m_pgc_domains), 719 616 .reg_access_table = &imx8m_access_table, 617 + .pgc_regs = &imx7_pgc_regs, 720 618 }; 721 619 722 620 static const struct imx_pgc_domain imx8mm_pgc_domains[] = { ··· 908 804 .domains = imx8mm_pgc_domains, 909 805 .domains_num = ARRAY_SIZE(imx8mm_pgc_domains), 910 806 .reg_access_table = &imx8mm_access_table, 807 + .pgc_regs = &imx7_pgc_regs, 808 + }; 809 + 810 + static const struct imx_pgc_domain imx8mp_pgc_domains[] = { 811 + [IMX8MP_POWER_DOMAIN_MIPI_PHY1] = { 812 + .genpd = { 813 + .name = "mipi-phy1", 814 + }, 815 + .bits = { 816 + .pxx = IMX8MP_MIPI_PHY1_SW_Pxx_REQ, 817 + .map = IMX8MP_MIPI_PHY1_A53_DOMAIN, 818 + }, 819 + .pgc = BIT(IMX8MP_PGC_MIPI1), 820 + }, 821 + 822 + [IMX8MP_POWER_DOMAIN_PCIE_PHY] = { 823 + .genpd = { 824 + .name = "pcie-phy1", 825 + }, 826 + .bits = { 827 + .pxx = IMX8MP_PCIE_PHY_SW_Pxx_REQ, 828 + .map = IMX8MP_PCIE_PHY_A53_DOMAIN, 829 + }, 830 + .pgc = BIT(IMX8MP_PGC_PCIE), 831 + }, 832 + 833 + [IMX8MP_POWER_DOMAIN_USB1_PHY] = { 834 + .genpd = { 835 + .name = "usb-otg1", 836 + }, 837 + .bits = { 838 + .pxx = IMX8MP_USB1_PHY_Pxx_REQ, 839 + .map = IMX8MP_USB1_PHY_A53_DOMAIN, 840 + }, 841 + .pgc = BIT(IMX8MP_PGC_USB1), 842 + }, 843 + 844 + [IMX8MP_POWER_DOMAIN_USB2_PHY] = { 845 + .genpd = { 846 + .name = "usb-otg2", 847 + }, 848 + .bits = { 849 + .pxx = IMX8MP_USB2_PHY_Pxx_REQ, 850 + .map = IMX8MP_USB2_PHY_A53_DOMAIN, 851 + }, 852 + .pgc = BIT(IMX8MP_PGC_USB2), 853 + }, 854 + 855 + [IMX8MP_POWER_DOMAIN_MLMIX] = { 856 + .genpd = { 857 + .name = "mlmix", 858 + }, 859 + .bits = { 860 + .pxx = IMX8MP_MLMIX_Pxx_REQ, 861 + .map = IMX8MP_MLMIX_A53_DOMAIN, 862 + .hskreq = IMX8MP_MLMIX_PWRDNREQN, 863 + .hskack = IMX8MP_MLMIX_PWRDNACKN, 864 + }, 865 + .pgc = BIT(IMX8MP_PGC_MLMIX), 866 + .keep_clocks = true, 867 + }, 868 + 869 + [IMX8MP_POWER_DOMAIN_AUDIOMIX] = { 870 + .genpd = { 871 + .name = "audiomix", 872 + }, 873 + .bits = { 874 + .pxx = IMX8MP_AUDIOMIX_Pxx_REQ, 875 + .map = IMX8MP_AUDIOMIX_A53_DOMAIN, 876 + .hskreq = IMX8MP_AUDIOMIX_PWRDNREQN, 877 + .hskack = IMX8MP_AUDIOMIX_PWRDNACKN, 878 + }, 879 + .pgc = BIT(IMX8MP_PGC_AUDIOMIX), 880 + .keep_clocks = true, 881 + }, 882 + 883 + [IMX8MP_POWER_DOMAIN_GPU2D] = { 884 + .genpd = { 885 + .name = "gpu2d", 886 + }, 887 + .bits = { 888 + .pxx = IMX8MP_GPU_2D_Pxx_REQ, 889 + .map = IMX8MP_GPU2D_A53_DOMAIN, 890 + }, 891 + .pgc = BIT(IMX8MP_PGC_GPU2D), 892 + }, 893 + 894 + [IMX8MP_POWER_DOMAIN_GPUMIX] = { 895 + .genpd = { 896 + .name = "gpumix", 897 + }, 898 + .bits = { 899 + .pxx = IMX8MP_GPU_SHARE_LOGIC_Pxx_REQ, 900 + .map = IMX8MP_GPUMIX_A53_DOMAIN, 901 + .hskreq = IMX8MP_GPUMIX_PWRDNREQN, 902 + .hskack = IMX8MP_GPUMIX_PWRDNACKN, 903 + }, 904 + .pgc = BIT(IMX8MP_PGC_GPUMIX), 905 + .keep_clocks = true, 906 + }, 907 + 908 + [IMX8MP_POWER_DOMAIN_VPUMIX] = { 909 + .genpd = { 910 + .name = "vpumix", 911 + }, 912 + .bits = { 913 + .pxx = IMX8MP_VPU_MIX_SHARE_LOGIC_Pxx_REQ, 914 + .map = IMX8MP_VPUMIX_A53_DOMAIN, 915 + .hskreq = IMX8MP_VPUMIX_PWRDNREQN, 916 + .hskack = IMX8MP_VPUMIX_PWRDNACKN, 917 + }, 918 + .pgc = BIT(IMX8MP_PGC_VPUMIX), 919 + .keep_clocks = true, 920 + }, 921 + 922 + [IMX8MP_POWER_DOMAIN_GPU3D] = { 923 + .genpd = { 924 + .name = "gpu3d", 925 + }, 926 + .bits = { 927 + .pxx = IMX8MP_GPU_3D_Pxx_REQ, 928 + .map = IMX8MP_GPU3D_A53_DOMAIN, 929 + }, 930 + .pgc = BIT(IMX8MP_PGC_GPU3D), 931 + }, 932 + 933 + [IMX8MP_POWER_DOMAIN_MEDIAMIX] = { 934 + .genpd = { 935 + .name = "mediamix", 936 + }, 937 + .bits = { 938 + .pxx = IMX8MP_MEDIMIX_Pxx_REQ, 939 + .map = IMX8MP_MEDIAMIX_A53_DOMAIN, 940 + .hskreq = IMX8MP_MEDIAMIX_PWRDNREQN, 941 + .hskack = IMX8MP_MEDIAMIX_PWRDNACKN, 942 + }, 943 + .pgc = BIT(IMX8MP_PGC_MEDIAMIX), 944 + .keep_clocks = true, 945 + }, 946 + 947 + [IMX8MP_POWER_DOMAIN_VPU_G1] = { 948 + .genpd = { 949 + .name = "vpu-g1", 950 + }, 951 + .bits = { 952 + .pxx = IMX8MP_VPU_G1_Pxx_REQ, 953 + .map = IMX8MP_VPU_G1_A53_DOMAIN, 954 + }, 955 + .pgc = BIT(IMX8MP_PGC_VPU_G1), 956 + }, 957 + 958 + [IMX8MP_POWER_DOMAIN_VPU_G2] = { 959 + .genpd = { 960 + .name = "vpu-g2", 961 + }, 962 + .bits = { 963 + .pxx = IMX8MP_VPU_G2_Pxx_REQ, 964 + .map = IMX8MP_VPU_G2_A53_DOMAIN 965 + }, 966 + .pgc = BIT(IMX8MP_PGC_VPU_G2), 967 + }, 968 + 969 + [IMX8MP_POWER_DOMAIN_VPU_VC8000E] = { 970 + .genpd = { 971 + .name = "vpu-h1", 972 + }, 973 + .bits = { 974 + .pxx = IMX8MP_VPU_VC8K_Pxx_REQ, 975 + .map = IMX8MP_VPU_VC8000E_A53_DOMAIN, 976 + }, 977 + .pgc = BIT(IMX8MP_PGC_VPU_VC8000E), 978 + }, 979 + 980 + [IMX8MP_POWER_DOMAIN_HDMIMIX] = { 981 + .genpd = { 982 + .name = "hdmimix", 983 + }, 984 + .bits = { 985 + .pxx = IMX8MP_HDMIMIX_Pxx_REQ, 986 + .map = IMX8MP_HDMIMIX_A53_DOMAIN, 987 + .hskreq = IMX8MP_HDMIMIX_PWRDNREQN, 988 + .hskack = IMX8MP_HDMIMIX_PWRDNACKN, 989 + }, 990 + .pgc = BIT(IMX8MP_PGC_HDMIMIX), 991 + .keep_clocks = true, 992 + }, 993 + 994 + [IMX8MP_POWER_DOMAIN_HDMI_PHY] = { 995 + .genpd = { 996 + .name = "hdmi-phy", 997 + }, 998 + .bits = { 999 + .pxx = IMX8MP_HDMI_PHY_Pxx_REQ, 1000 + .map = IMX8MP_HDMI_PHY_A53_DOMAIN, 1001 + }, 1002 + .pgc = BIT(IMX8MP_PGC_HDMI), 1003 + }, 1004 + 1005 + [IMX8MP_POWER_DOMAIN_MIPI_PHY2] = { 1006 + .genpd = { 1007 + .name = "mipi-phy2", 1008 + }, 1009 + .bits = { 1010 + .pxx = IMX8MP_MIPI_PHY2_Pxx_REQ, 1011 + .map = IMX8MP_MIPI_PHY2_A53_DOMAIN, 1012 + }, 1013 + .pgc = BIT(IMX8MP_PGC_MIPI2), 1014 + }, 1015 + 1016 + [IMX8MP_POWER_DOMAIN_HSIOMIX] = { 1017 + .genpd = { 1018 + .name = "hsiomix", 1019 + }, 1020 + .bits = { 1021 + .pxx = IMX8MP_HSIOMIX_Pxx_REQ, 1022 + .map = IMX8MP_HSIOMIX_A53_DOMAIN, 1023 + .hskreq = IMX8MP_HSIOMIX_PWRDNREQN, 1024 + .hskack = IMX8MP_HSIOMIX_PWRDNACKN, 1025 + }, 1026 + .pgc = BIT(IMX8MP_PGC_HSIOMIX), 1027 + .keep_clocks = true, 1028 + }, 1029 + 1030 + [IMX8MP_POWER_DOMAIN_MEDIAMIX_ISPDWP] = { 1031 + .genpd = { 1032 + .name = "mediamix-isp-dwp", 1033 + }, 1034 + .bits = { 1035 + .pxx = IMX8MP_MEDIA_ISP_DWP_Pxx_REQ, 1036 + .map = IMX8MP_MEDIA_ISPDWP_A53_DOMAIN, 1037 + }, 1038 + .pgc = BIT(IMX8MP_PGC_MEDIA_ISP_DWP), 1039 + }, 1040 + }; 1041 + 1042 + static const struct regmap_range imx8mp_yes_ranges[] = { 1043 + regmap_reg_range(GPC_LPCR_A_CORE_BSC, 1044 + IMX8MP_GPC_PGC_CPU_MAPPING), 1045 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_NOC), 1046 + GPC_PGC_SR(IMX8MP_PGC_NOC)), 1047 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_MIPI1), 1048 + GPC_PGC_SR(IMX8MP_PGC_MIPI1)), 1049 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_PCIE), 1050 + GPC_PGC_SR(IMX8MP_PGC_PCIE)), 1051 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_USB1), 1052 + GPC_PGC_SR(IMX8MP_PGC_USB1)), 1053 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_USB2), 1054 + GPC_PGC_SR(IMX8MP_PGC_USB2)), 1055 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_MLMIX), 1056 + GPC_PGC_SR(IMX8MP_PGC_MLMIX)), 1057 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_AUDIOMIX), 1058 + GPC_PGC_SR(IMX8MP_PGC_AUDIOMIX)), 1059 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_GPU2D), 1060 + GPC_PGC_SR(IMX8MP_PGC_GPU2D)), 1061 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_GPUMIX), 1062 + GPC_PGC_SR(IMX8MP_PGC_GPUMIX)), 1063 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_VPUMIX), 1064 + GPC_PGC_SR(IMX8MP_PGC_VPUMIX)), 1065 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_GPU3D), 1066 + GPC_PGC_SR(IMX8MP_PGC_GPU3D)), 1067 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_MEDIAMIX), 1068 + GPC_PGC_SR(IMX8MP_PGC_MEDIAMIX)), 1069 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_VPU_G1), 1070 + GPC_PGC_SR(IMX8MP_PGC_VPU_G1)), 1071 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_VPU_G2), 1072 + GPC_PGC_SR(IMX8MP_PGC_VPU_G2)), 1073 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_VPU_VC8000E), 1074 + GPC_PGC_SR(IMX8MP_PGC_VPU_VC8000E)), 1075 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_HDMIMIX), 1076 + GPC_PGC_SR(IMX8MP_PGC_HDMIMIX)), 1077 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_HDMI), 1078 + GPC_PGC_SR(IMX8MP_PGC_HDMI)), 1079 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_MIPI2), 1080 + GPC_PGC_SR(IMX8MP_PGC_MIPI2)), 1081 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_HSIOMIX), 1082 + GPC_PGC_SR(IMX8MP_PGC_HSIOMIX)), 1083 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_MEDIA_ISP_DWP), 1084 + GPC_PGC_SR(IMX8MP_PGC_MEDIA_ISP_DWP)), 1085 + regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_DDRMIX), 1086 + GPC_PGC_SR(IMX8MP_PGC_DDRMIX)), 1087 + }; 1088 + 1089 + static const struct regmap_access_table imx8mp_access_table = { 1090 + .yes_ranges = imx8mp_yes_ranges, 1091 + .n_yes_ranges = ARRAY_SIZE(imx8mp_yes_ranges), 1092 + }; 1093 + 1094 + static const struct imx_pgc_regs imx8mp_pgc_regs = { 1095 + .map = IMX8MP_GPC_PGC_CPU_MAPPING, 1096 + .pup = IMX8MP_GPC_PU_PGC_SW_PUP_REQ, 1097 + .pdn = IMX8MP_GPC_PU_PGC_SW_PDN_REQ, 1098 + .hsk = IMX8MP_GPC_PU_PWRHSK, 1099 + }; 1100 + static const struct imx_pgc_domain_data imx8mp_pgc_domain_data = { 1101 + .domains = imx8mp_pgc_domains, 1102 + .domains_num = ARRAY_SIZE(imx8mp_pgc_domains), 1103 + .reg_access_table = &imx8mp_access_table, 1104 + .pgc_regs = &imx8mp_pgc_regs, 911 1105 }; 912 1106 913 1107 static const struct imx_pgc_domain imx8mn_pgc_domains[] = { ··· 1297 895 .domains = imx8mn_pgc_domains, 1298 896 .domains_num = ARRAY_SIZE(imx8mn_pgc_domains), 1299 897 .reg_access_table = &imx8mn_access_table, 898 + .pgc_regs = &imx7_pgc_regs, 1300 899 }; 1301 900 1302 901 static int imx_pgc_domain_probe(struct platform_device *pdev) ··· 1330 927 pm_runtime_enable(domain->dev); 1331 928 1332 929 if (domain->bits.map) 1333 - regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, 930 + regmap_update_bits(domain->regmap, domain->regs->map, 1334 931 domain->bits.map, domain->bits.map); 1335 932 1336 933 ret = pm_genpd_init(&domain->genpd, NULL, true); ··· 1356 953 pm_genpd_remove(&domain->genpd); 1357 954 out_domain_unmap: 1358 955 if (domain->bits.map) 1359 - regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, 956 + regmap_update_bits(domain->regmap, domain->regs->map, 1360 957 domain->bits.map, 0); 1361 958 pm_runtime_disable(domain->dev); 1362 959 ··· 1371 968 pm_genpd_remove(&domain->genpd); 1372 969 1373 970 if (domain->bits.map) 1374 - regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, 971 + regmap_update_bits(domain->regmap, domain->regs->map, 1375 972 domain->bits.map, 0); 1376 973 1377 974 pm_runtime_disable(domain->dev); ··· 1502 1099 1503 1100 domain = pd_pdev->dev.platform_data; 1504 1101 domain->regmap = regmap; 1102 + domain->regs = domain_data->pgc_regs; 1103 + 1505 1104 domain->genpd.power_on = imx_pgc_power_up; 1506 1105 domain->genpd.power_off = imx_pgc_power_down; 1507 1106 ··· 1525 1120 { .compatible = "fsl,imx7d-gpc", .data = &imx7_pgc_domain_data, }, 1526 1121 { .compatible = "fsl,imx8mm-gpc", .data = &imx8mm_pgc_domain_data, }, 1527 1122 { .compatible = "fsl,imx8mn-gpc", .data = &imx8mn_pgc_domain_data, }, 1123 + { .compatible = "fsl,imx8mp-gpc", .data = &imx8mp_pgc_domain_data, }, 1528 1124 { .compatible = "fsl,imx8mq-gpc", .data = &imx8m_pgc_domain_data, }, 1529 1125 { } 1530 1126 };
+122 -2
drivers/soc/imx/imx8m-blk-ctrl.c
··· 15 15 16 16 #include <dt-bindings/power/imx8mm-power.h> 17 17 #include <dt-bindings/power/imx8mn-power.h> 18 + #include <dt-bindings/power/imx8mp-power.h> 18 19 #include <dt-bindings/power/imx8mq-power.h> 19 20 20 21 #define BLK_SFT_RSTN 0x0 21 22 #define BLK_CLK_EN 0x4 22 - #define BLK_MIPI_RESET_DIV 0x8 /* Mini/Nano DISPLAY_BLK_CTRL only */ 23 + #define BLK_MIPI_RESET_DIV 0x8 /* Mini/Nano/Plus DISPLAY_BLK_CTRL only */ 23 24 24 25 struct imx8m_blk_ctrl_domain; 25 26 ··· 42 41 u32 clk_mask; 43 42 44 43 /* 45 - * i.MX8M Mini and Nano have a third DISPLAY_BLK_CTRL register 44 + * i.MX8M Mini, Nano and Plus have a third DISPLAY_BLK_CTRL register 46 45 * which is used to control the reset for the MIPI Phy. 47 46 * Since it's only present in certain circumstances, 48 47 * an if-statement should be used before setting and clearing this ··· 242 241 ret = PTR_ERR(domain->power_dev); 243 242 goto cleanup_pds; 244 243 } 244 + dev_set_name(domain->power_dev, "%s", data->name); 245 245 246 246 domain->genpd.name = data->name; 247 247 domain->genpd.power_on = imx8m_blk_ctrl_power_on; ··· 592 590 .num_domains = ARRAY_SIZE(imx8mn_disp_blk_ctl_domain_data), 593 591 }; 594 592 593 + static int imx8mp_media_power_notifier(struct notifier_block *nb, 594 + unsigned long action, void *data) 595 + { 596 + struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl, 597 + power_nb); 598 + 599 + if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF) 600 + return NOTIFY_OK; 601 + 602 + /* Enable bus clock and deassert bus reset */ 603 + regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(8)); 604 + regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(8)); 605 + 606 + /* 607 + * On power up we have no software backchannel to the GPC to 608 + * wait for the ADB handshake to happen, so we just delay for a 609 + * bit. On power down the GPC driver waits for the handshake. 610 + */ 611 + if (action == GENPD_NOTIFY_ON) 612 + udelay(5); 613 + 614 + return NOTIFY_OK; 615 + } 616 + 617 + /* 618 + * From i.MX 8M Plus Applications Processor Reference Manual, Rev. 1, 619 + * section 13.2.2, 13.2.3 620 + * isp-ahb and dwe are not in Figure 13-5. Media BLK_CTRL Clocks 621 + */ 622 + static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[] = { 623 + [IMX8MP_MEDIABLK_PD_MIPI_DSI_1] = { 624 + .name = "mediablk-mipi-dsi-1", 625 + .clk_names = (const char *[]){ "apb", "phy", }, 626 + .num_clks = 2, 627 + .gpc_name = "mipi-dsi1", 628 + .rst_mask = BIT(0) | BIT(1), 629 + .clk_mask = BIT(0) | BIT(1), 630 + .mipi_phy_rst_mask = BIT(17), 631 + }, 632 + [IMX8MP_MEDIABLK_PD_MIPI_CSI2_1] = { 633 + .name = "mediablk-mipi-csi2-1", 634 + .clk_names = (const char *[]){ "apb", "cam1" }, 635 + .num_clks = 2, 636 + .gpc_name = "mipi-csi1", 637 + .rst_mask = BIT(2) | BIT(3), 638 + .clk_mask = BIT(2) | BIT(3), 639 + .mipi_phy_rst_mask = BIT(16), 640 + }, 641 + [IMX8MP_MEDIABLK_PD_LCDIF_1] = { 642 + .name = "mediablk-lcdif-1", 643 + .clk_names = (const char *[]){ "disp1", "apb", "axi", }, 644 + .num_clks = 3, 645 + .gpc_name = "lcdif1", 646 + .rst_mask = BIT(4) | BIT(5) | BIT(23), 647 + .clk_mask = BIT(4) | BIT(5) | BIT(23), 648 + }, 649 + [IMX8MP_MEDIABLK_PD_ISI] = { 650 + .name = "mediablk-isi", 651 + .clk_names = (const char *[]){ "axi", "apb" }, 652 + .num_clks = 2, 653 + .gpc_name = "isi", 654 + .rst_mask = BIT(6) | BIT(7), 655 + .clk_mask = BIT(6) | BIT(7), 656 + }, 657 + [IMX8MP_MEDIABLK_PD_MIPI_CSI2_2] = { 658 + .name = "mediablk-mipi-csi2-2", 659 + .clk_names = (const char *[]){ "apb", "cam2" }, 660 + .num_clks = 2, 661 + .gpc_name = "mipi-csi2", 662 + .rst_mask = BIT(9) | BIT(10), 663 + .clk_mask = BIT(9) | BIT(10), 664 + .mipi_phy_rst_mask = BIT(30), 665 + }, 666 + [IMX8MP_MEDIABLK_PD_LCDIF_2] = { 667 + .name = "mediablk-lcdif-2", 668 + .clk_names = (const char *[]){ "disp1", "apb", "axi", }, 669 + .num_clks = 3, 670 + .gpc_name = "lcdif2", 671 + .rst_mask = BIT(11) | BIT(12) | BIT(24), 672 + .clk_mask = BIT(11) | BIT(12) | BIT(24), 673 + }, 674 + [IMX8MP_MEDIABLK_PD_ISP] = { 675 + .name = "mediablk-isp", 676 + .clk_names = (const char *[]){ "isp", "axi", "apb" }, 677 + .num_clks = 3, 678 + .gpc_name = "isp", 679 + .rst_mask = BIT(16) | BIT(17) | BIT(18), 680 + .clk_mask = BIT(16) | BIT(17) | BIT(18), 681 + }, 682 + [IMX8MP_MEDIABLK_PD_DWE] = { 683 + .name = "mediablk-dwe", 684 + .clk_names = (const char *[]){ "axi", "apb" }, 685 + .num_clks = 2, 686 + .gpc_name = "dwe", 687 + .rst_mask = BIT(19) | BIT(20) | BIT(21), 688 + .clk_mask = BIT(19) | BIT(20) | BIT(21), 689 + }, 690 + [IMX8MP_MEDIABLK_PD_MIPI_DSI_2] = { 691 + .name = "mediablk-mipi-dsi-2", 692 + .clk_names = (const char *[]){ "phy", }, 693 + .num_clks = 1, 694 + .gpc_name = "mipi-dsi2", 695 + .rst_mask = BIT(22), 696 + .clk_mask = BIT(22), 697 + .mipi_phy_rst_mask = BIT(29), 698 + }, 699 + }; 700 + 701 + static const struct imx8m_blk_ctrl_data imx8mp_media_blk_ctl_dev_data = { 702 + .max_reg = 0x138, 703 + .power_notifier_fn = imx8mp_media_power_notifier, 704 + .domains = imx8mp_media_blk_ctl_domain_data, 705 + .num_domains = ARRAY_SIZE(imx8mp_media_blk_ctl_domain_data), 706 + }; 707 + 595 708 static int imx8mq_vpu_power_notifier(struct notifier_block *nb, 596 709 unsigned long action, void *data) 597 710 { ··· 779 662 }, { 780 663 .compatible = "fsl,imx8mn-disp-blk-ctrl", 781 664 .data = &imx8mn_disp_blk_ctl_dev_data 665 + }, { 666 + .compatible = "fsl,imx8mp-media-blk-ctrl", 667 + .data = &imx8mp_media_blk_ctl_dev_data 782 668 }, { 783 669 .compatible = "fsl,imx8mq-vpu-blk-ctrl", 784 670 .data = &imx8mq_vpu_blk_ctl_dev_data
+696
drivers/soc/imx/imx8mp-blk-ctrl.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + 3 + /* 4 + * Copyright 2022 Pengutronix, Lucas Stach <kernel@pengutronix.de> 5 + */ 6 + 7 + #include <linux/clk.h> 8 + #include <linux/device.h> 9 + #include <linux/module.h> 10 + #include <linux/of_device.h> 11 + #include <linux/platform_device.h> 12 + #include <linux/pm_domain.h> 13 + #include <linux/pm_runtime.h> 14 + #include <linux/regmap.h> 15 + 16 + #include <dt-bindings/power/imx8mp-power.h> 17 + 18 + #define GPR_REG0 0x0 19 + #define PCIE_CLOCK_MODULE_EN BIT(0) 20 + #define USB_CLOCK_MODULE_EN BIT(1) 21 + 22 + struct imx8mp_blk_ctrl_domain; 23 + 24 + struct imx8mp_blk_ctrl { 25 + struct device *dev; 26 + struct notifier_block power_nb; 27 + struct device *bus_power_dev; 28 + struct regmap *regmap; 29 + struct imx8mp_blk_ctrl_domain *domains; 30 + struct genpd_onecell_data onecell_data; 31 + void (*power_off) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain); 32 + void (*power_on) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain); 33 + }; 34 + 35 + struct imx8mp_blk_ctrl_domain_data { 36 + const char *name; 37 + const char * const *clk_names; 38 + int num_clks; 39 + const char *gpc_name; 40 + }; 41 + 42 + #define DOMAIN_MAX_CLKS 2 43 + 44 + struct imx8mp_blk_ctrl_domain { 45 + struct generic_pm_domain genpd; 46 + const struct imx8mp_blk_ctrl_domain_data *data; 47 + struct clk_bulk_data clks[DOMAIN_MAX_CLKS]; 48 + struct device *power_dev; 49 + struct imx8mp_blk_ctrl *bc; 50 + int id; 51 + }; 52 + 53 + struct imx8mp_blk_ctrl_data { 54 + int max_reg; 55 + notifier_fn_t power_notifier_fn; 56 + void (*power_off) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain); 57 + void (*power_on) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain); 58 + const struct imx8mp_blk_ctrl_domain_data *domains; 59 + int num_domains; 60 + }; 61 + 62 + static inline struct imx8mp_blk_ctrl_domain * 63 + to_imx8mp_blk_ctrl_domain(struct generic_pm_domain *genpd) 64 + { 65 + return container_of(genpd, struct imx8mp_blk_ctrl_domain, genpd); 66 + } 67 + 68 + static void imx8mp_hsio_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc, 69 + struct imx8mp_blk_ctrl_domain *domain) 70 + { 71 + switch (domain->id) { 72 + case IMX8MP_HSIOBLK_PD_USB: 73 + regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN); 74 + break; 75 + case IMX8MP_HSIOBLK_PD_PCIE: 76 + regmap_set_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN); 77 + break; 78 + default: 79 + break; 80 + } 81 + } 82 + 83 + static void imx8mp_hsio_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc, 84 + struct imx8mp_blk_ctrl_domain *domain) 85 + { 86 + switch (domain->id) { 87 + case IMX8MP_HSIOBLK_PD_USB: 88 + regmap_clear_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN); 89 + break; 90 + case IMX8MP_HSIOBLK_PD_PCIE: 91 + regmap_clear_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN); 92 + break; 93 + default: 94 + break; 95 + } 96 + } 97 + 98 + static int imx8mp_hsio_power_notifier(struct notifier_block *nb, 99 + unsigned long action, void *data) 100 + { 101 + struct imx8mp_blk_ctrl *bc = container_of(nb, struct imx8mp_blk_ctrl, 102 + power_nb); 103 + struct clk_bulk_data *usb_clk = bc->domains[IMX8MP_HSIOBLK_PD_USB].clks; 104 + int num_clks = bc->domains[IMX8MP_HSIOBLK_PD_USB].data->num_clks; 105 + int ret; 106 + 107 + switch (action) { 108 + case GENPD_NOTIFY_ON: 109 + /* 110 + * enable USB clock for a moment for the power-on ADB handshake 111 + * to proceed 112 + */ 113 + ret = clk_bulk_prepare_enable(num_clks, usb_clk); 114 + if (ret) 115 + return NOTIFY_BAD; 116 + regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN); 117 + 118 + udelay(5); 119 + 120 + regmap_clear_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN); 121 + clk_bulk_disable_unprepare(num_clks, usb_clk); 122 + break; 123 + case GENPD_NOTIFY_PRE_OFF: 124 + /* enable USB clock for the power-down ADB handshake to work */ 125 + ret = clk_bulk_prepare_enable(num_clks, usb_clk); 126 + if (ret) 127 + return NOTIFY_BAD; 128 + 129 + regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN); 130 + break; 131 + case GENPD_NOTIFY_OFF: 132 + clk_bulk_disable_unprepare(num_clks, usb_clk); 133 + break; 134 + default: 135 + break; 136 + } 137 + 138 + return NOTIFY_OK; 139 + } 140 + 141 + static const struct imx8mp_blk_ctrl_domain_data imx8mp_hsio_domain_data[] = { 142 + [IMX8MP_HSIOBLK_PD_USB] = { 143 + .name = "hsioblk-usb", 144 + .clk_names = (const char *[]){ "usb" }, 145 + .num_clks = 1, 146 + .gpc_name = "usb", 147 + }, 148 + [IMX8MP_HSIOBLK_PD_USB_PHY1] = { 149 + .name = "hsioblk-usb-phy1", 150 + .gpc_name = "usb-phy1", 151 + }, 152 + [IMX8MP_HSIOBLK_PD_USB_PHY2] = { 153 + .name = "hsioblk-usb-phy2", 154 + .gpc_name = "usb-phy2", 155 + }, 156 + [IMX8MP_HSIOBLK_PD_PCIE] = { 157 + .name = "hsioblk-pcie", 158 + .clk_names = (const char *[]){ "pcie" }, 159 + .num_clks = 1, 160 + .gpc_name = "pcie", 161 + }, 162 + [IMX8MP_HSIOBLK_PD_PCIE_PHY] = { 163 + .name = "hsioblk-pcie-phy", 164 + .gpc_name = "pcie-phy", 165 + }, 166 + }; 167 + 168 + static const struct imx8mp_blk_ctrl_data imx8mp_hsio_blk_ctl_dev_data = { 169 + .max_reg = 0x24, 170 + .power_on = imx8mp_hsio_blk_ctrl_power_on, 171 + .power_off = imx8mp_hsio_blk_ctrl_power_off, 172 + .power_notifier_fn = imx8mp_hsio_power_notifier, 173 + .domains = imx8mp_hsio_domain_data, 174 + .num_domains = ARRAY_SIZE(imx8mp_hsio_domain_data), 175 + }; 176 + 177 + #define HDMI_RTX_RESET_CTL0 0x20 178 + #define HDMI_RTX_CLK_CTL0 0x40 179 + #define HDMI_RTX_CLK_CTL1 0x50 180 + #define HDMI_RTX_CLK_CTL2 0x60 181 + #define HDMI_RTX_CLK_CTL3 0x70 182 + #define HDMI_RTX_CLK_CTL4 0x80 183 + #define HDMI_TX_CONTROL0 0x200 184 + 185 + static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc, 186 + struct imx8mp_blk_ctrl_domain *domain) 187 + { 188 + switch (domain->id) { 189 + case IMX8MP_HDMIBLK_PD_IRQSTEER: 190 + regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(9)); 191 + regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(16)); 192 + break; 193 + case IMX8MP_HDMIBLK_PD_LCDIF: 194 + regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, 195 + BIT(7) | BIT(16) | BIT(17) | BIT(18) | 196 + BIT(19) | BIT(20)); 197 + regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11)); 198 + regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, 199 + BIT(4) | BIT(5) | BIT(6)); 200 + break; 201 + case IMX8MP_HDMIBLK_PD_PAI: 202 + regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(17)); 203 + regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(18)); 204 + break; 205 + case IMX8MP_HDMIBLK_PD_PVI: 206 + regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(28)); 207 + regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(22)); 208 + break; 209 + case IMX8MP_HDMIBLK_PD_TRNG: 210 + regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(27) | BIT(30)); 211 + regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(20)); 212 + break; 213 + case IMX8MP_HDMIBLK_PD_HDMI_TX: 214 + regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, 215 + BIT(2) | BIT(4) | BIT(5)); 216 + regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, 217 + BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) | 218 + BIT(18) | BIT(19) | BIT(20) | BIT(21)); 219 + regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, 220 + BIT(7) | BIT(10) | BIT(11)); 221 + regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(1)); 222 + break; 223 + case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY: 224 + regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24)); 225 + regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12)); 226 + regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3)); 227 + break; 228 + default: 229 + break; 230 + } 231 + } 232 + 233 + static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc, 234 + struct imx8mp_blk_ctrl_domain *domain) 235 + { 236 + switch (domain->id) { 237 + case IMX8MP_HDMIBLK_PD_IRQSTEER: 238 + regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(9)); 239 + regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(16)); 240 + break; 241 + case IMX8MP_HDMIBLK_PD_LCDIF: 242 + regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, 243 + BIT(4) | BIT(5) | BIT(6)); 244 + regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11)); 245 + regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, 246 + BIT(7) | BIT(16) | BIT(17) | BIT(18) | 247 + BIT(19) | BIT(20)); 248 + break; 249 + case IMX8MP_HDMIBLK_PD_PAI: 250 + regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(18)); 251 + regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(17)); 252 + break; 253 + case IMX8MP_HDMIBLK_PD_PVI: 254 + regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(22)); 255 + regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(28)); 256 + break; 257 + case IMX8MP_HDMIBLK_PD_TRNG: 258 + regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(20)); 259 + regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(27) | BIT(30)); 260 + break; 261 + case IMX8MP_HDMIBLK_PD_HDMI_TX: 262 + regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(1)); 263 + regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, 264 + BIT(7) | BIT(10) | BIT(11)); 265 + regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, 266 + BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) | 267 + BIT(18) | BIT(19) | BIT(20) | BIT(21)); 268 + regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, 269 + BIT(2) | BIT(4) | BIT(5)); 270 + break; 271 + case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY: 272 + regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3)); 273 + regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12)); 274 + regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24)); 275 + break; 276 + default: 277 + break; 278 + } 279 + } 280 + 281 + static int imx8mp_hdmi_power_notifier(struct notifier_block *nb, 282 + unsigned long action, void *data) 283 + { 284 + struct imx8mp_blk_ctrl *bc = container_of(nb, struct imx8mp_blk_ctrl, 285 + power_nb); 286 + 287 + if (action != GENPD_NOTIFY_ON) 288 + return NOTIFY_OK; 289 + 290 + /* 291 + * Contrary to other blk-ctrls the reset and clock don't clear when the 292 + * power domain is powered down. To ensure the proper reset pulsing, 293 + * first clear them all to asserted state, then enable the bus clocks 294 + * and then release the ADB reset. 295 + */ 296 + regmap_write(bc->regmap, HDMI_RTX_RESET_CTL0, 0x0); 297 + regmap_write(bc->regmap, HDMI_RTX_CLK_CTL0, 0x0); 298 + regmap_write(bc->regmap, HDMI_RTX_CLK_CTL1, 0x0); 299 + regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, 300 + BIT(0) | BIT(1) | BIT(10)); 301 + regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(0)); 302 + 303 + /* 304 + * On power up we have no software backchannel to the GPC to 305 + * wait for the ADB handshake to happen, so we just delay for a 306 + * bit. On power down the GPC driver waits for the handshake. 307 + */ 308 + udelay(5); 309 + 310 + return NOTIFY_OK; 311 + } 312 + 313 + static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = { 314 + [IMX8MP_HDMIBLK_PD_IRQSTEER] = { 315 + .name = "hdmiblk-irqsteer", 316 + .clk_names = (const char *[]){ "apb" }, 317 + .num_clks = 1, 318 + .gpc_name = "irqsteer", 319 + }, 320 + [IMX8MP_HDMIBLK_PD_LCDIF] = { 321 + .name = "hdmiblk-lcdif", 322 + .clk_names = (const char *[]){ "axi", "apb" }, 323 + .num_clks = 2, 324 + .gpc_name = "lcdif", 325 + }, 326 + [IMX8MP_HDMIBLK_PD_PAI] = { 327 + .name = "hdmiblk-pai", 328 + .clk_names = (const char *[]){ "apb" }, 329 + .num_clks = 1, 330 + .gpc_name = "pai", 331 + }, 332 + [IMX8MP_HDMIBLK_PD_PVI] = { 333 + .name = "hdmiblk-pvi", 334 + .clk_names = (const char *[]){ "apb" }, 335 + .num_clks = 1, 336 + .gpc_name = "pvi", 337 + }, 338 + [IMX8MP_HDMIBLK_PD_TRNG] = { 339 + .name = "hdmiblk-trng", 340 + .clk_names = (const char *[]){ "apb" }, 341 + .num_clks = 1, 342 + .gpc_name = "trng", 343 + }, 344 + [IMX8MP_HDMIBLK_PD_HDMI_TX] = { 345 + .name = "hdmiblk-hdmi-tx", 346 + .clk_names = (const char *[]){ "apb", "ref_266m" }, 347 + .num_clks = 2, 348 + .gpc_name = "hdmi-tx", 349 + }, 350 + [IMX8MP_HDMIBLK_PD_HDMI_TX_PHY] = { 351 + .name = "hdmiblk-hdmi-tx-phy", 352 + .clk_names = (const char *[]){ "apb", "ref_24m" }, 353 + .num_clks = 2, 354 + .gpc_name = "hdmi-tx-phy", 355 + }, 356 + }; 357 + 358 + static const struct imx8mp_blk_ctrl_data imx8mp_hdmi_blk_ctl_dev_data = { 359 + .max_reg = 0x23c, 360 + .power_on = imx8mp_hdmi_blk_ctrl_power_on, 361 + .power_off = imx8mp_hdmi_blk_ctrl_power_off, 362 + .power_notifier_fn = imx8mp_hdmi_power_notifier, 363 + .domains = imx8mp_hdmi_domain_data, 364 + .num_domains = ARRAY_SIZE(imx8mp_hdmi_domain_data), 365 + }; 366 + 367 + static int imx8mp_blk_ctrl_power_on(struct generic_pm_domain *genpd) 368 + { 369 + struct imx8mp_blk_ctrl_domain *domain = to_imx8mp_blk_ctrl_domain(genpd); 370 + const struct imx8mp_blk_ctrl_domain_data *data = domain->data; 371 + struct imx8mp_blk_ctrl *bc = domain->bc; 372 + int ret; 373 + 374 + /* make sure bus domain is awake */ 375 + ret = pm_runtime_resume_and_get(bc->bus_power_dev); 376 + if (ret < 0) { 377 + dev_err(bc->dev, "failed to power up bus domain\n"); 378 + return ret; 379 + } 380 + 381 + /* enable upstream clocks */ 382 + ret = clk_bulk_prepare_enable(data->num_clks, domain->clks); 383 + if (ret) { 384 + dev_err(bc->dev, "failed to enable clocks\n"); 385 + goto bus_put; 386 + } 387 + 388 + /* domain specific blk-ctrl manipulation */ 389 + bc->power_on(bc, domain); 390 + 391 + /* power up upstream GPC domain */ 392 + ret = pm_runtime_resume_and_get(domain->power_dev); 393 + if (ret < 0) { 394 + dev_err(bc->dev, "failed to power up peripheral domain\n"); 395 + goto clk_disable; 396 + } 397 + 398 + clk_bulk_disable_unprepare(data->num_clks, domain->clks); 399 + 400 + return 0; 401 + 402 + clk_disable: 403 + clk_bulk_disable_unprepare(data->num_clks, domain->clks); 404 + bus_put: 405 + pm_runtime_put(bc->bus_power_dev); 406 + 407 + return ret; 408 + } 409 + 410 + static int imx8mp_blk_ctrl_power_off(struct generic_pm_domain *genpd) 411 + { 412 + struct imx8mp_blk_ctrl_domain *domain = to_imx8mp_blk_ctrl_domain(genpd); 413 + const struct imx8mp_blk_ctrl_domain_data *data = domain->data; 414 + struct imx8mp_blk_ctrl *bc = domain->bc; 415 + int ret; 416 + 417 + ret = clk_bulk_prepare_enable(data->num_clks, domain->clks); 418 + if (ret) { 419 + dev_err(bc->dev, "failed to enable clocks\n"); 420 + return ret; 421 + } 422 + 423 + /* domain specific blk-ctrl manipulation */ 424 + bc->power_off(bc, domain); 425 + 426 + clk_bulk_disable_unprepare(data->num_clks, domain->clks); 427 + 428 + /* power down upstream GPC domain */ 429 + pm_runtime_put(domain->power_dev); 430 + 431 + /* allow bus domain to suspend */ 432 + pm_runtime_put(bc->bus_power_dev); 433 + 434 + return 0; 435 + } 436 + 437 + static struct generic_pm_domain * 438 + imx8m_blk_ctrl_xlate(struct of_phandle_args *args, void *data) 439 + { 440 + struct genpd_onecell_data *onecell_data = data; 441 + unsigned int index = args->args[0]; 442 + 443 + if (args->args_count != 1 || 444 + index >= onecell_data->num_domains) 445 + return ERR_PTR(-EINVAL); 446 + 447 + return onecell_data->domains[index]; 448 + } 449 + 450 + static struct lock_class_key blk_ctrl_genpd_lock_class; 451 + 452 + static int imx8mp_blk_ctrl_probe(struct platform_device *pdev) 453 + { 454 + const struct imx8mp_blk_ctrl_data *bc_data; 455 + struct device *dev = &pdev->dev; 456 + struct imx8mp_blk_ctrl *bc; 457 + void __iomem *base; 458 + int num_domains, i, ret; 459 + 460 + struct regmap_config regmap_config = { 461 + .reg_bits = 32, 462 + .val_bits = 32, 463 + .reg_stride = 4, 464 + }; 465 + 466 + bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL); 467 + if (!bc) 468 + return -ENOMEM; 469 + 470 + bc->dev = dev; 471 + 472 + bc_data = of_device_get_match_data(dev); 473 + num_domains = bc_data->num_domains; 474 + 475 + base = devm_platform_ioremap_resource(pdev, 0); 476 + if (IS_ERR(base)) 477 + return PTR_ERR(base); 478 + 479 + regmap_config.max_register = bc_data->max_reg; 480 + bc->regmap = devm_regmap_init_mmio(dev, base, &regmap_config); 481 + if (IS_ERR(bc->regmap)) 482 + return dev_err_probe(dev, PTR_ERR(bc->regmap), 483 + "failed to init regmap\n"); 484 + 485 + bc->domains = devm_kcalloc(dev, num_domains, 486 + sizeof(struct imx8mp_blk_ctrl_domain), 487 + GFP_KERNEL); 488 + if (!bc->domains) 489 + return -ENOMEM; 490 + 491 + bc->onecell_data.num_domains = num_domains; 492 + bc->onecell_data.xlate = imx8m_blk_ctrl_xlate; 493 + bc->onecell_data.domains = 494 + devm_kcalloc(dev, num_domains, 495 + sizeof(struct generic_pm_domain *), GFP_KERNEL); 496 + if (!bc->onecell_data.domains) 497 + return -ENOMEM; 498 + 499 + bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus"); 500 + if (IS_ERR(bc->bus_power_dev)) 501 + return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev), 502 + "failed to attach bus power domain\n"); 503 + 504 + bc->power_off = bc_data->power_off; 505 + bc->power_on = bc_data->power_on; 506 + 507 + for (i = 0; i < num_domains; i++) { 508 + const struct imx8mp_blk_ctrl_domain_data *data = &bc_data->domains[i]; 509 + struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i]; 510 + int j; 511 + 512 + domain->data = data; 513 + 514 + for (j = 0; j < data->num_clks; j++) 515 + domain->clks[j].id = data->clk_names[j]; 516 + 517 + ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks); 518 + if (ret) { 519 + dev_err_probe(dev, ret, "failed to get clock\n"); 520 + goto cleanup_pds; 521 + } 522 + 523 + domain->power_dev = 524 + dev_pm_domain_attach_by_name(dev, data->gpc_name); 525 + if (IS_ERR(domain->power_dev)) { 526 + dev_err_probe(dev, PTR_ERR(domain->power_dev), 527 + "failed to attach power domain %s\n", 528 + data->gpc_name); 529 + ret = PTR_ERR(domain->power_dev); 530 + goto cleanup_pds; 531 + } 532 + dev_set_name(domain->power_dev, "%s", data->name); 533 + 534 + domain->genpd.name = data->name; 535 + domain->genpd.power_on = imx8mp_blk_ctrl_power_on; 536 + domain->genpd.power_off = imx8mp_blk_ctrl_power_off; 537 + domain->bc = bc; 538 + domain->id = i; 539 + 540 + ret = pm_genpd_init(&domain->genpd, NULL, true); 541 + if (ret) { 542 + dev_err_probe(dev, ret, "failed to init power domain\n"); 543 + dev_pm_domain_detach(domain->power_dev, true); 544 + goto cleanup_pds; 545 + } 546 + 547 + /* 548 + * We use runtime PM to trigger power on/off of the upstream GPC 549 + * domain, as a strict hierarchical parent/child power domain 550 + * setup doesn't allow us to meet the sequencing requirements. 551 + * This means we have nested locking of genpd locks, without the 552 + * nesting being visible at the genpd level, so we need a 553 + * separate lock class to make lockdep aware of the fact that 554 + * this are separate domain locks that can be nested without a 555 + * self-deadlock. 556 + */ 557 + lockdep_set_class(&domain->genpd.mlock, 558 + &blk_ctrl_genpd_lock_class); 559 + 560 + bc->onecell_data.domains[i] = &domain->genpd; 561 + } 562 + 563 + ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data); 564 + if (ret) { 565 + dev_err_probe(dev, ret, "failed to add power domain provider\n"); 566 + goto cleanup_pds; 567 + } 568 + 569 + bc->power_nb.notifier_call = bc_data->power_notifier_fn; 570 + ret = dev_pm_genpd_add_notifier(bc->bus_power_dev, &bc->power_nb); 571 + if (ret) { 572 + dev_err_probe(dev, ret, "failed to add power notifier\n"); 573 + goto cleanup_provider; 574 + } 575 + 576 + dev_set_drvdata(dev, bc); 577 + 578 + return 0; 579 + 580 + cleanup_provider: 581 + of_genpd_del_provider(dev->of_node); 582 + cleanup_pds: 583 + for (i--; i >= 0; i--) { 584 + pm_genpd_remove(&bc->domains[i].genpd); 585 + dev_pm_domain_detach(bc->domains[i].power_dev, true); 586 + } 587 + 588 + dev_pm_domain_detach(bc->bus_power_dev, true); 589 + 590 + return ret; 591 + } 592 + 593 + static int imx8mp_blk_ctrl_remove(struct platform_device *pdev) 594 + { 595 + struct imx8mp_blk_ctrl *bc = dev_get_drvdata(&pdev->dev); 596 + int i; 597 + 598 + of_genpd_del_provider(pdev->dev.of_node); 599 + 600 + for (i = 0; bc->onecell_data.num_domains; i++) { 601 + struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i]; 602 + 603 + pm_genpd_remove(&domain->genpd); 604 + dev_pm_domain_detach(domain->power_dev, true); 605 + } 606 + 607 + dev_pm_genpd_remove_notifier(bc->bus_power_dev); 608 + 609 + dev_pm_domain_detach(bc->bus_power_dev, true); 610 + 611 + return 0; 612 + } 613 + 614 + #ifdef CONFIG_PM_SLEEP 615 + static int imx8mp_blk_ctrl_suspend(struct device *dev) 616 + { 617 + struct imx8mp_blk_ctrl *bc = dev_get_drvdata(dev); 618 + int ret, i; 619 + 620 + /* 621 + * This may look strange, but is done so the generic PM_SLEEP code 622 + * can power down our domains and more importantly power them up again 623 + * after resume, without tripping over our usage of runtime PM to 624 + * control the upstream GPC domains. Things happen in the right order 625 + * in the system suspend/resume paths due to the device parent/child 626 + * hierarchy. 627 + */ 628 + ret = pm_runtime_get_sync(bc->bus_power_dev); 629 + if (ret < 0) { 630 + pm_runtime_put_noidle(bc->bus_power_dev); 631 + return ret; 632 + } 633 + 634 + for (i = 0; i < bc->onecell_data.num_domains; i++) { 635 + struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i]; 636 + 637 + ret = pm_runtime_get_sync(domain->power_dev); 638 + if (ret < 0) { 639 + pm_runtime_put_noidle(domain->power_dev); 640 + goto out_fail; 641 + } 642 + } 643 + 644 + return 0; 645 + 646 + out_fail: 647 + for (i--; i >= 0; i--) 648 + pm_runtime_put(bc->domains[i].power_dev); 649 + 650 + pm_runtime_put(bc->bus_power_dev); 651 + 652 + return ret; 653 + } 654 + 655 + static int imx8mp_blk_ctrl_resume(struct device *dev) 656 + { 657 + struct imx8mp_blk_ctrl *bc = dev_get_drvdata(dev); 658 + int i; 659 + 660 + for (i = 0; i < bc->onecell_data.num_domains; i++) 661 + pm_runtime_put(bc->domains[i].power_dev); 662 + 663 + pm_runtime_put(bc->bus_power_dev); 664 + 665 + return 0; 666 + } 667 + #endif 668 + 669 + static const struct dev_pm_ops imx8mp_blk_ctrl_pm_ops = { 670 + SET_SYSTEM_SLEEP_PM_OPS(imx8mp_blk_ctrl_suspend, 671 + imx8mp_blk_ctrl_resume) 672 + }; 673 + 674 + static const struct of_device_id imx8mp_blk_ctrl_of_match[] = { 675 + { 676 + .compatible = "fsl,imx8mp-hsio-blk-ctrl", 677 + .data = &imx8mp_hsio_blk_ctl_dev_data, 678 + }, { 679 + .compatible = "fsl,imx8mp-hdmi-blk-ctrl", 680 + .data = &imx8mp_hdmi_blk_ctl_dev_data, 681 + }, { 682 + /* Sentinel */ 683 + } 684 + }; 685 + MODULE_DEVICE_TABLE(of, imx8m_blk_ctrl_of_match); 686 + 687 + static struct platform_driver imx8mp_blk_ctrl_driver = { 688 + .probe = imx8mp_blk_ctrl_probe, 689 + .remove = imx8mp_blk_ctrl_remove, 690 + .driver = { 691 + .name = "imx8mp-blk-ctrl", 692 + .pm = &imx8mp_blk_ctrl_pm_ops, 693 + .of_match_table = imx8mp_blk_ctrl_of_match, 694 + }, 695 + }; 696 + module_platform_driver(imx8mp_blk_ctrl_driver);
+18
include/dt-bindings/power/imx8mp-power.h
··· 32 32 #define IMX8MP_HSIOBLK_PD_PCIE 3 33 33 #define IMX8MP_HSIOBLK_PD_PCIE_PHY 4 34 34 35 + #define IMX8MP_MEDIABLK_PD_MIPI_DSI_1 0 36 + #define IMX8MP_MEDIABLK_PD_MIPI_CSI2_1 1 37 + #define IMX8MP_MEDIABLK_PD_LCDIF_1 2 38 + #define IMX8MP_MEDIABLK_PD_ISI 3 39 + #define IMX8MP_MEDIABLK_PD_MIPI_CSI2_2 4 40 + #define IMX8MP_MEDIABLK_PD_LCDIF_2 5 41 + #define IMX8MP_MEDIABLK_PD_ISP 6 42 + #define IMX8MP_MEDIABLK_PD_DWE 7 43 + #define IMX8MP_MEDIABLK_PD_MIPI_DSI_2 8 44 + 45 + #define IMX8MP_HDMIBLK_PD_IRQSTEER 0 46 + #define IMX8MP_HDMIBLK_PD_LCDIF 1 47 + #define IMX8MP_HDMIBLK_PD_PAI 2 48 + #define IMX8MP_HDMIBLK_PD_PVI 3 49 + #define IMX8MP_HDMIBLK_PD_TRNG 4 50 + #define IMX8MP_HDMIBLK_PD_HDMI_TX 5 51 + #define IMX8MP_HDMIBLK_PD_HDMI_TX_PHY 6 52 + 35 53 #endif