Loading Documentation/devicetree/bindings/media/video/msm-fd.txt +27 −2 Original line number Diff line number Diff line Loading @@ -16,7 +16,9 @@ Required properties: - "fd_core" - FD CORE hardware register set. - "fd_misc" - FD MISC hardware register set. - "fd_vbif" - FD VBIF hardware register set. - interrupts: should contain the fd interrupts. - interrupts: should contain the fd interrupts. From fd cores with revisions 0x10010000 and higher, power collapse sequence is required. Face detection wrapper irq is needed to perform power collapse. - interrupt-names: should specify relevant names to each interrupts property defined. - vdd-supply: phandle to GDSC regulator controlling face detection hw. Loading @@ -33,7 +35,7 @@ Optional properties: If we want to have different operating clock frequencies we can define rate levels. They should be defined in incremental order. Example: Example revisions 0x10000000..0x10010000: qcom,fd@fd878000 { compatible = "qcom,face-detection"; Loading @@ -54,3 +56,26 @@ Example: <200000000 200000000 150000000 40000000>, <400000000 400000000 333000000 80000000>; }; Example revision 0x10010000 and above: qcom,fd@fd878000 { compatible = "qcom,face-detection"; reg = <0xfd878000 0x800>, <0xfd87c000 0x800>, <0xfd860000 0x1000>; reg-names = "fd_core", "fd_misc", "fd_vbif"; interrupts = <0 316 0>; interrupt-names = "fd"; vdd-supply = <&gdsc_fd>; clocks = <&clock_mmss clk_fd_core_clk>, <&clock_mmss clk_fd_core_uar_clk>, <&clock_mmss clk_fd_axi_clk>, <&clock_mmss clk_fd_ahb_clk>; clock-names = "fd_core_clk", "fd_core_uar_clk", "fd_axi_clk", "fd_ahb_clk"; clock-rates = <60000000 60000000 75000000 40000000>, <200000000 200000000 150000000 40000000>, <400000000 400000000 333000000 80000000>; }; drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c +16 −42 Original line number Diff line number Diff line Loading @@ -1193,23 +1193,6 @@ static void msm_fd_wq_handler(struct work_struct *work) msm_fd_hw_buffer_done(fd, active_buf); } /* * msm_fd_irq - Fd device irq handler. * @irq: Pointer to work struct. * @dev_id: Pointer to fd device. */ static irqreturn_t msm_fd_irq(int irq, void *dev_id) { struct msm_fd_device *fd = dev_id; if (msm_fd_hw_is_finished(fd)) queue_work(fd->work_queue, &fd->work); else dev_err(fd->dev, "Something wrong! FD still running\n"); return IRQ_HANDLED; } /* * fd_probe - Fd device probe method. * @pdev: Pointer fd platform device. Loading @@ -1226,6 +1209,8 @@ static int fd_probe(struct platform_device *pdev) mutex_init(&fd->lock); spin_lock_init(&fd->slock); init_completion(&fd->hw_halt_completion); INIT_LIST_HEAD(&fd->buf_queue); fd->dev = &pdev->dev; /* Get resources */ Loading Loading @@ -1255,29 +1240,21 @@ static int fd_probe(struct platform_device *pdev) goto error_iommu_get; } fd->irq_num = platform_get_irq(pdev, 0); if (fd->irq_num < 0) { dev_err(&pdev->dev, "Can not get fd irq resource\n"); ret = -ENODEV; goto error_irq_request; /* Get face detect hw before read engine revision */ ret = msm_fd_hw_get(fd, 0); if (ret < 0) { dev_err(&pdev->dev, "Fail to get hw\n"); goto error_iommu_get; } fd->hw_revision = msm_fd_hw_get_revision(fd); ret = devm_request_irq(&pdev->dev, fd->irq_num, msm_fd_irq, IRQF_TRIGGER_RISING, dev_name(&pdev->dev), fd); if (ret) { dev_err(&pdev->dev, "Can not claim IRQ %d\n", fd->irq_num); goto error_irq_request; } msm_fd_hw_put(fd); fd->work_queue = alloc_workqueue(MSM_FD_DRV_NAME, WQ_HIGHPRI | WQ_NON_REENTRANT | WQ_UNBOUND, 0); if (!fd->work_queue) { dev_err(&pdev->dev, "Can not register workqueue\n"); ret = -ENOMEM; goto error_alloc_workqueue; ret = msm_fd_hw_request_irq(pdev, fd, msm_fd_wq_handler); if (ret < 0) { dev_err(&pdev->dev, "Fail request irq\n"); goto error_request_irq; } INIT_WORK(&fd->work, msm_fd_wq_handler); INIT_LIST_HEAD(&fd->buf_queue); /* v4l2 device */ ret = v4l2_device_register(&pdev->dev, &fd->v4l2_dev); Loading Loading @@ -1311,10 +1288,8 @@ static int fd_probe(struct platform_device *pdev) error_video_register: v4l2_device_unregister(&fd->v4l2_dev); error_v4l2_register: destroy_workqueue(fd->work_queue); error_alloc_workqueue: devm_free_irq(&pdev->dev, fd->irq_num, fd); error_irq_request: msm_fd_hw_release_irq(fd); error_request_irq: msm_fd_hw_put_iommu(fd); error_iommu_get: msm_fd_hw_put_clocks(fd); Loading @@ -1341,9 +1316,8 @@ static int fd_device_remove(struct platform_device *pdev) return 0; } video_unregister_device(&fd->video); destroy_workqueue(fd->work_queue); v4l2_device_unregister(&fd->v4l2_dev); devm_free_irq(&pdev->dev, fd->irq_num, fd); msm_fd_hw_release_irq(fd); msm_fd_hw_put_iommu(fd); msm_fd_hw_put_clocks(fd); regulator_put(fd->vdd); Loading drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h +9 −3 Original line number Diff line number Diff line Loading @@ -144,7 +144,6 @@ struct msm_fd_stats { * @mem_pool: FD hw memory pool. * @stats: Pointer to statistic buffers. * @work_buf: Working memory buffer handle. * @wait_stop_stream: Pointer to completion to wait on stop stream. */ struct fd_ctx { struct msm_fd_device *fd_device; Loading @@ -157,7 +156,6 @@ struct fd_ctx { struct msm_fd_mem_pool mem_pool; struct msm_fd_stats *stats; struct msm_fd_buf_handle work_buf; struct completion *wait_stop_stream; }; /* Loading Loading @@ -187,8 +185,11 @@ enum msm_fd_mem_resources { /* * struct msm_fd_device - FD device structure. * @hw_revision: Face detection hw revision. * @lock: Lock used for reference count. * @slock: Spinlock used to protect FD device struct. * @core_irq_num: Face detection core irq number. * wrap_irq_num: Face detection wrapper irq number. * @ref_count: Device reference count. * @res_mem: Array of memory resources used by FD device. * @iomem_base: Array of register mappings used by FD device. Loading @@ -208,13 +209,17 @@ enum msm_fd_mem_resources { * @buf_queue: FD device processing queue. * @work_queue: Pointer to FD device IRQ bottom half workqueue. * @work: IRQ bottom half work struct. * @hw_halt_completion: Completes when face detection hw halt completes. */ struct msm_fd_device { u32 hw_revision; struct mutex lock; spinlock_t slock; int ref_count; int irq_num; int core_irq_num; int wrap_irq_num; struct resource *res_mem[MSM_FD_IOMEM_LAST]; void __iomem *iomem_base[MSM_FD_IOMEM_LAST]; struct resource *ioarea[MSM_FD_IOMEM_LAST]; Loading @@ -240,6 +245,7 @@ struct msm_fd_device { struct list_head buf_queue; struct workqueue_struct *work_queue; struct work_struct work; struct completion hw_halt_completion; }; #endif /* __MSM_FD_DEV_H__ */ drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c +208 −3 Original line number Diff line number Diff line Loading @@ -29,8 +29,14 @@ #include "msm_fd_hw.h" #include "msm_fd_regs.h" /* After which revision halt for engine is needed */ #define MSM_FD_HALT_FROM_REV 0x10010000 /* Face detection workqueue name */ #define MSM_FD_WORQUEUE_NAME "face-detection" /* Face detection processing timeout in ms */ #define MSM_FD_PROCESSING_TIMEOUT_MS 500 /* Face detection halt timeout in ms */ #define MSM_FD_HALT_TIMEOUT_MS 100 /* Fd iommu partition definition */ static struct msm_iova_partition msm_fd_fw_partition = { Loading Loading @@ -292,7 +298,7 @@ static inline void msm_fd_hw_run(struct msm_fd_device *fd) * * NOTE: If finish bit is not set, we should not read the result. */ int msm_fd_hw_is_finished(struct msm_fd_device *fd) static int msm_fd_hw_is_finished(struct msm_fd_device *fd) { u32 reg; Loading @@ -305,7 +311,7 @@ int msm_fd_hw_is_finished(struct msm_fd_device *fd) * msm_fd_hw_is_runnig - Check if fd hw engine is busy. * @fd: Pointer to fd device. */ int msm_fd_hw_is_runnig(struct msm_fd_device *fd) static int msm_fd_hw_is_runnig(struct msm_fd_device *fd) { u32 reg; Loading @@ -314,6 +320,46 @@ int msm_fd_hw_is_runnig(struct msm_fd_device *fd) return reg & MSM_FD_CONTROL_RUN; } /* * msm_fd_hw_misc_irq_is_halt - Check if fd received misc halt irq. * @fd: Pointer to fd device. */ static int msm_fd_hw_misc_irq_is_halt(struct msm_fd_device *fd) { u32 reg; reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_MISC, MSM_FD_MISC_IRQ_STATUS); return reg & MSM_FD_MISC_IRQ_STATUS_HALT_REQ; } /* * msm_fd_hw_misc_clear_all_irq - Clear all misc irq statuses. * @fd: Pointer to fd device. */ static void msm_fd_hw_misc_clear_all_irq(struct msm_fd_device *fd) { msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_MISC, MSM_FD_MISC_IRQ_CLEAR, MSM_FD_MISC_IRQ_CLEAR_HALT | MSM_FD_MISC_IRQ_CLEAR_CORE); } /* * msm_fd_hw_get_revision - Get hw revision and store in to device. * @fd: Pointer to fd device. */ int msm_fd_hw_get_revision(struct msm_fd_device *fd) { u32 reg; reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_MISC, MSM_FD_MISC_HW_VERSION); dev_dbg(fd->dev, "Face detection hw revision 0x%x\n", reg); return reg; } /* * msm_fd_hw_get_result_x - Get fd result center x coordinate. * @fd: Pointer to fd device. Loading Loading @@ -404,13 +450,171 @@ void msm_fd_hw_get_result_angle_pose(struct msm_fd_device *fd, int idx, } } /* * msm_fd_hw_halt_needed - Check if fd core halt is needed. * @fd: Pointer to fd device. */ static int msm_fd_hw_halt_needed(struct msm_fd_device *fd) { return fd->hw_revision >= MSM_FD_HALT_FROM_REV; } /* * msm_fd_hw_halt - Halt fd core. * @fd: Pointer to fd device. */ static void msm_fd_hw_halt(struct msm_fd_device *fd) { unsigned long time; if (msm_fd_hw_halt_needed(fd)) { init_completion(&fd->hw_halt_completion); msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_MISC, MSM_FD_HW_STOP, 1); time = wait_for_completion_timeout(&fd->hw_halt_completion, msecs_to_jiffies(MSM_FD_HALT_TIMEOUT_MS)); if (!time) dev_err(fd->dev, "Face detection halt timeout\n"); } } /* * msm_fd_hw_misc_irq_needed - Check if misc irq is needed * @fd: Pointer to fd device. */ static int msm_fd_hw_misc_irq_needed(struct msm_fd_device *fd) { return msm_fd_hw_halt_needed(fd); } /* * msm_fd_core_irq - Face detection core irq handler. * @irq: Irq number. * @dev_id: Pointer to fd device. */ static irqreturn_t msm_fd_hw_core_irq(int irq, void *dev_id) { struct msm_fd_device *fd = dev_id; if (msm_fd_hw_is_finished(fd)) queue_work(fd->work_queue, &fd->work); else dev_err(fd->dev, "Something wrong! FD still running\n"); return IRQ_HANDLED; } /* * msm_fd_wrap_irq - Face detection wrapper irq handler. * @irq: Irq number. * @dev_id: Pointer to fd device. */ static irqreturn_t msm_fd_hw_wrap_irq(int irq, void *dev_id) { struct msm_fd_device *fd = dev_id; if (msm_fd_hw_misc_irq_is_halt(fd)) complete_all(&fd->hw_halt_completion); msm_fd_hw_misc_clear_all_irq(fd); return IRQ_HANDLED; } /* * msm_fd_hw_request_irq - Configure and enable vbif interface. * @pdev: Pointer to platform device. * @fd: Pointer to fd device. * @work_func: Pointer to work func used for irq bottom half. */ int msm_fd_hw_request_irq(struct platform_device *pdev, struct msm_fd_device *fd, work_func_t work_func) { int ret; fd->core_irq_num = platform_get_irq(pdev, 0); if (fd->core_irq_num < 0) { dev_err(fd->dev, "Can not get fd core irq resource\n"); ret = -ENODEV; goto error_core_irq; } ret = devm_request_irq(fd->dev, fd->core_irq_num, msm_fd_hw_core_irq, IRQF_TRIGGER_RISING, dev_name(fd->dev), fd); if (ret) { dev_err(&pdev->dev, "Can not claim core IRQ %d\n", fd->core_irq_num); goto error_core_irq; } /* If vbif is shared we will need wrapper irq for releasing vbif */ fd->core_irq_num = -1; if (msm_fd_hw_misc_irq_needed(fd)) { fd->wrap_irq_num = platform_get_irq(pdev, 1); if (fd->core_irq_num < 0) { dev_err(fd->dev, "Can not get fd wrap irq resource\n"); ret = -ENODEV; goto error_wrap_irq; } ret = devm_request_irq(fd->dev, fd->wrap_irq_num, msm_fd_hw_wrap_irq, IRQF_TRIGGER_RISING, dev_name(&pdev->dev), fd); if (ret) { dev_err(fd->dev, "Can not claim wrapper IRQ %d\n", fd->wrap_irq_num); goto error_wrap_irq; } } fd->work_queue = alloc_workqueue(MSM_FD_WORQUEUE_NAME, WQ_HIGHPRI | WQ_NON_REENTRANT | WQ_UNBOUND, 0); if (!fd->work_queue) { dev_err(fd->dev, "Can not register workqueue\n"); ret = -ENOMEM; goto error_alloc_workqueue; } INIT_WORK(&fd->work, work_func); return 0; error_alloc_workqueue: if (fd->wrap_irq_num >= 0) devm_free_irq(fd->dev, fd->wrap_irq_num, fd); error_wrap_irq: devm_free_irq(&pdev->dev, fd->core_irq_num, fd); error_core_irq: return ret; } /* * msm_fd_hw_release_irq - Free core and wrap irq. * @fd: Pointer to fd device. */ void msm_fd_hw_release_irq(struct msm_fd_device *fd) { if (fd->core_irq_num >= 0) { devm_free_irq(fd->dev, fd->core_irq_num, fd); fd->core_irq_num = -1; } if (fd->wrap_irq_num >= 0) { devm_free_irq(fd->dev, fd->wrap_irq_num, fd); fd->wrap_irq_num = -1; } if (fd->work_queue) { destroy_workqueue(fd->work_queue); fd->work_queue = NULL; } } /* * msm_fd_hw_vbif_register - Configure and enable vbif interface. * @fd: Pointer to fd device. */ void msm_fd_hw_vbif_register(struct msm_fd_device *fd) { msm_fd_hw_reg_set(fd, MSM_FD_IOMEM_VBIF, MSM_FD_VBIF_CLKON, 0x1); Loading Loading @@ -854,6 +1058,7 @@ void msm_fd_hw_put(struct msm_fd_device *fd) BUG_ON(fd->ref_count == 0); if (--fd->ref_count == 0) { msm_fd_hw_halt(fd); msm_fd_hw_vbif_unregister(fd); msm_fd_hw_bus_release(fd); msm_fd_hw_disable_clocks(fd); Loading drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.h +7 −2 Original line number Diff line number Diff line Loading @@ -15,8 +15,6 @@ #include "msm_fd_dev.h" int msm_fd_hw_is_finished(struct msm_fd_device *fd); int msm_fd_hw_get_face_count(struct msm_fd_device *fd); int msm_fd_hw_get_result_x(struct msm_fd_device *fd, int idx); Loading @@ -29,6 +27,13 @@ void msm_fd_hw_get_result_conf_size(struct msm_fd_device *fd, void msm_fd_hw_get_result_angle_pose(struct msm_fd_device *fd, int idx, u32 *angle, u32 *pose); int msm_fd_hw_request_irq(struct platform_device *pdev, struct msm_fd_device *fd, work_func_t work_func); void msm_fd_hw_release_irq(struct msm_fd_device *fd); int msm_fd_hw_get_revision(struct msm_fd_device *fd); void msm_fd_hw_release_mem_resources(struct msm_fd_device *fd); int msm_fd_hw_get_mem_resources(struct platform_device *pdev, Loading Loading
Documentation/devicetree/bindings/media/video/msm-fd.txt +27 −2 Original line number Diff line number Diff line Loading @@ -16,7 +16,9 @@ Required properties: - "fd_core" - FD CORE hardware register set. - "fd_misc" - FD MISC hardware register set. - "fd_vbif" - FD VBIF hardware register set. - interrupts: should contain the fd interrupts. - interrupts: should contain the fd interrupts. From fd cores with revisions 0x10010000 and higher, power collapse sequence is required. Face detection wrapper irq is needed to perform power collapse. - interrupt-names: should specify relevant names to each interrupts property defined. - vdd-supply: phandle to GDSC regulator controlling face detection hw. Loading @@ -33,7 +35,7 @@ Optional properties: If we want to have different operating clock frequencies we can define rate levels. They should be defined in incremental order. Example: Example revisions 0x10000000..0x10010000: qcom,fd@fd878000 { compatible = "qcom,face-detection"; Loading @@ -54,3 +56,26 @@ Example: <200000000 200000000 150000000 40000000>, <400000000 400000000 333000000 80000000>; }; Example revision 0x10010000 and above: qcom,fd@fd878000 { compatible = "qcom,face-detection"; reg = <0xfd878000 0x800>, <0xfd87c000 0x800>, <0xfd860000 0x1000>; reg-names = "fd_core", "fd_misc", "fd_vbif"; interrupts = <0 316 0>; interrupt-names = "fd"; vdd-supply = <&gdsc_fd>; clocks = <&clock_mmss clk_fd_core_clk>, <&clock_mmss clk_fd_core_uar_clk>, <&clock_mmss clk_fd_axi_clk>, <&clock_mmss clk_fd_ahb_clk>; clock-names = "fd_core_clk", "fd_core_uar_clk", "fd_axi_clk", "fd_ahb_clk"; clock-rates = <60000000 60000000 75000000 40000000>, <200000000 200000000 150000000 40000000>, <400000000 400000000 333000000 80000000>; };
drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c +16 −42 Original line number Diff line number Diff line Loading @@ -1193,23 +1193,6 @@ static void msm_fd_wq_handler(struct work_struct *work) msm_fd_hw_buffer_done(fd, active_buf); } /* * msm_fd_irq - Fd device irq handler. * @irq: Pointer to work struct. * @dev_id: Pointer to fd device. */ static irqreturn_t msm_fd_irq(int irq, void *dev_id) { struct msm_fd_device *fd = dev_id; if (msm_fd_hw_is_finished(fd)) queue_work(fd->work_queue, &fd->work); else dev_err(fd->dev, "Something wrong! FD still running\n"); return IRQ_HANDLED; } /* * fd_probe - Fd device probe method. * @pdev: Pointer fd platform device. Loading @@ -1226,6 +1209,8 @@ static int fd_probe(struct platform_device *pdev) mutex_init(&fd->lock); spin_lock_init(&fd->slock); init_completion(&fd->hw_halt_completion); INIT_LIST_HEAD(&fd->buf_queue); fd->dev = &pdev->dev; /* Get resources */ Loading Loading @@ -1255,29 +1240,21 @@ static int fd_probe(struct platform_device *pdev) goto error_iommu_get; } fd->irq_num = platform_get_irq(pdev, 0); if (fd->irq_num < 0) { dev_err(&pdev->dev, "Can not get fd irq resource\n"); ret = -ENODEV; goto error_irq_request; /* Get face detect hw before read engine revision */ ret = msm_fd_hw_get(fd, 0); if (ret < 0) { dev_err(&pdev->dev, "Fail to get hw\n"); goto error_iommu_get; } fd->hw_revision = msm_fd_hw_get_revision(fd); ret = devm_request_irq(&pdev->dev, fd->irq_num, msm_fd_irq, IRQF_TRIGGER_RISING, dev_name(&pdev->dev), fd); if (ret) { dev_err(&pdev->dev, "Can not claim IRQ %d\n", fd->irq_num); goto error_irq_request; } msm_fd_hw_put(fd); fd->work_queue = alloc_workqueue(MSM_FD_DRV_NAME, WQ_HIGHPRI | WQ_NON_REENTRANT | WQ_UNBOUND, 0); if (!fd->work_queue) { dev_err(&pdev->dev, "Can not register workqueue\n"); ret = -ENOMEM; goto error_alloc_workqueue; ret = msm_fd_hw_request_irq(pdev, fd, msm_fd_wq_handler); if (ret < 0) { dev_err(&pdev->dev, "Fail request irq\n"); goto error_request_irq; } INIT_WORK(&fd->work, msm_fd_wq_handler); INIT_LIST_HEAD(&fd->buf_queue); /* v4l2 device */ ret = v4l2_device_register(&pdev->dev, &fd->v4l2_dev); Loading Loading @@ -1311,10 +1288,8 @@ static int fd_probe(struct platform_device *pdev) error_video_register: v4l2_device_unregister(&fd->v4l2_dev); error_v4l2_register: destroy_workqueue(fd->work_queue); error_alloc_workqueue: devm_free_irq(&pdev->dev, fd->irq_num, fd); error_irq_request: msm_fd_hw_release_irq(fd); error_request_irq: msm_fd_hw_put_iommu(fd); error_iommu_get: msm_fd_hw_put_clocks(fd); Loading @@ -1341,9 +1316,8 @@ static int fd_device_remove(struct platform_device *pdev) return 0; } video_unregister_device(&fd->video); destroy_workqueue(fd->work_queue); v4l2_device_unregister(&fd->v4l2_dev); devm_free_irq(&pdev->dev, fd->irq_num, fd); msm_fd_hw_release_irq(fd); msm_fd_hw_put_iommu(fd); msm_fd_hw_put_clocks(fd); regulator_put(fd->vdd); Loading
drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.h +9 −3 Original line number Diff line number Diff line Loading @@ -144,7 +144,6 @@ struct msm_fd_stats { * @mem_pool: FD hw memory pool. * @stats: Pointer to statistic buffers. * @work_buf: Working memory buffer handle. * @wait_stop_stream: Pointer to completion to wait on stop stream. */ struct fd_ctx { struct msm_fd_device *fd_device; Loading @@ -157,7 +156,6 @@ struct fd_ctx { struct msm_fd_mem_pool mem_pool; struct msm_fd_stats *stats; struct msm_fd_buf_handle work_buf; struct completion *wait_stop_stream; }; /* Loading Loading @@ -187,8 +185,11 @@ enum msm_fd_mem_resources { /* * struct msm_fd_device - FD device structure. * @hw_revision: Face detection hw revision. * @lock: Lock used for reference count. * @slock: Spinlock used to protect FD device struct. * @core_irq_num: Face detection core irq number. * wrap_irq_num: Face detection wrapper irq number. * @ref_count: Device reference count. * @res_mem: Array of memory resources used by FD device. * @iomem_base: Array of register mappings used by FD device. Loading @@ -208,13 +209,17 @@ enum msm_fd_mem_resources { * @buf_queue: FD device processing queue. * @work_queue: Pointer to FD device IRQ bottom half workqueue. * @work: IRQ bottom half work struct. * @hw_halt_completion: Completes when face detection hw halt completes. */ struct msm_fd_device { u32 hw_revision; struct mutex lock; spinlock_t slock; int ref_count; int irq_num; int core_irq_num; int wrap_irq_num; struct resource *res_mem[MSM_FD_IOMEM_LAST]; void __iomem *iomem_base[MSM_FD_IOMEM_LAST]; struct resource *ioarea[MSM_FD_IOMEM_LAST]; Loading @@ -240,6 +245,7 @@ struct msm_fd_device { struct list_head buf_queue; struct workqueue_struct *work_queue; struct work_struct work; struct completion hw_halt_completion; }; #endif /* __MSM_FD_DEV_H__ */
drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.c +208 −3 Original line number Diff line number Diff line Loading @@ -29,8 +29,14 @@ #include "msm_fd_hw.h" #include "msm_fd_regs.h" /* After which revision halt for engine is needed */ #define MSM_FD_HALT_FROM_REV 0x10010000 /* Face detection workqueue name */ #define MSM_FD_WORQUEUE_NAME "face-detection" /* Face detection processing timeout in ms */ #define MSM_FD_PROCESSING_TIMEOUT_MS 500 /* Face detection halt timeout in ms */ #define MSM_FD_HALT_TIMEOUT_MS 100 /* Fd iommu partition definition */ static struct msm_iova_partition msm_fd_fw_partition = { Loading Loading @@ -292,7 +298,7 @@ static inline void msm_fd_hw_run(struct msm_fd_device *fd) * * NOTE: If finish bit is not set, we should not read the result. */ int msm_fd_hw_is_finished(struct msm_fd_device *fd) static int msm_fd_hw_is_finished(struct msm_fd_device *fd) { u32 reg; Loading @@ -305,7 +311,7 @@ int msm_fd_hw_is_finished(struct msm_fd_device *fd) * msm_fd_hw_is_runnig - Check if fd hw engine is busy. * @fd: Pointer to fd device. */ int msm_fd_hw_is_runnig(struct msm_fd_device *fd) static int msm_fd_hw_is_runnig(struct msm_fd_device *fd) { u32 reg; Loading @@ -314,6 +320,46 @@ int msm_fd_hw_is_runnig(struct msm_fd_device *fd) return reg & MSM_FD_CONTROL_RUN; } /* * msm_fd_hw_misc_irq_is_halt - Check if fd received misc halt irq. * @fd: Pointer to fd device. */ static int msm_fd_hw_misc_irq_is_halt(struct msm_fd_device *fd) { u32 reg; reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_MISC, MSM_FD_MISC_IRQ_STATUS); return reg & MSM_FD_MISC_IRQ_STATUS_HALT_REQ; } /* * msm_fd_hw_misc_clear_all_irq - Clear all misc irq statuses. * @fd: Pointer to fd device. */ static void msm_fd_hw_misc_clear_all_irq(struct msm_fd_device *fd) { msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_MISC, MSM_FD_MISC_IRQ_CLEAR, MSM_FD_MISC_IRQ_CLEAR_HALT | MSM_FD_MISC_IRQ_CLEAR_CORE); } /* * msm_fd_hw_get_revision - Get hw revision and store in to device. * @fd: Pointer to fd device. */ int msm_fd_hw_get_revision(struct msm_fd_device *fd) { u32 reg; reg = msm_fd_hw_read_reg(fd, MSM_FD_IOMEM_MISC, MSM_FD_MISC_HW_VERSION); dev_dbg(fd->dev, "Face detection hw revision 0x%x\n", reg); return reg; } /* * msm_fd_hw_get_result_x - Get fd result center x coordinate. * @fd: Pointer to fd device. Loading Loading @@ -404,13 +450,171 @@ void msm_fd_hw_get_result_angle_pose(struct msm_fd_device *fd, int idx, } } /* * msm_fd_hw_halt_needed - Check if fd core halt is needed. * @fd: Pointer to fd device. */ static int msm_fd_hw_halt_needed(struct msm_fd_device *fd) { return fd->hw_revision >= MSM_FD_HALT_FROM_REV; } /* * msm_fd_hw_halt - Halt fd core. * @fd: Pointer to fd device. */ static void msm_fd_hw_halt(struct msm_fd_device *fd) { unsigned long time; if (msm_fd_hw_halt_needed(fd)) { init_completion(&fd->hw_halt_completion); msm_fd_hw_write_reg(fd, MSM_FD_IOMEM_MISC, MSM_FD_HW_STOP, 1); time = wait_for_completion_timeout(&fd->hw_halt_completion, msecs_to_jiffies(MSM_FD_HALT_TIMEOUT_MS)); if (!time) dev_err(fd->dev, "Face detection halt timeout\n"); } } /* * msm_fd_hw_misc_irq_needed - Check if misc irq is needed * @fd: Pointer to fd device. */ static int msm_fd_hw_misc_irq_needed(struct msm_fd_device *fd) { return msm_fd_hw_halt_needed(fd); } /* * msm_fd_core_irq - Face detection core irq handler. * @irq: Irq number. * @dev_id: Pointer to fd device. */ static irqreturn_t msm_fd_hw_core_irq(int irq, void *dev_id) { struct msm_fd_device *fd = dev_id; if (msm_fd_hw_is_finished(fd)) queue_work(fd->work_queue, &fd->work); else dev_err(fd->dev, "Something wrong! FD still running\n"); return IRQ_HANDLED; } /* * msm_fd_wrap_irq - Face detection wrapper irq handler. * @irq: Irq number. * @dev_id: Pointer to fd device. */ static irqreturn_t msm_fd_hw_wrap_irq(int irq, void *dev_id) { struct msm_fd_device *fd = dev_id; if (msm_fd_hw_misc_irq_is_halt(fd)) complete_all(&fd->hw_halt_completion); msm_fd_hw_misc_clear_all_irq(fd); return IRQ_HANDLED; } /* * msm_fd_hw_request_irq - Configure and enable vbif interface. * @pdev: Pointer to platform device. * @fd: Pointer to fd device. * @work_func: Pointer to work func used for irq bottom half. */ int msm_fd_hw_request_irq(struct platform_device *pdev, struct msm_fd_device *fd, work_func_t work_func) { int ret; fd->core_irq_num = platform_get_irq(pdev, 0); if (fd->core_irq_num < 0) { dev_err(fd->dev, "Can not get fd core irq resource\n"); ret = -ENODEV; goto error_core_irq; } ret = devm_request_irq(fd->dev, fd->core_irq_num, msm_fd_hw_core_irq, IRQF_TRIGGER_RISING, dev_name(fd->dev), fd); if (ret) { dev_err(&pdev->dev, "Can not claim core IRQ %d\n", fd->core_irq_num); goto error_core_irq; } /* If vbif is shared we will need wrapper irq for releasing vbif */ fd->core_irq_num = -1; if (msm_fd_hw_misc_irq_needed(fd)) { fd->wrap_irq_num = platform_get_irq(pdev, 1); if (fd->core_irq_num < 0) { dev_err(fd->dev, "Can not get fd wrap irq resource\n"); ret = -ENODEV; goto error_wrap_irq; } ret = devm_request_irq(fd->dev, fd->wrap_irq_num, msm_fd_hw_wrap_irq, IRQF_TRIGGER_RISING, dev_name(&pdev->dev), fd); if (ret) { dev_err(fd->dev, "Can not claim wrapper IRQ %d\n", fd->wrap_irq_num); goto error_wrap_irq; } } fd->work_queue = alloc_workqueue(MSM_FD_WORQUEUE_NAME, WQ_HIGHPRI | WQ_NON_REENTRANT | WQ_UNBOUND, 0); if (!fd->work_queue) { dev_err(fd->dev, "Can not register workqueue\n"); ret = -ENOMEM; goto error_alloc_workqueue; } INIT_WORK(&fd->work, work_func); return 0; error_alloc_workqueue: if (fd->wrap_irq_num >= 0) devm_free_irq(fd->dev, fd->wrap_irq_num, fd); error_wrap_irq: devm_free_irq(&pdev->dev, fd->core_irq_num, fd); error_core_irq: return ret; } /* * msm_fd_hw_release_irq - Free core and wrap irq. * @fd: Pointer to fd device. */ void msm_fd_hw_release_irq(struct msm_fd_device *fd) { if (fd->core_irq_num >= 0) { devm_free_irq(fd->dev, fd->core_irq_num, fd); fd->core_irq_num = -1; } if (fd->wrap_irq_num >= 0) { devm_free_irq(fd->dev, fd->wrap_irq_num, fd); fd->wrap_irq_num = -1; } if (fd->work_queue) { destroy_workqueue(fd->work_queue); fd->work_queue = NULL; } } /* * msm_fd_hw_vbif_register - Configure and enable vbif interface. * @fd: Pointer to fd device. */ void msm_fd_hw_vbif_register(struct msm_fd_device *fd) { msm_fd_hw_reg_set(fd, MSM_FD_IOMEM_VBIF, MSM_FD_VBIF_CLKON, 0x1); Loading Loading @@ -854,6 +1058,7 @@ void msm_fd_hw_put(struct msm_fd_device *fd) BUG_ON(fd->ref_count == 0); if (--fd->ref_count == 0) { msm_fd_hw_halt(fd); msm_fd_hw_vbif_unregister(fd); msm_fd_hw_bus_release(fd); msm_fd_hw_disable_clocks(fd); Loading
drivers/media/platform/msm/camera_v2/fd/msm_fd_hw.h +7 −2 Original line number Diff line number Diff line Loading @@ -15,8 +15,6 @@ #include "msm_fd_dev.h" int msm_fd_hw_is_finished(struct msm_fd_device *fd); int msm_fd_hw_get_face_count(struct msm_fd_device *fd); int msm_fd_hw_get_result_x(struct msm_fd_device *fd, int idx); Loading @@ -29,6 +27,13 @@ void msm_fd_hw_get_result_conf_size(struct msm_fd_device *fd, void msm_fd_hw_get_result_angle_pose(struct msm_fd_device *fd, int idx, u32 *angle, u32 *pose); int msm_fd_hw_request_irq(struct platform_device *pdev, struct msm_fd_device *fd, work_func_t work_func); void msm_fd_hw_release_irq(struct msm_fd_device *fd); int msm_fd_hw_get_revision(struct msm_fd_device *fd); void msm_fd_hw_release_mem_resources(struct msm_fd_device *fd); int msm_fd_hw_get_mem_resources(struct platform_device *pdev, Loading