diff options
Diffstat (limited to 'drivers/power/domain')
-rw-r--r-- | drivers/power/domain/Kconfig | 8 | ||||
-rw-r--r-- | drivers/power/domain/Makefile | 1 | ||||
-rw-r--r-- | drivers/power/domain/apple-pmgr.c | 30 | ||||
-rw-r--r-- | drivers/power/domain/bcm6328-power-domain.c | 6 | ||||
-rw-r--r-- | drivers/power/domain/imx8-power-domain-legacy.c | 16 | ||||
-rw-r--r-- | drivers/power/domain/imx8-power-domain.c | 24 | ||||
-rw-r--r-- | drivers/power/domain/imx8m-power-domain.c | 471 | ||||
-rw-r--r-- | drivers/power/domain/imx8mp-hsiomix.c | 159 | ||||
-rw-r--r-- | drivers/power/domain/meson-ee-pwrc.c | 12 | ||||
-rw-r--r-- | drivers/power/domain/meson-gx-pwrc-vpu.c | 12 | ||||
-rw-r--r-- | drivers/power/domain/mtk-power-domain.c | 6 | ||||
-rw-r--r-- | drivers/power/domain/power-domain-uclass.c | 22 | ||||
-rw-r--r-- | drivers/power/domain/tegra186-power-domain.c | 26 | ||||
-rw-r--r-- | drivers/power/domain/ti-power-domain.c | 13 | ||||
-rw-r--r-- | drivers/power/domain/ti-sci-power-domain.c | 14 |
15 files changed, 628 insertions, 192 deletions
diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig index 93d2599d83..7e1b8c072f 100644 --- a/drivers/power/domain/Kconfig +++ b/drivers/power/domain/Kconfig @@ -35,10 +35,18 @@ config IMX8_POWER_DOMAIN config IMX8M_POWER_DOMAIN bool "Enable i.MX8M power domain driver" depends on POWER_DOMAIN && ARCH_IMX8M + select CLK help Enable support for manipulating NXP i.MX8M on-SoC power domains via requests to the ATF. +config IMX8MP_HSIOMIX_BLKCTRL + bool "Enable i.MX8MP HSIOMIX domain driver" + depends on POWER_DOMAIN && IMX8MP + select CLK + help + Enable support for manipulating NXP i.MX8MP on-SoC HSIOMIX block controller. + config MTK_POWER_DOMAIN bool "Enable the MediaTek power domain driver" depends on POWER_DOMAIN && ARCH_MEDIATEK diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile index 7c8af67dbd..e624477621 100644 --- a/drivers/power/domain/Makefile +++ b/drivers/power/domain/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_APPLE_PMGR_POWER_DOMAIN) += apple-pmgr.o obj-$(CONFIG_BCM6328_POWER_DOMAIN) += bcm6328-power-domain.o obj-$(CONFIG_IMX8_POWER_DOMAIN) += imx8-power-domain-legacy.o imx8-power-domain.o obj-$(CONFIG_IMX8M_POWER_DOMAIN) += imx8m-power-domain.o +obj-$(CONFIG_IMX8MP_HSIOMIX_BLKCTRL) += imx8mp-hsiomix.o obj-$(CONFIG_MTK_POWER_DOMAIN) += mtk-power-domain.o obj-$(CONFIG_MESON_GX_VPU_POWER_DOMAIN) += meson-gx-pwrc-vpu.o obj-$(CONFIG_MESON_EE_POWER_DOMAIN) += meson-ee-pwrc.o diff --git a/drivers/power/domain/apple-pmgr.c b/drivers/power/domain/apple-pmgr.c index 4d06e76ff5..402c5b1fd1 100644 --- a/drivers/power/domain/apple-pmgr.c +++ b/drivers/power/domain/apple-pmgr.c @@ -42,16 +42,6 @@ static int apple_reset_of_xlate(struct reset_ctl *reset_ctl, return 0; } -static int apple_reset_request(struct reset_ctl *reset_ctl) -{ - return 0; -} - -static int apple_reset_free(struct reset_ctl *reset_ctl) -{ - return 0; -} - static int apple_reset_assert(struct reset_ctl *reset_ctl) { struct apple_pmgr_priv *priv = dev_get_priv(reset_ctl->dev->parent); @@ -80,8 +70,6 @@ static int apple_reset_deassert(struct reset_ctl *reset_ctl) struct reset_ops apple_reset_ops = { .of_xlate = apple_reset_of_xlate, - .request = apple_reset_request, - .rfree = apple_reset_free, .rst_assert = apple_reset_assert, .rst_deassert = apple_reset_deassert, }; @@ -92,16 +80,6 @@ static struct driver apple_reset_driver = { .ops = &apple_reset_ops, }; -static int apple_pmgr_request(struct power_domain *power_domain) -{ - return 0; -} - -static int apple_pmgr_rfree(struct power_domain *power_domain) -{ - return 0; -} - static int apple_pmgr_ps_set(struct power_domain *power_domain, u32 pstate) { struct apple_pmgr_priv *priv = dev_get_priv(power_domain->dev); @@ -121,11 +99,6 @@ static int apple_pmgr_on(struct power_domain *power_domain) return apple_pmgr_ps_set(power_domain, APPLE_PMGR_PS_ACTIVE); } -static int apple_pmgr_off(struct power_domain *power_domain) -{ - return 0; -} - static int apple_pmgr_of_xlate(struct power_domain *power_domain, struct ofnode_phandle_args *args) { @@ -167,10 +140,7 @@ static int apple_pmgr_probe(struct udevice *dev) } struct power_domain_ops apple_pmgr_ops = { - .request = apple_pmgr_request, - .rfree = apple_pmgr_rfree, .on = apple_pmgr_on, - .off = apple_pmgr_off, .of_xlate = apple_pmgr_of_xlate, }; diff --git a/drivers/power/domain/bcm6328-power-domain.c b/drivers/power/domain/bcm6328-power-domain.c index 6e720e0798..80144dd977 100644 --- a/drivers/power/domain/bcm6328-power-domain.c +++ b/drivers/power/domain/bcm6328-power-domain.c @@ -24,11 +24,6 @@ static int bcm6328_power_domain_request(struct power_domain *power_domain) return 0; } -static int bcm6328_power_domain_free(struct power_domain *power_domain) -{ - return 0; -} - static int bcm6328_power_domain_on(struct power_domain *power_domain) { struct bcm6328_power_domain *priv = dev_get_priv(power_domain->dev); @@ -64,7 +59,6 @@ static const struct udevice_id bcm6328_power_domain_ids[] = { }; struct power_domain_ops bcm6328_power_domain_ops = { - .rfree = bcm6328_power_domain_free, .off = bcm6328_power_domain_off, .on = bcm6328_power_domain_on, .request = bcm6328_power_domain_request, diff --git a/drivers/power/domain/imx8-power-domain-legacy.c b/drivers/power/domain/imx8-power-domain-legacy.c index e2fae2dbc8..bf45891bcc 100644 --- a/drivers/power/domain/imx8-power-domain-legacy.c +++ b/drivers/power/domain/imx8-power-domain-legacy.c @@ -84,20 +84,6 @@ int imx8_power_domain_lookup_name(const char *name, return 0; } -static int imx8_power_domain_request(struct power_domain *power_domain) -{ - debug("%s(power_domain=%p)\n", __func__, power_domain); - - return 0; -} - -static int imx8_power_domain_free(struct power_domain *power_domain) -{ - debug("%s(power_domain=%p)\n", __func__, power_domain); - - return 0; -} - static int imx8_power_domain_on(struct power_domain *power_domain) { struct udevice *dev = power_domain->dev; @@ -364,8 +350,6 @@ static const struct udevice_id imx8_power_domain_ids[] = { }; struct power_domain_ops imx8_power_domain_ops = { - .request = imx8_power_domain_request, - .rfree = imx8_power_domain_free, .on = imx8_power_domain_on, .off = imx8_power_domain_off, .of_xlate = imx8_power_domain_of_xlate, diff --git a/drivers/power/domain/imx8-power-domain.c b/drivers/power/domain/imx8-power-domain.c index 6461ab23d6..17b5d57b19 100644 --- a/drivers/power/domain/imx8-power-domain.c +++ b/drivers/power/domain/imx8-power-domain.c @@ -12,20 +12,6 @@ #include <asm/arch/power-domain.h> #include <asm/arch/sci/sci.h> -static int imx8_power_domain_request(struct power_domain *power_domain) -{ - debug("%s(power_domain=%p)\n", __func__, power_domain); - - return 0; -} - -static int imx8_power_domain_free(struct power_domain *power_domain) -{ - debug("%s(power_domain=%p)\n", __func__, power_domain); - - return 0; -} - static int imx8_power_domain_on(struct power_domain *power_domain) { u32 resource_id = power_domain->id; @@ -60,13 +46,6 @@ static int imx8_power_domain_off(struct power_domain *power_domain) return 0; } -static int imx8_power_domain_probe(struct udevice *dev) -{ - debug("%s(dev=%s)\n", __func__, dev->name); - - return 0; -} - static const struct udevice_id imx8_power_domain_ids[] = { { .compatible = "fsl,imx8qxp-scu-pd" }, { .compatible = "fsl,scu-pd" }, @@ -74,8 +53,6 @@ static const struct udevice_id imx8_power_domain_ids[] = { }; struct power_domain_ops imx8_power_domain_ops_v2 = { - .request = imx8_power_domain_request, - .rfree = imx8_power_domain_free, .on = imx8_power_domain_on, .off = imx8_power_domain_off, }; @@ -84,6 +61,5 @@ U_BOOT_DRIVER(imx8_power_domain_v2) = { .name = "imx8_power_domain_v2", .id = UCLASS_POWER_DOMAIN, .of_match = imx8_power_domain_ids, - .probe = imx8_power_domain_probe, .ops = &imx8_power_domain_ops_v2, }; diff --git a/drivers/power/domain/imx8m-power-domain.c b/drivers/power/domain/imx8m-power-domain.c index 5d34bc1290..145f6ec0cd 100644 --- a/drivers/power/domain/imx8m-power-domain.c +++ b/drivers/power/domain/imx8m-power-domain.c @@ -4,65 +4,446 @@ */ #include <common.h> +#include <clk.h> #include <dm.h> #include <malloc.h> #include <power-domain-uclass.h> #include <asm/global_data.h> #include <asm/io.h> -#include <asm/arch/power-domain.h> #include <asm/mach-imx/sys_proto.h> #include <dm/device-internal.h> #include <dm/device.h> +#include <dm/device_compat.h> #include <imx_sip.h> -#include <linux/arm-smccc.h> +#include <linux/bitmap.h> +#include <wait_bit.h> + +#include <dt-bindings/power/imx8mm-power.h> +#include <dt-bindings/power/imx8mn-power.h> +#include <dt-bindings/power/imx8mp-power.h> +#include <dt-bindings/power/imx8mq-power.h> DECLARE_GLOBAL_DATA_PTR; -static int imx8m_power_domain_request(struct power_domain *power_domain) -{ - return 0; -} +#define GPC_PGC_CPU_MAPPING 0x0ec +#define IMX8MP_GPC_PGC_CPU_MAPPING 0x1cc -static int imx8m_power_domain_free(struct power_domain *power_domain) -{ - return 0; -} +#define IMX8M_PCIE2_A53_DOMAIN BIT(15) +#define IMX8M_OTG2_A53_DOMAIN BIT(5) +#define IMX8M_OTG1_A53_DOMAIN BIT(4) +#define IMX8M_PCIE1_A53_DOMAIN BIT(3) + +#define IMX8MM_OTG2_A53_DOMAIN BIT(5) +#define IMX8MM_OTG1_A53_DOMAIN BIT(4) +#define IMX8MM_PCIE_A53_DOMAIN BIT(3) + +#define IMX8MN_OTG1_A53_DOMAIN BIT(4) +#define IMX8MN_MIPI_A53_DOMAIN BIT(2) + +#define IMX8MP_HSIOMIX_A53_DOMAIN BIT(19) +#define IMX8MP_USB2_PHY_A53_DOMAIN BIT(5) +#define IMX8MP_USB1_PHY_A53_DOMAIN BIT(4) +#define IMX8MP_PCIE_PHY_A53_DOMAIN BIT(3) + +#define IMX8MP_GPC_PU_PGC_SW_PUP_REQ 0x0d8 +#define IMX8MP_GPC_PU_PGC_SW_PDN_REQ 0x0e4 + +#define GPC_PU_PGC_SW_PUP_REQ 0x0f8 +#define GPC_PU_PGC_SW_PDN_REQ 0x104 + +#define IMX8M_PCIE2_SW_Pxx_REQ BIT(13) +#define IMX8M_OTG2_SW_Pxx_REQ BIT(3) +#define IMX8M_OTG1_SW_Pxx_REQ BIT(2) +#define IMX8M_PCIE1_SW_Pxx_REQ BIT(1) + +#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 IMX8MN_OTG1_SW_Pxx_REQ BIT(2) +#define IMX8MN_MIPI_SW_Pxx_REQ BIT(0) + +#define IMX8MP_HSIOMIX_Pxx_REQ BIT(17) +#define IMX8MP_USB2_PHY_Pxx_REQ BIT(3) +#define IMX8MP_USB1_PHY_Pxx_REQ BIT(2) +#define IMX8MP_PCIE_PHY_SW_Pxx_REQ BIT(1) + +#define GPC_M4_PU_PDN_FLG 0x1bc + +#define IMX8MP_GPC_PU_PWRHSK 0x190 +#define GPC_PU_PWRHSK 0x1fc + +#define IMX8MM_HSIO_HSK_PWRDNACKN (BIT(23) | BIT(24)) +#define IMX8MM_HSIO_HSK_PWRDNREQN (BIT(5) | BIT(6)) + +#define IMX8MN_HSIO_HSK_PWRDNACKN BIT(23) +#define IMX8MN_HSIO_HSK_PWRDNREQN BIT(5) + +#define IMX8MP_HSIOMIX_PWRDNACKN BIT(28) +#define IMX8MP_HSIOMIX_PWRDNREQN BIT(12) + +/* + * The PGC offset values in Reference Manual + * (Rev. 1, 01/2018 and the older ones) GPC chapter's + * GPC_PGC memory map are incorrect, below offset + * values are from design RTL. + */ +#define IMX8M_PGC_PCIE1 17 +#define IMX8M_PGC_OTG1 18 +#define IMX8M_PGC_OTG2 19 +#define IMX8M_PGC_PCIE2 29 + +#define IMX8MM_PGC_PCIE 17 +#define IMX8MM_PGC_OTG1 18 +#define IMX8MM_PGC_OTG2 19 + +#define IMX8MN_PGC_OTG1 18 + +#define IMX8MP_PGC_PCIE 13 +#define IMX8MP_PGC_USB1 14 +#define IMX8MP_PGC_USB2 15 +#define IMX8MP_PGC_HSIOMIX 29 + +#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) + +struct imx_pgc_regs { + u16 map; + u16 pup; + u16 pdn; + u16 hsk; +}; + +struct imx_pgc_domain { + unsigned long pgc; + + const struct { + u32 pxx; + u32 map; + u32 hskreq; + u32 hskack; + } bits; + + const bool keep_clocks; +}; + +struct imx_pgc_domain_data { + const struct imx_pgc_domain *domains; + size_t domains_num; + const struct imx_pgc_regs *pgc_regs; +}; + +struct imx8m_power_domain_plat { + struct power_domain pd; + const struct imx_pgc_domain *domain; + const struct imx_pgc_regs *regs; + struct clk_bulk clk; + void __iomem *base; + int resource_id; + int has_pd; +}; + +#if defined(CONFIG_IMX8MM) || defined(CONFIG_IMX8MN) || defined(CONFIG_IMX8MQ) +static const struct imx_pgc_regs imx7_pgc_regs = { + .map = GPC_PGC_CPU_MAPPING, + .pup = GPC_PU_PGC_SW_PUP_REQ, + .pdn = GPC_PU_PGC_SW_PDN_REQ, + .hsk = GPC_PU_PWRHSK, +}; +#endif + +#ifdef CONFIG_IMX8MQ +static const struct imx_pgc_domain imx8m_pgc_domains[] = { + [IMX8M_POWER_DOMAIN_PCIE1] = { + .bits = { + .pxx = IMX8M_PCIE1_SW_Pxx_REQ, + .map = IMX8M_PCIE1_A53_DOMAIN, + }, + .pgc = BIT(IMX8M_PGC_PCIE1), + }, + + [IMX8M_POWER_DOMAIN_USB_OTG1] = { + .bits = { + .pxx = IMX8M_OTG1_SW_Pxx_REQ, + .map = IMX8M_OTG1_A53_DOMAIN, + }, + .pgc = BIT(IMX8M_PGC_OTG1), + }, + + [IMX8M_POWER_DOMAIN_USB_OTG2] = { + .bits = { + .pxx = IMX8M_OTG2_SW_Pxx_REQ, + .map = IMX8M_OTG2_A53_DOMAIN, + }, + .pgc = BIT(IMX8M_PGC_OTG2), + }, + + [IMX8M_POWER_DOMAIN_PCIE2] = { + .bits = { + .pxx = IMX8M_PCIE2_SW_Pxx_REQ, + .map = IMX8M_PCIE2_A53_DOMAIN, + }, + .pgc = BIT(IMX8M_PGC_PCIE2), + }, +}; + +static const struct imx_pgc_domain_data imx8m_pgc_domain_data = { + .domains = imx8m_pgc_domains, + .domains_num = ARRAY_SIZE(imx8m_pgc_domains), + .pgc_regs = &imx7_pgc_regs, +}; +#endif + +#ifdef CONFIG_IMX8MM +static const struct imx_pgc_domain imx8mm_pgc_domains[] = { + [IMX8MM_POWER_DOMAIN_HSIOMIX] = { + .bits = { + .pxx = 0, /* no power sequence control */ + .map = 0, /* no power sequence control */ + .hskreq = IMX8MM_HSIO_HSK_PWRDNREQN, + .hskack = IMX8MM_HSIO_HSK_PWRDNACKN, + }, + .keep_clocks = true, + }, + + [IMX8MM_POWER_DOMAIN_PCIE] = { + .bits = { + .pxx = IMX8MM_PCIE_SW_Pxx_REQ, + .map = IMX8MM_PCIE_A53_DOMAIN, + }, + .pgc = BIT(IMX8MM_PGC_PCIE), + }, + + [IMX8MM_POWER_DOMAIN_OTG1] = { + .bits = { + .pxx = IMX8MM_OTG1_SW_Pxx_REQ, + .map = IMX8MM_OTG1_A53_DOMAIN, + }, + .pgc = BIT(IMX8MM_PGC_OTG1), + }, + + [IMX8MM_POWER_DOMAIN_OTG2] = { + .bits = { + .pxx = IMX8MM_OTG2_SW_Pxx_REQ, + .map = IMX8MM_OTG2_A53_DOMAIN, + }, + .pgc = BIT(IMX8MM_PGC_OTG2), + }, +}; + +static const struct imx_pgc_domain_data imx8mm_pgc_domain_data = { + .domains = imx8mm_pgc_domains, + .domains_num = ARRAY_SIZE(imx8mm_pgc_domains), + .pgc_regs = &imx7_pgc_regs, +}; +#endif + +#ifdef CONFIG_IMX8MN +static const struct imx_pgc_domain imx8mn_pgc_domains[] = { + [IMX8MN_POWER_DOMAIN_HSIOMIX] = { + .bits = { + .pxx = 0, /* no power sequence control */ + .map = 0, /* no power sequence control */ + .hskreq = IMX8MN_HSIO_HSK_PWRDNREQN, + .hskack = IMX8MN_HSIO_HSK_PWRDNACKN, + }, + .keep_clocks = true, + }, + + [IMX8MN_POWER_DOMAIN_OTG1] = { + .bits = { + .pxx = IMX8MN_OTG1_SW_Pxx_REQ, + .map = IMX8MN_OTG1_A53_DOMAIN, + }, + .pgc = BIT(IMX8MN_PGC_OTG1), + }, +}; + +static const struct imx_pgc_domain_data imx8mn_pgc_domain_data = { + .domains = imx8mn_pgc_domains, + .domains_num = ARRAY_SIZE(imx8mn_pgc_domains), + .pgc_regs = &imx7_pgc_regs, +}; +#endif + +#ifdef CONFIG_IMX8MP +static const struct imx_pgc_domain imx8mp_pgc_domains[] = { + [IMX8MP_POWER_DOMAIN_PCIE_PHY] = { + .bits = { + .pxx = IMX8MP_PCIE_PHY_SW_Pxx_REQ, + .map = IMX8MP_PCIE_PHY_A53_DOMAIN, + }, + .pgc = BIT(IMX8MP_PGC_PCIE), + }, + + [IMX8MP_POWER_DOMAIN_USB1_PHY] = { + .bits = { + .pxx = IMX8MP_USB1_PHY_Pxx_REQ, + .map = IMX8MP_USB1_PHY_A53_DOMAIN, + }, + .pgc = BIT(IMX8MP_PGC_USB1), + }, + + [IMX8MP_POWER_DOMAIN_USB2_PHY] = { + .bits = { + .pxx = IMX8MP_USB2_PHY_Pxx_REQ, + .map = IMX8MP_USB2_PHY_A53_DOMAIN, + }, + .pgc = BIT(IMX8MP_PGC_USB2), + }, + + [IMX8MP_POWER_DOMAIN_HSIOMIX] = { + .bits = { + .pxx = IMX8MP_HSIOMIX_Pxx_REQ, + .map = IMX8MP_HSIOMIX_A53_DOMAIN, + .hskreq = IMX8MP_HSIOMIX_PWRDNREQN, + .hskack = IMX8MP_HSIOMIX_PWRDNACKN, + }, + .pgc = BIT(IMX8MP_PGC_HSIOMIX), + .keep_clocks = true, + }, +}; + +static const struct imx_pgc_regs imx8mp_pgc_regs = { + .map = IMX8MP_GPC_PGC_CPU_MAPPING, + .pup = IMX8MP_GPC_PU_PGC_SW_PUP_REQ, + .pdn = IMX8MP_GPC_PU_PGC_SW_PDN_REQ, + .hsk = IMX8MP_GPC_PU_PWRHSK, +}; + +static const struct imx_pgc_domain_data imx8mp_pgc_domain_data = { + .domains = imx8mp_pgc_domains, + .domains_num = ARRAY_SIZE(imx8mp_pgc_domains), + .pgc_regs = &imx8mp_pgc_regs, +}; +#endif static int imx8m_power_domain_on(struct power_domain *power_domain) { struct udevice *dev = power_domain->dev; - struct imx8m_power_domain_plat *pdata; + struct imx8m_power_domain_plat *pdata = dev_get_plat(dev); + const struct imx_pgc_domain *domain = pdata->domain; + const struct imx_pgc_regs *regs = pdata->regs; + void __iomem *base = pdata->base; + u32 pgc; + int ret; - pdata = dev_get_plat(dev); + if (pdata->clk.count) { + ret = clk_enable_bulk(&pdata->clk); + if (ret) { + dev_err(dev, "failed to enable reset clocks\n"); + return ret; + } + } - if (pdata->resource_id < 0) - return -EINVAL; + if (domain->bits.pxx) { + /* request the domain to power up */ + setbits_le32(base + regs->pup, domain->bits.pxx); - if (pdata->has_pd) - power_domain_on(&pdata->pd); + /* + * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait + * for PUP_REQ/PDN_REQ bit to be cleared + */ + ret = wait_for_bit_le32(base + regs->pup, domain->bits.pxx, + false, 1000, false); + if (ret) { + dev_err(dev, "failed to command PGC\n"); + goto out_clk_disable; + } - arm_smccc_smc(IMX_SIP_GPC, IMX_SIP_GPC_PM_DOMAIN, - pdata->resource_id, 1, 0, 0, 0, 0, NULL); + /* disable power control */ + for_each_set_bit(pgc, &domain->pgc, 32) { + clrbits_le32(base + GPC_PGC_CTRL(pgc), + GPC_PGC_CTRL_PCR); + } + } + + /* delay for reset to propagate */ + udelay(5); + + /* request the ADB400 to power up */ + if (domain->bits.hskreq) + setbits_le32(base + regs->hsk, domain->bits.hskreq); + + /* Disable reset clocks for all devices in the domain */ + if (!domain->keep_clocks && pdata->clk.count) + clk_disable_bulk(&pdata->clk); return 0; + +out_clk_disable: + if (pdata->clk.count) + clk_disable_bulk(&pdata->clk); + return ret; } static int imx8m_power_domain_off(struct power_domain *power_domain) { struct udevice *dev = power_domain->dev; - struct imx8m_power_domain_plat *pdata; - pdata = dev_get_plat(dev); + struct imx8m_power_domain_plat *pdata = dev_get_plat(dev); + const struct imx_pgc_domain *domain = pdata->domain; + const struct imx_pgc_regs *regs = pdata->regs; + void __iomem *base = pdata->base; + u32 pgc; + int ret; + + /* Enable reset clocks for all devices in the domain */ + if (!domain->keep_clocks && pdata->clk.count) { + ret = clk_enable_bulk(&pdata->clk); + if (ret) + return ret; + } + + /* request the ADB400 to power down */ + if (domain->bits.hskreq) { + clrbits_le32(base + regs->hsk, domain->bits.hskreq); + + ret = wait_for_bit_le32(base + regs->hsk, domain->bits.hskack, + false, 1000, false); + if (ret) { + dev_err(dev, "failed to power down ADB400\n"); + goto out_clk_disable; + } + } - if (pdata->resource_id < 0) - return -EINVAL; + if (domain->bits.pxx) { + /* enable power control */ + for_each_set_bit(pgc, &domain->pgc, 32) { + setbits_le32(base + GPC_PGC_CTRL(pgc), + GPC_PGC_CTRL_PCR); + } - arm_smccc_smc(IMX_SIP_GPC, IMX_SIP_GPC_PM_DOMAIN, - pdata->resource_id, 0, 0, 0, 0, 0, NULL); + /* request the domain to power down */ + setbits_le32(base + regs->pdn, 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 = wait_for_bit_le32(base + regs->pdn, domain->bits.pxx, + false, 1000, false); + if (ret) { + dev_err(dev, "failed to command PGC\n"); + goto out_clk_disable; + } + } + + /* Disable reset clocks for all devices in the domain */ + if (pdata->clk.count) + clk_disable_bulk(&pdata->clk); if (pdata->has_pd) power_domain_off(&pdata->pd); return 0; + +out_clk_disable: + if (!domain->keep_clocks && pdata->clk.count) + clk_disable_bulk(&pdata->clk); + + return ret; } static int imx8m_power_domain_of_xlate(struct power_domain *power_domain, @@ -83,6 +464,12 @@ static int imx8m_power_domain_bind(struct udevice *dev) /* Bind the subnode to this driver */ name = fdt_get_name(gd->fdt_blob, offset, NULL); + /* Descend into 'pgc' subnode */ + if (!strstr(name, "power-domain")) { + offset = fdt_first_subnode(gd->fdt_blob, offset); + name = fdt_get_name(gd->fdt_blob, offset, NULL); + } + ret = device_bind_with_driver_data(dev, dev->driver, name, dev->driver_data, offset_to_ofnode(offset), @@ -102,15 +489,34 @@ static int imx8m_power_domain_bind(struct udevice *dev) static int imx8m_power_domain_probe(struct udevice *dev) { + struct imx8m_power_domain_plat *pdata = dev_get_plat(dev); + int ret; + + /* Nothing to do for non-"power-domain" driver instances. */ + if (!strstr(dev->name, "power-domain")) + return 0; + + /* Grab optional power domain clock. */ + ret = clk_get_bulk(dev, &pdata->clk); + if (ret && ret != -ENOENT) { + dev_err(dev, "Failed to get domain clock (%d)\n", ret); + return ret; + } + return 0; } static int imx8m_power_domain_of_to_plat(struct udevice *dev) { struct imx8m_power_domain_plat *pdata = dev_get_plat(dev); + struct imx_pgc_domain_data *domain_data = + (struct imx_pgc_domain_data *)dev_get_driver_data(dev); pdata->resource_id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", -1); + pdata->domain = &domain_data->domains[pdata->resource_id]; + pdata->regs = domain_data->pgc_regs; + pdata->base = dev_read_addr_ptr(dev->parent); if (!power_domain_get(dev, &pdata->pd)) pdata->has_pd = 1; @@ -119,15 +525,22 @@ static int imx8m_power_domain_of_to_plat(struct udevice *dev) } static const struct udevice_id imx8m_power_domain_ids[] = { - { .compatible = "fsl,imx8mq-gpc" }, - { .compatible = "fsl,imx8mm-gpc" }, - { .compatible = "fsl,imx8mn-gpc" }, +#ifdef CONFIG_IMX8MQ + { .compatible = "fsl,imx8mq-gpc", .data = (long)&imx8m_pgc_domain_data }, +#endif +#ifdef CONFIG_IMX8MM + { .compatible = "fsl,imx8mm-gpc", .data = (long)&imx8mm_pgc_domain_data }, +#endif +#ifdef CONFIG_IMX8MN + { .compatible = "fsl,imx8mn-gpc", .data = (long)&imx8mn_pgc_domain_data }, +#endif +#ifdef CONFIG_IMX8MP + { .compatible = "fsl,imx8mp-gpc", .data = (long)&imx8mp_pgc_domain_data }, +#endif { } }; struct power_domain_ops imx8m_power_domain_ops = { - .request = imx8m_power_domain_request, - .rfree = imx8m_power_domain_free, .on = imx8m_power_domain_on, .off = imx8m_power_domain_off, .of_xlate = imx8m_power_domain_of_xlate, diff --git a/drivers/power/domain/imx8mp-hsiomix.c b/drivers/power/domain/imx8mp-hsiomix.c new file mode 100644 index 0000000000..6a721a934a --- /dev/null +++ b/drivers/power/domain/imx8mp-hsiomix.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Marek Vasut <marex@denx.de> + */ + +#include <common.h> +#include <asm/io.h> +#include <clk.h> +#include <dm.h> +#include <dm/device.h> +#include <dm/device_compat.h> +#include <power-domain-uclass.h> + +#include <dt-bindings/power/imx8mp-power.h> + +#define GPR_REG0 0x0 +#define PCIE_CLOCK_MODULE_EN BIT(0) +#define USB_CLOCK_MODULE_EN BIT(1) + +struct imx8mp_hsiomix_priv { + void __iomem *base; + struct clk clk_usb; + struct power_domain pd_bus; + struct power_domain pd_usb; + struct power_domain pd_usb_phy1; + struct power_domain pd_usb_phy2; +}; + +static int imx8mp_hsiomix_on(struct power_domain *power_domain) +{ + struct udevice *dev = power_domain->dev; + struct imx8mp_hsiomix_priv *priv = dev_get_priv(dev); + struct power_domain *domain; + int ret; + + ret = power_domain_on(&priv->pd_bus); + if (ret) + return ret; + + if (power_domain->id == IMX8MP_HSIOBLK_PD_USB) { + domain = &priv->pd_usb; + } else if (power_domain->id == IMX8MP_HSIOBLK_PD_USB_PHY1) { + domain = &priv->pd_usb_phy1; + } else if (power_domain->id == IMX8MP_HSIOBLK_PD_USB_PHY2) { + domain = &priv->pd_usb_phy2; + } else { + ret = -EINVAL; + goto err_pd; + } + + ret = power_domain_on(domain); + if (ret) + goto err_pd; + + ret = clk_enable(&priv->clk_usb); + if (ret) + goto err_clk; + + if (power_domain->id == IMX8MP_HSIOBLK_PD_USB) + setbits_le32(priv->base + GPR_REG0, USB_CLOCK_MODULE_EN); + + return 0; + +err_clk: + power_domain_off(domain); +err_pd: + power_domain_off(&priv->pd_bus); + return ret; +} + +static int imx8mp_hsiomix_off(struct power_domain *power_domain) +{ + struct udevice *dev = power_domain->dev; + struct imx8mp_hsiomix_priv *priv = dev_get_priv(dev); + + if (power_domain->id == IMX8MP_HSIOBLK_PD_USB) + clrbits_le32(priv->base + GPR_REG0, USB_CLOCK_MODULE_EN); + + clk_disable(&priv->clk_usb); + + if (power_domain->id == IMX8MP_HSIOBLK_PD_USB) + power_domain_off(&priv->pd_usb); + else if (power_domain->id == IMX8MP_HSIOBLK_PD_USB_PHY1) + power_domain_off(&priv->pd_usb_phy1); + else if (power_domain->id == IMX8MP_HSIOBLK_PD_USB_PHY2) + power_domain_off(&priv->pd_usb_phy2); + + power_domain_off(&priv->pd_bus); + + return 0; +} + +static int imx8mp_hsiomix_of_xlate(struct power_domain *power_domain, + struct ofnode_phandle_args *args) +{ + power_domain->id = args->args[0]; + + return 0; +} + +static int imx8mp_hsiomix_probe(struct udevice *dev) +{ + struct imx8mp_hsiomix_priv *priv = dev_get_priv(dev); + int ret; + + priv->base = dev_read_addr_ptr(dev); + + ret = clk_get_by_name(dev, "usb", &priv->clk_usb); + if (ret < 0) + return ret; + + ret = power_domain_get_by_name(dev, &priv->pd_bus, "bus"); + if (ret < 0) + goto err_pd_bus; + + ret = power_domain_get_by_name(dev, &priv->pd_usb, "usb"); + if (ret < 0) + goto err_pd_usb; + + ret = power_domain_get_by_name(dev, &priv->pd_usb_phy1, "usb-phy1"); + if (ret < 0) + goto err_pd_usb_phy1; + + ret = power_domain_get_by_name(dev, &priv->pd_usb_phy2, "usb-phy2"); + if (ret < 0) + goto err_pd_usb_phy2; + + return 0; + +err_pd_usb_phy2: + power_domain_free(&priv->pd_usb_phy1); +err_pd_usb_phy1: + power_domain_free(&priv->pd_usb); +err_pd_usb: + power_domain_free(&priv->pd_bus); +err_pd_bus: + clk_free(&priv->clk_usb); + return ret; +} + +static const struct udevice_id imx8mp_hsiomix_ids[] = { + { .compatible = "fsl,imx8mp-hsio-blk-ctrl" }, + { } +}; + +struct power_domain_ops imx8mp_hsiomix_ops = { + .on = imx8mp_hsiomix_on, + .off = imx8mp_hsiomix_off, + .of_xlate = imx8mp_hsiomix_of_xlate, +}; + +U_BOOT_DRIVER(imx8mp_hsiomix) = { + .name = "imx8mp_hsiomix", + .id = UCLASS_POWER_DOMAIN, + .of_match = imx8mp_hsiomix_ids, + .probe = imx8mp_hsiomix_probe, + .priv_auto = sizeof(struct imx8mp_hsiomix_priv), + .ops = &imx8mp_hsiomix_ops, +}; diff --git a/drivers/power/domain/meson-ee-pwrc.c b/drivers/power/domain/meson-ee-pwrc.c index a4d50e701a..676fded808 100644 --- a/drivers/power/domain/meson-ee-pwrc.c +++ b/drivers/power/domain/meson-ee-pwrc.c @@ -273,16 +273,6 @@ static bool pwrc_ee_get_power(struct power_domain *power_domain) return (reg & pwrc_domain->top_pd->sleep_mask); } -static int meson_ee_pwrc_request(struct power_domain *power_domain) -{ - return 0; -} - -static int meson_ee_pwrc_free(struct power_domain *power_domain) -{ - return 0; -} - static int meson_ee_pwrc_off(struct power_domain *power_domain) { struct meson_ee_pwrc_priv *priv = dev_get_priv(power_domain->dev); @@ -387,10 +377,8 @@ static int meson_ee_pwrc_of_xlate(struct power_domain *power_domain, } struct power_domain_ops meson_ee_pwrc_ops = { - .rfree = meson_ee_pwrc_free, .off = meson_ee_pwrc_off, .on = meson_ee_pwrc_on, - .request = meson_ee_pwrc_request, .of_xlate = meson_ee_pwrc_of_xlate, }; diff --git a/drivers/power/domain/meson-gx-pwrc-vpu.c b/drivers/power/domain/meson-gx-pwrc-vpu.c index eb94af2cf8..612660ce89 100644 --- a/drivers/power/domain/meson-gx-pwrc-vpu.c +++ b/drivers/power/domain/meson-gx-pwrc-vpu.c @@ -45,16 +45,6 @@ struct meson_gx_pwrc_vpu_priv { struct clk_bulk clks; }; -static int meson_pwrc_vpu_request(struct power_domain *power_domain) -{ - return 0; -} - -static int meson_pwrc_vpu_free(struct power_domain *power_domain) -{ - return 0; -} - static int meson_gx_pwrc_vpu_on(struct power_domain *power_domain) { struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(power_domain->dev); @@ -274,10 +264,8 @@ static int meson_pwrc_vpu_of_xlate(struct power_domain *power_domain, } struct power_domain_ops meson_gx_pwrc_vpu_ops = { - .rfree = meson_pwrc_vpu_free, .off = meson_pwrc_vpu_off, .on = meson_pwrc_vpu_on, - .request = meson_pwrc_vpu_request, .of_xlate = meson_pwrc_vpu_of_xlate, }; diff --git a/drivers/power/domain/mtk-power-domain.c b/drivers/power/domain/mtk-power-domain.c index ca2ded00ef..3b84147d48 100644 --- a/drivers/power/domain/mtk-power-domain.c +++ b/drivers/power/domain/mtk-power-domain.c @@ -317,11 +317,6 @@ static int scpsys_power_request(struct power_domain *power_domain) return 0; } -static int scpsys_power_free(struct power_domain *power_domain) -{ - return 0; -} - static int mtk_power_domain_hook(struct udevice *dev) { struct scp_domain *scpd = dev_get_priv(dev); @@ -399,7 +394,6 @@ static const struct udevice_id mtk_power_domain_ids[] = { }; struct power_domain_ops mtk_power_domain_ops = { - .rfree = scpsys_power_free, .off = scpsys_power_off, .on = scpsys_power_on, .request = scpsys_power_request, diff --git a/drivers/power/domain/power-domain-uclass.c b/drivers/power/domain/power-domain-uclass.c index 1a317a00aa..f6286c70c1 100644 --- a/drivers/power/domain/power-domain-uclass.c +++ b/drivers/power/domain/power-domain-uclass.c @@ -71,7 +71,7 @@ int power_domain_get_by_index(struct udevice *dev, return ret; } - ret = ops->request(power_domain); + ret = ops->request ? ops->request(power_domain) : 0; if (ret) { debug("ops->request() failed: %d\n", ret); return ret; @@ -80,6 +80,20 @@ int power_domain_get_by_index(struct udevice *dev, return 0; } +int power_domain_get_by_name(struct udevice *dev, + struct power_domain *power_domain, const char *name) +{ + int index; + + index = dev_read_stringlist_search(dev, "power-domain-names", name); + if (index < 0) { + debug("fdt_stringlist_search() failed: %d\n", index); + return index; + } + + return power_domain_get_by_index(dev, power_domain, index); +} + int power_domain_get(struct udevice *dev, struct power_domain *power_domain) { return power_domain_get_by_index(dev, power_domain, 0); @@ -91,7 +105,7 @@ int power_domain_free(struct power_domain *power_domain) debug("%s(power_domain=%p)\n", __func__, power_domain); - return ops->rfree(power_domain); + return ops->rfree ? ops->rfree(power_domain) : 0; } int power_domain_on(struct power_domain *power_domain) @@ -100,7 +114,7 @@ int power_domain_on(struct power_domain *power_domain) debug("%s(power_domain=%p)\n", __func__, power_domain); - return ops->on(power_domain); + return ops->on ? ops->on(power_domain) : 0; } int power_domain_off(struct power_domain *power_domain) @@ -109,7 +123,7 @@ int power_domain_off(struct power_domain *power_domain) debug("%s(power_domain=%p)\n", __func__, power_domain); - return ops->off(power_domain); + return ops->off ? ops->off(power_domain) : 0; } #if CONFIG_IS_ENABLED(OF_REAL) diff --git a/drivers/power/domain/tegra186-power-domain.c b/drivers/power/domain/tegra186-power-domain.c index 707735cf85..46da541b75 100644 --- a/drivers/power/domain/tegra186-power-domain.c +++ b/drivers/power/domain/tegra186-power-domain.c @@ -15,22 +15,6 @@ #define UPDATE BIT(0) #define ON BIT(1) -static int tegra186_power_domain_request(struct power_domain *power_domain) -{ - debug("%s(power_domain=%p) (dev=%p, id=%lu)\n", __func__, - power_domain, power_domain->dev, power_domain->id); - - return 0; -} - -static int tegra186_power_domain_free(struct power_domain *power_domain) -{ - debug("%s(power_domain=%p) (dev=%p, id=%lu)\n", __func__, - power_domain, power_domain->dev, power_domain->id); - - return 0; -} - static int tegra186_power_domain_common(struct power_domain *power_domain, bool on) { @@ -73,22 +57,12 @@ static int tegra186_power_domain_off(struct power_domain *power_domain) } struct power_domain_ops tegra186_power_domain_ops = { - .request = tegra186_power_domain_request, - .rfree = tegra186_power_domain_free, .on = tegra186_power_domain_on, .off = tegra186_power_domain_off, }; -static int tegra186_power_domain_probe(struct udevice *dev) -{ - debug("%s(dev=%p)\n", __func__, dev); - - return 0; -} - U_BOOT_DRIVER(tegra186_power_domain) = { .name = "tegra186_power_domain", .id = UCLASS_POWER_DOMAIN, - .probe = tegra186_power_domain_probe, .ops = &tegra186_power_domain_ops, }; diff --git a/drivers/power/domain/ti-power-domain.c b/drivers/power/domain/ti-power-domain.c index 752e76b399..292fff0dfb 100644 --- a/drivers/power/domain/ti-power-domain.c +++ b/drivers/power/domain/ti-power-domain.c @@ -356,17 +356,6 @@ static int ti_power_domain_of_xlate(struct power_domain *pd, return 0; } - -static int ti_power_domain_request(struct power_domain *pd) -{ - return 0; -} - -static int ti_power_domain_free(struct power_domain *pd) -{ - return 0; -} - static const struct udevice_id ti_power_domain_of_match[] = { { .compatible = "ti,sci-pm-domain" }, { /* sentinel */ } @@ -376,8 +365,6 @@ static struct power_domain_ops ti_power_domain_ops = { .on = ti_power_domain_on, .off = ti_power_domain_off, .of_xlate = ti_power_domain_of_xlate, - .request = ti_power_domain_request, - .rfree = ti_power_domain_free, }; U_BOOT_DRIVER(ti_pm_domains) = { diff --git a/drivers/power/domain/ti-sci-power-domain.c b/drivers/power/domain/ti-sci-power-domain.c index f18e45617a..0140e5e521 100644 --- a/drivers/power/domain/ti-sci-power-domain.c +++ b/drivers/power/domain/ti-sci-power-domain.c @@ -44,18 +44,6 @@ static int ti_sci_power_domain_probe(struct udevice *dev) return 0; } -static int ti_sci_power_domain_request(struct power_domain *pd) -{ - debug("%s(pd=%p)\n", __func__, pd); - return 0; -} - -static int ti_sci_power_domain_free(struct power_domain *pd) -{ - debug("%s(pd=%p)\n", __func__, pd); - return 0; -} - static int ti_sci_power_domain_on(struct power_domain *pd) { struct ti_sci_power_domain_data *data = dev_get_priv(pd->dev); @@ -123,8 +111,6 @@ static const struct udevice_id ti_sci_power_domain_of_match[] = { }; static struct power_domain_ops ti_sci_power_domain_ops = { - .request = ti_sci_power_domain_request, - .rfree = ti_sci_power_domain_free, .on = ti_sci_power_domain_on, .off = ti_sci_power_domain_off, .of_xlate = ti_sci_power_domain_of_xlate, |