All of lore.kernel.org
 help / color / mirror / Atom feed
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
To: qemu-devel@nongnu.org
Cc: vineshp@xilinx.com, peter.maydell@linaro.org,
	Peter Crosthwaite <peter.crosthwaite@xilinx.com>,
	john.williams@xilinx.com, pbonzini@redhat.com,
	edgar.iglesias@gmail.com
Subject: [Qemu-devel] [PATCH v2 4/6] hw: Model of Primecell pl35x mem controller
Date: Mon, 22 Oct 2012 17:19:02 +1000	[thread overview]
Message-ID: <020c14efe0e1fa525818941c0e88cf272f55e20d.1350889929.git.peter.crosthwaite@xilinx.com> (raw)
In-Reply-To: <cover.1350889929.git.peter.crosthwaite@xilinx.com>
In-Reply-To: <cover.1350889929.git.peter.crosthwaite@xilinx.com>

Initial device model for the pl35x series of memory controllers. The SRAM
interface is just implemented as a passthrough using memory regions. NAND
interfaces are modelled.

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
---
changed since v1:
use sysbus_mmio_get_region() for SRAM mappings (PMM Review)
fixed header comment s/pl353/pl35x
fixed complie warnings in debug mode (-DPL35X_DEBUG)

 default-configs/arm-softmmu.mak |    1 +
 hw/Makefile.objs                |    1 +
 hw/pl35x.c                      |  299 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 301 insertions(+), 0 deletions(-)
 create mode 100644 hw/pl35x.c

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 2f1a5c9..b24bf68 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -41,6 +41,7 @@ CONFIG_PL110=y
 CONFIG_PL181=y
 CONFIG_PL190=y
 CONFIG_PL310=y
+CONFIG_PL35X=y
 CONFIG_CADENCE=y
 CONFIG_XGMAC=y
 
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 854faa9..502f139 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -88,6 +88,7 @@ common-obj-$(CONFIG_PL110) += pl110.o
 common-obj-$(CONFIG_PL181) += pl181.o
 common-obj-$(CONFIG_PL190) += pl190.o
 common-obj-$(CONFIG_PL310) += arm_l2x0.o
+common-obj-$(CONFIG_PL35X) += pl35x.o
 common-obj-$(CONFIG_VERSATILE_PCI) += versatile_pci.o
 common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
 common-obj-$(CONFIG_CADENCE) += cadence_uart.o
