mailbox.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /*++
  2. Copyright (c) 2015 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. mailbox.c
  9. Abstract:
  10. This module implements support for the Broadcom 2709 Mailbox.
  11. Author:
  12. Chris Stevens 31-Dec-2014
  13. Environment:
  14. Firmware
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <uefifw.h>
  20. #include <dev/bcm2709.h>
  21. //
  22. // --------------------------------------------------------------------- Macros
  23. //
  24. //
  25. // This macro reads from the BCM2709 mailbox. The parameter should
  26. // be a BCM2709_MAILBOX_REGISTER value.
  27. //
  28. #define READ_MAILBOX_REGISTER(_Register) \
  29. EfiReadRegister32(BCM2709_MAILBOX_BASE + (_Register))
  30. //
  31. // This macro writes to the BCM2709 mailbox. _Register should be a
  32. // BCM2709_MAILBOX_REGISTER value and _Value should be a UINT32.
  33. //
  34. #define WRITE_MAILBOX_REGISTER(_Register, _Value) \
  35. EfiWriteRegister32(BCM2709_MAILBOX_BASE + (_Register), (_Value))
  36. //
  37. // ---------------------------------------------------------------- Definitions
  38. //
  39. //
  40. // ------------------------------------------------------ Data Type Definitions
  41. //
  42. //
  43. // ----------------------------------------------- Internal Function Prototypes
  44. //
  45. VOID
  46. EfipBcm2709MailboxSend (
  47. UINT32 Channel,
  48. VOID *Data
  49. );
  50. EFI_STATUS
  51. EfipBcm2709MailboxReceive (
  52. UINT32 Channel,
  53. VOID **Data
  54. );
  55. //
  56. // -------------------------------------------------------------------- Globals
  57. //
  58. //
  59. // ------------------------------------------------------------------ Functions
  60. //
  61. EFI_STATUS
  62. EfipBcm2709MailboxSendCommand (
  63. UINT32 Channel,
  64. VOID *Command,
  65. UINT32 CommandSize,
  66. BOOLEAN Set
  67. )
  68. /*++
  69. Routine Description:
  70. This routine sends the given command to the given channel of the BCM2709's
  71. mailbox. If it is a GET request, then the data will be returned in the
  72. supplied command buffer.
  73. Arguments:
  74. Channel - Supplies the mailbox channel that is to receive the command.
  75. Command - Supplies the command to send.
  76. CommandSize - Supplies the size of the command to send.
  77. Set - Supplies a boolean indicating whether or not the command is a SET
  78. (TRUE) or GET (FALSE) request. SET-GET requests should be
  79. considered GETs.
  80. Return Value:
  81. Status code.
  82. --*/
  83. {
  84. VOID *AlignedBuffer;
  85. UINTN AllocationSize;
  86. VOID *Buffer;
  87. PBCM2709_MAILBOX_HEADER Header;
  88. VOID *ReceiveBuffer;
  89. EFI_STATUS Status;
  90. //
  91. // The BCM2709 device library must be initialized.
  92. //
  93. if (EfiBcm2709Initialized == FALSE) {
  94. return EFI_NOT_READY;
  95. }
  96. //
  97. // Allocate an aligned buffer for the command, if necessary.
  98. //
  99. Buffer = NULL;
  100. if (ALIGN_POINTER(Command, BCM2709_MAILBOX_DATA_ALIGNMENT) != Command) {
  101. AllocationSize = CommandSize + BCM2709_MAILBOX_DATA_ALIGNMENT;
  102. Status = EfiAllocatePool(EfiBootServicesData, AllocationSize, &Buffer);
  103. if (EFI_ERROR(Status)) {
  104. goto Bcm2709MailboxSendCommandEnd;
  105. }
  106. AlignedBuffer = ALIGN_POINTER(Buffer, BCM2709_MAILBOX_DATA_ALIGNMENT);
  107. //
  108. // Copy the data from the USB power template.
  109. //
  110. EfiCopyMem(AlignedBuffer, Command, CommandSize);
  111. } else {
  112. AlignedBuffer = Command;
  113. }
  114. //
  115. // Send the aligned command to the given channel.
  116. //
  117. EfipBcm2709MailboxSend(Channel, AlignedBuffer);
  118. //
  119. // Wait for a response to make sure the data was written or to get the read
  120. // data.
  121. //
  122. Status = EfipBcm2709MailboxReceive(Channel, &ReceiveBuffer);
  123. if (EFI_ERROR(Status)) {
  124. goto Bcm2709MailboxSendCommandEnd;
  125. }
  126. //
  127. // Check to make sure the transmission was successful.
  128. //
  129. Header = (PBCM2709_MAILBOX_HEADER)ReceiveBuffer;
  130. if (Header->Code != BCM2709_MAILBOX_STATUS_SUCCESS) {
  131. Status = EFI_DEVICE_ERROR;
  132. goto Bcm2709MailboxSendCommandEnd;
  133. }
  134. //
  135. // Copy the result back to the original command buffer in case information
  136. // was returned.
  137. //
  138. if ((Set == FALSE) && (ReceiveBuffer != Command)) {
  139. EfiCopyMem(Command, ReceiveBuffer, CommandSize);
  140. }
  141. Bcm2709MailboxSendCommandEnd:
  142. if (Buffer != NULL) {
  143. EfiFreePool(Buffer);
  144. }
  145. return Status;
  146. }
  147. //
  148. // --------------------------------------------------------- Internal Functions
  149. //
  150. VOID
  151. EfipBcm2709MailboxSend (
  152. UINT32 Channel,
  153. VOID *Data
  154. )
  155. /*++
  156. Routine Description:
  157. This routine sends the given data to the specified mailbox channel.
  158. Arguments:
  159. Channel - Supplies the mailbox channel to which the data should be sent.
  160. Data - Supplies the data buffer to send to the mailbox.
  161. Return Value:
  162. None.
  163. --*/
  164. {
  165. UINT32 MailboxData;
  166. UINT32 MailboxStatus;
  167. //
  168. // The data should be aligned such that there is room to OR in the channel
  169. // information.
  170. //
  171. // ASSERT((UINT32)Data == (UINTN)Data);
  172. // ASSERT(((UINT32)Data & BCM2709_MAILBOX_READ_WRITE_CHANNEL_MASK) == 0);
  173. // ASSERT((Channel & ~BCM2709_MAILBOX_READ_WRITE_CHANNEL_MASK) == 0);
  174. //
  175. //
  176. // Wait until there is nothing to read as noted by the read empty flag.
  177. //
  178. while (TRUE) {
  179. MailboxStatus = READ_MAILBOX_REGISTER(Bcm2709MailboxStatus);
  180. if ((MailboxStatus & BCM2709_MAILBOX_STATUS_READ_EMPTY) != 0) {
  181. break;
  182. }
  183. }
  184. //
  185. // Wait until there is room to write into the mailbox.
  186. //
  187. while (TRUE) {
  188. MailboxStatus = READ_MAILBOX_REGISTER(Bcm2709MailboxStatus);
  189. if ((MailboxStatus & BCM2709_MAILBOX_STATUS_WRITE_FULL) == 0) {
  190. break;
  191. }
  192. }
  193. //
  194. // Add the channel to the supplied data and write the data to the mailbox.
  195. //
  196. MailboxData = (UINT32)Data | Channel;
  197. WRITE_MAILBOX_REGISTER(Bcm2709MailboxWrite, MailboxData);
  198. return;
  199. }
  200. EFI_STATUS
  201. EfipBcm2709MailboxReceive (
  202. UINT32 Channel,
  203. VOID **Data
  204. )
  205. /*++
  206. Routine Description:
  207. This routine receives data from the given mailbox channel.
  208. Arguments:
  209. Channel - Supplies the mailbox channel from which data is expected.
  210. Data - Supplies a pointer that receives the data buffer returned by the
  211. mailbox.
  212. Return Value:
  213. Status code.
  214. --*/
  215. {
  216. UINT32 MailboxData;
  217. UINT32 MailboxStatus;
  218. EFI_STATUS Status;
  219. //
  220. // Wait until there is something to read from the mailbox.
  221. //
  222. while (TRUE) {
  223. MailboxStatus = READ_MAILBOX_REGISTER(Bcm2709MailboxStatus);
  224. if ((MailboxStatus & BCM2709_MAILBOX_STATUS_READ_EMPTY) == 0) {
  225. break;
  226. }
  227. }
  228. //
  229. // Read the mailbox and fail if the response is not for the correct channel.
  230. // There really shouldn't be concurrency issues at this point, but the
  231. // recourse would be to retry until data from the correct channel is
  232. // returned.
  233. //
  234. MailboxData = READ_MAILBOX_REGISTER(Bcm2709MailboxRead);
  235. if ((MailboxData & BCM2709_MAILBOX_READ_WRITE_CHANNEL_MASK) != Channel) {
  236. Status = EFI_NOT_READY;
  237. goto Bcm2709MailboxReceiveEnd;
  238. }
  239. //
  240. // Remove the channel information and return the data.
  241. //
  242. MailboxData &= ~BCM2709_MAILBOX_READ_WRITE_CHANNEL_MASK;
  243. *Data = (VOID *)MailboxData;
  244. Status = EFI_SUCCESS;
  245. Bcm2709MailboxReceiveEnd:
  246. return Status;
  247. }