提交 fa7e843a 编写于 作者: W weiyi.lu@mediatek.com 提交者: Matthias Brugger

soc: mediatek: extend bus protection API

MT2712 add "set/clear" bus control register to each control register set
instead of providing only one "enable" control register, we could avoid
the read-modify-write racing by declaring "bus_prot_reg_update" as "false"
in scp_soc_data or declaring as "true" to use the legacy update method.
By improving the mtk-infracfg bus protection implementation to
support set/clear bus protection control method by IC configuration.
Signed-off-by: NWeiyi Lu <weiyi.lu@mediatek.com>
Signed-off-by: NMatthias Brugger <matthias.bgg@gmail.com>
上级 3dcf01c9
...@@ -19,23 +19,33 @@ ...@@ -19,23 +19,33 @@
#define INFRA_TOPAXI_PROTECTEN 0x0220 #define INFRA_TOPAXI_PROTECTEN 0x0220
#define INFRA_TOPAXI_PROTECTSTA1 0x0228 #define INFRA_TOPAXI_PROTECTSTA1 0x0228
#define INFRA_TOPAXI_PROTECTEN_SET 0x0260
#define INFRA_TOPAXI_PROTECTEN_CLR 0x0264
/** /**
* mtk_infracfg_set_bus_protection - enable bus protection * mtk_infracfg_set_bus_protection - enable bus protection
* @regmap: The infracfg regmap * @regmap: The infracfg regmap
* @mask: The mask containing the protection bits to be enabled. * @mask: The mask containing the protection bits to be enabled.
* @reg_update: The boolean flag determines to set the protection bits
* by regmap_update_bits with enable register(PROTECTEN) or
* by regmap_write with set register(PROTECTEN_SET).
* *
* This function enables the bus protection bits for disabled power * This function enables the bus protection bits for disabled power
* domains so that the system does not hang when some unit accesses the * domains so that the system does not hang when some unit accesses the
* bus while in power down. * bus while in power down.
*/ */
int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask) int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask,
bool reg_update)
{ {
unsigned long expired; unsigned long expired;
u32 val; u32 val;
int ret; int ret;
regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask, mask); if (reg_update)
regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask,
mask);
else
regmap_write(infracfg, INFRA_TOPAXI_PROTECTEN_SET, mask);
expired = jiffies + HZ; expired = jiffies + HZ;
...@@ -59,16 +69,24 @@ int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask) ...@@ -59,16 +69,24 @@ int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask)
* mtk_infracfg_clear_bus_protection - disable bus protection * mtk_infracfg_clear_bus_protection - disable bus protection
* @regmap: The infracfg regmap * @regmap: The infracfg regmap
* @mask: The mask containing the protection bits to be disabled. * @mask: The mask containing the protection bits to be disabled.
* @reg_update: The boolean flag determines to clear the protection bits
* by regmap_update_bits with enable register(PROTECTEN) or
* by regmap_write with clear register(PROTECTEN_CLR).
* *
* This function disables the bus protection bits previously enabled with * This function disables the bus protection bits previously enabled with
* mtk_infracfg_set_bus_protection. * mtk_infracfg_set_bus_protection.
*/ */
int mtk_infracfg_clear_bus_protection(struct regmap *infracfg, u32 mask)
int mtk_infracfg_clear_bus_protection(struct regmap *infracfg, u32 mask,
bool reg_update)
{ {
unsigned long expired; unsigned long expired;
int ret; int ret;
regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask, 0); if (reg_update)
regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask, 0);
else
regmap_write(infracfg, INFRA_TOPAXI_PROTECTEN_CLR, mask);
expired = jiffies + HZ; expired = jiffies + HZ;
......
...@@ -134,6 +134,7 @@ struct scp { ...@@ -134,6 +134,7 @@ struct scp {
void __iomem *base; void __iomem *base;
struct regmap *infracfg; struct regmap *infracfg;
struct scp_ctrl_reg ctrl_reg; struct scp_ctrl_reg ctrl_reg;
bool bus_prot_reg_update;
}; };
struct scp_subdomain { struct scp_subdomain {
...@@ -147,6 +148,7 @@ struct scp_soc_data { ...@@ -147,6 +148,7 @@ struct scp_soc_data {
const struct scp_subdomain *subdomains; const struct scp_subdomain *subdomains;
int num_subdomains; int num_subdomains;
const struct scp_ctrl_reg regs; const struct scp_ctrl_reg regs;
bool bus_prot_reg_update;
}; };
static int scpsys_domain_is_on(struct scp_domain *scpd) static int scpsys_domain_is_on(struct scp_domain *scpd)
...@@ -254,7 +256,8 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) ...@@ -254,7 +256,8 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
if (scpd->data->bus_prot_mask) { if (scpd->data->bus_prot_mask) {
ret = mtk_infracfg_clear_bus_protection(scp->infracfg, ret = mtk_infracfg_clear_bus_protection(scp->infracfg,
scpd->data->bus_prot_mask); scpd->data->bus_prot_mask,
scp->bus_prot_reg_update);
if (ret) if (ret)
goto err_pwr_ack; goto err_pwr_ack;
} }
...@@ -289,7 +292,8 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) ...@@ -289,7 +292,8 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
if (scpd->data->bus_prot_mask) { if (scpd->data->bus_prot_mask) {
ret = mtk_infracfg_set_bus_protection(scp->infracfg, ret = mtk_infracfg_set_bus_protection(scp->infracfg,
scpd->data->bus_prot_mask); scpd->data->bus_prot_mask,
scp->bus_prot_reg_update);
if (ret) if (ret)
goto out; goto out;
} }
...@@ -371,7 +375,8 @@ static void init_clks(struct platform_device *pdev, struct clk **clk) ...@@ -371,7 +375,8 @@ static void init_clks(struct platform_device *pdev, struct clk **clk)
static struct scp *init_scp(struct platform_device *pdev, static struct scp *init_scp(struct platform_device *pdev,
const struct scp_domain_data *scp_domain_data, int num, const struct scp_domain_data *scp_domain_data, int num,
const struct scp_ctrl_reg *scp_ctrl_reg) const struct scp_ctrl_reg *scp_ctrl_reg,
bool bus_prot_reg_update)
{ {
struct genpd_onecell_data *pd_data; struct genpd_onecell_data *pd_data;
struct resource *res; struct resource *res;
...@@ -386,6 +391,8 @@ static struct scp *init_scp(struct platform_device *pdev, ...@@ -386,6 +391,8 @@ static struct scp *init_scp(struct platform_device *pdev,
scp->ctrl_reg.pwr_sta_offs = scp_ctrl_reg->pwr_sta_offs; scp->ctrl_reg.pwr_sta_offs = scp_ctrl_reg->pwr_sta_offs;
scp->ctrl_reg.pwr_sta2nd_offs = scp_ctrl_reg->pwr_sta2nd_offs; scp->ctrl_reg.pwr_sta2nd_offs = scp_ctrl_reg->pwr_sta2nd_offs;
scp->bus_prot_reg_update = bus_prot_reg_update;
scp->dev = &pdev->dev; scp->dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
...@@ -806,7 +813,8 @@ static const struct scp_soc_data mt2701_data = { ...@@ -806,7 +813,8 @@ static const struct scp_soc_data mt2701_data = {
.regs = { .regs = {
.pwr_sta_offs = SPM_PWR_STATUS, .pwr_sta_offs = SPM_PWR_STATUS,
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
} },
.bus_prot_reg_update = true,
}; };
static const struct scp_soc_data mt6797_data = { static const struct scp_soc_data mt6797_data = {
...@@ -817,7 +825,8 @@ static const struct scp_soc_data mt6797_data = { ...@@ -817,7 +825,8 @@ static const struct scp_soc_data mt6797_data = {
.regs = { .regs = {
.pwr_sta_offs = SPM_PWR_STATUS_MT6797, .pwr_sta_offs = SPM_PWR_STATUS_MT6797,
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND_MT6797 .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND_MT6797
} },
.bus_prot_reg_update = true,
}; };
static const struct scp_soc_data mt7622_data = { static const struct scp_soc_data mt7622_data = {
...@@ -826,7 +835,8 @@ static const struct scp_soc_data mt7622_data = { ...@@ -826,7 +835,8 @@ static const struct scp_soc_data mt7622_data = {
.regs = { .regs = {
.pwr_sta_offs = SPM_PWR_STATUS, .pwr_sta_offs = SPM_PWR_STATUS,
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
} },
.bus_prot_reg_update = true,
}; };
static const struct scp_soc_data mt8173_data = { static const struct scp_soc_data mt8173_data = {
...@@ -837,7 +847,8 @@ static const struct scp_soc_data mt8173_data = { ...@@ -837,7 +847,8 @@ static const struct scp_soc_data mt8173_data = {
.regs = { .regs = {
.pwr_sta_offs = SPM_PWR_STATUS, .pwr_sta_offs = SPM_PWR_STATUS,
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
} },
.bus_prot_reg_update = true,
}; };
/* /*
...@@ -874,7 +885,8 @@ static int scpsys_probe(struct platform_device *pdev) ...@@ -874,7 +885,8 @@ static int scpsys_probe(struct platform_device *pdev)
match = of_match_device(of_scpsys_match_tbl, &pdev->dev); match = of_match_device(of_scpsys_match_tbl, &pdev->dev);
soc = (const struct scp_soc_data *)match->data; soc = (const struct scp_soc_data *)match->data;
scp = init_scp(pdev, soc->domains, soc->num_domains, &soc->regs); scp = init_scp(pdev, soc->domains, soc->num_domains, &soc->regs,
soc->bus_prot_reg_update);
if (IS_ERR(scp)) if (IS_ERR(scp))
return PTR_ERR(scp); return PTR_ERR(scp);
......
...@@ -28,7 +28,8 @@ ...@@ -28,7 +28,8 @@
#define MT7622_TOP_AXI_PROT_EN_WB (BIT(2) | BIT(6) | \ #define MT7622_TOP_AXI_PROT_EN_WB (BIT(2) | BIT(6) | \
BIT(7) | BIT(8)) BIT(7) | BIT(8))
int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask); int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask,
int mtk_infracfg_clear_bus_protection(struct regmap *infracfg, u32 mask); bool reg_update);
int mtk_infracfg_clear_bus_protection(struct regmap *infracfg, u32 mask,
bool reg_update);
#endif /* __SOC_MEDIATEK_INFRACFG_H */ #endif /* __SOC_MEDIATEK_INFRACFG_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册