All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices
@ 2011-07-15 14:58 Peter Maydell
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 01/12] hw/nand: Pass block device state to init function Peter Maydell
                   ` (12 more replies)
  0 siblings, 13 replies; 14+ messages in thread
From: Peter Maydell @ 2011-07-15 14:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki, Markus Armbruster, patches

This patchseries is more goodies from the Meego tree. Specifically, various
bug fixes to hw/nand and hw/onenand, plus conversion of both to sysbus.

[An advance note on the next thing due to come out of the pipe: qdeving
nand and onenand allows us to move to qdevification of omap_gpmc, which
takes both of those (and other things) as 'downstream' devices. That
change will make it accept arbitrary SysBus devices as its 'downstream'
devices rather than the current setup of taking an opaque pointer and a
pair of resize/unmap function pointers. (There are also patches which add
NAND support so you can tell omap_gpmc "this is a NAND device" and it then
uses the nand_setpins/nand_getpins/nand_setio interface.) The rationale for
using SysBus there rather than defining some new kind of bus is that you
want to be able to plug any random thing into it; for instance the Overo
board has a lan9118 ethernet controller hanging off the GPMC. ]

A note on dependencies:
 * This patch depends on the omap gpio patchset (although more textually
   than seriously semantically)
 * the six nand patches and the six onenand patches are broadly independent
   of each other

Juha Riihimäki (9):
  hw/nand: Support large NAND devices
  hw/nand: Support devices wider than 8 bits
  hw/nand: Support multiple reads following READ STATUS
  hw/nand: qdevify
  onenand: Handle various ID fields separately
  onenand: Ignore zero writes to boot command space
  hw/onenand: program actions can only clear bits
  hw/sysbus: Add sysbus_mmio_unmap() for unmapping a region
  hw/onenand: qdevify

Peter Maydell (3):
  hw/nand: Pass block device state to init function
  hw/nand: Writing to NAND can only clear bits
  onenand: Pass BlockDriverState to init function

 hw/axis_dev88.c |    8 +-
 hw/flash.h      |   19 ++--
 hw/nand.c       |  345 ++++++++++++++++++++++++++++++++-------------------
 hw/nseries.c    |   13 ++-
 hw/onenand.c    |  373 +++++++++++++++++++++++++++++++++++++++++++------------
 hw/spitz.c      |    6 +-
 hw/sysbus.c     |   17 +++
 hw/sysbus.h     |    1 +
 hw/tc6393xb.c   |    7 +-
 9 files changed, 561 insertions(+), 228 deletions(-)

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH 01/12] hw/nand: Pass block device state to init function
  2011-07-15 14:58 [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices Peter Maydell
@ 2011-07-15 14:58 ` Peter Maydell
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 02/12] hw/nand: Support large NAND devices Peter Maydell
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2011-07-15 14:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki, Markus Armbruster, patches

Pass the BlockDeviceState to the nand_init() function rather
than having it look it up via drive_get() itself.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/axis_dev88.c |    6 +++++-
 hw/flash.h      |    2 +-
 hw/nand.c       |    8 ++------
 hw/spitz.c      |    4 +++-
 hw/tc6393xb.c   |    5 ++++-
 5 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
index 0e2135a..de1f5a5 100644
--- a/hw/axis_dev88.c
+++ b/hw/axis_dev88.c
@@ -30,6 +30,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "cris-boot.h"
+#include "blockdev.h"
 
 #define D(x)
 #define DNAND(x)
@@ -251,6 +252,7 @@ void axisdev88_init (ram_addr_t ram_size,
     CPUState *env;
     DeviceState *dev;
     SysBusDevice *s;
+    DriveInfo *nand;
     qemu_irq irq[30], nmi[2], *cpu_irq;
     void *etraxfs_dmac;
     struct etraxfs_dma_client *eth[2] = {NULL, NULL};
@@ -278,7 +280,9 @@ void axisdev88_init (ram_addr_t ram_size,
 
 
       /* Attach a NAND flash to CS1.  */
-    nand_state.nand = nand_init(NAND_MFR_STMICRO, 0x39);
+    nand = drive_get(IF_MTD, 0, 0);
+    nand_state.nand = nand_init(nand ? nand->bdrv : NULL,
+                                NAND_MFR_STMICRO, 0x39);
     nand_regs = cpu_register_io_memory(nand_read, nand_write, &nand_state,
                                        DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(0x10000000, 0x05000000, nand_regs);
diff --git a/hw/flash.h b/hw/flash.h
index c22e1a9..a992bb8 100644
--- a/hw/flash.h
+++ b/hw/flash.h
@@ -19,7 +19,7 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
 
 /* nand.c */
 typedef struct NANDFlashState NANDFlashState;
-NANDFlashState *nand_init(int manf_id, int chip_id);
+NANDFlashState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id);
 void nand_done(NANDFlashState *s);
 void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
                   uint8_t ce, uint8_t wp, uint8_t gnd);
diff --git a/hw/nand.c b/hw/nand.c
index 37e51d7..d6204d9 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -14,7 +14,6 @@
 # include "hw.h"
 # include "flash.h"
 # include "blockdev.h"
-/* FIXME: Pass block device as an argument.  */
 
 # define NAND_CMD_READ0		0x00
 # define NAND_CMD_READ1		0x01
@@ -451,20 +450,17 @@ uint8_t nand_getio(NANDFlashState *s)
     return *(s->ioaddr ++);
 }
 
