15
15
* Lesser General Public License for more details.
17
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this library; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
43
42
#include "qemu-timer.h"
45
#define PFLASH_BUG(fmt, args...) \
44
#define PFLASH_BUG(fmt, ...) \
47
printf("PFLASH: Possible BUG - " fmt, ##args); \
46
printf("PFLASH: Possible BUG - " fmt, ## __VA_ARGS__); \
51
50
/* #define PFLASH_DEBUG */
52
51
#ifdef PFLASH_DEBUG
53
#define DPRINTF(fmt, args...) \
52
#define DPRINTF(fmt, ...) \
55
printf("PFLASH: " fmt , ##args); \
54
printf("PFLASH: " fmt , ## __VA_ARGS__); \
58
#define DPRINTF(fmt, args...) do { } while (0)
57
#define DPRINTF(fmt, ...) do { } while (0)
62
61
BlockDriverState *bs;
64
target_ulong sector_len;
65
target_ulong total_len;
62
target_phys_addr_t base;
63
target_phys_addr_t sector_len;
64
target_phys_addr_t total_len;
67
66
int wcycle; /* if 0, the flash is read normally */
99
static uint32_t pflash_read (pflash_t *pfl, target_ulong offset, int width)
98
static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset,
101
target_phys_addr_t boff;
107
106
boff = offset & 0xFF; /* why this here ?? */
109
108
if (pfl->width == 2)
111
110
else if (pfl->width == 4)
112
111
boff = boff >> 2;
114
DPRINTF("%s: reading offset " TARGET_FMT_lx " under cmd %02x\n",
115
__func__, boff, pfl->cmd);
113
DPRINTF("%s: reading offset " TARGET_FMT_lx " under cmd %02x width %d\n",
114
__func__, offset, pfl->cmd, width);
117
116
switch (pfl->cmd) {
198
static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value,
197
static void inline pflash_data_write(pflash_t *pfl, target_phys_addr_t offset,
198
uint32_t value, int width)
200
uint8_t *p = pfl->storage;
202
DPRINTF("%s: block write offset " TARGET_FMT_lx
203
" value %x counter " TARGET_FMT_lx "\n",
204
__func__, offset, value, pfl->counter);
208
pflash_update(pfl, offset, 1);
211
#if defined(TARGET_WORDS_BIGENDIAN)
212
p[offset] = value >> 8;
213
p[offset + 1] = value;
216
p[offset + 1] = value >> 8;
218
pflash_update(pfl, offset, 2);
221
#if defined(TARGET_WORDS_BIGENDIAN)
222
p[offset] = value >> 24;
223
p[offset + 1] = value >> 16;
224
p[offset + 2] = value >> 8;
225
p[offset + 3] = value;
228
p[offset + 1] = value >> 8;
229
p[offset + 2] = value >> 16;
230
p[offset + 3] = value >> 24;
232
pflash_update(pfl, offset, 4);
238
static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
239
uint32_t value, int width)
241
target_phys_addr_t boff;
205
/* WARNING: when the memory area is in ROMD mode, the offset is a
206
ram offset, not a physical address */
209
if (pfl->wcycle == 0)
210
offset -= (target_ulong)(long)pfl->storage;
214
DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d wcycle 0x%x\n",
247
DPRINTF("%s: writing offset " TARGET_FMT_lx " value %08x width %d wcycle 0x%x\n",
215
248
__func__, offset, value, width, pfl->wcycle);
217
250
/* Set the device in I/O access mode */
230
263
case 0x00: /* ??? */
231
264
goto reset_flash;
265
case 0x10: /* Single Byte Program */
266
case 0x40: /* Single Byte Program */
267
DPRINTF(stderr, "%s: Single Byte Program\n", __func__);
232
269
case 0x20: /* Block erase */
233
270
p = pfl->storage;
234
271
offset &= ~(pfl->sector_len - 1);
272
309
switch (pfl->cmd) {
310
case 0x10: /* Single Byte Program */
311
case 0x40: /* Single Byte Program */
312
DPRINTF("%s: Single Byte Program\n", __func__);
313
pflash_data_write(pfl, offset, value, width);
314
pfl->status |= 0x80; /* Ready! */
273
317
case 0x20: /* Block erase */
275
319
if (cmd == 0xd0) { /* confirm */
277
321
pfl->status |= 0x80;
278
322
} else if (cmd == 0xff) { /* read array mode */
279
323
goto reset_flash;
315
359
switch (pfl->cmd) {
316
360
case 0xe8: /* Block write */
318
DPRINTF("%s: block write offset " TARGET_FMT_lx
319
" value %x counter " TARGET_FMT_lx "\n",
320
__func__, offset, value, pfl->counter);
324
pflash_update(pfl, offset, 1);
327
#if defined(TARGET_WORDS_BIGENDIAN)
328
p[offset] = value >> 8;
329
p[offset + 1] = value;
332
p[offset + 1] = value >> 8;
334
pflash_update(pfl, offset, 2);
337
#if defined(TARGET_WORDS_BIGENDIAN)
338
p[offset] = value >> 24;
339
p[offset + 1] = value >> 16;
340
p[offset + 2] = value >> 8;
341
p[offset + 3] = value;
344
p[offset + 1] = value >> 8;
345
p[offset + 2] = value >> 16;
346
p[offset + 3] = value >> 24;
348
pflash_update(pfl, offset, 4);
361
pflash_data_write(pfl, offset, value, width);
352
363
pfl->status |= 0x80;
389
400
printf("%s: Unimplemented flash cmd sequence "
390
"(offset " TARGET_FMT_lx ", wcycle 0x%x cmd 0x%x value 0x%x\n",
401
"(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)\n",
391
402
__func__, offset, pfl->wcycle, pfl->cmd, value);
442
453
pflash_write(pfl, addr, value, 4);
445
static CPUWriteMemoryFunc *pflash_write_ops[] = {
456
static CPUWriteMemoryFunc * const pflash_write_ops[] = {
451
static CPUReadMemoryFunc *pflash_read_ops[] = {
462
static CPUReadMemoryFunc * const pflash_read_ops[] = {
509
521
pfl = qemu_mallocz(sizeof(pflash_t));
513
pfl->storage = phys_ram_base + off;
514
pfl->fl_mem = cpu_register_io_memory(0,
523
/* FIXME: Allocate ram ourselves. */
524
pfl->storage = qemu_get_ram_ptr(off);
525
pfl->fl_mem = cpu_register_io_memory(
515
526
pflash_read_ops, pflash_write_ops, pfl);
517
528
cpu_register_physical_memory(base, total_len,
522
533
/* read the initial flash content */
523
bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
534
ret = bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
536
cpu_unregister_io_memory(pfl->fl_mem);
525
541
#if 0 /* XXX: there should be a bit to set up read-only,
526
542
* the same way the hardware does (with WP pin).
589
605
pfl->cfi_table[0x28] = 0x02;
590
606
pfl->cfi_table[0x29] = 0x00;
591
607
/* Max number of bytes in multi-bytes write */
592
pfl->cfi_table[0x2A] = 0x04;
608
pfl->cfi_table[0x2A] = 0x0B;
593
609
pfl->cfi_table[0x2B] = 0x00;
594
610
/* Number of erase block regions (uniform) */
595
611
pfl->cfi_table[0x2C] = 0x01;