From 2f1e5311c13adfda5d4b2cf08b0792fa51b8abc7 Mon Sep 17 00:00:00 2001 From: Eunyoung Lee Date: Mon, 23 Apr 2018 16:20:15 +0900 Subject: [PATCH] [COMMON] fimc-is2: added video_node, GROUP_PAF for paf_rdma Change-Id: I75f9a900781460b471e24068e7d7e235761bbb39 Signed-off-by: Eunyoung Lee --- .../media/platform/exynos/fimc-is2/Makefile | 2 +- .../exynos/fimc-is2/fimc-is-clk-gate.c | 4 + .../platform/exynos/fimc-is2/fimc-is-core.c | 10 + .../platform/exynos/fimc-is2/fimc-is-core.h | 2 + .../exynos/fimc-is2/fimc-is-device-ischain.c | 525 ++++++++++++ .../exynos/fimc-is2/fimc-is-device-ischain.h | 20 + .../exynos/fimc-is2/fimc-is-framemgr.h | 6 +- .../exynos/fimc-is2/fimc-is-groupmgr.c | 5 + .../exynos/fimc-is2/fimc-is-groupmgr.h | 35 +- .../exynos/fimc-is2/fimc-is-interface-wrap.c | 7 +- .../exynos/fimc-is2/fimc-is-subdev-ctrl.h | 1 + .../exynos/fimc-is2/fimc-is-video-pafrdma.c | 796 ++++++++++++++++++ .../platform/exynos/fimc-is2/fimc-is-video.h | 6 + .../exynos/fimc-is2/hardware/Makefile | 1 + .../fimc-is2/hardware/fimc-is-hw-control.c | 48 +- .../fimc-is2/hardware/fimc-is-hw-control.h | 2 + .../fimc-is2/hardware/fimc-is-hw-paf-rdma.c | 442 ++++++++++ .../fimc-is2/hardware/fimc-is-hw-paf-rdma.h | 36 + .../exynos/fimc-is2/include/fimc-is-cmd.h | 2 +- .../fimc-is2/include/fimc-is-common-config.h | 6 + .../interface/fimc-is-interface-ddk.c | 8 +- .../interface/fimc-is-interface-ischain.c | 81 ++ .../interface/fimc-is-interface-ischain.h | 2 + 23 files changed, 2018 insertions(+), 29 deletions(-) create mode 100644 drivers/media/platform/exynos/fimc-is2/fimc-is-video-pafrdma.c create mode 100644 drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-paf-rdma.c create mode 100644 drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-paf-rdma.h diff --git a/drivers/media/platform/exynos/fimc-is2/Makefile b/drivers/media/platform/exynos/fimc-is2/Makefile index d299d6fd642b..05fa9ce1dd59 100644 --- a/drivers/media/platform/exynos/fimc-is2/Makefile +++ b/drivers/media/platform/exynos/fimc-is2/Makefile @@ -28,6 +28,7 @@ fimc-is-objs := fimc-is-core.o \ fimc-is-video-ssvc2.o \ fimc-is-video-ssvc3.o \ fimc-is-video-preprocessor.o \ + fimc-is-video-pafrdma.o \ fimc-is-subdev-ctrl.o \ fimc-is-device-ischain.o \ fimc-is-device-preprocessor.o \ @@ -62,7 +63,6 @@ obj-$(CONFIG_EXYNOS_DEVICE_MIPI_CSIS_VER4) += fimc-is-device-csi_v4.o obj-$(CONFIG_EXYNOS_FIMC_BNS) += fimc-is-device-flite.o - obj-$(CONFIG_VIDEO_EXYNOS_FIMC_IS2) += fimc-is.o obj-$(CONFIG_VIDEO_EXYNOS_FIMC_IS2) += sensor/ obj-$(CONFIG_VIDEO_EXYNOS_FIMC_IS2) += ischain/ diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-clk-gate.c b/drivers/media/platform/exynos/fimc-is2/fimc-is-clk-gate.c index c3a65002bcf1..4e100ec23403 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-clk-gate.c +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-clk-gate.c @@ -91,6 +91,10 @@ inline bool fimc_is_group_otf(struct fimc_is_device_ischain *device, int group_i struct fimc_is_group *group; switch (group_id) { + case GROUP_ID_PAF0: + case GROUP_ID_PAF1: + group = &device->group_paf; + break; case GROUP_ID_3AA0: case GROUP_ID_3AA1: group = &device->group_3aa; diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-core.c b/drivers/media/platform/exynos/fimc-is2/fimc-is-core.c index dc5e62d21ec9..ab738eff97d1 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-core.c +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-core.c @@ -1307,6 +1307,16 @@ static int __init fimc_is_probe(struct platform_device *pdev) fimc_is_vra_video_probe(core); #endif +#ifdef SOC_PAF0 + /* video entity - paf_rdma0 */ + fimc_is_paf0s_video_probe(core); +#endif + +#ifdef SOC_PAF1 + /* video entity - paf_rdma1 */ + fimc_is_paf1s_video_probe(core); +#endif + /* TODO: video probe is needed for DCP */ platform_set_drvdata(pdev, core); diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-core.h b/drivers/media/platform/exynos/fimc-is2/fimc-is-core.h index 597f428bb567..0c8f108201ff 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-core.h +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-core.h @@ -333,6 +333,8 @@ struct fimc_is_core { struct fimc_is_video video_m4p; struct fimc_is_video video_m5p; struct fimc_is_video video_vra; + struct fimc_is_video video_paf0s; + struct fimc_is_video video_paf1s; /* spi */ struct fimc_is_spi spi0; diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-device-ischain.c b/drivers/media/platform/exynos/fimc-is2/fimc-is-device-ischain.c index d4a3024af951..859f18624f76 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-device-ischain.c +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-device-ischain.c @@ -66,6 +66,7 @@ #include "fimc-is-device-preprocessor.h" #include "fimc-is-vender-specific.h" #include "exynos-fimc-is-module.h" +#include "./sensor/module_framework/modules/fimc-is-device-module-base.h" #include "fimc-is-vender-specific.h" @@ -98,6 +99,7 @@ extern struct pm_qos_request exynos_isp_qos_cpu_online_min; extern struct gb_qos_request gb_req; #endif +extern const struct fimc_is_subdev_ops fimc_is_subdev_paf_ops; extern const struct fimc_is_subdev_ops fimc_is_subdev_3aa_ops; extern const struct fimc_is_subdev_ops fimc_is_subdev_3ac_ops; extern const struct fimc_is_subdev_ops fimc_is_subdev_3ap_ops; @@ -123,6 +125,8 @@ extern const struct fimc_is_subdev_ops fimc_is_subdev_vra_ops; extern void *fd_vaddr; #endif +static int fimc_is_ischain_paf_stop(void *qdevice, + struct fimc_is_queue *queue); static int fimc_is_ischain_3aa_stop(void *qdevice, struct fimc_is_queue *queue); static int fimc_is_ischain_isp_stop(void *qdevice, @@ -136,6 +140,8 @@ static int fimc_is_ischain_mcs_stop(void *qdevice, static int fimc_is_ischain_vra_stop(void *qdevice, struct fimc_is_queue *queue); +static int fimc_is_ischain_paf_shot(struct fimc_is_device_ischain *device, + struct fimc_is_frame *frame); static int fimc_is_ischain_3aa_shot(struct fimc_is_device_ischain *device, struct fimc_is_frame *frame); static int fimc_is_ischain_isp_shot(struct fimc_is_device_ischain *device, @@ -1332,6 +1338,9 @@ static u32 fimc_is_itf_g_group_info(struct fimc_is_device_ischain *device, { u32 group = 0; + if (path->group[GROUP_SLOT_PAF] != GROUP_ID_MAX) + group |= (GROUP_ID(path->group[GROUP_SLOT_PAF]) & GROUP_ID_PARM_MASK); + if (path->group[GROUP_SLOT_3AA] != GROUP_ID_MAX) group |= (GROUP_ID(path->group[GROUP_SLOT_3AA]) & GROUP_ID_PARM_MASK); @@ -3264,6 +3273,9 @@ int fimc_is_ischain_probe(struct fimc_is_device_ischain *device, fimc_is_pipe_probe(&device->pipe); #endif + fimc_is_group_probe(groupmgr, &device->group_paf, NULL, device, + fimc_is_ischain_paf_shot, + GROUP_SLOT_PAF, ENTRY_PAF, "PXS", &fimc_is_subdev_paf_ops); fimc_is_group_probe(groupmgr, &device->group_3aa, NULL, device, fimc_is_ischain_3aa_shot, GROUP_SLOT_3AA, ENTRY_3AA, "3XS", &fimc_is_subdev_3aa_ops); @@ -4106,6 +4118,292 @@ p_err: return ret; } +int fimc_is_ischain_paf_open(struct fimc_is_device_ischain *device, + struct fimc_is_video_ctx *vctx) +{ + int ret = 0; + int ret_err = 0; + u32 group_id; + struct fimc_is_groupmgr *groupmgr; + struct fimc_is_group *group; + + FIMC_BUG(!device); + FIMC_BUG(!vctx); + FIMC_BUG(!GET_VIDEO(vctx)); + + groupmgr = device->groupmgr; + group = &device->group_paf; + group_id = GROUP_ID_PAF0 + GET_PAFXS_ID(GET_VIDEO(vctx)); + + ret = fimc_is_group_open(groupmgr, + group, + group_id, + vctx); + if (ret) { + merr("fimc_is_group_open is fail(%d)", device, ret); + goto err_group_open; + } + + ret = fimc_is_ischain_open_wrap(device, false); + if (ret) { + merr("fimc_is_ischain_open_wrap is fail(%d)", device, ret); + goto err_ischain_open; + } + + atomic_inc(&device->group_open_cnt); + + return 0; + +err_ischain_open: + ret_err = fimc_is_group_close(groupmgr, group); + if (ret_err) + merr("fimc_is_group_close is fail(%d)", device, ret_err); +err_group_open: + return ret; +} + +int fimc_is_ischain_paf_close(struct fimc_is_device_ischain *device, + struct fimc_is_video_ctx *vctx) +{ + int ret = 0; + struct fimc_is_groupmgr *groupmgr; + struct fimc_is_group *group; + struct fimc_is_queue *queue; + + FIMC_BUG(!device); + + groupmgr = device->groupmgr; + group = &device->group_paf; + queue = GET_QUEUE(vctx); + + /* for mediaserver dead */ + if (test_bit(FIMC_IS_GROUP_START, &group->state)) { + mgwarn("sudden group close", device, group); + if (!test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state)) + fimc_is_itf_sudden_stop_wrap(device, device->instance); + set_bit(FIMC_IS_GROUP_REQUEST_FSTOP, &group->state); + if (test_bit(FIMC_IS_HAL_DEBUG_SUDDEN_DEAD_DETECT, &sysfs_debug.hal_debug_mode)) { + msleep(sysfs_debug.hal_debug_delay); + panic("HAL sudden group close #1"); + } + } + + if (group->head && test_bit(FIMC_IS_GROUP_START, &group->head->state)) { + mgwarn("sudden group close", device, group); + if (!test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state)) + fimc_is_itf_sudden_stop_wrap(device, device->instance); + set_bit(FIMC_IS_GROUP_REQUEST_FSTOP, &group->state); + if (test_bit(FIMC_IS_HAL_DEBUG_SUDDEN_DEAD_DETECT, &sysfs_debug.hal_debug_mode)) { + msleep(sysfs_debug.hal_debug_delay); + panic("HAL sudden group close #2"); + } + } + + ret = fimc_is_ischain_paf_stop(device, queue); + if (ret) + merr("fimc_is_ischain_paf_rdma_stop is fail", device); + + ret = fimc_is_group_close(groupmgr, group); + if (ret) + merr("fimc_is_group_close is fail", device); + + ret = fimc_is_ischain_close_wrap(device); + if (ret) + merr("fimc_is_ischain_close_wrap is fail(%d)", device, ret); + + atomic_dec(&device->group_open_cnt); + + return ret; +} + +int fimc_is_ischain_paf_s_input(struct fimc_is_device_ischain *device, + u32 stream_type, + u32 module_id, + u32 video_id, + u32 input_type, + u32 stream_leader) +{ + int ret = 0; + struct fimc_is_group *group; + struct fimc_is_groupmgr *groupmgr; + + FIMC_BUG(!device); + FIMC_BUG(!device->groupmgr); + + groupmgr = device->groupmgr; + group = &device->group_paf; + + mdbgd_ischain("%s()\n", device, __func__); + + ret = fimc_is_group_init(groupmgr, group, input_type, video_id, stream_leader); + if (ret) { + merr("fimc_is_group_init is fail(%d)", device, ret); + goto p_err; + } + + ret = fimc_is_ischain_init_wrap(device, stream_type, module_id); + if (ret) { + merr("fimc_is_ischain_init_wrap is fail(%d)", device, ret); + goto p_err; + } + +p_err: + return ret; +} + +static int fimc_is_ischain_paf_start(void *qdevice, + struct fimc_is_queue *queue) +{ + int ret = 0; + struct fimc_is_device_ischain *device = qdevice; + struct fimc_is_groupmgr *groupmgr; + struct fimc_is_group *group; + + FIMC_BUG(!device); + + groupmgr = device->groupmgr; + group = &device->group_paf; + + ret = fimc_is_group_start(groupmgr, group); + if (ret) { + merr("fimc_is_group_start is fail(%d)", device, ret); + goto p_err; + } + + ret = fimc_is_ischain_start_wrap(device, group); + if (ret) { + merr("fimc_is_ischain_start_wrap is fail(%d)", device, ret); + goto p_err; + } + +p_err: + return ret; +} + +static int fimc_is_ischain_paf_stop(void *qdevice, + struct fimc_is_queue *queue) +{ + int ret = 0; + struct fimc_is_device_ischain *device = qdevice; + struct fimc_is_groupmgr *groupmgr; + struct fimc_is_group *group; + + FIMC_BUG(!device); + + groupmgr = device->groupmgr; + group = &device->group_paf; + + ret = fimc_is_group_stop(groupmgr, group); + if (ret) { + merr("fimc_is_group_stop is fail(%d)", device, ret); + goto p_err; + } + + ret = fimc_is_ischain_stop_wrap(device, group); + if (ret) { + merr("fimc_is_ischain_stop_wrap is fail(%d)", device, ret); + goto p_err; + } + +p_err: + mginfo("%s(%d):%d\n", device, group, __func__, atomic_read(&group->scount), ret); + return ret; +} + +static int fimc_is_ischain_paf_reqbufs(void *qdevice, + struct fimc_is_queue *queue, u32 count) +{ + int ret = 0; + struct fimc_is_device_ischain *device = qdevice; + struct fimc_is_group *group; + + FIMC_BUG(!device); + + group = &device->group_paf; + + if (!count) { + ret = fimc_is_itf_unmap(device, GROUP_ID(group->id)); + if (ret) + merr("fimc_is_itf_unmap is fail(%d)", device, ret); + } + + return ret; +} + +static int fimc_is_ischain_paf_s_format(void *qdevice, + struct fimc_is_queue *queue) +{ + int ret = 0; + struct fimc_is_device_ischain *device = qdevice; + struct fimc_is_subdev *leader; + + FIMC_BUG(!device); + FIMC_BUG(!queue); + + leader = &device->group_paf.leader; + + leader->input.width = queue->framecfg.width; + leader->input.height = queue->framecfg.height; + + leader->input.crop.x = 0; + leader->input.crop.y = 0; + leader->input.crop.w = leader->input.width; + leader->input.crop.h = leader->input.height; + + return ret; +} + +int fimc_is_ischain_paf_buffer_queue(struct fimc_is_device_ischain *device, + struct fimc_is_queue *queue, + u32 index) +{ + int ret = 0; + struct fimc_is_groupmgr *groupmgr; + struct fimc_is_group *group; + + FIMC_BUG(!device); + FIMC_BUG(!test_bit(FIMC_IS_ISCHAIN_OPEN, &device->state)); + + mdbgs_ischain(4, "%s\n", device, __func__); + + groupmgr = device->groupmgr; + group = &device->group_paf; + + ret = fimc_is_group_buffer_queue(groupmgr, group, queue, index); + if (ret) + merr("fimc_is_group_buffer_queue is fail(%d)", device, ret); + + return ret; +} + +int fimc_is_ischain_paf_buffer_finish(struct fimc_is_device_ischain *device, + u32 index) +{ + int ret = 0; + struct fimc_is_groupmgr *groupmgr; + struct fimc_is_group *group; + + FIMC_BUG(!device); + + mdbgs_ischain(4, "%s\n", device, __func__); + + groupmgr = device->groupmgr; + group = &device->group_paf; + + ret = fimc_is_group_buffer_finish(groupmgr, group, index); + if (ret) + merr("fimc_is_group_buffer_finish is fail(%d)", device, ret); + + return ret; +} + +const struct fimc_is_queue_ops fimc_is_ischain_paf_ops = { + .start_streaming = fimc_is_ischain_paf_start, + .stop_streaming = fimc_is_ischain_paf_stop, + .s_format = fimc_is_ischain_paf_s_format, + .request_bufs = fimc_is_ischain_paf_reqbufs +}; + int fimc_is_ischain_3aa_open(struct fimc_is_device_ischain *device, struct fimc_is_video_ctx *vctx) { @@ -5826,6 +6124,25 @@ const struct fimc_is_queue_ops fimc_is_ischain_vra_ops = { .request_bufs = fimc_is_ischain_vra_reqbufs }; +static int fimc_is_ischain_paf_group_tag(struct fimc_is_device_ischain *device, + struct fimc_is_frame *frame, + struct camera2_node *ldr_node) +{ + int ret = 0; + struct fimc_is_group *group; + + group = &device->group_paf; + + ret = CALL_SOPS(&group->leader, tag, device, frame, ldr_node); + if (ret) { + merr("fimc_is_ischain_paf_tag is fail(%d)", device, ret); + goto p_err; + } + +p_err: + return ret; +} + static int fimc_is_ischain_3aa_group_tag(struct fimc_is_device_ischain *device, struct fimc_is_frame *frame, struct camera2_node *ldr_node) @@ -6467,6 +6784,214 @@ static void fimc_is_ischain_update_shot(struct fimc_is_device_ischain *device, #endif } +static int fimc_is_ischain_paf_shot(struct fimc_is_device_ischain *device, + struct fimc_is_frame *check_frame) +{ + int ret = 0; + unsigned long flags; + struct fimc_is_group *group, *child, *vra; + struct fimc_is_framemgr *framemgr; + struct fimc_is_frame *frame; + struct camera2_node_group *node_group; + struct camera2_node ldr_node = {0, }; + u32 setfile_save = 0; + + FIMC_BUG(!device); + FIMC_BUG(!check_frame); + + mdbgs_ischain(4, "%s()\n", device, __func__); + + frame = NULL; + group = &device->group_paf; + + framemgr = GET_HEAD_GROUP_FRAMEMGR(group); + if (!framemgr) { + merr("framemgr is NULL", device); + ret = -EINVAL; + goto p_err; + } + + frame = peek_frame(framemgr, FS_REQUEST); + + if (unlikely(!frame)) { + merr("frame is NULL", device); + ret = -EINVAL; + goto p_err; + } + + if (unlikely(frame != check_frame)) { + merr("frame checking is fail(%p != %p)", device, frame, check_frame); + ret = -EINVAL; + goto p_err; + } + + if (unlikely(!frame->shot)) { + merr("frame->shot is NULL", device); + ret = -EINVAL; + goto p_err; + } + + if (unlikely(!test_bit(FRAME_MEM_MAPPED, &frame->mem_state))) { + fimc_is_itf_map(device, GROUP_ID(group->id), frame->dvaddr_shot, frame->shot_size); + set_bit(FRAME_MEM_MAPPED, &frame->mem_state); + } + + frame->shot->ctl.vendor_entry.lowIndexParam = 0; + frame->shot->ctl.vendor_entry.highIndexParam = 0; + frame->shot->dm.vendor_entry.lowIndexParam = 0; + frame->shot->dm.vendor_entry.highIndexParam = 0; + node_group = &frame->shot_ext->node_group; + + PROGRAM_COUNT(8); + + if ((frame->shot_ext->setfile != device->setfile) && + (group->id == get_ischain_leader_group(device)->id)) { + setfile_save = device->setfile; + device->setfile = frame->shot_ext->setfile; + + mgrinfo(" setfile change at shot(%d -> %d)\n", device, group, frame, + setfile_save, device->setfile & FIMC_IS_SETFILE_MASK); + + if (test_bit(FIMC_IS_ISCHAIN_REPROCESSING, &device->state)) { + ret = fimc_is_ischain_chg_setfile(device); + if (ret) { + merr("fimc_is_ischain_chg_setfile is fail", device); + device->setfile = setfile_save; + goto p_err; + } + } + } + + if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state)) { + enum aa_capture_intent captureIntent; + captureIntent = group->intent_ctl.captureIntent; + + if (captureIntent != AA_CAPTURE_INTENT_CUSTOM) { + frame->shot->ctl.aa.captureIntent = captureIntent; + group->intent_ctl.captureIntent = AA_CAPTURE_INTENT_CUSTOM; + frame->shot->ctl.aa.vendor_captureCount = group->intent_ctl.vendor_captureCount; + group->intent_ctl.vendor_captureCount = 0; + if (group->intent_ctl.vendor_captureExposureTime > 0) { + frame->shot->ctl.aa.vendor_captureExposureTime = group->intent_ctl.vendor_captureExposureTime; + group->intent_ctl.vendor_captureExposureTime = 0; + } + minfo("frame count(%d), intent(%d), count(%d) captureExposureTime(%d)\n", device, frame->fcount, + frame->shot->ctl.aa.captureIntent, frame->shot->ctl.aa.vendor_captureCount, + frame->shot->ctl.aa.vendor_captureExposureTime); + } + } + + /* fd information copy */ +#if !defined(ENABLE_SHARED_METADATA) && !defined(FAST_FDAE) + memcpy(&frame->shot->uctl.fdUd, &device->fdUd, sizeof(struct camera2_fd_uctl)); +#endif + + PROGRAM_COUNT(9); + + if (test_bit(FIMC_IS_SUBDEV_PARAM_ERR, &group->head->leader.state)) + set_bit(FIMC_IS_SUBDEV_FORCE_SET, &group->head->leader.state); + else + clear_bit(FIMC_IS_SUBDEV_FORCE_SET, &group->head->leader.state); + + child = group; + while (child) { + switch (child->slot) { + case GROUP_SLOT_PAF: + TRANS_CROP(ldr_node.input.cropRegion, + node_group->leader.input.cropRegion); + + ret = fimc_is_ischain_paf_group_tag(device, frame, &ldr_node); + if (ret) { + merr("fimc_is_ischain_paf_group_tag is fail(%d)", device, ret); + goto p_err; + } + break; + case GROUP_SLOT_3AA: + TRANS_CROP(ldr_node.input.cropRegion, + node_group->leader.input.cropRegion); + if (child->junction->cid < CAPTURE_NODE_MAX) { + TRANS_CROP(ldr_node.output.cropRegion, + node_group->capture[child->junction->cid].output.cropRegion); + } else { + mgerr("capture id(%d) is invalid", group, group, child->junction->cid); + } + + ret = fimc_is_ischain_3aa_group_tag(device, frame, &ldr_node); + if (ret) { + merr("fimc_is_ischain_3aa_group_tag is fail(%d)", device, ret); + goto p_err; + } + break; + case GROUP_SLOT_ISP: + TRANS_CROP(ldr_node.input.cropRegion, + ldr_node.output.cropRegion); + TRANS_CROP(ldr_node.output.cropRegion, + ldr_node.input.cropRegion); + ret = fimc_is_ischain_isp_group_tag(device, frame, &ldr_node); + if (ret) { + merr("fimc_is_ischain_isp_group_tag is fail(%d)", device, ret); + goto p_err; + } + break; + case GROUP_SLOT_DIS: + TRANS_CROP(ldr_node.input.cropRegion, + ldr_node.output.cropRegion); + TRANS_CROP(ldr_node.output.cropRegion, + ldr_node.input.cropRegion); + ret = fimc_is_ischain_dis_group_tag(device, frame, &ldr_node); + if (ret) { + merr("fimc_is_ischain_dis_group_tag is fail(%d)", device, ret); + goto p_err; + } + break; + case GROUP_SLOT_MCS: + TRANS_CROP(ldr_node.input.cropRegion, + ldr_node.output.cropRegion); + TRANS_CROP(ldr_node.output.cropRegion, + ldr_node.input.cropRegion); + ret = fimc_is_ischain_mcs_group_tag(device, frame, &ldr_node); + if (ret) { + merr("fimc_is_ischain_mcs_group_tag is fail(%d)", device, ret); + goto p_err; + } + break; + case GROUP_SLOT_VRA: + vra = &device->group_vra; + TRANS_CROP(ldr_node.input.cropRegion, + (u32 *)&vra->prev->junction->output.crop); + TRANS_CROP(ldr_node.output.cropRegion, + ldr_node.input.cropRegion); + ret = fimc_is_ischain_vra_group_tag(device, frame, &ldr_node); + if (ret) { + merr("fimc_is_ischain_vra_group_tag is fail(%d)", device, ret); + goto p_err; + } + break; + default: + merr("group slot is invalid(%d)", device, child->slot); + BUG(); + } + + child = child->child; + } + + PROGRAM_COUNT(10); + +p_err: + fimc_is_ischain_update_shot(device, frame); + + if (ret) { + mgrerr(" SKIP(%d) : %d\n", device, group, check_frame, check_frame->index, ret); + } else { + set_bit(group->leader.id, &frame->out_flag); + framemgr_e_barrier_irqs(framemgr, FMGR_IDX_25, flags); + trans_frame(framemgr, frame, FS_PROCESS); + framemgr_x_barrier_irqr(framemgr, FMGR_IDX_25, flags); + } + + return ret; +} + static int fimc_is_ischain_3aa_shot(struct fimc_is_device_ischain *device, struct fimc_is_frame *check_frame) { diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-device-ischain.h b/drivers/media/platform/exynos/fimc-is2/fimc-is-device-ischain.h index 1d5ad2e78a21..1bb288b78de7 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-device-ischain.h +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-device-ischain.h @@ -128,6 +128,8 @@ struct fimc_is_device_ischain { struct fimc_is_pipe pipe; #endif + struct fimc_is_group group_paf; /* for PAF RDMA */ + struct fimc_is_group group_3aa; struct fimc_is_subdev txc; struct fimc_is_subdev txp; @@ -205,6 +207,23 @@ int fimc_is_ischain_stop_wrap(struct fimc_is_device_ischain *device, void fimc_is_ischain_version(enum fimc_is_bin_type type, const char *load_bin, u32 size); char* fimc_is_ischain_get_version(enum fimc_is_bin_type type); +/* PAF_RDMA subdev */ +int fimc_is_ischain_paf_open(struct fimc_is_device_ischain *device, + struct fimc_is_video_ctx *vctx); +int fimc_is_ischain_paf_close(struct fimc_is_device_ischain *device, + struct fimc_is_video_ctx *vctx); +int fimc_is_ischain_paf_s_input(struct fimc_is_device_ischain *device, + u32 stream_type, + u32 module_id, + u32 video_id, + u32 input_type, + u32 stream_leader); +int fimc_is_ischain_paf_buffer_queue(struct fimc_is_device_ischain *device, + struct fimc_is_queue *queue, + u32 index); +int fimc_is_ischain_paf_buffer_finish(struct fimc_is_device_ischain *device, + u32 index); + /* 3AA subdev */ int fimc_is_ischain_3aa_open(struct fimc_is_device_ischain *device, struct fimc_is_video_ctx *vctx); @@ -362,6 +381,7 @@ int fimc_is_ischain_buf_tag_64bit(struct fimc_is_device_ischain *device, u32 height, uint64_t target_addr[]); +extern const struct fimc_is_queue_ops fimc_is_ischain_paf_ops; extern const struct fimc_is_queue_ops fimc_is_ischain_3aa_ops; extern const struct fimc_is_queue_ops fimc_is_ischain_isp_ops; extern const struct fimc_is_queue_ops fimc_is_ischain_dis_ops; diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-framemgr.h b/drivers/media/platform/exynos/fimc-is2/fimc-is-framemgr.h index 31da4381bbce..6cf62c4f73af 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-framemgr.h +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-framemgr.h @@ -67,10 +67,12 @@ FRAMEMGR_ID_SSXVC2 | FRAMEMGR_ID_SSXVC3) #else #define FRAMEMGR_ID_MEXC 0x02000000 /* for ME */ -#define FRAMEMGR_ID_HW 0x04000000 +#define FRAMEMGR_ID_PAFXS 0x04000000 /* for PAF_RDMA */ +#define FRAMEMGR_ID_HW 0x08000000 #define FRAMEMGR_ID_SHOT (FRAMEMGR_ID_SSX | FRAMEMGR_ID_3XS | \ FRAMEMGR_ID_IXS | FRAMEMGR_ID_DXS | \ - FRAMEMGR_ID_MXS | FRAMEMGR_ID_VRA) + FRAMEMGR_ID_MXS | FRAMEMGR_ID_VRA | \ + FRAMEMGR_ID_PAFXS) #define FRAMEMGR_ID_STREAM (FRAMEMGR_ID_3XC | FRAMEMGR_ID_3XP | \ FRAMEMGR_ID_DXS | FRAMEMGR_ID_DXC | \ FRAMEMGR_ID_M0P | FRAMEMGR_ID_M1P | \ diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-groupmgr.c b/drivers/media/platform/exynos/fimc-is2/fimc-is-groupmgr.c index 9eec022f729d..ff613501dc66 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-groupmgr.c +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-groupmgr.c @@ -1252,6 +1252,10 @@ int fimc_is_groupmgr_init(struct fimc_is_groupmgr *groupmgr, } break; #endif + case GROUP_ID_PAF0: + break; + case GROUP_ID_PAF1: + break; case GROUP_ID_3AA0: if ((video->id >= FIMC_IS_VIDEO_31S_NUM) && (video->id <= FIMC_IS_VIDEO_31P_NUM)) { @@ -2202,6 +2206,7 @@ void wait_subdev_flush_work(struct fimc_is_device_ischain *device, wq_id = WORK_M5P_FDONE; break; case ENTRY_SENSOR: /* Falls Through */ + case ENTRY_PAF: /* Falls Through */ case ENTRY_3AA: /* Falls Through */ case ENTRY_ISP: /* Falls Through */ case ENTRY_DIS: /* Falls Through */ diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-groupmgr.h b/drivers/media/platform/exynos/fimc-is2/fimc-is-groupmgr.h index ad149fd5f06a..d610e29cf437 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-groupmgr.h +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-groupmgr.h @@ -35,26 +35,29 @@ #define GROUP_ID_MCS0 7 #define GROUP_ID_MCS1 8 #define GROUP_ID_VRA0 9 -#define GROUP_ID_SS0 10 -#define GROUP_ID_SS1 11 -#define GROUP_ID_SS2 12 -#define GROUP_ID_SS3 13 -#define GROUP_ID_SS4 14 -#define GROUP_ID_SS5 15 -#define GROUP_ID_MAX 16 +#define GROUP_ID_PAF0 10 /* PAF RDMA */ +#define GROUP_ID_PAF1 11 /* PAF RDMA */ +#define GROUP_ID_SS0 12 +#define GROUP_ID_SS1 13 +#define GROUP_ID_SS2 14 +#define GROUP_ID_SS3 15 +#define GROUP_ID_SS4 16 +#define GROUP_ID_SS5 17 +#define GROUP_ID_MAX 18 #define GROUP_ID_PARM_MASK ((1 << (GROUP_ID_SS0)) - 1) -#define GROUP_ID_SHIFT (16) -#define GROUP_ID_MASK (0xFFFF) +#define GROUP_ID_SHIFT (18) +#define GROUP_ID_MASK (0x3FFFF) #define GROUP_ID(id) (1 << (id)) #define GROUP_SLOT_SENSOR 0 -#define GROUP_SLOT_3AA 1 -#define GROUP_SLOT_ISP 2 -#define GROUP_SLOT_DIS 3 -#define GROUP_SLOT_DCP 4 -#define GROUP_SLOT_MCS 5 -#define GROUP_SLOT_VRA 6 -#define GROUP_SLOT_MAX 7 +#define GROUP_SLOT_PAF 1 +#define GROUP_SLOT_3AA 2 +#define GROUP_SLOT_ISP 3 +#define GROUP_SLOT_DIS 4 +#define GROUP_SLOT_DCP 5 +#define GROUP_SLOT_MCS 6 +#define GROUP_SLOT_VRA 7 +#define GROUP_SLOT_MAX 8 #else #define TRACE_GROUP #define GROUP_ID_3AA0 0 diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-interface-wrap.c b/drivers/media/platform/exynos/fimc-is2/fimc-is-interface-wrap.c index 4c75bd71c268..2aac9d7818b1 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-interface-wrap.c +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-interface-wrap.c @@ -145,8 +145,11 @@ int fimc_is_itf_open_wrap(struct fimc_is_device_ischain *device, u32 module_id, for (hw_id = 0; hw_id < DEV_HW_END; hw_id++) clear_bit(hw_id, &hardware->hw_map[instance]); - for (group_slot = GROUP_SLOT_3AA; group_slot < GROUP_SLOT_MAX; group_slot++) { + for (group_slot = GROUP_SLOT_PAF; group_slot < GROUP_SLOT_MAX; group_slot++) { switch (group_slot) { + case GROUP_SLOT_PAF: + group = &device->group_paf; + break; case GROUP_SLOT_3AA: group = &device->group_3aa; break; @@ -247,7 +250,7 @@ int fimc_is_itf_close_wrap(struct fimc_is_device_ischain *device) } #endif - for (group_slot = GROUP_SLOT_3AA; group_slot < GROUP_SLOT_MAX; group_slot++) { + for (group_slot = GROUP_SLOT_PAF; group_slot < GROUP_SLOT_MAX; group_slot++) { group_id = path->group[group_slot]; dbg_hw(1, "itf_close_wrap: group[SLOT_%d]=[%x]\n", group_slot, group_id); hw_maxnum = fimc_is_get_hw_list(group_id, hw_list); diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-subdev-ctrl.h b/drivers/media/platform/exynos/fimc-is2/fimc-is-subdev-ctrl.h index a5fb3f64a246..137cbd7025ce 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-subdev-ctrl.h +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-subdev-ctrl.h @@ -81,6 +81,7 @@ enum fimc_is_subdev_id { ENTRY_M4P, ENTRY_M5P, ENTRY_VRA, + ENTRY_PAF, /* PDP(PATSTAT) RDMA */ ENTRY_END }; diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-video-pafrdma.c b/drivers/media/platform/exynos/fimc-is2/fimc-is-video-pafrdma.c new file mode 100644 index 000000000000..7ca147589838 --- /dev/null +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-video-pafrdma.c @@ -0,0 +1,796 @@ +/* + * Samsung Exynos5 SoC series FIMC-IS driver + * + * exynos5 fimc-is video functions + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "fimc-is-core.h" +#include "fimc-is-cmd.h" +#include "fimc-is-regs.h" +#include "fimc-is-err.h" +#include "fimc-is-video.h" +#include "fimc-is-param.h" + +const struct v4l2_file_operations fimc_is_paf_video_fops; +const struct v4l2_ioctl_ops fimc_is_paf_video_ioctl_ops; +const struct vb2_ops fimc_is_paf_qops; + +int fimc_is_paf0s_video_probe(void *data) +{ + int ret = 0; + struct fimc_is_core *core; + struct fimc_is_video *video; + + BUG_ON(!data); + + core = (struct fimc_is_core *)data; + video = &core->video_paf0s; + video->resourcemgr = &core->resourcemgr; + + if (!core->pdev) { + probe_err("pdev is NULL"); + ret = -EINVAL; + goto p_err; + } + + ret = fimc_is_video_probe(video, + FIMC_IS_VIDEO_PAFXS_NAME(0), + FIMC_IS_VIDEO_PAF0S_NUM, + VFL_DIR_M2M, + &core->resourcemgr.mem, + &core->v4l2_dev, + &fimc_is_paf_video_fops, + &fimc_is_paf_video_ioctl_ops); + if (ret) + dev_err(&core->pdev->dev, "%s is fail(%d)\n", __func__, ret); + +p_err: + return ret; +} + +int fimc_is_paf1s_video_probe(void *data) +{ + int ret = 0; + struct fimc_is_core *core; + struct fimc_is_video *video; + + BUG_ON(!data); + + core = (struct fimc_is_core *)data; + video = &core->video_paf1s; + video->resourcemgr = &core->resourcemgr; + + if (!core->pdev) { + probe_err("pdev is NULL"); + ret = -EINVAL; + goto p_err; + } + + ret = fimc_is_video_probe(video, + FIMC_IS_VIDEO_PAFXS_NAME(1), + FIMC_IS_VIDEO_PAF1S_NUM, + VFL_DIR_M2M, + &core->resourcemgr.mem, + &core->v4l2_dev, + &fimc_is_paf_video_fops, + &fimc_is_paf_video_ioctl_ops); + if (ret) + dev_err(&core->pdev->dev, "%s is fail(%d)\n", __func__, ret); + +p_err: + return ret; +} + +/* + * ============================================================================= + * Video File Opertation + * ============================================================================= + */ + +static int fimc_is_paf_video_open(struct file *file) +{ + int ret = 0; + int ret_err = 0; + struct fimc_is_video *video; + struct fimc_is_video_ctx *vctx; + struct fimc_is_device_ischain *device; + struct fimc_is_resourcemgr *resourcemgr; + char name[FIMC_IS_STR_LEN]; + + vctx = NULL; + device = NULL; + video = video_drvdata(file); + resourcemgr = video->resourcemgr; + if (!resourcemgr) { + err("resourcemgr is NULL"); + ret = -EINVAL; + goto err_resource_null; + } + + ret = fimc_is_resource_open(resourcemgr, RESOURCE_TYPE_ISCHAIN, (void **)&device); + if (ret) { + err("fimc_is_resource_open is fail(%d)", ret); + goto err_resource_open; + } + + if (!device) { + err("device is NULL"); + ret = -EINVAL; + goto err_device_null; + } + + minfo("[PAF%dS:V] %s\n", device, GET_PAFXS_ID(video), __func__); + + snprintf(name, sizeof(name), "PAF%dS", GET_PAFXS_ID(video)); + ret = open_vctx(file, video, &vctx, device->instance, FRAMEMGR_ID_PAFXS, name); + if (ret) { + merr("open_vctx is fail(%d)", device, ret); + goto err_vctx_open; + } + + ret = fimc_is_video_open(vctx, + device, + VIDEO_PAFXS_READY_BUFFERS, + video, + &fimc_is_paf_qops, + &fimc_is_ischain_paf_ops); + if (ret) { + merr("fimc_is_video_open is fail(%d)", device, ret); + goto err_video_open; + } + + ret = fimc_is_ischain_paf_open(device, vctx); + if (ret) { + merr("fimc_is_ischain_paf_open is fail(%d)", device, ret); + goto err_ischain_open; + } + + return 0; + +err_ischain_open: + ret_err = fimc_is_video_close(vctx); + if (ret_err) + merr("fimc_is_video_close is fail(%d)", device, ret_err); +err_video_open: + ret_err = close_vctx(file, video, vctx); + if (ret_err < 0) + merr("close_vctx is fail(%d)", device, ret_err); +err_vctx_open: +err_device_null: +err_resource_open: +err_resource_null: + return ret; +} + +static int fimc_is_paf_video_close(struct file *file) +{ + int ret = 0; + int refcount; + struct fimc_is_video_ctx *vctx = file->private_data; + struct fimc_is_video *video; + struct fimc_is_device_ischain *device; + + BUG_ON(!file); + BUG_ON(!vctx); + BUG_ON(!GET_VIDEO(vctx)); + BUG_ON(!GET_DEVICE(vctx)); + + video = GET_VIDEO(vctx); + device = GET_DEVICE(vctx); + + ret = fimc_is_ischain_paf_close(device, vctx); + if (ret) + merr("fimc_is_ischain_paf_close is fail(%d)", device, ret); + + ret = fimc_is_video_close(vctx); + if (ret) + merr("fimc_is_video_close is fail(%d)", device, ret); + + refcount = close_vctx(file, video, vctx); + if (refcount < 0) + merr("close_vctx is fail(%d)", device, refcount); + + minfo("[PAF%dS:V] %s(%d,%d):%d\n", device, GET_PAFXS_ID(video), __func__, atomic_read(&device->open_cnt), refcount, ret); + + return ret; +} + +static unsigned int fimc_is_paf_video_poll(struct file *file, + struct poll_table_struct *wait) +{ + u32 ret = 0; + struct fimc_is_video_ctx *vctx = file->private_data; + + ret = fimc_is_video_poll(file, vctx, wait); + if (ret) + merr("fimc_is_video_poll is fail(%d)", vctx, ret); + + return ret; +} + +static int fimc_is_paf_video_mmap(struct file *file, + struct vm_area_struct *vma) +{ + int ret = 0; + struct fimc_is_video_ctx *vctx = file->private_data; + + ret = fimc_is_video_mmap(file, vctx, vma); + if (ret) + merr("fimc_is_video_mmap is fail(%d)", vctx, ret); + + return ret; +} + +const struct v4l2_file_operations fimc_is_paf_video_fops = { + .owner = THIS_MODULE, + .open = fimc_is_paf_video_open, + .release = fimc_is_paf_video_close, + .poll = fimc_is_paf_video_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = fimc_is_paf_video_mmap, +}; + +/* + * ============================================================================= + * Video Ioctl Opertation + * ============================================================================= + */ + +static int fimc_is_paf_video_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + /* Todo : add to query capability code */ + return 0; +} + +static int fimc_is_paf_video_enum_fmt_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + /* Todo : add to enumerate format code */ + return 0; +} + +static int fimc_is_paf_video_get_format_mplane(struct file *file, void *fh, + struct v4l2_format *format) +{ + /* Todo : add to get format code */ + return 0; +} + +static int fimc_is_paf_video_set_format_mplane(struct file *file, void *fh, + struct v4l2_format *format) +{ + int ret = 0; + struct fimc_is_video_ctx *vctx = file->private_data; + + BUG_ON(!vctx); + BUG_ON(!format); + + mdbgv_paf("%s\n", vctx, __func__); + + ret = fimc_is_video_set_format_mplane(file, vctx, format); + if (ret) { + merr("fimc_is_video_set_format_mplane is fail(%d)", vctx, ret); + goto p_err; + } + +p_err: + return ret; +} + +static int fimc_is_paf_video_cropcap(struct file *file, void *fh, + struct v4l2_cropcap *cropcap) +{ + /* Todo : add to crop capability code */ + return 0; +} + +static int fimc_is_paf_video_get_crop(struct file *file, void *fh, + struct v4l2_crop *crop) +{ + /* Todo : add to get crop control code */ + return 0; +} + +static int fimc_is_paf_video_set_crop(struct file *file, void *fh, + const struct v4l2_crop *crop) +{ + /* Todo : add to set crop control code */ + return 0; +} + +static int fimc_is_paf_video_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *buf) +{ + int ret = 0; + struct fimc_is_video_ctx *vctx = file->private_data; + + BUG_ON(!vctx); + + mdbgv_paf("%s(buffers : %d)\n", vctx, __func__, buf->count); + + ret = fimc_is_video_reqbufs(file, vctx, buf); + if (ret) + merr("fimc_is_video_reqbufs is fail(%d)", vctx, ret); + + return ret; +} + +static int fimc_is_paf_video_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + int ret; + struct fimc_is_video_ctx *vctx = file->private_data; + + mdbgv_paf("%s\n", vctx, __func__); + + ret = fimc_is_video_querybuf(file, vctx, buf); + if (ret) + merr("fimc_is_video_querybuf is fail(%d)", vctx, ret); + + return ret; +} + +static int fimc_is_paf_video_qbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + int ret = 0; + struct fimc_is_video_ctx *vctx = file->private_data; + + BUG_ON(!vctx); + + mvdbgs(3, "%s(%02d:%d)\n", vctx, &vctx->queue, __func__, buf->type, buf->index); + + ret = CALL_VOPS(vctx, qbuf, buf); + if (ret) + merr("qbuf is fail(%d)", vctx, ret); + + return ret; +} + +static int fimc_is_paf_video_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + int ret = 0; + struct fimc_is_video_ctx *vctx = file->private_data; + bool blocking = file->f_flags & O_NONBLOCK; + + BUG_ON(!vctx); + + mvdbgs(3, "%s\n", vctx, &vctx->queue, __func__); + + ret = CALL_VOPS(vctx, dqbuf, buf, blocking); + if (ret) + merr("dqbuf is fail(%d)", vctx, ret); + + return ret; +} + +static int fimc_is_paf_video_prepare(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + int ret = 0; + struct fimc_is_video_ctx *vctx = file->private_data; + struct fimc_is_device_ischain *device; + struct fimc_is_framemgr *framemgr; + struct fimc_is_frame *frame; + + BUG_ON(!buf); + BUG_ON(!vctx); + BUG_ON(!GET_FRAMEMGR(vctx)); + BUG_ON(!GET_DEVICE(vctx)); + BUG_ON(!GET_VIDEO(vctx)); + + device = GET_DEVICE(vctx); + framemgr = GET_FRAMEMGR(vctx); + frame = &framemgr->frames[buf->index]; + + ret = fimc_is_video_prepare(file, vctx, buf); + if (ret) { + merr("fimc_is_video_prepare is fail(%d)", vctx, ret); + goto p_err; + } + + if (!test_bit(FRAME_MEM_MAPPED, &frame->mem_state)) { + fimc_is_itf_map(device, GROUP_ID(device->group_3aa.id), frame->dvaddr_shot, frame->shot_size); + set_bit(FRAME_MEM_MAPPED, &frame->mem_state); + } + +p_err: + minfo("[PAF%dS:V] %s(%d):%d\n", device, GET_PAFXS_ID(GET_VIDEO(vctx)), __func__, buf->index, ret); + return ret; +} + +static int fimc_is_paf_video_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + int ret = 0; + struct fimc_is_video_ctx *vctx = file->private_data; + + mdbgv_paf("%s\n", vctx, __func__); + + ret = fimc_is_video_streamon(file, vctx, type); + if (ret) + merr("fimc_is_video_streamon is fail(%d)", vctx, ret); + + return ret; +} + +static int fimc_is_paf_video_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + int ret = 0; + struct fimc_is_video_ctx *vctx = file->private_data; + + mdbgv_paf("%s\n", vctx, __func__); + + ret = fimc_is_video_streamoff(file, vctx, type); + if (ret) + merr("fimc_is_video_streamoff is fail(%d)", vctx, ret); + + return ret; +} + +static int fimc_is_paf_video_enum_input(struct file *file, void *priv, + struct v4l2_input *input) +{ + /* Todo: add enum input control code */ + return 0; +} + +static int fimc_is_paf_video_g_input(struct file *file, void *priv, + unsigned int *input) +{ + /* Todo: add to get input control code */ + return 0; +} + +static int fimc_is_paf_video_s_input(struct file *file, void *priv, + unsigned int input) +{ + int ret = 0; + u32 stream, position, vindex, intype, leader; + struct fimc_is_video_ctx *vctx = file->private_data; + struct fimc_is_device_ischain *device; + + BUG_ON(!vctx); + BUG_ON(!vctx->device); + + device = GET_DEVICE(vctx); + stream = (input & INPUT_STREAM_MASK) >> INPUT_STREAM_SHIFT; + position = (input & INPUT_POSITION_MASK) >> INPUT_POSITION_SHIFT; + vindex = (input & INPUT_VINDEX_MASK) >> INPUT_VINDEX_SHIFT; + intype = (input & INPUT_INTYPE_MASK) >> INPUT_INTYPE_SHIFT; + leader = (input & INPUT_LEADER_MASK) >> INPUT_LEADER_SHIFT; + + mdbgv_paf("%s(input : %08X)[%d,%d,%d,%d,%d]\n", vctx, __func__, input, + stream, position, vindex, intype, leader); + + ret = fimc_is_video_s_input(file, vctx); + if (ret) { + merr("fimc_is_video_s_input is fail(%d)", vctx, ret); + goto p_err; + } + + ret = fimc_is_ischain_paf_s_input(device, stream, position, vindex, intype, leader); + if (ret) { + merr("fimc_is_ischain_paf_s_input is fail(%d)", vctx, ret); + goto p_err; + } + +p_err: + return ret; +} + +static int fimc_is_paf_video_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + int ret = 0; + struct fimc_is_video_ctx *vctx = file->private_data; + struct fimc_is_device_ischain *device; + + BUG_ON(!vctx); + BUG_ON(!GET_DEVICE(vctx)); + BUG_ON(!ctrl); + + mdbgv_paf("%s\n", vctx, __func__); + + device = GET_DEVICE(vctx); + + switch (ctrl->id) { + case V4L2_CID_IS_FORCE_DONE: + set_bit(FIMC_IS_GROUP_REQUEST_FSTOP, &device->group_paf.state); + break; + default: + ret = fimc_is_video_s_ctrl(file, vctx, ctrl); + if (ret) { + merr("fimc_is_video_s_ctrl is fail(%d)", device, ret); + goto p_err; + } + break; + } + +p_err: + return ret; +} + +static int fimc_is_paf_video_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + /* Todo: add to get control code */ + return 0; +} + +static int fimc_is_paf_video_s_ext_ctrl(struct file *file, void *priv, + struct v4l2_ext_controls *ctrls) +{ + int ret = 0; + int i; + struct fimc_is_video_ctx *vctx = file->private_data; + struct fimc_is_device_ischain *device; + struct fimc_is_framemgr *framemgr; + struct fimc_is_queue *queue; + struct v4l2_ext_control *ext_ctrl; + struct v4l2_control ctrl; + + BUG_ON(!vctx); + BUG_ON(!GET_DEVICE(vctx)); + BUG_ON(!ctrls); + + mdbgv_paf("%s\n", vctx, __func__); + + if (ctrls->which != V4L2_CTRL_CLASS_CAMERA) { + merr("Invalid control class(%d)", vctx, ctrls->which); + ret = -EINVAL; + goto p_err; + } + + device = GET_DEVICE(vctx); + queue = GET_QUEUE(vctx); + framemgr = &queue->framemgr; + + for (i = 0; i < ctrls->count; i++) { + ext_ctrl = (ctrls->controls + i); + + switch (ext_ctrl->id) { + default: + ctrl.id = ext_ctrl->id; + ctrl.value = ext_ctrl->value; + + ret = fimc_is_video_s_ctrl(file, vctx, &ctrl); + if (ret) { + merr("fimc_is_video_s_ctrl is fail(%d)", device, ret); + goto p_err; + } + break; + } + } + +p_err: + return ret; +} + +static int fimc_is_paf_video_g_ext_ctrl(struct file *file, void *priv, + struct v4l2_ext_controls *ctrls) +{ + /* Todo: add to get extra control code */ + return 0; +} + +const struct v4l2_ioctl_ops fimc_is_paf_video_ioctl_ops = { + .vidioc_querycap = fimc_is_paf_video_querycap, + + .vidioc_enum_fmt_vid_out_mplane = fimc_is_paf_video_enum_fmt_mplane, + .vidioc_enum_fmt_vid_cap_mplane = fimc_is_paf_video_enum_fmt_mplane, + + .vidioc_g_fmt_vid_out_mplane = fimc_is_paf_video_get_format_mplane, + .vidioc_g_fmt_vid_cap_mplane = fimc_is_paf_video_get_format_mplane, + + .vidioc_s_fmt_vid_out_mplane = fimc_is_paf_video_set_format_mplane, + .vidioc_s_fmt_vid_cap_mplane = fimc_is_paf_video_set_format_mplane, + + .vidioc_querybuf = fimc_is_paf_video_querybuf, + .vidioc_reqbufs = fimc_is_paf_video_reqbufs, + + .vidioc_qbuf = fimc_is_paf_video_qbuf, + .vidioc_dqbuf = fimc_is_paf_video_dqbuf, + .vidioc_prepare_buf = fimc_is_paf_video_prepare, + + .vidioc_streamon = fimc_is_paf_video_streamon, + .vidioc_streamoff = fimc_is_paf_video_streamoff, + + .vidioc_enum_input = fimc_is_paf_video_enum_input, + .vidioc_g_input = fimc_is_paf_video_g_input, + .vidioc_s_input = fimc_is_paf_video_s_input, + + .vidioc_s_ctrl = fimc_is_paf_video_s_ctrl, + .vidioc_g_ctrl = fimc_is_paf_video_g_ctrl, + .vidioc_s_ext_ctrls = fimc_is_paf_video_s_ext_ctrl, + .vidioc_g_ext_ctrls = fimc_is_paf_video_g_ext_ctrl, + + .vidioc_cropcap = fimc_is_paf_video_cropcap, + .vidioc_g_crop = fimc_is_paf_video_get_crop, + .vidioc_s_crop = fimc_is_paf_video_set_crop, +}; + +static int fimc_is_paf_queue_setup(struct vb2_queue *vbq, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + int ret = 0; + struct fimc_is_video_ctx *vctx = vbq->drv_priv; + struct fimc_is_video *video; + struct fimc_is_queue *queue; + + BUG_ON(!vctx); + BUG_ON(!vctx->video); + + mdbgv_paf("%s\n", vctx, __func__); + + video = GET_VIDEO(vctx); + queue = GET_QUEUE(vctx); + + ret = fimc_is_queue_setup(queue, + video->alloc_ctx, + num_planes, + sizes, + alloc_devs); + if (ret) + merr("fimc_is_queue_setup is fail(%d)", vctx, ret); + + return ret; +} + +static int fimc_is_paf_buffer_prepare(struct vb2_buffer *vb) +{ + return fimc_is_queue_prepare(vb); +} + +static inline void fimc_is_paf_wait_prepare(struct vb2_queue *vbq) +{ + fimc_is_queue_wait_prepare(vbq); +} + +static inline void fimc_is_paf_wait_finish(struct vb2_queue *vbq) +{ + fimc_is_queue_wait_finish(vbq); +} + +static int fimc_is_paf_start_streaming(struct vb2_queue *vbq, + unsigned int count) +{ + int ret = 0; + struct fimc_is_video_ctx *vctx = vbq->drv_priv; + struct fimc_is_queue *queue; + struct fimc_is_device_ischain *device; + + BUG_ON(!vctx); + BUG_ON(!GET_DEVICE(vctx)); + + mdbgv_paf("%s\n", vctx, __func__); + + device = GET_DEVICE(vctx); + queue = GET_QUEUE(vctx); + + ret = fimc_is_queue_start_streaming(queue, device); + if (ret) { + merr("fimc_is_queue_start_streaming is fail(%d)", device, ret); + goto p_err; + } + +p_err: + return ret; +} + +static void fimc_is_paf_stop_streaming(struct vb2_queue *vbq) +{ + int ret = 0; + struct fimc_is_video_ctx *vctx = vbq->drv_priv; + struct fimc_is_queue *queue; + struct fimc_is_device_ischain *device; + + BUG_ON(!vctx); + BUG_ON(!GET_DEVICE(vctx)); + + mdbgv_paf("%s\n", vctx, __func__); + + device = GET_DEVICE(vctx); + queue = GET_QUEUE(vctx); + + ret = fimc_is_queue_stop_streaming(queue, device); + if (ret) { + merr("fimc_is_queue_stop_streaming is fail(%d)", device, ret); + return; + } +} + +static void fimc_is_paf_buffer_queue(struct vb2_buffer *vb) +{ + int ret = 0; + struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv; + struct fimc_is_device_ischain *device; + struct fimc_is_queue *queue; + + BUG_ON(!vctx); + BUG_ON(!GET_DEVICE(vctx)); + + mvdbgs(3, "%s(%d)\n", vctx, &vctx->queue, __func__, vb->index); + + device = GET_DEVICE(vctx); + queue = GET_QUEUE(vctx); + + ret = fimc_is_queue_buffer_queue(queue, vb); + if (ret) { + merr("fimc_is_queue_buffer_queue is fail(%d)", device, ret); + return; + } + + ret = fimc_is_ischain_paf_buffer_queue(device, queue, vb->index); + if (ret) { + merr("fimc_is_ischain_paf_buffer_queue is fail(%d)", device, ret); + return; + } +} + +static void fimc_is_paf_buffer_finish(struct vb2_buffer *vb) +{ + int ret = 0; + struct fimc_is_video_ctx *vctx = vb->vb2_queue->drv_priv; + struct fimc_is_device_ischain *device; + + BUG_ON(!vctx); + BUG_ON(!GET_DEVICE(vctx)); + + mvdbgs(3, "%s(%d)\n", vctx, &vctx->queue, __func__, vb->index); + + device = GET_DEVICE(vctx); + + fimc_is_queue_buffer_finish(vb); + + ret = fimc_is_ischain_paf_buffer_finish(device, vb->index); + if (ret) { + merr("fimc_is_ischain_paf_buffer_finish is fail(%d)", device, ret); + return; + } +} + +const struct vb2_ops fimc_is_paf_qops = { + .queue_setup = fimc_is_paf_queue_setup, + .buf_init = fimc_is_buffer_init, + .buf_prepare = fimc_is_paf_buffer_prepare, + .buf_queue = fimc_is_paf_buffer_queue, + .buf_finish = fimc_is_paf_buffer_finish, + .wait_prepare = fimc_is_paf_wait_prepare, + .wait_finish = fimc_is_paf_wait_finish, + .start_streaming = fimc_is_paf_start_streaming, + .stop_streaming = fimc_is_paf_stop_streaming, +}; diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-video.h b/drivers/media/platform/exynos/fimc-is2/fimc-is-video.h index 1c18b568e4c6..5dcd576f0f0b 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-video.h +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-video.h @@ -102,6 +102,7 @@ #define VIDEO_SSXVC1_READY_BUFFERS 0 #define VIDEO_SSXVC2_READY_BUFFERS 0 #define VIDEO_SSXVC3_READY_BUFFERS 0 +#define VIDEO_PAFXS_READY_BUFFERS 0 #define FIMC_IS_VIDEO_NAME(name) ("exynos-fimc-is-"name) #define FIMC_IS_VIDEO_SSX_NAME FIMC_IS_VIDEO_NAME("ss") @@ -128,6 +129,7 @@ #define FIMC_IS_VIDEO_SSXVC1_NAME(id) FIMC_IS_VIDEO_NAME("ss"#id"vc1") #define FIMC_IS_VIDEO_SSXVC2_NAME(id) FIMC_IS_VIDEO_NAME("ss"#id"vc2") #define FIMC_IS_VIDEO_SSXVC3_NAME(id) FIMC_IS_VIDEO_NAME("ss"#id"vc3") +#define FIMC_IS_VIDEO_PAFXS_NAME(id) FIMC_IS_VIDEO_NAME("p"#id"s") struct fimc_is_device_ischain; struct fimc_is_subdev; @@ -212,6 +214,8 @@ enum fimc_is_video_dev_num { FIMC_IS_VIDEO_SS5VC1_NUM, FIMC_IS_VIDEO_SS5VC2_NUM, FIMC_IS_VIDEO_SS5VC3_NUM, + FIMC_IS_VIDEO_PAF0S_NUM = 140, + FIMC_IS_VIDEO_PAF1S_NUM, FIMC_IS_VIDEO_MAX_NUM }; @@ -462,6 +466,8 @@ extern int fimc_is_ssxvc0_video_probe(void *data); extern int fimc_is_ssxvc1_video_probe(void *data); extern int fimc_is_ssxvc2_video_probe(void *data); extern int fimc_is_ssxvc3_video_probe(void *data); +extern int fimc_is_paf0s_video_probe(void *data); +extern int fimc_is_paf1s_video_probe(void *data); #define GET_VIDEO(vctx) (vctx ? (vctx)->video : NULL) #define GET_QUEUE(vctx) (vctx ? &(vctx)->queue : NULL) diff --git a/drivers/media/platform/exynos/fimc-is2/hardware/Makefile b/drivers/media/platform/exynos/fimc-is2/hardware/Makefile index 491a5271ab98..d3d886cac43c 100644 --- a/drivers/media/platform/exynos/fimc-is2/hardware/Makefile +++ b/drivers/media/platform/exynos/fimc-is2/hardware/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_USE_DIRECT_IS_CONTROL) += fimc-is-hw-control.o \ + fimc-is-hw-paf-rdma.o \ fimc-is-hw-3aa.o \ fimc-is-hw-isp.o \ fimc-is-hw-tpu.o \ diff --git a/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-control.c b/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-control.c index c2854b31fcaf..d9716455b996 100644 --- a/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-control.c +++ b/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-control.c @@ -28,6 +28,7 @@ #include "fimc-is-hw-vra.h" #include "fimc-is-hw-dcp.h" #include "fimc-is-hw-dm.h" +#include "fimc-is-hw-paf-rdma.h" #define INTERNAL_SHOT_EXIST (1) @@ -193,6 +194,9 @@ static void prepare_sfr_dump(struct fimc_is_hardware *hardware) if (hw_ip->id == DEV_HW_END || hw_ip->id == 0) continue; + if (hw_ip->id == DEV_HW_PAF0 || hw_ip->id == DEV_HW_PAF1) + continue; + if (IS_ERR_OR_NULL(hw_ip->regs) || (hw_ip->regs_start == 0) || (hw_ip->regs_end == 0)) { @@ -441,6 +445,12 @@ u32 get_group_id_from_hw_ip(u32 hw_id) case DEV_HW_DCP: group_id = GROUP_ID_DCP; break; + case DEV_HW_PAF0: + group_id = GROUP_ID_PAF0; + break; + case DEV_HW_PAF1: + group_id = GROUP_ID_PAF1; + break; default: group_id = GROUP_ID_MAX; err_hw("invalid hw_id(%d)", hw_id); @@ -485,6 +495,12 @@ u32 get_hw_id_from_group(u32 group_id) case GROUP_ID_VRA0: hw_id = DEV_HW_VRA; break; + case GROUP_ID_PAF0: + hw_id = DEV_HW_PAF0; + break; + case GROUP_ID_PAF1: + hw_id = DEV_HW_PAF1; + break; default: hw_id = DEV_HW_END; err_hw("invalid group(%d)", group_id); @@ -673,6 +689,34 @@ int fimc_is_hardware_probe(struct fimc_is_hardware *hardware, sema_init(&hardware->smp_mcsc_hw_bug, 1); #endif +#if defined(SOC_PAF0) + hw_id = DEV_HW_PAF0; + hw_slot = fimc_is_hw_slot_id(hw_id); + if (!valid_hw_slot_id(hw_slot)) { + err_hw("invalid slot (%d,%d)", hw_id, hw_slot); + return -EINVAL; + } + ret = fimc_is_hw_paf_probe(&(hardware->hw_ip[hw_slot]), itf, itfc, hw_id, "PAF0"); + if (ret) { + err_hw("probe fail (%d,%d)", hw_id, hw_slot); + return ret; + } +#endif + +#if defined(SOC_PAF1) + hw_id = DEV_HW_PAF1; + hw_slot = fimc_is_hw_slot_id(hw_id); + if (!valid_hw_slot_id(hw_slot)) { + err_hw("invalid slot (%d,%d)", hw_id, hw_slot); + return -EINVAL; + } + ret = fimc_is_hw_paf_probe(&(hardware->hw_ip[hw_slot]), itf, itfc, hw_id, "PAF1"); + if (ret) { + err_hw("probe fail (%d,%d)", hw_id, hw_slot); + return ret; + } +#endif + #if defined(SOC_3AAISP) hw_id = DEV_HW_3AA0; hw_slot = fimc_is_hw_slot_id(hw_id); @@ -1364,7 +1408,7 @@ int fimc_is_hardware_config_lock(struct fimc_is_hw_ip *hw_ip, u32 instance, u32 hardware = hw_ip->hardware; - if (!test_bit(FIMC_IS_GROUP_OTF_INPUT, &hw_ip->group[instance]->state)) + if (!test_bit(FIMC_IS_GROUP_OTF_INPUT, &hw_ip->group[instance]->head->state)) return ret; msdbgs_hw(2, "[F:%d]C.L\n", instance, hw_ip, framenum); @@ -2290,6 +2334,8 @@ int fimc_is_hardware_shot_done(struct fimc_is_hw_ip *hw_ip, struct fimc_is_frame goto free_frame; switch (head->id) { + case GROUP_ID_PAF0: + case GROUP_ID_PAF1: case GROUP_ID_3AA0: case GROUP_ID_3AA1: case GROUP_ID_ISP0: diff --git a/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-control.h b/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-control.h index 33a967e45892..d26ad62c7453 100644 --- a/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-control.h +++ b/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-control.h @@ -87,6 +87,8 @@ enum fimc_is_hardware_id { DEV_HW_FD, DEV_HW_VRA, /* = 15 */ DEV_HW_DCP, + DEV_HW_PAF0, /* PAF RDMA */ + DEV_HW_PAF1, DEV_HW_END }; diff --git a/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-paf-rdma.c b/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-paf-rdma.c new file mode 100644 index 000000000000..dbe067134270 --- /dev/null +++ b/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-paf-rdma.c @@ -0,0 +1,442 @@ +/* + * Samsung EXYNOS FIMC-IS (Imaging Subsystem) driver + * + * Copyright (C) 2018 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "fimc-is-hw-paf-rdma.h" +#include "fimc-is-err.h" +#include "fimc-is-param.h" +#if defined(CONFIG_CAMERA_PAFSTAT) +#include "../sensor/module_framework/pafstat/fimc-is-hw-pafstat.h" +#elif defined(CONFIG_CAMERA_PDP) +#include "../sensor/module_framework/pdp/fimc-is-hw-pdp.h" +#endif +static int fimc_is_hw_paf_handle_interrupt(u32 id, void *context) +{ + struct fimc_is_hardware *hardware; + struct fimc_is_hw_ip *hw_ip = NULL; + struct fimc_is_hw_paf *hw_paf = NULL; + void __iomem *paf_ctx_addr; + u32 irq_src, irq_mask, status; + u32 hw_fcount, instance; + + hw_ip = (struct fimc_is_hw_ip *)context; + hardware = hw_ip->hardware; + hw_fcount = atomic_read(&hw_ip->fcount); + instance = atomic_read(&hw_ip->instance); + + if (!test_bit(HW_INIT, &hw_ip->state)) + return IRQ_NONE; + + FIMC_BUG(!hw_ip->priv_info); + hw_paf = (struct fimc_is_hw_paf *)hw_ip->priv_info; + paf_ctx_addr = (hw_ip->id == DEV_HW_PAF1) ? hw_paf->paf_ctx1_regs : hw_paf->paf_ctx0_regs; + + irq_src = pafstat_hw_g_irq_src(paf_ctx_addr); + irq_mask = pafstat_hw_g_irq_mask(paf_ctx_addr); + status = (~irq_mask) & irq_src; + + pafstat_hw_s_irq_src(paf_ctx_addr, status); + + msdbg_hw(2, "PAFSTAT RDMA IRQ : %08X\n", instance, hw_ip, irq_src); + + if (status & (1 << PAFSTAT_INT_FRAME_START)) { + msdbg_hw(2, "PAF: F.S[F:%d]", instance, hw_ip, hw_fcount); + fimc_is_hardware_frame_start(hw_ip, instance); + } + + if (status & (1 << PAFSTAT_INT_TOTAL_FRAME_END)) { + msdbg_hw(2, "PAF: F.E[F:%d]", instance, hw_ip, hw_fcount); + fimc_is_hardware_frame_done(hw_ip, NULL, -1, FIMC_IS_HW_CORE_END, + IS_SHOT_SUCCESS, true); + atomic_set(&hw_ip->status.Vvalid, V_BLANK); + wake_up(&hw_ip->status.wait_queue); + CALL_HW_OPS(hw_ip, clk_gate, instance, false, false); + } + + return 0; +} + +static int fimc_is_hw_paf_open(struct fimc_is_hw_ip *hw_ip, u32 instance, + struct fimc_is_group *group) +{ + int ret = 0; + struct fimc_is_hw_paf *hw_paf = NULL; + + FIMC_BUG(!hw_ip); + + if (test_bit(HW_OPEN, &hw_ip->state)) + return 0; + + frame_manager_probe(hw_ip->framemgr, FRAMEMGR_ID_HW | (1 << hw_ip->id), "HWPAF"); + frame_manager_probe(hw_ip->framemgr_late, FRAMEMGR_ID_HW | (1 << hw_ip->id) | 0xF000, "HWPAF LATE"); + frame_manager_open(hw_ip->framemgr, FIMC_IS_MAX_HW_FRAME); + frame_manager_open(hw_ip->framemgr_late, FIMC_IS_MAX_HW_FRAME_LATE); + + hw_ip->priv_info = vzalloc(sizeof(struct fimc_is_hw_paf)); + if(!hw_ip->priv_info) { + mserr_hw("hw_ip->priv_info(null)", instance, hw_ip); + ret = -ENOMEM; + goto err_alloc; + } + + hw_paf = (struct fimc_is_hw_paf *)hw_ip->priv_info; + + /* set baseaddress for context */ + hw_paf->paf_core_regs = hw_ip->regs_b; + hw_paf->paf_ctx0_regs = hw_paf->paf_core_regs + PAF_CONTEXT0_OFFSET; + hw_paf->paf_ctx1_regs = hw_paf->paf_core_regs + PAF_CONTEXT1_OFFSET; + + hw_paf->paf_rdma_core_regs = hw_ip->regs; + hw_paf->paf_rdma0_regs = hw_paf->paf_rdma_core_regs + PAF_RDMA0_OFFSET; + hw_paf->paf_rdma1_regs = hw_paf->paf_rdma_core_regs + PAF_RDMA1_OFFSET; + + set_bit(HW_OPEN, &hw_ip->state); + msdbg_hw(2, "open: [G:0x%x], framemgr[%s]", instance, hw_ip, + GROUP_ID(group->id), hw_ip->framemgr->name); + + return 0; + +err_alloc: + frame_manager_close(hw_ip->framemgr); + frame_manager_close(hw_ip->framemgr_late); + return ret; +} + +static int fimc_is_hw_paf_init(struct fimc_is_hw_ip *hw_ip, u32 instance, + struct fimc_is_group *group, bool flag, u32 module_id) +{ + int ret = 0; + struct fimc_is_hw_paf *hw_paf = NULL; + + FIMC_BUG(!hw_ip); + FIMC_BUG(!hw_ip->priv_info); + FIMC_BUG(!group); + + hw_paf = (struct fimc_is_hw_paf *)hw_ip->priv_info; + + set_bit(HW_INIT, &hw_ip->state); + return ret; +} + +static int fimc_is_hw_paf_deinit(struct fimc_is_hw_ip *hw_ip, u32 instance) +{ + int ret = 0; + struct fimc_is_hw_paf *hw_paf; + + FIMC_BUG(!hw_ip); + FIMC_BUG(!hw_ip->priv_info); + + hw_paf = (struct fimc_is_hw_paf *)hw_ip->priv_info; + + return ret; +} + +static int fimc_is_hw_paf_close(struct fimc_is_hw_ip *hw_ip, u32 instance) +{ + int ret = 0; + struct fimc_is_hw_paf *hw_paf; + void __iomem *paf_rdma_addr; + + FIMC_BUG(!hw_ip); + + if (!test_bit(HW_OPEN, &hw_ip->state)) + return 0; + + FIMC_BUG(!hw_ip->priv_info); + hw_paf = (struct fimc_is_hw_paf *)hw_ip->priv_info; + + hw_paf = (struct fimc_is_hw_paf *)hw_ip->priv_info; + paf_rdma_addr = (hw_ip->id == DEV_HW_PAF1) ? hw_paf->paf_rdma1_regs : hw_paf->paf_rdma0_regs; + fimc_is_hw_paf_rdma_enable(hw_paf->paf_rdma_core_regs, paf_rdma_addr, 0); + + vfree(hw_ip->priv_info); + frame_manager_close(hw_ip->framemgr); + frame_manager_close(hw_ip->framemgr_late); + + clear_bit(HW_OPEN, &hw_ip->state); + + return ret; +} + +static int fimc_is_hw_paf_enable(struct fimc_is_hw_ip *hw_ip, u32 instance, ulong hw_map) +{ + int ret = 0; + + FIMC_BUG(!hw_ip); + + if (!test_bit_variables(hw_ip->id, &hw_map)) + return 0; + + if (!test_bit(HW_INIT, &hw_ip->state)) { + mserr_hw("not initialized!!", instance, hw_ip); + return -EINVAL; + } + + set_bit(HW_RUN, &hw_ip->state); + + return ret; +} + +static int fimc_is_hw_paf_disable(struct fimc_is_hw_ip *hw_ip, u32 instance, ulong hw_map) +{ + int ret = 0; + long timetowait; + + FIMC_BUG(!hw_ip); + + if (!test_bit_variables(hw_ip->id, &hw_map)) + return 0; + + msinfo_hw("disable: Vvalid(%d)\n", instance, hw_ip, + atomic_read(&hw_ip->status.Vvalid)); + + timetowait = wait_event_timeout(hw_ip->status.wait_queue, + !atomic_read(&hw_ip->status.Vvalid), + FIMC_IS_HW_STOP_TIMEOUT); + + if (!timetowait) { + mserr_hw("wait FRAME_END timeout (%ld)", instance, + hw_ip, timetowait); + ret = -ETIME; + } + + if (atomic_read(&hw_ip->rsccount) > 1) + return 0; + + clear_bit(HW_RUN, &hw_ip->state); + clear_bit(HW_CONFIG, &hw_ip->state); + + return ret; +} + +static int fimc_is_hw_paf_shot(struct fimc_is_hw_ip *hw_ip, struct fimc_is_frame *frame, + ulong hw_map) +{ + int ret = 0; + int i; + struct fimc_is_hw_paf *hw_paf; + struct is_region *region; + struct paf_rdma_param *param; + u32 lindex, hindex; + void __iomem *paf_rdma_addr; + void __iomem *paf_ctx_addr; + + FIMC_BUG(!hw_ip); + FIMC_BUG(!frame); + + msdbgs_hw(2, "[F:%d]shot\n", frame->instance, hw_ip, frame->fcount); + + if (!test_bit_variables(hw_ip->id, &hw_map)) + return 0; + + if (!test_bit(HW_INIT, &hw_ip->state)) { + mserr_hw("not initialized!!", frame->instance, hw_ip); + return -EINVAL; + } + + FIMC_BUG(!hw_ip->priv_info); + hw_paf = (struct fimc_is_hw_paf *)hw_ip->priv_info; + region = hw_ip->region[frame->instance]; + FIMC_BUG(!region); + + FIMC_BUG(!frame->shot); + /* per-frame control + * check & update size from region */ + lindex = frame->shot->ctl.vendor_entry.lowIndexParam; + hindex = frame->shot->ctl.vendor_entry.highIndexParam; + + if (hw_ip->internal_fcount != 0) { + hw_ip->internal_fcount = 0; + lindex |= LOWBIT_OF(PARAM_PAF_DMA_INPUT); + lindex |= LOWBIT_OF(PARAM_PAF_OTF_OUTPUT); + + hindex |= HIGHBIT_OF(PARAM_PAF_DMA_INPUT); + hindex |= HIGHBIT_OF(PARAM_PAF_OTF_OUTPUT); + } + + /* DMA settings */ + param = &hw_ip->region[frame->instance]->parameter.paf; + if (param->dma_input.cmd != DMA_INPUT_COMMAND_DISABLE) { + for (i = 0; i < frame->planes; i++) { + hw_paf->input_dva[i] = frame->dvaddr_buffer[i]; + if (frame->dvaddr_buffer[i] == 0) { + msinfo_hw("[F:%d]dvaddr_buffer[%d] is zero\n", + frame->instance, hw_ip, frame->fcount, i); + FIMC_BUG(1); + } + } + } + + /* multi-buffer */ + if (frame->num_buffers) + hw_ip->num_buffers = frame->num_buffers; + + paf_ctx_addr = (hw_ip->id == DEV_HW_PAF1) ? hw_paf->paf_ctx1_regs : hw_paf->paf_ctx0_regs; + paf_rdma_addr = (hw_ip->id == DEV_HW_PAF1) ? hw_paf->paf_rdma1_regs : hw_paf->paf_rdma0_regs; + + ret = fimc_is_hw_paf_update_param(hw_ip, + region, param, + lindex, hindex, frame->instance); + + fimc_is_hw_paf_rdma_enable(hw_paf->paf_rdma_core_regs, paf_rdma_addr, 1); + fimc_is_hw_paf_oneshot_enable(paf_ctx_addr, 1); + + set_bit(hw_ip->id, &frame->core_flag); + set_bit(HW_CONFIG, &hw_ip->state); + +#if 0 + fimc_is_hw_paf_sfr_dump(hw_paf->paf_core_regs, hw_paf->paf_rdma_core_regs); + fimc_is_hw_paf_sfr_dump(hw_paf->paf_ctx0_regs, hw_paf->paf_rdma0_regs); + fimc_is_hw_paf_sfr_dump(hw_paf->paf_ctx1_regs, hw_paf->paf_rdma1_regs); +#endif + + return ret; +} + +static int fimc_is_hw_paf_set_param(struct fimc_is_hw_ip *hw_ip, struct is_region *region, + u32 lindex, u32 hindex, u32 instance, ulong hw_map) +{ + int ret = 0; + struct fimc_is_hw_paf *hw_paf; + struct paf_rdma_param *param; + + FIMC_BUG(!hw_ip); + + if (!test_bit_variables(hw_ip->id, &hw_map)) + return 0; + + if (!test_bit(HW_INIT, &hw_ip->state)) { + mserr_hw("not initialized!!", instance, hw_ip); + return -EINVAL; + } + + FIMC_BUG(!hw_ip->priv_info); + + hw_paf = (struct fimc_is_hw_paf *)hw_ip->priv_info; + param = &hw_ip->region[instance]->parameter.paf; + + hw_ip->region[instance] = region; + hw_ip->lindex[instance] = lindex; + hw_ip->hindex[instance] = hindex; + + return ret; +} + +int fimc_is_hw_paf_update_param(struct fimc_is_hw_ip *hw_ip, struct is_region *region, + struct paf_rdma_param *param, u32 lindex, u32 hindex, u32 instance) +{ + int ret = 0; + struct fimc_is_hw_paf *hw_paf; + u32 hw_format, bitwidth; + u32 width, height; + u32 paf_ch; + void __iomem *paf_ctx_addr; + void __iomem *paf_rdma_addr; + + FIMC_BUG(!hw_ip); + FIMC_BUG(!region); + FIMC_BUG(!param); + FIMC_BUG(!hw_ip->priv_info); + + hw_paf = (struct fimc_is_hw_paf *)hw_ip->priv_info; + param = &hw_ip->region[instance]->parameter.paf; + + hw_format = param->dma_input.format; + bitwidth = param->dma_input.bitwidth; + width = param->dma_input.width; + height = param->dma_input.height; + + paf_ch = (hw_ip->id == DEV_HW_PAF1) ? 1 : 0; + paf_ctx_addr = (hw_ip->id == DEV_HW_PAF1) ? hw_paf->paf_ctx1_regs : hw_paf->paf_ctx0_regs; + paf_rdma_addr = (hw_ip->id == DEV_HW_PAF1) ? hw_paf->paf_rdma1_regs : hw_paf->paf_rdma0_regs; + + if (width == 0 || height == 0) { + mserr_hw("pafstat size is zero : not configured\n", instance, hw_ip); + return 0; + } + + fimc_is_hw_paf_common_config(hw_paf->paf_core_regs, paf_ctx_addr, paf_ch, width, height); + fimc_is_hw_paf_rdma_set_addr(paf_rdma_addr, hw_paf->input_dva[0]); + fimc_is_hw_paf_rdma_config(paf_rdma_addr, hw_format, bitwidth, width, height); + + return ret; +} + +static int fimc_is_hw_paf_frame_ndone(struct fimc_is_hw_ip *hw_ip, struct fimc_is_frame *frame, + u32 instance, enum ShotErrorType done_type) +{ + int output_id; + int ret = 0; + + FIMC_BUG(!hw_ip); + FIMC_BUG(!frame); + + output_id = FIMC_IS_HW_CORE_END; + if (test_bit_variables(hw_ip->id, &frame->core_flag)) + ret = fimc_is_hardware_frame_done(hw_ip, frame, -1, + output_id, done_type, false); + + return ret; +} + +const struct fimc_is_hw_ip_ops fimc_is_hw_paf_ops = { + .open = fimc_is_hw_paf_open, + .init = fimc_is_hw_paf_init, + .deinit = fimc_is_hw_paf_deinit, + .close = fimc_is_hw_paf_close, + .enable = fimc_is_hw_paf_enable, + .disable = fimc_is_hw_paf_disable, + .shot = fimc_is_hw_paf_shot, + .set_param = fimc_is_hw_paf_set_param, + .frame_ndone = fimc_is_hw_paf_frame_ndone, + .clk_gate = fimc_is_hardware_clk_gate, +}; + +int fimc_is_hw_paf_probe(struct fimc_is_hw_ip *hw_ip, struct fimc_is_interface *itf, + struct fimc_is_interface_ischain *itfc, int id, const char *name) +{ + int ret = 0; + int hw_slot = -1; + + FIMC_BUG(!hw_ip); + FIMC_BUG(!itf); + FIMC_BUG(!itfc); + + /* initialize device hardware */ + hw_ip->id = id; + snprintf(hw_ip->name, sizeof(hw_ip->name), "%s", name); + hw_ip->ops = &fimc_is_hw_paf_ops; + hw_ip->itf = itf; + hw_ip->itfc = itfc; + atomic_set(&hw_ip->fcount, 0); + hw_ip->internal_fcount = 0; + hw_ip->is_leader = true; + atomic_set(&hw_ip->status.Vvalid, V_BLANK); + atomic_set(&hw_ip->status.otf_start, 0); + atomic_set(&hw_ip->rsccount, 0); + init_waitqueue_head(&hw_ip->status.wait_queue); + + hw_slot = fimc_is_hw_slot_id(id); + if (!valid_hw_slot_id(hw_slot)) { + serr_hw("invalid hw_slot (%d)", hw_ip, hw_slot); + return -EINVAL; + } + + itfc->itf_ip[hw_slot].handler[INTR_HWIP1].handler = &fimc_is_hw_paf_handle_interrupt; + + clear_bit(HW_OPEN, &hw_ip->state); + clear_bit(HW_INIT, &hw_ip->state); + clear_bit(HW_CONFIG, &hw_ip->state); + clear_bit(HW_RUN, &hw_ip->state); + clear_bit(HW_TUNESET, &hw_ip->state); + + sinfo_hw("probe done\n", hw_ip); + + return ret; +} diff --git a/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-paf-rdma.h b/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-paf-rdma.h new file mode 100644 index 000000000000..36971c7f9f51 --- /dev/null +++ b/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-paf-rdma.h @@ -0,0 +1,36 @@ +/* + * Samsung EXYNOS FIMC-IS (Imaging Subsystem) driver + * + * Copyright (C) 2018 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef FIMC_IS_HW_PAFRDMA_H +#define FIMC_IS_HW_PAFRDMA_H + +#include "fimc-is-hw-control.h" +#include "fimc-is-param.h" + +struct fimc_is_hw_paf { + struct paf_rdma_param param[FIMC_IS_STREAM_COUNT]; + void __iomem *paf_core_regs; + void __iomem *paf_ctx0_regs; + void __iomem *paf_ctx1_regs; + void __iomem *paf_rdma_core_regs; + void __iomem *paf_rdma0_regs; + void __iomem *paf_rdma1_regs; + u32 input_dva[FIMC_IS_MAX_PLANES]; + u32 instance_id; + u32 fcount; +}; + +int fimc_is_hw_paf_probe(struct fimc_is_hw_ip *hw_ip, struct fimc_is_interface *itf, + struct fimc_is_interface_ischain *itfc, int id, const char *name); +int fimc_is_hw_paf_mode_change(struct fimc_is_hw_ip *hw_ip, u32 instance, ulong hw_map); +int fimc_is_hw_paf_update_param(struct fimc_is_hw_ip *hw_ip, struct is_region *region, + struct paf_rdma_param *param, u32 lindex, u32 hindex, u32 instance); +int fimc_is_hw_paf_reset(struct fimc_is_hw_ip *hw_ip); +#endif diff --git a/drivers/media/platform/exynos/fimc-is2/include/fimc-is-cmd.h b/drivers/media/platform/exynos/fimc-is2/include/fimc-is-cmd.h index 32c4db371a56..9249fb4993b1 100644 --- a/drivers/media/platform/exynos/fimc-is2/include/fimc-is-cmd.h +++ b/drivers/media/platform/exynos/fimc-is2/include/fimc-is-cmd.h @@ -185,7 +185,7 @@ struct is_setfile_header_element { }; #ifdef CONFIG_USE_SENSOR_GROUP -#define MAX_ACTIVE_GROUP 7 +#define MAX_ACTIVE_GROUP 8 #else #define MAX_ACTIVE_GROUP 6 #endif diff --git a/drivers/media/platform/exynos/fimc-is2/include/fimc-is-common-config.h b/drivers/media/platform/exynos/fimc-is2/include/fimc-is-common-config.h index 423d98e4e260..d91bd7ddb87c 100644 --- a/drivers/media/platform/exynos/fimc-is2/include/fimc-is-common-config.h +++ b/drivers/media/platform/exynos/fimc-is2/include/fimc-is-common-config.h @@ -158,6 +158,7 @@ extern int debug_sensor; #endif #define GET_SSX_ID(video) (video->id - FIMC_IS_VIDEO_SS0_NUM) +#define GET_PAFXS_ID(video) ((video->id < FIMC_IS_VIDEO_PAF1S_NUM) ? 0 : 1) #define GET_3XS_ID(video) ((video->id < FIMC_IS_VIDEO_31S_NUM) ? 0 : 1) #define GET_3XC_ID(video) ((video->id < FIMC_IS_VIDEO_31S_NUM) ? 0 : 1) #define GET_3XP_ID(video) ((video->id < FIMC_IS_VIDEO_31S_NUM) ? 0 : 1) @@ -405,6 +406,11 @@ extern int debug_sensor; #define mdbgv_ssxvc3(fmt, this, args...) \ mdbg_common(debug_video, "[%d][SSXVC3:V]", fmt, ((struct fimc_is_device_sensor *)this->device)->instance, ##args) +#define mdbgv_paf(fmt, this, args...) \ + mdbg_common(debug_video, "[%d][PAF%dS:V]", fmt, \ + ((struct fimc_is_device_ischain *)this->device)->instance, \ + GET_PAFXS_ID(this->video), ##args) + /* * ================================================================================================= * LOG - DEBUG_DEVICE diff --git a/drivers/media/platform/exynos/fimc-is2/interface/fimc-is-interface-ddk.c b/drivers/media/platform/exynos/fimc-is2/interface/fimc-is-interface-ddk.c index 46f926c2a921..2a92e8a988f4 100644 --- a/drivers/media/platform/exynos/fimc-is2/interface/fimc-is-interface-ddk.c +++ b/drivers/media/platform/exynos/fimc-is2/interface/fimc-is-interface-ddk.c @@ -546,7 +546,6 @@ int fimc_is_lib_isp_object_create(struct fimc_is_hw_ip *hw_ip, { int ret = 0; u32 chain_id, input_type, obj_info = 0; - struct fimc_is_group *head; FIMC_BUG(!hw_ip); FIMC_BUG(!this); @@ -571,11 +570,8 @@ int fimc_is_lib_isp_object_create(struct fimc_is_hw_ip *hw_ip, break; } - head = GET_HEAD_GROUP_IN_DEVICE(FIMC_IS_DEVICE_ISCHAIN, hw_ip->group[instance_id]); - - FIMC_BUG(!head); - - if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &head->state)) + /* input_type : use only in 3AA (guide by DDK) */ + if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &hw_ip->group[instance_id]->state)) input_type = 0; /* default */ else input_type = 1; diff --git a/drivers/media/platform/exynos/fimc-is2/interface/fimc-is-interface-ischain.c b/drivers/media/platform/exynos/fimc-is2/interface/fimc-is-interface-ischain.c index 13b551929391..ee28546a71f2 100644 --- a/drivers/media/platform/exynos/fimc-is2/interface/fimc-is-interface-ischain.c +++ b/drivers/media/platform/exynos/fimc-is2/interface/fimc-is-interface-ischain.c @@ -59,6 +59,38 @@ int fimc_is_interface_ischain_probe(struct fimc_is_interface_ischain *this, /* this->regs_mcuctl = fimc_is_hw_get_sysreg(core_regs); *//* deprecated */ this->minfo = &resourcemgr->minfo; +#if defined(SOC_PAF0) + hw_id = DEV_HW_PAF0; + hw_slot = fimc_is_hw_slot_id(hw_id); + if (!valid_hw_slot_id(hw_slot)) { + err_itfc("invalid hw_slot (%d) ", hw_slot); + return -EINVAL; + } + + this->itf_ip[hw_slot].hw_ip = &(hardware->hw_ip[hw_slot]); + ret = fimc_is_interface_paf_probe(this, hw_id, pdev); + if (ret) { + err_itfc("interface probe fail (%d,%d)", hw_id, hw_slot); + return -EINVAL; + } +#endif + +#if defined(SOC_PAF1) + hw_id = DEV_HW_PAF1; + hw_slot = fimc_is_hw_slot_id(hw_id); + if (!valid_hw_slot_id(hw_slot)) { + err_itfc("invalid hw_slot (%d) ", hw_slot); + return -EINVAL; + } + + this->itf_ip[hw_slot].hw_ip = &(hardware->hw_ip[hw_slot]); + ret = fimc_is_interface_paf_probe(this, hw_id, pdev); + if (ret) { + err_itfc("interface probe fail (%d,%d)", hw_id, hw_slot); + return -EINVAL; + } +#endif + #if defined(SOC_30S) hw_id = DEV_HW_3AA0; hw_slot = fimc_is_hw_slot_id(hw_id); @@ -754,6 +786,51 @@ int fimc_is_interface_srdz_probe(struct fimc_is_interface_ischain *itfc, return ret; } +int fimc_is_interface_paf_probe(struct fimc_is_interface_ischain *itfc, + int hw_id, struct platform_device *pdev) +{ + struct fimc_is_interface_hwip *itf_paf = NULL; + int ret = 0; + int hw_slot = -1; + + FIMC_BUG(!itfc); + FIMC_BUG(!pdev); + + hw_slot = fimc_is_hw_slot_id(hw_id); + if (!valid_hw_slot_id(hw_slot)) { + err_itfc("invalid hw_slot (%d) ", hw_slot); + return -EINVAL; + } + + itf_paf = &itfc->itf_ip[hw_slot]; + itf_paf->id = hw_id; + itf_paf->state = 0; + + ret = fimc_is_hw_get_address(itf_paf, pdev, hw_id); + if (ret) { + err_itfc("[ID:%2d] hw_get_address failed (%d)", hw_id, ret); + return -EINVAL; + } + + ret = fimc_is_hw_get_irq(itf_paf, pdev, hw_id); + if (ret) { + err_itfc("[ID:%2d] hw_get_irq failed (%d)", hw_id, ret); + return -EINVAL; + } + + ret = fimc_is_hw_request_irq(itf_paf, hw_id); + if (ret) { + err_itfc("[ID:%2d] hw_request_irq failed (%d)", hw_id, ret); + return -EINVAL; + } + + set_bit(IS_CHAIN_IF_STATE_INIT, &itf_paf->state); + + dbg_itfc("[ID:%2d] probe done\n", hw_id); + + return ret; +} + int print_fre_work_list(struct fimc_is_work_list *this) { struct fimc_is_work *work, *temp; @@ -2529,6 +2606,10 @@ static void wq_func_shot(struct work_struct *data) status = msg->param2; switch (group_id) { + case GROUP_ID(GROUP_ID_PAF0): + case GROUP_ID(GROUP_ID_PAF1): + group = &device->group_paf; + break; case GROUP_ID(GROUP_ID_3AA0): case GROUP_ID(GROUP_ID_3AA1): group = &device->group_3aa; diff --git a/drivers/media/platform/exynos/fimc-is2/interface/fimc-is-interface-ischain.h b/drivers/media/platform/exynos/fimc-is2/interface/fimc-is-interface-ischain.h index 0433a2a28283..f47c871bfde8 100644 --- a/drivers/media/platform/exynos/fimc-is2/interface/fimc-is-interface-ischain.h +++ b/drivers/media/platform/exynos/fimc-is2/interface/fimc-is-interface-ischain.h @@ -64,6 +64,8 @@ struct fimc_is_interface_ischain { int fimc_is_interface_ischain_probe(struct fimc_is_interface_ischain *this, struct fimc_is_hardware *hardware, struct fimc_is_resourcemgr *resourcemgr, struct platform_device *pdev, ulong core_regs); +int fimc_is_interface_paf_probe(struct fimc_is_interface_ischain *itfc, + int hw_id, struct platform_device *pdev); int fimc_is_interface_3aa_probe(struct fimc_is_interface_ischain *itfc, int hw_id, struct platform_device *pdev); int fimc_is_interface_isp_probe(struct fimc_is_interface_ischain *itfc, -- 2.20.1