Re: [RFC PATCH 11/11] drm: exynos: mixer: Add interconnect support

2019-07-24 Thread Krzysztof Kozlowski
On Tue, Jul 23, 2019 at 02:20:16PM +0200, Artur Świgoń wrote:
> From: Marek Szyprowski 
> 
> This patch adds interconnect support to exynos-mixer. Please note that the
> mixer works the same as before when CONFIG_INTERCONNECT is 'n'.
> 
> Co-developed-by: Artur Świgoń 
> Signed-off-by: Artur Świgoń 
> Signed-off-by: Marek Szyprowski 
> ---
>  drivers/gpu/drm/exynos/exynos_mixer.c | 68 +--
>  1 file changed, 63 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c 
> b/drivers/gpu/drm/exynos/exynos_mixer.c
> index 7b24338fad3c..fb763854b300 100644
> --- a/drivers/gpu/drm/exynos/exynos_mixer.c
> +++ b/drivers/gpu/drm/exynos/exynos_mixer.c
> @@ -13,6 +13,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -97,6 +98,7 @@ struct mixer_context {
>   struct exynos_drm_crtc  *crtc;
>   struct exynos_drm_plane planes[MIXER_WIN_NR];
>   unsigned long   flags;
> + struct icc_path *soc_path;
>  
>   int irq;
>   void __iomem*mixer_regs;
> @@ -931,6 +933,37 @@ static void mixer_disable_vblank(struct exynos_drm_crtc 
> *crtc)
>   mixer_reg_writemask(mixer_ctx, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
>  }
>  
> +static void mixer_set_memory_bandwidth(struct exynos_drm_crtc *crtc)
> +{
> + struct drm_display_mode *mode = &crtc->base.state->adjusted_mode;
> + struct mixer_context *ctx = crtc->ctx;
> + unsigned long bw, bandwidth = 0;
> + int i, j, sub;
> +

Early exit if !ctx->soc_path, no need to figure out the bandwidth.
Optionally check it before calling mixer_set_memory_bandwidth() - should
not hurt readability.

> + for (i = 0; i < MIXER_WIN_NR; i++) {
> + struct drm_plane *plane = &ctx->planes[i].base;
> + const struct drm_format_info *format;
> +
> + if (plane->state && plane->state->crtc && plane->state->fb) {
> + format = plane->state->fb->format;
> + bw = mode->hdisplay * mode->vdisplay *
> + drm_mode_vrefresh(mode);
> + if (mode->flags & DRM_MODE_FLAG_INTERLACE)
> + bw /= 2;
> + for (j = 0; j < format->num_planes; j++) {
> + sub = j ? (format->vsub * format->hsub) : 1;
> + bandwidth += format->cpp[j] * bw / sub;
> + }
> + }
> + }
> +
> + /* add 20% safety margin */
> + bandwidth = 5UL * bandwidth / 4;
> +
> + pr_info("exynos-mixer: safe bandwidth %ld Bps\n", bandwidth);

dev_dbg()

Best regards,
Krzysztof


___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[RFC PATCH 11/11] drm: exynos: mixer: Add interconnect support

2019-07-23 Thread Artur Świgoń
From: Marek Szyprowski 

This patch adds interconnect support to exynos-mixer. Please note that the
mixer works the same as before when CONFIG_INTERCONNECT is 'n'.

Co-developed-by: Artur Świgoń 
Signed-off-by: Artur Świgoń 
Signed-off-by: Marek Szyprowski 
---
 drivers/gpu/drm/exynos/exynos_mixer.c | 68 +--
 1 file changed, 63 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c 
b/drivers/gpu/drm/exynos/exynos_mixer.c
index 7b24338fad3c..fb763854b300 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -13,6 +13,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -97,6 +98,7 @@ struct mixer_context {
struct exynos_drm_crtc  *crtc;
struct exynos_drm_plane planes[MIXER_WIN_NR];
unsigned long   flags;
+   struct icc_path *soc_path;
 
int irq;
void __iomem*mixer_regs;
@@ -931,6 +933,37 @@ static void mixer_disable_vblank(struct exynos_drm_crtc 
*crtc)
mixer_reg_writemask(mixer_ctx, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
 }
 
+static void mixer_set_memory_bandwidth(struct exynos_drm_crtc *crtc)
+{
+   struct drm_display_mode *mode = &crtc->base.state->adjusted_mode;
+   struct mixer_context *ctx = crtc->ctx;
+   unsigned long bw, bandwidth = 0;
+   int i, j, sub;
+
+   for (i = 0; i < MIXER_WIN_NR; i++) {
+   struct drm_plane *plane = &ctx->planes[i].base;
+   const struct drm_format_info *format;
+
+   if (plane->state && plane->state->crtc && plane->state->fb) {
+   format = plane->state->fb->format;
+   bw = mode->hdisplay * mode->vdisplay *
+   drm_mode_vrefresh(mode);
+   if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+   bw /= 2;
+   for (j = 0; j < format->num_planes; j++) {
+   sub = j ? (format->vsub * format->hsub) : 1;
+   bandwidth += format->cpp[j] * bw / sub;
+   }
+   }
+   }
+
+   /* add 20% safety margin */
+   bandwidth = 5UL * bandwidth / 4;
+
+   pr_info("exynos-mixer: safe bandwidth %ld Bps\n", bandwidth);
+   icc_set_bw(ctx->soc_path, 0, Bps_to_icc(bandwidth));
+}
+
 static void mixer_atomic_begin(struct exynos_drm_crtc *crtc)
 {
struct mixer_context *ctx = crtc->ctx;
@@ -982,6 +1015,7 @@ static void mixer_atomic_flush(struct exynos_drm_crtc 
*crtc)
if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
return;
 
+   mixer_set_memory_bandwidth(crtc);
mixer_enable_sync(mixer_ctx);
exynos_crtc_handle_event(crtc);
 }
@@ -1029,6 +1063,7 @@ static void mixer_disable(struct exynos_drm_crtc *crtc)
for (i = 0; i < MIXER_WIN_NR; i++)
mixer_disable_plane(crtc, &ctx->planes[i]);
 
+   mixer_set_memory_bandwidth(crtc);
exynos_drm_pipe_clk_enable(crtc, false);
 
pm_runtime_put(ctx->dev);
@@ -1220,12 +1255,22 @@ static int mixer_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
const struct mixer_drv_data *drv;
struct mixer_context *ctx;
+   struct icc_path *path;
int ret;
 
+   /*
+* Returns NULL if CONFIG_INTERCONNECT is disabled.
+* May return ERR_PTR(-EPROBE_DEFER).
+*/
+   path = of_icc_get(dev, NULL);
+   if (IS_ERR(path))
+   return PTR_ERR(path);
+
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx) {
DRM_DEV_ERROR(dev, "failed to alloc mixer context.\n");
-   return -ENOMEM;
+   ret = -ENOMEM;
+   goto err;
}
 
drv = of_device_get_match_data(dev);
@@ -1233,6 +1278,7 @@ static int mixer_probe(struct platform_device *pdev)
ctx->pdev = pdev;
ctx->dev = dev;
ctx->mxr_ver = drv->version;
+   ctx->soc_path = path;
 
if (drv->is_vp_enabled)
__set_bit(MXR_BIT_VP_ENABLED, &ctx->flags);
@@ -1242,17 +1288,29 @@ static int mixer_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ctx);
 
ret = component_add(&pdev->dev, &mixer_component_ops);
-   if (!ret)
-   pm_runtime_enable(dev);
+   if (ret < 0)
+   goto err;
+
+   pm_runtime_enable(dev);
+
+   return 0;
+
+err:
+   icc_put(path);
 
return ret;
 }
 
 static int mixer_remove(struct platform_device *pdev)
 {
-   pm_runtime_disable(&pdev->dev);
+   struct device *dev = &pdev->dev;
+   struct mixer_context *ctx = dev_get_drvdata(dev);
 
-   component_del(&pdev->dev, &mixer_component_ops);
+   pm_runtime_disable(dev);
+
+   component_del(dev, &mixer_component_ops);
+
+   icc