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