All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v7 0/4] i.MX: Add i.MX25 support through the 3DS evaluation board.
@ 2015-06-22 19:06 Jean-Christophe Dubois
  2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 1/4] i.MX: Add FEC Ethernet Emulator Jean-Christophe Dubois
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Jean-Christophe Dubois @ 2015-06-22 19:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jean-Christophe Dubois

This series of patches add the support for the i.MX25 processor through the
Freescale 3DS evaluation board.

For now a limited set of devices are supported.
    * GPT timers (from i.MX31)
    * EPIT timers (from i.MX31)
    * Serial ports (from i.MX31)
    * Ethernet FEC port
    * I2C controller

This was tested by:
    * booting a minimal linux system
    * booting the Xvisor hypervisor.

Jean-Christophe Dubois (4):
  i.MX: Add FEC Ethernet Emulator.
  i.MX: Add I2C contoller emulator
  i.MX: Add i.MX25 3DS evaluation board support
  i.MX: Add qtest support for I2C device	emulator

 default-configs/arm-softmmu.mak |   3 +
 hw/arm/Makefile.objs            |   1 +
 hw/arm/imx25_3ds.c              | 273 +++++++++++++
 hw/i2c/Makefile.objs            |   1 +
 hw/i2c/imx_i2c.c                | 361 ++++++++++++++++++
 hw/i2c/imx_i2c_regs.h           |  63 +++
 hw/net/Makefile.objs            |   1 +
 hw/net/imx_fec.c                | 820 ++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/imx.h            |   1 +
 tests/Makefile                  |   3 +
 tests/ds1338-test.c             |  75 ++++
 tests/libqos/i2c-imx.c          | 209 ++++++++++
 tests/libqos/i2c.h              |   3 +
 13 files changed, 1814 insertions(+)
 create mode 100644 hw/arm/imx25_3ds.c
 create mode 100644 hw/i2c/imx_i2c.c
 create mode 100644 hw/i2c/imx_i2c_regs.h
 create mode 100644 hw/net/imx_fec.c
 create mode 100644 tests/ds1338-test.c
 create mode 100644 tests/libqos/i2c-imx.c

-- 
2.1.4

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

* [Qemu-devel] [PATCH v7 1/4] i.MX: Add FEC Ethernet Emulator.
  2015-06-22 19:06 [Qemu-devel] [PATCH v7 0/4] i.MX: Add i.MX25 support through the 3DS evaluation board Jean-Christophe Dubois
