Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 2 May 2015 22:24:34 +0000 (UTC)
From:      Luiz Otavio O Souza <loos@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r282357 - head/sys/arm/broadcom/bcm2835
Message-ID:  <201505022224.t42MOYM8036944@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: loos
Date: Sat May  2 22:24:33 2015
New Revision: 282357
URL: https://svnweb.freebsd.org/changeset/base/282357

Log:
  Add the routines to query and setup the framebuffer state using the
  BCM2835_MBOX_CHAN_PROP channel.  The old channel (BCM2835_MBOX_CHAN_FB)
  seems deprecated on recent firmware versions and is causing a freeze on
  RPi 2.
  
  The actual changes in the framebuffer drivers will follow in subsequent
  commits.

Modified:
  head/sys/arm/broadcom/bcm2835/bcm2835_mbox.c
  head/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h

Modified: head/sys/arm/broadcom/bcm2835/bcm2835_mbox.c
==============================================================================
--- head/sys/arm/broadcom/bcm2835/bcm2835_mbox.c	Sat May  2 20:41:49 2015	(r282356)
+++ head/sys/arm/broadcom/bcm2835/bcm2835_mbox.c	Sat May  2 22:24:33 2015	(r282357)
@@ -318,6 +318,47 @@ bcm2835_mbox_init_dma(device_t dev, size
 	return (buf);
 }
 
