Enable Native DMA support for Tegra23 & Tegra24
Signed-off-by: Krishna Yarlagadda <[email protected]>
---
drivers/spi/spi-tegra210-quad.c | 136 +++++++++++++++++++++++---------
1 file changed, 97 insertions(+), 39 deletions(-)
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,
};
--
2.17.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 <[email protected]>
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
--
0-DAY CI Kernel Test Service
https://01.org/lkp
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 <[email protected]>
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
--
0-DAY CI Kernel Test Service
https://01.org/lkp
Hi Krishna,
On Sat, Oct 1, 2022 at 2:26 PM Krishna Yarlagadda
<[email protected]> wrote:
> Enable Native DMA support for Tegra23 & Tegra24
>
> Signed-off-by: Krishna Yarlagadda <[email protected]>
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 -- [email protected]
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