1262885Sbr/*- 2262885Sbr * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> 3262885Sbr * All rights reserved. 4262885Sbr * 5262885Sbr * Redistribution and use in source and binary forms, with or without 6262885Sbr * modification, are permitted provided that the following conditions 7262885Sbr * are met: 8262885Sbr * 1. Redistributions of source code must retain the above copyright 9262885Sbr * notice, this list of conditions and the following disclaimer. 10262885Sbr * 2. Redistributions in binary form must reproduce the above copyright 11262885Sbr * notice, this list of conditions and the following disclaimer in the 12262885Sbr * documentation and/or other materials provided with the distribution. 13262885Sbr * 14262885Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15262885Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16262885Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17262885Sbr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18262885Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19262885Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20262885Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21262885Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22262885Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23262885Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24262885Sbr * SUCH DAMAGE. 25262885Sbr */ 26262885Sbr 27262885Sbr/* 28262885Sbr * Vybrid Family Port control and interrupts (PORT) 29262885Sbr * Chapter 6, Vybrid Reference Manual, Rev. 5, 07/2013 30262885Sbr */ 31262885Sbr 32262885Sbr#include <sys/cdefs.h> 33262885Sbr__FBSDID("$FreeBSD: releng/11.0/sys/arm/freescale/vybrid/vf_port.c 297793 2016-04-10 23:07:00Z pfg $"); 34262885Sbr 35262885Sbr#include <sys/param.h> 36262885Sbr#include <sys/systm.h> 37262885Sbr#include <sys/bus.h> 38262885Sbr#include <sys/kernel.h> 39262885Sbr#include <sys/module.h> 40262885Sbr#include <sys/malloc.h> 41262885Sbr#include <sys/rman.h> 42262885Sbr#include <sys/timeet.h> 43262885Sbr#include <sys/timetc.h> 44262885Sbr#include <sys/watchdog.h> 45262885Sbr 46262885Sbr#include <dev/fdt/fdt_common.h> 47262885Sbr#include <dev/ofw/openfirm.h> 48262885Sbr#include <dev/ofw/ofw_bus.h> 49262885Sbr#include <dev/ofw/ofw_bus_subr.h> 50262885Sbr 51262885Sbr#include <machine/bus.h> 52262885Sbr#include <machine/cpu.h> 53262885Sbr#include <machine/intr.h> 54262885Sbr 55262885Sbr#include <arm/freescale/vybrid/vf_port.h> 56262885Sbr#include <arm/freescale/vybrid/vf_common.h> 57262885Sbr 58262885Sbr/* Pin Control Register */ 59262885Sbr#define PORT_PCR(n) (0x1000 * (n >> 5) + 0x4 * (n % 32)) 60262885Sbr#define PCR_IRQC_S 16 61262885Sbr#define PCR_IRQC_M 0xF 62262885Sbr#define PCR_DMA_RE 0x1 63262885Sbr#define PCR_DMA_FE 0x2 64262885Sbr#define PCR_DMA_EE 0x3 65262885Sbr#define PCR_INT_LZ 0x8 66262885Sbr#define PCR_INT_RE 0x9 67262885Sbr#define PCR_INT_FE 0xA 68262885Sbr#define PCR_INT_EE 0xB 69262885Sbr#define PCR_INT_LO 0xC 70262885Sbr#define PCR_ISF (1 << 24) 71262885Sbr#define PORT0_ISFR 0xA0 /* Interrupt Status Flag Register */ 72262885Sbr#define PORT0_DFER 0xC0 /* Digital Filter Enable Register */ 73262885Sbr#define PORT0_DFCR 0xC4 /* Digital Filter Clock Register */ 74262885Sbr#define PORT0_DFWR 0xC8 /* Digital Filter Width Register */ 75262885Sbr 76262885Sbrstruct port_event { 77262885Sbr uint32_t enabled; 78262885Sbr uint32_t mux_num; 79262885Sbr uint32_t mux_src; 80262885Sbr uint32_t mux_chn; 81262885Sbr void (*ih) (void *); 82262885Sbr void *ih_user; 83262885Sbr enum ev_type pevt; 84262885Sbr}; 85262885Sbr 86262885Sbrstatic struct port_event event_map[NGPIO]; 87262885Sbr 88262885Sbrstruct port_softc { 89262885Sbr struct resource *res[6]; 90262885Sbr bus_space_tag_t bst; 91262885Sbr bus_space_handle_t bsh; 92262885Sbr void *gpio_ih[NGPIO]; 93262885Sbr}; 94262885Sbr 95262885Sbrstruct port_softc *port_sc; 96262885Sbr 97262885Sbrstatic struct resource_spec port_spec[] = { 98262885Sbr { SYS_RES_MEMORY, 0, RF_ACTIVE }, 99262885Sbr { SYS_RES_IRQ, 0, RF_ACTIVE }, 100262885Sbr { SYS_RES_IRQ, 1, RF_ACTIVE }, 101262885Sbr { SYS_RES_IRQ, 2, RF_ACTIVE }, 102262885Sbr { SYS_RES_IRQ, 3, RF_ACTIVE }, 103262885Sbr { SYS_RES_IRQ, 4, RF_ACTIVE }, 104262885Sbr { -1, 0 } 105262885Sbr}; 106262885Sbr 107262885Sbrstatic int 108262885Sbrport_intr(void *arg) 109262885Sbr{ 110262885Sbr struct port_event *pev; 111262885Sbr struct port_softc *sc; 112262885Sbr int reg; 113262885Sbr int i; 114262885Sbr 115262885Sbr sc = arg; 116262885Sbr 117262885Sbr for (i = 0; i < NGPIO; i++) { 118262885Sbr reg = READ4(sc, PORT_PCR(i)); 119262885Sbr if (reg & PCR_ISF) { 120262885Sbr 121262885Sbr /* Clear interrupt */ 122262885Sbr WRITE4(sc, PORT_PCR(i), reg); 123262885Sbr 124262885Sbr /* Handle event */ 125262885Sbr pev = &event_map[i]; 126262885Sbr if (pev->enabled == 1) { 127262885Sbr if (pev->ih != NULL) { 128262885Sbr pev->ih(pev->ih_user); 129262885Sbr } 130262885Sbr } 131262885Sbr } 132262885Sbr } 133262885Sbr 134262885Sbr return (FILTER_HANDLED); 135262885Sbr} 136262885Sbr 137262885Sbrint 138262885Sbrport_setup(int pnum, enum ev_type pevt, void (*ih)(void *), void *ih_user) 139262885Sbr{ 140262885Sbr struct port_event *pev; 141262885Sbr struct port_softc *sc; 142262885Sbr int reg; 143262885Sbr int val; 144262885Sbr 145262885Sbr sc = port_sc; 146262885Sbr 147262885Sbr switch (pevt) { 148262885Sbr case DMA_RISING_EDGE: 149262885Sbr val = PCR_DMA_RE; 150262885Sbr break; 151262885Sbr case DMA_FALLING_EDGE: 152262885Sbr val = PCR_DMA_FE; 153262885Sbr break; 154262885Sbr case DMA_EITHER_EDGE: 155262885Sbr val = PCR_DMA_EE; 156262885Sbr break; 157262885Sbr case INT_LOGIC_ZERO: 158262885Sbr val = PCR_INT_LZ; 159262885Sbr break; 160262885Sbr case INT_RISING_EDGE: 161262885Sbr val = PCR_INT_RE; 162262885Sbr break; 163262885Sbr case INT_FALLING_EDGE: 164262885Sbr val = PCR_INT_FE; 165262885Sbr break; 166262885Sbr case INT_EITHER_EDGE: 167266021Sbr val = PCR_INT_EE; 168262885Sbr break; 169262885Sbr case INT_LOGIC_ONE: 170262885Sbr val = PCR_INT_LO; 171262885Sbr break; 172262885Sbr default: 173262885Sbr return (-1); 174297793Spfg } 175262885Sbr 176262885Sbr reg = READ4(sc, PORT_PCR(pnum)); 177262885Sbr reg &= ~(PCR_IRQC_M << PCR_IRQC_S); 178262885Sbr reg |= (val << PCR_IRQC_S); 179262885Sbr WRITE4(sc, PORT_PCR(pnum), reg); 180262885Sbr 181262885Sbr pev = &event_map[pnum]; 182262885Sbr pev->ih = ih; 183262885Sbr pev->ih_user = ih_user; 184262885Sbr pev->pevt = pevt; 185262885Sbr pev->enabled = 1; 186262885Sbr 187262885Sbr return (0); 188262885Sbr} 189262885Sbr 190262885Sbrstatic int 191262885Sbrport_probe(device_t dev) 192262885Sbr{ 193262885Sbr 194262885Sbr if (!ofw_bus_status_okay(dev)) 195262885Sbr return (ENXIO); 196262885Sbr 197262885Sbr if (!ofw_bus_is_compatible(dev, "fsl,mvf600-port")) 198262885Sbr return (ENXIO); 199262885Sbr 200262885Sbr device_set_desc(dev, "Vybrid Family Port control and interrupts"); 201262885Sbr return (BUS_PROBE_DEFAULT); 202262885Sbr} 203262885Sbr 204262885Sbrstatic int 205262885Sbrport_attach(device_t dev) 206262885Sbr{ 207262885Sbr struct port_softc *sc; 208262885Sbr int irq; 209262885Sbr 210262885Sbr sc = device_get_softc(dev); 211262885Sbr 212262885Sbr if (bus_alloc_resources(dev, port_spec, sc->res)) { 213262885Sbr device_printf(dev, "could not allocate resources\n"); 214262885Sbr return (ENXIO); 215262885Sbr } 216262885Sbr 217262885Sbr /* Memory interface */ 218262885Sbr sc->bst = rman_get_bustag(sc->res[0]); 219262885Sbr sc->bsh = rman_get_bushandle(sc->res[0]); 220262885Sbr 221262885Sbr port_sc = sc; 222262885Sbr 223262885Sbr for (irq = 0; irq < NPORTS; irq ++) { 224262885Sbr if ((bus_setup_intr(dev, sc->res[1 + irq], INTR_TYPE_MISC, 225262885Sbr port_intr, NULL, sc, &sc->gpio_ih[irq]))) { 226262885Sbr device_printf(dev, 227262885Sbr "ERROR: Unable to register interrupt handler\n"); 228262885Sbr return (ENXIO); 229262885Sbr } 230262885Sbr } 231262885Sbr 232262885Sbr return (0); 233262885Sbr} 234262885Sbr 235262885Sbrstatic device_method_t port_methods[] = { 236262885Sbr DEVMETHOD(device_probe, port_probe), 237262885Sbr DEVMETHOD(device_attach, port_attach), 238262885Sbr { 0, 0 } 239262885Sbr}; 240262885Sbr 241262885Sbrstatic driver_t port_driver = { 242262885Sbr "port", 243262885Sbr port_methods, 244262885Sbr sizeof(struct port_softc), 245262885Sbr}; 246262885Sbr 247262885Sbrstatic devclass_t port_devclass; 248262885Sbr 249262885SbrDRIVER_MODULE(port, simplebus, port_driver, port_devclass, 0, 0); 250