lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20250915081811.GF8224@nxa18884-linux.ap.freescale.net>
Date: Mon, 15 Sep 2025 16:18:11 +0800
From: Peng Fan <peng.fan@....nxp.com>
To: "irving.ch.lin" <irving-ch.lin@...iatek.com>
Cc: Michael Turquette <mturquette@...libre.com>,
	Stephen Boyd <sboyd@...nel.org>, Rob Herring <robh@...nel.org>,
	Krzysztof Kozlowski <krzk+dt@...nel.org>,
	Conor Dooley <conor+dt@...nel.org>,
	Matthias Brugger <matthias.bgg@...il.com>,
	AngeloGioacchino Del Regno <angelogioacchino.delregno@...labora.com>,
	Ulf Hansson <ulf.hansson@...aro.org>,
	Richard Cochran <richardcochran@...il.com>,
	Qiqi Wang <qiqi.wang@...iatek.com>, linux-clk@...r.kernel.org,
	devicetree@...r.kernel.org, linux-kernel@...r.kernel.org,
	linux-arm-kernel@...ts.infradead.org,
	linux-mediatek@...ts.infradead.org, linux-pm@...r.kernel.org,
	netdev@...r.kernel.org,
	Project_Global_Chrome_Upstream_Group@...iatek.com,
	sirius.wang@...iatek.com, vince-wl.liu@...iatek.com,
	jh.hsu@...iatek.com
Subject: Re: [PATCH v2 4/4] pmdomain: mediatek: Add power domain driver for
 MT8189 SoC

On Fri, Sep 12, 2025 at 08:04:53PM +0800, irving.ch.lin wrote:
>From: Irving-ch Lin <irving-ch.lin@...iatek.com>
>
>Introduce a new power domain (pmd) driver for the MediaTek mt8189 SoC.
>This driver ports and refines the power domain framework, dividing
>hardware blocks (CPU, GPU, peripherals, etc.) into independent power
>domains for precise and energy-efficient power management.

This seems also mix cleanup and add new support into one patch.

>
>Signed-off-by: Irving-ch Lin <irving-ch.lin@...iatek.com>
>---
>+ */
>+#ifndef __PMDOMAIN_MEDIATEK_MT8189_SCPSYS_H
>+#define __PMDOMAIN_MEDIATEK_MT8189_SCPSYS_H
>+
>+#define MT8189_SPM_CONN_PWR_CON			0xe04
>+#define MT8189_SPM_AUDIO_PWR_CON		0xe18
>+#define MT8189_SPM_ADSP_TOP_PWR_CON		0xe1c
...
>+#define MT8189_PROT_EN_MMSYS_STA_1_VDE0			(BIT(13))
>+#define MT8189_PROT_EN_MMSYS_STA_0_VEN0			(BIT(12))
>+#define MT8189_PROT_EN_MMSYS_STA_1_VEN0			(BIT(12))
>+#define MT8189_PROT_EN_PERISYS_STA_0_AUDIO		(BIT(6))
>+#define MT8189_PROT_EN_PERISYS_STA_0_SSUSB		(BIT(7))

Nit: align all the macro definitions.

>+
>+enum {
> #include <dt-bindings/power/mt7623a-power.h>
> #include <dt-bindings/power/mt8173-power.h>
> 
>+#include "mt8189-scpsys.h"
>+
> #define MTK_POLL_DELAY_US   10
> #define MTK_POLL_TIMEOUT    USEC_PER_SEC
>+#define MTK_POLL_TIMEOUT_300MS		(300 * USEC_PER_MSEC)
>+#define MTK_POLL_IRQ_TIMEOUT		USEC_PER_SEC
>+#define MTK_POLL_HWV_PREPARE_CNT	2500
>+#define MTK_POLL_HWV_PREPARE_US		2
>+#define MTK_ACK_DELAY_US		50
>+#define MTK_RTFF_DELAY_US		10
>+#define MTK_STABLE_DELAY_US		100
>+
>+#define MTK_BUS_PROTECTION_RETY_TIMES	10
> 
> #define MTK_SCPD_ACTIVE_WAKEUP		BIT(0)
> #define MTK_SCPD_FWAIT_SRAM		BIT(1)
>+#define MTK_SCPD_SRAM_ISO		BIT(2)
>+#define MTK_SCPD_SRAM_SLP		BIT(3)
>+#define MTK_SCPD_BYPASS_INIT_ON		BIT(4)
>+#define MTK_SCPD_IS_PWR_CON_ON		BIT(5)
>+#define MTK_SCPD_HWV_OPS		BIT(6)
>+#define MTK_SCPD_NON_CPU_RTFF		BIT(7)
>+#define MTK_SCPD_PEXTP_PHY_RTFF		BIT(8)
>+#define MTK_SCPD_UFS_RTFF		BIT(9)
>+#define MTK_SCPD_RTFF_DELAY		BIT(10)
>+#define MTK_SCPD_IRQ_SAVE		BIT(11)
>+#define MTK_SCPD_ALWAYS_ON		BIT(12)
>+#define MTK_SCPD_KEEP_DEFAULT_OFF	BIT(13)
> #define MTK_SCPD_CAPS(_scpd, _x)	((_scpd)->data->caps & (_x))
> 
> #define SPM_VDE_PWR_CON			0x0210
>@@ -56,6 +82,15 @@
> #define PWR_ON_BIT			BIT(2)
> #define PWR_ON_2ND_BIT			BIT(3)
> #define PWR_CLK_DIS_BIT			BIT(4)
>+#define PWR_SRAM_CLKISO_BIT		BIT(5)
>+#define PWR_SRAM_ISOINT_B_BIT		BIT(6)
>+#define PWR_RTFF_SAVE			BIT(24)
>+#define PWR_RTFF_NRESTORE		BIT(25)
>+#define PWR_RTFF_CLK_DIS		BIT(26)
>+#define PWR_RTFF_SAVE_FLAG		BIT(27)
>+#define PWR_RTFF_UFS_CLK_DIS		BIT(28)
>+#define PWR_ACK				BIT(30)
>+#define PWR_ACK_2ND			BIT(31)

Align the code

> 
> #define PWR_STATUS_CONN			BIT(1)
> #define PWR_STATUS_DISP			BIT(3)
>@@ -78,10 +113,39 @@
> #define PWR_STATUS_HIF1			BIT(26)	/* MT7622 */
> #define PWR_STATUS_WB			BIT(27)	/* MT7622 */
> 
>+#define _BUS_PROT(_type, _set_ofs, _clr_ofs,			\
>+		_en_ofs, _sta_ofs, _mask, _ack_mask,		\
>+		_ignore_clr_ack, _ignore_subsys_clk) {		\
>+		.type = _type,					\
>+		.set_ofs = _set_ofs,				\
>+		.clr_ofs = _clr_ofs,				\
>+		.en_ofs = _en_ofs,				\
>+		.sta_ofs = _sta_ofs,				\
>+		.mask = _mask,					\
>+		.ack_mask = _ack_mask,				\
>+		.ignore_clr_ack = _ignore_clr_ack,		\
>+		.ignore_subsys_clk = _ignore_subsys_clk,		\
>+	}
>+
>+#define BUS_PROT_IGN(_type, _set_ofs, _clr_ofs,	\
>+		_en_ofs, _sta_ofs, _mask)		\
>+		_BUS_PROT(_type, _set_ofs, _clr_ofs,	\
>+		_en_ofs, _sta_ofs, _mask, _mask, true, false)
>+
>+#define BUS_PROT_SUBSYS_CLK_IGN(_type, _set_ofs, _clr_ofs,	\
>+		_en_ofs, _sta_ofs, _mask)		\
>+		_BUS_PROT(_type, _set_ofs, _clr_ofs,	\
>+		_en_ofs, _sta_ofs, _mask, _mask, true, true)
>+
>+#define TEST_BP_ACK(bp, val)	((val & bp->ack_mask) == bp->ack_mask)
>+#define scpsys_get_infracfg(pdev)	\
>+	syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "infracfg")

