blob: 6188a04c45ed5a907268f1d1f00fbb0d34cedd54 [file] [log] [blame]
Marek Vasutdd96fba2022-04-13 00:42:54 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2022 Marek Vasut <marex@denx.de>
4 */
5
6#include <common.h>
7#include <asm/io.h>
8#include <clk.h>
Sumit Garg77ad6642024-03-21 20:25:01 +05309#include <clk-uclass.h>
Marek Vasutdd96fba2022-04-13 00:42:54 +020010#include <dm.h>
11#include <dm/device.h>
12#include <dm/device_compat.h>
Sumit Garg77ad6642024-03-21 20:25:01 +053013#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>
Marek Vasutdd96fba2022-04-13 00:42:54 +020018#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)
Sumit Gargaee7c462024-03-21 20:25:00 +053025#define PCIE_PHY_APB_RST BIT(4)
26#define PCIE_PHY_INIT_RST BIT(5)
Sumit Garg77ad6642024-03-21 20:25:01 +053027#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)
Marek Vasutdd96fba2022-04-13 00:42:54 +020036
37struct imx8mp_hsiomix_priv {
38 void __iomem *base;
39 struct clk clk_usb;
Sumit Gargaee7c462024-03-21 20:25:00 +053040 struct clk clk_pcie;
Marek Vasutdd96fba2022-04-13 00:42:54 +020041 struct power_domain pd_bus;
42 struct power_domain pd_usb;
Sumit Gargaee7c462024-03-21 20:25:00 +053043 struct power_domain pd_pcie;
Marek Vasutdd96fba2022-04-13 00:42:54 +020044 struct power_domain pd_usb_phy1;
45 struct power_domain pd_usb_phy2;
Sumit Gargaee7c462024-03-21 20:25:00 +053046 struct power_domain pd_pcie_phy;
Marek Vasutdd96fba2022-04-13 00:42:54 +020047};
48
Sumit Gargaee7c462024-03-21 20:25:00 +053049static int imx8mp_hsiomix_set(struct power_domain *power_domain, bool power_on)
Marek Vasutdd96fba2022-04-13 00:42:54 +020050{
51 struct udevice *dev = power_domain->dev;
52 struct imx8mp_hsiomix_priv *priv = dev_get_priv(dev);
Sumit Gargaee7c462024-03-21 20:25:00 +053053 struct power_domain *domain = NULL;
54 struct clk *clk = NULL;
55 u32 gpr_reg0_bits = 0;
Marek Vasutdd96fba2022-04-13 00:42:54 +020056 int ret;
57
Sumit Gargaee7c462024-03-21 20:25:00 +053058 switch (power_domain->id) {
59 case IMX8MP_HSIOBLK_PD_USB:
Marek Vasutdd96fba2022-04-13 00:42:54 +020060 domain = &priv->pd_usb;
Sumit Gargaee7c462024-03-21 20:25:00 +053061 clk = &priv->clk_usb;
62 gpr_reg0_bits |= USB_CLOCK_MODULE_EN;
63 break;
64 case IMX8MP_HSIOBLK_PD_USB_PHY1:
Marek Vasutdd96fba2022-04-13 00:42:54 +020065 domain = &priv->pd_usb_phy1;
Sumit Gargaee7c462024-03-21 20:25:00 +053066 break;
67 case IMX8MP_HSIOBLK_PD_USB_PHY2:
Marek Vasutdd96fba2022-04-13 00:42:54 +020068 domain = &priv->pd_usb_phy2;
Sumit Gargaee7c462024-03-21 20:25:00 +053069 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;
Marek Vasutdd96fba2022-04-13 00:42:54 +020084 }
85
Sumit Gargaee7c462024-03-21 20:25:00 +053086 if (power_on) {
87 ret = power_domain_on(&priv->pd_bus);
88 if (ret)
89 return ret;
Marek Vasutdd96fba2022-04-13 00:42:54 +020090
Sumit Gargaee7c462024-03-21 20:25:00 +053091 ret = power_domain_on(domain);
92 if (ret)
93 goto err_pd;
Marek Vasutdd96fba2022-04-13 00:42:54 +020094
Sumit Gargaee7c462024-03-21 20:25:00 +053095 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 }
Marek Vasutdd96fba2022-04-13 00:42:54 +0200113
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
Sumit Gargaee7c462024-03-21 20:25:00 +0530123static int imx8mp_hsiomix_on(struct power_domain *power_domain)
Marek Vasutdd96fba2022-04-13 00:42:54 +0200124{
Sumit Gargaee7c462024-03-21 20:25:00 +0530125 return imx8mp_hsiomix_set(power_domain, true);
126}
Marek Vasutdd96fba2022-04-13 00:42:54 +0200127
Sumit Gargaee7c462024-03-21 20:25:00 +0530128static int imx8mp_hsiomix_off(struct power_domain *power_domain)
129{
130 return imx8mp_hsiomix_set(power_domain, false);
Marek Vasutdd96fba2022-04-13 00:42:54 +0200131}
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
Sumit Garg77ad6642024-03-21 20:25:01 +0530141static 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
Marek Vasutdd96fba2022-04-13 00:42:54 +0200202static 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
Sumit Gargaee7c462024-03-21 20:25:00 +0530213 ret = clk_get_by_name(dev, "pcie", &priv->clk_pcie);
214 if (ret < 0)
215 return ret;
216
Marek Vasutdd96fba2022-04-13 00:42:54 +0200217 ret = power_domain_get_by_name(dev, &priv->pd_bus, "bus");
218 if (ret < 0)
Sean Andersond318eb32023-12-16 14:38:42 -0500219 return ret;
Marek Vasutdd96fba2022-04-13 00:42:54 +0200220
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
Sumit Gargaee7c462024-03-21 20:25:00 +0530233 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
Marek Vasutdd96fba2022-04-13 00:42:54 +0200241 return 0;
242
Sumit Gargaee7c462024-03-21 20:25:00 +0530243err_pd_pcie_phy:
244 power_domain_free(&priv->pd_pcie);
245err_pd_pcie:
246 power_domain_free(&priv->pd_usb_phy2);
Marek Vasutdd96fba2022-04-13 00:42:54 +0200247err_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);
Marek Vasutdd96fba2022-04-13 00:42:54 +0200253 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,
Sumit Garg77ad6642024-03-21 20:25:01 +0530272 .bind = imx8mp_hsiomix_bind,
Marek Vasutdd96fba2022-04-13 00:42:54 +0200273 .priv_auto = sizeof(struct imx8mp_hsiomix_priv),
274 .ops = &imx8mp_hsiomix_ops,
275};