/* * 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 "fimc-is-core.h" #include "fimc-is-param.h" #include "fimc-is-device-ischain.h" #include "fimc-is-debug.h" struct fimc_is_subdev * video2subdev(enum fimc_is_subdev_device_type device_type, void *device, u32 vid) { struct fimc_is_subdev *subdev = NULL; struct fimc_is_device_sensor *sensor = NULL; struct fimc_is_device_ischain *ischain = NULL; if (device_type == FIMC_IS_SENSOR_SUBDEV) { sensor = (struct fimc_is_device_sensor *)device; } else { ischain = (struct fimc_is_device_ischain *)device; sensor = ischain->sensor; } switch (vid) { case FIMC_IS_VIDEO_SS0VC0_NUM: case FIMC_IS_VIDEO_SS1VC0_NUM: case FIMC_IS_VIDEO_SS2VC0_NUM: case FIMC_IS_VIDEO_SS3VC0_NUM: case FIMC_IS_VIDEO_SS4VC0_NUM: case FIMC_IS_VIDEO_SS5VC0_NUM: subdev = &sensor->ssvc0; break; case FIMC_IS_VIDEO_SS0VC1_NUM: case FIMC_IS_VIDEO_SS1VC1_NUM: case FIMC_IS_VIDEO_SS2VC1_NUM: case FIMC_IS_VIDEO_SS3VC1_NUM: case FIMC_IS_VIDEO_SS4VC1_NUM: case FIMC_IS_VIDEO_SS5VC1_NUM: subdev = &sensor->ssvc1; break; case FIMC_IS_VIDEO_SS0VC2_NUM: case FIMC_IS_VIDEO_SS1VC2_NUM: case FIMC_IS_VIDEO_SS2VC2_NUM: case FIMC_IS_VIDEO_SS3VC2_NUM: case FIMC_IS_VIDEO_SS4VC2_NUM: case FIMC_IS_VIDEO_SS5VC2_NUM: subdev = &sensor->ssvc2; break; case FIMC_IS_VIDEO_SS0VC3_NUM: case FIMC_IS_VIDEO_SS1VC3_NUM: case FIMC_IS_VIDEO_SS2VC3_NUM: case FIMC_IS_VIDEO_SS3VC3_NUM: case FIMC_IS_VIDEO_SS4VC3_NUM: case FIMC_IS_VIDEO_SS5VC3_NUM: subdev = &sensor->ssvc3; break; case FIMC_IS_VIDEO_30S_NUM: case FIMC_IS_VIDEO_31S_NUM: subdev = &ischain->group_3aa.leader; break; case FIMC_IS_VIDEO_30C_NUM: case FIMC_IS_VIDEO_31C_NUM: subdev = &ischain->txc; break; case FIMC_IS_VIDEO_30P_NUM: case FIMC_IS_VIDEO_31P_NUM: subdev = &ischain->txp; break; case FIMC_IS_VIDEO_30F_NUM: case FIMC_IS_VIDEO_31F_NUM: subdev = &ischain->txf; break; case FIMC_IS_VIDEO_30G_NUM: case FIMC_IS_VIDEO_31G_NUM: subdev = &ischain->txg; break; case FIMC_IS_VIDEO_I0S_NUM: case FIMC_IS_VIDEO_I1S_NUM: subdev = &ischain->group_isp.leader; break; case FIMC_IS_VIDEO_I0C_NUM: case FIMC_IS_VIDEO_I1C_NUM: subdev = &ischain->ixc; break; case FIMC_IS_VIDEO_I0P_NUM: case FIMC_IS_VIDEO_I1P_NUM: subdev = &ischain->ixp; break; case FIMC_IS_VIDEO_ME0C_NUM: case FIMC_IS_VIDEO_ME1C_NUM: subdev = &ischain->mexc; break; case FIMC_IS_VIDEO_D0S_NUM: case FIMC_IS_VIDEO_D1S_NUM: subdev = &ischain->group_dis.leader; break; case FIMC_IS_VIDEO_D0C_NUM: case FIMC_IS_VIDEO_D1C_NUM: subdev = &ischain->dxc; break; case FIMC_IS_VIDEO_DCP0S_NUM: subdev = &ischain->group_dcp.leader; break; case FIMC_IS_VIDEO_DCP1S_NUM: subdev = &ischain->dc1s; break; case FIMC_IS_VIDEO_DCP0C_NUM: subdev = &ischain->dc0c; break; case FIMC_IS_VIDEO_DCP1C_NUM: subdev = &ischain->dc1c; break; case FIMC_IS_VIDEO_DCP2C_NUM: subdev = &ischain->dc2c; break; case FIMC_IS_VIDEO_DCP3C_NUM: subdev = &ischain->dc3c; break; case FIMC_IS_VIDEO_DCP4C_NUM: subdev = &ischain->dc4c; break; case FIMC_IS_VIDEO_M0S_NUM: case FIMC_IS_VIDEO_M1S_NUM: subdev = &ischain->group_mcs.leader; break; case FIMC_IS_VIDEO_M0P_NUM: subdev = &ischain->m0p; break; case FIMC_IS_VIDEO_M1P_NUM: subdev = &ischain->m1p; break; case FIMC_IS_VIDEO_M2P_NUM: subdev = &ischain->m2p; break; case FIMC_IS_VIDEO_M3P_NUM: subdev = &ischain->m3p; break; case FIMC_IS_VIDEO_M4P_NUM: subdev = &ischain->m4p; break; case FIMC_IS_VIDEO_M5P_NUM: subdev = &ischain->m5p; break; case FIMC_IS_VIDEO_VRA_NUM: subdev = &ischain->group_vra.leader; break; default: err("[%d] vid %d is NOT found", ((device_type == FIMC_IS_SENSOR_SUBDEV) ? (ischain ? ischain->instance : 0) : (sensor ? sensor->instance : 0)), vid); break; } return subdev; } int fimc_is_subdev_probe(struct fimc_is_subdev *subdev, u32 instance, u32 id, char *name, const struct fimc_is_subdev_ops *sops) { FIMC_BUG(!subdev); FIMC_BUG(!name); subdev->id = id; subdev->instance = instance; subdev->ops = sops; memset(subdev->name, 0x0, sizeof(subdev->name)); strncpy(subdev->name, name, sizeof(char[3])); clear_bit(FIMC_IS_SUBDEV_OPEN, &subdev->state); clear_bit(FIMC_IS_SUBDEV_RUN, &subdev->state); clear_bit(FIMC_IS_SUBDEV_START, &subdev->state); /* for internal use */ clear_bit(FIMC_IS_SUBDEV_INTERNAL_S_FMT, &subdev->state); return 0; } int fimc_is_subdev_open(struct fimc_is_subdev *subdev, struct fimc_is_video_ctx *vctx, void *ctl_data) { int ret = 0; struct fimc_is_video *video = GET_VIDEO(vctx); const struct param_control *init_ctl = (const struct param_control *)ctl_data; FIMC_BUG(!subdev); if (test_bit(FIMC_IS_SUBDEV_OPEN, &subdev->state)) { mserr("already open", subdev, subdev); ret = -EPERM; goto p_err; } subdev->vctx = vctx; subdev->vid = (video) ? video->id : 0; subdev->cid = CAPTURE_NODE_MAX; subdev->input.width = 0; subdev->input.height = 0; subdev->input.crop.x = 0; subdev->input.crop.y = 0; subdev->input.crop.w = 0; subdev->input.crop.h = 0; subdev->output.width = 0; subdev->output.height = 0; subdev->output.crop.x = 0; subdev->output.crop.y = 0; subdev->output.crop.w = 0; subdev->output.crop.h = 0; if (init_ctl) { set_bit(FIMC_IS_SUBDEV_START, &subdev->state); if (subdev->id == ENTRY_VRA) { /* vra only control by command for enabling or disabling */ if (init_ctl->cmd == CONTROL_COMMAND_STOP) clear_bit(FIMC_IS_SUBDEV_RUN, &subdev->state); else set_bit(FIMC_IS_SUBDEV_RUN, &subdev->state); } else { if (init_ctl->bypass == CONTROL_BYPASS_ENABLE) clear_bit(FIMC_IS_SUBDEV_RUN, &subdev->state); else set_bit(FIMC_IS_SUBDEV_RUN, &subdev->state); } } else { clear_bit(FIMC_IS_SUBDEV_START, &subdev->state); clear_bit(FIMC_IS_SUBDEV_RUN, &subdev->state); } set_bit(FIMC_IS_SUBDEV_OPEN, &subdev->state); p_err: return ret; } /* * DMA abstraction: * A overlapped use case of DMA should be detected. */ static int fimc_is_sensor_check_subdev_open(struct fimc_is_device_sensor *device, struct fimc_is_subdev *subdev, struct fimc_is_video_ctx *vctx) { int ret = 0; int i; struct fimc_is_core *core; struct fimc_is_device_sensor *all_sensor; struct fimc_is_device_sensor *each_sensor; FIMC_BUG(!device); FIMC_BUG(!subdev); core = device->private_data; all_sensor = fimc_is_get_sensor_device(core); for (i = 0; i < FIMC_IS_SENSOR_COUNT; i++) { each_sensor = &all_sensor[i]; if (each_sensor == device) continue; if (each_sensor->dma_abstract == false) continue; if (test_bit(FIMC_IS_SENSOR_OPEN, &each_sensor->state)) { if (test_bit(FIMC_IS_SUBDEV_OPEN, &each_sensor->ssvc0.state)) { if (each_sensor->ssvc0.dma_ch[0] == subdev->dma_ch[0]) { merr("vc0 dma(%d) is overlapped with another sensor(I:%d).\n", device, subdev->dma_ch[0], i); goto err_check_vc_open; } } if (test_bit(FIMC_IS_SUBDEV_OPEN, &each_sensor->ssvc1.state)) { if (each_sensor->ssvc1.dma_ch[0] == subdev->dma_ch[0]) { merr("vc1 dma(%d) is overlapped with another sensor(I:%d).\n", device, subdev->dma_ch[0], i); goto err_check_vc_open; } } if (test_bit(FIMC_IS_SUBDEV_OPEN, &each_sensor->ssvc2.state)) { if (each_sensor->ssvc2.dma_ch[0] == subdev->dma_ch[0]) { merr("vc2 dma(%d) is overlapped with another sensor(I:%d).\n", device, subdev->dma_ch[0], i); goto err_check_vc_open; } } if (test_bit(FIMC_IS_SUBDEV_OPEN, &each_sensor->ssvc3.state)) { if (each_sensor->ssvc3.dma_ch[0] == subdev->dma_ch[0]) { merr("vc3 dma(%d) is overlapped with another sensor(I:%d).\n", device, subdev->dma_ch[0], i); goto err_check_vc_open; } } } } ret = fimc_is_subdev_open(subdev, vctx, NULL); if (ret) { merr("fimc_is_subdev_open is fail(%d)", device, ret); goto err_subdev_open; } fimc_is_put_sensor_device(core); return 0; err_subdev_open: err_check_vc_open: fimc_is_put_sensor_device(core); return ret; } int fimc_is_sensor_subdev_open(struct fimc_is_device_sensor *device, struct fimc_is_video_ctx *vctx) { int ret = 0; struct fimc_is_subdev *subdev; FIMC_BUG(!device); FIMC_BUG(!vctx); FIMC_BUG(!GET_VIDEO(vctx)); subdev = video2subdev(FIMC_IS_SENSOR_SUBDEV, (void *)device, GET_VIDEO(vctx)->id); if (!subdev) { merr("video2subdev is fail", device); ret = -EINVAL; goto err_video2subdev; } ret = fimc_is_sensor_check_subdev_open(device, subdev, vctx); if (ret) { merr("fimc_is_sensor_check_subdev_open is fail", device); ret = -EINVAL; goto err_check_subdev_open; } vctx->subdev = subdev; return 0; err_check_subdev_open: err_video2subdev: return ret; } int fimc_is_ischain_subdev_open(struct fimc_is_device_ischain *device, struct fimc_is_video_ctx *vctx) { int ret = 0; int ret_err = 0; struct fimc_is_subdev *subdev; FIMC_BUG(!device); FIMC_BUG(!vctx); FIMC_BUG(!GET_VIDEO(vctx)); subdev = video2subdev(FIMC_IS_ISCHAIN_SUBDEV, (void *)device, GET_VIDEO(vctx)->id); if (!subdev) { merr("video2subdev is fail", device); ret = -EINVAL; goto err_video2subdev; } vctx->subdev = subdev; ret = fimc_is_subdev_open(subdev, vctx, NULL); if (ret) { merr("fimc_is_subdev_open is fail(%d)", device, ret); goto err_subdev_open; } ret = fimc_is_ischain_open_wrap(device, false); if (ret) { merr("fimc_is_ischain_open_wrap is fail(%d)", device, ret); fimc_is_subdev_close(subdev); goto err_ischain_open; } return 0; err_ischain_open: ret_err = fimc_is_subdev_close(subdev); if (ret_err) merr("fimc_is_subdev_close is fail(%d)", device, ret_err); err_subdev_open: err_video2subdev: return ret; } int fimc_is_subdev_close(struct fimc_is_subdev *subdev) { int ret = 0; if (!test_bit(FIMC_IS_SUBDEV_OPEN, &subdev->state)) { mserr("subdev is already close", subdev, subdev); ret = -EINVAL; goto p_err; } subdev->leader = NULL; subdev->vctx = NULL; subdev->vid = 0; clear_bit(FIMC_IS_SUBDEV_OPEN, &subdev->state); clear_bit(FIMC_IS_SUBDEV_RUN, &subdev->state); clear_bit(FIMC_IS_SUBDEV_START, &subdev->state); clear_bit(FIMC_IS_SUBDEV_FORCE_SET, &subdev->state); /* for internal use */ clear_bit(FIMC_IS_SUBDEV_INTERNAL_S_FMT, &subdev->state); p_err: return 0; } int fimc_is_sensor_subdev_close(struct fimc_is_device_sensor *device, struct fimc_is_video_ctx *vctx) { int ret = 0; struct fimc_is_subdev *subdev; FIMC_BUG(!device); FIMC_BUG(!vctx); subdev = vctx->subdev; if (!subdev) { merr("subdev is NULL", device); ret = -EINVAL; goto p_err; } vctx->subdev = NULL; if (test_bit(FIMC_IS_SENSOR_DRIVING, &device->state)) { if (test_bit(FIMC_IS_SENSOR_FRONT_START, &device->state)) { merr("sudden close, call sensor_front_stop()\n", device); ret = fimc_is_sensor_front_stop(device); if (ret) merr("fimc_is_sensor_front_stop is fail(%d)", device, ret); } } ret = fimc_is_subdev_close(subdev); if (ret) merr("fimc_is_subdev_close is fail(%d)", device, ret); p_err: return ret; } int fimc_is_ischain_subdev_close(struct fimc_is_device_ischain *device, struct fimc_is_video_ctx *vctx) { int ret = 0; struct fimc_is_subdev *subdev; FIMC_BUG(!device); FIMC_BUG(!vctx); subdev = vctx->subdev; if (!subdev) { merr("subdev is NULL", device); ret = -EINVAL; goto p_err; } vctx->subdev = NULL; ret = fimc_is_subdev_close(subdev); if (ret) { merr("fimc_is_subdev_close is fail(%d)", device, ret); goto p_err; } ret = fimc_is_ischain_close_wrap(device); if (ret) { merr("fimc_is_ischain_close_wrap is fail(%d)", device, ret); goto p_err; } p_err: return ret; } static int fimc_is_subdev_start(struct fimc_is_subdev *subdev) { int ret = 0; struct fimc_is_subdev *leader; FIMC_BUG(!subdev); FIMC_BUG(!subdev->leader); leader = subdev->leader; if (test_bit(FIMC_IS_SUBDEV_START, &subdev->state)) { mserr("already start", subdev, subdev); goto p_err; } if (test_bit(FIMC_IS_SUBDEV_START, &leader->state)) { mserr("leader%d is ALREADY started", subdev, subdev, leader->id); goto p_err; } set_bit(FIMC_IS_SUBDEV_START, &subdev->state); p_err: return ret; } static int fimc_is_sensor_subdev_start(void *qdevice, struct fimc_is_queue *queue) { int ret = 0; struct fimc_is_device_sensor *device = qdevice; struct fimc_is_video_ctx *vctx; struct fimc_is_subdev *subdev; FIMC_BUG(!device); FIMC_BUG(!queue); vctx = container_of(queue, struct fimc_is_video_ctx, queue); subdev = vctx->subdev; if (!subdev) { merr("subdev is NULL", device); ret = -EINVAL; goto p_err; } if (!test_bit(FIMC_IS_SENSOR_S_INPUT, &device->state)) { mserr("device is not yet init", device, subdev); ret = -EINVAL; goto p_err; } if (test_bit(FIMC_IS_SUBDEV_START, &subdev->state)) { mserr("already start", subdev, subdev); goto p_err; } set_bit(FIMC_IS_SUBDEV_START, &subdev->state); p_err: return ret; } static int fimc_is_ischain_subdev_start(void *qdevice, struct fimc_is_queue *queue) { int ret = 0; struct fimc_is_device_ischain *device = qdevice; struct fimc_is_video_ctx *vctx; struct fimc_is_subdev *subdev; FIMC_BUG(!device); FIMC_BUG(!queue); vctx = container_of(queue, struct fimc_is_video_ctx, queue); subdev = vctx->subdev; if (!subdev) { merr("subdev is NULL", device); ret = -EINVAL; goto p_err; } if (!test_bit(FIMC_IS_ISCHAIN_INIT, &device->state)) { mserr("device is not yet init", device, subdev); ret = -EINVAL; goto p_err; } ret = fimc_is_subdev_start(subdev); if (ret) { mserr("fimc_is_subdev_start is fail(%d)", device, subdev, ret); goto p_err; } p_err: return ret; } static int fimc_is_subdev_stop(struct fimc_is_subdev *subdev) { int ret = 0; unsigned long flags; struct fimc_is_subdev *leader; struct fimc_is_framemgr *framemgr; struct fimc_is_frame *frame; FIMC_BUG(!subdev); FIMC_BUG(!subdev->leader); leader = subdev->leader; framemgr = GET_SUBDEV_FRAMEMGR(subdev); FIMC_BUG(!framemgr); if (!test_bit(FIMC_IS_SUBDEV_START, &subdev->state)) { merr("already stop", subdev); goto p_err; } if (test_bit(FIMC_IS_SUBDEV_START, &leader->state)) { merr("leader%d is NOT stopped", subdev, leader->id); goto p_err; } framemgr_e_barrier_irqs(framemgr, FMGR_IDX_16, flags); if (framemgr->queued_count[FS_PROCESS] > 0) { framemgr_x_barrier_irqr(framemgr, FMGR_IDX_16, flags); merr("being processed, can't stop", subdev); ret = -EINVAL; goto p_err; } frame = peek_frame(framemgr, FS_REQUEST); while (frame) { CALL_VOPS(subdev->vctx, done, frame->index, VB2_BUF_STATE_ERROR); trans_frame(framemgr, frame, FS_COMPLETE); frame = peek_frame(framemgr, FS_REQUEST); } framemgr_x_barrier_irqr(framemgr, FMGR_IDX_16, flags); clear_bit(FIMC_IS_SUBDEV_RUN, &subdev->state); clear_bit(FIMC_IS_SUBDEV_START, &subdev->state); p_err: return ret; } static int fimc_is_sensor_subdev_stop(void *qdevice, struct fimc_is_queue *queue) { int ret = 0; unsigned long flags; struct fimc_is_device_sensor *device = qdevice; struct fimc_is_video_ctx *vctx; struct fimc_is_subdev *subdev; struct fimc_is_framemgr *framemgr; struct fimc_is_frame *frame; FIMC_BUG(!device); FIMC_BUG(!queue); vctx = container_of(queue, struct fimc_is_video_ctx, queue); subdev = vctx->subdev; if (!subdev) { merr("subdev is NULL", device); ret = -EINVAL; goto p_err; } if (!test_bit(FIMC_IS_SUBDEV_START, &subdev->state)) { merr("already stop", subdev); goto p_err; } framemgr = GET_SUBDEV_FRAMEMGR(subdev); if (!framemgr) { merr("framemgr is NULL", device); ret = -EINVAL; goto p_err; } framemgr_e_barrier_irqs(framemgr, FMGR_IDX_16, flags); frame = peek_frame(framemgr, FS_PROCESS); while (frame) { CALL_VOPS(subdev->vctx, done, frame->index, VB2_BUF_STATE_ERROR); trans_frame(framemgr, frame, FS_COMPLETE); frame = peek_frame(framemgr, FS_PROCESS); } frame = peek_frame(framemgr, FS_REQUEST); while (frame) { CALL_VOPS(subdev->vctx, done, frame->index, VB2_BUF_STATE_ERROR); trans_frame(framemgr, frame, FS_COMPLETE); frame = peek_frame(framemgr, FS_REQUEST); } framemgr_x_barrier_irqr(framemgr, FMGR_IDX_16, flags); clear_bit(FIMC_IS_SUBDEV_RUN, &subdev->state); clear_bit(FIMC_IS_SUBDEV_START, &subdev->state); p_err: return ret; } static int fimc_is_ischain_subdev_stop(void *qdevice, struct fimc_is_queue *queue) { int ret = 0; struct fimc_is_device_ischain *device = qdevice; struct fimc_is_video_ctx *vctx; struct fimc_is_subdev *subdev; FIMC_BUG(!device); FIMC_BUG(!queue); vctx = container_of(queue, struct fimc_is_video_ctx, queue); subdev = vctx->subdev; if (!subdev) { merr("subdev is NULL", device); ret = -EINVAL; goto p_err; } ret = fimc_is_subdev_stop(subdev); if (ret) { merr("fimc_is_subdev_stop is fail(%d)", device, ret); goto p_err; } p_err: return ret; } static int fimc_is_subdev_s_format(struct fimc_is_subdev *subdev, struct fimc_is_queue *queue) { int ret = 0; u32 pixelformat = 0, width, height; FIMC_BUG(!subdev); FIMC_BUG(!queue); FIMC_BUG(!queue->framecfg.format); pixelformat = queue->framecfg.format->pixelformat; width = queue->framecfg.width; height = queue->framecfg.height; switch (subdev->id) { case ENTRY_M0P: case ENTRY_M1P: case ENTRY_M2P: case ENTRY_M3P: case ENTRY_M4P: if (width % 8) { merr("width(%d) of format(%d) is not multiple of 8: need to check size", subdev, width, pixelformat); } break; default: break; } subdev->output.width = width; subdev->output.height = height; subdev->output.crop.x = 0; subdev->output.crop.y = 0; subdev->output.crop.w = subdev->output.width; subdev->output.crop.h = subdev->output.height; return ret; } static int fimc_is_sensor_subdev_s_format(void *qdevice, struct fimc_is_queue *queue) { int ret = 0; struct fimc_is_device_sensor *device = qdevice; struct fimc_is_video_ctx *vctx; struct fimc_is_subdev *subdev; FIMC_BUG(!device); FIMC_BUG(!queue); vctx = container_of(queue, struct fimc_is_video_ctx, queue); subdev = vctx->subdev; if (!subdev) { merr("subdev is NULL", device); ret = -EINVAL; goto p_err; } ret = fimc_is_subdev_s_format(subdev, queue); if (ret) { merr("fimc_is_subdev_s_format is fail(%d)", device, ret); goto p_err; } p_err: return ret; } static int fimc_is_ischain_subdev_s_format(void *qdevice, struct fimc_is_queue *queue) { int ret = 0; struct fimc_is_device_ischain *device = qdevice; struct fimc_is_video_ctx *vctx; struct fimc_is_subdev *subdev; FIMC_BUG(!device); FIMC_BUG(!queue); vctx = container_of(queue, struct fimc_is_video_ctx, queue); subdev = vctx->subdev; if (!subdev) { merr("subdev is NULL", device); ret = -EINVAL; goto p_err; } ret = fimc_is_subdev_s_format(subdev, queue); if (ret) { merr("fimc_is_subdev_s_format is fail(%d)", device, ret); goto p_err; } p_err: return ret; } int fimc_is_sensor_subdev_reqbuf(void *qdevice, struct fimc_is_queue *queue, u32 count) { int i = 0; int ret = 0; struct fimc_is_device_sensor *device = qdevice; struct fimc_is_video_ctx *vctx; struct fimc_is_subdev *subdev; struct fimc_is_framemgr *framemgr; struct fimc_is_frame *frame; FIMC_BUG(!device); FIMC_BUG(!queue); if (!count) goto p_err; vctx = container_of(queue, struct fimc_is_video_ctx, queue); subdev = vctx->subdev; if (!subdev) { merr("subdev is NULL", device); ret = -EINVAL; goto p_err; } framemgr = GET_SUBDEV_FRAMEMGR(subdev); if (!framemgr) { merr("framemgr is NULL", device); ret = -EINVAL; goto p_err; } for (i = 0; i < count; i++) { frame = &framemgr->frames[i]; frame->subdev = subdev; } p_err: return ret; } int fimc_is_subdev_buffer_queue(struct fimc_is_subdev *subdev, struct vb2_buffer *vb) { int ret = 0; unsigned long flags; struct fimc_is_framemgr *framemgr = GET_SUBDEV_FRAMEMGR(subdev); struct fimc_is_frame *frame; unsigned int index = vb->index; FIMC_BUG(!subdev); FIMC_BUG(!framemgr); FIMC_BUG(index >= framemgr->num_frames); frame = &framemgr->frames[index]; /* 1. check frame validation */ if (unlikely(!test_bit(FRAME_MEM_INIT, &frame->mem_state))) { mserr("frame %d is NOT init", subdev, subdev, index); ret = EINVAL; goto p_err; } /* 2. update frame manager */ framemgr_e_barrier_irqs(framemgr, FMGR_IDX_17, flags); if (frame->state == FS_FREE) { trans_frame(framemgr, frame, FS_REQUEST); } else { mserr("frame %d is invalid state(%d)\n", subdev, subdev, index, frame->state); frame_manager_print_queues(framemgr); ret = -EINVAL; } framemgr_x_barrier_irqr(framemgr, FMGR_IDX_17, flags); p_err: return ret; } int fimc_is_subdev_buffer_finish(struct fimc_is_subdev *subdev, struct vb2_buffer *vb) { int ret = 0; struct fimc_is_framemgr *framemgr; struct fimc_is_frame *frame; unsigned int index = vb->index; if (!subdev) { warn("subdev is NULL(%d)", index); ret = -EINVAL; return ret; } if (unlikely(!test_bit(FIMC_IS_SUBDEV_OPEN, &subdev->state))) { warn("subdev was closed..(%d)", index); ret = -EINVAL; return ret; } framemgr = GET_SUBDEV_FRAMEMGR(subdev); if (unlikely(!framemgr)) { warn("subdev's framemgr is null..(%d)", index); ret = -EINVAL; return ret; } FIMC_BUG(index >= framemgr->num_frames); frame = &framemgr->frames[index]; framemgr_e_barrier_irq(framemgr, FMGR_IDX_18); if (frame->state == FS_COMPLETE) { trans_frame(framemgr, frame, FS_FREE); } else { merr("frame is empty from complete", subdev); merr("frame(%d) is not com state(%d)", subdev, index, frame->state); frame_manager_print_queues(framemgr); ret = -EINVAL; } framemgr_x_barrier_irq(framemgr, FMGR_IDX_18); return ret; } const struct fimc_is_queue_ops fimc_is_sensor_subdev_ops = { .start_streaming = fimc_is_sensor_subdev_start, .stop_streaming = fimc_is_sensor_subdev_stop, .s_format = fimc_is_sensor_subdev_s_format, .request_bufs = fimc_is_sensor_subdev_reqbuf, }; const struct fimc_is_queue_ops fimc_is_ischain_subdev_ops = { .start_streaming = fimc_is_ischain_subdev_start, .stop_streaming = fimc_is_ischain_subdev_stop, .s_format = fimc_is_ischain_subdev_s_format }; void fimc_is_subdev_dis_start(struct fimc_is_device_ischain *device, struct fimc_is_frame *frame, u32 *lindex, u32 *hindex, u32 *indexes) { /* this function is for dis start */ } void fimc_is_subdev_dis_stop(struct fimc_is_device_ischain *device, struct fimc_is_frame *frame, u32 *lindex, u32 *hindex, u32 *indexes) { /* this function is for dis stop */ } void fimc_is_subdev_dis_bypass(struct fimc_is_device_ischain *device, struct fimc_is_frame *frame, u32 *lindex, u32 *hindex, u32 *indexes, bool bypass) { struct param_tpu_config *config_param; FIMC_BUG_VOID(!device); FIMC_BUG_VOID(!lindex); FIMC_BUG_VOID(!hindex); FIMC_BUG_VOID(!indexes); config_param = fimc_is_itf_g_param(device, frame, PARAM_TPU_CONFIG); config_param->dis_bypass = bypass ? CONTROL_BYPASS_ENABLE : CONTROL_BYPASS_DISABLE; *lindex |= LOWBIT_OF(PARAM_TPU_CONFIG); *hindex |= HIGHBIT_OF(PARAM_TPU_CONFIG); (*indexes)++; } void fimc_is_subdev_dnr_start(struct fimc_is_device_ischain *device, struct fimc_is_frame *frame, u32 *lindex, u32 *hindex, u32 *indexes) { /* this function is for dnr start */ } void fimc_is_subdev_dnr_stop(struct fimc_is_device_ischain *device, struct fimc_is_frame *frame, u32 *lindex, u32 *hindex, u32 *indexes) { /* this function is for dnr stop */ } void fimc_is_subdev_dnr_bypass(struct fimc_is_device_ischain *device, struct fimc_is_frame *frame, u32 *lindex, u32 *hindex, u32 *indexes, bool bypass) { struct param_tpu_config *config_param; FIMC_BUG_VOID(!device); FIMC_BUG_VOID(!lindex); FIMC_BUG_VOID(!hindex); FIMC_BUG_VOID(!indexes); config_param = fimc_is_itf_g_param(device, frame, PARAM_TPU_CONFIG); config_param->tdnr_bypass = bypass ? CONTROL_BYPASS_ENABLE : CONTROL_BYPASS_DISABLE; *lindex |= LOWBIT_OF(PARAM_TPU_CONFIG); *hindex |= HIGHBIT_OF(PARAM_TPU_CONFIG); (*indexes)++; } void fimc_is_subdev_drc_start(struct fimc_is_device_ischain *device, struct fimc_is_frame *frame, u32 *lindex, u32 *hindex, u32 *indexes) { #ifdef SOC_DRC struct param_control *ctl_param; FIMC_BUG_VOID(!device); FIMC_BUG_VOID(!lindex); FIMC_BUG_VOID(!hindex); FIMC_BUG_VOID(!indexes); ctl_param = fimc_is_itf_g_param(device, frame, PARAM_DRC_CONTROL); ctl_param->cmd = CONTROL_COMMAND_START; ctl_param->bypass = CONTROL_BYPASS_DISABLE; *lindex |= LOWBIT_OF(PARAM_DRC_CONTROL); *hindex |= HIGHBIT_OF(PARAM_DRC_CONTROL); (*indexes)++; #endif } void fimc_is_subdev_drc_stop(struct fimc_is_device_ischain *device, struct fimc_is_frame *frame, u32 *lindex, u32 *hindex, u32 *indexes) { #ifdef SOC_DRC struct param_control *ctl_param; FIMC_BUG_VOID(!device); FIMC_BUG_VOID(!lindex); FIMC_BUG_VOID(!hindex); FIMC_BUG_VOID(!indexes); ctl_param = fimc_is_itf_g_param(device, frame, PARAM_DRC_CONTROL); ctl_param->cmd = CONTROL_COMMAND_STOP; ctl_param->bypass = CONTROL_BYPASS_ENABLE; *lindex |= LOWBIT_OF(PARAM_DRC_CONTROL); *hindex |= HIGHBIT_OF(PARAM_DRC_CONTROL); (*indexes)++; #endif } void fimc_is_subdev_drc_bypass(struct fimc_is_device_ischain *device, struct fimc_is_frame *frame, u32 *lindex, u32 *hindex, u32 *indexes, bool bypass) { #ifdef SOC_DRC struct param_control *ctl_param; FIMC_BUG_VOID(!device); FIMC_BUG_VOID(!lindex); FIMC_BUG_VOID(!hindex); FIMC_BUG_VOID(!indexes); ctl_param = fimc_is_itf_g_param(device, frame, PARAM_DRC_CONTROL); ctl_param->cmd = CONTROL_COMMAND_START; ctl_param->bypass = bypass ? CONTROL_BYPASS_ENABLE : CONTROL_BYPASS_DISABLE; *lindex |= LOWBIT_OF(PARAM_DRC_CONTROL); *hindex |= HIGHBIT_OF(PARAM_DRC_CONTROL); (*indexes)++; #endif } void fimc_is_subdev_odc_start(struct fimc_is_device_ischain *device, struct fimc_is_frame *frame, u32 *lindex, u32 *hindex, u32 *indexes) { /* this function is for odc start */ } void fimc_is_subdev_odc_stop(struct fimc_is_device_ischain *device, struct fimc_is_frame *frame, u32 *lindex, u32 *hindex, u32 *indexes) { /* this function is for odc stop */ } void fimc_is_subdev_odc_bypass(struct fimc_is_device_ischain *device, struct fimc_is_frame *frame, u32 *lindex, u32 *hindex, u32 *indexes, bool bypass) { struct param_tpu_config *config_param; FIMC_BUG_VOID(!device); FIMC_BUG_VOID(!lindex); FIMC_BUG_VOID(!hindex); FIMC_BUG_VOID(!indexes); config_param = fimc_is_itf_g_param(device, frame, PARAM_TPU_CONFIG); config_param->odc_bypass = bypass ? CONTROL_BYPASS_ENABLE : CONTROL_BYPASS_DISABLE; *lindex |= LOWBIT_OF(PARAM_TPU_CONFIG); *hindex |= HIGHBIT_OF(PARAM_TPU_CONFIG); (*indexes)++; } #ifdef ENABLE_FD_SW int fimc_is_vra_trigger(struct fimc_is_device_ischain *device, struct fimc_is_subdev *subdev, struct fimc_is_frame *frame) { int ret = 0; struct fimc_is_lib_fd *lib_data; struct camera2_fd_udm *fd_dm; struct camera2_stats_dm *fdstats; u32 detect_num = 0; FIMC_BUG(!device); FIMC_BUG(!subdev); FIMC_BUG(!frame); /* Parameter memset */ fdstats = &frame->shot->dm.stats; memset(fdstats->faceRectangles, 0, sizeof(fdstats->faceRectangles)); memset(fdstats->faceScores, 0, sizeof(fdstats->faceScores)); memset(fdstats->faceIds, 0, sizeof(fdstats->faceIds)); /* vra bypass check */ if (!test_bit(FIMC_IS_SUBDEV_RUN, &subdev->state)) goto vra_pass; if (unlikely(!device->fd_lib)) { merr("fimc_is_fd_lib is NULL", device); goto vra_pass; } if (unlikely(!device->fd_lib->lib_data)) { merr("fimc_is_lib_data is NULL", device); goto vra_pass; } lib_data = device->fd_lib->lib_data; if (!test_bit(FD_LIB_CONFIG, &device->fd_lib->state)) { merr("didn't become FD lib config", device); goto vra_pass; } /* ToDo: Support face detection mode by setfile */ fdstats->faceDetectMode = FACEDETECT_MODE_FULL; if(!test_bit(FD_LIB_RUN, &device->fd_lib->state)) { /* Parameter copy for Host FD */ fd_dm = &frame->shot->udm.fd; lib_data->fd_uctl.faceDetectMode = fdstats->faceDetectMode; lib_data->data_fd_lib->sat = fd_dm->vendorSpecific[0]; if (!lib_data->num_detect) { memset(&lib_data->prev_fd_uctl, 0, sizeof(struct camera2_fd_uctl)); lib_data->prev_num_detect = 0; } else { for (detect_num = 0; detect_num < lib_data->num_detect; detect_num++) { /* Parameter copy for HAL */ fdstats->faceRectangles[detect_num][0] = lib_data->fd_uctl.faceRectangles[detect_num][0]; fdstats->faceRectangles[detect_num][1] = lib_data->fd_uctl.faceRectangles[detect_num][1]; fdstats->faceRectangles[detect_num][2] = lib_data->fd_uctl.faceRectangles[detect_num][2]; fdstats->faceRectangles[detect_num][3] = lib_data->fd_uctl.faceRectangles[detect_num][3]; fdstats->faceScores[detect_num] = lib_data->fd_uctl.faceScores[detect_num]; fdstats->faceIds[detect_num] = lib_data->fd_uctl.faceIds[detect_num]; } /* FD information backup */ memcpy(&lib_data->prev_fd_uctl, &lib_data->fd_uctl, sizeof(struct camera2_fd_uctl)); lib_data->prev_num_detect = lib_data->num_detect; } /* host fd thread run */ fimc_is_lib_fd_trigger(device->fd_lib); } else { for (detect_num = 0; detect_num < lib_data->prev_num_detect; detect_num++) { /* Previous parameter copy for HAL */ fdstats->faceRectangles[detect_num][0] = lib_data->prev_fd_uctl.faceRectangles[detect_num][0]; fdstats->faceRectangles[detect_num][1] = lib_data->prev_fd_uctl.faceRectangles[detect_num][1]; fdstats->faceRectangles[detect_num][2] = lib_data->prev_fd_uctl.faceRectangles[detect_num][2]; fdstats->faceRectangles[detect_num][3] = lib_data->prev_fd_uctl.faceRectangles[detect_num][3]; fdstats->faceScores[detect_num] = lib_data->prev_fd_uctl.faceScores[detect_num]; fdstats->faceIds[detect_num] = lib_data->prev_fd_uctl.faceIds[detect_num]; } } vra_pass: return ret; } #endif static int fimc_is_subdev_internal_alloc_buffer(struct fimc_is_subdev *subdev, struct fimc_is_mem *mem) { int ret; int i; int buffer_size; struct fimc_is_frame *frame; FIMC_BUG(!subdev); if (subdev->buffer_num > SUBDEV_INTERNAL_BUF_MAX) { err("invalid internal buffer num size(%d)", subdev->buffer_num); return -EINVAL; } for (i = 0; i < subdev->buffer_num; i++) { buffer_size = subdev->output.width * subdev->output.height * subdev->bytes_per_pixel; if (buffer_size <= 0) { err("wrong internal subdev buffer size(%d)", buffer_size); return -EINVAL; } subdev->pb_subdev[i] = CALL_PTR_MEMOP(mem, alloc, mem->default_ctx, buffer_size, NULL, 0); if (IS_ERR_OR_NULL(subdev->pb_subdev[i])) { err("failed to allocate buffer for internal subdev"); ret = -ENOMEM; goto err_allocate_pb_subdev; } } ret = frame_manager_open(&subdev->internal_framemgr, subdev->buffer_num); if (ret) { err("fimc_is_frame_open is fail(%d)", ret); ret = -EINVAL; goto err_open_framemgr; } for (i = 0; i < subdev->buffer_num; i++) { frame = &subdev->internal_framemgr.frames[i]; frame->subdev = subdev; /* TODO : support multi-plane */ frame->planes = 1; frame->dvaddr_buffer[0] = CALL_BUFOP(subdev->pb_subdev[i], dvaddr, subdev->pb_subdev[i]); frame->kvaddr_buffer[0] = CALL_BUFOP(subdev->pb_subdev[i], kvaddr, subdev->pb_subdev[i]); set_bit(FRAME_MEM_INIT, &frame->mem_state); } info("[%d] %s (subdev_id: %d, size: %d, buffernum: %d)", subdev->instance, __func__, subdev->id, buffer_size, subdev->buffer_num); return 0; err_open_framemgr: err_allocate_pb_subdev: while (i-- > 0) CALL_VOID_BUFOP(subdev->pb_subdev[i], free, subdev->pb_subdev[i]); return ret; }; static int fimc_is_subdev_internal_free_buffer(struct fimc_is_subdev *subdev) { int ret = 0; int i; FIMC_BUG(!subdev); frame_manager_close(&subdev->internal_framemgr); for (i = 0; i < subdev->buffer_num; i++) CALL_VOID_BUFOP(subdev->pb_subdev[i], free, subdev->pb_subdev[i]); info("[%d]%s(id: %d)", subdev->instance, __func__, subdev->id); return ret; }; static int fimc_is_sensor_subdev_internal_alloc_buffer(struct fimc_is_device_sensor *device) { int ret = 0; int i; struct fimc_is_device_csi *csi; struct fimc_is_subdev *dma_subdev; struct fimc_is_mem *mem = &device->resourcemgr->mem; csi = (struct fimc_is_device_csi *)v4l2_get_subdevdata(device->subdev_csi); if (!csi) { err("csi is NULL"); return -EINVAL; } for (i = CSI_VIRTUAL_CH_1; i < CSI_VIRTUAL_CH_MAX; i++) { dma_subdev = csi->dma_subdev[i]; if (!dma_subdev) continue; if (!test_bit(FIMC_IS_SUBDEV_INTERNAL_USE, &dma_subdev->state)) continue; if (!test_bit(FIMC_IS_SUBDEV_OPEN, &dma_subdev->state)) continue; if (!test_bit(FIMC_IS_SUBDEV_INTERNAL_S_FMT, &dma_subdev->state)) continue; if (dma_subdev->internal_framemgr.num_frames > 0) { mwarn("%s: [VC%d] already internal buffer alloced, re-alloc after free", device, __func__, i); ret = fimc_is_subdev_internal_free_buffer(dma_subdev); if (ret) { merr("subdev internal free buffer is fail", device); ret = -EINVAL; goto p_err; } } ret = fimc_is_subdev_internal_alloc_buffer(dma_subdev, mem); if (ret) { merr("subdev internal alloc buffer is fail", device); ret = -EINVAL; goto p_err; } } p_err: return ret; }; static int fimc_is_sensor_subdev_internal_free_buffer(struct fimc_is_device_sensor *device) { int ret = 0; int i; struct fimc_is_device_csi *csi; struct fimc_is_subdev *dma_subdev; csi = (struct fimc_is_device_csi *)v4l2_get_subdevdata(device->subdev_csi); if (!csi) { err("csi is NULL"); return -EINVAL; } if (test_bit(FIMC_IS_SENSOR_FRONT_START, &device->state)) { mwarn("sensor is not stopped, skip internal buffer free", device); goto p_err; } for (i = CSI_VIRTUAL_CH_1; i < CSI_VIRTUAL_CH_MAX; i++) { dma_subdev = csi->dma_subdev[i]; if (!dma_subdev) continue; if (!test_bit(FIMC_IS_SUBDEV_INTERNAL_USE, &dma_subdev->state)) continue; if (!test_bit(FIMC_IS_SUBDEV_OPEN, &dma_subdev->state)) continue; if (!test_bit(FIMC_IS_SUBDEV_INTERNAL_S_FMT, &dma_subdev->state)) continue; if (dma_subdev->internal_framemgr.num_frames == 0) { mwarn("[VC%d] already free internal buffer", device, i); continue; } ret = fimc_is_subdev_internal_free_buffer(dma_subdev); if (ret) { merr("subdev internal free buffer is fail", device); ret = -EINVAL; goto p_err; } } p_err: return ret; }; static int fimc_is_sensor_subdev_internal_start(struct fimc_is_device_sensor *device) { int ret = 0; int i, j; struct fimc_is_device_csi *csi; struct fimc_is_subdev *dma_subdev; struct fimc_is_framemgr *framemgr; struct fimc_is_frame *frame; unsigned long flags; csi = (struct fimc_is_device_csi *)v4l2_get_subdevdata(device->subdev_csi); if (!csi) { err("csi is NULL"); return -EINVAL; } if (!test_bit(FIMC_IS_SENSOR_S_INPUT, &device->state)) { merr("device is not yet init", device); ret = -EINVAL; goto p_err; } for (i = CSI_VIRTUAL_CH_1; i < CSI_VIRTUAL_CH_MAX; i++) { dma_subdev = csi->dma_subdev[i]; if (!dma_subdev) continue; if (!test_bit(FIMC_IS_SUBDEV_INTERNAL_USE, &dma_subdev->state)) continue; if (!test_bit(FIMC_IS_SUBDEV_OPEN, &dma_subdev->state)) continue; if (!test_bit(FIMC_IS_SUBDEV_INTERNAL_S_FMT, &dma_subdev->state)) continue; if (test_bit(FIMC_IS_SUBDEV_START, &dma_subdev->state)) { mwarn("[VC%d] subdev already start", device, i); continue; } /* qbuf a setting num of buffers before stream on */ framemgr = GET_SUBDEV_FRAMEMGR(dma_subdev); if (unlikely(!framemgr)) { warn("VC%d subdev's framemgr is null", i); continue; } for (j = 0; j < framemgr->num_frames; j++) { frame = &framemgr->frames[j]; /* 1. check frame validation */ if (unlikely(!test_bit(FRAME_MEM_INIT, &frame->mem_state))) { mserr("frame %d is NOT init", dma_subdev, dma_subdev, j); ret = EINVAL; goto p_err; } /* 2. update frame manager */ framemgr_e_barrier_irqs(framemgr, FMGR_IDX_17, flags); if (frame->state != FS_FREE) { mserr("frame %d is invalid state(%d)\n", dma_subdev, dma_subdev, j, frame->state); frame_manager_print_queues(framemgr); ret = -EINVAL; } framemgr_x_barrier_irqr(framemgr, FMGR_IDX_17, flags); } set_bit(FIMC_IS_SUBDEV_START, &dma_subdev->state); minfo("[VC%d] %s(%s)\n", device, i, __func__, dma_subdev->data_type); } p_err: return ret; }; static int fimc_is_sensor_subdev_internal_stop(struct fimc_is_device_sensor *device) { int ret = 0; int i; struct fimc_is_device_csi *csi; struct fimc_is_subdev *dma_subdev; struct fimc_is_framemgr *framemgr; struct fimc_is_frame *frame; unsigned long flags; csi = (struct fimc_is_device_csi *)v4l2_get_subdevdata(device->subdev_csi); if (!csi) { err("csi is NULL"); return -EINVAL; } for (i = CSI_VIRTUAL_CH_1; i < CSI_VIRTUAL_CH_MAX; i++) { dma_subdev = csi->dma_subdev[i]; if (!dma_subdev) continue; if (!test_bit(FIMC_IS_SUBDEV_INTERNAL_USE, &dma_subdev->state)) continue; if (!test_bit(FIMC_IS_SUBDEV_OPEN, &dma_subdev->state)) continue; if (!test_bit(FIMC_IS_SUBDEV_INTERNAL_S_FMT, &dma_subdev->state)) continue; if (!test_bit(FIMC_IS_SUBDEV_START, &dma_subdev->state)) { mserr("already stopped", dma_subdev, dma_subdev); continue; } framemgr = GET_SUBDEV_FRAMEMGR(dma_subdev); if (unlikely(!framemgr)) { warn("VC%d subdev's framemgr is null", i); continue; } framemgr_e_barrier_irqs(framemgr, FMGR_IDX_16, flags); frame = peek_frame(framemgr, FS_PROCESS); while (frame) { trans_frame(framemgr, frame, FS_COMPLETE); frame = peek_frame(framemgr, FS_PROCESS); } frame = peek_frame(framemgr, FS_REQUEST); while (frame) { trans_frame(framemgr, frame, FS_COMPLETE); frame = peek_frame(framemgr, FS_REQUEST); } frame = peek_frame(framemgr, FS_COMPLETE); while (frame) { trans_frame(framemgr, frame, FS_FREE); frame = peek_frame(framemgr, FS_COMPLETE); } framemgr_x_barrier_irqr(framemgr, FMGR_IDX_16, flags); clear_bit(FIMC_IS_SUBDEV_START, &dma_subdev->state); minfo("[VC%d] %s(%s)\n", device, i, __func__, dma_subdev->data_type); } return ret; }; int fimc_is_subdev_internal_start(void *device, enum fimc_is_device_type type) { int ret = 0; struct fimc_is_device_sensor *sensor; struct fimc_is_device_ischain *ischain; FIMC_BUG(!device); switch (type) { case FIMC_IS_DEVICE_SENSOR: sensor = (struct fimc_is_device_sensor *)device; ret = fimc_is_sensor_subdev_internal_alloc_buffer(sensor); if (ret) { err("sensor internal alloc buffer fail(%d)", ret); break; } ret = fimc_is_sensor_subdev_internal_start(sensor); if (ret) err("sensor internal start fail(%d)", ret); break; case FIMC_IS_DEVICE_ISCHAIN: ischain = (struct fimc_is_device_ischain *)device; /* TODO */ break; default: err("invalid device_type(%d)", type); ret = -EINVAL; break; } return ret; }; int fimc_is_subdev_internal_stop(void *device, enum fimc_is_device_type type) { int ret = 0; struct fimc_is_device_sensor *sensor; struct fimc_is_device_ischain *ischain; FIMC_BUG(!device); switch (type) { case FIMC_IS_DEVICE_SENSOR: sensor = (struct fimc_is_device_sensor *)device; ret = fimc_is_sensor_subdev_internal_stop(sensor); if (ret) { err("sensor internal stop fail(%d)", ret); break; } ret = fimc_is_sensor_subdev_internal_free_buffer(sensor); if (ret) err("sensor internal buffer free fail(%d)", ret); break; case FIMC_IS_DEVICE_ISCHAIN: ischain = (struct fimc_is_device_ischain *)device; /* TODO */ break; default: err("invalid device_type(%d)", type); ret = -EINVAL; break; } return ret; }; static int fimc_is_sensor_subdev_internal_s_format(struct fimc_is_device_sensor *sensor) { int ret = 0; int ch; struct fimc_is_device_csi *csi; struct fimc_is_module_enum *module = NULL; struct fimc_is_subdev *subdev = NULL; struct fimc_is_vci_config *vci_cfg = NULL; FIMC_BUG(!sensor); module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(sensor->subdev_module); if (!module) { err("module is NULL"); return -EINVAL; } csi = (struct fimc_is_device_csi *)v4l2_get_subdevdata(sensor->subdev_csi); if (!csi) { err("csi is NULL"); return -EINVAL; } for (ch = CSI_VIRTUAL_CH_1; ch < CSI_VIRTUAL_CH_MAX; ch++) { subdev = NULL; switch (ch) { case CSI_VIRTUAL_CH_1: if (test_bit(FIMC_IS_SUBDEV_INTERNAL_USE, &sensor->ssvc1.state)) subdev = &sensor->ssvc1; break; case CSI_VIRTUAL_CH_2: if (test_bit(FIMC_IS_SUBDEV_INTERNAL_USE, &sensor->ssvc2.state)) subdev = &sensor->ssvc2; break; case CSI_VIRTUAL_CH_3: if (test_bit(FIMC_IS_SUBDEV_INTERNAL_USE, &sensor->ssvc3.state)) subdev = &sensor->ssvc3; break; } if (!subdev) continue; clear_bit(FIMC_IS_SUBDEV_INTERNAL_S_FMT, &subdev->state); if (!test_bit(FIMC_IS_SUBDEV_OPEN, &subdev->state)) continue; vci_cfg = &sensor->cfg->output[ch]; if (vci_cfg->type == VC_NOTHING) continue; /* VC type dependent value setting */ switch (vci_cfg->type) { case VC_TAILPDAF: subdev->buffer_num = SUBDEV_INTERNAL_BUF_MAX; subdev->vc_buffer_offset = module->vc_buffer_offset[ch]; snprintf(subdev->data_type, sizeof(subdev->data_type), "VC_TAILPDAF"); break; case VC_MIPISTAT: subdev->buffer_num = SUBDEV_INTERNAL_BUF_MAX; subdev->vc_buffer_offset = module->vc_buffer_offset[ch]; snprintf(subdev->data_type, sizeof(subdev->data_type), "VC_MIPISTAT"); break; case VC_EMBEDDED: case VC_EMBEDDED2: subdev->buffer_num = SUBDEV_INTERNAL_BUF_MAX; subdev->vc_buffer_offset = module->vc_buffer_offset[ch]; snprintf(subdev->data_type, sizeof(subdev->data_type), "VC_EMBEDDED"); break; case VC_PRIVATE: subdev->buffer_num = SUBDEV_INTERNAL_BUF_MAX; subdev->vc_buffer_offset = module->vc_buffer_offset[ch]; snprintf(subdev->data_type, sizeof(subdev->data_type), "VC_PRIVATE"); break; default: err("wrong internal vc ch(%d) type(%d)", ch, vci_cfg->type); return -EINVAL; } subdev->output.width = vci_cfg->width; subdev->output.height = vci_cfg->height; if (subdev->output.width == 0 || subdev->output.height == 0) { err("wrong internal vc size(%d x %d)", subdev->output.width, subdev->output.height); return -EINVAL; } subdev->output.crop.x = 0; subdev->output.crop.y = 0; subdev->output.crop.w = subdev->output.width; subdev->output.crop.h = subdev->output.height; if (vci_cfg->type == VC_TAILPDAF) subdev->bytes_per_pixel = 2; else subdev->bytes_per_pixel = 1; set_bit(FIMC_IS_SUBDEV_INTERNAL_S_FMT, &subdev->state); } return ret; } int fimc_is_subdev_internal_s_format(void *device, enum fimc_is_device_type type) { int ret = 0; struct fimc_is_device_sensor *sensor; struct fimc_is_device_ischain *ischain; FIMC_BUG(!device); switch (type) { case FIMC_IS_DEVICE_SENSOR: sensor = (struct fimc_is_device_sensor *)device; ret = fimc_is_sensor_subdev_internal_s_format(sensor); if (ret) err("sensor internal s_format fail(%d)", ret); break; case FIMC_IS_DEVICE_ISCHAIN: ischain = (struct fimc_is_device_ischain *)device; /* TODO */ break; default: err("invalid device_type(%d)", type); ret = -EINVAL; break; } return ret; }; int fimc_is_subdev_internal_open(void *device, enum fimc_is_device_type type) { int ret = 0; struct fimc_is_device_sensor *sensor = NULL; struct fimc_is_device_ischain *ischain = NULL; struct fimc_is_subdev *subdev; char name[FIMC_IS_STR_LEN]; FIMC_BUG(!device); switch (type) { case FIMC_IS_DEVICE_SENSOR: sensor = (struct fimc_is_device_sensor *)device; /* SSVC1 */ subdev = &sensor->ssvc1; if (test_bit(FIMC_IS_SUBDEV_INTERNAL_USE, &subdev->state)) { snprintf(name, sizeof(name), "SS%dVC1", sensor->instance); frame_manager_probe(&subdev->internal_framemgr, FRAMEMGR_ID_SSXVC1, name); ret = fimc_is_sensor_check_subdev_open(sensor, subdev, NULL); if (ret) { err("fimc_is_sensor_check_subdev_open is fail(%d)", ret); goto p_err; } } /* SSVC2 */ subdev = &sensor->ssvc2; if (test_bit(FIMC_IS_SUBDEV_INTERNAL_USE, &subdev->state)) { snprintf(name, sizeof(name), "SS%dVC2", sensor->instance); frame_manager_probe(&subdev->internal_framemgr, FRAMEMGR_ID_SSXVC2, name); ret = fimc_is_sensor_check_subdev_open(sensor, subdev, NULL); if (ret) { err("fimc_is_sensor_check_subdev_open is fail(%d)", ret); goto p_err; } } /* SSVC3 */ subdev = &sensor->ssvc3; if (test_bit(FIMC_IS_SUBDEV_INTERNAL_USE, &subdev->state)) { snprintf(name, sizeof(name), "SS%dVC3", sensor->instance); frame_manager_probe(&subdev->internal_framemgr, FRAMEMGR_ID_SSXVC3, name); ret = fimc_is_sensor_check_subdev_open(sensor, subdev, NULL); if (ret) { err("fimc_is_sensor_check_subdev_open is fail(%d)", ret); goto p_err; } } break; case FIMC_IS_DEVICE_ISCHAIN: ischain = (struct fimc_is_device_ischain *)device; /* TODO */ break; default: err("invalid device_type(%d)", type); ret = -EINVAL; break; } p_err: return ret; }; int fimc_is_subdev_internal_close(void *device, enum fimc_is_device_type type) { int ret = 0; struct fimc_is_device_sensor *sensor = NULL; struct fimc_is_device_ischain *ischain = NULL; struct fimc_is_subdev *subdev; FIMC_BUG(!device); switch (type) { case FIMC_IS_DEVICE_SENSOR: sensor = (struct fimc_is_device_sensor *)device; /* for free buffer check */ ret = fimc_is_sensor_subdev_internal_free_buffer(sensor); if (ret) merr("fimc_is_sensor_subdev_internal_free_buffer fail", sensor); /* SSVC1 */ subdev = &sensor->ssvc1; if (test_bit(FIMC_IS_SUBDEV_INTERNAL_USE, &subdev->state)) { ret = fimc_is_subdev_close(subdev); if (ret) { merr("fimc_is_subdev_close is fail(%d)", sensor, ret); goto p_err; } } /* SSVC2 */ subdev = &sensor->ssvc2; if (test_bit(FIMC_IS_SUBDEV_INTERNAL_USE, &subdev->state)) { ret = fimc_is_subdev_close(subdev); if (ret) { merr("fimc_is_subdev_close is fail(%d)", sensor, ret); goto p_err; } } /* SSVC3 */ subdev = &sensor->ssvc3; if (test_bit(FIMC_IS_SUBDEV_INTERNAL_USE, &subdev->state)) { ret = fimc_is_subdev_close(subdev); if (ret) { merr("fimc_is_subdev_close is fail(%d)", sensor, ret); goto p_err; } } break; case FIMC_IS_DEVICE_ISCHAIN: ischain = (struct fimc_is_device_ischain *)device; /* TODO */ break; default: err("invalid device_type(%d)", type); ret = -EINVAL; break; } p_err: return ret; };