Commit 5ee74eb2 authored by Pierre-Louis Bossart's avatar Pierre-Louis Bossart Committed by Vinod Koul
Browse files

soundwire: intel: don't manage link power individually



Each link has separate power controls, but experimental results show
we need to use an all-or-none approach to the link power management.

This change has marginal power impacts, the DSP needs to be powered
anyways before SoundWire links can be powered, and even when powered a
link can be in clock-stopped mode.

Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20200901150556.19432-11-yung-chuan.liao@linux.intel.com


Signed-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent de763fa8
Loading
Loading
Loading
Loading
+46 −24
Original line number Diff line number Diff line
@@ -63,7 +63,9 @@ MODULE_PARM_DESC(sdw_md_flags, "SoundWire Intel Master device flags (0x0 all off
#define SDW_SHIM_WAKESTS		0x192

#define SDW_SHIM_LCTL_SPA		BIT(0)
#define SDW_SHIM_LCTL_SPA_MASK		GENMASK(3, 0)
#define SDW_SHIM_LCTL_CPA		BIT(8)
#define SDW_SHIM_LCTL_CPA_MASK		GENMASK(11, 8)

#define SDW_SHIM_SYNC_SYNCPRD_VAL_24	(24000 / SDW_CADENCE_GSYNC_KHZ - 1)
#define SDW_SHIM_SYNC_SYNCPRD_VAL_38_4	(38400 / SDW_CADENCE_GSYNC_KHZ - 1)
@@ -295,8 +297,8 @@ static int intel_link_power_up(struct sdw_intel *sdw)
	u32 *shim_mask = sdw->link_res->shim_mask;
	struct sdw_bus *bus = &sdw->cdns.bus;
	struct sdw_master_prop *prop = &bus->prop;
	int spa_mask, cpa_mask;
	int link_control;
	u32 spa_mask, cpa_mask;
	u32 link_control;
	int ret = 0;
	u32 syncprd;
	u32 sync_reg;
@@ -319,6 +321,8 @@ static int intel_link_power_up(struct sdw_intel *sdw)
		syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24;

	if (!*shim_mask) {
		dev_dbg(sdw->cdns.dev, "%s: powering up all links\n", __func__);

		/* we first need to program the SyncPRD/CPU registers */
		dev_dbg(sdw->cdns.dev,
			"%s: first link up, programming SYNCPRD\n", __func__);
@@ -331,12 +335,16 @@ static int intel_link_power_up(struct sdw_intel *sdw)
		/* Set SyncCPU bit */
		sync_reg |= SDW_SHIM_SYNC_SYNCCPU;
		intel_writel(shim, SDW_SHIM_SYNC, sync_reg);
	}

		/* Link power up sequence */
		link_control = intel_readl(shim, SDW_SHIM_LCTL);
	spa_mask = (SDW_SHIM_LCTL_SPA << link_id);
	cpa_mask = (SDW_SHIM_LCTL_CPA << link_id);

		/* only power-up enabled links */
		spa_mask = sdw->link_res->link_mask <<
			SDW_REG_SHIFT(SDW_SHIM_LCTL_SPA_MASK);
		cpa_mask = sdw->link_res->link_mask <<
			SDW_REG_SHIFT(SDW_SHIM_LCTL_CPA_MASK);

		link_control |=  spa_mask;

		ret = intel_set_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask);
@@ -345,7 +353,6 @@ static int intel_link_power_up(struct sdw_intel *sdw)
			goto out;
		}

	if (!*shim_mask) {
		/* SyncCPU will change once link is active */
		ret = intel_wait_bit(shim, SDW_SHIM_SYNC,
				     SDW_SHIM_SYNC_SYNCCPU, 0);
@@ -483,7 +490,7 @@ static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)

static int intel_link_power_down(struct sdw_intel *sdw)
{
	int link_control, spa_mask, cpa_mask;
	u32 link_control, spa_mask, cpa_mask;
	unsigned int link_id = sdw->instance;
	void __iomem *shim = sdw->link_res->shim;
	u32 *shim_mask = sdw->link_res->shim_mask;
@@ -493,24 +500,39 @@ static int intel_link_power_down(struct sdw_intel *sdw)

	intel_shim_master_ip_to_glue(sdw);

	if (!(*shim_mask & BIT(link_id)))
		dev_err(sdw->cdns.dev,
			"%s: Unbalanced power-up/down calls\n", __func__);

	*shim_mask &= ~BIT(link_id);

	if (!*shim_mask) {

		dev_dbg(sdw->cdns.dev, "%s: powering down all links\n", __func__);

		/* Link power down sequence */
		link_control = intel_readl(shim, SDW_SHIM_LCTL);
	spa_mask = ~(SDW_SHIM_LCTL_SPA << link_id);
	cpa_mask = (SDW_SHIM_LCTL_CPA << link_id);

		/* only power-down enabled links */
		spa_mask = (~sdw->link_res->link_mask) <<
			SDW_REG_SHIFT(SDW_SHIM_LCTL_SPA_MASK);
		cpa_mask = sdw->link_res->link_mask <<
			SDW_REG_SHIFT(SDW_SHIM_LCTL_CPA_MASK);

		link_control &=  spa_mask;

		ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask);
	}

	if (!(*shim_mask & BIT(link_id)))
		dev_err(sdw->cdns.dev,
			"%s: Unbalanced power-up/down calls\n", __func__);

	*shim_mask &= ~BIT(link_id);
	link_control = intel_readl(shim, SDW_SHIM_LCTL);

	mutex_unlock(sdw->link_res->shim_lock);

	if (ret < 0)
	if (ret < 0) {
		dev_err(sdw->cdns.dev, "%s: could not power down link\n", __func__);

		return ret;
	}

	sdw->cdns.link_up = false;
	return 0;