blob: afbc7ad8dd4c614ea97ec46442f7abeb44a1fc06 [file] [log] [blame]
Ye Lifde01d92021-02-21 08:26:21 -08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2021 NXP
4 *
5 */
6
7#include <common.h>
8#include <asm/io.h>
9#include <dm.h>
10#include <errno.h>
11#include <generic-phy.h>
12#include <linux/bitops.h>
13#include <linux/err.h>
14#include <clk.h>
15
16#define PHY_CTRL0 0x0
17#define PHY_CTRL0_REF_SSP_EN BIT(2)
18#define PHY_CTRL0_FSEL_MASK GENMASK(10, 5)
19#define PHY_CTRL0_FSEL_24M 0x2a
20#define PHY_CTRL0_FSEL_100M 0x27
21#define PHY_CTRL0_SSC_RANGE_MASK GENMASK(23, 21)
22#define PHY_CTRL0_SSC_RANGE_4003PPM (0x2 << 21)
23
24#define PHY_CTRL1 0x4
25#define PHY_CTRL1_RESET BIT(0)
26#define PHY_CTRL1_COMMONONN BIT(1)
27#define PHY_CTRL1_ATERESET BIT(3)
28#define PHY_CTRL1_DCDENB BIT(17)
29#define PHY_CTRL1_CHRGSEL BIT(18)
30#define PHY_CTRL1_VDATSRCENB0 BIT(19)
31#define PHY_CTRL1_VDATDETENB0 BIT(20)
32
33#define PHY_CTRL2 0x8
34#define PHY_CTRL2_TXENABLEN0 BIT(8)
35#define PHY_CTRL2_OTG_DISABLE BIT(9)
36
37#define PHY_CTRL3 0xc
38#define PHY_CTRL3_COMPDISTUNE_MASK GENMASK(2, 0)
39#define PHY_CTRL3_TXPREEMP_TUNE_MASK GENMASK(16, 15)
40#define PHY_CTRL3_TXPREEMP_TUNE_SHIFT 15
41#define PHY_CTRL3_TXRISE_TUNE_MASK GENMASK(21, 20)
42#define PHY_CTRL3_TXRISE_TUNE_SHIFT 20
43/* 1111: +24% ... 0000: -6% step: 2% */
44#define PHY_CTRL3_TXVREF_TUNE_MASK GENMASK(25, 22)
45#define PHY_CTRL3_TXVREF_TUNE_SHIFT 22
46#define PHY_CTRL3_TX_VBOOST_LEVEL_MASK GENMASK(31, 29)
47#define PHY_CTRL3_TX_VBOOST_LEVEL_SHIFT 29
48
49#define PHY_CTRL4 0x10
50#define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(20, 15)
51#define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_SHIFT 15
52
53#define PHY_CTRL5 0x14
54#define PHY_CTRL5_DMPWD_OVERRIDE_SEL BIT(23)
55#define PHY_CTRL5_DMPWD_OVERRIDE BIT(22)
56#define PHY_CTRL5_DPPWD_OVERRIDE_SEL BIT(21)
57#define PHY_CTRL5_DPPWD_OVERRIDE BIT(20)
58#define PHY_CTRL5_PCS_TX_SWING_FULL_MASK GENMASK(6, 0)
59
60#define PHY_CTRL6 0x18
61#define PHY_CTRL6_RXTERM_OVERRIDE_SEL BIT(29)
62#define PHY_CTRL6_ALT_CLK_EN BIT(1)
63#define PHY_CTRL6_ALT_CLK_SEL BIT(0)
64
65#define PHY_STS0 0x40
66#define PHY_STS0_OTGSESSVLD BIT(7)
67#define PHY_STS0_CHGDET BIT(4)
68#define PHY_STS0_FSVPLUS BIT(3)
69#define PHY_STS0_FSVMINUS BIT(2)
70
71struct imx8mq_usb_phy {
72#if CONFIG_IS_ENABLED(CLK)
73 struct clk phy_clk;
74#endif
75 void __iomem *base;
76};
77
78static const struct udevice_id imx8mq_usb_phy_of_match[] = {
79 {
80 .compatible = "fsl,imx8mq-usb-phy",
81 },
82 {},
83};
84
85static int imx8mq_usb_phy_init(struct phy *usb_phy)
86{
87 struct udevice *dev = usb_phy->dev;
88 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
89 u32 value;
90
91 value = readl(imx_phy->base + PHY_CTRL1);
92 value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0 |
93 PHY_CTRL1_COMMONONN);
94 value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET;
95 writel(value, imx_phy->base + PHY_CTRL1);
96
97 value = readl(imx_phy->base + PHY_CTRL0);
98 value |= PHY_CTRL0_REF_SSP_EN;
99 value &= ~PHY_CTRL0_SSC_RANGE_MASK;
100 value |= PHY_CTRL0_SSC_RANGE_4003PPM;
101 writel(value, imx_phy->base + PHY_CTRL0);
102
103 value = readl(imx_phy->base + PHY_CTRL2);
104 value |= PHY_CTRL2_TXENABLEN0;
105 writel(value, imx_phy->base + PHY_CTRL2);
106
107 value = readl(imx_phy->base + PHY_CTRL1);
108 value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
109 writel(value, imx_phy->base + PHY_CTRL1);
110
111 return 0;
112}
113
114static int imx8mq_usb_phy_power_on(struct phy *usb_phy)
115{
116 struct udevice *dev = usb_phy->dev;
117 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
118 u32 value;
119
120#if CONFIG_IS_ENABLED(CLK)
121 int ret;
122 ret = clk_enable(&imx_phy->phy_clk);
123 if (ret) {
124 printf("Failed to enable usb phy clock\n");
125 return ret;
126 }
127#endif
128
129 /* Disable rx term override */
130 value = readl(imx_phy->base + PHY_CTRL6);
131 value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
132 writel(value, imx_phy->base + PHY_CTRL6);
133
134 return 0;
135}
136
137static int imx8mq_usb_phy_power_off(struct phy *usb_phy)
138{
139 struct udevice *dev = usb_phy->dev;
140 struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev);
141 u32 value;
142
143 /* Override rx term to be 0 */
144 value = readl(imx_phy->base + PHY_CTRL6);
145 value |= PHY_CTRL6_RXTERM_OVERRIDE_SEL;
146 writel(value, imx_phy->base + PHY_CTRL6);
147
148#if CONFIG_IS_ENABLED(CLK)
149 clk_disable(&imx_phy->phy_clk);
150#endif
151
152 return 0;
153}
154
155static int imx8mq_usb_phy_exit(struct phy *usb_phy)
156{
157 return imx8mq_usb_phy_power_off(usb_phy);
158}
159
160struct phy_ops imx8mq_usb_phy_ops = {
161 .init = imx8mq_usb_phy_init,
162 .power_on = imx8mq_usb_phy_power_on,
163 .power_off = imx8mq_usb_phy_power_off,
164 .exit = imx8mq_usb_phy_exit,
165};
166
167int imx8mq_usb_phy_probe(struct udevice *dev)
168{
169 struct imx8mq_usb_phy *priv = dev_get_priv(dev);
170
171 priv->base = dev_read_addr_ptr(dev);
172
173 if (!priv->base)
174 return -EINVAL;
175
176#if CONFIG_IS_ENABLED(CLK)
177 int ret;
178
179 /* Assigned clock already set clock */
180 ret = clk_get_by_name(dev, "phy", &priv->phy_clk);
181 if (ret) {
182 printf("Failed to get usb phy clock\n");
183 return ret;
184 }
185#endif
186
187 return 0;
188}
189
190U_BOOT_DRIVER(nxp_imx8mq_usb_phy) = {
191 .name = "nxp_imx8mq_usb_phy",
192 .id = UCLASS_PHY,
193 .of_match = imx8mq_usb_phy_of_match,
194 .probe = imx8mq_usb_phy_probe,
195 .ops = &imx8mq_usb_phy_ops,
196 .priv_auto = sizeof(struct imx8mq_usb_phy),
197};