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.
This commit is contained in:
Luiz Otavio O Souza 2015-05-02 22:24:33 +00:00
parent f6c05535af
commit ae29e2d8a4
2 changed files with 327 additions and 0 deletions

View File

@ -318,6 +318,47 @@ bcm2835_mbox_init_dma(device_t dev, size_t len, bus_dma_tag_t *tag,
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, uint32_t clock_id, uint32_t *hz)
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);
}

View File

@ -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_ */