@ 2015-06-22 19:06 ` Jean-Christophe Dubois
  2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 2/4] i.MX: Add I2C contoller emulator Jean-Christophe Dubois
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Jean-Christophe Dubois @ 2015-06-22 19:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jean-Christophe Dubois

This is based on the mcf_fec.c FEC implementation for ColdFire.

    * a generic phy was added (borrowed from lan9118).
    * The buffer management is also modified as buffers are
      slightly different between coldfire and i.MX.

Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>
---

Changes since v1:
    * none

Changes since v2:
    * use QOM cast
    * reworked debug printf
    * use CamelCase for state type
    * warn with qemu_log_mask(LOG_GUEST_ERROR) or qemu_log_mask(LOG_UNIMP)
    * move to dma_memory_read/write API
    * rework interrupt handling
    * use qemu_flush_queued_packets() in rx_enable()

Changes since v3:
    * use realise for device initialization
    * More QOM cast
    * reworked debug printf some more
    * standardise GPL header
    * use CamelCase for buffer descriptor type

Changes since v4:
    * none

Changes since v5:
    * replace hw_error() with qemu_log_mask(LOG_GUEST_ERROR, ...)
    * remove reformating of imx.h header file.
    * remove unnecessary spaces.

Changes since v6:
    * port to new memory API
 default-configs/arm-softmmu.mak |   1 +
 hw/net/Makefile.objs            |   1 +
 hw/net/imx_fec.c                | 820 ++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/imx.h            |   1 +
 4 files changed, 823 insertions(+)
 create mode 100644 hw/net/imx_fec.c

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 74f1db3..d21ff7b 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -28,6 +28,7 @@ CONFIG_SSI_M25P80=y
 CONFIG_LAN9118=y
 CONFIG_SMC91C111=y
 CONFIG_ALLWINNER_EMAC=y
+CONFIG_IMX_FEC=y
 CONFIG_DS1338=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
index 9880173..64d0449 100644
--- a/hw/net/Makefile.objs
+++ b/hw/net/Makefile.objs
@@ -19,6 +19,7 @@ common-obj-$(CONFIG_XGMAC) += xgmac.o
 common-obj-$(CONFIG_MIPSNET) += mipsnet.o
 common-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o
 common-obj-$(CONFIG_ALLWINNER_EMAC) += allwinner_emac.o
+common-obj-$(CONFIG_IMX_FEC) += imx_fec.o
 
 common-obj-$(CONFIG_CADENCE) += cadence_gem.o
 common-obj-$(CONFIG_STELLARIS_ENET) += stellaris_enet.o
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
new file mode 100644
index 0000000..8649bb0
--- /dev/null
+++ b/hw/net/imx_fec.c
@@ -0,0 +1,820 @@
+/*
+ * i.MX Fast Ethernet Controller emulation.
+ *
+ * Copyright (c) 2013 Jean-Christophe Dubois.
+ *
+ * Based on Coldfire Fast Ethernet Controller emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysemu/dma.h"
+#include "hw/sysbus.h"
+#include "net/net.h"
+#include "hw/devices.h"
+#include "exec/address-spaces.h"
+
+/* For crc32 */
+#include <zlib.h>
+
+#include "hw/arm/imx.h"
+
+#ifndef IMX_FEC_DEBUG
+#define IMX_FEC_DEBUG          0
+#endif
+
+#ifndef IMX_PHY_DEBUG
+#define IMX_PHY_DEBUG          0
+#endif
+
+#if IMX_FEC_DEBUG
+#define FEC_PRINTF(fmt, ...) \
+    do { fprintf(stderr, "%s[%s]: " fmt , TYPE_IMX_FEC, __func__, \
+                 ## __VA_ARGS__); \
+    } while (0)
+#else
+#define FEC_PRINTF(fmt, ...) do {} while (0)
+#endif
+
+#if IMX_PHY_DEBUG
+#define PHY_PRINTF(fmt, ...) \
+    do { fprintf(stderr, "%s.phy[%s]: " fmt , TYPE_IMX_FEC, __func__, \
+                 ## __VA_ARGS__); \
+    } while (0)
+#else
+#define PHY_PRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define TYPE_IMX_FEC "imx.fec"
+#define IMX_FEC(obj) \
+    OBJECT_CHECK(IMXFECState, (obj), TYPE_IMX_FEC)
+
+#define FEC_MAX_FRAME_SIZE 2032
+
+typedef struct {
+    SysBusDevice parent_obj;
+
+    NICState *nic;
+    NICConf conf;
+    qemu_irq irq;
+    MemoryRegion iomem;
+
+    uint32_t irq_state;
+    uint32_t eir;
+    uint32_t eimr;
+    uint32_t rx_enabled;
+    uint32_t rx_descriptor;
+    uint32_t tx_descriptor;
+    uint32_t ecr;
+    uint32_t mmfr;
+    uint32_t mscr;
+    uint32_t mibc;
+    uint32_t rcr;
+    uint32_t tcr;
+    uint32_t tfwr;
+    uint32_t frsr;
+    uint32_t erdsr;
+    uint32_t etdsr;
+    uint32_t emrbr;
+    uint32_t miigsk_cfgr;
+    uint32_t miigsk_enr;
+
+    uint32_t phy_status;
+    uint32_t phy_control;
+    uint32_t phy_advertise;
+    uint32_t phy_int;
+    uint32_t phy_int_mask;
+} IMXFECState;
+
+static const VMStateDescription vmstate_imx_fec = {
+    .name = TYPE_IMX_FEC,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(irq_state, IMXFECState),
+        VMSTATE_UINT32(eir, IMXFECState),
+        VMSTATE_UINT32(eimr, IMXFECState),
+        VMSTATE_UINT32(rx_enabled, IMXFECState),
+        VMSTATE_UINT32(rx_descriptor, IMXFECState),
+        VMSTATE_UINT32(tx_descriptor, IMXFECState),
+        VMSTATE_UINT32(ecr, IMXFECState),
+        VMSTATE_UINT32(mmfr, IMXFECState),
+        VMSTATE_UINT32(mscr, IMXFECState),
+        VMSTATE_UINT32(mibc, IMXFECState),
+        VMSTATE_UINT32(rcr, IMXFECState),
+        VMSTATE_UINT32(tcr, IMXFECState),
+        VMSTATE_UINT32(tfwr, IMXFECState),
+        VMSTATE_UINT32(frsr, IMXFECState),
+        VMSTATE_UINT32(erdsr, IMXFECState),
+        VMSTATE_UINT32(etdsr, IMXFECState),
+        VMSTATE_UINT32(emrbr, IMXFECState),
+        VMSTATE_UINT32(miigsk_cfgr, IMXFECState),
+        VMSTATE_UINT32(miigsk_enr, IMXFECState),
+
+        VMSTATE_UINT32(phy_status, IMXFECState),
+        VMSTATE_UINT32(phy_control, IMXFECState),
+        VMSTATE_UINT32(phy_advertise, IMXFECState),
+        VMSTATE_UINT32(phy_int, IMXFECState),
+        VMSTATE_UINT32(phy_int_mask, IMXFECState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#define PHY_INT_ENERGYON            (1 << 7)
+#define PHY_INT_AUTONEG_COMPLETE    (1 << 6)
+#define PHY_INT_FAULT               (1 << 5)
+#define PHY_INT_DOWN                (1 << 4)
+#define PHY_INT_AUTONEG_LP          (1 << 3)
+#define PHY_INT_PARFAULT            (1 << 2)
+#define PHY_INT_AUTONEG_PAGE        (1 << 1)
+
+static void imx_fec_update(IMXFECState *s);
+
+/*
+ * The MII phy could raise a GPIO to the processor which in turn
+ * could be handled as an interrpt by the OS.
+ * For now we don't handle any GPIO/interrupt line, so the OS will
+ * have to poll for the PHY status.
+ */
+static void phy_update_irq(IMXFECState *s)
+{
+    imx_fec_update(s);
+}
+
+static void phy_update_link(IMXFECState *s)
+{
+    /* Autonegotiation status mirrors link status.  */
+    if (qemu_get_queue(s->nic)->link_down) {
+        PHY_PRINTF("link is down\n");
+        s->phy_status &= ~0x0024;
+        s->phy_int |= PHY_INT_DOWN;
+    } else {
+        PHY_PRINTF("link is up\n");
+        s->phy_status |= 0x0024;
+        s->phy_int |= PHY_INT_ENERGYON;
+        s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
+    }
+    phy_update_irq(s);
+}
+
+static void imx_fec_set_link(NetClientState *nc)
+{
+    phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc)));
+}
+
+static void phy_reset(IMXFECState *s)
+{
+    s->phy_status = 0x7809;
+    s->phy_control = 0x3000;
+    s->phy_advertise = 0x01e1;
+    s->phy_int_mask = 0;
+    s->phy_int = 0;
+    phy_update_link(s);
+}
+
+static uint32_t do_phy_read(IMXFECState *s, int reg)
+{
+    uint32_t val;
+
+    if (reg > 31) {
+        /* we only advertise one phy */
+        return 0;
+    }
+
+    switch (reg) {
+    case 0:     /* Basic Control */
+        val = s->phy_control;
+        break;
+    case 1:     /* Basic Status */
+        val = s->phy_status;
+        break;
+    case 2:     /* ID1 */
+        val = 0x0007;
+        break;
+    case 3:     /* ID2 */
+        val = 0xc0d1;
+        break;
+    case 4:     /* Auto-neg advertisement */
+        val = s->phy_advertise;
+        break;
+    case 5:     /* Auto-neg Link Partner Ability */
+        val = 0x0f71;
+        break;
+    case 6:     /* Auto-neg Expansion */
+        val = 1;
+        break;
+    case 29:    /* Interrupt source.  */
+        val = s->phy_int;
+        s->phy_int = 0;
+        phy_update_irq(s);
+        break;
+    case 30:    /* Interrupt mask */
+        val = s->phy_int_mask;
+        break;
+    case 17:
+    case 18:
+    case 27:
+    case 31:
+        qemu_log_mask(LOG_UNIMP, "%s.phy[%s]: reg %d not implemented\n",
+                      TYPE_IMX_FEC, __func__, reg);
+        val = 0;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
+                      TYPE_IMX_FEC, __func__, reg);
+        val = 0;
+        break;
+    }
+
+    PHY_PRINTF("read 0x%04x @ %d\n", val, reg);
+
+    return val;
+}
+
+static void do_phy_write(IMXFECState *s, int reg, uint32_t val)
+{
+    PHY_PRINTF("write 0x%04x @ %d\n", val, reg);
+
+    if (reg > 31) {
+        /* we only advertise one phy */
+        return;
+    }
+
+    switch (reg) {
+    case 0:     /* Basic Control */
+        if (val & 0x8000) {
+            phy_reset(s);
+        } else {
+            s->phy_control = val & 0x7980;
+            /* Complete autonegotiation immediately.  */
+            if (val & 0x1000) {
+                s->phy_status |= 0x0020;
+            }
+        }
+        break;
+    case 4:     /* Auto-neg advertisement */
+        s->phy_advertise = (val & 0x2d7f) | 0x80;
+        break;
+    case 30:    /* Interrupt mask */
+        s->phy_int_mask = val & 0xff;
+        phy_update_irq(s);
+        break;
+    case 17:
+    case 18:
+    case 27:
+    case 31:
+        qemu_log_mask(LOG_UNIMP, "%s.phy[%s]: reg %d not implemented\n",
+                      TYPE_IMX_FEC, __func__, reg);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
+                      TYPE_IMX_FEC, __func__, reg);
+        break;
+    }
+}
+
+#define FEC_INT_HB      (1 << 31)
+#define FEC_INT_BABR    (1 << 30)
+#define FEC_INT_BABT    (1 << 29)
+#define FEC_INT_GRA     (1 << 28)
+#define FEC_INT_TXF     (1 << 27)
+#define FEC_INT_TXB     (1 << 26)
+#define FEC_INT_RXF     (1 << 25)
+#define FEC_INT_RXB     (1 << 24)
+#define FEC_INT_MII     (1 << 23)
+#define FEC_INT_EBERR   (1 << 22)
+#define FEC_INT_LC      (1 << 21)
+#define FEC_INT_RL      (1 << 20)
+#define FEC_INT_UN      (1 << 19)
+
+#define FEC_EN      2
+#define FEC_RESET   1
+
+/* Buffer Descriptor.  */
+typedef struct {
+    uint16_t length;
+    uint16_t flags;
+    uint32_t data;
+} IMXFECBufDesc;
+
+#define FEC_BD_R    (1 << 15)
+#define FEC_BD_E    (1 << 15)
+#define FEC_BD_O1   (1 << 14)
+#define FEC_BD_W    (1 << 13)
+#define FEC_BD_O2   (1 << 12)
+#define FEC_BD_L    (1 << 11)
+#define FEC_BD_TC   (1 << 10)
+#define FEC_BD_ABC  (1 << 9)
+#define FEC_BD_M    (1 << 8)
+#define FEC_BD_BC   (1 << 7)
+#define FEC_BD_MC   (1 << 6)
+#define FEC_BD_LG   (1 << 5)
+#define FEC_BD_NO   (1 << 4)
+#define FEC_BD_CR   (1 << 2)
+#define FEC_BD_OV   (1 << 1)
+#define FEC_BD_TR   (1 << 0)
+
+static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr)
+{
+    dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd));
+}
+
+static void imx_fec_write_bd(IMXFECBufDesc *bd, dma_addr_t addr)
+{
+    dma_memory_write(&address_space_memory, addr, bd, sizeof(*bd));
+}
+
+static void imx_fec_update(IMXFECState *s)
+{
+    uint32_t active;
+    uint32_t changed;
+
+    active = s->eir & s->eimr;
+    changed = active ^ s->irq_state;
+    if (changed) {
+        qemu_set_irq(s->irq, active);
+    }
+    s->irq_state = active;
+}
+
+static void imx_fec_do_tx(IMXFECState *s)
+{
+    int frame_size = 0;
+    uint8_t frame[FEC_MAX_FRAME_SIZE];
+    uint8_t *ptr = frame;
+    uint32_t addr = s->tx_descriptor;
+
+    while (1) {
+        IMXFECBufDesc bd;
+        int len;
+
+        imx_fec_read_bd(&bd, addr);
+        FEC_PRINTF("tx_bd %x flags %04x len %d data %08x\n",
+                   addr, bd.flags, bd.length, bd.data);
+        if ((bd.flags & FEC_BD_R) == 0) {
+            /* Run out of descriptors to transmit.  */
+            break;
+        }
+        len = bd.length;
+        if (frame_size + len > FEC_MAX_FRAME_SIZE) {
+            len = FEC_MAX_FRAME_SIZE - frame_size;
+            s->eir |= FEC_INT_BABT;
+        }
+        dma_memory_read(&address_space_memory, bd.data, ptr, len);
+        ptr += len;
+        frame_size += len;
+        if (bd.flags & FEC_BD_L) {
+            /* Last buffer in frame.  */
+            qemu_send_packet(qemu_get_queue(s->nic), frame, len);
+            ptr = frame;
+            frame_size = 0;
+            s->eir |= FEC_INT_TXF;
+        }
+        s->eir |= FEC_INT_TXB;
+        bd.flags &= ~FEC_BD_R;
+        /* Write back the modified descriptor.  */
+        imx_fec_write_bd(&bd, addr);
+        /* Advance to the next descriptor.  */
+        if ((bd.flags & FEC_BD_W) != 0) {
+            addr = s->etdsr;
+        } else {
+            addr += 8;
+        }
+    }
+
+    s->tx_descriptor = addr;
+
+    imx_fec_update(s);
+}
+
+static void imx_fec_enable_rx(IMXFECState *s)
+{
+    IMXFECBufDesc bd;
+    uint32_t tmp;
+
+    imx_fec_read_bd(&bd, s->rx_descriptor);
+
+    tmp = ((bd.flags & FEC_BD_E) != 0);
+
+    if (!tmp) {
+        FEC_PRINTF("RX buffer full\n");
+    } else if (!s->rx_enabled) {
+        qemu_flush_queued_packets(qemu_get_queue(s->nic));
+    }
+
+    s->rx_enabled = tmp;
+}
+
+static void imx_fec_reset(DeviceState *d)
+{
+    IMXFECState *s = IMX_FEC(d);
+
+    /* Reset the FEC */
+    s->eir = 0;
+    s->eimr = 0;
+    s->rx_enabled = 0;
+    s->ecr = 0;
+    s->mscr = 0;
+    s->mibc = 0xc0000000;
+    s->rcr = 0x05ee0001;
+    s->tcr = 0;
+    s->tfwr = 0;
+    s->frsr = 0x500;
+    s->miigsk_cfgr = 0;
+    s->miigsk_enr = 0x6;
+
+    /* We also reset the PHY */
+    phy_reset(s);
+}
+
+static uint64_t imx_fec_read(void *opaque, hwaddr addr, unsigned size)
+{
+    IMXFECState *s = IMX_FEC(opaque);
+
+    FEC_PRINTF("reading from @ 0x%03x\n", (int)addr);
+
+    switch (addr & 0x3ff) {
+    case 0x004:
+        return s->eir;
+    case 0x008:
+        return s->eimr;
+    case 0x010:
+        return s->rx_enabled ? (1 << 24) : 0;   /* RDAR */
+    case 0x014:
+        return 0;   /* TDAR */
+    case 0x024:
+        return s->ecr;
+    case 0x040:
+        return s->mmfr;
+    case 0x044:
+        return s->mscr;
+    case 0x064:
+        return s->mibc; /* MIBC */
+    case 0x084:
+        return s->rcr;
+    case 0x0c4:
+        return s->tcr;
+    case 0x0e4:     /* PALR */
+        return (s->conf.macaddr.a[0] << 24)
+               | (s->conf.macaddr.a[1] << 16)
+               | (s->conf.macaddr.a[2] << 8)
+               | s->conf.macaddr.a[3];
+        break;
+    case 0x0e8:     /* PAUR */
+        return (s->conf.macaddr.a[4] << 24)
+               | (s->conf.macaddr.a[5] << 16)
+               | 0x8808;
+    case 0x0ec:
+        return 0x10000; /* OPD */
+    case 0x118:
+        return 0;
+    case 0x11c:
+        return 0;
+    case 0x120:
+        return 0;
+    case 0x124:
+        return 0;
+    case 0x144:
+        return s->tfwr;
+    case 0x14c:
+        return 0x600;
+    case 0x150:
+        return s->frsr;
+    case 0x180:
+        return s->erdsr;
+    case 0x184:
+        return s->etdsr;
+    case 0x188:
+        return s->emrbr;
+    case 0x300:
+        return s->miigsk_cfgr;
+    case 0x308:
+        return s->miigsk_enr;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
+                      TYPE_IMX_FEC, __func__, (int)addr);
+        return 0;
+    }
+}
+
+static void imx_fec_write(void *opaque, hwaddr addr,
+                          uint64_t value, unsigned size)
+{
+    IMXFECState *s = IMX_FEC(opaque);
+
+    FEC_PRINTF("writing 0x%08x @ 0x%03x\n", (int)value, (int)addr);
+
+    switch (addr & 0x3ff) {
+    case 0x004: /* EIR */
+        s->eir &= ~value;
+        break;
+    case 0x008: /* EIMR */
+        s->eimr = value;
+        break;
+    case 0x010: /* RDAR */
+        if ((s->ecr & FEC_EN) && !s->rx_enabled) {
+            imx_fec_enable_rx(s);
+        }
+        break;
+    case 0x014: /* TDAR */
+        if (s->ecr & FEC_EN) {
+            imx_fec_do_tx(s);
+        }
+        break;
+    case 0x024: /* ECR */
+        s->ecr = value;
+        if (value & FEC_RESET) {
+            imx_fec_reset(DEVICE(s));
+        }
+        if ((s->ecr & FEC_EN) == 0) {
+            s->rx_enabled = 0;
+        }
+        break;
+    case 0x040: /* MMFR */
+        /* store the value */
+        s->mmfr = value;
+        if (extract32(value, 28, 1)) {
+            do_phy_write(s, extract32(value, 18, 9), extract32(value, 0, 16));
+        } else {
+            s->mmfr = do_phy_read(s, extract32(value, 18, 9));
+        }
+        /* raise the interrupt as the PHY operation is done */
+        s->eir |= FEC_INT_MII;
+        break;
+    case 0x044: /* MSCR */
+        s->mscr = value & 0xfe;
+        break;
+    case 0x064: /* MIBC */
+        /* TODO: Implement MIB.  */
+        s->mibc = (value & 0x80000000) ? 0xc0000000 : 0;
+        break;
+    case 0x084: /* RCR */
+        s->rcr = value & 0x07ff003f;
+        /* TODO: Implement LOOP mode.  */
+        break;
+    case 0x0c4: /* TCR */
+        /* We transmit immediately, so raise GRA immediately.  */
+        s->tcr = value;
+        if (value & 1) {
+            s->eir |= FEC_INT_GRA;
+        }
+        break;
+    case 0x0e4: /* PALR */
+        s->conf.macaddr.a[0] = value >> 24;
+        s->conf.macaddr.a[1] = value >> 16;
+        s->conf.macaddr.a[2] = value >> 8;
+        s->conf.macaddr.a[3] = value;
+        break;
+    case 0x0e8: /* PAUR */
+        s->conf.macaddr.a[4] = value >> 24;
+        s->conf.macaddr.a[5] = value >> 16;
+        break;
+    case 0x0ec: /* OPDR */
+        break;
+    case 0x118: /* IAUR */
+    case 0x11c: /* IALR */
+    case 0x120: /* GAUR */
+    case 0x124: /* GALR */
+        /* TODO: implement MAC hash filtering.  */
+        break;
+    case 0x144: /* TFWR */
+        s->tfwr = value & 3;
+        break;
+    case 0x14c: /* FRBR */
+        /* FRBR writes ignored.  */
+        break;
+    case 0x150: /* FRSR */
+        s->frsr = (value & 0x3fc) | 0x400;
+        break;
+    case 0x180: /* ERDSR */
+        s->erdsr = value & ~3;
+        s->rx_descriptor = s->erdsr;
+        break;
+    case 0x184: /* ETDSR */
+        s->etdsr = value & ~3;
+        s->tx_descriptor = s->etdsr;
+        break;
+    case 0x188: /* EMRBR */
+        s->emrbr = value & 0x7f0;
+        break;
+    case 0x300: /* MIIGSK_CFGR */
+        s->miigsk_cfgr = value & 0x53;
+        break;
+    case 0x308: /* MIIGSK_ENR */
+        s->miigsk_enr = (value & 0x2) ? 0x6 : 0;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
+                      TYPE_IMX_FEC, __func__, (int)addr);
+        break;
+    }
+
+    imx_fec_update(s);
+}
+
+static int imx_fec_can_receive(NetClientState *nc)
+{
+    IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
+
+    return s->rx_enabled;
+}
+
+static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf,
+                               size_t len)
+{
+    IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
+    IMXFECBufDesc bd;
+    uint32_t flags = 0;
+    uint32_t addr;
+    uint32_t crc;
+    uint32_t buf_addr;
+    uint8_t *crc_ptr;
+    unsigned int buf_len;
+    size_t size = len;
+
+    FEC_PRINTF("len %d\n", (int)size);
+
+    if (!s->rx_enabled) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Unexpected packet\n",
+                      TYPE_IMX_FEC, __func__);
+        return 0;
+    }
+
+    /* 4 bytes for the CRC.  */
+    size += 4;
+    crc = cpu_to_be32(crc32(~0, buf, size));
+    crc_ptr = (uint8_t *) &crc;
+
+    /* Huge frames are truncted.  */
+    if (size > FEC_MAX_FRAME_SIZE) {
+        size = FEC_MAX_FRAME_SIZE;
+        flags |= FEC_BD_TR | FEC_BD_LG;
+    }
+
+    /* Frames larger than the user limit just set error flags.  */
+    if (size > (s->rcr >> 16)) {
+        flags |= FEC_BD_LG;
+    }
+
+    addr = s->rx_descriptor;
+    while (size > 0) {
+        imx_fec_read_bd(&bd, addr);
+        if ((bd.flags & FEC_BD_E) == 0) {
+            /* No descriptors available.  Bail out.  */
+            /*
+             * FIXME: This is wrong. We should probably either
+             * save the remainder for when more RX buffers are
+             * available, or flag an error.
+             */
+            qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Lost end of frame\n",
+                          TYPE_IMX_FEC, __func__);
+            break;
+        }
+        buf_len = (size <= s->emrbr) ? size : s->emrbr;
+        bd.length = buf_len;
+        size -= buf_len;
+        FEC_PRINTF("rx_bd %x length %d\n", addr, bd.length);
+        /* The last 4 bytes are the CRC.  */
+        if (size < 4) {
+            buf_len += size - 4;
+        }
+        buf_addr = bd.data;
+        dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
+        buf += buf_len;
+        if (size < 4) {
+            dma_memory_write(&address_space_memory, buf_addr + buf_len,
+                             crc_ptr, 4 - size);
+            crc_ptr += 4 - size;
+        }
+        bd.flags &= ~FEC_BD_E;
+        if (size == 0) {
+            /* Last buffer in frame.  */
+            bd.flags |= flags | FEC_BD_L;
+            FEC_PRINTF("rx frame flags %04x\n", bd.flags);
+            s->eir |= FEC_INT_RXF;
+        } else {
+            s->eir |= FEC_INT_RXB;
+        }
+        imx_fec_write_bd(&bd, addr);
+        /* Advance to the next descriptor.  */
+        if ((bd.flags & FEC_BD_W) != 0) {
+            addr = s->erdsr;
+        } else {
+            addr += 8;
+        }
+    }
+    s->rx_descriptor = addr;
+    imx_fec_enable_rx(s);
+    imx_fec_update(s);
+    return len;
+}
+
+static const MemoryRegionOps imx_fec_ops = {
+    .read = imx_fec_read,
+    .write = imx_fec_write,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 4,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void imx_fec_cleanup(NetClientState *nc)
+{
+    IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
+
+    s->nic = NULL;
+}
+
+static NetClientInfo net_imx_fec_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = imx_fec_can_receive,
+    .receive = imx_fec_receive,
+    .cleanup = imx_fec_cleanup,
+    .link_status_changed = imx_fec_set_link,
+};
+
+
+static void imx_fec_realize(DeviceState *dev, Error **errp)
+{
+    IMXFECState *s = IMX_FEC(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+    memory_region_init_io(&s->iomem, OBJECT(dev), &imx_fec_ops, s,
+                          TYPE_IMX_FEC, 0x400);
+    sysbus_init_mmio(sbd, &s->iomem);
+    sysbus_init_irq(sbd, &s->irq);
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+
+    s->conf.peers.ncs[0] = nd_table[0].netdev;
+
+    s->nic = qemu_new_nic(&net_imx_fec_info, &s->conf,
+                          object_get_typename(OBJECT(dev)), DEVICE(dev)->id,
+                          s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+}
+
+static Property imx_fec_properties[] = {
+    DEFINE_NIC_PROPERTIES(IMXFECState, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void imx_fec_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd = &vmstate_imx_fec;
+    dc->reset = imx_fec_reset;
+    dc->props = imx_fec_properties;
+    dc->realize = imx_fec_realize;
+}
+
+static const TypeInfo imx_fec_info = {
+    .name = TYPE_IMX_FEC,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IMXFECState),
+    .class_init = imx_fec_class_init,
+};
+
+static void imx_fec_register_types(void)
+{
+    type_register_static(&imx_fec_info);
+}
+
+DeviceState *imx_fec_create(int nic, const hwaddr base, qemu_irq irq)
+{
+    NICInfo *nd;
+    DeviceState *dev;
+    SysBusDevice *sbd;
+
+    if (nic >= MAX_NICS) {
+        hw_error("Cannot assign nic %d: QEMU supports only %d ports\n",
+                 nic, MAX_NICS);
+    }
+
+    nd = &nd_table[nic];
+
+    qemu_check_nic_model(nd, TYPE_IMX_FEC);
+    dev = qdev_create(NULL, TYPE_IMX_FEC);
+    qdev_set_nic_properties(dev, nd);
+    qdev_init_nofail(dev);
+    sbd = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(sbd, 0, base);
+    sysbus_connect_irq(sbd, 0, irq);
+
+    return dev;
+};
+
+type_init(imx_fec_register_types)
diff --git a/include/hw/arm/imx.h b/include/hw/arm/imx.h
index ea9e093..558ba60 100644
--- a/include/hw/arm/imx.h
+++ b/include/hw/arm/imx.h
@@ -30,5 +30,6 @@ void imx_timerg_create(const hwaddr addr,
                       qemu_irq irq,
                       DeviceState *ccm);
 
+DeviceState *imx_fec_create(int nic, const hwaddr base, qemu_irq irq);
 
 #endif /* IMX_H */
-- 
2.1.4

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

* [Qemu-devel] [PATCH v7 2/4] i.MX: Add I2C contoller emulator
  2015-06-22 19:06 [Qemu-devel] [PATCH v7 0/4] i.MX: Add i.MX25 support through the 3DS evaluation board Jean-Christophe Dubois
  2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 1/4] i.MX: Add FEC Ethernet Emulator Jean-Christophe Dubois
@ 2015-06-22 19:06 ` Jean-Christophe Dubois
  2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 3/4] i.MX: Add i.MX25 3DS evaluation board support Jean-Christophe Dubois
  2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 4/4] i.MX: Add qtest support for I2C device emulator Jean-Christophe Dubois
  3 siblings, 0 replies; 7+ messages in thread
