Commit 01d1a860 authored by Olof Johansson's avatar Olof Johansson
Browse files

Merge tag 'v5.4-next-soc' of...

Merge tag 'v5.4-next-soc' of https://git.kernel.org/pub/scm/linux/kernel/git/matthias.bgg/linux into arm/drivers

refactor code of mtk-scpsys

* tag 'v5.4-next-soc' of https://git.kernel.org/pub/scm/linux/kernel/git/matthias.bgg/linux:
  soc: mediatek: Refactor bus protection control
  soc: mediatek: Refactor sram control
  soc: mediatek: Refactor clock control
  soc: mediatek: Refactor regulator control
  soc: mediatek: Refactor polling timeout and documentation

Link: https://lore.kernel.org/r/294422a4-37b2-def5-5d32-8988f27c3a5b@gmail.com


Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parents 13a6c8ef 662c9d55
Loading
Loading
Loading
Loading
+146 −68
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@
#include <dt-bindings/power/mt8173-power.h>

#define MTK_POLL_DELAY_US   10
#define MTK_POLL_TIMEOUT    (jiffies_to_usecs(HZ))
#define MTK_POLL_TIMEOUT    USEC_PER_SEC

#define MTK_SCPD_ACTIVE_WAKEUP		BIT(0)
#define MTK_SCPD_FWAIT_SRAM		BIT(1)
@@ -108,6 +108,17 @@ static const char * const clk_names[] = {

#define MAX_CLKS	3

/**
 * struct scp_domain_data - scp domain data for power on/off flow
 * @name: The domain name.
 * @sta_mask: The mask for power on/off status bit.
 * @ctl_offs: The offset for main power control register.
 * @sram_pdn_bits: The mask for sram power control bits.
 * @sram_pdn_ack_bits: The mask for sram power control acked bits.
 * @bus_prot_mask: The mask for single step bus protection.
 * @clk_id: The basic clocks required by this power domain.
 * @caps: The flag for active wake-up action.
 */
struct scp_domain_data {
	const char *name;
	u32 sta_mask;
@@ -180,32 +191,132 @@ static int scpsys_domain_is_on(struct scp_domain *scpd)
	return -EINVAL;
}

static int scpsys_regulator_enable(struct scp_domain *scpd)
{
	if (!scpd->supply)
		return 0;

	return regulator_enable(scpd->supply);
}

static int scpsys_regulator_disable(struct scp_domain *scpd)
{
	if (!scpd->supply)
		return 0;

	return regulator_disable(scpd->supply);
}

static void scpsys_clk_disable(struct clk *clk[], int max_num)
{
	int i;

	for (i = max_num - 1; i >= 0; i--)
		clk_disable_unprepare(clk[i]);
}

static int scpsys_clk_enable(struct clk *clk[], int max_num)
{
	int i, ret = 0;

	for (i = 0; i < max_num && clk[i]; i++) {
		ret = clk_prepare_enable(clk[i]);
		if (ret) {
			scpsys_clk_disable(clk, i);
			break;
		}
	}

	return ret;
}

static int scpsys_sram_enable(struct scp_domain *scpd, void __iomem *ctl_addr)
{
	u32 val;
	u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
	int tmp;

	val = readl(ctl_addr);
	val &= ~scpd->data->sram_pdn_bits;
	writel(val, ctl_addr);

	/* Either wait until SRAM_PDN_ACK all 0 or have a force wait */
	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_FWAIT_SRAM)) {
		/*
		 * Currently, MTK_SCPD_FWAIT_SRAM is necessary only for
		 * MT7622_POWER_DOMAIN_WB and thus just a trivial setup
		 * is applied here.
		 */
		usleep_range(12000, 12100);
	} else {
		/* Either wait until SRAM_PDN_ACK all 1 or 0 */
		int ret = readl_poll_timeout(ctl_addr, tmp,
				(tmp & pdn_ack) == 0,
				MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
		if (ret < 0)
			return ret;
	}

	return 0;
}

