mailbox.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. /*++
  2. Copyright (c) 2015 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. mailbox.c
  5. Abstract:
  6. This module implements mailbox support for the TI AM33xx SoCs.
  7. Author:
  8. Evan Green 1-Oct-2015
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/driver.h>
  16. #include <minoca/fw/acpitabs.h>
  17. #include <minoca/soc/am335x.h>
  18. #include "mailbox.h"
  19. //
  20. // --------------------------------------------------------------------- Macros
  21. //
  22. #define AM3_READ_MAILBOX(_Controller, _Register) \
  23. HlReadRegister32((_Controller)->ControllerBase + (_Register))
  24. #define AM3_WRITE_MAILBOX(_Controller, _Register, _Value) \
  25. HlWriteRegister32((_Controller)->ControllerBase + (_Register), (_Value))
  26. #define AM3_MAILBOX_MESSAGE(_Index) (Am3MailboxMessage0 + ((_Index) * 4))
  27. #define AM3_MAILBOX_FIFO_STATUS(_Index) (Am3MailboxFifoStatus0 + ((_Index) * 4))
  28. #define AM3_MAILBOX_MESSAGE_STATUS(_Index) \
  29. (Am3MailboxMessageStatus0 + ((_Index) * 4))
  30. //
  31. // There are four possible users of the mailbox:
  32. // 0 - MPU subsystem
  33. // 1 - PRU_ICSS PRU0
  34. // 2 - PRU_ICSS PRU1
  35. // 3 - WakeM3
  36. //
  37. // Each user has their own interrupt.
  38. //
  39. #define AM3_MAILBOX_INTERRUPT_STATUS(_User) \
  40. (Am3MailboxInterruptStatusClear0 + ((_User) * 0x10))
  41. #define AM3_MAILBOX_INTERRUPT_ENABLE(_User) \
  42. (Am3MailboxInterruptEnableSet0 + ((_User) * 0x10))
  43. #define AM3_MAILBOX_INTERRUPT_DISABLE(_User) \
  44. (Am3MailboxInterruptEnableClear0 + ((_User) * 0x10))
  45. //
  46. // This macro returns a bitmask of the given interrupt for the given mailbox
  47. // index.
  48. //
  49. #define AM3_MAILBOX_INTERRUPT(_Mask, _Index) ((_Mask) << ((_Index) * 2))
  50. //
  51. // ---------------------------------------------------------------- Definitions
  52. //
  53. #define AM3_MAILBOX_INTERRUPT_MESSAGE 0x00000001
  54. #define AM3_MAILBOX_INTERRUPT_NOT_FULL 0x00000002
  55. //
  56. // ------------------------------------------------------ Data Type Definitions
  57. //
  58. typedef enum _AM3_MAILBOX_REGISTER {
  59. Am3MailboxRevision = 0x000,
  60. Am3MailboxSysConfig = 0x010,
  61. Am3MailboxMessage0 = 0x040,
  62. Am3MailboxFifoStatus0 = 0x080,
  63. Am3MailboxMessageStatus0 = 0x0C0,
  64. Am3MailboxInterruptStatusRaw0 = 0x100,
  65. Am3MailboxInterruptStatusClear0 = 0x104,
  66. Am3MailboxInterruptEnableSet0 = 0x108,
  67. Am3MailboxInterruptEnableClear0 = 0x10C,
  68. } AM3_MAILBOX_REGISTER, *PAM3_MAILBOX_REGISTER;
  69. typedef enum _AM3_MAILBOX_USER {
  70. Am3MailboxUserMpu = 0,
  71. Am3MailboxUserPru0 = 1,
  72. Am3MailboxUserPru1 = 2,
  73. Am3MailboxUserWakeM3 = 3
  74. } AM3_MAILBOX_USER, *PAM3_MAILBOX_USER;
  75. //
  76. // ----------------------------------------------- Internal Function Prototypes
  77. //
  78. INTERRUPT_STATUS
  79. Am3MailboxInterruptService (
  80. PVOID Context
  81. );
  82. //
  83. // -------------------------------------------------------------------- Globals
  84. //
  85. //
  86. // ------------------------------------------------------------------ Functions
  87. //
  88. KSTATUS
  89. Am3MailboxInitialize (
  90. PAM3_MAILBOX Mailbox,
  91. PIRP Irp,
  92. PRESOURCE_ALLOCATION ControllerPhysical,
  93. ULONGLONG InterruptLine,
  94. ULONGLONG InterruptVector
  95. )
  96. /*++
  97. Routine Description:
  98. This routine initializes support for the mailbox.
  99. Arguments:
  100. Irp - Supplies a pointer to the start IRP.
  101. Mailbox - Supplies a pointer to the controller, which is assumed to have
  102. been zeroed.
  103. ControllerPhysical - Supplies a pointer to the physical resource allocation
  104. of the mailbox controller.
  105. InterruptLine - Supplies the interrupt line the mailbox is connected on.
  106. InterruptVector - Supplies the interrupt vector the mailbox should use.
  107. Return Value:
  108. Status code.
  109. --*/
  110. {
  111. UINTN AlignmentOffset;
  112. IO_CONNECT_INTERRUPT_PARAMETERS Connect;
  113. PHYSICAL_ADDRESS EndAddress;
  114. ULONG PageSize;
  115. PHYSICAL_ADDRESS PhysicalAddress;
  116. ULONG Register;
  117. UINTN Size;
  118. KSTATUS Status;
  119. ULONG Value;
  120. ASSERT(Mailbox->ControllerBase == NULL);
  121. Mailbox->InterruptHandle = INVALID_HANDLE;
  122. Mailbox->InterruptLine = InterruptLine;
  123. Mailbox->InterruptVector = InterruptVector;
  124. //
  125. // Map the registers.
  126. //
  127. if (Mailbox->ControllerBase == NULL) {
  128. //
  129. // Page align the mapping request.
  130. //
  131. PageSize = MmPageSize();
  132. PhysicalAddress = ControllerPhysical->Allocation;
  133. EndAddress = PhysicalAddress + ControllerPhysical->Length;
  134. PhysicalAddress = ALIGN_RANGE_DOWN(PhysicalAddress, PageSize);
  135. AlignmentOffset = ControllerPhysical->Allocation - PhysicalAddress;
  136. EndAddress = ALIGN_RANGE_UP(EndAddress, PageSize);
  137. Size = (ULONG)(EndAddress - PhysicalAddress);
  138. //
  139. // If the size is not a the constant, then the failure code at the
  140. // bottom needs to be fancier.
  141. //
  142. ASSERT(Size == AM335_MAILBOX_SIZE);
  143. Mailbox->ControllerBase = MmMapPhysicalAddress(PhysicalAddress,
  144. Size,
  145. TRUE,
  146. FALSE,
  147. TRUE);
  148. if (Mailbox->ControllerBase == NULL) {
  149. Status = STATUS_NO_MEMORY;
  150. goto MailboxInitializeEnd;
  151. }
  152. Mailbox->ControllerBase += AlignmentOffset;
  153. }
  154. ASSERT(Mailbox->ControllerBase != NULL);
  155. //
  156. // Connect the mailbox interrupt.
  157. //
  158. ASSERT(Mailbox->InterruptHandle == INVALID_HANDLE);
  159. RtlZeroMemory(&Connect, sizeof(IO_CONNECT_INTERRUPT_PARAMETERS));
  160. Connect.Version = IO_CONNECT_INTERRUPT_PARAMETERS_VERSION;
  161. Connect.Device = Irp->Device;
  162. Connect.LineNumber = Mailbox->InterruptLine;
  163. Connect.Vector = Mailbox->InterruptVector;
  164. Connect.InterruptServiceRoutine = Am3MailboxInterruptService;
  165. Connect.Context = Mailbox;
  166. Connect.Interrupt = &(Mailbox->InterruptHandle);
  167. Status = IoConnectInterrupt(&Connect);
  168. if (!KSUCCESS(Status)) {
  169. goto MailboxInitializeEnd;
  170. }
  171. //
  172. // Enable interrupts towards the Cortex M3 for the mailbox dedicated to it.
  173. //
  174. Register = AM3_MAILBOX_INTERRUPT_ENABLE(Am3MailboxUserWakeM3);
  175. Value = AM3_MAILBOX_INTERRUPT(AM3_MAILBOX_INTERRUPT_MESSAGE,
  176. AM335_WAKEM3_MAILBOX);
  177. AM3_WRITE_MAILBOX(Mailbox, Register, Value);
  178. MailboxInitializeEnd:
  179. if (!KSUCCESS(Status)) {
  180. Am3MailboxDestroy(Mailbox);
  181. }
  182. return Status;
  183. }
  184. VOID
  185. Am3MailboxDestroy (
  186. PAM3_MAILBOX Mailbox
  187. )
  188. /*++
  189. Routine Description:
  190. This routine tears down a mailbox controller.
  191. Arguments:
  192. Mailbox - Supplies a pointer to the initialized controller.
  193. Return Value:
  194. None.
  195. --*/
  196. {
  197. if (Mailbox->InterruptHandle != INVALID_HANDLE) {
  198. IoDisconnectInterrupt(Mailbox->InterruptHandle);
  199. Mailbox->InterruptHandle = INVALID_HANDLE;
  200. }
  201. if (Mailbox->ControllerBase != NULL) {
  202. MmUnmapAddress(Mailbox->ControllerBase, AM335_MAILBOX_SIZE);
  203. Mailbox->ControllerBase = NULL;
  204. }
  205. return;
  206. }
  207. VOID
  208. Am3MailboxSend (
  209. PAM3_MAILBOX Mailbox,
  210. ULONG Index,
  211. ULONG Message
  212. )
  213. /*++
  214. Routine Description:
  215. This routine writes a new message to the AM3 mailbox.
  216. Arguments:
  217. Mailbox - Supplies a pointer to the controller.
  218. Index - Supplies the mailbox number to write to. Valid values are 0-7.
  219. Message - Supplies the value to write.
  220. Return Value:
  221. None.
  222. --*/
  223. {
  224. ULONG Register;
  225. Register = AM3_MAILBOX_MESSAGE(Index);
  226. AM3_WRITE_MAILBOX(Mailbox, Register, Message);
  227. return;
  228. }
  229. VOID
  230. Am3MailboxFlush (
  231. PAM3_MAILBOX Mailbox,
  232. ULONG Index
  233. )
  234. /*++
  235. Routine Description:
  236. This routine reads all messages back out of the mailbox and discards them.
  237. Arguments:
  238. Mailbox - Supplies a pointer to the controller.
  239. Index - Supplies the mailbox number to write to. Valid values are 0-7.
  240. Return Value:
  241. None.
  242. --*/
  243. {
  244. ULONG InterruptStatus;
  245. ULONG InterruptStatusRegister;
  246. ULONG MessageRegister;
  247. ULONG MessageStatusRegister;
  248. MessageRegister = AM3_MAILBOX_MESSAGE(Index);
  249. MessageStatusRegister = AM3_MAILBOX_MESSAGE_STATUS(Index);
  250. while (AM3_READ_MAILBOX(Mailbox, MessageStatusRegister) != 0) {
  251. AM3_READ_MAILBOX(Mailbox, MessageRegister);
  252. }
  253. //
  254. // Remove any interrupts from the Cortex M3 status as well.
  255. //
  256. if (Index == AM335_WAKEM3_MAILBOX) {
  257. InterruptStatusRegister =
  258. AM3_MAILBOX_INTERRUPT_STATUS(Am3MailboxUserWakeM3);
  259. InterruptStatus = AM3_READ_MAILBOX(Mailbox, InterruptStatusRegister);
  260. if (InterruptStatus != 0) {
  261. AM3_WRITE_MAILBOX(Mailbox,
  262. InterruptStatusRegister,
  263. InterruptStatus);
  264. }
  265. }
  266. return;
  267. }
  268. //
  269. // --------------------------------------------------------- Internal Functions
  270. //
  271. INTERRUPT_STATUS
  272. Am3MailboxInterruptService (
  273. PVOID Context
  274. )
  275. /*++
  276. Routine Description:
  277. This routine represents an interrupt service routine.
  278. Arguments:
  279. Context - Supplies the context supplied when this interrupt was initially
  280. connected.
  281. Return Value:
  282. Returns an interrupt status indicating if this ISR is claiming the
  283. interrupt, not claiming the interrupt, or needs the interrupt to be
  284. masked temporarily.
  285. --*/
  286. {
  287. //
  288. // Complete official mailbox support is not yet implemented. The only user
  289. // is currently the sleep code, which has interrupts disabled the whole
  290. // time.
  291. //
  292. ASSERT(FALSE);
  293. return InterruptStatusNotClaimed;
  294. }