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

Commit 5c6c3102 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm:disp:rotator: setup irq during first rotator commit"

parents 65b4eb59 bd59bbaf
Loading
Loading
Loading
Loading
+248 −229
Original line number Diff line number Diff line
@@ -569,6 +569,33 @@ static u32 __sde_hw_rotator_get_timestamp(struct sde_hw_rotator *rot, u32 q_id)
	return ts & SDE_REGDMA_SWTS_MASK;
}

/**
 * sde_hw_rotator_disable_irq - Disable hw rotator interrupt with ref. count
 *				Also, clear rotator/regdma irq enable masks.
 * @rot: Pointer to hw rotator
 */
static void sde_hw_rotator_disable_irq(struct sde_hw_rotator *rot)
{
	SDEROT_DBG("irq_num:%d enabled:%d\n", rot->irq_num,
		atomic_read(&rot->irq_enabled));

	if (!atomic_read(&rot->irq_enabled)) {
		SDEROT_ERR("irq %d is already disabled\n", rot->irq_num);
		return;
	}

	if (!atomic_dec_return(&rot->irq_enabled)) {
		if (rot->mode == ROT_REGDMA_OFF)
			SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_EN, 0);
		else
			SDE_ROTREG_WRITE(rot->mdss_base,
				REGDMA_CSR_REGDMA_INT_EN, 0);
		/* disable irq after last pending irq is handled, if any */
		synchronize_irq(rot->irq_num);
		disable_irq_nosync(rot->irq_num);
	}
}

/**
 * sde_hw_rotator_elapsed_swts - Find difference of 2 software timestamps
 * @ts_curr: current software timestamp
@@ -582,6 +609,174 @@ static int sde_hw_rotator_elapsed_swts(u32 ts_curr, u32 ts_prev)
	return sign_extend32(diff, (SDE_REGDMA_SWTS_SHIFT - 1));
}

/*
 * sde_hw_rotator_rotirq_handler - non-regdma interrupt handler
 * @irq: Interrupt number
 * @ptr: Pointer to private handle provided during registration
 *
 * This function services rotator interrupt and wakes up waiting client
 * with pending rotation requests already submitted to h/w.
 */
static irqreturn_t sde_hw_rotator_rotirq_handler(int irq, void *ptr)
{
	struct sde_hw_rotator *rot = ptr;
	struct sde_hw_rotator_context *ctx;
	irqreturn_t ret = IRQ_NONE;
	u32 isr;

	isr = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_INTR_STATUS);

	SDEROT_DBG("intr_status = %8.8x\n", isr);

	if (isr & ROT_DONE_MASK) {
		sde_hw_rotator_disable_irq(rot);
		SDEROT_DBG("Notify rotator complete\n");

		/* Normal rotator only 1 session, no need to lookup */
		ctx = rot->rotCtx[0][0];
		WARN_ON(ctx == NULL);
		complete_all(&ctx->rot_comp);

		spin_lock(&rot->rotisr_lock);
		SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR,
				ROT_DONE_CLEAR);
		spin_unlock(&rot->rotisr_lock);
		ret = IRQ_HANDLED;
	}

	return ret;
}

/*
 * sde_hw_rotator_regdmairq_handler - regdma interrupt handler
 * @irq: Interrupt number
 * @ptr: Pointer to private handle provided during registration
 *
 * This function services rotator interrupt, decoding the source of
 * events (high/low priority queue), and wakes up all waiting clients
 * with pending rotation requests already submitted to h/w.
 */
