sd.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  1. /*++
  2. Copyright (c) 2014 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. sd.c
  9. Abstract:
  10. This module implements BCM2709 SD support in UEFI.
  11. Author:
  12. Chris Stevens 5-Jan-2015
  13. Environment:
  14. Firmware
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <uefifw.h>
  20. #include <dev/sd.h>
  21. #include <dev/bcm2709.h>
  22. #include <minoca/uefi/protocol/blockio.h>
  23. //
  24. // --------------------------------------------------------------------- Macros
  25. //
  26. //
  27. // This macro returns a pointer to the disk I/O data given a pointer to the
  28. // block I/O protocol instance.
  29. //
  30. #define EFI_SD_BCM2709_FROM_THIS(_BlockIo) \
  31. (EFI_SD_BCM2709_CONTEXT *)((VOID *)(_BlockIo) - \
  32. ((VOID *)(&(((EFI_SD_BCM2709_CONTEXT *)0)->BlockIo))))
  33. //
  34. // ---------------------------------------------------------------- Definitions
  35. //
  36. #define EFI_SD_BCM2709_MAGIC 0x32426453 // '2BdS'
  37. #define EFI_SD_BCM2709_BLOCK_IO_DEVICE_PATH_GUID \
  38. { \
  39. 0xFCA216DE, 0x950E, 0x11E4, \
  40. {0xBD, 0x11, 0x04, 0x01, 0x0F, 0xDD, 0x74, 0x01} \
  41. }
  42. //
  43. // ------------------------------------------------------ Data Type Definitions
  44. //
  45. /*++
  46. Structure Description:
  47. This structure defines the data necessary to enable the eMMC.
  48. Members:
  49. Header - Stores a header that defines the total size of the messages being
  50. sent to and received from the mailbox.
  51. DeviceState - Stores a request to set the state for a particular device.
  52. EndTag - Stores the tag to denote the end of the mailbox message.
  53. --*/
  54. typedef struct _EFI_SD_BCM2709_ENABLE_EMMC {
  55. BCM2709_MAILBOX_HEADER Header;
  56. BCM2709_MAILBOX_DEVICE_STATE DeviceState;
  57. UINT32 EndTag;
  58. } EFI_SD_BCM2709_ENABLE_EMMC, *PEFI_SD_BCM2709_ENABLE_EMMC;
  59. /*++
  60. Structure Description:
  61. This structure defines the data necessary to get the eMMC clock rate in Hz.
  62. Members:
  63. Header - Stores a header that defines the total size of the messages being
  64. sent to and received from the mailbox.
  65. ClockRate - Stores a request to get the rate for a particular clock.
  66. EndTag - Stores the tag to denote the end of the mailbox message.
  67. --*/
  68. typedef struct _EFI_SD_BCM2709_GET_EMMC_CLOCK {
  69. BCM2709_MAILBOX_HEADER Header;
  70. BCM2709_MAILBOX_GET_CLOCK_RATE ClockRate;
  71. UINT32 EndTag;
  72. } EFI_SD_BCM2709_GET_EMMC_CLOCK, *PEFI_SD_BCM2709_GET_EMMC_CLOCK;
  73. /*++
  74. Structure Description:
  75. This structure describes the SD BCM2709 device context.
  76. Members:
  77. Magic - Stores the magic constand EFI_SD_BCM2709_MAGIC.
  78. Handle - Stores the handle to the block I/O device.
  79. DevicePath - Stores a pointer to the device path.
  80. Controller - Stores an pointer to the controller structure.
  81. ControllerBase - Stores a pointer to the virtual address of the HSMMC
  82. registers.
  83. MediaPresent - Stores a boolean indicating whether or not there is a card
  84. in the slot.
  85. BlockSize - Stores the cached block size of the media.
  86. BlockCount - Stores the cached block count of the media.
  87. BlockIo - Stores the block I/O protocol.
  88. Media - Stores the block I/O media information.
  89. --*/
  90. typedef struct _EFI_SD_BCM2709_CONTEXT {
  91. UINT32 Magic;
  92. EFI_HANDLE Handle;
  93. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  94. PEFI_SD_CONTROLLER Controller;
  95. BOOLEAN MediaPresent;
  96. UINT32 BlockSize;
  97. UINT64 BlockCount;
  98. EFI_BLOCK_IO_PROTOCOL BlockIo;
  99. EFI_BLOCK_IO_MEDIA Media;
  100. } EFI_SD_BCM2709_CONTEXT, *PEFI_SD_BCM2709_CONTEXT;
  101. /*++
  102. Structure Description:
  103. This structure defines the SD BCM2709 block I/O device path.
  104. Members:
  105. DevicePath - Stores the standard vendor-specific device path.
  106. ControllerBase - Stores the controller number.
  107. --*/
  108. typedef struct _EFI_SD_BCM2709_BLOCK_IO_DEVICE_PATH {
  109. VENDOR_DEVICE_PATH DevicePath;
  110. UINT32 ControllerBase;
  111. } EFI_SD_BCM2709_BLOCK_IO_DEVICE_PATH, *PEFI_SD_BCM2709_BLOCK_IO_DEVICE_PATH;
  112. /*++
  113. Structure Description:
  114. This structure defines the BCM2709 SD block I/O device path.
  115. Members:
  116. Disk - Stores the disk device path node.
  117. End - Stores the end device path node.
  118. --*/
  119. #pragma pack(push, 1)
  120. typedef struct _EFI_SD_BCM2709_DEVICE_PATH {
  121. EFI_SD_BCM2709_BLOCK_IO_DEVICE_PATH Disk;
  122. EFI_DEVICE_PATH_PROTOCOL End;
  123. } PACKED EFI_SD_BCM2709_DEVICE_PATH, *PEFI_SD_BCM2709_DEVICE_PATH;
  124. #pragma pack(pop)
  125. //
  126. // ----------------------------------------------- Internal Function Prototypes
  127. //
  128. EFIAPI
  129. EFI_STATUS
  130. EfipSdBcm2709Reset (
  131. EFI_BLOCK_IO_PROTOCOL *This,
  132. BOOLEAN ExtendedVerification
  133. );
  134. EFIAPI
  135. EFI_STATUS
  136. EfipSdBcm2709ReadBlocks (
  137. EFI_BLOCK_IO_PROTOCOL *This,
  138. UINT32 MediaId,
  139. EFI_LBA Lba,
  140. UINTN BufferSize,
  141. VOID *Buffer
  142. );
  143. EFIAPI
  144. EFI_STATUS
  145. EfipSdBcm2709WriteBlocks (
  146. EFI_BLOCK_IO_PROTOCOL *This,
  147. UINT32 MediaId,
  148. EFI_LBA Lba,
  149. UINTN BufferSize,
  150. VOID *Buffer
  151. );
  152. EFIAPI
  153. EFI_STATUS
  154. EfipSdBcm2709FlushBlocks (
  155. EFI_BLOCK_IO_PROTOCOL *This
  156. );
  157. EFI_STATUS
  158. EfipSdBcm2709ResetController (
  159. PEFI_SD_BCM2709_CONTEXT Device
  160. );
  161. //
  162. // -------------------------------------------------------------------- Globals
  163. //
  164. //
  165. // Define the private data template.
  166. //
  167. EFI_SD_BCM2709_CONTEXT EfiSdBcm2709DiskTemplate = {
  168. EFI_SD_BCM2709_MAGIC,
  169. NULL,
  170. NULL,
  171. NULL,
  172. FALSE,
  173. 0,
  174. 0,
  175. {
  176. EFI_BLOCK_IO_PROTOCOL_REVISION3,
  177. NULL,
  178. EfipSdBcm2709Reset,
  179. EfipSdBcm2709ReadBlocks,
  180. EfipSdBcm2709WriteBlocks,
  181. EfipSdBcm2709FlushBlocks
  182. },
  183. {0},
  184. };
  185. //
  186. // Define the device path template.
  187. //
  188. EFI_SD_BCM2709_DEVICE_PATH EfiSdBcm2709DevicePathTemplate = {
  189. {
  190. {
  191. {
  192. HARDWARE_DEVICE_PATH,
  193. HW_VENDOR_DP,
  194. sizeof(EFI_SD_BCM2709_BLOCK_IO_DEVICE_PATH)
  195. },
  196. EFI_SD_BCM2709_BLOCK_IO_DEVICE_PATH_GUID,
  197. },
  198. BCM2709_EMMC_OFFSET
  199. },
  200. {
  201. END_DEVICE_PATH_TYPE,
  202. END_ENTIRE_DEVICE_PATH_SUBTYPE,
  203. END_DEVICE_PATH_LENGTH
  204. }
  205. };
  206. //
  207. // Define a template for the command to enable the eMMC power.
  208. //
  209. EFI_SD_BCM2709_ENABLE_EMMC EfiBcm2709EmmcPowerCommand = {
  210. {
  211. sizeof(EFI_SD_BCM2709_ENABLE_EMMC),
  212. 0
  213. },
  214. {
  215. {
  216. BCM2709_MAILBOX_TAG_SET_POWER_STATE,
  217. sizeof(UINT32) + sizeof(UINT32),
  218. sizeof(UINT32) + sizeof(UINT32)
  219. },
  220. BCM2709_MAILBOX_DEVICE_SDHCI,
  221. BCM2709_MAILBOX_POWER_STATE_ON
  222. },
  223. 0
  224. };
  225. //
  226. // Define a template for the command to get the eMMC clock rate.
  227. //
  228. EFI_SD_BCM2709_GET_EMMC_CLOCK EfiBcm2709EmmcGetClockRateCommand = {
  229. {
  230. sizeof(EFI_SD_BCM2709_GET_EMMC_CLOCK),
  231. 0
  232. },
  233. {
  234. {
  235. BCM2709_MAILBOX_TAG_GET_CLOCK_RATE,
  236. sizeof(UINT32) + sizeof(UINT32),
  237. sizeof(UINT32)
  238. },
  239. BCM2709_MAILBOX_CLOCK_ID_EMMC,
  240. 0
  241. },
  242. 0
  243. };
  244. //
  245. // ------------------------------------------------------------------ Functions
  246. //
  247. EFI_STATUS
  248. EfipBcm2709EnumerateSd (
  249. VOID
  250. )
  251. /*++
  252. Routine Description:
  253. This routine enumerates the SD card on the BCM2709.
  254. Arguments:
  255. None.
  256. Return Value:
  257. EFI status code.
  258. --*/
  259. {
  260. UINT64 BlockCount;
  261. UINT32 BlockSize;
  262. PEFI_SD_BCM2709_DEVICE_PATH DevicePath;
  263. PEFI_SD_BCM2709_CONTEXT Disk;
  264. UINT32 ExpectedLength;
  265. UINT32 Frequency;
  266. EFI_SD_BCM2709_GET_EMMC_CLOCK GetClockRate;
  267. UINT32 Length;
  268. EFI_SD_INITIALIZATION_BLOCK SdParameters;
  269. EFI_STATUS Status;
  270. //
  271. // The BCM2709 device library must be initialized to enumerate SD.
  272. //
  273. if (EfiBcm2709Initialized == FALSE) {
  274. return EFI_NOT_READY;
  275. }
  276. //
  277. // Allocate and initialize the context structure.
  278. //
  279. Status = EfiAllocatePool(EfiBootServicesData,
  280. sizeof(EFI_SD_BCM2709_CONTEXT),
  281. (VOID **)&Disk);
  282. if (EFI_ERROR(Status)) {
  283. return Status;
  284. }
  285. EfiCopyMem(Disk, &EfiSdBcm2709DiskTemplate, sizeof(EFI_SD_BCM2709_CONTEXT));
  286. Disk->BlockIo.Media = &(Disk->Media);
  287. Disk->Media.RemovableMedia = TRUE;
  288. //
  289. // Create the device path.
  290. //
  291. Status = EfiAllocatePool(EfiBootServicesData,
  292. sizeof(EFI_SD_BCM2709_DEVICE_PATH),
  293. (VOID **)&DevicePath);
  294. if (EFI_ERROR(Status)) {
  295. goto Bcm2709EnumerateSdEnd;
  296. }
  297. //
  298. // Update the device path template now that the BCM2709 device has a base
  299. // address. The global array only had the offset.
  300. //
  301. EfiSdBcm2709DevicePathTemplate.Disk.ControllerBase =
  302. (UINTN)BCM2709_EMMC_BASE;
  303. EfiCopyMem(DevicePath,
  304. &EfiSdBcm2709DevicePathTemplate,
  305. sizeof(EFI_SD_BCM2709_DEVICE_PATH));
  306. Disk->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
  307. //
  308. // Initialize the eMMC's power.
  309. //
  310. Status = EfipBcm2709MailboxSendCommand(BCM2709_MAILBOX_PROPERTIES_CHANNEL,
  311. &EfiBcm2709EmmcPowerCommand,
  312. sizeof(EFI_SD_BCM2709_ENABLE_EMMC),
  313. TRUE);
  314. if (EFI_ERROR(Status)) {
  315. goto Bcm2709EnumerateSdEnd;
  316. }
  317. //
  318. // Get the eMMC's clock frequency.
  319. //
  320. EfiCopyMem(&GetClockRate,
  321. &EfiBcm2709EmmcGetClockRateCommand,
  322. sizeof(EFI_SD_BCM2709_GET_EMMC_CLOCK));
  323. Status = EfipBcm2709MailboxSendCommand(
  324. BCM2709_MAILBOX_PROPERTIES_CHANNEL,
  325. &GetClockRate,
  326. sizeof(EFI_SD_BCM2709_GET_EMMC_CLOCK),
  327. FALSE);
  328. if (EFI_ERROR(Status)) {
  329. goto Bcm2709EnumerateSdEnd;
  330. }
  331. Length = GetClockRate.ClockRate.TagHeader.Length;
  332. ExpectedLength = sizeof(BCM2709_MAILBOX_GET_CLOCK_RATE) -
  333. sizeof(BCM2709_MAILBOX_TAG);
  334. if (BCM2709_MAILBOX_CHECK_TAG_LENGTH(Length, ExpectedLength) == FALSE) {
  335. Status = EFI_DEVICE_ERROR;
  336. goto Bcm2709EnumerateSdEnd;
  337. }
  338. Frequency = GetClockRate.ClockRate.Rate;
  339. //
  340. // Create the SD controller.
  341. //
  342. EfiSetMem(&SdParameters, sizeof(EFI_SD_INITIALIZATION_BLOCK), 0);
  343. SdParameters.StandardControllerBase =
  344. (VOID *)DevicePath->Disk.ControllerBase;
  345. SdParameters.Voltages = SD_VOLTAGE_32_33 | SD_VOLTAGE_33_34;
  346. SdParameters.HostCapabilities = SD_MODE_4BIT |
  347. SD_MODE_RESPONSE136_SHIFTED |
  348. SD_MODE_HIGH_SPEED |
  349. SD_MODE_HIGH_SPEED_52MHZ |
  350. SD_MODE_AUTO_CMD12;
  351. SdParameters.FundamentalClock = Frequency;
  352. Disk->Controller = EfiSdCreateController(&SdParameters);
  353. if (Disk->Controller == NULL) {
  354. Status = EFI_OUT_OF_RESOURCES;
  355. goto Bcm2709EnumerateSdEnd;
  356. }
  357. //
  358. // Perform some initialization to see if the card is there.
  359. //
  360. Status = EfiSdInitializeController(Disk->Controller, TRUE);
  361. if (!EFI_ERROR(Status)) {
  362. Status = EfiSdGetMediaParameters(Disk->Controller,
  363. &BlockCount,
  364. &BlockSize);
  365. if (!EFI_ERROR(Status)) {
  366. Disk->MediaPresent = TRUE;
  367. Disk->BlockSize = BlockSize;
  368. Disk->BlockCount = BlockCount;
  369. Disk->Media.MediaPresent = TRUE;
  370. Disk->Media.BlockSize = BlockSize;
  371. Disk->Media.LastBlock = BlockCount - 1;
  372. }
  373. }
  374. Status = EfiInstallMultipleProtocolInterfaces(&(Disk->Handle),
  375. &EfiDevicePathProtocolGuid,
  376. Disk->DevicePath,
  377. &EfiBlockIoProtocolGuid,
  378. &(Disk->BlockIo),
  379. NULL);
  380. Bcm2709EnumerateSdEnd:
  381. if (EFI_ERROR(Status)) {
  382. if (Disk != NULL) {
  383. if (Disk->DevicePath != NULL) {
  384. EfiFreePool(DevicePath);
  385. }
  386. if (Disk->Controller != NULL) {
  387. EfiSdDestroyController(Disk->Controller);
  388. }
  389. EfiFreePool(Disk);
  390. }
  391. }
  392. return Status;
  393. }
  394. //
  395. // --------------------------------------------------------- Internal Functions
  396. //
  397. EFIAPI
  398. EFI_STATUS
  399. EfipSdBcm2709Reset (
  400. EFI_BLOCK_IO_PROTOCOL *This,
  401. BOOLEAN ExtendedVerification
  402. )
  403. /*++
  404. Routine Description:
  405. This routine resets the block device.
  406. Arguments:
  407. This - Supplies a pointer to the protocol instance.
  408. ExtendedVerification - Supplies a boolean indicating whether or not the
  409. driver should perform diagnostics on reset.
  410. Return Value:
  411. EFI_SUCCESS on success.
  412. EFI_DEVICE_ERROR if the device had an error and could not complete the
  413. request.
  414. --*/
  415. {
  416. PEFI_SD_BCM2709_CONTEXT Disk;
  417. EFI_STATUS Status;
  418. Disk = EFI_SD_BCM2709_FROM_THIS(This);
  419. Status = EfiSdInitializeController(Disk->Controller, TRUE);
  420. if (EFI_ERROR(Status)) {
  421. Disk->MediaPresent = FALSE;
  422. Disk->Media.MediaPresent = FALSE;
  423. } else {
  424. Disk->Media.MediaId += 1;
  425. Disk->Media.MediaPresent = TRUE;
  426. Disk->MediaPresent = TRUE;
  427. }
  428. return Status;
  429. }
  430. EFIAPI
  431. EFI_STATUS
  432. EfipSdBcm2709ReadBlocks (
  433. EFI_BLOCK_IO_PROTOCOL *This,
  434. UINT32 MediaId,
  435. EFI_LBA Lba,
  436. UINTN BufferSize,
  437. VOID *Buffer
  438. )
  439. /*++
  440. Routine Description:
  441. This routine performs a block I/O read from the device.
  442. Arguments:
  443. This - Supplies a pointer to the protocol instance.
  444. MediaId - Supplies the media identifier, which changes each time the media
  445. is replaced.
  446. Lba - Supplies the logical block address of the read.
  447. BufferSize - Supplies the size of the buffer in bytes.
  448. Buffer - Supplies the buffer where the read data will be returned.
  449. Return Value:
  450. EFI_SUCCESS on success.
  451. EFI_DEVICE_ERROR if the device had an error and could not complete the
  452. request.
  453. EFI_NO_MEDIA if there is no media in the device.
  454. EFI_MEDIA_CHANGED if the media ID does not match the current device.
  455. EFI_BAD_BUFFER_SIZE if the buffer was not a multiple of the device block
  456. size.
  457. EFI_INVALID_PARAMETER if the read request contains LBAs that are not valid,
  458. or the buffer is not properly aligned.
  459. --*/
  460. {
  461. PEFI_SD_BCM2709_CONTEXT Disk;
  462. EFI_STATUS Status;
  463. Disk = EFI_SD_BCM2709_FROM_THIS(This);
  464. if (MediaId != Disk->Media.MediaId) {
  465. return EFI_MEDIA_CHANGED;
  466. }
  467. if ((Disk->MediaPresent == FALSE) || (Disk->BlockSize == 0)) {
  468. return EFI_NO_MEDIA;
  469. }
  470. Status = EfiSdBlockIoPolled(Disk->Controller,
  471. Lba,
  472. BufferSize / Disk->BlockSize,
  473. Buffer,
  474. FALSE);
  475. return Status;
  476. }
  477. EFIAPI
  478. EFI_STATUS
  479. EfipSdBcm2709WriteBlocks (
  480. EFI_BLOCK_IO_PROTOCOL *This,
  481. UINT32 MediaId,
  482. EFI_LBA Lba,
  483. UINTN BufferSize,
  484. VOID *Buffer
  485. )
  486. /*++
  487. Routine Description:
  488. This routine performs a block I/O write to the device.
  489. Arguments:
  490. This - Supplies a pointer to the protocol instance.
  491. MediaId - Supplies the media identifier, which changes each time the media
  492. is replaced.
  493. Lba - Supplies the logical block address of the write.
  494. BufferSize - Supplies the size of the buffer in bytes.
  495. Buffer - Supplies the buffer containing the data to write.
  496. Return Value:
  497. EFI_SUCCESS on success.
  498. EFI_WRITE_PROTECTED if the device cannot be written to.
  499. EFI_DEVICE_ERROR if the device had an error and could not complete the
  500. request.
  501. EFI_NO_MEDIA if there is no media in the device.
  502. EFI_MEDIA_CHANGED if the media ID does not match the current device.
  503. EFI_BAD_BUFFER_SIZE if the buffer was not a multiple of the device block
  504. size.
  505. EFI_INVALID_PARAMETER if the read request contains LBAs that are not valid,
  506. or the buffer is not properly aligned.
  507. --*/
  508. {
  509. PEFI_SD_BCM2709_CONTEXT Disk;
  510. EFI_STATUS Status;
  511. Disk = EFI_SD_BCM2709_FROM_THIS(This);
  512. if (MediaId != Disk->Media.MediaId) {
  513. return EFI_MEDIA_CHANGED;
  514. }
  515. if ((Disk->MediaPresent == FALSE) || (Disk->BlockSize == 0)) {
  516. return EFI_NO_MEDIA;
  517. }
  518. Status = EfiSdBlockIoPolled(Disk->Controller,
  519. Lba,
  520. BufferSize / Disk->BlockSize,
  521. Buffer,
  522. TRUE);
  523. return Status;
  524. }
  525. EFIAPI
  526. EFI_STATUS
  527. EfipSdBcm2709FlushBlocks (
  528. EFI_BLOCK_IO_PROTOCOL *This
  529. )
  530. /*++
  531. Routine Description:
  532. This routine flushes the block device.
  533. Arguments:
  534. This - Supplies a pointer to the protocol instance.
  535. Return Value:
  536. EFI_SUCCESS on success.
  537. EFI_DEVICE_ERROR if the device had an error and could not complete the
  538. request.
  539. EFI_NO_MEDIA if there is no media in the device.
  540. --*/
  541. {
  542. return EFI_SUCCESS;
  543. }