@@ -535,10 +535,8 @@ static void gsc_src_set_fmt(struct gsc_context *ctx, u32 fmt, bool tiled)
cfg |= GSC_IN_YUV422_3P;
break;
case DRM_FORMAT_YUV420:
- cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_3P);
- break;
case DRM_FORMAT_YVU420:
- cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_3P);
+ cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_3P);
break;
case DRM_FORMAT_NV12:
cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_2P);
@@ -658,13 +656,32 @@ static void gsc_src_set_buf_seq(struct gsc_context *ctx, u32 buf_id,
gsc_write(cfg, GSC_IN_BASE_ADDR_CR_MASK);
}
+/* returns HW plane index based on pixel format */
+static int gsc_hw_plane_index(int index, u32 format)
+{
+ switch (format) {
+ case DRM_FORMAT_YVU420:
+ switch (index) {
+ case 0: return 0;
+ case 1: return 2;
+ case 2: return 1;
+ }
+ default:
+ return index;
+ }
+}
+
static void gsc_src_set_addr(struct gsc_context *ctx, u32 buf_id,
struct exynos_drm_ipp_buffer *buf)
{
+ int idx;
+
/* address register set */
gsc_write(buf->dma_addr[0], GSC_IN_BASE_ADDR_Y(buf_id));
- gsc_write(buf->dma_addr[1], GSC_IN_BASE_ADDR_CB(buf_id));
- gsc_write(buf->dma_addr[2], GSC_IN_BASE_ADDR_CR(buf_id));
+ idx = gsc_hw_plane_index(1, buf->format->format);
+ gsc_write(buf->dma_addr[idx], GSC_IN_BASE_ADDR_CB(buf_id));
+ idx = gsc_hw_plane_index(2, buf->format->format);
+ gsc_write(buf->dma_addr[idx], GSC_IN_BASE_ADDR_CR(buf_id));
gsc_src_set_buf_seq(ctx, buf_id, true);
}
@@ -722,10 +739,8 @@ static void gsc_dst_set_fmt(struct gsc_context *ctx, u32 fmt, bool tiled)
cfg |= GSC_OUT_YUV422_3P;
break;
case DRM_FORMAT_YUV420:
- cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_3P);
- break;
case DRM_FORMAT_YVU420:
- cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_3P);
+ cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_3P);
break;
case DRM_FORMAT_NV12:
cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_2P);
@@ -985,10 +1000,13 @@ static void gsc_dst_set_buf_seq(struct gsc_context *ctx, u32 buf_id,
static void gsc_dst_set_addr(struct gsc_context *ctx,
u32 buf_id, struct exynos_drm_ipp_buffer *buf)
{
- /* address register set */
+ int i;
+
gsc_write(buf->dma_addr[0], GSC_OUT_BASE_ADDR_Y(buf_id));
- gsc_write(buf->dma_addr[1], GSC_OUT_BASE_ADDR_CB(buf_id));
- gsc_write(buf->dma_addr[2], GSC_OUT_BASE_ADDR_CR(buf_id));
+ i = gsc_hw_plane_index(1, buf->format->format);
+ gsc_write(buf->dma_addr[i], GSC_OUT_BASE_ADDR_CB(buf_id));
+ i = gsc_hw_plane_index(2, buf->format->format);
+ gsc_write(buf->dma_addr[i], GSC_OUT_BASE_ADDR_CR(buf_id));
gsc_dst_set_buf_seq(ctx, buf_id, true);
}
@@ -1238,10 +1256,14 @@ static void gsc_update_plane(struct exynos_drm_plane *plane)
gsc_write(BIT(16) * cropped_w / scaled_w, GSC_MAIN_H_RATIO);
gsc_write(BIT(16) * cropped_h / scaled_h, GSC_MAIN_V_RATIO);
gsc_write(exynos_drm_fb_dma_addr(fb, 0), GSC_IN_BASE_ADDR_Y(0));
- if (fb->format->num_planes > 1)
- gsc_write(exynos_drm_fb_dma_addr(fb, 1), GSC_IN_BASE_ADDR_CB(0));
- if (fb->format->num_planes > 2)
- gsc_write(exynos_drm_fb_dma_addr(fb, 2), GSC_IN_BASE_ADDR_CR(0));
+ if (fb->format->num_planes > 1) {
+ i = gsc_hw_plane_index(1, fb->format->format);
+ gsc_write(exynos_drm_fb_dma_addr(fb, i), GSC_IN_BASE_ADDR_CB(0));
+ }
+ if (fb->format->num_planes > 2) {
+ i = gsc_hw_plane_index(2, fb->format->format);
+ gsc_write(exynos_drm_fb_dma_addr(fb, i), GSC_IN_BASE_ADDR_CR(0));
+ }
gsc_src_set_fmt(ctx, fb->format->format, fb->modifier);
gsc_write(scaled_w * scaled_h, GSC_SMART_IF_PIXEL_NUM);
gsc_write(GSC_ENABLE_SFR_UPDATE | GSC_ENABLE_ON, GSC_ENABLE);
YVU420 requires swapping addresses of U and V planes. Signed-off-by: Andrzej Hajda <a.hajda@samsung.com> --- drivers/gpu/drm/exynos/exynos_drm_gsc.c | 52 ++++++++++++++++++------- 1 file changed, 37 insertions(+), 15 deletions(-)