[COMMON] media: scaler: support 10bit pixel format
authorJanghyuck Kim <janghyuck.kim@samsung.com>
Sat, 6 May 2017 08:50:19 +0000 (17:50 +0900)
committerSeungchul Kim <sc377.kim@samsung.com>
Mon, 28 May 2018 05:28:29 +0000 (14:28 +0900)
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 <janghyuck.kim@samsung.com>
drivers/media/platform/exynos/scaler/scaler-core.c
drivers/media/platform/exynos/scaler/scaler-regs.c
drivers/media/platform/exynos/scaler/scaler-regs.h
drivers/media/platform/exynos/scaler/scaler.h

index 58fbd3eef764acbebf8084ecd3bcffc804a65424..7cb687869705b3adffc7c73601e6600961d26748 100644 (file)
@@ -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:
index cb2a4a1b77c52a7d9a5b9d19503081f832dd04db..0ef48558e7542ad54c0ebcc3d9d4e8be10734207 100644 (file)
@@ -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))
index 981e845bd72271edc4d0bf3c81eeb8935b74e7a9..daf6faa261df5278f1f581abf23eafa39a5128f0 100644 (file)
@@ -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)
 #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
index 5eb4e291e63d171eb1cc13f8b714363f148d88f8..19d1bcab5f75aa3598e01bd70ef12f08fef2cdd0 100644 (file)
@@ -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);