[PATCH 07/16] spi: bcm63xx-hsspi: Add polling mode support

From: William Zhang
Date: Fri Jan 06 2023 - 15:21:25 EST


Polling mode provides better throughput in general by avoiding the
interrupt overhead as the maximum data size one interrupt can handle is
only 512 bytes.

When interrupt is not defined in the HSSPI dts node, driver switches to
polling mode for controller SPI message processing. Also add driver
banner message when the driver is loaded successfully.

When test on a Broadcom BCM47622(ARM A7 dual core) reference board with
WINBOND W25N01GV SPI NAND chip at 100MHz SPI clock using the MTD speed
test suite, it shows about 15% improvement on the write and 30% on
the read:
** Interrupt mode **
mtd_speedtest: MTD device: 0 count: 16
mtd_speedtest: MTD device size 134217728, eraseblock size 131072, page
size 2048, count of eraseblocks 1024, pages per eraseblock 64, OOB size
64
mtd_test: scanning for bad eraseblocks
mtd_test: scanned 16 eraseblocks, 0 are bad
mtd_speedtest: testing eraseblock write speed
mtd_speedtest: eraseblock write speed is 3072 KiB/s
mtd_speedtest: testing eraseblock read speed
mtd_speedtest: eraseblock read speed is 6690 KiB/s
mtd_speedtest: testing page write speed
mtd_speedtest: page write speed is 3066 KiB/s
mtd_speedtest: testing page read speed
mtd_speedtest: page read speed is 6762 KiB/s
mtd_speedtest: testing 2 page write speed
mtd_speedtest: 2 page write speed is 3071 KiB/s
mtd_speedtest: testing 2 page read speed
mtd_speedtest: 2 page read speed is 6772 KiB/s
** Polling mode **
mtd_speedtest: MTD device: 0 count: 16
mtd_speedtest: MTD device size 134217728, eraseblock size 131072, page
size 2048, count of eraseblocks 1024, pages per eraseblock 64, OOB size
64
mtd_test: scanning for bad eraseblocks
mtd_test: scanned 16 eraseblocks, 0 are bad
mtd_speedtest: testing eraseblock write speed
mtd_speedtest: eraseblock write speed is 3542 KiB/s
mtd_speedtest: testing eraseblock read speed
mtd_speedtest: eraseblock read speed is 8825 KiB/s
mtd_speedtest: testing page write speed
mtd_speedtest: page write speed is 3563 KiB/s
mtd_speedtest: testing page read speed
mtd_speedtest: page read speed is 8787 KiB/s
mtd_speedtest: testing 2 page write speed
mtd_speedtest: 2 page write speed is 3572 KiB/s
mtd_speedtest: testing 2 page read speed
mtd_speedtest: 2 page read speed is 8806 KiB/s

Signed-off-by: William Zhang <william.zhang@xxxxxxxxxxxx>
---

drivers/spi/spi-bcm63xx-hsspi.c | 49 +++++++++++++++++++++++++--------
1 file changed, 38 insertions(+), 11 deletions(-)

diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c
index 63682c8ff955..2b4cdf7e7002 100644
--- a/drivers/spi/spi-bcm63xx-hsspi.c
+++ b/drivers/spi/spi-bcm63xx-hsspi.c
@@ -57,6 +57,7 @@
#define PINGPONG_CMD_SS_SHIFT 12

#define HSSPI_PINGPONG_STATUS_REG(x) (0x84 + (x) * 0x40)
+#define HSSPI_PINGPONG_STATUS_SRC_BUSY BIT(1)

#define HSSPI_PROFILE_CLK_CTRL_REG(x) (0x100 + (x) * 0x20)
#define CLK_CTRL_FREQ_CTRL_MASK 0x0000ffff
@@ -96,6 +97,7 @@

#define HSSPI_SPI_MAX_CS 8
#define HSSPI_BUS_NUM 1 /* 0 is legacy SPI */
+#define HSSPI_POLL_STATUS_TIMEOUT_MS 100

