Resend scpsys patches from v4[1].
Based on v5.1-rc1 with MT8183 dts v9 patch[2] and
MT8183 SMI dt-binding v6 patch[3].
[1] https://patchwork.kernel.org/patch/10792071/
[2] https://patchwork.kernel.org/patch/10856987/
[3] https://patchwork.kernel.org/patch/10816827/
changes since v4:
- add property to mt8183 smi-common
- seperate refactor patches and new add function
- add power controller device node
Weiyi Lu (14):
dt-bindings: mediatek: Add property to mt8183 smi-common
dt-bindings: soc: Add MT8183 power dt-bindings
soc: mediatek: Switch to SPDX license identifier
soc: mediatek: Refactor polling timeout and documentation
soc: mediatek: Refactor regulator control
soc: mediatek: Refactor clock control
soc: mediatek: Refactor sram control
soc: mediatek: Refactor bus protection control
soc: mediatek: Add basic_clk_name to scp_power_data
soc: mediatek: Add multiple step bus protection control
soc: mediatek: Add subsys clock control for bus protection
soc: mediatek: Add extra sram control
soc: mediatek: Add MT8183 scpsys support
arm64: dts: Add power controller device node of MT8183
.../mediatek,smi-common.txt | 2 +-
.../bindings/soc/mediatek/scpsys.txt | 14 +
arch/arm64/boot/dts/mediatek/mt8183.dtsi | 62 ++
drivers/soc/mediatek/Makefile | 2 +-
drivers/soc/mediatek/mtk-scpsys-ext.c | 99 +++
drivers/soc/mediatek/mtk-scpsys.c | 603 +++++++++++++++---
include/dt-bindings/power/mt8183-power.h | 26 +
include/linux/soc/mediatek/scpsys-ext.h | 39 ++
8 files changed, 757 insertions(+), 90 deletions(-)
create mode 100644 drivers/soc/mediatek/mtk-scpsys-ext.c
create mode 100644 include/dt-bindings/power/mt8183-power.h
create mode 100644 include/linux/soc/mediatek/scpsys-ext.h
Put bus protection enable and disable control in separate functions.
Signed-off-by: Weiyi Lu <[email protected]>
---
drivers/soc/mediatek/mtk-scpsys.c | 48 ++++++++++++++++++++++---------
1 file changed, 34 insertions(+), 14 deletions(-)
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index 65b734b40098..6bf846cb1893 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -279,6 +279,34 @@ static int scpsys_sram_disable(struct scp_domain *scpd, void __iomem *ctl_addr)
MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
}
+static int scpsys_bus_protect_enable(struct scp_domain *scpd)
+{
+ struct scp *scp = scpd->scp;
+ int ret = 0;
+
+ if (scpd->data->bus_prot_mask) {
+ ret = mtk_infracfg_set_bus_protection(scp->infracfg,
+ scpd->data->bus_prot_mask,
+ scp->bus_prot_reg_update);
+ }
+
+ return ret;
+}
+
+static int scpsys_bus_protect_disable(struct scp_domain *scpd)
+{
+ struct scp *scp = scpd->scp;
+ int ret = 0;
+
+ if (scpd->data->bus_prot_mask) {
+ ret = mtk_infracfg_clear_bus_protection(scp->infracfg,
+ scpd->data->bus_prot_mask,
+ scp->bus_prot_reg_update);
+ }
+
+ return ret;
+}
+
static int scpsys_power_on(struct generic_pm_domain *genpd)
{
struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
@@ -321,13 +349,9 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
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)
- goto err_pwr_ack;
- }
+ ret = scpsys_bus_protect_disable(scpd);
+ if (ret < 0)
+ goto err_pwr_ack;
return 0;
@@ -349,13 +373,9 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
u32 val;
int ret, tmp;
- 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)
- goto out;
- }
+ ret = scpsys_bus_protect_enable(scpd);
+ if (ret < 0)
+ goto out;
ret = scpsys_sram_disable(scpd, ctl_addr);
if (ret < 0)
--
2.18.0
Use USEC_PER_SEC to indicate the polling timeout directly.
And add documentation of scp_domain_data.
Signed-off-by: Weiyi Lu <[email protected]>
---
drivers/soc/mediatek/mtk-scpsys.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index 9f52f501178b..2855111b221a 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -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,18 @@ 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 clock needs to be enabled before enabling certain
+ * power domains.
+ * @caps: The flag for active wake-up action.
+ */
struct scp_domain_data {
const char *name;
u32 sta_mask;
--
2.18.0
Try to stop extending the clk_id or clk_names if there are
more and more new BASIC clocks. To get its own clocks by the
basic_clk_name of each power domain.
Signed-off-by: Weiyi Lu <[email protected]>
---
drivers/soc/mediatek/mtk-scpsys.c | 27 +++++++++++++++++++--------
1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index 6bf846cb1893..c6360de4e41e 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -118,6 +118,8 @@ static const char * const clk_names[] = {
* @bus_prot_mask: The mask for single step bus protection.
* @clk_id: The basic clock needs to be enabled before enabling certain
* power domains.
+ * @basic_clk_name: provide the same purpose with field "clk_id"
+ * by declaring basic clock prefix name rather than clk_id.
* @caps: The flag for active wake-up action.
*/
struct scp_domain_data {
@@ -128,6 +130,7 @@ struct scp_domain_data {
u32 sram_pdn_ack_bits;
u32 bus_prot_mask;
enum clk_id clk_id[MAX_CLKS];
+ const char *basic_clk_name[MAX_CLKS];
u8 caps;
};
@@ -499,16 +502,24 @@ static struct scp *init_scp(struct platform_device *pdev,
scpd->data = data;
- for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
- struct clk *c = clk[data->clk_id[j]];
+ if (data->clk_id[0]) {
+ for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
+ struct clk *c = clk[data->clk_id[j]];
- if (IS_ERR(c)) {
- dev_err(&pdev->dev, "%s: clk unavailable\n",
- data->name);
- return ERR_CAST(c);
- }
+ if (IS_ERR(c)) {
+ dev_err(&pdev->dev,
+ "%s: clk unavailable\n",
+ data->name);
+ return ERR_CAST(c);
+ }
- scpd->clk[j] = c;
+ scpd->clk[j] = c;
+ }
+ } else if (data->basic_clk_name[0]) {
+ for (j = 0; j < MAX_CLKS &&
+ data->basic_clk_name[j]; j++)
+ scpd->clk[j] = devm_clk_get(&pdev->dev,
+ data->basic_clk_name[j]);
}
genpd->name = data->name;
--
2.18.0
Both MT8183 & MT6765 have more control steps of bus protection
than previous project. And there add more bus protection registers
reside at infracfg & smi-common. Also add new APIs for multiple
step bus protection control with more customize arguments.
Signed-off-by: Weiyi Lu <[email protected]>
---
drivers/soc/mediatek/Makefile | 2 +-
drivers/soc/mediatek/mtk-scpsys-ext.c | 99 +++++++++++++++++++++++++
drivers/soc/mediatek/mtk-scpsys.c | 24 ++++++
include/linux/soc/mediatek/scpsys-ext.h | 39 ++++++++++
4 files changed, 163 insertions(+), 1 deletion(-)
create mode 100644 drivers/soc/mediatek/mtk-scpsys-ext.c
create mode 100644 include/linux/soc/mediatek/scpsys-ext.h
diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
index 64ce5eeaba32..b9dbad6b12f9 100644
--- a/drivers/soc/mediatek/Makefile
+++ b/drivers/soc/mediatek/Makefile
@@ -1,4 +1,4 @@
obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o
-obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
+obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o mtk-scpsys-ext.o
obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
diff --git a/drivers/soc/mediatek/mtk-scpsys-ext.c b/drivers/soc/mediatek/mtk-scpsys-ext.c
new file mode 100644
index 000000000000..f630edb2f65d
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-scpsys-ext.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Owen Chen <[email protected]>
+ */
+#include <linux/ktime.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/soc/mediatek/scpsys-ext.h>
+
+#define MTK_POLL_DELAY_US 10
+#define MTK_POLL_TIMEOUT USEC_PER_SEC
+
+static int set_bus_protection(struct regmap *map, u32 mask, u32 ack_mask,
+ u32 reg_set, u32 reg_sta, u32 reg_en)
+{
+ u32 val;
+
+ if (reg_set)
+ regmap_write(map, reg_set, mask);
+ else
+ regmap_update_bits(map, reg_en, mask, mask);
+
+ return regmap_read_poll_timeout(map, reg_sta,
+ val, (val & ack_mask) == ack_mask,
+ MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+}
+
+static int clear_bus_protection(struct regmap *map, u32 mask, u32 ack_mask,
+ u32 reg_clr, u32 reg_sta, u32 reg_en)
+{
+ u32 val;
+
+ if (reg_clr)
+ regmap_write(map, reg_clr, mask);
+ else
+ regmap_update_bits(map, reg_en, mask, 0);
+
+ return regmap_read_poll_timeout(map, reg_sta,
+ val, !(val & ack_mask),
+ MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+}
+
+int mtk_scpsys_ext_set_bus_protection(const struct bus_prot *bp_table,
+ struct regmap *infracfg, struct regmap *smi_common)
+{
+ int i;
+
+ for (i = 0; i < MAX_STEPS && bp_table[i].mask; i++) {
+ struct regmap *map;
+ int ret;
+
+ if (bp_table[i].type == IFR_TYPE)
+ map = infracfg;
+ else if (bp_table[i].type == SMI_TYPE)
+ map = smi_common;
+ else
+ return -EINVAL;
+
+ ret = set_bus_protection(map,
+ bp_table[i].mask, bp_table[i].mask,
+ bp_table[i].set_ofs, bp_table[i].sta_ofs,
+ bp_table[i].en_ofs);
+
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int mtk_scpsys_ext_clear_bus_protection(const struct bus_prot *bp_table,
+ struct regmap *infracfg, struct regmap *smi_common)
+{
+ int i;
+
+ for (i = MAX_STEPS - 1; i >= 0; i--) {
+ struct regmap *map;
+ int ret;
+
+ if (bp_table[i].type == IFR_TYPE)
+ map = infracfg;
+ else if (bp_table[i].type == SMI_TYPE)
+ map = smi_common;
+ else
+ return -EINVAL;
+
+ ret = clear_bus_protection(map,
+ bp_table[i].mask, bp_table[i].clr_ack_mask,
+ bp_table[i].clr_ofs, bp_table[i].sta_ofs,
+ bp_table[i].en_ofs);
+
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index c6360de4e41e..181bf7bce591 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -12,6 +12,7 @@
#include <linux/pm_domain.h>
#include <linux/regulator/consumer.h>
#include <linux/soc/mediatek/infracfg.h>
+#include <linux/soc/mediatek/scpsys-ext.h>
#include <dt-bindings/power/mt2701-power.h>
#include <dt-bindings/power/mt2712-power.h>
@@ -121,6 +122,7 @@ static const char * const clk_names[] = {
* @basic_clk_name: provide the same purpose with field "clk_id"
* by declaring basic clock prefix name rather than clk_id.
* @caps: The flag for active wake-up action.
+ * @bp_table: The mask table for multiple step bus protection.
*/
struct scp_domain_data {
const char *name;
@@ -132,6 +134,7 @@ struct scp_domain_data {
enum clk_id clk_id[MAX_CLKS];
const char *basic_clk_name[MAX_CLKS];
u8 caps;
+ struct bus_prot bp_table[MAX_STEPS];
};
struct scp;
@@ -155,6 +158,7 @@ struct scp {
struct device *dev;
void __iomem *base;
struct regmap *infracfg;
+ struct regmap *smi_common;
struct scp_ctrl_reg ctrl_reg;
bool bus_prot_reg_update;
};
@@ -291,6 +295,10 @@ static int scpsys_bus_protect_enable(struct scp_domain *scpd)
ret = mtk_infracfg_set_bus_protection(scp->infracfg,
scpd->data->bus_prot_mask,
scp->bus_prot_reg_update);
+ } else if (scpd->data->bp_table[0].mask) {
+ ret = mtk_scpsys_ext_set_bus_protection(scpd->data->bp_table,
+ scp->infracfg,
+ scp->smi_common);
}
return ret;
@@ -305,6 +313,11 @@ static int scpsys_bus_protect_disable(struct scp_domain *scpd)
ret = mtk_infracfg_clear_bus_protection(scp->infracfg,
scpd->data->bus_prot_mask,
scp->bus_prot_reg_update);
+ } else if (scpd->data->bp_table[0].mask) {
+ ret = mtk_scpsys_ext_clear_bus_protection(
+ scpd->data->bp_table,
+ scp->infracfg,
+ scp->smi_common);
}
return ret;
@@ -475,6 +488,17 @@ static struct scp *init_scp(struct platform_device *pdev,
return ERR_CAST(scp->infracfg);
}
+ scp->smi_common = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "smi_comm");
+
+ if (scp->smi_common == ERR_PTR(-ENODEV)) {
+ scp->smi_common = NULL;
+ } else if (IS_ERR(scp->smi_common)) {
+ dev_err(&pdev->dev, "Cannot find smi_common controller: %ld\n",
+ PTR_ERR(scp->smi_common));
+ return ERR_CAST(scp->smi_common);
+ }
+
for (i = 0; i < num; i++) {
struct scp_domain *scpd = &scp->domains[i];
const struct scp_domain_data *data = &scp_domain_data[i];
diff --git a/include/linux/soc/mediatek/scpsys-ext.h b/include/linux/soc/mediatek/scpsys-ext.h
new file mode 100644
index 000000000000..d0ed295c88a7
--- /dev/null
+++ b/include/linux/soc/mediatek/scpsys-ext.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __SOC_MEDIATEK_SCPSYS_EXT_H
+#define __SOC_MEDIATEK_SCPSYS_EXT_H
+
+#define MAX_STEPS 4
+
+#define BUS_PROT(_type, _set_ofs, _clr_ofs, \
+ _en_ofs, _sta_ofs, _mask, _clr_ack_mask) { \
+ .type = _type, \
+ .set_ofs = _set_ofs, \
+ .clr_ofs = _clr_ofs, \
+ .en_ofs = _en_ofs, \
+ .sta_ofs = _sta_ofs, \
+ .mask = _mask, \
+ .clr_ack_mask = _clr_ack_mask, \
+ }
+
+enum regmap_type {
+ IFR_TYPE,
+ SMI_TYPE,
+ MAX_REGMAP_TYPE,
+};
+
+struct bus_prot {
+ enum regmap_type type;
+ u32 set_ofs;
+ u32 clr_ofs;
+ u32 en_ofs;
+ u32 sta_ofs;
+ u32 mask;
+ u32 clr_ack_mask;
+};
+
+int mtk_scpsys_ext_set_bus_protection(const struct bus_prot *bp_table,
+ struct regmap *infracfg, struct regmap *smi_common);
+int mtk_scpsys_ext_clear_bus_protection(const struct bus_prot *bp_table,
+ struct regmap *infracfg, struct regmap *smi_common);
+
+#endif /* __SOC_MEDIATEK_SCPSYS_EXT_H */
--
2.18.0
Add scpsys driver for MT8183
Signed-off-by: Weiyi Lu <[email protected]>
---
drivers/soc/mediatek/mtk-scpsys.c | 226 ++++++++++++++++++++++++++++++
1 file changed, 226 insertions(+)
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index 94c10f69655d..f1d82cdb219e 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -20,6 +20,7 @@
#include <dt-bindings/power/mt7622-power.h>
#include <dt-bindings/power/mt7623a-power.h>
#include <dt-bindings/power/mt8173-power.h>
+#include <dt-bindings/power/mt8183-power.h>
#define MTK_POLL_DELAY_US 10
#define MTK_POLL_TIMEOUT USEC_PER_SEC
@@ -1141,6 +1142,217 @@ static const struct scp_subdomain scp_subdomain_mt8173[] = {
{MT8173_POWER_DOMAIN_MFG_2D, MT8173_POWER_DOMAIN_MFG},
};
+/*
+ * MT8183 power domain support
+ */
+
+static const struct scp_domain_data scp_domain_data_mt8183[] = {
+ [MT8183_POWER_DOMAIN_AUDIO] = {
+ .name = "audio",
+ .sta_mask = PWR_STATUS_AUDIO,
+ .ctl_offs = 0x0314,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .basic_clk_name = {"audio", "audio1", "audio2"},
+ },
+ [MT8183_POWER_DOMAIN_CONN] = {
+ .name = "conn",
+ .sta_mask = PWR_STATUS_CONN,
+ .ctl_offs = 0x032c,
+ .sram_pdn_bits = 0,
+ .sram_pdn_ack_bits = 0,
+ .bp_table = {
+ BUS_PROT(IFR_TYPE, 0x2a0, 0x2a4, 0, 0x228,
+ BIT(13) | BIT(14), BIT(13) | BIT(14)),
+ },
+ },
+ [MT8183_POWER_DOMAIN_MFG_ASYNC] = {
+ .name = "mfg_async",
+ .sta_mask = PWR_STATUS_MFG_ASYNC,
+ .ctl_offs = 0x0334,
+ .sram_pdn_bits = 0,
+ .sram_pdn_ack_bits = 0,
+ .basic_clk_name = {"mfg"},
+ },
+ [MT8183_POWER_DOMAIN_MFG] = {
+ .name = "mfg",
+ .sta_mask = PWR_STATUS_MFG,
+ .ctl_offs = 0x0338,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+ [MT8183_POWER_DOMAIN_MFG_CORE0] = {
+ .name = "mfg_core0",
+ .sta_mask = BIT(7),
+ .ctl_offs = 0x034c,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+ [MT8183_POWER_DOMAIN_MFG_CORE1] = {
+ .name = "mfg_core1",
+ .sta_mask = BIT(20),
+ .ctl_offs = 0x0310,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+ [MT8183_POWER_DOMAIN_MFG_2D] = {
+ .name = "mfg_2d",
+ .sta_mask = PWR_STATUS_MFG_2D,
+ .ctl_offs = 0x0348,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_table = {
+ BUS_PROT(IFR_TYPE, 0x2a8, 0x2ac, 0, 0x258,
+ BIT(19) | BIT(20) | BIT(21),
+ BIT(19) | BIT(20) | BIT(21)),
+ BUS_PROT(IFR_TYPE, 0x2a0, 0x2a4, 0, 0x228,
+ BIT(21) | BIT(22), BIT(21) | BIT(22)),
+ },
+ },
+ [MT8183_POWER_DOMAIN_DISP] = {
+ .name = "disp",
+ .sta_mask = PWR_STATUS_DISP,
+ .ctl_offs = 0x030c,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .basic_clk_name = {"mm"},
+ .subsys_clk_prefix = "mm",
+ .bp_table = {
+ BUS_PROT(IFR_TYPE, 0x2a8, 0x2ac, 0, 0x258,
+ BIT(16) | BIT(17), BIT(16) | BIT(17)),
+ BUS_PROT(IFR_TYPE, 0x2a0, 0x2a4, 0, 0x228,
+ BIT(10) | BIT(11), BIT(10) | BIT(11)),
+ BUS_PROT(SMI_TYPE, 0x3c4, 0x3c8, 0, 0x3c0,
+ GENMASK(7, 0), GENMASK(7, 0)),
+ },
+ },
+ [MT8183_POWER_DOMAIN_CAM] = {
+ .name = "cam",
+ .sta_mask = BIT(25),
+ .ctl_offs = 0x0344,
+ .sram_pdn_bits = GENMASK(9, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ .basic_clk_name = {"cam"},
+ .subsys_clk_prefix = "cam",
+ .bp_table = {
+ BUS_PROT(IFR_TYPE, 0x2d4, 0x2d8, 0, 0x2ec,
+ BIT(4) | BIT(5) | BIT(9) | BIT(13),
+ BIT(4) | BIT(5) | BIT(9) | BIT(13)),
+ BUS_PROT(IFR_TYPE, 0x2a0, 0x2a4, 0, 0x228,
+ BIT(28), BIT(28)),
+ BUS_PROT(IFR_TYPE, 0x2d4, 0x2d8, 0, 0x2ec,
+ BIT(11), 0),
+ BUS_PROT(SMI_TYPE, 0x3c4, 0x3c8, 0, 0x3c0,
+ BIT(3) | BIT(4), BIT(3) | BIT(4)),
+ },
+ },
+ [MT8183_POWER_DOMAIN_ISP] = {
+ .name = "isp",
+ .sta_mask = PWR_STATUS_ISP,
+ .ctl_offs = 0x0308,
+ .sram_pdn_bits = GENMASK(9, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ .basic_clk_name = {"isp"},
+ .subsys_clk_prefix = "isp",
+ .bp_table = {
+ BUS_PROT(IFR_TYPE, 0x2d4, 0x2d8, 0, 0x2ec,
+ BIT(3) | BIT(8), BIT(3) | BIT(8)),
+ BUS_PROT(IFR_TYPE, 0x2d4, 0x2d8, 0, 0x2ec,
+ BIT(10), 0),
+ BUS_PROT(SMI_TYPE, 0x3c4, 0x3c8, 0, 0x3c0,
+ BIT(2), BIT(2)),
+ },
+ },
+ [MT8183_POWER_DOMAIN_VDEC] = {
+ .name = "vdec",
+ .sta_mask = BIT(31),
+ .ctl_offs = 0x0300,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_table = {
+ BUS_PROT(SMI_TYPE, 0x3c4, 0x3c8, 0, 0x3c0,
+ BIT(7), BIT(7)),
+ },
+ },
+ [MT8183_POWER_DOMAIN_VENC] = {
+ .name = "venc",
+ .sta_mask = PWR_STATUS_VENC,
+ .ctl_offs = 0x0304,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .bp_table = {
+ BUS_PROT(SMI_TYPE, 0x3c4, 0x3c8, 0, 0x3c0,
+ BIT(1), BIT(1)),
+ },
+ },
+ [MT8183_POWER_DOMAIN_VPU_TOP] = {
+ .name = "vpu_top",
+ .sta_mask = BIT(26),
+ .ctl_offs = 0x0324,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .basic_clk_name = {"vpu", "vpu1"},
+ .subsys_clk_prefix = "vpu",
+ .bp_table = {
+ BUS_PROT(IFR_TYPE, 0x2d4, 0x2d8, 0, 0x2ec,
+ GENMASK(9, 6) | BIT(12),
+ GENMASK(9, 6) | BIT(12)),
+ BUS_PROT(IFR_TYPE, 0x2a0, 0x2a4, 0, 0x228,
+ BIT(27), BIT(27)),
+ BUS_PROT(IFR_TYPE, 0x2d4, 0x2d8, 0, 0x2ec,
+ BIT(10) | BIT(11), BIT(10) | BIT(11)),
+ BUS_PROT(SMI_TYPE, 0x3c4, 0x3c8, 0, 0x3c0,
+ BIT(5) | BIT(6), BIT(5) | BIT(6)),
+ },
+ },
+ [MT8183_POWER_DOMAIN_VPU_CORE0] = {
+ .name = "vpu_core0",
+ .sta_mask = BIT(27),
+ .ctl_offs = 0x33c,
+ .sram_iso_ctrl = true,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ .basic_clk_name = {"vpu2"},
+ .bp_table = {
+ BUS_PROT(IFR_TYPE, 0x2c4, 0x2c8, 0, 0x2e4,
+ BIT(6), BIT(6)),
+ BUS_PROT(IFR_TYPE, 0x2c4, 0x2c8, 0, 0x2e4,
+ BIT(0) | BIT(2) | BIT(4),
+ BIT(0) | BIT(2) | BIT(4)),
+ },
+ },
+ [MT8183_POWER_DOMAIN_VPU_CORE1] = {
+ .name = "vpu_core1",
+ .sta_mask = BIT(28),
+ .ctl_offs = 0x0340,
+ .sram_iso_ctrl = true,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ .basic_clk_name = {"vpu3"},
+ .bp_table = {
+ BUS_PROT(IFR_TYPE, 0x2c4, 0x2c8, 0, 0x2e4,
+ BIT(7), BIT(7)),
+ BUS_PROT(IFR_TYPE, 0x2c4, 0x2c8, 0, 0x2e4,
+ BIT(1) | BIT(3) | BIT(5),
+ BIT(1) | BIT(3) | BIT(5)),
+ },
+ },
+};
+
+static const struct scp_subdomain scp_subdomain_mt8183[] = {
+ {MT8183_POWER_DOMAIN_MFG_ASYNC, MT8183_POWER_DOMAIN_MFG},
+ {MT8183_POWER_DOMAIN_MFG, MT8183_POWER_DOMAIN_MFG_2D},
+ {MT8183_POWER_DOMAIN_MFG, MT8183_POWER_DOMAIN_MFG_CORE0},
+ {MT8183_POWER_DOMAIN_MFG, MT8183_POWER_DOMAIN_MFG_CORE1},
+ {MT8183_POWER_DOMAIN_DISP, MT8183_POWER_DOMAIN_CAM},
+ {MT8183_POWER_DOMAIN_DISP, MT8183_POWER_DOMAIN_ISP},
+ {MT8183_POWER_DOMAIN_DISP, MT8183_POWER_DOMAIN_VDEC},
+ {MT8183_POWER_DOMAIN_DISP, MT8183_POWER_DOMAIN_VENC},
+ {MT8183_POWER_DOMAIN_DISP, MT8183_POWER_DOMAIN_VPU_TOP},
+ {MT8183_POWER_DOMAIN_VPU_TOP, MT8183_POWER_DOMAIN_VPU_CORE0},
+ {MT8183_POWER_DOMAIN_VPU_TOP, MT8183_POWER_DOMAIN_VPU_CORE1},
+};
+
static const struct scp_soc_data mt2701_data = {
.domains = scp_domain_data_mt2701,
.num_domains = ARRAY_SIZE(scp_domain_data_mt2701),
@@ -1207,6 +1419,17 @@ static const struct scp_soc_data mt8173_data = {
.bus_prot_reg_update = true,
};
+static const struct scp_soc_data mt8183_data = {
+ .domains = scp_domain_data_mt8183,
+ .num_domains = ARRAY_SIZE(scp_domain_data_mt8183),
+ .subdomains = scp_subdomain_mt8183,
+ .num_subdomains = ARRAY_SIZE(scp_subdomain_mt8183),
+ .regs = {
+ .pwr_sta_offs = 0x0180,
+ .pwr_sta2nd_offs = 0x0184
+ }
+};
+
/*
* scpsys driver init
*/
@@ -1230,6 +1453,9 @@ static const struct of_device_id of_scpsys_match_tbl[] = {
}, {
.compatible = "mediatek,mt8173-scpsys",
.data = &mt8173_data,
+ }, {
+ .compatible = "mediatek,mt8183-scpsys",
+ .data = &mt8183_data,
}, {
/* sentinel */
}
--
2.18.0
Add power controller node and smi-common node for MT8183
In scpsys node, it contains clocks and regmapping of
infracfg and smi-common for bus protection.
Signed-off-by: Weiyi Lu <[email protected]>
---
arch/arm64/boot/dts/mediatek/mt8183.dtsi | 62 ++++++++++++++++++++++++
1 file changed, 62 insertions(+)
diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
index 08274bfcebd8..75c4881bbe5e 100644
--- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
@@ -8,6 +8,7 @@
#include <dt-bindings/clock/mt8183-clk.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/power/mt8183-power.h>
/ {
compatible = "mediatek,mt8183";
@@ -196,6 +197,62 @@
#clock-cells = <1>;
};
+ scpsys: syscon@10006000 {
+ compatible = "mediatek,mt8183-scpsys", "syscon";
+ #power-domain-cells = <1>;
+ reg = <0 0x10006000 0 0x1000>;
+ clocks = <&topckgen CLK_TOP_MUX_AUD_INTBUS>,
+ <&infracfg CLK_INFRA_AUDIO>,
+ <&infracfg CLK_INFRA_AUDIO_26M_BCLK>,
+ <&topckgen CLK_TOP_MUX_MFG>,
+ <&topckgen CLK_TOP_MUX_MM>,
+ <&topckgen CLK_TOP_MUX_CAM>,
+ <&topckgen CLK_TOP_MUX_IMG>,
+ <&topckgen CLK_TOP_MUX_IPU_IF>,
+ <&topckgen CLK_TOP_MUX_DSP>,
+ <&topckgen CLK_TOP_MUX_DSP1>,
+ <&topckgen CLK_TOP_MUX_DSP2>,
+ <&mmsys CLK_MM_SMI_COMMON>,
+ <&mmsys CLK_MM_SMI_LARB0>,
+ <&mmsys CLK_MM_SMI_LARB1>,
+ <&mmsys CLK_MM_GALS_COMM0>,
+ <&mmsys CLK_MM_GALS_COMM1>,
+ <&mmsys CLK_MM_GALS_CCU2MM>,
+ <&mmsys CLK_MM_GALS_IPU12MM>,
+ <&mmsys CLK_MM_GALS_IMG2MM>,
+ <&mmsys CLK_MM_GALS_CAM2MM>,
+ <&mmsys CLK_MM_GALS_IPU2MM>,
+ <&imgsys CLK_IMG_LARB5>,
+ <&imgsys CLK_IMG_LARB2>,
+ <&camsys CLK_CAM_LARB6>,
+ <&camsys CLK_CAM_LARB3>,
+ <&camsys CLK_CAM_SENINF>,
+ <&camsys CLK_CAM_CAMSV0>,
+ <&camsys CLK_CAM_CAMSV1>,
+ <&camsys CLK_CAM_CAMSV2>,
+ <&camsys CLK_CAM_CCU>,
+ <&ipu_conn CLK_IPU_CONN_IPU>,
+ <&ipu_conn CLK_IPU_CONN_AHB>,
+ <&ipu_conn CLK_IPU_CONN_AXI>,
+ <&ipu_conn CLK_IPU_CONN_ISP>,
+ <&ipu_conn CLK_IPU_CONN_CAM_ADL>,
+ <&ipu_conn CLK_IPU_CONN_IMG_ADL>;
+ clock-names = "audio", "audio1", "audio2",
+ "mfg", "mm", "cam",
+ "isp", "vpu", "vpu1",
+ "vpu2", "vpu3", "mm-0",
+ "mm-1", "mm-2", "mm-3",
+ "mm-4", "mm-5", "mm-6",
+ "mm-7", "mm-8", "mm-9",
+ "isp-0", "isp-1", "cam-0",
+ "cam-1", "cam-2", "cam-3",
+ "cam-4", "cam-5", "cam-6",
+ "vpu-0", "vpu-1", "vpu-2",
+ "vpu-3", "vpu-4", "vpu-5";
+ infracfg = <&infracfg>;
+ smi_comm = <&smi_common>;
+ };
+
apmixedsys: syscon@1000c000 {
compatible = "mediatek,mt8183-apmixedsys", "syscon";
reg = <0 0x1000c000 0 0x1000>;
@@ -260,6 +317,11 @@
#clock-cells = <1>;
};
+ smi_common: smi@14019000 {
+ compatible = "mediatek,mt8183-smi-common", "syscon";
+ reg = <0 0x14019000 0 0x1000>;
+ };
+
imgsys: syscon@15020000 {
compatible = "mediatek,mt8183-imgsys", "syscon";
reg = <0 0x15020000 0 0x1000>;
--
2.18.0
Signed-off-by: Weiyi Lu <[email protected]>
---
drivers/soc/mediatek/mtk-scpsys.c | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index 5b24bb4bfbf6..9f52f501178b 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -1,15 +1,7 @@
-/*
- * Copyright (c) 2015 Pengutronix, Sascha Hauer <[email protected]>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2015 Pengutronix, Sascha Hauer <[email protected]>
+
#include <linux/clk.h>
#include <linux/init.h>
#include <linux/io.h>
--
2.18.0
For some power domains like vpu_core on MT8183 whose sram need to
do clock and internal isolation while power on/off sram.
We add a flag "sram_iso_ctrl" in scp_domain_data to judge if we
need to do the extra sram isolation control or not.
Signed-off-by: Weiyi Lu <[email protected]>
---
drivers/soc/mediatek/mtk-scpsys.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index 356ca2626b36..94c10f69655d 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -57,6 +57,8 @@
#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_STATUS_CONN BIT(1)
#define PWR_STATUS_DISP BIT(3)
@@ -115,6 +117,8 @@ static const char * const clk_names[] = {
* @name: The domain name.
* @sta_mask: The mask for power on/off status bit.
* @ctl_offs: The offset for main power control register.
+ * @sram_iso_ctrl: The flag to judge if the power domain need to do
+ * the extra sram isolation control.
* @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.
@@ -131,6 +135,7 @@ struct scp_domain_data {
const char *name;
u32 sta_mask;
int ctl_offs;
+ bool sram_iso_ctrl;
u32 sram_pdn_bits;
u32 sram_pdn_ack_bits;
u32 bus_prot_mask;
@@ -273,6 +278,14 @@ static int scpsys_sram_enable(struct scp_domain *scpd, void __iomem *ctl_addr)
return ret;
}
+ if (scpd->data->sram_iso_ctrl) {
+ val = readl(ctl_addr) | PWR_SRAM_ISOINT_B_BIT;
+ writel(val, ctl_addr);
+ udelay(1);
+ val &= ~PWR_SRAM_CLKISO_BIT;
+ writel(val, ctl_addr);
+ }
+
return 0;
}
@@ -282,6 +295,15 @@ static int scpsys_sram_disable(struct scp_domain *scpd, void __iomem *ctl_addr)
u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
int tmp;
+ if (scpd->data->sram_iso_ctrl) {
+ val = readl(ctl_addr);
+ val |= PWR_SRAM_CLKISO_BIT;
+ writel(val, ctl_addr);
+ val &= ~PWR_SRAM_ISOINT_B_BIT;
+ writel(val, ctl_addr);
+ udelay(1);
+ }
+
val = readl(ctl_addr) | scpd->data->sram_pdn_bits;
writel(val, ctl_addr);
--
2.18.0
Add subsys CG control flow before/after the bus protect control
due to bus protection need SMI bus relative CGs enabled to feedback
its ack.
Signed-off-by: Weiyi Lu <[email protected]>
---
drivers/soc/mediatek/mtk-scpsys.c | 72 ++++++++++++++++++++++++++++++-
1 file changed, 70 insertions(+), 2 deletions(-)
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index 181bf7bce591..356ca2626b36 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -108,6 +108,7 @@ static const char * const clk_names[] = {
};
#define MAX_CLKS 3
+#define MAX_SUBSYS_CLKS 10
/**
* struct scp_domain_data - scp domain data for power on/off flow
@@ -121,6 +122,8 @@ static const char * const clk_names[] = {
* power domains.
* @basic_clk_name: provide the same purpose with field "clk_id"
* by declaring basic clock prefix name rather than clk_id.
+ * @subsys_clk_prefix: The prefix name of the clocks need to be enabled
+ * before releasing bus protection.
* @caps: The flag for active wake-up action.
* @bp_table: The mask table for multiple step bus protection.
*/
@@ -133,6 +136,7 @@ struct scp_domain_data {
u32 bus_prot_mask;
enum clk_id clk_id[MAX_CLKS];
const char *basic_clk_name[MAX_CLKS];
+ const char *subsys_clk_prefix;
u8 caps;
struct bus_prot bp_table[MAX_STEPS];
};
@@ -143,6 +147,7 @@ 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;
};
@@ -361,16 +366,22 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
val |= PWR_RST_B_BIT;
writel(val, ctl_addr);
- ret = scpsys_sram_enable(scpd, ctl_addr);
+ 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;
+
ret = scpsys_bus_protect_disable(scpd);
if (ret < 0)
- goto err_pwr_ack;
+ goto err_sram;
return 0;
+err_sram:
+ scpsys_clk_disable(scpd->subsys_clk, MAX_SUBSYS_CLKS);
err_pwr_ack:
scpsys_clk_disable(scpd->clk, MAX_CLKS);
err_clk:
@@ -397,6 +408,8 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
if (ret < 0)
goto out;
+ scpsys_clk_disable(scpd->subsys_clk, MAX_SUBSYS_CLKS);
+
/* subsys power off */
val = readl(ctl_addr) | PWR_ISO_BIT;
writel(val, ctl_addr);
@@ -433,6 +446,48 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
return ret;
}
+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) &&
+ (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 -ENOMEM;
+ }
+
+ clk[sub_clk_cnt] = devm_clk_get(&pdev->dev,
+ clk_name);
+
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev,
+ "Subsys clk read fail %ld\n",
+ PTR_ERR(clk));
+ return PTR_ERR(clk);
+ }
+ sub_clk_cnt++;
+ }
+ }
+
+ return sub_clk_cnt;
+}
+
static void init_clks(struct platform_device *pdev, struct clk **clk)
{
int i;
@@ -520,6 +575,7 @@ static struct scp *init_scp(struct platform_device *pdev,
struct scp_domain *scpd = &scp->domains[i];
struct generic_pm_domain *genpd = &scpd->genpd;
const struct scp_domain_data *data = &scp_domain_data[i];
+ int clk_cnt;
pd_data->domains[i] = genpd;
scpd->scp = scp;
@@ -546,6 +602,18 @@ static struct scp *init_scp(struct platform_device *pdev,
data->basic_clk_name[j]);
}
+ if (data->subsys_clk_prefix) {
+ clk_cnt = init_subsys_clks(pdev,
+ data->subsys_clk_prefix,
+ scpd->subsys_clk);
+ if (clk_cnt < 0) {
+ dev_err(&pdev->dev,
+ "%s: subsys clk unavailable\n",
+ data->name);
+ return ERR_PTR(clk_cnt);
+ }
+ }
+
genpd->name = data->name;
genpd->power_off = scpsys_power_off;
genpd->power_on = scpsys_power_on;
--
2.18.0
Put sram enable and disable control in separate functions.
Signed-off-by: Weiyi Lu <[email protected]>
---
drivers/soc/mediatek/mtk-scpsys.c | 79 ++++++++++++++++++++-----------
1 file changed, 51 insertions(+), 28 deletions(-)
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index 3e9be07a2627..65b734b40098 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -235,12 +235,55 @@ static void scpsys_clk_disable(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;
+ int tmp;
+
+ 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 */
+ 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) | 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_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;
@@ -252,6 +295,7 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
if (ret)
goto err_clk;
+ /* subsys power on */
val = readl(ctl_addr);
val |= PWR_ON_BIT;
writel(val, ctl_addr);
@@ -273,24 +317,9 @@ 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);
- if (ret < 0)
- goto err_pwr_ack;
- }
+ 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,
@@ -317,7 +346,6 @@ 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;
@@ -329,17 +357,12 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
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;
- val |= PWR_ISO_BIT;
+ /* subsys power off */
+ val = readl(ctl_addr) | PWR_ISO_BIT;
writel(val, ctl_addr);
val &= ~PWR_RST_B_BIT;
--
2.18.0
For scpsys driver using regmap based syscon driver API.
Signed-off-by: Weiyi Lu <[email protected]>
---
.../bindings/memory-controllers/mediatek,smi-common.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
index b478ade4da65..01744ec6a75b 100644
--- a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
+++ b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
@@ -20,7 +20,7 @@ Required properties:
"mediatek,mt2712-smi-common"
"mediatek,mt7623-smi-common", "mediatek,mt2701-smi-common"
"mediatek,mt8173-smi-common"
- "mediatek,mt8183-smi-common"
+ "mediatek,mt8183-smi-common", "syscon"
- reg : the register and size of the SMI block.
- power-domains : a phandle to the power domain of this local arbiter.
- clocks : Must contain an entry for each entry in clock-names.
--
2.18.0
Put clock enable and disable control in separate function.
Signed-off-by: Weiyi Lu <[email protected]>
---
drivers/soc/mediatek/mtk-scpsys.c | 49 ++++++++++++++++++++-----------
1 file changed, 32 insertions(+), 17 deletions(-)
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index 765ad4a5e5df..3e9be07a2627 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -208,6 +208,33 @@ static int scpsys_regulator_disable(struct scp_domain *scpd)
return regulator_disable(scpd->supply);
}
+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) {
+ for (--i; i >= 0; i--)
+ clk_disable_unprepare(clk[i]);
+
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static void scpsys_clk_disable(struct clk *clk[], int max_num)
+{
+ int i;
+
+ for (i = max_num - 1; i >= 0; i--) {
+ if (clk[i])
+ clk_disable_unprepare(clk[i]);
+ }
+}
+
static int scpsys_power_on(struct generic_pm_domain *genpd)
{
struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
@@ -216,21 +243,14 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
u32 val;
int ret, tmp;
- int i;
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]);
-
- goto err_clk;
- }
- }
+ ret = scpsys_clk_enable(scpd->clk, MAX_CLKS);
+ if (ret)
+ goto err_clk;
val = readl(ctl_addr);
val |= PWR_ON_BIT;
@@ -283,10 +303,7 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
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:
scpsys_regulator_disable(scpd);
@@ -303,7 +320,6 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
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,
@@ -344,8 +360,7 @@ 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);
ret = scpsys_regulator_disable(scpd);
if (ret < 0)
--
2.18.0
Put regulator enable and disable control in separate functions.
Signed-off-by: Weiyi Lu <[email protected]>
---
drivers/soc/mediatek/mtk-scpsys.c | 32 ++++++++++++++++++++++---------
1 file changed, 23 insertions(+), 9 deletions(-)
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index 2855111b221a..765ad4a5e5df 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -192,6 +192,22 @@ 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 int scpsys_power_on(struct generic_pm_domain *genpd)
{
struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
@@ -202,11 +218,9 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
int ret, tmp;
int i;
- if (scpd->supply) {
- ret = regulator_enable(scpd->supply);
- if (ret)
- return 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]);
@@ -274,8 +288,7 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
clk_disable_unprepare(scpd->clk[i]);
}
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);
@@ -334,8 +347,9 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++)
clk_disable_unprepare(scpd->clk[i]);
- if (scpd->supply)
- regulator_disable(scpd->supply);
+ ret = scpsys_regulator_disable(scpd);
+ if (ret < 0)
+ goto out;
return 0;
--
2.18.0
Add power dt-bindings of MT8183 and introduces "BASIC" and
"SUBSYS" clock types in binding document.
The "BASIC" type is compatible to the original power control with
clock name [a-z]+[0-9]*, e.g. mm, vpu1.
The "SUBSYS" type is used for bus protection control with clock
name [a-z]+-[0-9]+, e.g. isp-0, cam-1.
Signed-off-by: Weiyi Lu <[email protected]>
---
.../bindings/soc/mediatek/scpsys.txt | 14 ++++++++++
include/dt-bindings/power/mt8183-power.h | 26 +++++++++++++++++++
2 files changed, 40 insertions(+)
create mode 100644 include/dt-bindings/power/mt8183-power.h
diff --git a/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
index d6fe16f094af..b4728ce81c43 100644
--- a/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
+++ b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
@@ -14,6 +14,7 @@ power/power_domain.txt. It provides the power domains defined in
- include/dt-bindings/power/mt2701-power.h
- include/dt-bindings/power/mt2712-power.h
- include/dt-bindings/power/mt7622-power.h
+- include/dt-bindings/power/mt8183-power.h
Required properties:
- compatible: Should be one of:
@@ -24,18 +25,31 @@ Required properties:
- "mediatek,mt7623-scpsys", "mediatek,mt2701-scpsys": For MT7623 SoC
- "mediatek,mt7623a-scpsys": For MT7623A SoC
- "mediatek,mt8173-scpsys"
+ - "mediatek,mt8183-scpsys"
- #power-domain-cells: Must be 1
- reg: Address range of the SCPSYS unit
- infracfg: must contain a phandle to the infracfg controller
- clock, clock-names: clocks according to the common clock binding.
These are clocks which hardware needs to be
enabled before enabling certain power domains.
+ The new clock type "BASIC" belongs to the type above.
+ As to the new clock type "SUBSYS" needs to be
+ enabled before releasing bus protection.
Required clocks for MT2701 or MT7623: "mm", "mfg", "ethif"
Required clocks for MT2712: "mm", "mfg", "venc", "jpgdec", "audio", "vdec"
Required clocks for MT6797: "mm", "mfg", "vdec"
Required clocks for MT7622: "hif_sel"
Required clocks for MT7622A: "ethif"
Required clocks for MT8173: "mm", "mfg", "venc", "venc_lt"
+ Required clocks for MT8183: BASIC: "audio", "mfg", "mm", "cam", "isp",
+ "vpu", "vpu1", "vpu2", "vpu3"
+ SUBSYS: "mm-0", "mm-1", "mm-2", "mm-3",
+ "mm-4", "mm-5", "mm-6", "mm-7",
+ "mm-8", "mm-9", "isp-0", "isp-1",
+ "cam-0", "cam-1", "cam-2", "cam-3",
+ "cam-4", "cam-5", "cam-6", "vpu-0",
+ "vpu-1", "vpu-2", "vpu-3", "vpu-4",
+ "vpu-5"
Optional properties:
- vdec-supply: Power supply for the vdec power domain
diff --git a/include/dt-bindings/power/mt8183-power.h b/include/dt-bindings/power/mt8183-power.h
new file mode 100644
index 000000000000..5c0c8c7e3cd0
--- /dev/null
+++ b/include/dt-bindings/power/mt8183-power.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Weiyi Lu <[email protected]>
+ */
+
+#ifndef _DT_BINDINGS_POWER_MT8183_POWER_H
+#define _DT_BINDINGS_POWER_MT8183_POWER_H
+
+#define MT8183_POWER_DOMAIN_AUDIO 0
+#define MT8183_POWER_DOMAIN_CONN 1
+#define MT8183_POWER_DOMAIN_MFG_ASYNC 2
+#define MT8183_POWER_DOMAIN_MFG 3
+#define MT8183_POWER_DOMAIN_MFG_CORE0 4
+#define MT8183_POWER_DOMAIN_MFG_CORE1 5
+#define MT8183_POWER_DOMAIN_MFG_2D 6
+#define MT8183_POWER_DOMAIN_DISP 7
+#define MT8183_POWER_DOMAIN_CAM 8
+#define MT8183_POWER_DOMAIN_ISP 9
+#define MT8183_POWER_DOMAIN_VDEC 10
+#define MT8183_POWER_DOMAIN_VENC 11
+#define MT8183_POWER_DOMAIN_VPU_TOP 12
+#define MT8183_POWER_DOMAIN_VPU_CORE0 13
+#define MT8183_POWER_DOMAIN_VPU_CORE1 14
+
+#endif /* _DT_BINDINGS_POWER_MT8183_POWER_H */
--
2.18.0
On Tue, Mar 19, 2019 at 4:02 PM Weiyi Lu <[email protected]> wrote:
>
> Use USEC_PER_SEC to indicate the polling timeout directly.
> And add documentation of scp_domain_data.
>
> Signed-off-by: Weiyi Lu <[email protected]>
> ---
> drivers/soc/mediatek/mtk-scpsys.c | 14 +++++++++++++-
> 1 file changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> index 9f52f501178b..2855111b221a 100644
> --- a/drivers/soc/mediatek/mtk-scpsys.c
> +++ b/drivers/soc/mediatek/mtk-scpsys.c
> @@ -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,18 @@ 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 clock needs to be enabled before enabling certain
> + * power domains.
I assume these are the clock*s* that *this* scp_domain requires?
So maybe just: "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;
> --
> 2.18.0
>
On Tue, Mar 19, 2019 at 4:02 PM Weiyi Lu <[email protected]> wrote:
>
> Put clock enable and disable control in separate function.
>
> Signed-off-by: Weiyi Lu <[email protected]>
> ---
> drivers/soc/mediatek/mtk-scpsys.c | 49 ++++++++++++++++++++-----------
> 1 file changed, 32 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> index 765ad4a5e5df..3e9be07a2627 100644
> --- a/drivers/soc/mediatek/mtk-scpsys.c
> +++ b/drivers/soc/mediatek/mtk-scpsys.c
> @@ -208,6 +208,33 @@ static int scpsys_regulator_disable(struct scp_domain *scpd)
> return regulator_disable(scpd->supply);
> }
>
> +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) {
> + for (--i; i >= 0; i--)
> + clk_disable_unprepare(clk[i]);
Would it be simpler to just call scpsys_clk_disable(clk, i) ?
> +
> + break;
> + }
> + }
> +
> + return ret;
> +}
Maybe not for this series, but could you use clk_bulk_prepare_enable
instead? The only issue is that it'd still call clk_prepare_enable on
NULL clocks, but that does nothing, so it's just a little less
efficient...
> +
> +static void scpsys_clk_disable(struct clk *clk[], int max_num)
> +{
> + int i;
> +
> + for (i = max_num - 1; i >= 0; i--) {
> + if (clk[i])
if test not needed, clk_disable_unprepare ignores NULL parameters.
> + clk_disable_unprepare(clk[i]);
> + }
> +}
ditto: clk_bulk_disable_unprepare
> +
> static int scpsys_power_on(struct generic_pm_domain *genpd)
> {
> struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
> @@ -216,21 +243,14 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
> u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
> u32 val;
> int ret, tmp;
> - int i;
>
> 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]);
> -
> - goto err_clk;
> - }
> - }
> + ret = scpsys_clk_enable(scpd->clk, MAX_CLKS);
> + if (ret)
> + goto err_clk;
>
> val = readl(ctl_addr);
> val |= PWR_ON_BIT;
> @@ -283,10 +303,7 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
> 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:
> scpsys_regulator_disable(scpd);
>
> @@ -303,7 +320,6 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
> 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,
> @@ -344,8 +360,7 @@ 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);
>
> ret = scpsys_regulator_disable(scpd);
> if (ret < 0)
> --
> 2.18.0
>
On Tue, Mar 19, 2019 at 4:02 PM Weiyi Lu <[email protected]> wrote:
>
> Put sram enable and disable control in separate functions.
>
> Signed-off-by: Weiyi Lu <[email protected]>
Refactoring looks ok, just a small comment.
Reviewed-by: Nicolas Boichat <[email protected]>
> ---
> drivers/soc/mediatek/mtk-scpsys.c | 79 ++++++++++++++++++++-----------
> 1 file changed, 51 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> index 3e9be07a2627..65b734b40098 100644
> --- a/drivers/soc/mediatek/mtk-scpsys.c
> +++ b/drivers/soc/mediatek/mtk-scpsys.c
> @@ -235,12 +235,55 @@ static void scpsys_clk_disable(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;
> + int tmp;
> +
> + 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 */
> + 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);
Does the range really need to be so tight? Would 12000, 13000 also be ok?
> + } 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) | 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_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;
>
> @@ -252,6 +295,7 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
> if (ret)
> goto err_clk;
>
> + /* subsys power on */
> val = readl(ctl_addr);
> val |= PWR_ON_BIT;
> writel(val, ctl_addr);
> @@ -273,24 +317,9 @@ 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);
> - if (ret < 0)
> - goto err_pwr_ack;
> - }
> + 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,
> @@ -317,7 +346,6 @@ 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;
>
> @@ -329,17 +357,12 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
> 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;
>
> - val |= PWR_ISO_BIT;
> + /* subsys power off */
> + val = readl(ctl_addr) | PWR_ISO_BIT;
> writel(val, ctl_addr);
>
> val &= ~PWR_RST_B_BIT;
> --
> 2.18.0
>
On Tue, Mar 19, 2019 at 4:02 PM Weiyi Lu <[email protected]> wrote:
>
> Put bus protection enable and disable control in separate functions.
>
> Signed-off-by: Weiyi Lu <[email protected]>
> ---
> drivers/soc/mediatek/mtk-scpsys.c | 48 ++++++++++++++++++++++---------
> 1 file changed, 34 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> index 65b734b40098..6bf846cb1893 100644
> --- a/drivers/soc/mediatek/mtk-scpsys.c
> +++ b/drivers/soc/mediatek/mtk-scpsys.c
> @@ -279,6 +279,34 @@ static int scpsys_sram_disable(struct scp_domain *scpd, void __iomem *ctl_addr)
> MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
> }
>
> +static int scpsys_bus_protect_enable(struct scp_domain *scpd)
> +{
> + struct scp *scp = scpd->scp;
> + int ret = 0;
> +
> + if (scpd->data->bus_prot_mask) {
> + ret = mtk_infracfg_set_bus_protection(scp->infracfg,
> + scpd->data->bus_prot_mask,
> + scp->bus_prot_reg_update);
> + }
> +
> + return ret;
Maybe other people have different opinions, but I prefer:
if (!scpd->data->bus_prot_mask)
return 0;
return mtk_infracfg_set_bus_protection(...);
> +}
> +
> +static int scpsys_bus_protect_disable(struct scp_domain *scpd)
> +{
> + struct scp *scp = scpd->scp;
> + int ret = 0;
> +
> + if (scpd->data->bus_prot_mask) {
> + ret = mtk_infracfg_clear_bus_protection(scp->infracfg,
> + scpd->data->bus_prot_mask,
> + scp->bus_prot_reg_update);
> + }
> +
> + return ret;
> +}
> +
> static int scpsys_power_on(struct generic_pm_domain *genpd)
> {
> struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
> @@ -321,13 +349,9 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
> 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)
> - goto err_pwr_ack;
> - }
> + ret = scpsys_bus_protect_disable(scpd);
> + if (ret < 0)
> + goto err_pwr_ack;
>
> return 0;
>
> @@ -349,13 +373,9 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
> u32 val;
> int ret, tmp;
>
> - 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)
> - goto out;
> - }
> + ret = scpsys_bus_protect_enable(scpd);
> + if (ret < 0)
> + goto out;
>
> ret = scpsys_sram_disable(scpd, ctl_addr);
> if (ret < 0)
> --
> 2.18.0
>
On Tue, Mar 19, 2019 at 4:02 PM Weiyi Lu <[email protected]> wrote:
>
> Both MT8183 & MT6765 have more control steps of bus protection
> than previous project. And there add more bus protection registers
> reside at infracfg & smi-common. Also add new APIs for multiple
> step bus protection control with more customize arguments.
>
> Signed-off-by: Weiyi Lu <[email protected]>
> ---
> drivers/soc/mediatek/Makefile | 2 +-
> drivers/soc/mediatek/mtk-scpsys-ext.c | 99 +++++++++++++++++++++++++
> drivers/soc/mediatek/mtk-scpsys.c | 24 ++++++
> include/linux/soc/mediatek/scpsys-ext.h | 39 ++++++++++
> 4 files changed, 163 insertions(+), 1 deletion(-)
> create mode 100644 drivers/soc/mediatek/mtk-scpsys-ext.c
> create mode 100644 include/linux/soc/mediatek/scpsys-ext.h
>
> diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
> index 64ce5eeaba32..b9dbad6b12f9 100644
> --- a/drivers/soc/mediatek/Makefile
> +++ b/drivers/soc/mediatek/Makefile
> @@ -1,4 +1,4 @@
> obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o
> -obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
> +obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o mtk-scpsys-ext.o
> obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
> obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
> diff --git a/drivers/soc/mediatek/mtk-scpsys-ext.c b/drivers/soc/mediatek/mtk-scpsys-ext.c
> new file mode 100644
> index 000000000000..f630edb2f65d
> --- /dev/null
> +++ b/drivers/soc/mediatek/mtk-scpsys-ext.c
> @@ -0,0 +1,99 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2018 MediaTek Inc.
> + * Author: Owen Chen <[email protected]>
> + */
> +#include <linux/ktime.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/of_device.h>
> +#include <linux/regmap.h>
> +#include <linux/soc/mediatek/scpsys-ext.h>
> +
> +#define MTK_POLL_DELAY_US 10
> +#define MTK_POLL_TIMEOUT USEC_PER_SEC
> +
> +static int set_bus_protection(struct regmap *map, u32 mask, u32 ack_mask,
> + u32 reg_set, u32 reg_sta, u32 reg_en)
> +{
> + u32 val;
> +
> + if (reg_set)
> + regmap_write(map, reg_set, mask);
> + else
> + regmap_update_bits(map, reg_en, mask, mask);
> +
> + return regmap_read_poll_timeout(map, reg_sta,
> + val, (val & ack_mask) == ack_mask,
> + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
> +}
> +
> +static int clear_bus_protection(struct regmap *map, u32 mask, u32 ack_mask,
> + u32 reg_clr, u32 reg_sta, u32 reg_en)
> +{
> + u32 val;
> +
> + if (reg_clr)
> + regmap_write(map, reg_clr, mask);
> + else
> + regmap_update_bits(map, reg_en, mask, 0);
> +
> + return regmap_read_poll_timeout(map, reg_sta,
> + val, !(val & ack_mask),
> + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
> +}
> +
> +int mtk_scpsys_ext_set_bus_protection(const struct bus_prot *bp_table,
> + struct regmap *infracfg, struct regmap *smi_common)
> +{
> + int i;
> +
> + for (i = 0; i < MAX_STEPS && bp_table[i].mask; i++) {
> + struct regmap *map;
> + int ret;
> +
> + if (bp_table[i].type == IFR_TYPE)
> + map = infracfg;
> + else if (bp_table[i].type == SMI_TYPE)
> + map = smi_common;
> + else
> + return -EINVAL;
> +
> + ret = set_bus_protection(map,
> + bp_table[i].mask, bp_table[i].mask,
> + bp_table[i].set_ofs, bp_table[i].sta_ofs,
> + bp_table[i].en_ofs);
> +
> + if (ret)
> + return ret;
Should you undo the rest of the operations and clear bus protection on
the ones that were already enabled?
> + }
> +
> + return 0;
> +}
> +
> +int mtk_scpsys_ext_clear_bus_protection(const struct bus_prot *bp_table,
> + struct regmap *infracfg, struct regmap *smi_common)
> +{
> + int i;
> +
> + for (i = MAX_STEPS - 1; i >= 0; i--) {
So when you set protection, you stop at the first bp_table[i].mask ==
0, but when you clear it, you call clear_bus_protection for those, as
well. You should just skip over the ones when bp_table[i].mask == 0?
e.g.
if (!bp_table[i].mask)
continue;
> + struct regmap *map;
> + int ret;
> +
> + if (bp_table[i].type == IFR_TYPE)
> + map = infracfg;
> + else if (bp_table[i].type == SMI_TYPE)
> + map = smi_common;
> + else
> + return -EINVAL;
> +
> + ret = clear_bus_protection(map,
> + bp_table[i].mask, bp_table[i].clr_ack_mask,
> + bp_table[i].clr_ofs, bp_table[i].sta_ofs,
> + bp_table[i].en_ofs);
> +
> + if (ret)
> + return ret;
Similar question, is it ok to just abort? Or should you try to clear
the protection on all others, too?
> + }
> +
> + return 0;
> +}
> diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> index c6360de4e41e..181bf7bce591 100644
> --- a/drivers/soc/mediatek/mtk-scpsys.c
> +++ b/drivers/soc/mediatek/mtk-scpsys.c
> @@ -12,6 +12,7 @@
> #include <linux/pm_domain.h>
> #include <linux/regulator/consumer.h>
> #include <linux/soc/mediatek/infracfg.h>
> +#include <linux/soc/mediatek/scpsys-ext.h>
>
> #include <dt-bindings/power/mt2701-power.h>
> #include <dt-bindings/power/mt2712-power.h>
> @@ -121,6 +122,7 @@ static const char * const clk_names[] = {
> * @basic_clk_name: provide the same purpose with field "clk_id"
> * by declaring basic clock prefix name rather than clk_id.
> * @caps: The flag for active wake-up action.
> + * @bp_table: The mask table for multiple step bus protection.
> */
> struct scp_domain_data {
> const char *name;
> @@ -132,6 +134,7 @@ struct scp_domain_data {
> enum clk_id clk_id[MAX_CLKS];
> const char *basic_clk_name[MAX_CLKS];
> u8 caps;
> + struct bus_prot bp_table[MAX_STEPS];
> };
>
> struct scp;
> @@ -155,6 +158,7 @@ struct scp {
> struct device *dev;
> void __iomem *base;
> struct regmap *infracfg;
> + struct regmap *smi_common;
> struct scp_ctrl_reg ctrl_reg;
> bool bus_prot_reg_update;
> };
> @@ -291,6 +295,10 @@ static int scpsys_bus_protect_enable(struct scp_domain *scpd)
> ret = mtk_infracfg_set_bus_protection(scp->infracfg,
> scpd->data->bus_prot_mask,
> scp->bus_prot_reg_update);
> + } else if (scpd->data->bp_table[0].mask) {
> + ret = mtk_scpsys_ext_set_bus_protection(scpd->data->bp_table,
> + scp->infracfg,
> + scp->smi_common);
> }
>
> return ret;
> @@ -305,6 +313,11 @@ static int scpsys_bus_protect_disable(struct scp_domain *scpd)
> ret = mtk_infracfg_clear_bus_protection(scp->infracfg,
> scpd->data->bus_prot_mask,
> scp->bus_prot_reg_update);
> + } else if (scpd->data->bp_table[0].mask) {
> + ret = mtk_scpsys_ext_clear_bus_protection(
> + scpd->data->bp_table,
> + scp->infracfg,
> + scp->smi_common);
> }
>
> return ret;
> @@ -475,6 +488,17 @@ static struct scp *init_scp(struct platform_device *pdev,
> return ERR_CAST(scp->infracfg);
> }
>
> + scp->smi_common = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
> + "smi_comm");
> +
> + if (scp->smi_common == ERR_PTR(-ENODEV)) {
> + scp->smi_common = NULL;
> + } else if (IS_ERR(scp->smi_common)) {
> + dev_err(&pdev->dev, "Cannot find smi_common controller: %ld\n",
> + PTR_ERR(scp->smi_common));
> + return ERR_CAST(scp->smi_common);
> + }
> +
> for (i = 0; i < num; i++) {
> struct scp_domain *scpd = &scp->domains[i];
> const struct scp_domain_data *data = &scp_domain_data[i];
> diff --git a/include/linux/soc/mediatek/scpsys-ext.h b/include/linux/soc/mediatek/scpsys-ext.h
> new file mode 100644
> index 000000000000..d0ed295c88a7
> --- /dev/null
> +++ b/include/linux/soc/mediatek/scpsys-ext.h
> @@ -0,0 +1,39 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef __SOC_MEDIATEK_SCPSYS_EXT_H
> +#define __SOC_MEDIATEK_SCPSYS_EXT_H
> +
> +#define MAX_STEPS 4
> +
> +#define BUS_PROT(_type, _set_ofs, _clr_ofs, \
> + _en_ofs, _sta_ofs, _mask, _clr_ack_mask) { \
> + .type = _type, \
> + .set_ofs = _set_ofs, \
> + .clr_ofs = _clr_ofs, \
> + .en_ofs = _en_ofs, \
> + .sta_ofs = _sta_ofs, \
> + .mask = _mask, \
> + .clr_ack_mask = _clr_ack_mask, \
> + }
> +
> +enum regmap_type {
Maybe add INVALID_TYPE = 0, so that you can skip over those when
looping over them, instead of checking if mask is 0?
> + IFR_TYPE,
> + SMI_TYPE,
> + MAX_REGMAP_TYPE,
This is not used, right? Do you really need it?
> +};
> +
> +struct bus_prot {
> + enum regmap_type type;
> + u32 set_ofs;
> + u32 clr_ofs;
> + u32 en_ofs;
> + u32 sta_ofs;
> + u32 mask;
> + u32 clr_ack_mask;
> +};
> +
> +int mtk_scpsys_ext_set_bus_protection(const struct bus_prot *bp_table,
> + struct regmap *infracfg, struct regmap *smi_common);
> +int mtk_scpsys_ext_clear_bus_protection(const struct bus_prot *bp_table,
> + struct regmap *infracfg, struct regmap *smi_common);
> +
> +#endif /* __SOC_MEDIATEK_SCPSYS_EXT_H */
> --
> 2.18.0
>
On Tue, Mar 19, 2019 at 4:02 PM Weiyi Lu <[email protected]> wrote:
>
> Try to stop extending the clk_id or clk_names if there are
> more and more new BASIC clocks. To get its own clocks by the
> basic_clk_name of each power domain.
>
> Signed-off-by: Weiyi Lu <[email protected]>
> ---
> drivers/soc/mediatek/mtk-scpsys.c | 27 +++++++++++++++++++--------
> 1 file changed, 19 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> index 6bf846cb1893..c6360de4e41e 100644
> --- a/drivers/soc/mediatek/mtk-scpsys.c
> +++ b/drivers/soc/mediatek/mtk-scpsys.c
> @@ -118,6 +118,8 @@ static const char * const clk_names[] = {
> * @bus_prot_mask: The mask for single step bus protection.
> * @clk_id: The basic clock needs to be enabled before enabling certain
> * power domains.
> + * @basic_clk_name: provide the same purpose with field "clk_id"
> + * by declaring basic clock prefix name rather than clk_id.
> * @caps: The flag for active wake-up action.
> */
> struct scp_domain_data {
> @@ -128,6 +130,7 @@ struct scp_domain_data {
> u32 sram_pdn_ack_bits;
> u32 bus_prot_mask;
> enum clk_id clk_id[MAX_CLKS];
> + const char *basic_clk_name[MAX_CLKS];
Either call them basic_clk_id/basic_clk_name, or clk_id/clk_name.
> u8 caps;
> };
>
> @@ -499,16 +502,24 @@ static struct scp *init_scp(struct platform_device *pdev,
>
> scpd->data = data;
>
> - for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
> - struct clk *c = clk[data->clk_id[j]];
> + if (data->clk_id[0]) {
Since it's either clk_id or basic_clk_name, I wonder if it'd be good
to add a WARN_ON here, e.g.
WARN_ON(data->basic_clk_name[0]);
> + for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
> + struct clk *c = clk[data->clk_id[j]];
>
> - if (IS_ERR(c)) {
> - dev_err(&pdev->dev, "%s: clk unavailable\n",
> - data->name);
> - return ERR_CAST(c);
> - }
> + if (IS_ERR(c)) {
> + dev_err(&pdev->dev,
> + "%s: clk unavailable\n",
> + data->name);
> + return ERR_CAST(c);
> + }
>
> - scpd->clk[j] = c;
> + scpd->clk[j] = c;
> + }
> + } else if (data->basic_clk_name[0]) {
> + for (j = 0; j < MAX_CLKS &&
> + data->basic_clk_name[j]; j++)
> + scpd->clk[j] = devm_clk_get(&pdev->dev,
> + data->basic_clk_name[j]);
> }
>
> genpd->name = data->name;
> --
> 2.18.0
>
On Tue, 2019-03-19 at 19:45 +0800, Nicolas Boichat wrote:
> On Tue, Mar 19, 2019 at 4:02 PM Weiyi Lu <[email protected]> wrote:
> >
> > Use USEC_PER_SEC to indicate the polling timeout directly.
> > And add documentation of scp_domain_data.
> >
> > Signed-off-by: Weiyi Lu <[email protected]>
> > ---
> > drivers/soc/mediatek/mtk-scpsys.c | 14 +++++++++++++-
> > 1 file changed, 13 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> > index 9f52f501178b..2855111b221a 100644
> > --- a/drivers/soc/mediatek/mtk-scpsys.c
> > +++ b/drivers/soc/mediatek/mtk-scpsys.c
> > @@ -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,18 @@ 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 clock needs to be enabled before enabling certain
> > + * power domains.
>
> I assume these are the clock*s* that *this* scp_domain requires?
>
> So maybe just: "The basic clocks required by this power domain." ?
>
Thanks for revision. I'll update in next version.
> > + * @caps: The flag for active wake-up action.
> > + */
> > struct scp_domain_data {
> > const char *name;
> > u32 sta_mask;
> > --
> > 2.18.0
> >
>
> _______________________________________________
> Linux-mediatek mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-mediatek
On Tue, 2019-03-19 at 20:02 +0800, Nicolas Boichat wrote:
> On Tue, Mar 19, 2019 at 4:02 PM Weiyi Lu <[email protected]> wrote:
> >
> > Put clock enable and disable control in separate function.
> >
> > Signed-off-by: Weiyi Lu <[email protected]>
> > ---
> > drivers/soc/mediatek/mtk-scpsys.c | 49 ++++++++++++++++++++-----------
> > 1 file changed, 32 insertions(+), 17 deletions(-)
> >
> > diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> > index 765ad4a5e5df..3e9be07a2627 100644
> > --- a/drivers/soc/mediatek/mtk-scpsys.c
> > +++ b/drivers/soc/mediatek/mtk-scpsys.c
> > @@ -208,6 +208,33 @@ static int scpsys_regulator_disable(struct scp_domain *scpd)
> > return regulator_disable(scpd->supply);
> > }
> >
> > +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) {
> > + for (--i; i >= 0; i--)
> > + clk_disable_unprepare(clk[i]);
>
> Would it be simpler to just call scpsys_clk_disable(clk, i) ?
>
OK, I'll try.
> > +
> > + break;
> > + }
> > + }
> > +
> > + return ret;
> > +}
>
> Maybe not for this series, but could you use clk_bulk_prepare_enable
> instead? The only issue is that it'd still call clk_prepare_enable on
> NULL clocks, but that does nothing, so it's just a little less
> efficient...
>
OK, I'll try after this series.
> > +
> > +static void scpsys_clk_disable(struct clk *clk[], int max_num)
> > +{
> > + int i;
> > +
> > + for (i = max_num - 1; i >= 0; i--) {
> > + if (clk[i])
>
> if test not needed, clk_disable_unprepare ignores NULL parameters.
>
You're right. Supposed it's not needed, I'll test.
> > + clk_disable_unprepare(clk[i]);
> > + }
> > +}
>
> ditto: clk_bulk_disable_unprepare
>
> > +
> > static int scpsys_power_on(struct generic_pm_domain *genpd)
> > {
> > struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
> > @@ -216,21 +243,14 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
> > u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
> > u32 val;
> > int ret, tmp;
> > - int i;
> >
> > 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]);
> > -
> > - goto err_clk;
> > - }
> > - }
> > + ret = scpsys_clk_enable(scpd->clk, MAX_CLKS);
> > + if (ret)
> > + goto err_clk;
> >
> > val = readl(ctl_addr);
> > val |= PWR_ON_BIT;
> > @@ -283,10 +303,7 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
> > 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:
> > scpsys_regulator_disable(scpd);
> >
> > @@ -303,7 +320,6 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
> > 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,
> > @@ -344,8 +360,7 @@ 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);
> >
> > ret = scpsys_regulator_disable(scpd);
> > if (ret < 0)
> > --
> > 2.18.0
> >
On Tue, 2019-03-19 at 20:07 +0800, Nicolas Boichat wrote:
> On Tue, Mar 19, 2019 at 4:02 PM Weiyi Lu <[email protected]> wrote:
> >
> > Put sram enable and disable control in separate functions.
> >
> > Signed-off-by: Weiyi Lu <[email protected]>
>
> Refactoring looks ok, just a small comment.
>
> Reviewed-by: Nicolas Boichat <[email protected]>
>
> > ---
> > drivers/soc/mediatek/mtk-scpsys.c | 79 ++++++++++++++++++++-----------
> > 1 file changed, 51 insertions(+), 28 deletions(-)
> >
> > diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> > index 3e9be07a2627..65b734b40098 100644
> > --- a/drivers/soc/mediatek/mtk-scpsys.c
> > +++ b/drivers/soc/mediatek/mtk-scpsys.c
> > @@ -235,12 +235,55 @@ static void scpsys_clk_disable(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;
> > + int tmp;
> > +
> > + 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 */
> > + 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);
>
> Does the range really need to be so tight? Would 12000, 13000 also be ok?
>
I think Sean could give you a more accurate answer.
Hi Sean, would you mind answering this question?
> > + } 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) | 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_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;
> >
> > @@ -252,6 +295,7 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
> > if (ret)
> > goto err_clk;
> >
> > + /* subsys power on */
> > val = readl(ctl_addr);
> > val |= PWR_ON_BIT;
> > writel(val, ctl_addr);
> > @@ -273,24 +317,9 @@ 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);
> > - if (ret < 0)
> > - goto err_pwr_ack;
> > - }
> > + 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,
> > @@ -317,7 +346,6 @@ 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;
> >
> > @@ -329,17 +357,12 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
> > 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;
> >
> > - val |= PWR_ISO_BIT;
> > + /* subsys power off */
> > + val = readl(ctl_addr) | PWR_ISO_BIT;
> > writel(val, ctl_addr);
> >
> > val &= ~PWR_RST_B_BIT;
> > --
> > 2.18.0
> >
On Tue, 2019-03-19 at 20:09 +0800, Nicolas Boichat wrote:
> On Tue, Mar 19, 2019 at 4:02 PM Weiyi Lu <[email protected]> wrote:
> >
> > Put bus protection enable and disable control in separate functions.
> >
> > Signed-off-by: Weiyi Lu <[email protected]>
> > ---
> > drivers/soc/mediatek/mtk-scpsys.c | 48 ++++++++++++++++++++++---------
> > 1 file changed, 34 insertions(+), 14 deletions(-)
> >
> > diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> > index 65b734b40098..6bf846cb1893 100644
> > --- a/drivers/soc/mediatek/mtk-scpsys.c
> > +++ b/drivers/soc/mediatek/mtk-scpsys.c
> > @@ -279,6 +279,34 @@ static int scpsys_sram_disable(struct scp_domain *scpd, void __iomem *ctl_addr)
> > MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
> > }
> >
> > +static int scpsys_bus_protect_enable(struct scp_domain *scpd)
> > +{
> > + struct scp *scp = scpd->scp;
> > + int ret = 0;
> > +
> > + if (scpd->data->bus_prot_mask) {
> > + ret = mtk_infracfg_set_bus_protection(scp->infracfg,
> > + scpd->data->bus_prot_mask,
> > + scp->bus_prot_reg_update);
> > + }
> > +
> > + return ret;
>
> Maybe other people have different opinions, but I prefer:
>
> if (!scpd->data->bus_prot_mask)
> return 0;
>
> return mtk_infracfg_set_bus_protection(...);
>
ok, I'll update in next version.
> > +}
> > +
> > +static int scpsys_bus_protect_disable(struct scp_domain *scpd)
> > +{
> > + struct scp *scp = scpd->scp;
> > + int ret = 0;
> > +
> > + if (scpd->data->bus_prot_mask) {
> > + ret = mtk_infracfg_clear_bus_protection(scp->infracfg,
> > + scpd->data->bus_prot_mask,
> > + scp->bus_prot_reg_update);
> > + }
> > +
> > + return ret;
> > +}
> > +
> > static int scpsys_power_on(struct generic_pm_domain *genpd)
> > {
> > struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
> > @@ -321,13 +349,9 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
> > 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)
> > - goto err_pwr_ack;
> > - }
> > + ret = scpsys_bus_protect_disable(scpd);
> > + if (ret < 0)
> > + goto err_pwr_ack;
> >
> > return 0;
> >
> > @@ -349,13 +373,9 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
> > u32 val;
> > int ret, tmp;
> >
> > - 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)
> > - goto out;
> > - }
> > + ret = scpsys_bus_protect_enable(scpd);
> > + if (ret < 0)
> > + goto out;
> >
> > ret = scpsys_sram_disable(scpd, ctl_addr);
> > if (ret < 0)
> > --
> > 2.18.0
> >
>
> _______________________________________________
> Linux-mediatek mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-mediatek
On Thu, 2019-03-21 at 14:02 +0800, Nicolas Boichat wrote:
> On Tue, Mar 19, 2019 at 4:02 PM Weiyi Lu <[email protected]> wrote:
> >
> > Try to stop extending the clk_id or clk_names if there are
> > more and more new BASIC clocks. To get its own clocks by the
> > basic_clk_name of each power domain.
> >
> > Signed-off-by: Weiyi Lu <[email protected]>
> > ---
> > drivers/soc/mediatek/mtk-scpsys.c | 27 +++++++++++++++++++--------
> > 1 file changed, 19 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> > index 6bf846cb1893..c6360de4e41e 100644
> > --- a/drivers/soc/mediatek/mtk-scpsys.c
> > +++ b/drivers/soc/mediatek/mtk-scpsys.c
> > @@ -118,6 +118,8 @@ static const char * const clk_names[] = {
> > * @bus_prot_mask: The mask for single step bus protection.
> > * @clk_id: The basic clock needs to be enabled before enabling certain
> > * power domains.
> > + * @basic_clk_name: provide the same purpose with field "clk_id"
> > + * by declaring basic clock prefix name rather than clk_id.
> > * @caps: The flag for active wake-up action.
> > */
> > struct scp_domain_data {
> > @@ -128,6 +130,7 @@ struct scp_domain_data {
> > u32 sram_pdn_ack_bits;
> > u32 bus_prot_mask;
> > enum clk_id clk_id[MAX_CLKS];
> > + const char *basic_clk_name[MAX_CLKS];
>
> Either call them basic_clk_id/basic_clk_name, or clk_id/clk_name.
>
OK.
> > u8 caps;
> > };
> >
> > @@ -499,16 +502,24 @@ static struct scp *init_scp(struct platform_device *pdev,
> >
> > scpd->data = data;
> >
> > - for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
> > - struct clk *c = clk[data->clk_id[j]];
> > + if (data->clk_id[0]) {
>
> Since it's either clk_id or basic_clk_name, I wonder if it'd be good
> to add a WARN_ON here, e.g.
>
> WARN_ON(data->basic_clk_name[0]);
>
Thanks for the advise. I'll add it.
> > + for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
> > + struct clk *c = clk[data->clk_id[j]];
> >
> > - if (IS_ERR(c)) {
> > - dev_err(&pdev->dev, "%s: clk unavailable\n",
> > - data->name);
> > - return ERR_CAST(c);
> > - }
> > + if (IS_ERR(c)) {
> > + dev_err(&pdev->dev,
> > + "%s: clk unavailable\n",
> > + data->name);
> > + return ERR_CAST(c);
> > + }
> >
> > - scpd->clk[j] = c;
> > + scpd->clk[j] = c;
> > + }
> > + } else if (data->basic_clk_name[0]) {
> > + for (j = 0; j < MAX_CLKS &&
> > + data->basic_clk_name[j]; j++)
> > + scpd->clk[j] = devm_clk_get(&pdev->dev,
> > + data->basic_clk_name[j]);
> > }
> >
> > genpd->name = data->name;
> > --
> > 2.18.0
> >
On Thu, 2019-03-21 at 13:57 +0800, Nicolas Boichat wrote:
> On Tue, Mar 19, 2019 at 4:02 PM Weiyi Lu <[email protected]> wrote:
> >
> > Both MT8183 & MT6765 have more control steps of bus protection
> > than previous project. And there add more bus protection registers
> > reside at infracfg & smi-common. Also add new APIs for multiple
> > step bus protection control with more customize arguments.
> >
> > Signed-off-by: Weiyi Lu <[email protected]>
> > ---
> > drivers/soc/mediatek/Makefile | 2 +-
> > drivers/soc/mediatek/mtk-scpsys-ext.c | 99 +++++++++++++++++++++++++
> > drivers/soc/mediatek/mtk-scpsys.c | 24 ++++++
> > include/linux/soc/mediatek/scpsys-ext.h | 39 ++++++++++
> > 4 files changed, 163 insertions(+), 1 deletion(-)
> > create mode 100644 drivers/soc/mediatek/mtk-scpsys-ext.c
> > create mode 100644 include/linux/soc/mediatek/scpsys-ext.h
> >
> > diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
> > index 64ce5eeaba32..b9dbad6b12f9 100644
> > --- a/drivers/soc/mediatek/Makefile
> > +++ b/drivers/soc/mediatek/Makefile
> > @@ -1,4 +1,4 @@
> > obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o
> > -obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
> > +obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o mtk-scpsys-ext.o
> > obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
> > obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
> > diff --git a/drivers/soc/mediatek/mtk-scpsys-ext.c b/drivers/soc/mediatek/mtk-scpsys-ext.c
> > new file mode 100644
> > index 000000000000..f630edb2f65d
> > --- /dev/null
> > +++ b/drivers/soc/mediatek/mtk-scpsys-ext.c
> > @@ -0,0 +1,99 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (c) 2018 MediaTek Inc.
> > + * Author: Owen Chen <[email protected]>
> > + */
> > +#include <linux/ktime.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/of_device.h>
> > +#include <linux/regmap.h>
> > +#include <linux/soc/mediatek/scpsys-ext.h>
> > +
> > +#define MTK_POLL_DELAY_US 10
> > +#define MTK_POLL_TIMEOUT USEC_PER_SEC
> > +
> > +static int set_bus_protection(struct regmap *map, u32 mask, u32 ack_mask,
> > + u32 reg_set, u32 reg_sta, u32 reg_en)
> > +{
> > + u32 val;
> > +
> > + if (reg_set)
> > + regmap_write(map, reg_set, mask);
> > + else
> > + regmap_update_bits(map, reg_en, mask, mask);
> > +
> > + return regmap_read_poll_timeout(map, reg_sta,
> > + val, (val & ack_mask) == ack_mask,
> > + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
> > +}
> > +
> > +static int clear_bus_protection(struct regmap *map, u32 mask, u32 ack_mask,
> > + u32 reg_clr, u32 reg_sta, u32 reg_en)
> > +{
> > + u32 val;
> > +
> > + if (reg_clr)
> > + regmap_write(map, reg_clr, mask);
> > + else
> > + regmap_update_bits(map, reg_en, mask, 0);
> > +
> > + return regmap_read_poll_timeout(map, reg_sta,
> > + val, !(val & ack_mask),
> > + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
> > +}
> > +
> > +int mtk_scpsys_ext_set_bus_protection(const struct bus_prot *bp_table,
> > + struct regmap *infracfg, struct regmap *smi_common)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < MAX_STEPS && bp_table[i].mask; i++) {
> > + struct regmap *map;
> > + int ret;
> > +
> > + if (bp_table[i].type == IFR_TYPE)
> > + map = infracfg;
> > + else if (bp_table[i].type == SMI_TYPE)
> > + map = smi_common;
> > + else
> > + return -EINVAL;
> > +
> > + ret = set_bus_protection(map,
> > + bp_table[i].mask, bp_table[i].mask,
> > + bp_table[i].set_ofs, bp_table[i].sta_ofs,
> > + bp_table[i].en_ofs);
> > +
> > + if (ret)
> > + return ret;
>
> Should you undo the rest of the operations and clear bus protection on
> the ones that were already enabled?
>
Actually we assume all bus protection operations need to be done
successfully, undo might not be a very useful error handling here. But
I'll consider it carefully.
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +int mtk_scpsys_ext_clear_bus_protection(const struct bus_prot *bp_table,
> > + struct regmap *infracfg, struct regmap *smi_common)
> > +{
> > + int i;
> > +
> > + for (i = MAX_STEPS - 1; i >= 0; i--) {
>
> So when you set protection, you stop at the first bp_table[i].mask ==
> 0, but when you clear it, you call clear_bus_protection for those, as
> well. You should just skip over the ones when bp_table[i].mask == 0?
>
> e.g.
> if (!bp_table[i].mask)
> continue;
>
I'll use the idea of INVALID_TYPE = 0 to fix.
> > + struct regmap *map;
> > + int ret;
> > +
> > + if (bp_table[i].type == IFR_TYPE)
> > + map = infracfg;
> > + else if (bp_table[i].type == SMI_TYPE)
> > + map = smi_common;
> > + else
> > + return -EINVAL;
> > +
> > + ret = clear_bus_protection(map,
> > + bp_table[i].mask, bp_table[i].clr_ack_mask,
> > + bp_table[i].clr_ofs, bp_table[i].sta_ofs,
> > + bp_table[i].en_ofs);
> > +
> > + if (ret)
> > + return ret;
>
> Similar question, is it ok to just abort? Or should you try to clear
> the protection on all others, too?
>
> > + }
> > +
> > + return 0;
> > +}
> > diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
> > index c6360de4e41e..181bf7bce591 100644
> > --- a/drivers/soc/mediatek/mtk-scpsys.c
> > +++ b/drivers/soc/mediatek/mtk-scpsys.c
> > @@ -12,6 +12,7 @@
> > #include <linux/pm_domain.h>
> > #include <linux/regulator/consumer.h>
> > #include <linux/soc/mediatek/infracfg.h>
> > +#include <linux/soc/mediatek/scpsys-ext.h>
> >
> > #include <dt-bindings/power/mt2701-power.h>
> > #include <dt-bindings/power/mt2712-power.h>
> > @@ -121,6 +122,7 @@ static const char * const clk_names[] = {
> > * @basic_clk_name: provide the same purpose with field "clk_id"
> > * by declaring basic clock prefix name rather than clk_id.
> > * @caps: The flag for active wake-up action.
> > + * @bp_table: The mask table for multiple step bus protection.
> > */
> > struct scp_domain_data {
> > const char *name;
> > @@ -132,6 +134,7 @@ struct scp_domain_data {
> > enum clk_id clk_id[MAX_CLKS];
> > const char *basic_clk_name[MAX_CLKS];
> > u8 caps;
> > + struct bus_prot bp_table[MAX_STEPS];
> > };
> >
> > struct scp;
> > @@ -155,6 +158,7 @@ struct scp {
> > struct device *dev;
> > void __iomem *base;
> > struct regmap *infracfg;
> > + struct regmap *smi_common;
> > struct scp_ctrl_reg ctrl_reg;
> > bool bus_prot_reg_update;
> > };
> > @@ -291,6 +295,10 @@ static int scpsys_bus_protect_enable(struct scp_domain *scpd)
> > ret = mtk_infracfg_set_bus_protection(scp->infracfg,
> > scpd->data->bus_prot_mask,
> > scp->bus_prot_reg_update);
> > + } else if (scpd->data->bp_table[0].mask) {
> > + ret = mtk_scpsys_ext_set_bus_protection(scpd->data->bp_table,
> > + scp->infracfg,
> > + scp->smi_common);
> > }
> >
> > return ret;
> > @@ -305,6 +313,11 @@ static int scpsys_bus_protect_disable(struct scp_domain *scpd)
> > ret = mtk_infracfg_clear_bus_protection(scp->infracfg,
> > scpd->data->bus_prot_mask,
> > scp->bus_prot_reg_update);
> > + } else if (scpd->data->bp_table[0].mask) {
> > + ret = mtk_scpsys_ext_clear_bus_protection(
> > + scpd->data->bp_table,
> > + scp->infracfg,
> > + scp->smi_common);
> > }
> >
> > return ret;
> > @@ -475,6 +488,17 @@ static struct scp *init_scp(struct platform_device *pdev,
> > return ERR_CAST(scp->infracfg);
> > }
> >
> > + scp->smi_common = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
> > + "smi_comm");
> > +
> > + if (scp->smi_common == ERR_PTR(-ENODEV)) {
> > + scp->smi_common = NULL;
> > + } else if (IS_ERR(scp->smi_common)) {
> > + dev_err(&pdev->dev, "Cannot find smi_common controller: %ld\n",
> > + PTR_ERR(scp->smi_common));
> > + return ERR_CAST(scp->smi_common);
> > + }
> > +
> > for (i = 0; i < num; i++) {
> > struct scp_domain *scpd = &scp->domains[i];
> > const struct scp_domain_data *data = &scp_domain_data[i];
> > diff --git a/include/linux/soc/mediatek/scpsys-ext.h b/include/linux/soc/mediatek/scpsys-ext.h
> > new file mode 100644
> > index 000000000000..d0ed295c88a7
> > --- /dev/null
> > +++ b/include/linux/soc/mediatek/scpsys-ext.h
> > @@ -0,0 +1,39 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef __SOC_MEDIATEK_SCPSYS_EXT_H
> > +#define __SOC_MEDIATEK_SCPSYS_EXT_H
> > +
> > +#define MAX_STEPS 4
> > +
> > +#define BUS_PROT(_type, _set_ofs, _clr_ofs, \
> > + _en_ofs, _sta_ofs, _mask, _clr_ack_mask) { \
> > + .type = _type, \
> > + .set_ofs = _set_ofs, \
> > + .clr_ofs = _clr_ofs, \
> > + .en_ofs = _en_ofs, \
> > + .sta_ofs = _sta_ofs, \
> > + .mask = _mask, \
> > + .clr_ack_mask = _clr_ack_mask, \
> > + }
> > +
> > +enum regmap_type {
>
> Maybe add INVALID_TYPE = 0, so that you can skip over those when
> looping over them, instead of checking if mask is 0?
>
Thanks for advise. I'll use it in next version.
> > + IFR_TYPE,
> > + SMI_TYPE,
> > + MAX_REGMAP_TYPE,
>
> This is not used, right? Do you really need it?
>
I'll remove it.
> > +};
> > +
> > +struct bus_prot {
> > + enum regmap_type type;
> > + u32 set_ofs;
> > + u32 clr_ofs;
> > + u32 en_ofs;
> > + u32 sta_ofs;
> > + u32 mask;
> > + u32 clr_ack_mask;
> > +};
> > +
> > +int mtk_scpsys_ext_set_bus_protection(const struct bus_prot *bp_table,
> > + struct regmap *infracfg, struct regmap *smi_common);
> > +int mtk_scpsys_ext_clear_bus_protection(const struct bus_prot *bp_table,
> > + struct regmap *infracfg, struct regmap *smi_common);
> > +
> > +#endif /* __SOC_MEDIATEK_SCPSYS_EXT_H */
> > --
> > 2.18.0
> >