]> git.ipfire.org Git - thirdparty/u-boot.git/blame - drivers/power/domain/imx8mp-hsiomix.c
Revert "Merge patch series "arm: dts: am62-beagleplay: Fix Beagleplay Ethernet""
[thirdparty/u-boot.git] / drivers / power / domain / imx8mp-hsiomix.c
CommitLineData
898e7610
MV
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2022 Marek Vasut <marex@denx.de>
4 */
5
d678a59d 6#include <common.h>
898e7610
MV
7#include <asm/io.h>
8#include <clk.h>
0d588cb7 9#include <clk-uclass.h>
898e7610
MV
10#include <dm.h>
11#include <dm/device.h>
12#include <dm/device_compat.h>
0d588cb7
SG
13#include <dm/device-internal.h>
14#include <dm/lists.h>
15#include <linux/bitfield.h>
16#include <linux/delay.h>
17#include <linux/iopoll.h>
898e7610
MV
18#include <power-domain-uclass.h>
19
20#include <dt-bindings/power/imx8mp-power.h>
21
22#define GPR_REG0 0x0
23#define PCIE_CLOCK_MODULE_EN BIT(0)
24#define USB_CLOCK_MODULE_EN BIT(1)
c7ab1442
SG
25#define PCIE_PHY_APB_RST BIT(4)
26#define PCIE_PHY_INIT_RST BIT(5)
0d588cb7
SG
27#define GPR_REG1 0x4
28#define PLL_LOCK BIT(13)
29#define GPR_REG2 0x8
30#define P_PLL_MASK GENMASK(5, 0)
31#define M_PLL_MASK GENMASK(15, 6)
32#define S_PLL_MASK GENMASK(18, 16)
33#define GPR_REG3 0xc
34#define PLL_CKE BIT(17)
35#define PLL_RST BIT(31)
898e7610
MV
36
37struct imx8mp_hsiomix_priv {
38 void __iomem *base;
39 struct clk clk_usb;
c7ab1442 40 struct clk clk_pcie;
898e7610
MV
41 struct power_domain pd_bus;
42 struct power_domain pd_usb;
c7ab1442 43 struct power_domain pd_pcie;
898e7610
MV
44 struct power_domain pd_usb_phy1;
45 struct power_domain pd_usb_phy2;
c7ab1442 46 struct power_domain pd_pcie_phy;
898e7610
MV
47};
48
c7ab1442 49static int imx8mp_hsiomix_set(struct power_domain *power_domain, bool power_on)
898e7610
MV
50{
51 struct udevice *dev = power_domain->dev;
52 struct imx8mp_hsiomix_priv *priv = dev_get_priv(dev);
c7ab1442
SG
53 struct power_domain *domain = NULL;
54 struct clk *clk = NULL;
55 u32 gpr_reg0_bits = 0;
898e7610
MV
56 int ret;
57
c7ab1442
SG
58 switch (power_domain->id) {
59 case IMX8MP_HSIOBLK_PD_USB:
898e7610 60 domain = &priv->pd_usb;
c7ab1442
SG
61 clk = &priv->clk_usb;
62 gpr_reg0_bits |= USB_CLOCK_MODULE_EN;
63 break;
64 case IMX8MP_HSIOBLK_PD_USB_PHY1:
898e7610 65 domain = &priv->pd_usb_phy1;
c7ab1442
SG
66 break;
67 case IMX8MP_HSIOBLK_PD_USB_PHY2:
898e7610 68 domain = &priv->pd_usb_phy2;
c7ab1442
SG
69 break;
70 case IMX8MP_HSIOBLK_PD_PCIE:
71 domain = &priv->pd_pcie;
72 clk = &priv->clk_pcie;
73 gpr_reg0_bits |= PCIE_CLOCK_MODULE_EN;
74 break;
75 case IMX8MP_HSIOBLK_PD_PCIE_PHY:
76 domain = &priv->pd_pcie_phy;
77 /* Bits to deassert PCIe PHY reset */
78 gpr_reg0_bits |= PCIE_PHY_APB_RST | PCIE_PHY_INIT_RST;
79 break;
80 default:
81 dev_err(dev, "unknown power domain id: %ld\n",
82 power_domain->id);
83 return -EINVAL;
898e7610
MV
84 }
85
c7ab1442
SG
86 if (power_on) {
87 ret = power_domain_on(&priv->pd_bus);
88 if (ret)
89 return ret;
898e7610 90
c7ab1442
SG
91 ret = power_domain_on(domain);
92 if (ret)
93 goto err_pd;
898e7610 94
c7ab1442
SG
95 if (clk) {
96 ret = clk_enable(clk);
97 if (ret)
98 goto err_clk;
99 }
100
101 if (gpr_reg0_bits)
102 setbits_le32(priv->base + GPR_REG0, gpr_reg0_bits);
103 } else {
104 if (gpr_reg0_bits)
105 clrbits_le32(priv->base + GPR_REG0, gpr_reg0_bits);
106
107 if (clk)
108 clk_disable(clk);
109
110 power_domain_off(domain);
111 power_domain_off(&priv->pd_bus);
112 }
898e7610
MV
113
114 return 0;
115
116err_clk:
117 power_domain_off(domain);
118err_pd:
119 power_domain_off(&priv->pd_bus);
120 return ret;
121}
122
c7ab1442 123static int imx8mp_hsiomix_on(struct power_domain *power_domain)
898e7610 124{
c7ab1442
SG
125 return imx8mp_hsiomix_set(power_domain, true);
126}
898e7610 127
c7ab1442
SG
128static int imx8mp_hsiomix_off(struct power_domain *power_domain)
129{
130 return imx8mp_hsiomix_set(power_domain, false);
898e7610
MV
131}
132
133static int imx8mp_hsiomix_of_xlate(struct power_domain *power_domain,
134 struct ofnode_phandle_args *args)
135{
136 power_domain->id = args->args[0];
137
138 return 0;
139}
140
0d588cb7
SG
141static int hsio_pll_clk_enable(struct clk *clk)
142{
143 void *base = (void *)dev_get_driver_data(clk->dev);
144 u32 val;
145 int ret;
146
147 /* Setup HSIO PLL as 100 MHz output clock */
148 clrsetbits_le32(base + GPR_REG2,
149 P_PLL_MASK | M_PLL_MASK | S_PLL_MASK,
150 FIELD_PREP(P_PLL_MASK, 12) |
151 FIELD_PREP(M_PLL_MASK, 800) |
152 FIELD_PREP(S_PLL_MASK, 4));
153
154 /* de-assert PLL reset */
155 setbits_le32(base + GPR_REG3, PLL_RST);
156
157 /* enable PLL */
158 setbits_le32(base + GPR_REG3, PLL_CKE);
159
160 /* Check if PLL is locked */
161 ret = readl_poll_sleep_timeout(base + GPR_REG1, val,
162 val & PLL_LOCK, 10, 100000);
163 if (ret)
164 dev_err(clk->dev, "failed to lock HSIO PLL\n");
165
166 return ret;
167}
168
169static int hsio_pll_clk_disable(struct clk *clk)
170{
171 void *base = (void *)dev_get_driver_data(clk->dev);
172
173 clrbits_le32(base + GPR_REG3, PLL_CKE | PLL_RST);
174
175 return 0;
176}
177
178static const struct clk_ops hsio_pll_clk_ops = {
179 .enable = hsio_pll_clk_enable,
180 .disable = hsio_pll_clk_disable,
181};
182
183U_BOOT_DRIVER(hsio_pll) = {
184 .name = "hsio-pll",
185 .id = UCLASS_CLK,
186 .ops = &hsio_pll_clk_ops,
187};
188
189int imx8mp_hsiomix_bind(struct udevice *dev)
190{
191 struct driver *drv;
192
193 drv = lists_driver_lookup_name("hsio-pll");
194 if (!drv)
195 return -ENOENT;
196
197 return device_bind_with_driver_data(dev, drv, "hsio-pll",
198 (ulong)dev_read_addr_ptr(dev),
199 dev_ofnode(dev), NULL);
200}
201
898e7610
MV
202static int imx8mp_hsiomix_probe(struct udevice *dev)
203{
204 struct imx8mp_hsiomix_priv *priv = dev_get_priv(dev);
205 int ret;
206
207 priv->base = dev_read_addr_ptr(dev);
208
209 ret = clk_get_by_name(dev, "usb", &priv->clk_usb);
210 if (ret < 0)
211 return ret;
212
c7ab1442
SG
213 ret = clk_get_by_name(dev, "pcie", &priv->clk_pcie);
214 if (ret < 0)
215 return ret;
216
898e7610
MV
217 ret = power_domain_get_by_name(dev, &priv->pd_bus, "bus");
218 if (ret < 0)
c9309f40 219 return ret;
898e7610
MV
220
221 ret = power_domain_get_by_name(dev, &priv->pd_usb, "usb");
222 if (ret < 0)
223 goto err_pd_usb;
224
225 ret = power_domain_get_by_name(dev, &priv->pd_usb_phy1, "usb-phy1");
226 if (ret < 0)
227 goto err_pd_usb_phy1;
228
229 ret = power_domain_get_by_name(dev, &priv->pd_usb_phy2, "usb-phy2");
230 if (ret < 0)
231 goto err_pd_usb_phy2;
232
c7ab1442
SG
233 ret = power_domain_get_by_name(dev, &priv->pd_pcie, "pcie");
234 if (ret < 0)
235 goto err_pd_pcie;
236
237 ret = power_domain_get_by_name(dev, &priv->pd_pcie_phy, "pcie-phy");
238 if (ret < 0)
239 goto err_pd_pcie_phy;
240
898e7610
MV
241 return 0;
242
c7ab1442
SG
243err_pd_pcie_phy:
244 power_domain_free(&priv->pd_pcie);
245err_pd_pcie:
246 power_domain_free(&priv->pd_usb_phy2);
898e7610
MV
247err_pd_usb_phy2:
248 power_domain_free(&priv->pd_usb_phy1);
249err_pd_usb_phy1:
250 power_domain_free(&priv->pd_usb);
251err_pd_usb:
252 power_domain_free(&priv->pd_bus);
898e7610
MV
253 return ret;
254}
255
256static const struct udevice_id imx8mp_hsiomix_ids[] = {
257 { .compatible = "fsl,imx8mp-hsio-blk-ctrl" },
258 { }
259};
260
261struct power_domain_ops imx8mp_hsiomix_ops = {
262 .on = imx8mp_hsiomix_on,
263 .off = imx8mp_hsiomix_off,
264 .of_xlate = imx8mp_hsiomix_of_xlate,
265};
266
267U_BOOT_DRIVER(imx8mp_hsiomix) = {
268 .name = "imx8mp_hsiomix",
269 .id = UCLASS_POWER_DOMAIN,
270 .of_match = imx8mp_hsiomix_ids,
271 .probe = imx8mp_hsiomix_probe,
0d588cb7 272 .bind = imx8mp_hsiomix_bind,
898e7610
MV
273 .priv_auto = sizeof(struct imx8mp_hsiomix_priv),
274 .ops = &imx8mp_hsiomix_ops,
275};