]>
Commit | Line | Data |
---|---|---|
1802d0be | 1 | // SPDX-License-Identifier: GPL-2.0-only |
c84e3587 SH |
2 | /* |
3 | * Copyright (c) 2015 Pengutronix, Sascha Hauer <kernel@pengutronix.de> | |
c84e3587 SH |
4 | */ |
5 | #include <linux/clk.h> | |
6078c651 | 6 | #include <linux/init.h> |
c84e3587 | 7 | #include <linux/io.h> |
4a58732c | 8 | #include <linux/iopoll.h> |
c84e3587 SH |
9 | #include <linux/mfd/syscon.h> |
10 | #include <linux/of_device.h> | |
11 | #include <linux/platform_device.h> | |
12 | #include <linux/pm_domain.h> | |
4688f385 | 13 | #include <linux/regulator/consumer.h> |
6078c651 JL |
14 | #include <linux/soc/mediatek/infracfg.h> |
15 | ||
112ef188 | 16 | #include <dt-bindings/power/mt2701-power.h> |
320f4ced | 17 | #include <dt-bindings/power/mt2712-power.h> |
36c310f5 | 18 | #include <dt-bindings/power/mt6797-power.h> |
52510ee9 | 19 | #include <dt-bindings/power/mt7622-power.h> |
c932ba8c | 20 | #include <dt-bindings/power/mt7623a-power.h> |
c84e3587 SH |
21 | #include <dt-bindings/power/mt8173-power.h> |
22 | ||
4a58732c | 23 | #define MTK_POLL_DELAY_US 10 |
90a94314 | 24 | #define MTK_POLL_TIMEOUT USEC_PER_SEC |
4a58732c | 25 | |
ddf7aa99 | 26 | #define MTK_SCPD_ACTIVE_WAKEUP BIT(0) |
1ba96062 | 27 | #define MTK_SCPD_FWAIT_SRAM BIT(1) |
ddf7aa99 SW |
28 | #define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x)) |
29 | ||
c84e3587 SH |
30 | #define SPM_VDE_PWR_CON 0x0210 |
31 | #define SPM_MFG_PWR_CON 0x0214 | |
32 | #define SPM_VEN_PWR_CON 0x0230 | |
33 | #define SPM_ISP_PWR_CON 0x0238 | |
34 | #define SPM_DIS_PWR_CON 0x023c | |
112ef188 | 35 | #define SPM_CONN_PWR_CON 0x0280 |
c84e3587 | 36 | #define SPM_VEN2_PWR_CON 0x0298 |
320f4ced | 37 | #define SPM_AUDIO_PWR_CON 0x029c /* MT8173, MT2712 */ |
112ef188 SW |
38 | #define SPM_BDP_PWR_CON 0x029c /* MT2701 */ |
39 | #define SPM_ETH_PWR_CON 0x02a0 | |
40 | #define SPM_HIF_PWR_CON 0x02a4 | |
41 | #define SPM_IFR_MSC_PWR_CON 0x02a8 | |
c84e3587 SH |
42 | #define SPM_MFG_2D_PWR_CON 0x02c0 |
43 | #define SPM_MFG_ASYNC_PWR_CON 0x02c4 | |
44 | #define SPM_USB_PWR_CON 0x02cc | |
320f4ced | 45 | #define SPM_USB2_PWR_CON 0x02d4 /* MT2712 */ |
52510ee9 SW |
46 | #define SPM_ETHSYS_PWR_CON 0x02e0 /* MT7622 */ |
47 | #define SPM_HIF0_PWR_CON 0x02e4 /* MT7622 */ | |
48 | #define SPM_HIF1_PWR_CON 0x02e8 /* MT7622 */ | |
49 | #define SPM_WB_PWR_CON 0x02ec /* MT7622 */ | |
50 | ||
c84e3587 SH |
51 | #define SPM_PWR_STATUS 0x060c |
52 | #define SPM_PWR_STATUS_2ND 0x0610 | |
53 | ||
54 | #define PWR_RST_B_BIT BIT(0) | |
55 | #define PWR_ISO_BIT BIT(1) | |
56 | #define PWR_ON_BIT BIT(2) | |
57 | #define PWR_ON_2ND_BIT BIT(3) | |
58 | #define PWR_CLK_DIS_BIT BIT(4) | |
59 | ||
112ef188 | 60 | #define PWR_STATUS_CONN BIT(1) |
c84e3587 SH |
61 | #define PWR_STATUS_DISP BIT(3) |
62 | #define PWR_STATUS_MFG BIT(4) | |
63 | #define PWR_STATUS_ISP BIT(5) | |
64 | #define PWR_STATUS_VDEC BIT(7) | |
112ef188 SW |
65 | #define PWR_STATUS_BDP BIT(14) |
66 | #define PWR_STATUS_ETH BIT(15) | |
67 | #define PWR_STATUS_HIF BIT(16) | |
68 | #define PWR_STATUS_IFR_MSC BIT(17) | |
320f4ced | 69 | #define PWR_STATUS_USB2 BIT(19) /* MT2712 */ |
c84e3587 SH |
70 | #define PWR_STATUS_VENC_LT BIT(20) |
71 | #define PWR_STATUS_VENC BIT(21) | |
320f4ced | 72 | #define PWR_STATUS_MFG_2D BIT(22) /* MT8173 */ |
73 | #define PWR_STATUS_MFG_ASYNC BIT(23) /* MT8173 */ | |
74 | #define PWR_STATUS_AUDIO BIT(24) /* MT8173, MT2712 */ | |
75 | #define PWR_STATUS_USB BIT(25) /* MT8173, MT2712 */ | |
52510ee9 SW |
76 | #define PWR_STATUS_ETHSYS BIT(24) /* MT7622 */ |
77 | #define PWR_STATUS_HIF0 BIT(25) /* MT7622 */ | |
78 | #define PWR_STATUS_HIF1 BIT(26) /* MT7622 */ | |
79 | #define PWR_STATUS_WB BIT(27) /* MT7622 */ | |
c84e3587 SH |
80 | |
81 | enum clk_id { | |
6078c651 JL |
82 | CLK_NONE, |
83 | CLK_MM, | |
84 | CLK_MFG, | |
85 | CLK_VENC, | |
86 | CLK_VENC_LT, | |
112ef188 | 87 | CLK_ETHIF, |
a3acbbf4 | 88 | CLK_VDEC, |
52510ee9 | 89 | CLK_HIFSEL, |
d1fb29fa | 90 | CLK_JPGDEC, |
91 | CLK_AUDIO, | |
6078c651 JL |
92 | CLK_MAX, |
93 | }; | |
94 | ||
95 | static const char * const clk_names[] = { | |
96 | NULL, | |
97 | "mm", | |
98 | "mfg", | |
99 | "venc", | |
100 | "venc_lt", | |
112ef188 | 101 | "ethif", |
a3acbbf4 | 102 | "vdec", |
52510ee9 | 103 | "hif_sel", |
d1fb29fa | 104 | "jpgdec", |
105 | "audio", | |
6078c651 | 106 | NULL, |
c84e3587 SH |
107 | }; |
108 | ||
d1fb29fa | 109 | #define MAX_CLKS 3 |
41b3e0f0 | 110 | |
90a94314 WL |
111 | /** |
112 | * struct scp_domain_data - scp domain data for power on/off flow | |
113 | * @name: The domain name. | |
114 | * @sta_mask: The mask for power on/off status bit. | |
115 | * @ctl_offs: The offset for main power control register. | |
116 | * @sram_pdn_bits: The mask for sram power control bits. | |
117 | * @sram_pdn_ack_bits: The mask for sram power control acked bits. | |
118 | * @bus_prot_mask: The mask for single step bus protection. | |
119 | * @clk_id: The basic clocks required by this power domain. | |
120 | * @caps: The flag for active wake-up action. | |
121 | */ | |
c84e3587 SH |
122 | struct scp_domain_data { |
123 | const char *name; | |
124 | u32 sta_mask; | |
125 | int ctl_offs; | |
126 | u32 sram_pdn_bits; | |
127 | u32 sram_pdn_ack_bits; | |
128 | u32 bus_prot_mask; | |
41b3e0f0 | 129 | enum clk_id clk_id[MAX_CLKS]; |
ddf7aa99 | 130 | u8 caps; |
c84e3587 SH |
131 | }; |
132 | ||
c84e3587 SH |
133 | struct scp; |
134 | ||
135 | struct scp_domain { | |
136 | struct generic_pm_domain genpd; | |
137 | struct scp *scp; | |
41b3e0f0 | 138 | struct clk *clk[MAX_CLKS]; |
be29523d | 139 | const struct scp_domain_data *data; |
4688f385 | 140 | struct regulator *supply; |
c84e3587 SH |
141 | }; |
142 | ||
f1be4c4e MC |
143 | struct scp_ctrl_reg { |
144 | int pwr_sta_offs; | |
145 | int pwr_sta2nd_offs; | |
146 | }; | |
147 | ||
c84e3587 | 148 | struct scp { |
6078c651 | 149 | struct scp_domain *domains; |
c84e3587 SH |
150 | struct genpd_onecell_data pd_data; |
151 | struct device *dev; | |
152 | void __iomem *base; | |
153 | struct regmap *infracfg; | |
f1be4c4e | 154 | struct scp_ctrl_reg ctrl_reg; |
fa7e843a | 155 | bool bus_prot_reg_update; |
c84e3587 SH |
156 | }; |
157 | ||
53fddb1a SW |
158 | struct scp_subdomain { |
159 | int origin; | |
160 | int subdomain; | |
161 | }; | |
162 | ||
163 | struct scp_soc_data { | |
164 | const struct scp_domain_data *domains; | |
165 | int num_domains; | |
166 | const struct scp_subdomain *subdomains; | |
167 | int num_subdomains; | |
168 | const struct scp_ctrl_reg regs; | |
fa7e843a | 169 | bool bus_prot_reg_update; |
53fddb1a SW |
170 | }; |
171 | ||
c84e3587 SH |
172 | static int scpsys_domain_is_on(struct scp_domain *scpd) |
173 | { | |
174 | struct scp *scp = scpd->scp; | |
175 | ||
f1be4c4e MC |
176 | u32 status = readl(scp->base + scp->ctrl_reg.pwr_sta_offs) & |
177 | scpd->data->sta_mask; | |
178 | u32 status2 = readl(scp->base + scp->ctrl_reg.pwr_sta2nd_offs) & | |
179 | scpd->data->sta_mask; | |
c84e3587 SH |
180 | |
181 | /* | |
182 | * A domain is on when both status bits are set. If only one is set | |
183 | * return an error. This happens while powering up a domain | |
184 | */ | |
185 | ||
186 | if (status && status2) | |
187 | return true; | |
188 | if (!status && !status2) | |
189 | return false; | |
190 | ||
191 | return -EINVAL; | |
192 | } | |
193 | ||
d744d035 WL |
194 | static int scpsys_regulator_enable(struct scp_domain *scpd) |
195 | { | |
196 | if (!scpd->supply) | |
197 | return 0; | |
198 | ||
199 | return regulator_enable(scpd->supply); | |
200 | } | |
201 | ||
202 | static int scpsys_regulator_disable(struct scp_domain *scpd) | |
203 | { | |
204 | if (!scpd->supply) | |
205 | return 0; | |
206 | ||
207 | return regulator_disable(scpd->supply); | |
208 | } | |
209 | ||
cef021e2 WL |
210 | static void scpsys_clk_disable(struct clk *clk[], int max_num) |
211 | { | |
212 | int i; | |
213 | ||
214 | for (i = max_num - 1; i >= 0; i--) | |
215 | clk_disable_unprepare(clk[i]); | |
216 | } | |
217 | ||
218 | static int scpsys_clk_enable(struct clk *clk[], int max_num) | |
219 | { | |
220 | int i, ret = 0; | |
221 | ||
222 | for (i = 0; i < max_num && clk[i]; i++) { | |
223 | ret = clk_prepare_enable(clk[i]); | |
224 | if (ret) { | |
225 | scpsys_clk_disable(clk, i); | |
226 | break; | |
227 | } | |
228 | } | |
229 | ||
230 | return ret; | |
231 | } | |
232 | ||
0545aa1b WL |
233 | static int scpsys_sram_enable(struct scp_domain *scpd, void __iomem *ctl_addr) |
234 | { | |
235 | u32 val; | |
236 | u32 pdn_ack = scpd->data->sram_pdn_ack_bits; | |
237 | int tmp; | |
238 | ||
239 | val = readl(ctl_addr); | |
240 | val &= ~scpd->data->sram_pdn_bits; | |
241 | writel(val, ctl_addr); | |
242 | ||
243 | /* Either wait until SRAM_PDN_ACK all 0 or have a force wait */ | |
244 | if (MTK_SCPD_CAPS(scpd, MTK_SCPD_FWAIT_SRAM)) { | |
245 | /* | |
246 | * Currently, MTK_SCPD_FWAIT_SRAM is necessary only for | |
247 | * MT7622_POWER_DOMAIN_WB and thus just a trivial setup | |
248 | * is applied here. | |
249 | */ | |
250 | usleep_range(12000, 12100); | |
251 | } else { | |
252 | /* Either wait until SRAM_PDN_ACK all 1 or 0 */ | |
253 | int ret = readl_poll_timeout(ctl_addr, tmp, | |
254 | (tmp & pdn_ack) == 0, | |
255 | MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); | |
256 | if (ret < 0) | |
257 | return ret; | |
258 | } | |
259 | ||
260 | return 0; | |
261 | } | |
262 | ||
263 | static int scpsys_sram_disable(struct scp_domain *scpd, void __iomem *ctl_addr) | |
264 | { | |
265 | u32 val; | |
266 | u32 pdn_ack = scpd->data->sram_pdn_ack_bits; | |
267 | int tmp; | |
268 | ||
269 | val = readl(ctl_addr); | |
270 | val |= scpd->data->sram_pdn_bits; | |
271 | writel(val, ctl_addr); | |
272 | ||
273 | /* Either wait until SRAM_PDN_ACK all 1 or 0 */ | |
274 | return readl_poll_timeout(ctl_addr, tmp, | |
275 | (tmp & pdn_ack) == pdn_ack, | |
276 | MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); | |
277 | } | |
278 | ||
662c9d55 WL |
279 | static int scpsys_bus_protect_enable(struct scp_domain *scpd) |
280 | { | |
281 | struct scp *scp = scpd->scp; | |
282 | ||
283 | if (!scpd->data->bus_prot_mask) | |
284 | return 0; | |
285 | ||
286 | return mtk_infracfg_set_bus_protection(scp->infracfg, | |
287 | scpd->data->bus_prot_mask, | |
288 | scp->bus_prot_reg_update); | |
289 | } | |
290 | ||
291 | static int scpsys_bus_protect_disable(struct scp_domain *scpd) | |
292 | { | |
293 | struct scp *scp = scpd->scp; | |
294 | ||
295 | if (!scpd->data->bus_prot_mask) | |
296 | return 0; | |
297 | ||
298 | return mtk_infracfg_clear_bus_protection(scp->infracfg, | |
299 | scpd->data->bus_prot_mask, | |
300 | scp->bus_prot_reg_update); | |
301 | } | |
302 | ||
c84e3587 SH |
303 | static int scpsys_power_on(struct generic_pm_domain *genpd) |
304 | { | |
305 | struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd); | |
306 | struct scp *scp = scpd->scp; | |
be29523d | 307 | void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs; |
c84e3587 | 308 | u32 val; |
4a58732c | 309 | int ret, tmp; |
41b3e0f0 | 310 | |
d744d035 WL |
311 | ret = scpsys_regulator_enable(scpd); |
312 | if (ret < 0) | |
313 | return ret; | |
4688f385 | 314 | |
cef021e2 WL |
315 | ret = scpsys_clk_enable(scpd->clk, MAX_CLKS); |
316 | if (ret) | |
317 | goto err_clk; | |
c84e3587 | 318 | |
0545aa1b | 319 | /* subsys power on */ |
c84e3587 SH |
320 | val = readl(ctl_addr); |
321 | val |= PWR_ON_BIT; | |
322 | writel(val, ctl_addr); | |
323 | val |= PWR_ON_2ND_BIT; | |
324 | writel(val, ctl_addr); | |
325 | ||
326 | /* wait until PWR_ACK = 1 */ | |
4a58732c SW |
327 | ret = readx_poll_timeout(scpsys_domain_is_on, scpd, tmp, tmp > 0, |
328 | MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); | |
329 | if (ret < 0) | |
330 | goto err_pwr_ack; | |
c84e3587 SH |
331 | |
332 | val &= ~PWR_CLK_DIS_BIT; | |
333 | writel(val, ctl_addr); | |
334 | ||
335 | val &= ~PWR_ISO_BIT; | |
336 | writel(val, ctl_addr); | |
337 | ||
338 | val |= PWR_RST_B_BIT; | |
339 | writel(val, ctl_addr); | |
340 | ||
0545aa1b WL |
341 | ret = scpsys_sram_enable(scpd, ctl_addr); |
342 | if (ret < 0) | |
343 | goto err_pwr_ack; | |
c84e3587 | 344 | |
662c9d55 WL |
345 | ret = scpsys_bus_protect_disable(scpd); |
346 | if (ret < 0) | |
347 | goto err_pwr_ack; | |
c84e3587 SH |
348 | |
349 | return 0; | |
350 | ||
351 | err_pwr_ack: | |
cef021e2 | 352 | scpsys_clk_disable(scpd->clk, MAX_CLKS); |
c84e3587 | 353 | err_clk: |
d744d035 | 354 | scpsys_regulator_disable(scpd); |
4688f385 | 355 | |
c84e3587 SH |
356 | dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name); |
357 | ||
358 | return ret; | |
359 | } | |
360 | ||
361 | static int scpsys_power_off(struct generic_pm_domain *genpd) | |
362 | { | |
363 | struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd); | |
364 | struct scp *scp = scpd->scp; | |
be29523d | 365 | void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs; |
c84e3587 | 366 | u32 val; |
4a58732c | 367 | int ret, tmp; |
c84e3587 | 368 | |
662c9d55 WL |
369 | ret = scpsys_bus_protect_enable(scpd); |
370 | if (ret < 0) | |
371 | goto out; | |
c84e3587 | 372 | |
0545aa1b | 373 | ret = scpsys_sram_disable(scpd, ctl_addr); |
4a58732c SW |
374 | if (ret < 0) |
375 | goto out; | |
c84e3587 | 376 | |
0545aa1b WL |
377 | /* subsys power off */ |
378 | val = readl(ctl_addr); | |
c84e3587 SH |
379 | val |= PWR_ISO_BIT; |
380 | writel(val, ctl_addr); | |
381 | ||
382 | val &= ~PWR_RST_B_BIT; | |
383 | writel(val, ctl_addr); | |
384 | ||
385 | val |= PWR_CLK_DIS_BIT; | |
386 | writel(val, ctl_addr); | |
387 | ||
388 | val &= ~PWR_ON_BIT; | |
389 | writel(val, ctl_addr); | |
390 | ||
391 | val &= ~PWR_ON_2ND_BIT; | |
392 | writel(val, ctl_addr); | |
393 | ||
394 | /* wait until PWR_ACK = 0 */ | |
4a58732c SW |
395 | ret = readx_poll_timeout(scpsys_domain_is_on, scpd, tmp, tmp == 0, |
396 | MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); | |
397 | if (ret < 0) | |
398 | goto out; | |
c84e3587 | 399 | |
cef021e2 | 400 | scpsys_clk_disable(scpd->clk, MAX_CLKS); |
c84e3587 | 401 | |
d744d035 WL |
402 | ret = scpsys_regulator_disable(scpd); |
403 | if (ret < 0) | |
404 | goto out; | |
4688f385 | 405 | |
c84e3587 SH |
406 | return 0; |
407 | ||
408 | out: | |
409 | dev_err(scp->dev, "Failed to power off domain %s\n", genpd->name); | |
410 | ||
411 | return ret; | |
412 | } | |
413 | ||
6078c651 JL |
414 | static void init_clks(struct platform_device *pdev, struct clk **clk) |
415 | { | |
416 | int i; | |
417 | ||
418 | for (i = CLK_NONE + 1; i < CLK_MAX; i++) | |
419 | clk[i] = devm_clk_get(&pdev->dev, clk_names[i]); | |
420 | } | |
421 | ||
422 | static struct scp *init_scp(struct platform_device *pdev, | |
f1be4c4e | 423 | const struct scp_domain_data *scp_domain_data, int num, |
fa7e843a | 424 | const struct scp_ctrl_reg *scp_ctrl_reg, |
425 | bool bus_prot_reg_update) | |
c84e3587 SH |
426 | { |
427 | struct genpd_onecell_data *pd_data; | |
428 | struct resource *res; | |
6078c651 | 429 | int i, j; |
c84e3587 | 430 | struct scp *scp; |
6078c651 | 431 | struct clk *clk[CLK_MAX]; |
c84e3587 SH |
432 | |
433 | scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL); | |
434 | if (!scp) | |
6078c651 | 435 | return ERR_PTR(-ENOMEM); |
c84e3587 | 436 | |
f1be4c4e MC |
437 | scp->ctrl_reg.pwr_sta_offs = scp_ctrl_reg->pwr_sta_offs; |
438 | scp->ctrl_reg.pwr_sta2nd_offs = scp_ctrl_reg->pwr_sta2nd_offs; | |
439 | ||
fa7e843a | 440 | scp->bus_prot_reg_update = bus_prot_reg_update; |
441 | ||
c84e3587 SH |
442 | scp->dev = &pdev->dev; |
443 | ||
444 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
445 | scp->base = devm_ioremap_resource(&pdev->dev, res); | |
446 | if (IS_ERR(scp->base)) | |
6078c651 JL |
447 | return ERR_CAST(scp->base); |
448 | ||
a86854d0 KC |
449 | scp->domains = devm_kcalloc(&pdev->dev, |
450 | num, sizeof(*scp->domains), GFP_KERNEL); | |
6078c651 JL |
451 | if (!scp->domains) |
452 | return ERR_PTR(-ENOMEM); | |
c84e3587 SH |
453 | |
454 | pd_data = &scp->pd_data; | |
455 | ||
a86854d0 KC |
456 | pd_data->domains = devm_kcalloc(&pdev->dev, |
457 | num, sizeof(*pd_data->domains), GFP_KERNEL); | |
c84e3587 | 458 | if (!pd_data->domains) |
6078c651 | 459 | return ERR_PTR(-ENOMEM); |
41b3e0f0 | 460 | |
c84e3587 SH |
461 | scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, |
462 | "infracfg"); | |
463 | if (IS_ERR(scp->infracfg)) { | |
464 | dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n", | |
465 | PTR_ERR(scp->infracfg)); | |
6078c651 | 466 | return ERR_CAST(scp->infracfg); |
c84e3587 SH |
467 | } |
468 | ||
6078c651 | 469 | for (i = 0; i < num; i++) { |
4688f385 SH |
470 | struct scp_domain *scpd = &scp->domains[i]; |
471 | const struct scp_domain_data *data = &scp_domain_data[i]; | |
472 | ||
473 | scpd->supply = devm_regulator_get_optional(&pdev->dev, data->name); | |
474 | if (IS_ERR(scpd->supply)) { | |
475 | if (PTR_ERR(scpd->supply) == -ENODEV) | |
476 | scpd->supply = NULL; | |
477 | else | |
6078c651 | 478 | return ERR_CAST(scpd->supply); |
4688f385 SH |
479 | } |
480 | } | |
481 | ||
6078c651 | 482 | pd_data->num_domains = num; |
c84e3587 | 483 | |
6078c651 JL |
484 | init_clks(pdev, clk); |
485 | ||
486 | for (i = 0; i < num; i++) { | |
c84e3587 SH |
487 | struct scp_domain *scpd = &scp->domains[i]; |
488 | struct generic_pm_domain *genpd = &scpd->genpd; | |
489 | const struct scp_domain_data *data = &scp_domain_data[i]; | |
490 | ||
491 | pd_data->domains[i] = genpd; | |
492 | scpd->scp = scp; | |
493 | ||
be29523d | 494 | scpd->data = data; |
6078c651 JL |
495 | |
496 | for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) { | |
497 | struct clk *c = clk[data->clk_id[j]]; | |
498 | ||
499 | if (IS_ERR(c)) { | |
500 | dev_err(&pdev->dev, "%s: clk unavailable\n", | |
501 | data->name); | |
502 | return ERR_CAST(c); | |
503 | } | |
504 | ||
505 | scpd->clk[j] = c; | |
506 | } | |
c84e3587 SH |
507 | |
508 | genpd->name = data->name; | |
509 | genpd->power_off = scpsys_power_off; | |
510 | genpd->power_on = scpsys_power_on; | |
ddf7aa99 | 511 | if (MTK_SCPD_CAPS(scpd, MTK_SCPD_ACTIVE_WAKEUP)) |
7534d181 | 512 | genpd->flags |= GENPD_FLAG_ACTIVE_WAKEUP; |
6078c651 JL |
513 | } |
514 | ||
515 | return scp; | |
516 | } | |
517 | ||
518 | static void mtk_register_power_domains(struct platform_device *pdev, | |
519 | struct scp *scp, int num) | |
520 | { | |
521 | struct genpd_onecell_data *pd_data; | |
522 | int i, ret; | |
523 | ||
524 | for (i = 0; i < num; i++) { | |
525 | struct scp_domain *scpd = &scp->domains[i]; | |
526 | struct generic_pm_domain *genpd = &scpd->genpd; | |
c84e3587 SH |
527 | |
528 | /* | |
d9c9f3b8 JL |
529 | * Initially turn on all domains to make the domains usable |
530 | * with !CONFIG_PM and to get the hardware in sync with the | |
531 | * software. The unused domains will be switched off during | |
532 | * late_init time. | |
c84e3587 | 533 | */ |
d9c9f3b8 | 534 | genpd->power_on(genpd); |
c84e3587 | 535 | |
d9c9f3b8 | 536 | pm_genpd_init(genpd, NULL, false); |
c84e3587 SH |
537 | } |
538 | ||
539 | /* | |
540 | * We are not allowed to fail here since there is no way to unregister | |
541 | * a power domain. Once registered above we have to keep the domains | |
542 | * valid. | |
543 | */ | |
544 | ||
6078c651 JL |
545 | pd_data = &scp->pd_data; |
546 | ||
547 | ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data); | |
548 | if (ret) | |
549 | dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret); | |
550 | } | |
551 | ||
112ef188 SW |
552 | /* |
553 | * MT2701 power domain support | |
554 | */ | |
555 | ||
556 | static const struct scp_domain_data scp_domain_data_mt2701[] = { | |
557 | [MT2701_POWER_DOMAIN_CONN] = { | |
558 | .name = "conn", | |
559 | .sta_mask = PWR_STATUS_CONN, | |
560 | .ctl_offs = SPM_CONN_PWR_CON, | |
c59c9c85 SW |
561 | .bus_prot_mask = MT2701_TOP_AXI_PROT_EN_CONN_M | |
562 | MT2701_TOP_AXI_PROT_EN_CONN_S, | |
112ef188 | 563 | .clk_id = {CLK_NONE}, |
ddf7aa99 | 564 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
112ef188 SW |
565 | }, |
566 | [MT2701_POWER_DOMAIN_DISP] = { | |
567 | .name = "disp", | |
568 | .sta_mask = PWR_STATUS_DISP, | |
569 | .ctl_offs = SPM_DIS_PWR_CON, | |
570 | .sram_pdn_bits = GENMASK(11, 8), | |
571 | .clk_id = {CLK_MM}, | |
c59c9c85 | 572 | .bus_prot_mask = MT2701_TOP_AXI_PROT_EN_MM_M0, |
ddf7aa99 | 573 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
112ef188 SW |
574 | }, |
575 | [MT2701_POWER_DOMAIN_MFG] = { | |
576 | .name = "mfg", | |
577 | .sta_mask = PWR_STATUS_MFG, | |
578 | .ctl_offs = SPM_MFG_PWR_CON, | |
579 | .sram_pdn_bits = GENMASK(11, 8), | |
580 | .sram_pdn_ack_bits = GENMASK(12, 12), | |
581 | .clk_id = {CLK_MFG}, | |
ddf7aa99 | 582 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
112ef188 SW |
583 | }, |
584 | [MT2701_POWER_DOMAIN_VDEC] = { | |
585 | .name = "vdec", | |
586 | .sta_mask = PWR_STATUS_VDEC, | |
587 | .ctl_offs = SPM_VDE_PWR_CON, | |
588 | .sram_pdn_bits = GENMASK(11, 8), | |
589 | .sram_pdn_ack_bits = GENMASK(12, 12), | |
590 | .clk_id = {CLK_MM}, | |
ddf7aa99 | 591 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
112ef188 SW |
592 | }, |
593 | [MT2701_POWER_DOMAIN_ISP] = { | |
594 | .name = "isp", | |
595 | .sta_mask = PWR_STATUS_ISP, | |
596 | .ctl_offs = SPM_ISP_PWR_CON, | |
597 | .sram_pdn_bits = GENMASK(11, 8), | |
598 | .sram_pdn_ack_bits = GENMASK(13, 12), | |
599 | .clk_id = {CLK_MM}, | |
ddf7aa99 | 600 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
112ef188 SW |
601 | }, |
602 | [MT2701_POWER_DOMAIN_BDP] = { | |
603 | .name = "bdp", | |
604 | .sta_mask = PWR_STATUS_BDP, | |
605 | .ctl_offs = SPM_BDP_PWR_CON, | |
606 | .sram_pdn_bits = GENMASK(11, 8), | |
607 | .clk_id = {CLK_NONE}, | |
ddf7aa99 | 608 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
112ef188 SW |
609 | }, |
610 | [MT2701_POWER_DOMAIN_ETH] = { | |
611 | .name = "eth", | |
612 | .sta_mask = PWR_STATUS_ETH, | |
613 | .ctl_offs = SPM_ETH_PWR_CON, | |
614 | .sram_pdn_bits = GENMASK(11, 8), | |
615 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
616 | .clk_id = {CLK_ETHIF}, | |
ddf7aa99 | 617 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
112ef188 SW |
618 | }, |
619 | [MT2701_POWER_DOMAIN_HIF] = { | |
620 | .name = "hif", | |
621 | .sta_mask = PWR_STATUS_HIF, | |
622 | .ctl_offs = SPM_HIF_PWR_CON, | |
623 | .sram_pdn_bits = GENMASK(11, 8), | |
624 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
625 | .clk_id = {CLK_ETHIF}, | |
ddf7aa99 | 626 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
112ef188 SW |
627 | }, |
628 | [MT2701_POWER_DOMAIN_IFR_MSC] = { | |
629 | .name = "ifr_msc", | |
630 | .sta_mask = PWR_STATUS_IFR_MSC, | |
631 | .ctl_offs = SPM_IFR_MSC_PWR_CON, | |
632 | .clk_id = {CLK_NONE}, | |
ddf7aa99 | 633 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
112ef188 SW |
634 | }, |
635 | }; | |
636 | ||
320f4ced | 637 | /* |
638 | * MT2712 power domain support | |
639 | */ | |
640 | static const struct scp_domain_data scp_domain_data_mt2712[] = { | |
641 | [MT2712_POWER_DOMAIN_MM] = { | |
642 | .name = "mm", | |
643 | .sta_mask = PWR_STATUS_DISP, | |
644 | .ctl_offs = SPM_DIS_PWR_CON, | |
645 | .sram_pdn_bits = GENMASK(8, 8), | |
646 | .sram_pdn_ack_bits = GENMASK(12, 12), | |
647 | .clk_id = {CLK_MM}, | |
ddf7aa99 | 648 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
320f4ced | 649 | }, |
650 | [MT2712_POWER_DOMAIN_VDEC] = { | |
651 | .name = "vdec", | |
652 | .sta_mask = PWR_STATUS_VDEC, | |
653 | .ctl_offs = SPM_VDE_PWR_CON, | |
654 | .sram_pdn_bits = GENMASK(8, 8), | |
655 | .sram_pdn_ack_bits = GENMASK(12, 12), | |
656 | .clk_id = {CLK_MM, CLK_VDEC}, | |
ddf7aa99 | 657 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
320f4ced | 658 | }, |
659 | [MT2712_POWER_DOMAIN_VENC] = { | |
660 | .name = "venc", | |
661 | .sta_mask = PWR_STATUS_VENC, | |
662 | .ctl_offs = SPM_VEN_PWR_CON, | |
663 | .sram_pdn_bits = GENMASK(11, 8), | |
664 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
665 | .clk_id = {CLK_MM, CLK_VENC, CLK_JPGDEC}, | |
ddf7aa99 | 666 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
320f4ced | 667 | }, |
668 | [MT2712_POWER_DOMAIN_ISP] = { | |
669 | .name = "isp", | |
670 | .sta_mask = PWR_STATUS_ISP, | |
671 | .ctl_offs = SPM_ISP_PWR_CON, | |
672 | .sram_pdn_bits = GENMASK(11, 8), | |
673 | .sram_pdn_ack_bits = GENMASK(13, 12), | |
674 | .clk_id = {CLK_MM}, | |
ddf7aa99 | 675 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
320f4ced | 676 | }, |
677 | [MT2712_POWER_DOMAIN_AUDIO] = { | |
678 | .name = "audio", | |
679 | .sta_mask = PWR_STATUS_AUDIO, | |
680 | .ctl_offs = SPM_AUDIO_PWR_CON, | |
681 | .sram_pdn_bits = GENMASK(11, 8), | |
682 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
683 | .clk_id = {CLK_AUDIO}, | |
ddf7aa99 | 684 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
320f4ced | 685 | }, |
686 | [MT2712_POWER_DOMAIN_USB] = { | |
687 | .name = "usb", | |
688 | .sta_mask = PWR_STATUS_USB, | |
689 | .ctl_offs = SPM_USB_PWR_CON, | |
690 | .sram_pdn_bits = GENMASK(10, 8), | |
691 | .sram_pdn_ack_bits = GENMASK(14, 12), | |
692 | .clk_id = {CLK_NONE}, | |
ddf7aa99 | 693 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
320f4ced | 694 | }, |
695 | [MT2712_POWER_DOMAIN_USB2] = { | |
696 | .name = "usb2", | |
697 | .sta_mask = PWR_STATUS_USB2, | |
698 | .ctl_offs = SPM_USB2_PWR_CON, | |
699 | .sram_pdn_bits = GENMASK(10, 8), | |
700 | .sram_pdn_ack_bits = GENMASK(14, 12), | |
701 | .clk_id = {CLK_NONE}, | |
ddf7aa99 | 702 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
320f4ced | 703 | }, |
704 | [MT2712_POWER_DOMAIN_MFG] = { | |
705 | .name = "mfg", | |
706 | .sta_mask = PWR_STATUS_MFG, | |
707 | .ctl_offs = SPM_MFG_PWR_CON, | |
9f997126 | 708 | .sram_pdn_bits = GENMASK(8, 8), |
709 | .sram_pdn_ack_bits = GENMASK(16, 16), | |
320f4ced | 710 | .clk_id = {CLK_MFG}, |
711 | .bus_prot_mask = BIT(14) | BIT(21) | BIT(23), | |
ddf7aa99 | 712 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
320f4ced | 713 | }, |
9f997126 | 714 | [MT2712_POWER_DOMAIN_MFG_SC1] = { |
715 | .name = "mfg_sc1", | |
716 | .sta_mask = BIT(22), | |
717 | .ctl_offs = 0x02c0, | |
718 | .sram_pdn_bits = GENMASK(8, 8), | |
719 | .sram_pdn_ack_bits = GENMASK(16, 16), | |
720 | .clk_id = {CLK_NONE}, | |
ddf7aa99 | 721 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
9f997126 | 722 | }, |
723 | [MT2712_POWER_DOMAIN_MFG_SC2] = { | |
724 | .name = "mfg_sc2", | |
725 | .sta_mask = BIT(23), | |
726 | .ctl_offs = 0x02c4, | |
727 | .sram_pdn_bits = GENMASK(8, 8), | |
728 | .sram_pdn_ack_bits = GENMASK(16, 16), | |
729 | .clk_id = {CLK_NONE}, | |
ddf7aa99 | 730 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
9f997126 | 731 | }, |
732 | [MT2712_POWER_DOMAIN_MFG_SC3] = { | |
733 | .name = "mfg_sc3", | |
734 | .sta_mask = BIT(30), | |
735 | .ctl_offs = 0x01f8, | |
736 | .sram_pdn_bits = GENMASK(8, 8), | |
737 | .sram_pdn_ack_bits = GENMASK(16, 16), | |
738 | .clk_id = {CLK_NONE}, | |
ddf7aa99 | 739 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
9f997126 | 740 | }, |
741 | }; | |
742 | ||
743 | static const struct scp_subdomain scp_subdomain_mt2712[] = { | |
744 | {MT2712_POWER_DOMAIN_MM, MT2712_POWER_DOMAIN_VDEC}, | |
745 | {MT2712_POWER_DOMAIN_MM, MT2712_POWER_DOMAIN_VENC}, | |
746 | {MT2712_POWER_DOMAIN_MM, MT2712_POWER_DOMAIN_ISP}, | |
747 | {MT2712_POWER_DOMAIN_MFG, MT2712_POWER_DOMAIN_MFG_SC1}, | |
748 | {MT2712_POWER_DOMAIN_MFG_SC1, MT2712_POWER_DOMAIN_MFG_SC2}, | |
749 | {MT2712_POWER_DOMAIN_MFG_SC2, MT2712_POWER_DOMAIN_MFG_SC3}, | |
320f4ced | 750 | }; |
751 | ||
36c310f5 MC |
752 | /* |
753 | * MT6797 power domain support | |
754 | */ | |
755 | ||
756 | static const struct scp_domain_data scp_domain_data_mt6797[] = { | |
757 | [MT6797_POWER_DOMAIN_VDEC] = { | |
758 | .name = "vdec", | |
759 | .sta_mask = BIT(7), | |
760 | .ctl_offs = 0x300, | |
761 | .sram_pdn_bits = GENMASK(8, 8), | |
762 | .sram_pdn_ack_bits = GENMASK(12, 12), | |
763 | .clk_id = {CLK_VDEC}, | |
764 | }, | |
765 | [MT6797_POWER_DOMAIN_VENC] = { | |
766 | .name = "venc", | |
767 | .sta_mask = BIT(21), | |
768 | .ctl_offs = 0x304, | |
769 | .sram_pdn_bits = GENMASK(11, 8), | |
770 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
771 | .clk_id = {CLK_NONE}, | |
772 | }, | |
773 | [MT6797_POWER_DOMAIN_ISP] = { | |
774 | .name = "isp", | |
775 | .sta_mask = BIT(5), | |
776 | .ctl_offs = 0x308, | |
777 | .sram_pdn_bits = GENMASK(9, 8), | |
778 | .sram_pdn_ack_bits = GENMASK(13, 12), | |
779 | .clk_id = {CLK_NONE}, | |
780 | }, | |
781 | [MT6797_POWER_DOMAIN_MM] = { | |
782 | .name = "mm", | |
783 | .sta_mask = BIT(3), | |
784 | .ctl_offs = 0x30C, | |
785 | .sram_pdn_bits = GENMASK(8, 8), | |
786 | .sram_pdn_ack_bits = GENMASK(12, 12), | |
787 | .clk_id = {CLK_MM}, | |
788 | .bus_prot_mask = (BIT(1) | BIT(2)), | |
789 | }, | |
790 | [MT6797_POWER_DOMAIN_AUDIO] = { | |
791 | .name = "audio", | |
792 | .sta_mask = BIT(24), | |
793 | .ctl_offs = 0x314, | |
794 | .sram_pdn_bits = GENMASK(11, 8), | |
795 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
796 | .clk_id = {CLK_NONE}, | |
797 | }, | |
798 | [MT6797_POWER_DOMAIN_MFG_ASYNC] = { | |
799 | .name = "mfg_async", | |
800 | .sta_mask = BIT(13), | |
801 | .ctl_offs = 0x334, | |
802 | .sram_pdn_bits = 0, | |
803 | .sram_pdn_ack_bits = 0, | |
804 | .clk_id = {CLK_MFG}, | |
805 | }, | |
806 | [MT6797_POWER_DOMAIN_MJC] = { | |
807 | .name = "mjc", | |
808 | .sta_mask = BIT(20), | |
809 | .ctl_offs = 0x310, | |
810 | .sram_pdn_bits = GENMASK(8, 8), | |
811 | .sram_pdn_ack_bits = GENMASK(12, 12), | |
812 | .clk_id = {CLK_NONE}, | |
813 | }, | |
814 | }; | |
815 | ||
36c310f5 MC |
816 | #define SPM_PWR_STATUS_MT6797 0x0180 |
817 | #define SPM_PWR_STATUS_2ND_MT6797 0x0184 | |
818 | ||
53fddb1a SW |
819 | static const struct scp_subdomain scp_subdomain_mt6797[] = { |
820 | {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_VDEC}, | |
821 | {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_ISP}, | |
822 | {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_VENC}, | |
823 | {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_MJC}, | |
824 | }; | |
36c310f5 | 825 | |
52510ee9 SW |
826 | /* |
827 | * MT7622 power domain support | |
828 | */ | |
829 | ||
830 | static const struct scp_domain_data scp_domain_data_mt7622[] = { | |
831 | [MT7622_POWER_DOMAIN_ETHSYS] = { | |
832 | .name = "ethsys", | |
833 | .sta_mask = PWR_STATUS_ETHSYS, | |
834 | .ctl_offs = SPM_ETHSYS_PWR_CON, | |
835 | .sram_pdn_bits = GENMASK(11, 8), | |
836 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
837 | .clk_id = {CLK_NONE}, | |
838 | .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_ETHSYS, | |
ddf7aa99 | 839 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
52510ee9 SW |
840 | }, |
841 | [MT7622_POWER_DOMAIN_HIF0] = { | |
842 | .name = "hif0", | |
843 | .sta_mask = PWR_STATUS_HIF0, | |
844 | .ctl_offs = SPM_HIF0_PWR_CON, | |
845 | .sram_pdn_bits = GENMASK(11, 8), | |
846 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
847 | .clk_id = {CLK_HIFSEL}, | |
848 | .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_HIF0, | |
ddf7aa99 | 849 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
52510ee9 SW |
850 | }, |
851 | [MT7622_POWER_DOMAIN_HIF1] = { | |
852 | .name = "hif1", | |
853 | .sta_mask = PWR_STATUS_HIF1, | |
854 | .ctl_offs = SPM_HIF1_PWR_CON, | |
855 | .sram_pdn_bits = GENMASK(11, 8), | |
856 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
857 | .clk_id = {CLK_HIFSEL}, | |
858 | .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_HIF1, | |
ddf7aa99 | 859 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
52510ee9 SW |
860 | }, |
861 | [MT7622_POWER_DOMAIN_WB] = { | |
862 | .name = "wb", | |
863 | .sta_mask = PWR_STATUS_WB, | |
864 | .ctl_offs = SPM_WB_PWR_CON, | |
865 | .sram_pdn_bits = 0, | |
866 | .sram_pdn_ack_bits = 0, | |
867 | .clk_id = {CLK_NONE}, | |
868 | .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_WB, | |
1ba96062 | 869 | .caps = MTK_SCPD_ACTIVE_WAKEUP | MTK_SCPD_FWAIT_SRAM, |
52510ee9 SW |
870 | }, |
871 | }; | |
872 | ||
c932ba8c SW |
873 | /* |
874 | * MT7623A power domain support | |
875 | */ | |
876 | ||
877 | static const struct scp_domain_data scp_domain_data_mt7623a[] = { | |
878 | [MT7623A_POWER_DOMAIN_CONN] = { | |
879 | .name = "conn", | |
880 | .sta_mask = PWR_STATUS_CONN, | |
881 | .ctl_offs = SPM_CONN_PWR_CON, | |
882 | .bus_prot_mask = MT2701_TOP_AXI_PROT_EN_CONN_M | | |
883 | MT2701_TOP_AXI_PROT_EN_CONN_S, | |
884 | .clk_id = {CLK_NONE}, | |
ddf7aa99 | 885 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
c932ba8c SW |
886 | }, |
887 | [MT7623A_POWER_DOMAIN_ETH] = { | |
888 | .name = "eth", | |
889 | .sta_mask = PWR_STATUS_ETH, | |
890 | .ctl_offs = SPM_ETH_PWR_CON, | |
891 | .sram_pdn_bits = GENMASK(11, 8), | |
892 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
893 | .clk_id = {CLK_ETHIF}, | |
ddf7aa99 | 894 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
c932ba8c SW |
895 | }, |
896 | [MT7623A_POWER_DOMAIN_HIF] = { | |
897 | .name = "hif", | |
898 | .sta_mask = PWR_STATUS_HIF, | |
899 | .ctl_offs = SPM_HIF_PWR_CON, | |
900 | .sram_pdn_bits = GENMASK(11, 8), | |
901 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
902 | .clk_id = {CLK_ETHIF}, | |
ddf7aa99 | 903 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
c932ba8c SW |
904 | }, |
905 | [MT7623A_POWER_DOMAIN_IFR_MSC] = { | |
906 | .name = "ifr_msc", | |
907 | .sta_mask = PWR_STATUS_IFR_MSC, | |
908 | .ctl_offs = SPM_IFR_MSC_PWR_CON, | |
909 | .clk_id = {CLK_NONE}, | |
ddf7aa99 | 910 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
c932ba8c SW |
911 | }, |
912 | }; | |
913 | ||
6078c651 JL |
914 | /* |
915 | * MT8173 power domain support | |
916 | */ | |
917 | ||
918 | static const struct scp_domain_data scp_domain_data_mt8173[] = { | |
919 | [MT8173_POWER_DOMAIN_VDEC] = { | |
920 | .name = "vdec", | |
921 | .sta_mask = PWR_STATUS_VDEC, | |
922 | .ctl_offs = SPM_VDE_PWR_CON, | |
923 | .sram_pdn_bits = GENMASK(11, 8), | |
924 | .sram_pdn_ack_bits = GENMASK(12, 12), | |
925 | .clk_id = {CLK_MM}, | |
926 | }, | |
927 | [MT8173_POWER_DOMAIN_VENC] = { | |
928 | .name = "venc", | |
929 | .sta_mask = PWR_STATUS_VENC, | |
930 | .ctl_offs = SPM_VEN_PWR_CON, | |
931 | .sram_pdn_bits = GENMASK(11, 8), | |
932 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
933 | .clk_id = {CLK_MM, CLK_VENC}, | |
934 | }, | |
935 | [MT8173_POWER_DOMAIN_ISP] = { | |
936 | .name = "isp", | |
937 | .sta_mask = PWR_STATUS_ISP, | |
938 | .ctl_offs = SPM_ISP_PWR_CON, | |
939 | .sram_pdn_bits = GENMASK(11, 8), | |
940 | .sram_pdn_ack_bits = GENMASK(13, 12), | |
941 | .clk_id = {CLK_MM}, | |
942 | }, | |
943 | [MT8173_POWER_DOMAIN_MM] = { | |
944 | .name = "mm", | |
945 | .sta_mask = PWR_STATUS_DISP, | |
946 | .ctl_offs = SPM_DIS_PWR_CON, | |
947 | .sram_pdn_bits = GENMASK(11, 8), | |
948 | .sram_pdn_ack_bits = GENMASK(12, 12), | |
949 | .clk_id = {CLK_MM}, | |
950 | .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | | |
951 | MT8173_TOP_AXI_PROT_EN_MM_M1, | |
952 | }, | |
953 | [MT8173_POWER_DOMAIN_VENC_LT] = { | |
954 | .name = "venc_lt", | |
955 | .sta_mask = PWR_STATUS_VENC_LT, | |
956 | .ctl_offs = SPM_VEN2_PWR_CON, | |
957 | .sram_pdn_bits = GENMASK(11, 8), | |
958 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
959 | .clk_id = {CLK_MM, CLK_VENC_LT}, | |
960 | }, | |
961 | [MT8173_POWER_DOMAIN_AUDIO] = { | |
962 | .name = "audio", | |
963 | .sta_mask = PWR_STATUS_AUDIO, | |
964 | .ctl_offs = SPM_AUDIO_PWR_CON, | |
965 | .sram_pdn_bits = GENMASK(11, 8), | |
966 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
967 | .clk_id = {CLK_NONE}, | |
968 | }, | |
969 | [MT8173_POWER_DOMAIN_USB] = { | |
970 | .name = "usb", | |
971 | .sta_mask = PWR_STATUS_USB, | |
972 | .ctl_offs = SPM_USB_PWR_CON, | |
973 | .sram_pdn_bits = GENMASK(11, 8), | |
974 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
975 | .clk_id = {CLK_NONE}, | |
ddf7aa99 | 976 | .caps = MTK_SCPD_ACTIVE_WAKEUP, |
6078c651 JL |
977 | }, |
978 | [MT8173_POWER_DOMAIN_MFG_ASYNC] = { | |
979 | .name = "mfg_async", | |
980 | .sta_mask = PWR_STATUS_MFG_ASYNC, | |
981 | .ctl_offs = SPM_MFG_ASYNC_PWR_CON, | |
982 | .sram_pdn_bits = GENMASK(11, 8), | |
983 | .sram_pdn_ack_bits = 0, | |
984 | .clk_id = {CLK_MFG}, | |
985 | }, | |
986 | [MT8173_POWER_DOMAIN_MFG_2D] = { | |
987 | .name = "mfg_2d", | |
988 | .sta_mask = PWR_STATUS_MFG_2D, | |
989 | .ctl_offs = SPM_MFG_2D_PWR_CON, | |
990 | .sram_pdn_bits = GENMASK(11, 8), | |
991 | .sram_pdn_ack_bits = GENMASK(13, 12), | |
992 | .clk_id = {CLK_NONE}, | |
993 | }, | |
994 | [MT8173_POWER_DOMAIN_MFG] = { | |
995 | .name = "mfg", | |
996 | .sta_mask = PWR_STATUS_MFG, | |
997 | .ctl_offs = SPM_MFG_PWR_CON, | |
998 | .sram_pdn_bits = GENMASK(13, 8), | |
999 | .sram_pdn_ack_bits = GENMASK(21, 16), | |
1000 | .clk_id = {CLK_NONE}, | |
1001 | .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | | |
1002 | MT8173_TOP_AXI_PROT_EN_MFG_M0 | | |
1003 | MT8173_TOP_AXI_PROT_EN_MFG_M1 | | |
1004 | MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, | |
1005 | }, | |
1006 | }; | |
1007 | ||
53fddb1a SW |
1008 | static const struct scp_subdomain scp_subdomain_mt8173[] = { |
1009 | {MT8173_POWER_DOMAIN_MFG_ASYNC, MT8173_POWER_DOMAIN_MFG_2D}, | |
1010 | {MT8173_POWER_DOMAIN_MFG_2D, MT8173_POWER_DOMAIN_MFG}, | |
1011 | }; | |
6078c651 | 1012 | |
53fddb1a SW |
1013 | static const struct scp_soc_data mt2701_data = { |
1014 | .domains = scp_domain_data_mt2701, | |
1015 | .num_domains = ARRAY_SIZE(scp_domain_data_mt2701), | |
1016 | .regs = { | |
1017 | .pwr_sta_offs = SPM_PWR_STATUS, | |
1018 | .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND | |
fa7e843a | 1019 | }, |
1020 | .bus_prot_reg_update = true, | |
53fddb1a | 1021 | }; |
c84e3587 | 1022 | |
320f4ced | 1023 | static const struct scp_soc_data mt2712_data = { |
1024 | .domains = scp_domain_data_mt2712, | |
1025 | .num_domains = ARRAY_SIZE(scp_domain_data_mt2712), | |
9f997126 | 1026 | .subdomains = scp_subdomain_mt2712, |
1027 | .num_subdomains = ARRAY_SIZE(scp_subdomain_mt2712), | |
320f4ced | 1028 | .regs = { |
1029 | .pwr_sta_offs = SPM_PWR_STATUS, | |
1030 | .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND | |
1031 | }, | |
1032 | .bus_prot_reg_update = false, | |
1033 | }; | |
1034 | ||
53fddb1a SW |
1035 | static const struct scp_soc_data mt6797_data = { |
1036 | .domains = scp_domain_data_mt6797, | |
1037 | .num_domains = ARRAY_SIZE(scp_domain_data_mt6797), | |
1038 | .subdomains = scp_subdomain_mt6797, | |
1039 | .num_subdomains = ARRAY_SIZE(scp_subdomain_mt6797), | |
1040 | .regs = { | |
1041 | .pwr_sta_offs = SPM_PWR_STATUS_MT6797, | |
1042 | .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND_MT6797 | |
fa7e843a | 1043 | }, |
1044 | .bus_prot_reg_update = true, | |
53fddb1a | 1045 | }; |
c84e3587 | 1046 | |
52510ee9 SW |
1047 | static const struct scp_soc_data mt7622_data = { |
1048 | .domains = scp_domain_data_mt7622, | |
1049 | .num_domains = ARRAY_SIZE(scp_domain_data_mt7622), | |
1050 | .regs = { | |
1051 | .pwr_sta_offs = SPM_PWR_STATUS, | |
1052 | .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND | |
fa7e843a | 1053 | }, |
1054 | .bus_prot_reg_update = true, | |
52510ee9 SW |
1055 | }; |
1056 | ||
c932ba8c SW |
1057 | static const struct scp_soc_data mt7623a_data = { |
1058 | .domains = scp_domain_data_mt7623a, | |
1059 | .num_domains = ARRAY_SIZE(scp_domain_data_mt7623a), | |
1060 | .regs = { | |
1061 | .pwr_sta_offs = SPM_PWR_STATUS, | |
1062 | .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND | |
1063 | }, | |
1064 | .bus_prot_reg_update = true, | |
1065 | }; | |
1066 | ||
53fddb1a SW |
1067 | static const struct scp_soc_data mt8173_data = { |
1068 | .domains = scp_domain_data_mt8173, | |
1069 | .num_domains = ARRAY_SIZE(scp_domain_data_mt8173), | |
1070 | .subdomains = scp_subdomain_mt8173, | |
1071 | .num_subdomains = ARRAY_SIZE(scp_subdomain_mt8173), | |
1072 | .regs = { | |
1073 | .pwr_sta_offs = SPM_PWR_STATUS, | |
1074 | .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND | |
fa7e843a | 1075 | }, |
1076 | .bus_prot_reg_update = true, | |
53fddb1a | 1077 | }; |
c84e3587 | 1078 | |
6078c651 JL |
1079 | /* |
1080 | * scpsys driver init | |
1081 | */ | |
1082 | ||
c84e3587 SH |
1083 | static const struct of_device_id of_scpsys_match_tbl[] = { |
1084 | { | |
112ef188 | 1085 | .compatible = "mediatek,mt2701-scpsys", |
53fddb1a | 1086 | .data = &mt2701_data, |
320f4ced | 1087 | }, { |
1088 | .compatible = "mediatek,mt2712-scpsys", | |
1089 | .data = &mt2712_data, | |
36c310f5 MC |
1090 | }, { |
1091 | .compatible = "mediatek,mt6797-scpsys", | |
53fddb1a | 1092 | .data = &mt6797_data, |
52510ee9 SW |
1093 | }, { |
1094 | .compatible = "mediatek,mt7622-scpsys", | |
1095 | .data = &mt7622_data, | |
c932ba8c SW |
1096 | }, { |
1097 | .compatible = "mediatek,mt7623a-scpsys", | |
1098 | .data = &mt7623a_data, | |
112ef188 | 1099 | }, { |
c84e3587 | 1100 | .compatible = "mediatek,mt8173-scpsys", |
53fddb1a | 1101 | .data = &mt8173_data, |
c84e3587 SH |
1102 | }, { |
1103 | /* sentinel */ | |
1104 | } | |
1105 | }; | |
1106 | ||
6078c651 JL |
1107 | static int scpsys_probe(struct platform_device *pdev) |
1108 | { | |
53fddb1a SW |
1109 | const struct scp_subdomain *sd; |
1110 | const struct scp_soc_data *soc; | |
1111 | struct scp *scp; | |
1112 | struct genpd_onecell_data *pd_data; | |
1113 | int i, ret; | |
6078c651 | 1114 | |
38d19752 | 1115 | soc = of_device_get_match_data(&pdev->dev); |
6078c651 | 1116 | |
fa7e843a | 1117 | scp = init_scp(pdev, soc->domains, soc->num_domains, &soc->regs, |
1118 | soc->bus_prot_reg_update); | |
53fddb1a SW |
1119 | if (IS_ERR(scp)) |
1120 | return PTR_ERR(scp); | |
1121 | ||
1122 | mtk_register_power_domains(pdev, scp, soc->num_domains); | |
1123 | ||
1124 | pd_data = &scp->pd_data; | |
1125 | ||
73ce2ce1 | 1126 | for (i = 0, sd = soc->subdomains; i < soc->num_subdomains; i++, sd++) { |
53fddb1a SW |
1127 | ret = pm_genpd_add_subdomain(pd_data->domains[sd->origin], |
1128 | pd_data->domains[sd->subdomain]); | |
1129 | if (ret && IS_ENABLED(CONFIG_PM)) | |
1130 | dev_err(&pdev->dev, "Failed to add subdomain: %d\n", | |
1131 | ret); | |
1132 | } | |
6078c651 | 1133 | |
53fddb1a | 1134 | return 0; |
6078c651 JL |
1135 | } |
1136 | ||
c84e3587 | 1137 | static struct platform_driver scpsys_drv = { |
be29523d | 1138 | .probe = scpsys_probe, |
c84e3587 SH |
1139 | .driver = { |
1140 | .name = "mtk-scpsys", | |
be29523d | 1141 | .suppress_bind_attrs = true, |
c84e3587 SH |
1142 | .owner = THIS_MODULE, |
1143 | .of_match_table = of_match_ptr(of_scpsys_match_tbl), | |
1144 | }, | |
1145 | }; | |
be29523d | 1146 | builtin_platform_driver(scpsys_drv); |