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_ */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to