-NANDFlashState *nand_init(int manf_id, int chip_id)
+NANDFlashState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
 {
     int pagesize;
     NANDFlashState *s;
-    DriveInfo *dinfo;
 
     if (nand_flash_ids[chip_id].size == 0) {
         hw_error("%s: Unsupported NAND chip ID.\n", __FUNCTION__);
     }
 
     s = (NANDFlashState *) qemu_mallocz(sizeof(NANDFlashState));
-    dinfo = drive_get(IF_MTD, 0, 0);
-    if (dinfo)
-        s->bdrv = dinfo->bdrv;
+    s->bdrv = bdrv;
     s->manf_id = manf_id;
     s->chip_id = chip_id;
     s->size = nand_flash_ids[s->chip_id].size << 20;
diff --git a/hw/spitz.c b/hw/spitz.c
index 006f7a9..78e9c34 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -169,11 +169,13 @@ static void sl_flash_register(PXA2xxState *cpu, int size)
 static int sl_nand_init(SysBusDevice *dev) {
     int iomemtype;
     SLNANDState *s;
+    DriveInfo *nand;
 
     s = FROM_SYSBUS(SLNANDState, dev);
 
     s->ctl = 0;
-    s->nand = nand_init(s->manf_id, s->chip_id);
+    nand = drive_get(IF_MTD, 0, 0);
+    s->nand = nand_init(nand ? nand->bdrv : NULL, s->manf_id, s->chip_id);
 
     iomemtype = cpu_register_io_memory(sl_readfn,
                     sl_writefn, s, DEVICE_NATIVE_ENDIAN);
diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c
index ed49e94..4de0819 100644
--- a/hw/tc6393xb.c
+++ b/hw/tc6393xb.c
@@ -12,6 +12,7 @@
 #include "flash.h"
 #include "console.h"
 #include "pixel_ops.h"
+#include "blockdev.h"
 
 #define IRQ_TC6393_NAND		0
 #define IRQ_TC6393_MMC		1
@@ -566,6 +567,7 @@ TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq)
 {
     int iomemtype;
     TC6393xbState *s;
+    DriveInfo *nand;
     CPUReadMemoryFunc * const tc6393xb_readfn[] = {
         tc6393xb_readb,
         tc6393xb_readw,
@@ -586,7 +588,8 @@ TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq)
 
     s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS);
 
-    s->flash = nand_init(NAND_MFR_TOSHIBA, 0x76);
+    nand = drive_get(IF_MTD, 0, 0);
+    s->flash = nand_init(nand ? nand->bdrv : NULL, NAND_MFR_TOSHIBA, 0x76);
 
     iomemtype = cpu_register_io_memory(tc6393xb_readfn,
                     tc6393xb_writefn, s, DEVICE_NATIVE_ENDIAN);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH 02/12] hw/nand: Support large NAND devices
  2011-07-15 14:58 [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices Peter Maydell
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 01/12] hw/nand: Pass block device state to init function Peter Maydell
@ 2011-07-15 14:58 ` Peter Maydell
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 03/12] hw/nand: Support devices wider than 8 bits Peter Maydell
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2011-07-15 14:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki, Markus Armbruster, patches

From: Juha Riihimäki <juha.riihimaki@nokia.com>

Add support for NAND devices of over 1Gb.

Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
[Riku Voipio: Fixes and restructuring patchset]
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
[Peter Maydell: More fixes and cleanups for upstream submission]
Signed-off-by:  Peter Maydell <peter.maydell@linaro.org>
---
 hw/nand.c |   48 +++++++++++++++++++++++++++---------------------
 1 files changed, 27 insertions(+), 21 deletions(-)

diff --git a/hw/nand.c b/hw/nand.c
index d6204d9..18aa226 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -6,6 +6,10 @@
  * Copyright (c) 2006 Openedhand Ltd.
  * Written by Andrzej Zaborowski <balrog@zabor.org>
  *
+ * Support for additional features based on "MT29F2G16ABCWP 2Gx16"
+ * datasheet from Micron Technology and "NAND02G-B2C" datasheet
+ * from ST Microelectronics.
+ *
  * This code is licensed under the GNU GPL v2.
  */
 
@@ -57,14 +61,15 @@ struct NANDFlashState {
     uint8_t *ioaddr;
     int iolen;
 
-    uint32_t cmd, addr;
+    uint32_t cmd;
+    uint64_t addr;
     int addrlen;
     int status;
     int offset;
 
     void (*blk_write)(NANDFlashState *s);
     void (*blk_erase)(NANDFlashState *s);
-    void (*blk_load)(NANDFlashState *s, uint32_t addr, int offset);
+    void (*blk_load)(NANDFlashState *s, uint64_t addr, int offset);
 
     uint32_t ioaddr_vmstate;
 };
@@ -318,7 +323,7 @@ static const VMStateDescription vmstate_nand = {
         VMSTATE_UINT32(ioaddr_vmstate, NANDFlashState),
         VMSTATE_INT32(iolen, NANDFlashState),
         VMSTATE_UINT32(cmd, NANDFlashState),
-        VMSTATE_UINT32(addr, NANDFlashState),
+        VMSTATE_UINT64(addr, NANDFlashState),
         VMSTATE_INT32(addrlen, NANDFlashState),
         VMSTATE_INT32(status, NANDFlashState),
         VMSTATE_INT32(offset, NANDFlashState),
@@ -432,7 +437,7 @@ uint8_t nand_getio(NANDFlashState *s)
 
     /* Allow sequential reading */
     if (!s->iolen && s->cmd == NAND_CMD_READ0) {
-        offset = (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
+        offset = (int)(s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
         s->offset = 0;
 
         s->blk_load(s, s->addr, offset);
@@ -526,7 +531,7 @@ void nand_done(NANDFlashState *s)
 /* Program a single page */
 static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
 {
-    uint32_t off, page, sector, soff;
+    uint64_t off, page, sector, soff;
     uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200];
     if (PAGE(s->addr) >= s->pages)
         return;
@@ -539,7 +544,7 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
         off = (s->addr & PAGE_MASK) + s->offset;
         soff = SECTOR_OFFSET(s->addr);
         if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) {
-            printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+            printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
             return;
         }
 
@@ -551,20 +556,20 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
         }
 
         if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1)
-            printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+            printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
     } else {
         off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
         sector = off >> 9;
         soff = off & 0x1ff;
         if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) {
-            printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+            printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
             return;
         }
 
         memcpy(iobuf + soff, s->io, s->iolen);
 
         if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1)
-            printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+            printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
     }
     s->offset = 0;
 }
@@ -572,7 +577,7 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
 /* Erase a single block */
 static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
 {
-    uint32_t i, page, addr;
+    uint64_t i, page, addr;
     uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, };
     addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1);
 
@@ -589,34 +594,35 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
         page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
         for (; i < page; i ++)
             if (bdrv_write(s->bdrv, i, iobuf, 1) == -1)
-                printf("%s: write error in sector %i\n", __FUNCTION__, i);
+                printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
     } else {
         addr = PAGE_START(addr);
         page = addr >> 9;
         if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
-            printf("%s: read error in sector %i\n", __FUNCTION__, page);
+            printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
         memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
         if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
-            printf("%s: write error in sector %i\n", __FUNCTION__, page);
+            printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
 
         memset(iobuf, 0xff, 0x200);
         i = (addr & ~0x1ff) + 0x200;
         for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
                         i < addr; i += 0x200)
             if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1)
-                printf("%s: write error in sector %i\n", __FUNCTION__, i >> 9);
+                printf("%s: write error in sector %" PRIu64 "\n",
+                       __func__, i >> 9);
 
         page = i >> 9;
         if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
-            printf("%s: read error in sector %i\n", __FUNCTION__, page);
+            printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
         memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
         if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
-            printf("%s: write error in sector %i\n", __FUNCTION__, page);
+            printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
     }
 }
 
 static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
-                uint32_t addr, int offset)
+                uint64_t addr, int offset)
 {
     if (PAGE(addr) >= s->pages)
         return;
@@ -624,8 +630,8 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
     if (s->bdrv) {
         if (s->mem_oob) {
             if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) == -1)
-                printf("%s: read error in sector %i\n",
-                                __FUNCTION__, SECTOR(addr));
+                printf("%s: read error in sector %" PRIu64 "\n",
+                                __func__, SECTOR(addr));
             memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE,
                             s->storage + (PAGE(s->addr) << OOB_SHIFT),
                             OOB_SIZE);
@@ -633,8 +639,8 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
         } else {
             if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9,
                                     s->io, (PAGE_SECTORS + 2)) == -1)
-                printf("%s: read error in sector %i\n",
-                                __FUNCTION__, PAGE_START(addr) >> 9);
+                printf("%s: read error in sector %" PRIu64 "\n",
+                                __func__, PAGE_START(addr) >> 9);
             s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
         }
     } else {
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH 03/12] hw/nand: Support devices wider than 8 bits
  2011-07-15 14:58 [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices Peter Maydell
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 01/12] hw/nand: Pass block device state to init function Peter Maydell
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 02/12] hw/nand: Support large NAND devices Peter Maydell
@ 2011-07-15 14:58 ` Peter Maydell
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 04/12] hw/nand: Support multiple reads following READ STATUS Peter Maydell
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2011-07-15 14:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki, Markus Armbruster, patches

From: Juha Riihimäki <juha.riihimaki@nokia.com>

Support NAND devices which are wider than 8 bits.

Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
[Riku Voipio: Fixes and restructuring patchset]
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
[Peter Maydell: More fixes and cleanups for upstream submission]
Signed-off-by:  Peter Maydell <peter.maydell@linaro.org>
---
 hw/flash.h |    5 ++-
 hw/nand.c  |  119 +++++++++++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 89 insertions(+), 35 deletions(-)

diff --git a/hw/flash.h b/hw/flash.h
index a992bb8..132ad29 100644
--- a/hw/flash.h
+++ b/hw/flash.h
@@ -24,8 +24,9 @@ void nand_done(NANDFlashState *s);
 void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
                   uint8_t ce, uint8_t wp, uint8_t gnd);
 void nand_getpins(NANDFlashState *s, int *rb);
-void nand_setio(NANDFlashState *s, uint8_t value);
-uint8_t nand_getio(NANDFlashState *s);
+void nand_setio(NANDFlashState *s, uint32_t value);
+uint32_t nand_getio(NANDFlashState *s);
+uint32_t nand_getbuswidth(NANDFlashState *s);
 
 #define NAND_MFR_TOSHIBA	0x98
 #define NAND_MFR_SAMSUNG	0xec
diff --git a/hw/nand.c b/hw/nand.c
index 18aa226..2e98f25 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -49,6 +49,7 @@
 
 struct NANDFlashState {
     uint8_t manf_id, chip_id;
+    uint8_t buswidth; /* in BYTES */
     int size, pages;
     int page_shift, oob_shift, erase_shift, addr_shift;
     uint8_t *storage;
@@ -215,6 +216,14 @@ static void nand_reset(NANDFlashState *s)
     s->status &= NAND_IOSTATUS_UNPROTCT;
 }
 
+static inline void nand_pushio_byte(NANDFlashState *s, uint8_t value)
+{
+    s->ioaddr[s->iolen++] = value;
+    for (value = s->buswidth; --value;) {
+        s->ioaddr[s->iolen++] = 0;
+    }
+}
+
 static void nand_command(NANDFlashState *s)
 {
     unsigned int offset;
@@ -224,15 +233,19 @@ static void nand_command(NANDFlashState *s)
         break;
 
     case NAND_CMD_READID:
-        s->io[0] = s->manf_id;
-        s->io[1] = s->chip_id;
-        s->io[2] = 'Q';		/* Don't-care byte (often 0xa5) */
-        if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
-            s->io[3] = 0x15;	/* Page Size, Block Size, Spare Size.. */
-        else
-            s->io[3] = 0xc0;	/* Multi-plane */
         s->ioaddr = s->io;
-        s->iolen = 4;
+        s->iolen = 0;
+        nand_pushio_byte(s, s->manf_id);
+        nand_pushio_byte(s, s->chip_id);
+        nand_pushio_byte(s, 'Q'); /* Don't-care byte (often 0xa5) */
+        if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
+            /* Page Size, Block Size, Spare Size; bit 6 indicates
+             * 8 vs 16 bit width NAND.
+             */
+            nand_pushio_byte(s, (s->buswidth == 2) ? 0x55 : 0x15);
+        } else {
+            nand_pushio_byte(s, 0xc0); /* Multi-plane */
+        }
         break;
 
     case NAND_CMD_RANDOMREAD2:
@@ -277,9 +290,9 @@ static void nand_command(NANDFlashState *s)
         break;
 
     case NAND_CMD_READSTATUS:
-        s->io[0] = s->status;
         s->ioaddr = s->io;
-        s->iolen = 1;
+        s->iolen = 0;
+        nand_pushio_byte(s, s->status);
         break;
 
     default:
@@ -357,8 +370,10 @@ void nand_getpins(NANDFlashState *s, int *rb)
     *rb = 1;
 }
 
