xref: /rk3399_ARM-atf/plat/intel/soc/common/drivers/qspi/cadence_qspi.c (revision 52e486f6a6192bd18d36cdcbc35c59092eefc810)
1 /*
2  * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
3  * Copyright (c) 2019, Intel Corporation. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <assert.h>
9 #include <common/debug.h>
10 #include <lib/mmio.h>
11 #include <string.h>
12 #include <drivers/delay_timer.h>
13 #include <drivers/console.h>
14 
15 #include "cadence_qspi.h"
16 #include "socfpga_plat_def.h"
17 #include "wdt/watchdog.h"
18 
19 #define LESS(a, b)   (((a) < (b)) ? (a) : (b))
20 #define MORE(a, b)   (((a) > (b)) ? (a) : (b))
21 
22 
23 uint32_t qspi_device_size;
24 int cad_qspi_cs;
25 
26 int cad_qspi_idle(void)
27 {
28 	return (mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG)
29 			& CAD_QSPI_CFG_IDLE) >> 31;
30 }
31 
32 int cad_qspi_set_baudrate_div(uint32_t div)
33 {
34 	if (div > 0xf)
35 		return CAD_INVALID;
36 
37 	mmio_clrsetbits_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG,
38 			~CAD_QSPI_CFG_BAUDDIV_MSK,
39 			CAD_QSPI_CFG_BAUDDIV(div));
40 
41 	return 0;
42 }
43 
44 int cad_qspi_configure_dev_size(uint32_t addr_bytes,
45 		uint32_t bytes_per_dev, uint32_t bytes_per_block)
46 {
47 
48 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DEVSZ,
49 			CAD_QSPI_DEVSZ_ADDR_BYTES(addr_bytes) |
50 			CAD_QSPI_DEVSZ_BYTES_PER_PAGE(bytes_per_dev) |
51 			CAD_QSPI_DEVSZ_BYTES_PER_BLOCK(bytes_per_block));
52 	return 0;
53 }
54 
55 int cad_qspi_set_read_config(uint32_t opcode, uint32_t instr_type,
56 		uint32_t addr_type, uint32_t data_type,
57 		uint32_t mode_bit, uint32_t dummy_clk_cycle)
58 {
59 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DEVRD,
60 			CAD_QSPI_DEV_OPCODE(opcode) |
61 			CAD_QSPI_DEV_INST_TYPE(instr_type) |
62 			CAD_QSPI_DEV_ADDR_TYPE(addr_type) |
63 			CAD_QSPI_DEV_DATA_TYPE(data_type) |
64 			CAD_QSPI_DEV_MODE_BIT(mode_bit) |
65 			CAD_QSPI_DEV_DUMMY_CLK_CYCLE(dummy_clk_cycle));
66 
67 	return 0;
68 }
69 
70 int cad_qspi_set_write_config(uint32_t opcode, uint32_t addr_type,
71 		uint32_t data_type, uint32_t dummy_clk_cycle)
72 {
73 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DEVWR,
74 			CAD_QSPI_DEV_OPCODE(opcode) |
75 			CAD_QSPI_DEV_ADDR_TYPE(addr_type) |
76 			CAD_QSPI_DEV_DATA_TYPE(data_type) |
77 			CAD_QSPI_DEV_DUMMY_CLK_CYCLE(dummy_clk_cycle));
78 
79 	return 0;
80 }
81 
82 int cad_qspi_timing_config(uint32_t clkphase, uint32_t clkpol, uint32_t csda,
83 		uint32_t csdads, uint32_t cseot, uint32_t cssot,
84 		uint32_t rddatacap)
85 {
86 	uint32_t cfg = mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG);
87 
88 	cfg &= CAD_QSPI_CFG_SELCLKPHASE_CLR_MSK &
89 		CAD_QSPI_CFG_SELCLKPOL_CLR_MSK;
90 	cfg |= CAD_QSPI_SELCLKPHASE(clkphase) | CAD_QSPI_SELCLKPOL(clkpol);
91 
92 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG, cfg);
93 
94 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DELAY,
95 		CAD_QSPI_DELAY_CSSOT(cssot) | CAD_QSPI_DELAY_CSEOT(cseot) |
96 		CAD_QSPI_DELAY_CSDADS(csdads) | CAD_QSPI_DELAY_CSDA(csda));
97 
98 	return 0;
99 }
100 
101 int cad_qspi_stig_cmd_helper(int cs, uint32_t cmd)
102 {
103 	uint32_t count = 0;
104 
105 	/* chip select */
106 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG,
107 			(mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG)
108 			 & CAD_QSPI_CFG_CS_MSK) | CAD_QSPI_CFG_CS(cs));
109 
110 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD, cmd);
111 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD,
112 			cmd | CAD_QSPI_FLASHCMD_EXECUTE);
113 
114 	do {
115 		uint32_t reg = mmio_read_32(CAD_QSPI_OFFSET +
116 					CAD_QSPI_FLASHCMD);
117 		if (!(reg & CAD_QSPI_FLASHCMD_EXECUTE_STAT))
118 			break;
119 		count++;
120 	} while (count < CAD_QSPI_COMMAND_TIMEOUT);
121 
122 	if (count >= CAD_QSPI_COMMAND_TIMEOUT) {
123 		ERROR("Error sending QSPI command %x, timed out\n",
124 				cmd);
125 		return CAD_QSPI_ERROR;
126 	}
127 
128 	return 0;
129 }
130 
131 int cad_qspi_stig_cmd(uint32_t opcode, uint32_t dummy)
132 {
133 	if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1)) {
134 		ERROR("Faulty dummy bytes\n");
135 		return -1;
136 	}
137 
138 	return cad_qspi_stig_cmd_helper(cad_qspi_cs,
139 			CAD_QSPI_FLASHCMD_OPCODE(opcode) |
140 			CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES(dummy));
141 }
142 
143 int cad_qspi_stig_read_cmd(uint32_t opcode, uint32_t dummy, uint32_t num_bytes,
144 		uint32_t *output)
145 {
146 	if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1)) {
147 		ERROR("Faulty dummy byes\n");
148 		return -1;
149 	}
150 
151 	if ((num_bytes > 8) || (num_bytes == 0))
152 		return -1;
153 
154 	uint32_t cmd =
155 		CAD_QSPI_FLASHCMD_OPCODE(opcode) |
156 		CAD_QSPI_FLASHCMD_ENRDDATA(1) |
157 		CAD_QSPI_FLASHCMD_NUMRDDATABYTES(num_bytes - 1) |
158 		CAD_QSPI_FLASHCMD_ENCMDADDR(0) |
159 		CAD_QSPI_FLASHCMD_ENMODEBIT(0) |
160 		CAD_QSPI_FLASHCMD_NUMADDRBYTES(0) |
161 		CAD_QSPI_FLASHCMD_ENWRDATA(0) |
162 		CAD_QSPI_FLASHCMD_NUMWRDATABYTES(0) |
163 		CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(dummy);
164 
165 	if (cad_qspi_stig_cmd_helper(cad_qspi_cs, cmd)) {
166 		ERROR("failed to send stig cmd\n");
167 		return -1;
168 	}
169 
170 	output[0] = mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_RDDATA0);
171 
172 	if (num_bytes > 4) {
173 		output[1] = mmio_read_32(CAD_QSPI_OFFSET +
174 				CAD_QSPI_FLASHCMD_RDDATA1);
175 	}
176 
177 	return 0;
178 }
179 
180 int cad_qspi_stig_wr_cmd(uint32_t opcode, uint32_t dummy, uint32_t num_bytes,
181 		uint32_t *input)
182 {
183 	if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1)) {
184 		ERROR("Faulty dummy byes\n");
185 		return -1;
186 	}
187 
188 	if ((num_bytes > 8) || (num_bytes == 0))
189 		return -1;
190 
191 	uint32_t cmd = CAD_QSPI_FLASHCMD_OPCODE(opcode) |
192 		CAD_QSPI_FLASHCMD_ENRDDATA(0) |
193 		CAD_QSPI_FLASHCMD_NUMRDDATABYTES(0) |
194 		CAD_QSPI_FLASHCMD_ENCMDADDR(0) |
195 		CAD_QSPI_FLASHCMD_ENMODEBIT(0) |
196 		CAD_QSPI_FLASHCMD_NUMADDRBYTES(0) |
197 		CAD_QSPI_FLASHCMD_ENWRDATA(1) |
198 		CAD_QSPI_FLASHCMD_NUMWRDATABYTES(num_bytes - 1) |
199 		CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(dummy);
200 
201 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_WRDATA0, input[0]);
202 
203 	if (num_bytes > 4)
204 		mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_WRDATA1,
205 				input[1]);
206 
207 	return cad_qspi_stig_cmd_helper(cad_qspi_cs, cmd);
208 }
209 
210 int cad_qspi_stig_addr_cmd(uint32_t opcode, uint32_t dummy, uint32_t addr)
211 {
212 	uint32_t cmd;
213 
214 	if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1))
215 		return -1;
216 
217 	cmd = CAD_QSPI_FLASHCMD_OPCODE(opcode) |
218 		CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(dummy) |
219 		CAD_QSPI_FLASHCMD_ENCMDADDR(1) |
220 		CAD_QSPI_FLASHCMD_NUMADDRBYTES(2);
221 
222 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_ADDR, addr);
223 
224 	return cad_qspi_stig_cmd_helper(cad_qspi_cs, cmd);
225 }
226 
227 int cad_qspi_device_bank_select(uint32_t bank)
228 {
229 	int status = 0;
230 
231 	status = cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WREN, 0);
232 	if (status != 0)
233 		return status;
234 
235 	status = cad_qspi_stig_wr_cmd(CAD_QSPI_STIG_OPCODE_WREN_EXT_REG,
236 			0, 1, &bank);
237 	if (status != 0)
238 		return status;
239 
240 	return cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WRDIS, 0);
241 }
242 
243 int cad_qspi_device_status(uint32_t *status)
244 {
245 	return cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDSR, 0, 1, status);
246 }
247 
248 #if CAD_QSPI_MICRON_N25Q_SUPPORT
249 int cad_qspi_n25q_enable(void)
250 {
251 	cad_qspi_set_read_config(QSPI_FAST_READ, CAD_QSPI_INST_SINGLE,
252 			CAD_QSPI_ADDR_FASTREAD, CAT_QSPI_ADDR_SINGLE_IO, 1,
253 			0);
254 	cad_qspi_set_write_config(QSPI_WRITE, 0, 0, 0);
255 
256 	return 0;
257 }
258 
259 int cad_qspi_n25q_wait_for_program_and_erase(int program_only)
260 {
261 	uint32_t status, flag_sr;
262 	int count = 0;
263 
264 	while (count < CAD_QSPI_COMMAND_TIMEOUT) {
265 		status = cad_qspi_device_status(&status);
266 		if (status != 0) {
267 			ERROR("Error getting device status\n");
268 			return -1;
269 		}
270 		if (!CAD_QSPI_STIG_SR_BUSY(status))
271 			break;
272 		count++;
273 	}
274 
275 	if (count >= CAD_QSPI_COMMAND_TIMEOUT) {
276 		ERROR("Timed out waiting for idle\n");
277 		return -1;
278 	}
279 
280 	count = 0;
281 
282 	while (count < CAD_QSPI_COMMAND_TIMEOUT) {
283 		status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDFLGSR,
284 				0, 1, &flag_sr);
285 		if (status != 0) {
286 			ERROR("Error waiting program and erase.\n");
287 			return status;
288 		}
289 
290 		if ((program_only &&
291 			CAD_QSPI_STIG_FLAGSR_PROGRAMREADY(flag_sr)) ||
292 			(!program_only &&
293 			CAD_QSPI_STIG_FLAGSR_ERASEREADY(flag_sr)))
294 			break;
295 	}
296 
297 	if (count >= CAD_QSPI_COMMAND_TIMEOUT)
298 		ERROR("Timed out waiting for program and erase\n");
299 
300 	if ((program_only && CAD_QSPI_STIG_FLAGSR_PROGRAMERROR(flag_sr)) ||
301 			(!program_only &&
302 			CAD_QSPI_STIG_FLAGSR_ERASEERROR(flag_sr))) {
303 		ERROR("Error programming/erasing flash\n");
304 		cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_CLFSR, 0);
305 		return -1;
306 	}
307 
308 	return 0;
309 }
310 #endif
311 
312 int cad_qspi_indirect_read_start_bank(uint32_t flash_addr, uint32_t num_bytes)
313 {
314 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRDSTADDR, flash_addr);
315 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRDCNT, num_bytes);
316 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRD,
317 			CAD_QSPI_INDRD_START |
318 			CAD_QSPI_INDRD_IND_OPS_DONE);
319 
320 	return 0;
321 }
322 
323 
324 int cad_qspi_indirect_write_start_bank(uint32_t flash_addr,
325 					uint32_t num_bytes)
326 {
327 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWRSTADDR, flash_addr);
328 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWRCNT, num_bytes);
329 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWR,
330 			CAD_QSPI_INDWR_START |
331 			CAD_QSPI_INDWR_INDDONE);
332 
333 	return 0;
334 }
335 
336 int cad_qspi_indirect_write_finish(void)
337 {
338 #if CAD_QSPI_MICRON_N25Q_SUPPORT
339 	return cad_qspi_n25q_wait_for_program_and_erase(1);
340 #else
341 	return 0;
342 #endif
343 
344 }
345 
346 int cad_qspi_enable(void)
347 {
348 	int status;
349 
350 	mmio_setbits_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG, CAD_QSPI_CFG_ENABLE);
351 
352 #if CAD_QSPI_MICRON_N25Q_SUPPORT
353 	status = cad_qspi_n25q_enable();
354 	if (status != 0)
355 		return status;
356 #endif
357 	return 0;
358 }
359 
360 int cad_qspi_enable_subsector_bank(uint32_t addr)
361 {
362 	int status = 0;
363 
364 	status = cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WREN, 0);
365 	if (status != 0)
366 		return status;
367 
368 	status = cad_qspi_stig_addr_cmd(CAD_QSPI_STIG_OPCODE_SUBSEC_ERASE, 0,
369 					addr);
370 	if (status != 0)
371 		return status;
372 
373 #if CAD_QSPI_MICRON_N25Q_SUPPORT
374 	status = cad_qspi_n25q_wait_for_program_and_erase(0);
375 #endif
376 	return status;
377 }
378 
379 int cad_qspi_erase_subsector(uint32_t addr)
380 {
381 	int status = 0;
382 
383 	status = cad_qspi_device_bank_select(addr >> 24);
384 	if (status != 0)
385 		return status;
386 
387 	return cad_qspi_enable_subsector_bank(addr);
388 }
389 
390 int cad_qspi_erase_sector(uint32_t addr)
391 {
392 	int status = 0;
393 
394 	status = cad_qspi_device_bank_select(addr >> 24);
395 	if (status != 0)
396 		return status;
397 
398 	status = cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WREN, 0);
399 	if (status != 0)
400 		return status;
401 
402 	status = cad_qspi_stig_addr_cmd(CAD_QSPI_STIG_OPCODE_SEC_ERASE, 0,
403 					addr);
404 	if (status != 0)
405 		return status;
406 
407 #if CAD_QSPI_MICRON_N25Q_SUPPORT
408 	status = cad_qspi_n25q_wait_for_program_and_erase(0);
409 #endif
410 	return status;
411 }
412 
413 void cad_qspi_calibration(uint32_t dev_clk, uint32_t qspi_clk_mhz)
414 {
415 	int status;
416 	uint32_t dev_sclk_mhz = 27; /*min value to get biggest 0xF div factor*/
417 	uint32_t data_cap_delay;
418 	uint32_t sample_rdid;
419 	uint32_t rdid;
420 	uint32_t div_actual;
421 	uint32_t div_bits;
422 	int first_pass, last_pass;
423 
424 	/*1.  Set divider to bigger value (slowest SCLK)
425 	 *2.  RDID and save the value
426 	 */
427 	div_actual = (qspi_clk_mhz + (dev_sclk_mhz - 1)) / dev_sclk_mhz;
428 	div_bits = (((div_actual + 1) / 2) - 1);
429 	status = cad_qspi_set_baudrate_div(0xf);
430 
431 	status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID,
432 					0, 3, &sample_rdid);
433 	if (status != 0)
434 		return;
435 
436 	/*3. Set divider to the intended frequency
437 	 *4.  Set the read delay = 0
438 	 *5.  RDID and check whether the value is same as item 2
439 	 *6.  Increase read delay and compared the value against item 2
440 	 *7.  Find the range of read delay that have same as
441 	 *    item 2 and divide it to 2
442 	 */
443 	div_actual = (qspi_clk_mhz + (dev_clk - 1)) / dev_clk;
444 	div_bits = (((div_actual + 1) / 2) - 1);
445 	status = cad_qspi_set_baudrate_div(div_bits);
446 	if (status != 0)
447 		return;
448 
449 	data_cap_delay = 0;
450 	first_pass = -1;
451 	last_pass = -1;
452 
453 	do {
454 		if (status != 0)
455 			break;
456 		status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0,
457 						3, &rdid);
458 		if (status != 0)
459 			break;
460 		if (rdid == sample_rdid) {
461 			if (first_pass == -1)
462 				first_pass = data_cap_delay;
463 			else
464 				last_pass = data_cap_delay;
465 		}
466 
467 		data_cap_delay++;
468 
469 		mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_RDDATACAP,
470 				CAD_QSPI_RDDATACAP_BYP(1) |
471 				CAD_QSPI_RDDATACAP_DELAY(data_cap_delay));
472 
473 	} while (data_cap_delay < 0x10);
474 
475 	if (first_pass > 0) {
476 		int diff = first_pass - last_pass;
477 
478 		data_cap_delay = first_pass + diff / 2;
479 	}
480 
481 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_RDDATACAP,
482 			CAD_QSPI_RDDATACAP_BYP(1) |
483 			CAD_QSPI_RDDATACAP_DELAY(data_cap_delay));
484 	status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0, 3, &rdid);
485 
486 	if (status != 0)
487 		return;
488 }
489 
490 int cad_qspi_int_disable(uint32_t mask)
491 {
492 	if (cad_qspi_idle() == 0)
493 		return -1;
494 
495 	if ((CAD_QSPI_INT_STATUS_ALL & mask) == 0)
496 		return -1;
497 
498 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_IRQMSK, mask);
499 	return 0;
500 }
501 
502 void cad_qspi_set_chip_select(int cs)
503 {
504 	cad_qspi_cs = cs;
505 }
506 
507 int cad_qspi_init(uint32_t desired_clk_freq, uint32_t clk_phase,
508 			uint32_t clk_pol, uint32_t csda, uint32_t csdads,
509 			uint32_t cseot, uint32_t cssot, uint32_t rddatacap)
510 {
511 	int status = 0;
512 	uint32_t qspi_desired_clk_freq;
513 	uint32_t rdid = 0;
514 	uint32_t cap_code;
515 
516 	INFO("Initializing Qspi\n");
517 
518 	if (cad_qspi_idle() == 0) {
519 		ERROR("device not idle\n");
520 		return -1;
521 	}
522 
523 
524 	status = cad_qspi_timing_config(clk_phase, clk_pol, csda, csdads,
525 					cseot, cssot, rddatacap);
526 
527 	if (status != 0) {
528 		ERROR("config set timing failure\n");
529 		return status;
530 	}
531 
532 	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_REMAPADDR,
533 			CAD_QSPI_REMAPADDR_VALUE_SET(0));
534 
535 	status = cad_qspi_int_disable(CAD_QSPI_INT_STATUS_ALL);
536 	if (status != 0) {
537 		ERROR("failed disable\n");
538 		return status;
539 	}
540 
541 	cad_qspi_set_baudrate_div(0xf);
542 	status = cad_qspi_enable();
543 	if (status != 0) {
544 		ERROR("failed enable\n");
545 		return status;
546 	}
547 
548 	qspi_desired_clk_freq = 100;
549 	cad_qspi_calibration(qspi_desired_clk_freq, 50000000);
550 
551 	status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0, 3,
552 					&rdid);
553 
554 	if (status != 0) {
555 		ERROR("Error reading RDID\n");
556 		return status;
557 	}
558 
559 	/*
560 	 * NOTE: The Size code seems to be a form of BCD (binary coded decimal).
561 	 * The first nibble is the 10's digit and the second nibble is the 1's
562 	 * digit in the number of bytes.
563 	 *
564 	 * Capacity ID samples:
565 	 * 0x15 :   16 Mb =>   2 MiB => 1 << 21 ; BCD=15
566 	 * 0x16 :   32 Mb =>   4 MiB => 1 << 22 ; BCD=16
567 	 * 0x17 :   64 Mb =>   8 MiB => 1 << 23 ; BCD=17
568 	 * 0x18 :  128 Mb =>  16 MiB => 1 << 24 ; BCD=18
569 	 * 0x19 :  256 Mb =>  32 MiB => 1 << 25 ; BCD=19
570 	 * 0x1a
571 	 * 0x1b
572 	 * 0x1c
573 	 * 0x1d
574 	 * 0x1e
575 	 * 0x1f
576 	 * 0x20 :  512 Mb =>  64 MiB => 1 << 26 ; BCD=20
577 	 * 0x21 : 1024 Mb => 128 MiB => 1 << 27 ; BCD=21
578 	 */
579 
580 	cap_code = CAD_QSPI_STIG_RDID_CAPACITYID(rdid);
581 
582 	if (!(((cap_code >> 4) > 0x9) || ((cap_code & 0xf) > 0x9))) {
583 		uint32_t decoded_cap = ((cap_code >> 4) * 10) +
584 					(cap_code & 0xf);
585 		qspi_device_size = 1 << (decoded_cap + 6);
586 		INFO("QSPI Capacity: %x\n\n", qspi_device_size);
587 
588 	} else {
589 		ERROR("Invalid CapacityID encountered: 0x%02x\n",
590 				cap_code);
591 		return -1;
592 	}
593 
594 	cad_qspi_configure_dev_size(INTEL_QSPI_ADDR_BYTES,
595 				INTEL_QSPI_BYTES_PER_DEV,
596 				INTEL_BYTES_PER_BLOCK);
597 
598 	INFO("Flash size: %d Bytes\n", qspi_device_size);
599 
600 	return status;
601 }
602 
603 int cad_qspi_indirect_page_bound_write(uint32_t offset,
604 		uint8_t *buffer, uint32_t len)
605 {
606 	int status = 0, i;
607 	uint32_t write_count, write_capacity, *write_data, space,
608 		write_fill_level, sram_partition;
609 
610 	status = cad_qspi_indirect_write_start_bank(offset, len);
611 	if (status != 0)
612 		return status;
613 
614 	write_count = 0;
615 	sram_partition = CAD_QSPI_SRAMPART_ADDR(mmio_read_32(CAD_QSPI_OFFSET +
616 			 CAD_QSPI_SRAMPART));
617 	write_capacity = (uint32_t) CAD_QSPI_SRAM_FIFO_ENTRY_COUNT -
618 			sram_partition;
619 
620 	while (write_count < len) {
621 		write_fill_level = CAD_QSPI_SRAMFILL_INDWRPART(
622 					mmio_read_32(CAD_QSPI_OFFSET +
623 							CAD_QSPI_SRAMFILL));
624 		space = LESS(write_capacity - write_fill_level,
625 				(len - write_count) / sizeof(uint32_t));
626 		write_data = (uint32_t *)(buffer + write_count);
627 		for (i = 0; i < space; ++i)
628 			mmio_write_32(CAD_QSPIDATA_OFST, *write_data++);
629 
630 		write_count += space * sizeof(uint32_t);
631 	}
632 	return cad_qspi_indirect_write_finish();
633 }
634 
635 int cad_qspi_read_bank(uint8_t *buffer, uint32_t offset, uint32_t size)
636 {
637 	int status;
638 	uint32_t read_count = 0;
639 	int level = 1, count = 0, i;
640 	uint8_t *read_data;
641 
642 	status = cad_qspi_indirect_read_start_bank(offset, size);
643 
644 	if (status != 0)
645 		return status;
646 
647 	while (read_count < size) {
648 		do {
649 			level = CAD_QSPI_SRAMFILL_INDRDPART(
650 				mmio_read_32(CAD_QSPI_OFFSET +
651 					CAD_QSPI_SRAMFILL));
652 			read_data = (uint8_t *)(buffer + read_count);
653 			for (i = 0; i < level; ++i)
654 				*read_data++ = mmio_read_8(CAD_QSPIDATA_OFST);
655 
656 			read_count += level * sizeof(uint8_t);
657 			count++;
658 #if ARM_LINUX_KERNEL_AS_BL33
659 			watchdog_sw_rst();
660 #endif
661 		} while (level > 0);
662 	}
663 
664 	return 0;
665 }
666 
667 int cad_qspi_write_bank(uint32_t offset, uint8_t *buffer, uint32_t size)
668 {
669 	int status = 0;
670 	uint32_t page_offset  = offset & (CAD_QSPI_PAGE_SIZE - 1);
671 	uint32_t write_size = LESS(size, CAD_QSPI_PAGE_SIZE - page_offset);
672 
673 	while (size) {
674 		status = cad_qspi_indirect_page_bound_write(offset, buffer,
675 							write_size);
676 		if (status != 0)
677 			break;
678 
679 		offset  += write_size;
680 		buffer  += write_size;
681 		size -= write_size;
682 		write_size = LESS(size, CAD_QSPI_PAGE_SIZE);
683 	}
684 	return status;
685 }
686 
687 int cad_qspi_read(void *buffer, uint32_t  offset, uint32_t  size)
688 {
689 	uint32_t bank_count, bank_addr, bank_offset, copy_len;
690 	uint8_t *read_data;
691 	int i, status;
692 
693 	status = 0;
694 
695 	if ((offset >= qspi_device_size) ||
696 			(offset + size - 1 >= qspi_device_size) ||
697 			(size == 0)) {
698 		ERROR("Invalid read parameter\n");
699 		return -1;
700 	}
701 
702 	if (CAD_QSPI_INDRD_RD_STAT(mmio_read_32(CAD_QSPI_OFFSET +
703 						CAD_QSPI_INDRD))) {
704 		ERROR("Read in progress\n");
705 		return -1;
706 	}
707 
708 	/*
709 	 * bank_count : Number of bank(s) affected, including partial banks.
710 	 * bank_addr  : Aligned address of the first bank,
711 	 *		including partial bank.
712 	 * bank_ofst  : The offset of the bank to read.
713 	 *		Only used when reading the first bank.
714 	 */
715 	bank_count = CAD_QSPI_BANK_ADDR(offset + size - 1) -
716 			CAD_QSPI_BANK_ADDR(offset) + 1;
717 	bank_addr  = offset & CAD_QSPI_BANK_ADDR_MSK;
718 	bank_offset  = offset & (CAD_QSPI_BANK_SIZE - 1);
719 
720 	read_data = (uint8_t *)buffer;
721 
722 	copy_len = LESS(size, CAD_QSPI_BANK_SIZE - bank_offset);
723 
724 	for (i = 0; i < bank_count; ++i) {
725 		status = cad_qspi_device_bank_select(CAD_QSPI_BANK_ADDR(
726 								bank_addr));
727 		if (status != 0)
728 			break;
729 		status = cad_qspi_read_bank(read_data, bank_offset, copy_len);
730 		if (status != 0)
731 			break;
732 
733 		bank_addr += CAD_QSPI_BANK_SIZE;
734 		read_data += copy_len;
735 		size -= copy_len;
736 		bank_offset = 0;
737 		copy_len = LESS(size, CAD_QSPI_BANK_SIZE);
738 	}
739 
740 	return status;
741 }
742 
743 int cad_qspi_erase(uint32_t offset, uint32_t size)
744 {
745 	int status = 0;
746 	uint32_t subsector_offset  = offset & (CAD_QSPI_SUBSECTOR_SIZE - 1);
747 	uint32_t erase_size = LESS(size,
748 				CAD_QSPI_SUBSECTOR_SIZE - subsector_offset);
749 
750 	while (size) {
751 		status = cad_qspi_erase_subsector(offset);
752 		if (status != 0)
753 			break;
754 
755 		offset  += erase_size;
756 		size -= erase_size;
757 		erase_size = LESS(size, CAD_QSPI_SUBSECTOR_SIZE);
758 	}
759 	return status;
760 }
761 
762 int cad_qspi_write(void *buffer, uint32_t offset, uint32_t size)
763 {
764 	int status, i;
765 	uint32_t bank_count, bank_addr, bank_offset, copy_len;
766 	uint8_t *write_data;
767 
768 	status = 0;
769 
770 	if ((offset >= qspi_device_size) ||
771 			(offset + size - 1 >= qspi_device_size) ||
772 			(size == 0)) {
773 		return -2;
774 	}
775 
776 	if (CAD_QSPI_INDWR_RDSTAT(mmio_read_32(CAD_QSPI_OFFSET +
777 						CAD_QSPI_INDWR))) {
778 		ERROR("QSPI Error: Write in progress\n");
779 		return -1;
780 	}
781 
782 	bank_count = CAD_QSPI_BANK_ADDR(offset + size - 1) -
783 			CAD_QSPI_BANK_ADDR(offset) + 1;
784 	bank_addr = offset & CAD_QSPI_BANK_ADDR_MSK;
785 	bank_offset = offset & (CAD_QSPI_BANK_SIZE - 1);
786 
787 	write_data = buffer;
788 
789 	copy_len = LESS(size, CAD_QSPI_BANK_SIZE - bank_offset);
790 
791 	for (i = 0; i < bank_count; ++i) {
792 		status = cad_qspi_device_bank_select(
793 				CAD_QSPI_BANK_ADDR(bank_addr));
794 		if (status != 0)
795 			break;
796 
797 		status = cad_qspi_write_bank(bank_offset, write_data,
798 						copy_len);
799 		if (status != 0)
800 			break;
801 
802 		bank_addr += CAD_QSPI_BANK_SIZE;
803 		write_data += copy_len;
804 		size -= copy_len;
805 		bank_offset = 0;
806 
807 		copy_len = LESS(size, CAD_QSPI_BANK_SIZE);
808 	}
809 	return status;
810 }
811 
812 int cad_qspi_update(void *Buffer, uint32_t offset, uint32_t size)
813 {
814 	int status = 0;
815 
816 	status = cad_qspi_erase(offset, size);
817 	if (status != 0)
818 		return status;
819 
820 	return cad_qspi_write(Buffer, offset, size);
821 }
822 
823 void cad_qspi_reset(void)
824 {
825 	cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_RESET_EN, 0);
826 	cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_RESET_MEM, 0);
827 }
828 
829