diff options
Diffstat (limited to 'drivers/soc/imx')
-rw-r--r-- | drivers/soc/imx/gpcv2.c | 634 | ||||
-rw-r--r-- | drivers/soc/imx/soc-imx.c | 3 | ||||
-rw-r--r-- | drivers/soc/imx/soc-imx8m.c | 84 |
3 files changed, 534 insertions, 187 deletions
diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index db7e7fc321b1..34a9ac1f2b9b 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -12,11 +12,15 @@ #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_domain.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> +#include <linux/reset.h> #include <linux/sizes.h> #include <dt-bindings/power/imx7-power.h> #include <dt-bindings/power/imx8mq-power.h> +#include <dt-bindings/power/imx8mm-power.h> +#include <dt-bindings/power/imx8mn-power.h> #define GPC_LPCR_A_CORE_BSC 0x000 @@ -42,6 +46,25 @@ #define IMX8M_PCIE1_A53_DOMAIN BIT(3) #define IMX8M_MIPI_A53_DOMAIN BIT(2) +#define IMX8MM_VPUH1_A53_DOMAIN BIT(15) +#define IMX8MM_VPUG2_A53_DOMAIN BIT(14) +#define IMX8MM_VPUG1_A53_DOMAIN BIT(13) +#define IMX8MM_DISPMIX_A53_DOMAIN BIT(12) +#define IMX8MM_VPUMIX_A53_DOMAIN BIT(10) +#define IMX8MM_GPUMIX_A53_DOMAIN BIT(9) +#define IMX8MM_GPU_A53_DOMAIN (BIT(8) | BIT(11)) +#define IMX8MM_DDR1_A53_DOMAIN BIT(7) +#define IMX8MM_OTG2_A53_DOMAIN BIT(5) +#define IMX8MM_OTG1_A53_DOMAIN BIT(4) +#define IMX8MM_PCIE_A53_DOMAIN BIT(3) +#define IMX8MM_MIPI_A53_DOMAIN BIT(2) + +#define IMX8MN_DISPMIX_A53_DOMAIN BIT(12) +#define IMX8MN_GPUMIX_A53_DOMAIN BIT(9) +#define IMX8MN_DDR1_A53_DOMAIN BIT(7) +#define IMX8MN_OTG1_A53_DOMAIN BIT(4) +#define IMX8MN_MIPI_A53_DOMAIN BIT(2) + #define GPC_PU_PGC_SW_PUP_REQ 0x0f8 #define GPC_PU_PGC_SW_PDN_REQ 0x104 @@ -65,14 +88,55 @@ #define IMX8M_PCIE1_SW_Pxx_REQ BIT(1) #define IMX8M_MIPI_SW_Pxx_REQ BIT(0) +#define IMX8MM_VPUH1_SW_Pxx_REQ BIT(13) +#define IMX8MM_VPUG2_SW_Pxx_REQ BIT(12) +#define IMX8MM_VPUG1_SW_Pxx_REQ BIT(11) +#define IMX8MM_DISPMIX_SW_Pxx_REQ BIT(10) +#define IMX8MM_VPUMIX_SW_Pxx_REQ BIT(8) +#define IMX8MM_GPUMIX_SW_Pxx_REQ BIT(7) +#define IMX8MM_GPU_SW_Pxx_REQ (BIT(6) | BIT(9)) +#define IMX8MM_DDR1_SW_Pxx_REQ BIT(5) +#define IMX8MM_OTG2_SW_Pxx_REQ BIT(3) +#define IMX8MM_OTG1_SW_Pxx_REQ BIT(2) +#define IMX8MM_PCIE_SW_Pxx_REQ BIT(1) +#define IMX8MM_MIPI_SW_Pxx_REQ BIT(0) + +#define IMX8MN_DISPMIX_SW_Pxx_REQ BIT(10) +#define IMX8MN_GPUMIX_SW_Pxx_REQ BIT(7) +#define IMX8MN_DDR1_SW_Pxx_REQ BIT(5) +#define IMX8MN_OTG1_SW_Pxx_REQ BIT(2) +#define IMX8MN_MIPI_SW_Pxx_REQ BIT(0) + #define GPC_M4_PU_PDN_FLG 0x1bc #define GPC_PU_PWRHSK 0x1fc +#define IMX8M_GPU_HSK_PWRDNACKN BIT(26) +#define IMX8M_VPU_HSK_PWRDNACKN BIT(25) +#define IMX8M_DISP_HSK_PWRDNACKN BIT(24) #define IMX8M_GPU_HSK_PWRDNREQN BIT(6) #define IMX8M_VPU_HSK_PWRDNREQN BIT(5) #define IMX8M_DISP_HSK_PWRDNREQN BIT(4) + +#define IMX8MM_GPUMIX_HSK_PWRDNACKN BIT(29) +#define IMX8MM_GPU_HSK_PWRDNACKN (BIT(27) | BIT(28)) +#define IMX8MM_VPUMIX_HSK_PWRDNACKN BIT(26) +#define IMX8MM_DISPMIX_HSK_PWRDNACKN BIT(25) +#define IMX8MM_HSIO_HSK_PWRDNACKN (BIT(23) | BIT(24)) +#define IMX8MM_GPUMIX_HSK_PWRDNREQN BIT(11) +#define IMX8MM_GPU_HSK_PWRDNREQN (BIT(9) | BIT(10)) +#define IMX8MM_VPUMIX_HSK_PWRDNREQN BIT(8) +#define IMX8MM_DISPMIX_HSK_PWRDNREQN BIT(7) +#define IMX8MM_HSIO_HSK_PWRDNREQN (BIT(5) | BIT(6)) + +#define IMX8MN_GPUMIX_HSK_PWRDNACKN (BIT(29) | BIT(27)) +#define IMX8MN_DISPMIX_HSK_PWRDNACKN BIT(25) +#define IMX8MN_HSIO_HSK_PWRDNACKN BIT(23) +#define IMX8MN_GPUMIX_HSK_PWRDNREQN (BIT(11) | BIT(9)) +#define IMX8MN_DISPMIX_HSK_PWRDNREQN BIT(7) +#define IMX8MN_HSIO_HSK_PWRDNREQN BIT(5) + /* * The PGC offset values in Reference Manual * (Rev. 1, 01/2018 and the older ones) GPC chapter's @@ -95,18 +159,37 @@ #define IMX8M_PGC_MIPI_CSI2 28 #define IMX8M_PGC_PCIE2 29 +#define IMX8MM_PGC_MIPI 16 +#define IMX8MM_PGC_PCIE 17 +#define IMX8MM_PGC_OTG1 18 +#define IMX8MM_PGC_OTG2 19 +#define IMX8MM_PGC_DDR1 21 +#define IMX8MM_PGC_GPU2D 22 +#define IMX8MM_PGC_GPUMIX 23 +#define IMX8MM_PGC_VPUMIX 24 +#define IMX8MM_PGC_GPU3D 25 +#define IMX8MM_PGC_DISPMIX 26 +#define IMX8MM_PGC_VPUG1 27 +#define IMX8MM_PGC_VPUG2 28 +#define IMX8MM_PGC_VPUH1 29 + +#define IMX8MN_PGC_MIPI 16 +#define IMX8MN_PGC_OTG1 18 +#define IMX8MN_PGC_DDR1 21 +#define IMX8MN_PGC_GPUMIX 23 +#define IMX8MN_PGC_DISPMIX 26 + #define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40) #define GPC_PGC_SR(n) (GPC_PGC_CTRL(n) + 0xc) #define GPC_PGC_CTRL_PCR BIT(0) -#define GPC_CLK_MAX 6 - struct imx_pgc_domain { struct generic_pm_domain genpd; struct regmap *regmap; struct regulator *regulator; - struct clk *clk[GPC_CLK_MAX]; + struct reset_control *reset; + struct clk_bulk_data *clks; int num_clks; unsigned int pgc; @@ -114,7 +197,8 @@ struct imx_pgc_domain { const struct { u32 pxx; u32 map; - u32 hsk; + u32 hskreq; + u32 hskack; } bits; const int voltage; @@ -127,96 +211,172 @@ struct imx_pgc_domain_data { const struct regmap_access_table *reg_access_table; }; -static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd, - bool on) +static inline struct imx_pgc_domain * +to_imx_pgc_domain(struct generic_pm_domain *genpd) { - struct imx_pgc_domain *domain = container_of(genpd, - struct imx_pgc_domain, - genpd); - unsigned int offset = on ? - GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ; - const bool enable_power_control = !on; - const bool has_regulator = !IS_ERR(domain->regulator); - int i, ret = 0; - u32 pxx_req; - - regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, - domain->bits.map, domain->bits.map); - - if (has_regulator && on) { + return container_of(genpd, struct imx_pgc_domain, genpd); +} + +static int imx_pgc_power_up(struct generic_pm_domain *genpd) +{ + struct imx_pgc_domain *domain = to_imx_pgc_domain(genpd); + u32 reg_val; + int ret; + + ret = pm_runtime_get_sync(domain->dev); + if (ret < 0) { + pm_runtime_put_noidle(domain->dev); + return ret; + } + + if (!IS_ERR(domain->regulator)) { ret = regulator_enable(domain->regulator); if (ret) { dev_err(domain->dev, "failed to enable regulator\n"); - goto unmap; + goto out_put_pm; } } /* Enable reset clocks for all devices in the domain */ - for (i = 0; i < domain->num_clks; i++) - clk_prepare_enable(domain->clk[i]); + ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks); + if (ret) { + dev_err(domain->dev, "failed to enable reset clocks\n"); + goto out_regulator_disable; + } - if (enable_power_control) - regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), - GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR); + if (domain->bits.pxx) { + /* request the domain to power up */ + regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PUP_REQ, + domain->bits.pxx, domain->bits.pxx); + /* + * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait + * for PUP_REQ/PDN_REQ bit to be cleared + */ + ret = regmap_read_poll_timeout(domain->regmap, + GPC_PU_PGC_SW_PUP_REQ, reg_val, + !(reg_val & domain->bits.pxx), + 0, USEC_PER_MSEC); + if (ret) { + dev_err(domain->dev, "failed to command PGC\n"); + goto out_clk_disable; + } + + /* disable power control */ + regmap_clear_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), + GPC_PGC_CTRL_PCR); + } - if (domain->bits.hsk) + reset_control_assert(domain->reset); + + /* delay for reset to propagate */ + udelay(5); + + reset_control_deassert(domain->reset); + + /* request the ADB400 to power up */ + if (domain->bits.hskreq) { regmap_update_bits(domain->regmap, GPC_PU_PWRHSK, - domain->bits.hsk, on ? domain->bits.hsk : 0); - - regmap_update_bits(domain->regmap, offset, - domain->bits.pxx, domain->bits.pxx); - - /* - * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait - * for PUP_REQ/PDN_REQ bit to be cleared - */ - ret = regmap_read_poll_timeout(domain->regmap, offset, pxx_req, - !(pxx_req & domain->bits.pxx), - 0, USEC_PER_MSEC); - if (ret) { - dev_err(domain->dev, "failed to command PGC\n"); + domain->bits.hskreq, domain->bits.hskreq); + /* - * If we were in a process of enabling a - * domain and failed we might as well disable - * the regulator we just enabled. And if it - * was the opposite situation and we failed to - * power down -- keep the regulator on + * ret = regmap_read_poll_timeout(domain->regmap, GPC_PU_PWRHSK, reg_val, + * (reg_val & domain->bits.hskack), 0, + * USEC_PER_MSEC); + * Technically we need the commented code to wait handshake. But that needs + * the BLK-CTL module BUS clk-en bit being set. + * + * There is a separate BLK-CTL module and we will have such a driver for it, + * that driver will set the BUS clk-en bit and handshake will be triggered + * automatically there. Just add a delay and suppose the handshake finish + * after that. */ - on = !on; } - if (enable_power_control) - regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), - GPC_PGC_CTRL_PCR, 0); - /* Disable reset clocks for all devices in the domain */ - for (i = 0; i < domain->num_clks; i++) - clk_disable_unprepare(domain->clk[i]); - - if (has_regulator && !on) { - int err; - - err = regulator_disable(domain->regulator); - if (err) - dev_err(domain->dev, - "failed to disable regulator: %d\n", err); - /* Preserve earlier error code */ - ret = ret ?: err; - } -unmap: - regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, - domain->bits.map, 0); + clk_bulk_disable_unprepare(domain->num_clks, domain->clks); + + return 0; + +out_clk_disable: + clk_bulk_disable_unprepare(domain->num_clks, domain->clks); +out_regulator_disable: + if (!IS_ERR(domain->regulator)) + regulator_disable(domain->regulator); +out_put_pm: + pm_runtime_put(domain->dev); + return ret; } -static int imx_gpc_pu_pgc_sw_pup_req(struct generic_pm_domain *genpd) +static int imx_pgc_power_down(struct generic_pm_domain *genpd) { - return imx_gpc_pu_pgc_sw_pxx_req(genpd, true); -} + struct imx_pgc_domain *domain = to_imx_pgc_domain(genpd); + u32 reg_val; + int ret; -static int imx_gpc_pu_pgc_sw_pdn_req(struct generic_pm_domain *genpd) -{ - return imx_gpc_pu_pgc_sw_pxx_req(genpd, false); + /* Enable reset clocks for all devices in the domain */ + ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks); + if (ret) { + dev_err(domain->dev, "failed to enable reset clocks\n"); + return ret; + } + + /* request the ADB400 to power down */ + if (domain->bits.hskreq) { + regmap_clear_bits(domain->regmap, GPC_PU_PWRHSK, + domain->bits.hskreq); + + ret = regmap_read_poll_timeout(domain->regmap, GPC_PU_PWRHSK, + reg_val, + !(reg_val & domain->bits.hskack), + 0, USEC_PER_MSEC); + if (ret) { + dev_err(domain->dev, "failed to power down ADB400\n"); + goto out_clk_disable; + } + } + + if (domain->bits.pxx) { + /* enable power control */ + regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), + GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR); + + /* request the domain to power down */ + regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PDN_REQ, + domain->bits.pxx, domain->bits.pxx); + /* + * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait + * for PUP_REQ/PDN_REQ bit to be cleared + */ + ret = regmap_read_poll_timeout(domain->regmap, + GPC_PU_PGC_SW_PDN_REQ, reg_val, + !(reg_val & domain->bits.pxx), + 0, USEC_PER_MSEC); + if (ret) { + dev_err(domain->dev, "failed to command PGC\n"); + goto out_clk_disable; + } + } + + /* Disable reset clocks for all devices in the domain */ + clk_bulk_disable_unprepare(domain->num_clks, domain->clks); + + if (!IS_ERR(domain->regulator)) { + ret = regulator_disable(domain->regulator); + if (ret) { + dev_err(domain->dev, "failed to disable regulator\n"); + return ret; + } + } + + pm_runtime_put(domain->dev); + + return 0; + +out_clk_disable: + clk_bulk_disable_unprepare(domain->num_clks, domain->clks); + + return ret; } static const struct imx_pgc_domain imx7_pgc_domains[] = { @@ -342,7 +502,8 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = { .bits = { .pxx = IMX8M_GPU_SW_Pxx_REQ, .map = IMX8M_GPU_A53_DOMAIN, - .hsk = IMX8M_GPU_HSK_PWRDNREQN, + .hskreq = IMX8M_GPU_HSK_PWRDNREQN, + .hskack = IMX8M_GPU_HSK_PWRDNACKN, }, .pgc = IMX8M_PGC_GPU, }, @@ -354,7 +515,8 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = { .bits = { .pxx = IMX8M_VPU_SW_Pxx_REQ, .map = IMX8M_VPU_A53_DOMAIN, - .hsk = IMX8M_VPU_HSK_PWRDNREQN, + .hskreq = IMX8M_VPU_HSK_PWRDNREQN, + .hskack = IMX8M_VPU_HSK_PWRDNACKN, }, .pgc = IMX8M_PGC_VPU, }, @@ -366,7 +528,8 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = { .bits = { .pxx = IMX8M_DISP_SW_Pxx_REQ, .map = IMX8M_DISP_A53_DOMAIN, - .hsk = IMX8M_DISP_HSK_PWRDNREQN, + .hskreq = IMX8M_DISP_HSK_PWRDNREQN, + .hskack = IMX8M_DISP_HSK_PWRDNACKN, }, .pgc = IMX8M_PGC_DISP, }, @@ -443,40 +606,254 @@ static const struct imx_pgc_domain_data imx8m_pgc_domain_data = { .reg_access_table = &imx8m_access_table, }; -static int imx_pgc_get_clocks(struct imx_pgc_domain *domain) -{ - int i, ret; - - for (i = 0; ; i++) { - struct clk *clk = of_clk_get(domain->dev->of_node, i); - if (IS_ERR(clk)) - break; - if (i >= GPC_CLK_MAX) { - dev_err(domain->dev, "more than %d clocks\n", - GPC_CLK_MAX); - ret = -EINVAL; - goto clk_err; - } - domain->clk[i] = clk; - } - domain->num_clks = i; +static const struct imx_pgc_domain imx8mm_pgc_domains[] = { + [IMX8MM_POWER_DOMAIN_HSIOMIX] = { + .genpd = { + .name = "hsiomix", + }, + .bits = { + .pxx = 0, /* no power sequence control */ + .map = 0, /* no power sequence control */ + .hskreq = IMX8MM_HSIO_HSK_PWRDNREQN, + .hskack = IMX8MM_HSIO_HSK_PWRDNACKN, + }, + }, - return 0; + [IMX8MM_POWER_DOMAIN_PCIE] = { + .genpd = { + .name = "pcie", + }, + .bits = { + .pxx = IMX8MM_PCIE_SW_Pxx_REQ, + .map = IMX8MM_PCIE_A53_DOMAIN, + }, + .pgc = IMX8MM_PGC_PCIE, + }, -clk_err: - while (i--) - clk_put(domain->clk[i]); + [IMX8MM_POWER_DOMAIN_OTG1] = { + .genpd = { + .name = "usb-otg1", + }, + .bits = { + .pxx = IMX8MM_OTG1_SW_Pxx_REQ, + .map = IMX8MM_OTG1_A53_DOMAIN, + }, + .pgc = IMX8MM_PGC_OTG1, + }, - return ret; -} + [IMX8MM_POWER_DOMAIN_OTG2] = { + .genpd = { + .name = "usb-otg2", + }, + .bits = { + .pxx = IMX8MM_OTG2_SW_Pxx_REQ, + .map = IMX8MM_OTG2_A53_DOMAIN, + }, + .pgc = IMX8MM_PGC_OTG2, + }, -static void imx_pgc_put_clocks(struct imx_pgc_domain *domain) -{ - int i; + [IMX8MM_POWER_DOMAIN_GPUMIX] = { + .genpd = { + .name = "gpumix", + }, + .bits = { + .pxx = IMX8MM_GPUMIX_SW_Pxx_REQ, + .map = IMX8MM_GPUMIX_A53_DOMAIN, + .hskreq = IMX8MM_GPUMIX_HSK_PWRDNREQN, + .hskack = IMX8MM_GPUMIX_HSK_PWRDNACKN, + }, + .pgc = IMX8MM_PGC_GPUMIX, + }, - for (i = domain->num_clks - 1; i >= 0; i--) - clk_put(domain->clk[i]); -} + [IMX8MM_POWER_DOMAIN_GPU] = { + .genpd = { + .name = "gpu", + }, + .bits = { + .pxx = IMX8MM_GPU_SW_Pxx_REQ, + .map = IMX8MM_GPU_A53_DOMAIN, + .hskreq = IMX8MM_GPU_HSK_PWRDNREQN, + .hskack = IMX8MM_GPU_HSK_PWRDNACKN, + }, + .pgc = IMX8MM_PGC_GPU2D, + }, + + [IMX8MM_POWER_DOMAIN_VPUMIX] = { + .genpd = { + .name = "vpumix", + }, + .bits = { + .pxx = IMX8MM_VPUMIX_SW_Pxx_REQ, + .map = IMX8MM_VPUMIX_A53_DOMAIN, + .hskreq = IMX8MM_VPUMIX_HSK_PWRDNREQN, + .hskack = IMX8MM_VPUMIX_HSK_PWRDNACKN, + }, + .pgc = IMX8MM_PGC_VPUMIX, + }, + + [IMX8MM_POWER_DOMAIN_VPUG1] = { + .genpd = { + .name = "vpu-g1", + }, + .bits = { + .pxx = IMX8MM_VPUG1_SW_Pxx_REQ, + .map = IMX8MM_VPUG1_A53_DOMAIN, + }, + .pgc = IMX8MM_PGC_VPUG1, + }, + + [IMX8MM_POWER_DOMAIN_VPUG2] = { + .genpd = { + .name = "vpu-g2", + }, + .bits = { + .pxx = IMX8MM_VPUG2_SW_Pxx_REQ, + .map = IMX8MM_VPUG2_A53_DOMAIN, + }, + .pgc = IMX8MM_PGC_VPUG2, + }, + + [IMX8MM_POWER_DOMAIN_VPUH1] = { + .genpd = { + .name = "vpu-h1", + }, + .bits = { + .pxx = IMX8MM_VPUH1_SW_Pxx_REQ, + .map = IMX8MM_VPUH1_A53_DOMAIN, + }, + .pgc = IMX8MM_PGC_VPUH1, + }, + + [IMX8MM_POWER_DOMAIN_DISPMIX] = { + .genpd = { + .name = "dispmix", + }, + .bits = { + .pxx = IMX8MM_DISPMIX_SW_Pxx_REQ, + .map = IMX8MM_DISPMIX_A53_DOMAIN, + .hskreq = IMX8MM_DISPMIX_HSK_PWRDNREQN, + .hskack = IMX8MM_DISPMIX_HSK_PWRDNACKN, + }, + .pgc = IMX8MM_PGC_DISPMIX, + }, + + [IMX8MM_POWER_DOMAIN_MIPI] = { + .genpd = { + .name = "mipi", + }, + .bits = { + .pxx = IMX8MM_MIPI_SW_Pxx_REQ, + .map = IMX8MM_MIPI_A53_DOMAIN, + }, + .pgc = IMX8MM_PGC_MIPI, + }, +}; + +static const struct regmap_range imx8mm_yes_ranges[] = { + regmap_reg_range(GPC_LPCR_A_CORE_BSC, + GPC_PU_PWRHSK), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_MIPI), + GPC_PGC_SR(IMX8MM_PGC_MIPI)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_PCIE), + GPC_PGC_SR(IMX8MM_PGC_PCIE)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_OTG1), + GPC_PGC_SR(IMX8MM_PGC_OTG1)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_OTG2), + GPC_PGC_SR(IMX8MM_PGC_OTG2)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_DDR1), + GPC_PGC_SR(IMX8MM_PGC_DDR1)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_GPU2D), + GPC_PGC_SR(IMX8MM_PGC_GPU2D)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_GPUMIX), + GPC_PGC_SR(IMX8MM_PGC_GPUMIX)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUMIX), + GPC_PGC_SR(IMX8MM_PGC_VPUMIX)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_GPU3D), + GPC_PGC_SR(IMX8MM_PGC_GPU3D)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_DISPMIX), + GPC_PGC_SR(IMX8MM_PGC_DISPMIX)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUG1), + GPC_PGC_SR(IMX8MM_PGC_VPUG1)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUG2), + GPC_PGC_SR(IMX8MM_PGC_VPUG2)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUH1), + GPC_PGC_SR(IMX8MM_PGC_VPUH1)), +}; + +static const struct regmap_access_table imx8mm_access_table = { + .yes_ranges = imx8mm_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(imx8mm_yes_ranges), +}; + +static const struct imx_pgc_domain_data imx8mm_pgc_domain_data = { + .domains = imx8mm_pgc_domains, + .domains_num = ARRAY_SIZE(imx8mm_pgc_domains), + .reg_access_table = &imx8mm_access_table, +}; + +static const struct imx_pgc_domain imx8mn_pgc_domains[] = { + [IMX8MN_POWER_DOMAIN_HSIOMIX] = { + .genpd = { + .name = "hsiomix", + }, + .bits = { + .pxx = 0, /* no power sequence control */ + .map = 0, /* no power sequence control */ + .hskreq = IMX8MN_HSIO_HSK_PWRDNREQN, + .hskack = IMX8MN_HSIO_HSK_PWRDNACKN, + }, + }, + + [IMX8MN_POWER_DOMAIN_OTG1] = { + .genpd = { + .name = "usb-otg1", + }, + .bits = { + .pxx = IMX8MN_OTG1_SW_Pxx_REQ, + .map = IMX8MN_OTG1_A53_DOMAIN, + }, + .pgc = IMX8MN_PGC_OTG1, + }, + + [IMX8MN_POWER_DOMAIN_GPUMIX] = { + .genpd = { + .name = "gpumix", + }, + .bits = { + .pxx = IMX8MN_GPUMIX_SW_Pxx_REQ, + .map = IMX8MN_GPUMIX_A53_DOMAIN, + .hskreq = IMX8MN_GPUMIX_HSK_PWRDNREQN, + .hskack = IMX8MN_GPUMIX_HSK_PWRDNACKN, + }, + .pgc = IMX8MN_PGC_GPUMIX, + }, +}; + +static const struct regmap_range imx8mn_yes_ranges[] = { + regmap_reg_range(GPC_LPCR_A_CORE_BSC, + GPC_PU_PWRHSK), + regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_MIPI), + GPC_PGC_SR(IMX8MN_PGC_MIPI)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_OTG1), + GPC_PGC_SR(IMX8MN_PGC_OTG1)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_DDR1), + GPC_PGC_SR(IMX8MN_PGC_DDR1)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_GPUMIX), + GPC_PGC_SR(IMX8MN_PGC_GPUMIX)), + regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_DISPMIX), + GPC_PGC_SR(IMX8MN_PGC_DISPMIX)), +}; + +static const struct regmap_access_table imx8mn_access_table = { + .yes_ranges = imx8mn_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(imx8mn_yes_ranges), +}; + +static const struct imx_pgc_domain_data imx8mn_pgc_domain_data = { + .domains = imx8mn_pgc_domains, + .domains_num = ARRAY_SIZE(imx8mn_pgc_domains), + .reg_access_table = &imx8mn_access_table, +}; static int imx_pgc_domain_probe(struct platform_device *pdev) { @@ -495,25 +872,45 @@ static int imx_pgc_domain_probe(struct platform_device *pdev) domain->voltage, domain->voltage); } - ret = imx_pgc_get_clocks(domain); - if (ret) - return dev_err_probe(domain->dev, ret, "Failed to get domain's clocks\n"); + domain->num_clks = devm_clk_bulk_get_all(domain->dev, &domain->clks); + if (domain->num_clks < 0) + return dev_err_probe(domain->dev, domain->num_clks, + "Failed to get domain's clocks\n"); + + domain->reset = devm_reset_control_array_get_optional_exclusive(domain->dev); + if (IS_ERR(domain->reset)) + return dev_err_probe(domain->dev, PTR_ERR(domain->reset), + "Failed to get domain's resets\n"); + + pm_runtime_enable(domain->dev); + + if (domain->bits.map) + regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, + domain->bits.map, domain->bits.map); ret = pm_genpd_init(&domain->genpd, NULL, true); if (ret) { dev_err(domain->dev, "Failed to init power domain\n"); - imx_pgc_put_clocks(domain); - return ret; + goto out_domain_unmap; } ret = of_genpd_add_provider_simple(domain->dev->of_node, &domain->genpd); if (ret) { dev_err(domain->dev, "Failed to add genpd provider\n"); - pm_genpd_remove(&domain->genpd); - imx_pgc_put_clocks(domain); + goto out_genpd_remove; } + return 0; + +out_genpd_remove: + pm_genpd_remove(&domain->genpd); +out_domain_unmap: + if (domain->bits.map) + regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, + domain->bits.map, 0); + pm_runtime_disable(domain->dev); + return ret; } @@ -523,7 +920,12 @@ static int imx_pgc_domain_remove(struct platform_device *pdev) of_genpd_del_provider(domain->dev->of_node); pm_genpd_remove(&domain->genpd); - imx_pgc_put_clocks(domain); + + if (domain->bits.map) + regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, + domain->bits.map, 0); + + pm_runtime_disable(domain->dev); return 0; } @@ -617,8 +1019,8 @@ static int imx_gpcv2_probe(struct platform_device *pdev) domain = pd_pdev->dev.platform_data; domain->regmap = regmap; - domain->genpd.power_on = imx_gpc_pu_pgc_sw_pup_req; - domain->genpd.power_off = imx_gpc_pu_pgc_sw_pdn_req; + domain->genpd.power_on = imx_pgc_power_up; + domain->genpd.power_off = imx_pgc_power_down; pd_pdev->dev.parent = dev; pd_pdev->dev.of_node = np; @@ -636,6 +1038,8 @@ static int imx_gpcv2_probe(struct platform_device *pdev) static const struct of_device_id imx_gpcv2_dt_ids[] = { { .compatible = "fsl,imx7d-gpc", .data = &imx7_pgc_domain_data, }, + { .compatible = "fsl,imx8mm-gpc", .data = &imx8mm_pgc_domain_data, }, + { .compatible = "fsl,imx8mn-gpc", .data = &imx8mn_pgc_domain_data, }, { .compatible = "fsl,imx8mq-gpc", .data = &imx8m_pgc_domain_data, }, { } }; diff --git a/drivers/soc/imx/soc-imx.c b/drivers/soc/imx/soc-imx.c index 0738c0f36792..ac6d856ba228 100644 --- a/drivers/soc/imx/soc-imx.c +++ b/drivers/soc/imx/soc-imx.c @@ -70,6 +70,9 @@ static int __init imx_soc_device_init(void) case MXC_CPU_MX35: soc_id = "i.MX35"; break; + case MXC_CPU_MX50: + soc_id = "i.MX50"; + break; case MXC_CPU_MX51: ocotp_compat = "fsl,imx51-iim"; soc_id = "i.MX51"; diff --git a/drivers/soc/imx/soc-imx8m.c b/drivers/soc/imx/soc-imx8m.c index 071e14496e4b..cc57a384d74d 100644 --- a/drivers/soc/imx/soc-imx8m.c +++ b/drivers/soc/imx/soc-imx8m.c @@ -5,8 +5,6 @@ #include <linux/init.h> #include <linux/io.h> -#include <linux/module.h> -#include <linux/nvmem-consumer.h> #include <linux/of_address.h> #include <linux/slab.h> #include <linux/sys_soc.h> @@ -31,7 +29,7 @@ struct imx8_soc_data { char *name; - u32 (*soc_revision)(struct device *dev); + u32 (*soc_revision)(void); }; static u64 soc_uid; @@ -52,7 +50,7 @@ static u32 imx8mq_soc_revision_from_atf(void) static inline u32 imx8mq_soc_revision_from_atf(void) { return 0; }; #endif -static u32 __init imx8mq_soc_revision(struct device *dev) +static u32 __init imx8mq_soc_revision(void) { struct device_node *np; void __iomem *ocotp_base; @@ -77,20 +75,9 @@ static u32 __init imx8mq_soc_revision(struct device *dev) rev = REV_B1; } - if (dev) { - int ret; - - ret = nvmem_cell_read_u64(dev, "soc_unique_id", &soc_uid); - if (ret) { - iounmap(ocotp_base); - of_node_put(np); - return ret; - } - } else { - soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH); - soc_uid <<= 32; - soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW); - } + soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH); + soc_uid <<= 32; + soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW); iounmap(ocotp_base); of_node_put(np); @@ -120,7 +107,7 @@ static void __init imx8mm_soc_uid(void) of_node_put(np); } -static u32 __init imx8mm_soc_revision(struct device *dev) +static u32 __init imx8mm_soc_revision(void) { struct device_node *np; void __iomem *anatop_base; @@ -138,15 +125,7 @@ static u32 __init imx8mm_soc_revision(struct device *dev) iounmap(anatop_base); of_node_put(np); - if (dev) { - int ret; - - ret = nvmem_cell_read_u64(dev, "soc_unique_id", &soc_uid); - if (ret) - return ret; - } else { - imx8mm_soc_uid(); - } + imx8mm_soc_uid(); return rev; } @@ -171,7 +150,7 @@ static const struct imx8_soc_data imx8mp_soc_data = { .soc_revision = imx8mm_soc_revision, }; -static __maybe_unused const struct of_device_id imx8_machine_match[] = { +static __maybe_unused const struct of_device_id imx8_soc_match[] = { { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, }, { .compatible = "fsl,imx8mm", .data = &imx8mm_soc_data, }, { .compatible = "fsl,imx8mn", .data = &imx8mn_soc_data, }, @@ -179,20 +158,12 @@ static __maybe_unused const struct of_device_id imx8_machine_match[] = { { } }; -static __maybe_unused const struct of_device_id imx8_soc_match[] = { - { .compatible = "fsl,imx8mq-soc", .data = &imx8mq_soc_data, }, - { .compatible = "fsl,imx8mm-soc", .data = &imx8mm_soc_data, }, - { .compatible = "fsl,imx8mn-soc", .data = &imx8mn_soc_data, }, - { .compatible = "fsl,imx8mp-soc", .data = &imx8mp_soc_data, }, - { } -}; - #define imx8_revision(soc_rev) \ soc_rev ? \ kasprintf(GFP_KERNEL, "%d.%d", (soc_rev >> 4) & 0xf, soc_rev & 0xf) : \ "unknown" -static int imx8_soc_info(struct platform_device *pdev) +static int __init imx8_soc_init(void) { struct soc_device_attribute *soc_dev_attr; struct soc_device *soc_dev; @@ -211,10 +182,7 @@ static int imx8_soc_info(struct platform_device *pdev) if (ret) goto free_soc; - if (pdev) - id = of_match_node(imx8_soc_match, pdev->dev.of_node); - else - id = of_match_node(imx8_machine_match, of_root); + id = of_match_node(imx8_soc_match, of_root); if (!id) { ret = -ENODEV; goto free_soc; @@ -223,16 +191,8 @@ static int imx8_soc_info(struct platform_device *pdev) data = id->data; if (data) { soc_dev_attr->soc_id = data->name; - if (data->soc_revision) { - if (pdev) { - soc_rev = data->soc_revision(&pdev->dev); - ret = soc_rev; - if (ret < 0) - goto free_soc; - } else { - soc_rev = data->soc_revision(NULL); - } - } + if (data->soc_revision) + soc_rev = data->soc_revision(); } soc_dev_attr->revision = imx8_revision(soc_rev); @@ -270,24 +230,4 @@ free_soc: kfree(soc_dev_attr); return ret; } - -/* Retain device_initcall is for backward compatibility with DTS. */ -static int __init imx8_soc_init(void) -{ - if (of_find_matching_node_and_match(NULL, imx8_soc_match, NULL)) - return 0; - - return imx8_soc_info(NULL); -} device_initcall(imx8_soc_init); - -static struct platform_driver imx8_soc_info_driver = { - .probe = imx8_soc_info, - .driver = { - .name = "imx8_soc_info", - .of_match_table = imx8_soc_match, - }, -}; - -module_platform_driver(imx8_soc_info_driver); -MODULE_LICENSE("GPL v2"); |