static int scpsys_sram_disable(struct scp_domain *scpd, void __iomem *ctl_addr)
{
	u32 val;
	u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
	int tmp;

	val = readl(ctl_addr);
	val |= scpd->data->sram_pdn_bits;
	writel(val, ctl_addr);

	/* Either wait until SRAM_PDN_ACK all 1 or 0 */
	return readl_poll_timeout(ctl_addr, tmp,
			(tmp & pdn_ack) == pdn_ack,
			MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
}

static int scpsys_bus_protect_enable(struct scp_domain *scpd)
{
	struct scp *scp = scpd->scp;

	if (!scpd->data->bus_prot_mask)
		return 0;

	return mtk_infracfg_set_bus_protection(scp->infracfg,
			scpd->data->bus_prot_mask,
			scp->bus_prot_reg_update);
}

static int scpsys_bus_protect_disable(struct scp_domain *scpd)
{
	struct scp *scp = scpd->scp;

	if (!scpd->data->bus_prot_mask)
		return 0;

	return mtk_infracfg_clear_bus_protection(scp->infracfg,
			scpd->data->bus_prot_mask,
			scp->bus_prot_reg_update);
}

static int scpsys_power_on(struct generic_pm_domain *genpd)
{
	struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
	struct scp *scp = scpd->scp;
	void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
	u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
	u32 val;
	int ret, tmp;
	int i;

	if (scpd->supply) {
		ret = regulator_enable(scpd->supply);
		if (ret)
	ret = scpsys_regulator_enable(scpd);
	if (ret < 0)
		return ret;
	}

	for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) {
		ret = clk_prepare_enable(scpd->clk[i]);
		if (ret) {
			for (--i; i >= 0; i--)
				clk_disable_unprepare(scpd->clk[i]);

	ret = scpsys_clk_enable(scpd->clk, MAX_CLKS);
	if (ret)
		goto err_clk;
		}
	}

	/* subsys power on */
	val = readl(ctl_addr);
	val |= PWR_ON_BIT;
	writel(val, ctl_addr);
@@ -227,43 +338,20 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
	val |= PWR_RST_B_BIT;
	writel(val, ctl_addr);

	val &= ~scpd->data->sram_pdn_bits;
	writel(val, ctl_addr);

	/* Either wait until SRAM_PDN_ACK all 0 or have a force wait */
	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_FWAIT_SRAM)) {
		/*
		 * Currently, MTK_SCPD_FWAIT_SRAM is necessary only for
		 * MT7622_POWER_DOMAIN_WB and thus just a trivial setup is
		 * applied here.
		 */
		usleep_range(12000, 12100);

	} else {
		ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == 0,
					 MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
	ret = scpsys_sram_enable(scpd, ctl_addr);
	if (ret < 0)
		goto err_pwr_ack;
	}

	if (scpd->data->bus_prot_mask) {
		ret = mtk_infracfg_clear_bus_protection(scp->infracfg,
				scpd->data->bus_prot_mask,
				scp->bus_prot_reg_update);
		if (ret)
	ret = scpsys_bus_protect_disable(scpd);
	if (ret < 0)
		goto err_pwr_ack;
	}

	return 0;

err_pwr_ack:
	for (i = MAX_CLKS - 1; i >= 0; i--) {
		if (scpd->clk[i])
			clk_disable_unprepare(scpd->clk[i]);
	}
	scpsys_clk_disable(scpd->clk, MAX_CLKS);
err_clk:
	if (scpd->supply)
		regulator_disable(scpd->supply);
	scpsys_regulator_disable(scpd);

	dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name);

@@ -275,29 +363,19 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
	struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
	struct scp *scp = scpd->scp;
	void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
	u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
	u32 val;
	int ret, tmp;
	int i;

	if (scpd->data->bus_prot_mask) {
		ret = mtk_infracfg_set_bus_protection(scp->infracfg,
				scpd->data->bus_prot_mask,
				scp->bus_prot_reg_update);
		if (ret)
	ret = scpsys_bus_protect_enable(scpd);
	if (ret < 0)
		goto out;
	}

	val = readl(ctl_addr);
	val |= scpd->data->sram_pdn_bits;
	writel(val, ctl_addr);

	/* wait until SRAM_PDN_ACK all 1 */
	ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == pdn_ack,
				 MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
	ret = scpsys_sram_disable(scpd, ctl_addr);
	if (ret < 0)
		goto out;

	/* subsys power off */
	val = readl(ctl_addr);
	val |= PWR_ISO_BIT;
	writel(val, ctl_addr);

@@ -319,11 +397,11 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
	if (ret < 0)
		goto out;

	for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++)
		clk_disable_unprepare(scpd->clk[i]);
	scpsys_clk_disable(scpd->clk, MAX_CLKS);

	if (scpd->supply)
		regulator_disable(scpd->supply);
	ret = scpsys_regulator_disable(scpd);
	if (ret < 0)
		goto out;

	return 0;