Beispiel #1
0
/**
  This function can detect these card types:
    1. MMC card
    2. SD 1.1 card
    3. SD 2.0 standard card
    3. SD 2.0 high capacity card

  @param  CardData             Pointer to CARD_DATA.

  @return EFI_SUCCESS
  @return others

**/
EFI_STATUS
GetCardType (
  IN  CARD_DATA              *CardData
  )
{
  EFI_STATUS                 Status;
  EFI_SD_HOST_IO_PROTOCOL    *SDHostIo;
  UINT32                     Argument;
  UINT32                     ResponseData;
  UINT32                     Count;
  BOOLEAN                    SDCommand8Support;


  SDHostIo = CardData->SDHostIo;

  //
  // Reset the card
  //
  Status  = SendCommand (
              CardData,
              GO_IDLE_STATE,
              0,
              NoData,
              NULL,
              0,
              ResponseNo,
              TIMEOUT_COMMAND,
              NULL
              );
  if (EFI_ERROR (Status)) {
    DEBUG((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));
    goto Exit;
  }

  //
  //No spec requirment, can be adjusted
  //
  gBS->Stall (10 * 1000);


  //
  // Only 2.7V - 3.6V is supported for SD2.0, only SD 2.0 card can pass
  // MMC and SD1.1 card will fail this command
  //
  Argument          = (VOLTAGE_27_36 << 8) | CHECK_PATTERN;
  ResponseData      = 0;
  SDCommand8Support = FALSE;

  Status  = SendCommand (
              CardData,
              SEND_IF_COND,
              Argument,
              NoData,
              NULL,
              0,
              ResponseR7,
              TIMEOUT_COMMAND,
              &ResponseData
              );

  if (EFI_ERROR (Status)) {
    if (Status != EFI_TIMEOUT) {
       DEBUG((EFI_D_ERROR, "SEND_IF_COND Fail, none time out error\n"));
       goto Exit;
    }
  } else {
     if (ResponseData != Argument) {
       DEBUG((EFI_D_ERROR, "SEND_IF_COND Fail, respond data does not match send data\n"));
       Status = EFI_DEVICE_ERROR;
       goto Exit;
    }
    SDCommand8Support = TRUE;
  }


  Argument = 0;
  if (SDHostIo->HostCapability.V30Support == TRUE) {
    Argument |= BIT17 | BIT18;
  } else if (SDHostIo->HostCapability.V33Support == TRUE) {
    Argument |= BIT20 | BIT21;
  }

  if (SDCommand8Support) {
    //
    //If command SD_SEND_OP_COND sucessed, it should be set.
    // SD 1.1 card will ignore it
    // SD 2.0 standard card will repsond with CCS 0, SD high capacity card will respond with CCS 1
    // CCS is BIT30 of OCR
    Argument |= BIT30;
  }


  Count        = 20;
  //
  //Only SD card will respond to this command, and spec says the card only checks condition at first ACMD41 command
  //
  do {
    Status  = SendAppCommand (
                CardData,
                SD_SEND_OP_COND,
                Argument,
                NoData,
                NULL,
                0,
                ResponseR3,
                TIMEOUT_COMMAND,
                (UINT32*)&(CardData->OCRRegister)
                );
    if (EFI_ERROR (Status)) {
      if ((Status == EFI_TIMEOUT) && (!SDCommand8Support)) {
        CardData->CardType = MMCCard;
        Status = EFI_SUCCESS;
        DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, MMC card was identified\n"));
      } else {
        //
        // Not as expected, MMC card should has no response, which means timeout.
        // SD card should pass this command
        //
        DEBUG((EFI_D_ERROR, "SD_SEND_OP_COND Fail, check whether it is neither a MMC card nor a SD card\n"));
      }
      goto Exit;
    }
    //
    //Avoid waiting if sucess. Busy bit 0 means not ready
    //
    if (CardData->OCRRegister.Busy == 1) {
      break;
    }

    gBS->Stall (50 * 1000);
    Count--;
    if (Count == 0) {
      DEBUG((EFI_D_ERROR, "Card is always in busy state\n"));
      Status = EFI_TIMEOUT;
      goto Exit;
    }
  } while (1);

  //
  //Check supported voltage
  //
  Argument = 0;
  if (SDHostIo->HostCapability.V30Support == TRUE) {
    if ((CardData->OCRRegister.V270_V360 & BIT2) == BIT2) {
      Argument |= BIT17;
    } else if ((CardData->OCRRegister.V270_V360 & BIT3) == BIT3) {
      Argument |= BIT18;
    }
  } else if (SDHostIo->HostCapability.V33Support == TRUE) {
     if ((CardData->OCRRegister.V270_V360 & BIT5) == BIT5) {
       Argument |= BIT20;
     } else if ((CardData->OCRRegister.V270_V360 & BIT6) == BIT6) {
       Argument |= BIT21;
     }
  }

  if (Argument == 0) {
     //
     //No matched support voltage
     //
     PutCardInactive (CardData);
     DEBUG((EFI_D_ERROR, "No matched voltage for this card\n"));
     Status = EFI_UNSUPPORTED;
     goto Exit;
  }

  CardData->CardType = SDMemoryCard;
  if (SDCommand8Support == TRUE) {
   CardData->CardType = SDMemoryCard2;
   DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above standard card was identified\n"));
  }

  if ((CardData->OCRRegister.AccessMode & BIT1) == BIT1) {
    CardData->CardType = SDMemoryCard2High;
    DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above high capacity card was identified\n"));
  }



Exit:
  return Status;
}
Beispiel #2
0
/**
  MMC card high/low voltage selection function

  @param  CardData               Pointer to CARD_DATA.
                                
  @retval EFI_SUCCESS
  @retval EFI_INVALID_PARAMETER
  @retval EFI_UNSUPPORTED
  @retval EFI_BAD_BUFFER_SIZE

**/
EFI_STATUS
MMCCardVoltageSelection (
  IN  CARD_DATA              *CardData
  )   
{
  EFI_STATUS                 Status;
  EFI_SD_HOST_IO_PROTOCOL    *SDHostIo;
  UINT8                      Index; 
  UINT8                      Retry; 
  UINT32                     TimeOut;


  SDHostIo = CardData->SDHostIo;
  Status   = EFI_SUCCESS;
  //
  //First try the high voltage, then if supported choose the low voltage
  // 
  for (Index = 0; Index < 2; Index++) { 

    for (Retry = 0; Retry < 3; Retry++) {
      //
      // To bring back the normal MMC card to work
      // after sending the SD command. Otherwise some 
      // card could not work
   
      Status  = SendCommand (
                  SDHostIo,
                  GO_IDLE_STATE,
                  0,
                  NoData,
                  NULL,
                  0,  
                  ResponseNo,
                  TIMEOUT_COMMAND,
                  NULL
                  );
      if (EFI_ERROR (Status)) {
        DEBUG((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));
        continue;
      } 
      //
      //CE-ATA device needs long delay
      //
      gBS->Stall ((Retry + 1) * 50 * 1000);

      //
      //Get OCR register to check voltage support, first time the OCR is 0
      //
      Status  = SendCommand (
                  SDHostIo,
                  SEND_OP_COND,
                  0,
                  NoData,
                  NULL,
                  0,  
                  ResponseR3,
                  TIMEOUT_COMMAND,
                  (UINT32*)&(CardData->OCRRegister)
                  );
      if (!EFI_ERROR (Status)) {
        break;
      } 
    }
   
    if (Retry == 3) {
      DEBUG((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
      Status = EFI_DEVICE_ERROR;
      goto Exit;
    }

    if (CardData->OCRRegister.V170_V195 == 1) {
      CardData->DualVoltage = TRUE;
    }
    if (CardData->OCRRegister.V270_V360 != 0x1F &&
        CardData->OCRRegister.V200_V260 != 0) {
      DEBUG((EFI_D_ERROR, "Incompatiable voltage device\n"));
      PutCardInactive (CardData);
      Status = EFI_INCOMPATIBLE_VERSION;
      goto Exit;
    }
 
    if (Index == 0) {
      //
      //Choose the high voltage first
      //
      CardData->OCRRegister.V170_V195 = 0;
    } else {
      //
      //Choose the low voltage
      //
      CardData->OCRRegister.V170_V195 = 1;
      CardData->OCRRegister.V270_V360 = 0;
    }

    //
    //TimeOut Value, 5000 * 100 * 1000 = 5 s
    // 
    TimeOut = 5000;

    do {
      Status  = SendCommand (
                  SDHostIo,
                  SEND_OP_COND,
                  *(UINT32*)&(CardData->OCRRegister),
                  NoData,
                  NULL,
                  0,  
                  ResponseR3,
                  TIMEOUT_COMMAND,
                  (UINT32*)&(CardData->OCRRegister)
                  );
      if (EFI_ERROR (Status)) {
        DEBUG((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
        goto Exit;
      }  

      gBS->Stall (1 * 1000);
      TimeOut--;
      DEBUG((EFI_D_ERROR, "Card is always in busy state, timeout:%d(in 5000)\n", TimeOut));
      if (TimeOut == 0) {
        Status = EFI_TIMEOUT;
        goto Exit;
      }
    } while (CardData->OCRRegister.Busy != 1);

    if (CardData->DualVoltage == TRUE && SDHostIo->HostCapability.V18Support == TRUE) {
      //
      //Power Off the card and then power on into low voltage
      //
      SDHostIo->SetHostVoltage (SDHostIo, 0);
      gBS->Stall (1 * 1000);
      SDHostIo->SetHostVoltage (SDHostIo, 18);
    } else {
      //
      //Not support the low voltage, exit
      //
      break;
    }
  }

Exit:
  return Status;

}