1 #include <string.h>
2 #include <stdlib.h>
3 #include <time.h>
4 #include <pthread.h>
5 #include <errno.h>
6 #include <unistd.h>
7 #include <hal_timer.h>
8 
9 #include "inter.h"
10 
11 #define NOR_CMD_READ 0x03
12 #define NOR_CMD_FAST_READ 0x0B
13 #define NOR_CMD_DUAL_READ 0x3B
14 #define NOR_CMD_QUAD_READ 0x6B
15 #define NOR_CMD_DUAL_IO_READ 0xBB
16 #define NOR_CMD_QUAD_IO_READ 0xEB
17 #define NOR_CMD_PROG 0x02
18 #define NOR_CMD_QUAD_PROG 0x32
19 #define NOR_CMD_QUAD_IO_PROG 0x38
20 #define NOR_CMD_ERASE_BLK4K 0x20
21 #define NOR_CMD_ERASE_BLK32K 0x52
22 #define NOR_CMD_ERASE_BLK64K 0xD8
23 #define NOR_CMD_ERASE_CHIP 0x60
24 #define NOR_CMD_WREN 0x06
25 #define NOR_CMD_WRDI 0x04
26 #define NOR_CMD_READ_SR 0x05
27 #define NOR_CMD_WRITE_SR 0x01
28 #define NOR_CMD_READ_CR 0x15
29 #define NOR_CMD_READ_SCUR 0x2B
30 #define NOR_CMD_RESET_EN 0x66
31 #define NOR_CMD_RESET 0x99
32 #define NOR_CMD_RDID 0x9F
33 
34 #define cmd_4bytes(cmd) (nor->addr_width == 4 ? cmd ## 4B : cmd)
35 #define NOR_CMD_EN4B 0xB7
36 #define NOR_CMD_EX4B 0xE9
37 #define NOR_CMD_MXC_EX4B 0x29
38 #define NOR_CMD_READ4B 0x13
39 #define NOR_CMD_FAST_READ4B 0x0C
40 #define NOR_CMD_DUAL_READ4B 0x3C
41 #define NOR_CMD_QUAD_READ4B 0x6C
42 #define NOR_CMD_DUAL_IO_READ4B 0xBC
43 #define NOR_CMD_QUAD_IO_READ4B 0xEC
44 #define NOR_CMD_PROG4B 0x12
45 #define NOR_CMD_QUAD_PROG4B 0x34
46 #define NOR_CMD_QUAD_IO_PROG4B 0x3E
47 #define NOR_CMD_ERASE_BLK4K4B 0x21
48 #define NOR_CMD_ERASE_BLK32K4B 0x5C
49 #define NOR_CMD_ERASE_BLK64K4B 0xDC
50 
51 #define NOR_BUSY_MASK BIT(0)
52 #define NOR_SR_BIT_WEL BIT(1)
53 
54 static struct nor_flash g_nor, *nor = &g_nor;
55 static struct nor_factory g_fhead;
56 
nor_lock_init(void)57 static inline int nor_lock_init(void)
58 {
59     nor->hal_sem = hal_sem_create(1);
60     if (!nor->hal_sem) {
61         SPINOR_ERR("create hal_sem lock for nor_flash failed");
62         return -1;
63     }
64     return 0;
65 }
66 
nor_lock(void)67 static inline int nor_lock(void)
68 {
69     return hal_sem_wait(nor->hal_sem);
70 }
71 
nor_unlock(void)72 static inline int nor_unlock(void)
73 {
74     return hal_sem_post(nor->hal_sem);
75 }
76 
nor_msleep(unsigned int msec)77 static inline void nor_msleep(unsigned int msec)
78 {
79     hal_usleep(msec * 1000);
80 }
81 
cmd_bit(unsigned char cmd)82 static int cmd_bit(unsigned char cmd)
83 {
84     switch (cmd)
85     {
86         case NOR_CMD_DUAL_READ:
87         case NOR_CMD_DUAL_IO_READ:
88         case NOR_CMD_DUAL_READ4B:
89         case NOR_CMD_DUAL_IO_READ4B:
90             return 2;
91         case NOR_CMD_QUAD_READ:
92         case NOR_CMD_QUAD_IO_READ:
93         case NOR_CMD_QUAD_READ4B:
94         case NOR_CMD_QUAD_IO_READ4B:
95         case NOR_CMD_QUAD_PROG:
96         case NOR_CMD_QUAD_IO_PROG:
97         case NOR_CMD_QUAD_PROG4B:
98         case NOR_CMD_QUAD_IO_PROG4B:
99             return 4;
100         default:
101             return 1;
102     }
103 }
104 
nor_register_factory(struct nor_factory * f)105 int nor_register_factory(struct nor_factory *f)
106 {
107     struct nor_factory *p = &g_fhead;
108 
109     if (!f)
110         return -1;
111 
112     while (p->next)
113         p = p->next;
114     p->next = f;
115     f->next = NULL;
116 
117     SPINOR_DEBUG("register factory 0x%x", f->factory);
118     return 0;
119 }
120 
nor_transfer(int single_len,void * tbuf,int tlen,void * rbuf,int rlen)121 int nor_transfer(int single_len, void *tbuf, int tlen, void *rbuf, int rlen)
122 {
123     hal_spi_master_transfer_t tr;
124     unsigned char cmd = *(unsigned char *)tbuf;
125     int ret;
126 
127     tr.tx_buf = tbuf;
128     tr.tx_len = tlen;
129     tr.rx_buf = rbuf;
130     tr.rx_len = rlen;
131     tr.tx_single_len = single_len;
132     tr.dummy_byte = 0;
133 
134     tr.rx_nbits = tr.tx_nbits = SPI_NBITS_SINGLE;
135     switch (cmd)
136     {
137         case NOR_CMD_FAST_READ:
138         case NOR_CMD_FAST_READ4B:
139             tr.dummy_byte = 1;
140             break;
141         case NOR_CMD_DUAL_READ:
142         case NOR_CMD_DUAL_IO_READ:
143         case NOR_CMD_DUAL_READ4B:
144         case NOR_CMD_DUAL_IO_READ4B:
145             tr.rx_nbits = SPI_NBITS_DUAL;
146             tr.dummy_byte = 1;
147             break;
148         case NOR_CMD_QUAD_READ:
149         case NOR_CMD_QUAD_IO_READ:
150         case NOR_CMD_QUAD_READ4B:
151         case NOR_CMD_QUAD_IO_READ4B:
152             tr.rx_nbits = SPI_NBITS_QUAD;
153             tr.dummy_byte = 1;
154             break;
155         case NOR_CMD_QUAD_PROG:
156         case NOR_CMD_QUAD_IO_PROG:
157         case NOR_CMD_QUAD_PROG4B:
158         case NOR_CMD_QUAD_IO_PROG4B:
159             tr.tx_nbits = SPI_NBITS_QUAD;
160             break;
161     }
162 
163     ret = hal_spi_xfer(nor->spim.port, &tr);
164     if (ret)
165         SPINOR_ERR("spi transfer failed %d", ret);
166     return ret;
167 }
168 
nor_read_status(unsigned char * sr)169 int nor_read_status(unsigned char *sr)
170 {
171     int ret;
172     char cmd[1] = {NOR_CMD_READ_SR};
173     char reg[2] = {0};
174 
175     ret = nor_transfer(1, cmd, 1, reg, 2);
176     if (ret) {
177         SPINOR_ERR("read status register fail");
178         return ret;
179     }
180 
181     *sr = reg[1];
182     return 0;
183 }
184 
nor_is_busy(void)185 static int nor_is_busy(void)
186 {
187     int ret;
188     unsigned char reg;
189 
190     ret = nor_read_status(&reg);
191     if (ret)
192         return ret;
193 
194     if (reg & NOR_BUSY_MASK)
195         return true;
196     else
197         return false;
198 }
199 
200 /**
201  * As the minimum time is 1ms, to save time, we wait ready under 2 step:
202  * 1. sleep on ms, which take mush time.
203  * 2. check times on cpu. It will be ready soon in this case
204  */
nor_wait_ready(unsigned int ms,unsigned int times)205 int nor_wait_ready(unsigned int ms, unsigned int times)
206 {
207     unsigned int _ms = ms, _times = times;
208 
209     do {
210         if (nor_is_busy() == false)
211             return 0;
212         if (_ms)
213             nor_msleep(1);
214     } while (--_ms > 0);
215 
216     do {
217         if (nor_is_busy() == false)
218             return 0;
219     } while (--_times > 0);
220 
221     /* check the last time */
222     if (nor_is_busy() == false)
223         return 0;
224 
225     SPINOR_ERR("wait nor flash for %d ms and %d loop timeout", ms, times);
226     return -EBUSY;
227 }
228 
nor_send_cmd(unsigned char cmd)229 int nor_send_cmd(unsigned char cmd)
230 {
231     int ret;
232     ret = nor_transfer(1, &cmd, 1, NULL, 0);
233     if (ret)
234         return ret;
235     return nor_wait_ready(0, 500);
236 }
237 
nor_set_4byte(int enable)238 static int nor_set_4byte(int enable)
239 {
240     int ret;
241     struct nor_factory *f = nor->factory;
242 
243     if (f && f->set_4bytes_addr)
244         return f->set_4bytes_addr(nor, enable);
245 
246     ret = nor_send_cmd(NOR_CMD_EN4B);
247     if (ret) {
248         SPINOR_ERR("set 4byte %d fail", enable);
249         return ret;
250     }
251     SPINOR_DEBUG("set 4byte %d success", enable);
252     return 0;
253 }
254 
nor_write_enable(void)255 int nor_write_enable(void)
256 {
257     int ret;
258     unsigned char sr;
259 
260     ret = nor_send_cmd(NOR_CMD_WREN);
261     if (ret) {
262         SPINOR_ERR("send WREN failed - %d", ret);
263         return ret;
264     }
265 
266     ret = nor_read_status(&sr);
267     if (ret)
268         return ret;
269 
270     if (!(sr & NOR_SR_BIT_WEL)) {
271         SPINOR_ERR("enable write failed");
272         return -EINVAL;
273     }
274     return 0;
275 }
276 
nor_write_status(unsigned char * sr,unsigned int len)277 int nor_write_status(unsigned char *sr, unsigned int len)
278 {
279     int ret, i;
280     char tbuf[5] = {0};
281 
282     ret = nor_write_enable();
283     if (ret)
284         return ret;
285 
286     if (len > 5)
287         return -EINVAL;
288 
289     tbuf[0] = NOR_CMD_WRITE_SR;
290     for (i = 0; i < len; i++)
291         tbuf[i + 1] = *(sr + i);
292     i++;
293     ret = nor_transfer(i, tbuf, i, NULL, 0);
294     if (ret) {
295         SPINOR_ERR("write status register fail");
296         return ret;
297     }
298 
299     return nor_wait_ready(10, MAX_WAIT_LOOP);
300 }
301 
nor_read_id(char * id,int len)302 static int nor_read_id(char *id, int len)
303 {
304     int ret;
305     char cmd[1] = {NOR_CMD_RDID};
306 
307     if (nor_wait_ready(0, 500)) {
308         SPINOR_ERR("nor is busy before read id");
309         return -EBUSY;
310     }
311 
312     ret = nor_transfer(1, cmd, 1, id, MIN(len, (int)MAX_ID_LEN));
313     if (ret)
314         SPINOR_ERR("read nor id failed - %d", ret);
315     return ret;
316 }
317 
nor_reset(void)318 static int nor_reset(void)
319 {
320     int ret;
321     char cmd[2] = {NOR_CMD_RESET_EN, NOR_CMD_RESET};
322 
323     ret = nor_transfer(2, cmd, 2, NULL, 0);
324     if (ret)
325         SPINOR_ERR("reset nor failed - %d", ret);
326     return ret;
327 }
328 
nor_spi_master_init(struct nor_spi_master * spim)329 static int nor_spi_master_init(struct nor_spi_master *spim)
330 {
331     int ret;
332 
333     spim->port = HAL_SPI_MASTER_0;
334 
335 #ifdef CONFIG_DRIVERS_SPINOR_FREQ
336     spim->cfg.clock_frequency = CONFIG_DRIVERS_SPINOR_FREQ;
337 #else
338     spim->cfg.clock_frequency = NOR_DEFAULT_FREQUENCY;
339 #endif
340     spim->cfg.clock_frequency *= 1000 * 1000;
341     spim->cfg.slave_port = HAL_SPI_MASTER_SLAVE_0;
342     spim->cfg.cpha = HAL_SPI_MASTER_CLOCK_PHASE0;
343     spim->cfg.cpol = HAL_SPI_MASTER_CLOCK_POLARITY0;
344     spim->cfg.bit_order = HAL_SPI_MASTER_LSB_FIRST;
345 
346     ret = hal_spi_init(spim->port, &spim->cfg);
347     if (ret != HAL_SPI_MASTER_STATUS_OK)
348         SPINOR_ERR("init spi master failed - %d", ret);
349     return ret;
350 }
351 
nor_spi_master_deinit(struct nor_spi_master * spim)352 static int nor_spi_master_deinit(struct nor_spi_master *spim)
353 {
354     return hal_spi_deinit(spim->port);
355 }
356 
match_nor(struct nor_flash * nor,char * id,int id_len)357 static int match_nor(struct nor_flash *nor, char *id, int id_len)
358 {
359     struct nor_factory *f = g_fhead.next;
360     struct nor_info *info;
361     int i;
362 
363     for (; f; f = f->next) {
364         if (f->factory != (unsigned char)id[0])
365             continue;
366         for (i = 0; i < f->idt_cnt; i++) {
367             info = &f->idt[i];
368             if (!memcmp(info->id, id, id_len)) {
369                 SPINOR_DEBUG("match nor %s on table", info->model);
370                 nor->factory = f;
371                 nor->info = info;
372                 return 0;
373             }
374         }
375         /* the factory already check all ids but not match */
376         SPINOR_ERR("not match any id on factory 0x%x ids table", f->factory);
377         return -1;
378     }
379     SPINOR_ERR("not match any factory 0x%x ids table", id[0]);
380     return -1;
381 }
382 
nor_set_quad_mode(void)383 static int nor_set_quad_mode(void)
384 {
385     if (nor->factory->set_quad_mode)
386         return nor->factory->set_quad_mode(nor);
387     return 0;
388 }
389 
nor_factory_register(void)390 static int nor_factory_register(void)
391 {
392     nor_register_factory_gd();
393     nor_register_factory_mxic();
394     nor_register_factory_winbond();
395     nor_register_factory_xtx();
396     nor_register_factory_esmt();
397     nor_register_factory_fm();
398     nor_register_factory_xmc();
399     nor_register_factory_puya();
400     nor_register_factory_zetta();
401     return 0;
402 }
403 
nor_factory_init(void)404 static int nor_factory_init(void)
405 {
406     if (nor->factory->init)
407         return nor->factory->init(nor);
408     return 0;
409 }
410 
nor_factory_deinit(void)411 static void nor_factory_deinit(void)
412 {
413     if (nor->factory->deinit)
414         nor->factory->deinit(nor);
415 }
416 
nor_scan(void)417 static int nor_scan(void)
418 {
419     int ret;
420     char id[MAX_ID_LEN];
421 
422     ret = nor_read_id(id, MAX_ID_LEN);
423     if (ret) {
424         goto err;
425     }
426     ret = match_nor(nor, id, MAX_ID_LEN);
427     if (ret)
428         goto err;
429 
430     if (nor->info->flag == 0)
431         nor->info->flag = SUPPORT_GENERAL;
432 
433     nor->total_size = nor->info->total_size;
434     nor->addr_width = 3;
435     if (nor->total_size > SZ_16M) {
436         nor->addr_width = 4;
437         nor_set_4byte(true);
438     }
439 
440     nor->page_size = NOR_PAGE_SIZE;
441 #ifdef CONFIG_DRIVERS_SPINOR_4K_SECTORS
442     nor->blk_size = SZ_4K;
443 #else
444     if (nor->info->flag & SUPPORT_64K_ERASE_BLK) {
445         nor->blk_size = NOR_BLK_SIZE;
446     } else if (nor->info->flag & SUPPORT_32K_ERASE_BLK) {
447         nor->blk_size = NOR_HALF_BLK_SIZE;
448     } else if (nor->info->flag & SUPPORT_4K_ERASE_BLK) {
449         nor->blk_size = NOR_PAGE_SIZE;
450     } else {
451         SPINOR_ERR("invalid blk size");
452         ret = -EINVAL;
453         goto err;
454     }
455 #endif
456 
457     /* program property */
458     nor->w_cmd_slen = nor->addr_width == 4 ? 5 : 4;
459     nor->cmd_write = cmd_4bytes(NOR_CMD_PROG);
460     if (nor->info->flag & SUPPORT_QUAD_WRITE) {
461         nor->cmd_write = cmd_4bytes(NOR_CMD_QUAD_PROG);
462         if (nor->info->flag & USE_IO_PROG_X4) {
463             nor->cmd_write = cmd_4bytes(NOR_CMD_QUAD_IO_PROG);
464             nor->w_cmd_slen = 1;
465         }
466     }
467 
468     /* read property */
469     nor->r_cmd_slen = nor->addr_width == 4 ? 6 : 5;
470     nor->cmd_read = cmd_4bytes(NOR_CMD_FAST_READ);
471     if (nor->info->flag & SUPPORT_QUAD_READ) {
472         nor->cmd_read = cmd_4bytes(NOR_CMD_QUAD_READ);
473         if (nor->info->flag & USE_IO_READ_X4) {
474             nor->cmd_read = cmd_4bytes(NOR_CMD_QUAD_IO_READ);
475             nor->r_cmd_slen = 1;
476         }
477     } else if (nor->info->flag & SUPPORT_DUAL_READ) {
478         nor->cmd_read = cmd_4bytes(NOR_CMD_DUAL_READ);
479         if (nor->info->flag & USE_IO_READ_X2) {
480             nor->cmd_read = cmd_4bytes(NOR_CMD_DUAL_IO_READ);
481             nor->r_cmd_slen = 1;
482         }
483     }
484 
485     if (cmd_bit(nor->cmd_read) == 4 || cmd_bit(nor->cmd_write) == 4) {
486         ret = nor_set_quad_mode();
487         if (ret) {
488             SPINOR_ERR("enable quad mode failed");
489             goto err;
490         }
491     }
492 
493     return 0;
494 err:
495     SPINOR_ERR("scan nor flash failed");
496     nor->info = NULL;
497     return ret;
498 }
499 
nor_init(void)500 int nor_init(void)
501 {
502     int ret = -1;
503 
504     if (nor->info)
505         return 0;
506 
507     ret = nor_lock_init();
508     if (ret) {
509         SPINOR_ERR("create hal_sem lock for nor_flash failed");
510         goto out;
511     }
512 
513     nor_lock();
514 
515     ret = nor_spi_master_init(&nor->spim);
516     if (ret)
517         goto unlock;
518 
519     ret = nor_reset();
520     if (ret)
521         goto unlock;
522 
523     ret = nor_factory_register();
524     if (ret)
525         goto unlock;
526 
527     ret = nor_scan();
528     if (ret)
529         goto unlock;
530 
531     ret = nor_factory_init();
532     if (ret) {
533         SPINOR_ERR("factory init failed");
534         goto unlock;
535     }
536 
537     SPINOR_INFO("Nor Flash %s size %uMB write %dbit read %dbit blk size %uKB",
538             nor->info->model, nor->total_size / 1024 / 1024,
539             cmd_bit(nor->cmd_write), cmd_bit(nor->cmd_read), nor->blk_size / 1024);
540     SPINOR_INFO("Nor Flash ID (hex): %02x %02x %02x", nor->info->id[0],
541             nor->info->id[1], nor->info->id[2]);
542 
543 #ifdef CONFIG_DRIVERS_SPINOR_WRITE_LOCK
544     ret = nor_wr_lock_init(nor);
545     if (ret) {
546         SPINOR_ERR("write lock init failed");
547         goto unlock;
548     }
549 
550     /* ensure all block is locked default */
551     ret = nor_wr_lock_all(nor);
552     if (ret) {
553         SPINOR_ERR("write lock all failed");
554         goto unlock;
555     }
556 #endif
557 
558 #ifdef CONFIG_DRIVERS_SPINOR_CACHE
559     ret = nor_cache_init(nor);
560     if (ret) {
561         SPINOR_ERR("cache init failed");
562         goto unlock;
563     }
564 #endif
565 
566     ret = 0;
567 unlock:
568     nor_unlock();
569 out:
570     if (ret)
571         SPINOR_ERR("init nor flash failed");
572     else
573         SPINOR_INFO("nor flash init ok");
574     return ret;
575 }
576 
nor_deinit(void)577 int nor_deinit(void)
578 {
579     if (!nor->info)
580         return -EBUSY;
581 
582     if (nor_lock()) {
583         SPINOR_ERR("deinit: lock nor failed");
584         return -EBUSY;
585     }
586 
587 #ifdef CONFIG_DRIVERS_SPINOR_CACHE
588     nor_cache_exit();
589 #endif
590 
591 #ifdef CONFIG_DRIVERS_SPINOR_WRITE_LOCK
592     nor_wr_unlock_all(nor);
593 #endif
594 
595     if (nor->info) {
596         if (nor->addr_width == 4)
597             nor_set_4byte(0);
598         nor_spi_master_deinit(&nor->spim);
599     nor->info = NULL;
600     }
601 
602     /* we do not unlock nor in case other task using nor after deinit */
603     return 0;
604 }
605 
nor_erase_do(char cmd,unsigned int addr)606 static int nor_erase_do(char cmd, unsigned int addr)
607 {
608     int ret = -EBUSY;
609     char tbuf[5] = {0};
610     int cmdlen;
611 
612     ret = nor_write_enable();
613     if (ret)
614         goto out;
615 
616     tbuf[0] = cmd;
617     if (nor->addr_width == 4) {
618         tbuf[1] = addr >> 24;
619         tbuf[2] = addr >> 16;
620         tbuf[3] = addr >> 8;
621         tbuf[4] = addr & 0xFF;
622         cmdlen = 5;
623     } else {
624         tbuf[1] = addr >> 16;
625         tbuf[2] = addr >> 8;
626         tbuf[3] = addr & 0xFF;
627         cmdlen = 4;
628     }
629 
630     ret = nor_transfer(cmdlen, tbuf, cmdlen, NULL, 0);
631 out:
632     if (ret)
633         SPINOR_ERR("erase address 0x%x with cmd 0x%x failed\n", addr, cmd);
634     return ret;
635 }
636 
nor_erase_4k(unsigned int addr)637 static inline int nor_erase_4k(unsigned int addr)
638 {
639     int ret;
640 
641 #ifdef CONFIG_DRIVERS_SPINOR_WRITE_LOCK
642     ret = nor_wr_unlock(nor, addr, SZ_4K);
643     if (ret)
644         return -1;
645 #endif
646 
647     ret = nor_erase_do(cmd_4bytes(NOR_CMD_ERASE_BLK4K), addr);
648     if (ret)
649         goto out;
650 
651     ret = nor_wait_ready(30, MAX_WAIT_LOOP);
652 out:
653 #ifdef CONFIG_DRIVERS_SPINOR_WRITE_LOCK
654     nor_wr_lock_all(nor);
655 #endif
656     return ret;
657 }
658 
nor_erase_32k(unsigned int addr)659 static inline int nor_erase_32k(unsigned int addr)
660 {
661     int ret;
662 
663 #ifdef CONFIG_DRIVERS_SPINOR_WRITE_LOCK
664     ret = nor_wr_unlock(nor, addr, SZ_32K);
665     if (ret)
666         return -1;
667 #endif
668 
669     ret = nor_erase_do(cmd_4bytes(NOR_CMD_ERASE_BLK32K), addr);
670     if (ret)
671         goto out;
672 
673     ret = nor_wait_ready(120, MAX_WAIT_LOOP);
674 out:
675 #ifdef CONFIG_DRIVERS_SPINOR_WRITE_LOCK
676     nor_wr_lock_all(nor);
677 #endif
678     return ret;
679 }
680 
nor_erase_64k(unsigned int addr)681 static inline int nor_erase_64k(unsigned int addr)
682 {
683     int ret;
684 
685 #ifdef CONFIG_DRIVERS_SPINOR_WRITE_LOCK
686     ret = nor_wr_unlock(nor, addr, SZ_64K);
687     if (ret)
688         return -1;
689 #endif
690 
691     ret = nor_erase_do(cmd_4bytes(NOR_CMD_ERASE_BLK64K), addr);
692     if (ret)
693         goto out;
694 
695     ret = nor_wait_ready(150, MAX_WAIT_LOOP);
696 out:
697 #ifdef CONFIG_DRIVERS_SPINOR_WRITE_LOCK
698     nor_wr_lock_all(nor);
699 #endif
700     return ret;
701 }
702 
nor_erase_all(void)703 static inline int nor_erase_all(void)
704 {
705     int ret;
706 
707     if (!nor->info)
708         return -EBUSY;
709 
710 #ifdef CONFIG_DRIVERS_SPINOR_WRITE_LOCK
711     nor_wr_unlock_all(nor);
712 #endif
713 
714     ret = nor_write_enable();
715     if (ret)
716         goto out;
717 
718     ret = nor_send_cmd(NOR_CMD_ERASE_CHIP);
719     if (ret)
720         goto out;
721 
722     ret = nor_wait_ready(26 * 1000, MAX_WAIT_LOOP);
723 out:
724 #ifdef CONFIG_DRIVERS_SPINOR_WRITE_LOCK
725     nor_wr_lock_all(nor);
726 #endif
727     return ret;
728 }
729 
nor_erase(unsigned int addr,unsigned int size)730 int nor_erase(unsigned int addr, unsigned int size)
731 {
732     int ret;
733     struct nor_info *info = nor->info;
734 
735     ret = nor_lock();
736     if (ret) {
737         SPINOR_ERR("erase: lock nor failed\n");
738         return ret;
739     }
740 
741     ret = -EBUSY;
742     if (!nor->info)
743         goto unlock;
744 
745     /*
746      * nor erase size can be 4k/32k/64k, driver should erase block size base
747      * on given size. Here must be align to 4k
748      */
749     if (size % SZ_4K) {
750         SPINOR_ERR("erase size 4k is not align to %u\n", size);
751         ret = -EINVAL;
752         goto unlock;
753     }
754 
755     if (addr + size > nor->total_size) {
756         SPINOR_ERR("addr 0x%x with size %u over total size %u\n",
757                 addr, size, nor->total_size);
758         ret = -EINVAL;
759         goto unlock;
760     }
761 
762     SPINOR_DEBUG("try to erase addr 0x%x with size %u\n", addr, size);
763 
764     if (addr == 0 && size == nor->total_size) {
765         ret = nor_erase_all();
766         goto unlock;
767     }
768 
769     while (size) {
770 
771         if ((size >= SZ_64K) &&
772                         (addr % SZ_64K == 0) &&
773                         (info->flag & SUPPORT_64K_ERASE_BLK) &&
774                         !(info->flag & USE_4K_ERASE)) {
775             SPINOR_DEBUG("try to erase 64k from 0x%x\n", addr);
776             ret = nor_erase_64k(addr);
777             if (ret)
778                 goto unlock;
779             addr += SZ_64K;
780             size -= SZ_64K;
781             continue;
782         }
783 
784         if ((size >= SZ_32K) &&
785                         (addr % SZ_32K == 0) &&
786                         (info->flag & SUPPORT_32K_ERASE_BLK) &&
787                         !(info->flag & USE_4K_ERASE)) {
788             SPINOR_DEBUG("try to erase 32k from 0x%x\n", addr);
789             ret = nor_erase_32k(addr);
790             if (ret)
791                 goto unlock;
792             addr += SZ_32K;
793             size -= SZ_32K;
794             continue;
795         }
796 
797         if ((size >= SZ_4K) &&
798                         (addr % SZ_4K == 0) &&
799                         (info->flag & SUPPORT_4K_ERASE_BLK)) {
800             SPINOR_DEBUG("try to erase 4k from 0x%x\n", addr);
801             ret = nor_erase_4k(addr);
802             if (ret)
803                 goto unlock;
804             addr += SZ_4K;
805             size -= SZ_4K;
806             continue;
807         }
808 
809         SPINOR_ERR("no erase cmd matched, addr 0x%x, size 0x%x flag:0x%x\n",
810                         addr, size, info->flag);
811         break;
812     }
813 
814     ret = size ? -EINVAL : 0;
815 unlock:
816     nor_unlock();
817     return ret;
818 }
819 
nor_read_do(unsigned int addr,char * buf,unsigned int len)820 static int nor_read_do(unsigned int addr, char *buf, unsigned int len)
821 {
822     char cmd[5] = {0};
823     int cmdlen;
824 
825     if (len > NOR_PAGE_SIZE)
826         return -EINVAL;
827 
828     cmd[0] = nor->cmd_read;
829     if (nor->addr_width == 4) {
830         cmd[1] = addr >> 24;
831         cmd[2] = addr >> 16;
832         cmd[3] = addr >> 8;
833         cmd[4] = addr & 0xFF;
834         cmdlen = 5;
835     } else {
836         cmd[1] = addr >> 16;
837         cmd[2] = addr >> 8;
838         cmd[3] = addr & 0xFF;
839         cmdlen = 4;
840     }
841     return nor_transfer(nor->r_cmd_slen, cmd, cmdlen, buf, len);
842 }
843 
nor_read(unsigned int addr,char * buf,unsigned int len)844 int nor_read(unsigned int addr, char *buf, unsigned int len)
845 {
846     int ret;
847 
848     ret = nor_lock();
849     if (ret) {
850         SPINOR_ERR("read: lock nor failed\n");
851         goto out;
852     }
853 
854     ret = -EBUSY;
855     if (!nor->info)
856         goto unlock;
857 
858 //    SPINOR_DEBUG("try to read addr 0x%x with len %u\n", addr, len);
859 
860     if (nor_wait_ready(0, 500))
861         goto unlock;
862 
863     while (len) {
864         unsigned int align_addr = ALIGN(addr + 1, NOR_PAGE_SIZE);
865         unsigned int rlen = MIN(align_addr - addr, len);
866 
867         ret = nor_read_do(addr, buf, rlen);
868         if (ret)
869             goto unlock;
870 
871         addr += rlen;
872         buf += rlen;
873         len -= rlen;
874     }
875 
876 unlock:
877     nor_unlock();
878 out:
879     if (ret)
880         SPINOR_ERR("read address 0x%x with len %u failed\n", addr, len);
881     return ret;
882 }
883 
nor_write_do(unsigned int addr,char * buf,unsigned int len)884 static int nor_write_do(unsigned int addr, char *buf, unsigned int len)
885 {
886     int ret = -EINVAL;
887     char tbuf[NOR_PAGE_SIZE + 5] = {0};
888     int cmdlen;
889 
890     if (len > NOR_PAGE_SIZE)
891         return -EINVAL;
892 
893     ret = nor_write_enable();
894     if (ret)
895         return ret;
896 
897     if (nor->addr_width == 4) {
898         tbuf[0] = nor->cmd_write;
899         tbuf[1] = addr >> 24;
900         tbuf[2] = addr >> 16;
901         tbuf[3] = addr >> 8;
902         tbuf[4] = addr & 0xFF;
903         cmdlen = 5;
904     } else {
905         tbuf[0] = nor->cmd_write;
906         tbuf[1] = addr >> 16;
907         tbuf[2] = addr >> 8;
908         tbuf[3] = addr & 0xFF;
909         cmdlen = 4;
910     }
911 
912     memcpy(tbuf + cmdlen, buf, MIN(len, (unsigned int)NOR_PAGE_SIZE));
913     ret = nor_transfer(nor->w_cmd_slen, tbuf, len + cmdlen, NULL, 0);
914     if (ret)
915         return ret;
916 
917     return nor_wait_ready(0, 100 * 1000);
918 }
919 
nor_write(unsigned int addr,char * buf,unsigned int len)920 int nor_write(unsigned int addr, char *buf, unsigned int len)
921 {
922     int ret;
923 
924     ret = nor_lock();
925     if (ret) {
926         SPINOR_ERR("write: lock nor failed\n");
927         goto out;
928     }
929 
930     ret = -EBUSY;
931     if (!nor->info)
932         goto unlock;
933 
934     SPINOR_DEBUG("try to write addr 0x%x with len %u\n", addr, len);
935 
936     if (nor_wait_ready(0, 500))
937         goto unlock;
938 
939     while (len) {
940         unsigned int align_addr = ALIGN(addr + 1, NOR_PAGE_SIZE);
941         unsigned int wlen = MIN(align_addr - addr, len);
942 
943 #ifdef CONFIG_DRIVERS_SPINOR_WRITE_LOCK
944         ret = nor_wr_unlock(nor, addr, len);
945         if (ret)
946             goto unlock;
947 #endif
948 
949         ret = nor_write_do(addr, buf, wlen);
950         if (ret)
951             goto unlock;
952 
953 #ifdef CONFIG_DRIVERS_SPINOR_WRITE_LOCK
954         ret = nor_wr_lock_all(nor);
955         if (ret)
956             goto unlock;
957 #endif
958 
959         addr += wlen;
960         buf += wlen;
961         len -= wlen;
962     }
963 
964 unlock:
965     nor_unlock();
966 out:
967     if (ret)
968         SPINOR_ERR("write address 0x%x with len %u failed\n", addr, len);
969     return ret;
970 }
971 
get_nor_flash(void)972 struct nor_flash *get_nor_flash(void)
973 {
974     return nor;
975 }
976