There are some mix usage, one place use this marco, others places
use the API. not understand why introducing this macro.

>+
> enum clk_id {
> 	CLK_NONE,
> 	CLK_MM,
> 	CLK_MFG,
>+	CLK_MFG_TOP,
> 	CLK_VENC,
> 	CLK_VENC_LT,
> 	CLK_ETHIF,
>@@ -89,6 +153,9 @@ enum clk_id {
> 	CLK_HIFSEL,
> 	CLK_JPGDEC,
> 	CLK_AUDIO,
>+	CLK_DISP_AO_CONFIG,
>+	CLK_DISP_DPC,
>+	CLK_MDP,
> 	CLK_MAX,
> };
> 
>@@ -96,6 +163,7 @@ static const char * const clk_names[] = {
> 	NULL,
> 	"mm",
> 	"mfg",
>+	"mfg_top",
> 	"venc",
> 	"venc_lt",
> 	"ethif",
>@@ -103,10 +171,27 @@ static const char * const clk_names[] = {
> 	"hif_sel",
> 	"jpgdec",
> 	"audio",
>+	"disp_ao_config",
>+	"disp_dpc",
>+	"mdp",
> 	NULL,
> };
> 
> #define MAX_CLKS	3
>+#define MAX_STEPS	4
>+#define MAX_SUBSYS_CLKS 20
>+
>+struct bus_prot {
>+	u32 type;
>+	u32 set_ofs;
>+	u32 clr_ofs;
>+	u32 en_ofs;
>+	u32 sta_ofs;
>+	u32 mask;
>+	u32 ack_mask;
>+	bool ignore_clr_ack;
>+	bool ignore_subsys_clk;
>+};
> 
> /**
>  * struct scp_domain_data - scp domain data for power on/off flow
>@@ -115,8 +200,12 @@ static const char * const clk_names[] = {
>  * @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.
>+ * @sram_slp_bits: The mask for sram sleep control bits.
>+ * @sram_slp_ack_bits: The mask for sram sleep control acked bits.
>  * @bus_prot_mask: The mask for single step bus protection.
>  * @clk_id: The basic clocks required by this power domain.
>+ * @subsys_clk_prefix: Clock names need to enable before access this subsys.
>+ * @bp_table: Bus protection table for this power domain.
>  * @caps: The flag for active wake-up action.
>  */
> struct scp_domain_data {
>@@ -125,9 +214,13 @@ struct scp_domain_data {
> 	int ctl_offs;
> 	u32 sram_pdn_bits;
> 	u32 sram_pdn_ack_bits;
>+	u32 sram_slp_bits;
>+	u32 sram_slp_ack_bits;
> 	u32 bus_prot_mask;
> 	enum clk_id clk_id[MAX_CLKS];
>-	u8 caps;
>+	const char *subsys_clk_prefix;
>+	struct bus_prot bp_table[MAX_STEPS];
>+	u32 caps;
> };
> 
> struct scp;
>@@ -136,8 +229,11 @@ struct scp_domain {
> 	struct generic_pm_domain genpd;
> 	struct scp *scp;
> 	struct clk *clk[MAX_CLKS];
>+	struct clk *subsys_clk[MAX_SUBSYS_CLKS];
> 	const struct scp_domain_data *data;
> 	struct regulator *supply;
>+	bool rtff_flag;
>+	bool boot_status;
> };
> 
> struct scp_ctrl_reg {
>@@ -153,6 +249,8 @@ struct scp {
> 	struct regmap *infracfg;
> 	struct scp_ctrl_reg ctrl_reg;
> 	bool bus_prot_reg_update;
>+	struct regmap **bp_regmap;
>+	int num_bp;
> };
> 
> struct scp_subdomain {
>@@ -167,6 +265,8 @@ struct scp_soc_data {
> 	int num_subdomains;
> 	const struct scp_ctrl_reg regs;
> 	bool bus_prot_reg_update;
>+	const char **bp_list;
>+	int num_bp;
> };
> 
> static int scpsys_domain_is_on(struct scp_domain *scpd)
>@@ -191,6 +291,21 @@ static int scpsys_domain_is_on(struct scp_domain *scpd)
> 	return -EINVAL;
> }
> 
>+static bool scpsys_pwr_ack_is_on(struct scp_domain *scpd)
>+{
>+	u32 status = readl(scpd->scp->base + scpd->data->ctl_offs) & PWR_ACK;
>+
>+	return status ? true : false;
>+}
>+
>+static bool scpsys_pwr_ack_2nd_is_on(struct scp_domain *scpd)
>+{
>+	u32 status = readl(scpd->scp->base + scpd->data->ctl_offs) &
>+		     PWR_ACK_2ND;
>+
>+	return status ? true : false;
>+}
>+
> static int scpsys_regulator_enable(struct scp_domain *scpd)
> {
> 	if (!scpd->supply)
>@@ -233,11 +348,19 @@ static int scpsys_clk_enable(struct clk *clk[], int max_num)
> static int scpsys_sram_enable(struct scp_domain *scpd, void __iomem *ctl_addr)
> {
> 	u32 val;
>-	u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
>+	u32 ack_mask, ack_sta;
> 	int tmp;
> 
>-	val = readl(ctl_addr);
>-	val &= ~scpd->data->sram_pdn_bits;
>+	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_SRAM_SLP)) {
>+		ack_mask = scpd->data->sram_slp_ack_bits;
>+		ack_sta = ack_mask;
>+		val = readl(ctl_addr) | scpd->data->sram_slp_bits;
>+	} else {
>+		ack_mask = scpd->data->sram_pdn_ack_bits;
>+		ack_sta = 0;
>+		val = readl(ctl_addr) & ~scpd->data->sram_pdn_bits;
>+	}
>+
> 	writel(val, ctl_addr);
> 
> 	/* Either wait until SRAM_PDN_ACK all 0 or have a force wait */
>@@ -251,35 +374,184 @@ static int scpsys_sram_enable(struct scp_domain *scpd, void __iomem *ctl_addr)
> 	} else {
> 		/* Either wait until SRAM_PDN_ACK all 1 or 0 */
> 		int ret = readl_poll_timeout(ctl_addr, tmp,
>-				(tmp & pdn_ack) == 0,
>+				(tmp & ack_mask) == ack_sta,
> 				MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
> 		if (ret < 0)
> 			return ret;
> 	}
> 
>+	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_SRAM_ISO)) {
>+		val = readl(ctl_addr) | PWR_SRAM_ISOINT_B_BIT;
>+		writel(val, ctl_addr);
>+		udelay(1);

Add a comment on why delay 1us.

>+		val &= ~PWR_SRAM_CLKISO_BIT;
>+		writel(val, ctl_addr);
>+	}
>+
> 	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;
>+	u32 ack_mask, ack_sta;
> 	int tmp;
> 
>-	val = readl(ctl_addr);
>-	val |= scpd->data->sram_pdn_bits;
>+	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_SRAM_ISO)) {
>+		val = readl(ctl_addr) | PWR_SRAM_CLKISO_BIT;
>+		writel(val, ctl_addr);
>+		val &= ~PWR_SRAM_ISOINT_B_BIT;
>+		writel(val, ctl_addr);
>+		udelay(1);

Ditto.

>+	}
>+
>+	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_SRAM_SLP)) {
>+		ack_mask = scpd->data->sram_slp_ack_bits;
>+		ack_sta = 0;
>+		val = readl(ctl_addr) & ~scpd->data->sram_slp_bits;
>+	} else {
>+		ack_mask = scpd->data->sram_pdn_ack_bits;
>+		ack_sta = ack_mask;
>+		val = readl(ctl_addr) | 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,
>+			(tmp & ack_mask) == ack_sta,
> 			MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
> }
> 
>-static int scpsys_bus_protect_enable(struct scp_domain *scpd)
>+static int set_bus_protection(struct regmap *map, struct bus_prot *bp)
>+{
>+	u32 val = 0;
>+	int retry = 0;
>+	int ret = 0;
>+
>+	while (retry <= MTK_BUS_PROTECTION_RETY_TIMES) {
>+		if (bp->set_ofs)
>+			regmap_write(map,  bp->set_ofs, bp->mask);
>+		else
>+			regmap_update_bits(map, bp->en_ofs,
>+					   bp->mask, bp->mask);
>+
>+		/* check bus protect enable setting */
>+		regmap_read(map, bp->en_ofs, &val);
>+		if ((val & bp->mask) == bp->mask)
>+			break;
>+
>+		retry++;
>+	}
>+
>+	ret = regmap_read_poll_timeout_atomic(map, bp->sta_ofs, val,

Could non atomic version be used?

>+					      TEST_BP_ACK(bp, val),
>+					      MTK_POLL_DELAY_US,
>+					      MTK_POLL_TIMEOUT);
>+	if (ret < 0) {
>+		pr_err("%s val=0x%x, mask=0x%x, (val & mask)=0x%x\n",
>+		       __func__, val, bp->ack_mask, (val & bp->ack_mask));
>+	}
>+
>+	return ret;
>+}
>+
>+static int clear_bus_protection(struct regmap *map, struct bus_prot *bp)
>+{
>+	u32 val = 0;
>+	int ret = 0;
>+
>+	if (bp->clr_ofs)
>+		regmap_write(map, bp->clr_ofs, bp->mask);
>+	else
>+		regmap_update_bits(map, bp->en_ofs, bp->mask, 0);
>+
>+	if (bp->ignore_clr_ack)
>+		return 0;
>+
>+	ret = regmap_read_poll_timeout_atomic(map, bp->sta_ofs, val,

Ditto.

>+					      !(val & bp->ack_mask),
>+					      MTK_POLL_DELAY_US,
>+					      MTK_POLL_TIMEOUT);
>+	if (ret < 0) {
>+		pr_err("%s val=0x%x, mask=0x%x, (val & mask)=0x%x\n",
>+		       __func__, val, bp->ack_mask, (val & bp->ack_mask));
>+	}
>+	return ret;
>+}
>+
>+static int scpsys_bus_protect_table_disable(struct scp_domain *scpd,
>+					    unsigned int index,
>+					    bool ignore_subsys_clk)
>+{
>+	struct scp *scp = scpd->scp;
>+	const struct bus_prot *bp_table = scpd->data->bp_table;
>+	int ret = 0;
>+	int i;
>+
>+	for (i = index; i >= 0; i--) {
>+		struct regmap *map;
>+		struct bus_prot bp = bp_table[i];
>+
>+		if (bp.type == 0 || bp.type >= scp->num_bp)
>+			continue;
>+
>+		if (ignore_subsys_clk != bp.ignore_subsys_clk)
>+			continue;
>+
>+		map = scp->bp_regmap[bp.type];
>+		if (!map)
>+			continue;
>+
>+		ret = clear_bus_protection(map, &bp);
>+		if (ret)
>+			break;
>+	}
>+
>+	return ret;
>+}
>+
>+static int scpsys_bus_protect_table_enable(struct scp_domain *scpd,
>+					   bool ignore_subsys_clk)
>+{
>+	struct scp *scp = scpd->scp;
>+	const struct bus_prot *bp_table = scpd->data->bp_table;
>+	int ret = 0;
>+	int i;
>+
>+	for (i = 0; i < MAX_STEPS; i++) {
>+		struct regmap *map;
>+		struct bus_prot bp = bp_table[i];
>+
>+		if (bp.type == 0 || bp.type >= scp->num_bp)
>+			continue;
>+
>+		if (ignore_subsys_clk != bp.ignore_subsys_clk)
>+			continue;
>+
>+		map = scp->bp_regmap[bp.type];
>+		if (!map)
>+			continue;
>+
>+		ret = set_bus_protection(map, &bp);
>+		if (ret) {
>+			scpsys_bus_protect_table_disable(scpd, i,
>+							 ignore_subsys_clk);
>+			return ret;
>+		}
>+	}
>+
>+	return ret;
>+}
>+
>+static int scpsys_bus_protect_enable(struct scp_domain *scpd,
>+				     bool ignore_subsys_clk)
> {
> 	struct scp *scp = scpd->scp;
> 
>+	if (scp->bp_regmap && scp->num_bp > 0)
>+		return scpsys_bus_protect_table_enable(scpd,
>+						       ignore_subsys_clk);
>+
> 	if (!scpd->data->bus_prot_mask)
> 		return 0;
> 
>@@ -288,10 +560,15 @@ static int scpsys_bus_protect_enable(struct scp_domain *scpd)
> 			scp->bus_prot_reg_update);
> }
> 
>-static int scpsys_bus_protect_disable(struct scp_domain *scpd)
>+static int scpsys_bus_protect_disable(struct scp_domain *scpd,
>+				      bool ignore_subsys_clk)
> {
> 	struct scp *scp = scpd->scp;
> 
>+	if (scp->bp_regmap && scp->num_bp > 0)
>+		return scpsys_bus_protect_table_disable(scpd, MAX_STEPS - 1,
>+							ignore_subsys_clk);
>+
> 	if (!scpd->data->bus_prot_mask)
> 		return 0;
> 
>@@ -307,6 +584,11 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
> 	void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
> 	u32 val;
> 	int ret, tmp;
>+	bool pwr_ack;
>+
>+	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_KEEP_DEFAULT_OFF) &&
>+	    !scpd->boot_status)
>+		return 0;
> 
> 	ret = scpsys_regulator_enable(scpd);
> 	if (ret < 0)
>@@ -320,34 +602,121 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
> 	val = readl(ctl_addr);
> 	val |= PWR_ON_BIT;
> 	writel(val, ctl_addr);
>+	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_IS_PWR_CON_ON)) {
>+		ret = readx_poll_timeout_atomic(scpsys_pwr_ack_is_on,

Ditto.

>+						scpd, pwr_ack, pwr_ack,
>+						MTK_POLL_DELAY_US,
>+						MTK_POLL_TIMEOUT);
>+		if (ret < 0)
>+			goto err_pwr_ack;
>+
>+		udelay(MTK_ACK_DELAY_US);
>+	}
>+
> 	val |= PWR_ON_2ND_BIT;
> 	writel(val, ctl_addr);
> 
> 	/* wait until PWR_ACK = 1 */
>-	ret = readx_poll_timeout(scpsys_domain_is_on, scpd, tmp, tmp > 0,
>-				 MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
>+	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_IS_PWR_CON_ON))
>+		ret = readx_poll_timeout_atomic(scpsys_pwr_ack_2nd_is_on,

Ditto.

>+						scpd, pwr_ack, pwr_ack,
>+						MTK_POLL_DELAY_US,
>+						MTK_POLL_TIMEOUT);
>+	else
>+		ret = readx_poll_timeout(scpsys_domain_is_on,
>+					 scpd, tmp, tmp > 0,
>+					 MTK_POLL_DELAY_US,
>+					 MTK_POLL_TIMEOUT);
> 	if (ret < 0)
> 		goto err_pwr_ack;
> 
>+	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_PEXTP_PHY_RTFF) && scpd->rtff_flag) {
>+		val |= PWR_RTFF_CLK_DIS;
>+		writel(val, ctl_addr);
>+	}
>+
> 	val &= ~PWR_CLK_DIS_BIT;
> 	writel(val, ctl_addr);
> 
> 	val &= ~PWR_ISO_BIT;
> 	writel(val, ctl_addr);
> 
>+	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_RTFF_DELAY) && scpd->rtff_flag)
>+		udelay(MTK_RTFF_DELAY_US);
>+
> 	val |= PWR_RST_B_BIT;
> 	writel(val, ctl_addr);
> 
>-	ret = scpsys_sram_enable(scpd, ctl_addr);
>+	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_NON_CPU_RTFF)) {
>+		val = readl(ctl_addr);
>+		if (val & PWR_RTFF_SAVE_FLAG) {
>+			val &= ~PWR_RTFF_SAVE_FLAG;
>+			writel(val, ctl_addr);
>+
>+			val |= PWR_RTFF_CLK_DIS;
>+			writel(val, ctl_addr);
>+
>+			val &= ~PWR_RTFF_NRESTORE;
>+			writel(val, ctl_addr);
>+
>+			val |= PWR_RTFF_NRESTORE;
>+			writel(val, ctl_addr);
>+
>+			val &= ~PWR_RTFF_CLK_DIS;
>+			writel(val, ctl_addr);
>+		}
>+	} else if (MTK_SCPD_CAPS(scpd, MTK_SCPD_PEXTP_PHY_RTFF)) {
>+		val = readl(ctl_addr);
>+		if (val & PWR_RTFF_SAVE_FLAG) {
>+			val &= ~PWR_RTFF_SAVE_FLAG;
>+			writel(val, ctl_addr);
>+
>+			val &= ~PWR_RTFF_NRESTORE;
>+			writel(val, ctl_addr);
>+
>+			val |= PWR_RTFF_NRESTORE;
>+			writel(val, ctl_addr);
>+
>+			val &= ~PWR_RTFF_CLK_DIS;
>+			writel(val, ctl_addr);
>+		}
>+	} else if (MTK_SCPD_CAPS(scpd, MTK_SCPD_UFS_RTFF) &&
>+		   scpd->rtff_flag) {
>+		val |= PWR_RTFF_UFS_CLK_DIS;
>+		writel(val, ctl_addr);
>+
>+		val &= ~PWR_RTFF_NRESTORE;
>+		writel(val, ctl_addr);
>+
>+		val |= PWR_RTFF_NRESTORE;
>+		writel(val, ctl_addr);
>+
>+		val &= ~PWR_RTFF_UFS_CLK_DIS;
>+		writel(val, ctl_addr);
>+
>+		scpd->rtff_flag = false;
>+	}
>+
>+	ret = scpsys_bus_protect_disable(scpd, true);
> 	if (ret < 0)
> 		goto err_pwr_ack;
> 
>-	ret = scpsys_bus_protect_disable(scpd);
>+	ret = scpsys_clk_enable(scpd->subsys_clk, MAX_SUBSYS_CLKS);
> 	if (ret < 0)
> 		goto err_pwr_ack;
> 
>+	ret = scpsys_sram_enable(scpd, ctl_addr);
>+	if (ret < 0)
>+		goto err_sram_enable;
>+
>+	ret = scpsys_bus_protect_disable(scpd, false);
>+	if (ret < 0)
>+		goto err_sram_enable;
>+
> 	return 0;
> 
>+err_sram_enable:
>+	scpsys_clk_disable(scpd->subsys_clk, MAX_SUBSYS_CLKS);
> err_pwr_ack:
> 	scpsys_clk_disable(scpd->clk, MAX_CLKS);
> err_clk:
>@@ -365,8 +734,9 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
> 	void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
> 	u32 val;
> 	int ret, tmp;
>+	bool pwr_ack;
> 
>-	ret = scpsys_bus_protect_enable(scpd);
>+	ret = scpsys_bus_protect_enable(scpd, false);
> 	if (ret < 0)
> 		goto out;
> 
>@@ -374,11 +744,53 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
> 	if (ret < 0)
> 		goto out;
> 
>+	scpsys_clk_disable(scpd->subsys_clk, MAX_SUBSYS_CLKS);
>+
>+	ret = scpsys_bus_protect_enable(scpd, true);
>+	if (ret < 0)
>+		goto out;
>+
> 	/* subsys power off */
> 	val = readl(ctl_addr);
>+
>+	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_NON_CPU_RTFF) ||
>+	    MTK_SCPD_CAPS(scpd, MTK_SCPD_PEXTP_PHY_RTFF)) {
>+		val |= PWR_RTFF_CLK_DIS;
>+		writel(val, ctl_addr);
>+
>+		val |= PWR_RTFF_SAVE;
>+		writel(val, ctl_addr);
>+
>+		val &= ~PWR_RTFF_SAVE;
>+		writel(val, ctl_addr);
>+
>+		val &= ~PWR_RTFF_CLK_DIS;
>+		writel(val, ctl_addr);
>+
>+		val |= PWR_RTFF_SAVE_FLAG;
>+		writel(val, ctl_addr);
>+	} else if (MTK_SCPD_CAPS(scpd, MTK_SCPD_UFS_RTFF)) {
>+		val |= PWR_RTFF_UFS_CLK_DIS;
>+		writel(val, ctl_addr);
>+
>+		val |= PWR_RTFF_SAVE;
>+		writel(val, ctl_addr);
>+
>+		val &= ~PWR_RTFF_SAVE;
>+		writel(val, ctl_addr);
>+
>+		val &= ~PWR_RTFF_UFS_CLK_DIS;
>+		writel(val, ctl_addr);
>+		if (MTK_SCPD_CAPS(scpd, MTK_SCPD_UFS_RTFF))
>+			scpd->rtff_flag = true;
>+	}
>+
> 	val |= PWR_ISO_BIT;
> 	writel(val, ctl_addr);
> 
>+	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_RTFF_DELAY) && scpd->rtff_flag)
>+		udelay(1);

