Skip to content

Accessing mailboxes

NathanJPhillips edited this page Jul 16, 2012 · 9 revisions

Draft

This page is a stub for completion by someone who knows more than I about the subject.

Overview

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.

General procedure

To read from a mailbox:

  1. Read the status register until the empty flag is not set

  2. Read data from the read register

  3. If the lower four bits do not match the channel number desired then repeat from 1

  4. The upper 28 bits are the returned data

To write to a mailbox

  1. Read the status register until the full flag is not set

  2. Write the data (shifted into the upper 28 bits) combined with the channel (in the lower four bits) to the write register

Memory barriers & Invalidating/flushing data cache

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

Sample code

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;
}
Clone this wiki locally