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