1 /********************************************************************************
2 Copyright (C) 2016 Marvell International Ltd.
3
4 Marvell BSD License Option
5
6 If you received this File from Marvell, you may opt to use, redistribute and/or
7 modify this File under the following licensing terms.
8 Redistribution and use in source and binary forms, with or without modification,
9 are permitted provided that the following conditions are met:
10
11 * Redistributions of source code must Retain the above copyright notice,
12 this list of conditions and the following disclaimer.
13
14 * Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in the
16 documentation and/or other materials provided with the distribution.
17
18 * Neither the name of Marvell nor the names of its contributors may be
19 used to endorse or promote products derived from this software without
20 specific prior written permission.
21
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
26 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33 *******************************************************************************/
34
35 #include "UtmiPhyLib.h"
36
37 typedef struct {
38 EFI_PHYSICAL_ADDRESS UtmiBaseAddr;
39 EFI_PHYSICAL_ADDRESS UsbCfgAddr;
40 EFI_PHYSICAL_ADDRESS UtmiCfgAddr;
41 UINT32 UtmiPhyPort;
42 } UTMI_PHY_DATA;
43
44 STATIC
45 VOID
RegSetSilent(IN EFI_PHYSICAL_ADDRESS Addr,IN UINT32 Data,IN UINT32 Mask)46 RegSetSilent (
47 IN EFI_PHYSICAL_ADDRESS Addr,
48 IN UINT32 Data,
49 IN UINT32 Mask
50 )
51 {
52 UINT32 RegData;
53
54 RegData = MmioRead32 (Addr);
55 RegData &= ~Mask;
56 RegData |= Data;
57 MmioWrite32 (Addr, RegData);
58 }
59
60 STATIC
61 VOID
RegSet(IN EFI_PHYSICAL_ADDRESS Addr,IN UINT32 Data,IN UINT32 Mask)62 RegSet (
63 IN EFI_PHYSICAL_ADDRESS Addr,
64 IN UINT32 Data,
65 IN UINT32 Mask
66 )
67 {
68 DEBUG((DEBUG_INFO, "Write to address = %10x, data = %10x (mask = %10x)-\n",
69 Addr, Data, Mask));
70 DEBUG((DEBUG_INFO, "old value = %10x ==>\n", MmioRead32 (Addr)));
71 RegSetSilent (Addr, Data, Mask);
72 DEBUG((DEBUG_INFO, "new value %10x\n", MmioRead32 (Addr)));
73 }
74
75 STATIC
76 VOID
UtmiPhyPowerDown(IN UINT32 UtmiIndex,IN EFI_PHYSICAL_ADDRESS UtmiBaseAddr,IN EFI_PHYSICAL_ADDRESS UsbCfgAddr,IN EFI_PHYSICAL_ADDRESS UtmiCfgAddr,IN UINT32 UtmiPhyPort)77 UtmiPhyPowerDown (
78 IN UINT32 UtmiIndex,
79 IN EFI_PHYSICAL_ADDRESS UtmiBaseAddr,
80 IN EFI_PHYSICAL_ADDRESS UsbCfgAddr,
81 IN EFI_PHYSICAL_ADDRESS UtmiCfgAddr,
82 IN UINT32 UtmiPhyPort
83 )
84 {
85 UINT32 Mask, Data;
86
87 DEBUG((DEBUG_INFO, "UtmiPhy: stage: UTMI %d - Power down transceiver(power down Phy)\n",
88 UtmiIndex));
89 DEBUG((DEBUG_INFO, "UtmiPhy: stage: Power down PLL, and SuspendDM\n"));
90 /* Power down UTMI PHY */
91 RegSet (UtmiCfgAddr, 0x0 << UTMI_PHY_CFG_PU_OFFSET, UTMI_PHY_CFG_PU_MASK);
92 /* Config USB3 Device UTMI enable */
93 Mask = UTMI_USB_CFG_DEVICE_EN_MASK;
94
95 /*
96 * Prior to PHY init, configure mux for Device
97 * (Device can be connected to UTMI0 or to UTMI1)
98 */
99 if (UtmiPhyPort == UTMI_PHY_TO_USB_DEVICE0) {
100 Data = 0x1 << UTMI_USB_CFG_DEVICE_EN_OFFSET;
101 /* Config USB3 Device UTMI MUX */
102 Mask |= UTMI_USB_CFG_DEVICE_MUX_MASK;
103 Data |= UtmiIndex << UTMI_USB_CFG_DEVICE_MUX_OFFSET;
104 } else {
105 Data = 0x0 << UTMI_USB_CFG_DEVICE_EN_OFFSET;
106 }
107
108 /* Set Test suspendm mode */
109 Mask = UTMI_CTRL_STATUS0_SUSPENDM_MASK;
110 Data = 0x1 << UTMI_CTRL_STATUS0_SUSPENDM_OFFSET;
111 /* Enable Test UTMI select */
112 Mask |= UTMI_CTRL_STATUS0_TEST_SEL_MASK;
113 Data |= 0x1 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET;
114 RegSet (UtmiBaseAddr + UTMI_CTRL_STATUS0_REG, Data, Mask);
115
116 /* Wait for UTMI power down */
117 MicroSecondDelay (1000);
118 }
119
120 STATIC
121 VOID
UtmiPhyConfig(IN UINT32 UtmiIndex,IN EFI_PHYSICAL_ADDRESS UtmiBaseAddr,IN EFI_PHYSICAL_ADDRESS UsbCfgAddr,IN EFI_PHYSICAL_ADDRESS UtmiCfgAddr,IN UINT32 UtmiPhyPort)122 UtmiPhyConfig (
123 IN UINT32 UtmiIndex,
124 IN EFI_PHYSICAL_ADDRESS UtmiBaseAddr,
125 IN EFI_PHYSICAL_ADDRESS UsbCfgAddr,
126 IN EFI_PHYSICAL_ADDRESS UtmiCfgAddr,
127 IN UINT32 UtmiPhyPort
128 )
129 {
130 UINT32 Mask, Data;
131
132 DEBUG((DEBUG_INFO, "UtmiPhy: stage: Configure UTMI PHY %d registers\n",
133 UtmiIndex));
134 /* Reference Clock Divider Select */
135 Mask = UTMI_PLL_CTRL_REFDIV_MASK;
136 Data = 0x5 << UTMI_PLL_CTRL_REFDIV_OFFSET;
137 /* Feedback Clock Divider Select - 90 for 25Mhz */
138 Mask |= UTMI_PLL_CTRL_FBDIV_MASK;
139 Data |= 0x60 << UTMI_PLL_CTRL_FBDIV_OFFSET;
140 /* Select LPFR - 0x0 for 25Mhz/5=5Mhz */
141 Mask |= UTMI_PLL_CTRL_SEL_LPFR_MASK;
142 Data |= 0x0 << UTMI_PLL_CTRL_SEL_LPFR_OFFSET;
143 RegSet (UtmiBaseAddr + UTMI_PLL_CTRL_REG, Data, Mask);
144
145 /* Impedance Calibration Threshold Setting */
146 RegSet (UtmiBaseAddr + UTMI_CALIB_CTRL_REG,
147 0x6 << UTMI_CALIB_CTRL_IMPCAL_VTH_OFFSET,
148 UTMI_CALIB_CTRL_IMPCAL_VTH_MASK);
149
150 /* Set LS TX driver strength coarse control */
151 Mask = UTMI_TX_CH_CTRL_DRV_EN_LS_MASK;
152 Data = 0x3 << UTMI_TX_CH_CTRL_DRV_EN_LS_OFFSET;
153 /* Set LS TX driver fine adjustment */
154 Mask |= UTMI_TX_CH_CTRL_IMP_SEL_LS_MASK;
155 Data |= 0x3 << UTMI_TX_CH_CTRL_IMP_SEL_LS_OFFSET;
156 RegSet (UtmiBaseAddr + UTMI_TX_CH_CTRL_REG, Data, Mask);
157
158 /* Enable SQ */
159 Mask = UTMI_RX_CH_CTRL0_SQ_DET_MASK;
160 Data = 0x0 << UTMI_RX_CH_CTRL0_SQ_DET_OFFSET;
161 /* Enable analog squelch detect */
162 Mask |= UTMI_RX_CH_CTRL0_SQ_ANA_DTC_MASK;
163 Data |= 0x1 << UTMI_RX_CH_CTRL0_SQ_ANA_DTC_OFFSET;
164 RegSet (UtmiBaseAddr + UTMI_RX_CH_CTRL0_REG, Data, Mask);
165
166 /* Set External squelch calibration number */
167 Mask = UTMI_RX_CH_CTRL1_SQ_AMP_CAL_MASK;
168 Data = 0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_OFFSET;
169 /* Enable the External squelch calibration */
170 Mask |= UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_MASK;
171 Data |= 0x1 << UTMI_RX_CH_CTRL1_SQ_AMP_CAL_EN_OFFSET;
172 RegSet (UtmiBaseAddr + UTMI_RX_CH_CTRL1_REG, Data, Mask);
173
174 /* Set Control VDAT Reference Voltage - 0.325V */
175 Mask = UTMI_CHGDTC_CTRL_VDAT_MASK;
176 Data = 0x1 << UTMI_CHGDTC_CTRL_VDAT_OFFSET;
177 /* Set Control VSRC Reference Voltage - 0.6V */
178 Mask |= UTMI_CHGDTC_CTRL_VSRC_MASK;
179 Data |= 0x1 << UTMI_CHGDTC_CTRL_VSRC_OFFSET;
180 RegSet (UtmiBaseAddr + UTMI_CHGDTC_CTRL_REG, Data, Mask);
181 }
182
183 STATIC
184 UINTN
UtmiPhyPowerUp(IN UINT32 UtmiIndex,IN EFI_PHYSICAL_ADDRESS UtmiBaseAddr,IN EFI_PHYSICAL_ADDRESS UsbCfgAddr,IN EFI_PHYSICAL_ADDRESS UtmiCfgAddr,IN UINT32 UtmiPhyPort)185 UtmiPhyPowerUp (
186 IN UINT32 UtmiIndex,
187 IN EFI_PHYSICAL_ADDRESS UtmiBaseAddr,
188 IN EFI_PHYSICAL_ADDRESS UsbCfgAddr,
189 IN EFI_PHYSICAL_ADDRESS UtmiCfgAddr,
190 IN UINT32 UtmiPhyPort
191 )
192 {
193 EFI_STATUS Status;
194 UINT32 Data;
195
196 DEBUG((DEBUG_INFO, "UtmiPhy: stage: UTMI %d - Power up transceiver(Power up Phy)\n",
197 UtmiIndex));
198 DEBUG((DEBUG_INFO, "UtmiPhy: stage: exit SuspendDM\n"));
199 /* Power up UTMI PHY */
200 RegSet (UtmiCfgAddr, 0x1 << UTMI_PHY_CFG_PU_OFFSET, UTMI_PHY_CFG_PU_MASK);
201 /* Disable Test UTMI select */
202 RegSet (UtmiBaseAddr + UTMI_CTRL_STATUS0_REG,
203 0x0 << UTMI_CTRL_STATUS0_TEST_SEL_OFFSET,
204 UTMI_CTRL_STATUS0_TEST_SEL_MASK);
205
206 DEBUG((DEBUG_INFO, "UtmiPhy: stage: Wait for PLL and impedance calibration done, and PLL ready\n"));
207
208 /* Delay 10ms */
209 MicroSecondDelay (10000);
210
211 Data = MmioRead32 (UtmiBaseAddr + UTMI_CALIB_CTRL_REG);
212 if ((Data & UTMI_CALIB_CTRL_IMPCAL_DONE_MASK) == 0) {
213 DEBUG((DEBUG_ERROR, "UtmiPhy: Impedance calibration is not done\n"));
214 Status = EFI_D_ERROR;
215 }
216 if ((Data & UTMI_CALIB_CTRL_PLLCAL_DONE_MASK) == 0) {
217 DEBUG((DEBUG_ERROR, "UtmiPhy: PLL calibration is not done\n"));
218 Status = EFI_D_ERROR;
219 }
220 Data = MmioRead32 (UtmiBaseAddr + UTMI_PLL_CTRL_REG);
221 if ((Data & UTMI_PLL_CTRL_PLL_RDY_MASK) == 0) {
222 DEBUG((DEBUG_ERROR, "UtmiPhy: PLL is not ready\n"));
223 Status = EFI_D_ERROR;
224 }
225
226 return Status;
227 }
228
229 /*
230 * Cp110UtmiPhyInit initializes the UTMI PHY
231 * the init split in 3 parts:
232 * 1. Power down transceiver and PLL
233 * 2. UTMI PHY configure
234 * 3. Power up transceiver and PLL
235 */
236 STATIC
237 VOID
Cp110UtmiPhyInit(IN UINT32 UtmiPhyCount,IN UTMI_PHY_DATA * UtmiData)238 Cp110UtmiPhyInit (
239 IN UINT32 UtmiPhyCount,
240 IN UTMI_PHY_DATA *UtmiData
241 )
242 {
243 UINT32 i;
244
245 for (i = 0; i < UtmiPhyCount; i++) {
246 UtmiPhyPowerDown(i, UtmiData[i].UtmiBaseAddr,
247 UtmiData[i].UsbCfgAddr, UtmiData[i].UtmiCfgAddr,
248 UtmiData[i].UtmiPhyPort);
249 }
250
251 /* Power down PLL */
252 DEBUG((DEBUG_INFO, "UtmiPhy: stage: PHY power down PLL\n"));
253 RegSet (UtmiData[0].UsbCfgAddr, 0x0 << UTMI_USB_CFG_PLL_OFFSET,
254 UTMI_USB_CFG_PLL_MASK);
255
256 for (i = 0; i < UtmiPhyCount; i++) {
257 UtmiPhyConfig(i, UtmiData[i].UtmiBaseAddr,
258 UtmiData[i].UsbCfgAddr, UtmiData[i].UtmiCfgAddr,
259 UtmiData[i].UtmiPhyPort);
260 }
261
262 for (i = 0; i < UtmiPhyCount; i++) {
263 if (EFI_ERROR(UtmiPhyPowerUp(i, UtmiData[i].UtmiBaseAddr,
264 UtmiData[i].UsbCfgAddr, UtmiData[i].UtmiCfgAddr,
265 UtmiData[i].UtmiPhyPort))) {
266 DEBUG((DEBUG_ERROR, "UtmiPhy: Failed to initialize UTMI PHY %d\n", i));
267 continue;
268 }
269 DEBUG((DEBUG_ERROR, "UTMI PHY %d initialized to ", i));
270
271 if (UtmiData[i].UtmiPhyPort == UTMI_PHY_TO_USB_DEVICE0)
272 DEBUG((DEBUG_ERROR, "USB Device\n"));
273 else
274 DEBUG((DEBUG_ERROR, "USB Host%d\n", UtmiData[i].UtmiPhyPort));
275 }
276
277 /* Power up PLL */
278 DEBUG((DEBUG_INFO, "UtmiPhy: stage: PHY power up PLL\n"));
279 RegSet (UtmiData[0].UsbCfgAddr, 0x1 << UTMI_USB_CFG_PLL_OFFSET,
280 UTMI_USB_CFG_PLL_MASK);
281 }
282
283 EFI_STATUS
UtmiPhyInit(VOID)284 UtmiPhyInit (
285 VOID
286 )
287 {
288 EFI_STATUS Status;
289 UTMI_PHY_DATA UtmiData[PcdGet32 (PcdUtmiPhyCount)];
290 EFI_PHYSICAL_ADDRESS RegUtmiUnit[PcdGet32 (PcdUtmiPhyCount)];
291 EFI_PHYSICAL_ADDRESS RegUsbCfg[PcdGet32 (PcdUtmiPhyCount)];
292 EFI_PHYSICAL_ADDRESS RegUtmiCfg[PcdGet32 (PcdUtmiPhyCount)];
293 UINTN UtmiPort[PcdGet32 (PcdUtmiPhyCount)];
294 UINTN i, Count;
295
296 Count = PcdGet32 (PcdUtmiPhyCount);
297 if (Count == 0) {
298 /* No UTMI PHY on platform */
299 return EFI_SUCCESS;
300 }
301
302 DEBUG((DEBUG_INFO, "UtmiPhy: Initialize USB UTMI PHYs\n"));
303 /* Parse UtmiPhy PCDs */
304 Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdUtmiPhyRegUtmiUnit),
305 Count, RegUtmiUnit, NULL);
306 if (EFI_ERROR(Status)) {
307 DEBUG((DEBUG_ERROR, "UtmiPhy: Wrong PcdUtmiPhyRegUtmiUnit format\n"));
308 return EFI_INVALID_PARAMETER;
309 }
310
311 Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdUtmiPhyRegUsbCfg),
312 Count, RegUsbCfg, NULL);
313 if (EFI_ERROR(Status)) {
314 DEBUG((DEBUG_ERROR, "UtmiPhy: Wrong PcdUtmiPhyRegUsbCfg format\n"));
315 return EFI_INVALID_PARAMETER;
316 }
317
318 Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdUtmiPhyRegUtmiCfg),
319 Count, RegUtmiCfg, NULL);
320 if (EFI_ERROR(Status)) {
321 DEBUG((DEBUG_ERROR, "UtmiPhy: Wrong PcdUtmiPhyRegUtmiCfg format\n"));
322 return EFI_INVALID_PARAMETER;
323 }
324
325 Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdUtmiPhyUtmiPort),
326 Count, UtmiPort, NULL);
327 if (EFI_ERROR(Status)) {
328 DEBUG((DEBUG_ERROR, "UtmiPhy: Wrong PcdUtmiPhyUtmiPort format\n"));
329 return EFI_INVALID_PARAMETER;
330 }
331
332 for (i = 0 ; i < Count ; i++) {
333 /* Get base address of UTMI phy */
334 UtmiData[i].UtmiBaseAddr = RegUtmiUnit[i];
335
336 /* Get usb config address */
337 UtmiData[i].UsbCfgAddr = RegUsbCfg[i];
338
339 /* Get UTMI config address */
340 UtmiData[i].UtmiCfgAddr = RegUtmiCfg[i];
341
342 /*
343 * Get the usb port number, which will be used to check if
344 * the utmi connected to host or device
345 */
346 UtmiData[i].UtmiPhyPort = UtmiPort[i];
347 }
348
349 /* Currently only Cp110 is supported */
350 Cp110UtmiPhyInit (Count, UtmiData);
351
352 return EFI_SUCCESS;
353 }
354