diff options
-rw-r--r-- | arch/arm/include/asm/arch-davinci/emac_defs.h | 2 | ||||
-rw-r--r-- | drivers/spi/davinci_spi.c | 195 | ||||
-rw-r--r-- | include/configs/da830evm.h | 1 | ||||
-rw-r--r-- | include/configs/davinci_dm365evm.h | 1 | ||||
-rw-r--r-- | include/configs/davinci_dvevm.h | 1 | ||||
-rw-r--r-- | include/configs/davinci_schmoogie.h | 1 | ||||
-rw-r--r-- | include/configs/davinci_sffsdr.h | 1 | ||||
-rw-r--r-- | include/configs/davinci_sonata.h | 1 |
8 files changed, 135 insertions, 68 deletions
diff --git a/arch/arm/include/asm/arch-davinci/emac_defs.h b/arch/arm/include/asm/arch-davinci/emac_defs.h index b0ec8f5090..35a1585d17 100644 --- a/arch/arm/include/asm/arch-davinci/emac_defs.h +++ b/arch/arm/include/asm/arch-davinci/emac_defs.h @@ -85,7 +85,7 @@ #endif /* PHY mask - set only those phy number bits where phy is/can be connected */ -#define EMAC_MDIO_PHY_NUM 1 +#define EMAC_MDIO_PHY_NUM CONFIG_EMAC_MDIO_PHY_NUM #define EMAC_MDIO_PHY_MASK (1 << EMAC_MDIO_PHY_NUM) /* Ethernet Min/Max packet size */ diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 08f837b66f..4518ecbbc8 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -66,7 +66,7 @@ void spi_free_slave(struct spi_slave *slave) int spi_claim_bus(struct spi_slave *slave) { struct davinci_spi_slave *ds = to_davinci_spi(slave); - unsigned int scalar, data1_reg_val = 0; + unsigned int scalar; /* Enable the SPI hardware */ writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); @@ -93,11 +93,6 @@ int spi_claim_bus(struct spi_slave *slave) writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) | (1 << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0); - /* hold cs active at end of transfer until explicitly de-asserted */ - data1_reg_val = (1 << SPIDAT1_CSHOLD_SHIFT) | - (slave->cs << SPIDAT1_CSNR_SHIFT); - writel(data1_reg_val, &ds->regs->dat1); - /* * Including a minor delay. No science here. Should be good even with * no delay @@ -113,8 +108,7 @@ int spi_claim_bus(struct spi_slave *slave) writel(0, &ds->regs->lvl); /* enable SPI */ - writel((readl(&ds->regs->gcr1) | - SPIGCR1_SPIENA_MASK), &ds->regs->gcr1); + writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1); return 0; } @@ -127,14 +121,125 @@ void spi_release_bus(struct spi_slave *slave) writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0); } +/* + * This functions needs to act like a macro to avoid pipeline reloads in the + * loops below. Use always_inline. This gains us about 160KiB/s and the bloat + * appears to be zero bytes (da830). + */ +__attribute__((always_inline)) +static inline u32 davinci_spi_xfer_data(struct davinci_spi_slave *ds, u32 data) +{ + u32 buf_reg_val; + + /* send out data */ + writel(data, &ds->regs->dat1); + + /* wait for the data to clock in/out */ + while ((buf_reg_val = readl(&ds->regs->buf)) & SPIBUF_RXEMPTY_MASK) + ; + + return buf_reg_val; +} + +static int davinci_spi_read(struct spi_slave *slave, unsigned int len, + u8 *rxp, unsigned long flags) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave); + unsigned int data1_reg_val; + + /* enable CS hold, CS[n] and clear the data bits */ + data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | + (slave->cs << SPIDAT1_CSNR_SHIFT)); + + /* wait till TXFULL is deasserted */ + while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) + ; + + /* preload the TX buffer to avoid clock starvation */ + writel(data1_reg_val, &ds->regs->dat1); + + /* keep reading 1 byte until only 1 byte left */ + while ((len--) > 1) + *rxp++ = davinci_spi_xfer_data(ds, data1_reg_val); + + /* clear CS hold when we reach the end */ + if (flags & SPI_XFER_END) + data1_reg_val &= ~(1 << SPIDAT1_CSHOLD_SHIFT); + + /* read the last byte */ + *rxp = davinci_spi_xfer_data(ds, data1_reg_val); + + return 0; +} + +static int davinci_spi_write(struct spi_slave *slave, unsigned int len, + const u8 *txp, unsigned long flags) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave); + unsigned int data1_reg_val; + + /* enable CS hold and clear the data bits */ + data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | + (slave->cs << SPIDAT1_CSNR_SHIFT)); + + /* wait till TXFULL is deasserted */ + while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) + ; + + /* preload the TX buffer to avoid clock starvation */ + if (len > 2) { + writel(data1_reg_val | *txp++, &ds->regs->dat1); + len--; + } + + /* keep writing 1 byte until only 1 byte left */ + while ((len--) > 1) + davinci_spi_xfer_data(ds, data1_reg_val | *txp++); + + /* clear CS hold when we reach the end */ + if (flags & SPI_XFER_END) + data1_reg_val &= ~(1 << SPIDAT1_CSHOLD_SHIFT); + + /* write the last byte */ + davinci_spi_xfer_data(ds, data1_reg_val | *txp); + + return 0; +} + +#ifndef CONFIG_SPI_HALF_DUPLEX +static int davinci_spi_read_write(struct spi_slave *slave, unsigned int len, + u8 *rxp, const u8 *txp, unsigned long flags) +{ + struct davinci_spi_slave *ds = to_davinci_spi(slave); + unsigned int data1_reg_val; + + /* enable CS hold and clear the data bits */ + data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) | + (slave->cs << SPIDAT1_CSNR_SHIFT)); + + /* wait till TXFULL is deasserted */ + while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK) + ; + + /* keep reading and writing 1 byte until only 1 byte left */ + while ((len--) > 1) + *rxp++ = davinci_spi_xfer_data(ds, data1_reg_val | *txp++); + + /* clear CS hold when we reach the end */ + if (flags & SPI_XFER_END) + data1_reg_val &= ~(1 << SPIDAT1_CSHOLD_SHIFT); + + /* read and write the last byte */ + *rxp = davinci_spi_xfer_data(ds, data1_reg_val | *txp); + + return 0; +} +#endif + int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { - struct davinci_spi_slave *ds = to_davinci_spi(slave); - unsigned int len, data1_reg_val = readl(&ds->regs->dat1); - unsigned int i_cnt = 0, o_cnt = 0, buf_reg_val; - const u8 *txp = dout; /* dout can be NULL for read operation */ - u8 *rxp = din; /* din can be NULL for write operation */ + unsigned int len; if (bitlen == 0) /* Finish any previously submitted transfers */ @@ -154,63 +259,19 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, len = bitlen / 8; - /* do an empty read to clear the current contents */ - readl(&ds->regs->buf); - - /* keep writing and reading 1 byte until done */ - while ((i_cnt < len) || (o_cnt < len)) { - /* read RX buffer and flags */ - buf_reg_val = readl(&ds->regs->buf); - - /* if data is available */ - if ((i_cnt < len) && - (buf_reg_val & SPIBUF_RXEMPTY_MASK) == 0) { - /* - * If there is no read buffer simply - * ignore the read character - */ - if (rxp) - *rxp++ = buf_reg_val & 0xFF; - /* increment read words count */ - i_cnt++; - } - - /* - * if the tx buffer is empty and there - * is still data to transmit - */ - if ((o_cnt < len) && - ((buf_reg_val & SPIBUF_TXFULL_MASK) == 0)) { - /* write the data */ - data1_reg_val &= ~0xFFFF; - if (txp) - data1_reg_val |= *txp++; - /* - * Write to DAT1 is required to keep - * the serial transfer going. - * We just terminate when we reach the end. - */ - if ((o_cnt == (len - 1)) && (flags & SPI_XFER_END)) { - /* clear CS hold */ - writel(data1_reg_val & - ~(1 << SPIDAT1_CSHOLD_SHIFT), - &ds->regs->dat1); - } else { - /* enable CS hold and write TX register */ - data1_reg_val |= ((1 << SPIDAT1_CSHOLD_SHIFT) | - (slave->cs << SPIDAT1_CSNR_SHIFT)); - writel(data1_reg_val, &ds->regs->dat1); - } - /* increment written words count */ - o_cnt++; - } - } - return 0; + if (!dout) + return davinci_spi_read(slave, len, din, flags); + else if (!din) + return davinci_spi_write(slave, len, dout, flags); +#ifndef CONFIG_SPI_HALF_DUPLEX + else + return davinci_spi_read_write(slave, len, din, dout, flags); +#endif out: if (flags & SPI_XFER_END) { - writel(data1_reg_val & - ~(1 << SPIDAT1_CSHOLD_SHIFT), &ds->regs->dat1); + u8 dummy = 0; + davinci_spi_write(slave, 1, &dummy, flags); } return 0; } diff --git a/include/configs/da830evm.h b/include/configs/da830evm.h index 0f58e11e74..160ece2bf9 100644 --- a/include/configs/da830evm.h +++ b/include/configs/da830evm.h @@ -87,6 +87,7 @@ * Network & Ethernet Configuration */ #ifdef CONFIG_DRIVER_TI_EMAC +#define CONFIG_EMAC_MDIO_PHY_NUM 1 #define CONFIG_MII #define CONFIG_BOOTP_DEFAULT #define CONFIG_BOOTP_DNS diff --git a/include/configs/davinci_dm365evm.h b/include/configs/davinci_dm365evm.h index 6f99ae087d..2c3d88dc17 100644 --- a/include/configs/davinci_dm365evm.h +++ b/include/configs/davinci_dm365evm.h @@ -58,6 +58,7 @@ /* Network Configuration */ #define CONFIG_DRIVER_TI_EMAC +#define CONFIG_EMAC_MDIO_PHY_NUM 0 #define CONFIG_MII #define CONFIG_BOOTP_DEFAULT #define CONFIG_BOOTP_DNS diff --git a/include/configs/davinci_dvevm.h b/include/configs/davinci_dvevm.h index 5774df5cfb..aab2afa962 100644 --- a/include/configs/davinci_dvevm.h +++ b/include/configs/davinci_dvevm.h @@ -102,6 +102,7 @@ /* Network & Ethernet Configuration */ /*==================================*/ #define CONFIG_DRIVER_TI_EMAC +#define CONFIG_EMAC_MDIO_PHY_NUM 1 #define CONFIG_MII #define CONFIG_BOOTP_DEFAULT #define CONFIG_BOOTP_DNS diff --git a/include/configs/davinci_schmoogie.h b/include/configs/davinci_schmoogie.h index 3972ebce6f..875dda4442 100644 --- a/include/configs/davinci_schmoogie.h +++ b/include/configs/davinci_schmoogie.h @@ -69,6 +69,7 @@ /* Network & Ethernet Configuration */ /*==================================*/ #define CONFIG_DRIVER_TI_EMAC +#define CONFIG_EMAC_MDIO_PHY_NUM 1 #define CONFIG_MII #define CONFIG_BOOTP_DEFAULT #define CONFIG_BOOTP_DNS diff --git a/include/configs/davinci_sffsdr.h b/include/configs/davinci_sffsdr.h index 94be9dcf44..f4e17f8cc2 100644 --- a/include/configs/davinci_sffsdr.h +++ b/include/configs/davinci_sffsdr.h @@ -66,6 +66,7 @@ #define CONFIG_SYS_I2C_SLAVE 10 /* Bogus, master-only in U-Boot */ /* Network & Ethernet Configuration */ #define CONFIG_DRIVER_TI_EMAC +#define CONFIG_EMAC_MDIO_PHY_NUM 1 #define CONFIG_MII #define CONFIG_BOOTP_DEFAULT #define CONFIG_BOOTP_DNS diff --git a/include/configs/davinci_sonata.h b/include/configs/davinci_sonata.h index 490821a0e3..4c0184415f 100644 --- a/include/configs/davinci_sonata.h +++ b/include/configs/davinci_sonata.h @@ -102,6 +102,7 @@ /* Network & Ethernet Configuration */ /*==================================*/ #define CONFIG_DRIVER_TI_EMAC +#define CONFIG_EMAC_MDIO_PHY_NUM 1 #define CONFIG_MII #define CONFIG_BOOTP_DEFAULT #define CONFIG_BOOTP_DNS |