static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr)
{
	struct sde_rot_data_type *mdata = sde_rot_get_mdata();
	struct sde_hw_rotator *rot = ptr;
	struct sde_hw_rotator_context *ctx, *tmp;
	irqreturn_t ret = IRQ_NONE;
	u32 isr, isr_tmp;
	u32 ts;
	u32 q_id;

	isr = SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_INT_STATUS);
	/* acknowledge interrupt before reading latest timestamp */
	SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, isr);

	SDEROT_DBG("intr_status = %8.8x\n", isr);

	/* Any REGDMA status, including error and watchdog timer, should
	 * trigger and wake up waiting thread
	 */
	if (isr & (REGDMA_INT_HIGH_MASK | REGDMA_INT_LOW_MASK)) {
		spin_lock(&rot->rotisr_lock);

		/*
		 * Obtain rotator context based on timestamp from regdma
		 * and low/high interrupt status
		 */
		if (isr & REGDMA_INT_HIGH_MASK) {
			q_id = ROT_QUEUE_HIGH_PRIORITY;
		} else if (isr & REGDMA_INT_LOW_MASK) {
			q_id = ROT_QUEUE_LOW_PRIORITY;
		} else {
			SDEROT_ERR("unknown ISR status: isr=0x%X\n", isr);
			goto done_isr_handle;
		}

		ts = __sde_hw_rotator_get_timestamp(rot, q_id);

		/*
		 * Timestamp packet is not available in sbuf mode.
		 * Simulate timestamp update in the handler instead.
		 */
		if (test_bit(SDE_CAPS_HW_TIMESTAMP, mdata->sde_caps_map) ||
				list_empty(&rot->sbuf_ctx[q_id]))
			goto skip_sbuf;

		ctx = NULL;
		isr_tmp = isr;
		list_for_each_entry(tmp, &rot->sbuf_ctx[q_id], list) {
			u32 mask;

			mask = tmp->timestamp & 0x1 ? REGDMA_INT_1_MASK :
				REGDMA_INT_0_MASK;
			if (isr_tmp & mask) {
				isr_tmp &= ~mask;
				ctx = tmp;
				ts = ctx->timestamp;
				rot->ops.update_ts(rot, ctx->q_id, ts);
				SDEROT_DBG("update swts:0x%X\n", ts);
			}
			SDEROT_EVTLOG(isr, tmp->timestamp);
		}
		if (ctx == NULL)
			SDEROT_ERR("invalid swts ctx\n");
skip_sbuf:
		ctx = rot->rotCtx[q_id][ts & SDE_HW_ROT_REGDMA_SEG_MASK];

		/*
		 * Wake up all waiting context from the current and previous
		 * SW Timestamp.
		 */
		while (ctx &&
			sde_hw_rotator_elapsed_swts(ctx->timestamp, ts) >= 0) {
			ctx->last_regdma_isr_status = isr;
			ctx->last_regdma_timestamp  = ts;
			SDEROT_DBG(
				"regdma complete: ctx:%pK, ts:%X\n", ctx, ts);
			wake_up_all(&ctx->regdma_waitq);

			ts  = (ts - 1) & SDE_REGDMA_SWTS_MASK;
			ctx = rot->rotCtx[q_id]
				[ts & SDE_HW_ROT_REGDMA_SEG_MASK];
		};

done_isr_handle:
		spin_unlock(&rot->rotisr_lock);
		ret = IRQ_HANDLED;
	} else if (isr & REGDMA_INT_ERR_MASK) {
		/*
		 * For REGDMA Err, we save the isr info and wake up
		 * all waiting contexts
		 */
		int i, j;

		SDEROT_ERR(
			"regdma err isr:%X, wake up all waiting contexts\n",
			isr);

		spin_lock(&rot->rotisr_lock);

		for (i = 0; i < ROT_QUEUE_MAX; i++) {
			for (j = 0; j < SDE_HW_ROT_REGDMA_TOTAL_CTX; j++) {
				ctx = rot->rotCtx[i][j];
				if (ctx && ctx->last_regdma_isr_status == 0) {
					ts = __sde_hw_rotator_get_timestamp(
							rot, i);
					ctx->last_regdma_isr_status = isr;
					ctx->last_regdma_timestamp  = ts;
					wake_up_all(&ctx->regdma_waitq);
					SDEROT_DBG("Wake rotctx[%d][%d]:%pK\n",
							i, j, ctx);
				}
			}
		}

		spin_unlock(&rot->rotisr_lock);
		ret = IRQ_HANDLED;
	}

	return ret;
}

/**
 * sde_hw_rotator_pending_hwts - Check if the given context is still pending
 * @rot: Pointer to hw rotator
@@ -695,54 +890,76 @@ static void sde_hw_rotator_update_swts(struct sde_hw_rotator *rot,
	SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG, swts);
}

/**
 * sde_hw_rotator_enable_irq - Enable hw rotator interrupt with ref. count
 *				Also, clear rotator/regdma irq status.
 * @rot: Pointer to hw rotator
/*
 * sde_hw_rotator_irq_setup - setup rotator irq
 * @mgr: Pointer to rotator manager
 * return: none
 */
