All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v5 0/4] Add i.MX25 support through the 3DS evaluation board
@ 2013-05-08  8:28 Jean-Christophe DUBOIS
  2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 1/4] Add i.MX FEC Ethernet emulator Jean-Christophe DUBOIS
                   ` (4 more replies)
  0 siblings, 5 replies; 17+ messages in thread
From: Jean-Christophe DUBOIS @ 2013-05-08  8:28 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, peter.crosthwaite, peter.chubb, afaerber,
	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

It also adds qtest support for the I2C controller.

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

 default-configs/arm-softmmu.mak |   3 +
 hw/arm/Makefile.objs            |   1 +
 hw/arm/imx25_3ds.c              | 250 ++++++++++++
 hw/i2c/Makefile.objs            |   1 +
 hw/i2c/imx_i2c.c                | 357 ++++++++++++++++++
 hw/i2c/imx_i2c_regs.h           |  63 ++++
 hw/net/Makefile.objs            |   1 +
 hw/net/imx_fec.c                | 818 ++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/imx.h            |  10 +-
 tests/Makefile                  |   3 +
 tests/ds1338-test.c             |  75 ++++
 tests/libqos/i2c-imx.c          | 209 ++++++++++
 tests/libqos/i2c.h              |   3 +
 13 files changed, 1788 insertions(+), 6 deletions(-)
 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

-- 
1.8.1.2

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

* [Qemu-devel] [PATCH v5 1/4] Add i.MX FEC Ethernet emulator
  2013-05-08  8:28 [Qemu-devel] [PATCH v5 0/4] Add i.MX25 support through the 3DS evaluation board Jean-Christophe DUBOIS
@ 2013-05-08  8:28 ` Jean-Christophe DUBOIS
  2013-05-24  5:38   ` Peter Crosthwaite
  2013-06-03 15:12   ` Peter Maydell
  2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 2/4] Add i.MX I2C controller emulator Jean-Christophe DUBOIS
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 17+ messages in thread
From: Jean-Christophe DUBOIS @ 2013-05-08  8:28 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, peter.crosthwaite, peter.chubb, afaerber,
	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>
---

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

 default-configs/arm-softmmu.mak |   1 +
 hw/net/Makefile.objs            |   1 +
 hw/net/imx_fec.c                | 818 ++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/imx.h            |  10 +-
 4 files changed, 824 insertions(+), 6 deletions(-)
 create mode 100644 hw/net/imx_fec.c

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 27cbe3d..b3a0207 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -28,6 +28,7 @@ CONFIG_SSI_SD=y
 CONFIG_SSI_M25P80=y
 CONFIG_LAN9118=y
 CONFIG_SMC91C111=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 951cca3..5c84727 100644
--- a/hw/net/Makefile.objs
+++ b/hw/net/Makefile.objs
@@ -18,6 +18,7 @@ common-obj-$(CONFIG_OPENCORES_ETH) += opencores_eth.o
 common-obj-$(CONFIG_XGMAC) += xgmac.o
 common-obj-$(CONFIG_MIPSNET) += mipsnet.o
 common-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.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..e25d6cd
