Example #1
0
/**
  This function set the bus and device width for MMC card

  @param  CardData               Pointer to CARD_DATA.
  @param  Width                  1, 4, 8 bits.

  @retval EFI_SUCCESS
  @retval EFI_UNSUPPORTED
  @retval EFI_INVALID_PARAMETER

**/
EFI_STATUS
MMCCardSetBusWidth (
  IN  CARD_DATA              *CardData,
  IN  UINT8                  BusWidth,
  IN  BOOLEAN                EnableDDRMode
  )
{
  EFI_STATUS                 Status;
  EFI_SD_HOST_IO_PROTOCOL    *SDHostIo;
  SWITCH_ARGUMENT            SwitchArgument;
  UINT8                      Value;

  SDHostIo = CardData->SDHostIo;
  Value = 0;
  switch (BusWidth) {
    case 8:
      if (EnableDDRMode)
        Value = 6;
      else
      Value = 2;
      break;

    case 4:
      if (EnableDDRMode)
        Value = 5;
      else
      Value = 1;
      break;

    case 1:
      if (EnableDDRMode)    // Bus width 1 is not supported in ddr mode
        return EFI_UNSUPPORTED;
      Value = 0;
      break;

    default:
     ASSERT(0);
  }


  ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));
  SwitchArgument.CmdSet = 0;
  SwitchArgument.Value  = Value;
  SwitchArgument.Index  = (UINT32)((UINTN)
  (&(CardData->ExtCSDRegister.BUS_WIDTH)) - (UINTN)(&(CardData->ExtCSDRegister)));
  SwitchArgument.Access = WriteByte_Mode;
  Status  = SendCommand (
              CardData,
              SWITCH,
              *(UINT32*)&SwitchArgument,
              NoData,
              NULL,
              0,
              ResponseR1b,
              TIMEOUT_COMMAND,
              (UINT32*)&(CardData->CardStatus)
              );
  if (!EFI_ERROR (Status)) {
     Status  = SendCommand (
                 CardData,
                 SEND_STATUS,
                 (CardData->Address << 16),
                 NoData,
                 NULL,
                 0,
                 ResponseR1,
                 TIMEOUT_COMMAND,
                 (UINT32*)&(CardData->CardStatus)
                 );
    if (EFI_ERROR (Status)) {
      DEBUG((EFI_D_ERROR, "SWITCH %d bits Fail\n", BusWidth));
      goto Exit;
    } else {
      DEBUG((EFI_D_ERROR, "MMCCardSetBusWidth:SWITCH Card Status:0x%x\n", *(UINT32*)&(CardData->CardStatus)));
      Status = SDHostIo->SetBusWidth (SDHostIo, BusWidth);
      if (EFI_ERROR (Status)) {
         DEBUG((EFI_D_ERROR, "SWITCH set %d bits Fail\n", BusWidth));
         goto Exit;
      }
      gBS->Stall (5 * 1000);
    }
  }

  if (!EnableDDRMode) {     // CMD19 and CMD14 are illegal commands in ddr mode
  //if (EFI_ERROR (Status)) {
  //  DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest: Fail to enable high speed mode\n"));
  //  goto Exit;
  //}

  Status = MMCCardBusWidthTest (CardData, BusWidth);
  if (EFI_ERROR (Status)) {
    DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest %d bit Fail\n", BusWidth));
    goto Exit;
    }
  }

  CardData->CurrentBusWidth = BusWidth;