-void nand_setio(NANDFlashState *s, uint8_t value)
+void nand_setio(NANDFlashState *s, uint32_t value)
 {
+    int i;
+
     if (!s->ce && s->cle) {
         if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
             if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
@@ -404,36 +419,64 @@ void nand_setio(NANDFlashState *s, uint8_t value)
         s->addr = (s->addr & mask) | v;
         s->addrlen ++;
 
-        if (s->addrlen == 1 && s->cmd == NAND_CMD_READID)
-            nand_command(s);
-
-        if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
-                s->addrlen == 3 && (
-                    s->cmd == NAND_CMD_READ0 ||
-                    s->cmd == NAND_CMD_PAGEPROGRAM1))
-            nand_command(s);
-        if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
-               s->addrlen == 4 && (
-                    s->cmd == NAND_CMD_READ0 ||
-                    s->cmd == NAND_CMD_PAGEPROGRAM1))
-            nand_command(s);
+        switch (s->addrlen) {
+        case 1:
+            if (s->cmd == NAND_CMD_READID) {
+                nand_command(s);
+            }
+            break;
+        case 2: /* fix cache address as a byte address */
+            s->addr <<= (s->buswidth - 1);
+            break;
+        case 3:
+            if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
+                && (s->cmd == NAND_CMD_READ0
+                    || s->cmd == NAND_CMD_PAGEPROGRAM1)) {
+                nand_command(s);
+            }
+            break;
+        case 4:
+            if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
+                && nand_flash_ids[s->chip_id].size < 256 /* 1Gb or less */
+                && (s->cmd == NAND_CMD_READ0 ||
+                    s->cmd == NAND_CMD_PAGEPROGRAM1)) {
+                nand_command(s);
+            }
+            break;
+        case 5:
+            if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
+                && nand_flash_ids[s->chip_id].size >= 256 /* 2Gb or more */
+                && (s->cmd == NAND_CMD_READ0 ||
+                    s->cmd == NAND_CMD_PAGEPROGRAM1)) {
+                nand_command(s);
+            }
+            break;
+        default:
+            break;
+        }
     }
 
     if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) {
-        if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift))
-            s->io[s->iolen ++] = value;
+        if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift)) {
+            for (i = s->buswidth; i--; value >>= 8) {
+                s->io[s->iolen++] = (uint8_t)(value & 0xff);
+            }
+        }
     } else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) {
         if ((s->addr & ((1 << s->addr_shift) - 1)) <
-                (1 << s->page_shift) + (1 << s->oob_shift)) {
-            s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] = value;
-            s->addr ++;
+            (1 << s->page_shift) + (1 << s->oob_shift)) {
+            for (i = s->buswidth; i--; s->addr++, value >>= 8) {
+                s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] =
+                    (uint8_t)(value & 0xff);
+            }
         }
     }
 }
 
-uint8_t nand_getio(NANDFlashState *s)
+uint32_t nand_getio(NANDFlashState *s)
 {
     int offset;
+    uint32_t x = 0;
 
     /* Allow sequential reading */
     if (!s->iolen && s->cmd == NAND_CMD_READ0) {
@@ -450,9 +493,18 @@ uint8_t nand_getio(NANDFlashState *s)
     if (s->ce || s->iolen <= 0)
         return 0;
 
-    s->iolen --;
-    s->addr++;
-    return *(s->ioaddr ++);
+    for (offset = s->buswidth; offset--;) {
+        x |= s->ioaddr[offset] << (offset << 3);
+    }
+    s->addr   += s->buswidth;
+    s->ioaddr += s->buswidth;
+    s->iolen  -= s->buswidth;
+    return x;
+}
+
+uint32_t nand_getbuswidth(NANDFlashState *s)
+{
+    return s->buswidth << 3;
 }
 
 NANDFlashState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
@@ -468,6 +520,7 @@ NANDFlashState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
     s->bdrv = bdrv;
     s->manf_id = manf_id;
     s->chip_id = chip_id;
+    s->buswidth = nand_flash_ids[s->chip_id].width >> 3;
     s->size = nand_flash_ids[s->chip_id].size << 20;
     if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
         s->page_shift = 11;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH 04/12] hw/nand: Support multiple reads following READ STATUS
  2011-07-15 14:58 [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices Peter Maydell
                   ` (2 preceding siblings ...)
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 03/12] hw/nand: Support devices wider than 8 bits Peter Maydell
@ 2011-07-15 14:58 ` Peter Maydell
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 05/12] hw/nand: Writing to NAND can only clear bits Peter Maydell
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2011-07-15 14:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki, Markus Armbruster, patches

From: Juha Riihimäki <juha.riihimaki@nokia.com>

After receiving READ STATUS command all subsequent IO reads should return
the status register value until another command is issued.

Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
[Riku Voipio: Fixes and restructuring patchset]
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
[Peter Maydell: More fixes and cleanups for upstream submission]
Signed-off-by:  Peter Maydell <peter.maydell@linaro.org>
---
 hw/nand.c |   11 ++++++++---
 1 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/hw/nand.c b/hw/nand.c
index 2e98f25..e6c551d 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -496,9 +496,14 @@ uint32_t nand_getio(NANDFlashState *s)
     for (offset = s->buswidth; offset--;) {
         x |= s->ioaddr[offset] << (offset << 3);
     }
-    s->addr   += s->buswidth;
-    s->ioaddr += s->buswidth;
-    s->iolen  -= s->buswidth;
+    /* after receiving READ STATUS command all subsequent reads will
+     * return the status register value until another command is issued
+     */
+    if (s->cmd != NAND_CMD_READSTATUS) {
+        s->addr   += s->buswidth;
+        s->ioaddr += s->buswidth;
+        s->iolen  -= s->buswidth;
+    }
     return x;
 }
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH 05/12] hw/nand: Writing to NAND can only clear bits
  2011-07-15 14:58 [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices Peter Maydell
                   ` (3 preceding siblings ...)
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 04/12] hw/nand: Support multiple reads following READ STATUS Peter Maydell
@ 2011-07-15 14:58 ` Peter Maydell
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 06/12] hw/nand: qdevify Peter Maydell
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2011-07-15 14:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki, Markus Armbruster, patches

Writing to a NAND device cannot set bits, it can only clear them;
implement this rather than simply copying the data.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/nand.c |   17 +++++++++++++----
 1 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/hw/nand.c b/hw/nand.c
index e6c551d..d068eb6 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -75,6 +75,15 @@ struct NANDFlashState {
     uint32_t ioaddr_vmstate;
 };
 
+static void mem_and(uint8_t *dest, const uint8_t *src, size_t n)
+{
+    /* Like memcpy() but we logical-AND the data into the destination */
+    int i;
+    for (i = 0; i < n; i++) {
+        dest[i] &= src[i];
+    }
+}
+
 # define NAND_NO_AUTOINCR	0x00000001
 # define NAND_BUSWIDTH_16	0x00000002
 # define NAND_NO_PADDING	0x00000004
@@ -595,7 +604,7 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
         return;
 
     if (!s->bdrv) {
-        memcpy(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
+        mem_and(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
                         s->offset, s->io, s->iolen);
     } else if (s->mem_oob) {
         sector = SECTOR(s->addr);
@@ -606,10 +615,10 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
             return;
         }
 
-        memcpy(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
+        mem_and(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
         if (off + s->iolen > PAGE_SIZE) {
             page = PAGE(s->addr);
-            memcpy(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
+            mem_and(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
                             MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
         }
 
@@ -624,7 +633,7 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
             return;
         }
 
-        memcpy(iobuf + soff, s->io, s->iolen);
+        mem_and(iobuf + soff, s->io, s->iolen);
 
         if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1)
             printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH 06/12] hw/nand: qdevify
  2011-07-15 14:58 [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices Peter Maydell
                   ` (4 preceding siblings ...)
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 05/12] hw/nand: Writing to NAND can only clear bits Peter Maydell
@ 2011-07-15 14:58 ` Peter Maydell
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 07/12] onenand: Pass BlockDriverState to init function Peter Maydell
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2011-07-15 14:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki, Markus Armbruster, patches

From: Juha Riihimäki <juha.riihimaki@nokia.com>

Qdevify the NAND device.

Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
[Riku Voipio: Fixes and restructuring patchset]
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
[Peter Maydell: More fixes and cleanups for upstream submission]
Signed-off-by:  Peter Maydell <peter.maydell@linaro.org>
---
 hw/axis_dev88.c |    2 +-
 hw/flash.h      |   14 ++---
 hw/nand.c       |  164 +++++++++++++++++++++++++++++++------------------------
 hw/spitz.c      |    2 +-
 hw/tc6393xb.c   |    2 +-
 5 files changed, 102 insertions(+), 82 deletions(-)

diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
index de1f5a5..e0a8c14 100644
--- a/hw/axis_dev88.c
+++ b/hw/axis_dev88.c
@@ -37,7 +37,7 @@
 
 struct nand_state_t
 {
-    NANDFlashState *nand;
+    DeviceState *nand;
     unsigned int rdy:1;
     unsigned int ale:1;
     unsigned int cle:1;
diff --git a/hw/flash.h b/hw/flash.h
index 132ad29..43260ce 100644
--- a/hw/flash.h
+++ b/hw/flash.h
@@ -18,15 +18,13 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
                                 int be);
 
 /* nand.c */
-typedef struct NANDFlashState NANDFlashState;
-NANDFlashState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id);
-void nand_done(NANDFlashState *s);
-void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
+DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id);
+void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
                   uint8_t ce, uint8_t wp, uint8_t gnd);
-void nand_getpins(NANDFlashState *s, int *rb);
-void nand_setio(NANDFlashState *s, uint32_t value);
-uint32_t nand_getio(NANDFlashState *s);
-uint32_t nand_getbuswidth(NANDFlashState *s);
+void nand_getpins(DeviceState *dev, int *rb);
+void nand_setio(DeviceState *dev, uint32_t value);
+uint32_t nand_getio(DeviceState *dev);
+uint32_t nand_getbuswidth(DeviceState *dev);
 
 #define NAND_MFR_TOSHIBA	0x98
 #define NAND_MFR_SAMSUNG	0xec
diff --git a/hw/nand.c b/hw/nand.c
index d068eb6..2f5a40e 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -18,6 +18,7 @@
 # include "hw.h"
 # include "flash.h"
 # include "blockdev.h"
+# include "sysbus.h"
 
 # define NAND_CMD_READ0		0x00
 # define NAND_CMD_READ1		0x01
