Changes in v2 - Patch 2: Dropped dsi_link_clk_set_rate_6g_v2 and dsi_link_clk_disable_6g_v2 as suggested by Matthias
These patches add DVFS support for DPU and DSI.
These patches have no other dependency. Patch 1 and 2 will need to be merged in via the MSM DRM tree.
DT patches will need to land via the msm tree.
Rajendra Nayak (4): drm/msm/dpu: Use OPP API to set clk/perf state drm/msm: dsi: Use OPP API to set clk/perf state arm64: dts: sdm845: Add DSI and MDP OPP tables and power-domains arm64: dts: sc7180: Add DSI and MDP OPP tables and power-domains
arch/arm64/boot/dts/qcom/sc7180.dtsi | 49 ++++++++++++++++++++++ arch/arm64/boot/dts/qcom/sdm845.dtsi | 59 +++++++++++++++++++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c | 3 +- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 26 +++++++++++- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 4 ++ drivers/gpu/drm/msm/dsi/dsi_host.c | 26 +++++++++++- 6 files changed, 163 insertions(+), 4 deletions(-)
On some qualcomm platforms DPU needs to express a performance state requirement on a power domain depending on the clock rates. Use OPP table from DT to register with OPP framework and use dev_pm_opp_set_rate() to set the clk/perf state.
Signed-off-by: Rajendra Nayak rnayak@codeaurora.org Reviewed-by: Rob Clark robdclark@chromium.org Reviewed-by: Matthias Kaehlcke mka@chromium.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c | 3 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 26 +++++++++++++++++++++++++- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 4 ++++ 3 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c index 7c230f7..b36919d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c @@ -7,6 +7,7 @@ #include <linux/debugfs.h> #include <linux/errno.h> #include <linux/mutex.h> +#include <linux/pm_opp.h> #include <linux/sort.h> #include <linux/clk.h> #include <linux/bitmap.h> @@ -218,7 +219,7 @@ static int _dpu_core_perf_set_core_clk_rate(struct dpu_kms *kms, u64 rate) rate = core_clk->max_rate;
core_clk->rate = rate; - return msm_dss_clk_set_rate(core_clk, 1); + return dev_pm_opp_set_rate(&kms->pdev->dev, core_clk->rate); }
static u64 _dpu_core_perf_get_core_clk_rate(struct dpu_kms *kms) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index b8615d4..0bc8ec4 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -10,6 +10,7 @@ #include <linux/debugfs.h> #include <linux/dma-buf.h> #include <linux/of_irq.h> +#include <linux/pm_opp.h>
#include <drm/drm_crtc.h> #include <drm/drm_file.h> @@ -1025,11 +1026,23 @@ static int dpu_bind(struct device *dev, struct device *master, void *data) if (!dpu_kms) return -ENOMEM;
+ dpu_kms->opp_table = dev_pm_opp_set_clkname(dev, "core"); + if (IS_ERR(dpu_kms->opp_table)) + return PTR_ERR(dpu_kms->opp_table); + /* OPP table is optional */ + ret = dev_pm_opp_of_add_table(dev); + if (!ret) { + dpu_kms->has_opp_table = true; + } else if (ret != -ENODEV) { + dev_err(dev, "invalid OPP table in device tree\n"); + return ret; + } + mp = &dpu_kms->mp; ret = msm_dss_parse_clock(pdev, mp); if (ret) { DPU_ERROR("failed to parse clocks, ret=%d\n", ret); - return ret; + goto err; }
platform_set_drvdata(pdev, dpu_kms); @@ -1043,6 +1056,11 @@ static int dpu_bind(struct device *dev, struct device *master, void *data)
priv->kms = &dpu_kms->base; return ret; +err: + if (dpu_kms->has_opp_table) + dev_pm_opp_of_remove_table(dev); + dev_pm_opp_put_clkname(dpu_kms->opp_table); + return ret; }
static void dpu_unbind(struct device *dev, struct device *master, void *data) @@ -1057,6 +1075,10 @@ static void dpu_unbind(struct device *dev, struct device *master, void *data)
if (dpu_kms->rpm_enabled) pm_runtime_disable(&pdev->dev); + + if (dpu_kms->has_opp_table) + dev_pm_opp_of_remove_table(dev); + dev_pm_opp_put_clkname(dpu_kms->opp_table); }
static const struct component_ops dpu_ops = { @@ -1082,6 +1104,8 @@ static int __maybe_unused dpu_runtime_suspend(struct device *dev) struct dpu_kms *dpu_kms = platform_get_drvdata(pdev); struct dss_module_power *mp = &dpu_kms->mp;
+ /* Drop the performance state vote */ + dev_pm_opp_set_rate(dev, 0); rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, false); if (rc) DPU_ERROR("clock disable failed rc:%d\n", rc); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index a3b122b..7400cd7 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -128,6 +128,10 @@ struct dpu_kms {
struct platform_device *pdev; bool rpm_enabled; + + struct opp_table *opp_table; + bool has_opp_table; + struct dss_module_power mp;
/* reference count bandwidth requests, so we know when we can
On SDM845 and SC7180 DSI needs to express a performance state requirement on a power domain depending on the clock rates. Use OPP table from DT to register with OPP framework and use dev_pm_opp_set_rate() to set the clk/perf state.
dev_pm_opp_set_rate() is designed to be equivalent to clk_set_rate() for devices without an OPP table, hence the change works fine on devices/platforms which only need to set a clock rate.
Signed-off-by: Rajendra Nayak rnayak@codeaurora.org --- drivers/gpu/drm/msm/dsi/dsi_host.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 11ae5b8..09e16b8 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -14,6 +14,7 @@ #include <linux/of_graph.h> #include <linux/of_irq.h> #include <linux/pinctrl/consumer.h> +#include <linux/pm_opp.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/spinlock.h> @@ -111,6 +112,9 @@ struct msm_dsi_host { struct clk *pixel_clk_src; struct clk *byte_intf_clk;
+ struct opp_table *opp_table; + bool has_opp_table; + u32 byte_clk_rate; u32 pixel_clk_rate; u32 esc_clk_rate; @@ -512,9 +516,10 @@ int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host) DBG("Set clk rates: pclk=%d, byteclk=%d", msm_host->mode->clock, msm_host->byte_clk_rate);
- ret = clk_set_rate(msm_host->byte_clk, msm_host->byte_clk_rate); + ret = dev_pm_opp_set_rate(&msm_host->pdev->dev, + msm_host->byte_clk_rate); if (ret) { - pr_err("%s: Failed to set rate byte clk, %d\n", __func__, ret); + pr_err("%s: dev_pm_opp_set_rate failed %d\n", __func__, ret); return ret; }
@@ -658,6 +663,8 @@ int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host)
void dsi_link_clk_disable_6g(struct msm_dsi_host *msm_host) { + /* Drop the performance state vote */ + dev_pm_opp_set_rate(&msm_host->pdev->dev, 0); clk_disable_unprepare(msm_host->esc_clk); clk_disable_unprepare(msm_host->pixel_clk); if (msm_host->byte_intf_clk) @@ -1879,6 +1886,18 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) goto fail; }
+ msm_host->opp_table = dev_pm_opp_set_clkname(&pdev->dev, "byte"); + if (IS_ERR(msm_host->opp_table)) + return PTR_ERR(msm_host->opp_table); + /* OPP table is optional */ + ret = dev_pm_opp_of_add_table(&pdev->dev); + if (!ret) { + msm_host->has_opp_table = true; + } else if (ret != -ENODEV) { + dev_err(&pdev->dev, "invalid OPP table in device tree\n"); + return ret; + } + init_completion(&msm_host->dma_comp); init_completion(&msm_host->video_comp); mutex_init(&msm_host->dev_mutex); @@ -1914,6 +1933,9 @@ void msm_dsi_host_destroy(struct mipi_dsi_host *host) mutex_destroy(&msm_host->cmd_mutex); mutex_destroy(&msm_host->dev_mutex);
+ if (msm_host->has_opp_table) + dev_pm_opp_of_remove_table(&msm_host->pdev->dev); + dev_pm_opp_put_clkname(msm_host->opp_table); pm_runtime_disable(&msm_host->pdev->dev); }
On Thu, Jul 02, 2020 at 04:39:09PM +0530, Rajendra Nayak wrote:
On SDM845 and SC7180 DSI needs to express a performance state requirement on a power domain depending on the clock rates. Use OPP table from DT to register with OPP framework and use dev_pm_opp_set_rate() to set the clk/perf state.
dev_pm_opp_set_rate() is designed to be equivalent to clk_set_rate() for devices without an OPP table, hence the change works fine on devices/platforms which only need to set a clock rate.
Signed-off-by: Rajendra Nayak rnayak@codeaurora.org
drivers/gpu/drm/msm/dsi/dsi_host.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 11ae5b8..09e16b8 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -14,6 +14,7 @@ #include <linux/of_graph.h> #include <linux/of_irq.h> #include <linux/pinctrl/consumer.h> +#include <linux/pm_opp.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/spinlock.h> @@ -111,6 +112,9 @@ struct msm_dsi_host { struct clk *pixel_clk_src; struct clk *byte_intf_clk;
- struct opp_table *opp_table;
- bool has_opp_table;
- u32 byte_clk_rate; u32 pixel_clk_rate; u32 esc_clk_rate;
@@ -512,9 +516,10 @@ int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host) DBG("Set clk rates: pclk=%d, byteclk=%d", msm_host->mode->clock, msm_host->byte_clk_rate);
- ret = clk_set_rate(msm_host->byte_clk, msm_host->byte_clk_rate);
- ret = dev_pm_opp_set_rate(&msm_host->pdev->dev,
if (ret) {msm_host->byte_clk_rate);
pr_err("%s: Failed to set rate byte clk, %d\n", __func__, ret);
return ret; }pr_err("%s: dev_pm_opp_set_rate failed %d\n", __func__, ret);
@@ -658,6 +663,8 @@ int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host)
void dsi_link_clk_disable_6g(struct msm_dsi_host *msm_host) {
- /* Drop the performance state vote */
- dev_pm_opp_set_rate(&msm_host->pdev->dev, 0); clk_disable_unprepare(msm_host->esc_clk); clk_disable_unprepare(msm_host->pixel_clk); if (msm_host->byte_intf_clk)
@@ -1879,6 +1886,18 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) goto fail; }
- msm_host->opp_table = dev_pm_opp_set_clkname(&pdev->dev, "byte");
- if (IS_ERR(msm_host->opp_table))
return PTR_ERR(msm_host->opp_table);
- /* OPP table is optional */
- ret = dev_pm_opp_of_add_table(&pdev->dev);
- if (!ret) {
msm_host->has_opp_table = true;
- } else if (ret != -ENODEV) {
dev_err(&pdev->dev, "invalid OPP table in device tree\n");
dev_pm_opp_put_clkname(msm_host->opp_table);
return ret;
- }
With the missing _put_clkname() fixed:
Reviewed-by: Matthias Kaehlcke mka@chromium.org
On 7/6/2020 9:40 PM, Matthias Kaehlcke wrote:
On Thu, Jul 02, 2020 at 04:39:09PM +0530, Rajendra Nayak wrote:
On SDM845 and SC7180 DSI needs to express a performance state requirement on a power domain depending on the clock rates. Use OPP table from DT to register with OPP framework and use dev_pm_opp_set_rate() to set the clk/perf state.
dev_pm_opp_set_rate() is designed to be equivalent to clk_set_rate() for devices without an OPP table, hence the change works fine on devices/platforms which only need to set a clock rate.
Signed-off-by: Rajendra Nayak rnayak@codeaurora.org
drivers/gpu/drm/msm/dsi/dsi_host.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 11ae5b8..09e16b8 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -14,6 +14,7 @@ #include <linux/of_graph.h> #include <linux/of_irq.h> #include <linux/pinctrl/consumer.h> +#include <linux/pm_opp.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/spinlock.h> @@ -111,6 +112,9 @@ struct msm_dsi_host { struct clk *pixel_clk_src; struct clk *byte_intf_clk;
- struct opp_table *opp_table;
- bool has_opp_table;
- u32 byte_clk_rate; u32 pixel_clk_rate; u32 esc_clk_rate;
@@ -512,9 +516,10 @@ int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host) DBG("Set clk rates: pclk=%d, byteclk=%d", msm_host->mode->clock, msm_host->byte_clk_rate);
- ret = clk_set_rate(msm_host->byte_clk, msm_host->byte_clk_rate);
- ret = dev_pm_opp_set_rate(&msm_host->pdev->dev,
if (ret) {msm_host->byte_clk_rate);
pr_err("%s: Failed to set rate byte clk, %d\n", __func__, ret);
return ret; }pr_err("%s: dev_pm_opp_set_rate failed %d\n", __func__, ret);
@@ -658,6 +663,8 @@ int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host)
void dsi_link_clk_disable_6g(struct msm_dsi_host *msm_host) {
- /* Drop the performance state vote */
- dev_pm_opp_set_rate(&msm_host->pdev->dev, 0); clk_disable_unprepare(msm_host->esc_clk); clk_disable_unprepare(msm_host->pixel_clk); if (msm_host->byte_intf_clk)
@@ -1879,6 +1886,18 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) goto fail; }
- msm_host->opp_table = dev_pm_opp_set_clkname(&pdev->dev, "byte");
- if (IS_ERR(msm_host->opp_table))
return PTR_ERR(msm_host->opp_table);
- /* OPP table is optional */
- ret = dev_pm_opp_of_add_table(&pdev->dev);
- if (!ret) {
msm_host->has_opp_table = true;
- } else if (ret != -ENODEV) {
dev_err(&pdev->dev, "invalid OPP table in device tree\n");
dev_pm_opp_put_clkname(msm_host->opp_table);
return ret;
- }
With the missing _put_clkname() fixed:
Thanks, I'll fix and resend.
Reviewed-by: Matthias Kaehlcke mka@chromium.org
Add the OPP tables for DSI and MDP based on the perf state/clk requirements, and add the power-domains property to specify the scalable power domain.
Signed-off-by: Rajendra Nayak rnayak@codeaurora.org Reviewed-by: Matthias Kaehlcke mka@chromium.org --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 59 ++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 8eb5a31..b6afeb2 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -3296,6 +3296,35 @@ #power-domain-cells = <1>; };
+ dsi_opp_table: dsi-opp-table { + compatible = "operating-points-v2"; + + opp-19200000 { + opp-hz = /bits/ 64 <19200000>; + required-opps = <&rpmhpd_opp_min_svs>; + }; + + opp-180000000 { + opp-hz = /bits/ 64 <180000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-275000000 { + opp-hz = /bits/ 64 <275000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-328580000 { + opp-hz = /bits/ 64 <328580000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-358000000 { + opp-hz = /bits/ 64 <358000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + mdss: mdss@ae00000 { compatible = "qcom,sdm845-mdss"; reg = <0 0x0ae00000 0 0x1000>; @@ -3340,6 +3369,8 @@ <&dispcc DISP_CC_MDSS_VSYNC_CLK>; assigned-clock-rates = <300000000>, <19200000>; + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmhpd SDM845_CX>;
interrupt-parent = <&mdss>; interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; @@ -3364,6 +3395,30 @@ }; }; }; + + mdp_opp_table: mdp-opp-table { + compatible = "operating-points-v2"; + + opp-19200000 { + opp-hz = /bits/ 64 <19200000>; + required-opps = <&rpmhpd_opp_min_svs>; + }; + + opp-171428571 { + opp-hz = /bits/ 64 <171428571>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-344000000 { + opp-hz = /bits/ 64 <344000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-430000000 { + opp-hz = /bits/ 64 <430000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; };
dsi0: dsi@ae94000 { @@ -3386,6 +3441,8 @@ "core", "iface", "bus"; + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd SDM845_CX>;
phys = <&dsi0_phy>; phy-names = "dsi"; @@ -3450,6 +3507,8 @@ "core", "iface", "bus"; + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd SDM845_CX>;
phys = <&dsi1_phy>; phy-names = "dsi";
Add the OPP tables for DSI and MDP based on the perf state/clk requirements, and add the power-domains property to specify the scalable power domain.
Signed-off-by: Rajendra Nayak rnayak@codeaurora.org Reviewed-by: Matthias Kaehlcke mka@chromium.org --- arch/arm64/boot/dts/qcom/sc7180.dtsi | 49 ++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi index ad57df2..3430c33f 100644 --- a/arch/arm64/boot/dts/qcom/sc7180.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi @@ -2482,6 +2482,8 @@ <19200000>, <19200000>, <19200000>; + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmhpd SC7180_CX>;
interrupt-parent = <&mdss>; interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; @@ -2499,6 +2501,31 @@ }; }; }; + + mdp_opp_table: mdp-opp-table { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-345000000 { + opp-hz = /bits/ 64 <345000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-460000000 { + opp-hz = /bits/ 64 <460000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + };
dsi0: dsi@ae94000 { @@ -2522,6 +2549,9 @@ "iface", "bus";
+ operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd SC7180_CX>; + phys = <&dsi_phy>; phy-names = "dsi";
@@ -2547,6 +2577,25 @@ }; }; }; + + dsi_opp_table: dsi-opp-table { + compatible = "operating-points-v2"; + + opp-187500000 { + opp-hz = /bits/ 64 <187500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-358000000 { + opp-hz = /bits/ 64 <358000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; };
dsi_phy: dsi-phy@ae94400 {
dri-devel@lists.freedesktop.org