--- /dev/null
+++ b/hw/net/imx_fec.c
@@ -0,0 +1,818 @@
+/*
+ * 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 "qemu/bitops.h"
+
+#include "sysemu/dma.h"
+
+#include "net/net.h"
+
+#include "hw/sysbus.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
+
+#define TYPE_IMX_FEC                  "imx.fec"
+
+#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 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 guest which in turn
+ * could be handled as an interrupt by the guest.
+ * For now we don't handle any GPIO/interrupt line, so the guest 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:
+        hw_error("%s.phy[%s]: Bad address 0x%x\n", TYPE_IMX_FEC, __func__,
+                 (int)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 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;
+    case 30:    /* Interrupt mask */
+        s->phy_int_mask = val & 0xff;
+        phy_update_irq(s);
+        break;
+    default:
+        hw_error("%s.phy[%s]: Bad address 0x%x\n", TYPE_IMX_FEC, __func__,
+                 (int)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(&dma_context_memory, addr, bd, sizeof(*bd));
+}
+
+static void imx_fec_write_bd(IMXFECBufDesc *bd, dma_addr_t addr)
+{
+    dma_memory_write(&dma_context_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(&dma_context_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:
+        hw_error("%s[%s]: Bad address 0x%x\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:
+        hw_error("%s[%s]: Bad address 0x%x\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(&dma_context_memory, buf_addr, buf, buf_len);
+        buf += buf_len;
+        if (size < 4) {
+            dma_memory_write(&dma_context_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, &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..d16c468 100644
--- a/include/hw/arm/imx.h
+++ b/include/hw/arm/imx.h
@@ -23,12 +23,10 @@ typedef enum  {
 
 uint32_t imx_clock_frequency(DeviceState *s, IMXClk clock);
 
-void imx_timerp_create(const hwaddr addr,
-                      qemu_irq irq,
-                      DeviceState *ccm);
-void imx_timerg_create(const hwaddr addr,
-                      qemu_irq irq,
-                      DeviceState *ccm);
+void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm);
 
+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 */
-- 
1.8.1.2

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

* [Qemu-devel] [PATCH v5 2/4] Add i.MX I2C controller emulator
  2013-05-08  8:28 [Qemu-devel] [PATCH v5 0/4] Add i.MX25 support through the 3DS evaluation board Jean-Christophe DUBOIS
  2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 1/4] Add i.MX FEC Ethernet emulator Jean-Christophe DUBOIS
@ 2013-05-08  8:28 ` Jean-Christophe DUBOIS
  2013-05-24  5:29   ` Peter Crosthwaite
  2013-06-03 15:14   ` Peter Maydell
  2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 3/4] Add i.MX25 3DS evaluation board support Jean-Christophe DUBOIS
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 17+ messages in thread
From: Jean-Christophe DUBOIS @ 2013-05-08  8:28 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, peter.crosthwaite, peter.chubb, afaerber,
	Jean-Christophe DUBOIS

The slave mode is not implemented.

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

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

 default-configs/arm-softmmu.mak |   2 +
 hw/i2c/Makefile.objs            |   1 +
 hw/i2c/imx_i2c.c                | 357 ++++++++++++++++++++++++++++++++++++++++
 hw/i2c/imx_i2c_regs.h           |  63 +++++++
 4 files changed, 423 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 b3a0207..a20f112 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -81,3 +81,5 @@ CONFIG_VERSATILE_PCI=y
 CONFIG_VERSATILE_I2C=y
 
 CONFIG_SDHCI=y
+
+CONFIG_IMX_I2C=y
diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
index 648278e..d27bbaa 100644
--- a/hw/i2c/Makefile.objs
+++ b/hw/i2c/Makefile.objs
@@ -4,4 +4,5 @@ common-obj-$(CONFIG_ACPI) += 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..292c07b
--- /dev/null
+++ b/hw/i2c/imx_i2c.c
@@ -0,0 +1,357 @@
+/*
+ *  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 "qemu/bitops.h"
+
+#include "hw/sysbus.h"
+#include "hw/i2c/i2c.h"
+
+#include "hw/arm/imx.h"
+
+#include "hw/i2c/imx_i2c_regs.h"
+
+#ifndef IMX_I2C_DEBUG
+#define IMX_I2C_DEBUG                 0
+#endif
+
+#define TYPE_IMX_I2C                  "imx.i2c"
+
+#if IMX_I2C_DEBUG
+#define DPRINT(fmt, ...)              \
+    do { fprintf(stderr, "%s[%s]: " fmt, TYPE_IMX_I2C, __func__, \
+                 ## __VA_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
+
+#define IMX_I2C(obj)                  \
+    OBJECT_CHECK(IMXI2CState, (obj), TYPE_IMX_I2C)
+
+typedef struct IMXI2CState {
+    SysBusDevice parent_obj;
+
+    MemoryRegion iomem;
+    i2c_bus *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);
+
+    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;
+        }
+        break;
+    default:
+        hw_error("%s: Bad address 0x%x\n", __func__, (int)offset);
+        break;
+    }
+
+    DPRINT("read %s [0x%02x] -> 0x%02x\n", imx_i2c_get_regname(offset),
+           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),
+           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);
+                }
+            }
+        }
+        break;
+    default:
+        hw_error("%s: Bad address 0x%x\n", __func__, (int)offset);
+        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);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+    memory_region_init_io(&s->iomem, &imx_i2c_ops, s, TYPE_IMX_I2C,
+                          IMX_I2C_MEM_SIZE);
+    sysbus_init_mmio(sbd, &s->iomem);
+    sysbus_init_irq(sbd, &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_ */
-- 
1.8.1.2

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

* [Qemu-devel] [PATCH v5 3/4] Add i.MX25 3DS evaluation board support.
  2013-05-08  8:28 [Qemu-devel] [PATCH v5 0/4] Add i.MX25 support through the 3DS evaluation board Jean-Christophe DUBOIS
  2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 1/4] Add i.MX FEC Ethernet emulator Jean-Christophe DUBOIS
  2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 2/4] Add i.MX I2C controller emulator Jean-Christophe DUBOIS
@ 2013-05-08  8:28 ` Jean-Christophe DUBOIS
  2013-06-03 15:18   ` Peter Maydell
  2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 4/4] Add qtest support for i.MX I2C device emulation Jean-Christophe DUBOIS
  2013-05-12 12:55 ` [Qemu-devel] [PATCH v5 0/4] Add i.MX25 support through the 3DS evaluation board Jean-Christophe DUBOIS
  4 siblings, 1 reply; 17+ messages in thread
From: Jean-Christophe DUBOIS @ 2013-05-08  8:28 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, peter.crosthwaite, peter.chubb, afaerber,
	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

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

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 9e3a06f..2f4280d 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -2,6 +2,7 @@ obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o
 obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
 obj-y += omap_sx1.o palm.o pic_cpu.o realview.o spitz.o stellaris.o
 obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o
+obj-y += imx25_3ds.o
 
 obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
 obj-y += omap1.o omap2.o strongarm.o
diff --git a/hw/arm/imx25_3ds.c b/hw/arm/imx25_3ds.c
new file mode 100644
index 0000000..c845195
--- /dev/null
+++ b/hw/arm/imx25_3ds.c
@@ -0,0 +1,250 @@
+/*
+ * 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
+ *   0x5000c000 UART3                         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
+ *   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(QEMUMachineInitArgs *args)
+{
+    int i;
+    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;
+    qemu_irq *cpu_pic;
+    DeviceState *pic_dev, *ccm, *i2c_dev;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
+    MemoryRegion *sram_alias = g_new(MemoryRegion, 1);
+
+    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, ram_name, blk_size);
+        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, 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, "imx25.sram", IMX25_SRAMSIZE);
+    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, "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 */
+    cpu_pic = arm_pic_init_cpu(cpu);
+    pic_dev = sysbus_create_varargs("imx_avic", 0x68000000,
+                                    cpu_pic[ARM_PIC_CPU_IRQ],
+                                    cpu_pic[ARM_PIC_CPU_FIQ], NULL);
+
+    /* add some serial lines */
+    imx_serial_create(0, 0x43f90000, qdev_get_gpio_in(pic_dev, 45));
+    imx_serial_create(1, 0x43f94000, qdev_get_gpio_in(pic_dev, 32));
+    imx_serial_create(2, 0x5000c000, qdev_get_gpio_in(pic_dev, 18));
+
+    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);
+
+    /* add Ethernet */
+    imx_fec_create(0, 0x50038000, qdev_get_gpio_in(pic_dev, 57));
+
+    /* add I2C 0 */
+    i2c_dev = sysbus_create_simple("imx.i2c", 0x43f80000,
+                                   qdev_get_gpio_in(pic_dev, 3));
+    /*
+     * this I2C device doesn't exits on the real board.
+     * We add it to be able to do a bit of simple qtest.
+     * see "make check" for details
+     */
+    i2c_create_slave((i2c_bus *)qdev_get_child_bus(i2c_dev, "i2c"),
+                     "ds1338", 0x68);
+
+    /* 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 explicitely 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);
+    }
+}
+
+static QEMUMachine imx25_3ds_machine = {
+    .name = "imx25_3ds",
+    .desc = "ARM i.MX25 PDK board (ARM926)",
+    .init = imx25_3ds_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void imx25_3ds_machine_init(void)
+{
+    qemu_register_machine(&imx25_3ds_machine);
+}
+
+machine_init(imx25_3ds_machine_init)
-- 
1.8.1.2

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

* [Qemu-devel] [PATCH v5 4/4] Add qtest support for i.MX I2C device emulation.
  2013-05-08  8:28 [Qemu-devel] [PATCH v5 0/4] Add i.MX25 support through the 3DS evaluation board Jean-Christophe DUBOIS
                   ` (2 preceding siblings ...)
  2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 3/4] Add i.MX25 3DS evaluation board support Jean-Christophe DUBOIS
@ 2013-05-08  8:28 ` Jean-Christophe DUBOIS
  2013-06-03 15:21   ` Peter Maydell
  2013-05-12 12:55 ` [Qemu-devel] [PATCH v5 0/4] Add i.MX25 support through the 3DS evaluation board Jean-Christophe DUBOIS
  4 siblings, 1 reply; 17+ messages in thread
From: Jean-Christophe DUBOIS @ 2013-05-08  8:28 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, peter.crosthwaite, peter.chubb, afaerber,
	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

 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 bf41d10..5f7a0e0 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -64,6 +64,7 @@ gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y)
 gcov-files-sparc-y += hw/m48t59.c
 gcov-files-sparc64-y += hw/m48t59.c
 check-qtest-arm-y = tests/tmp105-test$(EXESUF)
+check-qtest-arm-y += tests/ds1338-test$(EXESUF)
 gcov-files-arm-y += hw/tmp105.c
 
 GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
@@ -123,12 +124,14 @@ libqos-obj-y += tests/libqos/i2c.o
 libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o tests/libqos/fw_cfg-pc.o
 libqos-pc-obj-y += tests/libqos/malloc-pc.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
 
 tests/rtc-test$(EXESUF): tests/rtc-test.o
 tests/m48t59-test$(EXESUF): tests/m48t59-test.o
 tests/fdc-test$(EXESUF): tests/fdc-test.o
 tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o
 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/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
-- 
1.8.1.2

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

* Re: [Qemu-devel] [PATCH v5 0/4] Add i.MX25 support through the 3DS evaluation board
  2013-05-08  8:28 [Qemu-devel] [PATCH v5 0/4] Add i.MX25 support through the 3DS evaluation board Jean-Christophe DUBOIS
                   ` (3 preceding siblings ...)
  2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 4/4] Add qtest support for i.MX I2C device emulation Jean-Christophe DUBOIS
@ 2013-05-12 12:55 ` Jean-Christophe DUBOIS
  2013-05-12 13:14   ` Peter Maydell
  4 siblings, 1 reply; 17+ messages in thread
From: Jean-Christophe DUBOIS @ 2013-05-12 12:55 UTC (permalink / raw)
  To: peter.maydell; +Cc: peter.crosthwaite, peter.chubb, qemu-devel, afaerber

Peter (and all),

In your opinion, is this patch set good enough in its actual state for 
inclusion?

Are you expecting anything else from me (beside maybe adding more i.MX 
devices in the future)?

Thanks

JC

On 05/08/2013 10:28 AM, Jean-Christophe DUBOIS wrote:
> 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
>
> It also adds qtest support for the I2C controller.
>
> Jean-Christophe DUBOIS (4):
>    Add i.MX FEC Ethernet emulator
>    Add i.MX I2C controller emulator
>    Add i.MX25 3DS evaluation board support.
>    Add qtest support for i.MX I2C device emulation.
>
>   default-configs/arm-softmmu.mak |   3 +
>   hw/arm/Makefile.objs            |   1 +
>   hw/arm/imx25_3ds.c              | 250 ++++++++++++
>   hw/i2c/Makefile.objs            |   1 +
>   hw/i2c/imx_i2c.c                | 357 ++++++++++++++++++
>   hw/i2c/imx_i2c_regs.h           |  63 ++++
>   hw/net/Makefile.objs            |   1 +
>   hw/net/imx_fec.c                | 818 ++++++++++++++++++++++++++++++++++++++++
>   include/hw/arm/imx.h            |  10 +-
>   tests/Makefile                  |   3 +
>   tests/ds1338-test.c             |  75 ++++
>   tests/libqos/i2c-imx.c          | 209 ++++++++++
>   tests/libqos/i2c.h              |   3 +
>   13 files changed, 1788 insertions(+), 6 deletions(-)
>   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
>

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

* Re: [Qemu-devel] [PATCH v5 0/4] Add i.MX25 support through the 3DS evaluation board
  2013-05-12 12:55 ` [Qemu-devel] [PATCH v5 0/4] Add i.MX25 support through the 3DS evaluation board Jean-Christophe DUBOIS
@ 2013-05-12 13:14   ` Peter Maydell
  2013-06-03 15:23     ` Peter Maydell
  0 siblings, 1 reply; 17+ messages in thread
From: Peter Maydell @ 2013-05-12 13:14 UTC (permalink / raw)
  To: Jean-Christophe DUBOIS
  Cc: peter.crosthwaite, peter.chubb, qemu-devel, afaerber

On 12 May 2013 13:55, Jean-Christophe DUBOIS <jcd@tribudubois.net> wrote:
> In your opinion, is this patch set good enough in its actual state for
> inclusion?
>
> Are you expecting anything else from me (beside maybe adding more i.MX
> devices in the future)?

I haven't looked at this series yet because we're in codefreeze.

thanks
-- PMM

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

* Re: [Qemu-devel] [PATCH v5 2/4] Add i.MX I2C controller emulator
  2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 2/4] Add i.MX I2C controller emulator Jean-Christophe DUBOIS
@ 2013-05-24  5:29   ` Peter Crosthwaite
  2013-06-03 15:14   ` Peter Maydell
  1 sibling, 0 replies; 17+ messages in thread
From: Peter Crosthwaite @ 2013-05-24  5:29 UTC (permalink / raw)
  To: Jean-Christophe DUBOIS; +Cc: peter.maydell, peter.chubb, qemu-devel, afaerber

Hi JC,

All blocker comments are addressed from my reviews. Only a few minor
suggestions below.

On Wed, May 8, 2013 at 6:28 PM, Jean-Christophe DUBOIS
<jcd@tribudubois.net> wrote:
> The slave mode is not implemented.

This may be worth a LOG_UNIMP in there somewhere (on detection of
selection or use in
slave mode?)

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

Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.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
>
>  default-configs/arm-softmmu.mak |   2 +
>  hw/i2c/Makefile.objs            |   1 +
>  hw/i2c/imx_i2c.c                | 357 ++++++++++++++++++++++++++++++++++++++++
>  hw/i2c/imx_i2c_regs.h           |  63 +++++++
>  4 files changed, 423 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 b3a0207..a20f112 100644
> --- a/default-configs/arm-softmmu.mak
> +++ b/default-configs/arm-softmmu.mak
> @@ -81,3 +81,5 @@ CONFIG_VERSATILE_PCI=y
>  CONFIG_VERSATILE_I2C=y
>
>  CONFIG_SDHCI=y
> +
> +CONFIG_IMX_I2C=y
> diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
> index 648278e..d27bbaa 100644
> --- a/hw/i2c/Makefile.objs
> +++ b/hw/i2c/Makefile.objs
> @@ -4,4 +4,5 @@ common-obj-$(CONFIG_ACPI) += 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..292c07b
> --- /dev/null
> +++ b/hw/i2c/imx_i2c.c
> @@ -0,0 +1,357 @@
> +/*
> + *  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 "qemu/bitops.h"
> +
> +#include "hw/sysbus.h"
> +#include "hw/i2c/i2c.h"
> +
> +#include "hw/arm/imx.h"
> +
> +#include "hw/i2c/imx_i2c_regs.h"
> +
> +#ifndef IMX_I2C_DEBUG
> +#define IMX_I2C_DEBUG                 0
> +#endif
> +
> +#define TYPE_IMX_I2C                  "imx.i2c"
> +
> +#if IMX_I2C_DEBUG
> +#define DPRINT(fmt, ...)              \
> +    do { fprintf(stderr, "%s[%s]: " fmt, TYPE_IMX_I2C, __func__, \
> +                 ## __VA_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
> +
> +#define IMX_I2C(obj)                  \
> +    OBJECT_CHECK(IMXI2CState, (obj), TYPE_IMX_I2C)
> +
> +typedef struct IMXI2CState {
> +    SysBusDevice parent_obj;
> +
> +    MemoryRegion iomem;
> +    i2c_bus *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);
> +
> +    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;
> +        }
> +        break;
> +    default:
> +        hw_error("%s: Bad address 0x%x\n", __func__, (int)offset);

I think the favor is for log_guest_error on this condition as well,
but AFAICT, your register region is completely covered making this
unreachable so Im cool with it. Perhaps either a hard abort() or just
the trivial translation to log_guest_error. Here and below.

Regards,
Peter

> +        break;
> +    }
> +
> +    DPRINT("read %s [0x%02x] -> 0x%02x\n", imx_i2c_get_regname(offset),
> +           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),
> +           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);
> +                }
> +            }
> +        }
> +        break;
> +    default:
> +        hw_error("%s: Bad address 0x%x\n", __func__, (int)offset);
> +        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);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +
> +    memory_region_init_io(&s->iomem, &imx_i2c_ops, s, TYPE_IMX_I2C,
> +                          IMX_I2C_MEM_SIZE);
> +    sysbus_init_mmio(sbd, &s->iomem);
> +    sysbus_init_irq(sbd, &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_ */
> --
> 1.8.1.2
>
>

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

* Re: [Qemu-devel] [PATCH v5 1/4] Add i.MX FEC Ethernet emulator
  2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 1/4] Add i.MX FEC Ethernet emulator Jean-Christophe DUBOIS
@ 2013-05-24  5:38   ` Peter Crosthwaite
  2013-06-03 15:12   ` Peter Maydell
  1 sibling, 0 replies; 17+ messages in thread
From: Peter Crosthwaite @ 2013-05-24  5:38 UTC (permalink / raw)
  To: Jean-Christophe DUBOIS; +Cc: peter.maydell, peter.chubb, qemu-devel, afaerber

Hi JC,

All major comments addressed. Few minor suggestions.

On Wed, May 8, 2013 at 6:28 PM, Jean-Christophe DUBOIS
<jcd@tribudubois.net> wrote:
> 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 <peter.crosthwaite@xilinx.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
>
>  default-configs/arm-softmmu.mak |   1 +
>  hw/net/Makefile.objs            |   1 +
>  hw/net/imx_fec.c                | 818 ++++++++++++++++++++++++++++++++++++++++
>  include/hw/arm/imx.h            |  10 +-
>  4 files changed, 824 insertions(+), 6 deletions(-)
>  create mode 100644 hw/net/imx_fec.c
>
> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
> index 27cbe3d..b3a0207 100644
> --- a/default-configs/arm-softmmu.mak
> +++ b/default-configs/arm-softmmu.mak
> @@ -28,6 +28,7 @@ CONFIG_SSI_SD=y
>  CONFIG_SSI_M25P80=y
>  CONFIG_LAN9118=y
>  CONFIG_SMC91C111=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 951cca3..5c84727 100644
> --- a/hw/net/Makefile.objs
> +++ b/hw/net/Makefile.objs
> @@ -18,6 +18,7 @@ common-obj-$(CONFIG_OPENCORES_ETH) += opencores_eth.o
>  common-obj-$(CONFIG_XGMAC) += xgmac.o
>  common-obj-$(CONFIG_MIPSNET) += mipsnet.o
>  common-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.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..e25d6cd
> --- /dev/null
> +++ b/hw/net/imx_fec.c
> @@ -0,0 +1,818 @@
> +/*
> + * 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 "qemu/bitops.h"
> +
> +#include "sysemu/dma.h"
> +
> +#include "net/net.h"
> +
> +#include "hw/sysbus.h"
> +

The spaces between individual lines are probably un-needed.

> +/* 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
> +
> +#define TYPE_IMX_FEC                  "imx.fec"
> +
> +#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 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 guest which in turn
> + * could be handled as an interrupt by the guest.
> + * For now we don't handle any GPIO/interrupt line, so the guest 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;

Theres a lot of magic numbers in the phy code but they all from the
copy-pasted bits AFAIK.

> +        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:
> +        hw_error("%s.phy[%s]: Bad address 0x%x\n", TYPE_IMX_FEC, __func__,
> +                 (int)reg);

Same as before with the I2C patch.

Regards,
Peter

> +        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 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;
> +    case 30:    /* Interrupt mask */
> +        s->phy_int_mask = val & 0xff;
> +        phy_update_irq(s);
> +        break;
> +    default:
> +        hw_error("%s.phy[%s]: Bad address 0x%x\n", TYPE_IMX_FEC, __func__,
> +                 (int)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(&dma_context_memory, addr, bd, sizeof(*bd));
> +}
> +
> +static void imx_fec_write_bd(IMXFECBufDesc *bd, dma_addr_t addr)
> +{
> +    dma_memory_write(&dma_context_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(&dma_context_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:
> +        hw_error("%s[%s]: Bad address 0x%x\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:
> +        hw_error("%s[%s]: Bad address 0x%x\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(&dma_context_memory, buf_addr, buf, buf_len);
> +        buf += buf_len;
> +        if (size < 4) {
> +            dma_memory_write(&dma_context_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, &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..d16c468 100644
> --- a/include/hw/arm/imx.h
> +++ b/include/hw/arm/imx.h
> @@ -23,12 +23,10 @@ typedef enum  {
>
>  uint32_t imx_clock_frequency(DeviceState *s, IMXClk clock);
>
> -void imx_timerp_create(const hwaddr addr,
> -                      qemu_irq irq,
> -                      DeviceState *ccm);
> -void imx_timerg_create(const hwaddr addr,
> -                      qemu_irq irq,
> -                      DeviceState *ccm);
> +void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm);
>
> +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 */
> --
> 1.8.1.2
>
>

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

* Re: [Qemu-devel] [PATCH v5 1/4] Add i.MX FEC Ethernet emulator
  2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 1/4] Add i.MX FEC Ethernet emulator Jean-Christophe DUBOIS
  2013-05-24  5:38   ` Peter Crosthwaite
@ 2013-06-03 15:12   ` Peter Maydell
  1 sibling, 0 replies; 17+ messages in thread
From: Peter Maydell @ 2013-06-03 15:12 UTC (permalink / raw)
  To: Jean-Christophe DUBOIS
  Cc: peter.crosthwaite, peter.chubb, qemu-devel, afaerber

On 8 May 2013 09:28, Jean-Christophe DUBOIS <jcd@tribudubois.net> wrote:
> --- a/include/hw/arm/imx.h
> +++ b/include/hw/arm/imx.h
> @@ -23,12 +23,10 @@ typedef enum  {
>
>  uint32_t imx_clock_frequency(DeviceState *s, IMXClk clock);
>
> -void imx_timerp_create(const hwaddr addr,
> -                      qemu_irq irq,
> -                      DeviceState *ccm);
> -void imx_timerg_create(const hwaddr addr,
> -                      qemu_irq irq,
> -                      DeviceState *ccm);
> +void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm);
>
> +void imx_timerg_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm);
> +

Please don't include random reformatting inside a patch
doing something else.

> +DeviceState *imx_fec_create(int nic, const hwaddr base, qemu_irq irq);

thanks
-- PMM

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

* Re: [Qemu-devel] [PATCH v5 2/4] Add i.MX I2C controller emulator
  2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 2/4] Add i.MX I2C controller emulator Jean-Christophe DUBOIS
  2013-05-24  5:29   ` Peter Crosthwaite
@ 2013-06-03 15:14   ` Peter Maydell
  1 sibling, 0 replies; 17+ messages in thread
From: Peter Maydell @ 2013-06-03 15:14 UTC (permalink / raw)
  To: Jean-Christophe DUBOIS
  Cc: peter.crosthwaite, peter.chubb, qemu-devel, afaerber

On 8 May 2013 09:28, Jean-Christophe DUBOIS <jcd@tribudubois.net> wrote:
> +                /*
> +                 *if we unset the master mode then it ends the ongoing
> +                 * transfer if any
> +                 */

nit: missing space between '*' and if'.

thanks
-- PMM

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

* Re: [Qemu-devel] [PATCH v5 3/4] Add i.MX25 3DS evaluation board support.
  2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 3/4] Add i.MX25 3DS evaluation board support Jean-Christophe DUBOIS
@ 2013-06-03 15:18   ` Peter Maydell
  0 siblings, 0 replies; 17+ messages in thread
From: Peter Maydell @ 2013-06-03 15:18 UTC (permalink / raw)
  To: Jean-Christophe DUBOIS
  Cc: peter.crosthwaite, peter.chubb, qemu-devel, afaerber

On 8 May 2013 09:28, 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)

> +    /* add I2C 0 */
> +    i2c_dev = sysbus_create_simple("imx.i2c", 0x43f80000,
> +                                   qdev_get_gpio_in(pic_dev, 3));
> +    /*
> +     * this I2C device doesn't exits on the real board.

"exist"

> +     * We add it to be able to do a bit of simple qtest.
> +     * see "make check" for details
> +     */
> +    i2c_create_slave((i2c_bus *)qdev_get_child_bus(i2c_dev, "i2c"),
> +                     "ds1338", 0x68);

If it doesn't exist on the real board we shouldn't create it
in the model (except possibly under an "if qtest" guard).

"if qtest" guards are pretty ugly though.

> +
> +    /* 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 explicitely for qtest here as it is not done (yet?) in

"explicitly".

> +     * arm_load_kernel(). Without this the "make check" command would
> +     * fail.
> +     */
> +    if (!qtest_enabled()) {
> +        arm_load_kernel(cpu, &imx25_3ds_binfo);
> +    }
> +}

thanks
-- PMM

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

* Re: [Qemu-devel] [PATCH v5 4/4] Add qtest support for i.MX I2C device emulation.
  2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 4/4] Add qtest support for i.MX I2C device emulation Jean-Christophe DUBOIS
@ 2013-06-03 15:21   ` Peter Maydell
  2013-06-04  3:24     ` Peter Crosthwaite
  0 siblings, 1 reply; 17+ messages in thread
From: Peter Maydell @ 2013-06-03 15:21 UTC (permalink / raw)
  To: Jean-Christophe DUBOIS
  Cc: peter.crosthwaite, peter.chubb, qemu-devel, afaerber

On 8 May 2013 09:28, Jean-Christophe DUBOIS <jcd@tribudubois.net> wrote:
> This is using a ds1338 RTC chip on the i2c bus. This RTC
> chip is not present on the real board.

Ideally this should work by the test driver passing
a "-device ds1338,something,something" argument to
instantiate the RTC and connect it to the I2C bus,
rather than the board doing it if it knows it's being
run by qtest. Does the i2c interface let us do that?

> +
> +    /* check retreived time againt local time */

"retrieve", "against"

thanks
-- PMM

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

* Re: [Qemu-devel] [PATCH v5 0/4] Add i.MX25 support through the 3DS evaluation board
  2013-05-12 13:14   ` Peter Maydell
@ 2013-06-03 15:23     ` Peter Maydell
  2013-06-04 18:23       ` Jean-Christophe DUBOIS
  0 siblings, 1 reply; 17+ messages in thread
From: Peter Maydell @ 2013-06-03 15:23 UTC (permalink / raw)
  To: Jean-Christophe DUBOIS
  Cc: peter.crosthwaite, peter.chubb, qemu-devel, afaerber

On 12 May 2013 14:14, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 12 May 2013 13:55, Jean-Christophe DUBOIS <jcd@tribudubois.net> wrote:
>> In your opinion, is this patch set good enough in its actual state for
>> inclusion?
>>
>> Are you expecting anything else from me (beside maybe adding more i.MX
>> devices in the future)?
>
> I haven't looked at this series yet because we're in codefreeze.

I've now glanced through this and noted a few (mostly nitpick)
issues. I see Peter Crosthwaite has also commented on some of the
patches, so there are some issues to fix in a v6. In general I
don't want to take this without an acked-by from Peter Chubb as
the iMX maintainer, since I don't know the board/devices and
don't have any test cases for it either.

thanks
-- PMM

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

* Re: [Qemu-devel] [PATCH v5 4/4] Add qtest support for i.MX I2C device emulation.
  2013-06-03 15:21   ` Peter Maydell
@ 2013-06-04  3:24     ` Peter Crosthwaite
  2013-06-04 18:41       ` Jean-Christophe DUBOIS
  0 siblings, 1 reply; 17+ messages in thread
From: Peter Crosthwaite @ 2013-06-04  3:24 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Jan Kiszka, peter.chubb, qemu-devel, Andreas Färber,
	Jean-Christophe DUBOIS

Hi Peter,

On Tue, Jun 4, 2013 at 1:21 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 8 May 2013 09:28, Jean-Christophe DUBOIS <jcd@tribudubois.net> wrote:
>> This is using a ds1338 RTC chip on the i2c bus. This RTC
>> chip is not present on the real board.
>
> Ideally this should work by the test driver passing
> a "-device ds1338,something,something" argument to
> instantiate the RTC and connect it to the I2C bus,
> rather than the board doing it if it knows it's being
> run by qtest. Does the i2c interface let us do that?
>

CC Jan, I think he had some success with this in the at24 work, so I
think the answer is yes. And I cant see any reason why not - I2C is
properly QOMified AFAIK.

Regards,
peter

>> +
>> +    /* check retreived time againt local time */
>
> "retrieve", "against"
>
> thanks
> -- PMM
>

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

* Re: [Qemu-devel] [PATCH v5 0/4] Add i.MX25 support through the 3DS evaluation board
  2013-06-03 15:23     ` Peter Maydell
@ 2013-06-04 18:23       ` Jean-Christophe DUBOIS
  0 siblings, 0 replies; 17+ messages in thread
From: Jean-Christophe DUBOIS @ 2013-06-04 18:23 UTC (permalink / raw)
  To: Peter Maydell; +Cc: peter.crosthwaite, peter.chubb, qemu-devel, afaerber

On 06/03/2013 05:23 PM, Peter Maydell wrote:
> On 12 May 2013 14:14, Peter Maydell <peter.maydell@linaro.org> wrote:
>> On 12 May 2013 13:55, Jean-Christophe DUBOIS <jcd@tribudubois.net> wrote:
>>> In your opinion, is this patch set good enough in its actual state for
>>> inclusion?
>>>
>>> Are you expecting anything else from me (beside maybe adding more i.MX
>>> devices in the future)?
>> I haven't looked at this series yet because we're in codefreeze.
> I've now glanced through this and noted a few (mostly nitpick)
> issues.
I'll fix them.
>   I see Peter Crosthwaite has also commented on some of the
> patches, so there are some issues to fix in a v6.

Will do.

>   In general I
> don't want to take this without an acked-by from Peter Chubb as
> the iMX maintainer, since I don't know the board/devices and
> don't have any test cases for it either.
Well, you would have to build a i.MX25 3DS kernel in Linux.

I am not sure Peter (Chubb) has the board either.

But as long as the emulation is able to boot the Linux kernel (I used 
3.7.1 last time) configured for the i.MX25 it has to be reasonable enough.

In addition to Linux, I personally also boot an hypervisor (Xvisor) on it.
I also checked the hypervisor was booting on the real hardware.
So all in all it is working OK.

JC

>
> thanks
> -- PMM
>

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

* Re: [Qemu-devel] [PATCH v5 4/4] Add qtest support for i.MX I2C device emulation.
  2013-06-04  3:24     ` Peter Crosthwaite
@ 2013-06-04 18:41       ` Jean-Christophe DUBOIS
  0 siblings, 0 replies; 17+ messages in thread
From: Jean-Christophe DUBOIS @ 2013-06-04 18:41 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Peter Maydell, peter.chubb, qemu-devel, Jan Kiszka, Andreas Färber

On 06/04/2013 05:24 AM, Peter Crosthwaite wrote:
> Hi Peter,
>
> On Tue, Jun 4, 2013 at 1:21 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> On 8 May 2013 09:28, Jean-Christophe DUBOIS <jcd@tribudubois.net> wrote:
>>> This is using a ds1338 RTC chip on the i2c bus. This RTC
>>> chip is not present on the real board.
>> Ideally this should work by the test driver passing
>> a "-device ds1338,something,something" argument to
>> instantiate the RTC and connect it to the I2C bus,
>> rather than the board doing it if it knows it's being
>> run by qtest. Does the i2c interface let us do that?
>>
> CC Jan, I think he had some success with this in the at24 work, so I
> think the answer is yes. And I cant see any reason why not - I2C is
> properly QOMified AFAIK.
>
> Regards,
> peter

Is there some tutorial or something?

How to select the i2C master bus (out of several available)?

How to integrate this argument passing in qtest framework?

Thanks

JC
>
>>> +
>>> +    /* check retreived time againt local time */
>> "retrieve", "against"
>>
>> thanks
>> -- PMM
>>

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

end of thread, other threads:[~2013-06-04 18:41 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-05-08  8:28 [Qemu-devel] [PATCH v5 0/4] Add i.MX25 support through the 3DS evaluation board Jean-Christophe DUBOIS
2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 1/4] Add i.MX FEC Ethernet emulator Jean-Christophe DUBOIS
2013-05-24  5:38   ` Peter Crosthwaite
2013-06-03 15:12   ` Peter Maydell
2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 2/4] Add i.MX I2C controller emulator Jean-Christophe DUBOIS
2013-05-24  5:29   ` Peter Crosthwaite
2013-06-03 15:14   ` Peter Maydell
2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 3/4] Add i.MX25 3DS evaluation board support Jean-Christophe DUBOIS
2013-06-03 15:18   ` Peter Maydell
2013-05-08  8:28 ` [Qemu-devel] [PATCH v5 4/4] Add qtest support for i.MX I2C device emulation Jean-Christophe DUBOIS
2013-06-03 15:21   ` Peter Maydell
2013-06-04  3:24     ` Peter Crosthwaite
2013-06-04 18:41       ` Jean-Christophe DUBOIS
2013-05-12 12:55 ` [Qemu-devel] [PATCH v5 0/4] Add i.MX25 support through the 3DS evaluation board Jean-Christophe DUBOIS
2013-05-12 13:14   ` Peter Maydell
2013-06-03 15:23     ` Peter Maydell
2013-06-04 18:23       ` 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.