[U-Boot] FSL eSPI driver is a mess, hack attached.
Eliot Dudley
ewdudley at gmail.com
Wed Jul 23 13:27:42 CEST 2014
We're bringing up a board that boots from SPI flash, so we had to re-work
fsl_espi.c for to get it to work at all and for speed.
Been working from 2009.11 because that's what came with a P1022DS box that
Freescale so generously provided. There has been a tremendous amount
divergence since 2009.11 and it will be a long time if ever before I get a
chance to start over with the trunk, plus I am not up to speed with
patches, git, and so forth.
So I'm just going to past in some code fragments here in case anyone wants
to re-work the trunk with a know-good implemntation. From the looks of it
it should be straightforward to revise the current fsl_espi.c
First, a fragment for computing Hz so it is not more than max_hz:
/* Set eSPI BRG clock source */
get_sys_info(&sysinfo);
eSPI_baud_rate_generator = sysinfo.freqSystemBus / 2;
for (prescale = 0; prescale < 2; ++prescale) {
for (pm = 0; pm < 16; ++pm) {
if (
(
(eSPI_baud_rate_generator) /
((prescale ? 16 : 1) * 2 * (pm + 1))
) <=
(max_hz)
) {
goto csmode_DONE;
}
}
}
debug(
"fls_espi: spi_setup_slave: Requested %d Hz is too low, using %d Hz"
,max_hz
,eSPI_baud_rate_generator / ((prescale ? 16 : 1) * 2 * (pm + 1))
);
prescale = 1;
pm = 15;
csmode_DONE:
(prescale) && (espi->csmode[cs] |= ESPI_CSMODE_DIV16);
espi->csmode[cs] |= ESPI_CSMODE_PM(pm);
And here is the xfer code. It is 850 times faster than 2009.11. (Love my
new Saleae Logic 16.)
int espi_xfer(struct spi_slave *slave)
{
volatile ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR);
struct espi_transfer *t = slave->transfer;
/* Tx logic. */
#define FIFO_BYTES 32
#define TX_IDLE 0xffffffff
unsigned int tx_len = t->cmd_len + t->data_len;
unsigned int cmd_len = t->cmd_len;
u8 *cmd_ptr = (u8*)t->tx_buf;
int tx_fifo_bytes;
int tx_fifo_words;
int tx_bytes;
int cmd_bytes;
unsigned long tx;
/* Rx logic. */
unsigned int rx_len = t->cmd_len + t->data_len;
int rx_bytes;
int rx_words;
u8 *data_dst = (u8*)t->rx_buf;
int data_idx = -((int)cmd_len);
int data_bytes;
unsigned long rx;
/* Variables for computing a non-forever timeout. */
int spin = 0;
int spin_per_timeout;
/* WAG. Using factor of twenty for timeout below so mox nix.*/
unsigned int cpu_clock_per_spin = 60;
unsigned int cpu_clock_per_word;
/*
* This controller automatically asserts and negates CS,
* so we will not pretend that it does not.
* If board has other means for gating CS to the device then
* that is something to be dealt with higher up the stack.
*/
if (
(t->flags & (SPI_XFER_BEGIN | SPI_XFER_END)) !=
(SPI_XFER_BEGIN | SPI_XFER_END)
) {
printf(
"fsl_espi: espi_xfer(): Unsupported mode: flags=0x%08x\n"
,(unsigned int)t->flags
);
return -1;
}
cpu_clock_per_word =
(32) *
(2) *
((espi->csmode[slave->cs] & ESPI_CSMODE_DIV16) ? 16 : 1) *
(2 * (((espi->csmode[slave->cs] >> 24) & 0x0f) + 1))
;
spin_per_timeout = 20 * (cpu_clock_per_word / cpu_clock_per_spin);
spi_cs_activate(slave);
/* Clear all eSPI events. */
espi->event = 0xffffffff;
/* Fill xmt FIFO with as many as FIFO_BYTES (32) bytes. */
tx_fifo_bytes = FIFO_BYTES;
(tx_fifo_bytes > tx_len) && (tx_fifo_bytes = tx_len);
tx_fifo_words = (tx_fifo_bytes + 3) / 4;
while (tx_fifo_words--) {
tx = TX_IDLE;
((tx_bytes = 4) > tx_len) && (tx_bytes = tx_len);
if (cmd_len) {
((cmd_bytes = tx_bytes) > cmd_len) && (cmd_bytes = cmd_len);
memcpy(&tx, cmd_ptr, cmd_bytes);
cmd_len -= cmd_bytes;
cmd_ptr += cmd_bytes;
}
espi->tx = tx;
tx_len -= tx_bytes;
}
for (rx_words = (rx_len + 3) / 4; rx_words--;) {
/* Wait for rx or timeout. */
((rx_bytes = 4) > rx_len) && (rx_bytes = rx_len);
spin = spin_per_timeout;
while ((((espi->event & 0x3f000000) >> 24) < rx_bytes) && (--spin)) {
;
}
/* Timed out? */
if (!spin) {
break;
}
/* Read from rx FIFO. */
rx = espi->rx;
/* Copy to espi_transfer->rx_buf when xmt is done with cmd. */
if (data_dst) {
if (data_idx >= 0) {
memcpy(data_dst, &rx, rx_bytes);
data_dst += rx_bytes;
} else {
if ((data_idx += 4) > 0) {
((data_bytes = data_idx) > rx_len) && (data_bytes = rx_len);
memcpy(data_dst, ((u8 *)&rx) + (4 - data_idx), data_bytes);
data_dst += data_bytes;
}
}
}
rx_len -= rx_bytes;
/* Previous rx is complete so there is room in FIFO for the next tx.
*/
if (tx_len) {
tx = TX_IDLE;
((tx_bytes = 4) > tx_len) && (tx_bytes = tx_len);
if (cmd_len) {
((cmd_bytes = tx_bytes) > cmd_len) && (cmd_bytes = cmd_len);
memcpy(&tx, cmd_ptr, cmd_bytes);
cmd_len -= cmd_bytes;
cmd_ptr += cmd_bytes;
}
espi->tx = tx;
tx_len -= tx_bytes;
}
}
spi_cs_deactivate(slave);
if (!spin) {
printf("fsl_espi: espi_xfer(): timeout");
return -1;
}
return 0;
}
void spi_cs_activate(struct spi_slave *slave)
{
volatile ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR);
struct espi_transfer *t = slave->transfer;
unsigned int com = 0;
unsigned int len = t->cmd_len + t->data_len;
com &= ~(ESPI_COM_CS(0x3) | ESPI_COM_TRANLEN(0xffff));
com |= ESPI_COM_CS(slave->cs);
com |= ESPI_COM_TRANLEN(len - 1);
espi->com = com;
}
void spi_cs_deactivate(struct spi_slave *slave)
{
volatile ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR);
/* clear the RXCNT and TXCNT */
espi->mode &= ~ESPI_MODE_EN;
espi->mode |= ESPI_MODE_EN;
}
--ewd
More information about the U-Boot
mailing list