drm/exynos: gsc: Add support for tiled formats
authorMarek Szyprowski <m.szyprowski@samsung.com>
Fri, 10 Aug 2018 13:29:01 +0000 (15:29 +0200)
committerInki Dae <inki.dae@samsung.com>
Sun, 30 Sep 2018 23:33:26 +0000 (08:33 +0900)
Add support for 16x16 tiled NV12 and NV21 formats.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
drivers/gpu/drm/exynos/exynos_drm_gsc.c

index 7ba414b..ce15d46 100644 (file)
@@ -448,7 +448,7 @@ static void gsc_handle_irq(struct gsc_context *ctx, bool enable,
 }
 
 
-static void gsc_src_set_fmt(struct gsc_context *ctx, u32 fmt)
+static void gsc_src_set_fmt(struct gsc_context *ctx, u32 fmt, bool tiled)
 {
        u32 cfg;
 
@@ -514,6 +514,9 @@ static void gsc_src_set_fmt(struct gsc_context *ctx, u32 fmt)
                break;
        }
 
+       if (tiled)
+               cfg |= (GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE);
+
        gsc_write(cfg, GSC_IN_CON);
 }
 
@@ -632,7 +635,7 @@ static void gsc_src_set_addr(struct gsc_context *ctx, u32 buf_id,
        gsc_src_set_buf_seq(ctx, buf_id, true);
 }
 
-static void gsc_dst_set_fmt(struct gsc_context *ctx, u32 fmt)
+static void gsc_dst_set_fmt(struct gsc_context *ctx, u32 fmt, bool tiled)
 {
        u32 cfg;
 
@@ -698,6 +701,9 @@ static void gsc_dst_set_fmt(struct gsc_context *ctx, u32 fmt)
                break;
        }
 
+       if (tiled)
+               cfg |= (GSC_IN_TILE_C_16x8 | GSC_OUT_TILE_MODE);
+
        gsc_write(cfg, GSC_OUT_CON);
 }
 
@@ -1122,11 +1128,11 @@ static int gsc_commit(struct exynos_drm_ipp *ipp,
                return ret;
        }
 
-       gsc_src_set_fmt(ctx, task->src.buf.fourcc);
+       gsc_src_set_fmt(ctx, task->src.buf.fourcc, task->src.buf.modifier);
        gsc_src_set_transf(ctx, task->transform.rotation);
        gsc_src_set_size(ctx, &task->src);
        gsc_src_set_addr(ctx, 0, &task->src);
-       gsc_dst_set_fmt(ctx, task->dst.buf.fourcc);
+       gsc_dst_set_fmt(ctx, task->dst.buf.fourcc, task->dst.buf.modifier);
        gsc_dst_set_size(ctx, &task->dst);
        gsc_dst_set_addr(ctx, 0, &task->dst);
        gsc_set_prescaler(ctx, &ctx->sc, &task->src.rect, &task->dst.rect);
@@ -1200,6 +1206,10 @@ static const unsigned int gsc_formats[] = {
        DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, DRM_FORMAT_YUV422,
 };
 
+static const unsigned int gsc_tiled_formats[] = {
+       DRM_FORMAT_NV12, DRM_FORMAT_NV21,
+};
+
 static int gsc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -1207,23 +1217,24 @@ static int gsc_probe(struct platform_device *pdev)
        struct exynos_drm_ipp_formats *formats;
        struct gsc_context *ctx;
        struct resource *res;
-       int ret, i;
+       int num_formats, ret, i, j;
 
        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
 
-       formats = devm_kcalloc(dev,
-                              ARRAY_SIZE(gsc_formats), sizeof(*formats),
-                              GFP_KERNEL);
-       if (!formats)
-               return -ENOMEM;
-
        driver_data = (struct gsc_driverdata *)of_device_get_match_data(dev);
        ctx->dev = dev;
        ctx->num_clocks = driver_data->num_clocks;
        ctx->clk_names = driver_data->clk_names;
 
+       /* construct formats/limits array */
+       num_formats = ARRAY_SIZE(gsc_formats) + ARRAY_SIZE(gsc_tiled_formats);
+       formats = devm_kcalloc(dev, num_formats, sizeof(*formats), GFP_KERNEL);
+       if (!formats)
+               return -ENOMEM;
+
+       /* linear formats */
        for (i = 0; i < ARRAY_SIZE(gsc_formats); i++) {
                formats[i].fourcc = gsc_formats[i];
                formats[i].type = DRM_EXYNOS_IPP_FORMAT_SOURCE |
@@ -1231,8 +1242,19 @@ static int gsc_probe(struct platform_device *pdev)
                formats[i].limits = driver_data->limits;
                formats[i].num_limits = driver_data->num_limits;
        }
+
+       /* tiled formats */
+       for (j = i, i = 0; i < ARRAY_SIZE(gsc_tiled_formats); j++, i++) {
+               formats[j].fourcc = gsc_tiled_formats[i];
+               formats[j].modifier = DRM_FORMAT_MOD_SAMSUNG_16_16_TILE;
+               formats[j].type = DRM_EXYNOS_IPP_FORMAT_SOURCE |
+                                 DRM_EXYNOS_IPP_FORMAT_DESTINATION;
+               formats[j].limits = driver_data->limits;
+               formats[j].num_limits = driver_data->num_limits;
+       }
+
        ctx->formats = formats;
-       ctx->num_formats = ARRAY_SIZE(gsc_formats);
+       ctx->num_formats = num_formats;
 
        /* clock control */
        for (i = 0; i < ctx->num_clocks; i++) {