• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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