1274656Sbr/*- 2274656Sbr * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> 3274656Sbr * All rights reserved. 4274656Sbr * 5274656Sbr * This software was developed by SRI International and the University of 6274656Sbr * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7274656Sbr * ("CTSRD"), as part of the DARPA CRASH research programme. 8274656Sbr * 9274656Sbr * Redistribution and use in source and binary forms, with or without 10274656Sbr * modification, are permitted provided that the following conditions 11274656Sbr * are met: 12274656Sbr * 1. Redistributions of source code must retain the above copyright 13274656Sbr * notice, this list of conditions and the following disclaimer. 14274656Sbr * 2. Redistributions in binary form must reproduce the above copyright 15274656Sbr * notice, this list of conditions and the following disclaimer in the 16274656Sbr * documentation and/or other materials provided with the distribution. 17274656Sbr * 18274656Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19274656Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20274656Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21274656Sbr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22274656Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23274656Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24274656Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25274656Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26274656Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27274656Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28274656Sbr * SUCH DAMAGE. 29274656Sbr */ 30274656Sbr 31274656Sbr/* 32274656Sbr * Altera PIO (Parallel IO) device driver 33274656Sbr */ 34274656Sbr 35274656Sbr#include <sys/cdefs.h> 36274656Sbr__FBSDID("$FreeBSD: releng/11.0/sys/dev/altera/pio/pio.c 276670 2015-01-04 23:14:04Z br $"); 37274656Sbr 38274656Sbr#include <sys/param.h> 39274656Sbr#include <sys/systm.h> 40274656Sbr#include <sys/bus.h> 41274656Sbr#include <sys/kernel.h> 42274656Sbr#include <sys/module.h> 43274656Sbr#include <sys/malloc.h> 44274656Sbr#include <sys/rman.h> 45274656Sbr#include <sys/timeet.h> 46274656Sbr#include <sys/timetc.h> 47274656Sbr 48274656Sbr#include <dev/fdt/fdt_common.h> 49274656Sbr#include <dev/ofw/openfirm.h> 50274656Sbr#include <dev/ofw/ofw_bus.h> 51274656Sbr#include <dev/ofw/ofw_bus_subr.h> 52274656Sbr 53274656Sbr#include <machine/bus.h> 54274656Sbr#include <machine/fdt.h> 55274656Sbr#include <machine/cpu.h> 56274656Sbr 57274656Sbr#include <dev/altera/pio/pio.h> 58274656Sbr#include "pio_if.h" 59274656Sbr 60274656Sbr#define READ4(_sc, _reg) bus_read_4((_sc)->res[0], _reg) 61274656Sbr#define READ2(_sc, _reg) bus_read_2((_sc)->res[0], _reg) 62274656Sbr#define READ1(_sc, _reg) bus_read_1((_sc)->res[0], _reg) 63274656Sbr#define WRITE4(_sc, _reg, _val) bus_write_4((_sc)->res[0], _reg, _val) 64274656Sbr#define WRITE2(_sc, _reg, _val) bus_write_2((_sc)->res[0], _reg, _val) 65274656Sbr#define WRITE1(_sc, _reg, _val) bus_write_1((_sc)->res[0], _reg, _val) 66274656Sbr 67274656Sbrstruct pio_softc { 68274656Sbr struct resource *res[2]; 69274656Sbr bus_space_tag_t bst; 70274656Sbr bus_space_handle_t bsh; 71274656Sbr device_t dev; 72274656Sbr void *ih; 73274656Sbr}; 74274656Sbr 75274656Sbrstatic struct resource_spec pio_spec[] = { 76274656Sbr { SYS_RES_MEMORY, 0, RF_ACTIVE }, 77274656Sbr { SYS_RES_IRQ, 0, RF_ACTIVE }, 78274656Sbr { -1, 0 } 79274656Sbr}; 80274656Sbr 81274656Sbrstatic int 82274656Sbrpio_setup_irq(device_t dev, void *intr_handler, void *ih_user) 83274656Sbr{ 84274656Sbr struct pio_softc *sc; 85274656Sbr 86274656Sbr sc = device_get_softc(dev); 87274656Sbr 88274656Sbr /* Setup interrupt handlers */ 89274656Sbr if (bus_setup_intr(sc->dev, sc->res[1], INTR_TYPE_BIO | INTR_MPSAFE, 90274656Sbr NULL, intr_handler, ih_user, &sc->ih)) { 91274656Sbr device_printf(sc->dev, "Unable to setup intr\n"); 92274656Sbr return (1); 93274656Sbr } 94274656Sbr 95274656Sbr return (0); 96274656Sbr} 97274656Sbr 98274656Sbrstatic int 99274656Sbrpio_teardown_irq(device_t dev) 100274656Sbr{ 101274656Sbr struct pio_softc *sc; 102274656Sbr 103274656Sbr sc = device_get_softc(dev); 104274656Sbr 105274656Sbr bus_teardown_intr(sc->dev, sc->res[1], sc->ih); 106274656Sbr 107274656Sbr return (0); 108274656Sbr} 109274656Sbr 110274656Sbrstatic int 111274656Sbrpio_read(device_t dev) 112274656Sbr{ 113274656Sbr struct pio_softc *sc; 114274656Sbr 115274656Sbr sc = device_get_softc(dev); 116274656Sbr 117274656Sbr return (READ4(sc, PIO_DATA)); 118274656Sbr} 119274656Sbr 120274656Sbrstatic int 121274656Sbrpio_set(device_t dev, int bit, int enable) 122274656Sbr{ 123274656Sbr struct pio_softc *sc; 124274656Sbr 125274656Sbr sc = device_get_softc(dev); 126274656Sbr 127274656Sbr if (enable) 128274656Sbr WRITE4(sc, PIO_OUTSET, bit); 129274656Sbr else 130274656Sbr WRITE4(sc, PIO_OUTCLR, bit); 131274656Sbr 132274656Sbr return (0); 133274656Sbr} 134274656Sbr 135274656Sbrstatic int 136274656Sbrpio_configure(device_t dev, int dir, int mask) 137274656Sbr{ 138274656Sbr struct pio_softc *sc; 139274656Sbr 140274656Sbr sc = device_get_softc(dev); 141274656Sbr 142274656Sbr WRITE4(sc, PIO_INT_MASK, mask); 143274656Sbr WRITE4(sc, PIO_DIR, dir); 144274656Sbr 145274656Sbr return (0); 146274656Sbr} 147274656Sbr 148274656Sbrstatic int 149274656Sbrpio_probe(device_t dev) 150274656Sbr{ 151274656Sbr 152274656Sbr if (!ofw_bus_status_okay(dev)) 153274656Sbr return (ENXIO); 154274656Sbr 155274656Sbr if (!ofw_bus_is_compatible(dev, "altr,pio")) 156274656Sbr return (ENXIO); 157274656Sbr 158274656Sbr device_set_desc(dev, "Altera PIO"); 159274656Sbr return (BUS_PROBE_DEFAULT); 160274656Sbr} 161274656Sbr 162274656Sbrstatic int 163274656Sbrpio_attach(device_t dev) 164274656Sbr{ 165274656Sbr struct pio_softc *sc; 166274656Sbr struct fdt_ic *fic; 167274656Sbr phandle_t node; 168274656Sbr 169274656Sbr sc = device_get_softc(dev); 170274656Sbr sc->dev = dev; 171274656Sbr 172274656Sbr if (bus_alloc_resources(dev, pio_spec, sc->res)) { 173274656Sbr device_printf(dev, "could not allocate resources\n"); 174274656Sbr return (ENXIO); 175274656Sbr } 176274656Sbr 177274656Sbr /* Memory interface */ 178274656Sbr sc->bst = rman_get_bustag(sc->res[0]); 179274656Sbr sc->bsh = rman_get_bushandle(sc->res[0]); 180274656Sbr 181274656Sbr if ((node = ofw_bus_get_node(sc->dev)) == -1) 182274656Sbr return (ENXIO); 183274656Sbr 184274656Sbr fic = malloc(sizeof(*fic), M_DEVBUF, M_WAITOK|M_ZERO); 185274656Sbr fic->iph = node; 186274656Sbr fic->dev = dev; 187274656Sbr SLIST_INSERT_HEAD(&fdt_ic_list_head, fic, fdt_ics); 188274656Sbr 189274656Sbr return (0); 190274656Sbr} 191274656Sbr 192274656Sbrstatic device_method_t pio_methods[] = { 193274656Sbr DEVMETHOD(device_probe, pio_probe), 194274656Sbr DEVMETHOD(device_attach, pio_attach), 195274656Sbr 196274656Sbr /* pio_if.m */ 197274656Sbr DEVMETHOD(pio_read, pio_read), 198274656Sbr DEVMETHOD(pio_configure, pio_configure), 199274656Sbr DEVMETHOD(pio_set, pio_set), 200274656Sbr DEVMETHOD(pio_setup_irq, pio_setup_irq), 201274656Sbr DEVMETHOD(pio_teardown_irq, pio_teardown_irq), 202274656Sbr DEVMETHOD_END 203274656Sbr}; 204274656Sbr 205274656Sbrstatic driver_t pio_driver = { 206274656Sbr "altera_pio", 207274656Sbr pio_methods, 208274656Sbr sizeof(struct pio_softc), 209274656Sbr}; 210274656Sbr 211274656Sbrstatic devclass_t pio_devclass; 212274656Sbr 213274656SbrDRIVER_MODULE(altera_pio, simplebus, pio_driver, pio_devclass, 0, 0); 214