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