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