* [Qemu-devel] [PATCH v7 0/4] i.MX: Add i.MX25 support through the 3DS evaluation board.
@ 2015-06-22 19:06 Jean-Christophe Dubois
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 1/4] i.MX: Add FEC Ethernet Emulator Jean-Christophe Dubois
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Jean-Christophe Dubois @ 2015-06-22 19:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Jean-Christophe Dubois
This series of patches add the support for the i.MX25 processor through the
Freescale 3DS evaluation board.
For now a limited set of devices are supported.
* GPT timers (from i.MX31)
* EPIT timers (from i.MX31)
* Serial ports (from i.MX31)
* Ethernet FEC port
* I2C controller
This was tested by:
* booting a minimal linux system
* booting the Xvisor hypervisor.
Jean-Christophe Dubois (4):
i.MX: Add FEC Ethernet Emulator.
i.MX: Add I2C contoller emulator
i.MX: Add i.MX25 3DS evaluation board support
i.MX: Add qtest support for I2C device emulator
default-configs/arm-softmmu.mak | 3 +
hw/arm/Makefile.objs | 1 +
hw/arm/imx25_3ds.c | 273 +++++++++++++
hw/i2c/Makefile.objs | 1 +
hw/i2c/imx_i2c.c | 361 ++++++++++++++++++
hw/i2c/imx_i2c_regs.h | 63 +++
hw/net/Makefile.objs | 1 +
hw/net/imx_fec.c | 820 ++++++++++++++++++++++++++++++++++++++++
include/hw/arm/imx.h | 1 +
tests/Makefile | 3 +
tests/ds1338-test.c | 75 ++++
tests/libqos/i2c-imx.c | 209 ++++++++++
tests/libqos/i2c.h | 3 +
13 files changed, 1814 insertions(+)
create mode 100644 hw/arm/imx25_3ds.c
create mode 100644 hw/i2c/imx_i2c.c
create mode 100644 hw/i2c/imx_i2c_regs.h
create mode 100644 hw/net/imx_fec.c
create mode 100644 tests/ds1338-test.c
create mode 100644 tests/libqos/i2c-imx.c
--
2.1.4
^ permalink raw reply [flat|nested] 7+ messages in thread
* [Qemu-devel] [PATCH v7 1/4] i.MX: Add FEC Ethernet Emulator.
2015-06-22 19:06 [Qemu-devel] [PATCH v7 0/4] i.MX: Add i.MX25 support through the 3DS evaluation board Jean-Christophe Dubois
@ 2015-06-22 19:06 ` Jean-Christophe Dubois
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 2/4] i.MX: Add I2C contoller emulator Jean-Christophe Dubois
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Jean-Christophe Dubois @ 2015-06-22 19:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Jean-Christophe Dubois
This is based on the mcf_fec.c FEC implementation for ColdFire.
* a generic phy was added (borrowed from lan9118).
* The buffer management is also modified as buffers are
slightly different between coldfire and i.MX.
Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>
---
Changes since v1:
* none
Changes since v2:
* use QOM cast
* reworked debug printf
* use CamelCase for state type
* warn with qemu_log_mask(LOG_GUEST_ERROR) or qemu_log_mask(LOG_UNIMP)
* move to dma_memory_read/write API
* rework interrupt handling
* use qemu_flush_queued_packets() in rx_enable()
Changes since v3:
* use realise for device initialization
* More QOM cast
* reworked debug printf some more
* standardise GPL header
* use CamelCase for buffer descriptor type
Changes since v4:
* none
Changes since v5:
* replace hw_error() with qemu_log_mask(LOG_GUEST_ERROR, ...)
* remove reformating of imx.h header file.
* remove unnecessary spaces.
Changes since v6:
* port to new memory API
default-configs/arm-softmmu.mak | 1 +
hw/net/Makefile.objs | 1 +
hw/net/imx_fec.c | 820 ++++++++++++++++++++++++++++++++++++++++
include/hw/arm/imx.h | 1 +
4 files changed, 823 insertions(+)
create mode 100644 hw/net/imx_fec.c
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 74f1db3..d21ff7b 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -28,6 +28,7 @@ CONFIG_SSI_M25P80=y
CONFIG_LAN9118=y
CONFIG_SMC91C111=y
CONFIG_ALLWINNER_EMAC=y
+CONFIG_IMX_FEC=y
CONFIG_DS1338=y
CONFIG_PFLASH_CFI01=y
CONFIG_PFLASH_CFI02=y
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
index 9880173..64d0449 100644
--- a/hw/net/Makefile.objs
+++ b/hw/net/Makefile.objs
@@ -19,6 +19,7 @@ common-obj-$(CONFIG_XGMAC) += xgmac.o
common-obj-$(CONFIG_MIPSNET) += mipsnet.o
common-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o
common-obj-$(CONFIG_ALLWINNER_EMAC) += allwinner_emac.o
+common-obj-$(CONFIG_IMX_FEC) += imx_fec.o
common-obj-$(CONFIG_CADENCE) += cadence_gem.o
common-obj-$(CONFIG_STELLARIS_ENET) += stellaris_enet.o
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
new file mode 100644
index 0000000..8649bb0
--- /dev/null
+++ b/hw/net/imx_fec.c
@@ -0,0 +1,820 @@
+/*
+ * i.MX Fast Ethernet Controller emulation.
+ *
+ * Copyright (c) 2013 Jean-Christophe Dubois.
+ *
+ * Based on Coldfire Fast Ethernet Controller emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysemu/dma.h"
+#include "hw/sysbus.h"
+#include "net/net.h"
+#include "hw/devices.h"
+#include "exec/address-spaces.h"
+
+/* For crc32 */
+#include <zlib.h>
+
+#include "hw/arm/imx.h"
+
+#ifndef IMX_FEC_DEBUG
+#define IMX_FEC_DEBUG 0
+#endif
+
+#ifndef IMX_PHY_DEBUG
+#define IMX_PHY_DEBUG 0
+#endif
+
+#if IMX_FEC_DEBUG
+#define FEC_PRINTF(fmt, ...) \
+ do { fprintf(stderr, "%s[%s]: " fmt , TYPE_IMX_FEC, __func__, \
+ ## __VA_ARGS__); \
+ } while (0)
+#else
+#define FEC_PRINTF(fmt, ...) do {} while (0)
+#endif
+
+#if IMX_PHY_DEBUG
+#define PHY_PRINTF(fmt, ...) \
+ do { fprintf(stderr, "%s.phy[%s]: " fmt , TYPE_IMX_FEC, __func__, \
+ ## __VA_ARGS__); \
+ } while (0)
+#else
+#define PHY_PRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define TYPE_IMX_FEC "imx.fec"
+#define IMX_FEC(obj) \
+ OBJECT_CHECK(IMXFECState, (obj), TYPE_IMX_FEC)
+
+#define FEC_MAX_FRAME_SIZE 2032
+
+typedef struct {
+ SysBusDevice parent_obj;
+
+ NICState *nic;
+ NICConf conf;
+ qemu_irq irq;
+ MemoryRegion iomem;
+
+ uint32_t irq_state;
+ uint32_t eir;
+ uint32_t eimr;
+ uint32_t rx_enabled;
+ uint32_t rx_descriptor;
+ uint32_t tx_descriptor;
+ uint32_t ecr;
+ uint32_t mmfr;
+ uint32_t mscr;
+ uint32_t mibc;
+ uint32_t rcr;
+ uint32_t tcr;
+ uint32_t tfwr;
+ uint32_t frsr;
+ uint32_t erdsr;
+ uint32_t etdsr;
+ uint32_t emrbr;
+ uint32_t miigsk_cfgr;
+ uint32_t miigsk_enr;
+
+ uint32_t phy_status;
+ uint32_t phy_control;
+ uint32_t phy_advertise;
+ uint32_t phy_int;
+ uint32_t phy_int_mask;
+} IMXFECState;
+
+static const VMStateDescription vmstate_imx_fec = {
+ .name = TYPE_IMX_FEC,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(irq_state, IMXFECState),
+ VMSTATE_UINT32(eir, IMXFECState),
+ VMSTATE_UINT32(eimr, IMXFECState),
+ VMSTATE_UINT32(rx_enabled, IMXFECState),
+ VMSTATE_UINT32(rx_descriptor, IMXFECState),
+ VMSTATE_UINT32(tx_descriptor, IMXFECState),
+ VMSTATE_UINT32(ecr, IMXFECState),
+ VMSTATE_UINT32(mmfr, IMXFECState),
+ VMSTATE_UINT32(mscr, IMXFECState),
+ VMSTATE_UINT32(mibc, IMXFECState),
+ VMSTATE_UINT32(rcr, IMXFECState),
+ VMSTATE_UINT32(tcr, IMXFECState),
+ VMSTATE_UINT32(tfwr, IMXFECState),
+ VMSTATE_UINT32(frsr, IMXFECState),
+ VMSTATE_UINT32(erdsr, IMXFECState),
+ VMSTATE_UINT32(etdsr, IMXFECState),
+ VMSTATE_UINT32(emrbr, IMXFECState),
+ VMSTATE_UINT32(miigsk_cfgr, IMXFECState),
+ VMSTATE_UINT32(miigsk_enr, IMXFECState),
+
+ VMSTATE_UINT32(phy_status, IMXFECState),
+ VMSTATE_UINT32(phy_control, IMXFECState),
+ VMSTATE_UINT32(phy_advertise, IMXFECState),
+ VMSTATE_UINT32(phy_int, IMXFECState),
+ VMSTATE_UINT32(phy_int_mask, IMXFECState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+#define PHY_INT_ENERGYON (1 << 7)
+#define PHY_INT_AUTONEG_COMPLETE (1 << 6)
+#define PHY_INT_FAULT (1 << 5)
+#define PHY_INT_DOWN (1 << 4)
+#define PHY_INT_AUTONEG_LP (1 << 3)
+#define PHY_INT_PARFAULT (1 << 2)
+#define PHY_INT_AUTONEG_PAGE (1 << 1)
+
+static void imx_fec_update(IMXFECState *s);
+
+/*
+ * The MII phy could raise a GPIO to the processor which in turn
+ * could be handled as an interrpt by the OS.
+ * For now we don't handle any GPIO/interrupt line, so the OS will
+ * have to poll for the PHY status.
+ */
+static void phy_update_irq(IMXFECState *s)
+{
+ imx_fec_update(s);
+}
+
+static void phy_update_link(IMXFECState *s)
+{
+ /* Autonegotiation status mirrors link status. */
+ if (qemu_get_queue(s->nic)->link_down) {
+ PHY_PRINTF("link is down\n");
+ s->phy_status &= ~0x0024;
+ s->phy_int |= PHY_INT_DOWN;
+ } else {
+ PHY_PRINTF("link is up\n");
+ s->phy_status |= 0x0024;
+ s->phy_int |= PHY_INT_ENERGYON;
+ s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
+ }
+ phy_update_irq(s);
+}
+
+static void imx_fec_set_link(NetClientState *nc)
+{
+ phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc)));
+}
+
+static void phy_reset(IMXFECState *s)
+{
+ s->phy_status = 0x7809;
+ s->phy_control = 0x3000;
+ s->phy_advertise = 0x01e1;
+ s->phy_int_mask = 0;
+ s->phy_int = 0;
+ phy_update_link(s);
+}
+
+static uint32_t do_phy_read(IMXFECState *s, int reg)
+{
+ uint32_t val;
+
+ if (reg > 31) {
+ /* we only advertise one phy */
+ return 0;
+ }
+
+ switch (reg) {
+ case 0: /* Basic Control */
+ val = s->phy_control;
+ break;
+ case 1: /* Basic Status */
+ val = s->phy_status;
+ break;
+ case 2: /* ID1 */
+ val = 0x0007;
+ break;
+ case 3: /* ID2 */
+ val = 0xc0d1;
+ break;
+ case 4: /* Auto-neg advertisement */
+ val = s->phy_advertise;
+ break;
+ case 5: /* Auto-neg Link Partner Ability */
+ val = 0x0f71;
+ break;
+ case 6: /* Auto-neg Expansion */
+ val = 1;
+ break;
+ case 29: /* Interrupt source. */
+ val = s->phy_int;
+ s->phy_int = 0;
+ phy_update_irq(s);
+ break;
+ case 30: /* Interrupt mask */
+ val = s->phy_int_mask;
+ break;
+ case 17:
+ case 18:
+ case 27:
+ case 31:
+ qemu_log_mask(LOG_UNIMP, "%s.phy[%s]: reg %d not implemented\n",
+ TYPE_IMX_FEC, __func__, reg);
+ val = 0;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
+ TYPE_IMX_FEC, __func__, reg);
+ val = 0;
+ break;
+ }
+
+ PHY_PRINTF("read 0x%04x @ %d\n", val, reg);
+
+ return val;
+}
+
+static void do_phy_write(IMXFECState *s, int reg, uint32_t val)
+{
+ PHY_PRINTF("write 0x%04x @ %d\n", val, reg);
+
+ if (reg > 31) {
+ /* we only advertise one phy */
+ return;
+ }
+
+ switch (reg) {
+ case 0: /* Basic Control */
+ if (val & 0x8000) {
+ phy_reset(s);
+ } else {
+ s->phy_control = val & 0x7980;
+ /* Complete autonegotiation immediately. */
+ if (val & 0x1000) {
+ s->phy_status |= 0x0020;
+ }
+ }
+ break;
+ case 4: /* Auto-neg advertisement */
+ s->phy_advertise = (val & 0x2d7f) | 0x80;
+ break;
+ case 30: /* Interrupt mask */
+ s->phy_int_mask = val & 0xff;
+ phy_update_irq(s);
+ break;
+ case 17:
+ case 18:
+ case 27:
+ case 31:
+ qemu_log_mask(LOG_UNIMP, "%s.phy[%s]: reg %d not implemented\n",
+ TYPE_IMX_FEC, __func__, reg);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
+ TYPE_IMX_FEC, __func__, reg);
+ break;
+ }
+}
+
+#define FEC_INT_HB (1 << 31)
+#define FEC_INT_BABR (1 << 30)
+#define FEC_INT_BABT (1 << 29)
+#define FEC_INT_GRA (1 << 28)
+#define FEC_INT_TXF (1 << 27)
+#define FEC_INT_TXB (1 << 26)
+#define FEC_INT_RXF (1 << 25)
+#define FEC_INT_RXB (1 << 24)
+#define FEC_INT_MII (1 << 23)
+#define FEC_INT_EBERR (1 << 22)
+#define FEC_INT_LC (1 << 21)
+#define FEC_INT_RL (1 << 20)
+#define FEC_INT_UN (1 << 19)
+
+#define FEC_EN 2
+#define FEC_RESET 1
+
+/* Buffer Descriptor. */
+typedef struct {
+ uint16_t length;
+ uint16_t flags;
+ uint32_t data;
+} IMXFECBufDesc;
+
+#define FEC_BD_R (1 << 15)
+#define FEC_BD_E (1 << 15)
+#define FEC_BD_O1 (1 << 14)
+#define FEC_BD_W (1 << 13)
+#define FEC_BD_O2 (1 << 12)
+#define FEC_BD_L (1 << 11)
+#define FEC_BD_TC (1 << 10)
+#define FEC_BD_ABC (1 << 9)
+#define FEC_BD_M (1 << 8)
+#define FEC_BD_BC (1 << 7)
+#define FEC_BD_MC (1 << 6)
+#define FEC_BD_LG (1 << 5)
+#define FEC_BD_NO (1 << 4)
+#define FEC_BD_CR (1 << 2)
+#define FEC_BD_OV (1 << 1)
+#define FEC_BD_TR (1 << 0)
+
+static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr)
+{
+ dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd));
+}
+
+static void imx_fec_write_bd(IMXFECBufDesc *bd, dma_addr_t addr)
+{
+ dma_memory_write(&address_space_memory, addr, bd, sizeof(*bd));
+}
+
+static void imx_fec_update(IMXFECState *s)
+{
+ uint32_t active;
+ uint32_t changed;
+
+ active = s->eir & s->eimr;
+ changed = active ^ s->irq_state;
+ if (changed) {
+ qemu_set_irq(s->irq, active);
+ }
+ s->irq_state = active;
+}
+
+static void imx_fec_do_tx(IMXFECState *s)
+{
+ int frame_size = 0;
+ uint8_t frame[FEC_MAX_FRAME_SIZE];
+ uint8_t *ptr = frame;
+ uint32_t addr = s->tx_descriptor;
+
+ while (1) {
+ IMXFECBufDesc bd;
+ int len;
+
+ imx_fec_read_bd(&bd, addr);
+ FEC_PRINTF("tx_bd %x flags %04x len %d data %08x\n",
+ addr, bd.flags, bd.length, bd.data);
+ if ((bd.flags & FEC_BD_R) == 0) {
+ /* Run out of descriptors to transmit. */
+ break;
+ }
+ len = bd.length;
+ if (frame_size + len > FEC_MAX_FRAME_SIZE) {
+ len = FEC_MAX_FRAME_SIZE - frame_size;
+ s->eir |= FEC_INT_BABT;
+ }
+ dma_memory_read(&address_space_memory, bd.data, ptr, len);
+ ptr += len;
+ frame_size += len;
+ if (bd.flags & FEC_BD_L) {
+ /* Last buffer in frame. */
+ qemu_send_packet(qemu_get_queue(s->nic), frame, len);
+ ptr = frame;
+ frame_size = 0;
+ s->eir |= FEC_INT_TXF;
+ }
+ s->eir |= FEC_INT_TXB;
+ bd.flags &= ~FEC_BD_R;
+ /* Write back the modified descriptor. */
+ imx_fec_write_bd(&bd, addr);
+ /* Advance to the next descriptor. */
+ if ((bd.flags & FEC_BD_W) != 0) {
+ addr = s->etdsr;
+ } else {
+ addr += 8;
+ }
+ }
+
+ s->tx_descriptor = addr;
+
+ imx_fec_update(s);
+}
+
+static void imx_fec_enable_rx(IMXFECState *s)
+{
+ IMXFECBufDesc bd;
+ uint32_t tmp;
+
+ imx_fec_read_bd(&bd, s->rx_descriptor);
+
+ tmp = ((bd.flags & FEC_BD_E) != 0);
+
+ if (!tmp) {
+ FEC_PRINTF("RX buffer full\n");
+ } else if (!s->rx_enabled) {
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
+ }
+
+ s->rx_enabled = tmp;
+}
+
+static void imx_fec_reset(DeviceState *d)
+{
+ IMXFECState *s = IMX_FEC(d);
+
+ /* Reset the FEC */
+ s->eir = 0;
+ s->eimr = 0;
+ s->rx_enabled = 0;
+ s->ecr = 0;
+ s->mscr = 0;
+ s->mibc = 0xc0000000;
+ s->rcr = 0x05ee0001;
+ s->tcr = 0;
+ s->tfwr = 0;
+ s->frsr = 0x500;
+ s->miigsk_cfgr = 0;
+ s->miigsk_enr = 0x6;
+
+ /* We also reset the PHY */
+ phy_reset(s);
+}
+
+static uint64_t imx_fec_read(void *opaque, hwaddr addr, unsigned size)
+{
+ IMXFECState *s = IMX_FEC(opaque);
+
+ FEC_PRINTF("reading from @ 0x%03x\n", (int)addr);
+
+ switch (addr & 0x3ff) {
+ case 0x004:
+ return s->eir;
+ case 0x008:
+ return s->eimr;
+ case 0x010:
+ return s->rx_enabled ? (1 << 24) : 0; /* RDAR */
+ case 0x014:
+ return 0; /* TDAR */
+ case 0x024:
+ return s->ecr;
+ case 0x040:
+ return s->mmfr;
+ case 0x044:
+ return s->mscr;
+ case 0x064:
+ return s->mibc; /* MIBC */
+ case 0x084:
+ return s->rcr;
+ case 0x0c4:
+ return s->tcr;
+ case 0x0e4: /* PALR */
+ return (s->conf.macaddr.a[0] << 24)
+ | (s->conf.macaddr.a[1] << 16)
+ | (s->conf.macaddr.a[2] << 8)
+ | s->conf.macaddr.a[3];
+ break;
+ case 0x0e8: /* PAUR */
+ return (s->conf.macaddr.a[4] << 24)
+ | (s->conf.macaddr.a[5] << 16)
+ | 0x8808;
+ case 0x0ec:
+ return 0x10000; /* OPD */
+ case 0x118:
+ return 0;
+ case 0x11c:
+ return 0;
+ case 0x120:
+ return 0;
+ case 0x124:
+ return 0;
+ case 0x144:
+ return s->tfwr;
+ case 0x14c:
+ return 0x600;
+ case 0x150:
+ return s->frsr;
+ case 0x180:
+ return s->erdsr;
+ case 0x184:
+ return s->etdsr;
+ case 0x188:
+ return s->emrbr;
+ case 0x300:
+ return s->miigsk_cfgr;
+ case 0x308:
+ return s->miigsk_enr;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
+ TYPE_IMX_FEC, __func__, (int)addr);
+ return 0;
+ }
+}
+
+static void imx_fec_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ IMXFECState *s = IMX_FEC(opaque);
+
+ FEC_PRINTF("writing 0x%08x @ 0x%03x\n", (int)value, (int)addr);
+
+ switch (addr & 0x3ff) {
+ case 0x004: /* EIR */
+ s->eir &= ~value;
+ break;
+ case 0x008: /* EIMR */
+ s->eimr = value;
+ break;
+ case 0x010: /* RDAR */
+ if ((s->ecr & FEC_EN) && !s->rx_enabled) {
+ imx_fec_enable_rx(s);
+ }
+ break;
+ case 0x014: /* TDAR */
+ if (s->ecr & FEC_EN) {
+ imx_fec_do_tx(s);
+ }
+ break;
+ case 0x024: /* ECR */
+ s->ecr = value;
+ if (value & FEC_RESET) {
+ imx_fec_reset(DEVICE(s));
+ }
+ if ((s->ecr & FEC_EN) == 0) {
+ s->rx_enabled = 0;
+ }
+ break;
+ case 0x040: /* MMFR */
+ /* store the value */
+ s->mmfr = value;
+ if (extract32(value, 28, 1)) {
+ do_phy_write(s, extract32(value, 18, 9), extract32(value, 0, 16));
+ } else {
+ s->mmfr = do_phy_read(s, extract32(value, 18, 9));
+ }
+ /* raise the interrupt as the PHY operation is done */
+ s->eir |= FEC_INT_MII;
+ break;
+ case 0x044: /* MSCR */
+ s->mscr = value & 0xfe;
+ break;
+ case 0x064: /* MIBC */
+ /* TODO: Implement MIB. */
+ s->mibc = (value & 0x80000000) ? 0xc0000000 : 0;
+ break;
+ case 0x084: /* RCR */
+ s->rcr = value & 0x07ff003f;
+ /* TODO: Implement LOOP mode. */
+ break;
+ case 0x0c4: /* TCR */
+ /* We transmit immediately, so raise GRA immediately. */
+ s->tcr = value;
+ if (value & 1) {
+ s->eir |= FEC_INT_GRA;
+ }
+ break;
+ case 0x0e4: /* PALR */
+ s->conf.macaddr.a[0] = value >> 24;
+ s->conf.macaddr.a[1] = value >> 16;
+ s->conf.macaddr.a[2] = value >> 8;
+ s->conf.macaddr.a[3] = value;
+ break;
+ case 0x0e8: /* PAUR */
+ s->conf.macaddr.a[4] = value >> 24;
+ s->conf.macaddr.a[5] = value >> 16;
+ break;
+ case 0x0ec: /* OPDR */
+ break;
+ case 0x118: /* IAUR */
+ case 0x11c: /* IALR */
+ case 0x120: /* GAUR */
+ case 0x124: /* GALR */
+ /* TODO: implement MAC hash filtering. */
+ break;
+ case 0x144: /* TFWR */
+ s->tfwr = value & 3;
+ break;
+ case 0x14c: /* FRBR */
+ /* FRBR writes ignored. */
+ break;
+ case 0x150: /* FRSR */
+ s->frsr = (value & 0x3fc) | 0x400;
+ break;
+ case 0x180: /* ERDSR */
+ s->erdsr = value & ~3;
+ s->rx_descriptor = s->erdsr;
+ break;
+ case 0x184: /* ETDSR */
+ s->etdsr = value & ~3;
+ s->tx_descriptor = s->etdsr;
+ break;
+ case 0x188: /* EMRBR */
+ s->emrbr = value & 0x7f0;
+ break;
+ case 0x300: /* MIIGSK_CFGR */
+ s->miigsk_cfgr = value & 0x53;
+ break;
+ case 0x308: /* MIIGSK_ENR */
+ s->miigsk_enr = (value & 0x2) ? 0x6 : 0;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
+ TYPE_IMX_FEC, __func__, (int)addr);
+ break;
+ }
+
+ imx_fec_update(s);
+}
+
+static int imx_fec_can_receive(NetClientState *nc)
+{
+ IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
+
+ return s->rx_enabled;
+}
+
+static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf,
+ size_t len)
+{
+ IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
+ IMXFECBufDesc bd;
+ uint32_t flags = 0;
+ uint32_t addr;
+ uint32_t crc;
+ uint32_t buf_addr;
+ uint8_t *crc_ptr;
+ unsigned int buf_len;
+ size_t size = len;
+
+ FEC_PRINTF("len %d\n", (int)size);
+
+ if (!s->rx_enabled) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Unexpected packet\n",
+ TYPE_IMX_FEC, __func__);
+ return 0;
+ }
+
+ /* 4 bytes for the CRC. */
+ size += 4;
+ crc = cpu_to_be32(crc32(~0, buf, size));
+ crc_ptr = (uint8_t *) &crc;
+
+ /* Huge frames are truncted. */
+ if (size > FEC_MAX_FRAME_SIZE) {
+ size = FEC_MAX_FRAME_SIZE;
+ flags |= FEC_BD_TR | FEC_BD_LG;
+ }
+
+ /* Frames larger than the user limit just set error flags. */
+ if (size > (s->rcr >> 16)) {
+ flags |= FEC_BD_LG;
+ }
+
+ addr = s->rx_descriptor;
+ while (size > 0) {
+ imx_fec_read_bd(&bd, addr);
+ if ((bd.flags & FEC_BD_E) == 0) {
+ /* No descriptors available. Bail out. */
+ /*
+ * FIXME: This is wrong. We should probably either
+ * save the remainder for when more RX buffers are
+ * available, or flag an error.
+ */
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Lost end of frame\n",
+ TYPE_IMX_FEC, __func__);
+ break;
+ }
+ buf_len = (size <= s->emrbr) ? size : s->emrbr;
+ bd.length = buf_len;
+ size -= buf_len;
+ FEC_PRINTF("rx_bd %x length %d\n", addr, bd.length);
+ /* The last 4 bytes are the CRC. */
+ if (size < 4) {
+ buf_len += size - 4;
+ }
+ buf_addr = bd.data;
+ dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
+ buf += buf_len;
+ if (size < 4) {
+ dma_memory_write(&address_space_memory, buf_addr + buf_len,
+ crc_ptr, 4 - size);
+ crc_ptr += 4 - size;
+ }
+ bd.flags &= ~FEC_BD_E;
+ if (size == 0) {
+ /* Last buffer in frame. */
+ bd.flags |= flags | FEC_BD_L;
+ FEC_PRINTF("rx frame flags %04x\n", bd.flags);
+ s->eir |= FEC_INT_RXF;
+ } else {
+ s->eir |= FEC_INT_RXB;
+ }
+ imx_fec_write_bd(&bd, addr);
+ /* Advance to the next descriptor. */
+ if ((bd.flags & FEC_BD_W) != 0) {
+ addr = s->erdsr;
+ } else {
+ addr += 8;
+ }
+ }
+ s->rx_descriptor = addr;
+ imx_fec_enable_rx(s);
+ imx_fec_update(s);
+ return len;
+}
+
+static const MemoryRegionOps imx_fec_ops = {
+ .read = imx_fec_read,
+ .write = imx_fec_write,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void imx_fec_cleanup(NetClientState *nc)
+{
+ IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
+
+ s->nic = NULL;
+}
+
+static NetClientInfo net_imx_fec_info = {
+ .type = NET_CLIENT_OPTIONS_KIND_NIC,
+ .size = sizeof(NICState),
+ .can_receive = imx_fec_can_receive,
+ .receive = imx_fec_receive,
+ .cleanup = imx_fec_cleanup,
+ .link_status_changed = imx_fec_set_link,
+};
+
+
+static void imx_fec_realize(DeviceState *dev, Error **errp)
+{
+ IMXFECState *s = IMX_FEC(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ memory_region_init_io(&s->iomem, OBJECT(dev), &imx_fec_ops, s,
+ TYPE_IMX_FEC, 0x400);
+ sysbus_init_mmio(sbd, &s->iomem);
+ sysbus_init_irq(sbd, &s->irq);
+ qemu_macaddr_default_if_unset(&s->conf.macaddr);
+
+ s->conf.peers.ncs[0] = nd_table[0].netdev;
+
+ s->nic = qemu_new_nic(&net_imx_fec_info, &s->conf,
+ object_get_typename(OBJECT(dev)), DEVICE(dev)->id,
+ s);
+ qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+}
+
+static Property imx_fec_properties[] = {
+ DEFINE_NIC_PROPERTIES(IMXFECState, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void imx_fec_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_imx_fec;
+ dc->reset = imx_fec_reset;
+ dc->props = imx_fec_properties;
+ dc->realize = imx_fec_realize;
+}
+
+static const TypeInfo imx_fec_info = {
+ .name = TYPE_IMX_FEC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IMXFECState),
+ .class_init = imx_fec_class_init,
+};
+
+static void imx_fec_register_types(void)
+{
+ type_register_static(&imx_fec_info);
+}
+
+DeviceState *imx_fec_create(int nic, const hwaddr base, qemu_irq irq)
+{
+ NICInfo *nd;
+ DeviceState *dev;
+ SysBusDevice *sbd;
+
+ if (nic >= MAX_NICS) {
+ hw_error("Cannot assign nic %d: QEMU supports only %d ports\n",
+ nic, MAX_NICS);
+ }
+
+ nd = &nd_table[nic];
+
+ qemu_check_nic_model(nd, TYPE_IMX_FEC);
+ dev = qdev_create(NULL, TYPE_IMX_FEC);
+ qdev_set_nic_properties(dev, nd);
+ qdev_init_nofail(dev);
+ sbd = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(sbd, 0, base);
+ sysbus_connect_irq(sbd, 0, irq);
+
+ return dev;
+};
+
+type_init(imx_fec_register_types)
diff --git a/include/hw/arm/imx.h b/include/hw/arm/imx.h
index ea9e093..558ba60 100644
--- a/include/hw/arm/imx.h
+++ b/include/hw/arm/imx.h
@@ -30,5 +30,6 @@ void imx_timerg_create(const hwaddr addr,
qemu_irq irq,
DeviceState *ccm);
+DeviceState *imx_fec_create(int nic, const hwaddr base, qemu_irq irq);
#endif /* IMX_H */
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [Qemu-devel] [PATCH v7 2/4] i.MX: Add I2C contoller emulator
2015-06-22 19:06 [Qemu-devel] [PATCH v7 0/4] i.MX: Add i.MX25 support through the 3DS evaluation board Jean-Christophe Dubois
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 1/4] i.MX: Add FEC Ethernet Emulator Jean-Christophe Dubois
@ 2015-06-22 19:06 ` Jean-Christophe Dubois
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 3/4] i.MX: Add i.MX25 3DS evaluation board support Jean-Christophe Dubois
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 4/4] i.MX: Add qtest support for I2C device emulator Jean-Christophe Dubois
3 siblings, 0 replies; 7+ messages in thread
From: Jean-Christophe Dubois @ 2015-06-22 19:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Jean-Christophe Dubois
The slave mode is not implemented.
Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>
---
Changes since v1:
* use QOM cast
* run checkpatch on code
* added restrictin on MemoryRegionOps
* use DeviceClass::realise as init function
Changes since v2:
* use CamelCase for state type
* use extrac32() for bit manipilation.
* improve QOM cast
* separate regs definition in its own file (to be reused by qtest)
Changes since v3:
* More QOM cast.
* Rework GPL headers
* Add a constructor helper.
* fix reset()
* rework debug printf
Changes since v4:
* remove the constructor helper
Changes since v5:
* replace hw_error() with qemu_log_mask(LOG_GUEST_ERROR, ...)
* add qemu_log_mask(LOG_UNIMP, ...) for slave mode.
* small comment fixes.
Changes since v6:
* port to new memory API
default-configs/arm-softmmu.mak | 2 +
hw/i2c/Makefile.objs | 1 +
hw/i2c/imx_i2c.c | 361 ++++++++++++++++++++++++++++++++++++++++
hw/i2c/imx_i2c_regs.h | 63 +++++++
4 files changed, 427 insertions(+)
create mode 100644 hw/i2c/imx_i2c.c
create mode 100644 hw/i2c/imx_i2c_regs.h
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index d21ff7b..c6f509d 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -99,6 +99,8 @@ CONFIG_ALLWINNER_A10_PIT=y
CONFIG_ALLWINNER_A10_PIC=y
CONFIG_ALLWINNER_A10=y
+CONFIG_IMX_I2C=y
+
CONFIG_XIO3130=y
CONFIG_IOH3420=y
CONFIG_I82801B11=y
diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
index 0f13060..aeb8f38 100644
--- a/hw/i2c/Makefile.objs
+++ b/hw/i2c/Makefile.objs
@@ -4,4 +4,5 @@ common-obj-$(CONFIG_ACPI_X86) += smbus_ich9.o
common-obj-$(CONFIG_APM) += pm_smbus.o
common-obj-$(CONFIG_BITBANG_I2C) += bitbang_i2c.o
common-obj-$(CONFIG_EXYNOS4) += exynos4210_i2c.o
+common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o
obj-$(CONFIG_OMAP) += omap_i2c.o
diff --git a/hw/i2c/imx_i2c.c b/hw/i2c/imx_i2c.c
new file mode 100644
index 0000000..41ac4fd
--- /dev/null
+++ b/hw/i2c/imx_i2c.c
@@ -0,0 +1,361 @@
+/*
+ * i.MX I2C Bus Serial Interface Emulation
+ *
+ * Copyright (C) 2013 Jean-Christophe Dubois.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "hw/sysbus.h"
+#include "hw/i2c/i2c.h"
+#include "hw/i2c/imx_i2c_regs.h"
+
+#ifndef IMX_I2C_DEBUG
+#define IMX_I2C_DEBUG 0
+#endif
+
+#define TYPE_IMX_I2C "imx.i2c"
+#define IMX_I2C(obj) \
+ OBJECT_CHECK(IMXI2CState, (obj), TYPE_IMX_I2C)
+
+#if IMX_I2C_DEBUG
+#define DPRINT(fmt, args...) \
+ do { fprintf(stderr, "%s: "fmt, __func__, ## args); } while (0)
+
+static const char *imx_i2c_get_regname(unsigned offset)
+{
+ switch (offset) {
+ case IADR_ADDR:
+ return "IADR";
+ case IFDR_ADDR:
+ return "IFDR";
+ case I2CR_ADDR:
+ return "I2CR";
+ case I2SR_ADDR:
+ return "I2SR";
+ case I2DR_ADDR:
+ return "I2DR";
+ default:
+ return "[?]";
+ }
+}
+#else
+#define DPRINT(fmt, args...) do { } while (0)
+#endif
+
+typedef struct IMXI2CState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion iomem;
+ I2CBus *bus;
+ qemu_irq irq;
+
+ uint16_t address;
+
+ uint16_t iadr;
+ uint16_t ifdr;
+ uint16_t i2cr;
+ uint16_t i2sr;
+ uint16_t i2dr_read;
+ uint16_t i2dr_write;
+} IMXI2CState;
+
+static inline bool imx_i2c_is_enabled(IMXI2CState *s)
+{
+ return s->i2cr & I2CR_IEN;
+}
+
+static inline bool imx_i2c_interrupt_is_enabled(IMXI2CState *s)
+{
+ return s->i2cr & I2CR_IIEN;
+}
+
+static inline bool imx_i2c_is_master(IMXI2CState *s)
+{
+ return s->i2cr & I2CR_MSTA;
+}
+
+static inline bool imx_i2c_direction_is_tx(IMXI2CState *s)
+{
+ return s->i2cr & I2CR_MTX;
+}
+
+static void imx_i2c_reset(DeviceState *dev)
+{
+ IMXI2CState *s = IMX_I2C(dev);
+
+ if (s->address != ADDR_RESET) {
+ i2c_end_transfer(s->bus);
+ }
+
+ s->address = ADDR_RESET;
+ s->iadr = IADR_RESET;
+ s->ifdr = IFDR_RESET;
+ s->i2cr = I2CR_RESET;
+ s->i2sr = I2SR_RESET;
+ s->i2dr_read = I2DR_RESET;
+ s->i2dr_write = I2DR_RESET;
+}
+
+static inline void imx_i2c_raise_interrupt(IMXI2CState *s)
+{
+ /*
+ * raise an interrupt if the device is enabled and it is configured
+ * to generate some interrupts.
+ */
+ if (imx_i2c_is_enabled(s) && imx_i2c_interrupt_is_enabled(s)) {
+ s->i2sr |= I2SR_IIF;
+ qemu_irq_raise(s->irq);
+ }
+}
+
+static uint64_t imx_i2c_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ uint16_t value;
+ IMXI2CState *s = IMX_I2C(opaque);
+
+ switch (offset) {
+ case IADR_ADDR:
+ value = s->iadr;
+ break;
+ case IFDR_ADDR:
+ value = s->ifdr;
+ break;
+ case I2CR_ADDR:
+ value = s->i2cr;
+ break;
+ case I2SR_ADDR:
+ value = s->i2sr;
+ break;
+ case I2DR_ADDR:
+ value = s->i2dr_read;
+
+ if (imx_i2c_is_master(s)) { /* master mode */
+ int ret = 0xff;
+
+ if (s->address == ADDR_RESET) {
+ /* something is wrong as the address is not set */
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Trying to read "
+ "without specifying the slave address\n",
+ TYPE_IMX_I2C, __func__);
+ } else if (s->i2cr & I2CR_MTX) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Trying to read "
+ "but MTX is set\n", TYPE_IMX_I2C, __func__);
+ } else {
+ /* get the next byte */
+ ret = i2c_recv(s->bus);
+
+ if (ret >= 0) {
+ imx_i2c_raise_interrupt(s);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: read failed "
+ "for device 0x%02x\n", TYPE_IMX_I2C,
+ __func__, s->address);
+ ret = 0xff;
+ }
+ }
+
+ s->i2dr_read = ret;
+ } else {
+ qemu_log_mask(LOG_UNIMP, "%s[%s]: slave mode not implemented\n",
+ TYPE_IMX_I2C, __func__);
+ }
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
+ TYPE_IMX_I2C, __func__, s->address);
+ value = 0;
+ break;
+ }
+
+ DPRINT("read %s [0x%02x] -> 0x%02x\n", imx_i2c_get_regname(offset),
+ (unsigned int)offset, value);
+
+ return (uint64_t)value;
+}
+
+static void imx_i2c_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ IMXI2CState *s = IMX_I2C(opaque);
+
+ DPRINT("write %s [0x%02x] <- 0x%02x\n", imx_i2c_get_regname(offset),
+ (unsigned int)offset, (int)value);
+
+ value &= 0xff;
+
+ switch (offset) {
+ case IADR_ADDR:
+ s->iadr = value & IADR_MASK;
+ /* i2c_set_slave_address(s->bus, (uint8_t)s->iadr); */
+ break;
+ case IFDR_ADDR:
+ s->ifdr = value & IFDR_MASK;
+ break;
+ case I2CR_ADDR:
+ if (imx_i2c_is_enabled(s) && ((value & I2CR_IEN) == 0)) {
+ /* This is a soft reset. IADR is preserved during soft resets */
+ uint16_t iadr = s->iadr;
+ imx_i2c_reset(DEVICE(s));
+ s->iadr = iadr;
+ } else { /* normal write */
+ s->i2cr = value & I2CR_MASK;
+
+ if (imx_i2c_is_master(s)) { /* master mode */
+ /* set the bus to busy */
+ s->i2sr |= I2SR_IBB;
+ } else { /* slave mode */
+ /* bus is not busy anymore */
+ s->i2sr &= ~I2SR_IBB;
+
+ /*
+ * if we unset the master mode then it ends the ongoing
+ * transfer if any
+ */
+ if (s->address != ADDR_RESET) {
+ i2c_end_transfer(s->bus);
+ s->address = ADDR_RESET;
+ }
+ }
+
+ if (s->i2cr & I2CR_RSTA) { /* Restart */
+ /* if this is a restart then it ends the ongoing transfer */
+ if (s->address != ADDR_RESET) {
+ i2c_end_transfer(s->bus);
+ s->address = ADDR_RESET;
+ s->i2cr &= ~I2CR_RSTA;
+ }
+ }
+ }
+ break;
+ case I2SR_ADDR:
+ /*
+ * if the user writes 0 to IIF then lower the interrupt and
+ * reset the bit
+ */
+ if ((s->i2sr & I2SR_IIF) && !(value & I2SR_IIF)) {
+ s->i2sr &= ~I2SR_IIF;
+ qemu_irq_lower(s->irq);
+ }
+
+ /*
+ * if the user writes 0 to IAL, reset the bit
+ */
+ if ((s->i2sr & I2SR_IAL) && !(value & I2SR_IAL)) {
+ s->i2sr &= ~I2SR_IAL;
+ }
+
+ break;
+ case I2DR_ADDR:
+ /* if the device is not enabled, nothing to do */
+ if (!imx_i2c_is_enabled(s)) {
+ break;
+ }
+
+ s->i2dr_write = value & I2DR_MASK;
+
+ if (imx_i2c_is_master(s)) { /* master mode */
+ /* If this is the first write cycle then it is the slave addr */
+ if (s->address == ADDR_RESET) {
+ if (i2c_start_transfer(s->bus, extract32(s->i2dr_write, 1, 7),
+ extract32(s->i2dr_write, 0, 1))) {
+ /* if non zero is returned, the adress is not valid */
+ s->i2sr |= I2SR_RXAK;
+ } else {
+ s->address = s->i2dr_write;
+ s->i2sr &= ~I2SR_RXAK;
+ imx_i2c_raise_interrupt(s);
+ }
+ } else { /* This is a normal data write */
+ if (i2c_send(s->bus, s->i2dr_write)) {
+ /* if the target return non zero then end the transfer */
+ s->i2sr |= I2SR_RXAK;
+ s->address = ADDR_RESET;
+ i2c_end_transfer(s->bus);
+ } else {
+ s->i2sr &= ~I2SR_RXAK;
+ imx_i2c_raise_interrupt(s);
+ }
+ }
+ } else {
+ qemu_log_mask(LOG_UNIMP, "%s[%s]: slave mode not implemented\n",
+ TYPE_IMX_I2C, __func__);
+ }
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
+ TYPE_IMX_I2C, __func__, s->address);
+ break;
+ }
+}
+
+static const MemoryRegionOps imx_i2c_ops = {
+ .read = imx_i2c_read,
+ .write = imx_i2c_write,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 2,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription imx_i2c_vmstate = {
+ .name = TYPE_IMX_I2C,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16(address, IMXI2CState),
+ VMSTATE_UINT16(iadr, IMXI2CState),
+ VMSTATE_UINT16(ifdr, IMXI2CState),
+ VMSTATE_UINT16(i2cr, IMXI2CState),
+ VMSTATE_UINT16(i2sr, IMXI2CState),
+ VMSTATE_UINT16(i2dr_read, IMXI2CState),
+ VMSTATE_UINT16(i2dr_write, IMXI2CState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void imx_i2c_realize(DeviceState *dev, Error **errp)
+{
+ IMXI2CState *s = IMX_I2C(dev);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &imx_i2c_ops, s, TYPE_IMX_I2C,
+ IMX_I2C_MEM_SIZE);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
+ s->bus = i2c_init_bus(DEVICE(dev), "i2c");
+}
+
+static void imx_i2c_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &imx_i2c_vmstate;
+ dc->reset = imx_i2c_reset;
+ dc->realize = imx_i2c_realize;
+}
+
+static const TypeInfo imx_i2c_type_info = {
+ .name = TYPE_IMX_I2C,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IMXI2CState),
+ .class_init = imx_i2c_class_init,
+};
+
+static void imx_i2c_register_types(void)
+{
+ type_register_static(&imx_i2c_type_info);
+}
+
+type_init(imx_i2c_register_types)
diff --git a/hw/i2c/imx_i2c_regs.h b/hw/i2c/imx_i2c_regs.h
new file mode 100644
index 0000000..95c7cf5
--- /dev/null
+++ b/hw/i2c/imx_i2c_regs.h
@@ -0,0 +1,63 @@
+/*
+ * i.MX I2C Bus Serial Interface registers definition
+ *
+ * Copyright (C) 2013 Jean-Christophe Dubois.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __IMX_I2C_REGS_H_
+#define __IMX_I2C_REGS_H_
+
+#define IMX_I2C_MEM_SIZE 0x14
+
+/* i.MX I2C memory map */
+#define IADR_ADDR 0x00 /* address register */
+#define IFDR_ADDR 0x04 /* frequency divider register */
+#define I2CR_ADDR 0x08 /* control register */
+#define I2SR_ADDR 0x0c /* status register */
+#define I2DR_ADDR 0x10 /* data register */
+
+#define IADR_MASK 0xFE
+#define IADR_RESET 0
+
+#define IFDR_MASK 0x3F
+#define IFDR_RESET 0
+
+#define I2CR_IEN (1 << 7)
+#define I2CR_IIEN (1 << 6)
+#define I2CR_MSTA (1 << 5)
+#define I2CR_MTX (1 << 4)
+#define I2CR_TXAK (1 << 3)
+#define I2CR_RSTA (1 << 2)
+#define I2CR_MASK 0xFC
+#define I2CR_RESET 0
+
+#define I2SR_ICF (1 << 7)
+#define I2SR_IAAF (1 << 6)
+#define I2SR_IBB (1 << 5)
+#define I2SR_IAL (1 << 4)
+#define I2SR_SRW (1 << 2)
+#define I2SR_IIF (1 << 1)
+#define I2SR_RXAK (1 << 0)
+#define I2SR_MASK 0xE9
+#define I2SR_RESET 0x81
+
+#define I2DR_MASK 0xFF
+#define I2DR_RESET 0
+
+#define ADDR_RESET 0xFF00
+
+#endif /* __IMX_I2C_REGS_H_ */
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [Qemu-devel] [PATCH v7 3/4] i.MX: Add i.MX25 3DS evaluation board support
2015-06-22 19:06 [Qemu-devel] [PATCH v7 0/4] i.MX: Add i.MX25 support through the 3DS evaluation board Jean-Christophe Dubois
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 1/4] i.MX: Add FEC Ethernet Emulator Jean-Christophe Dubois
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 2/4] i.MX: Add I2C contoller emulator Jean-Christophe Dubois
@ 2015-06-22 19:06 ` Jean-Christophe Dubois
2015-06-24 5:07 ` Peter Crosthwaite
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 4/4] i.MX: Add qtest support for I2C device emulator Jean-Christophe Dubois
3 siblings, 1 reply; 7+ messages in thread
From: Jean-Christophe Dubois @ 2015-06-22 19:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Jean-Christophe Dubois
For now we support:
* timers (GPT and EPIT)
* serial ports
* ethernet (through the newly added FEC emulator)
* I2C (through the newly added I2C emulator)
Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
---
Changes since v1:
* Added a ds1338 I2C device for qtest purpose.
Changes since v2:
* none
Changes since v3:
* Rework GPL header
* use I2C constructor helper.
Changes since v4:
* use sysbus_create_simple() instead of I2C constructor helper
Changes since v5:
* Add ds1338 only for qtest mode.
* small comment fixes.
Changes since v6:
* Allow for more than 4 serial if suppoted by Qemu.
hw/arm/Makefile.objs | 1 +
hw/arm/imx25_3ds.c | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 274 insertions(+)
create mode 100644 hw/arm/imx25_3ds.c
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index cf346c1..3ecb8b1 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -5,6 +5,7 @@ obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
obj-$(CONFIG_ACPI) += virt-acpi-build.o
obj-y += netduino2.o
+obj-y += imx25_3ds.o
obj-y += sysbus-fdt.o
obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
diff --git a/hw/arm/imx25_3ds.c b/hw/arm/imx25_3ds.c
new file mode 100644
index 0000000..f495f9a
--- /dev/null
+++ b/hw/arm/imx25_3ds.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2013 Jean-Christophe Dubois
+ *
+ * 3Dstack Board System emulation.
+ *
+ * Based on hw/arm/kzm.c
+ *
+ * Copyright (c) 2008 OKL and 2011 NICTA
+ * Written by Hans at OK-Labs
+ * Updated by Peter Chubb.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/sysbus.h"
+#include "exec/address-spaces.h"
+#include "hw/hw.h"
+#include "hw/arm/arm.h"
+#include "hw/devices.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/char/serial.h"
+#include "hw/arm/imx.h"
+#include "hw/i2c/i2c.h"
+
+#include "sysemu/qtest.h"
+
+/* Memory map for 3D-Stack Emulation Baseboard:
+ * 0x00000000-0x00003fff 16k ROM IGNORED
+ * 0x00004000-0x00403fff Reserved IGNORED
+ * 0x00404000-0x00408fff 20k ROM IGNORED
+ * 0x00409000-0x0fffffff Reserved IGNORED
+ * 0x10000000-0x1fffffff Reserved IGNORED
+ * 0x20000000-0x2fffffff Reserved IGNORED
+ * 0x30000000-0x3fffffff Reserved IGNORED
+ * 0x40000000-0x43efffff Reserved IGNORED
+ * 0x43f00000-0x6fffffff I.MX25 Internal Register Space
+ * 0x43f00000 IO_AREA0
+ * 0x43f80000 I2C0 EMULATED
+ * 0x43f84000 I2C2 EMULATED
+ * 0x43f98000 I2C1 EMULATED
+ * 0x43f90000 UART1 EMULATED
+ * 0x43f94000 UART2 EMULATED
+ * 0x43fb0000 UART4 IGNORED
+ * 0x43fb4000 UART5 IGNORED
+ * 0x5000c000 UART3 EMULATED
+ * 0x50038000 FEC EMULATED
+ * 0x53f80000 CCM EMULATED
+ * 0x53f84000 GPT 4 EMULATED
+ * 0x53f88000 GPT 3 EMULATED
+ * 0x53f8c000 GPT 2 EMULATED
+ * 0x53f90000 GPT 1 EMULATED
+ * 0x53f94000 PIT 1 EMULATED
+ * 0x53f98000 PIT 2 EMULATED
+ * 0x53f9c000 GPIO-4 EMULATED
+ * 0x53fa4000 GPIO-3 EMULATED
+ * 0x53fcc000 GPIO-1 EMULATED
+ * 0x53fd0000 GPIO-2 EMULATED
+ * 0x68000000 ASIC EMULATED
+ * 0x78000000-0x7801ffff SRAM EMULATED
+ * 0x78020000-0x7fffffff SRAM Aliasing EMULATED
+ * 0x80000000-0x87ffffff RAM + Alias EMULATED
+ * 0x90000000-0x9fffffff RAM + Alias EMULATED
+ * 0xa0000000-0xa7ffffff Flash IGNORED
+ * 0xa8000000-0xafffffff Flash IGNORED
+ * 0xb0000000-0xb1ffffff SRAM IGNORED
+ * 0xb2000000-0xb3ffffff SRAM IGNORED
+ * 0xb4000000-0xb5ffffff CS4 IGNORED
+ * 0xb6000000-0xb8000fff Reserved IGNORED
+ * 0xb8001000-0xb8001fff SDRAM CTRL reg IGNORED
+ * 0xb8002000-0xb8002fff WEIM CTRL reg IGNORED
+ * 0xb8003000-0xb8003fff M3IF CTRL reg IGNORED
+ * 0xb8004000-0xb8004fff EMI CTRL reg IGNORED
+ * 0xb8005000-0xbaffffff Reserved IGNORED
+ * 0xbb000000-0xbb000fff NAND flash area buf IGNORED
+ * 0xbb001000-0xbb0011ff NAND flash reserved IGNORED
+ * 0xbb001200-0xbb001dff Reserved IGNORED
+ * 0xbb001e00-0xbb001fff NAN flash CTRL reg IGNORED
+ * 0xbb012000-0xbfffffff Reserved IGNORED
+ * 0xc0000000-0xffffffff Reserved IGNORED
+ */
+
+#define IMX25_SRAM_ADDRESS (0x78000000)
+#define IMX25_SRAMSIZE (128*1024)
+#define IMX25_CS_SRAMSIZE (128*1024*1024)
+#define IMX25_3DS_ADDRESS (0x80000000)
+#define IMX25_CS_RAMSIZE (256*1024*1024)
+
+static struct arm_boot_info imx25_3ds_binfo = {
+ .loader_start = IMX25_3DS_ADDRESS,
+ .board_id = 1771,
+};
+
+static void imx25_3ds_init(MachineState *args)
+{
+ int i;
+ int serial_cnt = 0;
+ const ram_addr_t ram_size = args->ram_size;
+ const char *cpu_model = args->cpu_model;
+ const char *kernel_filename = args->kernel_filename;
+ const char *kernel_cmdline = args->kernel_cmdline;
+ const char *initrd_filename = args->initrd_filename;
+ ARMCPU *cpu;
+ DeviceState *pic_dev;
+ DeviceState *ccm, *i2c_dev;
+ MemoryRegion *address_space_mem = get_system_memory();
+ MemoryRegion *sram = g_new(MemoryRegion, 1);
+ MemoryRegion *sram_alias = g_new(MemoryRegion, 1);
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } serial_table[] = {
+ { 0x43f90000, 45 },
+ { 0x43f94000, 32 },
+ { 0x5000c000, 18 },
+ { 0x50008000, 5 },
+ { 0x5002c000, 40 },
+ { 0, 0 }
+ };
+
+ if (!cpu_model) {
+ cpu_model = "arm926";
+ }
+
+ cpu = cpu_arm_init(cpu_model);
+ if (!cpu) {
+ fprintf(stderr, "Unable to find CPU definition\n");
+ exit(1);
+ }
+
+ if (ram_size > (2 * IMX25_CS_RAMSIZE)) {
+ fprintf(stderr, "i.MX25 can support only up to %d MB\n",
+ 2 * IMX25_CS_RAMSIZE / (1024 * 1024));
+ exit(1);
+ }
+
+ /* create our main memory */
+ for (i = 0; i <= (ram_size / IMX25_CS_RAMSIZE); i++) {
+ ram_addr_t blk_size = ram_size - (IMX25_CS_RAMSIZE * i);
+ MemoryRegion *ram;
+ char ram_name[20];
+
+ if (blk_size > IMX25_CS_RAMSIZE) {
+ blk_size = IMX25_CS_RAMSIZE;
+ }
+
+ if (blk_size == 0) {
+ break;
+ }
+
+ sprintf(ram_name, "imx25.ram%d", i);
+
+ ram = g_new(MemoryRegion, 1);
+ memory_region_init_ram(ram, NULL, ram_name, blk_size, &error_abort);
+ vmstate_register_ram_global(ram);
+ memory_region_add_subregion(address_space_mem, IMX25_3DS_ADDRESS
+ + (IMX25_CS_RAMSIZE * i), ram);
+
+ /* Add ram alias */
+ if (blk_size < IMX25_CS_RAMSIZE) {
+ MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
+ char alias_name[20];
+
+ sprintf(alias_name, "ram.alias%d", i);
+
+ memory_region_init_alias(ram_alias, NULL, alias_name, ram, 0,
+ IMX25_CS_RAMSIZE - blk_size);
+ memory_region_add_subregion(address_space_mem, IMX25_3DS_ADDRESS
+ + (IMX25_CS_RAMSIZE * i) + blk_size,
+ ram_alias);
+ }
+ }
+
+ /* create the sram area */
+ memory_region_init_ram(sram, NULL, "imx25.sram", IMX25_SRAMSIZE, &error_abort);
+ vmstate_register_ram_global(sram);
+ memory_region_add_subregion(address_space_mem, IMX25_SRAM_ADDRESS,
+ sram);
+
+ /* add sram alias */
+ memory_region_init_alias(sram_alias, NULL, "sram.alias", sram, 0,
+ IMX25_CS_SRAMSIZE - IMX25_SRAMSIZE);
+ memory_region_add_subregion(address_space_mem,
+ IMX25_SRAM_ADDRESS + IMX25_SRAMSIZE,
+ sram_alias);
+
+ /* add the PIC */
+ pic_dev = sysbus_create_varargs("imx_avic", 0x68000000,
+ qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
+ qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
+ NULL);
+
+ while (serial_table[serial_cnt].addr && (serial_cnt < MAX_SERIAL_PORTS)) {
+ /* add some serial lines */
+ imx_serial_create(serial_cnt, serial_table[serial_cnt].addr,
+ qdev_get_gpio_in(pic_dev,
+ serial_table[serial_cnt].irq));
+ serial_cnt++;
+ }
+
+ ccm = sysbus_create_simple("imx_ccm", 0x53f80000, NULL);
+
+ /* add gpt timers */
+ imx_timerg_create(0x53f84000, qdev_get_gpio_in(pic_dev, 1), ccm);
+ imx_timerg_create(0x53f88000, qdev_get_gpio_in(pic_dev, 29), ccm);
+ imx_timerg_create(0x53f8c000, qdev_get_gpio_in(pic_dev, 53), ccm);
+ imx_timerg_create(0x53f90000, qdev_get_gpio_in(pic_dev, 54), ccm);
+
+ /* add epit timers */
+ imx_timerp_create(0x53f94000, qdev_get_gpio_in(pic_dev, 28), ccm);
+ imx_timerp_create(0x53f98000, qdev_get_gpio_in(pic_dev, 27), ccm);
+
+ imx_fec_create(0, 0x50038000, qdev_get_gpio_in(pic_dev, 57));
+
+ /* I2C 0 */
+ i2c_dev = sysbus_create_simple("imx.i2c", 0x43f80000,
+ qdev_get_gpio_in(pic_dev, 3));
+
+ /* add I2C 1 */
+ sysbus_create_simple("imx.i2c", 0x43f98000, qdev_get_gpio_in(pic_dev, 4));
+ /* add I2C 2 */
+ sysbus_create_simple("imx.i2c", 0x43f84000, qdev_get_gpio_in(pic_dev, 10));
+
+ imx25_3ds_binfo.ram_size = ram_size;
+ imx25_3ds_binfo.kernel_filename = kernel_filename;
+ imx25_3ds_binfo.kernel_cmdline = kernel_cmdline;
+ imx25_3ds_binfo.initrd_filename = initrd_filename;
+ imx25_3ds_binfo.nb_cpus = 1;
+
+ /*
+ * We test explicitly for qtest here as it is not done (yet?) in
+ * arm_load_kernel(). Without this the "make check" command would
+ * fail.
+ */
+
+ if (!qtest_enabled()) {
+ arm_load_kernel(cpu, &imx25_3ds_binfo);
+ } else {
+ /*
+ * This I2C device doesn't exist on the real board.
+ * We add it here (only on qtest usage) to be able to do a bit
+ * of simple qtest. See "make check" for details.
+ */
+ i2c_create_slave((I2CBus *)qdev_get_child_bus(i2c_dev, "i2c"),
+ "ds1338", 0x68);
+
+ }
+}
+
+static QEMUMachine imx25_3ds_machine = {
+ .name = "imx25_3ds",
+ .desc = "ARM i.MX25 PDK board (ARM926)",
+ .init = imx25_3ds_init,
+};
+
+static void imx25_3ds_machine_init(void)
+{
+ qemu_register_machine(&imx25_3ds_machine);
+}
+
+machine_init(imx25_3ds_machine_init)
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [Qemu-devel] [PATCH v7 4/4] i.MX: Add qtest support for I2C device emulator
2015-06-22 19:06 [Qemu-devel] [PATCH v7 0/4] i.MX: Add i.MX25 support through the 3DS evaluation board Jean-Christophe Dubois
` (2 preceding siblings ...)
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 3/4] i.MX: Add i.MX25 3DS evaluation board support Jean-Christophe Dubois
@ 2015-06-22 19:06 ` Jean-Christophe Dubois
3 siblings, 0 replies; 7+ messages in thread
From: Jean-Christophe Dubois @ 2015-06-22 19:06 UTC (permalink / raw)
To: qemu-devel; +Cc: Jean-Christophe Dubois
This is using a ds1338 RTC chip on the i2c bus. This RTC
chip is not present on the real board.
Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
---
Changes since v1:
* not present on v1
Changes since v2:
* use a common header file for I2C regs definition
Changes since v3:
* rework GPL headers.
Changes since v4:
* none
Changes since v5:
* none
Changes since v6:
* none
tests/Makefile | 3 +
tests/ds1338-test.c | 75 ++++++++++++++++++
tests/libqos/i2c-imx.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++++
tests/libqos/i2c.h | 3 +
4 files changed, 290 insertions(+)
create mode 100644 tests/ds1338-test.c
create mode 100644 tests/libqos/i2c-imx.c
diff --git a/tests/Makefile b/tests/Makefile
index c5e4744..93890a8 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -193,6 +193,7 @@ check-qtest-sparc64-y = tests/endianness-test$(EXESUF)
gcov-files-sparc-y += hw/timer/m48t59.c
gcov-files-sparc64-y += hw/timer/m48t59.c
check-qtest-arm-y = tests/tmp105-test$(EXESUF)
+check-qtest-arm-y = tests/ds1338-test$(EXESUF)
gcov-files-arm-y += hw/misc/tmp105.c
check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
gcov-files-arm-y += arm-softmmu/hw/block/virtio-blk.c
@@ -342,6 +343,7 @@ libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
libqos-pc-obj-y += tests/libqos/ahci.o
libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o
+libqos-imx-obj-y = $(libqos-obj-y) tests/libqos/i2c-imx.o
libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o
libqos-virtio-obj-y = $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/libqos/malloc-generic.o
@@ -356,6 +358,7 @@ tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o
tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y)
tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o $(libqos-obj-y)
tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
+tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y)
diff --git a/tests/ds1338-test.c b/tests/ds1338-test.c
new file mode 100644
index 0000000..fbc989b
--- /dev/null
+++ b/tests/ds1338-test.c
@@ -0,0 +1,75 @@
+/*
+ * QTest testcase for the DS1338 RTC
+ *
+ * Copyright (c) 2013 Jean-Christophe Dubois
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libqtest.h"
+#include "libqos/i2c.h"
+
+#include <glib.h>
+
+#define IMX25_I2C_0_BASE 0x43F80000
+
+#define DS1338_ADDR 0x68
+
+static I2CAdapter *i2c;
+static uint8_t addr;
+
+#define bcd2bin(x) (((x) & 0x0f) + ((x) >> 4) * 10)
+
+static void send_and_receive(void)
+{
+ uint8_t cmd[1];
+ uint8_t resp[7];
+ time_t now = time(NULL);
+ struct tm *tm_ptr = gmtime(&now);
+
+ /* reset the index in the RTC memory */
+ cmd[0] = 0;
+ i2c_send(i2c, addr, cmd, 1);
+
+ /* retrieve the date */
+ i2c_recv(i2c, addr, resp, 7);
+
+ /* check retreived time againt local time */
+ g_assert_cmpuint(bcd2bin(resp[4]), == , tm_ptr->tm_mday);
+ g_assert_cmpuint(bcd2bin(resp[5]), == , 1 + tm_ptr->tm_mon);
+ g_assert_cmpuint(2000 + bcd2bin(resp[6]), == , 1900 + tm_ptr->tm_year);
+}
+
+int main(int argc, char **argv)
+{
+ QTestState *s = NULL;
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+
+ s = qtest_start("-display none -machine imx25_3ds");
+ i2c = imx_i2c_create(IMX25_I2C_0_BASE);
+ addr = DS1338_ADDR;
+
+ qtest_add_func("/ds1338/tx-rx", send_and_receive);
+
+ ret = g_test_run();
+
+ if (s) {
+ qtest_quit(s);
+ }
+ g_free(i2c);
+
+ return ret;
+}
diff --git a/tests/libqos/i2c-imx.c b/tests/libqos/i2c-imx.c
new file mode 100644
index 0000000..2b18581
--- /dev/null
+++ b/tests/libqos/i2c-imx.c
@@ -0,0 +1,209 @@
+/*
+ * QTest i.MX I2C driver
+ *
+ * Copyright (c) 2013 Jean-Christophe Dubois
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libqos/i2c.h"
+
+#include <glib.h>
+#include <string.h>
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+#include "hw/i2c/imx_i2c_regs.h"
+
+enum IMXI2CDirection {
+ IMX_I2C_READ,
+ IMX_I2C_WRITE,
+};
+
+typedef struct IMXI2C {
+ I2CAdapter parent;
+
+ uint64_t addr;
+} IMXI2C;
+
+
+static void imx_i2c_set_slave_addr(IMXI2C *s, uint8_t addr,
+ enum IMXI2CDirection direction)
+{
+ writeb(s->addr + I2DR_ADDR, (addr << 1) |
+ (direction == IMX_I2C_READ ? 1 : 0));
+}
+
+static void imx_i2c_send(I2CAdapter *i2c, uint8_t addr,
+ const uint8_t *buf, uint16_t len)
+{
+ IMXI2C *s = (IMXI2C *)i2c;
+ uint8_t data;
+ uint8_t status;
+ uint16_t size = 0;
+
+ if (!len) {
+ return;
+ }
+
+ /* set the bus for write */
+ data = I2CR_IEN |
+ I2CR_IIEN |
+ I2CR_MSTA |
+ I2CR_MTX |
+ I2CR_TXAK;
+
+ writeb(s->addr + I2CR_ADDR, data);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IBB) != 0);
+
+ /* set the slave address */
+ imx_i2c_set_slave_addr(s, addr, IMX_I2C_WRITE);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) != 0);
+ g_assert((status & I2SR_RXAK) == 0);
+
+ /* ack the interrupt */
+ writeb(s->addr + I2SR_ADDR, 0);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) == 0);
+
+ while (size < len) {
+ /* check we are still busy */
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IBB) != 0);
+
+ /* write the data */
+ writeb(s->addr + I2DR_ADDR, buf[size]);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) != 0);
+ g_assert((status & I2SR_RXAK) == 0);
+
+ /* ack the interrupt */
+ writeb(s->addr + I2SR_ADDR, 0);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) == 0);
+
+ size++;
+ }
+
+ /* release the bus */
+ data &= ~(I2CR_MSTA | I2CR_MTX);
+ writeb(s->addr + I2CR_ADDR, data);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IBB) == 0);
+}
+
+static void imx_i2c_recv(I2CAdapter *i2c, uint8_t addr,
+ uint8_t *buf, uint16_t len)
+{
+ IMXI2C *s = (IMXI2C *)i2c;
+ uint8_t data;
+ uint8_t status;
+ uint16_t size = 0;
+
+ if (!len) {
+ return;
+ }
+
+ /* set the bus for write */
+ data = I2CR_IEN |
+ I2CR_IIEN |
+ I2CR_MSTA |
+ I2CR_MTX |
+ I2CR_TXAK;
+
+ writeb(s->addr + I2CR_ADDR, data);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IBB) != 0);
+
+ /* set the slave address */
+ imx_i2c_set_slave_addr(s, addr, IMX_I2C_READ);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) != 0);
+ g_assert((status & I2SR_RXAK) == 0);
+
+ /* ack the interrupt */
+ writeb(s->addr + I2SR_ADDR, 0);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) == 0);
+
+ /* set the bus for read */
+ data &= ~I2CR_MTX;
+ /* if only one byte don't ack */
+ if (len != 1) {
+ data &= ~I2CR_TXAK;
+ }
+ writeb(s->addr + I2CR_ADDR, data);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IBB) != 0);
+
+ /* dummy read */
+ readb(s->addr + I2DR_ADDR);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) != 0);
+
+ /* ack the interrupt */
+ writeb(s->addr + I2SR_ADDR, 0);
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) == 0);
+
+ while (size < len) {
+ /* check we are still busy */
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IBB) != 0);
+
+ if (size == (len - 1)) {
+ /* stop the read transaction */
+ data &= ~(I2CR_MSTA | I2CR_MTX);
+ } else {
+ /* ack the data read */
+ data |= I2CR_TXAK;
+ }
+ writeb(s->addr + I2CR_ADDR, data);
+
+ /* read the data */
+ buf[size] = readb(s->addr + I2DR_ADDR);
+
+ if (size != (len - 1)) {
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) != 0);
+
+ /* ack the interrupt */
+ writeb(s->addr + I2SR_ADDR, 0);
+ }
+
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IIF) == 0);
+
+ size++;
+ }
+
+ status = readb(s->addr + I2SR_ADDR);
+ g_assert((status & I2SR_IBB) == 0);
+}
+
+I2CAdapter *imx_i2c_create(uint64_t addr)
+{
+ IMXI2C *s = g_malloc0(sizeof(*s));
+ I2CAdapter *i2c = (I2CAdapter *)s;
+
+ s->addr = addr;
+
+ i2c->send = imx_i2c_send;
+ i2c->recv = imx_i2c_recv;
+
+ return i2c;
+}
diff --git a/tests/libqos/i2c.h b/tests/libqos/i2c.h
index 1ce9af4..c21f1dc 100644
--- a/tests/libqos/i2c.h
+++ b/tests/libqos/i2c.h
@@ -27,4 +27,7 @@ void i2c_recv(I2CAdapter *i2c, uint8_t addr,
/* libi2c-omap.c */
I2CAdapter *omap_i2c_create(uint64_t addr);
+/* libi2c-imx.c */
+I2CAdapter *imx_i2c_create(uint64_t addr);
+
#endif
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH v7 3/4] i.MX: Add i.MX25 3DS evaluation board support
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 3/4] i.MX: Add i.MX25 3DS evaluation board support Jean-Christophe Dubois
@ 2015-06-24 5:07 ` Peter Crosthwaite
2015-06-24 6:09 ` Jean-Christophe DUBOIS
0 siblings, 1 reply; 7+ messages in thread
From: Peter Crosthwaite @ 2015-06-24 5:07 UTC (permalink / raw)
To: Jean-Christophe Dubois, Peter Maydell, Andreas Färber
Cc: qemu-devel@nongnu.org Developers
On Mon, Jun 22, 2015 at 12:06 PM, Jean-Christophe Dubois
<jcd@tribudubois.net> wrote:
> For now we support:
> * timers (GPT and EPIT)
> * serial ports
> * ethernet (through the newly added FEC emulator)
> * I2C (through the newly added I2C emulator)
>
> Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
> ---
>
> Changes since v1:
> * Added a ds1338 I2C device for qtest purpose.
>
> Changes since v2:
> * none
>
> Changes since v3:
> * Rework GPL header
> * use I2C constructor helper.
>
> Changes since v4:
> * use sysbus_create_simple() instead of I2C constructor helper
>
> Changes since v5:
> * Add ds1338 only for qtest mode.
> * small comment fixes.
>
> Changes since v6:
> * Allow for more than 4 serial if suppoted by Qemu.
>
> hw/arm/Makefile.objs | 1 +
> hw/arm/imx25_3ds.c | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++
So the (new since v6) guideline with ARM SoCs is to split the SoC and
machine models. This would give you two files. A SoC file for imx25
and board for 3ds.
I'm not 100% on the "3ds" board following some googling but is it
really the PDK board? I found this:
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=635baf6b40ebaef683abf87d677467cba71a0d50
and can find product info for PDK from there:
http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=IMX25PDK
To see modern examples of split SoC/board, see stm32f205_soc wiith
netduino2 or xlnx-zynqmp with xlnx-ep108 (all in hw/arm).
It seems the only board level feature you are implementing is this
ds1338 which is not or the real board. So I guess qtest-only code can
be left in the SoC model.
This would make your board level very similar to netduino2 (perhaps
even slightly simpler).
Regards,
Peter
> 2 files changed, 274 insertions(+)
> create mode 100644 hw/arm/imx25_3ds.c
>
> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
> index cf346c1..3ecb8b1 100644
> --- a/hw/arm/Makefile.objs
> +++ b/hw/arm/Makefile.objs
> @@ -5,6 +5,7 @@ obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
> obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
> obj-$(CONFIG_ACPI) += virt-acpi-build.o
> obj-y += netduino2.o
> +obj-y += imx25_3ds.o
> obj-y += sysbus-fdt.o
>
> obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
> diff --git a/hw/arm/imx25_3ds.c b/hw/arm/imx25_3ds.c
> new file mode 100644
> index 0000000..f495f9a
> --- /dev/null
> +++ b/hw/arm/imx25_3ds.c
> @@ -0,0 +1,273 @@
> +/*
> + * Copyright (c) 2013 Jean-Christophe Dubois
> + *
> + * 3Dstack Board System emulation.
> + *
> + * Based on hw/arm/kzm.c
> + *
> + * Copyright (c) 2008 OKL and 2011 NICTA
> + * Written by Hans at OK-Labs
> + * Updated by Peter Chubb.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> + * for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "hw/sysbus.h"
> +#include "exec/address-spaces.h"
> +#include "hw/hw.h"
> +#include "hw/arm/arm.h"
> +#include "hw/devices.h"
> +#include "net/net.h"
> +#include "sysemu/sysemu.h"
> +#include "hw/boards.h"
> +#include "hw/char/serial.h"
> +#include "hw/arm/imx.h"
> +#include "hw/i2c/i2c.h"
> +
> +#include "sysemu/qtest.h"
> +
> +/* Memory map for 3D-Stack Emulation Baseboard:
> + * 0x00000000-0x00003fff 16k ROM IGNORED
> + * 0x00004000-0x00403fff Reserved IGNORED
> + * 0x00404000-0x00408fff 20k ROM IGNORED
> + * 0x00409000-0x0fffffff Reserved IGNORED
> + * 0x10000000-0x1fffffff Reserved IGNORED
> + * 0x20000000-0x2fffffff Reserved IGNORED
> + * 0x30000000-0x3fffffff Reserved IGNORED
> + * 0x40000000-0x43efffff Reserved IGNORED
> + * 0x43f00000-0x6fffffff I.MX25 Internal Register Space
> + * 0x43f00000 IO_AREA0
> + * 0x43f80000 I2C0 EMULATED
> + * 0x43f84000 I2C2 EMULATED
> + * 0x43f98000 I2C1 EMULATED
> + * 0x43f90000 UART1 EMULATED
> + * 0x43f94000 UART2 EMULATED
> + * 0x43fb0000 UART4 IGNORED
> + * 0x43fb4000 UART5 IGNORED
> + * 0x5000c000 UART3 EMULATED
> + * 0x50038000 FEC EMULATED
> + * 0x53f80000 CCM EMULATED
> + * 0x53f84000 GPT 4 EMULATED
> + * 0x53f88000 GPT 3 EMULATED
> + * 0x53f8c000 GPT 2 EMULATED
> + * 0x53f90000 GPT 1 EMULATED
> + * 0x53f94000 PIT 1 EMULATED
> + * 0x53f98000 PIT 2 EMULATED
> + * 0x53f9c000 GPIO-4 EMULATED
> + * 0x53fa4000 GPIO-3 EMULATED
> + * 0x53fcc000 GPIO-1 EMULATED
> + * 0x53fd0000 GPIO-2 EMULATED
> + * 0x68000000 ASIC EMULATED
> + * 0x78000000-0x7801ffff SRAM EMULATED
> + * 0x78020000-0x7fffffff SRAM Aliasing EMULATED
> + * 0x80000000-0x87ffffff RAM + Alias EMULATED
> + * 0x90000000-0x9fffffff RAM + Alias EMULATED
> + * 0xa0000000-0xa7ffffff Flash IGNORED
> + * 0xa8000000-0xafffffff Flash IGNORED
> + * 0xb0000000-0xb1ffffff SRAM IGNORED
> + * 0xb2000000-0xb3ffffff SRAM IGNORED
> + * 0xb4000000-0xb5ffffff CS4 IGNORED
> + * 0xb6000000-0xb8000fff Reserved IGNORED
> + * 0xb8001000-0xb8001fff SDRAM CTRL reg IGNORED
> + * 0xb8002000-0xb8002fff WEIM CTRL reg IGNORED
> + * 0xb8003000-0xb8003fff M3IF CTRL reg IGNORED
> + * 0xb8004000-0xb8004fff EMI CTRL reg IGNORED
> + * 0xb8005000-0xbaffffff Reserved IGNORED
> + * 0xbb000000-0xbb000fff NAND flash area buf IGNORED
> + * 0xbb001000-0xbb0011ff NAND flash reserved IGNORED
> + * 0xbb001200-0xbb001dff Reserved IGNORED
> + * 0xbb001e00-0xbb001fff NAN flash CTRL reg IGNORED
> + * 0xbb012000-0xbfffffff Reserved IGNORED
> + * 0xc0000000-0xffffffff Reserved IGNORED
> + */
> +
> +#define IMX25_SRAM_ADDRESS (0x78000000)
> +#define IMX25_SRAMSIZE (128*1024)
> +#define IMX25_CS_SRAMSIZE (128*1024*1024)
> +#define IMX25_3DS_ADDRESS (0x80000000)
> +#define IMX25_CS_RAMSIZE (256*1024*1024)
> +
> +static struct arm_boot_info imx25_3ds_binfo = {
> + .loader_start = IMX25_3DS_ADDRESS,
> + .board_id = 1771,
> +};
> +
> +static void imx25_3ds_init(MachineState *args)
> +{
> + int i;
> + int serial_cnt = 0;
> + const ram_addr_t ram_size = args->ram_size;
> + const char *cpu_model = args->cpu_model;
> + const char *kernel_filename = args->kernel_filename;
> + const char *kernel_cmdline = args->kernel_cmdline;
> + const char *initrd_filename = args->initrd_filename;
> + ARMCPU *cpu;
> + DeviceState *pic_dev;
> + DeviceState *ccm, *i2c_dev;
> + MemoryRegion *address_space_mem = get_system_memory();
> + MemoryRegion *sram = g_new(MemoryRegion, 1);
> + MemoryRegion *sram_alias = g_new(MemoryRegion, 1);
> + static const struct {
> + hwaddr addr;
> + unsigned int irq;
> + } serial_table[] = {
> + { 0x43f90000, 45 },
> + { 0x43f94000, 32 },
> + { 0x5000c000, 18 },
> + { 0x50008000, 5 },
> + { 0x5002c000, 40 },
> + { 0, 0 }
> + };
> +
> + if (!cpu_model) {
> + cpu_model = "arm926";
> + }
> +
> + cpu = cpu_arm_init(cpu_model);
> + if (!cpu) {
> + fprintf(stderr, "Unable to find CPU definition\n");
> + exit(1);
> + }
> +
> + if (ram_size > (2 * IMX25_CS_RAMSIZE)) {
> + fprintf(stderr, "i.MX25 can support only up to %d MB\n",
> + 2 * IMX25_CS_RAMSIZE / (1024 * 1024));
> + exit(1);
> + }
> +
> + /* create our main memory */
> + for (i = 0; i <= (ram_size / IMX25_CS_RAMSIZE); i++) {
> + ram_addr_t blk_size = ram_size - (IMX25_CS_RAMSIZE * i);
> + MemoryRegion *ram;
> + char ram_name[20];
> +
> + if (blk_size > IMX25_CS_RAMSIZE) {
> + blk_size = IMX25_CS_RAMSIZE;
> + }
> +
> + if (blk_size == 0) {
> + break;
> + }
> +
> + sprintf(ram_name, "imx25.ram%d", i);
> +
> + ram = g_new(MemoryRegion, 1);
> + memory_region_init_ram(ram, NULL, ram_name, blk_size, &error_abort);
> + vmstate_register_ram_global(ram);
> + memory_region_add_subregion(address_space_mem, IMX25_3DS_ADDRESS
> + + (IMX25_CS_RAMSIZE * i), ram);
> +
> + /* Add ram alias */
> + if (blk_size < IMX25_CS_RAMSIZE) {
> + MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
> + char alias_name[20];
> +
> + sprintf(alias_name, "ram.alias%d", i);
> +
> + memory_region_init_alias(ram_alias, NULL, alias_name, ram, 0,
> + IMX25_CS_RAMSIZE - blk_size);
> + memory_region_add_subregion(address_space_mem, IMX25_3DS_ADDRESS
> + + (IMX25_CS_RAMSIZE * i) + blk_size,
> + ram_alias);
> + }
> + }
> +
> + /* create the sram area */
> + memory_region_init_ram(sram, NULL, "imx25.sram", IMX25_SRAMSIZE, &error_abort);
> + vmstate_register_ram_global(sram);
> + memory_region_add_subregion(address_space_mem, IMX25_SRAM_ADDRESS,
> + sram);
> +
> + /* add sram alias */
> + memory_region_init_alias(sram_alias, NULL, "sram.alias", sram, 0,
> + IMX25_CS_SRAMSIZE - IMX25_SRAMSIZE);
> + memory_region_add_subregion(address_space_mem,
> + IMX25_SRAM_ADDRESS + IMX25_SRAMSIZE,
> + sram_alias);
> +
> + /* add the PIC */
> + pic_dev = sysbus_create_varargs("imx_avic", 0x68000000,
> + qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
> + qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
> + NULL);
> +
> + while (serial_table[serial_cnt].addr && (serial_cnt < MAX_SERIAL_PORTS)) {
> + /* add some serial lines */
> + imx_serial_create(serial_cnt, serial_table[serial_cnt].addr,
> + qdev_get_gpio_in(pic_dev,
> + serial_table[serial_cnt].irq));
> + serial_cnt++;
> + }
> +
> + ccm = sysbus_create_simple("imx_ccm", 0x53f80000, NULL);
> +
> + /* add gpt timers */
> + imx_timerg_create(0x53f84000, qdev_get_gpio_in(pic_dev, 1), ccm);
> + imx_timerg_create(0x53f88000, qdev_get_gpio_in(pic_dev, 29), ccm);
> + imx_timerg_create(0x53f8c000, qdev_get_gpio_in(pic_dev, 53), ccm);
> + imx_timerg_create(0x53f90000, qdev_get_gpio_in(pic_dev, 54), ccm);
> +
> + /* add epit timers */
> + imx_timerp_create(0x53f94000, qdev_get_gpio_in(pic_dev, 28), ccm);
> + imx_timerp_create(0x53f98000, qdev_get_gpio_in(pic_dev, 27), ccm);
> +
> + imx_fec_create(0, 0x50038000, qdev_get_gpio_in(pic_dev, 57));
> +
> + /* I2C 0 */
> + i2c_dev = sysbus_create_simple("imx.i2c", 0x43f80000,
> + qdev_get_gpio_in(pic_dev, 3));
> +
> + /* add I2C 1 */
> + sysbus_create_simple("imx.i2c", 0x43f98000, qdev_get_gpio_in(pic_dev, 4));
> + /* add I2C 2 */
> + sysbus_create_simple("imx.i2c", 0x43f84000, qdev_get_gpio_in(pic_dev, 10));
> +
> + imx25_3ds_binfo.ram_size = ram_size;
> + imx25_3ds_binfo.kernel_filename = kernel_filename;
> + imx25_3ds_binfo.kernel_cmdline = kernel_cmdline;
> + imx25_3ds_binfo.initrd_filename = initrd_filename;
> + imx25_3ds_binfo.nb_cpus = 1;
> +
> + /*
> + * We test explicitly for qtest here as it is not done (yet?) in
> + * arm_load_kernel(). Without this the "make check" command would
> + * fail.
> + */
> +
> + if (!qtest_enabled()) {
> + arm_load_kernel(cpu, &imx25_3ds_binfo);
> + } else {
> + /*
> + * This I2C device doesn't exist on the real board.
> + * We add it here (only on qtest usage) to be able to do a bit
> + * of simple qtest. See "make check" for details.
> + */
> + i2c_create_slave((I2CBus *)qdev_get_child_bus(i2c_dev, "i2c"),
> + "ds1338", 0x68);
> +
> + }
> +}
> +
> +static QEMUMachine imx25_3ds_machine = {
> + .name = "imx25_3ds",
> + .desc = "ARM i.MX25 PDK board (ARM926)",
> + .init = imx25_3ds_init,
> +};
> +
> +static void imx25_3ds_machine_init(void)
> +{
> + qemu_register_machine(&imx25_3ds_machine);
> +}
> +
> +machine_init(imx25_3ds_machine_init)
> --
> 2.1.4
>
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH v7 3/4] i.MX: Add i.MX25 3DS evaluation board support
2015-06-24 5:07 ` Peter Crosthwaite
@ 2015-06-24 6:09 ` Jean-Christophe DUBOIS
0 siblings, 0 replies; 7+ messages in thread
From: Jean-Christophe DUBOIS @ 2015-06-24 6:09 UTC (permalink / raw)
To: Peter Crosthwaite, Peter Maydell, Andreas Färber
Cc: qemu-devel@nongnu.org Developers
Le 24/06/2015 07:07, Peter Crosthwaite a écrit :
> On Mon, Jun 22, 2015 at 12:06 PM, Jean-Christophe Dubois
> <jcd@tribudubois.net> wrote:
>> For now we support:
>> * timers (GPT and EPIT)
>> * serial ports
>> * ethernet (through the newly added FEC emulator)
>> * I2C (through the newly added I2C emulator)
>>
>> Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
>> ---
>>
>> Changes since v1:
>> * Added a ds1338 I2C device for qtest purpose.
>>
>> Changes since v2:
>> * none
>>
>> Changes since v3:
>> * Rework GPL header
>> * use I2C constructor helper.
>>
>> Changes since v4:
>> * use sysbus_create_simple() instead of I2C constructor helper
>>
>> Changes since v5:
>> * Add ds1338 only for qtest mode.
>> * small comment fixes.
>>
>> Changes since v6:
>> * Allow for more than 4 serial if suppoted by Qemu.
>>
>> hw/arm/Makefile.objs | 1 +
>> hw/arm/imx25_3ds.c | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++
> So the (new since v6) guideline with ARM SoCs is to split the SoC and
> machine models. This would give you two files. A SoC file for imx25
> and board for 3ds.
>
> I'm not 100% on the "3ds" board following some googling but is it
> really the PDK board? I found this:
>
> http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=635baf6b40ebaef683abf87d677467cba71a0d50
>
> and can find product info for PDK from there:
>
> http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=IMX25PDK
Yes this is the board.
>
> To see modern examples of split SoC/board, see stm32f205_soc wiith
> netduino2 or xlnx-zynqmp with xlnx-ep108 (all in hw/arm).
I'll look at it.
>
> It seems the only board level feature you are implementing is this
> ds1338 which is not or the real board. So I guess qtest-only code can
> be left in the SoC model.
OK
>
> This would make your board level very similar to netduino2 (perhaps
> even slightly simpler).
Yes, for now there is basically only the SOC supported in my case.
>
> Regards,
> Peter
Thanks for the feedback.
JC
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2015-06-24 6:09 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-22 19:06 [Qemu-devel] [PATCH v7 0/4] i.MX: Add i.MX25 support through the 3DS evaluation board Jean-Christophe Dubois
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 1/4] i.MX: Add FEC Ethernet Emulator Jean-Christophe Dubois
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 2/4] i.MX: Add I2C contoller emulator Jean-Christophe Dubois
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 3/4] i.MX: Add i.MX25 3DS evaluation board support Jean-Christophe Dubois
2015-06-24 5:07 ` Peter Crosthwaite
2015-06-24 6:09 ` Jean-Christophe DUBOIS
2015-06-22 19:06 ` [Qemu-devel] [PATCH v7 4/4] i.MX: Add qtest support for I2C device emulator Jean-Christophe Dubois
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.