diff --git a/arch/arm/include/asm/arch-davinci/emac_defs.h b/arch/arm/include/asm/arch-davinci/emac_defs.h index b0ec8f50909acb59773e3ce933df99db69b88c76..35a1585d17baf1a43459869edbbda419b1bac75c 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 08f837b66f61ad753aba9816df8cabe1b6838ac9..4518ecbbc80744a2c18bed252f1aece0f799b19c 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 0f58e11e7461aa7e4816685e113b3f6e0f18b841..160ece2bf9cf8d20097d38178ea6e4aea98e80e6 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 6f99ae087dc4a5db6f2e57a7c915ad4924d3c0f7..2c3d88dc174740a35c88d79bb399cf0cf9a98eb3 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 5774df5cfbe5884abd240ca198226aaa690f93f5..aab2afa962b22ad81084366f0e754668cbbbb445 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 3972ebce6f41d72566d963b1abdf11eb509d64ee..875dda4442c6c6c8bb6c6e7bf78f512d4fe7a406 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 94be9dcf44607bddf1d32ed7c3043a40c1bd5beb..f4e17f8cc227e8a9ef5e70517d5fb9cc2bce9a17 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 490821a0e32b7058885fc0963c5490b1a73dcd1b..4c0184415ffd4c588d321d9e3c9a639f053430a2 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