summaryrefslogtreecommitdiff
path: root/src/mailbox.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mailbox.c')
-rw-r--r--src/mailbox.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/src/mailbox.c b/src/mailbox.c
new file mode 100644
index 0000000..eaf0955
--- /dev/null
+++ b/src/mailbox.c
@@ -0,0 +1,73 @@
1#include <mailbox.h>
2
3#include <mmio.h>
4
5#include <stdbool.h>
6#include <stdint.h>
7
8enum
9{
10 MAILBOX = 0xB880 // Mailbox address relative to MMIO base address.
11};
12
13typedef uint32_t Message;
14
15static inline uint8_t msg_channel(Message msg) {
16 return msg & 0xf;
17}
18
19static inline const void* msg_data(Message msg) {
20 // The data field is actually a pointer to the data.
21 return (const void*)((uintptr_t)(msg >> 4));
22}
23
24static inline Message msg_make(uint8_t channel, const void* data) {
25 return ((uintptr_t)(data) << 4) | (channel & 0xf);
26}
27
28typedef struct Mailbox {
29 Message inbox; // 0x00
30 uint32_t unused_1; // 0x04
31 uint32_t unused_2; // 0x08
32 uint32_t unused_3; // 0x0C
33 uint32_t unused_4; // 0x10
34 uint32_t unused_5; // 0x14
35 uint32_t status; // 0x18
36 uint32_t unused_6; // 0x1C
37 Message outbox; // 0x20
38} Mailbox;
39
40static inline bool inbox_empty(const volatile Mailbox* pMailbox) {
41 return (pMailbox->status & 0x40000000) != 0;
42}
43
44static inline bool outbox_full(const volatile Mailbox* pMailbox) {
45 return (pMailbox->status & 0x80000000) != 0;
46}
47
48static volatile Mailbox* pMailbox;
49
50void mbox_init() {
51 pMailbox = mmio_get_peripheral(MAILBOX);
52}
53
54const Mail* mbox_read(uint8_t channel) {
55 Message msg;
56 // Read until we get a message from the desired channel.
57 // Discard any other messages.
58 do {
59 // Wait until there is mail to receive.
60 while (inbox_empty(pMailbox));
61 // Read the mail.
62 msg = pMailbox->inbox;
63 } while (msg_channel(msg) != channel);
64 return (const Mail*)(msg_data(msg));
65}
66
67void mbox_write(uint8_t channel, const void* mail) {
68 // Wait until the outbox is clear.
69 while (outbox_full(pMailbox));
70 // Send the mail.
71 pMailbox->outbox = msg_make(channel, mail);
72}
73