From a9f4a0639dad9a62dd1a54ad719812a9451f1b81 Mon Sep 17 00:00:00 2001 From: hjc Date: Mon, 9 Mar 2015 11:14:14 +0800 Subject: [PATCH] rk fb: add support yuv420sp nv21 data format Signed-off-by: hjc --- drivers/video/rockchip/lcdc/rk312x_lcdc.c | 27 +++++++++++++++++++++-- drivers/video/rockchip/lcdc/rk3288_lcdc.c | 23 +++++++++++++++---- drivers/video/rockchip/rk_fb.c | 24 +++++++++++++++----- drivers/video/rockchip/rkfb_sysfs.c | 5 +++-- include/linux/rk_fb.h | 4 +++- 5 files changed, 68 insertions(+), 15 deletions(-) diff --git a/drivers/video/rockchip/lcdc/rk312x_lcdc.c b/drivers/video/rockchip/lcdc/rk312x_lcdc.c index c6662d009cb6..e714c929a32b 100755 --- a/drivers/video/rockchip/lcdc/rk312x_lcdc.c +++ b/drivers/video/rockchip/lcdc/rk312x_lcdc.c @@ -416,10 +416,12 @@ static void lcdc_layer_update_regs(struct lcdc_device *lcdc_dev, lcdc_layer_csc_mode(lcdc_dev, win); if (win->id == 0) { - mask = m_WIN0_EN | m_WIN0_FORMAT | m_WIN0_RB_SWAP; + mask = m_WIN0_EN | m_WIN0_FORMAT | m_WIN0_RB_SWAP | + m_WIN0_UV_SWAP; val = v_WIN0_EN(win->state) | v_WIN0_FORMAT(win->area[0].fmt_cfg) | - v_WIN0_RB_SWAP(win->area[0].swap_rb); + v_WIN0_RB_SWAP(win->area[0].swap_rb) | + v_WIN0_UV_SWAP(win->area[0].swap_uv); lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val); lcdc_writel(lcdc_dev, WIN0_SCL_FACTOR_YRGB, v_X_SCL_FACTOR(win->scale_yrgb_x) | @@ -1531,18 +1533,22 @@ static int rk312x_lcdc_set_par(struct rk_lcdc_driver *dev_drv, int win_id) case ARGB888: win->area[0].fmt_cfg = VOP_FORMAT_ARGB888; win->area[0].swap_rb = 0; + win->area[0].swap_uv = 0; break; case XBGR888: win->area[0].fmt_cfg = VOP_FORMAT_ARGB888; win->area[0].swap_rb = 1; + win->area[0].swap_uv = 0; break; case ABGR888: win->area[0].fmt_cfg = VOP_FORMAT_ARGB888; win->area[0].swap_rb = 1; + win->area[0].swap_uv = 0; break; case RGB888: win->area[0].fmt_cfg = VOP_FORMAT_RGB888; win->area[0].swap_rb = 0; + win->area[0].swap_uv = 0; break; case RGB565: win->area[0].fmt_cfg = VOP_FORMAT_RGB565; @@ -1556,6 +1562,7 @@ static int rk312x_lcdc_set_par(struct rk_lcdc_driver *dev_drv, int win_id) win->scale_cbcr_y = CalScale(win->area[0].yact, win->area[0].ysize); win->area[0].swap_rb = 0; + win->area[0].swap_uv = 0; } else { dev_err(lcdc_dev->driver.dev, "%s:un supported format!\n", __func__); @@ -1569,6 +1576,7 @@ static int rk312x_lcdc_set_par(struct rk_lcdc_driver *dev_drv, int win_id) win->scale_cbcr_y = CalScale(win->area[0].yact, win->area[0].ysize); win->area[0].swap_rb = 0; + win->area[0].swap_uv = 0; } else { dev_err(lcdc_dev->driver.dev, "%s:un supported format!\n", __func__); @@ -1582,6 +1590,21 @@ static int rk312x_lcdc_set_par(struct rk_lcdc_driver *dev_drv, int win_id) win->scale_cbcr_y = CalScale(win->area[0].yact / 2, win->area[0].ysize); win->area[0].swap_rb = 0; + win->area[0].swap_uv = 0; + } else { + dev_err(lcdc_dev->driver.dev, + "%s:un supported format!\n", __func__); + } + break; + case YUV420_NV21: + if (win_id == 0) { + win->area[0].fmt_cfg = VOP_FORMAT_YCBCR420; + win->scale_cbcr_x = + CalScale(win->area[0].xact / 2, win->area[0].xsize); + win->scale_cbcr_y = + CalScale(win->area[0].yact / 2, win->area[0].ysize); + win->area[0].swap_rb = 0; + win->area[0].swap_uv = 1; } else { dev_err(lcdc_dev->driver.dev, "%s:un supported format!\n", __func__); diff --git a/drivers/video/rockchip/lcdc/rk3288_lcdc.c b/drivers/video/rockchip/lcdc/rk3288_lcdc.c index 3b0bf195959c..3f5ced0dd7f8 100755 --- a/drivers/video/rockchip/lcdc/rk3288_lcdc.c +++ b/drivers/video/rockchip/lcdc/rk3288_lcdc.c @@ -767,12 +767,13 @@ static int rk3288_win_0_1_reg_update(struct rk_lcdc_driver *dev_drv,int win_id) if(win->state == 1){ mask = m_WIN0_EN | m_WIN0_DATA_FMT | m_WIN0_FMT_10 | - m_WIN0_LB_MODE | m_WIN0_RB_SWAP; + m_WIN0_LB_MODE | m_WIN0_RB_SWAP | m_WIN0_UV_SWAP; val = v_WIN0_EN(win->state) | v_WIN0_DATA_FMT(win->area[0].fmt_cfg) | v_WIN0_FMT_10(win->fmt_10) | v_WIN0_LB_MODE(win->win_lb_mode) | - v_WIN0_RB_SWAP(win->area[0].swap_rb); + v_WIN0_RB_SWAP(win->area[0].swap_rb) | + v_WIN0_UV_SWAP(win->area[0].swap_uv); lcdc_msk_reg(lcdc_dev, WIN0_CTRL0+off, mask,val); mask = m_WIN0_BIC_COE_SEL | @@ -2043,7 +2044,7 @@ static int win0_set_par(struct lcdc_device *lcdc_dev, struct rk_screen *screen, struct rk_lcdc_win *win) { u32 xact,yact,xvir, yvir,xpos, ypos; - u8 fmt_cfg = 0, swap_rb; + u8 fmt_cfg = 0, swap_rb, swap_uv = 0; char fmt[9] = "NULL"; xpos = win->area[0].xpos + screen->mode.left_margin + screen->mode.hsync_len; @@ -2084,6 +2085,12 @@ static int win0_set_par(struct lcdc_device *lcdc_dev, swap_rb = 0; win->fmt_10 = 0; break; + case YUV420_NV21: + fmt_cfg = 4; + swap_rb = 0; + swap_uv = 1; + win->fmt_10 = 0; + break; case YUV444: fmt_cfg = 6; swap_rb = 0; @@ -2112,6 +2119,7 @@ static int win0_set_par(struct lcdc_device *lcdc_dev, win->area[0].swap_rb = swap_rb; win->area[0].dsp_stx = xpos; win->area[0].dsp_sty = ypos; + win->area[0].swap_uv = swap_uv; xact = win->area[0].xact; yact = win->area[0].yact; xvir = win->area[0].xvir; @@ -2132,7 +2140,7 @@ static int win1_set_par(struct lcdc_device *lcdc_dev, struct rk_screen *screen, struct rk_lcdc_win *win) { u32 xact, yact, xvir, yvir, xpos, ypos; - u8 fmt_cfg = 0, swap_rb; + u8 fmt_cfg = 0, swap_rb, swap_uv = 0; char fmt[9] = "NULL"; xpos = win->area[0].xpos + screen->mode.left_margin + screen->mode.hsync_len; @@ -2173,6 +2181,12 @@ static int win1_set_par(struct lcdc_device *lcdc_dev, swap_rb = 0; win->fmt_10 = 0; break; + case YUV420_NV21: + fmt_cfg = 4; + swap_rb = 0; + swap_uv = 1; + win->fmt_10 = 0; + break; case YUV444: fmt_cfg = 6; swap_rb = 0; @@ -2202,6 +2216,7 @@ static int win1_set_par(struct lcdc_device *lcdc_dev, win->area[0].swap_rb = swap_rb; win->area[0].dsp_stx = xpos; win->area[0].dsp_sty = ypos; + win->area[0].swap_uv = swap_uv; xact = win->area[0].xact; yact = win->area[0].yact; xvir = win->area[0].xvir; diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index 55177cc9d711..f5d9cd08c731 100755 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -158,6 +158,7 @@ int rk_fb_pixel_width(int data_format) break; case YUV422: case YUV420: + case YUV420_NV21: case YUV444: pixel_width = 1 * 8; break; @@ -197,6 +198,9 @@ static int rk_fb_data_fmt(int data_format, int bits_per_pixel) case HAL_PIXEL_FORMAT_YCbCr_422_SP: /* yuv422 */ fb_data_fmt = YUV422; break; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: /* YUV420---vuvuvu */ + fb_data_fmt = YUV420_NV21; + break; case HAL_PIXEL_FORMAT_YCrCb_NV12: /* YUV420---uvuvuv */ fb_data_fmt = YUV420; break; @@ -503,6 +507,7 @@ char *get_format_string(enum data_format format, char *fmt) strcpy(fmt, "RGB565"); break; case YUV420: + case YUV420_NV21: strcpy(fmt, "YUV420"); break; case YUV422: @@ -1257,7 +1262,8 @@ static int rk_fb_pan_display(struct fb_var_screeninfo *var, fix->line_length = stride; uv_y_act = win->area[0].yact >> 1; break; - case YUV420: /* 420sp */ + case YUV420: /* nv12 */ + case YUV420_NV21: /* nv21 */ case YUV420_A: is_pic_yuv = 1; stride = stride_32bit_1; @@ -1640,6 +1646,7 @@ static void rk_fb_update_reg(struct rk_lcdc_driver *dev_drv, if (win_data) { if (rk_fb->disp_policy == DISPLAY_POLICY_BOX && (win_data->reg_area_data[0].data_format == YUV420 || + win_data->reg_area_data[0].data_format == YUV420_NV21 || win_data->reg_area_data[0].data_format == YUV420_A)) continue; mutex_lock(&dev_drv->win_config); @@ -1973,7 +1980,8 @@ static int rk_fb_set_win_buffer(struct fb_info *info, fix->line_length = stride; uv_y_act = win_par->area_par[0].yact >> 1; break; - case YUV420: /* 420sp */ + case YUV420: /* nv12 */ + case YUV420_NV21: /* nv21 */ case YUV420_A: is_pic_yuv = 1; stride = stride_32bit_1; @@ -2575,7 +2583,8 @@ static ssize_t rk_fb_read(struct fb_info *info, char __user *buf, /* only read the current frame buffer */ if (win->area[0].format == RGB565) { total_size = win->area[0].y_vir_stride * win->area[0].yact << 1; - } else if (win->area[0].format == YUV420) { + } else if ((win->area[0].format == YUV420) || + (win->area[0].format == YUV420_NV21)) { total_size = (win->area[0].y_vir_stride * win->area[0].yact * 6); } else { @@ -2754,7 +2763,8 @@ static int rk_fb_set_par(struct fb_info *info) cblen = crlen = (xvir * yvir) >> 1; uv_y_act = win->area[0].yact >> 1; break; - case YUV420: /* 420sp */ + case YUV420: /* nv12 */ + case YUV420_NV21: /* nv21 */ case YUV420_A: is_pic_yuv = 1; stride = stride_32bit_1; @@ -2848,8 +2858,10 @@ static int rk_fb_set_par(struct fb_info *info) win->g_alpha_val = 0; if (rk_fb->disp_policy == DISPLAY_POLICY_BOX && - (win->area[0].format == YUV420 || win->area[0].format == YUV420_A)) - win->state = 1; + (win->area[0].format == YUV420 || + win->area[0].format == YUV420_NV21 || + win->area[0].format == YUV420_A)) + win->state = 1; dev_drv->ops->set_par(dev_drv, win_id); diff --git a/drivers/video/rockchip/rkfb_sysfs.c b/drivers/video/rockchip/rkfb_sysfs.c index da80013612d7..bbac53ff86f0 100755 --- a/drivers/video/rockchip/rkfb_sysfs.c +++ b/drivers/video/rockchip/rkfb_sysfs.c @@ -48,6 +48,7 @@ static char *get_format_str(enum data_format format) case RGB565: return "RGB565"; case YUV420: + case YUV420_NV21: return "YUV420"; case YUV422: return "YUV422"; @@ -65,9 +66,9 @@ static char *get_format_str(enum data_format format) return "XBGR888"; case ABGR888: return "ABGR888"; + default: + return "invalid"; } - - return "invalid"; } static ssize_t show_screen_info(struct device *dev, diff --git a/include/linux/rk_fb.h b/include/linux/rk_fb.h index e513b2b1cca2..18a55f57b79f 100755 --- a/include/linux/rk_fb.h +++ b/include/linux/rk_fb.h @@ -213,7 +213,8 @@ enum data_format { ABGR888, YUV420_A = 10, YUV422_A, - YUV444_A, + YUV444_A, + YUV420_NV21, }; enum @@ -315,6 +316,7 @@ struct rk_lcdc_win_area { enum data_format format; u8 fmt_cfg; u8 swap_rb; + u8 swap_uv; u32 y_offset; /*yuv/rgb offset -->LCDC_WINx_YRGB_MSTx*/ u32 c_offset; /*cb cr offset--->LCDC_WINx_CBR_MSTx*/ u16 xpos; /*start point in panel --->LCDC_WINx_DSP_ST*/ -- 2.34.1