PL180Mci.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. /** @file
  2. This file implement the MMC Host Protocol for the ARM PrimeCell PL180.
  3. Copyright (c) 2011-2012, ARM Limited. All rights reserved.
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "PL180Mci.h"
  7. #include <Library/DevicePathLib.h>
  8. #include <Library/BaseMemoryLib.h>
  9. EFI_MMC_HOST_PROTOCOL *gpMmcHost;
  10. // Untested ...
  11. //#define USE_STREAM
  12. #define MMCI0_BLOCKLEN 512
  13. #define MMCI0_POW2_BLOCKLEN 9
  14. #define MMCI0_TIMEOUT 1000
  15. #define SYS_MCI_CARDIN BIT0
  16. #define SYS_MCI_WPROT BIT1
  17. BOOLEAN
  18. MciIsPowerOn (
  19. VOID
  20. )
  21. {
  22. return ((MmioRead32 (MCI_POWER_CONTROL_REG) & MCI_POWER_ON) == MCI_POWER_ON);
  23. }
  24. EFI_STATUS
  25. MciInitialize (
  26. VOID
  27. )
  28. {
  29. MCI_TRACE ("MciInitialize()");
  30. return EFI_SUCCESS;
  31. }
  32. BOOLEAN
  33. MciIsCardPresent (
  34. IN EFI_MMC_HOST_PROTOCOL *This
  35. )
  36. {
  37. return (MmioRead32 (FixedPcdGet32 (PcdPL180SysMciRegAddress)) & SYS_MCI_CARDIN);
  38. }
  39. BOOLEAN
  40. MciIsReadOnly (
  41. IN EFI_MMC_HOST_PROTOCOL *This
  42. )
  43. {
  44. return (MmioRead32 (FixedPcdGet32 (PcdPL180SysMciRegAddress)) & SYS_MCI_WPROT);
  45. }
  46. // Convert block size to 2^n
  47. STATIC
  48. UINT32
  49. GetPow2BlockLen (
  50. IN UINT32 BlockLen
  51. )
  52. {
  53. UINTN Loop;
  54. UINTN Pow2BlockLen;
  55. Loop = 0x8000;
  56. Pow2BlockLen = 15;
  57. do {
  58. Loop = (Loop >> 1) & 0xFFFF;
  59. Pow2BlockLen--;
  60. } while (Pow2BlockLen && (!(Loop & BlockLen)));
  61. return Pow2BlockLen;
  62. }
  63. VOID
  64. MciPrepareDataPath (
  65. IN UINTN TransferDirection
  66. )
  67. {
  68. // Set Data Length & Data Timer
  69. MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFFFF);
  70. MmioWrite32 (MCI_DATA_LENGTH_REG, MMCI0_BLOCKLEN);
  71. #ifndef USE_STREAM
  72. //Note: we are using a hardcoded BlockLen (==512). If we decide to use a variable size, we could
  73. // compute the pow2 of BlockLen with the above function GetPow2BlockLen ()
  74. MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_DMA_ENABLE | TransferDirection | (MMCI0_POW2_BLOCKLEN << 4));
  75. #else
  76. MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_DMA_ENABLE | TransferDirection | MCI_DATACTL_STREAM_TRANS);
  77. #endif
  78. }
  79. EFI_STATUS
  80. MciSendCommand (
  81. IN EFI_MMC_HOST_PROTOCOL *This,
  82. IN MMC_CMD MmcCmd,
  83. IN UINT32 Argument
  84. )
  85. {
  86. UINT32 Status;
  87. UINT32 Cmd;
  88. UINTN RetVal;
  89. UINTN CmdCtrlReg;
  90. UINT32 DoneMask;
  91. RetVal = EFI_SUCCESS;
  92. if ((MmcCmd == MMC_CMD17) || (MmcCmd == MMC_CMD11)) {
  93. MciPrepareDataPath (MCI_DATACTL_CARD_TO_CONT);
  94. } else if ((MmcCmd == MMC_CMD24) || (MmcCmd == MMC_CMD20)) {
  95. MciPrepareDataPath (MCI_DATACTL_CONT_TO_CARD);
  96. } else if (MmcCmd == MMC_CMD6) {
  97. MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFFFF);
  98. MmioWrite32 (MCI_DATA_LENGTH_REG, 64);
  99. #ifndef USE_STREAM
  100. MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | GetPow2BlockLen (64));
  101. #else
  102. MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | MCI_DATACTL_STREAM_TRANS);
  103. #endif
  104. } else if (MmcCmd == MMC_ACMD51) {
  105. MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFFFF);
  106. /* SCR register is 8 bytes long. */
  107. MmioWrite32 (MCI_DATA_LENGTH_REG, 8);
  108. #ifndef USE_STREAM
  109. MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | GetPow2BlockLen (8));
  110. #else
  111. MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | MCI_DATACTL_STREAM_TRANS);
  112. #endif
  113. }
  114. // Create Command for PL180
  115. Cmd = (MMC_GET_INDX (MmcCmd) & INDX_MASK) | MCI_CPSM_ENABLE;
  116. if (MmcCmd & MMC_CMD_WAIT_RESPONSE) {
  117. Cmd |= MCI_CPSM_WAIT_RESPONSE;
  118. }
  119. if (MmcCmd & MMC_CMD_LONG_RESPONSE) {
  120. Cmd |= MCI_CPSM_LONG_RESPONSE;
  121. }
  122. // Clear Status register static flags
  123. MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS);
  124. // Write to command argument register
  125. MmioWrite32 (MCI_ARGUMENT_REG, Argument);
  126. // Write to command register
  127. MmioWrite32 (MCI_COMMAND_REG, Cmd);
  128. DoneMask = (Cmd & MCI_CPSM_WAIT_RESPONSE)
  129. ? (MCI_STATUS_CMD_RESPEND | MCI_STATUS_CMD_ERROR)
  130. : (MCI_STATUS_CMD_SENT | MCI_STATUS_CMD_ERROR);
  131. do {
  132. Status = MmioRead32 (MCI_STATUS_REG);
  133. } while (! (Status & DoneMask));
  134. if ((Status & MCI_STATUS_CMD_ERROR)) {
  135. // Clear Status register error flags
  136. MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_STATUS_CMD_ERROR);
  137. if ((Status & MCI_STATUS_CMD_START_BIT_ERROR)) {
  138. DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) Start bit Error! Response:0x%X Status:0x%x\n", (Cmd & 0x3F), MmioRead32 (MCI_RESPONSE0_REG), Status));
  139. RetVal = EFI_NO_RESPONSE;
  140. } else if ((Status & MCI_STATUS_CMD_CMDTIMEOUT)) {
  141. //DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT! Response:0x%X Status:0x%x\n", (Cmd & 0x3F), MmioRead32 (MCI_RESPONSE0_REG), Status));
  142. RetVal = EFI_TIMEOUT;
  143. } else if ((!(MmcCmd & MMC_CMD_NO_CRC_RESPONSE)) && (Status & MCI_STATUS_CMD_CMDCRCFAIL)) {
  144. // The CMD1 and response type R3 do not contain CRC. We should ignore the CRC failed Status.
  145. RetVal = EFI_CRC_ERROR;
  146. }
  147. }
  148. // Disable Command Path
  149. CmdCtrlReg = MmioRead32 (MCI_COMMAND_REG);
  150. MmioWrite32 (MCI_COMMAND_REG, (CmdCtrlReg & ~MCI_CPSM_ENABLE));
  151. return RetVal;
  152. }
  153. EFI_STATUS
  154. MciReceiveResponse (
  155. IN EFI_MMC_HOST_PROTOCOL *This,
  156. IN MMC_RESPONSE_TYPE Type,
  157. IN UINT32* Buffer
  158. )
  159. {
  160. if (Buffer == NULL) {
  161. return EFI_INVALID_PARAMETER;
  162. }
  163. if ( (Type == MMC_RESPONSE_TYPE_R1)
  164. || (Type == MMC_RESPONSE_TYPE_R1b)
  165. || (Type == MMC_RESPONSE_TYPE_R3)
  166. || (Type == MMC_RESPONSE_TYPE_R6)
  167. || (Type == MMC_RESPONSE_TYPE_R7))
  168. {
  169. Buffer[0] = MmioRead32 (MCI_RESPONSE3_REG);
  170. } else if (Type == MMC_RESPONSE_TYPE_R2) {
  171. Buffer[0] = MmioRead32 (MCI_RESPONSE0_REG);
  172. Buffer[1] = MmioRead32 (MCI_RESPONSE1_REG);
  173. Buffer[2] = MmioRead32 (MCI_RESPONSE2_REG);
  174. Buffer[3] = MmioRead32 (MCI_RESPONSE3_REG);
  175. }
  176. return EFI_SUCCESS;
  177. }
  178. EFI_STATUS
  179. MciReadBlockData (
  180. IN EFI_MMC_HOST_PROTOCOL *This,
  181. IN EFI_LBA Lba,
  182. IN UINTN Length,
  183. IN UINT32* Buffer
  184. )
  185. {
  186. UINTN Loop;
  187. UINTN Finish;
  188. UINTN Status;
  189. EFI_STATUS RetVal;
  190. UINTN DataCtrlReg;
  191. EFI_TPL Tpl;
  192. RetVal = EFI_SUCCESS;
  193. // Read data from the RX FIFO
  194. Loop = 0;
  195. if (Length < MMCI0_BLOCKLEN) {
  196. Finish = Length / 4;
  197. } else {
  198. Finish = MMCI0_BLOCKLEN / 4;
  199. }
  200. // Raise the TPL at the highest level to disable Interrupts.
  201. Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
  202. do {
  203. // Read the Status flags
  204. Status = MmioRead32 (MCI_STATUS_REG);
  205. // Do eight reads if possible else a single read
  206. if (Status & MCI_STATUS_CMD_RXFIFOHALFFULL) {
  207. Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
  208. Loop++;
  209. Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
  210. Loop++;
  211. Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
  212. Loop++;
  213. Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
  214. Loop++;
  215. Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
  216. Loop++;
  217. Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
  218. Loop++;
  219. Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
  220. Loop++;
  221. Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
  222. Loop++;
  223. } else if (Status & MCI_STATUS_CMD_RXDATAAVAILBL) {
  224. Buffer[Loop] = MmioRead32(MCI_FIFO_REG);
  225. Loop++;
  226. } else {
  227. //Check for error conditions and timeouts
  228. if (Status & MCI_STATUS_CMD_DATATIMEOUT) {
  229. DEBUG ((EFI_D_ERROR, "MciReadBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));
  230. RetVal = EFI_TIMEOUT;
  231. break;
  232. } else if (Status & MCI_STATUS_CMD_DATACRCFAIL) {
  233. DEBUG ((EFI_D_ERROR, "MciReadBlockData(): CRC Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));
  234. RetVal = EFI_CRC_ERROR;
  235. break;
  236. } else if (Status & MCI_STATUS_CMD_START_BIT_ERROR) {
  237. DEBUG ((EFI_D_ERROR, "MciReadBlockData(): Start-bit Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));
  238. RetVal = EFI_NO_RESPONSE;
  239. break;
  240. }
  241. }
  242. //clear RX over run flag
  243. if(Status & MCI_STATUS_CMD_RXOVERRUN) {
  244. MmioWrite32(MCI_CLEAR_STATUS_REG, MCI_STATUS_CMD_RXOVERRUN);
  245. }
  246. } while ((Loop < Finish));
  247. // Restore Tpl
  248. gBS->RestoreTPL (Tpl);
  249. // Clear Status flags
  250. MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS);
  251. //Disable Data path
  252. DataCtrlReg = MmioRead32 (MCI_DATA_CTL_REG);
  253. MmioWrite32 (MCI_DATA_CTL_REG, (DataCtrlReg & MCI_DATACTL_DISABLE_MASK));
  254. return RetVal;
  255. }
  256. EFI_STATUS
  257. MciWriteBlockData (
  258. IN EFI_MMC_HOST_PROTOCOL *This,
  259. IN EFI_LBA Lba,
  260. IN UINTN Length,
  261. IN UINT32* Buffer
  262. )
  263. {
  264. UINTN Loop;
  265. UINTN Finish;
  266. UINTN Timer;
  267. UINTN Status;
  268. EFI_STATUS RetVal;
  269. UINTN DataCtrlReg;
  270. EFI_TPL Tpl;
  271. RetVal = EFI_SUCCESS;
  272. // Write the data to the TX FIFO
  273. Loop = 0;
  274. Finish = MMCI0_BLOCKLEN / 4;
  275. Timer = MMCI0_TIMEOUT * 100;
  276. // Raise the TPL at the highest level to disable Interrupts.
  277. Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
  278. do {
  279. // Read the Status flags
  280. Status = MmioRead32 (MCI_STATUS_REG);
  281. // Do eight writes if possible else a single write
  282. if (Status & MCI_STATUS_CMD_TXFIFOHALFEMPTY) {
  283. MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
  284. Loop++;
  285. MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
  286. Loop++;
  287. MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
  288. Loop++;
  289. MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
  290. Loop++;
  291. MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
  292. Loop++;
  293. MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
  294. Loop++;
  295. MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
  296. Loop++;
  297. MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
  298. Loop++;
  299. } else if (!(Status & MCI_STATUS_CMD_TXFIFOFULL)) {
  300. MmioWrite32(MCI_FIFO_REG, Buffer[Loop]);
  301. Loop++;
  302. } else {
  303. // Check for error conditions and timeouts
  304. if (Status & MCI_STATUS_CMD_DATATIMEOUT) {
  305. DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));
  306. RetVal = EFI_TIMEOUT;
  307. goto Exit;
  308. } else if (Status & MCI_STATUS_CMD_DATACRCFAIL) {
  309. DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): CRC Error! Response:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status));
  310. RetVal = EFI_CRC_ERROR;
  311. goto Exit;
  312. } else if (Status & MCI_STATUS_CMD_TX_UNDERRUN) {
  313. DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): TX buffer Underrun! Response:0x%X Status:0x%x, Number of bytes written 0x%x\n",MmioRead32(MCI_RESPONSE0_REG),Status, Loop));
  314. RetVal = EFI_BUFFER_TOO_SMALL;
  315. ASSERT(0);
  316. goto Exit;
  317. }
  318. }
  319. } while (Loop < Finish);
  320. // Restore Tpl
  321. gBS->RestoreTPL (Tpl);
  322. // Wait for FIFO to drain
  323. Timer = MMCI0_TIMEOUT * 60;
  324. Status = MmioRead32 (MCI_STATUS_REG);
  325. #ifndef USE_STREAM
  326. // Single block
  327. while (((Status & MCI_STATUS_TXDONE) != MCI_STATUS_TXDONE) && Timer) {
  328. #else
  329. // Stream
  330. while (((Status & MCI_STATUS_CMD_DATAEND) != MCI_STATUS_CMD_DATAEND) && Timer) {
  331. #endif
  332. NanoSecondDelay(10);
  333. Status = MmioRead32 (MCI_STATUS_REG);
  334. Timer--;
  335. }
  336. // Clear Status flags
  337. MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS);
  338. if (Timer == 0) {
  339. DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): Data End timeout Number of words written 0x%x\n", Loop));
  340. RetVal = EFI_TIMEOUT;
  341. }
  342. Exit:
  343. // Disable Data path
  344. DataCtrlReg = MmioRead32 (MCI_DATA_CTL_REG);
  345. MmioWrite32 (MCI_DATA_CTL_REG, (DataCtrlReg & MCI_DATACTL_DISABLE_MASK));
  346. return RetVal;
  347. }
  348. EFI_STATUS
  349. MciNotifyState (
  350. IN EFI_MMC_HOST_PROTOCOL *This,
  351. IN MMC_STATE State
  352. )
  353. {
  354. UINT32 Data32;
  355. switch (State) {
  356. case MmcInvalidState:
  357. ASSERT (0);
  358. break;
  359. case MmcHwInitializationState:
  360. // If device already turn on then restart it
  361. Data32 = MmioRead32 (MCI_POWER_CONTROL_REG);
  362. if ((Data32 & 0x2) == MCI_POWER_UP) {
  363. MCI_TRACE ("MciNotifyState(MmcHwInitializationState): TurnOff MCI");
  364. // Turn off
  365. MmioWrite32 (MCI_CLOCK_CONTROL_REG, 0);
  366. MmioWrite32 (MCI_POWER_CONTROL_REG, 0);
  367. MicroSecondDelay (100);
  368. }
  369. MCI_TRACE ("MciNotifyState(MmcHwInitializationState): TurnOn MCI");
  370. // Setup clock
  371. // - 0x1D = 29 => should be the clock divider to be less than 400kHz at MCLK = 24Mhz
  372. MmioWrite32 (MCI_CLOCK_CONTROL_REG, 0x1D | MCI_CLOCK_ENABLE | MCI_CLOCK_POWERSAVE);
  373. // Set the voltage
  374. MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_OPENDRAIN | (15<<2));
  375. MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_ROD | MCI_POWER_OPENDRAIN | (15<<2) | MCI_POWER_UP);
  376. MicroSecondDelay (10);
  377. MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_ROD | MCI_POWER_OPENDRAIN | (15<<2) | MCI_POWER_ON);
  378. MicroSecondDelay (100);
  379. // Set Data Length & Data Timer
  380. MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFF);
  381. MmioWrite32 (MCI_DATA_LENGTH_REG, 8);
  382. ASSERT ((MmioRead32 (MCI_POWER_CONTROL_REG) & 0x3) == MCI_POWER_ON);
  383. break;
  384. case MmcIdleState:
  385. MCI_TRACE ("MciNotifyState(MmcIdleState)");
  386. break;
  387. case MmcReadyState:
  388. MCI_TRACE ("MciNotifyState(MmcReadyState)");
  389. break;
  390. case MmcIdentificationState:
  391. MCI_TRACE ("MciNotifyState (MmcIdentificationState)");
  392. break;
  393. case MmcStandByState:{
  394. volatile UINT32 PwrCtrlReg;
  395. MCI_TRACE ("MciNotifyState (MmcStandByState)");
  396. // Enable MCICMD push-pull drive
  397. PwrCtrlReg = MmioRead32 (MCI_POWER_CONTROL_REG);
  398. //Disable Open Drain output
  399. PwrCtrlReg &= ~ (MCI_POWER_OPENDRAIN);
  400. MmioWrite32 (MCI_POWER_CONTROL_REG, PwrCtrlReg);
  401. // Set MMCI0 clock to 4MHz (24MHz may be possible with cache enabled)
  402. //
  403. // Note: Increasing clock speed causes TX FIFO under-run errors.
  404. // So careful when optimising this driver for higher performance.
  405. //
  406. MmioWrite32(MCI_CLOCK_CONTROL_REG,0x02 | MCI_CLOCK_ENABLE | MCI_CLOCK_POWERSAVE);
  407. // Set MMCI0 clock to 24MHz (by bypassing the divider)
  408. //MmioWrite32(MCI_CLOCK_CONTROL_REG,MCI_CLOCK_BYPASS | MCI_CLOCK_ENABLE);
  409. break;
  410. }
  411. case MmcTransferState:
  412. //MCI_TRACE ("MciNotifyState(MmcTransferState)");
  413. break;
  414. case MmcSendingDataState:
  415. MCI_TRACE ("MciNotifyState(MmcSendingDataState)");
  416. break;
  417. case MmcReceiveDataState:
  418. MCI_TRACE ("MciNotifyState(MmcReceiveDataState)");
  419. break;
  420. case MmcProgrammingState:
  421. MCI_TRACE ("MciNotifyState(MmcProgrammingState)");
  422. break;
  423. case MmcDisconnectState:
  424. MCI_TRACE ("MciNotifyState(MmcDisconnectState)");
  425. break;
  426. default:
  427. ASSERT (0);
  428. }
  429. return EFI_SUCCESS;
  430. }
  431. EFI_GUID mPL180MciDevicePathGuid = EFI_CALLER_ID_GUID;
  432. EFI_STATUS
  433. MciBuildDevicePath (
  434. IN EFI_MMC_HOST_PROTOCOL *This,
  435. IN EFI_DEVICE_PATH_PROTOCOL **DevicePath
  436. )
  437. {
  438. EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;
  439. NewDevicePathNode = CreateDeviceNode (HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH));
  440. CopyGuid (& ((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &mPL180MciDevicePathGuid);
  441. *DevicePath = NewDevicePathNode;
  442. return EFI_SUCCESS;
  443. }
  444. EFI_MMC_HOST_PROTOCOL gMciHost = {
  445. MMC_HOST_PROTOCOL_REVISION,
  446. MciIsCardPresent,
  447. MciIsReadOnly,
  448. MciBuildDevicePath,
  449. MciNotifyState,
  450. MciSendCommand,
  451. MciReceiveResponse,
  452. MciReadBlockData,
  453. MciWriteBlockData
  454. };
  455. EFI_STATUS
  456. PL180MciDxeInitialize (
  457. IN EFI_HANDLE ImageHandle,
  458. IN EFI_SYSTEM_TABLE *SystemTable
  459. )
  460. {
  461. EFI_STATUS Status;
  462. EFI_HANDLE Handle;
  463. DEBUG ((EFI_D_WARN, "Probing ID registers at 0x%lx for a PL180\n",
  464. MCI_PERIPH_ID_REG0));
  465. // Check if this is a PL180
  466. if (MmioRead8 (MCI_PERIPH_ID_REG0) != MCI_PERIPH_ID0 ||
  467. MmioRead8 (MCI_PERIPH_ID_REG1) != MCI_PERIPH_ID1 ||
  468. MmioRead8 (MCI_PERIPH_ID_REG2) != MCI_PERIPH_ID2 ||
  469. MmioRead8 (MCI_PCELL_ID_REG0) != MCI_PCELL_ID0 ||
  470. MmioRead8 (MCI_PCELL_ID_REG1) != MCI_PCELL_ID1 ||
  471. MmioRead8 (MCI_PCELL_ID_REG2) != MCI_PCELL_ID2 ||
  472. MmioRead8 (MCI_PCELL_ID_REG3) != MCI_PCELL_ID3) {
  473. DEBUG ((EFI_D_WARN, "Probing ID registers at 0x%lx for a PL180"
  474. " failed\n", MCI_PERIPH_ID_REG0));
  475. return EFI_NOT_FOUND;
  476. }
  477. Handle = NULL;
  478. MCI_TRACE ("PL180MciDxeInitialize()");
  479. //Publish Component Name, BlockIO protocol interfaces
  480. Status = gBS->InstallMultipleProtocolInterfaces (
  481. &Handle,
  482. &gEfiMmcHostProtocolGuid, &gMciHost,
  483. NULL
  484. );
  485. ASSERT_EFI_ERROR (Status);
  486. return EFI_SUCCESS;
  487. }