#include #include #include #include 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); }