diff options
Diffstat (limited to 'arch')
| -rw-r--r-- | arch/arm/cpu/arm1176/bcm2835/Makefile | 2 | ||||
| -rw-r--r-- | arch/arm/cpu/arm1176/bcm2835/mbox.c | 164 | ||||
| -rw-r--r-- | arch/arm/include/asm/arch-bcm2835/mbox.h | 407 | 
3 files changed, 572 insertions, 1 deletions
| diff --git a/arch/arm/cpu/arm1176/bcm2835/Makefile b/arch/arm/cpu/arm1176/bcm2835/Makefile index 95da6a822..135de42d3 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 000000000..fd65e3387 --- /dev/null +++ b/arch/arm/cpu/arm1176/bcm2835/mbox.c @@ -0,0 +1,164 @@ +/* + * (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 as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * 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 000000000..4752091b9 --- /dev/null +++ b/arch/arm/include/asm/arch-bcm2835/mbox.h @@ -0,0 +1,407 @@ +/* + * (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 as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * 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 |