Blame view

drivers/fpga/zynqmppl.c 7.17 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0
6b2450143   Siva Durga Prasad Paladugu   fpga: xilinx: zyn...
2
3
4
5
  /*
   * (C) Copyright 2015 - 2016, Xilinx, Inc,
   * Michal Simek <michal.simek@xilinx.com>
   * Siva Durga Prasad <siva.durga.paladugu@xilinx.com>
6b2450143   Siva Durga Prasad Paladugu   fpga: xilinx: zyn...
6
7
8
9
   */
  
  #include <console.h>
  #include <common.h>
1eb69ae49   Simon Glass   common: Move ARM ...
10
  #include <cpu_func.h>
6b2450143   Siva Durga Prasad Paladugu   fpga: xilinx: zyn...
11
  #include <zynqmppl.h>
009ab7b93   Ibai Erkiaga   firmware: zynqmp:...
12
  #include <zynqmp_firmware.h>
6b2450143   Siva Durga Prasad Paladugu   fpga: xilinx: zyn...
13
  #include <linux/sizes.h>
7033ae272   Siva Durga Prasad Paladugu   fpga: zynqmppl: R...
14
  #include <asm/arch/sys_proto.h>
31bcb3444   Siva Durga Prasad Paladugu   fpga: zynqmp: Fix...
15
  #include <memalign.h>
