~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/u-boot/drivers/mtd/spi/sandbox.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Simulate a SPI flash
 
3
 *
 
4
 * Copyright (c) 2011-2013 The Chromium OS Authors.
 
5
 * See file CREDITS for list of people who contributed to this
 
6
 * project.
 
7
 *
 
8
 * Licensed under the GPL-2 or later.
 
9
 */
 
10
 
 
11
#include <common.h>
 
12
#include <malloc.h>
 
13
#include <spi.h>
 
14
#include <os.h>
 
15
 
 
16
#include <spi_flash.h>
 
17
#include "sf_internal.h"
 
18
 
 
19
#include <asm/getopt.h>
 
20
#include <asm/spi.h>
 
21
#include <asm/state.h>
 
22
 
 
23
/*
 
24
 * The different states that our SPI flash transitions between.
 
25
 * We need to keep track of this across multiple xfer calls since
 
26
 * the SPI bus could possibly call down into us multiple times.
 
27
 */
 
28
enum sandbox_sf_state {
 
29
        SF_CMD,   /* default state -- we're awaiting a command */
 
30
        SF_ID,    /* read the flash's (jedec) ID code */
 
31
        SF_ADDR,  /* processing the offset in the flash to read/etc... */
 
32
        SF_READ,  /* reading data from the flash */
 
33
        SF_WRITE, /* writing data to the flash, i.e. page programming */
 
34
        SF_ERASE, /* erase the flash */
 
35
        SF_READ_STATUS, /* read the flash's status register */
 
36
        SF_READ_STATUS1, /* read the flash's status register upper 8 bits*/
 
37
};
 
38
 
 
39
static const char *sandbox_sf_state_name(enum sandbox_sf_state state)
 
40
{
 
41
        static const char * const states[] = {
 
42
                "CMD", "ID", "ADDR", "READ", "WRITE", "ERASE", "READ_STATUS",
 
43
        };
 
44
        return states[state];
 
45
}
 
46
 
 
47
/* Bits for the status register */
 
48
#define STAT_WIP        (1 << 0)
 
49
#define STAT_WEL        (1 << 1)
 
50
 
 
51
/* Assume all SPI flashes have 3 byte addresses since they do atm */
 
52
#define SF_ADDR_LEN     3
 
53
 
 
54
struct sandbox_spi_flash_erase_commands {
 
55
        u8 cmd;
 
56
        u32 size;
 
57
};
 
58
#define IDCODE_LEN 5
 
59
#define MAX_ERASE_CMDS 3
 
60
struct sandbox_spi_flash_data {
 
61
        const char *name;
 
62
        u8 idcode[IDCODE_LEN];
 
63
        u32 size;
 
64
        const struct sandbox_spi_flash_erase_commands
 
65
                                                erase_cmds[MAX_ERASE_CMDS];
 
66
};
 
67
 
 
68
/* Structure describing all the flashes we know how to emulate */
 
69
static const struct sandbox_spi_flash_data sandbox_sf_flashes[] = {
 
70
        {
 
71
                "M25P16", { 0x20, 0x20, 0x15 }, (2 << 20),
 
72
                {       /* erase commands */
 
73
                        { 0xd8, (64 << 10), }, /* sector */
 
74
                        { 0xc7, (2 << 20), }, /* bulk */
 
75
                },
 
76
        },
 
77
        {
 
78
                "W25Q32", { 0xef, 0x40, 0x16 }, (4 << 20),
 
79
                {       /* erase commands */
 
80
                        { 0x20, (4 << 10), }, /* 4KB */
 
81
                        { 0xd8, (64 << 10), }, /* sector */
 
82
                        { 0xc7, (4 << 20), }, /* bulk */
 
83
                },
 
84
        },
 
85
        {
 
86
                "W25Q128", { 0xef, 0x40, 0x18 }, (16 << 20),
 
87
                {       /* erase commands */
 
88
                        { 0x20, (4 << 10), }, /* 4KB */
 
89
                        { 0xd8, (64 << 10), }, /* sector */
 
90
                        { 0xc7, (16 << 20), }, /* bulk */
 
91
                },
 
92
        },
 
93
};
 
