All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [U-boot] [Patch 0/4] keystone2: ecc: add ddr3 error detection and correction support
@ 2014-10-10 15:17 Ivan Khoronzhuk
  2014-10-10 15:17 ` [U-Boot] [U-boot] [Patch 1/4] dma: ti-edma3: introduce edma3 driver Ivan Khoronzhuk
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Ivan Khoronzhuk @ 2014-10-10 15:17 UTC (permalink / raw)
  To: u-boot

This series adds the DDR3 ECC support to enable ECC in the DDR3
EMIF controller for Keystone II devices.

Based on
"[U-boot] [Patch 0/5] keystone2: add network support for K2E SoC and EVM"
https://www.mail-archive.com/u-boot at lists.denx.de/msg148985.html

Hao Zhang (1):
  ARM: keystone: cmd_ddr3: add ddr3 commands to test ddr

Ivan Khoronzhuk (1):
  dma: ti-edma3: introduce edma3 driver

Vitaly Andrianov (2):
  ARM: keystone: msmc: extend functionality of SES
  keystone2: ecc: add ddr3 error detection and correction support

 arch/arm/cpu/armv7/keystone/Makefile               |   2 +-
 arch/arm/cpu/armv7/keystone/cmd_ddr3.c             | 247 +++++++++++++
 arch/arm/cpu/armv7/keystone/ddr3.c                 | 244 +++++++++++++
 arch/arm/cpu/armv7/keystone/msmc.c                 |  26 ++
 arch/arm/include/asm/arch-keystone/ddr3.h          |   6 +
 arch/arm/include/asm/arch-keystone/hardware-k2hk.h |   4 +
 arch/arm/include/asm/arch-keystone/hardware.h      |  52 +++
 arch/arm/include/asm/arch-keystone/msmc.h          |  28 ++
 arch/arm/include/asm/ti-common/ti-edma3.h          | 121 +++++++
 board/ti/ks2_evm/board.c                           |   3 +
 board/ti/ks2_evm/ddr3_k2hk.c                       |  16 +
 drivers/dma/Makefile                               |   1 +
 drivers/dma/ti-edma3.c                             | 384 +++++++++++++++++++++
 include/configs/ks2_evm.h                          |   4 -
 14 files changed, 1133 insertions(+), 5 deletions(-)
 create mode 100644 arch/arm/cpu/armv7/keystone/cmd_ddr3.c
 create mode 100644 arch/arm/include/asm/ti-common/ti-edma3.h
 create mode 100644 drivers/dma/ti-edma3.c

-- 
1.8.3.2

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [U-Boot] [U-boot] [Patch 1/4] dma: ti-edma3: introduce edma3 driver
  2014-10-10 15:17 [U-Boot] [U-boot] [Patch 0/4] keystone2: ecc: add ddr3 error detection and correction support Ivan Khoronzhuk
@ 2014-10-10 15:17 ` Ivan Khoronzhuk
  2014-10-10 15:17 ` [U-Boot] [U-boot] [Patch 2/4] ARM: keystone: msmc: extend functionality of SES Ivan Khoronzhuk
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Ivan Khoronzhuk @ 2014-10-10 15:17 UTC (permalink / raw)
  To: u-boot

The EDMA3 controller?s primary purpose is to service data transfers
that you program between two memory-mapped slave endpoints on the device.

Typical usage includes, but is not limited to the following:
- Servicing software-driven paging transfers (e.g., transfers from external
  memory, such as SDRAM to internal device memory, such as DSP L2 SRAM)
- Servicing event-driven peripherals, such as a serial port
- Performing sorting or sub-frame extraction of various data structures
- Offloading data transfers from the main device DSP(s)
- See the device-specific data manual for specific peripherals that are
  accessible via the EDMA3 controller

Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
---
 arch/arm/include/asm/ti-common/ti-edma3.h | 121 ++++++++++
 drivers/dma/Makefile                      |   1 +
 drivers/dma/ti-edma3.c                    | 384 ++++++++++++++++++++++++++++++
 3 files changed, 506 insertions(+)
 create mode 100644 arch/arm/include/asm/ti-common/ti-edma3.h
 create mode 100644 drivers/dma/ti-edma3.c

diff --git a/arch/arm/include/asm/ti-common/ti-edma3.h b/arch/arm/include/asm/ti-common/ti-edma3.h
new file mode 100644
index 0000000..5adc1da
--- /dev/null
+++ b/arch/arm/include/asm/ti-common/ti-edma3.h
@@ -0,0 +1,121 @@
+/*
+ * Enhanced Direct Memory Access (EDMA3) Controller
+ *
+ * (C) Copyright 2014
+ *     Texas Instruments Incorporated, <www.ti.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef _EDMA3_H_
+#define _EDMA3_H_
+
+#include <linux/stddef.h>
+
+#define EDMA3_PARSET_NULL_LINK			0xffff
+
+/*
+ * All parameter RAM set options
+ * opt field in edma3_param_set_config structure
+ */
+#define EDMA3_SLOPT_PRIV_LEVEL			BIT(31)
+#define EDMA3_SLOPT_PRIV_ID(id)			((0xf & (id)) << 24)
+#define EDMA3_SLOPT_INTERM_COMP_CHAIN_ENB	BIT(23)
+#define EDMA3_SLOPT_TRANS_COMP_CHAIN_ENB	BIT(22)
+#define EDMA3_SLOPT_INTERM_COMP_INT_ENB		BIT(21)
+#define EDMA3_SLOPT_TRANS_COMP_INT_ENB		BIT(20)
+#define EDMA3_SLOPT_COMP_CODE(code)		((0x3f & (code)) << 12)
+#define EDMA3_SLOPT_FIFO_WIDTH_8		0
+#define EDMA3_SLOPT_FIFO_WIDTH_16		(1 << 8)
+#define EDMA3_SLOPT_FIFO_WIDTH_32		(2 << 8)
+#define EDMA3_SLOPT_FIFO_WIDTH_64		(3 << 8)
+#define EDMA3_SLOPT_FIFO_WIDTH_128		(4 << 8)
+#define EDMA3_SLOPT_FIFO_WIDTH_256		(5 << 8)
+#define EDMA3_SLOPT_FIFO_WIDTH_SET(w)		((w & 0x7) << 8)
+#define EDMA3_SLOPT_STATIC			BIT(3)
+#define EDMA3_SLOPT_AB_SYNC			BIT(2)
+#define EDMA3_SLOPT_DST_ADDR_CONST_MODE		BIT(1)
+#define EDMA3_SLOPT_SRC_ADDR_CONST_MODE		BIT(0)
+
+enum edma3_address_mode {
+	INCR = 0,
+	FIFO = 1
+};
+
+enum edma3_fifo_width {
+	W8BIT = 0,
+	W16BIT = 1,
+	W32BIT = 2,
+	W64BIT = 3,
+	W128BIT = 4,
+	W256BIT = 5
+};
+
+enum edma3_sync_dimension {
+	ASYNC = 0,
+	ABSYNC = 1
+};
+
+/* PaRAM slots are laid out like this */
+struct edma3_slot_layout {
+	u32 opt;
+	u32 src;
+	u32 a_b_cnt;
+	u32 dst;
+	u32 src_dst_bidx;
+	u32 link_bcntrld;
+	u32 src_dst_cidx;
+	u32 ccnt;
+} __packed;
+
+/*
+ * Use this to assign trigger word number of edma3_slot_layout struct.
+ * trigger_word_name - is the exact name from edma3_slot_layout.
+ */
+#define EDMA3_TWORD(trigger_word_name)\
+		(offsetof(struct edma3_slot_layout, trigger_word_name) / 4)
+
+struct edma3_slot_config {
+	u32 opt;
+	u32 src;
+	u32 dst;
+	int bcnt;
+	int acnt;
+	int ccnt;
+	int src_bidx;
+	int dst_bidx;
+	int src_cidx;
+	int dst_cidx;
+	int bcntrld;
+	int link;
+};
+
+struct edma3_channel_config {
+	int slot;
+	int chnum;
+	int complete_code;	/* indicate pending complete interrupt */
+	int trigger_slot_word;	/* only used for qedma */
+};
+
+void qedma3_start(u32 base, struct edma3_channel_config *cfg);
+void qedma3_stop(u32 base, struct edma3_channel_config *cfg);
+void edma3_slot_configure(u32 base, int slot, struct edma3_slot_config *cfg);
+int edma3_check_for_transfer(u32 base, struct edma3_channel_config *cfg);
+void edma3_write_slot(u32 base, int slot, struct edma3_slot_layout *param);
+void edma3_read_slot(u32 base, int slot, struct edma3_slot_layout *param);
+
+void edma3_set_dest(u32 base, int slot, u32 dst, enum edma3_address_mode mode,
+		    enum edma3_fifo_width width);
+void edma3_set_dest_index(u32 base, unsigned slot, int bidx, int cidx);
+void edma3_set_dest_addr(u32 base, int slot, u32 dst);
+
+void edma3_set_src(u32 base, int slot, u32 src, enum edma3_address_mode mode,
+		   enum edma3_fifo_width width);
+void edma3_set_src_index(u32 base, unsigned slot, int bidx, int cidx);
+void edma3_set_src_addr(u32 base, int slot, u32 src);
+
+void edma3_set_transfer_params(u32 base, int slot, int acnt,
+			       int bcnt, int ccnt, u16 bcnt_rld,
+			       enum edma3_sync_dimension sync_mode);
+
+#endif
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 15b0780..4c8fcc2 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_FSLDMAFEC) += MCD_tasksInit.o MCD_dmaApi.o MCD_tasks.o
 obj-$(CONFIG_APBH_DMA) += apbh_dma.o
 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
diff --git a/drivers/dma/ti-edma3.c b/drivers/dma/ti-edma3.c
new file mode 100644
index 0000000..8184ded
--- /dev/null
+++ b/drivers/dma/ti-edma3.c
@@ -0,0 +1,384 @@
+/*
+ * Enhanced Direct Memory Access (EDMA3) Controller
+ *
+ * (C) Copyright 2014
+ *     Texas Instruments Incorporated, <www.ti.com>
+ *
+ * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#include <asm/ti-common/ti-edma3.h>
+
+#define EDMA3_SL_BASE(slot)			(0x4000 + ((slot) << 5))
+#define EDMA3_SL_MAX_NUM			512
+#define EDMA3_SLOPT_FIFO_WIDTH_MASK		(0x7 << 8)
+
+#define EDMA3_QCHMAP(ch)			0x0200 + ((ch) << 2)
+#define EDMA3_CHMAP_PARSET_MASK			0x1ff
+#define EDMA3_CHMAP_PARSET_SHIFT		0x5
+#define EDMA3_CHMAP_TRIGWORD_SHIFT		0x2
+
+#define EDMA3_QEMCR				0x314
+#define EDMA3_IPR				0x1068
+#define EDMA3_IPRH				0x106c
+#define EDMA3_ICR				0x1070
+#define EDMA3_ICRH				0x1074
+#define EDMA3_QEECR				0x1088
+#define EDMA3_QEESR				0x108c
+#define EDMA3_QSECR				0x1094
+
+/**
+ * qedma3_start - start qdma on a channel
+ * @base: base address of edma
+ * @cfg: pinter to struct edma3_channel_config where you can set
+ * the slot number to associate with, the chnum, which corresponds
+ * your quick channel number 0-7, complete code - transfer complete code
+ * and trigger slot word - which has to correspond to the word number in
+ * edma3_slot_layout struct for generating event.
+ *
+ */
+void qedma3_start(u32 base, struct edma3_channel_config *cfg)
+{
+	u32 qchmap;
+
+	/* Clear the pending int bit */
+	if (cfg->complete_code < 32)
+		__raw_writel(1 << cfg->complete_code, base + EDMA3_ICR);
+	else
+		__raw_writel(1 << cfg->complete_code, base + EDMA3_ICRH);
+
+	/* Map parameter set and trigger word 7 to quick channel */
+	qchmap = ((EDMA3_CHMAP_PARSET_MASK & cfg->slot)
+		  << EDMA3_CHMAP_PARSET_SHIFT) |
+		  (cfg->trigger_slot_word << EDMA3_CHMAP_TRIGWORD_SHIFT);
+
+	__raw_writel(qchmap, base + EDMA3_QCHMAP(cfg->chnum));
+
+	/* Clear missed event if set*/
+	__raw_writel(1 << cfg->chnum, base + EDMA3_QSECR);
+	__raw_writel(1 << cfg->chnum, base + EDMA3_QEMCR);
+
+	/* Enable qdma channel event */
+	__raw_writel(1 << cfg->chnum, base + EDMA3_QEESR);
+}
+
+/**
+ * edma3_set_dest - set initial DMA destination address in parameter RAM slot
+ * @base: base address of edma
+ * @slot: parameter RAM slot being configured
+ * @dst: physical address of destination (memory, controller FIFO, etc)
+ * @addressMode: INCR, except in very rare cases
+ * @width: ignored unless @addressMode is FIFO, else specifies the
+ *	width to use when addressing the fifo (e.g. W8BIT, W32BIT)
+ *
+ * Note that the destination address is modified during the DMA transfer
+ * according to edma3_set_dest_index().
+ */
+void edma3_set_dest(u32 base, int slot, u32 dst, enum edma3_address_mode mode,
+		    enum edma3_fifo_width width)
+{
+	u32 opt;
+	struct edma3_slot_layout *rg;
+
+	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
+
+	opt = __raw_readl(&rg->opt);
+	if (mode == FIFO)
+		opt = (opt & EDMA3_SLOPT_FIFO_WIDTH_MASK) |
+		       (EDMA3_SLOPT_DST_ADDR_CONST_MODE |
+			EDMA3_SLOPT_FIFO_WIDTH_SET(width));
+	else
+		opt &= ~EDMA3_SLOPT_DST_ADDR_CONST_MODE;
+
+	__raw_writel(opt, &rg->opt);
+	__raw_writel(dst, &rg->dst);
+}
+
+/**
+ * edma3_set_dest_index - configure DMA destination address indexing
+ * @base: base address of edma
+ * @slot: parameter RAM slot being configured
+ * @bidx: byte offset between destination arrays in a frame
+ * @cidx: byte offset between destination frames in a block
+ *
+ * Offsets are specified to support either contiguous or discontiguous
+ * memory transfers, or repeated access to a hardware register, as needed.
+ * When accessing hardware registers, both offsets are normally zero.
+ */
+void edma3_set_dest_index(u32 base, unsigned slot, int bidx, int cidx)
+{
+	u32 src_dst_bidx;
+	u32 src_dst_cidx;
+	struct edma3_slot_layout *rg;
+
+	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
+
+	src_dst_bidx = __raw_readl(&rg->src_dst_bidx);
+	src_dst_cidx = __raw_readl(&rg->src_dst_cidx);
+
+	__raw_writel((src_dst_bidx & 0x0000ffff) | (bidx << 16),
+		     &rg->src_dst_bidx);
+	__raw_writel((src_dst_cidx & 0x0000ffff) | (cidx << 16),
+		     &rg->src_dst_cidx);
+}
+
+/**
+ * edma3_set_dest_addr - set destination address for slot only
+ */
+void edma3_set_dest_addr(u32 base, int slot, u32 dst)
+{
+	struct edma3_slot_layout *rg;
+
+	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
+	__raw_writel(dst, &rg->dst);
+}
+
+/**
+ * edma3_set_src - set initial DMA source address in parameter RAM slot
+ * @base: base address of edma
+ * @slot: parameter RAM slot being configured
+ * @src_port: physical address of source (memory, controller FIFO, etc)
+ * @mode: INCR, except in very rare cases
+ * @width: ignored unless @addressMode is FIFO, else specifies the
+ *	width to use when addressing the fifo (e.g. W8BIT, W32BIT)
+ *
+ * Note that the source address is modified during the DMA transfer
+ * according to edma3_set_src_index().
+ */
+void edma3_set_src(u32 base, int slot, u32 src, enum edma3_address_mode mode,
+		   enum edma3_fifo_width width)
+{
+	u32 opt;
+	struct edma3_slot_layout *rg;
+
+	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
+
+	opt = __raw_readl(&rg->opt);
+	if (mode == FIFO)
+		opt = (opt & EDMA3_SLOPT_FIFO_WIDTH_MASK) |
+		       (EDMA3_SLOPT_DST_ADDR_CONST_MODE |
+			EDMA3_SLOPT_FIFO_WIDTH_SET(width));
+	else
+		opt &= ~EDMA3_SLOPT_DST_ADDR_CONST_MODE;
+
+	__raw_writel(opt, &rg->opt);
+	__raw_writel(src, &rg->src);
+}
+
+/**
+ * edma3_set_src_index - configure DMA source address indexing
+ * @base: base address of edma
+ * @slot: parameter RAM slot being configured
+ * @bidx: byte offset between source arrays in a frame
+ * @cidx: byte offset between source frames in a block
+ *
+ * Offsets are specified to support either contiguous or discontiguous
+ * memory transfers, or repeated access to a hardware register, as needed.
+ * When accessing hardware registers, both offsets are normally zero.
+ */
+void edma3_set_src_index(u32 base, unsigned slot, int bidx, int cidx)
+{
+	u32 src_dst_bidx;
+	u32 src_dst_cidx;
+	struct edma3_slot_layout *rg;
+
+	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
+
+	src_dst_bidx = __raw_readl(&rg->src_dst_bidx);
+	src_dst_cidx = __raw_readl(&rg->src_dst_cidx);
+
+	__raw_writel((src_dst_bidx & 0xffff0000) | bidx,
+		     &rg->src_dst_bidx);
+	__raw_writel((src_dst_cidx & 0xffff0000) | cidx,
+		     &rg->src_dst_cidx);
+}
+
+/**
+ * edma3_set_src_addr - set source address for slot only
+ */
+void edma3_set_src_addr(u32 base, int slot, u32 src)
+{
+	struct edma3_slot_layout *rg;
+
+	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
+	__raw_writel(src, &rg->src);
+}
+
+/**
+ * edma3_set_transfer_params - configure DMA transfer parameters
+ * @base: base address of edma
+ * @slot: parameter RAM slot being configured
+ * @acnt: how many bytes per array (at least one)
+ * @bcnt: how many arrays per frame (at least one)
+ * @ccnt: how many frames per block (at least one)
+ * @bcnt_rld: used only for A-Synchronized transfers; this specifies
+ *	the value to reload into bcnt when it decrements to zero
+ * @sync_mode: ASYNC or ABSYNC
+ *
+ * See the EDMA3 documentation to understand how to configure and link
+ * transfers using the fields in PaRAM slots.  If you are not doing it
+ * all at once with edma3_write_slot(), you will use this routine
+ * plus two calls each for source and destination, setting the initial
+ * address and saying how to index that address.
+ *
+ * An example of an A-Synchronized transfer is a serial link using a
+ * single word shift register.  In that case, @acnt would be equal to
+ * that word size; the serial controller issues a DMA synchronization
+ * event to transfer each word, and memory access by the DMA transfer
+ * controller will be word-at-a-time.
+ *
+ * An example of an AB-Synchronized transfer is a device using a FIFO.
+ * In that case, @acnt equals the FIFO width and @bcnt equals its depth.
+ * The controller with the FIFO issues DMA synchronization events when
+ * the FIFO threshold is reached, and the DMA transfer controller will
+ * transfer one frame to (or from) the FIFO.  It will probably use
+ * efficient burst modes to access memory.
+ */
+void edma3_set_transfer_params(u32 base, int slot, int acnt,
+			       int bcnt, int ccnt, u16 bcnt_rld,
+			       enum edma3_sync_dimension sync_mode)
+{
+	u32 opt;
+	u32 link_bcntrld;
+	struct edma3_slot_layout *rg;
+
+	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
+
+	link_bcntrld = __raw_readl(&rg->link_bcntrld);
+
+	__raw_writel((bcnt_rld << 16) | (0x0000ffff & link_bcntrld),
+		     &rg->link_bcntrld);
+
+	opt = __raw_readl(&rg->opt);
+	if (sync_mode == ASYNC)
+		__raw_writel(opt & ~EDMA3_SLOPT_AB_SYNC, &rg->opt);
+	else
+		__raw_writel(opt | EDMA3_SLOPT_AB_SYNC, &rg->opt);
+
+	/* Set the acount, bcount, ccount registers */
+	__raw_writel((bcnt << 16) | (acnt & 0xffff), &rg->a_b_cnt);
+	__raw_writel(0xffff & ccnt, &rg->ccnt);
+}
+
+/**
+ * edma3_write_slot - write parameter RAM data for slot
+ * @base: base address of edma
+ * @slot: number of parameter RAM slot being modified
+ * @param: data to be written into parameter RAM slot
+ *
+ * Use this to assign all parameters of a transfer at once.  This
+ * allows more efficient setup of transfers than issuing multiple
+ * calls to set up those parameters in small pieces, and provides
+ * complete control over all transfer options.
+ */
+void edma3_write_slot(u32 base, int slot, struct edma3_slot_layout *param)
+{
+	int i;
+	u32 *p = (u32 *)param;
+	u32 *addr = (u32 *)(base + EDMA3_SL_BASE(slot));
+
+	for (i = 0; i < sizeof(struct edma3_slot_layout)/4; i += 4)
+		__raw_writel(*p++, addr++);
+}
+
+/**
+ * edma3_read_slot - read parameter RAM data from slot
+ * @base: base address of edma
+ * @slot: number of parameter RAM slot being copied
+ * @param: where to store copy of parameter RAM data
+ *
+ * Use this to read data from a parameter RAM slot, perhaps to
+ * save them as a template for later reuse.
+ */
+void edma3_read_slot(u32 base, int slot, struct edma3_slot_layout *param)
+{
+	int i;
+	u32 *p = (u32 *)param;
+	u32 *addr = (u32 *)(base + EDMA3_SL_BASE(slot));
+
+	for (i = 0; i < sizeof(struct edma3_slot_layout)/4; i += 4)
+		*p++ = __raw_readl(addr++);
+}
+
+void edma3_slot_configure(u32 base, int slot, struct edma3_slot_config *cfg)
+{
+	struct edma3_slot_layout *rg;
+
+	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
+
+	__raw_writel(cfg->opt, &rg->opt);
+	__raw_writel(cfg->src, &rg->src);
+	__raw_writel((cfg->bcnt << 16) | (cfg->acnt & 0xffff), &rg->a_b_cnt);
+	__raw_writel(cfg->dst, &rg->dst);
+	__raw_writel((cfg->dst_bidx << 16) |
+		     (cfg->src_bidx & 0xffff), &rg->src_dst_bidx);
+	__raw_writel((cfg->bcntrld << 16) |
+		     (cfg->link & 0xffff), &rg->link_bcntrld);
+	__raw_writel((cfg->dst_cidx << 16) |
+		     (cfg->src_cidx & 0xffff), &rg->src_dst_cidx);
+	__raw_writel(0xffff & cfg->ccnt, &rg->ccnt);
+}
+
+/**
+ * edma3_check_for_transfer - check if transfer coplete by checking
+ * interrupt pending bit. Clear interrupt pending bit if complete.
+ * @base: base address of edma
+ * @cfg: pinter to struct edma3_channel_config which was passed
+ * to qedma3_start when you started qdma channel
+ *
+ * Return 0 if complete, 1 if not.
+ */
+int edma3_check_for_transfer(u32 base, struct edma3_channel_config *cfg)
+{
+	u32 inum;
+	u32 ipr_base;
+	u32 icr_base;
+
+	if (cfg->complete_code < 32) {
+		ipr_base = base + EDMA3_IPR;
+		icr_base = base + EDMA3_ICR;
+		inum = 1 << cfg->complete_code;
+	} else {
+		ipr_base = base + EDMA3_IPRH;
+		icr_base = base + EDMA3_ICRH;
+		inum = 1 << (cfg->complete_code - 32);
+	}
+
+	/* check complete interrupt */
+	if (!(__raw_readl(ipr_base) & inum))
+		return 1;
+
+	/* clean up the pending int bit */
+	__raw_writel(inum, icr_base);
+
+	return 0;
+}
+
+/**
+ * qedma3_stop - stops dma on the channel passed
+ * @base: base address of edma
+ * @cfg: pinter to struct edma3_channel_config which was passed
+ * to qedma3_start when you started qdma channel
+ */
+void qedma3_stop(u32 base, struct edma3_channel_config *cfg)
+{
+	/* Disable qdma channel event */
+	__raw_writel(1 << cfg->chnum, base + EDMA3_QEECR);
+
+	/* clean up the interrupt indication */
+	if (cfg->complete_code < 32)
+		__raw_writel(1 << cfg->complete_code, base + EDMA3_ICR);
+	else
+		__raw_writel(1 << cfg->complete_code, base + EDMA3_ICRH);
+
+	/* Clear missed event if set*/
+	__raw_writel(1 << cfg->chnum, base + EDMA3_QSECR);
+	__raw_writel(1 << cfg->chnum, base + EDMA3_QEMCR);
+
+	/* Clear the channel map */
+	__raw_writel(0, base + EDMA3_QCHMAP(cfg->chnum));
+}
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [U-Boot] [U-boot] [Patch 2/4] ARM: keystone: msmc: extend functionality of SES
  2014-10-10 15:17 [U-Boot] [U-boot] [Patch 0/4] keystone2: ecc: add ddr3 error detection and correction support Ivan Khoronzhuk
  2014-10-10 15:17 ` [U-Boot] [U-boot] [Patch 1/4] dma: ti-edma3: introduce edma3 driver Ivan Khoronzhuk
