summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
authorTom Warren <twarren.nvidia@gmail.com>2011-04-28 07:55:13 -0700
committerSimon Glass <sjg@chromium.org>2011-08-24 09:56:21 -0700
commitd1b282db26a73650b51c680a693e707579ea8035 (patch)
treec985d8a611a2d549edd30902b0b4fd048686c455 /drivers/spi
parenta14a954f1ed38a92f83a7b2861e438f21d728027 (diff)
Fix Seaboard UART corruption on SPI activity
On Seaboard the UART and SPI interfere with each other. This causes the UART to receive spurious zero bytes after SPI transactions and also means that SPI can corrupt a few output characters when it starts up if they are still in the UART buffer. This hack corrects this by making SPI record that it may have corrupted the UART, and making the UART take evasive action. BUG=chromium-os:13228 TEST=Try developer U-Boot on Seaboard, make sure it auto-boots OK now Review URL: http://codereview.chromium.org/6715017 Change-Id: If2281357f177eeb3a19a170ddea22adbcf5942e9 Reviewed-on: http://gerrit.chromium.org/gerrit/191 Reviewed-by: Simon Glass <sjg@chromium.org> Tested-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/tegra2_spi.c71
1 files changed, 24 insertions, 47 deletions
diff --git a/drivers/spi/tegra2_spi.c b/drivers/spi/tegra2_spi.c
index 417fcc8dc7..e6ef00357e 100644
--- a/drivers/spi/tegra2_spi.c
+++ b/drivers/spi/tegra2_spi.c
@@ -24,8 +24,10 @@
#include <common.h>
#include <malloc.h>
+#include <ns16550.h> /* for NS16550_drain and NS16550_clear */
#include <spi.h>
#include <asm/io.h>
+#include <asm/arch/bitfield.h>
#include <asm/arch/clk_rst.h>
#include <asm/arch/clock.h>
#include <asm/arch/gpio.h>
@@ -114,20 +116,17 @@ void spi_init(void)
debug("spi_init: COMMAND = %08x\n", readl(&spi->command));
/*
- * SPI pins on Tegra2 are muxed - change pinmux last due to UART issue
+ * SPI pins on Tegra2 are muxed - change pinmux last due to UART
+ * issue. GMD_SEL [31:30] = (3) SFLASH
*/
- reg = readl(&pmt->pmt_ctl_c);
- reg |= GMD_SEL_SFLASH; /* GMD_SEL [31:30] = (3) SFLASH */
- writel(reg, &pmt->pmt_ctl_c);
- debug("spi_init: PinMuxRegC = %08x\n", reg);
+ bf_writel(GMD_SEL_SFLASH, 3, &pmt->pmt_ctl_c);
pinmux_tristate_disable(PIN_LSPI);
/*
* NOTE:
* Don't set PinMux bits 3:2 to SPI here or subsequent UART data
- * won't go out! It'll be correctly set in the actual SPI driver
- * before/after any transactions (cs_activate/_deactivate).
+ * won't go out! It'll be correctly set in seaboard_switch_spi_uart().
*/
}
@@ -138,64 +137,34 @@ int spi_claim_bus(struct spi_slave *slave)
void spi_release_bus(struct spi_slave *slave)
{
+ /*
+ * We can't release UART_DISABLE and set pinmux to UART4 here since
+ * some code (e,g, spi_flash_probe) uses printf() while the SPI
+ * bus is held. That is arguably bad, but it has the advantage of
+ * already being in the source tree.
+ */
}
void spi_cs_activate(struct spi_slave *slave)
{
- struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
struct spi_tegra *spi = (struct spi_tegra *)TEGRA2_SPI_BASE;
u32 val;
- /*
- * Delay here to clean up comms - spurious chars seen around SPI xfers.
- * Fine-tune later.
- */
- udelay(1000);
-
- /* We need to dynamically change the pinmux, shared w/UART RXD/CTS */
- val = readl(&pmt->pmt_ctl_b);
- val |= GMC_SEL_SFLASH; /* GMC_SEL [3:2] = (3) SFLASH */
- writel(val, &pmt->pmt_ctl_b);
-
- /*
- * On Seaboard, MOSI/MISO are shared w/UART.
- * Use GPIO I3 (UART_DISABLE) to tristate UART during SPI activity.
- * Enable UART later (cs_deactivate) so we can use it for U-Boot comms.
- */
- gpio_direction_output(UART_DISABLE_GPIO, 1);
+ seaboard_switch_spi_uart(SWITCH_SPI);
/* CS is negated on Tegra, so drive a 1 to get a 0 */
val = readl(&spi->command);
- writel((val |= SPI_CMD_CS_VAL), &spi->command);
+ writel(val | SPI_CMD_CS_VAL, &spi->command);
}
void spi_cs_deactivate(struct spi_slave *slave)
{
- struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
struct spi_tegra *spi = (struct spi_tegra *)TEGRA2_SPI_BASE;
u32 val;
- /*
- * Delay here to clean up comms - spurious chars seen around SPI xfers.
- * Fine-tune later.
- */
- udelay(1000);
-
- /* We need to dynamically change the pinmux, shared w/UART RXD/CTS */
- val = readl(&pmt->pmt_ctl_b);
- val &= ~GMC_SEL_SFLASH; /* GMC_SEL [3:2] = (0) UARTD */
- writel(val, &pmt->pmt_ctl_b);
-
- /*
- * On Seaboard, MOSI/MISO are shared w/UART.
- * GPIO I3 (UART_DISABLE) is used to tristate UART in cs_activate.
- * Enable UART here by setting that GPIO to 0 so we can do U-Boot comms.
- */
- gpio_direction_output(UART_DISABLE_GPIO, 0);
-
/* CS is negated on Tegra, so drive a 0 to get a 1 */
val = readl(&spi->command);
- writel((val &= ~SPI_CMD_CS_VAL), &spi->command);
+ writel(val & ~SPI_CMD_CS_VAL, &spi->command);
}
int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
@@ -235,7 +204,8 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
}
num_bytes -= bytes;
- dout += bytes;
+ if (dout)
+ dout += bytes;
bitlen -= bits;
reg = readl(&spi->command);
@@ -281,10 +251,17 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
/* swap bytes read in */
if (din != NULL) {
+ for (i = bytes - 1; i >= 0; --i) {
+ ((u8 *)din)[i] =
+ (tmpdin & 0xff);
+ tmpdin >>= 8;
+ }
+/* this is not the same!
for (i = 0; i < bytes; ++i) {
((u8 *)din)[i] = (tmpdin >> 24);
tmpdin <<= 8;
}
+*/
din += bytes;
}
}