Exit:
  return Status;
}
Example #2
0
/**
  MMC/SD card init function

  @param  CardData             Pointer to CARD_DATA.

  @return EFI_SUCCESS
  @return others

**/ 
EFI_STATUS
MMCSDCardInit (
  IN  CARD_DATA              *CardData
  ) 
{
  EFI_STATUS                 Status;
  EFI_SD_HOST_IO_PROTOCOL    *SDHostIo;
  SWITCH_ARGUMENT            SwitchArgument;
  UINT32                     Data;
  UINT32                     Argument;
  UINT8                      PowerValue;

  ASSERT(CardData != NULL);
  SDHostIo                  = CardData->SDHostIo;

  Status = GetCardType (CardData);
  if (EFI_ERROR (Status)) {
    goto Exit;
  }

  ASSERT (CardData->CardType != UnknownCard);
  //
  //MMC, SD card need host auto stop command support
  //
  SDHostIo->EnableAutoStopCmd (SDHostIo, TRUE);

  if (CardData->CardType == MMCCard) {
    Status = MMCCardVoltageSelection (CardData);
    if (EFI_ERROR(Status)) {
      goto Exit;
    }
  }

  //
  // Get CID Register, but the info is not used currently
  //
  Status  = SendCommand (
              SDHostIo,
              ALL_SEND_CID,
              0,
              NoData,
              NULL,
              0,  
              ResponseR2,
              TIMEOUT_COMMAND,
              (UINT32*)&(CardData->CIDRegister)
              );
  if (EFI_ERROR (Status)) {
    DEBUG((EFI_D_ERROR, "ALL_SEND_CID Fail Status = 0x%x\n", Status));
    goto Exit;
  }  

  //
  //SET_RELATIVE_ADDR
  //
  if (CardData->CardType == MMCCard) {
    //
    //Hard code the RCA address
    //
    CardData->Address = 1;

    //
    // Set RCA Register
    //
    Status  = SendCommand (
                SDHostIo,
                SET_RELATIVE_ADDR,
                (CardData->Address << 16),
                NoData,
                NULL,
                0,  
                ResponseR1,
                TIMEOUT_COMMAND,
                (UINT32*)&(CardData->CardStatus)
                );
    if (EFI_ERROR (Status)) {
      DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));
      goto Exit;
    }  
  } else {
    Data = 0;
    Status  = SendCommand (
                SDHostIo,
                SET_RELATIVE_ADDR,
                0,
                NoData,
                NULL,
                0,  
                ResponseR6,
                TIMEOUT_COMMAND,
                &Data
                );
    if (EFI_ERROR (Status)) {
      DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));
      goto Exit;
    }  

    CardData->Address = (UINT16)(Data >> 16);
    *(UINT32*)&CardData->CardStatus      = Data & 0x1FFF;
    CardData->CardStatus.ERROR           = (Data >> 13) & 0x1;
    CardData->CardStatus.ILLEGAL_COMMAND = (Data >> 14) & 0x1;
    CardData->CardStatus.COM_CRC_ERROR   = (Data >> 15) & 0x1;
    Status = CheckCardStatus (*(UINT32*)&CardData->CardStatus); 
    if (EFI_ERROR (Status)) {
      DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));
      goto Exit;
    }  
  } 

  //
  // Get CSD Register
  //
  Status  = SendCommand (
              SDHostIo,
              SEND_CSD,
              (CardData->Address << 16),
              NoData,
              NULL,
              0,  
              ResponseR2,
              TIMEOUT_COMMAND,
              (UINT32*)&(CardData->CSDRegister)
              );
  if (EFI_ERROR (Status)) {
    DEBUG((EFI_D_ERROR, "SEND_CSD Fail Status = 0x%x\n", Status));
    goto Exit;
  }  

  DEBUG((EFI_D_INFO, "CardData->CSDRegister.SPEC_VERS = 0x%x\n", CardData->CSDRegister.SPEC_VERS));
  DEBUG((EFI_D_INFO, "CardData->CSDRegister.CSD_STRUCTURE = 0x%x\n", CardData->CSDRegister.CSD_STRUCTURE));

  Status = CaculateCardParameter (CardData);
  if (EFI_ERROR (Status)) {
    goto Exit;
  } 


  //
  // It is platform and hardware specific, need hadrware engineer input
  //
  if (CardData->CSDRegister.DSR_IMP == 1) {
    //
    // Default is 0x404
    //
    Status  = SendCommand (
                SDHostIo,
                SET_DSR,
                (DEFAULT_DSR_VALUE << 16),
                NoData,
                NULL,
                0,  
                ResponseNo,
                TIMEOUT_COMMAND,
                NULL
                );
    if (EFI_ERROR (Status)) {
      DEBUG((EFI_D_ERROR, "SET_DSR Fail Status = 0x%x\n", Status));
      //
      // Assume can operate even fail
      //
    }  
  }
  //
  //Change clock frequency from 400KHz to max supported when not in high speed mode
  //Workaround to downgrade the frequency of MMC Card ver4.0 or above
  //In other words, don't enable high speed mode for the MMC card ver4.0 or above
  if ((CardData->CSDRegister.SPEC_VERS >= 4) && (CardData->CardType == MMCCard) ) {
    CardData->CSDRegister.SPEC_VERS = 3;
  } 
  Status = SDHostIo->SetClockFrequency (SDHostIo, CardData->MaxFrequency);
  if (EFI_ERROR (Status)) {
	DEBUG((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n"));
	goto Exit;
  }
  
  //
  //Put the card into tran state
  //
  Status = SendCommand (
             SDHostIo,
             SELECT_DESELECT_CARD,
             (CardData->Address << 16),
             NoData,
             NULL,
             0,   
             ResponseR1,
             TIMEOUT_COMMAND,
             (UINT32*)&(CardData->CardStatus)
             );
  if (EFI_ERROR (Status)) {
    DEBUG((EFI_D_ERROR, "SELECT_DESELECT_CARD Fail Status = 0x%x\n", Status));
    goto Exit;
  }  

  //
  // No spec requirment, can be adjusted
  //
  gBS->Stall (5 * 1000);
  //
  // No need to do so
  //
  //
  Status  = SendCommand (
              SDHostIo,
              SEND_STATUS,
              (CardData->Address << 16),
              NoData,
              NULL,
              0,   
              ResponseR1,
              TIMEOUT_COMMAND,
              (UINT32*)&(CardData->CardStatus)
              );
  if (EFI_ERROR (Status)) {
     DEBUG((EFI_D_ERROR, "SELECT_DESELECT_CARD SEND_STATUS Fail Status = 0x%x\n", Status));
     goto Exit;
  }
  //
  //if the SPEC_VERS indicates a version 4.0 or higher
  //The card is a high speed card and support Switch 
  //and Send_ext_csd command
  //otherwise it is an old card  
  //

  if (CardData->CardType == MMCCard) {
    //
    //Only V4.0 and above supports more than 1 bits and high speed
    //
    if (CardData->CSDRegister.SPEC_VERS >= 4) {
	  //
      //Get ExtCSDRegister
      //
      Status  = SendCommand (
                  SDHostIo,
                  SEND_EXT_CSD,
                  0x0,
                  InData,
                  CardData->AlignedBuffer,
                  sizeof (EXT_CSD),   
                  ResponseR1,
                  TIMEOUT_DATA,
                  (UINT32*)&(CardData->CardStatus)
                  );
      if (EFI_ERROR (Status)) {
        DEBUG((EFI_D_ERROR, "SEND_EXT_CSD Fail Status = 0x%x\n", Status));
        goto Exit;
      }

      CopyMem (&(CardData->ExtCSDRegister), CardData->AlignedBuffer, sizeof (EXT_CSD));

      //
      // Recaculate the block number for >2G MMC card
      //
      Data  = (CardData->ExtCSDRegister.SEC_COUNT[0]) |
              (CardData->ExtCSDRegister.SEC_COUNT[1] << 8) | 
              (CardData->ExtCSDRegister.SEC_COUNT[2] << 16) |
              (CardData->ExtCSDRegister.SEC_COUNT[3] << 24);

      if (Data != 0) {
        CardData->BlockNumber = Data;
      }
      //
      // Check current chipset capability and the plugged-in card 
      // whether supports HighSpeed
      //     
      if (SDHostIo->HostCapability.HighSpeedSupport) {

        //
        //Change card timing to high speed interface timing
        //
        ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));
        SwitchArgument.CmdSet = 0;
        SwitchArgument.Value  = 1;
        SwitchArgument.Index  = (UINT32)((UINTN)
        (&(CardData->ExtCSDRegister.HS_TIMING)) - (UINTN)(&(CardData->ExtCSDRegister)));
        SwitchArgument.Access = WriteByte_Mode;
        Status  = SendCommand (
                    CardData->SDHostIo,
                    SWITCH,
                    *(UINT32*)&SwitchArgument,
                    NoData,
                    NULL,
                    0,   
                    ResponseR1b,
                    TIMEOUT_COMMAND,
                    (UINT32*)&(CardData->CardStatus)
                    );
        if (EFI_ERROR (Status)) {
          DEBUG((EFI_D_ERROR, "MMCSDCardInit:SWITCH frequency Fail Status = 0x%x\n", Status));
        }
        
        gBS->Stall (5 * 1000);


        if (!EFI_ERROR (Status)) {
          Status  = SendCommand (
                      SDHostIo,
                      SEND_STATUS,
                      (CardData->Address << 16),
                      NoData,
                      NULL,
                      0,   
                      ResponseR1,
                      TIMEOUT_COMMAND,
                      (UINT32*)&(CardData->CardStatus)
                      );
          if (!EFI_ERROR (Status)) {
          //
          // Change host clock to support high speed and enable chispet to 
          // support speed
          // 
            if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
              Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_MMC_PP_HIGH);
            } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
              Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_MMC_PP);
            } else {
              Status = EFI_UNSUPPORTED;
            }
            if (EFI_ERROR (Status)) {
              DEBUG((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n"));
              goto Exit;
            }
            //
            // It seems no need to stall after changing bus freqeuncy.
            // It is said that the freqeuncy can be changed at any time. Just appends 8 clocks after command.  
            // But SetClock alreay has delay.     
            // 
          }
        }

      }
  

      Status = MMCCardBusWidthTest (CardData, 1);
      if (EFI_ERROR (Status)) {
        DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest 1 bit Fail Status = 0x%x\n", Status));
      }

      //
      // Prefer wide bus width for performance
      //
      //
      // Set to BusWidth bits mode, only version 4.0 or above support more than 1 bits
      //
      if (SDHostIo->HostCapability.BusWidth8 == TRUE) {
         Status = MMCCardSetBusWidth (CardData, 8);
         if (EFI_ERROR (Status)) {
            //
            // CE-ATA may support 8 bits and 4 bits, but has no software method for detection
            // 
            Status = MMCCardSetBusWidth (CardData, 4);
            if (EFI_ERROR (Status)) {
              goto Exit;
            }
         }
      } else if (SDHostIo->HostCapability.BusWidth4 == TRUE) {
         Status = MMCCardSetBusWidth (CardData, 4);
         if (EFI_ERROR (Status)) {
           goto Exit;
         }
      }
      
      PowerValue = 0;

      if (CardData->CurrentBusWidth == 8) {
        if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
          PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;
          PowerValue = PowerValue >> 4;
        } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
          PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;
          PowerValue = PowerValue >> 4;
        }