1 /*
2 * Copyright (c) 2022 ASR Microelectronics (Shanghai) Co., Ltd. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdlib.h>
17 #include <string.h>
18 #include "duet_flash_alg.h" // FlashOS Structures
19 #include "duet_cm4.h"
20 #include "duet.h"
21
duet_flash_alg_cache_flush(void)22 FLASH_DRIVER_SEG void duet_flash_alg_cache_flush(void)
23 {
24 SCB_InvalidateICache();
25 SCB_InvalidateDCache();
26 }
27
duet_flash_alg_cache_flush_by_Addr(uint32_t * addr,int32_t dsize)28 FLASH_DRIVER_SEG void duet_flash_alg_cache_flush_by_Addr(uint32_t *addr, int32_t dsize)
29 {
30 if (dsize < 0x4000) {
31 uint32_t off_set = (uint32_t)addr & 0x1F;
32 addr -= off_set;
33 dsize += off_set;
34 SCB_InvalidateDCache_by_Addr(addr, dsize);
35 } else {
36 SCB_InvalidateDCache();
37 }
38 }
39
duet_flash_alg_f_delay(unsigned char cycle)40 FLASH_DRIVER_SEG void duet_flash_alg_f_delay(unsigned char cycle)
41 {
42 while (cycle--) {
43 __asm("nop");
44 }
45 }
46
duet_flash_alg_check_busy(void)47 FLASH_DRIVER_SEG int duet_flash_alg_check_busy (void)
48 {
49
50 int var_rdata = 0;
51 int cnt = 0;
52 /* Add your Code */
53 var_rdata = FLASH->QSPI_SR; // read back
54
55 while (((var_rdata >> 5) & 0x01) == 1) {
56 var_rdata = FLASH->QSPI_SR; // read back
57 if (cnt < 80000000) { // erase chip time(10s)/(160MHz*2cycle)
58 cnt = cnt + 1;
59 } else {
60 return (1);
61 }
62 }
63
64 return (0); // Finished without Errors
65 }
66
duet_flash_alg_check_abort_busy(void)67 FLASH_DRIVER_SEG int duet_flash_alg_check_abort_busy (void)
68 {
69 int var_rdata = 0;
70 int cnt = 0;
71 /* Add your Code */
72 var_rdata = FLASH->QSPI_SR; // read back
73
74 while (((var_rdata >> 6) & 0x01) == 1) {
75 var_rdata = FLASH->QSPI_SR; // read back
76 if (cnt < 200) { // /160MHz*10cycled
77 cnt = cnt + 1;
78 } else {
79 return (1);
80 }
81 }
82
83 return (0); // Finished without Errors
84 }
85
duet_flash_alg_clr_flg(void)86 FLASH_DRIVER_SEG int duet_flash_alg_clr_flg (void)
87 {
88 /* Add your Code */
89 FLASH->QSPI_FCR = 0xF001B; // 0x1F;
90 FLASH->QSPI_FCR = 0x0;
91
92 return (0); // Finished without Errors
93 }
94
duet_flash_alg_abort_en(void)95 FLASH_DRIVER_SEG int duet_flash_alg_abort_en (void)
96 {
97 /* Add your Code */
98 int var_rdata;
99 var_rdata = FLASH->QSPI_CR;
100 FLASH->QSPI_CR = (var_rdata & 0xFFFFFFFD) + 0x2;
101 FLASH->QSPI_CR = var_rdata & 0xFFFFFFFD;
102
103 return (0); // Finished without Errors
104 }
105
duet_flash_alg_polling_wip(void)106 FLASH_DRIVER_SEG int duet_flash_alg_polling_wip (void)
107 {
108
109 int var_rdata = 0;
110 // dumode=2'b00,fmode=2'b10,dmode=2'b01,reserved=1'b0,dcyc=5'h0,absize=2'b00,abmode=2'b00,adsize=2'b00,admode=2'b00,imode=2'b01,instruction=8'h05;
111 FLASH->QSPI_CCR = 0x9000105;
112 var_rdata = FLASH->QSPI_CR;
113 FLASH->QSPI_CR = (var_rdata & 0xFFBFFFFF) + 0x400000; // QSPI_CR[22],apms= 1'b1;
114 FLASH->QSPI_DLR = 0x0; // one byte
115 FLASH->QSPI_PSMKR = 0x1; // mask = 0x1;
116 FLASH->QSPI_PSMAR = 0x0; // match = 0x0;
117 FLASH->SBUS_START = 0x1;
118 duet_flash_alg_f_delay(10);
119 duet_flash_alg_check_busy();
120 duet_flash_alg_clr_flg();
121
122 return (0); // Finished without Errors
123 }
124
duet_flash_alg_polling_wel(void)125 FLASH_DRIVER_SEG int duet_flash_alg_polling_wel (void)
126 {
127 int var_rdata = 0;
128 // dumode=2'b00,fmode=2'b10,dmode=2'b01,reserved=1'b0,dcyc=5'h0,absize=2'b00,abmode=2'b00,adsize=2'b00,admode=2'b00,imode=2'b01,instruction=8'h05;
129 FLASH->QSPI_CCR = 0x9000105;
130 var_rdata = FLASH->QSPI_CR;
131 FLASH->QSPI_CR = (var_rdata & 0xFFBFFFFF) + 0x400000; // QSPI_CR[22],apms= 1'b1;
132 FLASH->QSPI_DLR = 0x0; // one byte
133 FLASH->QSPI_PSMKR = 0x2; // mask = 0x1;
134 FLASH->QSPI_PSMAR = 0x2; // match = 0x0;
135 FLASH->SBUS_START = 0x1;
136 duet_flash_alg_f_delay(10);
137 duet_flash_alg_check_busy();
138 duet_flash_alg_clr_flg();
139
140 return (0); // Finished without Errors
141 }
142
duet_flash_alg_setqe(unsigned char quad)143 FLASH_DRIVER_SEG int duet_flash_alg_setqe (unsigned char quad)
144 {
145
146 // bypass enable 0x4000308C bit10 set 1
147 // *((volatile unsigned int *)(0x4000308C)) |= (1 << 10);
148 FLASH->QSPI_CFGR |= (1 << 10);
149 duet_flash_alg_abort_en();
150 duet_flash_alg_check_abort_busy();
151
152 FLASH->QSPI_CCR = 0x106; // IMODE=2'b01,INSTRUCTION=WREN
153 duet_flash_alg_clr_flg();
154 FLASH->SBUS_START = 0x1;
155 duet_flash_alg_f_delay(10);
156 duet_flash_alg_check_busy();
157 duet_flash_alg_polling_wel();
158
159 FLASH->QSPI_CCR =
160 0x01000101; // dumode=2'b00,fmode=2'b00,dmode=2'b01,reserved=1'b0,dcyc=5'h0,absize=2'b00,abmode=2'b00,adsize=2'b00,admode=2'b00,imode=2'b01,instruction=8'h01;
161 FLASH->QSPI_DLR = 0x1; // two byte
162 if (quad == 0x1) {
163 FLASH->QSPI_DR = 0x200;
164 } else {
165 FLASH->QSPI_DR = 0x0; // 0x200;
166 }
167 duet_flash_alg_clr_flg();
168 FLASH->SBUS_START = 0x1;
169 duet_flash_alg_f_delay(10);
170 duet_flash_alg_check_busy();
171 duet_flash_alg_clr_flg();
172 duet_flash_alg_polling_wip();
173 // bypass disable 0x4000308C bit10 clr
174 // *((volatile unsigned int *)(0x4000308C)) &= ~(1 << 10);
175 FLASH->QSPI_CFGR &= ~(1 << 10);
176 /* Add your Code */
177
178 return (0); // Finished without Errors
179 }
180
181 // use in unencryption
duet_flash_alg_check_setqe(void)182 FLASH_DRIVER_SEG int duet_flash_alg_check_setqe (void)
183 {
184
185 volatile int var_rdata = 0;
186
187 duet_flash_alg_abort_en();
188 duet_flash_alg_check_abort_busy();
189 duet_flash_alg_check_busy();
190 FLASH->QSPI_DLR = 0x0;
191 FLASH->QSPI_CCR =
192 0x5000135; // dumode=2'b00,fmode=2'b01,dmode=2'b01,reserved=1'b0,dcyc=5'h0,absize=2'b00,abmode=2'b00,adsize=2'b00,admode=2'b00,imode=2'b01,instruction=8'h35;
193 duet_flash_alg_clr_flg();
194 FLASH->SBUS_START = 0x1;
195 duet_flash_alg_f_delay(10);
196 duet_flash_alg_check_busy();
197 var_rdata = FLASH->QSPI_DR & 0xFF;
198 return var_rdata;
199 }
200
201 vu32 duet_flash_line_cfg = 0; // flash line number config
202 vu32 duet_flash_size_cfg = 0; // flash size config
203 vu32 duet_flash_clk_cfg = 52; // flash clock config, default 52MHz
duet_flash_alg_load_cfg(void)204 FLASH_DRIVER_SEG void duet_flash_alg_load_cfg (void)
205 {
206
207 duet_flash_alg_abort_en();
208 duet_flash_alg_check_abort_busy();
209 #ifdef _SPI_FLASH_240MHz_
210 if (duet_flash_clk_cfg == 240) {
211 FLASH->QSPI_CR = FLASH_QSPI_DIV3; // div3, // offset 0x00
212 FLASH->QSPI_CR |= 0x20; // set loop back en bit 5=1
213 FLASH->QSPI_CR &= ~(7 << 13);
214 FLASH->QSPI_CR |= (5 << 13); // ds = 5
215
216 FLASH->QSPI_DCR = 0x00150000 ; // offset 0x04
217 FLASH->QSPI_FCR = 0x0 ; // offset 0x0C
218 FLASH->QSPI_DLR = 0x0 ; // offset 0x10
219 FLASH->QSPI_CCR =
220 duet_flash_line_cfg; // dumode=2'b10,,sio=1'b0,fmode=2'b11,dmode=2'b10,reserved=1'b0,dcyc=5'h7,absize=2'b00,abmode=2'b00,adsize=2'b10,admode=2'b01,imode=2'b01,instruction=8'h3B;
221 FLASH->QSPI_AR = 0x0 ; // offset 0x18
222 FLASH->QSPI_ABR = 0x0 ; // offset 0x1C
223 FLASH->QSPI_DR = 0x0 ; // offset 0x20
224 FLASH->QSPI_PSMKR = 0x0 ; // offset 0x24
225 FLASH->QSPI_PSMAR = 0x0 ; // offset 0x28
226 FLASH->QSPI_PIR = 0x0 ; // offset 0x2C
227 FLASH->QSPI_TOR = 0x12FFFF ; // offset 0x30
228 FLASH->QSPI_CFGR = 0x7202; // offset 0x8C [15:12] set loop back delay=7
229 } else
230 #endif
231 {
232 FLASH->QSPI_CR = FLASH_QSPI_DIV2; // div2, // offset 0x00
233 FLASH->QSPI_DCR = 0x00150000 ; // offset 0x04
234 FLASH->QSPI_FCR = 0x0 ; // offset 0x0C
235 FLASH->QSPI_DLR = 0x0 ; // offset 0x10
236 FLASH->QSPI_CCR =
237 duet_flash_line_cfg; // dumode=2'b10,,sio=1'b0,fmode=2'b11,dmode=2'b10,reserved=1'b0,dcyc=5'h7,absize=2'b00,abmode=2'b00,adsize=2'b10,admode=2'b01,imode=2'b01,instruction=8'h3B;
238 FLASH->QSPI_AR = 0x0 ; // offset 0x18
239 FLASH->QSPI_ABR = 0x0 ; // offset 0x1C
240 FLASH->QSPI_DR = 0x0 ; // offset 0x20
241 FLASH->QSPI_PSMKR = 0x0 ; // offset 0x24
242 FLASH->QSPI_PSMAR = 0x0 ; // offset 0x28
243 FLASH->QSPI_PIR = 0x0 ; // offset 0x2C
244 FLASH->QSPI_TOR = 0x12FFFF ; // offset 0x30
245 FLASH->QSPI_CFGR = 0x202 ; // offset 0x8C bit1:direct access optimization enable
246 }
247
248 }
249
250 // flash crypt bypass test
duet_flash_alg_init(void)251 FLASH_DRIVER_SEG int duet_flash_alg_init (void)
252 {
253
254 // add delay to avoid confilict between flash cfg and instruction fetch by cache
255 duet_flash_alg_f_delay(32);
256 duet_flash_line_cfg = FLASH_QSPI_L4; // config flash line here
257 duet_flash_size_cfg = FLASH_QSPI_DCR_4M; // config flash size here
258 duet_flash_alg_abort_en();
259 duet_flash_alg_check_abort_busy();
260 if (duet_flash_line_cfg == FLASH_QSPI_L4) {
261 duet_flash_alg_setqe(1);
262 } else {
263 duet_flash_alg_setqe(0);
264 }
265
266 duet_flash_alg_load_cfg();
267
268 // flush cache after flash operation
269 duet_flash_alg_cache_flush();
270
271 return (0); // Finished without Errors
272 }
273
274 /*
275 * cmd: CHIP_ERASE_CMD or SECTOR_ERASE_CMD or BLOCK32_ERASE_CMD or BLOCK64_ERASE_CMD
276 * adr: not used for CHIP_ERASE_CMD
277 */
duet_flash_alg_erase(unsigned int cmd,unsigned long adr)278 FLASH_DRIVER_SEG int duet_flash_alg_erase(unsigned int cmd, unsigned long adr)
279 {
280
281 // add delay to avoid confilict between flash cfg and instruction fetch by cache
282 duet_flash_alg_f_delay(32);
283
284 duet_flash_alg_abort_en();
285 duet_flash_alg_check_abort_busy();
286
287 FLASH->QSPI_CCR = 0x106; // IMODE=2'b01,INSTRUCTION=WREN
288 duet_flash_alg_clr_flg();
289 FLASH->SBUS_START = 0x1;
290 duet_flash_alg_f_delay(10);
291 duet_flash_alg_check_busy();
292 duet_flash_alg_polling_wel();
293
294 FLASH->QSPI_CCR = cmd;
295 if (CHIP_ERASE_CMD != cmd) {
296 FLASH->QSPI_AR = adr;
297 }
298 duet_flash_alg_clr_flg();
299 FLASH->SBUS_START = 0x1;
300 duet_flash_alg_f_delay(10);
301 duet_flash_alg_check_busy();
302 duet_flash_alg_clr_flg();
303 duet_flash_alg_polling_wip();
304 duet_flash_alg_f_delay(10);
305 duet_flash_alg_clr_flg();
306 duet_flash_alg_load_cfg();
307
308 // flush cache after flash operation
309 duet_flash_alg_cache_flush();
310 /* Add your Code */
311
312 return (0); // Finished without Errors
313 }
314
315 /*
316 * Program Page in Flash Memory
317 * Parameter: adr: Page Start Address
318 * sz: Page Size
319 * buf: Page Data
320 * Return Value: 0 - OK, 1 - Failed
321 */
322
duet_flash_alg_programpage(unsigned long adr,unsigned long sz,unsigned char * buf)323 FLASH_DRIVER_SEG int duet_flash_alg_programpage(unsigned long adr, unsigned long sz, unsigned char *buf)
324 {
325
326 unsigned long sz_temp;
327 // volatile int cycle_count = 0;
328 int var_rdata = 0;
329 int fthres = 8;
330 int cnt = 0;
331 unsigned long ram_buf[SPI_FLASH_PAGE_SIZE / 4] = {0};
332
333 if ((0 == sz) || (NULL == buf)) {
334 return 1;
335 }
336
337 if (((uint32_t)buf >= SPI_FLASH_ADDR_START && (uint32_t)buf <= SPI_FLASH_ADDR_END) || ((uint32_t)buf & 0x3)) {
338 memcpy(ram_buf, buf, sz);
339 buf = (unsigned char *)ram_buf;
340 }
341
342 sz_temp = sz - 1;
343 sz = (sz + 3) & ~3; // Adjust size for Words
344
345 // add delay to avoid confilict between flash cfg and instruction fetch by cache
346 duet_flash_alg_f_delay(32);
347
348 duet_flash_alg_abort_en();
349 duet_flash_alg_check_abort_busy();
350
351 FLASH->QSPI_CCR = 0x106; // IMODE=2'b01,INSTRUCTION=WREN
352 duet_flash_alg_clr_flg();
353 FLASH->SBUS_START = 0x1;
354 duet_flash_alg_f_delay(10);
355 duet_flash_alg_check_busy();
356 duet_flash_alg_polling_wel();
357
358 FLASH->QSPI_CCR =
359 0x1002502; // fmode=2'b00,dmode=2'b01,reserved=1'b0,dcyc=5'h0,absize=2'b00,abmode=2'b00,adsize=2'b10,admode=2'b01,imode=2'b01,instruction=8'h02;
360 FLASH->QSPI_DLR = sz_temp;
361 FLASH->QSPI_AR = adr;
362 while ((sz > 0) && (cnt < fthres)) {
363 var_rdata = FLASH->QSPI_SR;
364 var_rdata = (var_rdata >> 8) & 0x3F;
365 if (var_rdata < fthres) {
366 FLASH->QSPI_DR = *((unsigned long *)buf); // Program Word
367 cnt += 1;
368 buf += 4;
369 sz -= 4;
370 }
371 }
372 duet_flash_alg_f_delay(10);
373 duet_flash_alg_check_busy();
374 FLASH->SBUS_START = 0x01; // WRITE
375 duet_flash_alg_f_delay(10);
376 while (sz) {
377 var_rdata = FLASH->QSPI_SR;
378 var_rdata = (var_rdata >> 8) & 0x3F;
379 if (var_rdata < fthres) {
380 FLASH->QSPI_DR = *((unsigned long *)buf); // Program Word
381 buf += 4;
382 sz -= 4;
383 }
384 }
385 duet_flash_alg_f_delay(10);
386 duet_flash_alg_check_busy();
387 duet_flash_alg_polling_wip();
388 duet_flash_alg_load_cfg ();
389
390 // flush cache after flash operation
391 // lega_flash_alg_cache_flush_by_Addr(adr,sz);
392 duet_flash_alg_cache_flush();
393
394 return (0); // Finished without Errors
395 }
396
duet_flash_alg_read_buf_clr(void)397 FLASH_DRIVER_SEG void duet_flash_alg_read_buf_clr(void)
398 {
399
400 #if 0
401 unsigned int tmp = REG_RD(FLASH_BASE);
402 REG_WR(FLASH_BASE, tmp & (~0x1));
403 REG_WR(FLASH_BASE, tmp);
404 #else
405 unsigned int tmp = FLASH->QSPI_CR;
406 FLASH->QSPI_CR = tmp & (~0x1);
407 FLASH->QSPI_CR = tmp;
408 #endif
409
410 }
411
412 #ifdef _SPI_FLASH_120MHz_
duet_flash_alg_set_clk_120(unsigned char en_120m)413 FLASH_DRIVER_SEG void duet_flash_alg_set_clk_120(unsigned char en_120m)
414 {
415 if (en_120m) {
416 // flash clock is source/4
417 REG_WR(APB_PERI_CLK_CTRL_REG, ((REG_RD(APB_PERI_CLK_CTRL_REG) & ~(0x3)) | 0x2));
418 // switch flash clock source to RF 480M
419 REG_WR(WIFI_BLE_FLASH_CLK_CTRL_REG, (REG_RD(WIFI_BLE_FLASH_CLK_CTRL_REG) | (1 << 7)));
420 } else {
421 // switch flash clock source to XO 52M
422 REG_WR(WIFI_BLE_FLASH_CLK_CTRL_REG, (REG_RD(WIFI_BLE_FLASH_CLK_CTRL_REG) & (~(1 << 7))));
423 }
424 }
425 #endif
426
427 #ifdef _SPI_FLASH_240MHz_
duet_flash_alg_set_clk_240(unsigned char en_240m)428 FLASH_DRIVER_SEG void duet_flash_alg_set_clk_240(unsigned char en_240m)
429 {
430 if (en_240m) {
431 duet_flash_clk_cfg = 240;
432 duet_flash_alg_load_cfg();
433 duet_flash_alg_cache_flush();
434
435 // 0x0:flash clock = source APLL 480MHZ / 2
436 REG_WR(APB_PERI_CLK_CTRL_REG, ((REG_RD(APB_PERI_CLK_CTRL_REG) & ~(0x3)) | 0x0));
437 // switch flash clock source to RF 480M
438 REG_WR(WIFI_BLE_FLASH_CLK_CTRL_REG, (REG_RD(WIFI_BLE_FLASH_CLK_CTRL_REG) | (1 << 7)));
439 } else {
440 // switch flash clock source to XO 52M
441 REG_WR(WIFI_BLE_FLASH_CLK_CTRL_REG, (REG_RD(WIFI_BLE_FLASH_CLK_CTRL_REG) & (~(1 << 7))));
442
443 duet_flash_clk_cfg = 52;
444 duet_flash_alg_load_cfg();
445 duet_flash_alg_cache_flush();
446 }
447
448 }
449
450 #if 0
451 FLASH_DRIVER_SEG int duet_flash_alg_read_id(void)
452 {
453
454 int var_rdata;
455 int dshift;
456 duet_flash_alg_abort_en();
457 duet_flash_alg_check_abort_busy();
458
459 FLASH->QSPI_CCR =
460 0x500019F; // fmode=2'b01,dmode=2'b01,reserved=1'b0,dcyc=5'h0,absize=2'b00,abmode=2'b00,adsize=2'b00,admode=2'b00,imode=2'b01,instruction=8'h9F;
461 FLASH->QSPI_DLR = 0x2;
462 duet_flash_alg_clr_flg();
463 FLASH->SBUS_START = 0x1;
464
465 duet_flash_alg_f_delay(10);
466 duet_flash_alg_check_busy();
467 var_rdata = FLASH->QSPI_CR;
468 dshift = (var_rdata >> 13) & 0x7;
469 duet_flash_alg_f_delay(dshift);
470
471 var_rdata = FLASH->QSPI_DR;
472
473 duet_flash_alg_load_cfg();
474 return (var_rdata);
475
476 }
477
478 FLASH_DRIVER_SEG void duet_flash_alg_calibrate_shift(int prescaler)
479 {
480 volatile int delay_shift = 0;
481 volatile int sshift = 0;
482 unsigned int rdata;
483 unsigned int wdata;
484 unsigned int identi;
485 volatile int id, mem_type, capacity;
486 int i = 0;
487 int sshift_max[8] = {0};
488 int sshift_min[8] = {0};
489 int match_flag[8] = {0};
490 int match_interval[8] = {0};
491
492 // *(volatile int *)(0x40000808) = 0x2;
493 REG_WR(CLK_FLASH_SEL, FLASH_240_CLK);
494
495 for (delay_shift = 0; delay_shift < 8; delay_shift = delay_shift + 1) {
496 sshift_max[delay_shift] = 0;
497 sshift_min[delay_shift] = 0;
498 for (sshift = 0; sshift < prescaler; sshift = sshift + 1) {
499 rdata = FLASH->QSPI_CR;
500 wdata = rdata & 0x87FF1FFF;
501 wdata |= (sshift & 0xF) << 27;
502 wdata |= (delay_shift & 0x7) << 13;
503 FLASH->QSPI_CR = wdata;
504 // read_id
505 identi = duet_flash_alg_read_id();
506
507 id = identi & 0xFF;
508 mem_type = (identi & 0xFF00) >> 8;
509 capacity = (identi & 0xFF0000) >> 16;
510
511 if (id == 0x0B && mem_type == 0x40 && capacity == 0x15) {
512 match_flag[delay_shift] = 0x1;
513 if (sshift_max[delay_shift] < sshift) {
514 sshift_max[delay_shift] = sshift;
515 }
516 if (sshift_min[delay_shift] > sshift) {
517 sshift_min[delay_shift] = sshift;
518 }
519 } else {
520 sshift_min[delay_shift] = sshift + 1;
521 if (sshift_min[delay_shift] == prescaler) {
522 sshift_min[delay_shift] = 0;
523 }
524 }
525 }
526 }
527
528 for (i = 0; i < 8; i++) {
529 if (match_flag[i] == 1) {
530 match_interval[i] = sshift_max[i] - sshift_min[i] + 1;
531 } else {
532 match_interval[i] = 0;
533 }
534 }
535 // get the best delay_shift(means max mactch_interval
536 delay_shift = 0;
537 for (i = 1; i < 8; i = i + 1) {
538 if (match_interval[i] > match_interval[delay_shift]) {
539 delay_shift = i;
540 }
541 }
542 sshift = (sshift_max[delay_shift] + sshift_min[delay_shift]) / 2 + (sshift_max[delay_shift] + sshift_min[delay_shift]) %
543 2;
544 rdata = FLASH->QSPI_CR;
545 wdata = rdata & 0x87FF1FFF;
546 wdata |= (sshift & 0xF) << 27;
547 wdata |= (delay_shift & 0x7) << 13;
548 FLASH->QSPI_CR = wdata;
549
550 }
551 #endif
552 #endif
553