94
 
 
95
/* Used to quickly bulk erase backing store */
 
96
static u8 sandbox_sf_0xff[0x1000];
 
97
 
 
98
/* Internal state data for each SPI flash */
 
99
struct sandbox_spi_flash {
 
100
        /*
 
101
         * As we receive data over the SPI bus, our flash transitions
 
102
         * between states.  For example, we start off in the SF_CMD
 
103
         * state where the first byte tells us what operation to perform
 
104
         * (such as read or write the flash).  But the operation itself
 
105
         * can go through a few states such as first reading in the
 
106
         * offset in the flash to perform the requested operation.
 
107
         * Thus "state" stores the exact state that our machine is in
 
108
         * while "cmd" stores the overall command we're processing.
 
109
         */
 
110
        enum sandbox_sf_state state;
 
111
        uint cmd;
 
112
        const void *cmd_data;
 
113
        /* Current position in the flash; used when reading/writing/etc... */
 
114
        uint off;
 
115
        /* How many address bytes we've consumed */
 
116
        uint addr_bytes, pad_addr_bytes;
 
117
        /* The current flash status (see STAT_XXX defines above) */
 
118
        u16 status;
 
119
        /* Data describing the flash we're emulating */
 
120
        const struct sandbox_spi_flash_data *data;
 
121
        /* The file on disk to serv up data from */
 
122
        int fd;
 
123
};
 
124
 
 
125
static int sandbox_sf_setup(void **priv, const char *spec)
 
126
{
 
127
        /* spec = idcode:file */
 
128
        struct sandbox_spi_flash *sbsf;
 
129
        const char *file;
 
130
        size_t i, len, idname_len;
 
131
        const struct sandbox_spi_flash_data *data;
 
132
 
 
133
        file = strchr(spec, ':');
 
134
        if (!file) {
 
135
                printf("sandbox_sf: unable to parse file\n");
 
136
                goto error;
 
137
        }
 
138
        idname_len = file - spec;
 
139
        ++file;
 
140
 
 
141
        for (i = 0; i < ARRAY_SIZE(sandbox_sf_flashes); ++i) {
 
142
                data = &sandbox_sf_flashes[i];
 
143
                len = strlen(data->name);
 
144
                if (idname_len != len)
 
145
                        continue;
 
146
                if (!memcmp(spec, data->name, len))
 
147
                        break;
 
148
        }
 
149
        if (i == ARRAY_SIZE(sandbox_sf_flashes)) {
 
150
                printf("sandbox_sf: unknown flash '%*s'\n", (int)idname_len,
 
151
                       spec);
 
152
                goto error;
 
153
        }
 
154
 
 
155
        if (sandbox_sf_0xff[0] == 0x00)
 
156
                memset(sandbox_sf_0xff, 0xff, sizeof(sandbox_sf_0xff));
 
157
 
 
158
        sbsf = calloc(sizeof(*sbsf), 1);
 
159
        if (!sbsf) {
 
160
                printf("sandbox_sf: out of memory\n");
 
161
                goto error;
 
162
        }
 
163
 
 
164
        sbsf->fd = os_open(file, 02);
 
165
        if (sbsf->fd == -1) {
 
166
                free(sbsf);
 
167
                printf("sandbox_sf: unable to open file '%s'\n", file);
 
168
                goto error;
 
169
        }
 
170
 
 
171
        sbsf->data = data;
 
172
 
 
173
        *priv = sbsf;
 
174
        return 0;
 
175
 
 
176
 error:
 
177
        return 1;
 
178
}
 
179
 
 
180
static void sandbox_sf_free(void *priv)
 
181
{
 
182
        struct sandbox_spi_flash *sbsf = priv;
 
183
 
 
184
        os_close(sbsf->fd);
 
185
        free(sbsf);
 
186
}
 
187
 
 
188
static void sandbox_sf_cs_activate(void *priv)
 
