diff options
Diffstat (limited to 'drivers/media/platform')
122 files changed, 5391 insertions, 2016 deletions
diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c index 3c02aa2a54aa..9e64041cc1c1 100644 --- a/drivers/media/platform/amphion/vdec.c +++ b/drivers/media/platform/amphion/vdec.c @@ -63,6 +63,7 @@ struct vdec_t { bool is_source_changed; u32 source_change; u32 drain; + bool aborting; }; static const struct vpu_format vdec_formats[] = { @@ -104,7 +105,6 @@ static const struct vpu_format vdec_formats[] = { .pixfmt = V4L2_PIX_FMT_VC1_ANNEX_L, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION }, { .pixfmt = V4L2_PIX_FMT_MPEG2, @@ -178,16 +178,6 @@ static int vdec_ctrl_init(struct vpu_inst *inst) return 0; } -static void vdec_set_last_buffer_dequeued(struct vpu_inst *inst) -{ - struct vdec_t *vdec = inst->priv; - - if (vdec->eos_received) { - if (!vpu_set_last_buffer_dequeued(inst)) - vdec->eos_received--; - } -} - static void vdec_handle_resolution_change(struct vpu_inst *inst) { struct vdec_t *vdec = inst->priv; @@ -234,6 +224,21 @@ static int vdec_update_state(struct vpu_inst *inst, enum vpu_codec_state state, return 0; } +static void vdec_set_last_buffer_dequeued(struct vpu_inst *inst) +{ + struct vdec_t *vdec = inst->priv; + + if (inst->state == VPU_CODEC_STATE_DYAMIC_RESOLUTION_CHANGE) + return; + + if (vdec->eos_received) { + if (!vpu_set_last_buffer_dequeued(inst)) { + vdec->eos_received--; + vdec_update_state(inst, VPU_CODEC_STATE_DRAIN, 0); + } + } +} + static int vdec_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { strscpy(cap->driver, "amphion-vpu", sizeof(cap->driver)); @@ -493,6 +498,8 @@ static int vdec_drain(struct vpu_inst *inst) static int vdec_cmd_start(struct vpu_inst *inst) { + struct vdec_t *vdec = inst->priv; + switch (inst->state) { case VPU_CODEC_STATE_STARTED: case VPU_CODEC_STATE_DRAIN: @@ -503,6 +510,8 @@ static int vdec_cmd_start(struct vpu_inst *inst) break; } vpu_process_capture_buffer(inst); + if (vdec->eos_received) + vdec_set_last_buffer_dequeued(inst); return 0; } @@ -731,6 +740,7 @@ static void vdec_stop_done(struct vpu_inst *inst) vdec->eos_received = 0; vdec->is_source_changed = false; vdec->source_change = 0; + inst->total_input_count = 0; vpu_inst_unlock(inst); } @@ -939,6 +949,9 @@ static int vdec_response_frame(struct vpu_inst *inst, struct vb2_v4l2_buffer *vb if (inst->state != VPU_CODEC_STATE_ACTIVE) return -EINVAL; + if (vdec->aborting) + return -EINVAL; + if (!vdec->req_frame_count) return -EINVAL; @@ -1048,6 +1061,8 @@ static void vdec_clear_slots(struct vpu_inst *inst) vpu_buf = vdec->slots[i]; vbuf = &vpu_buf->m2m_buf.vb; + vpu_trace(inst->dev, "clear slot %d\n", i); + vdec_response_fs_release(inst, i, vpu_buf->tag); vdec_recycle_buffer(inst, vbuf); vdec->slots[i]->state = VPU_BUF_STATE_IDLE; vdec->slots[i] = NULL; @@ -1203,7 +1218,6 @@ static void vdec_event_eos(struct vpu_inst *inst) vdec->eos_received++; vdec->fixed_fmt = false; inst->min_buffer_cap = VDEC_MIN_BUFFER_CAP; - vdec_update_state(inst, VPU_CODEC_STATE_DRAIN, 0); vdec_set_last_buffer_dequeued(inst); vpu_inst_unlock(inst); } @@ -1310,6 +1324,8 @@ static void vdec_abort(struct vpu_inst *inst) int ret; vpu_trace(inst->dev, "[%d] state = %d\n", inst->id, inst->state); + + vdec->aborting = true; vpu_iface_add_scode(inst, SCODE_PADDING_ABORT); vdec->params.end_flag = 1; vpu_iface_set_decode_params(inst, &vdec->params, 1); @@ -1333,6 +1349,7 @@ static void vdec_abort(struct vpu_inst *inst) vdec->decoded_frame_count = 0; vdec->display_frame_count = 0; vdec->sequence = 0; + vdec->aborting = false; } static void vdec_stop(struct vpu_inst *inst, bool free) @@ -1369,8 +1386,7 @@ static void vdec_cleanup(struct vpu_inst *inst) return; vdec = inst->priv; - if (vdec) - vfree(vdec); + vfree(vdec); inst->priv = NULL; vfree(inst); } @@ -1480,10 +1496,10 @@ static int vdec_stop_session(struct vpu_inst *inst, u32 type) vdec_update_state(inst, VPU_CODEC_STATE_SEEK, 0); vdec->drain = 0; } else { - if (inst->state != VPU_CODEC_STATE_DYAMIC_RESOLUTION_CHANGE) + if (inst->state != VPU_CODEC_STATE_DYAMIC_RESOLUTION_CHANGE) { vdec_abort(inst); - - vdec->eos_received = 0; + vdec->eos_received = 0; + } vdec_clear_slots(inst); } diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c index 43d61d82f58c..461524dd1e44 100644 --- a/drivers/media/platform/amphion/venc.c +++ b/drivers/media/platform/amphion/venc.c @@ -919,8 +919,7 @@ static void venc_cleanup(struct vpu_inst *inst) return; venc = inst->priv; - if (venc) - vfree(venc); + vfree(venc); inst->priv = NULL; vfree(inst); } diff --git a/drivers/media/platform/amphion/vpu.h b/drivers/media/platform/amphion/vpu.h index e56b96a7e5d3..f914de6ed81e 100644 --- a/drivers/media/platform/amphion/vpu.h +++ b/drivers/media/platform/amphion/vpu.h @@ -258,6 +258,7 @@ struct vpu_inst { struct vpu_format cap_format; u32 min_buffer_cap; u32 min_buffer_out; + u32 total_input_count; struct v4l2_rect crop; u32 colorspace; diff --git a/drivers/media/platform/amphion/vpu_cmds.c b/drivers/media/platform/amphion/vpu_cmds.c index 9b39d77a178d..f4d7ca78a621 100644 --- a/drivers/media/platform/amphion/vpu_cmds.c +++ b/drivers/media/platform/amphion/vpu_cmds.c @@ -117,8 +117,7 @@ static void vpu_free_cmd(struct vpu_cmd_t *cmd) { if (!cmd) return; - if (cmd->pkt) - vfree(cmd->pkt); + vfree(cmd->pkt); vfree(cmd); } diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c index 68ad183925fd..73faa50d2865 100644 --- a/drivers/media/platform/amphion/vpu_core.c +++ b/drivers/media/platform/amphion/vpu_core.c @@ -257,14 +257,8 @@ static int vpu_core_register(struct device *dev, struct vpu_core *core) } list_add_tail(&core->list, &vpu->cores); - vpu_core_get_vpu(core); - if (vpu_iface_get_power_state(core)) - ret = vpu_core_restore(core); - if (ret) - goto error; - return 0; error: if (core->msg_buffer) { @@ -362,7 +356,10 @@ struct vpu_core *vpu_request_core(struct vpu_dev *vpu, enum vpu_core_type type) pm_runtime_resume_and_get(core->dev); if (core->state == VPU_CORE_DEINIT) { - ret = vpu_core_boot(core, true); + if (vpu_iface_get_power_state(core)) + ret = vpu_core_restore(core); + else + ret = vpu_core_boot(core, true); if (ret) { pm_runtime_put_sync(core->dev); mutex_unlock(&core->lock); @@ -455,8 +452,13 @@ int vpu_inst_unregister(struct vpu_inst *inst) } vpu_core_check_hang(core); if (core->state == VPU_CORE_HANG && !core->instance_mask) { + int err; + dev_info(core->dev, "reset hang core\n"); - if (!vpu_core_sw_reset(core)) { + mutex_unlock(&core->lock); + err = vpu_core_sw_reset(core); + mutex_lock(&core->lock); + if (!err) { core->state = VPU_CORE_ACTIVE; core->hang_mask = 0; } diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c index da62bd718fb8..f72c8a506b22 100644 --- a/drivers/media/platform/amphion/vpu_dbg.c +++ b/drivers/media/platform/amphion/vpu_dbg.c @@ -27,7 +27,7 @@ struct print_buf_desc { u32 bytes; u32 read; u32 write; - char buffer[0]; + char buffer[]; }; static char *vb2_stat_name[] = { diff --git a/drivers/media/platform/amphion/vpu_malone.c b/drivers/media/platform/amphion/vpu_malone.c index f29c223eefce..f4a488bf9880 100644 --- a/drivers/media/platform/amphion/vpu_malone.c +++ b/drivers/media/platform/amphion/vpu_malone.c @@ -309,6 +309,7 @@ struct malone_padding_scode { struct malone_fmt_mapping { u32 pixelformat; enum vpu_malone_format malone_format; + u32 is_disabled; }; struct malone_scode_t { @@ -568,6 +569,8 @@ static enum vpu_malone_format vpu_malone_format_remap(u32 pixelformat) u32 i; for (i = 0; i < ARRAY_SIZE(fmt_mappings); i++) { + if (fmt_mappings[i].is_disabled) + continue; if (pixelformat == fmt_mappings[i].pixelformat) return fmt_mappings[i].malone_format; } @@ -575,6 +578,19 @@ static enum vpu_malone_format vpu_malone_format_remap(u32 pixelformat) return MALONE_FMT_NULL; } +bool vpu_malone_check_fmt(enum vpu_core_type type, u32 pixelfmt) +{ + if (!vpu_imx8q_check_fmt(type, pixelfmt)) + return false; + + if (pixelfmt == V4L2_PIX_FMT_NV12M_8L128 || pixelfmt == V4L2_PIX_FMT_NV12M_10BE_8L128) + return true; + if (vpu_malone_format_remap(pixelfmt) == MALONE_FMT_NULL) + return false; + + return true; +} + static void vpu_malone_set_stream_cfg(struct vpu_shared_addr *shared, u32 instance, enum vpu_malone_format malone_format) @@ -610,6 +626,8 @@ static int vpu_malone_set_params(struct vpu_shared_addr *shared, enum vpu_malone_format malone_format; malone_format = vpu_malone_format_remap(params->codec_format); + if (WARN_ON(malone_format == MALONE_FMT_NULL)) + return -EINVAL; iface->udata_buffer[instance].base = params->udata.base; iface->udata_buffer[instance].slot_size = params->udata.size; @@ -1296,6 +1314,8 @@ static int vpu_malone_insert_scode_vc1_l_seq(struct malone_scode_t *scode) int size = 0; u8 rcv_seqhdr[MALONE_VC1_RCV_SEQ_HEADER_LEN]; + if (scode->inst->total_input_count) + return 0; scode->need_data = 0; ret = vpu_malone_insert_scode_seq(scode, MALONE_CODEC_ID_VC1_SIMPLE, sizeof(rcv_seqhdr)); diff --git a/drivers/media/platform/amphion/vpu_malone.h b/drivers/media/platform/amphion/vpu_malone.h index e5a5cbe9843e..02a9d9530970 100644 --- a/drivers/media/platform/amphion/vpu_malone.h +++ b/drivers/media/platform/amphion/vpu_malone.h @@ -40,5 +40,6 @@ int vpu_malone_pre_cmd(struct vpu_shared_addr *shared, u32 instance); int vpu_malone_post_cmd(struct vpu_shared_addr *shared, u32 instance); int vpu_malone_init_instance(struct vpu_shared_addr *shared, u32 instance); u32 vpu_malone_get_max_instance_count(struct vpu_shared_addr *shared); +bool vpu_malone_check_fmt(enum vpu_core_type type, u32 pixelfmt); #endif diff --git a/drivers/media/platform/amphion/vpu_msgs.c b/drivers/media/platform/amphion/vpu_msgs.c index d5850df8f1d5..d8247f36d84b 100644 --- a/drivers/media/platform/amphion/vpu_msgs.c +++ b/drivers/media/platform/amphion/vpu_msgs.c @@ -150,7 +150,12 @@ static void vpu_session_handle_eos(struct vpu_inst *inst, struct vpu_rpc_event * static void vpu_session_handle_error(struct vpu_inst *inst, struct vpu_rpc_event *pkt) { - dev_err(inst->dev, "unsupported stream\n"); + char *str = (char *)pkt->data; + + if (strlen(str)) + dev_err(inst->dev, "instance %d firmware error : %s\n", inst->id, str); + else + dev_err(inst->dev, "instance %d is unsupported stream\n", inst->id); call_void_vop(inst, event_notify, VPU_MSG_ID_UNSUPPORTED, NULL); vpu_v4l2_set_error(inst); } diff --git a/drivers/media/platform/amphion/vpu_rpc.c b/drivers/media/platform/amphion/vpu_rpc.c index 18a164766409..676f7da041bd 100644 --- a/drivers/media/platform/amphion/vpu_rpc.c +++ b/drivers/media/platform/amphion/vpu_rpc.c @@ -195,7 +195,7 @@ static struct vpu_iface_ops imx8q_rpc_ops[] = { }, [VPU_CORE_TYPE_DEC] = { .check_codec = vpu_imx8q_check_codec, - .check_fmt = vpu_imx8q_check_fmt, + .check_fmt = vpu_malone_check_fmt, .boot_core = vpu_imx8q_boot_core, .get_power_state = vpu_imx8q_get_power_state, .on_firmware_loaded = vpu_imx8q_on_firmware_loaded, diff --git a/drivers/media/platform/amphion/vpu_rpc.h b/drivers/media/platform/amphion/vpu_rpc.h index 25119e5e807e..7eb6f01e6ab5 100644 --- a/drivers/media/platform/amphion/vpu_rpc.h +++ b/drivers/media/platform/amphion/vpu_rpc.h @@ -312,11 +312,16 @@ static inline int vpu_iface_input_frame(struct vpu_inst *inst, struct vb2_buffer *vb) { struct vpu_iface_ops *ops = vpu_core_get_iface(inst->core); + int ret; if (!ops || !ops->input_frame) return -EINVAL; - return ops->input_frame(inst->core->iface, inst, vb); + ret = ops->input_frame(inst->core->iface, inst, vb); + if (ret < 0) + return ret; + inst->total_input_count++; + return ret; } static inline int vpu_iface_config_memory_resource(struct vpu_inst *inst, diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 446f07d09d0b..8a3eed957ae6 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -500,10 +500,12 @@ static int vpu_vb2_start_streaming(struct vb2_queue *q, unsigned int count) fmt->sizeimage[1], fmt->bytesperline[1], fmt->sizeimage[2], fmt->bytesperline[2], q->num_buffers); - call_void_vop(inst, start, q->type); vb2_clear_last_buffer_dequeued(q); + ret = call_vop(inst, start, q->type); + if (ret) + vpu_vb2_buffers_return(inst, q->type, VB2_BUF_STATE_QUEUED); - return 0; + return ret; } static void vpu_vb2_stop_streaming(struct vb2_queue *q) diff --git a/drivers/media/platform/atmel/Kconfig b/drivers/media/platform/atmel/Kconfig index 83aebee0c8eb..f399dba62e17 100644 --- a/drivers/media/platform/atmel/Kconfig +++ b/drivers/media/platform/atmel/Kconfig @@ -20,12 +20,14 @@ config VIDEO_ATMEL_ISC config VIDEO_ATMEL_XISC tristate "ATMEL eXtended Image Sensor Controller (XISC) support" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV && COMMON_CLK && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_DEV && COMMON_CLK depends on ARCH_AT91 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select REGMAP_MMIO select V4L2_FWNODE select VIDEO_ATMEL_ISC_BASE + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help This module makes the ATMEL eXtended Image Sensor Controller available as a v4l2 device. diff --git a/drivers/media/platform/atmel/atmel-isc-base.c b/drivers/media/platform/atmel/atmel-isc-base.c index 2f07a50035c8..9e5317a7d516 100644 --- a/drivers/media/platform/atmel/atmel-isc-base.c +++ b/drivers/media/platform/atmel/atmel-isc-base.c @@ -132,12 +132,9 @@ static int isc_buffer_prepare(struct vb2_buffer *vb) return 0; } -static void isc_start_dma(struct isc_device *isc) +static void isc_crop_pfe(struct isc_device *isc) { struct regmap *regmap = isc->regmap; - u32 sizeimage = isc->fmt.fmt.pix.sizeimage; - u32 dctrl_dview; - dma_addr_t addr0; u32 h, w; h = isc->fmt.fmt.pix.height; @@ -172,6 +169,14 @@ static void isc_start_dma(struct isc_device *isc) regmap_update_bits(regmap, ISC_PFE_CFG0, ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN, ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN); +} + +static void isc_start_dma(struct isc_device *isc) +{ + struct regmap *regmap = isc->regmap; + u32 sizeimage = isc->fmt.fmt.pix.sizeimage; + u32 dctrl_dview; + dma_addr_t addr0; addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0); regmap_write(regmap, ISC_DAD0 + isc->offsets.dma, addr0); @@ -369,6 +374,7 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) struct isc_buffer, list); list_del(&isc->cur_frm->list); + isc_crop_pfe(isc); isc_start_dma(isc); spin_unlock_irqrestore(&isc->dma_queue_lock, flags); @@ -1466,7 +1472,7 @@ static void isc_awb_work(struct work_struct *w) if (isc->stop) { mutex_unlock(&isc->awb_mutex); return; - }; + } isc_update_profile(isc); @@ -1525,10 +1531,6 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl) else ctrls->awb = ISC_WB_NONE; - /* we did not configure ISC yet */ - if (!isc->config.sd_format) - break; - /* configure the controls with new values from v4l2 */ if (ctrl->cluster[ISC_CTRL_R_GAIN]->is_new) ctrls->gain[ISC_HIS_CFG_MODE_R] = isc->r_gain_ctrl->val; diff --git a/drivers/media/platform/atmel/atmel-sama7g5-isc.c b/drivers/media/platform/atmel/atmel-sama7g5-isc.c index 83b175070c06..8b11aa8340d7 100644 --- a/drivers/media/platform/atmel/atmel-sama7g5-isc.c +++ b/drivers/media/platform/atmel/atmel-sama7g5-isc.c @@ -591,11 +591,13 @@ static const struct dev_pm_ops microchip_xisc_dev_pm_ops = { SET_RUNTIME_PM_OPS(xisc_runtime_suspend, xisc_runtime_resume, NULL) }; +#if IS_ENABLED(CONFIG_OF) static const struct of_device_id microchip_xisc_of_match[] = { { .compatible = "microchip,sama7g5-isc" }, { } }; MODULE_DEVICE_TABLE(of, microchip_xisc_of_match); +#endif static struct platform_driver microchip_xisc_driver = { .probe = microchip_xisc_probe, diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index bc5b0a0168ec..87685a62a5c2 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -1369,6 +1369,9 @@ static int mtk_jpeg_probe(struct platform_device *pdev) jpeg->vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; + if (of_get_property(pdev->dev.of_node, "dma-ranges", NULL)) + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); + ret = video_register_device(jpeg->vdev, VFL_TYPE_VIDEO, -1); if (ret) { v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n"); diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_ipi.h b/drivers/media/platform/mediatek/mdp/mtk_mdp_ipi.h index 2cb8cecb3077..b810c96695c8 100644 --- a/drivers/media/platform/mediatek/mdp/mtk_mdp_ipi.h +++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_ipi.h @@ -40,12 +40,14 @@ struct mdp_ipi_init { * @ipi_id : IPI_MDP * @ap_inst : AP mtk_mdp_vpu address * @vpu_inst_addr : VPU MDP instance address + * @padding : Alignment padding */ struct mdp_ipi_comm { uint32_t msg_id; uint32_t ipi_id; uint64_t ap_inst; uint32_t vpu_inst_addr; + uint32_t padding; }; /** diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c index 52e5d36aa912..7d194a476713 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c @@ -35,6 +35,44 @@ mtk_vdec_find_format(struct v4l2_format *f, return NULL; } +static bool mtk_vdec_get_cap_fmt(struct mtk_vcodec_ctx *ctx, int format_index) +{ + const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; + const struct mtk_video_fmt *fmt; + struct mtk_q_data *q_data; + int num_frame_count = 0, i; + bool ret = true; + + for (i = 0; i < *dec_pdata->num_formats; i++) { + if (dec_pdata->vdec_formats[i].type != MTK_FMT_FRAME) + continue; + + num_frame_count++; + } + + if (num_frame_count == 1) + return true; + + fmt = &dec_pdata->vdec_formats[format_index]; + q_data = &ctx->q_data[MTK_Q_DATA_SRC]; + switch (q_data->fmt->fourcc) { + case V4L2_PIX_FMT_VP8_FRAME: + if (fmt->fourcc == V4L2_PIX_FMT_MM21) + ret = true; + break; + case V4L2_PIX_FMT_H264_SLICE: + case V4L2_PIX_FMT_VP9_FRAME: + if (fmt->fourcc == V4L2_PIX_FMT_MM21) + ret = false; + break; + default: + ret = true; + break; + } + + return ret; +} + static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_ctx *ctx, enum v4l2_buf_type type) { @@ -112,8 +150,6 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx) { struct mtk_q_data *q_data; - ctx->dev->vdec_pdata->init_vdec_params(ctx); - ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex; ctx->fh.m2m_ctx = ctx->m2m_ctx; ctx->fh.ctrl_handler = &ctx->ctrl_hdl; @@ -141,15 +177,6 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx) q_data->coded_height = DFT_CFG_HEIGHT; q_data->fmt = ctx->dev->vdec_pdata->default_cap_fmt; q_data->field = V4L2_FIELD_NONE; - ctx->max_width = MTK_VDEC_MAX_W; - ctx->max_height = MTK_VDEC_MAX_H; - - v4l_bound_align_image(&q_data->coded_width, - MTK_VDEC_MIN_W, - ctx->max_width, 4, - &q_data->coded_height, - MTK_VDEC_MIN_H, - ctx->max_height, 5, 6); q_data->sizeimage[0] = q_data->coded_width * q_data->coded_height; q_data->bytesperline[0] = q_data->coded_width; @@ -185,12 +212,34 @@ static int vidioc_vdec_dqbuf(struct file *file, void *priv, return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); } +static int mtk_vcodec_dec_get_chip_name(void *priv) +{ + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + struct device *dev = &ctx->dev->plat_dev->dev; + + if (of_device_is_compatible(dev->of_node, "mediatek,mt8173-vcodec-dec")) + return 8173; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8183-vcodec-dec")) + return 8183; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8192-vcodec-dec")) + return 8192; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8195-vcodec-dec")) + return 8195; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8186-vcodec-dec")) + return 8186; + else + return 8173; +} + static int vidioc_vdec_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strscpy(cap->driver, MTK_VCODEC_DEC_NAME, sizeof(cap->driver)); - strscpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info)); - strscpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card)); + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + struct device *dev = &ctx->dev->plat_dev->dev; + int platform_name = mtk_vcodec_dec_get_chip_name(priv); + + strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); + snprintf(cap->card, sizeof(cap->card), "MT%d video decoder", platform_name); return 0; } @@ -198,6 +247,11 @@ static int vidioc_vdec_querycap(struct file *file, void *priv, static int vidioc_vdec_subscribe_evt(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { + struct mtk_vcodec_ctx *ctx = fh_to_ctx(fh); + + if (ctx->dev->vdec_pdata->uses_stateless_api) + return v4l2_ctrl_subscribe_event(fh, sub); + switch (sub->type) { case V4L2_EVENT_EOS: return v4l2_event_subscribe(fh, sub, 2, NULL); @@ -212,13 +266,18 @@ static int vidioc_try_fmt(struct mtk_vcodec_ctx *ctx, struct v4l2_format *f, const struct mtk_video_fmt *fmt) { struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; + const struct v4l2_frmsize_stepwise *frmsize; pix_fmt_mp->field = V4L2_FIELD_NONE; - pix_fmt_mp->width = - clamp(pix_fmt_mp->width, MTK_VDEC_MIN_W, ctx->max_width); - pix_fmt_mp->height = - clamp(pix_fmt_mp->height, MTK_VDEC_MIN_H, ctx->max_height); + /* Always apply frame size constraints from the coded side */ + if (V4L2_TYPE_IS_OUTPUT(f->type)) + frmsize = &fmt->frmsize; + else + frmsize = &ctx->q_data[MTK_Q_DATA_SRC].fmt->frmsize; + + pix_fmt_mp->width = clamp(pix_fmt_mp->width, MTK_VDEC_MIN_W, frmsize->max_width); + pix_fmt_mp->height = clamp(pix_fmt_mp->height, MTK_VDEC_MIN_H, frmsize->max_height); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { pix_fmt_mp->num_planes = 1; @@ -234,18 +293,15 @@ static int vidioc_try_fmt(struct mtk_vcodec_ctx *ctx, struct v4l2_format *f, */ tmp_w = pix_fmt_mp->width; tmp_h = pix_fmt_mp->height; - v4l_bound_align_image(&pix_fmt_mp->width, - MTK_VDEC_MIN_W, - ctx->max_width, 6, - &pix_fmt_mp->height, - MTK_VDEC_MIN_H, - ctx->max_height, 6, 9); + v4l_bound_align_image(&pix_fmt_mp->width, MTK_VDEC_MIN_W, frmsize->max_width, 6, + &pix_fmt_mp->height, MTK_VDEC_MIN_H, frmsize->max_height, 6, + 9); if (pix_fmt_mp->width < tmp_w && - (pix_fmt_mp->width + 64) <= ctx->max_width) + (pix_fmt_mp->width + 64) <= frmsize->max_width) pix_fmt_mp->width += 64; if (pix_fmt_mp->height < tmp_h && - (pix_fmt_mp->height + 64) <= ctx->max_height) + (pix_fmt_mp->height + 64) <= frmsize->max_height) pix_fmt_mp->height += 64; mtk_v4l2_debug(0, @@ -435,13 +491,6 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, if (fmt == NULL) return -EINVAL; - if (!(ctx->dev->dec_capability & VCODEC_CAPABILITY_4K_DISABLED) && - fmt->fourcc != V4L2_PIX_FMT_VP8_FRAME) { - mtk_v4l2_debug(3, "4K is enabled"); - ctx->max_width = VCODEC_DEC_4K_CODED_WIDTH; - ctx->max_height = VCODEC_DEC_4K_CODED_HEIGHT; - } - q_data->fmt = fmt; vidioc_try_fmt(ctx, f, q_data->fmt); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { @@ -526,15 +575,17 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, if (fsize->index != 0) return -EINVAL; - for (i = 0; i < *dec_pdata->num_framesizes; ++i) { - if (fsize->pixel_format != dec_pdata->vdec_framesizes[i].fourcc) + for (i = 0; i < *dec_pdata->num_formats; i++) { + if (fsize->pixel_format != dec_pdata->vdec_formats[i].fourcc) continue; + /* Only coded formats have frame sizes set */ + if (!dec_pdata->vdec_formats[i].frmsize.max_width) + return -ENOTTY; + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - fsize->stepwise = dec_pdata->vdec_framesizes[i].stepwise; + fsize->stepwise = dec_pdata->vdec_formats[i].frmsize; - fsize->stepwise.max_width = ctx->max_width; - fsize->stepwise.max_height = ctx->max_height; mtk_v4l2_debug(1, "%x, %d %d %d %d %d %d", ctx->dev->dec_capability, fsize->stepwise.min_width, @@ -566,6 +617,9 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv, dec_pdata->vdec_formats[i].type != MTK_FMT_FRAME) continue; + if (!output_queue && !mtk_vdec_get_cap_fmt(ctx, i)) + continue; + if (j == f->index) break; ++j; @@ -735,6 +789,7 @@ int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb) mtk_v4l2_err("data will not fit into plane %d (%lu < %d)", i, vb2_plane_size(vb, i), q_data->sizeimage[i]); + return -EINVAL; } if (!V4L2_TYPE_IS_OUTPUT(vb->type)) vb2_set_plane_payload(vb, i, q_data->sizeimage[i]); @@ -938,6 +993,7 @@ int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq, src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->lock = &ctx->dev->dev_mutex; src_vq->dev = &ctx->dev->plat_dev->dev; + src_vq->allow_cache_hints = 1; ret = vb2_queue_init(src_vq); if (ret) { @@ -953,6 +1009,7 @@ int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->lock = &ctx->dev->dev_mutex; dst_vq->dev = &ctx->dev->plat_dev->dev; + dst_vq->allow_cache_hints = 1; ret = vb2_queue_init(dst_vq); if (ret) diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c index 995e6e2fb1ab..e0b6ae9d6caa 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c @@ -208,9 +208,12 @@ static int fops_vcodec_open(struct file *file) dev->dec_capability = mtk_vcodec_fw_get_vdec_capa(dev->fw_handler); + mtk_v4l2_debug(0, "decoder capability %x", dev->dec_capability); } + ctx->dev->vdec_pdata->init_vdec_params(ctx); + list_add(&ctx->list, &dev->ctx_list); mutex_unlock(&dev->dev_mutex); @@ -386,8 +389,14 @@ static int mtk_vcodec_probe(struct platform_device *pdev) mtk_v4l2_err("Main device of_platform_populate failed."); goto err_reg_cont; } + } else { + set_bit(MTK_VDEC_CORE, dev->subdev_bitmap); } + atomic_set(&dev->dec_active_cnt, 0); + memset(dev->vdec_racing_info, 0, sizeof(dev->vdec_racing_info)); + mutex_init(&dev->dec_racing_info_mutex); + ret = video_register_device(vfd_dec, VFL_TYPE_VIDEO, -1); if (ret) { mtk_v4l2_err("Failed to register video device"); @@ -465,6 +474,10 @@ static const struct of_device_id mtk_vcodec_match[] = { .compatible = "mediatek,mt8186-vcodec-dec", .data = &mtk_vdec_single_core_pdata, }, + { + .compatible = "mediatek,mt8195-vcodec-dec", + .data = &mtk_lat_sig_core_pdata, + }, {}, }; diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c index 14bed2bd4283..376db0e433d7 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c @@ -28,6 +28,10 @@ static const struct of_device_id mtk_vdec_hw_match[] = { .compatible = "mediatek,mtk-vcodec-core", .data = (void *)MTK_VDEC_CORE, }, + { + .compatible = "mediatek,mtk-vcodec-lat-soc", + .data = (void *)MTK_VDEC_LAT_SOC, + }, {}, }; MODULE_DEVICE_TABLE(of, mtk_vdec_hw_match); @@ -166,9 +170,11 @@ static int mtk_vdec_hw_probe(struct platform_device *pdev) subdev_dev->reg_base[VDEC_HW_SYS] = main_dev->reg_base[VDEC_HW_SYS]; set_bit(subdev_dev->hw_idx, main_dev->subdev_bitmap); - ret = mtk_vdec_hw_init_irq(subdev_dev); - if (ret) - goto err; + if (IS_SUPPORT_VDEC_HW_IRQ(hw_idx)) { + ret = mtk_vdec_hw_init_irq(subdev_dev); + if (ret) + goto err; + } subdev_dev->reg_base[VDEC_HW_MISC] = devm_platform_ioremap_resource(pdev, 0); diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.h b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.h index a63e4b1b81c3..36faa8d9d681 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.h +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.h @@ -17,6 +17,8 @@ #define VDEC_IRQ_CLR 0x10 #define VDEC_IRQ_CFG_REG 0xa4 +#define IS_SUPPORT_VDEC_HW_IRQ(hw_idx) ((hw_idx) != MTK_VDEC_LAT_SOC) + /** * enum mtk_vdec_hw_reg_idx - subdev hardware register base index * @VDEC_HW_SYS : vdec soc register index diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c index 0fb7e5ba635b..4305e4eb9900 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c @@ -144,6 +144,34 @@ static void mtk_vcodec_dec_disable_irq(struct mtk_vcodec_dev *vdec_dev, int hw_i } } +static void mtk_vcodec_load_racing_info(struct mtk_vcodec_ctx *ctx) +{ + void __iomem *vdec_racing_addr; + int j; + + mutex_lock(&ctx->dev->dec_racing_info_mutex); + if (atomic_inc_return(&ctx->dev->dec_active_cnt) == 1) { + vdec_racing_addr = ctx->dev->reg_base[VDEC_MISC] + 0x100; + for (j = 0; j < 132; j++) + writel(ctx->dev->vdec_racing_info[j], vdec_racing_addr + j * 4); + } + mutex_unlock(&ctx->dev->dec_racing_info_mutex); +} + +static void mtk_vcodec_record_racing_info(struct mtk_vcodec_ctx *ctx) +{ + void __iomem *vdec_racing_addr; + int j; + + mutex_lock(&ctx->dev->dec_racing_info_mutex); + if (atomic_dec_and_test(&ctx->dev->dec_active_cnt)) { + vdec_racing_addr = ctx->dev->reg_base[VDEC_MISC] + 0x100; + for (j = 0; j < 132; j++) + ctx->dev->vdec_racing_info[j] = readl(vdec_racing_addr + j * 4); + } + mutex_unlock(&ctx->dev->dec_racing_info_mutex); +} + static struct mtk_vcodec_pm *mtk_vcodec_dec_get_pm(struct mtk_vcodec_dev *vdec_dev, int hw_idx) { @@ -174,6 +202,14 @@ static void mtk_vcodec_dec_child_dev_on(struct mtk_vcodec_dev *vdec_dev, mtk_vcodec_dec_pw_on(pm); mtk_vcodec_dec_clock_on(pm); } + + if (hw_idx == MTK_VDEC_LAT0) { + pm = mtk_vcodec_dec_get_pm(vdec_dev, MTK_VDEC_LAT_SOC); + if (pm) { + mtk_vcodec_dec_pw_on(pm); + mtk_vcodec_dec_clock_on(pm); + } + } } static void mtk_vcodec_dec_child_dev_off(struct mtk_vcodec_dev *vdec_dev, @@ -186,6 +222,14 @@ static void mtk_vcodec_dec_child_dev_off(struct mtk_vcodec_dev *vdec_dev, mtk_vcodec_dec_clock_off(pm); mtk_vcodec_dec_pw_off(pm); } + + if (hw_idx == MTK_VDEC_LAT0) { + pm = mtk_vcodec_dec_get_pm(vdec_dev, MTK_VDEC_LAT_SOC); + if (pm) { + mtk_vcodec_dec_clock_off(pm); + mtk_vcodec_dec_pw_off(pm); + } + } } void mtk_vcodec_dec_enable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx) @@ -198,11 +242,17 @@ void mtk_vcodec_dec_enable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx) mtk_vcodec_dec_child_dev_on(ctx->dev, hw_idx); mtk_vcodec_dec_enable_irq(ctx->dev, hw_idx); + + if (IS_VDEC_INNER_RACING(ctx->dev->dec_capability)) + mtk_vcodec_load_racing_info(ctx); } EXPORT_SYMBOL_GPL(mtk_vcodec_dec_enable_hardware); void mtk_vcodec_dec_disable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx) { + if (IS_VDEC_INNER_RACING(ctx->dev->dec_capability)) + mtk_vcodec_record_racing_info(ctx); + mtk_vcodec_dec_disable_irq(ctx->dev, hw_idx); mtk_vcodec_dec_child_dev_off(ctx->dev, hw_idx); diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c index 9c7e6145cebb..035c86e7809f 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c @@ -17,18 +17,24 @@ static const struct mtk_video_fmt mtk_video_formats[] = { .type = MTK_FMT_DEC, .num_planes = 1, .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + .frmsize = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, + MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, }, { .fourcc = V4L2_PIX_FMT_VP8, .type = MTK_FMT_DEC, .num_planes = 1, .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + .frmsize = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, + MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, }, { .fourcc = V4L2_PIX_FMT_VP9, .type = MTK_FMT_DEC, .num_planes = 1, .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + .frmsize = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, + MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, }, { .fourcc = V4L2_PIX_FMT_MT21C, @@ -43,27 +49,6 @@ static const unsigned int num_supported_formats = #define DEFAULT_OUT_FMT_IDX 0 #define DEFAULT_CAP_FMT_IDX 3 -static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { - { - .fourcc = V4L2_PIX_FMT_H264, - .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, - MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, - }, - { - .fourcc = V4L2_PIX_FMT_VP8, - .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, - MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, - }, - { - .fourcc = V4L2_PIX_FMT_VP9, - .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, - MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, - }, -}; - -static const unsigned int num_supported_framesize = - ARRAY_SIZE(mtk_vdec_framesizes); - /* * This function tries to clean all display buffers, the buffers will return * in display order. @@ -618,8 +603,6 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = { .num_formats = &num_supported_formats, .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX], .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX], - .vdec_framesizes = mtk_vdec_framesizes, - .num_framesizes = &num_supported_framesize, .worker = mtk_vdec_worker, .flush_decoder = mtk_vdec_flush_decoder, .is_subdev_supported = false, diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c index 16d55785d84b..c45bd2599bb2 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c @@ -112,14 +112,12 @@ static const struct mtk_stateless_control mtk_stateless_controls[] = { #define NUM_CTRLS ARRAY_SIZE(mtk_stateless_controls) static struct mtk_video_fmt mtk_video_formats[5]; -static struct mtk_codec_framesizes mtk_vdec_framesizes[3]; static struct mtk_video_fmt default_out_format; static struct mtk_video_fmt default_cap_format; static unsigned int num_formats; -static unsigned int num_framesizes; -static struct v4l2_frmsize_stepwise stepwise_fhd = { +static const struct v4l2_frmsize_stepwise stepwise_fhd = { .min_width = MTK_VDEC_MIN_W, .max_width = MTK_VDEC_MAX_W, .step_width = 16, @@ -348,7 +346,6 @@ static void mtk_vcodec_add_formats(unsigned int fourcc, struct mtk_vcodec_dev *dev = ctx->dev; const struct mtk_vcodec_dec_pdata *pdata = dev->vdec_pdata; int count_formats = *pdata->num_formats; - int count_framesizes = *pdata->num_framesizes; switch (fourcc) { case V4L2_PIX_FMT_H264_SLICE: @@ -357,10 +354,15 @@ static void mtk_vcodec_add_formats(unsigned int fourcc, mtk_video_formats[count_formats].fourcc = fourcc; mtk_video_formats[count_formats].type = MTK_FMT_DEC; mtk_video_formats[count_formats].num_planes = 1; - - mtk_vdec_framesizes[count_framesizes].fourcc = fourcc; - mtk_vdec_framesizes[count_framesizes].stepwise = stepwise_fhd; - num_framesizes++; + mtk_video_formats[count_formats].frmsize = stepwise_fhd; + + if (!(ctx->dev->dec_capability & VCODEC_CAPABILITY_4K_DISABLED) && + fourcc != V4L2_PIX_FMT_VP8_FRAME) { + mtk_video_formats[count_formats].frmsize.max_width = + VCODEC_DEC_4K_CODED_WIDTH; + mtk_video_formats[count_formats].frmsize.max_height = + VCODEC_DEC_4K_CODED_HEIGHT; + } break; case V4L2_PIX_FMT_MM21: case V4L2_PIX_FMT_MT21C: @@ -374,15 +376,15 @@ static void mtk_vcodec_add_formats(unsigned int fourcc, } num_formats++; - mtk_v4l2_debug(3, "num_formats: %d num_frames:%d dec_capability: 0x%x", - count_formats, count_framesizes, ctx->dev->dec_capability); + mtk_v4l2_debug(3, "num_formats: %d dec_capability: 0x%x", + count_formats, ctx->dev->dec_capability); } static void mtk_vcodec_get_supported_formats(struct mtk_vcodec_ctx *ctx) { int cap_format_count = 0, out_format_count = 0; - if (num_formats && num_framesizes) + if (num_formats) return; if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_MM21) { @@ -461,8 +463,6 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata = { .num_formats = &num_formats, .default_out_fmt = &default_out_format, .default_cap_fmt = &default_cap_format, - .vdec_framesizes = mtk_vdec_framesizes, - .num_framesizes = &num_framesizes, .uses_stateless_api = true, .worker = mtk_vdec_worker, .flush_decoder = mtk_vdec_flush_decoder, @@ -481,8 +481,6 @@ const struct mtk_vcodec_dec_pdata mtk_lat_sig_core_pdata = { .num_formats = &num_formats, .default_out_fmt = &default_out_format, .default_cap_fmt = &default_cap_format, - .vdec_framesizes = mtk_vdec_framesizes, - .num_framesizes = &num_framesizes, .uses_stateless_api = true, .worker = mtk_vdec_worker, .flush_decoder = mtk_vdec_flush_decoder, @@ -500,8 +498,6 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_single_core_pdata = { .num_formats = &num_formats, .default_out_fmt = &default_out_format, .default_cap_fmt = &default_cap_format, - .vdec_framesizes = mtk_vdec_framesizes, - .num_framesizes = &num_framesizes, .uses_stateless_api = true, .worker = mtk_vdec_worker, .flush_decoder = mtk_vdec_flush_decoder, diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h index a29041a0b7e0..ef4584a46417 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h @@ -19,15 +19,14 @@ #include "mtk_vcodec_util.h" #include "vdec_msg_queue.h" -#define MTK_VCODEC_DRV_NAME "mtk_vcodec_drv" #define MTK_VCODEC_DEC_NAME "mtk-vcodec-dec" #define MTK_VCODEC_ENC_NAME "mtk-vcodec-enc" -#define MTK_PLATFORM_STR "platform:mt8173" #define MTK_VCODEC_MAX_PLANES 3 #define MTK_V4L2_BENCHMARK 0 #define WAIT_INTR_TIMEOUT_MS 1000 #define IS_VDEC_LAT_ARCH(hw_arch) ((hw_arch) >= MTK_VDEC_LAT_SINGLE_CORE) +#define IS_VDEC_INNER_RACING(capability) ((capability) & MTK_VCODEC_INNER_RACING) /* * enum mtk_hw_reg_idx - MTK hw register base index @@ -104,6 +103,7 @@ enum mtk_vdec_hw_id { MTK_VDEC_CORE, MTK_VDEC_LAT0, MTK_VDEC_LAT1, + MTK_VDEC_LAT_SOC, MTK_VDEC_HW_MAX, }; @@ -125,15 +125,7 @@ struct mtk_video_fmt { enum mtk_fmt_type type; u32 num_planes; u32 flags; -}; - -/* - * struct mtk_codec_framesizes - Structure used to store information about - * framesizes - */ -struct mtk_codec_framesizes { - u32 fourcc; - struct v4l2_frmsize_stepwise stepwise; + struct v4l2_frmsize_stepwise frmsize; }; /* @@ -255,7 +247,7 @@ struct vdec_pic_info { * @param_change: indicate encode parameter type * @enc_params: encoding parameters * @dec_if: hooked decoder driver interface - * @enc_if: hoooked encoder driver interface + * @enc_if: hooked encoder driver interface * @drv_handle: driver handle for specific decode/encode instance * * @picinfo: store picture info after header parsing @@ -285,8 +277,6 @@ struct vdec_pic_info { * mtk_video_dec_buf. * @hw_id: hardware index used to identify different hardware. * - * @max_width: hardware supported max width - * @max_height: hardware supported max height * @msg_queue: msg queue used to store lat buffer information. */ struct mtk_vcodec_ctx { @@ -333,8 +323,6 @@ struct mtk_vcodec_ctx { struct mutex lock; int hw_id; - unsigned int max_width; - unsigned int max_height; struct vdec_msg_queue msg_queue; }; @@ -356,6 +344,7 @@ enum mtk_vdec_format_types { MTK_VDEC_FORMAT_H264_SLICE = 0x100, MTK_VDEC_FORMAT_VP8_FRAME = 0x200, MTK_VDEC_FORMAT_VP9_FRAME = 0x400, + MTK_VCODEC_INNER_RACING = 0x20000, }; /** @@ -373,9 +362,6 @@ enum mtk_vdec_format_types { * @default_out_fmt: default output buffer format * @default_cap_fmt: default capture buffer format * - * @vdec_framesizes: supported video decoder frame sizes - * @num_framesizes: count of video decoder frame sizes - * * @hw_arch: hardware arch is used to separate pure_sin_core and lat_sin_core * * @is_subdev_supported: whether support parent-node architecture(subdev) @@ -398,9 +384,6 @@ struct mtk_vcodec_dec_pdata { const struct mtk_video_fmt *default_out_fmt; const struct mtk_video_fmt *default_cap_fmt; - const struct mtk_codec_framesizes *vdec_framesizes; - const int *num_framesizes; - enum mtk_vdec_hw_arch hw_arch; bool is_subdev_supported; @@ -477,6 +460,10 @@ struct mtk_vcodec_enc_pdata { * @subdev_dev: subdev hardware device * @subdev_prob_done: check whether all used hw device is prob done * @subdev_bitmap: used to record hardware is ready or not + * + * @dec_active_cnt: used to mark whether need to record register value + * @vdec_racing_info: record register value + * @dec_racing_info_mutex: mutex lock used for inner racing mode */ struct mtk_vcodec_dev { struct v4l2_device v4l2_dev; @@ -522,6 +509,11 @@ struct mtk_vcodec_dev { void *subdev_dev[MTK_VDEC_HW_MAX]; int (*subdev_prob_done)(struct mtk_vcodec_dev *vdec_dev); DECLARE_BITMAP(subdev_bitmap, MTK_VDEC_HW_MAX); + + atomic_t dec_active_cnt; + u32 vdec_racing_info[132]; + /* Protects access to vdec_racing_info data */ + struct mutex dec_racing_info_mutex; }; static inline struct mtk_vcodec_ctx *fh_to_ctx(struct v4l2_fh *fh) diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c index c21367038c34..25e816863597 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c @@ -50,6 +50,14 @@ static int vidioc_venc_s_ctrl(struct v4l2_ctrl *ctrl) int ret = 0; switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_BITRATE_MODE val= %d", + ctrl->val); + if (ctrl->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) { + mtk_v4l2_err("Unsupported bitrate mode =%d", ctrl->val); + ret = -EINVAL; + } + break; case V4L2_CID_MPEG_VIDEO_BITRATE: mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_BITRATE val = %d", ctrl->val); @@ -204,12 +212,32 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, pdata->num_output_formats); } +static int mtk_vcodec_enc_get_chip_name(void *priv) +{ + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + struct device *dev = &ctx->dev->plat_dev->dev; + + if (of_device_is_compatible(dev->of_node, "mediatek,mt8173-vcodec-enc")) + return 8173; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8183-vcodec-enc")) + return 8183; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8192-vcodec-enc")) + return 8192; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8195-vcodec-enc")) + return 8195; + else + return 8173; +} + static int vidioc_venc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strscpy(cap->driver, MTK_VCODEC_ENC_NAME, sizeof(cap->driver)); - strscpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info)); - strscpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card)); + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + struct device *dev = &ctx->dev->plat_dev->dev; + int platform_name = mtk_vcodec_enc_get_chip_name(priv); + + strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); + snprintf(cap->card, sizeof(cap->card), "MT%d video encoder", platform_name); return 0; } @@ -1373,6 +1401,9 @@ int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx) 0, V4L2_MPEG_VIDEO_H264_LEVEL_4_0); v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_VP8_PROFILE, V4L2_MPEG_VIDEO_VP8_PROFILE_0, 0, V4L2_MPEG_VIDEO_VP8_PROFILE_0); + v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + 0, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); if (handler->error) { diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c index ca628321d272..580ce979e2a3 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c @@ -51,7 +51,7 @@ void mtk_vdec_h264_fill_dpb_info(struct mtk_vcodec_ctx *ctx, struct vb2_queue *vq; struct vb2_buffer *vb; struct vb2_v4l2_buffer *vb2_v4l2; - int index, vb2_index; + int index; vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); @@ -62,8 +62,8 @@ void mtk_vdec_h264_fill_dpb_info(struct mtk_vcodec_ctx *ctx, continue; } - vb2_index = vb2_find_timestamp(vq, dpb->reference_ts, 0); - if (vb2_index < 0) { + vb = vb2_find_buffer(vq, dpb->reference_ts); + if (!vb) { dev_err(&ctx->dev->plat_dev->dev, "Reference invalid: dpb_index(%d) reference_ts(%lld)", index, dpb->reference_ts); @@ -76,7 +76,6 @@ void mtk_vdec_h264_fill_dpb_info(struct mtk_vcodec_ctx *ctx, else h264_dpb_info[index].reference_flag = 2; - vb = vq->bufs[vb2_index]; vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); h264_dpb_info[index].field = vb2_v4l2->field; diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c index 784d01f8bd50..4cc92700692b 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c @@ -633,6 +633,17 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs, goto err_scp_decode; } + share_info->trans_end = inst->ctx->msg_queue.wdma_addr.dma_addr + + inst->vsi->wdma_end_addr_offset; + share_info->trans_start = inst->ctx->msg_queue.wdma_wptr_addr; + share_info->nal_info = inst->vsi->dec.nal_info; + + if (IS_VDEC_INNER_RACING(inst->ctx->dev->dec_capability)) { + memcpy(&share_info->h264_slice_params, &inst->vsi->h264_slice_params, + sizeof(share_info->h264_slice_params)); + vdec_msg_queue_qbuf(&inst->ctx->dev->msg_queue_core_ctx, lat_buf); + } + /* wait decoder done interrupt */ timeout = mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED, WAIT_INTR_TIMEOUT_MS, MTK_VDEC_LAT0); @@ -646,18 +657,22 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs, share_info->trans_end = inst->ctx->msg_queue.wdma_addr.dma_addr + inst->vsi->wdma_end_addr_offset; - share_info->trans_start = inst->ctx->msg_queue.wdma_wptr_addr; - share_info->nal_info = inst->vsi->dec.nal_info; vdec_msg_queue_update_ube_wptr(&lat_buf->ctx->msg_queue, share_info->trans_end); - memcpy(&share_info->h264_slice_params, &inst->vsi->h264_slice_params, - sizeof(share_info->h264_slice_params)); - vdec_msg_queue_qbuf(&inst->ctx->dev->msg_queue_core_ctx, lat_buf); + if (!IS_VDEC_INNER_RACING(inst->ctx->dev->dec_capability)) { + memcpy(&share_info->h264_slice_params, &inst->vsi->h264_slice_params, + sizeof(share_info->h264_slice_params)); + vdec_msg_queue_qbuf(&inst->ctx->dev->msg_queue_core_ctx, lat_buf); + } + mtk_vcodec_debug(inst, "dec num: %d lat crc: 0x%x 0x%x 0x%x", inst->slice_dec_num, + inst->vsi->dec.crc[0], inst->vsi->dec.crc[1], inst->vsi->dec.crc[2]); inst->slice_dec_num++; return 0; err_scp_decode: + if (!IS_VDEC_INNER_RACING(inst->ctx->dev->dec_capability)) + vdec_msg_queue_qbuf(&inst->ctx->msg_queue.lat_ctx, lat_buf); err_free_fb_out: vdec_msg_queue_qbuf(&inst->ctx->msg_queue.lat_ctx, lat_buf); mtk_vcodec_err(inst, "slice dec number: %d err: %d", inst->slice_dec_num, err); diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c index eef102f3f4f3..e1fe2603e92e 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c @@ -237,7 +237,7 @@ static int vdec_vp8_slice_get_decode_parameters(struct vdec_vp8_slice_inst *inst struct vb2_queue *vq; struct vb2_buffer *vb; u64 referenct_ts; - int index, vb2_index; + int index; frame_header = vdec_vp8_slice_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_VP8_FRAME); if (IS_ERR(frame_header)) @@ -246,8 +246,8 @@ static int vdec_vp8_slice_get_decode_parameters(struct vdec_vp8_slice_inst *inst vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); for (index = 0; index < 3; index++) { referenct_ts = vdec_vp8_slice_get_ref_by_ts(frame_header, index); - vb2_index = vb2_find_timestamp(vq, referenct_ts, 0); - if (vb2_index < 0) { + vb = vb2_find_buffer(vq, referenct_ts); + if (!vb) { if (!V4L2_VP8_FRAME_IS_KEY_FRAME(frame_header)) mtk_vcodec_err(inst, "reference invalid: index(%d) ts(%lld)", index, referenct_ts); @@ -256,7 +256,6 @@ static int vdec_vp8_slice_get_decode_parameters(struct vdec_vp8_slice_inst *inst } inst->vsi->vp8_dpb_info[index].reference_flag = 1; - vb = vq->bufs[vb2_index]; inst->vsi->vp8_dpb_info[index].y_dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c index 023aba4ec2c4..fb1c36a3592d 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c @@ -439,6 +439,8 @@ struct vdec_vp9_slice_ref { * @init_vsi: vsi used for initialized VP9 instance * @vsi: vsi used for decoding/flush ... * @core_vsi: vsi used for Core stage + * + * @sc_pfc: per frame context single core * @counts_map: used map to counts_helper * @counts_helper: counts table according to newest kernel spec */ @@ -487,6 +489,7 @@ struct vdec_vp9_slice_instance { }; struct vdec_vp9_slice_vsi *core_vsi; + struct vdec_vp9_slice_pfc sc_pfc; struct vdec_vp9_slice_counts_map counts_map; struct v4l2_vp9_frame_symbol_counts counts_helper; }; @@ -523,13 +526,12 @@ static int vdec_vp9_slice_init_default_frame_ctx(struct vdec_vp9_slice_instance if (vdec_vp9_slice_default_frame_ctx) goto out; - frame_ctx = kmalloc(sizeof(*frame_ctx), GFP_KERNEL); + frame_ctx = kmemdup(remote_frame_ctx, sizeof(*frame_ctx), GFP_KERNEL); if (!frame_ctx) { ret = -ENOMEM; goto out; } - memcpy(frame_ctx, remote_frame_ctx, sizeof(*frame_ctx)); vdec_vp9_slice_default_frame_ctx = frame_ctx; out: @@ -689,7 +691,26 @@ static int vdec_vp9_slice_tile_offset(int idx, int mi_num, int tile_log2) int sbs = (mi_num + 7) >> 3; int offset = ((idx * sbs) >> tile_log2) << 3; - return offset < mi_num ? offset : mi_num; + return min(offset, mi_num); +} + +static +int vdec_vp9_slice_setup_single_from_src_to_dst(struct vdec_vp9_slice_instance *instance) +{ + struct vb2_v4l2_buffer *src; + struct vb2_v4l2_buffer *dst; + + src = v4l2_m2m_next_src_buf(instance->ctx->m2m_ctx); + if (!src) + return -EINVAL; + + dst = v4l2_m2m_next_dst_buf(instance->ctx->m2m_ctx); + if (!dst) + return -EINVAL; + + v4l2_m2m_buf_copy_metadata(src, dst, true); + + return 0; } static int vdec_vp9_slice_setup_lat_from_src_buf(struct vdec_vp9_slice_instance *instance, @@ -1567,6 +1588,33 @@ static int vdec_vp9_slice_update_prob(struct vdec_vp9_slice_instance *instance, return 0; } +static int vdec_vp9_slice_update_single(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_pfc *pfc) +{ + struct vdec_vp9_slice_vsi *vsi; + + vsi = &pfc->vsi; + memcpy(&pfc->state[0], &vsi->state, sizeof(vsi->state)); + + mtk_vcodec_debug(instance, "Frame %u Y_CRC %08x %08x %08x %08x\n", + pfc->seq, + vsi->state.crc[0], vsi->state.crc[1], + vsi->state.crc[2], vsi->state.crc[3]); + mtk_vcodec_debug(instance, "Frame %u C_CRC %08x %08x %08x %08x\n", + pfc->seq, + vsi->state.crc[4], vsi->state.crc[5], + vsi->state.crc[6], vsi->state.crc[7]); + + vdec_vp9_slice_update_prob(instance, vsi); + + instance->width = vsi->frame.uh.frame_width; + instance->height = vsi->frame.uh.frame_height; + instance->frame_type = vsi->frame.uh.frame_type; + instance->show_frame = vsi->frame.uh.show_frame; + + return 0; +} + static int vdec_vp9_slice_update_lat(struct vdec_vp9_slice_instance *instance, struct vdec_lat_buf *lat_buf, struct vdec_vp9_slice_pfc *pfc) @@ -1624,7 +1672,6 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst struct vdec_vp9_slice_reference *ref; int plane; int size; - int idx; int w; int h; int i; @@ -1667,15 +1714,16 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst */ for (i = 0; i < 3; i++) { ref = &vsi->frame.ref[i]; - idx = vb2_find_timestamp(vq, pfc->ref_idx[i], 0); - if (idx < 0) { + vb = vb2_find_buffer(vq, pfc->ref_idx[i]); + if (!vb) { ref->frame_width = w; ref->frame_height = h; memset(&vsi->ref[i], 0, sizeof(vsi->ref[i])); } else { + int idx = vb->index; + ref->frame_width = instance->dpb[idx].width; ref->frame_height = instance->dpb[idx].height; - vb = vq->bufs[idx]; vsi->ref[i].y.dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); if (plane == 1) @@ -1690,6 +1738,40 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst return 0; } +static void vdec_vp9_slice_setup_single_buffer(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_pfc *pfc, + struct vdec_vp9_slice_vsi *vsi, + struct mtk_vcodec_mem *bs, + struct vdec_fb *fb) +{ + int i; + + vsi->bs.buf.dma_addr = bs->dma_addr; + vsi->bs.buf.size = bs->size; + vsi->bs.frame.dma_addr = bs->dma_addr; + vsi->bs.frame.size = bs->size; + + for (i = 0; i < 2; i++) { + vsi->mv[i].dma_addr = instance->mv[i].dma_addr; + vsi->mv[i].size = instance->mv[i].size; + } + for (i = 0; i < 2; i++) { + vsi->seg[i].dma_addr = instance->seg[i].dma_addr; + vsi->seg[i].size = instance->seg[i].size; + } + vsi->tile.dma_addr = instance->tile.dma_addr; + vsi->tile.size = instance->tile.size; + vsi->prob.dma_addr = instance->prob.dma_addr; + vsi->prob.size = instance->prob.size; + vsi->counts.dma_addr = instance->counts.dma_addr; + vsi->counts.size = instance->counts.size; + + vsi->row_info.buf = 0; + vsi->row_info.size = 0; + + vdec_vp9_slice_setup_core_buffer(instance, pfc, vsi, fb, NULL); +} + static int vdec_vp9_slice_setup_core(struct vdec_vp9_slice_instance *instance, struct vdec_fb *fb, struct vdec_lat_buf *lat_buf, @@ -1716,6 +1798,43 @@ err: return ret; } +static int vdec_vp9_slice_setup_single(struct vdec_vp9_slice_instance *instance, + struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, + struct vdec_vp9_slice_pfc *pfc) +{ + struct vdec_vp9_slice_vsi *vsi = &pfc->vsi; + int ret; + + ret = vdec_vp9_slice_setup_single_from_src_to_dst(instance); + if (ret) + goto err; + + ret = vdec_vp9_slice_setup_pfc(instance, pfc); + if (ret) + goto err; + + ret = vdec_vp9_slice_alloc_working_buffer(instance, vsi); + if (ret) + goto err; + + vdec_vp9_slice_setup_single_buffer(instance, pfc, vsi, bs, fb); + vdec_vp9_slice_setup_seg_buffer(instance, vsi, &instance->seg[0]); + + ret = vdec_vp9_slice_setup_prob_buffer(instance, vsi); + if (ret) + goto err; + + ret = vdec_vp9_slice_setup_tile_buffer(instance, vsi, bs); + if (ret) + goto err; + + return 0; + +err: + return ret; +} + static int vdec_vp9_slice_update_core(struct vdec_vp9_slice_instance *instance, struct vdec_lat_buf *lat_buf, struct vdec_vp9_slice_pfc *pfc) @@ -1813,8 +1932,8 @@ static int vdec_vp9_slice_flush(void *h_vdec, struct mtk_vcodec_mem *bs, struct vdec_vp9_slice_instance *instance = h_vdec; mtk_vcodec_debug(instance, "flush ...\n"); - - vdec_msg_queue_wait_lat_buf_full(&instance->ctx->msg_queue); + if (instance->ctx->dev->vdec_pdata->hw_arch != MTK_VDEC_PURE_SINGLE_CORE) + vdec_msg_queue_wait_lat_buf_full(&instance->ctx->msg_queue); return vpu_dec_reset(&instance->vpu); } @@ -1867,6 +1986,63 @@ static int vdec_vp9_slice_get_param(void *h_vdec, enum vdec_get_param_type type, return 0; } +static int vdec_vp9_slice_single_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + struct vdec_vp9_slice_instance *instance = h_vdec; + struct vdec_vp9_slice_pfc *pfc = &instance->sc_pfc; + struct vdec_vp9_slice_vsi *vsi; + struct mtk_vcodec_ctx *ctx; + int ret; + + if (!instance || !instance->ctx) + return -EINVAL; + ctx = instance->ctx; + + /* bs NULL means flush decoder */ + if (!bs) + return vdec_vp9_slice_flush(h_vdec, bs, fb, res_chg); + + fb = ctx->dev->vdec_pdata->get_cap_buffer(ctx); + if (!fb) + return -EBUSY; + + vsi = &pfc->vsi; + + ret = vdec_vp9_slice_setup_single(instance, bs, fb, pfc); + if (ret) { + mtk_vcodec_err(instance, "Failed to setup VP9 single ret %d\n", ret); + return ret; + } + vdec_vp9_slice_vsi_to_remote(vsi, instance->vsi); + + ret = vpu_dec_start(&instance->vpu, NULL, 0); + if (ret) { + mtk_vcodec_err(instance, "Failed to dec VP9 ret %d\n", ret); + return ret; + } + + ret = mtk_vcodec_wait_for_done_ctx(ctx, MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS, MTK_VDEC_CORE); + /* update remote vsi if decode timeout */ + if (ret) { + mtk_vcodec_err(instance, "VP9 decode timeout %d\n", ret); + WRITE_ONCE(instance->vsi->state.timeout, 1); + } + + vpu_dec_end(&instance->vpu); + + vdec_vp9_slice_vsi_from_remote(vsi, instance->vsi, 0); + ret = vdec_vp9_slice_update_single(instance, pfc); + if (ret) { + mtk_vcodec_err(instance, "VP9 decode error: %d\n", ret); + return ret; + } + + instance->ctx->decoded_frame_cnt++; + return 0; +} + static int vdec_vp9_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs, struct vdec_fb *fb, bool *res_chg) { @@ -1946,6 +2122,20 @@ static int vdec_vp9_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs, return 0; } +static int vdec_vp9_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + struct vdec_vp9_slice_instance *instance = h_vdec; + int ret; + + if (instance->ctx->dev->vdec_pdata->hw_arch == MTK_VDEC_PURE_SINGLE_CORE) + ret = vdec_vp9_slice_single_decode(h_vdec, bs, fb, res_chg); + else + ret = vdec_vp9_slice_lat_decode(h_vdec, bs, fb, res_chg); + + return ret; +} + static int vdec_vp9_slice_core_decode(struct vdec_lat_buf *lat_buf) { struct vdec_vp9_slice_instance *instance; @@ -2024,7 +2214,7 @@ err: const struct vdec_common_if vdec_vp9_slice_lat_if = { .init = vdec_vp9_slice_init, - .decode = vdec_vp9_slice_lat_decode, + .decode = vdec_vp9_slice_decode, .get_param = vdec_vp9_slice_get_param, .deinit = vdec_vp9_slice_deinit, }; diff --git a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c index 27b4b35039cf..f3807f03d880 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c @@ -47,7 +47,7 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) break; case V4L2_PIX_FMT_VP9_FRAME: ctx->dec_if = &vdec_vp9_slice_lat_if; - ctx->hw_id = MTK_VDEC_LAT0; + ctx->hw_id = IS_VDEC_LAT_ARCH(hw_arch) ? MTK_VDEC_LAT0 : MTK_VDEC_CORE; break; default: return -EINVAL; diff --git a/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c b/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c index 35f4d5583084..df309e8e9379 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c +++ b/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c @@ -91,6 +91,11 @@ static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv) struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *) (unsigned long)msg->ap_inst_addr; + if (!vpu) { + mtk_v4l2_err("ap_inst_addr is NULL, did the SCP hang or crash?"); + return; + } + mtk_vcodec_debug(vpu, "+ id=%X", msg->msg_id); vpu->failure = msg->status; diff --git a/drivers/media/platform/nvidia/tegra-vde/h264.c b/drivers/media/platform/nvidia/tegra-vde/h264.c index 88f81a134ba0..204e474d57f7 100644 --- a/drivers/media/platform/nvidia/tegra-vde/h264.c +++ b/drivers/media/platform/nvidia/tegra-vde/h264.c @@ -659,20 +659,19 @@ static struct vb2_buffer *get_ref_buf(struct tegra_ctx *ctx, { const struct v4l2_h264_dpb_entry *dpb = ctx->h264.decode_params->dpb; struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; - int buf_idx = -1; + struct vb2_buffer *vb = NULL; if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) - buf_idx = vb2_find_timestamp(cap_q, - dpb[dpb_idx].reference_ts, 0); + vb = vb2_find_buffer(cap_q, dpb[dpb_idx].reference_ts); /* * If a DPB entry is unused or invalid, address of current destination * buffer is returned. */ - if (buf_idx < 0) + if (!vb) return &dst->vb2_buf; - return vb2_get_buffer(cap_q, buf_idx); + return vb; } static int tegra_vde_validate_vb_size(struct tegra_ctx *ctx, diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c index 29c604b1b179..9418fcf740a8 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c @@ -79,6 +79,11 @@ void mxc_jpeg_enable_irq(void __iomem *reg, int slot) writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN)); } +void mxc_jpeg_disable_irq(void __iomem *reg, int slot) +{ + writel(0x0, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN)); +} + void mxc_jpeg_sw_reset(void __iomem *reg) { /* @@ -100,9 +105,6 @@ void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg) /* all markers and segments */ writel(0x3ff, reg + CAST_CFG_MODE); - - /* quality factor */ - writel(0x4b, reg + CAST_QUALITY); } void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg) @@ -114,6 +116,14 @@ void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg) writel(0x140, reg + CAST_MODE); } +void mxc_jpeg_enc_set_quality(struct device *dev, void __iomem *reg, u8 quality) +{ + dev_dbg(dev, "CAST Encoder Quality %d...\n", quality); + + /* quality factor */ + writel(quality, reg + CAST_QUALITY); +} + void mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg) { dev_dbg(dev, "CAST Decoder GO...\n"); diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h index d838e875616c..ecf3b6562ba2 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h @@ -53,10 +53,10 @@ #define CAST_REC_REGS_SEL CAST_STATUS4 #define CAST_LUMTH CAST_STATUS5 #define CAST_CHRTH CAST_STATUS6 -#define CAST_NOMFRSIZE_LO CAST_STATUS7 -#define CAST_NOMFRSIZE_HI CAST_STATUS8 -#define CAST_OFBSIZE_LO CAST_STATUS9 -#define CAST_OFBSIZE_HI CAST_STATUS10 +#define CAST_NOMFRSIZE_LO CAST_STATUS16 +#define CAST_NOMFRSIZE_HI CAST_STATUS17 +#define CAST_OFBSIZE_LO CAST_STATUS18 +#define CAST_OFBSIZE_HI CAST_STATUS19 #define MXC_MAX_SLOTS 1 /* TODO use all 4 slots*/ /* JPEG-Decoder Wrapper Slot Registers 0..3 */ @@ -119,12 +119,14 @@ int mxc_jpeg_enable(void __iomem *reg); void wait_frmdone(struct device *dev, void __iomem *reg); void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg); void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg); +void mxc_jpeg_enc_set_quality(struct device *dev, void __iomem *reg, u8 quality); void mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg); int mxc_jpeg_get_slot(void __iomem *reg); u32 mxc_jpeg_get_offset(void __iomem *reg, int slot); void mxc_jpeg_enable_slot(void __iomem *reg, int slot); void mxc_jpeg_set_l_endian(void __iomem *reg, int le); void mxc_jpeg_enable_irq(void __iomem *reg, int slot); +void mxc_jpeg_disable_irq(void __iomem *reg, int slot); int mxc_jpeg_set_input(void __iomem *reg, u32 in_buf, u32 bufsize); int mxc_jpeg_set_output(void __iomem *reg, u16 out_pitch, u32 out_buf, u16 w, u16 h); diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index f36b512bae51..32fd04a3d8bb 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -389,7 +389,6 @@ static int enum_fmt(const struct mxc_jpeg_fmt *mxc_formats, int n, if (i >= n) return -EINVAL; - strscpy(f->description, mxc_formats[i].name, sizeof(f->description)); f->pixelformat = mxc_formats[i].fourcc; return 0; @@ -520,6 +519,7 @@ static bool mxc_jpeg_alloc_slot_data(struct mxc_jpeg_dev *jpeg, GFP_ATOMIC); if (!cfg_stm) goto err; + memset(cfg_stm, 0, MXC_JPEG_MAX_CFG_STREAM); jpeg->slot_data[slot].cfg_stream_vaddr = cfg_stm; skip_alloc: @@ -558,6 +558,18 @@ static void mxc_jpeg_free_slot_data(struct mxc_jpeg_dev *jpeg, jpeg->slot_data[slot].used = false; } +static void mxc_jpeg_check_and_set_last_buffer(struct mxc_jpeg_ctx *ctx, + struct vb2_v4l2_buffer *src_buf, + struct vb2_v4l2_buffer *dst_buf) +{ + if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) { + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx); + notify_eos(ctx); + ctx->header_parsed = false; + } +} + static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) { struct mxc_jpeg_dev *jpeg = priv; @@ -580,15 +592,8 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) dev_dbg(dev, "Irq %d on slot %d.\n", irq, slot); ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); - if (!ctx) { - dev_err(dev, - "Instance released before the end of transaction.\n"); - /* soft reset only resets internal state, not registers */ - mxc_jpeg_sw_reset(reg); - /* clear all interrupts */ - writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS)); + if (WARN_ON(!ctx)) goto job_unlock; - } if (slot != ctx->slot) { /* TODO investigate when adding multi-instance support */ @@ -624,6 +629,7 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) ctx->enc_state == MXC_JPEG_ENC_CONF) { ctx->enc_state = MXC_JPEG_ENCODING; dev_dbg(dev, "Encoder config finished. Start encoding...\n"); + mxc_jpeg_enc_set_quality(dev, reg, ctx->jpeg_quality); mxc_jpeg_enc_mode_go(dev, reg); goto job_unlock; } @@ -632,6 +638,7 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) dev_dbg(dev, "Decoder DHT cfg finished. Start decoding...\n"); goto job_unlock; } + if (jpeg->mode == MXC_JPEG_ENCODE) { payload = readl(reg + MXC_SLOT_OFFSET(slot, SLOT_BUF_PTR)); vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload); @@ -659,7 +666,9 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) buf_state = VB2_BUF_STATE_DONE; buffers_done: + mxc_jpeg_disable_irq(reg, ctx->slot); jpeg->slot_data[slot].used = false; /* unused, but don't free */ + mxc_jpeg_check_and_set_last_buffer(ctx, src_buf, dst_buf); v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); v4l2_m2m_buf_done(src_buf, buf_state); @@ -755,7 +764,13 @@ static unsigned int mxc_jpeg_setup_cfg_stream(void *cfg_stream_vaddr, u32 fourcc, u16 w, u16 h) { - unsigned int offset = 0; + /* + * There is a hardware issue that first 128 bytes of configuration data + * can't be loaded correctly. + * To avoid this issue, we need to write the configuration from + * an offset which should be no less than 0x80 (128 bytes). + */ + unsigned int offset = 0x80; u8 *cfg = (u8 *)cfg_stream_vaddr; struct mxc_jpeg_sof *sof; struct mxc_jpeg_sos *sos; @@ -887,8 +902,8 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf, jpeg->slot_data[slot].cfg_stream_size = mxc_jpeg_setup_cfg_stream(cfg_stream_vaddr, q_data->fmt->fourcc, - q_data->w_adjusted, - q_data->h_adjusted); + q_data->w, + q_data->h); /* chain the config descriptor with the encoding descriptor */ cfg_desc->next_descpt_ptr = desc_handle | MXC_NXT_DESCPT_EN; @@ -970,7 +985,7 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx, &q_data_cap->h_adjusted, q_data_cap->h_adjusted, /* adjust up */ MXC_JPEG_MAX_HEIGHT, - q_data_cap->fmt->v_align, + 0, 0); /* setup bytesperline/sizeimage for capture queue */ @@ -1027,6 +1042,7 @@ static void mxc_jpeg_device_run(void *priv) jpeg_src_buf->jpeg_parse_error = true; } if (jpeg_src_buf->jpeg_parse_error) { + mxc_jpeg_check_and_set_last_buffer(ctx, src_buf, dst_buf); v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); @@ -1077,45 +1093,33 @@ end: spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags); } -static void mxc_jpeg_set_last_buffer_dequeued(struct mxc_jpeg_ctx *ctx) -{ - struct vb2_queue *q; - - ctx->stopped = 1; - q = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx); - if (!list_empty(&q->done_list)) - return; - - q->last_buffer_dequeued = true; - wake_up(&q->done_wq); - ctx->stopped = 0; - ctx->header_parsed = false; -} - static int mxc_jpeg_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { struct v4l2_fh *fh = file->private_data; struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); - struct device *dev = ctx->mxc_jpeg->dev; int ret; ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, cmd); if (ret < 0) return ret; - if (cmd->cmd == V4L2_DEC_CMD_STOP) { - dev_dbg(dev, "Received V4L2_DEC_CMD_STOP"); - if (v4l2_m2m_num_src_bufs_ready(fh->m2m_ctx) == 0) { - /* No more src bufs, notify app EOS */ - notify_eos(ctx); - mxc_jpeg_set_last_buffer_dequeued(ctx); - } else { - /* will send EOS later*/ - ctx->stopping = 1; - } + if (!vb2_is_streaming(v4l2_m2m_get_src_vq(fh->m2m_ctx))) + return 0; + + ret = v4l2_m2m_ioctl_decoder_cmd(file, priv, cmd); + if (ret < 0) + return ret; + + if (cmd->cmd == V4L2_DEC_CMD_STOP && + v4l2_m2m_has_stopped(fh->m2m_ctx)) { + notify_eos(ctx); + ctx->header_parsed = false; } + if (cmd->cmd == V4L2_DEC_CMD_START && + v4l2_m2m_has_stopped(fh->m2m_ctx)) + vb2_clear_last_buffer_dequeued(&fh->m2m_ctx->cap_q_ctx.q); return 0; } @@ -1124,24 +1128,27 @@ static int mxc_jpeg_encoder_cmd(struct file *file, void *priv, { struct v4l2_fh *fh = file->private_data; struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); - struct device *dev = ctx->mxc_jpeg->dev; int ret; ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, cmd); if (ret < 0) return ret; - if (cmd->cmd == V4L2_ENC_CMD_STOP) { - dev_dbg(dev, "Received V4L2_ENC_CMD_STOP"); - if (v4l2_m2m_num_src_bufs_ready(fh->m2m_ctx) == 0) { - /* No more src bufs, notify app EOS */ - notify_eos(ctx); - mxc_jpeg_set_last_buffer_dequeued(ctx); - } else { - /* will send EOS later*/ - ctx->stopping = 1; - } - } + if (!vb2_is_streaming(v4l2_m2m_get_src_vq(fh->m2m_ctx)) || + !vb2_is_streaming(v4l2_m2m_get_dst_vq(fh->m2m_ctx))) + return 0; + + ret = v4l2_m2m_ioctl_encoder_cmd(file, fh, cmd); + if (ret < 0) + return 0; + + if (cmd->cmd == V4L2_ENC_CMD_STOP && + v4l2_m2m_has_stopped(fh->m2m_ctx)) + notify_eos(ctx); + + if (cmd->cmd == V4L2_ENC_CMD_START && + v4l2_m2m_has_stopped(fh->m2m_ctx)) + vb2_clear_last_buffer_dequeued(&fh->m2m_ctx->cap_q_ctx.q); return 0; } @@ -1154,18 +1161,30 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q, { struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q); struct mxc_jpeg_q_data *q_data = NULL; + struct mxc_jpeg_q_data tmp_q; int i; q_data = mxc_jpeg_get_q_data(ctx, q->type); if (!q_data) return -EINVAL; + tmp_q.fmt = q_data->fmt; + tmp_q.w = q_data->w_adjusted; + tmp_q.h = q_data->h_adjusted; + for (i = 0; i < MXC_JPEG_MAX_PLANES; i++) { + tmp_q.bytesperline[i] = q_data->bytesperline[i]; + tmp_q.sizeimage[i] = q_data->sizeimage[i]; + } + mxc_jpeg_sizeimage(&tmp_q); + for (i = 0; i < MXC_JPEG_MAX_PLANES; i++) + tmp_q.sizeimage[i] = max(tmp_q.sizeimage[i], q_data->sizeimage[i]); + /* Handle CREATE_BUFS situation - *nplanes != 0 */ if (*nplanes) { if (*nplanes != q_data->fmt->colplanes) return -EINVAL; for (i = 0; i < *nplanes; i++) { - if (sizes[i] < q_data->sizeimage[i]) + if (sizes[i] < tmp_q.sizeimage[i]) return -EINVAL; } return 0; @@ -1174,7 +1193,7 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q, /* Handle REQBUFS situation */ *nplanes = q_data->fmt->colplanes; for (i = 0; i < *nplanes; i++) - sizes[i] = q_data->sizeimage[i]; + sizes[i] = tmp_q.sizeimage[i]; return 0; } @@ -1185,6 +1204,8 @@ static int mxc_jpeg_start_streaming(struct vb2_queue *q, unsigned int count) struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, q->type); int ret; + v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q); + if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE && V4L2_TYPE_IS_CAPTURE(q->type)) ctx->source_change = 0; dev_dbg(ctx->mxc_jpeg->dev, "Start streaming ctx=%p", ctx); @@ -1216,11 +1237,15 @@ static void mxc_jpeg_stop_streaming(struct vb2_queue *q) break; v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); } - pm_runtime_put_sync(&ctx->mxc_jpeg->pdev->dev); - if (V4L2_TYPE_IS_OUTPUT(q->type)) { - ctx->stopping = 0; - ctx->stopped = 0; + + v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q); + if (V4L2_TYPE_IS_OUTPUT(q->type) && + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) { + notify_eos(ctx); + ctx->header_parsed = false; } + + pm_runtime_put_sync(&ctx->mxc_jpeg->pdev->dev); } static int mxc_jpeg_valid_comp_id(struct device *dev, @@ -1374,11 +1399,6 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb) } q_data_out->w = header.frame.width; q_data_out->h = header.frame.height; - if (header.frame.width % 8 != 0 || header.frame.height % 8 != 0) { - dev_err(dev, "JPEG width or height not multiple of 8: %dx%d\n", - header.frame.width, header.frame.height); - return -EINVAL; - } if (header.frame.width > MXC_JPEG_MAX_WIDTH || header.frame.height > MXC_JPEG_MAX_HEIGHT) { dev_err(dev, "JPEG width or height should be <= 8192: %dx%d\n", @@ -1424,6 +1444,20 @@ static void mxc_jpeg_buf_queue(struct vb2_buffer *vb) struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct mxc_jpeg_src_buf *jpeg_src_buf; + if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) && + vb2_is_streaming(vb->vb2_queue) && + v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) { + struct mxc_jpeg_q_data *q_data; + + q_data = mxc_jpeg_get_q_data(ctx, vb->vb2_queue->type); + vbuf->field = V4L2_FIELD_NONE; + vbuf->sequence = q_data->sequence++; + v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf); + notify_eos(ctx); + ctx->header_parsed = false; + return; + } + if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) goto end; @@ -1472,24 +1506,11 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb) return -EINVAL; } } - return 0; -} - -static void mxc_jpeg_buf_finish(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct vb2_queue *q = vb->vb2_queue; - - if (V4L2_TYPE_IS_OUTPUT(vb->type)) - return; - if (!ctx->stopped) - return; - if (list_empty(&q->done_list)) { - vbuf->flags |= V4L2_BUF_FLAG_LAST; - ctx->stopped = 0; - ctx->header_parsed = false; + if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) { + vb2_set_plane_payload(vb, 0, 0); + vb2_set_plane_payload(vb, 1, 0); } + return 0; } static const struct vb2_ops mxc_jpeg_qops = { @@ -1498,7 +1519,6 @@ static const struct vb2_ops mxc_jpeg_qops = { .wait_finish = vb2_ops_wait_finish, .buf_out_validate = mxc_jpeg_buf_out_validate, .buf_prepare = mxc_jpeg_buf_prepare, - .buf_finish = mxc_jpeg_buf_finish, .start_streaming = mxc_jpeg_start_streaming, .stop_streaming = mxc_jpeg_stop_streaming, .buf_queue = mxc_jpeg_buf_queue, @@ -1563,6 +1583,56 @@ static void mxc_jpeg_set_default_params(struct mxc_jpeg_ctx *ctx) } } +static int mxc_jpeg_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mxc_jpeg_ctx *ctx = + container_of(ctrl->handler, struct mxc_jpeg_ctx, ctrl_handler); + + switch (ctrl->id) { + case V4L2_CID_JPEG_COMPRESSION_QUALITY: + ctx->jpeg_quality = ctrl->val; + break; + default: + dev_err(ctx->mxc_jpeg->dev, "Invalid control, id = %d, val = %d\n", + ctrl->id, ctrl->val); + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops mxc_jpeg_ctrl_ops = { + .s_ctrl = mxc_jpeg_s_ctrl, +}; + +static void mxc_jpeg_encode_ctrls(struct mxc_jpeg_ctx *ctx) +{ + v4l2_ctrl_new_std(&ctx->ctrl_handler, &mxc_jpeg_ctrl_ops, + V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 75); +} + +static int mxc_jpeg_ctrls_setup(struct mxc_jpeg_ctx *ctx) +{ + int err; + + v4l2_ctrl_handler_init(&ctx->ctrl_handler, 2); + + if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE) + mxc_jpeg_encode_ctrls(ctx); + + if (ctx->ctrl_handler.error) { + err = ctx->ctrl_handler.error; + + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + return err; + } + + err = v4l2_ctrl_handler_setup(&ctx->ctrl_handler); + if (err) + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + return err; +} + static int mxc_jpeg_open(struct file *file) { struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file); @@ -1594,6 +1664,12 @@ static int mxc_jpeg_open(struct file *file) goto error; } + ret = mxc_jpeg_ctrls_setup(ctx); + if (ret) { + dev_err(ctx->mxc_jpeg->dev, "failed to setup mxc jpeg controls\n"); + goto err_ctrls_setup; + } + ctx->fh.ctrl_handler = &ctx->ctrl_handler; mxc_jpeg_set_default_params(ctx); ctx->slot = MXC_MAX_SLOTS; /* slot not allocated yet */ @@ -1605,6 +1681,8 @@ static int mxc_jpeg_open(struct file *file) return 0; +err_ctrls_setup: + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); error: v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); @@ -1646,7 +1724,6 @@ static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index) return -EINVAL; f->pixelformat = q_data->fmt->fourcc; - strscpy(f->description, q_data->fmt->name, sizeof(f->description)); return 0; } } @@ -1684,22 +1761,17 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f, const struct mxc_jpeg_fmt *fm pix_mp->num_planes = fmt->colplanes; pix_mp->pixelformat = fmt->fourcc; - /* - * use MXC_JPEG_H_ALIGN instead of fmt->v_align, for vertical - * alignment, to loosen up the alignment to multiple of 8, - * otherwise NV12-1080p fails as 1080 is not a multiple of 16 - */ + pix_mp->width = w; + pix_mp->height = h; v4l_bound_align_image(&w, - MXC_JPEG_MIN_WIDTH, - w, /* adjust downwards*/ + w, /* adjust upwards*/ + MXC_JPEG_MAX_WIDTH, fmt->h_align, &h, - MXC_JPEG_MIN_HEIGHT, - h, /* adjust downwards*/ - MXC_JPEG_H_ALIGN, + h, /* adjust upwards*/ + MXC_JPEG_MAX_HEIGHT, + 0, 0); - pix_mp->width = w; /* negotiate the width */ - pix_mp->height = h; /* negotiate the height */ /* get user input into the tmp_q */ tmp_q.w = w; @@ -1825,35 +1897,19 @@ static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx, q_data->w_adjusted = q_data->w; q_data->h_adjusted = q_data->h; - if (jpeg->mode == MXC_JPEG_DECODE) { - /* - * align up the resolution for CAST IP, - * but leave the buffer resolution unchanged - */ - v4l_bound_align_image(&q_data->w_adjusted, - q_data->w_adjusted, /* adjust upwards */ - MXC_JPEG_MAX_WIDTH, - q_data->fmt->h_align, - &q_data->h_adjusted, - q_data->h_adjusted, /* adjust upwards */ - MXC_JPEG_MAX_HEIGHT, - q_data->fmt->v_align, - 0); - } else { - /* - * align down the resolution for CAST IP, - * but leave the buffer resolution unchanged - */ - v4l_bound_align_image(&q_data->w_adjusted, - MXC_JPEG_MIN_WIDTH, - q_data->w_adjusted, /* adjust downwards*/ - q_data->fmt->h_align, - &q_data->h_adjusted, - MXC_JPEG_MIN_HEIGHT, - q_data->h_adjusted, /* adjust downwards*/ - q_data->fmt->v_align, - 0); - } + /* + * align up the resolution for CAST IP, + * but leave the buffer resolution unchanged + */ + v4l_bound_align_image(&q_data->w_adjusted, + q_data->w_adjusted, /* adjust upwards */ + MXC_JPEG_MAX_WIDTH, + q_data->fmt->h_align, + &q_data->h_adjusted, + q_data->h_adjusted, /* adjust upwards */ + MXC_JPEG_MAX_HEIGHT, + q_data->fmt->v_align, + 0); for (i = 0; i < pix_mp->num_planes; i++) { q_data->bytesperline[i] = pix_mp->plane_fmt[i].bytesperline; @@ -1958,32 +2014,13 @@ static int mxc_jpeg_subscribe_event(struct v4l2_fh *fh, return v4l2_event_subscribe(fh, sub, 0, NULL); case V4L2_EVENT_SOURCE_CHANGE: return v4l2_src_change_event_subscribe(fh, sub); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subscribe_event(fh, sub); default: return -EINVAL; } } -static int mxc_jpeg_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct v4l2_fh *fh = file->private_data; - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); - struct device *dev = ctx->mxc_jpeg->dev; - int num_src_ready = v4l2_m2m_num_src_bufs_ready(fh->m2m_ctx); - int ret; - - dev_dbg(dev, "DQBUF type=%d, index=%d", buf->type, buf->index); - if (ctx->stopping == 1 && num_src_ready == 0) { - /* No more src bufs, notify app EOS */ - notify_eos(ctx); - ctx->stopping = 0; - mxc_jpeg_set_last_buffer_dequeued(ctx); - } - - ret = v4l2_m2m_dqbuf(file, fh->m2m_ctx, buf); - return ret; -} - static const struct v4l2_ioctl_ops mxc_jpeg_ioctl_ops = { .vidioc_querycap = mxc_jpeg_querycap, .vidioc_enum_fmt_vid_cap = mxc_jpeg_enum_fmt_vid_cap, @@ -2007,7 +2044,7 @@ static const struct v4l2_ioctl_ops mxc_jpeg_ioctl_ops = { .vidioc_encoder_cmd = mxc_jpeg_encoder_cmd, .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, - .vidioc_dqbuf = mxc_jpeg_dqbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, @@ -2031,6 +2068,7 @@ static int mxc_jpeg_release(struct file *file) else dev_dbg(dev, "Release JPEG encoder instance on slot %d.", ctx->slot); + v4l2_ctrl_handler_free(&ctx->ctrl_handler); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); @@ -2167,12 +2205,14 @@ static int mxc_jpeg_probe(struct platform_device *pdev) jpeg->clk_ipg = devm_clk_get(dev, "ipg"); if (IS_ERR(jpeg->clk_ipg)) { dev_err(dev, "failed to get clock: ipg\n"); + ret = PTR_ERR(jpeg->clk_ipg); goto err_clk; } jpeg->clk_per = devm_clk_get(dev, "per"); if (IS_ERR(jpeg->clk_per)) { dev_err(dev, "failed to get clock: per\n"); + ret = PTR_ERR(jpeg->clk_per); goto err_clk; } diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h index 760eaf5387a1..c508d41a906f 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h @@ -92,11 +92,11 @@ struct mxc_jpeg_ctx { struct mxc_jpeg_q_data cap_q; struct v4l2_fh fh; enum mxc_jpeg_enc_state enc_state; - unsigned int stopping; - unsigned int stopped; unsigned int slot; unsigned int source_change; bool header_parsed; + struct v4l2_ctrl_handler ctrl_handler; + u8 jpeg_quality; }; struct mxc_jpeg_slot_data { diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index 80b1c021d14a..905072871ed2 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -46,6 +46,11 @@ /* Register map definition */ +/* CSIS version */ +#define MIPI_CSIS_VERSION 0x00 +#define MIPI_CSIS_VERSION_IMX7D 0x03030505 +#define MIPI_CSIS_VERSION_IMX8MP 0x03060301 + /* CSIS common control */ #define MIPI_CSIS_CMN_CTRL 0x04 #define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW BIT(16) @@ -1155,6 +1160,32 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, return 0; } +static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); + struct v4l2_mbus_frame_desc_entry *entry = &fd->entry[0]; + + if (pad != CSIS_PAD_SOURCE) + return -EINVAL; + + fd->type = V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL; + fd->num_entries = 1; + + memset(entry, 0, sizeof(*entry)); + + mutex_lock(&csis->lock); + + entry->flags = 0; + entry->pixelcode = csis->csis_fmt->code; + entry->bus.csi2.vc = 0; + entry->bus.csi2.dt = csis->csis_fmt->data_type; + + mutex_unlock(&csis->lock); + + return 0; +} + static int mipi_csis_log_status(struct v4l2_subdev *sd) { struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); @@ -1179,6 +1210,7 @@ static const struct v4l2_subdev_pad_ops mipi_csis_pad_ops = { .enum_mbus_code = mipi_csis_enum_mbus_code, .get_fmt = mipi_csis_get_fmt, .set_fmt = mipi_csis_set_fmt, + .get_frame_desc = mipi_csis_get_frame_desc, }; static const struct v4l2_subdev_ops mipi_csis_subdev_ops = { @@ -1378,6 +1410,13 @@ static int mipi_csis_subdev_init(struct mipi_csis_device *csis) sd->dev = csis->dev; + sd->fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(csis->dev), + 1, 0, 0); + if (!sd->fwnode) { + dev_err(csis->dev, "Unable to retrieve endpoint for port@1\n"); + return -ENOENT; + } + csis->csis_fmt = &mipi_csis_formats[0]; mipi_csis_init_cfg(sd, NULL); @@ -1498,6 +1537,7 @@ cleanup: v4l2_async_unregister_subdev(&csis->sd); disable_clock: mipi_csis_clk_disable(csis); + fwnode_handle_put(csis->sd.fwnode); mutex_destroy(&csis->lock); return ret; @@ -1517,6 +1557,7 @@ static int mipi_csis_remove(struct platform_device *pdev) mipi_csis_runtime_suspend(&pdev->dev); mipi_csis_clk_disable(csis); media_entity_cleanup(&csis->sd.entity); + fwnode_handle_put(csis->sd.fwnode); mutex_destroy(&csis->lock); pm_runtime_set_suspended(&pdev->dev); diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index f993f349b66b..88f188e0f750 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -245,7 +245,7 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) } if (!csid->testgen.enabled && - !media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK])) + !media_pad_remote_pad_first(&csid->pads[MSM_CSID_PAD_SINK])) return -ENOLINK; } @@ -518,7 +518,7 @@ static int csid_set_test_pattern(struct csid_device *csid, s32 value) struct csid_testgen_config *tg = &csid->testgen; /* If CSID is linked to CSIPHY, do not allow to enable test generator */ - if (value && media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK])) + if (value && media_pad_remote_pad_first(&csid->pads[MSM_CSID_PAD_SINK])) return -EBUSY; tg->enabled = !!value; @@ -666,7 +666,7 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, if (csid->num_supplies) { csid->supplies = devm_kmalloc_array(camss->dev, csid->num_supplies, - sizeof(csid->supplies), + sizeof(*csid->supplies), GFP_KERNEL); if (!csid->supplies) return -ENOMEM; @@ -729,7 +729,7 @@ static int csid_link_setup(struct media_entity *entity, const struct media_pad *remote, u32 flags) { if (flags & MEDIA_LNK_FL_ENABLED) - if (media_entity_remote_pad(local)) + if (media_pad_remote_pad_first(local)) return -EBUSY; if ((local->flags & MEDIA_PAD_FL_SINK) && diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 75fcfc627400..3f726a7237f5 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -693,7 +693,7 @@ static int csiphy_link_setup(struct media_entity *entity, struct csiphy_device *csiphy; struct csid_device *csid; - if (media_entity_remote_pad(local)) + if (media_pad_remote_pad_first(local)) return -EBUSY; sd = media_entity_to_v4l2_subdev(entity); diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index 4ee11bb979cd..b713f5b86aba 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -812,7 +812,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) int ret; if (enable) { - if (!media_entity_remote_pad(&line->pads[MSM_ISPIF_PAD_SINK])) + if (!media_pad_remote_pad_first(&line->pads[MSM_ISPIF_PAD_SINK])) return -ENOLINK; /* Config */ @@ -1253,6 +1253,41 @@ static enum ispif_intf ispif_get_intf(enum vfe_line_id line_id) } /* + * ispif_get_vfe_id - Get VFE HW module id + * @entity: Pointer to VFE media entity structure + * @id: Return CSID HW module id here + */ +static void ispif_get_vfe_id(struct media_entity *entity, u8 *id) +{ + struct v4l2_subdev *sd; + struct vfe_line *line; + struct vfe_device *vfe; + + sd = media_entity_to_v4l2_subdev(entity); + line = v4l2_get_subdevdata(sd); + vfe = to_vfe(line); + + *id = vfe->id; +} + +/* + * ispif_get_vfe_line_id - Get VFE line id by media entity + * @entity: Pointer to VFE media entity structure + * @id: Return VFE line id here + */ +static void ispif_get_vfe_line_id(struct media_entity *entity, + enum vfe_line_id *id) +{ + struct v4l2_subdev *sd; + struct vfe_line *line; + + sd = media_entity_to_v4l2_subdev(entity); + line = v4l2_get_subdevdata(sd); + + *id = line->id; +} + +/* * ispif_link_setup - Setup ISPIF connections * @entity: Pointer to media entity structure * @local: Pointer to local pad @@ -1266,7 +1301,7 @@ static int ispif_link_setup(struct media_entity *entity, const struct media_pad *remote, u32 flags) { if (flags & MEDIA_LNK_FL_ENABLED) { - if (media_entity_remote_pad(local)) + if (media_pad_remote_pad_first(local)) return -EBUSY; if (local->flags & MEDIA_PAD_FL_SINK) { @@ -1285,8 +1320,8 @@ static int ispif_link_setup(struct media_entity *entity, sd = media_entity_to_v4l2_subdev(entity); line = v4l2_get_subdevdata(sd); - msm_vfe_get_vfe_id(remote->entity, &line->vfe_id); - msm_vfe_get_vfe_line_id(remote->entity, &id); + ispif_get_vfe_id(remote->entity, &line->vfe_id); + ispif_get_vfe_line_id(remote->entity, &id); line->interface = ispif_get_intf(id); } } diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 5b148e9f8134..a26e4a5d87b6 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -1423,40 +1423,6 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, } /* - * msm_vfe_get_vfe_id - Get VFE HW module id - * @entity: Pointer to VFE media entity structure - * @id: Return CSID HW module id here - */ -void msm_vfe_get_vfe_id(struct media_entity *entity, u8 *id) -{ - struct v4l2_subdev *sd; - struct vfe_line *line; - struct vfe_device *vfe; - - sd = media_entity_to_v4l2_subdev(entity); - line = v4l2_get_subdevdata(sd); - vfe = to_vfe(line); - - *id = vfe->id; -} - -/* - * msm_vfe_get_vfe_line_id - Get VFE line id by media entity - * @entity: Pointer to VFE media entity structure - * @id: Return VFE line id here - */ -void msm_vfe_get_vfe_line_id(struct media_entity *entity, enum vfe_line_id *id) -{ - struct v4l2_subdev *sd; - struct vfe_line *line; - - sd = media_entity_to_v4l2_subdev(entity); - line = v4l2_get_subdevdata(sd); - - *id = line->id; -} - -/* * vfe_link_setup - Setup VFE connections * @entity: Pointer to media entity structure * @local: Pointer to local pad @@ -1470,7 +1436,7 @@ static int vfe_link_setup(struct media_entity *entity, const struct media_pad *remote, u32 flags) { if (flags & MEDIA_LNK_FL_ENABLED) - if (media_entity_remote_pad(local)) + if (media_pad_remote_pad_first(local)) return -EBUSY; return 0; diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index 0eba04eb9b77..cbc314c4e244 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -163,9 +163,6 @@ int msm_vfe_register_entities(struct vfe_device *vfe, void msm_vfe_unregister_entities(struct vfe_device *vfe); -void msm_vfe_get_vfe_id(struct media_entity *entity, u8 *id); -void msm_vfe_get_vfe_line_id(struct media_entity *entity, enum vfe_line_id *id); - /* * vfe_buf_add_pending - Add output buffer to list of pending * @output: VFE output diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 307bb1dc4589..290df04c4d02 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -328,7 +328,7 @@ static struct v4l2_subdev *video_remote_subdev(struct camss_video *video, { struct media_pad *remote; - remote = media_entity_remote_pad(&video->pad); + remote = media_pad_remote_pad_first(&video->pad); if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) return NULL; @@ -507,7 +507,7 @@ static int video_start_streaming(struct vb2_queue *q, unsigned int count) if (!(pad->flags & MEDIA_PAD_FL_SINK)) break; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; @@ -543,7 +543,7 @@ static void video_stop_streaming(struct vb2_queue *q) if (!(pad->flags & MEDIA_PAD_FL_SINK)) break; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 79ad82e233cb..1118c40886d5 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -937,7 +937,7 @@ struct media_entity *camss_find_sensor(struct media_entity *entity) if (!(pad->flags & MEDIA_PAD_FL_SINK)) return NULL; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) return NULL; @@ -1452,19 +1452,31 @@ static const struct media_device_ops camss_media_ops = { static int camss_configure_pd(struct camss *camss) { - int nbr_pm_domains = 0; + struct device *dev = camss->dev; int last_pm_domain = 0; int i; int ret; - if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) - nbr_pm_domains = PM_DOMAIN_GEN1_COUNT; - else if (camss->version == CAMSS_845 || - camss->version == CAMSS_8250) - nbr_pm_domains = PM_DOMAIN_GEN2_COUNT; + camss->genpd_num = of_count_phandle_with_args(dev->of_node, + "power-domains", + "#power-domain-cells"); + if (camss->genpd_num < 0) { + dev_err(dev, "Power domains are not defined for camss\n"); + return camss->genpd_num; + } + + camss->genpd = devm_kmalloc_array(dev, camss->genpd_num, + sizeof(*camss->genpd), GFP_KERNEL); + if (!camss->genpd) + return -ENOMEM; + + camss->genpd_link = devm_kmalloc_array(dev, camss->genpd_num, + sizeof(*camss->genpd_link), + GFP_KERNEL); + if (!camss->genpd_link) + return -ENOMEM; - for (i = 0; i < nbr_pm_domains; i++) { + for (i = 0; i < camss->genpd_num; i++) { camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i); if (IS_ERR(camss->genpd[i])) { ret = PTR_ERR(camss->genpd[i]); @@ -1529,7 +1541,7 @@ static int camss_probe(struct platform_device *pdev) struct camss *camss; int num_subdevs, ret; - camss = kzalloc(sizeof(*camss), GFP_KERNEL); + camss = devm_kzalloc(dev, sizeof(*camss), GFP_KERNEL); if (!camss) return -ENOMEM; @@ -1567,39 +1579,30 @@ static int camss_probe(struct platform_device *pdev) camss->csid_num = 4; camss->vfe_num = 4; } else { - ret = -EINVAL; - goto err_free; + return -EINVAL; } camss->csiphy = devm_kcalloc(dev, camss->csiphy_num, sizeof(*camss->csiphy), GFP_KERNEL); - if (!camss->csiphy) { - ret = -ENOMEM; - goto err_free; - } + if (!camss->csiphy) + return -ENOMEM; camss->csid = devm_kcalloc(dev, camss->csid_num, sizeof(*camss->csid), GFP_KERNEL); - if (!camss->csid) { - ret = -ENOMEM; - goto err_free; - } + if (!camss->csid) + return -ENOMEM; if (camss->version == CAMSS_8x16 || camss->version == CAMSS_8x96) { camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->ispif), GFP_KERNEL); - if (!camss->ispif) { - ret = -ENOMEM; - goto err_free; - } + if (!camss->ispif) + return -ENOMEM; } camss->vfe = devm_kcalloc(dev, camss->vfe_num, sizeof(*camss->vfe), GFP_KERNEL); - if (!camss->vfe) { - ret = -ENOMEM; - goto err_free; - } + if (!camss->vfe) + return -ENOMEM; v4l2_async_nf_init(&camss->notifier); @@ -1681,15 +1684,12 @@ err_register_entities: v4l2_device_unregister(&camss->v4l2_dev); err_cleanup: v4l2_async_nf_cleanup(&camss->notifier); -err_free: - kfree(camss); return ret; } void camss_delete(struct camss *camss) { - int nbr_pm_domains = 0; int i; v4l2_device_unregister(&camss->v4l2_dev); @@ -1698,19 +1698,10 @@ void camss_delete(struct camss *camss) pm_runtime_disable(camss->dev); - if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) - nbr_pm_domains = PM_DOMAIN_GEN1_COUNT; - else if (camss->version == CAMSS_845 || - camss->version == CAMSS_8250) - nbr_pm_domains = PM_DOMAIN_GEN2_COUNT; - - for (i = 0; i < nbr_pm_domains; i++) { + for (i = 0; i < camss->genpd_num; i++) { device_link_del(camss->genpd_link[i]); dev_pm_domain_detach(camss->genpd[i], true); } - - kfree(camss); } /* diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index c9b3e0df5be8..0db80cadbbaa 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -69,9 +69,7 @@ struct resources_icc { enum pm_domain { PM_DOMAIN_VFE0 = 0, PM_DOMAIN_VFE1 = 1, - PM_DOMAIN_GEN1_COUNT = 2, /* CAMSS series of ISPs */ PM_DOMAIN_VFELITE = 2, /* VFELITE / TOP GDSC */ - PM_DOMAIN_GEN2_COUNT = 3, /* Titan series of ISPs */ }; enum camss_version { @@ -101,8 +99,9 @@ struct camss { int vfe_num; struct vfe_device *vfe; atomic_t ref_count; - struct device *genpd[PM_DOMAIN_GEN2_COUNT]; - struct device_link *genpd_link[PM_DOMAIN_GEN2_COUNT]; + int genpd_num; + struct device **genpd; + struct device_link **genpd_link; struct icc_path *icc_path[ICC_SM8250_COUNT]; struct icc_bw_tbl icc_bw_tbl[ICC_SM8250_COUNT]; }; diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 877eca125803..990a1519f968 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -265,6 +265,19 @@ static void venus_assign_register_offsets(struct venus_core *core) } } +static irqreturn_t venus_isr_thread(int irq, void *dev_id) +{ + struct venus_core *core = dev_id; + irqreturn_t ret; + + ret = hfi_isr_thread(irq, dev_id); + + if (ret == IRQ_HANDLED && venus_fault_inject_ssr()) + hfi_core_trigger_ssr(core, HFI_TEST_SSR_SW_ERR_FATAL); + + return ret; +} + static int venus_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -320,7 +333,7 @@ static int venus_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&core->work, venus_sys_error_handler); init_waitqueue_head(&core->sys_err_done); - ret = devm_request_threaded_irq(dev, core->irq, hfi_isr, hfi_isr_thread, + ret = devm_request_threaded_irq(dev, core->irq, hfi_isr, venus_isr_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "venus", core); if (ret) @@ -832,6 +845,10 @@ static const struct reg_val sm7280_reg_preset[] = { { 0xb0088, 0 }, }; +static const struct hfi_ubwc_config sc7280_ubwc_config = { + 0, 0, {1, 1, 1, 0, 0, 0}, 8, 32, 14, 0, 0, {0, 0} +}; + static const struct venus_resources sc7280_res = { .freq_tbl = sc7280_freq_table, .freq_tbl_size = ARRAY_SIZE(sc7280_freq_table), @@ -841,6 +858,7 @@ static const struct venus_resources sc7280_res = { .bw_tbl_enc_size = ARRAY_SIZE(sc7280_bw_table_enc), .bw_tbl_dec = sc7280_bw_table_dec, .bw_tbl_dec_size = ARRAY_SIZE(sc7280_bw_table_dec), + .ubwc_conf = &sc7280_ubwc_config, .clks = {"core", "bus", "iface"}, .clks_num = 3, .vcodec0_clks = {"vcodec_core", "vcodec_bus"}, diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index d33825553edc..32551c2602a9 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -16,6 +16,7 @@ #include "dbgfs.h" #include "hfi.h" #include "hfi_platform.h" +#include "hfi_helper.h" #define VDBGL "VenusLow : " #define VDBGM "VenusMed : " @@ -57,6 +58,7 @@ struct venus_resources { unsigned int bw_tbl_dec_size; const struct reg_val *reg_tbl; unsigned int reg_tbl_size; + const struct hfi_ubwc_config *ubwc_conf; const char * const clks[VIDC_CLKS_NUM_MAX]; unsigned int clks_num; const char * const vcodec0_clks[VIDC_VCODEC_CLKS_NUM_MAX]; diff --git a/drivers/media/platform/qcom/venus/dbgfs.c b/drivers/media/platform/qcom/venus/dbgfs.c index 52de47f2ca88..726f4b730e69 100644 --- a/drivers/media/platform/qcom/venus/dbgfs.c +++ b/drivers/media/platform/qcom/venus/dbgfs.c @@ -4,13 +4,22 @@ */ #include <linux/debugfs.h> +#include <linux/fault-inject.h> #include "core.h" +#ifdef CONFIG_FAULT_INJECTION +DECLARE_FAULT_ATTR(venus_ssr_attr); +#endif + void venus_dbgfs_init(struct venus_core *core) { core->root = debugfs_create_dir("venus", NULL); debugfs_create_x32("fw_level", 0644, core->root, &venus_fw_debug); + +#ifdef CONFIG_FAULT_INJECTION + fault_create_debugfs_attr("fail_ssr", core->root, &venus_ssr_attr); +#endif } void venus_dbgfs_deinit(struct venus_core *core) diff --git a/drivers/media/platform/qcom/venus/dbgfs.h b/drivers/media/platform/qcom/venus/dbgfs.h index b7b621a8472f..c87c1355d039 100644 --- a/drivers/media/platform/qcom/venus/dbgfs.h +++ b/drivers/media/platform/qcom/venus/dbgfs.h @@ -4,8 +4,21 @@ #ifndef __VENUS_DBGFS_H__ #define __VENUS_DBGFS_H__ +#include <linux/fault-inject.h> + struct venus_core; +#ifdef CONFIG_FAULT_INJECTION +extern struct fault_attr venus_ssr_attr; +static inline bool venus_fault_inject_ssr(void) +{ + return should_fail(&venus_ssr_attr, 1); +} +#else +static inline bool venus_fault_inject_ssr(void) { return false; } +#endif + + void venus_dbgfs_init(struct venus_core *core); void venus_dbgfs_deinit(struct venus_core *core); diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 5c1104379c49..60de4200375d 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -671,8 +671,7 @@ int venus_helper_get_bufreq(struct venus_inst *inst, u32 type, unsigned int i; int ret; - if (req) - memset(req, 0, sizeof(*req)); + memset(req, 0, sizeof(*req)); if (type == HFI_BUFFER_OUTPUT || type == HFI_BUFFER_OUTPUT2) req->count_min = inst->fw_min_cnt; @@ -694,8 +693,7 @@ int venus_helper_get_bufreq(struct venus_inst *inst, u32 type, if (hprop.bufreq[i].type != type) continue; - if (req) - memcpy(req, &hprop.bufreq[i], sizeof(*req)); + memcpy(req, &hprop.bufreq[i], sizeof(*req)); ret = 0; break; } diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c index 4ecd444050bb..930b743f225e 100644 --- a/drivers/media/platform/qcom/venus/hfi_cmds.c +++ b/drivers/media/platform/qcom/venus/hfi_cmds.c @@ -58,6 +58,15 @@ void pkt_sys_coverage_config(struct hfi_sys_set_property_pkt *pkt, u32 mode) pkt->data[1] = mode; } +void pkt_sys_ubwc_config(struct hfi_sys_set_property_pkt *pkt, const struct hfi_ubwc_config *hfi) +{ + pkt->hdr.size = struct_size(pkt, data, 1) + sizeof(*hfi); + pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY; + pkt->num_properties = 1; + pkt->data[0] = HFI_PROPERTY_SYS_UBWC_CONFIG; + memcpy(&pkt->data[1], hfi, sizeof(*hfi)); +} + int pkt_sys_set_resource(struct hfi_sys_set_resource_pkt *pkt, u32 id, u32 size, u32 addr, void *cookie) { diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.h b/drivers/media/platform/qcom/venus/hfi_cmds.h index 327ed90a2788..99bc0b6db67c 100644 --- a/drivers/media/platform/qcom/venus/hfi_cmds.h +++ b/drivers/media/platform/qcom/venus/hfi_cmds.h @@ -256,6 +256,7 @@ void pkt_sys_init(struct hfi_sys_init_pkt *pkt, u32 arch_type); void pkt_sys_pc_prep(struct hfi_sys_pc_prep_pkt *pkt); void pkt_sys_idle_indicator(struct hfi_sys_set_property_pkt *pkt, u32 enable); void pkt_sys_power_control(struct hfi_sys_set_property_pkt *pkt, u32 enable); +void pkt_sys_ubwc_config(struct hfi_sys_set_property_pkt *pkt, const struct hfi_ubwc_config *hfi); int pkt_sys_set_resource(struct hfi_sys_set_resource_pkt *pkt, u32 id, u32 size, u32 addr, void *cookie); int pkt_sys_unset_resource(struct hfi_sys_release_resource_pkt *pkt, u32 id, diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h index 2daa88e3df9f..d2d6719a2ba4 100644 --- a/drivers/media/platform/qcom/venus/hfi_helper.h +++ b/drivers/media/platform/qcom/venus/hfi_helper.h @@ -427,6 +427,7 @@ #define HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL 0x5 #define HFI_PROPERTY_SYS_IMAGE_VERSION 0x6 #define HFI_PROPERTY_SYS_CONFIG_COVERAGE 0x7 +#define HFI_PROPERTY_SYS_UBWC_CONFIG 0x8 /* * HFI_PROPERTY_PARAM_COMMON_START @@ -626,6 +627,25 @@ struct hfi_debug_config { u32 mode; }; +struct hfi_ubwc_config { + u32 size; + u32 packet_type; + struct { + u32 max_channel_override : 1; + u32 mal_length_override : 1; + u32 hb_override : 1; + u32 bank_swzl_level_override : 1; + u32 bank_spreading_override : 1; + u32 reserved : 27; + } override_bit_info; + u32 max_channels; + u32 mal_length; + u32 highest_bank_bit; + u32 bank_swzl_level; + u32 bank_spreading; + u32 reserved[2]; +}; + struct hfi_enable { u32 enable; }; diff --git a/drivers/media/platform/qcom/venus/hfi_parser.c b/drivers/media/platform/qcom/venus/hfi_parser.c index 5b8389b98299..6cf74b2bc5ae 100644 --- a/drivers/media/platform/qcom/venus/hfi_parser.c +++ b/drivers/media/platform/qcom/venus/hfi_parser.c @@ -234,6 +234,7 @@ static int hfi_platform_parser(struct venus_core *core, struct venus_inst *inst) const struct hfi_plat_caps *caps = NULL; u32 enc_codecs, dec_codecs, count = 0; unsigned int entries; + int ret; plat = hfi_platform_get(core->res->hfi_version); if (!plat) @@ -242,8 +243,9 @@ static int hfi_platform_parser(struct venus_core *core, struct venus_inst *inst) if (inst) return 0; - if (plat->codecs) - plat->codecs(&enc_codecs, &dec_codecs, &count); + ret = hfi_platform_get_codecs(core, &enc_codecs, &dec_codecs, &count); + if (ret) + return ret; if (plat->capabilities) caps = plat->capabilities(&entries); diff --git a/drivers/media/platform/qcom/venus/hfi_platform.c b/drivers/media/platform/qcom/venus/hfi_platform.c index f16f8962273c..f07f554bc5fe 100644 --- a/drivers/media/platform/qcom/venus/hfi_platform.c +++ b/drivers/media/platform/qcom/venus/hfi_platform.c @@ -2,7 +2,9 @@ /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ +#include <linux/of_device.h> #include "hfi_platform.h" +#include "core.h" const struct hfi_platform *hfi_platform_get(enum hfi_version version) { @@ -66,3 +68,23 @@ hfi_platform_get_codec_lp_freq(enum hfi_version version, u32 codec, u32 session_ return freq; } +int +hfi_platform_get_codecs(struct venus_core *core, u32 *enc_codecs, u32 *dec_codecs, u32 *count) +{ + const struct hfi_platform *plat; + + plat = hfi_platform_get(core->res->hfi_version); + if (!plat) + return -EINVAL; + + if (plat->codecs) + plat->codecs(enc_codecs, dec_codecs, count); + + if (of_device_is_compatible(core->dev->of_node, "qcom,sc7280-venus")) { + *enc_codecs &= ~HFI_VIDEO_CODEC_VP8; + *dec_codecs &= ~HFI_VIDEO_CODEC_VP8; + } + + return 0; +} + diff --git a/drivers/media/platform/qcom/venus/hfi_platform.h b/drivers/media/platform/qcom/venus/hfi_platform.h index 1dcf4085928c..ec89a90a8129 100644 --- a/drivers/media/platform/qcom/venus/hfi_platform.h +++ b/drivers/media/platform/qcom/venus/hfi_platform.h @@ -66,4 +66,6 @@ unsigned long hfi_platform_get_codec_vsp_freq(enum hfi_version version, u32 code u32 session_type); unsigned long hfi_platform_get_codec_lp_freq(enum hfi_version version, u32 codec, u32 session_type); +int hfi_platform_get_codecs(struct venus_core *core, u32 *enc_codecs, u32 *dec_codecs, + u32 *count); #endif diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c index 9a34662fea38..2ad40b3945b0 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.c +++ b/drivers/media/platform/qcom/venus/hfi_venus.c @@ -904,6 +904,24 @@ static int venus_sys_set_power_control(struct venus_hfi_device *hdev, return 0; } +static int venus_sys_set_ubwc_config(struct venus_hfi_device *hdev) +{ + struct hfi_sys_set_property_pkt *pkt; + u8 packet[IFACEQ_VAR_SMALL_PKT_SIZE]; + const struct venus_resources *res = hdev->core->res; + int ret; + + pkt = (struct hfi_sys_set_property_pkt *)packet; + + pkt_sys_ubwc_config(pkt, res->ubwc_conf); + + ret = venus_iface_cmdq_write(hdev, pkt, false); + if (ret) + return ret; + + return 0; +} + static int venus_get_queue_size(struct venus_hfi_device *hdev, unsigned int index) { @@ -922,6 +940,7 @@ static int venus_get_queue_size(struct venus_hfi_device *hdev, static int venus_sys_set_default_properties(struct venus_hfi_device *hdev) { struct device *dev = hdev->core->dev; + const struct venus_resources *res = hdev->core->res; int ret; ret = venus_sys_set_debug(hdev, venus_fw_debug); @@ -945,6 +964,13 @@ static int venus_sys_set_default_properties(struct venus_hfi_device *hdev) dev_warn(dev, "setting hw power collapse ON failed (%d)\n", ret); + /* For specific venus core, it is mandatory to set the UBWC configuration */ + if (res->ubwc_conf) { + ret = venus_sys_set_ubwc_config(hdev); + if (ret) + dev_warn(dev, "setting ubwc config failed (%d)\n", ret); + } + return ret; } diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c index 49bdcfba010b..968a74234e92 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c @@ -845,7 +845,7 @@ static int rvin_csi2_link_notify(struct media_link *link, u32 flags, continue; /* Get remote CSI-2, if any. */ - csi_pad = media_entity_remote_pad( + csi_pad = media_pad_remote_pad_first( &group->vin[i]->vdev.entity.pads[0]); if (!csi_pad) continue; @@ -1261,7 +1261,7 @@ static const struct rvin_info rcar_info_r8a77980 = { }; static const struct rvin_group_route rcar_info_r8a77990_routes[] = { - { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 }, + { .master = 4, .csi = RVIN_CSI40, .chsel = 0x03 }, { /* Sentinel */ } }; diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c index fea8f00a9152..174aa6176f54 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c @@ -1313,7 +1313,7 @@ static int rcsi2_link_setup(struct media_entity *entity, channel = id % 4; if (flags & MEDIA_LNK_FL_ENABLED) { - if (media_entity_remote_pad(local)) { + if (media_pad_remote_pad_first(local)) { dev_dbg(priv->dev, "Each VC can only be routed to one output channel\n"); return -EINVAL; diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c index 6644b498929d..8d37fbdc266a 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c @@ -1258,7 +1258,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on) return ret == -ENOIOCTLCMD ? 0 : ret; } - pad = media_entity_remote_pad(&vin->pad); + pad = media_pad_remote_pad_first(&vin->pad); if (!pad) return -EPIPE; diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c index 2e2aa9d746ee..576059f9bbe3 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c @@ -1032,7 +1032,7 @@ static void rvin_notify(struct v4l2_subdev *sd, if (!vin) continue; - pad = media_entity_remote_pad(&vin->pad); + pad = media_pad_remote_pad_first(&vin->pad); if (!pad) continue; diff --git a/drivers/media/platform/renesas/rcar_drif.c b/drivers/media/platform/renesas/rcar_drif.c index 9a0982fa5c6b..3fec41f6e964 100644 --- a/drivers/media/platform/renesas/rcar_drif.c +++ b/drivers/media/platform/renesas/rcar_drif.c @@ -3,11 +3,6 @@ * R-Car Gen3 Digital Radio Interface (DRIF) driver * * Copyright (C) 2017 Renesas Electronics Corporation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ /* @@ -1477,7 +1472,7 @@ MODULE_DEVICE_TABLE(of, rcar_drif_of_table); static struct platform_driver rcar_drif_driver = { .driver = { .name = RCAR_DRIF_DRV_NAME, - .of_match_table = of_match_ptr(rcar_drif_of_table), + .of_match_table = rcar_drif_of_table, .pm = &rcar_drif_pm_ops, }, .probe = rcar_drif_probe, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c index a116a3362f9e..4c3bd2b1ca28 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c @@ -516,8 +516,8 @@ int vsp1_entity_link_setup(struct media_entity *entity, * higher than one for the data pipelines, except for the links to the HGO and * HGT that can be enabled in addition to a regular data link. When traversing * outgoing links this function ignores HGO and HGT entities and should thus be - * used in place of the generic media_entity_remote_pad() function to traverse - * data pipelines. + * used in place of the generic media_pad_remote_pad_first() function to + * traverse data pipelines. * * Return a pointer to the pad at the remote end of the first found enabled * link, or NULL if no enabled link has been found. diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c index 51219b1b6ea9..e8e0ee5f2277 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_video.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c @@ -50,7 +50,7 @@ vsp1_video_remote_subdev(struct media_pad *local, u32 *pad) { struct media_pad *remote; - remote = media_entity_remote_pad(local); + remote = media_pad_remote_pad_first(local); if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) return NULL; diff --git a/drivers/media/platform/rockchip/rkisp1/Kconfig b/drivers/media/platform/rockchip/rkisp1/Kconfig index dabd7e42c193..731c9acbf6ef 100644 --- a/drivers/media/platform/rockchip/rkisp1/Kconfig +++ b/drivers/media/platform/rockchip/rkisp1/Kconfig @@ -3,7 +3,7 @@ config VIDEO_ROCKCHIP_ISP1 tristate "Rockchip Image Signal Processing v1 Unit driver" depends on V4L_PLATFORM_DRIVERS depends on VIDEO_DEV && OF - depends on ARCH_ROCKCHIP || COMPILE_TEST + depends on ARCH_ROCKCHIP || ARCH_MXC || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG diff --git a/drivers/media/platform/rockchip/rkisp1/Makefile b/drivers/media/platform/rockchip/rkisp1/Makefile index ab32a77db8f7..b3844c4f7623 100644 --- a/drivers/media/platform/rockchip/rkisp1/Makefile +++ b/drivers/media/platform/rockchip/rkisp1/Makefile @@ -1,10 +1,14 @@ # SPDX-License-Identifier: GPL-2.0 +rockchip-isp1-y := rkisp1-capture.o \ + rkisp1-common.o \ + rkisp1-csi.o \ + rkisp1-dev.o \ + rkisp1-isp.o \ + rkisp1-resizer.o \ + rkisp1-stats.o \ + rkisp1-params.o + +rockchip-isp1-$(CONFIG_DEBUG_FS) += rkisp1-debug.o + obj-$(CONFIG_VIDEO_ROCKCHIP_ISP1) += rockchip-isp1.o -rockchip-isp1-objs += rkisp1-capture.o \ - rkisp1-common.o \ - rkisp1-dev.o \ - rkisp1-isp.o \ - rkisp1-resizer.o \ - rkisp1-stats.o \ - rkisp1-params.o diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index fee2aaacb26b..d5904c96ff3f 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -383,7 +383,7 @@ static void rkisp1_mi_config_ctrl(struct rkisp1_capture *cap) mi_ctrl |= RKISP1_CIF_MI_CTRL_INIT_BASE_EN | RKISP1_CIF_MI_CTRL_INIT_OFFSET_EN; - rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); + rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl); } static u32 rkisp1_pixfmt_comp_size(const struct v4l2_pix_format_mplane *pixm, @@ -404,7 +404,7 @@ static void rkisp1_irq_frame_end_enable(struct rkisp1_capture *cap) u32 mi_imsc = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_IMSC); mi_imsc |= RKISP1_CIF_MI_FRAME(cap); - rkisp1_write(cap->rkisp1, mi_imsc, RKISP1_CIF_MI_IMSC); + rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_IMSC, mi_imsc); } static void rkisp1_mp_config(struct rkisp1_capture *cap) @@ -413,12 +413,12 @@ static void rkisp1_mp_config(struct rkisp1_capture *cap) struct rkisp1_device *rkisp1 = cap->rkisp1; u32 reg; - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y), - cap->config->mi.y_size_init); - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB), - cap->config->mi.cb_size_init); - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR), - cap->config->mi.cr_size_init); + rkisp1_write(rkisp1, cap->config->mi.y_size_init, + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y)); + rkisp1_write(rkisp1, cap->config->mi.cb_size_init, + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB)); + rkisp1_write(rkisp1, cap->config->mi.cr_size_init, + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR)); rkisp1_irq_frame_end_enable(cap); @@ -429,7 +429,7 @@ static void rkisp1_mp_config(struct rkisp1_capture *cap) reg |= RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP; else reg &= ~RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP; - rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_XTD_FORMAT_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL, reg); } rkisp1_mi_config_ctrl(cap); @@ -437,11 +437,11 @@ static void rkisp1_mp_config(struct rkisp1_capture *cap) reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL); reg &= ~RKISP1_MI_CTRL_MP_FMT_MASK; reg |= cap->pix.cfg->write_format; - rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_MI_CTRL, reg); reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL); reg |= RKISP1_CIF_MI_MP_AUTOUPDATE_ENABLE; - rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_MI_CTRL, reg); } static void rkisp1_sp_config(struct rkisp1_capture *cap) @@ -450,16 +450,16 @@ static void rkisp1_sp_config(struct rkisp1_capture *cap) struct rkisp1_device *rkisp1 = cap->rkisp1; u32 mi_ctrl, reg; - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y), - cap->config->mi.y_size_init); - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB), - cap->config->mi.cb_size_init); - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR), - cap->config->mi.cr_size_init); + rkisp1_write(rkisp1, cap->config->mi.y_size_init, + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y)); + rkisp1_write(rkisp1, cap->config->mi.cb_size_init, + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB)); + rkisp1_write(rkisp1, cap->config->mi.cr_size_init, + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR)); - rkisp1_write(rkisp1, pixm->width, RKISP1_CIF_MI_SP_Y_PIC_WIDTH); - rkisp1_write(rkisp1, pixm->height, RKISP1_CIF_MI_SP_Y_PIC_HEIGHT); - rkisp1_write(rkisp1, cap->sp_y_stride, RKISP1_CIF_MI_SP_Y_LLENGTH); + rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_WIDTH, pixm->width); + rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_HEIGHT, pixm->height); + rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_LLENGTH, cap->sp_y_stride); rkisp1_irq_frame_end_enable(cap); @@ -470,7 +470,7 @@ static void rkisp1_sp_config(struct rkisp1_capture *cap) reg |= RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP; else reg &= ~RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP; - rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_XTD_FORMAT_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL, reg); } rkisp1_mi_config_ctrl(cap); @@ -481,7 +481,7 @@ static void rkisp1_sp_config(struct rkisp1_capture *cap) RKISP1_MI_CTRL_SP_INPUT_YUV422 | cap->pix.cfg->output_format | RKISP1_CIF_MI_SP_AUTOUPDATE_ENABLE; - rkisp1_write(rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl); } static void rkisp1_mp_disable(struct rkisp1_capture *cap) @@ -490,7 +490,7 @@ static void rkisp1_mp_disable(struct rkisp1_capture *cap) mi_ctrl &= ~(RKISP1_CIF_MI_CTRL_MP_ENABLE | RKISP1_CIF_MI_CTRL_RAW_ENABLE); - rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); + rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl); } static void rkisp1_sp_disable(struct rkisp1_capture *cap) @@ -498,7 +498,7 @@ static void rkisp1_sp_disable(struct rkisp1_capture *cap) u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); mi_ctrl &= ~RKISP1_CIF_MI_CTRL_SP_ENABLE; - rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); + rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl); } static void rkisp1_mp_enable(struct rkisp1_capture *cap) @@ -514,7 +514,7 @@ static void rkisp1_mp_enable(struct rkisp1_capture *cap) else mi_ctrl |= RKISP1_CIF_MI_CTRL_MP_ENABLE; - rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); + rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl); } static void rkisp1_sp_enable(struct rkisp1_capture *cap) @@ -522,15 +522,14 @@ static void rkisp1_sp_enable(struct rkisp1_capture *cap) u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); mi_ctrl |= RKISP1_CIF_MI_CTRL_SP_ENABLE; - rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); + rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl); } static void rkisp1_mp_sp_stop(struct rkisp1_capture *cap) { if (!cap->is_streaming) return; - rkisp1_write(cap->rkisp1, - RKISP1_CIF_MI_FRAME(cap), RKISP1_CIF_MI_ICR); + rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_ICR, RKISP1_CIF_MI_FRAME(cap)); cap->ops->disable(cap); } @@ -554,7 +553,7 @@ static void rkisp1_mp_set_data_path(struct rkisp1_capture *cap) dpcl = dpcl | RKISP1_CIF_VI_DPCL_CHAN_MODE_MP | RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI; - rkisp1_write(cap->rkisp1, dpcl, RKISP1_CIF_VI_DPCL); + rkisp1_write(cap->rkisp1, RKISP1_CIF_VI_DPCL, dpcl); } static void rkisp1_sp_set_data_path(struct rkisp1_capture *cap) @@ -562,7 +561,7 @@ static void rkisp1_sp_set_data_path(struct rkisp1_capture *cap) u32 dpcl = rkisp1_read(cap->rkisp1, RKISP1_CIF_VI_DPCL); dpcl |= RKISP1_CIF_VI_DPCL_CHAN_MODE_SP; - rkisp1_write(cap->rkisp1, dpcl, RKISP1_CIF_VI_DPCL); + rkisp1_write(cap->rkisp1, RKISP1_CIF_VI_DPCL, dpcl); } static const struct rkisp1_capture_ops rkisp1_capture_ops_mp = { @@ -628,9 +627,8 @@ static void rkisp1_set_next_buf(struct rkisp1_capture *cap) buff_addr = cap->buf.next->buff_addr; - rkisp1_write(cap->rkisp1, - buff_addr[RKISP1_PLANE_Y], - cap->config->mi.y_base_ad_init); + rkisp1_write(cap->rkisp1, cap->config->mi.y_base_ad_init, + buff_addr[RKISP1_PLANE_Y]); /* * In order to support grey format we capture * YUV422 planar format from the camera and @@ -638,39 +636,36 @@ static void rkisp1_set_next_buf(struct rkisp1_capture *cap) */ if (cap->pix.cfg->fourcc == V4L2_PIX_FMT_GREY) { rkisp1_write(cap->rkisp1, - cap->buf.dummy.dma_addr, - cap->config->mi.cb_base_ad_init); + cap->config->mi.cb_base_ad_init, + cap->buf.dummy.dma_addr); rkisp1_write(cap->rkisp1, - cap->buf.dummy.dma_addr, - cap->config->mi.cr_base_ad_init); + cap->config->mi.cr_base_ad_init, + cap->buf.dummy.dma_addr); } else { rkisp1_write(cap->rkisp1, - buff_addr[RKISP1_PLANE_CB], - cap->config->mi.cb_base_ad_init); + cap->config->mi.cb_base_ad_init, + buff_addr[RKISP1_PLANE_CB]); rkisp1_write(cap->rkisp1, - buff_addr[RKISP1_PLANE_CR], - cap->config->mi.cr_base_ad_init); + cap->config->mi.cr_base_ad_init, + buff_addr[RKISP1_PLANE_CR]); } } else { /* * Use the dummy space allocated by dma_alloc_coherent to * throw data if there is no available buffer. */ - rkisp1_write(cap->rkisp1, - cap->buf.dummy.dma_addr, - cap->config->mi.y_base_ad_init); - rkisp1_write(cap->rkisp1, - cap->buf.dummy.dma_addr, - cap->config->mi.cb_base_ad_init); - rkisp1_write(cap->rkisp1, - cap->buf.dummy.dma_addr, - cap->config->mi.cr_base_ad_init); + rkisp1_write(cap->rkisp1, cap->config->mi.y_base_ad_init, + cap->buf.dummy.dma_addr); + rkisp1_write(cap->rkisp1, cap->config->mi.cb_base_ad_init, + cap->buf.dummy.dma_addr); + rkisp1_write(cap->rkisp1, cap->config->mi.cr_base_ad_init, + cap->buf.dummy.dma_addr); } /* Set plane offsets */ - rkisp1_write(cap->rkisp1, 0, cap->config->mi.y_offs_cnt_init); - rkisp1_write(cap->rkisp1, 0, cap->config->mi.cb_offs_cnt_init); - rkisp1_write(cap->rkisp1, 0, cap->config->mi.cr_offs_cnt_init); + rkisp1_write(cap->rkisp1, cap->config->mi.y_offs_cnt_init, 0); + rkisp1_write(cap->rkisp1, cap->config->mi.cb_offs_cnt_init, 0); + rkisp1_write(cap->rkisp1, cap->config->mi.cr_offs_cnt_init, 0); } /* @@ -710,7 +705,7 @@ irqreturn_t rkisp1_capture_isr(int irq, void *ctx) if (!status) return IRQ_NONE; - rkisp1_write(rkisp1, status, RKISP1_CIF_MI_ICR); + rkisp1_write(rkisp1, RKISP1_CIF_MI_ICR, status); for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); ++i) { struct rkisp1_capture *cap = &rkisp1->capture_devs[i]; @@ -888,8 +883,8 @@ static void rkisp1_cap_stream_enable(struct rkisp1_capture *cap) */ if (!other->is_streaming) { /* force cfg update */ - rkisp1_write(rkisp1, - RKISP1_CIF_MI_INIT_SOFT_UPD, RKISP1_CIF_MI_INIT); + rkisp1_write(rkisp1, RKISP1_CIF_MI_INIT, + RKISP1_CIF_MI_INIT_SOFT_UPD); rkisp1_set_next_buf(cap); } spin_unlock_irq(&cap->buf.lock); @@ -931,11 +926,8 @@ static void rkisp1_pipeline_stream_disable(struct rkisp1_capture *cap) * If the other capture is streaming, isp and sensor nodes shouldn't * be disabled, skip them. */ - if (rkisp1->pipe.streaming_count < 2) { - v4l2_subdev_call(rkisp1->active_sensor->sd, video, s_stream, - false); + if (rkisp1->pipe.streaming_count < 2) v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false); - } v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream, false); @@ -971,15 +963,8 @@ static int rkisp1_pipeline_stream_enable(struct rkisp1_capture *cap) if (ret) goto err_disable_rsz; - ret = v4l2_subdev_call(rkisp1->active_sensor->sd, video, s_stream, - true); - if (ret) - goto err_disable_isp; - return 0; -err_disable_isp: - v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false); err_disable_rsz: v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream, false); @@ -1253,11 +1238,8 @@ static int rkisp1_g_fmt_vid_cap_mplane(struct file *file, void *fh, static int rkisp1_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct rkisp1_capture *cap_dev = video_drvdata(file); - struct rkisp1_device *rkisp1 = cap_dev->rkisp1; - - strscpy(cap->driver, rkisp1->dev->driver->name, sizeof(cap->driver)); - strscpy(cap->card, rkisp1->dev->driver->name, sizeof(cap->card)); + strscpy(cap->driver, RKISP1_DRIVER_NAME, sizeof(cap->driver)); + strscpy(cap->card, RKISP1_DRIVER_NAME, sizeof(cap->card)); strscpy(cap->bus_info, RKISP1_BUS_INFO, sizeof(cap->bus_info)); return 0; @@ -1302,8 +1284,16 @@ static int rkisp1_capture_link_validate(struct media_link *link) if (sd_fmt.format.height != cap->pix.fmt.height || sd_fmt.format.width != cap->pix.fmt.width || - sd_fmt.format.code != fmt->mbus) + sd_fmt.format.code != fmt->mbus) { + dev_dbg(cap->rkisp1->dev, + "link '%s':%u -> '%s':%u not valid: 0x%04x/%ux%u != 0x%04x/%ux%u\n", + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index, + sd_fmt.format.code, sd_fmt.format.width, + sd_fmt.format.height, fmt->mbus, cap->pix.fmt.width, + cap->pix.fmt.height); return -EPIPE; + } return 0; } @@ -1326,8 +1316,12 @@ static const struct v4l2_file_operations rkisp1_fops = { static void rkisp1_unregister_capture(struct rkisp1_capture *cap) { + if (!video_is_registered(&cap->vnode.vdev)) + return; + media_entity_cleanup(&cap->vnode.vdev.entity); vb2_video_unregister_device(&cap->vnode.vdev); + mutex_destroy(&cap->vnode.vlock); } void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1) @@ -1381,27 +1375,31 @@ static int rkisp1_register_capture(struct rkisp1_capture *cap) if (ret) { dev_err(cap->rkisp1->dev, "vb2 queue init failed (err=%d)\n", ret); - return ret; + goto error; } vdev->queue = q; + ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); + if (ret) + goto error; + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret) { dev_err(cap->rkisp1->dev, "failed to register %s, ret=%d\n", vdev->name, ret); - return ret; + goto error; } + v4l2_info(v4l2_dev, "registered %s as /dev/video%d\n", vdev->name, vdev->num); - ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); - if (ret) { - video_unregister_device(vdev); - return ret; - } - return 0; + +error: + media_entity_cleanup(&vdev->entity); + mutex_destroy(&node->vlock); + return ret; } static void @@ -1436,26 +1434,21 @@ rkisp1_capture_init(struct rkisp1_device *rkisp1, enum rkisp1_stream_id id) int rkisp1_capture_devs_register(struct rkisp1_device *rkisp1) { - struct rkisp1_capture *cap; - unsigned int i, j; + unsigned int i; int ret; for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); i++) { + struct rkisp1_capture *cap = &rkisp1->capture_devs[i]; + rkisp1_capture_init(rkisp1, i); - cap = &rkisp1->capture_devs[i]; - cap->rkisp1 = rkisp1; + ret = rkisp1_register_capture(cap); - if (ret) - goto err_unreg_capture_devs; + if (ret) { + rkisp1_capture_devs_unregister(rkisp1); + return ret; + } } return 0; -err_unreg_capture_devs: - for (j = 0; j < i; j++) { - cap = &rkisp1->capture_devs[j]; - rkisp1_unregister_capture(cap); - } - - return ret; } diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.c index cf889666e166..f956b90a407a 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.c @@ -5,10 +5,153 @@ * Copyright (C) 2019 Collabora, Ltd. */ +#include <media/mipi-csi2.h> #include <media/v4l2-rect.h> #include "rkisp1-common.h" +static const struct rkisp1_mbus_info rkisp1_formats[] = { + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + .pixel_enc = V4L2_PIXEL_ENC_YUV, + .direction = RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW10, + .bayer_pat = RKISP1_RAW_RGGB, + .bus_width = 10, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW10, + .bayer_pat = RKISP1_RAW_BGGR, + .bus_width = 10, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW10, + .bayer_pat = RKISP1_RAW_GBRG, + .bus_width = 10, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW10, + .bayer_pat = RKISP1_RAW_GRBG, + .bus_width = 10, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW12, + .bayer_pat = RKISP1_RAW_RGGB, + .bus_width = 12, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW12, + .bayer_pat = RKISP1_RAW_BGGR, + .bus_width = 12, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW12, + .bayer_pat = RKISP1_RAW_GBRG, + .bus_width = 12, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW12, + .bayer_pat = RKISP1_RAW_GRBG, + .bus_width = 12, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW8, + .bayer_pat = RKISP1_RAW_RGGB, + .bus_width = 8, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW8, + .bayer_pat = RKISP1_RAW_BGGR, + .bus_width = 8, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW8, + .bayer_pat = RKISP1_RAW_GBRG, + .bus_width = 8, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW8, + .bayer_pat = RKISP1_RAW_GRBG, + .bus_width = 8, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, + .pixel_enc = V4L2_PIXEL_ENC_YUV, + .mipi_dt = MIPI_CSI2_DT_YUV422_8B, + .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCBYCR, + .bus_width = 16, + .direction = RKISP1_ISP_SD_SINK, + }, { + .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, + .pixel_enc = V4L2_PIXEL_ENC_YUV, + .mipi_dt = MIPI_CSI2_DT_YUV422_8B, + .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCRYCB, + .bus_width = 16, + .direction = RKISP1_ISP_SD_SINK, + }, { + .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, + .pixel_enc = V4L2_PIXEL_ENC_YUV, + .mipi_dt = MIPI_CSI2_DT_YUV422_8B, + .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CBYCRY, + .bus_width = 16, + .direction = RKISP1_ISP_SD_SINK, + }, { + .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, + .pixel_enc = V4L2_PIXEL_ENC_YUV, + .mipi_dt = MIPI_CSI2_DT_YUV422_8B, + .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CRYCBY, + .bus_width = 16, + .direction = RKISP1_ISP_SD_SINK, + }, +}; + +const struct rkisp1_mbus_info *rkisp1_mbus_info_get_by_index(unsigned int index) +{ + if (index >= ARRAY_SIZE(rkisp1_formats)) + return NULL; + + return &rkisp1_formats[index]; +} + +const struct rkisp1_mbus_info *rkisp1_mbus_info_get_by_code(u32 mbus_code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(rkisp1_formats); i++) { + const struct rkisp1_mbus_info *fmt = &rkisp1_formats[i]; + + if (fmt->mbus_code == mbus_code) + return fmt; + } + + return NULL; +} + static const struct v4l2_rect rkisp1_sd_min_crop = { .width = RKISP1_ISP_MIN_WIDTH, .height = RKISP1_ISP_MIN_HEIGHT, diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index d8fa3f1a5a85..8056997d5c29 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -23,18 +23,20 @@ #include "rkisp1-regs.h" +struct dentry; + /* - * flags on the 'direction' field in struct 'rkisp1_isp_mbus_info' that indicate + * flags on the 'direction' field in struct rkisp1_mbus_info' that indicate * on which pad the media bus format is supported */ -#define RKISP1_ISP_SD_SRC BIT(0) -#define RKISP1_ISP_SD_SINK BIT(1) +#define RKISP1_ISP_SD_SRC BIT(0) +#define RKISP1_ISP_SD_SINK BIT(1) /* min and max values for the widths and heights of the entities */ -#define RKISP1_ISP_MAX_WIDTH 4032 -#define RKISP1_ISP_MAX_HEIGHT 3024 -#define RKISP1_ISP_MIN_WIDTH 32 -#define RKISP1_ISP_MIN_HEIGHT 32 +#define RKISP1_ISP_MAX_WIDTH 4032 +#define RKISP1_ISP_MAX_HEIGHT 3024 +#define RKISP1_ISP_MIN_WIDTH 32 +#define RKISP1_ISP_MIN_HEIGHT 32 #define RKISP1_RSZ_MP_SRC_MAX_WIDTH 4416 #define RKISP1_RSZ_MP_SRC_MAX_HEIGHT 3312 @@ -44,20 +46,20 @@ #define RKISP1_RSZ_SRC_MIN_HEIGHT 16 /* the default width and height of all the entities */ -#define RKISP1_DEFAULT_WIDTH 800 -#define RKISP1_DEFAULT_HEIGHT 600 +#define RKISP1_DEFAULT_WIDTH 800 +#define RKISP1_DEFAULT_HEIGHT 600 -#define RKISP1_DRIVER_NAME "rkisp1" -#define RKISP1_BUS_INFO "platform:" RKISP1_DRIVER_NAME +#define RKISP1_DRIVER_NAME "rkisp1" +#define RKISP1_BUS_INFO "platform:" RKISP1_DRIVER_NAME /* maximum number of clocks */ -#define RKISP1_MAX_BUS_CLK 8 +#define RKISP1_MAX_BUS_CLK 8 /* a bitmask of the ready stats */ -#define RKISP1_STATS_MEAS_MASK (RKISP1_CIF_ISP_AWB_DONE | \ - RKISP1_CIF_ISP_AFM_FIN | \ - RKISP1_CIF_ISP_EXP_END | \ - RKISP1_CIF_ISP_HIST_MEASURE_RDY) +#define RKISP1_STATS_MEAS_MASK (RKISP1_CIF_ISP_AWB_DONE | \ + RKISP1_CIF_ISP_AFM_FIN | \ + RKISP1_CIF_ISP_EXP_END | \ + RKISP1_CIF_ISP_HIST_MEASURE_RDY) /* enum for the resizer pads */ enum rkisp1_rsz_pad { @@ -66,6 +68,13 @@ enum rkisp1_rsz_pad { RKISP1_RSZ_PAD_MAX }; +/* enum for the csi receiver pads */ +enum rkisp1_csi_pad { + RKISP1_CSI_PAD_SINK, + RKISP1_CSI_PAD_SRC, + RKISP1_CSI_PAD_NUM +}; + /* enum for the capture id */ enum rkisp1_stream_id { RKISP1_MAINPATH, @@ -90,25 +99,89 @@ enum rkisp1_isp_pad { }; /* + * enum rkisp1_feature - ISP features + * + * @RKISP1_FEATURE_MIPI_CSI2: The ISP has an internal MIPI CSI-2 receiver + * + * The ISP features are stored in a bitmask in &rkisp1_info.features and allow + * the driver to implement support for features present in some ISP versions + * only. + */ +enum rkisp1_feature { + RKISP1_FEATURE_MIPI_CSI2 = BIT(0), +}; + +/* + * struct rkisp1_info - Model-specific ISP Information + * + * @clks: array of ISP clock names + * @clk_size: number of entries in the @clks array + * @isrs: array of ISP interrupt descriptors + * @isr_size: number of entries in the @isrs array + * @isp_ver: ISP version + * @features: bitmask of rkisp1_feature features implemented by the ISP + * + * This structure contains information about the ISP specific to a particular + * ISP model, version, or integration in a particular SoC. + */ +struct rkisp1_info { + const char * const *clks; + unsigned int clk_size; + const struct rkisp1_isr_data *isrs; + unsigned int isr_size; + enum rkisp1_cif_isp_version isp_ver; + unsigned int features; +}; + +/* * struct rkisp1_sensor_async - A container for the v4l2_async_subdev to add to the notifier * of the v4l2-async API * * @asd: async_subdev variable for the sensor + * @index: index of the sensor (counting sensor found in DT) + * @source_ep: fwnode for the sensor source endpoint * @lanes: number of lanes * @mbus_type: type of bus (currently only CSI2 is supported) * @mbus_flags: media bus (V4L2_MBUS_*) flags * @sd: a pointer to v4l2_subdev struct of the sensor * @pixel_rate_ctrl: pixel rate of the sensor, used to initialize the phy - * @dphy: a pointer to the phy + * @port: port number (0: MIPI, 1: Parallel) */ struct rkisp1_sensor_async { struct v4l2_async_subdev asd; + unsigned int index; + struct fwnode_handle *source_ep; unsigned int lanes; enum v4l2_mbus_type mbus_type; unsigned int mbus_flags; struct v4l2_subdev *sd; struct v4l2_ctrl *pixel_rate_ctrl; + unsigned int port; +}; + +/* + * struct rkisp1_csi - CSI receiver subdev + * + * @rkisp1: pointer to the rkisp1 device + * @dphy: a pointer to the phy + * @is_dphy_errctrl_disabled: if dphy errctrl is disabled (avoid endless interrupt) + * @sd: v4l2_subdev variable + * @pads: media pads + * @pad_cfg: configurations for the pads + * @sink_fmt: input format + * @lock: protects pad_cfg and sink_fmt + * @source: source in-use, set when starting streaming + */ +struct rkisp1_csi { + struct rkisp1_device *rkisp1; struct phy *dphy; + bool is_dphy_errctrl_disabled; + struct v4l2_subdev sd; + struct media_pad pads[RKISP1_CSI_PAD_NUM]; + struct v4l2_subdev_pad_config pad_cfg[RKISP1_CSI_PAD_NUM]; + const struct rkisp1_mbus_info *sink_fmt; + struct mutex lock; + struct v4l2_subdev *source; }; /* @@ -121,17 +194,16 @@ struct rkisp1_sensor_async { * @sink_fmt: input format * @src_fmt: output format * @ops_lock: ops serialization - * @is_dphy_errctrl_disabled: if dphy errctrl is disabled (avoid endless interrupt) * @frame_sequence: used to synchronize frame_id between video devices. */ struct rkisp1_isp { struct v4l2_subdev sd; + struct rkisp1_device *rkisp1; struct media_pad pads[RKISP1_ISP_PAD_MAX]; struct v4l2_subdev_pad_config pad_cfg[RKISP1_ISP_PAD_MAX]; - const struct rkisp1_isp_mbus_info *sink_fmt; - const struct rkisp1_isp_mbus_info *src_fmt; + const struct rkisp1_mbus_info *sink_fmt; + const struct rkisp1_mbus_info *src_fmt; struct mutex ops_lock; /* serialize the subdevice ops */ - bool is_dphy_errctrl_disabled; __u32 frame_sequence; }; @@ -313,6 +385,7 @@ struct rkisp1_params { * struct rkisp1_resizer - Resizer subdev * * @sd: v4l2_subdev variable + * @regs_base: base register address offset * @id: id of the resizer, one of RKISP1_SELFPATH, RKISP1_MAINPATH * @rkisp1: pointer to the rkisp1 device * @pads: media pads @@ -323,6 +396,7 @@ struct rkisp1_params { */ struct rkisp1_resizer { struct v4l2_subdev sd; + u32 regs_base; enum rkisp1_stream_id id; struct rkisp1_device *rkisp1; struct media_pad pads[RKISP1_RSZ_PAD_MAX]; @@ -373,7 +447,8 @@ struct rkisp1_debug { * @v4l2_dev: v4l2_device variable * @media_dev: media_device variable * @notifier: a notifier to register on the v4l2-async API to be notified on the sensor - * @active_sensor: sensor in-use, set when streaming on + * @source: source subdev in-use, set when starting streaming + * @csi: internal CSI-2 receiver * @isp: ISP sub-device * @resizer_devs: resizer sub-devices * @capture_devs: capture devices @@ -382,6 +457,7 @@ struct rkisp1_debug { * @pipe: media pipeline * @stream_lock: serializes {start/stop}_streaming callbacks between the capture devices. * @debug: debug params to be exposed on debugfs + * @info: version-specific ISP information */ struct rkisp1_device { void __iomem *base_addr; @@ -391,7 +467,8 @@ struct rkisp1_device { struct v4l2_device v4l2_dev; struct media_device media_dev; struct v4l2_async_notifier notifier; - struct rkisp1_sensor_async *active_sensor; + struct v4l2_subdev *source; + struct rkisp1_csi csi; struct rkisp1_isp isp; struct rkisp1_resizer resizer_devs[2]; struct rkisp1_capture capture_devs[2]; @@ -400,11 +477,12 @@ struct rkisp1_device { struct media_pipeline pipe; struct mutex stream_lock; /* serialize {start/stop}_streaming cb between capture devices */ struct rkisp1_debug debug; + const struct rkisp1_info *info; }; /* - * struct rkisp1_isp_mbus_info - ISP media bus info, Translates media bus code to hardware - * format values + * struct rkisp1_mbus_info - ISP media bus info, Translates media bus code to hardware + * format values * * @mbus_code: media bus code * @pixel_enc: pixel encoding @@ -414,7 +492,7 @@ struct rkisp1_device { * @bayer_pat: bayer pattern * @direction: a bitmask of the flags indicating on which pad the format is supported on */ -struct rkisp1_isp_mbus_info { +struct rkisp1_mbus_info { u32 mbus_code; enum v4l2_pixel_encoding pixel_enc; u32 mipi_dt; @@ -425,7 +503,7 @@ struct rkisp1_isp_mbus_info { }; static inline void -rkisp1_write(struct rkisp1_device *rkisp1, u32 val, unsigned int addr) +rkisp1_write(struct rkisp1_device *rkisp1, unsigned int addr, u32 val) { writel(val, rkisp1->base_addr + addr); } @@ -447,6 +525,13 @@ int rkisp1_cap_enum_mbus_codes(struct rkisp1_capture *cap, struct v4l2_subdev_mbus_code_enum *code); /* + * rkisp1_mbus_info_get_by_index - Retrieve the ith supported mbus info + * + * @index: index of the mbus info to fetch + */ +const struct rkisp1_mbus_info *rkisp1_mbus_info_get_by_index(unsigned int index); + +/* * rkisp1_sd_adjust_crop_rect - adjust a rectangle to fit into another rectangle. * * @crop: rectangle to adjust. @@ -465,11 +550,11 @@ void rkisp1_sd_adjust_crop(struct v4l2_rect *crop, const struct v4l2_mbus_framefmt *bounds); /* - * rkisp1_isp_mbus_info - get the isp info of the media bus code + * rkisp1_mbus_info_get_by_code - get the isp info of the media bus code * * @mbus_code: the media bus code */ -const struct rkisp1_isp_mbus_info *rkisp1_isp_mbus_info_get(u32 mbus_code); +const struct rkisp1_mbus_info *rkisp1_mbus_info_get_by_code(u32 mbus_code); /* rkisp1_params_configure - configure the params when stream starts. * This function is called by the isp entity upon stream starts. @@ -493,7 +578,7 @@ void rkisp1_params_disable(struct rkisp1_params *params); /* irq handlers */ irqreturn_t rkisp1_isp_isr(int irq, void *ctx); -irqreturn_t rkisp1_mipi_isr(int irq, void *ctx); +irqreturn_t rkisp1_csi_isr(int irq, void *ctx); irqreturn_t rkisp1_capture_isr(int irq, void *ctx); void rkisp1_stats_isr(struct rkisp1_stats *stats, u32 isp_ris); void rkisp1_params_isr(struct rkisp1_device *rkisp1); @@ -514,4 +599,16 @@ void rkisp1_stats_unregister(struct rkisp1_device *rkisp1); int rkisp1_params_register(struct rkisp1_device *rkisp1); void rkisp1_params_unregister(struct rkisp1_device *rkisp1); +#if IS_ENABLED(CONFIG_DEBUG_FS) +void rkisp1_debug_init(struct rkisp1_device *rkisp1); +void rkisp1_debug_cleanup(struct rkisp1_device *rkisp1); +#else +static inline void rkisp1_debug_init(struct rkisp1_device *rkisp1) +{ +} +static inline void rkisp1_debug_cleanup(struct rkisp1_device *rkisp1) +{ +} +#endif + #endif /* _RKISP1_COMMON_H */ diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c new file mode 100644 index 000000000000..d7acc94e10f8 --- /dev/null +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c @@ -0,0 +1,536 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - CSI-2 Receiver + * + * Copyright (C) 2019 Collabora, Ltd. + * Copyright (C) 2022 Ideas on Board + * + * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/lockdep.h> +#include <linux/phy/phy.h> +#include <linux/phy/phy-mipi-dphy.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-fwnode.h> + +#include "rkisp1-common.h" +#include "rkisp1-csi.h" + +#define RKISP1_CSI_DEV_NAME RKISP1_DRIVER_NAME "_csi" + +#define RKISP1_CSI_DEF_FMT MEDIA_BUS_FMT_SRGGB10_1X10 + +static inline struct rkisp1_csi *to_rkisp1_csi(struct v4l2_subdev *sd) +{ + return container_of(sd, struct rkisp1_csi, sd); +} + +static struct v4l2_mbus_framefmt * +rkisp1_csi_get_pad_fmt(struct rkisp1_csi *csi, + struct v4l2_subdev_state *sd_state, + unsigned int pad, u32 which) +{ + struct v4l2_subdev_state state = { + .pads = csi->pad_cfg + }; + + lockdep_assert_held(&csi->lock); + + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&csi->sd, sd_state, pad); + else + return v4l2_subdev_get_try_format(&csi->sd, &state, pad); +} + +int rkisp1_csi_link_sensor(struct rkisp1_device *rkisp1, struct v4l2_subdev *sd, + struct rkisp1_sensor_async *s_asd, + unsigned int source_pad) +{ + struct rkisp1_csi *csi = &rkisp1->csi; + int ret; + + s_asd->pixel_rate_ctrl = v4l2_ctrl_find(sd->ctrl_handler, + V4L2_CID_PIXEL_RATE); + if (!s_asd->pixel_rate_ctrl) { + dev_err(rkisp1->dev, "No pixel rate control in subdev %s\n", + sd->name); + return -EINVAL; + } + + /* Create the link from the sensor to the CSI receiver. */ + ret = media_create_pad_link(&sd->entity, source_pad, + &csi->sd.entity, RKISP1_CSI_PAD_SINK, + !s_asd->index ? MEDIA_LNK_FL_ENABLED : 0); + if (ret) { + dev_err(csi->rkisp1->dev, "failed to link src pad of %s\n", + sd->name); + return ret; + } + + return 0; +} + +static int rkisp1_csi_config(struct rkisp1_csi *csi, + const struct rkisp1_sensor_async *sensor) +{ + struct rkisp1_device *rkisp1 = csi->rkisp1; + unsigned int lanes = sensor->lanes; + u32 mipi_ctrl; + + if (lanes < 1 || lanes > 4) + return -EINVAL; + + mipi_ctrl = RKISP1_CIF_MIPI_CTRL_NUM_LANES(lanes - 1) | + RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(0xf) | + RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP | + RKISP1_CIF_MIPI_CTRL_CLOCKLANE_ENA; + + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_CTRL, mipi_ctrl); + + /* V12 could also use a newer csi2-host, but we don't want that yet */ + if (rkisp1->info->isp_ver == RKISP1_V12) + rkisp1_write(rkisp1, RKISP1_CIF_ISP_CSI0_CTRL0, 0); + + /* Configure Data Type and Virtual Channel */ + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL, + RKISP1_CIF_MIPI_DATA_SEL_DT(csi->sink_fmt->mipi_dt) | + RKISP1_CIF_MIPI_DATA_SEL_VC(0)); + + /* Clear MIPI interrupts */ + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_ICR, ~0); + + /* + * Disable RKISP1_CIF_MIPI_ERR_DPHY interrupt here temporary for + * isp bus may be dead when switch isp. + */ + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC, + RKISP1_CIF_MIPI_FRAME_END | RKISP1_CIF_MIPI_ERR_CSI | + RKISP1_CIF_MIPI_ERR_DPHY | + RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(0x03) | + RKISP1_CIF_MIPI_ADD_DATA_OVFLW); + + dev_dbg(rkisp1->dev, "\n MIPI_CTRL 0x%08x\n" + " MIPI_IMG_DATA_SEL 0x%08x\n" + " MIPI_STATUS 0x%08x\n" + " MIPI_IMSC 0x%08x\n", + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL), + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL), + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_STATUS), + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC)); + + return 0; +} + +static void rkisp1_csi_enable(struct rkisp1_csi *csi) +{ + struct rkisp1_device *rkisp1 = csi->rkisp1; + u32 val; + + val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_CTRL, + val | RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA); +} + +static void rkisp1_csi_disable(struct rkisp1_csi *csi) +{ + struct rkisp1_device *rkisp1 = csi->rkisp1; + u32 val; + + /* Mask and clear interrupts. */ + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC, 0); + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_ICR, ~0); + + val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_CTRL, + val & (~RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA)); +} + +static int rkisp1_csi_start(struct rkisp1_csi *csi, + const struct rkisp1_sensor_async *sensor) +{ + struct rkisp1_device *rkisp1 = csi->rkisp1; + union phy_configure_opts opts; + struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy; + s64 pixel_clock; + int ret; + + ret = rkisp1_csi_config(csi, sensor); + if (ret) + return ret; + + pixel_clock = v4l2_ctrl_g_ctrl_int64(sensor->pixel_rate_ctrl); + if (!pixel_clock) { + dev_err(rkisp1->dev, "Invalid pixel rate value\n"); + return -EINVAL; + } + + phy_mipi_dphy_get_default_config(pixel_clock, csi->sink_fmt->bus_width, + sensor->lanes, cfg); + phy_set_mode(csi->dphy, PHY_MODE_MIPI_DPHY); + phy_configure(csi->dphy, &opts); + phy_power_on(csi->dphy); + + rkisp1_csi_enable(csi); + + /* + * CIF spec says to wait for sufficient time after enabling + * the MIPI interface and before starting the sensor output. + */ + usleep_range(1000, 1200); + + return 0; +} + +static void rkisp1_csi_stop(struct rkisp1_csi *csi) +{ + rkisp1_csi_disable(csi); + + phy_power_off(csi->dphy); +} + +irqreturn_t rkisp1_csi_isr(int irq, void *ctx) +{ + struct device *dev = ctx; + struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); + u32 val, status; + + status = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_MIS); + if (!status) + return IRQ_NONE; + + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_ICR, status); + + /* + * Disable DPHY errctrl interrupt, because this dphy + * erctrl signal is asserted until the next changes + * of line state. This time is may be too long and cpu + * is hold in this interrupt. + */ + if (status & RKISP1_CIF_MIPI_ERR_CTRL(0x0f)) { + val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC); + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC, + val & ~RKISP1_CIF_MIPI_ERR_CTRL(0x0f)); + rkisp1->csi.is_dphy_errctrl_disabled = true; + } + + /* + * Enable DPHY errctrl interrupt again, if mipi have receive + * the whole frame without any error. + */ + if (status == RKISP1_CIF_MIPI_FRAME_END) { + /* + * Enable DPHY errctrl interrupt again, if mipi have receive + * the whole frame without any error. + */ + if (rkisp1->csi.is_dphy_errctrl_disabled) { + val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC); + val |= RKISP1_CIF_MIPI_ERR_CTRL(0x0f); + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC, val); + rkisp1->csi.is_dphy_errctrl_disabled = false; + } + } else { + rkisp1->debug.mipi_error++; + } + + return IRQ_HANDLED; +} + +/* ---------------------------------------------------------------------------- + * Subdev pad operations + */ + +static int rkisp1_csi_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct rkisp1_csi *csi = to_rkisp1_csi(sd); + unsigned int i; + int pos = 0; + + if (code->pad == RKISP1_CSI_PAD_SRC) { + const struct v4l2_mbus_framefmt *sink_fmt; + + if (code->index) + return -EINVAL; + + mutex_lock(&csi->lock); + + sink_fmt = rkisp1_csi_get_pad_fmt(csi, sd_state, + RKISP1_CSI_PAD_SINK, + code->which); + code->code = sink_fmt->code; + + mutex_unlock(&csi->lock); + + return 0; + } + + for (i = 0; ; i++) { + const struct rkisp1_mbus_info *fmt = + rkisp1_mbus_info_get_by_index(i); + + if (!fmt) + return -EINVAL; + + if (!(fmt->direction & RKISP1_ISP_SD_SINK)) + continue; + + if (code->index == pos) { + code->code = fmt->mbus_code; + return 0; + } + + pos++; + } + + return -EINVAL; +} + +static int rkisp1_csi_init_config(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; + + sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, + RKISP1_CSI_PAD_SINK); + src_fmt = v4l2_subdev_get_try_format(sd, sd_state, + RKISP1_CSI_PAD_SRC); + + sink_fmt->width = RKISP1_DEFAULT_WIDTH; + sink_fmt->height = RKISP1_DEFAULT_HEIGHT; + sink_fmt->field = V4L2_FIELD_NONE; + sink_fmt->code = RKISP1_CSI_DEF_FMT; + + *src_fmt = *sink_fmt; + + return 0; +} + +static int rkisp1_csi_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct rkisp1_csi *csi = to_rkisp1_csi(sd); + + mutex_lock(&csi->lock); + fmt->format = *rkisp1_csi_get_pad_fmt(csi, sd_state, fmt->pad, + fmt->which); + mutex_unlock(&csi->lock); + + return 0; +} + +static int rkisp1_csi_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct rkisp1_csi *csi = to_rkisp1_csi(sd); + const struct rkisp1_mbus_info *mbus_info; + struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; + + /* The format on the source pad always matches the sink pad. */ + if (fmt->pad == RKISP1_CSI_PAD_SRC) + return rkisp1_csi_get_fmt(sd, sd_state, fmt); + + mutex_lock(&csi->lock); + + sink_fmt = rkisp1_csi_get_pad_fmt(csi, sd_state, RKISP1_CSI_PAD_SINK, + fmt->which); + + sink_fmt->code = fmt->format.code; + + mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); + if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SINK)) { + sink_fmt->code = RKISP1_CSI_DEF_FMT; + mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); + } + + sink_fmt->width = clamp_t(u32, fmt->format.width, + RKISP1_ISP_MIN_WIDTH, + RKISP1_ISP_MAX_WIDTH); + sink_fmt->height = clamp_t(u32, fmt->format.height, + RKISP1_ISP_MIN_HEIGHT, + RKISP1_ISP_MAX_HEIGHT); + + fmt->format = *sink_fmt; + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) + csi->sink_fmt = mbus_info; + + /* Propagate the format to the source pad. */ + src_fmt = rkisp1_csi_get_pad_fmt(csi, sd_state, RKISP1_CSI_PAD_SRC, + fmt->which); + *src_fmt = *sink_fmt; + + mutex_unlock(&csi->lock); + + return 0; +} + +/* ---------------------------------------------------------------------------- + * Subdev video operations + */ + +static int rkisp1_csi_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct rkisp1_csi *csi = to_rkisp1_csi(sd); + struct rkisp1_device *rkisp1 = csi->rkisp1; + struct rkisp1_sensor_async *source_asd; + struct media_pad *source_pad; + struct v4l2_subdev *source; + int ret; + + if (!enable) { + v4l2_subdev_call(csi->source, video, s_stream, false); + + rkisp1_csi_stop(csi); + + return 0; + } + + source_pad = media_entity_remote_source_pad_unique(&sd->entity); + if (IS_ERR(source_pad)) { + dev_dbg(rkisp1->dev, "Failed to get source for CSI: %ld\n", + PTR_ERR(source_pad)); + return -EPIPE; + } + + source = media_entity_to_v4l2_subdev(source_pad->entity); + if (!source) { + /* This should really not happen, so is not worth a message. */ + return -EPIPE; + } + + source_asd = container_of(source->asd, struct rkisp1_sensor_async, asd); + if (source_asd->mbus_type != V4L2_MBUS_CSI2_DPHY) + return -EINVAL; + + mutex_lock(&csi->lock); + ret = rkisp1_csi_start(csi, source_asd); + mutex_unlock(&csi->lock); + if (ret) + return ret; + + ret = v4l2_subdev_call(source, video, s_stream, true); + if (ret) { + rkisp1_csi_stop(csi); + return ret; + } + + csi->source = source; + + return 0; +} + +/* ---------------------------------------------------------------------------- + * Registration + */ + +static const struct media_entity_operations rkisp1_csi_media_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct v4l2_subdev_video_ops rkisp1_csi_video_ops = { + .s_stream = rkisp1_csi_s_stream, +}; + +static const struct v4l2_subdev_pad_ops rkisp1_csi_pad_ops = { + .enum_mbus_code = rkisp1_csi_enum_mbus_code, + .init_cfg = rkisp1_csi_init_config, + .get_fmt = rkisp1_csi_get_fmt, + .set_fmt = rkisp1_csi_set_fmt, +}; + +static const struct v4l2_subdev_ops rkisp1_csi_ops = { + .video = &rkisp1_csi_video_ops, + .pad = &rkisp1_csi_pad_ops, +}; + +int rkisp1_csi_register(struct rkisp1_device *rkisp1) +{ + struct rkisp1_csi *csi = &rkisp1->csi; + struct v4l2_subdev_state state = {}; + struct media_pad *pads; + struct v4l2_subdev *sd; + int ret; + + csi->rkisp1 = rkisp1; + mutex_init(&csi->lock); + + sd = &csi->sd; + v4l2_subdev_init(sd, &rkisp1_csi_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->entity.ops = &rkisp1_csi_media_ops; + sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + sd->owner = THIS_MODULE; + strscpy(sd->name, RKISP1_CSI_DEV_NAME, sizeof(sd->name)); + + pads = csi->pads; + pads[RKISP1_CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK | + MEDIA_PAD_FL_MUST_CONNECT; + pads[RKISP1_CSI_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE | + MEDIA_PAD_FL_MUST_CONNECT; + + csi->sink_fmt = rkisp1_mbus_info_get_by_code(RKISP1_CSI_DEF_FMT); + + ret = media_entity_pads_init(&sd->entity, RKISP1_CSI_PAD_NUM, pads); + if (ret) + goto error; + + state.pads = csi->pad_cfg; + rkisp1_csi_init_config(sd, &state); + + ret = v4l2_device_register_subdev(&csi->rkisp1->v4l2_dev, sd); + if (ret) { + dev_err(sd->dev, "Failed to register csi receiver subdev\n"); + goto error; + } + + return 0; + +error: + media_entity_cleanup(&sd->entity); + mutex_destroy(&csi->lock); + csi->rkisp1 = NULL; + return ret; +} + +void rkisp1_csi_unregister(struct rkisp1_device *rkisp1) +{ + struct rkisp1_csi *csi = &rkisp1->csi; + + if (!csi->rkisp1) + return; + + v4l2_device_unregister_subdev(&csi->sd); + media_entity_cleanup(&csi->sd.entity); + mutex_destroy(&csi->lock); +} + +int rkisp1_csi_init(struct rkisp1_device *rkisp1) +{ + struct rkisp1_csi *csi = &rkisp1->csi; + + csi->rkisp1 = rkisp1; + + csi->dphy = devm_phy_get(rkisp1->dev, "dphy"); + if (IS_ERR(csi->dphy)) + return dev_err_probe(rkisp1->dev, PTR_ERR(csi->dphy), + "Couldn't get the MIPI D-PHY\n"); + + phy_init(csi->dphy); + + return 0; +} + +void rkisp1_csi_cleanup(struct rkisp1_device *rkisp1) +{ + struct rkisp1_csi *csi = &rkisp1->csi; + + phy_exit(csi->dphy); +} diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.h new file mode 100644 index 000000000000..1f5f2af31a7d --- /dev/null +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* + * Rockchip ISP1 Driver - CSI-2 Receiver + * + * Copyright (C) 2019 Collabora, Ltd. + * Copyright (C) 2022 Ideas on Board + * + * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ +#ifndef _RKISP1_CSI_H +#define _RKISP1_CSI_H + +struct rkisp1_csi; +struct rkisp1_device; +struct rkisp1_sensor_async; + +int rkisp1_csi_init(struct rkisp1_device *rkisp1); +void rkisp1_csi_cleanup(struct rkisp1_device *rkisp1); + +int rkisp1_csi_register(struct rkisp1_device *rkisp1); +void rkisp1_csi_unregister(struct rkisp1_device *rkisp1); + +int rkisp1_csi_link_sensor(struct rkisp1_device *rkisp1, struct v4l2_subdev *sd, + struct rkisp1_sensor_async *s_asd, + unsigned int source_pad); + +#endif /* _RKISP1_CSI_H */ diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c new file mode 100644 index 000000000000..71df3dc95e6f --- /dev/null +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - Base driver + * + * Copyright (C) 2019 Collabora, Ltd. + * + * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/minmax.h> +#include <linux/pm_runtime.h> +#include <linux/seq_file.h> +#include <linux/string.h> + +#include "rkisp1-common.h" +#include "rkisp1-regs.h" + +struct rkisp1_debug_register { + u32 reg; + u32 shd; + const char * const name; +}; + +#define RKISP1_DEBUG_REG(name) { RKISP1_CIF_##name, 0, #name } +#define RKISP1_DEBUG_SHD_REG(name) { \ + RKISP1_CIF_##name, RKISP1_CIF_##name##_SHD, #name \ +} + +/* Keep this up-to-date when adding new registers. */ +#define RKISP1_MAX_REG_LENGTH 21 + +static int rkisp1_debug_dump_regs(struct rkisp1_device *rkisp1, + struct seq_file *m, unsigned int offset, + const struct rkisp1_debug_register *regs) +{ + const int width = RKISP1_MAX_REG_LENGTH; + u32 val, shd; + int ret; + + ret = pm_runtime_get_if_in_use(rkisp1->dev); + if (ret <= 0) + return ret ? : -ENODATA; + + for (; regs->name; ++regs) { + val = rkisp1_read(rkisp1, offset + regs->reg); + + if (regs->shd) { + shd = rkisp1_read(rkisp1, offset + regs->shd); + seq_printf(m, "%*s: 0x%08x/0x%08x\n", width, regs->name, + val, shd); + } else { + seq_printf(m, "%*s: 0x%08x\n", width, regs->name, val); + } + } + + pm_runtime_put(rkisp1->dev); + + return 0; +} + +static int rkisp1_debug_dump_core_regs_show(struct seq_file *m, void *p) +{ + static const struct rkisp1_debug_register registers[] = { + RKISP1_DEBUG_REG(VI_CCL), + RKISP1_DEBUG_REG(VI_ICCL), + RKISP1_DEBUG_REG(VI_IRCL), + RKISP1_DEBUG_REG(VI_DPCL), + RKISP1_DEBUG_REG(MI_CTRL), + RKISP1_DEBUG_REG(MI_BYTE_CNT), + RKISP1_DEBUG_REG(MI_CTRL_SHD), + RKISP1_DEBUG_REG(MI_RIS), + RKISP1_DEBUG_REG(MI_STATUS), + RKISP1_DEBUG_REG(MI_DMA_CTRL), + RKISP1_DEBUG_REG(MI_DMA_STATUS), + { /* Sentinel */ }, + }; + struct rkisp1_device *rkisp1 = m->private; + + return rkisp1_debug_dump_regs(rkisp1, m, 0, registers); +} +DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_core_regs); + +static int rkisp1_debug_dump_isp_regs_show(struct seq_file *m, void *p) +{ + static const struct rkisp1_debug_register registers[] = { + RKISP1_DEBUG_REG(ISP_CTRL), + RKISP1_DEBUG_REG(ISP_ACQ_PROP), + RKISP1_DEBUG_REG(ISP_FLAGS_SHD), + RKISP1_DEBUG_REG(ISP_RIS), + RKISP1_DEBUG_REG(ISP_ERR), + { /* Sentinel */ }, + }; + struct rkisp1_device *rkisp1 = m->private; + + return rkisp1_debug_dump_regs(rkisp1, m, 0, registers); +} +DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_isp_regs); + +static int rkisp1_debug_dump_rsz_regs_show(struct seq_file *m, void *p) +{ + static const struct rkisp1_debug_register registers[] = { + RKISP1_DEBUG_SHD_REG(RSZ_CTRL), + RKISP1_DEBUG_SHD_REG(RSZ_SCALE_HY), + RKISP1_DEBUG_SHD_REG(RSZ_SCALE_HCB), + RKISP1_DEBUG_SHD_REG(RSZ_SCALE_HCR), + RKISP1_DEBUG_SHD_REG(RSZ_SCALE_VY), + RKISP1_DEBUG_SHD_REG(RSZ_SCALE_VC), + RKISP1_DEBUG_SHD_REG(RSZ_PHASE_HY), + RKISP1_DEBUG_SHD_REG(RSZ_PHASE_HC), + RKISP1_DEBUG_SHD_REG(RSZ_PHASE_VY), + RKISP1_DEBUG_SHD_REG(RSZ_PHASE_VC), + { /* Sentinel */ }, + }; + struct rkisp1_resizer *rsz = m->private; + + return rkisp1_debug_dump_regs(rsz->rkisp1, m, rsz->regs_base, registers); +} +DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_rsz_regs); + +static int rkisp1_debug_dump_mi_mp_show(struct seq_file *m, void *p) +{ + static const struct rkisp1_debug_register registers[] = { + RKISP1_DEBUG_REG(MI_MP_Y_BASE_AD_INIT), + RKISP1_DEBUG_REG(MI_MP_Y_BASE_AD_INIT2), + RKISP1_DEBUG_REG(MI_MP_Y_BASE_AD_SHD), + RKISP1_DEBUG_REG(MI_MP_Y_SIZE_INIT), + RKISP1_DEBUG_REG(MI_MP_Y_SIZE_INIT), + RKISP1_DEBUG_REG(MI_MP_Y_SIZE_SHD), + RKISP1_DEBUG_REG(MI_MP_Y_OFFS_CNT_SHD), + { /* Sentinel */ }, + }; + struct rkisp1_device *rkisp1 = m->private; + + return rkisp1_debug_dump_regs(rkisp1, m, 0, registers); +} +DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_mi_mp); + +#define RKISP1_DEBUG_DATA_COUNT_BINS 32 +#define RKISP1_DEBUG_DATA_COUNT_STEP (4096 / RKISP1_DEBUG_DATA_COUNT_BINS) + +static int rkisp1_debug_input_status_show(struct seq_file *m, void *p) +{ + struct rkisp1_device *rkisp1 = m->private; + u16 data_count[RKISP1_DEBUG_DATA_COUNT_BINS] = { }; + unsigned int hsync_count = 0; + unsigned int vsync_count = 0; + unsigned int i; + u32 data; + u32 val; + int ret; + + ret = pm_runtime_get_if_in_use(rkisp1->dev); + if (ret <= 0) + return ret ? : -ENODATA; + + /* Sample the ISP input port status 10000 times with a 1µs interval. */ + for (i = 0; i < 10000; ++i) { + val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_FLAGS_SHD); + + data = (val & RKISP1_CIF_ISP_FLAGS_SHD_S_DATA_MASK) + >> RKISP1_CIF_ISP_FLAGS_SHD_S_DATA_SHIFT; + data_count[data / RKISP1_DEBUG_DATA_COUNT_STEP]++; + + if (val & RKISP1_CIF_ISP_FLAGS_SHD_S_HSYNC) + hsync_count++; + if (val & RKISP1_CIF_ISP_FLAGS_SHD_S_VSYNC) + vsync_count++; + + udelay(1); + } + + pm_runtime_put(rkisp1->dev); + + seq_printf(m, "vsync: %u, hsync: %u\n", vsync_count, hsync_count); + seq_puts(m, "data:\n"); + for (i = 0; i < ARRAY_SIZE(data_count); ++i) + seq_printf(m, "- [%04u:%04u]: %u\n", + i * RKISP1_DEBUG_DATA_COUNT_STEP, + (i + 1) * RKISP1_DEBUG_DATA_COUNT_STEP - 1, + data_count[i]); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_input_status); + +void rkisp1_debug_init(struct rkisp1_device *rkisp1) +{ + struct rkisp1_debug *debug = &rkisp1->debug; + struct dentry *regs_dir; + + debug->debugfs_dir = debugfs_create_dir(dev_name(rkisp1->dev), NULL); + + debugfs_create_ulong("data_loss", 0444, debug->debugfs_dir, + &debug->data_loss); + debugfs_create_ulong("outform_size_err", 0444, debug->debugfs_dir, + &debug->outform_size_error); + debugfs_create_ulong("img_stabilization_size_error", 0444, + debug->debugfs_dir, + &debug->img_stabilization_size_error); + debugfs_create_ulong("inform_size_error", 0444, debug->debugfs_dir, + &debug->inform_size_error); + debugfs_create_ulong("irq_delay", 0444, debug->debugfs_dir, + &debug->irq_delay); + debugfs_create_ulong("mipi_error", 0444, debug->debugfs_dir, + &debug->mipi_error); + debugfs_create_ulong("stats_error", 0444, debug->debugfs_dir, + &debug->stats_error); + debugfs_create_ulong("mp_stop_timeout", 0444, debug->debugfs_dir, + &debug->stop_timeout[RKISP1_MAINPATH]); + debugfs_create_ulong("sp_stop_timeout", 0444, debug->debugfs_dir, + &debug->stop_timeout[RKISP1_SELFPATH]); + debugfs_create_ulong("mp_frame_drop", 0444, debug->debugfs_dir, + &debug->frame_drop[RKISP1_MAINPATH]); + debugfs_create_ulong("sp_frame_drop", 0444, debug->debugfs_dir, + &debug->frame_drop[RKISP1_SELFPATH]); + debugfs_create_file("input_status", 0444, debug->debugfs_dir, rkisp1, + &rkisp1_debug_input_status_fops); + + regs_dir = debugfs_create_dir("regs", debug->debugfs_dir); + + debugfs_create_file("core", 0444, regs_dir, rkisp1, + &rkisp1_debug_dump_core_regs_fops); + debugfs_create_file("isp", 0444, regs_dir, rkisp1, + &rkisp1_debug_dump_isp_regs_fops); + debugfs_create_file("mrsz", 0444, regs_dir, + &rkisp1->resizer_devs[RKISP1_MAINPATH], + &rkisp1_debug_dump_rsz_regs_fops); + debugfs_create_file("srsz", 0444, regs_dir, + &rkisp1->resizer_devs[RKISP1_SELFPATH], + &rkisp1_debug_dump_rsz_regs_fops); + + debugfs_create_file("mi_mp", 0444, regs_dir, rkisp1, + &rkisp1_debug_dump_mi_mp_fops); +} + +void rkisp1_debug_cleanup(struct rkisp1_device *rkisp1) +{ + debugfs_remove_recursive(rkisp1->debug.debugfs_dir); +} diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index 3f5cfa7eb937..f2475c6235ea 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -9,18 +9,18 @@ */ #include <linux/clk.h> -#include <linux/debugfs.h> #include <linux/interrupt.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_graph.h> #include <linux/of_platform.h> #include <linux/pinctrl/consumer.h> -#include <linux/phy/phy.h> -#include <linux/phy/phy-mipi-dphy.h> +#include <linux/pm_runtime.h> #include <media/v4l2-fwnode.h> +#include <media/v4l2-mc.h> #include "rkisp1-common.h" +#include "rkisp1-csi.h" /* * ISP Details @@ -68,18 +68,28 @@ * * Media Topology * -------------- - * +----------+ +----------+ - * | Sensor 2 | | Sensor X | - * ------------ ... ------------ - * | 0 | | 0 | - * +----------+ +----------+ +-----------+ - * \ | | params | - * \ | | (output) | - * +----------+ \ | +-----------+ - * | Sensor 1 | v v | - * ------------ +------+------+ | - * | 0 |----->| 0 | 1 |<---------+ - * +----------+ |------+------| + * + * +----------+ +----------+ + * | Sensor 1 | | Sensor X | + * ------------ ... ------------ + * | 0 | | 0 | + * +----------+ +----------+ + * | | + * \----\ /----/ + * | | + * v v + * +-------------+ + * | 0 | + * --------------- + * | CSI-2 RX | + * --------------- +-----------+ + * | 1 | | params | + * +-------------+ | (output) | + * | +-----------+ + * v | + * +------+------+ | + * | 0 | 1 |<---------+ + * |------+------| * | ISP | * |------+------| * +-------------| 2 | 3 |----------+ @@ -106,88 +116,10 @@ struct rkisp1_isr_data { irqreturn_t (*isr)(int irq, void *ctx); }; -struct rkisp1_match_data { - const char * const *clks; - unsigned int clk_size; - const struct rkisp1_isr_data *isrs; - unsigned int isr_size; - enum rkisp1_cif_isp_version isp_ver; -}; - /* ---------------------------------------------------------------------------- * Sensor DT bindings */ -static int rkisp1_create_links(struct rkisp1_device *rkisp1) -{ - struct media_entity *source, *sink; - unsigned int flags, source_pad; - struct v4l2_subdev *sd; - unsigned int i; - int ret; - - /* sensor links */ - flags = MEDIA_LNK_FL_ENABLED; - list_for_each_entry(sd, &rkisp1->v4l2_dev.subdevs, list) { - if (sd == &rkisp1->isp.sd || - sd == &rkisp1->resizer_devs[RKISP1_MAINPATH].sd || - sd == &rkisp1->resizer_devs[RKISP1_SELFPATH].sd) - continue; - - ret = media_entity_get_fwnode_pad(&sd->entity, sd->fwnode, - MEDIA_PAD_FL_SOURCE); - if (ret < 0) { - dev_err(rkisp1->dev, "failed to find src pad for %s\n", - sd->name); - return ret; - } - source_pad = ret; - - ret = media_create_pad_link(&sd->entity, source_pad, - &rkisp1->isp.sd.entity, - RKISP1_ISP_PAD_SINK_VIDEO, - flags); - if (ret) - return ret; - - flags = 0; - } - - flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE; - - /* create ISP->RSZ->CAP links */ - for (i = 0; i < 2; i++) { - source = &rkisp1->isp.sd.entity; - sink = &rkisp1->resizer_devs[i].sd.entity; - ret = media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_VIDEO, - sink, RKISP1_RSZ_PAD_SINK, - MEDIA_LNK_FL_ENABLED); - if (ret) - return ret; - - source = sink; - sink = &rkisp1->capture_devs[i].vnode.vdev.entity; - ret = media_create_pad_link(source, RKISP1_RSZ_PAD_SRC, - sink, 0, flags); - if (ret) - return ret; - } - - /* params links */ - source = &rkisp1->params.vnode.vdev.entity; - sink = &rkisp1->isp.sd.entity; - ret = media_create_pad_link(source, 0, sink, - RKISP1_ISP_PAD_SINK_PARAMS, flags); - if (ret) - return ret; - - /* 3A stats links */ - source = &rkisp1->isp.sd.entity; - sink = &rkisp1->stats.vnode.vdev.entity; - return media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_STATS, - sink, 0, flags); -} - static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) @@ -196,116 +128,171 @@ static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier, container_of(notifier, struct rkisp1_device, notifier); struct rkisp1_sensor_async *s_asd = container_of(asd, struct rkisp1_sensor_async, asd); + int source_pad; + int ret; - s_asd->pixel_rate_ctrl = v4l2_ctrl_find(sd->ctrl_handler, - V4L2_CID_PIXEL_RATE); s_asd->sd = sd; - s_asd->dphy = devm_phy_get(rkisp1->dev, "dphy"); - if (IS_ERR(s_asd->dphy)) { - if (PTR_ERR(s_asd->dphy) != -EPROBE_DEFER) - dev_err(rkisp1->dev, "Couldn't get the MIPI D-PHY\n"); - return PTR_ERR(s_asd->dphy); + + source_pad = media_entity_get_fwnode_pad(&sd->entity, s_asd->source_ep, + MEDIA_PAD_FL_SOURCE); + if (source_pad < 0) { + dev_err(rkisp1->dev, "failed to find source pad for %s\n", + sd->name); + return source_pad; } - phy_init(s_asd->dphy); + if (s_asd->port == 0) + return rkisp1_csi_link_sensor(rkisp1, sd, s_asd, source_pad); - return 0; -} - -static void rkisp1_subdev_notifier_unbind(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *sd, - struct v4l2_async_subdev *asd) -{ - struct rkisp1_sensor_async *s_asd = - container_of(asd, struct rkisp1_sensor_async, asd); + ret = media_create_pad_link(&sd->entity, source_pad, + &rkisp1->isp.sd.entity, + RKISP1_ISP_PAD_SINK_VIDEO, + !s_asd->index ? MEDIA_LNK_FL_ENABLED : 0); + if (ret) { + dev_err(rkisp1->dev, "failed to link source pad of %s\n", + sd->name); + return ret; + } - phy_exit(s_asd->dphy); + return 0; } static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier) { struct rkisp1_device *rkisp1 = container_of(notifier, struct rkisp1_device, notifier); - int ret; - ret = rkisp1_create_links(rkisp1); - if (ret) - return ret; - - ret = v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev); - if (ret) - return ret; + return v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev); +} - dev_dbg(rkisp1->dev, "Async subdev notifier completed\n"); +static void rkisp1_subdev_notifier_destroy(struct v4l2_async_subdev *asd) +{ + struct rkisp1_sensor_async *rk_asd = + container_of(asd, struct rkisp1_sensor_async, asd); - return 0; + fwnode_handle_put(rk_asd->source_ep); } static const struct v4l2_async_notifier_operations rkisp1_subdev_notifier_ops = { .bound = rkisp1_subdev_notifier_bound, - .unbind = rkisp1_subdev_notifier_unbind, .complete = rkisp1_subdev_notifier_complete, + .destroy = rkisp1_subdev_notifier_destroy, }; -static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1) +static int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1) { struct v4l2_async_notifier *ntf = &rkisp1->notifier; - unsigned int next_id = 0; - int ret; + struct fwnode_handle *fwnode = dev_fwnode(rkisp1->dev); + struct fwnode_handle *ep; + unsigned int index = 0; + int ret = 0; v4l2_async_nf_init(ntf); - while (1) { - struct v4l2_fwnode_endpoint vep = { - .bus_type = V4L2_MBUS_CSI2_DPHY - }; + ntf->ops = &rkisp1_subdev_notifier_ops; + + fwnode_graph_for_each_endpoint(fwnode, ep) { + struct fwnode_handle *port; + struct v4l2_fwnode_endpoint vep = { }; struct rkisp1_sensor_async *rk_asd; - struct fwnode_handle *ep; + struct fwnode_handle *source; + u32 reg = 0; + + /* Select the bus type based on the port. */ + port = fwnode_get_parent(ep); + fwnode_property_read_u32(port, "reg", ®); + fwnode_handle_put(port); + + switch (reg) { + case 0: + /* MIPI CSI-2 port */ + if (!(rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2)) { + dev_err(rkisp1->dev, + "internal CSI must be available for port 0\n"); + ret = -EINVAL; + break; + } + + vep.bus_type = V4L2_MBUS_CSI2_DPHY; + break; - ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(rkisp1->dev), - 0, next_id, - FWNODE_GRAPH_ENDPOINT_NEXT); - if (!ep) + case 1: + /* + * Parallel port. The bus-type property in DT is + * mandatory for port 1, it will be used to determine if + * it's PARALLEL or BT656. + */ + vep.bus_type = V4L2_MBUS_UNKNOWN; break; + } + /* Parse the endpoint and validate the bus type. */ ret = v4l2_fwnode_endpoint_parse(ep, &vep); - if (ret) - goto err_parse; + if (ret) { + dev_err(rkisp1->dev, "failed to parse endpoint %pfw\n", + ep); + break; + } - rk_asd = v4l2_async_nf_add_fwnode_remote(ntf, ep, - struct - rkisp1_sensor_async); + if (vep.base.port == 1) { + if (vep.bus_type != V4L2_MBUS_PARALLEL && + vep.bus_type != V4L2_MBUS_BT656) { + dev_err(rkisp1->dev, + "port 1 must be parallel or BT656\n"); + ret = -EINVAL; + break; + } + } + + /* Add the async subdev to the notifier. */ + source = fwnode_graph_get_remote_endpoint(ep); + if (!source) { + dev_err(rkisp1->dev, + "endpoint %pfw has no remote endpoint\n", + ep); + ret = -ENODEV; + break; + } + + rk_asd = v4l2_async_nf_add_fwnode(ntf, source, + struct rkisp1_sensor_async); if (IS_ERR(rk_asd)) { + fwnode_handle_put(source); ret = PTR_ERR(rk_asd); - goto err_parse; + break; } + rk_asd->index = index++; + rk_asd->source_ep = source; rk_asd->mbus_type = vep.bus_type; - rk_asd->mbus_flags = vep.bus.mipi_csi2.flags; - rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes; - - dev_dbg(rkisp1->dev, "registered ep id %d with %d lanes\n", - vep.base.id, rk_asd->lanes); + rk_asd->port = vep.base.port; - next_id = vep.base.id + 1; + if (vep.bus_type == V4L2_MBUS_CSI2_DPHY) { + rk_asd->mbus_flags = vep.bus.mipi_csi2.flags; + rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes; + } else { + rk_asd->mbus_flags = vep.bus.parallel.flags; + } - fwnode_handle_put(ep); + dev_dbg(rkisp1->dev, "registered ep id %d, bus type %u, %u lanes\n", + vep.base.id, rk_asd->mbus_type, rk_asd->lanes); + } - continue; -err_parse: + if (ret) { fwnode_handle_put(ep); v4l2_async_nf_cleanup(ntf); return ret; } - if (next_id == 0) + if (!index) dev_dbg(rkisp1->dev, "no remote subdevice found\n"); - ntf->ops = &rkisp1_subdev_notifier_ops; + ret = v4l2_async_nf_register(&rkisp1->v4l2_dev, ntf); if (ret) { v4l2_async_nf_cleanup(ntf); return ret; } + return 0; } @@ -346,48 +333,110 @@ static const struct dev_pm_ops rkisp1_pm_ops = { * Core */ +static int rkisp1_create_links(struct rkisp1_device *rkisp1) +{ + unsigned int i; + int ret; + + if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) { + /* Link the CSI receiver to the ISP. */ + ret = media_create_pad_link(&rkisp1->csi.sd.entity, + RKISP1_CSI_PAD_SRC, + &rkisp1->isp.sd.entity, + RKISP1_ISP_PAD_SINK_VIDEO, + MEDIA_LNK_FL_ENABLED); + if (ret) + return ret; + } + + /* create ISP->RSZ->CAP links */ + for (i = 0; i < 2; i++) { + struct media_entity *resizer = + &rkisp1->resizer_devs[i].sd.entity; + struct media_entity *capture = + &rkisp1->capture_devs[i].vnode.vdev.entity; + + ret = media_create_pad_link(&rkisp1->isp.sd.entity, + RKISP1_ISP_PAD_SOURCE_VIDEO, + resizer, RKISP1_RSZ_PAD_SINK, + MEDIA_LNK_FL_ENABLED); + if (ret) + return ret; + + ret = media_create_pad_link(resizer, RKISP1_RSZ_PAD_SRC, + capture, 0, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) + return ret; + } + + /* params links */ + ret = media_create_pad_link(&rkisp1->params.vnode.vdev.entity, 0, + &rkisp1->isp.sd.entity, + RKISP1_ISP_PAD_SINK_PARAMS, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) + return ret; + + /* 3A stats links */ + return media_create_pad_link(&rkisp1->isp.sd.entity, + RKISP1_ISP_PAD_SOURCE_STATS, + &rkisp1->stats.vnode.vdev.entity, 0, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); +} + +static void rkisp1_entities_unregister(struct rkisp1_device *rkisp1) +{ + if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) + rkisp1_csi_unregister(rkisp1); + rkisp1_params_unregister(rkisp1); + rkisp1_stats_unregister(rkisp1); + rkisp1_capture_devs_unregister(rkisp1); + rkisp1_resizer_devs_unregister(rkisp1); + rkisp1_isp_unregister(rkisp1); +} + static int rkisp1_entities_register(struct rkisp1_device *rkisp1) { int ret; ret = rkisp1_isp_register(rkisp1); if (ret) - return ret; + goto error; ret = rkisp1_resizer_devs_register(rkisp1); if (ret) - goto err_unreg_isp_subdev; + goto error; ret = rkisp1_capture_devs_register(rkisp1); if (ret) - goto err_unreg_resizer_devs; + goto error; ret = rkisp1_stats_register(rkisp1); if (ret) - goto err_unreg_capture_devs; + goto error; ret = rkisp1_params_register(rkisp1); if (ret) - goto err_unreg_stats; + goto error; - ret = rkisp1_subdev_notifier(rkisp1); - if (ret) { - dev_err(rkisp1->dev, - "Failed to register subdev notifier(%d)\n", ret); - goto err_unreg_params; + if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) { + ret = rkisp1_csi_register(rkisp1); + if (ret) + goto error; } + ret = rkisp1_create_links(rkisp1); + if (ret) + goto error; + return 0; -err_unreg_params: - rkisp1_params_unregister(rkisp1); -err_unreg_stats: - rkisp1_stats_unregister(rkisp1); -err_unreg_capture_devs: - rkisp1_capture_devs_unregister(rkisp1); -err_unreg_resizer_devs: - rkisp1_resizer_devs_unregister(rkisp1); -err_unreg_isp_subdev: - rkisp1_isp_unregister(rkisp1); + +error: + rkisp1_entities_unregister(rkisp1); return ret; } @@ -401,7 +450,7 @@ static irqreturn_t rkisp1_isr(int irq, void *ctx) */ rkisp1_capture_isr(irq, ctx); rkisp1_isp_isr(irq, ctx); - rkisp1_mipi_isr(irq, ctx); + rkisp1_csi_isr(irq, ctx); return IRQ_HANDLED; } @@ -416,15 +465,16 @@ static const char * const px30_isp_clks[] = { static const struct rkisp1_isr_data px30_isp_isrs[] = { { "isp", rkisp1_isp_isr }, { "mi", rkisp1_capture_isr }, - { "mipi", rkisp1_mipi_isr }, + { "mipi", rkisp1_csi_isr }, }; -static const struct rkisp1_match_data px30_isp_match_data = { +static const struct rkisp1_info px30_isp_info = { .clks = px30_isp_clks, .clk_size = ARRAY_SIZE(px30_isp_clks), .isrs = px30_isp_isrs, .isr_size = ARRAY_SIZE(px30_isp_isrs), .isp_ver = RKISP1_V12, + .features = RKISP1_FEATURE_MIPI_CSI2, }; static const char * const rk3399_isp_clks[] = { @@ -437,74 +487,45 @@ static const struct rkisp1_isr_data rk3399_isp_isrs[] = { { NULL, rkisp1_isr }, }; -static const struct rkisp1_match_data rk3399_isp_match_data = { +static const struct rkisp1_info rk3399_isp_info = { .clks = rk3399_isp_clks, .clk_size = ARRAY_SIZE(rk3399_isp_clks), .isrs = rk3399_isp_isrs, .isr_size = ARRAY_SIZE(rk3399_isp_isrs), .isp_ver = RKISP1_V10, + .features = RKISP1_FEATURE_MIPI_CSI2, }; static const struct of_device_id rkisp1_of_match[] = { { .compatible = "rockchip,px30-cif-isp", - .data = &px30_isp_match_data, + .data = &px30_isp_info, }, { .compatible = "rockchip,rk3399-cif-isp", - .data = &rk3399_isp_match_data, + .data = &rk3399_isp_info, }, {}, }; MODULE_DEVICE_TABLE(of, rkisp1_of_match); -static void rkisp1_debug_init(struct rkisp1_device *rkisp1) -{ - struct rkisp1_debug *debug = &rkisp1->debug; - - debug->debugfs_dir = debugfs_create_dir(dev_name(rkisp1->dev), NULL); - debugfs_create_ulong("data_loss", 0444, debug->debugfs_dir, - &debug->data_loss); - debugfs_create_ulong("outform_size_err", 0444, debug->debugfs_dir, - &debug->outform_size_error); - debugfs_create_ulong("img_stabilization_size_error", 0444, - debug->debugfs_dir, - &debug->img_stabilization_size_error); - debugfs_create_ulong("inform_size_error", 0444, debug->debugfs_dir, - &debug->inform_size_error); - debugfs_create_ulong("irq_delay", 0444, debug->debugfs_dir, - &debug->irq_delay); - debugfs_create_ulong("mipi_error", 0444, debug->debugfs_dir, - &debug->mipi_error); - debugfs_create_ulong("stats_error", 0444, debug->debugfs_dir, - &debug->stats_error); - debugfs_create_ulong("mp_stop_timeout", 0444, debug->debugfs_dir, - &debug->stop_timeout[RKISP1_MAINPATH]); - debugfs_create_ulong("sp_stop_timeout", 0444, debug->debugfs_dir, - &debug->stop_timeout[RKISP1_SELFPATH]); - debugfs_create_ulong("mp_frame_drop", 0444, debug->debugfs_dir, - &debug->frame_drop[RKISP1_MAINPATH]); - debugfs_create_ulong("sp_frame_drop", 0444, debug->debugfs_dir, - &debug->frame_drop[RKISP1_SELFPATH]); -} - static int rkisp1_probe(struct platform_device *pdev) { - const struct rkisp1_match_data *match_data; + const struct rkisp1_info *info; struct device *dev = &pdev->dev; struct rkisp1_device *rkisp1; struct v4l2_device *v4l2_dev; unsigned int i; int ret, irq; - - match_data = of_device_get_match_data(&pdev->dev); - if (!match_data) - return -ENODEV; + u32 cif_id; rkisp1 = devm_kzalloc(dev, sizeof(*rkisp1), GFP_KERNEL); if (!rkisp1) return -ENOMEM; + info = of_device_get_match_data(dev); + rkisp1->info = info; + dev_set_drvdata(dev, rkisp1); rkisp1->dev = dev; @@ -514,14 +535,14 @@ static int rkisp1_probe(struct platform_device *pdev) if (IS_ERR(rkisp1->base_addr)) return PTR_ERR(rkisp1->base_addr); - for (i = 0; i < match_data->isr_size; i++) { - irq = (match_data->isrs[i].name) ? - platform_get_irq_byname(pdev, match_data->isrs[i].name) : - platform_get_irq(pdev, i); + for (i = 0; i < info->isr_size; i++) { + irq = info->isrs[i].name + ? platform_get_irq_byname(pdev, info->isrs[i].name) + : platform_get_irq(pdev, i); if (irq < 0) return irq; - ret = devm_request_irq(dev, irq, match_data->isrs[i].isr, IRQF_SHARED, + ret = devm_request_irq(dev, irq, info->isrs[i].isr, IRQF_SHARED, dev_driver_string(dev), dev); if (ret) { dev_err(dev, "request irq failed: %d\n", ret); @@ -529,16 +550,25 @@ static int rkisp1_probe(struct platform_device *pdev) } } - for (i = 0; i < match_data->clk_size; i++) - rkisp1->clks[i].id = match_data->clks[i]; - ret = devm_clk_bulk_get(dev, match_data->clk_size, rkisp1->clks); + for (i = 0; i < info->clk_size; i++) + rkisp1->clks[i].id = info->clks[i]; + ret = devm_clk_bulk_get(dev, info->clk_size, rkisp1->clks); if (ret) return ret; - rkisp1->clk_size = match_data->clk_size; + rkisp1->clk_size = info->clk_size; pm_runtime_enable(&pdev->dev); - rkisp1->media_dev.hw_revision = match_data->isp_ver; + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret) + goto err_pm_runtime_disable; + + cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID); + dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n", cif_id); + + pm_runtime_put(&pdev->dev); + + rkisp1->media_dev.hw_revision = info->isp_ver; strscpy(rkisp1->media_dev.model, RKISP1_DRIVER_NAME, sizeof(rkisp1->media_dev.model)); rkisp1->media_dev.dev = &pdev->dev; @@ -552,7 +582,7 @@ static int rkisp1_probe(struct platform_device *pdev) ret = v4l2_device_register(rkisp1->dev, &rkisp1->v4l2_dev); if (ret) - return ret; + goto err_pm_runtime_disable; ret = media_device_register(&rkisp1->media_dev); if (ret) { @@ -560,18 +590,34 @@ static int rkisp1_probe(struct platform_device *pdev) goto err_unreg_v4l2_dev; } + if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) { + ret = rkisp1_csi_init(rkisp1); + if (ret) + goto err_unreg_media_dev; + } + ret = rkisp1_entities_register(rkisp1); if (ret) - goto err_unreg_media_dev; + goto err_cleanup_csi; + + ret = rkisp1_subdev_notifier_register(rkisp1); + if (ret) + goto err_unreg_entities; rkisp1_debug_init(rkisp1); return 0; +err_unreg_entities: + rkisp1_entities_unregister(rkisp1); +err_cleanup_csi: + if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) + rkisp1_csi_cleanup(rkisp1); err_unreg_media_dev: media_device_unregister(&rkisp1->media_dev); err_unreg_v4l2_dev: v4l2_device_unregister(&rkisp1->v4l2_dev); +err_pm_runtime_disable: pm_runtime_disable(&pdev->dev); return ret; } @@ -583,18 +629,16 @@ static int rkisp1_remove(struct platform_device *pdev) v4l2_async_nf_unregister(&rkisp1->notifier); v4l2_async_nf_cleanup(&rkisp1->notifier); - rkisp1_params_unregister(rkisp1); - rkisp1_stats_unregister(rkisp1); - rkisp1_capture_devs_unregister(rkisp1); - rkisp1_resizer_devs_unregister(rkisp1); - rkisp1_isp_unregister(rkisp1); + rkisp1_entities_unregister(rkisp1); + if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) + rkisp1_csi_cleanup(rkisp1); + rkisp1_debug_cleanup(rkisp1); media_device_unregister(&rkisp1->media_dev); v4l2_device_unregister(&rkisp1->v4l2_dev); pm_runtime_disable(&pdev->dev); - debugfs_remove_recursive(rkisp1->debug.debugfs_dir); return 0; } diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index 4415c7248c2f..383a3ec83ca9 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -9,13 +9,10 @@ */ #include <linux/iopoll.h> -#include <linux/phy/phy.h> -#include <linux/phy/phy-mipi-dphy.h> #include <linux/pm_runtime.h> #include <linux/videodev2.h> #include <linux/vmalloc.h> -#include <media/mipi-csi2.h> #include <media/v4l2-event.h> #include "rkisp1-common.h" @@ -56,158 +53,10 @@ * +---------------------------------------------------------+ */ -static const struct rkisp1_isp_mbus_info rkisp1_isp_formats[] = { - { - .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, - .pixel_enc = V4L2_PIXEL_ENC_YUV, - .direction = RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW10, - .bayer_pat = RKISP1_RAW_RGGB, - .bus_width = 10, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW10, - .bayer_pat = RKISP1_RAW_BGGR, - .bus_width = 10, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW10, - .bayer_pat = RKISP1_RAW_GBRG, - .bus_width = 10, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW10, - .bayer_pat = RKISP1_RAW_GRBG, - .bus_width = 10, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW12, - .bayer_pat = RKISP1_RAW_RGGB, - .bus_width = 12, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW12, - .bayer_pat = RKISP1_RAW_BGGR, - .bus_width = 12, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW12, - .bayer_pat = RKISP1_RAW_GBRG, - .bus_width = 12, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW12, - .bayer_pat = RKISP1_RAW_GRBG, - .bus_width = 12, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW8, - .bayer_pat = RKISP1_RAW_RGGB, - .bus_width = 8, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW8, - .bayer_pat = RKISP1_RAW_BGGR, - .bus_width = 8, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW8, - .bayer_pat = RKISP1_RAW_GBRG, - .bus_width = 8, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW8, - .bayer_pat = RKISP1_RAW_GRBG, - .bus_width = 8, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, - .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = MIPI_CSI2_DT_YUV422_8B, - .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCBYCR, - .bus_width = 16, - .direction = RKISP1_ISP_SD_SINK, - }, { - .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, - .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = MIPI_CSI2_DT_YUV422_8B, - .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCRYCB, - .bus_width = 16, - .direction = RKISP1_ISP_SD_SINK, - }, { - .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, - .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = MIPI_CSI2_DT_YUV422_8B, - .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CBYCRY, - .bus_width = 16, - .direction = RKISP1_ISP_SD_SINK, - }, { - .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, - .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = MIPI_CSI2_DT_YUV422_8B, - .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CRYCBY, - .bus_width = 16, - .direction = RKISP1_ISP_SD_SINK, - }, -}; - /* ---------------------------------------------------------------------------- * Helpers */ -const struct rkisp1_isp_mbus_info *rkisp1_isp_mbus_info_get(u32 mbus_code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(rkisp1_isp_formats); i++) { - const struct rkisp1_isp_mbus_info *fmt = &rkisp1_isp_formats[i]; - - if (fmt->mbus_code == mbus_code) - return fmt; - } - - return NULL; -} - -static struct v4l2_subdev *rkisp1_get_remote_sensor(struct v4l2_subdev *sd) -{ - struct media_pad *local, *remote; - struct media_entity *sensor_me; - - local = &sd->entity.pads[RKISP1_ISP_PAD_SINK_VIDEO]; - remote = media_entity_remote_pad(local); - if (!remote) - return NULL; - - sensor_me = remote->entity; - return media_entity_to_v4l2_subdev(sensor_me); -} - static struct v4l2_mbus_framefmt * rkisp1_isp_get_pad_fmt(struct rkisp1_isp *isp, struct v4l2_subdev_state *sd_state, @@ -215,7 +64,8 @@ rkisp1_isp_get_pad_fmt(struct rkisp1_isp *isp, { struct v4l2_subdev_state state = { .pads = isp->pad_cfg - }; + }; + if (which == V4L2_SUBDEV_FORMAT_TRY) return v4l2_subdev_get_try_format(&isp->sd, sd_state, pad); else @@ -229,7 +79,8 @@ rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp, { struct v4l2_subdev_state state = { .pads = isp->pad_cfg - }; + }; + if (which == V4L2_SUBDEV_FORMAT_TRY) return v4l2_subdev_get_try_crop(&isp->sd, sd_state, pad); else @@ -245,73 +96,73 @@ rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp, * This should only be called when configuring CIF * or at the frame end interrupt */ -static void rkisp1_config_ism(struct rkisp1_device *rkisp1) +static void rkisp1_config_ism(struct rkisp1_isp *isp) { - struct v4l2_rect *src_crop = - rkisp1_isp_get_pad_crop(&rkisp1->isp, NULL, + const struct v4l2_rect *src_crop = + rkisp1_isp_get_pad_crop(isp, NULL, RKISP1_ISP_PAD_SOURCE_VIDEO, V4L2_SUBDEV_FORMAT_ACTIVE); + struct rkisp1_device *rkisp1 = isp->rkisp1; u32 val; - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_RECENTER); - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_MAX_DX); - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_MAX_DY); - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_DISPLACE); - rkisp1_write(rkisp1, src_crop->left, RKISP1_CIF_ISP_IS_H_OFFS); - rkisp1_write(rkisp1, src_crop->top, RKISP1_CIF_ISP_IS_V_OFFS); - rkisp1_write(rkisp1, src_crop->width, RKISP1_CIF_ISP_IS_H_SIZE); - rkisp1_write(rkisp1, src_crop->height, RKISP1_CIF_ISP_IS_V_SIZE); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_RECENTER, 0); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_MAX_DX, 0); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_MAX_DY, 0); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_DISPLACE, 0); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_H_OFFS, src_crop->left); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_V_OFFS, src_crop->top); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_H_SIZE, src_crop->width); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_V_SIZE, src_crop->height); /* IS(Image Stabilization) is always on, working as output crop */ - rkisp1_write(rkisp1, 1, RKISP1_CIF_ISP_IS_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_CTRL, 1); val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD; - rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val); } /* * configure ISP blocks with input format, size...... */ -static int rkisp1_config_isp(struct rkisp1_device *rkisp1) -{ - u32 isp_ctrl = 0, irq_mask = 0, acq_mult = 0, signal = 0; - const struct rkisp1_isp_mbus_info *src_fmt, *sink_fmt; - struct rkisp1_sensor_async *sensor; - struct v4l2_mbus_framefmt *sink_frm; - struct v4l2_rect *sink_crop; +static int rkisp1_config_isp(struct rkisp1_isp *isp, + enum v4l2_mbus_type mbus_type, u32 mbus_flags) +{ + struct rkisp1_device *rkisp1 = isp->rkisp1; + u32 isp_ctrl = 0, irq_mask = 0, acq_mult = 0, acq_prop = 0; + const struct rkisp1_mbus_info *sink_fmt = isp->sink_fmt; + const struct rkisp1_mbus_info *src_fmt = isp->src_fmt; + const struct v4l2_mbus_framefmt *sink_frm; + const struct v4l2_rect *sink_crop; - sensor = rkisp1->active_sensor; - sink_fmt = rkisp1->isp.sink_fmt; - src_fmt = rkisp1->isp.src_fmt; - sink_frm = rkisp1_isp_get_pad_fmt(&rkisp1->isp, NULL, + sink_frm = rkisp1_isp_get_pad_fmt(isp, NULL, RKISP1_ISP_PAD_SINK_VIDEO, V4L2_SUBDEV_FORMAT_ACTIVE); - sink_crop = rkisp1_isp_get_pad_crop(&rkisp1->isp, NULL, + sink_crop = rkisp1_isp_get_pad_crop(isp, NULL, RKISP1_ISP_PAD_SINK_VIDEO, V4L2_SUBDEV_FORMAT_ACTIVE); if (sink_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) { acq_mult = 1; if (src_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) { - if (sensor->mbus_type == V4L2_MBUS_BT656) + if (mbus_type == V4L2_MBUS_BT656) isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT_ITU656; else isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT; } else { - rkisp1_write(rkisp1, RKISP1_CIF_ISP_DEMOSAIC_TH(0xc), - RKISP1_CIF_ISP_DEMOSAIC); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_DEMOSAIC, + RKISP1_CIF_ISP_DEMOSAIC_TH(0xc)); - if (sensor->mbus_type == V4L2_MBUS_BT656) + if (mbus_type == V4L2_MBUS_BT656) isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU656; else isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601; } } else if (sink_fmt->pixel_enc == V4L2_PIXEL_ENC_YUV) { acq_mult = 2; - if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) { + if (mbus_type == V4L2_MBUS_CSI2_DPHY) { isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601; } else { - if (sensor->mbus_type == V4L2_MBUS_BT656) + if (mbus_type == V4L2_MBUS_BT656) isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656; else isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601; @@ -321,50 +172,65 @@ static int rkisp1_config_isp(struct rkisp1_device *rkisp1) } /* Set up input acquisition properties */ - if (sensor->mbus_type == V4L2_MBUS_BT656 || - sensor->mbus_type == V4L2_MBUS_PARALLEL) { - if (sensor->mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) - signal = RKISP1_CIF_ISP_ACQ_PROP_POS_EDGE; + if (mbus_type == V4L2_MBUS_BT656 || mbus_type == V4L2_MBUS_PARALLEL) { + if (mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) + acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_POS_EDGE; + + switch (sink_fmt->bus_width) { + case 8: + acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO; + break; + case 10: + acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO; + break; + case 12: + acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B; + break; + default: + dev_err(rkisp1->dev, "Invalid bus width %u\n", + sink_fmt->bus_width); + return -EINVAL; + } } - if (sensor->mbus_type == V4L2_MBUS_PARALLEL) { - if (sensor->mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - signal |= RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW; + if (mbus_type == V4L2_MBUS_PARALLEL) { + if (mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW; - if (sensor->mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - signal |= RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW; + if (mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW; } - rkisp1_write(rkisp1, isp_ctrl, RKISP1_CIF_ISP_CTRL); - rkisp1_write(rkisp1, signal | sink_fmt->yuv_seq | + rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, isp_ctrl); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_PROP, + acq_prop | sink_fmt->yuv_seq | RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT(sink_fmt->bayer_pat) | - RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL, - RKISP1_CIF_ISP_ACQ_PROP); - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_NR_FRAMES); + RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_NR_FRAMES, 0); /* Acquisition Size */ - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_H_OFFS); - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_V_OFFS); - rkisp1_write(rkisp1, - acq_mult * sink_frm->width, RKISP1_CIF_ISP_ACQ_H_SIZE); - rkisp1_write(rkisp1, sink_frm->height, RKISP1_CIF_ISP_ACQ_V_SIZE); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_H_OFFS, 0); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_V_OFFS, 0); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_H_SIZE, + acq_mult * sink_frm->width); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_V_SIZE, sink_frm->height); /* ISP Out Area */ - rkisp1_write(rkisp1, sink_crop->left, RKISP1_CIF_ISP_OUT_H_OFFS); - rkisp1_write(rkisp1, sink_crop->top, RKISP1_CIF_ISP_OUT_V_OFFS); - rkisp1_write(rkisp1, sink_crop->width, RKISP1_CIF_ISP_OUT_H_SIZE); - rkisp1_write(rkisp1, sink_crop->height, RKISP1_CIF_ISP_OUT_V_SIZE); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_OUT_H_OFFS, sink_crop->left); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_OUT_V_OFFS, sink_crop->top); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_OUT_H_SIZE, sink_crop->width); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_OUT_V_SIZE, sink_crop->height); irq_mask |= RKISP1_CIF_ISP_FRAME | RKISP1_CIF_ISP_V_START | RKISP1_CIF_ISP_PIC_SIZE_ERROR; - rkisp1_write(rkisp1, irq_mask, RKISP1_CIF_ISP_IMSC); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IMSC, irq_mask); if (src_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) { rkisp1_params_disable(&rkisp1->params); } else { struct v4l2_mbus_framefmt *src_frm; - src_frm = rkisp1_isp_get_pad_fmt(&rkisp1->isp, NULL, + src_frm = rkisp1_isp_get_pad_fmt(isp, NULL, RKISP1_ISP_PAD_SINK_VIDEO, V4L2_SUBDEV_FORMAT_ACTIVE); rkisp1_params_configure(&rkisp1->params, sink_fmt->bayer_pat, @@ -374,213 +240,117 @@ static int rkisp1_config_isp(struct rkisp1_device *rkisp1) return 0; } -static int rkisp1_config_dvp(struct rkisp1_device *rkisp1) -{ - const struct rkisp1_isp_mbus_info *sink_fmt = rkisp1->isp.sink_fmt; - u32 val, input_sel; - - switch (sink_fmt->bus_width) { - case 8: - input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO; - break; - case 10: - input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO; - break; - case 12: - input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B; - break; - default: - dev_err(rkisp1->dev, "Invalid bus width\n"); - return -EINVAL; - } - - val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_ACQ_PROP); - rkisp1_write(rkisp1, val | input_sel, RKISP1_CIF_ISP_ACQ_PROP); - - return 0; -} - -static int rkisp1_config_mipi(struct rkisp1_device *rkisp1) -{ - const struct rkisp1_isp_mbus_info *sink_fmt = rkisp1->isp.sink_fmt; - unsigned int lanes = rkisp1->active_sensor->lanes; - u32 mipi_ctrl; - - if (lanes < 1 || lanes > 4) - return -EINVAL; - - mipi_ctrl = RKISP1_CIF_MIPI_CTRL_NUM_LANES(lanes - 1) | - RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(0xf) | - RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP | - RKISP1_CIF_MIPI_CTRL_CLOCKLANE_ENA; - - rkisp1_write(rkisp1, mipi_ctrl, RKISP1_CIF_MIPI_CTRL); - - /* V12 could also use a newer csi2-host, but we don't want that yet */ - if (rkisp1->media_dev.hw_revision == RKISP1_V12) - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_CSI0_CTRL0); - - /* Configure Data Type and Virtual Channel */ - rkisp1_write(rkisp1, - RKISP1_CIF_MIPI_DATA_SEL_DT(sink_fmt->mipi_dt) | - RKISP1_CIF_MIPI_DATA_SEL_VC(0), - RKISP1_CIF_MIPI_IMG_DATA_SEL); - - /* Clear MIPI interrupts */ - rkisp1_write(rkisp1, ~0, RKISP1_CIF_MIPI_ICR); - /* - * Disable RKISP1_CIF_MIPI_ERR_DPHY interrupt here temporary for - * isp bus may be dead when switch isp. - */ - rkisp1_write(rkisp1, - RKISP1_CIF_MIPI_FRAME_END | RKISP1_CIF_MIPI_ERR_CSI | - RKISP1_CIF_MIPI_ERR_DPHY | - RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(0x03) | - RKISP1_CIF_MIPI_ADD_DATA_OVFLW, - RKISP1_CIF_MIPI_IMSC); - - dev_dbg(rkisp1->dev, "\n MIPI_CTRL 0x%08x\n" - " MIPI_IMG_DATA_SEL 0x%08x\n" - " MIPI_STATUS 0x%08x\n" - " MIPI_IMSC 0x%08x\n", - rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL), - rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL), - rkisp1_read(rkisp1, RKISP1_CIF_MIPI_STATUS), - rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC)); - - return 0; -} - /* Configure MUX */ -static int rkisp1_config_path(struct rkisp1_device *rkisp1) +static void rkisp1_config_path(struct rkisp1_isp *isp, + enum v4l2_mbus_type mbus_type) { - struct rkisp1_sensor_async *sensor = rkisp1->active_sensor; + struct rkisp1_device *rkisp1 = isp->rkisp1; u32 dpcl = rkisp1_read(rkisp1, RKISP1_CIF_VI_DPCL); - int ret = 0; - if (sensor->mbus_type == V4L2_MBUS_BT656 || - sensor->mbus_type == V4L2_MBUS_PARALLEL) { - ret = rkisp1_config_dvp(rkisp1); + if (mbus_type == V4L2_MBUS_BT656 || mbus_type == V4L2_MBUS_PARALLEL) dpcl |= RKISP1_CIF_VI_DPCL_IF_SEL_PARALLEL; - } else if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) { - ret = rkisp1_config_mipi(rkisp1); + else if (mbus_type == V4L2_MBUS_CSI2_DPHY) dpcl |= RKISP1_CIF_VI_DPCL_IF_SEL_MIPI; - } - - rkisp1_write(rkisp1, dpcl, RKISP1_CIF_VI_DPCL); - return ret; + rkisp1_write(rkisp1, RKISP1_CIF_VI_DPCL, dpcl); } /* Hardware configure Entry */ -static int rkisp1_config_cif(struct rkisp1_device *rkisp1) +static int rkisp1_config_cif(struct rkisp1_isp *isp, + enum v4l2_mbus_type mbus_type, u32 mbus_flags) { - u32 cif_id; int ret; - cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID); - dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n", cif_id); - - ret = rkisp1_config_isp(rkisp1); + ret = rkisp1_config_isp(isp, mbus_type, mbus_flags); if (ret) return ret; - ret = rkisp1_config_path(rkisp1); - if (ret) - return ret; - rkisp1_config_ism(rkisp1); + + rkisp1_config_path(isp, mbus_type); + rkisp1_config_ism(isp); return 0; } -static void rkisp1_isp_stop(struct rkisp1_device *rkisp1) +static void rkisp1_isp_stop(struct rkisp1_isp *isp) { + struct rkisp1_device *rkisp1 = isp->rkisp1; u32 val; /* * ISP(mi) stop in mi frame end -> Stop ISP(mipi) -> * Stop ISP(isp) ->wait for ISP isp off */ - /* stop and clear MI, MIPI, and ISP interrupts */ - rkisp1_write(rkisp1, 0, RKISP1_CIF_MIPI_IMSC); - rkisp1_write(rkisp1, ~0, RKISP1_CIF_MIPI_ICR); - - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IMSC); - rkisp1_write(rkisp1, ~0, RKISP1_CIF_ISP_ICR); - - rkisp1_write(rkisp1, 0, RKISP1_CIF_MI_IMSC); - rkisp1_write(rkisp1, ~0, RKISP1_CIF_MI_ICR); - val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL); - rkisp1_write(rkisp1, val & (~RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA), - RKISP1_CIF_MIPI_CTRL); + /* stop and clear MI and ISP interrupts */ + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IMSC, 0); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, ~0); + + rkisp1_write(rkisp1, RKISP1_CIF_MI_IMSC, 0); + rkisp1_write(rkisp1, RKISP1_CIF_MI_ICR, ~0); + /* stop ISP */ val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); val &= ~(RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE | RKISP1_CIF_ISP_CTRL_ISP_ENABLE); - rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val); val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); - rkisp1_write(rkisp1, val | RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD, - RKISP1_CIF_ISP_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, + val | RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD); readx_poll_timeout(readl, rkisp1->base_addr + RKISP1_CIF_ISP_RIS, val, val & RKISP1_CIF_ISP_OFF, 20, 100); - rkisp1_write(rkisp1, - RKISP1_CIF_IRCL_MIPI_SW_RST | RKISP1_CIF_IRCL_ISP_SW_RST, - RKISP1_CIF_IRCL); - rkisp1_write(rkisp1, 0x0, RKISP1_CIF_IRCL); + rkisp1_write(rkisp1, RKISP1_CIF_VI_IRCL, + RKISP1_CIF_VI_IRCL_MIPI_SW_RST | + RKISP1_CIF_VI_IRCL_ISP_SW_RST); + rkisp1_write(rkisp1, RKISP1_CIF_VI_IRCL, 0x0); } -static void rkisp1_config_clk(struct rkisp1_device *rkisp1) +static void rkisp1_config_clk(struct rkisp1_isp *isp) { - u32 val = RKISP1_CIF_ICCL_ISP_CLK | RKISP1_CIF_ICCL_CP_CLK | - RKISP1_CIF_ICCL_MRSZ_CLK | RKISP1_CIF_ICCL_SRSZ_CLK | - RKISP1_CIF_ICCL_JPEG_CLK | RKISP1_CIF_ICCL_MI_CLK | - RKISP1_CIF_ICCL_IE_CLK | RKISP1_CIF_ICCL_MIPI_CLK | - RKISP1_CIF_ICCL_DCROP_CLK; + struct rkisp1_device *rkisp1 = isp->rkisp1; + + u32 val = RKISP1_CIF_VI_ICCL_ISP_CLK | RKISP1_CIF_VI_ICCL_CP_CLK | + RKISP1_CIF_VI_ICCL_MRSZ_CLK | RKISP1_CIF_VI_ICCL_SRSZ_CLK | + RKISP1_CIF_VI_ICCL_JPEG_CLK | RKISP1_CIF_VI_ICCL_MI_CLK | + RKISP1_CIF_VI_ICCL_IE_CLK | RKISP1_CIF_VI_ICCL_MIPI_CLK | + RKISP1_CIF_VI_ICCL_DCROP_CLK; - rkisp1_write(rkisp1, val, RKISP1_CIF_ICCL); + rkisp1_write(rkisp1, RKISP1_CIF_VI_ICCL, val); /* ensure sp and mp can run at the same time in V12 */ - if (rkisp1->media_dev.hw_revision == RKISP1_V12) { + if (rkisp1->info->isp_ver == RKISP1_V12) { val = RKISP1_CIF_CLK_CTRL_MI_Y12 | RKISP1_CIF_CLK_CTRL_MI_SP | RKISP1_CIF_CLK_CTRL_MI_RAW0 | RKISP1_CIF_CLK_CTRL_MI_RAW1 | RKISP1_CIF_CLK_CTRL_MI_READ | RKISP1_CIF_CLK_CTRL_MI_RAWRD | RKISP1_CIF_CLK_CTRL_CP | RKISP1_CIF_CLK_CTRL_IE; - rkisp1_write(rkisp1, val, RKISP1_CIF_VI_ISP_CLK_CTRL_V12); + rkisp1_write(rkisp1, RKISP1_CIF_VI_ISP_CLK_CTRL_V12, val); } } -static void rkisp1_isp_start(struct rkisp1_device *rkisp1) +static void rkisp1_isp_start(struct rkisp1_isp *isp) { - struct rkisp1_sensor_async *sensor = rkisp1->active_sensor; + struct rkisp1_device *rkisp1 = isp->rkisp1; u32 val; - rkisp1_config_clk(rkisp1); + rkisp1_config_clk(isp); - /* Activate MIPI */ - if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) { - val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL); - rkisp1_write(rkisp1, val | RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA, - RKISP1_CIF_MIPI_CTRL); - } /* Activate ISP */ val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD | RKISP1_CIF_ISP_CTRL_ISP_ENABLE | RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE; - rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL); - - /* - * CIF spec says to wait for sufficient time after enabling - * the MIPI interface and before starting the sensor output. - */ - usleep_range(1000, 1200); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val); } /* ---------------------------------------------------------------------------- * Subdev pad operations */ +static inline struct rkisp1_isp *to_rkisp1_isp(struct v4l2_subdev *sd) +{ + return container_of(sd, struct rkisp1_isp, sd); +} + static int rkisp1_isp_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) @@ -599,11 +369,12 @@ static int rkisp1_isp_enum_mbus_code(struct v4l2_subdev *sd, return 0; } - if (code->index >= ARRAY_SIZE(rkisp1_isp_formats)) - return -EINVAL; + for (i = 0; ; i++) { + const struct rkisp1_mbus_info *fmt = + rkisp1_mbus_info_get_by_index(i); - for (i = 0; i < ARRAY_SIZE(rkisp1_isp_formats); i++) { - const struct rkisp1_isp_mbus_info *fmt = &rkisp1_isp_formats[i]; + if (!fmt) + return -EINVAL; if (fmt->direction & dir) pos++; @@ -625,7 +396,7 @@ static int rkisp1_isp_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { - const struct rkisp1_isp_mbus_info *mbus_info; + const struct rkisp1_mbus_info *mbus_info; if (fse->pad == RKISP1_ISP_PAD_SINK_PARAMS || fse->pad == RKISP1_ISP_PAD_SOURCE_STATS) @@ -634,7 +405,7 @@ static int rkisp1_isp_enum_frame_size(struct v4l2_subdev *sd, if (fse->index > 0) return -EINVAL; - mbus_info = rkisp1_isp_mbus_info_get(fse->code); + mbus_info = rkisp1_mbus_info_get_by_code(fse->code); if (!mbus_info) return -EINVAL; @@ -701,7 +472,7 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, struct v4l2_mbus_framefmt *format, unsigned int which) { - const struct rkisp1_isp_mbus_info *mbus_info; + const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *src_fmt; const struct v4l2_rect *src_crop; @@ -711,10 +482,10 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, RKISP1_ISP_PAD_SOURCE_VIDEO, which); src_fmt->code = format->code; - mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code); + mbus_info = rkisp1_mbus_info_get_by_code(src_fmt->code); if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SRC)) { src_fmt->code = RKISP1_DEF_SRC_PAD_FMT; - mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code); + mbus_info = rkisp1_mbus_info_get_by_code(src_fmt->code); } if (which == V4L2_SUBDEV_FORMAT_ACTIVE) isp->src_fmt = mbus_info; @@ -771,7 +542,7 @@ static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp, struct v4l2_rect *r, unsigned int which) { struct v4l2_rect *sink_crop, *src_crop; - struct v4l2_mbus_framefmt *sink_fmt; + const struct v4l2_mbus_framefmt *sink_fmt; sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state, RKISP1_ISP_PAD_SINK_VIDEO, @@ -799,7 +570,7 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp, struct v4l2_mbus_framefmt *format, unsigned int which) { - const struct rkisp1_isp_mbus_info *mbus_info; + const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_rect *sink_crop; @@ -807,10 +578,10 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp, RKISP1_ISP_PAD_SINK_VIDEO, which); sink_fmt->code = format->code; - mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SINK)) { sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT; - mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); } if (which == V4L2_SUBDEV_FORMAT_ACTIVE) isp->sink_fmt = mbus_info; @@ -835,7 +606,7 @@ static int rkisp1_isp_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { - struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); + struct rkisp1_isp *isp = to_rkisp1_isp(sd); mutex_lock(&isp->ops_lock); fmt->format = *rkisp1_isp_get_pad_fmt(isp, sd_state, fmt->pad, @@ -848,7 +619,7 @@ static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { - struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); + struct rkisp1_isp *isp = to_rkisp1_isp(sd); mutex_lock(&isp->ops_lock); if (fmt->pad == RKISP1_ISP_PAD_SINK_VIDEO) @@ -869,7 +640,7 @@ static int rkisp1_isp_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { - struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); + struct rkisp1_isp *isp = to_rkisp1_isp(sd); int ret = 0; if (sel->pad != RKISP1_ISP_PAD_SOURCE_VIDEO && @@ -909,15 +680,13 @@ static int rkisp1_isp_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { - struct rkisp1_device *rkisp1 = - container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev); - struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); + struct rkisp1_isp *isp = to_rkisp1_isp(sd); int ret = 0; if (sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - dev_dbg(rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__, + dev_dbg(isp->rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__, sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height); mutex_lock(&isp->ops_lock); if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) @@ -954,77 +723,62 @@ static const struct v4l2_subdev_pad_ops rkisp1_isp_pad_ops = { * Stream operations */ -static int rkisp1_mipi_csi2_start(struct rkisp1_isp *isp, - struct rkisp1_sensor_async *sensor) -{ - struct rkisp1_device *rkisp1 = - container_of(isp->sd.v4l2_dev, struct rkisp1_device, v4l2_dev); - union phy_configure_opts opts; - struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy; - s64 pixel_clock; - - if (!sensor->pixel_rate_ctrl) { - dev_warn(rkisp1->dev, "No pixel rate control in sensor subdev\n"); - return -EPIPE; - } - - pixel_clock = v4l2_ctrl_g_ctrl_int64(sensor->pixel_rate_ctrl); - if (!pixel_clock) { - dev_err(rkisp1->dev, "Invalid pixel rate value\n"); - return -EINVAL; - } - - phy_mipi_dphy_get_default_config(pixel_clock, isp->sink_fmt->bus_width, - sensor->lanes, cfg); - phy_set_mode(sensor->dphy, PHY_MODE_MIPI_DPHY); - phy_configure(sensor->dphy, &opts); - phy_power_on(sensor->dphy); - - return 0; -} - -static void rkisp1_mipi_csi2_stop(struct rkisp1_sensor_async *sensor) -{ - phy_power_off(sensor->dphy); -} - static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable) { - struct rkisp1_device *rkisp1 = - container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev); - struct rkisp1_isp *isp = &rkisp1->isp; - struct v4l2_subdev *sensor_sd; - int ret = 0; + struct rkisp1_isp *isp = to_rkisp1_isp(sd); + struct rkisp1_device *rkisp1 = isp->rkisp1; + struct media_pad *source_pad; + struct media_pad *sink_pad; + enum v4l2_mbus_type mbus_type; + u32 mbus_flags; + int ret; if (!enable) { - rkisp1_isp_stop(rkisp1); - rkisp1_mipi_csi2_stop(rkisp1->active_sensor); + v4l2_subdev_call(rkisp1->source, video, s_stream, false); + rkisp1_isp_stop(isp); return 0; } - sensor_sd = rkisp1_get_remote_sensor(sd); - if (!sensor_sd) { - dev_warn(rkisp1->dev, "No link between isp and sensor\n"); - return -ENODEV; + sink_pad = &isp->pads[RKISP1_ISP_PAD_SINK_VIDEO]; + source_pad = media_pad_remote_pad_unique(sink_pad); + if (IS_ERR(source_pad)) { + dev_dbg(rkisp1->dev, "Failed to get source for ISP: %ld\n", + PTR_ERR(source_pad)); + return -EPIPE; } - rkisp1->active_sensor = container_of(sensor_sd->asd, - struct rkisp1_sensor_async, asd); + rkisp1->source = media_entity_to_v4l2_subdev(source_pad->entity); + if (!rkisp1->source) { + /* This should really not happen, so is not worth a message. */ + return -EPIPE; + } - if (rkisp1->active_sensor->mbus_type != V4L2_MBUS_CSI2_DPHY) - return -EINVAL; + if (rkisp1->source == &rkisp1->csi.sd) { + mbus_type = V4L2_MBUS_CSI2_DPHY; + mbus_flags = 0; + } else { + const struct rkisp1_sensor_async *asd; - rkisp1->isp.frame_sequence = -1; + asd = container_of(rkisp1->source->asd, + struct rkisp1_sensor_async, asd); + + mbus_type = asd->mbus_type; + mbus_flags = asd->mbus_flags; + } + + isp->frame_sequence = -1; mutex_lock(&isp->ops_lock); - ret = rkisp1_config_cif(rkisp1); + ret = rkisp1_config_cif(isp, mbus_type, mbus_flags); if (ret) goto mutex_unlock; - ret = rkisp1_mipi_csi2_start(&rkisp1->isp, rkisp1->active_sensor); - if (ret) - goto mutex_unlock; + rkisp1_isp_start(isp); - rkisp1_isp_start(rkisp1); + ret = v4l2_subdev_call(rkisp1->source, video, s_stream, true); + if (ret) { + rkisp1_isp_stop(isp); + goto mutex_unlock; + } mutex_unlock: mutex_unlock(&isp->ops_lock); @@ -1067,12 +821,14 @@ int rkisp1_isp_register(struct rkisp1_device *rkisp1) { struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg - }; + }; struct rkisp1_isp *isp = &rkisp1->isp; struct media_pad *pads = isp->pads; struct v4l2_subdev *sd = &isp->sd; int ret; + isp->rkisp1 = rkisp1; + v4l2_subdev_init(sd, &rkisp1_isp_ops); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; sd->entity.ops = &rkisp1_isp_media_ops; @@ -1086,95 +842,54 @@ int rkisp1_isp_register(struct rkisp1_device *rkisp1) pads[RKISP1_ISP_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE; pads[RKISP1_ISP_PAD_SOURCE_STATS].flags = MEDIA_PAD_FL_SOURCE; - isp->sink_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SINK_PAD_FMT); - isp->src_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SRC_PAD_FMT); + isp->sink_fmt = rkisp1_mbus_info_get_by_code(RKISP1_DEF_SINK_PAD_FMT); + isp->src_fmt = rkisp1_mbus_info_get_by_code(RKISP1_DEF_SRC_PAD_FMT); mutex_init(&isp->ops_lock); ret = media_entity_pads_init(&sd->entity, RKISP1_ISP_PAD_MAX, pads); if (ret) - return ret; + goto error; ret = v4l2_device_register_subdev(&rkisp1->v4l2_dev, sd); if (ret) { dev_err(rkisp1->dev, "Failed to register isp subdev\n"); - goto err_cleanup_media_entity; + goto error; } rkisp1_isp_init_config(sd, &state); + return 0; -err_cleanup_media_entity: +error: media_entity_cleanup(&sd->entity); - + mutex_destroy(&isp->ops_lock); + isp->sd.v4l2_dev = NULL; return ret; } void rkisp1_isp_unregister(struct rkisp1_device *rkisp1) { - struct v4l2_subdev *sd = &rkisp1->isp.sd; + struct rkisp1_isp *isp = &rkisp1->isp; - v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&sd->entity); + if (!isp->sd.v4l2_dev) + return; + + v4l2_device_unregister_subdev(&isp->sd); + media_entity_cleanup(&isp->sd.entity); + mutex_destroy(&isp->ops_lock); } /* ---------------------------------------------------------------------------- * Interrupt handlers */ -irqreturn_t rkisp1_mipi_isr(int irq, void *ctx) -{ - struct device *dev = ctx; - struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); - u32 val, status; - - status = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_MIS); - if (!status) - return IRQ_NONE; - - rkisp1_write(rkisp1, status, RKISP1_CIF_MIPI_ICR); - - /* - * Disable DPHY errctrl interrupt, because this dphy - * erctrl signal is asserted until the next changes - * of line state. This time is may be too long and cpu - * is hold in this interrupt. - */ - if (status & RKISP1_CIF_MIPI_ERR_CTRL(0x0f)) { - val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC); - rkisp1_write(rkisp1, val & ~RKISP1_CIF_MIPI_ERR_CTRL(0x0f), - RKISP1_CIF_MIPI_IMSC); - rkisp1->isp.is_dphy_errctrl_disabled = true; - } - - /* - * Enable DPHY errctrl interrupt again, if mipi have receive - * the whole frame without any error. - */ - if (status == RKISP1_CIF_MIPI_FRAME_END) { - /* - * Enable DPHY errctrl interrupt again, if mipi have receive - * the whole frame without any error. - */ - if (rkisp1->isp.is_dphy_errctrl_disabled) { - val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC); - val |= RKISP1_CIF_MIPI_ERR_CTRL(0x0f); - rkisp1_write(rkisp1, val, RKISP1_CIF_MIPI_IMSC); - rkisp1->isp.is_dphy_errctrl_disabled = false; - } - } else { - rkisp1->debug.mipi_error++; - } - - return IRQ_HANDLED; -} - static void rkisp1_isp_queue_event_sof(struct rkisp1_isp *isp) { struct v4l2_event event = { .type = V4L2_EVENT_FRAME_SYNC, }; - event.u.frame_sync.frame_sequence = isp->frame_sequence; + event.u.frame_sync.frame_sequence = isp->frame_sequence; v4l2_event_queue(isp->sd.devnode, &event); } @@ -1188,7 +903,7 @@ irqreturn_t rkisp1_isp_isr(int irq, void *ctx) if (!status) return IRQ_NONE; - rkisp1_write(rkisp1, status, RKISP1_CIF_ISP_ICR); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, status); /* Vertical sync signal, starting generating new frame */ if (status & RKISP1_CIF_ISP_V_START) { @@ -1208,7 +923,7 @@ irqreturn_t rkisp1_isp_isr(int irq, void *ctx) rkisp1->debug.img_stabilization_size_error++; if (isp_err & RKISP1_CIF_ISP_ERR_OUTFORM_SIZE) rkisp1->debug.outform_size_error++; - rkisp1_write(rkisp1, isp_err, RKISP1_CIF_ISP_ERR_CLR); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ERR_CLR, isp_err); } else if (status & RKISP1_CIF_ISP_DATA_LOSS) { /* keep track of data_loss in debugfs */ rkisp1->debug.data_loss++; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 8f62f09e635f..9da7dc1bc690 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -37,7 +37,7 @@ rkisp1_param_set_bits(struct rkisp1_params *params, u32 reg, u32 bit_mask) u32 val; val = rkisp1_read(params->rkisp1, reg); - rkisp1_write(params->rkisp1, val | bit_mask, reg); + rkisp1_write(params->rkisp1, reg, val | bit_mask); } static inline void @@ -46,7 +46,7 @@ rkisp1_param_clear_bits(struct rkisp1_params *params, u32 reg, u32 bit_mask) u32 val; val = rkisp1_read(params->rkisp1, reg); - rkisp1_write(params->rkisp1, val & ~bit_mask, reg); + rkisp1_write(params->rkisp1, reg, val & ~bit_mask); } /* ISP BP interface function */ @@ -60,35 +60,35 @@ static void rkisp1_dpcc_config(struct rkisp1_params *params, mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_DPCC_MODE); mode &= RKISP1_CIF_ISP_DPCC_ENA; mode |= arg->mode & ~RKISP1_CIF_ISP_DPCC_ENA; - rkisp1_write(params->rkisp1, mode, RKISP1_CIF_ISP_DPCC_MODE); - rkisp1_write(params->rkisp1, arg->output_mode, - RKISP1_CIF_ISP_DPCC_OUTPUT_MODE); - rkisp1_write(params->rkisp1, arg->set_use, - RKISP1_CIF_ISP_DPCC_SET_USE); - - rkisp1_write(params->rkisp1, arg->methods[0].method, - RKISP1_CIF_ISP_DPCC_METHODS_SET_1); - rkisp1_write(params->rkisp1, arg->methods[1].method, - RKISP1_CIF_ISP_DPCC_METHODS_SET_2); - rkisp1_write(params->rkisp1, arg->methods[2].method, - RKISP1_CIF_ISP_DPCC_METHODS_SET_3); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_MODE, mode); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_OUTPUT_MODE, + arg->output_mode); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_SET_USE, + arg->set_use); + + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_1, + arg->methods[0].method); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_2, + arg->methods[1].method); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_3, + arg->methods[2].method); for (i = 0; i < RKISP1_CIF_ISP_DPCC_METHODS_MAX; i++) { - rkisp1_write(params->rkisp1, arg->methods[i].line_thresh, - RKISP1_ISP_DPCC_LINE_THRESH(i)); - rkisp1_write(params->rkisp1, arg->methods[i].line_mad_fac, - RKISP1_ISP_DPCC_LINE_MAD_FAC(i)); - rkisp1_write(params->rkisp1, arg->methods[i].pg_fac, - RKISP1_ISP_DPCC_PG_FAC(i)); - rkisp1_write(params->rkisp1, arg->methods[i].rnd_thresh, - RKISP1_ISP_DPCC_RND_THRESH(i)); - rkisp1_write(params->rkisp1, arg->methods[i].rg_fac, - RKISP1_ISP_DPCC_RG_FAC(i)); + rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_LINE_THRESH(i), + arg->methods[i].line_thresh); + rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_LINE_MAD_FAC(i), + arg->methods[i].line_mad_fac); + rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_PG_FAC(i), + arg->methods[i].pg_fac); + rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_RND_THRESH(i), + arg->methods[i].rnd_thresh); + rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_RG_FAC(i), + arg->methods[i].rg_fac); } - rkisp1_write(params->rkisp1, arg->rnd_offs, - RKISP1_CIF_ISP_DPCC_RND_OFFS); - rkisp1_write(params->rkisp1, arg->ro_limits, - RKISP1_CIF_ISP_DPCC_RO_LIMITS); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_RND_OFFS, + arg->rnd_offs); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_RO_LIMITS, + arg->ro_limits); } /* ISP black level subtraction interface function */ @@ -107,44 +107,44 @@ static void rkisp1_bls_config(struct rkisp1_params *params, switch (params->raw_type) { case RKISP1_RAW_BGGR: - rkisp1_write(params->rkisp1, - pval->r, RKISP1_CIF_ISP_BLS_D_FIXED); - rkisp1_write(params->rkisp1, - pval->gr, RKISP1_CIF_ISP_BLS_C_FIXED); - rkisp1_write(params->rkisp1, - pval->gb, RKISP1_CIF_ISP_BLS_B_FIXED); - rkisp1_write(params->rkisp1, - pval->b, RKISP1_CIF_ISP_BLS_A_FIXED); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_D_FIXED, + pval->r); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_C_FIXED, + pval->gr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_B_FIXED, + pval->gb); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_A_FIXED, + pval->b); break; case RKISP1_RAW_GBRG: - rkisp1_write(params->rkisp1, - pval->r, RKISP1_CIF_ISP_BLS_C_FIXED); - rkisp1_write(params->rkisp1, - pval->gr, RKISP1_CIF_ISP_BLS_D_FIXED); - rkisp1_write(params->rkisp1, - pval->gb, RKISP1_CIF_ISP_BLS_A_FIXED); - rkisp1_write(params->rkisp1, - pval->b, RKISP1_CIF_ISP_BLS_B_FIXED); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_C_FIXED, + pval->r); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_D_FIXED, + pval->gr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_A_FIXED, + pval->gb); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_B_FIXED, + pval->b); break; case RKISP1_RAW_GRBG: - rkisp1_write(params->rkisp1, - pval->r, RKISP1_CIF_ISP_BLS_B_FIXED); - rkisp1_write(params->rkisp1, - pval->gr, RKISP1_CIF_ISP_BLS_A_FIXED); - rkisp1_write(params->rkisp1, - pval->gb, RKISP1_CIF_ISP_BLS_D_FIXED); - rkisp1_write(params->rkisp1, - pval->b, RKISP1_CIF_ISP_BLS_C_FIXED); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_B_FIXED, + pval->r); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_A_FIXED, + pval->gr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_D_FIXED, + pval->gb); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_C_FIXED, + pval->b); break; case RKISP1_RAW_RGGB: - rkisp1_write(params->rkisp1, - pval->r, RKISP1_CIF_ISP_BLS_A_FIXED); - rkisp1_write(params->rkisp1, - pval->gr, RKISP1_CIF_ISP_BLS_B_FIXED); - rkisp1_write(params->rkisp1, - pval->gb, RKISP1_CIF_ISP_BLS_C_FIXED); - rkisp1_write(params->rkisp1, - pval->b, RKISP1_CIF_ISP_BLS_D_FIXED); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_A_FIXED, + pval->r); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_B_FIXED, + pval->gr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_C_FIXED, + pval->gb); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_D_FIXED, + pval->b); break; default: break; @@ -152,35 +152,35 @@ static void rkisp1_bls_config(struct rkisp1_params *params, } else { if (arg->en_windows & BIT(1)) { - rkisp1_write(params->rkisp1, arg->bls_window2.h_offs, - RKISP1_CIF_ISP_BLS_H2_START); - rkisp1_write(params->rkisp1, arg->bls_window2.h_size, - RKISP1_CIF_ISP_BLS_H2_STOP); - rkisp1_write(params->rkisp1, arg->bls_window2.v_offs, - RKISP1_CIF_ISP_BLS_V2_START); - rkisp1_write(params->rkisp1, arg->bls_window2.v_size, - RKISP1_CIF_ISP_BLS_V2_STOP); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_H2_START, + arg->bls_window2.h_offs); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_H2_STOP, + arg->bls_window2.h_size); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_V2_START, + arg->bls_window2.v_offs); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_V2_STOP, + arg->bls_window2.v_size); new_control |= RKISP1_CIF_ISP_BLS_WINDOW_2; } if (arg->en_windows & BIT(0)) { - rkisp1_write(params->rkisp1, arg->bls_window1.h_offs, - RKISP1_CIF_ISP_BLS_H1_START); - rkisp1_write(params->rkisp1, arg->bls_window1.h_size, - RKISP1_CIF_ISP_BLS_H1_STOP); - rkisp1_write(params->rkisp1, arg->bls_window1.v_offs, - RKISP1_CIF_ISP_BLS_V1_START); - rkisp1_write(params->rkisp1, arg->bls_window1.v_size, - RKISP1_CIF_ISP_BLS_V1_STOP); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_H1_START, + arg->bls_window1.h_offs); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_H1_STOP, + arg->bls_window1.h_size); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_V1_START, + arg->bls_window1.v_offs); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_V1_STOP, + arg->bls_window1.v_size); new_control |= RKISP1_CIF_ISP_BLS_WINDOW_1; } - rkisp1_write(params->rkisp1, arg->bls_samples, - RKISP1_CIF_ISP_BLS_SAMPLES); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_SAMPLES, + arg->bls_samples); new_control |= RKISP1_CIF_ISP_BLS_MODE_MEASURED; } - rkisp1_write(params->rkisp1, new_control, RKISP1_CIF_ISP_BLS_CTRL); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_CTRL, new_control); } /* ISP LS correction interface function */ @@ -196,14 +196,10 @@ rkisp1_lsc_matrix_config_v10(struct rkisp1_params *params, sram_addr = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 : RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153; - rkisp1_write(params->rkisp1, sram_addr, - RKISP1_CIF_ISP_LSC_R_TABLE_ADDR); - rkisp1_write(params->rkisp1, sram_addr, - RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR); - rkisp1_write(params->rkisp1, sram_addr, - RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR); - rkisp1_write(params->rkisp1, sram_addr, - RKISP1_CIF_ISP_LSC_B_TABLE_ADDR); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR, sram_addr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR, sram_addr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR, sram_addr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR, sram_addr); /* program data tables (table size is 9 * 17 = 153) */ for (i = 0; i < RKISP1_CIF_ISP_LSC_SAMPLES_MAX; i++) { @@ -214,45 +210,45 @@ rkisp1_lsc_matrix_config_v10(struct rkisp1_params *params, for (j = 0; j < RKISP1_CIF_ISP_LSC_SAMPLES_MAX - 1; j += 2) { data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->r_data_tbl[i][j], pconfig->r_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_R_TABLE_DATA); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_R_TABLE_DATA, data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gr_data_tbl[i][j], pconfig->gr_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gb_data_tbl[i][j], pconfig->gb_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->b_data_tbl[i][j], pconfig->b_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_B_TABLE_DATA); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_B_TABLE_DATA, data); } data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->r_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_R_TABLE_DATA); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, + data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gr_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, + data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gb_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, + data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->b_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_B_TABLE_DATA); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, + data); } isp_lsc_table_sel = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? RKISP1_CIF_ISP_LSC_TABLE_0 : RKISP1_CIF_ISP_LSC_TABLE_1; - rkisp1_write(params->rkisp1, isp_lsc_table_sel, - RKISP1_CIF_ISP_LSC_TABLE_SEL); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_TABLE_SEL, + isp_lsc_table_sel); } static void @@ -267,10 +263,10 @@ rkisp1_lsc_matrix_config_v12(struct rkisp1_params *params, sram_addr = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 : RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153; - rkisp1_write(params->rkisp1, sram_addr, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR); - rkisp1_write(params->rkisp1, sram_addr, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR); - rkisp1_write(params->rkisp1, sram_addr, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR); - rkisp1_write(params->rkisp1, sram_addr, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR, sram_addr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR, sram_addr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR, sram_addr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR, sram_addr); /* program data tables (table size is 9 * 17 = 153) */ for (i = 0; i < RKISP1_CIF_ISP_LSC_SAMPLES_MAX; i++) { @@ -282,49 +278,49 @@ rkisp1_lsc_matrix_config_v12(struct rkisp1_params *params, data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( pconfig->r_data_tbl[i][j], pconfig->r_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_R_TABLE_DATA); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_R_TABLE_DATA, data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( pconfig->gr_data_tbl[i][j], pconfig->gr_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( pconfig->gb_data_tbl[i][j], pconfig->gb_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( pconfig->b_data_tbl[i][j], pconfig->b_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_B_TABLE_DATA); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_B_TABLE_DATA, data); } data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->r_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_R_TABLE_DATA); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, + data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->gr_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, + data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->gb_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, + data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->b_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_B_TABLE_DATA); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, + data); } isp_lsc_table_sel = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? RKISP1_CIF_ISP_LSC_TABLE_0 : RKISP1_CIF_ISP_LSC_TABLE_1; - rkisp1_write(params->rkisp1, isp_lsc_table_sel, - RKISP1_CIF_ISP_LSC_TABLE_SEL); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_TABLE_SEL, + isp_lsc_table_sel); } static void rkisp1_lsc_config(struct rkisp1_params *params, @@ -343,26 +339,26 @@ static void rkisp1_lsc_config(struct rkisp1_params *params, /* program x size tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_size_tbl[i * 2], arg->x_size_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_XSIZE_01 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_XSIZE_01 + i * 4, data); /* program x grad tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_grad_tbl[i * 2], arg->x_grad_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_XGRAD_01 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_XGRAD_01 + i * 4, data); /* program y size tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_size_tbl[i * 2], arg->y_size_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_YSIZE_01 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_YSIZE_01 + i * 4, data); /* program y grad tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_grad_tbl[i * 2], arg->y_grad_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_YGRAD_01 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_YGRAD_01 + i * 4, data); } /* restore the lsc ctrl status */ @@ -383,28 +379,32 @@ static void rkisp1_flt_config(struct rkisp1_params *params, { u32 filt_mode; - rkisp1_write(params->rkisp1, - arg->thresh_bl0, RKISP1_CIF_ISP_FILT_THRESH_BL0); - rkisp1_write(params->rkisp1, - arg->thresh_bl1, RKISP1_CIF_ISP_FILT_THRESH_BL1); - rkisp1_write(params->rkisp1, - arg->thresh_sh0, RKISP1_CIF_ISP_FILT_THRESH_SH0); - rkisp1_write(params->rkisp1, - arg->thresh_sh1, RKISP1_CIF_ISP_FILT_THRESH_SH1); - rkisp1_write(params->rkisp1, arg->fac_bl0, RKISP1_CIF_ISP_FILT_FAC_BL0); - rkisp1_write(params->rkisp1, arg->fac_bl1, RKISP1_CIF_ISP_FILT_FAC_BL1); - rkisp1_write(params->rkisp1, arg->fac_mid, RKISP1_CIF_ISP_FILT_FAC_MID); - rkisp1_write(params->rkisp1, arg->fac_sh0, RKISP1_CIF_ISP_FILT_FAC_SH0); - rkisp1_write(params->rkisp1, arg->fac_sh1, RKISP1_CIF_ISP_FILT_FAC_SH1); - rkisp1_write(params->rkisp1, - arg->lum_weight, RKISP1_CIF_ISP_FILT_LUM_WEIGHT); - - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_THRESH_BL0, + arg->thresh_bl0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_THRESH_BL1, + arg->thresh_bl1); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_THRESH_SH0, + arg->thresh_sh0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_THRESH_SH1, + arg->thresh_sh1); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_BL0, + arg->fac_bl0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_BL1, + arg->fac_bl1); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_MID, + arg->fac_mid); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_SH0, + arg->fac_sh0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_SH1, + arg->fac_sh1); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_LUM_WEIGHT, + arg->lum_weight); + + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE, (arg->mode ? RKISP1_CIF_ISP_FLT_MODE_DNR : 0) | RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) | RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) | - RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1), - RKISP1_CIF_ISP_FILT_MODE); + RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1)); /* avoid to override the old enable value */ filt_mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE); @@ -414,7 +414,7 @@ static void rkisp1_flt_config(struct rkisp1_params *params, filt_mode |= RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) | RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) | RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1); - rkisp1_write(params->rkisp1, filt_mode, RKISP1_CIF_ISP_FILT_MODE); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE, filt_mode); } /* ISP demosaic interface function */ @@ -428,7 +428,7 @@ static int rkisp1_bdm_config(struct rkisp1_params *params, bdm_th &= RKISP1_CIF_ISP_DEMOSAIC_BYPASS; bdm_th |= arg->demosaic_th & ~RKISP1_CIF_ISP_DEMOSAIC_BYPASS; /* set demosaic threshold */ - rkisp1_write(params->rkisp1, bdm_th, RKISP1_CIF_ISP_DEMOSAIC); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DEMOSAIC, bdm_th); return 0; } @@ -438,18 +438,21 @@ static void rkisp1_sdg_config(struct rkisp1_params *params, { unsigned int i; - rkisp1_write(params->rkisp1, - arg->xa_pnts.gamma_dx0, RKISP1_CIF_ISP_GAMMA_DX_LO); - rkisp1_write(params->rkisp1, - arg->xa_pnts.gamma_dx1, RKISP1_CIF_ISP_GAMMA_DX_HI); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_GAMMA_DX_LO, + arg->xa_pnts.gamma_dx0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_GAMMA_DX_HI, + arg->xa_pnts.gamma_dx1); for (i = 0; i < RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE; i++) { - rkisp1_write(params->rkisp1, arg->curve_r.gamma_y[i], - RKISP1_CIF_ISP_GAMMA_R_Y0 + i * 4); - rkisp1_write(params->rkisp1, arg->curve_g.gamma_y[i], - RKISP1_CIF_ISP_GAMMA_G_Y0 + i * 4); - rkisp1_write(params->rkisp1, arg->curve_b.gamma_y[i], - RKISP1_CIF_ISP_GAMMA_B_Y0 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_GAMMA_R_Y0 + i * 4, + arg->curve_r.gamma_y[i]); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_GAMMA_G_Y0 + i * 4, + arg->curve_g.gamma_y[i]); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_GAMMA_B_Y0 + i * 4, + arg->curve_b.gamma_y[i]); } } @@ -461,11 +464,13 @@ static void rkisp1_goc_config_v10(struct rkisp1_params *params, rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); - rkisp1_write(params->rkisp1, arg->mode, RKISP1_CIF_ISP_GAMMA_OUT_MODE_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_GAMMA_OUT_MODE_V10, + arg->mode); for (i = 0; i < RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V10; i++) - rkisp1_write(params->rkisp1, arg->gamma_y[i], - RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V10 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V10 + i * 4, + arg->gamma_y[i]); } static void rkisp1_goc_config_v12(struct rkisp1_params *params, @@ -476,14 +481,15 @@ static void rkisp1_goc_config_v12(struct rkisp1_params *params, rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); - rkisp1_write(params->rkisp1, arg->mode, RKISP1_CIF_ISP_GAMMA_OUT_MODE_V12); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_GAMMA_OUT_MODE_V12, + arg->mode); for (i = 0; i < RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V12 / 2; i++) { value = RKISP1_CIF_ISP_GAMMA_VALUE_V12( arg->gamma_y[2 * i + 1], arg->gamma_y[2 * i]); - rkisp1_write(params->rkisp1, value, - RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V12 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V12 + i * 4, value); } } @@ -495,11 +501,13 @@ static void rkisp1_ctk_config(struct rkisp1_params *params, for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) - rkisp1_write(params->rkisp1, arg->coeff[i][j], - RKISP1_CIF_ISP_CT_COEFF_0 + 4 * k++); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_CT_COEFF_0 + 4 * k++, + arg->coeff[i][j]); for (i = 0; i < 3; i++) - rkisp1_write(params->rkisp1, arg->ct_offset[i], - RKISP1_CIF_ISP_CT_OFFSET_R + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_CT_OFFSET_R + i * 4, + arg->ct_offset[i]); } static void rkisp1_ctk_enable(struct rkisp1_params *params, bool en) @@ -508,19 +516,19 @@ static void rkisp1_ctk_enable(struct rkisp1_params *params, bool en) return; /* Write back the default values. */ - rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_0); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_1); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_2); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_3); - rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_4); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_5); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_6); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_7); - rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_8); - - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_R); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_G); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_B); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_0, 0x80); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_1, 0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_2, 0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_3, 0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_4, 0x80); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_5, 0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_6, 0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_7, 0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_8, 0x80); + + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_OFFSET_R, 0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_OFFSET_G, 0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_OFFSET_B, 0); } /* ISP White Balance Mode */ @@ -531,15 +539,15 @@ static void rkisp1_awb_meas_config_v10(struct rkisp1_params *params, /* based on the mode,configure the awb module */ if (arg->awb_mode == RKISP1_CIF_ISP_AWB_MODE_YCBCR) { /* Reference Cb and Cr */ - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_REF_V10, RKISP1_CIF_ISP_AWB_REF_CR_SET(arg->awb_ref_cr) | - arg->awb_ref_cb, RKISP1_CIF_ISP_AWB_REF_V10); + arg->awb_ref_cb); /* Yc Threshold */ - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_THRESH_V10, RKISP1_CIF_ISP_AWB_MAX_Y_SET(arg->max_y) | RKISP1_CIF_ISP_AWB_MIN_Y_SET(arg->min_y) | RKISP1_CIF_ISP_AWB_MAX_CS_SET(arg->max_csum) | - arg->min_c, RKISP1_CIF_ISP_AWB_THRESH_V10); + arg->min_c); } reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V10); @@ -547,21 +555,21 @@ static void rkisp1_awb_meas_config_v10(struct rkisp1_params *params, reg_val |= RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; else reg_val &= ~RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; - rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V10, reg_val); /* window offset */ - rkisp1_write(params->rkisp1, - arg->awb_wnd.v_offs, RKISP1_CIF_ISP_AWB_WND_V_OFFS_V10); - rkisp1_write(params->rkisp1, - arg->awb_wnd.h_offs, RKISP1_CIF_ISP_AWB_WND_H_OFFS_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_WND_V_OFFS_V10, + arg->awb_wnd.v_offs); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_WND_H_OFFS_V10, + arg->awb_wnd.h_offs); /* AWB window size */ - rkisp1_write(params->rkisp1, - arg->awb_wnd.v_size, RKISP1_CIF_ISP_AWB_WND_V_SIZE_V10); - rkisp1_write(params->rkisp1, - arg->awb_wnd.h_size, RKISP1_CIF_ISP_AWB_WND_H_SIZE_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_WND_V_SIZE_V10, + arg->awb_wnd.v_size); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_WND_H_SIZE_V10, + arg->awb_wnd.h_size); /* Number of frames */ - rkisp1_write(params->rkisp1, - arg->frames, RKISP1_CIF_ISP_AWB_FRAMES_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_FRAMES_V10, + arg->frames); } static void rkisp1_awb_meas_config_v12(struct rkisp1_params *params, @@ -571,15 +579,15 @@ static void rkisp1_awb_meas_config_v12(struct rkisp1_params *params, /* based on the mode,configure the awb module */ if (arg->awb_mode == RKISP1_CIF_ISP_AWB_MODE_YCBCR) { /* Reference Cb and Cr */ - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_REF_V12, RKISP1_CIF_ISP_AWB_REF_CR_SET(arg->awb_ref_cr) | - arg->awb_ref_cb, RKISP1_CIF_ISP_AWB_REF_V12); + arg->awb_ref_cb); /* Yc Threshold */ - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_THRESH_V12, RKISP1_CIF_ISP_AWB_MAX_Y_SET(arg->max_y) | RKISP1_CIF_ISP_AWB_MIN_Y_SET(arg->min_y) | RKISP1_CIF_ISP_AWB_MAX_CS_SET(arg->max_csum) | - arg->min_c, RKISP1_CIF_ISP_AWB_THRESH_V12); + arg->min_c); } reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V12); @@ -589,18 +597,14 @@ static void rkisp1_awb_meas_config_v12(struct rkisp1_params *params, reg_val &= ~RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; reg_val &= ~RKISP1_CIF_ISP_AWB_SET_FRAMES_MASK_V12; reg_val |= RKISP1_CIF_ISP_AWB_SET_FRAMES_V12(arg->frames); - rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP_V12); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V12, reg_val); /* window offset */ - rkisp1_write(params->rkisp1, - arg->awb_wnd.v_offs << 16 | - arg->awb_wnd.h_offs, - RKISP1_CIF_ISP_AWB_OFFS_V12); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_OFFS_V12, + arg->awb_wnd.v_offs << 16 | arg->awb_wnd.h_offs); /* AWB window size */ - rkisp1_write(params->rkisp1, - arg->awb_wnd.v_size << 16 | - arg->awb_wnd.h_size, - RKISP1_CIF_ISP_AWB_SIZE_V12); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_SIZE_V12, + arg->awb_wnd.v_size << 16 | arg->awb_wnd.h_size); } static void @@ -619,14 +623,15 @@ rkisp1_awb_meas_enable_v10(struct rkisp1_params *params, else reg_val |= RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN; - rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V10, + reg_val); /* Measurements require AWB block be active. */ rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); } else { - rkisp1_write(params->rkisp1, - reg_val, RKISP1_CIF_ISP_AWB_PROP_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V10, + reg_val); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); } @@ -648,14 +653,15 @@ rkisp1_awb_meas_enable_v12(struct rkisp1_params *params, else reg_val |= RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN; - rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP_V12); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V12, + reg_val); /* Measurements require AWB block be active. */ rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); } else { - rkisp1_write(params->rkisp1, - reg_val, RKISP1_CIF_ISP_AWB_PROP_V12); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V12, + reg_val); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); } @@ -665,26 +671,26 @@ static void rkisp1_awb_gain_config_v10(struct rkisp1_params *params, const struct rkisp1_cif_isp_awb_gain_config *arg) { - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_G_V10, RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_green_r) | - arg->gain_green_b, RKISP1_CIF_ISP_AWB_GAIN_G_V10); + arg->gain_green_b); - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_RB_V10, RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_red) | - arg->gain_blue, RKISP1_CIF_ISP_AWB_GAIN_RB_V10); + arg->gain_blue); } static void rkisp1_awb_gain_config_v12(struct rkisp1_params *params, const struct rkisp1_cif_isp_awb_gain_config *arg) { - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_G_V12, RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_green_r) | - arg->gain_green_b, RKISP1_CIF_ISP_AWB_GAIN_G_V12); + arg->gain_green_b); - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_RB_V12, RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_red) | - arg->gain_blue, RKISP1_CIF_ISP_AWB_GAIN_RB_V12); + arg->gain_blue); } static void rkisp1_aec_config_v10(struct rkisp1_params *params, @@ -700,24 +706,22 @@ static void rkisp1_aec_config_v10(struct rkisp1_params *params, exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP; if (arg->mode == RKISP1_CIF_ISP_EXP_MEASURING_MODE_1) exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1; - rkisp1_write(params->rkisp1, exp_ctrl, RKISP1_CIF_ISP_EXP_CTRL); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_CTRL, exp_ctrl); - rkisp1_write(params->rkisp1, - arg->meas_window.h_offs, RKISP1_CIF_ISP_EXP_H_OFFSET_V10); - rkisp1_write(params->rkisp1, - arg->meas_window.v_offs, RKISP1_CIF_ISP_EXP_V_OFFSET_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_H_OFFSET_V10, + arg->meas_window.h_offs); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_V_OFFSET_V10, + arg->meas_window.v_offs); block_hsize = arg->meas_window.h_size / RKISP1_CIF_ISP_EXP_COLUMN_NUM_V10 - 1; block_vsize = arg->meas_window.v_size / RKISP1_CIF_ISP_EXP_ROW_NUM_V10 - 1; - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_EXP_H_SIZE_SET_V10(block_hsize), - RKISP1_CIF_ISP_EXP_H_SIZE_V10); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_EXP_V_SIZE_SET_V10(block_vsize), - RKISP1_CIF_ISP_EXP_V_SIZE_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_H_SIZE_V10, + RKISP1_CIF_ISP_EXP_H_SIZE_SET_V10(block_hsize)); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_V_SIZE_V10, + RKISP1_CIF_ISP_EXP_V_SIZE_SET_V10(block_vsize)); } static void rkisp1_aec_config_v12(struct rkisp1_params *params, @@ -736,20 +740,18 @@ static void rkisp1_aec_config_v12(struct rkisp1_params *params, if (arg->mode == RKISP1_CIF_ISP_EXP_MEASURING_MODE_1) exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1; exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_WNDNUM_SET_V12(wnd_num_idx); - rkisp1_write(params->rkisp1, exp_ctrl, RKISP1_CIF_ISP_EXP_CTRL); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_CTRL, exp_ctrl); - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_OFFS_V12, RKISP1_CIF_ISP_EXP_V_OFFSET_SET_V12(arg->meas_window.v_offs) | - RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V12(arg->meas_window.h_offs), - RKISP1_CIF_ISP_EXP_OFFS_V12); + RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V12(arg->meas_window.h_offs)); block_hsize = arg->meas_window.h_size / ae_wnd_num[wnd_num_idx] - 1; block_vsize = arg->meas_window.v_size / ae_wnd_num[wnd_num_idx] - 1; - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_SIZE_V12, RKISP1_CIF_ISP_EXP_V_SIZE_SET_V12(block_vsize) | - RKISP1_CIF_ISP_EXP_H_SIZE_SET_V12(block_hsize), - RKISP1_CIF_ISP_EXP_SIZE_V12); + RKISP1_CIF_ISP_EXP_H_SIZE_SET_V12(block_hsize)); } static void rkisp1_cproc_config(struct rkisp1_params *params, @@ -762,11 +764,12 @@ static void rkisp1_cproc_config(struct rkisp1_params *params, u32 effect = cur_ie_config->effect; u32 quantization = params->quantization; - rkisp1_write(params->rkisp1, arg->contrast, RKISP1_CIF_C_PROC_CONTRAST); - rkisp1_write(params->rkisp1, arg->hue, RKISP1_CIF_C_PROC_HUE); - rkisp1_write(params->rkisp1, arg->sat, RKISP1_CIF_C_PROC_SATURATION); - rkisp1_write(params->rkisp1, arg->brightness, - RKISP1_CIF_C_PROC_BRIGHTNESS); + rkisp1_write(params->rkisp1, RKISP1_CIF_C_PROC_CONTRAST, + arg->contrast); + rkisp1_write(params->rkisp1, RKISP1_CIF_C_PROC_HUE, arg->hue); + rkisp1_write(params->rkisp1, RKISP1_CIF_C_PROC_SATURATION, arg->sat); + rkisp1_write(params->rkisp1, RKISP1_CIF_C_PROC_BRIGHTNESS, + arg->brightness); if (quantization != V4L2_QUANTIZATION_FULL_RANGE || effect != V4L2_COLORFX_NONE) { @@ -802,31 +805,29 @@ static void rkisp1_hst_config_v10(struct rkisp1_params *params, hist_prop = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_HIST_PROP_V10); hist_prop &= RKISP1_CIF_ISP_HIST_PROP_MODE_MASK_V10; hist_prop |= RKISP1_CIF_ISP_HIST_PREDIV_SET_V10(arg->histogram_predivider); - rkisp1_write(params->rkisp1, hist_prop, RKISP1_CIF_ISP_HIST_PROP_V10); - rkisp1_write(params->rkisp1, - arg->meas_window.h_offs, - RKISP1_CIF_ISP_HIST_H_OFFS_V10); - rkisp1_write(params->rkisp1, - arg->meas_window.v_offs, - RKISP1_CIF_ISP_HIST_V_OFFS_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_PROP_V10, hist_prop); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_H_OFFS_V10, + arg->meas_window.h_offs); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_V_OFFS_V10, + arg->meas_window.v_offs); block_hsize = arg->meas_window.h_size / RKISP1_CIF_ISP_HIST_COLUMN_NUM_V10 - 1; block_vsize = arg->meas_window.v_size / RKISP1_CIF_ISP_HIST_ROW_NUM_V10 - 1; - rkisp1_write(params->rkisp1, block_hsize, RKISP1_CIF_ISP_HIST_H_SIZE_V10); - rkisp1_write(params->rkisp1, block_vsize, RKISP1_CIF_ISP_HIST_V_SIZE_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_H_SIZE_V10, + block_hsize); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_V_SIZE_V10, + block_vsize); weight = arg->hist_weight; for (i = 0; i < ARRAY_SIZE(hist_weight_regs); ++i, weight += 4) - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_HIST_WEIGHT_SET_V10(weight[0], - weight[1], - weight[2], - weight[3]), - hist_weight_regs[i]); + rkisp1_write(params->rkisp1, hist_weight_regs[i], + RKISP1_CIF_ISP_HIST_WEIGHT_SET_V10(weight[0], weight[1], + weight[2], weight[3])); - rkisp1_write(params->rkisp1, weight[0] & 0x1F, RKISP1_CIF_ISP_HIST_WEIGHT_44_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_WEIGHT_44_V10, + weight[0] & 0x1F); } static void rkisp1_hst_config_v12(struct rkisp1_params *params, @@ -852,18 +853,16 @@ static void rkisp1_hst_config_v12(struct rkisp1_params *params, RKISP1_CIF_ISP_HIST_CTRL_AUTOSTOP_SET_V12(0) | RKISP1_CIF_ISP_HIST_CTRL_WNDNUM_SET_V12(1) | RKISP1_CIF_ISP_HIST_CTRL_STEPSIZE_SET_V12(arg->histogram_predivider); - rkisp1_write(params->rkisp1, hist_ctrl, RKISP1_CIF_ISP_HIST_CTRL_V12); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_CTRL_V12, hist_ctrl); - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_OFFS_V12, RKISP1_CIF_ISP_HIST_OFFS_SET_V12(arg->meas_window.h_offs, - arg->meas_window.v_offs), - RKISP1_CIF_ISP_HIST_OFFS_V12); + arg->meas_window.v_offs)); block_hsize = arg->meas_window.h_size / hist_wnd_num[wnd_num_idx] - 1; block_vsize = arg->meas_window.v_size / hist_wnd_num[wnd_num_idx] - 1; - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_HIST_SIZE_SET_V12(block_hsize, block_vsize), - RKISP1_CIF_ISP_HIST_SIZE_V12); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_SIZE_V12, + RKISP1_CIF_ISP_HIST_SIZE_SET_V12(block_hsize, block_vsize)); for (i = 0; i < hist_wnd_num[wnd_num_idx]; i++) { for (j = 0; j < hist_wnd_num[wnd_num_idx]; j++) { @@ -879,12 +878,12 @@ static void rkisp1_hst_config_v12(struct rkisp1_params *params, weight15x15[4 * i + 1], weight15x15[4 * i + 2], weight15x15[4 * i + 3]); - rkisp1_write(params->rkisp1, value, - RKISP1_CIF_ISP_HIST_WEIGHT_V12 + 4 * i); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_HIST_WEIGHT_V12 + 4 * i, value); } value = RKISP1_CIF_ISP_HIST_WEIGHT_SET_V12(weight15x15[4 * i + 0], 0, 0, 0); - rkisp1_write(params->rkisp1, value, - RKISP1_CIF_ISP_HIST_WEIGHT_V12 + 4 * i); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_WEIGHT_V12 + 4 * i, + value); } static void @@ -938,22 +937,20 @@ static void rkisp1_afm_config_v10(struct rkisp1_params *params, RKISP1_CIF_ISP_AFM_ENA); for (i = 0; i < num_of_win; i++) { - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_LT_A + i * 8, RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_offs) | - RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_offs), - RKISP1_CIF_ISP_AFM_LT_A + i * 8); - rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_offs)); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_RB_A + i * 8, RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_size + arg->afm_win[i].h_offs) | RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_size + - arg->afm_win[i].v_offs), - RKISP1_CIF_ISP_AFM_RB_A + i * 8); + arg->afm_win[i].v_offs)); } - rkisp1_write(params->rkisp1, arg->thres, RKISP1_CIF_ISP_AFM_THRES); - rkisp1_write(params->rkisp1, arg->var_shift, - RKISP1_CIF_ISP_AFM_VAR_SHIFT); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_THRES, arg->thres); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_VAR_SHIFT, + arg->var_shift); /* restore afm status */ - rkisp1_write(params->rkisp1, afm_ctrl, RKISP1_CIF_ISP_AFM_CTRL); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_CTRL, afm_ctrl); } static void rkisp1_afm_config_v12(struct rkisp1_params *params, @@ -970,29 +967,26 @@ static void rkisp1_afm_config_v12(struct rkisp1_params *params, RKISP1_CIF_ISP_AFM_ENA); for (i = 0; i < num_of_win; i++) { - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_LT_A + i * 8, RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_offs) | - RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_offs), - RKISP1_CIF_ISP_AFM_LT_A + i * 8); - rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_offs)); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_RB_A + i * 8, RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_size + arg->afm_win[i].h_offs) | RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_size + - arg->afm_win[i].v_offs), - RKISP1_CIF_ISP_AFM_RB_A + i * 8); + arg->afm_win[i].v_offs)); } - rkisp1_write(params->rkisp1, arg->thres, RKISP1_CIF_ISP_AFM_THRES); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_THRES, arg->thres); lum_var_shift = RKISP1_CIF_ISP_AFM_GET_LUM_SHIFT_a_V12(arg->var_shift); afm_var_shift = RKISP1_CIF_ISP_AFM_GET_AFM_SHIFT_a_V12(arg->var_shift); - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_VAR_SHIFT, RKISP1_CIF_ISP_AFM_SET_SHIFT_a_V12(lum_var_shift, afm_var_shift) | RKISP1_CIF_ISP_AFM_SET_SHIFT_b_V12(lum_var_shift, afm_var_shift) | - RKISP1_CIF_ISP_AFM_SET_SHIFT_c_V12(lum_var_shift, afm_var_shift), - RKISP1_CIF_ISP_AFM_VAR_SHIFT); + RKISP1_CIF_ISP_AFM_SET_SHIFT_c_V12(lum_var_shift, afm_var_shift)); /* restore afm status */ - rkisp1_write(params->rkisp1, afm_ctrl, RKISP1_CIF_ISP_AFM_CTRL); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_CTRL, afm_ctrl); } static void rkisp1_ie_config(struct rkisp1_params *params, @@ -1011,8 +1005,8 @@ static void rkisp1_ie_config(struct rkisp1_params *params, eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA; break; case V4L2_COLORFX_SET_CBCR: - rkisp1_write(params->rkisp1, arg->eff_tint, - RKISP1_CIF_IMG_EFF_TINT); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_TINT, + arg->eff_tint); eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA; break; /* @@ -1021,26 +1015,26 @@ static void rkisp1_ie_config(struct rkisp1_params *params, */ case V4L2_COLORFX_AQUA: eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL; - rkisp1_write(params->rkisp1, arg->color_sel, - RKISP1_CIF_IMG_EFF_COLOR_SEL); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_COLOR_SEL, + arg->color_sel); break; case V4L2_COLORFX_EMBOSS: eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS; - rkisp1_write(params->rkisp1, arg->eff_mat_1, - RKISP1_CIF_IMG_EFF_MAT_1); - rkisp1_write(params->rkisp1, arg->eff_mat_2, - RKISP1_CIF_IMG_EFF_MAT_2); - rkisp1_write(params->rkisp1, arg->eff_mat_3, - RKISP1_CIF_IMG_EFF_MAT_3); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_1, + arg->eff_mat_1); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_2, + arg->eff_mat_2); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_3, + arg->eff_mat_3); break; case V4L2_COLORFX_SKETCH: eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH; - rkisp1_write(params->rkisp1, arg->eff_mat_3, - RKISP1_CIF_IMG_EFF_MAT_3); - rkisp1_write(params->rkisp1, arg->eff_mat_4, - RKISP1_CIF_IMG_EFF_MAT_4); - rkisp1_write(params->rkisp1, arg->eff_mat_5, - RKISP1_CIF_IMG_EFF_MAT_5); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_3, + arg->eff_mat_3); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_4, + arg->eff_mat_4); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_5, + arg->eff_mat_5); break; case V4L2_COLORFX_BW: eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE; @@ -1052,23 +1046,23 @@ static void rkisp1_ie_config(struct rkisp1_params *params, break; } - rkisp1_write(params->rkisp1, eff_ctrl, RKISP1_CIF_IMG_EFF_CTRL); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL, eff_ctrl); } static void rkisp1_ie_enable(struct rkisp1_params *params, bool en) { if (en) { - rkisp1_param_set_bits(params, RKISP1_CIF_ICCL, - RKISP1_CIF_ICCL_IE_CLK); - rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL_ENABLE, - RKISP1_CIF_IMG_EFF_CTRL); + rkisp1_param_set_bits(params, RKISP1_CIF_VI_ICCL, + RKISP1_CIF_VI_ICCL_IE_CLK); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL, + RKISP1_CIF_IMG_EFF_CTRL_ENABLE); rkisp1_param_set_bits(params, RKISP1_CIF_IMG_EFF_CTRL, RKISP1_CIF_IMG_EFF_CTRL_CFG_UPD); } else { rkisp1_param_clear_bits(params, RKISP1_CIF_IMG_EFF_CTRL, RKISP1_CIF_IMG_EFF_CTRL_ENABLE); - rkisp1_param_clear_bits(params, RKISP1_CIF_ICCL, - RKISP1_CIF_ICCL_IE_CLK); + rkisp1_param_clear_bits(params, RKISP1_CIF_VI_ICCL, + RKISP1_CIF_VI_ICCL_IE_CLK); } } @@ -1088,16 +1082,18 @@ static void rkisp1_csm_config(struct rkisp1_params *params, bool full_range) if (full_range) { for (i = 0; i < ARRAY_SIZE(full_range_coeff); i++) - rkisp1_write(params->rkisp1, full_range_coeff[i], - RKISP1_CIF_ISP_CC_COEFF_0 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_CC_COEFF_0 + i * 4, + full_range_coeff[i]); rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA | RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA); } else { for (i = 0; i < ARRAY_SIZE(limited_range_coeff); i++) - rkisp1_write(params->rkisp1, limited_range_coeff[i], - RKISP1_CIF_ISP_CC_COEFF_0 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_CC_COEFF_0 + i * 4, + limited_range_coeff[i]); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA | @@ -1152,52 +1148,53 @@ static void rkisp1_dpf_config(struct rkisp1_params *params, rkisp1_param_set_bits(params, RKISP1_CIF_ISP_DPF_MODE, isp_dpf_mode); - rkisp1_write(params->rkisp1, arg->gain.nf_b_gain, - RKISP1_CIF_ISP_DPF_NF_GAIN_B); - rkisp1_write(params->rkisp1, arg->gain.nf_r_gain, - RKISP1_CIF_ISP_DPF_NF_GAIN_R); - rkisp1_write(params->rkisp1, arg->gain.nf_gb_gain, - RKISP1_CIF_ISP_DPF_NF_GAIN_GB); - rkisp1_write(params->rkisp1, arg->gain.nf_gr_gain, - RKISP1_CIF_ISP_DPF_NF_GAIN_GR); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_NF_GAIN_B, + arg->gain.nf_b_gain); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_NF_GAIN_R, + arg->gain.nf_r_gain); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_NF_GAIN_GB, + arg->gain.nf_gb_gain); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_NF_GAIN_GR, + arg->gain.nf_gr_gain); for (i = 0; i < RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS; i++) { - rkisp1_write(params->rkisp1, arg->nll.coeff[i], - RKISP1_CIF_ISP_DPF_NULL_COEFF_0 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_DPF_NULL_COEFF_0 + i * 4, + arg->nll.coeff[i]); } spatial_coeff = arg->g_flt.spatial_coeff[0] | (arg->g_flt.spatial_coeff[1] << 8) | (arg->g_flt.spatial_coeff[2] << 16) | (arg->g_flt.spatial_coeff[3] << 24); - rkisp1_write(params->rkisp1, spatial_coeff, - RKISP1_CIF_ISP_DPF_S_WEIGHT_G_1_4); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_S_WEIGHT_G_1_4, + spatial_coeff); spatial_coeff = arg->g_flt.spatial_coeff[4] | (arg->g_flt.spatial_coeff[5] << 8); - rkisp1_write(params->rkisp1, spatial_coeff, - RKISP1_CIF_ISP_DPF_S_WEIGHT_G_5_6); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_S_WEIGHT_G_5_6, + spatial_coeff); spatial_coeff = arg->rb_flt.spatial_coeff[0] | (arg->rb_flt.spatial_coeff[1] << 8) | (arg->rb_flt.spatial_coeff[2] << 16) | (arg->rb_flt.spatial_coeff[3] << 24); - rkisp1_write(params->rkisp1, spatial_coeff, - RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_1_4); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_1_4, + spatial_coeff); spatial_coeff = arg->rb_flt.spatial_coeff[4] | (arg->rb_flt.spatial_coeff[5] << 8); - rkisp1_write(params->rkisp1, spatial_coeff, - RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6, + spatial_coeff); } static void rkisp1_dpf_strength_config(struct rkisp1_params *params, const struct rkisp1_cif_isp_dpf_strength_config *arg) { - rkisp1_write(params->rkisp1, arg->b, RKISP1_CIF_ISP_DPF_STRENGTH_B); - rkisp1_write(params->rkisp1, arg->g, RKISP1_CIF_ISP_DPF_STRENGTH_G); - rkisp1_write(params->rkisp1, arg->r, RKISP1_CIF_ISP_DPF_STRENGTH_R); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_STRENGTH_B, arg->b); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_STRENGTH_G, arg->g); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_STRENGTH_R, arg->r); } static void @@ -1804,7 +1801,7 @@ static void rkisp1_init_params(struct rkisp1_params *params) params->vdev_fmt.fmt.meta.buffersize = sizeof(struct rkisp1_params_cfg); - if (params->rkisp1->media_dev.hw_revision == RKISP1_V12) + if (params->rkisp1->info->isp_ver == RKISP1_V12) params->ops = &rkisp1_v12_params_ops; else params->ops = &rkisp1_v10_params_ops; @@ -1844,16 +1841,20 @@ int rkisp1_params_register(struct rkisp1_device *rkisp1) node->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); if (ret) - return ret; + goto error; + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret) { dev_err(rkisp1->dev, "failed to register %s, ret=%d\n", vdev->name, ret); - goto err_cleanup_media_entity; + goto error; } + return 0; -err_cleanup_media_entity: + +error: media_entity_cleanup(&vdev->entity); + mutex_destroy(&node->vlock); return ret; } @@ -1863,6 +1864,10 @@ void rkisp1_params_unregister(struct rkisp1_device *rkisp1) struct rkisp1_vdev_node *node = ¶ms->vnode; struct video_device *vdev = &node->vdev; + if (!video_is_registered(vdev)) + return; + vb2_video_unregister_device(vdev); media_entity_cleanup(&vdev->entity); + mutex_destroy(&node->vlock); } diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h index 82f8d33d98b3..dd3e6c38be67 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h @@ -11,7 +11,7 @@ /* ISP_CTRL */ #define RKISP1_CIF_ISP_CTRL_ISP_ENABLE BIT(0) #define RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT (0 << 1) -#define RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656 BIT(1) +#define RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656 (1 << 1) #define RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601 (2 << 1) #define RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601 (3 << 1) #define RKISP1_CIF_ISP_CTRL_ISP_MODE_DATA_MODE (4 << 1) @@ -33,37 +33,37 @@ #define RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW BIT(1) #define RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW BIT(2) #define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_RGGB (0 << 3) -#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_GRBG BIT(3) +#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_GRBG (1 << 3) #define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_GBRG (2 << 3) #define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_BGGR (3 << 3) #define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT(pat) ((pat) << 3) #define RKISP1_CIF_ISP_ACQ_PROP_YCBYCR (0 << 7) -#define RKISP1_CIF_ISP_ACQ_PROP_YCRYCB BIT(7) +#define RKISP1_CIF_ISP_ACQ_PROP_YCRYCB (1 << 7) #define RKISP1_CIF_ISP_ACQ_PROP_CBYCRY (2 << 7) #define RKISP1_CIF_ISP_ACQ_PROP_CRYCBY (3 << 7) #define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL (0 << 9) -#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_EVEN BIT(9) +#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_EVEN (1 << 9) #define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ODD (2 << 9) #define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B (0 << 12) -#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO BIT(12) +#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO (1 << 12) #define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_MSB (2 << 12) #define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO (3 << 12) #define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_MSB (4 << 12) /* VI_DPCL */ #define RKISP1_CIF_VI_DPCL_DMA_JPEG (0 << 0) -#define RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI BIT(0) +#define RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI (1 << 0) #define RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_JPEG (2 << 0) -#define RKISP1_CIF_VI_DPCL_CHAN_MODE_MP BIT(2) +#define RKISP1_CIF_VI_DPCL_CHAN_MODE_MP (1 << 2) #define RKISP1_CIF_VI_DPCL_CHAN_MODE_SP (2 << 2) #define RKISP1_CIF_VI_DPCL_CHAN_MODE_MPSP (3 << 2) #define RKISP1_CIF_VI_DPCL_DMA_SW_SPMUX (0 << 4) -#define RKISP1_CIF_VI_DPCL_DMA_SW_SI BIT(4) +#define RKISP1_CIF_VI_DPCL_DMA_SW_SI (1 << 4) #define RKISP1_CIF_VI_DPCL_DMA_SW_IE (2 << 4) #define RKISP1_CIF_VI_DPCL_DMA_SW_JPEG (3 << 4) #define RKISP1_CIF_VI_DPCL_DMA_SW_ISP (4 << 4) #define RKISP1_CIF_VI_DPCL_IF_SEL_PARALLEL (0 << 8) -#define RKISP1_CIF_VI_DPCL_IF_SEL_SMIA BIT(8) +#define RKISP1_CIF_VI_DPCL_IF_SEL_SMIA (1 << 8) #define RKISP1_CIF_VI_DPCL_IF_SEL_MIPI (2 << 8) #define RKISP1_CIF_VI_DPCL_DMA_IE_MUX_DMA BIT(10) #define RKISP1_CIF_VI_DPCL_DMA_SP_MUX_DMA BIT(11) @@ -112,26 +112,26 @@ #define RKISP1_CIF_MI_SP_AUTOUPDATE_ENABLE BIT(14) #define RKISP1_CIF_MI_LAST_PIXEL_SIG_ENABLE BIT(15) #define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_16 (0 << 16) -#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_32 BIT(16) +#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_32 (1 << 16) #define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_64 (2 << 16) #define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_16 (0 << 18) -#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_32 BIT(18) +#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_32 (1 << 18) #define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_64 (2 << 18) #define RKISP1_CIF_MI_CTRL_INIT_BASE_EN BIT(20) #define RKISP1_CIF_MI_CTRL_INIT_OFFSET_EN BIT(21) #define RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8 (0 << 22) -#define RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA BIT(22) +#define RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA (1 << 22) #define RKISP1_MI_CTRL_MP_WRITE_YUVINT (2 << 22) #define RKISP1_MI_CTRL_MP_WRITE_RAW12 (2 << 22) #define RKISP1_MI_CTRL_SP_WRITE_PLA (0 << 24) -#define RKISP1_MI_CTRL_SP_WRITE_SPLA BIT(24) +#define RKISP1_MI_CTRL_SP_WRITE_SPLA (1 << 24) #define RKISP1_MI_CTRL_SP_WRITE_INT (2 << 24) #define RKISP1_MI_CTRL_SP_INPUT_YUV400 (0 << 26) -#define RKISP1_MI_CTRL_SP_INPUT_YUV420 BIT(26) +#define RKISP1_MI_CTRL_SP_INPUT_YUV420 (1 << 26) #define RKISP1_MI_CTRL_SP_INPUT_YUV422 (2 << 26) #define RKISP1_MI_CTRL_SP_INPUT_YUV444 (3 << 26) #define RKISP1_MI_CTRL_SP_OUTPUT_YUV400 (0 << 28) -#define RKISP1_MI_CTRL_SP_OUTPUT_YUV420 BIT(28) +#define RKISP1_MI_CTRL_SP_OUTPUT_YUV420 (1 << 28) #define RKISP1_MI_CTRL_SP_OUTPUT_YUV422 (2 << 28) #define RKISP1_MI_CTRL_SP_OUTPUT_YUV444 (3 << 28) #define RKISP1_MI_CTRL_SP_OUTPUT_RGB565 (4 << 28) @@ -186,22 +186,22 @@ /* MI_DMA_CTRL */ #define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_16 (0 << 0) -#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_32 BIT(0) +#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_32 (1 << 0) #define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_64 (2 << 0) #define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_16 (0 << 2) -#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_32 BIT(2) +#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_32 (1 << 2) #define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_64 (2 << 2) #define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_PLANAR (0 << 4) -#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_SPLANAR BIT(4) -#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV400 (0 << 6) -#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV420 BIT(6) +#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_SPLANAR (1 << 4) #define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_PACKED (2 << 4) +#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV400 (0 << 6) +#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV420 (1 << 6) #define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV422 (2 << 6) #define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV444 (3 << 6) #define RKISP1_CIF_MI_DMA_CTRL_BYTE_SWAP BIT(8) #define RKISP1_CIF_MI_DMA_CTRL_CONTINUOUS_ENA BIT(9) #define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_NO (0 << 12) -#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_8BIT BIT(12) +#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_8BIT (1 << 12) #define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_16BIT (2 << 12) /* MI_DMA_START */ #define RKISP1_CIF_MI_DMA_START_ENABLE BIT(0) @@ -210,7 +210,7 @@ #define RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP BIT(1) #define RKISP1_CIF_MI_XTD_FMT_CTRL_DMA_CB_CR_SWAP BIT(2) -/* CCL */ +/* VI_CCL */ #define RKISP1_CIF_CCL_CIF_CLK_DIS BIT(2) /* VI_ISP_CLK_CTRL */ #define RKISP1_CIF_CLK_CTRL_ISP_RAW BIT(0) @@ -241,32 +241,32 @@ #define RKISP1_CIF_CLK_CTRL_RSZS BIT(25) #define RKISP1_CIF_CLK_CTRL_MIPI BIT(26) #define RKISP1_CIF_CLK_CTRL_MARVINMI BIT(27) -/* ICCL */ -#define RKISP1_CIF_ICCL_ISP_CLK BIT(0) -#define RKISP1_CIF_ICCL_CP_CLK BIT(1) -#define RKISP1_CIF_ICCL_RES_2 BIT(2) -#define RKISP1_CIF_ICCL_MRSZ_CLK BIT(3) -#define RKISP1_CIF_ICCL_SRSZ_CLK BIT(4) -#define RKISP1_CIF_ICCL_JPEG_CLK BIT(5) -#define RKISP1_CIF_ICCL_MI_CLK BIT(6) -#define RKISP1_CIF_ICCL_RES_7 BIT(7) -#define RKISP1_CIF_ICCL_IE_CLK BIT(8) -#define RKISP1_CIF_ICCL_SIMP_CLK BIT(9) -#define RKISP1_CIF_ICCL_SMIA_CLK BIT(10) -#define RKISP1_CIF_ICCL_MIPI_CLK BIT(11) -#define RKISP1_CIF_ICCL_DCROP_CLK BIT(12) -/* IRCL */ -#define RKISP1_CIF_IRCL_ISP_SW_RST BIT(0) -#define RKISP1_CIF_IRCL_CP_SW_RST BIT(1) -#define RKISP1_CIF_IRCL_YCS_SW_RST BIT(2) -#define RKISP1_CIF_IRCL_MRSZ_SW_RST BIT(3) -#define RKISP1_CIF_IRCL_SRSZ_SW_RST BIT(4) -#define RKISP1_CIF_IRCL_JPEG_SW_RST BIT(5) -#define RKISP1_CIF_IRCL_MI_SW_RST BIT(6) -#define RKISP1_CIF_IRCL_CIF_SW_RST BIT(7) -#define RKISP1_CIF_IRCL_IE_SW_RST BIT(8) -#define RKISP1_CIF_IRCL_SI_SW_RST BIT(9) -#define RKISP1_CIF_IRCL_MIPI_SW_RST BIT(11) +/* VI_ICCL */ +#define RKISP1_CIF_VI_ICCL_ISP_CLK BIT(0) +#define RKISP1_CIF_VI_ICCL_CP_CLK BIT(1) +#define RKISP1_CIF_VI_ICCL_RES_2 BIT(2) +#define RKISP1_CIF_VI_ICCL_MRSZ_CLK BIT(3) +#define RKISP1_CIF_VI_ICCL_SRSZ_CLK BIT(4) +#define RKISP1_CIF_VI_ICCL_JPEG_CLK BIT(5) +#define RKISP1_CIF_VI_ICCL_MI_CLK BIT(6) +#define RKISP1_CIF_VI_ICCL_RES_7 BIT(7) +#define RKISP1_CIF_VI_ICCL_IE_CLK BIT(8) +#define RKISP1_CIF_VI_ICCL_SIMP_CLK BIT(9) +#define RKISP1_CIF_VI_ICCL_SMIA_CLK BIT(10) +#define RKISP1_CIF_VI_ICCL_MIPI_CLK BIT(11) +#define RKISP1_CIF_VI_ICCL_DCROP_CLK BIT(12) +/* VI_IRCL */ +#define RKISP1_CIF_VI_IRCL_ISP_SW_RST BIT(0) +#define RKISP1_CIF_VI_IRCL_CP_SW_RST BIT(1) +#define RKISP1_CIF_VI_IRCL_YCS_SW_RST BIT(2) +#define RKISP1_CIF_VI_IRCL_MRSZ_SW_RST BIT(3) +#define RKISP1_CIF_VI_IRCL_SRSZ_SW_RST BIT(4) +#define RKISP1_CIF_VI_IRCL_JPEG_SW_RST BIT(5) +#define RKISP1_CIF_VI_IRCL_MI_SW_RST BIT(6) +#define RKISP1_CIF_VI_IRCL_CIF_SW_RST BIT(7) +#define RKISP1_CIF_VI_IRCL_IE_SW_RST BIT(8) +#define RKISP1_CIF_VI_IRCL_SI_SW_RST BIT(9) +#define RKISP1_CIF_VI_IRCL_MIPI_SW_RST BIT(11) /* C_PROC_CTR */ #define RKISP1_CIF_C_PROC_CTR_ENABLE BIT(0) @@ -282,10 +282,10 @@ #define RKISP1_CIF_C_PROC_TONE_RESERVED 0xF000 /* DUAL_CROP_CTRL */ #define RKISP1_CIF_DUAL_CROP_MP_MODE_BYPASS (0 << 0) -#define RKISP1_CIF_DUAL_CROP_MP_MODE_YUV BIT(0) +#define RKISP1_CIF_DUAL_CROP_MP_MODE_YUV (1 << 0) #define RKISP1_CIF_DUAL_CROP_MP_MODE_RAW (2 << 0) #define RKISP1_CIF_DUAL_CROP_SP_MODE_BYPASS (0 << 2) -#define RKISP1_CIF_DUAL_CROP_SP_MODE_YUV BIT(2) +#define RKISP1_CIF_DUAL_CROP_SP_MODE_YUV (1 << 2) #define RKISP1_CIF_DUAL_CROP_SP_MODE_RAW (2 << 2) #define RKISP1_CIF_DUAL_CROP_CFG_UPD_PERMANENT BIT(4) #define RKISP1_CIF_DUAL_CROP_CFG_UPD BIT(5) @@ -294,7 +294,7 @@ /* IMG_EFF_CTRL */ #define RKISP1_CIF_IMG_EFF_CTRL_ENABLE BIT(0) #define RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE (0 << 1) -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE BIT(1) +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE (1 << 1) #define RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA (2 << 1) #define RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL (3 << 1) #define RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS (4 << 1) @@ -314,7 +314,7 @@ /* IMG_EFF_COLOR_SEL */ #define RKISP1_CIF_IMG_EFF_COLOR_RGB 0 -#define RKISP1_CIF_IMG_EFF_COLOR_B BIT(0) +#define RKISP1_CIF_IMG_EFF_COLOR_B (1 << 0) #define RKISP1_CIF_IMG_EFF_COLOR_G (2 << 0) #define RKISP1_CIF_IMG_EFF_COLOR_GB (3 << 0) #define RKISP1_CIF_IMG_EFF_COLOR_R (4 << 0) @@ -365,7 +365,7 @@ /* ISP HISTOGRAM CALCULATION : ISP_HIST_PROP */ #define RKISP1_CIF_ISP_HIST_PROP_MODE_DIS_V10 (0 << 0) -#define RKISP1_CIF_ISP_HIST_PROP_MODE_RGB_V10 BIT(0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_RGB_V10 (1 << 0) #define RKISP1_CIF_ISP_HIST_PROP_MODE_RED_V10 (2 << 0) #define RKISP1_CIF_ISP_HIST_PROP_MODE_GREEN_V10 (3 << 0) #define RKISP1_CIF_ISP_HIST_PROP_MODE_BLUE_V10 (4 << 0) @@ -443,6 +443,15 @@ #define RKISP1_CIF_ISP_DEMOSAIC_BYPASS BIT(10) #define RKISP1_CIF_ISP_DEMOSAIC_TH(x) ((x) & 0xFF) +/* ISP_FLAGS_SHD */ +#define RKISP1_CIF_ISP_FLAGS_SHD_ISP_ENABLE_SHD BIT(0) +#define RKISP1_CIF_ISP_FLAGS_SHD_ISP_ENABLE_INFORM_SHD BIT(1) +#define RKISP1_CIF_ISP_FLAGS_SHD_INFORM_FIELD BIT(2) +#define RKISP1_CIF_ISP_FLAGS_SHD_S_DATA_MASK GENMASK(27, 16) +#define RKISP1_CIF_ISP_FLAGS_SHD_S_DATA_SHIFT 16 +#define RKISP1_CIF_ISP_FLAGS_SHD_S_VSYNC BIT(30) +#define RKISP1_CIF_ISP_FLAGS_SHD_S_HSYNC BIT(31) + /* AWB */ /* ISP_AWB_PROP */ #define RKISP1_CIF_ISP_AWB_YMAX_CMP_EN BIT(2) @@ -628,7 +637,7 @@ #define RKISP1_CIF_ISP_BLS_ENA BIT(0) #define RKISP1_CIF_ISP_BLS_MODE_MEASURED BIT(1) #define RKISP1_CIF_ISP_BLS_MODE_FIXED 0 -#define RKISP1_CIF_ISP_BLS_WINDOW_1 BIT(2) +#define RKISP1_CIF_ISP_BLS_WINDOW_1 (1 << 2) #define RKISP1_CIF_ISP_BLS_WINDOW_2 (2 << 2) /* GAMMA-IN */ @@ -676,11 +685,11 @@ /* CIF Registers */ /* =================================================================== */ #define RKISP1_CIF_CTRL_BASE 0x00000000 -#define RKISP1_CIF_CCL (RKISP1_CIF_CTRL_BASE + 0x00000000) +#define RKISP1_CIF_VI_CCL (RKISP1_CIF_CTRL_BASE + 0x00000000) #define RKISP1_CIF_VI_ID (RKISP1_CIF_CTRL_BASE + 0x00000008) #define RKISP1_CIF_VI_ISP_CLK_CTRL_V12 (RKISP1_CIF_CTRL_BASE + 0x0000000C) -#define RKISP1_CIF_ICCL (RKISP1_CIF_CTRL_BASE + 0x00000010) -#define RKISP1_CIF_IRCL (RKISP1_CIF_CTRL_BASE + 0x00000014) +#define RKISP1_CIF_VI_ICCL (RKISP1_CIF_CTRL_BASE + 0x00000010) +#define RKISP1_CIF_VI_IRCL (RKISP1_CIF_CTRL_BASE + 0x00000014) #define RKISP1_CIF_VI_DPCL (RKISP1_CIF_CTRL_BASE + 0x00000018) #define RKISP1_CIF_IMG_EFF_BASE 0x00000200 @@ -894,52 +903,29 @@ #define RKISP1_CIF_DUAL_CROP_S_V_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000040) #define RKISP1_CIF_MRSZ_BASE 0x00000C00 -#define RKISP1_CIF_MRSZ_CTRL (RKISP1_CIF_MRSZ_BASE + 0x00000000) -#define RKISP1_CIF_MRSZ_SCALE_HY (RKISP1_CIF_MRSZ_BASE + 0x00000004) -#define RKISP1_CIF_MRSZ_SCALE_HCB (RKISP1_CIF_MRSZ_BASE + 0x00000008) -#define RKISP1_CIF_MRSZ_SCALE_HCR (RKISP1_CIF_MRSZ_BASE + 0x0000000C) -#define RKISP1_CIF_MRSZ_SCALE_VY (RKISP1_CIF_MRSZ_BASE + 0x00000010) -#define RKISP1_CIF_MRSZ_SCALE_VC (RKISP1_CIF_MRSZ_BASE + 0x00000014) -#define RKISP1_CIF_MRSZ_PHASE_HY (RKISP1_CIF_MRSZ_BASE + 0x00000018) -#define RKISP1_CIF_MRSZ_PHASE_HC (RKISP1_CIF_MRSZ_BASE + 0x0000001C) -#define RKISP1_CIF_MRSZ_PHASE_VY (RKISP1_CIF_MRSZ_BASE + 0x00000020) -#define RKISP1_CIF_MRSZ_PHASE_VC (RKISP1_CIF_MRSZ_BASE + 0x00000024) -#define RKISP1_CIF_MRSZ_SCALE_LUT_ADDR (RKISP1_CIF_MRSZ_BASE + 0x00000028) -#define RKISP1_CIF_MRSZ_SCALE_LUT (RKISP1_CIF_MRSZ_BASE + 0x0000002C) -#define RKISP1_CIF_MRSZ_CTRL_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000030) -#define RKISP1_CIF_MRSZ_SCALE_HY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000034) -#define RKISP1_CIF_MRSZ_SCALE_HCB_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000038) -#define RKISP1_CIF_MRSZ_SCALE_HCR_SHD (RKISP1_CIF_MRSZ_BASE + 0x0000003C) -#define RKISP1_CIF_MRSZ_SCALE_VY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000040) -#define RKISP1_CIF_MRSZ_SCALE_VC_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000044) -#define RKISP1_CIF_MRSZ_PHASE_HY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000048) -#define RKISP1_CIF_MRSZ_PHASE_HC_SHD (RKISP1_CIF_MRSZ_BASE + 0x0000004C) -#define RKISP1_CIF_MRSZ_PHASE_VY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000050) -#define RKISP1_CIF_MRSZ_PHASE_VC_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000054) - #define RKISP1_CIF_SRSZ_BASE 0x00001000 -#define RKISP1_CIF_SRSZ_CTRL (RKISP1_CIF_SRSZ_BASE + 0x00000000) -#define RKISP1_CIF_SRSZ_SCALE_HY (RKISP1_CIF_SRSZ_BASE + 0x00000004) -#define RKISP1_CIF_SRSZ_SCALE_HCB (RKISP1_CIF_SRSZ_BASE + 0x00000008) -#define RKISP1_CIF_SRSZ_SCALE_HCR (RKISP1_CIF_SRSZ_BASE + 0x0000000C) -#define RKISP1_CIF_SRSZ_SCALE_VY (RKISP1_CIF_SRSZ_BASE + 0x00000010) -#define RKISP1_CIF_SRSZ_SCALE_VC (RKISP1_CIF_SRSZ_BASE + 0x00000014) -#define RKISP1_CIF_SRSZ_PHASE_HY (RKISP1_CIF_SRSZ_BASE + 0x00000018) -#define RKISP1_CIF_SRSZ_PHASE_HC (RKISP1_CIF_SRSZ_BASE + 0x0000001C) -#define RKISP1_CIF_SRSZ_PHASE_VY (RKISP1_CIF_SRSZ_BASE + 0x00000020) -#define RKISP1_CIF_SRSZ_PHASE_VC (RKISP1_CIF_SRSZ_BASE + 0x00000024) -#define RKISP1_CIF_SRSZ_SCALE_LUT_ADDR (RKISP1_CIF_SRSZ_BASE + 0x00000028) -#define RKISP1_CIF_SRSZ_SCALE_LUT (RKISP1_CIF_SRSZ_BASE + 0x0000002C) -#define RKISP1_CIF_SRSZ_CTRL_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000030) -#define RKISP1_CIF_SRSZ_SCALE_HY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000034) -#define RKISP1_CIF_SRSZ_SCALE_HCB_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000038) -#define RKISP1_CIF_SRSZ_SCALE_HCR_SHD (RKISP1_CIF_SRSZ_BASE + 0x0000003C) -#define RKISP1_CIF_SRSZ_SCALE_VY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000040) -#define RKISP1_CIF_SRSZ_SCALE_VC_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000044) -#define RKISP1_CIF_SRSZ_PHASE_HY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000048) -#define RKISP1_CIF_SRSZ_PHASE_HC_SHD (RKISP1_CIF_SRSZ_BASE + 0x0000004C) -#define RKISP1_CIF_SRSZ_PHASE_VY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000050) -#define RKISP1_CIF_SRSZ_PHASE_VC_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000054) +#define RKISP1_CIF_RSZ_CTRL 0x0000 +#define RKISP1_CIF_RSZ_SCALE_HY 0x0004 +#define RKISP1_CIF_RSZ_SCALE_HCB 0x0008 +#define RKISP1_CIF_RSZ_SCALE_HCR 0x000C +#define RKISP1_CIF_RSZ_SCALE_VY 0x0010 +#define RKISP1_CIF_RSZ_SCALE_VC 0x0014 +#define RKISP1_CIF_RSZ_PHASE_HY 0x0018 +#define RKISP1_CIF_RSZ_PHASE_HC 0x001C +#define RKISP1_CIF_RSZ_PHASE_VY 0x0020 +#define RKISP1_CIF_RSZ_PHASE_VC 0x0024 +#define RKISP1_CIF_RSZ_SCALE_LUT_ADDR 0x0028 +#define RKISP1_CIF_RSZ_SCALE_LUT 0x002C +#define RKISP1_CIF_RSZ_CTRL_SHD 0x0030 +#define RKISP1_CIF_RSZ_SCALE_HY_SHD 0x0034 +#define RKISP1_CIF_RSZ_SCALE_HCB_SHD 0x0038 +#define RKISP1_CIF_RSZ_SCALE_HCR_SHD 0x003C +#define RKISP1_CIF_RSZ_SCALE_VY_SHD 0x0040 +#define RKISP1_CIF_RSZ_SCALE_VC_SHD 0x0044 +#define RKISP1_CIF_RSZ_PHASE_HY_SHD 0x0048 +#define RKISP1_CIF_RSZ_PHASE_HC_SHD 0x004C +#define RKISP1_CIF_RSZ_PHASE_VY_SHD 0x0050 +#define RKISP1_CIF_RSZ_PHASE_VC_SHD 0x0054 #define RKISP1_CIF_MI_BASE 0x00001400 #define RKISP1_CIF_MI_CTRL (RKISP1_CIF_MI_BASE + 0x00000000) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index 2070f4b06705..f4caa8f684aa 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -61,30 +61,6 @@ struct rkisp1_rsz_config { /* registers */ struct { u32 ctrl; - u32 ctrl_shd; - u32 scale_hy; - u32 scale_hcr; - u32 scale_hcb; - u32 scale_vy; - u32 scale_vc; - u32 scale_lut; - u32 scale_lut_addr; - u32 scale_hy_shd; - u32 scale_hcr_shd; - u32 scale_hcb_shd; - u32 scale_vy_shd; - u32 scale_vc_shd; - u32 phase_hy; - u32 phase_hc; - u32 phase_vy; - u32 phase_vc; - u32 phase_hy_shd; - u32 phase_hc_shd; - u32 phase_vy_shd; - u32 phase_vc_shd; - } rsz; - struct { - u32 ctrl; u32 yuvmode_mask; u32 rawmode_mask; u32 h_offset; @@ -101,30 +77,6 @@ static const struct rkisp1_rsz_config rkisp1_rsz_config_mp = { .min_rsz_width = RKISP1_RSZ_SRC_MIN_WIDTH, .min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT, /* registers */ - .rsz = { - .ctrl = RKISP1_CIF_MRSZ_CTRL, - .scale_hy = RKISP1_CIF_MRSZ_SCALE_HY, - .scale_hcr = RKISP1_CIF_MRSZ_SCALE_HCR, - .scale_hcb = RKISP1_CIF_MRSZ_SCALE_HCB, - .scale_vy = RKISP1_CIF_MRSZ_SCALE_VY, - .scale_vc = RKISP1_CIF_MRSZ_SCALE_VC, - .scale_lut = RKISP1_CIF_MRSZ_SCALE_LUT, - .scale_lut_addr = RKISP1_CIF_MRSZ_SCALE_LUT_ADDR, - .scale_hy_shd = RKISP1_CIF_MRSZ_SCALE_HY_SHD, - .scale_hcr_shd = RKISP1_CIF_MRSZ_SCALE_HCR_SHD, - .scale_hcb_shd = RKISP1_CIF_MRSZ_SCALE_HCB_SHD, - .scale_vy_shd = RKISP1_CIF_MRSZ_SCALE_VY_SHD, - .scale_vc_shd = RKISP1_CIF_MRSZ_SCALE_VC_SHD, - .phase_hy = RKISP1_CIF_MRSZ_PHASE_HY, - .phase_hc = RKISP1_CIF_MRSZ_PHASE_HC, - .phase_vy = RKISP1_CIF_MRSZ_PHASE_VY, - .phase_vc = RKISP1_CIF_MRSZ_PHASE_VC, - .ctrl_shd = RKISP1_CIF_MRSZ_CTRL_SHD, - .phase_hy_shd = RKISP1_CIF_MRSZ_PHASE_HY_SHD, - .phase_hc_shd = RKISP1_CIF_MRSZ_PHASE_HC_SHD, - .phase_vy_shd = RKISP1_CIF_MRSZ_PHASE_VY_SHD, - .phase_vc_shd = RKISP1_CIF_MRSZ_PHASE_VC_SHD, - }, .dual_crop = { .ctrl = RKISP1_CIF_DUAL_CROP_CTRL, .yuvmode_mask = RKISP1_CIF_DUAL_CROP_MP_MODE_YUV, @@ -143,30 +95,6 @@ static const struct rkisp1_rsz_config rkisp1_rsz_config_sp = { .min_rsz_width = RKISP1_RSZ_SRC_MIN_WIDTH, .min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT, /* registers */ - .rsz = { - .ctrl = RKISP1_CIF_SRSZ_CTRL, - .scale_hy = RKISP1_CIF_SRSZ_SCALE_HY, - .scale_hcr = RKISP1_CIF_SRSZ_SCALE_HCR, - .scale_hcb = RKISP1_CIF_SRSZ_SCALE_HCB, - .scale_vy = RKISP1_CIF_SRSZ_SCALE_VY, - .scale_vc = RKISP1_CIF_SRSZ_SCALE_VC, - .scale_lut = RKISP1_CIF_SRSZ_SCALE_LUT, - .scale_lut_addr = RKISP1_CIF_SRSZ_SCALE_LUT_ADDR, - .scale_hy_shd = RKISP1_CIF_SRSZ_SCALE_HY_SHD, - .scale_hcr_shd = RKISP1_CIF_SRSZ_SCALE_HCR_SHD, - .scale_hcb_shd = RKISP1_CIF_SRSZ_SCALE_HCB_SHD, - .scale_vy_shd = RKISP1_CIF_SRSZ_SCALE_VY_SHD, - .scale_vc_shd = RKISP1_CIF_SRSZ_SCALE_VC_SHD, - .phase_hy = RKISP1_CIF_SRSZ_PHASE_HY, - .phase_hc = RKISP1_CIF_SRSZ_PHASE_HC, - .phase_vy = RKISP1_CIF_SRSZ_PHASE_VY, - .phase_vc = RKISP1_CIF_SRSZ_PHASE_VC, - .ctrl_shd = RKISP1_CIF_SRSZ_CTRL_SHD, - .phase_hy_shd = RKISP1_CIF_SRSZ_PHASE_HY_SHD, - .phase_hc_shd = RKISP1_CIF_SRSZ_PHASE_HC_SHD, - .phase_vy_shd = RKISP1_CIF_SRSZ_PHASE_VY_SHD, - .phase_vc_shd = RKISP1_CIF_SRSZ_PHASE_VC_SHD, - }, .dual_crop = { .ctrl = RKISP1_CIF_DUAL_CROP_CTRL, .yuvmode_mask = RKISP1_CIF_DUAL_CROP_SP_MODE_YUV, @@ -178,6 +106,17 @@ static const struct rkisp1_rsz_config rkisp1_rsz_config_sp = { }, }; +static inline u32 rkisp1_rsz_read(struct rkisp1_resizer *rsz, u32 offset) +{ + return rkisp1_read(rsz->rkisp1, rsz->regs_base + offset); +} + +static inline void rkisp1_rsz_write(struct rkisp1_resizer *rsz, u32 offset, + u32 value) +{ + rkisp1_write(rsz->rkisp1, rsz->regs_base + offset, value); +} + static struct v4l2_mbus_framefmt * rkisp1_rsz_get_pad_fmt(struct rkisp1_resizer *rsz, struct v4l2_subdev_state *sd_state, @@ -222,7 +161,7 @@ static void rkisp1_dcrop_disable(struct rkisp1_resizer *rsz, dc_ctrl |= RKISP1_CIF_DUAL_CROP_GEN_CFG_UPD; else dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD; - rkisp1_write(rsz->rkisp1, dc_ctrl, rsz->config->dual_crop.ctrl); + rkisp1_write(rsz->rkisp1, rsz->config->dual_crop.ctrl, dc_ctrl); } /* configure dual-crop unit */ @@ -247,13 +186,13 @@ static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz) } dc_ctrl = rkisp1_read(rkisp1, rsz->config->dual_crop.ctrl); - rkisp1_write(rkisp1, sink_crop->left, rsz->config->dual_crop.h_offset); - rkisp1_write(rkisp1, sink_crop->top, rsz->config->dual_crop.v_offset); - rkisp1_write(rkisp1, sink_crop->width, rsz->config->dual_crop.h_size); - rkisp1_write(rkisp1, sink_crop->height, rsz->config->dual_crop.v_size); + rkisp1_write(rkisp1, rsz->config->dual_crop.h_offset, sink_crop->left); + rkisp1_write(rkisp1, rsz->config->dual_crop.v_offset, sink_crop->top); + rkisp1_write(rkisp1, rsz->config->dual_crop.h_size, sink_crop->width); + rkisp1_write(rkisp1, rsz->config->dual_crop.v_size, sink_crop->height); dc_ctrl |= rsz->config->dual_crop.yuvmode_mask; dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD; - rkisp1_write(rkisp1, dc_ctrl, rsz->config->dual_crop.ctrl); + rkisp1_write(rkisp1, rsz->config->dual_crop.ctrl, dc_ctrl); dev_dbg(rkisp1->dev, "stream %d crop: %dx%d -> %dx%d\n", rsz->id, sink_fmt->width, sink_fmt->height, @@ -264,52 +203,17 @@ static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz) * Resizer hw configs */ -static void rkisp1_rsz_dump_regs(struct rkisp1_resizer *rsz) -{ - dev_dbg(rsz->rkisp1->dev, - "RSZ_CTRL 0x%08x/0x%08x\n" - "RSZ_SCALE_HY %d/%d\n" - "RSZ_SCALE_HCB %d/%d\n" - "RSZ_SCALE_HCR %d/%d\n" - "RSZ_SCALE_VY %d/%d\n" - "RSZ_SCALE_VC %d/%d\n" - "RSZ_PHASE_HY %d/%d\n" - "RSZ_PHASE_HC %d/%d\n" - "RSZ_PHASE_VY %d/%d\n" - "RSZ_PHASE_VC %d/%d\n", - rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hy), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hy_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcb), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcb_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcr), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcr_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vy), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vy_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vc), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vc_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hy), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hy_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hc), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hc_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vy), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vy_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vc), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vc_shd)); -} - static void rkisp1_rsz_update_shadow(struct rkisp1_resizer *rsz, enum rkisp1_shadow_regs_when when) { - u32 ctrl_cfg = rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl); + u32 ctrl_cfg = rkisp1_rsz_read(rsz, RKISP1_CIF_RSZ_CTRL); if (when == RKISP1_SHADOW_REGS_ASYNC) ctrl_cfg |= RKISP1_CIF_RSZ_CTRL_CFG_UPD_AUTO; else ctrl_cfg |= RKISP1_CIF_RSZ_CTRL_CFG_UPD; - rkisp1_write(rsz->rkisp1, ctrl_cfg, rsz->config->rsz.ctrl); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_CTRL, ctrl_cfg); } static u32 rkisp1_rsz_calc_ratio(u32 len_sink, u32 len_src) @@ -325,7 +229,7 @@ static u32 rkisp1_rsz_calc_ratio(u32 len_sink, u32 len_src) static void rkisp1_rsz_disable(struct rkisp1_resizer *rsz, enum rkisp1_shadow_regs_when when) { - rkisp1_write(rsz->rkisp1, 0, rsz->config->rsz.ctrl); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_CTRL, 0); if (when == RKISP1_SHADOW_REGS_SYNC) rkisp1_rsz_update_shadow(rsz, when); @@ -338,20 +242,19 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, struct v4l2_rect *src_c, enum rkisp1_shadow_regs_when when) { - struct rkisp1_device *rkisp1 = rsz->rkisp1; u32 ratio, rsz_ctrl = 0; unsigned int i; /* No phase offset */ - rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_hy); - rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_hc); - rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_vy); - rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_vc); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_PHASE_HY, 0); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_PHASE_HC, 0); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_PHASE_VY, 0); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_PHASE_VC, 0); /* Linear interpolation */ for (i = 0; i < 64; i++) { - rkisp1_write(rkisp1, i, rsz->config->rsz.scale_lut_addr); - rkisp1_write(rkisp1, i, rsz->config->rsz.scale_lut); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_LUT_ADDR, i); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_LUT, i); } if (sink_y->width != src_y->width) { @@ -359,7 +262,7 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, if (sink_y->width < src_y->width) rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HY_UP; ratio = rkisp1_rsz_calc_ratio(sink_y->width, src_y->width); - rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hy); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_HY, ratio); } if (sink_c->width != src_c->width) { @@ -367,8 +270,8 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, if (sink_c->width < src_c->width) rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HC_UP; ratio = rkisp1_rsz_calc_ratio(sink_c->width, src_c->width); - rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hcb); - rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hcr); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_HCB, ratio); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_HCR, ratio); } if (sink_y->height != src_y->height) { @@ -376,7 +279,7 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, if (sink_y->height < src_y->height) rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VY_UP; ratio = rkisp1_rsz_calc_ratio(sink_y->height, src_y->height); - rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_vy); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_VY, ratio); } if (sink_c->height != src_c->height) { @@ -384,10 +287,10 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, if (sink_c->height < src_c->height) rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VC_UP; ratio = rkisp1_rsz_calc_ratio(sink_c->height, src_c->height); - rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_vc); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_VC, ratio); } - rkisp1_write(rkisp1, rsz_ctrl, rsz->config->rsz.ctrl); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_CTRL, rsz_ctrl); rkisp1_rsz_update_shadow(rsz, when); } @@ -448,8 +351,6 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, /* set values in the hw */ rkisp1_rsz_config_regs(rsz, &sink_y, &sink_c, &src_y, &src_c, when); - - rkisp1_rsz_dump_regs(rsz); } /* ---------------------------------------------------------------------------- @@ -532,14 +433,14 @@ static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz, struct v4l2_mbus_framefmt *format, unsigned int which) { - const struct rkisp1_isp_mbus_info *sink_mbus_info; + const struct rkisp1_mbus_info *sink_mbus_info; struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SINK, which); src_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SRC, which); - sink_mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + sink_mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); /* for YUV formats, userspace can change the mbus code on the src pad if it is supported */ if (sink_mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV && @@ -561,7 +462,7 @@ static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz, struct v4l2_rect *r, unsigned int which) { - const struct rkisp1_isp_mbus_info *mbus_info; + const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_rect *sink_crop; @@ -572,7 +473,7 @@ static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz, which); /* Not crop for MP bayer raw data */ - mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); if (rsz->id == RKISP1_MAINPATH && mbus_info->pixel_enc == V4L2_PIXEL_ENC_BAYER) { @@ -599,7 +500,7 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, struct v4l2_mbus_framefmt *format, unsigned int which) { - const struct rkisp1_isp_mbus_info *mbus_info; + const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; struct v4l2_rect *sink_crop; @@ -615,10 +516,10 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, else sink_fmt->code = format->code; - mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SRC)) { sink_fmt->code = RKISP1_DEF_FMT; - mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); } if (which == V4L2_SUBDEV_FORMAT_ACTIVE) rsz->pixel_enc = mbus_info->pixel_enc; @@ -782,8 +683,12 @@ static const struct v4l2_subdev_ops rkisp1_rsz_ops = { static void rkisp1_rsz_unregister(struct rkisp1_resizer *rsz) { + if (!rsz->rkisp1) + return; + v4l2_device_unregister_subdev(&rsz->sd); media_entity_cleanup(&rsz->sd.entity); + mutex_destroy(&rsz->ops_lock); } static int rkisp1_rsz_register(struct rkisp1_resizer *rsz) @@ -799,10 +704,13 @@ static int rkisp1_rsz_register(struct rkisp1_resizer *rsz) struct v4l2_subdev *sd = &rsz->sd; int ret; - if (rsz->id == RKISP1_SELFPATH) + if (rsz->id == RKISP1_SELFPATH) { + rsz->regs_base = RKISP1_CIF_SRSZ_BASE; rsz->config = &rkisp1_rsz_config_sp; - else + } else { + rsz->regs_base = RKISP1_CIF_MRSZ_BASE; rsz->config = &rkisp1_rsz_config_mp; + } v4l2_subdev_init(sd, &rkisp1_rsz_ops); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; @@ -821,47 +729,43 @@ static int rkisp1_rsz_register(struct rkisp1_resizer *rsz) mutex_init(&rsz->ops_lock); ret = media_entity_pads_init(&sd->entity, RKISP1_RSZ_PAD_MAX, pads); if (ret) - return ret; + goto error; ret = v4l2_device_register_subdev(&rsz->rkisp1->v4l2_dev, sd); if (ret) { dev_err(sd->dev, "Failed to register resizer subdev\n"); - goto err_cleanup_media_entity; + goto error; } rkisp1_rsz_init_config(sd, &state); return 0; -err_cleanup_media_entity: +error: media_entity_cleanup(&sd->entity); - + mutex_destroy(&rsz->ops_lock); return ret; } int rkisp1_resizer_devs_register(struct rkisp1_device *rkisp1) { - struct rkisp1_resizer *rsz; - unsigned int i, j; + unsigned int i; int ret; for (i = 0; i < ARRAY_SIZE(rkisp1->resizer_devs); i++) { - rsz = &rkisp1->resizer_devs[i]; + struct rkisp1_resizer *rsz = &rkisp1->resizer_devs[i]; + rsz->rkisp1 = rkisp1; rsz->id = i; + ret = rkisp1_rsz_register(rsz); - if (ret) - goto err_unreg_resizer_devs; + if (ret) { + rsz->rkisp1 = NULL; + rkisp1_resizer_devs_unregister(rkisp1); + return ret; + } } return 0; - -err_unreg_resizer_devs: - for (j = 0; j < i; j++) { - rsz = &rkisp1->resizer_devs[j]; - rkisp1_rsz_unregister(rsz); - } - - return ret; } void rkisp1_resizer_devs_unregister(struct rkisp1_device *rkisp1) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c index be5777c65bfb..2795eef91bdd 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c @@ -305,7 +305,7 @@ static void rkisp1_stats_get_bls_meas(struct rkisp1_stats *stats, struct rkisp1_stat_buffer *pbuf) { struct rkisp1_device *rkisp1 = stats->rkisp1; - const struct rkisp1_isp_mbus_info *in_fmt = rkisp1->isp.sink_fmt; + const struct rkisp1_mbus_info *in_fmt = rkisp1->isp.sink_fmt; struct rkisp1_cif_isp_bls_meas_val *bls_val; bls_val = &pbuf->params.ae.bls_val; @@ -408,7 +408,7 @@ void rkisp1_stats_isr(struct rkisp1_stats *stats, u32 isp_ris) spin_lock(&stats->lock); - rkisp1_write(rkisp1, RKISP1_STATS_MEAS_MASK, RKISP1_CIF_ISP_ICR); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, RKISP1_STATS_MEAS_MASK); isp_mis_tmp = rkisp1_read(rkisp1, RKISP1_CIF_ISP_MIS); if (isp_mis_tmp & RKISP1_STATS_MEAS_MASK) @@ -427,7 +427,7 @@ static void rkisp1_init_stats(struct rkisp1_stats *stats) stats->vdev_fmt.fmt.meta.buffersize = sizeof(struct rkisp1_stat_buffer); - if (stats->rkisp1->media_dev.hw_revision == RKISP1_V12) + if (stats->rkisp1->info->isp_ver == RKISP1_V12) stats->ops = &rkisp1_v12_stats_ops; else stats->ops = &rkisp1_v10_stats_ops; @@ -463,21 +463,21 @@ int rkisp1_stats_register(struct rkisp1_device *rkisp1) node->pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); if (ret) - goto err_mutex_destroy; + goto error; ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret) { dev_err(&vdev->dev, "failed to register %s, ret=%d\n", vdev->name, ret); - goto err_cleanup_media_entity; + goto error; } return 0; -err_cleanup_media_entity: +error: media_entity_cleanup(&vdev->entity); -err_mutex_destroy: mutex_destroy(&node->vlock); + stats->rkisp1 = NULL; return ret; } @@ -487,6 +487,9 @@ void rkisp1_stats_unregister(struct rkisp1_device *rkisp1) struct rkisp1_vdev_node *node = &stats->vnode; struct video_device *vdev = &node->vdev; + if (!stats->rkisp1) + return; + vb2_video_unregister_device(vdev); media_entity_cleanup(&vdev->entity); mutex_destroy(&node->vlock); diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-core.c b/drivers/media/platform/samsung/exynos-gsc/gsc-core.c index e3559b047092..b147c645ae0b 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-core.c @@ -339,8 +339,7 @@ static int get_plane_info(struct gsc_frame *frm, u32 addr, u32 *index, u32 *ret_ void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm) { - u32 f_chk_addr, f_chk_len, s_chk_addr, s_chk_len; - f_chk_addr = f_chk_len = s_chk_addr = s_chk_len = 0; + u32 f_chk_addr, f_chk_len, s_chk_addr = 0, s_chk_len = 0; f_chk_addr = frm->addr.y; f_chk_len = frm->payload[0]; diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-core.h b/drivers/media/platform/samsung/exynos-gsc/gsc-core.h index e894e85e84a4..1ea5fa1bf3c8 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-core.h @@ -222,7 +222,7 @@ struct gsc_m2m_device { * @org_scaler_input_w: max pixel width when the scaler is enabled * @org_scaler_input_h: max pixel height when the scaler is enabled * @real_rot_dis_w: max pixel src cropped height with the rotator is off - * @real_rot_dis_h: max pixel src croppped width with the rotator is off + * @real_rot_dis_h: max pixel src cropped width with the rotator is off * @real_rot_en_w: max pixel src cropped width with the rotator is on * @real_rot_en_h: max pixel src cropped height with the rotator is on * @target_rot_dis_w: max pixel dst scaled width with the rotator is off diff --git a/drivers/media/platform/samsung/exynos4-is/common.c b/drivers/media/platform/samsung/exynos4-is/common.c index 26ee2388edfd..e41333535eac 100644 --- a/drivers/media/platform/samsung/exynos4-is/common.c +++ b/drivers/media/platform/samsung/exynos4-is/common.c @@ -21,7 +21,7 @@ struct v4l2_subdev *fimc_find_remote_sensor(struct media_entity *entity) while (pad->flags & MEDIA_PAD_FL_SINK) { /* source pad */ - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c index 7ff4024003f4..03638c8f772d 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c @@ -737,7 +737,7 @@ static struct media_entity *fimc_pipeline_get_head(struct media_entity *me) struct media_pad *pad = &me->pads[0]; while (!(pad->flags & MEDIA_PAD_FL_SOURCE)) { - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad) break; me = pad->entity; @@ -810,7 +810,7 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx, return ret; } - pad = media_entity_remote_pad(&me->pads[sfmt.pad]); + pad = media_pad_remote_pad_first(&me->pads[sfmt.pad]); if (!pad) return -EINVAL; me = pad->entity; @@ -1115,7 +1115,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc) if (p->flags & MEDIA_PAD_FL_SINK) { sink_pad = p; - src_pad = media_entity_remote_pad(sink_pad); + src_pad = media_pad_remote_pad_first(sink_pad); if (src_pad) break; } diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h b/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h index da36b48b8f9f..9dcbb9853ac0 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h +++ b/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h @@ -116,7 +116,7 @@ enum fimc_is_error { ERROR_COMMON_PARAMETER = 2, /* Invalid parameter */ /* setfile is not loaded before adjusting */ ERROR_COMMON_SETFILE_LOAD = 3, - /* setfile is not Adjusted before runnng. */ + /* setfile is not Adjusted before running. */ ERROR_COMMON_SETFILE_ADJUST = 4, /* Index of setfile is not valid (0~MAX_SETFILE_NUM-1) */ ERROR_COMMON_SETFILE_INDEX = 5, diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c index 83688a7982f7..8f12240b0eb7 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c @@ -465,7 +465,7 @@ static int isp_video_pipeline_validate(struct fimc_isp *isp) return -EPIPE; /* Retrieve format at the source pad */ - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c index 1a396b7cd9a9..41b0a4a5929a 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c @@ -789,7 +789,7 @@ static int fimc_pipeline_validate(struct fimc_lite *fimc) return -EPIPE; } /* Retrieve format at the source pad */ - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.c b/drivers/media/platform/samsung/exynos4-is/media-dev.c index 544b54e428c9..52b43ea04030 100644 --- a/drivers/media/platform/samsung/exynos4-is/media-dev.c +++ b/drivers/media/platform/samsung/exynos4-is/media-dev.c @@ -81,7 +81,7 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_pad *spad = &me->pads[i]; if (!(spad->flags & MEDIA_PAD_FL_SINK)) continue; - pad = media_entity_remote_pad(spad); + pad = media_pad_remote_pad_first(spad); if (pad) break; } diff --git a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c index 27a214936cb0..6a0d35f33e8c 100644 --- a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c @@ -124,7 +124,7 @@ static char *csi_clock_name[] = { #define DEFAULT_SCLK_CSIS_FREQ 166000000UL static const char * const csis_supply_name[] = { - "vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) suppply */ + "vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) supply */ "vddio", /* CSIS I/O and PLL (1.8V) supply */ }; #define CSIS_NUM_SUPPLIES ARRAY_SIZE(csis_supply_name) diff --git a/drivers/media/platform/samsung/s3c-camif/camif-capture.c b/drivers/media/platform/samsung/s3c-camif/camif-capture.c index 140854ab4dd8..c2d8f1e425d8 100644 --- a/drivers/media/platform/samsung/s3c-camif/camif-capture.c +++ b/drivers/media/platform/samsung/s3c-camif/camif-capture.c @@ -811,7 +811,7 @@ static int camif_pipeline_validate(struct camif_dev *camif) int ret; /* Retrieve format at the sensor subdev source pad */ - pad = media_entity_remote_pad(&camif->pads[0]); + pad = media_pad_remote_pad_first(&camif->pads[0]); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) return -EPIPE; diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c index 456287186ad8..55814041b8d8 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c @@ -1709,7 +1709,7 @@ static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx, w_ratio = ctx->out_q.w / r->width; h_ratio = ctx->out_q.h / r->height; - scale_factor = w_ratio > h_ratio ? w_ratio : h_ratio; + scale_factor = max(w_ratio, h_ratio); scale_factor = clamp_val(scale_factor, 1, 8); /* Align scale ratio to the nearest power of 2 */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c index 72a901e99450..187849841a28 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c @@ -88,7 +88,6 @@ int s5p_mfc_power_on(void) if (ret < 0) { mfc_err("clock prepare failed for clock: %s\n", pm->clk_names[i]); - i++; goto err; } } @@ -98,7 +97,7 @@ int s5p_mfc_power_on(void) return 0; err: - while (--i > 0) + while (--i >= 0) clk_disable_unprepare(pm->clocks[i]); pm_runtime_put(pm->device); return ret; diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c index 7bb1384e4bad..cefe6b7bfdc4 100644 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c @@ -107,7 +107,7 @@ static void channel_swdemux_tsklet(struct tasklet_struct *t) size, DMA_FROM_DEVICE); - buf = (u8 *) channel->back_buffer_aligned; + buf = channel->back_buffer_aligned; dev_dbg(fei->dev, "chan=%d channel=%p num_packets = %d, buf = %p, pos = 0x%x\n\trp=0x%lx, wp=0x%lx\n", @@ -176,7 +176,7 @@ static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed) channel = fei->channel_data[stdemux->tsin_index]; - bitmap = (unsigned long *) channel->pid_buffer_aligned; + bitmap = channel->pid_buffer_aligned; /* 8192 is a special PID */ if (dvbdmxfeed->pid == 8192) { @@ -272,7 +272,7 @@ static int c8sectpfe_stop_feed(struct dvb_demux_feed *dvbdmxfeed) channel = fei->channel_data[stdemux->tsin_index]; - bitmap = (unsigned long *) channel->pid_buffer_aligned; + bitmap = channel->pid_buffer_aligned; if (dvbdmxfeed->pid == 8192) { tmp = readl(fei->io + C8SECTPFE_IB_PID_SET(channel->tsin_id)); @@ -333,8 +333,7 @@ static int c8sectpfe_stop_feed(struct dvb_demux_feed *dvbdmxfeed) __func__, __LINE__, stdemux, channel->tsin_id); /* turn off all PIDS in the bitmap */ - memset((void *)channel->pid_buffer_aligned - , 0x00, PID_TABLE_SIZE); + memset(channel->pid_buffer_aligned, 0, PID_TABLE_SIZE); /* manage cache so data is visible to HW */ dma_sync_single_for_device(fei->dev, @@ -458,23 +457,19 @@ static int configure_memdma_and_inputblock(struct c8sectpfei *fei, init_completion(&tsin->idle_completion); - tsin->back_buffer_start = kzalloc(FEI_BUFFER_SIZE + - FEI_ALIGNMENT, GFP_KERNEL); - + tsin->back_buffer_start = kzalloc(FEI_BUFFER_SIZE + FEI_ALIGNMENT, GFP_KERNEL); if (!tsin->back_buffer_start) { ret = -ENOMEM; goto err_unmap; } /* Ensure backbuffer is 32byte aligned */ - tsin->back_buffer_aligned = tsin->back_buffer_start - + FEI_ALIGNMENT; + tsin->back_buffer_aligned = tsin->back_buffer_start + FEI_ALIGNMENT; - tsin->back_buffer_aligned = (void *) - (((uintptr_t) tsin->back_buffer_aligned) & ~0x1F); + tsin->back_buffer_aligned = PTR_ALIGN(tsin->back_buffer_aligned, FEI_ALIGNMENT); tsin->back_buffer_busaddr = dma_map_single(fei->dev, - (void *)tsin->back_buffer_aligned, + tsin->back_buffer_aligned, FEI_BUFFER_SIZE, DMA_BIDIRECTIONAL); @@ -489,8 +484,7 @@ static int configure_memdma_and_inputblock(struct c8sectpfei *fei, * per pid. By powers of deduction we conclude stih407 family * is configured (at SoC design stage) for bit per pid. */ - tsin->pid_buffer_start = kzalloc(2048, GFP_KERNEL); - + tsin->pid_buffer_start = kzalloc(PID_TABLE_SIZE + PID_TABLE_SIZE, GFP_KERNEL); if (!tsin->pid_buffer_start) { ret = -ENOMEM; goto err_unmap; @@ -503,11 +497,9 @@ static int configure_memdma_and_inputblock(struct c8sectpfei *fei, * the register. */ - tsin->pid_buffer_aligned = tsin->pid_buffer_start + - PID_TABLE_SIZE; + tsin->pid_buffer_aligned = tsin->pid_buffer_start + PID_TABLE_SIZE; - tsin->pid_buffer_aligned = (void *) - (((uintptr_t) tsin->pid_buffer_aligned) & ~0x3ff); + tsin->pid_buffer_aligned = PTR_ALIGN(tsin->pid_buffer_aligned, PID_TABLE_SIZE); tsin->pid_buffer_busaddr = dma_map_single(fei->dev, tsin->pid_buffer_aligned, @@ -915,8 +907,7 @@ static int c8sectpfe_remove(struct platform_device *pdev) if (readl(fei->io + SYS_OTHER_CLKEN)) writel(0, fei->io + SYS_OTHER_CLKEN); - if (fei->c8sectpfeclk) - clk_disable_unprepare(fei->c8sectpfeclk); + clk_disable_unprepare(fei->c8sectpfeclk); return 0; } diff --git a/drivers/media/platform/st/sti/delta/delta-v4l2.c b/drivers/media/platform/st/sti/delta/delta-v4l2.c index 420ad4d8df5d..03eaee6d15da 100644 --- a/drivers/media/platform/st/sti/delta/delta-v4l2.c +++ b/drivers/media/platform/st/sti/delta/delta-v4l2.c @@ -1669,14 +1669,12 @@ static int delta_open(struct file *file) set_default_params(ctx); /* enable ST231 clocks */ - if (delta->clk_st231) - if (clk_prepare_enable(delta->clk_st231)) - dev_warn(delta->dev, "failed to enable st231 clk\n"); + if (clk_prepare_enable(delta->clk_st231)) + dev_warn(delta->dev, "failed to enable st231 clk\n"); /* enable FLASH_PROMIP clock */ - if (delta->clk_flash_promip) - if (clk_prepare_enable(delta->clk_flash_promip)) - dev_warn(delta->dev, "failed to enable delta promip clk\n"); + if (clk_prepare_enable(delta->clk_flash_promip)) + dev_warn(delta->dev, "failed to enable delta promip clk\n"); mutex_unlock(&delta->lock); @@ -1717,12 +1715,10 @@ static int delta_release(struct file *file) v4l2_fh_exit(&ctx->fh); /* disable ST231 clocks */ - if (delta->clk_st231) - clk_disable_unprepare(delta->clk_st231); + clk_disable_unprepare(delta->clk_st231); /* disable FLASH_PROMIP clock */ - if (delta->clk_flash_promip) - clk_disable_unprepare(delta->clk_flash_promip); + clk_disable_unprepare(delta->clk_flash_promip); dev_dbg(delta->dev, "%s decoder instance released\n", ctx->name); @@ -1926,8 +1922,7 @@ static int delta_runtime_suspend(struct device *dev) { struct delta_dev *delta = dev_get_drvdata(dev); - if (delta->clk_delta) - clk_disable_unprepare(delta->clk_delta); + clk_disable_unprepare(delta->clk_delta); return 0; } @@ -1936,9 +1931,8 @@ static int delta_runtime_resume(struct device *dev) { struct delta_dev *delta = dev_get_drvdata(dev); - if (delta->clk_delta) - if (clk_prepare_enable(delta->clk_delta)) - dev_warn(dev, "failed to prepare/enable delta clk\n"); + if (clk_prepare_enable(delta->clk_delta)) + dev_warn(dev, "failed to prepare/enable delta clk\n"); return 0; } diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c index 09a743cd7004..2ca95ab2b0fe 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmi.c +++ b/drivers/media/platform/st/stm32/stm32-dcmi.c @@ -611,7 +611,7 @@ static struct media_entity *dcmi_find_source(struct stm32_dcmi *dcmi) if (!(pad->flags & MEDIA_PAD_FL_SINK)) break; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; @@ -622,7 +622,6 @@ static struct media_entity *dcmi_find_source(struct stm32_dcmi *dcmi) } static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi, - struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct media_entity *entity = &dcmi->source->entity; @@ -664,7 +663,7 @@ static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi, format->format.width, format->format.height); fmt.pad = pad->index; - ret = v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &fmt); + ret = v4l2_subdev_call(subdev, pad, set_fmt, NULL, &fmt); if (ret < 0) { dev_err(dcmi->dev, "%s: Failed to set format 0x%x %ux%u on \"%s\":%d pad (%d)\n", __func__, format->format.code, @@ -682,7 +681,7 @@ static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi, } /* Walk to next entity */ - sink_pad = media_entity_remote_pad(src_pad); + sink_pad = media_pad_remote_pad_first(src_pad); if (!sink_pad || !is_media_entity_v4l2_subdev(sink_pad->entity)) break; @@ -706,7 +705,7 @@ static int dcmi_pipeline_s_stream(struct stm32_dcmi *dcmi, int state) if (!(pad->flags & MEDIA_PAD_FL_SINK)) break; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; @@ -999,10 +998,6 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, const struct dcmi_format *sd_fmt; struct dcmi_framesize sd_fsize; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_subdev_pad_config pad_cfg; - struct v4l2_subdev_state pad_state = { - .pads = &pad_cfg - }; struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_TRY, }; @@ -1037,8 +1032,7 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, } v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code); - ret = v4l2_subdev_call(dcmi->source, pad, set_fmt, - &pad_state, &format); + ret = v4l2_subdev_call_state_try(dcmi->source, pad, set_fmt, &format); if (ret < 0) return ret; @@ -1115,7 +1109,7 @@ static int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f) mf->width = sd_framesize.width; mf->height = sd_framesize.height; - ret = dcmi_pipeline_s_fmt(dcmi, NULL, &format); + ret = dcmi_pipeline_s_fmt(dcmi, &format); if (ret < 0) return ret; @@ -1187,10 +1181,6 @@ static int dcmi_set_sensor_format(struct stm32_dcmi *dcmi, struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_TRY, }; - struct v4l2_subdev_pad_config pad_cfg; - struct v4l2_subdev_state pad_state = { - .pads = &pad_cfg - }; int ret; sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat); @@ -1203,8 +1193,7 @@ static int dcmi_set_sensor_format(struct stm32_dcmi *dcmi, } v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code); - ret = v4l2_subdev_call(dcmi->source, pad, set_fmt, - &pad_state, &format); + ret = v4l2_subdev_call_state_try(dcmi->source, pad, set_fmt, &format); if (ret < 0) return ret; @@ -1592,26 +1581,32 @@ static int dcmi_set_default_fmt(struct stm32_dcmi *dcmi) return 0; } -/* - * FIXME: For the time being we only support subdevices - * which expose RGB & YUV "parallel form" mbus code (_2X8). - * Nevertheless, this allows to support serial source subdevices - * and serial to parallel bridges which conform to this. - */ static const struct dcmi_format dcmi_formats[] = { { .fourcc = V4L2_PIX_FMT_RGB565, .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, .bpp = 2, }, { + .fourcc = V4L2_PIX_FMT_RGB565, + .mbus_code = MEDIA_BUS_FMT_RGB565_1X16, + .bpp = 2, + }, { .fourcc = V4L2_PIX_FMT_YUYV, .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 2, }, { + .fourcc = V4L2_PIX_FMT_YUYV, + .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, + .bpp = 2, + }, { .fourcc = V4L2_PIX_FMT_UYVY, .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, .bpp = 2, }, { + .fourcc = V4L2_PIX_FMT_UYVY, + .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, + .bpp = 2, + }, { .fourcc = V4L2_PIX_FMT_JPEG, .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, .bpp = 1, @@ -1631,6 +1626,54 @@ static const struct dcmi_format dcmi_formats[] = { .fourcc = V4L2_PIX_FMT_SRGGB8, .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 1, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR12, + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG12, + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG12, + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB12, + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR14, + .mbus_code = MEDIA_BUS_FMT_SBGGR14_1X14, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG14, + .mbus_code = MEDIA_BUS_FMT_SGBRG14_1X14, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG14, + .mbus_code = MEDIA_BUS_FMT_SGRBG14_1X14, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB14, + .mbus_code = MEDIA_BUS_FMT_SRGGB14_1X14, + .bpp = 2, }, }; diff --git a/drivers/media/platform/sunxi/Kconfig b/drivers/media/platform/sunxi/Kconfig index 46b7b9bf989c..2dd15083a1d9 100644 --- a/drivers/media/platform/sunxi/Kconfig +++ b/drivers/media/platform/sunxi/Kconfig @@ -4,5 +4,7 @@ comment "Sunxi media platform drivers" source "drivers/media/platform/sunxi/sun4i-csi/Kconfig" source "drivers/media/platform/sunxi/sun6i-csi/Kconfig" +source "drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig" +source "drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig" source "drivers/media/platform/sunxi/sun8i-di/Kconfig" source "drivers/media/platform/sunxi/sun8i-rotate/Kconfig" diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile index fc537c9f5ca9..9aa01cb01883 100644 --- a/drivers/media/platform/sunxi/Makefile +++ b/drivers/media/platform/sunxi/Makefile @@ -2,5 +2,7 @@ obj-y += sun4i-csi/ obj-y += sun6i-csi/ +obj-y += sun6i-mipi-csi2/ +obj-y += sun8i-a83t-mipi-csi2/ obj-y += sun8i-di/ obj-y += sun8i-rotate/ diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index 682c26536034..1d46e113d01d 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -77,7 +77,7 @@ sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad) { struct media_pad *remote; - remote = media_entity_remote_pad(&video->pad); + remote = media_pad_remote_pad_first(&video->pad); if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) return NULL; @@ -560,7 +560,7 @@ static int sun6i_video_link_validate(struct media_link *link) video->mbus_code = 0; - if (!media_entity_remote_pad(link->sink->entity->pads)) { + if (!media_pad_remote_pad_first(link->sink->entity->pads)) { dev_info(video->csi->dev, "video node %s pad not connected\n", vdev->name); return -ENOLINK; diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig new file mode 100644 index 000000000000..eb982466abd3 --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_SUN6I_MIPI_CSI2 + tristate "Allwinner A31 MIPI CSI-2 Controller Driver" + depends on V4L_PLATFORM_DRIVERS && VIDEO_DEV + depends on ARCH_SUNXI || COMPILE_TEST + depends on PM && COMMON_CLK + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + select PHY_SUN6I_MIPI_DPHY + select GENERIC_PHY_MIPI_DPHY + select REGMAP_MMIO + help + Support for the Allwinner A31 MIPI CSI-2 controller, also found on + other platforms such as the V3/V3s. diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile new file mode 100644 index 000000000000..14e4e03818b5 --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +sun6i-mipi-csi2-y += sun6i_mipi_csi2.o + +obj-$(CONFIG_VIDEO_SUN6I_MIPI_CSI2) += sun6i-mipi-csi2.o diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c new file mode 100644 index 000000000000..a4e3f9a6b2ff --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c @@ -0,0 +1,750 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020-2022 Bootlin + * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> + */ + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/reset.h> +#include <media/mipi-csi2.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#include "sun6i_mipi_csi2.h" +#include "sun6i_mipi_csi2_reg.h" + +/* Format */ + +static const struct sun6i_mipi_csi2_format sun6i_mipi_csi2_formats[] = { + { + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .data_type = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .data_type = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .data_type = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .data_type = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .data_type = MIPI_CSI2_DT_RAW10, + .bpp = 10, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .data_type = MIPI_CSI2_DT_RAW10, + .bpp = 10, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .data_type = MIPI_CSI2_DT_RAW10, + .bpp = 10, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .data_type = MIPI_CSI2_DT_RAW10, + .bpp = 10, + }, +}; + +static const struct sun6i_mipi_csi2_format * +sun6i_mipi_csi2_format_find(u32 mbus_code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sun6i_mipi_csi2_formats); i++) + if (sun6i_mipi_csi2_formats[i].mbus_code == mbus_code) + return &sun6i_mipi_csi2_formats[i]; + + return NULL; +} + +/* Controller */ + +static void sun6i_mipi_csi2_enable(struct sun6i_mipi_csi2_device *csi2_dev) +{ + struct regmap *regmap = csi2_dev->regmap; + + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, + SUN6I_MIPI_CSI2_CTL_EN, SUN6I_MIPI_CSI2_CTL_EN); +} + +static void sun6i_mipi_csi2_disable(struct sun6i_mipi_csi2_device *csi2_dev) +{ + struct regmap *regmap = csi2_dev->regmap; + + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, + SUN6I_MIPI_CSI2_CTL_EN, 0); +} + +static void sun6i_mipi_csi2_configure(struct sun6i_mipi_csi2_device *csi2_dev) +{ + struct regmap *regmap = csi2_dev->regmap; + unsigned int lanes_count = + csi2_dev->bridge.endpoint.bus.mipi_csi2.num_data_lanes; + struct v4l2_mbus_framefmt *mbus_format = &csi2_dev->bridge.mbus_format; + const struct sun6i_mipi_csi2_format *format; + struct device *dev = csi2_dev->dev; + u32 version = 0; + + format = sun6i_mipi_csi2_format_find(mbus_format->code); + if (WARN_ON(!format)) + return; + + /* + * The enable flow in the Allwinner BSP is a bit different: the enable + * and reset bits are set together before starting the CSI controller. + * + * In mainline we enable the CSI controller first (due to subdev logic). + * One reliable way to make this work is to deassert reset, configure + * registers and enable the controller when everything's ready. + * + * However, setting the version enable bit and removing it afterwards + * appears necessary for capture to work reliably, while replacing it + * with a delay doesn't do the trick. + */ + regmap_write(regmap, SUN6I_MIPI_CSI2_CTL_REG, + SUN6I_MIPI_CSI2_CTL_RESET_N | + SUN6I_MIPI_CSI2_CTL_VERSION_EN | + SUN6I_MIPI_CSI2_CTL_UNPK_EN); + + regmap_read(regmap, SUN6I_MIPI_CSI2_VERSION_REG, &version); + + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, + SUN6I_MIPI_CSI2_CTL_VERSION_EN, 0); + + dev_dbg(dev, "A31 MIPI CSI-2 version: %04x\n", version); + + regmap_write(regmap, SUN6I_MIPI_CSI2_CFG_REG, + SUN6I_MIPI_CSI2_CFG_CHANNEL_MODE(1) | + SUN6I_MIPI_CSI2_CFG_LANE_COUNT(lanes_count)); + + /* + * Only a single virtual channel (index 0) is currently supported. + * While the registers do mention multiple physical channels being + * available (which can be configured to match a specific virtual + * channel or data type), it's unclear whether channels > 0 are actually + * connected and available and the reference source code only makes use + * of channel 0. + * + * Using extra channels would also require matching channels to be + * available on the CSI (and ISP) side, which is also unsure although + * some CSI implementations are said to support multiple channels for + * BT656 time-sharing. + * + * We still configure virtual channel numbers to ensure that virtual + * channel 0 only goes to channel 0. + */ + + regmap_write(regmap, SUN6I_MIPI_CSI2_VCDT_RX_REG, + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(3, 3) | + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(2, 2) | + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(1, 1) | + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(0, 0) | + SUN6I_MIPI_CSI2_VCDT_RX_CH_DT(0, format->data_type)); + + regmap_write(regmap, SUN6I_MIPI_CSI2_CH_INT_PD_REG, + SUN6I_MIPI_CSI2_CH_INT_PD_CLEAR); +} + +/* V4L2 Subdev */ + +static int sun6i_mipi_csi2_s_stream(struct v4l2_subdev *subdev, int on) +{ + struct sun6i_mipi_csi2_device *csi2_dev = v4l2_get_subdevdata(subdev); + struct v4l2_subdev *source_subdev = csi2_dev->bridge.source_subdev; + union phy_configure_opts dphy_opts = { 0 }; + struct phy_configure_opts_mipi_dphy *dphy_cfg = &dphy_opts.mipi_dphy; + struct v4l2_mbus_framefmt *mbus_format = &csi2_dev->bridge.mbus_format; + const struct sun6i_mipi_csi2_format *format; + struct phy *dphy = csi2_dev->dphy; + struct device *dev = csi2_dev->dev; + struct v4l2_ctrl *ctrl; + unsigned int lanes_count = + csi2_dev->bridge.endpoint.bus.mipi_csi2.num_data_lanes; + unsigned long pixel_rate; + int ret; + + if (!source_subdev) + return -ENODEV; + + if (!on) { + ret = v4l2_subdev_call(source_subdev, video, s_stream, 0); + goto disable; + } + + /* Runtime PM */ + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + /* Sensor Pixel Rate */ + + ctrl = v4l2_ctrl_find(source_subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); + if (!ctrl) { + dev_err(dev, "missing sensor pixel rate\n"); + ret = -ENODEV; + goto error_pm; + } + + pixel_rate = (unsigned long)v4l2_ctrl_g_ctrl_int64(ctrl); + if (!pixel_rate) { + dev_err(dev, "missing (zero) sensor pixel rate\n"); + ret = -ENODEV; + goto error_pm; + } + + /* D-PHY */ + + if (!lanes_count) { + dev_err(dev, "missing (zero) MIPI CSI-2 lanes count\n"); + ret = -ENODEV; + goto error_pm; + } + + format = sun6i_mipi_csi2_format_find(mbus_format->code); + if (WARN_ON(!format)) { + ret = -ENODEV; + goto error_pm; + } + + phy_mipi_dphy_get_default_config(pixel_rate, format->bpp, lanes_count, + dphy_cfg); + + /* + * Note that our hardware is using DDR, which is not taken in account by + * phy_mipi_dphy_get_default_config when calculating hs_clk_rate from + * the pixel rate, lanes count and bpp. + * + * The resulting clock rate is basically the symbol rate over the whole + * link. The actual clock rate is calculated with division by two since + * DDR samples both on rising and falling edges. + */ + + dev_dbg(dev, "A31 MIPI CSI-2 config:\n"); + dev_dbg(dev, "%ld pixels/s, %u bits/pixel, %u lanes, %lu Hz clock\n", + pixel_rate, format->bpp, lanes_count, + dphy_cfg->hs_clk_rate / 2); + + ret = phy_reset(dphy); + if (ret) { + dev_err(dev, "failed to reset MIPI D-PHY\n"); + goto error_pm; + } + + ret = phy_configure(dphy, &dphy_opts); + if (ret) { + dev_err(dev, "failed to configure MIPI D-PHY\n"); + goto error_pm; + } + + /* Controller */ + + sun6i_mipi_csi2_configure(csi2_dev); + sun6i_mipi_csi2_enable(csi2_dev); + + /* D-PHY */ + + ret = phy_power_on(dphy); + if (ret) { + dev_err(dev, "failed to power on MIPI D-PHY\n"); + goto error_pm; + } + + /* Source */ + + ret = v4l2_subdev_call(source_subdev, video, s_stream, 1); + if (ret && ret != -ENOIOCTLCMD) + goto disable; + + return 0; + +disable: + if (!on) + ret = 0; + phy_power_off(dphy); + sun6i_mipi_csi2_disable(csi2_dev); + +error_pm: + pm_runtime_put(dev); + + return ret; +} + +static const struct v4l2_subdev_video_ops sun6i_mipi_csi2_video_ops = { + .s_stream = sun6i_mipi_csi2_s_stream, +}; + +static void +sun6i_mipi_csi2_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format) +{ + if (!sun6i_mipi_csi2_format_find(mbus_format->code)) + mbus_format->code = sun6i_mipi_csi2_formats[0].mbus_code; + + mbus_format->field = V4L2_FIELD_NONE; + mbus_format->colorspace = V4L2_COLORSPACE_RAW; + mbus_format->quantization = V4L2_QUANTIZATION_DEFAULT; + mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; +} + +static int sun6i_mipi_csi2_init_cfg(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state) +{ + struct sun6i_mipi_csi2_device *csi2_dev = v4l2_get_subdevdata(subdev); + unsigned int pad = SUN6I_MIPI_CSI2_PAD_SINK; + struct v4l2_mbus_framefmt *mbus_format = + v4l2_subdev_get_try_format(subdev, state, pad); + struct mutex *lock = &csi2_dev->bridge.lock; + + mutex_lock(lock); + + mbus_format->code = sun6i_mipi_csi2_formats[0].mbus_code; + mbus_format->width = 640; + mbus_format->height = 480; + + sun6i_mipi_csi2_mbus_format_prepare(mbus_format); + + mutex_unlock(lock); + + return 0; +} + +static int +sun6i_mipi_csi2_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code_enum) +{ + if (code_enum->index >= ARRAY_SIZE(sun6i_mipi_csi2_formats)) + return -EINVAL; + + code_enum->code = sun6i_mipi_csi2_formats[code_enum->index].mbus_code; + + return 0; +} + +static int sun6i_mipi_csi2_get_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct sun6i_mipi_csi2_device *csi2_dev = v4l2_get_subdevdata(subdev); + struct v4l2_mbus_framefmt *mbus_format = &format->format; + struct mutex *lock = &csi2_dev->bridge.lock; + + mutex_lock(lock); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + *mbus_format = *v4l2_subdev_get_try_format(subdev, state, + format->pad); + else + *mbus_format = csi2_dev->bridge.mbus_format; + + mutex_unlock(lock); + + return 0; +} + +static int sun6i_mipi_csi2_set_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct sun6i_mipi_csi2_device *csi2_dev = v4l2_get_subdevdata(subdev); + struct v4l2_mbus_framefmt *mbus_format = &format->format; + struct mutex *lock = &csi2_dev->bridge.lock; + + mutex_lock(lock); + + sun6i_mipi_csi2_mbus_format_prepare(mbus_format); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + *v4l2_subdev_get_try_format(subdev, state, format->pad) = + *mbus_format; + else + csi2_dev->bridge.mbus_format = *mbus_format; + + mutex_unlock(lock); + + return 0; +} + +static const struct v4l2_subdev_pad_ops sun6i_mipi_csi2_pad_ops = { + .init_cfg = sun6i_mipi_csi2_init_cfg, + .enum_mbus_code = sun6i_mipi_csi2_enum_mbus_code, + .get_fmt = sun6i_mipi_csi2_get_fmt, + .set_fmt = sun6i_mipi_csi2_set_fmt, +}; + +static const struct v4l2_subdev_ops sun6i_mipi_csi2_subdev_ops = { + .video = &sun6i_mipi_csi2_video_ops, + .pad = &sun6i_mipi_csi2_pad_ops, +}; + +/* Media Entity */ + +static const struct media_entity_operations sun6i_mipi_csi2_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +/* V4L2 Async */ + +static int +sun6i_mipi_csi2_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *remote_subdev, + struct v4l2_async_subdev *async_subdev) +{ + struct v4l2_subdev *subdev = notifier->sd; + struct sun6i_mipi_csi2_device *csi2_dev = + container_of(notifier, struct sun6i_mipi_csi2_device, + bridge.notifier); + struct media_entity *sink_entity = &subdev->entity; + struct media_entity *source_entity = &remote_subdev->entity; + struct device *dev = csi2_dev->dev; + int sink_pad_index = 0; + int source_pad_index; + int ret; + + ret = media_entity_get_fwnode_pad(source_entity, remote_subdev->fwnode, + MEDIA_PAD_FL_SOURCE); + if (ret < 0) { + dev_err(dev, "missing source pad in external entity %s\n", + source_entity->name); + return -EINVAL; + } + + source_pad_index = ret; + + dev_dbg(dev, "creating %s:%u -> %s:%u link\n", source_entity->name, + source_pad_index, sink_entity->name, sink_pad_index); + + ret = media_create_pad_link(source_entity, source_pad_index, + sink_entity, sink_pad_index, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) { + dev_err(dev, "failed to create %s:%u -> %s:%u link\n", + source_entity->name, source_pad_index, + sink_entity->name, sink_pad_index); + return ret; + } + + csi2_dev->bridge.source_subdev = remote_subdev; + + return 0; +} + +static const struct v4l2_async_notifier_operations +sun6i_mipi_csi2_notifier_ops = { + .bound = sun6i_mipi_csi2_notifier_bound, +}; + +/* Bridge */ + +static int +sun6i_mipi_csi2_bridge_source_setup(struct sun6i_mipi_csi2_device *csi2_dev) +{ + struct v4l2_async_notifier *notifier = &csi2_dev->bridge.notifier; + struct v4l2_fwnode_endpoint *endpoint = &csi2_dev->bridge.endpoint; + struct v4l2_async_subdev *subdev_async; + struct fwnode_handle *handle; + struct device *dev = csi2_dev->dev; + int ret; + + handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + if (!handle) + return -ENODEV; + + endpoint->bus_type = V4L2_MBUS_CSI2_DPHY; + + ret = v4l2_fwnode_endpoint_parse(handle, endpoint); + if (ret) + goto complete; + + subdev_async = + v4l2_async_nf_add_fwnode_remote(notifier, handle, + struct v4l2_async_subdev); + if (IS_ERR(subdev_async)) + ret = PTR_ERR(subdev_async); + +complete: + fwnode_handle_put(handle); + + return ret; +} + +static int sun6i_mipi_csi2_bridge_setup(struct sun6i_mipi_csi2_device *csi2_dev) +{ + struct sun6i_mipi_csi2_bridge *bridge = &csi2_dev->bridge; + struct v4l2_subdev *subdev = &bridge->subdev; + struct v4l2_async_notifier *notifier = &bridge->notifier; + struct media_pad *pads = bridge->pads; + struct device *dev = csi2_dev->dev; + int ret; + + mutex_init(&bridge->lock); + + /* V4L2 Subdev */ + + v4l2_subdev_init(subdev, &sun6i_mipi_csi2_subdev_ops); + strscpy(subdev->name, SUN6I_MIPI_CSI2_NAME, sizeof(subdev->name)); + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + subdev->owner = THIS_MODULE; + subdev->dev = dev; + + v4l2_set_subdevdata(subdev, csi2_dev); + + /* Media Entity */ + + subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + subdev->entity.ops = &sun6i_mipi_csi2_entity_ops; + + /* Media Pads */ + + pads[SUN6I_MIPI_CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + pads[SUN6I_MIPI_CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&subdev->entity, SUN6I_MIPI_CSI2_PAD_COUNT, + pads); + if (ret) + return ret; + + /* V4L2 Async */ + + v4l2_async_nf_init(notifier); + notifier->ops = &sun6i_mipi_csi2_notifier_ops; + + ret = sun6i_mipi_csi2_bridge_source_setup(csi2_dev); + if (ret) + goto error_v4l2_notifier_cleanup; + + ret = v4l2_async_subdev_nf_register(subdev, notifier); + if (ret < 0) + goto error_v4l2_notifier_cleanup; + + /* V4L2 Subdev */ + + ret = v4l2_async_register_subdev(subdev); + if (ret < 0) + goto error_v4l2_notifier_unregister; + + return 0; + +error_v4l2_notifier_unregister: + v4l2_async_nf_unregister(notifier); + +error_v4l2_notifier_cleanup: + v4l2_async_nf_cleanup(notifier); + + media_entity_cleanup(&subdev->entity); + + return ret; +} + +static void +sun6i_mipi_csi2_bridge_cleanup(struct sun6i_mipi_csi2_device *csi2_dev) +{ + struct v4l2_subdev *subdev = &csi2_dev->bridge.subdev; + struct v4l2_async_notifier *notifier = &csi2_dev->bridge.notifier; + + v4l2_async_unregister_subdev(subdev); + v4l2_async_nf_unregister(notifier); + v4l2_async_nf_cleanup(notifier); + media_entity_cleanup(&subdev->entity); +} + +/* Platform */ + +static int sun6i_mipi_csi2_suspend(struct device *dev) +{ + struct sun6i_mipi_csi2_device *csi2_dev = dev_get_drvdata(dev); + + clk_disable_unprepare(csi2_dev->clock_mod); + reset_control_assert(csi2_dev->reset); + + return 0; +} + +static int sun6i_mipi_csi2_resume(struct device *dev) +{ + struct sun6i_mipi_csi2_device *csi2_dev = dev_get_drvdata(dev); + int ret; + + ret = reset_control_deassert(csi2_dev->reset); + if (ret) { + dev_err(dev, "failed to deassert reset\n"); + return ret; + } + + ret = clk_prepare_enable(csi2_dev->clock_mod); + if (ret) { + dev_err(dev, "failed to enable module clock\n"); + goto error_reset; + } + + return 0; + +error_reset: + reset_control_assert(csi2_dev->reset); + + return ret; +} + +static const struct dev_pm_ops sun6i_mipi_csi2_pm_ops = { + .runtime_suspend = sun6i_mipi_csi2_suspend, + .runtime_resume = sun6i_mipi_csi2_resume, +}; + +static const struct regmap_config sun6i_mipi_csi2_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x400, +}; + +static int +sun6i_mipi_csi2_resources_setup(struct sun6i_mipi_csi2_device *csi2_dev, + struct platform_device *platform_dev) +{ + struct device *dev = csi2_dev->dev; + void __iomem *io_base; + int ret; + + /* Registers */ + + io_base = devm_platform_ioremap_resource(platform_dev, 0); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); + + csi2_dev->regmap = + devm_regmap_init_mmio_clk(dev, "bus", io_base, + &sun6i_mipi_csi2_regmap_config); + if (IS_ERR(csi2_dev->regmap)) { + dev_err(dev, "failed to init register map\n"); + return PTR_ERR(csi2_dev->regmap); + } + + /* Clock */ + + csi2_dev->clock_mod = devm_clk_get(dev, "mod"); + if (IS_ERR(csi2_dev->clock_mod)) { + dev_err(dev, "failed to acquire mod clock\n"); + return PTR_ERR(csi2_dev->clock_mod); + } + + ret = clk_set_rate_exclusive(csi2_dev->clock_mod, 297000000); + if (ret) { + dev_err(dev, "failed to set mod clock rate\n"); + return ret; + } + + /* Reset */ + + csi2_dev->reset = devm_reset_control_get_shared(dev, NULL); + if (IS_ERR(csi2_dev->reset)) { + dev_err(dev, "failed to get reset controller\n"); + return PTR_ERR(csi2_dev->reset); + } + + /* D-PHY */ + + csi2_dev->dphy = devm_phy_get(dev, "dphy"); + if (IS_ERR(csi2_dev->dphy)) { + dev_err(dev, "failed to get MIPI D-PHY\n"); + return PTR_ERR(csi2_dev->dphy); + } + + ret = phy_init(csi2_dev->dphy); + if (ret) { + dev_err(dev, "failed to initialize MIPI D-PHY\n"); + return ret; + } + + /* Runtime PM */ + + pm_runtime_enable(dev); + + return 0; +} + +static void +sun6i_mipi_csi2_resources_cleanup(struct sun6i_mipi_csi2_device *csi2_dev) +{ + pm_runtime_disable(csi2_dev->dev); + phy_exit(csi2_dev->dphy); + clk_rate_exclusive_put(csi2_dev->clock_mod); +} + +static int sun6i_mipi_csi2_probe(struct platform_device *platform_dev) +{ + struct sun6i_mipi_csi2_device *csi2_dev; + struct device *dev = &platform_dev->dev; + int ret; + + csi2_dev = devm_kzalloc(dev, sizeof(*csi2_dev), GFP_KERNEL); + if (!csi2_dev) + return -ENOMEM; + + csi2_dev->dev = dev; + platform_set_drvdata(platform_dev, csi2_dev); + + ret = sun6i_mipi_csi2_resources_setup(csi2_dev, platform_dev); + if (ret) + return ret; + + ret = sun6i_mipi_csi2_bridge_setup(csi2_dev); + if (ret) + return ret; + + return 0; +} + +static int sun6i_mipi_csi2_remove(struct platform_device *platform_dev) +{ + struct sun6i_mipi_csi2_device *csi2_dev = + platform_get_drvdata(platform_dev); + + sun6i_mipi_csi2_bridge_cleanup(csi2_dev); + sun6i_mipi_csi2_resources_cleanup(csi2_dev); + + return 0; +} + +static const struct of_device_id sun6i_mipi_csi2_of_match[] = { + { .compatible = "allwinner,sun6i-a31-mipi-csi2" }, + {}, +}; +MODULE_DEVICE_TABLE(of, sun6i_mipi_csi2_of_match); + +static struct platform_driver sun6i_mipi_csi2_platform_driver = { + .probe = sun6i_mipi_csi2_probe, + .remove = sun6i_mipi_csi2_remove, + .driver = { + .name = SUN6I_MIPI_CSI2_NAME, + .of_match_table = of_match_ptr(sun6i_mipi_csi2_of_match), + .pm = &sun6i_mipi_csi2_pm_ops, + }, +}; +module_platform_driver(sun6i_mipi_csi2_platform_driver); + +MODULE_DESCRIPTION("Allwinner A31 MIPI CSI-2 Controller Driver"); +MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h new file mode 100644 index 000000000000..24b15e34b5e8 --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2020-2022 Bootlin + * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> + */ + +#ifndef _SUN6I_MIPI_CSI2_H_ +#define _SUN6I_MIPI_CSI2_H_ + +#include <linux/phy/phy.h> +#include <linux/regmap.h> +#include <linux/reset.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#define SUN6I_MIPI_CSI2_NAME "sun6i-mipi-csi2" + +enum sun6i_mipi_csi2_pad { + SUN6I_MIPI_CSI2_PAD_SINK = 0, + SUN6I_MIPI_CSI2_PAD_SOURCE = 1, + SUN6I_MIPI_CSI2_PAD_COUNT = 2, +}; + +struct sun6i_mipi_csi2_format { + u32 mbus_code; + u8 data_type; + u32 bpp; +}; + +struct sun6i_mipi_csi2_bridge { + struct v4l2_subdev subdev; + struct media_pad pads[SUN6I_MIPI_CSI2_PAD_COUNT]; + struct v4l2_fwnode_endpoint endpoint; + struct v4l2_async_notifier notifier; + struct v4l2_mbus_framefmt mbus_format; + struct mutex lock; /* Mbus format lock. */ + + struct v4l2_subdev *source_subdev; +}; + +struct sun6i_mipi_csi2_device { + struct device *dev; + + struct regmap *regmap; + struct clk *clock_mod; + struct reset_control *reset; + struct phy *dphy; + + struct sun6i_mipi_csi2_bridge bridge; +}; + +#endif diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2_reg.h b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2_reg.h new file mode 100644 index 000000000000..d9c92cf2b038 --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2_reg.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2020-2022 Bootlin + * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> + */ + +#ifndef _SUN6I_MIPI_CSI2_REG_H_ +#define _SUN6I_MIPI_CSI2_REG_H_ + +#define SUN6I_MIPI_CSI2_CTL_REG 0x0 +#define SUN6I_MIPI_CSI2_CTL_RESET_N BIT(31) +#define SUN6I_MIPI_CSI2_CTL_VERSION_EN BIT(30) +#define SUN6I_MIPI_CSI2_CTL_UNPK_EN BIT(1) +#define SUN6I_MIPI_CSI2_CTL_EN BIT(0) + +#define SUN6I_MIPI_CSI2_CFG_REG 0x4 +#define SUN6I_MIPI_CSI2_CFG_CHANNEL_MODE(v) ((((v) - 1) << 8) & \ + GENMASK(9, 8)) +#define SUN6I_MIPI_CSI2_CFG_LANE_COUNT(v) (((v) - 1) & GENMASK(1, 0)) + +#define SUN6I_MIPI_CSI2_VCDT_RX_REG 0x8 +#define SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(ch, vc) (((vc) & GENMASK(1, 0)) << \ + ((ch) * 8 + 6)) +#define SUN6I_MIPI_CSI2_VCDT_RX_CH_DT(ch, t) (((t) & GENMASK(5, 0)) << \ + ((ch) * 8)) +#define SUN6I_MIPI_CSI2_RX_PKT_NUM_REG 0xc + +#define SUN6I_MIPI_CSI2_VERSION_REG 0x3c + +#define SUN6I_MIPI_CSI2_CH_CFG_REG 0x40 +#define SUN6I_MIPI_CSI2_CH_INT_EN_REG 0x50 +#define SUN6I_MIPI_CSI2_CH_INT_EN_EOT_ERR BIT(29) +#define SUN6I_MIPI_CSI2_CH_INT_EN_CHKSUM_ERR BIT(28) +#define SUN6I_MIPI_CSI2_CH_INT_EN_ECC_WRN BIT(27) +#define SUN6I_MIPI_CSI2_CH_INT_EN_ECC_ERR BIT(26) +#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_SYNC_ERR BIT(25) +#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_SYNC_ERR BIT(24) +#define SUN6I_MIPI_CSI2_CH_INT_EN_EMB_DATA BIT(18) +#define SUN6I_MIPI_CSI2_CH_INT_EN_PF BIT(17) +#define SUN6I_MIPI_CSI2_CH_INT_EN_PH_UPDATE BIT(16) +#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_START_SYNC BIT(11) +#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_END_SYNC BIT(10) +#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_START_SYNC BIT(9) +#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_END_SYNC BIT(8) +#define SUN6I_MIPI_CSI2_CH_INT_EN_FIFO_OVER BIT(0) + +#define SUN6I_MIPI_CSI2_CH_INT_PD_REG 0x58 +#define SUN6I_MIPI_CSI2_CH_INT_PD_CLEAR 0xff +#define SUN6I_MIPI_CSI2_CH_INT_PD_EOT_ERR BIT(29) +#define SUN6I_MIPI_CSI2_CH_INT_PD_CHKSUM_ERR BIT(28) +#define SUN6I_MIPI_CSI2_CH_INT_PD_ECC_WRN BIT(27) +#define SUN6I_MIPI_CSI2_CH_INT_PD_ECC_ERR BIT(26) +#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_SYNC_ERR BIT(25) +#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_SYNC_ERR BIT(24) +#define SUN6I_MIPI_CSI2_CH_INT_PD_EMB_DATA BIT(18) +#define SUN6I_MIPI_CSI2_CH_INT_PD_PF BIT(17) +#define SUN6I_MIPI_CSI2_CH_INT_PD_PH_UPDATE BIT(16) +#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_START_SYNC BIT(11) +#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_END_SYNC BIT(10) +#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_START_SYNC BIT(9) +#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_END_SYNC BIT(8) +#define SUN6I_MIPI_CSI2_CH_INT_PD_FIFO_OVER BIT(0) + +#define SUN6I_MIPI_CSI2_CH_DT_TRIGGER_REG 0x60 +#define SUN6I_MIPI_CSI2_CH_CUR_PH_REG 0x70 +#define SUN6I_MIPI_CSI2_CH_ECC_REG 0x74 +#define SUN6I_MIPI_CSI2_CH_CKS_REG 0x78 +#define SUN6I_MIPI_CSI2_CH_FRAME_NUM_REG 0x7c +#define SUN6I_MIPI_CSI2_CH_LINE_NUM_REG 0x80 + +#define SUN6I_MIPI_CSI2_CH_OFFSET 0x100 + +#define SUN6I_MIPI_CSI2_CH_REG(reg, ch) \ + (SUN6I_MIPI_CSI2_CH_OFFSET * (ch) + (reg)) + +#endif diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig new file mode 100644 index 000000000000..789d58ee12ea --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_SUN8I_A83T_MIPI_CSI2 + tristate "Allwinner A83T MIPI CSI-2 Controller and D-PHY Driver" + depends on V4L_PLATFORM_DRIVERS && VIDEO_DEV + depends on ARCH_SUNXI || COMPILE_TEST + depends on PM && COMMON_CLK + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + select REGMAP_MMIO + select GENERIC_PHY_MIPI_DPHY + help + Support for the Allwinner A83T MIPI CSI-2 controller and D-PHY. diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile new file mode 100644 index 000000000000..1427d15a879a --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +sun8i-a83t-mipi-csi2-y += sun8i_a83t_mipi_csi2.o sun8i_a83t_dphy.o + +obj-$(CONFIG_VIDEO_SUN8I_A83T_MIPI_CSI2) += sun8i-a83t-mipi-csi2.o diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c new file mode 100644 index 000000000000..24bbcc85013d --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020-2022 Bootlin + * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> + */ + +#include <linux/phy/phy.h> +#include <linux/regmap.h> + +#include "sun8i_a83t_dphy.h" +#include "sun8i_a83t_mipi_csi2.h" + +static int sun8i_a83t_dphy_configure(struct phy *dphy, + union phy_configure_opts *opts) +{ + return phy_mipi_dphy_config_validate(&opts->mipi_dphy); +} + +static int sun8i_a83t_dphy_power_on(struct phy *dphy) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = phy_get_drvdata(dphy); + struct regmap *regmap = csi2_dev->regmap; + + regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG, + SUN8I_A83T_DPHY_CTRL_RESET_N | + SUN8I_A83T_DPHY_CTRL_SHUTDOWN_N); + + regmap_write(regmap, SUN8I_A83T_DPHY_ANA0_REG, + SUN8I_A83T_DPHY_ANA0_REXT_EN | + SUN8I_A83T_DPHY_ANA0_RINT(2) | + SUN8I_A83T_DPHY_ANA0_SNK(2)); + + return 0; +}; + +static int sun8i_a83t_dphy_power_off(struct phy *dphy) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = phy_get_drvdata(dphy); + struct regmap *regmap = csi2_dev->regmap; + + regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG, 0); + + return 0; +}; + +static const struct phy_ops sun8i_a83t_dphy_ops = { + .configure = sun8i_a83t_dphy_configure, + .power_on = sun8i_a83t_dphy_power_on, + .power_off = sun8i_a83t_dphy_power_off, +}; + +int sun8i_a83t_dphy_register(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + struct device *dev = csi2_dev->dev; + struct phy_provider *phy_provider; + + csi2_dev->dphy = devm_phy_create(dev, NULL, &sun8i_a83t_dphy_ops); + if (IS_ERR(csi2_dev->dphy)) { + dev_err(dev, "failed to create D-PHY\n"); + return PTR_ERR(csi2_dev->dphy); + } + + phy_set_drvdata(csi2_dev->dphy, csi2_dev); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) { + dev_err(dev, "failed to register D-PHY provider\n"); + return PTR_ERR(phy_provider); + } + + return 0; +} diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h new file mode 100644 index 000000000000..9ab709060770 --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2020 Kévin L'hôpital <kevin.lhopital@bootlin.com> + * Copyright 2020-2022 Bootlin + * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> + */ + +#ifndef _SUN8I_A83T_DPHY_H_ +#define _SUN8I_A83T_DPHY_H_ + +#include "sun8i_a83t_mipi_csi2.h" + +#define SUN8I_A83T_DPHY_CTRL_REG 0x10 +#define SUN8I_A83T_DPHY_CTRL_INIT_VALUE 0xb8df698e +#define SUN8I_A83T_DPHY_CTRL_RESET_N BIT(31) +#define SUN8I_A83T_DPHY_CTRL_SHUTDOWN_N BIT(15) +#define SUN8I_A83T_DPHY_CTRL_DEBUG BIT(8) +#define SUN8I_A83T_DPHY_STATUS_REG 0x14 +#define SUN8I_A83T_DPHY_STATUS_CLK_STOP BIT(10) +#define SUN8I_A83T_DPHY_STATUS_CLK_ULPS BIT(9) +#define SUN8I_A83T_DPHY_STATUS_HSCLK BIT(8) +#define SUN8I_A83T_DPHY_STATUS_D3_STOP BIT(7) +#define SUN8I_A83T_DPHY_STATUS_D2_STOP BIT(6) +#define SUN8I_A83T_DPHY_STATUS_D1_STOP BIT(5) +#define SUN8I_A83T_DPHY_STATUS_D0_STOP BIT(4) +#define SUN8I_A83T_DPHY_STATUS_D3_ULPS BIT(3) +#define SUN8I_A83T_DPHY_STATUS_D2_ULPS BIT(2) +#define SUN8I_A83T_DPHY_STATUS_D1_ULPS BIT(1) +#define SUN8I_A83T_DPHY_STATUS_D0_ULPS BIT(0) + +#define SUN8I_A83T_DPHY_ANA0_REG 0x30 +#define SUN8I_A83T_DPHY_ANA0_REXT_EN BIT(31) +#define SUN8I_A83T_DPHY_ANA0_REXT BIT(30) +#define SUN8I_A83T_DPHY_ANA0_RINT(v) (((v) << 28) & GENMASK(29, 28)) +#define SUN8I_A83T_DPHY_ANA0_SNK(v) (((v) << 20) & GENMASK(22, 20)) + +int sun8i_a83t_dphy_register(struct sun8i_a83t_mipi_csi2_device *csi2_dev); + +#endif diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c new file mode 100644 index 000000000000..d052ee77ef0a --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c @@ -0,0 +1,816 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 Kévin L'hôpital <kevin.lhopital@bootlin.com> + * Copyright 2020-2022 Bootlin + * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> + */ + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/reset.h> +#include <media/mipi-csi2.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#include "sun8i_a83t_dphy.h" +#include "sun8i_a83t_mipi_csi2.h" +#include "sun8i_a83t_mipi_csi2_reg.h" + +/* Format */ + +static const struct sun8i_a83t_mipi_csi2_format +sun8i_a83t_mipi_csi2_formats[] = { + { + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .data_type = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .data_type = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .data_type = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .data_type = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .data_type = MIPI_CSI2_DT_RAW10, + .bpp = 10, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .data_type = MIPI_CSI2_DT_RAW10, + .bpp = 10, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .data_type = MIPI_CSI2_DT_RAW10, + .bpp = 10, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .data_type = MIPI_CSI2_DT_RAW10, + .bpp = 10, + }, +}; + +static const struct sun8i_a83t_mipi_csi2_format * +sun8i_a83t_mipi_csi2_format_find(u32 mbus_code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sun8i_a83t_mipi_csi2_formats); i++) + if (sun8i_a83t_mipi_csi2_formats[i].mbus_code == mbus_code) + return &sun8i_a83t_mipi_csi2_formats[i]; + + return NULL; +} + +/* Controller */ + +static void +sun8i_a83t_mipi_csi2_init(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + struct regmap *regmap = csi2_dev->regmap; + + /* + * The Allwinner BSP sets various magic values on a bunch of registers. + * This is apparently a necessary initialization process that will cause + * the capture to fail with unsolicited interrupts hitting if skipped. + * + * Most of the registers are set to proper values later, except for the + * two reserved registers. They are said to hold a "hardware lock" + * value, without more information available. + */ + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CTRL_REG, 0); + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CTRL_REG, + SUN8I_A83T_MIPI_CSI2_CTRL_INIT_VALUE); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_REG, 0); + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_REG, + SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_INIT_VALUE); + + regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG, 0); + regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG, + SUN8I_A83T_DPHY_CTRL_INIT_VALUE); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RSVD1_REG, 0); + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RSVD1_REG, + SUN8I_A83T_MIPI_CSI2_RSVD1_HW_LOCK_VALUE); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RSVD2_REG, 0); + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RSVD2_REG, + SUN8I_A83T_MIPI_CSI2_RSVD2_HW_LOCK_VALUE); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG, 0); + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG, + SUN8I_A83T_MIPI_CSI2_CFG_INIT_VALUE); +} + +static void +sun8i_a83t_mipi_csi2_enable(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + struct regmap *regmap = csi2_dev->regmap; + + regmap_update_bits(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG, + SUN8I_A83T_MIPI_CSI2_CFG_SYNC_EN, + SUN8I_A83T_MIPI_CSI2_CFG_SYNC_EN); +} + +static void +sun8i_a83t_mipi_csi2_disable(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + struct regmap *regmap = csi2_dev->regmap; + + regmap_update_bits(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG, + SUN8I_A83T_MIPI_CSI2_CFG_SYNC_EN, 0); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CTRL_REG, 0); +} + +static void +sun8i_a83t_mipi_csi2_configure(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + struct regmap *regmap = csi2_dev->regmap; + unsigned int lanes_count = + csi2_dev->bridge.endpoint.bus.mipi_csi2.num_data_lanes; + struct v4l2_mbus_framefmt *mbus_format = &csi2_dev->bridge.mbus_format; + const struct sun8i_a83t_mipi_csi2_format *format; + struct device *dev = csi2_dev->dev; + u32 version = 0; + + format = sun8i_a83t_mipi_csi2_format_find(mbus_format->code); + if (WARN_ON(!format)) + return; + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CTRL_REG, + SUN8I_A83T_MIPI_CSI2_CTRL_RESET_N); + + regmap_read(regmap, SUN8I_A83T_MIPI_CSI2_VERSION_REG, &version); + + dev_dbg(dev, "A83T MIPI CSI-2 version: %04x\n", version); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG, + SUN8I_A83T_MIPI_CSI2_CFG_UNPKT_EN | + SUN8I_A83T_MIPI_CSI2_CFG_SYNC_DLY_CYCLE(8) | + SUN8I_A83T_MIPI_CSI2_CFG_N_CHANNEL(1) | + SUN8I_A83T_MIPI_CSI2_CFG_N_LANE(lanes_count)); + + /* + * Only a single virtual channel (index 0) is currently supported. + * While the registers do mention multiple physical channels being + * available (which can be configured to match a specific virtual + * channel or data type), it's unclear whether channels > 0 are actually + * connected and available and the reference source code only makes use + * of channel 0. + * + * Using extra channels would also require matching channels to be + * available on the CSI (and ISP) side, which is also unsure although + * some CSI implementations are said to support multiple channels for + * BT656 time-sharing. + * + * We still configure virtual channel numbers to ensure that virtual + * channel 0 only goes to channel 0. + */ + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_VCDT0_REG, + SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(3, 3) | + SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(2, 2) | + SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(1, 1) | + SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(0, 0) | + SUN8I_A83T_MIPI_CSI2_VCDT0_CH_DT(0, format->data_type)); +} + +/* V4L2 Subdev */ + +static int sun8i_a83t_mipi_csi2_s_stream(struct v4l2_subdev *subdev, int on) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = + v4l2_get_subdevdata(subdev); + struct v4l2_subdev *source_subdev = csi2_dev->bridge.source_subdev; + union phy_configure_opts dphy_opts = { 0 }; + struct phy_configure_opts_mipi_dphy *dphy_cfg = &dphy_opts.mipi_dphy; + struct v4l2_mbus_framefmt *mbus_format = &csi2_dev->bridge.mbus_format; + const struct sun8i_a83t_mipi_csi2_format *format; + struct phy *dphy = csi2_dev->dphy; + struct device *dev = csi2_dev->dev; + struct v4l2_ctrl *ctrl; + unsigned int lanes_count = + csi2_dev->bridge.endpoint.bus.mipi_csi2.num_data_lanes; + unsigned long pixel_rate; + int ret; + + if (!source_subdev) + return -ENODEV; + + if (!on) { + ret = v4l2_subdev_call(source_subdev, video, s_stream, 0); + goto disable; + } + + /* Runtime PM */ + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + /* Sensor pixel rate */ + + ctrl = v4l2_ctrl_find(source_subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); + if (!ctrl) { + dev_err(dev, "missing sensor pixel rate\n"); + ret = -ENODEV; + goto error_pm; + } + + pixel_rate = (unsigned long)v4l2_ctrl_g_ctrl_int64(ctrl); + if (!pixel_rate) { + dev_err(dev, "missing (zero) sensor pixel rate\n"); + ret = -ENODEV; + goto error_pm; + } + + /* D-PHY */ + + if (!lanes_count) { + dev_err(dev, "missing (zero) MIPI CSI-2 lanes count\n"); + ret = -ENODEV; + goto error_pm; + } + + format = sun8i_a83t_mipi_csi2_format_find(mbus_format->code); + if (WARN_ON(!format)) { + ret = -ENODEV; + goto error_pm; + } + + phy_mipi_dphy_get_default_config(pixel_rate, format->bpp, lanes_count, + dphy_cfg); + + /* + * Note that our hardware is using DDR, which is not taken in account by + * phy_mipi_dphy_get_default_config when calculating hs_clk_rate from + * the pixel rate, lanes count and bpp. + * + * The resulting clock rate is basically the symbol rate over the whole + * link. The actual clock rate is calculated with division by two since + * DDR samples both on rising and falling edges. + */ + + dev_dbg(dev, "A83T MIPI CSI-2 config:\n"); + dev_dbg(dev, "%ld pixels/s, %u bits/pixel, %u lanes, %lu Hz clock\n", + pixel_rate, format->bpp, lanes_count, + dphy_cfg->hs_clk_rate / 2); + + ret = phy_reset(dphy); + if (ret) { + dev_err(dev, "failed to reset MIPI D-PHY\n"); + goto error_pm; + } + + ret = phy_configure(dphy, &dphy_opts); + if (ret) { + dev_err(dev, "failed to configure MIPI D-PHY\n"); + goto error_pm; + } + + /* Controller */ + + sun8i_a83t_mipi_csi2_configure(csi2_dev); + sun8i_a83t_mipi_csi2_enable(csi2_dev); + + /* D-PHY */ + + ret = phy_power_on(dphy); + if (ret) { + dev_err(dev, "failed to power on MIPI D-PHY\n"); + goto error_pm; + } + + /* Source */ + + ret = v4l2_subdev_call(source_subdev, video, s_stream, 1); + if (ret && ret != -ENOIOCTLCMD) + goto disable; + + return 0; + +disable: + if (!on) + ret = 0; + phy_power_off(dphy); + sun8i_a83t_mipi_csi2_disable(csi2_dev); + +error_pm: + pm_runtime_put(dev); + + return ret; +} + +static const struct v4l2_subdev_video_ops +sun8i_a83t_mipi_csi2_video_ops = { + .s_stream = sun8i_a83t_mipi_csi2_s_stream, +}; + +static void +sun8i_a83t_mipi_csi2_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format) +{ + if (!sun8i_a83t_mipi_csi2_format_find(mbus_format->code)) + mbus_format->code = sun8i_a83t_mipi_csi2_formats[0].mbus_code; + + mbus_format->field = V4L2_FIELD_NONE; + mbus_format->colorspace = V4L2_COLORSPACE_RAW; + mbus_format->quantization = V4L2_QUANTIZATION_DEFAULT; + mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; +} + +static int sun8i_a83t_mipi_csi2_init_cfg(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = + v4l2_get_subdevdata(subdev); + unsigned int pad = SUN8I_A83T_MIPI_CSI2_PAD_SINK; + struct v4l2_mbus_framefmt *mbus_format = + v4l2_subdev_get_try_format(subdev, state, pad); + struct mutex *lock = &csi2_dev->bridge.lock; + + mutex_lock(lock); + + mbus_format->code = sun8i_a83t_mipi_csi2_formats[0].mbus_code; + mbus_format->width = 640; + mbus_format->height = 480; + + sun8i_a83t_mipi_csi2_mbus_format_prepare(mbus_format); + + mutex_unlock(lock); + + return 0; +} + +static int +sun8i_a83t_mipi_csi2_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code_enum) +{ + if (code_enum->index >= ARRAY_SIZE(sun8i_a83t_mipi_csi2_formats)) + return -EINVAL; + + code_enum->code = + sun8i_a83t_mipi_csi2_formats[code_enum->index].mbus_code; + + return 0; +} + +static int sun8i_a83t_mipi_csi2_get_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = + v4l2_get_subdevdata(subdev); + struct v4l2_mbus_framefmt *mbus_format = &format->format; + struct mutex *lock = &csi2_dev->bridge.lock; + + mutex_lock(lock); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + *mbus_format = *v4l2_subdev_get_try_format(subdev, state, + format->pad); + else + *mbus_format = csi2_dev->bridge.mbus_format; + + mutex_unlock(lock); + + return 0; +} + +static int sun8i_a83t_mipi_csi2_set_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = + v4l2_get_subdevdata(subdev); + struct v4l2_mbus_framefmt *mbus_format = &format->format; + struct mutex *lock = &csi2_dev->bridge.lock; + + mutex_lock(lock); + + sun8i_a83t_mipi_csi2_mbus_format_prepare(mbus_format); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + *v4l2_subdev_get_try_format(subdev, state, format->pad) = + *mbus_format; + else + csi2_dev->bridge.mbus_format = *mbus_format; + + mutex_unlock(lock); + + return 0; +} + +static const struct v4l2_subdev_pad_ops sun8i_a83t_mipi_csi2_pad_ops = { + .init_cfg = sun8i_a83t_mipi_csi2_init_cfg, + .enum_mbus_code = sun8i_a83t_mipi_csi2_enum_mbus_code, + .get_fmt = sun8i_a83t_mipi_csi2_get_fmt, + .set_fmt = sun8i_a83t_mipi_csi2_set_fmt, +}; + +static const struct v4l2_subdev_ops sun8i_a83t_mipi_csi2_subdev_ops = { + .video = &sun8i_a83t_mipi_csi2_video_ops, + .pad = &sun8i_a83t_mipi_csi2_pad_ops, +}; + +/* Media Entity */ + +static const struct media_entity_operations sun8i_a83t_mipi_csi2_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +/* V4L2 Async */ + +static int +sun8i_a83t_mipi_csi2_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *remote_subdev, + struct v4l2_async_subdev *async_subdev) +{ + struct v4l2_subdev *subdev = notifier->sd; + struct sun8i_a83t_mipi_csi2_device *csi2_dev = + container_of(notifier, struct sun8i_a83t_mipi_csi2_device, + bridge.notifier); + struct media_entity *sink_entity = &subdev->entity; + struct media_entity *source_entity = &remote_subdev->entity; + struct device *dev = csi2_dev->dev; + int sink_pad_index = 0; + int source_pad_index; + int ret; + + ret = media_entity_get_fwnode_pad(source_entity, remote_subdev->fwnode, + MEDIA_PAD_FL_SOURCE); + if (ret < 0) { + dev_err(dev, "missing source pad in external entity %s\n", + source_entity->name); + return -EINVAL; + } + + source_pad_index = ret; + + dev_dbg(dev, "creating %s:%u -> %s:%u link\n", source_entity->name, + source_pad_index, sink_entity->name, sink_pad_index); + + ret = media_create_pad_link(source_entity, source_pad_index, + sink_entity, sink_pad_index, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) { + dev_err(dev, "failed to create %s:%u -> %s:%u link\n", + source_entity->name, source_pad_index, + sink_entity->name, sink_pad_index); + return ret; + } + + csi2_dev->bridge.source_subdev = remote_subdev; + + return 0; +} + +static const struct v4l2_async_notifier_operations +sun8i_a83t_mipi_csi2_notifier_ops = { + .bound = sun8i_a83t_mipi_csi2_notifier_bound, +}; + +/* Bridge */ + +static int +sun8i_a83t_mipi_csi2_bridge_source_setup(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + struct v4l2_async_notifier *notifier = &csi2_dev->bridge.notifier; + struct v4l2_fwnode_endpoint *endpoint = &csi2_dev->bridge.endpoint; + struct v4l2_async_subdev *subdev_async; + struct fwnode_handle *handle; + struct device *dev = csi2_dev->dev; + int ret; + + handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + if (!handle) + return -ENODEV; + + endpoint->bus_type = V4L2_MBUS_CSI2_DPHY; + + ret = v4l2_fwnode_endpoint_parse(handle, endpoint); + if (ret) + goto complete; + + subdev_async = + v4l2_async_nf_add_fwnode_remote(notifier, handle, + struct v4l2_async_subdev); + if (IS_ERR(subdev_async)) + ret = PTR_ERR(subdev_async); + +complete: + fwnode_handle_put(handle); + + return ret; +} + +static int +sun8i_a83t_mipi_csi2_bridge_setup(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + struct sun8i_a83t_mipi_csi2_bridge *bridge = &csi2_dev->bridge; + struct v4l2_subdev *subdev = &bridge->subdev; + struct v4l2_async_notifier *notifier = &bridge->notifier; + struct media_pad *pads = bridge->pads; + struct device *dev = csi2_dev->dev; + int ret; + + mutex_init(&bridge->lock); + + /* V4L2 Subdev */ + + v4l2_subdev_init(subdev, &sun8i_a83t_mipi_csi2_subdev_ops); + strscpy(subdev->name, SUN8I_A83T_MIPI_CSI2_NAME, sizeof(subdev->name)); + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + subdev->owner = THIS_MODULE; + subdev->dev = dev; + + v4l2_set_subdevdata(subdev, csi2_dev); + + /* Media Entity */ + + subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + subdev->entity.ops = &sun8i_a83t_mipi_csi2_entity_ops; + + /* Media Pads */ + + pads[SUN8I_A83T_MIPI_CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + pads[SUN8I_A83T_MIPI_CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&subdev->entity, + SUN8I_A83T_MIPI_CSI2_PAD_COUNT, pads); + if (ret) + return ret; + + /* V4L2 Async */ + + v4l2_async_nf_init(notifier); + notifier->ops = &sun8i_a83t_mipi_csi2_notifier_ops; + + ret = sun8i_a83t_mipi_csi2_bridge_source_setup(csi2_dev); + if (ret) + goto error_v4l2_notifier_cleanup; + + ret = v4l2_async_subdev_nf_register(subdev, notifier); + if (ret < 0) + goto error_v4l2_notifier_cleanup; + + /* V4L2 Subdev */ + + ret = v4l2_async_register_subdev(subdev); + if (ret < 0) + goto error_v4l2_notifier_unregister; + + return 0; + +error_v4l2_notifier_unregister: + v4l2_async_nf_unregister(notifier); + +error_v4l2_notifier_cleanup: + v4l2_async_nf_cleanup(notifier); + + media_entity_cleanup(&subdev->entity); + + return ret; +} + +static void +sun8i_a83t_mipi_csi2_bridge_cleanup(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + struct v4l2_subdev *subdev = &csi2_dev->bridge.subdev; + struct v4l2_async_notifier *notifier = &csi2_dev->bridge.notifier; + + v4l2_async_unregister_subdev(subdev); + v4l2_async_nf_unregister(notifier); + v4l2_async_nf_cleanup(notifier); + media_entity_cleanup(&subdev->entity); +} + +/* Platform */ + +static int sun8i_a83t_mipi_csi2_suspend(struct device *dev) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = dev_get_drvdata(dev); + + clk_disable_unprepare(csi2_dev->clock_misc); + clk_disable_unprepare(csi2_dev->clock_mipi); + clk_disable_unprepare(csi2_dev->clock_mod); + reset_control_assert(csi2_dev->reset); + + return 0; +} + +static int sun8i_a83t_mipi_csi2_resume(struct device *dev) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = dev_get_drvdata(dev); + int ret; + + ret = reset_control_deassert(csi2_dev->reset); + if (ret) { + dev_err(dev, "failed to deassert reset\n"); + return ret; + } + + ret = clk_prepare_enable(csi2_dev->clock_mod); + if (ret) { + dev_err(dev, "failed to enable module clock\n"); + goto error_reset; + } + + ret = clk_prepare_enable(csi2_dev->clock_mipi); + if (ret) { + dev_err(dev, "failed to enable MIPI clock\n"); + goto error_clock_mod; + } + + ret = clk_prepare_enable(csi2_dev->clock_misc); + if (ret) { + dev_err(dev, "failed to enable CSI misc clock\n"); + goto error_clock_mipi; + } + + sun8i_a83t_mipi_csi2_init(csi2_dev); + + return 0; + +error_clock_mipi: + clk_disable_unprepare(csi2_dev->clock_mipi); + +error_clock_mod: + clk_disable_unprepare(csi2_dev->clock_mod); + +error_reset: + reset_control_assert(csi2_dev->reset); + + return ret; +} + +static const struct dev_pm_ops sun8i_a83t_mipi_csi2_pm_ops = { + .runtime_suspend = sun8i_a83t_mipi_csi2_suspend, + .runtime_resume = sun8i_a83t_mipi_csi2_resume, +}; + +static const struct regmap_config sun8i_a83t_mipi_csi2_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x120, +}; + +static int +sun8i_a83t_mipi_csi2_resources_setup(struct sun8i_a83t_mipi_csi2_device *csi2_dev, + struct platform_device *platform_dev) +{ + struct device *dev = csi2_dev->dev; + void __iomem *io_base; + int ret; + + /* Registers */ + + io_base = devm_platform_ioremap_resource(platform_dev, 0); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); + + csi2_dev->regmap = + devm_regmap_init_mmio_clk(dev, "bus", io_base, + &sun8i_a83t_mipi_csi2_regmap_config); + if (IS_ERR(csi2_dev->regmap)) { + dev_err(dev, "failed to init register map\n"); + return PTR_ERR(csi2_dev->regmap); + } + + /* Clocks */ + + csi2_dev->clock_mod = devm_clk_get(dev, "mod"); + if (IS_ERR(csi2_dev->clock_mod)) { + dev_err(dev, "failed to acquire mod clock\n"); + return PTR_ERR(csi2_dev->clock_mod); + } + + ret = clk_set_rate_exclusive(csi2_dev->clock_mod, 297000000); + if (ret) { + dev_err(dev, "failed to set mod clock rate\n"); + return ret; + } + + csi2_dev->clock_mipi = devm_clk_get(dev, "mipi"); + if (IS_ERR(csi2_dev->clock_mipi)) { + dev_err(dev, "failed to acquire mipi clock\n"); + return PTR_ERR(csi2_dev->clock_mipi); + } + + csi2_dev->clock_misc = devm_clk_get(dev, "misc"); + if (IS_ERR(csi2_dev->clock_misc)) { + dev_err(dev, "failed to acquire misc clock\n"); + return PTR_ERR(csi2_dev->clock_misc); + } + + /* Reset */ + + csi2_dev->reset = devm_reset_control_get_shared(dev, NULL); + if (IS_ERR(csi2_dev->reset)) { + dev_err(dev, "failed to get reset controller\n"); + return PTR_ERR(csi2_dev->reset); + } + + /* D-PHY */ + + ret = sun8i_a83t_dphy_register(csi2_dev); + if (ret) { + dev_err(dev, "failed to initialize MIPI D-PHY\n"); + return ret; + } + + /* Runtime PM */ + + pm_runtime_enable(dev); + + return 0; +} + +static void +sun8i_a83t_mipi_csi2_resources_cleanup(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + pm_runtime_disable(csi2_dev->dev); + phy_exit(csi2_dev->dphy); + clk_rate_exclusive_put(csi2_dev->clock_mod); +} + +static int sun8i_a83t_mipi_csi2_probe(struct platform_device *platform_dev) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev; + struct device *dev = &platform_dev->dev; + int ret; + + csi2_dev = devm_kzalloc(dev, sizeof(*csi2_dev), GFP_KERNEL); + if (!csi2_dev) + return -ENOMEM; + + csi2_dev->dev = dev; + platform_set_drvdata(platform_dev, csi2_dev); + + ret = sun8i_a83t_mipi_csi2_resources_setup(csi2_dev, platform_dev); + if (ret) + return ret; + + ret = sun8i_a83t_mipi_csi2_bridge_setup(csi2_dev); + if (ret) + return ret; + + return 0; +} + +static int sun8i_a83t_mipi_csi2_remove(struct platform_device *platform_dev) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = + platform_get_drvdata(platform_dev); + + sun8i_a83t_mipi_csi2_bridge_cleanup(csi2_dev); + sun8i_a83t_mipi_csi2_resources_cleanup(csi2_dev); + + return 0; +} + +static const struct of_device_id sun8i_a83t_mipi_csi2_of_match[] = { + { .compatible = "allwinner,sun8i-a83t-mipi-csi2" }, + {}, +}; +MODULE_DEVICE_TABLE(of, sun8i_a83t_mipi_csi2_of_match); + +static struct platform_driver sun8i_a83t_mipi_csi2_platform_driver = { + .probe = sun8i_a83t_mipi_csi2_probe, + .remove = sun8i_a83t_mipi_csi2_remove, + .driver = { + .name = SUN8I_A83T_MIPI_CSI2_NAME, + .of_match_table = of_match_ptr(sun8i_a83t_mipi_csi2_of_match), + .pm = &sun8i_a83t_mipi_csi2_pm_ops, + }, +}; +module_platform_driver(sun8i_a83t_mipi_csi2_platform_driver); + +MODULE_DESCRIPTION("Allwinner A83T MIPI CSI-2 and D-PHY Controller Driver"); +MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h new file mode 100644 index 000000000000..f1e64c53434c --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2020 Kévin L'hôpital <kevin.lhopital@bootlin.com> + * Copyright 2020-2022 Bootlin + * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> + */ + +#ifndef _SUN8I_A83T_MIPI_CSI2_H_ +#define _SUN8I_A83T_MIPI_CSI2_H_ + +#include <linux/phy/phy.h> +#include <linux/regmap.h> +#include <linux/reset.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#define SUN8I_A83T_MIPI_CSI2_NAME "sun8i-a83t-mipi-csi2" + +enum sun8i_a83t_mipi_csi2_pad { + SUN8I_A83T_MIPI_CSI2_PAD_SINK = 0, + SUN8I_A83T_MIPI_CSI2_PAD_SOURCE = 1, + SUN8I_A83T_MIPI_CSI2_PAD_COUNT = 2, +}; + +struct sun8i_a83t_mipi_csi2_format { + u32 mbus_code; + u8 data_type; + u32 bpp; +}; + +struct sun8i_a83t_mipi_csi2_bridge { + struct v4l2_subdev subdev; + struct media_pad pads[SUN8I_A83T_MIPI_CSI2_PAD_COUNT]; + struct v4l2_fwnode_endpoint endpoint; + struct v4l2_async_notifier notifier; + struct v4l2_mbus_framefmt mbus_format; + struct mutex lock; /* Mbus format lock. */ + + struct v4l2_subdev *source_subdev; +}; + +struct sun8i_a83t_mipi_csi2_device { + struct device *dev; + + struct regmap *regmap; + struct clk *clock_mod; + struct clk *clock_mipi; + struct clk *clock_misc; + struct reset_control *reset; + struct phy *dphy; + + struct sun8i_a83t_mipi_csi2_bridge bridge; +}; + +#endif diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2_reg.h b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2_reg.h new file mode 100644 index 000000000000..2cfc9eb490e6 --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2_reg.h @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2020 Kévin L'hôpital <kevin.lhopital@bootlin.com> + * Copyright 2020-2022 Bootlin + * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> + */ + +#ifndef _SUN8I_A83T_MIPI_CSI2_REG_H_ +#define _SUN8I_A83T_MIPI_CSI2_REG_H_ + +#define SUN8I_A83T_MIPI_CSI2_VERSION_REG 0x0 +#define SUN8I_A83T_MIPI_CSI2_CTRL_REG 0x4 +#define SUN8I_A83T_MIPI_CSI2_CTRL_INIT_VALUE 0xb8c39bec +#define SUN8I_A83T_MIPI_CSI2_CTRL_RESET_N BIT(31) +#define SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_REG 0x8 +#define SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_INIT_VALUE 0xb8d257f8 +#define SUN8I_A83T_MIPI_CSI2_RSVD0_REG 0xc + +#define SUN8I_A83T_MIPI_CSI2_RSVD1_REG 0x18 +#define SUN8I_A83T_MIPI_CSI2_RSVD1_HW_LOCK_VALUE 0xb8c8a30c +#define SUN8I_A83T_MIPI_CSI2_RSVD2_REG 0x1c +#define SUN8I_A83T_MIPI_CSI2_RSVD2_HW_LOCK_VALUE 0xb8df8ad7 +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_REG 0x20 +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_ECC_ERR_DBL BIT(28) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_CKSM_ERR_VC3 BIT(27) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_CKSM_ERR_VC2 BIT(26) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_CKSM_ERR_VC1 BIT(25) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_CKSM_ERR_VC0 BIT(24) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_SEQ_ERR_DT3 BIT(23) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_SEQ_ERR_DT2 BIT(22) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_SEQ_ERR_DT1 BIT(21) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_SEQ_ERR_DT0 BIT(20) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LS_LE_ERR_DT3 BIT(19) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LS_LE_ERR_DT2 BIT(18) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LS_LE_ERR_DT1 BIT(17) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LS_LE_ERR_DT0 BIT(16) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_CRC_ERR_VC3 BIT(15) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_CRC_ERR_VC2 BIT(14) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_CRC_ERR_VC1 BIT(13) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_CRC_ERR_VC0 BIT(12) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FRM_SEQ_ERR_VC3 BIT(11) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FRM_SEQ_ERR_VC2 BIT(10) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FRM_SEQ_ERR_VC1 BIT(9) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FRM_SEQ_ERR_VC0 BIT(8) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FS_FE_ERR_VC3 BIT(7) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FS_FE_ERR_VC2 BIT(6) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FS_FE_ERR_VC1 BIT(5) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FS_FE_ERR_VC0 BIT(4) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_SOT_SYNC_ERR_3 BIT(3) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_SOT_SYNC_ERR_2 BIT(2) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_SOT_SYNC_ERR_1 BIT(1) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_SOT_SYNC_ERR_0 BIT(0) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_REG 0x24 +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LINE_SEQ_ERR_DT7 BIT(23) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LINE_SEQ_ERR_DT6 BIT(22) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LINE_SEQ_ERR_DT5 BIT(21) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LINE_SEQ_ERR_DT4 BIT(20) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LS_LE_ERR_DT7 BIT(19) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LS_LE_ERR_DT6 BIT(18) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LS_LE_ERR_DT5 BIT(17) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LS_LE_ERR_DT4 BIT(16) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_DT_ERR_VC3 BIT(15) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_DT_ERR_VC2 BIT(14) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_DT_ERR_VC1 BIT(13) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_DT_ERR_VC0 BIT(12) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ECC_ERR1_VC3 BIT(11) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ECC_ERR1_VC2 BIT(10) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ECC_ERR1_VC1 BIT(9) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ECC_ERR1_VC0 BIT(8) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_SOT_ERR_3 BIT(7) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_SOT_ERR_2 BIT(6) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_SOT_ERR_1 BIT(5) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_SOT_ERR_0 BIT(4) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ESC_ENTRY_ERR_3 BIT(3) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ESC_ENTRY_ERR_2 BIT(2) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ESC_ENTRY_ERR_1 BIT(1) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ESC_ENTRY_ERR_0 BIT(0) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_REG 0x28 +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_ECC_ERR_DBL BIT(28) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CKSM_ERR_VC3 BIT(27) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CKSM_ERR_VC2 BIT(26) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CKSM_ERR_VC1 BIT(25) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CKSM_ERR_VC0 BIT(24) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LINE_SEQ_ERR_DT3 BIT(23) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LINE_SEQ_ERR_DT2 BIT(22) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LINE_SEQ_ERR_DT1 BIT(21) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LINE_SEQ_ERR_DT0 BIT(20) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LS_LE_ERR_DT3 BIT(19) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LS_LE_ERR_DT2 BIT(18) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LS_LE_ERR_DT1 BIT(17) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LS_LE_ERR_DT0 BIT(16) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CRC_ERR_VC3 BIT(15) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CRC_ERR_VC2 BIT(14) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CRC_ERR_VC1 BIT(13) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CRC_ERR_VC0 BIT(12) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FRM_SEQ_ERR_VC3 BIT(11) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FRM_SEQ_ERR_VC2 BIT(10) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FRM_SEQ_ERR_VC1 BIT(9) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FRM_SEQ_ERR_VC0 BIT(8) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FS_FE_ERR_VC3 BIT(7) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FS_FE_ERR_VC2 BIT(6) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FS_FE_ERR_VC1 BIT(5) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FS_FE_ERR_VC0 BIT(4) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_SOT_SYNC_ERR_3 BIT(3) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_SOT_SYNC_ERR_2 BIT(2) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_SOT_SYNC_ERR_1 BIT(1) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_SOT_SYNC_ERR_0 BIT(0) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_REG 0x2c +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_DT_ERR_VC3 BIT(15) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_DT_ERR_VC2 BIT(14) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_DT_ERR_VC1 BIT(13) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_DT_ERR_VC0 BIT(12) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ECC_ERR1_VC3 BIT(11) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ECC_ERR1_VC2 BIT(10) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ECC_ERR1_VC1 BIT(9) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ECC_ERR1_VC0 BIT(8) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_SOT_ERR_3 BIT(7) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_SOT_ERR_2 BIT(6) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_SOT_ERR_1 BIT(5) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_SOT_ERR_0 BIT(4) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ESC_ENTRY_ERR_3 BIT(3) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ESC_ENTRY_ERR_2 BIT(2) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ESC_ENTRY_ERR_1 BIT(1) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ESC_ENTRY_ERR_0 BIT(0) + +#define SUN8I_A83T_MIPI_CSI2_CFG_REG 0x100 +#define SUN8I_A83T_MIPI_CSI2_CFG_INIT_VALUE 0xb8c64f24 +#define SUN8I_A83T_MIPI_CSI2_CFG_SYNC_EN BIT(31) +#define SUN8I_A83T_MIPI_CSI2_CFG_BYPASS_ECC_EN BIT(29) +#define SUN8I_A83T_MIPI_CSI2_CFG_UNPKT_EN BIT(28) +#define SUN8I_A83T_MIPI_CSI2_CFG_NONE_UNPKT_RX_MODE BIT(27) +#define SUN8I_A83T_MIPI_CSI2_CFG_YC_SWAB BIT(26) +#define SUN8I_A83T_MIPI_CSI2_CFG_N_BYTE BIT(24) +#define SUN8I_A83T_MIPI_CSI2_CFG_SYNC_DLY_CYCLE(v) (((v) << 18) & \ + GENMASK(22, 18)) +#define SUN8I_A83T_MIPI_CSI2_CFG_N_CHANNEL(v) ((((v) - 1) << 16) & \ + GENMASK(17, 16)) +#define SUN8I_A83T_MIPI_CSI2_CFG_N_LANE(v) ((((v) - 1) << 4) & \ + GENMASK(5, 4)) +#define SUN8I_A83T_MIPI_CSI2_VCDT0_REG 0x104 +#define SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(ch, vc) (((vc) & GENMASK(1, 0)) << \ + ((ch) * 8 + 6)) +#define SUN8I_A83T_MIPI_CSI2_VCDT0_CH_DT(ch, t) (((t) & GENMASK(5, 0)) << \ + ((ch) * 8)) +#define SUN8I_A83T_MIPI_CSI2_VCDT1_REG 0x108 +#define SUN8I_A83T_MIPI_CSI2_VCDT1_CH_VC(ch, vc) (((vc) & GENMASK(1, 0)) << \ + (((ch) - 4) * 8 + 6)) +#define SUN8I_A83T_MIPI_CSI2_VCDT1_CH_DT(ch, t) (((t) & GENMASK(5, 0)) << \ + (((ch) - 4) * 8)) + +#endif diff --git a/drivers/media/platform/ti/cal/cal-camerarx.c b/drivers/media/platform/ti/cal/cal-camerarx.c index e69fed117fea..e136d70b4048 100644 --- a/drivers/media/platform/ti/cal/cal-camerarx.c +++ b/drivers/media/platform/ti/cal/cal-camerarx.c @@ -305,7 +305,7 @@ static int cal_camerarx_start(struct cal_camerarx *phy) /* * CSI-2 PHY Link Initialization Sequence, according to the DRA74xP / * DRA75xP / DRA76xP / DRA77xP TRM. The DRA71x / DRA72x and the AM65x / - * DRA80xM TRMs have a a slightly simplified sequence. + * DRA80xM TRMs have a slightly simplified sequence. */ /* @@ -592,7 +592,7 @@ int cal_camerarx_get_remote_frame_desc(struct cal_camerarx *phy, if (!phy->source) return -EPIPE; - pad = media_entity_remote_pad(&phy->pads[CAL_CAMERARX_PAD_SINK]); + pad = media_pad_remote_pad_first(&phy->pads[CAL_CAMERARX_PAD_SINK]); if (!pad) return -EPIPE; diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c index 07ae1a34e6b0..776da0cfcdbe 100644 --- a/drivers/media/platform/ti/cal/cal-video.c +++ b/drivers/media/platform/ti/cal/cal-video.c @@ -685,7 +685,7 @@ static int cal_video_check_format(struct cal_ctx *ctx) const struct v4l2_mbus_framefmt *format; struct media_pad *remote_pad; - remote_pad = media_entity_remote_pad(&ctx->pad); + remote_pad = media_pad_remote_pad_first(&ctx->pad); if (!remote_pad) return -ENODEV; diff --git a/drivers/media/platform/ti/davinci/vpif.c b/drivers/media/platform/ti/davinci/vpif.c index 97ef770266af..da27da4c165a 100644 --- a/drivers/media/platform/ti/davinci/vpif.c +++ b/drivers/media/platform/ti/davinci/vpif.c @@ -469,6 +469,7 @@ static int vpif_probe(struct platform_device *pdev) endpoint); if (!endpoint) return 0; + of_node_put(endpoint); /* * For DT platforms, manually create platform_devices for diff --git a/drivers/media/platform/ti/omap/omap_voutlib.c b/drivers/media/platform/ti/omap/omap_voutlib.c index 480a7e95533d..fdea2309ee37 100644 --- a/drivers/media/platform/ti/omap/omap_voutlib.c +++ b/drivers/media/platform/ti/omap/omap_voutlib.c @@ -314,7 +314,7 @@ unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr) if (virt_addr) { while (size > 0) { - SetPageReserved(virt_to_page(addr)); + SetPageReserved(virt_to_page((void *)addr)); addr += PAGE_SIZE; size -= PAGE_SIZE; } @@ -335,7 +335,7 @@ void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size) order = get_order(size); while (size > 0) { - ClearPageReserved(virt_to_page(addr)); + ClearPageReserved(virt_to_page((void *)addr)); addr += PAGE_SIZE; size -= PAGE_SIZE; } diff --git a/drivers/media/platform/ti/omap3isp/isp.c b/drivers/media/platform/ti/omap3isp/isp.c index 4c937f3f323e..d251736eb420 100644 --- a/drivers/media/platform/ti/omap3isp/isp.c +++ b/drivers/media/platform/ti/omap3isp/isp.c @@ -700,7 +700,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe, if (!(pad->flags & MEDIA_PAD_FL_SINK)) break; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; @@ -797,7 +797,7 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) if (!(pad->flags & MEDIA_PAD_FL_SINK)) break; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; @@ -942,7 +942,7 @@ static int isp_pipeline_is_last(struct media_entity *me) pipe = to_isp_pipeline(me); if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED) return 0; - pad = media_entity_remote_pad(&pipe->output->pad); + pad = media_pad_remote_pad_first(&pipe->output->pad); return pad->entity == me; } diff --git a/drivers/media/platform/ti/omap3isp/ispccdc.c b/drivers/media/platform/ti/omap3isp/ispccdc.c index 108b5e9f82cb..11afb8aec292 100644 --- a/drivers/media/platform/ti/omap3isp/ispccdc.c +++ b/drivers/media/platform/ti/omap3isp/ispccdc.c @@ -1133,7 +1133,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) ccdc->bt656 = false; ccdc->fields = 0; - pad = media_entity_remote_pad(&ccdc->pads[CCDC_PAD_SINK]); + pad = media_pad_remote_pad_first(&ccdc->pads[CCDC_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); if (ccdc->input == CCDC_INPUT_PARALLEL) { struct v4l2_subdev *sd = diff --git a/drivers/media/platform/ti/omap3isp/ispccp2.c b/drivers/media/platform/ti/omap3isp/ispccp2.c index acb58b6ddba1..fc90ff88464f 100644 --- a/drivers/media/platform/ti/omap3isp/ispccp2.c +++ b/drivers/media/platform/ti/omap3isp/ispccp2.c @@ -357,7 +357,7 @@ static int ccp2_if_configure(struct isp_ccp2_device *ccp2) ccp2_pwr_cfg(ccp2); - pad = media_entity_remote_pad(&ccp2->pads[CCP2_PAD_SINK]); + pad = media_pad_remote_pad_first(&ccp2->pads[CCP2_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); buscfg = v4l2_subdev_to_bus_cfg(pipe->external); diff --git a/drivers/media/platform/ti/omap3isp/ispcsi2.c b/drivers/media/platform/ti/omap3isp/ispcsi2.c index 6302e0c94034..6870980a2fa9 100644 --- a/drivers/media/platform/ti/omap3isp/ispcsi2.c +++ b/drivers/media/platform/ti/omap3isp/ispcsi2.c @@ -561,7 +561,7 @@ static int csi2_configure(struct isp_csi2_device *csi2) if (csi2->contexts[0].enabled || csi2->ctrl.if_enable) return -EBUSY; - pad = media_entity_remote_pad(&csi2->pads[CSI2_PAD_SINK]); + pad = media_pad_remote_pad_first(&csi2->pads[CSI2_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); buscfg = v4l2_subdev_to_bus_cfg(pipe->external); diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c index 8811d6dd4ee7..d7059180e80e 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.c +++ b/drivers/media/platform/ti/omap3isp/ispvideo.c @@ -206,7 +206,7 @@ isp_video_remote_subdev(struct isp_video *video, u32 *pad) { struct media_pad *remote; - remote = media_entity_remote_pad(&video->pad); + remote = media_pad_remote_pad_first(&video->pad); if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) return NULL; @@ -981,7 +981,7 @@ static int isp_video_check_external_subdevs(struct isp_video *video, continue; /* ISP entities have always sink pad == 0. Find source. */ - source_pad = media_entity_remote_pad(&ents[i]->pads[0]); + source_pad = media_pad_remote_pad_first(&ents[i]->pads[0]); if (source_pad == NULL) continue; diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c index b31e5913a4cd..71d97042a470 100644 --- a/drivers/media/platform/video-mux.c +++ b/drivers/media/platform/video-mux.c @@ -118,7 +118,7 @@ static int video_mux_s_stream(struct v4l2_subdev *sd, int enable) return -EINVAL; } - pad = media_entity_remote_pad(&sd->entity.pads[vmux->active]); + pad = media_pad_remote_pad_first(&sd->entity.pads[vmux->active]); if (!pad) { dev_err(sd->dev, "Failed to find remote source pad\n"); return -ENOLINK; diff --git a/drivers/media/platform/xilinx/xilinx-csi2rxss.c b/drivers/media/platform/xilinx/xilinx-csi2rxss.c index 051c60cba1e0..cf8e892c47f0 100644 --- a/drivers/media/platform/xilinx/xilinx-csi2rxss.c +++ b/drivers/media/platform/xilinx/xilinx-csi2rxss.c @@ -474,7 +474,7 @@ static struct v4l2_subdev *xcsi2rxss_get_remote_subdev(struct media_pad *local) { struct media_pad *remote; - remote = media_entity_remote_pad(local); + remote = media_pad_remote_pad_first(local); if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) return NULL; diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index 338c3661d809..2d1ef7a25c33 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -44,7 +44,7 @@ xvip_dma_remote_subdev(struct media_pad *local, u32 *pad) { struct media_pad *remote; - remote = media_entity_remote_pad(local); + remote = media_pad_remote_pad_first(local); if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) return NULL; @@ -107,7 +107,7 @@ static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start) if (!(pad->flags & MEDIA_PAD_FL_SINK)) break; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; diff --git a/drivers/media/platform/xilinx/xilinx-vip.h b/drivers/media/platform/xilinx/xilinx-vip.h index d0b0e0600952..48fe229c5b33 100644 --- a/drivers/media/platform/xilinx/xilinx-vip.h +++ b/drivers/media/platform/xilinx/xilinx-vip.h @@ -28,8 +28,8 @@ struct clk; #define XVIP_MAX_HEIGHT 7680 /* - * Pad IDs. IP cores with with multiple inputs or outputs should define - * their own values. + * Pad IDs. IP cores with multiple inputs or outputs should define their own + * values. */ #define XVIP_PAD_SINK 0 #define XVIP_PAD_SOURCE 1 |