static void sde_hw_rotator_enable_irq(struct sde_hw_rotator *rot)
static int sde_hw_rotator_irq_setup(struct sde_hw_rotator *rot)
{
	SDEROT_DBG("irq_num:%d enabled:%d\n", rot->irq_num,
		atomic_read(&rot->irq_enabled));
	int rc = 0;

	if (!atomic_read(&rot->irq_enabled)) {
	/* return early if irq is already setup */
	if (rot->irq_num >= 0)
		return 0;

	rot->irq_num = platform_get_irq(rot->pdev, 0);
	if (rot->irq_num < 0) {
		rc = rot->irq_num;
		SDEROT_ERR("fail to get rot irq, fallback to poll %d\n", rc);
	} else {
		if (rot->mode == ROT_REGDMA_OFF)
			SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR,
				ROT_DONE_MASK);
			rc = devm_request_threaded_irq(&rot->pdev->dev,
					rot->irq_num,
					sde_hw_rotator_rotirq_handler,
					NULL, 0, "sde_rotator_r3", rot);
		else
			SDE_ROTREG_WRITE(rot->mdss_base,
				REGDMA_CSR_REGDMA_INT_CLEAR, REGDMA_INT_MASK);

		enable_irq(rot->irq_num);
			rc = devm_request_threaded_irq(&rot->pdev->dev,
					rot->irq_num,
					sde_hw_rotator_regdmairq_handler,
					NULL, 0, "sde_rotator_r3", rot);
		if (rc) {
			SDEROT_ERR("fail to request irq r:%d\n", rc);
			rot->irq_num = -1;
		} else {
			disable_irq(rot->irq_num);
		}
	atomic_inc(&rot->irq_enabled);
	}

	return rc;
}

/**
 * sde_hw_rotator_disable_irq - Disable hw rotator interrupt with ref. count
 *				Also, clear rotator/regdma irq enable masks.
 * sde_hw_rotator_enable_irq - Enable hw rotator interrupt with ref. count
 *				Also, clear rotator/regdma irq status.
 * @rot: Pointer to hw rotator
 */
static void sde_hw_rotator_disable_irq(struct sde_hw_rotator *rot)
static int sde_hw_rotator_enable_irq(struct sde_hw_rotator *rot)
{
	int ret = 0;
	SDEROT_DBG("irq_num:%d enabled:%d\n", rot->irq_num,
		atomic_read(&rot->irq_enabled));

	if (!atomic_read(&rot->irq_enabled)) {
		SDEROT_ERR("irq %d is already disabled\n", rot->irq_num);
		return;
	ret = sde_hw_rotator_irq_setup(rot);
	if (ret < 0) {
		SDEROT_ERR("Rotator irq setup failed %d\n", ret);
		return ret;
	}

	if (!atomic_dec_return(&rot->irq_enabled)) {
	if (!atomic_read(&rot->irq_enabled)) {

		if (rot->mode == ROT_REGDMA_OFF)
			SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_EN, 0);
			SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR,
				ROT_DONE_MASK);
		else
			SDE_ROTREG_WRITE(rot->mdss_base,
				REGDMA_CSR_REGDMA_INT_EN, 0);
		/* disable irq after last pending irq is handled, if any */
		synchronize_irq(rot->irq_num);
		disable_irq_nosync(rot->irq_num);
				REGDMA_CSR_REGDMA_INT_CLEAR, REGDMA_INT_MASK);

		enable_irq(rot->irq_num);
	}
	atomic_inc(&rot->irq_enabled);

	return ret;
}