struct bcm63xx_hsspi {
struct completion done;
@@ -109,6 +111,7 @@ struct bcm63xx_hsspi {

u32 speed_hz;
u8 cs_polarity;
+ int irq;
};

static void bcm63xx_hsspi_set_cs(struct bcm63xx_hsspi *bs, unsigned int cs,
@@ -163,6 +166,8 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
int step_size = HSSPI_BUFFER_LEN;
const u8 *tx = t->tx_buf;
u8 *rx = t->rx_buf;
+ u32 val;
+ unsigned long limit;

bcm63xx_hsspi_set_clk(bs, spi, t->speed_hz);
bcm63xx_hsspi_set_cs(bs, spi->chip_select, true);
@@ -197,8 +202,9 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
__raw_writew(cpu_to_be16(opcode | curr_step), bs->fifo);

/* enable interrupt */
- __raw_writel(HSSPI_PINGx_CMD_DONE(0),
- bs->regs + HSSPI_INT_MASK_REG);
+ if (bs->irq > 0)
+ __raw_writel(HSSPI_PINGx_CMD_DONE(0),
+ bs->regs + HSSPI_INT_MASK_REG);

/* start the transfer */
__raw_writel(!chip_select << PINGPONG_CMD_SS_SHIFT |
@@ -206,9 +212,21 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
PINGPONG_COMMAND_START_NOW,
bs->regs + HSSPI_PINGPONG_COMMAND_REG(0));

- if (wait_for_completion_timeout(&bs->done, HZ) == 0) {
- dev_err(&bs->pdev->dev, "transfer timed out!\n");
- return -ETIMEDOUT;
+ if (bs->irq > 0) {
+ if (wait_for_completion_timeout(&bs->done, HZ) == 0)
+ goto err_timeout;
+ } else {
+ /* polling mode checks for status busy bit */
+ limit = jiffies + msecs_to_jiffies(HSSPI_POLL_STATUS_TIMEOUT_MS);
+ while (!time_after(jiffies, limit)) {
+ val = __raw_readl(bs->regs + HSSPI_PINGPONG_STATUS_REG(0));
+ if (val & HSSPI_PINGPONG_STATUS_SRC_BUSY)
+ cpu_relax();
+ else
+ break;
+ }
+ if (val & HSSPI_PINGPONG_STATUS_SRC_BUSY)
+ goto err_timeout;
}

if (rx) {
@@ -220,6 +238,10 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
}

return 0;
+
+err_timeout:
+ dev_err(&bs->pdev->dev, "transfer timed out!\n");
+ return -ETIMEDOUT;
}

static int bcm63xx_hsspi_setup(struct spi_device *spi)
@@ -338,8 +360,8 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
u32 reg, rate, num_cs = HSSPI_SPI_MAX_CS;
struct reset_control *reset;

- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
+ irq = platform_get_irq_optional(pdev, 0);
+ if (irq < 0 && irq != -ENXIO)
return irq;

regs = devm_platform_ioremap_resource(pdev, 0);
@@ -398,6 +420,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
bs->regs = regs;
bs->speed_hz = rate;
bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0));
+ bs->irq = irq;

mutex_init(&bs->bus_mutex);
init_completion(&bs->done);
@@ -434,11 +457,13 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
__raw_writel(reg | GLOBAL_CTRL_CLK_GATE_SSOFF,
bs->regs + HSSPI_GLOBAL_CTRL_REG);

- ret = devm_request_irq(dev, irq, bcm63xx_hsspi_interrupt, IRQF_SHARED,
- pdev->name, bs);
+ if (bs->irq > 0) {
+ ret = devm_request_irq(dev, irq, bcm63xx_hsspi_interrupt, IRQF_SHARED,
+ pdev->name, bs);

- if (ret)
- goto out_put_master;
+ if (ret)
+ goto out_put_master;
+ }

pm_runtime_enable(&pdev->dev);

@@ -447,6 +472,8 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
if (ret)
goto out_pm_disable;

+ dev_info(dev, "Broadcom 63XX High Speed SPI Controller driver");
+
return 0;

out_pm_disable:
--
2.37.3