summaryrefslogtreecommitdiffstats
path: root/src/soc/imgtec/pistachio/spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/imgtec/pistachio/spi.c')
-rw-r--r--src/soc/imgtec/pistachio/spi.c587
1 files changed, 0 insertions, 587 deletions
diff --git a/src/soc/imgtec/pistachio/spi.c b/src/soc/imgtec/pistachio/spi.c
deleted file mode 100644
index acbbd909bd77..000000000000
--- a/src/soc/imgtec/pistachio/spi.c
+++ /dev/null
@@ -1,587 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2014 Imagination Technologies
- *
- * 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.
- */
-
-#include <console/console.h>
-#include <device/mmio.h>
-#include <soc/cpu.h>
-#include <soc/spi.h>
-#include <spi_flash.h>
-#include <spi-generic.h>
-#include <stdlib.h>
-#include <string.h>
-#include <timer.h>
-
-/* Imgtec controller uses 16 bit packet length. */
-#define IMGTEC_SPI_MAX_TRANSFER_SIZE ((1 << 16) - 1)
-
-struct img_spi_slave {
- /* SPIM instance device parameters */
- struct spim_device_parameters device_parameters;
- /* SPIM instance base address */
- u32 base;
- /* Boolean property that is TRUE if API has been initialised */
- int initialised;
-};
-
-/* Allocate memory for the maximum number of devices */
-static struct
-img_spi_slave img_spi_slaves[SPIM_NUM_BLOCKS*SPIM_NUM_PORTS_PER_BLOCK];
-
-/*
- * Wait for the bit at the shift position to be set in reg
- * If the bit is not set in SPI_TIMEOUT_VALUE_US return with error
- */
-static int wait_status(u32 reg, u32 shift)
-{
- struct stopwatch sw;
-
- stopwatch_init_usecs_expire(&sw, SPI_TIMEOUT_VALUE_US);
- while (!(read32_x(reg) & (1 << shift))) {
- if (stopwatch_expired(&sw))
- return -SPIM_TIMEOUT;
- }
- return SPIM_OK;
-}
-
-static struct img_spi_slave *get_img_slave(const struct spi_slave *slave)
-{
- return img_spi_slaves + slave->bus * SPIM_NUM_PORTS_PER_BLOCK +
- slave->cs;
-}
-
-/* Transmitter function. Fills TX FIFO with data before enabling SPIM */
-static int transmitdata(const struct spi_slave *slave, u8 *buffer, u32 size)
-{
- u32 blocksize, base, write_data;
- int ret;
- struct img_spi_slave *img_slave = get_img_slave(slave);
-
- base = img_slave->base;
- while (size) {
- /* Wait until FIFO empty */
- write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, SPFI_SDE_MASK);
- ret = wait_status(base + SPFI_INT_STATUS_REG_OFFSET,
- SPFI_SDE_SHIFT);
- if (ret)
- return ret;
-
- /*
- * Write to FIFO in blocks of 16 words (64 bytes)
- * Do 32bit writes first.
- */
- blocksize = SPIM_MAX_BLOCK_BYTES;
- while ((size >= sizeof(u32)) && blocksize) {
- memcpy(&write_data, buffer, sizeof(u32));
- write32_x(base + SPFI_SEND_LONG_REG_OFFSET, write_data);
- buffer += sizeof(u32);
- size -= sizeof(u32);
- blocksize -= sizeof(u32);
- }
- while (size && blocksize) {
- write32_x(base + SPFI_SEND_BYTE_REG_OFFSET, *buffer);
- buffer++;
- size--;
- blocksize--;
- }
- }
- return SPIM_OK;
-}
-
-/* Receiver function */
-static int receivedata(const struct spi_slave *slave, u8 *buffer, u32 size)
-{
- u32 read_data, base;
- int ret;
- struct img_spi_slave *img_slave = get_img_slave(slave);
-
- base = img_slave->base;
- /*
- * Do 32bit reads first. Clear status GDEX32BIT here so that the first
- * status reg. read gets the actual bit state
- */
- write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, SPFI_GDEX32BIT_MASK);
- while (size >= sizeof(u32)) {
- ret = wait_status(base + SPFI_INT_STATUS_REG_OFFSET,
- SPFI_GDEX32BIT_SHIFT);
- if (ret)
- return ret;
- read_data = read32_x(base + SPFI_GET_LONG_REG_OFFSET);
- memcpy(buffer, &read_data, sizeof(u32));
- buffer += sizeof(u32);
- size -= sizeof(u32);
- /* Clear interrupt status on GDEX32BITL */
- write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, SPFI_GDEX32BIT_MASK);
- }
-
- /*
- * Do the remaining 8bit reads. Clear status GDEX8BIT here so that
- * the first status reg. read gets the actual bit state
- */
- write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, SPFI_GDEX8BIT_MASK);
- while (size) {
- ret = wait_status(base + SPFI_INT_STATUS_REG_OFFSET,
- SPFI_GDEX8BIT_SHIFT);
- if (ret)
- return ret;
- *buffer = read32_x(base + SPFI_GET_BYTE_REG_OFFSET);
- buffer++;
- size--;
- /* Clear interrupt status on SPFI_GDEX8BIT */
- write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, SPFI_GDEX8BIT_MASK);
- }
- return SPIM_OK;
-}
-
-/* Sets port parameters in port state register. */
-static void setparams(const struct spi_slave *slave, u32 port,
- struct spim_device_parameters *params)
-{
- u32 spim_parameters, port_state, base;
- struct img_spi_slave *img_slave = get_img_slave(slave);
-
- base = img_slave->base;
- spim_parameters = 0;
- port_state = read32_x(base + SPFI_PORT_STATE_REG_OFFSET);
- port_state &= ~((SPIM_PORT0_MASK>>port)|SPFI_PORT_SELECT_MASK);
- port_state |= params->cs_idle_level<<(SPIM_CS0_IDLE_SHIFT-port);
- port_state |=
- params->data_idle_level<<(SPIM_DATA0_IDLE_SHIFT-port);
-
- /* Clock idle level and phase */
- switch (params->spi_mode) {
- case SPIM_MODE_0:
- break;
- case SPIM_MODE_1:
- port_state |= (1 << (SPIM_CLOCK0_PHASE_SHIFT - port));
- break;
- case SPIM_MODE_2:
- port_state |= (1 << (SPIM_CLOCK0_IDLE_SHIFT - port));
- break;
- case SPIM_MODE_3:
- port_state |= (1 << (SPIM_CLOCK0_IDLE_SHIFT - port)) |
- (1 << (SPIM_CLOCK0_PHASE_SHIFT - port));
- break;
- }
- /* Set port state register */
- write32_x(base + SPFI_PORT_STATE_REG_OFFSET, port_state);
-
- /* Set up values to be written to device parameter register */
- spim_parameters |= params->bitrate << SPIM_CLK_DIVIDE_SHIFT;
- spim_parameters |= params->cs_setup << SPIM_CS_SETUP_SHIFT;
- spim_parameters |= params->cs_hold << SPIM_CS_HOLD_SHIFT;
- spim_parameters |= params->cs_delay << SPIM_CS_DELAY_SHIFT;
-
- write32_x(base + SPFI_PORT_0_PARAM_REG_OFFSET + 4 * port,
- spim_parameters);
-}
-
-/* Sets up transaction register */
-static u32 transaction_reg_setup(struct spim_buffer *first,
- struct spim_buffer *second)
-{
- u32 reg = 0;
-
- /* 2nd transfer exists? */
- if (second) {
- /*
- * If second transfer exists, it's a "command followed by data"
- * type of transfer and first transfer is defined by
- * CMD_LENGTH, ADDR_LENGTH, DUMMY_LENGTH... fields of
- * transaction register
- */
- reg = spi_write_reg_field(reg, SPFI_CMD_LENGTH, 1);
- reg = spi_write_reg_field(reg, SPFI_ADDR_LENGTH,
- first->size - 1);
- reg = spi_write_reg_field(reg, SPFI_DUMMY_LENGTH, 0);
- /* Set data size (size of the second transfer) */
- reg = spi_write_reg_field(reg, SPFI_TSIZE, second->size);
- } else {
- /* Set data size, in this case size of the 1st transfer */
- reg = spi_write_reg_field(reg, SPFI_TSIZE, first->size);
- }
- return reg;
-}
-
-/* Sets up control register */
-static u32 control_reg_setup(struct spim_buffer *first,
- struct spim_buffer *second)
-{
- u32 reg;
-
- /* Enable SPFI */
- reg = SPFI_EN_MASK;
- reg |= first->inter_byte_delay ? SPIM_BYTE_DELAY_MASK : 0;
-
- /* Set up the transfer mode */
- reg = spi_write_reg_field(reg, SPFI_TRNSFR_MODE_DQ, SPIM_CMD_MODE_0);
- reg = spi_write_reg_field(reg, SPFI_TRNSFR_MODE, SPIM_DMODE_SINGLE);
- reg = spi_write_reg_field(reg, SPIM_EDGE_TX_RX, 1);
-
- if (second) {
- /* Set TX bit if the 2nd transaction is 'send' */
- reg = spi_write_reg_field(reg, SPFI_TX_RX,
- second->isread ? 0 : 1);
- /*
- * Set send/get DMA for both transactions
- * (first is always 'send')
- */
- reg = spi_write_reg_field(reg, SPIM_SEND_DMA, 1);
- if (second->isread)
- reg = spi_write_reg_field(reg, SPIM_GET_DMA, 1);
-
- } else {
- /* Set TX bit if the 1st transaction is 'send' */
- reg |= first->isread ? 0 : SPFI_TX_RX_MASK;
- /* Set send/get DMA */
- reg |= first->isread ? SPIM_GET_DMA_MASK : SPIM_SEND_DMA_MASK;
- }
- return reg;
-}
-
-/* Checks the given buffer information */
-static int check_buffers(const struct spi_slave *slave, struct spim_buffer *first,
- struct spim_buffer *second){
-
- struct img_spi_slave *img_slave = get_img_slave(slave);
-
- if (!(img_slave->initialised))
- return -SPIM_API_NOT_INITIALISED;
- /*
- * First operation must always be defined
- * It can be either a read or a write and its size cannot be bigge
- * than SPIM_MAX_TANSFER_BYTES = 64KB - 1 (0xFFFF)
- */
- if (!first)
- return -SPIM_INVALID_READ_WRITE;
- if (first->size > SPIM_MAX_TRANSFER_BYTES)
- return -SPIM_INVALID_SIZE;
- if (first->isread > 1)
- return -SPIM_INVALID_READ_WRITE;
- /* Check operation parameters for 'second' */
- if (second) {
- /*
- * If the second operation is defined it must be a read
- * operation and its size must not be bigger than
- * SPIM_MAX_TANSFER_BYTES = 64KB - 1 (0xFFFF)
- */
- if (second->size > SPIM_MAX_TRANSFER_BYTES)
- return -SPIM_INVALID_SIZE;
- if (!second->isread)
- return -SPIM_INVALID_READ_WRITE;
- /*
- * If the second operations is defined, the first operation
- * must be a write and its size cannot be bigger than
- * SPIM_MAX_FLASH_COMMAND_BYTES(8): command size (1) +
- * address size (7).
- */
- if (first->isread)
- return -SPIM_INVALID_READ_WRITE;
- if (first->size > SPIM_MAX_FLASH_COMMAND_BYTES)
- return -SPIM_INVALID_SIZE;
-
- }
- return SPIM_OK;
-}
-
-/* Checks the set bitrate */
-static int check_bitrate(u32 rate)
-{
- /* Bitrate must be 1, 2, 4, 8, 16, 32, 64, or 128 */
- switch (rate) {
- case 1:
- case 2:
- case 4:
- case 8:
- case 16:
- case 32:
- case 64:
- case 128:
- return SPIM_OK;
- default:
- return -SPIM_INVALID_BIT_RATE;
- }
- return -SPIM_INVALID_BIT_RATE;
-}
-
-/* Checks device parameters for errors */
-static int check_device_params(struct spim_device_parameters *pdev_param)
-{
- if (pdev_param->spi_mode < SPIM_MODE_0 ||
- pdev_param->spi_mode > SPIM_MODE_3)
- return -SPIM_INVALID_SPI_MODE;
- if (check_bitrate(pdev_param->bitrate) != SPIM_OK)
- return -SPIM_INVALID_BIT_RATE;
- if (pdev_param->cs_idle_level > 1)
- return -SPIM_INVALID_CS_IDLE_LEVEL;
- if (pdev_param->data_idle_level > 1)
- return -SPIM_INVALID_DATA_IDLE_LEVEL;
- return SPIM_OK;
-}
-
-/* Function that carries out read/write operations */
-static int spim_io(const struct spi_slave *slave, struct spim_buffer *first,
- struct spim_buffer *second)
-{
- u32 reg, base;
- int i, trans_count, ret;
- struct spim_buffer *transaction[2];
- struct img_spi_slave *img_slave = get_img_slave(slave);
-
- base = img_slave->base;
-
- ret = check_buffers(slave, first, second);
- if (ret)
- return ret;
-
- /*
- * Soft reset peripheral internals, this will terminate any
- * pending transactions
- */
- write32_x(base + SPFI_CONTROL_REG_OFFSET, SPIM_SOFT_RESET_MASK);
- write32_x(base + SPFI_CONTROL_REG_OFFSET, 0);
- /* Port state register */
- reg = read32_x(base + SPFI_PORT_STATE_REG_OFFSET);
- reg = spi_write_reg_field(reg, SPFI_PORT_SELECT, slave->cs);
- write32_x(base + SPFI_PORT_STATE_REG_OFFSET, reg);
- /* Set transaction register */
- reg = transaction_reg_setup(first, second);
- write32_x(base + SPFI_TRANSACTION_REG_OFFSET, reg);
- /* Clear status */
- write32_x(base + SPFI_INT_CLEAR_REG_OFFSET, 0xffffffff);
- /* Set control register */
- reg = control_reg_setup(first, second);
- write32_x(base + SPFI_CONTROL_REG_OFFSET, reg);
- /* First transaction always exists */
- transaction[0] = first;
- trans_count = 1;
- /* Is there a second transaction? */
- if (second) {
- transaction[1] = second;
- trans_count++;
- }
- /* Now write/read FIFO's */
- for (i = 0; i < trans_count; i++)
- /* Which transaction to execute, "Send" or "Get"? */
- if (transaction[i]->isread) {
- /* Get */
- ret = receivedata(slave, transaction[i]->buffer,
- transaction[i]->size);
- if (ret) {
- printk(BIOS_ERR,
- "%s: Error: receive data failed.\n",
- __func__);
- return ret;
- }
- } else {
- /* Send */
- ret = transmitdata(slave, transaction[i]->buffer,
- transaction[i]->size);
- if (ret) {
- printk(BIOS_ERR,
- "%s: Error: transmit data failed.\n",
- __func__);
- return ret;
- }
- }
-
- /* Wait for end of the transaction */
- ret = wait_status(base + SPFI_INT_STATUS_REG_OFFSET,
- SPFI_ALLDONE_SHIFT);
- if (ret)
- return ret;
- /*
- * Soft reset peripheral internals, this will terminate any
- * pending transactions
- */
- write32_x(base + SPFI_CONTROL_REG_OFFSET, SPIM_SOFT_RESET_MASK);
- write32_x(base + SPFI_CONTROL_REG_OFFSET, 0);
-
- return SPIM_OK;
-}
-
-/* Claim the bus and prepare it for communication */
-static int spi_ctrlr_claim_bus(const struct spi_slave *slave)
-{
- int ret;
- struct img_spi_slave *img_slave;
-
- if (!slave) {
- printk(BIOS_ERR, "%s: Error: slave was not set up.\n",
- __func__);
- return -SPIM_API_NOT_INITIALISED;
- }
- img_slave = get_img_slave(slave);
- if (img_slave->initialised)
- return SPIM_OK;
- /* Check device parameters */
- ret = check_device_params(&(img_slave->device_parameters));
- if (ret) {
- printk(BIOS_ERR, "%s: Error: incorrect device parameters.\n",
- __func__);
- return ret;
- }
- /* Set device parameters */
- setparams(slave, slave->cs, &(img_slave->device_parameters));
- /* Soft reset peripheral internals */
- write32_x(img_slave->base + SPFI_CONTROL_REG_OFFSET,
- SPIM_SOFT_RESET_MASK);
- write32_x(img_slave->base + SPFI_CONTROL_REG_OFFSET, 0);
- img_slave->initialised = IMG_TRUE;
- return SPIM_OK;
-}
-
-/* Release the SPI bus */
-static void spi_ctrlr_release_bus(const struct spi_slave *slave)
-{
- struct img_spi_slave *img_slave;
-
- if (!slave) {
- printk(BIOS_ERR, "%s: Error: slave was not set up.\n",
- __func__);
- return;
- }
- img_slave = get_img_slave(slave);
- img_slave->initialised = IMG_FALSE;
- /* Soft reset peripheral internals */
- write32_x(img_slave->base + SPFI_CONTROL_REG_OFFSET,
- SPIM_SOFT_RESET_MASK);
- write32_x(img_slave->base + SPFI_CONTROL_REG_OFFSET, 0);
-}
-
-/* SPI transfer */
-static int do_spi_xfer(const struct spi_slave *slave, const void *dout,
- size_t bytesout, void *din, size_t bytesin)
-{
- struct spim_buffer buff_0;
- struct spim_buffer buff_1;
-
- /* If we only have a read or a write operation
- * the parameters for it will be put in the first buffer
- */
- buff_0.buffer = (dout) ? (void *)dout : (void *)din;
- buff_0.size = (dout) ? bytesout : bytesin;
- buff_0.isread = (dout) ? IMG_FALSE : IMG_TRUE;
- buff_0.inter_byte_delay = 0;
-
- if (dout && din) {
- /* Set up the read buffer to receive our data */
- buff_1.buffer = din;
- buff_1.size = bytesin;
- buff_1.isread = IMG_TRUE;
- buff_1.inter_byte_delay = 0;
- }
- return spim_io(slave, &buff_0, (dout && din) ? &buff_1 : NULL);
-}
-
-static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
- size_t bytesout, void *din, size_t bytesin)
-{
- unsigned int in_sz, out_sz;
- int ret;
-
- if (!slave) {
- printk(BIOS_ERR, "%s: Error: slave was not set up.\n",
- __func__);
- return -SPIM_API_NOT_INITIALISED;
- }
- if (!dout && !din) {
- printk(BIOS_ERR, "%s: Error: both buffers are NULL.\n",
- __func__);
- return -SPIM_INVALID_TRANSFER_DESC;
- }
-
- while (bytesin || bytesout) {
- in_sz = min(IMGTEC_SPI_MAX_TRANSFER_SIZE, bytesin);
- out_sz = min(IMGTEC_SPI_MAX_TRANSFER_SIZE, bytesout);
-
- ret = do_spi_xfer(slave, dout, out_sz, din, in_sz);
- if (ret)
- return ret;
-
- bytesin -= in_sz;
- bytesout -= out_sz;
-
- if (bytesin)
- din += in_sz;
- else
- din = NULL;
-
- if (bytesout)
- dout += out_sz;
- else
- dout = NULL;
- }
-
- return SPIM_OK;
-}
-
-static int spi_ctrlr_setup(const struct spi_slave *slave)
-{
- struct img_spi_slave *img_slave = NULL;
- struct spim_device_parameters *device_parameters;
- u32 base;
-
- switch (slave->bus) {
- case 0:
- base = IMG_SPIM0_BASE_ADDRESS;
- break;
- case 1:
- base = IMG_SPIM1_BASE_ADDRESS;
- break;
- default:
- printk(BIOS_ERR, "%s: Error: unsupported bus.\n",
- __func__);
- return -1;
- }
- if (slave->cs > SPIM_DEVICE4) {
- printk(BIOS_ERR, "%s: Error: unsupported chipselect.\n",
- __func__);
- return -1;
- }
-
- img_slave = get_img_slave(slave);
- device_parameters = &(img_slave->device_parameters);
-
- img_slave->base = base;
-
- device_parameters->bitrate = 64;
- device_parameters->cs_setup = 0;
- device_parameters->cs_hold = 0;
- device_parameters->cs_delay = 0;
- device_parameters->spi_mode = SPIM_MODE_0;
- device_parameters->cs_idle_level = 1;
- device_parameters->data_idle_level = 0;
- img_slave->initialised = IMG_FALSE;
-
- return 0;
-}
-
-static const struct spi_ctrlr spi_ctrlr = {
- .setup = spi_ctrlr_setup,
- .claim_bus = spi_ctrlr_claim_bus,
- .release_bus = spi_ctrlr_release_bus,
- .xfer = spi_ctrlr_xfer,
- .max_xfer_size = IMGTEC_SPI_MAX_TRANSFER_SIZE,
-};
-
-const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = {
- {
- .ctrlr = &spi_ctrlr,
- .bus_start = 0,
- .bus_end = 1,
- },
-};
-
-const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map);