1 /** @file
2 
3 CEATA specific functions implementation
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   Send RW_MULTIPLE_REGISTER command
21 
22   @param  CardData             Pointer to CARD_DATA.
23   @param  Address              Register address.
24   @param  ByteCount            Buffer size.
25   @param  Write                TRUE means write, FALSE means read.
26   @param  Buffer               Buffer pointer.
27 
28   @retval EFI_SUCCESS                Success
29   @retval EFI_DEVICE_ERROR           Hardware Error
30   @retval EFI_INVALID_PARAMETER      Parameter is error
31   @retval EFI_NO_MEDIA               No media
32   @retval EFI_MEDIA_CHANGED          Media Change
33   @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
34 
35 **/
36 EFI_STATUS
ReadWriteMultipleRegister(IN CARD_DATA * CardData,IN UINT16 Address,IN UINT8 ByteCount,IN BOOLEAN Write,IN UINT8 * Buffer)37 ReadWriteMultipleRegister (
38   IN  CARD_DATA   *CardData,
39   IN  UINT16      Address,
40   IN  UINT8       ByteCount,
41   IN  BOOLEAN     Write,
42   IN  UINT8       *Buffer
43   )
44 {
45   EFI_STATUS                 Status;
46   UINT32                     Argument;
47 
48   Status   = EFI_SUCCESS;
49 
50   if ((Address % 4 != 0) || (ByteCount % 4 != 0)) {
51     Status = EFI_INVALID_PARAMETER;
52     goto Exit;
53   }
54 
55   Argument = (Address << 16) | ByteCount;
56   if (Write) {
57     Argument |= BIT31;
58   }
59 
60 
61   if (Write) {
62     CopyMem (CardData->AlignedBuffer, Buffer, ByteCount);
63 
64     Status = SendCommand (
65                CardData,
66                RW_MULTIPLE_REGISTER,
67                Argument,
68                OutData,
69                CardData->AlignedBuffer,
70                ByteCount,
71                ResponseR1b,
72                TIMEOUT_DATA,
73                (UINT32*)&(CardData->CardStatus)
74                );
75   } else {
76     Status = SendCommand (
77                CardData,
78                RW_MULTIPLE_REGISTER,
79                Argument,
80                InData,
81                CardData->AlignedBuffer,
82                ByteCount,
83                ResponseR1,
84                TIMEOUT_DATA,
85                (UINT32*)&(CardData->CardStatus)
86                );
87     if (!EFI_ERROR (Status)) {
88       CopyMem (Buffer, CardData->AlignedBuffer, ByteCount);
89     }
90 
91   }
92 Exit:
93   return Status;
94 }
95 
96 /**
97   Send ReadWriteMultipleBlock command with RW_MULTIPLE_REGISTER command
98 
99   @param  CardData             Pointer to CARD_DATA.
100   @param  DataUnitCount        Buffer size in 512 bytes unit.
101   @param  Write                TRUE means write, FALSE means read.
102   @param  Buffer               Buffer pointer.
103 
104   @retval EFI_SUCCESS                Success
105   @retval EFI_DEVICE_ERROR           Hardware Error
106   @retval EFI_INVALID_PARAMETER      Parameter is error
107   @retval EFI_NO_MEDIA               No media
108   @retval EFI_MEDIA_CHANGED          Media Change
109   @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
110 
111 **/
112 EFI_STATUS
ReadWriteMultipleBlock(IN CARD_DATA * CardData,IN UINT16 DataUnitCount,IN BOOLEAN Write,IN UINT8 * Buffer)113 ReadWriteMultipleBlock (
114   IN  CARD_DATA   *CardData,
115   IN  UINT16      DataUnitCount,
116   IN  BOOLEAN     Write,
117   IN  UINT8       *Buffer
118   )
119 {
120   EFI_STATUS                 Status;
121   EFI_SD_HOST_IO_PROTOCOL    *SDHostIo;
122   UINT32                     TransferLength;
123 
124   Status   = EFI_SUCCESS;
125   SDHostIo = CardData->SDHostIo;
126 
127   TransferLength = DataUnitCount * DATA_UNIT_SIZE;
128   if (TransferLength > SDHostIo->HostCapability.BoundarySize) {
129     return EFI_INVALID_PARAMETER;
130   }
131 
132   if (Write) {
133     CopyMem (CardData->AlignedBuffer, Buffer, TransferLength);
134 
135     Status = SendCommand (
136                CardData,
137                RW_MULTIPLE_BLOCK,
138                (DataUnitCount | BIT31),
139                OutData,
140                CardData->AlignedBuffer,
141                TransferLength,
142                ResponseR1b,
143                TIMEOUT_DATA,
144                (UINT32*)&(CardData->CardStatus)
145                );
146    } else {
147       Status = SendCommand (
148                  CardData,
149                  RW_MULTIPLE_BLOCK,
150                  DataUnitCount,
151                  InData,
152                  CardData->AlignedBuffer,
153                  TransferLength,
154                  ResponseR1,
155                  TIMEOUT_DATA,
156                  (UINT32*)&(CardData->CardStatus)
157                  );
158       if (!EFI_ERROR (Status)) {
159         CopyMem (Buffer, CardData->AlignedBuffer, TransferLength);
160       }
161   }
162 
163   return Status;
164 }
165 
166 /**
167   Send software reset
168 
169   @param  CardData             Pointer to CARD_DATA.
170 
171   @retval EFI_SUCCESS                Success
172   @retval EFI_DEVICE_ERROR           Hardware Error
173   @retval EFI_INVALID_PARAMETER      Parameter is error
174   @retval EFI_NO_MEDIA               No media
175   @retval EFI_MEDIA_CHANGED          Media Change
176   @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
177 
178 **/
179 EFI_STATUS
SoftwareReset(IN CARD_DATA * CardData)180 SoftwareReset (
181   IN  CARD_DATA    *CardData
182   )
183 {
184   EFI_STATUS    Status;
185   UINT8         Data;
186   UINT32        TimeOut;
187 
188   Data = BIT2;
189 
190   Status = FastIO (CardData, Reg_Control, &Data, TRUE);
191   if (EFI_ERROR (Status)) {
192     goto Exit;
193   }
194 
195   TimeOut = 5 * 1000;
196 
197   do {
198     gBS->Stall (1 * 1000);
199     Status = FastIO (CardData, Reg_Control, &Data, FALSE);
200     if (EFI_ERROR (Status)) {
201       goto Exit;
202     }
203     if ((Data & BIT2) == BIT2) {
204       break;
205     }
206 
207     TimeOut--;
208   } while (TimeOut > 0);
209 
210   if (TimeOut == 0) {
211    Status = EFI_TIMEOUT;
212    goto Exit;
213   }
214 
215   Data &= ~BIT2;
216   Status = FastIO (CardData, Reg_Control, &Data, TRUE);
217 
218   TimeOut = 5 * 1000;
219 
220   do {
221     gBS->Stall (1 * 1000);
222     Status = FastIO (CardData, Reg_Control, &Data, FALSE);
223     if (EFI_ERROR (Status)) {
224       goto Exit;
225     }
226     if ((Data & BIT2) != BIT2) {
227       break;
228     }
229 
230     TimeOut--;
231   } while (TimeOut > 0);
232 
233 
234   if (TimeOut == 0) {
235    Status = EFI_TIMEOUT;
236    goto Exit;
237   }
238 
239 
240 Exit:
241   return Status;
242 }
243 
244 
245 /**
246   SendATACommand specificed in Taskfile
247 
248   @param  CardData             Pointer to CARD_DATA.
249   @param  TaskFile             Pointer to TASK_FILE.
250   @param  Write                TRUE means write, FALSE means read.
251   @param  Buffer               If NULL, means no data transfer, neither read nor write.
252   @param  SectorCount          Buffer size in 512 bytes unit.
253 
254   @retval EFI_SUCCESS                Success
255   @retval EFI_DEVICE_ERROR           Hardware Error
256   @retval EFI_INVALID_PARAMETER      Parameter is error
257   @retval EFI_NO_MEDIA               No media
258   @retval EFI_MEDIA_CHANGED          Media Change
259   @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
260 
261 **/
262 EFI_STATUS
SendATACommand(IN CARD_DATA * CardData,IN TASK_FILE * TaskFile,IN BOOLEAN Write,IN UINT8 * Buffer,IN UINT16 SectorCount)263 SendATACommand (
264   IN  CARD_DATA   *CardData,
265   IN  TASK_FILE   *TaskFile,
266   IN  BOOLEAN     Write,
267   IN  UINT8       *Buffer,
268   IN  UINT16      SectorCount
269   )
270 {
271   EFI_STATUS                 Status;
272   EFI_SD_HOST_IO_PROTOCOL    *SDHostIo;
273   UINT8                      Data;
274   UINT32                     TimeOut;
275 
276   SDHostIo = CardData->SDHostIo;
277 
278   //
279   //Write register
280   //
281   Status = ReadWriteMultipleRegister (
282              CardData,
283              0,
284              sizeof (TASK_FILE),
285              TRUE,
286              (UINT8*)TaskFile
287              );
288   if (EFI_ERROR (Status)) {
289     DEBUG((EFI_D_ERROR, "ReadWriteMultipleRegister 0x%x\n", Status));
290     goto Exit;
291   }
292 
293   TimeOut = 5000;
294   do {
295     gBS->Stall (1 * 1000);
296     Data = 0;
297     Status = FastIO (
298                CardData,
299                Reg_Command_Status,
300                &Data,
301                FALSE
302                );
303     if (EFI_ERROR (Status)) {
304       return Status;
305     }
306 
307     if (((Data & BIT7) == 0) && ((Data & BIT6) == BIT6)) {
308       break;
309     }
310 
311     TimeOut --;
312   } while (TimeOut > 0);
313 
314   if (TimeOut == 0) {
315     DEBUG((EFI_D_ERROR, "ReadWriteMultipleRegister FastIO EFI_TIMEOUT 0x%x\n", Data));
316     Status = EFI_TIMEOUT;
317     goto Exit;
318   }
319 
320 
321   if (Buffer != NULL) {
322     Status = ReadWriteMultipleBlock (
323                CardData,
324                SectorCount,
325                Write,
326                (UINT8*)Buffer
327                );
328     if (EFI_ERROR (Status)) {
329       DEBUG((EFI_D_ERROR, "ReadWriteMultipleBlock EFI_TIMEOUT 0x%x\n", Status));
330       goto Exit;
331     }
332 
333     TimeOut = 5 * 1000;
334     do {
335       gBS->Stall (1 * 1000);
336 
337       Data = 0;
338       Status = FastIO (
339                  CardData,
340                  Reg_Command_Status,
341                  &Data,
342                  FALSE
343                  );
344       if (EFI_ERROR (Status)) {
345         return Status;
346       }
347 
348       if (((Data & BIT7) == 0) && ((Data & BIT3) == 0)) {
349         break;
350       }
351 
352       TimeOut --;
353     } while (TimeOut > 0);
354     if (TimeOut == 0) {
355       DEBUG((EFI_D_ERROR, "ReadWriteMultipleBlock FastIO EFI_TIMEOUT 0x%x\n", Data));
356       Status = EFI_TIMEOUT;
357       goto Exit;
358     }
359 
360 
361     if (((Data & BIT6) == BIT6) && (Data & BIT0) == 0) {
362       Status = EFI_SUCCESS;
363     } else {
364       Status = EFI_DEVICE_ERROR;
365     }
366   }
367 
368 Exit:
369   if (EFI_ERROR (Status)) {
370     SoftwareReset (CardData);
371   }
372 
373   return Status;
374 }
375 
376 /**
377   IDENTIFY_DEVICE command
378 
379   @param  CardData             Pointer to CARD_DATA.
380 
381   @retval EFI_SUCCESS                Success
382   @retval EFI_DEVICE_ERROR           Hardware Error
383   @retval EFI_INVALID_PARAMETER      Parameter is error
384   @retval EFI_NO_MEDIA               No media
385   @retval EFI_MEDIA_CHANGED          Media Change
386   @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
387 
388 **/
389 EFI_STATUS
IndentifyDevice(IN CARD_DATA * CardData)390 IndentifyDevice (
391   IN  CARD_DATA    *CardData
392   )
393 {
394   EFI_STATUS                 Status;
395 
396   ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
397 
398   //
399   //The host only supports nIEN = 0
400   //
401   CardData->TaskFile.Command_Status = IDENTIFY_DEVICE;
402 
403 
404   Status = SendATACommand (
405              CardData,
406              &CardData->TaskFile,
407              FALSE,
408              (UINT8*)&(CardData->IndentifyDeviceData),
409              1
410              );
411 
412 
413   return Status;
414 }
415 
416 /**
417   FLUSH_CACHE_EXT command
418 
419   @param  CardData             Pointer to CARD_DATA.
420 
421   @retval EFI_SUCCESS                Success
422   @retval EFI_DEVICE_ERROR           Hardware Error
423   @retval EFI_INVALID_PARAMETER      Parameter is error
424   @retval EFI_NO_MEDIA               No media
425   @retval EFI_MEDIA_CHANGED          Media Change
426   @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
427 
428 **/
429 EFI_STATUS
FlushCache(IN CARD_DATA * CardData)430 FlushCache (
431   IN  CARD_DATA    *CardData
432   )
433 {
434 
435   //
436   //Hitachi CE-ATA will always make the busy high after
437   //receving this command
438   //
439 /*
440   EFI_STATUS  Status;
441   ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
442   //
443   //The host only supports nIEN = 0
444   //
445   CardData->TaskFile.Command_Status = FLUSH_CACHE_EXT;
446 
447   Status = SendATACommand (
448              CardData,
449              &CardData->TaskFile,
450              FALSE,
451              NULL,
452              0
453              );
454 */
455   return EFI_SUCCESS;
456 }
457 
458 /**
459   STANDBY_IMMEDIATE command
460 
461   @param  CardData             Pointer to CARD_DATA.
462 
463   @retval EFI_SUCCESS                Success
464   @retval EFI_DEVICE_ERROR           Hardware Error
465   @retval EFI_INVALID_PARAMETER      Parameter is error
466   @retval EFI_NO_MEDIA               No media
467   @retval EFI_MEDIA_CHANGED          Media Change
468   @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
469 
470 **/
471 EFI_STATUS
StandByImmediate(IN CARD_DATA * CardData)472 StandByImmediate (
473   IN  CARD_DATA    *CardData
474   )
475 {
476   EFI_STATUS  Status;
477 
478   ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
479   //
480   //The host only supports nIEN = 0
481   //
482   CardData->TaskFile.Command_Status = STANDBY_IMMEDIATE;
483 
484 
485   Status = SendATACommand (
486              CardData,
487              &CardData->TaskFile,
488              FALSE,
489              NULL,
490              0
491              );
492   return Status;
493 }
494 
495 /**
496   READ_DMA_EXT command
497 
498   @param  CardData             Pointer to CARD_DATA.
499   @param  LBA                  The starting logical block address to read from on the device.
500   @param  Buffer               A pointer to the destination buffer for the data. The caller
501                                is responsible for either having implicit or explicit ownership
502                                of the buffer.
503   @param  SectorCount          Size in 512 bytes unit.
504 
505   @retval EFI_SUCCESS                Success
506   @retval EFI_DEVICE_ERROR           Hardware Error
507   @retval EFI_INVALID_PARAMETER      Parameter is error
508   @retval EFI_NO_MEDIA               No media
509   @retval EFI_MEDIA_CHANGED          Media Change
510   @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
511 
512 **/
513 EFI_STATUS
ReadDMAExt(IN CARD_DATA * CardData,IN EFI_LBA LBA,IN UINT8 * Buffer,IN UINT16 SectorCount)514 ReadDMAExt (
515   IN  CARD_DATA   *CardData,
516   IN  EFI_LBA     LBA,
517   IN  UINT8       *Buffer,
518   IN  UINT16      SectorCount
519   )
520 {
521 
522   EFI_STATUS  Status;
523 
524   ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
525   //
526   //The host only supports nIEN = 0
527   //
528   CardData->TaskFile.Command_Status = READ_DMA_EXT;
529 
530   CardData->TaskFile.SectorCount     = (UINT8)SectorCount;
531   CardData->TaskFile.SectorCount_Exp = (UINT8)(SectorCount >> 8);
532 
533   CardData->TaskFile.LBALow          = (UINT8)LBA;
534   CardData->TaskFile.LBAMid          = (UINT8)RShiftU64(LBA, 8);
535   CardData->TaskFile.LBAHigh         = (UINT8)RShiftU64(LBA, 16);
536 
537   CardData->TaskFile.LBALow_Exp      = (UINT8)RShiftU64(LBA, 24);
538   CardData->TaskFile.LBAMid_Exp      = (UINT8)RShiftU64(LBA, 32);
539   CardData->TaskFile.LBAHigh_Exp     = (UINT8)RShiftU64(LBA, 40);
540 
541   Status = SendATACommand (
542              CardData,
543              &CardData->TaskFile,
544              FALSE,
545              Buffer,
546              SectorCount
547              );
548   return Status;
549 
550 }
551 
552 /**
553   WRITE_DMA_EXT command
554 
555   @param  CardData             Pointer to CARD_DATA.
556   @param  LBA                  The starting logical block address to read from on the device.
557   @param  Buffer               A pointer to the destination buffer for the data. The caller
558                                is responsible for either having implicit or explicit ownership
559                                of the buffer.
560   @param  SectorCount          Size in 512 bytes unit.
561 
562   @retval EFI_SUCCESS                Success
563   @retval EFI_DEVICE_ERROR           Hardware Error
564   @retval EFI_INVALID_PARAMETER      Parameter is error
565   @retval EFI_NO_MEDIA               No media
566   @retval EFI_MEDIA_CHANGED          Media Change
567   @retval EFI_BAD_BUFFER_SIZE        Buffer size is bad
568 
569 **/
570 EFI_STATUS
WriteDMAExt(IN CARD_DATA * CardData,IN EFI_LBA LBA,IN UINT8 * Buffer,IN UINT16 SectorCount)571 WriteDMAExt (
572   IN  CARD_DATA   *CardData,
573   IN  EFI_LBA     LBA,
574   IN  UINT8       *Buffer,
575   IN  UINT16      SectorCount
576   )
577 {
578 
579   EFI_STATUS  Status;
580 
581   ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
582   //
583   //The host only supports nIEN = 0
584   //
585   CardData->TaskFile.Command_Status = WRITE_DMA_EXT;
586 
587   CardData->TaskFile.SectorCount     = (UINT8)SectorCount;
588   CardData->TaskFile.SectorCount_Exp = (UINT8)(SectorCount >> 8);
589 
590   CardData->TaskFile.LBALow          = (UINT8)LBA;
591   CardData->TaskFile.LBAMid          = (UINT8)RShiftU64(LBA, 8);
592   CardData->TaskFile.LBAHigh         = (UINT8)RShiftU64(LBA, 16);
593 
594   CardData->TaskFile.LBALow_Exp      = (UINT8)RShiftU64(LBA, 24);
595   CardData->TaskFile.LBAMid_Exp      = (UINT8)RShiftU64(LBA, 32);
596   CardData->TaskFile.LBAHigh_Exp     = (UINT8)RShiftU64(LBA, 40);
597 
598   Status = SendATACommand (
599              CardData,
600              &CardData->TaskFile,
601              TRUE,
602              Buffer,
603              SectorCount
604              );
605   return Status;
606 
607 }
608 
609 
610 /**
611   Judge whether it is CE-ATA device or not.
612 
613   @param  CardData             Pointer to CARD_DATA.
614 
615   @retval TRUE
616   @retval FALSE
617 
618 **/
619 BOOLEAN
IsCEATADevice(IN CARD_DATA * CardData)620 IsCEATADevice (
621   IN  CARD_DATA    *CardData
622   )
623 {
624   EFI_STATUS                 Status;
625 
626   Status = ReadWriteMultipleRegister (
627              CardData,
628              0,
629              sizeof (TASK_FILE),
630              FALSE,
631              (UINT8*)&CardData->TaskFile
632              );
633   if (EFI_ERROR (Status)) {
634     //
635     //To bring back the normal MMC card to work
636     //
637     CardData->SDHostIo->ResetSDHost (CardData->SDHostIo, Reset_DAT_CMD);
638     return FALSE;
639   }
640 
641   if (CardData->TaskFile.LBAMid == CE_ATA_SIG_CE &&
642       CardData->TaskFile.LBAHigh == CE_ATA_SIG_AA
643     ) {
644     //
645     //Disable Auto CMD for CE-ATA
646     //
647     CardData->SDHostIo->EnableAutoStopCmd (CardData->SDHostIo, FALSE);
648 
649     return TRUE;
650   }
651 
652   return FALSE;
653 }
654 
655 
656 
657