From: Jean-Christophe Dubois @ 2015-06-22 19:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jean-Christophe Dubois

The slave mode is not implemented.

Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>
---

Changes since v1: 
    * use QOM cast
    * run checkpatch on code
    * added restrictin on MemoryRegionOps
    * use DeviceClass::realise as init function

Changes since v2:
    * use CamelCase for state type   
    * use extrac32() for bit manipilation.
    * improve QOM cast           
    * separate regs definition in its own file (to be reused by qtest)
 
Changes since v3:
    * More QOM cast.
    * Rework GPL headers
    * Add a constructor helper.
    * fix reset()
    * rework debug printf

Changes since v4:
    * remove the constructor helper

Changes since v5:
    * replace hw_error() with qemu_log_mask(LOG_GUEST_ERROR, ...)
    * add qemu_log_mask(LOG_UNIMP, ...) for slave mode.
    * small comment fixes.

Changes since v6:
    * port to new memory API

 default-configs/arm-softmmu.mak |   2 +
 hw/i2c/Makefile.objs            |   1 +
 hw/i2c/imx_i2c.c                | 361 ++++++++++++++++++++++++++++++++++++++++
 hw/i2c/imx_i2c_regs.h           |  63 +++++++
 4 files changed, 427 insertions(+)
 create mode 100644 hw/i2c/imx_i2c.c
 create mode 100644 hw/i2c/imx_i2c_regs.h

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index d21ff7b..c6f509d 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -99,6 +99,8 @@ CONFIG_ALLWINNER_A10_PIT=y
 CONFIG_ALLWINNER_A10_PIC=y
 CONFIG_ALLWINNER_A10=y
 
+CONFIG_IMX_I2C=y
+
 CONFIG_XIO3130=y
 CONFIG_IOH3420=y
 CONFIG_I82801B11=y
diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
index 0f13060..aeb8f38 100644
--- a/hw/i2c/Makefile.objs
+++ b/hw/i2c/Makefile.objs
@@ -4,4 +4,5 @@ common-obj-$(CONFIG_ACPI_X86) += smbus_ich9.o
 common-obj-$(CONFIG_APM) += pm_smbus.o
 common-obj-$(CONFIG_BITBANG_I2C) += bitbang_i2c.o
 common-obj-$(CONFIG_EXYNOS4) += exynos4210_i2c.o
+common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o
 obj-$(CONFIG_OMAP) += omap_i2c.o
