diff options
author | Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com> | 2016-01-15 10:11:24 +0100 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2016-02-05 20:25:22 -0500 |
commit | 655fb9fb2ea2f45d3c5d593433c1530894f4c02b (patch) | |
tree | 4fb6ab5a8020b13cce0197a1f5eca51b461bf844 /drivers/spi | |
parent | bfb8b375a3c0f9c9d78efa2c4f615b1f2b511a9d (diff) |
spi: dw: Fix how internal FIFO is handled
- Refine how DFS is calulated now that it is strictely used to
manipulate buffer lengths.
- Fix threshold limit
- Tune RX threshold relevantly (reduce it if rx_len is lower than actual)
- Don't push more than available left space in FIFO
- Tune the private structure to lower memory space occupation
Change-Id: I65b1b48b996b2104cebcb24cc366fb4dcbf7d53b
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi_dw.c | 66 | ||||
-rw-r--r-- | drivers/spi/spi_dw.h | 19 |
2 files changed, 52 insertions, 33 deletions
diff --git a/drivers/spi/spi_dw.c b/drivers/spi/spi_dw.c index 54a8072b7..e018da0ea 100644 --- a/drivers/spi/spi_dw.c +++ b/drivers/spi/spi_dw.c @@ -85,6 +85,7 @@ DEFINE_MM_REG_WRITE(ser, DW_SPI_REG_SER, 8) DEFINE_MM_REG_WRITE(baudr, DW_SPI_REG_BAUDR, 16) DEFINE_MM_REG_WRITE(txftlr, DW_SPI_REG_TXFTLR, 32) DEFINE_MM_REG_WRITE(rxftlr, DW_SPI_REG_RXFTLR, 32) +DEFINE_MM_REG_READ(rxftlr, DW_SPI_REG_RXFTLR, 32) DEFINE_MM_REG_READ(txflr, DW_SPI_REG_TXFLR, 32) DEFINE_MM_REG_READ(rxflr, DW_SPI_REG_RXFLR, 32) DEFINE_MM_REG_WRITE(imr, DW_SPI_REG_IMR, 8) @@ -112,8 +113,6 @@ DEFINE_MM_REG_READ(ssi_comp_version, DW_SPI_REG_SSI_COMP_VERSION, 32) DEFINE_SET_BIT_OP(ssienr, DW_SPI_REG_SSIENR, DW_SPI_SSIENR_SSIEN_BIT) DEFINE_CLEAR_BIT_OP(ssienr, DW_SPI_REG_SSIENR, DW_SPI_SSIENR_SSIEN_BIT) DEFINE_TEST_BIT_OP(sr_busy, DW_SPI_REG_SR, DW_SPI_SR_BUSY_BIT) -DEFINE_TEST_BIT_OP(sr_tfnf, DW_SPI_REG_SR, DW_SPI_SR_TFNF_BIT) -DEFINE_TEST_BIT_OP(sr_rfne, DW_SPI_REG_SR, DW_SPI_SR_RFNE_BIT) DEFINE_TEST_BIT_OP(icr, DW_SPI_REG_ICR, DW_SPI_SR_ICR_BIT) #ifdef CONFIG_SOC_QUARK_SE @@ -163,6 +162,10 @@ static void completed(struct device *dev, int error) struct spi_dw_config *info = dev->config->config_info; struct spi_dw_data *spi = dev->driver_data; + if (spi->fifo_diff) { + return; + } + if (!((spi->tx_buf && !spi->tx_buf_len && !spi->rx_buf) || (spi->rx_buf && !spi->rx_buf_len && !spi->tx_buf) || (spi->tx_buf && !spi->tx_buf_len && @@ -171,12 +174,6 @@ static void completed(struct device *dev, int error) return; } - if (spi->t_len) { - return; - } - - spi->tx_buf = spi->rx_buf = NULL; - spi->tx_buf_len = spi->rx_buf_len = 0; spi->error = error; /* Disabling interrupts */ @@ -191,14 +188,13 @@ static void push_data(struct device *dev) struct spi_dw_data *spi = dev->driver_data; uint32_t cnt = 0; uint32_t data = 0; + uint32_t f_tx; DBG("spi: push_data\n"); - while (test_bit_sr_tfnf(info->regs)) { - if (cnt >= DW_SPI_RXFTLR_DFLT) { - break; - } - + f_tx = DW_SPI_FIFO_DEPTH - read_txflr(info->regs) - + read_rxflr(info->regs) - 1; + while (f_tx) { if (spi->tx_buf && spi->tx_buf_len > 0) { switch (spi->dfs) { case 1: @@ -215,10 +211,10 @@ static void push_data(struct device *dev) } spi->tx_buf += spi->dfs; - spi->tx_buf_len -= spi->dfs; + spi->tx_buf_len--; } else if (spi->rx_buf && spi->rx_buf_len > 0) { /* No need to push more than necessary */ - if (spi->rx_buf_len - cnt <= 0) { + if (spi->rx_buf_len - spi->fifo_diff <= 0) { break; } @@ -229,11 +225,12 @@ static void push_data(struct device *dev) } write_dr(data, info->regs); - cnt += spi->dfs; + f_tx--; + spi->fifo_diff++; + cnt++; } DBG("Pushed: %d\n", cnt); - spi->t_len += cnt; } static void pull_data(struct device *dev) @@ -245,9 +242,9 @@ static void pull_data(struct device *dev) DBG("spi: pull_data\n"); - while (test_bit_sr_rfne(info->regs)) { + while (read_rxflr(info->regs)) { data = read_dr(info->regs); - cnt += spi->dfs; + cnt++; if (spi->rx_buf && spi->rx_buf_len > 0) { switch (spi->dfs) { @@ -265,12 +262,19 @@ static void pull_data(struct device *dev) } spi->rx_buf += spi->dfs; - spi->rx_buf_len -= spi->dfs; + spi->rx_buf_len--; } + + spi->fifo_diff--; + } + + if (!spi->rx_buf_len) { + write_rxftlr(DW_SPI_RXFTLR_DFLT, info->regs); + } else if (read_rxftlr(info->regs) >= spi->rx_buf_len) { + write_rxftlr(spi->rx_buf_len - 1, info->regs); } DBG("Pulled: %d\n", cnt); - spi->t_len -= cnt; } static int spi_dw_configure(struct device *dev, @@ -316,16 +320,12 @@ static int spi_dw_configure(struct device *dev, /* Installing the configuration */ write_ctrlr0(ctrlr0, info->regs); - /* Tx/Rx Threshold */ + /* Tx Threshold, always at default */ write_txftlr(DW_SPI_TXFTLR_DFLT, info->regs); - write_rxftlr(DW_SPI_RXFTLR_DFLT, info->regs); /* Configuring the rate */ write_baudr(config->max_sys_freq, info->regs); - spi->tx_buf = spi->rx_buf = NULL; - spi->tx_buf_len = spi->rx_buf_len = spi->t_len = 0; - /* Mask SPI interrupts */ write_imr(DW_SPI_IMR_MASK, info->regs); @@ -354,6 +354,7 @@ static int spi_dw_transceive(struct device *dev, { struct spi_dw_config *info = dev->config->config_info; struct spi_dw_data *spi = dev->driver_data; + uint32_t rx_thsld = DW_SPI_RXFTLR_DFLT; DBG("spi_dw_transceive: %p, %p, %u, %p, %u\n", dev, tx_buf, tx_buf_len, rx_buf, rx_buf_len); @@ -369,9 +370,18 @@ static int spi_dw_transceive(struct device *dev, /* Set buffers info */ spi->tx_buf = tx_buf; - spi->tx_buf_len = tx_buf_len; + spi->tx_buf_len = tx_buf_len/spi->dfs; spi->rx_buf = rx_buf; - spi->rx_buf_len = rx_buf_len; + spi->rx_buf_len = rx_buf_len/spi->dfs; + spi->fifo_diff = 0; + + /* Does Rx thresholds needs to be lower? */ + if (rx_buf_len && spi->rx_buf_len < DW_SPI_FIFO_DEPTH) { + rx_thsld = spi->rx_buf_len - 1; + } else if (!rx_buf_len && spi->tx_buf_len < DW_SPI_FIFO_DEPTH) { + rx_thsld = spi->tx_buf_len - 1; + } + write_rxftlr(rx_thsld, info->regs); /* Slave select */ write_ser(spi->slave, info->regs); diff --git a/drivers/spi/spi_dw.h b/drivers/spi/spi_dw.h index 9ecb1af70..31b9823ec 100644 --- a/drivers/spi/spi_dw.h +++ b/drivers/spi/spi_dw.h @@ -36,9 +36,11 @@ struct spi_dw_config { struct spi_dw_data { device_sync_call_t sync; - uint8_t error; - uint8_t dfs; /* data frame size in bytes */ - uint16_t slave; + uint32_t error:1; + uint32_t dfs:3; /* dfs in bytes: 1,2 or 4 */ + uint32_t slave:17; /* up 16 slaves */ + uint32_t fifo_diff:9; /* cannot be bigger than FIFO depth */ + uint32_t _unused:2; #ifdef CONFIG_SPI_DW_CLOCK_GATE struct device *clock; #endif /* CONFIG_SPI_DW_CLOCK_GATE */ @@ -46,7 +48,6 @@ struct spi_dw_data { uint32_t tx_buf_len; uint8_t *rx_buf; uint32_t rx_buf_len; - uint32_t t_len; }; /* Registers */ @@ -91,7 +92,14 @@ struct spi_dw_data { #define DW_SPI_CTRLR0_DFS DW_SPI_CTRLR0_DFS_32 #endif -#define SPI_DFS_TO_BYTES(__bpw) ((__bpw / 8) + 1) +/* 0x38 represents the bits 8,16 and 32. Knowing that 24 is bits 8 and 16 + * These are the bits were when you divide by 8, you keep the result as it is. + * For all the other ones, 4 to 7, 9 to 15, etc... you need a +1, + * since on such division it takes only the result above 0 + */ +#define SPI_DFS_TO_BYTES(__bpw) (((__bpw) & ~0x38) ? \ + (((__bpw) / 8) + 1) : \ + ((__bpw) / 8)) /* SSIENR bits */ #define DW_SPI_SSIENR_SSIEN_BIT (0) @@ -136,6 +144,7 @@ struct spi_dw_data { /* Threshold defaults */ #define DW_SPI_TXFTLR_DFLT (0x5) #define DW_SPI_RXFTLR_DFLT (0x5) +#define DW_SPI_FIFO_DEPTH (8) /* Interrupt mask (IMR) */ #define DW_SPI_IMR_MASK (0x0) |