diff mbox series

[U-Boot,1/5] drivers: dma: Enable DMA-330 driver support

Message ID 1527754134-164985-2-git-send-email-tien.fong.chee@intel.com
State Deferred
Delegated to: Tom Rini
Headers show
Series Add DMA driver for DMA330 controller | expand

Commit Message

Chee, Tien Fong May 31, 2018, 8:08 a.m. UTC
From: Tien Fong Chee <tien.fong.chee@intel.com>

Enable DMAC driver support for DMA-330 controller.
The driver is also compatible to PL330 product.

Signed-off-by: Tien Fong Chee <tien.fong.chee@intel.com>
---
 drivers/dma/Kconfig  |    9 +-
 drivers/dma/Makefile |    1 +
 drivers/dma/dma330.c | 1514 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/dma330.h     |  136 +++++
 4 files changed, 1659 insertions(+), 1 deletion(-)
 create mode 100644 drivers/dma/dma330.c
 create mode 100644 include/dma330.h

Comments

Simon Glass June 1, 2018, 2:24 p.m. UTC | #1
Hi Tien,

On 31 May 2018 at 02:08,  <tien.fong.chee@intel.com> wrote:
> From: Tien Fong Chee <tien.fong.chee@intel.com>
>
> Enable DMAC driver support for DMA-330 controller.
> The driver is also compatible to PL330 product.
>
> Signed-off-by: Tien Fong Chee <tien.fong.chee@intel.com>
> ---
>  drivers/dma/Kconfig  |    9 +-
>  drivers/dma/Makefile |    1 +
>  drivers/dma/dma330.c | 1514 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/dma330.h     |  136 +++++
>  4 files changed, 1659 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/dma/dma330.c
>  create mode 100644 include/dma330.h
>
> diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
> index 4ee6afa..6e77e07 100644
> --- a/drivers/dma/Kconfig
> +++ b/drivers/dma/Kconfig
> @@ -2,7 +2,7 @@ menu "DMA Support"
>
>  config DMA
>         bool "Enable Driver Model for DMA drivers"
> -       depends on DM
> +       depends on DM || SPL_DM
>         help
>           Enable driver model for DMA. DMA engines can do
>           asynchronous data transfers without involving the host
> @@ -34,4 +34,11 @@ config APBH_DMA_BURST8
>
>  endif
>
> +config DMA330_DMA
> +       bool "PL330/DMA-330 DMA Controller(DMAC) driver"
> +       depends on DMA
> +       help
> +        Enable the DMA controller driver for both PL330 and
> +        DMA-330 products.
> +
>  endmenu # menu "DMA Support"
> diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
> index 4eaef8a..bfad0dd 100644
> --- a/drivers/dma/Makefile
> +++ b/drivers/dma/Makefile
> @@ -11,3 +11,4 @@ obj-$(CONFIG_FSL_DMA) += fsl_dma.o
>  obj-$(CONFIG_TI_KSNAV) += keystone_nav.o keystone_nav_cfg.o
>  obj-$(CONFIG_TI_EDMA3) += ti-edma3.o
>  obj-$(CONFIG_DMA_LPC32XX) += lpc32xx_dma.o
> +obj-$(CONFIG_DMA330_DMA) += dma330.o
> diff --git a/drivers/dma/dma330.c b/drivers/dma/dma330.c
> new file mode 100644
> index 0000000..66575d8
> --- /dev/null
> +++ b/drivers/dma/dma330.c
> @@ -0,0 +1,1514 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2018 Intel Corporation <www.intel.com>
> + */
> +
> +#include <common.h>
> +#include <asm/io.h>
> +#include <dma330.h>
> +#include <dm.h>
> +#include <fdtdec.h>
> +#include <wait_bit.h>
> +#include <linux/unaligned/access_ok.h>
> +
> +/* Register and Bit field Definitions */
> +
> +/* DMA Status */
> +#define DS                     0x0
> +#define DS_ST_STOP             0x0
> +#define DS_ST_EXEC             0x1
> +#define DS_ST_CMISS            0x2
> +#define DS_ST_UPDTPC           0x3
> +#define DS_ST_WFE              0x4
> +#define DS_ST_ATBRR            0x5
> +#define DS_ST_QBUSY            0x6
> +#define DS_ST_WFP              0x7
> +#define DS_ST_KILL             0x8
> +#define DS_ST_CMPLT            0x9
> +#define DS_ST_FLTCMP           0xe
> +#define DS_ST_FAULT            0xf

It is possible to use enum for some of these?

enum {
   DS             = 0,
   DS_ST_STOP,
 ...
}

> +
> +/* DMA Program Count register */
> +#define DPC                    0x4
> +/* Interrupt Enable register */
> +#define INTEN                  0x20
> +/* event-Interrupt Raw Status register */
> +#define ES                     0x24
> +/* Interrupt Status register */
> +#define INTSTATUS              0x28
> +/* Interrupt Clear register */
> +#define INTCLR                 0x2c
> +/* Fault Status DMA Manager register */
> +#define FSM                    0x30
> +/* Fault Status DMA Channel register */
> +#define FSC                    0x34
> +/* Fault Type DMA Manager register */
> +#define FTM                    0x38
> +
> +/* Fault Type DMA Channel register */
> +#define _FTC                   0x40
> +#define FTC(n)                 (_FTC + (n) * 0x4)
> +
> +/* Channel Status register */
> +#define _CS                    0x100
> +#define CS(n)                  (_CS + (n) * 0x8)
> +#define CS_CNS                 BIT(21)
> +
> +/* Channel Program Counter register */
> +#define _CPC                   0x104
> +#define CPC(n)                 (_CPC + (n) * 0x8)
> +
> +/* Source Address register */
> +#define _SA                    0x400
> +#define SA(n)                  (_SA + (n) * 0x20)
> +
> +/* Destination Address register */
> +#define _DA                    0x404
> +#define DA(n)                  (_DA + (n) * 0x20)
> +
> +/* Channel Control register */
> +#define _CC                    0x408
> +#define CC(n)                  (_CC + (n) * 0x20)
> +
> +/* Channel Control register (CCR) Setting */
> +#define CC_SRCINC              BIT(0)
> +#define CC_DSTINC              BIT(14)
> +#define CC_SRCPRI              BIT(8)
> +#define CC_DSTPRI              BIT(22)
> +#define CC_SRCNS               BIT(9)
> +#define CC_DSTNS               BIT(23)
> +#define CC_SRCIA               BIT(10)
> +#define CC_DSTIA               BIT(24)
> +#define CC_SRCBRSTLEN_SHFT     4
> +#define CC_DSTBRSTLEN_SHFT     18
> +#define CC_SRCBRSTSIZE_SHFT    1
> +#define CC_DSTBRSTSIZE_SHFT    15
> +#define CC_SRCCCTRL_SHFT       11
> +#define CC_SRCCCTRL_MASK       0x7

Can you make the mask a shifted mask? Then it is easier to use in
clrsetbits_le32(), for example.

e.g.

#define CC_SRCCCTRL_MASK (7 << CC_SRCCCTRL_SHFT)

> +#define CC_DSTCCTRL_SHFT       25
> +#define CC_DRCCCTRL_MASK       0x7
> +#define CC_SWAP_SHFT           28
> +
> +/* Loop Counter 0 register */
> +#define _LC0                   0x40c
> +#define LC0(n)                 (_LC0 + (n) * 0x20)
> +
> +/* Loop Counter 1 register */
> +#define _LC1                   0x410
> +#define LC1(n)                 (_LC1 + (n) * 0x20)
> +
> +/* Debug Status register */
> +#define DBGSTATUS              0xd00
> +#define DBG_BUSY               BIT(0)
> +
> +/* Debug Command register */
> +#define DBGCMD                 0xd04
> +/* Debug Instruction 0 register */
> +#define DBGINST0               0xd08
> +/* Debug Instruction 1 register */
> +#define DBGINST1               0xd0c
> +
> +/* Configuration register */
> +#define CR0                    0xe00
> +#define CR1                    0xe04
> +#define CR2                    0xe08
> +#define CR3                    0xe0c
> +#define CR4                    0xe10
> +#define CRD                    0xe14
> +
> +/* Peripheral Identification register */
> +#define PERIPH_ID              0xfe0
> +/* Component Identification register */
> +#define PCELL_ID               0xff0
> +
> +/* Configuration register value */
> +#define CR0_PERIPH_REQ_SET     BIT(0)
> +#define CR0_BOOT_EN_SET                BIT(1)
> +#define CR0_BOOT_MAN_NS                BIT(2)
> +#define CR0_NUM_CHANS_SHIFT    4
> +#define CR0_NUM_CHANS_MASK     0x7
> +#define CR0_NUM_PERIPH_SHIFT   12
> +#define CR0_NUM_PERIPH_MASK    0x1f
> +#define CR0_NUM_EVENTS_SHIFT   17
> +#define CR0_NUM_EVENTS_MASK    0x1f
> +
> +/* Configuration register value */
> +#define CR1_ICACHE_LEN_SHIFT           0
> +#define CR1_ICACHE_LEN_MASK            0x7
> +#define CR1_NUM_ICACHELINES_SHIFT      4
> +#define CR1_NUM_ICACHELINES_MASK       0xf
> +
> +/* Configuration register value */
> +#define CRD_DATA_WIDTH_SHIFT   0
> +#define CRD_DATA_WIDTH_MASK    0x7
> +#define CRD_WR_CAP_SHIFT       4
> +#define CRD_WR_CAP_MASK                0x7
> +#define CRD_WR_Q_DEP_SHIFT     8
> +#define CRD_WR_Q_DEP_MASK      0xf
> +#define CRD_RD_CAP_SHIFT       12
> +#define CRD_RD_CAP_MASK                0x7
> +#define CRD_RD_Q_DEP_SHIFT     16
> +#define CRD_RD_Q_DEP_MASK      0xf
> +#define CRD_DATA_BUFF_SHIFT    20
> +#define CRD_DATA_BUFF_MASK     0x3ff
> +
> +/* Microcode opcode value */
> +#define CMD_DMAADDH            0x54
> +#define CMD_DMAEND             0x00
> +#define CMD_DMAFLUSHP          0x35
> +#define CMD_DMAGO              0xa0
> +#define CMD_DMALD              0x04
> +#define CMD_DMALDP             0x25
> +#define CMD_DMALP              0x20
> +#define CMD_DMALPEND           0x28
> +#define CMD_DMAKILL            0x01
> +#define CMD_DMAMOV             0xbc
> +#define CMD_DMANOP             0x18
> +#define CMD_DMARMB             0x12
> +#define CMD_DMASEV             0x34
> +#define CMD_DMAST              0x08
> +#define CMD_DMASTP             0x29
> +#define CMD_DMASTZ             0x0c
> +#define CMD_DMAWFE             0x36
> +#define CMD_DMAWFP             0x30
> +#define CMD_DMAWMB             0x13
> +
> +/* the size of opcode plus opcode required settings */
> +#define SZ_DMAADDH             3
> +#define SZ_DMAEND              1
> +#define SZ_DMAFLUSHP           2
> +#define SZ_DMALD               1
> +#define SZ_DMALDP              2
> +#define SZ_DMALP               2
> +#define SZ_DMALPEND            2
> +#define SZ_DMAKILL             1
> +#define SZ_DMAMOV              6
> +#define SZ_DMANOP              1
> +#define SZ_DMARMB              1
> +#define SZ_DMASEV              2
> +#define SZ_DMAST               1
> +#define SZ_DMASTP              2
> +#define SZ_DMASTZ              1
> +#define SZ_DMAWFE              2
> +#define SZ_DMAWFP              2
> +#define SZ_DMAWMB              1
> +#define SZ_DMAGO               6
> +
> +/* Use this _only_ to wait on transient states */
> +#define UNTIL(t, s)    do { \
> +                               WATCHDOG_RESET(); \
> +                       } while (!(dma330_getstate(t) & (s)))
> +
> +/* debug message printout */
> +#ifdef DEBUG
> +#define DMA330_DBGCMD_DUMP(off, x...)  do { \
> +                                               printf("%x bytes:", off); \
> +                                               printf(x); \
> +                                               WATCHDOG_RESET(); \
> +                                       } while (0)
> +#else
> +#define DMA330_DBGCMD_DUMP(off, x...)  do {} while (0)
> +#endif

Can DMA330_DBGCMD_DUMP be a static function, and lower case? It's only
used in one file, right?

> +
> +/* Enum declaration */

We know that :-)

Can you please add comments explaining what these enums are for, and
what the values mean?

> +enum dmamov_dst {
> +       SAR = 0,
> +       CCR,
> +       DAR,
> +};
> +
> +enum dma330_dst {
> +       SRC = 0,
> +       DST,
> +};
> +
> +enum dma330_cond {
> +       SINGLE,
> +       BURST,
> +       ALWAYS,
> +};
> +
> +/* Structure will be used by _emit_lpend function */
> +struct _arg_lpend {
> +       enum dma330_cond cond;
> +       int forever;
> +       u32 loop;
> +       u8 bjump;
> +};
> +
> +/* Structure will be used by _emit_go function */
> +struct _arg_go {

Please drop the _ on these struct names, and document the members here.

> +       u8 chan;
> +       u32 addr;
> +       u32 ns;
> +};
> +
> +/*
> + * _emit_end - Add opcode DMAEND into microcode (end).
> + *
> + * @buf: The buffer which stored the microcode program.
> + *
> + * Return: Size of opcode.
> + */
> +static inline u32 _emit_end(u8 buf[])

Why is everything inline? The compiler will do it automatically when
there is only one caller. Other than that, it just increases code size
I think.

