|
|
@@ -56,6 +56,7 @@
|
|
|
|
|
|
/* The maximum bytes that a sdma BD can transfer.*/
|
|
|
#define MAX_SDMA_BD_BYTES (1 << 15)
|
|
|
+#define MX51_ECSPI_CTRL_MAX_BURST 512
|
|
|
|
|
|
enum spi_imx_devtype {
|
|
|
IMX1_CSPI,
|
|
|
@@ -77,6 +78,7 @@ struct spi_imx_devtype_data {
|
|
|
void (*reset)(struct spi_imx_data *);
|
|
|
bool has_dmamode;
|
|
|
unsigned int fifo_size;
|
|
|
+ bool dynamic_burst;
|
|
|
enum spi_imx_devtype devtype;
|
|
|
};
|
|
|
|
|
|
@@ -97,12 +99,14 @@ struct spi_imx_data {
|
|
|
unsigned int bits_per_word;
|
|
|
unsigned int spi_drctl;
|
|
|
|
|
|
- unsigned int count;
|
|
|
+ unsigned int count, remainder;
|
|
|
void (*tx)(struct spi_imx_data *);
|
|
|
void (*rx)(struct spi_imx_data *);
|
|
|
void *rx_buf;
|
|
|
const void *tx_buf;
|
|
|
unsigned int txfifo; /* number of words pushed in tx FIFO */
|
|
|
+ unsigned int dynamic_burst, read_u32;
|
|
|
+ unsigned int word_mask;
|
|
|
|
|
|
/* DMA */
|
|
|
bool usedma;
|
|
|
@@ -231,6 +235,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
|
|
|
return false;
|
|
|
|
|
|
spi_imx->wml = i;
|
|
|
+ spi_imx->dynamic_burst = 0;
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
@@ -245,6 +250,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
|
|
|
#define MX51_ECSPI_CTRL_PREDIV_OFFSET 12
|
|
|
#define MX51_ECSPI_CTRL_CS(cs) ((cs) << 18)
|
|
|
#define MX51_ECSPI_CTRL_BL_OFFSET 20
|
|
|
+#define MX51_ECSPI_CTRL_BL_MASK (0xfff << 20)
|
|
|
|
|
|
#define MX51_ECSPI_CONFIG 0x0c
|
|
|
#define MX51_ECSPI_CONFIG_SCLKPHA(cs) (1 << ((cs) + 0))
|
|
|
@@ -272,6 +278,102 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
|
|
|
#define MX51_ECSPI_TESTREG 0x20
|
|
|
#define MX51_ECSPI_TESTREG_LBC BIT(31)
|
|
|
|
|
|
+static void spi_imx_buf_rx_swap_u32(struct spi_imx_data *spi_imx)
|
|
|
+{
|
|
|
+ unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA);
|
|
|
+ unsigned int bytes_per_word;
|
|
|
+
|
|
|
+ if (spi_imx->rx_buf) {
|
|
|
+#ifdef __LITTLE_ENDIAN
|
|
|
+ bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
|
|
|
+ if (bytes_per_word == 1)
|
|
|
+ val = cpu_to_be32(val);
|
|
|
+ else if (bytes_per_word == 2)
|
|
|
+ val = (val << 16) | (val >> 16);
|
|
|
+#endif
|
|
|
+ val &= spi_imx->word_mask;
|
|
|
+ *(u32 *)spi_imx->rx_buf = val;
|
|
|
+ spi_imx->rx_buf += sizeof(u32);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void spi_imx_buf_rx_swap(struct spi_imx_data *spi_imx)
|
|
|
+{
|
|
|
+ unsigned int bytes_per_word;
|
|
|
+
|
|
|
+ bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
|
|
|
+ if (spi_imx->read_u32) {
|
|
|
+ spi_imx_buf_rx_swap_u32(spi_imx);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (bytes_per_word == 1)
|
|
|
+ spi_imx_buf_rx_u8(spi_imx);
|
|
|
+ else if (bytes_per_word == 2)
|
|
|
+ spi_imx_buf_rx_u16(spi_imx);
|
|
|
+}
|
|
|
+
|
|
|
+static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx)
|
|
|
+{
|
|
|
+ u32 val = 0;
|
|
|
+ unsigned int bytes_per_word;
|
|
|
+
|
|
|
+ if (spi_imx->tx_buf) {
|
|
|
+ val = *(u32 *)spi_imx->tx_buf;
|
|
|
+ val &= spi_imx->word_mask;
|
|
|
+ spi_imx->tx_buf += sizeof(u32);
|
|
|
+ }
|
|
|
+
|
|
|
+ spi_imx->count -= sizeof(u32);
|
|
|
+#ifdef __LITTLE_ENDIAN
|
|
|
+ bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
|
|
|
+
|
|
|
+ if (bytes_per_word == 1)
|
|
|
+ val = cpu_to_be32(val);
|
|
|
+ else if (bytes_per_word == 2)
|
|
|
+ val = (val << 16) | (val >> 16);
|
|
|
+#endif
|
|
|
+ writel(val, spi_imx->base + MXC_CSPITXDATA);
|
|
|
+}
|
|
|
+
|
|
|
+static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)
|
|
|
+{
|
|
|
+ u32 ctrl, val;
|
|
|
+ unsigned int bytes_per_word;
|
|
|
+
|
|
|
+ if (spi_imx->count == spi_imx->remainder) {
|
|
|
+ ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
|
|
|
+ ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
|
|
|
+ if (spi_imx->count > MX51_ECSPI_CTRL_MAX_BURST) {
|
|
|
+ spi_imx->remainder = spi_imx->count %
|
|
|
+ MX51_ECSPI_CTRL_MAX_BURST;
|
|
|
+ val = MX51_ECSPI_CTRL_MAX_BURST * 8 - 1;
|
|
|
+ } else if (spi_imx->count >= sizeof(u32)) {
|
|
|
+ spi_imx->remainder = spi_imx->count % sizeof(u32);
|
|
|
+ val = (spi_imx->count - spi_imx->remainder) * 8 - 1;
|
|
|
+ } else {
|
|
|
+ spi_imx->remainder = 0;
|
|
|
+ val = spi_imx->bits_per_word - 1;
|
|
|
+ spi_imx->read_u32 = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ ctrl |= (val << MX51_ECSPI_CTRL_BL_OFFSET);
|
|
|
+ writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (spi_imx->count >= sizeof(u32)) {
|
|
|
+ spi_imx_buf_tx_swap_u32(spi_imx);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
|
|
|
+
|
|
|
+ if (bytes_per_word == 1)
|
|
|
+ spi_imx_buf_tx_u8(spi_imx);
|
|
|
+ else if (bytes_per_word == 2)
|
|
|
+ spi_imx_buf_tx_u16(spi_imx);
|
|
|
+}
|
|
|
+
|
|
|
/* MX51 eCSPI */
|
|
|
static unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx,
|
|
|
unsigned int fspi, unsigned int *fres)
|
|
|
@@ -698,6 +800,7 @@ static struct spi_imx_devtype_data imx1_cspi_devtype_data = {
|
|
|
.reset = mx1_reset,
|
|
|
.fifo_size = 8,
|
|
|
.has_dmamode = false,
|
|
|
+ .dynamic_burst = false,
|
|
|
.devtype = IMX1_CSPI,
|
|
|
};
|
|
|
|
|
|
@@ -709,6 +812,7 @@ static struct spi_imx_devtype_data imx21_cspi_devtype_data = {
|
|
|
.reset = mx21_reset,
|
|
|
.fifo_size = 8,
|
|
|
.has_dmamode = false,
|
|
|
+ .dynamic_burst = false,
|
|
|
.devtype = IMX21_CSPI,
|
|
|
};
|
|
|
|
|
|
@@ -721,6 +825,7 @@ static struct spi_imx_devtype_data imx27_cspi_devtype_data = {
|
|
|
.reset = mx21_reset,
|
|
|
.fifo_size = 8,
|
|
|
.has_dmamode = false,
|
|
|
+ .dynamic_burst = false,
|
|
|
.devtype = IMX27_CSPI,
|
|
|
};
|
|
|
|
|
|
@@ -732,6 +837,7 @@ static struct spi_imx_devtype_data imx31_cspi_devtype_data = {
|
|
|
.reset = mx31_reset,
|
|
|
.fifo_size = 8,
|
|
|
.has_dmamode = false,
|
|
|
+ .dynamic_burst = false,
|
|
|
.devtype = IMX31_CSPI,
|
|
|
};
|
|
|
|
|
|
@@ -744,6 +850,7 @@ static struct spi_imx_devtype_data imx35_cspi_devtype_data = {
|
|
|
.reset = mx31_reset,
|
|
|
.fifo_size = 8,
|
|
|
.has_dmamode = true,
|
|
|
+ .dynamic_burst = false,
|
|
|
.devtype = IMX35_CSPI,
|
|
|
};
|
|
|
|
|
|
@@ -755,6 +862,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
|
|
|
.reset = mx51_ecspi_reset,
|
|
|
.fifo_size = 64,
|
|
|
.has_dmamode = true,
|
|
|
+ .dynamic_burst = true,
|
|
|
.devtype = IMX51_ECSPI,
|
|
|
};
|
|
|
|
|
|
@@ -827,6 +935,8 @@ static void spi_imx_push(struct spi_imx_data *spi_imx)
|
|
|
while (spi_imx->txfifo < spi_imx->devtype_data->fifo_size) {
|
|
|
if (!spi_imx->count)
|
|
|
break;
|
|
|
+ if (spi_imx->txfifo && (spi_imx->count == spi_imx->remainder))
|
|
|
+ break;
|
|
|
spi_imx->tx(spi_imx);
|
|
|
spi_imx->txfifo++;
|
|
|
}
|
|
|
@@ -920,15 +1030,37 @@ static int spi_imx_setupxfer(struct spi_device *spi,
|
|
|
spi_imx->speed_hz = t->speed_hz;
|
|
|
|
|
|
/* Initialize the functions for transfer */
|
|
|
- if (spi_imx->bits_per_word <= 8) {
|
|
|
- spi_imx->rx = spi_imx_buf_rx_u8;
|
|
|
- spi_imx->tx = spi_imx_buf_tx_u8;
|
|
|
- } else if (spi_imx->bits_per_word <= 16) {
|
|
|
- spi_imx->rx = spi_imx_buf_rx_u16;
|
|
|
- spi_imx->tx = spi_imx_buf_tx_u16;
|
|
|
+ if (spi_imx->devtype_data->dynamic_burst) {
|
|
|
+ u32 mask;
|
|
|
+
|
|
|
+ spi_imx->dynamic_burst = 0;
|
|
|
+ spi_imx->remainder = 0;
|
|
|
+ spi_imx->read_u32 = 1;
|
|
|
+
|
|
|
+ mask = (1 << spi_imx->bits_per_word) - 1;
|
|
|
+ spi_imx->rx = spi_imx_buf_rx_swap;
|
|
|
+ spi_imx->tx = spi_imx_buf_tx_swap;
|
|
|
+ spi_imx->dynamic_burst = 1;
|
|
|
+ spi_imx->remainder = t->len;
|
|
|
+
|
|
|
+ if (spi_imx->bits_per_word <= 8)
|
|
|
+ spi_imx->word_mask = mask << 24 | mask << 16
|
|
|
+ | mask << 8 | mask;
|
|
|
+ else if (spi_imx->bits_per_word <= 16)
|
|
|
+ spi_imx->word_mask = mask << 16 | mask;
|
|
|
+ else
|
|
|
+ spi_imx->word_mask = mask;
|
|
|
} else {
|
|
|
- spi_imx->rx = spi_imx_buf_rx_u32;
|
|
|
- spi_imx->tx = spi_imx_buf_tx_u32;
|
|
|
+ if (spi_imx->bits_per_word <= 8) {
|
|
|
+ spi_imx->rx = spi_imx_buf_rx_u8;
|
|
|
+ spi_imx->tx = spi_imx_buf_tx_u8;
|
|
|
+ } else if (spi_imx->bits_per_word <= 16) {
|
|
|
+ spi_imx->rx = spi_imx_buf_rx_u16;
|
|
|
+ spi_imx->tx = spi_imx_buf_tx_u16;
|
|
|
+ } else {
|
|
|
+ spi_imx->rx = spi_imx_buf_rx_u32;
|
|
|
+ spi_imx->tx = spi_imx_buf_tx_u32;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (spi_imx_can_dma(spi_imx->bitbang.master, spi, t))
|