soc: amlogic: meson-gx-pwrc-vpu: fix power-off when powered by bootloader
authorNeil Armstrong <narmstrong@baylibre.com>
Fri, 3 Nov 2017 15:43:24 +0000 (16:43 +0100)
committerArnd Bergmann <arnd@arndb.de>
Thu, 9 Nov 2017 10:42:17 +0000 (11:42 +0100)
In the case the VPU power domain has been powered on by the bootloader
and no driver are attached to this power domain, the genpd will power it
off after a certain amount of time, but the clocks hasn't been enabled
by the kernel itself and the power-off will trigger some faults.
This patch enable the clocks to have a coherent state for an eventual
poweroff and switches to the pm_domain_always_on_gov governor.

Fixes: 75fcb5ca4b46 ("soc: amlogic: add Meson GX VPU Domains driver")
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Tested-by: Kevin Hilman <khilman@baylibre.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
drivers/soc/amlogic/meson-gx-pwrc-vpu.c

index bf5190b..2bdeebc 100644 (file)
@@ -34,7 +34,6 @@ struct meson_gx_pwrc_vpu {
        struct reset_control *rstc;
        struct clk *vpu_clk;
        struct clk *vapb_clk;
-       bool powered;
 };
 
 static inline
@@ -78,8 +77,6 @@ static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
        clk_disable_unprepare(pd->vpu_clk);
        clk_disable_unprepare(pd->vapb_clk);
 
-       pd->powered = false;
-
        return 0;
 }
 
@@ -91,7 +88,11 @@ static int meson_gx_pwrc_vpu_setup_clk(struct meson_gx_pwrc_vpu *pd)
        if (ret)
                return ret;
 
-       return clk_prepare_enable(pd->vapb_clk);
+       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)
@@ -139,8 +140,6 @@ static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
        if (ret)
                return ret;
 
-       pd->powered = true;
-
        return 0;
 }
 
@@ -167,6 +166,8 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
        struct reset_control *rstc;
        struct clk *vpu_clk;
        struct clk *vapb_clk;
+       bool powered_off;
+       int ret;
 
        regmap_ao = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node));
        if (IS_ERR(regmap_ao)) {
@@ -205,8 +206,17 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
        vpu_hdmi_pd.vpu_clk = vpu_clk;
        vpu_hdmi_pd.vapb_clk = vapb_clk;
 
-       pm_genpd_init(&vpu_hdmi_pd.genpd, &simple_qos_governor,
-                     meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd));
+       powered_off = meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd);
+
+       /* If already powered, sync the clock states */
+       if (!powered_off) {
+               ret = meson_gx_pwrc_vpu_setup_clk(&vpu_hdmi_pd);
+               if (ret)
+                       return ret;
+       }
+
+       pm_genpd_init(&vpu_hdmi_pd.genpd, &pm_domain_always_on_gov,
+                     powered_off);
 
        return of_genpd_add_provider_simple(pdev->dev.of_node,
                                            &vpu_hdmi_pd.genpd);
@@ -214,8 +224,7 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
 
 static void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev)
 {
-       if (vpu_hdmi_pd.powered)
-               meson_gx_pwrc_vpu_power_off(&vpu_hdmi_pd.genpd);
+       meson_gx_pwrc_vpu_power_off(&vpu_hdmi_pd.genpd);
 }
 
 static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = {