From a44f0000779d48c061703351df58adb88419a7c3 Mon Sep 17 00:00:00 2001 From: Chuanhong Guo Date: Sun, 25 Nov 2018 10:25:40 +0800 Subject: [PATCH] ramips: mt7621-spi: replace the driver with upstream staging one That driver is more efficient thanks to the refactor of spi reading operation. Signed-off-by: Chuanhong Guo --- .../0043-spi-add-mt7621-support.patch | 219 ++++++++++-------- 1 file changed, 121 insertions(+), 98 deletions(-) diff --git a/target/linux/ramips/patches-4.14/0043-spi-add-mt7621-support.patch b/target/linux/ramips/patches-4.14/0043-spi-add-mt7621-support.patch index d9bc48d69b..8367675ff5 100644 --- a/target/linux/ramips/patches-4.14/0043-spi-add-mt7621-support.patch +++ b/target/linux/ramips/patches-4.14/0043-spi-add-mt7621-support.patch @@ -5,6 +5,8 @@ Subject: [PATCH 43/53] spi: add mt7621 support Signed-off-by: John Crispin --- +Note: This patch contains upstream mt7621-spi at 9c562d8411a54f6731cdc587c29968d9e8610c85 + drivers/spi/Kconfig | 6 + drivers/spi/Makefile | 1 + drivers/spi/spi-mt7621.c | 480 ++++++++++++++++++++++++++++++++++++++++++++++ @@ -38,7 +40,7 @@ Signed-off-by: John Crispin obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o --- /dev/null +++ b/drivers/spi/spi-mt7621.c -@@ -0,0 +1,494 @@ +@@ -0,0 +1,515 @@ +/* + * spi-mt7621.c -- MediaTek MT7621 SPI controller driver + * @@ -96,7 +98,8 @@ Signed-off-by: John Crispin +#define MT7621_CPOL BIT(4) +#define MT7621_LSB_FIRST BIT(3) + -+#define RT2880_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH) ++#define RT2880_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | \ ++ SPI_LSB_FIRST | SPI_CS_HIGH) + +struct mt7621_spi; + @@ -106,6 +109,7 @@ Signed-off-by: John Crispin + unsigned int sys_freq; + unsigned int speed; + struct clk *clk; ++ int pending_write; + + struct mt7621_spi_ops *ops; +}; @@ -131,14 +135,13 @@ Signed-off-by: John Crispin + + master |= 7 << 29; + master |= 1 << 2; -+#ifdef CONFIG_SOC_MT7620 + if (duplex) + master |= 1 << 10; + else -+#endif + master &= ~(1 << 10); + + mt7621_spi_write(rs, MT7621_SPI_MASTER, master); ++ rs->pending_write = 0; +} + +static void mt7621_spi_set_cs(struct spi_device *spi, int enable) @@ -147,7 +150,7 @@ Signed-off-by: John Crispin + int cs = spi->chip_select; + u32 polar = 0; + -+ mt7621_spi_reset(rs, cs); ++ mt7621_spi_reset(rs, cs); + if (enable) + polar = BIT(cs); + mt7621_spi_write(rs, MT7621_SPI_POLAR, polar); @@ -180,36 +183,34 @@ Signed-off-by: John Crispin + reg |= MT7621_LSB_FIRST; + + reg &= ~(MT7621_CPHA | MT7621_CPOL); -+ switch(spi->mode & (SPI_CPOL | SPI_CPHA)) { -+ case SPI_MODE_0: -+ break; -+ case SPI_MODE_1: -+ reg |= MT7621_CPHA; -+ break; -+ case SPI_MODE_2: -+ reg |= MT7621_CPOL; -+ break; -+ case SPI_MODE_3: -+ reg |= MT7621_CPOL | MT7621_CPHA; -+ break; ++ switch (spi->mode & (SPI_CPOL | SPI_CPHA)) { ++ case SPI_MODE_0: ++ break; ++ case SPI_MODE_1: ++ reg |= MT7621_CPHA; ++ break; ++ case SPI_MODE_2: ++ reg |= MT7621_CPOL; ++ break; ++ case SPI_MODE_3: ++ reg |= MT7621_CPOL | MT7621_CPHA; ++ break; + } + mt7621_spi_write(rs, MT7621_SPI_MASTER, reg); + + return 0; +} + -+static inline int mt7621_spi_wait_till_ready(struct spi_device *spi) ++static inline int mt7621_spi_wait_till_ready(struct mt7621_spi *rs) +{ -+ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); + int i; + + for (i = 0; i < RALINK_SPI_WAIT_MAX_LOOP; i++) { + u32 status; + + status = mt7621_spi_read(rs, MT7621_SPI_TRANS); -+ if ((status & SPITRANS_BUSY) == 0) { ++ if ((status & SPITRANS_BUSY) == 0) + return 0; -+ } + cpu_relax(); + udelay(1); + } @@ -217,92 +218,124 @@ Signed-off-by: John Crispin + return -ETIMEDOUT; +} + -+static int mt7621_spi_transfer_half_duplex(struct spi_master *master, -+ struct spi_message *m) ++static void mt7621_spi_read_half_duplex(struct mt7621_spi *rs, ++ int rx_len, u8 *buf) +{ -+ struct mt7621_spi *rs = spi_master_get_devdata(master); -+ struct spi_device *spi = m->spi; -+ unsigned int speed = spi->max_speed_hz; -+ struct spi_transfer *t = NULL; -+ int status = 0; -+ int i, len = 0; -+ int rx_len = 0; -+ u32 data[9] = { 0 }; -+ u32 val; ++ /* Combine with any pending write, and perform one or ++ * more half-duplex transactions reading 'len' bytes. ++ * Data to be written is already in MT7621_SPI_DATA* ++ */ ++ int tx_len = rs->pending_write; + -+ mt7621_spi_wait_till_ready(spi); ++ rs->pending_write = 0; + -+ list_for_each_entry(t, &m->transfers, transfer_list) { -+ const u8 *buf = t->tx_buf; ++ while (rx_len || tx_len) { ++ int i; ++ u32 val = (min(tx_len, 4) * 8) << 24; ++ int rx = min(rx_len, 32); + -+ if (t->rx_buf) -+ rx_len += t->len; ++ if (tx_len > 4) ++ val |= (tx_len - 4) * 8; ++ val |= (rx * 8) << 12; ++ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val); + -+ if (!buf) -+ continue; ++ tx_len = 0; + -+ if (t->speed_hz < speed) -+ speed = t->speed_hz; ++ val = mt7621_spi_read(rs, MT7621_SPI_TRANS); ++ val |= SPI_CTL_START; ++ mt7621_spi_write(rs, MT7621_SPI_TRANS, val); + -+ /* -+ * m25p80 might attempt to write more data than we can handle. -+ * truncate the message to what we can fit into the registers -+ */ -+ if (len + t->len > 36) -+ t->len = 36 - len; ++ mt7621_spi_wait_till_ready(rs); + -+ for (i = 0; i < t->len; i++, len++) -+ data[len / 4] |= buf[i] << (8 * (len & 3)); ++ for (i = 0; i < rx; i++) { ++ if ((i % 4) == 0) ++ val = mt7621_spi_read(rs, MT7621_SPI_DATA0 + i); ++ *buf++ = val & 0xff; ++ val >>= 8; ++ } ++ rx_len -= i; + } ++} + -+ if (WARN_ON(rx_len > 32)) { -+ status = -EIO; -+ goto msg_done; -+ } ++static inline void mt7621_spi_flush(struct mt7621_spi *rs) ++{ ++ mt7621_spi_read_half_duplex(rs, 0, NULL); ++} + -+ if (mt7621_spi_prepare(spi, speed)) { -+ status = -EIO; -+ goto msg_done; ++static void mt7621_spi_write_half_duplex(struct mt7621_spi *rs, ++ int tx_len, const u8 *buf) ++{ ++ int val = 0; ++ int len = rs->pending_write; ++ ++ if (len & 3) { ++ val = mt7621_spi_read(rs, MT7621_SPI_OPCODE + (len & ~3)); ++ if (len < 4) { ++ val <<= (4 - len) * 8; ++ val = swab32(val); ++ } + } -+ data[0] = swab32(data[0]); -+ if (len < 4) -+ data[0] >>= (4 - len) * 8; -+ -+ for (i = 0; i < len; i += 4) -+ mt7621_spi_write(rs, MT7621_SPI_OPCODE + i, data[i / 4]); -+ -+ val = (min_t(int, len, 4) * 8) << 24; -+ if (len > 4) -+ val |= (len - 4) * 8; -+ val |= (rx_len * 8) << 12; -+ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val); + -+ mt7621_spi_set_cs(spi, 1); ++ while (tx_len > 0) { ++ if (len >= 36) { ++ rs->pending_write = len; ++ mt7621_spi_flush(rs); ++ len = 0; ++ } + -+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS); -+ val |= SPI_CTL_START; -+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val); ++ val |= *buf++ << (8 * (len & 3)); ++ len++; ++ if ((len & 3) == 0) { ++ if (len == 4) ++ /* The byte-order of the opcode is weird! */ ++ val = swab32(val); ++ mt7621_spi_write(rs, MT7621_SPI_OPCODE + len - 4, val); ++ val = 0; ++ } ++ tx_len -= 1; ++ } ++ if (len & 3) { ++ if (len < 4) { ++ val = swab32(val); ++ val >>= (4 - len) * 8; ++ } ++ mt7621_spi_write(rs, MT7621_SPI_OPCODE + (len & ~3), val); ++ } ++ rs->pending_write = len; ++} + -+ mt7621_spi_wait_till_ready(spi); ++static int mt7621_spi_transfer_half_duplex(struct spi_master *master, ++ struct spi_message *m) ++{ ++ struct mt7621_spi *rs = spi_master_get_devdata(master); ++ struct spi_device *spi = m->spi; ++ unsigned int speed = spi->max_speed_hz; ++ struct spi_transfer *t = NULL; ++ int status = 0; + -+ mt7621_spi_set_cs(spi, 0); ++ mt7621_spi_wait_till_ready(rs); + -+ for (i = 0; i < rx_len; i += 4) -+ data[i / 4] = mt7621_spi_read(rs, MT7621_SPI_DATA0 + i); ++ list_for_each_entry(t, &m->transfers, transfer_list) ++ if (t->speed_hz < speed) ++ speed = t->speed_hz; + -+ m->actual_length = len + rx_len; ++ if (mt7621_spi_prepare(spi, speed)) { ++ status = -EIO; ++ goto msg_done; ++ } + -+ len = 0; ++ mt7621_spi_set_cs(spi, 1); ++ m->actual_length = 0; + list_for_each_entry(t, &m->transfers, transfer_list) { -+ u8 *buf = t->rx_buf; -+ -+ if (!buf) -+ continue; -+ -+ for (i = 0; i < t->len; i++, len++) -+ buf[i] = data[len / 4] >> (8 * (len & 3)); ++ if (t->rx_buf) ++ mt7621_spi_read_half_duplex(rs, t->len, t->rx_buf); ++ else if (t->tx_buf) ++ mt7621_spi_write_half_duplex(rs, t->len, t->tx_buf); ++ m->actual_length += t->len; + } ++ mt7621_spi_flush(rs); + ++ mt7621_spi_set_cs(spi, 0); +msg_done: + m->status = status; + spi_finalize_current_message(master); @@ -310,7 +343,6 @@ Signed-off-by: John Crispin + return 0; +} + -+#ifdef CONFIG_SOC_MT7620 +static int mt7621_spi_transfer_full_duplex(struct spi_master *master, + struct spi_message *m) +{ @@ -324,7 +356,7 @@ Signed-off-by: John Crispin + u32 data[9] = { 0 }; + u32 val = 0; + -+ mt7621_spi_wait_till_ready(spi); ++ mt7621_spi_wait_till_ready(rs); + + list_for_each_entry(t, &m->transfers, transfer_list) { + const u8 *buf = t->tx_buf; @@ -369,7 +401,7 @@ Signed-off-by: John Crispin + val |= SPI_CTL_START; + mt7621_spi_write(rs, MT7621_SPI_TRANS, val); + -+ mt7621_spi_wait_till_ready(spi); ++ mt7621_spi_wait_till_ready(rs); + + mt7621_spi_set_cs(spi, 0); + @@ -395,18 +427,15 @@ Signed-off-by: John Crispin + + return 0; +} -+#endif + +static int mt7621_spi_transfer_one_message(struct spi_master *master, + struct spi_message *m) +{ + struct spi_device *spi = m->spi; -+#ifdef CONFIG_SOC_MT7620 + int cs = spi->chip_select; + + if (cs) + return mt7621_spi_transfer_full_duplex(master, m); -+#endif + return mt7621_spi_transfer_half_duplex(master, m); +} + @@ -433,11 +462,6 @@ Signed-off-by: John Crispin +}; +MODULE_DEVICE_TABLE(of, mt7621_spi_match); + -+static size_t mt7621_max_transfer_size(struct spi_device *spi) -+{ -+ return 32; -+} -+ +static int mt7621_spi_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; @@ -483,7 +507,6 @@ Signed-off-by: John Crispin + master->bits_per_word_mask = SPI_BPW_MASK(8); + master->dev.of_node = pdev->dev.of_node; + master->num_chipselect = 2; -+ master->max_transfer_size = mt7621_max_transfer_size; + + dev_set_drvdata(&pdev->dev, master); + @@ -493,6 +516,7 @@ Signed-off-by: John Crispin + rs->master = master; + rs->sys_freq = clk_get_rate(rs->clk); + rs->ops = ops; ++ rs->pending_write = 0; + dev_info(&pdev->dev, "sys_freq: %u\n", rs->sys_freq); + + device_reset(&pdev->dev); @@ -521,7 +545,6 @@ Signed-off-by: John Crispin +static struct platform_driver mt7621_spi_driver = { + .driver = { + .name = DRIVER_NAME, -+ .owner = THIS_MODULE, + .of_match_table = mt7621_spi_match, + }, + .probe = mt7621_spi_probe,