From 86d19d07beaeab12b004848968eb919c0e90baae Mon Sep 17 00:00:00 2001 From: David Cohen Date: Fri, 25 Nov 2011 15:32:20 +0200 Subject: [PATCH] [PORT FROM R2] atomisp: (re)start ISP and handle frame buffers from ISR BZ: 17272 Atomisp driver needs to manage ISP and frame buffers in low latency way to allow camera to work with high fps. This patch makes ISR to (re)start ISP whenever it's possible and handle frame buffers. Change-Id: I01b098937b9174a48bd97af216cb7b3c01b24c60 Orig-Change-Id: Id2bd9a7aa5dd4948350d442d72b9c1ca16cb0bb6 Signed-off-by: David Cohen Reviewed-on: http://android.intel.com:8080/26723 Reviewed-by: Koski, Anttu Reviewed-by: Koskinen, Ilkka Reviewed-by: Kruger, Jozef Tested-by: Koski, Anttu Reviewed-by: buildbot Tested-by: buildbot Reviewed-on: http://android.intel.com:8080/28058 Reviewed-by: Tuominen, TeemuX --- drivers/media/video/atomisp/atomisp_cmd.c | 123 +++++++++++++++------ drivers/media/video/atomisp/atomisp_v4l2.c | 1 - .../atomisp/include/atomisp/atomisp_internal.h | 2 +- 3 files changed, 93 insertions(+), 33 deletions(-) diff --git a/drivers/media/video/atomisp/atomisp_cmd.c b/drivers/media/video/atomisp/atomisp_cmd.c index e2d0159..eff4906 100644 --- a/drivers/media/video/atomisp/atomisp_cmd.c +++ b/drivers/media/video/atomisp/atomisp_cmd.c @@ -56,6 +56,9 @@ atomisp_acc_fw_free_args(struct atomisp_device *isp, struct sh_css_acc_fw *fw); static void atomisp_acc_fw_free(struct atomisp_device *isp, struct sh_css_acc_fw *fw); static int atomisp_wdt_pet_dog(struct atomisp_device *isp); +static void atomisp_buf_done(struct atomisp_device *isp, int error); +static int atomisp_start_binary(struct atomisp_device *isp); +static int atomisp_buffer_dequeue(struct atomisp_device *isp, int wait); /* * get sensor:dis71430/ov2720 related info from v4l2_subdev->priv data field. @@ -232,14 +235,13 @@ irqreturn_t atomisp_isr(int irq, void *dev) return IRQ_NONE; } - isp->irq_infos |= irq_infos; if (irq_infos & SH_CSS_IRQ_INFO_FRAME_DONE || irq_infos & SH_CSS_IRQ_INFO_START_NEXT_STAGE) { /* Wake up sleep thread for next binary */ - signal_worker = true; if (irq_infos & SH_CSS_IRQ_INFO_STATISTICS_READY) { signal_statistics = true; isp->isp3a_stat_ready = true; + irq_infos &= ~SH_CSS_IRQ_INFO_STATISTICS_READY; } if (irq_infos & SH_CSS_IRQ_INFO_FW_ACC_DONE) { signal_acceleration = true; @@ -262,6 +264,66 @@ irqreturn_t atomisp_isr(int irq, void *dev) isp->sw_contex.invalid_frame = true; /* + * Cannot handle frame from ISR when there's events from: + * - Acceleration API + * - Flash + * - CSS needs to do memory (re)allocation + */ + if (signal_acceleration || + isp->fr_status != ATOMISP_FRAME_STATUS_OK || + isp->params.num_flash_frames) + goto no_frame_done; + + if (irq_infos & (SH_CSS_IRQ_INFO_START_NEXT_STAGE | + SH_CSS_IRQ_INFO_FRAME_DONE)) { + switch (isp->sw_contex.run_mode) { + case CI_MODE_PREVIEW: + if (sh_css_preview_next_stage_needs_alloc()) + goto no_frame_done; + break; + case CI_MODE_VIDEO: + if (sh_css_video_next_stage_needs_alloc()) + goto no_frame_done; + break; + default: + goto no_frame_done; + } + } + + /* We're fine to proceed in atomic context */ + if (irq_infos & SH_CSS_IRQ_INFO_START_NEXT_STAGE) { + sh_css_start_next_stage(); + irq_infos &= ~SH_CSS_IRQ_INFO_START_NEXT_STAGE; + } + + if (irq_infos & SH_CSS_IRQ_INFO_FRAME_DONE) { + int ret; + + atomisp_buf_done(isp, 0); + + if (!isp->sw_contex.invalid_frame) { + ret = atomisp_buffer_dequeue(isp, 0); + if (ret) + /* buffer underrun? */ + goto no_frame_done; + } else { + isp->sw_contex.invalid_frame = false; + } + + ret = atomisp_start_binary(isp); + if (ret) + goto no_frame_done; + + irq_infos &= ~SH_CSS_IRQ_INFO_FRAME_DONE; + } + +no_frame_done: + signal_worker = !!(irq_infos & (SH_CSS_IRQ_INFO_START_NEXT_STAGE | + SH_CSS_IRQ_INFO_FRAME_DONE)); + + isp->irq_infos |= irq_infos; + + /* * After every iteration of acceleration there will be an interrupt * which needs priority. */ @@ -711,12 +773,13 @@ void atomisp_work(struct work_struct *work) bool timeout_flag, flash_in_progress = false, flash_enabled = false; - enum atomisp_frame_status fr_status = ATOMISP_FRAME_STATUS_OK; u32 irq_infos; + isp->fr_status = ATOMISP_FRAME_STATUS_OK; isp->sw_contex.error = false; isp->sw_contex.invalid_frame = false; INIT_COMPLETION(isp->wq_frame_complete); + isp->irq_infos = 0; for (;;) { timeout_flag = false; @@ -772,20 +835,21 @@ void atomisp_work(struct work_struct *work) /* if the previous frame was partially exposed, this one is * going to be fully exposed. */ if (flash_in_progress && - fr_status == ATOMISP_FRAME_STATUS_FLASH_PARTIAL) { + isp->fr_status == ATOMISP_FRAME_STATUS_FLASH_PARTIAL) { /* If flash is in progress and the previous frame * was partially exposed, then this frame will be * correctly exposed. */ - fr_status = ATOMISP_FRAME_STATUS_FLASH_EXPOSED; + isp->fr_status = ATOMISP_FRAME_STATUS_FLASH_EXPOSED; } else if (flash_in_progress && - fr_status == ATOMISP_FRAME_STATUS_FLASH_EXPOSED) { + isp->fr_status == + ATOMISP_FRAME_STATUS_FLASH_EXPOSED) { /* If the previous frame was flash-exposed, we assume * that some of the flash leaked into the current frame * so we tell the app not to use this frame. */ - fr_status = ATOMISP_FRAME_STATUS_FLASH_PARTIAL; + isp->fr_status = ATOMISP_FRAME_STATUS_FLASH_PARTIAL; flash_in_progress = false; } else { - fr_status = ATOMISP_FRAME_STATUS_OK; + isp->fr_status = ATOMISP_FRAME_STATUS_OK; } if (isp->params.num_flash_frames) { @@ -798,9 +862,11 @@ void atomisp_work(struct work_struct *work) * for a flash-exposed frame. */ if (ret) - fr_status = ATOMISP_FRAME_STATUS_FLASH_FAILED; + isp->fr_status = + ATOMISP_FRAME_STATUS_FLASH_FAILED; else { - fr_status = ATOMISP_FRAME_STATUS_FLASH_PARTIAL; + isp->fr_status = + ATOMISP_FRAME_STATUS_FLASH_PARTIAL; flash_in_progress = true; flash_enabled = true; } @@ -817,7 +883,9 @@ void atomisp_work(struct work_struct *work) if (!isp->irq_infos) { spin_unlock_irqrestore(&isp->irq_lock, irqflags); + mutex_unlock(&isp->isp_lock); wait_for_completion(&isp->wq_frame_complete); + mutex_lock(&isp->isp_lock); spin_lock_irqsave(&isp->irq_lock, irqflags); } @@ -847,38 +915,23 @@ void atomisp_work(struct work_struct *work) sh_css_terminate_firmware(); /* regardless of timeout or not, we disable the flash */ - if (flash_enabled && fr_status == + if (flash_enabled && isp->fr_status == ATOMISP_FRAME_STATUS_FLASH_EXPOSED) { atomisp_stop_flash(isp); /* always check the result, this clears any * errors that may have occurred. */ if (atomisp_flash_error(isp)) - fr_status = + isp->fr_status = ATOMISP_FRAME_STATUS_FLASH_FAILED; flash_enabled = false; } /* proc interrupt */ INIT_COMPLETION(isp->wq_frame_complete); - if (irq_infos & SH_CSS_IRQ_INFO_START_NEXT_STAGE) { + if (irq_infos & SH_CSS_IRQ_INFO_START_NEXT_STAGE) sh_css_start_next_stage(); - /* Getting 3A statistics if ready */ - if (isp->isp3a_stat_ready) { - mutex_lock(&isp->isp3a_lock); - ret = sh_css_get_3a_statistics - (isp->params.s3a_output_buf); - mutex_unlock(&isp->isp3a_lock); - - isp->isp3a_stat_ready = false; - if (ret != sh_css_success) - v4l2_err(&atomisp_dev, - "get 3a statistics" - " failed, not " - "enough memory.\n"); - } - } } while (!(irq_infos & SH_CSS_IRQ_INFO_FRAME_DONE)); /* @@ -907,7 +960,7 @@ void atomisp_work(struct work_struct *work) /* HACK: do we have a better way/place for it? */ if (isp->vb_capture) isp->frame_status[isp->vb_capture->i] = - fr_status; + isp->fr_status; atomisp_buf_done(isp, 0); } } @@ -1962,10 +2015,18 @@ int atomisp_3a_stat(struct atomisp_device *isp, int flag, sizeof(isp->params.curr_grid_info)) != 0) return -EAGAIN; - mutex_lock(&isp->isp3a_lock); + mutex_lock(&isp->isp_lock); + /* Getting 3A statistics if ready */ + ret = sh_css_get_3a_statistics(isp->params.s3a_output_buf); + if (ret != sh_css_success) { + v4l2_err(&atomisp_dev, "get 3a statistics failed, not " + "enough memory.\n"); + mutex_unlock(&isp->isp_lock); + return -EIO; + } ret = copy_to_user(arg->data, isp->params.s3a_output_buf, isp->params.s3a_output_bytes); - mutex_unlock(&isp->isp3a_lock); + mutex_unlock(&isp->isp_lock); if (ret) { v4l2_err(&atomisp_dev, "copy to user failed: copied %lu bytes\n", ret); diff --git a/drivers/media/video/atomisp/atomisp_v4l2.c b/drivers/media/video/atomisp/atomisp_v4l2.c index 62cbf1b..8c45866 100644 --- a/drivers/media/video/atomisp/atomisp_v4l2.c +++ b/drivers/media/video/atomisp/atomisp_v4l2.c @@ -835,7 +835,6 @@ static int __devinit atomisp_pci_probe(struct pci_dev *dev, mutex_init(&isp->input_lock); /* isp_lock is to protect race access of css functions */ mutex_init(&isp->isp_lock); - mutex_init(&isp->isp3a_lock); isp->sw_contex.updating_uptr = false; isp->isp3a_stat_ready = false; diff --git a/drivers/media/video/atomisp/include/atomisp/atomisp_internal.h b/drivers/media/video/atomisp/include/atomisp/atomisp_internal.h index 2e779ac..ba991b3 100644 --- a/drivers/media/video/atomisp/include/atomisp/atomisp_internal.h +++ b/drivers/media/video/atomisp/include/atomisp/atomisp_internal.h @@ -265,7 +265,6 @@ struct atomisp_device { uint32_t irq_infos; struct mutex input_lock; struct mutex isp_lock; - struct mutex isp3a_lock; struct atomisp_tvnorm *tvnorm; bool isp3a_stat_ready; @@ -295,6 +294,7 @@ struct atomisp_device { bool isp_timeout; int timeout_cnt; enum atomisp_wdt_status wdt_status; + enum atomisp_frame_status fr_status; struct videobuf_buffer *vb_capture; struct videobuf_buffer *vb_preview; -- 2.7.4