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

Configure Feed

Select the types of activity you want to include in your feed.

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

i.MX drivers update for 5.14:

- A patch series from Lucas Stach and Peng Fan adding i.MX8MM power
domains support into i.MX GPCv2 driver.
- A couple of patches from Adam Ford adding i.MX8MN power domains on top
of i.MX8MM power domain support.

* tag 'imx-drivers-5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux:
soc: imx: gpcv2: add support for i.MX8MN power domains
dt-bindings: add defines for i.MX8MN power domains
soc: imx: gpcv2: move reset assert after requesting domain power up
soc: imx: gpcv2: Add support for missing i.MX8MM VPU/DISPMIX power domains
soc: imx: gpcv2: add support for i.MX8MM power domains
dt-bindings: power: add defines for i.MX8MM power domains
soc: imx: gpcv2: add support for optional resets
soc: imx: gpcv2: allow domains without power-sequence control
soc: imx: gpcv2: add runtime PM support for power-domains
soc: imx: gpcv2: wait for ADB400 handshake
soc: imx: gpcv2: split power up and power down sequence control
soc: imx: gpcv2: switch to clk_bulk_* API
soc: imx: gpcv2: move domain mapping to domain driver probe
soc: imx: gpcv2: move to more ideomatic error handling in probe

Link: https://lore.kernel.org/r/20210613082544.16067-1-shawnguo@kernel.org
Signed-off-by: Olof Johansson <olof@lixom.net>

