summaryrefslogtreecommitdiffstats
path: root/drivers/staging/media/atomisp/pci/atomisp_cmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/media/atomisp/pci/atomisp_cmd.c')
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_cmd.c281
1 files changed, 125 insertions, 156 deletions
diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
index 8593ba90605f..102d39a45c9c 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
@@ -61,13 +61,6 @@
#include "ia_css_debug.h"
#include "bits.h"
-/* We should never need to run the flash for more than 2 frames.
- * At 15fps this means 133ms. We set the timeout a bit longer.
- * Each flash driver is supposed to set its own timeout, but
- * just in case someone else changed the timeout, we set it
- * here to make sure we don't damage the flash hardware. */
-#define FLASH_TIMEOUT 800 /* ms */
-
union host {
struct {
void *kernel_ptr;
@@ -676,7 +669,6 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
struct atomisp_metadata_buf *md_buf = NULL, *_md_buf_tmp, *md_iter;
enum atomisp_metadata_type md_type;
struct atomisp_device *isp = asd->isp;
- struct v4l2_control ctrl;
int i, err;
lockdep_assert_held(&isp->mutex);
@@ -791,19 +783,6 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
dev_dbg(isp->dev, "%s: vf frame with exp_id %d is ready\n",
__func__, frame->exp_id);
- if (asd->params.flash_state == ATOMISP_FLASH_ONGOING) {
- if (frame->flash_state
- == IA_CSS_FRAME_FLASH_STATE_PARTIAL)
- dev_dbg(isp->dev, "%s thumb partially flashed\n",
- __func__);
- else if (frame->flash_state
- == IA_CSS_FRAME_FLASH_STATE_FULL)
- dev_dbg(isp->dev, "%s thumb completely flashed\n",
- __func__);
- else
- dev_dbg(isp->dev, "%s thumb no flash in this frame\n",
- __func__);
- }
pipe->frame_config_id[frame->vb.vb2_buf.index] = frame->isp_config_id;
break;
case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME:
@@ -834,40 +813,6 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
}
pipe->frame_config_id[i] = frame->isp_config_id;
- ctrl.id = V4L2_CID_FLASH_MODE;
- if (asd->params.flash_state == ATOMISP_FLASH_ONGOING) {
- if (frame->flash_state == IA_CSS_FRAME_FLASH_STATE_PARTIAL) {
- asd->frame_status[i] = ATOMISP_FRAME_STATUS_FLASH_PARTIAL;
- dev_dbg(isp->dev, "%s partially flashed\n", __func__);
- } else if (frame->flash_state == IA_CSS_FRAME_FLASH_STATE_FULL) {
- asd->frame_status[i] = ATOMISP_FRAME_STATUS_FLASH_EXPOSED;
- asd->params.num_flash_frames--;
- dev_dbg(isp->dev, "%s completely flashed\n", __func__);
- } else {
- asd->frame_status[i] = ATOMISP_FRAME_STATUS_OK;
- dev_dbg(isp->dev, "%s no flash in this frame\n", __func__);
- }
-
- /* Check if flashing sequence is done */
- if (asd->frame_status[i] == ATOMISP_FRAME_STATUS_FLASH_EXPOSED)
- asd->params.flash_state = ATOMISP_FLASH_DONE;
- } else if (isp->flash) {
- if (v4l2_g_ctrl(isp->flash->ctrl_handler, &ctrl) == 0 &&
- ctrl.value == ATOMISP_FLASH_MODE_TORCH) {
- ctrl.id = V4L2_CID_FLASH_TORCH_INTENSITY;
- if (v4l2_g_ctrl(isp->flash->ctrl_handler, &ctrl) == 0 &&
- ctrl.value > 0)
- asd->frame_status[i] = ATOMISP_FRAME_STATUS_FLASH_EXPOSED;
- else
- asd->frame_status[i] = ATOMISP_FRAME_STATUS_OK;
- } else {
- asd->frame_status[i] = ATOMISP_FRAME_STATUS_OK;
- }
- } else {
- asd->frame_status[i] = ATOMISP_FRAME_STATUS_OK;
- }
-
- asd->params.last_frame_status = asd->frame_status[i];
if (asd->params.css_update_params_needed) {
atomisp_apply_css_parameters(asd,
@@ -1010,51 +955,18 @@ out_unlock:
mutex_unlock(&isp->mutex);
}
-void atomisp_setup_flash(struct atomisp_sub_device *asd)
-{
- struct atomisp_device *isp = asd->isp;
- struct v4l2_control ctrl;
-
- if (!isp->flash)
- return;
-
- if (asd->params.flash_state != ATOMISP_FLASH_REQUESTED &&
- asd->params.flash_state != ATOMISP_FLASH_DONE)
- return;
-
- if (asd->params.num_flash_frames) {
- /* make sure the timeout is set before setting flash mode */
- ctrl.id = V4L2_CID_FLASH_TIMEOUT;
- ctrl.value = FLASH_TIMEOUT;
-
- if (v4l2_s_ctrl(NULL, isp->flash->ctrl_handler, &ctrl)) {
- dev_err(isp->dev, "flash timeout configure failed\n");
- return;
- }
-
- ia_css_stream_request_flash(asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream);
-
- asd->params.flash_state = ATOMISP_FLASH_ONGOING;
- } else {
- asd->params.flash_state = ATOMISP_FLASH_IDLE;
- }
-}
-
irqreturn_t atomisp_isr_thread(int irq, void *isp_ptr)
{
struct atomisp_device *isp = isp_ptr;
unsigned long flags;
-
- dev_dbg(isp->dev, ">%s\n", __func__);
+ bool streaming;
spin_lock_irqsave(&isp->lock, flags);
+ streaming = isp->asd.streaming;
+ spin_unlock_irqrestore(&isp->lock, flags);
- if (!isp->asd.streaming) {
- spin_unlock_irqrestore(&isp->lock, flags);
+ if (!streaming)
return IRQ_HANDLED;
- }
-
- spin_unlock_irqrestore(&isp->lock, flags);
/*
* The standard CSS2.0 API tells the following calling sequence of
@@ -1082,14 +994,8 @@ irqreturn_t atomisp_isr_thread(int irq, void *isp_ptr)
* time, instead, dequue one and process one, then another
*/
mutex_lock(&isp->mutex);
- if (atomisp_css_isr_thread(isp))
- goto out;
-
- if (isp->asd.streaming)
- atomisp_setup_flash(&isp->asd);
-out:
+ atomisp_css_isr_thread(isp);
mutex_unlock(&isp->mutex);
- dev_dbg(isp->dev, "<%s\n", __func__);
return IRQ_HANDLED;
}
@@ -1123,7 +1029,7 @@ v4l2_fmt_to_sh_fmt(u32 fmt)
return IA_CSS_FRAME_FORMAT_YUYV;
case V4L2_PIX_FMT_RGB24:
return IA_CSS_FRAME_FORMAT_PLANAR_RGB888;
- case V4L2_PIX_FMT_RGB32:
+ case V4L2_PIX_FMT_RGBX32:
return IA_CSS_FRAME_FORMAT_RGBA888;
case V4L2_PIX_FMT_RGB565:
return IA_CSS_FRAME_FORMAT_RGB565;
@@ -1210,7 +1116,7 @@ u32 atomisp_get_pixel_depth(u32 pixelformat)
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_YUV444:
return 24;
- case V4L2_PIX_FMT_RGB32:
+ case V4L2_PIX_FMT_RGBX32:
return 32;
case V4L2_PIX_FMT_JPEG:
case V4L2_PIX_FMT_CUSTOM_M10MO_RAW:
@@ -1261,11 +1167,11 @@ int atomisp_gdc_cac(struct atomisp_sub_device *asd, int flag,
}
asd->params.gdc_cac_en = !!*value;
- if (asd->params.gdc_cac_en) {
+ if (asd->params.gdc_cac_en)
asd->params.config.morph_table = asd->params.css_param.morph_table;
- } else {
+ else
asd->params.config.morph_table = NULL;
- }
+
asd->params.css_update_params_needed = true;
atomisp_update_capture_mode(asd);
return 0;
@@ -3035,8 +2941,8 @@ void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe)
}
/*
-* Function to configure ISP parameters
-*/
+ * Function to configure ISP parameters
+ */
int atomisp_set_parameters(struct video_device *vdev,
struct atomisp_parameters *arg)
{
@@ -3367,7 +3273,7 @@ int atomisp_fixed_pattern(struct atomisp_sub_device *asd, int flag,
return 0;
}
- /* Add function to get black from from sensor with shutter off */
+ /* Add function to get black from sensor with shutter off */
return 0;
}
@@ -3721,9 +3627,79 @@ apply_min_padding:
*padding_h = max_t(u32, *padding_h, min_pad_h);
}
-static int atomisp_set_crop_and_fmt(struct atomisp_device *isp,
- struct v4l2_mbus_framefmt *ffmt,
- int which)
+int atomisp_s_sensor_power(struct atomisp_device *isp, unsigned int input, bool on)
+{
+ int ret;
+
+ if (isp->inputs[input].camera_on == on)
+ return 0;
+
+ ret = v4l2_subdev_call(isp->inputs[input].camera, core, s_power, on);
+ if (ret && ret != -ENOIOCTLCMD) {
+ dev_err(isp->dev, "Error setting sensor power %d: %d\n", on, ret);
+ return ret;
+ }
+
+ isp->inputs[input].camera_on = on;
+ return 0;
+}
+
+int atomisp_select_input(struct atomisp_device *isp, unsigned int input)
+{
+ unsigned int input_orig = isp->asd.input_curr;
+ int ret;
+
+ /* Power on new sensor */
+ ret = atomisp_s_sensor_power(isp, input, 1);
+ if (ret)
+ return ret;
+
+ isp->asd.input_curr = input;
+
+ /* Power off previous sensor */
+ if (input != input_orig)
+ atomisp_s_sensor_power(isp, input_orig, 0);
+
+ atomisp_setup_input_links(isp);
+ return 0;
+}
+
+/*
+ * Ensure the CSI-receiver -> ISP link for input_curr is marked as enabled and
+ * the other CSI-receiver -> ISP links are disabled.
+ */
+void atomisp_setup_input_links(struct atomisp_device *isp)
+{
+ struct media_link *link;
+
+ lockdep_assert_held(&isp->media_dev.graph_mutex);
+
+ for (int i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
+ link = media_entity_find_link(
+ &isp->csi2_port[i].subdev.entity.pads[CSI2_PAD_SOURCE],
+ &isp->asd.subdev.entity.pads[ATOMISP_SUBDEV_PAD_SINK]);
+ if (!link) {
+ dev_err(isp->dev, "Error cannot find CSI2-port[%d] -> ISP link\n", i);
+ continue; /* Should never happen */
+ }
+
+ /*
+ * Modify the flags directly, calling media_entity_setup_link()
+ * will end up calling atomisp_link_setup() which calls this
+ * function again leading to endless recursion.
+ */
+ if (isp->sensor_subdevs[i] == isp->inputs[isp->asd.input_curr].camera)
+ link->flags |= MEDIA_LNK_FL_ENABLED;
+ else
+ link->flags &= ~MEDIA_LNK_FL_ENABLED;
+
+ link->reverse->flags = link->flags;
+ }
+}
+
+static int atomisp_set_sensor_crop_and_fmt(struct atomisp_device *isp,
+ struct v4l2_mbus_framefmt *ffmt,
+ int which)
{
struct atomisp_input_subdev *input = &isp->inputs[isp->asd.input_curr];
struct v4l2_subdev_selection sel = {
@@ -3742,6 +3718,17 @@ static int atomisp_set_crop_and_fmt(struct atomisp_device *isp,
if (!input->camera)
return -EINVAL;
+ /*
+ * Some old sensor drivers already write the registers on set_fmt
+ * instead of on stream on, power on the sensor now (on newer
+ * sensor drivers the s_power op is a no-op).
+ */
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ ret = atomisp_s_sensor_power(isp, isp->asd.input_curr, 1);
+ if (ret)
+ return ret;
+ }
+
sd_state = (which == V4L2_SUBDEV_FORMAT_TRY) ? input->try_sd_state :
input->camera->active_state;
if (sd_state)
@@ -3776,6 +3763,13 @@ set_fmt:
if (sd_state)
v4l2_subdev_unlock_state(sd_state);
+ /* Propagate new fmt to CSI port */
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ ret = v4l2_subdev_call(input->csi_port, pad, set_fmt, NULL, &format);
+ if (ret)
+ return ret;
+ }
+
*ffmt = format.format;
return ret;
}
@@ -3817,7 +3811,7 @@ int atomisp_try_fmt(struct atomisp_device *isp, struct v4l2_pix_format *f,
dev_dbg(isp->dev, "try_mbus_fmt: try %ux%u\n", ffmt.width, ffmt.height);
- ret = atomisp_set_crop_and_fmt(isp, &ffmt, V4L2_SUBDEV_FORMAT_TRY);
+ ret = atomisp_set_sensor_crop_and_fmt(isp, &ffmt, V4L2_SUBDEV_FORMAT_TRY);
if (ret)
return ret;
@@ -4044,6 +4038,7 @@ static int atomisp_set_fmt_to_isp(struct video_device *vdev,
unsigned int width, unsigned int height) =
configure_pp_input_nop;
const struct atomisp_in_fmt_conv *fc = NULL;
+ struct v4l2_mbus_framefmt *ffmt;
int ret, i;
isp_sink_crop = atomisp_subdev_get_rect(
@@ -4054,28 +4049,26 @@ static int atomisp_set_fmt_to_isp(struct video_device *vdev,
if (!format)
return -EINVAL;
- if (input->type != TEST_PATTERN) {
- mipi_info = atomisp_to_sensor_mipi_info(input->camera);
+ mipi_info = atomisp_to_sensor_mipi_info(input->camera);
- if (atomisp_set_sensor_mipi_to_isp(asd, ATOMISP_INPUT_STREAM_GENERAL,
- mipi_info))
- return -EINVAL;
-
- if (mipi_info)
- fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt(mipi_info->input_format);
+ if (atomisp_set_sensor_mipi_to_isp(asd, ATOMISP_INPUT_STREAM_GENERAL,
+ mipi_info))
+ return -EINVAL;
- if (!fc)
- fc = atomisp_find_in_fmt_conv(
- atomisp_subdev_get_ffmt(&asd->subdev,
- NULL, V4L2_SUBDEV_FORMAT_ACTIVE,
- ATOMISP_SUBDEV_PAD_SINK)->code);
- if (!fc)
- return -EINVAL;
- if (format->sh_fmt == IA_CSS_FRAME_FORMAT_RAW &&
- raw_output_format_match_input(fc->atomisp_in_fmt,
- pix->pixelformat))
- return -EINVAL;
+ if (mipi_info)
+ fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt(mipi_info->input_format);
+ if (!fc) {
+ ffmt = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
+ V4L2_SUBDEV_FORMAT_ACTIVE,
+ ATOMISP_SUBDEV_PAD_SINK);
+ fc = atomisp_find_in_fmt_conv(ffmt->code);
}
+ if (!fc)
+ return -EINVAL;
+
+ if (format->sh_fmt == IA_CSS_FRAME_FORMAT_RAW &&
+ raw_output_format_match_input(fc->atomisp_in_fmt, pix->pixelformat))
+ return -EINVAL;
/*
* Configure viewfinder also when vfpp is disabled: the
@@ -4263,7 +4256,7 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev, const struct v4l2_p
/* Disable dvs if resolution can't be supported by sensor */
if (asd->params.video_dis_en && asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
- ret = atomisp_set_crop_and_fmt(isp, &ffmt, V4L2_SUBDEV_FORMAT_TRY);
+ ret = atomisp_set_sensor_crop_and_fmt(isp, &ffmt, V4L2_SUBDEV_FORMAT_TRY);
if (ret)
return ret;
@@ -4281,7 +4274,7 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev, const struct v4l2_p
}
}
- ret = atomisp_set_crop_and_fmt(isp, &ffmt, V4L2_SUBDEV_FORMAT_ACTIVE);
+ ret = atomisp_set_sensor_crop_and_fmt(isp, &ffmt, V4L2_SUBDEV_FORMAT_ACTIVE);
if (ret)
return ret;
@@ -4420,8 +4413,6 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
atomisp_fill_pix_format(&pipe->pix, f->fmt.pix.width, f->fmt.pix.height, format_bridge);
f->fmt.pix = pipe->pix;
- f->fmt.pix.priv = PAGE_ALIGN(pipe->pix.width *
- pipe->pix.height * 2);
dev_dbg(isp->dev, "%s: %dx%d, image size: %d, %d bytes per line\n",
__func__,
@@ -4493,28 +4484,6 @@ out:
return ret;
}
-int atomisp_flash_enable(struct atomisp_sub_device *asd, int num_frames)
-{
- struct atomisp_device *isp = asd->isp;
-
- if (num_frames < 0) {
- dev_dbg(isp->dev, "%s ERROR: num_frames: %d\n", __func__,
- num_frames);
- return -EINVAL;
- }
- /* a requested flash is still in progress. */
- if (num_frames && asd->params.flash_state != ATOMISP_FLASH_IDLE) {
- dev_dbg(isp->dev, "%s flash busy: %d frames left: %d\n",
- __func__, asd->params.flash_state,
- asd->params.num_flash_frames);
- return -EBUSY;
- }
-
- asd->params.num_flash_frames = num_frames;
- asd->params.flash_state = ATOMISP_FLASH_REQUESTED;
- return 0;
-}
-
static int __checking_exp_id(struct atomisp_sub_device *asd, int exp_id)
{
struct atomisp_device *isp = asd->isp;