> +{
> +       buf[0] = CMD_DMAEND;
> +       DMA330_DBGCMD_DUMP(SZ_DMAEND, "\tDMAEND\n");
> +       return SZ_DMAEND;
> +}
> +
> +/*
> + * _emit_flushp - Add opcode DMAFLUSHP into microcode (flush peripheral).
> + *
> + * @buf -> The buffer which stored the microcode program.
> + * @peri -> Peripheral ID as listed in DMA NPP.
> + *
> + * Return: Size of opcode.
> + */
> +static inline u32 _emit_flushp(u8 buf[], u8 peri)
> +{
> +       u8 *buffer = buf;
> +
> +       buffer[0] = CMD_DMAFLUSHP;
> +       peri &= 0x1f;
> +       peri <<= 3;

These should be enums too so we don't have open-coded values in the
code, Please check throughout.

> +       buffer[1] = peri;
> +       DMA330_DBGCMD_DUMP(SZ_DMAFLUSHP, "\tDMAFLUSHP %u\n", peri >> 3);
> +       return SZ_DMAFLUSHP;
> +}
> +
> +/**
> + * _emit_ld - Add opcode DMALD into microcode (load).
> + *
> + * @buf: The buffer which stored the microcode program.
> + * @cond: Execution criteria such as single, burst or always.
> + *
> + * Return: Size of opcode.
> + */
> +static inline u32 _emit_ld(u8 buf[], enum dma330_cond cond)
> +{
> +       buf[0] = CMD_DMALD;
> +       if (cond == SINGLE)
> +               buf[0] |= (0 << 1) | (1 << 0);

More open-coded things

> +       else if (cond == BURST)
> +               buf[0] |= (1 << 1) | (1 << 0);
> +       DMA330_DBGCMD_DUMP(SZ_DMALD, "\tDMALD%c\n",
> +                         cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A'));
> +       return SZ_DMALD;
> +}
> +
> +/**
> + * _emit_lp - Add opcode DMALP into microcode (loop).
> + *
> + * @buf: The buffer which stored the microcode program.
> + * @loop: Selection of using counter 0 or 1  (valid value 0 or 1).
> + * @cnt: number of iteration (valid value 1-256).
> + *
> + * Return: Size of opcode.
> + */
> +static inline u32 _emit_lp(u8 buf[], u32 loop, u32 cnt)
> +{
> +       u8 *buffer = buf;
> +
> +       buffer[0] = CMD_DMALP;
> +       if (loop)
> +               buffer[0] |= (1 << 1);
> +       /* DMAC increments by 1 internally */
> +       cnt--;
> +       buffer[1] = cnt;
> +       DMA330_DBGCMD_DUMP(SZ_DMALP, "\tDMALP_%c %u\n", loop ? '1' : '0', cnt);
> +       return SZ_DMALP;
> +}
> +
> +/**
> + * _emit_lpend - Add opcode DMALPEND into microcode (loop end).
> + *
> + * @buf: The buffer which stored the microcode program.
> + * @arg: Structure _arg_lpend which contain all needed info.
> + *     arg->cond -> Execution criteria such as single, burst or always
> + *     arg->forever -> Forever loop? used if DMALPFE started the loop
> + *     arg->bjump -> Backwards jump (relative location of
> + *                   1st instruction in the loop.

The members of the struct should be documented in the struct above, not here.

> + *
> + * Return: Size of opcode.
> + */
> +static inline u32 _emit_lpend(u8 buf[], const struct _arg_lpend *arg)
> +{
> +       u8 *buffer = buf;
> +       enum dma330_cond cond = arg->cond;
> +       int forever = arg->forever;
> +       u32 loop = arg->loop;
> +       u8 bjump = arg->bjump;

Why have these? Can you not use arg-bjump, etc., directly?

> +
> +       buffer[0] = CMD_DMALPEND;
> +       if (loop)
> +               buffer[0] |= (1 << 2);

More open-coded things

> +       if (!forever)
> +               buffer[0] |= (1 << 4);
> +       if (cond == SINGLE)
> +               buffer[0] |= (0 << 1) | (1 << 0);
> +       else if (cond == BURST)
> +               buffer[0] |= (1 << 1) | (1 << 0);
> +
> +       buffer[1] = bjump;
> +       DMA330_DBGCMD_DUMP(SZ_DMALPEND, "\tDMALP%s%c_%c bjmpto_%x\n",
> +                         forever ? "FE" : "END",
> +                         cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A'),
> +                         loop ? '1' : '0',
> +                         bjump);
> +       return SZ_DMALPEND;
> +}
> +
> +/**
> + * _emit_kill - Add opcode DMAKILL into microcode (kill).
> + *
> + * @buf: The buffer which stored the microcode program.
> + *
> + * Return: Size of opcode.
> + */
> +static inline u32 _emit_kill(u8 buf[])
> +{
> +       buf[0] = CMD_DMAKILL;
> +       return SZ_DMAKILL;
> +}
> +
> +/**
> + * _emit_mov - Add opcode DMAMOV into microcode (move).
> + *
> + * @buf: The buffer which stored the microcode program.
> + * @dst: Destination register (valid value SAR[0b000], DAR[0b010],
> + *      or CCR[0b001]).
> + * @val: 32bit value that to be written into destination register.
> + *
> + * Return: Size of opcode.
> + */
> +static inline u32 _emit_mov(u8 buf[], enum dmamov_dst dst, u32 val)
> +{
> +       u8 *buffer = buf;
> +
> +       buffer[0] = CMD_DMAMOV;
> +       buffer[1] = dst;
> +       buffer[2] = val & 0xFF;
> +       buffer[3] = (val >> 8) & 0xFF;
> +       buffer[4] = (val >> 16) & 0xFF;
> +       buffer[5] = (val >> 24) & 0xFF;

Can you use put_unaligned_le32() ? Also check the same thing below.


> +       DMA330_DBGCMD_DUMP(SZ_DMAMOV, "\tDMAMOV %s 0x%x\n",
> +                         dst == SAR ? "SAR" : (dst == DAR ? "DAR" : "CCR"),
> +                          val);
> +       return SZ_DMAMOV;
> +}
> +
> +/**
> + * _emit_nop - Add opcode DMANOP into microcode (no operation).
> + *
> + * @buf: The buffer which stored the microcode program.
> + *
> + * Return: Size of opcode.
> + */
> +static inline u32 _emit_nop(u8 buf[])
> +{
> +       buf[0] = CMD_DMANOP;
> +       DMA330_DBGCMD_DUMP(SZ_DMANOP, "\tDMANOP\n");

please add a blank line before 'return'

> +       return SZ_DMANOP;
> +}
> +
> +/**
> + * _emit_rmb - Add opcode DMARMB into microcode (read memory barrier).
> + *
> + * @buf: The buffer which stored the microcode program.
> + *
> + * Return: Size of opcode.
> + */
> +static inline u32 _emit_rmb(u8 buf[])
> +{
> +       buf[0] = CMD_DMARMB;
> +       DMA330_DBGCMD_DUMP(SZ_DMARMB, "\tDMARMB\n");
> +       return SZ_DMARMB;
> +}
> +
> +/**
> + * _emit_sev - Add opcode DMASEV into microcode (send event).
> + *
> + * @buf: The buffer which stored the microcode program.
> + * @ev: The event number (valid 0 - 31).
> + *
> + * Return: Size of opcode.
> + */
> +static inline u32 _emit_sev(u8 buf[], u8 ev)
> +{
> +       u8 *buffer = buf;
> +
> +       buffer[0] = CMD_DMASEV;
> +       ev &= 0x1f;
> +       ev <<= 3;
> +       buffer[1] = ev;
> +       DMA330_DBGCMD_DUMP(SZ_DMASEV, "\tDMASEV %u\n", ev >> 3);
> +       return SZ_DMASEV;
> +}
> +
> +/**
> + * _emit_st - Add opcode DMAST into microcode (store).
> + *
> + * @buf: The buffer which stored the microcode program.
> + * @cond: Execution criteria such as single, burst or always.
> + *
> + * Return: Size of opcode.
> + */
> +static inline u32 _emit_st(u8 buf[], enum dma330_cond cond)
> +{
> +       buf[0] = CMD_DMAST;
> +       if (cond == SINGLE)
> +               buf[0] |= (0 << 1) | (1 << 0);
> +       else if (cond == BURST)
> +               buf[0] |= (1 << 1) | (1 << 0);
> +
> +       DMA330_DBGCMD_DUMP(SZ_DMAST, "\tDMAST%c\n",
> +               cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A'));
> +       return SZ_DMAST;
> +}
> +
> +/**
> + * _emit_stp - Add opcode DMASTP into microcode (store and notify peripheral).
> + *
> + * @buf: The buffer which stored the microcode program.
> + * @cond: Execution criteria such as single, burst or always.
> + * @peri: Peripheral ID as listed in DMA NPP.
> + *
> + * Return: Size of opcode.
> + */
> +static inline u32 _emit_stp(u8 buf[], enum dma330_cond cond, u8 peri)
> +{
> +       u8 *buffer = buf;
> +
> +       buffer[0] = CMD_DMASTP;
> +       if (cond == BURST)
> +               buf[0] |= (1 << 1);
> +       peri &= 0x1f;
> +       peri <<= 3;
> +       buffer[1] = peri;
> +       DMA330_DBGCMD_DUMP(SZ_DMASTP, "\tDMASTP%c %u\n",
> +               cond == SINGLE ? 'S' : 'B', peri >> 3);
> +       return SZ_DMASTP;
> +}
> +
> +/**
> + * _emit_stz - Add opcode DMASTZ into microcode (store zeros).
> + *
> + * @buf -> The buffer which stored the microcode program.
> + *
> + * Return: Size of opcode.
> + */
> +static inline u32 _emit_stz(u8 buf[])
> +{
> +       buf[0] = CMD_DMASTZ;
> +       DMA330_DBGCMD_DUMP(SZ_DMASTZ, "\tDMASTZ\n");
> +       return SZ_DMASTZ;
> +}
> +
> +/**
> + * _emit_wfp - Add opcode DMAWFP into microcode (wait for peripheral).
> + *
> + * @buf: The buffer which stored the microcode program.
> + * @cond: Execution criteria such as single, burst or always.
> + * @peri: Peripheral ID as listed in DMA NPP.
> + *
> + * Return: Size of opcode.
> + */
> +static inline u32 _emit_wfp(u8 buf[], enum dma330_cond cond, u8 peri)
> +{
> +       u8 *buffer = buf;
> +
> +       buffer[0] = CMD_DMAWFP;
> +       if (cond == SINGLE)
> +               buffer[0] |= (0 << 1) | (0 << 0);
> +       else if (cond == BURST)
> +               buffer[0] |= (1 << 1) | (0 << 0);
> +       else
> +               buffer[0] |= (0 << 1) | (1 << 0);

Perhaps these three values are the same for each command? If so, the
three expressions (0, 1, 2) could go in an enum.

> +
> +       peri &= 0x1f;
> +       peri <<= 3;
> +       buffer[1] = peri;
> +       DMA330_DBGCMD_DUMP(SZ_DMAWFP, "\tDMAWFP%c %u\n",
> +               cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'P'), peri >> 3);
> +       return SZ_DMAWFP;
> +}
> +
> +/**
> + * _emit_wmb - Add opcode DMAWMB into microcode (write memory barrier).
> + *
> + * @buf: The buffer which stored the microcode program.
> + *
> + * Return: Size of opcode.
> + */
> +static inline u32 _emit_wmb(u8 buf[])
> +{
> +       buf[0] = CMD_DMAWMB;
> +       DMA330_DBGCMD_DUMP(SZ_DMAWMB, "\tDMAWMB\n");
> +       return SZ_DMAWMB;
> +}
> +
> +/**
> + * _emit_go - Add opcode DMALGO into microcode (go).
> + *
> + * @buf: The buffer which stored the microcode program.
> + * @arg: structure _arg_go which contain all needed info
> + *     arg->chan -> channel number
> + *     arg->addr -> start address of the microcode program
> + *                  which will be wrote into CPC register
> + *     arg->ns -> 1 for non secure, 0 for secure
> + *                (if only DMA Manager is in secure).
> + *
> + * Return: Size of opcode.
> + */
> +static inline u32 _emit_go(u8 buf[], const struct _arg_go *arg)
> +{
> +       u8 *buffer = buf;
> +       u8 chan = arg->chan;
> +       u32 addr = arg->addr;
> +       u32 ns = arg->ns;

These local vars seem pointless as the are only used once. Maybe it's
worth it for 'addr', but even there you should use the put_unaligned
thing.
> +
> +       buffer[0] = CMD_DMAGO;
> +       buffer[0] |= (ns << 1);
> +       buffer[1] = chan & 0x7;
> +       buf[2] = addr & 0xFF;
> +       buf[3] = (addr >> 8) & 0xFF;
> +       buf[4] = (addr >> 16) & 0xFF;
> +       buf[5] = (addr >> 24) & 0xFF;
> +       return SZ_DMAGO;
> +}
> +
> +/**
> + * _prepare_ccr - Populate the CCR register.
> + * @rqc: Request Configuration.
> + *
> + * Return: Channel Control register (CCR) Setting.
> + */
> +static inline u32 _prepare_ccr(const struct dma330_reqcfg *rqc)
> +{
> +       u32 ccr = 0;
> +
> +       if (rqc->src_inc)
> +               ccr |= CC_SRCINC;
> +       if (rqc->dst_inc)
> +               ccr |= CC_DSTINC;
> +
> +       /* We set same protection levels for Src and DST for now */
> +       if (rqc->privileged)
> +               ccr |= CC_SRCPRI | CC_DSTPRI;
> +       if (rqc->nonsecure)
> +               ccr |= CC_SRCNS | CC_DSTNS;
> +       if (rqc->insnaccess)
> +               ccr |= CC_SRCIA | CC_DSTIA;
> +
> +       ccr |= (((rqc->brst_len - 1) & 0xf) << CC_SRCBRSTLEN_SHFT);
> +       ccr |= (((rqc->brst_len - 1) & 0xf) << CC_DSTBRSTLEN_SHFT);
> +
> +       ccr |= (rqc->brst_size << CC_SRCBRSTSIZE_SHFT);
> +       ccr |= (rqc->brst_size << CC_DSTBRSTSIZE_SHFT);
> +
> +       ccr |= (rqc->scctl << CC_SRCCCTRL_SHFT);
> +       ccr |= (rqc->dcctl << CC_DSTCCTRL_SHFT);

You don't need the outer brackets on these.

> +
> +       ccr |= (rqc->swap << CC_SWAP_SHFT);
> +       return ccr;
> +}
> +
> +/**
> + * dma330_until_dmac_idle - Wait until DMA Manager is idle.
> + *
> + * @plat: Pointer to struct dma_dma330_platdata.
> + * @timeout_ms: Timeout (in miliseconds).
> + *
> + * Return: Negative value for error / timeout ocurred before idle,
> + *        0 for successful.
> + */
> +static int dma330_until_dmac_idle(struct dma_dma330_platdata *plat,
> +                                 const u32 timeout_ms)
> +{
> +       void __iomem *regs = plat->base;
> +
> +       return wait_for_bit(__func__,
> +                           (const u32 *)(uintptr_t)(regs + DBGSTATUS),
> +                           DBG_BUSY, 0, timeout_ms, false);
> +}
> +
> +/**
> + * dma330_execute_dbginsn - Execute debug instruction such as DMAGO and DMAKILL.
> + *
> + * @insn: The buffer which stored the debug instruction.
> + * @plat: Pointer to struct dma_dma330_platdata.
> + * @timeout_ms: Timeout (in miliseconds).
> + *
> + * Return: void.
> + */
> +static inline void dma330_execute_dbginsn(u8 insn[],
> +                                         struct dma_dma330_platdata *plat,
> +                                         const u32 timeout_ms)
> +{
> +       void __iomem *regs = plat->base;
> +       u32 val;
> +
> +       val = (insn[0] << 16) | (insn[1] << 24);
> +       if (!plat->dma330.channel0_manager1)
> +               val |= (1 << 0);
> +       val |= (plat->dma330.channel_num << 8); /* Channel Number */
> +       writel(val, regs + DBGINST0);
> +       val = insn[2];
> +       val = val | (insn[3] << 8);
> +       val = val | (insn[4] << 16);
> +       val = val | (insn[5] << 24);
> +       writel(val, regs + DBGINST1);
> +
> +       /* If timed out due to halted state-machine */
> +       if (dma330_until_dmac_idle(plat, timeout_ms)) {
> +               debug("DMAC halted!\n");
> +               return;
> +       }
> +       /* Get going */
> +       writel(0, regs + DBGCMD);
> +}
> +
> +/**
> + * dma330_getstate - Get the status of current channel or manager.
> + *
> + * @plat: Pointer to struct dma_dma330_platdata.
> + *
> + * Return: Status state of current channel or current manager.
> + */
> +static inline u32 dma330_getstate(struct dma_dma330_platdata *plat)
> +{
> +       void __iomem *regs = plat->base;
> +       u32 val;
> +
> +       if (plat->dma330.channel0_manager1)
> +               val = readl((uintptr_t)(regs + DS)) & 0xf;
> +       else
> +               val = readl((uintptr_t)(regs + CS(plat->dma330.channel_num))) &
> +                           0xf;
> +
> +       switch (val) {
> +       case DS_ST_STOP:
> +               return DMA330_STATE_STOPPED;
> +       case DS_ST_EXEC:
> +               return DMA330_STATE_EXECUTING;
> +       case DS_ST_CMISS:
> +               return DMA330_STATE_CACHEMISS;
> +       case DS_ST_UPDTPC:
> +               return DMA330_STATE_UPDTPC;
> +       case DS_ST_WFE:
> +               return DMA330_STATE_WFE;
> +       case DS_ST_FAULT:
> +               return DMA330_STATE_FAULTING;
> +       case DS_ST_ATBRR:
> +               if (plat->dma330.channel0_manager1)
> +                       return DMA330_STATE_INVALID;
> +               else
> +                       return DMA330_STATE_ATBARRIER;
> +       case DS_ST_QBUSY:
> +               if (plat->dma330.channel0_manager1)
> +                       return DMA330_STATE_INVALID;
> +               else
> +                       return DMA330_STATE_QUEUEBUSY;
> +       case DS_ST_WFP:
> +               if (plat->dma330.channel0_manager1)
> +                       return DMA330_STATE_INVALID;
> +               else
> +                       return DMA330_STATE_WFP;
> +       case DS_ST_KILL:
> +               if (plat->dma330.channel0_manager1)
> +                       return DMA330_STATE_INVALID;
> +               else
> +                       return DMA330_STATE_KILLING;
> +       case DS_ST_CMPLT:
> +               if (plat->dma330.channel0_manager1)
> +                       return DMA330_STATE_INVALID;
> +               else
> +                       return DMA330_STATE_COMPLETING;
> +       case DS_ST_FLTCMP:
> +               if (plat->dma330.channel0_manager1)
> +                       return DMA330_STATE_INVALID;
> +               else
> +                       return DMA330_STATE_FAULT_COMPLETING;
> +       default:
> +               return DMA330_STATE_INVALID;
> +       }
> +}
> +
> +/**
> + * dma330_trigger - Execute the DMAGO through debug instruction.
> + *
> + * @plat: Pointer to struct dma_dma330_platdata.
> + * @timeout_ms: Timeout (in miliseconds).
> + *
> + * When the DMA manager executes Go for a DMA channel that is in the Stopped
> + * state, it moves a 32-bit immediate into the program counter, then setting
> + * its security state and updating DMA channel to the Executing state.
> + *
> + * Return: Negative value for error as DMA is not ready. 0 for successful.
> + */
> +static int dma330_trigger(struct dma_dma330_platdata *plat,
> +                         const u32 timeout_ms)
> +{
> +       u8 insn[6] = {0, 0, 0, 0, 0, 0};
> +       struct _arg_go go;
> +
> +       /*
> +        * Return if already ACTIVE. It will ensure DMAGO is executed at
> +        * STOPPED state too
> +        */
> +       plat->dma330.channel0_manager1 = 0;
> +       if (dma330_getstate(plat) !=
> +               DMA330_STATE_STOPPED)
> +               return -EPERM;
> +
> +       go.chan = plat->dma330.channel_num;
> +       go.addr = (uintptr_t)plat->dma330.buf;
> +
> +       if (!plat->dma330.secure)
> +               go.ns = 1; /* non-secure condition */
> +       else
> +               go.ns = 0; /* secure condition */
> +
> +       _emit_go(insn, &go);
> +
> +       /* Only manager can execute GO */
> +       plat->dma330.channel0_manager1 = 1;
> +       dma330_execute_dbginsn(insn, plat, timeout_ms);
> +       return 0;
> +}
> +
> +/**
> + * dma330_stop - Stop the manager or channel.
> + *
> + * @plat: Pointer to struct dma_dma330_platdata.
> + * @timeout_ms: Timeout (in miliseconds).
> + *
> + * Stop the manager/channel or killing them and ensure they reach to stop
> + * state.
> + *
> + * Return: void.
> + */
> +static void dma330_stop(struct dma_dma330_platdata *plat, const u32 timeout_ms)
> +{
> +       u8 insn[6] = {0, 0, 0, 0, 0, 0};
> +
> +       /* If fault completing, wait until reach faulting and killing state */
> +       if (dma330_getstate(plat) == DMA330_STATE_FAULT_COMPLETING)
> +               UNTIL(plat, DMA330_STATE_FAULTING | DMA330_STATE_KILLING);
> +
> +       /* Return if nothing needs to be done */
> +       if (dma330_getstate(plat) == DMA330_STATE_COMPLETING ||
> +           dma330_getstate(plat) == DMA330_STATE_KILLING ||
> +           dma330_getstate(plat) == DMA330_STATE_STOPPED)
> +               return;
> +
> +       /* Kill it to ensure it reach to stop state */
> +       _emit_kill(insn);
> +
> +       /* Execute the KILL instruction through debug registers */
> +       dma330_execute_dbginsn(insn, plat, timeout_ms);
> +}
> +
> +/**
> + * dma330_start - Execute the command list through DMAGO and debug instruction.
> + *
> + * @plat: Pointer to struct dma_dma330_platdata.
> + * @timeout_ms: Timeout (in miliseconds).
> + *
> + * Return: Negative value for error where DMA is not ready. 0 for successful.
> + */
> +static int dma330_start(struct dma_dma330_platdata *plat, const u32 timeout_ms)
> +{
> +       debug("INFO: DMA BASE Address = 0x%08x\n",
> +             (u32)(uintptr_t)plat->base);
> +
> +       switch (dma330_getstate(plat)) {
> +       case DMA330_STATE_FAULT_COMPLETING:
> +               UNTIL(plat, DMA330_STATE_FAULTING | DMA330_STATE_KILLING);
> +
> +               if (dma330_getstate(plat) == DMA330_STATE_KILLING)
> +                       UNTIL(plat, DMA330_STATE_STOPPED);
> +
> +       case DMA330_STATE_FAULTING:
> +               dma330_stop(plat, timeout_ms);
> +
> +       case DMA330_STATE_KILLING:
> +       case DMA330_STATE_COMPLETING:
> +               UNTIL(plat, DMA330_STATE_STOPPED);
> +
> +       case DMA330_STATE_STOPPED:
> +               return dma330_trigger(plat, timeout_ms);
> +
> +       case DMA330_STATE_WFP:
> +       case DMA330_STATE_QUEUEBUSY:
> +       case DMA330_STATE_ATBARRIER:
> +       case DMA330_STATE_UPDTPC:
> +       case DMA330_STATE_CACHEMISS:
> +       case DMA330_STATE_EXECUTING:
> +               return -ESRCH;
> +       /* For RESUME, nothing yet */
> +       case DMA330_STATE_WFE:
> +       default:
> +               return -ESRCH;
> +       }
> +}
> +
> +/**
> + * dma330_transfer_start - DMA start to run.
> + *
> + * @plat: Pointer to struct dma_dma330_platdata.
> + *
> + * DMA start to excecute microcode command list.
> + *
> + * Return: Negative value for error or not successful. 0 for successful.
> + */
> +static int dma330_transfer_start(struct dma_dma330_platdata *plat)
> +{
> +       const u32 timeout_ms = 1000;
> +
> +       /* Execute the command list */
> +       return dma330_start(plat, timeout_ms);
> +}
> +
> +/**
> + * dma330_transfer_finish - DMA polling until execution finish or error.
> + *
> + * @plat: Pointer to struct dma_dma330_platdata.
> + *
> + * DMA polling until excution finish and checking the state status.
> + *
> + * Return: Negative value for state error or not successful. 0 for successful.
> + */
> +static int dma330_transfer_finish(struct dma_dma330_platdata *plat)
> +{
> +       void __iomem *regs = plat->base;
> +
> +       if (!plat->dma330.buf) {
> +               debug("ERROR DMA330 : DMA Microcode buffer pointer is NULL\n");
> +               return -EINVAL;
> +       }
> +
> +       plat->dma330.channel0_manager1 = 0;
> +
> +       /* Wait until finish execution to ensure we compared correct result*/
> +       UNTIL(plat, DMA330_STATE_STOPPED | DMA330_STATE_FAULTING);
> +
> +       /* check the state */
> +       if (dma330_getstate(plat) == DMA330_STATE_FAULTING) {
> +               debug("FAULT Mode: Channel %d Faulting, FTR = 0x%08x,",
> +                    plat->dma330.channel_num,
> +                    readl(regs + FTC(plat->dma330.channel_num)));
> +               debug("CPC = 0x%08lx\n",
> +                    (readl(regs + CPC(plat->dma330.channel_num))
> +                    - (uintptr_t)plat->dma330.buf));
> +               return -EPROTO;
> +       }
> +       return 0;
> +}
> +
> +/**
> + * dma330_transfer_setup - DMA transfer setup (DMA_MEM_TO_MEM, DMA_MEM_TO_DEV
> + *                        or DMA_DEV_TO_MEM).
> + *
> + * @plat: Pointer to struct dma_dma330_platdata.
> + *
> + * For Peripheral transfer, the FIFO threshold value is expected at
> + * 2 ^ plat->brst_size * plat->brst_len.
> + *
> + * Return: Negative value for error or not successful. 0 for successful.
> + */
> +static int dma330_transfer_setup(struct dma_dma330_platdata *plat)

This function is extremely long, Can it be split into separete
sub-functions which perform the work, if the work can be split
sensibly into different parts?

> +{
> +       /* Variable declaration */
> +       /* Buffer offset clear to 0 */
> +       int off = 0;
> +       int ret = 0;
> +       /* For DMALPEND */
> +       u32 loopjmp0, loopjmp1;
> +       /* Loop count 0 */
> +       u32 lcnt0 = 0;
> +       /* Loop count 1 */
> +       u32 lcnt1 = 0;
> +       u32 brst_size = 0;
> +       u32 brst_len = 0;
> +       u32 data_size_byte = plat->dma330.size_byte;
> +       /* Strong order memory is required to store microcode command list */
> +       u8 *buf = (u8 *)plat->dma330.buf;
> +       /* Channel Control Register */
> +       u32 ccr = 0;
> +       struct dma330_reqcfg reqcfg;
> +
> +       if (!buf) {
> +               debug("ERROR DMA330 : DMA Microcode buffer pointer is NULL\n");
> +               return -EINVAL;
> +       }
> +
> +       if (plat->dma330.transfer_type == DMA_MEM_TO_DEV)
> +               debug("INFO: mem2perip");
> +       else if (plat->dma330.transfer_type == DMA_DEV_TO_MEM)
> +               debug("INFO: perip2mem");
> +       else
> +               debug("INFO: DMA_MEM_TO_MEM");
> +
> +       debug(" - 0x%x%x -> 0x%x%x\nsize=%08x brst_size=2^%d ",
> +             (u32)(plat->dma330.src_addr >> 32),
> +             (u32)plat->dma330.src_addr,
> +             (u32)(plat->dma330.dst_addr >> 32),
> +             (u32)plat->dma330.dst_addr,
> +             data_size_byte,
> +             plat->brst_size);
> +
> +       debug("brst_len=%d singles_brst_size=2^%d\n", plat->brst_len,
> +             plat->dma330.single_brst_size);
> +
> +       /* brst_size = 2 ^ plat->brst_size */
> +       brst_size = 1 << plat->brst_size;
> +
> +       /* Fool proof checking */
> +       if (plat->brst_size < 0 || plat->brst_size >
> +               plat->max_brst_size) {
> +               debug("ERROR DMA330: brst_size must 0-%d (not %d)\n",
> +                       plat->max_brst_size, plat->brst_size);
> +               return -EINVAL;
> +       }
> +       if (plat->dma330.single_brst_size < 0 ||
> +               plat->dma330.single_brst_size > plat->max_brst_size) {
> +               debug("ERROR DMA330 : single_brst_size must 0-%d (not %d)\n",
> +                       plat->max_brst_size, plat->dma330.single_brst_size);
> +               return -EINVAL;
> +       }
> +       if (plat->brst_len < 1 || plat->brst_len > 16) {
> +               debug("ERROR DMA330 : brst_len must 1-16 (not %d)\n",
> +                       plat->brst_len);
> +               return -EINVAL;
> +       }
> +       if (plat->dma330.src_addr & (brst_size - 1)) {
> +               debug("ERROR DMA330 : Source address unaligned\n");
> +               return -EINVAL;
> +       }
> +       if (plat->dma330.dst_addr & (brst_size - 1)) {
> +               debug("ERROR DMA330 : Destination address unaligned\n");
> +               return -EINVAL;
> +       }
> +
> +       /* Setup the command list */
> +       /* DMAMOV SAR, x->src_addr */
> +       off += _emit_mov(&buf[off], SAR, plat->dma330.src_addr);
> +       /* DMAMOV DAR, x->dst_addr */
> +       off += _emit_mov(&buf[off], DAR, plat->dma330.dst_addr);
> +       /* DMAFLUSHP P(periheral_id) */
> +       if (plat->dma330.transfer_type != DMA_MEM_TO_MEM)
> +               off += _emit_flushp(&buf[off], plat->dma330.peripheral_id);
> +
> +       /* Preparing the CCR value */
> +       if (plat->dma330.transfer_type == DMA_MEM_TO_DEV) {
> +               /* Disable auto increment */
> +               reqcfg.dst_inc = 0;
> +               /* Enable auto increment */
> +               reqcfg.src_inc = 1;
> +       } else if (plat->dma330.transfer_type == DMA_DEV_TO_MEM) {
> +               reqcfg.dst_inc = 1;
> +               reqcfg.src_inc = 0;
> +       } else {
> +               /* DMA_MEM_TO_MEM */
> +               reqcfg.dst_inc = 1;
> +               reqcfg.src_inc = 1;
> +       }
> +
> +       if (!plat->dma330.secure)
> +               reqcfg.nonsecure = 1; /* Non Secure mode */
> +       else
> +               reqcfg.nonsecure = 0; /* Secure mode */
> +
> +       if (plat->dma330.enable_cache1 == 0) {
> +               /* Noncacheable but bufferable */
> +               reqcfg.dcctl = 0x1;
> +               reqcfg.scctl = 0x1;
> +       } else {
> +               if (plat->dma330.transfer_type == DMA_MEM_TO_DEV) {
> +                       reqcfg.dcctl = 0x1;
> +                       /* Cacheable write back */
> +                       reqcfg.scctl = 0x7;
> +               } else if (plat->dma330.transfer_type == DMA_DEV_TO_MEM) {
> +                       reqcfg.dcctl = 0x7;
> +                       reqcfg.scctl = 0x1;
> +               } else {
> +                       reqcfg.dcctl = 0x7;
> +                       reqcfg.scctl = 0x7;
> +               }
> +       }
> +       /* 1 - Privileged  */
> +       reqcfg.privileged = 1;
> +       /* 0 - Data access */
> +       reqcfg.insnaccess = 0;
> +       /* 0 - No endian swap */

I am not keen on these comments. The struct members should be
documented when the struct is declared, not here.

> +       reqcfg.swap = 0;
> +       /* DMA burst length */
> +       reqcfg.brst_len = plat->brst_len;
> +       /* DMA burst size */
> +       reqcfg.brst_size = plat->brst_size;
> +       /* Preparing the CCR value */
> +       ccr = _prepare_ccr(&reqcfg);
> +       /* DMAMOV CCR, ccr */
> +       off += _emit_mov(&buf[off], CCR, ccr);
> +
> +       /* BURST */
> +       /* Can initiate a burst? */
These two comments should be joined

> +       while (data_size_byte >= brst_size * plat->brst_len) {
> +               lcnt0 = data_size_byte / (brst_size * plat->brst_len);
> +               lcnt1 = 0;
> +               if (lcnt0 >= 256 * 256) {
> +                       lcnt0 = 256;
> +                       lcnt1 = 256;
> +               } else if (lcnt0 >= 256) {
> +                       lcnt1 = lcnt0 / 256;
> +                       lcnt0 = 256;
> +               }
> +               data_size_byte = data_size_byte -
> +                       (brst_size * plat->brst_len * lcnt0 * lcnt1);
> +
> +               debug("Transferring 0x%08x Remain 0x%08x\n", (brst_size *
> +                       plat->brst_len * lcnt0 * lcnt1), data_size_byte);
> +               debug("Running burst - brst_size=2^%d, brst_len=%d, ",
> +                     plat->brst_size, plat->brst_len);
> +               debug("lcnt0=%d, lcnt1=%d\n", lcnt0, lcnt1);
> +
> +               if (lcnt1) {
> +                       /* DMALP1 */
> +                       off += _emit_lp(&buf[off], 1, lcnt1);
> +                       loopjmp1 = off;
> +               }
> +               /* DMALP0 */

What does this comment mean?

> +               off += _emit_lp(&buf[off], 0, lcnt0);
> +               loopjmp0 = off;
> +               /* DMAWFP periheral_id, burst */
> +               if (plat->dma330.transfer_type != DMA_MEM_TO_MEM)
> +                       off += _emit_wfp(&buf[off], BURST,
> +                               plat->dma330.peripheral_id);
> +               /* DMALD */
> +               off += _emit_ld(&buf[off], ALWAYS);
> +
> +               WATCHDOG_RESET();
> +
> +               /* DMARMB */
> +               off += _emit_rmb(&buf[off]);
> +               /* DMASTPB peripheral_id */
> +               if (plat->dma330.transfer_type != DMA_MEM_TO_MEM)
> +                       off += _emit_stp(&buf[off], BURST,
> +                               plat->dma330.peripheral_id);
> +               else
> +                       off += _emit_st(&buf[off], ALWAYS);
> +               /* DMAWMB */
> +               off += _emit_wmb(&buf[off]);
> +               /* DMALP0END */
> +               struct _arg_lpend lpend;
> +
> +               lpend.cond = ALWAYS;
> +               lpend.forever = 0;
> +               /* Loop cnt 0 */
> +               lpend.loop = 0;
> +               lpend.bjump = off - loopjmp0;
> +               off += _emit_lpend(&buf[off], &lpend);
> +               /* DMALP1END */
> +               if (lcnt1) {
> +                       struct _arg_lpend lpend;
> +
> +                       lpend.cond = ALWAYS;
> +                       lpend.forever = 0;
> +                       lpend.loop = 1;         /* loop cnt 1*/
> +                       lpend.bjump = off - loopjmp1;
> +                       off += _emit_lpend(&buf[off], &lpend);
> +               }
> +               /* Ensure the microcode don't exceed buffer size */
> +               if (off > plat->buf_size) {
> +                       debug("ERROR DMA330 : Exceed buffer size\n");
> +                       return -ENOMEM;
> +               }
> +       }
> +
> +       /* SINGLE */
> +       brst_len = 1;
> +       /* brst_size = 2 ^ plat->dma330.single_brst_size; */
> +       brst_size = (1 << plat->dma330.single_brst_size);
> +       lcnt0 = data_size_byte / (brst_size * brst_len);
> +
> +       /* Ensure all data will be transferred */
> +       data_size_byte = data_size_byte -
> +               (brst_size * brst_len * lcnt0);
> +       if (data_size_byte) {
> +               debug("ERROR DMA330 : Detected the possibility of ");
> +               debug("untransfered data. Please ensure correct single ");
> +               debug("burst size\n");
> +       }
> +
> +       if (lcnt0) {
> +               debug("Transferring 0x%08x Remain 0x%08x\n", (brst_size *
> +                       brst_len * lcnt0 * lcnt1), data_size_byte);
> +               debug("Running single - brst_size=2^%d, brst_len=%d, ",
> +                     brst_size, brst_len);
> +               debug("lcnt0=%d\n", lcnt0);
> +
> +               /* Preparing the CCR value */
> +               /* DMA burst length */
> +               reqcfg.brst_len = brst_len;
> +               /* DMA burst size */
> +               reqcfg.brst_size = brst_size;
> +               ccr = _prepare_ccr(&reqcfg);
> +               /* DMAMOV CCR, ccr */
> +               off += _emit_mov(&buf[off], CCR, ccr);
> +
> +               /* DMALP0 */
> +               off += _emit_lp(&buf[off], 0, lcnt0);
> +               loopjmp0 = off;
> +               /* DMAWFP peripheral_id, single */
> +               if (plat->dma330.transfer_type != DMA_MEM_TO_MEM)
> +                       off += _emit_wfp(&buf[off], SINGLE,
> +                               plat->dma330.peripheral_id);
> +
> +               /* DMALD */
> +               off += _emit_ld(&buf[off], ALWAYS);
> +               /* DMARMB */
> +               off += _emit_rmb(&buf[off]);
> +               /* DMASTPS peripheral_id */
> +               if (plat->dma330.transfer_type != DMA_MEM_TO_MEM)
> +                       off += _emit_stp(&buf[off], SINGLE,
> +                               plat->dma330.peripheral_id);
> +               else
> +                       off += _emit_st(&buf[off], ALWAYS);
> +
> +               /* DMAWMB */
> +               off += _emit_wmb(&buf[off]);
> +               /* DMALPEND */
> +               struct _arg_lpend lpend1;
> +
> +               lpend1.cond = ALWAYS;
> +               lpend1.forever = 0;
> +               /* loop cnt 0 */
> +               lpend1.loop = 0;
> +               lpend1.bjump = off - loopjmp0;
> +               off += _emit_lpend(&buf[off], &lpend1);
> +               /* Ensure the microcode don't exceed buffer size */
> +               if (off > plat->buf_size) {
> +                       puts("ERROR DMA330 : Exceed buffer size\n");
> +                       return -ENOMEM;
> +               }
> +       }
> +
> +       /* DMAEND */
> +       off += _emit_end(&buf[off]);
> +
> +       ret = dma330_transfer_start(plat);
> +       if (ret)
> +               return ret;
> +
> +       return dma330_transfer_finish(plat);
> +}
> +
> +/**
> + * dma330_transfer_zeroes - DMA transfer zeros.
> + *
> + * @plat: Pointer to struct dma_dma330_platdata.
> + *
> + * Used to write zeros to a memory chunk for memory scrubbing purpose.
> + *
> + * Return: Negative value for error or not successful. 0 for successful.
> + */
> +static int dma330_transfer_zeroes_setup(struct dma_dma330_platdata *plat)

Can this function be combined with the above somehow? It seems like a
lot of duplicate code.

> +{
> +       /* Variable declaration */
> +       /* Buffer offset clear to 0 */
> +       int off = 0;
> +       int ret = 0;
> +       /* For DMALPEND */
> +       u32 loopjmp0, loopjmp1;
> +       /* Loop count 0 */
> +       u32 lcnt0 = 0;
> +       /* Loop count 1 */
> +       u32 lcnt1 = 0;
> +       u32 brst_size = 0;
> +       u32 brst_len = 0;
> +       u32 data_size_byte = plat->dma330.size_byte;
> +       /* Strong order memory is required to store microcode command list */
> +       u8 *buf = (u8 *)plat->dma330.buf;
> +       /* Channel Control Register */
> +       u32 ccr = 0;
> +       struct dma330_reqcfg reqcfg;
> +
> +       if (!buf) {
> +               debug("ERROR DMA330 : DMA Microcode buffer pointer is NULL\n");
> +               return -EINVAL;
> +       }
> +
> +       debug("INFO: Write zeros -> ");
> +       debug("0x%x%x size=0x%08x\n",
> +             (u32)(plat->dma330.dst_addr >> 32),
> +             (u32)plat->dma330.dst_addr,
> +             data_size_byte);
> +
> +       plat->dma330.single_brst_size = 1;
> +
> +       /* burst_size = 2 ^ plat->brst_size */
> +       brst_size = 1 << plat->brst_size;
> +
> +       /* Setup the command list */
> +       /* DMAMOV DAR, x->dst_addr */
> +       off += _emit_mov(&buf[off], DAR, plat->dma330.dst_addr);
> +
> +       /* Preparing the CCR value */
> +       /* Enable auto increment */
> +       reqcfg.dst_inc = 1;
> +       /* Disable auto increment (not applicable) */
> +       reqcfg.src_inc = 0;
> +       /* Noncacheable but bufferable */
> +       reqcfg.dcctl = 0x1;
> +       /* Noncacheable and bufferable */
> +       reqcfg.scctl = 0x1;
> +       /* 1 - Privileged  */
> +       reqcfg.privileged = 1;
> +       /* 0 - Data access */
> +       reqcfg.insnaccess = 0;
> +       /* 0 - No endian swap */
> +       reqcfg.swap = 0;
> +
> +       if (!plat->dma330.secure)
> +               reqcfg.nonsecure = 1; /* Non Secure mode */
> +       else
> +               reqcfg.nonsecure = 0; /* Secure mode */
> +
> +       /* DMA burst length */
> +       reqcfg.brst_len = plat->brst_len;
> +       /* DMA burst size */
> +       reqcfg.brst_size = plat->brst_size;
> +       /* Preparing the CCR value */
> +       ccr = _prepare_ccr(&reqcfg);
> +       /* DMAMOV CCR, ccr */
> +       off += _emit_mov(&buf[off], CCR, ccr);
> +
> +       /* BURST */
> +       /* Can initiate a burst? */
> +       while (data_size_byte >= brst_size * plat->brst_len) {
> +               lcnt0 = data_size_byte / (brst_size * plat->brst_len);
> +               lcnt1 = 0;
> +               if (lcnt0 >= 256 * 256) {
> +                       lcnt0 = 256;
> +                       lcnt1 = 256;
> +               } else if (lcnt0 >= 256) {
> +                       lcnt1 = lcnt0 / 256;
> +                       lcnt0 = 256;
> +               }
> +
> +               data_size_byte = data_size_byte -
> +                       (brst_size * plat->brst_len * lcnt0 * lcnt1);
> +
> +               debug("Transferring 0x%08x Remain 0x%08x\n", (brst_size *
> +                       plat->brst_len * lcnt0 * lcnt1), data_size_byte);
> +               debug("Running burst - brst_size=2^%d, brst_len=%d,",
> +                     plat->brst_size, plat->brst_len);
> +               debug("lcnt0=%d, lcnt1=%d\n", lcnt0, lcnt1);
> +
> +               if (lcnt1) {
> +                       /* DMALP1 */
> +                       off += _emit_lp(&buf[off], 1, lcnt1);
> +                       loopjmp1 = off;
> +               }
> +               /* DMALP0 */
> +               off += _emit_lp(&buf[off], 0, lcnt0);
> +               loopjmp0 = off;
> +               /* DMALSTZ */
> +               off += _emit_stz(&buf[off]);
> +
> +               WATCHDOG_RESET();
> +
> +               /* DMALP0END */
> +               struct _arg_lpend lpend;
> +
> +               lpend.cond = ALWAYS;
> +               lpend.forever = 0;
> +               /* Loop cnt 0 */
> +               lpend.loop = 0;
> +               lpend.bjump = off - loopjmp0;
> +               off += _emit_lpend(&buf[off], &lpend);
> +               /* DMALP1END */
> +               if (lcnt1) {
> +                       struct _arg_lpend lpend;
> +
> +                       lpend.cond = ALWAYS;
> +                       lpend.forever = 0;
> +                       /* Loop cnt 1*/
> +                       lpend.loop = 1;
> +                       lpend.bjump = off - loopjmp1;
> +                       off += _emit_lpend(&buf[off], &lpend);
> +               }
> +               /* Ensure the microcode don't exceed buffer size */
> +               if (off > plat->buf_size) {
> +                       printf("off = %d\n", off);
> +                       debug("ERROR DMA330 : Exceed buffer size off %d\n",
> +                             off);
> +                       return -ENOMEM;
> +               }
> +       }
> +
> +       /* SINGLE */
> +       brst_len = 1;
> +       /* brst_size = 2 ^ plat->dma330.single_brst_size */
> +       brst_size = (1 << plat->dma330.single_brst_size);
> +       lcnt0 = data_size_byte / (brst_size * brst_len);
> +
> +       /* ensure all data will be transferred */
> +       data_size_byte = data_size_byte -
> +               (brst_size * brst_len * lcnt0);
> +       if (data_size_byte) {
> +               debug("ERROR DMA330 : Detected the possibility of ");
> +               debug("untransfered data. Please ensure correct single ");
> +               debug("burst size\n");
> +       }
> +
> +       if (lcnt0) {
> +               debug("Transferring 0x%08x Remain 0x%08x\n", (brst_size *
> +                    brst_len * lcnt0), data_size_byte);
> +               debug("Running single - brst_size=2^%d, brst_len=%d, ",
> +                     brst_size, brst_len);
> +               debug("lcnt0=%d\n", lcnt0);
> +
> +               /* Preparing the CCR value */
> +               /* DMA burst length */
> +               reqcfg.brst_len = brst_len;
> +               /* DMA burst size */
> +               reqcfg.brst_size = brst_size;
> +               ccr = _prepare_ccr(&reqcfg);
> +               /* DMAMOV CCR, ccr */
> +               off += _emit_mov(&buf[off], CCR, ccr);
> +
> +               /* DMALP0 */
> +               off += _emit_lp(&buf[off], 0, lcnt0);
> +               loopjmp0 = off;
> +               /* DMALSTZ */
> +               off += _emit_stz(&buf[off]);
> +               /* DMALPEND */
> +               struct _arg_lpend lpend1;
> +
> +               lpend1.cond = ALWAYS;
> +               lpend1.forever = 0;
> +               /* Loop cnt 0 */
> +               lpend1.loop = 0;
> +               lpend1.bjump = off - loopjmp0;
> +               off += _emit_lpend(&buf[off], &lpend1);
> +               /* Ensure the microcode don't exceed buffer size */
> +               if (off > plat->buf_size) {
> +                       debug("ERROR DMA330 : Exceed buffer size\n");
> +                       return -ENOMEM;
> +               }
> +       }
> +
> +       /* DMAEND */
> +       off += _emit_end(&buf[off]);
> +
> +       ret = dma330_transfer_start(plat);
> +       if (ret)
> +               return ret;
> +
> +       return dma330_transfer_finish(plat);
> +}
> +
> +static int dma330_transfer_zeroes(struct udevice *dev, void *dst, size_t len)
> +{
> +       struct dma_dma330_platdata *plat = dev->platdata;
> +       int ret = 0;
> +
> +       /* If DMA access is set to secure, base change to DMA secure base */
> +       if (plat->dma330.secure)
> +               plat->base += 0x1000;

What is this? I suggest you set up the secure base separately in
'plat', e.g. with a base_secure member. You should not change platform
data while running.

You can pass the base address to dma330_transfer_zeroes_setup, perhaps.

> +
> +       plat->dma330.dst_addr = (phys_size_t)(uintptr_t)dst;
> +       plat->dma330.size_byte = len;
> +
> +       ret = dma330_transfer_zeroes_setup(plat);
> +
> +       /* Revert back to non secure DMA base */
> +       if (plat->dma330.secure)
> +               plat->base -= 0x1000;
> +
> +       return ret;
> +}
> +
> +static int dma330_transfer(struct udevice *dev, int direction, void *dst,
> +                         void *src, size_t len)
> +{
> +       struct dma_dma330_platdata *plat = dev->platdata;
> +       int ret = 0;
> +
> +       /* If DMA access is set to secure, base change to DMA secure base */
> +       if (plat->dma330.secure)
> +               plat->base += 0x1000;

Same as above

> +
> +       plat->dma330.dst_addr = (phys_size_t)(uintptr_t)dst;
> +       plat->dma330.src_addr = (phys_size_t)(uintptr_t)src;
> +       plat->dma330.size_byte = len;
> +
> +       switch (direction) {
> +       case DMA_MEM_TO_MEM:
> +               plat->dma330.transfer_type = DMA_SUPPORTS_MEM_TO_MEM;
> +               break;
> +       case DMA_MEM_TO_DEV:
> +               plat->dma330.transfer_type = DMA_SUPPORTS_MEM_TO_DEV;
> +               break;
> +       case DMA_DEV_TO_MEM:
> +               plat->dma330.transfer_type = DMA_SUPPORTS_DEV_TO_MEM;
> +               break;
> +       }
> +
> +       ret = dma330_transfer_setup(plat);
> +
> +       /* Revert back to non secure DMA base */
> +       if (plat->dma330.secure)
> +               plat->base -= 0x1000;
> +
> +       return ret;
> +}
> +
> +static int dma330_ofdata_to_platdata(struct udevice *dev)
> +{
> +       struct dma_dma330_platdata *plat = dev->platdata;
> +       const void *blob = gd->fdt_blob;
> +       int node = dev_of_offset(dev);
> +
> +       plat->base = (void __iomem *)devfdt_get_addr(dev);

dev_read_addr()

> +       plat->max_brst_size = fdtdec_get_uint(blob, node, "dma-max-burst-size",
> +                                             2);

Use dev_read API please (live tree)

> +       plat->brst_size = fdtdec_get_uint(blob, node, "dma-burst-size", 2);
> +       plat->brst_len = fdtdec_get_uint(blob, node, "dma-burst-length", 2);
> +
> +       return 0;
> +}
> +
> +static int dma330_probe(struct udevice *adev)
> +{
> +       struct dma_dev_priv *uc_priv = dev_get_uclass_priv(adev);
> +
> +       uc_priv->supported = (DMA_SUPPORTS_MEM_TO_MEM |
> +                            DMA_SUPPORTS_MEM_TO_DEV |
> +                            DMA_SUPPORTS_DEV_TO_MEM);
> +       return 0;
> +}
> +
> +static const struct dma_ops dma330_ops = {
> +       .transfer = dma330_transfer,
> +       .transfer_zeroes = dma330_transfer_zeroes,
> +};
> +
> +static const struct udevice_id dma330_ids[] = {
> +       { .compatible = "arm,pl330" },
> +       { .compatible = "arm,dma330" },
> +       { /* sentinel */ }
> +};
> +
> +U_BOOT_DRIVER(dma_dma330) = {
> +       .name   = "dma_dma330",
> +       .id     = UCLASS_DMA,
> +       .of_match = dma330_ids,
> +       .ops    = &dma330_ops,
> +       .ofdata_to_platdata = dma330_ofdata_to_platdata,
> +       .probe = dma330_probe,
> +       .platdata_auto_alloc_size = sizeof(struct dma_dma330_platdata),
> +};
> diff --git a/include/dma330.h b/include/dma330.h
> new file mode 100644
> index 0000000..c054bf2
> --- /dev/null
> +++ b/include/dma330.h
> @@ -0,0 +1,136 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2018 Intel Corporation <www.intel.com>
> + */
> +
> +#include <dma.h>
> +#include <linux/sizes.h>
> +
> +#ifndef __DMA330_CORE_H
> +#define __DMA330_CORE_H
> +
> +#define DMA330_MAX_CHAN                8
> +#define DMA330_MAX_IRQS                32
> +#define DMA330_MAX_PERI                32
> +
> +#define DMA330_STATE_STOPPED           BIT(0)
> +#define DMA330_STATE_EXECUTING         BIT(1)
> +#define DMA330_STATE_WFE               BIT(2)
> +#define DMA330_STATE_FAULTING          BIT(3)
> +#define        DMA330_STATE_COMPLETING         BIT(4)
> +#define DMA330_STATE_WFP               BIT(5)
> +#define DMA330_STATE_KILLING           BIT(6)
> +#define DMA330_STATE_FAULT_COMPLETING  BIT(7)
> +#define DMA330_STATE_CACHEMISS         BIT(8)
> +#define DMA330_STATE_UPDTPC            BIT(9)
> +#define DMA330_STATE_ATBARRIER         BIT(10)
> +#define DMA330_STATE_QUEUEBUSY         BIT(11))
> +#define DMA330_STATE_INVALID           BIT(15)
> +
> +enum dma330_srccachectrl {
> +       SCCTRL0 = 0,    /* Noncacheable and nonbufferable */
> +       SCCTRL1,        /* Bufferable only */
> +       SCCTRL2,        /* Cacheable, but do not allocate */
> +       SCCTRL3,        /* Cacheable and bufferable, but do not allocate */
> +       SINVALID1,
> +       SINVALID2,
> +       SCCTRL6,        /* Cacheable write-through, allocate on reads only */
> +       SCCTRL7,        /* Cacheable write-back, allocate on reads only */
> +};
> +
> +enum dma330_dstcachectrl {
> +       DCCTRL0 = 0,    /* Noncacheable and nonbufferable */
> +       DCCTRL1,        /* Bufferable only */
> +       DCCTRL2,        /* Cacheable, but do not allocate */
> +       DCCTRL3,        /* Cacheable and bufferable, but do not allocate */
> +       DINVALID1 = 8,
> +       DINVALID2,
> +       DCCTRL6,        /* Cacheable write-through, allocate on writes only */
> +       DCCTRL7,        /* Cacheable write-back, allocate on writes only */
> +};
> +
> +enum dma330_byteswap {
> +       SWAP_NO = 0,
> +       SWAP_2,
> +       SWAP_4,
> +       SWAP_8,
> +       SWAP_16,
> +};
> +
> +/**
> + * dma330_reqcfg - Request Configuration.
> + *
> + * The DMA330 core does not modify this and uses the last
> + * working configuration if the request doesn't provide any.
> + *
> + * The Client may want to provide this info only for the
> + * first request and a request with new settings.
> + */
> +struct dma330_reqcfg {
> +       /* Address Incrementing */
> +       u8 dst_inc;
> +       u8 src_inc;
> +
> +       /*
> +        * For now, the SRC & DST protection levels
> +        * and burst size/length are assumed same.
> +        */
> +       u8 nonsecure;
> +       u8 privileged;
> +       u8 insnaccess;
> +       u8 brst_len;
> +       u8 brst_size; /* in power of 2 */
> +
> +       enum dma330_dstcachectrl dcctl;
> +       enum dma330_srccachectrl scctl;
> +       enum dma330_byteswap swap;
> +};
> +
> +/**
> + * dma330_transfer_struct - Structure to be passed in for dma330_transfer_x.
> + *
> + * @channel0_manager1: Switching configuration on DMA channel or DMA manager.
> + * @channel_num: Channel number assigned, valid from 0 to 7.
> + * @src_addr: Address to transfer from / source.
> + * @dst_addr: Address to transfer to / destination.
> + * @size_byte: Number of bytes to be transferred.
> + * @brst_size: Valid from 0 - 4,
> + *            where 0 = 1 (2 ^ 0) bytes and 3 = 16 bytes (2 ^ 4).
> + * @max_brst_size: Max transfer size (from 0 - 4).
> + * @single_brst_size: Single transfer size (from 0 - 4).
> + * @brst_len: Valid from 1 - 16 where each burst can transfer 1 - 16
> + *           Data chunk (each chunk size equivalent to brst_size).
> + * @peripheral_id: Assigned peripheral_id, valid from 0 to 31.
> + * @transfer_type: MEM2MEM, MEM2PERIPH or PERIPH2MEM.
> + * @enable_cache1: 1 for cache enabled for memory
> + *                (cacheable and bufferable, but do not allocate).
> + * @buf: Buffer handler which will point to the memory
> + *      allocated for dma microcode
> + * @secure: Set DMA channel in secure mode.

This is a good way to document structs. Please do it for the others.

> + *
> + * Description of the structure.

Yes?

> + */
> +struct dma330_transfer_struct {
> +       u32 channel0_manager1;
> +       u32 channel_num;
> +       phys_size_t src_addr;
> +       phys_size_t dst_addr;
> +       u32 size_byte;
> +       u32 single_brst_size;
> +       u32 peripheral_id;
> +       u32 transfer_type;
> +       u32 enable_cache1;
> +       u32 *buf;
> +       u8 secure;
> +};
> +
> +struct dma_dma330_platdata {
> +       void __iomem *base;
> +       u32 buf_size;
> +       u32 max_brst_size;
> +       u32 brst_size;
> +       u32 brst_len;
> +       struct dma330_transfer_struct dma330;
> +};
> +
> +#endif /* __DMA330_CORE_H */
> --
> 2.2.0
>

Regards,
Simon
Chee, Tien Fong June 6, 2018, 5:22 a.m. UTC | #2
On Fri, 2018-06-01 at 08:24 -0600, Simon Glass wrote:
> Hi Tien,
> 
> On 31 May 2018 at 02:08,  <tien.fong.chee@intel.com> wrote:
> > 
> > From: Tien Fong Chee <tien.fong.chee@intel.com>
> > 
> > Enable DMAC driver support for DMA-330 controller.
> > The driver is also compatible to PL330 product.
> > 
> > Signed-off-by: Tien Fong Chee <tien.fong.chee@intel.com>
> > ---
> >  drivers/dma/Kconfig  |    9 +-
> >  drivers/dma/Makefile |    1 +
> >  drivers/dma/dma330.c | 1514
> > ++++++++++++++++++++++++++++++++++++++++++++++++++
> >  include/dma330.h     |  136 +++++
> >  4 files changed, 1659 insertions(+), 1 deletion(-)
> >  create mode 100644 drivers/dma/dma330.c
> >  create mode 100644 include/dma330.h
> > 
> > diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
> > index 4ee6afa..6e77e07 100644
> > --- a/drivers/dma/Kconfig
> > +++ b/drivers/dma/Kconfig
> > @@ -2,7 +2,7 @@ menu "DMA Support"
> > 
> >  config DMA
> >         bool "Enable Driver Model for DMA drivers"
> > -       depends on DM
> > +       depends on DM || SPL_DM
> >         help
> >           Enable driver model for DMA. DMA engines can do
> >           asynchronous data transfers without involving the host
> > @@ -34,4 +34,11 @@ config APBH_DMA_BURST8
> > 
> >  endif
> > 
> > +config DMA330_DMA
> > +       bool "PL330/DMA-330 DMA Controller(DMAC) driver"
> > +       depends on DMA
> > +       help
> > +        Enable the DMA controller driver for both PL330 and
> > +        DMA-330 products.
> > +
> >  endmenu # menu "DMA Support"
> > diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
> > index 4eaef8a..bfad0dd 100644
> > --- a/drivers/dma/Makefile
> > +++ b/drivers/dma/Makefile
> > @@ -11,3 +11,4 @@ obj-$(CONFIG_FSL_DMA) += fsl_dma.o
> >  obj-$(CONFIG_TI_KSNAV) += keystone_nav.o keystone_nav_cfg.o
> >  obj-$(CONFIG_TI_EDMA3) += ti-edma3.o
> >  obj-$(CONFIG_DMA_LPC32XX) += lpc32xx_dma.o
> > +obj-$(CONFIG_DMA330_DMA) += dma330.o
> > diff --git a/drivers/dma/dma330.c b/drivers/dma/dma330.c
> > new file mode 100644
> > index 0000000..66575d8
> > --- /dev/null
> > +++ b/drivers/dma/dma330.c
> > @@ -0,0 +1,1514 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2018 Intel Corporation <www.intel.com>
> > + */
> > +
> > +#include <common.h>
> > +#include <asm/io.h>
> > +#include <dma330.h>
> > +#include <dm.h>
> > +#include <fdtdec.h>
> > +#include <wait_bit.h>
> > +#include <linux/unaligned/access_ok.h>
> > +
> > +/* Register and Bit field Definitions */
> > +
> > +/* DMA Status */
> > +#define DS                     0x0
> > +#define DS_ST_STOP             0x0
> > +#define DS_ST_EXEC             0x1
> > +#define DS_ST_CMISS            0x2
> > +#define DS_ST_UPDTPC           0x3
> > +#define DS_ST_WFE              0x4
> > +#define DS_ST_ATBRR            0x5
> > +#define DS_ST_QBUSY            0x6
> > +#define DS_ST_WFP              0x7
> > +#define DS_ST_KILL             0x8
> > +#define DS_ST_CMPLT            0x9
> > +#define DS_ST_FLTCMP           0xe
> > +#define DS_ST_FAULT            0xf
> It is possible to use enum for some of these?
> 
> enum {
>    DS             = 0,
>    DS_ST_STOP,
>  ...
> }
> 
Okay.
> > 
> > +
> > +/* DMA Program Count register */
> > +#define DPC                    0x4
> > +/* Interrupt Enable register */
> > +#define INTEN                  0x20
> > +/* event-Interrupt Raw Status register */
> > +#define ES                     0x24
> > +/* Interrupt Status register */
> > +#define INTSTATUS              0x28
> > +/* Interrupt Clear register */
> > +#define INTCLR                 0x2c
> > +/* Fault Status DMA Manager register */
> > +#define FSM                    0x30
> > +/* Fault Status DMA Channel register */
> > +#define FSC                    0x34
> > +/* Fault Type DMA Manager register */
> > +#define FTM                    0x38
> > +
> > +/* Fault Type DMA Channel register */
> > +#define _FTC                   0x40
> > +#define FTC(n)                 (_FTC + (n) * 0x4)
> > +
> > +/* Channel Status register */
> > +#define _CS                    0x100
> > +#define CS(n)                  (_CS + (n) * 0x8)
> > +#define CS_CNS                 BIT(21)
> > +
> > +/* Channel Program Counter register */
> > +#define _CPC                   0x104
> > +#define CPC(n)                 (_CPC + (n) * 0x8)
> > +
> > +/* Source Address register */
> > +#define _SA                    0x400
> > +#define SA(n)                  (_SA + (n) * 0x20)
> > +
> > +/* Destination Address register */
> > +#define _DA                    0x404
> > +#define DA(n)                  (_DA + (n) * 0x20)
> > +
> > +/* Channel Control register */
> > +#define _CC                    0x408
> > +#define CC(n)                  (_CC + (n) * 0x20)
> > +
> > +/* Channel Control register (CCR) Setting */
> > +#define CC_SRCINC              BIT(0)
> > +#define CC_DSTINC              BIT(14)
> > +#define CC_SRCPRI              BIT(8)
> > +#define CC_DSTPRI              BIT(22)
> > +#define CC_SRCNS               BIT(9)
> > +#define CC_DSTNS               BIT(23)
> > +#define CC_SRCIA               BIT(10)
> > +#define CC_DSTIA               BIT(24)
> > +#define CC_SRCBRSTLEN_SHFT     4
> > +#define CC_DSTBRSTLEN_SHFT     18
> > +#define CC_SRCBRSTSIZE_SHFT    1
> > +#define CC_DSTBRSTSIZE_SHFT    15
> > +#define CC_SRCCCTRL_SHFT       11
> > +#define CC_SRCCCTRL_MASK       0x7
> Can you make the mask a shifted mask? Then it is easier to use in
> clrsetbits_le32(), for example.
> 
> e.g.
> 
> #define CC_SRCCCTRL_MASK (7 << CC_SRCCCTRL_SHFT)
> 
Okay.
> > 
> > +#define CC_DSTCCTRL_SHFT       25
> > +#define CC_DRCCCTRL_MASK       0x7
> > +#define CC_SWAP_SHFT           28
> > +
> > +/* Loop Counter 0 register */
> > +#define _LC0                   0x40c
> > +#define LC0(n)                 (_LC0 + (n) * 0x20)
> > +
> > +/* Loop Counter 1 register */
> > +#define _LC1                   0x410
> > +#define LC1(n)                 (_LC1 + (n) * 0x20)
> > +
> > +/* Debug Status register */
> > +#define DBGSTATUS              0xd00
> > +#define DBG_BUSY               BIT(0)
> > +
> > +/* Debug Command register */
> > +#define DBGCMD                 0xd04
> > +/* Debug Instruction 0 register */
> > +#define DBGINST0               0xd08
> > +/* Debug Instruction 1 register */
> > +#define DBGINST1               0xd0c
> > +
> > +/* Configuration register */
> > +#define CR0                    0xe00
> > +#define CR1                    0xe04
> > +#define CR2                    0xe08
> > +#define CR3                    0xe0c
> > +#define CR4                    0xe10
> > +#define CRD                    0xe14
> > +
> > +/* Peripheral Identification register */
> > +#define PERIPH_ID              0xfe0
> > +/* Component Identification register */
> > +#define PCELL_ID               0xff0
> > +
> > +/* Configuration register value */
> > +#define CR0_PERIPH_REQ_SET     BIT(0)
> > +#define CR0_BOOT_EN_SET                BIT(1)
> > +#define CR0_BOOT_MAN_NS                BIT(2)
> > +#define CR0_NUM_CHANS_SHIFT    4
> > +#define CR0_NUM_CHANS_MASK     0x7
> > +#define CR0_NUM_PERIPH_SHIFT   12
> > +#define CR0_NUM_PERIPH_MASK    0x1f
> > +#define CR0_NUM_EVENTS_SHIFT   17
> > +#define CR0_NUM_EVENTS_MASK    0x1f
> > +
> > +/* Configuration register value */
> > +#define CR1_ICACHE_LEN_SHIFT           0
> > +#define CR1_ICACHE_LEN_MASK            0x7
> > +#define CR1_NUM_ICACHELINES_SHIFT      4
> > +#define CR1_NUM_ICACHELINES_MASK       0xf
> > +
> > +/* Configuration register value */
> > +#define CRD_DATA_WIDTH_SHIFT   0
> > +#define CRD_DATA_WIDTH_MASK    0x7
> > +#define CRD_WR_CAP_SHIFT       4
> > +#define CRD_WR_CAP_MASK                0x7
> > +#define CRD_WR_Q_DEP_SHIFT     8
> > +#define CRD_WR_Q_DEP_MASK      0xf
> > +#define CRD_RD_CAP_SHIFT       12
> > +#define CRD_RD_CAP_MASK                0x7
> > +#define CRD_RD_Q_DEP_SHIFT     16
> > +#define CRD_RD_Q_DEP_MASK      0xf
> > +#define CRD_DATA_BUFF_SHIFT    20
> > +#define CRD_DATA_BUFF_MASK     0x3ff
> > +
> > +/* Microcode opcode value */
> > +#define CMD_DMAADDH            0x54
> > +#define CMD_DMAEND             0x00
> > +#define CMD_DMAFLUSHP          0x35
> > +#define CMD_DMAGO              0xa0
> > +#define CMD_DMALD              0x04
> > +#define CMD_DMALDP             0x25
> > +#define CMD_DMALP              0x20
> > +#define CMD_DMALPEND           0x28
> > +#define CMD_DMAKILL            0x01
> > +#define CMD_DMAMOV             0xbc
> > +#define CMD_DMANOP             0x18
> > +#define CMD_DMARMB             0x12
> > +#define CMD_DMASEV             0x34
> > +#define CMD_DMAST              0x08
> > +#define CMD_DMASTP             0x29
> > +#define CMD_DMASTZ             0x0c
> > +#define CMD_DMAWFE             0x36
> > +#define CMD_DMAWFP             0x30
> > +#define CMD_DMAWMB             0x13
> > +
> > +/* the size of opcode plus opcode required settings */
> > +#define SZ_DMAADDH             3
> > +#define SZ_DMAEND              1
> > +#define SZ_DMAFLUSHP           2
> > +#define SZ_DMALD               1
> > +#define SZ_DMALDP              2
> > +#define SZ_DMALP               2
> > +#define SZ_DMALPEND            2
> > +#define SZ_DMAKILL             1
> > +#define SZ_DMAMOV              6
> > +#define SZ_DMANOP              1
> > +#define SZ_DMARMB              1
> > +#define SZ_DMASEV              2
> > +#define SZ_DMAST               1
> > +#define SZ_DMASTP              2
> > +#define SZ_DMASTZ              1
> > +#define SZ_DMAWFE              2
> > +#define SZ_DMAWFP              2
> > +#define SZ_DMAWMB              1
> > +#define SZ_DMAGO               6
> > +
> > +/* Use this _only_ to wait on transient states */
> > +#define UNTIL(t, s)    do { \
> > +                               WATCHDOG_RESET(); \
> > +                       } while (!(dma330_getstate(t) & (s)))
> > +
> > +/* debug message printout */
> > +#ifdef DEBUG
> > +#define DMA330_DBGCMD_DUMP(off, x...)  do { \
> > +                                               printf("%x bytes:",
> > off); \
> > +                                               printf(x); \
> > +                                               WATCHDOG_RESET(); \
> > +                                       } while (0)
> > +#else
> > +#define DMA330_DBGCMD_DUMP(off, x...)  do {} while (0)
> > +#endif
> Can DMA330_DBGCMD_DUMP be a static function, and lower case? It's
> only
> used in one file, right?
> 
Okay, yes.
> > 
> > +
> > +/* Enum declaration */
> We know that :-)
> 
> Can you please add comments explaining what these enums are for, and
> what the values mean?
> 
Sure.
> > 
> > +enum dmamov_dst {
> > +       SAR = 0,
> > +       CCR,
> > +       DAR,
> > +};
> > +
> > +enum dma330_dst {
> > +       SRC = 0,
> > +       DST,
> > +};
> > +
> > +enum dma330_cond {
> > +       SINGLE,
> > +       BURST,
> > +       ALWAYS,
> > +};
> > +
> > +/* Structure will be used by _emit_lpend function */
> > +struct _arg_lpend {
> > +       enum dma330_cond cond;
> > +       int forever;
> > +       u32 loop;
> > +       u8 bjump;
> > +};
> > +
> > +/* Structure will be used by _emit_go function */
> > +struct _arg_go {
> Please drop the _ on these struct names, and document the members
> here.
> 
Okay.
> > 
> > +       u8 chan;
> > +       u32 addr;
> > +       u32 ns;
> > +};
> > +
> > +/*
> > + * _emit_end - Add opcode DMAEND into microcode (end).
> > + *
> > + * @buf: The buffer which stored the microcode program.
> > + *
> > + * Return: Size of opcode.
> > + */
> > +static inline u32 _emit_end(u8 buf[])
> Why is everything inline? The compiler will do it automatically when
> there is only one caller. Other than that, it just increases code
> size
> I think.
> 
Okay, will convert to static function.
> > 
> > +{
> > +       buf[0] = CMD_DMAEND;
> > +       DMA330_DBGCMD_DUMP(SZ_DMAEND, "\tDMAEND\n");
> > +       return SZ_DMAEND;
> > +}
> > +
> > +/*
> > + * _emit_flushp - Add opcode DMAFLUSHP into microcode (flush
> > peripheral).
> > + *
> > + * @buf -> The buffer which stored the microcode program.
> > + * @peri -> Peripheral ID as listed in DMA NPP.
> > + *
> > + * Return: Size of opcode.
> > + */
> > +static inline u32 _emit_flushp(u8 buf[], u8 peri)
> > +{
> > +       u8 *buffer = buf;
> > +
> > +       buffer[0] = CMD_DMAFLUSHP;
> > +       peri &= 0x1f;
> > +       peri <<= 3;
> These should be enums too so we don't have open-coded values in the
> code, Please check throughout.
> 
Okay, may be with #define or enum.
> > 
> > +       buffer[1] = peri;
> > +       DMA330_DBGCMD_DUMP(SZ_DMAFLUSHP, "\tDMAFLUSHP %u\n", peri
> > >> 3);
> > +       return SZ_DMAFLUSHP;
> > +}
> > +
> > +/**
> > + * _emit_ld - Add opcode DMALD into microcode (load).
> > + *
> > + * @buf: The buffer which stored the microcode program.
> > + * @cond: Execution criteria such as single, burst or always.
> > + *
> > + * Return: Size of opcode.
> > + */
> > +static inline u32 _emit_ld(u8 buf[], enum dma330_cond cond)
> > +{
> > +       buf[0] = CMD_DMALD;
> > +       if (cond == SINGLE)
> > +               buf[0] |= (0 << 1) | (1 << 0);
> More open-coded things
> 
Noted.
> > 
> > +       else if (cond == BURST)
> > +               buf[0] |= (1 << 1) | (1 << 0);
> > +       DMA330_DBGCMD_DUMP(SZ_DMALD, "\tDMALD%c\n",
> > +                         cond == SINGLE ? 'S' : (cond == BURST ?
> > 'B' : 'A'));
> > +       return SZ_DMALD;
> > +}
> > +
> > +/**
> > + * _emit_lp - Add opcode DMALP into microcode (loop).
> > + *
> > + * @buf: The buffer which stored the microcode program.
> > + * @loop: Selection of using counter 0 or 1  (valid value 0 or 1).
> > + * @cnt: number of iteration (valid value 1-256).
> > + *
> > + * Return: Size of opcode.
> > + */
> > +static inline u32 _emit_lp(u8 buf[], u32 loop, u32 cnt)
> > +{
> > +       u8 *buffer = buf;
> > +
> > +       buffer[0] = CMD_DMALP;
> > +       if (loop)
> > +               buffer[0] |= (1 << 1);
> > +       /* DMAC increments by 1 internally */
> > +       cnt--;
> > +       buffer[1] = cnt;
> > +       DMA330_DBGCMD_DUMP(SZ_DMALP, "\tDMALP_%c %u\n", loop ? '1'
> > : '0', cnt);
> > +       return SZ_DMALP;
> > +}
> > +
> > +/**
> > + * _emit_lpend - Add opcode DMALPEND into microcode (loop end).
> > + *
> > + * @buf: The buffer which stored the microcode program.
> > + * @arg: Structure _arg_lpend which contain all needed info.
> > + *     arg->cond -> Execution criteria such as single, burst or
> > always
> > + *     arg->forever -> Forever loop? used if DMALPFE started the
> > loop
> > + *     arg->bjump -> Backwards jump (relative location of
> > + *                   1st instruction in the loop.
> The members of the struct should be documented in the struct above,
> not here.
> 
Okay.
> > 
> > + *
> > + * Return: Size of opcode.
> > + */
> > +static inline u32 _emit_lpend(u8 buf[], const struct _arg_lpend
> > *arg)
> > +{
> > +       u8 *buffer = buf;
> > +       enum dma330_cond cond = arg->cond;
> > +       int forever = arg->forever;
> > +       u32 loop = arg->loop;
> > +       u8 bjump = arg->bjump;
> Why have these? Can you not use arg-bjump, etc., directly?
> 
Okay.
> > 
> > +
> > +       buffer[0] = CMD_DMALPEND;
> > +       if (loop)
> > +               buffer[0] |= (1 << 2);
> More open-coded things
> 
noted.
> > 
> > +       if (!forever)
> > +               buffer[0] |= (1 << 4);
> > +       if (cond == SINGLE)
> > +               buffer[0] |= (0 << 1) | (1 << 0);
> > +       else if (cond == BURST)
> > +               buffer[0] |= (1 << 1) | (1 << 0);
> > +
> > +       buffer[1] = bjump;
> > +       DMA330_DBGCMD_DUMP(SZ_DMALPEND, "\tDMALP%s%c_%c
> > bjmpto_%x\n",
> > +                         forever ? "FE" : "END",
> > +                         cond == SINGLE ? 'S' : (cond == BURST ?
> > 'B' : 'A'),
> > +                         loop ? '1' : '0',
> > +                         bjump);
> > +       return SZ_DMALPEND;
> > +}
> > +
> > +/**
> > + * _emit_kill - Add opcode DMAKILL into microcode (kill).
> > + *
> > + * @buf: The buffer which stored the microcode program.
> > + *
> > + * Return: Size of opcode.
> > + */
> > +static inline u32 _emit_kill(u8 buf[])
> > +{
> > +       buf[0] = CMD_DMAKILL;
> > +       return SZ_DMAKILL;
> > +}
> > +
> > +/**
> > + * _emit_mov - Add opcode DMAMOV into microcode (move).
> > + *
> > + * @buf: The buffer which stored the microcode program.
> > + * @dst: Destination register (valid value SAR[0b000], DAR[0b010],
> > + *      or CCR[0b001]).
> > + * @val: 32bit value that to be written into destination register.
> > + *
> > + * Return: Size of opcode.
> > + */
> > +static inline u32 _emit_mov(u8 buf[], enum dmamov_dst dst, u32
> > val)
> > +{
> > +       u8 *buffer = buf;
> > +
> > +       buffer[0] = CMD_DMAMOV;
> > +       buffer[1] = dst;
> > +       buffer[2] = val & 0xFF;
> > +       buffer[3] = (val >> 8) & 0xFF;
> > +       buffer[4] = (val >> 16) & 0xFF;
> > +       buffer[5] = (val >> 24) & 0xFF;
> Can you use put_unaligned_le32() ? Also check the same thing below.
> 
Okay.
> 
> > 
> > +       DMA330_DBGCMD_DUMP(SZ_DMAMOV, "\tDMAMOV %s 0x%x\n",
> > +                         dst == SAR ? "SAR" : (dst == DAR ? "DAR"
> > : "CCR"),
> > +                          val);
> > +       return SZ_DMAMOV;
> > +}
> > +
> > +/**
> > + * _emit_nop - Add opcode DMANOP into microcode (no operation).
> > + *
> > + * @buf: The buffer which stored the microcode program.
> > + *
> > + * Return: Size of opcode.
> > + */
> > +static inline u32 _emit_nop(u8 buf[])
> > +{
> > +       buf[0] = CMD_DMANOP;
> > +       DMA330_DBGCMD_DUMP(SZ_DMANOP, "\tDMANOP\n");
> please add a blank line before 'return'
> 
Okay.
> > 
> > +       return SZ_DMANOP;
> > +}
> > +
> > +/**
> > + * _emit_rmb - Add opcode DMARMB into microcode (read memory
> > barrier).
> > + *
> > + * @buf: The buffer which stored the microcode program.
> > + *
> > + * Return: Size of opcode.
> > + */
> > +static inline u32 _emit_rmb(u8 buf[])
> > +{
> > +       buf[0] = CMD_DMARMB;
> > +       DMA330_DBGCMD_DUMP(SZ_DMARMB, "\tDMARMB\n");
> > +       return SZ_DMARMB;
> > +}
> > +
> > +/**
> > + * _emit_sev - Add opcode DMASEV into microcode (send event).
> > + *
> > + * @buf: The buffer which stored the microcode program.
> > + * @ev: The event number (valid 0 - 31).
> > + *
> > + * Return: Size of opcode.
> > + */
> > +static inline u32 _emit_sev(u8 buf[], u8 ev)
> > +{
> > +       u8 *buffer = buf;
> > +
> > +       buffer[0] = CMD_DMASEV;
> > +       ev &= 0x1f;
> > +       ev <<= 3;
> > +       buffer[1] = ev;
> > +       DMA330_DBGCMD_DUMP(SZ_DMASEV, "\tDMASEV %u\n", ev >> 3);
> > +       return SZ_DMASEV;
> > +}
> > +
> > +/**
> > + * _emit_st - Add opcode DMAST into microcode (store).
> > + *
> > + * @buf: The buffer which stored the microcode program.
> > + * @cond: Execution criteria such as single, burst or always.
> > + *
> > + * Return: Size of opcode.
> > + */
> > +static inline u32 _emit_st(u8 buf[], enum dma330_cond cond)
> > +{
> > +       buf[0] = CMD_DMAST;
> > +       if (cond == SINGLE)
> > +               buf[0] |= (0 << 1) | (1 << 0);
> > +       else if (cond == BURST)
> > +               buf[0] |= (1 << 1) | (1 << 0);
> > +
> > +       DMA330_DBGCMD_DUMP(SZ_DMAST, "\tDMAST%c\n",
> > +               cond == SINGLE ? 'S' : (cond == BURST ? 'B' :
> > 'A'));
> > +       return SZ_DMAST;
> > +}
> > +
> > +/**
> > + * _emit_stp - Add opcode DMASTP into microcode (store and notify
> > peripheral).
> > + *
> > + * @buf: The buffer which stored the microcode program.
> > + * @cond: Execution criteria such as single, burst or always.
> > + * @peri: Peripheral ID as listed in DMA NPP.
> > + *
> > + * Return: Size of opcode.
> > + */
> > +static inline u32 _emit_stp(u8 buf[], enum dma330_cond cond, u8
> > peri)
> > +{
> > +       u8 *buffer = buf;
> > +
> > +       buffer[0] = CMD_DMASTP;
> > +       if (cond == BURST)
> > +               buf[0] |= (1 << 1);
> > +       peri &= 0x1f;
> > +       peri <<= 3;
> > +       buffer[1] = peri;
> > +       DMA330_DBGCMD_DUMP(SZ_DMASTP, "\tDMASTP%c %u\n",
> > +               cond == SINGLE ? 'S' : 'B', peri >> 3);
> > +       return SZ_DMASTP;
> > +}
> > +
> > +/**
> > + * _emit_stz - Add opcode DMASTZ into microcode (store zeros).
> > + *
> > + * @buf -> The buffer which stored the microcode program.
> > + *
> > + * Return: Size of opcode.
> > + */
> > +static inline u32 _emit_stz(u8 buf[])
> > +{
> > +       buf[0] = CMD_DMASTZ;
> > +       DMA330_DBGCMD_DUMP(SZ_DMASTZ, "\tDMASTZ\n");
> > +       return SZ_DMASTZ;
> > +}
> > +
> > +/**
> > + * _emit_wfp - Add opcode DMAWFP into microcode (wait for
> > peripheral).
> > + *
> > + * @buf: The buffer which stored the microcode program.
> > + * @cond: Execution criteria such as single, burst or always.
> > + * @peri: Peripheral ID as listed in DMA NPP.
> > + *
> > + * Return: Size of opcode.
> > + */
> > +static inline u32 _emit_wfp(u8 buf[], enum dma330_cond cond, u8
> > peri)
> > +{
> > +       u8 *buffer = buf;
> > +
> > +       buffer[0] = CMD_DMAWFP;
> > +       if (cond == SINGLE)
> > +               buffer[0] |= (0 << 1) | (0 << 0);
> > +       else if (cond == BURST)
> > +               buffer[0] |= (1 << 1) | (0 << 0);
> > +       else
> > +               buffer[0] |= (0 << 1) | (1 << 0);
> Perhaps these three values are the same for each command? If so, the
> three expressions (0, 1, 2) could go in an enum.
> 
Okay.
> > 
> > +
> > +       peri &= 0x1f;
> > +       peri <<= 3;
> > +       buffer[1] = peri;
> > +       DMA330_DBGCMD_DUMP(SZ_DMAWFP, "\tDMAWFP%c %u\n",
> > +               cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'P'),
> > peri >> 3);
> > +       return SZ_DMAWFP;
> > +}
> > +
> > +/**
> > + * _emit_wmb - Add opcode DMAWMB into microcode (write memory
> > barrier).
> > + *
> > + * @buf: The buffer which stored the microcode program.
> > + *
> > + * Return: Size of opcode.
> > + */
> > +static inline u32 _emit_wmb(u8 buf[])
> > +{
> > +       buf[0] = CMD_DMAWMB;
> > +       DMA330_DBGCMD_DUMP(SZ_DMAWMB, "\tDMAWMB\n");
> > +       return SZ_DMAWMB;
> > +}
> > +
> > +/**
> > + * _emit_go - Add opcode DMALGO into microcode (go).
> > + *
> > + * @buf: The buffer which stored the microcode program.
> > + * @arg: structure _arg_go which contain all needed info
> > + *     arg->chan -> channel number
> > + *     arg->addr -> start address of the microcode program
> > + *                  which will be wrote into CPC register
> > + *     arg->ns -> 1 for non secure, 0 for secure
> > + *                (if only DMA Manager is in secure).
> > + *
> > + * Return: Size of opcode.
> > + */
> > +static inline u32 _emit_go(u8 buf[], const struct _arg_go *arg)
> > +{
> > +       u8 *buffer = buf;
> > +       u8 chan = arg->chan;
> > +       u32 addr = arg->addr;
> > +       u32 ns = arg->ns;
> These local vars seem pointless as the are only used once. Maybe it's
> worth it for 'addr', but even there you should use the put_unaligned
> thing.
Okay.
> > 
> > +
> > +       buffer[0] = CMD_DMAGO;
> > +       buffer[0] |= (ns << 1);
> > +       buffer[1] = chan & 0x7;
> > +       buf[2] = addr & 0xFF;
> > +       buf[3] = (addr >> 8) & 0xFF;
> > +       buf[4] = (addr >> 16) & 0xFF;
> > +       buf[5] = (addr >> 24) & 0xFF;
> > +       return SZ_DMAGO;
> > +}
> > +
> > +/**
> > + * _prepare_ccr - Populate the CCR register.
> > + * @rqc: Request Configuration.
> > + *
> > + * Return: Channel Control register (CCR) Setting.
> > + */
> > +static inline u32 _prepare_ccr(const struct dma330_reqcfg *rqc)
> > +{
> > +       u32 ccr = 0;
> > +
> > +       if (rqc->src_inc)
> > +               ccr |= CC_SRCINC;
> > +       if (rqc->dst_inc)
> > +               ccr |= CC_DSTINC;
> > +
> > +       /* We set same protection levels for Src and DST for now */
> > +       if (rqc->privileged)
> > +               ccr |= CC_SRCPRI | CC_DSTPRI;
> > +       if (rqc->nonsecure)
> > +               ccr |= CC_SRCNS | CC_DSTNS;
> > +       if (rqc->insnaccess)
> > +               ccr |= CC_SRCIA | CC_DSTIA;
> > +
> > +       ccr |= (((rqc->brst_len - 1) & 0xf) << CC_SRCBRSTLEN_SHFT);
> > +       ccr |= (((rqc->brst_len - 1) & 0xf) << CC_DSTBRSTLEN_SHFT);
> > +
> > +       ccr |= (rqc->brst_size << CC_SRCBRSTSIZE_SHFT);
> > +       ccr |= (rqc->brst_size << CC_DSTBRSTSIZE_SHFT);
> > +
> > +       ccr |= (rqc->scctl << CC_SRCCCTRL_SHFT);
> > +       ccr |= (rqc->dcctl << CC_DSTCCTRL_SHFT);
> You don't need the outer brackets on these.
OKAY.
> 
> > 
> > +
> > +       ccr |= (rqc->swap << CC_SWAP_SHFT);
> > +       return ccr;
> > +}
> > +
> > +/**
> > + * dma330_until_dmac_idle - Wait until DMA Manager is idle.
> > + *
> > + * @plat: Pointer to struct dma_dma330_platdata.
> > + * @timeout_ms: Timeout (in miliseconds).
> > + *
> > + * Return: Negative value for error / timeout ocurred before idle,
> > + *        0 for successful.
> > + */
> > +static int dma330_until_dmac_idle(struct dma_dma330_platdata
> > *plat,
> > +                                 const u32 timeout_ms)
> > +{
> > +       void __iomem *regs = plat->base;
> > +
> > +       return wait_for_bit(__func__,
> > +                           (const u32 *)(uintptr_t)(regs +
> > DBGSTATUS),
> > +                           DBG_BUSY, 0, timeout_ms, false);
> > +}
> > +
> > +/**
> > + * dma330_execute_dbginsn - Execute debug instruction such as
> > DMAGO and DMAKILL.
> > + *
> > + * @insn: The buffer which stored the debug instruction.
> > + * @plat: Pointer to struct dma_dma330_platdata.
> > + * @timeout_ms: Timeout (in miliseconds).
> > + *
> > + * Return: void.
> > + */
> > +static inline void dma330_execute_dbginsn(u8 insn[],
> > +                                         struct
> > dma_dma330_platdata *plat,
> > +                                         const u32 timeout_ms)
> > +{
> > +       void __iomem *regs = plat->base;
> > +       u32 val;
> > +
> > +       val = (insn[0] << 16) | (insn[1] << 24);
> > +       if (!plat->dma330.channel0_manager1)
> > +               val |= (1 << 0);
> > +       val |= (plat->dma330.channel_num << 8); /* Channel Number
> > */
> > +       writel(val, regs + DBGINST0);
> > +       val = insn[2];
> > +       val = val | (insn[3] << 8);
> > +       val = val | (insn[4] << 16);
> > +       val = val | (insn[5] << 24);
> > +       writel(val, regs + DBGINST1);
> > +
> > +       /* If timed out due to halted state-machine */
> > +       if (dma330_until_dmac_idle(plat, timeout_ms)) {
> > +               debug("DMAC halted!\n");
> > +               return;
> > +       }
> > +       /* Get going */
> > +       writel(0, regs + DBGCMD);
> > +}
> > +
> > +/**
> > + * dma330_getstate - Get the status of current channel or manager.
> > + *
> > + * @plat: Pointer to struct dma_dma330_platdata.
> > + *
> > + * Return: Status state of current channel or current manager.
> > + */
> > +static inline u32 dma330_getstate(struct dma_dma330_platdata
> > *plat)
> > +{
> > +       void __iomem *regs = plat->base;
> > +       u32 val;
> > +
> > +       if (plat->dma330.channel0_manager1)
> > +               val = readl((uintptr_t)(regs + DS)) & 0xf;
> > +       else
> > +               val = readl((uintptr_t)(regs + CS(plat-
> > >dma330.channel_num))) &
> > +                           0xf;
> > +
> > +       switch (val) {
> > +       case DS_ST_STOP:
> > +               return DMA330_STATE_STOPPED;
> > +       case DS_ST_EXEC:
> > +               return DMA330_STATE_EXECUTING;
> > +       case DS_ST_CMISS:
> > +               return DMA330_STATE_CACHEMISS;
> > +       case DS_ST_UPDTPC:
> > +               return DMA330_STATE_UPDTPC;
> > +       case DS_ST_WFE:
> > +               return DMA330_STATE_WFE;
> > +       case DS_ST_FAULT:
> > +               return DMA330_STATE_FAULTING;
> > +       case DS_ST_ATBRR:
> > +               if (plat->dma330.channel0_manager1)
> > +                       return DMA330_STATE_INVALID;
> > +               else
> > +                       return DMA330_STATE_ATBARRIER;
> > +       case DS_ST_QBUSY:
> > +               if (plat->dma330.channel0_manager1)
> > +                       return DMA330_STATE_INVALID;
> > +               else
> > +                       return DMA330_STATE_QUEUEBUSY;
> > +       case DS_ST_WFP:
> > +               if (plat->dma330.channel0_manager1)
> > +                       return DMA330_STATE_INVALID;
> > +               else
> > +                       return DMA330_STATE_WFP;
> > +       case DS_ST_KILL:
> > +               if (plat->dma330.channel0_manager1)
> > +                       return DMA330_STATE_INVALID;
> > +               else
> > +                       return DMA330_STATE_KILLING;
> > +       case DS_ST_CMPLT:
> > +               if (plat->dma330.channel0_manager1)
> > +                       return DMA330_STATE_INVALID;
> > +               else
> > +                       return DMA330_STATE_COMPLETING;
> > +       case DS_ST_FLTCMP:
> > +               if (plat->dma330.channel0_manager1)
> > +                       return DMA330_STATE_INVALID;
> > +               else
> > +                       return DMA330_STATE_FAULT_COMPLETING;
> > +       default:
> > +               return DMA330_STATE_INVALID;
> > +       }
> > +}
> > +
> > +/**
> > + * dma330_trigger - Execute the DMAGO through debug instruction.
> > + *
> > + * @plat: Pointer to struct dma_dma330_platdata.
> > + * @timeout_ms: Timeout (in miliseconds).
> > + *
> > + * When the DMA manager executes Go for a DMA channel that is in
> > the Stopped
> > + * state, it moves a 32-bit immediate into the program counter,
> > then setting
> > + * its security state and updating DMA channel to the Executing
> > state.
> > + *
> > + * Return: Negative value for error as DMA is not ready. 0 for
> > successful.
> > + */
> > +static int dma330_trigger(struct dma_dma330_platdata *plat,
> > +                         const u32 timeout_ms)
> > +{
> > +       u8 insn[6] = {0, 0, 0, 0, 0, 0};
> > +       struct _arg_go go;
> > +
> > +       /*
> > +        * Return if already ACTIVE. It will ensure DMAGO is
> > executed at
> > +        * STOPPED state too
> > +        */
> > +       plat->dma330.channel0_manager1 = 0;
> > +       if (dma330_getstate(plat) !=
> > +               DMA330_STATE_STOPPED)
> > +               return -EPERM;
> > +
> > +       go.chan = plat->dma330.channel_num;
> > +       go.addr = (uintptr_t)plat->dma330.buf;
> > +
> > +       if (!plat->dma330.secure)
> > +               go.ns = 1; /* non-secure condition */
> > +       else
> > +               go.ns = 0; /* secure condition */
> > +
> > +       _emit_go(insn, &go);
> > +
> > +       /* Only manager can execute GO */
> > +       plat->dma330.channel0_manager1 = 1;
> > +       dma330_execute_dbginsn(insn, plat, timeout_ms);
> > +       return 0;
> > +}
> > +
> > +/**
> > + * dma330_stop - Stop the manager or channel.
> > + *
> > + * @plat: Pointer to struct dma_dma330_platdata.
> > + * @timeout_ms: Timeout (in miliseconds).
> > + *
> > + * Stop the manager/channel or killing them and ensure they reach
> > to stop
> > + * state.
> > + *
> > + * Return: void.
> > + */
> > +static void dma330_stop(struct dma_dma330_platdata *plat, const
> > u32 timeout_ms)
> > +{
> > +       u8 insn[6] = {0, 0, 0, 0, 0, 0};
> > +
> > +       /* If fault completing, wait until reach faulting and
> > killing state */
> > +       if (dma330_getstate(plat) == DMA330_STATE_FAULT_COMPLETING)
> > +               UNTIL(plat, DMA330_STATE_FAULTING |
> > DMA330_STATE_KILLING);
> > +
> > +       /* Return if nothing needs to be done */
> > +       if (dma330_getstate(plat) == DMA330_STATE_COMPLETING ||
> > +           dma330_getstate(plat) == DMA330_STATE_KILLING ||
> > +           dma330_getstate(plat) == DMA330_STATE_STOPPED)
> > +               return;
> > +
> > +       /* Kill it to ensure it reach to stop state */
> > +       _emit_kill(insn);
> > +
> > +       /* Execute the KILL instruction through debug registers */
> > +       dma330_execute_dbginsn(insn, plat, timeout_ms);
> > +}
> > +
> > +/**
> > + * dma330_start - Execute the command list through DMAGO and debug
> > instruction.
> > + *
> > + * @plat: Pointer to struct dma_dma330_platdata.
> > + * @timeout_ms: Timeout (in miliseconds).
> > + *
> > + * Return: Negative value for error where DMA is not ready. 0 for
> > successful.
> > + */
> > +static int dma330_start(struct dma_dma330_platdata *plat, const
> > u32 timeout_ms)
> > +{
> > +       debug("INFO: DMA BASE Address = 0x%08x\n",
> > +             (u32)(uintptr_t)plat->base);
> > +
> > +       switch (dma330_getstate(plat)) {
> > +       case DMA330_STATE_FAULT_COMPLETING:
> > +               UNTIL(plat, DMA330_STATE_FAULTING |
> > DMA330_STATE_KILLING);
> > +
> > +               if (dma330_getstate(plat) == DMA330_STATE_KILLING)
> > +                       UNTIL(plat, DMA330_STATE_STOPPED);
> > +
> > +       case DMA330_STATE_FAULTING:
> > +               dma330_stop(plat, timeout_ms);
> > +
> > +       case DMA330_STATE_KILLING:
> > +       case DMA330_STATE_COMPLETING:
> > +               UNTIL(plat, DMA330_STATE_STOPPED);
> > +
> > +       case DMA330_STATE_STOPPED:
> > +               return dma330_trigger(plat, timeout_ms);
> > +
> > +       case DMA330_STATE_WFP:
> > +       case DMA330_STATE_QUEUEBUSY:
> > +       case DMA330_STATE_ATBARRIER:
> > +       case DMA330_STATE_UPDTPC:
> > +       case DMA330_STATE_CACHEMISS:
> > +       case DMA330_STATE_EXECUTING:
> > +               return -ESRCH;
> > +       /* For RESUME, nothing yet */
> > +       case DMA330_STATE_WFE:
> > +       default:
> > +               return -ESRCH;
> > +       }
> > +}
> > +
> > +/**
> > + * dma330_transfer_start - DMA start to run.
> > + *
> > + * @plat: Pointer to struct dma_dma330_platdata.
> > + *
> > + * DMA start to excecute microcode command list.
> > + *
> > + * Return: Negative value for error or not successful. 0 for
> > successful.
> > + */
> > +static int dma330_transfer_start(struct dma_dma330_platdata *plat)
> > +{
> > +       const u32 timeout_ms = 1000;
> > +
> > +       /* Execute the command list */
> > +       return dma330_start(plat, timeout_ms);
> > +}
> > +
> > +/**
> > + * dma330_transfer_finish - DMA polling until execution finish or
> > error.
> > + *
> > + * @plat: Pointer to struct dma_dma330_platdata.
> > + *
> > + * DMA polling until excution finish and checking the state
> > status.
> > + *
> > + * Return: Negative value for state error or not successful. 0 for
> > successful.
> > + */
> > +static int dma330_transfer_finish(struct dma_dma330_platdata
> > *plat)
> > +{
> > +       void __iomem *regs = plat->base;
> > +
> > +       if (!plat->dma330.buf) {
> > +               debug("ERROR DMA330 : DMA Microcode buffer pointer
> > is NULL\n");
> > +               return -EINVAL;
> > +       }
> > +
> > +       plat->dma330.channel0_manager1 = 0;
> > +
> > +       /* Wait until finish execution to ensure we compared
> > correct result*/
> > +       UNTIL(plat, DMA330_STATE_STOPPED | DMA330_STATE_FAULTING);
> > +
> > +       /* check the state */
> > +       if (dma330_getstate(plat) == DMA330_STATE_FAULTING) {
> > +               debug("FAULT Mode: Channel %d Faulting, FTR =
> > 0x%08x,",
> > +                    plat->dma330.channel_num,
> > +                    readl(regs + FTC(plat->dma330.channel_num)));
> > +               debug("CPC = 0x%08lx\n",
> > +                    (readl(regs + CPC(plat->dma330.channel_num))
> > +                    - (uintptr_t)plat->dma330.buf));
> > +               return -EPROTO;
> > +       }
> > +       return 0;
> > +}
> > +
> > +/**
> > + * dma330_transfer_setup - DMA transfer setup (DMA_MEM_TO_MEM,
> > DMA_MEM_TO_DEV
> > + *                        or DMA_DEV_TO_MEM).
> > + *
> > + * @plat: Pointer to struct dma_dma330_platdata.
> > + *
> > + * For Peripheral transfer, the FIFO threshold value is expected
> > at
> > + * 2 ^ plat->brst_size * plat->brst_len.
> > + *
> > + * Return: Negative value for error or not successful. 0 for
> > successful.
> > + */
> > +static int dma330_transfer_setup(struct dma_dma330_platdata *plat)
> This function is extremely long, Can it be split into separete
> sub-functions which perform the work, if the work can be split
> sensibly into different parts?
> 
Let me see how the work can be further split into different parts.
> > 
> > +{
> > +       /* Variable declaration */
> > +       /* Buffer offset clear to 0 */
> > +       int off = 0;
> > +       int ret = 0;
> > +       /* For DMALPEND */
> > +       u32 loopjmp0, loopjmp1;
> > +       /* Loop count 0 */
> > +       u32 lcnt0 = 0;
> > +       /* Loop count 1 */
> > +       u32 lcnt1 = 0;
> > +       u32 brst_size = 0;
> > +       u32 brst_len = 0;
> > +       u32 data_size_byte = plat->dma330.size_byte;
> > +       /* Strong order memory is required to store microcode
> > command list */
> > +       u8 *buf = (u8 *)plat->dma330.buf;
> > +       /* Channel Control Register */
> > +       u32 ccr = 0;
> > +       struct dma330_reqcfg reqcfg;
> > +
> > +       if (!buf) {
> > +               debug("ERROR DMA330 : DMA Microcode buffer pointer
> > is NULL\n");
> > +               return -EINVAL;
> > +       }
> > +
> > +       if (plat->dma330.transfer_type == DMA_MEM_TO_DEV)
> > +               debug("INFO: mem2perip");
> > +       else if (plat->dma330.transfer_type == DMA_DEV_TO_MEM)
> > +               debug("INFO: perip2mem");
> > +       else
> > +               debug("INFO: DMA_MEM_TO_MEM");
> > +
> > +       debug(" - 0x%x%x -> 0x%x%x\nsize=%08x brst_size=2^%d ",
> > +             (u32)(plat->dma330.src_addr >> 32),
> > +             (u32)plat->dma330.src_addr,
> > +             (u32)(plat->dma330.dst_addr >> 32),
> > +             (u32)plat->dma330.dst_addr,
> > +             data_size_byte,
> > +             plat->brst_size);
> > +
> > +       debug("brst_len=%d singles_brst_size=2^%d\n", plat-
> > >brst_len,
> > +             plat->dma330.single_brst_size);
> > +
> > +       /* brst_size = 2 ^ plat->brst_size */
> > +       brst_size = 1 << plat->brst_size;
> > +
> > +       /* Fool proof checking */
> > +       if (plat->brst_size < 0 || plat->brst_size >
> > +               plat->max_brst_size) {
> > +               debug("ERROR DMA330: brst_size must 0-%d (not
> > %d)\n",
> > +                       plat->max_brst_size, plat->brst_size);
> > +               return -EINVAL;
> > +       }
> > +       if (plat->dma330.single_brst_size < 0 ||
> > +               plat->dma330.single_brst_size > plat-
> > >max_brst_size) {
> > +               debug("ERROR DMA330 : single_brst_size must 0-%d
> > (not %d)\n",
> > +                       plat->max_brst_size, plat-
> > >dma330.single_brst_size);
> > +               return -EINVAL;
> > +       }
> > +       if (plat->brst_len < 1 || plat->brst_len > 16) {
> > +               debug("ERROR DMA330 : brst_len must 1-16 (not
> > %d)\n",
> > +                       plat->brst_len);
> > +               return -EINVAL;
> > +       }
> > +       if (plat->dma330.src_addr & (brst_size - 1)) {
> > +               debug("ERROR DMA330 : Source address unaligned\n");
> > +               return -EINVAL;
> > +       }
> > +       if (plat->dma330.dst_addr & (brst_size - 1)) {
> > +               debug("ERROR DMA330 : Destination address
> > unaligned\n");
> > +               return -EINVAL;
> > +       }
> > +
> > +       /* Setup the command list */
> > +       /* DMAMOV SAR, x->src_addr */
> > +       off += _emit_mov(&buf[off], SAR, plat->dma330.src_addr);
> > +       /* DMAMOV DAR, x->dst_addr */
> > +       off += _emit_mov(&buf[off], DAR, plat->dma330.dst_addr);
> > +       /* DMAFLUSHP P(periheral_id) */
> > +       if (plat->dma330.transfer_type != DMA_MEM_TO_MEM)
> > +               off += _emit_flushp(&buf[off], plat-
> > >dma330.peripheral_id);
> > +
> > +       /* Preparing the CCR value */
> > +       if (plat->dma330.transfer_type == DMA_MEM_TO_DEV) {
> > +               /* Disable auto increment */
> > +               reqcfg.dst_inc = 0;
> > +               /* Enable auto increment */
> > +               reqcfg.src_inc = 1;
> > +       } else if (plat->dma330.transfer_type == DMA_DEV_TO_MEM) {
> > +               reqcfg.dst_inc = 1;
> > +               reqcfg.src_inc = 0;
> > +       } else {
> > +               /* DMA_MEM_TO_MEM */
> > +               reqcfg.dst_inc = 1;
> > +               reqcfg.src_inc = 1;
> > +       }
> > +
> > +       if (!plat->dma330.secure)
> > +               reqcfg.nonsecure = 1; /* Non Secure mode */
> > +       else
> > +               reqcfg.nonsecure = 0; /* Secure mode */
> > +
> > +       if (plat->dma330.enable_cache1 == 0) {
> > +               /* Noncacheable but bufferable */
> > +               reqcfg.dcctl = 0x1;
> > +               reqcfg.scctl = 0x1;
> > +       } else {
> > +               if (plat->dma330.transfer_type == DMA_MEM_TO_DEV) {
> > +                       reqcfg.dcctl = 0x1;
> > +                       /* Cacheable write back */
> > +                       reqcfg.scctl = 0x7;
> > +               } else if (plat->dma330.transfer_type ==
> > DMA_DEV_TO_MEM) {
> > +                       reqcfg.dcctl = 0x7;
> > +                       reqcfg.scctl = 0x1;
> > +               } else {
> > +                       reqcfg.dcctl = 0x7;
> > +                       reqcfg.scctl = 0x7;
> > +               }
> > +       }
> > +       /* 1 - Privileged  */
> > +       reqcfg.privileged = 1;
> > +       /* 0 - Data access */
> > +       reqcfg.insnaccess = 0;
> > +       /* 0 - No endian swap */
> I am not keen on these comments. The struct members should be
> documented when the struct is declared, not here.
> 
Okay.
> > 
> > +       reqcfg.swap = 0;
> > +       /* DMA burst length */
> > +       reqcfg.brst_len = plat->brst_len;
> > +       /* DMA burst size */
> > +       reqcfg.brst_size = plat->brst_size;
> > +       /* Preparing the CCR value */
> > +       ccr = _prepare_ccr(&reqcfg);
> > +       /* DMAMOV CCR, ccr */
> > +       off += _emit_mov(&buf[off], CCR, ccr);
> > +
> > +       /* BURST */
> > +       /* Can initiate a burst? */
> These two comments should be joined
> 
Okay. Actually comments helping to track the operation easily.
> > 
> > +       while (data_size_byte >= brst_size * plat->brst_len) {
> > +               lcnt0 = data_size_byte / (brst_size * plat-
> > >brst_len);
> > +               lcnt1 = 0;
> > +               if (lcnt0 >= 256 * 256) {
> > +                       lcnt0 = 256;
> > +                       lcnt1 = 256;
> > +               } else if (lcnt0 >= 256) {
> > +                       lcnt1 = lcnt0 / 256;
> > +                       lcnt0 = 256;
> > +               }
> > +               data_size_byte = data_size_byte -
> > +                       (brst_size * plat->brst_len * lcnt0 *
> > lcnt1);
> > +
> > +               debug("Transferring 0x%08x Remain 0x%08x\n",
> > (brst_size *
> > +                       plat->brst_len * lcnt0 * lcnt1),
> > data_size_byte);
> > +               debug("Running burst - brst_size=2^%d, brst_len=%d,
> > ",
> > +                     plat->brst_size, plat->brst_len);
> > +               debug("lcnt0=%d, lcnt1=%d\n", lcnt0, lcnt1);
> > +
> > +               if (lcnt1) {
> > +                       /* DMALP1 */
> > +                       off += _emit_lp(&buf[off], 1, lcnt1);
> > +                       loopjmp1 = off;
> > +               }
> > +               /* DMALP0 */
> What does this comment mean?
> 
This means below _emit_lp would insert the microcode DMALP(looping)
into buffer[off]
> > 
> > +               off += _emit_lp(&buf[off], 0, lcnt0);
> > +               loopjmp0 = off;
> > +               /* DMAWFP periheral_id, burst */
> > +               if (plat->dma330.transfer_type != DMA_MEM_TO_MEM)
> > +                       off += _emit_wfp(&buf[off], BURST,
> > +                               plat->dma330.peripheral_id);
> > +               /* DMALD */
> > +               off += _emit_ld(&buf[off], ALWAYS);
> > +
> > +               WATCHDOG_RESET();
> > +
> > +               /* DMARMB */
> > +               off += _emit_rmb(&buf[off]);
> > +               /* DMASTPB peripheral_id */
> > +               if (plat->dma330.transfer_type != DMA_MEM_TO_MEM)
> > +                       off += _emit_stp(&buf[off], BURST,
> > +                               plat->dma330.peripheral_id);
> > +               else
> > +                       off += _emit_st(&buf[off], ALWAYS);
> > +               /* DMAWMB */
> > +               off += _emit_wmb(&buf[off]);
> > +               /* DMALP0END */
> > +               struct _arg_lpend lpend;
> > +
> > +               lpend.cond = ALWAYS;
> > +               lpend.forever = 0;
> > +               /* Loop cnt 0 */
> > +               lpend.loop = 0;
> > +               lpend.bjump = off - loopjmp0;
> > +               off += _emit_lpend(&buf[off], &lpend);
> > +               /* DMALP1END */
> > +               if (lcnt1) {
> > +                       struct _arg_lpend lpend;
> > +
> > +                       lpend.cond = ALWAYS;
> > +                       lpend.forever = 0;
> > +                       lpend.loop = 1;         /* loop cnt 1*/
> > +                       lpend.bjump = off - loopjmp1;
> > +                       off += _emit_lpend(&buf[off], &lpend);
> > +               }
> > +               /* Ensure the microcode don't exceed buffer size */
> > +               if (off > plat->buf_size) {
> > +                       debug("ERROR DMA330 : Exceed buffer
> > size\n");
> > +                       return -ENOMEM;
> > +               }
> > +       }
> > +
> > +       /* SINGLE */
> > +       brst_len = 1;
> > +       /* brst_size = 2 ^ plat->dma330.single_brst_size; */
> > +       brst_size = (1 << plat->dma330.single_brst_size);
> > +       lcnt0 = data_size_byte / (brst_size * brst_len);
> > +
> > +       /* Ensure all data will be transferred */
> > +       data_size_byte = data_size_byte -
> > +               (brst_size * brst_len * lcnt0);
> > +       if (data_size_byte) {
> > +               debug("ERROR DMA330 : Detected the possibility of
> > ");
> > +               debug("untransfered data. Please ensure correct
> > single ");
> > +               debug("burst size\n");
> > +       }
> > +
> > +       if (lcnt0) {
> > +               debug("Transferring 0x%08x Remain 0x%08x\n",
> > (brst_size *
> > +                       brst_len * lcnt0 * lcnt1), data_size_byte);
> > +               debug("Running single - brst_size=2^%d,
> > brst_len=%d, ",
> > +                     brst_size, brst_len);
> > +               debug("lcnt0=%d\n", lcnt0);
> > +
> > +               /* Preparing the CCR value */
> > +               /* DMA burst length */
> > +               reqcfg.brst_len = brst_len;
> > +               /* DMA burst size */
> > +               reqcfg.brst_size = brst_size;
> > +               ccr = _prepare_ccr(&reqcfg);
> > +               /* DMAMOV CCR, ccr */
> > +               off += _emit_mov(&buf[off], CCR, ccr);
> > +
> > +               /* DMALP0 */
> > +               off += _emit_lp(&buf[off], 0, lcnt0);
> > +               loopjmp0 = off;
> > +               /* DMAWFP peripheral_id, single */
> > +               if (plat->dma330.transfer_type != DMA_MEM_TO_MEM)
> > +                       off += _emit_wfp(&buf[off], SINGLE,
> > +                               plat->dma330.peripheral_id);
> > +
> > +               /* DMALD */
> > +               off += _emit_ld(&buf[off], ALWAYS);
> > +               /* DMARMB */
> > +               off += _emit_rmb(&buf[off]);
> > +               /* DMASTPS peripheral_id */
> > +               if (plat->dma330.transfer_type != DMA_MEM_TO_MEM)
> > +                       off += _emit_stp(&buf[off], SINGLE,
> > +                               plat->dma330.peripheral_id);
> > +               else
> > +                       off += _emit_st(&buf[off], ALWAYS);
> > +
> > +               /* DMAWMB */
> > +               off += _emit_wmb(&buf[off]);
> > +               /* DMALPEND */
> > +               struct _arg_lpend lpend1;
> > +
> > +               lpend1.cond = ALWAYS;
> > +               lpend1.forever = 0;
> > +               /* loop cnt 0 */
> > +               lpend1.loop = 0;
> > +               lpend1.bjump = off - loopjmp0;
> > +               off += _emit_lpend(&buf[off], &lpend1);
> > +               /* Ensure the microcode don't exceed buffer size */
> > +               if (off > plat->buf_size) {
> > +                       puts("ERROR DMA330 : Exceed buffer
> > size\n");
> > +                       return -ENOMEM;
> > +               }
> > +       }
> > +
> > +       /* DMAEND */
> > +       off += _emit_end(&buf[off]);
> > +
> > +       ret = dma330_transfer_start(plat);
> > +       if (ret)
> > +               return ret;
> > +
> > +       return dma330_transfer_finish(plat);
> > +}
> > +
> > +/**
> > + * dma330_transfer_zeroes - DMA transfer zeros.
> > + *
> > + * @plat: Pointer to struct dma_dma330_platdata.
> > + *
> > + * Used to write zeros to a memory chunk for memory scrubbing
> > purpose.
> > + *
> > + * Return: Negative value for error or not successful. 0 for
> > successful.
> > + */
> > +static int dma330_transfer_zeroes_setup(struct dma_dma330_platdata
> > *plat)
> Can this function be combined with the above somehow? It seems like a
> lot of duplicate code.
> 
Let me see how to merge them.
> > 
> > +{
> > +       /* Variable declaration */
> > +       /* Buffer offset clear to 0 */
> > +       int off = 0;
> > +       int ret = 0;
> > +       /* For DMALPEND */
> > +       u32 loopjmp0, loopjmp1;
> > +       /* Loop count 0 */
> > +       u32 lcnt0 = 0;
> > +       /* Loop count 1 */
> > +       u32 lcnt1 = 0;
> > +       u32 brst_size = 0;
> > +       u32 brst_len = 0;
> > +       u32 data_size_byte = plat->dma330.size_byte;
> > +       /* Strong order memory is required to store microcode
> > command list */
> > +       u8 *buf = (u8 *)plat->dma330.buf;
> > +       /* Channel Control Register */
> > +       u32 ccr = 0;
> > +       struct dma330_reqcfg reqcfg;
> > +
> > +       if (!buf) {
> > +               debug("ERROR DMA330 : DMA Microcode buffer pointer
> > is NULL\n");
> > +               return -EINVAL;
> > +       }
> > +
> > +       debug("INFO: Write zeros -> ");
> > +       debug("0x%x%x size=0x%08x\n",
> > +             (u32)(plat->dma330.dst_addr >> 32),
> > +             (u32)plat->dma330.dst_addr,
> > +             data_size_byte);
> > +
> > +       plat->dma330.single_brst_size = 1;
> > +
> > +       /* burst_size = 2 ^ plat->brst_size */
> > +       brst_size = 1 << plat->brst_size;
> > +
> > +       /* Setup the command list */
> > +       /* DMAMOV DAR, x->dst_addr */
> > +       off += _emit_mov(&buf[off], DAR, plat->dma330.dst_addr);
> > +
> > +       /* Preparing the CCR value */
> > +       /* Enable auto increment */
> > +       reqcfg.dst_inc = 1;
> > +       /* Disable auto increment (not applicable) */
> > +       reqcfg.src_inc = 0;
> > +       /* Noncacheable but bufferable */
> > +       reqcfg.dcctl = 0x1;
> > +       /* Noncacheable and bufferable */
> > +       reqcfg.scctl = 0x1;
> > +       /* 1 - Privileged  */
> > +       reqcfg.privileged = 1;
> > +       /* 0 - Data access */
> > +       reqcfg.insnaccess = 0;
> > +       /* 0 - No endian swap */
> > +       reqcfg.swap = 0;
> > +
> > +       if (!plat->dma330.secure)
> > +               reqcfg.nonsecure = 1; /* Non Secure mode */
> > +       else
> > +               reqcfg.nonsecure = 0; /* Secure mode */
> > +
> > +       /* DMA burst length */
> > +       reqcfg.brst_len = plat->brst_len;
> > +       /* DMA burst size */
> > +       reqcfg.brst_size = plat->brst_size;
> > +       /* Preparing the CCR value */
> > +       ccr = _prepare_ccr(&reqcfg);
> > +       /* DMAMOV CCR, ccr */
> > +       off += _emit_mov(&buf[off], CCR, ccr);
> > +
> > +       /* BURST */
> > +       /* Can initiate a burst? */
> > +       while (data_size_byte >= brst_size * plat->brst_len) {
> > +               lcnt0 = data_size_byte / (brst_size * plat-
> > >brst_len);
> > +               lcnt1 = 0;
> > +               if (lcnt0 >= 256 * 256) {
> > +                       lcnt0 = 256;
> > +                       lcnt1 = 256;
> > +               } else if (lcnt0 >= 256) {
> > +                       lcnt1 = lcnt0 / 256;
> > +                       lcnt0 = 256;
> > +               }
> > +
> > +               data_size_byte = data_size_byte -
> > +                       (brst_size * plat->brst_len * lcnt0 *
> > lcnt1);
> > +
> > +               debug("Transferring 0x%08x Remain 0x%08x\n",
> > (brst_size *
> > +                       plat->brst_len * lcnt0 * lcnt1),
> > data_size_byte);
> > +               debug("Running burst - brst_size=2^%d,
> > brst_len=%d,",
> > +                     plat->brst_size, plat->brst_len);
> > +               debug("lcnt0=%d, lcnt1=%d\n", lcnt0, lcnt1);
> > +
> > +               if (lcnt1) {
> > +                       /* DMALP1 */
> > +                       off += _emit_lp(&buf[off], 1, lcnt1);
> > +                       loopjmp1 = off;
> > +               }
> > +               /* DMALP0 */
> > +               off += _emit_lp(&buf[off], 0, lcnt0);
> > +               loopjmp0 = off;
> > +               /* DMALSTZ */
> > +               off += _emit_stz(&buf[off]);
> > +
> > +               WATCHDOG_RESET();
> > +
> > +               /* DMALP0END */
> > +               struct _arg_lpend lpend;
> > +
> > +               lpend.cond = ALWAYS;
> > +               lpend.forever = 0;
> > +               /* Loop cnt 0 */
> > +               lpend.loop = 0;
> > +               lpend.bjump = off - loopjmp0;
> > +               off += _emit_lpend(&buf[off], &lpend);
> > +               /* DMALP1END */
> > +               if (lcnt1) {
> > +                       struct _arg_lpend lpend;
> > +
> > +                       lpend.cond = ALWAYS;
> > +                       lpend.forever = 0;
> > +                       /* Loop cnt 1*/
> > +                       lpend.loop = 1;
> > +                       lpend.bjump = off - loopjmp1;
> > +                       off += _emit_lpend(&buf[off], &lpend);
> > +               }
> > +               /* Ensure the microcode don't exceed buffer size */
> > +               if (off > plat->buf_size) {
> > +                       printf("off = %d\n", off);
> > +                       debug("ERROR DMA330 : Exceed buffer size
> > off %d\n",
> > +                             off);
> > +                       return -ENOMEM;
> > +               }
> > +       }
> > +
> > +       /* SINGLE */
> > +       brst_len = 1;
> > +       /* brst_size = 2 ^ plat->dma330.single_brst_size */
> > +       brst_size = (1 << plat->dma330.single_brst_size);
> > +       lcnt0 = data_size_byte / (brst_size * brst_len);
> > +
> > +       /* ensure all data will be transferred */
> > +       data_size_byte = data_size_byte -
> > +               (brst_size * brst_len * lcnt0);
> > +       if (data_size_byte) {
> > +               debug("ERROR DMA330 : Detected the possibility of
> > ");
> > +               debug("untransfered data. Please ensure correct
> > single ");
> > +               debug("burst size\n");
> > +       }
> > +
> > +       if (lcnt0) {
> > +               debug("Transferring 0x%08x Remain 0x%08x\n",
> > (brst_size *
> > +                    brst_len * lcnt0), data_size_byte);
> > +               debug("Running single - brst_size=2^%d,
> > brst_len=%d, ",
> > +                     brst_size, brst_len);
> > +               debug("lcnt0=%d\n", lcnt0);
> > +
> > +               /* Preparing the CCR value */
> > +               /* DMA burst length */
> > +               reqcfg.brst_len = brst_len;
> > +               /* DMA burst size */
> > +               reqcfg.brst_size = brst_size;
> > +               ccr = _prepare_ccr(&reqcfg);
> > +               /* DMAMOV CCR, ccr */
> > +               off += _emit_mov(&buf[off], CCR, ccr);
> > +
> > +               /* DMALP0 */
> > +               off += _emit_lp(&buf[off], 0, lcnt0);
> > +               loopjmp0 = off;
> > +               /* DMALSTZ */
> > +               off += _emit_stz(&buf[off]);
> > +               /* DMALPEND */
> > +               struct _arg_lpend lpend1;
> > +
> > +               lpend1.cond = ALWAYS;
> > +               lpend1.forever = 0;
> > +               /* Loop cnt 0 */
> > +               lpend1.loop = 0;
> > +               lpend1.bjump = off - loopjmp0;
> > +               off += _emit_lpend(&buf[off], &lpend1);
> > +               /* Ensure the microcode don't exceed buffer size */
> > +               if (off > plat->buf_size) {
> > +                       debug("ERROR DMA330 : Exceed buffer
> > size\n");
> > +                       return -ENOMEM;
> > +               }
> > +       }
> > +
> > +       /* DMAEND */
> > +       off += _emit_end(&buf[off]);
> > +
> > +       ret = dma330_transfer_start(plat);
> > +       if (ret)
> > +               return ret;
> > +
> > +       return dma330_transfer_finish(plat);
> > +}
> > +
> > +static int dma330_transfer_zeroes(struct udevice *dev, void *dst,
> > size_t len)
> > +{
> > +       struct dma_dma330_platdata *plat = dev->platdata;
> > +       int ret = 0;
> > +
> > +       /* If DMA access is set to secure, base change to DMA
> > secure base */
> > +       if (plat->dma330.secure)
> > +               plat->base += 0x1000;
> What is this? I suggest you set up the secure base separately in
> 'plat', e.g. with a base_secure member. You should not change
> platform
> data while running.
> 
> You can pass the base address to dma330_transfer_zeroes_setup,
> perhaps.
> 
Okay.
> > 
> > +
> > +       plat->dma330.dst_addr = (phys_size_t)(uintptr_t)dst;
> > +       plat->dma330.size_byte = len;
> > +
> > +       ret = dma330_transfer_zeroes_setup(plat);
> > +
> > +       /* Revert back to non secure DMA base */
> > +       if (plat->dma330.secure)
> > +               plat->base -= 0x1000;
> > +
> > +       return ret;
> > +}
> > +
> > +static int dma330_transfer(struct udevice *dev, int direction,
> > void *dst,
> > +                         void *src, size_t len)
> > +{
> > +       struct dma_dma330_platdata *plat = dev->platdata;
> > +       int ret = 0;
> > +
> > +       /* If DMA access is set to secure, base change to DMA
> > secure base */
> > +       if (plat->dma330.secure)
> > +               plat->base += 0x1000;
> Same as above
> 
Okay.
> > 
> > +
> > +       plat->dma330.dst_addr = (phys_size_t)(uintptr_t)dst;
> > +       plat->dma330.src_addr = (phys_size_t)(uintptr_t)src;
> > +       plat->dma330.size_byte = len;
> > +
> > +       switch (direction) {
> > +       case DMA_MEM_TO_MEM:
> > +               plat->dma330.transfer_type =
> > DMA_SUPPORTS_MEM_TO_MEM;
> > +               break;
> > +       case DMA_MEM_TO_DEV:
> > +               plat->dma330.transfer_type =
> > DMA_SUPPORTS_MEM_TO_DEV;
> > +               break;
> > +       case DMA_DEV_TO_MEM:
> > +               plat->dma330.transfer_type =
> > DMA_SUPPORTS_DEV_TO_MEM;
> > +               break;
> > +       }
> > +
> > +       ret = dma330_transfer_setup(plat);
> > +
> > +       /* Revert back to non secure DMA base */
> > +       if (plat->dma330.secure)
> > +               plat->base -= 0x1000;
> > +
> > +       return ret;
> > +}
> > +
> > +static int dma330_ofdata_to_platdata(struct udevice *dev)
> > +{
> > +       struct dma_dma330_platdata *plat = dev->platdata;
> > +       const void *blob = gd->fdt_blob;
> > +       int node = dev_of_offset(dev);
> > +
> > +       plat->base = (void __iomem *)devfdt_get_addr(dev);
> dev_read_addr()
> 
Okay.
> > 
> > 
> > +       plat->max_brst_size = fdtdec_get_uint(blob, node, "dma-max-
> > burst-size",
> > +                                             2);
> Use dev_read API please (live tree)
> 
Okay.
> > +       plat->brst_size = fdtdec_get_uint(blob, node, "dma-burst-
> > size", 2);
> > +       plat->brst_len = fdtdec_get_uint(blob, node, "dma-burst-
> > length", 2);
> > +
> > +       return 0;
> > +}
> > +
> > +static int dma330_probe(struct udevice *adev)
> > +{
> > +       struct dma_dev_priv *uc_priv = dev_get_uclass_priv(adev);
> > +
> > +       uc_priv->supported = (DMA_SUPPORTS_MEM_TO_MEM |
> > +                            DMA_SUPPORTS_MEM_TO_DEV |
> > +                            DMA_SUPPORTS_DEV_TO_MEM);
> > +       return 0;
> > +}
> > +
> > +static const struct dma_ops dma330_ops = {
> > +       .transfer = dma330_transfer,
> > +       .transfer_zeroes = dma330_transfer_zeroes,
> > +};
> > +
> > +static const struct udevice_id dma330_ids[] = {
> > +       { .compatible = "arm,pl330" },
> > +       { .compatible = "arm,dma330" },
> > +       { /* sentinel */ }
> > +};
> > +
> > +U_BOOT_DRIVER(dma_dma330) = {
> > +       .name   = "dma_dma330",
> > +       .id     = UCLASS_DMA,
> > +       .of_match = dma330_ids,
> > +       .ops    = &dma330_ops,
> > +       .ofdata_to_platdata = dma330_ofdata_to_platdata,
> > +       .probe = dma330_probe,
> > +       .platdata_auto_alloc_size = sizeof(struct
> > dma_dma330_platdata),
> > +};
> > diff --git a/include/dma330.h b/include/dma330.h
> > new file mode 100644
> > index 0000000..c054bf2
> > --- /dev/null
> > +++ b/include/dma330.h
> > @@ -0,0 +1,136 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Copyright (C) 2018 Intel Corporation <www.intel.com>
> > + */
> > +
> > +#include <dma.h>
> > +#include <linux/sizes.h>
> > +
> > +#ifndef __DMA330_CORE_H
> > +#define __DMA330_CORE_H
> > +
> > +#define DMA330_MAX_CHAN                8
> > +#define DMA330_MAX_IRQS                32
> > +#define DMA330_MAX_PERI                32
> > +
> > +#define DMA330_STATE_STOPPED           BIT(0)
> > +#define DMA330_STATE_EXECUTING         BIT(1)
> > +#define DMA330_STATE_WFE               BIT(2)
> > +#define DMA330_STATE_FAULTING          BIT(3)
> > +#define        DMA330_STATE_COMPLETING         BIT(4)
> > +#define DMA330_STATE_WFP               BIT(5)
> > +#define DMA330_STATE_KILLING           BIT(6)
> > +#define DMA330_STATE_FAULT_COMPLETING  BIT(7)
> > +#define DMA330_STATE_CACHEMISS         BIT(8)
> > +#define DMA330_STATE_UPDTPC            BIT(9)
> > +#define DMA330_STATE_ATBARRIER         BIT(10)
> > +#define DMA330_STATE_QUEUEBUSY         BIT(11))
> > +#define DMA330_STATE_INVALID           BIT(15)
> > +
> > +enum dma330_srccachectrl {
> > +       SCCTRL0 = 0,    /* Noncacheable and nonbufferable */
> > +       SCCTRL1,        /* Bufferable only */
> > +       SCCTRL2,        /* Cacheable, but do not allocate */
> > +       SCCTRL3,        /* Cacheable and bufferable, but do not
> > allocate */
> > +       SINVALID1,
> > +       SINVALID2,
> > +       SCCTRL6,        /* Cacheable write-through, allocate on
> > reads only */
> > +       SCCTRL7,        /* Cacheable write-back, allocate on reads
> > only */
> > +};
> > +
> > +enum dma330_dstcachectrl {
> > +       DCCTRL0 = 0,    /* Noncacheable and nonbufferable */
> > +       DCCTRL1,        /* Bufferable only */
> > +       DCCTRL2,        /* Cacheable, but do not allocate */
> > +       DCCTRL3,        /* Cacheable and bufferable, but do not
> > allocate */
> > +       DINVALID1 = 8,
> > +       DINVALID2,
> > +       DCCTRL6,        /* Cacheable write-through, allocate on
> > writes only */
> > +       DCCTRL7,        /* Cacheable write-back, allocate on writes
> > only */
> > +};
> > +
> > +enum dma330_byteswap {
> > +       SWAP_NO = 0,
> > +       SWAP_2,
> > +       SWAP_4,
> > +       SWAP_8,
> > +       SWAP_16,
> > +};
> > +
> > +/**
> > + * dma330_reqcfg - Request Configuration.
> > + *
> > + * The DMA330 core does not modify this and uses the last
> > + * working configuration if the request doesn't provide any.
> > + *
> > + * The Client may want to provide this info only for the
> > + * first request and a request with new settings.
> > + */
> > +struct dma330_reqcfg {
> > +       /* Address Incrementing */
> > +       u8 dst_inc;
> > +       u8 src_inc;
> > +
> > +       /*
> > +        * For now, the SRC & DST protection levels
> > +        * and burst size/length are assumed same.
> > +        */
> > +       u8 nonsecure;
> > +       u8 privileged;
> > +       u8 insnaccess;
> > +       u8 brst_len;
> > +       u8 brst_size; /* in power of 2 */
> > +
> > +       enum dma330_dstcachectrl dcctl;
> > +       enum dma330_srccachectrl scctl;
> > +       enum dma330_byteswap swap;
> > +};
> > +
> > +/**
> > + * dma330_transfer_struct - Structure to be passed in for
> > dma330_transfer_x.
> > + *
> > + * @channel0_manager1: Switching configuration on DMA channel or
> > DMA manager.
> > + * @channel_num: Channel number assigned, valid from 0 to 7.
> > + * @src_addr: Address to transfer from / source.
> > + * @dst_addr: Address to transfer to / destination.
> > + * @size_byte: Number of bytes to be transferred.
> > + * @brst_size: Valid from 0 - 4,
> > + *            where 0 = 1 (2 ^ 0) bytes and 3 = 16 bytes (2 ^ 4).
> > + * @max_brst_size: Max transfer size (from 0 - 4).
> > + * @single_brst_size: Single transfer size (from 0 - 4).
> > + * @brst_len: Valid from 1 - 16 where each burst can transfer 1 -
> > 16
> > + *           Data chunk (each chunk size equivalent to brst_size).
> > + * @peripheral_id: Assigned peripheral_id, valid from 0 to 31.
> > + * @transfer_type: MEM2MEM, MEM2PERIPH or PERIPH2MEM.
> > + * @enable_cache1: 1 for cache enabled for memory
> > + *                (cacheable and bufferable, but do not allocate).
> > + * @buf: Buffer handler which will point to the memory
> > + *      allocated for dma microcode
> > + * @secure: Set DMA channel in secure mode.
> This is a good way to document structs. Please do it for the others.
> 
> > 
> > + *
> > + * Description of the structure.
> Yes?
> 
Sure.
> > 
> > + */
> > +struct dma330_transfer_struct {
> > +       u32 channel0_manager1;
> > +       u32 channel_num;
> > +       phys_size_t src_addr;
> > +       phys_size_t dst_addr;
> > +       u32 size_byte;
> > +       u32 single_brst_size;
> > +       u32 peripheral_id;
> > +       u32 transfer_type;
> > +       u32 enable_cache1;
> > +       u32 *buf;
> > +       u8 secure;
> > +};
> > +
> > +struct dma_dma330_platdata {
> > +       void __iomem *base;
> > +       u32 buf_size;
> > +       u32 max_brst_size;
> > +       u32 brst_size;
> > +       u32 brst_len;
> > +       struct dma330_transfer_struct dma330;
> > +};
> > +
> > +#endif /* __DMA330_CORE_H */
> > --
> > 2.2.0
> > 
> Regards,
> Simon
diff mbox series

Patch

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 4ee6afa..6e77e07 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -2,7 +2,7 @@  menu "DMA Support"
 
 config DMA
 	bool "Enable Driver Model for DMA drivers"
-	depends on DM
+	depends on DM || SPL_DM
 	help
 	  Enable driver model for DMA. DMA engines can do
 	  asynchronous data transfers without involving the host
@@ -34,4 +34,11 @@  config APBH_DMA_BURST8
 
 endif
 
+config DMA330_DMA
+	bool "PL330/DMA-330 DMA Controller(DMAC) driver"
+	depends on DMA
+	help
+	 Enable the DMA controller driver for both PL330 and
+	 DMA-330 products.
+
 endmenu # menu "DMA Support"
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 4eaef8a..bfad0dd 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -11,3 +11,4 @@  obj-$(CONFIG_FSL_DMA) += fsl_dma.o
 obj-$(CONFIG_TI_KSNAV) += keystone_nav.o keystone_nav_cfg.o
 obj-$(CONFIG_TI_EDMA3) += ti-edma3.o
 obj-$(CONFIG_DMA_LPC32XX) += lpc32xx_dma.o
+obj-$(CONFIG_DMA330_DMA) += dma330.o
diff --git a/drivers/dma/dma330.c b/drivers/dma/dma330.c
new file mode 100644
index 0000000..66575d8
--- /dev/null
+++ b/drivers/dma/dma330.c
@@ -0,0 +1,1514 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Intel Corporation <www.intel.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <dma330.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <wait_bit.h>
+#include <linux/unaligned/access_ok.h>
+
+/* Register and Bit field Definitions */
+
+/* DMA Status */
+#define DS			0x0
+#define DS_ST_STOP		0x0
+#define DS_ST_EXEC		0x1
+#define DS_ST_CMISS		0x2
+#define DS_ST_UPDTPC		0x3
+#define DS_ST_WFE		0x4
+#define DS_ST_ATBRR		0x5
+#define DS_ST_QBUSY		0x6
+#define DS_ST_WFP		0x7
+#define DS_ST_KILL		0x8
+#define DS_ST_CMPLT		0x9
+#define DS_ST_FLTCMP		0xe
+#define DS_ST_FAULT		0xf
+
+/* DMA Program Count register */
+#define DPC			0x4
+/* Interrupt Enable register */
+#define INTEN			0x20
+/* event-Interrupt Raw Status register */
+#define ES			0x24
+/* Interrupt Status register */
+#define INTSTATUS		0x28
+/* Interrupt Clear register */
+#define INTCLR			0x2c
+/* Fault Status DMA Manager register */
+#define FSM			0x30
+/* Fault Status DMA Channel register */
+#define FSC			0x34
+/* Fault Type DMA Manager register */
+#define FTM			0x38
+
+/* Fault Type DMA Channel register */
+#define _FTC			0x40
+#define FTC(n)			(_FTC + (n) * 0x4)
+
+/* Channel Status register */
+#define _CS			0x100
+#define CS(n)			(_CS + (n) * 0x8)
+#define CS_CNS			BIT(21)
+
+/* Channel Program Counter register */
+#define _CPC			0x104
+#define CPC(n)			(_CPC + (n) * 0x8)
+
+/* Source Address register */
+#define _SA			0x400
+#define SA(n)			(_SA + (n) * 0x20)
+
+/* Destination Address register */
+#define _DA			0x404
+#define DA(n)			(_DA + (n) * 0x20)
+
+/* Channel Control register */
+#define _CC			0x408
+#define CC(n)			(_CC + (n) * 0x20)
+
+/* Channel Control register (CCR) Setting */
+#define CC_SRCINC		BIT(0)
+#define CC_DSTINC		BIT(14)
+#define CC_SRCPRI		BIT(8)
+#define CC_DSTPRI		BIT(22)
+#define CC_SRCNS		BIT(9)
+#define CC_DSTNS		BIT(23)
+#define CC_SRCIA		BIT(10)
+#define CC_DSTIA		BIT(24)
+#define CC_SRCBRSTLEN_SHFT	4
+#define CC_DSTBRSTLEN_SHFT	18
+#define CC_SRCBRSTSIZE_SHFT	1
+#define CC_DSTBRSTSIZE_SHFT	15
+#define CC_SRCCCTRL_SHFT	11
+#define CC_SRCCCTRL_MASK	0x7
+#define CC_DSTCCTRL_SHFT	25
+#define CC_DRCCCTRL_MASK	0x7
+#define CC_SWAP_SHFT		28
+
+/* Loop Counter 0 register */
+#define _LC0			0x40c
+#define LC0(n)			(_LC0 + (n) * 0x20)
+
+/* Loop Counter 1 register */
+#define _LC1			0x410
+#define LC1(n)			(_LC1 + (n) * 0x20)
+
+/* Debug Status register */
+#define DBGSTATUS		0xd00
+#define DBG_BUSY		BIT(0)
+
+/* Debug Command register */
+#define DBGCMD			0xd04
+/* Debug Instruction 0 register */
+#define DBGINST0		0xd08
+/* Debug Instruction 1 register */
+#define DBGINST1		0xd0c
+
+/* Configuration register */
+#define CR0			0xe00
+#define CR1			0xe04
+#define CR2			0xe08
+#define CR3			0xe0c
+#define CR4			0xe10
+#define CRD			0xe14
+
+/* Peripheral Identification register */
+#define PERIPH_ID		0xfe0
+/* Component Identification register */
+#define PCELL_ID		0xff0
+
+/* Configuration register value */
+#define CR0_PERIPH_REQ_SET	BIT(0)
+#define CR0_BOOT_EN_SET		BIT(1)
+#define CR0_BOOT_MAN_NS		BIT(2)
+#define CR0_NUM_CHANS_SHIFT	4
+#define CR0_NUM_CHANS_MASK	0x7
+#define CR0_NUM_PERIPH_SHIFT	12
+#define CR0_NUM_PERIPH_MASK	0x1f
+#define CR0_NUM_EVENTS_SHIFT	17
+#define CR0_NUM_EVENTS_MASK	0x1f
+
+/* Configuration register value */
+#define CR1_ICACHE_LEN_SHIFT		0
+#define CR1_ICACHE_LEN_MASK		0x7
+#define CR1_NUM_ICACHELINES_SHIFT	4
+#define CR1_NUM_ICACHELINES_MASK	0xf
+
+/* Configuration register value */
+#define CRD_DATA_WIDTH_SHIFT	0
+#define CRD_DATA_WIDTH_MASK	0x7
+#define CRD_WR_CAP_SHIFT	4
+#define CRD_WR_CAP_MASK		0x7
+#define CRD_WR_Q_DEP_SHIFT	8
+#define CRD_WR_Q_DEP_MASK	0xf
+#define CRD_RD_CAP_SHIFT	12
+#define CRD_RD_CAP_MASK		0x7
+#define CRD_RD_Q_DEP_SHIFT	16
+#define CRD_RD_Q_DEP_MASK	0xf
+#define CRD_DATA_BUFF_SHIFT	20
+#define CRD_DATA_BUFF_MASK	0x3ff
+
+/* Microcode opcode value */
+#define CMD_DMAADDH		0x54
+#define CMD_DMAEND		0x00
+#define CMD_DMAFLUSHP		0x35
+#define CMD_DMAGO		0xa0
+#define CMD_DMALD		0x04
+#define CMD_DMALDP		0x25
+#define CMD_DMALP		0x20
+#define CMD_DMALPEND		0x28
+#define CMD_DMAKILL		0x01
+#define CMD_DMAMOV		0xbc
+#define CMD_DMANOP		0x18
+#define CMD_DMARMB		0x12
+#define CMD_DMASEV		0x34
+#define CMD_DMAST		0x08
+#define CMD_DMASTP		0x29
+#define CMD_DMASTZ		0x0c
+#define CMD_DMAWFE		0x36
+#define CMD_DMAWFP		0x30
+#define CMD_DMAWMB		0x13
+
+/* the size of opcode plus opcode required settings */
+#define SZ_DMAADDH		3
+#define SZ_DMAEND		1
+#define SZ_DMAFLUSHP		2
+#define SZ_DMALD		1
+#define SZ_DMALDP		2
+#define SZ_DMALP		2
+#define SZ_DMALPEND		2
+#define SZ_DMAKILL		1
+#define SZ_DMAMOV		6
+#define SZ_DMANOP		1
+#define SZ_DMARMB		1
+#define SZ_DMASEV		2
+#define SZ_DMAST		1
+#define SZ_DMASTP		2
+#define SZ_DMASTZ		1
+#define SZ_DMAWFE		2
+#define SZ_DMAWFP		2
+#define SZ_DMAWMB		1
+#define SZ_DMAGO		6
+
+/* Use this _only_ to wait on transient states */
+#define UNTIL(t, s)	do { \
+				WATCHDOG_RESET(); \
+			} while (!(dma330_getstate(t) & (s)))
+
+/* debug message printout */
+#ifdef DEBUG
+#define DMA330_DBGCMD_DUMP(off, x...)	do { \
+						printf("%x bytes:", off); \
+						printf(x); \
+						WATCHDOG_RESET(); \
+					} while (0)
+#else
+#define DMA330_DBGCMD_DUMP(off, x...)	do {} while (0)
+#endif
+
+/* Enum declaration */
+enum dmamov_dst {
+	SAR = 0,
+	CCR,
+	DAR,
+};
+
+enum dma330_dst {
+	SRC = 0,
+	DST,
+};
+
+enum dma330_cond {
+	SINGLE,
+	BURST,
+	ALWAYS,
+};
+
+/* Structure will be used by _emit_lpend function */
+struct _arg_lpend {
+	enum dma330_cond cond;
+	int forever;
+	u32 loop;
+	u8 bjump;
+};
+
+/* Structure will be used by _emit_go function */
+struct _arg_go {
+	u8 chan;
+	u32 addr;
+	u32 ns;
+};
+
+/*
+ * _emit_end - Add opcode DMAEND into microcode (end).
+ *
+ * @buf: The buffer which stored the microcode program.
+ *
+ * Return: Size of opcode.
+ */
+static inline u32 _emit_end(u8 buf[])
+{
+	buf[0] = CMD_DMAEND;
+	DMA330_DBGCMD_DUMP(SZ_DMAEND, "\tDMAEND\n");
+	return SZ_DMAEND;
+}
+
+/*
+ * _emit_flushp - Add opcode DMAFLUSHP into microcode (flush peripheral).
+ *
+ * @buf -> The buffer which stored the microcode program.
+ * @peri -> Peripheral ID as listed in DMA NPP.
+ *
+ * Return: Size of opcode.
+ */
+static inline u32 _emit_flushp(u8 buf[], u8 peri)
+{
+	u8 *buffer = buf;
+
+	buffer[0] = CMD_DMAFLUSHP;
+	peri &= 0x1f;
+	peri <<= 3;
+	buffer[1] = peri;
+	DMA330_DBGCMD_DUMP(SZ_DMAFLUSHP, "\tDMAFLUSHP %u\n", peri >> 3);
+	return SZ_DMAFLUSHP;
+}
+
+/**
+ * _emit_ld - Add opcode DMALD into microcode (load).
+ *
+ * @buf: The buffer which stored the microcode program.
+ * @cond: Execution criteria such as single, burst or always.
+ *
+ * Return: Size of opcode.
+ */
+static inline u32 _emit_ld(u8 buf[], enum dma330_cond cond)
+{
+	buf[0] = CMD_DMALD;
+	if (cond == SINGLE)
+		buf[0] |= (0 << 1) | (1 << 0);
+	else if (cond == BURST)
+		buf[0] |= (1 << 1) | (1 << 0);
+	DMA330_DBGCMD_DUMP(SZ_DMALD, "\tDMALD%c\n",
+			  cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A'));
+	return SZ_DMALD;
+}
+
+/**
+ * _emit_lp - Add opcode DMALP into microcode (loop).
+ *
+ * @buf: The buffer which stored the microcode program.
+ * @loop: Selection of using counter 0 or 1  (valid value 0 or 1).
+ * @cnt: number of iteration (valid value 1-256).
+ *
+ * Return: Size of opcode.
+ */
+static inline u32 _emit_lp(u8 buf[], u32 loop, u32 cnt)
+{
+	u8 *buffer = buf;
+
+	buffer[0] = CMD_DMALP;
+	if (loop)
+		buffer[0] |= (1 << 1);
+	/* DMAC increments by 1 internally */
+	cnt--;
+	buffer[1] = cnt;
+	DMA330_DBGCMD_DUMP(SZ_DMALP, "\tDMALP_%c %u\n", loop ? '1' : '0', cnt);
+	return SZ_DMALP;
+}
+
+/**
+ * _emit_lpend - Add opcode DMALPEND into microcode (loop end).
+ *
+ * @buf: The buffer which stored the microcode program.
+ * @arg: Structure _arg_lpend which contain all needed info.
+ *	arg->cond -> Execution criteria such as single, burst or always
+ *	arg->forever -> Forever loop? used if DMALPFE started the loop
+ *	arg->bjump -> Backwards jump (relative location of
+ *		      1st instruction in the loop.
+ *
+ * Return: Size of opcode.
+ */
+static inline u32 _emit_lpend(u8 buf[], const struct _arg_lpend *arg)
+{
+	u8 *buffer = buf;
+	enum dma330_cond cond = arg->cond;
+	int forever = arg->forever;
+	u32 loop = arg->loop;
+	u8 bjump = arg->bjump;
+
+	buffer[0] = CMD_DMALPEND;
+	if (loop)
+		buffer[0] |= (1 << 2);
+	if (!forever)
+		buffer[0] |= (1 << 4);
+	if (cond == SINGLE)
+		buffer[0] |= (0 << 1) | (1 << 0);
+	else if (cond == BURST)
+		buffer[0] |= (1 << 1) | (1 << 0);
+
+	buffer[1] = bjump;
+	DMA330_DBGCMD_DUMP(SZ_DMALPEND, "\tDMALP%s%c_%c bjmpto_%x\n",
+			  forever ? "FE" : "END",
+			  cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A'),
+			  loop ? '1' : '0',
+			  bjump);
+	return SZ_DMALPEND;
+}
+
+/**
+ * _emit_kill - Add opcode DMAKILL into microcode (kill).
+ *
+ * @buf: The buffer which stored the microcode program.
+ *
+ * Return: Size of opcode.
+ */
+static inline u32 _emit_kill(u8 buf[])
+{
+	buf[0] = CMD_DMAKILL;
+	return SZ_DMAKILL;
+}
+
+/**
+ * _emit_mov - Add opcode DMAMOV into microcode (move).
+ *
+ * @buf: The buffer which stored the microcode program.
+ * @dst: Destination register (valid value SAR[0b000], DAR[0b010],
+ *	 or CCR[0b001]).
+ * @val: 32bit value that to be written into destination register.
+ *
+ * Return: Size of opcode.
+ */
+static inline u32 _emit_mov(u8 buf[], enum dmamov_dst dst, u32 val)
+{
+	u8 *buffer = buf;
+
+	buffer[0] = CMD_DMAMOV;
+	buffer[1] = dst;
+	buffer[2] = val & 0xFF;
+	buffer[3] = (val >> 8) & 0xFF;
+	buffer[4] = (val >> 16) & 0xFF;
+	buffer[5] = (val >> 24) & 0xFF;
+	DMA330_DBGCMD_DUMP(SZ_DMAMOV, "\tDMAMOV %s 0x%x\n",
+			  dst == SAR ? "SAR" : (dst == DAR ? "DAR" : "CCR"),
+			   val);
+	return SZ_DMAMOV;
+}
+
+/**
+ * _emit_nop -	Add opcode DMANOP into microcode (no operation).
+ *
+ * @buf: The buffer which stored the microcode program.
+ *
+ * Return: Size of opcode.
+ */
+static inline u32 _emit_nop(u8 buf[])
+{
+	buf[0] = CMD_DMANOP;
+	DMA330_DBGCMD_DUMP(SZ_DMANOP, "\tDMANOP\n");
+	return SZ_DMANOP;
+}
+
+/**
+ * _emit_rmb - Add opcode DMARMB into microcode (read memory barrier).
+ *
+ * @buf: The buffer which stored the microcode program.
+ *
+ * Return: Size of opcode.
+ */
+static inline u32 _emit_rmb(u8 buf[])
+{
+	buf[0] = CMD_DMARMB;
+	DMA330_DBGCMD_DUMP(SZ_DMARMB, "\tDMARMB\n");
+	return SZ_DMARMB;
+}
+
+/**
+ * _emit_sev - Add opcode DMASEV into microcode (send event).
+ *
+ * @buf: The buffer which stored the microcode program.
+ * @ev: The event number (valid 0 - 31).
+ *
+ * Return: Size of opcode.
+ */
+static inline u32 _emit_sev(u8 buf[], u8 ev)
+{
+	u8 *buffer = buf;
+
+	buffer[0] = CMD_DMASEV;
+	ev &= 0x1f;
+	ev <<= 3;
+	buffer[1] = ev;
+	DMA330_DBGCMD_DUMP(SZ_DMASEV, "\tDMASEV %u\n", ev >> 3);
+	return SZ_DMASEV;
+}
+
+/**
+ * _emit_st - Add opcode DMAST into microcode (store).
+ *
+ * @buf: The buffer which stored the microcode program.
+ * @cond: Execution criteria such as single, burst or always.
+ *
+ * Return: Size of opcode.
+ */
+static inline u32 _emit_st(u8 buf[], enum dma330_cond cond)
+{
+	buf[0] = CMD_DMAST;
+	if (cond == SINGLE)
+		buf[0] |= (0 << 1) | (1 << 0);
+	else if (cond == BURST)
+		buf[0] |= (1 << 1) | (1 << 0);
+
+	DMA330_DBGCMD_DUMP(SZ_DMAST, "\tDMAST%c\n",
+		cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A'));
+	return SZ_DMAST;
+}
+
+/**
+ * _emit_stp - Add opcode DMASTP into microcode (store and notify peripheral).
+ *
+ * @buf: The buffer which stored the microcode program.
+ * @cond: Execution criteria such as single, burst or always.
+ * @peri: Peripheral ID as listed in DMA NPP.
+ *
+ * Return: Size of opcode.
+ */
+static inline u32 _emit_stp(u8 buf[], enum dma330_cond cond, u8 peri)
+{
+	u8 *buffer = buf;
+
+	buffer[0] = CMD_DMASTP;
+	if (cond == BURST)
+		buf[0] |= (1 << 1);
+	peri &= 0x1f;
+	peri <<= 3;
+	buffer[1] = peri;
+	DMA330_DBGCMD_DUMP(SZ_DMASTP, "\tDMASTP%c %u\n",
+		cond == SINGLE ? 'S' : 'B', peri >> 3);
+	return SZ_DMASTP;
+}
+
+/**
+ * _emit_stz - Add opcode DMASTZ into microcode (store zeros).
+ *
+ * @buf -> The buffer which stored the microcode program.
+ *
+ * Return: Size of opcode.
+ */
+static inline u32 _emit_stz(u8 buf[])
+{
+	buf[0] = CMD_DMASTZ;
+	DMA330_DBGCMD_DUMP(SZ_DMASTZ, "\tDMASTZ\n");
+	return SZ_DMASTZ;
+}
+
+/**
+ * _emit_wfp - Add opcode DMAWFP into microcode (wait for peripheral).
+ *
+ * @buf: The buffer which stored the microcode program.
+ * @cond: Execution criteria such as single, burst or always.
+ * @peri: Peripheral ID as listed in DMA NPP.
+ *
+ * Return: Size of opcode.
+ */
+static inline u32 _emit_wfp(u8 buf[], enum dma330_cond cond, u8 peri)
+{
+	u8 *buffer = buf;
+
+	buffer[0] = CMD_DMAWFP;
+	if (cond == SINGLE)
+		buffer[0] |= (0 << 1) | (0 << 0);
+	else if (cond == BURST)
+		buffer[0] |= (1 << 1) | (0 << 0);
+	else
+		buffer[0] |= (0 << 1) | (1 << 0);
+
+	peri &= 0x1f;
+	peri <<= 3;
+	buffer[1] = peri;
+	DMA330_DBGCMD_DUMP(SZ_DMAWFP, "\tDMAWFP%c %u\n",
+		cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'P'), peri >> 3);
+	return SZ_DMAWFP;
+}
+
+/**
+ * _emit_wmb - Add opcode DMAWMB into microcode (write memory barrier).
+ *
+ * @buf: The buffer which stored the microcode program.
+ *
+ * Return: Size of opcode.
+ */
+static inline u32 _emit_wmb(u8 buf[])
+{
+	buf[0] = CMD_DMAWMB;
+	DMA330_DBGCMD_DUMP(SZ_DMAWMB, "\tDMAWMB\n");
+	return SZ_DMAWMB;
+}
+
+/**
+ * _emit_go - Add opcode DMALGO into microcode (go).
+ *
+ * @buf: The buffer which stored the microcode program.
+ * @arg: structure _arg_go which contain all needed info
+ *	arg->chan -> channel number
+ *	arg->addr -> start address of the microcode program
+ *		     which will be wrote into CPC register
+ *	arg->ns -> 1 for non secure, 0 for secure
+ *		   (if only DMA Manager is in secure).
+ *
+ * Return: Size of opcode.
+ */
+static inline u32 _emit_go(u8 buf[], const struct _arg_go *arg)
+{
+	u8 *buffer = buf;
+	u8 chan = arg->chan;
+	u32 addr = arg->addr;
+	u32 ns = arg->ns;
+
+	buffer[0] = CMD_DMAGO;
+	buffer[0] |= (ns << 1);
+	buffer[1] = chan & 0x7;
+	buf[2] = addr & 0xFF;
+	buf[3] = (addr >> 8) & 0xFF;
+	buf[4] = (addr >> 16) & 0xFF;
+	buf[5] = (addr >> 24) & 0xFF;
+	return SZ_DMAGO;
+}
+
+/**
+ * _prepare_ccr - Populate the CCR register.
+ * @rqc: Request Configuration.
+ *
+ * Return: Channel Control register (CCR) Setting.
+ */
+static inline u32 _prepare_ccr(const struct dma330_reqcfg *rqc)
+{
+	u32 ccr = 0;
+
+	if (rqc->src_inc)
+		ccr |= CC_SRCINC;
+	if (rqc->dst_inc)
+		ccr |= CC_DSTINC;
+
+	/* We set same protection levels for Src and DST for now */
+	if (rqc->privileged)
+		ccr |= CC_SRCPRI | CC_DSTPRI;
+	if (rqc->nonsecure)
+		ccr |= CC_SRCNS | CC_DSTNS;
+	if (rqc->insnaccess)
+		ccr |= CC_SRCIA | CC_DSTIA;
+
+	ccr |= (((rqc->brst_len - 1) & 0xf) << CC_SRCBRSTLEN_SHFT);
+	ccr |= (((rqc->brst_len - 1) & 0xf) << CC_DSTBRSTLEN_SHFT);
+
+	ccr |= (rqc->brst_size << CC_SRCBRSTSIZE_SHFT);
+	ccr |= (rqc->brst_size << CC_DSTBRSTSIZE_SHFT);
+
+	ccr |= (rqc->scctl << CC_SRCCCTRL_SHFT);
+	ccr |= (rqc->dcctl << CC_DSTCCTRL_SHFT);
+
+	ccr |= (rqc->swap << CC_SWAP_SHFT);
+	return ccr;
+}
+
+/**
+ * dma330_until_dmac_idle - Wait until DMA Manager is idle.
+ *
+ * @plat: Pointer to struct dma_dma330_platdata.
+ * @timeout_ms: Timeout (in miliseconds).
+ *
+ * Return: Negative value for error / timeout ocurred before idle,
+ *	   0 for successful.
+ */
+static int dma330_until_dmac_idle(struct dma_dma330_platdata *plat,
+				  const u32 timeout_ms)
+{
+	void __iomem *regs = plat->base;
+
+	return wait_for_bit(__func__,
+			    (const u32 *)(uintptr_t)(regs + DBGSTATUS),
+			    DBG_BUSY, 0, timeout_ms, false);
+}
+
+/**
+ * dma330_execute_dbginsn - Execute debug instruction such as DMAGO and DMAKILL.
+ *
+ * @insn: The buffer which stored the debug instruction.
+ * @plat: Pointer to struct dma_dma330_platdata.
+ * @timeout_ms: Timeout (in miliseconds).
+ *
+ * Return: void.
+ */
+static inline void dma330_execute_dbginsn(u8 insn[],
+					  struct dma_dma330_platdata *plat,
+					  const u32 timeout_ms)
+{
+	void __iomem *regs = plat->base;
+	u32 val;
+
+	val = (insn[0] << 16) | (insn[1] << 24);
+	if (!plat->dma330.channel0_manager1)
+		val |= (1 << 0);
+	val |= (plat->dma330.channel_num << 8); /* Channel Number */
+	writel(val, regs + DBGINST0);
+	val = insn[2];
+	val = val | (insn[3] << 8);
+	val = val | (insn[4] << 16);
+	val = val | (insn[5] << 24);
+	writel(val, regs + DBGINST1);
+
+	/* If timed out due to halted state-machine */
+	if (dma330_until_dmac_idle(plat, timeout_ms)) {
+		debug("DMAC halted!\n");
+		return;
+	}
+	/* Get going */
+	writel(0, regs + DBGCMD);
+}
+
+/**
+ * dma330_getstate - Get the status of current channel or manager.
+ *
+ * @plat: Pointer to struct dma_dma330_platdata.
+ *
+ * Return: Status state of current channel or current manager.
+ */
+static inline u32 dma330_getstate(struct dma_dma330_platdata *plat)
+{
+	void __iomem *regs = plat->base;
+	u32 val;
+
+	if (plat->dma330.channel0_manager1)
+		val = readl((uintptr_t)(regs + DS)) & 0xf;
+	else
+		val = readl((uintptr_t)(regs + CS(plat->dma330.channel_num))) &
+			    0xf;
+
+	switch (val) {
+	case DS_ST_STOP:
+		return DMA330_STATE_STOPPED;
+	case DS_ST_EXEC:
+		return DMA330_STATE_EXECUTING;
+	case DS_ST_CMISS:
+		return DMA330_STATE_CACHEMISS;
+	case DS_ST_UPDTPC:
+		return DMA330_STATE_UPDTPC;
+	case DS_ST_WFE:
+		return DMA330_STATE_WFE;
+	case DS_ST_FAULT:
+		return DMA330_STATE_FAULTING;
+	case DS_ST_ATBRR:
+		if (plat->dma330.channel0_manager1)
+			return DMA330_STATE_INVALID;
+		else
+			return DMA330_STATE_ATBARRIER;
+	case DS_ST_QBUSY:
+		if (plat->dma330.channel0_manager1)
+			return DMA330_STATE_INVALID;
+		else
+			return DMA330_STATE_QUEUEBUSY;
+	case DS_ST_WFP:
+		if (plat->dma330.channel0_manager1)
+			return DMA330_STATE_INVALID;
+		else
+			return DMA330_STATE_WFP;
+	case DS_ST_KILL:
+		if (plat->dma330.channel0_manager1)
+			return DMA330_STATE_INVALID;
+		else
+			return DMA330_STATE_KILLING;
+	case DS_ST_CMPLT:
+		if (plat->dma330.channel0_manager1)
+			return DMA330_STATE_INVALID;
+		else
+			return DMA330_STATE_COMPLETING;
+	case DS_ST_FLTCMP:
+		if (plat->dma330.channel0_manager1)
+			return DMA330_STATE_INVALID;
+		else
+			return DMA330_STATE_FAULT_COMPLETING;
+	default:
+		return DMA330_STATE_INVALID;
+	}
+}
+
+/**
+ * dma330_trigger - Execute the DMAGO through debug instruction.
+ *
+ * @plat: Pointer to struct dma_dma330_platdata.
+ * @timeout_ms: Timeout (in miliseconds).
+ *
+ * When the DMA manager executes Go for a DMA channel that is in the Stopped
+ * state, it moves a 32-bit immediate into the program counter, then setting
+ * its security state and updating DMA channel to the Executing state.
+ *
+ * Return: Negative value for error as DMA is not ready. 0 for successful.
+ */
+static int dma330_trigger(struct dma_dma330_platdata *plat,
+			  const u32 timeout_ms)
+{
+	u8 insn[6] = {0, 0, 0, 0, 0, 0};
+	struct _arg_go go;
+
+	/*
+	 * Return if already ACTIVE. It will ensure DMAGO is executed at
+	 * STOPPED state too
+	 */
+	plat->dma330.channel0_manager1 = 0;
+	if (dma330_getstate(plat) !=
+		DMA330_STATE_STOPPED)
+		return -EPERM;
+
+	go.chan = plat->dma330.channel_num;
+	go.addr = (uintptr_t)plat->dma330.buf;
+
+	if (!plat->dma330.secure)
+		go.ns = 1; /* non-secure condition */
+	else
+		go.ns = 0; /* secure condition */
+
+	_emit_go(insn, &go);
+
+	/* Only manager can execute GO */
+	plat->dma330.channel0_manager1 = 1;
+	dma330_execute_dbginsn(insn, plat, timeout_ms);
+	return 0;
+}
+
+/**
+ * dma330_stop - Stop the manager or channel.
+ *
+ * @plat: Pointer to struct dma_dma330_platdata.
+ * @timeout_ms: Timeout (in miliseconds).
+ *
+ * Stop the manager/channel or killing them and ensure they reach to stop
+ * state.
+ *
+ * Return: void.
+ */
+static void dma330_stop(struct dma_dma330_platdata *plat, const u32 timeout_ms)
+{
+	u8 insn[6] = {0, 0, 0, 0, 0, 0};
+
+	/* If fault completing, wait until reach faulting and killing state */
+	if (dma330_getstate(plat) == DMA330_STATE_FAULT_COMPLETING)
+		UNTIL(plat, DMA330_STATE_FAULTING | DMA330_STATE_KILLING);
+
+	/* Return if nothing needs to be done */
+	if (dma330_getstate(plat) == DMA330_STATE_COMPLETING ||
+	    dma330_getstate(plat) == DMA330_STATE_KILLING ||
+	    dma330_getstate(plat) == DMA330_STATE_STOPPED)
+		return;
+
+	/* Kill it to ensure it reach to stop state */
+	_emit_kill(insn);
+
+	/* Execute the KILL instruction through debug registers */
+	dma330_execute_dbginsn(insn, plat, timeout_ms);
+}
+
+/**
+ * dma330_start - Execute the command list through DMAGO and debug instruction.
+ *
+ * @plat: Pointer to struct dma_dma330_platdata.
+ * @timeout_ms: Timeout (in miliseconds).
+ *
+ * Return: Negative value for error where DMA is not ready. 0 for successful.
+ */
+static int dma330_start(struct dma_dma330_platdata *plat, const u32 timeout_ms)
+{
+	debug("INFO: DMA BASE Address = 0x%08x\n",
+	      (u32)(uintptr_t)plat->base);
+
+	switch (dma330_getstate(plat)) {
+	case DMA330_STATE_FAULT_COMPLETING:
+		UNTIL(plat, DMA330_STATE_FAULTING | DMA330_STATE_KILLING);
+
+		if (dma330_getstate(plat) == DMA330_STATE_KILLING)
+			UNTIL(plat, DMA330_STATE_STOPPED);
+
+	case DMA330_STATE_FAULTING:
+		dma330_stop(plat, timeout_ms);
+
+	case DMA330_STATE_KILLING:
+	case DMA330_STATE_COMPLETING:
+		UNTIL(plat, DMA330_STATE_STOPPED);
+
+	case DMA330_STATE_STOPPED:
+		return dma330_trigger(plat, timeout_ms);
+
+	case DMA330_STATE_WFP:
+	case DMA330_STATE_QUEUEBUSY:
+	case DMA330_STATE_ATBARRIER:
+	case DMA330_STATE_UPDTPC:
+	case DMA330_STATE_CACHEMISS:
+	case DMA330_STATE_EXECUTING:
+		return -ESRCH;
+	/* For RESUME, nothing yet */
+	case DMA330_STATE_WFE:
+	default:
+		return -ESRCH;
+	}
+}
+
+/**
+ * dma330_transfer_start - DMA start to run.
+ *
+ * @plat: Pointer to struct dma_dma330_platdata.
+ *
+ * DMA start to excecute microcode command list.
+ *
+ * Return: Negative value for error or not successful. 0 for successful.
+ */
+static int dma330_transfer_start(struct dma_dma330_platdata *plat)
+{
+	const u32 timeout_ms = 1000;
+
+	/* Execute the command list */
+	return dma330_start(plat, timeout_ms);
+}
+
+/**
+ * dma330_transfer_finish - DMA polling until execution finish or error.
+ *
+ * @plat: Pointer to struct dma_dma330_platdata.
+ *
+ * DMA polling until excution finish and checking the state status.
+ *
+ * Return: Negative value for state error or not successful. 0 for successful.
+ */
+static int dma330_transfer_finish(struct dma_dma330_platdata *plat)
+{
+	void __iomem *regs = plat->base;
+
+	if (!plat->dma330.buf) {
+		debug("ERROR DMA330 : DMA Microcode buffer pointer is NULL\n");
+		return -EINVAL;
+	}
+
+	plat->dma330.channel0_manager1 = 0;
+
+	/* Wait until finish execution to ensure we compared correct result*/
+	UNTIL(plat, DMA330_STATE_STOPPED | DMA330_STATE_FAULTING);
+
+	/* check the state */
+	if (dma330_getstate(plat) == DMA330_STATE_FAULTING) {
+		debug("FAULT Mode: Channel %d Faulting, FTR = 0x%08x,",
+		     plat->dma330.channel_num,
+		     readl(regs + FTC(plat->dma330.channel_num)));
+		debug("CPC = 0x%08lx\n",
+		     (readl(regs + CPC(plat->dma330.channel_num))
+		     - (uintptr_t)plat->dma330.buf));
+		return -EPROTO;
+	}
+	return 0;
+}
+
+/**
+ * dma330_transfer_setup - DMA transfer setup (DMA_MEM_TO_MEM, DMA_MEM_TO_DEV
+ *			   or DMA_DEV_TO_MEM).
+ *
+ * @plat: Pointer to struct dma_dma330_platdata.
+ *
+ * For Peripheral transfer, the FIFO threshold value is expected at
+ * 2 ^ plat->brst_size * plat->brst_len.
+ *
+ * Return: Negative value for error or not successful. 0 for successful.
+ */
+static int dma330_transfer_setup(struct dma_dma330_platdata *plat)
+{
+	/* Variable declaration */
+	/* Buffer offset clear to 0 */
+	int off = 0;
+	int ret = 0;
+	/* For DMALPEND */
+	u32 loopjmp0, loopjmp1;
+	/* Loop count 0 */
+	u32 lcnt0 = 0;
+	/* Loop count 1 */
+	u32 lcnt1 = 0;
+	u32 brst_size = 0;
+	u32 brst_len = 0;
+	u32 data_size_byte = plat->dma330.size_byte;
+	/* Strong order memory is required to store microcode command list */
+	u8 *buf = (u8 *)plat->dma330.buf;
+	/* Channel Control Register */
+	u32 ccr = 0;
+	struct dma330_reqcfg reqcfg;
+
+	if (!buf) {
+		debug("ERROR DMA330 : DMA Microcode buffer pointer is NULL\n");
+		return -EINVAL;
+	}
+
+	if (plat->dma330.transfer_type == DMA_MEM_TO_DEV)
+		debug("INFO: mem2perip");
+	else if (plat->dma330.transfer_type == DMA_DEV_TO_MEM)
+		debug("INFO: perip2mem");
+	else
+		debug("INFO: DMA_MEM_TO_MEM");
+
+	debug(" - 0x%x%x -> 0x%x%x\nsize=%08x brst_size=2^%d ",
+	      (u32)(plat->dma330.src_addr >> 32),
+	      (u32)plat->dma330.src_addr,
+	      (u32)(plat->dma330.dst_addr >> 32),
+	      (u32)plat->dma330.dst_addr,
+	      data_size_byte,
+	      plat->brst_size);
+
+	debug("brst_len=%d singles_brst_size=2^%d\n", plat->brst_len,
+	      plat->dma330.single_brst_size);
+
+	/* brst_size = 2 ^ plat->brst_size */
+	brst_size = 1 << plat->brst_size;
+
+	/* Fool proof checking */
+	if (plat->brst_size < 0 || plat->brst_size >
+		plat->max_brst_size) {
+		debug("ERROR DMA330: brst_size must 0-%d (not %d)\n",
+			plat->max_brst_size, plat->brst_size);
+		return -EINVAL;
+	}
+	if (plat->dma330.single_brst_size < 0 ||
+		plat->dma330.single_brst_size > plat->max_brst_size) {
+		debug("ERROR DMA330 : single_brst_size must 0-%d (not %d)\n",
+			plat->max_brst_size, plat->dma330.single_brst_size);
+		return -EINVAL;
+	}
+	if (plat->brst_len < 1 || plat->brst_len > 16) {
+		debug("ERROR DMA330 : brst_len must 1-16 (not %d)\n",
+			plat->brst_len);
+		return -EINVAL;
+	}
+	if (plat->dma330.src_addr & (brst_size - 1)) {
+		debug("ERROR DMA330 : Source address unaligned\n");
+		return -EINVAL;
+	}
+	if (plat->dma330.dst_addr & (brst_size - 1)) {
+		debug("ERROR DMA330 : Destination address unaligned\n");
+		return -EINVAL;
+	}
+
+	/* Setup the command list */
+	/* DMAMOV SAR, x->src_addr */
+	off += _emit_mov(&buf[off], SAR, plat->dma330.src_addr);
+	/* DMAMOV DAR, x->dst_addr */
+	off += _emit_mov(&buf[off], DAR, plat->dma330.dst_addr);
+	/* DMAFLUSHP P(periheral_id) */
+	if (plat->dma330.transfer_type != DMA_MEM_TO_MEM)
+		off += _emit_flushp(&buf[off], plat->dma330.peripheral_id);
+
+	/* Preparing the CCR value */
+	if (plat->dma330.transfer_type == DMA_MEM_TO_DEV) {
+		/* Disable auto increment */
+		reqcfg.dst_inc = 0;
+		/* Enable auto increment */
+		reqcfg.src_inc = 1;
+	} else if (plat->dma330.transfer_type == DMA_DEV_TO_MEM) {
+		reqcfg.dst_inc = 1;
+		reqcfg.src_inc = 0;
+	} else {
+		/* DMA_MEM_TO_MEM */
+		reqcfg.dst_inc = 1;
+		reqcfg.src_inc = 1;
+	}
+
+	if (!plat->dma330.secure)
+		reqcfg.nonsecure = 1; /* Non Secure mode */
+	else
+		reqcfg.nonsecure = 0; /* Secure mode */
+
+	if (plat->dma330.enable_cache1 == 0) {
+		/* Noncacheable but bufferable */
+		reqcfg.dcctl = 0x1;
+		reqcfg.scctl = 0x1;
+	} else {
+		if (plat->dma330.transfer_type == DMA_MEM_TO_DEV) {
+			reqcfg.dcctl = 0x1;
+			/* Cacheable write back */
+			reqcfg.scctl = 0x7;
+		} else if (plat->dma330.transfer_type == DMA_DEV_TO_MEM) {
+			reqcfg.dcctl = 0x7;
+			reqcfg.scctl = 0x1;
+		} else {
+			reqcfg.dcctl = 0x7;
+			reqcfg.scctl = 0x7;
+		}
+	}
+	/* 1 - Privileged  */
+	reqcfg.privileged = 1;
+	/* 0 - Data access */
+	reqcfg.insnaccess = 0;
+	/* 0 - No endian swap */
+	reqcfg.swap = 0;
+	/* DMA burst length */
+	reqcfg.brst_len = plat->brst_len;
+	/* DMA burst size */
+	reqcfg.brst_size = plat->brst_size;
+	/* Preparing the CCR value */
+	ccr = _prepare_ccr(&reqcfg);
+	/* DMAMOV CCR, ccr */
+	off += _emit_mov(&buf[off], CCR, ccr);
+
+	/* BURST */
+	/* Can initiate a burst? */
+	while (data_size_byte >= brst_size * plat->brst_len) {
+		lcnt0 = data_size_byte / (brst_size * plat->brst_len);
+		lcnt1 = 0;
+		if (lcnt0 >= 256 * 256) {
+			lcnt0 = 256;
+			lcnt1 = 256;
+		} else if (lcnt0 >= 256) {
+			lcnt1 = lcnt0 / 256;
+			lcnt0 = 256;
+		}
+		data_size_byte = data_size_byte -
+			(brst_size * plat->brst_len * lcnt0 * lcnt1);
+
+		debug("Transferring 0x%08x Remain 0x%08x\n", (brst_size *
+			plat->brst_len * lcnt0 * lcnt1), data_size_byte);
+		debug("Running burst - brst_size=2^%d, brst_len=%d, ",
+		      plat->brst_size, plat->brst_len);
+		debug("lcnt0=%d, lcnt1=%d\n", lcnt0, lcnt1);
+
+		if (lcnt1) {
+			/* DMALP1 */
+			off += _emit_lp(&buf[off], 1, lcnt1);
+			loopjmp1 = off;
+		}
+		/* DMALP0 */
+		off += _emit_lp(&buf[off], 0, lcnt0);
+		loopjmp0 = off;
+		/* DMAWFP periheral_id, burst */
+		if (plat->dma330.transfer_type != DMA_MEM_TO_MEM)
+			off += _emit_wfp(&buf[off], BURST,
+				plat->dma330.peripheral_id);
+		/* DMALD */
+		off += _emit_ld(&buf[off], ALWAYS);
+
+		WATCHDOG_RESET();
+
+		/* DMARMB */
+		off += _emit_rmb(&buf[off]);
+		/* DMASTPB peripheral_id */
+		if (plat->dma330.transfer_type != DMA_MEM_TO_MEM)
+			off += _emit_stp(&buf[off], BURST,
+				plat->dma330.peripheral_id);
+		else
+			off += _emit_st(&buf[off], ALWAYS);
+		/* DMAWMB */
+		off += _emit_wmb(&buf[off]);
+		/* DMALP0END */
+		struct _arg_lpend lpend;
+
+		lpend.cond = ALWAYS;
+		lpend.forever = 0;
+		/* Loop cnt 0 */
+		lpend.loop = 0;
+		lpend.bjump = off - loopjmp0;
+		off += _emit_lpend(&buf[off], &lpend);
+		/* DMALP1END */
+		if (lcnt1) {
+			struct _arg_lpend lpend;
+
+			lpend.cond = ALWAYS;
+			lpend.forever = 0;
+			lpend.loop = 1;		/* loop cnt 1*/
+			lpend.bjump = off - loopjmp1;
+			off += _emit_lpend(&buf[off], &lpend);
+		}
+		/* Ensure the microcode don't exceed buffer size */
+		if (off > plat->buf_size) {
+			debug("ERROR DMA330 : Exceed buffer size\n");
+			return -ENOMEM;
+		}
+	}
+
+	/* SINGLE */
+	brst_len = 1;
+	/* brst_size = 2 ^ plat->dma330.single_brst_size; */
+	brst_size = (1 << plat->dma330.single_brst_size);
+	lcnt0 = data_size_byte / (brst_size * brst_len);
+
+	/* Ensure all data will be transferred */
+	data_size_byte = data_size_byte -
+		(brst_size * brst_len * lcnt0);
+	if (data_size_byte) {
+		debug("ERROR DMA330 : Detected the possibility of ");
+		debug("untransfered data. Please ensure correct single ");
+		debug("burst size\n");
+	}
+
+	if (lcnt0) {
+		debug("Transferring 0x%08x Remain 0x%08x\n", (brst_size *
+			brst_len * lcnt0 * lcnt1), data_size_byte);
+		debug("Running single - brst_size=2^%d, brst_len=%d, ",
+		      brst_size, brst_len);
+		debug("lcnt0=%d\n", lcnt0);
+
+		/* Preparing the CCR value */
+		/* DMA burst length */
+		reqcfg.brst_len = brst_len;
+		/* DMA burst size */
+		reqcfg.brst_size = brst_size;
+		ccr = _prepare_ccr(&reqcfg);
+		/* DMAMOV CCR, ccr */
+		off += _emit_mov(&buf[off], CCR, ccr);
+
+		/* DMALP0 */
+		off += _emit_lp(&buf[off], 0, lcnt0);
+		loopjmp0 = off;
+		/* DMAWFP peripheral_id, single */
+		if (plat->dma330.transfer_type != DMA_MEM_TO_MEM)
+			off += _emit_wfp(&buf[off], SINGLE,
+				plat->dma330.peripheral_id);
+
+		/* DMALD */
+		off += _emit_ld(&buf[off], ALWAYS);
+		/* DMARMB */
+		off += _emit_rmb(&buf[off]);
+		/* DMASTPS peripheral_id */
+		if (plat->dma330.transfer_type != DMA_MEM_TO_MEM)
+			off += _emit_stp(&buf[off], SINGLE,
+				plat->dma330.peripheral_id);
+		else
+			off += _emit_st(&buf[off], ALWAYS);
+
+		/* DMAWMB */
+		off += _emit_wmb(&buf[off]);
+		/* DMALPEND */
+		struct _arg_lpend lpend1;
+
+		lpend1.cond = ALWAYS;
+		lpend1.forever = 0;
+		/* loop cnt 0 */
+		lpend1.loop = 0;
+		lpend1.bjump = off - loopjmp0;
+		off += _emit_lpend(&buf[off], &lpend1);
+		/* Ensure the microcode don't exceed buffer size */
+		if (off > plat->buf_size) {
+			puts("ERROR DMA330 : Exceed buffer size\n");
+			return -ENOMEM;
+		}
+	}
+
+	/* DMAEND */
+	off += _emit_end(&buf[off]);
+
+	ret = dma330_transfer_start(plat);
+	if (ret)
+		return ret;
+
+	return dma330_transfer_finish(plat);
+}
+
+/**
+ * dma330_transfer_zeroes - DMA transfer zeros.
+ *
+ * @plat: Pointer to struct dma_dma330_platdata.
+ *
+ * Used to write zeros to a memory chunk for memory scrubbing purpose.
+ *
+ * Return: Negative value for error or not successful. 0 for successful.
+ */
+static int dma330_transfer_zeroes_setup(struct dma_dma330_platdata *plat)
+{
+	/* Variable declaration */
+	/* Buffer offset clear to 0 */
+	int off = 0;
+	int ret = 0;
+	/* For DMALPEND */
+	u32 loopjmp0, loopjmp1;
+	/* Loop count 0 */
+	u32 lcnt0 = 0;
+	/* Loop count 1 */
+	u32 lcnt1 = 0;
+	u32 brst_size = 0;
+	u32 brst_len = 0;
+	u32 data_size_byte = plat->dma330.size_byte;
+	/* Strong order memory is required to store microcode command list */
+	u8 *buf = (u8 *)plat->dma330.buf;
+	/* Channel Control Register */
+	u32 ccr = 0;
+	struct dma330_reqcfg reqcfg;
+
+	if (!buf) {
+		debug("ERROR DMA330 : DMA Microcode buffer pointer is NULL\n");
+		return -EINVAL;
+	}
+
+	debug("INFO: Write zeros -> ");
+	debug("0x%x%x size=0x%08x\n",
+	      (u32)(plat->dma330.dst_addr >> 32),
+	      (u32)plat->dma330.dst_addr,
+	      data_size_byte);
+
+	plat->dma330.single_brst_size = 1;
+
+	/* burst_size = 2 ^ plat->brst_size */
+	brst_size = 1 << plat->brst_size;
+
+	/* Setup the command list */
+	/* DMAMOV DAR, x->dst_addr */
+	off += _emit_mov(&buf[off], DAR, plat->dma330.dst_addr);
+
+	/* Preparing the CCR value */
+	/* Enable auto increment */
+	reqcfg.dst_inc = 1;
+	/* Disable auto increment (not applicable) */
+	reqcfg.src_inc = 0;
+	/* Noncacheable but bufferable */
+	reqcfg.dcctl = 0x1;
+	/* Noncacheable and bufferable */
+	reqcfg.scctl = 0x1;
+	/* 1 - Privileged  */
+	reqcfg.privileged = 1;
+	/* 0 - Data access */
+	reqcfg.insnaccess = 0;
+	/* 0 - No endian swap */
+	reqcfg.swap = 0;
+
+	if (!plat->dma330.secure)
+		reqcfg.nonsecure = 1; /* Non Secure mode */
+	else
+		reqcfg.nonsecure = 0; /* Secure mode */
+
+	/* DMA burst length */
+	reqcfg.brst_len = plat->brst_len;
+	/* DMA burst size */
+	reqcfg.brst_size = plat->brst_size;
+	/* Preparing the CCR value */
+	ccr = _prepare_ccr(&reqcfg);
+	/* DMAMOV CCR, ccr */
+	off += _emit_mov(&buf[off], CCR, ccr);
+
+	/* BURST */
+	/* Can initiate a burst? */
+	while (data_size_byte >= brst_size * plat->brst_len) {
+		lcnt0 = data_size_byte / (brst_size * plat->brst_len);
+		lcnt1 = 0;
+		if (lcnt0 >= 256 * 256) {
+			lcnt0 = 256;
+			lcnt1 = 256;
+		} else if (lcnt0 >= 256) {
+			lcnt1 = lcnt0 / 256;
+			lcnt0 = 256;
+		}
+
+		data_size_byte = data_size_byte -
+			(brst_size * plat->brst_len * lcnt0 * lcnt1);
+
+		debug("Transferring 0x%08x Remain 0x%08x\n", (brst_size *
+			plat->brst_len * lcnt0 * lcnt1), data_size_byte);
+		debug("Running burst - brst_size=2^%d, brst_len=%d,",
+		      plat->brst_size, plat->brst_len);
+		debug("lcnt0=%d, lcnt1=%d\n", lcnt0, lcnt1);
+
+		if (lcnt1) {
+			/* DMALP1 */
+			off += _emit_lp(&buf[off], 1, lcnt1);
+			loopjmp1 = off;
+		}
+		/* DMALP0 */
+		off += _emit_lp(&buf[off], 0, lcnt0);
+		loopjmp0 = off;
+		/* DMALSTZ */
+		off += _emit_stz(&buf[off]);
+
+		WATCHDOG_RESET();
+
+		/* DMALP0END */
+		struct _arg_lpend lpend;
+
+		lpend.cond = ALWAYS;
+		lpend.forever = 0;
+		/* Loop cnt 0 */
+		lpend.loop = 0;
+		lpend.bjump = off - loopjmp0;
+		off += _emit_lpend(&buf[off], &lpend);
+		/* DMALP1END */
+		if (lcnt1) {
+			struct _arg_lpend lpend;
+
+			lpend.cond = ALWAYS;
+			lpend.forever = 0;
+			/* Loop cnt 1*/
+			lpend.loop = 1;
+			lpend.bjump = off - loopjmp1;
+			off += _emit_lpend(&buf[off], &lpend);
+		}
+		/* Ensure the microcode don't exceed buffer size */
+		if (off > plat->buf_size) {
+			printf("off = %d\n", off);
+			debug("ERROR DMA330 : Exceed buffer size off %d\n",
+			      off);
+			return -ENOMEM;
+		}
+	}
+
+	/* SINGLE */
+	brst_len = 1;
+	/* brst_size = 2 ^ plat->dma330.single_brst_size */
+	brst_size = (1 << plat->dma330.single_brst_size);
+	lcnt0 = data_size_byte / (brst_size * brst_len);
+
+	/* ensure all data will be transferred */
+	data_size_byte = data_size_byte -
+		(brst_size * brst_len * lcnt0);
+	if (data_size_byte) {
+		debug("ERROR DMA330 : Detected the possibility of ");
+		debug("untransfered data. Please ensure correct single ");
+		debug("burst size\n");
+	}
+
+	if (lcnt0) {
+		debug("Transferring 0x%08x Remain 0x%08x\n", (brst_size *
+		     brst_len * lcnt0), data_size_byte);
+		debug("Running single - brst_size=2^%d, brst_len=%d, ",
+		      brst_size, brst_len);
+		debug("lcnt0=%d\n", lcnt0);
+
+		/* Preparing the CCR value */
+		/* DMA burst length */
+		reqcfg.brst_len = brst_len;
+		/* DMA burst size */
+		reqcfg.brst_size = brst_size;
+		ccr = _prepare_ccr(&reqcfg);
+		/* DMAMOV CCR, ccr */
+		off += _emit_mov(&buf[off], CCR, ccr);
+
+		/* DMALP0 */
+		off += _emit_lp(&buf[off], 0, lcnt0);
+		loopjmp0 = off;
+		/* DMALSTZ */
+		off += _emit_stz(&buf[off]);
+		/* DMALPEND */
+		struct _arg_lpend lpend1;
+
+		lpend1.cond = ALWAYS;
+		lpend1.forever = 0;
+		/* Loop cnt 0 */
+		lpend1.loop = 0;
+		lpend1.bjump = off - loopjmp0;
+		off += _emit_lpend(&buf[off], &lpend1);
+		/* Ensure the microcode don't exceed buffer size */
+		if (off > plat->buf_size) {
+			debug("ERROR DMA330 : Exceed buffer size\n");
+			return -ENOMEM;
+		}
+	}
+
+	/* DMAEND */
+	off += _emit_end(&buf[off]);
+
+	ret = dma330_transfer_start(plat);
+	if (ret)
+		return ret;
+
+	return dma330_transfer_finish(plat);
+}
+
+static int dma330_transfer_zeroes(struct udevice *dev, void *dst, size_t len)
+{
+	struct dma_dma330_platdata *plat = dev->platdata;
+	int ret = 0;
+
+	/* If DMA access is set to secure, base change to DMA secure base */
+	if (plat->dma330.secure)
+		plat->base += 0x1000;
+
+	plat->dma330.dst_addr = (phys_size_t)(uintptr_t)dst;
+	plat->dma330.size_byte = len;
+
+	ret = dma330_transfer_zeroes_setup(plat);
+
+	/* Revert back to non secure DMA base */
+	if (plat->dma330.secure)
+		plat->base -= 0x1000;
+
+	return ret;
+}
+
+static int dma330_transfer(struct udevice *dev, int direction, void *dst,
+			  void *src, size_t len)
+{
+	struct dma_dma330_platdata *plat = dev->platdata;
+	int ret = 0;
+
+	/* If DMA access is set to secure, base change to DMA secure base */
+	if (plat->dma330.secure)
+		plat->base += 0x1000;
+
+	plat->dma330.dst_addr = (phys_size_t)(uintptr_t)dst;
+	plat->dma330.src_addr = (phys_size_t)(uintptr_t)src;
+	plat->dma330.size_byte = len;
+
+	switch (direction) {
+	case DMA_MEM_TO_MEM:
+		plat->dma330.transfer_type = DMA_SUPPORTS_MEM_TO_MEM;
+		break;
+	case DMA_MEM_TO_DEV:
+		plat->dma330.transfer_type = DMA_SUPPORTS_MEM_TO_DEV;
+		break;
+	case DMA_DEV_TO_MEM:
+		plat->dma330.transfer_type = DMA_SUPPORTS_DEV_TO_MEM;
+		break;
+	}
+
+	ret = dma330_transfer_setup(plat);
+
+	/* Revert back to non secure DMA base */
+	if (plat->dma330.secure)
+		plat->base -= 0x1000;
+
+	return ret;
+}
+
+static int dma330_ofdata_to_platdata(struct udevice *dev)
+{
+	struct dma_dma330_platdata *plat = dev->platdata;
+	const void *blob = gd->fdt_blob;
+	int node = dev_of_offset(dev);
+
+	plat->base = (void __iomem *)devfdt_get_addr(dev);
+	plat->max_brst_size = fdtdec_get_uint(blob, node, "dma-max-burst-size",
+					      2);
+	plat->brst_size = fdtdec_get_uint(blob, node, "dma-burst-size", 2);
+	plat->brst_len = fdtdec_get_uint(blob, node, "dma-burst-length", 2);
+
+	return 0;
+}
+
+static int dma330_probe(struct udevice *adev)
+{
+	struct dma_dev_priv *uc_priv = dev_get_uclass_priv(adev);
+
+	uc_priv->supported = (DMA_SUPPORTS_MEM_TO_MEM |
+			     DMA_SUPPORTS_MEM_TO_DEV |
+			     DMA_SUPPORTS_DEV_TO_MEM);
+	return 0;
+}
+
+static const struct dma_ops dma330_ops = {
+	.transfer = dma330_transfer,
+	.transfer_zeroes = dma330_transfer_zeroes,
+};
+
+static const struct udevice_id dma330_ids[] = {
+	{ .compatible = "arm,pl330" },
+	{ .compatible = "arm,dma330" },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(dma_dma330) = {
+	.name   = "dma_dma330",
+	.id     = UCLASS_DMA,
+	.of_match = dma330_ids,
+	.ops    = &dma330_ops,
+	.ofdata_to_platdata = dma330_ofdata_to_platdata,
+	.probe = dma330_probe,
+	.platdata_auto_alloc_size = sizeof(struct dma_dma330_platdata),
+};
diff --git a/include/dma330.h b/include/dma330.h
new file mode 100644
index 0000000..c054bf2
--- /dev/null
+++ b/include/dma330.h
@@ -0,0 +1,136 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Intel Corporation <www.intel.com>
+ */
+
+#include <dma.h>
+#include <linux/sizes.h>
+
+#ifndef __DMA330_CORE_H
+#define __DMA330_CORE_H
+
+#define DMA330_MAX_CHAN		8
+#define DMA330_MAX_IRQS		32
+#define DMA330_MAX_PERI		32
+
+#define DMA330_STATE_STOPPED		BIT(0)
+#define DMA330_STATE_EXECUTING		BIT(1)
+#define DMA330_STATE_WFE		BIT(2)
+#define DMA330_STATE_FAULTING		BIT(3)
+#define	DMA330_STATE_COMPLETING		BIT(4)
+#define DMA330_STATE_WFP		BIT(5)
+#define DMA330_STATE_KILLING		BIT(6)
+#define DMA330_STATE_FAULT_COMPLETING	BIT(7)
+#define DMA330_STATE_CACHEMISS		BIT(8)
+#define DMA330_STATE_UPDTPC		BIT(9)
+#define DMA330_STATE_ATBARRIER		BIT(10)
+#define DMA330_STATE_QUEUEBUSY		BIT(11))
+#define DMA330_STATE_INVALID		BIT(15)
+
+enum dma330_srccachectrl {
+	SCCTRL0 = 0,	/* Noncacheable and nonbufferable */
+	SCCTRL1,	/* Bufferable only */
+	SCCTRL2,	/* Cacheable, but do not allocate */
+	SCCTRL3,	/* Cacheable and bufferable, but do not allocate */
+	SINVALID1,
+	SINVALID2,
+	SCCTRL6,	/* Cacheable write-through, allocate on reads only */
+	SCCTRL7,	/* Cacheable write-back, allocate on reads only */
+};
+
+enum dma330_dstcachectrl {
+	DCCTRL0 = 0,	/* Noncacheable and nonbufferable */
+	DCCTRL1,	/* Bufferable only */
+	DCCTRL2,	/* Cacheable, but do not allocate */
+	DCCTRL3,	/* Cacheable and bufferable, but do not allocate */
+	DINVALID1 = 8,
+	DINVALID2,
+	DCCTRL6,	/* Cacheable write-through, allocate on writes only */
+	DCCTRL7,	/* Cacheable write-back, allocate on writes only */
+};
+
+enum dma330_byteswap {
+	SWAP_NO = 0,
+	SWAP_2,
+	SWAP_4,
+	SWAP_8,
+	SWAP_16,
+};
+
+/**
+ * dma330_reqcfg - Request Configuration.
+ *
+ * The DMA330 core does not modify this and uses the last
+ * working configuration if the request doesn't provide any.
+ *
+ * The Client may want to provide this info only for the
+ * first request and a request with new settings.
+ */
+struct dma330_reqcfg {
+	/* Address Incrementing */
+	u8 dst_inc;
+	u8 src_inc;
+
+	/*
+	 * For now, the SRC & DST protection levels
+	 * and burst size/length are assumed same.
+	 */
+	u8 nonsecure;
+	u8 privileged;
+	u8 insnaccess;
+	u8 brst_len;
+	u8 brst_size; /* in power of 2 */
+
+	enum dma330_dstcachectrl dcctl;
+	enum dma330_srccachectrl scctl;
+	enum dma330_byteswap swap;
+};
+
+/**
+ * dma330_transfer_struct - Structure to be passed in for dma330_transfer_x.
+ *
+ * @channel0_manager1: Switching configuration on DMA channel or DMA manager.
+ * @channel_num: Channel number assigned, valid from 0 to 7.
+ * @src_addr: Address to transfer from / source.
+ * @dst_addr: Address to transfer to / destination.
+ * @size_byte: Number of bytes to be transferred.
+ * @brst_size: Valid from 0 - 4,
+ *	       where 0 = 1 (2 ^ 0) bytes and 3 = 16 bytes (2 ^ 4).
+ * @max_brst_size: Max transfer size (from 0 - 4).
+ * @single_brst_size: Single transfer size (from 0 - 4).
+ * @brst_len: Valid from 1 - 16 where each burst can transfer 1 - 16
+ *	      Data chunk (each chunk size equivalent to brst_size).
+ * @peripheral_id: Assigned peripheral_id, valid from 0 to 31.
+ * @transfer_type: MEM2MEM, MEM2PERIPH or PERIPH2MEM.
+ * @enable_cache1: 1 for cache enabled for memory
+ *		   (cacheable and bufferable, but do not allocate).
+ * @buf: Buffer handler which will point to the memory
+ *	 allocated for dma microcode
+ * @secure: Set DMA channel in secure mode.
+ *
+ * Description of the structure.
+ */
+struct dma330_transfer_struct {
+	u32 channel0_manager1;
+	u32 channel_num;
+	phys_size_t src_addr;
+	phys_size_t dst_addr;
+	u32 size_byte;
+	u32 single_brst_size;
+	u32 peripheral_id;
+	u32 transfer_type;
+	u32 enable_cache1;
+	u32 *buf;
+	u8 secure;
+};
+
+struct dma_dma330_platdata {
+	void __iomem *base;
+	u32 buf_size;
+	u32 max_brst_size;
+	u32 brst_size;
+	u32 brst_len;
+	struct dma330_transfer_struct dma330;
+};
+
+#endif	/* __DMA330_CORE_H */