blob: e570b6af2e6ffbddccf1fe76075375d4e39e3e0c [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>
Mars Cheng36c310f2017-04-08 09:20:34 +080024#include <dt-bindings/power/mt6797-power.h>
Sean Wang52510ee2017-08-07 15:24:37 +080025#include <dt-bindings/power/mt7622-power.h>
Sascha Hauerc84e3582015-06-24 08:17:04 +020026#include <dt-bindings/power/mt8173-power.h>
27
28#define SPM_VDE_PWR_CON 0x0210
29#define SPM_MFG_PWR_CON 0x0214
30#define SPM_VEN_PWR_CON 0x0230
31#define SPM_ISP_PWR_CON 0x0238
32#define SPM_DIS_PWR_CON 0x023c
Shunli Wang112ef182016-10-20 16:56:38 +080033#define SPM_CONN_PWR_CON 0x0280
Sascha Hauerc84e3582015-06-24 08:17:04 +020034#define SPM_VEN2_PWR_CON 0x0298
Shunli Wang112ef182016-10-20 16:56:38 +080035#define SPM_AUDIO_PWR_CON 0x029c /* MT8173 */
36#define SPM_BDP_PWR_CON 0x029c /* MT2701 */
37#define SPM_ETH_PWR_CON 0x02a0
38#define SPM_HIF_PWR_CON 0x02a4
39#define SPM_IFR_MSC_PWR_CON 0x02a8
Sascha Hauerc84e3582015-06-24 08:17:04 +020040#define SPM_MFG_2D_PWR_CON 0x02c0
41#define SPM_MFG_ASYNC_PWR_CON 0x02c4
42#define SPM_USB_PWR_CON 0x02cc
Sean Wang52510ee2017-08-07 15:24:37 +080043#define SPM_ETHSYS_PWR_CON 0x02e0 /* MT7622 */
44#define SPM_HIF0_PWR_CON 0x02e4 /* MT7622 */
45#define SPM_HIF1_PWR_CON 0x02e8 /* MT7622 */
46#define SPM_WB_PWR_CON 0x02ec /* MT7622 */
47
James Liao6078c652016-10-20 16:56:35 +080048
Sascha Hauerc84e3582015-06-24 08:17:04 +020049#define SPM_PWR_STATUS 0x060c
50#define SPM_PWR_STATUS_2ND 0x0610
51
52#define PWR_RST_B_BIT BIT(0)
53#define PWR_ISO_BIT BIT(1)
54#define PWR_ON_BIT BIT(2)
55#define PWR_ON_2ND_BIT BIT(3)
56#define PWR_CLK_DIS_BIT BIT(4)
57
Shunli Wang112ef182016-10-20 16:56:38 +080058#define PWR_STATUS_CONN BIT(1)
Sascha Hauerc84e3582015-06-24 08:17:04 +020059#define PWR_STATUS_DISP BIT(3)
60#define PWR_STATUS_MFG BIT(4)
61#define PWR_STATUS_ISP BIT(5)
62#define PWR_STATUS_VDEC BIT(7)
Shunli Wang112ef182016-10-20 16:56:38 +080063#define PWR_STATUS_BDP BIT(14)
64#define PWR_STATUS_ETH BIT(15)
65#define PWR_STATUS_HIF BIT(16)
66#define PWR_STATUS_IFR_MSC BIT(17)
Sascha Hauerc84e3582015-06-24 08:17:04 +020067#define PWR_STATUS_VENC_LT BIT(20)
68#define PWR_STATUS_VENC BIT(21)
69#define PWR_STATUS_MFG_2D BIT(22)
70#define PWR_STATUS_MFG_ASYNC BIT(23)
71#define PWR_STATUS_AUDIO BIT(24)
72#define PWR_STATUS_USB BIT(25)
Sean Wang52510ee2017-08-07 15:24:37 +080073#define PWR_STATUS_ETHSYS BIT(24) /* MT7622 */
74#define PWR_STATUS_HIF0 BIT(25) /* MT7622 */
75#define PWR_STATUS_HIF1 BIT(26) /* MT7622 */
76#define PWR_STATUS_WB BIT(27) /* MT7622 */
Sascha Hauerc84e3582015-06-24 08:17:04 +020077
78enum clk_id {
James Liao6078c652016-10-20 16:56:35 +080079 CLK_NONE,
80 CLK_MM,
81 CLK_MFG,
82 CLK_VENC,
83 CLK_VENC_LT,
Shunli Wang112ef182016-10-20 16:56:38 +080084 CLK_ETHIF,
Mars Chenga3acbbf2017-04-08 09:20:32 +080085 CLK_VDEC,
Sean Wang52510ee2017-08-07 15:24:37 +080086 CLK_HIFSEL,
James Liao6078c652016-10-20 16:56:35 +080087 CLK_MAX,
88};
89
90static const char * const clk_names[] = {
91 NULL,
92 "mm",
93 "mfg",
94 "venc",
95 "venc_lt",
Shunli Wang112ef182016-10-20 16:56:38 +080096 "ethif",
Mars Chenga3acbbf2017-04-08 09:20:32 +080097 "vdec",
Sean Wang52510ee2017-08-07 15:24:37 +080098 "hif_sel",
James Liao6078c652016-10-20 16:56:35 +080099 NULL,
Sascha Hauerc84e3582015-06-24 08:17:04 +0200100};
101
James Liao41b3e0f2015-10-07 17:14:40 +0800102#define MAX_CLKS 2
103
Sascha Hauerc84e3582015-06-24 08:17:04 +0200104struct scp_domain_data {
105 const char *name;
106 u32 sta_mask;
107 int ctl_offs;
108 u32 sram_pdn_bits;
109 u32 sram_pdn_ack_bits;
110 u32 bus_prot_mask;
James Liao41b3e0f2015-10-07 17:14:40 +0800111 enum clk_id clk_id[MAX_CLKS];
Eddie Huang47e90152015-08-26 15:14:41 +0800112 bool active_wakeup;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200113};
114
Sascha Hauerc84e3582015-06-24 08:17:04 +0200115struct scp;
116
117struct scp_domain {
118 struct generic_pm_domain genpd;
119 struct scp *scp;
James Liao41b3e0f2015-10-07 17:14:40 +0800120 struct clk *clk[MAX_CLKS];
Matthias Bruggerbe295232015-12-30 09:30:40 +0100121 const struct scp_domain_data *data;
Sascha Hauer4688f382015-11-30 11:41:40 +0100122 struct regulator *supply;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200123};
124
Mars Chengf1be4c42017-04-08 09:20:31 +0800125struct scp_ctrl_reg {
126 int pwr_sta_offs;
127 int pwr_sta2nd_offs;
128};
129
Sascha Hauerc84e3582015-06-24 08:17:04 +0200130struct scp {
James Liao6078c652016-10-20 16:56:35 +0800131 struct scp_domain *domains;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200132 struct genpd_onecell_data pd_data;
133 struct device *dev;
134 void __iomem *base;
135 struct regmap *infracfg;
Mars Chengf1be4c42017-04-08 09:20:31 +0800136 struct scp_ctrl_reg ctrl_reg;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200137};
138
Sean Wang53fddb12017-08-07 15:24:35 +0800139struct scp_subdomain {
140 int origin;
141 int subdomain;
142};
143
144struct scp_soc_data {
145 const struct scp_domain_data *domains;
146 int num_domains;
147 const struct scp_subdomain *subdomains;
148 int num_subdomains;
149 const struct scp_ctrl_reg regs;
150};
151
Sascha Hauerc84e3582015-06-24 08:17:04 +0200152static int scpsys_domain_is_on(struct scp_domain *scpd)
153{
154 struct scp *scp = scpd->scp;
155
Mars Chengf1be4c42017-04-08 09:20:31 +0800156 u32 status = readl(scp->base + scp->ctrl_reg.pwr_sta_offs) &
157 scpd->data->sta_mask;
158 u32 status2 = readl(scp->base + scp->ctrl_reg.pwr_sta2nd_offs) &
159 scpd->data->sta_mask;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200160
161 /*
162 * A domain is on when both status bits are set. If only one is set
163 * return an error. This happens while powering up a domain
164 */
165
166 if (status && status2)
167 return true;
168 if (!status && !status2)
169 return false;
170
171 return -EINVAL;
172}
173
174static int scpsys_power_on(struct generic_pm_domain *genpd)
175{
176 struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
177 struct scp *scp = scpd->scp;
178 unsigned long timeout;
179 bool expired;
Matthias Bruggerbe295232015-12-30 09:30:40 +0100180 void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
181 u32 sram_pdn_ack = scpd->data->sram_pdn_ack_bits;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200182 u32 val;
183 int ret;
James Liao41b3e0f2015-10-07 17:14:40 +0800184 int i;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200185
Sascha Hauer4688f382015-11-30 11:41:40 +0100186 if (scpd->supply) {
187 ret = regulator_enable(scpd->supply);
188 if (ret)
189 return ret;
190 }
191
James Liao41b3e0f2015-10-07 17:14:40 +0800192 for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) {
193 ret = clk_prepare_enable(scpd->clk[i]);
194 if (ret) {
195 for (--i; i >= 0; i--)
196 clk_disable_unprepare(scpd->clk[i]);
197
Sascha Hauerc84e3582015-06-24 08:17:04 +0200198 goto err_clk;
James Liao41b3e0f2015-10-07 17:14:40 +0800199 }
Sascha Hauerc84e3582015-06-24 08:17:04 +0200200 }
201
202 val = readl(ctl_addr);
203 val |= PWR_ON_BIT;
204 writel(val, ctl_addr);
205 val |= PWR_ON_2ND_BIT;
206 writel(val, ctl_addr);
207
208 /* wait until PWR_ACK = 1 */
209 timeout = jiffies + HZ;
210 expired = false;
211 while (1) {
212 ret = scpsys_domain_is_on(scpd);
213 if (ret > 0)
214 break;
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
227 val &= ~PWR_CLK_DIS_BIT;
228 writel(val, ctl_addr);
229
230 val &= ~PWR_ISO_BIT;
231 writel(val, ctl_addr);
232
233 val |= PWR_RST_B_BIT;
234 writel(val, ctl_addr);
235
Matthias Bruggerbe295232015-12-30 09:30:40 +0100236 val &= ~scpd->data->sram_pdn_bits;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200237 writel(val, ctl_addr);
238
239 /* wait until SRAM_PDN_ACK all 0 */
240 timeout = jiffies + HZ;
241 expired = false;
242 while (sram_pdn_ack && (readl(ctl_addr) & sram_pdn_ack)) {
243
244 if (expired) {
245 ret = -ETIMEDOUT;
246 goto err_pwr_ack;
247 }
248
249 cpu_relax();
250
251 if (time_after(jiffies, timeout))
252 expired = true;
253 }
254
Matthias Bruggerbe295232015-12-30 09:30:40 +0100255 if (scpd->data->bus_prot_mask) {
Sascha Hauerc84e3582015-06-24 08:17:04 +0200256 ret = mtk_infracfg_clear_bus_protection(scp->infracfg,
Matthias Bruggerbe295232015-12-30 09:30:40 +0100257 scpd->data->bus_prot_mask);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200258 if (ret)
259 goto err_pwr_ack;
260 }
261
262 return 0;
263
264err_pwr_ack:
James Liao41b3e0f2015-10-07 17:14:40 +0800265 for (i = MAX_CLKS - 1; i >= 0; i--) {
266 if (scpd->clk[i])
267 clk_disable_unprepare(scpd->clk[i]);
268 }
Sascha Hauerc84e3582015-06-24 08:17:04 +0200269err_clk:
Sascha Hauer4688f382015-11-30 11:41:40 +0100270 if (scpd->supply)
271 regulator_disable(scpd->supply);
272
Sascha Hauerc84e3582015-06-24 08:17:04 +0200273 dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name);
274
275 return ret;
276}
277
278static int scpsys_power_off(struct generic_pm_domain *genpd)
279{
280 struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
281 struct scp *scp = scpd->scp;
282 unsigned long timeout;
283 bool expired;
Matthias Bruggerbe295232015-12-30 09:30:40 +0100284 void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
285 u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200286 u32 val;
287 int ret;
James Liao41b3e0f2015-10-07 17:14:40 +0800288 int i;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200289
Matthias Bruggerbe295232015-12-30 09:30:40 +0100290 if (scpd->data->bus_prot_mask) {
Sascha Hauerc84e3582015-06-24 08:17:04 +0200291 ret = mtk_infracfg_set_bus_protection(scp->infracfg,
Matthias Bruggerbe295232015-12-30 09:30:40 +0100292 scpd->data->bus_prot_mask);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200293 if (ret)
294 goto out;
295 }
296
297 val = readl(ctl_addr);
Matthias Bruggerbe295232015-12-30 09:30:40 +0100298 val |= scpd->data->sram_pdn_bits;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200299 writel(val, ctl_addr);
300
301 /* wait until SRAM_PDN_ACK all 1 */
302 timeout = jiffies + HZ;
303 expired = false;
304 while (pdn_ack && (readl(ctl_addr) & pdn_ack) != pdn_ack) {
305 if (expired) {
306 ret = -ETIMEDOUT;
307 goto out;
308 }
309
310 cpu_relax();
311
312 if (time_after(jiffies, timeout))
313 expired = true;
314 }
315
316 val |= PWR_ISO_BIT;
317 writel(val, ctl_addr);
318
319 val &= ~PWR_RST_B_BIT;
320 writel(val, ctl_addr);
321
322 val |= PWR_CLK_DIS_BIT;
323 writel(val, ctl_addr);
324
325 val &= ~PWR_ON_BIT;
326 writel(val, ctl_addr);
327
328 val &= ~PWR_ON_2ND_BIT;
329 writel(val, ctl_addr);
330
331 /* wait until PWR_ACK = 0 */
332 timeout = jiffies + HZ;
333 expired = false;
334 while (1) {
335 ret = scpsys_domain_is_on(scpd);
336 if (ret == 0)
337 break;
338
339 if (expired) {
340 ret = -ETIMEDOUT;
341 goto out;
342 }
343
344 cpu_relax();
345
346 if (time_after(jiffies, timeout))
347 expired = true;
348 }
349
James Liao41b3e0f2015-10-07 17:14:40 +0800350 for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++)
351 clk_disable_unprepare(scpd->clk[i]);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200352
Sascha Hauer4688f382015-11-30 11:41:40 +0100353 if (scpd->supply)
354 regulator_disable(scpd->supply);
355
Sascha Hauerc84e3582015-06-24 08:17:04 +0200356 return 0;
357
358out:
359 dev_err(scp->dev, "Failed to power off domain %s\n", genpd->name);
360
361 return ret;
362}
363
James Liao6078c652016-10-20 16:56:35 +0800364static void init_clks(struct platform_device *pdev, struct clk **clk)
365{
366 int i;
367
368 for (i = CLK_NONE + 1; i < CLK_MAX; i++)
369 clk[i] = devm_clk_get(&pdev->dev, clk_names[i]);
370}
371
372static struct scp *init_scp(struct platform_device *pdev,
Mars Chengf1be4c42017-04-08 09:20:31 +0800373 const struct scp_domain_data *scp_domain_data, int num,
Sean Wang53fddb12017-08-07 15:24:35 +0800374 const struct scp_ctrl_reg *scp_ctrl_reg)
Sascha Hauerc84e3582015-06-24 08:17:04 +0200375{
376 struct genpd_onecell_data *pd_data;
377 struct resource *res;
James Liao6078c652016-10-20 16:56:35 +0800378 int i, j;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200379 struct scp *scp;
James Liao6078c652016-10-20 16:56:35 +0800380 struct clk *clk[CLK_MAX];
Sascha Hauerc84e3582015-06-24 08:17:04 +0200381
382 scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
383 if (!scp)
James Liao6078c652016-10-20 16:56:35 +0800384 return ERR_PTR(-ENOMEM);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200385
Mars Chengf1be4c42017-04-08 09:20:31 +0800386 scp->ctrl_reg.pwr_sta_offs = scp_ctrl_reg->pwr_sta_offs;
387 scp->ctrl_reg.pwr_sta2nd_offs = scp_ctrl_reg->pwr_sta2nd_offs;
388
Sascha Hauerc84e3582015-06-24 08:17:04 +0200389 scp->dev = &pdev->dev;
390
391 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
392 scp->base = devm_ioremap_resource(&pdev->dev, res);
393 if (IS_ERR(scp->base))
James Liao6078c652016-10-20 16:56:35 +0800394 return ERR_CAST(scp->base);
395
396 scp->domains = devm_kzalloc(&pdev->dev,
397 sizeof(*scp->domains) * num, GFP_KERNEL);
398 if (!scp->domains)
399 return ERR_PTR(-ENOMEM);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200400
401 pd_data = &scp->pd_data;
402
403 pd_data->domains = devm_kzalloc(&pdev->dev,
James Liao6078c652016-10-20 16:56:35 +0800404 sizeof(*pd_data->domains) * num, GFP_KERNEL);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200405 if (!pd_data->domains)
James Liao6078c652016-10-20 16:56:35 +0800406 return ERR_PTR(-ENOMEM);
James Liao41b3e0f2015-10-07 17:14:40 +0800407
Sascha Hauerc84e3582015-06-24 08:17:04 +0200408 scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
409 "infracfg");
410 if (IS_ERR(scp->infracfg)) {
411 dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
412 PTR_ERR(scp->infracfg));
James Liao6078c652016-10-20 16:56:35 +0800413 return ERR_CAST(scp->infracfg);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200414 }
415
James Liao6078c652016-10-20 16:56:35 +0800416 for (i = 0; i < num; i++) {
Sascha Hauer4688f382015-11-30 11:41:40 +0100417 struct scp_domain *scpd = &scp->domains[i];
418 const struct scp_domain_data *data = &scp_domain_data[i];
419
420 scpd->supply = devm_regulator_get_optional(&pdev->dev, data->name);
421 if (IS_ERR(scpd->supply)) {
422 if (PTR_ERR(scpd->supply) == -ENODEV)
423 scpd->supply = NULL;
424 else
James Liao6078c652016-10-20 16:56:35 +0800425 return ERR_CAST(scpd->supply);
Sascha Hauer4688f382015-11-30 11:41:40 +0100426 }
427 }
428
James Liao6078c652016-10-20 16:56:35 +0800429 pd_data->num_domains = num;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200430
James Liao6078c652016-10-20 16:56:35 +0800431 init_clks(pdev, clk);
432
433 for (i = 0; i < num; i++) {
Sascha Hauerc84e3582015-06-24 08:17:04 +0200434 struct scp_domain *scpd = &scp->domains[i];
435 struct generic_pm_domain *genpd = &scpd->genpd;
436 const struct scp_domain_data *data = &scp_domain_data[i];
437
438 pd_data->domains[i] = genpd;
439 scpd->scp = scp;
440
Matthias Bruggerbe295232015-12-30 09:30:40 +0100441 scpd->data = data;
James Liao6078c652016-10-20 16:56:35 +0800442
443 for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
444 struct clk *c = clk[data->clk_id[j]];
445
446 if (IS_ERR(c)) {
447 dev_err(&pdev->dev, "%s: clk unavailable\n",
448 data->name);
449 return ERR_CAST(c);
450 }
451
452 scpd->clk[j] = c;
453 }
Sascha Hauerc84e3582015-06-24 08:17:04 +0200454
455 genpd->name = data->name;
456 genpd->power_off = scpsys_power_off;
457 genpd->power_on = scpsys_power_on;
Geert Uytterhoeven7534d182017-11-07 13:48:13 +0100458 if (scpd->data->active_wakeup)
459 genpd->flags |= GENPD_FLAG_ACTIVE_WAKEUP;
James Liao6078c652016-10-20 16:56:35 +0800460 }
461
462 return scp;
463}
464
465static void mtk_register_power_domains(struct platform_device *pdev,
466 struct scp *scp, int num)
467{
468 struct genpd_onecell_data *pd_data;
469 int i, ret;
470
471 for (i = 0; i < num; i++) {
472 struct scp_domain *scpd = &scp->domains[i];
473 struct generic_pm_domain *genpd = &scpd->genpd;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200474
475 /*
James Liaod9c9f3b2016-04-12 16:34:30 +0800476 * Initially turn on all domains to make the domains usable
477 * with !CONFIG_PM and to get the hardware in sync with the
478 * software. The unused domains will be switched off during
479 * late_init time.
Sascha Hauerc84e3582015-06-24 08:17:04 +0200480 */
James Liaod9c9f3b2016-04-12 16:34:30 +0800481 genpd->power_on(genpd);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200482
James Liaod9c9f3b2016-04-12 16:34:30 +0800483 pm_genpd_init(genpd, NULL, false);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200484 }
485
486 /*
487 * We are not allowed to fail here since there is no way to unregister
488 * a power domain. Once registered above we have to keep the domains
489 * valid.
490 */
491
James Liao6078c652016-10-20 16:56:35 +0800492 pd_data = &scp->pd_data;
493
494 ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
495 if (ret)
496 dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
497}
498
499/*
Shunli Wang112ef182016-10-20 16:56:38 +0800500 * MT2701 power domain support
501 */
502
503static const struct scp_domain_data scp_domain_data_mt2701[] = {
504 [MT2701_POWER_DOMAIN_CONN] = {
505 .name = "conn",
506 .sta_mask = PWR_STATUS_CONN,
507 .ctl_offs = SPM_CONN_PWR_CON,
508 .bus_prot_mask = 0x0104,
509 .clk_id = {CLK_NONE},
510 .active_wakeup = true,
511 },
512 [MT2701_POWER_DOMAIN_DISP] = {
513 .name = "disp",
514 .sta_mask = PWR_STATUS_DISP,
515 .ctl_offs = SPM_DIS_PWR_CON,
516 .sram_pdn_bits = GENMASK(11, 8),
517 .clk_id = {CLK_MM},
518 .bus_prot_mask = 0x0002,
519 .active_wakeup = true,
520 },
521 [MT2701_POWER_DOMAIN_MFG] = {
522 .name = "mfg",
523 .sta_mask = PWR_STATUS_MFG,
524 .ctl_offs = SPM_MFG_PWR_CON,
525 .sram_pdn_bits = GENMASK(11, 8),
526 .sram_pdn_ack_bits = GENMASK(12, 12),
527 .clk_id = {CLK_MFG},
528 .active_wakeup = true,
529 },
530 [MT2701_POWER_DOMAIN_VDEC] = {
531 .name = "vdec",
532 .sta_mask = PWR_STATUS_VDEC,
533 .ctl_offs = SPM_VDE_PWR_CON,
534 .sram_pdn_bits = GENMASK(11, 8),
535 .sram_pdn_ack_bits = GENMASK(12, 12),
536 .clk_id = {CLK_MM},
537 .active_wakeup = true,
538 },
539 [MT2701_POWER_DOMAIN_ISP] = {
540 .name = "isp",
541 .sta_mask = PWR_STATUS_ISP,
542 .ctl_offs = SPM_ISP_PWR_CON,
543 .sram_pdn_bits = GENMASK(11, 8),
544 .sram_pdn_ack_bits = GENMASK(13, 12),
545 .clk_id = {CLK_MM},
546 .active_wakeup = true,
547 },
548 [MT2701_POWER_DOMAIN_BDP] = {
549 .name = "bdp",
550 .sta_mask = PWR_STATUS_BDP,
551 .ctl_offs = SPM_BDP_PWR_CON,
552 .sram_pdn_bits = GENMASK(11, 8),
553 .clk_id = {CLK_NONE},
554 .active_wakeup = true,
555 },
556 [MT2701_POWER_DOMAIN_ETH] = {
557 .name = "eth",
558 .sta_mask = PWR_STATUS_ETH,
559 .ctl_offs = SPM_ETH_PWR_CON,
560 .sram_pdn_bits = GENMASK(11, 8),
561 .sram_pdn_ack_bits = GENMASK(15, 12),
562 .clk_id = {CLK_ETHIF},
563 .active_wakeup = true,
564 },
565 [MT2701_POWER_DOMAIN_HIF] = {
566 .name = "hif",
567 .sta_mask = PWR_STATUS_HIF,
568 .ctl_offs = SPM_HIF_PWR_CON,
569 .sram_pdn_bits = GENMASK(11, 8),
570 .sram_pdn_ack_bits = GENMASK(15, 12),
571 .clk_id = {CLK_ETHIF},
572 .active_wakeup = true,
573 },
574 [MT2701_POWER_DOMAIN_IFR_MSC] = {
575 .name = "ifr_msc",
576 .sta_mask = PWR_STATUS_IFR_MSC,
577 .ctl_offs = SPM_IFR_MSC_PWR_CON,
578 .clk_id = {CLK_NONE},
579 .active_wakeup = true,
580 },
581};
582
Shunli Wang112ef182016-10-20 16:56:38 +0800583/*
Mars Cheng36c310f2017-04-08 09:20:34 +0800584 * MT6797 power domain support
585 */
586
587static const struct scp_domain_data scp_domain_data_mt6797[] = {
588 [MT6797_POWER_DOMAIN_VDEC] = {
589 .name = "vdec",
590 .sta_mask = BIT(7),
591 .ctl_offs = 0x300,
592 .sram_pdn_bits = GENMASK(8, 8),
593 .sram_pdn_ack_bits = GENMASK(12, 12),
594 .clk_id = {CLK_VDEC},
595 },
596 [MT6797_POWER_DOMAIN_VENC] = {
597 .name = "venc",
598 .sta_mask = BIT(21),
599 .ctl_offs = 0x304,
600 .sram_pdn_bits = GENMASK(11, 8),
601 .sram_pdn_ack_bits = GENMASK(15, 12),
602 .clk_id = {CLK_NONE},
603 },
604 [MT6797_POWER_DOMAIN_ISP] = {
605 .name = "isp",
606 .sta_mask = BIT(5),
607 .ctl_offs = 0x308,
608 .sram_pdn_bits = GENMASK(9, 8),
609 .sram_pdn_ack_bits = GENMASK(13, 12),
610 .clk_id = {CLK_NONE},
611 },
612 [MT6797_POWER_DOMAIN_MM] = {
613 .name = "mm",
614 .sta_mask = BIT(3),
615 .ctl_offs = 0x30C,
616 .sram_pdn_bits = GENMASK(8, 8),
617 .sram_pdn_ack_bits = GENMASK(12, 12),
618 .clk_id = {CLK_MM},
619 .bus_prot_mask = (BIT(1) | BIT(2)),
620 },
621 [MT6797_POWER_DOMAIN_AUDIO] = {
622 .name = "audio",
623 .sta_mask = BIT(24),
624 .ctl_offs = 0x314,
625 .sram_pdn_bits = GENMASK(11, 8),
626 .sram_pdn_ack_bits = GENMASK(15, 12),
627 .clk_id = {CLK_NONE},
628 },
629 [MT6797_POWER_DOMAIN_MFG_ASYNC] = {
630 .name = "mfg_async",
631 .sta_mask = BIT(13),
632 .ctl_offs = 0x334,
633 .sram_pdn_bits = 0,
634 .sram_pdn_ack_bits = 0,
635 .clk_id = {CLK_MFG},
636 },
637 [MT6797_POWER_DOMAIN_MJC] = {
638 .name = "mjc",
639 .sta_mask = BIT(20),
640 .ctl_offs = 0x310,
641 .sram_pdn_bits = GENMASK(8, 8),
642 .sram_pdn_ack_bits = GENMASK(12, 12),
643 .clk_id = {CLK_NONE},
644 },
645};
646
Mars Cheng36c310f2017-04-08 09:20:34 +0800647#define SPM_PWR_STATUS_MT6797 0x0180
648#define SPM_PWR_STATUS_2ND_MT6797 0x0184
649
Sean Wang53fddb12017-08-07 15:24:35 +0800650static const struct scp_subdomain scp_subdomain_mt6797[] = {
651 {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_VDEC},
652 {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_ISP},
653 {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_VENC},
654 {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_MJC},
655};
Mars Cheng36c310f2017-04-08 09:20:34 +0800656
657/*
Sean Wang52510ee2017-08-07 15:24:37 +0800658 * MT7622 power domain support
659 */
660
661static const struct scp_domain_data scp_domain_data_mt7622[] = {
662 [MT7622_POWER_DOMAIN_ETHSYS] = {
663 .name = "ethsys",
664 .sta_mask = PWR_STATUS_ETHSYS,
665 .ctl_offs = SPM_ETHSYS_PWR_CON,
666 .sram_pdn_bits = GENMASK(11, 8),
667 .sram_pdn_ack_bits = GENMASK(15, 12),
668 .clk_id = {CLK_NONE},
669 .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_ETHSYS,
670 .active_wakeup = true,
671 },
672 [MT7622_POWER_DOMAIN_HIF0] = {
673 .name = "hif0",
674 .sta_mask = PWR_STATUS_HIF0,
675 .ctl_offs = SPM_HIF0_PWR_CON,
676 .sram_pdn_bits = GENMASK(11, 8),
677 .sram_pdn_ack_bits = GENMASK(15, 12),
678 .clk_id = {CLK_HIFSEL},
679 .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_HIF0,
680 .active_wakeup = true,
681 },
682 [MT7622_POWER_DOMAIN_HIF1] = {
683 .name = "hif1",
684 .sta_mask = PWR_STATUS_HIF1,
685 .ctl_offs = SPM_HIF1_PWR_CON,
686 .sram_pdn_bits = GENMASK(11, 8),
687 .sram_pdn_ack_bits = GENMASK(15, 12),
688 .clk_id = {CLK_HIFSEL},
689 .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_HIF1,
690 .active_wakeup = true,
691 },
692 [MT7622_POWER_DOMAIN_WB] = {
693 .name = "wb",
694 .sta_mask = PWR_STATUS_WB,
695 .ctl_offs = SPM_WB_PWR_CON,
696 .sram_pdn_bits = 0,
697 .sram_pdn_ack_bits = 0,
698 .clk_id = {CLK_NONE},
699 .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_WB,
700 .active_wakeup = true,
701 },
702};
703
704/*
James Liao6078c652016-10-20 16:56:35 +0800705 * MT8173 power domain support
706 */
707
708static const struct scp_domain_data scp_domain_data_mt8173[] = {
709 [MT8173_POWER_DOMAIN_VDEC] = {
710 .name = "vdec",
711 .sta_mask = PWR_STATUS_VDEC,
712 .ctl_offs = SPM_VDE_PWR_CON,
713 .sram_pdn_bits = GENMASK(11, 8),
714 .sram_pdn_ack_bits = GENMASK(12, 12),
715 .clk_id = {CLK_MM},
716 },
717 [MT8173_POWER_DOMAIN_VENC] = {
718 .name = "venc",
719 .sta_mask = PWR_STATUS_VENC,
720 .ctl_offs = SPM_VEN_PWR_CON,
721 .sram_pdn_bits = GENMASK(11, 8),
722 .sram_pdn_ack_bits = GENMASK(15, 12),
723 .clk_id = {CLK_MM, CLK_VENC},
724 },
725 [MT8173_POWER_DOMAIN_ISP] = {
726 .name = "isp",
727 .sta_mask = PWR_STATUS_ISP,
728 .ctl_offs = SPM_ISP_PWR_CON,
729 .sram_pdn_bits = GENMASK(11, 8),
730 .sram_pdn_ack_bits = GENMASK(13, 12),
731 .clk_id = {CLK_MM},
732 },
733 [MT8173_POWER_DOMAIN_MM] = {
734 .name = "mm",
735 .sta_mask = PWR_STATUS_DISP,
736 .ctl_offs = SPM_DIS_PWR_CON,
737 .sram_pdn_bits = GENMASK(11, 8),
738 .sram_pdn_ack_bits = GENMASK(12, 12),
739 .clk_id = {CLK_MM},
740 .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
741 MT8173_TOP_AXI_PROT_EN_MM_M1,
742 },
743 [MT8173_POWER_DOMAIN_VENC_LT] = {
744 .name = "venc_lt",
745 .sta_mask = PWR_STATUS_VENC_LT,
746 .ctl_offs = SPM_VEN2_PWR_CON,
747 .sram_pdn_bits = GENMASK(11, 8),
748 .sram_pdn_ack_bits = GENMASK(15, 12),
749 .clk_id = {CLK_MM, CLK_VENC_LT},
750 },
751 [MT8173_POWER_DOMAIN_AUDIO] = {
752 .name = "audio",
753 .sta_mask = PWR_STATUS_AUDIO,
754 .ctl_offs = SPM_AUDIO_PWR_CON,
755 .sram_pdn_bits = GENMASK(11, 8),
756 .sram_pdn_ack_bits = GENMASK(15, 12),
757 .clk_id = {CLK_NONE},
758 },
759 [MT8173_POWER_DOMAIN_USB] = {
760 .name = "usb",
761 .sta_mask = PWR_STATUS_USB,
762 .ctl_offs = SPM_USB_PWR_CON,
763 .sram_pdn_bits = GENMASK(11, 8),
764 .sram_pdn_ack_bits = GENMASK(15, 12),
765 .clk_id = {CLK_NONE},
766 .active_wakeup = true,
767 },
768 [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
769 .name = "mfg_async",
770 .sta_mask = PWR_STATUS_MFG_ASYNC,
771 .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
772 .sram_pdn_bits = GENMASK(11, 8),
773 .sram_pdn_ack_bits = 0,
774 .clk_id = {CLK_MFG},
775 },
776 [MT8173_POWER_DOMAIN_MFG_2D] = {
777 .name = "mfg_2d",
778 .sta_mask = PWR_STATUS_MFG_2D,
779 .ctl_offs = SPM_MFG_2D_PWR_CON,
780 .sram_pdn_bits = GENMASK(11, 8),
781 .sram_pdn_ack_bits = GENMASK(13, 12),
782 .clk_id = {CLK_NONE},
783 },
784 [MT8173_POWER_DOMAIN_MFG] = {
785 .name = "mfg",
786 .sta_mask = PWR_STATUS_MFG,
787 .ctl_offs = SPM_MFG_PWR_CON,
788 .sram_pdn_bits = GENMASK(13, 8),
789 .sram_pdn_ack_bits = GENMASK(21, 16),
790 .clk_id = {CLK_NONE},
791 .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
792 MT8173_TOP_AXI_PROT_EN_MFG_M0 |
793 MT8173_TOP_AXI_PROT_EN_MFG_M1 |
794 MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
795 },
796};
797
Sean Wang53fddb12017-08-07 15:24:35 +0800798static const struct scp_subdomain scp_subdomain_mt8173[] = {
799 {MT8173_POWER_DOMAIN_MFG_ASYNC, MT8173_POWER_DOMAIN_MFG_2D},
800 {MT8173_POWER_DOMAIN_MFG_2D, MT8173_POWER_DOMAIN_MFG},
801};
James Liao6078c652016-10-20 16:56:35 +0800802
Sean Wang53fddb12017-08-07 15:24:35 +0800803static const struct scp_soc_data mt2701_data = {
804 .domains = scp_domain_data_mt2701,
805 .num_domains = ARRAY_SIZE(scp_domain_data_mt2701),
806 .regs = {
807 .pwr_sta_offs = SPM_PWR_STATUS,
808 .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
809 }
810};
James Liao6078c652016-10-20 16:56:35 +0800811
Sean Wang53fddb12017-08-07 15:24:35 +0800812static const struct scp_soc_data mt6797_data = {
813 .domains = scp_domain_data_mt6797,
814 .num_domains = ARRAY_SIZE(scp_domain_data_mt6797),
815 .subdomains = scp_subdomain_mt6797,
816 .num_subdomains = ARRAY_SIZE(scp_subdomain_mt6797),
817 .regs = {
818 .pwr_sta_offs = SPM_PWR_STATUS_MT6797,
819 .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND_MT6797
820 }
821};
Mars Chengf1be4c42017-04-08 09:20:31 +0800822
Sean Wang52510ee2017-08-07 15:24:37 +0800823static const struct scp_soc_data mt7622_data = {
824 .domains = scp_domain_data_mt7622,
825 .num_domains = ARRAY_SIZE(scp_domain_data_mt7622),
826 .regs = {
827 .pwr_sta_offs = SPM_PWR_STATUS,
828 .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
829 }
830};
831
Sean Wang53fddb12017-08-07 15:24:35 +0800832static const struct scp_soc_data mt8173_data = {
833 .domains = scp_domain_data_mt8173,
834 .num_domains = ARRAY_SIZE(scp_domain_data_mt8173),
835 .subdomains = scp_subdomain_mt8173,
836 .num_subdomains = ARRAY_SIZE(scp_subdomain_mt8173),
837 .regs = {
838 .pwr_sta_offs = SPM_PWR_STATUS,
839 .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
840 }
841};
Sascha Hauerc84e3582015-06-24 08:17:04 +0200842
James Liao6078c652016-10-20 16:56:35 +0800843/*
844 * scpsys driver init
845 */
846
Sascha Hauerc84e3582015-06-24 08:17:04 +0200847static const struct of_device_id of_scpsys_match_tbl[] = {
848 {
Shunli Wang112ef182016-10-20 16:56:38 +0800849 .compatible = "mediatek,mt2701-scpsys",
Sean Wang53fddb12017-08-07 15:24:35 +0800850 .data = &mt2701_data,
Shunli Wang112ef182016-10-20 16:56:38 +0800851 }, {
Mars Cheng36c310f2017-04-08 09:20:34 +0800852 .compatible = "mediatek,mt6797-scpsys",
Sean Wang53fddb12017-08-07 15:24:35 +0800853 .data = &mt6797_data,
Mars Cheng36c310f2017-04-08 09:20:34 +0800854 }, {
Sean Wang52510ee2017-08-07 15:24:37 +0800855 .compatible = "mediatek,mt7622-scpsys",
856 .data = &mt7622_data,
857 }, {
Sascha Hauerc84e3582015-06-24 08:17:04 +0200858 .compatible = "mediatek,mt8173-scpsys",
Sean Wang53fddb12017-08-07 15:24:35 +0800859 .data = &mt8173_data,
Sascha Hauerc84e3582015-06-24 08:17:04 +0200860 }, {
861 /* sentinel */
862 }
863};
864
James Liao6078c652016-10-20 16:56:35 +0800865static int scpsys_probe(struct platform_device *pdev)
866{
Sean Wang53fddb12017-08-07 15:24:35 +0800867 const struct of_device_id *match;
868 const struct scp_subdomain *sd;
869 const struct scp_soc_data *soc;
870 struct scp *scp;
871 struct genpd_onecell_data *pd_data;
872 int i, ret;
James Liao6078c652016-10-20 16:56:35 +0800873
Sean Wang53fddb12017-08-07 15:24:35 +0800874 match = of_match_device(of_scpsys_match_tbl, &pdev->dev);
875 soc = (const struct scp_soc_data *)match->data;
James Liao6078c652016-10-20 16:56:35 +0800876
Sean Wang53fddb12017-08-07 15:24:35 +0800877 scp = init_scp(pdev, soc->domains, soc->num_domains, &soc->regs);
878 if (IS_ERR(scp))
879 return PTR_ERR(scp);
James Liao6078c652016-10-20 16:56:35 +0800880
Sean Wang53fddb12017-08-07 15:24:35 +0800881 mtk_register_power_domains(pdev, scp, soc->num_domains);
882
883 pd_data = &scp->pd_data;
884
885 for (i = 0, sd = soc->subdomains ; i < soc->num_subdomains ; i++) {
886 ret = pm_genpd_add_subdomain(pd_data->domains[sd->origin],
887 pd_data->domains[sd->subdomain]);
888 if (ret && IS_ENABLED(CONFIG_PM))
889 dev_err(&pdev->dev, "Failed to add subdomain: %d\n",
890 ret);
891 }
892
893 return 0;
James Liao6078c652016-10-20 16:56:35 +0800894}
895
Sascha Hauerc84e3582015-06-24 08:17:04 +0200896static struct platform_driver scpsys_drv = {
Matthias Bruggerbe295232015-12-30 09:30:40 +0100897 .probe = scpsys_probe,
Sascha Hauerc84e3582015-06-24 08:17:04 +0200898 .driver = {
899 .name = "mtk-scpsys",
Matthias Bruggerbe295232015-12-30 09:30:40 +0100900 .suppress_bind_attrs = true,
Sascha Hauerc84e3582015-06-24 08:17:04 +0200901 .owner = THIS_MODULE,
902 .of_match_table = of_match_ptr(of_scpsys_match_tbl),
903 },
904};
Matthias Bruggerbe295232015-12-30 09:30:40 +0100905builtin_platform_driver(scpsys_drv);