The branch main has been updated by wulf:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=1f40866feb2135a4cf764a07b1b90a8a3398ff0a

commit 1f40866feb2135a4cf764a07b1b90a8a3398ff0a
Author:     Val Packett <[email protected]>
AuthorDate: 2023-04-24 09:41:52 +0000
Commit:     Vladimir Kondratyev <[email protected]>
CommitDate: 2023-04-24 09:41:52 +0000

    intelspi: add PCI attachment (Lynx/Wildcat/Sunrise Point)
    
    Also adds fixups and cleanups:
    
    - apply the child's mode/speed
    - implement suspend/resume support
    - use RF_SHAREABLE interrupts
    - use bus_delayed_attach_children since the transfer can use interrupts
    - add support for newly added spibus features (cs_delay and flags)
    
    Operation tested on Broadwell (Wildcat Point) MacBookPro12,1.
    Attachment also tested on Kaby Lake (Sunrise Point) Pixelbook.
    
    Reviewed by:    wulf
    MFC after:      1 month
    Differential revision:  https://reviews.freebsd.org/D29249
---
 sys/conf/files.x86            |   2 +
 sys/dev/intel/spi.c           | 241 +++++++++++++++++++++++-------------------
 sys/dev/intel/spi.h           |  99 +++++++++++++++++
 sys/dev/intel/spi_acpi.c      | 111 +++++++++++++++++++
 sys/dev/intel/spi_pci.c       | 138 ++++++++++++++++++++++++
 sys/modules/intelspi/Makefile |   4 +-
 6 files changed, 485 insertions(+), 110 deletions(-)

diff --git a/sys/conf/files.x86 b/sys/conf/files.x86
index 2e7ce6c00b3b..f80638f98f95 100644
--- a/sys/conf/files.x86
+++ b/sys/conf/files.x86
@@ -145,6 +145,8 @@ dev/imcsmb/imcsmb.c         optional        imcsmb
 dev/imcsmb/imcsmb_pci.c                optional        imcsmb pci
 dev/intel/pchtherm.c           optional        pchtherm
 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.c b/sys/dev/intel/spi.c
index 676530234382..497c2606a1c9 100644
--- 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 <[email protected]>
  * All rights reserved.
  *
@@ -24,9 +26,6 @@
  * SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
 #include "opt_acpi.h"
 
 #include <sys/param.h>
@@ -42,12 +41,7 @@ __FBSDID("$FreeBSD$");
 #include <dev/spibus/spi.h>
 #include <dev/spibus/spibusvar.h>
 
