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
cad_qspi_idle(void)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
cad_qspi_set_baudrate_div(uint32_t div)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
cad_qspi_configure_dev_size(uint32_t addr_bytes,uint32_t bytes_per_dev,uint32_t bytes_per_block)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
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)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
cad_qspi_set_write_config(uint32_t opcode,uint32_t addr_type,uint32_t data_type,uint32_t dummy_clk_cycle)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
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)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
cad_qspi_stig_cmd_helper(int cs,uint32_t cmd)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
cad_qspi_stig_cmd(uint32_t opcode,uint32_t dummy)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
cad_qspi_stig_read_cmd(uint32_t opcode,uint32_t dummy,uint32_t num_bytes,uint32_t * output)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
cad_qspi_stig_wr_cmd(uint32_t opcode,uint32_t dummy,uint32_t num_bytes,uint32_t * input)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
cad_qspi_stig_addr_cmd(uint32_t opcode,uint32_t dummy,uint32_t addr)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
cad_qspi_device_bank_select(uint32_t bank)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
cad_qspi_device_status(uint32_t * status)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
cad_qspi_n25q_enable(void)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
cad_qspi_n25q_wait_for_program_and_erase(int program_only)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
cad_qspi_indirect_read_start_bank(uint32_t flash_addr,uint32_t num_bytes)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
cad_qspi_indirect_write_start_bank(uint32_t flash_addr,uint32_t num_bytes)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
cad_qspi_indirect_write_finish(void)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
cad_qspi_enable(void)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
cad_qspi_enable_subsector_bank(uint32_t addr)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
cad_qspi_erase_subsector(uint32_t addr)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
cad_qspi_erase_sector(uint32_t addr)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
cad_qspi_calibration(uint32_t dev_clk,uint32_t qspi_clk_mhz)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
cad_qspi_int_disable(uint32_t mask)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
cad_qspi_set_chip_select(int cs)502 void cad_qspi_set_chip_select(int cs)
503 {
504 cad_qspi_cs = cs;
505 }
506
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)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
cad_qspi_indirect_page_bound_write(uint32_t offset,uint8_t * buffer,uint32_t len)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
cad_qspi_read_bank(uint8_t * buffer,uint32_t offset,uint32_t size)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
cad_qspi_write_bank(uint32_t offset,uint8_t * buffer,uint32_t size)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
cad_qspi_read(void * buffer,uint32_t offset,uint32_t size)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
cad_qspi_erase(uint32_t offset,uint32_t size)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
cad_qspi_write(void * buffer,uint32_t offset,uint32_t size)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
cad_qspi_update(void * Buffer,uint32_t offset,uint32_t size)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
cad_qspi_reset(void)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