]> Git Repo - u-boot.git/blob - drivers/power/domain/mtk-power-domain.c
Restore patch series "arm: dts: am62-beagleplay: Fix Beagleplay Ethernet"
[u-boot.git] / drivers / power / domain / mtk-power-domain.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2018 MediaTek Inc.
4  * Author: Ryder Lee <[email protected]>
5  */
6
7 #include <clk.h>
8 #include <dm.h>
9 #include <malloc.h>
10 #include <power-domain-uclass.h>
11 #include <regmap.h>
12 #include <syscon.h>
13 #include <asm/io.h>
14 #include <asm/processor.h>
15 #include <linux/bitops.h>
16 #include <linux/err.h>
17 #include <linux/iopoll.h>
18
19 #include <dt-bindings/power/mt7623-power.h>
20 #include <dt-bindings/power/mt7629-power.h>
21
22 #define SPM_EN                  (0xb16 << 16 | 0x1)
23 #define SPM_VDE_PWR_CON         0x0210
24 #define SPM_MFG_PWR_CON         0x0214
25 #define SPM_ISP_PWR_CON         0x0238
26 #define SPM_DIS_PWR_CON         0x023c
27 #define SPM_CONN_PWR_CON        0x0280
28 #define SPM_BDP_PWR_CON         0x029c
29 #define SPM_ETH_PWR_CON         0x02a0
30 #define SPM_HIF_PWR_CON         0x02a4
31 #define SPM_IFR_MSC_PWR_CON     0x02a8
32 #define SPM_ETHSYS_PWR_CON      0x2e0
33 #define SPM_HIF0_PWR_CON        0x2e4
34 #define SPM_HIF1_PWR_CON        0x2e8
35 #define SPM_PWR_STATUS          0x60c
36 #define SPM_PWR_STATUS_2ND      0x610
37
38 #define PWR_RST_B_BIT           BIT(0)
39 #define PWR_ISO_BIT             BIT(1)
40 #define PWR_ON_BIT              BIT(2)
41 #define PWR_ON_2ND_BIT          BIT(3)
42 #define PWR_CLK_DIS_BIT         BIT(4)
43
44 #define PWR_STATUS_CONN         BIT(1)
45 #define PWR_STATUS_DISP         BIT(3)
46 #define PWR_STATUS_MFG          BIT(4)
47 #define PWR_STATUS_ISP          BIT(5)
48 #define PWR_STATUS_VDEC         BIT(7)
49 #define PWR_STATUS_BDP          BIT(14)
50 #define PWR_STATUS_ETH          BIT(15)
51 #define PWR_STATUS_HIF          BIT(16)
52 #define PWR_STATUS_IFR_MSC      BIT(17)
53 #define PWR_STATUS_ETHSYS       BIT(24)
54 #define PWR_STATUS_HIF0         BIT(25)
55 #define PWR_STATUS_HIF1         BIT(26)
56
57 /* Infrasys configuration */
58 #define INFRA_TOPDCM_CTRL       0x10
59 #define INFRA_TOPAXI_PROT_EN    0x220
60 #define INFRA_TOPAXI_PROT_STA1  0x228
61
62 #define DCM_TOP_EN              BIT(0)
63
64 enum scp_domain_type {
65         SCPSYS_MT7622,
66         SCPSYS_MT7623,
67         SCPSYS_MT7629,
68 };
69
70 struct scp_domain;
71
72 struct scp_domain_data {
73         struct scp_domain *scpd;
74         u32 sta_mask;
75         int ctl_offs;
76         u32 sram_pdn_bits;
77         u32 sram_pdn_ack_bits;
78         u32 bus_prot_mask;
79 };
80
81 struct scp_domain {
82         void __iomem *base;
83         void __iomem *infracfg;
84         enum scp_domain_type type;
85         struct scp_domain_data *data;
86 };
87
88 static struct scp_domain_data scp_domain_mt7623[] = {
89         [MT7623_POWER_DOMAIN_CONN] = {
90                 .sta_mask = PWR_STATUS_CONN,
91                 .ctl_offs = SPM_CONN_PWR_CON,
92                 .bus_prot_mask = BIT(8) | BIT(2),
93         },
94         [MT7623_POWER_DOMAIN_DISP] = {
95                 .sta_mask = PWR_STATUS_DISP,
96                 .ctl_offs = SPM_DIS_PWR_CON,
97                 .sram_pdn_bits = GENMASK(11, 8),
98                 .bus_prot_mask = BIT(2),
99         },
100         [MT7623_POWER_DOMAIN_MFG] = {
101                 .sta_mask = PWR_STATUS_MFG,
102                 .ctl_offs = SPM_MFG_PWR_CON,
103                 .sram_pdn_bits = GENMASK(11, 8),
104                 .sram_pdn_ack_bits = GENMASK(12, 12),
105         },
106         [MT7623_POWER_DOMAIN_VDEC] = {
107                 .sta_mask = PWR_STATUS_VDEC,
108                 .ctl_offs = SPM_VDE_PWR_CON,
109                 .sram_pdn_bits = GENMASK(11, 8),
110                 .sram_pdn_ack_bits = GENMASK(12, 12),
111         },
112         [MT7623_POWER_DOMAIN_ISP] = {
113                 .sta_mask = PWR_STATUS_ISP,
114                 .ctl_offs = SPM_ISP_PWR_CON,
115                 .sram_pdn_bits = GENMASK(11, 8),
116                 .sram_pdn_ack_bits = GENMASK(13, 12),
117         },
118         [MT7623_POWER_DOMAIN_BDP] = {
119                 .sta_mask = PWR_STATUS_BDP,
120                 .ctl_offs = SPM_BDP_PWR_CON,
121                 .sram_pdn_bits = GENMASK(11, 8),
122         },
123         [MT7623_POWER_DOMAIN_ETH] = {
124                 .sta_mask = PWR_STATUS_ETH,
125                 .ctl_offs = SPM_ETH_PWR_CON,
126                 .sram_pdn_bits = GENMASK(11, 8),
127                 .sram_pdn_ack_bits = GENMASK(15, 12),
128         },
129         [MT7623_POWER_DOMAIN_HIF] = {
130                 .sta_mask = PWR_STATUS_HIF,
131                 .ctl_offs = SPM_HIF_PWR_CON,
132                 .sram_pdn_bits = GENMASK(11, 8),
133                 .sram_pdn_ack_bits = GENMASK(15, 12),
134         },
135         [MT7623_POWER_DOMAIN_IFR_MSC] = {
136                 .sta_mask = PWR_STATUS_IFR_MSC,
137                 .ctl_offs = SPM_IFR_MSC_PWR_CON,
138         },
139 };
140
141 static struct scp_domain_data scp_domain_mt7629[] = {
142         [MT7629_POWER_DOMAIN_ETHSYS] = {
143                 .sta_mask = PWR_STATUS_ETHSYS,
144                 .ctl_offs = SPM_ETHSYS_PWR_CON,
145                 .sram_pdn_bits = GENMASK(11, 8),
146                 .sram_pdn_ack_bits = GENMASK(15, 12),
147                 .bus_prot_mask = (BIT(3) | BIT(17)),
148         },
149         [MT7629_POWER_DOMAIN_HIF0] = {
150                 .sta_mask = PWR_STATUS_HIF0,
151                 .ctl_offs = SPM_HIF0_PWR_CON,
152                 .sram_pdn_bits = GENMASK(11, 8),
153                 .sram_pdn_ack_bits = GENMASK(15, 12),
154                 .bus_prot_mask = GENMASK(25, 24),
155         },
156         [MT7629_POWER_DOMAIN_HIF1] = {
157                 .sta_mask = PWR_STATUS_HIF1,
158                 .ctl_offs = SPM_HIF1_PWR_CON,
159                 .sram_pdn_bits = GENMASK(11, 8),
160                 .sram_pdn_ack_bits = GENMASK(15, 12),
161                 .bus_prot_mask = GENMASK(28, 26),
162         },
163 };
164
165 /**
166  * This function enables the bus protection bits for disabled power
167  * domains so that the system does not hang when some unit accesses the
168  * bus while in power down.
169  */
170 static int mtk_infracfg_set_bus_protection(void __iomem *infracfg,
171                                            u32 mask)
172 {
173         u32 val;
174
175         clrsetbits_le32(infracfg + INFRA_TOPAXI_PROT_EN, mask, mask);
176
177         return readl_poll_timeout(infracfg + INFRA_TOPAXI_PROT_STA1, val,
178                                   (val & mask) == mask, 100);
179 }
180
181 static int mtk_infracfg_clear_bus_protection(void __iomem *infracfg,
182                                              u32 mask)
183 {
184         u32 val;
185
186         clrbits_le32(infracfg + INFRA_TOPAXI_PROT_EN, mask);
187
188         return readl_poll_timeout(infracfg + INFRA_TOPAXI_PROT_STA1, val,
189                                   !(val & mask), 100);
190 }
191
192 static int scpsys_domain_is_on(struct scp_domain_data *data)
193 {
194         struct scp_domain *scpd = data->scpd;
195         u32 sta = readl(scpd->base + SPM_PWR_STATUS) &
196                         data->sta_mask;
197         u32 sta2 = readl(scpd->base + SPM_PWR_STATUS_2ND) &
198                          data->sta_mask;
199
200         /*
201          * A domain is on when both status bits are set. If only one is set
202          * return an error. This happens while powering up a domain
203          */
204         if (sta && sta2)
205                 return true;
206         if (!sta && !sta2)
207                 return false;
208
209         return -EINVAL;
210 }
211
212 static int scpsys_power_on(struct power_domain *power_domain)
213 {
214         struct scp_domain *scpd = dev_get_priv(power_domain->dev);
215         struct scp_domain_data *data = &scpd->data[power_domain->id];
216         void __iomem *ctl_addr = scpd->base + data->ctl_offs;
217         u32 pdn_ack = data->sram_pdn_ack_bits;
218         u32 val;
219         int ret, tmp;
220
221         writel(SPM_EN, scpd->base);
222
223         val = readl(ctl_addr);
224         val |= PWR_ON_BIT;
225         writel(val, ctl_addr);
226
227         val |= PWR_ON_2ND_BIT;
228         writel(val, ctl_addr);
229
230         ret = readx_poll_timeout(scpsys_domain_is_on, data, tmp, tmp > 0,
231                                  100);
232         if (ret < 0)
233                 return ret;
234
235         val &= ~PWR_CLK_DIS_BIT;
236         writel(val, ctl_addr);
237
238         val &= ~PWR_ISO_BIT;
239         writel(val, ctl_addr);
240
241         val |= PWR_RST_B_BIT;
242         writel(val, ctl_addr);
243
244         val &= ~data->sram_pdn_bits;
245         writel(val, ctl_addr);
246
247         ret = readl_poll_timeout(ctl_addr, tmp, !(tmp & pdn_ack), 100);
248         if (ret < 0)
249                 return ret;
250
251         if (data->bus_prot_mask) {
252                 ret = mtk_infracfg_clear_bus_protection(scpd->infracfg,
253                                                         data->bus_prot_mask);
254                 if (ret)
255                         return ret;
256         }
257
258         return 0;
259 }
260
261 static int scpsys_power_off(struct power_domain *power_domain)
262 {
263         struct scp_domain *scpd = dev_get_priv(power_domain->dev);
264         struct scp_domain_data *data = &scpd->data[power_domain->id];
265         void __iomem *ctl_addr = scpd->base + data->ctl_offs;
266         u32 pdn_ack = data->sram_pdn_ack_bits;
267         u32 val;
268         int ret, tmp;
269
270         if (data->bus_prot_mask) {
271                 ret = mtk_infracfg_set_bus_protection(scpd->infracfg,
272                                                       data->bus_prot_mask);
273                 if (ret)
274                         return ret;
275         }
276
277         val = readl(ctl_addr);
278         val |= data->sram_pdn_bits;
279         writel(val, ctl_addr);
280
281         ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == pdn_ack,
282                                  100);
283         if (ret < 0)
284                 return ret;
285
286         val |= PWR_ISO_BIT;
287         writel(val, ctl_addr);
288
289         val &= ~PWR_RST_B_BIT;
290         writel(val, ctl_addr);
291
292         val |= PWR_CLK_DIS_BIT;
293         writel(val, ctl_addr);
294
295         val &= ~PWR_ON_BIT;
296         writel(val, ctl_addr);
297
298         val &= ~PWR_ON_2ND_BIT;
299         writel(val, ctl_addr);
300
301         ret = readx_poll_timeout(scpsys_domain_is_on, data, tmp, !tmp, 100);
302         if (ret < 0)
303                 return ret;
304
305         return 0;
306 }
307
308 static int scpsys_power_request(struct power_domain *power_domain)
309 {
310         struct scp_domain *scpd = dev_get_priv(power_domain->dev);
311         struct scp_domain_data *data;
312
313         data = &scpd->data[power_domain->id];
314         data->scpd = scpd;
315
316         return 0;
317 }
318
319 static int mtk_power_domain_hook(struct udevice *dev)
320 {
321         struct scp_domain *scpd = dev_get_priv(dev);
322
323         scpd->type = (enum scp_domain_type)dev_get_driver_data(dev);
324
325         switch (scpd->type) {
326         case SCPSYS_MT7623:
327                 scpd->data = scp_domain_mt7623;
328                 break;
329         case SCPSYS_MT7622:
330         case SCPSYS_MT7629:
331                 scpd->data = scp_domain_mt7629;
332                 break;
333         default:
334                 return -EINVAL;
335         }
336
337         return 0;
338 }
339
340 static int mtk_power_domain_probe(struct udevice *dev)
341 {
342         struct ofnode_phandle_args args;
343         struct scp_domain *scpd = dev_get_priv(dev);
344         struct regmap *regmap;
345         struct clk_bulk bulk;
346         int err;
347
348         scpd->base = dev_read_addr_ptr(dev);
349         if (!scpd->base)
350                 return -ENOENT;
351
352         err = mtk_power_domain_hook(dev);
353         if (err)
354                 return err;
355
356         /* get corresponding syscon phandle */
357         err = dev_read_phandle_with_args(dev, "infracfg", NULL, 0, 0, &args);
358         if (err)
359                 return err;
360
361         regmap = syscon_node_to_regmap(args.node);
362         if (IS_ERR(regmap))
363                 return PTR_ERR(regmap);
364
365         scpd->infracfg = regmap_get_range(regmap, 0);
366         if (!scpd->infracfg)
367                 return -ENOENT;
368
369         /* enable Infra DCM */
370         setbits_le32(scpd->infracfg + INFRA_TOPDCM_CTRL, DCM_TOP_EN);
371
372         err = clk_get_bulk(dev, &bulk);
373         if (err)
374                 return err;
375
376         return clk_enable_bulk(&bulk);
377 }
378
379 static const struct udevice_id mtk_power_domain_ids[] = {
380         {
381                 .compatible = "mediatek,mt7622-scpsys",
382                 .data = SCPSYS_MT7622,
383         },
384         {
385                 .compatible = "mediatek,mt7623-scpsys",
386                 .data = SCPSYS_MT7623,
387         },
388         {
389                 .compatible = "mediatek,mt7629-scpsys",
390                 .data = SCPSYS_MT7629,
391         },
392         { /* sentinel */ }
393 };
394
395 struct power_domain_ops mtk_power_domain_ops = {
396         .off = scpsys_power_off,
397         .on = scpsys_power_on,
398         .request = scpsys_power_request,
399 };
400
401 U_BOOT_DRIVER(mtk_power_domain) = {
402         .name = "mtk_power_domain",
403         .id = UCLASS_POWER_DOMAIN,
404         .ops = &mtk_power_domain_ops,
405         .probe = mtk_power_domain_probe,
406         .of_match = mtk_power_domain_ids,
407         .priv_auto      = sizeof(struct scp_domain),
408 };
This page took 0.048289 seconds and 4 git commands to generate.