From nobody Mon Apr 24 09:43:07 2023 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Q4gDD0CWzz46Zlk; Mon, 24 Apr 2023 09:43:08 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Q4gDC66Sqz3Dgc; Mon, 24 Apr 2023 09:43:07 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1682329387; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=J6PqmQZHwgc4t5vEc9xSqfXE6X13QldK441K8vzj5b8=; b=xok70b0p77UWTK0vjrkGHnJXfBoAdnbHOHgAi1eT80yqJIy6y+oVoOlPo37Xdh8LtbByuw uMJg7Kvu33hJUbPEagYC5ZZ51DFvN8mZcBqk/X/siDYkUA7hcYVTjDQBVUXhVXLIv8N5oS ttRkPUyOkZYMNawRpCanReVUZbhguy4AtRalOBNukM1uSGUfGoGdnl/7fvDIINIFOAPM+h SMGGPxKVjP2mABSISmfdkBbwGg38uF/Y9uWssORjM0cwUvIt3//BoGE3NBfsCmom0wyIIo GLT9YBO2dfDVeJchR0WnFNo46a32zwH2Ma4GXSYerA0lYgJJbKoH3fr0M60b0w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1682329387; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=J6PqmQZHwgc4t5vEc9xSqfXE6X13QldK441K8vzj5b8=; b=xwjk5ocOWju76pwnDVVD13IeLTVWOD8w/j1PuHggaAdJZTGxe2OMAvqTt27s/cOxEXgIKa P5hnfeM44Ogir6bugQKRJVDHdyMQ0kBb6BK+BeYpXHLMB9UikVuyoh0rAUO3/ix2LP935C pmb+jO3tXy6KzFtMQlDi7IyEvjiGC0Rct2ZgDoob70Fg9QZSQ/Ev3QDJi8jGufRklVn3zB sj2qZTQqepT2t8oV5OR83RkmulDU9QrD0t/8ESw/sbaYvjiPTSvk+0XTmz6/U3++MpPWNk F455J0h5X/OmBE6iaTpDh1MidpDJUboKY8FxdzKkKkXSyBTnstGH+ufbbas/Bw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1682329387; a=rsa-sha256; cv=none; b=ZLjWteyNb5VJ01tlDMpADPJda04kR6PHxmeTN8NKZYKoG00XnP/OSlwpLvK1nQjDiOX0gK E/pKMyauy3TafB6J4OMLy5aBFbFmvNEtiZVB5wZNwHPjm6g6ekoYRkD/wXo+q/dvKD6qcS kCb6e+lM43dawYO95zicHqbGOkFvFUG4N+ujUSG5HJ/JK2Ml/mB0i3QIKsCARDhN+znDTv Kj3v2avfNV/BU4SDO3IQRSPoQ5HbXQeCb6q5PzYBx32VXavY8i+DS07xYd82dhTBisb2EP zbU1TORXA9NSc7IhgIDVwyWVYN3XjPsjqEeHAxdGqsn6w6YddiL3HAvMYWHMzg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4Q4gDC55bDzLTj; Mon, 24 Apr 2023 09:43:07 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 33O9h7uY088244; Mon, 24 Apr 2023 09:43:07 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 33O9h7ht088243; Mon, 24 Apr 2023 09:43:07 GMT (envelope-from git) Date: Mon, 24 Apr 2023 09:43:07 GMT Message-Id: <202304240943.33O9h7ht088243@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Vladimir Kondratyev Subject: git: 1f40866feb21 - main - intelspi: add PCI attachment (Lynx/Wildcat/Sunrise Point) List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: wulf X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 1f40866feb2135a4cf764a07b1b90a8a3398ff0a Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by wulf: URL: https://cgit.FreeBSD.org/src/commit/?id=1f40866feb2135a4cf764a07b1b90a8a3398ff0a commit 1f40866feb2135a4cf764a07b1b90a8a3398ff0a Author: Val Packett AuthorDate: 2023-04-24 09:41:52 +0000 Commit: Vladimir Kondratyev 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 * All rights reserved. * @@ -24,9 +26,6 @@ * SUCH DAMAGE. */ -#include -__FBSDID("$FreeBSD$"); - #include "opt_acpi.h" #include @@ -42,12 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include - -#include - -#include "spibus_if.h" +#include /** * 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 + * 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, + }, +}; + +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 + * + * 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), +}; + +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 + * + * 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), +}; + +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