From patchwork Thu May 31 08:08:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chee, Tien Fong" X-Patchwork-Id: 923234 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=intel.com Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 40xKrF6WdXz9s0x for ; Thu, 31 May 2018 18:09:49 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 7C9ABC21E0B; Thu, 31 May 2018 08:09:42 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=RCVD_IN_DNSWL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id DE1CAC21DED; Thu, 31 May 2018 08:09:07 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 1864DC21C2C; Thu, 31 May 2018 08:09:05 +0000 (UTC) Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by lists.denx.de (Postfix) with ESMTPS id 32FC7C21C27 for ; Thu, 31 May 2018 08:09:04 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 31 May 2018 01:09:03 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,463,1520924400"; d="scan'208";a="60068540" Received: from pg-iccf0339.altera.com ([10.104.4.2]) by fmsmga001.fm.intel.com with ESMTP; 31 May 2018 01:09:01 -0700 From: tien.fong.chee@intel.com To: u-boot@lists.denx.de Date: Thu, 31 May 2018 16:08:50 +0800 Message-Id: <1527754134-164985-2-git-send-email-tien.fong.chee@intel.com> X-Mailer: git-send-email 1.7.7.4 In-Reply-To: <1527754134-164985-1-git-send-email-tien.fong.chee@intel.com> References: <1527754134-164985-1-git-send-email-tien.fong.chee@intel.com> Cc: Marek Vasut , Tom Rini , Tien Fong Chee , Mugunthan V N , Ching Liang See , Westergteen Dalon Subject: [U-Boot] [PATCH 1/5] drivers: dma: Enable DMA-330 driver support X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Tien Fong Chee Enable DMAC driver support for DMA-330 controller. The driver is also compatible to PL330 product. Signed-off-by: Tien Fong Chee --- 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +/* 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 + */ + +#include +#include + +#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 */ From patchwork Thu May 31 08:08:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chee, Tien Fong" X-Patchwork-Id: 923235 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=intel.com Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 40xKsj0vKhz9s0W for ; Thu, 31 May 2018 18:11:05 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id C12C6C21C29; Thu, 31 May 2018 08:10:56 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=RCVD_IN_DNSWL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id EEB24C21E1A; Thu, 31 May 2018 08:09:17 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id B7134C21CB1; Thu, 31 May 2018 08:09:11 +0000 (UTC) Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by lists.denx.de (Postfix) with ESMTPS id B088EC21DA1 for ; Thu, 31 May 2018 08:09:06 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 31 May 2018 01:09:06 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,463,1520924400"; d="scan'208";a="60068558" Received: from pg-iccf0339.altera.com ([10.104.4.2]) by fmsmga001.fm.intel.com with ESMTP; 31 May 2018 01:09:04 -0700 From: tien.fong.chee@intel.com To: u-boot@lists.denx.de Date: Thu, 31 May 2018 16:08:51 +0800 Message-Id: <1527754134-164985-3-git-send-email-tien.fong.chee@intel.com> X-Mailer: git-send-email 1.7.7.4 In-Reply-To: <1527754134-164985-1-git-send-email-tien.fong.chee@intel.com> References: <1527754134-164985-1-git-send-email-tien.fong.chee@intel.com> Cc: Marek Vasut , Tom Rini , Tien Fong Chee , Mugunthan V N , Ching Liang See , Westergteen Dalon Subject: [U-Boot] [PATCH 2/5] drivers: dma: Add function to zeroes a range of destination such as memory X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Tien Fong Chee This new DMA class function enables DMA being used for initializing a range of destination such as memory to zeros. This is quite useful to help accelerating the performance in scrubbing memory when ECC is enabled. Signed-off-by: Tien Fong Chee --- drivers/dma/dma-uclass.c | 15 +++++++++++++++ include/dma.h | 12 ++++++++++++ 2 files changed, 27 insertions(+) diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c index a33f7d5..cb83c24 100644 --- a/drivers/dma/dma-uclass.c +++ b/drivers/dma/dma-uclass.c @@ -61,6 +61,21 @@ int dma_memcpy(void *dst, void *src, size_t len) return ops->transfer(dev, DMA_MEM_TO_MEM, dst, src, len); } +int dma_memcpy_zeroes(struct udevice *dev, void *dst, size_t len) +{ + const struct dma_ops *ops; + + ops = device_get_ops(dev); + if (!ops->transfer_zeroes) + return -ENOSYS; + + /* Invalidate the area, so no writeback into the RAM races with DMA */ + invalidate_dcache_range((unsigned long)dst, (unsigned long)dst + + roundup(len, ARCH_DMA_MINALIGN)); + + return ops->transfer_zeroes(dev, dst, len); +} + UCLASS_DRIVER(dma) = { .id = UCLASS_DMA, .name = "dma", diff --git a/include/dma.h b/include/dma.h index 50e9652..6bad2264 100644 --- a/include/dma.h +++ b/include/dma.h @@ -46,6 +46,7 @@ struct dma_ops { */ int (*transfer)(struct udevice *dev, int direction, void *dst, void *src, size_t len); + int (*transfer_zeroes)(struct udevice *dev, void *dst, size_t len); }; /* @@ -82,4 +83,15 @@ int dma_get_device(u32 transfer_type, struct udevice **devp); */ int dma_memcpy(void *dst, void *src, size_t len); +/* + * dma_memcpy_zeroes - Fill up destination with zeros through DMA. + * + * @dev: The DMA device + * @dst: destination pointer + * @len: length to be copied with zero + * @return: on successful transfer returns zero. + * on failure returns error code. + */ +int dma_memcpy_zeroes(struct udevice *dev, void *dst, size_t len); + #endif /* _DMA_H_ */ From patchwork Thu May 31 08:08:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chee, Tien Fong" X-Patchwork-Id: 923238 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=intel.com Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 40xKvd5Qq2z9s0W for ; Thu, 31 May 2018 18:12:45 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 5C727C21E18; Thu, 31 May 2018 08:11:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=RCVD_IN_DNSWL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 9FCB6C21E1D; Thu, 31 May 2018 08:09:24 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 1293CC21E0F; Thu, 31 May 2018 08:09:15 +0000 (UTC) Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by lists.denx.de (Postfix) with ESMTPS id 03685C21DB5 for ; Thu, 31 May 2018 08:09:09 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 31 May 2018 01:09:09 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,463,1520924400"; d="scan'208";a="60068572" Received: from pg-iccf0339.altera.com ([10.104.4.2]) by fmsmga001.fm.intel.com with ESMTP; 31 May 2018 01:09:06 -0700 From: tien.fong.chee@intel.com To: u-boot@lists.denx.de Date: Thu, 31 May 2018 16:08:52 +0800 Message-Id: <1527754134-164985-4-git-send-email-tien.fong.chee@intel.com> X-Mailer: git-send-email 1.7.7.4 In-Reply-To: <1527754134-164985-1-git-send-email-tien.fong.chee@intel.com> References: <1527754134-164985-1-git-send-email-tien.fong.chee@intel.com> Cc: Marek Vasut , Tom Rini , Tien Fong Chee , Mugunthan V N , Ching Liang See , Westergteen Dalon Subject: [U-Boot] [PATCH 3/5] drivers: dma: Factor out dma_get_device from DMA class function X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Tien Fong Chee Factor out the dma_get_device from DMA class function so caller can set some configuration and changes on the DMA device structure which is return by calling dma_get_device before device instance is processed by DMA class functions. Signed-off-by: Tien Fong Chee Reviewed-by: Simon Glass --- drivers/dma/dma-uclass.c | 8 +------- drivers/mtd/spi/spi_flash.c | 9 ++++++++- include/dma.h | 3 ++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c index cb83c24..5663be8 100644 --- a/drivers/dma/dma-uclass.c +++ b/drivers/dma/dma-uclass.c @@ -40,15 +40,9 @@ int dma_get_device(u32 transfer_type, struct udevice **devp) return ret; } -int dma_memcpy(void *dst, void *src, size_t len) +int dma_memcpy(struct udevice *dev, void *dst, void *src, size_t len) { - struct udevice *dev; const struct dma_ops *ops; - int ret; - - ret = dma_get_device(DMA_SUPPORTS_MEM_TO_MEM, &dev); - if (ret < 0) - return ret; ops = device_get_ops(dev); if (!ops->transfer) diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 2911729..7aa66b6 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -457,7 +457,14 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, void __weak spi_flash_copy_mmap(void *data, void *offset, size_t len) { #ifdef CONFIG_DMA - if (!dma_memcpy(data, offset, len)) + struct udevice *dev; + int ret; + + ret = dma_get_device(DMA_SUPPORTS_MEM_TO_MEM, &dev); + if (ret < 0) + return; + + if (!dma_memcpy(dev, data, offset, len)) return; #endif memcpy(data, offset, len); diff --git a/include/dma.h b/include/dma.h index 6bad2264..0a0c9dd 100644 --- a/include/dma.h +++ b/include/dma.h @@ -75,13 +75,14 @@ int dma_get_device(u32 transfer_type, struct udevice **devp); * dma_memcpy - try to use DMA to do a mem copy which will be * much faster than CPU mem copy * + * @dev - The DMA device * @dst - destination pointer * @src - souce pointer * @len - data length to be copied * @return - on successful transfer returns no of bytes transferred and on failure return error code. */ -int dma_memcpy(void *dst, void *src, size_t len); +int dma_memcpy(struct udevice *dev, void *dst, void *src, size_t len); /* * dma_memcpy_zeroes - Fill up destination with zeros through DMA. From patchwork Thu May 31 08:08:53 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chee, Tien Fong" X-Patchwork-Id: 923236 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=intel.com Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 40xKtZ6rbrz9s0W for ; Thu, 31 May 2018 18:11:50 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 92F3AC21CB1; Thu, 31 May 2018 08:11:14 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=RCVD_IN_DNSWL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id E74DAC21DC1; Thu, 31 May 2018 08:09:18 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id B63CDC21DD9; Thu, 31 May 2018 08:09:16 +0000 (UTC) Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by lists.denx.de (Postfix) with ESMTPS id 026E8C21DFF for ; Thu, 31 May 2018 08:09:11 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 31 May 2018 01:09:11 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,463,1520924400"; d="scan'208";a="60068584" Received: from pg-iccf0339.altera.com ([10.104.4.2]) by fmsmga001.fm.intel.com with ESMTP; 31 May 2018 01:09:09 -0700 From: tien.fong.chee@intel.com To: u-boot@lists.denx.de Date: Thu, 31 May 2018 16:08:53 +0800 Message-Id: <1527754134-164985-5-git-send-email-tien.fong.chee@intel.com> X-Mailer: git-send-email 1.7.7.4 In-Reply-To: <1527754134-164985-1-git-send-email-tien.fong.chee@intel.com> References: <1527754134-164985-1-git-send-email-tien.fong.chee@intel.com> Cc: Marek Vasut , Tom Rini , Tien Fong Chee , Mugunthan V N , Ching Liang See , Westergteen Dalon Subject: [U-Boot] [PATCH 4/5] include: dma: Update the function description for dma_memcpy X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Tien Fong Chee Update the dma_memcpy description on return argument for DMA330 driver. Signed-off-by: Tien Fong Chee --- include/dma.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/dma.h b/include/dma.h index 0a0c9dd..b825c1e 100644 --- a/include/dma.h +++ b/include/dma.h @@ -79,8 +79,8 @@ int dma_get_device(u32 transfer_type, struct udevice **devp); * @dst - destination pointer * @src - souce pointer * @len - data length to be copied - * @return - on successful transfer returns no of bytes - transferred and on failure return error code. + * @return - on successful transfer returns no of bytes or zero(for DMA330) + * transferred and on failure return error code. */ int dma_memcpy(struct udevice *dev, void *dst, void *src, size_t len); From patchwork Thu May 31 08:08:54 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chee, Tien Fong" X-Patchwork-Id: 923237 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=intel.com Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 40xKv15VDfz9s0W for ; Thu, 31 May 2018 18:12:13 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 765AEC21E12; Thu, 31 May 2018 08:11:45 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=RCVD_IN_DNSWL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 62C3DC21DDC; Thu, 31 May 2018 08:09:26 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id C2C8AC21E0F; Thu, 31 May 2018 08:09:18 +0000 (UTC) Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by lists.denx.de (Postfix) with ESMTPS id 95DF5C21DFD for ; Thu, 31 May 2018 08:09:14 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 31 May 2018 01:09:14 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,463,1520924400"; d="scan'208";a="60068601" Received: from pg-iccf0339.altera.com ([10.104.4.2]) by fmsmga001.fm.intel.com with ESMTP; 31 May 2018 01:09:11 -0700 From: tien.fong.chee@intel.com To: u-boot@lists.denx.de Date: Thu, 31 May 2018 16:08:54 +0800 Message-Id: <1527754134-164985-6-git-send-email-tien.fong.chee@intel.com> X-Mailer: git-send-email 1.7.7.4 In-Reply-To: <1527754134-164985-1-git-send-email-tien.fong.chee@intel.com> References: <1527754134-164985-1-git-send-email-tien.fong.chee@intel.com> Cc: Marek Vasut , Tom Rini , Tien Fong Chee , Mugunthan V N , Ching Liang See , Westergteen Dalon Subject: [U-Boot] [PATCH 5/5] arm: dts: socfpga: stratix10: update pdma X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Tien Fong Chee Update pdma properties for Stratix 10 Signed-off-by: Tien Fong Chee Reviewed-by: Simon Glass --- arch/arm/dts/socfpga_stratix10.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm/dts/socfpga_stratix10.dtsi b/arch/arm/dts/socfpga_stratix10.dtsi index ccd3f32..311ba09 100644 --- a/arch/arm/dts/socfpga_stratix10.dtsi +++ b/arch/arm/dts/socfpga_stratix10.dtsi @@ -82,6 +82,26 @@ ranges = <0 0 0 0xffffffff>; u-boot,dm-pre-reloc; + amba { + u-boot,dm-pre-reloc; + compatible = "arm,amba-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + pdma: pdma@ffda0000 { + u-boot,dm-pre-reloc; + compatible = "arm,pl330", "arm,dma330"; + reg = <0xffda0000 0x2000>; + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <32>; + dma-max-burst-size = <2>; + dma-burst-size = <2>; + dma-burst-length = <16>; + }; + }; + clkmgr@ffd1000 { compatible = "altr,clk-mgr"; reg = <0xffd10000 0x1000>;