-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Accessing mailboxes
This page is a stub for completion by someone who knows more than I about the subject.
Mailboxes facilitate communication between the ARM and the VideoCore. This page describes the procedure for accessing a mailbox. For a list of the available mailboxes, see here.
To read from a mailbox:
-
Read the status register until the empty flag is not set
-
Read data from the read register
-
If the lower four bits do not match the channel number desired then repeat from 1
-
The upper 28 bits are the returned data
To write to a mailbox
-
Read the status register until the full flag is not set
-
Write the data (shifted into the upper 28 bits) combined with the channel (in the lower four bits) to the write register
Memory barriers or data cache invalidation/flushing may be required around mailbox accesses, details on this needs to be added to this page (or the page for the particular mailbox/channel that requires it) by someone who knows the details.
The following instructions are taken from http://infocenter.arm.com/help/topic/com.arm.doc.ddi0360f/I1014942.html. Any unneeded register can be used in the following example instead of r3.
mov r3, #0 # The read register Should Be Zero before the call
mcr p15, 0, r3, C7, C6, 0 # Invalidate Entire Data Cache
mcr p15, 0, r3, c7, c10, 0 # Clean Entire Data Cache
mcr p15, 0, r3, c7, c14, 0 # Clean and Invalidate Entire Data Cache
mcr p15, 0, r3, c7, c10, 4 # Data Synchronization Barrier
mcr p15, 0, r3, c7, c10, 5 # Data Memory Barrier
The following procedure is used sometimes around physical device accesses.
MemoryBarrier:
mcr p15, 0, r3, c7, c5, 0 # Invalidate instruction cache
mcr p15, 0, r3, c7, c5, 6 # Invalidate BTB
mcr p15, 0, r3, c7, c10, 4 # Drain write buffer
mcr p15, 0, r3, c7, c5, 4 # Prefetch flush
mov pc, lr # Return
This code is untested and is written for clarity rather than brevity or efficiency, but is provided for convenience.
#define MAIL_BASE 0xB880 // Base address for the mailbox registers
// This bit is set in the status register if there is no space to write into the mailbox
#define MAIL_FULL 0x80000000
// This bit is set in the status register if there is nothing to read from the mailbox
#define MAIL_EMPTY 0x40000000
uint32 ReadMailbox(byte channel)
{
// Loop until we receive something from the requested channel
for (;;)
{
while ((ReadMemMappedReg<uint32>(MAIL_BASE, StatusOffset) & MAIL_EMPTY) != 0)
{
// Wait for data
}
// Read the data
uint32 data = ReadMemMappedReg<uint32>(MAIL_BASE, ReadOffset);
byte readChannel = data & 0xF;
data >>= 4;
// Return it straight away if it's for the requested channel
if (readChannel == channel)
return data;
}
}
void WriteMailbox(byte channel, uint32 data)
{
while ((ReadMemMappedReg<uint32>(MAIL_BASE, StatusOffset) & MAIL_FULL) != 0)
{
// Wait for space
}
// Write the value to the requested channel
WriteMemMappedReg(MAIL_BASE, WriteOffset, (data << 4) | channel);
}
#define BUS_BASE (L2CACHE_ENABLED ? 0x40000000 : 0xC0000000)
template<class T>
static T ReadMemMappedReg(size_t BaseAddress, size_t Offset)
{
return *reinterpret_cast<const T *>(BUS_BASE + BaseAddress + Offset);
}
template<class T>
static void WriteMemMappedReg(size_t BaseAddress, size_t Offset, T Data)
{
*reinterpret_cast<T *>(BUS_BASE + BaseAddress + Offset) = Data;
}