* [PATCH v3 1/6] spi: tegra210-quad: Fix X1_X2_X4 encoding and support x4 transfers
2025-04-16 11:06 [PATCH v3 0/6] Configure Clocks, Add Internal DMA support Vishwaroop A
@ 2025-04-16 11:06 ` Vishwaroop A
2025-04-16 11:06 ` [PATCH v3 2/6] spi: tegra210-quad: remove redundant error handling code Vishwaroop A
` (6 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Vishwaroop A @ 2025-04-16 11:06 UTC (permalink / raw)
To: thierry.reding, jonathanh, skomatineni, ldewangan, broonie,
linux-spi, linux-tegra, linux-kernel, kyarlagadda, smangipudi
Cc: va
This patch corrects the QSPI_COMMAND_X1_X2_X4 and QSPI_ADDRESS_X1_X2_X4
macros to properly encode the bus width for x1, x2, and x4 transfers.
Although these macros were previously incorrect, they were not being
used in the driver, so no functionality was affected.
The patch updates tegra_qspi_cmd_config() and tegra_qspi_addr_config()
function calls to use the actual bus width from the transfer, instead of
hardcoding it to 0 (which implied x1 mode). This change enables proper
support for x1, x2, and x4 data transfers by correctly configuring the
interface width for commands and addresses.
These modifications improve the QSPI driver's flexibility and prepare it
for future use cases that may require different bus widths for commands
and addresses.
Fixes: 1b8342cc4a38 ("spi: tegra210-quad: combined sequence mode")
Signed-off-by: Vishwaroop A <va@nvidia.com>
---
drivers/spi/spi-tegra210-quad.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c
index 08e49a876894..4983b1f705b8 100644
--- a/drivers/spi/spi-tegra210-quad.c
+++ b/drivers/spi/spi-tegra210-quad.c
@@ -134,7 +134,7 @@
#define QSPI_COMMAND_VALUE_SET(X) (((x) & 0xFF) << 0)
#define QSPI_CMB_SEQ_CMD_CFG 0x1a0
-#define QSPI_COMMAND_X1_X2_X4(x) (((x) & 0x3) << 13)
+#define QSPI_COMMAND_X1_X2_X4(x) ((((x) >> 1) & 0x3) << 13)
#define QSPI_COMMAND_X1_X2_X4_MASK (0x03 << 13)
#define QSPI_COMMAND_SDR_DDR BIT(12)
#define QSPI_COMMAND_SIZE_SET(x) (((x) & 0xFF) << 0)
@@ -147,7 +147,7 @@
#define QSPI_ADDRESS_VALUE_SET(X) (((x) & 0xFFFF) << 0)
#define QSPI_CMB_SEQ_ADDR_CFG 0x1ac
-#define QSPI_ADDRESS_X1_X2_X4(x) (((x) & 0x3) << 13)
+#define QSPI_ADDRESS_X1_X2_X4(x) ((((x) >> 1) & 0x3) << 13)
#define QSPI_ADDRESS_X1_X2_X4_MASK (0x03 << 13)
#define QSPI_ADDRESS_SDR_DDR BIT(12)
#define QSPI_ADDRESS_SIZE_SET(x) (((x) & 0xFF) << 0)
@@ -1036,10 +1036,6 @@ static u32 tegra_qspi_addr_config(bool is_ddr, u8 bus_width, u8 len)
{
u32 addr_config = 0;
- /* Extract Address configuration and value */
- is_ddr = 0; //Only SDR mode supported
- bus_width = 0; //X1 mode
-
if (is_ddr)
addr_config |= QSPI_ADDRESS_SDR_DDR;
else
@@ -1079,13 +1075,13 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi,
switch (transfer_phase) {
case CMD_TRANSFER:
/* X1 SDR mode */
- cmd_config = tegra_qspi_cmd_config(false, 0,
+ cmd_config = tegra_qspi_cmd_config(false, xfer->tx_nbits,
xfer->len);
cmd_value = *((const u8 *)(xfer->tx_buf));
break;
case ADDR_TRANSFER:
/* X1 SDR mode */
- addr_config = tegra_qspi_addr_config(false, 0,
+ addr_config = tegra_qspi_addr_config(false, xfer->tx_nbits,
xfer->len);
address_value = *((const u32 *)(xfer->tx_buf));
break;
--
2.17.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v3 2/6] spi: tegra210-quad: remove redundant error handling code
2025-04-16 11:06 [PATCH v3 0/6] Configure Clocks, Add Internal DMA support Vishwaroop A
2025-04-16 11:06 ` [PATCH v3 1/6] spi: tegra210-quad: Fix X1_X2_X4 encoding and support x4 transfers Vishwaroop A
@ 2025-04-16 11:06 ` Vishwaroop A
2025-04-16 11:06 ` [PATCH v3 3/6] spi: tegra210-quad: modify chip select (CS) deactivation Vishwaroop A
` (5 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Vishwaroop A @ 2025-04-16 11:06 UTC (permalink / raw)
To: thierry.reding, jonathanh, skomatineni, ldewangan, broonie,
linux-spi, linux-tegra, linux-kernel, kyarlagadda, smangipudi
Cc: va
Remove unnecessary error handling code that terminated transfers and
executed delay on errors. This code was redundant as error handling is
already done at a higher level in the SPI core.
Fixes: 1b8342cc4a38 ("spi: tegra210-quad: combined sequence mode")
Signed-off-by: Vishwaroop A <va@nvidia.com>
---
drivers/spi/spi-tegra210-quad.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c
index 4983b1f705b8..a9359b005ee8 100644
--- a/drivers/spi/spi-tegra210-quad.c
+++ b/drivers/spi/spi-tegra210-quad.c
@@ -1175,10 +1175,6 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi,
exit:
msg->status = ret;
- if (ret < 0) {
- tegra_qspi_transfer_end(spi);
- spi_transfer_delay_exec(xfer);
- }
return ret;
}
--
2.17.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v3 3/6] spi: tegra210-quad: modify chip select (CS) deactivation
2025-04-16 11:06 [PATCH v3 0/6] Configure Clocks, Add Internal DMA support Vishwaroop A
2025-04-16 11:06 ` [PATCH v3 1/6] spi: tegra210-quad: Fix X1_X2_X4 encoding and support x4 transfers Vishwaroop A
2025-04-16 11:06 ` [PATCH v3 2/6] spi: tegra210-quad: remove redundant error handling code Vishwaroop A
@ 2025-04-16 11:06 ` Vishwaroop A
2025-04-16 11:06 ` [PATCH v3 4/6] arm64: tegra: Configure QSPI clocks and add DMA Vishwaroop A
` (4 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Vishwaroop A @ 2025-04-16 11:06 UTC (permalink / raw)
To: thierry.reding, jonathanh, skomatineni, ldewangan, broonie,
linux-spi, linux-tegra, linux-kernel, kyarlagadda, smangipudi
Cc: va
Modify the chip select (CS) deactivation and inter-transfer delay
execution only during the DATA_TRANSFER phase when the cs_change
flag is not set. This ensures proper CS handling and timing between
transfers while eliminating redundant operations.
Fixes: 1b8342cc4a38 ("spi: tegra210-quad: combined sequence mode")
Signed-off-by: Vishwaroop A <va@nvidia.com>
---
drivers/spi/spi-tegra210-quad.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c
index a9359b005ee8..159fbbfd4a38 100644
--- a/drivers/spi/spi-tegra210-quad.c
+++ b/drivers/spi/spi-tegra210-quad.c
@@ -1159,16 +1159,16 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi,
ret = -EIO;
goto exit;
}
- if (!xfer->cs_change) {
- tegra_qspi_transfer_end(spi);
- spi_transfer_delay_exec(xfer);
- }
break;
default:
ret = -EINVAL;
goto exit;
}
msg->actual_length += xfer->len;
+ if (!xfer->cs_change && transfer_phase == DATA_TRANSFER) {
+ tegra_qspi_transfer_end(spi);
+ spi_transfer_delay_exec(xfer);
+ }
transfer_phase++;
}
ret = 0;
--
2.17.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v3 4/6] arm64: tegra: Configure QSPI clocks and add DMA
2025-04-16 11:06 [PATCH v3 0/6] Configure Clocks, Add Internal DMA support Vishwaroop A
` (2 preceding siblings ...)
2025-04-16 11:06 ` [PATCH v3 3/6] spi: tegra210-quad: modify chip select (CS) deactivation Vishwaroop A
@ 2025-04-16 11:06 ` Vishwaroop A
2025-04-16 14:11 ` Jon Hunter
2025-04-16 11:06 ` [PATCH v3 5/6] spi: tegra210-quad: Update dummy sequence configuration Vishwaroop A
` (3 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Vishwaroop A @ 2025-04-16 11:06 UTC (permalink / raw)
To: thierry.reding, jonathanh, skomatineni, ldewangan, broonie,
linux-spi, linux-tegra, linux-kernel, kyarlagadda, smangipudi
Cc: va
For Tegra234 devices, set QSPI0_2X_PM to 199.99 MHz and QSPI0_PM to
99.99 MHz using PLLC as the parent clock. These frequencies enable
Quad IO reads at up to 99.99 MHz, the maximum achievable given PLL
and clock divider limitations.
Signed-off-by: Vishwaroop A <va@nvidia.com>
---
arch/arm64/boot/dts/nvidia/tegra234.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
index 2601b43b2d8c..419dde2bfdf9 100644
--- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
@@ -2948,6 +2948,11 @@
<&bpmp TEGRA234_CLK_QSPI0_PM>;
clock-names = "qspi", "qspi_out";
resets = <&bpmp TEGRA234_RESET_QSPI0>;
+ iommus = <&smmu_niso1 TEGRA234_SID_QSPI0>;
+ assigned-clocks = <&bpmp TEGRA234_CLK_QSPI0_2X_PM>,
+ <&bpmp TEGRA234_CLK_QSPI0_PM>;
+ assigned-clock-rates = <199999999 99999999>;
+ assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLC>;
status = "disabled";
};
@@ -3031,6 +3036,11 @@
<&bpmp TEGRA234_CLK_QSPI1_PM>;
clock-names = "qspi", "qspi_out";
resets = <&bpmp TEGRA234_RESET_QSPI1>;
+ assigned-clocks = <&bpmp TEGRA234_CLK_QSPI1_2X_PM>,
+ <&bpmp TEGRA234_CLK_QSPI1_PM>;
+ assigned-clock-rates = <199999999 99999999>;
+ assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLC>;
+ iommus = <&smmu_niso1 TEGRA234_SID_QSPI1>;
status = "disabled";
};
--
2.17.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v3 4/6] arm64: tegra: Configure QSPI clocks and add DMA
2025-04-16 11:06 ` [PATCH v3 4/6] arm64: tegra: Configure QSPI clocks and add DMA Vishwaroop A
@ 2025-04-16 14:11 ` Jon Hunter
0 siblings, 0 replies; 14+ messages in thread
From: Jon Hunter @ 2025-04-16 14:11 UTC (permalink / raw)
To: Vishwaroop A, thierry.reding, skomatineni, ldewangan, broonie,
linux-spi, linux-tegra, linux-kernel, kyarlagadda, smangipudi
On 16/04/2025 12:06, Vishwaroop A wrote:
> For Tegra234 devices, set QSPI0_2X_PM to 199.99 MHz and QSPI0_PM to
> 99.99 MHz using PLLC as the parent clock. These frequencies enable
> Quad IO reads at up to 99.99 MHz, the maximum achievable given PLL
> and clock divider limitations.
No mention of adding the iommus property here.
> Signed-off-by: Vishwaroop A <va@nvidia.com>
> ---
> arch/arm64/boot/dts/nvidia/tegra234.dtsi | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
> index 2601b43b2d8c..419dde2bfdf9 100644
> --- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi
> +++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
> @@ -2948,6 +2948,11 @@
> <&bpmp TEGRA234_CLK_QSPI0_PM>;
> clock-names = "qspi", "qspi_out";
> resets = <&bpmp TEGRA234_RESET_QSPI0>;
> + iommus = <&smmu_niso1 TEGRA234_SID_QSPI0>;
> + assigned-clocks = <&bpmp TEGRA234_CLK_QSPI0_2X_PM>,
> + <&bpmp TEGRA234_CLK_QSPI0_PM>;
> + assigned-clock-rates = <199999999 99999999>;
> + assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLC>;
> status = "disabled";
> };
>
> @@ -3031,6 +3036,11 @@
> <&bpmp TEGRA234_CLK_QSPI1_PM>;
> clock-names = "qspi", "qspi_out";
> resets = <&bpmp TEGRA234_RESET_QSPI1>;
> + assigned-clocks = <&bpmp TEGRA234_CLK_QSPI1_2X_PM>,
> + <&bpmp TEGRA234_CLK_QSPI1_PM>;
> + assigned-clock-rates = <199999999 99999999>;
> + assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLC>;
> + iommus = <&smmu_niso1 TEGRA234_SID_QSPI1>;
Please be consistent with the ordering of properties.
> status = "disabled";
> };
>
--
nvpublic
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 5/6] spi: tegra210-quad: Update dummy sequence configuration
2025-04-16 11:06 [PATCH v3 0/6] Configure Clocks, Add Internal DMA support Vishwaroop A
` (3 preceding siblings ...)
2025-04-16 11:06 ` [PATCH v3 4/6] arm64: tegra: Configure QSPI clocks and add DMA Vishwaroop A
@ 2025-04-16 11:06 ` Vishwaroop A
2025-04-16 11:06 ` [PATCH v3 6/6] spi: tegra210-quad: Add support for internal DMA Vishwaroop A
` (2 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Vishwaroop A @ 2025-04-16 11:06 UTC (permalink / raw)
To: thierry.reding, jonathanh, skomatineni, ldewangan, broonie,
linux-spi, linux-tegra, linux-kernel, kyarlagadda, smangipudi
Cc: va
Adding support for the dummy sequence configuration. The dummy sequence
introduces a delay between the command and the data phases of a
transfer. This delay, measured in clock cycles, allows the slave
device to prepare for data transmission, ensuring data integrity and
proper synchronization.
Signed-off-by: Vishwaroop A <va@nvidia.com>
---
drivers/spi/spi-tegra210-quad.c | 31 ++++++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c
index 159fbbfd4a38..04f41e92c1e2 100644
--- a/drivers/spi/spi-tegra210-quad.c
+++ b/drivers/spi/spi-tegra210-quad.c
@@ -22,6 +22,7 @@
#include <linux/spi/spi.h>
#include <linux/acpi.h>
#include <linux/property.h>
+#include <linux/sizes.h>
#define QSPI_COMMAND1 0x000
#define QSPI_BIT_LENGTH(x) (((x) & 0x1f) << 0)
@@ -156,10 +157,14 @@
#define DATA_DIR_RX BIT(1)
#define QSPI_DMA_TIMEOUT (msecs_to_jiffies(1000))
-#define DEFAULT_QSPI_DMA_BUF_LEN (64 * 1024)
-#define CMD_TRANSFER 0
-#define ADDR_TRANSFER 1
-#define DATA_TRANSFER 2
+#define DEFAULT_QSPI_DMA_BUF_LEN SZ_64K
+
+enum tegra_qspi_transfer_type {
+ CMD_TRANSFER = 0,
+ ADDR_TRANSFER = 1,
+ DUMMY_TRANSFER = 2,
+ DATA_TRANSFER = 3
+};
struct tegra_qspi_soc_data {
bool has_dma;
@@ -1085,6 +1090,13 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi,
xfer->len);
address_value = *((const u32 *)(xfer->tx_buf));
break;
+ case DUMMY_TRANSFER:
+ if (xfer->dummy_data) {
+ tqspi->dummy_cycles = xfer->len * 8 / xfer->tx_nbits;
+ break;
+ }
+ transfer_phase++;
+ fallthrough;
case DATA_TRANSFER:
/* Program Command, Address value in register */
tegra_qspi_writel(tqspi, cmd_value, QSPI_CMB_SEQ_CMD);
@@ -1292,7 +1304,9 @@ static bool tegra_qspi_validate_cmb_seq(struct tegra_qspi *tqspi,
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
transfer_count++;
}
- if (!tqspi->soc_data->cmb_xfer_capable || transfer_count != 3)
+ if (!tqspi->soc_data->cmb_xfer_capable)
+ return false;
+ if (transfer_count > 4 || transfer_count < 3)
return false;
xfer = list_first_entry(&msg->transfers, typeof(*xfer),
transfer_list);
@@ -1302,6 +1316,13 @@ static bool tegra_qspi_validate_cmb_seq(struct tegra_qspi *tqspi,
if (xfer->len > 4 || xfer->len < 3)
return false;
xfer = list_next_entry(xfer, transfer_list);
+ if (transfer_count == 4) {
+ if (xfer->dummy_data != 1)
+ return false;
+ if ((xfer->len * 8 / xfer->tx_nbits) > QSPI_DUMMY_CYCLES_MAX)
+ return false;
+ xfer = list_next_entry(xfer, transfer_list);
+ }
if (!tqspi->soc_data->has_dma && xfer->len > (QSPI_FIFO_DEPTH << 2))
return false;
--
2.17.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v3 6/6] spi: tegra210-quad: Add support for internal DMA
2025-04-16 11:06 [PATCH v3 0/6] Configure Clocks, Add Internal DMA support Vishwaroop A
` (4 preceding siblings ...)
2025-04-16 11:06 ` [PATCH v3 5/6] spi: tegra210-quad: Update dummy sequence configuration Vishwaroop A
@ 2025-04-16 11:06 ` Vishwaroop A
2025-04-16 11:57 ` Mukesh Kumar Savaliya
2025-04-24 13:29 ` Mark Brown
2025-04-16 12:43 ` [PATCH v3 0/6] Configure Clocks, Add Internal DMA support Rob Herring (Arm)
2025-04-25 23:00 ` (subset) " Mark Brown
7 siblings, 2 replies; 14+ messages in thread
From: Vishwaroop A @ 2025-04-16 11:06 UTC (permalink / raw)
To: thierry.reding, jonathanh, skomatineni, ldewangan, broonie,
linux-spi, linux-tegra, linux-kernel, kyarlagadda, smangipudi
Cc: va
Previous generations of Tegra supported DMA operations by an external
DMA controller, but the QSPI on Tegra234 devices now have an internal
DMA controller.
Introduce routines to initialize and configure internal DMA channels
for both transmit and receive paths. Set up DMA mapping functions to
manage buffer addresses effectively.
The variable err is changed to num_errors to more accurately represent
its purpose in the code. The updated name clarifies that the variable
tracks the number of errors encountered during execution, rather than
serving as a generic error flag or code.
Tegra241 device supports DMA via an external DMA controller (GPCDMA), so
enable this.
Signed-off-by: Vishwaroop A <va@nvidia.com>
---
drivers/spi/spi-tegra210-quad.c | 227 +++++++++++++++++++-------------
1 file changed, 132 insertions(+), 95 deletions(-)
diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c
index 04f41e92c1e2..e80a0850d07e 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 0x028
+#define QSPI_DMA_HI_ADDRESS 0x02c
+
#define QSPI_TX_FIFO 0x108
#define QSPI_RX_FIFO 0x188
@@ -167,9 +170,9 @@ enum tegra_qspi_transfer_type {
};
struct tegra_qspi_soc_data {
- bool has_dma;
bool cmb_xfer_capable;
bool supports_tpm;
+ bool has_ext_dma;
unsigned int cs_count;
};
@@ -605,17 +608,21 @@ 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_ext_dma;
if (tqspi->is_packed) {
ret = tegra_qspi_dma_map_xfer(tqspi, t);
@@ -634,60 +641,86 @@ 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);
}
- 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) {
- 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;
- ret = dmaengine_slave_config(tqspi->tx_dma_chan, &dma_sconfig);
- if (ret < 0) {
- dev_err(tqspi->dev, "failed DMA slave config: %d\n", ret);
- return ret;
- }
- tegra_qspi_copy_client_txbuf_to_qspi_txbuf(tqspi, t);
- ret = tegra_qspi_start_tx_dma(tqspi, t, len);
- if (ret < 0) {
- dev_err(tqspi->dev, "failed to starting TX DMA: %d\n", ret);
- return ret;
+ if ((tqspi->cur_direction & DATA_DIR_TX)) {
+ if (tqspi->tx_dma_chan) {
+ 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;
+ ret = dmaengine_slave_config(tqspi->tx_dma_chan, &dma_sconfig);
+ if (ret < 0) {
+ dev_err(tqspi->dev, "failed DMA slave config: %d\n", ret);
+ return ret;
+ }
+
+ tegra_qspi_copy_client_txbuf_to_qspi_txbuf(tqspi, t);
+ ret = tegra_qspi_start_tx_dma(tqspi, t, len);
+ if (ret < 0) {
+ dev_err(tqspi->dev, "failed to starting TX DMA: %d\n", ret);
+ return ret;
+ }
+ } else {
+ 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, lower_32_bits(tx_dma_phys),
+ QSPI_DMA_MEM_ADDRESS);
+ tegra_qspi_writel(tqspi, (upper_32_bits(tx_dma_phys) & 0xff),
+ QSPI_DMA_HI_ADDRESS);
}
}
if (tqspi->cur_direction & DATA_DIR_RX) {
- 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;
- ret = dmaengine_slave_config(tqspi->rx_dma_chan, &dma_sconfig);
- if (ret < 0) {
- dev_err(tqspi->dev, "failed DMA slave config: %d\n", ret);
- return ret;
- }
-
- dma_sync_single_for_device(tqspi->dev, tqspi->rx_dma_phys,
- tqspi->dma_buf_size,
- DMA_FROM_DEVICE);
+ if (tqspi->rx_dma_chan) {
+ 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;
+ ret = dmaengine_slave_config(tqspi->rx_dma_chan, &dma_sconfig);
+ if (ret < 0) {
+ dev_err(tqspi->dev, "failed DMA slave config: %d\n", ret);
+ return ret;
+ }
+ dma_sync_single_for_device(tqspi->dev, tqspi->rx_dma_phys,
+ tqspi->dma_buf_size, DMA_FROM_DEVICE);
+ ret = tegra_qspi_start_rx_dma(tqspi, t, len);
+ if (ret < 0) {
+ dev_err(tqspi->dev, "failed to start RX DMA: %d\n", ret);
+ if (tqspi->cur_direction & DATA_DIR_TX)
+ dmaengine_terminate_all(tqspi->tx_dma_chan);
+ return ret;
+ }
- ret = tegra_qspi_start_rx_dma(tqspi, t, len);
- if (ret < 0) {
- dev_err(tqspi->dev, "failed to start RX DMA: %d\n", ret);
- if (tqspi->cur_direction & DATA_DIR_TX)
- dmaengine_terminate_all(tqspi->tx_dma_chan);
- return ret;
+ } else {
+ if (tqspi->is_packed)
+ rx_dma_phys = t->rx_dma;
+ else
+ rx_dma_phys = tqspi->rx_dma_phys;
+
+ tegra_qspi_writel(tqspi, lower_32_bits(rx_dma_phys),
+ QSPI_DMA_MEM_ADDRESS);
+ tegra_qspi_writel(tqspi, (upper_32_bits(rx_dma_phys) & 0xff),
+ QSPI_DMA_HI_ADDRESS);
}
}
@@ -726,9 +759,6 @@ static int tegra_qspi_start_cpu_based_transfer(struct tegra_qspi *qspi, struct s
static void tegra_qspi_deinit_dma(struct tegra_qspi *tqspi)
{
- if (!tqspi->soc_data->has_dma)
- return;
-
if (tqspi->tx_dma_buf) {
dma_free_coherent(tqspi->dev, tqspi->dma_buf_size,
tqspi->tx_dma_buf, tqspi->tx_dma_phys);
@@ -759,16 +789,26 @@ static int tegra_qspi_init_dma(struct tegra_qspi *tqspi)
u32 *dma_buf;
int err;
- if (!tqspi->soc_data->has_dma)
- return 0;
+ if (tqspi->soc_data->has_ext_dma) {
+ dma_chan = dma_request_chan(tqspi->dev, "rx");
+ if (IS_ERR(dma_chan)) {
+ err = PTR_ERR(dma_chan);
+ goto err_out;
+ }
- 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) {
@@ -779,14 +819,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;
@@ -1056,6 +1088,7 @@ 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_ext_dma;
struct spi_transfer *xfer;
struct spi_device *spi = msg->spi;
u8 transfer_phase = 0;
@@ -1128,15 +1161,14 @@ 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 &&
- (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))
- dmaengine_terminate_all
- (tqspi->rx_dma_chan);
+ if (tqspi->is_curr_dma_xfer) {
+ if ((tqspi->cur_direction & DATA_DIR_TX) &&
+ tqspi->tx_dma_chan)
+ dmaengine_terminate_all(tqspi->tx_dma_chan);
+ if ((tqspi->cur_direction & DATA_DIR_RX) &&
+ tqspi->rx_dma_chan)
+ dmaengine_terminate_all(tqspi->rx_dma_chan);
+ }
/* Abort transfer by resetting pio/dma bit */
if (!tqspi->is_curr_dma_xfer) {
@@ -1197,6 +1229,7 @@ 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_ext_dma;
int ret = 0, val = 0;
msg->status = 0;
@@ -1251,10 +1284,12 @@ 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))
- dmaengine_terminate_all(tqspi->tx_dma_chan);
- if (tqspi->is_curr_dma_xfer && (tqspi->cur_direction & DATA_DIR_RX))
- dmaengine_terminate_all(tqspi->rx_dma_chan);
+ if (tqspi->is_curr_dma_xfer) {
+ if ((tqspi->cur_direction & DATA_DIR_TX) && tqspi->tx_dma_chan)
+ dmaengine_terminate_all(tqspi->tx_dma_chan);
+ if ((tqspi->cur_direction & DATA_DIR_RX) && tqspi->rx_dma_chan)
+ dmaengine_terminate_all(tqspi->rx_dma_chan);
+ }
tegra_qspi_handle_error(tqspi);
ret = -EIO;
goto complete_xfer;
@@ -1323,7 +1358,7 @@ static bool tegra_qspi_validate_cmb_seq(struct tegra_qspi *tqspi,
return false;
xfer = list_next_entry(xfer, transfer_list);
}
- if (!tqspi->soc_data->has_dma && xfer->len > (QSPI_FIFO_DEPTH << 2))
+ if (!tqspi->soc_data->has_ext_dma && xfer->len > (QSPI_FIFO_DEPTH << 2))
return false;
return true;
@@ -1384,41 +1419,43 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_qspi *tqspi)
unsigned int total_fifo_words;
unsigned long flags;
long wait_status;
- int err = 0;
+ int num_errors = 0;
if (tqspi->cur_direction & DATA_DIR_TX) {
if (tqspi->tx_status) {
- dmaengine_terminate_all(tqspi->tx_dma_chan);
- err += 1;
- } else {
+ if (tqspi->tx_dma_chan)
+ dmaengine_terminate_all(tqspi->tx_dma_chan);
+ num_errors++;
+ } else if (tqspi->tx_dma_chan) {
wait_status = wait_for_completion_interruptible_timeout(
&tqspi->tx_dma_complete, QSPI_DMA_TIMEOUT);
if (wait_status <= 0) {
dmaengine_terminate_all(tqspi->tx_dma_chan);
dev_err(tqspi->dev, "failed TX DMA transfer\n");
- err += 1;
+ num_errors++;
}
}
}
if (tqspi->cur_direction & DATA_DIR_RX) {
if (tqspi->rx_status) {
- dmaengine_terminate_all(tqspi->rx_dma_chan);
- err += 2;
- } else {
+ if (tqspi->rx_dma_chan)
+ dmaengine_terminate_all(tqspi->rx_dma_chan);
+ num_errors++;
+ } else if (tqspi->rx_dma_chan) {
wait_status = wait_for_completion_interruptible_timeout(
&tqspi->rx_dma_complete, QSPI_DMA_TIMEOUT);
if (wait_status <= 0) {
dmaengine_terminate_all(tqspi->rx_dma_chan);
dev_err(tqspi->dev, "failed RX DMA transfer\n");
- err += 2;
+ num_errors++;
}
}
}
spin_lock_irqsave(&tqspi->lock, flags);
- if (err) {
+ if (num_errors) {
tegra_qspi_dma_unmap_xfer(tqspi, t);
tegra_qspi_handle_error(tqspi);
complete(&tqspi->xfer_completion);
@@ -1444,9 +1481,9 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_qspi *tqspi)
/* continue transfer in current message */
total_fifo_words = tegra_qspi_calculate_curr_xfer_param(tqspi, t);
if (total_fifo_words > QSPI_FIFO_DEPTH)
- err = tegra_qspi_start_dma_based_transfer(tqspi, t);
+ num_errors = tegra_qspi_start_dma_based_transfer(tqspi, t);
else
- err = tegra_qspi_start_cpu_based_transfer(tqspi, t);
+ num_errors = tegra_qspi_start_cpu_based_transfer(tqspi, t);
exit:
spin_unlock_irqrestore(&tqspi->lock, flags);
@@ -1474,28 +1511,28 @@ 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_ext_dma = true,
.cmb_xfer_capable = false,
.supports_tpm = false,
.cs_count = 1,
};
static struct tegra_qspi_soc_data tegra186_qspi_soc_data = {
- .has_dma = true,
+ .has_ext_dma = true,
.cmb_xfer_capable = true,
.supports_tpm = false,
.cs_count = 1,
};
static struct tegra_qspi_soc_data tegra234_qspi_soc_data = {
- .has_dma = false,
+ .has_ext_dma = false,
.cmb_xfer_capable = true,
.supports_tpm = true,
.cs_count = 1,
};
static struct tegra_qspi_soc_data tegra241_qspi_soc_data = {
- .has_dma = false,
+ .has_ext_dma = true,
.cmb_xfer_capable = true,
.supports_tpm = true,
.cs_count = 4,
--
2.17.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v3 6/6] spi: tegra210-quad: Add support for internal DMA
2025-04-16 11:06 ` [PATCH v3 6/6] spi: tegra210-quad: Add support for internal DMA Vishwaroop A
@ 2025-04-16 11:57 ` Mukesh Kumar Savaliya
2025-04-16 12:23 ` Mark Brown
2025-04-16 14:08 ` Jon Hunter
2025-04-24 13:29 ` Mark Brown
1 sibling, 2 replies; 14+ messages in thread
From: Mukesh Kumar Savaliya @ 2025-04-16 11:57 UTC (permalink / raw)
To: Vishwaroop A, thierry.reding, jonathanh, skomatineni, ldewangan,
broonie, linux-spi, linux-tegra, linux-kernel, kyarlagadda,
smangipudi
On 4/16/2025 4:36 PM, Vishwaroop A wrote:
> Previous generations of Tegra supported DMA operations by an external
> DMA controller, but the QSPI on Tegra234 devices now have an internal
> DMA controller.
>
> Introduce routines to initialize and configure internal DMA channels
> for both transmit and receive paths. Set up DMA mapping functions to
> manage buffer addresses effectively.
>
> The variable err is changed to num_errors to more accurately represent
> its purpose in the code. The updated name clarifies that the variable
> tracks the number of errors encountered during execution, rather than
> serving as a generic error flag or code.
>
> Tegra241 device supports DMA via an external DMA controller (GPCDMA), so
> enable this.
>
> Signed-off-by: Vishwaroop A <va@nvidia.com>
> ---
> drivers/spi/spi-tegra210-quad.c | 227 +++++++++++++++++++-------------
> 1 file changed, 132 insertions(+), 95 deletions(-)
>
> diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c
> index 04f41e92c1e2..e80a0850d07e 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 0x028
> +#define QSPI_DMA_HI_ADDRESS 0x02c
> +
> #define QSPI_TX_FIFO 0x108
> #define QSPI_RX_FIFO 0x188
>
> @@ -167,9 +170,9 @@ enum tegra_qspi_transfer_type {
> };
>
> struct tegra_qspi_soc_data {
> - bool has_dma;
> bool cmb_xfer_capable;
> bool supports_tpm;
> + bool has_ext_dma;
> unsigned int cs_count;
> };
>
> @@ -605,17 +608,21 @@ 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_ext_dma;
>
> if (tqspi->is_packed) {
> ret = tegra_qspi_dma_map_xfer(tqspi, t);
> @@ -634,60 +641,86 @@ 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);
> }
>
> - 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) {
> - 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;
> - ret = dmaengine_slave_config(tqspi->tx_dma_chan, &dma_sconfig);
> - if (ret < 0) {
> - dev_err(tqspi->dev, "failed DMA slave config: %d\n", ret);
> - return ret;
> - }
>
> - tegra_qspi_copy_client_txbuf_to_qspi_txbuf(tqspi, t);
> - ret = tegra_qspi_start_tx_dma(tqspi, t, len);
> - if (ret < 0) {
> - dev_err(tqspi->dev, "failed to starting TX DMA: %d\n", ret);
> - return ret;
> + if ((tqspi->cur_direction & DATA_DIR_TX)) {
> + if (tqspi->tx_dma_chan) {
> + 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;
> + ret = dmaengine_slave_config(tqspi->tx_dma_chan, &dma_sconfig);
> + if (ret < 0) {
> + dev_err(tqspi->dev, "failed DMA slave config: %d\n", ret);
> + return ret;
> + }
> +
> + tegra_qspi_copy_client_txbuf_to_qspi_txbuf(tqspi, t);
> + ret = tegra_qspi_start_tx_dma(tqspi, t, len);
> + if (ret < 0) {
> + dev_err(tqspi->dev, "failed to starting TX DMA: %d\n", ret);
> + return ret;
> + }
> + } else {
> + 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, lower_32_bits(tx_dma_phys),
> + QSPI_DMA_MEM_ADDRESS);
> + tegra_qspi_writel(tqspi, (upper_32_bits(tx_dma_phys) & 0xff),
> + QSPI_DMA_HI_ADDRESS);
> }
> }
>
> if (tqspi->cur_direction & DATA_DIR_RX) {
> - 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;
> - ret = dmaengine_slave_config(tqspi->rx_dma_chan, &dma_sconfig);
> - if (ret < 0) {
> - dev_err(tqspi->dev, "failed DMA slave config: %d\n", ret);
> - return ret;
> - }
> -
> - dma_sync_single_for_device(tqspi->dev, tqspi->rx_dma_phys,
> - tqspi->dma_buf_size,
> - DMA_FROM_DEVICE);
> + if (tqspi->rx_dma_chan) {
> + 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;
> + ret = dmaengine_slave_config(tqspi->rx_dma_chan, &dma_sconfig);
> + if (ret < 0) {
> + dev_err(tqspi->dev, "failed DMA slave config: %d\n", ret);
> + return ret;
> + }
> + dma_sync_single_for_device(tqspi->dev, tqspi->rx_dma_phys,
> + tqspi->dma_buf_size, DMA_FROM_DEVICE);
> + ret = tegra_qspi_start_rx_dma(tqspi, t, len);
> + if (ret < 0) {
> + dev_err(tqspi->dev, "failed to start RX DMA: %d\n", ret);
> + if (tqspi->cur_direction & DATA_DIR_TX)
> + dmaengine_terminate_all(tqspi->tx_dma_chan);
> + return ret;
> + }
>
> - ret = tegra_qspi_start_rx_dma(tqspi, t, len);
> - if (ret < 0) {
> - dev_err(tqspi->dev, "failed to start RX DMA: %d\n", ret);
> - if (tqspi->cur_direction & DATA_DIR_TX)
> - dmaengine_terminate_all(tqspi->tx_dma_chan);
> - return ret;
> + } else {
> + if (tqspi->is_packed)
> + rx_dma_phys = t->rx_dma;
> + else
> + rx_dma_phys = tqspi->rx_dma_phys;
> +
> + tegra_qspi_writel(tqspi, lower_32_bits(rx_dma_phys),
> + QSPI_DMA_MEM_ADDRESS);
> + tegra_qspi_writel(tqspi, (upper_32_bits(rx_dma_phys) & 0xff),
> + QSPI_DMA_HI_ADDRESS);
> }
> }
>
> @@ -726,9 +759,6 @@ static int tegra_qspi_start_cpu_based_transfer(struct tegra_qspi *qspi, struct s
>
> static void tegra_qspi_deinit_dma(struct tegra_qspi *tqspi)
> {
> - if (!tqspi->soc_data->has_dma)
> - return;
> -
> if (tqspi->tx_dma_buf) {
> dma_free_coherent(tqspi->dev, tqspi->dma_buf_size,
> tqspi->tx_dma_buf, tqspi->tx_dma_phys);
> @@ -759,16 +789,26 @@ static int tegra_qspi_init_dma(struct tegra_qspi *tqspi)
> u32 *dma_buf;
> int err;
>
> - if (!tqspi->soc_data->has_dma)
> - return 0;
> + if (tqspi->soc_data->has_ext_dma) {
> + dma_chan = dma_request_chan(tqspi->dev, "rx");
> + if (IS_ERR(dma_chan)) {
> + err = PTR_ERR(dma_chan);
> + goto err_out;
> + }
>
> - 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) {
> @@ -779,14 +819,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;
> @@ -1056,6 +1088,7 @@ 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_ext_dma;
> struct spi_transfer *xfer;
> struct spi_device *spi = msg->spi;
> u8 transfer_phase = 0;
> @@ -1128,15 +1161,14 @@ 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 &&
> - (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))
> - dmaengine_terminate_all
> - (tqspi->rx_dma_chan);
> + if (tqspi->is_curr_dma_xfer) {
> + if ((tqspi->cur_direction & DATA_DIR_TX) &&
> + tqspi->tx_dma_chan)
> + dmaengine_terminate_all(tqspi->tx_dma_chan);
> + if ((tqspi->cur_direction & DATA_DIR_RX) &&
> + tqspi->rx_dma_chan)
> + dmaengine_terminate_all(tqspi->rx_dma_chan);
> + }
>
> /* Abort transfer by resetting pio/dma bit */
> if (!tqspi->is_curr_dma_xfer) {
> @@ -1197,6 +1229,7 @@ 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_ext_dma;
> int ret = 0, val = 0;
>
> msg->status = 0;
> @@ -1251,10 +1284,12 @@ 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))
> - dmaengine_terminate_all(tqspi->tx_dma_chan);
> - if (tqspi->is_curr_dma_xfer && (tqspi->cur_direction & DATA_DIR_RX))
> - dmaengine_terminate_all(tqspi->rx_dma_chan);
> + if (tqspi->is_curr_dma_xfer) {
> + if ((tqspi->cur_direction & DATA_DIR_TX) && tqspi->tx_dma_chan)
> + dmaengine_terminate_all(tqspi->tx_dma_chan);
> + if ((tqspi->cur_direction & DATA_DIR_RX) && tqspi->rx_dma_chan)
> + dmaengine_terminate_all(tqspi->rx_dma_chan);
> + }
> tegra_qspi_handle_error(tqspi);
> ret = -EIO;
> goto complete_xfer;
> @@ -1323,7 +1358,7 @@ static bool tegra_qspi_validate_cmb_seq(struct tegra_qspi *tqspi,
> return false;
> xfer = list_next_entry(xfer, transfer_list);
> }
> - if (!tqspi->soc_data->has_dma && xfer->len > (QSPI_FIFO_DEPTH << 2))
> + if (!tqspi->soc_data->has_ext_dma && xfer->len > (QSPI_FIFO_DEPTH << 2))
> return false;
>
> return true;
> @@ -1384,41 +1419,43 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_qspi *tqspi)
> unsigned int total_fifo_words;
> unsigned long flags;
> long wait_status;
> - int err = 0;
> + int num_errors = 0;
>
> if (tqspi->cur_direction & DATA_DIR_TX) {
> if (tqspi->tx_status) {
> - dmaengine_terminate_all(tqspi->tx_dma_chan);
> - err += 1;
> - } else {
> + if (tqspi->tx_dma_chan)
> + dmaengine_terminate_all(tqspi->tx_dma_chan);
> + num_errors++;
> + } else if (tqspi->tx_dma_chan) {
> wait_status = wait_for_completion_interruptible_timeout(
> &tqspi->tx_dma_complete, QSPI_DMA_TIMEOUT);
> if (wait_status <= 0) {
> dmaengine_terminate_all(tqspi->tx_dma_chan);
> dev_err(tqspi->dev, "failed TX DMA transfer\n");
> - err += 1;
> + num_errors++;
what do you do with incrementing this local num_errors ?
I don't see any post processing .
Also all are are mutually exclusive due to if/else, not sequential. So
could not get any specific usage.
> }
> }
> }
>
> if (tqspi->cur_direction & DATA_DIR_RX) {
> if (tqspi->rx_status) {
> - dmaengine_terminate_all(tqspi->rx_dma_chan);
> - err += 2;
> - } else {
> + if (tqspi->rx_dma_chan)
> + dmaengine_terminate_all(tqspi->rx_dma_chan);
> + num_errors++;
> + } else if (tqspi->rx_dma_chan) {
> wait_status = wait_for_completion_interruptible_timeout(
> &tqspi->rx_dma_complete, QSPI_DMA_TIMEOUT);
> if (wait_status <= 0) {
> dmaengine_terminate_all(tqspi->rx_dma_chan);
> dev_err(tqspi->dev, "failed RX DMA transfer\n");
> - err += 2;
> + num_errors++;
> }
> }
> }
>
> spin_lock_irqsave(&tqspi->lock, flags);
>
> - if (err) {
> + if (num_errors) {
> tegra_qspi_dma_unmap_xfer(tqspi, t);
> tegra_qspi_handle_error(tqspi);
> complete(&tqspi->xfer_completion);
> @@ -1444,9 +1481,9 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_qspi *tqspi)
> /* continue transfer in current message */
> total_fifo_words = tegra_qspi_calculate_curr_xfer_param(tqspi, t);
> if (total_fifo_words > QSPI_FIFO_DEPTH)
> - err = tegra_qspi_start_dma_based_transfer(tqspi, t);
> + num_errors = tegra_qspi_start_dma_based_transfer(tqspi, t);
> else
> - err = tegra_qspi_start_cpu_based_transfer(tqspi, t);
> + num_errors = tegra_qspi_start_cpu_based_transfer(tqspi, t);
>
> exit:
> spin_unlock_irqrestore(&tqspi->lock, flags);
> @@ -1474,28 +1511,28 @@ 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_ext_dma = true,
> .cmb_xfer_capable = false,
> .supports_tpm = false,
> .cs_count = 1,
> };
>
> static struct tegra_qspi_soc_data tegra186_qspi_soc_data = {
> - .has_dma = true,
> + .has_ext_dma = true,
> .cmb_xfer_capable = true,
> .supports_tpm = false,
> .cs_count = 1,
> };
>
> static struct tegra_qspi_soc_data tegra234_qspi_soc_data = {
> - .has_dma = false,
> + .has_ext_dma = false,
> .cmb_xfer_capable = true,
> .supports_tpm = true,
> .cs_count = 1,
> };
>
> static struct tegra_qspi_soc_data tegra241_qspi_soc_data = {
> - .has_dma = false,
> + .has_ext_dma = true,
> .cmb_xfer_capable = true,
> .supports_tpm = true,
> .cs_count = 4,
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH v3 6/6] spi: tegra210-quad: Add support for internal DMA
2025-04-16 11:57 ` Mukesh Kumar Savaliya
@ 2025-04-16 12:23 ` Mark Brown
2025-04-16 14:08 ` Jon Hunter
1 sibling, 0 replies; 14+ messages in thread
From: Mark Brown @ 2025-04-16 12:23 UTC (permalink / raw)
To: Mukesh Kumar Savaliya
Cc: Vishwaroop A, thierry.reding, jonathanh, skomatineni, ldewangan,
linux-spi, linux-tegra, linux-kernel, kyarlagadda, smangipudi
[-- Attachment #1: Type: text/plain, Size: 521 bytes --]
On Wed, Apr 16, 2025 at 05:27:47PM +0530, Mukesh Kumar Savaliya wrote:
>
>
> On 4/16/2025 4:36 PM, Vishwaroop A wrote:
> > Previous generations of Tegra supported DMA operations by an external
> > DMA controller, but the QSPI on Tegra234 devices now have an internal
> > DMA controller.
Please delete unneeded context from mails when replying. Doing this
makes it much easier to find your reply in the message, helping ensure
it won't be missed by people scrolling through the irrelevant quoted
material.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 6/6] spi: tegra210-quad: Add support for internal DMA
2025-04-16 11:57 ` Mukesh Kumar Savaliya
2025-04-16 12:23 ` Mark Brown
@ 2025-04-16 14:08 ` Jon Hunter
1 sibling, 0 replies; 14+ messages in thread
From: Jon Hunter @ 2025-04-16 14:08 UTC (permalink / raw)
To: Mukesh Kumar Savaliya, Vishwaroop A, thierry.reding, skomatineni,
ldewangan, broonie, linux-spi, linux-tegra, linux-kernel,
kyarlagadda, smangipudi
On 16/04/2025 12:57, Mukesh Kumar Savaliya wrote:
...
>> @@ -1384,41 +1419,43 @@ static irqreturn_t
>> handle_dma_based_xfer(struct tegra_qspi *tqspi)
>> unsigned int total_fifo_words;
>> unsigned long flags;
>> long wait_status;
>> - int err = 0;
>> + int num_errors = 0;
>> if (tqspi->cur_direction & DATA_DIR_TX) {
>> if (tqspi->tx_status) {
>> - dmaengine_terminate_all(tqspi->tx_dma_chan);
>> - err += 1;
>> - } else {
>> + if (tqspi->tx_dma_chan)
>> + dmaengine_terminate_all(tqspi->tx_dma_chan);
>> + num_errors++;
>> + } else if (tqspi->tx_dma_chan) {
>> wait_status = wait_for_completion_interruptible_timeout(
>> &tqspi->tx_dma_complete, QSPI_DMA_TIMEOUT);
>> if (wait_status <= 0) {
>> dmaengine_terminate_all(tqspi->tx_dma_chan);
>> dev_err(tqspi->dev, "failed TX DMA transfer\n");
>> - err += 1;
>> + num_errors++;
> what do you do with incrementing this local num_errors ?
> I don't see any post processing .
> Also all are are mutually exclusive due to if/else, not sequential. So
> could not get any specific usage.
This is really legacy code and yes I am not too thrilled with it either.
At the same time this change is simply making the variable name a bit
more clear. It is not critical that this is changed as part of this
patch, but does not hurt either. I don't have strong feelings on this.
Jon
--
nvpublic
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 6/6] spi: tegra210-quad: Add support for internal DMA
2025-04-16 11:06 ` [PATCH v3 6/6] spi: tegra210-quad: Add support for internal DMA Vishwaroop A
2025-04-16 11:57 ` Mukesh Kumar Savaliya
@ 2025-04-24 13:29 ` Mark Brown
1 sibling, 0 replies; 14+ messages in thread
From: Mark Brown @ 2025-04-24 13:29 UTC (permalink / raw)
To: Vishwaroop A
Cc: thierry.reding, jonathanh, skomatineni, ldewangan, linux-spi,
linux-tegra, linux-kernel, kyarlagadda, smangipudi
[-- Attachment #1: Type: text/plain, Size: 706 bytes --]
On Wed, Apr 16, 2025 at 11:06:06AM +0000, Vishwaroop A wrote:
> Previous generations of Tegra supported DMA operations by an external
> DMA controller, but the QSPI on Tegra234 devices now have an internal
> DMA controller.
This breaks an allmodconfig build:
/build/stage/linux/drivers/spi/spi-tegra210-quad.c:1091:7: error: unused variable 'has_ext_dma' [-Werror,-Wunused-variable]
1091 | bool has_ext_dma = tqspi->soc_data->has_ext_dma;
| ^~~~~~~~~~~
/build/stage/linux/drivers/spi/spi-tegra210-quad.c:1232:7: error: unused variable 'has_ext_dma' [-Werror,-Wunused-variable]
1232 | bool has_ext_dma = tqspi->soc_data->has_ext_dma;
| ^~~~~~~~~~~
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 0/6] Configure Clocks, Add Internal DMA support
2025-04-16 11:06 [PATCH v3 0/6] Configure Clocks, Add Internal DMA support Vishwaroop A
` (5 preceding siblings ...)
2025-04-16 11:06 ` [PATCH v3 6/6] spi: tegra210-quad: Add support for internal DMA Vishwaroop A
@ 2025-04-16 12:43 ` Rob Herring (Arm)
2025-04-25 23:00 ` (subset) " Mark Brown
7 siblings, 0 replies; 14+ messages in thread
From: Rob Herring (Arm) @ 2025-04-16 12:43 UTC (permalink / raw)
To: Vishwaroop A
Cc: linux-tegra, smangipudi, linux-spi, skomatineni, thierry.reding,
kyarlagadda, ldewangan, linux-kernel, broonie, jonathanh
On Wed, 16 Apr 2025 11:06:00 +0000, Vishwaroop A wrote:
> This series introduces QSPI clock configuration and internal DMA
> support for Quad SPI controller. The patches have been reorganized
> for better logical flow and review comments from v2 have been addressed.
>
> Vishwaroop A (6):
> spi: tegra210-quad: Fix X1_X2_X4 encoding and support x4 transfers
> spi: tegra210-quad: remove redundant error handling code
> spi: tegra210-quad: modify chip select (CS) deactivation
> arm64: tegra: Configure QSPI clocks and add DMA
> spi: tegra210-quad: Update dummy sequence configuration
> spi: tegra210-quad: Add support for internal DMA
>
> arch/arm64/boot/dts/nvidia/tegra234.dtsi | 10 +
> drivers/spi/spi-tegra210-quad.c | 282 +++++++++++++----------
> 2 files changed, 176 insertions(+), 116 deletions(-)
>
> ---
> v2 -> v3:
> * Reorganized the patches.
> * Addressed review comments received on the patches.
> ---
>
> --
> 2.17.1
>
>
>
My bot found new DTB warnings on the .dts files added or changed in this
series.
Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.
If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:
pip3 install dtschema --upgrade
This patch series was applied (using b4) to base:
Base: attempting to guess base-commit...
Base: tags/v6.15-rc2-1-g36ff6c3f5084 (exact match)
If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)
New warnings running 'make CHECK_DTBS=y for arch/arm64/boot/dts/nvidia/' for 20250416110606.2737315-1-va@nvidia.com:
arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0008.dtb: spi@3270000 (nvidia,tegra234-qspi): Unevaluated properties are not allowed ('iommus' was unexpected)
from schema $id: http://devicetree.org/schemas/spi/nvidia,tegra210-quad.yaml#
arch/arm64/boot/dts/nvidia/tegra234-p3768-0000+p3767-0000.dtb: spi@3270000 (nvidia,tegra234-qspi): Unevaluated properties are not allowed ('iommus' was unexpected)
from schema $id: http://devicetree.org/schemas/spi/nvidia,tegra210-quad.yaml#
arch/arm64/boot/dts/nvidia/tegra234-p3768-0000+p3767-0005.dtb: spi@3270000 (nvidia,tegra234-qspi): Unevaluated properties are not allowed ('iommus' was unexpected)
from schema $id: http://devicetree.org/schemas/spi/nvidia,tegra210-quad.yaml#
arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dtb: spi@3270000 (nvidia,tegra234-qspi): Unevaluated properties are not allowed ('iommus' was unexpected)
from schema $id: http://devicetree.org/schemas/spi/nvidia,tegra210-quad.yaml#
arch/arm64/boot/dts/nvidia/tegra234-p3740-0002+p3701-0008.dtb: spi@3270000 (nvidia,tegra234-qspi): Unevaluated properties are not allowed ('iommus' was unexpected)
from schema $id: http://devicetree.org/schemas/spi/nvidia,tegra210-quad.yaml#
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: (subset) [PATCH v3 0/6] Configure Clocks, Add Internal DMA support
2025-04-16 11:06 [PATCH v3 0/6] Configure Clocks, Add Internal DMA support Vishwaroop A
` (6 preceding siblings ...)
2025-04-16 12:43 ` [PATCH v3 0/6] Configure Clocks, Add Internal DMA support Rob Herring (Arm)
@ 2025-04-25 23:00 ` Mark Brown
7 siblings, 0 replies; 14+ messages in thread
From: Mark Brown @ 2025-04-25 23:00 UTC (permalink / raw)
To: thierry.reding, jonathanh, skomatineni, ldewangan, linux-spi,
linux-tegra, linux-kernel, kyarlagadda, smangipudi, Vishwaroop A
On Wed, 16 Apr 2025 11:06:00 +0000, Vishwaroop A wrote:
> This series introduces QSPI clock configuration and internal DMA
> support for Quad SPI controller. The patches have been reorganized
> for better logical flow and review comments from v2 have been addressed.
>
> Vishwaroop A (6):
> spi: tegra210-quad: Fix X1_X2_X4 encoding and support x4 transfers
> spi: tegra210-quad: remove redundant error handling code
> spi: tegra210-quad: modify chip select (CS) deactivation
> arm64: tegra: Configure QSPI clocks and add DMA
> spi: tegra210-quad: Update dummy sequence configuration
> spi: tegra210-quad: Add support for internal DMA
>
> [...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
Thanks!
[1/6] spi: tegra210-quad: Fix X1_X2_X4 encoding and support x4 transfers
commit: dcb06c638a1174008a985849fa30fc0da7d08904
[2/6] spi: tegra210-quad: remove redundant error handling code
commit: 400d9f1a27cc2fceabdb1ed93eaf0b89b6d32ba5
[3/6] spi: tegra210-quad: modify chip select (CS) deactivation
commit: d8966b65413390d1b5b706886987caac05fbe024
[5/6] spi: tegra210-quad: Update dummy sequence configuration
commit: c283fcdc4e2b89678c171691fd26f576139fc256
[6/6] spi: tegra210-quad: Add support for internal DMA
(no commit info)
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
^ permalink raw reply [flat|nested] 14+ messages in thread