* [PATCH v3 0/4] Add QCOM graphics clock controller driver for SDM845 @ 2018-08-13 6:33 Amit Nischal 2018-08-13 6:33 ` [PATCH v3 1/4] clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC Amit Nischal ` (4 more replies) 0 siblings, 5 replies; 12+ messages in thread From: Amit Nischal @ 2018-08-13 6:33 UTC (permalink / raw) To: Stephen Boyd, Michael Turquette Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, Taniya Das, linux-arm-msm, linux-soc, linux-clk, linux-kernel, Amit Nischal Changes in v3: * Modified the determine_rate() op to use the min/max rate range to round the requested rate within the set_rate range. With this, requested set rate will always stay within the limits. Changes in v2: Addressed review comments given by Stephen: https://lkml.org/lkml/2018/6/6/294 * Introduce clk_rcg2_gfx3d_determine_rate ops to return the best parent as 'gpucc_pll0_even' and best parent rate as twice of the requested rate always. This will eliminate the need of frequency table as source and div-2 are fixed for gfx3d_clk_src. Also modified the clk_rcg2_set_rate ops to configure the fixed source and div. * Add support to check if requested rate falls within allowed set_rate range. This will not let the source gpucc_pll0 to go out of the supported range and also client can request the rate within the range. * Fixed comment text in probe function and added module description for GPUCC driver. The graphics clock driver depends upon the below change. https://lkml.org/lkml/2018/6/23/108 Changes in v1: This patch series adds support for graphics clock controller for SDM845. Below is the brief description for each change: 1. For some of the GDSCs, there is requirement to enable/disable the few clocks before turning on/off the gdsc power domain. This patch will add support to enable/disable the clock associated with the gdsc along with power domain on/off callbacks. 2. To turn on the gpu_gx_gdsc, there is a hardware requirement to turn on the root clock (GFX3D RCG) first which would be the turn on signal for the gdsc along with the SW_COLLAPSE. As per the current implementation of clk_rcg2_shared_ops, it clears the root_enable bit in the enable() clock ops. But due to the above said requirement for GFX3D shared RCG, root_enable bit would be already set by gdsc driver and rcg2_shared_ops should not clear the root unless the disable() is called. This patch add support for the same by reusing the existing clk_rcg2_shared_ops and deriving "clk_rcg2_gfx3d_ops" clk_ops for GFX3D clock to take care of the root set/clear requirement. 3. Add device tree bindings for graphics clock controller for SDM845. 4. Add graphics clock controller (GPUCC) driver for SDM845. [v1] : https://lore.kernel.org/patchwork/project/lkml/list/?series=348697 [v2] : https://lore.kernel.org/patchwork/project/lkml/list/?series=359012 Amit Nischal (4): clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC clk: qcom: Add clk_rcg2_gfx3d_ops for SDM845 dt-bindings: clock: Introduce QCOM Graphics clock bindings clk: qcom: Add graphics clock controller driver for SDM845 .../devicetree/bindings/clock/qcom,gpucc.txt | 18 + drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clk-rcg.h | 1 + drivers/clk/qcom/clk-rcg2.c | 86 +++- drivers/clk/qcom/gdsc.c | 44 +++ drivers/clk/qcom/gdsc.h | 5 + drivers/clk/qcom/gpucc-sdm845.c | 438 +++++++++++++++++++++ include/dt-bindings/clock/qcom,gpucc-sdm845.h | 38 ++ 9 files changed, 638 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/qcom,gpucc.txt create mode 100644 drivers/clk/qcom/gpucc-sdm845.c create mode 100644 include/dt-bindings/clock/qcom,gpucc-sdm845.h -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 1/4] clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC 2018-08-13 6:33 [PATCH v3 0/4] Add QCOM graphics clock controller driver for SDM845 Amit Nischal @ 2018-08-13 6:33 ` Amit Nischal 2018-11-05 6:34 ` Stephen Boyd 2018-08-13 6:33 ` [PATCH v3 2/4] clk: qcom: Add clk_rcg2_gfx3d_ops for SDM845 Amit Nischal ` (3 subsequent siblings) 4 siblings, 1 reply; 12+ messages in thread From: Amit Nischal @ 2018-08-13 6:33 UTC (permalink / raw) To: Stephen Boyd, Michael Turquette Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, Taniya Das, linux-arm-msm, linux-soc, linux-clk, linux-kernel, Amit Nischal For some of the GDSCs, there is a requirement to enable/disable the few clocks before turning on/off the gdsc power domain. Add support for the same by specifying a list of clk_hw pointers per gdsc and enable/disable them along with power domain on/off callbacks. Signed-off-by: Amit Nischal <anischal@codeaurora.org> --- drivers/clk/qcom/gdsc.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ drivers/clk/qcom/gdsc.h | 5 +++++ 2 files changed, 49 insertions(+) diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c index a077133..b6adca1 100644 --- a/drivers/clk/qcom/gdsc.c +++ b/drivers/clk/qcom/gdsc.c @@ -12,6 +12,8 @@ */ #include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/jiffies.h> @@ -208,11 +210,41 @@ static inline void gdsc_assert_reset_aon(struct gdsc *sc) regmap_update_bits(sc->regmap, sc->clamp_io_ctrl, GMEM_RESET_MASK, 0); } + +static int gdsc_clk_prepare_enable(struct gdsc *sc) +{ + int i, ret; + + for (i = 0; i < sc->clk_count; i++) { + ret = clk_prepare_enable(sc->clk_hws[i]->clk); + if (ret) { + for (i--; i >= 0; i--) + clk_disable_unprepare(sc->clk_hws[i]->clk); + return ret; + } + } + return 0; +} + +static void gdsc_clk_disable_unprepare(struct gdsc *sc) +{ + int i; + + for (i = 0; i < sc->clk_count; i++) + clk_disable_unprepare(sc->clk_hws[i]->clk); +} + static int gdsc_enable(struct generic_pm_domain *domain) { struct gdsc *sc = domain_to_gdsc(domain); int ret; + if (sc->clk_count) { + ret = gdsc_clk_prepare_enable(sc); + if (ret) + return ret; + } + if (sc->pwrsts == PWRSTS_ON) return gdsc_deassert_reset(sc); @@ -260,6 +292,9 @@ static int gdsc_enable(struct generic_pm_domain *domain) udelay(1); } + if (sc->clk_count) + gdsc_clk_disable_unprepare(sc); + return 0; } @@ -268,6 +303,12 @@ static int gdsc_disable(struct generic_pm_domain *domain) struct gdsc *sc = domain_to_gdsc(domain); int ret; + if (sc->clk_count) { + ret = gdsc_clk_prepare_enable(sc); + if (ret) + return ret; + } + if (sc->pwrsts == PWRSTS_ON) return gdsc_assert_reset(sc); @@ -299,6 +340,9 @@ static int gdsc_disable(struct generic_pm_domain *domain) if (sc->flags & CLAMP_IO) gdsc_assert_clamp_io(sc); + if (sc->clk_count) + gdsc_clk_disable_unprepare(sc); + return 0; } diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h index bd1f2c7..59957d7 100644 --- a/drivers/clk/qcom/gdsc.h +++ b/drivers/clk/qcom/gdsc.h @@ -17,6 +17,7 @@ #include <linux/err.h> #include <linux/pm_domain.h> +struct clk_hw; struct regmap; struct reset_controller_dev; @@ -32,6 +33,8 @@ * @resets: ids of resets associated with this gdsc * @reset_count: number of @resets * @rcdev: reset controller + * @clk_count: number of associated clocks + * @clk_hws: clk_hw pointers for associated clocks with gdsc */ struct gdsc { struct generic_pm_domain pd; @@ -60,6 +63,8 @@ struct gdsc { struct reset_controller_dev *rcdev; unsigned int *resets; unsigned int reset_count; + unsigned int clk_count; + struct clk_hw *clk_hws[]; }; struct gdsc_desc { -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v3 1/4] clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC 2018-08-13 6:33 ` [PATCH v3 1/4] clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC Amit Nischal @ 2018-11-05 6:34 ` Stephen Boyd 2018-11-19 11:21 ` Taniya Das 0 siblings, 1 reply; 12+ messages in thread From: Stephen Boyd @ 2018-11-05 6:34 UTC (permalink / raw) To: Amit Nischal, Michael Turquette Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, Taniya Das, linux-arm-msm, linux-soc, linux-clk, linux-kernel, Amit Nischal, Jordan Crouse Quoting Amit Nischal (2018-08-12 23:33:04) > For some of the GDSCs, there is a requirement to enable/disable the > few clocks before turning on/off the gdsc power domain. Add support > for the same by specifying a list of clk_hw pointers per gdsc and > enable/disable them along with power domain on/off callbacks. > > Signed-off-by: Amit Nischal <anischal@codeaurora.org> In v1 of this patch series I asked for much more information in this commit text. Please add it here. I won't apply this patch until the justification is put into this commit text. > --- > drivers/clk/qcom/gdsc.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ > drivers/clk/qcom/gdsc.h | 5 +++++ > 2 files changed, 49 insertions(+) > > diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c > index a077133..b6adca1 100644 > --- a/drivers/clk/qcom/gdsc.c > +++ b/drivers/clk/qcom/gdsc.c > @@ -12,6 +12,8 @@ > */ > > #include <linux/bitops.h> > +#include <linux/clk.h> > +#include <linux/clk-provider.h> This makes me unhappy. It's almost always a problem when we see clk.h and clk-provider.h included in the same file, so if gdsc has to call clk APIs to operate correctly, then we should do that by having the gdsc code get clks properly instead of directly reaching into the clk_hw structure to get a clk pointer. This means we should have the gdsc code ask the clk framework to convert a clk_hw pointer into a clk pointer because of how so intimately connected the gdsc is to clks on this SoC. But given all that, I'm still trying to understand why we need to do this within the gdsc code. Adding these clk calls to the gdsc seems like we're attaching at the wrong abstraction level. Especially if the reason we do it is to make it easier for the GPU driver to handle dependencies. I hope that's not the case. Either way, it would make more sense to me if we made genpds for the clks and genpds for the gdscs and then associated the clk genpds with the gdsc genpds so that when a gdsc is enabled the clk domain that it depends on is enabled first. Then we have a generic solution for connecting clks to gdscs that doesn't require us to add more logic to the gdsc driver and avoids having clk providers do clk consumer things. Instead, it's all handled outside of this driver by specifying a domain dependency. It may turn out that such a solution would still need a way to make clk domains in the clk driver, and it will probably need to do that by converting clk_hw structures into clk pointers, but it would be good to do that anyway. So in summary, I believe we should end up at a point where we have clk domains and power domains (gdscs) all supported with genpds, and then we can connect them together however they're connected by linking the genpds to each other. Device drivers wouldn't really need to care how they're connected, as long as those genpds are attached to their device then the driver would be able to enable/disable them through runtime PM. But I can see how this may be hard to do for this patch series, so in the spirit of progress and getting things done, it would be OK with me if the gdsc code called some new clk API to convert a clk_hw pointer into a clk pointer and then did the same enable/disable things it's doing in this patch. This whole patch would need to be completely untangled and ripped out later when we have clk domains but at least we could get something working now while we work on making clk domains and plumbing them into genpds and runtime PM. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 1/4] clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC 2018-11-05 6:34 ` Stephen Boyd @ 2018-11-19 11:21 ` Taniya Das 0 siblings, 0 replies; 12+ messages in thread From: Taniya Das @ 2018-11-19 11:21 UTC (permalink / raw) To: Stephen Boyd, Michael Turquette Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, linux-arm-msm, linux-soc, linux-clk, linux-kernel, Jordan Crouse Hello Stephen, On 11/5/2018 12:04 PM, Stephen Boyd wrote: > Quoting Amit Nischal (2018-08-12 23:33:04) >> For some of the GDSCs, there is a requirement to enable/disable the >> few clocks before turning on/off the gdsc power domain. Add support >> for the same by specifying a list of clk_hw pointers per gdsc and >> enable/disable them along with power domain on/off callbacks. >> >> Signed-off-by: Amit Nischal <anischal@codeaurora.org> > > In v1 of this patch series I asked for much more information in this > commit text. Please add it here. I won't apply this patch until the > justification is put into this commit text. > Would surely add more details. >> --- >> drivers/clk/qcom/gdsc.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ >> drivers/clk/qcom/gdsc.h | 5 +++++ >> 2 files changed, 49 insertions(+) >> >> diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c >> index a077133..b6adca1 100644 >> --- a/drivers/clk/qcom/gdsc.c >> +++ b/drivers/clk/qcom/gdsc.c >> @@ -12,6 +12,8 @@ >> */ >> >> #include <linux/bitops.h> >> +#include <linux/clk.h> >> +#include <linux/clk-provider.h> > > This makes me unhappy. It's almost always a problem when we see clk.h > and clk-provider.h included in the same file, so if gdsc has to call clk > APIs to operate correctly, then we should do that by having the gdsc > code get clks properly instead of directly reaching into the clk_hw > structure to get a clk pointer. This means we should have the gdsc code > ask the clk framework to convert a clk_hw pointer into a clk pointer > because of how so intimately connected the gdsc is to clks on this SoC. > But given all that, I'm still trying to understand why we need to do > this within the gdsc code. > > Adding these clk calls to the gdsc seems like we're attaching at the > wrong abstraction level. Especially if the reason we do it is to make it > easier for the GPU driver to handle dependencies. I hope that's not the > case. Either way, it would make more sense to me if we made genpds for > the clks and genpds for the gdscs and then associated the clk genpds > with the gdsc genpds so that when a gdsc is enabled the clk domain that > it depends on is enabled first. Then we have a generic solution for > connecting clks to gdscs that doesn't require us to add more logic to > the gdsc driver and avoids having clk providers do clk consumer things. > Instead, it's all handled outside of this driver by specifying a domain > dependency. It may turn out that such a solution would still need a way > to make clk domains in the clk driver, and it will probably need to do > that by converting clk_hw structures into clk pointers, but it would be > good to do that anyway. > > So in summary, I believe we should end up at a point where we have clk > domains and power domains (gdscs) all supported with genpds, and then we > can connect them together however they're connected by linking the > genpds to each other. Device drivers wouldn't really need to care how > they're connected, as long as those genpds are attached to their device > then the driver would be able to enable/disable them through runtime PM. > But I can see how this may be hard to do for this patch series, so in > the spirit of progress and getting things done, it would be OK with me > if the gdsc code called some new clk API to convert a clk_hw pointer > into a clk pointer and then did the same enable/disable things it's > doing in this patch. This whole patch would need to be completely > untangled and ripped out later when we have clk domains but at least we > could get something working now while we work on making clk domains and > plumbing them into genpds and runtime PM. > Yes, I agree with your points above, but as genpds currently cannot have a way to take in clock handles, this was the way we chose. I would add a new clock API as suggested and submit the next series. -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. -- ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 2/4] clk: qcom: Add clk_rcg2_gfx3d_ops for SDM845 2018-08-13 6:33 [PATCH v3 0/4] Add QCOM graphics clock controller driver for SDM845 Amit Nischal 2018-08-13 6:33 ` [PATCH v3 1/4] clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC Amit Nischal @ 2018-08-13 6:33 ` Amit Nischal 2018-11-02 20:52 ` Stephen Boyd 2018-08-13 6:33 ` [PATCH v3 3/4] dt-bindings: clock: Introduce QCOM Graphics clock bindings Amit Nischal ` (2 subsequent siblings) 4 siblings, 1 reply; 12+ messages in thread From: Amit Nischal @ 2018-08-13 6:33 UTC (permalink / raw) To: Stephen Boyd, Michael Turquette Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, Taniya Das, linux-arm-msm, linux-soc, linux-clk, linux-kernel, Amit Nischal To turn on the gpu_gx_gdsc, there is a hardware requirement to turn on the root clock (GFX3D RCG) first which would be the turn on signal for the gdsc along with the SW_COLLAPSE. As per the current implementation of clk_rcg2_shared_ops, it clears the root_enable bit in the enable() clock op. But due to the above said requirement for GFX3D shared RCG, root_enable bit would be already set by gdsc driver and clk_rcg2_shared_enable()should not clear the root unless the disable is called. Add support for the same by reusing the existing clk_rcg2_shared_ops and deriving "clk_rcg2_gfx3d_ops" clk_ops for GFX3D clock to take care of the root set/clear requirement. Signed-off-by: Amit Nischal <anischal@codeaurora.org> --- drivers/clk/qcom/clk-rcg.h | 1 + drivers/clk/qcom/clk-rcg2.c | 86 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index dbd5a9e..081eca9 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -162,5 +162,6 @@ struct clk_rcg2 { extern const struct clk_ops clk_pixel_ops; extern const struct clk_ops clk_gfx3d_ops; extern const struct clk_ops clk_rcg2_shared_ops; +extern const struct clk_ops clk_rcg2_gfx3d_ops; #endif diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 52208d4..a57ce00 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -866,7 +866,7 @@ static int clk_rcg2_shared_set_rate_and_parent(struct clk_hw *hw, return clk_rcg2_shared_set_rate(hw, rate, parent_rate); } -static int clk_rcg2_shared_enable(struct clk_hw *hw) +static int __clk_rcg2_shared_enable(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); int ret; @@ -879,7 +879,14 @@ static int clk_rcg2_shared_enable(struct clk_hw *hw) if (ret) return ret; - ret = update_config(rcg); + return update_config(rcg); +} + +static int clk_rcg2_shared_enable(struct clk_hw *hw) +{ + int ret; + + ret = __clk_rcg2_shared_enable(hw); if (ret) return ret; @@ -929,3 +936,78 @@ static void clk_rcg2_shared_disable(struct clk_hw *hw) .set_rate_and_parent = clk_rcg2_shared_set_rate_and_parent, }; EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops); + +static int clk_rcg2_gfx3d_enable(struct clk_hw *hw) +{ + return __clk_rcg2_shared_enable(hw); +} + +static int clk_rcg2_gfx3d_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_rate_request parent_req = { }; + struct clk_hw *p; + unsigned long rate = req->rate; + int ret; + + rate = clamp(rate, req->min_rate, req->max_rate); + + /* Get fixed parent - GPU_CC_PLL0_OUT_EVEN */ + p = clk_hw_get_parent_by_index(hw, 1); + + /* Parent should always run at twice of the requested rate */ + parent_req.rate = 2 * rate; + + ret = __clk_determine_rate(req->best_parent_hw, &parent_req); + if (ret) + return ret; + + req->best_parent_hw = p; + req->best_parent_rate = parent_req.rate; + req->rate = parent_req.rate / 2; + + return 0; +} + +static int clk_rcg2_gfx3d_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + int ret; + u32 cfg; + + /* Configure fixed SRC and DIV */ + cfg = rcg->parent_map[1].cfg << CFG_SRC_SEL_SHIFT; + cfg |= 0x3 << CFG_SRC_DIV_SHIFT; + + ret = regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, cfg); + if (ret) + return ret; + + /* + * In case clock is disabled, update the SRC and DIV only + * and return without configuration update. + */ + if (!__clk_is_enabled(hw->clk)) + return 0; + + return update_config(rcg); +} + +static int clk_rcg2_gfx3d_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate, u8 index) +{ + return clk_rcg2_gfx3d_set_rate(hw, rate, parent_rate); +} + +const struct clk_ops clk_rcg2_gfx3d_ops = { + .enable = clk_rcg2_gfx3d_enable, + .disable = clk_rcg2_shared_disable, + .get_parent = clk_rcg2_get_parent, + .set_parent = clk_rcg2_set_parent, + .recalc_rate = clk_rcg2_recalc_rate, + .determine_rate = clk_rcg2_gfx3d_determine_rate, + .set_rate = clk_rcg2_gfx3d_set_rate, + .set_rate_and_parent = clk_rcg2_gfx3d_set_rate_and_parent, +}; +EXPORT_SYMBOL_GPL(clk_rcg2_gfx3d_ops); -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v3 2/4] clk: qcom: Add clk_rcg2_gfx3d_ops for SDM845 2018-08-13 6:33 ` [PATCH v3 2/4] clk: qcom: Add clk_rcg2_gfx3d_ops for SDM845 Amit Nischal @ 2018-11-02 20:52 ` Stephen Boyd 0 siblings, 0 replies; 12+ messages in thread From: Stephen Boyd @ 2018-11-02 20:52 UTC (permalink / raw) To: Amit Nischal, Michael Turquette Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, Taniya Das, linux-arm-msm, linux-soc, linux-clk, linux-kernel, Amit Nischal Quoting Amit Nischal (2018-08-12 23:33:05) > diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c > index 52208d4..a57ce00 100644 > --- a/drivers/clk/qcom/clk-rcg2.c > +++ b/drivers/clk/qcom/clk-rcg2.c > @@ -866,7 +866,7 @@ static int clk_rcg2_shared_set_rate_and_parent(struct clk_hw *hw, > return clk_rcg2_shared_set_rate(hw, rate, parent_rate); > } > > -static int clk_rcg2_shared_enable(struct clk_hw *hw) > +static int __clk_rcg2_shared_enable(struct clk_hw *hw) Name this clk_rcg2_force_enable() please. Also add a comment above like: /* Set RCG force enable bit and flush out any configuration settings */ > { > struct clk_rcg2 *rcg = to_clk_rcg2(hw); > int ret; > @@ -879,7 +879,14 @@ static int clk_rcg2_shared_enable(struct clk_hw *hw) > if (ret) > return ret; > > - ret = update_config(rcg); > + return update_config(rcg); > +} > + > +static int clk_rcg2_shared_enable(struct clk_hw *hw) > +{ > + int ret; > + > + ret = __clk_rcg2_shared_enable(hw); > if (ret) > return ret; > > @@ -929,3 +936,78 @@ static void clk_rcg2_shared_disable(struct clk_hw *hw) > .set_rate_and_parent = clk_rcg2_shared_set_rate_and_parent, > }; > EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops); > + > +static int clk_rcg2_gfx3d_enable(struct clk_hw *hw) > +{ > + return __clk_rcg2_shared_enable(hw); > +} And then drop this wrapper and just use clk_rcg2_force_enable() in the clk_ops structure. > + > +static int clk_rcg2_gfx3d_determine_rate(struct clk_hw *hw, > + struct clk_rate_request *req) > +{ > + struct clk_rate_request parent_req = { }; > + struct clk_hw *p; > + unsigned long rate = req->rate; > + int ret; > + > + rate = clamp(rate, req->min_rate, req->max_rate); Doesn't the core already clamp the rate for you? Seems wasteful to do it again. > + > + /* Get fixed parent - GPU_CC_PLL0_OUT_EVEN */ I hope this doesn't change in the future! Any way to make this detectable by storing the parent index somewhere so this op can work with any future index selection instead of hardcoding '1' here? > + p = clk_hw_get_parent_by_index(hw, 1); > + > + /* Parent should always run at twice of the requested rate */ > + parent_req.rate = 2 * rate; > + > + ret = __clk_determine_rate(req->best_parent_hw, &parent_req); > + if (ret) > + return ret; > + > + req->best_parent_hw = p; > + req->best_parent_rate = parent_req.rate; > + req->rate = parent_req.rate / 2; > + > + return 0; > +} > + > +static int clk_rcg2_gfx3d_set_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate) > +{ > + struct clk_rcg2 *rcg = to_clk_rcg2(hw); > + int ret; > + u32 cfg; > + > + /* Configure fixed SRC and DIV */ > + cfg = rcg->parent_map[1].cfg << CFG_SRC_SEL_SHIFT; This would need to be dynamic too instead of hardcoding '1'. > + cfg |= 0x3 << CFG_SRC_DIV_SHIFT; > + > + ret = regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, cfg); > + if (ret) > + return ret; > + > + /* > + * In case clock is disabled, update the SRC and DIV only > + * and return without configuration update. Add: When the clk is enabled, we'll configure the rate to be what we requested here. This allows other users of this clk (i.e. GPU) to change the rate when this clk is disabled from our perspective. > + */ > + if (!__clk_is_enabled(hw->clk)) > + return 0; > + > + return update_config(rcg); > +} ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 3/4] dt-bindings: clock: Introduce QCOM Graphics clock bindings 2018-08-13 6:33 [PATCH v3 0/4] Add QCOM graphics clock controller driver for SDM845 Amit Nischal 2018-08-13 6:33 ` [PATCH v3 1/4] clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC Amit Nischal 2018-08-13 6:33 ` [PATCH v3 2/4] clk: qcom: Add clk_rcg2_gfx3d_ops for SDM845 Amit Nischal @ 2018-08-13 6:33 ` Amit Nischal 2018-08-13 6:33 ` [PATCH v3 4/4] clk: qcom: Add graphics clock controller driver for SDM845 Amit Nischal 2018-11-19 20:45 ` [PATCH v3 0/4] Add QCOM " Jordan Crouse 4 siblings, 0 replies; 12+ messages in thread From: Amit Nischal @ 2018-08-13 6:33 UTC (permalink / raw) To: Stephen Boyd, Michael Turquette Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, Taniya Das, linux-arm-msm, linux-soc, linux-clk, linux-kernel, Amit Nischal Add device tree bindings for graphics clock controller for Qualcomm Technology Inc's SDM845 SoCs. Signed-off-by: Amit Nischal <anischal@codeaurora.org> --- .../devicetree/bindings/clock/qcom,gpucc.txt | 18 ++++++++++ include/dt-bindings/clock/qcom,gpucc-sdm845.h | 38 ++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,gpucc.txt create mode 100644 include/dt-bindings/clock/qcom,gpucc-sdm845.h diff --git a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt new file mode 100644 index 0000000..93752db --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt @@ -0,0 +1,18 @@ +Qualcomm Graphics Clock & Reset Controller Binding +-------------------------------------------------- + +Required properties : +- compatible : shall contain "qcom,sdm845-gpucc". +- reg : shall contain base register location and length. +- #clock-cells : from common clock binding, shall contain 1. +- #reset-cells : from common reset binding, shall contain 1. +- #power-domain-cells : from generic power domain binding, shall contain 1. + +Example: + gpucc: clock-controller@5090000 { + compatible = "qcom,sdm845-gpucc"; + reg = <0x5090000 0x9000>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; diff --git a/include/dt-bindings/clock/qcom,gpucc-sdm845.h b/include/dt-bindings/clock/qcom,gpucc-sdm845.h new file mode 100644 index 0000000..643b42a --- /dev/null +++ b/include/dt-bindings/clock/qcom,gpucc-sdm845.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_SDM_GPU_CC_SDM845_H +#define _DT_BINDINGS_CLK_SDM_GPU_CC_SDM845_H + +/* GPU_CC clock registers */ +#define GPU_CC_CRC_AHB_CLK 0 +#define GPU_CC_CX_APB_CLK 1 +#define GPU_CC_CX_GFX3D_CLK 2 +#define GPU_CC_CX_GFX3D_SLV_CLK 3 +#define GPU_CC_CX_GMU_CLK 4 +#define GPU_CC_CX_SNOC_DVM_CLK 5 +#define GPU_CC_CXO_CLK 6 +#define GPU_CC_GMU_CLK_SRC 7 +#define GPU_CC_GX_GMU_CLK 8 +#define GPU_CC_GX_GFX3D_CLK_SRC 9 +#define GPU_CC_GX_GFX3D_CLK 10 +#define GPU_CC_PLL0 11 +#define GPU_CC_PLL0_OUT_EVEN 12 +#define GPU_CC_PLL1 13 + +/* GPU_CC Resets */ +#define GPUCC_GPU_CC_ACD_BCR 0 +#define GPUCC_GPU_CC_CX_BCR 1 +#define GPUCC_GPU_CC_GFX3D_AON_BCR 2 +#define GPUCC_GPU_CC_GMU_BCR 3 +#define GPUCC_GPU_CC_GX_BCR 4 +#define GPUCC_GPU_CC_SPDM_BCR 5 +#define GPUCC_GPU_CC_XO_BCR 6 + +/* GPU_CC GDSCRs */ +#define GPU_CX_GDSC 0 +#define GPU_GX_GDSC 1 + +#endif -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v3 4/4] clk: qcom: Add graphics clock controller driver for SDM845 2018-08-13 6:33 [PATCH v3 0/4] Add QCOM graphics clock controller driver for SDM845 Amit Nischal ` (2 preceding siblings ...) 2018-08-13 6:33 ` [PATCH v3 3/4] dt-bindings: clock: Introduce QCOM Graphics clock bindings Amit Nischal @ 2018-08-13 6:33 ` Amit Nischal 2018-11-05 6:37 ` Stephen Boyd 2018-11-19 20:51 ` Jordan Crouse 2018-11-19 20:45 ` [PATCH v3 0/4] Add QCOM " Jordan Crouse 4 siblings, 2 replies; 12+ messages in thread From: Amit Nischal @ 2018-08-13 6:33 UTC (permalink / raw) To: Stephen Boyd, Michael Turquette Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, Taniya Das, linux-arm-msm, linux-soc, linux-clk, linux-kernel, Amit Nischal Add support for the graphics clock controller found on SDM845 based devices. This would allow graphics drivers to probe and control their clocks. Signed-off-by: Amit Nischal <anischal@codeaurora.org> --- drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gpucc-sdm845.c | 438 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 448 insertions(+) create mode 100644 drivers/clk/qcom/gpucc-sdm845.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 0647686..1595464 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -244,6 +244,15 @@ config SDM_GCC_845 Say Y if you want to use peripheral devices such as UART, SPI, i2C, USB, UFS, SDDC, PCIe, etc. +config SDM_GPUCC_845 + tristate "SDM845 Graphics Clock Controller" + depends on COMMON_CLK_QCOM + select SDM_GCC_845 + help + Support for the graphics clock controller on SDM845 devices. + Say Y if you want to support graphics controller devices and + functionality such as 3D graphics. + config SDM_VIDEOCC_845 tristate "SDM845 Video Clock Controller" depends on COMMON_CLK_QCOM diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index c4ed36f..93c1089 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -42,5 +42,6 @@ obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o +obj-$(CONFIG_SDM_GPUCC_845) += gpucc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c new file mode 100644 index 0000000..7a11b70 --- /dev/null +++ b/drivers/clk/qcom/gpucc-sdm845.c @@ -0,0 +1,438 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#include <dt-bindings/clock/qcom,gpucc-sdm845.h> + +#include "common.h" +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "gdsc.h" + +#define CX_GMU_CBCR_SLEEP_MASK 0xf +#define CX_GMU_CBCR_SLEEP_SHIFT 4 +#define CX_GMU_CBCR_WAKE_MASK 0xf +#define CX_GMU_CBCR_WAKE_SHIFT 8 +#define CLK_DIS_WAIT_SHIFT 12 +#define CLK_DIS_WAIT_MASK (0xf << CLK_DIS_WAIT_SHIFT) + +enum { + P_BI_TCXO, + P_CORE_BI_PLL_TEST_SE, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, + P_GPU_CC_PLL0_OUT_EVEN, + P_GPU_CC_PLL0_OUT_MAIN, + P_GPU_CC_PLL0_OUT_ODD, + P_GPU_CC_PLL1_OUT_EVEN, + P_GPU_CC_PLL1_OUT_MAIN, + P_GPU_CC_PLL1_OUT_ODD, +}; + +static const struct parent_map gpu_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_MAIN, 1 }, + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gpu_cc_parent_names_0[] = { + "bi_tcxo", + "gpu_cc_pll0", + "gpu_cc_pll1", + "gcc_gpu_gpll0_clk_src", + "gcc_gpu_gpll0_div_clk_src", + "core_bi_pll_test_se", +}; + +static const struct parent_map gpu_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_EVEN, 1 }, + { P_GPU_CC_PLL0_OUT_ODD, 2 }, + { P_GPU_CC_PLL1_OUT_EVEN, 3 }, + { P_GPU_CC_PLL1_OUT_ODD, 4 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gpu_cc_parent_names_1[] = { + "bi_tcxo", + "gpu_cc_pll0_out_even", + "gpu_cc_pll0_out_odd", + "gpu_cc_pll1_out_even", + "gpu_cc_pll1_out_odd", + "gcc_gpu_gpll0_clk_src", + "core_bi_pll_test_se", +}; + +static const struct alpha_pll_config gpu_cc_pll0_config = { + .l = 0x1d, + .alpha = 0x2aaa, +}; + +static const struct alpha_pll_config gpu_cc_pll1_config = { + .l = 0x1a, + .alpha = 0xaab, +}; + +static struct clk_alpha_pll gpu_cc_pll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_fabia_even[] = { + { 0x0, 1 }, +}; + +static struct clk_alpha_pll_postdiv gpu_cc_pll0_out_even = { + .offset = 0x0, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll0_out_even", + .parent_names = (const char *[]){ "gpu_cc_pll0" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_fabia_ops, + }, +}; + +static struct clk_alpha_pll gpu_cc_pll1 = { + .offset = 0x100, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll1", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), + F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gmu_clk_src = { + .cmd_rcgr = 0x1120, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_0, + .freq_tbl = ftbl_gpu_cc_gmu_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gmu_clk_src", + .parent_names = gpu_cc_parent_names_0, + .num_parents = 6, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = { + .cmd_rcgr = 0x101c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_1, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_clk_src", + .parent_names = gpu_cc_parent_names_1, + .num_parents = 7, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_gfx3d_ops, + }, +}; + +static struct clk_branch gpu_cc_crc_ahb_clk = { + .halt_reg = 0x107c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x107c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_crc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_apb_clk = { + .halt_reg = 0x1088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1088, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_apb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gfx3d_clk = { + .halt_reg = 0x10a4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10a4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gfx3d_clk", + .parent_names = (const char *[]){ + "gpu_cc_gx_gfx3d_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gfx3d_slv_clk = { + .halt_reg = 0x10a8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10a8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gfx3d_slv_clk", + .parent_names = (const char *[]){ + "gpu_cc_gx_gfx3d_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gmu_clk = { + .halt_reg = 0x1098, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1098, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gmu_clk", + .parent_names = (const char *[]){ + "gpu_cc_gmu_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_snoc_dvm_clk = { + .halt_reg = 0x108c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x108c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_snoc_dvm_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_clk = { + .halt_reg = 0x109c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x109c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gfx3d_clk = { + .halt_reg = 0x1054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_clk", + .parent_names = (const char *[]){ + "gpu_cc_gx_gfx3d_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gmu_clk = { + .halt_reg = 0x1064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gmu_clk", + .parent_names = (const char *[]){ + "gpu_cc_gmu_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc gpu_cx_gdsc = { + .gdscr = 0x106c, + .gds_hw_ctrl = 0x1540, + .pd = { + .name = "gpu_cx_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc gpu_gx_gdsc = { + .gdscr = 0x100c, + .clamp_io_ctrl = 0x1508, + .pd = { + .name = "gpu_gx_gdsc", + }, + .clk_hws = { + &gpu_cc_gx_gfx3d_clk_src.clkr.hw, + }, + .clk_count = 1, + .pwrsts = PWRSTS_OFF_ON, + .flags = CLAMP_IO | AON_RESET | POLL_CFG_GDSCR, +}; + +static struct clk_regmap *gpu_cc_sdm845_clocks[] = { + [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, + [GPU_CC_CX_APB_CLK] = &gpu_cc_cx_apb_clk.clkr, + [GPU_CC_CX_GFX3D_CLK] = &gpu_cc_cx_gfx3d_clk.clkr, + [GPU_CC_CX_GFX3D_SLV_CLK] = &gpu_cc_cx_gfx3d_slv_clk.clkr, + [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr, + [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr, + [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr, + [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, + [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr, + [GPU_CC_GX_GFX3D_CLK_SRC] = &gpu_cc_gx_gfx3d_clk_src.clkr, + [GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr, + [GPU_CC_PLL0] = &gpu_cc_pll0.clkr, + [GPU_CC_PLL0_OUT_EVEN] = &gpu_cc_pll0_out_even.clkr, + [GPU_CC_PLL1] = &gpu_cc_pll1.clkr, +}; + +static struct gdsc *gpu_cc_sdm845_gdscs[] = { + [GPU_CX_GDSC] = &gpu_cx_gdsc, + [GPU_GX_GDSC] = &gpu_gx_gdsc, +}; + +static const struct regmap_config gpu_cc_sdm845_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x8008, + .fast_io = true, +}; + +static const struct qcom_cc_desc gpu_cc_sdm845_desc = { + .config = &gpu_cc_sdm845_regmap_config, + .clks = gpu_cc_sdm845_clocks, + .num_clks = ARRAY_SIZE(gpu_cc_sdm845_clocks), + .gdscs = gpu_cc_sdm845_gdscs, + .num_gdscs = ARRAY_SIZE(gpu_cc_sdm845_gdscs), +}; + +static const struct of_device_id gpu_cc_sdm845_match_table[] = { + { .compatible = "qcom,sdm845-gpucc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gpu_cc_sdm845_match_table); + +static int gpu_cc_sdm845_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + unsigned int value, mask; + int ret; + + regmap = qcom_cc_map(pdev, &gpu_cc_sdm845_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + clk_fabia_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); + clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); + + /* + * Configure gpu_cc_cx_gmu_clk with recommended + * wakeup/sleep settings + */ + mask = CX_GMU_CBCR_WAKE_MASK << CX_GMU_CBCR_WAKE_SHIFT; + mask |= CX_GMU_CBCR_SLEEP_MASK << CX_GMU_CBCR_SLEEP_SHIFT; + value = 0xf << CX_GMU_CBCR_WAKE_SHIFT | 0xf << CX_GMU_CBCR_SLEEP_SHIFT; + regmap_update_bits(regmap, 0x1098, mask, value); + + ret = qcom_cc_really_probe(pdev, &gpu_cc_sdm845_desc, regmap); + if (ret) + return ret; + + /* Configure clk_dis_wait for gpu_cx_gdsc */ + regmap_update_bits(regmap, 0x106c, CLK_DIS_WAIT_MASK, + 8 << CLK_DIS_WAIT_SHIFT); + + /* Set supported range of frequencies for gfx3d clock */ + clk_hw_set_rate_range(&gpu_cc_gx_gfx3d_clk_src.clkr.hw, 180000000, + 710000000); + + return 0; +} + +static struct platform_driver gpu_cc_sdm845_driver = { + .probe = gpu_cc_sdm845_probe, + .driver = { + .name = "sdm845-gpucc", + .of_match_table = gpu_cc_sdm845_match_table, + }, +}; + +static int __init gpu_cc_sdm845_init(void) +{ + return platform_driver_register(&gpu_cc_sdm845_driver); +} +subsys_initcall(gpu_cc_sdm845_init); + +static void __exit gpu_cc_sdm845_exit(void) +{ + platform_driver_unregister(&gpu_cc_sdm845_driver); +} +module_exit(gpu_cc_sdm845_exit); + +MODULE_DESCRIPTION("QTI GPUCC SDM845 Driver"); +MODULE_LICENSE("GPL v2"); -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v3 4/4] clk: qcom: Add graphics clock controller driver for SDM845 2018-08-13 6:33 ` [PATCH v3 4/4] clk: qcom: Add graphics clock controller driver for SDM845 Amit Nischal @ 2018-11-05 6:37 ` Stephen Boyd 2018-11-19 11:32 ` Taniya Das 2018-11-19 20:51 ` Jordan Crouse 1 sibling, 1 reply; 12+ messages in thread From: Stephen Boyd @ 2018-11-05 6:37 UTC (permalink / raw) To: Amit Nischal, Michael Turquette Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, Taniya Das, linux-arm-msm, linux-soc, linux-clk, linux-kernel, Amit Nischal Quoting Amit Nischal (2018-08-12 23:33:07) > + > +static int gpu_cc_sdm845_probe(struct platform_device *pdev) > +{ > + struct regmap *regmap; > + unsigned int value, mask; > + int ret; > + > + regmap = qcom_cc_map(pdev, &gpu_cc_sdm845_desc); > + if (IS_ERR(regmap)) > + return PTR_ERR(regmap); > + > + clk_fabia_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); > + clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); > + > + /* > + * Configure gpu_cc_cx_gmu_clk with recommended > + * wakeup/sleep settings > + */ > + mask = CX_GMU_CBCR_WAKE_MASK << CX_GMU_CBCR_WAKE_SHIFT; > + mask |= CX_GMU_CBCR_SLEEP_MASK << CX_GMU_CBCR_SLEEP_SHIFT; > + value = 0xf << CX_GMU_CBCR_WAKE_SHIFT | 0xf << CX_GMU_CBCR_SLEEP_SHIFT; > + regmap_update_bits(regmap, 0x1098, mask, value); > + > + ret = qcom_cc_really_probe(pdev, &gpu_cc_sdm845_desc, regmap); > + if (ret) > + return ret; > + > + /* Configure clk_dis_wait for gpu_cx_gdsc */ > + regmap_update_bits(regmap, 0x106c, CLK_DIS_WAIT_MASK, > + 8 << CLK_DIS_WAIT_SHIFT); Is there a reason this is done after clks are registered? I'd think we would want to do it before. > + > + /* Set supported range of frequencies for gfx3d clock */ > + clk_hw_set_rate_range(&gpu_cc_gx_gfx3d_clk_src.clkr.hw, 180000000, > + 710000000); > + > + return 0; > +} ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 4/4] clk: qcom: Add graphics clock controller driver for SDM845 2018-11-05 6:37 ` Stephen Boyd @ 2018-11-19 11:32 ` Taniya Das 0 siblings, 0 replies; 12+ messages in thread From: Taniya Das @ 2018-11-19 11:32 UTC (permalink / raw) To: Stephen Boyd, Amit Nischal, Michael Turquette Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, linux-arm-msm, linux-soc, linux-clk, linux-kernel Hello Stephen, On 11/5/2018 12:07 PM, Stephen Boyd wrote: > Quoting Amit Nischal (2018-08-12 23:33:07) >> + >> +static int gpu_cc_sdm845_probe(struct platform_device *pdev) >> +{ >> + struct regmap *regmap; >> + unsigned int value, mask; >> + int ret; >> + >> + regmap = qcom_cc_map(pdev, &gpu_cc_sdm845_desc); >> + if (IS_ERR(regmap)) >> + return PTR_ERR(regmap); >> + >> + clk_fabia_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); >> + clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); >> + >> + /* >> + * Configure gpu_cc_cx_gmu_clk with recommended >> + * wakeup/sleep settings >> + */ >> + mask = CX_GMU_CBCR_WAKE_MASK << CX_GMU_CBCR_WAKE_SHIFT; >> + mask |= CX_GMU_CBCR_SLEEP_MASK << CX_GMU_CBCR_SLEEP_SHIFT; >> + value = 0xf << CX_GMU_CBCR_WAKE_SHIFT | 0xf << CX_GMU_CBCR_SLEEP_SHIFT; >> + regmap_update_bits(regmap, 0x1098, mask, value); >> + >> + ret = qcom_cc_really_probe(pdev, &gpu_cc_sdm845_desc, regmap); >> + if (ret) >> + return ret; >> + >> + /* Configure clk_dis_wait for gpu_cx_gdsc */ >> + regmap_update_bits(regmap, 0x106c, CLK_DIS_WAIT_MASK, >> + 8 << CLK_DIS_WAIT_SHIFT); > > Is there a reason this is done after clks are registered? I'd think we > would want to do it before. > Yes, it could be done before, would move it. >> + >> + /* Set supported range of frequencies for gfx3d clock */ >> + clk_hw_set_rate_range(&gpu_cc_gx_gfx3d_clk_src.clkr.hw, 180000000, >> + 710000000); >> + >> + return 0; >> +} -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. -- ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 4/4] clk: qcom: Add graphics clock controller driver for SDM845 2018-08-13 6:33 ` [PATCH v3 4/4] clk: qcom: Add graphics clock controller driver for SDM845 Amit Nischal 2018-11-05 6:37 ` Stephen Boyd @ 2018-11-19 20:51 ` Jordan Crouse 1 sibling, 0 replies; 12+ messages in thread From: Jordan Crouse @ 2018-11-19 20:51 UTC (permalink / raw) To: Amit Nischal Cc: Stephen Boyd, Michael Turquette, Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, Taniya Das, linux-arm-msm, linux-soc, linux-clk, linux-kernel On Mon, Aug 13, 2018 at 12:03:07PM +0530, Amit Nischal wrote: > Add support for the graphics clock controller found on SDM845 > based devices. This would allow graphics drivers to probe and > control their clocks. > > Signed-off-by: Amit Nischal <anischal@codeaurora.org> > --- > drivers/clk/qcom/Kconfig | 9 + > drivers/clk/qcom/Makefile | 1 + > drivers/clk/qcom/gpucc-sdm845.c | 438 ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 448 insertions(+) > create mode 100644 drivers/clk/qcom/gpucc-sdm845.c > > diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig > index 0647686..1595464 100644 > --- a/drivers/clk/qcom/Kconfig > +++ b/drivers/clk/qcom/Kconfig > @@ -244,6 +244,15 @@ config SDM_GCC_845 > Say Y if you want to use peripheral devices such as UART, SPI, > i2C, USB, UFS, SDDC, PCIe, etc. > > +config SDM_GPUCC_845 > + tristate "SDM845 Graphics Clock Controller" > + depends on COMMON_CLK_QCOM > + select SDM_GCC_845 > + help > + Support for the graphics clock controller on SDM845 devices. > + Say Y if you want to support graphics controller devices and > + functionality such as 3D graphics. > + > config SDM_VIDEOCC_845 > tristate "SDM845 Video Clock Controller" > depends on COMMON_CLK_QCOM > diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile > index c4ed36f..93c1089 100644 > --- a/drivers/clk/qcom/Makefile > +++ b/drivers/clk/qcom/Makefile > @@ -42,5 +42,6 @@ obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o > obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o > obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o > obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o > +obj-$(CONFIG_SDM_GPUCC_845) += gpucc-sdm845.o > obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o > obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o > diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c > new file mode 100644 > index 0000000..7a11b70 > --- /dev/null > +++ b/drivers/clk/qcom/gpucc-sdm845.c > @@ -0,0 +1,438 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2018, The Linux Foundation. All rights reserved. > + */ > + > +#include <linux/clk-provider.h> > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/regmap.h> > + > +#include <dt-bindings/clock/qcom,gpucc-sdm845.h> > + > +#include "common.h" > +#include "clk-alpha-pll.h" > +#include "clk-branch.h" > +#include "clk-pll.h" > +#include "clk-rcg.h" > +#include "clk-regmap.h" > +#include "gdsc.h" > + > +#define CX_GMU_CBCR_SLEEP_MASK 0xf > +#define CX_GMU_CBCR_SLEEP_SHIFT 4 > +#define CX_GMU_CBCR_WAKE_MASK 0xf > +#define CX_GMU_CBCR_WAKE_SHIFT 8 > +#define CLK_DIS_WAIT_SHIFT 12 > +#define CLK_DIS_WAIT_MASK (0xf << CLK_DIS_WAIT_SHIFT) > + > +enum { > + P_BI_TCXO, > + P_CORE_BI_PLL_TEST_SE, > + P_GPLL0_OUT_MAIN, > + P_GPLL0_OUT_MAIN_DIV, > + P_GPU_CC_PLL0_OUT_EVEN, > + P_GPU_CC_PLL0_OUT_MAIN, > + P_GPU_CC_PLL0_OUT_ODD, > + P_GPU_CC_PLL1_OUT_EVEN, > + P_GPU_CC_PLL1_OUT_MAIN, > + P_GPU_CC_PLL1_OUT_ODD, > +}; > + > +static const struct parent_map gpu_cc_parent_map_0[] = { > + { P_BI_TCXO, 0 }, > + { P_GPU_CC_PLL0_OUT_MAIN, 1 }, > + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, > + { P_GPLL0_OUT_MAIN, 5 }, > + { P_GPLL0_OUT_MAIN_DIV, 6 }, > + { P_CORE_BI_PLL_TEST_SE, 7 }, > +}; > + > +static const char * const gpu_cc_parent_names_0[] = { > + "bi_tcxo", > + "gpu_cc_pll0", > + "gpu_cc_pll1", > + "gcc_gpu_gpll0_clk_src", > + "gcc_gpu_gpll0_div_clk_src", > + "core_bi_pll_test_se", > +}; > + > +static const struct parent_map gpu_cc_parent_map_1[] = { > + { P_BI_TCXO, 0 }, > + { P_GPU_CC_PLL0_OUT_EVEN, 1 }, > + { P_GPU_CC_PLL0_OUT_ODD, 2 }, > + { P_GPU_CC_PLL1_OUT_EVEN, 3 }, > + { P_GPU_CC_PLL1_OUT_ODD, 4 }, > + { P_GPLL0_OUT_MAIN, 5 }, > + { P_CORE_BI_PLL_TEST_SE, 7 }, > +}; > + > +static const char * const gpu_cc_parent_names_1[] = { > + "bi_tcxo", > + "gpu_cc_pll0_out_even", > + "gpu_cc_pll0_out_odd", > + "gpu_cc_pll1_out_even", > + "gpu_cc_pll1_out_odd", > + "gcc_gpu_gpll0_clk_src", > + "core_bi_pll_test_se", > +}; > + > +static const struct alpha_pll_config gpu_cc_pll0_config = { > + .l = 0x1d, > + .alpha = 0x2aaa, > +}; > + > +static const struct alpha_pll_config gpu_cc_pll1_config = { > + .l = 0x1a, > + .alpha = 0xaab, > +}; > + > +static struct clk_alpha_pll gpu_cc_pll0 = { > + .offset = 0x0, > + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], > + .clkr = { > + .hw.init = &(struct clk_init_data){ > + .name = "gpu_cc_pll0", > + .parent_names = (const char *[]){ "bi_tcxo" }, > + .num_parents = 1, > + .ops = &clk_alpha_pll_fabia_ops, > + }, > + }, > +}; > + > +static const struct clk_div_table post_div_table_fabia_even[] = { > + { 0x0, 1 }, > +}; > + > +static struct clk_alpha_pll_postdiv gpu_cc_pll0_out_even = { > + .offset = 0x0, > + .post_div_shift = 8, > + .post_div_table = post_div_table_fabia_even, > + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), > + .width = 4, > + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], > + .clkr.hw.init = &(struct clk_init_data){ > + .name = "gpu_cc_pll0_out_even", > + .parent_names = (const char *[]){ "gpu_cc_pll0" }, > + .num_parents = 1, > + .flags = CLK_SET_RATE_PARENT, > + .ops = &clk_alpha_pll_postdiv_fabia_ops, > + }, > +}; > + > +static struct clk_alpha_pll gpu_cc_pll1 = { > + .offset = 0x100, > + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], > + .clkr = { > + .hw.init = &(struct clk_init_data){ > + .name = "gpu_cc_pll1", > + .parent_names = (const char *[]){ "bi_tcxo" }, > + .num_parents = 1, > + .ops = &clk_alpha_pll_fabia_ops, > + }, > + }, > +}; > + > +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { > + F(19200000, P_BI_TCXO, 1, 0, 0), > + F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), > + F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0), > + { } > +}; > + > +static struct clk_rcg2 gpu_cc_gmu_clk_src = { > + .cmd_rcgr = 0x1120, > + .mnd_width = 0, > + .hid_width = 5, > + .parent_map = gpu_cc_parent_map_0, > + .freq_tbl = ftbl_gpu_cc_gmu_clk_src, > + .clkr.hw.init = &(struct clk_init_data){ > + .name = "gpu_cc_gmu_clk_src", > + .parent_names = gpu_cc_parent_names_0, > + .num_parents = 6, > + .ops = &clk_rcg2_shared_ops, > + }, > +}; > + > +static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = { > + .cmd_rcgr = 0x101c, > + .mnd_width = 0, > + .hid_width = 5, > + .parent_map = gpu_cc_parent_map_1, > + .clkr.hw.init = &(struct clk_init_data){ > + .name = "gpu_cc_gx_gfx3d_clk_src", > + .parent_names = gpu_cc_parent_names_1, > + .num_parents = 7, > + .flags = CLK_SET_RATE_PARENT, > + .ops = &clk_rcg2_gfx3d_ops, > + }, > +}; > + > +static struct clk_branch gpu_cc_crc_ahb_clk = { > + .halt_reg = 0x107c, > + .halt_check = BRANCH_HALT, > + .clkr = { > + .enable_reg = 0x107c, > + .enable_mask = BIT(0), > + .hw.init = &(struct clk_init_data){ > + .name = "gpu_cc_crc_ahb_clk", > + .ops = &clk_branch2_ops, > + }, > + }, > +}; > + > +static struct clk_branch gpu_cc_cx_apb_clk = { > + .halt_reg = 0x1088, > + .halt_check = BRANCH_HALT, > + .clkr = { > + .enable_reg = 0x1088, > + .enable_mask = BIT(0), > + .hw.init = &(struct clk_init_data){ > + .name = "gpu_cc_cx_apb_clk", > + .ops = &clk_branch2_ops, > + }, > + }, > +}; > + > +static struct clk_branch gpu_cc_cx_gfx3d_clk = { > + .halt_reg = 0x10a4, > + .halt_check = BRANCH_HALT, > + .clkr = { > + .enable_reg = 0x10a4, > + .enable_mask = BIT(0), > + .hw.init = &(struct clk_init_data){ > + .name = "gpu_cc_cx_gfx3d_clk", > + .parent_names = (const char *[]){ > + "gpu_cc_gx_gfx3d_clk_src", > + }, > + .num_parents = 1, > + .flags = CLK_SET_RATE_PARENT, > + .ops = &clk_branch2_ops, > + }, > + }, > +}; > + > +static struct clk_branch gpu_cc_cx_gfx3d_slv_clk = { > + .halt_reg = 0x10a8, > + .halt_check = BRANCH_HALT, > + .clkr = { > + .enable_reg = 0x10a8, > + .enable_mask = BIT(0), > + .hw.init = &(struct clk_init_data){ > + .name = "gpu_cc_cx_gfx3d_slv_clk", > + .parent_names = (const char *[]){ > + "gpu_cc_gx_gfx3d_clk_src", > + }, > + .num_parents = 1, > + .flags = CLK_SET_RATE_PARENT, > + .ops = &clk_branch2_ops, > + }, > + }, > +}; > + > +static struct clk_branch gpu_cc_cx_gmu_clk = { > + .halt_reg = 0x1098, > + .halt_check = BRANCH_HALT, > + .clkr = { > + .enable_reg = 0x1098, > + .enable_mask = BIT(0), > + .hw.init = &(struct clk_init_data){ > + .name = "gpu_cc_cx_gmu_clk", > + .parent_names = (const char *[]){ > + "gpu_cc_gmu_clk_src", > + }, > + .num_parents = 1, > + .flags = CLK_SET_RATE_PARENT, > + .ops = &clk_branch2_ops, > + }, > + }, > +}; > + > +static struct clk_branch gpu_cc_cx_snoc_dvm_clk = { > + .halt_reg = 0x108c, > + .halt_check = BRANCH_HALT, > + .clkr = { > + .enable_reg = 0x108c, > + .enable_mask = BIT(0), > + .hw.init = &(struct clk_init_data){ > + .name = "gpu_cc_cx_snoc_dvm_clk", > + .ops = &clk_branch2_ops, > + }, > + }, > +}; > + > +static struct clk_branch gpu_cc_cxo_clk = { > + .halt_reg = 0x109c, > + .halt_check = BRANCH_HALT, > + .clkr = { > + .enable_reg = 0x109c, > + .enable_mask = BIT(0), > + .hw.init = &(struct clk_init_data){ > + .name = "gpu_cc_cxo_clk", > + .ops = &clk_branch2_ops, > + }, > + }, > +}; > + > +static struct clk_branch gpu_cc_gx_gfx3d_clk = { > + .halt_reg = 0x1054, > + .halt_check = BRANCH_HALT, > + .clkr = { > + .enable_reg = 0x1054, > + .enable_mask = BIT(0), > + .hw.init = &(struct clk_init_data){ > + .name = "gpu_cc_gx_gfx3d_clk", > + .parent_names = (const char *[]){ > + "gpu_cc_gx_gfx3d_clk_src", > + }, > + .num_parents = 1, > + .flags = CLK_SET_RATE_PARENT, > + .ops = &clk_branch2_ops, > + }, > + }, > +}; > + > +static struct clk_branch gpu_cc_gx_gmu_clk = { > + .halt_reg = 0x1064, > + .halt_check = BRANCH_HALT, > + .clkr = { > + .enable_reg = 0x1064, > + .enable_mask = BIT(0), > + .hw.init = &(struct clk_init_data){ > + .name = "gpu_cc_gx_gmu_clk", > + .parent_names = (const char *[]){ > + "gpu_cc_gmu_clk_src", > + }, > + .num_parents = 1, > + .flags = CLK_SET_RATE_PARENT, > + .ops = &clk_branch2_ops, > + }, > + }, > +}; > + > +static struct gdsc gpu_cx_gdsc = { > + .gdscr = 0x106c, > + .gds_hw_ctrl = 0x1540, > + .pd = { > + .name = "gpu_cx_gdsc", > + }, > + .pwrsts = PWRSTS_OFF_ON, > + .flags = VOTABLE, > +}; > + > +static struct gdsc gpu_gx_gdsc = { > + .gdscr = 0x100c, > + .clamp_io_ctrl = 0x1508, > + .pd = { > + .name = "gpu_gx_gdsc", > + }, > + .clk_hws = { > + &gpu_cc_gx_gfx3d_clk_src.clkr.hw, > + }, > + .clk_count = 1, So from my perspective, this isn't needed - it at least seems that if the CX domain is still enabled that I can safely toggle this gdsc off even if these clocks are not defined. Full disclosure, my experiment has the "enable" hacked out so its possible that might have needed this in some past life but from what I can tell we won't need it upstream. > + .pwrsts = PWRSTS_OFF_ON, > + .flags = CLAMP_IO | AON_RESET | POLL_CFG_GDSCR, > +}; > + > +static struct clk_regmap *gpu_cc_sdm845_clocks[] = { > + [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, It does not appear that we control this clock from the CPU. > + [GPU_CC_CX_APB_CLK] = &gpu_cc_cx_apb_clk.clkr, Same. > + [GPU_CC_CX_GFX3D_CLK] = &gpu_cc_cx_gfx3d_clk.clkr, Same. > + [GPU_CC_CX_GFX3D_SLV_CLK] = &gpu_cc_cx_gfx3d_slv_clk.clkr, Same. > + [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr, > + [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr, Same. > + [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr, > + [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, > + [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr, Same. > + [GPU_CC_GX_GFX3D_CLK_SRC] = &gpu_cc_gx_gfx3d_clk_src.clkr, > + [GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr, With the discussion above, these are no longer used. > + [GPU_CC_PLL0] = &gpu_cc_pll0.clkr, > + [GPU_CC_PLL0_OUT_EVEN] = &gpu_cc_pll0_out_even.clkr, If GX_GFX3D goes away, this can too. > + [GPU_CC_PLL1] = &gpu_cc_pll1.clkr, > +}; > + > +static struct gdsc *gpu_cc_sdm845_gdscs[] = { > + [GPU_CX_GDSC] = &gpu_cx_gdsc, > + [GPU_GX_GDSC] = &gpu_gx_gdsc, > +}; > + > +static const struct regmap_config gpu_cc_sdm845_regmap_config = { > + .reg_bits = 32, > + .reg_stride = 4, > + .val_bits = 32, > + .max_register = 0x8008, > + .fast_io = true, > +}; > + > +static const struct qcom_cc_desc gpu_cc_sdm845_desc = { > + .config = &gpu_cc_sdm845_regmap_config, > + .clks = gpu_cc_sdm845_clocks, > + .num_clks = ARRAY_SIZE(gpu_cc_sdm845_clocks), > + .gdscs = gpu_cc_sdm845_gdscs, > + .num_gdscs = ARRAY_SIZE(gpu_cc_sdm845_gdscs), > +}; > + > +static const struct of_device_id gpu_cc_sdm845_match_table[] = { > + { .compatible = "qcom,sdm845-gpucc" }, > + { } > +}; > +MODULE_DEVICE_TABLE(of, gpu_cc_sdm845_match_table); > + > +static int gpu_cc_sdm845_probe(struct platform_device *pdev) > +{ > + struct regmap *regmap; > + unsigned int value, mask; > + int ret; > + > + regmap = qcom_cc_map(pdev, &gpu_cc_sdm845_desc); > + if (IS_ERR(regmap)) > + return PTR_ERR(regmap); > + > + clk_fabia_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); > + clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); > + > + /* > + * Configure gpu_cc_cx_gmu_clk with recommended > + * wakeup/sleep settings > + */ > + mask = CX_GMU_CBCR_WAKE_MASK << CX_GMU_CBCR_WAKE_SHIFT; > + mask |= CX_GMU_CBCR_SLEEP_MASK << CX_GMU_CBCR_SLEEP_SHIFT; > + value = 0xf << CX_GMU_CBCR_WAKE_SHIFT | 0xf << CX_GMU_CBCR_SLEEP_SHIFT; > + regmap_update_bits(regmap, 0x1098, mask, value); > + > + ret = qcom_cc_really_probe(pdev, &gpu_cc_sdm845_desc, regmap); > + if (ret) > + return ret; > + > + /* Configure clk_dis_wait for gpu_cx_gdsc */ > + regmap_update_bits(regmap, 0x106c, CLK_DIS_WAIT_MASK, > + 8 << CLK_DIS_WAIT_SHIFT); > + > + /* Set supported range of frequencies for gfx3d clock */ > + clk_hw_set_rate_range(&gpu_cc_gx_gfx3d_clk_src.clkr.hw, 180000000, > + 710000000); > + > + return 0; > +} > + > +static struct platform_driver gpu_cc_sdm845_driver = { > + .probe = gpu_cc_sdm845_probe, > + .driver = { > + .name = "sdm845-gpucc", > + .of_match_table = gpu_cc_sdm845_match_table, > + }, > +}; > + > +static int __init gpu_cc_sdm845_init(void) > +{ > + return platform_driver_register(&gpu_cc_sdm845_driver); > +} > +subsys_initcall(gpu_cc_sdm845_init); > + > +static void __exit gpu_cc_sdm845_exit(void) > +{ > + platform_driver_unregister(&gpu_cc_sdm845_driver); > +} > +module_exit(gpu_cc_sdm845_exit); > + > +MODULE_DESCRIPTION("QTI GPUCC SDM845 Driver"); > +MODULE_LICENSE("GPL v2"); -- The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 0/4] Add QCOM graphics clock controller driver for SDM845 2018-08-13 6:33 [PATCH v3 0/4] Add QCOM graphics clock controller driver for SDM845 Amit Nischal ` (3 preceding siblings ...) 2018-08-13 6:33 ` [PATCH v3 4/4] clk: qcom: Add graphics clock controller driver for SDM845 Amit Nischal @ 2018-11-19 20:45 ` Jordan Crouse 4 siblings, 0 replies; 12+ messages in thread From: Jordan Crouse @ 2018-11-19 20:45 UTC (permalink / raw) To: Amit Nischal Cc: Stephen Boyd, Michael Turquette, Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla, Taniya Das, linux-arm-msm, linux-soc, linux-clk, linux-kernel On Mon, Aug 13, 2018 at 12:03:03PM +0530, Amit Nischal wrote: > Changes in v3: > * Modified the determine_rate() op to use the min/max rate range > to round the requested rate within the set_rate range. With this, > requested set rate will always stay within the limits. > > Changes in v2: > Addressed review comments given by Stephen: https://lkml.org/lkml/2018/6/6/294 > * Introduce clk_rcg2_gfx3d_determine_rate ops to return the best parent > as 'gpucc_pll0_even' and best parent rate as twice of the requested rate > always. This will eliminate the need of frequency table as source and > div-2 are fixed for gfx3d_clk_src. > Also modified the clk_rcg2_set_rate ops to configure the fixed source and > div. > * Add support to check if requested rate falls within allowed set_rate range. > This will not let the source gpucc_pll0 to go out of the supported range > and also client can request the rate within the range. > * Fixed comment text in probe function and added module description for GPUCC > driver. > > The graphics clock driver depends upon the below change. > https://lkml.org/lkml/2018/6/23/108 > > Changes in v1: > This patch series adds support for graphics clock controller for SDM845. > Below is the brief description for each change: > > 1. For some of the GDSCs, there is requirement to enable/disable the > few clocks before turning on/off the gdsc power domain. This patch > will add support to enable/disable the clock associated with the > gdsc along with power domain on/off callbacks. > > 2. To turn on the gpu_gx_gdsc, there is a hardware requirement to > turn on the root clock (GFX3D RCG) first which would be the turn > on signal for the gdsc along with the SW_COLLAPSE. As per the > current implementation of clk_rcg2_shared_ops, it clears the > root_enable bit in the enable() clock ops. But due to the above > said requirement for GFX3D shared RCG, root_enable bit would be > already set by gdsc driver and rcg2_shared_ops should not clear > the root unless the disable() is called. > > This patch add support for the same by reusing the existing > clk_rcg2_shared_ops and deriving "clk_rcg2_gfx3d_ops" clk_ops > for GFX3D clock to take care of the root set/clear requirement. > > 3. Add device tree bindings for graphics clock controller for SDM845. > > 4. Add graphics clock controller (GPUCC) driver for SDM845. > > [v1] : https://lore.kernel.org/patchwork/project/lkml/list/?series=348697 > [v2] : https://lore.kernel.org/patchwork/project/lkml/list/?series=359012 > > Amit Nischal (4): > clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC > clk: qcom: Add clk_rcg2_gfx3d_ops for SDM845 > dt-bindings: clock: Introduce QCOM Graphics clock bindings > clk: qcom: Add graphics clock controller driver for SDM845 > > .../devicetree/bindings/clock/qcom,gpucc.txt | 18 + > drivers/clk/qcom/Kconfig | 9 + > drivers/clk/qcom/Makefile | 1 + > drivers/clk/qcom/clk-rcg.h | 1 + > drivers/clk/qcom/clk-rcg2.c | 86 +++- > drivers/clk/qcom/gdsc.c | 44 +++ > drivers/clk/qcom/gdsc.h | 5 + > drivers/clk/qcom/gpucc-sdm845.c | 438 +++++++++++++++++++++ > include/dt-bindings/clock/qcom,gpucc-sdm845.h | 38 ++ > 9 files changed, 638 insertions(+), 2 deletions(-) > create mode 100644 Documentation/devicetree/bindings/clock/qcom,gpucc.txt > create mode 100644 drivers/clk/qcom/gpucc-sdm845.c > create mode 100644 include/dt-bindings/clock/qcom,gpucc-sdm845.h This seems as good a place as any to kick off this discussion since it will influence what these patches look like the next go around. Settle in because this is going to get wordy... The sdm845 GPU is comprised of two nested power domains: CX and GX. Put simply from a CPU perspective the CX domain controls the GMU which is a microprocessor co-located with the GPU. The GMU in turn controls the GX domain which powers the GPU hardware. Under normal conditions the CPU powers on the CX domain and boots the GMU and then the GMU turns on the GX and controls it under the assumption that the GMU firmware can handle power collapse much faster than the CPU. The GMU continues to control the GX domain up and down until we are idle for long enough that we want to suspend the CX domain as well. When we want to suspend the GMU we trigger a shutdown process on the GMU which turns off GX and then the CPU turns off CX through the usual pm_runtime_put() sequence. Under these ideal circumstances the CPU should have no visibility into the GX at all - we should never control any headswitches or clocks anywhere in that domain. Except.... There is one case where the CPU needs to touch the GX: due to power sequencing requirements the GX needs to be turned off before the CX (and the CX needs to be enabled before the GX during power up). In the very rare situation where the GMU itself crashes and leaves the GX headswitch on the CPU needs to reach in and turn off the GX before turning off the CX and rebooting the GMU. This is problematic from a CPU perspective because there is no way to just go in and hack on the register directly; we need some infrastructure set up and ready to handle the odd use case. We discussed this a while at LPC and Stephen had a good idea. We should keep the GX gdsc but hack it so that the enable function does nothing (because we don't want the GPU to turn on the headswitch ever) but leave the disable function as is. Then we attach that genpd with dev_pm_attach_by_name() to the GMU device and power enable/disable it at the appropriate times. Most of the time the disable call will write to an already disabled headswitch but in that very special situation it will actually turn off the headswitch and the world can be right again. So I did this and it works. At least it works for the regular case. It is really difficult to cause the GMU to fault with the GX left on; I think I'm going to need to hack on the firmware to test that path but I've verified that the modified GDSC is toggling the power off before we suspend the CX so I think thats a win. I'll post patches against this patchset for an RFC but I mention it here because there are a bunch of clocks defined in gpucc-sdm845.c that are not needed ( either we never call them because we don't touch GX clocks or they are parents of uneeded clocks). It also seems like we don't need the clk_hws/clk_count infrastructure in gdsc.c. From my testing I can safely toggle the gx gdsc off from the CPU without 'gpu_cc_gx_gfx3d_clk_src'. Obviously we'll need some more review and I need the actual clock experts to weigh in but this is encouraging news because I think it lets us move ahead with gpucc and also solve my little nagging hardware workaround issue to boot. Look for patches shortly, in the mean time I'm going to comment to point out the clocks I don't think we need any more so Taniya can make a new patchset. Jordan -- The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2018-11-19 20:51 UTC | newest] Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2018-08-13 6:33 [PATCH v3 0/4] Add QCOM graphics clock controller driver for SDM845 Amit Nischal 2018-08-13 6:33 ` [PATCH v3 1/4] clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC Amit Nischal 2018-11-05 6:34 ` Stephen Boyd 2018-11-19 11:21 ` Taniya Das 2018-08-13 6:33 ` [PATCH v3 2/4] clk: qcom: Add clk_rcg2_gfx3d_ops for SDM845 Amit Nischal 2018-11-02 20:52 ` Stephen Boyd 2018-08-13 6:33 ` [PATCH v3 3/4] dt-bindings: clock: Introduce QCOM Graphics clock bindings Amit Nischal 2018-08-13 6:33 ` [PATCH v3 4/4] clk: qcom: Add graphics clock controller driver for SDM845 Amit Nischal 2018-11-05 6:37 ` Stephen Boyd 2018-11-19 11:32 ` Taniya Das 2018-11-19 20:51 ` Jordan Crouse 2018-11-19 20:45 ` [PATCH v3 0/4] Add QCOM " Jordan Crouse
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).