@ 2014-10-10 15:17 ` Ivan Khoronzhuk
  2014-10-10 15:17 ` [U-Boot] [U-boot] [Patch 3/4] keystone2: ecc: add ddr3 error detection and correction support Ivan Khoronzhuk
  2014-10-10 15:17 ` [U-Boot] [U-boot] [Patch 4/4] ARM: keystone: cmd_ddr3: add ddr3 commands to test ddr Ivan Khoronzhuk
  3 siblings, 0 replies; 5+ messages in thread
From: Ivan Khoronzhuk @ 2014-10-10 15:17 UTC (permalink / raw)
  To: u-boot

From: Vitaly Andrianov <vitalya@ti.com>

Add functions to set/get SES PMAX values of Pivilege ID pair.
Also add msmc module definitions.

Acked-by: Murali Karicheri <m-karicheri2@ti.com>
Signed-off-by: Hao Zhang <hzhang@ti.com>
Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
---
 arch/arm/cpu/armv7/keystone/msmc.c            | 26 +++++++++++++++++++++++++
 arch/arm/include/asm/arch-keystone/hardware.h |  6 ++++++
 arch/arm/include/asm/arch-keystone/msmc.h     | 28 +++++++++++++++++++++++++++
 3 files changed, 60 insertions(+)

diff --git a/arch/arm/cpu/armv7/keystone/msmc.c b/arch/arm/cpu/armv7/keystone/msmc.c
index 7d8e597..7899141 100644
--- a/arch/arm/cpu/armv7/keystone/msmc.c
+++ b/arch/arm/cpu/armv7/keystone/msmc.c
@@ -66,3 +66,29 @@ void msmc_share_all_segments(int priv_id)
 		msmc->ses[priv_id][j].mpaxh &= 0xffffff7ful;
 	}
 }
+
+void msmc_map_ses_segment(int priv_id, int ses_pair,
+			  u32 src_pfn, u32 dst_pfn, enum mpax_seg_size size)
+{
+	struct msms_regs *msmc = (struct msms_regs *)KS2_MSMC_CTRL_BASE;
+
+	msmc->ses[priv_id][ses_pair].mpaxh = src_pfn << 12 |
+					     (size & 0x1f) | 0x80;
+	msmc->ses[priv_id][ses_pair].mpaxl = dst_pfn << 8 | 0x3f;
+}
+
+void msmc_get_ses_mpax(int priv_id, int ses_pair, u32 *mpax)
+{
+	struct msms_regs *msmc = (struct msms_regs *)KS2_MSMC_CTRL_BASE;
+
+	*mpax++ = msmc->ses[priv_id][ses_pair].mpaxl;
+	*mpax = msmc->ses[priv_id][ses_pair].mpaxh;
+}
+
+void msmc_set_ses_mpax(int priv_id, int ses_pair, u32 *mpax)
+{
+	struct msms_regs *msmc = (struct msms_regs *)KS2_MSMC_CTRL_BASE;
+
+	msmc->ses[priv_id][ses_pair].mpaxl = *mpax++;
+	msmc->ses[priv_id][ses_pair].mpaxh = *mpax;
+}
diff --git a/arch/arm/include/asm/arch-keystone/hardware.h b/arch/arm/include/asm/arch-keystone/hardware.h
index 6788001..d2bd6cb 100644
--- a/arch/arm/include/asm/arch-keystone/hardware.h
+++ b/arch/arm/include/asm/arch-keystone/hardware.h
@@ -165,6 +165,12 @@ typedef volatile unsigned int   *dv_reg_p;
 #define KS2_MSMC_CTRL_BASE		0x0bc00000
 #define KS2_MSMC_DATA_BASE		0x0c000000
 
+/* MSMC segment size shift bits */
+#define KS2_MSMC_SEG_SIZE_SHIFT		12
+#define KS2_MSMC_MAP_SEG_NUM		(2 << (30 - KS2_MSMC_SEG_SIZE_SHIFT))
+#define KS2_MSMC_DST_SEG_BASE		(CONFIG_SYS_LPAE_SDRAM_BASE >> \
+					KS2_MSMC_SEG_SIZE_SHIFT)
+
 /* USB */
 #define KS2_USB_SS_BASE			0x02680000
 #define KS2_USB_HOST_XHCI_BASE		(KS2_USB_SS_BASE + 0x10000)
diff --git a/arch/arm/include/asm/arch-keystone/msmc.h b/arch/arm/include/asm/arch-keystone/msmc.h
index c320db5..083f5ba 100644
--- a/arch/arm/include/asm/arch-keystone/msmc.h
+++ b/arch/arm/include/asm/arch-keystone/msmc.h
@@ -12,6 +12,34 @@
 
 #include <asm/arch/hardware.h>
 
+enum mpax_seg_size {
+	MPAX_SEG_4K = 0x0b,
+	MPAX_SEG_8K,
+	MPAX_SEG_16K,
+	MPAX_SEG_32K,
+	MPAX_SEG_64K,
+	MPAX_SEG_128K,
+	MPAX_SEG_256K,
+	MPAX_SEG_512K,
+	MPAX_SEG_1M,
+	MPAX_SEG_2M,
+	MPAX_SEG_4M,
+	MPAX_SEG_8M,
+	MPAX_SEG_16M,
+	MPAX_SEG_32M,
+	MPAX_SEG_64M,
+	MPAX_SEG_128M,
+	MPAX_SEG_256M,
+	MPAX_SEG_512M,
+	MPAX_SEG_1G,
+	MPAX_SEG_2G,
+	MPAX_SEG_4G
+};
+
 void msmc_share_all_segments(int priv_id);
+void msmc_get_ses_mpax(int priv_id, int ses_pair, u32 *mpax);
+void msmc_set_ses_mpax(int priv_id, int ses_pair, u32 *mpax);
+void msmc_map_ses_segment(int priv_id, int ses_pair,
+			  u32 src_pfn, u32 dst_pfn, enum mpax_seg_size size);
 
 #endif
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [U-Boot] [U-boot] [Patch 3/4] keystone2: ecc: add ddr3 error detection and correction support
  2014-10-10 15:17 [U-Boot] [U-boot] [Patch 0/4] keystone2: ecc: add ddr3 error detection and correction support Ivan Khoronzhuk
  2014-10-10 15:17 ` [U-Boot] [U-boot] [Patch 1/4] dma: ti-edma3: introduce edma3 driver Ivan Khoronzhuk
  2014-10-10 15:17 ` [U-Boot] [U-boot] [Patch 2/4] ARM: keystone: msmc: extend functionality of SES Ivan Khoronzhuk
@ 2014-10-10 15:17 ` Ivan Khoronzhuk
  2014-10-10 15:17 ` [U-Boot] [U-boot] [Patch 4/4] ARM: keystone: cmd_ddr3: add ddr3 commands to test ddr Ivan Khoronzhuk
  3 siblings, 0 replies; 5+ messages in thread
From: Ivan Khoronzhuk @ 2014-10-10 15:17 UTC (permalink / raw)
  To: u-boot

From: Vitaly Andrianov <vitalya@ti.com>

This patch adds the DDR3 ECC support to enable ECC in the DDR3
EMIF controller for Keystone II devices.

By default, ECC will only be enabled if RMW is supported in the
DDR EMIF controller. The entire DDR memory will be scrubbed to
zero using an EDMA channel after ECC is enabled and before
u-boot is re-located to DDR memory.

An ecc_test environment variable is added for ECC testing.
If ecc_test is set to 0, a detection of 2-bit error will reset
the device, if ecc_test is set to 1, 2-bit error detection
will not reset the device, user can still boot the kernel to
check the ECC error handling in kernel.

Signed-off-by: Hao Zhang <hzhang@ti.com>
Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
---
 arch/arm/cpu/armv7/keystone/ddr3.c                 | 244 +++++++++++++++++++++
 arch/arm/include/asm/arch-keystone/ddr3.h          |   6 +
 arch/arm/include/asm/arch-keystone/hardware-k2hk.h |   4 +
 arch/arm/include/asm/arch-keystone/hardware.h      |  46 ++++
 board/ti/ks2_evm/board.c                           |   3 +
 board/ti/ks2_evm/ddr3_k2hk.c                       |  16 ++
 6 files changed, 319 insertions(+)

diff --git a/arch/arm/cpu/armv7/keystone/ddr3.c b/arch/arm/cpu/armv7/keystone/ddr3.c
index 2eabec1..923906a 100644
--- a/arch/arm/cpu/armv7/keystone/ddr3.c
+++ b/arch/arm/cpu/armv7/keystone/ddr3.c
@@ -9,9 +9,19 @@
 
 #include <asm/io.h>
 #include <common.h>
+#include <asm/arch/msmc.h>
 #include <asm/arch/ddr3.h>
 #include <asm/arch/psc_defs.h>
 
+#include <asm/ti-common/ti-edma3.h>
+
+#define DDR3_EDMA_BLK_SIZE_SHIFT	10
+#define DDR3_EDMA_BLK_SIZE		(1 << DDR3_EDMA_BLK_SIZE_SHIFT)
+#define DDR3_EDMA_BCNT			0x8000
+#define DDR3_EDMA_CCNT			1
+#define DDR3_EDMA_XF_SIZE		(DDR3_EDMA_BLK_SIZE * DDR3_EDMA_BCNT)
+#define DDR3_EDMA_SLOT_NUM		1
+
 void ddr3_init_ddrphy(u32 base, struct ddr3_phy_config *phy_cfg)
 {
 	unsigned int tmp;
@@ -70,6 +80,240 @@ void ddr3_init_ddremif(u32 base, struct ddr3_emif_config *emif_cfg)
 	__raw_writel(emif_cfg->sdrfc,  base + KS2_DDR3_SDRFC_OFFSET);
 }
 
+int ddr3_ecc_support_rmw(u32 base)
+{
+	u32 value = __raw_readl(base + KS2_DDR3_MIDR_OFFSET);
+
+	/* Check the DDR3 controller ID reg if the controllers
+	   supports ECC RMW or not */
+	if (value == 0x40461C02)
+		return 1;
+
+	return 0;
+}
+
+static void ddr3_ecc_config(u32 base, u32 value)
+{
+	u32 data;
+
+	__raw_writel(value,  base + KS2_DDR3_ECC_CTRL_OFFSET);
+	udelay(100000); /* delay required to synchronize across clock domains */
+
+	if (value & KS2_DDR3_ECC_EN) {
+		/* Clear the 1-bit error count */
+		data = __raw_readl(base + KS2_DDR3_ONE_BIT_ECC_ERR_CNT_OFFSET);
+		__raw_writel(data, base + KS2_DDR3_ONE_BIT_ECC_ERR_CNT_OFFSET);
+
+		/* enable the ECC interrupt */
+		__raw_writel(KS2_DDR3_1B_ECC_ERR_SYS | KS2_DDR3_2B_ECC_ERR_SYS |
+			     KS2_DDR3_WR_ECC_ERR_SYS,
+			     base + KS2_DDR3_ECC_INT_ENABLE_SET_SYS_OFFSET);
+
+		/* Clear the ECC error interrupt status */
+		__raw_writel(KS2_DDR3_1B_ECC_ERR_SYS | KS2_DDR3_2B_ECC_ERR_SYS |
+			     KS2_DDR3_WR_ECC_ERR_SYS,
+			     base + KS2_DDR3_ECC_INT_STATUS_OFFSET);
+	}
+}
+
+static void ddr3_reset_data(u32 base, u32 ddr3_size)
+{
+	u32 mpax[2];
+	u32 seg_num;
+	u32 seg, blks, dst, edma_blks;
+	struct edma3_slot_config slot;
+	struct edma3_channel_config edma_channel;
+	u32 edma_src[DDR3_EDMA_BLK_SIZE/4] __aligned(16) = {0, };
+
+	/* Setup an edma to copy the 1k block to the entire DDR */
+	puts("\nClear entire DDR3 memory to enable ECC\n");
+
+	/* save the SES MPAX regs */
+	msmc_get_ses_mpax(8, 0, mpax);
+
+	/* setup edma slot 1 configuration */
+	slot.opt = EDMA3_SLOPT_TRANS_COMP_INT_ENB |
+		   EDMA3_SLOPT_COMP_CODE(0) |
+		   EDMA3_SLOPT_STATIC | EDMA3_SLOPT_AB_SYNC;
+	slot.bcnt = DDR3_EDMA_BCNT;
+	slot.acnt = DDR3_EDMA_BLK_SIZE;
+	slot.ccnt = DDR3_EDMA_CCNT;
+	slot.src_bidx = 0;
+	slot.dst_bidx = DDR3_EDMA_BLK_SIZE;
+	slot.src_cidx = 0;
+	slot.dst_cidx = 0;
+	slot.link = EDMA3_PARSET_NULL_LINK;
+	slot.bcntrld = 0;
+	edma3_slot_configure(KS2_EDMA0_BASE, DDR3_EDMA_SLOT_NUM, &slot);
+
+	/* configure quik edma channel */
+	edma_channel.slot = DDR3_EDMA_SLOT_NUM;
+	edma_channel.chnum = 0;
+	edma_channel.complete_code = 0;
+	/* event trigger after dst update */
+	edma_channel.trigger_slot_word = EDMA3_TWORD(dst);
+	qedma3_start(KS2_EDMA0_BASE, &edma_channel);
+
+	/* DDR3 size in segments (4KB seg size) */
+	seg_num = ddr3_size << (30 - KS2_MSMC_SEG_SIZE_SHIFT);
+
+	for (seg = 0; seg < seg_num; seg += KS2_MSMC_MAP_SEG_NUM) {
+		/* map 2GB 36-bit DDR address to 32-bit DDR address in EMIF
+		   access slave interface so that edma driver can access */
+		msmc_map_ses_segment(8, 0, base >> KS2_MSMC_SEG_SIZE_SHIFT,
+				     KS2_MSMC_DST_SEG_BASE + seg, MPAX_SEG_2G);
+
+		if ((seg_num - seg) > KS2_MSMC_MAP_SEG_NUM)
+			edma_blks = KS2_MSMC_MAP_SEG_NUM <<
+					(KS2_MSMC_SEG_SIZE_SHIFT
+					- DDR3_EDMA_BLK_SIZE_SHIFT);
+		else
+			edma_blks = (seg_num - seg) << (KS2_MSMC_SEG_SIZE_SHIFT
+					- DDR3_EDMA_BLK_SIZE_SHIFT);
+
+		/* Use edma driver to scrub 2GB DDR memory */
+		for (dst = base, blks = 0; blks < edma_blks;
+		     blks += DDR3_EDMA_BCNT, dst += DDR3_EDMA_XF_SIZE) {
+			edma3_set_src_addr(KS2_EDMA0_BASE,
+					   edma_channel.slot, (u32)edma_src);
+			edma3_set_dest_addr(KS2_EDMA0_BASE,
+					    edma_channel.slot, (u32)dst);
+
+			while (edma3_check_for_transfer(KS2_EDMA0_BASE,
+							&edma_channel))
+				udelay(10);
+		}
+	}
+
+	qedma3_stop(KS2_EDMA0_BASE, &edma_channel);
+
+	/* restore the SES MPAX regs */
+	msmc_set_ses_mpax(8, 0, mpax);
+}
+
+static void ddr3_ecc_init_range(u32 base)
+{
+	u32 ecc_val = KS2_DDR3_ECC_EN;
+	u32 rmw = ddr3_ecc_support_rmw(base);
+
+	if (rmw)
+		ecc_val |= KS2_DDR3_ECC_RMW_EN;
+
+	__raw_writel(0, base + KS2_DDR3_ECC_ADDR_RANGE1_OFFSET);
+
+	ddr3_ecc_config(base, ecc_val);
+}
+
+void ddr3_enable_ecc(u32 base, int test)
+{
+	u32 ecc_val = KS2_DDR3_ECC_ENABLE;
+	u32 rmw = ddr3_ecc_support_rmw(base);
+
+	if (test)
+		ecc_val |= KS2_DDR3_ECC_ADDR_RNG_1_EN;
+
+	if (!rmw) {
+		if (!test)
+			/* by default, disable ecc when rmw = 0 and no
+			   ecc test */
+			ecc_val = 0;
+	} else {
+		ecc_val |= KS2_DDR3_ECC_RMW_EN;
+	}
+
+	ddr3_ecc_config(base, ecc_val);
+}
+
+void ddr3_disable_ecc(u32 base)
+{
+	ddr3_ecc_config(base, 0);
+}
+
+#if defined(CONFIG_SOC_K2HK) || defined(CONFIG_SOC_K2L)
+static void cic_init(u32 base)
+{
+	/* Disable CIC global interrupts */
+	__raw_writel(0, base + KS2_CIC_GLOBAL_ENABLE);
+
+	/* Set to normal mode, no nesting, no priority hold */
+	__raw_writel(0, base + KS2_CIC_CTRL);
+	__raw_writel(0, base + KS2_CIC_HOST_CTRL);
+
+	/* Enable CIC global interrupts */
+	__raw_writel(1, base + KS2_CIC_GLOBAL_ENABLE);
+}
+
+static void cic_map_cic_to_gic(u32 base, u32 chan_num, u32 irq_num)
+{
+	/* Map the system interrupt to a CIC channel */
+	__raw_writeb(chan_num, base + KS2_CIC_CHAN_MAP(0) + irq_num);
+
+	/* Enable CIC system interrupt */
+	__raw_writel(irq_num, base + KS2_CIC_SYS_ENABLE_IDX_SET);
+
+	/* Enable CIC Host interrupt */
+	__raw_writel(chan_num, base + KS2_CIC_HOST_ENABLE_IDX_SET);
+}
+
+static void ddr3_map_ecc_cic2_irq(u32 base)
+{
+	cic_init(base);
+	cic_map_cic_to_gic(base, KS2_CIC2_DDR3_ECC_CHAN_NUM,
+			   KS2_CIC2_DDR3_ECC_IRQ_NUM);
+}
+#endif
+
+void ddr3_init_ecc(u32 base)
+{
+	u32 ddr3_size;
+
+	if (!ddr3_ecc_support_rmw(base)) {
+		ddr3_disable_ecc(base);
+		return;
+	}
+
+	ddr3_ecc_init_range(base);
+	ddr3_size = ddr3_get_size();
+	ddr3_reset_data(CONFIG_SYS_SDRAM_BASE, ddr3_size);
+
+	/* mapping DDR3 ECC system interrupt from CIC2 to GIC */
+#if defined(CONFIG_SOC_K2HK) || defined(CONFIG_SOC_K2L)
+	ddr3_map_ecc_cic2_irq(KS2_CIC2_BASE);
+#endif
+	ddr3_enable_ecc(base, 0);
+}
+
+void ddr3_check_ecc_int(u32 base)
+{
+	char *env;
+	int ecc_test = 0;
+	u32 value = __raw_readl(base + KS2_DDR3_ECC_INT_STATUS_OFFSET);
+
+	env = getenv("ecc_test");
+	if (env)
+		ecc_test = simple_strtol(env, NULL, 0);
+
+	if (value & KS2_DDR3_WR_ECC_ERR_SYS)
+		puts("DDR3 ECC write error interrupted\n");
+
+	if (value & KS2_DDR3_2B_ECC_ERR_SYS) {
+		puts("DDR3 ECC 2-bit error interrupted\n");
+
+		if (!ecc_test) {
+			puts("Reseting the device ...\n");
+			reset_cpu(0);
+		}
+	}
+
+	value = __raw_readl(base + KS2_DDR3_ONE_BIT_ECC_ERR_CNT_OFFSET);
+	if (value) {
+		printf("1-bit ECC err count: 0x%x\n", value);
+		value = __raw_readl(base +
+				    KS2_DDR3_ONE_BIT_ECC_ERR_ADDR_LOG_OFFSET);
+		printf("1-bit ECC err address log: 0x%x\n", value);
+	}
+}
+
 void ddr3_reset_ddrphy(void)
 {
 	u32 tmp;
diff --git a/arch/arm/include/asm/arch-keystone/ddr3.h b/arch/arm/include/asm/arch-keystone/ddr3.h
index 6bf35d3..b044d6f 100644
--- a/arch/arm/include/asm/arch-keystone/ddr3.h
+++ b/arch/arm/include/asm/arch-keystone/ddr3.h
@@ -49,8 +49,14 @@ struct ddr3_emif_config {
 };
 
 void ddr3_init(void);
+int ddr3_get_size(void);
 void ddr3_reset_ddrphy(void);
+void ddr3_init_ecc(u32 base);
+void ddr3_disable_ecc(u32 base);
+void ddr3_check_ecc_int(u32 base);
+int ddr3_ecc_support_rmw(u32 base);
 void ddr3_err_reset_workaround(void);
+void ddr3_enable_ecc(u32 base, int test);
 void ddr3_init_ddrphy(u32 base, struct ddr3_phy_config *phy_cfg);
 void ddr3_init_ddremif(u32 base, struct ddr3_emif_config *emif_cfg);
 
diff --git a/arch/arm/include/asm/arch-keystone/hardware-k2hk.h b/arch/arm/include/asm/arch-keystone/hardware-k2hk.h
index 28de3f5..5a9ea4f 100644
--- a/arch/arm/include/asm/arch-keystone/hardware-k2hk.h
+++ b/arch/arm/include/asm/arch-keystone/hardware-k2hk.h
@@ -79,6 +79,10 @@
 #define KS2_DDR3B_EMIF_DATA_BASE	0x60000000
 #define KS2_DDR3B_DDRPHYC		0x02328000
 
+#define KS2_CIC2_DDR3_ECC_IRQ_NUM	0x0D3 /* DDR3 ECC system irq number */
+#define KS2_CIC2_DDR3_ECC_CHAN_NUM	0x01D /* DDR3 ECC int mapped to CIC2
+						 channel 29 */
+
 /* SGMII SerDes */
 #define KS2_LANES_PER_SGMII_SERDES	4
 
diff --git a/arch/arm/include/asm/arch-keystone/hardware.h b/arch/arm/include/asm/arch-keystone/hardware.h
index d2bd6cb..3e54998 100644
--- a/arch/arm/include/asm/arch-keystone/hardware.h
+++ b/arch/arm/include/asm/arch-keystone/hardware.h
@@ -87,6 +87,52 @@ typedef volatile unsigned int   *dv_reg_p;
 
 #define KS2_DDR3_PLLCTRL_PHY_RESET	0x80000000
 
+/* DDR3 ECC */
+#define KS2_DDR3_ECC_INT_STATUS_OFFSET			0x0AC
+#define KS2_DDR3_ECC_INT_ENABLE_SET_SYS_OFFSET		0x0B4
+#define KS2_DDR3_ECC_CTRL_OFFSET			0x110
+#define KS2_DDR3_ECC_ADDR_RANGE1_OFFSET			0x114
+#define KS2_DDR3_ONE_BIT_ECC_ERR_CNT_OFFSET		0x130
+#define KS2_DDR3_ONE_BIT_ECC_ERR_ADDR_LOG_OFFSET	0x13C
+
+/* DDR3 ECC Interrupt Status register */
+#define KS2_DDR3_1B_ECC_ERR_SYS		BIT(5)
+#define KS2_DDR3_2B_ECC_ERR_SYS		BIT(4)
+#define KS2_DDR3_WR_ECC_ERR_SYS		BIT(3)
+
+/* DDR3 ECC Control register */
+#define KS2_DDR3_ECC_EN			BIT(31)
+#define KS2_DDR3_ECC_ADDR_RNG_PROT	BIT(30)
+#define KS2_DDR3_ECC_VERIFY_EN		BIT(29)
+#define KS2_DDR3_ECC_RMW_EN		BIT(28)
+#define KS2_DDR3_ECC_ADDR_RNG_1_EN	BIT(0)
+
+#define KS2_DDR3_ECC_ENABLE		(KS2_DDR3_ECC_EN | \
+					KS2_DDR3_ECC_ADDR_RNG_PROT | \
+					KS2_DDR3_ECC_VERIFY_EN)
+
+/* EDMA */
+#define KS2_EDMA0_BASE			0x02700000
+
+/* EDMA3 register offsets */
+#define KS2_EDMA_QCHMAP0		0x0200
+#define KS2_EDMA_IPR			0x1068
+#define KS2_EDMA_ICR			0x1070
+#define KS2_EDMA_QEECR			0x1088
+#define KS2_EDMA_QEESR			0x108c
+#define KS2_EDMA_PARAM_1(x)		(0x4020 + (4 * x))
+
+/* Chip Interrupt Controller */
+#define KS2_CIC2_BASE			0x02608000
+
+/* Chip Interrupt Controller register offsets */
+#define KS2_CIC_CTRL			0x04
+#define KS2_CIC_HOST_CTRL		0x0C
+#define KS2_CIC_GLOBAL_ENABLE		0x10
+#define KS2_CIC_SYS_ENABLE_IDX_SET	0x28
+#define KS2_CIC_HOST_ENABLE_IDX_SET	0x34
+#define KS2_CIC_CHAN_MAP(n)		(0x0400 + (n << 2))
+
 #define KS2_UART0_BASE                	0x02530c00
 #define KS2_UART1_BASE                	0x02531000
 
diff --git a/board/ti/ks2_evm/board.c b/board/ti/ks2_evm/board.c
index cdfca23..ffb0c7e 100644
--- a/board/ti/ks2_evm/board.c
+++ b/board/ti/ks2_evm/board.c
@@ -39,6 +39,7 @@ int dram_init(void)
 	gd->ram_size = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE,
 				    CONFIG_MAX_RAM_BANK_SIZE);
 	aemif_init(ARRAY_SIZE(aemif_configs), aemif_configs);
+	ddr3_init_ecc(KS2_DDR3A_EMIF_CTRL_BASE);
 	return 0;
 }
 
@@ -234,5 +235,7 @@ void ft_board_setup_ex(void *blob, bd_t *bd)
 			reserve_start += 2;
 		}
 	}
+
+	ddr3_check_ecc_int(KS2_DDR3A_EMIF_CTRL_BASE);
 }
 #endif
diff --git a/board/ti/ks2_evm/ddr3_k2hk.c b/board/ti/ks2_evm/ddr3_k2hk.c
index 6070a99..a1c3d05 100644
--- a/board/ti/ks2_evm/ddr3_k2hk.c
+++ b/board/ti/ks2_evm/ddr3_k2hk.c
@@ -12,6 +12,8 @@
 #include <asm/arch/ddr3.h>
 #include <asm/arch/hardware.h>
 
+static int ddr3_size;
+
 struct pll_init_data ddr3a_333 = DDR3_PLL_333(A);
 struct pll_init_data ddr3a_400 = DDR3_PLL_400(A);
 
@@ -44,12 +46,14 @@ void ddr3_init(void)
 			ddr3_init_ddremif(KS2_DDR3A_EMIF_CTRL_BASE,
 					  &ddr3_1600_8g);
 			printf("DRAM:  Capacity 8 GiB (includes reported below)\n");
+			ddr3_size = 8;
 		} else {
 			ddr3_init_ddrphy(KS2_DDR3A_DDRPHYC, &ddr3phy_1600_8g);
 			ddr3_1600_8g.sdcfg |= 0x1000;
 			ddr3_init_ddremif(KS2_DDR3A_EMIF_CTRL_BASE,
 					  &ddr3_1600_8g);
 			printf("DRAM:  Capacity 4 GiB (includes reported below)\n");
+			ddr3_size = 4;
 		}
 	} else if (!strcmp(dimm_name, "SQR-SD3T-2G1333SED")) {
 		init_pll(&ddr3a_333);
@@ -70,11 +74,15 @@ void ddr3_init(void)
 			}
 			ddr3_init_ddremif(KS2_DDR3A_EMIF_CTRL_BASE,
 					  &ddr3_1333_2g);
+			ddr3_size = 2;
+			printf("DRAM:  2 GiB");
 		} else {
 			ddr3_init_ddrphy(KS2_DDR3A_DDRPHYC, &ddr3phy_1333_2g);
 			ddr3_1333_2g.sdcfg |= 0x1000;
 			ddr3_init_ddremif(KS2_DDR3A_EMIF_CTRL_BASE,
 					  &ddr3_1333_2g);
+			ddr3_size = 1;
+			printf("DRAM:  1 GiB");
 		}
 	} else {
 		printf("Unknown SO-DIMM. Cannot configure DDR3\n");
@@ -86,3 +94,11 @@ void ddr3_init(void)
 	if (cpu_revision() <= 1)
 		ddr3_err_reset_workaround();
 }
+
+/**
+ * ddr3_get_size - return ddr3 size in GiB
+ */
+int ddr3_get_size(void)
+{
+	return ddr3_size;
+}
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [U-Boot] [U-boot] [Patch 4/4] ARM: keystone: cmd_ddr3: add ddr3 commands to test ddr
  2014-10-10 15:17 [U-Boot] [U-boot] [Patch 0/4] keystone2: ecc: add ddr3 error detection and correction support Ivan Khoronzhuk
                   ` (2 preceding siblings ...)
  2014-10-10 15:17 ` [U-Boot] [U-boot] [Patch 3/4] keystone2: ecc: add ddr3 error detection and correction support Ivan Khoronzhuk
@ 2014-10-10 15:17 ` Ivan Khoronzhuk
  3 siblings, 0 replies; 5+ messages in thread
