[coreboot-gerrit] Change in coreboot[master]: soc/intel/common: Add support for common GSPI controller
Furquan Shaikh (Code Review)
gerrit at coreboot.org
Tue Apr 4 01:52:02 CEST 2017
Furquan Shaikh has uploaded a new change for review. ( https://review.coreboot.org/19098 )
Change subject: soc/intel/common: Add support for common GSPI controller
......................................................................
soc/intel/common: Add support for common GSPI controller
Add support for GSPI controller in Intel PCH. This controller is
compliant with PXA2xx SPI controller with some additional registers to
provide more fine-grained control of the SPI bus. Currently, DMA is
not enabled as this driver might be used before memory is up (e.g. TPM
on SPI).
BUG=b:35583330
Change-Id: I0eb91eba2c523be457fee8922c44fb500a9fa140
Signed-off-by: Furquan Shaikh <furquan at chromium.org>
---
A src/soc/intel/common/block/gspi/Kconfig
A src/soc/intel/common/block/gspi/Makefile.inc
A src/soc/intel/common/block/gspi/gspi.c
A src/soc/intel/common/block/include/intelblocks/gspi.h
4 files changed, 583 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/98/19098/1
diff --git a/src/soc/intel/common/block/gspi/Kconfig b/src/soc/intel/common/block/gspi/Kconfig
new file mode 100644
index 0000000..d2c907a
--- /dev/null
+++ b/src/soc/intel/common/block/gspi/Kconfig
@@ -0,0 +1,12 @@
+config SOC_INTEL_COMMON_BLOCK_GSPI
+ bool
+ help
+ Intel Processor Common GSPI support
+
+config SOC_INTEL_COMMON_BLOCK_GSPI_CLK_MHZ
+ int
+ depends on SOC_INTEL_COMMON_BLOCK_GSPI
+ help
+ The clock speed that the GSPI controller is running at, in MHz.
+ This is an SoC-specific value and must be provided by the SoC when it
+ selects this driver.
diff --git a/src/soc/intel/common/block/gspi/Makefile.inc b/src/soc/intel/common/block/gspi/Makefile.inc
new file mode 100644
index 0000000..85cb18e
--- /dev/null
+++ b/src/soc/intel/common/block/gspi/Makefile.inc
@@ -0,0 +1,4 @@
+bootblock-$(CONFIG_SOC_INTEL_COMMON_BLOCK_GSPI) += gspi.c
+romstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_GSPI) += gspi.c
+ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_GSPI) += gspi.c
+verstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_GSPI) += gspi.c
diff --git a/src/soc/intel/common/block/gspi/gspi.c b/src/soc/intel/common/block/gspi/gspi.c
new file mode 100644
index 0000000..8ece724
--- /dev/null
+++ b/src/soc/intel/common/block/gspi/gspi.c
@@ -0,0 +1,523 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2017 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <arch/io.h>
+#include <assert.h>
+#include <console/console.h>
+#include <delay.h>
+#include <intelblocks/gspi.h>
+#include <timer.h>
+
+/* GSPI Memory Mapped Registers */
+#define SSCR0 0x0 /* SSP Control Register 0 */
+#define SSCR0_EDSS_0 (0 << 20)
+#define SSCR0_EDSS_1 (1 << 20)
+#define SSCR0_SCR_SHIFT (8)
+#define SSCR0_SCR_MASK (0xFFF)
+#define SSCR0_SSE_DISABLE (0 << 7)
+#define SSCR0_SSE_ENABLE (1 << 7)
+#define SSCR0_ECS_ON_CHIP (0 << 6)
+#define SSCR0_FRF_MOTOROLA (0 << 4)
+#define SSCR0_DSS_SHIFT (0)
+#define SSCR0_DSS_MASK (0xF)
+#define SSCR1 0x4 /* SSP Control Register 1 */
+#define SSCR1_IFS_LOW (0 << 16)
+#define SSCR1_IFS_HIGH (1 << 16)
+#define SSCR1_SPH_FIRST (0 << 4)
+#define SSCR1_SPH_SECOND (1 << 4)
+#define SSCR1_SPO_LOW (0 << 3)
+#define SSCR1_SPO_HIGH (1 << 3)
+#define SSSR 0x8 /* SSP Status Register */
+#define SSSR_TUR (1 << 21) /* Tx FIFO underrun */
+#define SSSR_TINT (1 << 19) /* Rx Time-out interrupt */
+#define SSSR_PINT (1 << 18) /* Peripheral trailing byte
+ interrupt */
+#define SSSR_ROR (1 << 7) /* Rx FIFO Overrun */
+#define SSSR_BSY (1 << 4) /* SSP Busy */
+#define SSSR_RNE (1 << 3) /* Receive FIFO not empty */
+#define SSSR_TNF (1 << 2) /* Transmit FIFO not full */
+#define SSDR 0x10 /* SSP Data Register */
+#define SSTO 0x28 /* SSP Time out */
+#define SITF 0x44 /* SPI Transmit FIFO */
+#define SITF_LEVEL_SHIFT (16)
+#define SITF_LEVEL_MASK (0x3f)
+#define SITF_LWM_SHIFT (8)
+#define SITF_LWM_MASK (0x3f)
+#define SITF_LWM(x) ((((x) - 1) & SITF_LWM_MASK) << SITF_LWM_SHIFT)
+#define SITF_HWM_SHIFT (0)
+#define SITF_HWM_MASK (0x3f)
+#define SITF_HWM(x) ((((x) - 1) & SITF_HWM_MASK) << SITF_HWM_SHIFT)
+#define SIRF 0x48 /* SPI Receive FIFO */
+#define SIRF_LEVEL_SHIFT (8)
+#define SIRF_LEVEL_MASK (0x3f)
+#define SIRF_WM_SHIFT (0)
+#define SIRF_WM_MASK (0x3f)
+#define SIRF_WM(x) ((((x) - 1) & SIRF_WM_MASK) << SIRF_WM_SHIFT)
+
+/* GSPI Additional Registers */
+#define CLOCKS 0x200 /* Clocks */
+#define CLOCKS_UPDATE (1 << 31)
+#define CLOCKS_N_SHIFT (16)
+#define CLOCKS_N_MASK (0x7fff)
+#define CLOCKS_M_SHIFT (1)
+#define CLOCKS_M_MASK (0x7fff)
+#define CLOCKS_DISABLE (0 << 0)
+#define CLOCKS_ENABLE (1 << 0)
+#define RESETS 0x204 /* Resets */
+#define DMA_RESET (0 << 2)
+#define DMA_ACTIVE (1 << 2)
+#define CTRLR_RESET (0 << 0)
+#define CTRLR_ACTIVE (3 << 0)
+#define ACTIVELTR_VALUE 0x210 /* Active LTR */
+#define IDLELTR_VALUE 0x214 /* Idle LTR Value */
+#define TX_BIT_COUNT 0x218 /* Tx Bit Count */
+#define RX_BIT_COUNT 0x21c /* Rx Bit Count */
+#define SSP_REG 0x220 /* SSP Reg */
+#define DMA_FINISH_DISABLE (1 << 0)
+#define SPI_CS_CONTROL 0x224 /* SPI CS Control */
+#define CS_POLARITY_LOW (0 << 12)
+#define CS_POLARITY_HIGH (1 << 12)
+#define CS_0 (0 << 8)
+#define CS_STATE_LOW (0 << 1)
+#define CS_STATE_HIGH (1 << 1)
+#define CS_STATE_MASK (1 << 1)
+#define CS_MODE_HW (0 << 0)
+#define CS_MODE_SW (1 << 0)
+
+#define GSPI_DATA_BIT_LENGTH (8)
+
+int __attribute__((weak)) gspi_get_bus_config(unsigned int bus,
+ struct spi_cfg *cfg)
+{
+ cfg->clk_phase = SPI_CLOCK_PHASE_FIRST;
+ cfg->clk_polarity = SPI_POLARITY_LOW;
+ cfg->cs_polarity = SPI_POLARITY_LOW;
+ cfg->wire_mode = SPI_4_WIRE_MODE;
+ cfg->data_bit_length = GSPI_DATA_BIT_LENGTH;
+
+ return 0;
+}
+
+static int gspi_ctrlr_get_config(const struct spi_slave *dev,
+ struct spi_cfg *cfg)
+{
+ /* Currently, only chip select 0 is supported. */
+ if (dev->cs != 0) {
+ printk(BIOS_ERR, "%s: Unsupported device bus=%u,cs=%u!\n",
+ __func__, dev->bus, dev->cs);
+ return -1;
+ }
+
+ return gspi_get_bus_config(dev->bus, cfg);
+}
+
+static int gspi_read_mmio_reg(const struct spi_slave *dev, uint32_t offset,
+ uint32_t *value)
+{
+ uintptr_t base = gspi_get_bus_base_address(dev->bus);
+
+ if (!base) {
+ printk(BIOS_ERR, "%s: base address not found for bus %u."
+ " Read failed for 0x%x.\n",__func__, dev->bus, offset);
+ return -1;
+ }
+
+ *value = read32((void *)(base + offset));
+ return 0;
+}
+
+static int gspi_write_mmio_reg(const struct spi_slave *dev, uint32_t offset,
+ uint32_t value)
+{
+ uintptr_t base = gspi_get_bus_base_address(dev->bus);
+
+ if (!base) {
+ printk(BIOS_ERR, "%s: base address not found for bus %u."
+ " Write failed for 0x%x.\n",__func__, dev->bus, offset);
+ return -1;
+ }
+
+ write32((void *)(base + offset), value);
+ return 0;
+}
+
+/* If status read fails for any reason, value returned is 0. */
+static uint32_t gspi_read_status(const struct spi_slave *dev)
+{
+ uint32_t sssr = 0;
+ gspi_read_mmio_reg(dev, SSSR, &sssr);
+ return sssr;
+}
+
+/*
+ * If status clear fails, xfer operation is not stopped right away. Instead, let
+ * it continue and see if we can go through with the transfer.
+ */
+static void gspi_clear_status(const struct spi_slave *dev)
+{
+ const uint32_t sssr = SSSR_TUR | SSSR_TINT | SSSR_PINT | SSSR_ROR;
+ gspi_write_mmio_reg(dev, SSSR, sssr);
+}
+
+/* Read SSDR and return lowest byte. */
+static int gspi_read_byte(const struct spi_slave *dev, uint8_t *data)
+{
+ uint32_t ssdr;
+ if (gspi_read_mmio_reg(dev, SSDR, &ssdr))
+ return -1;
+ if (data)
+ *data = ssdr & 0xFF;
+ return 0;
+}
+
+/* Write 32-bit word with "data" in lowest byte to SSDR. */
+static int gspi_write_byte(const struct spi_slave *dev, uint8_t data)
+{
+ return gspi_write_mmio_reg(dev, SSDR, data);
+}
+
+enum cs_assert {
+ CS_ASSERT,
+ CS_DEASSERT,
+};
+
+static int gspi_cs_change(const struct spi_slave *dev, enum cs_assert assert)
+{
+ uint32_t cs_ctrl, state;
+
+ if (gspi_read_mmio_reg(dev, SPI_CS_CONTROL, &cs_ctrl))
+ return -1;
+
+ cs_ctrl &= ~CS_STATE_MASK;
+
+ if (cs_ctrl & CS_POLARITY_HIGH)
+ state = (assert == CS_ASSERT) ? CS_STATE_HIGH : CS_STATE_LOW;
+ else
+ state = (assert == CS_ASSERT) ? CS_STATE_LOW : CS_STATE_HIGH;
+
+ cs_ctrl |= state;
+
+ if (gspi_write_mmio_reg(dev, SPI_CS_CONTROL, cs_ctrl))
+ return -1;
+
+ return 0;
+}
+
+static int gspi_cs_assert(const struct spi_slave *dev)
+{
+ return gspi_cs_change(dev, CS_ASSERT);
+}
+
+static void gspi_cs_deassert(const struct spi_slave *dev)
+{
+ gspi_cs_change(dev, CS_DEASSERT);
+}
+
+static uint32_t gspi_get_clk_div(const struct spi_slave *dev)
+{
+ const uint32_t ref_clk_mhz = CONFIG_SOC_INTEL_COMMON_BLOCK_GSPI_CLK_MHZ;
+ const uint32_t gspi_clk_mhz = gspi_get_bus_clk_mhz(dev->bus);
+
+ assert(gspi_clk_mhz != 0);
+ assert(ref_clk_mhz != 0);
+ return (ref_clk_mhz/gspi_clk_mhz - 1) & SSCR0_SCR_MASK;
+}
+
+static int gspi_ctrlr_setup(const struct spi_slave *dev)
+{
+ struct spi_cfg cfg;
+ uint32_t cs_ctrl, sscr0, sscr1, clocks, sitf, sirf;
+
+ /* Only chip select 0 is supported. */
+ if (dev->cs != 0) {
+ printk(BIOS_ERR, "%s: Unsupported device bus=%u,cs=%u!\n",
+ __func__, dev->bus, dev->cs);
+ return -1;
+ }
+
+ /* Obtain SPI bus configuration for the device. */
+ if (spi_get_config(dev, &cfg)) {
+ printk(BIOS_ERR, "%s: Failed to get config for bus=%u.\n",
+ __func__, dev->bus);
+ return -1;
+ }
+
+ /* Take controller out of reset, keeping DMA in reset. */
+ if (gspi_write_mmio_reg(dev, RESETS, CTRLR_ACTIVE | DMA_RESET))
+ return -1;
+
+ /* De-assert SPI chip. */
+ gspi_cs_deassert(dev);
+
+ /*
+ * CS control:
+ * - Set SW mode.
+ * - Set chip select to 0.
+ * - Set polarity based on device configuration.
+ * - Do not assert CS.
+ */
+ cs_ctrl = CS_MODE_SW | CS_0;
+ if (cfg.cs_polarity == SPI_POLARITY_LOW)
+ cs_ctrl |= CS_POLARITY_LOW | CS_STATE_HIGH;
+ else
+ cs_ctrl |= CS_POLARITY_HIGH | CS_STATE_LOW;
+ if (gspi_write_mmio_reg(dev, SPI_CS_CONTROL, cs_ctrl))
+ return -1;
+
+ /* Disable SPI controller. */
+ if (gspi_write_mmio_reg(dev, SSCR0, SSCR0_SSE_DISABLE))
+ return -1;
+
+ /*
+ * SSCR0 configuration:
+ * clk_div - Based on reference clock and expected clock frequency.
+ * data bit length - assumed to be 8, hence EDSS = 0.
+ * ECS - Use on-chip clock
+ * FRF - Frame format set to Motorola SPI
+ */
+ sscr0 = gspi_get_clk_div(dev) << SSCR0_SCR_SHIFT;
+ assert(GSPI_DATA_BIT_LENGTH == 8);
+ sscr0 |= ((GSPI_DATA_BIT_LENGTH - 1) << SSCR0_DSS_SHIFT) | SSCR0_EDSS_0;
+ sscr0 |= SSCR0_ECS_ON_CHIP | SSCR0_FRF_MOTOROLA;
+ if (gspi_write_mmio_reg(dev, SSCR0, sscr0))
+ return -1;
+
+ /*
+ * SSCR1 configuration:
+ * - Chip select polarity
+ * - Clock phase setting
+ * - Clock polarity
+ */
+ sscr1 = (cfg.cs_polarity == SPI_POLARITY_LOW) ? SSCR1_IFS_LOW :
+ SSCR1_IFS_HIGH;
+ sscr1 |= (cfg.clk_phase == SPI_CLOCK_PHASE_FIRST) ? SSCR1_SPH_FIRST :
+ SSCR1_SPH_SECOND;
+ sscr1 |= (cfg.clk_polarity == SPI_POLARITY_LOW) ? SSCR1_SPO_LOW :
+ SSCR1_SPO_HIGH;
+ if (gspi_write_mmio_reg(dev, SSCR1, sscr1))
+ return -1;
+
+ /*
+ * Program m/n divider.
+ * Set m and n to 1, so that this divider acts as a pass-through.
+ */
+ clocks = (1 << CLOCKS_N_SHIFT) | (1 << CLOCKS_M_SHIFT) | CLOCKS_ENABLE;
+ if (gspi_write_mmio_reg(dev, CLOCKS, clocks))
+ return -1;
+ udelay(10);
+
+ /*
+ * Tx FIFO Threshold.
+ * Low watermark threshold = 1
+ * High watermark threshold = 1
+ */
+ sitf = SITF_LWM(1) | SITF_HWM(1);
+ if (gspi_write_mmio_reg(dev, SITF, sitf))
+ return -1;
+ gspi_read_mmio_reg(dev, SITF, &sitf);
+
+ /* Rx FIFO Threshold (set to 1). */
+ sirf = SIRF_WM(1);
+ if (gspi_write_mmio_reg(dev, SIRF, sirf))
+ return -1;
+
+ /* Enable GSPI controller. */
+ sscr0 |= SSCR0_SSE_ENABLE;
+ if (gspi_write_mmio_reg(dev, SSCR0, sscr0))
+ return -1;
+
+ return 0;
+}
+
+static bool gspi_tx_fifo_full(const struct spi_slave *dev)
+{
+ return !(gspi_read_status(dev) & SSSR_TNF);
+}
+
+static bool gspi_rx_fifo_empty(const struct spi_slave *dev)
+{
+ return !(gspi_read_status(dev) & SSSR_RNE);
+}
+
+static bool gspi_rx_fifo_overrun(const struct spi_slave *dev)
+{
+ if (gspi_read_status(dev) & SSSR_ROR) {
+ printk(BIOS_ERR, "%s:GSPI receive FIFO overrun!"
+ " (bus=%u).\n", __func__, dev->bus);
+ return true;
+ }
+
+ return false;
+}
+
+static int gspi_ctrlr_flush(const struct spi_slave *dev)
+{
+ const uint32_t timeout_ms = 500;
+ struct stopwatch sw;
+
+ /* Wait 500ms to allow Rx FIFO to be empty. */
+ stopwatch_init_msecs_expire(&sw, timeout_ms);
+
+ while(!gspi_rx_fifo_empty(dev)) {
+ if (stopwatch_expired(&sw)) {
+ printk(BIOS_ERR, "%s: Rx FIFO not empty after 500ms! "
+ "(bus=%u)\n", __func__, dev->bus);
+ return -1;
+ }
+
+ gspi_read_byte(dev, NULL);
+ }
+
+ return 0;
+}
+
+/* Parameters for xfer operation. */
+struct gspi_xfer_params {
+ const struct spi_slave *dev;
+ uint8_t *in;
+ size_t bytesin;
+ const uint8_t *out;
+ size_t bytesout;
+};
+
+static int gspi_read_data(struct gspi_xfer_params *p)
+{
+ if (gspi_read_byte(p->dev, p->in))
+ return -1;
+ (p->in)++;
+ p->bytesin--;
+ return 0;
+}
+
+static int gspi_write_data(struct gspi_xfer_params *p)
+{
+ if (gspi_write_byte(p->dev, *(p->out)))
+ return -1;
+ (p->out)++;
+ p->bytesout--;
+ return 0;
+}
+
+static int gspi_read_dummy(struct gspi_xfer_params *p)
+{
+ if (gspi_read_byte(p->dev, NULL))
+ return -1;
+ p->bytesin--;
+ return 0;
+}
+
+static int gspi_write_dummy(struct gspi_xfer_params *p)
+{
+ if (gspi_write_byte(p->dev, 0))
+ return -1;
+ p->bytesout--;
+ return 0;
+}
+
+static int __gspi_xfer(struct gspi_xfer_params *p)
+{
+ /*
+ * If bytesin is non-zero, then use gspi_read_data to perform
+ * byte-by-byte read of data from SSDR and save it to "in" buffer. Else
+ * discard the read data using gspi_read_dummy.
+ */
+ int (*fn_read)(struct gspi_xfer_params *p) = gspi_read_data;
+
+ /*
+ * If bytesout is non-zero, then use gspi_write_data to perform
+ * byte-by-byte write of data from "out" buffer to SSDR. Else, use
+ * gspi_write_dummy to write dummy "0" data to SSDR in order to trigger
+ * read from slave.
+ */
+ int (*fn_write)(struct gspi_xfer_params *p) = gspi_write_data;;
+
+ if (!p->bytesin) {
+ p->bytesin = p->bytesout;
+ fn_read = gspi_read_dummy;
+ }
+
+ if (!p->bytesout) {
+ p->bytesout = p->bytesin;
+ fn_write = gspi_write_dummy;
+ }
+
+ while (p->bytesout || p->bytesin) {
+ if (p->bytesout && !gspi_tx_fifo_full(p->dev))
+ if (fn_write(p))
+ return -1;
+ if (p->bytesin && !gspi_rx_fifo_empty(p->dev)) {
+ if (gspi_rx_fifo_overrun(p->dev))
+ return -1;
+ if (fn_read(p))
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int gspi_ctrlr_xfer(const struct spi_slave *dev,
+ const void *dout, size_t bytesout,
+ void *din, size_t bytesin)
+{
+ struct gspi_xfer_params params = {
+ .dev = dev,
+ .in = (uint8_t *)din,
+ .bytesin = bytesin,
+ .out = (const uint8_t *)dout,
+ .bytesout = bytesout,
+ };
+
+ /*
+ * Assumptions about in and out transfers:
+ * 1. Both bytesin and bytesout cannot be 0.
+ * 2. If both bytesin and bytesout are non-zero, then they should be
+ * equal i.e. if both in and out transfers are to be done in same
+ * transaction, then they should be equal in length.
+ * 3. Buffer corresponding to non-zero bytes (bytesin/bytesout) cannot
+ * be NULL.
+ */
+ if (!bytesin && !bytesout) {
+ printk(BIOS_ERR, "%s: Both in and out bytes cannot be zero!\n",
+ __func__);
+ return -1;
+ } else if (bytesin && bytesout && (bytesin != bytesout)) {
+ printk(BIOS_ERR, "%s: bytesin(%zd) != bytesout(%zd)\n",
+ __func__, bytesin, bytesout);
+ return -1;
+ }
+ if ((bytesin && !din) || (bytesout && !dout)) {
+ printk(BIOS_ERR, "%s: in/out buffer is NULL!\n", __func__);
+ return -1;
+ }
+
+ /* Flush out any stale data in Rx FIFO. */
+ if (gspi_ctrlr_flush(dev))
+ return -1;
+
+ /* Clear status bits. */
+ gspi_clear_status(dev);
+
+ return __gspi_xfer(¶ms);
+}
+
+const struct spi_ctrlr gspi_ctrlr = {
+ .get_config = gspi_ctrlr_get_config,
+ .claim_bus = gspi_cs_assert,
+ .release_bus = gspi_cs_deassert,
+ .setup = gspi_ctrlr_setup,
+ .xfer = gspi_ctrlr_xfer,
+};
diff --git a/src/soc/intel/common/block/include/intelblocks/gspi.h b/src/soc/intel/common/block/include/intelblocks/gspi.h
new file mode 100644
index 0000000..868eb53
--- /dev/null
+++ b/src/soc/intel/common/block/include/intelblocks/gspi.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2017 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SOC_INTEL_COMMON_BLOCK_GSPI_H
+#define SOC_INTEL_COMMON_BLOCK_GSPI_H
+
+#include <spi-generic.h>
+#include <stdint.h>
+
+/* GSPI controller structure to allow SoCs to define bus-controller mapping. */
+extern const struct spi_ctrlr gspi_ctrlr;
+
+/*
+ * SoC-provided callback for returning the base address of GSPI controller
+ * controlling the bus.
+ */
+uintptr_t gspi_get_bus_base_address(unsigned int bus);
+
+/*
+ * SoC-provided callback for getting configuration of SPI bus. Driver provides
+ * weak implementation with default SPI-bus configuration.
+ *
+ * Return value:
+ * 0 = Success
+ * non-zero = Error
+ */
+int gspi_get_bus_config(unsigned int bus, struct spi_cfg *cfg);
+
+/* SoC-provided callback for getting desired clock frequency of SPI bus. */
+uint32_t gspi_get_bus_clk_mhz(unsigned int bus);
+
+#endif /* SOC_INTEL_COMMON_BLOCK_LPSS_SPI_H */
--
To view, visit https://review.coreboot.org/19098
To unsubscribe, visit https://review.coreboot.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I0eb91eba2c523be457fee8922c44fb500a9fa140
Gerrit-PatchSet: 1
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Owner: Furquan Shaikh <furquan at google.com>
More information about the coreboot-gerrit
mailing list