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