ti_pruss.c revision 277958
1114402Sru/*- 2151497Sru * Copyright (c) 2013 Rui Paulo <rpaulo@FreeBSD.org> 3114402Sru * All rights reserved. 4114402Sru * 5114402Sru * Redistribution and use in source and binary forms, with or without 6114402Sru * modification, are permitted provided that the following conditions 7114402Sru * are met: 8114402Sru * 1. Redistributions of source code must retain the above copyright 9114402Sru * notice, this list of conditions and the following disclaimer. 10114402Sru * 2. Redistributions in binary form must reproduce the above copyright 11114402Sru * notice, this list of conditions and the following disclaimer in the 12114402Sru * documentation and/or other materials provided with the distribution. 13114402Sru * 14114402Sru * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15114402Sru * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16114402Sru * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17114402Sru * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 18114402Sru * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19151497Sru * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20114402Sru * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21114402Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22114402Sru * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 23114402Sru * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24114402Sru * POSSIBILITY OF SUCH DAMAGE. 25114402Sru */ 26114402Sru#include <sys/cdefs.h> 27114402Sru__FBSDID("$FreeBSD: head/sys/arm/ti/ti_pruss.c 277958 2015-01-31 02:12:57Z rpaulo $"); 28114402Sru 29114402Sru#include <sys/param.h> 30114402Sru#include <sys/systm.h> 31114402Sru#include <sys/bus.h> 32114402Sru#include <sys/conf.h> 33114402Sru#include <sys/kernel.h> 34114402Sru#include <sys/module.h> 35114402Sru#include <sys/malloc.h> 36114402Sru#include <sys/rman.h> 37151497Sru#include <sys/event.h> 38114402Sru#include <sys/selinfo.h> 39114402Sru#include <machine/bus.h> 40114402Sru#include <machine/cpu.h> 41114402Sru#include <machine/frame.h> 42114402Sru#include <machine/intr.h> 43151497Sru 44114402Sru#include <dev/fdt/fdt_common.h> 45114402Sru#include <dev/ofw/openfirm.h> 46114402Sru#include <dev/ofw/ofw_bus.h> 47151497Sru#include <dev/ofw/ofw_bus_subr.h> 48151497Sru 49114402Sru#include <machine/bus.h> 50151497Sru#include <machine/fdt.h> 51114402Sru 52114402Sru#include <arm/ti/ti_prcm.h> 53114402Sru#include <arm/ti/ti_pruss.h> 54114402Sru 55114402Sru#ifdef DEBUG 56114402Sru#define DPRINTF(fmt, ...) do { \ 57151497Sru printf("%s: ", __func__); \ 58151497Sru printf(fmt, __VA_ARGS__); \ 59151497Sru} while (0) 60151497Sru#else 61151497Sru#define DPRINTF(fmt, ...) 62151497Sru#endif 63151497Sru 64151497Srustatic device_probe_t ti_pruss_probe; 65151497Srustatic device_attach_t ti_pruss_attach; 66151497Srustatic device_detach_t ti_pruss_detach; 67151497Srustatic void ti_pruss_intr(void *); 68151497Srustatic d_open_t ti_pruss_open; 69151497Srustatic d_mmap_t ti_pruss_mmap; 70151497Srustatic void ti_pruss_kq_read_detach(struct knote *); 71151497Srustatic int ti_pruss_kq_read_event(struct knote *, long); 72151497Srustatic d_kqfilter_t ti_pruss_kqfilter; 73151497Sru 74151497Sru#define TI_PRUSS_IRQS 8 75151497Srustruct ti_pruss_softc { 76151497Sru struct mtx sc_mtx; 77151497Sru struct resource *sc_mem_res; 78151497Sru struct resource *sc_irq_res[TI_PRUSS_IRQS]; 79151497Sru void *sc_intr[TI_PRUSS_IRQS]; 80151497Sru bus_space_tag_t sc_bt; 81151497Sru bus_space_handle_t sc_bh; 82151497Sru struct cdev *sc_pdev; 83151497Sru struct selinfo sc_selinfo; 84151497Sru}; 85151497Sru 86151497Srustatic struct cdevsw ti_pruss_cdevsw = { 87151497Sru .d_version = D_VERSION, 88151497Sru .d_name = "ti_pruss", 89151497Sru .d_open = ti_pruss_open, 90151497Sru .d_mmap = ti_pruss_mmap, 91151497Sru .d_kqfilter = ti_pruss_kqfilter, 92151497Sru}; 93151497Sru 94151497Srustatic device_method_t ti_pruss_methods[] = { 95151497Sru DEVMETHOD(device_probe, ti_pruss_probe), 96151497Sru DEVMETHOD(device_attach, ti_pruss_attach), 97151497Sru DEVMETHOD(device_detach, ti_pruss_detach), 98151497Sru 99151497Sru DEVMETHOD_END 100151497Sru}; 101151497Sru 102151497Srustatic driver_t ti_pruss_driver = { 103151497Sru "ti_pruss", 104151497Sru ti_pruss_methods, 105151497Sru sizeof(struct ti_pruss_softc) 106151497Sru}; 107151497Sru 108151497Srustatic devclass_t ti_pruss_devclass; 109151497Sru 110151497SruDRIVER_MODULE(ti_pruss, simplebus, ti_pruss_driver, ti_pruss_devclass, 0, 0); 111151497Sru 112151497Srustatic struct resource_spec ti_pruss_irq_spec[] = { 113151497Sru { SYS_RES_IRQ, 0, RF_ACTIVE }, 114151497Sru { SYS_RES_IRQ, 1, RF_ACTIVE }, 115151497Sru { SYS_RES_IRQ, 2, RF_ACTIVE }, 116151497Sru { SYS_RES_IRQ, 3, RF_ACTIVE }, 117151497Sru { SYS_RES_IRQ, 4, RF_ACTIVE }, 118151497Sru { SYS_RES_IRQ, 5, RF_ACTIVE }, 119151497Sru { SYS_RES_IRQ, 6, RF_ACTIVE }, 120151497Sru { SYS_RES_IRQ, 7, RF_ACTIVE }, 121151497Sru { -1, 0, 0 } 122151497Sru}; 123151497Sru 124151497Srustatic struct ti_pruss_irq_arg { 125151497Sru int irq; 126151497Sru struct ti_pruss_softc *sc; 127151497Sru} ti_pruss_irq_args[TI_PRUSS_IRQS]; 128151497Sru 129151497Srustatic __inline uint32_t 130151497Sruti_pruss_reg_read(struct ti_pruss_softc *sc, uint32_t reg) 131151497Sru{ 132151497Sru return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg)); 133151497Sru} 134151497Sru 135151497Srustatic __inline void 136151497Sruti_pruss_reg_write(struct ti_pruss_softc *sc, uint32_t reg, uint32_t val) 137151497Sru{ 138151497Sru bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val); 139114402Sru} 140114402Sru 141114402Srustatic int 142114402Sruti_pruss_probe(device_t dev) 143114402Sru{ 144114402Sru 145151497Sru if (!ofw_bus_status_okay(dev)) 146151497Sru return (ENXIO); 147151497Sru 148151497Sru if (ofw_bus_is_compatible(dev, "ti,pruss-v1") || 149114402Sru ofw_bus_is_compatible(dev, "ti,pruss-v2")) { 150151497Sru device_set_desc(dev, "TI Programmable Realtime Unit Subsystem"); 151151497Sru return (BUS_PROBE_DEFAULT); 152151497Sru } 153151497Sru 154151497Sru return (ENXIO); 155114402Sru} 156114402Sru 157114402Srustatic int 158114402Sruti_pruss_attach(device_t dev) 159114402Sru{ 160114402Sru struct ti_pruss_softc *sc; 161114402Sru int rid, i; 162114402Sru 163114402Sru if (ti_prcm_clk_enable(PRUSS_CLK) != 0) { 164151497Sru device_printf(dev, "could not enable PRUSS clock\n"); 165114402Sru return (ENXIO); 166114402Sru } 167114402Sru sc = device_get_softc(dev); 168151497Sru rid = 0; 169114402Sru mtx_init(&sc->sc_mtx, "TI PRUSS", NULL, MTX_DEF); 170114402Sru sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 171151497Sru RF_ACTIVE); 172114402Sru if (sc->sc_mem_res == NULL) { 173114402Sru device_printf(dev, "could not allocate memory resource\n"); 174151497Sru return (ENXIO); 175151497Sru } 176151497Sru sc->sc_bt = rman_get_bustag(sc->sc_mem_res); 177114402Sru sc->sc_bh = rman_get_bushandle(sc->sc_mem_res); 178151497Sru if (bus_alloc_resources(dev, ti_pruss_irq_spec, sc->sc_irq_res) != 0) { 179151497Sru device_printf(dev, "could not allocate interrupt resource\n"); 180151497Sru ti_pruss_detach(dev); 181151497Sru return (ENXIO); 182151497Sru } 183151497Sru for (i = 0; i < TI_PRUSS_IRQS; i++) { 184151497Sru ti_pruss_irq_args[i].irq = i; 185151497Sru ti_pruss_irq_args[i].sc = sc; 186151497Sru if (bus_setup_intr(dev, sc->sc_irq_res[i], 187151497Sru INTR_MPSAFE | INTR_TYPE_MISC, 188151497Sru NULL, ti_pruss_intr, &ti_pruss_irq_args[i], 189151497Sru &sc->sc_intr[i]) != 0) { 190114402Sru device_printf(dev, 191151497Sru "unable to setup the interrupt handler\n"); 192151497Sru ti_pruss_detach(dev); 193151497Sru return (ENXIO); 194151497Sru } 195151497Sru } 196151497Sru if (ti_pruss_reg_read(sc, PRUSS_AM18XX_INTC) == PRUSS_AM18XX_REV) 197151497Sru device_printf(dev, "AM18xx PRU-ICSS\n"); 198151497Sru else if (ti_pruss_reg_read(sc, PRUSS_AM33XX_INTC) == PRUSS_AM33XX_REV) 199151497Sru device_printf(dev, "AM33xx PRU-ICSS\n"); 200151497Sru 201151497Sru sc->sc_pdev = make_dev(&ti_pruss_cdevsw, 0, UID_ROOT, GID_WHEEL, 202151497Sru 0600, "pruss%d", device_get_unit(dev)); 203151497Sru sc->sc_pdev->si_drv1 = dev; 204114402Sru 205151497Sru return (0); 206151497Sru} 207151497Sru 208151497Srustatic int 209151497Sruti_pruss_detach(device_t dev) 210114402Sru{ 211114402Sru struct ti_pruss_softc *sc; 212151497Sru int i; 213114402Sru 214151497Sru sc = device_get_softc(dev); 215114402Sru for (i = 0; i < TI_PRUSS_IRQS; i++) { 216114402Sru if (sc->sc_intr[i]) 217114402Sru bus_teardown_intr(dev, sc->sc_irq_res[i], sc->sc_intr[i]); 218114402Sru if (sc->sc_irq_res[i]) 219114402Sru bus_release_resource(dev, SYS_RES_IRQ, 220114402Sru rman_get_rid(sc->sc_irq_res[i]), 221151497Sru sc->sc_irq_res[i]); 222114402Sru } 223151497Sru if (sc->sc_mem_res) 224114402Sru bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_mem_res), 225114402Sru sc->sc_mem_res); 226114402Sru if (sc->sc_pdev) 227114402Sru destroy_dev(sc->sc_pdev); 228151497Sru 229114402Sru return (0); 230151497Sru} 231151497Sru 232114402Srustatic void 233114402Sruti_pruss_intr(void *arg) 234151497Sru{ 235114402Sru struct ti_pruss_irq_arg *iap; 236114402Sru struct ti_pruss_softc *sc; 237114402Sru 238114402Sru iap = arg; 239114402Sru sc = iap->sc; 240151497Sru DPRINTF("interrupt %p", sc); 241151497Sru KNOTE_UNLOCKED(&sc->sc_selinfo.si_note, iap->irq); 242114402Sru} 243114402Sru 244151497Srustatic int 245114402Sruti_pruss_open(struct cdev *cdev __unused, int oflags __unused, 246114402Sru int devtype __unused, struct thread *td __unused) 247114402Sru{ 248114402Sru return (0); 249114402Sru} 250114402Sru 251114402Srustatic int 252114402Sruti_pruss_mmap(struct cdev *cdev, vm_ooffset_t offset, vm_paddr_t *paddr, 253114402Sru int nprot, vm_memattr_t *memattr) 254114402Sru{ 255114402Sru device_t dev = cdev->si_drv1; 256114402Sru struct ti_pruss_softc *sc = device_get_softc(dev); 257114402Sru 258114402Sru if (offset > rman_get_size(sc->sc_mem_res)) 259114402Sru return (-1); 260114402Sru *paddr = rman_get_start(sc->sc_mem_res) + offset; 261114402Sru *memattr = VM_MEMATTR_UNCACHEABLE; 262114402Sru 263114402Sru return (0); 264114402Sru} 265114402Sru 266114402Srustatic struct filterops ti_pruss_kq_read = { 267114402Sru .f_isfd = 1, 268114402Sru .f_detach = ti_pruss_kq_read_detach, 269114402Sru .f_event = ti_pruss_kq_read_event, 270114402Sru}; 271114402Sru 272114402Srustatic void 273114402Sruti_pruss_kq_read_detach(struct knote *kn) 274114402Sru{ 275114402Sru struct ti_pruss_softc *sc = kn->kn_hook; 276114402Sru 277114402Sru knlist_remove(&sc->sc_selinfo.si_note, kn, 0); 278114402Sru} 279114402Sru 280114402Srustatic int 281114402Sruti_pruss_kq_read_event(struct knote *kn, long hint) 282114402Sru{ 283114402Sru kn->kn_data = hint; 284114402Sru 285151497Sru return (hint); 286114402Sru} 287114402Sru 288151497Srustatic int 289114402Sruti_pruss_kqfilter(struct cdev *cdev, struct knote *kn) 290114402Sru{ 291114402Sru device_t dev = cdev->si_drv1; 292114402Sru struct ti_pruss_softc *sc = device_get_softc(dev); 293114402Sru 294114402Sru switch (kn->kn_filter) { 295114402Sru case EVFILT_READ: 296114402Sru kn->kn_hook = sc; 297114402Sru kn->kn_fop = &ti_pruss_kq_read; 298114402Sru knlist_add(&sc->sc_selinfo.si_note, kn, 1); 299114402Sru break; 300114402Sru default: 301114402Sru return (EINVAL); 302114402Sru } 303114402Sru 304114402Sru return (0); 305114402Sru} 306114402Sru