-#include <contrib/dev/acpica/include/acpi.h>
-#include <contrib/dev/acpica/include/accommon.h>
-
-#include <dev/acpica/acpivar.h>
-
-#include "spibus_if.h"
+#include <dev/intel/spi.h>
 
 /**
  *     Macros for driver mutex locking
@@ -71,12 +65,13 @@ __FBSDID("$FreeBSD$");
 #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 +83,6 @@ __FBSDID("$FreeBSD$");
 #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 +101,14 @@ __FBSDID("$FreeBSD$");
 #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 +263,15 @@ intelspi_init(struct intelspi_softc *sc)
        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 +287,23 @@ intelspi_set_cs(struct intelspi_softc *sc, int level)
 {
        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;
+       int err, poll_limit;
+       uint32_t sscr0, sscr1, mode, clock, cs_delay;
+       bool restart = false;
 
        sc = device_get_softc(dev);
        err = 0;
@@ -359,6 +317,8 @@ intelspi_transfer(device_t dev, device_t child, struct 
spi_command *cmd)
 
        /* If the controller is in use wait until it is available. */
        while (sc->sc_flags & INTELSPI_BUSY) {
+               if ((cmd->flags & SPI_FLAG_NO_SLEEP) == SPI_FLAG_NO_SLEEP)
+                       return (EBUSY);
                err = mtx_sleep(dev, &sc->sc_mtx, 0, "intelspi", 0);
                if (err == EINTR) {
                        INTELSPI_UNLOCK(sc);
@@ -369,6 +329,45 @@ intelspi_transfer(device_t dev, device_t child, struct 
spi_command *cmd)
        /* 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;
@@ -377,19 +376,36 @@ intelspi_transfer(device_t dev, device_t child, struct 
spi_command *cmd)
 
        /* Enable CS */
        intelspi_set_cs(sc, CS_LOW);
-       /* Transfer as much as possible to FIFOs */
-       if (!intelspi_transact(sc)) {
-               /* If FIFO is not large enough - enable interrupts */
-               sscr1 = INTELSPI_READ(sc, INTELSPI_SSPREG_SSCR1);
-               sscr1 |= (SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE);
-               INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR1, sscr1);
 
-               /* and wait for transaction to complete */
-               err = mtx_sleep(dev, &sc->sc_mtx, 0, "intelspi", hz * 2);
+       /* Wait the CS delay */
+       spibus_get_cs_delay(child, &cs_delay);
+       DELAY(cs_delay);
+
+       /* Transfer as much as possible to FIFOs */
+       if ((cmd->flags & SPI_FLAG_NO_SLEEP) == SPI_FLAG_NO_SLEEP) {
+               /* We cannot wait with mtx_sleep if we're called from e.g. an 
ithread */
+               poll_limit = 2000;
+               while (!intelspi_transact(sc) && poll_limit-- > 0)
+                       DELAY(1000);
+               if (poll_limit == 0) {
+                       device_printf(dev, "polling was stuck, transaction not 
finished\n");
+                       err = EIO;
+               }
+       } else {
+               if (!intelspi_transact(sc)) {
+                       /* If FIFO is not large enough - enable interrupts */
+                       sscr1 = INTELSPI_READ(sc, INTELSPI_SSPREG_SSCR1);
+                       sscr1 |= (SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE);
+                       INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR1, sscr1);
+
+                       /* and wait for transaction to complete */
+                       err = mtx_sleep(dev, &sc->sc_mtx, 0, "intelspi", hz * 
2);
+               }
        }
 
-       /* de-asser CS */
-       intelspi_set_cs(sc, CS_HIGH);
+       /* De-assert CS */
+       if ((cmd->flags & SPI_FLAG_KEEP_CS) == 0)
+               intelspi_set_cs(sc, CS_HIGH);
 
        /* Clear transaction details */
        sc->sc_cmd = NULL;
@@ -419,32 +435,16 @@ intelspi_transfer(device_t dev, device_t child, struct 
spi_command *cmd)
        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 +452,8 @@ intelspi_attach(device_t dev)
                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 +470,7 @@ intelspi_attach(device_t dev)
 
        device_add_child(dev, "spibus", -1);
 
-       return (bus_generic_attach(dev));
+       return (bus_delayed_attach_children(dev));
 
 error:
        INTELSPI_LOCK_DESTROY(sc);
@@ -487,7 +486,7 @@ error:
        return (ENXIO);
 }
 
-static int
+int
 intelspi_detach(device_t dev)
 {
        struct intelspi_softc   *sc;
@@ -510,24 +509,50 @@ intelspi_detach(device_t dev)
        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);
+       }
+
+       /* Shutdown just in case */
+       INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR0, 0);
 
-DRIVER_MODULE(intelspi, acpi, intelspi_driver, 0, 0);
-MODULE_DEPEND(intelspi, acpi, 1, 1, 1);
-MODULE_DEPEND(intelspi, spibus, 1, 1, 1);
+       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.h b/sys/dev/intel/spi.h
new file mode 100644
index 000000000000..31b708572630
--- /dev/null
+++ b/sys/dev/intel/spi.h
@@ -0,0 +1,99 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2016 Oleksandr Tymoshenko <[email protected]>
+ * 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 <contrib/dev/acpica/include/acpi.h>
+#include <contrib/dev/acpica/include/accommon.h>
+
+#include <dev/acpica/acpivar.h>
+
+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,
+       },
+};
+
+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_acpi.c b/sys/dev/intel/spi_acpi.c
new file mode 100644
index 000000000000..015694f4a008
--- /dev/null
+++ b/sys/dev/intel/spi_acpi.c
@@ -0,0 +1,111 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Val Packett <[email protected]>
+ *
+ * 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 <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/proc.h>
+#include <sys/rman.h>
+
+#include <dev/intel/spi.h>
+
+#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),
+};
+
+DRIVER_MODULE(intelspi, acpi, intelspi_acpi_driver, 0, 0);
+MODULE_DEPEND(intelspi, acpi, 1, 1, 1);
+MODULE_DEPEND(intelspi, spibus, 1, 1, 1);
+ACPI_PNP_INFO(intelspi_ids);
diff --git a/sys/dev/intel/spi_pci.c b/sys/dev/intel/spi_pci.c
new file mode 100644
index 000000000000..c55b5a12228e
--- /dev/null
+++ b/sys/dev/intel/spi_pci.c
@@ -0,0 +1,138 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Val Packett <[email protected]>
+ *
+ * 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 <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/proc.h>
+#include <sys/rman.h>
+
+#include <dev/intel/spi.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#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),
+};
+
+DRIVER_MODULE(intelspi, pci, intelspi_pci_driver, 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
index b2bceee4b3f8..2220a0b87232 100644
--- 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 <bsd.kmod.mk>

Reply via email to