diff options
| author | James Liao <jamesjj.liao@mediatek.com> | 2015-10-07 05:14:40 -0400 |
|---|---|---|
| committer | Matthias Brugger <matthias.bgg@gmail.com> | 2015-10-14 09:34:43 -0400 |
| commit | 41b3e0f067c26dd17837aa49fba13fcb5c6319e1 (patch) | |
| tree | bd8bb92f2cc008f98efed6b4e89bac8db5ce8824 /drivers/soc/mediatek | |
| parent | 47e90154fafd1a1310e3c5baed77d8f4c33ab271 (diff) | |
soc: mediatek: Fix random hang up issue while kernel init
In kernel late init, it turns off all unused clocks, which
needs to access subsystem registers such as VENC and VENC_LT.
Accessing MT8173 VENC registers needs two top clocks, mm_sel and
venc_sel. Accessing VENC_LT registers needs mm_sel and venclt_sel.
So we need to keep these clocks on before accessing their registers.
This patch keeps venc_sel / venclt_sel clock on when
VENC / VENC_LT's power is on, to prevent system hang up while
accessing its registeres.
Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
Diffstat (limited to 'drivers/soc/mediatek')
| -rw-r--r-- | drivers/soc/mediatek/mtk-scpsys.c | 67 |
1 files changed, 44 insertions, 23 deletions
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c index 55ab08ffc010..4d4203c896c4 100644 --- a/drivers/soc/mediatek/mtk-scpsys.c +++ b/drivers/soc/mediatek/mtk-scpsys.c | |||
| @@ -54,12 +54,16 @@ | |||
| 54 | #define PWR_STATUS_USB BIT(25) | 54 | #define PWR_STATUS_USB BIT(25) |
| 55 | 55 | ||
| 56 | enum clk_id { | 56 | enum clk_id { |
| 57 | MT8173_CLK_NONE, | ||
| 57 | MT8173_CLK_MM, | 58 | MT8173_CLK_MM, |
| 58 | MT8173_CLK_MFG, | 59 | MT8173_CLK_MFG, |
| 59 | MT8173_CLK_NONE, | 60 | MT8173_CLK_VENC, |
| 60 | MT8173_CLK_MAX = MT8173_CLK_NONE, | 61 | MT8173_CLK_VENC_LT, |
| 62 | MT8173_CLK_MAX, | ||
| 61 | }; | 63 | }; |
| 62 | 64 | ||
| 65 | #define MAX_CLKS 2 | ||
| 66 | |||
| 63 | struct scp_domain_data { | 67 | struct scp_domain_data { |
| 64 | const char *name; | 68 | const char *name; |
| 65 | u32 sta_mask; | 69 | u32 sta_mask; |
| @@ -67,7 +71,7 @@ struct scp_domain_data { | |||
| 67 | u32 sram_pdn_bits; | 71 | u32 sram_pdn_bits; |
| 68 | u32 sram_pdn_ack_bits; | 72 | u32 sram_pdn_ack_bits; |
| 69 | u32 bus_prot_mask; | 73 | u32 bus_prot_mask; |
| 70 | enum clk_id clk_id; | 74 | enum clk_id clk_id[MAX_CLKS]; |
| 71 | bool active_wakeup; | 75 | bool active_wakeup; |
| 72 | }; | 76 | }; |
| 73 | 77 | ||
| @@ -78,7 +82,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { | |||
| 78 | .ctl_offs = SPM_VDE_PWR_CON, | 82 | .ctl_offs = SPM_VDE_PWR_CON, |
| 79 | .sram_pdn_bits = GENMASK(11, 8), | 83 | .sram_pdn_bits = GENMASK(11, 8), |
| 80 | .sram_pdn_ack_bits = GENMASK(12, 12), | 84 | .sram_pdn_ack_bits = GENMASK(12, 12), |
| 81 | .clk_id = MT8173_CLK_MM, | 85 | .clk_id = {MT8173_CLK_MM}, |
| 82 | }, | 86 | }, |
| 83 | [MT8173_POWER_DOMAIN_VENC] = { | 87 | [MT8173_POWER_DOMAIN_VENC] = { |
| 84 | .name = "venc", | 88 | .name = "venc", |
| @@ -86,7 +90,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { | |||
| 86 | .ctl_offs = SPM_VEN_PWR_CON, | 90 | .ctl_offs = SPM_VEN_PWR_CON, |
| 87 | .sram_pdn_bits = GENMASK(11, 8), | 91 | .sram_pdn_bits = GENMASK(11, 8), |
| 88 | .sram_pdn_ack_bits = GENMASK(15, 12), | 92 | .sram_pdn_ack_bits = GENMASK(15, 12), |
| 89 | .clk_id = MT8173_CLK_MM, | 93 | .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC}, |
| 90 | }, | 94 | }, |
| 91 | [MT8173_POWER_DOMAIN_ISP] = { | 95 | [MT8173_POWER_DOMAIN_ISP] = { |
| 92 | .name = "isp", | 96 | .name = "isp", |
| @@ -94,7 +98,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { | |||
| 94 | .ctl_offs = SPM_ISP_PWR_CON, | 98 | .ctl_offs = SPM_ISP_PWR_CON, |
| 95 | .sram_pdn_bits = GENMASK(11, 8), | 99 | .sram_pdn_bits = GENMASK(11, 8), |
| 96 | .sram_pdn_ack_bits = GENMASK(13, 12), | 100 | .sram_pdn_ack_bits = GENMASK(13, 12), |
| 97 | .clk_id = MT8173_CLK_MM, | 101 | .clk_id = {MT8173_CLK_MM}, |
| 98 | }, | 102 | }, |
| 99 | [MT8173_POWER_DOMAIN_MM] = { | 103 | [MT8173_POWER_DOMAIN_MM] = { |
| 100 | .name = "mm", | 104 | .name = "mm", |
| @@ -102,7 +106,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { | |||
| 102 | .ctl_offs = SPM_DIS_PWR_CON, | 106 | .ctl_offs = SPM_DIS_PWR_CON, |
| 103 | .sram_pdn_bits = GENMASK(11, 8), | 107 | .sram_pdn_bits = GENMASK(11, 8), |
| 104 | .sram_pdn_ack_bits = GENMASK(12, 12), | 108 | .sram_pdn_ack_bits = GENMASK(12, 12), |
| 105 | .clk_id = MT8173_CLK_MM, | 109 | .clk_id = {MT8173_CLK_MM}, |
| 106 | .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | | 110 | .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | |
| 107 | MT8173_TOP_AXI_PROT_EN_MM_M1, | 111 | MT8173_TOP_AXI_PROT_EN_MM_M1, |
| 108 | }, | 112 | }, |
| @@ -112,7 +116,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { | |||
| 112 | .ctl_offs = SPM_VEN2_PWR_CON, | 116 | .ctl_offs = SPM_VEN2_PWR_CON, |
| 113 | .sram_pdn_bits = GENMASK(11, 8), | 117 | .sram_pdn_bits = GENMASK(11, 8), |
| 114 | .sram_pdn_ack_bits = GENMASK(15, 12), | 118 | .sram_pdn_ack_bits = GENMASK(15, 12), |
| 115 | .clk_id = MT8173_CLK_MM, | 119 | .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT}, |
| 116 | }, | 120 | }, |
| 117 | [MT8173_POWER_DOMAIN_AUDIO] = { | 121 | [MT8173_POWER_DOMAIN_AUDIO] = { |
| 118 | .name = "audio", | 122 | .name = "audio", |
| @@ -120,7 +124,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { | |||
| 120 | .ctl_offs = SPM_AUDIO_PWR_CON, | 124 | .ctl_offs = SPM_AUDIO_PWR_CON, |
| 121 | .sram_pdn_bits = GENMASK(11, 8), | 125 | .sram_pdn_bits = GENMASK(11, 8), |
| 122 | .sram_pdn_ack_bits = GENMASK(15, 12), | 126 | .sram_pdn_ack_bits = GENMASK(15, 12), |
| 123 | .clk_id = MT8173_CLK_NONE, | 127 | .clk_id = {MT8173_CLK_NONE}, |
| 124 | }, | 128 | }, |
| 125 | [MT8173_POWER_DOMAIN_USB] = { | 129 | [MT8173_POWER_DOMAIN_USB] = { |
| 126 | .name = "usb", | 130 | .name = "usb", |
| @@ -128,7 +132,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { | |||
| 128 | .ctl_offs = SPM_USB_PWR_CON, | 132 | .ctl_offs = SPM_USB_PWR_CON, |
| 129 | .sram_pdn_bits = GENMASK(11, 8), | 133 | .sram_pdn_bits = GENMASK(11, 8), |
| 130 | .sram_pdn_ack_bits = GENMASK(15, 12), | 134 | .sram_pdn_ack_bits = GENMASK(15, 12), |
| 131 | .clk_id = MT8173_CLK_NONE, | 135 | .clk_id = {MT8173_CLK_NONE}, |
| 132 | .active_wakeup = true, | 136 | .active_wakeup = true, |
| 133 | }, | 137 | }, |
| 134 | [MT8173_POWER_DOMAIN_MFG_ASYNC] = { | 138 | [MT8173_POWER_DOMAIN_MFG_ASYNC] = { |
| @@ -137,7 +141,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { | |||
| 137 | .ctl_offs = SPM_MFG_ASYNC_PWR_CON, | 141 | .ctl_offs = SPM_MFG_ASYNC_PWR_CON, |
| 138 | .sram_pdn_bits = GENMASK(11, 8), | 142 | .sram_pdn_bits = GENMASK(11, 8), |
| 139 | .sram_pdn_ack_bits = 0, | 143 | .sram_pdn_ack_bits = 0, |
| 140 | .clk_id = MT8173_CLK_MFG, | 144 | .clk_id = {MT8173_CLK_MFG}, |
| 141 | }, | 145 | }, |
| 142 | [MT8173_POWER_DOMAIN_MFG_2D] = { | 146 | [MT8173_POWER_DOMAIN_MFG_2D] = { |
| 143 | .name = "mfg_2d", | 147 | .name = "mfg_2d", |
| @@ -145,7 +149,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { | |||
| 145 | .ctl_offs = SPM_MFG_2D_PWR_CON, | 149 | .ctl_offs = SPM_MFG_2D_PWR_CON, |
| 146 | .sram_pdn_bits = GENMASK(11, 8), | 150 | .sram_pdn_bits = GENMASK(11, 8), |
| 147 | .sram_pdn_ack_bits = GENMASK(13, 12), | 151 | .sram_pdn_ack_bits = GENMASK(13, 12), |
| 148 | .clk_id = MT8173_CLK_NONE, | 152 | .clk_id = {MT8173_CLK_NONE}, |
| 149 | }, | 153 | }, |
| 150 | [MT8173_POWER_DOMAIN_MFG] = { | 154 | [MT8173_POWER_DOMAIN_MFG] = { |
| 151 | .name = "mfg", | 155 | .name = "mfg", |
| @@ -153,7 +157,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = { | |||
| 153 | .ctl_offs = SPM_MFG_PWR_CON, | 157 | .ctl_offs = SPM_MFG_PWR_CON, |
| 154 | .sram_pdn_bits = GENMASK(13, 8), | 158 | .sram_pdn_bits = GENMASK(13, 8), |
| 155 | .sram_pdn_ack_bits = GENMASK(21, 16), | 159 | .sram_pdn_ack_bits = GENMASK(21, 16), |
| 156 | .clk_id = MT8173_CLK_NONE, | 160 | .clk_id = {MT8173_CLK_NONE}, |
| 157 | .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | | 161 | .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | |
| 158 | MT8173_TOP_AXI_PROT_EN_MFG_M0 | | 162 | MT8173_TOP_AXI_PROT_EN_MFG_M0 | |
| 159 | MT8173_TOP_AXI_PROT_EN_MFG_M1 | | 163 | MT8173_TOP_AXI_PROT_EN_MFG_M1 | |
| @@ -168,7 +172,7 @@ struct scp; | |||
| 168 | struct scp_domain { | 172 | struct scp_domain { |
| 169 | struct generic_pm_domain genpd; | 173 | struct generic_pm_domain genpd; |
| 170 | struct scp *scp; | 174 | struct scp *scp; |
| 171 | struct clk *clk; | 175 | struct clk *clk[MAX_CLKS]; |
| 172 | u32 sta_mask; | 176 | u32 sta_mask; |
| 173 | void __iomem *ctl_addr; | 177 | void __iomem *ctl_addr; |
| 174 | u32 sram_pdn_bits; | 178 | u32 sram_pdn_bits; |
| @@ -215,11 +219,16 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) | |||
| 215 | u32 sram_pdn_ack = scpd->sram_pdn_ack_bits; | 219 | u32 sram_pdn_ack = scpd->sram_pdn_ack_bits; |
| 216 | u32 val; | 220 | u32 val; |
| 217 | int ret; | 221 | int ret; |
| 222 | int i; | ||
| 223 | |||
| 224 | for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) { | ||
| 225 | ret = clk_prepare_enable(scpd->clk[i]); | ||
| 226 | if (ret) { | ||
| 227 | for (--i; i >= 0; i--) | ||
| 228 | clk_disable_unprepare(scpd->clk[i]); | ||
| 218 | 229 | ||
| 219 | if (scpd->clk) { | ||
| 220 | ret = clk_prepare_enable(scpd->clk); | ||
| 221 | if (ret) | ||
| 222 | goto err_clk; | 230 | goto err_clk; |
| 231 | } | ||
| 223 | } | 232 | } |
| 224 | 233 | ||
| 225 | val = readl(ctl_addr); | 234 | val = readl(ctl_addr); |
| @@ -285,7 +294,10 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) | |||
| 285 | return 0; | 294 | return 0; |
| 286 | 295 | ||
| 287 | err_pwr_ack: | 296 | err_pwr_ack: |
| 288 | clk_disable_unprepare(scpd->clk); | 297 | for (i = MAX_CLKS - 1; i >= 0; i--) { |
| 298 | if (scpd->clk[i]) | ||
| 299 | clk_disable_unprepare(scpd->clk[i]); | ||
| 300 | } | ||
| 289 | err_clk: | 301 | err_clk: |
| 290 | dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name); | 302 | dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name); |
| 291 | 303 | ||
| @@ -302,6 +314,7 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) | |||
| 302 | u32 pdn_ack = scpd->sram_pdn_ack_bits; | 314 | u32 pdn_ack = scpd->sram_pdn_ack_bits; |
| 303 | u32 val; | 315 | u32 val; |
| 304 | int ret; | 316 | int ret; |
| 317 | int i; | ||
| 305 | 318 | ||
| 306 | if (scpd->bus_prot_mask) { | 319 | if (scpd->bus_prot_mask) { |
| 307 | ret = mtk_infracfg_set_bus_protection(scp->infracfg, | 320 | ret = mtk_infracfg_set_bus_protection(scp->infracfg, |
| @@ -363,8 +376,8 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) | |||
| 363 | expired = true; | 376 | expired = true; |
| 364 | } | 377 | } |
| 365 | 378 | ||
| 366 | if (scpd->clk) | 379 | for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) |
| 367 | clk_disable_unprepare(scpd->clk); | 380 | clk_disable_unprepare(scpd->clk[i]); |
| 368 | 381 | ||
| 369 | return 0; | 382 | return 0; |
| 370 | 383 | ||
| @@ -389,7 +402,7 @@ static int __init scpsys_probe(struct platform_device *pdev) | |||
| 389 | { | 402 | { |
| 390 | struct genpd_onecell_data *pd_data; | 403 | struct genpd_onecell_data *pd_data; |
| 391 | struct resource *res; | 404 | struct resource *res; |
| 392 | int i, ret; | 405 | int i, j, ret; |
| 393 | struct scp *scp; | 406 | struct scp *scp; |
| 394 | struct clk *clk[MT8173_CLK_MAX]; | 407 | struct clk *clk[MT8173_CLK_MAX]; |
| 395 | 408 | ||
| @@ -419,6 +432,14 @@ static int __init scpsys_probe(struct platform_device *pdev) | |||
| 419 | if (IS_ERR(clk[MT8173_CLK_MFG])) | 432 | if (IS_ERR(clk[MT8173_CLK_MFG])) |
| 420 | return PTR_ERR(clk[MT8173_CLK_MFG]); | 433 | return PTR_ERR(clk[MT8173_CLK_MFG]); |
| 421 | 434 | ||
| 435 | clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc"); | ||
| 436 | if (IS_ERR(clk[MT8173_CLK_VENC])) | ||
| 437 | return PTR_ERR(clk[MT8173_CLK_VENC]); | ||
| 438 | |||
| 439 | clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt"); | ||
| 440 | if (IS_ERR(clk[MT8173_CLK_VENC_LT])) | ||
| 441 | return PTR_ERR(clk[MT8173_CLK_VENC_LT]); | ||
| 442 | |||
| 422 | scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, | 443 | scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, |
| 423 | "infracfg"); | 444 | "infracfg"); |
| 424 | if (IS_ERR(scp->infracfg)) { | 445 | if (IS_ERR(scp->infracfg)) { |
| @@ -443,8 +464,8 @@ static int __init scpsys_probe(struct platform_device *pdev) | |||
| 443 | scpd->sram_pdn_ack_bits = data->sram_pdn_ack_bits; | 464 | scpd->sram_pdn_ack_bits = data->sram_pdn_ack_bits; |
| 444 | scpd->bus_prot_mask = data->bus_prot_mask; | 465 | scpd->bus_prot_mask = data->bus_prot_mask; |
| 445 | scpd->active_wakeup = data->active_wakeup; | 466 | scpd->active_wakeup = data->active_wakeup; |
| 446 | if (data->clk_id != MT8173_CLK_NONE) | 467 | for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) |
| 447 | scpd->clk = clk[data->clk_id]; | 468 | scpd->clk[j] = clk[data->clk_id[j]]; |
| 448 | 469 | ||
| 449 | genpd->name = data->name; | 470 | genpd->name = data->name; |
| 450 | genpd->power_off = scpsys_power_off; | 471 | genpd->power_off = scpsys_power_off; |
