blob: b44aae78e6de9733e1e53bbec80f54562487a76b [file] [log] [blame]
Patrick Wildt8bd56562019-10-03 15:51:50 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2017 NXP
4 */
5
Marek Vasute5481a82022-04-13 00:42:51 +02006#include <clk.h>
Patrick Wildt8bd56562019-10-03 15:51:50 +02007#include <dm.h>
Simon Glass9bc15642020-02-03 07:36:16 -07008#include <malloc.h>
Patrick Wildt8bd56562019-10-03 15:51:50 +02009#include <power-domain-uclass.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060010#include <asm/global_data.h>
Patrick Wildt8bd56562019-10-03 15:51:50 +020011#include <asm/io.h>
Patrick Wildt8bd56562019-10-03 15:51:50 +020012#include <asm/mach-imx/sys_proto.h>
13#include <dm/device-internal.h>
14#include <dm/device.h>
Marek Vasute5481a82022-04-13 00:42:51 +020015#include <dm/device_compat.h>
Patrick Wildt8bd56562019-10-03 15:51:50 +020016#include <imx_sip.h>
Marek Vasute5481a82022-04-13 00:42:51 +020017#include <linux/bitmap.h>
18#include <wait_bit.h>
19
20#include <dt-bindings/power/imx8mm-power.h>
21#include <dt-bindings/power/imx8mn-power.h>
Marek Vasut2e1405e2022-04-13 00:42:53 +020022#include <dt-bindings/power/imx8mp-power.h>
Marek Vasute5481a82022-04-13 00:42:51 +020023#include <dt-bindings/power/imx8mq-power.h>
Patrick Wildt8bd56562019-10-03 15:51:50 +020024
25DECLARE_GLOBAL_DATA_PTR;
26
Marek Vasute5481a82022-04-13 00:42:51 +020027#define GPC_PGC_CPU_MAPPING 0x0ec
Marek Vasut2e1405e2022-04-13 00:42:53 +020028#define IMX8MP_GPC_PGC_CPU_MAPPING 0x1cc
Marek Vasute5481a82022-04-13 00:42:51 +020029
30#define IMX8M_PCIE2_A53_DOMAIN BIT(15)
31#define IMX8M_OTG2_A53_DOMAIN BIT(5)
32#define IMX8M_OTG1_A53_DOMAIN BIT(4)
33#define IMX8M_PCIE1_A53_DOMAIN BIT(3)
34
35#define IMX8MM_OTG2_A53_DOMAIN BIT(5)
36#define IMX8MM_OTG1_A53_DOMAIN BIT(4)
37#define IMX8MM_PCIE_A53_DOMAIN BIT(3)
38
39#define IMX8MN_OTG1_A53_DOMAIN BIT(4)
40#define IMX8MN_MIPI_A53_DOMAIN BIT(2)
41
Marek Vasut2e1405e2022-04-13 00:42:53 +020042#define IMX8MP_HSIOMIX_A53_DOMAIN BIT(19)
Miquel Raynal72f27972025-04-03 09:39:08 +020043#define IMX8MP_MEDIAMIX_A53_DOMAIN BIT(12)
Marek Vasut2e1405e2022-04-13 00:42:53 +020044#define IMX8MP_USB2_PHY_A53_DOMAIN BIT(5)
45#define IMX8MP_USB1_PHY_A53_DOMAIN BIT(4)
46#define IMX8MP_PCIE_PHY_A53_DOMAIN BIT(3)
47
48#define IMX8MP_GPC_PU_PGC_SW_PUP_REQ 0x0d8
49#define IMX8MP_GPC_PU_PGC_SW_PDN_REQ 0x0e4
50
Marek Vasute5481a82022-04-13 00:42:51 +020051#define GPC_PU_PGC_SW_PUP_REQ 0x0f8
52#define GPC_PU_PGC_SW_PDN_REQ 0x104
53
54#define IMX8M_PCIE2_SW_Pxx_REQ BIT(13)
55#define IMX8M_OTG2_SW_Pxx_REQ BIT(3)
56#define IMX8M_OTG1_SW_Pxx_REQ BIT(2)
57#define IMX8M_PCIE1_SW_Pxx_REQ BIT(1)
58
59#define IMX8MM_OTG2_SW_Pxx_REQ BIT(3)
60#define IMX8MM_OTG1_SW_Pxx_REQ BIT(2)
61#define IMX8MM_PCIE_SW_Pxx_REQ BIT(1)
62
63#define IMX8MN_OTG1_SW_Pxx_REQ BIT(2)
64#define IMX8MN_MIPI_SW_Pxx_REQ BIT(0)
65
Marek Vasut2e1405e2022-04-13 00:42:53 +020066#define IMX8MP_HSIOMIX_Pxx_REQ BIT(17)
Miquel Raynal72f27972025-04-03 09:39:08 +020067#define IMX8MP_MEDIAMIX_Pxx_REQ BIT(10)
Marek Vasut2e1405e2022-04-13 00:42:53 +020068#define IMX8MP_USB2_PHY_Pxx_REQ BIT(3)
69#define IMX8MP_USB1_PHY_Pxx_REQ BIT(2)
70#define IMX8MP_PCIE_PHY_SW_Pxx_REQ BIT(1)
71
Marek Vasute5481a82022-04-13 00:42:51 +020072#define GPC_M4_PU_PDN_FLG 0x1bc
73
Marek Vasut2e1405e2022-04-13 00:42:53 +020074#define IMX8MP_GPC_PU_PWRHSK 0x190
Marek Vasute5481a82022-04-13 00:42:51 +020075#define GPC_PU_PWRHSK 0x1fc
76
77#define IMX8MM_HSIO_HSK_PWRDNACKN (BIT(23) | BIT(24))
78#define IMX8MM_HSIO_HSK_PWRDNREQN (BIT(5) | BIT(6))
79
80#define IMX8MN_HSIO_HSK_PWRDNACKN BIT(23)
81#define IMX8MN_HSIO_HSK_PWRDNREQN BIT(5)
82
Marek Vasut2e1405e2022-04-13 00:42:53 +020083#define IMX8MP_HSIOMIX_PWRDNACKN BIT(28)
84#define IMX8MP_HSIOMIX_PWRDNREQN BIT(12)
85
Miquel Raynal72f27972025-04-03 09:39:08 +020086#define IMX8MP_MEDIAMIX_PWRDNACKN BIT(30)
87#define IMX8MP_MEDIAMIX_PWRDNREQN BIT(14)
88
Marek Vasute5481a82022-04-13 00:42:51 +020089/*
90 * The PGC offset values in Reference Manual
91 * (Rev. 1, 01/2018 and the older ones) GPC chapter's
92 * GPC_PGC memory map are incorrect, below offset
93 * values are from design RTL.
94 */
95#define IMX8M_PGC_PCIE1 17
96#define IMX8M_PGC_OTG1 18
97#define IMX8M_PGC_OTG2 19
98#define IMX8M_PGC_PCIE2 29
99
100#define IMX8MM_PGC_PCIE 17
101#define IMX8MM_PGC_OTG1 18
102#define IMX8MM_PGC_OTG2 19
103
104#define IMX8MN_PGC_OTG1 18
105
Marek Vasut2e1405e2022-04-13 00:42:53 +0200106#define IMX8MP_PGC_PCIE 13
107#define IMX8MP_PGC_USB1 14
108#define IMX8MP_PGC_USB2 15
Miquel Raynal72f27972025-04-03 09:39:08 +0200109#define IMX8MP_PGC_MEDIAMIX 22
Marek Vasut2e1405e2022-04-13 00:42:53 +0200110#define IMX8MP_PGC_HSIOMIX 29
111
Marek Vasute5481a82022-04-13 00:42:51 +0200112#define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40)
113#define GPC_PGC_SR(n) (GPC_PGC_CTRL(n) + 0xc)
114
115#define GPC_PGC_CTRL_PCR BIT(0)
116
117struct imx_pgc_regs {
118 u16 map;
119 u16 pup;
120 u16 pdn;
121 u16 hsk;
122};
123
124struct imx_pgc_domain {
125 unsigned long pgc;
126
127 const struct {
128 u32 pxx;
129 u32 map;
130 u32 hskreq;
131 u32 hskack;
132 } bits;
133
134 const bool keep_clocks;
135};
136
137struct imx_pgc_domain_data {
138 const struct imx_pgc_domain *domains;
139 size_t domains_num;
140 const struct imx_pgc_regs *pgc_regs;
141};
142
Marek Vasut93d1d8b2022-04-13 00:42:50 +0200143struct imx8m_power_domain_plat {
Marek Vasute5481a82022-04-13 00:42:51 +0200144 struct power_domain pd;
145 const struct imx_pgc_domain *domain;
146 const struct imx_pgc_regs *regs;
147 struct clk_bulk clk;
148 void __iomem *base;
Marek Vasut93d1d8b2022-04-13 00:42:50 +0200149 int resource_id;
150 int has_pd;
Marek Vasute5481a82022-04-13 00:42:51 +0200151};
152
153#if defined(CONFIG_IMX8MM) || defined(CONFIG_IMX8MN) || defined(CONFIG_IMX8MQ)
154static const struct imx_pgc_regs imx7_pgc_regs = {
155 .map = GPC_PGC_CPU_MAPPING,
156 .pup = GPC_PU_PGC_SW_PUP_REQ,
157 .pdn = GPC_PU_PGC_SW_PDN_REQ,
158 .hsk = GPC_PU_PWRHSK,
159};
160#endif
161
162#ifdef CONFIG_IMX8MQ
163static const struct imx_pgc_domain imx8m_pgc_domains[] = {
164 [IMX8M_POWER_DOMAIN_PCIE1] = {
165 .bits = {
166 .pxx = IMX8M_PCIE1_SW_Pxx_REQ,
167 .map = IMX8M_PCIE1_A53_DOMAIN,
168 },
169 .pgc = BIT(IMX8M_PGC_PCIE1),
170 },
171
172 [IMX8M_POWER_DOMAIN_USB_OTG1] = {
173 .bits = {
174 .pxx = IMX8M_OTG1_SW_Pxx_REQ,
175 .map = IMX8M_OTG1_A53_DOMAIN,
176 },
177 .pgc = BIT(IMX8M_PGC_OTG1),
178 },
179
180 [IMX8M_POWER_DOMAIN_USB_OTG2] = {
181 .bits = {
182 .pxx = IMX8M_OTG2_SW_Pxx_REQ,
183 .map = IMX8M_OTG2_A53_DOMAIN,
184 },
185 .pgc = BIT(IMX8M_PGC_OTG2),
186 },
187
188 [IMX8M_POWER_DOMAIN_PCIE2] = {
189 .bits = {
190 .pxx = IMX8M_PCIE2_SW_Pxx_REQ,
191 .map = IMX8M_PCIE2_A53_DOMAIN,
192 },
193 .pgc = BIT(IMX8M_PGC_PCIE2),
194 },
195};
196
197static const struct imx_pgc_domain_data imx8m_pgc_domain_data = {
198 .domains = imx8m_pgc_domains,
199 .domains_num = ARRAY_SIZE(imx8m_pgc_domains),
200 .pgc_regs = &imx7_pgc_regs,
201};
202#endif
203
204#ifdef CONFIG_IMX8MM
205static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
206 [IMX8MM_POWER_DOMAIN_HSIOMIX] = {
207 .bits = {
208 .pxx = 0, /* no power sequence control */
209 .map = 0, /* no power sequence control */
210 .hskreq = IMX8MM_HSIO_HSK_PWRDNREQN,
211 .hskack = IMX8MM_HSIO_HSK_PWRDNACKN,
212 },
213 .keep_clocks = true,
214 },
215
216 [IMX8MM_POWER_DOMAIN_PCIE] = {
217 .bits = {
218 .pxx = IMX8MM_PCIE_SW_Pxx_REQ,
219 .map = IMX8MM_PCIE_A53_DOMAIN,
220 },
221 .pgc = BIT(IMX8MM_PGC_PCIE),
222 },
223
224 [IMX8MM_POWER_DOMAIN_OTG1] = {
225 .bits = {
226 .pxx = IMX8MM_OTG1_SW_Pxx_REQ,
227 .map = IMX8MM_OTG1_A53_DOMAIN,
228 },
229 .pgc = BIT(IMX8MM_PGC_OTG1),
230 },
231
232 [IMX8MM_POWER_DOMAIN_OTG2] = {
233 .bits = {
234 .pxx = IMX8MM_OTG2_SW_Pxx_REQ,
235 .map = IMX8MM_OTG2_A53_DOMAIN,
236 },
237 .pgc = BIT(IMX8MM_PGC_OTG2),
238 },
Marek Vasut93d1d8b2022-04-13 00:42:50 +0200239};
240
Marek Vasute5481a82022-04-13 00:42:51 +0200241static const struct imx_pgc_domain_data imx8mm_pgc_domain_data = {
242 .domains = imx8mm_pgc_domains,
243 .domains_num = ARRAY_SIZE(imx8mm_pgc_domains),
244 .pgc_regs = &imx7_pgc_regs,
245};
246#endif
247
248#ifdef CONFIG_IMX8MN
249static const struct imx_pgc_domain imx8mn_pgc_domains[] = {
250 [IMX8MN_POWER_DOMAIN_HSIOMIX] = {
251 .bits = {
252 .pxx = 0, /* no power sequence control */
253 .map = 0, /* no power sequence control */
254 .hskreq = IMX8MN_HSIO_HSK_PWRDNREQN,
255 .hskack = IMX8MN_HSIO_HSK_PWRDNACKN,
256 },
257 .keep_clocks = true,
258 },
259
260 [IMX8MN_POWER_DOMAIN_OTG1] = {
261 .bits = {
262 .pxx = IMX8MN_OTG1_SW_Pxx_REQ,
263 .map = IMX8MN_OTG1_A53_DOMAIN,
264 },
265 .pgc = BIT(IMX8MN_PGC_OTG1),
266 },
267};
268
269static const struct imx_pgc_domain_data imx8mn_pgc_domain_data = {
270 .domains = imx8mn_pgc_domains,
271 .domains_num = ARRAY_SIZE(imx8mn_pgc_domains),
272 .pgc_regs = &imx7_pgc_regs,
273};
274#endif
275
Marek Vasut2e1405e2022-04-13 00:42:53 +0200276#ifdef CONFIG_IMX8MP
277static const struct imx_pgc_domain imx8mp_pgc_domains[] = {
278 [IMX8MP_POWER_DOMAIN_PCIE_PHY] = {
279 .bits = {
280 .pxx = IMX8MP_PCIE_PHY_SW_Pxx_REQ,
281 .map = IMX8MP_PCIE_PHY_A53_DOMAIN,
282 },
283 .pgc = BIT(IMX8MP_PGC_PCIE),
284 },
285
286 [IMX8MP_POWER_DOMAIN_USB1_PHY] = {
287 .bits = {
288 .pxx = IMX8MP_USB1_PHY_Pxx_REQ,
289 .map = IMX8MP_USB1_PHY_A53_DOMAIN,
290 },
291 .pgc = BIT(IMX8MP_PGC_USB1),
292 },
293
294 [IMX8MP_POWER_DOMAIN_USB2_PHY] = {
295 .bits = {
296 .pxx = IMX8MP_USB2_PHY_Pxx_REQ,
297 .map = IMX8MP_USB2_PHY_A53_DOMAIN,
298 },
299 .pgc = BIT(IMX8MP_PGC_USB2),
300 },
301
302 [IMX8MP_POWER_DOMAIN_HSIOMIX] = {
303 .bits = {
304 .pxx = IMX8MP_HSIOMIX_Pxx_REQ,
305 .map = IMX8MP_HSIOMIX_A53_DOMAIN,
306 .hskreq = IMX8MP_HSIOMIX_PWRDNREQN,
307 .hskack = IMX8MP_HSIOMIX_PWRDNACKN,
308 },
309 .pgc = BIT(IMX8MP_PGC_HSIOMIX),
310 .keep_clocks = true,
311 },
Miquel Raynal72f27972025-04-03 09:39:08 +0200312
313 [IMX8MP_POWER_DOMAIN_MEDIAMIX] = {
314 .bits = {
315 .pxx = IMX8MP_MEDIAMIX_Pxx_REQ,
316 .map = IMX8MP_MEDIAMIX_A53_DOMAIN,
317 .hskreq = IMX8MP_MEDIAMIX_PWRDNREQN,
318 .hskack = IMX8MP_MEDIAMIX_PWRDNACKN,
319 },
320 .pgc = BIT(IMX8MP_PGC_MEDIAMIX),
321 .keep_clocks = true,
322 },
Marek Vasut2e1405e2022-04-13 00:42:53 +0200323};
324
325static const struct imx_pgc_regs imx8mp_pgc_regs = {
326 .map = IMX8MP_GPC_PGC_CPU_MAPPING,
327 .pup = IMX8MP_GPC_PU_PGC_SW_PUP_REQ,
328 .pdn = IMX8MP_GPC_PU_PGC_SW_PDN_REQ,
329 .hsk = IMX8MP_GPC_PU_PWRHSK,
330};
331
332static const struct imx_pgc_domain_data imx8mp_pgc_domain_data = {
333 .domains = imx8mp_pgc_domains,
334 .domains_num = ARRAY_SIZE(imx8mp_pgc_domains),
335 .pgc_regs = &imx8mp_pgc_regs,
336};
337#endif
338
Patrick Wildt8bd56562019-10-03 15:51:50 +0200339static int imx8m_power_domain_on(struct power_domain *power_domain)
340{
341 struct udevice *dev = power_domain->dev;
Marek Vasute5481a82022-04-13 00:42:51 +0200342 struct imx8m_power_domain_plat *pdata = dev_get_plat(dev);
343 const struct imx_pgc_domain *domain = pdata->domain;
344 const struct imx_pgc_regs *regs = pdata->regs;
345 void __iomem *base = pdata->base;
346 u32 pgc;
347 int ret;
Peng Fanaae33562020-05-11 15:16:37 +0800348
Marek Vasute5481a82022-04-13 00:42:51 +0200349 if (pdata->clk.count) {
350 ret = clk_enable_bulk(&pdata->clk);
351 if (ret) {
352 dev_err(dev, "failed to enable reset clocks\n");
353 return ret;
354 }
355 }
Patrick Wildt8bd56562019-10-03 15:51:50 +0200356
Fabio Estevam24d8f572023-05-06 13:14:02 -0300357 /* delay for reset to propagate */
358 udelay(5);
359
Marek Vasute5481a82022-04-13 00:42:51 +0200360 if (domain->bits.pxx) {
361 /* request the domain to power up */
362 setbits_le32(base + regs->pup, domain->bits.pxx);
Patrick Wildt8bd56562019-10-03 15:51:50 +0200363
Marek Vasute5481a82022-04-13 00:42:51 +0200364 /*
365 * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
366 * for PUP_REQ/PDN_REQ bit to be cleared
367 */
368 ret = wait_for_bit_le32(base + regs->pup, domain->bits.pxx,
369 false, 1000, false);
370 if (ret) {
371 dev_err(dev, "failed to command PGC\n");
372 goto out_clk_disable;
373 }
374
375 /* disable power control */
376 for_each_set_bit(pgc, &domain->pgc, 32) {
377 clrbits_le32(base + GPC_PGC_CTRL(pgc),
378 GPC_PGC_CTRL_PCR);
379 }
380 }
381
382 /* delay for reset to propagate */
383 udelay(5);
Patrick Wildt8bd56562019-10-03 15:51:50 +0200384
Marek Vasute5481a82022-04-13 00:42:51 +0200385 /* request the ADB400 to power up */
386 if (domain->bits.hskreq)
387 setbits_le32(base + regs->hsk, domain->bits.hskreq);
388
389 /* Disable reset clocks for all devices in the domain */
390 if (!domain->keep_clocks && pdata->clk.count)
391 clk_disable_bulk(&pdata->clk);
Patrick Wildt8bd56562019-10-03 15:51:50 +0200392
393 return 0;
Marek Vasute5481a82022-04-13 00:42:51 +0200394
395out_clk_disable:
396 if (pdata->clk.count)
397 clk_disable_bulk(&pdata->clk);
398 return ret;
Patrick Wildt8bd56562019-10-03 15:51:50 +0200399}
400
401static int imx8m_power_domain_off(struct power_domain *power_domain)
402{
403 struct udevice *dev = power_domain->dev;
Marek Vasute5481a82022-04-13 00:42:51 +0200404 struct imx8m_power_domain_plat *pdata = dev_get_plat(dev);
405 const struct imx_pgc_domain *domain = pdata->domain;
406 const struct imx_pgc_regs *regs = pdata->regs;
407 void __iomem *base = pdata->base;
408 u32 pgc;
409 int ret;
410
411 /* Enable reset clocks for all devices in the domain */
412 if (!domain->keep_clocks && pdata->clk.count) {
413 ret = clk_enable_bulk(&pdata->clk);
414 if (ret)
415 return ret;
416 }
417
418 /* request the ADB400 to power down */
419 if (domain->bits.hskreq) {
420 clrbits_le32(base + regs->hsk, domain->bits.hskreq);
421
422 ret = wait_for_bit_le32(base + regs->hsk, domain->bits.hskack,
423 false, 1000, false);
424 if (ret) {
425 dev_err(dev, "failed to power down ADB400\n");
426 goto out_clk_disable;
427 }
428 }
Patrick Wildt8bd56562019-10-03 15:51:50 +0200429
Marek Vasute5481a82022-04-13 00:42:51 +0200430 if (domain->bits.pxx) {
431 /* enable power control */
432 for_each_set_bit(pgc, &domain->pgc, 32) {
433 setbits_le32(base + GPC_PGC_CTRL(pgc),
434 GPC_PGC_CTRL_PCR);
435 }
Patrick Wildt8bd56562019-10-03 15:51:50 +0200436
Marek Vasute5481a82022-04-13 00:42:51 +0200437 /* request the domain to power down */
438 setbits_le32(base + regs->pdn, domain->bits.pxx);
439
440 /*
441 * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
442 * for PUP_REQ/PDN_REQ bit to be cleared
443 */
444 ret = wait_for_bit_le32(base + regs->pdn, domain->bits.pxx,
445 false, 1000, false);
446 if (ret) {
447 dev_err(dev, "failed to command PGC\n");
448 goto out_clk_disable;
449 }
450 }
451
452 /* Disable reset clocks for all devices in the domain */
453 if (pdata->clk.count)
454 clk_disable_bulk(&pdata->clk);
Patrick Wildt8bd56562019-10-03 15:51:50 +0200455
456 if (pdata->has_pd)
457 power_domain_off(&pdata->pd);
458
459 return 0;
Marek Vasute5481a82022-04-13 00:42:51 +0200460
461out_clk_disable:
462 if (!domain->keep_clocks && pdata->clk.count)
463 clk_disable_bulk(&pdata->clk);
464
465 return ret;
Patrick Wildt8bd56562019-10-03 15:51:50 +0200466}
467
468static int imx8m_power_domain_of_xlate(struct power_domain *power_domain,
469 struct ofnode_phandle_args *args)
470{
471 return 0;
472}
473
474static int imx8m_power_domain_bind(struct udevice *dev)
475{
Tim Harvey87f43032024-10-23 13:28:53 -0700476 ofnode subnode;
Patrick Wildt8bd56562019-10-03 15:51:50 +0200477 const char *name;
478 int ret = 0;
479
Tim Harvey87f43032024-10-23 13:28:53 -0700480 ofnode_for_each_subnode(subnode, dev_ofnode(dev)) {
Patrick Wildt8bd56562019-10-03 15:51:50 +0200481 /* Bind the subnode to this driver */
Tim Harvey87f43032024-10-23 13:28:53 -0700482 name = ofnode_get_name(subnode);
Patrick Wildt8bd56562019-10-03 15:51:50 +0200483
Marek Vasut78fb0072022-04-13 00:42:49 +0200484 /* Descend into 'pgc' subnode */
485 if (!strstr(name, "power-domain")) {
Tim Harvey87f43032024-10-23 13:28:53 -0700486 subnode = ofnode_first_subnode(subnode);
487 name = ofnode_get_name(subnode);
Marek Vasut78fb0072022-04-13 00:42:49 +0200488 }
Patrick Wildt8bd56562019-10-03 15:51:50 +0200489 ret = device_bind_with_driver_data(dev, dev->driver, name,
490 dev->driver_data,
Tim Harvey87f43032024-10-23 13:28:53 -0700491 subnode,
Patrick Wildt8bd56562019-10-03 15:51:50 +0200492 NULL);
493
494 if (ret == -ENODEV)
495 printf("Driver '%s' refuses to bind\n",
496 dev->driver->name);
497
498 if (ret)
499 printf("Error binding driver '%s': %d\n",
500 dev->driver->name, ret);
501 }
502
Patrick Wildt8bd56562019-10-03 15:51:50 +0200503 return 0;
504}
505
Marek Vasute5481a82022-04-13 00:42:51 +0200506static int imx8m_power_domain_probe(struct udevice *dev)
507{
508 struct imx8m_power_domain_plat *pdata = dev_get_plat(dev);
Miquel Raynal887da2b2025-04-25 08:49:33 +0200509 struct power_domain_plat *plat = dev_get_uclass_plat(dev);
Marek Vasute5481a82022-04-13 00:42:51 +0200510 int ret;
511
Miquel Raynal887da2b2025-04-25 08:49:33 +0200512 /* Every subdomain has its own device node */
513 plat->subdomains = 1;
514
Marek Vasute5481a82022-04-13 00:42:51 +0200515 /* Nothing to do for non-"power-domain" driver instances. */
516 if (!strstr(dev->name, "power-domain"))
517 return 0;
518
519 /* Grab optional power domain clock. */
520 ret = clk_get_bulk(dev, &pdata->clk);
521 if (ret && ret != -ENOENT) {
522 dev_err(dev, "Failed to get domain clock (%d)\n", ret);
523 return ret;
524 }
525
526 return 0;
527}
528
Simon Glassaad29ae2020-12-03 16:55:21 -0700529static int imx8m_power_domain_of_to_plat(struct udevice *dev)
Patrick Wildt8bd56562019-10-03 15:51:50 +0200530{
Simon Glassb75b15b2020-12-03 16:55:23 -0700531 struct imx8m_power_domain_plat *pdata = dev_get_plat(dev);
Marek Vasute5481a82022-04-13 00:42:51 +0200532 struct imx_pgc_domain_data *domain_data =
533 (struct imx_pgc_domain_data *)dev_get_driver_data(dev);
Patrick Wildt8bd56562019-10-03 15:51:50 +0200534
Tim Harvey87f43032024-10-23 13:28:53 -0700535 pdata->resource_id = ofnode_read_u32_default(dev_ofnode(dev), "reg", -1);
Marek Vasute5481a82022-04-13 00:42:51 +0200536 pdata->domain = &domain_data->domains[pdata->resource_id];
537 pdata->regs = domain_data->pgc_regs;
538 pdata->base = dev_read_addr_ptr(dev->parent);
Patrick Wildt8bd56562019-10-03 15:51:50 +0200539
540 if (!power_domain_get(dev, &pdata->pd))
541 pdata->has_pd = 1;
542
543 return 0;
544}
545
546static const struct udevice_id imx8m_power_domain_ids[] = {
Marek Vasute5481a82022-04-13 00:42:51 +0200547#ifdef CONFIG_IMX8MQ
548 { .compatible = "fsl,imx8mq-gpc", .data = (long)&imx8m_pgc_domain_data },
549#endif
550#ifdef CONFIG_IMX8MM
551 { .compatible = "fsl,imx8mm-gpc", .data = (long)&imx8mm_pgc_domain_data },
552#endif
553#ifdef CONFIG_IMX8MN
554 { .compatible = "fsl,imx8mn-gpc", .data = (long)&imx8mn_pgc_domain_data },
555#endif
Marek Vasut2e1405e2022-04-13 00:42:53 +0200556#ifdef CONFIG_IMX8MP
557 { .compatible = "fsl,imx8mp-gpc", .data = (long)&imx8mp_pgc_domain_data },
558#endif
Patrick Wildt8bd56562019-10-03 15:51:50 +0200559 { }
560};
561
562struct power_domain_ops imx8m_power_domain_ops = {
Patrick Wildt8bd56562019-10-03 15:51:50 +0200563 .on = imx8m_power_domain_on,
564 .off = imx8m_power_domain_off,
565 .of_xlate = imx8m_power_domain_of_xlate,
566};
567
568U_BOOT_DRIVER(imx8m_power_domain) = {
569 .name = "imx8m_power_domain",
570 .id = UCLASS_POWER_DOMAIN,
571 .of_match = imx8m_power_domain_ids,
572 .bind = imx8m_power_domain_bind,
Marek Vasute5481a82022-04-13 00:42:51 +0200573 .probe = imx8m_power_domain_probe,
Simon Glassaad29ae2020-12-03 16:55:21 -0700574 .of_to_plat = imx8m_power_domain_of_to_plat,
Simon Glassb75b15b2020-12-03 16:55:23 -0700575 .plat_auto = sizeof(struct imx8m_power_domain_plat),
Patrick Wildt8bd56562019-10-03 15:51:50 +0200576 .ops = &imx8m_power_domain_ops,
577};