--- .../media/platform/tegra/camera/sensor_common.c | 15 ++- drivers/media/platform/tegra/camera/vi/channel.c | 2 + drivers/media/platform/tegra/camera/vi/vi4_fops.c | 118 +++++++++++++++------ include/media/mc_common.h | 8 ++ include/media/tegra-v4l2-camera.h | 2 + 5 files changed, 111 insertions(+), 34 deletions(-) diff --git a/drivers/media/platform/tegra/camera/sensor_common.c b/drivers/media/platform/tegra/camera/sensor_common.c index 39813ad..f68987a 100644 --- a/drivers/media/platform/tegra/camera/sensor_common.c +++ b/drivers/media/platform/tegra/camera/sensor_common.c @@ -97,7 +97,8 @@ static int sensor_common_parse_signal_props( if (signal->serdes_pixel_clock.val != 0ULL && signal->serdes_pixel_clock.val < signal->pixel_clock.val) { - dev_err(dev, "%s: serdes_pix_clk_hz is lower than pix_clk_hz!\n", __func__); + dev_err(dev, "%s: serdes_pix_clk_hz is lower than pix_clk_hz!\n", + __func__); return -EINVAL; } @@ -516,6 +517,18 @@ static int sensor_common_parse_control_props( [206/45102] } else control->default_exp_time.val = val64; + err = read_property_u32(node, "is_interlaced", &value); + if (err) + control->is_interlaced = 0; + else + control->is_interlaced = value; + + err = read_property_u32(node, "interlaced_type", &value); + if (err) + control->interlace_type = 0; + else + control->interlace_type = value; + return 0; } diff --git a/drivers/media/platform/tegra/camera/vi/channel.c b/drivers/media/platform/tegra/camera/vi/channel.c index 7bb5c7b..eb0a553 100644 --- a/drivers/media/platform/tegra/camera/vi/channel.c +++ b/drivers/media/platform/tegra/camera/vi/channel.c @@ -2217,6 +2217,8 @@ int tegra_channel_init(struct tegra_channel *chan) &chan->fmtinfo->bpp, 0); chan->buffer_offset[0] = 0; + /* Init bpl factor to 1, will be overidden based on interlace_type */ + chan->interlace_bplfactor = 1; /* Initialize the media entity... */ chan->pad.flags = MEDIA_PAD_FL_SINK; diff --git a/drivers/media/platform/tegra/camera/vi/vi4_fops.c b/drivers/media/platform/tegra/camera/vi/vi4_fops.c index 412fb88..795806b 100644 --- a/drivers/media/platform/tegra/camera/vi/vi4_fops.c +++ b/drivers/media/platform/tegra/camera/vi/vi4_fops.c @@ -27,6 +27,8 @@ #include #define BPP_MEM 2 #define MAX_VI_CHANNEL 12 +#define NUM_FIELDS_INTERLACED 2 +#define NUM_FIELDS_SINGLE 1 #define SOF_SYNCPT_IDX 0 #define FE_SYNCPT_IDX 1 @@ -245,7 +247,8 @@ static void tegra_channel_surface_setup( vi4_channel_write(chan, vnc_id, ATOMP_SURFACE_OFFSET0, buf->addr + offset); vi4_channel_write(chan, vnc_id, - ATOMP_SURFACE_STRIDE0, chan->format.bytesperline); + ATOMP_SURFACE_STRIDE0, + chan->format.bytesperline * chan->interlace_bplfactor); vi4_channel_write(chan, vnc_id, ATOMP_SURFACE_OFFSET0_H, 0x0); if (chan->fmtinfo->fourcc == V4L2_PIX_FMT_NV16) { @@ -255,7 +258,8 @@ static void tegra_channel_surface_setup( vi4_channel_write(chan, vnc_id, ATOMP_SURFACE_OFFSET1_H, 0x0); vi4_channel_write(chan, vnc_id, - ATOMP_SURFACE_STRIDE1, chan->format.bytesperline); + ATOMP_SURFACE_STRIDE1, + chan->format.bytesperline * chan->interlace_bplfactor); } else { vi4_channel_write(chan, vnc_id, ATOMP_SURFACE_OFFSET1, 0x0); @@ -525,49 +529,75 @@ static int tegra_channel_capture_frame_single_thread( int state = VB2_BUF_STATE_DONE; unsigned long flags; int err = false; + int run_captures = 0; int i; + int j; - spin_lock_irqsave(&chan->capture_state_lock, flags); - chan->capture_state = CAPTURE_IDLE; - spin_unlock_irqrestore(&chan->capture_state_lock, flags); + if (chan->is_interlaced) + run_captures = NUM_FIELDS_INTERLACED; + else + run_captures = NUM_FIELDS_SINGLE; - for (i = 0; i < chan->valid_ports; i++) - tegra_channel_surface_setup(chan, buf, i); + for (j = 0 ; j < run_captures; j++) { + state = VB2_BUF_STATE_DONE; + spin_lock_irqsave(&chan->capture_state_lock, flags); + chan->capture_state = CAPTURE_IDLE; + spin_unlock_irqrestore(&chan->capture_state_lock, flags); - if (!chan->bfirst_fstart) { - err = tegra_channel_set_stream(chan, true); - if (err < 0) - return err; + if (chan->is_interlaced) { + if (chan->interlace_type == Interleaved) { + chan->buffer_offset[0] = + j * chan->format.bytesperline; + chan->interlace_bplfactor = + NUM_FIELDS_INTERLACED; + } else { + chan->buffer_offset[0] = j * + chan->format.bytesperline * chan->format.height; + + chan->interlace_bplfactor = NUM_FIELDS_SINGLE; + } + } - err = tegra_channel_write_blobs(chan); - if (err < 0) - return err; - } + for (i = 0; i < chan->valid_ports; i++) + tegra_channel_surface_setup(chan, buf, i); - for (i = 0; i < chan->valid_ports; i++) { - vi4_channel_write(chan, chan->vnc_id[i], CHANNEL_COMMAND, LOAD); - vi4_channel_write(chan, chan->vnc_id[i], - CONTROL, SINGLESHOT | MATCH_STATE_EN); - } + if (!chan->bfirst_fstart) { + err = tegra_channel_set_stream(chan, true); + if (err < 0) + return err; - /* wait for vi notifier events */ - if (!vi_notify_wait(chan, buf, &ts)) { - tegra_channel_error_recovery(chan); + err = tegra_channel_write_blobs(chan); + if (err < 0) + return err; + } - state = VB2_BUF_STATE_REQUEUEING; [74/45102] + for (i = 0; i < chan->valid_ports; i++) { + vi4_channel_write(chan, chan->vnc_id[i], + CHANNEL_COMMAND, LOAD); + vi4_channel_write(chan, chan->vnc_id[i], + CONTROL, SINGLESHOT | MATCH_STATE_EN); + } + + /* wait for vi notifier events */ + if (!vi_notify_wait(chan, buf, &ts)) { + tegra_channel_error_recovery(chan); + + state = VB2_BUF_STATE_REQUEUEING; + + spin_lock_irqsave(&chan->capture_state_lock, flags); + chan->capture_state = CAPTURE_TIMEOUT; + spin_unlock_irqrestore(&chan->capture_state_lock, + flags); + } + + vi4_check_status(chan); spin_lock_irqsave(&chan->capture_state_lock, flags); - chan->capture_state = CAPTURE_TIMEOUT; + if (chan->capture_state == CAPTURE_IDLE) + chan->capture_state = CAPTURE_GOOD; spin_unlock_irqrestore(&chan->capture_state_lock, flags); } - vi4_check_status(chan); - - spin_lock_irqsave(&chan->capture_state_lock, flags); - if (chan->capture_state == CAPTURE_IDLE) - chan->capture_state = CAPTURE_GOOD; - spin_unlock_irqrestore(&chan->capture_state_lock, flags); - set_timestamp(buf, &ts); tegra_channel_ring_buffer(chan, vb, &ts, state); trace_tegra_channel_capture_frame("sof", ts); @@ -686,7 +716,7 @@ static void tegra_channel_release_frame(struct tegra_channel *chan, [35/45102] "ATOMP_FE syncpt timeout! err = %d\n", err); else dev_dbg(&chan->video.dev, - "%s: vi4 got EOF syncpt buf[%p]\n", __func__, buf); + "%s: vi4 got EOF syncpt buf[%p]\n", __func__, buf); } if (err) { @@ -1024,6 +1054,28 @@ static int vi4_channel_start_streaming(struct vb2_queue *vq, u32 count) chan->vi->emb_buf_size = emb_buf_size; } } + /* Check if sensor mode is interlaced and the type of interlaced mode */ + sd = chan->subdev_on_csi; + node = sd->dev->of_node; + s_data = to_camera_common_data(sd->dev); + + /* get sensor properties from DT */ + if (s_data != NULL && node != NULL) { + int idx = s_data->mode_prop_idx; + + if (idx < s_data->sensor_props.num_modes) { + sensor_mode = + &s_data->sensor_props.sensor_modes[idx]; + chan->is_interlaced = + sensor_mode->control_properties.is_interlaced; + if (chan->is_interlaced) { + if (sensor_mode->control_properties.interlace_type) + chan->interlace_type = Interleaved; + else + chan->interlace_type = Top_Bottom; + } + } + } for (i = 0; i < chan->valid_ports; i++) { ret = tegra_channel_capture_setup(chan, i); diff --git a/include/media/mc_common.h b/include/media/mc_common.h index 8eb886c..4ddeb78 100644 --- a/include/media/mc_common.h +++ b/include/media/mc_common.h @@ -60,6 +60,11 @@ enum tegra_vi_pg_mode { TEGRA_VI_PG_PATCH, }; +enum interlaced_type { + Top_Bottom = 0, + Interleaved, +}; + /** * struct tegra_channel_buffer - video channel buffer * @buf: vb2 buffer base object @@ -251,6 +256,9 @@ struct tegra_channel { struct tegra_vi_channel *tegra_vi_channel; struct capture_descriptor *request; bool is_slvsec; + int is_interlaced; + enum interlaced_type interlace_type; + int interlace_bplfactor; }; #define to_tegra_channel(vdev) \ diff --git a/include/media/tegra-v4l2-camera.h b/include/media/tegra-v4l2-camera.h index d1c71fc..cb63198 100644 --- a/include/media/tegra-v4l2-camera.h +++ b/include/media/tegra-v4l2-camera.h @@ -146,6 +146,8 @@ struct sensor_control_properties { __u32 default_gain; __u32 default_framerate; union __u64val default_exp_time; + __u32 is_interlaced; + __u32 interlace_type; __u32 reserved[10]; }; -- 2.7.4