189
{
 
190
        struct sandbox_spi_flash *sbsf = priv;
 
191
 
 
192
        debug("sandbox_sf: CS activated; state is fresh!\n");
 
193
 
 
194
        /* CS is asserted, so reset state */
 
195
        sbsf->off = 0;
 
196
        sbsf->addr_bytes = 0;
 
197
        sbsf->pad_addr_bytes = 0;
 
198
        sbsf->state = SF_CMD;
 
199
        sbsf->cmd = SF_CMD;
 
200
}
 
201
 
 
202
static void sandbox_sf_cs_deactivate(void *priv)
 
203
{
 
204
        debug("sandbox_sf: CS deactivated; cmd done processing!\n");
 
205
}
 
206
 
 
207
/* Figure out what command this stream is telling us to do */
 
208
static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx,
 
209
                                  u8 *tx)
 
210
{
 
211
        enum sandbox_sf_state oldstate = sbsf->state;
 
212
 
 
213
        /* We need to output a byte for the cmd byte we just ate */
 
214
        sandbox_spi_tristate(tx, 1);
 
215
 
 
216
        sbsf->cmd = rx[0];
 
217
        switch (sbsf->cmd) {
 
218
        case CMD_READ_ID:
 
219
                sbsf->state = SF_ID;
 
220
                sbsf->cmd = SF_ID;
 
221
                break;
 
222
        case CMD_READ_ARRAY_FAST:
 
223
                sbsf->pad_addr_bytes = 1;
 
224
        case CMD_READ_ARRAY_SLOW:
 
225
        case CMD_PAGE_PROGRAM:
 
226
 state_addr:
 
227
                sbsf->state = SF_ADDR;
 
228
                break;
 
229
        case CMD_WRITE_DISABLE:
 
230
                debug(" write disabled\n");
 
231
                sbsf->status &= ~STAT_WEL;
 
232
                break;
 
233
        case CMD_READ_STATUS:
 
234
                sbsf->state = SF_READ_STATUS;
 
235
                break;
 
236
        case CMD_READ_STATUS1:
 
237
                sbsf->state = SF_READ_STATUS1;
 
238
                break;
 
239
        case CMD_WRITE_ENABLE:
 
240
                debug(" write enabled\n");
 
241
                sbsf->status |= STAT_WEL;
 
242
                break;
 
243
        default: {
 
244
                size_t i;
 
245
 
 
246
                /* handle erase commands first */
 
247
                for (i = 0; i < MAX_ERASE_CMDS; ++i) {
 
248
                        const struct sandbox_spi_flash_erase_commands *
 
249
                                erase_cmd = &sbsf->data->erase_cmds[i];
 
250
 
 
251
                        if (erase_cmd->cmd == 0x00)
 
252
                                continue;
 
253
                        if (sbsf->cmd != erase_cmd->cmd)
 
254
                                continue;
 
255
 
 
256
                        sbsf->cmd_data = erase_cmd;
 
257
                        goto state_addr;
 
258
                }
 
259
 
 
260
                debug(" cmd unknown: %#x\n", sbsf->cmd);
 
261
                return 1;
 
262
        }
 
263
        }
 
264
 
 
265
        if (oldstate != sbsf->state)
 
266
                debug(" cmd: transition to %s state\n",
 
267
                      sandbox_sf_state_name(sbsf->state));
 
268
 
 
269
        return 0;
 
270
}
 
271
 
 
272
int sandbox_erase_part(struct sandbox_spi_flash *sbsf, int size)
 
273
{
 
274
        int todo;
 
275
        int ret;
 
276
 
 
277
        while (size > 0) {
 
278
                todo = min(size, sizeof(sandbox_sf_0xff));
 
279
                ret = os_write(sbsf->fd, sandbox_sf_0xff, todo);
 
280
                if (ret != todo)
 
281
                        return ret;
 
282
                size -= todo;
 
283
        }
 
284
 
 
285
        return 0;
 
286
}
 
287
 
 
288
static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
 
289
                uint bytes)
 
