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 \
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/
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;
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);
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;
#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"
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;
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,
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,
{
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);
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);
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)
{
.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)
#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)
{
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;
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);
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;
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 | \
}
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)) {
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 */
#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
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;
}
#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);
ENTRY_M4P,
ENTRY_M5P,
ENTRY_VRA,
+ ENTRY_PAF, /* PDP(PATSTAT) RDMA */
ENTRY_END
};
--- /dev/null
+/*
+ * 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 <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/bug.h>
+
+#include <media/videobuf2-v4l2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-mediabus.h>
+
+#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,
+};
#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")
#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;
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
};
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)
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 \
#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)
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)) {
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);
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);
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);
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);
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:
DEV_HW_FD,
DEV_HW_VRA, /* = 15 */
DEV_HW_DCP,
+ DEV_HW_PAF0, /* PAF RDMA */
+ DEV_HW_PAF1,
DEV_HW_END
};
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
};
#ifdef CONFIG_USE_SENSOR_GROUP
-#define MAX_ACTIVE_GROUP 7
+#define MAX_ACTIVE_GROUP 8
#else
#define MAX_ACTIVE_GROUP 6
#endif
#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)
#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
{
int ret = 0;
u32 chain_id, input_type, obj_info = 0;
- struct fimc_is_group *head;
FIMC_BUG(!hw_ip);
FIMC_BUG(!this);
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;
/* 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);
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;
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;
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,