1*1f40866fSVal Packett /*- 2*1f40866fSVal Packett * SPDX-License-Identifier: BSD-2-Clause 3*1f40866fSVal Packett * 4*1f40866fSVal Packett * Copyright (c) 2021 Val Packett <val@packett.cool> 5*1f40866fSVal Packett * 6*1f40866fSVal Packett * Redistribution and use in source and binary forms, with or without 7*1f40866fSVal Packett * modification, are permitted provided that the following conditions 8*1f40866fSVal Packett * are met: 9*1f40866fSVal Packett * 1. Redistributions of source code must retain the above copyright 10*1f40866fSVal Packett * notice, this list of conditions and the following disclaimer. 11*1f40866fSVal Packett * 2. Redistributions in binary form must reproduce the above copyright 12*1f40866fSVal Packett * notice, this list of conditions and the following disclaimer in the 13*1f40866fSVal Packett * documentation and/or other materials provided with the distribution. 14*1f40866fSVal Packett * 15*1f40866fSVal Packett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*1f40866fSVal Packett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*1f40866fSVal Packett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*1f40866fSVal Packett * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*1f40866fSVal Packett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*1f40866fSVal Packett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*1f40866fSVal Packett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*1f40866fSVal Packett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*1f40866fSVal Packett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*1f40866fSVal Packett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*1f40866fSVal Packett * SUCH DAMAGE. 26*1f40866fSVal Packett */ 27*1f40866fSVal Packett 28*1f40866fSVal Packett #include "opt_acpi.h" 29*1f40866fSVal Packett #include "opt_pci.h" 30*1f40866fSVal Packett 31*1f40866fSVal Packett #include <sys/cdefs.h> 32*1f40866fSVal Packett #include <sys/param.h> 33*1f40866fSVal Packett #include <sys/bus.h> 34*1f40866fSVal Packett #include <sys/kernel.h> 35*1f40866fSVal Packett #include <sys/module.h> 36*1f40866fSVal Packett #include <sys/proc.h> 37*1f40866fSVal Packett #include <sys/rman.h> 38*1f40866fSVal Packett 39*1f40866fSVal Packett #include <dev/intel/spi.h> 40*1f40866fSVal Packett #include <dev/pci/pcireg.h> 41*1f40866fSVal Packett #include <dev/pci/pcivar.h> 42*1f40866fSVal Packett 43*1f40866fSVal Packett #include "spibus_if.h" 44*1f40866fSVal Packett 45*1f40866fSVal Packett static struct intelspi_pci_device { 46*1f40866fSVal Packett uint32_t devid; 47*1f40866fSVal Packett enum intelspi_vers vers; 48*1f40866fSVal Packett } intelspi_pci_devices[] = { 49*1f40866fSVal Packett { 0x9c658086, SPI_LYNXPOINT }, 50*1f40866fSVal Packett { 0x9c668086, SPI_LYNXPOINT }, 51*1f40866fSVal Packett { 0x9ce58086, SPI_LYNXPOINT }, 52*1f40866fSVal Packett { 0x9ce68086, SPI_LYNXPOINT }, 53*1f40866fSVal Packett { 0x9d298086, SPI_SUNRISEPOINT }, 54*1f40866fSVal Packett { 0x9d2a8086, SPI_SUNRISEPOINT }, 55*1f40866fSVal Packett { 0xa1298086, SPI_SUNRISEPOINT }, 56*1f40866fSVal Packett { 0xa12a8086, SPI_SUNRISEPOINT }, 57*1f40866fSVal Packett { 0xa2a98086, SPI_SUNRISEPOINT }, 58*1f40866fSVal Packett { 0xa2aa8086, SPI_SUNRISEPOINT }, 59*1f40866fSVal Packett { 0xa3a98086, SPI_SUNRISEPOINT }, 60*1f40866fSVal Packett { 0xa3aa8086, SPI_SUNRISEPOINT }, 61*1f40866fSVal Packett }; 62*1f40866fSVal Packett 63*1f40866fSVal Packett static int 64*1f40866fSVal Packett intelspi_pci_probe(device_t dev) 65*1f40866fSVal Packett { 66*1f40866fSVal Packett struct intelspi_softc *sc = device_get_softc(dev); 67*1f40866fSVal Packett uint32_t devid = pci_get_devid(dev); 68*1f40866fSVal Packett int i; 69*1f40866fSVal Packett 70*1f40866fSVal Packett for (i = 0; i < nitems(intelspi_pci_devices); i++) { 71*1f40866fSVal Packett if (intelspi_pci_devices[i].devid == devid) { 72*1f40866fSVal Packett sc->sc_vers = intelspi_pci_devices[i].vers; 73*1f40866fSVal Packett /* The PCI device is listed in ACPI too. 74*1f40866fSVal Packett * Not that we use the handle for anything... */ 75*1f40866fSVal Packett sc->sc_handle = acpi_get_handle(dev); 76*1f40866fSVal Packett device_set_desc(dev, intelspi_infos[sc->sc_vers].desc); 77*1f40866fSVal Packett return (BUS_PROBE_DEFAULT); 78*1f40866fSVal Packett } 79*1f40866fSVal Packett } 80*1f40866fSVal Packett 81*1f40866fSVal Packett return (ENXIO); 82*1f40866fSVal Packett } 83*1f40866fSVal Packett 84*1f40866fSVal Packett static int 85*1f40866fSVal Packett intelspi_pci_attach(device_t dev) 86*1f40866fSVal Packett { 87*1f40866fSVal Packett struct intelspi_softc *sc = device_get_softc(dev); 88*1f40866fSVal Packett 89*1f40866fSVal Packett sc->sc_mem_rid = PCIR_BAR(0); 90*1f40866fSVal Packett sc->sc_irq_rid = 0; 91*1f40866fSVal Packett if (pci_alloc_msi(dev, &sc->sc_irq_rid)) { 92*1f40866fSVal Packett device_printf(dev, "Using MSI\n"); 93*1f40866fSVal Packett } 94*1f40866fSVal Packett 95*1f40866fSVal Packett return (intelspi_attach(dev)); 96*1f40866fSVal Packett } 97*1f40866fSVal Packett 98*1f40866fSVal Packett static int 99*1f40866fSVal Packett intelspi_pci_detach(device_t dev) 100*1f40866fSVal Packett { 101*1f40866fSVal Packett struct intelspi_softc *sc = device_get_softc(dev); 102*1f40866fSVal Packett int err; 103*1f40866fSVal Packett 104*1f40866fSVal Packett err = intelspi_detach(dev); 105*1f40866fSVal Packett if (err) 106*1f40866fSVal Packett return (err); 107*1f40866fSVal Packett 108*1f40866fSVal Packett if (sc->sc_irq_rid != 0) 109*1f40866fSVal Packett pci_release_msi(dev); 110*1f40866fSVal Packett 111*1f40866fSVal Packett return (0); 112*1f40866fSVal Packett } 113*1f40866fSVal Packett 114*1f40866fSVal Packett static device_method_t intelspi_pci_methods[] = { 115*1f40866fSVal Packett /* Device interface */ 116*1f40866fSVal Packett DEVMETHOD(device_probe, intelspi_pci_probe), 117*1f40866fSVal Packett DEVMETHOD(device_attach, intelspi_pci_attach), 118*1f40866fSVal Packett DEVMETHOD(device_detach, intelspi_pci_detach), 119*1f40866fSVal Packett DEVMETHOD(device_suspend, intelspi_suspend), 120*1f40866fSVal Packett DEVMETHOD(device_resume, intelspi_resume), 121*1f40866fSVal Packett 122*1f40866fSVal Packett /* SPI interface */ 123*1f40866fSVal Packett DEVMETHOD(spibus_transfer, intelspi_transfer), 124*1f40866fSVal Packett 125*1f40866fSVal Packett DEVMETHOD_END 126*1f40866fSVal Packett }; 127*1f40866fSVal Packett 128*1f40866fSVal Packett static driver_t intelspi_pci_driver = { 129*1f40866fSVal Packett "spi", 130*1f40866fSVal Packett intelspi_pci_methods, 131*1f40866fSVal Packett sizeof(struct intelspi_softc), 132*1f40866fSVal Packett }; 133*1f40866fSVal Packett 134*1f40866fSVal Packett DRIVER_MODULE(intelspi, pci, intelspi_pci_driver, 0, 0); 135*1f40866fSVal Packett MODULE_DEPEND(intelspi, pci, 1, 1, 1); 136*1f40866fSVal Packett MODULE_DEPEND(intelspi, spibus, 1, 1, 1); 137*1f40866fSVal Packett MODULE_PNP_INFO("W32:vendor/device", pci, intelspi, intelspi_pci_devices, 138*1f40866fSVal Packett nitems(intelspi_pci_devices)); 139