static int sde_hw_rotator_halt_vbif_xin_client(void)
@@ -1814,11 +2031,10 @@ static u32 sde_hw_rotator_start_no_regdma(struct sde_hw_rotator_context *ctx,
	mem_rdptr = sde_hw_rotator_get_regdma_segment_base(ctx);
	wrptr = sde_hw_rotator_get_regdma_segment(ctx);

	if (rot->irq_num >= 0) {
	if (!sde_hw_rotator_enable_irq(rot)) {
		SDE_REGDMA_WRITE(wrptr, ROTTOP_INTR_EN, 1);
		SDE_REGDMA_WRITE(wrptr, ROTTOP_INTR_CLEAR, 1);
		reinit_completion(&ctx->rot_comp);
		sde_hw_rotator_enable_irq(rot);
	}

	SDE_REGDMA_WRITE(wrptr, ROTTOP_START_CTRL, ctx->start_ctrl);
@@ -2526,7 +2742,6 @@ static struct sde_rot_hw_resource *sde_hw_rotator_alloc_ext(
			sde_hw_rotator_swts_create(resinfo->rot);
	}

	if (resinfo->rot->irq_num >= 0)
	sde_hw_rotator_enable_irq(resinfo->rot);

	SDEROT_DBG("New rotator resource:%pK, priority:%d\n",
@@ -2555,7 +2770,6 @@ static void sde_hw_rotator_free_ext(struct sde_rot_mgr *mgr,
		resinfo, hw->wb_id, atomic_read(&hw->num_active),
		hw->pending_count);

	if (resinfo->rot->irq_num >= 0)
	sde_hw_rotator_disable_irq(resinfo->rot);

	devm_kfree(&mgr->pdev->dev, resinfo);
@@ -3303,176 +3517,6 @@ static int sde_rotator_hw_rev_init(struct sde_hw_rotator *rot)
	return 0;
}

/*
 * sde_hw_rotator_rotirq_handler - non-regdma interrupt handler
 * @irq: Interrupt number
 * @ptr: Pointer to private handle provided during registration
 *
 * This function services rotator interrupt and wakes up waiting client
 * with pending rotation requests already submitted to h/w.
 */
static irqreturn_t sde_hw_rotator_rotirq_handler(int irq, void *ptr)
{
	struct sde_hw_rotator *rot = ptr;
	struct sde_hw_rotator_context *ctx;
	irqreturn_t ret = IRQ_NONE;
	u32 isr;

	isr = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_INTR_STATUS);

	SDEROT_DBG("intr_status = %8.8x\n", isr);

	if (isr & ROT_DONE_MASK) {
		if (rot->irq_num >= 0)
			sde_hw_rotator_disable_irq(rot);
		SDEROT_DBG("Notify rotator complete\n");

		/* Normal rotator only 1 session, no need to lookup */
		ctx = rot->rotCtx[0][0];
		WARN_ON(ctx == NULL);
		complete_all(&ctx->rot_comp);

		spin_lock(&rot->rotisr_lock);
		SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR,
				ROT_DONE_CLEAR);
		spin_unlock(&rot->rotisr_lock);
		ret = IRQ_HANDLED;
	}

	return ret;
}

/*
 * sde_hw_rotator_regdmairq_handler - regdma interrupt handler
 * @irq: Interrupt number
 * @ptr: Pointer to private handle provided during registration
 *
 * This function services rotator interrupt, decoding the source of
 * events (high/low priority queue), and wakes up all waiting clients
 * with pending rotation requests already submitted to h/w.
 */
