[U-Boot] FSL eSPI driver is a mess, hack attached.

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
participants (1)
-
Eliot Dudley