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> 451b1a53cfSOleksandr Tymoshenko 46279cd101SRui Paulo #include "mbox_if.h" 47279cd101SRui Paulo 481b1a53cfSOleksandr Tymoshenko #define REG_READ 0x00 491b1a53cfSOleksandr Tymoshenko #define REG_POL 0x10 501b1a53cfSOleksandr Tymoshenko #define REG_SENDER 0x14 511b1a53cfSOleksandr Tymoshenko #define REG_STATUS 0x18 521b1a53cfSOleksandr Tymoshenko #define STATUS_FULL 0x80000000 531b1a53cfSOleksandr Tymoshenko #define STATUS_EMPTY 0x40000000 541b1a53cfSOleksandr Tymoshenko #define REG_CONFIG 0x1C 551b1a53cfSOleksandr Tymoshenko #define CONFIG_DATA_IRQ 0x00000001 561b1a53cfSOleksandr Tymoshenko #define REG_WRITE 0x20 /* This is Mailbox 1 address */ 571b1a53cfSOleksandr Tymoshenko 581b1a53cfSOleksandr Tymoshenko #define MBOX_MSG(chan, data) (((data) & ~0xf) | ((chan) & 0xf)) 591b1a53cfSOleksandr Tymoshenko #define MBOX_CHAN(msg) ((msg) & 0xf) 601b1a53cfSOleksandr Tymoshenko #define MBOX_DATA(msg) ((msg) & ~0xf) 611b1a53cfSOleksandr Tymoshenko 62279cd101SRui Paulo #define MBOX_LOCK(sc) do { \ 63279cd101SRui Paulo mtx_lock(&(sc)->lock); \ 641b1a53cfSOleksandr Tymoshenko } while(0) 651b1a53cfSOleksandr Tymoshenko 66279cd101SRui Paulo #define MBOX_UNLOCK(sc) do { \ 67279cd101SRui Paulo mtx_unlock(&(sc)->lock); \ 681b1a53cfSOleksandr Tymoshenko } while(0) 691b1a53cfSOleksandr Tymoshenko 701b1a53cfSOleksandr Tymoshenko #ifdef DEBUG 711b1a53cfSOleksandr Tymoshenko #define dprintf(fmt, args...) printf(fmt, ##args) 721b1a53cfSOleksandr Tymoshenko #else 731b1a53cfSOleksandr Tymoshenko #define dprintf(fmt, args...) 741b1a53cfSOleksandr Tymoshenko #endif 751b1a53cfSOleksandr Tymoshenko 761b1a53cfSOleksandr Tymoshenko struct bcm_mbox_softc { 771b1a53cfSOleksandr Tymoshenko struct mtx lock; 781b1a53cfSOleksandr Tymoshenko struct resource * mem_res; 791b1a53cfSOleksandr Tymoshenko struct resource * irq_res; 801b1a53cfSOleksandr Tymoshenko void* intr_hl; 811b1a53cfSOleksandr Tymoshenko bus_space_tag_t bst; 821b1a53cfSOleksandr Tymoshenko bus_space_handle_t bsh; 831b1a53cfSOleksandr Tymoshenko int msg[BCM2835_MBOX_CHANS]; 84b9450e43SRui Paulo struct sema sema[BCM2835_MBOX_CHANS]; 851b1a53cfSOleksandr Tymoshenko }; 861b1a53cfSOleksandr Tymoshenko 87279cd101SRui Paulo #define mbox_read_4(sc, reg) \ 88279cd101SRui Paulo bus_space_read_4((sc)->bst, (sc)->bsh, reg) 89279cd101SRui Paulo #define mbox_write_4(sc, reg, val) \ 90279cd101SRui Paulo bus_space_write_4((sc)->bst, (sc)->bsh, reg, val) 911b1a53cfSOleksandr Tymoshenko 92*d792cd92SAndrew Turner static int 93*d792cd92SAndrew Turner bcm_mbox_read_msg(struct bcm_mbox_softc *sc, int *ochan) 941b1a53cfSOleksandr Tymoshenko { 951b1a53cfSOleksandr Tymoshenko uint32_t data; 961b1a53cfSOleksandr Tymoshenko uint32_t msg; 97*d792cd92SAndrew Turner int chan; 981b1a53cfSOleksandr Tymoshenko 99279cd101SRui Paulo msg = mbox_read_4(sc, REG_READ); 1001b1a53cfSOleksandr Tymoshenko dprintf("bcm_mbox_intr: raw data %08x\n", msg); 1011b1a53cfSOleksandr Tymoshenko chan = MBOX_CHAN(msg); 1021b1a53cfSOleksandr Tymoshenko data = MBOX_DATA(msg); 103b9450e43SRui Paulo if (sc->msg[chan]) { 1041b1a53cfSOleksandr Tymoshenko printf("bcm_mbox_intr: channel %d oveflow\n", chan); 105*d792cd92SAndrew Turner return (1); 1061b1a53cfSOleksandr Tymoshenko } 1071b1a53cfSOleksandr Tymoshenko dprintf("bcm_mbox_intr: chan %d, data %08x\n", chan, data); 1081432fa20SLuiz Otavio O Souza sc->msg[chan] = msg; 109*d792cd92SAndrew Turner 110*d792cd92SAndrew Turner if (ochan != NULL) 111*d792cd92SAndrew Turner *ochan = chan; 112*d792cd92SAndrew Turner 113*d792cd92SAndrew Turner return (0); 1141b1a53cfSOleksandr Tymoshenko } 115*d792cd92SAndrew Turner 116*d792cd92SAndrew Turner static void 117*d792cd92SAndrew Turner bcm_mbox_intr(void *arg) 118*d792cd92SAndrew Turner { 119*d792cd92SAndrew Turner struct bcm_mbox_softc *sc = arg; 120*d792cd92SAndrew Turner int chan; 121*d792cd92SAndrew Turner 122*d792cd92SAndrew Turner while (!(mbox_read_4(sc, REG_STATUS) & STATUS_EMPTY)) 123*d792cd92SAndrew Turner if (bcm_mbox_read_msg(sc, &chan) == 0) 124*d792cd92SAndrew Turner sema_post(&sc->sema[chan]); 1251b1a53cfSOleksandr Tymoshenko } 1261b1a53cfSOleksandr Tymoshenko 1271b1a53cfSOleksandr Tymoshenko static int 1281b1a53cfSOleksandr Tymoshenko bcm_mbox_probe(device_t dev) 1291b1a53cfSOleksandr Tymoshenko { 1301b1a53cfSOleksandr Tymoshenko 131add35ed5SIan Lepore if (!ofw_bus_status_okay(dev)) 132add35ed5SIan Lepore return (ENXIO); 133add35ed5SIan Lepore 1341b1a53cfSOleksandr Tymoshenko if (ofw_bus_is_compatible(dev, "broadcom,bcm2835-mbox")) { 1351b1a53cfSOleksandr Tymoshenko device_set_desc(dev, "BCM2835 VideoCore Mailbox"); 1361b1a53cfSOleksandr Tymoshenko return(BUS_PROBE_DEFAULT); 1371b1a53cfSOleksandr Tymoshenko } 1381b1a53cfSOleksandr Tymoshenko 1391b1a53cfSOleksandr Tymoshenko return (ENXIO); 1401b1a53cfSOleksandr Tymoshenko } 1411b1a53cfSOleksandr Tymoshenko 1421b1a53cfSOleksandr Tymoshenko static int 1431b1a53cfSOleksandr Tymoshenko bcm_mbox_attach(device_t dev) 1441b1a53cfSOleksandr Tymoshenko { 1451b1a53cfSOleksandr Tymoshenko struct bcm_mbox_softc *sc = device_get_softc(dev); 1461b1a53cfSOleksandr Tymoshenko int i; 1471b1a53cfSOleksandr Tymoshenko int rid = 0; 1481b1a53cfSOleksandr Tymoshenko 1491b1a53cfSOleksandr Tymoshenko sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 1501b1a53cfSOleksandr Tymoshenko if (sc->mem_res == NULL) { 1511b1a53cfSOleksandr Tymoshenko device_printf(dev, "could not allocate memory resource\n"); 1521b1a53cfSOleksandr Tymoshenko return (ENXIO); 1531b1a53cfSOleksandr Tymoshenko } 1541b1a53cfSOleksandr Tymoshenko 1551b1a53cfSOleksandr Tymoshenko sc->bst = rman_get_bustag(sc->mem_res); 1561b1a53cfSOleksandr Tymoshenko sc->bsh = rman_get_bushandle(sc->mem_res); 1571b1a53cfSOleksandr Tymoshenko 1581b1a53cfSOleksandr Tymoshenko rid = 0; 1591b1a53cfSOleksandr Tymoshenko sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 1601b1a53cfSOleksandr Tymoshenko if (sc->irq_res == NULL) { 1611b1a53cfSOleksandr Tymoshenko device_printf(dev, "could not allocate interrupt resource\n"); 1621b1a53cfSOleksandr Tymoshenko return (ENXIO); 1631b1a53cfSOleksandr Tymoshenko } 1641b1a53cfSOleksandr Tymoshenko 1651b1a53cfSOleksandr Tymoshenko /* Setup and enable the timer */ 16695506b81SRui Paulo if (bus_setup_intr(dev, sc->irq_res, INTR_MPSAFE | INTR_TYPE_MISC, 16795506b81SRui Paulo NULL, bcm_mbox_intr, sc, &sc->intr_hl) != 0) { 16895506b81SRui Paulo bus_release_resource(dev, SYS_RES_IRQ, rid, sc->irq_res); 1691b1a53cfSOleksandr Tymoshenko device_printf(dev, "Unable to setup the clock irq handler.\n"); 1701b1a53cfSOleksandr Tymoshenko return (ENXIO); 1711b1a53cfSOleksandr Tymoshenko } 1721b1a53cfSOleksandr Tymoshenko 173d01195e3SChristian Brueffer mtx_init(&sc->lock, "vcio mbox", NULL, MTX_DEF); 1741b1a53cfSOleksandr Tymoshenko for (i = 0; i < BCM2835_MBOX_CHANS; i++) { 175b9450e43SRui Paulo sc->msg[i] = 0; 176b9450e43SRui Paulo sema_init(&sc->sema[i], 0, "mbox"); 1771b1a53cfSOleksandr Tymoshenko } 1781b1a53cfSOleksandr Tymoshenko 1791b1a53cfSOleksandr Tymoshenko /* Read all pending messages */ 1801432fa20SLuiz Otavio O Souza while ((mbox_read_4(sc, REG_STATUS) & STATUS_EMPTY) == 0) 1811432fa20SLuiz Otavio O Souza (void)mbox_read_4(sc, REG_READ); 1821b1a53cfSOleksandr Tymoshenko 183279cd101SRui Paulo mbox_write_4(sc, REG_CONFIG, CONFIG_DATA_IRQ); 184279cd101SRui Paulo 185279cd101SRui Paulo return (0); 186279cd101SRui Paulo } 187279cd101SRui Paulo 188279cd101SRui Paulo /* 189279cd101SRui Paulo * Mailbox API 190279cd101SRui Paulo */ 191279cd101SRui Paulo static int 192279cd101SRui Paulo bcm_mbox_write(device_t dev, int chan, uint32_t data) 193279cd101SRui Paulo { 19409df4bfdSLuiz Otavio O Souza int limit = 1000; 195279cd101SRui Paulo struct bcm_mbox_softc *sc = device_get_softc(dev); 196279cd101SRui Paulo 197279cd101SRui Paulo dprintf("bcm_mbox_write: chan %d, data %08x\n", chan, data); 198279cd101SRui Paulo MBOX_LOCK(sc); 19909df4bfdSLuiz Otavio O Souza while ((mbox_read_4(sc, REG_STATUS) & STATUS_FULL) && --limit) 20009df4bfdSLuiz Otavio O Souza DELAY(5); 201279cd101SRui Paulo if (limit == 0) { 202279cd101SRui Paulo printf("bcm_mbox_write: STATUS_FULL stuck"); 203279cd101SRui Paulo MBOX_UNLOCK(sc); 204279cd101SRui Paulo return (EAGAIN); 205279cd101SRui Paulo } 206279cd101SRui Paulo mbox_write_4(sc, REG_WRITE, MBOX_MSG(chan, data)); 207279cd101SRui Paulo MBOX_UNLOCK(sc); 20809df4bfdSLuiz Otavio O Souza 209279cd101SRui Paulo return (0); 210279cd101SRui Paulo } 211279cd101SRui Paulo 212279cd101SRui Paulo static int 213279cd101SRui Paulo bcm_mbox_read(device_t dev, int chan, uint32_t *data) 214279cd101SRui Paulo { 215279cd101SRui Paulo struct bcm_mbox_softc *sc = device_get_softc(dev); 216*d792cd92SAndrew Turner int err, read_chan; 217279cd101SRui Paulo 218279cd101SRui Paulo dprintf("bcm_mbox_read: chan %d\n", chan); 219*d792cd92SAndrew Turner 220*d792cd92SAndrew Turner err = 0; 221279cd101SRui Paulo MBOX_LOCK(sc); 222*d792cd92SAndrew Turner if (!cold) { 223b9450e43SRui Paulo while (sema_trywait(&sc->sema[chan]) == 0) { 224b9450e43SRui Paulo /* do not unlock sc while waiting for the mbox */ 225b9450e43SRui Paulo if (sema_timedwait(&sc->sema[chan], 10*hz) == 0) 226b9450e43SRui Paulo break; 227b9450e43SRui Paulo printf("timeout sema for chan %d\n", chan); 228b9450e43SRui Paulo } 229*d792cd92SAndrew Turner } else { 230*d792cd92SAndrew Turner do { 231*d792cd92SAndrew Turner /* Wait for a message */ 232*d792cd92SAndrew Turner while ((mbox_read_4(sc, REG_STATUS) & STATUS_EMPTY)) 233*d792cd92SAndrew Turner ; 234*d792cd92SAndrew Turner /* Read the message */ 235*d792cd92SAndrew Turner if (bcm_mbox_read_msg(sc, &read_chan) != 0) { 236*d792cd92SAndrew Turner err = EINVAL; 237*d792cd92SAndrew Turner goto out; 238*d792cd92SAndrew Turner } 239*d792cd92SAndrew Turner } while (read_chan != chan); 240*d792cd92SAndrew Turner } 241b9450e43SRui Paulo /* 242b9450e43SRui Paulo * get data from intr handler, the same channel is never coming 243b9450e43SRui Paulo * because of holding sc lock. 244b9450e43SRui Paulo */ 245b9450e43SRui Paulo *data = MBOX_DATA(sc->msg[chan]); 246b9450e43SRui Paulo sc->msg[chan] = 0; 247*d792cd92SAndrew Turner out: 248279cd101SRui Paulo MBOX_UNLOCK(sc); 249279cd101SRui Paulo dprintf("bcm_mbox_read: chan %d, data %08x\n", chan, *data); 2501b1a53cfSOleksandr Tymoshenko 251*d792cd92SAndrew Turner return (err); 2521b1a53cfSOleksandr Tymoshenko } 2531b1a53cfSOleksandr Tymoshenko 2541b1a53cfSOleksandr Tymoshenko static device_method_t bcm_mbox_methods[] = { 2551b1a53cfSOleksandr Tymoshenko DEVMETHOD(device_probe, bcm_mbox_probe), 2561b1a53cfSOleksandr Tymoshenko DEVMETHOD(device_attach, bcm_mbox_attach), 257279cd101SRui Paulo 258279cd101SRui Paulo DEVMETHOD(mbox_read, bcm_mbox_read), 259279cd101SRui Paulo DEVMETHOD(mbox_write, bcm_mbox_write), 260279cd101SRui Paulo 261279cd101SRui Paulo DEVMETHOD_END 2621b1a53cfSOleksandr Tymoshenko }; 2631b1a53cfSOleksandr Tymoshenko 2641b1a53cfSOleksandr Tymoshenko static driver_t bcm_mbox_driver = { 2651b1a53cfSOleksandr Tymoshenko "mbox", 2661b1a53cfSOleksandr Tymoshenko bcm_mbox_methods, 2671b1a53cfSOleksandr Tymoshenko sizeof(struct bcm_mbox_softc), 2681b1a53cfSOleksandr Tymoshenko }; 2691b1a53cfSOleksandr Tymoshenko 2701b1a53cfSOleksandr Tymoshenko static devclass_t bcm_mbox_devclass; 2711b1a53cfSOleksandr Tymoshenko 2721b1a53cfSOleksandr Tymoshenko DRIVER_MODULE(mbox, simplebus, bcm_mbox_driver, bcm_mbox_devclass, 0, 0); 273