From: Ivan Khoronzhuk @ 2014-10-10 15:17 UTC (permalink / raw)
  To: u-boot

From: Hao Zhang <hzhang@ti.com>

Add ddr3 commands:

test <start_addr in hex> <end_addr in hex> - test DDR from start\n
	address to end address\n
ddr compare <start_addr in hex> <end_addr in hex> <size in hex> -\n
	compare DDR data of (size) bytes from start address to end
	address\n
ddr ecc_err <addr in hex> <bit_err in hex> - generate bit errors\n
	in DDR data at <addr>, the command will read a 32-bit data\n
	from <addr>, and write (data ^ bit_err) back to <addr>\n

Delete CONFIG_MAX_UBOOT_MEM_SIZE, as it was supposed to be used
for ddr3 commands and for now it's not needed any more.

Signed-off-by: Hao Zhang <hzhang@ti.com>
Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
---
 arch/arm/cpu/armv7/keystone/Makefile   |   2 +-
 arch/arm/cpu/armv7/keystone/cmd_ddr3.c | 247 +++++++++++++++++++++++++++++++++
 include/configs/ks2_evm.h              |   4 -
 3 files changed, 248 insertions(+), 5 deletions(-)
 create mode 100644 arch/arm/cpu/armv7/keystone/cmd_ddr3.c

