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 "XenonSdhci.h"
36
37 STATIC
38 VOID
XenonReadVersion(IN EFI_PCI_IO_PROTOCOL * PciIo,OUT UINT32 * ControllerVersion)39 XenonReadVersion (
40 IN EFI_PCI_IO_PROTOCOL *PciIo,
41 OUT UINT32 *ControllerVersion
42 )
43 {
44 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CTRL_VER, TRUE, SDHC_REG_SIZE_2B, ControllerVersion);
45 }
46
47 STATIC
48 VOID
XenonSetFifo(IN EFI_PCI_IO_PROTOCOL * PciIo)49 XenonSetFifo (
50 IN EFI_PCI_IO_PROTOCOL *PciIo
51 )
52 {
53 UINTN Data;
54
55 // Set FIFO_RTC, FIFO_WTC, FIFO_CS and FIFO_PDLVMC
56 Data = SDHC_SLOT_FIFO_DEFAULT_CONFIG;
57
58 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SLOT_FIFO_CTRL, FALSE, SDHC_REG_SIZE_4B, &Data);
59 }
60
61 // Auto Clock Gating
62 STATIC
63 VOID
XenonSetAcg(IN EFI_PCI_IO_PROTOCOL * PciIo,IN BOOLEAN Enable)64 XenonSetAcg (
65 IN EFI_PCI_IO_PROTOCOL *PciIo,
66 IN BOOLEAN Enable
67 )
68 {
69 UINT32 Var;
70
71 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, TRUE, SDHC_REG_SIZE_4B, &Var);
72
73 if (Enable) {
74 Var &= ~AUTO_CLKGATE_DISABLE_MASK;
75 } else {
76 Var |= AUTO_CLKGATE_DISABLE_MASK;
77 }
78
79 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, FALSE, SDHC_REG_SIZE_4B, &Var);
80 }
81
82 STATIC
83 VOID
XenonSetSlot(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT8 Slot,IN BOOLEAN Enable)84 XenonSetSlot (
85 IN EFI_PCI_IO_PROTOCOL *PciIo,
86 IN UINT8 Slot,
87 IN BOOLEAN Enable
88 )
89 {
90 UINT32 Var;
91
92 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, TRUE, SDHC_REG_SIZE_4B, &Var);
93 if (Enable) {
94 Var |= ((0x1 << Slot) << SLOT_ENABLE_SHIFT);
95 } else {
96 Var &= ~((0x1 << Slot) << SLOT_ENABLE_SHIFT);
97 }
98
99 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, FALSE, SDHC_REG_SIZE_4B, &Var);
100 }
101
102 //
103 // Stub function, which will in future be responsible for
104 // setting SDIO controller in either HIGH (if Voltage parameter
105 // is equal 1) or LOW (if Voltage is equal 0)
106 //
107 STATIC
108 VOID
XenonSetSdio(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINTN Voltage)109 XenonSetSdio (
110 IN EFI_PCI_IO_PROTOCOL *PciIo,
111 IN UINTN Voltage
112 )
113 {
114 // Currently SDIO isn't supported
115 return;
116 }
117
118 STATIC
119 VOID
XenonSetPower(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT32 Vcc,IN UINT32 Vccq,IN UINT8 Mode)120 XenonSetPower (
121 IN EFI_PCI_IO_PROTOCOL *PciIo,
122 IN UINT32 Vcc,
123 IN UINT32 Vccq,
124 IN UINT8 Mode
125 )
126 {
127 UINT8 Pwr = 0;
128 UINT32 Ctrl = 0;
129
130 // Below statement calls routine to set voltage for SDIO devices in either HIGH (1) or LOW (0) mode
131 switch (Vcc) {
132 case MMC_VDD_165_195:
133 Pwr = SDHCI_POWER_180;
134 if (Mode == XENON_MMC_MODE_SD_SDIO) {
135 XenonSetSdio (PciIo, 0);
136 }
137 break;
138 case MMC_VDD_29_30:
139 case MMC_VDD_30_31:
140 Pwr = SDHCI_POWER_300;
141 if (Mode == XENON_MMC_MODE_SD_SDIO) {
142 XenonSetSdio (PciIo, 1);
143 }
144 break;
145 case MMC_VDD_32_33:
146 case MMC_VDD_33_34:
147 Pwr = SDHCI_POWER_330;
148 if (Mode == XENON_MMC_MODE_SD_SDIO) {
149 XenonSetSdio (PciIo, 1);
150 }
151 break;
152 default:
153 DEBUG((DEBUG_ERROR, "SD/MMC: Does not support power mode(0x%X)\n", Vcc));
154 break;
155 }
156
157 if (Pwr == 0) {
158 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_POWER_CTRL, FALSE, SDHC_REG_SIZE_1B, &Pwr);
159 return;
160 }
161
162 Pwr |= SDHCI_POWER_ON;
163
164 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX,SD_MMC_HC_POWER_CTRL, FALSE, SDHC_REG_SIZE_1B, &Pwr);
165
166 // Set VCCQ
167 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SLOT_eMMC_CTRL, TRUE, SDHC_REG_SIZE_4B, &Ctrl);
168 Ctrl |= Vccq;
169 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SLOT_eMMC_CTRL, FALSE, SDHC_REG_SIZE_4B, &Ctrl);
170 }
171
172 UINTN
XenonSetClk(IN EFI_PCI_IO_PROTOCOL * PciIo,IN SD_MMC_HC_PRIVATE_DATA * Private,IN UINT32 Clock)173 XenonSetClk (
174 IN EFI_PCI_IO_PROTOCOL *PciIo,
175 IN SD_MMC_HC_PRIVATE_DATA *Private,
176 IN UINT32 Clock
177 )
178 {
179 UINT32 Div;
180 UINT32 Clk;
181 UINT32 Retry;
182 UINT16 Value = 0;
183
184 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &Value);
185
186 if (Clock == 0) {
187 return 0;
188 }
189
190 if (Private->ControllerVersion >= SDHCI_SPEC_300) {
191 // Version 3.00 Divisors must be a multiple of 2
192 if (XENON_MMC_MAX_CLK <= Clock) {
193 Div = 1;
194 } else {
195 for (Div = 2; Div < SDHCI_MAX_DIV_SPEC_300; Div += 2) {
196 if ((XENON_MMC_MAX_CLK / Div) <= Clock)
197 break;
198 }
199 }
200 } else {
201 // Version 2.00 Divisors must be a power of 2
202 for (Div = 1; Div < SDHCI_MAX_DIV_SPEC_200; Div *= 2) {
203 if ((XENON_MMC_MAX_CLK / Div) <= Clock)
204 break;
205 }
206 }
207 Div >>= 1;
208
209 Clk = (Div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
210 Clk |= ((Div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) << SDHCI_DIVIDER_HI_SHIFT;
211 Clk |= SDHCI_CLOCK_INT_EN;
212
213 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &Clk);
214
215 //
216 // Poll for internal controller clock to be stabilised
217 // Wait up to 200us for this to occur
218 //
219 Retry = 200;
220
221 do {
222 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, SDHC_REG_SIZE_2B, &Clk);
223 if (Retry == 0) {
224 DEBUG((DEBUG_ERROR, "SD/MMC: Internal Clock never stabilised\n"));
225 return -1;
226 }
227
228 Retry--;
229
230 // Wait for internal clock to be stabilised
231 gBS->Stall (1);
232
233 } while (!(Clk & SDHCI_CLOCK_INT_STABLE));
234
235 Clk |= SDHCI_CLOCK_CARD_EN;
236 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &Clk);
237
238 return 0;
239 }
240
241 VOID
XenonPhyInit(IN EFI_PCI_IO_PROTOCOL * PciIo)242 XenonPhyInit (
243 IN EFI_PCI_IO_PROTOCOL *PciIo
244 )
245 {
246 UINT32 Var, Wait, Time;
247 UINT32 Clock = XENON_MMC_MAX_CLK;
248 UINT16 ClkCtrl;
249
250 // Need to disable the clock to set EMMC_PHY_TIMING_ADJUST register
251 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, SDHC_REG_SIZE_2B, &ClkCtrl);
252 ClkCtrl &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN);
253 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &ClkCtrl);
254
255 // Enable QSP PHASE SELECT
256 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var);
257 Var |= SAMPL_INV_QSP_PHASE_SELECT;
258 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, SDHC_REG_SIZE_4B, &Var);
259
260 // Enable internal clock
261 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, SDHC_REG_SIZE_2B, &ClkCtrl);
262 ClkCtrl |= SDHCI_CLOCK_INT_EN;
263 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &ClkCtrl);
264
265 //
266 // Poll for host MMC PHY clock init to be stable
267 // Wait up to 100us
268 //
269 Time = 100;
270 while (Time--) {
271 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var);
272 if (Var & SDHCI_CLOCK_INT_STABLE) {
273 break;
274 }
275
276 // Poll interval for MMC PHY clock to be stable is 1us
277 gBS->Stall (1);
278 }
279 if (Time <= 0) {
280 DEBUG((DEBUG_ERROR, "SD/MMC: Failed to enable MMC internal clock in Time\n"));
281 return;
282 }
283
284 // Enable bus clock
285 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, SDHC_REG_SIZE_2B, &ClkCtrl);
286 ClkCtrl |= SDHCI_CLOCK_CARD_EN;
287 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, SDHC_REG_SIZE_2B, &ClkCtrl);
288
289 // Delay 200us to wait for the completion of bus clock
290 gBS->Stall (200);
291
292 // Init PHY
293 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var);
294 Var |= PHY_INITIALIZAION;
295 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, SDHC_REG_SIZE_4B, &Var);
296
297 // Add duration of FC_SYNC_RST
298 Wait = ((Var >> FC_SYNC_RST_DURATION_SHIFT) & FC_SYNC_RST_DURATION_MASK);
299
300 // Add interval between FC_SYNC_EN and FC_SYNC_RST
301 Wait += ((Var >> FC_SYNC_RST_EN_DURATION_SHIFT) & FC_SYNC_RST_EN_DURATION_MASK);
302
303 // Add duration of asserting FC_SYNC_EN
304 Wait += ((Var >> FC_SYNC_EN_DURATION_SHIFT) & FC_SYNC_EN_DURATION_MASK);
305
306 // Add duration of Waiting for PHY
307 Wait += ((Var >> WAIT_CYCLE_BEFORE_USING_SHIFT) & WAIT_CYCLE_BEFORE_USING_MASK);
308
309 // 4 addtional bus clock and 4 AXI bus clock are required left shift 20 bits
310 Wait += 8;
311 Wait <<= 20;
312
313 // Use the possibly slowest bus frequency value
314 if (Clock == 0) {
315 Clock = XENON_MMC_MIN_CLK;
316 }
317
318 // Get the Wait Time in unit of ms
319 Wait = Wait / Clock;
320 Wait++;
321
322 // Poll for host eMMC PHY init to complete, wait up to 100us
323 Time = 100;
324 while (Time--) {
325 Var = SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var);
326 Var &= PHY_INITIALIZAION;
327 if (!Var) {
328 break;
329 }
330
331 // Wait for host eMMC PHY init to complete
332 gBS->Stall (1);
333 }
334
335 if (Time <= 0) {
336 DEBUG((DEBUG_ERROR, "SD/MMC: Failed to init MMC PHY in Time\n"));
337 return;
338 }
339
340 return;
341 }
342
343 STATIC
344 VOID
XenonSetPhy(IN EFI_PCI_IO_PROTOCOL * PciIo,UINT8 Timing)345 XenonSetPhy (
346 IN EFI_PCI_IO_PROTOCOL *PciIo,
347 UINT8 Timing
348 )
349 {
350 UINT32 Var = 0;
351
352 // Setup pad, set bit[30], bit[28] and bits[26:24]
353 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL, TRUE, SDHC_REG_SIZE_4B, &Var);
354 Var |= (AUTO_RECEN_CTRL | OEN_QSN | FC_QSP_RECEN | FC_CMD_RECEN | FC_DQ_RECEN);
355 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL, FALSE, SDHC_REG_SIZE_4B, &Var);
356
357 //
358 // If Timing belongs to high speed, set bit[17] of
359 // EMMC_PHY_TIMING_ADJUST register
360 //
361 if ((Timing == MMC_TIMING_MMC_HS400) ||
362 (Timing == MMC_TIMING_MMC_HS200) ||
363 (Timing == MMC_TIMING_UHS_SDR50) ||
364 (Timing == MMC_TIMING_UHS_SDR104) ||
365 (Timing == MMC_TIMING_UHS_DDR50) ||
366 (Timing == MMC_TIMING_UHS_SDR25)) {
367
368 SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, SDHC_REG_SIZE_4B, &Var);
369
370 // Set SLOW_MODE for PHY
371 Var |= OUTPUT_QSN_PHASE_SELECT | QSN_PHASE_SLOW_MODE_BIT;
372 SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, SDHC_REG_SIZE_4B, &Var);
373 }
374
375 SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, TRUE, SDHC_REG_SIZE_4B, &Var);
376 Var |= (DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE;
377 SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, FALSE, SDHC_REG_SIZE_4B, &Var);
378
379 if (Timing == MMC_TIMING_MMC_HS400) {
380 SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, TRUE, SDHC_REG_SIZE_4B, &Var);
381 Var &= ~DQ_ASYNC_MODE;
382 SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, FALSE, SDHC_REG_SIZE_4B, &Var);
383
384 Var = LOGIC_TIMING_VALUE;
385 SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_LOGIC_TIMING_ADJUST, FALSE, SDHC_REG_SIZE_4B, &Var);
386 }
387
388 XenonPhyInit (PciIo);
389 }
390
391 STATIC
392 VOID
XenonConfigureInterrupts(IN EFI_PCI_IO_PROTOCOL * PciIo)393 XenonConfigureInterrupts (
394 IN EFI_PCI_IO_PROTOCOL *PciIo
395 )
396 {
397 UINT32 Var;
398
399 // Clear interrupt status
400 Var = SDHC_CLR_ALL_IRQ_MASK;
401 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_STS, FALSE, SDHC_REG_SIZE_4B, &Var);
402 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_STS, FALSE, SDHC_REG_SIZE_4B, &Var);
403
404 // Enable only interrupts served by the SD controller
405 Var = SDHC_CLR_ALL_IRQ_MASK & ~(NOR_INT_STS_CARD_INS | NOR_INT_STS_CARD_INT);
406 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_STS_EN, FALSE, SDHC_REG_SIZE_4B, &Var);
407
408 // Mask all sdhci interrupt sources
409 Var = SDHC_CLR_ALL_IRQ_MASK & ~NOR_INT_SIG_EN_CARD_INT;
410 SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_SIG_EN, FALSE, SDHC_REG_SIZE_4B, &Var);
411 }
412
413 // Enable Parallel Transfer Mode
414 STATIC
415 VOID
XenonSetParallelTransfer(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT8 Slot,IN BOOLEAN Enable)416 XenonSetParallelTransfer (
417 IN EFI_PCI_IO_PROTOCOL *PciIo,
418 IN UINT8 Slot,
419 IN BOOLEAN Enable
420 )
421 {
422 UINT32 Var;
423
424 SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SYS_EXT_OP_CTRL, TRUE, SDHC_REG_SIZE_4B, &Var);
425
426 if (Enable) {
427 Var |= (0x1 << Slot);
428 } else {
429 Var &= ~(0x1 << Slot);
430 }
431
432 SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SYS_EXT_OP_CTRL, FALSE, SDHC_REG_SIZE_4B, &Var);
433 }
434
435 STATIC
436 VOID
XenonSetTuning(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT8 Slot,IN BOOLEAN Enable)437 XenonSetTuning (
438 IN EFI_PCI_IO_PROTOCOL *PciIo,
439 IN UINT8 Slot,
440 IN BOOLEAN Enable
441 )
442 {
443 UINT32 Var;
444
445 // Set the Re-Tuning Request functionality
446 SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SLOT_RETUNING_REQ_CTRL, TRUE, SDHC_REG_SIZE_4B, &Var);
447
448 if (Enable) {
449 Var |= RETUNING_COMPATIBLE;
450 } else {
451 Var &= ~RETUNING_COMPATIBLE;
452 }
453
454 SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SLOT_RETUNING_REQ_CTRL, FALSE, SDHC_REG_SIZE_4B, &Var);
455
456 // Set the Re-tuning Event Signal Enable
457 SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHCI_SIGNAL_ENABLE, TRUE, SDHC_REG_SIZE_4B, &Var);
458
459 if (Enable) {
460 Var |= SDHCI_RETUNE_EVT_INTSIG;
461 } else {
462 Var &= ~SDHCI_RETUNE_EVT_INTSIG;
463 }
464
465 SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHCI_SIGNAL_ENABLE, FALSE, SDHC_REG_SIZE_4B, &Var);
466 }
467
468 VOID
XenonReset(IN SD_MMC_HC_PRIVATE_DATA * Private,IN UINT8 Slot,IN UINT8 Mask)469 XenonReset (
470 IN SD_MMC_HC_PRIVATE_DATA *Private,
471 IN UINT8 Slot,
472 IN UINT8 Mask
473 )
474 {
475 UINT32 Retry = 1000;
476 UINT8 SwReset;
477
478 SwReset = Mask;
479
480 SdMmcHcRwMmio (
481 Private->PciIo,
482 Slot,
483 SD_MMC_HC_SW_RST,
484 FALSE,
485 sizeof (SwReset),
486 &SwReset
487 );
488
489 SdMmcHcRwMmio (
490 Private->PciIo,
491 Slot,
492 SD_MMC_HC_SW_RST,
493 TRUE,
494 sizeof (SwReset),
495 &SwReset
496 );
497
498 while (SwReset & Mask) {
499 if (Retry == 0) {
500 DEBUG((DEBUG_ERROR, "SD/MMC: Reset never completed\n"));
501 return;
502 }
503
504 Retry--;
505
506 // Poll interval for SwReset is 100us according to SDHCI spec
507 gBS-> Stall (100);
508 SdMmcHcRwMmio (
509 Private->PciIo,
510 Slot,
511 SD_MMC_HC_SW_RST,
512 TRUE,
513 sizeof (SwReset),
514 &SwReset
515 );
516 }
517 }
518
519 STATIC
520 VOID
XenonTransferPio(IN SD_MMC_HC_PRIVATE_DATA * Private,IN UINT8 Slot,IN OUT VOID * Buffer,IN UINT16 BlockSize,IN BOOLEAN Read)521 XenonTransferPio (
522 IN SD_MMC_HC_PRIVATE_DATA *Private,
523 IN UINT8 Slot,
524 IN OUT VOID *Buffer,
525 IN UINT16 BlockSize,
526 IN BOOLEAN Read
527 )
528 {
529 UINTN Index;
530 UINT8 *Offs;
531
532 //
533 // SD stack's intrinsic functions cannot perform properly reading/writing from
534 // buffer register, that is why MmioRead/MmioWrite are used. It is temporary
535 // solution.
536 //
537 for (Index = 0; Index < BlockSize; Index += 4) {
538 Offs = Buffer + Index;
539 if (Read) {
540 *(UINT32 *)Offs = MmioRead32 (SDHC_DAT_BUF_PORT_ADDR);
541 } else {
542 MmioWrite32 (SDHC_DAT_BUF_PORT_ADDR, *(UINT32 *)Offs);
543 }
544 }
545 }
546
547 EFI_STATUS
XenonTransferData(IN SD_MMC_HC_PRIVATE_DATA * Private,IN UINT8 Slot,IN OUT VOID * Buffer,IN UINT32 DataLen,IN UINT16 BlockSize,IN UINT16 Blocks,IN BOOLEAN Read)548 XenonTransferData (
549 IN SD_MMC_HC_PRIVATE_DATA *Private,
550 IN UINT8 Slot,
551 IN OUT VOID *Buffer,
552 IN UINT32 DataLen,
553 IN UINT16 BlockSize,
554 IN UINT16 Blocks,
555 IN BOOLEAN Read
556 )
557 {
558 UINT32 IntStatus, PresentState, Rdy, Mask, Retry, Block = 0;
559
560 if (Buffer == NULL) {
561 return EFI_DEVICE_ERROR;
562 }
563
564 Retry = SDHC_INT_STATUS_POLL_RETRY_DATA_TRAN;
565 Rdy = NOR_INT_STS_TX_RDY | NOR_INT_STS_RX_RDY;
566 Mask = PRESENT_STATE_BUFFER_RD_EN | PRESENT_STATE_BUFFER_WR_EN;
567
568 do {
569 SdMmcHcRwMmio (
570 Private->PciIo,
571 Slot,
572 SD_MMC_HC_NOR_INT_STS,
573 TRUE,
574 sizeof (IntStatus),
575 &IntStatus
576 );
577
578 if (IntStatus & NOR_INT_STS_ERR_INT) {
579 DEBUG((DEBUG_INFO, "SD/MMC: Error detected in status %0x\n", IntStatus));
580 return EFI_DEVICE_ERROR;
581 }
582
583 if (IntStatus & Rdy) {
584 SdMmcHcRwMmio (
585 Private->PciIo,
586 Slot,
587 SD_MMC_HC_PRESENT_STATE,
588 TRUE,
589 sizeof (PresentState),
590 &PresentState
591 );
592
593 if (!(PresentState & Mask)) {
594 continue;
595 }
596
597 SdMmcHcRwMmio (
598 Private->PciIo,
599 Slot,
600 SD_MMC_HC_NOR_INT_STS,
601 FALSE,
602 sizeof (Rdy),
603 &Rdy
604 );
605
606 XenonTransferPio (Private, Slot, Buffer, BlockSize, Read);
607
608 Buffer += BlockSize;
609 if (++Block >= Blocks) {
610 break;
611 }
612 }
613
614 if (Retry-- > 0) {
615
616 // Poll interval for data transfer complete bit in NOR_INT_STS register is 10us
617 gBS->Stall (10);
618 } else {
619 DEBUG((DEBUG_INFO, "SD/MMC: Transfer data timeout\n"));
620 return EFI_TIMEOUT;
621 }
622 } while (!(IntStatus & NOR_INT_STS_XFER_COMPLETE));
623
624 return EFI_SUCCESS;
625 }
626
627 EFI_STATUS
XenonInit(IN SD_MMC_HC_PRIVATE_DATA * Private)628 XenonInit (
629 IN SD_MMC_HC_PRIVATE_DATA *Private
630 )
631 {
632 EFI_PCI_IO_PROTOCOL *PciIo = Private->PciIo;
633
634 // Read XENON version
635 XenonReadVersion (PciIo, &Private->ControllerVersion);
636
637 XenonSetFifo (PciIo);
638
639 // Disable auto clock generator
640 XenonSetAcg (PciIo, FALSE);
641
642 // XENON has only one port
643 XenonSetSlot (PciIo, XENON_MMC_SLOT_ID, TRUE);
644
645 XenonSetPower (PciIo, MMC_VDD_165_195, eMMC_VCCQ_1_8V, XENON_MMC_MODE_SD_SDIO);
646
647 // Set MAX_CLOCK for configuring PHY
648 XenonSetClk (PciIo, Private, XENON_MMC_MAX_CLK);
649 XenonSetPhy (PciIo, MMC_TIMING_UHS_SDR50);
650
651 XenonConfigureInterrupts (PciIo);
652
653 // Enable parallel transfer
654 XenonSetParallelTransfer (PciIo, XENON_MMC_SLOT_ID, TRUE);
655 XenonSetTuning (PciIo, XENON_MMC_SLOT_ID, FALSE);
656
657 // Enable auto clock generator
658 XenonSetAcg (PciIo, TRUE);
659
660 // Set proper clock for PHY configuration
661 XenonSetClk (PciIo, Private, XENON_MMC_BASE_CLK);
662 XenonPhyInit (PciIo);
663
664 return EFI_SUCCESS;
665 }
666