Lab2: Mailbox

CPU透過呼叫VideoCoreIV(GPU) routine來設定peripheral像是clock rate及framebuffer,Mailbox充當CPU和VideoCoreIV之間的橋。

目標:用Mailbox

  1. 取得board revision及VC Core base address
  2. 設定UART clock,並取代PL011 UART為mini UART
  3. 設定framebuffer,啟動時顯示splash image

Accessing Mailbox

參考Raspberry pi官方文件mbox.c取得詳細流程。

Write

  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

因為4 bit作為channel number用,作為傳遞的地址必須對齊16bytes。

Read

  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

除了property channel外,傳遞address需考慮到VC看到的bus address。

With the exception of the property tags mailbox channel, when passing memory addresses as the data part of a mailbox message, the addresses should be bus addresses as seen from the VC.

mbox.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int mbox_call(unsigned char ch) {
/* Write to a mailbox*/
register unsigned int r =
(unsigned int)(((unsigned long)&mbox) & (~0xF)) | (ch & 0xF);
// read the status register until the full flag is not set
while (*MBOX_STATUS & MBOX_FULL) {
asm volatile("nop");
}
// Write the data combined with the channel to the write register
*MBOX_WRITE = r;

/* Read to a mailbox*/
while (1) {
// Read the status register until the empty flag is not set
while (*MBOX_STATUS & MBOX_EMPTY) {
asm volatile("nop");
}
/* Is it a response to our message? */
if (r == *MBOX_READ)
/* Is it a valid successful response? */
return mbox[1] == MBOX_RESPONSE;
}
return 0;
}

Get Board revisionGet Board revision使用channel 8進行操作

  • Channel 8: Request from ARM for response by VC
  • Channel 9: Request from VC for response by ARM (none currently defined)

Ref: Mailbox property interface

Get Board revision

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void get_board_revision() {
mbox[0] = 7 * 4; // length of the message
mbox[1] = MBOX_REQUEST; // tags begin
mbox[2] = GET_BOARD_REVISION; // tag identifier
mbox[3] = 4; // maximum of request and response value buffer's length.
mbox[4] = 0;
mbox[5] = 0; // value buffer
mbox[6] = MBOX_TAG_LAST; // tags end

if (mbox_call(MBOX_CH_PROP)) {
uart_printf("Board revision: 0x%h\n", mbox[5]);
} else {
uart_printf("Unable to retrieve board revision.\n");
};
}

Get VC Core Base Address

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void get_vc_mem() {
mbox[0] = 8 * 4;
mbox[1] = MBOX_REQUEST;
mbox[2] = GET_VC_MEMORY;
mbox[3] = 8;
mbox[4] = 0;
mbox[5] = 0;
mbox[6] = 0;
mbox[7] = MBOX_TAG_LAST;

if (mbox_call(MBOX_CH_PROP)) {
uart_printf("VC core base address: 0x%h Size: 0x%h\n", mbox[5], mbox[6]);
} else {
uart_printf("Unable to retrieve address.\n");
};
}