text: /*
   * 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/early_variables.h>
  #include <arch/io.h>
  #include <assert.h>
  #include <compiler.h>
  #include <console/console.h>
  #include <delay.h>
  #include <device/device.h>
  #include <device/pci_def.h>
  #include <device/pci_ops.h>
  #include <intelblocks/chip.h>
  #include <intelblocks/gspi.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 = dev_find_slot(0, 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] CAR_GLOBAL;
  static uintptr_t gspi_get_bus_base_addr(unsigned int gspi_bus)
  {
  	uintptr_t *base = car_get_var_ptr(gspi_base);
  
  	if (!base[gspi_bus])
  		base[gspi_bus] = gspi_calc_base_addr(gspi_bus);
  
  	return 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 (IS_ENABLED(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 (IS_ENABLED(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;
  	const uint32_t gspi_clk_mhz = gspi_get_bus_clk_mhz(gspi_bus);
  
  	assert(gspi_clk_mhz != 0);
  	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;
  	uint32_t cs_ctrl, sscr0, sscr1, clocks, sitf, sirf, pol;
  	struct gspi_ctrlr_params params, *p = &params;
  
  	/* 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;
  	}
  
  	/* 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);
  	gspi_write_mmio_reg(p, SPI_CS_CONTROL, cs_ctrl);
  
  	/* De-assert chip select. */
  	__gspi_cs_change(p, CS_DEASSERT);
  
  	/* 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,
  };
  