Hi Stephen, On Thu, 18 Oct 2012 22:51:31 -0600, Stephen Warren <swar...@wwwdotorg.org> wrote:
> The BCM2835 SoC contains (at least) two CPUs; the VideoCore (a/k/a "GPU") > and the ARM CPU. The ARM CPU is often thought of as the main CPU. > However, the VideoCore actually controls the initial SoC boot, and hides > much of the hardware behind a protocol. This protocol is transported > using the SoC's mailbox hardware module. > > Here, we add a very simplistic driver for the mailbox module, and define > a few structures for the property messages. > > Signed-off-by: Stephen Warren <swar...@wwwdotorg.org> > --- > v2: > * Added documentation to mbox.h. > * Implemented macros to set up headers and tags. > * Implemented error-checking of response bits in bcm2835_mbox_call_prop(). > * Reworked tag structs based on experience writing LCD driver. > * Added a lot more video-related tag structs. > * Added debug spew and error messages to mbox.c; useful when debugging LCD. > * Removed __packed attributes from message structs. > * Removed stale FIXME comments. > --- > arch/arm/cpu/arm1176/bcm2835/Makefile | 2 +- > arch/arm/cpu/arm1176/bcm2835/mbox.c | 163 ++++++++++++ > arch/arm/include/asm/arch-bcm2835/mbox.h | 406 > ++++++++++++++++++++++++++++++ > 3 files changed, 570 insertions(+), 1 deletion(-) > create mode 100644 arch/arm/cpu/arm1176/bcm2835/mbox.c > create mode 100644 arch/arm/include/asm/arch-bcm2835/mbox.h > > diff --git a/arch/arm/cpu/arm1176/bcm2835/Makefile > b/arch/arm/cpu/arm1176/bcm2835/Makefile > index 95da6a8..135de42 100644 > --- a/arch/arm/cpu/arm1176/bcm2835/Makefile > +++ b/arch/arm/cpu/arm1176/bcm2835/Makefile > @@ -17,7 +17,7 @@ include $(TOPDIR)/config.mk > LIB = $(obj)lib$(SOC).o > > SOBJS := lowlevel_init.o > -COBJS := init.o reset.o timer.o > +COBJS := init.o reset.o timer.o mbox.o > > SRCS := $(SOBJS:.o=.c) $(COBJS:.o=.c) > OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) > diff --git a/arch/arm/cpu/arm1176/bcm2835/mbox.c > b/arch/arm/cpu/arm1176/bcm2835/mbox.c > new file mode 100644 > index 0000000..3ce76d0 > --- /dev/null > +++ b/arch/arm/cpu/arm1176/bcm2835/mbox.c > @@ -0,0 +1,163 @@ > +/* > + * (C) Copyright 2012 Stephen Warren > + * > + * See file CREDITS for list of people who contributed to this > + * project. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * version 2 as published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + */ > + > +#include <common.h> > +#include <asm/io.h> > +#include <asm/arch/mbox.h> > + > +#define TIMEOUT (100 * 1000) /* 100mS in uS */ > + > +int bcm2835_mbox_call_raw(u32 chan, u32 send, u32 *recv) > +{ > + struct bcm2835_mbox_regs *regs = > + (struct bcm2835_mbox_regs *)BCM2835_MBOX_PHYSADDR; > + ulong endtime = get_timer(0) + TIMEOUT; > + u32 val; > + > + debug("time: %lu timeout: %lu\n", get_timer(0), endtime); > + > + if (send & BCM2835_CHAN_MASK) { > + printf("mbox: Illegal mbox data 0x%08x\n", send); > + return -1; > + } > + > + /* Drain any stale responses */ > + > + for (;;) { > + val = readl(®s->status); > + if (val & BCM2835_MBOX_STATUS_RD_EMPTY) > + break; > + if (get_timer(0) >= endtime) { > + printf("mbox: Timeout draining stale responses\n"); > + return -1; > + } > + val = readl(®s->read); > + } > + > + /* Wait for space to send */ > + > + for (;;) { > + val = readl(®s->status); > + if (!(val & BCM2835_MBOX_STATUS_WR_FULL)) > + break; > + if (get_timer(0) >= endtime) { > + printf("mbox: Timeout waiting for send space\n"); > + return -1; > + } > + } > + > + /* Send the request */ > + > + val = BCM2835_MBOX_PACK(chan, send); > + debug("mbox: TX raw: 0x%08x\n", val); > + writel(val, ®s->write); > + > + /* Wait for the response */ > + > + for (;;) { > + val = readl(®s->status); > + if (!(val & BCM2835_MBOX_STATUS_RD_EMPTY)) > + break; > + if (get_timer(0) >= endtime) { > + printf("mbox: Timeout waiting for response\n"); > + return -1; > + } > + } > + > + /* Read the response */ > + > + val = readl(®s->read); > + debug("mbox: RX raw: 0x%08x\n", val); > + > + /* Validate the response */ > + > + if (BCM2835_MBOX_UNPACK_CHAN(val) != chan) { > + printf("mbox: Response channel mismatch\n"); > + return -1; > + } > + > + *recv = BCM2835_MBOX_UNPACK_DATA(val); > + > + return 0; > +} > + > +#ifdef DEBUG > +void dump_buf(struct bcm2835_mbox_hdr *buffer) > +{ > + u32 *p; > + u32 words; > + int i; > + > + p = (u32 *)buffer; > + words = buffer->buf_size / 4; > + for (i = 0; i < words; i++) > + printf(" 0x%04x: 0x%08x\n", i * 4, p[i]); > +} > +#endif > + > +int bcm2835_mbox_call_prop(u32 chan, struct bcm2835_mbox_hdr *buffer) > +{ > + int ret; > + u32 rbuffer; > + struct bcm2835_mbox_tag_hdr *tag; > + int tag_index; > + > +#ifdef DEBUG > + printf("mbox: TX buffer\n"); > + dump_buf(buffer); > +#endif > + > + ret = bcm2835_mbox_call_raw(chan, (u32)buffer, &rbuffer); > + if (ret) > + return ret; > + if (rbuffer != (u32)buffer) { > + printf("mbox: Response buffer mismatch\n"); > + return -1; > + } > + > +#ifdef DEBUG > + printf("mbox: RX buffer\n"); > + dump_buf(buffer); > +#endif > + > + /* Validate overall response status */ > + > + if (buffer->code != BCM2835_MBOX_RESP_CODE_SUCCESS) { > + printf("mbox: Header response code invalid\n"); > + return -1; > + } > + > + /* Validate each tag's response status */ > + > + tag = (void *)(buffer + 1); > + tag_index = 0; > + while (tag->tag) { > + if (!(tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE)) { > + printf("mbox: Tag %d missing val_len response bit\n", > + tag_index); > + return -1; > + } > + /* > + * Clear the reponse bit so clients can just look right at the > + * length field without extra processing > + */ > + tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE; > + tag = (void *)(((u8 *)tag) + sizeof(*tag) + tag->val_buf_size); > + tag_index++; > + } > + > + return 0; > +} > diff --git a/arch/arm/include/asm/arch-bcm2835/mbox.h > b/arch/arm/include/asm/arch-bcm2835/mbox.h > new file mode 100644 > index 0000000..6e040c5 > --- /dev/null > +++ b/arch/arm/include/asm/arch-bcm2835/mbox.h > @@ -0,0 +1,406 @@ > +/* > + * (C) Copyright 2012 Stephen Warren > + * > + * See file CREDITS for list of people who contributed to this > + * project. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * version 2 as published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + */ > + > +#ifndef _BCM2835_MBOX_H > +#define _BCM2835_MBOX_H > + > +#include <linux/compiler.h> > + > +/* > + * The BCM2835 SoC contains (at least) two CPUs; the VideoCore (a/k/a "GPU") > + * and the ARM CPU. The ARM CPU is often thought of as the main CPU. > + * However, the VideoCore actually controls the initial SoC boot, and hides > + * much of the hardware behind a protocol. This protocol is transported > + * using the SoC's mailbox hardware module. > + * > + * The mailbox hardware supports passing 32-bit values back and forth. > + * Presumably by software convention of the firmware, the bottom 4 bits of > the > + * value are used to indicate a logical channel, and the upper 28 bits are > the > + * actual payload. Various channels exist using these simple raw messages. > See > + * https://github.com/raspberrypi/firmware/wiki/Mailboxes for a list. As an > + * example, the messages on the power management channel are a bitmask of > + * devices whose power should be enabled. > + * > + * The property mailbox channel passes messages that contain the (16-byte > + * aligned) ARM physical address of a memory buffer. This buffer is passed to > + * the VC for processing, is modified in-place by the VC, and the address > then > + * passed back to the ARM CPU as the response mailbox message to indicate > + * request completion. The buffers have a generic and extensible format; each > + * buffer contains a standard header, a list of "tags", and a terminating > zero > + * entry. Each tag contains an ID indicating its type, and length fields for > + * generic parsing. With some limitations, an arbitrary set of tags may be > + * combined together into a single message buffer. This file defines structs > + * representing the header and many individual tag layouts and IDs. > + */ > + > +/* Raw mailbox HW */ > + > +#define BCM2835_MBOX_PHYSADDR 0x2000b880 > + > +struct bcm2835_mbox_regs { > + u32 read; > + u32 rsvd0[5]; > + u32 status; > + u32 config; > + u32 write; > +}; > + > +#define BCM2835_MBOX_STATUS_WR_FULL 0x80000000 > +#define BCM2835_MBOX_STATUS_RD_EMPTY 0x40000000 > + > +/* Lower 4-bits are channel ID */ > +#define BCM2835_CHAN_MASK 0xf > +#define BCM2835_MBOX_PACK(chan, data) (((data) & > (~BCM2835_CHAN_MASK)) | \ > + (chan & BCM2835_CHAN_MASK)) > +#define BCM2835_MBOX_UNPACK_CHAN(val) ((val) & BCM2835_CHAN_MASK) > +#define BCM2835_MBOX_UNPACK_DATA(val) ((val) & (~BCM2835_CHAN_MASK)) > + > +/* Property mailbox buffer structures */ > + > +#define BCM2835_MBOX_PROP_CHAN 8 > + > +/* All message buffers must start with this header */ > +struct bcm2835_mbox_hdr { > + u32 buf_size; > + u32 code; > +}; > + > +#define BCM2835_MBOX_REQ_CODE 0 > +#define BCM2835_MBOX_RESP_CODE_SUCCESS 0x80000000 > + > +#define BCM2835_MBOX_INIT_HDR(_m_) { \ > + memset((_m_), 0, sizeof(*(_m_))); \ > + (_m_)->hdr.buf_size = sizeof(*(_m_)); \ > + (_m_)->hdr.code = 0; \ > + (_m_)->end_tag = 0; \ > + } > + > +/* > + * A message buffer contains a list of tags. Each tag must also start with > + * a standardized header. > + */ > +struct bcm2835_mbox_tag_hdr { > + u32 tag; > + u32 val_buf_size; > + u32 val_len; > +}; > + > +#define BCM2835_MBOX_INIT_TAG(_t_, _id_) { \ > + (_t_)->tag_hdr.tag = BCM2835_MBOX_TAG_##_id_; \ > + (_t_)->tag_hdr.val_buf_size = sizeof((_t_)->body); \ > + (_t_)->tag_hdr.val_len = sizeof((_t_)->body.req); \ > + } > + > +#define BCM2835_MBOX_INIT_TAG_NO_REQ(_t_, _id_) { \ > + (_t_)->tag_hdr.tag = BCM2835_MBOX_TAG_##_id_; \ > + (_t_)->tag_hdr.val_buf_size = sizeof((_t_)->body); \ > + (_t_)->tag_hdr.val_len = 0; \ > + } > + > +/* When responding, the VC sets this bit in val_len to indicate a response */ > +#define BCM2835_MBOX_TAG_VAL_LEN_RESPONSE 0x80000000 > + > +/* > + * Below we define the ID and struct for many possible tags. This header only > + * defines individual tag structs, not entire message structs, since in > + * general an arbitrary set of tags may be combined into a single message. > + * Clients of the mbox API are expected to define their own overall message > + * structures by combining the header, a set of tags, and a terminating > + * entry. For example, > + * > + * struct msg { > + * struct bcm2835_mbox_hdr hdr; > + * struct bcm2835_mbox_tag_get_arm_mem get_arm_mem; > + * ... perhaps other tags here ... > + * u32 end_tag; > + * }; > + */ > + > +#define BCM2835_MBOX_TAG_GET_ARM_MEMORY 0x00010005 > + > +struct bcm2835_mbox_tag_get_arm_mem { > + struct bcm2835_mbox_tag_hdr tag_hdr; > + union { > + struct { > + } req; > + struct { > + u32 mem_base; > + u32 mem_size; > + } resp; > + } body; > +}; > + > +#define BCM2835_MBOX_TAG_ALLOCATE_BUFFER 0x00040001 > + > +struct bcm2835_mbox_tag_allocate_buffer { > + struct bcm2835_mbox_tag_hdr tag_hdr; > + union { > + struct { > + u32 alignment; > + } req; > + struct { > + u32 fb_address; > + u32 fb_size; > + } resp; > + } body; > +}; > + > +#define BCM2835_MBOX_TAG_RELEASE_BUFFER 0x00048001 > + > +struct bcm2835_mbox_tag_release_buffer { > + struct bcm2835_mbox_tag_hdr tag_hdr; > + union { > + struct { > + } req; > + struct { > + } resp; > + } body; > +}; > + > +#define BCM2835_MBOX_TAG_BLANK_SCREEN 0x00040002 > + > +struct bcm2835_mbox_tag_blank_screen { > + struct bcm2835_mbox_tag_hdr tag_hdr; > + union { > + struct { > + /* bit 0 means on, other bots reserved */ > + u32 state; > + } req; > + struct { > + u32 state; > + } resp; > + } body; > +}; > + > +/* Physical means output signal */ > +#define BCM2835_MBOX_TAG_GET_PHYSICAL_W_H 0x00040003 > +#define BCM2835_MBOX_TAG_TEST_PHYSICAL_W_H 0x00044003 > +#define BCM2835_MBOX_TAG_SET_PHYSICAL_W_H 0x00048003 > + > +struct bcm2835_mbox_tag_physical_w_h { > + struct bcm2835_mbox_tag_hdr tag_hdr; > + union { > + /* req not used for get */ > + struct { > + u32 width; > + u32 height; > + } req; > + struct { > + u32 width; > + u32 height; > + } resp; > + } body; > +}; > + > +/* Virtual means display buffer */ > +#define BCM2835_MBOX_TAG_GET_VIRTUAL_W_H 0x00040004 > +#define BCM2835_MBOX_TAG_TEST_VIRTUAL_W_H 0x00044004 > +#define BCM2835_MBOX_TAG_SET_VIRTUAL_W_H 0x00048004 > + > +struct bcm2835_mbox_tag_virtual_w_h { > + struct bcm2835_mbox_tag_hdr tag_hdr; > + union { > + /* req not used for get */ > + struct { > + u32 width; > + u32 height; > + } req; > + struct { > + u32 width; > + u32 height; > + } resp; > + } body; > +}; > + > +#define BCM2835_MBOX_TAG_GET_DEPTH 0x00040005 > +#define BCM2835_MBOX_TAG_TEST_DEPTH 0x00044005 > +#define BCM2835_MBOX_TAG_SET_DEPTH 0x00048005 > + > +struct bcm2835_mbox_tag_depth { > + struct bcm2835_mbox_tag_hdr tag_hdr; > + union { > + /* req not used for get */ > + struct { > + u32 bpp; > + } req; > + struct { > + u32 bpp; > + } resp; > + } body; > +}; > + > +#define BCM2835_MBOX_TAG_GET_PIXEL_ORDER 0x00040006 > +#define BCM2835_MBOX_TAG_TEST_PIXEL_ORDER 0x00044005 > +#define BCM2835_MBOX_TAG_SET_PIXEL_ORDER 0x00048006 > + > +#define BCM2835_MBOX_PIXEL_ORDER_BGR 0 > +#define BCM2835_MBOX_PIXEL_ORDER_RGB 1 > + > +struct bcm2835_mbox_tag_pixel_order { > + struct bcm2835_mbox_tag_hdr tag_hdr; > + union { > + /* req not used for get */ > + struct { > + u32 order; > + } req; > + struct { > + u32 order; > + } resp; > + } body; > +}; > + > +#define BCM2835_MBOX_TAG_GET_ALPHA_MODE 0x00040007 > +#define BCM2835_MBOX_TAG_TEST_ALPHA_MODE 0x00044007 > +#define BCM2835_MBOX_TAG_SET_ALPHA_MODE 0x00048007 > + > +#define BCM2835_MBOX_ALPHA_MODE_0_OPAQUE 0 > +#define BCM2835_MBOX_ALPHA_MODE_0_TRANSPARENT 1 > +#define BCM2835_MBOX_ALPHA_MODE_IGNORED 2 > + > +struct bcm2835_mbox_tag_alpha_mode { > + struct bcm2835_mbox_tag_hdr tag_hdr; > + union { > + /* req not used for get */ > + struct { > + u32 alpha; > + } req; > + struct { > + u32 alpha; > + } resp; > + } body; > +}; > + > +#define BCM2835_MBOX_TAG_GET_PITCH 0x00040008 > + > +struct bcm2835_mbox_tag_pitch { > + struct bcm2835_mbox_tag_hdr tag_hdr; > + union { > + struct { > + } req; > + struct { > + u32 pitch; > + } resp; > + } body; > +}; > + > +/* Offset of display window within buffer */ > +#define BCM2835_MBOX_TAG_GET_VIRTUAL_OFFSET 0x00040009 > +#define BCM2835_MBOX_TAG_TEST_VIRTUAL_OFFSET 0x00044009 > +#define BCM2835_MBOX_TAG_SET_VIRTUAL_OFFSET 0x00048009 > + > +struct bcm2835_mbox_tag_virtual_offset { > + struct bcm2835_mbox_tag_hdr tag_hdr; > + union { > + /* req not used for get */ > + struct { > + u32 x; > + u32 y; > + } req; > + struct { > + u32 x; > + u32 y; > + } resp; > + } body; > +}; > + > +#define BCM2835_MBOX_TAG_GET_OVERSCAN 0x0004000a > +#define BCM2835_MBOX_TAG_TEST_OVERSCAN 0x0004400a > +#define BCM2835_MBOX_TAG_SET_OVERSCAN 0x0004800a > + > +struct bcm2835_mbox_tag_overscan { > + struct bcm2835_mbox_tag_hdr tag_hdr; > + union { > + /* req not used for get */ > + struct { > + u32 top; > + u32 bottom; > + u32 left; > + u32 right; > + } req; > + struct { > + u32 top; > + u32 bottom; > + u32 left; > + } resp; > + } body; > +}; > + > +#define BCM2835_MBOX_TAG_GET_PALETTE 0x0004000b > + > +struct bcm2835_mbox_tag_get_palette { > + struct bcm2835_mbox_tag_hdr tag_hdr; > + union { > + struct { > + } req; > + struct { > + u32 data[1024]; > + } resp; > + } body; > +}; > + > +#define BCM2835_MBOX_TAG_TEST_PALETTE 0x0004400b > + > +struct bcm2835_mbox_tag_test_palette { > + struct bcm2835_mbox_tag_hdr tag_hdr; > + union { > + struct { > + u32 offset; > + u32 num_entries; > + u32 data[256]; > + } req; > + struct { > + u32 is_invalid; > + } resp; > + } body; > +}; > + > +#define BCM2835_MBOX_TAG_SET_PALETTE 0x0004800b > + > +struct bcm2835_mbox_tag_set_palette { > + struct bcm2835_mbox_tag_hdr tag_hdr; > + union { > + struct { > + u32 offset; > + u32 num_entries; > + u32 data[256]; > + } req; > + struct { > + u32 is_invalid; > + } resp; > + } body; > +}; > + > +/* > + * Pass a raw u32 message to the VC, and receive a raw u32 back. > + * > + * Returns 0 for success, any other value for error. > + */ > +int bcm2835_mbox_call_raw(u32 chan, u32 send, u32 *recv); > + > +/* > + * Pass a complete property-style buffer to the VC, and wait until it has > + * been processed. > + * > + * This function expects a pointer to the mbox_hdr structure in an attempt > + * to ensure some degree of type safety. However, some number of tags and > + * a termination value are expected to immediately follow the header in > + * memory, as required by the property protocol. > + * > + * Returns 0 for success, any other value for error. > + */ > +int bcm2835_mbox_call_prop(u32 chan, struct bcm2835_mbox_hdr *buffer); > + > +#endif Cc: Anatolij as the video custodian. 2 of the 4 commits in this patch set are ARM related, 2 are video related. Anatolij, if you ack the last two, I can pull the whole series in ARM directly. Amicalement, -- Albert. _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot