diff options
Diffstat (limited to 'drivers/pmdomain/amlogic')
-rw-r--r-- | drivers/pmdomain/amlogic/Kconfig | 11 | ||||
-rw-r--r-- | drivers/pmdomain/amlogic/Makefile | 1 | ||||
-rw-r--r-- | drivers/pmdomain/amlogic/meson-ee-pwrc.c | 1 | ||||
-rw-r--r-- | drivers/pmdomain/amlogic/meson-gx-pwrc-vpu.c | 379 | ||||
-rw-r--r-- | drivers/pmdomain/amlogic/meson-secure-pwrc.c | 67 |
5 files changed, 62 insertions, 397 deletions
diff --git a/drivers/pmdomain/amlogic/Kconfig b/drivers/pmdomain/amlogic/Kconfig index 2108729909b5..e72b664174af 100644 --- a/drivers/pmdomain/amlogic/Kconfig +++ b/drivers/pmdomain/amlogic/Kconfig @@ -1,17 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only menu "Amlogic PM Domains" -config MESON_GX_PM_DOMAINS - tristate "Amlogic Meson GX Power Domains driver" - depends on ARCH_MESON || COMPILE_TEST - depends on PM && OF - default ARCH_MESON - select PM_GENERIC_DOMAINS - select PM_GENERIC_DOMAINS_OF - help - Say yes to expose Amlogic Meson GX Power Domains as - Generic Power Domains. - config MESON_EE_PM_DOMAINS tristate "Amlogic Meson Everything-Else Power Domains driver" depends on ARCH_MESON || COMPILE_TEST diff --git a/drivers/pmdomain/amlogic/Makefile b/drivers/pmdomain/amlogic/Makefile index 3d58abd574f9..99f195f09957 100644 --- a/drivers/pmdomain/amlogic/Makefile +++ b/drivers/pmdomain/amlogic/Makefile @@ -1,4 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o obj-$(CONFIG_MESON_EE_PM_DOMAINS) += meson-ee-pwrc.o obj-$(CONFIG_MESON_SECURE_PM_DOMAINS) += meson-secure-pwrc.o diff --git a/drivers/pmdomain/amlogic/meson-ee-pwrc.c b/drivers/pmdomain/amlogic/meson-ee-pwrc.c index fcec6eb610e4..fbb2b4103930 100644 --- a/drivers/pmdomain/amlogic/meson-ee-pwrc.c +++ b/drivers/pmdomain/amlogic/meson-ee-pwrc.c @@ -648,4 +648,5 @@ static struct platform_driver meson_ee_pwrc_driver = { }, }; module_platform_driver(meson_ee_pwrc_driver); +MODULE_DESCRIPTION("Amlogic Meson Everything-Else Power Domains driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pmdomain/amlogic/meson-gx-pwrc-vpu.c b/drivers/pmdomain/amlogic/meson-gx-pwrc-vpu.c deleted file mode 100644 index 33df520eab95..000000000000 --- a/drivers/pmdomain/amlogic/meson-gx-pwrc-vpu.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright (c) 2017 BayLibre, SAS - * Author: Neil Armstrong <narmstrong@baylibre.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <linux/platform_device.h> -#include <linux/pm_domain.h> -#include <linux/bitfield.h> -#include <linux/regmap.h> -#include <linux/mfd/syscon.h> -#include <linux/of.h> -#include <linux/reset.h> -#include <linux/clk.h> -#include <linux/module.h> - -/* AO Offsets */ - -#define AO_RTI_GEN_PWR_SLEEP0 (0x3a << 2) - -#define GEN_PWR_VPU_HDMI BIT(8) -#define GEN_PWR_VPU_HDMI_ISO BIT(9) - -/* HHI Offsets */ - -#define HHI_MEM_PD_REG0 (0x40 << 2) -#define HHI_VPU_MEM_PD_REG0 (0x41 << 2) -#define HHI_VPU_MEM_PD_REG1 (0x42 << 2) -#define HHI_VPU_MEM_PD_REG2 (0x4d << 2) - -struct meson_gx_pwrc_vpu { - struct generic_pm_domain genpd; - struct regmap *regmap_ao; - struct regmap *regmap_hhi; - struct reset_control *rstc; - struct clk *vpu_clk; - struct clk *vapb_clk; -}; - -static inline -struct meson_gx_pwrc_vpu *genpd_to_pd(struct generic_pm_domain *d) -{ - return container_of(d, struct meson_gx_pwrc_vpu, genpd); -} - -static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd) -{ - struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd); - int i; - - regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO); - udelay(20); - - /* Power Down Memories */ - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, - 0x3 << i, 0x3 << i); - udelay(5); - } - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, - 0x3 << i, 0x3 << i); - udelay(5); - } - for (i = 8; i < 16; i++) { - regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0, - BIT(i), BIT(i)); - udelay(5); - } - udelay(20); - - regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI); - - msleep(20); - - clk_disable_unprepare(pd->vpu_clk); - clk_disable_unprepare(pd->vapb_clk); - - return 0; -} - -static int meson_g12a_pwrc_vpu_power_off(struct generic_pm_domain *genpd) -{ - struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd); - int i; - - regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO); - udelay(20); - - /* Power Down Memories */ - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, - 0x3 << i, 0x3 << i); - udelay(5); - } - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, - 0x3 << i, 0x3 << i); - udelay(5); - } - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2, - 0x3 << i, 0x3 << i); - udelay(5); - } - for (i = 8; i < 16; i++) { - regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0, - BIT(i), BIT(i)); - udelay(5); - } - udelay(20); - - regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI); - - msleep(20); - - clk_disable_unprepare(pd->vpu_clk); - clk_disable_unprepare(pd->vapb_clk); - - return 0; -} - -static int meson_gx_pwrc_vpu_setup_clk(struct meson_gx_pwrc_vpu *pd) -{ - int ret; - - ret = clk_prepare_enable(pd->vpu_clk); - if (ret) - return ret; - - ret = clk_prepare_enable(pd->vapb_clk); - if (ret) - clk_disable_unprepare(pd->vpu_clk); - - return ret; -} - -static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd) -{ - struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd); - int ret; - int i; - - regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VPU_HDMI, 0); - udelay(20); - - /* Power Up Memories */ - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, - 0x3 << i, 0); - udelay(5); - } - - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, - 0x3 << i, 0); - udelay(5); - } - - for (i = 8; i < 16; i++) { - regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0, - BIT(i), 0); - udelay(5); - } - udelay(20); - - ret = reset_control_assert(pd->rstc); - if (ret) - return ret; - - regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VPU_HDMI_ISO, 0); - - ret = reset_control_deassert(pd->rstc); - if (ret) - return ret; - - ret = meson_gx_pwrc_vpu_setup_clk(pd); - if (ret) - return ret; - - return 0; -} - -static int meson_g12a_pwrc_vpu_power_on(struct generic_pm_domain *genpd) -{ - struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd); - int ret; - int i; - - regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VPU_HDMI, 0); - udelay(20); - - /* Power Up Memories */ - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, - 0x3 << i, 0); - udelay(5); - } - - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, - 0x3 << i, 0); - udelay(5); - } - - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2, - 0x3 << i, 0); - udelay(5); - } - - for (i = 8; i < 16; i++) { - regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0, - BIT(i), 0); - udelay(5); - } - udelay(20); - - ret = reset_control_assert(pd->rstc); - if (ret) - return ret; - - regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VPU_HDMI_ISO, 0); - - ret = reset_control_deassert(pd->rstc); - if (ret) - return ret; - - ret = meson_gx_pwrc_vpu_setup_clk(pd); - if (ret) - return ret; - - return 0; -} - -static bool meson_gx_pwrc_vpu_get_power(struct meson_gx_pwrc_vpu *pd) -{ - u32 reg; - - regmap_read(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, ®); - - return (reg & GEN_PWR_VPU_HDMI); -} - -static struct meson_gx_pwrc_vpu vpu_hdmi_pd = { - .genpd = { - .name = "vpu_hdmi", - .power_off = meson_gx_pwrc_vpu_power_off, - .power_on = meson_gx_pwrc_vpu_power_on, - }, -}; - -static struct meson_gx_pwrc_vpu vpu_hdmi_pd_g12a = { - .genpd = { - .name = "vpu_hdmi", - .power_off = meson_g12a_pwrc_vpu_power_off, - .power_on = meson_g12a_pwrc_vpu_power_on, - }, -}; - -static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev) -{ - const struct meson_gx_pwrc_vpu *vpu_pd_match; - struct regmap *regmap_ao, *regmap_hhi; - struct meson_gx_pwrc_vpu *vpu_pd; - struct device_node *parent_np; - struct reset_control *rstc; - struct clk *vpu_clk; - struct clk *vapb_clk; - bool powered_off; - int ret; - - vpu_pd_match = of_device_get_match_data(&pdev->dev); - if (!vpu_pd_match) { - dev_err(&pdev->dev, "failed to get match data\n"); - return -ENODEV; - } - - vpu_pd = devm_kzalloc(&pdev->dev, sizeof(*vpu_pd), GFP_KERNEL); - if (!vpu_pd) - return -ENOMEM; - - memcpy(vpu_pd, vpu_pd_match, sizeof(*vpu_pd)); - - parent_np = of_get_parent(pdev->dev.of_node); - regmap_ao = syscon_node_to_regmap(parent_np); - of_node_put(parent_np); - if (IS_ERR(regmap_ao)) { - dev_err(&pdev->dev, "failed to get regmap\n"); - return PTR_ERR(regmap_ao); - } - - regmap_hhi = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, - "amlogic,hhi-sysctrl"); - if (IS_ERR(regmap_hhi)) { - dev_err(&pdev->dev, "failed to get HHI regmap\n"); - return PTR_ERR(regmap_hhi); - } - - rstc = devm_reset_control_array_get_exclusive(&pdev->dev); - if (IS_ERR(rstc)) - return dev_err_probe(&pdev->dev, PTR_ERR(rstc), - "failed to get reset lines\n"); - - vpu_clk = devm_clk_get(&pdev->dev, "vpu"); - if (IS_ERR(vpu_clk)) { - dev_err(&pdev->dev, "vpu clock request failed\n"); - return PTR_ERR(vpu_clk); - } - - vapb_clk = devm_clk_get(&pdev->dev, "vapb"); - if (IS_ERR(vapb_clk)) { - dev_err(&pdev->dev, "vapb clock request failed\n"); - return PTR_ERR(vapb_clk); - } - - vpu_pd->regmap_ao = regmap_ao; - vpu_pd->regmap_hhi = regmap_hhi; - vpu_pd->rstc = rstc; - vpu_pd->vpu_clk = vpu_clk; - vpu_pd->vapb_clk = vapb_clk; - - platform_set_drvdata(pdev, vpu_pd); - - powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd); - - /* If already powered, sync the clock states */ - if (!powered_off) { - ret = meson_gx_pwrc_vpu_setup_clk(vpu_pd); - if (ret) - return ret; - } - - vpu_pd->genpd.flags = GENPD_FLAG_ALWAYS_ON; - pm_genpd_init(&vpu_pd->genpd, NULL, powered_off); - - return of_genpd_add_provider_simple(pdev->dev.of_node, - &vpu_pd->genpd); -} - -static void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev) -{ - struct meson_gx_pwrc_vpu *vpu_pd = platform_get_drvdata(pdev); - bool powered_off; - - powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd); - if (!powered_off) - vpu_pd->genpd.power_off(&vpu_pd->genpd); -} - -static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = { - { .compatible = "amlogic,meson-gx-pwrc-vpu", .data = &vpu_hdmi_pd }, - { - .compatible = "amlogic,meson-g12a-pwrc-vpu", - .data = &vpu_hdmi_pd_g12a - }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, meson_gx_pwrc_vpu_match_table); - -static struct platform_driver meson_gx_pwrc_vpu_driver = { - .probe = meson_gx_pwrc_vpu_probe, - .shutdown = meson_gx_pwrc_vpu_shutdown, - .driver = { - .name = "meson_gx_pwrc_vpu", - .of_match_table = meson_gx_pwrc_vpu_match_table, - }, -}; -module_platform_driver(meson_gx_pwrc_vpu_driver); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/pmdomain/amlogic/meson-secure-pwrc.c b/drivers/pmdomain/amlogic/meson-secure-pwrc.c index 4d5bda0d60fc..ff76ea36835e 100644 --- a/drivers/pmdomain/amlogic/meson-secure-pwrc.c +++ b/drivers/pmdomain/amlogic/meson-secure-pwrc.c @@ -14,6 +14,8 @@ #include <dt-bindings/power/amlogic,c3-pwrc.h> #include <dt-bindings/power/meson-s4-power.h> #include <dt-bindings/power/amlogic,t7-pwrc.h> +#include <dt-bindings/power/amlogic,a4-pwrc.h> +#include <dt-bindings/power/amlogic,a5-pwrc.h> #include <linux/arm-smccc.h> #include <linux/firmware/meson/meson_sm.h> #include <linux/module.h> @@ -45,7 +47,7 @@ struct meson_secure_pwrc_domain_desc { struct meson_secure_pwrc_domain_data { unsigned int count; - struct meson_secure_pwrc_domain_desc *domains; + const struct meson_secure_pwrc_domain_desc *domains; }; static bool pwrc_secure_is_off(struct meson_secure_pwrc_domain *pwrc_domain) @@ -109,7 +111,7 @@ static int meson_secure_pwrc_on(struct generic_pm_domain *domain) .parent = __parent, \ } -static struct meson_secure_pwrc_domain_desc a1_pwrc_domains[] = { +static const struct meson_secure_pwrc_domain_desc a1_pwrc_domains[] = { SEC_PD(DSPA, 0), SEC_PD(DSPB, 0), /* UART should keep working in ATF after suspend and before resume */ @@ -136,7 +138,41 @@ static struct meson_secure_pwrc_domain_desc a1_pwrc_domains[] = { SEC_PD(RSA, 0), }; -static struct meson_secure_pwrc_domain_desc c3_pwrc_domains[] = { +static const struct meson_secure_pwrc_domain_desc a4_pwrc_domains[] = { + SEC_PD(A4_AUDIO, 0), + SEC_PD(A4_SDIOA, 0), + SEC_PD(A4_EMMC, 0), + SEC_PD(A4_USB_COMB, 0), + SEC_PD(A4_ETH, 0), + SEC_PD(A4_VOUT, 0), + SEC_PD(A4_AUDIO_PDM, 0), + /* DMC is for DDR PHY ana/dig and DMC, and should be always on */ + SEC_PD(A4_DMC, GENPD_FLAG_ALWAYS_ON), + /* WRAP is secure_top, a lot of modules are included, and should be always on */ + SEC_PD(A4_SYS_WRAP, GENPD_FLAG_ALWAYS_ON), + SEC_PD(A4_AO_I2C_S, 0), + SEC_PD(A4_AO_UART, 0), + /* IR is wake up trigger source, and should be always on */ + SEC_PD(A4_AO_IR, GENPD_FLAG_ALWAYS_ON), +}; + +static const struct meson_secure_pwrc_domain_desc a5_pwrc_domains[] = { + SEC_PD(A5_NNA, 0), + SEC_PD(A5_AUDIO, 0), + SEC_PD(A5_SDIOA, 0), + SEC_PD(A5_EMMC, 0), + SEC_PD(A5_USB_COMB, 0), + SEC_PD(A5_ETH, 0), + SEC_PD(A5_RSA, 0), + SEC_PD(A5_AUDIO_PDM, 0), + /* DMC is for DDR PHY ana/dig and DMC, and should be always on */ + SEC_PD(A5_DMC, GENPD_FLAG_ALWAYS_ON), + /* WRAP is secure_top, a lot of modules are included, and should be always on */ + SEC_PD(A5_SYS_WRAP, GENPD_FLAG_ALWAYS_ON), + SEC_PD(A5_DSPA, 0), +}; + +static const struct meson_secure_pwrc_domain_desc c3_pwrc_domains[] = { SEC_PD(C3_NNA, 0), SEC_PD(C3_AUDIO, 0), SEC_PD(C3_SDIOA, 0), @@ -153,7 +189,7 @@ static struct meson_secure_pwrc_domain_desc c3_pwrc_domains[] = { SEC_PD(C3_VCODEC, 0), }; -static struct meson_secure_pwrc_domain_desc s4_pwrc_domains[] = { +static const struct meson_secure_pwrc_domain_desc s4_pwrc_domains[] = { SEC_PD(S4_DOS_HEVC, 0), SEC_PD(S4_DOS_VDEC, 0), SEC_PD(S4_VPU_HDMI, 0), @@ -165,7 +201,7 @@ static struct meson_secure_pwrc_domain_desc s4_pwrc_domains[] = { SEC_PD(S4_AUDIO, 0), }; -static struct meson_secure_pwrc_domain_desc t7_pwrc_domains[] = { +static const struct meson_secure_pwrc_domain_desc t7_pwrc_domains[] = { SEC_PD(T7_DSPA, 0), SEC_PD(T7_DSPB, 0), TOP_PD(T7_DOS_HCODEC, 0, PWRC_T7_NIC3_ID), @@ -185,7 +221,7 @@ static struct meson_secure_pwrc_domain_desc t7_pwrc_domains[] = { SEC_PD(T7_VI_CLK2, 0), /* ETH is for ethernet online wakeup, and should be always on */ SEC_PD(T7_ETH, GENPD_FLAG_ALWAYS_ON), - SEC_PD(T7_ISP, 0), + TOP_PD(T7_ISP, 0, PWRC_T7_MIPI_ISP_ID), SEC_PD(T7_MIPI_ISP, 0), TOP_PD(T7_GDC, 0, PWRC_T7_NIC3_ID), TOP_PD(T7_DEWARP, 0, PWRC_T7_NIC3_ID), @@ -311,6 +347,16 @@ static struct meson_secure_pwrc_domain_data meson_secure_a1_pwrc_data = { .count = ARRAY_SIZE(a1_pwrc_domains), }; +static struct meson_secure_pwrc_domain_data amlogic_secure_a4_pwrc_data = { + .domains = a4_pwrc_domains, + .count = ARRAY_SIZE(a4_pwrc_domains), +}; + +static struct meson_secure_pwrc_domain_data amlogic_secure_a5_pwrc_data = { + .domains = a5_pwrc_domains, + .count = ARRAY_SIZE(a5_pwrc_domains), +}; + static struct meson_secure_pwrc_domain_data amlogic_secure_c3_pwrc_data = { .domains = c3_pwrc_domains, .count = ARRAY_SIZE(c3_pwrc_domains), @@ -332,6 +378,14 @@ static const struct of_device_id meson_secure_pwrc_match_table[] = { .data = &meson_secure_a1_pwrc_data, }, { + .compatible = "amlogic,a4-pwrc", + .data = &amlogic_secure_a4_pwrc_data, + }, + { + .compatible = "amlogic,a5-pwrc", + .data = &amlogic_secure_a5_pwrc_data, + }, + { .compatible = "amlogic,c3-pwrc", .data = &amlogic_secure_c3_pwrc_data, }, @@ -355,4 +409,5 @@ static struct platform_driver meson_secure_pwrc_driver = { }, }; module_platform_driver(meson_secure_pwrc_driver); +MODULE_DESCRIPTION("Amlogic Meson Secure Power Domains driver"); MODULE_LICENSE("Dual MIT/GPL"); |