Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 641f783e authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: face detect: add shared vbif power collapse sequence"

parents 86fcef65 b333ad00
Loading
Loading
Loading
Loading
+27 −2
Original line number Diff line number Diff line
@@ -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.
@@ -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";
@@ -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>;
   };
+16 −42
Original line number Diff line number Diff line
@@ -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.
@@ -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 */
@@ -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);
@@ -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);
@@ -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);
+9 −3
Original line number Diff line number Diff line
@@ -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;
@@ -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;
};

/*
@@ -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.
@@ -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];
@@ -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__ */
+208 −3
Original line number Diff line number Diff line
@@ -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 = {
@@ -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;

@@ -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;

@@ -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.
@@ -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);

@@ -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);
+7 −2
Original line number Diff line number Diff line
@@ -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);
@@ -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