blob: 939d2e014686e55b30496849326d19110440e422 [file] [log] [blame]
/* This file is part of the coreboot project. */
/*
*
* 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 <device/mmio.h>
#include <assert.h>
#include <console/console.h>
#include <delay.h>
#include <device/device.h>
#include <device/pci_def.h>
#include <device/pci_ops.h>
#include <intelblocks/cfg.h>
#include <intelblocks/gspi.h>
#include <intelblocks/lpss.h>
#include <intelblocks/spi.h>
#include <soc/iomap.h>
#include <soc/pci_devs.h>
#include <string.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_0_POL_SHIFT (12)
#define CS_0_POL_MASK (1 << CS_0_POL_SHIFT)
#define CS_POL_LOW (0)
#define CS_POL_HIGH (1)
#define CS_0 (0 << 8)
#define CS_STATE_SHIFT (1)
#define CS_STATE_MASK (1 << CS_STATE_SHIFT)
#define CS_V1_STATE_LOW (0)
#define CS_V1_STATE_HIGH (1)
#define CS_MODE_HW (0 << 0)
#define CS_MODE_SW (1 << 0)
#define GSPI_DATA_BIT_LENGTH (8)
#define GSPI_BUS_BASE(bar, bus) ((bar) + (bus) * 4 * KiB)
/* Get base address for early init of GSPI controllers. */
static uintptr_t gspi_get_early_base(void)
{
return EARLY_GSPI_BASE_ADDRESS;
}
/* Get gspi_config array from devicetree. Returns NULL in case of error. */
static const struct gspi_cfg *gspi_get_cfg(void)
{
const struct soc_intel_common_config *common_config;
common_config = chip_get_common_soc_structure();
return &common_config->gspi[0];
}
#if defined(__SIMPLE_DEVICE__)
static uintptr_t gspi_get_base_addr(int devfn,
DEVTREE_CONST struct device *dev)
{
pci_devfn_t pci_dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn));
return ALIGN_DOWN(pci_read_config32(pci_dev, PCI_BASE_ADDRESS_0), 16);
}
static void gspi_set_base_addr(int devfn, DEVTREE_CONST struct device *dev,
uintptr_t base)
{
pci_devfn_t pci_dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn));
pci_write_config32(pci_dev, PCI_BASE_ADDRESS_0, base);
pci_write_config32(pci_dev, PCI_COMMAND, PCI_COMMAND_MEMORY |
PCI_COMMAND_MASTER);
}
void gspi_early_bar_init(void)
{
unsigned int gspi_bus;
const unsigned int gspi_max = CONFIG_SOC_INTEL_COMMON_BLOCK_GSPI_MAX;
const struct gspi_cfg *cfg = gspi_get_cfg();
int devfn;
uintptr_t gspi_base_addr;
assert(gspi_max != 0);
if (!cfg) {
printk(BIOS_ERR, "%s: No GSPI config provided by SoC!\n",
__func__);
return;
}
gspi_base_addr = gspi_get_early_base();
if (!gspi_base_addr) {
printk(BIOS_ERR, "%s: GSPI base address provided is NULL!\n",
__func__);
return;
}
for (gspi_bus = 0; gspi_bus < gspi_max; gspi_bus++) {
if (!cfg[gspi_bus].early_init)
continue;
devfn = gspi_soc_bus_to_devfn(gspi_bus);
gspi_set_base_addr(devfn, NULL,
GSPI_BUS_BASE(gspi_base_addr, gspi_bus));
}
}
#else
static uintptr_t gspi_get_base_addr(int devfn, struct device *dev)
{
return ALIGN_DOWN(pci_read_config32(dev, PCI_BASE_ADDRESS_0), 16);
}
static void gspi_set_base_addr(int devfn, struct device *dev, uintptr_t base)
{
pci_write_config32(dev, PCI_BASE_ADDRESS_0, base);
pci_write_config32(dev, PCI_COMMAND, PCI_COMMAND_MEMORY |
PCI_COMMAND_MASTER);
}
#endif
static int gspi_read_bus_range(unsigned int *start, unsigned int *end)
{
size_t i;
const struct spi_ctrlr_buses *desc;
for (i = 0; i < spi_ctrlr_bus_map_count; i++) {
desc = &spi_ctrlr_bus_map[i];
if (desc->ctrlr != &gspi_ctrlr)
continue;
*start = desc->bus_start;
*end = desc->bus_end;
return 0;
}
return -1;
}
static int gspi_spi_to_gspi_bus(unsigned int spi_bus, unsigned int *gspi_bus)
{
unsigned int start;
unsigned int end;
int ret;
ret = gspi_read_bus_range(&start, &end);
if (ret != 0 || (spi_bus < start) || (spi_bus > end))
return -1;
*gspi_bus = spi_bus - start;
return 0;
}
static uintptr_t gspi_calc_base_addr(unsigned int gspi_bus)
{
uintptr_t bus_base, gspi_base_addr;
DEVTREE_CONST struct device *dev;
int devfn = gspi_soc_bus_to_devfn(gspi_bus);
if (devfn < 0)
return 0;
dev = pcidev_path_on_root(devfn);
if (!dev || !dev->enabled)
return 0;
bus_base = gspi_get_base_addr(devfn, dev);
if (bus_base)
return bus_base;
gspi_base_addr = gspi_get_early_base();
if (!gspi_base_addr)
return 0;
bus_base = GSPI_BUS_BASE(gspi_base_addr, gspi_bus);
gspi_set_base_addr(devfn, dev, bus_base);
return bus_base;
}
static uint32_t gspi_get_bus_clk_mhz(unsigned int gspi_bus)
{
const struct gspi_cfg *cfg = gspi_get_cfg();
if (!cfg)
return 0;
return cfg[gspi_bus].speed_mhz;
}
static uintptr_t gspi_base[CONFIG_SOC_INTEL_COMMON_BLOCK_GSPI_MAX];
static uintptr_t gspi_get_bus_base_addr(unsigned int gspi_bus)
{
if (!gspi_base[gspi_bus])
gspi_base[gspi_bus] = gspi_calc_base_addr(gspi_bus);
return gspi_base[gspi_bus];
}
/* Parameters for GSPI controller operation. */
struct gspi_ctrlr_params {
uintptr_t mmio_base;
unsigned int gspi_bus;
uint8_t *in;
size_t bytesin;
const uint8_t *out;
size_t bytesout;
};
static uint32_t gspi_read_mmio_reg(const struct gspi_ctrlr_params *p,
uint32_t offset)
{
assert(p->mmio_base != 0);
return read32((void *)(p->mmio_base + offset));
}
static void gspi_write_mmio_reg(const struct gspi_ctrlr_params *p,
uint32_t offset, uint32_t value)
{
assert(p->mmio_base != 0);
write32((void *)(p->mmio_base + offset), value);
}
static int gspi_ctrlr_params_init(struct gspi_ctrlr_params *p,
unsigned int spi_bus)
{
memset(p, 0, sizeof(*p));
if (gspi_spi_to_gspi_bus(spi_bus, &p->gspi_bus)) {
printk(BIOS_ERR, "%s: No GSPI bus available for SPI bus %u.\n",
__func__, spi_bus);
return -1;
}
p->mmio_base = gspi_get_bus_base_addr(p->gspi_bus);
if (!p->mmio_base) {
printk(BIOS_ERR, "%s: Base addr is 0 for GSPI bus=%u.\n",
__func__, p->gspi_bus);
return -1;
}
return 0;
}
enum cs_assert {
CS_ASSERT,
CS_DEASSERT,
};
/*
* SPI_CS_CONTROL bit definitions based on GSPI_VERSION_x:
*
* VERSION_2 (CNL GSPI controller):
* Polarity: Indicates inactive polarity of chip-select
* State : Indicates assert/de-assert of chip-select
*
* Default (SKL/KBL GSPI controller):
* Polarity: Indicates active polarity of chip-select
* State : Indicates low/high output state of chip-select
*/
static uint32_t gspi_csctrl_state_v2(uint32_t pol, enum cs_assert cs_assert)
{
return cs_assert;
}
static uint32_t gspi_csctrl_state_v1(uint32_t pol, enum cs_assert cs_assert)
{
uint32_t state;
if (pol == CS_POL_HIGH)
state = (cs_assert == CS_ASSERT) ? CS_V1_STATE_HIGH :
CS_V1_STATE_LOW;
else
state = (cs_assert == CS_ASSERT) ? CS_V1_STATE_LOW :
CS_V1_STATE_HIGH;
return state;
}
static uint32_t gspi_csctrl_state(uint32_t pol, enum cs_assert cs_assert)
{
if (CONFIG(SOC_INTEL_COMMON_BLOCK_GSPI_VERSION_2))
return gspi_csctrl_state_v2(pol, cs_assert);
return gspi_csctrl_state_v1(pol, cs_assert);
}
static uint32_t gspi_csctrl_polarity_v2(enum spi_polarity active_pol)
{
/* Polarity field indicates cs inactive polarity */
if (active_pol == SPI_POLARITY_LOW)
return CS_POL_HIGH;
return CS_POL_LOW;
}
static uint32_t gspi_csctrl_polarity_v1(enum spi_polarity active_pol)
{
/* Polarity field indicates cs active polarity */
if (active_pol == SPI_POLARITY_LOW)
return CS_POL_LOW;
return CS_POL_HIGH;
}
static uint32_t gspi_csctrl_polarity(enum spi_polarity active_pol)
{
if (CONFIG(SOC_INTEL_COMMON_BLOCK_GSPI_VERSION_2))
return gspi_csctrl_polarity_v2(active_pol);
return gspi_csctrl_polarity_v1(active_pol);
}
static void __gspi_cs_change(const struct gspi_ctrlr_params *p,
enum cs_assert cs_assert)
{
uint32_t cs_ctrl, pol;
cs_ctrl = gspi_read_mmio_reg(p, SPI_CS_CONTROL);
cs_ctrl &= ~CS_STATE_MASK;
pol = !!(cs_ctrl & CS_0_POL_MASK);
cs_ctrl |= gspi_csctrl_state(pol, cs_assert) << CS_STATE_SHIFT;
gspi_write_mmio_reg(p, SPI_CS_CONTROL, cs_ctrl);
}
static int gspi_cs_change(const struct spi_slave *dev, enum cs_assert cs_assert)
{
struct gspi_ctrlr_params params, *p = &params;
if (gspi_ctrlr_params_init(p, dev->bus))
return -1;
__gspi_cs_change(p, cs_assert);
return 0;
}
int __weak gspi_get_soc_spi_cfg(unsigned int gspi_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_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(unsigned int gspi_bus)
{
const uint32_t ref_clk_mhz =
CONFIG_SOC_INTEL_COMMON_BLOCK_GSPI_CLOCK_MHZ;
uint32_t gspi_clk_mhz = gspi_get_bus_clk_mhz(gspi_bus);
if (!gspi_clk_mhz)
gspi_clk_mhz = 1;
assert(ref_clk_mhz != 0);
return (DIV_ROUND_UP(ref_clk_mhz, gspi_clk_mhz) - 1) & SSCR0_SCR_MASK;
}
static int gspi_ctrlr_setup(const struct spi_slave *dev)
{
struct spi_cfg cfg;
int devfn;
uint32_t cs_ctrl, sscr0, sscr1, clocks, sitf, sirf, pol;
struct gspi_ctrlr_params params, *p = &params;
const struct device *device;
/* Only chip select 0 is supported. */
if (dev->cs != 0) {
printk(BIOS_ERR, "%s: Invalid CS value: cs=%u.\n", __func__,
dev->cs);
return -1;
}
if (gspi_ctrlr_params_init(p, dev->bus))
return -1;
/* Obtain SPI bus configuration for the device. */
if (gspi_get_soc_spi_cfg(p->gspi_bus, &cfg)) {
printk(BIOS_ERR, "%s: Failed to get config for bus=%u.\n",
__func__, p->gspi_bus);
return -1;
}
devfn = gspi_soc_bus_to_devfn(p->gspi_bus);
/*
* devfn is already validated as part of gspi_ctrlr_params_init.
* No need to revalidate it again.
*/
device = pcidev_path_on_root(devfn);
/* Ensure controller is in D0 state */
lpss_set_power_state(device, STATE_D0);
/* Take controller out of reset, keeping DMA in reset. */
gspi_write_mmio_reg(p, RESETS, CTRLR_ACTIVE | DMA_RESET);
/*
* 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;
pol = gspi_csctrl_polarity(cfg.cs_polarity);
cs_ctrl |= pol << CS_0_POL_SHIFT;
cs_ctrl |= gspi_csctrl_state(pol, CS_DEASSERT) << CS_STATE_SHIFT;
gspi_write_mmio_reg(p, SPI_CS_CONTROL, cs_ctrl);
/* Disable SPI controller. */
gspi_write_mmio_reg(p, SSCR0, SSCR0_SSE_DISABLE);
/*
* 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(p->gspi_bus) << 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;
gspi_write_mmio_reg(p, SSCR0, sscr0);
/*
* 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;
gspi_write_mmio_reg(p, SSCR1, sscr1);
/*
* 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 |
CLOCKS_UPDATE;
gspi_write_mmio_reg(p, CLOCKS, clocks);
udelay(10);
/*
* Tx FIFO Threshold.
* Low watermark threshold = 1
* High watermark threshold = 1
*/
sitf = SITF_LWM(1) | SITF_HWM(1);
gspi_write_mmio_reg(p, SITF, sitf);
/* Rx FIFO Threshold (set to 1). */
sirf = SIRF_WM(1);
gspi_write_mmio_reg(p, SIRF, sirf);
/* Enable GSPI controller. */
sscr0 |= SSCR0_SSE_ENABLE;
gspi_write_mmio_reg(p, SSCR0, sscr0);
return 0;
}
static uint32_t gspi_read_status(const struct gspi_ctrlr_params *p)
{
return gspi_read_mmio_reg(p, SSSR);
}
static void gspi_clear_status(const struct gspi_ctrlr_params *p)
{
const uint32_t sssr = SSSR_TUR | SSSR_TINT | SSSR_PINT | SSSR_ROR;
gspi_write_mmio_reg(p, SSSR, sssr);
}
static bool gspi_rx_fifo_empty(const struct gspi_ctrlr_params *p)
{
return !(gspi_read_status(p) & SSSR_RNE);
}
static bool gspi_tx_fifo_full(const struct gspi_ctrlr_params *p)
{
return !(gspi_read_status(p) & SSSR_TNF);
}
static bool gspi_rx_fifo_overrun(const struct gspi_ctrlr_params *p)
{
if (gspi_read_status(p) & SSSR_ROR) {
printk(BIOS_ERR, "%s:GSPI receive FIFO overrun!"
" (bus=%u).\n", __func__, p->gspi_bus);
return true;
}
return false;
}
/* Read SSDR and return lowest byte. */
static uint8_t gspi_read_byte(const struct gspi_ctrlr_params *p)
{
return gspi_read_mmio_reg(p, SSDR) & 0xFF;
}
/* Write 32-bit word with "data" in lowest byte to SSDR. */
static void gspi_write_byte(const struct gspi_ctrlr_params *p, uint8_t data)
{
return gspi_write_mmio_reg(p, SSDR, data);
}
static void gspi_read_data(struct gspi_ctrlr_params *p)
{
*(p->in) = gspi_read_byte(p);
p->in++;
p->bytesin--;
}
static void gspi_write_data(struct gspi_ctrlr_params *p)
{
gspi_write_byte(p, *(p->out));
p->out++;
p->bytesout--;
}
static void gspi_read_dummy(struct gspi_ctrlr_params *p)
{
gspi_read_byte(p);
p->bytesin--;
}
static void gspi_write_dummy(struct gspi_ctrlr_params *p)
{
gspi_write_byte(p, 0);
p->bytesout--;
}
static int gspi_ctrlr_flush(const struct gspi_ctrlr_params *p)
{
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(p)) {
if (stopwatch_expired(&sw)) {
printk(BIOS_ERR, "%s: Rx FIFO not empty after 500ms! "
"(bus=%u)\n", __func__, p->gspi_bus);
return -1;
}
gspi_read_byte(p);
}
return 0;
}
static int __gspi_xfer(struct gspi_ctrlr_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.
*/
void (*fn_read)(struct gspi_ctrlr_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.
*/
void (*fn_write)(struct gspi_ctrlr_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))
fn_write(p);
if (p->bytesin && !gspi_rx_fifo_empty(p)) {
if (gspi_rx_fifo_overrun(p))
return -1;
fn_read(p);
}
}
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_ctrlr_params params;
struct gspi_ctrlr_params *p = &params;
/*
* 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;
}
if (gspi_ctrlr_params_init(p, dev->bus))
return -1;
/* Flush out any stale data in Rx FIFO. */
if (gspi_ctrlr_flush(p))
return -1;
/* Clear status bits. */
gspi_clear_status(p);
p->in = din;
p->bytesin = bytesin;
p->out = dout;
p->bytesout = bytesout;
return __gspi_xfer(p);
}
const struct spi_ctrlr gspi_ctrlr = {
.claim_bus = gspi_cs_assert,
.release_bus = gspi_cs_deassert,
.setup = gspi_ctrlr_setup,
.xfer = gspi_ctrlr_xfer,
.max_xfer_size = SPI_CTRLR_DEFAULT_MAX_XFER_SIZE,
};