tegra124: implement x2 mode for SPI transfers on CBFS media
This implements x2 mode when reading CBFS media over SPI. In theory this effectively doubles our throughput, though the initial results were almost negligibly better. Using a logic analyzer we see a pattern of 12 clocks, ~70ns delay, 4 clocks, ~310ns delay. So if we want to see further gains here then we'll probably need to tune AHB arbitration and utilization to eliminate bubbles/stalls when copying from APB DMA. BUG=none BRANCH=none TEST=built and booted on Nyan. Signed-off-by: David Hendricks <dhendrix@chromium.org> Change-Id: I33d6ae30923fc42b4dc7103d029085985472cf3e Reviewed-on: https://chromium-review.googlesource.com/177835 Reviewed-by: Tom Warren <twarren@nvidia.com> Reviewed-by: David Hendricks <dhendrix@chromium.org> Commit-Queue: David Hendricks <dhendrix@chromium.org> Tested-by: David Hendricks <dhendrix@chromium.org>
This commit is contained in:
parent
de6869a335
commit
2928922336
2 changed files with 35 additions and 7 deletions
|
|
@ -842,19 +842,37 @@ static int tegra_spi_cbfs_close(struct cbfs_media *media)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define JEDEC_READ 0x03
|
||||
#define JEDEC_READ_OUTSIZE 0x04
|
||||
/* JEDEC_READ_INSIZE : any length */
|
||||
#define JEDEC_READ 0x03
|
||||
#define JEDEC_READ_OUTSIZE 0x04
|
||||
#define JEDEC_FAST_READ_DUAL 0x3b
|
||||
#define JEDEC_FAST_READ_DUAL_OUTSIZE 0x05
|
||||
|
||||
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];
|
||||
u8 spi_read_cmd[JEDEC_FAST_READ_DUAL_OUTSIZE];
|
||||
unsigned int read_cmd_bytes;
|
||||
int ret = count;
|
||||
struct tegra_spi_channel *channel;
|
||||
|
||||
/* TODO: Dual mode (BOTH_EN_BIT) and packed mode */
|
||||
spi_read_cmd[0] = JEDEC_READ;
|
||||
channel = to_tegra_spi(spi->slave->bus);
|
||||
|
||||
if (channel->dual_mode) {
|
||||
/*
|
||||
* Command 0x3b will interleave data only, command 0xbb will
|
||||
* interleave the address as well. It's nice to see the address
|
||||
* plainly when debugging, and we're mostly concerned with
|
||||
* large transfers so the optimization of using 0xbb isn't
|
||||
* really worthwhile.
|
||||
*/
|
||||
spi_read_cmd[0] = JEDEC_FAST_READ_DUAL;
|
||||
spi_read_cmd[4] = 0x00; /* dummy byte */
|
||||
read_cmd_bytes = JEDEC_FAST_READ_DUAL_OUTSIZE;
|
||||
} else {
|
||||
spi_read_cmd[0] = JEDEC_READ;
|
||||
read_cmd_bytes = JEDEC_READ_OUTSIZE;
|
||||
}
|
||||
spi_read_cmd[1] = (offset >> 16) & 0xff;
|
||||
spi_read_cmd[2] = (offset >> 8) & 0xff;
|
||||
spi_read_cmd[3] = offset & 0xff;
|
||||
|
|
@ -863,18 +881,23 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
|
|||
spi_cs_activate(spi->slave);
|
||||
|
||||
if (spi_xfer(spi->slave, spi_read_cmd,
|
||||
sizeof(spi_read_cmd) * 8, NULL, 0) < 0) {
|
||||
read_cmd_bytes * 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 (channel->dual_mode) {
|
||||
setbits_le32(&channel->regs->command1, SPI_CMD1_BOTH_EN_BIT);
|
||||
}
|
||||
if (spi_xfer(spi->slave, NULL, 0, dest, count * 8)) {
|
||||
ret = -1;
|
||||
printk(BIOS_ERR, "%s: Failed to transfer %u bytes\n",
|
||||
__func__, count);
|
||||
}
|
||||
if (channel->dual_mode)
|
||||
clrbits_le32(&channel->regs->command1, SPI_CMD1_BOTH_EN_BIT);
|
||||
|
||||
tegra_spi_cbfs_read_exit:
|
||||
/* de-assert /CS */
|
||||
|
|
@ -924,6 +947,10 @@ int initialize_tegra_spi_cbfs_media(struct cbfs_media *media,
|
|||
media->map = tegra_spi_cbfs_map;
|
||||
media->unmap = tegra_spi_cbfs_unmap;
|
||||
|
||||
#if CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B == 1
|
||||
channel->dual_mode = 1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ struct tegra_spi_channel {
|
|||
/* stuff that is specific to the attached device */
|
||||
int rx_frame_header_enable;
|
||||
u8 frame_header;
|
||||
int dual_mode; /* for x2 transfers with bit interleaving */
|
||||
|
||||
/* context (used internally) */
|
||||
u8 *in_buf, *out_buf;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue