From 20874a60722b2b282e29b0819198c1649eff65f2 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 13 Apr 2022 00:42:48 +0200 Subject: power-domain: Return 0 if ops unimplemented and remove empty functions In case the ops is not implemented, return 0 in the core right away. This is better than having multiple copies of functions which just return 0 in each power domain driver. Drop all those empty functions. Signed-off-by: Marek Vasut Cc: Patrick Delaunay Cc: Simon Glass --- drivers/power/domain/apple-pmgr.c | 30 ------------------------- drivers/power/domain/bcm6328-power-domain.c | 6 ----- drivers/power/domain/imx8-power-domain-legacy.c | 16 ------------- drivers/power/domain/imx8-power-domain.c | 24 -------------------- drivers/power/domain/imx8m-power-domain.c | 18 --------------- drivers/power/domain/meson-ee-pwrc.c | 12 ---------- drivers/power/domain/meson-gx-pwrc-vpu.c | 12 ---------- drivers/power/domain/mtk-power-domain.c | 6 ----- drivers/power/domain/power-domain-uclass.c | 8 +++---- drivers/power/domain/tegra186-power-domain.c | 26 --------------------- drivers/power/domain/ti-power-domain.c | 13 ----------- drivers/power/domain/ti-sci-power-domain.c | 14 ------------ 12 files changed, 4 insertions(+), 181 deletions(-) (limited to 'drivers') diff --git a/drivers/power/domain/apple-pmgr.c b/drivers/power/domain/apple-pmgr.c index 4d06e76ff5e..402c5b1fd18 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 6e720e0798c..80144dd9772 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 e2fae2dbc86..bf45891bccd 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 6461ab23d62..17b5d57b19b 100644 --- a/drivers/power/domain/imx8-power-domain.c +++ b/drivers/power/domain/imx8-power-domain.c @@ -12,20 +12,6 @@ #include #include -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 5d34bc12902..6082ee6ff8c 100644 --- a/drivers/power/domain/imx8m-power-domain.c +++ b/drivers/power/domain/imx8m-power-domain.c @@ -18,16 +18,6 @@ DECLARE_GLOBAL_DATA_PTR; -static int imx8m_power_domain_request(struct power_domain *power_domain) -{ - return 0; -} - -static int imx8m_power_domain_free(struct power_domain *power_domain) -{ - return 0; -} - static int imx8m_power_domain_on(struct power_domain *power_domain) { struct udevice *dev = power_domain->dev; @@ -100,11 +90,6 @@ static int imx8m_power_domain_bind(struct udevice *dev) return 0; } -static int imx8m_power_domain_probe(struct udevice *dev) -{ - return 0; -} - static int imx8m_power_domain_of_to_plat(struct udevice *dev) { struct imx8m_power_domain_plat *pdata = dev_get_plat(dev); @@ -126,8 +111,6 @@ static const struct udevice_id imx8m_power_domain_ids[] = { }; 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, @@ -138,7 +121,6 @@ U_BOOT_DRIVER(imx8m_power_domain) = { .id = UCLASS_POWER_DOMAIN, .of_match = imx8m_power_domain_ids, .bind = imx8m_power_domain_bind, - .probe = imx8m_power_domain_probe, .of_to_plat = imx8m_power_domain_of_to_plat, .plat_auto = sizeof(struct imx8m_power_domain_plat), .ops = &imx8m_power_domain_ops, diff --git a/drivers/power/domain/meson-ee-pwrc.c b/drivers/power/domain/meson-ee-pwrc.c index a4d50e701ae..676fded8080 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 eb94af2cf83..612660ce89f 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 ca2ded00efa..3b84147d481 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 33f9206bd09..0c5823ceddf 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; @@ -91,7 +91,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 +100,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 +109,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 707735cf851..46da541b75a 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 752e76b3996..292fff0dfbf 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 f18e45617a1..0140e5e5217 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, -- cgit v1.2.3 From 8741d9275626dc2fdea725b6c5bdcd824c03a526 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 13 Apr 2022 00:42:49 +0200 Subject: imx: power-domain: Descend into pgc subnode if present In case the power domain node structure is gpc@303a0000/pgc/power-domain@N, do not bind power domain driver to the 'pgc' node, but rather descend into it and only bind power domain drivers to power-domain@N subnodes. This way we do not waste one useless driver instance associated with 'pgc' node. Tested-By: Tim Harvey #imx8mp-venice-defconfig Signed-off-by: Marek Vasut Cc: Fabio Estevam Cc: Peng Fan Cc: Stefano Babic --- drivers/power/domain/imx8m-power-domain.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/power/domain/imx8m-power-domain.c b/drivers/power/domain/imx8m-power-domain.c index 6082ee6ff8c..ac7411f8327 100644 --- a/drivers/power/domain/imx8m-power-domain.c +++ b/drivers/power/domain/imx8m-power-domain.c @@ -73,6 +73,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), -- cgit v1.2.3 From 19842b6a20f3205c40f868f9d0a787f7ed5c9f18 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 13 Apr 2022 00:42:50 +0200 Subject: imx: power-domain: Inline arch-imx8m/power-domain.h The arch/arm/include/asm/arch-imx8m/power-domain.h is not included anywhere except in drivers/power/domain/imx8m-power-domain.c, just inline the content and drop the header. No functional change. Tested-By: Tim Harvey #imx8mp-venice-defconfig Signed-off-by: Marek Vasut Cc: Fabio Estevam Cc: Peng Fan Cc: Stefano Babic --- drivers/power/domain/imx8m-power-domain.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/domain/imx8m-power-domain.c b/drivers/power/domain/imx8m-power-domain.c index ac7411f8327..c32dbcc31ae 100644 --- a/drivers/power/domain/imx8m-power-domain.c +++ b/drivers/power/domain/imx8m-power-domain.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -18,6 +17,12 @@ DECLARE_GLOBAL_DATA_PTR; +struct imx8m_power_domain_plat { + int resource_id; + int has_pd; + struct power_domain pd; +}; + static int imx8m_power_domain_on(struct power_domain *power_domain) { struct udevice *dev = power_domain->dev; -- cgit v1.2.3 From 4eb82c2e56a7cd68b74c3a21de5c79ea80c5dcd6 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 13 Apr 2022 00:42:51 +0200 Subject: imx: power-domain: Get rid of SMCCC dependency This driver is the only SMCCC dependency in iMX8M U-Boot port. Rework the driver based on Linux GPCv2 driver to directly control the GPCv2 block instead of using SMCCC calls. This way, U-Boot can operate the i.MX8M power domains without depending on anything else. This is losely based on Linux GPCv2 driver. The GPU, VPU, MIPI power domains are not supported to save space, since they are not useful in the bootloader. The only domains kept are ones for HSIO, PCIe, USB. Tested-By: Tim Harvey #imx8mp-venice-defconfig Signed-off-by: Marek Vasut Cc: Fabio Estevam Cc: Peng Fan Cc: Stefano Babic --- drivers/power/domain/Kconfig | 1 + drivers/power/domain/imx8m-power-domain.c | 379 ++++++++++++++++++++++++++++-- 2 files changed, 361 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig index 93d2599d83c..04fc0054323 100644 --- a/drivers/power/domain/Kconfig +++ b/drivers/power/domain/Kconfig @@ -35,6 +35,7 @@ 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. diff --git a/drivers/power/domain/imx8m-power-domain.c b/drivers/power/domain/imx8m-power-domain.c index c32dbcc31ae..e2e41cf5fee 100644 --- a/drivers/power/domain/imx8m-power-domain.c +++ b/drivers/power/domain/imx8m-power-domain.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -12,52 +13,361 @@ #include #include #include +#include #include -#include +#include +#include + +#include +#include +#include DECLARE_GLOBAL_DATA_PTR; +#define GPC_PGC_CPU_MAPPING 0x0ec + +#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 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 GPC_M4_PU_PDN_FLG 0x1bc + +#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) + +/* + * 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 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; - struct power_domain 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 + 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; + + if (pdata->clk.count) { + ret = clk_enable_bulk(&pdata->clk); + if (ret) { + dev_err(dev, "failed to enable reset clocks\n"); + return ret; + } + } - pdata = dev_get_plat(dev); + if (domain->bits.pxx) { + /* request the domain to power up */ + setbits_le32(base + regs->pup, domain->bits.pxx); - if (pdata->resource_id < 0) - return -EINVAL; + /* + * 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; + } - if (pdata->has_pd) - power_domain_on(&pdata->pd); + /* 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); - arm_smccc_smc(IMX_SIP_GPC, IMX_SIP_GPC_PM_DOMAIN, - pdata->resource_id, 1, 0, 0, 0, 0, NULL); + /* 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; - if (pdata->resource_id < 0) - return -EINVAL; + /* 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; + } - arm_smccc_smc(IMX_SIP_GPC, IMX_SIP_GPC_PM_DOMAIN, - pdata->resource_id, 0, 0, 0, 0, 0, NULL); + /* 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 (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); + } + + /* 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, @@ -101,12 +411,36 @@ static int imx8m_power_domain_bind(struct udevice *dev) return 0; } +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; @@ -115,9 +449,15 @@ 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 { } }; @@ -132,6 +472,7 @@ U_BOOT_DRIVER(imx8m_power_domain) = { .id = UCLASS_POWER_DOMAIN, .of_match = imx8m_power_domain_ids, .bind = imx8m_power_domain_bind, + .probe = imx8m_power_domain_probe, .of_to_plat = imx8m_power_domain_of_to_plat, .plat_auto = sizeof(struct imx8m_power_domain_plat), .ops = &imx8m_power_domain_ops, -- cgit v1.2.3 From 63c390a1eac72bcf46d0b61d69c570fe5e48177d Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 13 Apr 2022 00:42:52 +0200 Subject: power_domain: Add power_domain_get_by_name() Implement power_domain_get_by_name() convenience function which parses DT property 'power-domain-names' and looks up power domain by matching name. Signed-off-by: Marek Vasut Cc: Patrick Delaunay Cc: Simon Glass --- drivers/power/domain/power-domain-uclass.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/power/domain/power-domain-uclass.c b/drivers/power/domain/power-domain-uclass.c index 0c5823ceddf..74c33d4e2e0 100644 --- a/drivers/power/domain/power-domain-uclass.c +++ b/drivers/power/domain/power-domain-uclass.c @@ -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); -- cgit v1.2.3 From 2e760f180d5e8598c9ff6f0492cad050687fb32d Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 13 Apr 2022 00:42:53 +0200 Subject: imx: power-domain: Add i.MX8MP support Add i.MX8MP power domain handling into the driver. This is based on the Linux GPCv2 driver state which is soon to be in Linux next. Tested-By: Tim Harvey #imx8mp-venice-gw74xx Signed-off-by: Marek Vasut Cc: Fabio Estevam Cc: Peng Fan Cc: Stefano Babic --- drivers/power/domain/imx8m-power-domain.c | 79 +++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) (limited to 'drivers') diff --git a/drivers/power/domain/imx8m-power-domain.c b/drivers/power/domain/imx8m-power-domain.c index e2e41cf5fee..145f6ec0cd3 100644 --- a/drivers/power/domain/imx8m-power-domain.c +++ b/drivers/power/domain/imx8m-power-domain.c @@ -20,11 +20,13 @@ #include #include +#include #include DECLARE_GLOBAL_DATA_PTR; #define GPC_PGC_CPU_MAPPING 0x0ec +#define IMX8MP_GPC_PGC_CPU_MAPPING 0x1cc #define IMX8M_PCIE2_A53_DOMAIN BIT(15) #define IMX8M_OTG2_A53_DOMAIN BIT(5) @@ -38,6 +40,14 @@ DECLARE_GLOBAL_DATA_PTR; #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 @@ -53,8 +63,14 @@ DECLARE_GLOBAL_DATA_PTR; #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)) @@ -63,6 +79,9 @@ DECLARE_GLOBAL_DATA_PTR; #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 @@ -80,6 +99,11 @@ DECLARE_GLOBAL_DATA_PTR; #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) @@ -244,6 +268,58 @@ static const struct imx_pgc_domain_data imx8mn_pgc_domain_data = { }; #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; @@ -457,6 +533,9 @@ static const struct udevice_id imx8m_power_domain_ids[] = { #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 { } }; -- cgit v1.2.3 From 898e7610c62aa6f0cc173d909a150f7b26e872bb Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 13 Apr 2022 00:42:54 +0200 Subject: imx: power-domain: Add i.MX8MP HSIOMIX driver Add trivial driver for i.MX8MP HSIOMIX handling. This is responsible for enabling the GPCv2 power domains and clock for USB 3.0 and PCIe in the correct order. Currently supported is the USB 3.0 part which can be tested, PCIe support should be easy to add. Tested-By: Tim Harvey #imx8mp-venice-gw74xx Signed-off-by: Marek Vasut Cc: Fabio Estevam Cc: Peng Fan Cc: Stefano Babic --- drivers/power/domain/Kconfig | 7 ++ drivers/power/domain/Makefile | 1 + drivers/power/domain/imx8mp-hsiomix.c | 159 ++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 drivers/power/domain/imx8mp-hsiomix.c (limited to 'drivers') diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig index 04fc0054323..7e1b8c072fa 100644 --- a/drivers/power/domain/Kconfig +++ b/drivers/power/domain/Kconfig @@ -40,6 +40,13 @@ config IMX8M_POWER_DOMAIN 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 7c8af67dbd6..e6244776216 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/imx8mp-hsiomix.c b/drivers/power/domain/imx8mp-hsiomix.c new file mode 100644 index 00000000000..6a721a934a7 --- /dev/null +++ b/drivers/power/domain/imx8mp-hsiomix.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Marek Vasut + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#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, +}; -- cgit v1.2.3 From f1ef95591c29c1324415dc0a61254160d7d9290a Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 13 Apr 2022 00:42:55 +0200 Subject: usb: dwc3: Rename .select_dr_mode to .glue_configure Rename the select_dr_mode callback to glue_configure, the callback is used for more than enforcing controller mode even on the TI chips, so change the name to a more generic one. No functional change. Tested-By: Tim Harvey #imx8mp-venice-gw74xx Signed-off-by: Marek Vasut Cc: Angus Ainslie Cc: Bin Meng Cc: Fabio Estevam Cc: Kunihiko Hayashi Cc: Michal Simek Cc: Peng Fan Cc: Stefano Babic --- drivers/usb/dwc3/dwc3-generic.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index 01bd0ca190e..7e3814207e4 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -219,11 +219,11 @@ U_BOOT_DRIVER(dwc3_generic_host) = { #endif struct dwc3_glue_ops { - void (*select_dr_mode)(struct udevice *dev, int index, + void (*glue_configure)(struct udevice *dev, int index, enum usb_dr_mode mode); }; -void dwc3_ti_select_dr_mode(struct udevice *dev, int index, +void dwc3_ti_glue_configure(struct udevice *dev, int index, enum usb_dr_mode mode) { #define USBOTGSS_UTMI_OTG_STATUS 0x0084 @@ -304,7 +304,7 @@ enum dwc3_omap_utmi_mode { } struct dwc3_glue_ops ti_ops = { - .select_dr_mode = dwc3_ti_select_dr_mode, + .glue_configure = dwc3_ti_glue_configure, }; static int dwc3_glue_bind(struct udevice *parent) @@ -435,8 +435,8 @@ static int dwc3_glue_probe(struct udevice *dev) dr_mode = usb_get_dr_mode(dev_ofnode(child)); device_find_next_child(&child); - if (ops && ops->select_dr_mode) - ops->select_dr_mode(dev, index, dr_mode); + if (ops && ops->glue_configure) + ops->glue_configure(dev, index, dr_mode); index++; } -- cgit v1.2.3 From d0f7a0559a9c7d63b2ecceb43f3eddecdf8c1b7e Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 13 Apr 2022 00:42:56 +0200 Subject: usb: dwc3: Implement .glue_configure for i.MX8MP The i.MX8MP glue needs to be configured based on a couple of DT properties, implement .glue_configure callback to parse those DT properties and configure the glue accordingly. Tested-By: Tim Harvey #imx8mp-venice-gw74xx Signed-off-by: Marek Vasut Cc: Angus Ainslie Cc: Bin Meng Cc: Fabio Estevam Cc: Kunihiko Hayashi Cc: Michal Simek Cc: Peng Fan Cc: Stefano Babic --- drivers/usb/dwc3/dwc3-generic.c | 52 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index 7e3814207e4..6cf844cb483 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -223,6 +223,57 @@ struct dwc3_glue_ops { enum usb_dr_mode mode); }; +void dwc3_imx8mp_glue_configure(struct udevice *dev, int index, + enum usb_dr_mode mode) +{ +/* USB glue registers */ +#define USB_CTRL0 0x00 +#define USB_CTRL1 0x04 + +#define USB_CTRL0_PORTPWR_EN BIT(12) /* 1 - PPC enabled (default) */ +#define USB_CTRL0_USB3_FIXED BIT(22) /* 1 - USB3 permanent attached */ +#define USB_CTRL0_USB2_FIXED BIT(23) /* 1 - USB2 permanent attached */ + +#define USB_CTRL1_OC_POLARITY BIT(16) /* 0 - HIGH / 1 - LOW */ +#define USB_CTRL1_PWR_POLARITY BIT(17) /* 0 - HIGH / 1 - LOW */ + fdt_addr_t regs = dev_read_addr_index(dev, 1); + void *base = map_physmem(regs, 0x8, MAP_NOCACHE); + u32 value; + + value = readl(base + USB_CTRL0); + + if (dev_read_bool(dev, "fsl,permanently-attached")) + value |= (USB_CTRL0_USB2_FIXED | USB_CTRL0_USB3_FIXED); + else + value &= ~(USB_CTRL0_USB2_FIXED | USB_CTRL0_USB3_FIXED); + + if (dev_read_bool(dev, "fsl,disable-port-power-control")) + value &= ~(USB_CTRL0_PORTPWR_EN); + else + value |= USB_CTRL0_PORTPWR_EN; + + writel(value, base + USB_CTRL0); + + value = readl(base + USB_CTRL1); + if (dev_read_bool(dev, "fsl,over-current-active-low")) + value |= USB_CTRL1_OC_POLARITY; + else + value &= ~USB_CTRL1_OC_POLARITY; + + if (dev_read_bool(dev, "fsl,power-active-low")) + value |= USB_CTRL1_PWR_POLARITY; + else + value &= ~USB_CTRL1_PWR_POLARITY; + + writel(value, base + USB_CTRL1); + + unmap_physmem(base, MAP_NOCACHE); +} + +struct dwc3_glue_ops imx8mp_ops = { + .glue_configure = dwc3_imx8mp_glue_configure, +}; + void dwc3_ti_glue_configure(struct udevice *dev, int index, enum usb_dr_mode mode) { @@ -464,6 +515,7 @@ static const struct udevice_id dwc3_glue_ids[] = { { .compatible = "rockchip,rk3328-dwc3" }, { .compatible = "rockchip,rk3399-dwc3" }, { .compatible = "qcom,dwc3" }, + { .compatible = "fsl,imx8mp-dwc3", .data = (ulong)&imx8mp_ops }, { .compatible = "fsl,imx8mq-dwc3" }, { .compatible = "intel,tangier-dwc3" }, { } -- cgit v1.2.3 From 6f6e069ca3dc76ce8b613e8a9860da573df42dd2 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Wed, 13 Apr 2022 15:54:37 -0700 Subject: pci: imx: use vpcie-supply if defined by device-tree If vpcie-supply is defined by device-tree use that if CONFIG_PCIE_IMX_POWER_GPIO is not defined. Note that after this the following boards which define CONFIG_PCIE_IMX_POWER_GPIO in their board header file as well as their device-tree should be able to remove CONFIG_PCIE_IMX_PERST_GPIO without consequence: - mx6sabresd - mx6sxsabresd - novena Note that the ge_bx50v3 board uses CONFIG_PCIE_IMX_POWER_GPIO and does not have vpcie-supply defined in it's pcie node in the dt thus removing CONFIG_PCIE_IMX_POWER_GPIO globally can't be done until that board adds vpcie-supply. Cc: Ian Ray (maintainer:GE BX50V3 BOARD) Cc: Sebastian Reichel (maintainer:GE BX50V3 BOARD) Cc: Fabio Estevam (maintainer:MX6SABRESD BOARD) Cc: Marek Vasut (maintainer:NOVENA BOARD) Signed-off-by: Tim Harvey --- drivers/pci/pcie_imx.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie_imx.c b/drivers/pci/pcie_imx.c index 2cec3900e9a..f8daedbce35 100644 --- a/drivers/pci/pcie_imx.c +++ b/drivers/pci/pcie_imx.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -102,6 +103,7 @@ struct imx_pcie_priv { void __iomem *cfg_base; struct gpio_desc reset_gpio; bool reset_active_high; + struct udevice *vpcie; }; /* @@ -530,7 +532,7 @@ static int imx6_pcie_init_phy(void) return 0; } -__weak int imx6_pcie_toggle_power(void) +__weak int imx6_pcie_toggle_power(struct udevice *vpcie) { #ifdef CONFIG_PCIE_IMX_POWER_GPIO gpio_request(CONFIG_PCIE_IMX_POWER_GPIO, "pcie_power"); @@ -540,6 +542,15 @@ __weak int imx6_pcie_toggle_power(void) mdelay(20); gpio_free(CONFIG_PCIE_IMX_POWER_GPIO); #endif + +#if CONFIG_IS_ENABLED(DM_REGULATOR) + if (vpcie) { + regulator_set_enable(vpcie, false); + mdelay(20); + regulator_set_enable(vpcie, true); + mdelay(20); + } +#endif return 0; } @@ -598,7 +609,7 @@ static int imx6_pcie_deassert_core_reset(struct imx_pcie_priv *priv) { struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR; - imx6_pcie_toggle_power(); + imx6_pcie_toggle_power(priv->vpcie); enable_pcie_clock(); @@ -717,6 +728,10 @@ static int imx_pcie_dm_probe(struct udevice *dev) { struct imx_pcie_priv *priv = dev_get_priv(dev); +#if CONFIG_IS_ENABLED(DM_REGULATOR) + device_get_supply_regulator(dev, "vpcie-supply", &priv->vpcie); +#endif + /* if PERST# valid from dt then assert it */ gpio_request_by_name(dev, "reset-gpio", 0, &priv->reset_gpio, GPIOD_IS_OUT); -- cgit v1.2.3 From e3bdc97148204863c4c1a5c6323e103274a3fcd8 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Wed, 13 Apr 2022 15:57:37 -0700 Subject: pci: imx: remove weak overrides no longer used There are no users of the imx6_pcie_toggle_power and imx6_pcie_toggle_reset weak overrides and as these functions are able to be handled now via dt properties lets remove these. Cc: Marek Vasut Signed-off-by: Tim Harvey --- drivers/pci/pcie_imx.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie_imx.c b/drivers/pci/pcie_imx.c index f8daedbce35..46ac01713ff 100644 --- a/drivers/pci/pcie_imx.c +++ b/drivers/pci/pcie_imx.c @@ -532,7 +532,7 @@ static int imx6_pcie_init_phy(void) return 0; } -__weak int imx6_pcie_toggle_power(struct udevice *vpcie) +int imx6_pcie_toggle_power(struct udevice *vpcie) { #ifdef CONFIG_PCIE_IMX_POWER_GPIO gpio_request(CONFIG_PCIE_IMX_POWER_GPIO, "pcie_power"); @@ -554,7 +554,7 @@ __weak int imx6_pcie_toggle_power(struct udevice *vpcie) return 0; } -__weak int imx6_pcie_toggle_reset(struct gpio_desc *gpio, bool active_high) +int imx6_pcie_toggle_reset(struct gpio_desc *gpio, bool active_high) { /* * See 'PCI EXPRESS BASE SPECIFICATION, REV 3.0, SECTION 6.6.1' @@ -570,12 +570,6 @@ __weak int imx6_pcie_toggle_reset(struct gpio_desc *gpio, bool active_high) * configuration file and the condition below will handle the rest * of the reset toggling. * - * In case your #PERST toggling logic is more complex, for example - * connected via CPLD or somesuch, you can override this function - * in your board file and implement reset logic as needed. You must - * not forget to wait at least 20 ms after de-asserting #PERST in - * this case either though. - * * In case your #PERST line of the PCIe EP device is not connected * at all, your design is broken and you should fix your design, * otherwise you will observe problems like for example the link -- cgit v1.2.3 From cc84edddd17ed6eedbd17ad1ab9672854ec5fa27 Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Fri, 15 Apr 2022 16:52:34 +0530 Subject: crypto/fsl: Clear the memory when blob decapsulation fails issue: blob decapsulation operation store the decrypted data in memory even if ICV check failed. fix: clear the blob data output memory. Fixes: c5de15cbc8 (crypto/fsl: Add command for encapsulating/decapsulating blobs) Signed-off-by: Gaurav Jain Reviewed-by: Kshitiz Varshney Tested-by: Kshitiz Varshney Reviewed-by: Fabio Estevam --- drivers/crypto/fsl/fsl_blob.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/crypto/fsl/fsl_blob.c b/drivers/crypto/fsl/fsl_blob.c index e8202cc5697..9b6e4bca062 100644 --- a/drivers/crypto/fsl/fsl_blob.c +++ b/drivers/crypto/fsl/fsl_blob.c @@ -71,6 +71,10 @@ int blob_decap(u8 *key_mod, u8 *src, u8 *dst, u32 len) ret = run_descriptor_jr(desc); if (ret) { + /* clear the blob data output buffer */ + memset(dst, 0x00, len); + size = ALIGN(len, ARCH_DMA_MINALIGN); + flush_dcache_range((unsigned long)dst, (unsigned long)dst + size); printf("Error in blob decapsulation: %d\n", ret); } else { size = ALIGN(len, ARCH_DMA_MINALIGN); -- cgit v1.2.3 From 2c16bf2d14d7fbacafb5473f49487ba7f219e40c Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Tue, 19 Apr 2022 10:52:28 +0530 Subject: crypto/fsl: add invalidate_dcache_range for hash output buffer HW accelerated hash operations are giving incorrect hash output. so invalidate cache lines to avoid cache overwriting in DDR memory region. caam_hash() -moved address alignment check in the beginning of function. -added invalidate_dcache_range for pout buffer before running descriptor. Fixes: d7af2baa49 (crypto/fsl: Fix HW accelerated hash commands) Signed-off-by: Gaurav Jain Reviewed-by: Fabio Estevam --- drivers/crypto/fsl/fsl_hash.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/fsl/fsl_hash.c b/drivers/crypto/fsl/fsl_hash.c index 2379b70c2da..a52c4ac957e 100644 --- a/drivers/crypto/fsl/fsl_hash.c +++ b/drivers/crypto/fsl/fsl_hash.c @@ -168,18 +168,18 @@ int caam_hash(const unsigned char *pbuf, unsigned int buf_len, uint32_t *desc; unsigned int size; - desc = malloc_cache_aligned(sizeof(int) * MAX_CAAM_DESCSIZE); - if (!desc) { - debug("Not enough memory for descriptor allocation\n"); - return -ENOMEM; - } - if (!IS_ALIGNED((uintptr_t)pbuf, ARCH_DMA_MINALIGN) || !IS_ALIGNED((uintptr_t)pout, ARCH_DMA_MINALIGN)) { puts("Error: Address arguments are not aligned\n"); return -EINVAL; } + desc = malloc_cache_aligned(sizeof(int) * MAX_CAAM_DESCSIZE); + if (!desc) { + debug("Not enough memory for descriptor allocation\n"); + return -ENOMEM; + } + size = ALIGN(buf_len, ARCH_DMA_MINALIGN); flush_dcache_range((unsigned long)pbuf, (unsigned long)pbuf + size); @@ -190,6 +190,8 @@ int caam_hash(const unsigned char *pbuf, unsigned int buf_len, size = ALIGN(sizeof(int) * MAX_CAAM_DESCSIZE, ARCH_DMA_MINALIGN); flush_dcache_range((unsigned long)desc, (unsigned long)desc + size); + size = ALIGN(driver_hash[algo].digestsize, ARCH_DMA_MINALIGN); + invalidate_dcache_range((unsigned long)pout, (unsigned long)pout + size); ret = run_descriptor_jr(desc); -- cgit v1.2.3