summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
authorTomasz Bursztyka <tomasz.bursztyka@linux.intel.com>2016-01-15 10:11:24 +0100
committerAnas Nashif <anas.nashif@intel.com>2016-02-05 20:25:22 -0500
commit655fb9fb2ea2f45d3c5d593433c1530894f4c02b (patch)
tree4fb6ab5a8020b13cce0197a1f5eca51b461bf844 /drivers/spi
parentbfb8b375a3c0f9c9d78efa2c4f615b1f2b511a9d (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.c66
-rw-r--r--drivers/spi/spi_dw.h19
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)