summaryrefslogtreecommitdiff
path: root/src/mailbox.c
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);
}