mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-09 14:56:54 -04:00
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:
committed by
Hans Verkuil
parent
25482a986e
commit
c1eefe88c3
@@ -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;
|
||||
|
||||
/*
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user