media: rcar-vin: Simplify the shutdown process

When shutting down capture extra care was needed to try and complete a
buffer that was involved in the emulated support for SEQ_{TB,BT}. This
was needed as a buffer might be queued once to the driver, but two times
to the hardware using different offsets.

As support for SEQ_{TB,BT} is now removed this shutdown process can be
greatly simplified. And in addition the state keeping of the VIN device
can be reduced to a single boolean value instead of keeping track of
this SEQ_{TB,BT} stopping dance.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
Tested-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
This commit is contained in:
Niklas Söderlund
2025-02-10 18:56:14 +01:00
committed by Hans Verkuil
parent 25482a986e
commit c1eefe88c3
3 changed files with 26 additions and 71 deletions

View File

@@ -1080,7 +1080,7 @@ static int __maybe_unused rvin_suspend(struct device *dev)
{
struct rvin_dev *vin = dev_get_drvdata(dev);
if (vin->state != RUNNING)
if (!vin->running)
return 0;
rvin_stop_streaming(vin);
@@ -1092,7 +1092,7 @@ static int __maybe_unused rvin_resume(struct device *dev)
{
struct rvin_dev *vin = dev_get_drvdata(dev);
if (vin->state != RUNNING)
if (!vin->running)
return 0;
/*

View File

@@ -1006,8 +1006,7 @@ static void rvin_fill_hw_slot(struct rvin_dev *vin, int slot)
if (WARN_ON(vin->buf_hw[slot].buffer))
return;
if ((vin->state != STOPPED && vin->state != RUNNING) ||
list_empty(&vin->buf_list)) {
if (list_empty(&vin->buf_list)) {
vin->buf_hw[slot].buffer = NULL;
phys_addr = vin->scratch_phys;
} else {
@@ -1048,8 +1047,6 @@ static int rvin_capture_start(struct rvin_dev *vin)
/* Continuous Frame Capture Mode */
rvin_write(vin, VNFC_C_FRAME, VNFC_REG);
vin->state = RUNNING;
return 0;
}
@@ -1090,9 +1087,9 @@ static irqreturn_t rvin_irq(int irq, void *data)
if (!(int_status & VNINTS_FIS))
goto done;
/* Nothing to do if capture status is 'STOPPED' */
if (vin->state == STOPPED) {
vin_dbg(vin, "IRQ while state stopped\n");
/* Nothing to do if not running. */
if (!vin->running) {
vin_dbg(vin, "IRQ while not running, ignoring\n");
goto done;
}
@@ -1373,6 +1370,8 @@ int rvin_start_streaming(struct rvin_dev *vin)
if (ret)
rvin_set_stream(vin, 0);
vin->running = true;
spin_unlock_irqrestore(&vin->qlock, flags);
return ret;
@@ -1405,44 +1404,21 @@ static int rvin_start_streaming_vq(struct vb2_queue *vq, unsigned int count)
void rvin_stop_streaming(struct rvin_dev *vin)
{
unsigned int i, retries;
unsigned long flags;
bool buffersFreed;
spin_lock_irqsave(&vin->qlock, flags);
if (vin->state == STOPPED) {
if (!vin->running) {
spin_unlock_irqrestore(&vin->qlock, flags);
return;
}
vin->state = STOPPING;
/* Wait until only scratch buffer is used, max 3 interrupts. */
retries = 0;
while (retries++ < RVIN_RETRIES) {
buffersFreed = true;
for (i = 0; i < HW_BUFFER_NUM; i++)
if (vin->buf_hw[i].buffer)
buffersFreed = false;
if (buffersFreed)
break;
spin_unlock_irqrestore(&vin->qlock, flags);
msleep(RVIN_TIMEOUT_MS);
spin_lock_irqsave(&vin->qlock, flags);
}
/* Wait for streaming to stop */
retries = 0;
while (retries++ < RVIN_RETRIES) {
for (unsigned int i = 0; i < RVIN_RETRIES; i++) {
rvin_capture_stop(vin);
/* Check if HW is stopped */
if (!rvin_capture_active(vin)) {
vin->state = STOPPED;
break;
}
@@ -1451,32 +1427,25 @@ void rvin_stop_streaming(struct rvin_dev *vin)
spin_lock_irqsave(&vin->qlock, flags);
}
if (!buffersFreed || vin->state != STOPPED) {
/*
* If this happens something have gone horribly wrong.
* Set state to stopped to prevent the interrupt handler
* to make things worse...
*/
vin_err(vin, "Failed stop HW, something is seriously broken\n");
vin->state = STOPPED;
}
if (rvin_capture_active(vin))
vin_err(vin, "Hardware did not stop\n");
vin->running = false;
spin_unlock_irqrestore(&vin->qlock, flags);
/* If something went wrong, free buffers with an error. */
if (!buffersFreed) {
return_unused_buffers(vin, VB2_BUF_STATE_ERROR);
for (i = 0; i < HW_BUFFER_NUM; i++) {
if (vin->buf_hw[i].buffer)
vb2_buffer_done(&vin->buf_hw[i].buffer->vb2_buf,
VB2_BUF_STATE_ERROR);
}
}
rvin_set_stream(vin, 0);
/* disable interrupts */
rvin_disable_interrupts(vin);
/* Return unprocessed buffers from hardware. */
for (unsigned int i = 0; i < HW_BUFFER_NUM; i++) {
if (vin->buf_hw[i].buffer)
vb2_buffer_done(&vin->buf_hw[i].buffer->vb2_buf,
VB2_BUF_STATE_ERROR);
}
}
static void rvin_stop_streaming_vq(struct vb2_queue *vq)
@@ -1522,8 +1491,6 @@ int rvin_dma_register(struct rvin_dev *vin, int irq)
spin_lock_init(&vin->qlock);
vin->state = STOPPED;
for (i = 0; i < HW_BUFFER_NUM; i++)
vin->buf_hw[i].buffer = NULL;
@@ -1626,7 +1593,7 @@ void rvin_set_alpha(struct rvin_dev *vin, unsigned int alpha)
vin->alpha = alpha;
if (vin->state == STOPPED)
if (!vin->running)
goto out;
switch (vin->format.pixelformat) {

View File

@@ -61,18 +61,6 @@ enum rvin_isp_id {
(((unsigned int)RVIN_CSI_MAX) > ((unsigned int)RVIN_ISP_MAX) ? \
(unsigned int)RVIN_CSI_MAX : (unsigned int)RVIN_ISP_MAX)
/**
* enum rvin_dma_state - DMA states
* @STOPPED: No operation in progress
* @RUNNING: Operation in progress have buffers
* @STOPPING: Stopping operation
*/
enum rvin_dma_state {
STOPPED = 0,
RUNNING,
STOPPING,
};
/**
* struct rvin_video_format - Data format stored in memory
* @fourcc: Pixelformat
@@ -173,11 +161,11 @@ struct rvin_info {
* @scratch: cpu address for scratch buffer
* @scratch_phys: physical address of the scratch buffer
*
* @qlock: protects @buf_hw, @buf_list, @sequence and @state
* @qlock: Protects @buf_hw, @buf_list, @sequence and @running
* @buf_hw: Keeps track of buffers given to HW slot
* @buf_list: list of queued buffers
* @sequence: V4L2 buffers sequence number
* @state: keeps track of operation state
* @running: Keeps track of if the VIN is running
*
* @is_csi: flag to mark the VIN as using a CSI-2 subdevice
* @chsel: Cached value of the current CSI-2 channel selection
@@ -220,7 +208,7 @@ struct rvin_dev {
} buf_hw[HW_BUFFER_NUM];
struct list_head buf_list;
unsigned int sequence;
enum rvin_dma_state state;
bool running;
bool is_csi;
unsigned int chsel;