1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2022 Marek Vasut <marex@denx.de>
10 #include <dm/device.h>
11 #include <dm/device_compat.h>
12 #include <power-domain-uclass.h>
14 #include <dt-bindings/power/imx8mp-power.h>
17 #define PCIE_CLOCK_MODULE_EN BIT(0)
18 #define USB_CLOCK_MODULE_EN BIT(1)
19 #define PCIE_PHY_APB_RST BIT(4)
20 #define PCIE_PHY_INIT_RST BIT(5)
22 struct imx8mp_hsiomix_priv
{
26 struct power_domain pd_bus
;
27 struct power_domain pd_usb
;
28 struct power_domain pd_pcie
;
29 struct power_domain pd_usb_phy1
;
30 struct power_domain pd_usb_phy2
;
31 struct power_domain pd_pcie_phy
;
34 static int imx8mp_hsiomix_set(struct power_domain
*power_domain
, bool power_on
)
36 struct udevice
*dev
= power_domain
->dev
;
37 struct imx8mp_hsiomix_priv
*priv
= dev_get_priv(dev
);
38 struct power_domain
*domain
= NULL
;
39 struct clk
*clk
= NULL
;
40 u32 gpr_reg0_bits
= 0;
43 switch (power_domain
->id
) {
44 case IMX8MP_HSIOBLK_PD_USB
:
45 domain
= &priv
->pd_usb
;
47 gpr_reg0_bits
|= USB_CLOCK_MODULE_EN
;
49 case IMX8MP_HSIOBLK_PD_USB_PHY1
:
50 domain
= &priv
->pd_usb_phy1
;
52 case IMX8MP_HSIOBLK_PD_USB_PHY2
:
53 domain
= &priv
->pd_usb_phy2
;
55 case IMX8MP_HSIOBLK_PD_PCIE
:
56 domain
= &priv
->pd_pcie
;
57 clk
= &priv
->clk_pcie
;
58 gpr_reg0_bits
|= PCIE_CLOCK_MODULE_EN
;
60 case IMX8MP_HSIOBLK_PD_PCIE_PHY
:
61 domain
= &priv
->pd_pcie_phy
;
62 /* Bits to deassert PCIe PHY reset */
63 gpr_reg0_bits
|= PCIE_PHY_APB_RST
| PCIE_PHY_INIT_RST
;
66 dev_err(dev
, "unknown power domain id: %ld\n",
72 ret
= power_domain_on(&priv
->pd_bus
);
76 ret
= power_domain_on(domain
);
81 ret
= clk_enable(clk
);
87 setbits_le32(priv
->base
+ GPR_REG0
, gpr_reg0_bits
);
90 clrbits_le32(priv
->base
+ GPR_REG0
, gpr_reg0_bits
);
95 power_domain_off(domain
);
96 power_domain_off(&priv
->pd_bus
);
102 power_domain_off(domain
);
104 power_domain_off(&priv
->pd_bus
);
108 static int imx8mp_hsiomix_on(struct power_domain
*power_domain
)
110 return imx8mp_hsiomix_set(power_domain
, true);
113 static int imx8mp_hsiomix_off(struct power_domain
*power_domain
)
115 return imx8mp_hsiomix_set(power_domain
, false);
118 static int imx8mp_hsiomix_of_xlate(struct power_domain
*power_domain
,
119 struct ofnode_phandle_args
*args
)
121 power_domain
->id
= args
->args
[0];
126 static int imx8mp_hsiomix_probe(struct udevice
*dev
)
128 struct imx8mp_hsiomix_priv
*priv
= dev_get_priv(dev
);
131 priv
->base
= dev_read_addr_ptr(dev
);
133 ret
= clk_get_by_name(dev
, "usb", &priv
->clk_usb
);
137 ret
= clk_get_by_name(dev
, "pcie", &priv
->clk_pcie
);
141 ret
= power_domain_get_by_name(dev
, &priv
->pd_bus
, "bus");
145 ret
= power_domain_get_by_name(dev
, &priv
->pd_usb
, "usb");
149 ret
= power_domain_get_by_name(dev
, &priv
->pd_usb_phy1
, "usb-phy1");
151 goto err_pd_usb_phy1
;
153 ret
= power_domain_get_by_name(dev
, &priv
->pd_usb_phy2
, "usb-phy2");
155 goto err_pd_usb_phy2
;
157 ret
= power_domain_get_by_name(dev
, &priv
->pd_pcie
, "pcie");
161 ret
= power_domain_get_by_name(dev
, &priv
->pd_pcie_phy
, "pcie-phy");
163 goto err_pd_pcie_phy
;
168 power_domain_free(&priv
->pd_pcie
);
170 power_domain_free(&priv
->pd_usb_phy2
);
172 power_domain_free(&priv
->pd_usb_phy1
);
174 power_domain_free(&priv
->pd_usb
);
176 power_domain_free(&priv
->pd_bus
);
180 static const struct udevice_id imx8mp_hsiomix_ids
[] = {
181 { .compatible
= "fsl,imx8mp-hsio-blk-ctrl" },
185 struct power_domain_ops imx8mp_hsiomix_ops
= {
186 .on
= imx8mp_hsiomix_on
,
187 .off
= imx8mp_hsiomix_off
,
188 .of_xlate
= imx8mp_hsiomix_of_xlate
,
191 U_BOOT_DRIVER(imx8mp_hsiomix
) = {
192 .name
= "imx8mp_hsiomix",
193 .id
= UCLASS_POWER_DOMAIN
,
194 .of_match
= imx8mp_hsiomix_ids
,
195 .probe
= imx8mp_hsiomix_probe
,
196 .priv_auto
= sizeof(struct imx8mp_hsiomix_priv
),
197 .ops
= &imx8mp_hsiomix_ops
,