Add comment on delay 1us.

>+
> 	val &= ~PWR_RST_B_BIT;
> 	writel(val, ctl_addr);
> 
>@@ -388,12 +800,29 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
> 	val &= ~PWR_ON_BIT;
> 	writel(val, ctl_addr);
> 
>+	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_IS_PWR_CON_ON)) {
>+		ret = readx_poll_timeout_atomic(scpsys_pwr_ack_is_on,

Non atomic version?

>+						scpd, pwr_ack, !pwr_ack,
>+						MTK_POLL_DELAY_US,
>+						MTK_POLL_TIMEOUT);
>+		if (ret < 0)
>+			goto out;
>+	}
>+
> 	val &= ~PWR_ON_2ND_BIT;
> 	writel(val, ctl_addr);
> 
> 	/* wait until PWR_ACK = 0 */
>-	ret = readx_poll_timeout(scpsys_domain_is_on, scpd, tmp, tmp == 0,
>-				 MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
>+	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_IS_PWR_CON_ON))
>+		ret = readx_poll_timeout_atomic(scpsys_pwr_ack_2nd_is_on,
>+						scpd, pwr_ack, !pwr_ack,
>+						MTK_POLL_DELAY_US,
>+						MTK_POLL_TIMEOUT);
>+	else
>+		ret = readx_poll_timeout(scpsys_domain_is_on,
>+					 scpd, tmp, tmp == 0,
>+					 MTK_POLL_DELAY_US,
>+					 MTK_POLL_TIMEOUT);
> 	if (ret < 0)
> 		goto out;
> 
>@@ -419,54 +848,145 @@ static void init_clks(struct platform_device *pdev, struct clk **clk)
> 		clk[i] = devm_clk_get(&pdev->dev, clk_names[i]);
> }
> 
>+static int init_subsys_clks(struct platform_device *pdev,
>+			    const char *prefix, struct clk **clk)
>+{
>+	struct device_node *node = pdev->dev.of_node;
>+	u32 prefix_len, sub_clk_cnt = 0;
>+	struct property *prop;
>+	const char *clk_name;
>+
>+	if (!node) {
>+		dev_err(&pdev->dev, "Cannot find scpsys node: %ld\n",
>+			PTR_ERR(node));
>+		return PTR_ERR(node);
>+	}
>+
>+	prefix_len = strlen(prefix);
>+
>+	of_property_for_each_string(node, "clock-names", prop, clk_name) {
>+		if (!strncmp(clk_name, prefix, prefix_len) &&
>+		    (strlen(clk_name) > prefix_len + 1) &&
>+		    (clk_name[prefix_len] == '-')) {
>+			if (sub_clk_cnt >= MAX_SUBSYS_CLKS) {
>+				dev_err(&pdev->dev,
>+					"subsys clk out of range %d\n",
>+					sub_clk_cnt);
>+				return -EINVAL;
>+			}
>+
>+			clk[sub_clk_cnt] = devm_clk_get(&pdev->dev, clk_name);
>+
>+			if (IS_ERR(clk[sub_clk_cnt])) {
>+				dev_err(&pdev->dev,
>+					"Subsys clk get fail %ld\n",
>+					PTR_ERR(clk[sub_clk_cnt]));
>+				return PTR_ERR(clk[sub_clk_cnt]);
>+			}
>+			sub_clk_cnt++;
>+		}
>+	}
>+
>+	return sub_clk_cnt;
>+}
>+
>+static int mtk_pd_get_regmap(struct platform_device *pdev,
>+			     struct regmap **regmap,
>+			     const char *name)
>+{
>+	*regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, name);
>+	if (PTR_ERR(*regmap) == -ENODEV) {
>+		dev_notice(&pdev->dev, "%s regmap is null(%ld)\n",
>+			   name, PTR_ERR(*regmap));
>+		*regmap = NULL;
>+	} else if (IS_ERR(*regmap)) {
>+		dev_notice(&pdev->dev, "Cannot find %s controller: %ld\n",
>+			   name, PTR_ERR(*regmap));
>+		return PTR_ERR(*regmap);
>+	}
>+
>+	return 0;
>+}
>+
>+static bool scpsys_get_boot_status(struct scp_domain *scpd)
>+{
>+	if (MTK_SCPD_CAPS(scpd, MTK_SCPD_IS_PWR_CON_ON))
>+		return scpsys_pwr_ack_is_on(scpd) &&
>+		       scpsys_pwr_ack_2nd_is_on(scpd);
>+	return (scpsys_domain_is_on(scpd) > 0) ? true : false;
>+}
>+
> static struct scp *init_scp(struct platform_device *pdev,
>-			const struct scp_domain_data *scp_domain_data, int num,
>-			const struct scp_ctrl_reg *scp_ctrl_reg,
>-			bool bus_prot_reg_update)
>+		     const struct scp_soc_data *soc)

