diff options
Diffstat (limited to 'src/soc/imgtec/pistachio/spi.c')
-rw-r--r-- | src/soc/imgtec/pistachio/spi.c | 587 |
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 acbbd909bd..0000000000 --- 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); |