diff --git a/sys/conf/files.x86 b/sys/conf/files.x86 --- a/sys/conf/files.x86 +++ b/sys/conf/files.x86 @@ -144,6 +144,8 @@ dev/imcsmb/imcsmb.c optional imcsmb dev/imcsmb/imcsmb_pci.c optional imcsmb pci dev/intel/spi.c optional intelspi +dev/intel/spi_pci.c optional intelspi pci +dev/intel/spi_acpi.c optional intelspi acpi dev/io/iodev.c optional io dev/iommu/busdma_iommu.c optional acpi iommu pci dev/iommu/iommu_gas.c optional acpi iommu pci diff --git a/sys/dev/intel/spi.h b/sys/dev/intel/spi.h new file mode 100644 --- /dev/null +++ b/sys/dev/intel/spi.h @@ -0,0 +1,100 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2016 Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _DEV_INTEL_SPI_H_ +#define _DEV_INTEL_SPI_H_ + +#include +#include + +#include + +enum intelspi_vers { + SPI_BAYTRAIL, + SPI_BRASWELL, + SPI_LYNXPOINT, + SPI_SUNRISEPOINT, +}; + +/* Same order as intelspi_vers */ +static const struct intelspi_info { + const char *desc; + uint32_t reg_lpss_base; + uint32_t reg_cs_ctrl; +} intelspi_infos[] = { + [SPI_BAYTRAIL] = { + .desc = "Intel Bay Trail SPI Controller", + .reg_lpss_base = 0x400, + .reg_cs_ctrl = 0x18, + }, + [SPI_BRASWELL] = { + .desc = "Intel Braswell SPI Controller", + .reg_lpss_base = 0x400, + .reg_cs_ctrl = 0x18, + }, + [SPI_LYNXPOINT] = { + .desc = "Intel Lynx Point / Wildcat Point SPI Controller", + .reg_lpss_base = 0x800, + .reg_cs_ctrl = 0x18, + }, + [SPI_SUNRISEPOINT] = { + .desc = "Intel Sunrise Point SPI Controller", + .reg_lpss_base = 0x200, + .reg_cs_ctrl = 0x24, + }, + { NULL, 0 } +}; + +struct intelspi_softc { + ACPI_HANDLE sc_handle; + device_t sc_dev; + enum intelspi_vers sc_vers; + struct mtx sc_mtx; + int sc_mem_rid; + struct resource *sc_mem_res; + int sc_irq_rid; + struct resource *sc_irq_res; + void *sc_irq_ih; + struct spi_command *sc_cmd; + uint32_t sc_len; + uint32_t sc_read; + uint32_t sc_flags; + uint32_t sc_written; + uint32_t sc_clock; + uint32_t sc_mode; + /* LPSS private register storage for suspend-resume */ + uint32_t sc_regs[9]; +}; + +int intelspi_attach(device_t dev); +int intelspi_detach(device_t dev); +int intelspi_transfer(device_t dev, device_t child, struct spi_command *cmd); +int intelspi_suspend(device_t dev); +int intelspi_resume(device_t dev); + +#endif diff --git a/sys/dev/intel/spi.c b/sys/dev/intel/spi.c --- a/sys/dev/intel/spi.c +++ b/sys/dev/intel/spi.c @@ -1,4 +1,6 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause + * * Copyright (c) 2016 Oleksandr Tymoshenko * All rights reserved. * @@ -42,12 +44,7 @@ #include #include -#include -#include - -#include - -#include "spibus_if.h" +#include /** * Macros for driver mutex locking @@ -71,12 +68,13 @@ #define RX_FIFO_THRESHOLD 2 #define CLOCK_DIV_10MHZ 5 #define DATA_SIZE_8BITS 8 +#define MAX_CLOCK_RATE 50000000 #define CS_LOW 0 #define CS_HIGH 1 #define INTELSPI_SSPREG_SSCR0 0x0 -#define SSCR0_SCR(n) (((n) - 1) << 8) +#define SSCR0_SCR(n) ((((n) - 1) & 0xfff) << 8) #define SSCR0_SSE (1 << 7) #define SSCR0_FRF_SPI (0 << 4) #define SSCR0_DSS(n) (((n) - 1) << 0) @@ -88,10 +86,6 @@ #define SSCR1_SPI_SPH (1 << 4) #define SSCR1_SPI_SPO (1 << 3) #define SSCR1_MODE_MASK (SSCR1_SPI_SPO | SSCR1_SPI_SPH) -#define SSCR1_MODE_0 (0) -#define SSCR1_MODE_1 (SSCR1_SPI_SPH) -#define SSCR1_MODE_2 (SSCR1_SPI_SPO) -#define SSCR1_MODE_3 (SSCR1_SPI_SPO | SSCR1_SPI_SPH) #define SSCR1_TIE (1 << 1) #define SSCR1_RIE (1 << 0) #define INTELSPI_SSPREG_SSSR 0x8 @@ -110,36 +104,14 @@ #define INTELSPI_SSPREG_ITF 0x40 #define INTELSPI_SSPREG_SITF 0x44 #define INTELSPI_SSPREG_SIRF 0x48 -#define INTELSPI_SSPREG_PRV_CLOCK_PARAMS 0x400 -#define INTELSPI_SSPREG_RESETS 0x404 -#define INTELSPI_SSPREG_GENERAL 0x408 -#define INTELSPI_SSPREG_SSP_REG 0x40C -#define INTELSPI_SSPREG_SPI_CS_CTRL 0x418 +#define SPI_CS_CTRL(sc) \ + (intelspi_infos[sc->sc_vers].reg_lpss_base + \ + intelspi_infos[sc->sc_vers].reg_cs_ctrl) #define SPI_CS_CTRL_CS_MASK (3) #define SPI_CS_CTRL_SW_MODE (1 << 0) #define SPI_CS_CTRL_HW_MODE (1 << 0) #define SPI_CS_CTRL_CS_HIGH (1 << 1) -#define SPI_CS_CTRL_CS_LOW (0 << 1) -struct intelspi_softc { - ACPI_HANDLE sc_handle; - device_t sc_dev; - struct mtx sc_mtx; - int sc_mem_rid; - struct resource *sc_mem_res; - int sc_irq_rid; - struct resource *sc_irq_res; - void *sc_irq_ih; - struct spi_command *sc_cmd; - uint32_t sc_len; - uint32_t sc_read; - uint32_t sc_flags; - uint32_t sc_written; -}; - -static int intelspi_probe(device_t dev); -static int intelspi_attach(device_t dev); -static int intelspi_detach(device_t dev); static void intelspi_intr(void *); static int @@ -294,25 +266,15 @@ INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR0, 0); /* Manual CS control */ - reg = INTELSPI_READ(sc, INTELSPI_SSPREG_SPI_CS_CTRL); + reg = INTELSPI_READ(sc, SPI_CS_CTRL(sc)); reg &= ~(SPI_CS_CTRL_CS_MASK); reg |= (SPI_CS_CTRL_SW_MODE | SPI_CS_CTRL_CS_HIGH); - INTELSPI_WRITE(sc, INTELSPI_SSPREG_SPI_CS_CTRL, reg); + INTELSPI_WRITE(sc, SPI_CS_CTRL(sc), reg); /* Set TX/RX FIFO IRQ threshold levels */ reg = SSCR1_TFT(TX_FIFO_THRESHOLD) | SSCR1_RFT(RX_FIFO_THRESHOLD); - /* - * Set SPI mode. This should be part of transaction or sysctl - */ - reg |= SSCR1_MODE_0; INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR1, reg); - /* - * Parent clock on Minowboard Turbot is 50MHz - * divide it by 5 to set to more or less reasonable - * value. But this should be part of transaction config - * or sysctl - */ reg = SSCR0_SCR(CLOCK_DIV_10MHZ); /* Put SSP in SPI mode */ reg |= SSCR0_FRF_SPI; @@ -328,24 +290,23 @@ { uint32_t reg; - reg = INTELSPI_READ(sc, INTELSPI_SSPREG_SPI_CS_CTRL); + reg = INTELSPI_READ(sc, SPI_CS_CTRL(sc)); reg &= ~(SPI_CS_CTRL_CS_MASK); reg |= SPI_CS_CTRL_SW_MODE; if (level == CS_HIGH) reg |= SPI_CS_CTRL_CS_HIGH; - else - reg |= SPI_CS_CTRL_CS_LOW; - - INTELSPI_WRITE(sc, INTELSPI_SSPREG_SPI_CS_CTRL, reg); + + INTELSPI_WRITE(sc, SPI_CS_CTRL(sc), reg); } -static int +int intelspi_transfer(device_t dev, device_t child, struct spi_command *cmd) { struct intelspi_softc *sc; int err; - uint32_t sscr1; + uint32_t sscr0, sscr1, mode, clock; + bool restart = false; sc = device_get_softc(dev); err = 0; @@ -369,6 +330,45 @@ /* Now we have control over SPI controller. */ sc->sc_flags = INTELSPI_BUSY; + /* Configure the clock rate and SPI mode. */ + spibus_get_clock(child, &clock); + spibus_get_mode(child, &mode); + + if (clock != sc->sc_clock || mode != sc->sc_mode) { + sscr0 = INTELSPI_READ(sc, INTELSPI_SSPREG_SSCR0); + sscr0 &= ~SSCR0_SSE; + INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR0, sscr0); + restart = true; + } + + if (clock != sc->sc_clock) { + sscr0 = INTELSPI_READ(sc, INTELSPI_SSPREG_SSCR0); + sscr0 &= ~SSCR0_SCR(0xfff); + if (clock == 0) + sscr0 |= SSCR0_SCR(CLOCK_DIV_10MHZ); + else + sscr0 |= SSCR0_SCR(howmany(MAX_CLOCK_RATE, min(MAX_CLOCK_RATE, clock))); + INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR0, sscr0); + sc->sc_clock = clock; + } + + if (mode != sc->sc_mode) { + sscr1 = INTELSPI_READ(sc, INTELSPI_SSPREG_SSCR1); + sscr1 &= ~SSCR1_MODE_MASK; + if (mode & SPIBUS_MODE_CPHA) + sscr1 |= SSCR1_SPI_SPH; + if (mode & SPIBUS_MODE_CPOL) + sscr1 |= SSCR1_SPI_SPO; + INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR1, sscr1); + sc->sc_mode = mode; + } + + if (restart) { + sscr0 = INTELSPI_READ(sc, INTELSPI_SSPREG_SSCR0); + sscr0 |= SSCR0_SSE; + INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR0, sscr0); + } + /* Save a pointer to the SPI command. */ sc->sc_cmd = cmd; sc->sc_read = 0; @@ -419,32 +419,16 @@ return (err); } -static int -intelspi_probe(device_t dev) -{ - static char *gpio_ids[] = { "80860F0E", NULL }; - int rv; - - if (acpi_disabled("spi") ) - return (ENXIO); - rv = ACPI_ID_PROBE(device_get_parent(dev), dev, gpio_ids, NULL); - if (rv <= 0) - device_set_desc(dev, "Intel SPI Controller"); - return (rv); -} - -static int +int intelspi_attach(device_t dev) { struct intelspi_softc *sc; sc = device_get_softc(dev); sc->sc_dev = dev; - sc->sc_handle = acpi_get_handle(dev); INTELSPI_LOCK_INIT(sc); - sc->sc_mem_rid = 0; sc->sc_mem_res = bus_alloc_resource_any(sc->sc_dev, SYS_RES_MEMORY, &sc->sc_mem_rid, RF_ACTIVE); if (sc->sc_mem_res == NULL) { @@ -452,9 +436,8 @@ goto error; } - sc->sc_irq_rid = 0; sc->sc_irq_res = bus_alloc_resource_any(sc->sc_dev, - SYS_RES_IRQ, &sc->sc_irq_rid, RF_ACTIVE); + SYS_RES_IRQ, &sc->sc_irq_rid, RF_ACTIVE | RF_SHAREABLE); if (sc->sc_irq_res == NULL) { device_printf(dev, "can't allocate IRQ resource\n"); goto error; @@ -471,7 +454,7 @@ device_add_child(dev, "spibus", -1); - return (bus_generic_attach(dev)); + return (bus_delayed_attach_children(dev)); error: INTELSPI_LOCK_DESTROY(sc); @@ -487,7 +470,7 @@ return (ENXIO); } -static int +int intelspi_detach(device_t dev) { struct intelspi_softc *sc; @@ -510,25 +493,49 @@ return (bus_generic_detach(dev)); } -static device_method_t intelspi_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, intelspi_probe), - DEVMETHOD(device_attach, intelspi_attach), - DEVMETHOD(device_detach, intelspi_detach), +int +intelspi_suspend(device_t dev) +{ + struct intelspi_softc *sc; + int err, i; - /* SPI interface */ - DEVMETHOD(spibus_transfer, intelspi_transfer), + sc = device_get_softc(dev); - DEVMETHOD_END -}; + err = bus_generic_suspend(dev); + if (err) + return (err); -static driver_t intelspi_driver = { - "spi", - intelspi_methods, - sizeof(struct intelspi_softc), -}; + for (i = 0; i < 9; i++) { + unsigned long offset = i * sizeof(uint32_t); + sc->sc_regs[i] = INTELSPI_READ(sc, + intelspi_infos[sc->sc_vers].reg_lpss_base + offset); + } -static devclass_t intelspi_devclass; -DRIVER_MODULE(intelspi, acpi, intelspi_driver, intelspi_devclass, 0, 0); -MODULE_DEPEND(intelspi, acpi, 1, 1, 1); -MODULE_DEPEND(intelspi, spibus, 1, 1, 1); + /* Shutdown just in case */ + INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR0, 0); + + return (0); +} + +int +intelspi_resume(device_t dev) +{ + struct intelspi_softc *sc; + int i; + + sc = device_get_softc(dev); + + for (i = 0; i < 9; i++) { + unsigned long offset = i * sizeof(uint32_t); + INTELSPI_WRITE(sc, intelspi_infos[sc->sc_vers].reg_lpss_base + offset, + sc->sc_regs[i]); + } + + intelspi_init(sc); + + /* Ensure the next transfer would reconfigure these */ + sc->sc_clock = 0; + sc->sc_mode = 0; + + return (bus_generic_resume(dev)); +} diff --git a/sys/dev/intel/spi_acpi.c b/sys/dev/intel/spi_acpi.c new file mode 100644 --- /dev/null +++ b/sys/dev/intel/spi_acpi.c @@ -0,0 +1,112 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2021 Greg V + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "opt_acpi.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "spibus_if.h" + +static const struct intelspi_acpi_device { + const char *hid; + enum intelspi_vers vers; +} intelspi_acpi_devices[] = { + { "80860F0E", SPI_BAYTRAIL }, + { "8086228E", SPI_BRASWELL }, +}; + +static char *intelspi_ids[] = { "80860F0E", "8086228E", NULL }; + +static int +intelspi_acpi_probe(device_t dev) +{ + struct intelspi_softc *sc = device_get_softc(dev); + char *hid; + int i; + + if (acpi_disabled("spi")) + return (ENXIO); + + if (ACPI_ID_PROBE(device_get_parent(dev), dev, intelspi_ids, &hid) > 0) + return (ENXIO); + + for (i = 0; i < nitems(intelspi_acpi_devices); i++) { + if (strcmp(intelspi_acpi_devices[i].hid, hid) == 0) { + sc->sc_vers = intelspi_acpi_devices[i].vers; + sc->sc_handle = acpi_get_handle(dev); + device_set_desc(dev, intelspi_infos[sc->sc_vers].desc); + return (BUS_PROBE_DEFAULT); + } + } + + return (ENXIO); +} + +static int +intelspi_acpi_attach(device_t dev) +{ + struct intelspi_softc *sc = device_get_softc(dev); + + sc->sc_mem_rid = 0; + sc->sc_irq_rid = 0; + + return (intelspi_attach(dev)); +} + +static device_method_t intelspi_acpi_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, intelspi_acpi_probe), + DEVMETHOD(device_attach, intelspi_acpi_attach), + DEVMETHOD(device_detach, intelspi_detach), + DEVMETHOD(device_suspend, intelspi_suspend), + DEVMETHOD(device_resume, intelspi_resume), + + /* SPI interface */ + DEVMETHOD(spibus_transfer, intelspi_transfer), + + DEVMETHOD_END +}; + +static driver_t intelspi_acpi_driver = { + "spi", + intelspi_acpi_methods, + sizeof(struct intelspi_softc), +}; + +static devclass_t intelspi_acpi_devclass; +DRIVER_MODULE(intelspi, acpi, intelspi_acpi_driver, intelspi_acpi_devclass, 0, + 0); +MODULE_DEPEND(intelspi, acpi, 1, 1, 1); +MODULE_DEPEND(intelspi, spibus, 1, 1, 1); diff --git a/sys/dev/intel/spi_pci.c b/sys/dev/intel/spi_pci.c new file mode 100644 --- /dev/null +++ b/sys/dev/intel/spi_pci.c @@ -0,0 +1,139 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2021 Greg V + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "opt_acpi.h" +#include "opt_pci.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "spibus_if.h" + +static struct intelspi_pci_device { + uint32_t devid; + enum intelspi_vers vers; +} intelspi_pci_devices[] = { + { 0x9c658086, SPI_LYNXPOINT }, + { 0x9c668086, SPI_LYNXPOINT }, + { 0x9ce58086, SPI_LYNXPOINT }, + { 0x9ce68086, SPI_LYNXPOINT }, + { 0x9d298086, SPI_SUNRISEPOINT }, + { 0x9d2a8086, SPI_SUNRISEPOINT }, + { 0xa1298086, SPI_SUNRISEPOINT }, + { 0xa12a8086, SPI_SUNRISEPOINT }, + { 0xa2a98086, SPI_SUNRISEPOINT }, + { 0xa2aa8086, SPI_SUNRISEPOINT }, + { 0xa3a98086, SPI_SUNRISEPOINT }, + { 0xa3aa8086, SPI_SUNRISEPOINT }, +}; + +static int +intelspi_pci_probe(device_t dev) +{ + struct intelspi_softc *sc = device_get_softc(dev); + uint32_t devid = pci_get_devid(dev); + int i; + + for (i = 0; i < nitems(intelspi_pci_devices); i++) { + if (intelspi_pci_devices[i].devid == devid) { + sc->sc_vers = intelspi_pci_devices[i].vers; + /* The PCI device is listed in ACPI too. + * Not that we use the handle for anything... */ + sc->sc_handle = acpi_get_handle(dev); + device_set_desc(dev, intelspi_infos[sc->sc_vers].desc); + return (BUS_PROBE_DEFAULT); + } + } + + return (ENXIO); +} + +static int +intelspi_pci_attach(device_t dev) +{ + struct intelspi_softc *sc = device_get_softc(dev); + + sc->sc_mem_rid = PCIR_BAR(0); + sc->sc_irq_rid = 0; + if (pci_alloc_msi(dev, &sc->sc_irq_rid)) { + device_printf(dev, "Using MSI\n"); + } + + return (intelspi_attach(dev)); +} + +static int +intelspi_pci_detach(device_t dev) +{ + struct intelspi_softc *sc = device_get_softc(dev); + int err; + + err = intelspi_detach(dev); + if (err) + return (err); + + if (sc->sc_irq_rid != 0) + pci_release_msi(dev); + + return (0); +} + +static device_method_t intelspi_pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, intelspi_pci_probe), + DEVMETHOD(device_attach, intelspi_pci_attach), + DEVMETHOD(device_detach, intelspi_pci_detach), + DEVMETHOD(device_suspend, intelspi_suspend), + DEVMETHOD(device_resume, intelspi_resume), + + /* SPI interface */ + DEVMETHOD(spibus_transfer, intelspi_transfer), + + DEVMETHOD_END +}; + +static driver_t intelspi_pci_driver = { + "spi", + intelspi_pci_methods, + sizeof(struct intelspi_softc), +}; + +static devclass_t intelspi_pci_devclass; +DRIVER_MODULE(intelspi, pci, intelspi_pci_driver, intelspi_pci_devclass, 0, 0); +MODULE_DEPEND(intelspi, pci, 1, 1, 1); +MODULE_DEPEND(intelspi, spibus, 1, 1, 1); +MODULE_PNP_INFO("W32:vendor/device", pci, intelspi, intelspi_pci_devices, + nitems(intelspi_pci_devices)); diff --git a/sys/modules/intelspi/Makefile b/sys/modules/intelspi/Makefile --- a/sys/modules/intelspi/Makefile +++ b/sys/modules/intelspi/Makefile @@ -2,7 +2,7 @@ .PATH: ${SRCTOP}/sys/dev/intel KMOD= intelspi -SRCS= spi.c -SRCS+= acpi_if.h device_if.h bus_if.h opt_acpi.h spibus_if.h +SRCS= spi.c spi_acpi.c spi_pci.c +SRCS+= acpi_if.h pci_if.h device_if.h bus_if.h opt_acpi.h opt_pci.h spibus_if.h .include