11b1a53cfSOleksandr Tymoshenko /*- 21b1a53cfSOleksandr Tymoshenko * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org> 31b1a53cfSOleksandr Tymoshenko * All rights reserved. 41b1a53cfSOleksandr Tymoshenko * 51b1a53cfSOleksandr Tymoshenko * Redistribution and use in source and binary forms, with or without 61b1a53cfSOleksandr Tymoshenko * modification, are permitted provided that the following conditions 71b1a53cfSOleksandr Tymoshenko * are met: 81b1a53cfSOleksandr Tymoshenko * 1. Redistributions of source code must retain the above copyright 91b1a53cfSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer. 101b1a53cfSOleksandr Tymoshenko * 2. Redistributions in binary form must reproduce the above copyright 111b1a53cfSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer in the 121b1a53cfSOleksandr Tymoshenko * documentation and/or other materials provided with the distribution. 131b1a53cfSOleksandr Tymoshenko * 141b1a53cfSOleksandr Tymoshenko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 151b1a53cfSOleksandr Tymoshenko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161b1a53cfSOleksandr Tymoshenko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171b1a53cfSOleksandr Tymoshenko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 181b1a53cfSOleksandr Tymoshenko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191b1a53cfSOleksandr Tymoshenko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201b1a53cfSOleksandr Tymoshenko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211b1a53cfSOleksandr Tymoshenko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221b1a53cfSOleksandr Tymoshenko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231b1a53cfSOleksandr Tymoshenko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241b1a53cfSOleksandr Tymoshenko * SUCH DAMAGE. 251b1a53cfSOleksandr Tymoshenko */ 261b1a53cfSOleksandr Tymoshenko 271b1a53cfSOleksandr Tymoshenko #include <sys/cdefs.h> 281b1a53cfSOleksandr Tymoshenko __FBSDID("$FreeBSD$"); 291b1a53cfSOleksandr Tymoshenko 301b1a53cfSOleksandr Tymoshenko #include <sys/param.h> 311b1a53cfSOleksandr Tymoshenko #include <sys/systm.h> 321b1a53cfSOleksandr Tymoshenko #include <sys/bus.h> 331b1a53cfSOleksandr Tymoshenko #include <sys/kernel.h> 3409df4bfdSLuiz Otavio O Souza #include <sys/lock.h> 351b1a53cfSOleksandr Tymoshenko #include <sys/module.h> 3609df4bfdSLuiz Otavio O Souza #include <sys/mutex.h> 371b1a53cfSOleksandr Tymoshenko #include <sys/rman.h> 38b9450e43SRui Paulo #include <sys/sema.h> 391b1a53cfSOleksandr Tymoshenko #include <machine/bus.h> 401b1a53cfSOleksandr Tymoshenko 411b1a53cfSOleksandr Tymoshenko #include <dev/ofw/ofw_bus.h> 421b1a53cfSOleksandr Tymoshenko #include <dev/ofw/ofw_bus_subr.h> 431b1a53cfSOleksandr Tymoshenko 441b1a53cfSOleksandr Tymoshenko #include <arm/broadcom/bcm2835/bcm2835_mbox.h> 45b812d0adSAndrew Turner #include <arm/broadcom/bcm2835/bcm2835_mbox_prop.h> 46b812d0adSAndrew Turner #include <arm/broadcom/bcm2835/bcm2835_vcbus.h> 471b1a53cfSOleksandr Tymoshenko 48279cd101SRui Paulo #include "mbox_if.h" 49279cd101SRui Paulo 501b1a53cfSOleksandr Tymoshenko #define REG_READ 0x00 511b1a53cfSOleksandr Tymoshenko #define REG_POL 0x10 521b1a53cfSOleksandr Tymoshenko #define REG_SENDER 0x14 531b1a53cfSOleksandr Tymoshenko #define REG_STATUS 0x18 541b1a53cfSOleksandr Tymoshenko #define STATUS_FULL 0x80000000 551b1a53cfSOleksandr Tymoshenko #define STATUS_EMPTY 0x40000000 561b1a53cfSOleksandr Tymoshenko #define REG_CONFIG 0x1C 571b1a53cfSOleksandr Tymoshenko #define CONFIG_DATA_IRQ 0x00000001 581b1a53cfSOleksandr Tymoshenko #define REG_WRITE 0x20 /* This is Mailbox 1 address */ 591b1a53cfSOleksandr Tymoshenko 601b1a53cfSOleksandr Tymoshenko #define MBOX_MSG(chan, data) (((data) & ~0xf) | ((chan) & 0xf)) 611b1a53cfSOleksandr Tymoshenko #define MBOX_CHAN(msg) ((msg) & 0xf) 621b1a53cfSOleksandr Tymoshenko #define MBOX_DATA(msg) ((msg) & ~0xf) 631b1a53cfSOleksandr Tymoshenko 64279cd101SRui Paulo #define MBOX_LOCK(sc) do { \ 65279cd101SRui Paulo mtx_lock(&(sc)->lock); \ 661b1a53cfSOleksandr Tymoshenko } while(0) 671b1a53cfSOleksandr Tymoshenko 68279cd101SRui Paulo #define MBOX_UNLOCK(sc) do { \ 69279cd101SRui Paulo mtx_unlock(&(sc)->lock); \ 701b1a53cfSOleksandr Tymoshenko } while(0) 711b1a53cfSOleksandr Tymoshenko 721b1a53cfSOleksandr Tymoshenko #ifdef DEBUG 731b1a53cfSOleksandr Tymoshenko #define dprintf(fmt, args...) printf(fmt, ##args) 741b1a53cfSOleksandr Tymoshenko #else 751b1a53cfSOleksandr Tymoshenko #define dprintf(fmt, args...) 761b1a53cfSOleksandr Tymoshenko #endif 771b1a53cfSOleksandr Tymoshenko 781b1a53cfSOleksandr Tymoshenko struct bcm_mbox_softc { 791b1a53cfSOleksandr Tymoshenko struct mtx lock; 801b1a53cfSOleksandr Tymoshenko struct resource * mem_res; 811b1a53cfSOleksandr Tymoshenko struct resource * irq_res; 821b1a53cfSOleksandr Tymoshenko void* intr_hl; 831b1a53cfSOleksandr Tymoshenko bus_space_tag_t bst; 841b1a53cfSOleksandr Tymoshenko bus_space_handle_t bsh; 851b1a53cfSOleksandr Tymoshenko int msg[BCM2835_MBOX_CHANS]; 86b9450e43SRui Paulo struct sema sema[BCM2835_MBOX_CHANS]; 871b1a53cfSOleksandr Tymoshenko }; 881b1a53cfSOleksandr Tymoshenko 89279cd101SRui Paulo #define mbox_read_4(sc, reg) \ 90279cd101SRui Paulo bus_space_read_4((sc)->bst, (sc)->bsh, reg) 91279cd101SRui Paulo #define mbox_write_4(sc, reg, val) \ 92279cd101SRui Paulo bus_space_write_4((sc)->bst, (sc)->bsh, reg, val) 931b1a53cfSOleksandr Tymoshenko 94d792cd92SAndrew Turner static int 95d792cd92SAndrew Turner bcm_mbox_read_msg(struct bcm_mbox_softc *sc, int *ochan) 961b1a53cfSOleksandr Tymoshenko { 971b1a53cfSOleksandr Tymoshenko uint32_t data; 981b1a53cfSOleksandr Tymoshenko uint32_t msg; 99d792cd92SAndrew Turner int chan; 1001b1a53cfSOleksandr Tymoshenko 101279cd101SRui Paulo msg = mbox_read_4(sc, REG_READ); 1021b1a53cfSOleksandr Tymoshenko dprintf("bcm_mbox_intr: raw data %08x\n", msg); 1031b1a53cfSOleksandr Tymoshenko chan = MBOX_CHAN(msg); 1041b1a53cfSOleksandr Tymoshenko data = MBOX_DATA(msg); 105b9450e43SRui Paulo if (sc->msg[chan]) { 1061b1a53cfSOleksandr Tymoshenko printf("bcm_mbox_intr: channel %d oveflow\n", chan); 107d792cd92SAndrew Turner return (1); 1081b1a53cfSOleksandr Tymoshenko } 1091b1a53cfSOleksandr Tymoshenko dprintf("bcm_mbox_intr: chan %d, data %08x\n", chan, data); 1101432fa20SLuiz Otavio O Souza sc->msg[chan] = msg; 111d792cd92SAndrew Turner 112d792cd92SAndrew Turner if (ochan != NULL) 113d792cd92SAndrew Turner *ochan = chan; 114d792cd92SAndrew Turner 115d792cd92SAndrew Turner return (0); 1161b1a53cfSOleksandr Tymoshenko } 117d792cd92SAndrew Turner 118d792cd92SAndrew Turner static void 119d792cd92SAndrew Turner bcm_mbox_intr(void *arg) 120d792cd92SAndrew Turner { 121d792cd92SAndrew Turner struct bcm_mbox_softc *sc = arg; 122d792cd92SAndrew Turner int chan; 123d792cd92SAndrew Turner 124d792cd92SAndrew Turner while (!(mbox_read_4(sc, REG_STATUS) & STATUS_EMPTY)) 125d792cd92SAndrew Turner if (bcm_mbox_read_msg(sc, &chan) == 0) 126d792cd92SAndrew Turner sema_post(&sc->sema[chan]); 1271b1a53cfSOleksandr Tymoshenko } 1281b1a53cfSOleksandr Tymoshenko 1291b1a53cfSOleksandr Tymoshenko static int 1301b1a53cfSOleksandr Tymoshenko bcm_mbox_probe(device_t dev) 1311b1a53cfSOleksandr Tymoshenko { 1321b1a53cfSOleksandr Tymoshenko 133add35ed5SIan Lepore if (!ofw_bus_status_okay(dev)) 134add35ed5SIan Lepore return (ENXIO); 135add35ed5SIan Lepore 1361b1a53cfSOleksandr Tymoshenko if (ofw_bus_is_compatible(dev, "broadcom,bcm2835-mbox")) { 1371b1a53cfSOleksandr Tymoshenko device_set_desc(dev, "BCM2835 VideoCore Mailbox"); 1381b1a53cfSOleksandr Tymoshenko return(BUS_PROBE_DEFAULT); 1391b1a53cfSOleksandr Tymoshenko } 1401b1a53cfSOleksandr Tymoshenko 1411b1a53cfSOleksandr Tymoshenko return (ENXIO); 1421b1a53cfSOleksandr Tymoshenko } 1431b1a53cfSOleksandr Tymoshenko 1441b1a53cfSOleksandr Tymoshenko static int 1451b1a53cfSOleksandr Tymoshenko bcm_mbox_attach(device_t dev) 1461b1a53cfSOleksandr Tymoshenko { 1471b1a53cfSOleksandr Tymoshenko struct bcm_mbox_softc *sc = device_get_softc(dev); 1481b1a53cfSOleksandr Tymoshenko int i; 1491b1a53cfSOleksandr Tymoshenko int rid = 0; 1501b1a53cfSOleksandr Tymoshenko 1511b1a53cfSOleksandr Tymoshenko sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 1521b1a53cfSOleksandr Tymoshenko if (sc->mem_res == NULL) { 1531b1a53cfSOleksandr Tymoshenko device_printf(dev, "could not allocate memory resource\n"); 1541b1a53cfSOleksandr Tymoshenko return (ENXIO); 1551b1a53cfSOleksandr Tymoshenko } 1561b1a53cfSOleksandr Tymoshenko 1571b1a53cfSOleksandr Tymoshenko sc->bst = rman_get_bustag(sc->mem_res); 1581b1a53cfSOleksandr Tymoshenko sc->bsh = rman_get_bushandle(sc->mem_res); 1591b1a53cfSOleksandr Tymoshenko 1601b1a53cfSOleksandr Tymoshenko rid = 0; 1611b1a53cfSOleksandr Tymoshenko sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 1621b1a53cfSOleksandr Tymoshenko if (sc->irq_res == NULL) { 1631b1a53cfSOleksandr Tymoshenko device_printf(dev, "could not allocate interrupt resource\n"); 1641b1a53cfSOleksandr Tymoshenko return (ENXIO); 1651b1a53cfSOleksandr Tymoshenko } 1661b1a53cfSOleksandr Tymoshenko 1671b1a53cfSOleksandr Tymoshenko /* Setup and enable the timer */ 16895506b81SRui Paulo if (bus_setup_intr(dev, sc->irq_res, INTR_MPSAFE | INTR_TYPE_MISC, 16995506b81SRui Paulo NULL, bcm_mbox_intr, sc, &sc->intr_hl) != 0) { 17095506b81SRui Paulo bus_release_resource(dev, SYS_RES_IRQ, rid, sc->irq_res); 1711b1a53cfSOleksandr Tymoshenko device_printf(dev, "Unable to setup the clock irq handler.\n"); 1721b1a53cfSOleksandr Tymoshenko return (ENXIO); 1731b1a53cfSOleksandr Tymoshenko } 1741b1a53cfSOleksandr Tymoshenko 175d01195e3SChristian Brueffer mtx_init(&sc->lock, "vcio mbox", NULL, MTX_DEF); 1761b1a53cfSOleksandr Tymoshenko for (i = 0; i < BCM2835_MBOX_CHANS; i++) { 177b9450e43SRui Paulo sc->msg[i] = 0; 178b9450e43SRui Paulo sema_init(&sc->sema[i], 0, "mbox"); 1791b1a53cfSOleksandr Tymoshenko } 1801b1a53cfSOleksandr Tymoshenko 1811b1a53cfSOleksandr Tymoshenko /* Read all pending messages */ 1821432fa20SLuiz Otavio O Souza while ((mbox_read_4(sc, REG_STATUS) & STATUS_EMPTY) == 0) 1831432fa20SLuiz Otavio O Souza (void)mbox_read_4(sc, REG_READ); 1841b1a53cfSOleksandr Tymoshenko 185279cd101SRui Paulo mbox_write_4(sc, REG_CONFIG, CONFIG_DATA_IRQ); 186279cd101SRui Paulo 187279cd101SRui Paulo return (0); 188279cd101SRui Paulo } 189279cd101SRui Paulo 190279cd101SRui Paulo /* 191279cd101SRui Paulo * Mailbox API 192279cd101SRui Paulo */ 193279cd101SRui Paulo static int 194279cd101SRui Paulo bcm_mbox_write(device_t dev, int chan, uint32_t data) 195279cd101SRui Paulo { 19609df4bfdSLuiz Otavio O Souza int limit = 1000; 197279cd101SRui Paulo struct bcm_mbox_softc *sc = device_get_softc(dev); 198279cd101SRui Paulo 199279cd101SRui Paulo dprintf("bcm_mbox_write: chan %d, data %08x\n", chan, data); 200279cd101SRui Paulo MBOX_LOCK(sc); 20109df4bfdSLuiz Otavio O Souza while ((mbox_read_4(sc, REG_STATUS) & STATUS_FULL) && --limit) 20209df4bfdSLuiz Otavio O Souza DELAY(5); 203279cd101SRui Paulo if (limit == 0) { 204279cd101SRui Paulo printf("bcm_mbox_write: STATUS_FULL stuck"); 205279cd101SRui Paulo MBOX_UNLOCK(sc); 206279cd101SRui Paulo return (EAGAIN); 207279cd101SRui Paulo } 208279cd101SRui Paulo mbox_write_4(sc, REG_WRITE, MBOX_MSG(chan, data)); 209279cd101SRui Paulo MBOX_UNLOCK(sc); 21009df4bfdSLuiz Otavio O Souza 211279cd101SRui Paulo return (0); 212279cd101SRui Paulo } 213279cd101SRui Paulo 214279cd101SRui Paulo static int 215279cd101SRui Paulo bcm_mbox_read(device_t dev, int chan, uint32_t *data) 216279cd101SRui Paulo { 217279cd101SRui Paulo struct bcm_mbox_softc *sc = device_get_softc(dev); 218d792cd92SAndrew Turner int err, read_chan; 219279cd101SRui Paulo 220279cd101SRui Paulo dprintf("bcm_mbox_read: chan %d\n", chan); 221d792cd92SAndrew Turner 222d792cd92SAndrew Turner err = 0; 223279cd101SRui Paulo MBOX_LOCK(sc); 224d792cd92SAndrew Turner if (!cold) { 225b9450e43SRui Paulo while (sema_trywait(&sc->sema[chan]) == 0) { 226b9450e43SRui Paulo /* do not unlock sc while waiting for the mbox */ 227b9450e43SRui Paulo if (sema_timedwait(&sc->sema[chan], 10*hz) == 0) 228b9450e43SRui Paulo break; 229b9450e43SRui Paulo printf("timeout sema for chan %d\n", chan); 230b9450e43SRui Paulo } 231d792cd92SAndrew Turner } else { 232d792cd92SAndrew Turner do { 233d792cd92SAndrew Turner /* Wait for a message */ 234d792cd92SAndrew Turner while ((mbox_read_4(sc, REG_STATUS) & STATUS_EMPTY)) 235d792cd92SAndrew Turner ; 236d792cd92SAndrew Turner /* Read the message */ 237d792cd92SAndrew Turner if (bcm_mbox_read_msg(sc, &read_chan) != 0) { 238d792cd92SAndrew Turner err = EINVAL; 239d792cd92SAndrew Turner goto out; 240d792cd92SAndrew Turner } 241d792cd92SAndrew Turner } while (read_chan != chan); 242d792cd92SAndrew Turner } 243b9450e43SRui Paulo /* 244b9450e43SRui Paulo * get data from intr handler, the same channel is never coming 245b9450e43SRui Paulo * because of holding sc lock. 246b9450e43SRui Paulo */ 247b9450e43SRui Paulo *data = MBOX_DATA(sc->msg[chan]); 248b9450e43SRui Paulo sc->msg[chan] = 0; 249d792cd92SAndrew Turner out: 250279cd101SRui Paulo MBOX_UNLOCK(sc); 251279cd101SRui Paulo dprintf("bcm_mbox_read: chan %d, data %08x\n", chan, *data); 2521b1a53cfSOleksandr Tymoshenko 253d792cd92SAndrew Turner return (err); 2541b1a53cfSOleksandr Tymoshenko } 2551b1a53cfSOleksandr Tymoshenko 2561b1a53cfSOleksandr Tymoshenko static device_method_t bcm_mbox_methods[] = { 2571b1a53cfSOleksandr Tymoshenko DEVMETHOD(device_probe, bcm_mbox_probe), 2581b1a53cfSOleksandr Tymoshenko DEVMETHOD(device_attach, bcm_mbox_attach), 259279cd101SRui Paulo 260279cd101SRui Paulo DEVMETHOD(mbox_read, bcm_mbox_read), 261279cd101SRui Paulo DEVMETHOD(mbox_write, bcm_mbox_write), 262279cd101SRui Paulo 263279cd101SRui Paulo DEVMETHOD_END 2641b1a53cfSOleksandr Tymoshenko }; 2651b1a53cfSOleksandr Tymoshenko 2661b1a53cfSOleksandr Tymoshenko static driver_t bcm_mbox_driver = { 2671b1a53cfSOleksandr Tymoshenko "mbox", 2681b1a53cfSOleksandr Tymoshenko bcm_mbox_methods, 2691b1a53cfSOleksandr Tymoshenko sizeof(struct bcm_mbox_softc), 2701b1a53cfSOleksandr Tymoshenko }; 2711b1a53cfSOleksandr Tymoshenko 2721b1a53cfSOleksandr Tymoshenko static devclass_t bcm_mbox_devclass; 2731b1a53cfSOleksandr Tymoshenko 2741b1a53cfSOleksandr Tymoshenko DRIVER_MODULE(mbox, simplebus, bcm_mbox_driver, bcm_mbox_devclass, 0, 0); 275b812d0adSAndrew Turner 276b812d0adSAndrew Turner static void 277b812d0adSAndrew Turner bcm2835_mbox_dma_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) 278b812d0adSAndrew Turner { 279b812d0adSAndrew Turner bus_addr_t *addr; 280b812d0adSAndrew Turner 281b812d0adSAndrew Turner if (err) 282b812d0adSAndrew Turner return; 283b812d0adSAndrew Turner addr = (bus_addr_t *)arg; 284b812d0adSAndrew Turner *addr = PHYS_TO_VCBUS(segs[0].ds_addr); 285b812d0adSAndrew Turner } 286b812d0adSAndrew Turner 28727eb3304SAndrew Turner static void * 28827eb3304SAndrew Turner bcm2835_mbox_init_dma(device_t dev, size_t len, bus_dma_tag_t *tag, 28927eb3304SAndrew Turner bus_dmamap_t *map, bus_addr_t *phys) 29027eb3304SAndrew Turner { 29127eb3304SAndrew Turner void *buf; 29227eb3304SAndrew Turner int err; 29327eb3304SAndrew Turner 29427eb3304SAndrew Turner err = bus_dma_tag_create(bus_get_dma_tag(dev), 16, 0, 29527eb3304SAndrew Turner BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 29627eb3304SAndrew Turner len, 1, len, 0, NULL, NULL, tag); 29727eb3304SAndrew Turner if (err != 0) { 29827eb3304SAndrew Turner device_printf(dev, "can't create DMA tag\n"); 29927eb3304SAndrew Turner return (NULL); 30027eb3304SAndrew Turner } 30127eb3304SAndrew Turner 30227eb3304SAndrew Turner err = bus_dmamem_alloc(*tag, &buf, 0, map); 30327eb3304SAndrew Turner if (err != 0) { 30427eb3304SAndrew Turner bus_dma_tag_destroy(*tag); 30527eb3304SAndrew Turner device_printf(dev, "can't allocate dmamem\n"); 30627eb3304SAndrew Turner return (NULL); 30727eb3304SAndrew Turner } 30827eb3304SAndrew Turner 309*723af368SLuiz Otavio O Souza err = bus_dmamap_load(*tag, *map, buf, len, bcm2835_mbox_dma_cb, 31027eb3304SAndrew Turner phys, 0); 31127eb3304SAndrew Turner if (err != 0) { 31227eb3304SAndrew Turner bus_dmamem_free(*tag, buf, *map); 31327eb3304SAndrew Turner bus_dma_tag_destroy(*tag); 31427eb3304SAndrew Turner device_printf(dev, "can't load DMA map\n"); 31527eb3304SAndrew Turner return (NULL); 31627eb3304SAndrew Turner } 31727eb3304SAndrew Turner 31827eb3304SAndrew Turner return (buf); 31927eb3304SAndrew Turner } 32027eb3304SAndrew Turner 321b812d0adSAndrew Turner int 322b812d0adSAndrew Turner bcm2835_mbox_set_power_state(device_t dev, uint32_t device_id, boolean_t on) 323b812d0adSAndrew Turner { 324b812d0adSAndrew Turner struct msg_set_power_state *msg; 325b812d0adSAndrew Turner bus_dma_tag_t msg_tag; 326b812d0adSAndrew Turner bus_dmamap_t msg_map; 327b812d0adSAndrew Turner bus_addr_t msg_phys; 328b812d0adSAndrew Turner uint32_t reg; 329b812d0adSAndrew Turner device_t mbox; 330b812d0adSAndrew Turner 331b812d0adSAndrew Turner /* get mbox device */ 332b812d0adSAndrew Turner mbox = devclass_get_device(devclass_find("mbox"), 0); 333b812d0adSAndrew Turner if (mbox == NULL) { 334b812d0adSAndrew Turner device_printf(dev, "can't find mbox\n"); 335b812d0adSAndrew Turner return (ENXIO); 336b812d0adSAndrew Turner } 337b812d0adSAndrew Turner 33827eb3304SAndrew Turner /* Allocate memory for the message */ 33927eb3304SAndrew Turner msg = bcm2835_mbox_init_dma(dev, sizeof(*msg), &msg_tag, &msg_map, 34027eb3304SAndrew Turner &msg_phys); 34127eb3304SAndrew Turner if (msg == NULL) 34227eb3304SAndrew Turner return (ENOMEM); 343b812d0adSAndrew Turner 344b812d0adSAndrew Turner memset(msg, 0, sizeof(*msg)); 345b812d0adSAndrew Turner msg->hdr.buf_size = sizeof(*msg); 346b812d0adSAndrew Turner msg->hdr.code = BCM2835_MBOX_CODE_REQ; 347b812d0adSAndrew Turner msg->tag_hdr.tag = BCM2835_MBOX_TAG_SET_POWER_STATE; 348b812d0adSAndrew Turner msg->tag_hdr.val_buf_size = sizeof(msg->body); 349b812d0adSAndrew Turner msg->tag_hdr.val_len = sizeof(msg->body.req); 350b812d0adSAndrew Turner msg->body.req.device_id = device_id; 351b812d0adSAndrew Turner msg->body.req.state = (on ? BCM2835_MBOX_POWER_ON : 0) | 352b812d0adSAndrew Turner BCM2835_MBOX_POWER_WAIT; 353b812d0adSAndrew Turner msg->end_tag = 0; 354b812d0adSAndrew Turner 355b812d0adSAndrew Turner bus_dmamap_sync(msg_tag, msg_map, 356b812d0adSAndrew Turner BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 357b812d0adSAndrew Turner 358b812d0adSAndrew Turner MBOX_WRITE(mbox, BCM2835_MBOX_CHAN_PROP, (uint32_t)msg_phys); 359b812d0adSAndrew Turner MBOX_READ(mbox, BCM2835_MBOX_CHAN_PROP, ®); 360b812d0adSAndrew Turner 361b812d0adSAndrew Turner bus_dmamap_unload(msg_tag, msg_map); 36227eb3304SAndrew Turner bus_dmamem_free(msg_tag, msg, msg_map); 36327eb3304SAndrew Turner bus_dma_tag_destroy(msg_tag); 36427eb3304SAndrew Turner 36527eb3304SAndrew Turner return (0); 36627eb3304SAndrew Turner } 36727eb3304SAndrew Turner 36827eb3304SAndrew Turner int 36927eb3304SAndrew Turner bcm2835_mbox_get_clock_rate(device_t dev, uint32_t clock_id, uint32_t *hz) 37027eb3304SAndrew Turner { 37127eb3304SAndrew Turner struct msg_get_clock_rate *msg; 37227eb3304SAndrew Turner bus_dma_tag_t msg_tag; 37327eb3304SAndrew Turner bus_dmamap_t msg_map; 37427eb3304SAndrew Turner bus_addr_t msg_phys; 37527eb3304SAndrew Turner uint32_t reg; 37627eb3304SAndrew Turner device_t mbox; 37727eb3304SAndrew Turner 37827eb3304SAndrew Turner /* get mbox device */ 37927eb3304SAndrew Turner mbox = devclass_get_device(devclass_find("mbox"), 0); 38027eb3304SAndrew Turner if (mbox == NULL) { 38127eb3304SAndrew Turner device_printf(dev, "can't find mbox\n"); 38227eb3304SAndrew Turner return (ENXIO); 38327eb3304SAndrew Turner } 38427eb3304SAndrew Turner 38527eb3304SAndrew Turner /* Allocate memory for the message */ 38627eb3304SAndrew Turner msg = bcm2835_mbox_init_dma(dev, sizeof(*msg), &msg_tag, &msg_map, 38727eb3304SAndrew Turner &msg_phys); 38827eb3304SAndrew Turner if (msg == NULL) 38927eb3304SAndrew Turner return (ENOMEM); 39027eb3304SAndrew Turner 39127eb3304SAndrew Turner memset(msg, 0, sizeof(*msg)); 39227eb3304SAndrew Turner msg->hdr.buf_size = sizeof(*msg); 39327eb3304SAndrew Turner msg->hdr.code = BCM2835_MBOX_CODE_REQ; 39427eb3304SAndrew Turner msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_CLOCK_RATE; 39527eb3304SAndrew Turner msg->tag_hdr.val_buf_size = sizeof(msg->body); 39627eb3304SAndrew Turner msg->tag_hdr.val_len = sizeof(msg->body.req); 39727eb3304SAndrew Turner msg->body.req.clock_id = clock_id; 39827eb3304SAndrew Turner msg->end_tag = 0; 39927eb3304SAndrew Turner 40027eb3304SAndrew Turner bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_PREWRITE); 40127eb3304SAndrew Turner MBOX_WRITE(mbox, BCM2835_MBOX_CHAN_PROP, (uint32_t)msg_phys); 40227eb3304SAndrew Turner bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_POSTWRITE); 40327eb3304SAndrew Turner 40427eb3304SAndrew Turner bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_PREREAD); 40527eb3304SAndrew Turner MBOX_READ(mbox, BCM2835_MBOX_CHAN_PROP, ®); 40627eb3304SAndrew Turner bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_POSTREAD); 40727eb3304SAndrew Turner 40827eb3304SAndrew Turner *hz = msg->body.resp.rate_hz; 40927eb3304SAndrew Turner 41027eb3304SAndrew Turner bus_dmamap_unload(msg_tag, msg_map); 41127eb3304SAndrew Turner bus_dmamem_free(msg_tag, msg, msg_map); 412b812d0adSAndrew Turner bus_dma_tag_destroy(msg_tag); 413b812d0adSAndrew Turner 414b812d0adSAndrew Turner return (0); 415b812d0adSAndrew Turner } 416