6b2450143   Siva Durga Prasad Paladugu   fpga: xilinx: zyn...
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  
  #define DUMMY_WORD	0xffffffff
  
  /* Xilinx binary format header */
  static const u32 bin_format[] = {
  	DUMMY_WORD, /* Dummy words */
  	DUMMY_WORD,
  	DUMMY_WORD,
  	DUMMY_WORD,
  	DUMMY_WORD,
  	DUMMY_WORD,
  	DUMMY_WORD,
  	DUMMY_WORD,
  	DUMMY_WORD,
  	DUMMY_WORD,
  	DUMMY_WORD,
  	DUMMY_WORD,
  	DUMMY_WORD,
  	DUMMY_WORD,
  	DUMMY_WORD,
  	DUMMY_WORD,
  	0x000000bb, /* Sync word */
  	0x11220044, /* Sync word */
  	DUMMY_WORD,
  	DUMMY_WORD,
  	0xaa995566, /* Sync word */
  };
  
  #define SWAP_NO		1
  #define SWAP_DONE	2
  
  /*
   * Load the whole word from unaligned buffer
   * Keep in your mind that it is byte loading on little-endian system
   */
  static u32 load_word(const void *buf, u32 swap)
  {
  	u32 word = 0;
  	u8 *bitc = (u8 *)buf;
  	int p;
  
  	if (swap == SWAP_NO) {
  		for (p = 0; p < 4; p++) {
  			word <<= 8;
  			word |= bitc[p];
  		}
  	} else {
  		for (p = 3; p >= 0; p--) {
  			word <<= 8;
  			word |= bitc[p];
  		}
  	}
  
  	return word;
  }
  
  static u32 check_header(const void *buf)
  {
  	u32 i, pattern;
  	int swap = SWAP_NO;
  	u32 *test = (u32 *)buf;
  
  	debug("%s: Let's check bitstream header
  ", __func__);
  
  	/* Checking that passing bin is not a bitstream */
  	for (i = 0; i < ARRAY_SIZE(bin_format); i++) {
  		pattern = load_word(&test[i], swap);
  
  		/*
  		 * Bitstreams in binary format are swapped
  		 * compare to regular bistream.
  		 * Do not swap dummy word but if swap is done assume
  		 * that parsing buffer is binary format
  		 */
  		if ((__swab32(pattern) != DUMMY_WORD) &&
  		    (__swab32(pattern) == bin_format[i])) {
  			swap = SWAP_DONE;
  			debug("%s: data swapped - let's swap
  ", __func__);
  		}
  
  		debug("%s: %d/%px: pattern %x/%x bin_format
  ", __func__, i,
  		      &test[i], pattern, bin_format[i]);
  	}
  	debug("%s: Found bitstream header at %px %s swapinng
  ", __func__,
  	      buf, swap == SWAP_NO ? "without" : "with");
  
  	return swap;
  }
  
  static void *check_data(u8 *buf, size_t bsize, u32 *swap)
  {
  	u32 word, p = 0; /* possition */
  
  	/* Because buf doesn't need to be aligned let's read it by chars */
  	for (p = 0; p < bsize; p++) {
  		word = load_word(&buf[p], SWAP_NO);
  		debug("%s: word %x %x/%px
  ", __func__, word, p, &buf[p]);
  
  		/* Find the first bitstream dummy word */
  		if (word == DUMMY_WORD) {
  			debug("%s: Found dummy word at position %x/%px
  ",
  			      __func__, p, &buf[p]);
  			*swap = check_header(&buf[p]);
  			if (*swap) {
  				/* FIXME add full bitstream checking here */
  				return &buf[p];
  			}
  		}
  		/* Loop can be huge - support CTRL + C */
  		if (ctrlc())
  			return NULL;
  	}
  	return NULL;
  }
  
  static ulong zynqmp_align_dma_buffer(u32 *buf, u32 len, u32 swap)
  {
  	u32 *new_buf;
  	u32 i;
  
  	if ((ulong)buf != ALIGN((ulong)buf, ARCH_DMA_MINALIGN)) {
  		new_buf = (u32 *)ALIGN((ulong)buf, ARCH_DMA_MINALIGN);
  
  		/*
  		 * This might be dangerous but permits to flash if
  		 * ARCH_DMA_MINALIGN is greater than header size
  		 */
  		if (new_buf > (u32 *)buf) {
  			debug("%s: Aligned buffer is after buffer start
  ",
  			      __func__);
  			new_buf -= ARCH_DMA_MINALIGN;
  		}
  		printf("%s: Align buffer at %px to %px(swap %d)
  ", __func__,
  		       buf, new_buf, swap);
  
  		for (i = 0; i < (len/4); i++)
  			new_buf[i] = load_word(&buf[i], swap);
  
  		buf = new_buf;
fbf7fb0f9   Siva Durga Prasad Paladugu   fpga: zynqmp: Mod...
163
  	} else if ((swap != SWAP_DONE) &&
5743981e2   Ibai Erkiaga   arm64: zynqmp: us...
164
  		   (zynqmp_firmware_version() <= PMUFW_V1_0)) {
6b2450143   Siva Durga Prasad Paladugu   fpga: xilinx: zyn...
165
  		/* For bitstream which are aligned */
23decf013   Michal Simek   fpga: zynqmp: Fix...
166
  		new_buf = buf;
6b2450143   Siva Durga Prasad Paladugu   fpga: xilinx: zyn...
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
  
  		printf("%s: Bitstream is not swapped(%d) - swap it
  ", __func__,
  		       swap);
  
  		for (i = 0; i < (len/4); i++)
  			new_buf[i] = load_word(&buf[i], swap);
  	}
  
  	return (ulong)buf;
  }
  
  static int zynqmp_validate_bitstream(xilinx_desc *desc, const void *buf,
  				   size_t bsize, u32 blocksize, u32 *swap)
  {
  	ulong *buf_start;
  	ulong diff;
  
  	buf_start = check_data((u8 *)buf, blocksize, swap);
  
  	if (!buf_start)
  		return FPGA_FAIL;
  
  	/* Check if data is postpone from start */
  	diff = (ulong)buf_start - (ulong)buf;
  	if (diff) {
  		printf("%s: Bitstream is not validated yet (diff %lx)
  ",
  		       __func__, diff);
  		return FPGA_FAIL;
  	}
  
  	if ((ulong)buf < SZ_1M) {
  		printf("%s: Bitstream has to be placed up to 1MB (%px)
  ",
  		       __func__, buf);
  		return FPGA_FAIL;
  	}
  
  	return 0;
  }
6b2450143   Siva Durga Prasad Paladugu   fpga: xilinx: zyn...
208
209
210
  static int zynqmp_load(xilinx_desc *desc, const void *buf, size_t bsize,
  		     bitstream_type bstype)
  {
31bcb3444   Siva Durga Prasad Paladugu   fpga: zynqmp: Fix...
211
  	ALLOC_CACHE_ALIGN_BUFFER(u32, bsizeptr, 1);
fbf7fb0f9   Siva Durga Prasad Paladugu   fpga: zynqmp: Mod...
212
  	u32 swap = 0;
7033ae272   Siva Durga Prasad Paladugu   fpga: zynqmppl: R...
213
  	ulong bin_buf;
6b2450143   Siva Durga Prasad Paladugu   fpga: xilinx: zyn...
214
  	int ret;
7033ae272   Siva Durga Prasad Paladugu   fpga: zynqmppl: R...
215
216
  	u32 buf_lo, buf_hi;
  	u32 ret_payload[PAYLOAD_ARG_CNT];
fbf7fb0f9   Siva Durga Prasad Paladugu   fpga: zynqmp: Mod...
217
  	bool xilfpga_old = false;
5743981e2   Ibai Erkiaga   arm64: zynqmp: us...
218
  	if (zynqmp_firmware_version() <= PMUFW_V1_0) {
fbf7fb0f9   Siva Durga Prasad Paladugu   fpga: zynqmp: Mod...
219
220
221
222
223
224
225
226
227
228
229
230
231
232
  		puts("WARN: PMUFW v1.0 or less is detected
  ");
  		puts("WARN: Not all bitstream formats are supported
  ");
  		puts("WARN: Please upgrade PMUFW
  ");
  		xilfpga_old = true;
  		if (zynqmp_validate_bitstream(desc, buf, bsize, bsize, &swap))
  			return FPGA_FAIL;
  		bsizeptr = (u32 *)&bsize;
  		flush_dcache_range((ulong)bsizeptr,
  				   (ulong)bsizeptr + sizeof(size_t));
  		bstype |= BIT(ZYNQMP_FPGA_BIT_NS);
  	}
6b2450143   Siva Durga Prasad Paladugu   fpga: xilinx: zyn...
233
234
235
236
237
238
  
  	bin_buf = zynqmp_align_dma_buffer((u32 *)buf, bsize, swap);
  
  	debug("%s called!
  ", __func__);
  	flush_dcache_range(bin_buf, bin_buf + bsize);
7033ae272   Siva Durga Prasad Paladugu   fpga: zynqmppl: R...
239
240
  	buf_lo = (u32)bin_buf;
  	buf_hi = upper_32_bits(bin_buf);
fbf7fb0f9   Siva Durga Prasad Paladugu   fpga: zynqmp: Mod...
241
242
  
  	if (xilfpga_old)
403619515   Michal Simek   arm64: zynqmp: Co...
243
244
245
  		ret = xilinx_pm_request(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo,
  					buf_hi, (u32)(uintptr_t)bsizeptr,
  					bstype, ret_payload);
fbf7fb0f9   Siva Durga Prasad Paladugu   fpga: zynqmp: Mod...
246
  	else
403619515   Michal Simek   arm64: zynqmp: Co...
247
248
  		ret = xilinx_pm_request(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo,
  					buf_hi, (u32)bsize, 0, ret_payload);
fbf7fb0f9   Siva Durga Prasad Paladugu   fpga: zynqmp: Mod...
249

6b2450143   Siva Durga Prasad Paladugu   fpga: xilinx: zyn...
250
  	if (ret)
8df324a20   Luca Ceresoli   fpga: zynqmp: sho...
251
252
  		puts("PL FPGA LOAD fail
  ");
6b2450143   Siva Durga Prasad Paladugu   fpga: xilinx: zyn...
253
254
255
  
  	return ret;
  }
a18d09ea3   Siva Durga Prasad Paladugu   fpga: zynqmp: Add...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
  #if defined(CONFIG_CMD_FPGA_LOAD_SECURE) && !defined(CONFIG_SPL_BUILD)
  static int zynqmp_loads(xilinx_desc *desc, const void *buf, size_t bsize,
  			struct fpga_secure_info *fpga_sec_info)
  {
  	int ret;
  	u32 buf_lo, buf_hi;
  	u32 ret_payload[PAYLOAD_ARG_CNT];
  	u8 flag = 0;
  
  	flush_dcache_range((ulong)buf, (ulong)buf +
  			   ALIGN(bsize, CONFIG_SYS_CACHELINE_SIZE));
  
  	if (!fpga_sec_info->encflag)
  		flag |= BIT(ZYNQMP_FPGA_BIT_ENC_DEV_KEY);
  
  	if (fpga_sec_info->userkey_addr &&
  	    fpga_sec_info->encflag == FPGA_ENC_USR_KEY) {
  		flush_dcache_range((ulong)fpga_sec_info->userkey_addr,
  				   (ulong)fpga_sec_info->userkey_addr +
  				   ALIGN(KEY_PTR_LEN,
  					 CONFIG_SYS_CACHELINE_SIZE));
  		flag |= BIT(ZYNQMP_FPGA_BIT_ENC_USR_KEY);
  	}
  
  	if (!fpga_sec_info->authflag)
  		flag |= BIT(ZYNQMP_FPGA_BIT_AUTH_OCM);
  
  	if (fpga_sec_info->authflag == ZYNQMP_FPGA_AUTH_DDR)
  		flag |= BIT(ZYNQMP_FPGA_BIT_AUTH_DDR);
  
  	buf_lo = lower_32_bits((ulong)buf);
  	buf_hi = upper_32_bits((ulong)buf);
403619515   Michal Simek   arm64: zynqmp: Co...
288
289
  	ret = xilinx_pm_request(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo,
  				buf_hi,
a18d09ea3   Siva Durga Prasad Paladugu   fpga: zynqmp: Add...
290
291
292
293
294
295
296
297
298
299
300
301
  			 (u32)(uintptr_t)fpga_sec_info->userkey_addr,
  			 flag, ret_payload);
  	if (ret)
  		puts("PL FPGA LOAD fail
  ");
  	else
  		puts("Bitstream successfully loaded
  ");
  
  	return ret;
  }
  #endif
b32e11a71   Nitin Jain   fpga: zynqmp: Add...
302
303
304
305
  static int zynqmp_pcap_info(xilinx_desc *desc)
  {
  	int ret;
  	u32 ret_payload[PAYLOAD_ARG_CNT];
403619515   Michal Simek   arm64: zynqmp: Co...
306
307
  	ret = xilinx_pm_request(ZYNQMP_SIP_SVC_PM_FPGA_STATUS, 0, 0, 0,
  				0, ret_payload);
b32e11a71   Nitin Jain   fpga: zynqmp: Add...
308
309
310
311
312
313
  	if (!ret)
  		printf("PCAP status\t0x%x
  ", ret_payload[1]);
  
  	return ret;
  }
6b2450143   Siva Durga Prasad Paladugu   fpga: xilinx: zyn...
314
315
  struct xilinx_fpga_op zynqmp_op = {
  	.load = zynqmp_load,
a18d09ea3   Siva Durga Prasad Paladugu   fpga: zynqmp: Add...
316
317
318
  #if defined CONFIG_CMD_FPGA_LOAD_SECURE
  	.loads = zynqmp_loads,
  #endif
b32e11a71   Nitin Jain   fpga: zynqmp: Add...
319
  	.info = zynqmp_pcap_info,
6b2450143   Siva Durga Prasad Paladugu   fpga: xilinx: zyn...
320
  };