Hi Inki,
In case of some pipielines there is need to set clock in one component by driver of another component, for example: 1. Decon and Mixer driver must enable HDMI-PHY clock before configuration. 2. DP driver must enable DP clock provided by FIMD.
This set of patches provide more generic solution for such problem than currently present clock_enable callback. More details in particular patches. The patchset is based on recently sent patchset with HDMI/DECON path fixes[1].
[1]: http://permalink.gmane.org/gmane.comp.video.dri.devel/149714
Regards Andrzej
Andrzej Hajda (6): drm/exynos: add helper to get crtc from pipe drm/exynos: add support for pipeline clock to the framework drm/exynos/hdmi: expose HDMI-PHY clock as pipeline clock drm/exynos/decon5433: enable HDMI-PHY before configuring DECON drm/exynos/mixer: enable HDMI-PHY before configuring MIXER drm/exynos: convert clock_enable crtc callback to pipeline clock
drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 4 ++ drivers/gpu/drm/exynos/exynos_dp_core.c | 8 +--- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 10 ++-- drivers/gpu/drm/exynos/exynos_drm_drv.h | 25 ++++++++-- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 27 ++++++----- drivers/gpu/drm/exynos/exynos_hdmi.c | 67 +++++++++++++++++++-------- drivers/gpu/drm/exynos/exynos_mixer.c | 4 ++ 7 files changed, 95 insertions(+), 50 deletions(-)
The helper abstracts out conversion from pipeline to crtc. Currently it is used in two places, but there will be more uses in next patches.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 10 ++++------ drivers/gpu/drm/exynos/exynos_drm_drv.h | 8 ++++++++ 2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index e36579c..50dd33d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -157,9 +157,8 @@ err_crtc:
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe) { - struct exynos_drm_private *private = dev->dev_private; - struct exynos_drm_crtc *exynos_crtc = - to_exynos_crtc(private->crtc[pipe]); + struct exynos_drm_crtc *exynos_crtc = exynos_drm_crtc_from_pipe(dev, + pipe);
if (exynos_crtc->ops->enable_vblank) return exynos_crtc->ops->enable_vblank(exynos_crtc); @@ -169,9 +168,8 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe)
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, unsigned int pipe) { - struct exynos_drm_private *private = dev->dev_private; - struct exynos_drm_crtc *exynos_crtc = - to_exynos_crtc(private->crtc[pipe]); + struct exynos_drm_crtc *exynos_crtc = exynos_drm_crtc_from_pipe(dev, + pipe);
if (exynos_crtc->ops->disable_vblank) exynos_crtc->ops->disable_vblank(exynos_crtc); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 3f170ce..fcea940 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -232,6 +232,14 @@ struct exynos_drm_private { wait_queue_head_t wait; };
+static inline struct exynos_drm_crtc * +exynos_drm_crtc_from_pipe(struct drm_device *dev, int pipe) +{ + struct exynos_drm_private *private = dev->dev_private; + + return to_exynos_crtc(private->crtc[pipe]); +} + static inline struct device *to_dma_dev(struct drm_device *dev) { struct exynos_drm_private *priv = dev->dev_private;
Components belonging to the same pipeline often requires synchronized clocks. Such clocks are sometimes provided by external clock controller, but they can be also provided by pipeline components. In latter case there should be a way to access them from another component belonging to the same pipeline. This is the case of: - DECON,FIMD -> HDMI and HDMI-PHY clock, - FIMD -> DP and DP clock in FIMD. The latter case has been solved by clock_enable callback in exynos_drm_crtc_ops. This solutin will not work with HDMI path as in this case clock is provided by encoder.
This patch provides more generic solution allowing to register pipeline clock during initialization in exynos_drm_crtc structure. This way the clock will be easily accessible from both components.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index fcea940..6ee0b20 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -154,6 +154,10 @@ struct exynos_drm_crtc_ops { void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable); };
+struct exynos_drm_clk { + void (*enable)(struct exynos_drm_clk *clk, bool enable); +}; + /* * Exynos specific crtc structure. * @@ -182,8 +186,16 @@ struct exynos_drm_crtc { atomic_t pending_update; const struct exynos_drm_crtc_ops *ops; void *ctx; + struct exynos_drm_clk *pipe_clk; };
+static inline void exynos_drm_pipe_clk_enable(struct exynos_drm_crtc *crtc, + bool enable) +{ + if (crtc->pipe_clk) + crtc->pipe_clk->enable(crtc->pipe_clk, enable); +} + struct exynos_drm_g2d_private { struct device *dev; struct list_head inuse_cmdlist;
HDMI-PHY clock should be accessible from other components in the pipeline.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_hdmi.c | 67 ++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 49a5902..0d1c2f0 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -146,6 +146,7 @@ struct hdmi_context { struct clk **clk_muxes; struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)]; struct regulator *reg_hdmi_en; + struct exynos_drm_clk phy_clk; };
static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e) @@ -1448,7 +1449,6 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata)
static void hdmi_conf_apply(struct hdmi_context *hdata) { - hdmiphy_conf_apply(hdata); hdmi_start(hdata, false); hdmi_conf_init(hdata); hdmi_audio_init(hdata); @@ -1481,10 +1481,8 @@ static void hdmi_set_refclk(struct hdmi_context *hdata, bool on) SYSREG_HDMI_REFCLK_INT_CLK, on ? ~0 : 0); }
-static void hdmi_enable(struct drm_encoder *encoder) +static void hdmiphy_enable(struct hdmi_context *hdata) { - struct hdmi_context *hdata = encoder_to_hdmi(encoder); - if (hdata->powered) return;
@@ -1500,11 +1498,40 @@ static void hdmi_enable(struct drm_encoder *encoder)
hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0, HDMI_PHY_POWER_OFF_EN);
- hdmi_conf_apply(hdata); + hdmiphy_conf_apply(hdata);
hdata->powered = true; }
+static void hdmiphy_disable(struct hdmi_context *hdata) +{ + if (!hdata->powered) + return; + + hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN); + + hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0, HDMI_PHY_POWER_OFF_EN); + + hdmi_set_refclk(hdata, false); + + regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL, + PMU_HDMI_PHY_ENABLE_BIT, 0); + + regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk); + + pm_runtime_put_sync(hdata->dev); + + hdata->powered = false; +} + +static void hdmi_enable(struct drm_encoder *encoder) +{ + struct hdmi_context *hdata = encoder_to_hdmi(encoder); + + hdmiphy_enable(hdata); + hdmi_conf_apply(hdata); +} + static void hdmi_disable(struct drm_encoder *encoder) { struct hdmi_context *hdata = encoder_to_hdmi(encoder); @@ -1528,22 +1555,9 @@ static void hdmi_disable(struct drm_encoder *encoder) if (funcs && funcs->disable) (*funcs->disable)(crtc);
- hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN); - cancel_delayed_work(&hdata->hotplug_work);
- hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0, HDMI_PHY_POWER_OFF_EN); - - hdmi_set_refclk(hdata, false); - - regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL, - PMU_HDMI_PHY_ENABLE_BIT, 0); - - regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk); - - pm_runtime_put_sync(hdata->dev); - - hdata->powered = false; + hdmiphy_disable(hdata); }
static const struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = { @@ -1627,6 +1641,17 @@ static int hdmi_clk_init(struct hdmi_context *hdata) return hdmi_clks_get(hdata, &drv_data->clk_muxes, hdata->clk_muxes); }
+static void hdmiphy_clk_enable(struct exynos_drm_clk *clk, bool enable) +{ + struct hdmi_context *hdata = container_of(clk, struct hdmi_context, + phy_clk); + + if (enable) + hdmiphy_enable(hdata); + else + hdmiphy_disable(hdata); +} + static int hdmi_resources_init(struct hdmi_context *hdata) { struct device *dev = hdata->dev; @@ -1710,6 +1735,10 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) if (pipe < 0) return pipe;
+ hdata->phy_clk.enable = hdmiphy_clk_enable; + + exynos_drm_crtc_from_pipe(drm_dev, pipe)->pipe_clk = &hdata->phy_clk; + encoder->possible_crtcs = 1 << pipe;
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
Hi Inki,
It looks like this patch felt through the cracks. It is a part of "drm/exynos: add pipeline clock support" patchset. Other patches from the patchset were taken already. Could you queue it to next pull request?
Regards Andrzej
On 03/23/2016 02:25 PM, Andrzej Hajda wrote:
HDMI-PHY clock should be accessible from other components in the pipeline.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com
drivers/gpu/drm/exynos/exynos_hdmi.c | 67 ++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 49a5902..0d1c2f0 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -146,6 +146,7 @@ struct hdmi_context { struct clk **clk_muxes; struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)]; struct regulator *reg_hdmi_en;
- struct exynos_drm_clk phy_clk;
};
static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e) @@ -1448,7 +1449,6 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata)
static void hdmi_conf_apply(struct hdmi_context *hdata) {
- hdmiphy_conf_apply(hdata); hdmi_start(hdata, false); hdmi_conf_init(hdata); hdmi_audio_init(hdata);
@@ -1481,10 +1481,8 @@ static void hdmi_set_refclk(struct hdmi_context *hdata, bool on) SYSREG_HDMI_REFCLK_INT_CLK, on ? ~0 : 0); }
-static void hdmi_enable(struct drm_encoder *encoder) +static void hdmiphy_enable(struct hdmi_context *hdata) {
- struct hdmi_context *hdata = encoder_to_hdmi(encoder);
- if (hdata->powered) return;
@@ -1500,11 +1498,40 @@ static void hdmi_enable(struct drm_encoder *encoder)
hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0, HDMI_PHY_POWER_OFF_EN);
- hdmi_conf_apply(hdata);
hdmiphy_conf_apply(hdata);
hdata->powered = true;
}
+static void hdmiphy_disable(struct hdmi_context *hdata) +{
- if (!hdata->powered)
return;
- hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
- hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0, HDMI_PHY_POWER_OFF_EN);
- hdmi_set_refclk(hdata, false);
- regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
PMU_HDMI_PHY_ENABLE_BIT, 0);
- regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk);
- pm_runtime_put_sync(hdata->dev);
- hdata->powered = false;
+}
+static void hdmi_enable(struct drm_encoder *encoder) +{
- struct hdmi_context *hdata = encoder_to_hdmi(encoder);
- hdmiphy_enable(hdata);
- hdmi_conf_apply(hdata);
+}
static void hdmi_disable(struct drm_encoder *encoder) { struct hdmi_context *hdata = encoder_to_hdmi(encoder); @@ -1528,22 +1555,9 @@ static void hdmi_disable(struct drm_encoder *encoder) if (funcs && funcs->disable) (*funcs->disable)(crtc);
hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
cancel_delayed_work(&hdata->hotplug_work);
hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0, HDMI_PHY_POWER_OFF_EN);
hdmi_set_refclk(hdata, false);
regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
PMU_HDMI_PHY_ENABLE_BIT, 0);
regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk);
pm_runtime_put_sync(hdata->dev);
hdata->powered = false;
- hdmiphy_disable(hdata);
}
static const struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = { @@ -1627,6 +1641,17 @@ static int hdmi_clk_init(struct hdmi_context *hdata) return hdmi_clks_get(hdata, &drv_data->clk_muxes, hdata->clk_muxes); }
+static void hdmiphy_clk_enable(struct exynos_drm_clk *clk, bool enable) +{
- struct hdmi_context *hdata = container_of(clk, struct hdmi_context,
phy_clk);
- if (enable)
hdmiphy_enable(hdata);
- else
hdmiphy_disable(hdata);
+}
static int hdmi_resources_init(struct hdmi_context *hdata) { struct device *dev = hdata->dev; @@ -1710,6 +1735,10 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) if (pipe < 0) return pipe;
hdata->phy_clk.enable = hdmiphy_clk_enable;
exynos_drm_crtc_from_pipe(drm_dev, pipe)->pipe_clk = &hdata->phy_clk;
encoder->possible_crtcs = 1 << pipe;
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
Hi Andrzej,
2016-05-04 18:52 GMT+09:00 Andrzej Hajda a.hajda@samsung.com:
Hi Inki,
It looks like this patch felt through the cracks. It is a part of "drm/exynos: add pipeline clock support" patchset.
Ah, sorry.
Other patches from the patchset were taken already. Could you queue it to next pull request?
Got it.
Thanks, Inki Dae
Regards Andrzej
On 03/23/2016 02:25 PM, Andrzej Hajda wrote:
HDMI-PHY clock should be accessible from other components in the pipeline.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com
drivers/gpu/drm/exynos/exynos_hdmi.c | 67 ++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 49a5902..0d1c2f0 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -146,6 +146,7 @@ struct hdmi_context { struct clk **clk_muxes; struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)]; struct regulator *reg_hdmi_en;
struct exynos_drm_clk phy_clk;
};
static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e) @@ -1448,7 +1449,6 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata)
static void hdmi_conf_apply(struct hdmi_context *hdata) {
hdmiphy_conf_apply(hdata); hdmi_start(hdata, false); hdmi_conf_init(hdata); hdmi_audio_init(hdata);
@@ -1481,10 +1481,8 @@ static void hdmi_set_refclk(struct hdmi_context *hdata, bool on) SYSREG_HDMI_REFCLK_INT_CLK, on ? ~0 : 0); }
-static void hdmi_enable(struct drm_encoder *encoder) +static void hdmiphy_enable(struct hdmi_context *hdata) {
struct hdmi_context *hdata = encoder_to_hdmi(encoder);
if (hdata->powered) return;
@@ -1500,11 +1498,40 @@ static void hdmi_enable(struct drm_encoder *encoder)
hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0, HDMI_PHY_POWER_OFF_EN);
hdmi_conf_apply(hdata);
hdmiphy_conf_apply(hdata); hdata->powered = true;
}
+static void hdmiphy_disable(struct hdmi_context *hdata) +{
if (!hdata->powered)
return;
hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0, HDMI_PHY_POWER_OFF_EN);
hdmi_set_refclk(hdata, false);
regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
PMU_HDMI_PHY_ENABLE_BIT, 0);
regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk);
pm_runtime_put_sync(hdata->dev);
hdata->powered = false;
+}
+static void hdmi_enable(struct drm_encoder *encoder) +{
struct hdmi_context *hdata = encoder_to_hdmi(encoder);
hdmiphy_enable(hdata);
hdmi_conf_apply(hdata);
+}
static void hdmi_disable(struct drm_encoder *encoder) { struct hdmi_context *hdata = encoder_to_hdmi(encoder); @@ -1528,22 +1555,9 @@ static void hdmi_disable(struct drm_encoder *encoder) if (funcs && funcs->disable) (*funcs->disable)(crtc);
hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
cancel_delayed_work(&hdata->hotplug_work);
hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0, HDMI_PHY_POWER_OFF_EN);
hdmi_set_refclk(hdata, false);
regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
PMU_HDMI_PHY_ENABLE_BIT, 0);
regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk);
pm_runtime_put_sync(hdata->dev);
hdata->powered = false;
hdmiphy_disable(hdata);
}
static const struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = { @@ -1627,6 +1641,17 @@ static int hdmi_clk_init(struct hdmi_context *hdata) return hdmi_clks_get(hdata, &drv_data->clk_muxes, hdata->clk_muxes); }
+static void hdmiphy_clk_enable(struct exynos_drm_clk *clk, bool enable) +{
struct hdmi_context *hdata = container_of(clk, struct hdmi_context,
phy_clk);
if (enable)
hdmiphy_enable(hdata);
else
hdmiphy_disable(hdata);
+}
static int hdmi_resources_init(struct hdmi_context *hdata) { struct device *dev = hdata->dev; @@ -1710,6 +1735,10 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) if (pipe < 0) return pipe;
hdata->phy_clk.enable = hdmiphy_clk_enable;
exynos_drm_crtc_from_pipe(drm_dev, pipe)->pipe_clk = &hdata->phy_clk;
encoder->possible_crtcs = 1 << pipe; DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
According to documentation and tests HDMI-PHY must be on prior to MIXER configuration.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index c8c921c..26b582c 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -393,6 +393,8 @@ static void decon_enable(struct exynos_drm_crtc *crtc)
pm_runtime_get_sync(ctx->dev);
+ exynos_drm_pipe_clk_enable(crtc, true); + set_bit(BIT_CLKS_ENABLED, &ctx->flags);
decon_swreset(ctx); @@ -424,6 +426,8 @@ static void decon_disable(struct exynos_drm_crtc *crtc)
clear_bit(BIT_CLKS_ENABLED, &ctx->flags);
+ exynos_drm_pipe_clk_enable(crtc, false); + pm_runtime_put_sync(ctx->dev);
set_bit(BIT_SUSPENDED, &ctx->flags);
According to documentation HDMI-PHY must be on prior to MIXER configuration.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_mixer.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 0a5a600..27f36c0 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1065,6 +1065,8 @@ static void mixer_enable(struct exynos_drm_crtc *crtc)
pm_runtime_get_sync(ctx->dev);
+ exynos_drm_pipe_clk_enable(crtc, true); + mixer_vsync_set_update(ctx, false);
mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET); @@ -1094,6 +1096,8 @@ static void mixer_disable(struct exynos_drm_crtc *crtc) for (i = 0; i < MIXER_WIN_NR; i++) mixer_disable_plane(crtc, &ctx->planes[i]);
+ exynos_drm_pipe_clk_enable(crtc, false); + pm_runtime_put(ctx->dev);
clear_bit(MXR_BIT_POWERED, &ctx->flags);
clock_enable callback is used only by FIMD->DP pipeline. Similar but more universal functionality provides pipeline clock.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_dp_core.c | 8 ++------ drivers/gpu/drm/exynos/exynos_drm_drv.h | 5 ----- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 27 +++++++++++++-------------- 3 files changed, 15 insertions(+), 25 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index cff8dc7..ebb96eb 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -1054,7 +1054,6 @@ static int exynos_dp_bridge_attach(struct drm_bridge *bridge) static void exynos_dp_bridge_enable(struct drm_bridge *bridge) { struct exynos_dp_device *dp = bridge->driver_private; - struct exynos_drm_crtc *crtc = dp_to_crtc(dp);
if (dp->dpms_mode == DRM_MODE_DPMS_ON) return; @@ -1068,8 +1067,7 @@ static void exynos_dp_bridge_enable(struct drm_bridge *bridge) } }
- if (crtc->ops->clock_enable) - crtc->ops->clock_enable(dp_to_crtc(dp), true); + exynos_drm_pipe_clk_enable(dp_to_crtc(dp), true);
phy_power_on(dp->phy); exynos_dp_init_dp(dp); @@ -1082,7 +1080,6 @@ static void exynos_dp_bridge_enable(struct drm_bridge *bridge) static void exynos_dp_bridge_disable(struct drm_bridge *bridge) { struct exynos_dp_device *dp = bridge->driver_private; - struct exynos_drm_crtc *crtc = dp_to_crtc(dp);
if (dp->dpms_mode != DRM_MODE_DPMS_ON) return; @@ -1098,8 +1095,7 @@ static void exynos_dp_bridge_disable(struct drm_bridge *bridge) flush_work(&dp->hotplug_work); phy_power_off(dp->phy);
- if (crtc->ops->clock_enable) - crtc->ops->clock_enable(dp_to_crtc(dp), false); + exynos_drm_pipe_clk_enable(dp_to_crtc(dp), false);
if (dp->panel) { if (drm_panel_unprepare(dp->panel)) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 6ee0b20..1542910 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -129,10 +129,6 @@ struct exynos_drm_plane_config { * @disable_plane: disable hardware specific overlay. * @te_handler: trigger to transfer video image at the tearing effect * synchronization signal if there is a page flip request. - * @clock_enable: optional function enabling/disabling display domain clock, - * called from exynos-dp driver before powering up (with - * 'enable' argument as true) and after powering down (with - * 'enable' as false). */ struct exynos_drm_crtc; struct exynos_drm_crtc_ops { @@ -151,7 +147,6 @@ struct exynos_drm_crtc_ops { struct exynos_drm_plane *plane); void (*atomic_flush)(struct exynos_drm_crtc *crtc); void (*te_handler)(struct exynos_drm_crtc *crtc); - void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable); };
struct exynos_drm_clk { diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 51d484a..004bf57 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -102,6 +102,7 @@ struct fimd_driver_data { unsigned int has_vidoutcon:1; unsigned int has_vtsel:1; unsigned int has_mic_bypass:1; + unsigned int has_dp_clk:1; };
static struct fimd_driver_data s3c64xx_fimd_driver_data = { @@ -145,6 +146,7 @@ static struct fimd_driver_data exynos5_fimd_driver_data = { .has_shadowcon = 1, .has_vidoutcon = 1, .has_vtsel = 1, + .has_dp_clk = 1, };
static struct fimd_driver_data exynos5420_fimd_driver_data = { @@ -157,6 +159,7 @@ static struct fimd_driver_data exynos5420_fimd_driver_data = { .has_vidoutcon = 1, .has_vtsel = 1, .has_mic_bypass = 1, + .has_dp_clk = 1, };
struct fimd_context { @@ -184,6 +187,7 @@ struct fimd_context {
struct fimd_driver_data *driver_data; struct drm_encoder *encoder; + struct exynos_drm_clk dp_clk; };
static const struct of_device_id fimd_driver_dt_match[] = { @@ -878,21 +882,12 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc) drm_crtc_handle_vblank(&ctx->crtc->base); }
-static void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable) +static void fimd_dp_clock_enable(struct exynos_drm_clk *clk, bool enable) { - struct fimd_context *ctx = crtc->ctx; - u32 val; - - /* - * Only Exynos 5250, 5260, 5410 and 542x requires enabling DP/MIE - * clock. On these SoCs the bootloader may enable it but any - * power domain off/on will reset it to disable state. - */ - if (ctx->driver_data != &exynos5_fimd_driver_data || - ctx->driver_data != &exynos5420_fimd_driver_data) - return; + struct fimd_context *ctx = container_of(clk, struct fimd_context, + dp_clk); + u32 val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE;
- val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE; writel(val, ctx->regs + DP_MIE_CLKCON); }
@@ -908,7 +903,6 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = { .disable_plane = fimd_disable_plane, .atomic_flush = fimd_atomic_flush, .te_handler = fimd_te_handler, - .clock_enable = fimd_dp_clock_enable, };
static irqreturn_t fimd_irq_handler(int irq, void *dev_id) @@ -987,6 +981,11 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) if (IS_ERR(ctx->crtc)) return PTR_ERR(ctx->crtc);
+ if (ctx->driver_data->has_dp_clk) { + ctx->dp_clk.enable = fimd_dp_clock_enable; + ctx->crtc->pipe_clk = &ctx->dp_clk; + } + if (ctx->encoder) exynos_dpi_bind(drm_dev, ctx->encoder);
dri-devel@lists.freedesktop.org