summaryrefslogtreecommitdiffstats
path: root/sys/arm/broadcom/bcm2835/bcm2835_mbox.c
diff options
context:
space:
mode:
authorandrew <andrew@FreeBSD.org>2015-03-20 16:54:21 +0000
committerandrew <andrew@FreeBSD.org>2015-03-20 16:54:21 +0000
commit778929f2cccf19c8b69d8bcd0da2243bf9e3fb95 (patch)
tree2be4cd347b9c86751b397d70b5194de5219145fb /sys/arm/broadcom/bcm2835/bcm2835_mbox.c
parent54b9845962ee172059fcff65bb911e42fbd4607b (diff)
downloadFreeBSD-src-778929f2cccf19c8b69d8bcd0da2243bf9e3fb95.zip
FreeBSD-src-778929f2cccf19c8b69d8bcd0da2243bf9e3fb95.tar.gz
Add a helper function to read clock frequencies from videocore and use this
to get the default frequency of the sdhci device. While here use a u_int to hold the frequency as it may be too large to fit in a 32-bit signed integer. This is the case when we have a 250MHz clock.
Diffstat (limited to 'sys/arm/broadcom/bcm2835/bcm2835_mbox.c')
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_mbox.c117
1 files changed, 88 insertions, 29 deletions
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_mbox.c b/sys/arm/broadcom/bcm2835/bcm2835_mbox.c
index 1dd2cc9..2ab7ebf 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_mbox.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_mbox.c
@@ -284,53 +284,63 @@ bcm2835_mbox_dma_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
*addr = PHYS_TO_VCBUS(segs[0].ds_addr);
}
-int
-bcm2835_mbox_set_power_state(device_t dev, uint32_t device_id, boolean_t on)
+static void *
+bcm2835_mbox_init_dma(device_t dev, size_t len, bus_dma_tag_t *tag,
+ bus_dmamap_t *map, bus_addr_t *phys)
{
- struct msg_set_power_state *msg;
- bus_dma_tag_t msg_tag;
- bus_dmamap_t msg_map;
- bus_addr_t msg_phys;
- void *msg_buf;
- uint32_t reg;
- device_t mbox;
+ void *buf;
int err;
- /* get mbox device */
- mbox = devclass_get_device(devclass_find("mbox"), 0);
- if (mbox == NULL) {
- device_printf(dev, "can't find mbox\n");
- return (ENXIO);
- }
-
err = bus_dma_tag_create(bus_get_dma_tag(dev), 16, 0,
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
- sizeof(struct msg_set_power_state), 1,
- sizeof(struct msg_set_power_state), 0,
- NULL, NULL, &msg_tag);
+ len, 1, len, 0, NULL, NULL, tag);
if (err != 0) {
device_printf(dev, "can't create DMA tag\n");
- return (ENXIO);
+ return (NULL);
}
- err = bus_dmamem_alloc(msg_tag, (void **)&msg_buf, 0, &msg_map);
+ err = bus_dmamem_alloc(*tag, &buf, 0, map);
if (err != 0) {
- bus_dma_tag_destroy(msg_tag);
+ bus_dma_tag_destroy(*tag);
device_printf(dev, "can't allocate dmamem\n");
- return (ENXIO);
+ return (NULL);
}
- err = bus_dmamap_load(msg_tag, msg_map, msg_buf,
+ err = bus_dmamap_load(*tag, *map, buf,
sizeof(struct msg_set_power_state), bcm2835_mbox_dma_cb,
- &msg_phys, 0);
+ phys, 0);
if (err != 0) {
- bus_dmamem_free(msg_tag, msg_buf, msg_map);
- bus_dma_tag_destroy(msg_tag);
+ bus_dmamem_free(*tag, buf, *map);
+ bus_dma_tag_destroy(*tag);
device_printf(dev, "can't load DMA map\n");
+ return (NULL);
+ }
+
+ return (buf);
+}
+
+int
+bcm2835_mbox_set_power_state(device_t dev, uint32_t device_id, boolean_t on)
+{
+ struct msg_set_power_state *msg;
+ bus_dma_tag_t msg_tag;
+ bus_dmamap_t msg_map;
+ bus_addr_t msg_phys;
+ uint32_t reg;
+ device_t mbox;
+
+ /* get mbox device */
+ mbox = devclass_get_device(devclass_find("mbox"), 0);
+ if (mbox == NULL) {
+ device_printf(dev, "can't find mbox\n");
return (ENXIO);
}
- msg = msg_buf;
+ /* 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);
@@ -350,7 +360,56 @@ bcm2835_mbox_set_power_state(device_t dev, uint32_t device_id, boolean_t on)
MBOX_READ(mbox, BCM2835_MBOX_CHAN_PROP, &reg);
bus_dmamap_unload(msg_tag, msg_map);
- bus_dmamem_free(msg_tag, msg_buf, msg_map);
+ bus_dmamem_free(msg_tag, msg, msg_map);
+ bus_dma_tag_destroy(msg_tag);
+
+ return (0);
+}
+
+int
+bcm2835_mbox_get_clock_rate(device_t dev, uint32_t clock_id, uint32_t *hz)
+{
+ struct msg_get_clock_rate *msg;
+ bus_dma_tag_t msg_tag;
+ bus_dmamap_t msg_map;
+ bus_addr_t msg_phys;
+ uint32_t reg;
+ device_t mbox;
+
+ /* 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;
+ msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_CLOCK_RATE;
+ msg->tag_hdr.val_buf_size = sizeof(msg->body);
+ msg->tag_hdr.val_len = sizeof(msg->body.req);
+ msg->body.req.clock_id = clock_id;
+ 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);
+
+ *hz = msg->body.resp.rate_hz;
+
+ bus_dmamap_unload(msg_tag, msg_map);
+ bus_dmamem_free(msg_tag, msg, msg_map);
bus_dma_tag_destroy(msg_tag);
return (0);
OpenPOWER on IntegriCloud