1 /*******************************************************************************
2 Copyright (C) 2016 Marvell International Ltd.
3 Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
4 
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 *******************************************************************************/
8 
9 #include "XenonSdhci.h"
10 
11 STATIC
12 VOID
XenonReadVersion(IN EFI_PCI_IO_PROTOCOL * PciIo,OUT UINT32 * ControllerVersion)13 XenonReadVersion (
14   IN  EFI_PCI_IO_PROTOCOL   *PciIo,
15   OUT UINT32 *ControllerVersion
16   )
17 {
18   XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_CTRL_VER, TRUE, SDHC_REG_SIZE_2B, ControllerVersion);
19 }
20 
21 // Auto Clock Gating
22 STATIC
23 VOID
XenonSetAcg(IN EFI_PCI_IO_PROTOCOL * PciIo,IN BOOLEAN Enable)24 XenonSetAcg (
25   IN EFI_PCI_IO_PROTOCOL   *PciIo,
26   IN BOOLEAN Enable
27   )
28 {
29   UINT32 Var;
30 
31   XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, TRUE, SDHC_REG_SIZE_4B, &Var);
32 
33   if (Enable) {
34     Var &= ~AUTO_CLKGATE_DISABLE_MASK;
35   } else {
36     Var |= AUTO_CLKGATE_DISABLE_MASK;
37   }
38 
39   XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, FALSE, SDHC_REG_SIZE_4B, &Var);
40 }
41 
42 STATIC
43 VOID
XenonSetSlot(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT8 Slot,IN BOOLEAN Enable)44 XenonSetSlot (
45   IN EFI_PCI_IO_PROTOCOL *PciIo,
46   IN UINT8 Slot,
47   IN BOOLEAN Enable
48   )
49 {
50   UINT32 Var;
51 
52   XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, TRUE, SDHC_REG_SIZE_4B, &Var);
53   if (Enable) {
54     Var |= ((0x1 << Slot) << SLOT_ENABLE_SHIFT);
55   } else {
56     Var &= ~((0x1 << Slot) << SLOT_ENABLE_SHIFT);
57   }
58 
59   // Enable SDCLK off while idle
60   Var |= SDCLK_IDLEOFF_ENABLE_MASK;
61 
62   XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, FALSE, SDHC_REG_SIZE_4B, &Var);
63 }
64 
65 //
66 // Stub function, which will in future be responsible for
67 // setting SDIO controller in either HIGH (if Voltage parameter
68 // is equal 1) or LOW (if Voltage is equal 0)
69 //
70 STATIC
71 VOID
XenonSetSdio(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINTN Voltage)72 XenonSetSdio (
73   IN EFI_PCI_IO_PROTOCOL *PciIo,
74   IN UINTN Voltage
75   )
76 {
77   // Currently SDIO isn't supported
78   return;
79 }
80 
81 STATIC
82 VOID
XenonSetPower(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT32 Vcc,IN UINT32 Vccq,IN UINT8 Mode)83 XenonSetPower (
84   IN EFI_PCI_IO_PROTOCOL *PciIo,
85   IN UINT32 Vcc,
86   IN UINT32 Vccq,
87   IN UINT8 Mode
88   )
89 {
90   UINT8 Pwr = 0;
91 
92   // Below statement calls routine to set voltage for SDIO devices in either HIGH (1) or LOW (0) mode
93   switch (Vcc) {
94   case MMC_VDD_165_195:
95     Pwr = SDHCI_POWER_180;
96     if (Mode == XENON_MMC_MODE_SD_SDIO) {
97       XenonSetSdio (PciIo, 0);
98     }
99     break;
100   case MMC_VDD_29_30:
101   case MMC_VDD_30_31:
102     Pwr = SDHCI_POWER_300;
103     if (Mode == XENON_MMC_MODE_SD_SDIO) {
104       XenonSetSdio (PciIo, 1);
105     }
106     break;
107   case MMC_VDD_32_33:
108   case MMC_VDD_33_34:
109     Pwr = SDHCI_POWER_330;
110     if (Mode == XENON_MMC_MODE_SD_SDIO) {
111       XenonSetSdio (PciIo, 1);
112     }
113     break;
114   default:
115     DEBUG((DEBUG_ERROR, "SD/MMC: Does not support power mode(0x%X)\n", Vcc));
116     break;
117   }
118 
119   if (Pwr == 0) {
120     XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_POWER_CTRL, FALSE, SDHC_REG_SIZE_1B, &Pwr);
121     return;
122   }
123 
124   Pwr |= SDHCI_POWER_ON;
125 
126   XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_POWER_CTRL, FALSE, SDHC_REG_SIZE_1B, &Pwr);
127 }
128 
129 UINTN
XenonSetClk(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT32 Clock)130 XenonSetClk (
131   IN EFI_PCI_IO_PROTOCOL   *PciIo,
132   IN UINT32 Clock
133   )
134 {
135   UINT32 Div;
136   UINT32 Clk;
137   UINT32 Retry;
138   UINT32 ControllerVersion;
139   UINT16 Value = 0;
140 
141   XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &Value);
142 
143   if (Clock == 0) {
144     return 0;
145   }
146 
147   XenonReadVersion (PciIo, &ControllerVersion);
148 
149   if (ControllerVersion >= SDHCI_SPEC_300) {
150     // Version 3.00 Divisors must be a multiple of 2
151     if (XENON_MMC_MAX_CLK <= Clock) {
152       Div = 1;
153     } else {
154       for (Div = 2; Div < SDHCI_MAX_DIV_SPEC_300; Div += 2) {
155         if ((XENON_MMC_MAX_CLK / Div) <= Clock)
156           break;
157       }
158     }
159   } else {
160     // Version 2.00 Divisors must be a power of 2
161     for (Div = 1; Div < SDHCI_MAX_DIV_SPEC_200; Div *= 2) {
162       if ((XENON_MMC_MAX_CLK / Div) <= Clock)
163         break;
164     }
165   }
166   Div >>= 1;
167 
168   Clk = (Div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
169   Clk |= ((Div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) << SDHCI_DIVIDER_HI_SHIFT;
170   Clk |= SDHCI_CLOCK_INT_EN;
171 
172   XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &Clk);
173 
174   //
175   // Poll for internal controller clock to be stabilised
176   // Wait up to 200us for this to occur
177   //
178   Retry = 200;
179 
180   do {
181     XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_CLOCK_CTRL, TRUE, SDHC_REG_SIZE_2B, &Clk);
182     if (Retry == 0) {
183       DEBUG((DEBUG_ERROR, "SD/MMC: Internal Clock never stabilised\n"));
184       return -1;
185     }
186 
187     Retry--;
188 
189     // Wait for internal clock to be stabilised
190     gBS->Stall (1);
191 
192   } while (!(Clk & SDHCI_CLOCK_INT_STABLE));
193 
194   Clk |= SDHCI_CLOCK_CARD_EN;
195   XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &Clk);
196 
197   return 0;
198 }
199 
200 VOID
XenonPhyInit(IN EFI_PCI_IO_PROTOCOL * PciIo)201 XenonPhyInit (
202   IN EFI_PCI_IO_PROTOCOL   *PciIo
203   )
204 {
205   UINT32 Var, Wait, Time;
206   UINT32 Clock = XENON_MMC_MAX_CLK;
207 
208   // Init PHY
209   XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var);
210   Var |= PHY_INITIALIZAION;
211   XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, SDHC_REG_SIZE_4B, &Var);
212 
213   // Add duration of FC_SYNC_RST
214   Wait = ((Var >> FC_SYNC_RST_DURATION_SHIFT) & FC_SYNC_RST_DURATION_MASK);
215 
216   // Add interval between FC_SYNC_EN and FC_SYNC_RST
217   Wait += ((Var >> FC_SYNC_RST_EN_DURATION_SHIFT) & FC_SYNC_RST_EN_DURATION_MASK);
218 
219   // Add duration of asserting FC_SYNC_EN
220   Wait += ((Var >> FC_SYNC_EN_DURATION_SHIFT) & FC_SYNC_EN_DURATION_MASK);
221 
222   // Add duration of Waiting for PHY
223   Wait += ((Var >> WAIT_CYCLE_BEFORE_USING_SHIFT) & WAIT_CYCLE_BEFORE_USING_MASK);
224 
225   // 4 addtional bus clock and 4 AXI bus clock are required left shift 20 bits
226   Wait += 8;
227   Wait <<= 20;
228 
229   // Use the possibly slowest bus frequency value
230   if (Clock == 0) {
231     Clock = XENON_MMC_MIN_CLK;
232   }
233 
234   // Get the Wait Time in unit of ms
235   Wait = Wait / Clock;
236   Wait++;
237 
238   // Poll for host eMMC PHY init to complete, wait up to 100us
239   Time = 100;
240   while (Time--) {
241     Var = XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var);
242     Var &= PHY_INITIALIZAION;
243     if (!Var) {
244       break;
245     }
246 
247     // Wait for host eMMC PHY init to complete
248     gBS->Stall (1);
249   }
250 
251   if (Time <= 0) {
252     DEBUG((DEBUG_ERROR, "SD/MMC: Failed to init MMC PHY in Time\n"));
253     return;
254   }
255 
256   return;
257 }
258 
259 //
260 // Enable eMMC PHY HW DLL
261 // DLL should be enabled and stable before HS200/SDR104 tuning,
262 // and before HS400 data strobe setting.
263 //
264 STATIC
265 EFI_STATUS
EmmcPhyEnableDll(IN EFI_PCI_IO_PROTOCOL * PciIo)266 EmmcPhyEnableDll (
267   IN EFI_PCI_IO_PROTOCOL   *PciIo
268   )
269 {
270   UINT32 Var;
271   UINT16 SlotState;
272   UINT8 Retry;
273 
274   XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_DLL_CONTROL, TRUE, SDHC_REG_SIZE_4B, &Var);
275   if (Var & DLL_ENABLE) {
276     return EFI_SUCCESS;
277   }
278 
279   // Enable DLL
280   Var |= (DLL_ENABLE | DLL_FAST_LOCK);
281 
282   //
283   // Set Phase as 90 degree, which is most common value.
284   //
285   Var &= ~((DLL_PHASE_MASK << DLL_PHSEL0_SHIFT) |
286            (DLL_PHASE_MASK << DLL_PHSEL1_SHIFT));
287   Var |= ((DLL_PHASE_90_DEGREE << DLL_PHSEL0_SHIFT) |
288           (DLL_PHASE_90_DEGREE << DLL_PHSEL1_SHIFT));
289 
290   Var &= ~(DLL_BYPASS_EN | DLL_REFCLK_SEL);
291   Var |= DLL_UPDATE;
292   XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_DLL_CONTROL, FALSE, SDHC_REG_SIZE_4B, &Var);
293 
294   // Wait max 32 ms for the DLL to lock
295   Retry = 32;
296   do {
297     XenonHcRwMmio (PciIo, SD_BAR_INDEX, XENON_SLOT_EXT_PRESENT_STATE, TRUE, SDHC_REG_SIZE_2B, &SlotState);
298 
299     if (Retry == 0) {
300       DEBUG ((DEBUG_ERROR, "SD/MMC: Fail to lock DLL\n"));
301       return EFI_TIMEOUT;
302     }
303 
304     gBS->Stall (1000);
305     Retry--;
306 
307   } while (!(SlotState & DLL_LOCK_STATE));
308 
309   return EFI_SUCCESS;
310 }
311 
312 //
313 // Config to eMMC PHY to prepare for tuning.
314 // Enable HW DLL and set the TUNING_STEP
315 //
316 STATIC
317 EFI_STATUS
EmmcPhyConfigTuning(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT8 TuningStepDivisor)318 EmmcPhyConfigTuning (
319   IN EFI_PCI_IO_PROTOCOL   *PciIo,
320   IN UINT8 TuningStepDivisor
321   )
322 {
323   UINT32 Var, TuningStep;
324   EFI_STATUS Status;
325 
326   Status = EmmcPhyEnableDll (PciIo);
327   if (EFI_ERROR (Status)) {
328     return Status;
329   }
330 
331   // Achieve TUNING_STEP with HW DLL help
332   XenonHcRwMmio (PciIo, SD_BAR_INDEX, XENON_SLOT_DLL_CUR_DLY_VAL, TRUE, SDHC_REG_SIZE_4B, &Var);
333   TuningStep = Var / TuningStepDivisor;
334   if (TuningStep > TUNING_STEP_MASK) {
335       DEBUG ((DEBUG_ERROR, "HS200 TUNING_STEP %d is larger than MAX value\n", TuningStep));
336     TuningStep = TUNING_STEP_MASK;
337   }
338 
339   // Set TUNING_STEP for later tuning
340   XenonHcRwMmio (PciIo, SD_BAR_INDEX, XENON_SLOT_OP_STATUS_CTRL, TRUE, SDHC_REG_SIZE_4B, &Var);
341   Var &= ~(TUN_CONSECUTIVE_TIMES_MASK << TUN_CONSECUTIVE_TIMES_SHIFT);
342   Var |= (TUN_CONSECUTIVE_TIMES << TUN_CONSECUTIVE_TIMES_SHIFT);
343   Var &= ~(TUNING_STEP_MASK << TUNING_STEP_SHIFT);
344   Var |= (TuningStep << TUNING_STEP_SHIFT);
345   XenonHcRwMmio (PciIo, SD_BAR_INDEX, XENON_SLOT_OP_STATUS_CTRL, FALSE, SDHC_REG_SIZE_4B, &Var);
346 
347   return EFI_SUCCESS;
348 }
349 
350 STATIC
351 BOOLEAN
XenonPhySlowMode(IN EFI_PCI_IO_PROTOCOL * PciIo,IN SD_MMC_BUS_MODE Timing,IN BOOLEAN SlowMode)352 XenonPhySlowMode (
353   IN EFI_PCI_IO_PROTOCOL   *PciIo,
354   IN SD_MMC_BUS_MODE        Timing,
355   IN BOOLEAN SlowMode
356   )
357 {
358   UINT32 Var = 0;
359 
360   // Check if Slow Mode is required in lower speed mode in SDR mode
361   if (((Timing == SdMmcUhsSdr50) ||
362        (Timing == SdMmcUhsSdr25) ||
363        (Timing == SdMmcUhsSdr12) ||
364        (Timing == SdMmcSdDs)  ||
365        (Timing == SdMmcSdHs)  ||
366        (Timing == SdMmcMmcHsDdr) ||
367        (Timing == SdMmcMmcHsSdr) ||
368        (Timing == SdMmcMmcLegacy)) && SlowMode) {
369     Var = QSN_PHASE_SLOW_MODE_BIT;
370     XenonHcOrMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, SDHC_REG_SIZE_4B, &Var);
371     return TRUE;
372   }
373 
374   Var = ~QSN_PHASE_SLOW_MODE_BIT;
375   XenonHcAndMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, SDHC_REG_SIZE_4B, &Var);
376   return FALSE;
377 }
378 
379 EFI_STATUS
XenonSetPhy(IN EFI_PCI_IO_PROTOCOL * PciIo,IN BOOLEAN SlowMode,IN UINT8 TuningStepDivisor,IN SD_MMC_BUS_MODE Timing)380 XenonSetPhy (
381   IN EFI_PCI_IO_PROTOCOL   *PciIo,
382   IN BOOLEAN               SlowMode,
383   IN UINT8                 TuningStepDivisor,
384   IN SD_MMC_BUS_MODE       Timing
385   )
386 {
387   UINT32 Var = 0;
388   UINT16 ClkCtrl;
389 
390   // Setup pad, bit[28] and bits[26:24]
391   Var = OEN_QSN | FC_QSP_RECEN | FC_CMD_RECEN | FC_DQ_RECEN;
392   // All FC_XX_RECEIVCE should be set as CMOS Type
393   Var |= FC_ALL_CMOS_RECEIVER;
394   XenonHcOrMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL, SDHC_REG_SIZE_4B, &Var);
395 
396   // Set CMD and DQ Pull Up
397   XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL1, TRUE, SDHC_REG_SIZE_4B, &Var);
398   Var |= (EMMC5_1_FC_CMD_PU | EMMC5_1_FC_DQ_PU);
399   Var &= ~(EMMC5_1_FC_CMD_PD | EMMC5_1_FC_DQ_PD);
400   XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL1, FALSE, SDHC_REG_SIZE_4B, &Var);
401 
402   if (Timing == SdMmcUhsSdr12 || Timing == SdMmcSdDs) {
403     if (SlowMode) {
404       XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var);
405       Var |= QSN_PHASE_SLOW_MODE_BIT;
406       XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, SDHC_REG_SIZE_4B, &Var);
407     }
408 
409     goto PhyInit;
410   }
411 
412   //
413   // If Timing belongs to high speed, set bit[17] of
414   // EMMC_PHY_TIMING_ADJUST register
415   //
416   if ((Timing == SdMmcMmcHs400) ||
417       (Timing == SdMmcMmcHs200) ||
418       (Timing == SdMmcUhsDdr50) ||
419       (Timing == SdMmcUhsSdr50) ||
420       (Timing == SdMmcUhsSdr104) ||
421       (Timing == SdMmcUhsSdr25)) {
422     Var = ~OUTPUT_QSN_PHASE_SELECT;
423     XenonHcAndMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, SDHC_REG_SIZE_4B, &Var);
424   }
425 
426   if (XenonPhySlowMode (PciIo, Timing, SlowMode)) {
427     goto PhyInit;
428   }
429 
430   // Set default ZNR and ZPR value
431   XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL2, TRUE, SDHC_REG_SIZE_4B, &Var);
432   Var &= ~((ZNR_MASK << ZNR_SHIFT) | ZPR_MASK);
433   Var |= ((ZNR_DEF_VALUE << ZNR_SHIFT) | ZPR_DEF_VALUE);
434   XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL2, FALSE, SDHC_REG_SIZE_4B, &Var);
435 
436   // Need to disable the clock to set EMMC_PHY_FUNC_CONTROL register
437   ClkCtrl = ~SDHCI_CLOCK_CARD_EN;
438   XenonHcAndMmio (PciIo, SD_BAR_INDEX, SDHC_CLOCK_CTRL, SDHC_REG_SIZE_2B, &ClkCtrl);
439 
440   if ((Timing == SdMmcMmcHs400) ||
441       (Timing == SdMmcUhsDdr50)) {
442     Var = (DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE;
443     XenonHcOrMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, SDHC_REG_SIZE_4B, &Var);
444   } else {
445     Var = ~((DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE);
446     XenonHcAndMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, SDHC_REG_SIZE_4B, &Var);
447   }
448 
449   if (Timing == SdMmcMmcHs400) {
450     Var = ~DQ_ASYNC_MODE;
451     XenonHcAndMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, SDHC_REG_SIZE_4B, &Var);
452   } else {
453     Var = DQ_ASYNC_MODE;
454     XenonHcOrMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, SDHC_REG_SIZE_4B, &Var);
455   }
456 
457   // Enable bus clock
458   ClkCtrl = SDHCI_CLOCK_CARD_EN;
459   XenonHcOrMmio (PciIo, SD_BAR_INDEX, SDHC_CLOCK_CTRL, SDHC_REG_SIZE_2B, &ClkCtrl);
460 
461   // Delay 200us to wait for the completion of bus clock
462   gBS->Stall (200);
463 
464   if (Timing == SdMmcMmcHs400) {
465     Var = LOGIC_TIMING_VALUE;
466     XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_LOGIC_TIMING_ADJUST, FALSE, SDHC_REG_SIZE_4B, &Var);
467   } else {
468     // Disable data strobe
469     Var = ~ENABLE_DATA_STROBE;
470     XenonHcAndMmio (PciIo, SD_BAR_INDEX, XENON_SLOT_EMMC_CTRL, SDHC_REG_SIZE_4B, &Var);
471   }
472 
473 PhyInit:
474   XenonPhyInit (PciIo);
475 
476   if ((Timing == SdMmcMmcHs200) ||
477       (Timing == SdMmcUhsSdr104)) {
478     return EmmcPhyConfigTuning (PciIo, TuningStepDivisor);
479   }
480 
481   return EFI_SUCCESS;
482 }
483 
484 STATIC
485 VOID
XenonConfigureInterrupts(IN EFI_PCI_IO_PROTOCOL * PciIo)486 XenonConfigureInterrupts (
487   IN EFI_PCI_IO_PROTOCOL *PciIo
488   )
489 {
490   UINT32 Var;
491 
492   // Clear interrupt status
493   Var = SDHC_CLR_ALL_IRQ_MASK;
494   XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_NOR_INT_STS, FALSE, SDHC_REG_SIZE_4B, &Var);
495   XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_NOR_INT_STS, FALSE, SDHC_REG_SIZE_4B, &Var);
496 
497   // Enable only interrupts served by the SD controller
498   Var = SDHC_CLR_ALL_IRQ_MASK & ~(NOR_INT_STS_CARD_INS | NOR_INT_STS_CARD_INT);
499   XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_NOR_INT_STS_EN, FALSE, SDHC_REG_SIZE_4B, &Var);
500 
501   // Mask all sdhci interrupt sources
502   Var = SDHC_CLR_ALL_IRQ_MASK & ~NOR_INT_SIG_EN_CARD_INT;
503   XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_NOR_INT_SIG_EN, FALSE, SDHC_REG_SIZE_4B, &Var);
504 }
505 
506 // Enable Parallel Transfer Mode
507 STATIC
508 VOID
XenonSetParallelTransfer(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT8 Slot,IN BOOLEAN Enable)509 XenonSetParallelTransfer (
510   IN EFI_PCI_IO_PROTOCOL *PciIo,
511   IN UINT8 Slot,
512   IN BOOLEAN Enable
513   )
514 {
515   UINT32 Var;
516 
517   XenonHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SYS_EXT_OP_CTRL, TRUE, SDHC_REG_SIZE_4B, &Var);
518 
519   if (Enable) {
520     Var |= (0x1 << Slot);
521   } else {
522     Var &= ~(0x1 << Slot);
523   }
524 
525   // Mask command conflict error
526   Var |= MASK_CMD_CONFLICT_ERR;
527 
528   XenonHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SYS_EXT_OP_CTRL, FALSE, SDHC_REG_SIZE_4B, &Var);
529 }
530 
531 STATIC
532 VOID
XenonSetTuning(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT8 Slot,IN BOOLEAN Enable)533 XenonSetTuning (
534   IN EFI_PCI_IO_PROTOCOL   *PciIo,
535   IN UINT8 Slot,
536   IN BOOLEAN Enable
537   )
538 {
539   UINT32 Var;
540 
541   // Set the Re-Tuning Request functionality
542   XenonHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SLOT_RETUNING_REQ_CTRL, TRUE, SDHC_REG_SIZE_4B, &Var);
543 
544   if (Enable) {
545     Var |= RETUNING_COMPATIBLE;
546   } else {
547     Var &= ~RETUNING_COMPATIBLE;
548   }
549 
550   XenonHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SLOT_RETUNING_REQ_CTRL, FALSE, SDHC_REG_SIZE_4B, &Var);
551 
552   // Set the Re-tuning Event Signal Enable
553   XenonHcRwMmio(PciIo, SD_BAR_INDEX, SDHCI_SIGNAL_ENABLE, TRUE, SDHC_REG_SIZE_4B, &Var);
554 
555   if (Enable) {
556     Var |= SDHCI_RETUNE_EVT_INTSIG;
557   } else {
558     Var &= ~SDHCI_RETUNE_EVT_INTSIG;
559   }
560 
561   XenonHcRwMmio(PciIo, SD_BAR_INDEX, SDHCI_SIGNAL_ENABLE, FALSE, SDHC_REG_SIZE_4B, &Var);
562 }
563 
564 VOID
XenonReset(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT8 Slot,IN UINT8 Mask)565 XenonReset (
566   IN EFI_PCI_IO_PROTOCOL *PciIo,
567   IN UINT8 Slot,
568   IN UINT8 Mask
569   )
570 {
571   UINT32 Retry = 1000;
572   UINT8 SwReset;
573 
574   SwReset = Mask;
575 
576   XenonHcRwMmio (
577           PciIo,
578           Slot,
579           SDHC_SW_RST,
580           FALSE,
581           sizeof (SwReset),
582           &SwReset
583         );
584 
585   XenonHcRwMmio (
586           PciIo,
587           Slot,
588           SDHC_SW_RST,
589           TRUE,
590           sizeof (SwReset),
591           &SwReset
592         );
593 
594   while (SwReset & Mask) {
595     if (Retry == 0) {
596       DEBUG((DEBUG_ERROR, "SD/MMC: Reset never completed\n"));
597       return;
598     }
599 
600     Retry--;
601 
602     // Poll interval for SwReset is 100us according to SDHCI spec
603     gBS-> Stall (100);
604     XenonHcRwMmio (
605             PciIo,
606             Slot,
607             SDHC_SW_RST,
608             TRUE,
609             sizeof (SwReset),
610             &SwReset
611           );
612   }
613 }
614 
615 STATIC
616 VOID
XenonTransferPio(IN UINT8 Slot,IN OUT VOID * Buffer,IN UINT16 BlockSize,IN BOOLEAN Read)617 XenonTransferPio (
618   IN UINT8 Slot,
619   IN OUT VOID *Buffer,
620   IN UINT16 BlockSize,
621   IN BOOLEAN Read
622   )
623 {
624   UINTN Index;
625   UINT8 *Offs;
626 
627   //
628   // SD stack's intrinsic functions cannot perform properly reading/writing from
629   // buffer register, that is why MmioRead/MmioWrite are used. It is temporary
630   // solution.
631   //
632   for (Index = 0; Index < BlockSize; Index += 4) {
633     Offs = (UINT8*)((UINTN)Buffer + Index);
634     if (Read) {
635       *(UINT32 *)Offs = MmioRead32 (SDHC_DAT_BUF_PORT_ADDR);
636     } else {
637       MmioWrite32 (SDHC_DAT_BUF_PORT_ADDR, *(UINT32 *)Offs);
638     }
639   }
640 }
641 
642 EFI_STATUS
XenonTransferData(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT8 Slot,IN OUT VOID * Buffer,IN UINT32 DataLen,IN UINT16 BlockSize,IN UINT16 Blocks,IN BOOLEAN Read)643 XenonTransferData (
644   IN EFI_PCI_IO_PROTOCOL *PciIo,
645   IN UINT8 Slot,
646   IN OUT VOID *Buffer,
647   IN UINT32 DataLen,
648   IN UINT16 BlockSize,
649   IN UINT16 Blocks,
650   IN BOOLEAN Read
651   )
652 {
653   UINT32 IntStatus, PresentState, Rdy, Mask, Retry, Block = 0;
654 
655   if (Buffer == NULL) {
656     return EFI_DEVICE_ERROR;
657   }
658 
659   Retry = SDHC_INT_STATUS_POLL_RETRY_DATA_TRAN;
660   Rdy = NOR_INT_STS_TX_RDY | NOR_INT_STS_RX_RDY;
661   Mask = PRESENT_STATE_BUFFER_RD_EN | PRESENT_STATE_BUFFER_WR_EN;
662 
663   do {
664     XenonHcRwMmio (
665             PciIo,
666             Slot,
667             SDHC_NOR_INT_STS,
668             TRUE,
669             sizeof (IntStatus),
670             &IntStatus
671           );
672 
673     if (IntStatus & NOR_INT_STS_ERR_INT) {
674       DEBUG((DEBUG_INFO, "SD/MMC: Error detected in status %0x\n", IntStatus));
675       return EFI_DEVICE_ERROR;
676     }
677 
678     if (IntStatus & Rdy) {
679       XenonHcRwMmio (
680               PciIo,
681               Slot,
682               SDHC_PRESENT_STATE,
683               TRUE,
684               sizeof (PresentState),
685               &PresentState
686             );
687 
688       if (!(PresentState & Mask)) {
689         continue;
690       }
691 
692       XenonHcRwMmio (
693               PciIo,
694               Slot,
695               SDHC_NOR_INT_STS,
696               FALSE,
697               sizeof (Rdy),
698               &Rdy
699             );
700 
701       XenonTransferPio (Slot, Buffer, BlockSize, Read);
702 
703       Buffer = (VOID*)((UINTN)Buffer + BlockSize);
704       if (++Block >= Blocks) {
705         break;
706       }
707     }
708 
709     if (Retry-- > 0) {
710 
711       // Poll interval for data transfer complete bit in NOR_INT_STS register is 10us
712       gBS->Stall (10);
713     } else {
714       DEBUG((DEBUG_INFO, "SD/MMC: Transfer data timeout\n"));
715       return EFI_TIMEOUT;
716     }
717   } while (!(IntStatus & NOR_INT_STS_XFER_COMPLETE));
718 
719   return EFI_SUCCESS;
720 }
721 
722 EFI_STATUS
XenonInit(IN EFI_PCI_IO_PROTOCOL * PciIo,IN BOOLEAN Support1v8,IN BOOLEAN SlowMode,IN UINT8 TuningStepDivisor)723 XenonInit (
724   IN EFI_PCI_IO_PROTOCOL *PciIo,
725   IN BOOLEAN             Support1v8,
726   IN BOOLEAN             SlowMode,
727   IN UINT8               TuningStepDivisor
728   )
729 {
730   EFI_STATUS Status;
731 
732   // Disable auto clock generator
733   XenonSetAcg (PciIo, FALSE);
734 
735   // XENON has only one port
736   XenonSetSlot (PciIo, XENON_MMC_SLOT_ID, TRUE);
737 
738   if (Support1v8) {
739     XenonSetPower (PciIo, MMC_VDD_165_195, eMMC_VCCQ_1_8V, XENON_MMC_MODE_SD_SDIO);
740   } else {
741     XenonSetPower (PciIo, MMC_VDD_32_33, eMMC_VCCQ_3_3V, XENON_MMC_MODE_SD_SDIO);
742   }
743 
744   XenonConfigureInterrupts (PciIo);
745 
746   // Enable parallel transfer
747   XenonSetParallelTransfer (PciIo, XENON_MMC_SLOT_ID, TRUE);
748   XenonSetTuning (PciIo, XENON_MMC_SLOT_ID, FALSE);
749 
750   // Enable auto clock generator
751   XenonSetAcg (PciIo, TRUE);
752 
753   // Set lowest clock and the PHY for the initialization phase
754   XenonSetClk (PciIo, XENON_MMC_BASE_CLK);
755   Status = XenonSetPhy (PciIo, SlowMode, TuningStepDivisor, SdMmcSdDs);
756   if (EFI_ERROR (Status)) {
757     return Status;
758   }
759 
760   return EFI_SUCCESS;
761 }
762