1 /* all about mxic factory */
2 
3 #include <string.h>
4 #include <stdlib.h>
5 #include <time.h>
6 #include <pthread.h>
7 #include <errno.h>
8 #include <unistd.h>
9 #include <hal_timer.h>
10 
11 #include "inter.h"
12 
13 #define NOR_MXIC_CMD_READ_CR 0x15
14 #define NOR_MXIC_CMD_RDSCUR 0x2B
15 #define NOR_MXIC_CMD_WRSCUR 0x2F
16 #define NOR_MXIC_CMD_WPSEL 0x68
17 #define NOR_MXIC_CMD_ESSPB 0xE4
18 #define NOR_MXIC_CMD_RDSPB 0xE2
19 #define NOR_MXIC_CMD_WRSPB 0xE3
20 #define NOR_MXIC_CMD_RDDPB 0xE0
21 #define NOR_MXIC_CMD_WRDPB 0xE1
22 #define NOR_MXIC_WPSEL_BIT BIT(7)
23 #define NOR_MXIC_QE_BIT BIT(6)
24 #define NOR_MXIC_DPB_LOCK (0xFF)
25 #define NOR_MXIC_DPB_UNLOCK (0x00)
26 #define NOR_MXIC_PT_MASK (BIT(3) | BIT(2) | BIT(1) | BIT(0))
27 #define NOR_MXIC_PROTECT_BP_SHIFT 2
28 
29 static struct nor_info idt_mxic[] =
30 {
31     {
32         .model = "mx25l6433f",
33         .id = {0xc2, 0x20, 0x17},
34         .total_size = SZ_8M,
35         .flag = SUPPORT_GENERAL | USE_IO_PROG_X4 | SUPPORT_INDIVIDUAL_PROTECT,
36     },
37     {
38         .model = "mx25l12833f",
39         .id = {0xc2, 0x20, 0x18},
40         .total_size = SZ_16M,
41         .flag = SUPPORT_GENERAL | USE_IO_PROG_X4 | SUPPORT_INDIVIDUAL_PROTECT,
42     },
43     {
44         .model = "mx25l51234g",
45         .id = {0xc2, 0x20, 0x1a},
46         .total_size = SZ_64M,
47         .flag = SUPPORT_GENERAL | USE_IO_PROG_X4,
48     }
49 };
50 
nor_mxic_quad_mode(struct nor_flash * nor)51 static int nor_mxic_quad_mode(struct nor_flash *nor)
52 {
53     int ret;
54     unsigned char sr;
55 
56     ret = nor_read_status(&sr);
57     if (ret)
58         return ret;
59 
60     if (sr & NOR_MXIC_QE_BIT)
61         return 0;
62 
63     sr |= NOR_MXIC_QE_BIT;
64     /*
65      * If individual protect mode is enable, BP can't not write. If BP bits
66      * are set, write status will go failed, which make QE bit set failed.
67      */
68     if (is_wrlock_work(nor))
69         sr &= ~(NOR_MXIC_PT_MASK << NOR_MXIC_PROTECT_BP_SHIFT);
70     ret = nor_write_status(&sr, 1);
71     if (ret)
72         return ret;
73 
74     ret = nor_read_status(&sr);
75     if (ret)
76         return ret;
77 
78     if (!(sr & NOR_MXIC_QE_BIT)) {
79         SPINOR_ERR("set mxic QE failed (0x%x)\n", sr);
80         return -EINVAL;
81     }
82     return 0;
83 }
84 
nor_mxic_set_wps(void)85 static int nor_mxic_set_wps(void)
86 {
87     int ret;
88     unsigned char cmd, sr;
89 
90     cmd = NOR_MXIC_CMD_RDSCUR;
91     ret = nor_transfer(1, &cmd, 1, &sr, 1);
92     if (ret)
93         return ret;
94 
95     /* already set before, no need to set again */
96     if (sr & NOR_MXIC_WPSEL_BIT)
97         return 0;
98 
99     ret = nor_write_enable();
100     if (ret)
101         return ret;
102 
103     ret = nor_send_cmd(NOR_MXIC_CMD_WPSEL);
104     if (ret)
105         return ret;
106 
107     ret = nor_wait_ready(10, 100 * 1000);
108     if (ret)
109         return ret;
110 
111     cmd = NOR_MXIC_CMD_RDSCUR;
112     ret = nor_transfer(1, &cmd, 1, &sr, 1);
113     if (ret)
114         return ret;
115     return !(sr & NOR_MXIC_WPSEL_BIT);
116 }
117 
nor_mxic_reset_spb(void)118 static int nor_mxic_reset_spb(void)
119 {
120     int ret;
121 
122     ret = nor_write_enable();
123     if (ret)
124         return ret;
125 
126     ret = nor_send_cmd(NOR_MXIC_CMD_ESSPB);
127     if (ret)
128         return ret;
129 
130     ret = nor_wait_ready(10, 500);
131     if (ret)
132         return ret;
133 
134     return 0;
135 }
136 
nor_mxic_init_lock(struct nor_flash * nor)137 static int nor_mxic_init_lock(struct nor_flash *nor)
138 {
139     int ret;
140 
141     ret = nor_mxic_set_wps();
142     if (ret)
143         return ret;
144 
145     ret = nor_mxic_reset_spb();
146     if (ret)
147         return ret;
148 
149     return 0;
150 }
151 
nor_mxic_blk_islock(unsigned int addr)152 static bool nor_mxic_blk_islock(unsigned int addr)
153 {
154     int ret;
155     unsigned char tbuf[5], st;
156 
157     tbuf[0] = NOR_MXIC_CMD_RDDPB;
158     tbuf[1] = addr >> 24;
159     tbuf[2] = addr >> 16;
160     tbuf[3] = addr >> 8;
161     tbuf[4] = addr & 0xFF;
162     ret = nor_transfer(5, tbuf, 5, &st, 1);
163     if (ret)
164         return ret;
165 
166     return st == 0xFF ? true : false;
167 }
168 
nor_mxic_blk_unlock(unsigned int addr)169 static int nor_mxic_blk_unlock(unsigned int addr)
170 {
171     int ret;
172     unsigned char tbuf[6];
173 
174     ret = nor_write_enable();
175     if (ret)
176         return ret;
177 
178     tbuf[0] = NOR_MXIC_CMD_WRDPB;
179     tbuf[1] = addr >> 24;
180     tbuf[2] = addr >> 16;
181     tbuf[3] = addr >> 8;
182     tbuf[4] = addr & 0xFF;
183     tbuf[5] = NOR_MXIC_DPB_UNLOCK;
184     ret = nor_transfer(6, tbuf, 6, NULL, 0);
185     if (ret) {
186         SPINOR_ERR("mxic unlock 0x%x failed - %d\n", addr, ret);
187         return ret;
188     }
189     if (nor_mxic_blk_islock(addr) == true)
190         return -EBUSY;
191     return 0;
192 }
193 
nor_mxic_blk_lock(unsigned int addr)194 static int nor_mxic_blk_lock(unsigned int addr)
195 {
196     int ret;
197     unsigned char tbuf[6];
198 
199     ret = nor_write_enable();
200     if (ret)
201         return ret;
202 
203     tbuf[0] = NOR_MXIC_CMD_WRDPB;
204     tbuf[1] = addr >> 24;
205     tbuf[2] = addr >> 16;
206     tbuf[3] = addr >> 8;
207     tbuf[4] = addr & 0xFF;
208     tbuf[5] = NOR_MXIC_DPB_LOCK;
209     ret = nor_transfer(6, tbuf, 6, NULL, 0);
210     if (ret) {
211         SPINOR_ERR("mxic lock 0x%x failed - %d\n", addr, ret);
212         return ret;
213     }
214     if (nor_mxic_blk_islock(addr) == false)
215         return -EBUSY;
216     return 0;
217 }
218 
nor_mxic_lock(struct nor_flash * nor,unsigned int addr,unsigned int len)219 static int nor_mxic_lock(struct nor_flash *nor, unsigned int addr,
220         unsigned int len)
221 {
222     return nor_mxic_blk_lock(addr);
223 }
224 
nor_mxic_unlock(struct nor_flash * nor,unsigned int addr,unsigned int len)225 static int nor_mxic_unlock(struct nor_flash *nor, unsigned int addr,
226         unsigned int len)
227 {
228     return nor_mxic_blk_unlock(addr);
229 }
230 
nor_mxic_islock(struct nor_flash * nor,unsigned int addr,unsigned int len)231 static bool nor_mxic_islock(struct nor_flash *nor, unsigned int addr,
232         unsigned int len)
233 {
234     return nor_mxic_blk_islock(addr);
235 }
236 
237 static struct nor_factory nor_mxic = {
238     .factory = FACTORY_MXIC,
239     .idt = idt_mxic,
240     .idt_cnt = sizeof(idt_mxic),
241 
242     .init = NULL,
243     .deinit = NULL,
244     .init_lock = nor_mxic_init_lock,
245     .deinit_lock = NULL,
246     .lock = nor_mxic_lock,
247     .unlock = nor_mxic_unlock,
248     .islock = nor_mxic_islock,
249     .set_quad_mode = nor_mxic_quad_mode,
250     .set_4bytes_addr = NULL,
251 };
252 
nor_register_factory_mxic(void)253 int nor_register_factory_mxic(void)
254 {
255     return nor_register_factory(&nor_mxic);
256 }
257