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