| 1 | /** @file |
| 2 | * |
| 3 | * Copyright (c) 2008 - 2009, Apple Inc. All rights reserved. |
| 4 | * Copyright (c) 2011, ARM Limited. All rights reserved. |
| 5 | * |
| 6 | * This program and the accompanying materials |
| 7 | * are licensed and made available under the terms and conditions of the BSD License |
| 8 | * which accompanies this distribution. The full text of the license may be found at |
| 9 | * http://opensource.org/licenses/bsd-license.php |
| 10 | * |
| 11 | * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. |
| 13 | * |
| 14 | **/ |
| 15 | |
| 16 | #include "MmcHostDxe.h" |
| 17 | |
| 18 | EMBEDDED_EXTERNAL_DEVICE *gTPS65950; |
| 19 | UINT8 MaxDataTransferRate = 0; |
| 20 | UINT32 Rca = 0; |
| 21 | BOOLEAN BitModeSet = FALSE; |
| 22 | |
| 23 | |
| 24 | typedef struct { |
| 25 | VENDOR_DEVICE_PATH Mmc; |
| 26 | EFI_DEVICE_PATH End; |
| 27 | } MMCHS_DEVICE_PATH; |
| 28 | |
| 29 | MMCHS_DEVICE_PATH gMMCDevicePath = { |
| 30 | { |
| 31 | HARDWARE_DEVICE_PATH, |
| 32 | HW_VENDOR_DP, |
| 33 | (UINT8)(sizeof(VENDOR_DEVICE_PATH)), |
| 34 | (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8), |
| 35 | 0xb615f1f5, 0x5088, 0x43cd, 0x80, 0x9c, 0xa1, 0x6e, 0x52, 0x48, 0x7d, 0x00 |
| 36 | }, |
| 37 | { |
| 38 | END_DEVICE_PATH_TYPE, |
| 39 | END_ENTIRE_DEVICE_PATH_SUBTYPE, |
| 40 | sizeof (EFI_DEVICE_PATH_PROTOCOL), |
| 41 | 0 |
| 42 | } |
| 43 | }; |
| 44 | |
| 45 | BOOLEAN |
| 46 | IgnoreCommand ( |
| 47 | UINT32 Command |
| 48 | ) |
| 49 | { |
| 50 | switch(Command) { |
| 51 | case MMC_CMD12: |
| 52 | return TRUE; |
| 53 | case MMC_CMD13: |
| 54 | return TRUE; |
| 55 | default: |
| 56 | return FALSE; |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | UINT32 |
| 61 | TranslateCommand ( |
| 62 | UINT32 Command |
| 63 | ) |
| 64 | { |
| 65 | UINT32 Translation; |
| 66 | |
| 67 | switch(Command) { |
| 68 | case MMC_CMD2: |
| 69 | Translation = CMD2; |
| 70 | break; |
| 71 | case MMC_CMD3: |
| 72 | Translation = CMD3; |
| 73 | break; |
| 74 | /*case MMC_CMD6: |
| 75 | Translation = CMD6; |
| 76 | break;*/ |
| 77 | case MMC_CMD7: |
| 78 | Translation = CMD7; |
| 79 | break; |
| 80 | case MMC_CMD8: |
| 81 | Translation = CMD8; |
| 82 | break; |
| 83 | case MMC_CMD9: |
| 84 | Translation = CMD9; |
| 85 | break; |
| 86 | /*case MMC_CMD12: |
| 87 | Translation = CMD12; |
| 88 | break; |
| 89 | case MMC_CMD13: |
| 90 | Translation = CMD13; |
| 91 | break;*/ |
| 92 | case MMC_CMD16: |
| 93 | Translation = CMD16; |
| 94 | break; |
| 95 | case MMC_CMD17: |
| 96 | Translation = 0x113A0014;//CMD17; |
| 97 | break; |
| 98 | case MMC_CMD24: |
| 99 | Translation = CMD24 | 4; |
| 100 | break; |
| 101 | case MMC_CMD55: |
| 102 | Translation = CMD55; |
| 103 | break; |
| 104 | case MMC_ACMD41: |
| 105 | Translation = ACMD41; |
| 106 | break; |
| 107 | default: |
| 108 | Translation = Command; |
| 109 | } |
| 110 | |
| 111 | return Translation; |
| 112 | } |
| 113 | |
| 114 | VOID |
| 115 | CalculateCardCLKD ( |
| 116 | UINTN *ClockFrequencySelect |
| 117 | ) |
| 118 | { |
| 119 | DEBUG((EFI_D_ERROR, "CalculateCardCLKD()\n")); |
| 120 | UINTN TransferRateValue = 0; |
| 121 | UINTN TimeValue = 0 ; |
| 122 | UINTN Frequency = 0; |
| 123 | |
| 124 | // For SD Cards we would need to send CMD6 to set |
| 125 | // speeds abouve 25MHz. High Speed mode 50 MHz and up |
| 126 | |
| 127 | //Calculate Transfer rate unit (Bits 2:0 of TRAN_SPEED) |
| 128 | switch (MaxDataTransferRate & 0x7) { // 2 |
| 129 | case 0: |
| 130 | TransferRateValue = 100 * 1000; |
| 131 | break; |
| 132 | |
| 133 | case 1: |
| 134 | TransferRateValue = 1 * 1000 * 1000; |
| 135 | break; |
| 136 | |
| 137 | case 2: |
| 138 | TransferRateValue = 10 * 1000 * 1000; |
| 139 | break; |
| 140 | |
| 141 | case 3: |
| 142 | TransferRateValue = 100 * 1000 * 1000; |
| 143 | break; |
| 144 | |
| 145 | default: |
| 146 | DEBUG((EFI_D_ERROR, "Invalid parameter.\n")); |
| 147 | ASSERT(FALSE); |
| 148 | } |
| 149 | |
| 150 | //Calculate Time value (Bits 6:3 of TRAN_SPEED) |
| 151 | switch ((MaxDataTransferRate >> 3) & 0xF) { // 6 |
| 152 | case 1: |
| 153 | TimeValue = 10; |
| 154 | break; |
| 155 | |
| 156 | case 2: |
| 157 | TimeValue = 12; |
| 158 | break; |
| 159 | |
| 160 | case 3: |
| 161 | TimeValue = 13; |
| 162 | break; |
| 163 | |
| 164 | case 4: |
| 165 | TimeValue = 15; |
| 166 | break; |
| 167 | |
| 168 | case 5: |
| 169 | TimeValue = 20; |
| 170 | break; |
| 171 | |
| 172 | case 6: |
| 173 | TimeValue = 25; |
| 174 | break; |
| 175 | |
| 176 | case 7: |
| 177 | TimeValue = 30; |
| 178 | break; |
| 179 | |
| 180 | case 8: |
| 181 | TimeValue = 35; |
| 182 | break; |
| 183 | |
| 184 | case 9: |
| 185 | TimeValue = 40; |
| 186 | break; |
| 187 | |
| 188 | case 10: |
| 189 | TimeValue = 45; |
| 190 | break; |
| 191 | |
| 192 | case 11: |
| 193 | TimeValue = 50; |
| 194 | break; |
| 195 | |
| 196 | case 12: |
| 197 | TimeValue = 55; |
| 198 | break; |
| 199 | |
| 200 | case 13: |
| 201 | TimeValue = 60; |
| 202 | break; |
| 203 | |
| 204 | case 14: |
| 205 | TimeValue = 70; |
| 206 | break; |
| 207 | |
| 208 | case 15: |
| 209 | TimeValue = 80; |
| 210 | break; |
| 211 | |
| 212 | default: |
| 213 | DEBUG((EFI_D_ERROR, "Invalid parameter.\n")); |
| 214 | ASSERT(FALSE); |
| 215 | } |
| 216 | |
| 217 | Frequency = TransferRateValue * TimeValue/10; |
| 218 | |
| 219 | //Calculate Clock divider value to program in MMCHS_SYSCTL[CLKD] field. |
| 220 | *ClockFrequencySelect = ((MMC_REFERENCE_CLK/Frequency) + 1); |
| 221 | |
| 222 | DEBUG ((EFI_D_INFO, "MaxDataTransferRate: 0x%x, Frequency: %d KHz, ClockFrequencySelect: %x\n", MaxDataTransferRate, Frequency/1000, *ClockFrequencySelect)); |
| 223 | } |
| 224 | |
| 225 | VOID |
| 226 | UpdateMMCHSClkFrequency ( |
| 227 | UINTN NewCLKD |
| 228 | ) |
| 229 | { |
| 230 | DEBUG((EFI_D_ERROR, "UpdateMMCHSClkFrequency()\n")); |
| 231 | //Set Clock enable to 0x0 to not provide the clock to the card |
| 232 | MmioAnd32 (MMCHS_SYSCTL, ~CEN); |
| 233 | |
| 234 | //Set new clock frequency. |
| 235 | MmioAndThenOr32 (MMCHS_SYSCTL, ~CLKD_MASK, NewCLKD << 6); |
| 236 | |
| 237 | //Poll till Internal Clock Stable |
| 238 | while ((MmioRead32 (MMCHS_SYSCTL) & ICS_MASK) != ICS); |
| 239 | |
| 240 | //Set Clock enable to 0x1 to provide the clock to the card |
| 241 | MmioOr32 (MMCHS_SYSCTL, CEN); |
| 242 | } |
| 243 | |
| 244 | EFI_STATUS |
| 245 | InitializeMMCHS ( |
| 246 | VOID |
| 247 | ) |
| 248 | { |
| 249 | DEBUG((EFI_D_ERROR, "InitializeMMCHS()\n")); |
| 250 | UINT8 Data = 0; |
| 251 | EFI_STATUS Status; |
| 252 | |
| 253 | //Select Device group to belong to P1 device group in Power IC. |
| 254 | Data = DEV_GRP_P1; |
| 255 | Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEV_GRP), 1, &Data); |
| 256 | ASSERT_EFI_ERROR(Status); |
| 257 | |
| 258 | //Configure voltage regulator for MMC1 in Power IC to output 3.0 voltage. |
| 259 | Data = VSEL_3_00V; |
| 260 | Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEDICATED_REG), 1, &Data); |
| 261 | ASSERT_EFI_ERROR(Status); |
| 262 | |
| 263 | //After ramping up voltage, set VDDS stable bit to indicate that voltage level is stable. |
| 264 | MmioOr32 (CONTROL_PBIAS_LITE, (PBIASLITEVMODE0 | PBIASLITEPWRDNZ0 | PBIASSPEEDCTRL0 | PBIASLITEVMODE1 | PBIASLITEWRDNZ1)); |
| 265 | |
| 266 | // Enable WP GPIO |
| 267 | MmioAndThenOr32 (GPIO1_BASE + GPIO_OE, ~BIT23, BIT23); |
| 268 | |
| 269 | // Enable Card Detect |
| 270 | Data = CARD_DETECT_ENABLE; |
| 271 | gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, TPS65950_GPIO_CTRL), 1, &Data); |
| 272 | |
| 273 | |
| 274 | return Status; |
| 275 | } |
| 276 | |
| 277 | BOOLEAN |
| 278 | MMCIsCardPresent ( |
| 279 | VOID |
| 280 | ) |
| 281 | { |
| 282 | //DEBUG((EFI_D_ERROR, "MMCIsCardPresent()\n")); |
| 283 | EFI_STATUS Status; |
| 284 | UINT8 Data; |
| 285 | |
| 286 | // |
| 287 | // Card detect is a GPIO0 on the TPS65950 |
| 288 | // |
| 289 | Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, GPIODATAIN1), 1, &Data); |
| 290 | if (EFI_ERROR (Status)) { |
| 291 | return FALSE; |
| 292 | } |
| 293 | |
| 294 | return !(Data & CARD_DETECT_BIT); |
| 295 | } |
| 296 | |
| 297 | BOOLEAN |
| 298 | MMCIsReadOnly ( |
| 299 | VOID |
| 300 | ) |
| 301 | { |
| 302 | /* Note: |
| 303 | * On our BeagleBoard the SD card WP pin is always read as TRUE. |
| 304 | * Probably something wrong with GPIO configuration. |
| 305 | * BeagleBoard-xM uses microSD cards so there is no write protect at all. |
| 306 | * Hence commenting out SD card WP pin read status. |
| 307 | */ |
| 308 | //return (MmioRead32 (GPIO1_BASE + GPIO_DATAIN) & BIT23) == BIT23; |
| 309 | return 0; |
| 310 | |
| 311 | } |
| 312 | |
| 313 | // TODO |
| 314 | EFI_GUID mPL180MciDevicePathGuid = EFI_CALLER_ID_GUID; |
| 315 | |
| 316 | EFI_STATUS |
| 317 | MMCBuildDevicePath ( |
| 318 | IN EFI_DEVICE_PATH_PROTOCOL **DevicePath |
| 319 | ) |
| 320 | { |
| 321 | EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode; |
| 322 | |
| 323 | NewDevicePathNode = CreateDeviceNode(HARDWARE_DEVICE_PATH,HW_VENDOR_DP,sizeof(VENDOR_DEVICE_PATH)); |
| 324 | CopyGuid(&((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid,&mPL180MciDevicePathGuid); |
| 325 | *DevicePath = NewDevicePathNode; |
| 326 | return EFI_SUCCESS; |
| 327 | } |
| 328 | |
| 329 | EFI_STATUS |
| 330 | MMCSendCommand ( |
| 331 | IN MMC_CMD MmcCmd, |
| 332 | IN UINT32 Argument |
| 333 | ) |
| 334 | { |
| 335 | if (IgnoreCommand(MmcCmd)) |
| 336 | return EFI_SUCCESS; |
| 337 | |
| 338 | MmcCmd = TranslateCommand(MmcCmd); |
| 339 | |
| 340 | //DEBUG((EFI_D_ERROR, "MMCSendCommand(%d)\n", MmcCmd)); |
| 341 | UINTN MmcStatus; |
| 342 | UINTN RetryCount = 0; |
| 343 | |
| 344 | //Check if command line is in use or not. Poll till command line is available. |
| 345 | while ((MmioRead32 (MMCHS_PSTATE) & DATI_MASK) == DATI_NOT_ALLOWED); |
| 346 | |
| 347 | //Provide the block size. |
| 348 | MmioWrite32 (MMCHS_BLK, BLEN_512BYTES); |
| 349 | |
| 350 | //Setting Data timeout counter value to max value. |
| 351 | MmioAndThenOr32 (MMCHS_SYSCTL, ~DTO_MASK, DTO_VAL); |
| 352 | |
| 353 | //Clear Status register. |
| 354 | MmioWrite32 (MMCHS_STAT, 0xFFFFFFFF); |
| 355 | |
| 356 | //Set command argument register |
| 357 | MmioWrite32 (MMCHS_ARG, Argument); |
| 358 | |
| 359 | //TODO: fix this |
| 360 | //Enable interrupt enable events to occur |
| 361 | //MmioWrite32 (MMCHS_IE, CmdInterruptEnableVal); |
| 362 | |
| 363 | //Send a command |
| 364 | MmioWrite32 (MMCHS_CMD, MmcCmd); |
| 365 | |
| 366 | //Check for the command status. |
| 367 | while (RetryCount < MAX_RETRY_COUNT) { |
| 368 | do { |
| 369 | MmcStatus = MmioRead32 (MMCHS_STAT); |
| 370 | } while (MmcStatus == 0); |
| 371 | |
| 372 | //Read status of command response |
| 373 | if ((MmcStatus & ERRI) != 0) { |
| 374 | |
| 375 | //Perform soft-reset for mmci_cmd line. |
| 376 | MmioOr32 (MMCHS_SYSCTL, SRC); |
| 377 | while ((MmioRead32 (MMCHS_SYSCTL) & SRC)); |
| 378 | |
| 379 | //DEBUG ((EFI_D_INFO, "MmcStatus: 0x%x\n", MmcStatus)); |
| 380 | return EFI_DEVICE_ERROR; |
| 381 | } |
| 382 | |
| 383 | //Check if command is completed. |
| 384 | if ((MmcStatus & CC) == CC) { |
| 385 | MmioWrite32 (MMCHS_STAT, CC); |
| 386 | break; |
| 387 | } |
| 388 | |
| 389 | RetryCount++; |
| 390 | } |
| 391 | |
| 392 | if (RetryCount == MAX_RETRY_COUNT) { |
| 393 | DEBUG((EFI_D_ERROR, "MMCSendCommand: Timeout\n")); |
| 394 | return EFI_TIMEOUT; |
| 395 | } |
| 396 | |
| 397 | return EFI_SUCCESS; |
| 398 | } |
| 399 | |
| 400 | EFI_STATUS |
| 401 | MMCNotifyState ( |
| 402 | IN MMC_STATE State |
| 403 | ) |
| 404 | { |
| 405 | EFI_STATUS Status; |
| 406 | UINTN freqSel; |
| 407 | switch(State) { |
| 408 | case MmcInvalidState: |
| 409 | ASSERT(0); |
| 410 | break; |
| 411 | case MmcHwInitializationState: |
| 412 | BitModeSet = FALSE; |
| 413 | |
| 414 | DEBUG((EFI_D_ERROR, "MMCHwInitializationState()\n")); |
| 415 | Status = InitializeMMCHS (); |
| 416 | if (EFI_ERROR(Status)) { |
| 417 | DEBUG ((EFI_D_ERROR, "Initialize MMC host controller fails. Status: %x\n", Status)); |
| 418 | return Status; |
| 419 | } |
| 420 | |
| 421 | //Software reset of the MMCHS host controller. |
| 422 | MmioWrite32 (MMCHS_SYSCONFIG, SOFTRESET); |
| 423 | gBS->Stall(1000); |
| 424 | while ((MmioRead32 (MMCHS_SYSSTATUS) & RESETDONE_MASK) != RESETDONE); |
| 425 | |
| 426 | //Soft reset for all. |
| 427 | MmioWrite32 (MMCHS_SYSCTL, SRA); |
| 428 | gBS->Stall(1000); |
| 429 | while ((MmioRead32 (MMCHS_SYSCTL) & SRA) != 0x0); |
| 430 | |
| 431 | //Voltage capabilities initialization. Activate VS18 and VS30. |
| 432 | MmioOr32 (MMCHS_CAPA, (VS30 | VS18)); |
| 433 | |
| 434 | //Wakeup configuration |
| 435 | MmioOr32 (MMCHS_SYSCONFIG, ENAWAKEUP); |
| 436 | MmioOr32 (MMCHS_HCTL, IWE); |
| 437 | |
| 438 | //MMCHS Controller default initialization |
| 439 | MmioOr32 (MMCHS_CON, (OD | DW8_1_4_BIT | CEATA_OFF)); |
| 440 | |
| 441 | MmioWrite32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_OFF)); |
| 442 | |
| 443 | //Enable internal clock |
| 444 | MmioOr32 (MMCHS_SYSCTL, ICE); |
| 445 | |
| 446 | //Set the clock frequency to 80KHz. |
| 447 | UpdateMMCHSClkFrequency (CLKD_80KHZ); |
| 448 | |
| 449 | //Enable SD bus power. |
| 450 | MmioOr32 (MMCHS_HCTL, (SDBP_ON)); |
| 451 | |
| 452 | //Poll till SD bus power bit is set. |
| 453 | while ((MmioRead32 (MMCHS_HCTL) & SDBP_MASK) != SDBP_ON); |
| 454 | |
| 455 | //Enable interrupts. |
| 456 | MmioWrite32 (MMCHS_IE, (BADA_EN | CERR_EN | DEB_EN | DCRC_EN | DTO_EN | CIE_EN | |
| 457 | CEB_EN | CCRC_EN | CTO_EN | BRR_EN | BWR_EN | TC_EN | CC_EN)); |
| 458 | |
| 459 | //Controller INIT procedure start. |
| 460 | MmioOr32 (MMCHS_CON, INIT); |
| 461 | MmioWrite32 (MMCHS_CMD, 0x00000000); |
| 462 | while (!(MmioRead32 (MMCHS_STAT) & CC)); |
| 463 | |
| 464 | //Wait for 1 ms |
| 465 | gBS->Stall(1000); |
| 466 | |
| 467 | //Set CC bit to 0x1 to clear the flag |
| 468 | MmioOr32 (MMCHS_STAT, CC); |
| 469 | |
| 470 | //Retry INIT procedure. |
| 471 | MmioWrite32 (MMCHS_CMD, 0x00000000); |
| 472 | while (!(MmioRead32 (MMCHS_STAT) & CC)); |
| 473 | |
| 474 | //End initialization sequence |
| 475 | MmioAnd32 (MMCHS_CON, ~INIT); |
| 476 | |
| 477 | MmioOr32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_ON)); |
| 478 | |
| 479 | //Change clock frequency to 400KHz to fit protocol |
| 480 | UpdateMMCHSClkFrequency(CLKD_400KHZ); |
| 481 | |
| 482 | MmioOr32 (MMCHS_CON, OD); |
| 483 | break; |
| 484 | case MmcIdleState: |
| 485 | break; |
| 486 | case MmcReadyState: |
| 487 | break; |
| 488 | case MmcIdentificationState: |
| 489 | break; |
| 490 | case MmcStandByState: |
| 491 | CalculateCardCLKD(&freqSel); |
| 492 | UpdateMMCHSClkFrequency(freqSel); |
| 493 | break; |
| 494 | case MmcTransferState: |
| 495 | if (!BitModeSet) { |
| 496 | Status = MMCSendCommand (CMD55, Rca << 16); |
| 497 | if (!EFI_ERROR (Status)) { |
| 498 | // set device into 4-bit data bus mode |
| 499 | Status = MMCSendCommand (ACMD6, 0x2); |
| 500 | if (!EFI_ERROR (Status)) { |
| 501 | // Set host controler into 4-bit mode |
| 502 | MmioOr32 (MMCHS_HCTL, DTW_4_BIT); |
| 503 | DEBUG ((EFI_D_INFO, "SD Memory Card set to 4-bit mode\n")); |
| 504 | BitModeSet = TRUE; |
| 505 | } |
| 506 | } |
| 507 | } |
| 508 | break; |
| 509 | case MmcSendingDataState: |
| 510 | break; |
| 511 | case MmcReceiveDataState: |
| 512 | break; |
| 513 | case MmcProgrammingState: |
| 514 | break; |
| 515 | case MmcDisconnectState: |
| 516 | default: |
| 517 | ASSERT(0); |
| 518 | } |
| 519 | return EFI_SUCCESS; |
| 520 | } |
| 521 | |
| 522 | EFI_STATUS |
| 523 | MMCReceiveResponse ( |
| 524 | IN MMC_RESPONSE_TYPE Type, |
| 525 | IN UINT32* Buffer |
| 526 | ) |
| 527 | { |
| 528 | //DEBUG((EFI_D_ERROR, "MMCReceiveResponse()\n")); |
| 529 | if (Buffer == NULL) { |
| 530 | DEBUG((EFI_D_ERROR, "Buffer was NULL\n")); |
| 531 | return EFI_INVALID_PARAMETER; |
| 532 | } |
| 533 | |
| 534 | if (Type == MMC_RESPONSE_TYPE_R2) { |
| 535 | Buffer[0] = MmioRead32 (MMCHS_RSP10); |
| 536 | Buffer[1] = MmioRead32 (MMCHS_RSP32); |
| 537 | Buffer[2] = MmioRead32 (MMCHS_RSP54); |
| 538 | Buffer[3] = MmioRead32 (MMCHS_RSP76); |
| 539 | } else { |
| 540 | Buffer[0] = MmioRead32 (MMCHS_RSP10); |
| 541 | } |
| 542 | |
| 543 | if (Type == MMC_RESPONSE_TYPE_CSD) { |
| 544 | MaxDataTransferRate = Buffer[3] & 0xFF; |
| 545 | } else if (Type == MMC_RESPONSE_TYPE_RCA) { |
| 546 | Rca = Buffer[0] >> 16; |
| 547 | } |
| 548 | |
| 549 | return EFI_SUCCESS; |
| 550 | } |
| 551 | |
| 552 | EFI_STATUS |
| 553 | MMCReadBlockData ( |
| 554 | IN EFI_LBA Lba, |
| 555 | IN UINTN Length, |
| 556 | IN UINT32* Buffer |
| 557 | ) |
| 558 | { |
| 559 | //DEBUG((EFI_D_ERROR, "MMCReadBlockData(LBA: 0x%x, ", Lba)); |
| 560 | //DEBUG((EFI_D_ERROR, "Length: 0x%x, ", Length)); |
| 561 | //DEBUG((EFI_D_ERROR, "Buffer: 0x%x)\n", Buffer)); |
| 562 | UINTN MmcStatus; |
| 563 | UINTN Count; |
| 564 | UINTN RetryCount = 0; |
| 565 | |
| 566 | //Check controller status to make sure there is no error. |
| 567 | while (RetryCount < MAX_RETRY_COUNT) { |
| 568 | do { |
| 569 | //Read Status. |
| 570 | MmcStatus = MmioRead32 (MMCHS_STAT); |
| 571 | } while(MmcStatus == 0); |
| 572 | |
| 573 | //Check if Buffer read ready (BRR) bit is set? |
| 574 | if (MmcStatus & BRR) { |
| 575 | |
| 576 | //Clear BRR bit |
| 577 | MmioOr32 (MMCHS_STAT, BRR); |
| 578 | |
| 579 | for (Count = 0; Count < Length / 4; Count++) { |
| 580 | *Buffer++ = MmioRead32(MMCHS_DATA); |
| 581 | } |
| 582 | break; |
| 583 | } |
| 584 | RetryCount++; |
| 585 | } |
| 586 | |
| 587 | if (RetryCount == MAX_RETRY_COUNT) { |
| 588 | return EFI_TIMEOUT; |
| 589 | } |
| 590 | |
| 591 | return EFI_SUCCESS; |
| 592 | } |
| 593 | |
| 594 | EFI_STATUS |
| 595 | MMCWriteBlockData ( |
| 596 | IN EFI_LBA Lba, |
| 597 | IN UINTN Length, |
| 598 | IN UINT32* Buffer |
| 599 | ) |
| 600 | { |
| 601 | UINTN MmcStatus; |
| 602 | UINTN Count; |
| 603 | UINTN RetryCount = 0; |
| 604 | |
| 605 | //Check controller status to make sure there is no error. |
| 606 | while (RetryCount < MAX_RETRY_COUNT) { |
| 607 | do { |
| 608 | //Read Status. |
| 609 | MmcStatus = MmioRead32 (MMCHS_STAT); |
| 610 | } while(MmcStatus == 0); |
| 611 | |
| 612 | //Check if Buffer write ready (BWR) bit is set? |
| 613 | if (MmcStatus & BWR) { |
| 614 | |
| 615 | //Clear BWR bit |
| 616 | MmioOr32 (MMCHS_STAT, BWR); |
| 617 | |
| 618 | //Write block worth of data. |
| 619 | for (Count = 0; Count < Length / 4; Count++) { |
| 620 | MmioWrite32 (MMCHS_DATA, *Buffer++); |
| 621 | } |
| 622 | |
| 623 | break; |
| 624 | } |
| 625 | RetryCount++; |
| 626 | } |
| 627 | |
| 628 | if (RetryCount == MAX_RETRY_COUNT) { |
| 629 | return EFI_TIMEOUT; |
| 630 | } |
| 631 | |
| 632 | return EFI_SUCCESS; |
| 633 | } |
| 634 | |
| 635 | EFI_MMC_HOST_PROTOCOL gMMCHost = { |
| 636 | MMCIsCardPresent, |
| 637 | MMCIsReadOnly, |
| 638 | MMCBuildDevicePath, |
| 639 | MMCNotifyState, |
| 640 | MMCSendCommand, |
| 641 | MMCReceiveResponse, |
| 642 | MMCReadBlockData, |
| 643 | MMCWriteBlockData |
| 644 | }; |
| 645 | |
| 646 | EFI_STATUS |
| 647 | MMCInitialize ( |
| 648 | IN EFI_HANDLE ImageHandle, |
| 649 | IN EFI_SYSTEM_TABLE *SystemTable |
| 650 | ) |
| 651 | { |
| 652 | DEBUG((EFI_D_ERROR, "MMCInitialize()\n")); |
| 653 | EFI_STATUS Status; |
| 654 | EFI_HANDLE Handle = NULL; |
| 655 | |
| 656 | Status = gBS->LocateProtocol (&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950); |
| 657 | ASSERT_EFI_ERROR(Status); |
| 658 | |
| 659 | Status = gBS->InstallMultipleProtocolInterfaces ( |
| 660 | &Handle, |
| 661 | &gEfiMmcHostProtocolGuid, &gMMCHost, |
| 662 | NULL |
| 663 | ); |
| 664 | ASSERT_EFI_ERROR (Status); |
| 665 | |
| 666 | return Status; |
| 667 | } |