lineage_kernel_xcoverpro/drivers/media/platform/exynos/fimc-is2/fimc-is-subdev-ctrl.c

1896 lines
46 KiB
C
Executable File

/*
* 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 "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;
};