blob: 0e92d8c6b7c96aa0082053cb45b57d2490ffa79d [file] [log] [blame]
Norman James6a58a272015-10-07 14:34:16 -05001#include <stdio.h>
2#include <stdlib.h>
3#include <stdint.h>
4#include <string.h>
5
6#include <libflash/libflash.h>
7#include <libflash/libflash-priv.h>
8
9#include "../libflash.c"
10
11#define __unused __attribute__((unused))
12
13#define ERR(fmt...) fprintf(stderr, fmt)
14
15/* Flash commands */
16#define CMD_PP 0x02
17#define CMD_READ 0x03
18#define CMD_WRDI 0x04
19#define CMD_RDSR 0x05
20#define CMD_WREN 0x06
21#define CMD_SE 0x20
22#define CMD_RDSCUR 0x2b
23#define CMD_BE32K 0x52
24#define CMD_CE 0x60
25#define CMD_RDID 0x9f
26#define CMD_EN4B 0xb7
27#define CMD_BE 0xd8
28#define CMD_RDDPB 0xe0
29#define CMD_RDSPB 0xe2
30#define CMD_EX4B 0xe9
31
32/* Flash status bits */
33#define STAT_WIP 0x01
34#define STAT_WEN 0x02
35
36static uint8_t *sim_image;
37static uint32_t sim_image_sz = 0x100000;
38static uint32_t sim_index;
39static uint32_t sim_addr;
40static uint32_t sim_er_size;
41static uint8_t sim_sr;
42static bool sim_fl_4b;
43static bool sim_ct_4b;
44
45static enum sim_state {
46 sim_state_idle,
47 sim_state_rdid,
48 sim_state_rdsr,
49 sim_state_read_addr,
50 sim_state_read_data,
51 sim_state_write_addr,
52 sim_state_write_data,
53 sim_state_erase_addr,
54 sim_state_erase_done,
55} sim_state;
56
57/*
58 * Simulated flash & controller
59 */
60static int sim_start_cmd(uint8_t cmd)
61{
62 if (sim_state != sim_state_idle) {
63 ERR("SIM: Command %02x in wrong state %d\n", cmd, sim_state);
64 return -1;
65 }
66
67 sim_index = 0;
68 sim_addr = 0;
69
70 switch(cmd) {
71 case CMD_RDID:
72 sim_state = sim_state_rdid;
73 break;
74 case CMD_RDSR:
75 sim_state = sim_state_rdsr;
76 break;
77 case CMD_EX4B:
78 sim_fl_4b = false;
79 break;
80 case CMD_EN4B:
81 sim_fl_4b = true;
82 break;
83 case CMD_WREN:
84 sim_sr |= STAT_WEN;
85 break;
86 case CMD_READ:
87 sim_state = sim_state_read_addr;
88 if (sim_ct_4b != sim_fl_4b)
89 ERR("SIM: 4b mode mismatch in READ !\n");
90 break;
91 case CMD_PP:
92 sim_state = sim_state_write_addr;
93 if (sim_ct_4b != sim_fl_4b)
94 ERR("SIM: 4b mode mismatch in PP !\n");
95 if (!(sim_sr & STAT_WEN))
96 ERR("SIM: PP without WEN, ignoring... \n");
97 break;
98 case CMD_SE:
99 case CMD_BE32K:
100 case CMD_BE:
101 if (sim_ct_4b != sim_fl_4b)
102 ERR("SIM: 4b mode mismatch in SE/BE !\n");
103 if (!(sim_sr & STAT_WEN))
104 ERR("SIM: SE/BE without WEN, ignoring... \n");
105 sim_state = sim_state_erase_addr;
106 switch(cmd) {
107 case CMD_SE: sim_er_size = 0x1000; break;
108 case CMD_BE32K: sim_er_size = 0x8000; break;
109 case CMD_BE: sim_er_size = 0x10000; break;
110 }
111 break;
112 case CMD_CE:
113 if (!(sim_sr & STAT_WEN)) {
114 ERR("SIM: CE without WEN, ignoring... \n");
115 break;
116 }
117 memset(sim_image, 0xff, sim_image_sz);
118 sim_sr |= STAT_WIP;
119 sim_sr &= ~STAT_WEN;
120 break;
121 default:
122 ERR("SIM: Unsupported command %02x\n", cmd);
123 return -1;
124 }
125 return 0;
126}
127
128static void sim_end_cmd(void)
129{
130 /* For write and sector/block erase, set WIP & clear WEN here */
131 if (sim_state == sim_state_write_data) {
132 sim_sr |= STAT_WIP;
133 sim_sr &= ~STAT_WEN;
134 }
135 sim_state = sim_state_idle;
136}
137
138static bool sim_do_address(const uint8_t **buf, uint32_t *len)
139{
140 uint8_t asize = sim_fl_4b ? 4 : 3;
141 const uint8_t *p = *buf;
142
143 while(*len) {
144 sim_addr = (sim_addr << 8) | *(p++);
145 *buf = p;
146 *len = *len - 1;
147 sim_index++;
148 if (sim_index >= asize)
149 return true;
150 }
151 return false;
152}
153
154static int sim_wbytes(const void *buf, uint32_t len)
155{
156 const uint8_t *b = buf;
157 bool addr_complete;
158
159 again:
160 switch(sim_state) {
161 case sim_state_read_addr:
162 addr_complete = sim_do_address(&b, &len);
163 if (addr_complete) {
164 sim_state = sim_state_read_data;
165 sim_index = 0;
166 if (len)
167 goto again;
168 }
169 break;
170 case sim_state_write_addr:
171 addr_complete = sim_do_address(&b, &len);
172 if (addr_complete) {
173 sim_state = sim_state_write_data;
174 sim_index = 0;
175 if (len)
176 goto again;
177 }
178 break;
179 case sim_state_write_data:
180 if (!(sim_sr & STAT_WEN))
181 break;
182 while(len--) {
183 uint8_t c = *(b++);
184 if (sim_addr >= sim_image_sz) {
185 ERR("SIM: Write past end of flash\n");
186 return -1;
187 }
188 /* Flash write only clears bits */
189 sim_image[sim_addr] &= c;
190 sim_addr = (sim_addr & 0xffffff00) |
191 ((sim_addr + 1) & 0xff);
192 }
193 break;
194 case sim_state_erase_addr:
195 if (!(sim_sr & STAT_WEN))
196 break;
197 addr_complete = sim_do_address(&b, &len);
198 if (addr_complete) {
199 memset(sim_image + sim_addr, 0xff, sim_er_size);
200 sim_sr |= STAT_WIP;
201 sim_sr &= ~STAT_WEN;
202 sim_state = sim_state_erase_done;
203 }
204 break;
205 default:
206 ERR("SIM: Write in wrong state %d\n", sim_state);
207 return -1;
208 }
209 return 0;
210}
211
212static int sim_rbytes(void *buf, uint32_t len)
213{
214 uint8_t *b = buf;
215
216 switch(sim_state) {
217 case sim_state_rdid:
218 while(len--) {
219 switch(sim_index) {
220 case 0:
221 *(b++) = 0x55;
222 break;
223 case 1:
224 *(b++) = 0xaa;
225 break;
226 case 2:
227 *(b++) = 0x55;
228 break;
229 default:
230 ERR("SIM: RDID index %d\n", sim_index);
231 *(b++) = 0;
232 break;
233 }
234 sim_index++;
235 }
236 break;
237 case sim_state_rdsr:
238 while(len--) {
239 *(b++) = sim_sr;
240 if (sim_index > 0)
241 ERR("SIM: RDSR index %d\n", sim_index);
242 sim_index++;
243
244 /* If WIP was 1, clear it, ie, simulate write/erase
245 * completion
246 */
247 sim_sr &= ~STAT_WIP;
248 }
249 break;
250 case sim_state_read_data:
251 while(len--) {
252 if (sim_addr >= sim_image_sz) {
253 ERR("SIM: Read past end of flash\n");
254 return -1;
255 }
256 *(b++) = sim_image[sim_addr++];
257 }
258 break;
259 default:
260 ERR("SIM: Read in wrong state %d\n", sim_state);
261 return -1;
262 }
263 return 0;
264}
265
266static int sim_send_addr(uint32_t addr)
267{
268 const void *ap;
269
270 /* Layout address MSB first in memory */
271 addr = cpu_to_be32(addr);
272
273 /* Send the right amount of bytes */
274 ap = (char *)&addr;
275
276 if (sim_ct_4b)
277 return sim_wbytes(ap, 4);
278 else
279 return sim_wbytes(ap + 1, 3);
280}
281
282static int sim_cmd_rd(struct spi_flash_ctrl *ctrl __unused, uint8_t cmd,
283 bool has_addr, uint32_t addr, void *buffer,
284 uint32_t size)
285{
286 int rc;
287
288 rc = sim_start_cmd(cmd);
289 if (rc)
290 goto bail;
291 if (has_addr) {
292 rc = sim_send_addr(addr);
293 if (rc)
294 goto bail;
295 }
296 if (buffer && size)
297 rc = sim_rbytes(buffer, size);
298 bail:
299 sim_end_cmd();
300 return rc;
301}
302
303static int sim_cmd_wr(struct spi_flash_ctrl *ctrl __unused, uint8_t cmd,
304 bool has_addr, uint32_t addr, const void *buffer,
305 uint32_t size)
306{
307 int rc;
308
309 rc = sim_start_cmd(cmd);
310 if (rc)
311 goto bail;
312 if (has_addr) {
313 rc = sim_send_addr(addr);
314 if (rc)
315 goto bail;
316 }
317 if (buffer && size)
318 rc = sim_wbytes(buffer, size);
319 bail:
320 sim_end_cmd();
321 return rc;
322}
323
324static int sim_set_4b(struct spi_flash_ctrl *ctrl __unused, bool enable)
325{
326 sim_ct_4b = enable;
327
328 return 0;
329}
330
331static int sim_read(struct spi_flash_ctrl *ctrl __unused, uint32_t pos,
332 void *buf, uint32_t len)
333{
334 if (sim_ct_4b != sim_fl_4b)
335 ERR("SIM: 4b mode mismatch in autoread !\n");
336 if ((pos + len) < pos)
337 return -1;
338 if ((pos + len) > sim_image_sz)
339 return -1;
340 memcpy(buf, sim_image + pos, len);
341 return 0;
342};
343
344struct spi_flash_ctrl sim_ctrl = {
345 .cmd_wr = sim_cmd_wr,
346 .cmd_rd = sim_cmd_rd,
347 .set_4b = sim_set_4b,
348 .read = sim_read,
349};
350
351int main(void)
352{
353 struct flash_chip *fl;
354 uint32_t total_size, erase_granule;
355 const char *name;
356 uint16_t *test;
357 int i, rc;
358
359 sim_image = malloc(sim_image_sz);
360 memset(sim_image, 0xff, sim_image_sz);
361 test = malloc(0x10000 * 2);
362
363 rc = flash_init(&sim_ctrl, &fl);
364 if (rc) {
365 ERR("flash_init failed with err %d\n", rc);
366 exit(1);
367 }
368 rc = flash_get_info(fl, &name, &total_size, &erase_granule);
369 if (rc) {
370 ERR("flash_get_info failed with err %d\n", rc);
371 exit(1);
372 }
373
374 /* Make up a test pattern */
375 for (i=0; i<0x10000;i++)
376 test[i] = cpu_to_be16(i);
377
378 /* Write 64k of stuff at 0 and at 128k */
379 printf("Writing test patterns...\n");
380 flash_smart_write(fl, 0, test, 0x10000);
381 flash_smart_write(fl, 0x20000, test, 0x10000);
382
383 /* Write "Hello world" straddling the 64k boundary */
384#define HW "Hello World"
385 printf("Writing test string...\n");
386 flash_smart_write(fl, 0xfffc, HW, sizeof(HW));
387
388 /* Check result */
389 if (memcmp(sim_image + 0xfffc, HW, sizeof(HW))) {
390 ERR("Test string mismatch !\n");
391 exit(1);
392 }
393 printf("Test string pass\n");
394 if (memcmp(sim_image, test, 0xfffc)) {
395 ERR("Test pattern mismatch !\n");
396 exit(1);
397 }
398 printf("Test pattern pass\n");
399 flash_exit(fl);
400
401 return 0;
402}
403