@@ -47,7 +48,9 @@
 # define MAX_PAGE		0x800
 # define MAX_OOB		0x40
 
+typedef struct NANDFlashState NANDFlashState;
 struct NANDFlashState {
+    SysBusDevice busdev;
     uint8_t manf_id, chip_id;
     uint8_t buswidth; /* in BYTES */
     int size, pages;
@@ -215,8 +218,9 @@ static const struct {
     [0xc5] = { 2048,	16,	0, 0, LP_OPTIONS16 },
 };
 
-static void nand_reset(NANDFlashState *s)
+static void nand_reset(DeviceState *dev)
 {
+    NANDFlashState *s = FROM_SYSBUS(NANDFlashState, sysbus_from_qdev(dev));
     s->cmd = NAND_CMD_READ0;
     s->addr = 0;
     s->addrlen = 0;
@@ -270,7 +274,7 @@ static void nand_command(NANDFlashState *s)
         break;
 
     case NAND_CMD_RESET:
-        nand_reset(s);
+        nand_reset(&s->busdev.qdev);
         break;
 
     case NAND_CMD_PAGEPROGRAM1:
@@ -354,15 +358,84 @@ static const VMStateDescription vmstate_nand = {
     }
 };
 
+static int nand_device_init(SysBusDevice *dev)
+{
+    int pagesize;
+    NANDFlashState *s = FROM_SYSBUS(NANDFlashState, dev);
+    s->buswidth = nand_flash_ids[s->chip_id].width >> 3;
+    s->size = nand_flash_ids[s->chip_id].size << 20;
+    if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
+        s->page_shift = 11;
+        s->erase_shift = 6;
+    } else {
+        s->page_shift = nand_flash_ids[s->chip_id].page_shift;
+        s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
+    }
+
+    switch (1 << s->page_shift) {
+    case 256:
+        nand_init_256(s);
+        break;
+    case 512:
+        nand_init_512(s);
+        break;
+    case 2048:
+        nand_init_2048(s);
+        break;
+    default:
+        hw_error("%s: Unsupported NAND block size.\n", __func__);
+    }
+
+    pagesize = 1 << s->oob_shift;
+    s->mem_oob = 1;
+    if (s->bdrv && bdrv_getlength(s->bdrv) >=
+        (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
+        pagesize = 0;
+        s->mem_oob = 0;
+    }
+
+    if (!s->bdrv) {
+        pagesize += 1 << s->page_shift;
+    }
+    if (pagesize) {
+        s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize),
+                                        0xff, s->pages * pagesize);
+    }
+    /* Give s->ioaddr a sane value in case we save state before it is used. */
+    s->ioaddr = s->io;
+
+    return 0;
+}
+
+static SysBusDeviceInfo nand_info = {
+    .init = nand_device_init,
+    .qdev.name = "nand",
+    .qdev.size = sizeof(NANDFlashState),
+    .qdev.reset = nand_reset,
+    .qdev.vmsd = &vmstate_nand,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0),
+        DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0),
+        DEFINE_PROP_DRIVE("drive", NANDFlashState, bdrv),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
+
+static void nand_create_device(void)
+{
+    sysbus_register_withprop(&nand_info);
+}
+
 /*
  * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins.  Chip
  * outputs are R/B and eight I/O pins.
  *
  * CE, WP and R/B are active low.
  */
-void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
+void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
                   uint8_t ce, uint8_t wp, uint8_t gnd)
 {
+    NANDFlashState *s = (NANDFlashState *)dev;
     s->cle = cle;
     s->ale = ale;
     s->ce = ce;
@@ -374,15 +447,15 @@ void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
         s->status &= ~NAND_IOSTATUS_UNPROTCT;
 }
 
-void nand_getpins(NANDFlashState *s, int *rb)
+void nand_getpins(DeviceState *dev, int *rb)
 {
     *rb = 1;
 }
 
-void nand_setio(NANDFlashState *s, uint32_t value)
+void nand_setio(DeviceState *dev, uint32_t value)
 {
     int i;
-
+    NANDFlashState *s = (NANDFlashState *)dev;
     if (!s->ce && s->cle) {
         if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
             if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
@@ -482,10 +555,11 @@ void nand_setio(NANDFlashState *s, uint32_t value)
     }
 }
 
-uint32_t nand_getio(NANDFlashState *s)
+uint32_t nand_getio(DeviceState *dev)
 {
     int offset;
     uint32_t x = 0;
+    NANDFlashState *s = (NANDFlashState *)dev;
 
     /* Allow sequential reading */
     if (!s->iolen && s->cmd == NAND_CMD_READ0) {
@@ -516,82 +590,30 @@ uint32_t nand_getio(NANDFlashState *s)
     return x;
 }
 
-uint32_t nand_getbuswidth(NANDFlashState *s)
+uint32_t nand_getbuswidth(DeviceState *dev)
 {
+    NANDFlashState *s = (NANDFlashState *)dev;
     return s->buswidth << 3;
 }
 
-NANDFlashState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
+DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
 {
-    int pagesize;
-    NANDFlashState *s;
-
+    DeviceState *dev;
     if (nand_flash_ids[chip_id].size == 0) {
         hw_error("%s: Unsupported NAND chip ID.\n", __FUNCTION__);
     }
-
-    s = (NANDFlashState *) qemu_mallocz(sizeof(NANDFlashState));
-    s->bdrv = bdrv;
-    s->manf_id = manf_id;
-    s->chip_id = chip_id;
-    s->buswidth = nand_flash_ids[s->chip_id].width >> 3;
-    s->size = nand_flash_ids[s->chip_id].size << 20;
-    if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
-        s->page_shift = 11;
-        s->erase_shift = 6;
-    } else {
-        s->page_shift = nand_flash_ids[s->chip_id].page_shift;
-        s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
+    dev = qdev_create(NULL, "nand");
+    qdev_prop_set_uint8(dev, "manufacturer_id", manf_id);
+    qdev_prop_set_uint8(dev, "chip_id", chip_id);
+    if (bdrv) {
+        qdev_prop_set_drive_nofail(dev, "drive", bdrv);
     }
 
-    switch (1 << s->page_shift) {
-    case 256:
-        nand_init_256(s);
-        break;
-    case 512:
-        nand_init_512(s);
-        break;
-    case 2048:
-        nand_init_2048(s);
-        break;
-    default:
-        hw_error("%s: Unsupported NAND block size.\n", __FUNCTION__);
-    }
-
-    pagesize = 1 << s->oob_shift;
-    s->mem_oob = 1;
-    if (s->bdrv && bdrv_getlength(s->bdrv) >=
-                    (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
-        pagesize = 0;
-        s->mem_oob = 0;
-    }
-
-    if (!s->bdrv)
-        pagesize += 1 << s->page_shift;
-    if (pagesize)
-        s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize),
-                        0xff, s->pages * pagesize);
-    /* Give s->ioaddr a sane value in case we save state before it
-       is used.  */
-    s->ioaddr = s->io;
-
-    vmstate_register(NULL, -1, &vmstate_nand, s);
-
-    return s;
+    qdev_init_nofail(dev);
+    return dev;
 }
 
-void nand_done(NANDFlashState *s)
-{
-    if (s->bdrv) {
-        bdrv_close(s->bdrv);
-        bdrv_delete(s->bdrv);
-    }
-
-    if (!s->bdrv || s->mem_oob)
-        qemu_free(s->storage);
-
-    qemu_free(s);
-}
+device_init(nand_create_device)
 
 #else
 
diff --git a/hw/spitz.c b/hw/spitz.c
index 78e9c34..c05b5f7 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -48,7 +48,7 @@
 
 typedef struct {
     SysBusDevice busdev;
-    NANDFlashState *nand;
+    DeviceState *nand;
     uint8_t ctl;
     uint8_t manf_id;
     uint8_t chip_id;
diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c
index 4de0819..a1c48bf 100644
--- a/hw/tc6393xb.c
+++ b/hw/tc6393xb.c
@@ -118,7 +118,7 @@ struct TC6393xbState {
     } nand;
     int nand_enable;
     uint32_t nand_phys;
-    NANDFlashState *flash;
+    DeviceState *flash;
     ECCState ecc;
 
     DisplayState *ds;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH 07/12] onenand: Pass BlockDriverState to init function
  2011-07-15 14:58 [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices Peter Maydell
                   ` (5 preceding siblings ...)
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 06/12] hw/nand: qdevify Peter Maydell
@ 2011-07-15 14:58 ` Peter Maydell
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 08/12] onenand: Handle various ID fields separately Peter Maydell
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2011-07-15 14:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki, Markus Armbruster, patches

Pass the BlockDriverState to the onenand init function so it doesn't
need to look up the drive itself.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/flash.h   |    3 ++-
 hw/nseries.c |   10 ++++++----
 hw/onenand.c |   14 ++++++++------
 3 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/hw/flash.h b/hw/flash.h
index 43260ce..1aae43d 100644
--- a/hw/flash.h
+++ b/hw/flash.h
@@ -38,7 +38,8 @@ uint32_t nand_getbuswidth(DeviceState *dev);
 /* onenand.c */
 void onenand_base_update(void *opaque, target_phys_addr_t new);
 void onenand_base_unmap(void *opaque);
-void *onenand_init(uint32_t id, int regshift, qemu_irq irq);
+void *onenand_init(BlockDriverState *bdrv, uint32_t id,
+                   int regshift, qemu_irq irq);
 void *onenand_raw_otp(void *opaque);
 
 /* ecc.c */
diff --git a/hw/nseries.c b/hw/nseries.c
index 32f2f53..4fef05d 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -31,6 +31,7 @@
 #include "hw.h"
 #include "bt.h"
 #include "loader.h"
