]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
dmaengine: mmp_pdma: Add SpacemiT K1 PDMA support with 64-bit addressing
authorGuodong Xu <guodong@riscstar.com>
Fri, 22 Aug 2025 03:06:31 +0000 (11:06 +0800)
committerVinod Koul <vkoul@kernel.org>
Tue, 2 Sep 2025 07:07:42 +0000 (12:37 +0530)
Add support for SpacemiT K1 PDMA controller which features 64-bit
addressing capabilities.

The SpacemiT K1 PDMA extends the descriptor format with additional
32-bit words for high address bits, enabling access to memory beyond
4GB boundaries. The new spacemit_k1_pdma_ops provides necessary 64-bit
address handling functions and k1 specific controller configurations.

Key changes:
- Add ARCH_SPACEMIT dependency to Kconfig
- Define new high 32-bit address registers (DDADRH, DSADRH, DTADRH)
- Add DCSR_LPAEEN bit for Long Physical Address Extension Enable
- Implement 64-bit operations for SpacemiT K1 PDMA

Signed-off-by: Guodong Xu <guodong@riscstar.com>
Link: https://lore.kernel.org/r/20250822-working_dma_0701_v2-v5-5-f5c0eda734cc@riscstar.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/Kconfig
drivers/dma/mmp_pdma.c

index 05c7c7d9e5a4e52a8ad7ada8c8b9b1a6f9d875f6..b8a74b1798ba1d44b26553990428c065de6fc535 100644 (file)
@@ -450,7 +450,7 @@ config MILBEAUT_XDMAC
 
 config MMP_PDMA
        tristate "MMP PDMA support"
-       depends on ARCH_MMP || ARCH_PXA || COMPILE_TEST
+       depends on ARCH_MMP || ARCH_PXA || ARCH_SPACEMIT || COMPILE_TEST
        select DMA_ENGINE
        help
          Support the MMP PDMA engine for PXA and MMP platform.
index 38d1a4cdfd0e92e53c77b61caa1133559ef40dbd..d07229a748868b8115892c63c54c16130d88e326 100644 (file)
@@ -28,6 +28,9 @@
 #define DDADR(n)       (0x0200 + ((n) << 4))
 #define DSADR(n)       (0x0204 + ((n) << 4))
 #define DTADR(n)       (0x0208 + ((n) << 4))
+#define DDADRH(n)      (0x0300 + ((n) << 4))
+#define DSADRH(n)      (0x0304 + ((n) << 4))
+#define DTADRH(n)      (0x0308 + ((n) << 4))
 #define DCMD           0x020c
 
 #define DCSR_RUN       BIT(31) /* Run Bit (read / write) */
@@ -44,6 +47,7 @@
 #define DCSR_EORSTOPEN BIT(26) /* STOP on an EOR */
 #define DCSR_SETCMPST  BIT(25) /* Set Descriptor Compare Status */
 #define DCSR_CLRCMPST  BIT(24) /* Clear Descriptor Compare Status */
+#define DCSR_LPAEEN    BIT(21) /* Long Physical Address Extension Enable */
 #define DCSR_CMPST     BIT(10) /* The Descriptor Compare Status */
 #define DCSR_EORINTR   BIT(9)  /* The end of Receive */
 
@@ -76,6 +80,16 @@ struct mmp_pdma_desc_hw {
        u32 dsadr;      /* DSADR value for the current transfer */
        u32 dtadr;      /* DTADR value for the current transfer */
        u32 dcmd;       /* DCMD value for the current transfer */
+       /*
+        * The following 32-bit words are only used in the 64-bit, ie.
+        * LPAE (Long Physical Address Extension) mode.
+        * They are used to specify the high 32 bits of the descriptor's
+        * addresses.
+        */
+       u32 ddadrh;     /* High 32-bit of DDADR */
+       u32 dsadrh;     /* High 32-bit of DSADR */
+       u32 dtadrh;     /* High 32-bit of DTADR */
+       u32 rsvd;       /* reserved */
 } __aligned(32);
 
 struct mmp_pdma_desc_sw {
@@ -222,6 +236,57 @@ static u64 get_desc_dst_addr_32(const struct mmp_pdma_desc_hw *desc)
        return desc->dtadr;
 }
 
+/* For 64-bit PDMA */
+static void write_next_addr_64(struct mmp_pdma_phy *phy, dma_addr_t addr)
+{
+       writel(lower_32_bits(addr), phy->base + DDADR(phy->idx));
+       writel(upper_32_bits(addr), phy->base + DDADRH(phy->idx));
+}
+
+static u64 read_src_addr_64(struct mmp_pdma_phy *phy)
+{
+       u32 low = readl(phy->base + DSADR(phy->idx));
+       u32 high = readl(phy->base + DSADRH(phy->idx));
+
+       return ((u64)high << 32) | low;
+}
+
+static u64 read_dst_addr_64(struct mmp_pdma_phy *phy)
+{
+       u32 low = readl(phy->base + DTADR(phy->idx));
+       u32 high = readl(phy->base + DTADRH(phy->idx));
+
+       return ((u64)high << 32) | low;
+}
+
+static void set_desc_next_addr_64(struct mmp_pdma_desc_hw *desc, dma_addr_t addr)
+{
+       desc->ddadr = lower_32_bits(addr);
+       desc->ddadrh = upper_32_bits(addr);
+}
+
+static void set_desc_src_addr_64(struct mmp_pdma_desc_hw *desc, dma_addr_t addr)
+{
+       desc->dsadr = lower_32_bits(addr);
+       desc->dsadrh = upper_32_bits(addr);
+}
+
+static void set_desc_dst_addr_64(struct mmp_pdma_desc_hw *desc, dma_addr_t addr)
+{
+       desc->dtadr = lower_32_bits(addr);
+       desc->dtadrh = upper_32_bits(addr);
+}
+
+static u64 get_desc_src_addr_64(const struct mmp_pdma_desc_hw *desc)
+{
+       return ((u64)desc->dsadrh << 32) | desc->dsadr;
+}
+
+static u64 get_desc_dst_addr_64(const struct mmp_pdma_desc_hw *desc)
+{
+       return ((u64)desc->dtadrh << 32) | desc->dtadr;
+}
+
 static int mmp_pdma_config_write(struct dma_chan *dchan,
                                 struct dma_slave_config *cfg,
                                 enum dma_transfer_direction direction);
@@ -1110,10 +1175,26 @@ static const struct mmp_pdma_ops marvell_pdma_v1_ops = {
        .dma_mask = 0,                  /* let OF/platform set DMA mask */
 };
 
+static const struct mmp_pdma_ops spacemit_k1_pdma_ops = {
+       .write_next_addr = write_next_addr_64,
+       .read_src_addr = read_src_addr_64,
+       .read_dst_addr = read_dst_addr_64,
+       .set_desc_next_addr = set_desc_next_addr_64,
+       .set_desc_src_addr = set_desc_src_addr_64,
+       .set_desc_dst_addr = set_desc_dst_addr_64,
+       .get_desc_src_addr = get_desc_src_addr_64,
+       .get_desc_dst_addr = get_desc_dst_addr_64,
+       .run_bits = (DCSR_RUN | DCSR_LPAEEN),
+       .dma_mask = DMA_BIT_MASK(64),   /* force 64-bit DMA addr capability */
+};
+
 static const struct of_device_id mmp_pdma_dt_ids[] = {
        {
                .compatible = "marvell,pdma-1.0",
                .data = &marvell_pdma_v1_ops
+       }, {
+               .compatible = "spacemit,k1-pdma",
+               .data = &spacemit_k1_pdma_ops
        }, {
                /* sentinel */
        }