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