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

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

Merge "disp: msm: sde: add vbif axi port halt request support"

parents 65d27833 ac8fbfff
Loading
Loading
Loading
Loading
+29 −4
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@
/*
 * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 */
#include <linux/iopoll.h>

#include "sde_hwio.h"
#include "sde_hw_catalog.h"
@@ -9,6 +10,7 @@
#include "sde_dbg.h"

#define VBIF_VERSION			0x0000
#define VBIF_CLKON			0x0004
#define VBIF_CLK_FORCE_CTRL0		0x0008
#define VBIF_CLK_FORCE_CTRL1		0x000C
#define VBIF_QOS_REMAP_00		0x0020
@@ -33,6 +35,8 @@
#define VBIF_XIN_CLR_ERR		0x019C
#define VBIF_XIN_HALT_CTRL0		0x0200
#define VBIF_XIN_HALT_CTRL1		0x0204
#define VBIF_AXI_HALT_CTRL0		0x0208
#define VBIF_AXI_HALT_CTRL1		0x020c
#define VBIF_XINL_QOS_RP_REMAP_000	0x0550
#define VBIF_XINL_QOS_LVL_REMAP_000	0x0590

@@ -154,7 +158,7 @@ static u32 sde_hw_get_limit_conf(struct sde_hw_vbif *vbif,
	return limit;
}