static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr)
{
	struct sde_rot_data_type *mdata = sde_rot_get_mdata();
	struct sde_hw_rotator *rot = ptr;
	struct sde_hw_rotator_context *ctx, *tmp;
	irqreturn_t ret = IRQ_NONE;
	u32 isr, isr_tmp;
	u32 ts;
	u32 q_id;

	isr = SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_INT_STATUS);
	/* acknowledge interrupt before reading latest timestamp */
	SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, isr);

	SDEROT_DBG("intr_status = %8.8x\n", isr);

	/* Any REGDMA status, including error and watchdog timer, should
	 * trigger and wake up waiting thread
	 */
	if (isr & (REGDMA_INT_HIGH_MASK | REGDMA_INT_LOW_MASK)) {
		spin_lock(&rot->rotisr_lock);

		/*
		 * Obtain rotator context based on timestamp from regdma
		 * and low/high interrupt status
		 */
		if (isr & REGDMA_INT_HIGH_MASK) {
			q_id = ROT_QUEUE_HIGH_PRIORITY;
		} else if (isr & REGDMA_INT_LOW_MASK) {
			q_id = ROT_QUEUE_LOW_PRIORITY;
		} else {
			SDEROT_ERR("unknown ISR status: isr=0x%X\n", isr);
			goto done_isr_handle;
		}

		ts = __sde_hw_rotator_get_timestamp(rot, q_id);

		/*
		 * Timestamp packet is not available in sbuf mode.
		 * Simulate timestamp update in the handler instead.
		 */
		if (test_bit(SDE_CAPS_HW_TIMESTAMP, mdata->sde_caps_map) ||
				list_empty(&rot->sbuf_ctx[q_id]))
			goto skip_sbuf;

		ctx = NULL;
		isr_tmp = isr;
		list_for_each_entry(tmp, &rot->sbuf_ctx[q_id], list) {
			u32 mask;

			mask = tmp->timestamp & 0x1 ? REGDMA_INT_1_MASK :
				REGDMA_INT_0_MASK;
			if (isr_tmp & mask) {
				isr_tmp &= ~mask;
				ctx = tmp;
				ts = ctx->timestamp;
				rot->ops.update_ts(rot, ctx->q_id, ts);
				SDEROT_DBG("update swts:0x%X\n", ts);
			}
			SDEROT_EVTLOG(isr, tmp->timestamp);
		}
		if (ctx == NULL)
			SDEROT_ERR("invalid swts ctx\n");
skip_sbuf:
		ctx = rot->rotCtx[q_id][ts & SDE_HW_ROT_REGDMA_SEG_MASK];

		/*
		 * Wake up all waiting context from the current and previous
		 * SW Timestamp.
		 */
		while (ctx &&
			sde_hw_rotator_elapsed_swts(ctx->timestamp, ts) >= 0) {
			ctx->last_regdma_isr_status = isr;
			ctx->last_regdma_timestamp  = ts;
			SDEROT_DBG(
				"regdma complete: ctx:%pK, ts:%X\n", ctx, ts);
			wake_up_all(&ctx->regdma_waitq);

			ts  = (ts - 1) & SDE_REGDMA_SWTS_MASK;
			ctx = rot->rotCtx[q_id]
				[ts & SDE_HW_ROT_REGDMA_SEG_MASK];
		}

done_isr_handle:
		spin_unlock(&rot->rotisr_lock);
		ret = IRQ_HANDLED;
	} else if (isr & REGDMA_INT_ERR_MASK) {
		/*
		 * For REGDMA Err, we save the isr info and wake up
		 * all waiting contexts
		 */
		int i, j;

		SDEROT_ERR(
			"regdma err isr:%X, wake up all waiting contexts\n",
			isr);

		spin_lock(&rot->rotisr_lock);

		for (i = 0; i < ROT_QUEUE_MAX; i++) {
			for (j = 0; j < SDE_HW_ROT_REGDMA_TOTAL_CTX; j++) {
				ctx = rot->rotCtx[i][j];
				if (ctx && ctx->last_regdma_isr_status == 0) {
					ts = __sde_hw_rotator_get_timestamp(
							rot, i);
					ctx->last_regdma_isr_status = isr;
					ctx->last_regdma_timestamp  = ts;
					wake_up_all(&ctx->regdma_waitq);
					SDEROT_DBG(
						"Wakeup rotctx[%d][%d]:%pK\n",
						i, j, ctx);
				}
			}
		}

		spin_unlock(&rot->rotisr_lock);
		ret = IRQ_HANDLED;
	}

	return ret;
}

/*
 * sde_hw_rotator_validate_entry - validate rotation entry
 * @mgr: Pointer to rotator manager
@@ -3985,30 +4029,7 @@ int sde_rotator_r3_init(struct sde_rot_mgr *mgr)
	if (ret)
		goto error_parse_dt;

	rot->irq_num = platform_get_irq(mgr->pdev, 0);
	if (rot->irq_num == -EPROBE_DEFER) {
		SDEROT_INFO("irq master master not ready, defer probe\n");
		return -EPROBE_DEFER;
	} else if (rot->irq_num < 0) {
		SDEROT_ERR("fail to get rotator irq, fallback to polling\n");
	} else {
		if (rot->mode == ROT_REGDMA_OFF)
			ret = devm_request_threaded_irq(&mgr->pdev->dev,
					rot->irq_num,
					sde_hw_rotator_rotirq_handler,
					NULL, 0, "sde_rotator_r3", rot);
		else
			ret = devm_request_threaded_irq(&mgr->pdev->dev,
					rot->irq_num,
					sde_hw_rotator_regdmairq_handler,
					NULL, 0, "sde_rotator_r3", rot);
		if (ret) {
			SDEROT_ERR("fail to request irq r:%d\n", ret);
			rot->irq_num = -1;
		} else {
			disable_irq(rot->irq_num);
		}
	}
	rot->irq_num = -EINVAL;
	atomic_set(&rot->irq_enabled, 0);

	ret = sde_rotator_hw_rev_init(rot);
@@ -4056,8 +4077,6 @@ int sde_rotator_r3_init(struct sde_rot_mgr *mgr)
	mdata->sde_rot_hw = rot;
	return 0;
error_hw_rev_init:
	if (rot->irq_num >= 0)
		devm_free_irq(&mgr->pdev->dev, rot->irq_num, mdata);
	devm_kfree(&mgr->pdev->dev, mgr->hw_data);
error_parse_dt:
	return ret;