diff --git a/hw/i2c/imx_i2c.c b/hw/i2c/imx_i2c.c
new file mode 100644
index 0000000..41ac4fd
--- /dev/null
+++ b/hw/i2c/imx_i2c.c
@@ -0,0 +1,361 @@
+/*
+ *  i.MX I2C Bus Serial Interface Emulation
+ *
+ *  Copyright (C) 2013 Jean-Christophe Dubois.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "hw/sysbus.h"
+#include "hw/i2c/i2c.h"
+#include "hw/i2c/imx_i2c_regs.h"
+
+#ifndef IMX_I2C_DEBUG
+#define IMX_I2C_DEBUG                 0
+#endif
+
+#define TYPE_IMX_I2C                  "imx.i2c"
+#define IMX_I2C(obj)                  \
+    OBJECT_CHECK(IMXI2CState, (obj), TYPE_IMX_I2C)
+
+#if IMX_I2C_DEBUG
+#define DPRINT(fmt, args...)              \
+    do { fprintf(stderr, "%s: "fmt, __func__, ## args); } while (0)
+
+static const char *imx_i2c_get_regname(unsigned offset)
+{
+    switch (offset) {
+    case IADR_ADDR:
+        return "IADR";
+    case IFDR_ADDR:
+        return "IFDR";
+    case I2CR_ADDR:
+        return "I2CR";
+    case I2SR_ADDR:
+        return "I2SR";
+    case I2DR_ADDR:
+        return "I2DR";
+    default:
+        return "[?]";
+    }
+}
+#else
+#define DPRINT(fmt, args...)              do { } while (0)
+#endif
+
+typedef struct IMXI2CState {
+    SysBusDevice parent_obj;
+
+    MemoryRegion iomem;
+    I2CBus *bus;
+    qemu_irq irq;
+
+    uint16_t  address;
+
+    uint16_t iadr;
+    uint16_t ifdr;
+    uint16_t i2cr;
+    uint16_t i2sr;
+    uint16_t i2dr_read;
+    uint16_t i2dr_write;
+} IMXI2CState;
+
+static inline bool imx_i2c_is_enabled(IMXI2CState *s)
+{
+    return s->i2cr & I2CR_IEN;
+}
+
+static inline bool imx_i2c_interrupt_is_enabled(IMXI2CState *s)
+{
+    return s->i2cr & I2CR_IIEN;
+}
+
+static inline bool imx_i2c_is_master(IMXI2CState *s)
+{
+    return s->i2cr & I2CR_MSTA;
+}
+
+static inline bool imx_i2c_direction_is_tx(IMXI2CState *s)
+{
+    return s->i2cr & I2CR_MTX;
+}
+
+static void imx_i2c_reset(DeviceState *dev)
+{
+    IMXI2CState *s = IMX_I2C(dev);
+
+    if (s->address != ADDR_RESET) {
+        i2c_end_transfer(s->bus);
+    }
+
+    s->address    = ADDR_RESET;
+    s->iadr       = IADR_RESET;
+    s->ifdr       = IFDR_RESET;
+    s->i2cr       = I2CR_RESET;
+    s->i2sr       = I2SR_RESET;
+    s->i2dr_read  = I2DR_RESET;
+    s->i2dr_write = I2DR_RESET;
+}
+
+static inline void imx_i2c_raise_interrupt(IMXI2CState *s)
+{
+    /*
+     * raise an interrupt if the device is enabled and it is configured
+     * to generate some interrupts.
+     */
+    if (imx_i2c_is_enabled(s) && imx_i2c_interrupt_is_enabled(s)) {
+        s->i2sr |= I2SR_IIF;
+        qemu_irq_raise(s->irq);
+    }
+}
+
+static uint64_t imx_i2c_read(void *opaque, hwaddr offset,
+                             unsigned size)
+{
+    uint16_t value;
+    IMXI2CState *s = IMX_I2C(opaque);
+
+    switch (offset) {
+    case IADR_ADDR:
+        value = s->iadr;
+        break;
+    case IFDR_ADDR:
+        value = s->ifdr;
+        break;
+    case I2CR_ADDR:
+        value = s->i2cr;
+        break;
+    case I2SR_ADDR:
+        value = s->i2sr;
+        break;
+    case I2DR_ADDR:
+        value = s->i2dr_read;
+
+        if (imx_i2c_is_master(s)) { /* master mode */
+            int ret = 0xff;
+
+            if (s->address == ADDR_RESET) {
+                /* something is wrong as the address is not set */
+                qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Trying to read "
+                              "without specifying the slave address\n",
+                              TYPE_IMX_I2C, __func__);
+            } else if (s->i2cr & I2CR_MTX) {
+                qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Trying to read "
+                              "but MTX is set\n", TYPE_IMX_I2C, __func__);
+            } else {
+                /* get the next byte */
+                ret = i2c_recv(s->bus);
+
+                if (ret >= 0) {
+                    imx_i2c_raise_interrupt(s);
+                } else {
+                    qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: read failed "
+                                  "for device 0x%02x\n", TYPE_IMX_I2C,
+                                  __func__, s->address);
+                    ret = 0xff;
+                }
+            }
+
+            s->i2dr_read = ret;
+        } else {
+            qemu_log_mask(LOG_UNIMP, "%s[%s]: slave mode not implemented\n",
+                          TYPE_IMX_I2C, __func__);
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
+                      TYPE_IMX_I2C, __func__, s->address);
+        value = 0;
+        break;
+    }
+
+    DPRINT("read %s [0x%02x] -> 0x%02x\n", imx_i2c_get_regname(offset),
+           (unsigned int)offset, value);
+
+    return (uint64_t)value;
+}
+
+static void imx_i2c_write(void *opaque, hwaddr offset,
+                          uint64_t value, unsigned size)
+{
+    IMXI2CState *s = IMX_I2C(opaque);
+
+    DPRINT("write %s [0x%02x] <- 0x%02x\n", imx_i2c_get_regname(offset),
+           (unsigned int)offset, (int)value);
+
+    value &= 0xff;
+
+    switch (offset) {
+    case IADR_ADDR:
+        s->iadr = value & IADR_MASK;
+        /* i2c_set_slave_address(s->bus, (uint8_t)s->iadr); */
+        break;
+    case IFDR_ADDR:
+        s->ifdr = value & IFDR_MASK;
+        break;
+    case I2CR_ADDR:
+        if (imx_i2c_is_enabled(s) && ((value & I2CR_IEN) == 0)) {
+            /* This is a soft reset. IADR is preserved during soft resets */
+            uint16_t iadr = s->iadr;
+            imx_i2c_reset(DEVICE(s));
+            s->iadr = iadr;
+        } else { /* normal write */
+            s->i2cr = value & I2CR_MASK;
+
+            if (imx_i2c_is_master(s)) { /* master mode */
+                /* set the bus to busy */
+                s->i2sr |= I2SR_IBB;
+            } else { /* slave mode */
+                /* bus is not busy anymore */
+                s->i2sr &= ~I2SR_IBB;
+
+                /*
+                 * if we unset the master mode then it ends the ongoing
+                 * transfer if any
+                 */
+                if (s->address != ADDR_RESET) {
+                    i2c_end_transfer(s->bus);
+                    s->address = ADDR_RESET;
+                }
+            }
+
+            if (s->i2cr & I2CR_RSTA) { /* Restart */
+                /* if this is a restart then it ends the ongoing transfer */
+                if (s->address != ADDR_RESET) {
+                    i2c_end_transfer(s->bus);
+                    s->address = ADDR_RESET;
+                    s->i2cr &= ~I2CR_RSTA;
+                }
+            }
+        }
+        break;
+    case I2SR_ADDR:
+        /*
+         * if the user writes 0 to IIF then lower the interrupt and
+         * reset the bit
+         */
+        if ((s->i2sr & I2SR_IIF) && !(value & I2SR_IIF)) {
+            s->i2sr &= ~I2SR_IIF;
+            qemu_irq_lower(s->irq);
+        }
+
+        /*
+         * if the user writes 0 to IAL, reset the bit
+         */
+        if ((s->i2sr & I2SR_IAL) && !(value & I2SR_IAL)) {
+            s->i2sr &= ~I2SR_IAL;
+        }
+
+        break;
+    case I2DR_ADDR:
+        /* if the device is not enabled, nothing to do */
+        if (!imx_i2c_is_enabled(s)) {
+            break;
+        }
+
+        s->i2dr_write = value & I2DR_MASK;
+
+        if (imx_i2c_is_master(s)) { /* master mode */
+            /* If this is the first write cycle then it is the slave addr */
+            if (s->address == ADDR_RESET) {
+                if (i2c_start_transfer(s->bus, extract32(s->i2dr_write, 1, 7),
+                                       extract32(s->i2dr_write, 0, 1))) {
+                    /* if non zero is returned, the adress is not valid */
+                    s->i2sr |= I2SR_RXAK;
+                } else {
+                    s->address = s->i2dr_write;
+                    s->i2sr &= ~I2SR_RXAK;
+                    imx_i2c_raise_interrupt(s);
+                }
+            } else { /* This is a normal data write */
+                if (i2c_send(s->bus, s->i2dr_write)) {
+                    /* if the target return non zero then end the transfer */
+                    s->i2sr |= I2SR_RXAK;
+                    s->address = ADDR_RESET;
+                    i2c_end_transfer(s->bus);
+                } else {
+                    s->i2sr &= ~I2SR_RXAK;
+                    imx_i2c_raise_interrupt(s);
+                }
+            }
+        } else {
+            qemu_log_mask(LOG_UNIMP, "%s[%s]: slave mode not implemented\n",
+                          TYPE_IMX_I2C, __func__);
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
+                      TYPE_IMX_I2C, __func__, s->address);
+        break;
+    }
+}
+
+static const MemoryRegionOps imx_i2c_ops = {
+    .read = imx_i2c_read,
+    .write = imx_i2c_write,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 2,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription imx_i2c_vmstate = {
+    .name = TYPE_IMX_I2C,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT16(address, IMXI2CState),
+        VMSTATE_UINT16(iadr, IMXI2CState),
+        VMSTATE_UINT16(ifdr, IMXI2CState),
+        VMSTATE_UINT16(i2cr, IMXI2CState),
+        VMSTATE_UINT16(i2sr, IMXI2CState),
+        VMSTATE_UINT16(i2dr_read, IMXI2CState),
+        VMSTATE_UINT16(i2dr_write, IMXI2CState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void imx_i2c_realize(DeviceState *dev, Error **errp)
+{
+    IMXI2CState *s = IMX_I2C(dev);
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &imx_i2c_ops, s, TYPE_IMX_I2C,
+                          IMX_I2C_MEM_SIZE);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
+    s->bus = i2c_init_bus(DEVICE(dev), "i2c");
+}
+
+static void imx_i2c_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd = &imx_i2c_vmstate;
+    dc->reset = imx_i2c_reset;
+    dc->realize = imx_i2c_realize;
+}
+
+static const TypeInfo imx_i2c_type_info = {
+    .name = TYPE_IMX_I2C,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IMXI2CState),
+    .class_init = imx_i2c_class_init,
+};
+
+static void imx_i2c_register_types(void)
+{
+    type_register_static(&imx_i2c_type_info);
+}
+
+type_init(imx_i2c_register_types)
diff --git a/hw/i2c/imx_i2c_regs.h b/hw/i2c/imx_i2c_regs.h
new file mode 100644
index 0000000..95c7cf5
--- /dev/null
+++ b/hw/i2c/imx_i2c_regs.h
@@ -0,0 +1,63 @@
+/*
+ *  i.MX I2C Bus Serial Interface registers definition
+ *
+ *  Copyright (C) 2013 Jean-Christophe Dubois.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __IMX_I2C_REGS_H_
+#define __IMX_I2C_REGS_H_
+
+#define IMX_I2C_MEM_SIZE           0x14
+
+/* i.MX I2C memory map */
+#define IADR_ADDR                  0x00  /* address register */
+#define IFDR_ADDR                  0x04  /* frequency divider register */
+#define I2CR_ADDR                  0x08  /* control register */
+#define I2SR_ADDR                  0x0c  /* status register */
+#define I2DR_ADDR                  0x10  /* data register */
+
+#define IADR_MASK                  0xFE
+#define IADR_RESET                 0
+
+#define IFDR_MASK                  0x3F
+#define IFDR_RESET                 0
+
+#define I2CR_IEN                   (1 << 7)
+#define I2CR_IIEN                  (1 << 6)
+#define I2CR_MSTA                  (1 << 5)
+#define I2CR_MTX                   (1 << 4)
+#define I2CR_TXAK                  (1 << 3)
+#define I2CR_RSTA                  (1 << 2)
+#define I2CR_MASK                  0xFC
+#define I2CR_RESET                 0
+
+#define I2SR_ICF                   (1 << 7)
+#define I2SR_IAAF                  (1 << 6)
+#define I2SR_IBB                   (1 << 5)
+#define I2SR_IAL                   (1 << 4)
+#define I2SR_SRW                   (1 << 2)
+#define I2SR_IIF                   (1 << 1)
+#define I2SR_RXAK                  (1 << 0)
+#define I2SR_MASK                  0xE9
+#define I2SR_RESET                 0x81
+
+#define I2DR_MASK                  0xFF
+#define I2DR_RESET                 0
+
+#define ADDR_RESET                 0xFF00
+
+#endif /* __IMX_I2C_REGS_H_ */
-- 
2.1.4

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

