1 /** @file
2
3 Block I/O protocol for MMC/SD device
4
5 Copyright (c) 2013-2015 Intel Corporation.
6
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "SDMediaDevice.h"
18
19 /**
20 Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
21
22 @param This The EFI_BLOCK_IO_PROTOCOL instance.
23 @param ExtendedVerification Indicates that the driver may perform a more exhaustive.
24 verification operation of the device during reset.
25 (This parameter is ingored in this driver.)
26
27 @retval EFI_SUCCESS Success
28 **/
29 EFI_STATUS
30 EFIAPI
MMCSDBlockReset(IN EFI_BLOCK_IO_PROTOCOL * This,IN BOOLEAN ExtendedVerification)31 MMCSDBlockReset (
32 IN EFI_BLOCK_IO_PROTOCOL *This,
33 IN BOOLEAN ExtendedVerification
34 )
35 {
36 CARD_DATA *CardData;
37 EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
38
39 CardData = CARD_DATA_FROM_THIS(This);
40 SDHostIo = CardData->SDHostIo;
41
42 return SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD);
43 }
44
45 /**
46 Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
47
48 @param This The EFI_BLOCK_IO_PROTOCOL instance.
49 @param MediaId The media id that the write request is for.
50 @param LBA The starting logical block address to read from on the device.
51 The caller is responsible for writing to only legitimate locations.
52 @param BufferSize The size of the Buffer in bytes. This must be a multiple of the
53 intrinsic block size of the device.
54 @param Buffer A pointer to the destination buffer for the data. The caller
55 is responsible for either having implicit or explicit ownership
56 of the buffer.
57
58 @retval EFI_SUCCESS Success
59 @retval EFI_DEVICE_ERROR Hardware Error
60 @retval EFI_INVALID_PARAMETER Parameter is error
61 @retval EFI_NO_MEDIA No media
62 @retval EFI_MEDIA_CHANGED Media Change
63 @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
64 **/
65 EFI_STATUS
66 EFIAPI
MMCSDBlockReadBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA LBA,IN UINTN BufferSize,OUT VOID * Buffer)67 MMCSDBlockReadBlocks (
68 IN EFI_BLOCK_IO_PROTOCOL *This,
69 IN UINT32 MediaId,
70 IN EFI_LBA LBA,
71 IN UINTN BufferSize,
72 OUT VOID *Buffer
73 )
74 {
75 EFI_STATUS Status;
76 UINT32 Address;
77 CARD_DATA *CardData;
78 EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
79 UINT32 RemainingLength;
80 UINT32 TransferLength;
81 UINT8 *BufferPointer;
82 BOOLEAN SectorAddressing;
83 UINTN TotalBlock;
84
85 DEBUG((EFI_D_INFO, "Read(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));
86 Status = EFI_SUCCESS;
87 CardData = CARD_DATA_FROM_THIS(This);
88 SDHostIo = CardData->SDHostIo;
89 if (MediaId != CardData->BlockIoMedia.MediaId) {
90 return EFI_MEDIA_CHANGED;
91 }
92
93 if (ModU64x32 (BufferSize,CardData->BlockIoMedia.BlockSize) != 0) {
94 return EFI_BAD_BUFFER_SIZE;
95 }
96 if ((CardData->CardType == SDMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {
97 SectorAddressing = TRUE;
98 } else {
99 SectorAddressing = FALSE;
100 }
101 if (SectorAddressing) {
102 //
103 //Block Address
104 //
105 Address = (UINT32)DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);
106 } else {
107 //
108 //Byte Address
109 //
110 Address = (UINT32)MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
111 }
112 TotalBlock = (UINTN) DivU64x32 (BufferSize, CardData->BlockIoMedia.BlockSize);
113 if (LBA + TotalBlock > CardData->BlockIoMedia.LastBlock + 1) {
114 return EFI_INVALID_PARAMETER;
115 }
116
117
118 if (!Buffer) {
119 Status = EFI_INVALID_PARAMETER;
120 DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks:Invalid parameter \r\n"));
121 goto Done;
122 }
123
124 if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
125 Status = EFI_BAD_BUFFER_SIZE;
126 DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: Bad buffer size \r\n"));
127 goto Done;
128 }
129
130 if (BufferSize == 0) {
131 Status = EFI_SUCCESS;
132 goto Done;
133 }
134
135
136
137
138 BufferPointer = Buffer;
139 RemainingLength = (UINT32)BufferSize;
140
141 while (RemainingLength > 0) {
142 if ((BufferSize > CardData->BlockIoMedia.BlockSize)) {
143 if (RemainingLength > SDHostIo->HostCapability.BoundarySize) {
144 TransferLength = SDHostIo->HostCapability.BoundarySize;
145 } else {
146 TransferLength = RemainingLength;
147 }
148
149 if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
150 if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {
151 Status = SendCommand (
152 CardData,
153 SET_BLOCKLEN,
154 CardData->BlockIoMedia.BlockSize,
155 NoData,
156 NULL,
157 0,
158 ResponseR1,
159 TIMEOUT_COMMAND,
160 (UINT32*)&(CardData->CardStatus)
161 );
162 if (EFI_ERROR (Status)) {
163 break;
164 }
165 }
166 Status = SendCommand (
167 CardData,
168 SET_BLOCK_COUNT,
169 TransferLength / CardData->BlockIoMedia.BlockSize,
170 NoData,
171 NULL,
172 0,
173 ResponseR1,
174 TIMEOUT_COMMAND,
175 (UINT32*)&(CardData->CardStatus)
176 );
177 if (EFI_ERROR (Status)) {
178 break;
179 }
180 }
181 Status = SendCommand (
182 CardData,
183 READ_MULTIPLE_BLOCK,
184 Address,
185 InData,
186 CardData->AlignedBuffer,
187 TransferLength,
188 ResponseR1,
189 TIMEOUT_DATA,
190 (UINT32*)&(CardData->CardStatus)
191 );
192
193 if (EFI_ERROR (Status)) {
194 DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_MULTIPLE_BLOCK -> Fail\n"));
195 break;
196 }
197 } else {
198 if (RemainingLength > CardData->BlockIoMedia.BlockSize) {
199 TransferLength = CardData->BlockIoMedia.BlockSize;
200 } else {
201 TransferLength = RemainingLength;
202 }
203
204 Status = SendCommand (
205 CardData,
206 READ_SINGLE_BLOCK,
207 Address,
208 InData,
209 CardData->AlignedBuffer,
210 (UINT32)TransferLength,
211 ResponseR1,
212 TIMEOUT_DATA,
213 (UINT32*)&(CardData->CardStatus)
214 );
215 if (EFI_ERROR (Status)) {
216 DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_SINGLE_BLOCK -> Fail\n"));
217 break;
218 }
219 }
220 CopyMem (BufferPointer, CardData->AlignedBuffer, TransferLength);
221
222 if (SectorAddressing) {
223 //
224 //Block Address
225 //
226 Address += TransferLength / 512;
227 } else {
228 //
229 //Byte Address
230 //
231 Address += TransferLength;
232 }
233 BufferPointer += TransferLength;
234 RemainingLength -= TransferLength;
235 }
236
237
238 if (EFI_ERROR (Status)) {
239 if ((CardData->CardType == SDMemoryCard) ||
240 (CardData->CardType == SDMemoryCard2)||
241 (CardData->CardType == SDMemoryCard2High)) {
242 SendCommand (
243 CardData,
244 STOP_TRANSMISSION,
245 0,
246 NoData,
247 NULL,
248 0,
249 ResponseR1b,
250 TIMEOUT_COMMAND,
251 (UINT32*)&(CardData->CardStatus)
252 );
253 } else {
254 SendCommand (
255 CardData,
256 STOP_TRANSMISSION,
257 0,
258 NoData,
259 NULL,
260 0,
261 ResponseR1,
262 TIMEOUT_COMMAND,
263 (UINT32*)&(CardData->CardStatus)
264 );
265 }
266
267 }
268
269
270 Done:
271 DEBUG((EFI_D_INFO, "MMCSDBlockReadBlocks: Status = %r\n", Status));
272 return Status;
273 }
274
275 /**
276 Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
277
278 @param This The EFI_BLOCK_IO_PROTOCOL instance.
279 @param MediaId The media id that the write request is for.
280 @param LBA The starting logical block address to read from on the device.
281 The caller is responsible for writing to only legitimate locations.
282 @param BufferSize The size of the Buffer in bytes. This must be a multiple of the
283 intrinsic block size of the device.
284 @param Buffer A pointer to the destination buffer for the data. The caller
285 is responsible for either having implicit or explicit ownership
286 of the buffer.
287
288 @retval EFI_SUCCESS Success
289 @retval EFI_DEVICE_ERROR Hardware Error
290 @retval EFI_INVALID_PARAMETER Parameter is error
291 @retval EFI_NO_MEDIA No media
292 @retval EFI_MEDIA_CHANGED Media Change
293 @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
294 **/
295 EFI_STATUS
296 EFIAPI
MMCSDBlockWriteBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA LBA,IN UINTN BufferSize,IN VOID * Buffer)297 MMCSDBlockWriteBlocks (
298 IN EFI_BLOCK_IO_PROTOCOL *This,
299 IN UINT32 MediaId,
300 IN EFI_LBA LBA,
301 IN UINTN BufferSize,
302 IN VOID *Buffer
303 )
304 {
305 EFI_STATUS Status;
306 UINT32 Address;
307 CARD_DATA *CardData;
308 EFI_SD_HOST_IO_PROTOCOL *SDHostIo;
309 UINT32 RemainingLength;
310 UINT32 TransferLength;
311 UINT8 *BufferPointer;
312 BOOLEAN SectorAddressing;
313
314 DEBUG((EFI_D_INFO, "Write(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));
315 Status = EFI_SUCCESS;
316 CardData = CARD_DATA_FROM_THIS(This);
317 SDHostIo = CardData->SDHostIo;
318 if ((CardData->CardType == SDMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {
319 SectorAddressing = TRUE;
320 } else {
321 SectorAddressing = FALSE;
322 }
323 if (SectorAddressing) {
324 //
325 //Block Address
326 //
327 Address = (UINT32)DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);
328 } else {
329 //
330 //Byte Address
331 //
332 Address = (UINT32)MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
333 }
334
335 if (!Buffer) {
336 Status = EFI_INVALID_PARAMETER;
337 DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Invalid parameter \r\n"));
338 goto Done;
339 }
340
341 if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
342 Status = EFI_BAD_BUFFER_SIZE;
343 DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Bad buffer size \r\n"));
344 goto Done;
345 }
346
347 if (BufferSize == 0) {
348 Status = EFI_SUCCESS;
349 goto Done;
350 }
351
352 if (This->Media->ReadOnly == TRUE) {
353 Status = EFI_WRITE_PROTECTED;
354 DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Write protected \r\n"));
355 goto Done;
356 }
357
358
359
360 BufferPointer = Buffer;
361 RemainingLength = (UINT32)BufferSize;
362
363 while (RemainingLength > 0) {
364 if ((BufferSize > CardData->BlockIoMedia.BlockSize) ) {
365 if (RemainingLength > SDHostIo->HostCapability.BoundarySize) {
366 TransferLength = SDHostIo->HostCapability.BoundarySize;
367 } else {
368 TransferLength = RemainingLength;
369 }
370
371 if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
372
373 if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {
374 Status = SendCommand (
375 CardData,
376 SET_BLOCKLEN,
377 CardData->BlockIoMedia.BlockSize,
378 NoData,
379 NULL,
380 0,
381 ResponseR1,
382 TIMEOUT_COMMAND,
383 (UINT32*)&(CardData->CardStatus)
384 );
385 if (EFI_ERROR (Status)) {
386 break;
387 }
388 }
389 Status = SendCommand (
390 CardData,
391 SET_BLOCK_COUNT,
392 TransferLength / CardData->BlockIoMedia.BlockSize,
393 NoData,
394 NULL,
395 0,
396 ResponseR1,
397 TIMEOUT_COMMAND,
398 (UINT32*)&(CardData->CardStatus)
399 );
400 if (EFI_ERROR (Status)) {
401 break;
402 }
403 }
404
405 CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
406
407 Status = SendCommand (
408 CardData,
409 WRITE_MULTIPLE_BLOCK,
410 Address,
411 OutData,
412 CardData->AlignedBuffer,
413 (UINT32)TransferLength,
414 ResponseR1,
415 TIMEOUT_DATA,
416 (UINT32*)&(CardData->CardStatus)
417 );
418 if (EFI_ERROR (Status)) {
419 DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: WRITE_MULTIPLE_BLOCK -> Fail\n"));
420 break;
421 }
422 } else {
423 if (RemainingLength > CardData->BlockIoMedia.BlockSize) {
424 TransferLength = CardData->BlockIoMedia.BlockSize;
425 } else {
426 TransferLength = RemainingLength;
427 }
428
429 CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
430
431 Status = SendCommand (
432 CardData,
433 WRITE_BLOCK,
434 Address,
435 OutData,
436 CardData->AlignedBuffer,
437 (UINT32)TransferLength,
438 ResponseR1,
439 TIMEOUT_DATA,
440 (UINT32*)&(CardData->CardStatus)
441 );
442 }
443 if (SectorAddressing) {
444 //
445 //Block Address
446 //
447 Address += TransferLength / 512;
448 } else {
449 //
450 //Byte Address
451 //
452 Address += TransferLength;
453 }
454 BufferPointer += TransferLength;
455 RemainingLength -= TransferLength;
456
457 }
458
459 if (EFI_ERROR (Status)) {
460 SendCommand (
461 CardData,
462 STOP_TRANSMISSION,
463 0,
464 NoData,
465 NULL,
466 0,
467 ResponseR1b,
468 TIMEOUT_COMMAND,
469 (UINT32*)&(CardData->CardStatus)
470 );
471
472 }
473
474
475 Done:
476 return EFI_SUCCESS;
477 }
478
479 /**
480 Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
481 (In this driver, this function just returns EFI_SUCCESS.)
482
483 @param This The EFI_BLOCK_IO_PROTOCOL instance.
484
485 @retval EFI_SUCCESS
486 @retval Others
487 **/
488 EFI_STATUS
489 EFIAPI
MMCSDBlockFlushBlocks(IN EFI_BLOCK_IO_PROTOCOL * This)490 MMCSDBlockFlushBlocks (
491 IN EFI_BLOCK_IO_PROTOCOL *This
492 )
493 {
494 return EFI_SUCCESS;
495 }
496
497
498 /**
499 MMC/SD card BlockIo init function.
500
501 @param CardData Pointer to CARD_DATA.
502
503 @retval EFI_SUCCESS
504 @retval Others
505 **/
506 EFI_STATUS
MMCSDBlockIoInit(IN CARD_DATA * CardData)507 MMCSDBlockIoInit (
508 IN CARD_DATA *CardData
509 )
510 {
511 //
512 //BlockIO protocol
513 //
514 CardData->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
515 CardData->BlockIo.Media = &(CardData->BlockIoMedia);
516 CardData->BlockIo.Reset = MMCSDBlockReset;
517 CardData->BlockIo.ReadBlocks = MMCSDBlockReadBlocks ;
518 CardData->BlockIo.WriteBlocks = MMCSDBlockWriteBlocks;
519 CardData->BlockIo.FlushBlocks = MMCSDBlockFlushBlocks;
520
521 CardData->BlockIoMedia.MediaId = 0;
522 CardData->BlockIoMedia.RemovableMedia = FALSE;
523 CardData->BlockIoMedia.MediaPresent = TRUE;
524 CardData->BlockIoMedia.LogicalPartition = FALSE;
525
526 if (CardData->CSDRegister.PERM_WRITE_PROTECT || CardData->CSDRegister.TMP_WRITE_PROTECT) {
527 CardData->BlockIoMedia.ReadOnly = TRUE;
528 } else {
529 CardData->BlockIoMedia.ReadOnly = FALSE;
530 }
531
532
533 CardData->BlockIoMedia.WriteCaching = FALSE;
534 CardData->BlockIoMedia.BlockSize = CardData->BlockLen;
535 CardData->BlockIoMedia.IoAlign = 1;
536 CardData->BlockIoMedia.LastBlock = (EFI_LBA)(CardData->BlockNumber - 1);
537
538
539 return EFI_SUCCESS;
540
541 }
542
543
544
545