diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 62fd8a17fd5f..adbbb63fd526 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -60,7 +60,7 @@ static int fimc_init_capture(struct fimc_dev *fimc) fimc_hw_set_mainscaler(ctx); fimc_hw_set_target_format(ctx); fimc_hw_set_rotation(ctx); - fimc_hw_set_effect(ctx); + fimc_hw_set_effect(ctx, false); fimc_hw_set_output_path(ctx); fimc_hw_set_out_dma(ctx); clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); @@ -731,6 +731,17 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, return 0; } +static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx, bool jpeg) +{ + ctx->scaler.enabled = !jpeg; + fimc_ctrls_activate(ctx, !jpeg); + + if (jpeg) + set_bit(ST_CAPT_JPEG, &ctx->fimc_dev->state); + else + clear_bit(ST_CAPT_JPEG, &ctx->fimc_dev->state); +} + static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) { struct fimc_ctx *ctx = fimc->vid_cap.ctx; @@ -783,6 +794,8 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) if (!(ctx->state & FIMC_DST_CROP)) set_frame_crop(ff, 0, 0, pix->width, pix->height); + fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ff->fmt->color)); + /* Reset cropping and set format at the camera interface input */ if (!fimc->vid_cap.user_subdev_api) { ctx->s_frame.fmt = s_fmt; @@ -1133,6 +1146,8 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, *mf = fmt->format; return 0; } + fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ffmt->color)); + ff = fmt->pad == FIMC_SD_PAD_SINK ? &ctx->s_frame : &ctx->d_frame; diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 1a479a23cefb..10aee626c7c9 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -159,22 +159,28 @@ static struct fimc_fmt fimc_formats[] = { .memplanes = 2, .colplanes = 2, .flags = FMT_FLAGS_M2M, + }, { + .name = "JPEG encoded data", + .fourcc = V4L2_PIX_FMT_JPEG, + .color = S5P_FIMC_JPEG, + .depth = { 8 }, + .memplanes = 1, + .colplanes = 1, + .mbus_code = V4L2_MBUS_FMT_JPEG_1X8, + .flags = FMT_FLAGS_CAM, }, }; -int fimc_check_scaler_ratio(int sw, int sh, int dw, int dh, int rot) +int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh, + int dw, int dh, int rotation) { - int tx, ty; + if (rotation == 90 || rotation == 270) + swap(dw, dh); - if (rot == 90 || rot == 270) { - ty = dw; - tx = dh; - } else { - tx = dw; - ty = dh; - } + if (!ctx->scaler.enabled) + return (sw == dw && sh == dh) ? 0 : -EINVAL; - if ((sw >= SCALER_MAX_HRATIO * tx) || (sh >= SCALER_MAX_VRATIO * ty)) + if ((sw >= SCALER_MAX_HRATIO * dw) || (sh >= SCALER_MAX_VRATIO * dh)) return -EINVAL; return 0; @@ -321,7 +327,7 @@ static int stop_streaming(struct vb2_queue *q) return 0; } -static void fimc_capture_irq_handler(struct fimc_dev *fimc) +void fimc_capture_irq_handler(struct fimc_dev *fimc, bool final) { struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_vid_buffer *v_buf; @@ -329,7 +335,7 @@ static void fimc_capture_irq_handler(struct fimc_dev *fimc) struct timespec ts; if (!list_empty(&cap->active_buf_q) && - test_bit(ST_CAPT_RUN, &fimc->state)) { + test_bit(ST_CAPT_RUN, &fimc->state) && final) { ktime_get_real_ts(&ts); v_buf = active_queue_pop(cap); @@ -364,7 +370,8 @@ static void fimc_capture_irq_handler(struct fimc_dev *fimc) } if (cap->active_buf_cnt == 0) { - clear_bit(ST_CAPT_RUN, &fimc->state); + if (final) + clear_bit(ST_CAPT_RUN, &fimc->state); if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) cap->buf_index = 0; @@ -407,14 +414,12 @@ static irqreturn_t fimc_irq_handler(int irq, void *priv) spin_unlock(&ctx->slock); } return IRQ_HANDLED; - } else { - if (test_bit(ST_CAPT_PEND, &fimc->state)) { - fimc_capture_irq_handler(fimc); - - if (cap->active_buf_cnt == 1) { - fimc_deactivate_capture(fimc); - clear_bit(ST_CAPT_STREAM, &fimc->state); - } + } else if (test_bit(ST_CAPT_PEND, &fimc->state)) { + fimc_capture_irq_handler(fimc, + !test_bit(ST_CAPT_JPEG, &fimc->state)); + if (cap->active_buf_cnt == 1) { + fimc_deactivate_capture(fimc); + clear_bit(ST_CAPT_STREAM, &fimc->state); } } out: @@ -586,9 +591,6 @@ int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags) fimc_set_yuv_order(ctx); } - /* Input DMA mode is not allowed when the scaler is disabled. */ - ctx->scaler.enabled = 1; - if (flags & FIMC_SRC_ADDR) { vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); ret = fimc_prepare_addr(ctx, vb, s_frame, &s_frame->paddr); @@ -643,7 +645,7 @@ static void fimc_dma_run(void *priv) fimc_hw_set_mainscaler(ctx); fimc_hw_set_target_format(ctx); fimc_hw_set_rotation(ctx); - fimc_hw_set_effect(ctx); + fimc_hw_set_effect(ctx, false); } fimc_hw_set_output_path(ctx); @@ -773,7 +775,7 @@ static int fimc_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_ROTATE: if (fimc_capture_pending(fimc) || fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { - ret = fimc_check_scaler_ratio(ctx->s_frame.width, + ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, ctx->s_frame.height, ctx->d_frame.width, ctx->d_frame.height, ctrl->val); } @@ -1098,6 +1100,8 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, fimc_fill_frame(frame, f); + ctx->scaler.enabled = 1; + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_DST_FMT, ctx); else @@ -1269,15 +1273,13 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) /* Check to see if scaling ratio is within supported range */ if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height, - ctx->d_frame.width, - ctx->d_frame.height, - ctx->rotation); + ret = fimc_check_scaler_ratio(ctx, cr->c.width, + cr->c.height, ctx->d_frame.width, + ctx->d_frame.height, ctx->rotation); } else { - ret = fimc_check_scaler_ratio(ctx->s_frame.width, - ctx->s_frame.height, - cr->c.width, cr->c.height, - ctx->rotation); + ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, + ctx->s_frame.height, cr->c.width, + cr->c.height, ctx->rotation); } if (ret) { v4l2_err(fimc->m2m.vfd, "Out of scaler range\n"); diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index e4520b2dde43..9b448751f44b 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -66,6 +66,7 @@ enum fimc_dev_flags { ST_CAPT_SHUT, ST_CAPT_BUSY, ST_CAPT_APPLY_CFG, + ST_CAPT_JPEG, }; #define fimc_m2m_active(dev) test_bit(ST_M2M_RUN, &(dev)->state) @@ -669,7 +670,7 @@ void fimc_hw_en_irq(struct fimc_dev *fimc, int enable); void fimc_hw_set_prescaler(struct fimc_ctx *ctx); void fimc_hw_set_mainscaler(struct fimc_ctx *ctx); void fimc_hw_en_capture(struct fimc_ctx *ctx); -void fimc_hw_set_effect(struct fimc_ctx *ctx); +void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active); void fimc_hw_set_in_dma(struct fimc_ctx *ctx); void fimc_hw_set_input_path(struct fimc_ctx *ctx); void fimc_hw_set_output_path(struct fimc_ctx *ctx); @@ -697,7 +698,8 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, struct fimc_fmt *fimc_find_format(u32 *pixelformat, u32 *mbus_code, unsigned int mask, int index); -int fimc_check_scaler_ratio(int sw, int sh, int dw, int dh, int rot); +int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh, + int dw, int dh, int rotation); int fimc_set_scaler_info(struct fimc_ctx *ctx); int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags); int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, @@ -705,6 +707,7 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f); void fimc_set_yuv_order(struct fimc_ctx *ctx); void fimc_fill_frame(struct fimc_frame *frame, struct v4l2_format *f); +void fimc_capture_irq_handler(struct fimc_dev *fimc, bool done); int fimc_register_m2m_device(struct fimc_dev *fimc, struct v4l2_device *v4l2_dev); diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index a1fff022c5b4..2a1ae51ad949 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -352,17 +352,19 @@ void fimc_hw_en_capture(struct fimc_ctx *ctx) writel(cfg | S5P_CIIMGCPT_IMGCPTEN, dev->regs + S5P_CIIMGCPT); } -void fimc_hw_set_effect(struct fimc_ctx *ctx) +void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active) { struct fimc_dev *dev = ctx->fimc_dev; struct fimc_effect *effect = &ctx->effect; - u32 cfg = (S5P_CIIMGEFF_IE_ENABLE | S5P_CIIMGEFF_IE_SC_AFTER); + u32 cfg = 0; - cfg |= effect->type; - - if (effect->type == S5P_FIMC_EFFECT_ARBITRARY) { - cfg |= S5P_CIIMGEFF_PAT_CB(effect->pat_cb); - cfg |= S5P_CIIMGEFF_PAT_CR(effect->pat_cr); + if (active) { + cfg |= S5P_CIIMGEFF_IE_SC_AFTER | S5P_CIIMGEFF_IE_ENABLE; + cfg |= effect->type; + if (effect->type == S5P_FIMC_EFFECT_ARBITRARY) { + cfg |= S5P_CIIMGEFF_PAT_CB(effect->pat_cb); + cfg |= S5P_CIIMGEFF_PAT_CR(effect->pat_cr); + } } writel(cfg, dev->regs + S5P_CIIMGEFF); @@ -592,6 +594,9 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc, else if (bus_width == 16) cfg |= S5P_CISRCFMT_ITU601_16BIT; } /* else defaults to ITU-R BT.656 8-bit */ + } else if (cam->bus_type == FIMC_MIPI_CSI2) { + if (fimc_fmt_is_jpeg(f->fmt->color)) + cfg |= S5P_CISRCFMT_ITU601_8BIT; } cfg |= S5P_CISRCFMT_HSIZE(f->o_width) | S5P_CISRCFMT_VSIZE(f->o_height); @@ -633,7 +638,7 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, /* Select ITU B interface, disable Writeback path and test pattern. */ cfg &= ~(S5P_CIGCTRL_TESTPAT_MASK | S5P_CIGCTRL_SELCAM_ITU_A | S5P_CIGCTRL_SELCAM_MIPI | S5P_CIGCTRL_CAMIF_SELWB | - S5P_CIGCTRL_SELCAM_MIPI_A); + S5P_CIGCTRL_SELCAM_MIPI_A | S5P_CIGCTRL_CAM_JPEG); if (cam->bus_type == FIMC_MIPI_CSI2) { cfg |= S5P_CIGCTRL_SELCAM_MIPI; @@ -642,9 +647,15 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, cfg |= S5P_CIGCTRL_SELCAM_MIPI_A; /* TODO: add remaining supported formats. */ - if (vid_cap->mf.code == V4L2_MBUS_FMT_VYUY8_2X8) { + switch (vid_cap->mf.code) { + case V4L2_MBUS_FMT_VYUY8_2X8: tmp = S5P_CSIIMGFMT_YCBCR422_8BIT; - } else { + break; + case V4L2_MBUS_FMT_JPEG_1X8: + tmp = S5P_CSIIMGFMT_USER(1); + cfg |= S5P_CIGCTRL_CAM_JPEG; + break; + default: v4l2_err(fimc->vid_cap.vfd, "Not supported camera pixel format: %d", vid_cap->mf.code); diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h index 0fea3e635d76..94d2302698a9 100644 --- a/drivers/media/video/s5p-fimc/regs-fimc.h +++ b/drivers/media/video/s5p-fimc/regs-fimc.h @@ -54,6 +54,7 @@ #define S5P_CIGCTRL_IRQ_CLR (1 << 19) #define S5P_CIGCTRL_IRQ_ENABLE (1 << 16) #define S5P_CIGCTRL_SHDW_DISABLE (1 << 12) +#define S5P_CIGCTRL_CAM_JPEG (1 << 8) #define S5P_CIGCTRL_SELCAM_MIPI_A (1 << 7) #define S5P_CIGCTRL_CAMIF_SELWB (1 << 6) /* 0 - ITU601; 1 - ITU709 */ @@ -184,7 +185,6 @@ /* Image effect */ #define S5P_CIIMGEFF 0xd0 -#define S5P_CIIMGEFF_IE_DISABLE (0 << 30) #define S5P_CIIMGEFF_IE_ENABLE (1 << 30) #define S5P_CIIMGEFF_IE_SC_BEFORE (0 << 29) #define S5P_CIIMGEFF_IE_SC_AFTER (1 << 29) @@ -286,10 +286,8 @@ #define S5P_CSIIMGFMT_RAW8 0x2a #define S5P_CSIIMGFMT_RAW10 0x2b #define S5P_CSIIMGFMT_RAW12 0x2c -#define S5P_CSIIMGFMT_USER1 0x30 -#define S5P_CSIIMGFMT_USER2 0x31 -#define S5P_CSIIMGFMT_USER3 0x32 -#define S5P_CSIIMGFMT_USER4 0x33 +/* User defined formats. x = 0...16. */ +#define S5P_CSIIMGFMT_USER(x) (0x30 + x - 1) /* Output frame buffer sequence mask */ #define S5P_CIFCNTSEQ 0x1FC