+static int
+bcm2835_mbox_err(device_t dev, bus_addr_t msg_phys, uint32_t resp_phys,
+	struct bcm2835_mbox_hdr *msg, size_t len)
+{
+	int idx;
+	struct bcm2835_mbox_tag_hdr *tag;
+	uint8_t *last;
+
+	if ((uint32_t)msg_phys != resp_phys) {
+		device_printf(dev, "response channel mismatch\n");
+		return (EIO);
+	}
+	if (msg->code != BCM2835_MBOX_CODE_RESP_SUCCESS) {
+		device_printf(dev, "mbox response error\n");
+		return (EIO);
+	}
+
+	/* Loop until the end tag. */
+	tag = (struct bcm2835_mbox_tag_hdr *)(msg + 1);
+	last = (uint8_t *)msg + len;
+	for (idx = 0; tag->tag != 0; idx++) {
+		if ((tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE) == 0) {
+			device_printf(dev, "tag %d response error\n", idx);
+			return (EIO);
+		}
+		/* Clear the response bit. */
+		tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE;
+
+		/* Next tag. */
+		tag = (struct bcm2835_mbox_tag_hdr *)((uint8_t *)tag +
+		    sizeof(*tag) + tag->val_buf_size);
+
+		if ((uint8_t *)tag > last) {
+			device_printf(dev, "mbox buffer size error\n");
+			return (EIO);
+		}
+	}
+
+	return (0);
+}
+
 int
 bcm2835_mbox_set_power_state(device_t dev, uint32_t device_id, boolean_t on)
 {
@@ -413,3 +454,136 @@ bcm2835_mbox_get_clock_rate(device_t dev
 
 	return (0);
 }
+
+int
+bcm2835_mbox_fb_get_w_h(device_t dev, struct bcm2835_fb_config *fb)
+{
+	device_t mbox;
+	int err;
+	bus_dma_tag_t msg_tag;
+	bus_dmamap_t msg_map;
+	bus_addr_t msg_phys;
+	struct msg_fb_get_w_h *msg;
+	uint32_t reg;
+
+	/* get mbox device */
+	mbox = devclass_get_device(devclass_find("mbox"), 0);
+	if (mbox == NULL) {
+		device_printf(dev, "can't find mbox\n");
+		return (ENXIO);
+	}
+
+	/* Allocate memory for the message */
+	msg = bcm2835_mbox_init_dma(dev, sizeof(*msg), &msg_tag, &msg_map,
+	    &msg_phys);
+	if (msg == NULL)
+		return (ENOMEM);
+
+	memset(msg, 0, sizeof(*msg));
+	msg->hdr.buf_size = sizeof(*msg);
+	msg->hdr.code = BCM2835_MBOX_CODE_REQ;
+	BCM2835_MBOX_INIT_TAG(&msg->physical_w_h, GET_PHYSICAL_W_H);
+	msg->physical_w_h.tag_hdr.val_len = 0;
+	BCM2835_MBOX_INIT_TAG(&msg->virtual_w_h, GET_VIRTUAL_W_H);
+	msg->virtual_w_h.tag_hdr.val_len = 0;
+	BCM2835_MBOX_INIT_TAG(&msg->offset, GET_VIRTUAL_OFFSET);
+	msg->offset.tag_hdr.val_len = 0;
+	msg->end_tag = 0;
+
+	bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_PREWRITE);
+	MBOX_WRITE(mbox, BCM2835_MBOX_CHAN_PROP, (uint32_t)msg_phys);
+	bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_POSTWRITE);
+
+	bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_PREREAD);
+	MBOX_READ(mbox, BCM2835_MBOX_CHAN_PROP, &reg);
+	bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_POSTREAD);
+
+	err = bcm2835_mbox_err(dev, msg_phys, reg, &msg->hdr, sizeof(*msg));
+	if (err == 0) {
+		fb->xres = msg->physical_w_h.body.resp.width;
+		fb->yres = msg->physical_w_h.body.resp.height;
+		fb->vxres = msg->virtual_w_h.body.resp.width;
+		fb->vyres = msg->virtual_w_h.body.resp.height;
+		fb->xoffset = msg->offset.body.resp.x;
+		fb->yoffset = msg->offset.body.resp.y;
+	}
+
+	bus_dmamap_unload(msg_tag, msg_map);
+	bus_dmamem_free(msg_tag, msg, msg_map);
+	bus_dma_tag_destroy(msg_tag);
+
+	return (err);
+}
+
+int
+bcm2835_mbox_fb_init(device_t dev, struct bcm2835_fb_config *fb)
+{
+	device_t mbox;
+	int err;
+	bus_dma_tag_t msg_tag;
+	bus_dmamap_t msg_map;
+	bus_addr_t msg_phys;
+	struct msg_fb_setup *msg;
+	uint32_t reg;
+
+	/* get mbox device */
+	mbox = devclass_get_device(devclass_find("mbox"), 0);
+	if (mbox == NULL) {
+		device_printf(dev, "can't find mbox\n");
+		return (ENXIO);
+	}
+
+	/* Allocate memory for the message */
+	msg = bcm2835_mbox_init_dma(dev, sizeof(*msg), &msg_tag, &msg_map,
+	    &msg_phys);
+	if (msg == NULL)
+		return (ENOMEM);
+
+	memset(msg, 0, sizeof(*msg));
+	msg->hdr.buf_size = sizeof(*msg);
+	msg->hdr.code = BCM2835_MBOX_CODE_REQ;
+	BCM2835_MBOX_INIT_TAG(&msg->physical_w_h, SET_PHYSICAL_W_H);
+	msg->physical_w_h.body.req.width = fb->xres;
+	msg->physical_w_h.body.req.height = fb->yres;
+	BCM2835_MBOX_INIT_TAG(&msg->virtual_w_h, SET_VIRTUAL_W_H);
+	msg->virtual_w_h.body.req.width = fb->vxres;
+	msg->virtual_w_h.body.req.height = fb->vyres;
+	BCM2835_MBOX_INIT_TAG(&msg->offset, GET_VIRTUAL_OFFSET);
+	msg->offset.body.req.x = fb->xoffset;
+	msg->offset.body.req.y = fb->yoffset;
+	BCM2835_MBOX_INIT_TAG(&msg->depth, SET_DEPTH);
+	msg->depth.body.req.bpp = fb->bpp;
+	BCM2835_MBOX_INIT_TAG(&msg->alpha, SET_ALPHA_MODE);
+	msg->alpha.body.req.alpha = BCM2835_MBOX_ALPHA_MODE_IGNORED;
+	BCM2835_MBOX_INIT_TAG(&msg->buffer, ALLOCATE_BUFFER);
+	msg->buffer.body.req.alignment = PAGE_SIZE;
+	BCM2835_MBOX_INIT_TAG(&msg->pitch, GET_PITCH);
+	msg->end_tag = 0;
+
+	bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_PREWRITE);
+	MBOX_WRITE(mbox, BCM2835_MBOX_CHAN_PROP, (uint32_t)msg_phys);
+	bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_POSTWRITE);
+
+	bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_PREREAD);
+	MBOX_READ(mbox, BCM2835_MBOX_CHAN_PROP, &reg);
+	bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_POSTREAD);
+
+	err = bcm2835_mbox_err(dev, msg_phys, reg, &msg->hdr, sizeof(*msg));
+	if (err == 0) {
+		fb->xres = msg->physical_w_h.body.resp.width;
+		fb->yres = msg->physical_w_h.body.resp.height;
+		fb->vxres = msg->virtual_w_h.body.resp.width;
+		fb->vyres = msg->virtual_w_h.body.resp.height;
+		fb->xoffset = msg->offset.body.resp.x;
+		fb->yoffset = msg->offset.body.resp.y;
+		fb->pitch = msg->pitch.body.resp.pitch;
+		fb->base = msg->buffer.body.resp.fb_address;
+		fb->size = msg->buffer.body.resp.fb_size;
+	}
+
+	bus_dmamap_unload(msg_tag, msg_map);
+	bus_dmamem_free(msg_tag, msg, msg_map);
+	bus_dma_tag_destroy(msg_tag);
+
+	return (err);
+}

Modified: head/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h
==============================================================================
--- head/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h	Sat May  2 20:41:49 2015	(r282356)
+++ head/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h	Sat May  2 22:24:33 2015	(r282357)
@@ -52,6 +52,12 @@ struct bcm2835_mbox_tag_hdr {
 	uint32_t	val_len;
 };
 
