blob: e1ce8b1b5090aa0a7b91b6abcd73ad7fa0760261 [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
Eddie Huang47e90152015-08-26 15:14:41 +0800364static bool scpsys_active_wakeup(struct device *dev)
365{
366 struct generic_pm_domain *genpd;
367 struct scp_domain *scpd;
368
369 genpd = pd_to_genpd(dev->pm_domain);
370 scpd = container_of(genpd, struct scp_domain, genpd);
371
Matthias Bruggerbe295232015-12-30 09:30:40 +0100372 return scpd->data->active_wakeup;
Eddie Huang47e90152015-08-26 15:14:41 +0800373}
374
James Liao6078c652016-10-20 16:56:35 +0800375static void init_clks(struct platform_device *pdev, struct clk **clk)
376{
377 int i;
378
379 for (i = CLK_NONE + 1; i < CLK_MAX; i++)
380 clk[i] = devm_clk_get(&pdev->dev, clk_names[i]);
381}
382
383static struct scp *init_scp(struct platform_device *pdev,
Mars Chengf1be4c42017-04-08 09:20:31 +0800384 const struct scp_domain_data *scp_domain_data, int num,
Sean Wang53fddb12017-08-07 15:24:35 +0800385 const struct scp_ctrl_reg *scp_ctrl_reg)
Sascha Hauerc84e3582015-06-24 08:17:04 +0200386{
387 struct genpd_onecell_data *pd_data;
388 struct resource *res;
James Liao6078c652016-10-20 16:56:35 +0800389 int i, j;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200390 struct scp *scp;
James Liao6078c652016-10-20 16:56:35 +0800391 struct clk *clk[CLK_MAX];
Sascha Hauerc84e3582015-06-24 08:17:04 +0200392
393 scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
394 if (!scp)
James Liao6078c652016-10-20 16:56:35 +0800395 return ERR_PTR(-ENOMEM);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200396
Mars Chengf1be4c42017-04-08 09:20:31 +0800397 scp->ctrl_reg.pwr_sta_offs = scp_ctrl_reg->pwr_sta_offs;
398 scp->ctrl_reg.pwr_sta2nd_offs = scp_ctrl_reg->pwr_sta2nd_offs;
399
Sascha Hauerc84e3582015-06-24 08:17:04 +0200400 scp->dev = &pdev->dev;
401
402 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
403 scp->base = devm_ioremap_resource(&pdev->dev, res);
404 if (IS_ERR(scp->base))
James Liao6078c652016-10-20 16:56:35 +0800405 return ERR_CAST(scp->base);
406
407 scp->domains = devm_kzalloc(&pdev->dev,
408 sizeof(*scp->domains) * num, GFP_KERNEL);
409 if (!scp->domains)
410 return ERR_PTR(-ENOMEM);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200411
412 pd_data = &scp->pd_data;
413
414 pd_data->domains = devm_kzalloc(&pdev->dev,
James Liao6078c652016-10-20 16:56:35 +0800415 sizeof(*pd_data->domains) * num, GFP_KERNEL);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200416 if (!pd_data->domains)
James Liao6078c652016-10-20 16:56:35 +0800417 return ERR_PTR(-ENOMEM);
James Liao41b3e0f2015-10-07 17:14:40 +0800418
Sascha Hauerc84e3582015-06-24 08:17:04 +0200419 scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
420 "infracfg");
421 if (IS_ERR(scp->infracfg)) {
422 dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
423 PTR_ERR(scp->infracfg));
James Liao6078c652016-10-20 16:56:35 +0800424 return ERR_CAST(scp->infracfg);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200425 }
426
James Liao6078c652016-10-20 16:56:35 +0800427 for (i = 0; i < num; i++) {
Sascha Hauer4688f382015-11-30 11:41:40 +0100428 struct scp_domain *scpd = &scp->domains[i];
429 const struct scp_domain_data *data = &scp_domain_data[i];
430
431 scpd->supply = devm_regulator_get_optional(&pdev->dev, data->name);
432 if (IS_ERR(scpd->supply)) {
433 if (PTR_ERR(scpd->supply) == -ENODEV)
434 scpd->supply = NULL;
435 else
James Liao6078c652016-10-20 16:56:35 +0800436 return ERR_CAST(scpd->supply);
Sascha Hauer4688f382015-11-30 11:41:40 +0100437 }
438 }
439
James Liao6078c652016-10-20 16:56:35 +0800440 pd_data->num_domains = num;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200441
James Liao6078c652016-10-20 16:56:35 +0800442 init_clks(pdev, clk);
443
444 for (i = 0; i < num; i++) {
Sascha Hauerc84e3582015-06-24 08:17:04 +0200445 struct scp_domain *scpd = &scp->domains[i];
446 struct generic_pm_domain *genpd = &scpd->genpd;
447 const struct scp_domain_data *data = &scp_domain_data[i];
448
449 pd_data->domains[i] = genpd;
450 scpd->scp = scp;
451
Matthias Bruggerbe295232015-12-30 09:30:40 +0100452 scpd->data = data;
James Liao6078c652016-10-20 16:56:35 +0800453
454 for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
455 struct clk *c = clk[data->clk_id[j]];
456
457 if (IS_ERR(c)) {
458 dev_err(&pdev->dev, "%s: clk unavailable\n",
459 data->name);
460 return ERR_CAST(c);
461 }
462
463 scpd->clk[j] = c;
464 }
Sascha Hauerc84e3582015-06-24 08:17:04 +0200465
466 genpd->name = data->name;
467 genpd->power_off = scpsys_power_off;
468 genpd->power_on = scpsys_power_on;
Eddie Huang47e90152015-08-26 15:14:41 +0800469 genpd->dev_ops.active_wakeup = scpsys_active_wakeup;
James Liao6078c652016-10-20 16:56:35 +0800470 }
471
472 return scp;
473}
474
475static void mtk_register_power_domains(struct platform_device *pdev,
476 struct scp *scp, int num)
477{
478 struct genpd_onecell_data *pd_data;
479 int i, ret;
480
481 for (i = 0; i < num; i++) {
482 struct scp_domain *scpd = &scp->domains[i];
483 struct generic_pm_domain *genpd = &scpd->genpd;
Sascha Hauerc84e3582015-06-24 08:17:04 +0200484
485 /*
James Liaod9c9f3b2016-04-12 16:34:30 +0800486 * Initially turn on all domains to make the domains usable
487 * with !CONFIG_PM and to get the hardware in sync with the
488 * software. The unused domains will be switched off during
489 * late_init time.
Sascha Hauerc84e3582015-06-24 08:17:04 +0200490 */
James Liaod9c9f3b2016-04-12 16:34:30 +0800491 genpd->power_on(genpd);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200492
James Liaod9c9f3b2016-04-12 16:34:30 +0800493 pm_genpd_init(genpd, NULL, false);
Sascha Hauerc84e3582015-06-24 08:17:04 +0200494 }
495
496 /*
497 * We are not allowed to fail here since there is no way to unregister
498 * a power domain. Once registered above we have to keep the domains
499 * valid.
500 */
501
James Liao6078c652016-10-20 16:56:35 +0800502 pd_data = &scp->pd_data;
503
504 ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
505 if (ret)
506 dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
507}
508
509/*
Shunli Wang112ef182016-10-20 16:56:38 +0800510 * MT2701 power domain support
511 */
512
513static const struct scp_domain_data scp_domain_data_mt2701[] = {
514 [MT2701_POWER_DOMAIN_CONN] = {
515 .name = "conn",
516 .sta_mask = PWR_STATUS_CONN,
517 .ctl_offs = SPM_CONN_PWR_CON,
518 .bus_prot_mask = 0x0104,
519 .clk_id = {CLK_NONE},
520 .active_wakeup = true,
521 },
522 [MT2701_POWER_DOMAIN_DISP] = {
523 .name = "disp",
524 .sta_mask = PWR_STATUS_DISP,
525 .ctl_offs = SPM_DIS_PWR_CON,
526 .sram_pdn_bits = GENMASK(11, 8),
527 .clk_id = {CLK_MM},
528 .bus_prot_mask = 0x0002,
529 .active_wakeup = true,
530 },
531 [MT2701_POWER_DOMAIN_MFG] = {
532 .name = "mfg",
533 .sta_mask = PWR_STATUS_MFG,
534 .ctl_offs = SPM_MFG_PWR_CON,
535 .sram_pdn_bits = GENMASK(11, 8),
536 .sram_pdn_ack_bits = GENMASK(12, 12),
537 .clk_id = {CLK_MFG},
538 .active_wakeup = true,
539 },
540 [MT2701_POWER_DOMAIN_VDEC] = {
541 .name = "vdec",
542 .sta_mask = PWR_STATUS_VDEC,
543 .ctl_offs = SPM_VDE_PWR_CON,
544 .sram_pdn_bits = GENMASK(11, 8),
545 .sram_pdn_ack_bits = GENMASK(12, 12),
546 .clk_id = {CLK_MM},
547 .active_wakeup = true,
548 },
549 [MT2701_POWER_DOMAIN_ISP] = {
550 .name = "isp",
551 .sta_mask = PWR_STATUS_ISP,
552 .ctl_offs = SPM_ISP_PWR_CON,
553 .sram_pdn_bits = GENMASK(11, 8),
554 .sram_pdn_ack_bits = GENMASK(13, 12),
555 .clk_id = {CLK_MM},
556 .active_wakeup = true,
557 },
558 [MT2701_POWER_DOMAIN_BDP] = {
559 .name = "bdp",
560 .sta_mask = PWR_STATUS_BDP,
561 .ctl_offs = SPM_BDP_PWR_CON,
562 .sram_pdn_bits = GENMASK(11, 8),
563 .clk_id = {CLK_NONE},
564 .active_wakeup = true,
565 },
566 [MT2701_POWER_DOMAIN_ETH] = {
567 .name = "eth",
568 .sta_mask = PWR_STATUS_ETH,
569 .ctl_offs = SPM_ETH_PWR_CON,
570 .sram_pdn_bits = GENMASK(11, 8),
571 .sram_pdn_ack_bits = GENMASK(15, 12),
572 .clk_id = {CLK_ETHIF},
573 .active_wakeup = true,
574 },
575 [MT2701_POWER_DOMAIN_HIF] = {
576 .name = "hif",
577 .sta_mask = PWR_STATUS_HIF,
578 .ctl_offs = SPM_HIF_PWR_CON,
579 .sram_pdn_bits = GENMASK(11, 8),
580 .sram_pdn_ack_bits = GENMASK(15, 12),
581 .clk_id = {CLK_ETHIF},
582 .active_wakeup = true,
583 },
584 [MT2701_POWER_DOMAIN_IFR_MSC] = {
585 .name = "ifr_msc",
586 .sta_mask = PWR_STATUS_IFR_MSC,
587 .ctl_offs = SPM_IFR_MSC_PWR_CON,
588 .clk_id = {CLK_NONE},
589 .active_wakeup = true,
590 },
591};
592
Shunli Wang112ef182016-10-20 16:56:38 +0800593/*
Mars Cheng36c310f2017-04-08 09:20:34 +0800594 * MT6797 power domain support
595 */
596
597static const struct scp_domain_data scp_domain_data_mt6797[] = {
598 [MT6797_POWER_DOMAIN_VDEC] = {
599 .name = "vdec",
600 .sta_mask = BIT(7),
601 .ctl_offs = 0x300,
602 .sram_pdn_bits = GENMASK(8, 8),
603 .sram_pdn_ack_bits = GENMASK(12, 12),
604 .clk_id = {CLK_VDEC},
605 },
606 [MT6797_POWER_DOMAIN_VENC] = {
607 .name = "venc",
608 .sta_mask = BIT(21),
609 .ctl_offs = 0x304,
610 .sram_pdn_bits = GENMASK(11, 8),
611 .sram_pdn_ack_bits = GENMASK(15, 12),
612 .clk_id = {CLK_NONE},
613 },
614 [MT6797_POWER_DOMAIN_ISP] = {
615 .name = "isp",
616 .sta_mask = BIT(5),
617 .ctl_offs = 0x308,
618 .sram_pdn_bits = GENMASK(9, 8),
619 .sram_pdn_ack_bits = GENMASK(13, 12),
620 .clk_id = {CLK_NONE},
621 },
622 [MT6797_POWER_DOMAIN_MM] = {
623 .name = "mm",
624 .sta_mask = BIT(3),
625 .ctl_offs = 0x30C,
626 .sram_pdn_bits = GENMASK(8, 8),
627 .sram_pdn_ack_bits = GENMASK(12, 12),
628 .clk_id = {CLK_MM},
629 .bus_prot_mask = (BIT(1) | BIT(2)),
630 },
631 [MT6797_POWER_DOMAIN_AUDIO] = {
632 .name = "audio",
633 .sta_mask = BIT(24),
634 .ctl_offs = 0x314,
635 .sram_pdn_bits = GENMASK(11, 8),
636 .sram_pdn_ack_bits = GENMASK(15, 12),
637 .clk_id = {CLK_NONE},
638 },
639 [MT6797_POWER_DOMAIN_MFG_ASYNC] = {
640 .name = "mfg_async",
641 .sta_mask = BIT(13),
642 .ctl_offs = 0x334,
643 .sram_pdn_bits = 0,
644 .sram_pdn_ack_bits = 0,
645 .clk_id = {CLK_MFG},
646 },
647 [MT6797_POWER_DOMAIN_MJC] = {
648 .name = "mjc",
649 .sta_mask = BIT(20),
650 .ctl_offs = 0x310,
651 .sram_pdn_bits = GENMASK(8, 8),
652 .sram_pdn_ack_bits = GENMASK(12, 12),
653 .clk_id = {CLK_NONE},
654 },
655};
656
Mars Cheng36c310f2017-04-08 09:20:34 +0800657#define SPM_PWR_STATUS_MT6797 0x0180
658#define SPM_PWR_STATUS_2ND_MT6797 0x0184
659
Sean Wang53fddb12017-08-07 15:24:35 +0800660static const struct scp_subdomain scp_subdomain_mt6797[] = {
661 {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_VDEC},
662 {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_ISP},
663 {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_VENC},
664 {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_MJC},
665};
Mars Cheng36c310f2017-04-08 09:20:34 +0800666
667/*
Sean Wang52510ee2017-08-07 15:24:37 +0800668 * MT7622 power domain support
669 */
670
671static const struct scp_domain_data scp_domain_data_mt7622[] = {
672 [MT7622_POWER_DOMAIN_ETHSYS] = {
673 .name = "ethsys",
674 .sta_mask = PWR_STATUS_ETHSYS,
675 .ctl_offs = SPM_ETHSYS_PWR_CON,
676 .sram_pdn_bits = GENMASK(11, 8),
677 .sram_pdn_ack_bits = GENMASK(15, 12),
678 .clk_id = {CLK_NONE},
679 .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_ETHSYS,
680 .active_wakeup = true,
681 },
682 [MT7622_POWER_DOMAIN_HIF0] = {
683 .name = "hif0",
684 .sta_mask = PWR_STATUS_HIF0,
685 .ctl_offs = SPM_HIF0_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_HIF0,
690 .active_wakeup = true,
691 },
692 [MT7622_POWER_DOMAIN_HIF1] = {
693 .name = "hif1",
694 .sta_mask = PWR_STATUS_HIF1,
695 .ctl_offs = SPM_HIF1_PWR_CON,
696 .sram_pdn_bits = GENMASK(11, 8),
697 .sram_pdn_ack_bits = GENMASK(15, 12),
698 .clk_id = {CLK_HIFSEL},
699 .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_HIF1,
700 .active_wakeup = true,
701 },
702 [MT7622_POWER_DOMAIN_WB] = {
703 .name = "wb",
704 .sta_mask = PWR_STATUS_WB,
705 .ctl_offs = SPM_WB_PWR_CON,
706 .sram_pdn_bits = 0,
707 .sram_pdn_ack_bits = 0,
708 .clk_id = {CLK_NONE},
709 .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_WB,
710 .active_wakeup = true,
711 },
712};
713
714/*
James Liao6078c652016-10-20 16:56:35 +0800715 * MT8173 power domain support
716 */
717
718static const struct scp_domain_data scp_domain_data_mt8173[] = {
719 [MT8173_POWER_DOMAIN_VDEC] = {
720 .name = "vdec",
721 .sta_mask = PWR_STATUS_VDEC,
722 .ctl_offs = SPM_VDE_PWR_CON,
723 .sram_pdn_bits = GENMASK(11, 8),
724 .sram_pdn_ack_bits = GENMASK(12, 12),
725 .clk_id = {CLK_MM},
726 },
727 [MT8173_POWER_DOMAIN_VENC] = {
728 .name = "venc",
729 .sta_mask = PWR_STATUS_VENC,
730 .ctl_offs = SPM_VEN_PWR_CON,
731 .sram_pdn_bits = GENMASK(11, 8),
732 .sram_pdn_ack_bits = GENMASK(15, 12),
733 .clk_id = {CLK_MM, CLK_VENC},
734 },
735 [MT8173_POWER_DOMAIN_ISP] = {
736 .name = "isp",
737 .sta_mask = PWR_STATUS_ISP,
738 .ctl_offs = SPM_ISP_PWR_CON,
739 .sram_pdn_bits = GENMASK(11, 8),
740 .sram_pdn_ack_bits = GENMASK(13, 12),
741 .clk_id = {CLK_MM},
742 },
743 [MT8173_POWER_DOMAIN_MM] = {
744 .name = "mm",
745 .sta_mask = PWR_STATUS_DISP,
746 .ctl_offs = SPM_DIS_PWR_CON,
747 .sram_pdn_bits = GENMASK(11, 8),
748 .sram_pdn_ack_bits = GENMASK(12, 12),
749 .clk_id = {CLK_MM},
750 .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
751 MT8173_TOP_AXI_PROT_EN_MM_M1,
752 },
753 [MT8173_POWER_DOMAIN_VENC_LT] = {
754 .name = "venc_lt",
755 .sta_mask = PWR_STATUS_VENC_LT,
756 .ctl_offs = SPM_VEN2_PWR_CON,
757 .sram_pdn_bits = GENMASK(11, 8),
758 .sram_pdn_ack_bits = GENMASK(15, 12),
759 .clk_id = {CLK_MM, CLK_VENC_LT},
760 },
761 [MT8173_POWER_DOMAIN_AUDIO] = {
762 .name = "audio",
763 .sta_mask = PWR_STATUS_AUDIO,
764 .ctl_offs = SPM_AUDIO_PWR_CON,
765 .sram_pdn_bits = GENMASK(11, 8),
766 .sram_pdn_ack_bits = GENMASK(15, 12),
767 .clk_id = {CLK_NONE},
768 },
769 [MT8173_POWER_DOMAIN_USB] = {
770 .name = "usb",
771 .sta_mask = PWR_STATUS_USB,
772 .ctl_offs = SPM_USB_PWR_CON,
773 .sram_pdn_bits = GENMASK(11, 8),
774 .sram_pdn_ack_bits = GENMASK(15, 12),
775 .clk_id = {CLK_NONE},
776 .active_wakeup = true,
777 },
778 [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
779 .name = "mfg_async",
780 .sta_mask = PWR_STATUS_MFG_ASYNC,
781 .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
782 .sram_pdn_bits = GENMASK(11, 8),
783 .sram_pdn_ack_bits = 0,
784 .clk_id = {CLK_MFG},
785 },
786 [MT8173_POWER_DOMAIN_MFG_2D] = {
787 .name = "mfg_2d",
788 .sta_mask = PWR_STATUS_MFG_2D,
789 .ctl_offs = SPM_MFG_2D_PWR_CON,
790 .sram_pdn_bits = GENMASK(11, 8),
791 .sram_pdn_ack_bits = GENMASK(13, 12),
792 .clk_id = {CLK_NONE},
793 },
794 [MT8173_POWER_DOMAIN_MFG] = {
795 .name = "mfg",
796 .sta_mask = PWR_STATUS_MFG,
797 .ctl_offs = SPM_MFG_PWR_CON,
798 .sram_pdn_bits = GENMASK(13, 8),
799 .sram_pdn_ack_bits = GENMASK(21, 16),
800 .clk_id = {CLK_NONE},
801 .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
802 MT8173_TOP_AXI_PROT_EN_MFG_M0 |
803 MT8173_TOP_AXI_PROT_EN_MFG_M1 |
804 MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
805 },
806};
807
Sean Wang53fddb12017-08-07 15:24:35 +0800808static const struct scp_subdomain scp_subdomain_mt8173[] = {
809 {MT8173_POWER_DOMAIN_MFG_ASYNC, MT8173_POWER_DOMAIN_MFG_2D},
810 {MT8173_POWER_DOMAIN_MFG_2D, MT8173_POWER_DOMAIN_MFG},
811};
James Liao6078c652016-10-20 16:56:35 +0800812
Sean Wang53fddb12017-08-07 15:24:35 +0800813static const struct scp_soc_data mt2701_data = {
814 .domains = scp_domain_data_mt2701,
815 .num_domains = ARRAY_SIZE(scp_domain_data_mt2701),
816 .regs = {
817 .pwr_sta_offs = SPM_PWR_STATUS,
818 .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
819 }
820};
James Liao6078c652016-10-20 16:56:35 +0800821
Sean Wang53fddb12017-08-07 15:24:35 +0800822static const struct scp_soc_data mt6797_data = {
823 .domains = scp_domain_data_mt6797,
824 .num_domains = ARRAY_SIZE(scp_domain_data_mt6797),
825 .subdomains = scp_subdomain_mt6797,
826 .num_subdomains = ARRAY_SIZE(scp_subdomain_mt6797),
827 .regs = {
828 .pwr_sta_offs = SPM_PWR_STATUS_MT6797,
829 .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND_MT6797
830 }
831};
Mars Chengf1be4c42017-04-08 09:20:31 +0800832
Sean Wang52510ee2017-08-07 15:24:37 +0800833static const struct scp_soc_data mt7622_data = {
834 .domains = scp_domain_data_mt7622,
835 .num_domains = ARRAY_SIZE(scp_domain_data_mt7622),
836 .regs = {
837 .pwr_sta_offs = SPM_PWR_STATUS,
838 .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
839 }
840};
841
Sean Wang53fddb12017-08-07 15:24:35 +0800842static const struct scp_soc_data mt8173_data = {
843 .domains = scp_domain_data_mt8173,
844 .num_domains = ARRAY_SIZE(scp_domain_data_mt8173),
845 .subdomains = scp_subdomain_mt8173,
846 .num_subdomains = ARRAY_SIZE(scp_subdomain_mt8173),
847 .regs = {
848 .pwr_sta_offs = SPM_PWR_STATUS,
849 .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
850 }
851};
Sascha Hauerc84e3582015-06-24 08:17:04 +0200852
James Liao6078c652016-10-20 16:56:35 +0800853/*
854 * scpsys driver init
855 */
856
Sascha Hauerc84e3582015-06-24 08:17:04 +0200857static const struct of_device_id of_scpsys_match_tbl[] = {
858 {
Shunli Wang112ef182016-10-20 16:56:38 +0800859 .compatible = "mediatek,mt2701-scpsys",
Sean Wang53fddb12017-08-07 15:24:35 +0800860 .data = &mt2701_data,
Shunli Wang112ef182016-10-20 16:56:38 +0800861 }, {
Mars Cheng36c310f2017-04-08 09:20:34 +0800862 .compatible = "mediatek,mt6797-scpsys",
Sean Wang53fddb12017-08-07 15:24:35 +0800863 .data = &mt6797_data,
Mars Cheng36c310f2017-04-08 09:20:34 +0800864 }, {
Sean Wang52510ee2017-08-07 15:24:37 +0800865 .compatible = "mediatek,mt7622-scpsys",
866 .data = &mt7622_data,
867 }, {
Sascha Hauerc84e3582015-06-24 08:17:04 +0200868 .compatible = "mediatek,mt8173-scpsys",
Sean Wang53fddb12017-08-07 15:24:35 +0800869 .data = &mt8173_data,
Sascha Hauerc84e3582015-06-24 08:17:04 +0200870 }, {
871 /* sentinel */
872 }
873};
874
James Liao6078c652016-10-20 16:56:35 +0800875static int scpsys_probe(struct platform_device *pdev)
876{
Sean Wang53fddb12017-08-07 15:24:35 +0800877 const struct of_device_id *match;
878 const struct scp_subdomain *sd;
879 const struct scp_soc_data *soc;
880 struct scp *scp;
881 struct genpd_onecell_data *pd_data;
882 int i, ret;
James Liao6078c652016-10-20 16:56:35 +0800883
Sean Wang53fddb12017-08-07 15:24:35 +0800884 match = of_match_device(of_scpsys_match_tbl, &pdev->dev);
885 soc = (const struct scp_soc_data *)match->data;
James Liao6078c652016-10-20 16:56:35 +0800886
Sean Wang53fddb12017-08-07 15:24:35 +0800887 scp = init_scp(pdev, soc->domains, soc->num_domains, &soc->regs);
888 if (IS_ERR(scp))
889 return PTR_ERR(scp);
James Liao6078c652016-10-20 16:56:35 +0800890
Sean Wang53fddb12017-08-07 15:24:35 +0800891 mtk_register_power_domains(pdev, scp, soc->num_domains);
892
893 pd_data = &scp->pd_data;
894
895 for (i = 0, sd = soc->subdomains ; i < soc->num_subdomains ; i++) {
896 ret = pm_genpd_add_subdomain(pd_data->domains[sd->origin],
897 pd_data->domains[sd->subdomain]);
898 if (ret && IS_ENABLED(CONFIG_PM))
899 dev_err(&pdev->dev, "Failed to add subdomain: %d\n",
900 ret);
901 }
902
903 return 0;
James Liao6078c652016-10-20 16:56:35 +0800904}
905
Sascha Hauerc84e3582015-06-24 08:17:04 +0200906static struct platform_driver scpsys_drv = {
Matthias Bruggerbe295232015-12-30 09:30:40 +0100907 .probe = scpsys_probe,
Sascha Hauerc84e3582015-06-24 08:17:04 +0200908 .driver = {
909 .name = "mtk-scpsys",
Matthias Bruggerbe295232015-12-30 09:30:40 +0100910 .suppress_bind_attrs = true,
Sascha Hauerc84e3582015-06-24 08:17:04 +0200911 .owner = THIS_MODULE,
912 .of_match_table = of_match_ptr(of_scpsys_match_tbl),
913 },
914};
Matthias Bruggerbe295232015-12-30 09:30:40 +0100915builtin_platform_driver(scpsys_drv);