290
{
 
291
        struct sandbox_spi_flash *sbsf = priv;
 
292
        uint cnt, pos = 0;
 
293
        int ret;
 
294
 
 
295
        debug("sandbox_sf: state:%x(%s) bytes:%u\n", sbsf->state,
 
296
              sandbox_sf_state_name(sbsf->state), bytes);
 
297
 
 
298
        if (sbsf->state == SF_CMD) {
 
299
                /* Figure out the initial state */
 
300
                if (sandbox_sf_process_cmd(sbsf, rx, tx))
 
301
                        return 1;
 
302
                ++pos;
 
303
        }
 
304
 
 
305
        /* Process the remaining data */
 
306
        while (pos < bytes) {
 
307
                switch (sbsf->state) {
 
308
                case SF_ID: {
 
309
                        u8 id;
 
310
 
 
311
                        debug(" id: off:%u tx:", sbsf->off);
 
312
                        if (sbsf->off < IDCODE_LEN)
 
313
                                id = sbsf->data->idcode[sbsf->off];
 
314
                        else
 
315
                                id = 0;
 
316
                        debug("%02x\n", id);
 
317
                        tx[pos++] = id;
 
318
                        ++sbsf->off;
 
319
                        break;
 
320
                }
 
321
                case SF_ADDR:
 
322
                        debug(" addr: bytes:%u rx:%02x ", sbsf->addr_bytes,
 
323
                              rx[pos]);
 
324
 
 
325
                        if (sbsf->addr_bytes++ < SF_ADDR_LEN)
 
326
                                sbsf->off = (sbsf->off << 8) | rx[pos];
 
327
                        debug("addr:%06x\n", sbsf->off);
 
328
 
 
329
                        sandbox_spi_tristate(&tx[pos++], 1);
 
330
 
 
331
                        /* See if we're done processing */
 
332
                        if (sbsf->addr_bytes <
 
333
                                        SF_ADDR_LEN + sbsf->pad_addr_bytes)
 
334
                                break;
 
335
 
 
336
                        /* Next state! */
 
337
                        if (os_lseek(sbsf->fd, sbsf->off, OS_SEEK_SET) < 0) {
 
338
                                puts("sandbox_sf: os_lseek() failed");
 
339
                                return 1;
 
340
                        }
 
341
                        switch (sbsf->cmd) {
 
342
                        case CMD_READ_ARRAY_FAST:
 
343
                        case CMD_READ_ARRAY_SLOW:
 
344
                                sbsf->state = SF_READ;
 
345
                                break;
 
346
                        case CMD_PAGE_PROGRAM:
 
347
                                sbsf->state = SF_WRITE;
 
348
                                break;
 
349
                        default:
 
350
                                /* assume erase state ... */
 
351
                                sbsf->state = SF_ERASE;
 
352
                                goto case_sf_erase;
 
353
                        }
 
354
                        debug(" cmd: transition to %s state\n",
 
355
                              sandbox_sf_state_name(sbsf->state));
 
356
                        break;
 
357
                case SF_READ:
 
358
                        /*
 
359
                         * XXX: need to handle exotic behavior:
 
360
                         *      - reading past end of device
 
361
                         */
 
362
 
 
363
                        cnt = bytes - pos;
 
364
                        debug(" tx: read(%u)\n", cnt);
 
365
                        ret = os_read(sbsf->fd, tx + pos, cnt);
 
366
                        if (ret < 0) {
 
367
                                puts("sandbox_spi: os_read() failed\n");
 
368
                                return 1;
 
369
                        }
 
370
                        pos += ret;
 
371
                        break;
 
372
                case SF_READ_STATUS:
 
373
                        debug(" read status: %#x\n", sbsf->status);
 
374
                        cnt = bytes - pos;
 
375
                        memset(tx + pos, sbsf->status, cnt);
 
376
                        pos += cnt;
 
377
                        break;
 
378
                case SF_READ_STATUS1:
 
379
                        debug(" read status: %#x\n", sbsf->status);
 
380
                        cnt = bytes - pos;
 
381
                        memset(tx + pos, sbsf->status >> 8, cnt);
 
382
                        pos += cnt;
 
383
                        break;
 
384
                case SF_WRITE:
 
385
                        /*
 
386
                         * XXX: need to handle exotic behavior:
 
387
                         *      - unaligned addresses
 
388
                         *      - more than a page (256) worth of data
 
389
                         *      - reading past end of device
 
390
                         */
 
391
                        if (!(sbsf->status & STAT_WEL)) {
 
392
                                puts("sandbox_sf: write enable not set before write\n");
 
393
                                goto done;
 
394
                        }
 
395
 
 
396
                        cnt = bytes - pos;
 
397
                        debug(" rx: write(%u)\n", cnt);
 
398
                        sandbox_spi_tristate(&tx[pos], cnt);
 
399
                        ret = os_write(sbsf->fd, rx + pos, cnt);
 
400
                        if (ret < 0) {
 
401
                                puts("sandbox_spi: os_write() failed\n");
 
402
                                return 1;
 
403
                        }
 
404
                        pos += ret;
 
405
                        sbsf->status &= ~STAT_WEL;
 
406
                        break;
 
407
                case SF_ERASE:
 
408
 case_sf_erase: {
 
409
                        const struct sandbox_spi_flash_erase_commands *
 
410
                                                erase_cmd = sbsf->cmd_data;
 
411
 
 
412
                        if (!(sbsf->status & STAT_WEL)) {
 
413
                                puts("sandbox_sf: write enable not set before erase\n");
 
414
                                goto done;
 
415
                        }
 
416
 
 
417
                        /* verify address is aligned */
 
418
                        if (sbsf->off & (erase_cmd->size - 1)) {
 
419
                                debug(" sector erase: cmd:%#x needs align:%#x, but we got %#x\n",
 
420
                                      erase_cmd->cmd, erase_cmd->size,
 
421
                                      sbsf->off);
 
422
                                sbsf->status &= ~STAT_WEL;
 
423
                                goto done;
 
424
                        }
 
425
 
 
426
                        debug(" sector erase addr: %u\n", sbsf->off);
 
427
 
 
428
                        cnt = bytes - pos;
 
429
                        sandbox_spi_tristate(&tx[pos], cnt);
 
430
                        pos += cnt;
 
431
 
 
432
                        /*
 
433
                         * TODO(vapier@gentoo.org): latch WIP in status, and
 
434
                         * delay before clearing it ?
 
435
                         */
 
436
                        ret = sandbox_erase_part(sbsf, erase_cmd->size);
 
437
                        sbsf->status &= ~STAT_WEL;
 
438
                        if (ret) {
 
439
                                debug("sandbox_sf: Erase failed\n");
 
440
                                goto done;
 
441
                        }
 
442
                        goto done;
 
443
                }
 
444
                default:
 
445
                        debug(" ??? no idea what to do ???\n");
 
446
                        goto done;
 
447
                }
 
448
        }
 
449
 
 
450
 done:
 
451
        return pos == bytes ? 0 : 1;
 
452
}
 
