--- /dev/null
+From 7841a272e44620959d734735a231371b3b7f5ed9 Mon Sep 17 00:00:00 2001
+From: Maksim Kiselev <bigunclemax@gmail.com>
+Date: Sat, 24 Jun 2023 16:16:22 +0300
+Subject: [PATCH 12/25] spi: sun6i: add quirk for dual and quad SPI modes
+ support
+
+New Allwinner's SPI controllers can support dual and quad SPI modes.
+To enable one of these modes, we should set the corresponding bit in
+the SUN6I_BURST_CTL_CNT_REG register. DRM (28 bits) for dual mode and
+Quad_EN (29 bits) for quad transmission.
+
+Signed-off-by: Maksim Kiselev <bigunclemax@gmail.com>
+---
+ drivers/spi/spi-sun6i.c | 29 +++++++++++++++++++++++++----
+ 1 file changed, 25 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
+index 4f32cd99a81e..f7350ab86e14 100644
+--- a/drivers/spi/spi-sun6i.c
++++ b/drivers/spi/spi-sun6i.c
+@@ -83,6 +83,9 @@
+ #define SUN6I_XMIT_CNT_REG 0x34
+
+ #define SUN6I_BURST_CTL_CNT_REG 0x38
++#define SUN6I_BURST_CTL_CNT_STC_MASK GENMASK(23, 0)
++#define SUN6I_BURST_CTL_CNT_DRM BIT(28)
++#define SUN6I_BURST_CTL_CNT_QUAD_EN BIT(29)
+
+ #define SUN6I_TXDATA_REG 0x200
+ #define SUN6I_RXDATA_REG 0x300
+@@ -90,6 +93,7 @@
+ struct sun6i_spi_cfg {
+ unsigned long fifo_depth;
+ bool has_clk_ctl;
++ u32 mode_bits;
+ };
+
+ struct sun6i_spi {
+@@ -266,7 +270,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
+ unsigned int div, div_cdr1, div_cdr2, timeout;
+ unsigned int start, end, tx_time;
+ unsigned int trig_level;
+- unsigned int tx_len = 0, rx_len = 0;
++ unsigned int tx_len = 0, rx_len = 0, nbits = 0;
+ bool use_dma;
+ int ret = 0;
+ u32 reg;
+@@ -418,13 +422,29 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
+ sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, reg);
+
+ /* Setup the transfer now... */
+- if (sspi->tx_buf)
++ if (sspi->tx_buf) {
+ tx_len = tfr->len;
++ nbits = tfr->tx_nbits;
++ } else if (tfr->rx_buf) {
++ nbits = tfr->rx_nbits;
++ }
++
++ switch (nbits) {
++ case SPI_NBITS_DUAL:
++ reg = SUN6I_BURST_CTL_CNT_DRM;
++ break;
++ case SPI_NBITS_QUAD:
++ reg = SUN6I_BURST_CTL_CNT_QUAD_EN;
++ break;
++ case SPI_NBITS_SINGLE:
++ default:
++ reg = FIELD_PREP(SUN6I_BURST_CTL_CNT_STC_MASK, tx_len);
++ }
+
+ /* Setup the counters */
++ sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, reg);
+ sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, tfr->len);
+ sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, tx_len);
+- sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, tx_len);
+
+ if (!use_dma) {
+ /* Fill the TX FIFO */
+@@ -623,7 +643,8 @@ static int sun6i_spi_probe(struct platform_device *pdev)
+ master->set_cs = sun6i_spi_set_cs;
+ master->transfer_one = sun6i_spi_transfer_one;
+ master->num_chipselect = 4;
+- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
++ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
++ sspi->cfg->mode_bits;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->dev.of_node = pdev->dev.of_node;
+ master->auto_runtime_pm = true;
+--
+2.20.1
+