[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v8 12/24] hw/arm: add FTNANDC021 nand flash controll
From: |
Kuo-Jung Su |
Subject: |
[Qemu-devel] [PATCH v8 12/24] hw/arm: add FTNANDC021 nand flash controller support |
Date: |
Fri, 15 Mar 2013 21:15:24 +0800 |
From: Kuo-Jung Su <address@hidden>
The FTNANDC021 is an integrated NAND flash controller which
re-pack the NAND flash command set with a shorter built-in opcode.
It also provides a register base interface for user to easily
access the underlying NAND flash chips, and also supports HW ECC.
However the optional hardware ECC function is not implemented.
Signed-off-by: Kuo-Jung Su <address@hidden>
---
hw/arm/Makefile.objs | 1 +
hw/arm/faraday_a369.c | 14 ++
hw/arm/faraday_a369_soc.c | 9 +
hw/arm/ftnandc021.c | 516 +++++++++++++++++++++++++++++++++++++++++++++
hw/arm/ftnandc021.h | 84 ++++++++
5 files changed, 624 insertions(+)
create mode 100644 hw/arm/ftnandc021.c
create mode 100644 hw/arm/ftnandc021.h
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index cc5e343..2622f3f 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -45,3 +45,4 @@ obj-y += ftwdt010.o
obj-y += ftrtc011.o
obj-y += ftdmac020.o
obj-y += ftapbbrg020.o
+obj-y += ftnandc021.o
diff --git a/hw/arm/faraday_a369.c b/hw/arm/faraday_a369.c
index 3a89a04..c85de25 100644
--- a/hw/arm/faraday_a369.c
+++ b/hw/arm/faraday_a369.c
@@ -25,6 +25,8 @@ a369_board_init(QEMUMachineInitArgs *args)
{
DeviceState *ds;
FaradaySoCState *s;
+ DriveInfo *dinfo;
+ Error *local_errp = NULL;
if (!args->cpu_model) {
args->cpu_model = "fa626te";
@@ -46,6 +48,18 @@ a369_board_init(QEMUMachineInitArgs *args)
s = FARADAY_SOC(ds);
+ /* Attach the nand flash to ftnandc021 */
+ dinfo = drive_get_next(IF_MTD);
+ ds = nand_init(dinfo ? dinfo->bdrv : NULL, NAND_MFR_SAMSUNG, 0xda);
+ object_property_set_link(OBJECT(s->nandc[0]),
+ OBJECT(ds),
+ "flash",
+ &local_errp);
+ if (local_errp) {
+ fprintf(stderr, "a369: Unable to set flash link for FTNANDC021\n");
+ abort();
+ }
+
/* System start-up */
if (args->kernel_filename) {
diff --git a/hw/arm/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c
index bb80537..0088915 100644
--- a/hw/arm/faraday_a369_soc.c
+++ b/hw/arm/faraday_a369_soc.c
@@ -84,6 +84,7 @@ a369soc_device_init(FaradaySoCState *s)
DriveInfo *dinfo;
DeviceState *ds;
qemu_irq *cpu_pic;
+ qemu_irq ack, req;
int i;
s->as = get_system_memory();
@@ -232,6 +233,14 @@ a369soc_device_init(FaradaySoCState *s)
fprintf(stderr, "a369soc: Unable to set soc link for FTAPBBRG020\n");
abort();
}
+
+ /* ftnandc021 */
+ ds = sysbus_create_simple("ftnandc021", 0x90200000, s->pic[30]);
+ s->nandc[0] = ds;
+ ack = qdev_get_gpio_in(ds, 0);
+ req = qdev_get_gpio_in(s->hdma[0], 15);
+ qdev_connect_gpio_out(s->hdma[0], 15, ack);
+ qdev_connect_gpio_out(ds, 0, req);
}
static void a369soc_realize(DeviceState *dev, Error **errp)
diff --git a/hw/arm/ftnandc021.c b/hw/arm/ftnandc021.c
new file mode 100644
index 0000000..8b4c84c
--- /dev/null
+++ b/hw/arm/ftnandc021.c
@@ -0,0 +1,516 @@
+/*
+ * QEMU model of the FTNANDC021 NAND Flash Controller
+ *
+ * Copyright (C) 2012 Faraday Technology
+ * Written by Dante Su <address@hidden>
+ *
+ * This file is licensed under GNU GPL v2+.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/devices.h"
+#include "hw/flash.h"
+#include "sysemu/blockdev.h"
+
+#include "ftnandc021.h"
+
+#define TYPE_FTNANDC021 "ftnandc021"
+
+typedef struct Ftnandc021State {
+ SysBusDevice busdev;
+ MemoryRegion mmio;
+
+ qemu_irq irq;
+ DeviceState *flash;
+
+ /* DMA hardware handshake */
+ qemu_irq req;
+
+ uint8_t manf_id, chip_id;
+
+ int cmd;
+ int len; /* buffer length for page read/write */
+ int pi; /* page index */
+ int bw; /* bus width (8-bits, 16-bits) */
+
+ uint64_t size; /* flash size (maximum access range) */
+ uint32_t pgsz; /* page size (Bytes) */
+ uint32_t bksz; /* block size (Bytes) */
+ uint32_t alen; /* address length (cycle) */
+
+ uint32_t id[2];
+ uint8_t oob[8];/* 5 bytes for 512/2048 page; 7 bytes for 4096 page */
+
+ /* HW register caches */
+ uint32_t sr;
+ uint32_t fcr;
+ uint32_t mcr;
+ uint32_t ier;
+ uint32_t bcr;
+} Ftnandc021State;
+
+#define FTNANDC021(obj) \
+ OBJECT_CHECK(Ftnandc021State, obj, TYPE_FTNANDC021)
+
+static void ftnandc021_update_irq(Ftnandc021State *s)
+{
+ if (s->ier & IER_ENA) {
+ if ((s->ier & 0x0f) & (s->sr >> 2)) {
+ qemu_set_irq(s->irq, 1);
+ } else {
+ qemu_set_irq(s->irq, 0);
+ }
+ }
+}
+
+static void ftnandc021_set_idle(Ftnandc021State *s)
+{
+ /* CLE=0, ALE=0, CS=1 */
+ nand_setpins(s->flash, 0, 0, 1, 1, 0);
+
+ /* Set command compelete */
+ s->sr |= SR_CMD;
+
+ /* Update IRQ signal */
+ ftnandc021_update_irq(s);
+}
+
+static void ftnandc021_set_cmd(Ftnandc021State *s, uint8_t cmd)
+{
+ /* CLE=1, ALE=0, CS=0 */
+ nand_setpins(s->flash, 1, 0, 0, 1, 0);
+
+ /* Write out command code */
+ nand_setio(s->flash, cmd);
+}
+
+static void ftnandc021_set_addr(Ftnandc021State *s, int col, int row)
+{
+ /* CLE=0, ALE=1, CS=0 */
+ nand_setpins(s->flash, 0, 1, 0, 1, 0);
+
+ if (col < 0 && row < 0) {
+ /* special case for READ_ID (0x90) */
+ nand_setio(s->flash, 0);
+ } else {
+ /* column address */
+ if (col >= 0) {
+ nand_setio(s->flash, extract32(col, 0, 8));
+ nand_setio(s->flash, extract32(col, 8, 8));
+ }
+ /* row address */
+ if (row >= 0) {
+ nand_setio(s->flash, extract32(row, 0, 8));
+ if (s->alen >= 4) {
+ nand_setio(s->flash, extract32(row, 8, 8));
+ }
+ if (s->alen >= 5) {
+ nand_setio(s->flash, extract32(row, 16, 8));
+ }
+ }
+ }
+}
+
+static void ftnandc021_handle_ack(void *opaque, int line, int level)
+{
+ Ftnandc021State *s = FTNANDC021(opaque);
+
+ if (!s->bcr) {
+ return;
+ }
+
+ if (level) {
+ qemu_set_irq(s->req, 0);
+ } else if (s->len > 0) {
+ qemu_set_irq(s->req, 1);
+ }
+}
+
+static void ftnandc021_command(Ftnandc021State *s, uint32_t cmd)
+{
+ int i;
+
+ s->sr &= ~SR_CMD;
+ s->cmd = cmd;
+
+ switch (cmd) {
+ case FTNANDC021_CMD_RDID: /* read id */
+ ftnandc021_set_cmd(s, 0x90);
+ ftnandc021_set_addr(s, -1, -1);
+ nand_setpins(s->flash, 0, 0, 0, 1, 0);
+ if (s->bw == 8) {
+ s->id[0] = (nand_getio(s->flash) << 0)
+ | (nand_getio(s->flash) << 8)
+ | (nand_getio(s->flash) << 16)
+ | (nand_getio(s->flash) << 24);
+ s->id[1] = (nand_getio(s->flash) << 0);
+ } else {
+ s->id[0] = (nand_getio(s->flash) << 0)
+ | (nand_getio(s->flash) << 16);
+ s->id[1] = (nand_getio(s->flash) << 0);
+ }
+ break;
+ case FTNANDC021_CMD_RESET: /* reset */
+ ftnandc021_set_cmd(s, 0xff);
+ break;
+ case FTNANDC021_CMD_RDST: /* read status */
+ ftnandc021_set_cmd(s, 0x70);
+ nand_setpins(s->flash, 0, 0, 0, 1, 0);
+ s->id[1] = (nand_getio(s->flash) << 0);
+ break;
+ case FTNANDC021_CMD_RDPG: /* read page */
+ ftnandc021_set_cmd(s, 0x00);
+ ftnandc021_set_addr(s, 0, s->pi);
+ ftnandc021_set_cmd(s, 0x30);
+ nand_setpins(s->flash, 0, 0, 0, 1, 0);
+ s->len = s->pgsz;
+ break;
+ case FTNANDC021_CMD_RDOOB: /* read oob */
+ ftnandc021_set_cmd(s, 0x00);
+ ftnandc021_set_addr(s, s->pgsz, s->pi);
+ ftnandc021_set_cmd(s, 0x30);
+ nand_setpins(s->flash, 0, 0, 0, 1, 0);
+ for (i = 0; i < 16 * (s->pgsz / 512); ) {
+ if (s->bw == 8) {
+ if (i < 7) {
+ s->oob[i] = (uint8_t)nand_getio(s->flash);
+ } else {
+ (void)nand_getio(s->flash);
+ }
+ i += 1;
+ } else {
+ if (i < 7) {
+ *(uint16_t *)(s->oob + i) = (uint16_t)nand_getio(s->flash);
+ } else {
+ (void)nand_getio(s->flash);
+ }
+ i += 2;
+ }
+ }
+ break;
+ case FTNANDC021_CMD_WRPG: /* write page + read status */
+ ftnandc021_set_cmd(s, 0x80);
+ ftnandc021_set_addr(s, 0, s->pi);
+ /* data phase */
+ nand_setpins(s->flash, 0, 0, 0, 1, 0);
+ s->len = s->pgsz;
+ break;
+ case FTNANDC021_CMD_ERBLK: /* erase block + read status */
+ ftnandc021_set_cmd(s, 0x60);
+ ftnandc021_set_addr(s, -1, s->pi);
+ ftnandc021_set_cmd(s, 0xd0);
+ /* read status */
+ ftnandc021_command(s, 0x04);
+ break;
+ case FTNANDC021_CMD_WROOB: /* write oob + read status */
+ ftnandc021_set_cmd(s, 0x80);
+ ftnandc021_set_addr(s, s->pgsz, s->pi);
+ /* data phase */
+ nand_setpins(s->flash, 0, 0, 0, 1, 0);
+ for (i = 0; i < 16 * (s->pgsz / 512); ) {
+ if (s->bw == 8) {
+ if (i <= 7) {
+ nand_setio(s->flash, s->oob[i]);
+ } else {
+ nand_setio(s->flash, 0xffffffff);
+ }
+ i += 1;
+ } else {
+ if (i <= 7) {
+ nand_setio(s->flash, s->oob[i] | (s->oob[i + 1] << 8));
+ } else {
+ nand_setio(s->flash, 0xffffffff);
+ }
+ i += 2;
+ }
+ }
+ ftnandc021_set_cmd(s, 0x10);
+ /* read status */
+ ftnandc021_command(s, 0x04);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ftnandc021: unknow command=0x%02x\n", cmd);
+ break;
+ }
+
+ /* if cmd is not page read/write, then return to idle mode */
+ switch (s->cmd) {
+ case FTNANDC021_CMD_RDPG:
+ case FTNANDC021_CMD_WRPG:
+ if (s->bcr && (s->len > 0)) {
+ qemu_set_irq(s->req, 1);
+ }
+ break;
+ default:
+ ftnandc021_set_idle(s);
+ break;
+ }
+}
+
+static uint64_t
+ftnandc021_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+ uint32_t i, ret = 0;
+ Ftnandc021State *s = FTNANDC021(opaque);
+
+ switch (addr) {
+ case REG_DR:
+ if ((s->cmd == FTNANDC021_CMD_RDPG) && (s->len > 0)) {
+ if (s->bw == 8) {
+ for (i = 0; i < 4 && s->len > 0; i++, s->len--) {
+ ret = deposit32(ret, i * 8, 8, nand_getio(s->flash));
+ }
+ } else {
+ for (i = 0; i < 2 && s->len > 1; i++, s->len -= 2) {
+ ret = deposit32(ret, i * 16, 16, nand_getio(s->flash));
+ }
+ }
+ if (s->len <= 0) {
+ ftnandc021_set_idle(s);
+ }
+ }
+ break;
+ case REG_SR:
+ return s->sr;
+ case REG_ACR:
+ return s->cmd << 8;
+ case REG_RDBR:
+ return s->oob[0];
+ case REG_RDLSN:
+ return s->oob[1] | (s->oob[2] << 8);
+ case REG_RDCRC:
+ if (s->pgsz > 2048) {
+ return s->oob[3] | (s->oob[4] << 8)
+ | (s->oob[5] << 16) | (s->oob[6] << 24);
+ } else {
+ return s->oob[3] | (s->oob[4] << 8);
+ }
+ case REG_FCR:
+ return s->fcr;
+ case REG_PIR:
+ return s->pi;
+ case REG_PCR:
+ return 1; /* page count = 1 */
+ case REG_MCR:
+ return s->mcr;
+ case REG_IDRL:
+ return s->id[0];
+ case REG_IDRH:
+ return s->id[1];
+ case REG_IER:
+ return s->ier;
+ case REG_BCR:
+ return s->bcr;
+ case REG_ATR1:
+ return 0x02240264; /* AC Timing */
+ case REG_ATR2:
+ return 0x42054209; /* AC Timing */
+ case REG_PRR:
+ return 0x00000001; /* Always ready for I/O */
+ case REG_REVR:
+ return 0x00010100; /* Rev. 1.1.0 */
+ case REG_CFGR:
+ return 0x00081601; /* 8-bit BCH, 16 bit flash, 1 chip */
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ftnandc021: undefined memory address@hidden" HWADDR_PRIx "\n",
addr);
+ break;
+ }
+
+ return ret;
+}
+
+static void
+ftnandc021_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+ uint32_t i;
+ Ftnandc021State *s = FTNANDC021(opaque);
+
+ switch (addr) {
+ case REG_DR:
+ if (s->cmd == FTNANDC021_CMD_WRPG && s->len > 0) {
+ if (s->bw == 8) {
+ for (i = 0; i < 4 && s->len > 0; i++, s->len--) {
+ nand_setio(s->flash,
+ extract32((uint32_t)val, i * 8, 8));
+ }
+ } else {
+ for (i = 0; i < 2 && s->len > 1; i++, s->len -= 2) {
+ nand_setio(s->flash,
+ extract32((uint32_t)val, i * 16, 16));
+ }
+ }
+ if (s->len <= 0) {
+ ftnandc021_set_cmd(s, 0x10);
+ /* read status */
+ ftnandc021_command(s, 0x04);
+ }
+ }
+ break;
+ case REG_ACR:
+ if (!(val & ACR_START)) {
+ break;
+ }
+ ftnandc021_command(s, extract32((uint32_t)val, 8, 5));
+ break;
+ case REG_WRBR:
+ s->oob[0] = (uint32_t)val & 0xff;
+ break;
+ case REG_WRLSN:
+ s->oob[1] = ((uint32_t)val >> 0) & 0xff;
+ s->oob[2] = ((uint32_t)val >> 8) & 0xff;
+ break;
+ case REG_WRCRC:
+ s->oob[3] = ((uint32_t)val >> 0) & 0xff;
+ s->oob[4] = ((uint32_t)val >> 8) & 0xff;
+ if (s->pgsz > 2048) {
+ s->oob[5] = ((uint32_t)val >> 16) & 0xff;
+ s->oob[6] = ((uint32_t)val >> 24) & 0xff;
+ }
+ break;
+ case REG_FCR:
+ s->fcr = (uint32_t)val;
+ if (s->fcr & FCR_16BIT) {
+ s->bw = 16;
+ } else {
+ s->bw = 8;
+ }
+ break;
+ case REG_PIR:
+ s->pi = (uint32_t)val & 0x03ffffff;
+ break;
+ case REG_MCR:
+ s->mcr = (uint32_t)val;
+ /* page size */
+ switch (extract32(s->mcr, 8, 2)) {
+ case 0:
+ s->pgsz = 512;
+ break;
+ case 2:
+ s->pgsz = 4096;
+ break;
+ default:
+ s->pgsz = 2048;
+ break;
+ }
+ /* block size */
+ s->bksz = s->pgsz * (1 << (4 + extract32(s->mcr, 16, 2)));
+ /* address length (cycle) */
+ s->alen = 3 + extract32(s->mcr, 10, 2);
+ /* flash size */
+ s->size = 1ULL << (24 + extract32(s->mcr, 4, 4));
+ break;
+ case REG_IER:
+ s->ier = (uint32_t)val & 0x8f;
+ ftnandc021_update_irq(s);
+ break;
+ case REG_ISCR:
+ s->sr &= ~(((uint32_t)val & 0x0f) << 2);
+ ftnandc021_update_irq(s);
+ break;
+ case REG_BCR:
+ s->bcr = (uint32_t)val;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ftnandc021: undefined memory address@hidden" HWADDR_PRIx "\n",
addr);
+ break;
+ }
+}
+
+static const MemoryRegionOps mmio_ops = {
+ .read = ftnandc021_mem_read,
+ .write = ftnandc021_mem_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+static void ftnandc021_reset(DeviceState *ds)
+{
+ Ftnandc021State *s = FTNANDC021(SYS_BUS_DEVICE(ds));
+ Error *local_errp = NULL;
+
+ s->flash = DEVICE(object_property_get_link(OBJECT(s),
+ "flash",
+ &local_errp));
+ if (local_errp) {
+ fprintf(stderr, "ftnandc021: Unable to get flash link\n");
+ abort();
+ }
+
+ s->sr = 0;
+ s->fcr = 0;
+ s->mcr = 0;
+ s->ier = 0;
+ s->bcr = 0;
+ s->id[0] = 0;
+ s->id[1] = 0;
+
+ /* We can assume our GPIO outputs have been wired up now */
+ qemu_set_irq(s->req, 0);
+}
+
+static void ftnandc021_realize(DeviceState *dev, Error **errp)
+{
+ Ftnandc021State *s = FTNANDC021(dev);
+
+ memory_region_init_io(&s->mmio,
+ &mmio_ops,
+ s,
+ TYPE_FTNANDC021,
+ 0x1000);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
+
+ qdev_init_gpio_in(&s->busdev.qdev, ftnandc021_handle_ack, 1);
+ qdev_init_gpio_out(&s->busdev.qdev, &s->req, 1);
+
+ object_property_add_link(OBJECT(dev),
+ "flash",
+ TYPE_DEVICE,
+ (Object **) &s->flash,
+ errp);
+}
+
+static const VMStateDescription vmstate_ftnandc021 = {
+ .name = TYPE_FTNANDC021,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(sr, Ftnandc021State),
+ VMSTATE_UINT32(fcr, Ftnandc021State),
+ VMSTATE_UINT32(mcr, Ftnandc021State),
+ VMSTATE_UINT32(ier, Ftnandc021State),
+ VMSTATE_UINT32(bcr, Ftnandc021State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void ftnandc021_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_ftnandc021;
+ dc->reset = ftnandc021_reset;
+ dc->realize = ftnandc021_realize;
+ dc->no_user = 1;
+}
+
+static const TypeInfo ftnandc021_info = {
+ .name = TYPE_FTNANDC021,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Ftnandc021State),
+ .class_init = ftnandc021_class_init,
+};
+
+static void ftnandc021_register_types(void)
+{
+ type_register_static(&ftnandc021_info);
+}
+
+type_init(ftnandc021_register_types)
diff --git a/hw/arm/ftnandc021.h b/hw/arm/ftnandc021.h
new file mode 100644
index 0000000..199de95
--- /dev/null
+++ b/hw/arm/ftnandc021.h
@@ -0,0 +1,84 @@
+/*
+ * QEMU model of the FTNANDC021 NAND Flash Controller
+ *
+ * Copyright (C) 2012 Faraday Technology
+ * Written by Dante Su <address@hidden>
+ *
+ * This file is licensed under GNU GPL v2+.
+ */
+
+#ifndef HW_ARM_FTNANDC021_H
+#define HW_ARM_FTNANDC021_H
+
+#include "qemu/bitops.h"
+
+/* NANDC control registers */
+#define REG_SR 0x100 /* Status Register */
+#define REG_ACR 0x104 /* Access Control Register */
+#define REG_FCR 0x108 /* Flow Control Register */
+#define REG_PIR 0x10C /* Page Index Register */
+#define REG_MCR 0x110 /* Memory Configuration Register */
+#define REG_ATR1 0x114 /* AC Timing Register 1 */
+#define REG_ATR2 0x118 /* AC Timing Register 2 */
+#define REG_IDRL 0x120 /* ID Register LSB */
+#define REG_IDRH 0x124 /* ID Register MSB */
+#define REG_IER 0x128 /* Interrupt Enable Register */
+#define REG_ISCR 0x12C /* Interrupt Status Clear Register */
+#define REG_WRBR 0x140 /* Write Bad Block Register */
+#define REG_WRLSN 0x144 /* Write LSN Register */
+#define REG_WRCRC 0x148 /* Write LSN CRC Register */
+#define REG_RDBR 0x150 /* Read Bad Block Register */
+#define REG_RDLSN 0x154 /* Read LSN Register */
+#define REG_RDCRC 0x158 /* Read LSN CRC Register */
+
+/* BMC control registers */
+#define REG_PRR 0x208 /* BMC PIO Ready Register */
+#define REG_BCR 0x20C /* BMC Burst Control Register */
+
+/** MISC register **/
+#define REG_DR 0x300 /* Data Register */
+#define REG_PCR 0x308 /* Page Count Register */
+#define REG_RSTR 0x30C /* MLC Reset Register */
+#define REG_REVR 0x3F8 /* Revision Register */
+#define REG_CFGR 0x3FC /* Configuration Register */
+
+
+/*
+ * Register BITMASK
+ */
+#define SR_BLANK BIT(7) /* blanking check failed */
+#define SR_ECC BIT(6) /* ecc failed */
+#define SR_STS BIT(4) /* status error */
+#define SR_CRC BIT(3) /* crc error */
+#define SR_CMD BIT(2) /* command finished */
+#define SR_BUSY BIT(1) /* chip busy */
+#define SR_ENA BIT(0) /* chip enabled */
+
+#define ACR_CMD(x) (((x) & 0x1f) << 8) /* command code */
+#define ACR_START BIT(7) /* command start */
+
+#define FCR_16BIT BIT(4) /* 16 bit data bus */
+#define FCR_WPROT BIT(3) /* write protected */
+#define FCR_NOSC BIT(2) /* bypass status check error */
+#define FCR_MICRON BIT(1) /* Micron 2-plane command */
+#define FCR_NOBC BIT(0) /* skip blanking check error */
+
+#define IER_ENA BIT(7) /* interrupt enabled */
+#define IER_ECC BIT(3) /* ecc error timeout */
+#define IER_STS BIT(2) /* status error */
+#define IER_CRC BIT(1) /* crc error */
+#define IER_CMD BIT(0) /* command finished */
+
+/*
+ * FTNANDC021 integrated command set
+ */
+#define FTNANDC021_CMD_RDID 0x01 /* read id */
+#define FTNANDC021_CMD_RESET 0x02
+#define FTNANDC021_CMD_RDST 0x04 /* read status */
+#define FTNANDC021_CMD_RDPG 0x05 /* read page (data + oob) */
+#define FTNANDC021_CMD_RDOOB 0x06 /* read oob */
+#define FTNANDC021_CMD_WRPG 0x10 /* write page (data + oob) */
+#define FTNANDC021_CMD_ERBLK 0x11 /* erase block */
+#define FTNANDC021_CMD_WROOB 0x13 /* write oob */
+
+#endif
--
1.7.9.5
- [Qemu-devel] [PATCH v8 04/24] hw/arm: add FTAHBC020 AHB controller support, (continued)
- [Qemu-devel] [PATCH v8 04/24] hw/arm: add FTAHBC020 AHB controller support, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 03/24] hw/arm: add FTINTC020 interrupt controller support, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 06/24] hw/arm: add FTPWMTMR010 timer support, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII controller support, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 08/24] hw/arm: add FTRTC011 RTC timer support, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 09/24] tests: add QTest for FTRTC011, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 10/24] hw/arm: add FTDMAC020 AHB DMA support, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 07/24] hw/arm: add FTWDT010 watchdog timer support, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 11/24] hw/arm: add FTAPBBRG020 APB DMA support, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 14/24] hw: Add AudioCodecClass for wm87xx audio class abstration., Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 12/24] hw/arm: add FTNANDC021 nand flash controller support,
Kuo-Jung Su <=
- [Qemu-devel] [PATCH v8 15/24] hw: add WM8731 audio codec support, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 17/24] qemu/bitops.h: add the bit ordering reversal functions, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 13/24] hw/arm: add FTI2C010 I2C controller support, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 16/24] hw/arm: add FTSSP010 multi-function controller support, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 20/24] hw/arm: add FTTSC010 touchscreen controller support, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 19/24] hw/arm: add FTLCDC200 LCD controller support, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 21/24] hw/arm: add FTSDC010 MMC/SD controller support, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 18/24] hw/arm: add FTGMAC100 1Gbps ethernet support, Kuo-Jung Su, 2013/03/15