blob: 455ad53ef525e18ae45068fa5d8c2be8a1b79335 [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
Marek Vasutdd96fba2022-04-13 00:42:54 +02006#include <asm/io.h>
7#include <clk.h>
Sumit Garg77ad6642024-03-21 20:25:01 +05308#include <clk-uclass.h>
Marek Vasutdd96fba2022-04-13 00:42:54 +02009#include <dm.h>
10#include <dm/device.h>
11#include <dm/device_compat.h>
Sumit Garg77ad6642024-03-21 20:25:01 +053012#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>
Marek Vasutdd96fba2022-04-13 00:42:54 +020017#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)
Sumit Gargaee7c462024-03-21 20:25:00 +053024#define PCIE_PHY_APB_RST BIT(4)
25#define PCIE_PHY_INIT_RST BIT(5)
Sumit Garg77ad6642024-03-21 20:25:01 +053026#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)
Marek Vasutdd96fba2022-04-13 00:42:54 +020035
36struct imx8mp_hsiomix_priv {
37 void __iomem *base;
38 struct clk clk_usb;
Sumit Gargaee7c462024-03-21 20:25:00 +053039 struct clk clk_pcie;
Marek Vasutdd96fba2022-04-13 00:42:54 +020040 struct power_domain pd_bus;
41 struct power_domain pd_usb;
Sumit Gargaee7c462024-03-21 20:25:00 +053042 struct power_domain pd_pcie;
Marek Vasutdd96fba2022-04-13 00:42:54 +020043 struct power_domain pd_usb_phy1;
44 struct power_domain pd_usb_phy2;
Sumit Gargaee7c462024-03-21 20:25:00 +053045 struct power_domain pd_pcie_phy;
Marek Vasutdd96fba2022-04-13 00:42:54 +020046};
47
Sumit Gargaee7c462024-03-21 20:25:00 +053048static int imx8mp_hsiomix_set(struct power_domain *power_domain, bool power_on)
Marek Vasutdd96fba2022-04-13 00:42:54 +020049{
50 struct udevice *dev = power_domain->dev;
51 struct imx8mp_hsiomix_priv *priv = dev_get_priv(dev);
Sumit Gargaee7c462024-03-21 20:25:00 +053052 struct power_domain *domain = NULL;
53 struct clk *clk = NULL;
54 u32 gpr_reg0_bits = 0;
Marek Vasutdd96fba2022-04-13 00:42:54 +020055 int ret;
56
Sumit Gargaee7c462024-03-21 20:25:00 +053057 switch (power_domain->id) {
58 case IMX8MP_HSIOBLK_PD_USB:
Marek Vasutdd96fba2022-04-13 00:42:54 +020059 domain = &priv->pd_usb;
Sumit Gargaee7c462024-03-21 20:25:00 +053060 clk = &priv->clk_usb;
61 gpr_reg0_bits |= USB_CLOCK_MODULE_EN;
62 break;
63 case IMX8MP_HSIOBLK_PD_USB_PHY1:
Marek Vasutdd96fba2022-04-13 00:42:54 +020064 domain = &priv->pd_usb_phy1;
Sumit Gargaee7c462024-03-21 20:25:00 +053065 break;
66 case IMX8MP_HSIOBLK_PD_USB_PHY2:
Marek Vasutdd96fba2022-04-13 00:42:54 +020067 domain = &priv->pd_usb_phy2;
Sumit Gargaee7c462024-03-21 20:25:00 +053068 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;
Marek Vasutdd96fba2022-04-13 00:42:54 +020083 }
84
Sumit Gargaee7c462024-03-21 20:25:00 +053085 if (power_on) {
86 ret = power_domain_on(&priv->pd_bus);
87 if (ret)
88 return ret;
Marek Vasutdd96fba2022-04-13 00:42:54 +020089
Sumit Gargaee7c462024-03-21 20:25:00 +053090 ret = power_domain_on(domain);
91 if (ret)
92 goto err_pd;
Marek Vasutdd96fba2022-04-13 00:42:54 +020093
Sumit Gargaee7c462024-03-21 20:25:00 +053094 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 }
Marek Vasutdd96fba2022-04-13 00:42:54 +0200112
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
Sumit Gargaee7c462024-03-21 20:25:00 +0530122static int imx8mp_hsiomix_on(struct power_domain *power_domain)
Marek Vasutdd96fba2022-04-13 00:42:54 +0200123{
Sumit Gargaee7c462024-03-21 20:25:00 +0530124 return imx8mp_hsiomix_set(power_domain, true);
125}
Marek Vasutdd96fba2022-04-13 00:42:54 +0200126
Sumit Gargaee7c462024-03-21 20:25:00 +0530127static int imx8mp_hsiomix_off(struct power_domain *power_domain)
128{
129 return imx8mp_hsiomix_set(power_domain, false);
Marek Vasutdd96fba2022-04-13 00:42:54 +0200130}
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
Sumit Garg77ad6642024-03-21 20:25:01 +0530140static 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
Marek Vasutdd96fba2022-04-13 00:42:54 +0200201static 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
Sumit Gargaee7c462024-03-21 20:25:00 +0530212 ret = clk_get_by_name(dev, "pcie", &priv->clk_pcie);
213 if (ret < 0)
214 return ret;
215
Marek Vasutdd96fba2022-04-13 00:42:54 +0200216 ret = power_domain_get_by_name(dev, &priv->pd_bus, "bus");
217 if (ret < 0)
Sean Andersond318eb32023-12-16 14:38:42 -0500218 return ret;
Marek Vasutdd96fba2022-04-13 00:42:54 +0200219
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
Sumit Gargaee7c462024-03-21 20:25:00 +0530232 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
Marek Vasutdd96fba2022-04-13 00:42:54 +0200240 return 0;
241
Sumit Gargaee7c462024-03-21 20:25:00 +0530242err_pd_pcie_phy:
243 power_domain_free(&priv->pd_pcie);
244err_pd_pcie:
245 power_domain_free(&priv->pd_usb_phy2);
Marek Vasutdd96fba2022-04-13 00:42:54 +0200246err_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);
Marek Vasutdd96fba2022-04-13 00:42:54 +0200252 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,
Sumit Garg77ad6642024-03-21 20:25:01 +0530271 .bind = imx8mp_hsiomix_bind,
Marek Vasutdd96fba2022-04-13 00:42:54 +0200272 .priv_auto = sizeof(struct imx8mp_hsiomix_priv),
273 .ops = &imx8mp_hsiomix_ops,
274};