Message ID | 20170711182008.28298-2-robdclark@gmail.com (mailing list archive) |
---|---|
State | RFC |
Delegated to: | Stephen Boyd |
Headers | show |
Hi Rob, On 07/11/2017 11:50 PM, Rob Clark wrote: > The goal here is to support inheriting a display setup by bootloader, > although there may also be some non-display related use-cases. > > Rough idea is to add a flag for clks and power domains that might > already be enabled when kernel starts, and make corresponding fixups > to clk enable/prepare_count and power-domain state so that these are > not automatically disabled late in boot. > > If bootloader is enabling display, and kernel is using efifb before > real display driver is loaded (potentially from kernel module after > userspace starts, in a typical distro kernel), we don't want to kill > the clocks and power domains that are used by the display before > userspace starts. > > Second part is for drm/msm to check if display related clocks are > enabled when it is loaded, and if so read back hw state to sync > existing display state w/ software state, and skip the initial > clk_enable's and otherwise fixing up clk/regulator/etc ref counts > (skipping the normal display-enable codepaths), therefore inheriting > the enable done by bootloader. > > Obviously this should be split up into multiple patches and many > TODOs addressed. But I guess this is enough for now to start > discussing the approach, and in particular how drm and clock/pd > drivers work together to handle handover from bootloader. > > The CLK_INHERIT_BOOTLOADER and related gsdc flag should only be set > on leaf nodes. > --- [].. > diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c > index d523991c945f..90b698c910d0 100644 > --- a/drivers/clk/qcom/common.c > +++ b/drivers/clk/qcom/common.c > @@ -11,6 +11,7 @@ > * GNU General Public License for more details. > */ > > +#include <linux/clk.h> > #include <linux/export.h> > #include <linux/module.h> > #include <linux/regmap.h> > @@ -258,6 +259,33 @@ int qcom_cc_really_probe(struct platform_device *pdev, > if (ret) > return ret; > > + /* Check which of clocks that we inherit state from bootloader > + * are enabled, and fixup enable/prepare state (as well as that > + * of it's parents). > + * > + * TODO can we assume that parents coming from another clk > + * driver are already registered? > + */ > + for (i = 0; i < num_clks; i++) { > + struct clk_hw *hw; > + > + if (!rclks[i]) > + continue; > + > + hw = &rclks[i]->hw; > + > + if (!(hw->init->flags & CLK_INHERIT_BOOTLOADER)) > + continue; > + > + if (!clk_is_enabled_regmap(hw)) > + continue; > + > + dev_dbg(dev, "%s is enabled from bootloader!\n", > + hw->init->name); > + > + clk_inherit_enabled(hw->clk); how about just calling a clk_prepare_enable(hw->clk) instead of adding a new API? The flag could also be something qcom specific and then we avoid having to add anything in generic CCF code and its all handled in the qcom clock drivers. > + } > + > reset = &cc->reset; > reset->rcdev.of_node = dev->of_node; > reset->rcdev.ops = &qcom_reset_ops; [] .. > diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c > index a4f3580587b7..440d819b2d9d 100644 > --- a/drivers/clk/qcom/gdsc.c > +++ b/drivers/clk/qcom/gdsc.c > @@ -291,6 +291,12 @@ static int gdsc_init(struct gdsc *sc) > if ((sc->flags & VOTABLE) && on) > gdsc_enable(&sc->pd); > > + if ((sc->flags & INHERIT_BL) && on) { > + pr_debug("gdsc: %s is enabled from bootloader!\n", sc->pd.name); > + gdsc_enable(&sc->pd); > + sc->pd.flags |= GENPD_FLAG_ALWAYS_ON; Would this not prevent the powerdomain from ever getting disabled? regards, Rajendra > + } > + > if (on || (sc->pwrsts & PWRSTS_RET)) > gdsc_force_mem_on(sc); > else > diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h > index 39648348e5ec..3b5e64b060c2 100644 > --- a/drivers/clk/qcom/gdsc.h > +++ b/drivers/clk/qcom/gdsc.h > @@ -53,6 +53,7 @@ struct gdsc { > #define VOTABLE BIT(0) > #define CLAMP_IO BIT(1) > #define HW_CTRL BIT(2) > +#define INHERIT_BL BIT(3) > struct reset_controller_dev *rcdev; > unsigned int *resets; > unsigned int reset_count; > diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h > index c59c62571e4f..4d5505f92329 100644 > --- a/include/linux/clk-provider.h > +++ b/include/linux/clk-provider.h > @@ -35,6 +35,7 @@ > #define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */ > /* parents need enable during gate/ungate, set rate and re-parent */ > #define CLK_OPS_PARENT_ENABLE BIT(12) > +#define CLK_INHERIT_BOOTLOADER BIT(13) /* clk may be enabled from bootloader */ > > struct clk; > struct clk_hw; > diff --git a/include/linux/clk.h b/include/linux/clk.h > index 91bd464f4c9b..461991fc57e2 100644 > --- a/include/linux/clk.h > +++ b/include/linux/clk.h > @@ -391,6 +391,15 @@ void clk_disable(struct clk *clk); > void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks); > > /** > + * clk_inherit_enabled - update the enable/prepare count of a clock and it's > + * parents for clock enabled by bootloader. > + * > + * Intended to be used by clock drivers to inform the clk core of a clock > + * that is already running. > + */ > +void clk_inherit_enabled(struct clk *clk); > + > +/** > * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. > * This is only valid once the clock source has been enabled. > * @clk: clock source >
On Fri, Jul 14, 2017 at 12:52 AM, Rajendra Nayak <rnayak@codeaurora.org> wrote: > Hi Rob, > > On 07/11/2017 11:50 PM, Rob Clark wrote: >> The goal here is to support inheriting a display setup by bootloader, >> although there may also be some non-display related use-cases. >> >> Rough idea is to add a flag for clks and power domains that might >> already be enabled when kernel starts, and make corresponding fixups >> to clk enable/prepare_count and power-domain state so that these are >> not automatically disabled late in boot. >> >> If bootloader is enabling display, and kernel is using efifb before >> real display driver is loaded (potentially from kernel module after >> userspace starts, in a typical distro kernel), we don't want to kill >> the clocks and power domains that are used by the display before >> userspace starts. >> >> Second part is for drm/msm to check if display related clocks are >> enabled when it is loaded, and if so read back hw state to sync >> existing display state w/ software state, and skip the initial >> clk_enable's and otherwise fixing up clk/regulator/etc ref counts >> (skipping the normal display-enable codepaths), therefore inheriting >> the enable done by bootloader. >> >> Obviously this should be split up into multiple patches and many >> TODOs addressed. But I guess this is enough for now to start >> discussing the approach, and in particular how drm and clock/pd >> drivers work together to handle handover from bootloader. >> >> The CLK_INHERIT_BOOTLOADER and related gsdc flag should only be set >> on leaf nodes. >> --- > > [].. > >> diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c >> index d523991c945f..90b698c910d0 100644 >> --- a/drivers/clk/qcom/common.c >> +++ b/drivers/clk/qcom/common.c >> @@ -11,6 +11,7 @@ >> * GNU General Public License for more details. >> */ >> >> +#include <linux/clk.h> >> #include <linux/export.h> >> #include <linux/module.h> >> #include <linux/regmap.h> >> @@ -258,6 +259,33 @@ int qcom_cc_really_probe(struct platform_device *pdev, >> if (ret) >> return ret; >> >> + /* Check which of clocks that we inherit state from bootloader >> + * are enabled, and fixup enable/prepare state (as well as that >> + * of it's parents). >> + * >> + * TODO can we assume that parents coming from another clk >> + * driver are already registered? >> + */ >> + for (i = 0; i < num_clks; i++) { >> + struct clk_hw *hw; >> + >> + if (!rclks[i]) >> + continue; >> + >> + hw = &rclks[i]->hw; >> + >> + if (!(hw->init->flags & CLK_INHERIT_BOOTLOADER)) >> + continue; >> + >> + if (!clk_is_enabled_regmap(hw)) >> + continue; >> + >> + dev_dbg(dev, "%s is enabled from bootloader!\n", >> + hw->init->name); >> + >> + clk_inherit_enabled(hw->clk); > > how about just calling a clk_prepare_enable(hw->clk) instead of adding a new API? > The flag could also be something qcom specific and then we avoid having to add > anything in generic CCF code and its all handled in the qcom clock drivers. Hmm, I could try that.. I *guess* it doesn't hurt to enable an already enabled clk.. beyond that, I wonder if this is something that other platforms would want, so maybe I should be doing the check for enabled in CCF core? If not, making this a qcom specific flag makes sense. >> + } >> + >> reset = &cc->reset; >> reset->rcdev.of_node = dev->of_node; >> reset->rcdev.ops = &qcom_reset_ops; > > [] .. > >> diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c >> index a4f3580587b7..440d819b2d9d 100644 >> --- a/drivers/clk/qcom/gdsc.c >> +++ b/drivers/clk/qcom/gdsc.c >> @@ -291,6 +291,12 @@ static int gdsc_init(struct gdsc *sc) >> if ((sc->flags & VOTABLE) && on) >> gdsc_enable(&sc->pd); >> >> + if ((sc->flags & INHERIT_BL) && on) { >> + pr_debug("gdsc: %s is enabled from bootloader!\n", sc->pd.name); >> + gdsc_enable(&sc->pd); >> + sc->pd.flags |= GENPD_FLAG_ALWAYS_ON; > > Would this not prevent the powerdomain from ever getting disabled? Yeah, this is a hack, because I couldn't figure out something better. The problem is that gdsc/powerdomain doesn't have it's own enable_count but this is tracked at the device level (afaict.. maybe I'm miss-understanding something). I guess we could add our own enable_count within gdsc? Suggestions welcome, since I don't know these parts of the code so well. BR, -R > regards, > Rajendra > >> + } >> + >> if (on || (sc->pwrsts & PWRSTS_RET)) >> gdsc_force_mem_on(sc); >> else >> diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h >> index 39648348e5ec..3b5e64b060c2 100644 >> --- a/drivers/clk/qcom/gdsc.h >> +++ b/drivers/clk/qcom/gdsc.h >> @@ -53,6 +53,7 @@ struct gdsc { >> #define VOTABLE BIT(0) >> #define CLAMP_IO BIT(1) >> #define HW_CTRL BIT(2) >> +#define INHERIT_BL BIT(3) >> struct reset_controller_dev *rcdev; >> unsigned int *resets; >> unsigned int reset_count; >> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h >> index c59c62571e4f..4d5505f92329 100644 >> --- a/include/linux/clk-provider.h >> +++ b/include/linux/clk-provider.h >> @@ -35,6 +35,7 @@ >> #define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */ >> /* parents need enable during gate/ungate, set rate and re-parent */ >> #define CLK_OPS_PARENT_ENABLE BIT(12) >> +#define CLK_INHERIT_BOOTLOADER BIT(13) /* clk may be enabled from bootloader */ >> >> struct clk; >> struct clk_hw; >> diff --git a/include/linux/clk.h b/include/linux/clk.h >> index 91bd464f4c9b..461991fc57e2 100644 >> --- a/include/linux/clk.h >> +++ b/include/linux/clk.h >> @@ -391,6 +391,15 @@ void clk_disable(struct clk *clk); >> void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks); >> >> /** >> + * clk_inherit_enabled - update the enable/prepare count of a clock and it's >> + * parents for clock enabled by bootloader. >> + * >> + * Intended to be used by clock drivers to inform the clk core of a clock >> + * that is already running. >> + */ >> +void clk_inherit_enabled(struct clk *clk); >> + >> +/** >> * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. >> * This is only valid once the clock source has been enabled. >> * @clk: clock source >> > > -- > Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, > hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-clk" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 7/14/2017 4:13 PM, Rob Clark wrote: > On Fri, Jul 14, 2017 at 12:52 AM, Rajendra Nayak <rnayak@codeaurora.org> wrote: >> Hi Rob, >> >> On 07/11/2017 11:50 PM, Rob Clark wrote: >>> The goal here is to support inheriting a display setup by bootloader, >>> although there may also be some non-display related use-cases. >>> >>> Rough idea is to add a flag for clks and power domains that might >>> already be enabled when kernel starts, and make corresponding fixups >>> to clk enable/prepare_count and power-domain state so that these are >>> not automatically disabled late in boot. >>> >>> If bootloader is enabling display, and kernel is using efifb before >>> real display driver is loaded (potentially from kernel module after >>> userspace starts, in a typical distro kernel), we don't want to kill >>> the clocks and power domains that are used by the display before >>> userspace starts. >>> >>> Second part is for drm/msm to check if display related clocks are >>> enabled when it is loaded, and if so read back hw state to sync >>> existing display state w/ software state, and skip the initial >>> clk_enable's and otherwise fixing up clk/regulator/etc ref counts >>> (skipping the normal display-enable codepaths), therefore inheriting >>> the enable done by bootloader. >>> >>> Obviously this should be split up into multiple patches and many >>> TODOs addressed. But I guess this is enough for now to start >>> discussing the approach, and in particular how drm and clock/pd >>> drivers work together to handle handover from bootloader. >>> >>> The CLK_INHERIT_BOOTLOADER and related gsdc flag should only be set >>> on leaf nodes. >>> --- >> >> [].. >> >>> diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c >>> index d523991c945f..90b698c910d0 100644 >>> --- a/drivers/clk/qcom/common.c >>> +++ b/drivers/clk/qcom/common.c >>> @@ -11,6 +11,7 @@ >>> * GNU General Public License for more details. >>> */ >>> >>> +#include <linux/clk.h> >>> #include <linux/export.h> >>> #include <linux/module.h> >>> #include <linux/regmap.h> >>> @@ -258,6 +259,33 @@ int qcom_cc_really_probe(struct platform_device *pdev, >>> if (ret) >>> return ret; >>> >>> + /* Check which of clocks that we inherit state from bootloader >>> + * are enabled, and fixup enable/prepare state (as well as that >>> + * of it's parents). >>> + * >>> + * TODO can we assume that parents coming from another clk >>> + * driver are already registered? >>> + */ >>> + for (i = 0; i < num_clks; i++) { >>> + struct clk_hw *hw; >>> + >>> + if (!rclks[i]) >>> + continue; >>> + >>> + hw = &rclks[i]->hw; >>> + >>> + if (!(hw->init->flags & CLK_INHERIT_BOOTLOADER)) >>> + continue; >>> + >>> + if (!clk_is_enabled_regmap(hw)) >>> + continue; >>> + >>> + dev_dbg(dev, "%s is enabled from bootloader!\n", >>> + hw->init->name); >>> + >>> + clk_inherit_enabled(hw->clk); >> >> how about just calling a clk_prepare_enable(hw->clk) instead of adding a new API? >> The flag could also be something qcom specific and then we avoid having to add >> anything in generic CCF code and its all handled in the qcom clock drivers. > > Hmm, I could try that.. I *guess* it doesn't hurt to enable an > already enabled clk.. yes, ideally it shouldn't hurt. > > beyond that, I wonder if this is something that other platforms would > want, so maybe I should be doing the check for enabled in CCF core? > If not, making this a qcom specific flag makes sense. I think most previous attempts to solve this were done trying to keep it very generic and they didn't go too far. So I was thinking maybe we could deal with it within qcom drivers for now, and if others come up with something similar, then look to consolidate at a generic CCF level. > >>> + } >>> + >>> reset = &cc->reset; >>> reset->rcdev.of_node = dev->of_node; >>> reset->rcdev.ops = &qcom_reset_ops; >> >> [] .. >> >>> diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c >>> index a4f3580587b7..440d819b2d9d 100644 >>> --- a/drivers/clk/qcom/gdsc.c >>> +++ b/drivers/clk/qcom/gdsc.c >>> @@ -291,6 +291,12 @@ static int gdsc_init(struct gdsc *sc) >>> if ((sc->flags & VOTABLE) && on) >>> gdsc_enable(&sc->pd); >>> >>> + if ((sc->flags & INHERIT_BL) && on) { >>> + pr_debug("gdsc: %s is enabled from bootloader!\n", sc->pd.name); >>> + gdsc_enable(&sc->pd); >>> + sc->pd.flags |= GENPD_FLAG_ALWAYS_ON; >> >> Would this not prevent the powerdomain from ever getting disabled? > > Yeah, this is a hack, because I couldn't figure out something better. > The problem is that gdsc/powerdomain doesn't have it's own > enable_count but this is tracked at the device level (afaict.. maybe > I'm miss-understanding something). I guess we could add our own > enable_count within gdsc? Suggestions welcome, since I don't know > these parts of the code so well. One way to deal with it would be to tell the genpd core, that the gdsc isn't really enabled, so it does not go ahead and disable it thinking its unused. Once the display driver comes up, it runtime enables/disables it. I am guessing, if the bootloader turns on the gdsc, there will also be a kernel driver to handle it. So I am basically saying, if ((sc->flags & INHERIT_BL) && on) on = !on; /* Prevent genpd from thinking its unsued */ > -- > To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- To unsubscribe from this list: send the line "unsubscribe linux-clk" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 07/17, Nayak, Rajendra wrote: > > > On 7/14/2017 4:13 PM, Rob Clark wrote: > >On Fri, Jul 14, 2017 at 12:52 AM, Rajendra Nayak <rnayak@codeaurora.org> wrote: > >>Hi Rob, > >> > >>On 07/11/2017 11:50 PM, Rob Clark wrote: > >> > >>>diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c > >>>index d523991c945f..90b698c910d0 100644 > >>>--- a/drivers/clk/qcom/common.c > >>>+++ b/drivers/clk/qcom/common.c > >>>@@ -11,6 +11,7 @@ > >>> * GNU General Public License for more details. > >>> */ > >>> > >>>+#include <linux/clk.h> > >>> #include <linux/export.h> > >>> #include <linux/module.h> > >>> #include <linux/regmap.h> > >>>@@ -258,6 +259,33 @@ int qcom_cc_really_probe(struct platform_device *pdev, > >>> if (ret) > >>> return ret; > >>> > >>>+ /* Check which of clocks that we inherit state from bootloader > >>>+ * are enabled, and fixup enable/prepare state (as well as that > >>>+ * of it's parents). > >>>+ * > >>>+ * TODO can we assume that parents coming from another clk > >>>+ * driver are already registered? > >>>+ */ > >>>+ for (i = 0; i < num_clks; i++) { > >>>+ struct clk_hw *hw; > >>>+ > >>>+ if (!rclks[i]) > >>>+ continue; > >>>+ > >>>+ hw = &rclks[i]->hw; > >>>+ > >>>+ if (!(hw->init->flags & CLK_INHERIT_BOOTLOADER)) > >>>+ continue; > >>>+ > >>>+ if (!clk_is_enabled_regmap(hw)) > >>>+ continue; > >>>+ > >>>+ dev_dbg(dev, "%s is enabled from bootloader!\n", > >>>+ hw->init->name); > >>>+ > >>>+ clk_inherit_enabled(hw->clk); > >> > >>how about just calling a clk_prepare_enable(hw->clk) instead of adding a new API? > >>The flag could also be something qcom specific and then we avoid having to add > >>anything in generic CCF code and its all handled in the qcom clock drivers. > > > >Hmm, I could try that.. I *guess* it doesn't hurt to enable an > >already enabled clk.. > > yes, ideally it shouldn't hurt. It hurts when you enable a PLL when it's already enabled. I recall having to add code specifically for this reason to avoid enabling a PLL that is already enabled out of the bootloader. But that's because the enable sequence for a PLL is multiple writes that first keep the output off and then turn it back on after things stabilize. For RCGs this isn't the case. > > > > >beyond that, I wonder if this is something that other platforms would > >want, so maybe I should be doing the check for enabled in CCF core? > >If not, making this a qcom specific flag makes sense. > > I think most previous attempts to solve this were done trying to keep > it very generic and they didn't go too far. > So I was thinking maybe we could deal with it within qcom drivers for > now, and if others come up with something similar, then look to > consolidate at a generic CCF level. We know that other SoC vendors need handoff features as well, so there will definitely be a point where we need to consolidate at the framework level. Working something up that works for qcom would be good to try out though to find edge cases, etc.
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index fc58c52a26b4..7c84e8d6e816 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -796,6 +796,24 @@ static void clk_disable_unused_subtree(struct clk_core *core) clk_core_disable_unprepare(core->parent); } +/* clock and it's parents are already prepared/enabled from bootloader, + * so simply record the fact. + */ +static void __clk_inherit_enabled(struct clk_core *core) +{ + core->enable_count++; + core->prepare_count++; +if (core->hw->init->name) // XXX hack.. something funny with xo/xo_board.. + if (core->parent) + __clk_inherit_enabled(core->parent); +} + +void clk_inherit_enabled(struct clk *clk) +{ + __clk_inherit_enabled(clk->core); +} +EXPORT_SYMBOL_GPL(clk_inherit_enabled); + static bool clk_ignore_unused; static int __init clk_ignore_unused_setup(char *__unused) { diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index d523991c945f..90b698c910d0 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -11,6 +11,7 @@ * GNU General Public License for more details. */ +#include <linux/clk.h> #include <linux/export.h> #include <linux/module.h> #include <linux/regmap.h> @@ -258,6 +259,33 @@ int qcom_cc_really_probe(struct platform_device *pdev, if (ret) return ret; + /* Check which of clocks that we inherit state from bootloader + * are enabled, and fixup enable/prepare state (as well as that + * of it's parents). + * + * TODO can we assume that parents coming from another clk + * driver are already registered? + */ + for (i = 0; i < num_clks; i++) { + struct clk_hw *hw; + + if (!rclks[i]) + continue; + + hw = &rclks[i]->hw; + + if (!(hw->init->flags & CLK_INHERIT_BOOTLOADER)) + continue; + + if (!clk_is_enabled_regmap(hw)) + continue; + + dev_dbg(dev, "%s is enabled from bootloader!\n", + hw->init->name); + + clk_inherit_enabled(hw->clk); + } + reset = &cc->reset; reset->rcdev.of_node = dev->of_node; reset->rcdev.ops = &qcom_reset_ops; diff --git a/drivers/clk/qcom/gcc-msm8916.c b/drivers/clk/qcom/gcc-msm8916.c index 2cfe7000fc60..c939d33f6377 100644 --- a/drivers/clk/qcom/gcc-msm8916.c +++ b/drivers/clk/qcom/gcc-msm8916.c @@ -2468,7 +2468,7 @@ static struct clk_branch gcc_mdss_ahb_clk = { "pcnoc_bfdcd_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_INHERIT_BOOTLOADER, .ops = &clk_branch2_ops, }, }, @@ -2485,7 +2485,7 @@ static struct clk_branch gcc_mdss_axi_clk = { "system_noc_bfdcd_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_INHERIT_BOOTLOADER, .ops = &clk_branch2_ops, }, }, @@ -2502,7 +2502,7 @@ static struct clk_branch gcc_mdss_byte0_clk = { "byte0_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_INHERIT_BOOTLOADER, .ops = &clk_branch2_ops, }, }, @@ -2519,7 +2519,7 @@ static struct clk_branch gcc_mdss_esc0_clk = { "esc0_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_INHERIT_BOOTLOADER, .ops = &clk_branch2_ops, }, }, @@ -2536,7 +2536,7 @@ static struct clk_branch gcc_mdss_mdp_clk = { "mdp_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_INHERIT_BOOTLOADER, .ops = &clk_branch2_ops, }, }, @@ -2553,7 +2553,7 @@ static struct clk_branch gcc_mdss_pclk0_clk = { "pclk0_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_INHERIT_BOOTLOADER, .ops = &clk_branch2_ops, }, }, @@ -2570,7 +2570,7 @@ static struct clk_branch gcc_mdss_vsync_clk = { "vsync_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_INHERIT_BOOTLOADER, .ops = &clk_branch2_ops, }, }, @@ -3060,6 +3060,7 @@ static struct gdsc mdss_gdsc = { .name = "mdss", }, .pwrsts = PWRSTS_OFF_ON, + .flags = INHERIT_BL, }; static struct gdsc jpeg_gdsc = { diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c index a4f3580587b7..440d819b2d9d 100644 --- a/drivers/clk/qcom/gdsc.c +++ b/drivers/clk/qcom/gdsc.c @@ -291,6 +291,12 @@ static int gdsc_init(struct gdsc *sc) if ((sc->flags & VOTABLE) && on) gdsc_enable(&sc->pd); + if ((sc->flags & INHERIT_BL) && on) { + pr_debug("gdsc: %s is enabled from bootloader!\n", sc->pd.name); + gdsc_enable(&sc->pd); + sc->pd.flags |= GENPD_FLAG_ALWAYS_ON; + } + if (on || (sc->pwrsts & PWRSTS_RET)) gdsc_force_mem_on(sc); else diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h index 39648348e5ec..3b5e64b060c2 100644 --- a/drivers/clk/qcom/gdsc.h +++ b/drivers/clk/qcom/gdsc.h @@ -53,6 +53,7 @@ struct gdsc { #define VOTABLE BIT(0) #define CLAMP_IO BIT(1) #define HW_CTRL BIT(2) +#define INHERIT_BL BIT(3) struct reset_controller_dev *rcdev; unsigned int *resets; unsigned int reset_count; diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index c59c62571e4f..4d5505f92329 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -35,6 +35,7 @@ #define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */ /* parents need enable during gate/ungate, set rate and re-parent */ #define CLK_OPS_PARENT_ENABLE BIT(12) +#define CLK_INHERIT_BOOTLOADER BIT(13) /* clk may be enabled from bootloader */ struct clk; struct clk_hw; diff --git a/include/linux/clk.h b/include/linux/clk.h index 91bd464f4c9b..461991fc57e2 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -391,6 +391,15 @@ void clk_disable(struct clk *clk); void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks); /** + * clk_inherit_enabled - update the enable/prepare count of a clock and it's + * parents for clock enabled by bootloader. + * + * Intended to be used by clock drivers to inform the clk core of a clock + * that is already running. + */ +void clk_inherit_enabled(struct clk *clk); + +/** * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. * This is only valid once the clock source has been enabled. * @clk: clock source