DwEmmcDxe.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. /** @file
  2. This file implement the MMC Host Protocol for the DesignWare eMMC.
  3. Copyright (c) 2014-2017, Linaro Limited. All rights reserved.
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <Library/BaseMemoryLib.h>
  7. #include <Library/CacheMaintenanceLib.h>
  8. #include <Library/DebugLib.h>
  9. #include <Library/DevicePathLib.h>
  10. #include <Library/IoLib.h>
  11. #include <Library/MemoryAllocationLib.h>
  12. #include <Library/PcdLib.h>
  13. #include <Library/TimerLib.h>
  14. #include <Library/UefiBootServicesTableLib.h>
  15. #include <Library/UefiLib.h>
  16. #include <Protocol/MmcHost.h>
  17. #include "DwEmmc.h"
  18. #define DWEMMC_DESC_PAGE 1
  19. #define DWEMMC_BLOCK_SIZE 512
  20. #define DWEMMC_DMA_BUF_SIZE (512 * 8)
  21. #define DWEMMC_MAX_DESC_PAGES 512
  22. typedef struct {
  23. UINT32 Des0;
  24. UINT32 Des1;
  25. UINT32 Des2;
  26. UINT32 Des3;
  27. } DWEMMC_IDMAC_DESCRIPTOR;
  28. EFI_MMC_HOST_PROTOCOL *gpMmcHost;
  29. DWEMMC_IDMAC_DESCRIPTOR *gpIdmacDesc;
  30. EFI_GUID mDwEmmcDevicePathGuid = EFI_CALLER_ID_GUID;
  31. STATIC UINT32 mDwEmmcCommand;
  32. STATIC UINT32 mDwEmmcArgument;
  33. EFI_STATUS
  34. DwEmmcReadBlockData (
  35. IN EFI_MMC_HOST_PROTOCOL *This,
  36. IN EFI_LBA Lba,
  37. IN UINTN Length,
  38. IN UINT32* Buffer
  39. );
  40. BOOLEAN
  41. DwEmmcIsPowerOn (
  42. VOID
  43. )
  44. {
  45. return TRUE;
  46. }
  47. EFI_STATUS
  48. DwEmmcInitialize (
  49. VOID
  50. )
  51. {
  52. DEBUG ((DEBUG_BLKIO, "DwEmmcInitialize()"));
  53. return EFI_SUCCESS;
  54. }
  55. BOOLEAN
  56. DwEmmcIsCardPresent (
  57. IN EFI_MMC_HOST_PROTOCOL *This
  58. )
  59. {
  60. return TRUE;
  61. }
  62. BOOLEAN
  63. DwEmmcIsReadOnly (
  64. IN EFI_MMC_HOST_PROTOCOL *This
  65. )
  66. {
  67. return FALSE;
  68. }
  69. BOOLEAN
  70. DwEmmcIsDmaSupported (
  71. IN EFI_MMC_HOST_PROTOCOL *This
  72. )
  73. {
  74. return TRUE;
  75. }
  76. EFI_STATUS
  77. DwEmmcBuildDevicePath (
  78. IN EFI_MMC_HOST_PROTOCOL *This,
  79. IN EFI_DEVICE_PATH_PROTOCOL **DevicePath
  80. )
  81. {
  82. EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;
  83. NewDevicePathNode = CreateDeviceNode (HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH));
  84. CopyGuid (& ((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &mDwEmmcDevicePathGuid);
  85. *DevicePath = NewDevicePathNode;
  86. return EFI_SUCCESS;
  87. }
  88. EFI_STATUS
  89. DwEmmcUpdateClock (
  90. VOID
  91. )
  92. {
  93. UINT32 Data;
  94. /* CMD_UPDATE_CLK */
  95. Data = BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_UPDATE_CLOCK_ONLY |
  96. BIT_CMD_START;
  97. MmioWrite32 (DWEMMC_CMD, Data);
  98. while (1) {
  99. Data = MmioRead32 (DWEMMC_CMD);
  100. if (!(Data & CMD_START_BIT)) {
  101. break;
  102. }
  103. Data = MmioRead32 (DWEMMC_RINTSTS);
  104. if (Data & DWEMMC_INT_HLE) {
  105. Print (L"failed to update mmc clock frequency\n");
  106. return EFI_DEVICE_ERROR;
  107. }
  108. }
  109. return EFI_SUCCESS;
  110. }
  111. EFI_STATUS
  112. DwEmmcSetClock (
  113. IN UINTN ClockFreq
  114. )
  115. {
  116. UINT32 Divider, Rate, Data;
  117. EFI_STATUS Status;
  118. BOOLEAN Found = FALSE;
  119. for (Divider = 1; Divider < 256; Divider++) {
  120. Rate = PcdGet32 (PcdDwEmmcDxeClockFrequencyInHz);
  121. if ((Rate / (2 * Divider)) <= ClockFreq) {
  122. Found = TRUE;
  123. break;
  124. }
  125. }
  126. if (Found == FALSE) {
  127. return EFI_NOT_FOUND;
  128. }
  129. // Wait until MMC is idle
  130. do {
  131. Data = MmioRead32 (DWEMMC_STATUS);
  132. } while (Data & DWEMMC_STS_DATA_BUSY);
  133. // Disable MMC clock first
  134. MmioWrite32 (DWEMMC_CLKENA, 0);
  135. Status = DwEmmcUpdateClock ();
  136. ASSERT (!EFI_ERROR (Status));
  137. MmioWrite32 (DWEMMC_CLKDIV, Divider);
  138. Status = DwEmmcUpdateClock ();
  139. ASSERT (!EFI_ERROR (Status));
  140. // Enable MMC clock
  141. MmioWrite32 (DWEMMC_CLKENA, 1);
  142. MmioWrite32 (DWEMMC_CLKSRC, 0);
  143. Status = DwEmmcUpdateClock ();
  144. ASSERT (!EFI_ERROR (Status));
  145. return EFI_SUCCESS;
  146. }
  147. EFI_STATUS
  148. DwEmmcNotifyState (
  149. IN EFI_MMC_HOST_PROTOCOL *This,
  150. IN MMC_STATE State
  151. )
  152. {
  153. UINT32 Data;
  154. EFI_STATUS Status;
  155. switch (State) {
  156. case MmcInvalidState:
  157. return EFI_INVALID_PARAMETER;
  158. case MmcHwInitializationState:
  159. MmioWrite32 (DWEMMC_PWREN, 1);
  160. // If device already turn on then restart it
  161. Data = DWEMMC_CTRL_RESET_ALL;
  162. MmioWrite32 (DWEMMC_CTRL, Data);
  163. do {
  164. // Wait until reset operation finished
  165. Data = MmioRead32 (DWEMMC_CTRL);
  166. } while (Data & DWEMMC_CTRL_RESET_ALL);
  167. // Setup clock that could not be higher than 400KHz.
  168. Status = DwEmmcSetClock (400000);
  169. ASSERT (!EFI_ERROR (Status));
  170. // Wait clock stable
  171. MicroSecondDelay (100);
  172. MmioWrite32 (DWEMMC_RINTSTS, ~0);
  173. MmioWrite32 (DWEMMC_INTMASK, 0);
  174. MmioWrite32 (DWEMMC_TMOUT, ~0);
  175. MmioWrite32 (DWEMMC_IDINTEN, 0);
  176. MmioWrite32 (DWEMMC_BMOD, DWEMMC_IDMAC_SWRESET);
  177. MmioWrite32 (DWEMMC_BLKSIZ, DWEMMC_BLOCK_SIZE);
  178. do {
  179. Data = MmioRead32 (DWEMMC_BMOD);
  180. } while (Data & DWEMMC_IDMAC_SWRESET);
  181. break;
  182. case MmcIdleState:
  183. break;
  184. case MmcReadyState:
  185. break;
  186. case MmcIdentificationState:
  187. break;
  188. case MmcStandByState:
  189. break;
  190. case MmcTransferState:
  191. break;
  192. case MmcSendingDataState:
  193. break;
  194. case MmcReceiveDataState:
  195. break;
  196. case MmcProgrammingState:
  197. break;
  198. case MmcDisconnectState:
  199. break;
  200. default:
  201. return EFI_INVALID_PARAMETER;
  202. }
  203. return EFI_SUCCESS;
  204. }
  205. // Need to prepare DMA buffer first before sending commands to MMC card
  206. BOOLEAN
  207. IsPendingReadCommand (
  208. IN MMC_CMD MmcCmd
  209. )
  210. {
  211. UINTN Mask;
  212. Mask = BIT_CMD_DATA_EXPECTED | BIT_CMD_READ;
  213. if ((MmcCmd & Mask) == Mask) {
  214. return TRUE;
  215. }
  216. return FALSE;
  217. }
  218. BOOLEAN
  219. IsPendingWriteCommand (
  220. IN MMC_CMD MmcCmd
  221. )
  222. {
  223. UINTN Mask;
  224. Mask = BIT_CMD_DATA_EXPECTED | BIT_CMD_WRITE;
  225. if ((MmcCmd & Mask) == Mask) {
  226. return TRUE;
  227. }
  228. return FALSE;
  229. }
  230. EFI_STATUS
  231. SendCommand (
  232. IN MMC_CMD MmcCmd,
  233. IN UINT32 Argument
  234. )
  235. {
  236. UINT32 Data, ErrMask;
  237. // Wait until MMC is idle
  238. do {
  239. Data = MmioRead32 (DWEMMC_STATUS);
  240. } while (Data & DWEMMC_STS_DATA_BUSY);
  241. MmioWrite32 (DWEMMC_RINTSTS, ~0);
  242. MmioWrite32 (DWEMMC_CMDARG, Argument);
  243. MmioWrite32 (DWEMMC_CMD, MmcCmd);
  244. ErrMask = DWEMMC_INT_EBE | DWEMMC_INT_HLE | DWEMMC_INT_RTO |
  245. DWEMMC_INT_RCRC | DWEMMC_INT_RE;
  246. ErrMask |= DWEMMC_INT_DCRC | DWEMMC_INT_DRT | DWEMMC_INT_SBE;
  247. do {
  248. MicroSecondDelay(500);
  249. Data = MmioRead32 (DWEMMC_RINTSTS);
  250. if (Data & ErrMask) {
  251. return EFI_DEVICE_ERROR;
  252. }
  253. if (Data & DWEMMC_INT_DTO) { // Transfer Done
  254. break;
  255. }
  256. } while (!(Data & DWEMMC_INT_CMD_DONE));
  257. return EFI_SUCCESS;
  258. }
  259. EFI_STATUS
  260. DwEmmcSendCommand (
  261. IN EFI_MMC_HOST_PROTOCOL *This,
  262. IN MMC_CMD MmcCmd,
  263. IN UINT32 Argument
  264. )
  265. {
  266. UINT32 Cmd = 0;
  267. EFI_STATUS Status = EFI_SUCCESS;
  268. switch (MMC_GET_INDX(MmcCmd)) {
  269. case MMC_INDX(0):
  270. Cmd = BIT_CMD_SEND_INIT;
  271. break;
  272. case MMC_INDX(1):
  273. Cmd = BIT_CMD_RESPONSE_EXPECT;
  274. break;
  275. case MMC_INDX(2):
  276. Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_LONG_RESPONSE |
  277. BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_SEND_INIT;
  278. break;
  279. case MMC_INDX(3):
  280. Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
  281. BIT_CMD_SEND_INIT;
  282. break;
  283. case MMC_INDX(7):
  284. if (Argument)
  285. Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;
  286. else
  287. Cmd = 0;
  288. break;
  289. case MMC_INDX(8):
  290. Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
  291. BIT_CMD_DATA_EXPECTED | BIT_CMD_READ |
  292. BIT_CMD_WAIT_PRVDATA_COMPLETE;
  293. break;
  294. case MMC_INDX(9):
  295. Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
  296. BIT_CMD_LONG_RESPONSE;
  297. break;
  298. case MMC_INDX(12):
  299. Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
  300. BIT_CMD_STOP_ABORT_CMD;
  301. break;
  302. case MMC_INDX(13):
  303. Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
  304. BIT_CMD_WAIT_PRVDATA_COMPLETE;
  305. break;
  306. case MMC_INDX(16):
  307. Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
  308. BIT_CMD_DATA_EXPECTED | BIT_CMD_READ |
  309. BIT_CMD_WAIT_PRVDATA_COMPLETE;
  310. break;
  311. case MMC_INDX(17):
  312. case MMC_INDX(18):
  313. Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
  314. BIT_CMD_DATA_EXPECTED | BIT_CMD_READ |
  315. BIT_CMD_WAIT_PRVDATA_COMPLETE;
  316. break;
  317. case MMC_INDX(24):
  318. case MMC_INDX(25):
  319. Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
  320. BIT_CMD_DATA_EXPECTED | BIT_CMD_WRITE |
  321. BIT_CMD_WAIT_PRVDATA_COMPLETE;
  322. break;
  323. case MMC_INDX(30):
  324. Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
  325. BIT_CMD_DATA_EXPECTED;
  326. break;
  327. default:
  328. Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;
  329. break;
  330. }
  331. Cmd |= MMC_GET_INDX(MmcCmd) | BIT_CMD_USE_HOLD_REG | BIT_CMD_START;
  332. if (IsPendingReadCommand (Cmd) || IsPendingWriteCommand (Cmd)) {
  333. mDwEmmcCommand = Cmd;
  334. mDwEmmcArgument = Argument;
  335. } else {
  336. Status = SendCommand (Cmd, Argument);
  337. }
  338. return Status;
  339. }
  340. EFI_STATUS
  341. DwEmmcReceiveResponse (
  342. IN EFI_MMC_HOST_PROTOCOL *This,
  343. IN MMC_RESPONSE_TYPE Type,
  344. IN UINT32* Buffer
  345. )
  346. {
  347. if (Buffer == NULL) {
  348. return EFI_INVALID_PARAMETER;
  349. }
  350. if ( (Type == MMC_RESPONSE_TYPE_R1)
  351. || (Type == MMC_RESPONSE_TYPE_R1b)
  352. || (Type == MMC_RESPONSE_TYPE_R3)
  353. || (Type == MMC_RESPONSE_TYPE_R6)
  354. || (Type == MMC_RESPONSE_TYPE_R7))
  355. {
  356. Buffer[0] = MmioRead32 (DWEMMC_RESP0);
  357. } else if (Type == MMC_RESPONSE_TYPE_R2) {
  358. Buffer[0] = MmioRead32 (DWEMMC_RESP0);
  359. Buffer[1] = MmioRead32 (DWEMMC_RESP1);
  360. Buffer[2] = MmioRead32 (DWEMMC_RESP2);
  361. Buffer[3] = MmioRead32 (DWEMMC_RESP3);
  362. }
  363. return EFI_SUCCESS;
  364. }
  365. VOID
  366. DwEmmcAdjustFifoThreshold (
  367. VOID
  368. )
  369. {
  370. /* DMA multiple transaction size map to reg value as array index */
  371. CONST UINT32 BurstSize[] = {1, 4, 8, 16, 32, 64, 128, 256};
  372. UINT32 BlkDepthInFifo, FifoThreshold, FifoWidth, FifoDepth;
  373. UINT32 BlkSize = DWEMMC_BLOCK_SIZE, Idx = 0, RxWatermark = 1, TxWatermark, TxWatermarkInvers;
  374. /* Skip FIFO adjustment if we do not have platform FIFO depth info */
  375. FifoDepth = PcdGet32 (PcdDwEmmcDxeFifoDepth);
  376. if (!FifoDepth) {
  377. return;
  378. }
  379. TxWatermark = FifoDepth / 2;
  380. TxWatermarkInvers = FifoDepth - TxWatermark;
  381. FifoWidth = DWEMMC_GET_HDATA_WIDTH (MmioRead32 (DWEMMC_HCON));
  382. if (!FifoWidth) {
  383. FifoWidth = 2;
  384. } else if (FifoWidth == 2) {
  385. FifoWidth = 8;
  386. } else {
  387. FifoWidth = 4;
  388. }
  389. BlkDepthInFifo = BlkSize / FifoWidth;
  390. Idx = ARRAY_SIZE (BurstSize) - 1;
  391. while (Idx && ((BlkDepthInFifo % BurstSize[Idx]) || (TxWatermarkInvers % BurstSize[Idx]))) {
  392. Idx--;
  393. }
  394. RxWatermark = BurstSize[Idx] - 1;
  395. FifoThreshold = DWEMMC_DMA_BURST_SIZE (Idx) | DWEMMC_FIFO_TWMARK (TxWatermark)
  396. | DWEMMC_FIFO_RWMARK (RxWatermark);
  397. MmioWrite32 (DWEMMC_FIFOTH, FifoThreshold);
  398. }
  399. EFI_STATUS
  400. PrepareDmaData (
  401. IN DWEMMC_IDMAC_DESCRIPTOR* IdmacDesc,
  402. IN UINTN Length,
  403. IN UINT32* Buffer
  404. )
  405. {
  406. UINTN Cnt, Blks, Idx, LastIdx;
  407. Cnt = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE;
  408. Blks = (Length + DWEMMC_BLOCK_SIZE - 1) / DWEMMC_BLOCK_SIZE;
  409. Length = DWEMMC_BLOCK_SIZE * Blks;
  410. for (Idx = 0; Idx < Cnt; Idx++) {
  411. (IdmacDesc + Idx)->Des0 = DWEMMC_IDMAC_DES0_OWN | DWEMMC_IDMAC_DES0_CH |
  412. DWEMMC_IDMAC_DES0_DIC;
  413. (IdmacDesc + Idx)->Des1 = DWEMMC_IDMAC_DES1_BS1(DWEMMC_DMA_BUF_SIZE);
  414. /* Buffer Address */
  415. (IdmacDesc + Idx)->Des2 = (UINT32)((UINTN)Buffer + DWEMMC_DMA_BUF_SIZE * Idx);
  416. /* Next Descriptor Address */
  417. (IdmacDesc + Idx)->Des3 = (UINT32)((UINTN)IdmacDesc +
  418. (sizeof(DWEMMC_IDMAC_DESCRIPTOR) * (Idx + 1)));
  419. }
  420. /* First Descriptor */
  421. IdmacDesc->Des0 |= DWEMMC_IDMAC_DES0_FS;
  422. /* Last Descriptor */
  423. LastIdx = Cnt - 1;
  424. (IdmacDesc + LastIdx)->Des0 |= DWEMMC_IDMAC_DES0_LD;
  425. (IdmacDesc + LastIdx)->Des0 &= ~(DWEMMC_IDMAC_DES0_DIC | DWEMMC_IDMAC_DES0_CH);
  426. (IdmacDesc + LastIdx)->Des1 = DWEMMC_IDMAC_DES1_BS1(Length -
  427. (LastIdx * DWEMMC_DMA_BUF_SIZE));
  428. /* Set the Next field of Last Descriptor */
  429. (IdmacDesc + LastIdx)->Des3 = 0;
  430. MmioWrite32 (DWEMMC_DBADDR, (UINT32)((UINTN)IdmacDesc));
  431. return EFI_SUCCESS;
  432. }
  433. VOID
  434. StartDma (
  435. UINTN Length
  436. )
  437. {
  438. UINT32 Data;
  439. Data = MmioRead32 (DWEMMC_CTRL);
  440. Data |= DWEMMC_CTRL_INT_EN | DWEMMC_CTRL_DMA_EN | DWEMMC_CTRL_IDMAC_EN;
  441. MmioWrite32 (DWEMMC_CTRL, Data);
  442. Data = MmioRead32 (DWEMMC_BMOD);
  443. Data |= DWEMMC_IDMAC_ENABLE | DWEMMC_IDMAC_FB;
  444. MmioWrite32 (DWEMMC_BMOD, Data);
  445. MmioWrite32 (DWEMMC_BLKSIZ, DWEMMC_BLOCK_SIZE);
  446. MmioWrite32 (DWEMMC_BYTCNT, Length);
  447. }
  448. EFI_STATUS
  449. DwEmmcReadBlockData (
  450. IN EFI_MMC_HOST_PROTOCOL *This,
  451. IN EFI_LBA Lba,
  452. IN UINTN Length,
  453. IN UINT32* Buffer
  454. )
  455. {
  456. EFI_STATUS Status;
  457. UINT32 DescPages, CountPerPage, Count;
  458. EFI_TPL Tpl;
  459. Tpl = gBS->RaiseTPL (TPL_NOTIFY);
  460. CountPerPage = EFI_PAGE_SIZE / 16;
  461. Count = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE;
  462. DescPages = (Count + CountPerPage - 1) / CountPerPage;
  463. InvalidateDataCacheRange (Buffer, Length);
  464. Status = PrepareDmaData (gpIdmacDesc, Length, Buffer);
  465. if (EFI_ERROR (Status)) {
  466. goto out;
  467. }
  468. WriteBackDataCacheRange (gpIdmacDesc, DescPages * EFI_PAGE_SIZE);
  469. StartDma (Length);
  470. Status = SendCommand (mDwEmmcCommand, mDwEmmcArgument);
  471. if (EFI_ERROR (Status)) {
  472. DEBUG ((DEBUG_ERROR, "Failed to read data, mDwEmmcCommand:%x, mDwEmmcArgument:%x, Status:%r\n", mDwEmmcCommand, mDwEmmcArgument, Status));
  473. goto out;
  474. }
  475. out:
  476. // Restore Tpl
  477. gBS->RestoreTPL (Tpl);
  478. return Status;
  479. }
  480. EFI_STATUS
  481. DwEmmcWriteBlockData (
  482. IN EFI_MMC_HOST_PROTOCOL *This,
  483. IN EFI_LBA Lba,
  484. IN UINTN Length,
  485. IN UINT32* Buffer
  486. )
  487. {
  488. EFI_STATUS Status;
  489. UINT32 DescPages, CountPerPage, Count;
  490. EFI_TPL Tpl;
  491. Tpl = gBS->RaiseTPL (TPL_NOTIFY);
  492. CountPerPage = EFI_PAGE_SIZE / 16;
  493. Count = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE;
  494. DescPages = (Count + CountPerPage - 1) / CountPerPage;
  495. WriteBackDataCacheRange (Buffer, Length);
  496. Status = PrepareDmaData (gpIdmacDesc, Length, Buffer);
  497. if (EFI_ERROR (Status)) {
  498. goto out;
  499. }
  500. WriteBackDataCacheRange (gpIdmacDesc, DescPages * EFI_PAGE_SIZE);
  501. StartDma (Length);
  502. Status = SendCommand (mDwEmmcCommand, mDwEmmcArgument);
  503. if (EFI_ERROR (Status)) {
  504. DEBUG ((DEBUG_ERROR, "Failed to write data, mDwEmmcCommand:%x, mDwEmmcArgument:%x, Status:%r\n", mDwEmmcCommand, mDwEmmcArgument, Status));
  505. goto out;
  506. }
  507. out:
  508. // Restore Tpl
  509. gBS->RestoreTPL (Tpl);
  510. return Status;
  511. }
  512. EFI_STATUS
  513. DwEmmcSetIos (
  514. IN EFI_MMC_HOST_PROTOCOL *This,
  515. IN UINT32 BusClockFreq,
  516. IN UINT32 BusWidth,
  517. IN UINT32 TimingMode
  518. )
  519. {
  520. EFI_STATUS Status = EFI_SUCCESS;
  521. UINT32 Data;
  522. if ((PcdGet32 (PcdDwEmmcDxeMaxClockFreqInHz) != 0) &&
  523. (BusClockFreq > PcdGet32 (PcdDwEmmcDxeMaxClockFreqInHz))) {
  524. return EFI_UNSUPPORTED;
  525. }
  526. if (TimingMode != EMMCBACKWARD) {
  527. Data = MmioRead32 (DWEMMC_UHSREG);
  528. switch (TimingMode) {
  529. case EMMCHS52DDR1V2:
  530. case EMMCHS52DDR1V8:
  531. Data |= 1 << 16;
  532. break;
  533. case EMMCHS52:
  534. case EMMCHS26:
  535. Data &= ~(1 << 16);
  536. break;
  537. default:
  538. return EFI_UNSUPPORTED;
  539. }
  540. MmioWrite32 (DWEMMC_UHSREG, Data);
  541. }
  542. switch (BusWidth) {
  543. case 1:
  544. MmioWrite32 (DWEMMC_CTYPE, 0);
  545. break;
  546. case 4:
  547. MmioWrite32 (DWEMMC_CTYPE, 1);
  548. break;
  549. case 8:
  550. MmioWrite32 (DWEMMC_CTYPE, 1 << 16);
  551. break;
  552. default:
  553. return EFI_UNSUPPORTED;
  554. }
  555. if (BusClockFreq) {
  556. Status = DwEmmcSetClock (BusClockFreq);
  557. }
  558. return Status;
  559. }
  560. BOOLEAN
  561. DwEmmcIsMultiBlock (
  562. IN EFI_MMC_HOST_PROTOCOL *This
  563. )
  564. {
  565. return TRUE;
  566. }
  567. EFI_MMC_HOST_PROTOCOL gMciHost = {
  568. MMC_HOST_PROTOCOL_REVISION,
  569. DwEmmcIsCardPresent,
  570. DwEmmcIsReadOnly,
  571. DwEmmcBuildDevicePath,
  572. DwEmmcNotifyState,
  573. DwEmmcSendCommand,
  574. DwEmmcReceiveResponse,
  575. DwEmmcReadBlockData,
  576. DwEmmcWriteBlockData,
  577. DwEmmcSetIos,
  578. DwEmmcIsMultiBlock
  579. };
  580. EFI_STATUS
  581. DwEmmcDxeInitialize (
  582. IN EFI_HANDLE ImageHandle,
  583. IN EFI_SYSTEM_TABLE *SystemTable
  584. )
  585. {
  586. EFI_STATUS Status;
  587. EFI_HANDLE Handle;
  588. Handle = NULL;
  589. DwEmmcAdjustFifoThreshold ();
  590. gpIdmacDesc = (DWEMMC_IDMAC_DESCRIPTOR *)AllocatePages (DWEMMC_MAX_DESC_PAGES);
  591. if (gpIdmacDesc == NULL) {
  592. return EFI_BUFFER_TOO_SMALL;
  593. }
  594. DEBUG ((DEBUG_BLKIO, "DwEmmcDxeInitialize()\n"));
  595. //Publish Component Name, BlockIO protocol interfaces
  596. Status = gBS->InstallMultipleProtocolInterfaces (
  597. &Handle,
  598. &gEfiMmcHostProtocolGuid, &gMciHost,
  599. NULL
  600. );
  601. ASSERT_EFI_ERROR (Status);
  602. return EFI_SUCCESS;
  603. }