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>
.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,
},
};
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)
{
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;
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:
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))
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);
}
} 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:
} 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:
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)
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))
#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
(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))
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);