[PATCH 3/9] dma: qcom: bam_dma: Fix command element mask field for BAM v1.6.0+

Md Sadre Alam posted 9 patches 1 week, 6 days ago
[PATCH 3/9] dma: qcom: bam_dma: Fix command element mask field for BAM v1.6.0+
Posted by Md Sadre Alam 1 week, 6 days ago
BAM version 1.6.0 and later changed the behavior of the mask field in
command elements for read operations. In newer BAM versions, the mask
field for read commands contains the upper 4 bits of the destination
address to support 36-bit addressing, while for write commands it
continues to function as a traditional write mask.

This change causes NAND enumeration failures on platforms like IPQ5424
that use BAM v1.6.0+, because the current code sets mask=0xffffffff
for all commands. For read commands on newer BAM versions, this results
in the hardware interpreting the destination address as 0xf_xxxxxxxx
(invalid high memory) instead of the intended 0x0_xxxxxxxx address.

Fixed this issue by:
1. Updating the bam_cmd_element structure documentation to reflect the
   dual purpose of the mask field
2. Modifying bam_prep_ce_le32() to set appropriate mask values based on
   command type:
   - For read commands: mask = 0 (32-bit addressing, upper bits = 0)
   - For write commands: mask = 0xffffffff (traditional write mask)
3. Maintaining backward compatibility with older BAM versions

This fix enables proper NAND functionality on IPQ5424 and other platforms
using BAM v1.6.0+ while preserving compatibility with existing systems.

Signed-off-by: Md Sadre Alam <quic_mdalam@quicinc.com>
---
 include/linux/dma/qcom_bam_dma.h | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/include/linux/dma/qcom_bam_dma.h b/include/linux/dma/qcom_bam_dma.h
index 68fc0e643b1b..d9d07a9ab313 100644
--- a/include/linux/dma/qcom_bam_dma.h
+++ b/include/linux/dma/qcom_bam_dma.h
@@ -13,9 +13,12 @@
  * supported by BAM DMA Engine.
  *
  * @cmd_and_addr - upper 8 bits command and lower 24 bits register address.
- * @data - for write command: content to be written into peripheral register.
- *	   for read command: dest addr to write peripheral register value.
- * @mask - register mask.
+ * @data - For write command: content to be written into peripheral register.
+ *	   For read command: lower 32 bits of destination address.
+ * @mask - For write command: register write mask.
+ *	   For read command on BAM v1.6.0+: upper 4 bits of destination address.
+ *	   For read command on BAM < v1.6.0: ignored by hardware.
+ *	   Setting to 0 ensures 32-bit addressing compatibility.
  * @reserved - for future usage.
  *
  */
