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