diff mbox series

[5/5] spi: tegra210-quad: native dma support

Message ID 20221001122148.9158-5-kyarlagadda@nvidia.com (mailing list archive)
State New, archived
Headers show
Series [1/5] spi: tegra210-quad: Fix combined sequence | expand

Commit Message

Krishna Yarlagadda Oct. 1, 2022, 12:21 p.m. UTC
Enable Native DMA support for Tegra23 & Tegra24

Signed-off-by: Krishna Yarlagadda <kyarlagadda@nvidia.com>
---
 drivers/spi/spi-tegra210-quad.c | 136 +++++++++++++++++++++++---------
 1 file changed, 97 insertions(+), 39 deletions(-)

Comments

kernel test robot Oct. 1, 2022, 8:08 p.m. UTC | #1
Hi Krishna,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on broonie-spi/for-next]
[also build test WARNING on linus/master v6.0-rc7 next-20220930]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Krishna-Yarlagadda/spi-tegra210-quad-Fix-combined-sequence/20221001-202349
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
config: hexagon-randconfig-r045-20220925
compiler: clang version 16.0.0 (https://github.com/llvm/llvm-project 791a7ae1ba3efd6bca96338e10ffde557ba83920)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/1c7e26dac0d8ad5c5cb6f42d07a57b943b369185
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Krishna-Yarlagadda/spi-tegra210-quad-Fix-combined-sequence/20221001-202349
        git checkout 1c7e26dac0d8ad5c5cb6f42d07a57b943b369185
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash drivers/spi/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/spi/spi-tegra210-quad.c:669:42: warning: shift count >= width of type [-Wshift-count-overflow]
                   tegra_qspi_writel(tqspi, ((tx_dma_phys >> 32) & 0xff),
                                                          ^  ~~
   drivers/spi/spi-tegra210-quad.c:696:42: warning: shift count >= width of type [-Wshift-count-overflow]
                   tegra_qspi_writel(tqspi, ((rx_dma_phys >> 32) & 0xff),
                                                          ^  ~~
   2 warnings generated.


vim +669 drivers/spi/spi-tegra210-quad.c

   614	
   615	static int tegra_qspi_start_dma_based_transfer(struct tegra_qspi *tqspi, struct spi_transfer *t)
   616	{
   617		struct dma_slave_config dma_sconfig = { 0 };
   618		dma_addr_t rx_dma_phys, tx_dma_phys;
   619		unsigned int len;
   620		u8 dma_burst;
   621		int ret = 0;
   622		u32 val;
   623		bool has_ext_dma = (tqspi->soc_data->has_dma &
   624				    QSPI_DMA_EXT) ? true : false;
   625	
   626		if (tqspi->is_packed) {
   627			ret = tegra_qspi_dma_map_xfer(tqspi, t);
   628			if (ret < 0)
   629				return ret;
   630		}
   631	
   632		val = QSPI_DMA_BLK_SET(tqspi->curr_dma_words - 1);
   633		tegra_qspi_writel(tqspi, val, QSPI_DMA_BLK);
   634	
   635		tegra_qspi_unmask_irq(tqspi);
   636	
   637		if (tqspi->is_packed)
   638			len = DIV_ROUND_UP(tqspi->curr_dma_words * tqspi->bytes_per_word, 4) * 4;
   639		else
   640			len = tqspi->curr_dma_words * 4;
   641	
   642		/* set attention level based on length of transfer */
   643		if (has_ext_dma) {
   644			val = 0;
   645			if (len & 0xf) {
   646				val |= QSPI_TX_TRIG_1 | QSPI_RX_TRIG_1;
   647				dma_burst = 1;
   648			} else if (((len) >> 4) & 0x1) {
   649				val |= QSPI_TX_TRIG_4 | QSPI_RX_TRIG_4;
   650				dma_burst = 4;
   651			} else {
   652				val |= QSPI_TX_TRIG_8 | QSPI_RX_TRIG_8;
   653				dma_burst = 8;
   654			}
   655		}
   656	
   657		tegra_qspi_writel(tqspi, val, QSPI_DMA_CTL);
   658		tqspi->dma_control_reg = val;
   659	
   660		dma_sconfig.device_fc = true;
   661		if ((tqspi->cur_direction & DATA_DIR_TX) && !has_ext_dma) {
   662			if (tqspi->is_packed)
   663				tx_dma_phys = t->tx_dma;
   664			else
   665				tx_dma_phys = tqspi->tx_dma_phys;
   666			tegra_qspi_copy_client_txbuf_to_qspi_txbuf(tqspi, t);
   667			tegra_qspi_writel(tqspi, (tx_dma_phys & 0xffffffff),
   668					  QSPI_DMA_MEM_ADDRESS_REG);
 > 669			tegra_qspi_writel(tqspi, ((tx_dma_phys >> 32) & 0xff),
   670					  QSPI_DMA_HI_ADDRESS_REG);
   671		} else if ((tqspi->cur_direction & DATA_DIR_TX) && has_ext_dma) {
   672			dma_sconfig.dst_addr = tqspi->phys + QSPI_TX_FIFO;
   673			dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
   674			dma_sconfig.dst_maxburst = dma_burst;
   675			ret = dmaengine_slave_config(tqspi->tx_dma_chan, &dma_sconfig);
   676			if (ret < 0) {
   677				dev_err(tqspi->dev, "failed DMA slave config: %d\n", ret);
   678				return ret;
   679			}
   680	
   681			tegra_qspi_copy_client_txbuf_to_qspi_txbuf(tqspi, t);
   682			ret = tegra_qspi_start_tx_dma(tqspi, t, len);
   683			if (ret < 0) {
   684				dev_err(tqspi->dev, "failed to starting TX DMA: %d\n", ret);
   685				return ret;
   686			}
   687		}
   688	
   689		if ((tqspi->cur_direction & DATA_DIR_RX) && !has_ext_dma) {
   690			if (tqspi->is_packed)
   691				rx_dma_phys = t->rx_dma;
   692			else
   693				rx_dma_phys = tqspi->rx_dma_phys;
   694			tegra_qspi_writel(tqspi, (rx_dma_phys & 0xffffffff),
   695					  QSPI_DMA_MEM_ADDRESS_REG);
   696			tegra_qspi_writel(tqspi, ((rx_dma_phys >> 32) & 0xff),
   697					  QSPI_DMA_HI_ADDRESS_REG);
   698		} else if ((tqspi->cur_direction & DATA_DIR_RX) && has_ext_dma) {
   699			dma_sconfig.src_addr = tqspi->phys + QSPI_RX_FIFO;
   700			dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
   701			dma_sconfig.src_maxburst = dma_burst;
   702			ret = dmaengine_slave_config(tqspi->rx_dma_chan, &dma_sconfig);
   703			if (ret < 0) {
   704				dev_err(tqspi->dev, "failed DMA slave config: %d\n", ret);
   705				return ret;
   706			}
   707	
   708			dma_sync_single_for_device(tqspi->dev, tqspi->rx_dma_phys,
   709						   tqspi->dma_buf_size,
   710						   DMA_FROM_DEVICE);
   711	
   712			ret = tegra_qspi_start_rx_dma(tqspi, t, len);
   713			if (ret < 0) {
   714				dev_err(tqspi->dev, "failed to start RX DMA: %d\n", ret);
   715				if (tqspi->cur_direction & DATA_DIR_TX)
   716					dmaengine_terminate_all(tqspi->tx_dma_chan);
   717				return ret;
   718			}
   719		}
   720	
   721		tegra_qspi_writel(tqspi, tqspi->command1_reg, QSPI_COMMAND1);
   722	
   723		tqspi->is_curr_dma_xfer = true;
   724		tqspi->dma_control_reg = val;
   725		val |= QSPI_DMA_EN;
   726		tegra_qspi_writel(tqspi, val, QSPI_DMA_CTL);
   727	
   728		return ret;
   729	}
   730
kernel test robot Oct. 1, 2022, 8:50 p.m. UTC | #2
Hi Krishna,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on broonie-spi/for-next]
[also build test WARNING on linus/master v6.0-rc7 next-20220930]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Krishna-Yarlagadda/spi-tegra210-quad-Fix-combined-sequence/20221001-202349
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
config: m68k-allyesconfig
compiler: m68k-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/1c7e26dac0d8ad5c5cb6f42d07a57b943b369185
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Krishna-Yarlagadda/spi-tegra210-quad-Fix-combined-sequence/20221001-202349
        git checkout 1c7e26dac0d8ad5c5cb6f42d07a57b943b369185
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k SHELL=/bin/bash drivers/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/spi/spi-tegra210-quad.c: In function 'tegra_qspi_start_dma_based_transfer':
>> drivers/spi/spi-tegra210-quad.c:669:56: warning: right shift count >= width of type [-Wshift-count-overflow]
     669 |                 tegra_qspi_writel(tqspi, ((tx_dma_phys >> 32) & 0xff),
         |                                                        ^~
   drivers/spi/spi-tegra210-quad.c:696:56: warning: right shift count >= width of type [-Wshift-count-overflow]
     696 |                 tegra_qspi_writel(tqspi, ((rx_dma_phys >> 32) & 0xff),
         |                                                        ^~


vim +669 drivers/spi/spi-tegra210-quad.c

   614	
   615	static int tegra_qspi_start_dma_based_transfer(struct tegra_qspi *tqspi, struct spi_transfer *t)
   616	{
   617		struct dma_slave_config dma_sconfig = { 0 };
   618		dma_addr_t rx_dma_phys, tx_dma_phys;
   619		unsigned int len;
   620		u8 dma_burst;
   621		int ret = 0;
   622		u32 val;
   623		bool has_ext_dma = (tqspi->soc_data->has_dma &
   624				    QSPI_DMA_EXT) ? true : false;
   625	
   626		if (tqspi->is_packed) {
   627			ret = tegra_qspi_dma_map_xfer(tqspi, t);
   628			if (ret < 0)
   629				return ret;
   630		}
   631	
   632		val = QSPI_DMA_BLK_SET(tqspi->curr_dma_words - 1);
   633		tegra_qspi_writel(tqspi, val, QSPI_DMA_BLK);
   634	
   635		tegra_qspi_unmask_irq(tqspi);
   636	
   637		if (tqspi->is_packed)
   638			len = DIV_ROUND_UP(tqspi->curr_dma_words * tqspi->bytes_per_word, 4) * 4;
   639		else
   640			len = tqspi->curr_dma_words * 4;
   641	
   642		/* set attention level based on length of transfer */
   643		if (has_ext_dma) {
   644			val = 0;
   645			if (len & 0xf) {
   646				val |= QSPI_TX_TRIG_1 | QSPI_RX_TRIG_1;
   647				dma_burst = 1;
   648			} else if (((len) >> 4) & 0x1) {
   649				val |= QSPI_TX_TRIG_4 | QSPI_RX_TRIG_4;
   650				dma_burst = 4;
   651			} else {
   652				val |= QSPI_TX_TRIG_8 | QSPI_RX_TRIG_8;
   653				dma_burst = 8;
   654			}
   655		}
   656	
   657		tegra_qspi_writel(tqspi, val, QSPI_DMA_CTL);
   658		tqspi->dma_control_reg = val;
   659	
   660		dma_sconfig.device_fc = true;
   661		if ((tqspi->cur_direction & DATA_DIR_TX) && !has_ext_dma) {
   662			if (tqspi->is_packed)
   663				tx_dma_phys = t->tx_dma;
   664			else
   665				tx_dma_phys = tqspi->tx_dma_phys;
   666			tegra_qspi_copy_client_txbuf_to_qspi_txbuf(tqspi, t);
   667			tegra_qspi_writel(tqspi, (tx_dma_phys & 0xffffffff),
   668					  QSPI_DMA_MEM_ADDRESS_REG);
 > 669			tegra_qspi_writel(tqspi, ((tx_dma_phys >> 32) & 0xff),
   670					  QSPI_DMA_HI_ADDRESS_REG);
   671		} else if ((tqspi->cur_direction & DATA_DIR_TX) && has_ext_dma) {
   672			dma_sconfig.dst_addr = tqspi->phys + QSPI_TX_FIFO;
   673			dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
   674			dma_sconfig.dst_maxburst = dma_burst;
   675			ret = dmaengine_slave_config(tqspi->tx_dma_chan, &dma_sconfig);
   676			if (ret < 0) {
   677				dev_err(tqspi->dev, "failed DMA slave config: %d\n", ret);
   678				return ret;
   679			}
   680	
   681			tegra_qspi_copy_client_txbuf_to_qspi_txbuf(tqspi, t);
   682			ret = tegra_qspi_start_tx_dma(tqspi, t, len);
   683			if (ret < 0) {
   684				dev_err(tqspi->dev, "failed to starting TX DMA: %d\n", ret);
   685				return ret;
   686			}
   687		}
   688	
   689		if ((tqspi->cur_direction & DATA_DIR_RX) && !has_ext_dma) {
   690			if (tqspi->is_packed)
   691				rx_dma_phys = t->rx_dma;
   692			else
   693				rx_dma_phys = tqspi->rx_dma_phys;
   694			tegra_qspi_writel(tqspi, (rx_dma_phys & 0xffffffff),
   695					  QSPI_DMA_MEM_ADDRESS_REG);
   696			tegra_qspi_writel(tqspi, ((rx_dma_phys >> 32) & 0xff),
   697					  QSPI_DMA_HI_ADDRESS_REG);
   698		} else if ((tqspi->cur_direction & DATA_DIR_RX) && has_ext_dma) {
   699			dma_sconfig.src_addr = tqspi->phys + QSPI_RX_FIFO;
   700			dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
   701			dma_sconfig.src_maxburst = dma_burst;
   702			ret = dmaengine_slave_config(tqspi->rx_dma_chan, &dma_sconfig);
   703			if (ret < 0) {
   704				dev_err(tqspi->dev, "failed DMA slave config: %d\n", ret);
   705				return ret;
   706			}
   707	
   708			dma_sync_single_for_device(tqspi->dev, tqspi->rx_dma_phys,
   709						   tqspi->dma_buf_size,
   710						   DMA_FROM_DEVICE);
   711	
   712			ret = tegra_qspi_start_rx_dma(tqspi, t, len);
   713			if (ret < 0) {
   714				dev_err(tqspi->dev, "failed to start RX DMA: %d\n", ret);
   715				if (tqspi->cur_direction & DATA_DIR_TX)
   716					dmaengine_terminate_all(tqspi->tx_dma_chan);
   717				return ret;
   718			}
   719		}
   720	
   721		tegra_qspi_writel(tqspi, tqspi->command1_reg, QSPI_COMMAND1);
   722	
   723		tqspi->is_curr_dma_xfer = true;
   724		tqspi->dma_control_reg = val;
   725		val |= QSPI_DMA_EN;
   726		tegra_qspi_writel(tqspi, val, QSPI_DMA_CTL);
   727	
   728		return ret;
   729	}
   730
Geert Uytterhoeven Oct. 2, 2022, 10:37 a.m. UTC | #3
Hi Krishna,

On Sat, Oct 1, 2022 at 2:26 PM Krishna Yarlagadda
<kyarlagadda@nvidia.com> wrote:
> Enable Native DMA support for Tegra23 & Tegra24
>
> Signed-off-by: Krishna Yarlagadda <kyarlagadda@nvidia.com>

Thanks for your patch!

> --- a/drivers/spi/spi-tegra210-quad.c
> +++ b/drivers/spi/spi-tegra210-quad.c

> @@ -163,7 +169,7 @@
>  #define DATA_TRANSFER                          3
>
>  struct tegra_qspi_soc_data {
> -       bool has_dma;
> +       int has_dma;

unsigned int

Please rename the variable to e.g. "dma_mode", as "has_<foo>" suggests
it is a boolean flag.

>         bool cmb_xfer_capable;
>         unsigned int cs_count;
>  };

> @@ -629,23 +640,35 @@ static int tegra_qspi_start_dma_based_transfer(struct tegra_qspi *tqspi, struct
>                 len = tqspi->curr_dma_words * 4;
>
>         /* set attention level based on length of transfer */
> -       val = 0;
> -       if (len & 0xf) {
> -               val |= QSPI_TX_TRIG_1 | QSPI_RX_TRIG_1;
> -               dma_burst = 1;
> -       } else if (((len) >> 4) & 0x1) {
> -               val |= QSPI_TX_TRIG_4 | QSPI_RX_TRIG_4;
> -               dma_burst = 4;
> -       } else {
> -               val |= QSPI_TX_TRIG_8 | QSPI_RX_TRIG_8;
> -               dma_burst = 8;
> +       if (has_ext_dma) {
> +               val = 0;
> +               if (len & 0xf) {
> +                       val |= QSPI_TX_TRIG_1 | QSPI_RX_TRIG_1;
> +                       dma_burst = 1;
> +               } else if (((len) >> 4) & 0x1) {
> +                       val |= QSPI_TX_TRIG_4 | QSPI_RX_TRIG_4;
> +                       dma_burst = 4;
> +               } else {
> +                       val |= QSPI_TX_TRIG_8 | QSPI_RX_TRIG_8;
> +                       dma_burst = 8;
> +               }
>         }
>
>         tegra_qspi_writel(tqspi, val, QSPI_DMA_CTL);
>         tqspi->dma_control_reg = val;
>
>         dma_sconfig.device_fc = true;
> -       if (tqspi->cur_direction & DATA_DIR_TX) {
> +       if ((tqspi->cur_direction & DATA_DIR_TX) && !has_ext_dma) {
> +               if (tqspi->is_packed)
> +                       tx_dma_phys = t->tx_dma;
> +               else
> +                       tx_dma_phys = tqspi->tx_dma_phys;
> +               tegra_qspi_copy_client_txbuf_to_qspi_txbuf(tqspi, t);
> +               tegra_qspi_writel(tqspi, (tx_dma_phys & 0xffffffff),

lower_32_bits(), for consistency with below.

> +                                 QSPI_DMA_MEM_ADDRESS_REG);
> +               tegra_qspi_writel(tqspi, ((tx_dma_phys >> 32) & 0xff),

upper_32_bits(), to fix the build failures reported by 0-day
("warning: shift count >= width of type").

> +                                 QSPI_DMA_HI_ADDRESS_REG);
> +       } else if ((tqspi->cur_direction & DATA_DIR_TX) && has_ext_dma) {
>                 dma_sconfig.dst_addr = tqspi->phys + QSPI_TX_FIFO;
>                 dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
>                 dma_sconfig.dst_maxburst = dma_burst;

> @@ -1045,6 +1085,8 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi,
>                                         struct spi_message *msg)
>  {
>         bool is_first_msg = true;
> +       bool has_ext_dma = (tqspi->soc_data->has_dma &
> +                           QSPI_DMA_EXT) ? true : false;

No need for the "? true : false" (everywhere)

>         struct spi_transfer *xfer;
>         struct spi_device *spi = msg->spi;
>         u8 transfer_phase = 0;

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
diff mbox series

Patch

diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c
index 99811509dafa..edecb999a614 100644
--- a/drivers/spi/spi-tegra210-quad.c
+++ b/drivers/spi/spi-tegra210-quad.c
@@ -111,6 +111,9 @@ 
 #define QSPI_DMA_BLK				0x024
 #define QSPI_DMA_BLK_SET(x)			(((x) & 0xffff) << 0)
 
+#define QSPI_DMA_MEM_ADDRESS_REG		0x028
+#define QSPI_DMA_HI_ADDRESS_REG			0x02c
+
 #define QSPI_TX_FIFO				0x108
 #define QSPI_RX_FIFO				0x188
 
@@ -155,6 +158,9 @@ 
 #define DATA_DIR_TX				BIT(0)
 #define DATA_DIR_RX				BIT(1)
 
+#define QSPI_DMA_EXT				BIT(0)
+#define QSPI_DMA_INT				BIT(1)
+
 #define QSPI_DMA_TIMEOUT			(msecs_to_jiffies(1000))
 #define DEFAULT_QSPI_DMA_BUF_LEN		(64 * 1024)
 #define CMD_TRANSFER				0
@@ -163,7 +169,7 @@ 
 #define DATA_TRANSFER				3
 
 struct tegra_qspi_soc_data {
-	bool has_dma;
+	int has_dma;
 	bool cmb_xfer_capable;
 	unsigned int cs_count;
 };
@@ -600,17 +606,22 @@  static void tegra_qspi_dma_unmap_xfer(struct tegra_qspi *tqspi, struct spi_trans
 
 	len = DIV_ROUND_UP(tqspi->curr_dma_words * tqspi->bytes_per_word, 4) * 4;
 
-	dma_unmap_single(tqspi->dev, t->tx_dma, len, DMA_TO_DEVICE);
-	dma_unmap_single(tqspi->dev, t->rx_dma, len, DMA_FROM_DEVICE);
+	if (t->tx_buf)
+		dma_unmap_single(tqspi->dev, t->tx_dma, len, DMA_TO_DEVICE);
+	if (t->rx_buf)
+		dma_unmap_single(tqspi->dev, t->rx_dma, len, DMA_FROM_DEVICE);
 }
 
 static int tegra_qspi_start_dma_based_transfer(struct tegra_qspi *tqspi, struct spi_transfer *t)
 {
 	struct dma_slave_config dma_sconfig = { 0 };
+	dma_addr_t rx_dma_phys, tx_dma_phys;
 	unsigned int len;
 	u8 dma_burst;
 	int ret = 0;
 	u32 val;
+	bool has_ext_dma = (tqspi->soc_data->has_dma &
+			    QSPI_DMA_EXT) ? true : false;
 
 	if (tqspi->is_packed) {
 		ret = tegra_qspi_dma_map_xfer(tqspi, t);
@@ -629,23 +640,35 @@  static int tegra_qspi_start_dma_based_transfer(struct tegra_qspi *tqspi, struct
 		len = tqspi->curr_dma_words * 4;
 
 	/* set attention level based on length of transfer */
-	val = 0;
-	if (len & 0xf) {
-		val |= QSPI_TX_TRIG_1 | QSPI_RX_TRIG_1;
-		dma_burst = 1;
-	} else if (((len) >> 4) & 0x1) {
-		val |= QSPI_TX_TRIG_4 | QSPI_RX_TRIG_4;
-		dma_burst = 4;
-	} else {
-		val |= QSPI_TX_TRIG_8 | QSPI_RX_TRIG_8;
-		dma_burst = 8;
+	if (has_ext_dma) {
+		val = 0;
+		if (len & 0xf) {
+			val |= QSPI_TX_TRIG_1 | QSPI_RX_TRIG_1;
+			dma_burst = 1;
+		} else if (((len) >> 4) & 0x1) {
+			val |= QSPI_TX_TRIG_4 | QSPI_RX_TRIG_4;
+			dma_burst = 4;
+		} else {
+			val |= QSPI_TX_TRIG_8 | QSPI_RX_TRIG_8;
+			dma_burst = 8;
+		}
 	}
 
 	tegra_qspi_writel(tqspi, val, QSPI_DMA_CTL);
 	tqspi->dma_control_reg = val;
 
 	dma_sconfig.device_fc = true;
-	if (tqspi->cur_direction & DATA_DIR_TX) {
+	if ((tqspi->cur_direction & DATA_DIR_TX) && !has_ext_dma) {
+		if (tqspi->is_packed)
+			tx_dma_phys = t->tx_dma;
+		else
+			tx_dma_phys = tqspi->tx_dma_phys;
+		tegra_qspi_copy_client_txbuf_to_qspi_txbuf(tqspi, t);
+		tegra_qspi_writel(tqspi, (tx_dma_phys & 0xffffffff),
+				  QSPI_DMA_MEM_ADDRESS_REG);
+		tegra_qspi_writel(tqspi, ((tx_dma_phys >> 32) & 0xff),
+				  QSPI_DMA_HI_ADDRESS_REG);
+	} else if ((tqspi->cur_direction & DATA_DIR_TX) && has_ext_dma) {
 		dma_sconfig.dst_addr = tqspi->phys + QSPI_TX_FIFO;
 		dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 		dma_sconfig.dst_maxburst = dma_burst;
@@ -663,7 +686,16 @@  static int tegra_qspi_start_dma_based_transfer(struct tegra_qspi *tqspi, struct
 		}
 	}
 
-	if (tqspi->cur_direction & DATA_DIR_RX) {
+	if ((tqspi->cur_direction & DATA_DIR_RX) && !has_ext_dma) {
+		if (tqspi->is_packed)
+			rx_dma_phys = t->rx_dma;
+		else
+			rx_dma_phys = tqspi->rx_dma_phys;
+		tegra_qspi_writel(tqspi, (rx_dma_phys & 0xffffffff),
+				  QSPI_DMA_MEM_ADDRESS_REG);
+		tegra_qspi_writel(tqspi, ((rx_dma_phys >> 32) & 0xff),
+				  QSPI_DMA_HI_ADDRESS_REG);
+	} else if ((tqspi->cur_direction & DATA_DIR_RX) && has_ext_dma) {
 		dma_sconfig.src_addr = tqspi->phys + QSPI_RX_FIFO;
 		dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 		dma_sconfig.src_maxburst = dma_burst;
@@ -751,13 +783,29 @@  static int tegra_qspi_init_dma(struct tegra_qspi *tqspi)
 	u32 *dma_buf;
 	int err;
 
-	dma_chan = dma_request_chan(tqspi->dev, "rx");
-	if (IS_ERR(dma_chan)) {
-		err = PTR_ERR(dma_chan);
-		goto err_out;
-	}
+	if (!tqspi->soc_data->has_dma)
+		return -ENODEV;
+
+	if (tqspi->soc_data->has_dma & QSPI_DMA_EXT) {
+		dma_chan = dma_request_chan(tqspi->dev, "rx");
+		if (IS_ERR(dma_chan)) {
+			err = PTR_ERR(dma_chan);
+			goto err_out;
+		}
 
-	tqspi->rx_dma_chan = dma_chan;
+		tqspi->rx_dma_chan = dma_chan;
+
+		dma_chan = dma_request_chan(tqspi->dev, "tx");
+		if (IS_ERR(dma_chan)) {
+			err = PTR_ERR(dma_chan);
+			goto err_out;
+		}
+
+		tqspi->tx_dma_chan = dma_chan;
+	} else {
+		tqspi->rx_dma_chan = NULL;
+		tqspi->tx_dma_chan = NULL;
+	}
 
 	dma_buf = dma_alloc_coherent(tqspi->dev, tqspi->dma_buf_size, &dma_phys, GFP_KERNEL);
 	if (!dma_buf) {
@@ -768,14 +816,6 @@  static int tegra_qspi_init_dma(struct tegra_qspi *tqspi)
 	tqspi->rx_dma_buf = dma_buf;
 	tqspi->rx_dma_phys = dma_phys;
 
-	dma_chan = dma_request_chan(tqspi->dev, "tx");
-	if (IS_ERR(dma_chan)) {
-		err = PTR_ERR(dma_chan);
-		goto err_out;
-	}
-
-	tqspi->tx_dma_chan = dma_chan;
-
 	dma_buf = dma_alloc_coherent(tqspi->dev, tqspi->dma_buf_size, &dma_phys, GFP_KERNEL);
 	if (!dma_buf) {
 		err = -ENOMEM;
@@ -1045,6 +1085,8 @@  static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi,
 					struct spi_message *msg)
 {
 	bool is_first_msg = true;
+	bool has_ext_dma = (tqspi->soc_data->has_dma &
+			    QSPI_DMA_EXT) ? true : false;
 	struct spi_transfer *xfer;
 	struct spi_device *spi = msg->spi;
 	u8 transfer_phase = 0;
@@ -1109,12 +1151,12 @@  static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi,
 			if (WARN_ON(ret == 0)) {
 				dev_err(tqspi->dev, "QSPI Transfer failed with timeout: %d\n",
 					ret);
-				if (tqspi->is_curr_dma_xfer &&
+				if (tqspi->is_curr_dma_xfer && has_ext_dma &&
 				    (tqspi->cur_direction & DATA_DIR_TX))
 					dmaengine_terminate_all
 						(tqspi->tx_dma_chan);
 
-				if (tqspi->is_curr_dma_xfer &&
+				if (tqspi->is_curr_dma_xfer && has_ext_dma &&
 				    (tqspi->cur_direction & DATA_DIR_RX))
 					dmaengine_terminate_all
 						(tqspi->rx_dma_chan);
@@ -1178,6 +1220,8 @@  static int tegra_qspi_non_combined_seq_xfer(struct tegra_qspi *tqspi,
 	struct spi_device *spi = msg->spi;
 	struct spi_transfer *transfer;
 	bool is_first_msg = true;
+	bool has_ext_dma = (tqspi->soc_data->has_dma &
+			    QSPI_DMA_EXT) ? true : false;
 	int ret = 0, val = 0;
 
 	msg->status = 0;
@@ -1230,9 +1274,11 @@  static int tegra_qspi_non_combined_seq_xfer(struct tegra_qspi *tqspi,
 						  QSPI_DMA_TIMEOUT);
 		if (WARN_ON(ret == 0)) {
 			dev_err(tqspi->dev, "transfer timeout\n");
-			if (tqspi->is_curr_dma_xfer && (tqspi->cur_direction & DATA_DIR_TX))
+			if (tqspi->is_curr_dma_xfer && has_ext_dma &&
+			    (tqspi->cur_direction & DATA_DIR_TX))
 				dmaengine_terminate_all(tqspi->tx_dma_chan);
-			if (tqspi->is_curr_dma_xfer && (tqspi->cur_direction & DATA_DIR_RX))
+			if (tqspi->is_curr_dma_xfer && has_ext_dma &&
+			    (tqspi->cur_direction & DATA_DIR_RX))
 				dmaengine_terminate_all(tqspi->rx_dma_chan);
 			tegra_qspi_handle_error(tqspi);
 			ret = -EIO;
@@ -1365,8 +1411,20 @@  static irqreturn_t handle_dma_based_xfer(struct tegra_qspi *tqspi)
 	unsigned long flags;
 	long wait_status;
 	int err = 0;
+	bool has_ext_dma = (tqspi->soc_data->has_dma &
+			    QSPI_DMA_EXT) ? true : false;
+
+	if (tqspi->cur_direction & DATA_DIR_TX && !has_ext_dma) {
+		if (tqspi->tx_status)
+			err += 1;
+	}
+
+	if (tqspi->cur_direction & DATA_DIR_RX && !has_ext_dma) {
+		if (tqspi->rx_status)
+			err += 2;
+	}
 
-	if (tqspi->cur_direction & DATA_DIR_TX) {
+	if (tqspi->cur_direction & DATA_DIR_TX && has_ext_dma) {
 		if (tqspi->tx_status) {
 			dmaengine_terminate_all(tqspi->tx_dma_chan);
 			err += 1;
@@ -1381,7 +1439,7 @@  static irqreturn_t handle_dma_based_xfer(struct tegra_qspi *tqspi)
 		}
 	}
 
-	if (tqspi->cur_direction & DATA_DIR_RX) {
+	if (tqspi->cur_direction & DATA_DIR_RX && has_ext_dma) {
 		if (tqspi->rx_status) {
 			dmaengine_terminate_all(tqspi->rx_dma_chan);
 			err += 2;
@@ -1454,25 +1512,25 @@  static irqreturn_t tegra_qspi_isr_thread(int irq, void *context_data)
 }
 
 static struct tegra_qspi_soc_data tegra210_qspi_soc_data = {
-	.has_dma = true,
+	.has_dma = QSPI_DMA_EXT,
 	.cmb_xfer_capable = false,
 	.cs_count = 1,
 };
 
 static struct tegra_qspi_soc_data tegra186_qspi_soc_data = {
-	.has_dma = true,
+	.has_dma = QSPI_DMA_EXT,
 	.cmb_xfer_capable = true,
 	.cs_count = 1,
 };
 
 static struct tegra_qspi_soc_data tegra234_qspi_soc_data = {
-	.has_dma = false,
+	.has_dma = QSPI_DMA_INT,
 	.cmb_xfer_capable = true,
 	.cs_count = 1,
 };
 
 static struct tegra_qspi_soc_data tegra241_qspi_soc_data = {
-	.has_dma = false,
+	.has_dma = QSPI_DMA_INT,
 	.cmb_xfer_capable = true,
 	.cs_count = 4,
 };