blob: 373827820bade6df2a2346caee7103163ef31d57 [file] [log] [blame]
/*
* NVIDIA Tegra SPI controller (T114 and later)
*
* Copyright (c) 2010-2013 NVIDIA Corporation
* Copyright (C) 2013 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <assert.h>
#include <cbfs.h>
#include <cbfs_core.h>
#include <inttypes.h>
#include <spi-generic.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <arch/cache.h>
#include <arch/io.h>
#include <console/console.h>
#include <soc/addressmap.h>
#include <delay.h>
#include "dma.h"
#include "spi.h"
#if defined(CONFIG_DEBUG_SPI) && CONFIG_DEBUG_SPI
# define DEBUG_SPI(x,...) printk(BIOS_DEBUG, "TEGRA_SPI: " x)
#else
# define DEBUG_SPI(x,...)
#endif
/*
* 64 packets in FIFO mode, BLOCK_SIZE packets in DMA mode. Packets can vary
* in size from 4 to 32 bits. To keep things simple we'll use 8-bit packets.
*/
#define SPI_PACKET_SIZE_BYTES 1
#define SPI_MAX_TRANSFER_BYTES_FIFO (64 * SPI_PACKET_SIZE_BYTES)
#define SPI_MAX_TRANSFER_BYTES_DMA (65535 * SPI_PACKET_SIZE_BYTES)
/* COMMAND1 */
#define SPI_CMD1_GO (1 << 31)
#define SPI_CMD1_M_S (1 << 30)
#define SPI_CMD1_MODE_MASK 0x3
#define SPI_CMD1_MODE_SHIFT 28
#define SPI_CMD1_CS_SEL_MASK 0x3
#define SPI_CMD1_CS_SEL_SHIFT 26
#define SPI_CMD1_CS_POL_INACTIVE3 (1 << 25)
#define SPI_CMD1_CS_POL_INACTIVE2 (1 << 24)
#define SPI_CMD1_CS_POL_INACTIVE1 (1 << 23)
#define SPI_CMD1_CS_POL_INACTIVE0 (1 << 22)
#define SPI_CMD1_CS_SW_HW (1 << 21)
#define SPI_CMD1_CS_SW_VAL (1 << 20)
#define SPI_CMD1_IDLE_SDA_MASK 0x3
#define SPI_CMD1_IDLE_SDA_SHIFT 18
#define SPI_CMD1_BIDIR (1 << 17)
#define SPI_CMD1_LSBI_FE (1 << 16)
#define SPI_CMD1_LSBY_FE (1 << 15)
#define SPI_CMD1_BOTH_EN_BIT (1 << 14)
#define SPI_CMD1_BOTH_EN_BYTE (1 << 13)
#define SPI_CMD1_RX_EN (1 << 12)
#define SPI_CMD1_TX_EN (1 << 11)
#define SPI_CMD1_PACKED (1 << 5)
#define SPI_CMD1_BIT_LEN_MASK 0x1f
#define SPI_CMD1_BIT_LEN_SHIFT 0
/* COMMAND2 */
#define SPI_CMD2_TX_CLK_TAP_DELAY (1 << 6)
#define SPI_CMD2_TX_CLK_TAP_DELAY_MASK (0x3F << 6)
#define SPI_CMD2_RX_CLK_TAP_DELAY (1 << 0)
#define SPI_CMD2_RX_CLK_TAP_DELAY_MASK (0x3F << 0)
/* SPI_TRANS_STATUS */
#define SPI_STATUS_RDY (1 << 30)
#define SPI_STATUS_SLV_IDLE_COUNT_MASK 0xff
#define SPI_STATUS_SLV_IDLE_COUNT_SHIFT 16
#define SPI_STATUS_BLOCK_COUNT 0xffff
#define SPI_STATUS_BLOCK_COUNT_SHIFT 0
/* SPI_FIFO_STATUS */
#define SPI_FIFO_STATUS_CS_INACTIVE (1 << 31)
#define SPI_FIFO_STATUS_FRAME_END (1 << 30)
#define SPI_FIFO_STATUS_RX_FIFO_FLUSH (1 << 15)
#define SPI_FIFO_STATUS_TX_FIFO_FLUSH (1 << 14)
#define SPI_FIFO_STATUS_ERR (1 << 8)
#define SPI_FIFO_STATUS_TX_FIFO_OVF (1 << 7)
#define SPI_FIFO_STATUS_TX_FIFO_UNR (1 << 6)
#define SPI_FIFO_STATUS_RX_FIFO_OVF (1 << 5)
#define SPI_FIFO_STATUS_RX_FIFO_UNR (1 << 4)
#define SPI_FIFO_STATUS_TX_FIFO_FULL (1 << 3)
#define SPI_FIFO_STATUS_TX_FIFO_EMPTY (1 << 2)
#define SPI_FIFO_STATUS_RX_FIFO_FULL (1 << 1)
#define SPI_FIFO_STATUS_RX_FIFO_EMPTY (1 << 0)
/* SPI_DMA_CTL */
#define SPI_DMA_CTL_DMA (1 << 31)
#define SPI_DMA_CTL_CONT (1 << 30)
#define SPI_DMA_CTL_IE_RX (1 << 29)
#define SPI_DMA_CTL_IE_TX (1 << 28)
#define SPI_DMA_CTL_RX_TRIG_MASK 0x3
#define SPI_DMA_CTL_RX_TRIG_SHIFT 19
#define SPI_DMA_CTL_TX_TRIG_MASK 0x3
#define SPI_DMA_CTL_TX_TRIG_SHIFT 15
/* SPI_DMA_BLK */
#define SPI_DMA_CTL_BLOCK_SIZE_MASK 0xffff
#define SPI_DMA_CTL_BLOCK_SIZE_SHIFT 0
static struct tegra_spi_channel tegra_spi_channels[] = {
/*
* Note: Tegra pinmux must be setup for corresponding SPI channel in
* order for its registers to be accessible. If pinmux has not been
* set up, access to the channel's registers will simply hang.
*
* TODO(dhendrix): Clarify or remove this comment (is clock setup
* necessary first, or just pinmux, or both?)
*/
{
.slave = { .bus = 1, },
.regs = (struct tegra_spi_regs *)TEGRA_SPI1_BASE,
.req_sel = APBDMA_SLAVE_SL2B1,
},
{
.slave = { .bus = 2, },
.regs = (struct tegra_spi_regs *)TEGRA_SPI2_BASE,
.req_sel = APBDMA_SLAVE_SL2B2,
},
{
.slave = { .bus = 3, },
.regs = (struct tegra_spi_regs *)TEGRA_SPI3_BASE,
.req_sel = APBDMA_SLAVE_SL2B3,
},
{
.slave = { .bus = 4, },
.regs = (struct tegra_spi_regs *)TEGRA_SPI4_BASE,
.req_sel = APBDMA_SLAVE_SL2B4,
},
{
.slave = { .bus = 5, },
.regs = (struct tegra_spi_regs *)TEGRA_SPI5_BASE,
.req_sel = APBDMA_SLAVE_SL2B5,
},
{
.slave = { .bus = 6, },
.regs = (struct tegra_spi_regs *)TEGRA_SPI6_BASE,
.req_sel = APBDMA_SLAVE_SL2B6,
},
};
enum spi_direction {
SPI_SEND,
SPI_RECEIVE,
};
struct tegra_spi_channel *tegra_spi_init(unsigned int bus)
{
int i;
struct tegra_spi_channel *spi = NULL;
for (i = 0; i < ARRAY_SIZE(tegra_spi_channels); i++) {
if (tegra_spi_channels[i].slave.bus == bus) {
spi = &tegra_spi_channels[i];
break;
}
}
if (!spi)
return NULL;
/* software drives chip-select, set value to high */
setbits_le32(&spi->regs->command1,
SPI_CMD1_CS_SW_HW | SPI_CMD1_CS_SW_VAL);
/* 8-bit transfers, unpacked mode, most significant bit first */
clrbits_le32(&spi->regs->command1,
SPI_CMD1_BIT_LEN_MASK | SPI_CMD1_PACKED);
setbits_le32(&spi->regs->command1, 7 << SPI_CMD1_BIT_LEN_SHIFT);
return spi;
}
static struct tegra_spi_channel * const to_tegra_spi(int bus) {
return &tegra_spi_channels[bus - 1];
}
static unsigned int tegra_spi_speed(unsigned int bus)
{
/* FIXME: implement this properly, for now use max value (50MHz) */
return 50000000;
}
void spi_cs_activate(struct spi_slave *slave)
{
struct tegra_spi_regs *regs = to_tegra_spi(slave->bus)->regs;
u32 val;
val = read32(&regs->command1);
/* select appropriate chip-select line */
val &= ~(SPI_CMD1_CS_SEL_MASK << SPI_CMD1_CS_SEL_SHIFT);
val |= (slave->cs << SPI_CMD1_CS_SEL_SHIFT);
/* drive chip-select with the inverse of the "inactive" value */
if (val & (SPI_CMD1_CS_POL_INACTIVE0 << slave->cs))
val &= ~SPI_CMD1_CS_SW_VAL;
else
val |= SPI_CMD1_CS_SW_VAL;
write32(val, &regs->command1);
}
void spi_cs_deactivate(struct spi_slave *slave)
{
struct tegra_spi_regs *regs = to_tegra_spi(slave->bus)->regs;
u32 val;
val = read32(&regs->command1);
if (val & (SPI_CMD1_CS_POL_INACTIVE0 << slave->cs))
val |= SPI_CMD1_CS_SW_VAL;
else
val &= ~SPI_CMD1_CS_SW_VAL;
write32(val, &regs->command1);
}
static void dump_fifo_status(struct tegra_spi_channel *spi)
{
u32 status = read32(&spi->regs->fifo_status);
printk(BIOS_INFO, "Raw FIFO status: 0x%08x\n", status);
if (status & SPI_FIFO_STATUS_TX_FIFO_OVF)
printk(BIOS_INFO, "\tTx overflow detected\n");
if (status & SPI_FIFO_STATUS_TX_FIFO_UNR)
printk(BIOS_INFO, "\tTx underrun detected\n");
if (status & SPI_FIFO_STATUS_RX_FIFO_OVF)
printk(BIOS_INFO, "\tRx overflow detected\n");
if (status & SPI_FIFO_STATUS_RX_FIFO_UNR)
printk(BIOS_INFO, "\tRx underrun detected\n");
printk(BIOS_INFO, "TX_FIFO: 0x%08x, TX_DATA: 0x%08x\n",
read32(&spi->regs->tx_fifo), read32(&spi->regs->tx_data));
printk(BIOS_INFO, "RX_FIFO: 0x%08x, RX_DATA: 0x%08x\n",
read32(&spi->regs->rx_fifo), read32(&spi->regs->rx_data));
}
static void clear_fifo_status(struct tegra_spi_channel *spi)
{
clrbits_le32(&spi->regs->fifo_status,
SPI_FIFO_STATUS_ERR |
SPI_FIFO_STATUS_TX_FIFO_OVF |
SPI_FIFO_STATUS_TX_FIFO_UNR |
SPI_FIFO_STATUS_RX_FIFO_OVF |
SPI_FIFO_STATUS_RX_FIFO_UNR);
}
static void dump_spi_regs(struct tegra_spi_channel *spi)
{
printk(BIOS_INFO, "SPI regs:\n"
"\tdma_blk: 0x%08x\n"
"\tcommand1: 0x%08x\n"
"\tdma_ctl: 0x%08x\n"
"\ttrans_status: 0x%08x\n",
read32(&spi->regs->dma_blk),
read32(&spi->regs->command1),
read32(&spi->regs->dma_ctl),
read32(&spi->regs->trans_status));
}
static void dump_dma_regs(struct apb_dma_channel *dma)
{
printk(BIOS_INFO, "DMA regs:\n"
"\tahb_ptr: 0x%08x\n"
"\tapb_ptr: 0x%08x\n"
"\tahb_seq: 0x%08x\n"
"\tapb_seq: 0x%08x\n"
"\tcsr: 0x%08x\n"
"\tcsre: 0x%08x\n"
"\twcount: 0x%08x\n"
"\tdma_byte_sta: 0x%08x\n"
"\tword_transfer: 0x%08x\n",
read32(&dma->regs->ahb_ptr),
read32(&dma->regs->apb_ptr),
read32(&dma->regs->ahb_seq),
read32(&dma->regs->apb_seq),
read32(&dma->regs->csr),
read32(&dma->regs->csre),
read32(&dma->regs->wcount),
read32(&dma->regs->dma_byte_sta),
read32(&dma->regs->word_transfer));
}
static inline unsigned int spi_byte_count(struct tegra_spi_channel *spi)
{
/* FIXME: Make this take total packet size into account */
return read32(&spi->regs->trans_status) &
(SPI_STATUS_BLOCK_COUNT << SPI_STATUS_BLOCK_COUNT_SHIFT);
}
/*
* This calls udelay() with a calculated value based on the SPI speed and
* number of bytes remaining to be transferred. It assumes that if the
* calculated delay period is less than MIN_DELAY_US then it is probably
* not worth the overhead of yielding.
*/
#define MIN_DELAY_US 250
static void spi_delay(struct tegra_spi_channel *spi,
unsigned int bytes_remaining)
{
unsigned int ns_per_byte, delay_us;
ns_per_byte = 1000000000 / (tegra_spi_speed(spi->slave.bus) / 8);
delay_us = (ns_per_byte * bytes_remaining) / 1000;
if (delay_us < MIN_DELAY_US)
return;
udelay(delay_us);
}
static void tegra_spi_wait(struct tegra_spi_channel *spi)
{
unsigned int count, dma_blk;
dma_blk = 1 + (read32(&spi->regs->dma_blk) &
(SPI_DMA_CTL_BLOCK_SIZE_MASK << SPI_DMA_CTL_BLOCK_SIZE_SHIFT));
while ((count = spi_byte_count(spi)) != dma_blk)
spi_delay(spi, dma_blk - count);
}
static int fifo_error(struct tegra_spi_channel *spi)
{
return read32(&spi->regs->fifo_status) & SPI_FIFO_STATUS_ERR ? 1 : 0;
}
static int tegra_spi_pio_prepare(struct tegra_spi_channel *spi,
unsigned int bytes, enum spi_direction dir)
{
u8 *p = spi->out_buf;
unsigned int todo = MIN(bytes, SPI_MAX_TRANSFER_BYTES_FIFO);
u32 flush_mask, enable_mask;
if (dir == SPI_SEND) {
flush_mask = SPI_FIFO_STATUS_TX_FIFO_FLUSH;
enable_mask = SPI_CMD1_TX_EN;
} else {
flush_mask = SPI_FIFO_STATUS_RX_FIFO_FLUSH;
enable_mask = SPI_CMD1_RX_EN;
}
setbits_le32(&spi->regs->fifo_status, flush_mask);
while (read32(&spi->regs->fifo_status) & flush_mask)
;
setbits_le32(&spi->regs->command1, enable_mask);
/* BLOCK_SIZE in SPI_DMA_BLK register applies to both DMA and
* PIO transfers */
write32(todo - 1, &spi->regs->dma_blk);
if (dir == SPI_SEND) {
unsigned int to_fifo = bytes;
while (to_fifo) {
write32(*p, &spi->regs->tx_fifo);
p++;
to_fifo--;
}
}
return todo;
}
static void tegra_spi_pio_start(struct tegra_spi_channel *spi)
{
setbits_le32(&spi->regs->trans_status, SPI_STATUS_RDY);
setbits_le32(&spi->regs->command1, SPI_CMD1_GO);
}
static int tegra_spi_pio_finish(struct tegra_spi_channel *spi)
{
u8 *p = spi->in_buf;
clrbits_le32(&spi->regs->command1, SPI_CMD1_RX_EN | SPI_CMD1_TX_EN);
while (!(read32(&spi->regs->fifo_status) &
SPI_FIFO_STATUS_RX_FIFO_EMPTY)) {
*p = read8(&spi->regs->rx_fifo);
p++;
}
if (fifo_error(spi)) {
printk(BIOS_ERR, "%s: ERROR:\n", __func__);
dump_spi_regs(spi);
dump_fifo_status(spi);
return -1;
}
return 0;
}
static void setup_dma_params(struct tegra_spi_channel *spi,
struct apb_dma_channel *dma)
{
/* APB bus width = 8-bits, address wrap for each word */
clrbits_le32(&dma->regs->apb_seq,
AHB_BUS_WIDTH_MASK << AHB_BUS_WIDTH_SHIFT);
/* AHB 1 word burst, bus width = 32 bits (fixed in hardware),
* no address wrapping */
clrsetbits_le32(&dma->regs->ahb_seq,
(AHB_BURST_MASK << AHB_BURST_SHIFT) |
(AHB_SEQ_WRAP_MASK << AHB_SEQ_WRAP_SHIFT),
AHB_BURST_MASK << AHB_BURST_SHIFT);
/* Set ONCE mode to transfer one "block" at a time (64KB) and enable
* flow control. */
clrbits_le32(&dma->regs->csr,
APB_CSR_REQ_SEL_MASK << APB_CSR_REQ_SEL_SHIFT);
setbits_le32(&dma->regs->csr, APB_CSR_ONCE | APB_CSR_FLOW |
(spi->req_sel << APB_CSR_REQ_SEL_SHIFT));
}
static int tegra_spi_dma_prepare(struct tegra_spi_channel *spi,
unsigned int bytes, enum spi_direction dir)
{
unsigned int todo, wcount;
/*
* For DMA we need to think of things in terms of word count.
* AHB width is fixed at 32-bits. To avoid overrunning
* the in/out buffers we must align down. (Note: lowest 2-bits
* in WCOUNT register are ignored, and WCOUNT seems to count
* words starting at n-1)
*
* Example: If "bytes" is 7 and we are transferring 1-byte at a time,
* WCOUNT should be 4. The remaining 3 bytes must be transferred
* using PIO.
*/
todo = MIN(bytes, SPI_MAX_TRANSFER_BYTES_DMA - TEGRA_DMA_ALIGN_BYTES);
todo = ALIGN_DOWN(todo, TEGRA_DMA_ALIGN_BYTES);
wcount = ALIGN_DOWN(todo - TEGRA_DMA_ALIGN_BYTES, TEGRA_DMA_ALIGN_BYTES);
if (dir == SPI_SEND) {
spi->dma_out = dma_claim();
if (!spi->dma_out)
return -1;
/* ensure bytes to send will be visible to DMA controller */
dcache_clean_by_mva(spi->out_buf, bytes);
write32((u32)&spi->regs->tx_fifo, &spi->dma_out->regs->apb_ptr);
write32((u32)spi->out_buf, &spi->dma_out->regs->ahb_ptr);
setbits_le32(&spi->dma_out->regs->csr, APB_CSR_DIR);
setup_dma_params(spi, spi->dma_out);
write32(wcount, &spi->dma_out->regs->wcount);
} else {
spi->dma_in = dma_claim();
if (!spi->dma_in)
return -1;
/* avoid data collisions */
dcache_clean_invalidate_by_mva(spi->in_buf, bytes);
write32((u32)&spi->regs->rx_fifo, &spi->dma_in->regs->apb_ptr);
write32((u32)spi->in_buf, &spi->dma_in->regs->ahb_ptr);
clrbits_le32(&spi->dma_in->regs->csr, APB_CSR_DIR);
setup_dma_params(spi, spi->dma_in);
write32(wcount, &spi->dma_in->regs->wcount);
}
/* BLOCK_SIZE starts at n-1 */
write32(todo - 1, &spi->regs->dma_blk);
return todo;
}
static void tegra_spi_dma_start(struct tegra_spi_channel *spi)
{
/*
* The RDY bit in SPI_TRANS_STATUS needs to be cleared manually
* (set bit to clear) between each transaction. Otherwise the next
* transaction does not start.
*/
setbits_le32(&spi->regs->trans_status, SPI_STATUS_RDY);
if (spi->dma_out)
setbits_le32(&spi->regs->command1, SPI_CMD1_TX_EN);
if (spi->dma_in)
setbits_le32(&spi->regs->command1, SPI_CMD1_RX_EN);
/*
* To avoid underrun conditions, enable APB DMA before SPI DMA for
* Tx and enable SPI DMA before APB DMA before Rx.
*/
if (spi->dma_out)
dma_start(spi->dma_out);
setbits_le32(&spi->regs->dma_ctl, SPI_DMA_CTL_DMA);
if (spi->dma_in)
dma_start(spi->dma_in);
}
static int tegra_spi_dma_finish(struct tegra_spi_channel *spi)
{
int ret;
unsigned int todo;
todo = read32(&spi->dma_in->regs->wcount);
if (spi->dma_in) {
while ((read32(&spi->dma_in->regs->dma_byte_sta) < todo) ||
dma_busy(spi->dma_in))
; /* this shouldn't take long, no udelay */
dma_stop(spi->dma_in);
clrbits_le32(&spi->regs->command1, SPI_CMD1_RX_EN);
}
if (spi->dma_out) {
while ((read32(&spi->dma_out->regs->dma_byte_sta) < todo) ||
dma_busy(spi->dma_out))
spi_delay(spi, todo - spi_byte_count(spi));
clrbits_le32(&spi->regs->command1, SPI_CMD1_TX_EN);
dma_stop(spi->dma_out);
}
if (fifo_error(spi)) {
printk(BIOS_ERR, "%s: ERROR:\n", __func__);
dump_dma_regs(spi->dma_out);
dump_dma_regs(spi->dma_in);
dump_spi_regs(spi);
dump_fifo_status(spi);
ret = -1;
goto done;
}
ret = 0;
done:
spi->dma_in = NULL;
spi->dma_out = NULL;
return ret;
}
/*
* xfer_setup() prepares a transfer. It does sanity checking, alignment, and
* sets transfer mode used by this channel (if not set already).
*
* A few caveats to watch out for:
* - The number of bytes which can be transferred may be smaller than the
* number of bytes the caller specifies. The number of bytes ready for
* a transfer will be returned (unless an error occurs).
*
* - Only one mode can be used for both RX and TX. The transfer mode of the
* SPI channel (spi->xfer_mode) is checked each time this function is called.
* If conflicting modes are detected, spi->xfer_mode will be set to
* XFER_MODE_NONE and an error will be returned.
*
* Returns bytes ready for transfer if successful, <0 to indicate error.
*/
static int xfer_setup(struct tegra_spi_channel *spi, void *buf,
unsigned int bytes, enum spi_direction dir)
{
unsigned int line_size = dcache_line_bytes();
unsigned int align;
int ret = -1;
if (!bytes)
return 0;
if (dir == SPI_SEND)
spi->out_buf = buf;
else if (dir == SPI_RECEIVE)
spi->in_buf = buf;
/*
* Alignment consideratons:
* When we enable caching we'll need to clean/invalidate portions of
* memory. So we need to be careful about memory alignment. Also, DMA
* likes to operate on 4-bytes at a time on the AHB side. So for
* example, if we only want to receive 1 byte, 4 bytes will be be
* written in memory even if those extra 3 bytes are beyond the length
* we want.
*
* For now we'll use PIO to send/receive unaligned bytes. We may
* consider setting aside some space for a kind of bounce buffer to
* stay in DMA mode once we have a chance to benchmark the two
* approaches.
*/
if (bytes < line_size) {
if (spi->xfer_mode == XFER_MODE_DMA) {
spi->xfer_mode = XFER_MODE_NONE;
ret = -1;
} else {
spi->xfer_mode = XFER_MODE_PIO;
ret = tegra_spi_pio_prepare(spi, bytes, dir);
}
goto done;
}
/* transfer bytes before the aligned boundary */
align = line_size - ((uintptr_t)buf % line_size);
if ((align != 0) && (align != line_size)) {
if (spi->xfer_mode == XFER_MODE_DMA) {
spi->xfer_mode = XFER_MODE_NONE;
ret = -1;
} else {
spi->xfer_mode = XFER_MODE_PIO;
ret = tegra_spi_pio_prepare(spi, align, dir);
}
goto done;
}
/* do aligned DMA transfer */
align = (((uintptr_t)buf + bytes) % line_size);
if (bytes - align > 0) {
unsigned int dma_bytes = bytes - align;
if (spi->xfer_mode == XFER_MODE_PIO) {
spi->xfer_mode = XFER_MODE_NONE;
ret = -1;
} else {
spi->xfer_mode = XFER_MODE_DMA;
ret = tegra_spi_dma_prepare(spi, dma_bytes, dir);
}
goto done;
}
/* transfer any remaining unaligned bytes */
if (align) {
if (spi->xfer_mode == XFER_MODE_DMA) {
spi->xfer_mode = XFER_MODE_NONE;
ret = -1;
} else {
spi->xfer_mode = XFER_MODE_PIO;
ret = tegra_spi_pio_prepare(spi, align, dir);
}
goto done;
}
done:
return ret;
}
static void xfer_start(struct tegra_spi_channel *spi)
{
if (spi->xfer_mode == XFER_MODE_DMA)
tegra_spi_dma_start(spi);
else
tegra_spi_pio_start(spi);
}
static void xfer_wait(struct tegra_spi_channel *spi)
{
tegra_spi_wait(spi);
}
static int xfer_finish(struct tegra_spi_channel *spi)
{
int ret;
if (spi->xfer_mode == XFER_MODE_DMA)
ret = tegra_spi_dma_finish(spi);
else
ret = tegra_spi_pio_finish(spi);
spi->xfer_mode = XFER_MODE_NONE;
return ret;
}
int spi_xfer(struct spi_slave *slave, const void *dout,
unsigned int bitsout, void *din, unsigned int bitsin)
{
unsigned int out_bytes = bitsout / 8, in_bytes = bitsin / 8;
struct tegra_spi_channel *spi = to_tegra_spi(slave->bus);
u8 *out_buf = (u8 *)dout;
u8 *in_buf = (u8 *)din;
unsigned int todo;
int ret = 0, frame_started = 1;
ASSERT(bitsout % 8 == 0 && bitsin % 8 == 0);
/* tegra bus numbers start at 1 */
ASSERT(slave->bus >= 1 && slave->bus <= ARRAY_SIZE(tegra_spi_channels));
if (spi->rx_frame_header_enable) {
memset(in_buf, ~spi->frame_header, in_bytes);
frame_started = 0;
}
while (out_bytes || in_bytes) {
int x = 0;
if (out_bytes == 0)
todo = in_bytes;
else if (in_bytes == 0)
todo = out_bytes;
else
todo = MIN(out_bytes, in_bytes);
if (out_bytes) {
x = xfer_setup(spi, out_buf, todo, SPI_SEND);
if (x < 0) {
if (spi->xfer_mode == XFER_MODE_NONE) {
spi->xfer_mode = XFER_MODE_PIO;
continue;
} else {
ret = -1;
break;
}
}
}
if (in_bytes) {
x = xfer_setup(spi, in_buf, todo, SPI_RECEIVE);
if (x < 0) {
if (spi->xfer_mode == XFER_MODE_NONE) {
spi->xfer_mode = XFER_MODE_PIO;
continue;
} else {
ret = -1;
break;
}
}
}
/*
* Note: Some devices (such as Chrome EC) are sensitive to
* delays, so be careful when adding debug prints not to
* cause timeouts between transfers.
*/
xfer_start(spi);
xfer_wait(spi);
if (xfer_finish(spi)) {
ret = -1;
break;
}
/*
* Post-processing. For output, we only need to increment
* the buffer and decrement the counter. Same for input if
* there is no frame header to be concerned with.
*
* If a frame header is used and is found, the input buffer
* is shifted so that the header starts at offset 0, and
* in_bytes and in_buf are incremented/decremented according
* to the offset where the header was originally found.
*/
if (out_bytes) {
out_bytes -= x;
out_buf += x;
}
if (in_bytes) {
if (spi->rx_frame_header_enable && !frame_started) {
int i;
for (i = 0; i < x; i++) {
if (in_buf[i] == spi->frame_header) {
frame_started = 1;
i++; /* discard frame header */
break;
}
}
if (frame_started) {
memmove(&in_buf[0], &in_buf[i], x - i);
in_bytes -= x - i;
in_buf += x - i;
}
} else {
in_bytes -= x;
in_buf += x;
}
}
}
if (ret < 0) {
printk(BIOS_ERR, "%s: Error detected\n", __func__);
printk(BIOS_ERR, "Transaction size: %u, bytes remaining: "
"%u out / %u in\n", todo, out_bytes, in_bytes);
clear_fifo_status(spi);
}
return ret;
}
/* SPI as CBFS media. */
struct tegra_spi_media {
struct spi_slave *slave;
struct cbfs_simple_buffer buffer;
};
static int tegra_spi_cbfs_open(struct cbfs_media *media)
{
DEBUG_SPI("tegra_spi_cbfs_open\n");
return 0;
}
static int tegra_spi_cbfs_close(struct cbfs_media *media)
{
DEBUG_SPI("tegra_spi_cbfs_close\n");
return 0;
}
#define JEDEC_READ 0x03
#define JEDEC_READ_OUTSIZE 0x04
/* JEDEC_READ_INSIZE : any length */
static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
size_t offset, size_t count)
{
struct tegra_spi_media *spi = (struct tegra_spi_media *)media->context;
u8 spi_read_cmd[JEDEC_READ_OUTSIZE];
int ret = count;
/* TODO: Dual mode (BOTH_EN_BIT) and packed mode */
spi_read_cmd[0] = JEDEC_READ;
spi_read_cmd[1] = (offset >> 16) & 0xff;
spi_read_cmd[2] = (offset >> 8) & 0xff;
spi_read_cmd[3] = offset & 0xff;
/* assert /CS */
spi_cs_activate(spi->slave);
if (spi_xfer(spi->slave, spi_read_cmd,
sizeof(spi_read_cmd) * 8, NULL, 0) < 0) {
ret = -1;
printk(BIOS_ERR, "%s: Failed to transfer %u bytes\n",
__func__, sizeof(spi_read_cmd));
goto tegra_spi_cbfs_read_exit;
}
if (spi_xfer(spi->slave, NULL, 0, dest, count * 8)) {
ret = -1;
printk(BIOS_ERR, "%s: Failed to transfer %u bytes\n",
__func__, count);
}
tegra_spi_cbfs_read_exit:
/* de-assert /CS */
spi_cs_deactivate(spi->slave);
return (ret < 0) ? 0 : ret;
}
static void *tegra_spi_cbfs_map(struct cbfs_media *media, size_t offset,
size_t count)
{
struct tegra_spi_media *spi = (struct tegra_spi_media*)media->context;
void *map;
DEBUG_SPI("tegra_spi_cbfs_map\n");
map = cbfs_simple_buffer_map(&spi->buffer, media, offset, count);
printk(BIOS_INFO, "%s: map: 0x%p\n", __func__, map);
return map;
}
static void *tegra_spi_cbfs_unmap(struct cbfs_media *media,
const void *address)
{
struct tegra_spi_media *spi = (struct tegra_spi_media*)media->context;
DEBUG_SPI("tegra_spi_cbfs_unmap\n");
return cbfs_simple_buffer_unmap(&spi->buffer, address);
}
int initialize_tegra_spi_cbfs_media(struct cbfs_media *media,
void *buffer_address,
size_t buffer_size)
{
// TODO Replace static variable to support multiple streams.
static struct tegra_spi_media context;
static struct tegra_spi_channel *channel;
channel = &tegra_spi_channels[CONFIG_BOOT_MEDIA_SPI_BUS - 1];
channel->slave.cs = CONFIG_BOOT_MEDIA_SPI_CHIP_SELECT;
DEBUG_SPI("Initializing CBFS media on SPI\n");
context.slave = &channel->slave;
context.buffer.allocated = context.buffer.last_allocate = 0;
context.buffer.buffer = buffer_address;
context.buffer.size = buffer_size;
media->context = (void*)&context;
media->open = tegra_spi_cbfs_open;
media->close = tegra_spi_cbfs_close;
media->read = tegra_spi_cbfs_read;
media->map = tegra_spi_cbfs_map;
media->unmap = tegra_spi_cbfs_unmap;
return 0;
}
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
struct tegra_spi_channel *channel = to_tegra_spi(bus);
if (!channel)
return NULL;
return &channel->slave;
}
int spi_claim_bus(struct spi_slave *slave)
{
tegra_spi_init(slave->bus);
spi_cs_activate(slave);
return 0;
}
void spi_release_bus(struct spi_slave *slave)
{
spi_cs_deactivate(slave);
}