* [Qemu-devel] [PATCH v7 3/4] i.MX: Add i.MX25 3DS evaluation board support
  2015-06-22 19:06 [Qemu-devel] [PATCH v7 0/4] i.MX: Add i.MX25 support through the 3DS evaluation board Jean-Christophe Dubois
  2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 1/4] i.MX: Add FEC Ethernet Emulator Jean-Christophe Dubois
  2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 2/4] i.MX: Add I2C contoller emulator Jean-Christophe Dubois
@ 2015-06-22 19:06 ` Jean-Christophe Dubois
  2015-06-24  5:07   ` Peter Crosthwaite
  2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 4/4] i.MX: Add qtest support for I2C device emulator Jean-Christophe Dubois
  3 siblings, 1 reply; 7+ messages in thread
From: Jean-Christophe Dubois @ 2015-06-22 19:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jean-Christophe Dubois

For now we support:
    * timers (GPT and EPIT)
    * serial ports
    * ethernet (through the newly added FEC emulator)
    * I2C (through the newly added I2C emulator)

Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
---

Changes since v1:
    * Added a ds1338 I2C device for qtest purpose.

Changes since v2:
    * none
 
Changes since v3:
    * Rework GPL header          
    * use I2C constructor helper.

Changes since v4:
    * use sysbus_create_simple() instead of I2C constructor helper

Changes since v5:
    * Add ds1338 only for qtest mode.
    * small comment fixes.

Changes since v6:
    * Allow for more than 4 serial if suppoted by Qemu.

 hw/arm/Makefile.objs |   1 +
 hw/arm/imx25_3ds.c   | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 274 insertions(+)
 create mode 100644 hw/arm/imx25_3ds.c

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index cf346c1..3ecb8b1 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -5,6 +5,7 @@ obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
 obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
 obj-$(CONFIG_ACPI) += virt-acpi-build.o
 obj-y += netduino2.o
+obj-y += imx25_3ds.o
 obj-y += sysbus-fdt.o
 
 obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
diff --git a/hw/arm/imx25_3ds.c b/hw/arm/imx25_3ds.c
new file mode 100644
index 0000000..f495f9a
--- /dev/null
+++ b/hw/arm/imx25_3ds.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2013 Jean-Christophe Dubois
+ *
+ * 3Dstack Board System emulation.
+ *
+ * Based on hw/arm/kzm.c
+ *
+ * Copyright (c) 2008 OKL and 2011 NICTA
+ * Written by Hans at OK-Labs
+ * Updated by Peter Chubb.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/sysbus.h"
+#include "exec/address-spaces.h"
+#include "hw/hw.h"
+#include "hw/arm/arm.h"
+#include "hw/devices.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/char/serial.h"
+#include "hw/arm/imx.h"
+#include "hw/i2c/i2c.h"
+
+#include "sysemu/qtest.h"
+
+/* Memory map for 3D-Stack Emulation Baseboard:
+ * 0x00000000-0x00003fff 16k ROM              IGNORED
+ * 0x00004000-0x00403fff Reserved             IGNORED
+ * 0x00404000-0x00408fff 20k ROM              IGNORED
+ * 0x00409000-0x0fffffff Reserved             IGNORED
+ * 0x10000000-0x1fffffff Reserved             IGNORED
+ * 0x20000000-0x2fffffff Reserved             IGNORED
+ * 0x30000000-0x3fffffff Reserved             IGNORED
+ * 0x40000000-0x43efffff Reserved             IGNORED
+ * 0x43f00000-0x6fffffff I.MX25 Internal Register Space
+ *   0x43f00000 IO_AREA0
+ *   0x43f80000 I2C0                          EMULATED
+ *   0x43f84000 I2C2                          EMULATED
+ *   0x43f98000 I2C1                          EMULATED
+ *   0x43f90000 UART1                         EMULATED
+ *   0x43f94000 UART2                         EMULATED
+ *   0x43fb0000 UART4                         IGNORED
+ *   0x43fb4000 UART5                         IGNORED
+ *   0x5000c000 UART3                         EMULATED
+ *   0x50038000 FEC                           EMULATED
+ *   0x53f80000 CCM                           EMULATED
+ *   0x53f84000 GPT 4                         EMULATED
+ *   0x53f88000 GPT 3                         EMULATED
+ *   0x53f8c000 GPT 2                         EMULATED
+ *   0x53f90000 GPT 1                         EMULATED
+ *   0x53f94000 PIT 1                         EMULATED
+ *   0x53f98000 PIT 2                         EMULATED
+ *   0x53f9c000 GPIO-4                        EMULATED
+ *   0x53fa4000 GPIO-3                        EMULATED
+ *   0x53fcc000 GPIO-1                        EMULATED
+ *   0x53fd0000 GPIO-2                        EMULATED
+ *   0x68000000 ASIC                          EMULATED
+ * 0x78000000-0x7801ffff SRAM                 EMULATED
+ * 0x78020000-0x7fffffff SRAM Aliasing        EMULATED
+ * 0x80000000-0x87ffffff RAM + Alias          EMULATED
+ * 0x90000000-0x9fffffff RAM + Alias          EMULATED
+ * 0xa0000000-0xa7ffffff Flash                IGNORED
+ * 0xa8000000-0xafffffff Flash                IGNORED
+ * 0xb0000000-0xb1ffffff SRAM                 IGNORED
+ * 0xb2000000-0xb3ffffff SRAM                 IGNORED
+ * 0xb4000000-0xb5ffffff CS4                  IGNORED
+ * 0xb6000000-0xb8000fff Reserved             IGNORED
+ * 0xb8001000-0xb8001fff SDRAM CTRL reg       IGNORED
+ * 0xb8002000-0xb8002fff WEIM CTRL reg        IGNORED
+ * 0xb8003000-0xb8003fff M3IF CTRL reg        IGNORED
+ * 0xb8004000-0xb8004fff EMI CTRL reg         IGNORED
+ * 0xb8005000-0xbaffffff Reserved             IGNORED
+ * 0xbb000000-0xbb000fff NAND flash area buf  IGNORED
+ * 0xbb001000-0xbb0011ff NAND flash reserved  IGNORED
+ * 0xbb001200-0xbb001dff Reserved             IGNORED
+ * 0xbb001e00-0xbb001fff NAN flash CTRL reg   IGNORED
+ * 0xbb012000-0xbfffffff Reserved             IGNORED
+ * 0xc0000000-0xffffffff Reserved             IGNORED
+ */
+
+#define IMX25_SRAM_ADDRESS  (0x78000000)
+#define IMX25_SRAMSIZE      (128*1024)
+#define IMX25_CS_SRAMSIZE   (128*1024*1024)
+#define IMX25_3DS_ADDRESS   (0x80000000)
+#define IMX25_CS_RAMSIZE    (256*1024*1024)
+
+static struct arm_boot_info imx25_3ds_binfo = {
+    .loader_start = IMX25_3DS_ADDRESS,
+    .board_id = 1771,
+};
+
+static void imx25_3ds_init(MachineState *args)
+{
+    int i;
+    int serial_cnt = 0;
+    const ram_addr_t ram_size = args->ram_size;
+    const char *cpu_model = args->cpu_model;
+    const char *kernel_filename = args->kernel_filename;
+    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *initrd_filename = args->initrd_filename;
+    ARMCPU *cpu;
+    DeviceState *pic_dev;
+    DeviceState *ccm, *i2c_dev;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
+    MemoryRegion *sram_alias = g_new(MemoryRegion, 1);
+    static const struct {
+        hwaddr addr;
+        unsigned int irq;
+    } serial_table[] = {
+        { 0x43f90000, 45 },
+        { 0x43f94000, 32 },
+        { 0x5000c000, 18 },
+        { 0x50008000, 5  },
+        { 0x5002c000, 40 },
+        { 0, 0 }
+    };
+
+    if (!cpu_model) {
+        cpu_model = "arm926";
+    }
+
+    cpu = cpu_arm_init(cpu_model);
+    if (!cpu) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+
+    if (ram_size > (2 * IMX25_CS_RAMSIZE)) {
+        fprintf(stderr, "i.MX25 can support only up to %d MB\n",
+                2 * IMX25_CS_RAMSIZE / (1024 * 1024));
+        exit(1);
+    }
+
+    /* create our main memory */
+    for (i = 0; i <= (ram_size / IMX25_CS_RAMSIZE); i++) {
+        ram_addr_t blk_size = ram_size - (IMX25_CS_RAMSIZE * i);
+        MemoryRegion *ram;
+        char ram_name[20];
+
+        if (blk_size > IMX25_CS_RAMSIZE) {
+            blk_size = IMX25_CS_RAMSIZE;
+        }
+
+        if (blk_size == 0) {
+            break;
+        }
+
+        sprintf(ram_name, "imx25.ram%d", i);
+
+        ram = g_new(MemoryRegion, 1);
+        memory_region_init_ram(ram, NULL, ram_name, blk_size, &error_abort);
+        vmstate_register_ram_global(ram);
+        memory_region_add_subregion(address_space_mem, IMX25_3DS_ADDRESS
+                                    + (IMX25_CS_RAMSIZE * i), ram);
+
+        /* Add ram alias */
+        if (blk_size < IMX25_CS_RAMSIZE) {
+            MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
+            char alias_name[20];
+
+            sprintf(alias_name, "ram.alias%d", i);
+
+            memory_region_init_alias(ram_alias, NULL, alias_name, ram, 0,
+                                     IMX25_CS_RAMSIZE - blk_size);
+            memory_region_add_subregion(address_space_mem, IMX25_3DS_ADDRESS
+                                        + (IMX25_CS_RAMSIZE * i) + blk_size,
+                                        ram_alias);
+        }
+    }
+
+    /* create the sram area */
+    memory_region_init_ram(sram, NULL, "imx25.sram", IMX25_SRAMSIZE, &error_abort);
+    vmstate_register_ram_global(sram);
+    memory_region_add_subregion(address_space_mem, IMX25_SRAM_ADDRESS,
+                                sram);
+
+    /* add sram alias */
+    memory_region_init_alias(sram_alias, NULL, "sram.alias", sram, 0,
+                             IMX25_CS_SRAMSIZE - IMX25_SRAMSIZE);
+    memory_region_add_subregion(address_space_mem,
+                                IMX25_SRAM_ADDRESS + IMX25_SRAMSIZE,
+                                sram_alias);
+
+    /* add the PIC */
+    pic_dev = sysbus_create_varargs("imx_avic", 0x68000000,
+                                    qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
+                                    qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
+                                    NULL);
+
+    while (serial_table[serial_cnt].addr && (serial_cnt < MAX_SERIAL_PORTS)) {
+        /* add some serial lines */
+        imx_serial_create(serial_cnt, serial_table[serial_cnt].addr,
+                          qdev_get_gpio_in(pic_dev,
+                                           serial_table[serial_cnt].irq));
+        serial_cnt++;
+    }
+
+    ccm = sysbus_create_simple("imx_ccm", 0x53f80000, NULL);
+
+    /* add gpt timers */
+    imx_timerg_create(0x53f84000, qdev_get_gpio_in(pic_dev, 1), ccm);
+    imx_timerg_create(0x53f88000, qdev_get_gpio_in(pic_dev, 29), ccm);
+    imx_timerg_create(0x53f8c000, qdev_get_gpio_in(pic_dev, 53), ccm);
+    imx_timerg_create(0x53f90000, qdev_get_gpio_in(pic_dev, 54), ccm);
+
+    /* add epit timers */
+    imx_timerp_create(0x53f94000, qdev_get_gpio_in(pic_dev, 28), ccm);
+    imx_timerp_create(0x53f98000, qdev_get_gpio_in(pic_dev, 27), ccm);
+
+    imx_fec_create(0, 0x50038000, qdev_get_gpio_in(pic_dev, 57));
+
+    /* I2C 0 */
+    i2c_dev = sysbus_create_simple("imx.i2c", 0x43f80000,
+                                   qdev_get_gpio_in(pic_dev, 3));
+
+    /* add I2C 1 */
+    sysbus_create_simple("imx.i2c", 0x43f98000, qdev_get_gpio_in(pic_dev, 4));
+    /* add I2C 2 */
+    sysbus_create_simple("imx.i2c", 0x43f84000, qdev_get_gpio_in(pic_dev, 10));
+
+    imx25_3ds_binfo.ram_size = ram_size;
+    imx25_3ds_binfo.kernel_filename = kernel_filename;
+    imx25_3ds_binfo.kernel_cmdline = kernel_cmdline;
+    imx25_3ds_binfo.initrd_filename = initrd_filename;
+    imx25_3ds_binfo.nb_cpus = 1;
+
+    /*
+     * We test explicitly for qtest here as it is not done (yet?) in
+     * arm_load_kernel(). Without this the "make check" command would
+     * fail.
+     */
+
+    if (!qtest_enabled()) {
+        arm_load_kernel(cpu, &imx25_3ds_binfo);
+    } else {
+        /*
+         * This I2C device doesn't exist on the real board.
+         * We add it here (only on qtest usage) to be able to do a bit
+         * of simple qtest. See "make check" for details.
+         */
+        i2c_create_slave((I2CBus *)qdev_get_child_bus(i2c_dev, "i2c"),
+                         "ds1338", 0x68);
+
+    }
+}
+
+static QEMUMachine imx25_3ds_machine = {
+    .name = "imx25_3ds",
+    .desc = "ARM i.MX25 PDK board (ARM926)",
+    .init = imx25_3ds_init,
+};
+
+static void imx25_3ds_machine_init(void)
+{
+    qemu_register_machine(&imx25_3ds_machine);
+}
+
+machine_init(imx25_3ds_machine_init)
-- 
2.1.4

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