+#define	BCM2835_MBOX_INIT_TAG(tag_, tagid_) do {		\
+	(tag_)->tag_hdr.tag = BCM2835_MBOX_TAG_##tagid_;	\
+	(tag_)->tag_hdr.val_buf_size = sizeof((tag_)->body);	\
+	(tag_)->tag_hdr.val_len = sizeof((tag_)->body.req);	\
+} while (0)
+
 #define BCM2835_MBOX_POWER_ID_EMMC		0x00000000
 #define BCM2835_MBOX_POWER_ID_UART0		0x00000001
 #define BCM2835_MBOX_POWER_ID_UART1		0x00000002
@@ -322,4 +328,151 @@ struct msg_get_max_temperature {
 	uint32_t end_tag;
 };
 
+#define	BCM2835_MBOX_TAG_GET_PHYSICAL_W_H	0x00040003
+#define	BCM2835_MBOX_TAG_SET_PHYSICAL_W_H	0x00048003
+#define	BCM2835_MBOX_TAG_GET_VIRTUAL_W_H	0x00040004
+#define	BCM2835_MBOX_TAG_SET_VIRTUAL_W_H	0x00048004
+
+struct bcm2835_mbox_tag_fb_w_h {
+	struct bcm2835_mbox_tag_hdr tag_hdr;
+	union {
+		struct {
+			uint32_t width;
+			uint32_t height;
+		} req;
+		struct {
+			uint32_t width;
+			uint32_t height;
+		} resp;
+	} body;
+};
+
+#define	BCM2835_MBOX_TAG_GET_DEPTH		0x00040005
+#define	BCM2835_MBOX_TAG_SET_DEPTH		0x00048005
+
+struct bcm2835_mbox_tag_depth {
+	struct bcm2835_mbox_tag_hdr tag_hdr;
+	union {
+		struct {
+			uint32_t bpp;
+		} req;
+		struct {
+			uint32_t bpp;
+		} resp;
+	} body;
+};
+
+#define	BCM2835_MBOX_TAG_GET_ALPHA_MODE		0x00040007
+#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 {
+		struct {
+			uint32_t alpha;
+		} req;
+		struct {
+			uint32_t alpha;
+		} resp;
+	} body;
+};
+
+#define	BCM2835_MBOX_TAG_GET_VIRTUAL_OFFSET	0x00040009
+#define	BCM2835_MBOX_TAG_SET_VIRTUAL_OFFSET	0x00048009
+
+struct bcm2835_mbox_tag_virtual_offset {
+	struct bcm2835_mbox_tag_hdr tag_hdr;
+	union {
+		struct {
+			uint32_t x;
+			uint32_t y;
+		} req;
+		struct {
+			uint32_t x;
+			uint32_t y;
+		} 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 {
+			uint32_t pitch;
+		} resp;
+	} body;
+};
+
+#define	BCM2835_MBOX_TAG_ALLOCATE_BUFFER	0x00040001
+
+struct bcm2835_mbox_tag_allocate_buffer {
+	struct bcm2835_mbox_tag_hdr tag_hdr;
+	union {
+		struct {
+			uint32_t alignment;
+		} req;
+		struct {
+			uint32_t fb_address;
+			uint32_t 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;
+};
+
+struct bcm2835_fb_config {
+	uint32_t xres;
+	uint32_t yres;
+	uint32_t vxres;
+	uint32_t vyres;
+	uint32_t xoffset;
+	uint32_t yoffset;
+	uint32_t bpp;
+	uint32_t pitch;
+	uint32_t base;
+	uint32_t size;
+};
+
+struct msg_fb_get_w_h {
+	struct bcm2835_mbox_hdr hdr;
+	struct bcm2835_mbox_tag_fb_w_h physical_w_h;
+	struct bcm2835_mbox_tag_fb_w_h virtual_w_h;
+	struct bcm2835_mbox_tag_virtual_offset offset;
+	uint32_t end_tag;
+};
+
+int bcm2835_mbox_fb_get_w_h(device_t, struct bcm2835_fb_config *);
+
+struct msg_fb_setup {
+	struct bcm2835_mbox_hdr hdr;
+	struct bcm2835_mbox_tag_fb_w_h physical_w_h;
+	struct bcm2835_mbox_tag_fb_w_h virtual_w_h;
+	struct bcm2835_mbox_tag_virtual_offset offset;
+	struct bcm2835_mbox_tag_depth depth;
+	struct bcm2835_mbox_tag_alpha_mode alpha;
+	struct bcm2835_mbox_tag_allocate_buffer buffer;
+	struct bcm2835_mbox_tag_pitch pitch;
+	uint32_t end_tag;
+};
+
+int bcm2835_mbox_fb_init(device_t, struct bcm2835_fb_config *);
+
 #endif /* _BCM2835_MBOX_PROP_H_ */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201505022224.t42MOYM8036944>