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:
parent
f6c05535af
commit
ae29e2d8a4
@ -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, ®);
|
||||
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, ®);
|
||||
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);
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user