diff --git a/hw/pl35x.c b/hw/pl35x.c
new file mode 100644
index 0000000..0f8c5ed
--- /dev/null
+++ b/hw/pl35x.c
@@ -0,0 +1,299 @@
+/*
+ * QEMU model of Primcell PL35X family of memory controllers
+ *
+ * Copyright (c) 2012 Xilinx Inc.
+ * Copyright (c) 2012 Peter Crosthwaite <peter.crosthwaite@xilinx.com>.
+ * Copyright (c) 2011 Edgar E. Iglesias.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw.h"
+#include "qemu-timer.h"
+#include "sysbus.h"
+#include "sysemu.h"
+#include "flash.h"
+
+#ifdef PL35X_ERR_DEBUG
+#define DB_PRINT(...) do { \
+    fprintf(stderr,  ": %s: ", __func__); \
+    fprintf(stderr, ## __VA_ARGS__); \
+    } while (0);
+#else
+    #define DB_PRINT(...)
+#endif
+
+typedef struct PL35xItf {
+    MemoryRegion mm;
+    DeviceState *dev;
+    uint8_t nand_pending_addr_cycles;
+} PL35xItf;
+
+typedef struct PL35xState {
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+
+    /* FIXME: add support for multiple chip selects/interface */
+
+    PL35xItf itf[2];
+
+    /* FIXME: add Interrupt support */
+
+    /* FIXME: add ECC support */
+
+    uint8_t x; /* the "x" in pl35x */
+} PL35xState;
+
+static uint64_t pl35x_read(void *opaque, target_phys_addr_t addr,
+                         unsigned int size)
+{
+    PL35xState *s = opaque;
+    uint32_t r = 0;
+    int rdy;
+
+    addr >>= 2;
+    switch (addr) {
+    case 0x0:
+        if (s->itf[0].dev && object_dynamic_cast(OBJECT(s->itf[0].dev),
+                                                      "nand")) {
+            nand_getpins(s->itf[0].dev, &rdy);
+            r |= (!!rdy) << 5;
+        }
+        if (s->itf[1].dev && object_dynamic_cast(OBJECT(s->itf[1].dev),
+                                                      "nand")) {
+            nand_getpins(s->itf[1].dev, &rdy);
+            r |= (!!rdy) << 6;
+        }
+        break;
+    default:
+        DB_PRINT("Unimplemented SMC read access reg=" TARGET_FMT_plx "\n",
+                 addr * 4);
+        break;
+    }
+    return r;
+}
+
+static void pl35x_write(void *opaque, target_phys_addr_t addr, uint64_t value64,
+                      unsigned int size)
+{
+    DB_PRINT("addr=%x v=%x\n", (unsigned)addr, (unsigned)value64);
+    addr >>= 2;
+    /* FIXME: implement */
+    DB_PRINT("Unimplemented SMC write access reg=" TARGET_FMT_plx "\n",
+                 addr * 4);
+}
+
+static const MemoryRegionOps pl35x_ops = {
+    .read = pl35x_read,
+    .write = pl35x_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static uint64_t nand_read(void *opaque, target_phys_addr_t addr,
+                           unsigned int size)
+{
+    PL35xItf *s = opaque;
+    unsigned int len = size;
+    int shift = 0;
+    uint32_t r = 0;
+
+    while (len--) {
+        uint8_t r8;
+
+        r8 = nand_getio(s->dev) & 0xff;
+        r |= r8 << shift;
+        shift += 8;
+    }
+    DB_PRINT("addr=%x r=%x size=%d\n", (unsigned)addr, r, size);
+    return r;
+}
+
+static void nand_write(void *opaque, target_phys_addr_t addr, uint64_t value64,
+                       unsigned int size)
+{
+    struct PL35xItf *s = opaque;
+    bool data_phase, ecmd_valid;
+    unsigned int addr_cycles = 0;
+    uint16_t start_cmd, end_cmd;
+    uint32_t value = value64;
+    uint32_t nandaddr = value;
+
+    DB_PRINT("addr=%x v=%x size=%d\n", (unsigned)addr, (unsigned)value, size);
+
+    /* Decode the various signals.  */
+    data_phase = (addr >> 19) & 1;
+    ecmd_valid = (addr >> 20) & 1;
+    start_cmd = (addr >> 3) & 0xff;
+    end_cmd = (addr >> 11) & 0xff;
+    if (!data_phase) {
+        addr_cycles = (addr >> 21) & 7;
+    }
+
+    if (!data_phase) {
+        DB_PRINT("start_cmd=%x end_cmd=%x (valid=%d) acycl=%d\n",
+                start_cmd, end_cmd, ecmd_valid, addr_cycles);
+    }
+
+    /* Writing data to the NAND.  */
+    if (data_phase) {
+        nand_setpins(s->dev, 0, 0, 0, 1, 0);
+        while (size--) {
+            nand_setio(s->dev, value & 0xff);
+            value >>= 8;
+        }
+    }
+
+    /* Writing Start cmd.  */
+    if (!data_phase && !s->nand_pending_addr_cycles) {
+        nand_setpins(s->dev, 1, 0, 0, 1, 0);
+        nand_setio(s->dev, start_cmd);
+    }
+
+    if (!addr_cycles) {
+        s->nand_pending_addr_cycles = 0;
+    }
+    if (s->nand_pending_addr_cycles) {
+        addr_cycles = s->nand_pending_addr_cycles;
+        s->nand_pending_addr_cycles = 0;
+    }
+    if (addr_cycles > 4) {
+        s->nand_pending_addr_cycles = addr_cycles - 4;
+        addr_cycles = 4;
+    }
+    while (addr_cycles) {
+        nand_setpins(s->dev, 0, 1, 0, 1, 0);
+        DB_PRINT("nand cycl=%d addr=%x\n", addr_cycles, nandaddr & 0xff);
+        nand_setio(s->dev, nandaddr & 0xff);
+        nandaddr >>= 8;
+        addr_cycles--;
+    }
+
+    /* Writing commands. One or two (Start and End).  */
+    if (ecmd_valid && !s->nand_pending_addr_cycles) {
+        nand_setpins(s->dev, 1, 0, 0, 1, 0);
+        nand_setio(s->dev, end_cmd);
+    }
+}
+
+static const MemoryRegionOps nand_ops = {
+    .read = nand_read,
+    .write = nand_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 4
+    }
+};
+
+static void pl35x_init_sram(SysBusDevice *dev, PL35xItf *itf)
+{
+    /* d Just needs to be a valid sysbus device with at least one memory
+     * region
+     */
+    SysBusDevice *sbd = SYS_BUS_DEVICE(itf->dev);
+
+    memory_region_init(&itf->mm, "pl35x.sram", 1 << 24);
+    memory_region_add_subregion(&itf->mm, 0, sysbus_mmio_get_region(sbd, 0));
+    sysbus_init_mmio(dev, &itf->mm);
+}
+
+static void pl35x_init_nand(SysBusDevice *dev, PL35xItf *itf)
+{
+    /* d Must be a NAND flash */
+    object_dynamic_cast_assert(OBJECT(itf->dev), "nand");
+
+    memory_region_init_io(&itf->mm, &nand_ops, itf, "pl35x.nand", 1 << 24);
+    sysbus_init_mmio(dev, &itf->mm);
+}
+
+static int pl35x_init(SysBusDevice *dev)
+{
+    PL35xState *s = FROM_SYSBUS(typeof(*s), dev);
+    int itfn = 0;
+
+    memory_region_init_io(&s->mmio, &pl35x_ops, s, "pl35x_io", 0x1000);
+    sysbus_init_mmio(dev, &s->mmio);
+    if (s->x != 1) { /* everything cept PL351 has at least one SRAM */
+        pl35x_init_sram(dev, &s->itf[itfn]);
+        itfn++;
+    }
+    if (s->x & 0x1) { /* PL351 and PL353 have NAND */
+        pl35x_init_nand(dev, &s->itf[itfn]);
+    } else if (s->x == 4) { /* PL354 has a second SRAM */
+        pl35x_init_sram(dev, &s->itf[itfn]);
+    }
+    return 0;
+}
+static void pl35x_initfn(Object *obj)
+{
+    PL35xState *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
+    Error *errp = NULL;
+
+    object_property_add_link(obj, "dev0", TYPE_DEVICE,
+                             (Object **)&s->itf[0].dev, &errp);
+    assert_no_error(errp);
+    object_property_add_link(obj, "dev1", TYPE_DEVICE,
+                             (Object **)&s->itf[1].dev, &errp);
+    assert_no_error(errp);
+}
+
+static Property pl35x_properties[] = {
+    DEFINE_PROP_UINT8("x", PL35xState, x, 3),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription vmstate_pl35x = {
+    .name = "pl35x",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(itf[0].nand_pending_addr_cycles, PL35xState),
+        VMSTATE_UINT8(itf[1].nand_pending_addr_cycles, PL35xState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void pl35x_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl35x_init;
+    dc->props = pl35x_properties;
+    dc->vmsd = &vmstate_pl35x;
+}
+
+static TypeInfo pl35x_info = {
+    .name           = "arm.pl35x",
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(PL35xState),
+    .class_init     = pl35x_class_init,
+    .instance_init  = pl35x_initfn,
+};
+
+static void pl35x_register_types(void)
+{
+    type_register_static(&pl35x_info);
+}
+
+type_init(pl35x_register_types)
-- 
1.7.0.4

  parent reply	other threads:[~2012-10-22  7:19 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-10-22  7:18 [Qemu-devel] [PATCH v2 0/6] QOMify pflash_cfi0x + PL353 for Xilinx Zynq Peter Crosthwaite
2012-10-22  7:18 ` [Qemu-devel] [PATCH v2 1/6] pflash_cfi0x: remove unused base field Peter Crosthwaite
2012-10-22  7:19 ` [Qemu-devel] [PATCH v2 2/6] pflash_cfi01: remove unused total_len field Peter Crosthwaite
2012-10-22  7:19 ` [Qemu-devel] [PATCH v2 3/6] pflash_cfi0x: QOMified Peter Crosthwaite
2012-10-22 14:36   ` Peter Maydell
2012-10-22  7:19 ` Peter Crosthwaite [this message]
2012-10-22 16:12   ` [Qemu-devel] [PATCH v2 4/6] hw: Model of Primecell pl35x mem controller Peter Maydell
2012-10-22 18:43     ` Peter Crosthwaite
2012-10-22  7:19 ` [Qemu-devel] [PATCH v2 5/6] xilinx_zynq: add pl353 Peter Crosthwaite
2012-10-22 19:06   ` Peter Maydell
2013-11-06 12:46     ` vbalaji
2012-10-22  7:19 ` [Qemu-devel] [PATCH v2 6/6] pflash_cfi01: Fix debug mode printfery Peter Crosthwaite
2012-10-22 16:17   ` Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=020c14efe0e1fa525818941c0e88cf272f55e20d.1350889929.git.peter.crosthwaite@xilinx.com \
    --to=peter.crosthwaite@xilinx.com \
    --cc=edgar.iglesias@gmail.com \
    --cc=john.williams@xilinx.com \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=vineshp@xilinx.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.