diff options
author | Sungchun Kang <sungchun.kang@samsung.com> | 2011-02-07 13:59:46 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-03-22 03:54:13 -0400 |
commit | 8ec737ffccd7fab629e28427b4d0581ce62ffedd (patch) | |
tree | 5f6539a5dad7db0b78f6270e0bafdfe53111777c /drivers/media/video | |
parent | 4174ebf5ebd7a09589ff8ff3bc3246ea0a9bd356 (diff) |
[media] s5p-fimc: fix ISR and buffer handling for fimc-capture
In some cases fimc H/W did not stop although there were no output
buffers available. So the capture deactivation interrupt routine
is modified and the state of ST_CAPT_RUN is cleared only
in the LAST-IRQ call.
After LAST-IRQ is generated, H/W pointer will be skipped by 1 frame.
(reference by user manual) So, S/W pointer should be increased too.
Reviewed-by Jonghun Han <jonghun.han@samsung.com>
Signed-off-by: Sungchun Kang <sungchun.kang@samsung.com>
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-capture.c | 70 | ||||
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-core.c | 33 |
2 files changed, 45 insertions, 58 deletions
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 5159cc8a0e1c..6b6f72e4066c 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c | |||
@@ -153,40 +153,6 @@ static int fimc_isp_subdev_init(struct fimc_dev *fimc, unsigned int index) | |||
153 | return ret; | 153 | return ret; |
154 | } | 154 | } |
155 | 155 | ||
156 | /* | ||
157 | * At least one buffer on the pending_buf_q queue is required. | ||
158 | * Locking: The caller holds fimc->slock spinlock. | ||
159 | */ | ||
160 | int fimc_vid_cap_buf_queue(struct fimc_dev *fimc, | ||
161 | struct fimc_vid_buffer *fimc_vb) | ||
162 | { | ||
163 | struct fimc_vid_cap *cap = &fimc->vid_cap; | ||
164 | struct fimc_ctx *ctx = cap->ctx; | ||
165 | int ret = 0; | ||
166 | |||
167 | BUG_ON(!fimc || !fimc_vb); | ||
168 | |||
169 | ret = fimc_prepare_addr(ctx, &fimc_vb->vb, &ctx->d_frame, | ||
170 | &fimc_vb->paddr); | ||
171 | if (ret) | ||
172 | return ret; | ||
173 | |||
174 | if (test_bit(ST_CAPT_STREAM, &fimc->state)) { | ||
175 | fimc_pending_queue_add(cap, fimc_vb); | ||
176 | } else { | ||
177 | /* Setup the buffer directly for processing. */ | ||
178 | int buf_id = (cap->reqbufs_count == 1) ? -1 : cap->buf_index; | ||
179 | fimc_hw_set_output_addr(fimc, &fimc_vb->paddr, buf_id); | ||
180 | |||
181 | fimc_vb->index = cap->buf_index; | ||
182 | active_queue_add(cap, fimc_vb); | ||
183 | |||
184 | if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) | ||
185 | cap->buf_index = 0; | ||
186 | } | ||
187 | return ret; | ||
188 | } | ||
189 | |||
190 | static int fimc_stop_capture(struct fimc_dev *fimc) | 156 | static int fimc_stop_capture(struct fimc_dev *fimc) |
191 | { | 157 | { |
192 | unsigned long flags; | 158 | unsigned long flags; |
@@ -211,7 +177,7 @@ static int fimc_stop_capture(struct fimc_dev *fimc) | |||
211 | 177 | ||
212 | spin_lock_irqsave(&fimc->slock, flags); | 178 | spin_lock_irqsave(&fimc->slock, flags); |
213 | fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND | | 179 | fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND | |
214 | 1 << ST_CAPT_STREAM); | 180 | 1 << ST_CAPT_SHUT | 1 << ST_CAPT_STREAM); |
215 | 181 | ||
216 | fimc->vid_cap.active_buf_cnt = 0; | 182 | fimc->vid_cap.active_buf_cnt = 0; |
217 | 183 | ||
@@ -239,6 +205,8 @@ static int start_streaming(struct vb2_queue *q) | |||
239 | struct s5p_fimc_isp_info *isp_info; | 205 | struct s5p_fimc_isp_info *isp_info; |
240 | int ret; | 206 | int ret; |
241 | 207 | ||
208 | fimc_hw_reset(fimc); | ||
209 | |||
242 | ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1); | 210 | ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1); |
243 | if (ret && ret != -ENOIOCTLCMD) | 211 | if (ret && ret != -ENOIOCTLCMD) |
244 | return ret; | 212 | return ret; |
@@ -273,7 +241,7 @@ static int start_streaming(struct vb2_queue *q) | |||
273 | INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q); | 241 | INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q); |
274 | fimc->vid_cap.active_buf_cnt = 0; | 242 | fimc->vid_cap.active_buf_cnt = 0; |
275 | fimc->vid_cap.frame_count = 0; | 243 | fimc->vid_cap.frame_count = 0; |
276 | fimc->vid_cap.buf_index = fimc_hw_get_frame_index(fimc); | 244 | fimc->vid_cap.buf_index = 0; |
277 | 245 | ||
278 | set_bit(ST_CAPT_PEND, &fimc->state); | 246 | set_bit(ST_CAPT_PEND, &fimc->state); |
279 | 247 | ||
@@ -372,19 +340,33 @@ static void buffer_queue(struct vb2_buffer *vb) | |||
372 | = container_of(vb, struct fimc_vid_buffer, vb); | 340 | = container_of(vb, struct fimc_vid_buffer, vb); |
373 | struct fimc_vid_cap *vid_cap = &fimc->vid_cap; | 341 | struct fimc_vid_cap *vid_cap = &fimc->vid_cap; |
374 | unsigned long flags; | 342 | unsigned long flags; |
343 | int min_bufs; | ||
375 | 344 | ||
376 | spin_lock_irqsave(&fimc->slock, flags); | 345 | spin_lock_irqsave(&fimc->slock, flags); |
377 | fimc_vid_cap_buf_queue(fimc, buf); | 346 | fimc_prepare_addr(ctx, &buf->vb, &ctx->d_frame, &buf->paddr); |
347 | |||
348 | if (!test_bit(ST_CAPT_STREAM, &fimc->state) | ||
349 | && vid_cap->active_buf_cnt < FIMC_MAX_OUT_BUFS) { | ||
350 | /* Setup the buffer directly for processing. */ | ||
351 | int buf_id = (vid_cap->reqbufs_count == 1) ? -1 : | ||
352 | vid_cap->buf_index; | ||
378 | 353 | ||
379 | dbg("active_buf_cnt: %d", fimc->vid_cap.active_buf_cnt); | 354 | fimc_hw_set_output_addr(fimc, &buf->paddr, buf_id); |
355 | buf->index = vid_cap->buf_index; | ||
356 | active_queue_add(vid_cap, buf); | ||
380 | 357 | ||
381 | if (vid_cap->active_buf_cnt >= vid_cap->reqbufs_count || | 358 | if (++vid_cap->buf_index >= FIMC_MAX_OUT_BUFS) |
382 | vid_cap->active_buf_cnt >= FIMC_MAX_OUT_BUFS) { | 359 | vid_cap->buf_index = 0; |
383 | if (!test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) { | 360 | } else { |
384 | fimc_activate_capture(ctx); | 361 | fimc_pending_queue_add(vid_cap, buf); |
385 | dbg(""); | ||
386 | } | ||
387 | } | 362 | } |
363 | |||
364 | min_bufs = vid_cap->reqbufs_count > 1 ? 2 : 1; | ||
365 | |||
366 | if (vid_cap->active_buf_cnt >= min_bufs && | ||
367 | !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) | ||
368 | fimc_activate_capture(ctx); | ||
369 | |||
388 | spin_unlock_irqrestore(&fimc->slock, flags); | 370 | spin_unlock_irqrestore(&fimc->slock, flags); |
389 | } | 371 | } |
390 | 372 | ||
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index cd8a3003f1aa..fdf4270fcb62 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c | |||
@@ -327,9 +327,10 @@ static int stop_streaming(struct vb2_queue *q) | |||
327 | static void fimc_capture_handler(struct fimc_dev *fimc) | 327 | static void fimc_capture_handler(struct fimc_dev *fimc) |
328 | { | 328 | { |
329 | struct fimc_vid_cap *cap = &fimc->vid_cap; | 329 | struct fimc_vid_cap *cap = &fimc->vid_cap; |
330 | struct fimc_vid_buffer *v_buf = NULL; | 330 | struct fimc_vid_buffer *v_buf; |
331 | 331 | ||
332 | if (!list_empty(&cap->active_buf_q)) { | 332 | if (!list_empty(&cap->active_buf_q) && |
333 | test_bit(ST_CAPT_RUN, &fimc->state)) { | ||
333 | v_buf = active_queue_pop(cap); | 334 | v_buf = active_queue_pop(cap); |
334 | vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE); | 335 | vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE); |
335 | } | 336 | } |
@@ -345,9 +346,6 @@ static void fimc_capture_handler(struct fimc_dev *fimc) | |||
345 | fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index); | 346 | fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index); |
346 | v_buf->index = cap->buf_index; | 347 | v_buf->index = cap->buf_index; |
347 | 348 | ||
348 | dbg("hw ptr: %d, sw ptr: %d", | ||
349 | fimc_hw_get_frame_index(fimc), cap->buf_index); | ||
350 | |||
351 | /* Move the buffer to the capture active queue */ | 349 | /* Move the buffer to the capture active queue */ |
352 | active_queue_add(cap, v_buf); | 350 | active_queue_add(cap, v_buf); |
353 | 351 | ||
@@ -356,19 +354,25 @@ static void fimc_capture_handler(struct fimc_dev *fimc) | |||
356 | 354 | ||
357 | if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) | 355 | if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) |
358 | cap->buf_index = 0; | 356 | cap->buf_index = 0; |
357 | } | ||
358 | |||
359 | if (cap->active_buf_cnt == 0) { | ||
360 | clear_bit(ST_CAPT_RUN, &fimc->state); | ||
359 | 361 | ||
360 | } else if (test_and_clear_bit(ST_CAPT_STREAM, &fimc->state) && | 362 | if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) |
361 | cap->active_buf_cnt <= 1) { | 363 | cap->buf_index = 0; |
362 | fimc_deactivate_capture(fimc); | 364 | } else { |
365 | set_bit(ST_CAPT_RUN, &fimc->state); | ||
363 | } | 366 | } |
364 | 367 | ||
365 | dbg("frame: %d, active_buf_cnt= %d", | 368 | dbg("frame: %d, active_buf_cnt: %d", |
366 | fimc_hw_get_frame_index(fimc), cap->active_buf_cnt); | 369 | fimc_hw_get_frame_index(fimc), cap->active_buf_cnt); |
367 | } | 370 | } |
368 | 371 | ||
369 | static irqreturn_t fimc_isr(int irq, void *priv) | 372 | static irqreturn_t fimc_isr(int irq, void *priv) |
370 | { | 373 | { |
371 | struct fimc_dev *fimc = priv; | 374 | struct fimc_dev *fimc = priv; |
375 | struct fimc_vid_cap *cap = &fimc->vid_cap; | ||
372 | 376 | ||
373 | BUG_ON(!fimc); | 377 | BUG_ON(!fimc); |
374 | fimc_hw_clear_irq(fimc); | 378 | fimc_hw_clear_irq(fimc); |
@@ -396,12 +400,13 @@ static irqreturn_t fimc_isr(int irq, void *priv) | |||
396 | 400 | ||
397 | } | 401 | } |
398 | 402 | ||
399 | if (test_bit(ST_CAPT_RUN, &fimc->state)) | 403 | if (test_bit(ST_CAPT_PEND, &fimc->state)) { |
400 | fimc_capture_handler(fimc); | 404 | fimc_capture_irq_handler(fimc); |
401 | 405 | ||
402 | if (test_and_clear_bit(ST_CAPT_PEND, &fimc->state)) { | 406 | if (cap->active_buf_cnt == 1) { |
403 | set_bit(ST_CAPT_RUN, &fimc->state); | 407 | fimc_deactivate_capture(fimc); |
404 | wake_up(&fimc->irq_queue); | 408 | clear_bit(ST_CAPT_STREAM, &fimc->state); |
409 | } | ||
405 | } | 410 | } |
406 | 411 | ||
407 | isr_unlock: | 412 | isr_unlock: |