]>
Commit | Line | Data |
---|---|---|
230fe9b2 PM |
1 | /* |
2 | * Copyright (C) 2012 Altera Corporation <www.altera.com> | |
3 | * All rights reserved. | |
4 | * | |
5 | * SPDX-License-Identifier: BSD-3-Clause | |
6 | */ | |
7 | ||
8 | #include <common.h> | |
9 | #include <asm/io.h> | |
10 | #include <asm/errno.h> | |
11 | #include <asm/arch/fpga_manager.h> | |
12 | #include <asm/arch/reset_manager.h> | |
13 | #include <asm/arch/system_manager.h> | |
14 | ||
15 | DECLARE_GLOBAL_DATA_PTR; | |
16 | ||
17 | /* Timeout count */ | |
18 | #define FPGA_TIMEOUT_CNT 0x1000000 | |
19 | ||
20 | static struct socfpga_fpga_manager *fpgamgr_regs = | |
21 | (struct socfpga_fpga_manager *)SOCFPGA_FPGAMGRREGS_ADDRESS; | |
22 | static struct socfpga_system_manager *sysmgr_regs = | |
23 | (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS; | |
24 | ||
25 | /* Set CD ratio */ | |
26 | static void fpgamgr_set_cd_ratio(unsigned long ratio) | |
27 | { | |
28 | clrsetbits_le32(&fpgamgr_regs->ctrl, | |
29 | 0x3 << FPGAMGRREGS_CTRL_CDRATIO_LSB, | |
30 | (ratio & 0x3) << FPGAMGRREGS_CTRL_CDRATIO_LSB); | |
31 | } | |
32 | ||
33 | static int fpgamgr_dclkcnt_set(unsigned long cnt) | |
34 | { | |
35 | unsigned long i; | |
36 | ||
37 | /* Clear any existing done status */ | |
38 | if (readl(&fpgamgr_regs->dclkstat)) | |
39 | writel(0x1, &fpgamgr_regs->dclkstat); | |
40 | ||
41 | /* Write the dclkcnt */ | |
42 | writel(cnt, &fpgamgr_regs->dclkcnt); | |
43 | ||
44 | /* Wait till the dclkcnt done */ | |
45 | for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { | |
46 | if (!readl(&fpgamgr_regs->dclkstat)) | |
47 | continue; | |
48 | ||
49 | writel(0x1, &fpgamgr_regs->dclkstat); | |
50 | return 0; | |
51 | } | |
52 | ||
53 | return -ETIMEDOUT; | |
54 | } | |
55 | ||
56 | /* Start the FPGA programming by initialize the FPGA Manager */ | |
57 | static int fpgamgr_program_init(void) | |
58 | { | |
59 | unsigned long msel, i; | |
60 | ||
61 | /* Get the MSEL value */ | |
62 | msel = readl(&fpgamgr_regs->stat); | |
63 | msel &= FPGAMGRREGS_STAT_MSEL_MASK; | |
64 | msel >>= FPGAMGRREGS_STAT_MSEL_LSB; | |
65 | ||
66 | /* | |
67 | * Set the cfg width | |
68 | * If MSEL[3] = 1, cfg width = 32 bit | |
69 | */ | |
70 | if (msel & 0x8) { | |
71 | setbits_le32(&fpgamgr_regs->ctrl, | |
72 | FPGAMGRREGS_CTRL_CFGWDTH_MASK); | |
73 | ||
74 | /* To determine the CD ratio */ | |
75 | /* MSEL[1:0] = 0, CD Ratio = 1 */ | |
76 | if ((msel & 0x3) == 0x0) | |
77 | fpgamgr_set_cd_ratio(CDRATIO_x1); | |
78 | /* MSEL[1:0] = 1, CD Ratio = 4 */ | |
79 | else if ((msel & 0x3) == 0x1) | |
80 | fpgamgr_set_cd_ratio(CDRATIO_x4); | |
81 | /* MSEL[1:0] = 2, CD Ratio = 8 */ | |
82 | else if ((msel & 0x3) == 0x2) | |
83 | fpgamgr_set_cd_ratio(CDRATIO_x8); | |
84 | ||
85 | } else { /* MSEL[3] = 0 */ | |
86 | clrbits_le32(&fpgamgr_regs->ctrl, | |
87 | FPGAMGRREGS_CTRL_CFGWDTH_MASK); | |
88 | ||
89 | /* To determine the CD ratio */ | |
90 | /* MSEL[1:0] = 0, CD Ratio = 1 */ | |
91 | if ((msel & 0x3) == 0x0) | |
92 | fpgamgr_set_cd_ratio(CDRATIO_x1); | |
93 | /* MSEL[1:0] = 1, CD Ratio = 2 */ | |
94 | else if ((msel & 0x3) == 0x1) | |
95 | fpgamgr_set_cd_ratio(CDRATIO_x2); | |
96 | /* MSEL[1:0] = 2, CD Ratio = 4 */ | |
97 | else if ((msel & 0x3) == 0x2) | |
98 | fpgamgr_set_cd_ratio(CDRATIO_x4); | |
99 | } | |
100 | ||
101 | /* To enable FPGA Manager configuration */ | |
102 | clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCE_MASK); | |
103 | ||
104 | /* To enable FPGA Manager drive over configuration line */ | |
105 | setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_EN_MASK); | |
106 | ||
107 | /* Put FPGA into reset phase */ | |
108 | setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCONFIGPULL_MASK); | |
109 | ||
110 | /* (1) wait until FPGA enter reset phase */ | |
111 | for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { | |
112 | if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_RESETPHASE) | |
113 | break; | |
114 | } | |
115 | ||
116 | /* If not in reset state, return error */ | |
117 | if (fpgamgr_get_mode() != FPGAMGRREGS_MODE_RESETPHASE) { | |
118 | puts("FPGA: Could not reset\n"); | |
119 | return -1; | |
120 | } | |
121 | ||
122 | /* Release FPGA from reset phase */ | |
123 | clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCONFIGPULL_MASK); | |
124 | ||
125 | /* (2) wait until FPGA enter configuration phase */ | |
126 | for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { | |
127 | if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_CFGPHASE) | |
128 | break; | |
129 | } | |
130 | ||
131 | /* If not in configuration state, return error */ | |
132 | if (fpgamgr_get_mode() != FPGAMGRREGS_MODE_CFGPHASE) { | |
133 | puts("FPGA: Could not configure\n"); | |
134 | return -2; | |
135 | } | |
136 | ||
137 | /* Clear all interrupts in CB Monitor */ | |
138 | writel(0xFFF, &fpgamgr_regs->gpio_porta_eoi); | |
139 | ||
140 | /* Enable AXI configuration */ | |
141 | setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_AXICFGEN_MASK); | |
142 | ||
143 | return 0; | |
144 | } | |
145 | ||
146 | /* Write the RBF data to FPGA Manager */ | |
147 | static void fpgamgr_program_write(const void *rbf_data, unsigned long rbf_size) | |
148 | { | |
149 | uint32_t src = (uint32_t)rbf_data; | |
150 | uint32_t dst = SOCFPGA_FPGAMGRDATA_ADDRESS; | |
151 | ||
152 | /* Number of loops for 32-byte long copying. */ | |
153 | uint32_t loops32 = rbf_size / 32; | |
154 | /* Number of loops for 4-byte long copying + trailing bytes */ | |
155 | uint32_t loops4 = DIV_ROUND_UP(rbf_size % 32, 4); | |
156 | ||
157 | asm volatile( | |
158 | "1: ldmia %0!, {r0-r7}\n" | |
159 | " stmia %1!, {r0-r7}\n" | |
160 | " sub %1, #32\n" | |
161 | " subs %2, #1\n" | |
162 | " bne 1b\n" | |
bfa89d2b MV |
163 | " cmp %3, #0\n" |
164 | " beq 3f\n" | |
230fe9b2 PM |
165 | "2: ldr %2, [%0], #4\n" |
166 | " str %2, [%1]\n" | |
167 | " subs %3, #1\n" | |
168 | " bne 2b\n" | |
bfa89d2b | 169 | "3: nop\n" |
230fe9b2 PM |
170 | : "+r"(src), "+r"(dst), "+r"(loops32), "+r"(loops4) : |
171 | : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "cc"); | |
172 | } | |
173 | ||
174 | /* Ensure the FPGA entering config done */ | |
175 | static int fpgamgr_program_poll_cd(void) | |
176 | { | |
177 | const uint32_t mask = FPGAMGRREGS_MON_GPIO_EXT_PORTA_NS_MASK | | |
178 | FPGAMGRREGS_MON_GPIO_EXT_PORTA_CD_MASK; | |
179 | unsigned long reg, i; | |
180 | ||
181 | /* (3) wait until full config done */ | |
182 | for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { | |
183 | reg = readl(&fpgamgr_regs->gpio_ext_porta); | |
184 | ||
185 | /* Config error */ | |
186 | if (!(reg & mask)) { | |
187 | printf("FPGA: Configuration error.\n"); | |
188 | return -3; | |
189 | } | |
190 | ||
191 | /* Config done without error */ | |
192 | if (reg & mask) | |
193 | break; | |
194 | } | |
195 | ||
196 | /* Timeout happened, return error */ | |
197 | if (i == FPGA_TIMEOUT_CNT) { | |
198 | printf("FPGA: Timeout waiting for program.\n"); | |
199 | return -4; | |
200 | } | |
201 | ||
202 | /* Disable AXI configuration */ | |
203 | clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_AXICFGEN_MASK); | |
204 | ||
205 | return 0; | |
206 | } | |
207 | ||
208 | /* Ensure the FPGA entering init phase */ | |
209 | static int fpgamgr_program_poll_initphase(void) | |
210 | { | |
211 | unsigned long i; | |
212 | ||
213 | /* Additional clocks for the CB to enter initialization phase */ | |
214 | if (fpgamgr_dclkcnt_set(0x4)) | |
215 | return -5; | |
216 | ||
217 | /* (4) wait until FPGA enter init phase or user mode */ | |
218 | for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { | |
219 | if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_INITPHASE) | |
220 | break; | |
221 | if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_USERMODE) | |
222 | break; | |
223 | } | |
224 | ||
225 | /* If not in configuration state, return error */ | |
226 | if (i == FPGA_TIMEOUT_CNT) | |
227 | return -6; | |
228 | ||
229 | return 0; | |
230 | } | |
231 | ||
232 | /* Ensure the FPGA entering user mode */ | |
233 | static int fpgamgr_program_poll_usermode(void) | |
234 | { | |
235 | unsigned long i; | |
236 | ||
237 | /* Additional clocks for the CB to exit initialization phase */ | |
238 | if (fpgamgr_dclkcnt_set(0x5000)) | |
239 | return -7; | |
240 | ||
241 | /* (5) wait until FPGA enter user mode */ | |
242 | for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { | |
243 | if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_USERMODE) | |
244 | break; | |
245 | } | |
246 | /* If not in configuration state, return error */ | |
247 | if (i == FPGA_TIMEOUT_CNT) | |
248 | return -8; | |
249 | ||
250 | /* To release FPGA Manager drive over configuration line */ | |
251 | clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_EN_MASK); | |
252 | ||
253 | return 0; | |
254 | } | |
255 | ||
256 | /* | |
257 | * FPGA Manager to program the FPGA. This is the interface used by FPGA driver. | |
258 | * Return 0 for sucess, non-zero for error. | |
259 | */ | |
260 | int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size) | |
261 | { | |
262 | unsigned long status; | |
263 | ||
264 | if ((uint32_t)rbf_data & 0x3) { | |
265 | puts("FPGA: Unaligned data, realign to 32bit boundary.\n"); | |
266 | return -EINVAL; | |
267 | } | |
268 | ||
269 | /* Prior programming the FPGA, all bridges need to be shut off */ | |
270 | ||
271 | /* Disable all signals from hps peripheral controller to fpga */ | |
a409a8b8 | 272 | writel(0, &sysmgr_regs->fpgaintfgrp_module); |
230fe9b2 PM |
273 | |
274 | /* Disable all signals from FPGA to HPS SDRAM */ | |
275 | #define SDR_CTRLGRP_FPGAPORTRST_ADDRESS 0x5080 | |
276 | writel(0, SOCFPGA_SDR_ADDRESS + SDR_CTRLGRP_FPGAPORTRST_ADDRESS); | |
277 | ||
278 | /* Disable all axi bridge (hps2fpga, lwhps2fpga & fpga2hps) */ | |
279 | socfpga_bridges_reset(1); | |
280 | ||
281 | /* Unmap the bridges from NIC-301 */ | |
282 | writel(0x1, SOCFPGA_L3REGS_ADDRESS); | |
283 | ||
284 | /* Initialize the FPGA Manager */ | |
285 | status = fpgamgr_program_init(); | |
286 | if (status) | |
287 | return status; | |
288 | ||
289 | /* Write the RBF data to FPGA Manager */ | |
290 | fpgamgr_program_write(rbf_data, rbf_size); | |
291 | ||
292 | /* Ensure the FPGA entering config done */ | |
293 | status = fpgamgr_program_poll_cd(); | |
294 | if (status) | |
295 | return status; | |
296 | ||
297 | /* Ensure the FPGA entering init phase */ | |
298 | status = fpgamgr_program_poll_initphase(); | |
299 | if (status) | |
300 | return status; | |
301 | ||
302 | /* Ensure the FPGA entering user mode */ | |
303 | return fpgamgr_program_poll_usermode(); | |
304 | } |