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