1 | /** @file
|
---|
2 | *
|
---|
3 | * Copyright (c) 2011-2015, ARM Limited. All rights reserved.
|
---|
4 | *
|
---|
5 | * SPDX-License-Identifier: BSD-2-Clause-Patent
|
---|
6 | *
|
---|
7 | **/
|
---|
8 |
|
---|
9 | #include <Library/BaseMemoryLib.h>
|
---|
10 | #include <Library/MemoryAllocationLib.h>
|
---|
11 | #include <Library/TimerLib.h>
|
---|
12 |
|
---|
13 | #include "Mmc.h"
|
---|
14 |
|
---|
15 | typedef union {
|
---|
16 | UINT32 Raw;
|
---|
17 | OCR Ocr;
|
---|
18 | } OCR_RESPONSE;
|
---|
19 |
|
---|
20 | #define MAX_RETRY_COUNT 1000
|
---|
21 | #define CMD_RETRY_COUNT 20
|
---|
22 | #define RCA_SHIFT_OFFSET 16
|
---|
23 | #define EMMC_CARD_SIZE 512
|
---|
24 | #define EMMC_ECSD_SIZE_OFFSET 53
|
---|
25 |
|
---|
26 | #define EXTCSD_BUS_WIDTH 183
|
---|
27 | #define EXTCSD_HS_TIMING 185
|
---|
28 |
|
---|
29 | #define EMMC_TIMING_BACKWARD 0
|
---|
30 | #define EMMC_TIMING_HS 1
|
---|
31 | #define EMMC_TIMING_HS200 2
|
---|
32 | #define EMMC_TIMING_HS400 3
|
---|
33 |
|
---|
34 | #define EMMC_BUS_WIDTH_1BIT 0
|
---|
35 | #define EMMC_BUS_WIDTH_4BIT 1
|
---|
36 | #define EMMC_BUS_WIDTH_8BIT 2
|
---|
37 | #define EMMC_BUS_WIDTH_DDR_4BIT 5
|
---|
38 | #define EMMC_BUS_WIDTH_DDR_8BIT 6
|
---|
39 |
|
---|
40 | #define EMMC_SWITCH_ERROR (1 << 7)
|
---|
41 |
|
---|
42 | #define SD_BUS_WIDTH_1BIT (1 << 0)
|
---|
43 | #define SD_BUS_WIDTH_4BIT (1 << 2)
|
---|
44 |
|
---|
45 | #define SD_CCC_SWITCH (1 << 10)
|
---|
46 |
|
---|
47 | #define DEVICE_STATE(x) (((x) >> 9) & 0xf)
|
---|
48 | typedef enum _EMMC_DEVICE_STATE {
|
---|
49 | EMMC_IDLE_STATE = 0,
|
---|
50 | EMMC_READY_STATE,
|
---|
51 | EMMC_IDENT_STATE,
|
---|
52 | EMMC_STBY_STATE,
|
---|
53 | EMMC_TRAN_STATE,
|
---|
54 | EMMC_DATA_STATE,
|
---|
55 | EMMC_RCV_STATE,
|
---|
56 | EMMC_PRG_STATE,
|
---|
57 | EMMC_DIS_STATE,
|
---|
58 | EMMC_BTST_STATE,
|
---|
59 | EMMC_SLP_STATE
|
---|
60 | } EMMC_DEVICE_STATE;
|
---|
61 |
|
---|
62 | UINT32 mEmmcRcaCount = 0;
|
---|
63 |
|
---|
64 | STATIC
|
---|
65 | EFI_STATUS
|
---|
66 | EFIAPI
|
---|
67 | EmmcGetDeviceState (
|
---|
68 | IN MMC_HOST_INSTANCE *MmcHostInstance,
|
---|
69 | OUT EMMC_DEVICE_STATE *State
|
---|
70 | )
|
---|
71 | {
|
---|
72 | EFI_MMC_HOST_PROTOCOL *Host;
|
---|
73 | EFI_STATUS Status;
|
---|
74 | UINT32 Data, RCA;
|
---|
75 |
|
---|
76 | if (State == NULL) {
|
---|
77 | return EFI_INVALID_PARAMETER;
|
---|
78 | }
|
---|
79 |
|
---|
80 | Host = MmcHostInstance->MmcHost;
|
---|
81 | RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET;
|
---|
82 | Status = Host->SendCommand (Host, MMC_CMD13, RCA);
|
---|
83 | if (EFI_ERROR (Status)) {
|
---|
84 | DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to get card status, Status=%r.\n", Status));
|
---|
85 | return Status;
|
---|
86 | }
|
---|
87 | Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R1, &Data);
|
---|
88 | if (EFI_ERROR (Status)) {
|
---|
89 | DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to get response of CMD13, Status=%r.\n", Status));
|
---|
90 | return Status;
|
---|
91 | }
|
---|
92 | if (Data & EMMC_SWITCH_ERROR) {
|
---|
93 | DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to switch expected mode, Status=%r.\n", Status));
|
---|
94 | return EFI_DEVICE_ERROR;
|
---|
95 | }
|
---|
96 | *State = DEVICE_STATE(Data);
|
---|
97 | return EFI_SUCCESS;
|
---|
98 | }
|
---|
99 |
|
---|
100 | STATIC
|
---|
101 | EFI_STATUS
|
---|
102 | EFIAPI
|
---|
103 | EmmcSetEXTCSD (
|
---|
104 | IN MMC_HOST_INSTANCE *MmcHostInstance,
|
---|
105 | UINT32 ExtCmdIndex,
|
---|
106 | UINT32 Value
|
---|
107 | )
|
---|
108 | {
|
---|
109 | EFI_MMC_HOST_PROTOCOL *Host;
|
---|
110 | EMMC_DEVICE_STATE State;
|
---|
111 | EFI_STATUS Status;
|
---|
112 | UINT32 Argument;
|
---|
113 |
|
---|
114 | Host = MmcHostInstance->MmcHost;
|
---|
115 | Argument = EMMC_CMD6_ARG_ACCESS(3) | EMMC_CMD6_ARG_INDEX(ExtCmdIndex) |
|
---|
116 | EMMC_CMD6_ARG_VALUE(Value) | EMMC_CMD6_ARG_CMD_SET(1);
|
---|
117 | Status = Host->SendCommand (Host, MMC_CMD6, Argument);
|
---|
118 | if (EFI_ERROR (Status)) {
|
---|
119 | DEBUG ((EFI_D_ERROR, "EmmcSetEXTCSD(): Failed to send CMD6, Status=%r.\n", Status));
|
---|
120 | return Status;
|
---|
121 | }
|
---|
122 | // Make sure device exiting prog mode
|
---|
123 | do {
|
---|
124 | Status = EmmcGetDeviceState (MmcHostInstance, &State);
|
---|
125 | if (EFI_ERROR (Status)) {
|
---|
126 | DEBUG ((EFI_D_ERROR, "EmmcSetEXTCSD(): Failed to get device state, Status=%r.\n", Status));
|
---|
127 | return Status;
|
---|
128 | }
|
---|
129 | } while (State == EMMC_PRG_STATE);
|
---|
130 | return EFI_SUCCESS;
|
---|
131 | }
|
---|
132 |
|
---|
133 | STATIC
|
---|
134 | EFI_STATUS
|
---|
135 | EFIAPI
|
---|
136 | EmmcIdentificationMode (
|
---|
137 | IN MMC_HOST_INSTANCE *MmcHostInstance,
|
---|
138 | IN OCR_RESPONSE Response
|
---|
139 | )
|
---|
140 | {
|
---|
141 | EFI_MMC_HOST_PROTOCOL *Host;
|
---|
142 | EFI_BLOCK_IO_MEDIA *Media;
|
---|
143 | EFI_STATUS Status;
|
---|
144 | EMMC_DEVICE_STATE State;
|
---|
145 | UINT32 RCA;
|
---|
146 |
|
---|
147 | Host = MmcHostInstance->MmcHost;
|
---|
148 | Media = MmcHostInstance->BlockIo.Media;
|
---|
149 |
|
---|
150 | // Fetch card identity register
|
---|
151 | Status = Host->SendCommand (Host, MMC_CMD2, 0);
|
---|
152 | if (EFI_ERROR (Status)) {
|
---|
153 | DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to send CMD2, Status=%r.\n", Status));
|
---|
154 | return Status;
|
---|
155 | }
|
---|
156 |
|
---|
157 | Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CIDData));
|
---|
158 | if (EFI_ERROR (Status)) {
|
---|
159 | DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): CID retrieval error, Status=%r.\n", Status));
|
---|
160 | return Status;
|
---|
161 | }
|
---|
162 |
|
---|
163 | // Assign a relative address value to the card
|
---|
164 | MmcHostInstance->CardInfo.RCA = ++mEmmcRcaCount; // TODO: might need a more sophisticated way of doing this
|
---|
165 | RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET;
|
---|
166 | Status = Host->SendCommand (Host, MMC_CMD3, RCA);
|
---|
167 | if (EFI_ERROR (Status)) {
|
---|
168 | DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): RCA set error, Status=%r.\n", Status));
|
---|
169 | return Status;
|
---|
170 | }
|
---|
171 |
|
---|
172 | // Fetch card specific data
|
---|
173 | Status = Host->SendCommand (Host, MMC_CMD9, RCA);
|
---|
174 | if (EFI_ERROR (Status)) {
|
---|
175 | DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to send CMD9, Status=%r.\n", Status));
|
---|
176 | return Status;
|
---|
177 | }
|
---|
178 |
|
---|
179 | Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CSDData));
|
---|
180 | if (EFI_ERROR (Status)) {
|
---|
181 | DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): CSD retrieval error, Status=%r.\n", Status));
|
---|
182 | return Status;
|
---|
183 | }
|
---|
184 |
|
---|
185 | // Select the card
|
---|
186 | Status = Host->SendCommand (Host, MMC_CMD7, RCA);
|
---|
187 | if (EFI_ERROR (Status)) {
|
---|
188 | DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Card selection error, Status=%r.\n", Status));
|
---|
189 | }
|
---|
190 |
|
---|
191 | if (MMC_HOST_HAS_SETIOS(Host)) {
|
---|
192 | // Set 1-bit bus width
|
---|
193 | Status = Host->SetIos (Host, 0, 1, EMMCBACKWARD);
|
---|
194 | if (EFI_ERROR (Status)) {
|
---|
195 | DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set 1-bit bus width error, Status=%r.\n", Status));
|
---|
196 | return Status;
|
---|
197 | }
|
---|
198 |
|
---|
199 | // Set 1-bit bus width for EXTCSD
|
---|
200 | Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, EMMC_BUS_WIDTH_1BIT);
|
---|
201 | if (EFI_ERROR (Status)) {
|
---|
202 | DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set extcsd bus width error, Status=%r.\n", Status));
|
---|
203 | return Status;
|
---|
204 | }
|
---|
205 | }
|
---|
206 |
|
---|
207 | // Fetch ECSD
|
---|
208 | MmcHostInstance->CardInfo.ECSDData = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (ECSD)));
|
---|
209 | if (MmcHostInstance->CardInfo.ECSDData == NULL) {
|
---|
210 | return EFI_OUT_OF_RESOURCES;
|
---|
211 | }
|
---|
212 | Status = Host->SendCommand (Host, MMC_CMD8, 0);
|
---|
213 | if (EFI_ERROR (Status)) {
|
---|
214 | DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD fetch error, Status=%r.\n", Status));
|
---|
215 | }
|
---|
216 |
|
---|
217 | Status = Host->ReadBlockData (Host, 0, 512, (UINT32 *)MmcHostInstance->CardInfo.ECSDData);
|
---|
218 | if (EFI_ERROR (Status)) {
|
---|
219 | DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD read error, Status=%r.\n", Status));
|
---|
220 | goto FreePageExit;
|
---|
221 | }
|
---|
222 |
|
---|
223 | // Make sure device exiting data mode
|
---|
224 | do {
|
---|
225 | Status = EmmcGetDeviceState (MmcHostInstance, &State);
|
---|
226 | if (EFI_ERROR (Status)) {
|
---|
227 | DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to get device state, Status=%r.\n", Status));
|
---|
228 | goto FreePageExit;
|
---|
229 | }
|
---|
230 | } while (State == EMMC_DATA_STATE);
|
---|
231 |
|
---|
232 | // Set up media
|
---|
233 | Media->BlockSize = EMMC_CARD_SIZE; // 512-byte support is mandatory for eMMC cards
|
---|
234 | Media->MediaId = MmcHostInstance->CardInfo.CIDData.PSN;
|
---|
235 | Media->ReadOnly = MmcHostInstance->CardInfo.CSDData.PERM_WRITE_PROTECT;
|
---|
236 | Media->LogicalBlocksPerPhysicalBlock = 1;
|
---|
237 | Media->IoAlign = 4;
|
---|
238 | // Compute last block using bits [215:212] of the ECSD
|
---|
239 | Media->LastBlock = MmcHostInstance->CardInfo.ECSDData->SECTOR_COUNT - 1; // eMMC isn't supposed to report this for
|
---|
240 | // Cards <2GB in size, but the model does.
|
---|
241 |
|
---|
242 | // Setup card type
|
---|
243 | MmcHostInstance->CardInfo.CardType = EMMC_CARD;
|
---|
244 | return EFI_SUCCESS;
|
---|
245 |
|
---|
246 | FreePageExit:
|
---|
247 | FreePages (MmcHostInstance->CardInfo.ECSDData, EFI_SIZE_TO_PAGES (sizeof (ECSD)));
|
---|
248 | return Status;
|
---|
249 | }
|
---|
250 |
|
---|
251 | STATIC
|
---|
252 | EFI_STATUS
|
---|
253 | InitializeEmmcDevice (
|
---|
254 | IN MMC_HOST_INSTANCE *MmcHostInstance
|
---|
255 | )
|
---|
256 | {
|
---|
257 | EFI_MMC_HOST_PROTOCOL *Host;
|
---|
258 | EFI_STATUS Status = EFI_SUCCESS;
|
---|
259 | ECSD *ECSDData;
|
---|
260 | UINT32 BusClockFreq, Idx, BusMode;
|
---|
261 | UINT32 TimingMode[4] = {EMMCHS52DDR1V2, EMMCHS52DDR1V8, EMMCHS52, EMMCHS26};
|
---|
262 |
|
---|
263 | Host = MmcHostInstance->MmcHost;
|
---|
264 | ECSDData = MmcHostInstance->CardInfo.ECSDData;
|
---|
265 | if (ECSDData->DEVICE_TYPE == EMMCBACKWARD)
|
---|
266 | return EFI_SUCCESS;
|
---|
267 |
|
---|
268 | if (!MMC_HOST_HAS_SETIOS(Host)) {
|
---|
269 | return EFI_SUCCESS;
|
---|
270 | }
|
---|
271 | Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_HS_TIMING, EMMC_TIMING_HS);
|
---|
272 | if (EFI_ERROR (Status)) {
|
---|
273 | DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to switch high speed mode, Status:%r.\n", Status));
|
---|
274 | return Status;
|
---|
275 | }
|
---|
276 |
|
---|
277 | for (Idx = 0; Idx < 4; Idx++) {
|
---|
278 | switch (TimingMode[Idx]) {
|
---|
279 | case EMMCHS52DDR1V2:
|
---|
280 | case EMMCHS52DDR1V8:
|
---|
281 | case EMMCHS52:
|
---|
282 | BusClockFreq = 52000000;
|
---|
283 | break;
|
---|
284 | case EMMCHS26:
|
---|
285 | BusClockFreq = 26000000;
|
---|
286 | break;
|
---|
287 | default:
|
---|
288 | return EFI_UNSUPPORTED;
|
---|
289 | }
|
---|
290 | Status = Host->SetIos (Host, BusClockFreq, 8, TimingMode[Idx]);
|
---|
291 | if (!EFI_ERROR (Status)) {
|
---|
292 | switch (TimingMode[Idx]) {
|
---|
293 | case EMMCHS52DDR1V2:
|
---|
294 | case EMMCHS52DDR1V8:
|
---|
295 | BusMode = EMMC_BUS_WIDTH_DDR_8BIT;
|
---|
296 | break;
|
---|
297 | case EMMCHS52:
|
---|
298 | case EMMCHS26:
|
---|
299 | BusMode = EMMC_BUS_WIDTH_8BIT;
|
---|
300 | break;
|
---|
301 | default:
|
---|
302 | return EFI_UNSUPPORTED;
|
---|
303 | }
|
---|
304 | Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, BusMode);
|
---|
305 | if (EFI_ERROR (Status)) {
|
---|
306 | DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to set EXTCSD bus width, Status:%r\n", Status));
|
---|
307 | }
|
---|
308 | return Status;
|
---|
309 | }
|
---|
310 | }
|
---|
311 | return Status;
|
---|
312 | }
|
---|
313 |
|
---|
314 | STATIC
|
---|
315 | UINT32
|
---|
316 | CreateSwitchCmdArgument (
|
---|
317 | IN UINT32 Mode,
|
---|
318 | IN UINT8 Group,
|
---|
319 | IN UINT8 Value
|
---|
320 | )
|
---|
321 | {
|
---|
322 | UINT32 Argument;
|
---|
323 |
|
---|
324 | Argument = Mode << 31 | 0x00FFFFFF;
|
---|
325 | Argument &= ~(0xF << (Group * 4));
|
---|
326 | Argument |= Value << (Group * 4);
|
---|
327 |
|
---|
328 | return Argument;
|
---|
329 | }
|
---|
330 |
|
---|
331 | STATIC
|
---|
332 | EFI_STATUS
|
---|
333 | InitializeSdMmcDevice (
|
---|
334 | IN MMC_HOST_INSTANCE *MmcHostInstance
|
---|
335 | )
|
---|
336 | {
|
---|
337 | UINT32 CmdArg;
|
---|
338 | UINT32 Response[4];
|
---|
339 | UINT32 Buffer[128];
|
---|
340 | UINT32 Speed;
|
---|
341 | UINTN BlockSize;
|
---|
342 | UINTN CardSize;
|
---|
343 | UINTN NumBlocks;
|
---|
344 | BOOLEAN CccSwitch;
|
---|
345 | SCR Scr;
|
---|
346 | EFI_STATUS Status;
|
---|
347 | EFI_MMC_HOST_PROTOCOL *MmcHost;
|
---|
348 |
|
---|
349 | Speed = SD_DEFAULT_SPEED;
|
---|
350 | MmcHost = MmcHostInstance->MmcHost;
|
---|
351 |
|
---|
352 | // Send a command to get Card specific data
|
---|
353 | CmdArg = MmcHostInstance->CardInfo.RCA << 16;
|
---|
354 | Status = MmcHost->SendCommand (MmcHost, MMC_CMD9, CmdArg);
|
---|
355 | if (EFI_ERROR (Status)) {
|
---|
356 | DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(MMC_CMD9): Error, Status=%r\n", Status));
|
---|
357 | return Status;
|
---|
358 | }
|
---|
359 |
|
---|
360 | // Read Response
|
---|
361 | Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CSD, Response);
|
---|
362 | if (EFI_ERROR (Status)) {
|
---|
363 | DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(): Failed to receive CSD, Status=%r\n", Status));
|
---|
364 | return Status;
|
---|
365 | }
|
---|
366 | PrintCSD (Response);
|
---|
367 | if (MMC_CSD_GET_CCC(Response) & SD_CCC_SWITCH) {
|
---|
368 | CccSwitch = TRUE;
|
---|
369 | } else {
|
---|
370 | CccSwitch = FALSE;
|
---|
371 | }
|
---|
372 |
|
---|
373 | if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) {
|
---|
374 | CardSize = HC_MMC_CSD_GET_DEVICESIZE (Response);
|
---|
375 | NumBlocks = ((CardSize + 1) * 1024);
|
---|
376 | BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);
|
---|
377 | } else {
|
---|
378 | CardSize = MMC_CSD_GET_DEVICESIZE (Response);
|
---|
379 | NumBlocks = (CardSize + 1) * (1 << (MMC_CSD_GET_DEVICESIZEMULT (Response) + 2));
|
---|
380 | BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);
|
---|
381 | }
|
---|
382 |
|
---|
383 | // For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes.
|
---|
384 | if (BlockSize > 512) {
|
---|
385 | NumBlocks = MultU64x32 (NumBlocks, BlockSize / 512);
|
---|
386 | BlockSize = 512;
|
---|
387 | }
|
---|
388 |
|
---|
389 | MmcHostInstance->BlockIo.Media->LastBlock = (NumBlocks - 1);
|
---|
390 | MmcHostInstance->BlockIo.Media->BlockSize = BlockSize;
|
---|
391 | MmcHostInstance->BlockIo.Media->ReadOnly = MmcHost->IsReadOnly (MmcHost);
|
---|
392 | MmcHostInstance->BlockIo.Media->MediaPresent = TRUE;
|
---|
393 | MmcHostInstance->BlockIo.Media->MediaId++;
|
---|
394 |
|
---|
395 | CmdArg = MmcHostInstance->CardInfo.RCA << 16;
|
---|
396 | Status = MmcHost->SendCommand (MmcHost, MMC_CMD7, CmdArg);
|
---|
397 | if (EFI_ERROR (Status)) {
|
---|
398 | DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(MMC_CMD7): Error and Status = %r\n", Status));
|
---|
399 | return Status;
|
---|
400 | }
|
---|
401 |
|
---|
402 | Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, CmdArg);
|
---|
403 | if (EFI_ERROR (Status)) {
|
---|
404 | DEBUG ((DEBUG_ERROR, "%a (MMC_CMD55): Error and Status = %r\n", __FUNCTION__, Status));
|
---|
405 | return Status;
|
---|
406 | }
|
---|
407 | Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);
|
---|
408 | if (EFI_ERROR (Status)) {
|
---|
409 | DEBUG ((DEBUG_ERROR, "%a (MMC_CMD55): Error and Status = %r\n", __FUNCTION__, Status));
|
---|
410 | return Status;
|
---|
411 | }
|
---|
412 | if ((Response[0] & MMC_STATUS_APP_CMD) == 0) {
|
---|
413 | return EFI_SUCCESS;
|
---|
414 | }
|
---|
415 |
|
---|
416 | /* SCR */
|
---|
417 | Status = MmcHost->SendCommand (MmcHost, MMC_ACMD51, 0);
|
---|
418 | if (EFI_ERROR (Status)) {
|
---|
419 | DEBUG ((EFI_D_ERROR, "%a(MMC_ACMD51): Error and Status = %r\n", __func__, Status));
|
---|
420 | return Status;
|
---|
421 | } else {
|
---|
422 | Status = MmcHost->ReadBlockData (MmcHost, 0, 8, Buffer);
|
---|
423 | if (EFI_ERROR (Status)) {
|
---|
424 | DEBUG ((EFI_D_ERROR, "%a(MMC_ACMD51): ReadBlockData Error and Status = %r\n", __func__, Status));
|
---|
425 | return Status;
|
---|
426 | }
|
---|
427 | CopyMem (&Scr, Buffer, 8);
|
---|
428 | if (Scr.SD_SPEC == 2) {
|
---|
429 | if (Scr.SD_SPEC3 == 1) {
|
---|
430 | if (Scr.SD_SPEC4 == 1) {
|
---|
431 | DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 4.xx\n"));
|
---|
432 | } else {
|
---|
433 | DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 3.0x\n"));
|
---|
434 | }
|
---|
435 | } else {
|
---|
436 | if (Scr.SD_SPEC4 == 0) {
|
---|
437 | DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 2.0\n"));
|
---|
438 | } else {
|
---|
439 | DEBUG ((EFI_D_ERROR, "Found invalid SD Card\n"));
|
---|
440 | }
|
---|
441 | }
|
---|
442 | } else {
|
---|
443 | if ((Scr.SD_SPEC3 == 0) && (Scr.SD_SPEC4 == 0)) {
|
---|
444 | if (Scr.SD_SPEC == 1) {
|
---|
445 | DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 1.10\n"));
|
---|
446 | } else {
|
---|
447 | DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 1.0\n"));
|
---|
448 | }
|
---|
449 | } else {
|
---|
450 | DEBUG ((EFI_D_ERROR, "Found invalid SD Card\n"));
|
---|
451 | }
|
---|
452 | }
|
---|
453 | }
|
---|
454 | if (CccSwitch) {
|
---|
455 | /* SD Switch, Mode:0, Group:0, Value:0 */
|
---|
456 | CmdArg = CreateSwitchCmdArgument(0, 0, 0);
|
---|
457 | Status = MmcHost->SendCommand (MmcHost, MMC_CMD6, CmdArg);
|
---|
458 | if (EFI_ERROR (Status)) {
|
---|
459 | DEBUG ((DEBUG_ERROR, "%a (MMC_CMD6): Error and Status = %r\n", __FUNCTION__, Status));
|
---|
460 | return Status;
|
---|
461 | } else {
|
---|
462 | Status = MmcHost->ReadBlockData (MmcHost, 0, SWITCH_CMD_DATA_LENGTH, Buffer);
|
---|
463 | if (EFI_ERROR (Status)) {
|
---|
464 | DEBUG ((DEBUG_ERROR, "%a (MMC_CMD6): ReadBlockData Error and Status = %r\n", __FUNCTION__, Status));
|
---|
465 | return Status;
|
---|
466 | }
|
---|
467 | }
|
---|
468 |
|
---|
469 | if (!(Buffer[3] & SD_HIGH_SPEED_SUPPORTED)) {
|
---|
470 | DEBUG ((DEBUG_INFO, "%a : High Speed not supported by Card\n", __FUNCTION__));
|
---|
471 | } else {
|
---|
472 | Speed = SD_HIGH_SPEED;
|
---|
473 |
|
---|
474 | /* SD Switch, Mode:1, Group:0, Value:1 */
|
---|
475 | CmdArg = CreateSwitchCmdArgument(1, 0, 1);
|
---|
476 | Status = MmcHost->SendCommand (MmcHost, MMC_CMD6, CmdArg);
|
---|
477 | if (EFI_ERROR (Status)) {
|
---|
478 | DEBUG ((DEBUG_ERROR, "%a (MMC_CMD6): Error and Status = %r\n", __FUNCTION__, Status));
|
---|
479 | return Status;
|
---|
480 | } else {
|
---|
481 | Status = MmcHost->ReadBlockData (MmcHost, 0, SWITCH_CMD_DATA_LENGTH, Buffer);
|
---|
482 | if (EFI_ERROR (Status)) {
|
---|
483 | DEBUG ((DEBUG_ERROR, "%a (MMC_CMD6): ReadBlockData Error and Status = %r\n", __FUNCTION__, Status));
|
---|
484 | return Status;
|
---|
485 | }
|
---|
486 |
|
---|
487 | if ((Buffer[4] & SWITCH_CMD_SUCCESS_MASK) != 0x01000000) {
|
---|
488 | DEBUG((DEBUG_ERROR, "Problem switching SD card into high-speed mode\n"));
|
---|
489 | return Status;
|
---|
490 | }
|
---|
491 | }
|
---|
492 | }
|
---|
493 | }
|
---|
494 | if (Scr.SD_BUS_WIDTHS & SD_BUS_WIDTH_4BIT) {
|
---|
495 | CmdArg = MmcHostInstance->CardInfo.RCA << 16;
|
---|
496 | Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, CmdArg);
|
---|
497 | if (EFI_ERROR (Status)) {
|
---|
498 | DEBUG ((DEBUG_ERROR, "%a (MMC_CMD55): Error and Status = %r\n", __FUNCTION__, Status));
|
---|
499 | return Status;
|
---|
500 | }
|
---|
501 | /* Width: 4 */
|
---|
502 | Status = MmcHost->SendCommand (MmcHost, MMC_CMD6, 2);
|
---|
503 | if (EFI_ERROR (Status)) {
|
---|
504 | DEBUG ((DEBUG_ERROR, "%a (MMC_CMD6): Error and Status = %r\n", __FUNCTION__, Status));
|
---|
505 | return Status;
|
---|
506 | }
|
---|
507 | }
|
---|
508 | if (MMC_HOST_HAS_SETIOS(MmcHost)) {
|
---|
509 | Status = MmcHost->SetIos (MmcHost, Speed, BUSWIDTH_4, EMMCBACKWARD);
|
---|
510 | if (EFI_ERROR (Status)) {
|
---|
511 | DEBUG ((DEBUG_ERROR, "%a (SetIos): Error and Status = %r\n", __FUNCTION__, Status));
|
---|
512 | return Status;
|
---|
513 | }
|
---|
514 | }
|
---|
515 | return EFI_SUCCESS;
|
---|
516 | }
|
---|
517 |
|
---|
518 | STATIC
|
---|
519 | EFI_STATUS
|
---|
520 | EFIAPI
|
---|
521 | MmcIdentificationMode (
|
---|
522 | IN MMC_HOST_INSTANCE *MmcHostInstance
|
---|
523 | )
|
---|
524 | {
|
---|
525 | EFI_STATUS Status;
|
---|
526 | UINT32 Response[4];
|
---|
527 | UINTN Timeout;
|
---|
528 | UINTN CmdArg;
|
---|
529 | BOOLEAN IsHCS;
|
---|
530 | EFI_MMC_HOST_PROTOCOL *MmcHost;
|
---|
531 | OCR_RESPONSE OcrResponse;
|
---|
532 |
|
---|
533 | MmcHost = MmcHostInstance->MmcHost;
|
---|
534 | CmdArg = 0;
|
---|
535 | IsHCS = FALSE;
|
---|
536 |
|
---|
537 | if (MmcHost == NULL) {
|
---|
538 | return EFI_INVALID_PARAMETER;
|
---|
539 | }
|
---|
540 |
|
---|
541 | // We can get into this function if we restart the identification mode
|
---|
542 | if (MmcHostInstance->State == MmcHwInitializationState) {
|
---|
543 | // Initialize the MMC Host HW
|
---|
544 | Status = MmcNotifyState (MmcHostInstance, MmcHwInitializationState);
|
---|
545 | if (EFI_ERROR (Status)) {
|
---|
546 | DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcHwInitializationState, Status=%r.\n", Status));
|
---|
547 | return Status;
|
---|
548 | }
|
---|
549 | }
|
---|
550 |
|
---|
551 | Status = MmcHost->SendCommand (MmcHost, MMC_CMD0, 0);
|
---|
552 | if (EFI_ERROR (Status)) {
|
---|
553 | DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD0): Error, Status=%r.\n", Status));
|
---|
554 | return Status;
|
---|
555 | }
|
---|
556 | Status = MmcNotifyState (MmcHostInstance, MmcIdleState);
|
---|
557 | if (EFI_ERROR (Status)) {
|
---|
558 | DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdleState, Status=%r.\n", Status));
|
---|
559 | return Status;
|
---|
560 | }
|
---|
561 |
|
---|
562 | // Send CMD1 to get OCR (MMC)
|
---|
563 | // This command only valid for MMC and eMMC
|
---|
564 | Timeout = MAX_RETRY_COUNT;
|
---|
565 | do {
|
---|
566 | Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, EMMC_CMD1_CAPACITY_GREATER_THAN_2GB);
|
---|
567 | if (EFI_ERROR (Status))
|
---|
568 | break;
|
---|
569 | Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, (UINT32 *)&OcrResponse);
|
---|
570 | if (EFI_ERROR (Status)) {
|
---|
571 | DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));
|
---|
572 | return Status;
|
---|
573 | }
|
---|
574 | Timeout--;
|
---|
575 | } while (!OcrResponse.Ocr.PowerUp && (Timeout > 0));
|
---|
576 | if (Status == EFI_SUCCESS) {
|
---|
577 | if (!OcrResponse.Ocr.PowerUp) {
|
---|
578 | DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD1): Card initialisation failure, Status=%r.\n", Status));
|
---|
579 | return EFI_DEVICE_ERROR;
|
---|
580 | }
|
---|
581 | OcrResponse.Ocr.PowerUp = 0;
|
---|
582 | if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB) {
|
---|
583 | MmcHostInstance->CardInfo.OCRData.AccessMode = BIT1;
|
---|
584 | }
|
---|
585 | else {
|
---|
586 | MmcHostInstance->CardInfo.OCRData.AccessMode = 0x0;
|
---|
587 | }
|
---|
588 | // Check whether MMC or eMMC
|
---|
589 | if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB ||
|
---|
590 | OcrResponse.Raw == EMMC_CMD1_CAPACITY_LESS_THAN_2GB) {
|
---|
591 | return EmmcIdentificationMode (MmcHostInstance, OcrResponse);
|
---|
592 | }
|
---|
593 | }
|
---|
594 |
|
---|
595 | // Are we using SDIO ?
|
---|
596 | Status = MmcHost->SendCommand (MmcHost, MMC_CMD5, 0);
|
---|
597 | if (Status == EFI_SUCCESS) {
|
---|
598 | DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD5): Error - SDIO not supported, Status=%r.\n", Status));
|
---|
599 | return EFI_UNSUPPORTED;
|
---|
600 | }
|
---|
601 |
|
---|
602 | // Check which kind of card we are using. Ver2.00 or later SD Memory Card (PL180 is SD v1.1)
|
---|
603 | CmdArg = (0x0UL << 12 | BIT8 | 0xCEUL << 0);
|
---|
604 | Status = MmcHost->SendCommand (MmcHost, MMC_CMD8, CmdArg);
|
---|
605 | if (Status == EFI_SUCCESS) {
|
---|
606 | DEBUG ((EFI_D_ERROR, "Card is SD2.0 => Supports high capacity\n"));
|
---|
607 | IsHCS = TRUE;
|
---|
608 | Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R7, Response);
|
---|
609 | if (EFI_ERROR (Status)) {
|
---|
610 | DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive response to CMD8, Status=%r.\n", Status));
|
---|
611 | return Status;
|
---|
612 | }
|
---|
613 | PrintResponseR1 (Response[0]);
|
---|
614 | // Check if it is valid response
|
---|
615 | if (Response[0] != CmdArg) {
|
---|
616 | DEBUG ((EFI_D_ERROR, "The Card is not usable\n"));
|
---|
617 | return EFI_UNSUPPORTED;
|
---|
618 | }
|
---|
619 | } else {
|
---|
620 | DEBUG ((EFI_D_ERROR, "Not a SD2.0 Card\n"));
|
---|
621 | }
|
---|
622 |
|
---|
623 | // We need to wait for the MMC or SD card is ready => (gCardInfo.OCRData.PowerUp == 1)
|
---|
624 | Timeout = MAX_RETRY_COUNT;
|
---|
625 | while (Timeout > 0) {
|
---|
626 | // SD Card or MMC Card ? CMD55 indicates to the card that the next command is an application specific command
|
---|
627 | Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, 0);
|
---|
628 | if (Status == EFI_SUCCESS) {
|
---|
629 | DEBUG ((EFI_D_INFO, "Card should be SD\n"));
|
---|
630 | if (IsHCS) {
|
---|
631 | MmcHostInstance->CardInfo.CardType = SD_CARD_2;
|
---|
632 | } else {
|
---|
633 | MmcHostInstance->CardInfo.CardType = SD_CARD;
|
---|
634 | }
|
---|
635 |
|
---|
636 | // Note: The first time CmdArg will be zero
|
---|
637 | CmdArg = ((UINTN *) &(MmcHostInstance->CardInfo.OCRData))[0];
|
---|
638 | if (IsHCS) {
|
---|
639 | CmdArg |= BIT30;
|
---|
640 | }
|
---|
641 | Status = MmcHost->SendCommand (MmcHost, MMC_ACMD41, CmdArg);
|
---|
642 | if (!EFI_ERROR (Status)) {
|
---|
643 | Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);
|
---|
644 | if (EFI_ERROR (Status)) {
|
---|
645 | DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));
|
---|
646 | return Status;
|
---|
647 | }
|
---|
648 | ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];
|
---|
649 | }
|
---|
650 | } else {
|
---|
651 | DEBUG ((EFI_D_INFO, "Card should be MMC\n"));
|
---|
652 | MmcHostInstance->CardInfo.CardType = MMC_CARD;
|
---|
653 |
|
---|
654 | Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, 0x800000);
|
---|
655 | if (!EFI_ERROR (Status)) {
|
---|
656 | Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);
|
---|
657 | if (EFI_ERROR (Status)) {
|
---|
658 | DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));
|
---|
659 | return Status;
|
---|
660 | }
|
---|
661 | ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];
|
---|
662 | }
|
---|
663 | }
|
---|
664 |
|
---|
665 | if (!EFI_ERROR (Status)) {
|
---|
666 | if (!MmcHostInstance->CardInfo.OCRData.PowerUp) {
|
---|
667 | gBS->Stall (1);
|
---|
668 | Timeout--;
|
---|
669 | } else {
|
---|
670 | if ((MmcHostInstance->CardInfo.CardType == SD_CARD_2) && (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1)) {
|
---|
671 | MmcHostInstance->CardInfo.CardType = SD_CARD_2_HIGH;
|
---|
672 | DEBUG ((EFI_D_ERROR, "High capacity card.\n"));
|
---|
673 | }
|
---|
674 | break; // The MMC/SD card is ready. Continue the Identification Mode
|
---|
675 | }
|
---|
676 | } else {
|
---|
677 | gBS->Stall (1);
|
---|
678 | Timeout--;
|
---|
679 | }
|
---|
680 | }
|
---|
681 |
|
---|
682 | if (Timeout == 0) {
|
---|
683 | DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(): No Card\n"));
|
---|
684 | return EFI_NO_MEDIA;
|
---|
685 | } else {
|
---|
686 | PrintOCR (Response[0]);
|
---|
687 | }
|
---|
688 |
|
---|
689 | Status = MmcNotifyState (MmcHostInstance, MmcReadyState);
|
---|
690 | if (EFI_ERROR (Status)) {
|
---|
691 | DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcReadyState\n"));
|
---|
692 | return Status;
|
---|
693 | }
|
---|
694 |
|
---|
695 | Status = MmcHost->SendCommand (MmcHost, MMC_CMD2, 0);
|
---|
696 | if (EFI_ERROR (Status)) {
|
---|
697 | DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD2): Error\n"));
|
---|
698 | return Status;
|
---|
699 | }
|
---|
700 | Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CID, Response);
|
---|
701 | if (EFI_ERROR (Status)) {
|
---|
702 | DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive CID, Status=%r.\n", Status));
|
---|
703 | return Status;
|
---|
704 | }
|
---|
705 |
|
---|
706 | PrintCID (Response);
|
---|
707 |
|
---|
708 | Status = MmcHost->NotifyState (MmcHost, MmcIdentificationState);
|
---|
709 | if (EFI_ERROR (Status)) {
|
---|
710 | DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdentificationState\n"));
|
---|
711 | return Status;
|
---|
712 | }
|
---|
713 |
|
---|
714 | //
|
---|
715 | // Note, SD specifications say that "if the command execution causes a state change, it
|
---|
716 | // will be visible to the host in the response to the next command"
|
---|
717 | // The status returned for this CMD3 will be 2 - identification
|
---|
718 | //
|
---|
719 | CmdArg = 1;
|
---|
720 | Status = MmcHost->SendCommand (MmcHost, MMC_CMD3, CmdArg);
|
---|
721 | if (EFI_ERROR (Status)) {
|
---|
722 | DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD3): Error\n"));
|
---|
723 | return Status;
|
---|
724 | }
|
---|
725 |
|
---|
726 | Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_RCA, Response);
|
---|
727 | if (EFI_ERROR (Status)) {
|
---|
728 | DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive RCA, Status=%r.\n", Status));
|
---|
729 | return Status;
|
---|
730 | }
|
---|
731 | PrintRCA (Response[0]);
|
---|
732 |
|
---|
733 | // For MMC card, RCA is assigned by CMD3 while CMD3 dumps the RCA for SD card
|
---|
734 | if (MmcHostInstance->CardInfo.CardType != MMC_CARD) {
|
---|
735 | MmcHostInstance->CardInfo.RCA = Response[0] >> 16;
|
---|
736 | } else {
|
---|
737 | MmcHostInstance->CardInfo.RCA = CmdArg;
|
---|
738 | }
|
---|
739 | Status = MmcNotifyState (MmcHostInstance, MmcStandByState);
|
---|
740 | if (EFI_ERROR (Status)) {
|
---|
741 | DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcStandByState\n"));
|
---|
742 | return Status;
|
---|
743 | }
|
---|
744 |
|
---|
745 | return EFI_SUCCESS;
|
---|
746 | }
|
---|
747 |
|
---|
748 | EFI_STATUS
|
---|
749 | InitializeMmcDevice (
|
---|
750 | IN MMC_HOST_INSTANCE *MmcHostInstance
|
---|
751 | )
|
---|
752 | {
|
---|
753 | EFI_STATUS Status;
|
---|
754 | EFI_MMC_HOST_PROTOCOL *MmcHost;
|
---|
755 | UINTN BlockCount;
|
---|
756 |
|
---|
757 | BlockCount = 1;
|
---|
758 | MmcHost = MmcHostInstance->MmcHost;
|
---|
759 |
|
---|
760 | Status = MmcIdentificationMode (MmcHostInstance);
|
---|
761 | if (EFI_ERROR (Status)) {
|
---|
762 | DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error in Identification Mode, Status=%r\n", Status));
|
---|
763 | return Status;
|
---|
764 | }
|
---|
765 |
|
---|
766 | Status = MmcNotifyState (MmcHostInstance, MmcTransferState);
|
---|
767 | if (EFI_ERROR (Status)) {
|
---|
768 | DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error MmcTransferState, Status=%r\n", Status));
|
---|
769 | return Status;
|
---|
770 | }
|
---|
771 |
|
---|
772 | if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) {
|
---|
773 | Status = InitializeSdMmcDevice (MmcHostInstance);
|
---|
774 | } else {
|
---|
775 | Status = InitializeEmmcDevice (MmcHostInstance);
|
---|
776 | }
|
---|
777 | if (EFI_ERROR (Status)) {
|
---|
778 | return Status;
|
---|
779 | }
|
---|
780 |
|
---|
781 | // Set Block Length
|
---|
782 | Status = MmcHost->SendCommand (MmcHost, MMC_CMD16, MmcHostInstance->BlockIo.Media->BlockSize);
|
---|
783 | if (EFI_ERROR (Status)) {
|
---|
784 | DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD16): Error MmcHostInstance->BlockIo.Media->BlockSize: %d and Error = %r\n",
|
---|
785 | MmcHostInstance->BlockIo.Media->BlockSize, Status));
|
---|
786 | return Status;
|
---|
787 | }
|
---|
788 |
|
---|
789 | // Block Count (not used). Could return an error for SD card
|
---|
790 | if (MmcHostInstance->CardInfo.CardType == MMC_CARD) {
|
---|
791 | Status = MmcHost->SendCommand (MmcHost, MMC_CMD23, BlockCount);
|
---|
792 | if (EFI_ERROR (Status)) {
|
---|
793 | DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD23): Error, Status=%r\n", Status));
|
---|
794 | return Status;
|
---|
795 | }
|
---|
796 | }
|
---|
797 |
|
---|
798 | return EFI_SUCCESS;
|
---|
799 | }
|
---|