static void sde_hw_set_halt_ctrl(struct sde_hw_vbif *vbif,
static void sde_hw_set_xin_halt(struct sde_hw_vbif *vbif,
		u32 xin_id, bool enable)
{
	struct sde_hw_blk_reg_map *c = &vbif->hw;
@@ -168,9 +172,10 @@ static void sde_hw_set_halt_ctrl(struct sde_hw_vbif *vbif,
		reg_val &= ~BIT(xin_id);

	SDE_REG_WRITE(c, VBIF_XIN_HALT_CTRL0, reg_val);
	wmb(); /* make sure that xin client halted */
}

static bool sde_hw_get_halt_ctrl(struct sde_hw_vbif *vbif,
static bool sde_hw_get_xin_halt_status(struct sde_hw_vbif *vbif,
		u32 xin_id)
{
	struct sde_hw_blk_reg_map *c = &vbif->hw;
@@ -181,6 +186,24 @@ static bool sde_hw_get_halt_ctrl(struct sde_hw_vbif *vbif,
	return ((reg_val >> 16) & BIT(xin_id)) ? true : false;
}

static void sde_hw_set_axi_halt(struct sde_hw_vbif *vbif)
{
	struct sde_hw_blk_reg_map *c = &vbif->hw;

	SDE_REG_WRITE(c, VBIF_CLKON, BIT(0));
	SDE_REG_WRITE(c, VBIF_AXI_HALT_CTRL0, BIT(0));
	wmb(); /* make sure that axi transactions are halted */
}

static int sde_hw_get_axi_halt_status(struct sde_hw_vbif *vbif)
{
	struct sde_hw_blk_reg_map *c = &vbif->hw;
	int ctrl = 0;

	return readl_poll_timeout(c->base_off + c->blk_off +
		VBIF_AXI_HALT_CTRL1, ctrl, ctrl & BIT(0), 100, 4000);
}

static void sde_hw_set_qos_remap(struct sde_hw_vbif *vbif,
		u32 xin_id, u32 level, u32 remap_level)
{
@@ -230,8 +253,10 @@ static void _setup_vbif_ops(const struct sde_mdss_cfg *m,
{
	ops->set_limit_conf = sde_hw_set_limit_conf;
	ops->get_limit_conf = sde_hw_get_limit_conf;
	ops->set_halt_ctrl = sde_hw_set_halt_ctrl;
	ops->get_halt_ctrl = sde_hw_get_halt_ctrl;
	ops->set_axi_halt = sde_hw_set_axi_halt;
	ops->get_axi_halt_status = sde_hw_get_axi_halt_status;
	ops->set_xin_halt = sde_hw_set_xin_halt;
	ops->get_xin_halt_status = sde_hw_get_xin_halt_status;
	if (test_bit(SDE_VBIF_QOS_REMAP, &cap))
		ops->set_qos_remap = sde_hw_set_qos_remap;
	if (test_bit(SDE_VBIF_DISABLE_SHAREABLE, &cap))
+17 −5
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 */

#ifndef _SDE_HW_VBIF_H
@@ -38,23 +38,35 @@ struct sde_hw_vbif_ops {
			u32 xin_id, bool rd);

	/**
	 * set_halt_ctrl - set halt control
	 * set_xin_halt - set xin client halt control
	 * @vbif: vbif context driver
	 * @xin_id: client interface identifier
	 * @enable: halt control enable
	 */
	void (*set_halt_ctrl)(struct sde_hw_vbif *vbif,
	void (*set_xin_halt)(struct sde_hw_vbif *vbif,
			u32 xin_id, bool enable);

	/**
	 * get_halt_ctrl - get halt control
	 * get_xin_halt_status - get xin client halt control
	 * @vbif: vbif context driver
	 * @xin_id: client interface identifier
	 * @return: halt control enable
	 */
	bool (*get_halt_ctrl)(struct sde_hw_vbif *vbif,
	bool (*get_xin_halt_status)(struct sde_hw_vbif *vbif,
			u32 xin_id);

	/**
	 * set_axi_halt - set axi port halt control
	 * @vbif: vbif context driver
	 */
	void (*set_axi_halt)(struct sde_hw_vbif *vbif);

	/**
	 * get_axi_halt_status - get axi port halt control status
	 * @vbif: vbif context driver
	 */
	int (*get_axi_halt_status)(struct sde_hw_vbif *vbif);

	/**
	 * set_qos_remap - set QoS priority remap
	 * @vbif: vbif context driver
+2 −0
Original line number Diff line number Diff line
@@ -2948,6 +2948,8 @@ static void sde_kms_handle_power_event(u32 event_type, void *usr)
		sde_irq_update(msm_kms, false);
		sde_kms->first_kickoff = false;
		_sde_kms_active_override(sde_kms, true);
		if (!is_sde_rsc_available(SDE_RSC_INDEX))
			sde_vbif_axi_halt_request(sde_kms);
	}
}

+65 −19
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 */

#define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__
@@ -26,18 +26,18 @@ static int _sde_vbif_wait_for_xin_halt(struct sde_hw_vbif *vbif, u32 xin_id)
	bool status;
	int rc;

	if (!vbif || !vbif->cap || !vbif->ops.get_halt_ctrl) {
	if (!vbif || !vbif->cap || !vbif->ops.get_xin_halt_status) {
		SDE_ERROR("invalid arguments vbif %d\n", !vbif);
		return -EINVAL;
	}

	timeout = ktime_add_us(ktime_get(), vbif->cap->xin_halt_timeout);
	for (;;) {
		status = vbif->ops.get_halt_ctrl(vbif, xin_id);
		status = vbif->ops.get_xin_halt_status(vbif, xin_id);
		if (status)
			break;
		if (ktime_compare_safe(ktime_get(), timeout) > 0) {
			status = vbif->ops.get_halt_ctrl(vbif, xin_id);
			status = vbif->ops.get_xin_halt_status(vbif, xin_id);
			break;
		}
		usleep_range(501, 1000);
@@ -56,6 +56,26 @@ static int _sde_vbif_wait_for_xin_halt(struct sde_hw_vbif *vbif, u32 xin_id)
	return rc;
}

static int _sde_vbif_wait_for_axi_halt(struct sde_hw_vbif *vbif)
{
	int rc;

	if (!vbif || !vbif->cap || !vbif->ops.get_axi_halt_status) {
		SDE_ERROR("invalid arguments vbif %d\n", !vbif);
		return -EINVAL;
	}

	rc = vbif->ops.get_axi_halt_status(vbif);
	if (rc)
		SDE_ERROR("VBIF %d AXI port(s) not halting. TIMEDOUT.\n",
				vbif->idx - VBIF_0);
	else
		SDE_DEBUG("VBIF %d AXI port(s) halted\n",
				vbif->idx - VBIF_0);

	return rc;
}

int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl)
{
	struct sde_hw_vbif *vbif = NULL;
@@ -76,8 +96,8 @@ int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl)

	vbif = sde_kms->hw_vbif[VBIF_RT];
	mdp = sde_kms->hw_mdp;
	if (!vbif || !mdp || !vbif->ops.get_halt_ctrl ||
		       !vbif->ops.set_halt_ctrl ||
	if (!vbif || !mdp || !vbif->ops.get_xin_halt_status ||
		       !vbif->ops.set_xin_halt ||
		       !mdp->ops.setup_clk_force_ctrl) {
		SDE_ERROR("invalid vbif or mdp arguments\n");
		return -EINVAL;
@@ -92,7 +112,7 @@ int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl)
	 * while halting by forcing it ON only if it was not previously
	 * forced on. If status is 1 then its already halted.
	 */
	status = vbif->ops.get_halt_ctrl(vbif, xin_id);
	status = vbif->ops.get_xin_halt_status(vbif, xin_id);
	if (status) {
		mutex_unlock(&vbif->mutex);
		return 0;
@@ -101,7 +121,7 @@ int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl)
	forced_on = mdp->ops.setup_clk_force_ctrl(mdp, clk_ctrl, true);

	/* send halt request for unused plane's xin client */
	vbif->ops.set_halt_ctrl(vbif, xin_id, true);
	vbif->ops.set_xin_halt(vbif, xin_id, true);

	rc = _sde_vbif_wait_for_xin_halt(vbif, xin_id);
	if (rc) {
@@ -112,7 +132,7 @@ int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl)
	}

	/* open xin client to enable transactions */
	vbif->ops.set_halt_ctrl(vbif, xin_id, false);
	vbif->ops.set_xin_halt(vbif, xin_id, false);
	if (forced_on)
		mdp->ops.setup_clk_force_ctrl(mdp, clk_ctrl, false);

@@ -250,7 +270,7 @@ void sde_vbif_set_ot_limit(struct sde_kms *sde_kms,

	if (!mdp->ops.setup_clk_force_ctrl ||
			!vbif->ops.set_limit_conf ||
			!vbif->ops.set_halt_ctrl)
			!vbif->ops.set_xin_halt)
		return;

	mutex_lock(&vbif->mutex);
@@ -273,13 +293,13 @@ void sde_vbif_set_ot_limit(struct sde_kms *sde_kms,

	vbif->ops.set_limit_conf(vbif, params->xin_id, params->rd, ot_lim);

	vbif->ops.set_halt_ctrl(vbif, params->xin_id, true);
	vbif->ops.set_xin_halt(vbif, params->xin_id, true);

	ret = _sde_vbif_wait_for_xin_halt(vbif, params->xin_id);
	if (ret)
		SDE_EVT32(vbif->idx, params->xin_id);

	vbif->ops.set_halt_ctrl(vbif, params->xin_id, false);
	vbif->ops.set_xin_halt(vbif, params->xin_id, false);

	if (forced_on)
		mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, false);
@@ -357,7 +377,7 @@ bool sde_vbif_set_xin_halt(struct sde_kms *sde_kms,
	}

	if (!mdp->ops.setup_clk_force_ctrl ||
			!vbif->ops.set_halt_ctrl)
			!vbif->ops.set_xin_halt)
		return false;

	mutex_lock(&vbif->mutex);
@@ -368,13 +388,13 @@ bool sde_vbif_set_xin_halt(struct sde_kms *sde_kms,
		forced_on = mdp->ops.setup_clk_force_ctrl(mdp,
				params->clk_ctrl, true);

		vbif->ops.set_halt_ctrl(vbif, params->xin_id, true);
		vbif->ops.set_xin_halt(vbif, params->xin_id, true);

		ret = _sde_vbif_wait_for_xin_halt(vbif, params->xin_id);
		if (ret)
			SDE_EVT32(vbif->idx, params->xin_id, SDE_EVTLOG_ERROR);
	} else {
		vbif->ops.set_halt_ctrl(vbif, params->xin_id, false);
		vbif->ops.set_xin_halt(vbif, params->xin_id, false);

		if (params->forced_on)
			mdp->ops.setup_clk_force_ctrl(mdp,
@@ -511,6 +531,32 @@ void sde_vbif_init_memtypes(struct sde_kms *sde_kms)
	}
}

void sde_vbif_axi_halt_request(struct sde_kms *sde_kms)
{
	struct sde_hw_vbif *vbif;
	int i;

	if (!sde_kms) {
		SDE_ERROR("invalid argument\n");
		return;
	}

	if (!sde_kms_is_vbif_operation_allowed(sde_kms)) {
		SDE_DEBUG("vbif operations not permitted\n");
		return;
	}

	for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) {
		vbif = sde_kms->hw_vbif[i];
		if (vbif && vbif->cap && vbif->ops.set_axi_halt) {
			mutex_lock(&vbif->mutex);
			vbif->ops.set_axi_halt(vbif);
			_sde_vbif_wait_for_axi_halt(vbif);
			mutex_unlock(&vbif->mutex);
		}
	}
}

int sde_vbif_halt_xin_mask(struct sde_kms *sde_kms, u32 xin_id_mask,
				bool halt)
{
@@ -524,7 +570,7 @@ int sde_vbif_halt_xin_mask(struct sde_kms *sde_kms, u32 xin_id_mask,

	vbif = sde_kms->hw_vbif[VBIF_RT];

	if (!vbif->ops.get_halt_ctrl || !vbif->ops.set_halt_ctrl)
	if (!vbif->ops.get_xin_halt_status || !vbif->ops.set_xin_halt)
		return 0;

	SDE_EVT32(xin_id_mask, halt);
@@ -533,16 +579,16 @@ int sde_vbif_halt_xin_mask(struct sde_kms *sde_kms, u32 xin_id_mask,
		if (xin_id_mask & BIT(i)) {
			/* unhalt the xin-clients */
			if (!halt) {
				vbif->ops.set_halt_ctrl(vbif, i, false);
				vbif->ops.set_xin_halt(vbif, i, false);
				continue;
			}

			status = vbif->ops.get_halt_ctrl(vbif, i);
			status = vbif->ops.get_xin_halt_status(vbif, i);
			if (status)
				continue;

			/* halt xin-clients and wait for ack */
			vbif->ops.set_halt_ctrl(vbif, i, true);
			vbif->ops.set_xin_halt(vbif, i, true);

			rc = _sde_vbif_wait_for_xin_halt(vbif, i);
			if (rc) {
+7 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
 */

#ifndef __SDE_VBIF_H__
@@ -98,6 +98,12 @@ void sde_vbif_clear_errors(struct sde_kms *sde_kms);
 */
void sde_vbif_init_memtypes(struct sde_kms *sde_kms);

/**
 * sde_vbif_axi_halt_request - halt all axi transcations on vbif
 * @sde_kms:	SDE handler
 */
void sde_vbif_axi_halt_request(struct sde_kms *sde_kms);

/**
 * sde_vbif_halt_plane_xin - halts the xin client for the unused plane
 * On unused plane, check if the vbif for this plane is idle or not.