Align. scripts/checkpatch.pl should be able to report the warnings.

> {
> 	struct genpd_onecell_data *pd_data;
>+	struct resource *res;
> 	int i, j;
> 	struct scp *scp;
> 	struct clk *clk[CLK_MAX];
>+	int ret;
> 
> 	scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
> 	if (!scp)
> 		return ERR_PTR(-ENOMEM);
> 
>-	scp->ctrl_reg.pwr_sta_offs = scp_ctrl_reg->pwr_sta_offs;
>-	scp->ctrl_reg.pwr_sta2nd_offs = scp_ctrl_reg->pwr_sta2nd_offs;
>+	scp->ctrl_reg.pwr_sta_offs = soc->regs.pwr_sta_offs;
>+	scp->ctrl_reg.pwr_sta2nd_offs = soc->regs.pwr_sta2nd_offs;
> 
>-	scp->bus_prot_reg_update = bus_prot_reg_update;
>+	scp->bus_prot_reg_update = soc->bus_prot_reg_update;
> 
> 	scp->dev = &pdev->dev;
> 
>-	scp->base = devm_platform_ioremap_resource(pdev, 0);
>+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>+	scp->base = devm_ioremap_resource(&pdev->dev, res);

Not sure why change this. The same range are also mapped by others?


> 	if (IS_ERR(scp->base))
> 		return ERR_CAST(scp->base);
> 
>-	scp->domains = devm_kcalloc(&pdev->dev,
>-				num, sizeof(*scp->domains), GFP_KERNEL);
>+	scp->domains = devm_kcalloc(&pdev->dev, soc->num_domains,
>+				    sizeof(*scp->domains), GFP_KERNEL);
> 	if (!scp->domains)
> 		return ERR_PTR(-ENOMEM);
> 
> 	pd_data = &scp->pd_data;
> 
>-	pd_data->domains = devm_kcalloc(&pdev->dev,
>-			num, sizeof(*pd_data->domains), GFP_KERNEL);
>+	pd_data->domains = devm_kcalloc(&pdev->dev, soc->num_domains,
>+					sizeof(*pd_data->domains),
>+					GFP_KERNEL);
> 	if (!pd_data->domains)
> 		return ERR_PTR(-ENOMEM);
> 
>-	scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
>-			"infracfg");
>-	if (IS_ERR(scp->infracfg)) {
>-		dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
>+	if (soc->bp_list && soc->num_bp > 0) {
>+		scp->num_bp = soc->num_bp;
>+		scp->bp_regmap = devm_kcalloc(&pdev->dev, scp->num_bp,
>+					      sizeof(*scp->bp_regmap),
>+					      GFP_KERNEL);
>+		if (!scp->bp_regmap)
>+			return ERR_PTR(-ENOMEM);
>+
>+		/*
>+		 * get bus prot regmap from dts node,
>+		 * 0 means invalid bus type
>+		 */
>+		for (i = 1; i < scp->num_bp; i++) {
>+			ret = mtk_pd_get_regmap(pdev, &scp->bp_regmap[i],
>+						soc->bp_list[i]);
>+			if (ret)
>+				return ERR_PTR(ret);
>+		}
>+	} else {
>+		scp->infracfg = scpsys_get_infracfg(pdev);
>+
>+		if (IS_ERR(scp->infracfg)) {
>+			dev_err(&pdev->dev,
>+				"Cannot find infracfg controller: %ld\n",
> 				PTR_ERR(scp->infracfg));
>-		return ERR_CAST(scp->infracfg);
>+			return ERR_CAST(scp->infracfg);
>+		}
> 	}
> 
>-	for (i = 0; i < num; i++) {
>+	for (i = 0; i < soc->num_domains; i++) {
> 		struct scp_domain *scpd = &scp->domains[i];
>-		const struct scp_domain_data *data = &scp_domain_data[i];
>+		const struct scp_domain_data *data = &soc->domains[i];
> 
> 		scpd->supply = devm_regulator_get_optional(&pdev->dev, data->name);
> 		if (IS_ERR(scpd->supply)) {
>@@ -477,14 +997,14 @@ static struct scp *init_scp(struct platform_device *pdev,
> 		}
> 	}
> 
>-	pd_data->num_domains = num;
>+	pd_data->num_domains = soc->num_domains;
> 
> 	init_clks(pdev, clk);
> 
>-	for (i = 0; i < num; i++) {
>+	for (i = 0; i < soc->num_domains; i++) {
> 		struct scp_domain *scpd = &scp->domains[i];
> 		struct generic_pm_domain *genpd = &scpd->genpd;
>-		const struct scp_domain_data *data = &scp_domain_data[i];
>+		const struct scp_domain_data *data = &soc->domains[i];
> 
> 		pd_data->domains[i] = genpd;
> 		scpd->scp = scp;
>@@ -503,11 +1023,26 @@ static struct scp *init_scp(struct platform_device *pdev,
> 			scpd->clk[j] = c;
> 		}
> 
>+		if (data->subsys_clk_prefix) {
>+			ret = init_subsys_clks(pdev,
>+					       data->subsys_clk_prefix,
>+					       scpd->subsys_clk);
>+			if (ret < 0) {
>+				dev_notice(&pdev->dev,
>+					   "%s: subsys clk unavailable\n",
>+					   data->name);
>+				return ERR_PTR(ret);
>+			}
>+		}
> 		genpd->name = data->name;
> 		genpd->power_off = scpsys_power_off;
> 		genpd->power_on = scpsys_power_on;
> 		if (MTK_SCPD_CAPS(scpd, MTK_SCPD_ACTIVE_WAKEUP))
> 			genpd->flags |= GENPD_FLAG_ACTIVE_WAKEUP;
>+		if (MTK_SCPD_CAPS(scpd, MTK_SCPD_IRQ_SAVE))
>+			genpd->flags |= GENPD_FLAG_IRQ_SAFE;
>+		if (MTK_SCPD_CAPS(scpd, MTK_SCPD_ALWAYS_ON))
>+			genpd->flags |= GENPD_FLAG_ALWAYS_ON;
> 	}
> 
> 	return scp;
>@@ -530,8 +1065,17 @@ static void mtk_register_power_domains(struct platform_device *pdev,
> 		 * software.  The unused domains will be switched off during
> 		 * late_init time.
> 		 */
>-		on = !WARN_ON(genpd->power_on(genpd) < 0);
>-
>+		if (MTK_SCPD_CAPS(scpd, MTK_SCPD_KEEP_DEFAULT_OFF)) {
>+			scpd->boot_status = scpsys_get_boot_status(scpd);
>+			if (scpd->boot_status)
>+				on = !WARN_ON(genpd->power_on(genpd) < 0);
>+			else
>+				on = false;
>+		} else if (MTK_SCPD_CAPS(scpd, MTK_SCPD_BYPASS_INIT_ON)) {
>+			on = false;
>+		} else {
>+			on = !WARN_ON(genpd->power_on(genpd) < 0);
>+		}
> 		pm_genpd_init(genpd, NULL, !on);
> 	}
> 
>@@ -1009,6 +1553,328 @@ static const struct scp_subdomain scp_subdomain_mt8173[] = {
> 	{MT8173_POWER_DOMAIN_MFG_2D, MT8173_POWER_DOMAIN_MFG},
> };
> 
>+/*
>+ * MT8189 power domain support
>+ */
>+static const char *mt8189_bus_list[MT8189_BUS_TYPE_NUM] = {
>+	[MT8189_BP_IFR_TYPE] = "infra-infracfg-ao-reg-bus",
>+	[MT8189_BP_VLP_TYPE] = "vlpcfg-reg-bus",
>+	[MT8189_VLPCFG_REG_TYPE] = "vlpcfg-reg-bus",
>+	[MT8189_EMICFG_AO_MEM_TYPE] = "emicfg-ao-mem",
>+};
>+
>+static const struct scp_domain_data scp_domain_mt8189_spm_data[] = {
>+	[MT8189_POWER_DOMAIN_CONN] = {
>+		.name = "conn",
>+		.ctl_offs = MT8189_SPM_CONN_PWR_CON,
>+		.bp_table = {
>+			BUS_PROT_IGN(MT8189_BP_IFR_TYPE,
>+				     0x0c94, 0x0c98, 0x0c90, 0x0c9c,
>+				     MT8189_PROT_EN_MCU_STA_0_CONN),
>+			BUS_PROT_IGN(MT8189_BP_IFR_TYPE,
>+				     0x0c54, 0x0c58, 0x0c50, 0x0c5c,
>+				     MT8189_PROT_EN_INFRASYS_STA_1_CONN),
>+			BUS_PROT_IGN(MT8189_BP_IFR_TYPE,
>+				     0x0c94, 0x0c98, 0x0c90, 0x0c9c,
>+				     MT8189_PROT_EN_MCU_STA_0_CONN_2ND),
>+			BUS_PROT_IGN(MT8189_BP_IFR_TYPE,
>+				     0x0c44, 0x0c48, 0x0c40, 0x0c4c,
>+				     MT8189_PROT_EN_INFRASYS_STA_0_CONN),
>+		},
>+		.caps = MTK_SCPD_IS_PWR_CON_ON | MTK_SCPD_KEEP_DEFAULT_OFF,
>+	},
>+	[MT8189_POWER_DOMAIN_AUDIO] = {
>+		.name = "audio",
>+		.ctl_offs = MT8189_SPM_AUDIO_PWR_CON,
>+		.sram_pdn_bits = GENMASK(8, 8),
>+		.sram_pdn_ack_bits = GENMASK(12, 12),

You could use BIT, same applied the below GENMASK usage.

>+		.bp_table = {
>+			BUS_PROT_IGN(MT8189_BP_IFR_TYPE,
>+				     0x0c84, 0x0c88, 0x0c80, 0x0c8c,
>+				     MT8189_PROT_EN_PERISYS_STA_0_AUDIO),
>+		},
>+		.clk_id = {CLK_AUDIO},
>+		.caps = MTK_SCPD_IS_PWR_CON_ON,
>+	},
> /*
>  * scpsys driver init
>  */
>@@ -1098,6 +1977,9 @@ static const struct of_device_id of_scpsys_match_tbl[] = {
> 	}, {
> 		.compatible = "mediatek,mt8173-scpsys",
> 		.data = &mt8173_data,
>+	}, {
>+		.compatible = "mediatek,mt8189-scpsys",
>+		.data = &mt8189_spm_data,
> 	}, {
> 		/* sentinel */
> 	}
>@@ -1113,8 +1995,7 @@ static int scpsys_probe(struct platform_device *pdev)
> 
> 	soc = of_device_get_match_data(&pdev->dev);
> 
>-	scp = init_scp(pdev, soc->domains, soc->num_domains, &soc->regs,
>-			soc->bus_prot_reg_update);
>+	scp = init_scp(pdev, soc);

In the end, better separate your changes into small patches, mix cleanup
and new support is not easy to review.

Regards
Peng

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