+557 -113
+3
Documentation/devicetree/bindings/power/fsl,imx-gpcv2.yaml
··· 25 25 compatible: 26 26 enum: 27 27 - fsl,imx7d-gpc 28 + - fsl,imx8mn-gpc 28 29 - fsl,imx8mq-gpc 30 + - fsl,imx8mm-gpc 29 31 30 32 reg: 31 33 maxItems: 1 ··· 56 54 Power domain index. Valid values are defined in 57 55 include/dt-bindings/power/imx7-power.h for fsl,imx7d-gpc and 58 56 include/dt-bindings/power/imx8m-power.h for fsl,imx8mq-gpc 57 + include/dt-bindings/power/imx8mm-power.h for fsl,imx8mm-gpc 59 58 maxItems: 1 60 59 61 60 clocks:
+517 -113
drivers/soc/imx/gpcv2.c
··· 12 12 #include <linux/of_device.h> 13 13 #include <linux/platform_device.h> 14 14 #include <linux/pm_domain.h> 15 + #include <linux/pm_runtime.h> 15 16 #include <linux/regmap.h> 16 17 #include <linux/regulator/consumer.h> 18 + #include <linux/reset.h> 17 19 #include <linux/sizes.h> 18 20 #include <dt-bindings/power/imx7-power.h> 19 21 #include <dt-bindings/power/imx8mq-power.h> 22 + #include <dt-bindings/power/imx8mm-power.h> 23 + #include <dt-bindings/power/imx8mn-power.h> 20 24 21 25 #define GPC_LPCR_A_CORE_BSC 0x000 22 26 ··· 46 42 #define IMX8M_PCIE1_A53_DOMAIN BIT(3) 47 43 #define IMX8M_MIPI_A53_DOMAIN BIT(2) 48 44 45 + #define IMX8MM_VPUH1_A53_DOMAIN BIT(15) 46 + #define IMX8MM_VPUG2_A53_DOMAIN BIT(14) 47 + #define IMX8MM_VPUG1_A53_DOMAIN BIT(13) 48 + #define IMX8MM_DISPMIX_A53_DOMAIN BIT(12) 49 + #define IMX8MM_VPUMIX_A53_DOMAIN BIT(10) 50 + #define IMX8MM_GPUMIX_A53_DOMAIN BIT(9) 51 + #define IMX8MM_GPU_A53_DOMAIN (BIT(8) | BIT(11)) 52 + #define IMX8MM_DDR1_A53_DOMAIN BIT(7) 53 + #define IMX8MM_OTG2_A53_DOMAIN BIT(5) 54 + #define IMX8MM_OTG1_A53_DOMAIN BIT(4) 55 + #define IMX8MM_PCIE_A53_DOMAIN BIT(3) 56 + #define IMX8MM_MIPI_A53_DOMAIN BIT(2) 57 + 58 + #define IMX8MN_DISPMIX_A53_DOMAIN BIT(12) 59 + #define IMX8MN_GPUMIX_A53_DOMAIN BIT(9) 60 + #define IMX8MN_DDR1_A53_DOMAIN BIT(7) 61 + #define IMX8MN_OTG1_A53_DOMAIN BIT(4) 62 + #define IMX8MN_MIPI_A53_DOMAIN BIT(2) 63 + 49 64 #define GPC_PU_PGC_SW_PUP_REQ 0x0f8 50 65 #define GPC_PU_PGC_SW_PDN_REQ 0x104 51 66 ··· 88 65 #define IMX8M_PCIE1_SW_Pxx_REQ BIT(1) 89 66 #define IMX8M_MIPI_SW_Pxx_REQ BIT(0) 90 67 68 + #define IMX8MM_VPUH1_SW_Pxx_REQ BIT(13) 69 + #define IMX8MM_VPUG2_SW_Pxx_REQ BIT(12) 70 + #define IMX8MM_VPUG1_SW_Pxx_REQ BIT(11) 71 + #define IMX8MM_DISPMIX_SW_Pxx_REQ BIT(10) 72 + #define IMX8MM_VPUMIX_SW_Pxx_REQ BIT(8) 73 + #define IMX8MM_GPUMIX_SW_Pxx_REQ BIT(7) 74 + #define IMX8MM_GPU_SW_Pxx_REQ (BIT(6) | BIT(9)) 75 + #define IMX8MM_DDR1_SW_Pxx_REQ BIT(5) 76 + #define IMX8MM_OTG2_SW_Pxx_REQ BIT(3) 77 + #define IMX8MM_OTG1_SW_Pxx_REQ BIT(2) 78 + #define IMX8MM_PCIE_SW_Pxx_REQ BIT(1) 79 + #define IMX8MM_MIPI_SW_Pxx_REQ BIT(0) 80 + 81 + #define IMX8MN_DISPMIX_SW_Pxx_REQ BIT(10) 82 + #define IMX8MN_GPUMIX_SW_Pxx_REQ BIT(7) 83 + #define IMX8MN_DDR1_SW_Pxx_REQ BIT(5) 84 + #define IMX8MN_OTG1_SW_Pxx_REQ BIT(2) 85 + #define IMX8MN_MIPI_SW_Pxx_REQ BIT(0) 86 + 91 87 #define GPC_M4_PU_PDN_FLG 0x1bc 92 88 93 89 #define GPC_PU_PWRHSK 0x1fc 94 90 91 + #define IMX8M_GPU_HSK_PWRDNACKN BIT(26) 92 + #define IMX8M_VPU_HSK_PWRDNACKN BIT(25) 93 + #define IMX8M_DISP_HSK_PWRDNACKN BIT(24) 95 94 #define IMX8M_GPU_HSK_PWRDNREQN BIT(6) 96 95 #define IMX8M_VPU_HSK_PWRDNREQN BIT(5) 97 96 #define IMX8M_DISP_HSK_PWRDNREQN BIT(4) 97 + 98 + 99 + #define IMX8MM_GPUMIX_HSK_PWRDNACKN BIT(29) 100 + #define IMX8MM_GPU_HSK_PWRDNACKN (BIT(27) | BIT(28)) 101 + #define IMX8MM_VPUMIX_HSK_PWRDNACKN BIT(26) 102 + #define IMX8MM_DISPMIX_HSK_PWRDNACKN BIT(25) 103 + #define IMX8MM_HSIO_HSK_PWRDNACKN (BIT(23) | BIT(24)) 104 + #define IMX8MM_GPUMIX_HSK_PWRDNREQN BIT(11) 105 + #define IMX8MM_GPU_HSK_PWRDNREQN (BIT(9) | BIT(10)) 106 + #define IMX8MM_VPUMIX_HSK_PWRDNREQN BIT(8) 107 + #define IMX8MM_DISPMIX_HSK_PWRDNREQN BIT(7) 108 + #define IMX8MM_HSIO_HSK_PWRDNREQN (BIT(5) | BIT(6)) 109 + 110 + #define IMX8MN_GPUMIX_HSK_PWRDNACKN (BIT(29) | BIT(27)) 111 + #define IMX8MN_DISPMIX_HSK_PWRDNACKN BIT(25) 112 + #define IMX8MN_HSIO_HSK_PWRDNACKN BIT(23) 113 + #define IMX8MN_GPUMIX_HSK_PWRDNREQN (BIT(11) | BIT(9)) 114 + #define IMX8MN_DISPMIX_HSK_PWRDNREQN BIT(7) 115 + #define IMX8MN_HSIO_HSK_PWRDNREQN BIT(5) 98 116 99 117 /* 100 118 * The PGC offset values in Reference Manual ··· 159 95 #define IMX8M_PGC_MIPI_CSI2 28 160 96 #define IMX8M_PGC_PCIE2 29 161 97 98 + #define IMX8MM_PGC_MIPI 16 99 + #define IMX8MM_PGC_PCIE 17 100 + #define IMX8MM_PGC_OTG1 18 101 + #define IMX8MM_PGC_OTG2 19 102 + #define IMX8MM_PGC_DDR1 21 103 + #define IMX8MM_PGC_GPU2D 22 104 + #define IMX8MM_PGC_GPUMIX 23 105 + #define IMX8MM_PGC_VPUMIX 24 106 + #define IMX8MM_PGC_GPU3D 25 107 + #define IMX8MM_PGC_DISPMIX 26 108 + #define IMX8MM_PGC_VPUG1 27 109 + #define IMX8MM_PGC_VPUG2 28 110 + #define IMX8MM_PGC_VPUH1 29 111 + 112 + #define IMX8MN_PGC_MIPI 16 113 + #define IMX8MN_PGC_OTG1 18 114 + #define IMX8MN_PGC_DDR1 21 115 + #define IMX8MN_PGC_GPUMIX 23 116 + #define IMX8MN_PGC_DISPMIX 26 117 + 162 118 #define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40) 163 119 #define GPC_PGC_SR(n) (GPC_PGC_CTRL(n) + 0xc) 164 120 165 121 #define GPC_PGC_CTRL_PCR BIT(0) 166 122 167 - #define GPC_CLK_MAX 6 168 - 169 123 struct imx_pgc_domain { 170 124 struct generic_pm_domain genpd; 171 125 struct regmap *regmap; 172 126 struct regulator *regulator; 173 - struct clk *clk[GPC_CLK_MAX]; 127 + struct reset_control *reset; 128 + struct clk_bulk_data *clks; 174 129 int num_clks; 175 130 176 131 unsigned int pgc; ··· 197 114 const struct { 198 115 u32 pxx; 199 116 u32 map; 200 - u32 hsk; 117 + u32 hskreq; 118 + u32 hskack; 201 119 } bits; 202 120 203 121 const int voltage; ··· 211 127 const struct regmap_access_table *reg_access_table; 212 128 }; 213 129 214 - static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd, 215 - bool on) 130 + static inline struct imx_pgc_domain * 131 + to_imx_pgc_domain(struct generic_pm_domain *genpd) 216 132 { 217 - struct imx_pgc_domain *domain = container_of(genpd, 218 - struct imx_pgc_domain, 219 - genpd); 220 - unsigned int offset = on ? 221 - GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ; 222 - const bool enable_power_control = !on; 223 - const bool has_regulator = !IS_ERR(domain->regulator); 224 - int i, ret = 0; 225 - u32 pxx_req; 133 + return container_of(genpd, struct imx_pgc_domain, genpd); 134 + } 226 135 227 - regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, 228 - domain->bits.map, domain->bits.map); 136 + static int imx_pgc_power_up(struct generic_pm_domain *genpd) 137 + { 138 + struct imx_pgc_domain *domain = to_imx_pgc_domain(genpd); 139 + u32 reg_val; 140 + int ret; 229 141 230 - if (has_regulator && on) { 142 + ret = pm_runtime_get_sync(domain->dev); 143 + if (ret < 0) { 144 + pm_runtime_put_noidle(domain->dev); 145 + return ret; 146 + } 147 + 148 + if (!IS_ERR(domain->regulator)) { 231 149 ret = regulator_enable(domain->regulator); 232 150 if (ret) { 233 151 dev_err(domain->dev, "failed to enable regulator\n"); 234 - goto unmap; 152 + goto out_put_pm; 235 153 } 236 154 } 237 155 238 156 /* Enable reset clocks for all devices in the domain */ 239 - for (i = 0; i < domain->num_clks; i++) 240 - clk_prepare_enable(domain->clk[i]); 241 - 242 - if (enable_power_control) 243 - regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), 244 - GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR); 245 - 246 - if (domain->bits.hsk) 247 - regmap_update_bits(domain->regmap, GPC_PU_PWRHSK, 248 - domain->bits.hsk, on ? domain->bits.hsk : 0); 249 - 250 - regmap_update_bits(domain->regmap, offset, 251 - domain->bits.pxx, domain->bits.pxx); 252 - 253 - /* 254 - * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait 255 - * for PUP_REQ/PDN_REQ bit to be cleared 256 - */ 257 - ret = regmap_read_poll_timeout(domain->regmap, offset, pxx_req, 258 - !(pxx_req & domain->bits.pxx), 259 - 0, USEC_PER_MSEC); 157 + ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks); 260 158 if (ret) { 261 - dev_err(domain->dev, "failed to command PGC\n"); 262 - /* 263 - * If we were in a process of enabling a 264 - * domain and failed we might as well disable 265 - * the regulator we just enabled. And if it 266 - * was the opposite situation and we failed to 267 - * power down -- keep the regulator on 268 - */ 269 - on = !on; 159 + dev_err(domain->dev, "failed to enable reset clocks\n"); 160 + goto out_regulator_disable; 270 161 } 271 162 272 - if (enable_power_control) 273 - regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), 274 - GPC_PGC_CTRL_PCR, 0); 163 + if (domain->bits.pxx) { 164 + /* request the domain to power up */ 165 + regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PUP_REQ, 166 + domain->bits.pxx, domain->bits.pxx); 167 + /* 168 + * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait 169 + * for PUP_REQ/PDN_REQ bit to be cleared 170 + */ 171 + ret = regmap_read_poll_timeout(domain->regmap, 172 + GPC_PU_PGC_SW_PUP_REQ, reg_val, 173 + !(reg_val & domain->bits.pxx), 174 + 0, USEC_PER_MSEC); 175 + if (ret) { 176 + dev_err(domain->dev, "failed to command PGC\n"); 177 + goto out_clk_disable; 178 + } 179 + 180 + /* disable power control */ 181 + regmap_clear_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), 182 + GPC_PGC_CTRL_PCR); 183 + } 184 + 185 + reset_control_assert(domain->reset); 186 + 187 + /* delay for reset to propagate */ 188 + udelay(5); 189 + 190 + reset_control_deassert(domain->reset); 191 + 192 + /* request the ADB400 to power up */ 193 + if (domain->bits.hskreq) { 194 + regmap_update_bits(domain->regmap, GPC_PU_PWRHSK, 195 + domain->bits.hskreq, domain->bits.hskreq); 196 + 197 + /* 198 + * ret = regmap_read_poll_timeout(domain->regmap, GPC_PU_PWRHSK, reg_val, 199 + * (reg_val & domain->bits.hskack), 0, 200 + * USEC_PER_MSEC); 201 + * Technically we need the commented code to wait handshake. But that needs 202 + * the BLK-CTL module BUS clk-en bit being set. 203 + * 204 + * There is a separate BLK-CTL module and we will have such a driver for it, 205 + * that driver will set the BUS clk-en bit and handshake will be triggered 206 + * automatically there. Just add a delay and suppose the handshake finish 207 + * after that. 208 + */ 209 + } 275 210 276 211 /* Disable reset clocks for all devices in the domain */ 277 - for (i = 0; i < domain->num_clks; i++) 278 - clk_disable_unprepare(domain->clk[i]); 212 + clk_bulk_disable_unprepare(domain->num_clks, domain->clks); 279 213 280 - if (has_regulator && !on) { 281 - int err; 214 + return 0; 282 215 283 - err = regulator_disable(domain->regulator); 284 - if (err) 285 - dev_err(domain->dev, 286 - "failed to disable regulator: %d\n", err); 287 - /* Preserve earlier error code */ 288 - ret = ret ?: err; 289 - } 290 - unmap: 291 - regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, 292 - domain->bits.map, 0); 216 + out_clk_disable: 217 + clk_bulk_disable_unprepare(domain->num_clks, domain->clks); 218 + out_regulator_disable: 219 + if (!IS_ERR(domain->regulator)) 220 + regulator_disable(domain->regulator); 221 + out_put_pm: 222 + pm_runtime_put(domain->dev); 223 + 293 224 return ret; 294 225 } 295 226 296 - static int imx_gpc_pu_pgc_sw_pup_req(struct generic_pm_domain *genpd) 227 + static int imx_pgc_power_down(struct generic_pm_domain *genpd) 297 228 { 298 - return imx_gpc_pu_pgc_sw_pxx_req(genpd, true); 299 - } 229 + struct imx_pgc_domain *domain = to_imx_pgc_domain(genpd); 230 + u32 reg_val; 231 + int ret; 300 232 301 - static int imx_gpc_pu_pgc_sw_pdn_req(struct generic_pm_domain *genpd) 302 - { 303 - return imx_gpc_pu_pgc_sw_pxx_req(genpd, false); 233 + /* Enable reset clocks for all devices in the domain */ 234 + ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks); 235 + if (ret) { 236 + dev_err(domain->dev, "failed to enable reset clocks\n"); 237 + return ret; 238 + } 239 + 240 + /* request the ADB400 to power down */ 241 + if (domain->bits.hskreq) { 242 + regmap_clear_bits(domain->regmap, GPC_PU_PWRHSK, 243 + domain->bits.hskreq); 244 + 245 + ret = regmap_read_poll_timeout(domain->regmap, GPC_PU_PWRHSK, 246 + reg_val, 247 + !(reg_val & domain->bits.hskack), 248 + 0, USEC_PER_MSEC); 249 + if (ret) { 250 + dev_err(domain->dev, "failed to power down ADB400\n"); 251 + goto out_clk_disable; 252 + } 253 + } 254 + 255 + if (domain->bits.pxx) { 256 + /* enable power control */ 257 + regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), 258 + GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR); 259 + 260 + /* request the domain to power down */ 261 + regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PDN_REQ, 262 + domain->bits.pxx, domain->bits.pxx); 263 + /* 264 + * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait 265 + * for PUP_REQ/PDN_REQ bit to be cleared 266 + */ 267 + ret = regmap_read_poll_timeout(domain->regmap, 268 + GPC_PU_PGC_SW_PDN_REQ, reg_val, 269 + !(reg_val & domain->bits.pxx), 270 + 0, USEC_PER_MSEC); 271 + if (ret) { 272 + dev_err(domain->dev, "failed to command PGC\n"); 273 + goto out_clk_disable; 274 + } 275 + } 276 + 277 + /* Disable reset clocks for all devices in the domain */ 278 + clk_bulk_disable_unprepare(domain->num_clks, domain->clks); 279 + 280 + if (!IS_ERR(domain->regulator)) { 281 + ret = regulator_disable(domain->regulator); 282 + if (ret) { 283 + dev_err(domain->dev, "failed to disable regulator\n"); 284 + return ret; 285 + } 286 + } 287 + 288 + pm_runtime_put(domain->dev); 289 + 290 + return 0; 291 + 292 + out_clk_disable: 293 + clk_bulk_disable_unprepare(domain->num_clks, domain->clks); 294 + 295 + return ret; 304 296 } 305 297 306 298 static const struct imx_pgc_domain imx7_pgc_domains[] = { ··· 502 342 .bits = { 503 343 .pxx = IMX8M_GPU_SW_Pxx_REQ, 504 344 .map = IMX8M_GPU_A53_DOMAIN, 505 - .hsk = IMX8M_GPU_HSK_PWRDNREQN, 345 + .hskreq = IMX8M_GPU_HSK_PWRDNREQN, 346 + .hskack = IMX8M_GPU_HSK_PWRDNACKN, 506 347 }, 507 348 .pgc = IMX8M_PGC_GPU, 508 349 }, ··· 515 354 .bits = { 516 355 .pxx = IMX8M_VPU_SW_Pxx_REQ, 517 356 .map = IMX8M_VPU_A53_DOMAIN, 518 - .hsk = IMX8M_VPU_HSK_PWRDNREQN, 357 + .hskreq = IMX8M_VPU_HSK_PWRDNREQN, 358 + .hskack = IMX8M_VPU_HSK_PWRDNACKN, 519 359 }, 520 360 .pgc = IMX8M_PGC_VPU, 521 361 }, ··· 528 366 .bits = { 529 367 .pxx = IMX8M_DISP_SW_Pxx_REQ, 530 368 .map = IMX8M_DISP_A53_DOMAIN, 531 - .hsk = IMX8M_DISP_HSK_PWRDNREQN, 369 + .hskreq = IMX8M_DISP_HSK_PWRDNREQN, 370 + .hskack = IMX8M_DISP_HSK_PWRDNACKN, 532 371 }, 533 372 .pgc = IMX8M_PGC_DISP, 534 373 }, ··· 606 443 .reg_access_table = &imx8m_access_table, 607 444 }; 608 445 609 - static int imx_pgc_get_clocks(struct imx_pgc_domain *domain) 610 - { 611 - int i, ret; 446 + static const struct imx_pgc_domain imx8mm_pgc_domains[] = { 447 + [IMX8MM_POWER_DOMAIN_HSIOMIX] = { 448 + .genpd = { 449 + .name = "hsiomix", 450 + }, 451 + .bits = { 452 + .pxx = 0, /* no power sequence control */ 453 + .map = 0, /* no power sequence control */ 454 + .hskreq = IMX8MM_HSIO_HSK_PWRDNREQN, 455 + .hskack = IMX8MM_HSIO_HSK_PWRDNACKN, 456 + }, 457 + }, 612 458 613 - for (i = 0; ; i++) { 614 - struct clk *clk = of_clk_get(domain->dev->of_node, i); 615 - if (IS_ERR(clk)) 616 - break; 617 - if (i >= GPC_CLK_MAX) { 618 - dev_err(domain->dev, "more than %d clocks\n", 619 - GPC_CLK_MAX); 620 - ret = -EINVAL; 621 - goto clk_err; 622 - } 623 - domain->clk[i] = clk; 624 - } 625 - domain->num_clks = i; 459 + [IMX8MM_POWER_DOMAIN_PCIE] = { 460 + .genpd = { 461 + .name = "pcie", 462 + }, 463 + .bits = { 464 + .pxx = IMX8MM_PCIE_SW_Pxx_REQ, 465 + .map = IMX8MM_PCIE_A53_DOMAIN, 466 + }, 467 + .pgc = IMX8MM_PGC_PCIE, 468 + }, 626 469 627 - return 0; 470 + [IMX8MM_POWER_DOMAIN_OTG1] = { 471 + .genpd = { 472 + .name = "usb-otg1", 473 + }, 474 + .bits = { 475 + .pxx = IMX8MM_OTG1_SW_Pxx_REQ, 476 + .map = IMX8MM_OTG1_A53_DOMAIN, 477 + }, 478 + .pgc = IMX8MM_PGC_OTG1, 479 + }, 628 480 629 - clk_err: 630 - while (i--) 631 - clk_put(domain->clk[i]); 481 + [IMX8MM_POWER_DOMAIN_OTG2] = { 482 + .genpd = { 483 + .name = "usb-otg2", 484 + }, 485 + .bits = { 486 + .pxx = IMX8MM_OTG2_SW_Pxx_REQ, 487 + .map = IMX8MM_OTG2_A53_DOMAIN, 488 + }, 489 + .pgc = IMX8MM_PGC_OTG2, 490 + }, 632 491 633 - return ret; 634 - } 492 + [IMX8MM_POWER_DOMAIN_GPUMIX] = { 493 + .genpd = { 494 + .name = "gpumix", 495 + }, 496 + .bits = { 497 + .pxx = IMX8MM_GPUMIX_SW_Pxx_REQ, 498 + .map = IMX8MM_GPUMIX_A53_DOMAIN, 499 + .hskreq = IMX8MM_GPUMIX_HSK_PWRDNREQN, 500 + .hskack = IMX8MM_GPUMIX_HSK_PWRDNACKN, 501 + }, 502 + .pgc = IMX8MM_PGC_GPUMIX, 503 + }, 635 504 636 - static void imx_pgc_put_clocks(struct imx_pgc_domain *domain) 637 - { 638 - int i; 505 + [IMX8MM_POWER_DOMAIN_GPU] = { 506 + .genpd = { 507 + .name = "gpu", 508 + }, 509 + .bits = { 510 + .pxx = IMX8MM_GPU_SW_Pxx_REQ, 511 + .map = IMX8MM_GPU_A53_DOMAIN, 512 + .hskreq = IMX8MM_GPU_HSK_PWRDNREQN, 513 + .hskack = IMX8MM_GPU_HSK_PWRDNACKN, 514 + }, 515 + .pgc = IMX8MM_PGC_GPU2D, 516 + }, 639 517 640 - for (i = domain->num_clks - 1; i >= 0; i--) 641 - clk_put(domain->clk[i]); 642 - } 518 + [IMX8MM_POWER_DOMAIN_VPUMIX] = { 519 + .genpd = { 520 + .name = "vpumix", 521 + }, 522 + .bits = { 523 + .pxx = IMX8MM_VPUMIX_SW_Pxx_REQ, 524 + .map = IMX8MM_VPUMIX_A53_DOMAIN, 525 + .hskreq = IMX8MM_VPUMIX_HSK_PWRDNREQN, 526 + .hskack = IMX8MM_VPUMIX_HSK_PWRDNACKN, 527 + }, 528 + .pgc = IMX8MM_PGC_VPUMIX, 529 + }, 530 + 531 + [IMX8MM_POWER_DOMAIN_VPUG1] = { 532 + .genpd = { 533 + .name = "vpu-g1", 534 + }, 535 + .bits = { 536 + .pxx = IMX8MM_VPUG1_SW_Pxx_REQ, 537 + .map = IMX8MM_VPUG1_A53_DOMAIN, 538 + }, 539 + .pgc = IMX8MM_PGC_VPUG1, 540 + }, 541 + 542 + [IMX8MM_POWER_DOMAIN_VPUG2] = { 543 + .genpd = { 544 + .name = "vpu-g2", 545 + }, 546 + .bits = { 547 + .pxx = IMX8MM_VPUG2_SW_Pxx_REQ, 548 + .map = IMX8MM_VPUG2_A53_DOMAIN, 549 + }, 550 + .pgc = IMX8MM_PGC_VPUG2, 551 + }, 552 + 553 + [IMX8MM_POWER_DOMAIN_VPUH1] = { 554 + .genpd = { 555 + .name = "vpu-h1", 556 + }, 557 + .bits = { 558 + .pxx = IMX8MM_VPUH1_SW_Pxx_REQ, 559 + .map = IMX8MM_VPUH1_A53_DOMAIN, 560 + }, 561 + .pgc = IMX8MM_PGC_VPUH1, 562 + }, 563 + 564 + [IMX8MM_POWER_DOMAIN_DISPMIX] = { 565 + .genpd = { 566 + .name = "dispmix", 567 + }, 568 + .bits = { 569 + .pxx = IMX8MM_DISPMIX_SW_Pxx_REQ, 570 + .map = IMX8MM_DISPMIX_A53_DOMAIN, 571 + .hskreq = IMX8MM_DISPMIX_HSK_PWRDNREQN, 572 + .hskack = IMX8MM_DISPMIX_HSK_PWRDNACKN, 573 + }, 574 + .pgc = IMX8MM_PGC_DISPMIX, 575 + }, 576 + 577 + [IMX8MM_POWER_DOMAIN_MIPI] = { 578 + .genpd = { 579 + .name = "mipi", 580 + }, 581 + .bits = { 582 + .pxx = IMX8MM_MIPI_SW_Pxx_REQ, 583 + .map = IMX8MM_MIPI_A53_DOMAIN, 584 + }, 585 + .pgc = IMX8MM_PGC_MIPI, 586 + }, 587 + }; 588 + 589 + static const struct regmap_range imx8mm_yes_ranges[] = { 590 + regmap_reg_range(GPC_LPCR_A_CORE_BSC, 591 + GPC_PU_PWRHSK), 592 + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_MIPI), 593 + GPC_PGC_SR(IMX8MM_PGC_MIPI)), 594 + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_PCIE), 595 + GPC_PGC_SR(IMX8MM_PGC_PCIE)), 596 + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_OTG1), 597 + GPC_PGC_SR(IMX8MM_PGC_OTG1)), 598 + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_OTG2), 599 + GPC_PGC_SR(IMX8MM_PGC_OTG2)), 600 + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_DDR1), 601 + GPC_PGC_SR(IMX8MM_PGC_DDR1)), 602 + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_GPU2D), 603 + GPC_PGC_SR(IMX8MM_PGC_GPU2D)), 604 + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_GPUMIX), 605 + GPC_PGC_SR(IMX8MM_PGC_GPUMIX)), 606 + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUMIX), 607 + GPC_PGC_SR(IMX8MM_PGC_VPUMIX)), 608 + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_GPU3D), 609 + GPC_PGC_SR(IMX8MM_PGC_GPU3D)), 610 + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_DISPMIX), 611 + GPC_PGC_SR(IMX8MM_PGC_DISPMIX)), 612 + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUG1), 613 + GPC_PGC_SR(IMX8MM_PGC_VPUG1)), 614 + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUG2), 615 + GPC_PGC_SR(IMX8MM_PGC_VPUG2)), 616 + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUH1), 617 + GPC_PGC_SR(IMX8MM_PGC_VPUH1)), 618 + }; 619 + 620 + static const struct regmap_access_table imx8mm_access_table = { 621 + .yes_ranges = imx8mm_yes_ranges, 622 + .n_yes_ranges = ARRAY_SIZE(imx8mm_yes_ranges), 623 + }; 624 + 625 + static const struct imx_pgc_domain_data imx8mm_pgc_domain_data = { 626 + .domains = imx8mm_pgc_domains, 627 + .domains_num = ARRAY_SIZE(imx8mm_pgc_domains), 628 + .reg_access_table = &imx8mm_access_table, 629 + }; 630 + 631 + static const struct imx_pgc_domain imx8mn_pgc_domains[] = { 632 + [IMX8MN_POWER_DOMAIN_HSIOMIX] = { 633 + .genpd = { 634 + .name = "hsiomix", 635 + }, 636 + .bits = { 637 + .pxx = 0, /* no power sequence control */ 638 + .map = 0, /* no power sequence control */ 639 + .hskreq = IMX8MN_HSIO_HSK_PWRDNREQN, 640 + .hskack = IMX8MN_HSIO_HSK_PWRDNACKN, 641 + }, 642 + }, 643 + 644 + [IMX8MN_POWER_DOMAIN_OTG1] = { 645 + .genpd = { 646 + .name = "usb-otg1", 647 + }, 648 + .bits = { 649 + .pxx = IMX8MN_OTG1_SW_Pxx_REQ, 650 + .map = IMX8MN_OTG1_A53_DOMAIN, 651 + }, 652 + .pgc = IMX8MN_PGC_OTG1, 653 + }, 654 + 655 + [IMX8MN_POWER_DOMAIN_GPUMIX] = { 656 + .genpd = { 657 + .name = "gpumix", 658 + }, 659 + .bits = { 660 + .pxx = IMX8MN_GPUMIX_SW_Pxx_REQ, 661 + .map = IMX8MN_GPUMIX_A53_DOMAIN, 662 + .hskreq = IMX8MN_GPUMIX_HSK_PWRDNREQN, 663 + .hskack = IMX8MN_GPUMIX_HSK_PWRDNACKN, 664 + }, 665 + .pgc = IMX8MN_PGC_GPUMIX, 666 + }, 667 + }; 668 + 669 + static const struct regmap_range imx8mn_yes_ranges[] = { 670 + regmap_reg_range(GPC_LPCR_A_CORE_BSC, 671 + GPC_PU_PWRHSK), 672 + regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_MIPI), 673 + GPC_PGC_SR(IMX8MN_PGC_MIPI)), 674 + regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_OTG1), 675 + GPC_PGC_SR(IMX8MN_PGC_OTG1)), 676 + regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_DDR1), 677 + GPC_PGC_SR(IMX8MN_PGC_DDR1)), 678 + regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_GPUMIX), 679 + GPC_PGC_SR(IMX8MN_PGC_GPUMIX)), 680 + regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_DISPMIX), 681 + GPC_PGC_SR(IMX8MN_PGC_DISPMIX)), 682 + }; 683 + 684 + static const struct regmap_access_table imx8mn_access_table = { 685 + .yes_ranges = imx8mn_yes_ranges, 686 + .n_yes_ranges = ARRAY_SIZE(imx8mn_yes_ranges), 687 + }; 688 + 689 + static const struct imx_pgc_domain_data imx8mn_pgc_domain_data = { 690 + .domains = imx8mn_pgc_domains, 691 + .domains_num = ARRAY_SIZE(imx8mn_pgc_domains), 692 + .reg_access_table = &imx8mn_access_table, 693 + }; 643 694 644 695 static int imx_pgc_domain_probe(struct platform_device *pdev) 645 696 { ··· 872 495 domain->voltage, domain->voltage); 873 496 } 874 497 875 - ret = imx_pgc_get_clocks(domain); 876 - if (ret) 877 - return dev_err_probe(domain->dev, ret, "Failed to get domain's clocks\n"); 498 + domain->num_clks = devm_clk_bulk_get_all(domain->dev, &domain->clks); 499 + if (domain->num_clks < 0) 500 + return dev_err_probe(domain->dev, domain->num_clks, 501 + "Failed to get domain's clocks\n"); 502 + 503 + domain->reset = devm_reset_control_array_get_optional_exclusive(domain->dev); 504 + if (IS_ERR(domain->reset)) 505 + return dev_err_probe(domain->dev, PTR_ERR(domain->reset), 506 + "Failed to get domain's resets\n"); 507 + 508 + pm_runtime_enable(domain->dev); 509 + 510 + if (domain->bits.map) 511 + regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, 512 + domain->bits.map, domain->bits.map); 878 513 879 514 ret = pm_genpd_init(&domain->genpd, NULL, true); 880 515 if (ret) { 881 516 dev_err(domain->dev, "Failed to init power domain\n"); 882 - imx_pgc_put_clocks(domain); 883 - return ret; 517 + goto out_domain_unmap; 884 518 } 885 519 886 520 ret = of_genpd_add_provider_simple(domain->dev->of_node, 887 521 &domain->genpd); 888 522 if (ret) { 889 523 dev_err(domain->dev, "Failed to add genpd provider\n"); 890 - pm_genpd_remove(&domain->genpd); 891 - imx_pgc_put_clocks(domain); 524 + goto out_genpd_remove; 892 525 } 526 + 527 + return 0; 528 + 529 + out_genpd_remove: 530 + pm_genpd_remove(&domain->genpd); 531 + out_domain_unmap: 532 + if (domain->bits.map) 533 + regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, 534 + domain->bits.map, 0); 535 + pm_runtime_disable(domain->dev); 893 536 894 537 return ret; 895 538 } ··· 920 523 921 524 of_genpd_del_provider(domain->dev->of_node); 922 525 pm_genpd_remove(&domain->genpd); 923 - imx_pgc_put_clocks(domain); 526 + 527 + if (domain->bits.map) 528 + regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, 529 + domain->bits.map, 0); 530 + 531 + pm_runtime_disable(domain->dev); 924 532 925 533 return 0; 926 534 } ··· 1019 617 1020 618 domain = pd_pdev->dev.platform_data; 1021 619 domain->regmap = regmap; 1022 - domain->genpd.power_on = imx_gpc_pu_pgc_sw_pup_req; 1023 - domain->genpd.power_off = imx_gpc_pu_pgc_sw_pdn_req; 620 + domain->genpd.power_on = imx_pgc_power_up; 621 + domain->genpd.power_off = imx_pgc_power_down; 1024 622 1025 623 pd_pdev->dev.parent = dev; 1026 624 pd_pdev->dev.of_node = np; ··· 1038 636 1039 637 static const struct of_device_id imx_gpcv2_dt_ids[] = { 1040 638 { .compatible = "fsl,imx7d-gpc", .data = &imx7_pgc_domain_data, }, 639 + { .compatible = "fsl,imx8mm-gpc", .data = &imx8mm_pgc_domain_data, }, 640 + { .compatible = "fsl,imx8mn-gpc", .data = &imx8mn_pgc_domain_data, }, 1041 641 { .compatible = "fsl,imx8mq-gpc", .data = &imx8m_pgc_domain_data, }, 1042 642 { } 1043 643 };
+22
include/dt-bindings/power/imx8mm-power.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ 2 + /* 3 + * Copyright (C) 2020 Pengutronix, Lucas Stach <kernel@pengutronix.de> 4 + */ 5 + 6 + #ifndef __DT_BINDINGS_IMX8MM_POWER_H__ 7 + #define __DT_BINDINGS_IMX8MM_POWER_H__ 8 + 9 + #define IMX8MM_POWER_DOMAIN_HSIOMIX 0 10 + #define IMX8MM_POWER_DOMAIN_PCIE 1 11 + #define IMX8MM_POWER_DOMAIN_OTG1 2 12 + #define IMX8MM_POWER_DOMAIN_OTG2 3 13 + #define IMX8MM_POWER_DOMAIN_GPUMIX 4 14 + #define IMX8MM_POWER_DOMAIN_GPU 5 15 + #define IMX8MM_POWER_DOMAIN_VPUMIX 6 16 + #define IMX8MM_POWER_DOMAIN_VPUG1 7 17 + #define IMX8MM_POWER_DOMAIN_VPUG2 8 18 + #define IMX8MM_POWER_DOMAIN_VPUH1 9 19 + #define IMX8MM_POWER_DOMAIN_DISPMIX 10 20 + #define IMX8MM_POWER_DOMAIN_MIPI 11 21 + 22 + #endif
+15
include/dt-bindings/power/imx8mn-power.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ 2 + /* 3 + * Copyright (C) 2020 Compass Electronics Group, LLC 4 + */ 5 + 6 + #ifndef __DT_BINDINGS_IMX8MN_POWER_H__ 7 + #define __DT_BINDINGS_IMX8MN_POWER_H__ 8 + 9 + #define IMX8MN_POWER_DOMAIN_HSIOMIX 0 10 + #define IMX8MN_POWER_DOMAIN_OTG1 1 11 + #define IMX8MN_POWER_DOMAIN_GPUMIX 2 12 + #define IMX8MN_POWER_DOMAIN_DISPMIX 3 13 + #define IMX8MN_POWER_DOMAIN_MIPI 4 14 + 15 + #endif