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