blob: eadbf0d13e34a951b78ad6522e466d075cfb9768 [file] [log] [blame]
Sascha Hauerc84e3582015-06-24 08:17:04 +02001/*
2 * Copyright (c) 2015 Pengutronix, Sascha Hauer <kernel@pengutronix.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13#include <linux/clk.h>
Paul Gortmakere50be5c2015-09-04 19:33:54 -040014#include <linux/init.h>
James Liao6078c652016-10-20 16:56:35 +080015#include <linux/io.h>
16#include <linux/mfd/syscon.h>
Sascha Hauerc84e3582015-06-24 08:17:04 +020017#include <linux/of_device.h>
18#include <linux/platform_device.h>
19#include <linux/pm_domain.h>
Sascha Hauer4688f382015-11-30 11:41:40 +010020#include <linux/regulator/consumer.h>
James Liao6078c652016-10-20 16:56:35 +080021#include <linux/soc/mediatek/infracfg.h>
22
Shunli Wang112ef182016-10-20 16:56:38 +080023#include <dt-bindings/power/mt2701-power.h>
Sascha Hauerc84e3582015-06-24 08:17:04 +020024#include <dt-bindings/power/mt8173-power.h>
25
26#define SPM_VDE_PWR_CON 0x0210
27#define SPM_MFG_PWR_CON 0x0214
28#define SPM_VEN_PWR_CON 0x0230
29#define SPM_ISP_PWR_CON 0x0238
30#define SPM_DIS_PWR_CON 0x023c
Shunli Wang112ef182016-10-20 16:56:38 +080031#define SPM_CONN_PWR_CON 0x0280
Sascha Hauerc84e3582015-06-24 08:17:04 +020032#define SPM_VEN2_PWR_CON 0x0298
Shunli Wang112ef182016-10-20 16:56:38 +080033#define SPM_AUDIO_PWR_CON 0x029c /* MT8173 */
34#define SPM_BDP_PWR_CON 0x029c /* MT2701 */
35#define SPM_ETH_PWR_CON 0x02a0
36#define SPM_HIF_PWR_CON 0x02a4
37#define SPM_IFR_MSC_PWR_CON 0x02a8
Sascha Hauerc84e3582015-06-24 08:17:04 +020038#define SPM_MFG_2D_PWR_CON 0x02c0
39#define SPM_MFG_ASYNC_PWR_CON 0x02c4
40#define SPM_USB_PWR_CON 0x02cc
James Liao6078c652016-10-20 16:56:35 +080041
Sascha Hauerc84e3582015-06-24 08:17:04 +020042#define SPM_PWR_STATUS 0x060c
43#define SPM_PWR_STATUS_2ND 0x0610
44
45#define PWR_RST_B_BIT BIT(0)
46#define PWR_ISO_BIT BIT(1)
47#define PWR_ON_BIT BIT(2)
48#define PWR_ON_2ND_BIT BIT(3)
49#define PWR_CLK_DIS_BIT BIT(4)
50
Shunli Wang112ef182016-10-20 16:56:38 +080051#define PWR_STATUS_CONN BIT(1)
Sascha Hauerc84e3582015-06-24 08:17:04 +020052#define PWR_STATUS_DISP BIT(3)
53#define PWR_STATUS_MFG BIT(4)
54#define PWR_STATUS_ISP BIT(5)
55#define PWR_STATUS_VDEC BIT(7)
Shunli Wang112ef182016-10-20 16:56:38 +080056#define PWR_STATUS_BDP BIT(14)
57#define PWR_STATUS_ETH BIT(15)
58#define PWR_STATUS_HIF BIT(16)
59#define PWR_STATUS_IFR_MSC BIT(17)
Sascha Hauerc84e3582015-06-24 08:17:04 +020060#define PWR_STATUS_VENC_LT BIT(20)
61#define PWR_STATUS_VENC BIT(21)
62#define PWR_STATUS_MFG_2D BIT(22)
63#define PWR_STATUS_MFG_ASYNC BIT(23)
64#define PWR_STATUS_AUDIO BIT(24)
65#define PWR_STATUS_USB BIT(25)
66
67enum clk_id {
James Liao6078c652016-10-20 16:56:35 +080068 CLK_NONE,
69 CLK_MM,
70 CLK_MFG,
71 CLK_VENC,
72 CLK_VENC_LT,
Shunli Wang112ef182016-10-20 16:56:38 +080073 CLK_ETHIF,
James Liao6078c652016-10-20 16:56:35 +080074 CLK_MAX,
75};
76
77static const char * const clk_names[] = {
78 NULL,
79 "mm",
80 "mfg",
81 "venc",
82 "venc_lt",
Shunli Wang112ef182016-10-20 16:56:38 +080083 "ethif",
James Liao6078c652016-10-20 16:56:35 +080084 NULL,
Sascha Hauerc84e3582015-06-24 08:17:04 +020085};
86
James Liao41b3e0f2015-10-07 17:14:40 +080087#define MAX_CLKS 2
88
Sascha Hauerc84e3582015-06-24 08:17:04 +020089struct scp_domain_data {
90 const char *name;
91 u32 sta_mask;
92 int ctl_offs;
93 u32 sram_pdn_bits;
94 u32 sram_pdn_ack_bits;
95 u32 bus_prot_mask;
James Liao41b3e0f2015-10-07 17:14:40 +080096 enum clk_id clk_id[MAX_CLKS];
Eddie Huang47e90152015-08-26 15:14:41 +080097 bool active_wakeup;
Sascha Hauerc84e3582015-06-24 08:17:04 +020098};
99
Sascha Hauerc84e3582015-06-24 08:17:04 +0200100struct scp;
101
102struct scp_domain {
103 struct generic_pm_domain genpd;
104 struct scp *scp;
James Liao41b3e0f2015-10-07 17:14:40 +0800105 struct clk *clk[MAX_CLKS];
Matthias Bruggerbe295232015-12-30 09:30:40 +0100106 const struct scp_domain_data *data;
Sascha Hauer4688f382015-11-30 11:41:40 +0100107 struct regulator *supply;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200108};
109
Mars Chengf1be4c42017-04-08 09:20:31 +0800110struct scp_ctrl_reg {
111 int pwr_sta_offs;
112 int pwr_sta2nd_offs;
113};
114
Sascha Hauerc84e3582015-06-24 08:17:04 +0200115struct scp {
James Liao6078c652016-10-20 16:56:35 +0800116 struct scp_domain *domains;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200117 struct genpd_onecell_data pd_data;
118 struct device *dev;
119 void __iomem *base;
120 struct regmap *infracfg;
Mars Chengf1be4c42017-04-08 09:20:31 +0800121 struct scp_ctrl_reg ctrl_reg;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200122};
123
124static int scpsys_domain_is_on(struct scp_domain *scpd)
125{
126 struct scp *scp = scpd->scp;
127
Mars Chengf1be4c42017-04-08 09:20:31 +0800128 u32 status = readl(scp->base + scp->ctrl_reg.pwr_sta_offs) &
129 scpd->data->sta_mask;
130 u32 status2 = readl(scp->base + scp->ctrl_reg.pwr_sta2nd_offs) &
131 scpd->data->sta_mask;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200132
133 /*
134 * A domain is on when both status bits are set. If only one is set
135 * return an error. This happens while powering up a domain
136 */
137
138 if (status && status2)
139 return true;
140 if (!status && !status2)
141 return false;
142
143 return -EINVAL;
144}
145
146static int scpsys_power_on(struct generic_pm_domain *genpd)
147{
148 struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
149 struct scp *scp = scpd->scp;
150 unsigned long timeout;
151 bool expired;
Matthias Bruggerbe295232015-12-30 09:30:40 +0100152 void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
153 u32 sram_pdn_ack = scpd->data->sram_pdn_ack_bits;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200154 u32 val;
155 int ret;
James Liao41b3e0f2015-10-07 17:14:40 +0800156 int i;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200157
Sascha Hauer4688f382015-11-30 11:41:40 +0100158 if (scpd->supply) {
159 ret = regulator_enable(scpd->supply);
160 if (ret)
161 return ret;
162 }
163
James Liao41b3e0f2015-10-07 17:14:40 +0800164 for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) {
165 ret = clk_prepare_enable(scpd->clk[i]);
166 if (ret) {
167 for (--i; i >= 0; i--)
168 clk_disable_unprepare(scpd->clk[i]);
169
Sascha Hauerc84e3582015-06-24 08:17:04 +0200170 goto err_clk;
James Liao41b3e0f2015-10-07 17:14:40 +0800171 }
Sascha Hauerc84e3582015-06-24 08:17:04 +0200172 }
173
174 val = readl(ctl_addr);
175 val |= PWR_ON_BIT;
176 writel(val, ctl_addr);
177 val |= PWR_ON_2ND_BIT;
178 writel(val, ctl_addr);
179
180 /* wait until PWR_ACK = 1 */
181 timeout = jiffies + HZ;
182 expired = false;
183 while (1) {
184 ret = scpsys_domain_is_on(scpd);
185 if (ret > 0)
186 break;
187
188 if (expired) {
189 ret = -ETIMEDOUT;
190 goto err_pwr_ack;
191 }
192
193 cpu_relax();
194
195 if (time_after(jiffies, timeout))
196 expired = true;
197 }
198
199 val &= ~PWR_CLK_DIS_BIT;
200 writel(val, ctl_addr);
201
202 val &= ~PWR_ISO_BIT;
203 writel(val, ctl_addr);
204
205 val |= PWR_RST_B_BIT;
206 writel(val, ctl_addr);
207
Matthias Bruggerbe295232015-12-30 09:30:40 +0100208 val &= ~scpd->data->sram_pdn_bits;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200209 writel(val, ctl_addr);
210
211 /* wait until SRAM_PDN_ACK all 0 */
212 timeout = jiffies + HZ;
213 expired = false;
214 while (sram_pdn_ack && (readl(ctl_addr) & sram_pdn_ack)) {
215
216 if (expired) {
217 ret = -ETIMEDOUT;
218 goto err_pwr_ack;
219 }
220
221 cpu_relax();
222
223 if (time_after(jiffies, timeout))
224 expired = true;
225 }
226
Matthias Bruggerbe295232015-12-30 09:30:40 +0100227 if (scpd->data->bus_prot_mask) {
Sascha Hauerc84e3582015-06-24 08:17:04 +0200228 ret = mtk_infracfg_clear_bus_protection(scp->infracfg,
Matthias Bruggerbe295232015-12-30 09:30:40 +0100229 scpd->data->bus_prot_mask);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200230 if (ret)
231 goto err_pwr_ack;
232 }
233
234 return 0;
235
236err_pwr_ack:
James Liao41b3e0f2015-10-07 17:14:40 +0800237 for (i = MAX_CLKS - 1; i >= 0; i--) {
238 if (scpd->clk[i])
239 clk_disable_unprepare(scpd->clk[i]);
240 }
Sascha Hauerc84e3582015-06-24 08:17:04 +0200241err_clk:
Sascha Hauer4688f382015-11-30 11:41:40 +0100242 if (scpd->supply)
243 regulator_disable(scpd->supply);
244
Sascha Hauerc84e3582015-06-24 08:17:04 +0200245 dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name);
246
247 return ret;
248}
249
250static int scpsys_power_off(struct generic_pm_domain *genpd)
251{
252 struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
253 struct scp *scp = scpd->scp;
254 unsigned long timeout;
255 bool expired;
Matthias Bruggerbe295232015-12-30 09:30:40 +0100256 void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
257 u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200258 u32 val;
259 int ret;
James Liao41b3e0f2015-10-07 17:14:40 +0800260 int i;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200261
Matthias Bruggerbe295232015-12-30 09:30:40 +0100262 if (scpd->data->bus_prot_mask) {
Sascha Hauerc84e3582015-06-24 08:17:04 +0200263 ret = mtk_infracfg_set_bus_protection(scp->infracfg,
Matthias Bruggerbe295232015-12-30 09:30:40 +0100264 scpd->data->bus_prot_mask);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200265 if (ret)
266 goto out;
267 }
268
269 val = readl(ctl_addr);
Matthias Bruggerbe295232015-12-30 09:30:40 +0100270 val |= scpd->data->sram_pdn_bits;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200271 writel(val, ctl_addr);
272
273 /* wait until SRAM_PDN_ACK all 1 */
274 timeout = jiffies + HZ;
275 expired = false;
276 while (pdn_ack && (readl(ctl_addr) & pdn_ack) != pdn_ack) {
277 if (expired) {
278 ret = -ETIMEDOUT;
279 goto out;
280 }
281
282 cpu_relax();
283
284 if (time_after(jiffies, timeout))
285 expired = true;
286 }
287
288 val |= PWR_ISO_BIT;
289 writel(val, ctl_addr);
290
291 val &= ~PWR_RST_B_BIT;
292 writel(val, ctl_addr);
293
294 val |= PWR_CLK_DIS_BIT;
295 writel(val, ctl_addr);
296
297 val &= ~PWR_ON_BIT;
298 writel(val, ctl_addr);
299
300 val &= ~PWR_ON_2ND_BIT;
301 writel(val, ctl_addr);
302
303 /* wait until PWR_ACK = 0 */
304 timeout = jiffies + HZ;
305 expired = false;
306 while (1) {
307 ret = scpsys_domain_is_on(scpd);
308 if (ret == 0)
309 break;
310
311 if (expired) {
312 ret = -ETIMEDOUT;
313 goto out;
314 }
315
316 cpu_relax();
317
318 if (time_after(jiffies, timeout))
319 expired = true;
320 }
321
James Liao41b3e0f2015-10-07 17:14:40 +0800322 for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++)
323 clk_disable_unprepare(scpd->clk[i]);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200324
Sascha Hauer4688f382015-11-30 11:41:40 +0100325 if (scpd->supply)
326 regulator_disable(scpd->supply);
327
Sascha Hauerc84e3582015-06-24 08:17:04 +0200328 return 0;
329
330out:
331 dev_err(scp->dev, "Failed to power off domain %s\n", genpd->name);
332
333 return ret;
334}
335
Eddie Huang47e90152015-08-26 15:14:41 +0800336static bool scpsys_active_wakeup(struct device *dev)
337{
338 struct generic_pm_domain *genpd;
339 struct scp_domain *scpd;
340
341 genpd = pd_to_genpd(dev->pm_domain);
342 scpd = container_of(genpd, struct scp_domain, genpd);
343
Matthias Bruggerbe295232015-12-30 09:30:40 +0100344 return scpd->data->active_wakeup;
Eddie Huang47e90152015-08-26 15:14:41 +0800345}
346
James Liao6078c652016-10-20 16:56:35 +0800347static void init_clks(struct platform_device *pdev, struct clk **clk)
348{
349 int i;
350
351 for (i = CLK_NONE + 1; i < CLK_MAX; i++)
352 clk[i] = devm_clk_get(&pdev->dev, clk_names[i]);
353}
354
355static struct scp *init_scp(struct platform_device *pdev,
Mars Chengf1be4c42017-04-08 09:20:31 +0800356 const struct scp_domain_data *scp_domain_data, int num,
357 struct scp_ctrl_reg *scp_ctrl_reg)
Sascha Hauerc84e3582015-06-24 08:17:04 +0200358{
359 struct genpd_onecell_data *pd_data;
360 struct resource *res;
James Liao6078c652016-10-20 16:56:35 +0800361 int i, j;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200362 struct scp *scp;
James Liao6078c652016-10-20 16:56:35 +0800363 struct clk *clk[CLK_MAX];
Sascha Hauerc84e3582015-06-24 08:17:04 +0200364
365 scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
366 if (!scp)
James Liao6078c652016-10-20 16:56:35 +0800367 return ERR_PTR(-ENOMEM);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200368
Mars Chengf1be4c42017-04-08 09:20:31 +0800369 scp->ctrl_reg.pwr_sta_offs = scp_ctrl_reg->pwr_sta_offs;
370 scp->ctrl_reg.pwr_sta2nd_offs = scp_ctrl_reg->pwr_sta2nd_offs;
371
Sascha Hauerc84e3582015-06-24 08:17:04 +0200372 scp->dev = &pdev->dev;
373
374 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
375 scp->base = devm_ioremap_resource(&pdev->dev, res);
376 if (IS_ERR(scp->base))
James Liao6078c652016-10-20 16:56:35 +0800377 return ERR_CAST(scp->base);
378
379 scp->domains = devm_kzalloc(&pdev->dev,
380 sizeof(*scp->domains) * num, GFP_KERNEL);
381 if (!scp->domains)
382 return ERR_PTR(-ENOMEM);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200383
384 pd_data = &scp->pd_data;
385
386 pd_data->domains = devm_kzalloc(&pdev->dev,
James Liao6078c652016-10-20 16:56:35 +0800387 sizeof(*pd_data->domains) * num, GFP_KERNEL);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200388 if (!pd_data->domains)
James Liao6078c652016-10-20 16:56:35 +0800389 return ERR_PTR(-ENOMEM);
James Liao41b3e0f2015-10-07 17:14:40 +0800390
Sascha Hauerc84e3582015-06-24 08:17:04 +0200391 scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
392 "infracfg");
393 if (IS_ERR(scp->infracfg)) {
394 dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
395 PTR_ERR(scp->infracfg));
James Liao6078c652016-10-20 16:56:35 +0800396 return ERR_CAST(scp->infracfg);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200397 }
398
James Liao6078c652016-10-20 16:56:35 +0800399 for (i = 0; i < num; i++) {
Sascha Hauer4688f382015-11-30 11:41:40 +0100400 struct scp_domain *scpd = &scp->domains[i];
401 const struct scp_domain_data *data = &scp_domain_data[i];
402
403 scpd->supply = devm_regulator_get_optional(&pdev->dev, data->name);
404 if (IS_ERR(scpd->supply)) {
405 if (PTR_ERR(scpd->supply) == -ENODEV)
406 scpd->supply = NULL;
407 else
James Liao6078c652016-10-20 16:56:35 +0800408 return ERR_CAST(scpd->supply);
Sascha Hauer4688f382015-11-30 11:41:40 +0100409 }
410 }
411
James Liao6078c652016-10-20 16:56:35 +0800412 pd_data->num_domains = num;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200413
James Liao6078c652016-10-20 16:56:35 +0800414 init_clks(pdev, clk);
415
416 for (i = 0; i < num; i++) {
Sascha Hauerc84e3582015-06-24 08:17:04 +0200417 struct scp_domain *scpd = &scp->domains[i];
418 struct generic_pm_domain *genpd = &scpd->genpd;
419 const struct scp_domain_data *data = &scp_domain_data[i];
420
421 pd_data->domains[i] = genpd;
422 scpd->scp = scp;
423
Matthias Bruggerbe295232015-12-30 09:30:40 +0100424 scpd->data = data;
James Liao6078c652016-10-20 16:56:35 +0800425
426 for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
427 struct clk *c = clk[data->clk_id[j]];
428
429 if (IS_ERR(c)) {
430 dev_err(&pdev->dev, "%s: clk unavailable\n",
431 data->name);
432 return ERR_CAST(c);
433 }
434
435 scpd->clk[j] = c;
436 }
Sascha Hauerc84e3582015-06-24 08:17:04 +0200437
438 genpd->name = data->name;
439 genpd->power_off = scpsys_power_off;
440 genpd->power_on = scpsys_power_on;
Eddie Huang47e90152015-08-26 15:14:41 +0800441 genpd->dev_ops.active_wakeup = scpsys_active_wakeup;
James Liao6078c652016-10-20 16:56:35 +0800442 }
443
444 return scp;
445}
446
447static void mtk_register_power_domains(struct platform_device *pdev,
448 struct scp *scp, int num)
449{
450 struct genpd_onecell_data *pd_data;
451 int i, ret;
452
453 for (i = 0; i < num; i++) {
454 struct scp_domain *scpd = &scp->domains[i];
455 struct generic_pm_domain *genpd = &scpd->genpd;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200456
457 /*
James Liaod9c9f3b2016-04-12 16:34:30 +0800458 * Initially turn on all domains to make the domains usable
459 * with !CONFIG_PM and to get the hardware in sync with the
460 * software. The unused domains will be switched off during
461 * late_init time.
Sascha Hauerc84e3582015-06-24 08:17:04 +0200462 */
James Liaod9c9f3b2016-04-12 16:34:30 +0800463 genpd->power_on(genpd);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200464
James Liaod9c9f3b2016-04-12 16:34:30 +0800465 pm_genpd_init(genpd, NULL, false);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200466 }
467
468 /*
469 * We are not allowed to fail here since there is no way to unregister
470 * a power domain. Once registered above we have to keep the domains
471 * valid.
472 */
473
James Liao6078c652016-10-20 16:56:35 +0800474 pd_data = &scp->pd_data;
475
476 ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
477 if (ret)
478 dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
479}
480
481/*
Shunli Wang112ef182016-10-20 16:56:38 +0800482 * MT2701 power domain support
483 */
484
485static const struct scp_domain_data scp_domain_data_mt2701[] = {
486 [MT2701_POWER_DOMAIN_CONN] = {
487 .name = "conn",
488 .sta_mask = PWR_STATUS_CONN,
489 .ctl_offs = SPM_CONN_PWR_CON,
490 .bus_prot_mask = 0x0104,
491 .clk_id = {CLK_NONE},
492 .active_wakeup = true,
493 },
494 [MT2701_POWER_DOMAIN_DISP] = {
495 .name = "disp",
496 .sta_mask = PWR_STATUS_DISP,
497 .ctl_offs = SPM_DIS_PWR_CON,
498 .sram_pdn_bits = GENMASK(11, 8),
499 .clk_id = {CLK_MM},
500 .bus_prot_mask = 0x0002,
501 .active_wakeup = true,
502 },
503 [MT2701_POWER_DOMAIN_MFG] = {
504 .name = "mfg",
505 .sta_mask = PWR_STATUS_MFG,
506 .ctl_offs = SPM_MFG_PWR_CON,
507 .sram_pdn_bits = GENMASK(11, 8),
508 .sram_pdn_ack_bits = GENMASK(12, 12),
509 .clk_id = {CLK_MFG},
510 .active_wakeup = true,
511 },
512 [MT2701_POWER_DOMAIN_VDEC] = {
513 .name = "vdec",
514 .sta_mask = PWR_STATUS_VDEC,
515 .ctl_offs = SPM_VDE_PWR_CON,
516 .sram_pdn_bits = GENMASK(11, 8),
517 .sram_pdn_ack_bits = GENMASK(12, 12),
518 .clk_id = {CLK_MM},
519 .active_wakeup = true,
520 },
521 [MT2701_POWER_DOMAIN_ISP] = {
522 .name = "isp",
523 .sta_mask = PWR_STATUS_ISP,
524 .ctl_offs = SPM_ISP_PWR_CON,
525 .sram_pdn_bits = GENMASK(11, 8),
526 .sram_pdn_ack_bits = GENMASK(13, 12),
527 .clk_id = {CLK_MM},
528 .active_wakeup = true,
529 },
530 [MT2701_POWER_DOMAIN_BDP] = {
531 .name = "bdp",
532 .sta_mask = PWR_STATUS_BDP,
533 .ctl_offs = SPM_BDP_PWR_CON,
534 .sram_pdn_bits = GENMASK(11, 8),
535 .clk_id = {CLK_NONE},
536 .active_wakeup = true,
537 },
538 [MT2701_POWER_DOMAIN_ETH] = {
539 .name = "eth",
540 .sta_mask = PWR_STATUS_ETH,
541 .ctl_offs = SPM_ETH_PWR_CON,
542 .sram_pdn_bits = GENMASK(11, 8),
543 .sram_pdn_ack_bits = GENMASK(15, 12),
544 .clk_id = {CLK_ETHIF},
545 .active_wakeup = true,
546 },
547 [MT2701_POWER_DOMAIN_HIF] = {
548 .name = "hif",
549 .sta_mask = PWR_STATUS_HIF,
550 .ctl_offs = SPM_HIF_PWR_CON,
551 .sram_pdn_bits = GENMASK(11, 8),
552 .sram_pdn_ack_bits = GENMASK(15, 12),
553 .clk_id = {CLK_ETHIF},
554 .active_wakeup = true,
555 },
556 [MT2701_POWER_DOMAIN_IFR_MSC] = {
557 .name = "ifr_msc",
558 .sta_mask = PWR_STATUS_IFR_MSC,
559 .ctl_offs = SPM_IFR_MSC_PWR_CON,
560 .clk_id = {CLK_NONE},
561 .active_wakeup = true,
562 },
563};
564
565#define NUM_DOMAINS_MT2701 ARRAY_SIZE(scp_domain_data_mt2701)
566
567static int __init scpsys_probe_mt2701(struct platform_device *pdev)
568{
569 struct scp *scp;
Mars Chengf1be4c42017-04-08 09:20:31 +0800570 struct scp_ctrl_reg scp_reg;
Shunli Wang112ef182016-10-20 16:56:38 +0800571
Mars Chengf1be4c42017-04-08 09:20:31 +0800572 scp_reg.pwr_sta_offs = SPM_PWR_STATUS;
573 scp_reg.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND;
574
575 scp = init_scp(pdev, scp_domain_data_mt2701, NUM_DOMAINS_MT2701,
576 &scp_reg);
Shunli Wang112ef182016-10-20 16:56:38 +0800577 if (IS_ERR(scp))
578 return PTR_ERR(scp);
579
580 mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT2701);
581
582 return 0;
583}
584
585/*
James Liao6078c652016-10-20 16:56:35 +0800586 * MT8173 power domain support
587 */
588
589static const struct scp_domain_data scp_domain_data_mt8173[] = {
590 [MT8173_POWER_DOMAIN_VDEC] = {
591 .name = "vdec",
592 .sta_mask = PWR_STATUS_VDEC,
593 .ctl_offs = SPM_VDE_PWR_CON,
594 .sram_pdn_bits = GENMASK(11, 8),
595 .sram_pdn_ack_bits = GENMASK(12, 12),
596 .clk_id = {CLK_MM},
597 },
598 [MT8173_POWER_DOMAIN_VENC] = {
599 .name = "venc",
600 .sta_mask = PWR_STATUS_VENC,
601 .ctl_offs = SPM_VEN_PWR_CON,
602 .sram_pdn_bits = GENMASK(11, 8),
603 .sram_pdn_ack_bits = GENMASK(15, 12),
604 .clk_id = {CLK_MM, CLK_VENC},
605 },
606 [MT8173_POWER_DOMAIN_ISP] = {
607 .name = "isp",
608 .sta_mask = PWR_STATUS_ISP,
609 .ctl_offs = SPM_ISP_PWR_CON,
610 .sram_pdn_bits = GENMASK(11, 8),
611 .sram_pdn_ack_bits = GENMASK(13, 12),
612 .clk_id = {CLK_MM},
613 },
614 [MT8173_POWER_DOMAIN_MM] = {
615 .name = "mm",
616 .sta_mask = PWR_STATUS_DISP,
617 .ctl_offs = SPM_DIS_PWR_CON,
618 .sram_pdn_bits = GENMASK(11, 8),
619 .sram_pdn_ack_bits = GENMASK(12, 12),
620 .clk_id = {CLK_MM},
621 .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
622 MT8173_TOP_AXI_PROT_EN_MM_M1,
623 },
624 [MT8173_POWER_DOMAIN_VENC_LT] = {
625 .name = "venc_lt",
626 .sta_mask = PWR_STATUS_VENC_LT,
627 .ctl_offs = SPM_VEN2_PWR_CON,
628 .sram_pdn_bits = GENMASK(11, 8),
629 .sram_pdn_ack_bits = GENMASK(15, 12),
630 .clk_id = {CLK_MM, CLK_VENC_LT},
631 },
632 [MT8173_POWER_DOMAIN_AUDIO] = {
633 .name = "audio",
634 .sta_mask = PWR_STATUS_AUDIO,
635 .ctl_offs = SPM_AUDIO_PWR_CON,
636 .sram_pdn_bits = GENMASK(11, 8),
637 .sram_pdn_ack_bits = GENMASK(15, 12),
638 .clk_id = {CLK_NONE},
639 },
640 [MT8173_POWER_DOMAIN_USB] = {
641 .name = "usb",
642 .sta_mask = PWR_STATUS_USB,
643 .ctl_offs = SPM_USB_PWR_CON,
644 .sram_pdn_bits = GENMASK(11, 8),
645 .sram_pdn_ack_bits = GENMASK(15, 12),
646 .clk_id = {CLK_NONE},
647 .active_wakeup = true,
648 },
649 [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
650 .name = "mfg_async",
651 .sta_mask = PWR_STATUS_MFG_ASYNC,
652 .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
653 .sram_pdn_bits = GENMASK(11, 8),
654 .sram_pdn_ack_bits = 0,
655 .clk_id = {CLK_MFG},
656 },
657 [MT8173_POWER_DOMAIN_MFG_2D] = {
658 .name = "mfg_2d",
659 .sta_mask = PWR_STATUS_MFG_2D,
660 .ctl_offs = SPM_MFG_2D_PWR_CON,
661 .sram_pdn_bits = GENMASK(11, 8),
662 .sram_pdn_ack_bits = GENMASK(13, 12),
663 .clk_id = {CLK_NONE},
664 },
665 [MT8173_POWER_DOMAIN_MFG] = {
666 .name = "mfg",
667 .sta_mask = PWR_STATUS_MFG,
668 .ctl_offs = SPM_MFG_PWR_CON,
669 .sram_pdn_bits = GENMASK(13, 8),
670 .sram_pdn_ack_bits = GENMASK(21, 16),
671 .clk_id = {CLK_NONE},
672 .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
673 MT8173_TOP_AXI_PROT_EN_MFG_M0 |
674 MT8173_TOP_AXI_PROT_EN_MFG_M1 |
675 MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
676 },
677};
678
679#define NUM_DOMAINS_MT8173 ARRAY_SIZE(scp_domain_data_mt8173)
680
681static int __init scpsys_probe_mt8173(struct platform_device *pdev)
682{
683 struct scp *scp;
684 struct genpd_onecell_data *pd_data;
685 int ret;
Mars Chengf1be4c42017-04-08 09:20:31 +0800686 struct scp_ctrl_reg scp_reg;
James Liao6078c652016-10-20 16:56:35 +0800687
Mars Chengf1be4c42017-04-08 09:20:31 +0800688 scp_reg.pwr_sta_offs = SPM_PWR_STATUS;
689 scp_reg.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND;
690
691 scp = init_scp(pdev, scp_domain_data_mt8173, NUM_DOMAINS_MT8173,
692 &scp_reg);
James Liao6078c652016-10-20 16:56:35 +0800693 if (IS_ERR(scp))
694 return PTR_ERR(scp);
695
696 mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT8173);
697
698 pd_data = &scp->pd_data;
699
Sascha Hauerc84e3582015-06-24 08:17:04 +0200700 ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_ASYNC],
701 pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D]);
702 if (ret && IS_ENABLED(CONFIG_PM))
703 dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
704
705 ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D],
706 pd_data->domains[MT8173_POWER_DOMAIN_MFG]);
707 if (ret && IS_ENABLED(CONFIG_PM))
708 dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
709
Sascha Hauerc84e3582015-06-24 08:17:04 +0200710 return 0;
711}
712
James Liao6078c652016-10-20 16:56:35 +0800713/*
714 * scpsys driver init
715 */
716
Sascha Hauerc84e3582015-06-24 08:17:04 +0200717static const struct of_device_id of_scpsys_match_tbl[] = {
718 {
Shunli Wang112ef182016-10-20 16:56:38 +0800719 .compatible = "mediatek,mt2701-scpsys",
720 .data = scpsys_probe_mt2701,
721 }, {
Sascha Hauerc84e3582015-06-24 08:17:04 +0200722 .compatible = "mediatek,mt8173-scpsys",
James Liao6078c652016-10-20 16:56:35 +0800723 .data = scpsys_probe_mt8173,
Sascha Hauerc84e3582015-06-24 08:17:04 +0200724 }, {
725 /* sentinel */
726 }
727};
728
James Liao6078c652016-10-20 16:56:35 +0800729static int scpsys_probe(struct platform_device *pdev)
730{
731 int (*probe)(struct platform_device *);
732 const struct of_device_id *of_id;
733
734 of_id = of_match_node(of_scpsys_match_tbl, pdev->dev.of_node);
735 if (!of_id || !of_id->data)
736 return -EINVAL;
737
738 probe = of_id->data;
739
740 return probe(pdev);
741}
742
Sascha Hauerc84e3582015-06-24 08:17:04 +0200743static struct platform_driver scpsys_drv = {
Matthias Bruggerbe295232015-12-30 09:30:40 +0100744 .probe = scpsys_probe,
Sascha Hauerc84e3582015-06-24 08:17:04 +0200745 .driver = {
746 .name = "mtk-scpsys",
Matthias Bruggerbe295232015-12-30 09:30:40 +0100747 .suppress_bind_attrs = true,
Sascha Hauerc84e3582015-06-24 08:17:04 +0200748 .owner = THIS_MODULE,
749 .of_match_table = of_match_ptr(of_scpsys_match_tbl),
750 },
751};
Matthias Bruggerbe295232015-12-30 09:30:40 +0100752builtin_platform_driver(scpsys_drv);