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