Re: [RFC PATCH v6 6/9] media: tegra: Add Tegra210 Video input driver

Dmitry Osipenko
2020-04-05T20:35:48Z

04.04.2020 04:25, Sowjanya Komatineni пишет:
...
> +static int tegra_channel_capture_frame(struct tegra_vi_channel *chan,
> + struct tegra_channel_buffer *buf)
> +{
> + int err = 0;
> + u32 thresh, value, frame_start, mw_ack_done;
> + int bytes_per_line = chan->format.bytesperline;
> +
> + /* program buffer address by using surface 0 */
> + vi_csi_write(chan, TEGRA_VI_CSI_SURFACE0_OFFSET_MSB,
> + (u64)buf->addr >> 32);
> + vi_csi_write(chan, TEGRA_VI_CSI_SURFACE0_OFFSET_LSB, buf->addr);
> + vi_csi_write(chan, TEGRA_VI_CSI_SURFACE0_STRIDE, bytes_per_line);
> +
> + /*
> + * Tegra VI block interacts with host1x syncpt for synchronizing
> + * programmed condition of capture state and hardware operation.
> + * Frame start and Memory write acknowledge syncpts has their own
> + * FIFO of depth 2.
> + *
> + * Syncpoint trigger conditions set through VI_INCR_SYNCPT register
> + * are added to HW syncpt FIFO and when the HW triggers, syncpt
> + * condition is removed from the FIFO and counter at syncpoint index
> + * will be incremented by the hardware and software can wait for
> + * counter to reach threshold to synchronize capturing frame with the
> + * hardware capture events.
> + */
> +
> + /* increase channel syncpoint threshold for FRAME_START */
> + thresh = host1x_syncpt_incr_max(chan->frame_start_sp, 1);
> +
> + /* Program FRAME_START trigger condition syncpt request */
> + frame_start = VI_CSI_PP_FRAME_START(chan->portno);
> + value = VI_CFG_VI_INCR_SYNCPT_COND(frame_start) |
> + host1x_syncpt_id(chan->frame_start_sp);
> + tegra_vi_write(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT, value);
> +
> + /* increase channel syncpoint threshold for MW_ACK_DONE */
> + buf->mw_ack_sp_thresh = host1x_syncpt_incr_max(chan->mw_ack_sp, 1);
> +
> + /* Program MW_ACK_DONE trigger condition syncpt request */
> + mw_ack_done = VI_CSI_MW_ACK_DONE(chan->portno);
> + value = VI_CFG_VI_INCR_SYNCPT_COND(mw_ack_done) |
> + host1x_syncpt_id(chan->mw_ack_sp);
> + tegra_vi_write(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT, value);
> +
> + /* enable single shot capture */
> + vi_csi_write(chan, TEGRA_VI_CSI_SINGLE_SHOT, SINGLE_SHOT_CAPTURE);
> + chan->capture_reqs++;
> +
> + /* wait for syncpt counter to reach frame start event threshold */
> + err = host1x_syncpt_wait(chan->frame_start_sp, thresh,
> + TEGRA_VI_SYNCPT_WAIT_TIMEOUT, &value);
> + if (err) {
> + dev_err(&chan->video.dev,
> + "frame start syncpt timeout: %d\n", err);

> + /* increment syncpoint counter for timedout events */
> + host1x_syncpt_incr(chan->frame_start_sp);

Why incrementing is done while hardware is still active?

The sync point's state needs to be completely reset after resetting
hardware. But I don't think that the current upstream host1x driver
supports doing that, it's one of the known-long-standing problems of the
host1x driver.

At least the sp->max_val incrementing should be done based on the actual
syncpoint value and this should be done after resetting hardware.

> + spin_lock(&chan->sp_incr_lock);
> + host1x_syncpt_incr(chan->mw_ack_sp);
> + spin_unlock(&chan->sp_incr_lock);
> + /* clear errors and recover */
> + tegra_channel_capture_error_recover(chan);
> + release_buffer(chan, buf, VB2_BUF_STATE_ERROR);
> + return err;
> + }