15b8db1daSRui Paulo /*- 25b8db1daSRui Paulo * Copyright (c) 2013 Rui Paulo <rpaulo@FreeBSD.org> 35b8db1daSRui Paulo * All rights reserved. 45b8db1daSRui Paulo * 55b8db1daSRui Paulo * Redistribution and use in source and binary forms, with or without 65b8db1daSRui Paulo * modification, are permitted provided that the following conditions 75b8db1daSRui Paulo * are met: 85b8db1daSRui Paulo * 1. Redistributions of source code must retain the above copyright 95b8db1daSRui Paulo * notice, this list of conditions and the following disclaimer. 105b8db1daSRui Paulo * 2. Redistributions in binary form must reproduce the above copyright 115b8db1daSRui Paulo * notice, this list of conditions and the following disclaimer in the 125b8db1daSRui Paulo * documentation and/or other materials provided with the distribution. 135b8db1daSRui Paulo * 145b8db1daSRui Paulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 155b8db1daSRui Paulo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 165b8db1daSRui Paulo * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 175b8db1daSRui Paulo * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 185b8db1daSRui Paulo * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 195b8db1daSRui Paulo * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 205b8db1daSRui Paulo * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 215b8db1daSRui Paulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 225b8db1daSRui Paulo * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 235b8db1daSRui Paulo * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 245b8db1daSRui Paulo * POSSIBILITY OF SUCH DAMAGE. 255b8db1daSRui Paulo */ 265b8db1daSRui Paulo #include <sys/cdefs.h> 275b8db1daSRui Paulo __FBSDID("$FreeBSD$"); 285b8db1daSRui Paulo 295b8db1daSRui Paulo #include <sys/param.h> 305b8db1daSRui Paulo #include <sys/systm.h> 315b8db1daSRui Paulo #include <sys/bus.h> 325b8db1daSRui Paulo #include <sys/kernel.h> 335b8db1daSRui Paulo #include <sys/module.h> 345b8db1daSRui Paulo #include <sys/malloc.h> 355b8db1daSRui Paulo #include <sys/rman.h> 365b8db1daSRui Paulo #include <sys/timeet.h> 375b8db1daSRui Paulo #include <sys/timetc.h> 385b8db1daSRui Paulo #include <sys/watchdog.h> 395b8db1daSRui Paulo #include <machine/bus.h> 405b8db1daSRui Paulo #include <machine/cpu.h> 415b8db1daSRui Paulo #include <machine/frame.h> 425b8db1daSRui Paulo #include <machine/intr.h> 435b8db1daSRui Paulo 445b8db1daSRui Paulo #include <dev/fdt/fdt_common.h> 455b8db1daSRui Paulo #include <dev/ofw/openfirm.h> 465b8db1daSRui Paulo #include <dev/ofw/ofw_bus.h> 475b8db1daSRui Paulo #include <dev/ofw/ofw_bus_subr.h> 485b8db1daSRui Paulo 495b8db1daSRui Paulo #include <machine/bus.h> 505b8db1daSRui Paulo 515b8db1daSRui Paulo #include <arm/ti/ti_mbox.h> 525b8db1daSRui Paulo #include <arm/ti/ti_prcm.h> 535b8db1daSRui Paulo 545b8db1daSRui Paulo #include "mbox_if.h" 555b8db1daSRui Paulo 565b8db1daSRui Paulo #ifdef DEBUG 575b8db1daSRui Paulo #define DPRINTF(fmt, ...) do { \ 585b8db1daSRui Paulo printf("%s: ", __func__); \ 595b8db1daSRui Paulo printf(fmt, __VA_ARGS__); \ 605b8db1daSRui Paulo } while (0) 615b8db1daSRui Paulo #else 625b8db1daSRui Paulo #define DPRINTF(fmt, ...) 635b8db1daSRui Paulo #endif 645b8db1daSRui Paulo 655b8db1daSRui Paulo static device_probe_t ti_mbox_probe; 665b8db1daSRui Paulo static device_attach_t ti_mbox_attach; 675b8db1daSRui Paulo static device_detach_t ti_mbox_detach; 685b8db1daSRui Paulo static void ti_mbox_intr(void *); 695b8db1daSRui Paulo static int ti_mbox_read(device_t, int, uint32_t *); 705b8db1daSRui Paulo static int ti_mbox_write(device_t, int, uint32_t); 715b8db1daSRui Paulo 725b8db1daSRui Paulo struct ti_mbox_softc { 735b8db1daSRui Paulo struct mtx sc_mtx; 745b8db1daSRui Paulo struct resource *sc_mem_res; 755b8db1daSRui Paulo struct resource *sc_irq_res; 765b8db1daSRui Paulo void *sc_intr; 775b8db1daSRui Paulo bus_space_tag_t sc_bt; 785b8db1daSRui Paulo bus_space_handle_t sc_bh; 795b8db1daSRui Paulo }; 805b8db1daSRui Paulo 815b8db1daSRui Paulo #define TI_MBOX_LOCK(sc) mtx_lock(&(sc)->sc_mtx) 825b8db1daSRui Paulo #define TI_MBOX_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) 835b8db1daSRui Paulo 845b8db1daSRui Paulo static device_method_t ti_mbox_methods[] = { 855b8db1daSRui Paulo DEVMETHOD(device_probe, ti_mbox_probe), 865b8db1daSRui Paulo DEVMETHOD(device_attach, ti_mbox_attach), 875b8db1daSRui Paulo DEVMETHOD(device_detach, ti_mbox_detach), 885b8db1daSRui Paulo 895b8db1daSRui Paulo DEVMETHOD(mbox_read, ti_mbox_read), 905b8db1daSRui Paulo DEVMETHOD(mbox_write, ti_mbox_write), 915b8db1daSRui Paulo 925b8db1daSRui Paulo DEVMETHOD_END 935b8db1daSRui Paulo }; 945b8db1daSRui Paulo 955b8db1daSRui Paulo static driver_t ti_mbox_driver = { 965b8db1daSRui Paulo "ti_mbox", 975b8db1daSRui Paulo ti_mbox_methods, 985b8db1daSRui Paulo sizeof(struct ti_mbox_softc) 995b8db1daSRui Paulo }; 1005b8db1daSRui Paulo 1015b8db1daSRui Paulo static devclass_t ti_mbox_devclass; 1025b8db1daSRui Paulo 1035b8db1daSRui Paulo DRIVER_MODULE(ti_mbox, simplebus, ti_mbox_driver, ti_mbox_devclass, 0, 0); 1045b8db1daSRui Paulo 1055b8db1daSRui Paulo static __inline uint32_t 1065b8db1daSRui Paulo ti_mbox_reg_read(struct ti_mbox_softc *sc, uint16_t reg) 1075b8db1daSRui Paulo { 1085b8db1daSRui Paulo return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg)); 1095b8db1daSRui Paulo } 1105b8db1daSRui Paulo 1115b8db1daSRui Paulo static __inline void 1125b8db1daSRui Paulo ti_mbox_reg_write(struct ti_mbox_softc *sc, uint16_t reg, uint32_t val) 1135b8db1daSRui Paulo { 1145b8db1daSRui Paulo bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val); 1155b8db1daSRui Paulo } 1165b8db1daSRui Paulo 1175b8db1daSRui Paulo static int 1185b8db1daSRui Paulo ti_mbox_probe(device_t dev) 1195b8db1daSRui Paulo { 120add35ed5SIan Lepore 121add35ed5SIan Lepore if (!ofw_bus_status_okay(dev)) 122add35ed5SIan Lepore return (ENXIO); 123add35ed5SIan Lepore 124*5b03aba6SOleksandr Tymoshenko if (ofw_bus_is_compatible(dev, "ti,omap4-mailbox")) { 1255b8db1daSRui Paulo device_set_desc(dev, "TI System Mailbox"); 1265b8db1daSRui Paulo return (BUS_PROBE_DEFAULT); 1275b8db1daSRui Paulo } 1285b8db1daSRui Paulo 1295b8db1daSRui Paulo return (ENXIO); 1305b8db1daSRui Paulo } 1315b8db1daSRui Paulo 1325b8db1daSRui Paulo static int 1335b8db1daSRui Paulo ti_mbox_attach(device_t dev) 1345b8db1daSRui Paulo { 1355b8db1daSRui Paulo struct ti_mbox_softc *sc; 1365b8db1daSRui Paulo int rid, delay, chan; 1375b8db1daSRui Paulo uint32_t rev, sysconfig; 1385b8db1daSRui Paulo 1395b8db1daSRui Paulo if (ti_prcm_clk_enable(MAILBOX0_CLK) != 0) { 1405b8db1daSRui Paulo device_printf(dev, "could not enable MBOX clock\n"); 1415b8db1daSRui Paulo return (ENXIO); 1425b8db1daSRui Paulo } 1435b8db1daSRui Paulo sc = device_get_softc(dev); 1445b8db1daSRui Paulo rid = 0; 1456eebe850SJohn-Mark Gurney mtx_init(&sc->sc_mtx, "TI mbox", NULL, MTX_DEF); 1465b8db1daSRui Paulo sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 1475b8db1daSRui Paulo RF_ACTIVE); 1485b8db1daSRui Paulo if (sc->sc_mem_res == NULL) { 1495b8db1daSRui Paulo device_printf(dev, "could not allocate memory resource\n"); 1505b8db1daSRui Paulo return (ENXIO); 1515b8db1daSRui Paulo } 1525b8db1daSRui Paulo sc->sc_bt = rman_get_bustag(sc->sc_mem_res); 1535b8db1daSRui Paulo sc->sc_bh = rman_get_bushandle(sc->sc_mem_res); 1545b8db1daSRui Paulo rid = 0; 1555b8db1daSRui Paulo sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 1565b8db1daSRui Paulo RF_ACTIVE); 1575b8db1daSRui Paulo if (sc->sc_irq_res == NULL) { 1585b8db1daSRui Paulo device_printf(dev, "could not allocate interrupt resource\n"); 1595b8db1daSRui Paulo ti_mbox_detach(dev); 1605b8db1daSRui Paulo return (ENXIO); 1615b8db1daSRui Paulo } 1625b8db1daSRui Paulo if (bus_setup_intr(dev, sc->sc_irq_res, INTR_MPSAFE | INTR_TYPE_MISC, 1635b8db1daSRui Paulo NULL, ti_mbox_intr, sc, &sc->sc_intr) != 0) { 1645b8db1daSRui Paulo device_printf(dev, "unable to setup the interrupt handler\n"); 1655b8db1daSRui Paulo ti_mbox_detach(dev); 1665b8db1daSRui Paulo return (ENXIO); 1675b8db1daSRui Paulo } 1685b8db1daSRui Paulo /* 1695b8db1daSRui Paulo * Reset the controller. 1705b8db1daSRui Paulo */ 1715b8db1daSRui Paulo sysconfig = ti_mbox_reg_read(sc, TI_MBOX_SYSCONFIG); 1725b8db1daSRui Paulo DPRINTF("initial sysconfig %d\n", sysconfig); 1735b8db1daSRui Paulo sysconfig |= TI_MBOX_SYSCONFIG_SOFTRST; 1745b8db1daSRui Paulo delay = 100; 1755b8db1daSRui Paulo while (ti_mbox_reg_read(sc, TI_MBOX_SYSCONFIG) & 1765b8db1daSRui Paulo TI_MBOX_SYSCONFIG_SOFTRST) { 1775b8db1daSRui Paulo delay--; 1785b8db1daSRui Paulo DELAY(10); 1795b8db1daSRui Paulo } 1805b8db1daSRui Paulo if (delay == 0) { 1815b8db1daSRui Paulo device_printf(dev, "controller reset failed\n"); 1825b8db1daSRui Paulo ti_mbox_detach(dev); 1835b8db1daSRui Paulo return (ENXIO); 1845b8db1daSRui Paulo } 1855b8db1daSRui Paulo /* 1865b8db1daSRui Paulo * Enable smart idle mode. 1875b8db1daSRui Paulo */ 1885b8db1daSRui Paulo ti_mbox_reg_write(sc, TI_MBOX_SYSCONFIG, 1895b8db1daSRui Paulo ti_mbox_reg_read(sc, TI_MBOX_SYSCONFIG) | TI_MBOX_SYSCONFIG_SMARTIDLE); 1905b8db1daSRui Paulo rev = ti_mbox_reg_read(sc, TI_MBOX_REVISION); 1915b8db1daSRui Paulo DPRINTF("rev %d\n", rev); 1925b8db1daSRui Paulo device_printf(dev, "revision %d.%d\n", (rev >> 8) & 0x4, rev & 0x40); 1935b8db1daSRui Paulo /* 1945b8db1daSRui Paulo * Enable message interrupts. 1955b8db1daSRui Paulo */ 1965b8db1daSRui Paulo for (chan = 0; chan < 8; chan++) 1975b8db1daSRui Paulo ti_mbox_reg_write(sc, TI_MBOX_IRQENABLE_SET(chan), 1); 1985b8db1daSRui Paulo 1995b8db1daSRui Paulo return (0); 2005b8db1daSRui Paulo } 2015b8db1daSRui Paulo 2025b8db1daSRui Paulo static int 2035b8db1daSRui Paulo ti_mbox_detach(device_t dev) 2045b8db1daSRui Paulo { 2055b8db1daSRui Paulo struct ti_mbox_softc *sc; 2065b8db1daSRui Paulo 2075b8db1daSRui Paulo sc = device_get_softc(dev); 2085b8db1daSRui Paulo if (sc->sc_intr) 2095b8db1daSRui Paulo bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr); 2105b8db1daSRui Paulo if (sc->sc_irq_res) 2115b8db1daSRui Paulo bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->sc_irq_res), 2125b8db1daSRui Paulo sc->sc_irq_res); 2135b8db1daSRui Paulo if (sc->sc_mem_res) 2145b8db1daSRui Paulo bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_mem_res), 2155b8db1daSRui Paulo sc->sc_mem_res); 2165b8db1daSRui Paulo 2175b8db1daSRui Paulo return (0); 2185b8db1daSRui Paulo } 2195b8db1daSRui Paulo 2205b8db1daSRui Paulo static void 2215b8db1daSRui Paulo ti_mbox_intr(void *arg) 2225b8db1daSRui Paulo { 2235b8db1daSRui Paulo struct ti_mbox_softc *sc; 2245b8db1daSRui Paulo 2255b8db1daSRui Paulo sc = arg; 2265b8db1daSRui Paulo DPRINTF("interrupt %p", sc); 2275b8db1daSRui Paulo } 2285b8db1daSRui Paulo 2295b8db1daSRui Paulo static int 2305b8db1daSRui Paulo ti_mbox_read(device_t dev, int chan, uint32_t *data) 2315b8db1daSRui Paulo { 2325b8db1daSRui Paulo struct ti_mbox_softc *sc; 2335b8db1daSRui Paulo 2345b8db1daSRui Paulo if (chan < 0 || chan > 7) 2355b8db1daSRui Paulo return (EINVAL); 2365b8db1daSRui Paulo sc = device_get_softc(dev); 2375b8db1daSRui Paulo 2385b8db1daSRui Paulo return (ti_mbox_reg_read(sc, TI_MBOX_MESSAGE(chan))); 2395b8db1daSRui Paulo } 2405b8db1daSRui Paulo 2415b8db1daSRui Paulo static int 2425b8db1daSRui Paulo ti_mbox_write(device_t dev, int chan, uint32_t data) 2435b8db1daSRui Paulo { 2445b8db1daSRui Paulo int limit = 500; 2455b8db1daSRui Paulo struct ti_mbox_softc *sc; 2465b8db1daSRui Paulo 2475b8db1daSRui Paulo if (chan < 0 || chan > 7) 2485b8db1daSRui Paulo return (EINVAL); 2495b8db1daSRui Paulo sc = device_get_softc(dev); 2505b8db1daSRui Paulo TI_MBOX_LOCK(sc); 2515b8db1daSRui Paulo /* XXX implement interrupt method */ 2525b8db1daSRui Paulo while (ti_mbox_reg_read(sc, TI_MBOX_FIFOSTATUS(chan)) == 1 && 2535b8db1daSRui Paulo limit--) { 2545b8db1daSRui Paulo DELAY(10); 2555b8db1daSRui Paulo } 2565b8db1daSRui Paulo if (limit == 0) { 2575b8db1daSRui Paulo device_printf(dev, "FIFOSTAUS%d stuck\n", chan); 2585b8db1daSRui Paulo TI_MBOX_UNLOCK(sc); 2595b8db1daSRui Paulo return (EAGAIN); 2605b8db1daSRui Paulo } 2615b8db1daSRui Paulo ti_mbox_reg_write(sc, TI_MBOX_MESSAGE(chan), data); 2625b8db1daSRui Paulo 2635b8db1daSRui Paulo return (0); 2645b8db1daSRui Paulo } 265