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 | |
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')
-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; |