* [Qemu-devel] [PATCH v7 4/4] i.MX: Add qtest support for I2C device emulator
  2015-06-22 19:06 [Qemu-devel] [PATCH v7 0/4] i.MX: Add i.MX25 support through the 3DS evaluation board Jean-Christophe Dubois
                   ` (2 preceding siblings ...)
  2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 3/4] i.MX: Add i.MX25 3DS evaluation board support Jean-Christophe Dubois
@ 2015-06-22 19:06 ` Jean-Christophe Dubois
  3 siblings, 0 replies; 7+ messages in thread
From: Jean-Christophe Dubois @ 2015-06-22 19:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jean-Christophe Dubois

This is using a ds1338 RTC chip on the i2c bus. This RTC
chip is not present on the real board.

Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
---

Changes since v1:
    * not present on v1

Changes since v2:
    * use a common header file for I2C regs definition

Changes since v3:
    * rework GPL headers.

Changes since v4:
    * none

Changes since v5:
    * none

Changes since v6:
    * none

 tests/Makefile         |   3 +
 tests/ds1338-test.c    |  75 ++++++++++++++++++
 tests/libqos/i2c-imx.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/i2c.h     |   3 +
 4 files changed, 290 insertions(+)
 create mode 100644 tests/ds1338-test.c
 create mode 100644 tests/libqos/i2c-imx.c

diff --git a/tests/Makefile b/tests/Makefile
index c5e4744..93890a8 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -193,6 +193,7 @@ check-qtest-sparc64-y = tests/endianness-test$(EXESUF)
 gcov-files-sparc-y += hw/timer/m48t59.c
 gcov-files-sparc64-y += hw/timer/m48t59.c
 check-qtest-arm-y = tests/tmp105-test$(EXESUF)
+check-qtest-arm-y = tests/ds1338-test$(EXESUF)
 gcov-files-arm-y += hw/misc/tmp105.c
 check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
 gcov-files-arm-y += arm-softmmu/hw/block/virtio-blk.c
@@ -342,6 +343,7 @@ libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
 libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
 libqos-pc-obj-y += tests/libqos/ahci.o
 libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o
+libqos-imx-obj-y = $(libqos-obj-y) tests/libqos/i2c-imx.o
 libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o
 libqos-virtio-obj-y = $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/libqos/malloc-generic.o
 
@@ -356,6 +358,7 @@ tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o
 tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y)
 tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o $(libqos-obj-y)
 tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
+tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
 tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
 tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
 tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y)
diff --git a/tests/ds1338-test.c b/tests/ds1338-test.c
new file mode 100644
index 0000000..fbc989b
--- /dev/null
+++ b/tests/ds1338-test.c
@@ -0,0 +1,75 @@
+/*
+ * QTest testcase for the DS1338 RTC
+ *
+ * Copyright (c) 2013 Jean-Christophe Dubois
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libqtest.h"
+#include "libqos/i2c.h"
+
+#include <glib.h>
+
+#define IMX25_I2C_0_BASE 0x43F80000
+
+#define DS1338_ADDR 0x68
+
+static I2CAdapter *i2c;
+static uint8_t addr;
+
+#define bcd2bin(x)        (((x) & 0x0f) + ((x) >> 4) * 10)
+
+static void send_and_receive(void)
+{
+    uint8_t cmd[1];
+    uint8_t resp[7];
+    time_t now = time(NULL);
+    struct tm *tm_ptr = gmtime(&now);
+
+    /* reset the index in the RTC memory */
+    cmd[0] = 0;
+    i2c_send(i2c, addr, cmd, 1);
+
+    /* retrieve the date */
+    i2c_recv(i2c, addr, resp, 7);
+
+    /* check retreived time againt local time */
+    g_assert_cmpuint(bcd2bin(resp[4]), == , tm_ptr->tm_mday);
+    g_assert_cmpuint(bcd2bin(resp[5]), == , 1 + tm_ptr->tm_mon);
+    g_assert_cmpuint(2000 + bcd2bin(resp[6]), == , 1900 + tm_ptr->tm_year);
+}
+
+int main(int argc, char **argv)
+{
+    QTestState *s = NULL;
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    s = qtest_start("-display none -machine imx25_3ds");
+    i2c = imx_i2c_create(IMX25_I2C_0_BASE);
+    addr = DS1338_ADDR;
+
+    qtest_add_func("/ds1338/tx-rx", send_and_receive);
+
+    ret = g_test_run();
+
+    if (s) {
+        qtest_quit(s);
+    }
+    g_free(i2c);
+
+    return ret;
+}
diff --git a/tests/libqos/i2c-imx.c b/tests/libqos/i2c-imx.c
new file mode 100644
index 0000000..2b18581
--- /dev/null
+++ b/tests/libqos/i2c-imx.c
@@ -0,0 +1,209 @@
+/*
+ * QTest i.MX I2C driver
+ *
+ * Copyright (c) 2013 Jean-Christophe Dubois
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libqos/i2c.h"
+
+#include <glib.h>
+#include <string.h>
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+#include "hw/i2c/imx_i2c_regs.h"
+
+enum IMXI2CDirection {
+    IMX_I2C_READ,
+    IMX_I2C_WRITE,
+};
+
+typedef struct IMXI2C {
+    I2CAdapter parent;
+
+    uint64_t addr;
+} IMXI2C;
+
+
+static void imx_i2c_set_slave_addr(IMXI2C *s, uint8_t addr,
+                                   enum IMXI2CDirection direction)
+{
+    writeb(s->addr + I2DR_ADDR, (addr << 1) |
+           (direction == IMX_I2C_READ ? 1 : 0));
+}
+
+static void imx_i2c_send(I2CAdapter *i2c, uint8_t addr,
+                         const uint8_t *buf, uint16_t len)
+{
+    IMXI2C *s = (IMXI2C *)i2c;
+    uint8_t data;
+    uint8_t status;
+    uint16_t size = 0;
+
+    if (!len) {
+        return;
+    }
+
+    /* set the bus for write */
+    data = I2CR_IEN |
+           I2CR_IIEN |
+           I2CR_MSTA |
+           I2CR_MTX |
+           I2CR_TXAK;
+
+    writeb(s->addr + I2CR_ADDR, data);
+    status = readb(s->addr + I2SR_ADDR);
+    g_assert((status & I2SR_IBB) != 0);
+
+    /* set the slave address */
+    imx_i2c_set_slave_addr(s, addr, IMX_I2C_WRITE);
+    status = readb(s->addr + I2SR_ADDR);
+    g_assert((status & I2SR_IIF) != 0);
+    g_assert((status & I2SR_RXAK) == 0);
+
+    /* ack the interrupt */
+    writeb(s->addr + I2SR_ADDR, 0);
+    status = readb(s->addr + I2SR_ADDR);
+    g_assert((status & I2SR_IIF) == 0);
+
+    while (size < len) {
+        /* check we are still busy */
+        status = readb(s->addr + I2SR_ADDR);
+        g_assert((status & I2SR_IBB) != 0);
+
+        /* write the data */
+        writeb(s->addr + I2DR_ADDR, buf[size]);
+        status = readb(s->addr + I2SR_ADDR);
+        g_assert((status & I2SR_IIF) != 0);
+        g_assert((status & I2SR_RXAK) == 0);
+
+        /* ack the interrupt */
+        writeb(s->addr + I2SR_ADDR, 0);
+        status = readb(s->addr + I2SR_ADDR);
+        g_assert((status & I2SR_IIF) == 0);
+
+        size++;
+    }
+
+    /* release the bus */
+    data &= ~(I2CR_MSTA | I2CR_MTX);
+    writeb(s->addr + I2CR_ADDR, data);
+    status = readb(s->addr + I2SR_ADDR);
+    g_assert((status & I2SR_IBB) == 0);
+}
+
+static void imx_i2c_recv(I2CAdapter *i2c, uint8_t addr,
+                         uint8_t *buf, uint16_t len)
+{
+    IMXI2C *s = (IMXI2C *)i2c;
+    uint8_t data;
+    uint8_t status;
+    uint16_t size = 0;
+
+    if (!len) {
+        return;
+    }
+
+    /* set the bus for write */
+    data = I2CR_IEN |
+           I2CR_IIEN |
+           I2CR_MSTA |
+           I2CR_MTX |
+           I2CR_TXAK;
+
+    writeb(s->addr + I2CR_ADDR, data);
+    status = readb(s->addr + I2SR_ADDR);
+    g_assert((status & I2SR_IBB) != 0);
+
+    /* set the slave address */
+    imx_i2c_set_slave_addr(s, addr, IMX_I2C_READ);
+    status = readb(s->addr + I2SR_ADDR);
+    g_assert((status & I2SR_IIF) != 0);
+    g_assert((status & I2SR_RXAK) == 0);
+
+    /* ack the interrupt */
+    writeb(s->addr + I2SR_ADDR, 0);
+    status = readb(s->addr + I2SR_ADDR);
+    g_assert((status & I2SR_IIF) == 0);
+
+    /* set the bus for read */
+    data &= ~I2CR_MTX;
+    /* if only one byte don't ack */
+    if (len != 1) {
+        data &= ~I2CR_TXAK;
+    }
+    writeb(s->addr + I2CR_ADDR, data);
+    status = readb(s->addr + I2SR_ADDR);
+    g_assert((status & I2SR_IBB) != 0);
+
+    /* dummy read */
+    readb(s->addr + I2DR_ADDR);
+    status = readb(s->addr + I2SR_ADDR);
+    g_assert((status & I2SR_IIF) != 0);
+
+    /* ack the interrupt */
+    writeb(s->addr + I2SR_ADDR, 0);
+    status = readb(s->addr + I2SR_ADDR);
+    g_assert((status & I2SR_IIF) == 0);
+
+    while (size < len) {
+        /* check we are still busy */
+        status = readb(s->addr + I2SR_ADDR);
+        g_assert((status & I2SR_IBB) != 0);
+
+        if (size == (len - 1)) {
+            /* stop the read transaction */
+            data &= ~(I2CR_MSTA | I2CR_MTX);
+        } else {
+            /* ack the data read */
+            data |= I2CR_TXAK;
+        }
+        writeb(s->addr + I2CR_ADDR, data);
+
+        /* read the data */
+        buf[size] = readb(s->addr + I2DR_ADDR);
+
+        if (size != (len - 1)) {
+            status = readb(s->addr + I2SR_ADDR);
+            g_assert((status & I2SR_IIF) != 0);
+
+            /* ack the interrupt */
+            writeb(s->addr + I2SR_ADDR, 0);
+        }
+
+        status = readb(s->addr + I2SR_ADDR);
+        g_assert((status & I2SR_IIF) == 0);
+
+        size++;
+    }
+
+    status = readb(s->addr + I2SR_ADDR);
+    g_assert((status & I2SR_IBB) == 0);
+}
+
+I2CAdapter *imx_i2c_create(uint64_t addr)
+{
+    IMXI2C *s = g_malloc0(sizeof(*s));
+    I2CAdapter *i2c = (I2CAdapter *)s;
+
+    s->addr = addr;
+
+    i2c->send = imx_i2c_send;
+    i2c->recv = imx_i2c_recv;
+
+    return i2c;
+}
diff --git a/tests/libqos/i2c.h b/tests/libqos/i2c.h
index 1ce9af4..c21f1dc 100644
--- a/tests/libqos/i2c.h
+++ b/tests/libqos/i2c.h
@@ -27,4 +27,7 @@ void i2c_recv(I2CAdapter *i2c, uint8_t addr,
 /* libi2c-omap.c */
 I2CAdapter *omap_i2c_create(uint64_t addr);
 
+/* libi2c-imx.c */
+I2CAdapter *imx_i2c_create(uint64_t addr);
+
 #endif
-- 
2.1.4

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

* Re: [Qemu-devel] [PATCH v7 3/4] i.MX: Add i.MX25 3DS evaluation board support
  2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 3/4] i.MX: Add i.MX25 3DS evaluation board support Jean-Christophe Dubois