+#include "blockdev.h"
 
 /* Nokia N8x0 support */
 struct n800_s {
@@ -163,13 +164,14 @@ static const uint8_t n8x0_cal_bt_id[] = {
 static void n8x0_nand_setup(struct n800_s *s)
 {
     char *otp_region;
+    DriveInfo *dinfo;
 
+    dinfo = drive_get(IF_MTD, 0, 0);
     /* Either ec40xx or ec48xx are OK for the ID */
+    s->nand = onenand_init(dinfo ? dinfo->bdrv : 0, 0xec4800, 1,
+                           qdev_get_gpio_in(s->cpu->gpio, N8X0_ONENAND_GPIO));
     omap_gpmc_attach(s->cpu->gpmc, N8X0_ONENAND_CS, 0, onenand_base_update,
-                    onenand_base_unmap,
-                    (s->nand = onenand_init(0xec4800, 1,
-                                            qdev_get_gpio_in(s->cpu->gpio,
-                                                    N8X0_ONENAND_GPIO))));
+                     onenand_base_unmap, s->nand);
     otp_region = onenand_raw_otp(s->nand);
 
     memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac));
diff --git a/hw/onenand.c b/hw/onenand.c
index 71c1ab4..3a19d7f 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -615,10 +615,10 @@ static CPUWriteMemoryFunc * const onenand_writefn[] = {
     onenand_write,
 };
 
-void *onenand_init(uint32_t id, int regshift, qemu_irq irq)
+void *onenand_init(BlockDriverState *bdrv, uint32_t id,
+                   int regshift, qemu_irq irq)
 {
     OneNANDState *s = (OneNANDState *) qemu_mallocz(sizeof(*s));
-    DriveInfo *dinfo = drive_get(IF_MTD, 0, 0);
     uint32_t size = 1 << (24 + ((id >> 12) & 7));
     void *ram;
 
@@ -632,11 +632,13 @@ void *onenand_init(uint32_t id, int regshift, qemu_irq irq)
     s->density_mask = (id & (1 << 11)) ? (1 << (6 + ((id >> 12) & 7))) : 0;
     s->iomemtype = cpu_register_io_memory(onenand_readfn,
                     onenand_writefn, s, DEVICE_NATIVE_ENDIAN);
-    if (!dinfo)
+    s->bdrv = bdrv;
+    if (!s->bdrv) {
         s->image = memset(qemu_malloc(size + (size >> 5)),
-                        0xff, size + (size >> 5));
-    else
-        s->bdrv = dinfo->bdrv;
+                          0xff, size + (size >> 5));
+    } else {
+        s->bdrv_cur = s->bdrv;
+    }
     s->otp = memset(qemu_malloc((64 + 2) << PAGE_SHIFT),
                     0xff, (64 + 2) << PAGE_SHIFT);
     s->ram = qemu_ram_alloc(NULL, "onenand.ram", 0xc000 << s->shift);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH 08/12] onenand: Handle various ID fields separately
  2011-07-15 14:58 [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices Peter Maydell
                   ` (6 preceding siblings ...)
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 07/12] onenand: Pass BlockDriverState to init function Peter Maydell
@ 2011-07-15 14:58 ` Peter Maydell
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 09/12] onenand: Ignore zero writes to boot command space Peter Maydell
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2011-07-15 14:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki, Markus Armbruster, patches

From: Juha Riihimäki <juha.riihimaki@nokia.com>

Handle the manufacturer, device and version IDs separately rather than
smooshing them all together into a single uint32_t. Note that the ID
registers are actually 16 bit, even though typically the top bits are 0
and the Read Identification Data command only returns the bottom 8 bits.

Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
[Riku Voipio: Fixes and restructuring patchset]
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
[Peter Maydell: More fixes and cleanups for upstream submission]
Signed-off-by:  Peter Maydell <peter.maydell@linaro.org>
---
 hw/flash.h   |    3 ++-
 hw/nseries.c |    5 +++--
 hw/onenand.c |   29 ++++++++++++++++++-----------
 3 files changed, 23 insertions(+), 14 deletions(-)

diff --git a/hw/flash.h b/hw/flash.h
index 1aae43d..1064fd0 100644
--- a/hw/flash.h
+++ b/hw/flash.h
@@ -38,7 +38,8 @@ uint32_t nand_getbuswidth(DeviceState *dev);
 /* onenand.c */
 void onenand_base_update(void *opaque, target_phys_addr_t new);
 void onenand_base_unmap(void *opaque);
