From 3c3dc2f6900cd4d3aed94f40774b248a3c1a8610 Mon Sep 17 00:00:00 2001 From: Janghyuck Kim Date: Sat, 6 May 2017 17:50:19 +0900 Subject: [PATCH] [COMMON] media: scaler: support 10bit pixel format This patch supports 10bit pixel format that listed in below. V4L2_PIX_FMT_NV12M_S10B V4L2_PIX_FMT_NV12M_P010 V4L2_PIX_FMT_NV16M_S10B V4L2_PIX_FMT_NV61M_S10B Change-Id: Idabb2476333add13b895ef0725211df0a23dec0f Signed-off-by: Janghyuck Kim --- .../platform/exynos/scaler/scaler-core.c | 133 +++++++++++++++++- .../platform/exynos/scaler/scaler-regs.c | 68 ++++++++- .../platform/exynos/scaler/scaler-regs.h | 14 ++ drivers/media/platform/exynos/scaler/scaler.h | 7 +- 4 files changed, 211 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/exynos/scaler/scaler-core.c b/drivers/media/platform/exynos/scaler/scaler-core.c index 58fbd3eef764..7cb687869705 100644 --- a/drivers/media/platform/exynos/scaler/scaler-core.c +++ b/drivers/media/platform/exynos/scaler/scaler-core.c @@ -256,6 +256,44 @@ static const struct sc_fmt sc_formats[] = { .num_comp = 3, .h_shift = 1, .v_shift = 1, + }, { + .name = "YUV 4:2:0 contiguous 2-planar, Y/CbCr 8+2 bit", + .pixelformat = V4L2_PIX_FMT_NV12M_S10B, + .cfg_val = SCALER_CFG_FMT_YCBCR420_2P | + SCALER_CFG_10BIT_S10, + .bitperpixel = { 10, 5 }, + .num_planes = 2, + .num_comp = 2, + .h_shift = 1, + .v_shift = 1, + }, { + .name = "YUV 4:2:0 contiguous 2-planar, Y/CbCr 10-bit", + .pixelformat = V4L2_PIX_FMT_NV12M_P010, + .cfg_val = SCALER_CFG_FMT_YCBCR420_2P | + SCALER_CFG_10BIT_P010, + .bitperpixel = { 16, 8 }, + .num_planes = 2, + .num_comp = 2, + .h_shift = 1, + .v_shift = 1, + }, { + .name = "YUV 4:2:2 contiguous 2-planar, Y/CbCr 8+2 bit", + .pixelformat = V4L2_PIX_FMT_NV16M_S10B, + .cfg_val = SCALER_CFG_FMT_YCBCR422_2P | + SCALER_CFG_10BIT_S10, + .bitperpixel = { 10, 10 }, + .num_planes = 2, + .num_comp = 2, + .h_shift = 1, + }, { + .name = "YUV 4:2:2 contiguous 2-planar, Y/CrCb 8+2 bit", + .pixelformat = V4L2_PIX_FMT_NV61M_S10B, + .cfg_val = SCALER_CFG_FMT_YCRCB422_2P | + SCALER_CFG_10BIT_S10, + .bitperpixel = { 10, 10 }, + .num_planes = 2, + .num_comp = 2, + .h_shift = 1, }, }; @@ -575,6 +613,67 @@ static int sc_v4l2_g_fmt_mplane(struct file *file, void *fh, return 0; } +int sc_calc_s10b_planesize(u32 pixelformat, u32 width, u32 height, + u32 *ysize, u32 *csize, bool only_8bit) +{ + int ret = 0; + + switch (pixelformat) { + case V4L2_PIX_FMT_NV12M_S10B: + *ysize = NV12M_Y_SIZE(width, height); + *csize = NV12M_CBCR_SIZE(width, height); + break; + case V4L2_PIX_FMT_NV16M_S10B: + case V4L2_PIX_FMT_NV61M_S10B: + *ysize = NV16M_Y_SIZE(width, height); + *csize = NV16M_CBCR_SIZE(width, height); + break; + default: + ret = -EINVAL; + break; + } + + if (ret || only_8bit) + return ret; + + switch (pixelformat) { + case V4L2_PIX_FMT_NV12M_S10B: + *ysize += NV12M_Y_2B_SIZE(width, height); + *csize += NV12M_CBCR_2B_SIZE(width, height); + break; + case V4L2_PIX_FMT_NV16M_S10B: + case V4L2_PIX_FMT_NV61M_S10B: + *ysize += NV16M_Y_2B_SIZE(width, height); + *csize += NV16M_CBCR_2B_SIZE(width, height); + break; + default: + break; + } + + return ret; +} + +static int sc_calc_fmt_s10b_size(const struct sc_fmt *sc_fmt, + struct v4l2_pix_format_mplane *pixm) +{ + int i, ret; + + BUG_ON(sc_fmt->num_comp != 2); + + for (i = 0; i < pixm->num_planes; i++) + pixm->plane_fmt[i].bytesperline = (pixm->width * + sc_fmt->bitperpixel[i]) >> 3; + + ret = sc_calc_s10b_planesize(sc_fmt->pixelformat, + pixm->width, pixm->height, + &pixm->plane_fmt[0].sizeimage, + &pixm->plane_fmt[1].sizeimage, false); + if (ret) + pr_err("Scaler doesn't support %s format\n", sc_fmt->name); + + return ret; +} + static int sc_v4l2_try_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { @@ -619,6 +718,9 @@ static int sc_v4l2_try_fmt_mplane(struct file *file, void *fh, pixm->num_planes = sc_fmt->num_planes; pixm->colorspace = 0; + if (sc_fmt_is_s10bit_yuv(sc_fmt->pixelformat)) + return sc_calc_fmt_s10b_size(sc_fmt, pixm); + for (i = 0; i < pixm->num_planes; ++i) { pixm->plane_fmt[i].bytesperline = (pixm->width * sc_fmt->bitperpixel[i]) >> 3; @@ -1012,7 +1114,12 @@ static void sc_calc_intbufsize(struct sc_dev *sc, struct sc_int_frame *int_frame frame->addr.size[SC_PLANE_Y] = pixsize; frame->addr.size[SC_PLANE_CB] = bytesize - pixsize; } else if (frame->sc_fmt->num_planes == 2) { - sc_calc_planesize(frame, pixsize); + if (frame->sc_fmt->pixelformat == V4L2_PIX_FMT_NV12M_S10B) { + frame->addr.size[SC_PLANE_Y] = NV12M_Y_SIZE(frame->width, frame->height); + frame->addr.size[SC_PLANE_CB] = NV12M_CBCR_SIZE(frame->width, frame->height); + } else { + sc_calc_planesize(frame, pixsize); + } } break; case 3: @@ -2228,8 +2335,8 @@ static bool sc_process_2nd_stage(struct sc_dev *sc, struct sc_ctx *ctx) sc_hwset_dst_pos(sc, d_frame->crop.left, d_frame->crop.top); sc_hwset_dst_wh(sc, d_frame->crop.width, d_frame->crop.height); - sc_hwset_src_addr(sc, &s_frame->addr); - sc_hwset_dst_addr(sc, &d_frame->addr); + sc_hwset_src_addr(sc, s_frame); + sc_hwset_dst_addr(sc, d_frame); if ((ctx->flip_rot_cfg & SCALER_ROT_MASK) && (ctx->dnoise_ft.strength > SC_FT_BLUR)) @@ -2414,8 +2521,8 @@ static int sc_run_next_job(struct sc_dev *sc) if (sc->variant->initphase) sc_set_initial_phase(ctx); - sc_hwset_src_addr(sc, &s_frame->addr); - sc_hwset_dst_addr(sc, &d_frame->addr); + sc_hwset_src_addr(sc, s_frame); + sc_hwset_dst_addr(sc, d_frame); sc_set_dithering(ctx); @@ -2609,7 +2716,13 @@ static int sc_get_bufaddr(struct sc_dev *sc, struct vb2_buffer *vb2buf, } } else if (frame->sc_fmt->num_planes == 2) { frame->addr.ioaddr[SC_PLANE_CB] = vb2_dma_sg_plane_dma_addr(vb2buf, 1); - sc_calc_planesize(frame, pixsize); + if (sc_fmt_is_s10bit_yuv(frame->sc_fmt->pixelformat)) + sc_calc_s10b_planesize(frame->sc_fmt->pixelformat, + frame->width, frame->height, + &frame->addr.size[SC_PLANE_Y], + &frame->addr.size[SC_PLANE_CB], false); + else + sc_calc_planesize(frame, pixsize); } break; case 3: @@ -3022,7 +3135,13 @@ static void sc_m2m1shot_get_bufaddr(struct sc_dev *sc, } else if (frame->sc_fmt->num_planes == 2) { frame->addr.ioaddr[SC_PLANE_CB] = buf->plane[1].dma_addr; - sc_calc_planesize(frame, pixsize); + if (sc_fmt_is_s10bit_yuv(frame->sc_fmt->pixelformat)) + sc_calc_s10b_planesize(frame->sc_fmt->pixelformat, + frame->width, frame->height, + &frame->addr.size[SC_PLANE_Y], + &frame->addr.size[SC_PLANE_CB], false); + else + sc_calc_planesize(frame, pixsize); } break; case 3: diff --git a/drivers/media/platform/exynos/scaler/scaler-regs.c b/drivers/media/platform/exynos/scaler/scaler-regs.c index cb2a4a1b77c5..0ef48558e754 100644 --- a/drivers/media/platform/exynos/scaler/scaler-regs.c +++ b/drivers/media/platform/exynos/scaler/scaler-regs.c @@ -851,18 +851,76 @@ void sc_hwset_dst_imgsize(struct sc_dev *sc, struct sc_frame *frame) writel(cfg, sc->regs + SCALER_DST_SPAN); } -void sc_hwset_src_addr(struct sc_dev *sc, struct sc_addr *addr) +int sc_calc_s10b_planesize(u32 pixelformat, u32 width, u32 height, + u32 *ysize, u32 *csize, bool only_8bit); +static void sc_hwset_src_2bit_addr(struct sc_dev *sc, struct sc_frame *frame) { + u32 yaddr_2bit, caddr_2bit; + unsigned long cfg = 0; + + BUG_ON(frame->sc_fmt->num_comp != 2); + + sc_calc_s10b_planesize(frame->sc_fmt->pixelformat, + frame->width, frame->height, + &yaddr_2bit, &caddr_2bit, true); + yaddr_2bit += frame->addr.ioaddr[SC_PLANE_Y]; + caddr_2bit += frame->addr.ioaddr[SC_PLANE_CB]; + + writel(yaddr_2bit, sc->regs + SCALER_SRC_2BIT_Y_BASE); + writel(caddr_2bit, sc->regs + SCALER_SRC_2BIT_C_BASE); + + cfg &= ~(SCALER_SRC_2BIT_CSPAN_MASK | SCALER_SRC_2BIT_YSPAN_MASK); + cfg |= frame->width; + cfg |= (frame->width << frame->sc_fmt->cspan) << 16; + writel(cfg, sc->regs + SCALER_SRC_2BIT_SPAN); +} + +void sc_hwset_src_addr(struct sc_dev *sc, struct sc_frame *frame) +{ + struct sc_addr *addr = &frame->addr; + writel(addr->ioaddr[SC_PLANE_Y], sc->regs + SCALER_SRC_Y_BASE); writel(addr->ioaddr[SC_PLANE_CB], sc->regs + SCALER_SRC_CB_BASE); writel(addr->ioaddr[SC_PLANE_CR], sc->regs + SCALER_SRC_CR_BASE); + + if (sc_fmt_is_s10bit_yuv(frame->sc_fmt->pixelformat) && + sc->variant->pixfmt_10bit) + sc_hwset_src_2bit_addr(sc, frame); +} + +static void sc_hwset_dst_2bit_addr(struct sc_dev *sc, struct sc_frame *frame) +{ + u32 yaddr_2bit, caddr_2bit; + unsigned long cfg = 0; + + BUG_ON(frame->sc_fmt->num_comp != 2); + + sc_calc_s10b_planesize(frame->sc_fmt->pixelformat, + frame->width, frame->height, + &yaddr_2bit, &caddr_2bit, true); + yaddr_2bit += frame->addr.ioaddr[SC_PLANE_Y]; + caddr_2bit += frame->addr.ioaddr[SC_PLANE_CB]; + + writel(yaddr_2bit, sc->regs + SCALER_DST_2BIT_Y_BASE); + writel(caddr_2bit, sc->regs + SCALER_DST_2BIT_C_BASE); + + cfg &= ~(SCALER_DST_2BIT_CSPAN_MASK | SCALER_DST_2BIT_YSPAN_MASK); + cfg |= frame->width; + cfg |= (frame->width << frame->sc_fmt->cspan) << 16; + writel(cfg, sc->regs + SCALER_DST_2BIT_SPAN); } -void sc_hwset_dst_addr(struct sc_dev *sc, struct sc_addr *addr) +void sc_hwset_dst_addr(struct sc_dev *sc, struct sc_frame *frame) { + struct sc_addr *addr = &frame->addr; + writel(addr->ioaddr[SC_PLANE_Y], sc->regs + SCALER_DST_Y_BASE); writel(addr->ioaddr[SC_PLANE_CB], sc->regs + SCALER_DST_CB_BASE); writel(addr->ioaddr[SC_PLANE_CR], sc->regs + SCALER_DST_CR_BASE); + + if (sc_fmt_is_s10bit_yuv(frame->sc_fmt->pixelformat) && + sc->variant->pixfmt_10bit) + sc_hwset_dst_2bit_addr(sc, frame); } void sc_hwregs_dump(struct sc_dev *sc) @@ -889,11 +947,17 @@ void sc_hwregs_dump(struct sc_dev *sc) if (sc->version <= SCALER_VERSION(2, 1, 1)) print_hex_dump(KERN_NOTICE, "", DUMP_PREFIX_ADDRESS, 16, 4, sc->regs + 0x280, 0x28C - 0x280 + 4, false); + if (sc->version >= SCALER_VERSION(5, 0, 0)) + print_hex_dump(KERN_NOTICE, "", DUMP_PREFIX_ADDRESS, 16, 4, + sc->regs + 0x280, 0x288 - 0x280 + 4, false); print_hex_dump(KERN_NOTICE, "", DUMP_PREFIX_ADDRESS, 16, 4, sc->regs + 0x290, 0x298 - 0x290 + 4, false); if (sc->version <= SCALER_VERSION(2, 1, 1)) print_hex_dump(KERN_NOTICE, "", DUMP_PREFIX_ADDRESS, 16, 4, sc->regs + 0x2A8, 0x2A8 - 0x2A0 + 4, false); + if (sc->version >= SCALER_VERSION(5, 0, 0)) + print_hex_dump(KERN_NOTICE, "", DUMP_PREFIX_ADDRESS, 16, 4, + sc->regs + 0x2A0, 0x2A8 - 0x280 + 4, false); print_hex_dump(KERN_NOTICE, "", DUMP_PREFIX_ADDRESS, 16, 4, sc->regs + 0x2B0, 0x2C4 - 0x2B0 + 4, false); if (sc->version >= SCALER_VERSION(3, 0, 0)) diff --git a/drivers/media/platform/exynos/scaler/scaler-regs.h b/drivers/media/platform/exynos/scaler/scaler-regs.h index 981e845bd722..daf6faa261df 100644 --- a/drivers/media/platform/exynos/scaler/scaler-regs.h +++ b/drivers/media/platform/exynos/scaler/scaler-regs.h @@ -49,6 +49,8 @@ #define SCALER_CFG_TILE_EN (1 << 10) #define SCALER_CFG_VHALF_PHASE_EN (1 << 9) #define SCALER_CFG_BIG_ENDIAN (1 << 8) +#define SCALER_CFG_10BIT_P010 (1 << 7) +#define SCALER_CFG_10BIT_S10 (2 << 7) #define SCALER_CFG_SWAP_MASK (3 << 5) #define SCALER_CFG_BYTE_SWAP (1 << 5) #define SCALER_CFG_HWORD_SWAP (2 << 5) @@ -158,6 +160,18 @@ #define SCALER_OP_SEL_INV_SHIFT (28) #define SCALER_OP_SEL_SHIFT (24) +#define SCALER_SRC_2BIT_Y_BASE 0x280 +#define SCALER_SRC_2BIT_C_BASE 0x284 +#define SCALER_SRC_2BIT_SPAN 0x288 +#define SCALER_SRC_2BIT_YSPAN_MASK (0x7fff << 0) +#define SCALER_SRC_2BIT_CSPAN_MASK (0x7fff << 16) + +#define SCALER_DST_2BIT_Y_BASE 0x2A0 +#define SCALER_DST_2BIT_C_BASE 0x2A4 +#define SCALER_DST_2BIT_SPAN 0x2A8 +#define SCALER_DST_2BIT_YSPAN_MASK (0x7fff << 0) +#define SCALER_DST_2BIT_CSPAN_MASK (0x7fff << 16) + #define SCALER_FILL_COLOR 0x290 #define SCALER_TIMEOUT_CTRL 0x2c0 diff --git a/drivers/media/platform/exynos/scaler/scaler.h b/drivers/media/platform/exynos/scaler/scaler.h index 5eb4e291e63d..19d1bcab5f75 100644 --- a/drivers/media/platform/exynos/scaler/scaler.h +++ b/drivers/media/platform/exynos/scaler/scaler.h @@ -93,6 +93,9 @@ extern int sc_log_level; (x == V4L2_PIX_FMT_NV21M) || (x == V4L2_PIX_FMT_YUV420M) || \ (x == V4L2_PIX_FMT_YVU420M) || (x == V4L2_PIX_FMT_NV12MT_16X16)) #define sc_fmt_is_ayv12(x) ((x) == V4L2_PIX_FMT_YVU420) +#define sc_fmt_is_s10bit_yuv(x) ((x == V4L2_PIX_FMT_NV12M_S10B) || \ + (x == V4L2_PIX_FMT_NV12N_10B) || (x == V4L2_PIX_FMT_NV16M_S10B) || \ + (x == V4L2_PIX_FMT_NV61M_S10B)) #define sc_dith_val(a, b, c) ((a << SCALER_DITH_R_SHIFT) | \ (b << SCALER_DITH_G_SHIFT) | (c << SCALER_DITH_B_SHIFT)) @@ -511,8 +514,8 @@ void sc_hwset_src_crop(struct sc_dev *sc, struct v4l2_rect *rect, const struct sc_fmt *fmt, unsigned int pre_h_ratio, unsigned int pre_v_ratio); void sc_hwset_dst_crop(struct sc_dev *sc, struct v4l2_rect *rect); -void sc_hwset_src_addr(struct sc_dev *sc, struct sc_addr *addr); -void sc_hwset_dst_addr(struct sc_dev *sc, struct sc_addr *addr); +void sc_hwset_src_addr(struct sc_dev *sc, struct sc_frame *frame); +void sc_hwset_dst_addr(struct sc_dev *sc, struct sc_frame *frame); void sc_hwset_hcoef(struct sc_dev *sc, unsigned int coef); void sc_hwset_vcoef(struct sc_dev *sc, unsigned int coef); -- 2.20.1