@@ -42,6 +45,10 @@ enum bam_command_type {
  * @addr: target address
  * @cmd: BAM command
  * @data: actual data for write and dest addr for read in le32
+ *
+ * For BAM v1.6.0+, the mask field behavior depends on command type:
+ * - Write commands: mask = write mask (typically 0xffffffff)
+ * - Read commands: mask = upper 4 bits of destination address (0 for 32-bit)
  */
 static inline void
 bam_prep_ce_le32(struct bam_cmd_element *bam_ce, u32 addr,
@@ -50,7 +57,11 @@ bam_prep_ce_le32(struct bam_cmd_element *bam_ce, u32 addr,
 	bam_ce->cmd_and_addr =
 		cpu_to_le32((addr & 0xffffff) | ((cmd & 0xff) << 24));
 	bam_ce->data = data;
-	bam_ce->mask = cpu_to_le32(0xffffffff);
+	if (cmd == BAM_READ_COMMAND)
+		bam_ce->mask = cpu_to_le32(0x0); /* 32-bit addressing */
+	else
+		bam_ce->mask = cpu_to_le32(0xffffffff); /* Write mask */
+	bam_ce->reserved = 0;
 }
 
 /*
@@ -60,7 +71,7 @@ bam_prep_ce_le32(struct bam_cmd_element *bam_ce, u32 addr,
  * @bam_ce: BAM command element
  * @addr: target address
  * @cmd: BAM command
- * @data: actual data for write and dest addr for read
+ * @data: actual data for write and destination address for read
  */
 static inline void
 bam_prep_ce(struct bam_cmd_element *bam_ce, u32 addr,
-- 
2.34.1
Re: [PATCH 3/9] dma: qcom: bam_dma: Fix command element mask field for BAM v1.6.0+
Posted by Konrad Dybcio 1 week, 6 days ago
On 9/18/25 11:40 AM, Md Sadre Alam wrote:
> BAM version 1.6.0 and later changed the behavior of the mask field in
> command elements for read operations. In newer BAM versions, the mask
> field for read commands contains the upper 4 bits of the destination
> address to support 36-bit addressing, while for write commands it
> continues to function as a traditional write mask.

So the hardware can read from higher addresses but not write to them?

Plus, you didn't explain what the mask register does on BAM <1.6.0.
If it really masks the address, all reads will now point to 0x0

Konrad
Re: [PATCH 3/9] dma: qcom: bam_dma: Fix command element mask field for BAM v1.6.0+
Posted by Md Sadre Alam 1 week, 6 days ago

On 9/18/2025 3:57 PM, Konrad Dybcio wrote:
> On 9/18/25 11:40 AM, Md Sadre Alam wrote:
>> BAM version 1.6.0 and later changed the behavior of the mask field in
>> command elements for read operations. In newer BAM versions, the mask
>> field for read commands contains the upper 4 bits of the destination
>> address to support 36-bit addressing, while for write commands it
>> continues to function as a traditional write mask.
> 
> So the hardware can read from higher addresses but not write to them?
No,
Write Operations: Can target any 32-bit address in the peripheral 
address space (up to 4GB)

Read Operations: Can read from any 32-bit peripheral address and
place the data into 36-bit memory addresses (up to 64GB) starting
from BAM v1.6.0
> 
> Plus, you didn't explain what the mask register does on BAM <1.6.0.
> If it really masks the address, all reads will now point to 0x0
The mask field never masks addresses in any BAM version. Here's the 
complete specification:

BAM Command Element Structure

Write Command Elements (All BAM Versions):

| Field  | Bits  | Description                                         |
|--------|-------|-----------------------------------------------------|
| 1st DW | 31:24 | Command (must be 0 for write)                       |
|        | 23:0  | Address - target address in peripheral              |
|-----------------------------------------------------------------------
| 2nd DW | 31:0  | Data - the data to be written                       |
------------------------------------------------------------------------
| 3rd DW | 31:0  | Mask - 32-bit mask defining which bits to modify    |
-----------------------------------------------------------------------
| 4th DW | 31:0  | Reserved                                            |
------------------------------------------------------------------------

Read Command Elements (BAM < v1.6.0):

| Field  | Bits  | Description                                         |
|--------|-------|-----------------------------------------------------|
| 1st DW | 31:24 | Command (must be 1 for read)                        |
|        | 23:0  | Address - source address in peripheral              |
------------------------------------------------------------------------
| 2nd DW | 31:0  | Destination - memory address to write read-data     |
------------------------------------------------------------------------
| 3rd DW | 31:0  | Reserved (IGNORED by hardware)                      |
------------------------------------------------------------------------
| 4th DW | 31:0  | Reserved                                            |
------------------------------------------------------------------------

Read Command Elements (BAM >= v1.6.0):

| Field  | Bits  | Description                                         |
|--------|-------|-----------------------------------------------------|
| 1st DW | 31:24 | Command (must be 1 for read)                        |
|        | 23:0  | Address - source address in peripheral              |
------------------------------------------------------------------------
| 2nd DW | 31:0  | Destination - 32 LSBs of 36-bit destination addr    |
------------------------------------------------------------------------
| 3rd DW | 31:4  | Reserved                                            |
|        | 3:0   | Destination Address 4 MSBs (bits 35:32)             |
------------------------------------------------------------------------
| 4th DW | 31:0  | Reserved                                            |
------------------------------------------------------------------------

For Read Commands:
- BAM < v1.6.0: 3rd Dword completely ignored by hardware
- BAM >= v1.6.0: 3rd Dword[3:0] contains upper 4 bits of destination
address

Thanks,
Alam.
RE: [PATCH 3/9] dma: qcom: bam_dma: Fix command element mask field for BAM v1.6.0+
Posted by Lakshmi Sowjanya D (QUIC) 1 week, 1 day ago

> -----Original Message-----
> From: Md Sadre Alam <quic_mdalam@quicinc.com>
> Sent: Friday, September 19, 2025 11:27 AM
> To: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>;
> broonie@kernel.org; robh@kernel.org; krzk+dt@kernel.org;
> conor+dt@kernel.org; andersson@kernel.org; konradybcio@kernel.org;
> vkoul@kernel.org; linux-arm-msm@vger.kernel.org; linux-spi@vger.kernel.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> dmaengine@vger.kernel.org
> Cc: Varadarajan Narayanan (QUIC) <quic_varada@quicinc.com>
> Subject: Re: [PATCH 3/9] dma: qcom: bam_dma: Fix command element mask
> field for BAM v1.6.0+
> 
> 
> 
> On 9/18/2025 3:57 PM, Konrad Dybcio wrote:
> > On 9/18/25 11:40 AM, Md Sadre Alam wrote:
> >> BAM version 1.6.0 and later changed the behavior of the mask field in
> >> command elements for read operations. In newer BAM versions, the mask
> >> field for read commands contains the upper 4 bits of the destination
> >> address to support 36-bit addressing, while for write commands it
> >> continues to function as a traditional write mask.
> >
> > So the hardware can read from higher addresses but not write to them?
> No,
> Write Operations: Can target any 32-bit address in the peripheral address
> space (up to 4GB)
> 
> Read Operations: Can read from any 32-bit peripheral address and place the
> data into 36-bit memory addresses (up to 64GB) starting from BAM v1.6.0
> >
> > Plus, you didn't explain what the mask register does on BAM <1.6.0.
> > If it really masks the address, all reads will now point to 0x0
> The mask field never masks addresses in any BAM version. Here's the
> complete specification:
> 
> BAM Command Element Structure
> 
> Write Command Elements (All BAM Versions):
> 
> | Field  | Bits  | Description                                         |
> |--------|-------|-----------------------------------------------------|
> | 1st DW | 31:24 | Command (must be 0 for write)                       |
> |        | 23:0  | Address - target address in peripheral              |
> |-----------------------------------------------------------------------
> | 2nd DW | 31:0  | Data - the data to be written                       |
> ------------------------------------------------------------------------
> | 3rd DW | 31:0  | Mask - 32-bit mask defining which bits to modify    |
> -----------------------------------------------------------------------
> | 4th DW | 31:0  | Reserved                                            |
> ------------------------------------------------------------------------
> 
> Read Command Elements (BAM < v1.6.0):
> 
> | Field  | Bits  | Description                                         |
> |--------|-------|-----------------------------------------------------|
> | 1st DW | 31:24 | Command (must be 1 for read)                        |
> |        | 23:0  | Address - source address in peripheral              |
> ------------------------------------------------------------------------
> | 2nd DW | 31:0  | Destination - memory address to write read-data     |
> ------------------------------------------------------------------------
> | 3rd DW | 31:0  | Reserved (IGNORED by hardware)                      |
> ------------------------------------------------------------------------
> | 4th DW | 31:0  | Reserved                                            |
> ------------------------------------------------------------------------
> 
> Read Command Elements (BAM >= v1.6.0):
> 
> | Field  | Bits  | Description                                         |
> |--------|-------|-----------------------------------------------------|
> | 1st DW | 31:24 | Command (must be 1 for read)                        |
> |        | 23:0  | Address - source address in peripheral              |
> ------------------------------------------------------------------------
> | 2nd DW | 31:0  | Destination - 32 LSBs of 36-bit destination addr    |
> ------------------------------------------------------------------------
> | 3rd DW | 31:4  | Reserved                                            |
> |        | 3:0   | Destination Address 4 MSBs (bits 35:32)             |
> ------------------------------------------------------------------------
> | 4th DW | 31:0  | Reserved                                            |
> ------------------------------------------------------------------------
> 
> For Read Commands:
> - BAM < v1.6.0: 3rd Dword completely ignored by hardware
> - BAM >= v1.6.0: 3rd Dword[3:0] contains upper 4 bits of destination address
> 
> Thanks,
> Alam.

Tested-by: Lakshmi Sowjanya D <quic_laksd@quicinc.com>  # on SDX75

Thanks,
Lakshmi Sowjanya