blackfin: bf60x: add dma support
authorBob Liu <lliubbo@gmail.com>
Thu, 16 Aug 2012 03:19:08 +0000 (11:19 +0800)
committersonic <sonic@sonic-linuxvm.(none)>
Mon, 4 Mar 2013 05:42:06 +0000 (13:42 +0800)
Add dma support for bf60x.

Signed-off-by: Bob Liu <lliubbo@gmail.com>
Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
Signed-off-by: Sonic Zhang <sonic.adi@gmail.com>
arch/blackfin/include/asm/dma.h
arch/blackfin/include/asm/mach-common/bits/dma.h
arch/blackfin/lib/string.c

index 21ff1cf..ef1db6e 100644 (file)
@@ -8,7 +8,12 @@
 #ifndef _BLACKFIN_DMA_H_
 #define _BLACKFIN_DMA_H_
 
+#include <linux/types.h>
+#ifdef __ADSPBF60x__
+#include <asm/mach-common/bits/dde.h>
+#else
 #include <asm/mach-common/bits/dma.h>
+#endif
 
 struct dmasg_large {
        void *next_desc_addr;
@@ -30,46 +35,70 @@ struct dmasg {
 } __attribute__((packed));
 
 struct dma_register {
+#ifdef __ADSPBF60x__
+       void *next_desc_ptr;    /* DMA Next Descriptor Pointer register */
+       u32 start_addr;         /* DMA Start address  register */
+       u32 config;             /* DMA Configuration register */
+
+       u32 x_count;            /* DMA x_count register */
+       s32 x_modify;           /* DMA x_modify register */
+       u32 y_count;            /* DMA y_count register */
+       s32 y_modify;           /* DMA y_modify register */
+       u32 __pad0[2];
+
+       void *curr_desc_ptr;    /* DMA Curr Descriptor Pointer register */
+       void *prev_desc_ptr;    /* DMA Prev Descriptor Pointer register */
+       void *curr_addr;        /* DMA Current Address Pointer register */
+       u32 status;             /* DMA irq status register */
+       u32 curr_x_count;       /* DMA Current x-count register */
+       u32 curr_y_count;       /* DMA Current y-count register */
+       u32 __pad1[2];
+
+       u32 bw_limit;           /* DMA Bandwidth Limit Count */
+       u32 curr_bw_limit;      /* DMA curr Bandwidth Limit Count */
+       u32 bw_monitor;         /* DMA Bandwidth Monitor Count */
+       u32 curr_bw_monitor;    /* DMA curr Bandwidth Monitor Count */
+#else
        void *next_desc_ptr;    /* DMA Next Descriptor Pointer register */
-       unsigned long start_addr;       /* DMA Start address  register */
+       u32 start_addr;         /* DMA Start address  register */
 
-       unsigned short cfg;     /* DMA Configuration register */
-       unsigned short dummy1;  /* DMA Configuration register */
+       u16 config;             /* DMA Configuration register */
+       u16 dummy1;             /* DMA Configuration register */
 
-       unsigned long reserved;
+       u32 reserved;
 
-       unsigned short x_count; /* DMA x_count register */
-       unsigned short dummy2;
+       u16 x_count;            /* DMA x_count register */
+       u16 dummy2;
 
-       short x_modify; /* DMA x_modify register */
-       unsigned short dummy3;
+       s16 x_modify;           /* DMA x_modify register */
+       u16 dummy3;
 
-       unsigned short y_count; /* DMA y_count register */
-       unsigned short dummy4;
+       u16 y_count;            /* DMA y_count register */
+       u16 dummy4;
 
-       short y_modify; /* DMA y_modify register */
-       unsigned short dummy5;
+       s16 y_modify;           /* DMA y_modify register */
+       u16 dummy5;
 
-       void *curr_desc_ptr;    /* DMA Current Descriptor Pointer
-                                          register */
-       unsigned long curr_addr_ptr;    /* DMA Current Address Pointer
-                                                  register */
-       unsigned short irq_status;      /* DMA irq status register */
-       unsigned short dummy6;
+       void *curr_desc_ptr;    /* DMA Current Descriptor Pointer register */
 
-       unsigned short peripheral_map;  /* DMA peripheral map register */
-       unsigned short dummy7;
+       u32 curr_addr_ptr;      /* DMA Current Address Pointer register */
 
-       unsigned short curr_x_count;    /* DMA Current x-count register */
-       unsigned short dummy8;
+       u16 status;             /* DMA irq status register */
+       u16 dummy6;
 
-       unsigned long reserved2;
+       u16 peripheral_map;     /* DMA peripheral map register */
+       u16 dummy7;
 
-       unsigned short curr_y_count;    /* DMA Current y-count register */
-       unsigned short dummy9;
+       u16 curr_x_count;       /* DMA Current x-count register */
+       u16 dummy8;
 
-       unsigned long reserved3;
+       u32 reserved2;
 
+       u16 curr_y_count;       /* DMA Current y-count register */
+       u16 dummy9;
+
+       u32 reserved3;
+#endif
 };
 
 #endif
index 136313e..ac426ad 100644 (file)
@@ -9,14 +9,54 @@
 #define DMAEN                  0x0001  /* DMA Channel Enable */
 #define WNR                    0x0002  /* Channel Direction (W/R*) */
 #define WDSIZE_8               0x0000  /* Transfer Word Size = 8 */
+
+#ifdef CONFIG_BF60x
+
+#define PSIZE_8                        0x00000000      /* Transfer Word Size = 16 */
+#define PSIZE_16               0x00000010      /* Transfer Word Size = 16 */
+#define PSIZE_32               0x00000020      /* Transfer Word Size = 32 */
+#define PSIZE_64               0x00000030      /* Transfer Word Size = 32 */
+#define WDSIZE_16              0x00000100      /* Transfer Word Size = 16 */
+#define WDSIZE_32              0x00000200      /* Transfer Word Size = 32 */
+#define WDSIZE_64              0x00000300      /* Transfer Word Size = 32 */
+#define WDSIZE_128             0x00000400      /* Transfer Word Size = 32 */
+#define WDSIZE_256             0x00000500      /* Transfer Word Size = 32 */
+#define DMA2D                  0x04000000      /* DMA Mode (2D/1D*) */
+#define RESTART                        0x00000004      /* DMA Buffer Clear SYNC */
+#define DI_EN_X                        0x00100000      /* Data Int Enable in X count */
+#define DI_EN_Y                        0x00200000      /* Data Int Enable in Y count */
+#define DI_EN_P                        0x00300000      /* Data Int Enable in Peri */
+#define DI_EN                  DI_EN_X         /* Data Int Enable */
+#define NDSIZE_0               0x00000000      /* Next Desc Size = 0 */
+#define NDSIZE_1               0x00010000      /* Next Desc Size = 1 */
+#define NDSIZE_2               0x00020000      /* Next Desc Size = 2 */
+#define NDSIZE_3               0x00030000      /* Next Desc Size = 3 */
+#define NDSIZE_4               0x00040000      /* Next Desc Size = 4 */
+#define NDSIZE_5               0x00050000      /* Next Desc Size = 5 */
+#define NDSIZE_6               0x00060000      /* Next Desc Size = 6 */
+#define NDSIZE                 0x00070000      /* Next Desc Size */
+#define NDSIZE_OFFSET          16              /* Next Desc Size Offset */
+#define DMAFLOW_LIST           0x00004000      /* Desc List Mode */
+#define DMAFLOW_ARRAY          0x00005000      /* Desc Array Mode */
+#define DMAFLOW_LIST_DEMAND    0x00006000      /* Desc Demand List Mode */
+#define DMAFLOW_ARRAY_DEMAND   0x00007000      /* Desc Demand Array Mode */
+#define DMA_RUN_DFETCH         0x00000100      /* DMA Channel Run (DFETCH) */
+#define DMA_RUN                        0x00000200      /* DMA Channel Run */
+#define DMA_RUN_WAIT_TRIG      0x00000300      /* DMA Channel Run (WAIT TRIG)*/
+#define DMA_RUN_WAIT_ACK       0x00000400      /* DMA Channel Run (WAIT ACK) */
+
+#else
+
 #define WDSIZE_16              0x0004  /* Transfer Word Size = 16 */
 #define WDSIZE_32              0x0008  /* Transfer Word Size = 32 */
+#define PSIZE_16               WDSIZE_16
+#define PSIZE_32               WDSIZE_32
 #define DMA2D                  0x0010  /* DMA Mode (2D/1D*) */
 #define RESTART                        0x0020  /* DMA Buffer Clear */
 #define DI_SEL                 0x0040  /* Data Interrupt Timing Select */
 #define DI_EN                  0x0080  /* Data Interrupt Enable */
 #define NDSIZE                 0x0F00  /* Next Descriptor bitmask */
-#define NDSIZE_0               0x0000  /* Next Descriptor Size = 0 (Stop/Autobuffer) */
+#define NDSIZE_0               0x0000  /* Next Descriptor Size = 0 */
 #define NDSIZE_1               0x0100  /* Next Descriptor Size = 1 */
 #define NDSIZE_2               0x0200  /* Next Descriptor Size = 2 */
 #define NDSIZE_3               0x0300  /* Next Descriptor Size = 3 */
 #define NDSIZE_7               0x0700  /* Next Descriptor Size = 7 */
 #define NDSIZE_8               0x0800  /* Next Descriptor Size = 8 */
 #define NDSIZE_9               0x0900  /* Next Descriptor Size = 9 */
-#define FLOW_STOP              0x0000  /* Stop Mode */
-#define FLOW_AUTO              0x1000  /* Autobuffer Mode */
 #define FLOW_ARRAY             0x4000  /* Descriptor Array Mode */
 #define FLOW_SMALL             0x6000  /* Small Model Descriptor List Mode */
 #define FLOW_LARGE             0x7000  /* Large Model Descriptor List Mode */
 
 #define DMAEN_P                        0       /* Channel Enable */
 #define WNR_P                  1       /* Channel Direction (W/R*) */
+#define WDSIZE_P               2       /* Transfer Word Size */
 #define DMA2D_P                        4       /* 2D/1D* Mode */
 #define RESTART_P              5       /* Restart */
 #define DI_SEL_P               6       /* Data Interrupt Select */
 #define DFETCH                 0x0004  /* DMA Descriptor Fetch Indicator */
 #define DMA_RUN                        0x0008  /* DMA Channel Running Indicator */
 
+#endif
+#define DMAFLOW                        0x7000  /* Flow Control */
+#define FLOW_STOP              0x0000  /* Stop Mode */
+#define FLOW_AUTO              0x1000  /* Autobuffer Mode */
+
 #define DMA_DONE_P             0       /* DMA Done Indicator */
 #define DMA_ERR_P              1       /* DMA Error Indicator */
 #define DFETCH_P               2       /* Descriptor Fetch Indicator */
 #define DMA_RUN_P              3       /* DMA Running Indicator */
 
 /* DMAx_PERIPHERAL_MAP, MDMA_yy_PERIPHERAL_MAP Masks */
-#define CTYPE                  0x0040  /* DMA Channel Type Indicator (Memory/Peripheral*) */
-#define CTYPE_P                        6       /* DMA Channel Type Indicator BIT POSITION */
+#define CTYPE                  0x0040  /* DMA Channel Type (Mem/Peri) */
+#define CTYPE_P                        6       /* DMA Channel Type BIT POSITION */
 #define PMAP                   0xF000  /* Peripheral Mapped To This Channel */
 
 #endif
index e344d3b..44d8c6d 100644 (file)
@@ -29,7 +29,7 @@
 #include <config.h>
 #include <asm/blackfin.h>
 #include <asm/io.h>
-#include <asm/mach-common/bits/dma.h>
+#include <asm/dma.h>
 
 char *strcpy(char *dest, const char *src)
 {
@@ -117,81 +117,88 @@ int strncmp(const char *cs, const char *ct, size_t count)
        return __res1;
 }
 
-#ifdef bfin_write_MDMA1_D0_IRQ_STATUS
-# define bfin_write_MDMA_D0_IRQ_STATUS bfin_write_MDMA1_D0_IRQ_STATUS
-# define bfin_write_MDMA_D0_START_ADDR bfin_write_MDMA1_D0_START_ADDR
-# define bfin_write_MDMA_D0_X_COUNT    bfin_write_MDMA1_D0_X_COUNT
-# define bfin_write_MDMA_D0_X_MODIFY   bfin_write_MDMA1_D0_X_MODIFY
-# define bfin_write_MDMA_D0_CONFIG     bfin_write_MDMA1_D0_CONFIG
-# define bfin_write_MDMA_S0_START_ADDR bfin_write_MDMA1_S0_START_ADDR
-# define bfin_write_MDMA_S0_X_COUNT    bfin_write_MDMA1_S0_X_COUNT
-# define bfin_write_MDMA_S0_X_MODIFY   bfin_write_MDMA1_S0_X_MODIFY
-# define bfin_write_MDMA_S0_CONFIG     bfin_write_MDMA1_S0_CONFIG
-# define bfin_write_MDMA_D0_IRQ_STATUS bfin_write_MDMA1_D0_IRQ_STATUS
-# define bfin_read_MDMA_D0_IRQ_STATUS  bfin_read_MDMA1_D0_IRQ_STATUS
+#ifdef MDMA1_D0_NEXT_DESC_PTR
+# define MDMA_D0_NEXT_DESC_PTR MDMA1_D0_NEXT_DESC_PTR
+# define MDMA_S0_NEXT_DESC_PTR MDMA1_S0_NEXT_DESC_PTR
 #endif
+
+static void dma_calc_size(unsigned long ldst, unsigned long lsrc, size_t count,
+                       unsigned long *dshift, unsigned long *bpos)
+{
+       unsigned long limit;
+
+#ifdef MSIZE
+       limit = 6;
+       *dshift = MSIZE_P;
+#else
+       limit = 3;
+       *dshift = WDSIZE_P;
+#endif
+
+       *bpos = min(limit, ffs(ldst | lsrc | count)) - 1;
+}
+
 /* This version misbehaves for count values of 0 and 2^16+.
  * Perhaps we should detect that ?  Nowhere do we actually
  * use dma memcpy for those types of lengths though ...
  */
 void dma_memcpy_nocache(void *dst, const void *src, size_t count)
 {
-       uint16_t wdsize, mod;
+       struct dma_register *mdma_d0 = (void *)MDMA_D0_NEXT_DESC_PTR;
+       struct dma_register *mdma_s0 = (void *)MDMA_S0_NEXT_DESC_PTR;
+       unsigned long ldst = (unsigned long)dst;
+       unsigned long lsrc = (unsigned long)src;
+       unsigned long dshift, bpos;
+       uint32_t dsize, mod;
 
        /* Disable DMA in case it's still running (older u-boot's did not
         * always turn them off).  Do it before the if statement below so
         * we can be cheap and not do a SSYNC() due to the forced abort.
         */
-       bfin_write_MDMA_D0_CONFIG(0);
-       bfin_write_MDMA_S0_CONFIG(0);
-       bfin_write_MDMA_D0_IRQ_STATUS(DMA_RUN | DMA_DONE | DMA_ERR);
+       bfin_write(&mdma_d0->config, 0);
+       bfin_write(&mdma_s0->config, 0);
+       bfin_write(&mdma_d0->status, DMA_RUN | DMA_DONE | DMA_ERR);
 
        /* Scratchpad cannot be a DMA source or destination */
-       if (((unsigned long)src >= L1_SRAM_SCRATCH &&
-            (unsigned long)src < L1_SRAM_SCRATCH_END) ||
-           ((unsigned long)dst >= L1_SRAM_SCRATCH &&
-            (unsigned long)dst < L1_SRAM_SCRATCH_END))
+       if ((lsrc >= L1_SRAM_SCRATCH && lsrc < L1_SRAM_SCRATCH_END) ||
+           (ldst >= L1_SRAM_SCRATCH && ldst < L1_SRAM_SCRATCH_END))
                hang();
 
-       if (((unsigned long)dst | (unsigned long)src | count) & 0x1) {
-               wdsize = WDSIZE_8;
-               mod = 1;
-       } else if (((unsigned long)dst | (unsigned long)src | count) & 0x2) {
-               wdsize = WDSIZE_16;
-               count >>= 1;
-               mod = 2;
-       } else {
-               wdsize = WDSIZE_32;
-               count >>= 2;
-               mod = 4;
-       }
+       dma_calc_size(ldst, lsrc, count, &dshift, &bpos);
+       dsize = bpos << dshift;
+       count >>= bpos;
+       mod = 1 << bpos;
+
+#ifdef PSIZE
+       dsize |= min(3, bpos) << PSIZE_P;
+#endif
 
        /* Copy sram functions from sdram to sram */
        /* Setup destination start address */
-       bfin_write_MDMA_D0_START_ADDR(dst);
+       bfin_write(&mdma_d0->start_addr, ldst);
        /* Setup destination xcount */
-       bfin_write_MDMA_D0_X_COUNT(count);
+       bfin_write(&mdma_d0->x_count, count);
        /* Setup destination xmodify */
-       bfin_write_MDMA_D0_X_MODIFY(mod);
+       bfin_write(&mdma_d0->x_modify, mod);
 
        /* Setup Source start address */
-       bfin_write_MDMA_S0_START_ADDR(src);
+       bfin_write(&mdma_s0->start_addr, lsrc);
        /* Setup Source xcount */
-       bfin_write_MDMA_S0_X_COUNT(count);
+       bfin_write(&mdma_s0->x_count, count);
        /* Setup Source xmodify */
-       bfin_write_MDMA_S0_X_MODIFY(mod);
+       bfin_write(&mdma_s0->x_modify, mod);
 
        /* Enable source DMA */
-       bfin_write_MDMA_S0_CONFIG(wdsize | DMAEN);
-       bfin_write_MDMA_D0_CONFIG(wdsize | DMAEN | WNR | DI_EN);
+       bfin_write(&mdma_s0->config, dsize | DMAEN);
+       bfin_write(&mdma_d0->config, dsize | DMAEN | WNR | DI_EN);
        SSYNC();
 
-       while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE))
+       while (!(bfin_read(&mdma_d0->status) & DMA_DONE))
                continue;
 
-       bfin_write_MDMA_D0_IRQ_STATUS(DMA_RUN | DMA_DONE | DMA_ERR);
-       bfin_write_MDMA_D0_CONFIG(0);
-       bfin_write_MDMA_S0_CONFIG(0);
+       bfin_write(&mdma_d0->status, DMA_RUN | DMA_DONE | DMA_ERR);
+       bfin_write(&mdma_d0->config, 0);
+       bfin_write(&mdma_s0->config, 0);
 }
 /* We should do a dcache invalidate on the destination after the dma, but since
  * we lack such hardware capability, we'll flush/invalidate the destination