aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/soc
diff options
context:
space:
mode:
authorJames Liao <jamesjj.liao@mediatek.com>2015-10-07 05:14:40 -0400
committerMatthias Brugger <matthias.bgg@gmail.com>2015-10-14 09:34:43 -0400
commit41b3e0f067c26dd17837aa49fba13fcb5c6319e1 (patch)
treebd8bb92f2cc008f98efed6b4e89bac8db5ce8824 /drivers/soc
parent47e90154fafd1a1310e3c5baed77d8f4c33ab271 (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.c67
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
56enum clk_id { 56enum 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
63struct scp_domain_data { 67struct 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;
168struct scp_domain { 172struct 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
287err_pwr_ack: 296err_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 }
289err_clk: 301err_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;