From patchwork Fri Jul 15 14:58:26 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 2724 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 796F123F42 for ; Fri, 15 Jul 2011 14:58:40 +0000 (UTC) Received: from mail-qy0-f180.google.com (mail-qy0-f180.google.com [209.85.216.180]) by fiordland.canonical.com (Postfix) with ESMTP id 31E59A18709 for ; Fri, 15 Jul 2011 14:58:40 +0000 (UTC) Received: by mail-qy0-f180.google.com with SMTP id 30so947162qyk.11 for ; Fri, 15 Jul 2011 07:58:40 -0700 (PDT) Received: by 10.229.25.212 with SMTP id a20mr2757138qcc.148.1310741919889; Fri, 15 Jul 2011 07:58:39 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.229.217.78 with SMTP id hl14cs50446qcb; Fri, 15 Jul 2011 07:58:39 -0700 (PDT) Received: by 10.227.6.18 with SMTP id 18mr3325030wbx.66.1310741915408; Fri, 15 Jul 2011 07:58:35 -0700 (PDT) Received: from mnementh.archaic.org.uk (mnementh.archaic.org.uk [81.2.115.146]) by mx.google.com with ESMTPS id p2si2863637wbh.145.2011.07.15.07.58.33 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 15 Jul 2011 07:58:34 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 81.2.115.146 as permitted sender) client-ip=81.2.115.146; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 81.2.115.146 as permitted sender) smtp.mail=pm215@archaic.org.uk Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.72) (envelope-from ) id 1QhjqU-0000Qj-N2; Fri, 15 Jul 2011 15:58:26 +0100 From: Peter Maydell To: qemu-devel@nongnu.org Cc: patches@linaro.org, Riku Voipio , =?UTF-8?q?Juha=20Riihim=C3=A4ki?= , andrzej zaborowski , Markus Armbruster Subject: [PATCH 12/12] hw/onenand: qdevify Date: Fri, 15 Jul 2011 15:58:26 +0100 Message-Id: <1310741906-1606-13-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1310741906-1606-1-git-send-email-peter.maydell@linaro.org> References: <1310741906-1606-1-git-send-email-peter.maydell@linaro.org> MIME-Version: 1.0 From: Juha Riihimäki Qdevify the ONENAND device. Signed-off-by: Juha Riihimäki [Riku Voipio: Fixes and restructuring patchset] Signed-off-by: Riku Voipio [Peter Maydell: More fixes and cleanups for upstream submission] Signed-off-by: Peter Maydell --- 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)