ti_mbox.c revision 261211
1/*- 2 * Copyright (c) 2013 Rui Paulo <rpaulo@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 23 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 * POSSIBILITY OF SUCH DAMAGE. 25 */ 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD: head/sys/arm/ti/ti_mbox.c 261211 2014-01-27 17:31:21Z jmg $"); 28 29#include <sys/param.h> 30#include <sys/systm.h> 31#include <sys/bus.h> 32#include <sys/kernel.h> 33#include <sys/module.h> 34#include <sys/malloc.h> 35#include <sys/rman.h> 36#include <sys/timeet.h> 37#include <sys/timetc.h> 38#include <sys/watchdog.h> 39#include <machine/bus.h> 40#include <machine/cpu.h> 41#include <machine/frame.h> 42#include <machine/intr.h> 43 44#include <dev/fdt/fdt_common.h> 45#include <dev/ofw/openfirm.h> 46#include <dev/ofw/ofw_bus.h> 47#include <dev/ofw/ofw_bus_subr.h> 48 49#include <machine/bus.h> 50#include <machine/fdt.h> 51 52#include <arm/ti/ti_mbox.h> 53#include <arm/ti/ti_prcm.h> 54 55#include "mbox_if.h" 56 57#define DEBUG 58#ifdef DEBUG 59#define DPRINTF(fmt, ...) do { \ 60 printf("%s: ", __func__); \ 61 printf(fmt, __VA_ARGS__); \ 62} while (0) 63#else 64#define DPRINTF(fmt, ...) 65#endif 66 67static device_probe_t ti_mbox_probe; 68static device_attach_t ti_mbox_attach; 69static device_detach_t ti_mbox_detach; 70static void ti_mbox_intr(void *); 71static int ti_mbox_read(device_t, int, uint32_t *); 72static int ti_mbox_write(device_t, int, uint32_t); 73 74struct ti_mbox_softc { 75 struct mtx sc_mtx; 76 struct resource *sc_mem_res; 77 struct resource *sc_irq_res; 78 void *sc_intr; 79 bus_space_tag_t sc_bt; 80 bus_space_handle_t sc_bh; 81}; 82 83#define TI_MBOX_LOCK(sc) mtx_lock(&(sc)->sc_mtx) 84#define TI_MBOX_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) 85 86static device_method_t ti_mbox_methods[] = { 87 DEVMETHOD(device_probe, ti_mbox_probe), 88 DEVMETHOD(device_attach, ti_mbox_attach), 89 DEVMETHOD(device_detach, ti_mbox_detach), 90 91 DEVMETHOD(mbox_read, ti_mbox_read), 92 DEVMETHOD(mbox_write, ti_mbox_write), 93 94 DEVMETHOD_END 95}; 96 97static driver_t ti_mbox_driver = { 98 "ti_mbox", 99 ti_mbox_methods, 100 sizeof(struct ti_mbox_softc) 101}; 102 103static devclass_t ti_mbox_devclass; 104 105DRIVER_MODULE(ti_mbox, simplebus, ti_mbox_driver, ti_mbox_devclass, 0, 0); 106 107static __inline uint32_t 108ti_mbox_reg_read(struct ti_mbox_softc *sc, uint16_t reg) 109{ 110 return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg)); 111} 112 113static __inline void 114ti_mbox_reg_write(struct ti_mbox_softc *sc, uint16_t reg, uint32_t val) 115{ 116 bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val); 117} 118 119static int 120ti_mbox_probe(device_t dev) 121{ 122 if (ofw_bus_is_compatible(dev, "ti,system-mbox")) { 123 device_set_desc(dev, "TI System Mailbox"); 124 return (BUS_PROBE_DEFAULT); 125 } 126 127 return (ENXIO); 128} 129 130static int 131ti_mbox_attach(device_t dev) 132{ 133 struct ti_mbox_softc *sc; 134 int rid, delay, chan; 135 uint32_t rev, sysconfig; 136 137 if (ti_prcm_clk_enable(MAILBOX0_CLK) != 0) { 138 device_printf(dev, "could not enable MBOX clock\n"); 139 return (ENXIO); 140 } 141 sc = device_get_softc(dev); 142 rid = 0; 143 mtx_init(&sc->sc_mtx, "TI mbox", NULL, MTX_DEF); 144 sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 145 RF_ACTIVE); 146 if (sc->sc_mem_res == NULL) { 147 device_printf(dev, "could not allocate memory resource\n"); 148 return (ENXIO); 149 } 150 sc->sc_bt = rman_get_bustag(sc->sc_mem_res); 151 sc->sc_bh = rman_get_bushandle(sc->sc_mem_res); 152 rid = 0; 153 sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 154 RF_ACTIVE); 155 if (sc->sc_irq_res == NULL) { 156 device_printf(dev, "could not allocate interrupt resource\n"); 157 ti_mbox_detach(dev); 158 return (ENXIO); 159 } 160 if (bus_setup_intr(dev, sc->sc_irq_res, INTR_MPSAFE | INTR_TYPE_MISC, 161 NULL, ti_mbox_intr, sc, &sc->sc_intr) != 0) { 162 device_printf(dev, "unable to setup the interrupt handler\n"); 163 ti_mbox_detach(dev); 164 return (ENXIO); 165 } 166 /* 167 * Reset the controller. 168 */ 169 sysconfig = ti_mbox_reg_read(sc, TI_MBOX_SYSCONFIG); 170 DPRINTF("initial sysconfig %d\n", sysconfig); 171 sysconfig |= TI_MBOX_SYSCONFIG_SOFTRST; 172 delay = 100; 173 while (ti_mbox_reg_read(sc, TI_MBOX_SYSCONFIG) & 174 TI_MBOX_SYSCONFIG_SOFTRST) { 175 delay--; 176 DELAY(10); 177 } 178 if (delay == 0) { 179 device_printf(dev, "controller reset failed\n"); 180 ti_mbox_detach(dev); 181 return (ENXIO); 182 } 183 /* 184 * Enable smart idle mode. 185 */ 186 ti_mbox_reg_write(sc, TI_MBOX_SYSCONFIG, 187 ti_mbox_reg_read(sc, TI_MBOX_SYSCONFIG) | TI_MBOX_SYSCONFIG_SMARTIDLE); 188 rev = ti_mbox_reg_read(sc, TI_MBOX_REVISION); 189 DPRINTF("rev %d\n", rev); 190 device_printf(dev, "revision %d.%d\n", (rev >> 8) & 0x4, rev & 0x40); 191 /* 192 * Enable message interrupts. 193 */ 194 for (chan = 0; chan < 8; chan++) 195 ti_mbox_reg_write(sc, TI_MBOX_IRQENABLE_SET(chan), 1); 196 197 return (0); 198} 199 200static int 201ti_mbox_detach(device_t dev) 202{ 203 struct ti_mbox_softc *sc; 204 205 sc = device_get_softc(dev); 206 if (sc->sc_intr) 207 bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr); 208 if (sc->sc_irq_res) 209 bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->sc_irq_res), 210 sc->sc_irq_res); 211 if (sc->sc_mem_res) 212 bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_mem_res), 213 sc->sc_mem_res); 214 215 return (0); 216} 217 218static void 219ti_mbox_intr(void *arg) 220{ 221 struct ti_mbox_softc *sc; 222 223 sc = arg; 224 DPRINTF("interrupt %p", sc); 225} 226 227static int 228ti_mbox_read(device_t dev, int chan, uint32_t *data) 229{ 230 struct ti_mbox_softc *sc; 231 232 if (chan < 0 || chan > 7) 233 return (EINVAL); 234 sc = device_get_softc(dev); 235 236 return (ti_mbox_reg_read(sc, TI_MBOX_MESSAGE(chan))); 237} 238 239static int 240ti_mbox_write(device_t dev, int chan, uint32_t data) 241{ 242 int limit = 500; 243 struct ti_mbox_softc *sc; 244 245 if (chan < 0 || chan > 7) 246 return (EINVAL); 247 sc = device_get_softc(dev); 248 TI_MBOX_LOCK(sc); 249 /* XXX implement interrupt method */ 250 while (ti_mbox_reg_read(sc, TI_MBOX_FIFOSTATUS(chan)) == 1 && 251 limit--) { 252 DELAY(10); 253 } 254 if (limit == 0) { 255 device_printf(dev, "FIFOSTAUS%d stuck\n", chan); 256 TI_MBOX_UNLOCK(sc); 257 return (EAGAIN); 258 } 259 ti_mbox_reg_write(sc, TI_MBOX_MESSAGE(chan), data); 260 261 return (0); 262} 263