diff --git a/arch/arm/cpu/armv7/keystone/Makefile b/arch/arm/cpu/armv7/keystone/Makefile
index 4750371..b61219a 100644
--- a/arch/arm/cpu/armv7/keystone/Makefile
+++ b/arch/arm/cpu/armv7/keystone/Makefile
@@ -15,5 +15,5 @@ obj-y	+= cmd_clock.o
 obj-y	+= cmd_mon.o
 obj-y	+= msmc.o
 obj-$(CONFIG_SPL_BUILD)	+= spl.o
-obj-y	+= ddr3.o
+obj-y	+= ddr3.o cmd_ddr3.o
 obj-y	+= keystone.o
diff --git a/arch/arm/cpu/armv7/keystone/cmd_ddr3.c b/arch/arm/cpu/armv7/keystone/cmd_ddr3.c
new file mode 100644
index 0000000..e85027b
--- /dev/null
+++ b/arch/arm/cpu/armv7/keystone/cmd_ddr3.c
@@ -0,0 +1,247 @@
+/*
+ * Keystone2: DDR3 test commands
+ *
+ * (C) Copyright 2012-2014
+ *     Texas Instruments Incorporated, <www.ti.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/ddr3.h>
+#include <common.h>
+#include <command.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define DDR_MIN_ADDR		CONFIG_SYS_SDRAM_BASE
+
+#define DDR_REMAP_ADDR		0x80000000
+#define ECC_START_ADDR1		((DDR_MIN_ADDR - DDR_REMAP_ADDR) >> 17)
+
+#define ECC_END_ADDR1		(((gd->start_addr_sp - DDR_REMAP_ADDR - \
+				 CONFIG_STACKSIZE) >> 17) - 2)
+
+#define DDR_TEST_BURST_SIZE	1024
+
+static int ddr_memory_test(u32 start_address, u32 end_address, int quick)
+{
+	u32 index_start, value, index;
+
+	index_start = start_address;
+
+	while (1) {
+		/* Write a pattern */
+		for (index = index_start;
+				index < index_start + DDR_TEST_BURST_SIZE;
+				index += 4)
+			__raw_writel(index, index);
+
+		/* Read and check the pattern */
+		for (index = index_start;
+				index < index_start + DDR_TEST_BURST_SIZE;
+				index += 4) {
+			value = __raw_readl(index);
+			if (value != index) {
+				printf("ddr_memory_test: Failed@address index = 0x%x value = 0x%x *(index) = 0x%x\n",
+				       index, value, __raw_readl(index));
+
+				return -1;
+			}
+		}
+
+		index_start += DDR_TEST_BURST_SIZE;
+		if (index_start >= end_address)
+			break;
+
+		if (quick)
+			continue;
+
+		/* Write a pattern for complementary values */
+		for (index = index_start;
+		     index < index_start + DDR_TEST_BURST_SIZE;
+		     index += 4)
+			__raw_writel((u32)~index, index);
+
+		/* Read and check the pattern */
+		for (index = index_start;
+		     index < index_start + DDR_TEST_BURST_SIZE;
+		     index += 4) {
+			value = __raw_readl(index);
+			if (value != ~index) {
+				printf("ddr_memory_test: Failed@address index = 0x%x value = 0x%x *(index) = 0x%x\n",
+				       index, value, __raw_readl(index));
+
+				return -1;
+			}
+		}
+
+		index_start += DDR_TEST_BURST_SIZE;
+		if (index_start >= end_address)
+			break;
+
+		/* Write a pattern */
+		for (index = index_start;
+		     index < index_start + DDR_TEST_BURST_SIZE;
+		     index += 2)
+			__raw_writew((u16)index, index);
+
+		/* Read and check the pattern */
+		for (index = index_start;
+		     index < index_start + DDR_TEST_BURST_SIZE;
+		     index += 2) {
+			value = __raw_readw(index);
+			if (value != (u16)index) {
+				printf("ddr_memory_test: Failed@address index = 0x%x value = 0x%x *(index) = 0x%x\n",
+				       index, value, __raw_readw(index));
+
+				return -1;
+			}
+		}
+
+		index_start += DDR_TEST_BURST_SIZE;
+		if (index_start >= end_address)
+			break;
+
+		/* Write a pattern */
+		for (index = index_start;
+		     index < index_start + DDR_TEST_BURST_SIZE;
+		     index += 1)
+			__raw_writeb((u8)index, index);
+
+		/* Read and check the pattern */
+		for (index = index_start;
+		     index < index_start + DDR_TEST_BURST_SIZE;
+		     index += 1) {
+			value = __raw_readb(index);
+			if (value != (u8)index) {
+				printf("ddr_memory_test: Failed@address index = 0x%x value = 0x%x *(index) = 0x%x\n",
+				       index, value, __raw_readb(index));
+
+				return -1;
+			}
+		}
+
+		index_start += DDR_TEST_BURST_SIZE;
+		if (index_start >= end_address)
+			break;
+	}
+
+	puts("ddr memory test PASSED!\n");
+	return 0;
+}
+
+static int ddr_memory_compare(u32 address1, u32 address2, u32 size)
+{
+	u32 index, value, index2, value2;
+
+	for (index = address1, index2 = address2;
+	     index < address1 + size;
+	     index += 4, index2 += 4) {
+		value = __raw_readl(index);
+		value2 = __raw_readl(index2);
+
+		if (value != value2) {
+			printf("ddr_memory_test: Compare failed@address = 0x%x value = 0x%x, address2 = 0x%x value2 = 0x%x\n",
+			       index, value, index2, value2);
+
+			return -1;
+		}
+	}
+
+	puts("ddr memory compare PASSED!\n");
+	return 0;
+}
+
+static int ddr_memory_ecc_err(u32 base, u32 address, u32 ecc_err)
+{
+	u32 value1, value2, value3;
+
+	puts("Disabling DDR ECC ...\n");
+	ddr3_disable_ecc(base);
+
+	value1 = __raw_readl(address);
+	value2 = value1 ^ ecc_err;
+	__raw_writel(value2, address);
+
+	value3 = __raw_readl(address);
+	printf("ECC err test, addr 0x%x, read data 0x%x, wrote data 0x%x, err pattern: 0x%x, read after write data 0x%x\n",
+	       address, value1, value2, ecc_err, value3);
+
+	__raw_writel(ECC_START_ADDR1 | (ECC_END_ADDR1 << 16),
+		     base + KS2_DDR3_ECC_ADDR_RANGE1_OFFSET);
+
+	puts("Enabling DDR ECC ...\n");
+	ddr3_enable_ecc(base, 1);
+
+	value1 = __raw_readl(address);
+	printf("ECC err test, addr 0x%x, read data 0x%x\n", address, value1);
+
+	ddr3_check_ecc_int(base);
+	return 0;
+}
+
+static int do_ddr_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	u32 start_addr, end_addr, size, ecc_err;
+
+	if ((argc == 4) && (strncmp(argv[1], "ecc_err", 8) == 0)) {
+		if (!ddr3_ecc_support_rmw(KS2_DDR3A_EMIF_CTRL_BASE)) {
+			puts("ECC RMW isn't supported for this SOC\n");
+			return 1;
+		}
+
+		start_addr = simple_strtoul(argv[2], NULL, 16);
+		ecc_err = simple_strtoul(argv[3], NULL, 16);
+
+		if ((start_addr < CONFIG_SYS_SDRAM_BASE) ||
+		    (start_addr > (CONFIG_SYS_SDRAM_BASE +
+		     CONFIG_MAX_RAM_BANK_SIZE - 1))) {
+			puts("Invalid address!\n");
+			return cmd_usage(cmdtp);
+		}
+
+		ddr_memory_ecc_err(KS2_DDR3A_EMIF_CTRL_BASE,
+				   start_addr, ecc_err);
+		return 0;
+	}
+
+	if (!(((argc == 4) && (strncmp(argv[1], "test", 5) == 0)) ||
+	      ((argc == 5) && (strncmp(argv[1], "compare", 8) == 0))))
+		return cmd_usage(cmdtp);
+
+	start_addr = simple_strtoul(argv[2], NULL, 16);
+	end_addr = simple_strtoul(argv[3], NULL, 16);
+
+	if ((start_addr < CONFIG_SYS_SDRAM_BASE) ||
+	    (start_addr > (CONFIG_SYS_SDRAM_BASE +
+	     CONFIG_MAX_RAM_BANK_SIZE - 1)) ||
+	    (end_addr < CONFIG_SYS_SDRAM_BASE) ||
+	    (end_addr > (CONFIG_SYS_SDRAM_BASE +
+	     CONFIG_MAX_RAM_BANK_SIZE - 1)) || (start_addr >= end_addr)) {
+		puts("Invalid start or end address!\n");
+		return cmd_usage(cmdtp);
+	}
+
+	puts("Please wait ...\n");
+	if (argc == 5) {
+		size = simple_strtoul(argv[4], NULL, 16);
+		ddr_memory_compare(start_addr, end_addr, size);
+	} else {
+		ddr_memory_test(start_addr, end_addr, 0);
+	}
+
+	return 0;
+}
+
+U_BOOT_CMD(ddr,	5, 1, do_ddr_test,
+	   "DDR3 test",
+	   "test <start_addr in hex> <end_addr in hex> - test DDR from start\n"
+	   "	address to end address\n"
+	   "ddr compare <start_addr in hex> <end_addr in hex> <size in hex> -\n"
+	   "	compare DDR data of (size) bytes from start address to end"
+	   "	address\n"
+	   "ddr ecc_err <addr in hex> <bit_err in hex> - generate bit errors\n"
+	   "	in DDR data at <addr>, the command will read a 32-bit data\n"
+	   "	from <addr>, and write (data ^ bit_err) back to <addr>\n"
+);
diff --git a/include/configs/ks2_evm.h b/include/configs/ks2_evm.h
index a92ab04..d13efe3 100644
--- a/include/configs/ks2_evm.h
+++ b/include/configs/ks2_evm.h
@@ -321,8 +321,4 @@
 #include <asm/arch/clock.h>
 #define CONFIG_SYS_HZ_CLOCK		clk_get_rate(KS2_CLK1_6)
 
-/* Maximum memory size for relocated U-boot at the end of the DDR3 memory
-   which is NOT applicable for DDR ECC test */
-#define CONFIG_MAX_UBOOT_MEM_SIZE	(4 << 20)	/* 4 MiB */
-
 #endif /* __CONFIG_KS2_EVM_H */
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2014-10-10 15:17 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-10-10 15:17 [U-Boot] [U-boot] [Patch 0/4] keystone2: ecc: add ddr3 error detection and correction support Ivan Khoronzhuk
2014-10-10 15:17 ` [U-Boot] [U-boot] [Patch 1/4] dma: ti-edma3: introduce edma3 driver Ivan Khoronzhuk
2014-10-10 15:17 ` [U-Boot] [U-boot] [Patch 2/4] ARM: keystone: msmc: extend functionality of SES Ivan Khoronzhuk
2014-10-10 15:17 ` [U-Boot] [U-boot] [Patch 3/4] keystone2: ecc: add ddr3 error detection and correction support Ivan Khoronzhuk
2014-10-10 15:17 ` [U-Boot] [U-boot] [Patch 4/4] ARM: keystone: cmd_ddr3: add ddr3 commands to test ddr Ivan Khoronzhuk

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.