From: Chin Liang See <clsee@altera.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [RFC 1/4] drivers: dma: Add the ARM PL330 DMA driver
Date: Thu, 13 Oct 2016 00:04:09 +0800 [thread overview]
Message-ID: <1476288249.2220.26.camel@altera.com> (raw)
In-Reply-To: <20161010155223.23751-2-dinguyen@kernel.org>
On Mon, 2016-10-10 at 10:52 -0500, Dinh Nguyen wrote:
> From: Dinh Nguyen <dinguyen@opensource.altera.com>
>
> Adopted from the Linux kernel PL330 DMA driver.
>
> Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com>
> ---
> arch/arm/include/asm/pl330.h | 105 +++++
> drivers/dma/pl330.c | 942
> +++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 1047 insertions(+)
> create mode 100644 arch/arm/include/asm/pl330.h
> create mode 100644 drivers/dma/pl330.c
>
> diff --git a/arch/arm/include/asm/pl330.h
> b/arch/arm/include/asm/pl330.h
> new file mode 100644
> index 0000000..dd19b4c
> --- /dev/null
> +++ b/arch/arm/include/asm/pl330.h
> @@ -0,0 +1,105 @@
> +/*
> + * Copyright (C) 2010 Samsung Electronics Co. Ltd.
> + * Jaswinder Singh <jassi.brar@samsung.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + *
> + * adapted from linux kernel pl330.h
> + */
> +
> +#ifndef __PL330_H_
> +#define __PL330_H_
> +
> +#define PL330_STATE_STOPPED (1 << 0)
> +#define PL330_STATE_EXECUTING (1 << 1)
> +#define PL330_STATE_WFE (1 << 2)
> +#define PL330_STATE_FAULTING (1 << 3)
> +#define PL330_STATE_COMPLETING (1 << 4)
> +#define PL330_STATE_WFP (1 << 5)
> +#define PL330_STATE_KILLING (1 << 6)
> +#define PL330_STATE_FAULT_COMPLETING (1 << 7)
> +#define PL330_STATE_CACHEMISS (1 << 8)
> +#define PL330_STATE_UPDTPC (1 << 9)
> +#define PL330_STATE_ATBARRIER (1 << 10)
> +#define PL330_STATE_QUEUEBUSY (1 << 11)
> +#define PL330_STATE_INVALID (1 << 15)
> +
> +#define PL330_DMA_MAX_BURST_SIZE 3
> +
Not sure this is true for other platform. If not, this would need goto
include/configs header files.
[..]
>
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> new file mode 100644
> index 0000000..a97cd9f
> --- /dev/null
> +++ b/drivers/dma/pl330.c
> @@ -0,0 +1,942 @@
> +/*
> + * Copyright (c) 2012 Samsung Electronics Co., Ltd.
> + * http://www.samsung.com
> + *
> + * Copyright (C) 2010 Samsung Electronics Co. Ltd.
> + * Jaswinder Singh <jassi.brar@samsung.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + */
> +
> +#include <asm/io.h>
> +#include <common.h>
> +#include <dma.h>
> +#include <dm/device.h>
> +#include <asm/pl330.h>
> +#include <asm/processor.h>
> +
>
[..]
> +
> +static inline u32 _state(struct pl330_transfer_struct *pl330)
> +{
> + void __iomem *regs = pl330->reg_base;
> + u32 val;
> +
> + val = readl(regs + CS(pl330->channel_num)) & 0xf;
> +
> + udelay(1);
> +
> + switch (val) {
> + case DS_ST_STOP:
> + return PL330_STATE_STOPPED;
> + case DS_ST_EXEC:
> + return PL330_STATE_EXECUTING;
> + case DS_ST_CMISS:
> + return PL330_STATE_CACHEMISS;
> + case DS_ST_UPDTPC:
> + return PL330_STATE_UPDTPC;
> + case DS_ST_WFE:
> + return PL330_STATE_WFE;
> + case DS_ST_FAULT:
> + return PL330_STATE_FAULTING;
> + case DS_ST_ATBRR:
> + return PL330_STATE_ATBARRIER;
This state and below would yield difference between channel and
manager.
[..]
>
> +/*
> + * DMA transfer setup (DMA_SUPPORTS_MEM_TO_MEM,
> DMA_SUPPORTS_MEM_TO_DEV or
> + DMA_SUPPORTS_DEV_TO_MEM)
> + * For Peripheral transfer, the FIFO threshold value is expected at
> + * 2 ^ pl330->brst_size * pl330->brst_len.
> + * Return: 1 for error or not successful
> + *
> + * channel_num - channel number assigned, valid from 0
> to 7
> + * src_addr - address to transfer from / source
> + * dst_addr - address to transfer to / destination
> + * len - number of bytes to be transferred
> + * brst_size - valid from 0 - 3
> + * where 0 = 1 (2 ^ 0) bytes and 3 = 8 bytes
> (2 ^ 3)
> + * single_brst_size - single transfer size (from 0 - 3)
> + * brst_len - valid from 1 - 16 where each burst can
> trasfer 1 - 16
> + * data chunk (each chunk size equivalent to
> brst_size)
> + * peripheral_id assigned peripheral_id, valid from 0 to 31
> + * transfer_type DMA_SUPPORTS_MEM_TO_MEM,
> DMA_SUPPORTS_MEM_TO_DEV or
> + * DMA_SUPPORTS_DEV_TO_MEM
> + * buf_size - sizeof(buf)
> + * buf - buffer handler which will point to
> the memory
> + * allocated for dma microcode
> + */
> +static int pl330_transfer_setup(struct pl330_transfer_struct *pl330)
> +{
> + /* Variable declaration */
> + int off = 0; /* buffer offset clear
> to 0 */
> + int ret = 0;
> + unsigned loopjmp0, loopjmp1; /* for DMALPEND */
> + unsigned lcnt0 = 0; /* loop count 0 */
> + unsigned lcnt1 = 0; /* loop count 1 */
> + unsigned burst_size = 0;
> + unsigned len = pl330->len;
> + u32 ccr = 0; /* Channel Control
> Register */
> + struct pl330_reqcfg reqcfg;
> +
> + /* for burst, always use the maximum burst size and length
> */
> + pl330->brst_size = PL330_DMA_MAX_BURST_SIZE;
> + pl330->brst_len = 16;
> + pl330->single_brst_size = 1;
> +
> + /* burst_size = 2 ^ brst_size */
> + burst_size = 1 << pl330->brst_size;
> +
> + pl330->src_addr = (u32)&pl330->buf;
> + if (pl330->dst_addr & (burst_size - 1)) {
> + puts("ERROR PL330 : destination address
> unaligned\n");
> + return 1;
> + }
> +
Good to check the src_addr too. If unaligned, the microcode would not
be applicable.
> + /* DMAMOV DAR, x->dst_addr */
> + off += _emit_MOV(&pl330->buf[off], DAR, pl330->dst_addr);
> + /* DMAFLUSHP P(periheral_id) */
> + if (pl330->transfer_type != DMA_SUPPORTS_MEM_TO_MEM)
> + off += _emit_FLUSHP(&pl330->buf[off], pl330
> ->peripheral_id);
> +
> + /* Preparing the CCR value */
> + if (pl330->transfer_type == DMA_SUPPORTS_MEM_TO_DEV) {
> + reqcfg.dst_inc = 0; /* disable auto increment
> */
> + reqcfg.src_inc = 1; /* enable auto increment
> */
> + } else if (pl330->transfer_type == DMA_SUPPORTS_DEV_TO_MEM)
> {
> + reqcfg.dst_inc = 1;
> + reqcfg.src_inc = 0;
> + } else {
> + /* DMA_SUPPORTS_MEM_TO_MEM */
> + reqcfg.dst_inc = 1;
> + reqcfg.src_inc = 1;
> + }
We won't need setup based on transfer type as the microcode is setup to
write zero to mem only.
Thanks
Chin Liang
> +
> + reqcfg.nonsecure = 0; /* Secure mode */
> + reqcfg.dcctl = 0x1; /* noncacheable but bufferable */
> + reqcfg.scctl = 0x1;
> + reqcfg.privileged = 1; /* 1 - Priviledge */
> + reqcfg.insnaccess = 0; /* 0 - data access */
> + reqcfg.swap = 0; /* 0 - no endian swap */
> + reqcfg.brst_len = pl330->brst_len; /* DMA burst
> length */
> + reqcfg.brst_size = pl330->brst_size; /* DMA burst
> size */
> + /* Preparing the CCR value */
> + ccr = _prepare_ccr(&reqcfg);
> + /* DMAMOV CCR, ccr */
> + off += _emit_MOV(&pl330->buf[off], CCR, ccr);
> +
> + /* BURST */
> + /* Can initiate a burst? */
> + while (len >= burst_size * pl330->brst_len) {
> + lcnt0 = len / (burst_size * pl330->brst_len);
> + lcnt1 = 0;
> + if (lcnt0 >= 256 * 256)
> + lcnt0 = lcnt1 = 256;
> + else if (lcnt0 >= 256) {
> + lcnt1 = lcnt0 / 256;
> + lcnt0 = 256;
> + }
> + len = len -
> + (burst_size * pl330->brst_len * lcnt0 *
> lcnt1);
> +
> + if (lcnt1) {
> + /* DMALP1 */
> + off += _emit_LP(&pl330->buf[off], 1, lcnt1);
> + loopjmp1 = off;
> + }
> + /* DMALP0 */
> + off += _emit_LP(&pl330->buf[off], 0, lcnt0);
> + loopjmp0 = off;
> +
> + off += _emit_STZ(&pl330->buf[off]);
> + /* DMALP0END */
> + struct _arg_LPEND lpend;
> + lpend.cond = ALWAYS;
> + lpend.forever = 0;
> + lpend.loop = 0; /* loop cnt 0 */
> + lpend.bjump = off - loopjmp0;
> + off += _emit_LPEND(&pl330->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(&pl330->buf[off],
> &lpend);
> + }
> + /* ensure the microcode don't exceed buffer size */
> + if (off > pl330->buf_size) {
> + puts("ERROR PL330 : Exceed buffer size\n");
> + return 1;
> + }
> + }
> +
> + /* SINGLE */
> + pl330->brst_size = pl330->single_brst_size;
> + pl330->brst_len = 1;
> + /* burst_size = 2 ^ brst_size */
> + burst_size = (1 << pl330->brst_size);
> + lcnt0 = len / (burst_size * pl330->brst_len);
> +
> + /* ensure all data will be transfered */
> + len = len -
> + (burst_size * pl330->brst_len * lcnt0);
> + if (len)
> + puts("ERROR PL330 : Detected the possibility of
> untransfered"
> + "data. Please ensure correct single burst
> size\n");
> +
> + if (lcnt0) {
> + /* Preparing the CCR value */
> + reqcfg.brst_len = pl330->brst_len; /* DMA
> burst length */
> + reqcfg.brst_size = pl330->brst_size; /* DMA
> burst size */
> + ccr = _prepare_ccr(&reqcfg);
> + /* DMAMOV CCR, ccr */
> + off += _emit_MOV(&pl330->buf[off], CCR, ccr);
> +
> + /* DMALP0 */
> + off += _emit_LP(&pl330->buf[off], 0, lcnt0);
> + loopjmp0 = off;
> +
> + off += _emit_STZ(&pl330->buf[off]);
> + struct _arg_LPEND lpend1;
> + lpend1.cond = ALWAYS;
> + lpend1.forever = 0;
> + lpend1.loop = 0; /* loop cnt 0 */
> + lpend1.bjump = off - loopjmp0;
> + off += _emit_LPEND(&pl330->buf[off], &lpend1);
> + /* ensure the microcode don't exceed buffer size */
> + if (off > pl330->buf_size) {
> + puts("ERROR PL330 : Exceed buffer size\n");
> + return 1;
> + }
> + }
> +
> + /* DMAEND */
> + off += _emit_END(&pl330->buf[off]);
> +
> + ret = pl330_transfer_start(pl330);
> + if (ret)
> + return ret;
> +
> + ret = pl330_transfer_finish(pl330);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
>
[..]
next prev parent reply other threads:[~2016-10-12 16:04 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-10-10 15:52 [U-Boot] [RFC] 0/4] Add Pl330 DMA support Dinh Nguyen
2016-10-10 15:52 ` [U-Boot] [RFC 1/4] drivers: dma: Add the ARM PL330 DMA driver Dinh Nguyen
2016-10-12 16:04 ` Chin Liang See [this message]
2016-10-10 15:52 ` [U-Boot] [RFC 2/4] dma: Kconfig: Add CONFIG_PL330_DMA entry Dinh Nguyen
2016-10-12 16:05 ` Chin Liang See
2016-10-14 15:17 ` Marek Vasut
2016-10-10 15:52 ` [U-Boot] [RFC 3/4] dm: add DMA_SUPPORTS_DEV_TO_MEM type to DMA_UCLASS Dinh Nguyen
2016-10-13 0:03 ` Simon Glass
2016-10-14 15:20 ` Marek Vasut
2016-10-10 15:52 ` [U-Boot] [RFC 4/4] arm: socfpga: scrub the SDRAM to properly enable ECC support Dinh Nguyen
2016-10-12 16:13 ` Chin Liang See
2016-10-16 16:03 ` Marek Vasut
2016-10-14 7:23 ` [U-Boot] [RFC] 0/4] Add Pl330 DMA support Marek Vasut
2016-10-14 13:08 ` Dinh Nguyen
2016-10-14 15:09 ` Marek Vasut
2016-10-14 22:13 ` Dinh Nguyen
2016-10-15 16:43 ` Marek Vasut
2016-10-14 22:10 ` Dinh Nguyen
2016-10-16 15:59 ` Marek Vasut
2016-10-18 15:50 ` Dinh Nguyen
2016-10-18 18:36 ` Marek Vasut
2016-10-29 19:59 ` Marek Vasut
2016-11-01 15:43 ` Dinh Nguyen
2016-11-01 20:09 ` Marek Vasut
2016-11-01 20:39 ` Dinh Nguyen
2016-11-01 20:42 ` Marek Vasut
2016-11-01 20:43 ` Dinh Nguyen
2016-11-02 16:30 ` Dinh Nguyen
2016-11-02 20:47 ` Marek Vasut
2016-11-03 14:21 ` Dinh Nguyen
2016-11-04 20:56 ` Marek Vasut
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1476288249.2220.26.camel@altera.com \
--to=clsee@altera.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.