This is the code I'm using (at least, enough of it that should be useful to you):
Code: Select all
#define BCM2708_PERI_BASE 0x20000000
#define GPUCORE_MAILBOX (BCM2708_PERI_BASE + 0xB880)
#define GPUCORE_MAILBOX0 (BCM2708_PERI_BASE + 0xB880)
#define GPUCORE_MAILBOX1 (BCM2708_PERI_BASE + 0xB8A0)
#define GPUCORE_MAILBOX_READ_REGISTER 0x00
#define GPUCORE_MAILBOX_WRITE_REGISTER 0x20
#define GPUCORE_MAILBOX_STATUS_REGISTER 0x18
#define GPUCORE_MAILBOX_CONFIG_REGISTER 0x1C
#define MAILBOX_STATUS_FULL 0x80000000
#define MAILBOX_STATUS_EMPTY 0x40000000
#define MAILBOX_CHANNEL_ARM_TO_VC 8
#define MAILBOX_CHANNEL_VC_TO_ARM 9
#define VCTAG_NONE 0
#define VCTAG_SINGLE sizeof(vc_mailbox_tag)
#define VCTAG_DOUBLE (sizeof(vc_mailbox_tag) + sizeof(unsigned int))
#define VCTAG_SINGLE_VAL sizeof(unsigned int)
#define VCTAG_DOUBLE_VAL (2 * sizeof(unsigned int))
#define VCTAG_REQUEST 0x00000000
#define VCTAG_RESPONSE 0x00000001
#define VCBUF_PROCESS_REQUEST 0x00000000
#define VCBUF_REQUEST_SUCCESS 0x80000000
#define VCBUF_REQUEST_ERROR 0x80000001
#define VCTAG_GET_FIRMWARE_VERSION 0x00000001
#define VCTAG_GET_BOARD_MODEL 0x00010001
#define VCTAG_GET_BOARD_REVISION 0x00010002
#define VCTAG_GET_BOARD_MAC_ADDRESS 0x00010003
#define VCTAG_GET_BOARD_SERIAL 0x00010004
#define VCTAG_GET_ARM_MEMORY 0x00010005
#define VCTAG_GET_VC_MEMORY 0x00010006
#define VCTAG_GET_CLOCKS 0x00010007
#define VCTAG_GET_COMMAND_LINE 0x00050001
#define VCTAG_GET_DMA_CHANNELS 0x00060001
#define VCTAG_GET_POWER_STATE 0x00020001
#define VCTAG_GET_TIMING 0x00020002
#define VCTAG_SET_POWER_STATE 0x00028001
#define VCTAG_GET_CLOCK_STATE 0x00030001
#define VGTAG_SET_CLOCK_STATE 0x00038001
#define VCTAG_GET_CLOCK_RATE 0x00030002
#define VCTAG_SET_CLOCK_RATE 0x00038002
#define VCTAG_ALLOCATE_FRAMEBUFFER 0x00040001
#define VCTAG_RELEASE_FRAMEBUFFER 0x00048001
#define VCTAG_BLANK_SCREEN 0x00040002
#define VCTAG_FB_GET_DIMENSIONS 0x00040003
#define VCTAG_FB_SET_DIMENSIONS 0x00048003
#define VCTAG_FB_TEST_DIMENSIONS 0x00044003
#define VCTAG_FB_GET_VDIMENSIONS 0x00040004
#define VCTAG_FB_TEST_VDIMENSIONS 0x00044004
#define VCTAG_FB_SET_VDIMENSIONS 0x00048004
#define VCTAG_FB_GET_DEPTH 0x00040005
#define VCTAG_FB_TEST_DEPTH 0x00044005
#define VCTAG_FB_SET_DEPTH 0x00048005
#define VCTAG_FB_GET_PIXEL_ORDER 0x00040006
#define VCTAG_FB_TEST_PIXEL_ORDER 0x00044006
#define VCTAG_FB_SET_PIXEL_ORDER 0x00048006
#define VCTAG_FB_GET_ALPHA_MODE 0x00040007
#define VCTAG_FB_TEST_ALPHA_MODE 0x00044007
#define VCTAG_FB_SET_ALPHA_MODE 0x00048007
#define VCTAG_FB_GET_PITCH 0x00040008
#define VCTAG_FB_GET_VOFFSET 0x00040009
#define VCTAG_FB_TEST_VOFFSET 0x00044009
#define VCTAG_FB_SET_VOFFSET 0x00048009
#define VCTAG_FB_GET_OVERSCAN 0x0004000A
#define VCTAG_FB_TEST_OVERSCAN 0x0004400A
#define VCTAG_FB_SET_OVERSCAN 0x0004800A
#define VCTAG_FB_GET_PALETTE 0x0004000B
#define VCTAG_FB_TEST_PALETTE 0x0004400B
#define VCTAG_FB_SET_PALETTE 0x0004800B
#define ALPHA_MODE_ENABLE 0
#define ALPHA_MODE_REVERSE 1
#define ALPHA_MODE_DISABLE 2
// rgb variant
unsigned int ws_palette_8bit[] = {
0, 216,
0x00000000, 0x00330000, 0x00660000, 0x00990000, 0x00CC0000, 0x00FF0000,
0x00003300, 0x00333300, 0x00663300, 0x00993300, 0x00CC3300, 0x00FF3300,
0x00006600, 0x00336600, 0x00666600, 0x00996600, 0x00CC6600, 0x00FF6600,
0x00009900, 0x00339900, 0x00669900, 0x00999900, 0x00CC9900, 0x00FF9900,
0x0000CC00, 0x0033CC00, 0x0066CC00, 0x0099CC00, 0x00CCCC00, 0x00FFCC00,
0x0000FF00, 0x0033FF00, 0x0066FF00, 0x0099FF00, 0x00CCFF00, 0x00FFFF00,
0x00000033, 0x00330033, 0x00660033, 0x00990033, 0x00CC0033, 0x00FF0033,
0x00003333, 0x00333333, 0x00663333, 0x00993333, 0x00CC3333, 0x00FF3333,
0x00006633, 0x00336633, 0x00666633, 0x00996633, 0x00CC6633, 0x00FF6633,
0x00009933, 0x00339933, 0x00669933, 0x00999933, 0x00CC9933, 0x00FF9933,
0x0000CC33, 0x0033CC33, 0x0066CC33, 0x0099CC33, 0x00CCCC33, 0x00FFCC33,
0x0000FF33, 0x0033FF33, 0x0066FF33, 0x0099FF33, 0x00CCFF33, 0x00FFFF33,
0x00000066, 0x00330066, 0x00660066, 0x00990066, 0x00CC0066, 0x00FF0066,
0x00003366, 0x00333366, 0x00663366, 0x00993366, 0x00CC3366, 0x00FF3366,
0x00006666, 0x00336666, 0x00666666, 0x00996666, 0x00CC6666, 0x00FF6666,
0x00009966, 0x00339966, 0x00669966, 0x00999966, 0x00CC9966, 0x00FF9966,
0x0000CC66, 0x0033CC66, 0x0066CC66, 0x0099CC66, 0x00CCCC66, 0x00FFCC66,
0x0000FF66, 0x0033FF66, 0x0066FF66, 0x0099FF66, 0x00CCFF66, 0x00FFFF66,
0x00000099, 0x00330099, 0x00660099, 0x00990099, 0x00CC0099, 0x00FF0099,
0x00003399, 0x00333399, 0x00663399, 0x00993399, 0x00CC3399, 0x00FF3399,
0x00006699, 0x00336699, 0x00666699, 0x00996699, 0x00CC6699, 0x00FF6699,
0x00009999, 0x00339999, 0x00669999, 0x00999999, 0x00CC9999, 0x00FF9999,
0x0000CC99, 0x0033CC99, 0x0066CC99, 0x0099CC99, 0x00CCCC99, 0x00FFCC99,
0x0000FF99, 0x0033FF99, 0x0066FF99, 0x0099FF99, 0x00CCFF99, 0x00FFFF99,
0x000000CC, 0x003300CC, 0x006600CC, 0x009900CC, 0x00CC00CC, 0x00FF00CC,
0x000033CC, 0x003333CC, 0x006633CC, 0x009933CC, 0x00CC33CC, 0x00FF33CC,
0x000066CC, 0x003366CC, 0x006666CC, 0x009966CC, 0x00CC66CC, 0x00FF66CC,
0x000099CC, 0x003399CC, 0x006699CC, 0x009999CC, 0x00CC99CC, 0x00FF99CC,
0x0000CCCC, 0x0033CCCC, 0x0066CCCC, 0x0099CCCC, 0x00CCCCCC, 0x00FFCCCC,
0x0000FFCC, 0x0033FFCC, 0x0066FFCC, 0x0099FFCC, 0x00CCFFCC, 0x00FFFFCC,
0x000000FF, 0x003300FF, 0x006600FF, 0x009900FF, 0x00CC00FF, 0x00FF00FF,
0x000033FF, 0x003333FF, 0x006633FF, 0x009933FF, 0x00CC33FF, 0x00FF33FF,
0x000066FF, 0x003366FF, 0x006666FF, 0x009966FF, 0x00CC66FF, 0x00FF66FF,
0x000099FF, 0x003399FF, 0x006699FF, 0x009999FF, 0x00CC99FF, 0x00FF99FF,
0x0000CCFF, 0x0033CCFF, 0x0066CCFF, 0x0099CCFF, 0x00CCCCFF, 0x00FFCCFF,
0x0000FFFF, 0x0033FFFF, 0x0066FFFF, 0x0099FFFF, 0x00CCFFFF, 0x00FFFFFF,
};
typedef struct vc_mailbox_tag {
unsigned int id;
unsigned int value_buffer_size;
union {
struct {
unsigned int value_length : 31;
unsigned int type : 1; // 0 = request, 1 = response
} bits;
unsigned int word;
} ctrl;
unsigned int value_buffer; // The first (of possibly many) values
} vc_mailbox_tag;
typedef struct vc_mailbox_hdr {
unsigned int size; // Size in bytes including header, end tag and padding
unsigned int type; // requests: 0x0 = process request, responses: 0x80000000 = success, 0x80000001 = error
} vc_mailbox_hdr;
typedef struct vc_mailbox_ftr {
unsigned int end_tag; // always 0x00000000
unsigned char padding;
} vc_mailbox_ftr;
unsigned int* mb_make_tag(unsigned char *buf, unsigned int *offset, unsigned int tag_id, unsigned int tagbuf_size, unsigned int tagval_size, unsigned int *data)
{
vc_mailbox_tag *tag = (vc_mailbox_tag *)(buf + *offset);
unsigned int *valptr = (unsigned int *)&tag->value_buffer;
tag->id = tag_id;
tag->value_buffer_size = tagbuf_size;
tag->ctrl.bits.value_length = tagval_size;
tag->ctrl.bits.type = VCTAG_REQUEST;
for (unsigned int i = 0; i < (tagval_size / sizeof(unsigned int)); i++)
{
*(valptr + i) = *data++;
}
*offset += sizeof(vc_mailbox_tag) + (tagbuf_size - sizeof(unsigned int));
return valptr;
}
unsigned int mb_single_request(unsigned int tag, unsigned int arg)
{
// This is a 1 tag/one value request
unsigned int tags_size = 0;
tags_size += VCTAG_SINGLE;
unsigned int buffer_size = sizeof(vc_mailbox_hdr) + sizeof(vc_mailbox_ftr) + tags_size;
unsigned char *vc_mailbox_buf = (unsigned char *)malloc(buffer_size);
vc_mailbox_hdr *hdr = (vc_mailbox_hdr *)vc_mailbox_buf;
vc_mailbox_ftr *ftr = (vc_mailbox_ftr *)(vc_mailbox_buf + sizeof(vc_mailbox_hdr) + tags_size);
hdr->size = buffer_size;
hdr->type = VCBUF_PROCESS_REQUEST;
ftr->end_tag = 0x00000000;
unsigned int offset = sizeof(vc_mailbox_hdr);
unsigned int *valptr = mb_make_tag(vc_mailbox_buf, &offset, tag, VCTAG_SINGLE_VAL, VCTAG_SINGLE_VAL, &arg);
mbox_write_gen(MAILBOX_CHANNEL_ARM_TO_VC, arm_to_vc((void *)vc_mailbox_buf));
mbox_read_gen(MAILBOX_CHANNEL_ARM_TO_VC);
unsigned int response = *valptr;
free(vc_mailbox_buf);
return response;
}
unsigned int get_fb_depth(void)
{
return mb_single_request(VCTAG_FB_GET_DEPTH, 0);
}
unsigned int get_fb_pitch(void)
{
return mb_single_request(VCTAG_FB_GET_PITCH, 0);
}
void initialise_framebuffer(unsigned int xsize, unsigned ysize, unsigned int bpp, unsigned int *base_addr, unsigned int *size)
{
// This is a 6 tag/multi value request
unsigned int tags_size = 0;
tags_size += VCTAG_SINGLE; // set alpha mode
tags_size += VCTAG_DOUBLE; // set dimensions
tags_size += VCTAG_DOUBLE; // set vdimensions
tags_size += VCTAG_SINGLE; // set depth
tags_size += VCTAG_SINGLE; // set pixel order
tags_size += VCTAG_DOUBLE; // set voffset
tags_size += VCTAG_DOUBLE; // allocate buffer
unsigned int buffer_size = sizeof(vc_mailbox_hdr) + sizeof(vc_mailbox_ftr) + tags_size;
unsigned char *vc_mailbox_buf = (unsigned char *)malloc(buffer_size);
vc_mailbox_hdr *hdr = (vc_mailbox_hdr *)vc_mailbox_buf;
vc_mailbox_ftr *ftr = (vc_mailbox_ftr *)(vc_mailbox_buf + sizeof(vc_mailbox_hdr) + tags_size);
hdr->size = buffer_size;
hdr->type = VCBUF_PROCESS_REQUEST;
ftr->end_tag = 0x00000000;
unsigned int offset = sizeof(vc_mailbox_hdr);
unsigned int alpha_mode = ALPHA_MODE_DISABLE;
mb_make_tag(vc_mailbox_buf, &offset, VCTAG_FB_SET_ALPHA_MODE, VCTAG_SINGLE_VAL, VCTAG_SINGLE_VAL, &alpha_mode);
unsigned int fbdims[2] = { xsize, ysize };
mb_make_tag(vc_mailbox_buf, &offset, VCTAG_FB_SET_DIMENSIONS, VCTAG_DOUBLE_VAL, VCTAG_DOUBLE_VAL, fbdims);
unsigned int vfbdims[2] = { xsize, ysize * 3 };
mb_make_tag(vc_mailbox_buf, &offset, VCTAG_FB_SET_VDIMENSIONS, VCTAG_DOUBLE_VAL, VCTAG_DOUBLE_VAL, vfbdims);
mb_make_tag(vc_mailbox_buf, &offset, VCTAG_FB_SET_DEPTH, VCTAG_SINGLE_VAL, VCTAG_SINGLE_VAL, &bpp);
unsigned int pixel_order = 0;
mb_make_tag(vc_mailbox_buf, &offset, VCTAG_FB_SET_PIXEL_ORDER, VCTAG_SINGLE_VAL, VCTAG_SINGLE_VAL, &pixel_order);
unsigned int voffset[2] = { 0, 0 };
mb_make_tag(vc_mailbox_buf, &offset, VCTAG_FB_SET_VOFFSET, VCTAG_DOUBLE_VAL, VCTAG_DOUBLE_VAL, voffset);
unsigned int fbalign = 0x20;
unsigned int *valptr = mb_make_tag(vc_mailbox_buf, &offset, VCTAG_ALLOCATE_FRAMEBUFFER, VCTAG_DOUBLE_VAL, VCTAG_SINGLE_VAL, &fbalign);
mbox_write_gen(MAILBOX_CHANNEL_ARM_TO_VC, arm_to_vc((void *)vc_mailbox_buf));
mbox_read_gen(MAILBOX_CHANNEL_ARM_TO_VC);
// Get the base address and fb size (assuming tags are returned in the same order)
*base_addr = *valptr;
*size = *(valptr + 1);
free(vc_mailbox_buf);
return;
}
void set_palette(void)
{
// This is a 1 tag/one value request
unsigned int tags_size = 0;
tags_size += VCTAG_SINGLE;
tags_size += (257 * sizeof(unsigned int));
unsigned int buffer_size = sizeof(vc_mailbox_hdr) + sizeof(vc_mailbox_ftr) + tags_size;
unsigned char *vc_mailbox_buf = (unsigned char *)malloc(buffer_size);
vc_mailbox_hdr *hdr = (vc_mailbox_hdr *)vc_mailbox_buf;
vc_mailbox_ftr *ftr = (vc_mailbox_ftr *)(vc_mailbox_buf + sizeof(vc_mailbox_hdr) + tags_size);
hdr->size = buffer_size;
hdr->type = VCBUF_PROCESS_REQUEST;
ftr->end_tag = 0x00000000;
unsigned int offset = sizeof(vc_mailbox_hdr);
unsigned int bufsize = sizeof(ws_palette_8bit) * sizeof(unsigned int);
unsigned int *valptr = mb_make_tag(vc_mailbox_buf, &offset, VCTAG_FB_SET_PALETTE, bufsize, bufsize, ws_palette_8bit);
mbox_write_gen(MAILBOX_CHANNEL_ARM_TO_VC, arm_to_vc((void *)vc_mailbox_buf));
mbox_read_gen(MAILBOX_CHANNEL_ARM_TO_VC);
free(vc_mailbox_buf);
return;
}
unsigned int read_mm_reg32(unsigned int base, unsigned int reg)
{
memory_barrier(); //Make sure we read the right thing
return *(volatile unsigned int *)(base + reg);
}
void write_mm_reg32(unsigned int base, unsigned int reg, unsigned int value)
{
*(volatile unsigned int *)(base + reg) = value;
memory_barrier(); //Make sure the write is visible elsewhere (see read_mm_reg32 for note on how necessary this is)
}
unsigned int mbox_read_gen(unsigned int channel)
{
unsigned int r = 0;
do
{
while (read_mm_reg32(GPUCORE_MAILBOX, GPUCORE_MAILBOX_STATUS_REGISTER) & MAILBOX_STATUS_EMPTY); // wait for data
r = read_mm_reg32(GPUCORE_MAILBOX, GPUCORE_MAILBOX_READ_REGISTER); // read the data
} while ((r & 0xF) != channel); // loop until we received something from the frame buffer channel
return r & 0xFFFFFFF0;
}
void mbox_write_gen(unsigned int channel, unsigned int v)
{
while (read_mm_reg32(GPUCORE_MAILBOX, GPUCORE_MAILBOX_STATUS_REGISTER) & MAILBOX_STATUS_FULL);
write_mm_reg32(GPUCORE_MAILBOX, GPUCORE_MAILBOX_WRITE_REGISTER, channel | (v & 0xFFFFFFF0));
}
Hopefully this will get you going in the right direction.
Please: no flames about using native types - I have no intention of ever porting this code to another platform!