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