From 5ec0a47ae87f965239d921f13aafaa94436de91a Mon Sep 17 00:00:00 2001 From: Maciej Socha Date: Fri, 17 Jun 2011 15:09:02 +0200 Subject: b2r2: Correct support for 24/32bit (A)YUV(8)888 Order of the color components has been corrected to match the specification of the formats. ST-Ericsson ID: 341178 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I9211ccce6a099b89fe247bc2ed486aa2bc6c6ac8 Signed-off-by: Maciej Socha Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/25429 Reviewed-by: QATOOLS Reviewed-by: QATEST Reviewed-by: Robert FEKETE Reviewed-by: Linus WALLEIJ --- drivers/video/b2r2/b2r2_generic.c | 147 ++++++++++++++++++++++++----------- drivers/video/b2r2/b2r2_hw.h | 48 +++++++++++- drivers/video/b2r2/b2r2_node_split.c | 62 +++++++++++++++ 3 files changed, 212 insertions(+), 45 deletions(-) diff --git a/drivers/video/b2r2/b2r2_generic.c b/drivers/video/b2r2/b2r2_generic.c index d2228e3cf8a..738e11bf4ba 100644 --- a/drivers/video/b2r2/b2r2_generic.c +++ b/drivers/video/b2r2/b2r2_generic.c @@ -543,22 +543,27 @@ static void setup_fill_input_stage(const struct b2r2_blt_request *req, case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: - /* - * Set up IVMX - * The destination format is in fact YUV, - * but the input stage stores the data in - * an intermediate buffer which is RGB. - * Hence the conversion from YUV to RGB. - */ - node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED; - node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; - node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_YUV_TO_RGB_601_VIDEO; - node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_YUV_TO_RGB_601_VIDEO; - node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_YUV_TO_RGB_601_VIDEO; - node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_YUV_TO_RGB_601_VIDEO; - if ((req->user_req.flags & B2R2_BLT_FLAG_SOURCE_FILL) != 0) { fill_fmt = B2R2_NATIVE_AYCBCR8888; + /* + * Set up IVMX + * The destination format is in fact YUV, + * but the input stage stores the data in + * an intermediate buffer which is RGB. + * Hence the conversion from YUV to RGB. + * Format of the supplied src_color is + * B2R2_BLT_FMT_32_BIT_AYUV8888. + */ + node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_BLT_YUV888_TO_RGB_601_VIDEO; } else { /* SOURCE_FILL_RAW */ bool dst_yuv_planar = @@ -599,7 +604,22 @@ static void setup_fill_input_stage(const struct b2r2_blt_request *req, fill_fmt = to_native_fmt(dst_img->fmt); } - if (dst_img->fmt == B2R2_BLT_FMT_Y_CB_Y_CR) { + switch (dst_img->fmt) { + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + node->node.GROUP0.B2R2_INS |= + B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_BLT_YUV888_TO_RGB_601_VIDEO; + break; + case B2R2_BLT_FMT_Y_CB_Y_CR: /* * Setup input VMX to convert YVU to * RGB 601 VIDEO @@ -614,6 +634,27 @@ static void setup_fill_input_stage(const struct b2r2_blt_request *req, B2R2_VMX2_YVU_TO_RGB_601_VIDEO; node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_YVU_TO_RGB_601_VIDEO; + break; + default: + /* + * Set up IVMX + * The destination format is in fact YUV, + * but the input stage stores the data in + * an intermediate buffer which is RGB. + * Hence the conversion from YUV to RGB. + */ + node->node.GROUP0.B2R2_INS |= + B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_YUV_TO_RGB_601_VIDEO; + break; } } break; @@ -766,36 +807,54 @@ static void setup_input_stage(const struct b2r2_blt_request *req, node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_RGB_TO_BGR; break; case B2R2_BLT_FMT_Y_CB_Y_CR: + /* + * Setup input VMX to convert YVU to RGB 601 VIDEO + * Chroma components are swapped so + * it is YVU and not YUV. + */ + node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_YVU_TO_RGB_601_VIDEO; + break; case B2R2_BLT_FMT_CB_Y_CR_Y: + /* Set up IVMX */ + node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_YUV_TO_RGB_601_VIDEO; + break; case B2R2_BLT_FMT_24_BIT_YUV888: case B2R2_BLT_FMT_32_BIT_AYUV8888: - /* Set up IVMX */ + /* + * Set up IVMX. + * Color components are laid out in memory as V, U, Y, (A) + * with V at the first byte (due to little endian addressing). + * B2R2 expects them to be as U, Y, V, (A) + * with U at the first byte. + */ node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED; node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; - if (src_img->fmt == B2R2_BLT_FMT_Y_CB_Y_CR) { - /* - * Setup input VMX to convert YVU to RGB 601 VIDEO - * Chroma components are swapped so - * it is YVU and not YUV. - */ - node->node.GROUP15.B2R2_VMX0 = - B2R2_VMX0_YVU_TO_RGB_601_VIDEO; - node->node.GROUP15.B2R2_VMX1 = - B2R2_VMX1_YVU_TO_RGB_601_VIDEO; - node->node.GROUP15.B2R2_VMX2 = - B2R2_VMX2_YVU_TO_RGB_601_VIDEO; - node->node.GROUP15.B2R2_VMX3 = - B2R2_VMX3_YVU_TO_RGB_601_VIDEO; - } else { - node->node.GROUP15.B2R2_VMX0 = - B2R2_VMX0_YUV_TO_RGB_601_VIDEO; - node->node.GROUP15.B2R2_VMX1 = - B2R2_VMX1_YUV_TO_RGB_601_VIDEO; - node->node.GROUP15.B2R2_VMX2 = - B2R2_VMX2_YUV_TO_RGB_601_VIDEO; - node->node.GROUP15.B2R2_VMX3 = - B2R2_VMX3_YUV_TO_RGB_601_VIDEO; - } + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_BLT_YUV888_TO_RGB_601_VIDEO; break; case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: @@ -2002,13 +2061,13 @@ static void setup_writeback_stage(const struct b2r2_blt_request *req, node->node.GROUP0.B2R2_INS |= B2R2_INS_OVMX_ENABLED; node->node.GROUP0.B2R2_CIC |= B2R2_CIC_OVMX; node->node.GROUP16.B2R2_VMX0 = - B2R2_VMX0_RGB_TO_YUV_601_VIDEO; + B2R2_VMX0_RGB_TO_BLT_YUV888_601_VIDEO; node->node.GROUP16.B2R2_VMX1 = - B2R2_VMX1_RGB_TO_YUV_601_VIDEO; + B2R2_VMX1_RGB_TO_BLT_YUV888_601_VIDEO; node->node.GROUP16.B2R2_VMX2 = - B2R2_VMX2_RGB_TO_YUV_601_VIDEO; + B2R2_VMX2_RGB_TO_BLT_YUV888_601_VIDEO; node->node.GROUP16.B2R2_VMX3 = - B2R2_VMX3_RGB_TO_YUV_601_VIDEO; + B2R2_VMX3_RGB_TO_BLT_YUV888_601_VIDEO; break; default: break; diff --git a/drivers/video/b2r2/b2r2_hw.h b/drivers/video/b2r2/b2r2_hw.h index 2112a34dfe9..0dd5f758eb5 100644 --- a/drivers/video/b2r2/b2r2_hw.h +++ b/drivers/video/b2r2/b2r2_hw.h @@ -143,7 +143,8 @@ enum b2r2_ack { B2R2_ACK_MODE_BYPASS_S2_S3 = 0x7 << B2R2_ACK_MODE_SHIFT, B2R2_ACK_MODE_CLIPMASK_LOGICAL_SECOND_PASS = 0x8 << B2R2_ACK_MODE_SHIFT, B2R2_ACK_MODE_CLIPMASK_XYL_LOGICAL = 0x9 << B2R2_ACK_MODE_SHIFT, - B2R2_ACK_MODE_CLIPMASK_XYL_BLEND_NOT_PREMULT = 0xa << B2R2_ACK_MODE_SHIFT, + B2R2_ACK_MODE_CLIPMASK_XYL_BLEND_NOT_PREMULT = + 0xa << B2R2_ACK_MODE_SHIFT, B2R2_ACK_MODE_CLIPMASK_XYL_BLEND_PREMULT = 0xb << B2R2_ACK_MODE_SHIFT, /* ALU channel selection */ @@ -634,4 +635,49 @@ enum b2r2_plug_page_size { #define B2R2_VMX2_YVU_TO_YUV_601_VIDEO 0x20000000 #define B2R2_VMX3_YVU_TO_YUV_601_VIDEO 0x00000000 +/* VMX register values for RGB to BLT_YUV888 conversion */ + +/* 601 Video Matrix (standard 601 conversion) */ +/* + * BLT_YUV888 has color components laid out in memory as V, U, Y, (Alpha) + * with V at the first byte (due to little endian addressing). + * B2R2 expects them to be as U, Y, V, (A) + * with U at the first byte. + * Note: RGB -> BLT_YUV888 values are calculated by multiplying + * the RGB -> YUV matrix [A], with [S] to form [S]x[A] where + * |0 1 0| + * S = |0 0 1| + * |1 0 0| + * Essentially changing the order of rows in the original + * matrix [A]. + * row1 -> row3 + * row2 -> row1 + * row3 -> row2 + * Values in the offset vector are swapped in the same manner. + */ +#define B2R2_VMX0_RGB_TO_BLT_YUV888_601_VIDEO 0x0982581d +#define B2R2_VMX1_RGB_TO_BLT_YUV888_601_VIDEO 0xfa9ea483 +#define B2R2_VMX2_RGB_TO_BLT_YUV888_601_VIDEO 0x107e4beb +#define B2R2_VMX3_RGB_TO_BLT_YUV888_601_VIDEO 0x00020080 + +/* VMX register values for BLT_YUV888 to RGB conversion */ + +/* + * Note: BLT_YUV888 -> RGB values are calculated by multiplying + * the YUV -> RGB matrix [A], with [S] to form [A]x[S] where + * |0 0 1| + * S = |1 0 0| + * |0 1 0| + * Essentially changing the order of columns in the original + * matrix [A]. + * col1 -> col3 + * col2 -> col1 + * col3 -> col2 + * Values in the offset vector remain unchanged. + */ +#define B2R2_VMX0_BLT_YUV888_TO_RGB_601_VIDEO 0x20000121 +#define B2R2_VMX1_BLT_YUV888_TO_RGB_601_VIDEO 0x201ea74c +#define B2R2_VMX2_BLT_YUV888_TO_RGB_601_VIDEO 0x2006f000 +#define B2R2_VMX3_BLT_YUV888_TO_RGB_601_VIDEO 0x34f21322 + #endif /* B2R2_HW_H__ */ diff --git a/drivers/video/b2r2/b2r2_node_split.c b/drivers/video/b2r2/b2r2_node_split.c index c2b7e048dd5..90674e0e540 100644 --- a/drivers/video/b2r2/b2r2_node_split.c +++ b/drivers/video/b2r2/b2r2_node_split.c @@ -46,6 +46,13 @@ static const u32 vmx_rgb_to_yuv[] = { B2R2_VMX3_RGB_TO_YUV_601_VIDEO, }; +static const u32 vmx_rgb_to_blt_yuv888[] = { + B2R2_VMX0_RGB_TO_BLT_YUV888_601_VIDEO, + B2R2_VMX1_RGB_TO_BLT_YUV888_601_VIDEO, + B2R2_VMX2_RGB_TO_BLT_YUV888_601_VIDEO, + B2R2_VMX3_RGB_TO_BLT_YUV888_601_VIDEO, +}; + static const u32 vmx_yuv_to_rgb[] = { B2R2_VMX0_YUV_TO_RGB_601_VIDEO, B2R2_VMX1_YUV_TO_RGB_601_VIDEO, @@ -53,6 +60,13 @@ static const u32 vmx_yuv_to_rgb[] = { B2R2_VMX3_YUV_TO_RGB_601_VIDEO, }; +static const u32 vmx_blt_yuv888_to_rgb[] = { + B2R2_VMX0_BLT_YUV888_TO_RGB_601_VIDEO, + B2R2_VMX1_BLT_YUV888_TO_RGB_601_VIDEO, + B2R2_VMX2_BLT_YUV888_TO_RGB_601_VIDEO, + B2R2_VMX3_BLT_YUV888_TO_RGB_601_VIDEO, +}; + static const u32 vmx_yvu_to_rgb[] = { B2R2_VMX0_YVU_TO_RGB_601_VIDEO, B2R2_VMX1_YVU_TO_RGB_601_VIDEO, @@ -252,6 +266,32 @@ int b2r2_node_split_analyze(const struct b2r2_blt_request *req, goto unsupported; } + /* Unsupported formats on src */ + switch (req->user_req.src_img.fmt) { + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + if (!is_rgb_fmt(req->user_req.dst_img.fmt)) { + ret = -ENOSYS; + goto unsupported; + } + break; + default: + break; + } + + /* Unsupported formats on dst */ + switch (req->user_req.dst_img.fmt) { + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + if (!is_rgb_fmt(req->user_req.src_img.fmt)) { + ret = -ENOSYS; + goto unsupported; + } + break; + default: + break; + } + if ((this->flags & B2R2_BLT_FLAG_SOURCE_COLOR_KEY) && (is_yuv_fmt(req->user_req.src_img.fmt) || req->user_req.src_img.fmt == B2R2_BLT_FMT_1_BIT_A1 || @@ -651,6 +691,9 @@ static int analyze_fmt_conv(struct b2r2_node_split_buf *src, if (is_rgb_fmt(src->fmt)) { if (is_yvu_fmt(dst->fmt)) *vmx = &vmx_rgb_to_yvu[0]; + else if (dst->fmt == B2R2_BLT_FMT_24_BIT_YUV888 || + dst->fmt == B2R2_BLT_FMT_32_BIT_AYUV8888) + *vmx = &vmx_rgb_to_blt_yuv888[0]; else if (is_yuv_fmt(dst->fmt)) *vmx = &vmx_rgb_to_yuv[0]; else if (is_bgr_fmt(dst->fmt)) @@ -660,14 +703,30 @@ static int analyze_fmt_conv(struct b2r2_node_split_buf *src, *vmx = &vmx_yvu_to_rgb[0]; else if (is_bgr_fmt(dst->fmt)) *vmx = &vmx_yvu_to_bgr[0]; + else if (dst->fmt == B2R2_BLT_FMT_24_BIT_YUV888 || + dst->fmt == B2R2_BLT_FMT_32_BIT_AYUV8888) + BUG_ON(1); else if (is_yuv_fmt(dst->fmt) && !is_yvu_fmt(dst->fmt)) *vmx = &vmx_yvu_to_yuv[0]; + } else if (src->fmt == B2R2_BLT_FMT_24_BIT_YUV888 || + src->fmt == B2R2_BLT_FMT_32_BIT_AYUV8888) { + if (is_rgb_fmt(dst->fmt)) + *vmx = &vmx_blt_yuv888_to_rgb[0]; + else + /* + * not supported, b2r2_node_split_analyze() + * should have returned ENOSYS. + */ + BUG_ON(1); } else if (is_yuv_fmt(src->fmt)) { if (is_rgb_fmt(dst->fmt)) *vmx = &vmx_yuv_to_rgb[0]; else if (is_bgr_fmt(dst->fmt)) *vmx = &vmx_yuv_to_bgr[0]; + else if (dst->fmt == B2R2_BLT_FMT_24_BIT_YUV888 || + dst->fmt == B2R2_BLT_FMT_32_BIT_AYUV8888) + BUG_ON(1); else if (is_yvu_fmt(dst->fmt)) *vmx = &vmx_yvu_to_yuv[0]; } else if (is_bgr_fmt(src->fmt)) { @@ -675,6 +734,9 @@ static int analyze_fmt_conv(struct b2r2_node_split_buf *src, *vmx = &vmx_rgb_to_bgr[0]; else if (is_yvu_fmt(dst->fmt)) *vmx = &vmx_bgr_to_yvu[0]; + else if (dst->fmt == B2R2_BLT_FMT_24_BIT_YUV888 || + dst->fmt == B2R2_BLT_FMT_32_BIT_AYUV8888) + BUG_ON(1); else if (is_yuv_fmt(dst->fmt)) *vmx = &vmx_bgr_to_yuv[0]; } -- cgit v1.2.3