Page MenuHomeFreeBSD

D29249.diff
No OneTemporary

D29249.diff

diff --git a/sys/conf/files.x86 b/sys/conf/files.x86
--- a/sys/conf/files.x86
+++ b/sys/conf/files.x86
@@ -145,6 +145,8 @@
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.h b/sys/dev/intel/spi.h
new file mode 100644
--- /dev/null
+++ b/sys/dev/intel/spi.h
@@ -0,0 +1,99 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2016 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ * 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.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 <gonzo@FreeBSD.org>
* 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 @@
#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 @@
#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 @@
#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 @@
#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_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 @@
{
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 @@
/* 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 @@
/* 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 @@
/* 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 @@
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 @@
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 @@
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 @@
return (ENXIO);
}
-static int
+int
intelspi_detach(device_t dev)
{
struct intelspi_softc *sc;
@@ -510,24 +509,50 @@
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_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,111 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Val Packett <val@packett.cool>
+ *
+ * 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
--- /dev/null
+++ b/sys/dev/intel/spi_pci.c
@@ -0,0 +1,138 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Val Packett <val@packett.cool>
+ *
+ * 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
--- 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>

File Metadata

Mime Type
text/plain
Expires
Tue, Sep 24, 8:26 PM (22 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
12696000
Default Alt Text
D29249.diff (21 KB)

Event Timeline