diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 201ea212e410..b1c95caa7463 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -1100,6 +1100,77 @@ static inline u32 rkcif_scl_ctl(struct rkcif_stream *stream) ENABLE_YUV_16BIT_BYPASS : ENABLE_RAW_16BIT_BYPASS; } +/** + * rkcif_align_bits_per_pixel() - return the bit width of per pixel for stored + * In raw or jpeg mode, data is stored by 16-bits,so need to align it. + */ +static u32 rkcif_align_bits_per_pixel(const struct cif_output_fmt *fmt, + int plane_index) +{ + u32 bpp = 0, i; + + if (fmt) { + switch (fmt->fourcc) { + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_Y16: + bpp = fmt->bpp[plane_index]; + break; + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_BGR666: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SBGGR16: + bpp = max(fmt->bpp[plane_index], (u8)CIF_RAW_STORED_BIT_WIDTH); + for (i = 1; i < 5; i++) { + if (i * CIF_RAW_STORED_BIT_WIDTH >= bpp) { + bpp = i * CIF_RAW_STORED_BIT_WIDTH; + break; + } + } + break; + default: + pr_err("fourcc: %d is not supported!\n", fmt->fourcc); + break; + } + } + + return bpp; +} + +/** + * rkcif_cal_raw_vir_line_ratio() - return ratio for virtual line width setting + * In raw or jpeg mode, data is stored by 16-bits, + * so need to align virtual line width. + */ +static u32 rkcif_cal_raw_vir_line_ratio(const struct cif_output_fmt *fmt) +{ + u32 ratio = 0, bpp = 0; + + if (fmt) { + bpp = rkcif_align_bits_per_pixel(fmt, 0); + ratio = bpp / CIF_YUV_STORED_BIT_WIDTH; + } + + return ratio; +} + static int rkcif_stream_start(struct rkcif_stream *stream) { u32 val, mbus_flags, href_pol, vsync_pol, @@ -1107,6 +1178,7 @@ static int rkcif_stream_start(struct rkcif_stream *stream) inputmode = 0, mipimode = 0, workmode = 0; struct rkcif_device *dev = stream->cifdev; struct rkcif_sensor_info *sensor_info; + const struct cif_output_fmt *fmt; void __iomem *base = dev->base_addr; sensor_info = dev->active_sensor; @@ -1154,8 +1226,10 @@ static int rkcif_stream_start(struct rkcif_stream *stream) write_cif_reg(base, CIF_FOR, val); val = stream->pixm.width; - if (stream->cif_fmt_in->fmt_type == CIF_FMT_TYPE_RAW) - val = stream->pixm.width * 2; + if (stream->cif_fmt_in->fmt_type == CIF_FMT_TYPE_RAW) { + fmt = find_output_fmt(stream, stream->pixm.pixelformat); + val = stream->pixm.width * rkcif_cal_raw_vir_line_ratio(fmt); + } write_cif_reg(base, CIF_VIR_LINE_WIDTH, val); write_cif_reg(base, CIF_SET_SIZE, stream->pixm.width | (stream->pixm.height << 16)); @@ -1412,7 +1486,7 @@ static void rkcif_set_fmt(struct rkcif_stream *stream, for (i = 0; i < planes; i++) { struct v4l2_plane_pix_format *plane_fmt; - int width, height, bpl, size; + int width, height, bpl, size, bpp; if (i == 0) { width = pixm->width; @@ -1422,7 +1496,8 @@ static void rkcif_set_fmt(struct rkcif_stream *stream, height = pixm->height / ysubs; } - bpl = width * fmt->bpp[i] / 8; + bpp = rkcif_align_bits_per_pixel(fmt, i); + bpl = width * bpp / CIF_YUV_STORED_BIT_WIDTH; size = bpl * height; imagesize += size; diff --git a/drivers/media/platform/rockchip/cif/regs.h b/drivers/media/platform/rockchip/cif/regs.h index dc4ed448ea7a..fd01091e257f 100644 --- a/drivers/media/platform/rockchip/cif/regs.h +++ b/drivers/media/platform/rockchip/cif/regs.h @@ -39,6 +39,8 @@ #define CIF_FETCH_Y_LAST_LINE(val) ((val) & 0x1fff) /* Check if swap y and c in bt1120 mode */ #define CIF_FETCH_IS_Y_FIRST(val) ((val) & 0xf) +#define CIF_RAW_STORED_BIT_WIDTH (16U) +#define CIF_YUV_STORED_BIT_WIDTH (8U) /* RK1808 CIF CSI Registers Offset */ #define CIF_CSI_ID0_CTRL0 0x80 diff --git a/drivers/media/platform/rockchip/cif/version.h b/drivers/media/platform/rockchip/cif/version.h index 6459cc6ed322..c0d59841a47c 100644 --- a/drivers/media/platform/rockchip/cif/version.h +++ b/drivers/media/platform/rockchip/cif/version.h @@ -17,6 +17,7 @@ *2. Compatible with cif only have single dma mode in driver *3. Support cif works with mipi channel for rk3288 *4. Support switching between oneframe and pingpong for cif + *5. Support sampling raw data for cif */ #define RKCIF_DRIVER_VERSION KERNEL_VERSION(0, 1, 0x2)