453
 
 
454
static const struct sandbox_spi_emu_ops sandbox_sf_ops = {
 
455
        .setup         = sandbox_sf_setup,
 
456
        .free          = sandbox_sf_free,
 
457
        .cs_activate   = sandbox_sf_cs_activate,
 
458
        .cs_deactivate = sandbox_sf_cs_deactivate,
 
459
        .xfer          = sandbox_sf_xfer,
 
460
};
 
461
 
 
462
static int sandbox_cmdline_cb_spi_sf(struct sandbox_state *state,
 
463
                                     const char *arg)
 
464
{
 
465
        unsigned long bus, cs;
 
466
        const char *spec = sandbox_spi_parse_spec(arg, &bus, &cs);
 
467
 
 
468
        if (!spec)
 
469
                return 1;
 
470
 
 
471
        /*
 
472
         * It is safe to not make a copy of 'spec' because it comes from the
 
473
         * command line.
 
474
         *
 
475
         * TODO(sjg@chromium.org): It would be nice if we could parse the
 
476
         * spec here, but the problem is that no U-Boot init has been done
 
477
         * yet. Perhaps we can figure something out.
 
478
         */
 
479
        state->spi[bus][cs].ops = &sandbox_sf_ops;
 
480
        state->spi[bus][cs].spec = spec;
 
481
        return 0;
 
482
}
 
483
SANDBOX_CMDLINE_OPT(spi_sf, 1, "connect a SPI flash: <bus>:<cs>:<id>:<file>");