@ 2015-06-24  5:07   ` Peter Crosthwaite
  2015-06-24  6:09     ` Jean-Christophe DUBOIS
  0 siblings, 1 reply; 7+ messages in thread
From: Peter Crosthwaite @ 2015-06-24  5:07 UTC (permalink / raw)
  To: Jean-Christophe Dubois, Peter Maydell, Andreas Färber
  Cc: qemu-devel@nongnu.org Developers

On Mon, Jun 22, 2015 at 12:06 PM, Jean-Christophe Dubois
<jcd@tribudubois.net> wrote:
> For now we support:
>     * timers (GPT and EPIT)
>     * serial ports
>     * ethernet (through the newly added FEC emulator)
>     * I2C (through the newly added I2C emulator)
>
> Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
> ---
>
> Changes since v1:
>     * Added a ds1338 I2C device for qtest purpose.
>
> Changes since v2:
>     * none
>
> Changes since v3:
>     * Rework GPL header
>     * use I2C constructor helper.
>
> Changes since v4:
>     * use sysbus_create_simple() instead of I2C constructor helper
>
> Changes since v5:
>     * Add ds1338 only for qtest mode.
>     * small comment fixes.
>
> Changes since v6:
>     * Allow for more than 4 serial if suppoted by Qemu.
>
>  hw/arm/Makefile.objs |   1 +
>  hw/arm/imx25_3ds.c   | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++

So the (new since v6) guideline with ARM SoCs is to split the SoC and
machine models. This would give you two files. A SoC file for imx25
and board for 3ds.

I'm not 100% on the "3ds" board following some googling but is it
really the PDK board? I found this:

http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=635baf6b40ebaef683abf87d677467cba71a0d50

and can find product info for PDK from there:

http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=IMX25PDK

To see modern examples of split SoC/board, see stm32f205_soc wiith
netduino2 or xlnx-zynqmp with xlnx-ep108 (all in hw/arm).

It seems the only board level feature you are implementing is this
ds1338 which is not or the real board. So I guess qtest-only code can
be left in the SoC model.

This would make your board level very similar to netduino2 (perhaps
even slightly simpler).

Regards,
Peter