-void *onenand_init(BlockDriverState *bdrv, uint32_t id,
+void *onenand_init(BlockDriverState *bdrv,
+                   uint16_t man_id, uint16_t dev_id, uint16_t ver_id,
                    int regshift, qemu_irq irq);
 void *onenand_raw_otp(void *opaque);
 
diff --git a/hw/nseries.c b/hw/nseries.c
index 4fef05d..9b8d338 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -167,8 +167,9 @@ static void n8x0_nand_setup(struct n800_s *s)
     DriveInfo *dinfo;
 
     dinfo = drive_get(IF_MTD, 0, 0);
-    /* Either ec40xx or ec48xx are OK for the ID */
-    s->nand = onenand_init(dinfo ? dinfo->bdrv : 0, 0xec4800, 1,
+    /* Either 0x40 or 0x48 are OK for the device ID */
+    s->nand = onenand_init(dinfo ? dinfo->bdrv : 0,
+                           NAND_MFR_SAMSUNG, 0x48, 0, 1,
                            qdev_get_gpio_in(s->cpu->gpio, N8X0_ONENAND_GPIO));
     omap_gpmc_attach(s->cpu->gpmc, N8X0_ONENAND_CS, 0, onenand_base_update,
                      onenand_base_unmap, s->nand);
diff --git a/hw/onenand.c b/hw/onenand.c
index 3a19d7f..9f02736 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -31,7 +31,11 @@
 #define BLOCK_SHIFT	(PAGE_SHIFT + 6)
 
 typedef struct {
-    uint32_t id;
+    struct {
+        uint16_t man;
+        uint16_t dev;
+        uint16_t ver;
+    } id;
     int shift;
     target_phys_addr_t base;
     qemu_irq intr;
@@ -453,12 +457,12 @@ static uint32_t onenand_read(void *opaque, target_phys_addr_t addr)
         return lduw_le_p(s->boot[0] + addr);
 
     case 0xf000:	/* Manufacturer ID */
-        return (s->id >> 16) & 0xff;
+        return s->id.man;
     case 0xf001:	/* Device ID */
-        return (s->id >>  8) & 0xff;
-    /* TODO: get the following values from a real chip!  */
+        return s->id.dev;
     case 0xf002:	/* Version ID */
-        return (s->id >>  0) & 0xff;
+        return s->id.ver;
+    /* TODO: get the following values from a real chip!  */
     case 0xf003:	/* Data Buffer size */
         return 1 << PAGE_SHIFT;
     case 0xf004:	/* Boot Buffer size */
@@ -541,8 +545,8 @@ static void onenand_write(void *opaque, target_phys_addr_t addr,
 
         case 0x0090:	/* Read Identification Data */
             memset(s->boot[0], 0, 3 << s->shift);
-            s->boot[0][0 << s->shift] = (s->id >> 16) & 0xff;
-            s->boot[0][1 << s->shift] = (s->id >>  8) & 0xff;
+            s->boot[0][0 << s->shift] = s->id.man & 0xff;
+            s->boot[0][1 << s->shift] = s->id.dev & 0xff;
             s->boot[0][2 << s->shift] = s->wpstatus & 0xff;
             break;
 
@@ -615,21 +619,24 @@ static CPUWriteMemoryFunc * const onenand_writefn[] = {
     onenand_write,
 };
 
-void *onenand_init(BlockDriverState *bdrv, uint32_t id,
+void *onenand_init(BlockDriverState *bdrv,
+                   uint16_t man_id, uint16_t dev_id, uint16_t ver_id,
                    int regshift, qemu_irq irq)
 {
     OneNANDState *s = (OneNANDState *) qemu_mallocz(sizeof(*s));
-    uint32_t size = 1 << (24 + ((id >> 12) & 7));
+    uint32_t size = 1 << (24 + ((dev_id >> 4) & 7));
     void *ram;
 
     s->shift = regshift;
     s->intr = irq;
     s->rdy = NULL;
-    s->id = id;
+    s->id.man = man_id;
+    s->id.dev = dev_id;
+    s->id.ver = ver_id;
     s->blocks = size >> BLOCK_SHIFT;
     s->secs = size >> 9;
     s->blockwp = qemu_malloc(s->blocks);
-    s->density_mask = (id & (1 << 11)) ? (1 << (6 + ((id >> 12) & 7))) : 0;
+    s->density_mask = (dev_id & 0x08) ? (1 << (6 + ((dev_id >> 4) & 7))) : 0;
     s->iomemtype = cpu_register_io_memory(onenand_readfn,
                     onenand_writefn, s, DEVICE_NATIVE_ENDIAN);
     s->bdrv = bdrv;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH 09/12] onenand: Ignore zero writes to boot command space
  2011-07-15 14:58 [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices Peter Maydell
                   ` (7 preceding siblings ...)
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 08/12] onenand: Handle various ID fields separately Peter Maydell
@ 2011-07-15 14:58 ` Peter Maydell
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 10/12] hw/onenand: program actions can only clear bits Peter Maydell
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2011-07-15 14:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki, Markus Armbruster, patches

From: Juha Riihimäki <juha.riihimaki@nokia.com>

Ignore zero writes to the boot command space; Linux will issue
these in the powerdown/reset sequence.

Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
[Riku Voipio: Fixes and restructuring patchset]
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
[Peter Maydell: More fixes and cleanups for upstream submission]
Signed-off-by:  Peter Maydell <peter.maydell@linaro.org>
---
 hw/onenand.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/hw/onenand.c b/hw/onenand.c
index 9f02736..0edcfe2 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -550,6 +550,13 @@ static void onenand_write(void *opaque, target_phys_addr_t addr,
             s->boot[0][2 << s->shift] = s->wpstatus & 0xff;
             break;
 
+        case 0x0000:
+            /* ignore zero writes without error messages,
+             * linux omap2/3 kernel will issue these upon
+             * powerdown/reset sequence.
+             */
+            break;
+
         default:
             fprintf(stderr, "%s: unknown OneNAND boot command %x\n",
                             __FUNCTION__, value);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH 10/12] hw/onenand: program actions can only clear bits
  2011-07-15 14:58 [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices Peter Maydell
                   ` (8 preceding siblings ...)
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 09/12] onenand: Ignore zero writes to boot command space Peter Maydell
@ 2011-07-15 14:58 ` Peter Maydell
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 11/12] hw/sysbus: Add sysbus_mmio_unmap() for unmapping a region Peter Maydell
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2011-07-15 14:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki, Markus Armbruster, patches

From: Juha Riihimäki <juha.riihimaki@nokia.com>

The program actions onenand_prog_main() and onenand_prog_spare()
can only set bits.

This implies a rewrite of onenand_erase() to not use the program
functions, since erase does need to set bits.

Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
[Riku Voipio: Fixes and restructuring patchset]
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
[Peter Maydell: More fixes and cleanups for upstream submission]
Signed-off-by:  Peter Maydell <peter.maydell@linaro.org>
---
 hw/onenand.c |  135 +++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 106 insertions(+), 29 deletions(-)

diff --git a/hw/onenand.c b/hw/onenand.c
index 0edcfe2..981d23c 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -179,14 +179,39 @@ static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
 static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
                 void *src)
 {
-    if (s->bdrv_cur)
-        return bdrv_write(s->bdrv_cur, sec, src, secn) < 0;
-    else if (sec + secn > s->secs_cur)
-        return 1;
-
-    memcpy(s->current + (sec << 9), src, secn << 9);
+    int result = 0;
+
+    if (secn > 0) {
+        uint32_t size = (uint32_t)secn * 512;
+        const uint8_t *sp = (const uint8_t *)src;
+        uint8_t *dp = 0;
+        if (s->bdrv_cur) {
+            dp = qemu_malloc(size);
+            if (!dp || bdrv_read(s->bdrv_cur, sec, dp, secn) < 0) {
+                result = 1;
+            }
+        } else {
+            if (sec + secn > s->secs_cur) {
+                result = 1;
+            } else {
+                dp = (uint8_t *)s->current + (sec << 9);
+            }
+        }
+        if (!result) {
+            uint32_t i;
+            for (i = 0; i < size; i++) {
+                dp[i] &= sp[i];
+            }
+            if (s->bdrv_cur) {
+                result = bdrv_write(s->bdrv_cur, sec, dp, secn) < 0;
+            }
+        }
+        if (dp && s->bdrv_cur) {
+            qemu_free(dp);
+        }
+    }
 
-    return 0;
+    return result;
 }
 
 static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
@@ -209,35 +234,87 @@ static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
 static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
                 void *src)
 {
-    uint8_t buf[512];
-
-    if (s->bdrv_cur) {
-        if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0)
-            return 1;
-        memcpy(buf + ((sec & 31) << 4), src, secn << 4);
-        return bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0;
-    } else if (sec + secn > s->secs_cur)
-        return 1;
-
-    memcpy(s->current + (s->secs_cur << 9) + (sec << 4), src, secn << 4);
- 
-    return 0;
+    int result = 0;
+    if (secn > 0) {
+        const uint8_t *sp = (const uint8_t *)src;
+        uint8_t *dp = 0, *dpp = 0;
+        if (s->bdrv_cur) {
+            dp = qemu_malloc(512);
+            if (!dp || bdrv_read(s->bdrv_cur,
+                                 s->secs_cur + (sec >> 5),
+                                 dp, 1) < 0) {
+                result = 1;
+            } else {
+                dpp = dp + ((sec & 31) << 4);
+            }
+        } else {
+            if (sec + secn > s->secs_cur) {
+                result = 1;
+            } else {
+                dpp = s->current + (s->secs_cur << 9) + (sec << 4);
+            }
+        }
+        if (!result) {
+            uint32_t i;
+            for (i = 0; i < (secn << 4); i++) {
+                dpp[i] &= sp[i];
+            }
+            if (s->bdrv_cur) {
+                result = bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5),
+                                    dp, 1) < 0;
+            }
+        }
+        if (dp) {
+            qemu_free(dp);
+        }
+    }
+    return result;
 }
 
 static inline int onenand_erase(OneNANDState *s, int sec, int num)
 {
-    /* TODO: optimise */
-    uint8_t buf[512];
-
-    memset(buf, 0xff, sizeof(buf));
-    for (; num > 0; num --, sec ++) {
-        if (onenand_prog_main(s, sec, 1, buf))
-            return 1;
-        if (onenand_prog_spare(s, sec, 1, buf))
-            return 1;
+    uint8_t *blankbuf, *tmpbuf;
+    blankbuf = qemu_malloc(512);
+    if (!blankbuf) {
+        return 1;
+    }
+    tmpbuf = qemu_malloc(512);
+    if (!tmpbuf) {
+        qemu_free(blankbuf);
+        return 1;
+    }
+    memset(blankbuf, 0xff, 512);
+    for (; num > 0; num--, sec++) {
+        if (s->bdrv_cur) {
+            int erasesec = s->secs_cur + (sec >> 5);
+            if (bdrv_write(s->bdrv_cur, sec, blankbuf, 1)) {
+                goto fail;
+            }
+            if (bdrv_read(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
+                goto fail;
+            }
+            memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4);
+            if (bdrv_write(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
+                goto fail;
+            }
+        } else {
+            if (sec + 1 > s->secs_cur) {
+                goto fail;
+            }
+            memcpy(s->current + (sec << 9), blankbuf, 512);
+            memcpy(s->current + (s->secs_cur << 9) + (sec << 4),
+                   blankbuf, 1 << 4);
+        }
     }
 
+    qemu_free(tmpbuf);
+    qemu_free(blankbuf);
     return 0;
+
+fail:
+    qemu_free(tmpbuf);
+    qemu_free(blankbuf);
+    return 1;
 }
 
 static void onenand_command(OneNANDState *s, int cmd)
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH 11/12] hw/sysbus: Add sysbus_mmio_unmap() for unmapping a region
  2011-07-15 14:58 [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices Peter Maydell
                   ` (9 preceding siblings ...)
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 10/12] hw/onenand: program actions can only clear bits Peter Maydell
@ 2011-07-15 14:58 ` Peter Maydell
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 12/12] hw/onenand: qdevify Peter Maydell
  2011-07-28 13:51 ` [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices Peter Maydell
  12 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2011-07-15 14:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki, Markus Armbruster, patches

From: Juha Riihimäki <juha.riihimaki@nokia.com>

Add support for unmapping a SysBus device's mmio region, via a new
function sysbus_mmio_unmap(). This simply reverses the effect of
sysbus_mmio_map().

Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/sysbus.c |   17 +++++++++++++++++
 hw/sysbus.h |    1 +
 2 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/hw/sysbus.c b/hw/sysbus.c
index 2e22be7..021c653 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -39,6 +39,23 @@ void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
     }
 }
 
+void sysbus_mmio_unmap(SysBusDevice *dev, int n)
+{
+    assert(n >= 0 && n < dev->num_mmio);
+
+    if (dev->mmio[n].addr == (target_phys_addr_t)-1) {
+        /* region already unmapped */
+        return;
+    }
+    if (dev->mmio[n].cb) {
+        dev->mmio[n].cb(dev, (target_phys_addr_t)-1);
+    } else {
+        cpu_register_physical_memory(dev->mmio[n].addr, dev->mmio[n].size,
+                                     IO_MEM_UNASSIGNED);
+    }
+    dev->mmio[n].addr = (target_phys_addr_t)-1;
+}
+
 void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr)
 {
     assert(n >= 0 && n < dev->num_mmio);
diff --git a/hw/sysbus.h b/hw/sysbus.h
index 4e8cb16..4f93b70 100644
--- a/hw/sysbus.h
+++ b/hw/sysbus.h
@@ -53,6 +53,7 @@ void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size);
 
 void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq);
 void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr);
+void sysbus_mmio_unmap(SysBusDevice *dev, int n);
 
 /* Legacy helper function for creating devices.  */
 DeviceState *sysbus_create_varargs(const char *name,
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH 12/12] hw/onenand: qdevify
  2011-07-15 14:58 [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices Peter Maydell
                   ` (10 preceding siblings ...)
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 11/12] hw/sysbus: Add sysbus_mmio_unmap() for unmapping a region Peter Maydell
@ 2011-07-15 14:58 ` Peter Maydell
  2011-07-28 13:51 ` [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices Peter Maydell
  12 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2011-07-15 14:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki, Markus Armbruster, patches

From: Juha Riihimäki <juha.riihimaki@nokia.com>

Qdevify the ONENAND device.

Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
[Riku Voipio: Fixes and restructuring patchset]
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
[Peter Maydell: More fixes and cleanups for upstream submission]
Signed-off-by:  Peter Maydell <peter.maydell@linaro.org>
---
 hw/flash.h   |    8 +-
 hw/onenand.c |  208 +++++++++++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 167 insertions(+), 49 deletions(-)

diff --git a/hw/flash.h b/hw/flash.h
index 1064fd0..bbf397a 100644
--- a/hw/flash.h
+++ b/hw/flash.h
@@ -38,10 +38,10 @@ uint32_t nand_getbuswidth(DeviceState *dev);
 /* onenand.c */
 void onenand_base_update(void *opaque, target_phys_addr_t new);
 void onenand_base_unmap(void *opaque);
-void *onenand_init(BlockDriverState *bdrv,
-                   uint16_t man_id, uint16_t dev_id, uint16_t ver_id,
-                   int regshift, qemu_irq irq);
-void *onenand_raw_otp(void *opaque);
+DeviceState *onenand_init(BlockDriverState *bdrv,
+                          uint16_t man_id, uint16_t dev_id, uint16_t ver_id,
+                          int regshift, qemu_irq irq);
+void *onenand_raw_otp(DeviceState *onenand_device);
 
 /* ecc.c */
 typedef struct {
diff --git a/hw/onenand.c b/hw/onenand.c
index 981d23c..16fd29a 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -23,6 +23,7 @@
 #include "flash.h"
 #include "irq.h"
 #include "blockdev.h"
+#include "sysbus.h"
 
 /* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */
 #define PAGE_SHIFT	11
@@ -31,6 +32,7 @@
 #define BLOCK_SHIFT	(PAGE_SHIFT + 6)
 
 typedef struct {
+    SysBusDevice busdev;
     struct {
         uint16_t man;
         uint16_t dev;
@@ -45,6 +47,7 @@ typedef struct {
     uint8_t *image;
     uint8_t *otp;
     uint8_t *current;
+    uint8_t current_direction;
     ram_addr_t ram;
     uint8_t *boot[2];
     uint8_t *data[2][2];
@@ -100,31 +103,45 @@ enum {
     ONEN_LOCK_UNLOCKED = 1 << 2,
 };
 
-void onenand_base_update(void *opaque, target_phys_addr_t new)
+static void onenand_base_updatefn(SysBusDevice *dev, target_phys_addr_t new)
 {
-    OneNANDState *s = (OneNANDState *) opaque;
+    OneNANDState *s = (OneNANDState *)dev;
+    if (s->base != new) {
+        if (s->base != (target_phys_addr_t)-1) {
+            cpu_register_physical_memory(s->base, 0x10000 << s->shift,
+                                         IO_MEM_UNASSIGNED);
+        }
+        if (new != (target_phys_addr_t)-1) {
+            /* XXX: We should use IO_MEM_ROMD but we broke it earlier...
+             * Both 0x0000 ... 0x01ff and 0x8000 ... 0x800f can be used to
+             * write boot commands.  Also take note of the BWPS bit.  */
+            cpu_register_physical_memory(new + (0x0000 << s->shift),
+                                         0x0200 << s->shift, s->iomemtype);
+            cpu_register_physical_memory(new + (0x0200 << s->shift),
+                                         0xbe00 << s->shift,
+                                         (s->ram + (0x0200 << s->shift))
+                                         | IO_MEM_RAM);
+            if (s->iomemtype) {
+                cpu_register_physical_memory_offset(new + (0xc000 << s->shift),
+                                                    0x4000 << s->shift,
+                                                    s->iomemtype,
+                                                    (0xc000 << s->shift));
+            }
+        }
+        s->base = new;
+    }
+}
 
-    s->base = new;
-
-    /* XXX: We should use IO_MEM_ROMD but we broke it earlier...
-     * Both 0x0000 ... 0x01ff and 0x8000 ... 0x800f can be used to
-     * write boot commands.  Also take note of the BWPS bit.  */
-    cpu_register_physical_memory(s->base + (0x0000 << s->shift),
-                    0x0200 << s->shift, s->iomemtype);
-    cpu_register_physical_memory(s->base + (0x0200 << s->shift),
-                    0xbe00 << s->shift,
-                    (s->ram +(0x0200 << s->shift)) | IO_MEM_RAM);
-    if (s->iomemtype)
-        cpu_register_physical_memory_offset(s->base + (0xc000 << s->shift),
-                    0x4000 << s->shift, s->iomemtype, (0xc000 << s->shift));
+/* This wrapper can go away as soon as omap_gpmc is qdevified */
+void onenand_base_update(void *opaque, target_phys_addr_t new)
+{
+    onenand_base_updatefn(opaque, new);
 }
 
+/* Also only needed for pre-qdev omap_gpmc */
 void onenand_base_unmap(void *opaque)
 {
-    OneNANDState *s = (OneNANDState *) opaque;
-
-    cpu_register_physical_memory(s->base,
-                    0x10000 << s->shift, IO_MEM_UNASSIGNED);
+    sysbus_mmio_unmap(sysbus_from_qdev((DeviceState *)opaque), 0);
 }
 
 static void onenand_intr_update(OneNANDState *s)
@@ -132,6 +149,67 @@ static void onenand_intr_update(OneNANDState *s)
     qemu_set_irq(s->intr, ((s->intstatus >> 15) ^ (~s->config[0] >> 6)) & 1);
 }
 
+static void onenand_pre_save(void *opaque)
+{
+    OneNANDState *s = opaque;
+    if (s->current == s->otp) {
+        s->current_direction = 1;
+    } else if (s->current == s->image) {
+        s->current_direction = 2;
+    } else {
+        s->current_direction = 0;
+    }
+}
+
+static int onenand_post_load(void *opaque, int version_id)
+{
+    OneNANDState *s = opaque;
+    switch (s->current_direction) {
+    case 0:
+        break;
+    case 1:
+        s->current = s->otp;
+        break;
+    case 2:
+        s->current = s->image;
+        break;
+    default:
+        return -1;
+    }
+    onenand_intr_update(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_onenand = {
+    .name = "onenand",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = onenand_pre_save,
+    .post_load = onenand_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(current_direction, OneNANDState),
+        VMSTATE_INT32(cycle, OneNANDState),
+        VMSTATE_INT32(otpmode, OneNANDState),
+        VMSTATE_UINT16_ARRAY(addr, OneNANDState, 8),
+        VMSTATE_UINT16_ARRAY(unladdr, OneNANDState, 8),
+        VMSTATE_INT32(bufaddr, OneNANDState),
+        VMSTATE_INT32(count, OneNANDState),
+        VMSTATE_UINT16(command, OneNANDState),
+        VMSTATE_UINT16_ARRAY(config, OneNANDState, 2),
+        VMSTATE_UINT16(status, OneNANDState),
+        VMSTATE_UINT16(intstatus, OneNANDState),
+        VMSTATE_UINT16(wpstatus, OneNANDState),
+        VMSTATE_INT32(secs_cur, OneNANDState),
+        VMSTATE_PARTIAL_VBUFFER(blockwp, OneNANDState, blocks),
+        VMSTATE_UINT8(ecc.cp, OneNANDState),
+        VMSTATE_UINT16_ARRAY(ecc.lp, OneNANDState, 2),
+        VMSTATE_UINT16(ecc.count, OneNANDState),
+        VMSTATE_BUFFER_UNSAFE(otp, OneNANDState, 0, ((64 + 2) << PAGE_SHIFT)),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 /* Hot reset (Reset OneNAND command) or warm reset (RP pin low) */
 static void onenand_reset(OneNANDState *s, int cold)
 {
@@ -158,11 +236,17 @@ static void onenand_reset(OneNANDState *s, int cold)
         /* Lock the whole flash */
         memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks);
 
-        if (s->bdrv && bdrv_read(s->bdrv, 0, s->boot[0], 8) < 0)
-            hw_error("%s: Loading the BootRAM failed.\n", __FUNCTION__);
+        if (s->bdrv_cur && bdrv_read(s->bdrv_cur, 0, s->boot[0], 8) < 0) {
+            hw_error("%s: Loading the BootRAM failed.\n", __func__);
+        }
     }
 }
 
+static void onenand_system_reset(DeviceState *dev)
+{
+    onenand_reset(FROM_SYSBUS(OneNANDState, sysbus_from_qdev(dev)), 1);
+}
+
 static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
                 void *dest)
 {
@@ -317,7 +401,7 @@ fail:
     return 1;
 }
 
-static void onenand_command(OneNANDState *s, int cmd)
+static void onenand_command(OneNANDState *s)
 {
     int b;
     int sec;
@@ -337,7 +421,7 @@ static void onenand_command(OneNANDState *s, int cmd)
             s->data[(s->bufaddr >> 2) & 1][1] : s->boot[1];	\
     buf += (s->bufaddr & 3) << 4;
 
-    switch (cmd) {
+    switch (s->command) {
     case 0x00:	/* Load single/multiple sector data unit into buffer */
         SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
 
@@ -518,7 +602,7 @@ static void onenand_command(OneNANDState *s, int cmd)
         s->status |= ONEN_ERR_CMD;
         s->intstatus |= ONEN_INT;
         fprintf(stderr, "%s: unknown OneNAND command %x\n",
-                        __FUNCTION__, cmd);
+                        __func__, s->command);
     }
 
     onenand_intr_update(s);
@@ -656,7 +740,7 @@ static void onenand_write(void *opaque, target_phys_addr_t addr,
         if (s->intstatus & (1 << 15))
             break;
         s->command = value;
-        onenand_command(s, s->command);
+        onenand_command(s);
         break;
     case 0xf221:	/* System Configuration 1 */
         s->config[0] = value;
@@ -703,27 +787,19 @@ static CPUWriteMemoryFunc * const onenand_writefn[] = {
     onenand_write,
 };
 
-void *onenand_init(BlockDriverState *bdrv,
-                   uint16_t man_id, uint16_t dev_id, uint16_t ver_id,
-                   int regshift, qemu_irq irq)
+static int onenand_initfn(SysBusDevice *dev)
 {
-    OneNANDState *s = (OneNANDState *) qemu_mallocz(sizeof(*s));
-    uint32_t size = 1 << (24 + ((dev_id >> 4) & 7));
-    void *ram;
-
-    s->shift = regshift;
-    s->intr = irq;
+    OneNANDState *s = (OneNANDState *)dev;
+    uint32_t size = 1 << (24 + ((s->id.dev >> 4) & 7));
+    s->base = (target_phys_addr_t)-1;
     s->rdy = NULL;
-    s->id.man = man_id;
-    s->id.dev = dev_id;
-    s->id.ver = ver_id;
     s->blocks = size >> BLOCK_SHIFT;
     s->secs = size >> 9;
     s->blockwp = qemu_malloc(s->blocks);
-    s->density_mask = (dev_id & 0x08) ? (1 << (6 + ((dev_id >> 4) & 7))) : 0;
+    s->density_mask = (s->id.dev & 0x08)
+        ? (1 << (6 + ((s->id.dev >> 4) & 7))) : 0;
     s->iomemtype = cpu_register_io_memory(onenand_readfn,
                     onenand_writefn, s, DEVICE_NATIVE_ENDIAN);
-    s->bdrv = bdrv;
     if (!s->bdrv) {
         s->image = memset(qemu_malloc(size + (size >> 5)),
                           0xff, size + (size >> 5));
@@ -733,22 +809,64 @@ void *onenand_init(BlockDriverState *bdrv,
     s->otp = memset(qemu_malloc((64 + 2) << PAGE_SHIFT),
                     0xff, (64 + 2) << PAGE_SHIFT);
     s->ram = qemu_ram_alloc(NULL, "onenand.ram", 0xc000 << s->shift);
-    ram = qemu_get_ram_ptr(s->ram);
+    void *ram = qemu_get_ram_ptr(s->ram);
     s->boot[0] = ram + (0x0000 << s->shift);
     s->boot[1] = ram + (0x8000 << s->shift);
     s->data[0][0] = ram + ((0x0200 + (0 << (PAGE_SHIFT - 1))) << s->shift);
     s->data[0][1] = ram + ((0x8010 + (0 << (PAGE_SHIFT - 6))) << s->shift);
     s->data[1][0] = ram + ((0x0200 + (1 << (PAGE_SHIFT - 1))) << s->shift);
     s->data[1][1] = ram + ((0x8010 + (1 << (PAGE_SHIFT - 6))) << s->shift);
+    sysbus_init_irq(dev, &s->intr);
+    sysbus_init_mmio_cb(dev, 0x10000 << s->shift, onenand_base_updatefn);
+    vmstate_register(&dev->qdev,
+                     ((s->shift & 0x7f) << 24)
+                     | ((s->id.man & 0xff) << 16)
+                     | ((s->id.dev & 0xff) << 8)
+                     | (s->id.ver & 0xff),
+                     &vmstate_onenand, s);
+    return 0;
+}
 
-    onenand_reset(s, 1);
+static SysBusDeviceInfo onenand_info = {
+    .init = onenand_initfn,
+    .qdev.name = "onenand",
+    .qdev.size = sizeof(OneNANDState),
+    .qdev.reset = onenand_system_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT16("manufacturer_id", OneNANDState, id.man, 0),
+        DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0),
+        DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0),
+        DEFINE_PROP_INT32("shift", OneNANDState, shift, 0),
+        DEFINE_PROP_DRIVE("drive", OneNANDState, bdrv),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
 
-    return s;
+static void onenand_register_device(void)
+{
+    sysbus_register_withprop(&onenand_info);
 }
 
-void *onenand_raw_otp(void *opaque)
+DeviceState *onenand_init(BlockDriverState *bdrv,
+                          uint16_t man_id, uint16_t dev_id, uint16_t ver_id,
+                          int regshift, qemu_irq irq)
 {
-    OneNANDState *s = (OneNANDState *) opaque;
+    DeviceState *dev = qdev_create(NULL, "onenand");
+    qdev_prop_set_uint16(dev, "manufacturer_id", man_id);
+    qdev_prop_set_uint16(dev, "device_id", dev_id);
+    qdev_prop_set_uint16(dev, "version_id", ver_id);
+    qdev_prop_set_int32(dev, "shift", regshift);
+    if (bdrv) {
+        qdev_prop_set_drive_nofail(dev, "drive", bdrv);
+    }
+    qdev_init_nofail(dev);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+    return dev;
+}
 
-    return s->otp;
+void *onenand_raw_otp(DeviceState *onenand_device)
+{
+    return FROM_SYSBUS(OneNANDState, sysbus_from_qdev(onenand_device))->otp;
 }
+
+device_init(onenand_register_device)
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices
  2011-07-15 14:58 [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices Peter Maydell
                   ` (11 preceding siblings ...)
  2011-07-15 14:58 ` [Qemu-devel] [PATCH 12/12] hw/onenand: qdevify Peter Maydell
@ 2011-07-28 13:51 ` Peter Maydell
  12 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2011-07-28 13:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio, Juha Riihimäki, Markus Armbruster, patches

Ping on this one too, since I'm nearly ready with the next chunk of
patches (18 patches fixing bugs and adding NAND support to omap_gpmc)
and they obviously depend on this set.

-- PMM

On 15 July 2011 15:58, Peter Maydell <peter.maydell@linaro.org> wrote:
> This patchseries is more goodies from the Meego tree. Specifically, various
> bug fixes to hw/nand and hw/onenand, plus conversion of both to sysbus.
>
> [An advance note on the next thing due to come out of the pipe: qdeving
> nand and onenand allows us to move to qdevification of omap_gpmc, which
> takes both of those (and other things) as 'downstream' devices. That
> change will make it accept arbitrary SysBus devices as its 'downstream'
> devices rather than the current setup of taking an opaque pointer and a
> pair of resize/unmap function pointers. (There are also patches which add
> NAND support so you can tell omap_gpmc "this is a NAND device" and it then
> uses the nand_setpins/nand_getpins/nand_setio interface.) The rationale for
> using SysBus there rather than defining some new kind of bus is that you
> want to be able to plug any random thing into it; for instance the Overo
> board has a lan9118 ethernet controller hanging off the GPMC. ]
>
> A note on dependencies:
>  * This patch depends on the omap gpio patchset (although more textually
>   than seriously semantically)
>  * the six nand patches and the six onenand patches are broadly independent
>   of each other
>
> Juha Riihimäki (9):
>  hw/nand: Support large NAND devices
>  hw/nand: Support devices wider than 8 bits
>  hw/nand: Support multiple reads following READ STATUS
>  hw/nand: qdevify
>  onenand: Handle various ID fields separately
>  onenand: Ignore zero writes to boot command space
>  hw/onenand: program actions can only clear bits
>  hw/sysbus: Add sysbus_mmio_unmap() for unmapping a region
>  hw/onenand: qdevify
>
> Peter Maydell (3):
>  hw/nand: Pass block device state to init function
>  hw/nand: Writing to NAND can only clear bits
>  onenand: Pass BlockDriverState to init function
>
>  hw/axis_dev88.c |    8 +-
>  hw/flash.h      |   19 ++--
>  hw/nand.c       |  345 ++++++++++++++++++++++++++++++++-------------------
>  hw/nseries.c    |   13 ++-
>  hw/onenand.c    |  373 +++++++++++++++++++++++++++++++++++++++++++------------
>  hw/spitz.c      |    6 +-
>  hw/sysbus.c     |   17 +++
>  hw/sysbus.h     |    1 +
>  hw/tc6393xb.c   |    7 +-
>  9 files changed, 561 insertions(+), 228 deletions(-)

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2011-07-28 13:52 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-15 14:58 [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices Peter Maydell
2011-07-15 14:58 ` [Qemu-devel] [PATCH 01/12] hw/nand: Pass block device state to init function Peter Maydell
2011-07-15 14:58 ` [Qemu-devel] [PATCH 02/12] hw/nand: Support large NAND devices Peter Maydell
2011-07-15 14:58 ` [Qemu-devel] [PATCH 03/12] hw/nand: Support devices wider than 8 bits Peter Maydell
2011-07-15 14:58 ` [Qemu-devel] [PATCH 04/12] hw/nand: Support multiple reads following READ STATUS Peter Maydell
2011-07-15 14:58 ` [Qemu-devel] [PATCH 05/12] hw/nand: Writing to NAND can only clear bits Peter Maydell
2011-07-15 14:58 ` [Qemu-devel] [PATCH 06/12] hw/nand: qdevify Peter Maydell
2011-07-15 14:58 ` [Qemu-devel] [PATCH 07/12] onenand: Pass BlockDriverState to init function Peter Maydell
2011-07-15 14:58 ` [Qemu-devel] [PATCH 08/12] onenand: Handle various ID fields separately Peter Maydell
2011-07-15 14:58 ` [Qemu-devel] [PATCH 09/12] onenand: Ignore zero writes to boot command space Peter Maydell
2011-07-15 14:58 ` [Qemu-devel] [PATCH 10/12] hw/onenand: program actions can only clear bits Peter Maydell
2011-07-15 14:58 ` [Qemu-devel] [PATCH 11/12] hw/sysbus: Add sysbus_mmio_unmap() for unmapping a region Peter Maydell
2011-07-15 14:58 ` [Qemu-devel] [PATCH 12/12] hw/onenand: qdevify Peter Maydell
2011-07-28 13:51 ` [Qemu-devel] [PATCH 00/12] bugfix and qdevify NAND and ONENAND devices Peter Maydell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.