diff options
author | Olof Johansson <olof@lixom.net> | 2019-04-29 09:44:20 +0300 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2019-04-29 09:44:20 +0300 |
commit | 149d35c72a145cc6183373687007cd78d167fd19 (patch) | |
tree | c90ca58ce8de81f650c9d0cc37e3fbfd47906eb1 /drivers/soc | |
parent | 3e0c0aee4571980328b0e84dd119298b3511805e (diff) | |
parent | bb1dca3a3900a00b881286c96340d6ab85eafe0c (diff) | |
download | linux-149d35c72a145cc6183373687007cd78d167fd19.tar.xz |
Merge tag 'amlogic-drivers-2' of https://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic into arm/drivers
soc: amlogic: updates for v5.2, round 2
- VPU power domain: add supporg for G12A SoCs
- socinfo: add new SoC and package IDS.
* tag 'amlogic-drivers-2' of https://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic:
soc: amlogic: meson-gx-pwrc-vpu: Add support for G12A
soc: amlogic: meson-gx-pwrc-vpu: Fix power on/off register bitmask
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'drivers/soc')
-rw-r--r-- | drivers/soc/amlogic/meson-gx-pwrc-vpu.c | 160 |
1 files changed, 144 insertions, 16 deletions
diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c index 6289965c42e9..511b6856225d 100644 --- a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c +++ b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c @@ -11,6 +11,7 @@ #include <linux/bitfield.h> #include <linux/regmap.h> #include <linux/mfd/syscon.h> +#include <linux/of_device.h> #include <linux/reset.h> #include <linux/clk.h> @@ -26,6 +27,7 @@ #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; @@ -54,12 +56,55 @@ static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd) /* Power Down Memories */ for (i = 0; i < 32; i += 2) { regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, - 0x2 << i, 0x3 << i); + 0x3 << i, 0x3 << i); udelay(5); } for (i = 0; i < 32; i += 2) { regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, - 0x2 << i, 0x3 << i); + 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++) { @@ -108,13 +153,67 @@ static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd) /* Power Up Memories */ for (i = 0; i < 32; i += 2) { regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, - 0x2 << i, 0); + 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, - 0x2 << i, 0); + 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); } @@ -160,15 +259,37 @@ static struct meson_gx_pwrc_vpu vpu_hdmi_pd = { }, }; +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 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)); + regmap_ao = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node)); if (IS_ERR(regmap_ao)) { dev_err(&pdev->dev, "failed to get regmap\n"); @@ -201,39 +322,46 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev) return PTR_ERR(vapb_clk); } - vpu_hdmi_pd.regmap_ao = regmap_ao; - vpu_hdmi_pd.regmap_hhi = regmap_hhi; - vpu_hdmi_pd.rstc = rstc; - vpu_hdmi_pd.vpu_clk = vpu_clk; - vpu_hdmi_pd.vapb_clk = 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_hdmi_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_hdmi_pd); + ret = meson_gx_pwrc_vpu_setup_clk(vpu_pd); if (ret) return ret; } - pm_genpd_init(&vpu_hdmi_pd.genpd, &pm_domain_always_on_gov, + pm_genpd_init(&vpu_pd->genpd, &pm_domain_always_on_gov, powered_off); return of_genpd_add_provider_simple(pdev->dev.of_node, - &vpu_hdmi_pd.genpd); + &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_hdmi_pd); + powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd); if (!powered_off) - meson_gx_pwrc_vpu_power_off(&vpu_hdmi_pd.genpd); + 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" }, + { .compatible = "amlogic,meson-gx-pwrc-vpu", .data = &vpu_hdmi_pd }, + { + .compatible = "amlogic,meson-g12a-pwrc-vpu", + .data = &vpu_hdmi_pd_g12a + }, { /* sentinel */ } }; |