>  2 files changed, 274 insertions(+)
>  create mode 100644 hw/arm/imx25_3ds.c
>
> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
> index cf346c1..3ecb8b1 100644
> --- a/hw/arm/Makefile.objs
> +++ b/hw/arm/Makefile.objs
> @@ -5,6 +5,7 @@ obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
>  obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
>  obj-$(CONFIG_ACPI) += virt-acpi-build.o
>  obj-y += netduino2.o
> +obj-y += imx25_3ds.o
>  obj-y += sysbus-fdt.o
>
>  obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
> diff --git a/hw/arm/imx25_3ds.c b/hw/arm/imx25_3ds.c
> new file mode 100644
> index 0000000..f495f9a
> --- /dev/null
> +++ b/hw/arm/imx25_3ds.c
> @@ -0,0 +1,273 @@
> +/*
> + * Copyright (c) 2013 Jean-Christophe Dubois
> + *
> + * 3Dstack Board System emulation.
> + *
> + * Based on hw/arm/kzm.c
> + *
> + * Copyright (c) 2008 OKL and 2011 NICTA
> + * Written by Hans at OK-Labs
> + * Updated by Peter Chubb.
> + *
> + *  This program is free software; you can redistribute it and/or modify it
> + *  under the terms of the GNU General Public License as published by the
> + *  Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful, but WITHOUT
> + *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> + *  for more details.
> + *
> + *  You should have received a copy of the GNU General Public License along
> + *  with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "hw/sysbus.h"
> +#include "exec/address-spaces.h"
> +#include "hw/hw.h"
> +#include "hw/arm/arm.h"
> +#include "hw/devices.h"
> +#include "net/net.h"
> +#include "sysemu/sysemu.h"
> +#include "hw/boards.h"
> +#include "hw/char/serial.h"
> +#include "hw/arm/imx.h"
> +#include "hw/i2c/i2c.h"
> +
> +#include "sysemu/qtest.h"
> +
> +/* Memory map for 3D-Stack Emulation Baseboard:
> + * 0x00000000-0x00003fff 16k ROM              IGNORED
> + * 0x00004000-0x00403fff Reserved             IGNORED
> + * 0x00404000-0x00408fff 20k ROM              IGNORED
> + * 0x00409000-0x0fffffff Reserved             IGNORED
> + * 0x10000000-0x1fffffff Reserved             IGNORED
> + * 0x20000000-0x2fffffff Reserved             IGNORED
> + * 0x30000000-0x3fffffff Reserved             IGNORED
> + * 0x40000000-0x43efffff Reserved             IGNORED
> + * 0x43f00000-0x6fffffff I.MX25 Internal Register Space
> + *   0x43f00000 IO_AREA0
> + *   0x43f80000 I2C0                          EMULATED
> + *   0x43f84000 I2C2                          EMULATED
> + *   0x43f98000 I2C1                          EMULATED
> + *   0x43f90000 UART1                         EMULATED
> + *   0x43f94000 UART2                         EMULATED
> + *   0x43fb0000 UART4                         IGNORED
> + *   0x43fb4000 UART5                         IGNORED
> + *   0x5000c000 UART3                         EMULATED
> + *   0x50038000 FEC                           EMULATED
> + *   0x53f80000 CCM                           EMULATED
> + *   0x53f84000 GPT 4                         EMULATED
> + *   0x53f88000 GPT 3                         EMULATED
> + *   0x53f8c000 GPT 2                         EMULATED
> + *   0x53f90000 GPT 1                         EMULATED
> + *   0x53f94000 PIT 1                         EMULATED
> + *   0x53f98000 PIT 2                         EMULATED
> + *   0x53f9c000 GPIO-4                        EMULATED
> + *   0x53fa4000 GPIO-3                        EMULATED
> + *   0x53fcc000 GPIO-1                        EMULATED
> + *   0x53fd0000 GPIO-2                        EMULATED
> + *   0x68000000 ASIC                          EMULATED
> + * 0x78000000-0x7801ffff SRAM                 EMULATED
> + * 0x78020000-0x7fffffff SRAM Aliasing        EMULATED
> + * 0x80000000-0x87ffffff RAM + Alias          EMULATED
> + * 0x90000000-0x9fffffff RAM + Alias          EMULATED
> + * 0xa0000000-0xa7ffffff Flash                IGNORED
> + * 0xa8000000-0xafffffff Flash                IGNORED
> + * 0xb0000000-0xb1ffffff SRAM                 IGNORED
> + * 0xb2000000-0xb3ffffff SRAM                 IGNORED
> + * 0xb4000000-0xb5ffffff CS4                  IGNORED
> + * 0xb6000000-0xb8000fff Reserved             IGNORED
> + * 0xb8001000-0xb8001fff SDRAM CTRL reg       IGNORED
> + * 0xb8002000-0xb8002fff WEIM CTRL reg        IGNORED
> + * 0xb8003000-0xb8003fff M3IF CTRL reg        IGNORED
> + * 0xb8004000-0xb8004fff EMI CTRL reg         IGNORED
> + * 0xb8005000-0xbaffffff Reserved             IGNORED
> + * 0xbb000000-0xbb000fff NAND flash area buf  IGNORED
> + * 0xbb001000-0xbb0011ff NAND flash reserved  IGNORED
> + * 0xbb001200-0xbb001dff Reserved             IGNORED
> + * 0xbb001e00-0xbb001fff NAN flash CTRL reg   IGNORED
> + * 0xbb012000-0xbfffffff Reserved             IGNORED
> + * 0xc0000000-0xffffffff Reserved             IGNORED
> + */
> +
> +#define IMX25_SRAM_ADDRESS  (0x78000000)
> +#define IMX25_SRAMSIZE      (128*1024)
> +#define IMX25_CS_SRAMSIZE   (128*1024*1024)
> +#define IMX25_3DS_ADDRESS   (0x80000000)
> +#define IMX25_CS_RAMSIZE    (256*1024*1024)
> +
> +static struct arm_boot_info imx25_3ds_binfo = {
> +    .loader_start = IMX25_3DS_ADDRESS,
> +    .board_id = 1771,
> +};
> +
> +static void imx25_3ds_init(MachineState *args)
> +{
> +    int i;
> +    int serial_cnt = 0;
> +    const ram_addr_t ram_size = args->ram_size;
> +    const char *cpu_model = args->cpu_model;
> +    const char *kernel_filename = args->kernel_filename;
> +    const char *kernel_cmdline = args->kernel_cmdline;
> +    const char *initrd_filename = args->initrd_filename;
> +    ARMCPU *cpu;
> +    DeviceState *pic_dev;
> +    DeviceState *ccm, *i2c_dev;
> +    MemoryRegion *address_space_mem = get_system_memory();
> +    MemoryRegion *sram = g_new(MemoryRegion, 1);
> +    MemoryRegion *sram_alias = g_new(MemoryRegion, 1);
> +    static const struct {
> +        hwaddr addr;
> +        unsigned int irq;
> +    } serial_table[] = {
> +        { 0x43f90000, 45 },
> +        { 0x43f94000, 32 },
> +        { 0x5000c000, 18 },
> +        { 0x50008000, 5  },
> +        { 0x5002c000, 40 },
> +        { 0, 0 }
> +    };
> +
> +    if (!cpu_model) {
> +        cpu_model = "arm926";
> +    }
> +
> +    cpu = cpu_arm_init(cpu_model);
> +    if (!cpu) {
> +        fprintf(stderr, "Unable to find CPU definition\n");
> +        exit(1);
> +    }
> +
> +    if (ram_size > (2 * IMX25_CS_RAMSIZE)) {
> +        fprintf(stderr, "i.MX25 can support only up to %d MB\n",
> +                2 * IMX25_CS_RAMSIZE / (1024 * 1024));
> +        exit(1);
> +    }
> +
> +    /* create our main memory */
> +    for (i = 0; i <= (ram_size / IMX25_CS_RAMSIZE); i++) {
> +        ram_addr_t blk_size = ram_size - (IMX25_CS_RAMSIZE * i);
> +        MemoryRegion *ram;
> +        char ram_name[20];
> +
> +        if (blk_size > IMX25_CS_RAMSIZE) {
> +            blk_size = IMX25_CS_RAMSIZE;
> +        }
> +
> +        if (blk_size == 0) {
> +            break;
> +        }
> +
> +        sprintf(ram_name, "imx25.ram%d", i);
> +
> +        ram = g_new(MemoryRegion, 1);
> +        memory_region_init_ram(ram, NULL, ram_name, blk_size, &error_abort);
> +        vmstate_register_ram_global(ram);
> +        memory_region_add_subregion(address_space_mem, IMX25_3DS_ADDRESS
> +                                    + (IMX25_CS_RAMSIZE * i), ram);
> +
> +        /* Add ram alias */
> +        if (blk_size < IMX25_CS_RAMSIZE) {
> +            MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
> +            char alias_name[20];
> +
> +            sprintf(alias_name, "ram.alias%d", i);
> +
> +            memory_region_init_alias(ram_alias, NULL, alias_name, ram, 0,
> +                                     IMX25_CS_RAMSIZE - blk_size);
> +            memory_region_add_subregion(address_space_mem, IMX25_3DS_ADDRESS
> +                                        + (IMX25_CS_RAMSIZE * i) + blk_size,
> +                                        ram_alias);
> +        }
> +    }
> +
> +    /* create the sram area */
> +    memory_region_init_ram(sram, NULL, "imx25.sram", IMX25_SRAMSIZE, &error_abort);
> +    vmstate_register_ram_global(sram);
> +    memory_region_add_subregion(address_space_mem, IMX25_SRAM_ADDRESS,
> +                                sram);
> +
> +    /* add sram alias */
> +    memory_region_init_alias(sram_alias, NULL, "sram.alias", sram, 0,
> +                             IMX25_CS_SRAMSIZE - IMX25_SRAMSIZE);
> +    memory_region_add_subregion(address_space_mem,
> +                                IMX25_SRAM_ADDRESS + IMX25_SRAMSIZE,
> +                                sram_alias);
> +
> +    /* add the PIC */
> +    pic_dev = sysbus_create_varargs("imx_avic", 0x68000000,
> +                                    qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
> +                                    qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
> +                                    NULL);
> +
> +    while (serial_table[serial_cnt].addr && (serial_cnt < MAX_SERIAL_PORTS)) {
> +        /* add some serial lines */
> +        imx_serial_create(serial_cnt, serial_table[serial_cnt].addr,
> +                          qdev_get_gpio_in(pic_dev,
> +                                           serial_table[serial_cnt].irq));
> +        serial_cnt++;
> +    }
> +
> +    ccm = sysbus_create_simple("imx_ccm", 0x53f80000, NULL);
> +
> +    /* add gpt timers */
> +    imx_timerg_create(0x53f84000, qdev_get_gpio_in(pic_dev, 1), ccm);
> +    imx_timerg_create(0x53f88000, qdev_get_gpio_in(pic_dev, 29), ccm);
> +    imx_timerg_create(0x53f8c000, qdev_get_gpio_in(pic_dev, 53), ccm);
> +    imx_timerg_create(0x53f90000, qdev_get_gpio_in(pic_dev, 54), ccm);
> +
> +    /* add epit timers */
> +    imx_timerp_create(0x53f94000, qdev_get_gpio_in(pic_dev, 28), ccm);
> +    imx_timerp_create(0x53f98000, qdev_get_gpio_in(pic_dev, 27), ccm);
> +
> +    imx_fec_create(0, 0x50038000, qdev_get_gpio_in(pic_dev, 57));
> +
> +    /* I2C 0 */
> +    i2c_dev = sysbus_create_simple("imx.i2c", 0x43f80000,
> +                                   qdev_get_gpio_in(pic_dev, 3));
> +
> +    /* add I2C 1 */
> +    sysbus_create_simple("imx.i2c", 0x43f98000, qdev_get_gpio_in(pic_dev, 4));
> +    /* add I2C 2 */
> +    sysbus_create_simple("imx.i2c", 0x43f84000, qdev_get_gpio_in(pic_dev, 10));
> +
> +    imx25_3ds_binfo.ram_size = ram_size;
> +    imx25_3ds_binfo.kernel_filename = kernel_filename;
> +    imx25_3ds_binfo.kernel_cmdline = kernel_cmdline;
> +    imx25_3ds_binfo.initrd_filename = initrd_filename;
> +    imx25_3ds_binfo.nb_cpus = 1;
> +
> +    /*
> +     * We test explicitly for qtest here as it is not done (yet?) in
> +     * arm_load_kernel(). Without this the "make check" command would
> +     * fail.
> +     */
> +
> +    if (!qtest_enabled()) {
> +        arm_load_kernel(cpu, &imx25_3ds_binfo);
> +    } else {
> +        /*
> +         * This I2C device doesn't exist on the real board.
> +         * We add it here (only on qtest usage) to be able to do a bit
> +         * of simple qtest. See "make check" for details.
> +         */
> +        i2c_create_slave((I2CBus *)qdev_get_child_bus(i2c_dev, "i2c"),
> +                         "ds1338", 0x68);
> +
> +    }
> +}
> +
> +static QEMUMachine imx25_3ds_machine = {
> +    .name = "imx25_3ds",
> +    .desc = "ARM i.MX25 PDK board (ARM926)",
> +    .init = imx25_3ds_init,
> +};
> +
> +static void imx25_3ds_machine_init(void)
> +{
> +    qemu_register_machine(&imx25_3ds_machine);
> +}
> +
> +machine_init(imx25_3ds_machine_init)
> --
> 2.1.4
>
>

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

* Re: [Qemu-devel] [PATCH v7 3/4] i.MX: Add i.MX25 3DS evaluation board support
  2015-06-24  5:07   ` Peter Crosthwaite
@ 2015-06-24  6:09     ` Jean-Christophe DUBOIS
  0 siblings, 0 replies; 7+ messages in thread
From: Jean-Christophe DUBOIS @ 2015-06-24  6:09 UTC (permalink / raw)
  To: Peter Crosthwaite, Peter Maydell, Andreas Färber
  Cc: qemu-devel@nongnu.org Developers

Le 24/06/2015 07:07, Peter Crosthwaite a écrit :
> On Mon, Jun 22, 2015 at 12:06 PM, Jean-Christophe Dubois
> <jcd@tribudubois.net> wrote:
>> For now we support:
>>      * timers (GPT and EPIT)
>>      * serial ports
>>      * ethernet (through the newly added FEC emulator)
>>      * I2C (through the newly added I2C emulator)
>>
>> Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
>> ---
>>
>> Changes since v1:
>>      * Added a ds1338 I2C device for qtest purpose.
>>
>> Changes since v2:
>>      * none
>>
>> Changes since v3:
>>      * Rework GPL header
>>      * use I2C constructor helper.
>>
>> Changes since v4:
>>      * use sysbus_create_simple() instead of I2C constructor helper
>>
>> Changes since v5:
>>      * Add ds1338 only for qtest mode.
>>      * small comment fixes.
>>
>> Changes since v6:
>>      * Allow for more than 4 serial if suppoted by Qemu.
>>
>>   hw/arm/Makefile.objs |   1 +
>>   hw/arm/imx25_3ds.c   | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++
> So the (new since v6) guideline with ARM SoCs is to split the SoC and
> machine models. This would give you two files. A SoC file for imx25
> and board for 3ds.
>
> I'm not 100% on the "3ds" board following some googling but is it
> really the PDK board? I found this:
>
> http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=635baf6b40ebaef683abf87d677467cba71a0d50
>
> and can find product info for PDK from there:
>
> http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=IMX25PDK
Yes this is the board.

>
> To see modern examples of split SoC/board, see stm32f205_soc wiith
> netduino2 or xlnx-zynqmp with xlnx-ep108 (all in hw/arm).
I'll look at it.
>
> It seems the only board level feature you are implementing is this
> ds1338 which is not or the real board. So I guess qtest-only code can
> be left in the SoC model.
OK
>
> This would make your board level very similar to netduino2 (perhaps
> even slightly simpler).
Yes, for now there is basically only the SOC supported in my case.
>
> Regards,
> Peter
Thanks for the feedback.

JC

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

end of thread, other threads:[~2015-06-24  6:09 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-22 19:06 [Qemu-devel] [PATCH v7 0/4] i.MX: Add i.MX25 support through the 3DS evaluation board Jean-Christophe Dubois
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 1/4] i.MX: Add FEC Ethernet Emulator Jean-Christophe Dubois
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 2/4] i.MX: Add I2C contoller emulator Jean-Christophe Dubois
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 3/4] i.MX: Add i.MX25 3DS evaluation board support Jean-Christophe Dubois
2015-06-24  5:07   ` Peter Crosthwaite
2015-06-24  6:09     ` Jean-Christophe DUBOIS
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 4/4] i.MX: Add qtest support for I2C device emulator Jean-Christophe Dubois

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.