Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F96143504
D29249.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
21 KB
Referenced Files
None
Subscribers
None
D29249.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D29249: intelspi: add PCI attachment (Lynx/Wildcat/Sunrise Point), fixup/cleanup
Attached
Detach File
Event Timeline
Log In to Comment