1// SPDX-License-Identifier: MIT
2/*
3 *  Copyright(c) 2015 - 2020 Xilinx, Inc.
4 *
5 *  Jorge Ramirez-Ortiz <jorge@foundries.io>
6 */
7
8#include <common.h>
9#include <cpu_func.h>
10#include <asm/arch/hardware.h>
11#include <asm/arch/ecc_spl_init.h>
12#include <asm/io.h>
13#include <linux/delay.h>
14
15#define ZDMA_TRANSFER_MAX_LEN		(0x3FFFFFFFU - 7U)
16#define ZDMA_CH_STATUS			((ADMA_CH0_BASEADDR) + 0x0000011CU)
17#define ZDMA_CH_STATUS_STATE_MASK	0x00000003U
18#define ZDMA_CH_STATUS_STATE_DONE	0x00000000U
19#define ZDMA_CH_STATUS_STATE_ERR	0x00000003U
20#define ZDMA_CH_CTRL0			((ADMA_CH0_BASEADDR) + 0x00000110U)
21#define ZDMA_CH_CTRL0_POINT_TYPE_MASK	(u32)0x00000040U
22#define ZDMA_CH_CTRL0_POINT_TYPE_NORMAL	(u32)0x00000000U
23#define ZDMA_CH_CTRL0_MODE_MASK		(u32)0x00000030U
24#define ZDMA_CH_CTRL0_MODE_WR_ONLY	(u32)0x00000010U
25#define ZDMA_CH_CTRL0_TOTAL_BYTE_COUNT	((ADMA_CH0_BASEADDR) + 0x00000188U)
26#define ZDMA_CH_WR_ONLY_WORD0		((ADMA_CH0_BASEADDR) + 0x00000148U)
27#define ZDMA_CH_WR_ONLY_WORD1		((ADMA_CH0_BASEADDR) + 0x0000014CU)
28#define ZDMA_CH_WR_ONLY_WORD2		((ADMA_CH0_BASEADDR) + 0x00000150U)
29#define ZDMA_CH_WR_ONLY_WORD3		((ADMA_CH0_BASEADDR) + 0x00000154U)
30#define ZDMA_CH_DST_DSCR_WORD0		((ADMA_CH0_BASEADDR) + 0x00000138U)
31#define ZDMA_CH_DST_DSCR_WORD0_LSB_MASK	0xFFFFFFFFU
32#define ZDMA_CH_DST_DSCR_WORD1		((ADMA_CH0_BASEADDR) + 0x0000013CU)
33#define ZDMA_CH_DST_DSCR_WORD1_MSB_MASK	0x0001FFFFU
34#define ZDMA_CH_SRC_DSCR_WORD2		((ADMA_CH0_BASEADDR) + 0x00000130U)
35#define ZDMA_CH_DST_DSCR_WORD2		((ADMA_CH0_BASEADDR) + 0x00000140U)
36#define ZDMA_CH_CTRL2			((ADMA_CH0_BASEADDR) + 0x00000200U)
37#define ZDMA_CH_CTRL2_EN_MASK		0x00000001U
38#define ZDMA_CH_ISR			((ADMA_CH0_BASEADDR) + 0x00000100U)
39#define ZDMA_CH_ISR_DMA_DONE_MASK	0x00000400U
40#define ECC_INIT_VAL_WORD		0xDEADBEEFU
41
42#define ZDMA_IDLE_TIMEOUT_USEC		1000000
43#define ZDMA_DONE_TIMEOUT_USEC		5000000
44
45static void ecc_zdma_restore(void)
46{
47	/* Restore reset values for the DMA registers used */
48	writel(ZDMA_CH_CTRL0, 0x00000080U);
49	writel(ZDMA_CH_WR_ONLY_WORD0, 0x00000000U);
50	writel(ZDMA_CH_WR_ONLY_WORD1, 0x00000000U);
51	writel(ZDMA_CH_WR_ONLY_WORD2, 0x00000000U);
52	writel(ZDMA_CH_WR_ONLY_WORD3, 0x00000000U);
53	writel(ZDMA_CH_DST_DSCR_WORD0, 0x00000000U);
54	writel(ZDMA_CH_DST_DSCR_WORD1, 0x00000000U);
55	writel(ZDMA_CH_SRC_DSCR_WORD2, 0x00000000U);
56	writel(ZDMA_CH_DST_DSCR_WORD2, 0x00000000U);
57	writel(ZDMA_CH_CTRL0_TOTAL_BYTE_COUNT, 0x00000000U);
58}
59
60static void ecc_dram_bank_init(u64 addr, u64 len)
61{
62	bool retry = true;
63	u32 timeout;
64	u64 bytes;
65	u32 size;
66	u64 src;
67	u32 reg;
68
69	if (!len)
70		return;
71retry:
72	bytes = len;
73	src = addr;
74	ecc_zdma_restore();
75	while (bytes > 0) {
76		size = bytes > ZDMA_TRANSFER_MAX_LEN ?
77			ZDMA_TRANSFER_MAX_LEN : (u32)bytes;
78
79		/* Wait until the DMA is in idle state */
80		timeout = ZDMA_IDLE_TIMEOUT_USEC;
81		do {
82			udelay(1);
83			reg = readl(ZDMA_CH_STATUS);
84			reg &= ZDMA_CH_STATUS_STATE_MASK;
85			if (!timeout--) {
86				puts("error, ECC DMA failed to idle\n");
87				goto done;
88			}
89
90		} while ((reg != ZDMA_CH_STATUS_STATE_DONE) &&
91			(reg != ZDMA_CH_STATUS_STATE_ERR));
92
93		/* Enable Simple (Write Only) Mode */
94		reg = readl(ZDMA_CH_CTRL0);
95		reg &= (ZDMA_CH_CTRL0_POINT_TYPE_MASK |
96			ZDMA_CH_CTRL0_MODE_MASK);
97		reg |= (ZDMA_CH_CTRL0_POINT_TYPE_NORMAL |
98			ZDMA_CH_CTRL0_MODE_WR_ONLY);
99		writel(reg, ZDMA_CH_CTRL0);
100
101		/* Fill in the data to be written */
102		writel(ECC_INIT_VAL_WORD, ZDMA_CH_WR_ONLY_WORD0);
103		writel(ECC_INIT_VAL_WORD, ZDMA_CH_WR_ONLY_WORD1);
104		writel(ECC_INIT_VAL_WORD, ZDMA_CH_WR_ONLY_WORD2);
105		writel(ECC_INIT_VAL_WORD, ZDMA_CH_WR_ONLY_WORD3);
106
107		/* Write Destination Address */
108		writel((u32)(src & ZDMA_CH_DST_DSCR_WORD0_LSB_MASK),
109		       ZDMA_CH_DST_DSCR_WORD0);
110		writel((u32)((src >> 32) & ZDMA_CH_DST_DSCR_WORD1_MSB_MASK),
111		       ZDMA_CH_DST_DSCR_WORD1);
112
113		/* Size to be Transferred. Recommended to set both src and dest sizes */
114		writel(size, ZDMA_CH_SRC_DSCR_WORD2);
115		writel(size, ZDMA_CH_DST_DSCR_WORD2);
116
117		/* DMA Enable */
118		reg = readl(ZDMA_CH_CTRL2);
119		reg |= ZDMA_CH_CTRL2_EN_MASK;
120		writel(reg, ZDMA_CH_CTRL2);
121
122		/* Check the status of the transfer by polling on DMA Done */
123		timeout = ZDMA_DONE_TIMEOUT_USEC;
124		do {
125			udelay(1);
126			reg = readl(ZDMA_CH_ISR);
127			reg &= ZDMA_CH_ISR_DMA_DONE_MASK;
128			if (!timeout--) {
129				puts("error, ECC DMA timeout\n");
130				goto done;
131			}
132		} while (reg != ZDMA_CH_ISR_DMA_DONE_MASK);
133
134		/* Clear DMA status */
135		reg = readl(ZDMA_CH_ISR);
136		reg |= ZDMA_CH_ISR_DMA_DONE_MASK;
137		writel(ZDMA_CH_ISR_DMA_DONE_MASK, ZDMA_CH_ISR);
138
139		/* Read the channel status for errors */
140		reg = readl(ZDMA_CH_STATUS);
141		if (reg == ZDMA_CH_STATUS_STATE_ERR) {
142			if (retry) {
143				retry = false;
144				goto retry;
145			}
146			puts("error, ECC DMA error\n");
147			break;
148		}
149
150		bytes -= size;
151		src += size;
152	}
153done:
154	ecc_zdma_restore();
155}
156
157void zynqmp_ecc_init(void)
158{
159	ecc_dram_bank_init(CONFIG_SPL_ZYNQMP_DRAM_BANK1_BASE,
160			   CONFIG_SPL_ZYNQMP_DRAM_BANK1_LEN);
161	ecc_dram_bank_init(CONFIG_SPL_ZYNQMP_DRAM_BANK2_BASE,
162			   CONFIG_SPL_ZYNQMP_DRAM_BANK2_LEN);
163}
164