[Qemu-devel] [PATCH] util/path: Always translate /etc/ld.so.cache
Always translate /etc/ld.so.cache to point somwhere inside of guest's filesystem tree pointed to by 'prefix'. This prevents guest's libc from reading /etc/ld.so.cache of the host and potentialy failing. One of the manifestation of the problem could be easily reproduced by executing and simple application compiled for PowerPC on a x86 host using linux-use/qemu-ppc emulation. Anything as simple as: qemu-ppc -L /bin/ls should trigger the problem. Signed-off-by: Andrey Smirnov --- util/path.c | 53 + 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/util/path.c b/util/path.c index 5479f76..cc28bff 100644 --- a/util/path.c +++ b/util/path.c @@ -108,8 +108,8 @@ static void set_parents(struct pathelem *child, struct pathelem *parent) } /* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */ -static const char * -follow_path(const struct pathelem *cursor, const char *name) +static struct pathelem * +follow_path(struct pathelem *cursor, const char *name) { unsigned int i, namelen; @@ -117,7 +117,7 @@ follow_path(const struct pathelem *cursor, const char *name) namelen = strcspn(name, "/"); if (namelen == 0) -return cursor->pathname; +return cursor; if (strneq(name, namelen, "..")) return follow_path(cursor->parent, name + namelen); @@ -133,9 +133,28 @@ follow_path(const struct pathelem *cursor, const char *name) return NULL; } + +static void append_entry(struct pathelem *cursor, + const char *name, unsigned type) +{ +size_t i; +struct pathelem *parent; + +parent = cursor->parent; + +for (i = 0; i < parent->num_entries; i++) { +if (parent->entries[i] == cursor) { +break; +} +} + +parent->entries[i] = add_entry(cursor, name, type); +} + void init_paths(const char *prefix) { char pref_buf[PATH_MAX]; +struct pathelem *cursor; if (prefix[0] == '\0' || !strcmp(prefix, "/")) @@ -164,15 +183,41 @@ void init_paths(const char *prefix) } else { set_parents(base, base); } + +/* + * libc does not necessarily handle reading host's ld.so.cache + * well (e.g. running PowerPC code on x86, or, very likely any + * mixed endian combination) + * + * So check if guest's prefix "tree" provides ld.so.cache and if + * not add a fake translation entry, so as to prevent guest's libc + * request to /etc/ld.so.cache to resolve into host's + * /etc/ld.so.cache + */ +cursor = follow_path(base, "/etc/ld.so.cache"); +if (!cursor) { +cursor = follow_path(base, "/etc/"); +if (!cursor) { +cursor = follow_path(base, "/"); +append_entry(cursor, "etc", DT_DIR); +cursor = follow_path(base, "/etc/"); +} + +append_entry(cursor, "ld.so.cache", DT_REG); +} } /* Look for path in emulation dir, otherwise return name. */ const char *path(const char *name) { +struct pathelem *cursor; + /* Only do absolute paths: quick and dirty, but should mostly be OK. Could do relative by tracking cwd. */ if (!base || !name || name[0] != '/') return name; -return follow_path(base, name) ?: name; +cursor = follow_path(base, name); + +return cursor ? cursor->pathname : name; } -- 2.9.3
Re: [Qemu-devel] [PATCH] util/path: Always translate /etc/ld.so.cache
On Fri, Jan 27, 2017 at 10:53 AM, Peter Maydell wrote: > On 27 January 2017 at 18:31, Andrey Smirnov wrote: >> Always translate /etc/ld.so.cache to point somwhere inside of guest's >> filesystem tree pointed to by 'prefix'. This prevents guest's libc from >> reading /etc/ld.so.cache of the host and potentialy failing. One of the >> manifestation of the problem could be easily reproduced by executing and >> simple application compiled for PowerPC on a x86 host using >> linux-use/qemu-ppc emulation. >> >> Anything as simple as: >> >> qemu-ppc -L /bin/ls >> >> should trigger the problem. >> >> Signed-off-by: Andrey Smirnov > > Have you tested that this doesn't cause execution inside a chroot > to behave wrongly (in a chroot, the host fs /etc/ld.so.cache is > definitely the one you want to use) ? No, I have not. I'll go back and do more homework. Just to make sure that my assumptions are correct, I consider "qemu-ppc -L" and "chroot qemu-ppc" to be the only use-cases supported, and "chroot qemu-ppc -L " is not something that is expected to work correctly. Is that a correct assumption to make? > > (glibc really ought to fix their ld.so.cache reading bugs.) > I agree. I am planning on taking a look at the glibc side of things to see if there's a simple way to fix the problem there, but in the meantime I thought it would be good to float this patch and get some feedback. Cheers! Andrey Smirnov
[Qemu-devel] [RFC PATCH] armv7m_nvic: Use qemu_get_cpu(0) instead of current_cpu
Starting QEMU with -S results in current_cpu containing its initial value of NULL. It is however possible to connect to such QEMU instance and query various CPU registers, one example being CPUID, and doing that results in QEMU segfaulting. Using qemu_get_cpu(0) seem reasonable enough given that ARMv7M architecture is a single core architecture. Signed-off-by: Andrey Smirnov --- hw/intc/armv7m_nvic.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 890d5d7..06d8db6 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -187,11 +187,11 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset) case 0x1c: /* SysTick Calibration Value. */ return 1; case 0xd00: /* CPUID Base. */ -cpu = ARM_CPU(current_cpu); +cpu = ARM_CPU(qemu_get_cpu(0)); return cpu->midr; case 0xd04: /* Interrupt Control State. */ /* VECTACTIVE */ -cpu = ARM_CPU(current_cpu); +cpu = ARM_CPU(qemu_get_cpu(0)); val = cpu->env.v7m.exception; if (val == 1023) { val = 0; @@ -222,7 +222,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset) val |= (1 << 31); return val; case 0xd08: /* Vector Table Offset. */ -cpu = ARM_CPU(current_cpu); +cpu = ARM_CPU(qemu_get_cpu(0)); return cpu->env.v7m.vecbase; case 0xd0c: /* Application Interrupt/Reset Control. */ return 0xfa05; @@ -349,7 +349,7 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value) } break; case 0xd08: /* Vector Table Offset. */ -cpu = ARM_CPU(current_cpu); +cpu = ARM_CPU(qemu_get_cpu(0)); cpu->env.v7m.vecbase = value & 0xff80; break; case 0xd0c: /* Application Interrupt/Reset Control. */ -- 2.5.5
[Qemu-devel] [RFC PATCH] exec: Support non-direct memory writes in cpu_memory_rw_debug
Add code to support writing to memory mapped peripherals via cpu_memory_rw_debug(). The code of that function already supports reading from such memory regions, so this commit makes that functionality "symmetric". One use-case for that functionality is setting various registers of a non-running CPU. A concrete example would be starting QEMU emulating Cortex-M with -S, connecting with GDB and modifying the value of Vector Table Offset register. Signed-off-by: Andrey Smirnov --- cpus.c | 2 +- disas.c | 4 ++-- exec.c | 57 - gdbstub.c | 10 hw/i386/kvmvapic.c | 18 +++--- hw/mips/mips_jazz.c | 2 +- hw/pci-host/prep.c | 2 +- hw/virtio/virtio.c | 2 +- include/exec/cpu-all.h | 2 +- include/exec/memory.h | 15 +--- include/exec/softmmu-semi.h | 16 ++--- ioport.c| 6 ++--- monitor.c | 2 +- target-arm/arm-semi.c | 2 +- target-arm/kvm64.c | 8 +++ target-i386/helper.c| 6 ++--- target-i386/kvm.c | 8 +++ target-ppc/kvm.c| 8 +++ target-s390x/kvm.c | 8 +++ target-xtensa/xtensa-semi.c | 6 ++--- 20 files changed, 100 insertions(+), 84 deletions(-) diff --git a/cpus.c b/cpus.c index 84c3520..14f0f4f 100644 --- a/cpus.c +++ b/cpus.c @@ -1691,7 +1691,7 @@ void qmp_memsave(int64_t addr, int64_t size, const char *filename, l = sizeof(buf); if (l > size) l = size; -if (cpu_memory_rw_debug(cpu, addr, buf, l, 0) != 0) { +if (cpu_memory_rw_debug(cpu, addr, buf, l, MEMTX_READ) != 0) { error_setg(errp, "Invalid addr 0x%016" PRIx64 "/size %" PRId64 " specified", orig_addr, orig_size); goto exit; diff --git a/disas.c b/disas.c index 05a7a12..8ceeedb 100644 --- a/disas.c +++ b/disas.c @@ -39,7 +39,7 @@ target_read_memory (bfd_vma memaddr, { CPUDebug *s = container_of(info, CPUDebug, info); -cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0); +cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, MEMTX_READ); return 0; } @@ -358,7 +358,7 @@ monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length, if (monitor_disas_is_physical) { cpu_physical_memory_read(memaddr, myaddr, length); } else { -cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0); +cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, MEMTX_READ); } return 0; } diff --git a/exec.c b/exec.c index 0122ef7..048d3d0 100644 --- a/exec.c +++ b/exec.c @@ -2219,7 +2219,7 @@ static MemTxResult subpage_write(void *opaque, hwaddr addr, abort(); } return address_space_write(subpage->as, addr + subpage->base, - attrs, buf, len); + attrs, buf, len, false); } static bool subpage_accepts(void *opaque, hwaddr addr, @@ -2436,7 +2436,7 @@ MemoryRegion *get_system_io(void) /* physical memory access (slow version, mainly for debug) */ #if defined(CONFIG_USER_ONLY) int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr, -uint8_t *buf, int len, int is_write) +uint8_t *buf, int len, MemTxType type) { int l, flags; target_ulong page; @@ -2450,7 +2450,8 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr, flags = page_get_flags(page); if (!(flags & PAGE_VALID)) return -1; -if (is_write) { +if (type == MEMTX_WRITE || +type == MEMTX_PROGRAM) { if (!(flags & PAGE_WRITE)) return -1; /* XXX: this code should not depend on lock_user */ @@ -2552,7 +2553,8 @@ static MemTxResult address_space_write_continue(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, const uint8_t *buf, int len, hwaddr addr1, -hwaddr l, MemoryRegion *mr) +hwaddr l, MemoryRegion *mr, +bool force) { uint8_t *ptr; uint64_t val; @@ -2560,7 +2562,14 @@ static MemTxResult address_space_write_continue(AddressSpace *as, hwaddr addr, bool release_lock = false; for (;;) { -if (!memory_access_is_direct(mr, true)) { + +if (memory_access_is_direct(mr, true) || +(force && memory_region_is_romd(mr))) { +/* RAM case */ +ptr = qemu_map_ram_ptr(mr->ram_block, addr1); +memcpy(ptr, buf, l); +inv
Re: [Qemu-devel] [RFC PATCH] exec: Support non-direct memory writes in cpu_memory_rw_debug
On Wed, Jun 29, 2016 at 8:55 AM, Paolo Bonzini wrote: > On 28/06/2016 23:44, Andrey Smirnov wrote: >> Add code to support writing to memory mapped peripherals via >> cpu_memory_rw_debug(). The code of that function already supports >> reading from such memory regions, so this commit makes that >> functionality "symmetric". > > It's not entirely symmetric however, as you cannot write to the MMIO > registers of romd devices. Is this correct? So I'll leave to others > the review of whether the functionality is appropriate. What I meant by "symmetric" is that with that change address_space_rw is used in both code-paths: for reading and for writing. As for your question, I think so, the reason why I kept it that way was to preserve the old code's behavior (see cpu_physical_memory_write_rom_internal). However according to the comments/documentation in memory.h writes to ROM devices in ROMD and MMIO mode should always be handled via callbacks so there seem to be a contradiction there. I don't know QEMU codebase well enough to make a call on who's right, so I tried to keep the old behavior. > Regarding the code: > >> @@ -2621,7 +2625,7 @@ static MemTxResult >> address_space_write_continue(AddressSpace *as, hwaddr addr, >> } >> >> MemTxResult address_space_write(AddressSpace *as, hwaddr addr, MemTxAttrs >> attrs, >> -const uint8_t *buf, int len) >> +const uint8_t *buf, int len, bool force) > > I would prefer to leave this API as is, and instead add a new API such > as address_space_write_debug or address_space_program. It's okay to add > the "force" argument to address_space_write_continue. Having thought about that, I agree. Will update in v2. Andrey
Re: [Qemu-devel] [RFC PATCH] exec: Support non-direct memory writes in cpu_memory_rw_debug
On Thu, Jun 30, 2016 at 7:06 AM, Peter Maydell wrote: > On 28 June 2016 at 22:44, Andrey Smirnov wrote: >> Add code to support writing to memory mapped peripherals via >> cpu_memory_rw_debug(). The code of that function already supports >> reading from such memory regions, so this commit makes that >> functionality "symmetric". >> >> One use-case for that functionality is setting various registers of a >> non-running CPU. A concrete example would be starting QEMU emulating >> Cortex-M with -S, connecting with GDB and modifying the value of Vector >> Table Offset register. >> >> Signed-off-by: Andrey Smirnov > >> static uint16_t vring_used_idx(VirtQueue *vq) >> diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h >> index 9f38edf..d5b4966 100644 >> --- a/include/exec/cpu-all.h >> +++ b/include/exec/cpu-all.h >> @@ -302,6 +302,6 @@ void dump_opcount_info(FILE *f, fprintf_function >> cpu_fprintf); >> #endif /* !CONFIG_USER_ONLY */ >> >> int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr, >> -uint8_t *buf, int len, int is_write); >> +uint8_t *buf, int len, MemTxType type); >> >> #endif /* CPU_ALL_H */ >> diff --git a/include/exec/memory.h b/include/exec/memory.h >> index 4ab6800..8fbaf1b 100644 >> --- a/include/exec/memory.h >> +++ b/include/exec/memory.h >> @@ -14,6 +14,13 @@ >> #ifndef MEMORY_H >> #define MEMORY_H >> >> +typedef enum { >> +MEMTX_READ, >> +MEMTX_WRITE, >> +MEMTX_PROGRAM, >> +} MemTxType; > > We already have an enum for this: MMUAccessType. > That is currently unhelpfully located in cpu-common.h, but there's a > patch on list which should get applied soon which moves it to > include/qom/cpu.h: > http://patchwork.ozlabs.org/patch/635235/ > > >> + >> #ifndef CONFIG_USER_ONLY >> >> #define DIRTY_MEMORY_VGA 0 >> @@ -1240,6 +1247,7 @@ AddressSpace >> *address_space_init_shareable(MemoryRegion *root, >> */ >> void address_space_destroy(AddressSpace *as); >> >> + >> /** >> * address_space_rw: read from or write to an address space. >> * >> @@ -1251,11 +1259,11 @@ void address_space_destroy(AddressSpace *as); >> * @addr: address within that address space >> * @attrs: memory transaction attributes >> * @buf: buffer with the data transferred >> - * @is_write: indicates the transfer direction >> + * @type: indicates the transfer type >> */ >> MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, >> MemTxAttrs attrs, uint8_t *buf, >> - int len, bool is_write); >> + int len, MemTxType type); >> >> /** >> * address_space_write: write to address space. >> @@ -1268,10 +1276,11 @@ MemTxResult address_space_rw(AddressSpace *as, >> hwaddr addr, >> * @addr: address within that address space >> * @attrs: memory transaction attributes >> * @buf: buffer with the data transferred >> + * @force: force writing to ROM areas >> */ >> MemTxResult address_space_write(AddressSpace *as, hwaddr addr, >> MemTxAttrs attrs, >> -const uint8_t *buf, int len); >> +const uint8_t *buf, int len, bool force); >> >> /* address_space_ld*: load from an address space >> * address_space_st*: store to an address space > > I think this patch would be easier to review if it was > split up, something like: > * a patch which just converts the is_write bool parameter to the >enum and updates all the callers, with no change in behaviour > * a patch which makes use of the ability to pass in something other >than 0 or 1 > * a patch which adds and uses address_space_write_debug(), >or whatever API we go for > > The important bit is splitting the mechanical "convert bool > to enum" part (which touches lots of files but makes no > behaviour change) from the part which changes behaviour > and doesn't touch many files. OK, sounds good, will update in v2. Andrey
[Qemu-devel] [PATCH 09/17] imx_fec: Use correct length for packet size
Use 'frame_size' instead of 'len' when calling qemu_send_packet(), failing to do so results in malformed packets send in case when that packed is fragmented into multiple DMA transactions. Cc: Peter Maydell Cc: Jason Wang Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/net/imx_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 6045ffe673..c45b9648d9 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -532,7 +532,7 @@ static void imx_enet_do_tx(IMXFECState *s, uint32_t index) } } /* Last buffer in frame. */ -qemu_send_packet(qemu_get_queue(s->nic), frame, len); +qemu_send_packet(qemu_get_queue(s->nic), frame, frame_size); ptr = frame; frame_size = 0; if (bd.option & ENET_BD_TX_INT) { -- 2.13.5
[Qemu-devel] [PATCH 02/17] imx_fec: Do not calculate FEC
Save some computation time and avoid calculating CRC's frame Cc: Peter Maydell Cc: Jason Wang Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/net/imx_fec.c | 9 +++-- 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 88b4b049d7..75822344fc 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1032,9 +1032,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, IMXENETBufDesc 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; @@ -1048,8 +1046,6 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, /* 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 > ENET_MAX_FRAME_SIZE) { @@ -1090,9 +1086,10 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, dma_memory_write(&address_space_memory, buf_addr, buf, buf_len); buf += buf_len; if (size < 4) { +const uint8_t zeros[4] = { 0 }; + dma_memory_write(&address_space_memory, buf_addr + buf_len, - crc_ptr, 4 - size); -crc_ptr += 4 - size; + zeros, 4 - size); } bd.flags &= ~ENET_BD_E; if (size == 0) { -- 2.13.5
[Qemu-devel] [PATCH 00/17] Initial i.MX7 support
Hi everyone, This patch series contains the work that I've done in order to enable support for i.MX7 emulation in QEMU. Majority of the set are just odd fixes and small features implementation that I had to do to already exisitng code but last 5 commits contain new emulation code. As the one before last commit in the series states the supported i.MX7 features are: * up to 2 Cortex A9 cores (SMP works with PSCI) * A7 MPCORE (identical to A15 MPCORE) * 7 i.MX UARTs * 1 CCM device * 2 Ethernet controllers (FEC) * 3 SD controllers (USDHC) * 1 SNVS device * 1 WDT device I also have a follow up series that implements bit needes for PCIe emulation support (DesignWare IP emulation + supporting code) which I'll be submitting after this series is accepted. Feedback is welcome! Thanks, Andrey Smirnov Andrey Smirnov (17): imx_fec: Do not link to netdev imx_fec: Do not calculate FEC imx_fec: Refactor imx_eth_enable_rx() imx_fec: Change queue flushing heuristics imx_fec: Use ENET_FTRL to determine truncation length imx_fec: Use MIN instead of explicit ternary operator imx_fec: Emulate SHIFT16 in ENETx_RACC imx_fec: Add support for multiple Tx DMA rings imx_fec: Use correct length for packet size sdhci: Add i.MX specific subtype of SDHCI sdhci: Implement write method of ACMD12ERRSTS register i.MX: Add i.MX7 CCM, PMU and ANALOG device i.MX: Add code to emulate i.MX2 watchdog IP block i.MX7: Add code to emulate SNVS IP-block include/qemu: Add sizes.h from Linux i.MX: Add i.MX7 SOC implementation. Implement support for i.MX7 Sabre board default-configs/arm-softmmu.mak | 1 + hw/arm/Makefile.objs| 2 + hw/arm/fsl-imx6.c | 1 + hw/arm/fsl-imx7.c | 327 hw/arm/mcimx7d-sabre.c | 100 hw/misc/Makefile.objs | 3 + hw/misc/imx2_wdt.c | 117 ++ hw/misc/imx7_ccm.c | 201 hw/misc/imx7_snvs.c | 84 +++ hw/net/imx_fec.c| 153 ++- hw/sd/sdhci-internal.h | 15 ++ hw/sd/sdhci.c | 126 +++- include/hw/arm/fsl-imx7.h | 114 ++ include/hw/misc/imx2_wdt.h | 36 + include/hw/misc/imx7_ccm.h | 76 ++ include/hw/misc/imx7_snvs.h | 35 + include/hw/net/imx_fec.h| 26 +++- include/hw/sd/sdhci.h | 8 + include/qemu/sizes.h| 47 ++ 19 files changed, 1433 insertions(+), 39 deletions(-) create mode 100644 hw/arm/fsl-imx7.c create mode 100644 hw/arm/mcimx7d-sabre.c create mode 100644 hw/misc/imx2_wdt.c create mode 100644 hw/misc/imx7_ccm.c create mode 100644 hw/misc/imx7_snvs.c create mode 100644 include/hw/arm/fsl-imx7.h create mode 100644 include/hw/misc/imx2_wdt.h create mode 100644 include/hw/misc/imx7_ccm.h create mode 100644 include/hw/misc/imx7_snvs.h create mode 100644 include/qemu/sizes.h -- 2.13.5
[Qemu-devel] [PATCH 05/17] imx_fec: Use ENET_FTRL to determine truncation length
Frame truncation length, TRUNC_FL, is determined by the contents of ENET_FTRL register, so convert the code to use it instead of a hardcoded constant. Cc: Peter Maydell Cc: Jason Wang Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/net/imx_fec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 767402909d..989c11be5f 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1050,8 +1050,8 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, size += 4; /* Huge frames are truncted. */ -if (size > ENET_MAX_FRAME_SIZE) { -size = ENET_MAX_FRAME_SIZE; +if (size > s->regs[ENET_FTRL]) { +size = s->regs[ENET_FTRL]; flags |= ENET_BD_TR | ENET_BD_LG; } -- 2.13.5
[Qemu-devel] [PATCH 07/17] imx_fec: Emulate SHIFT16 in ENETx_RACC
Needed to support latest Linux kernel driver which relies on that functionality. Cc: Peter Maydell Cc: Jason Wang Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/net/imx_fec.c | 23 +++ include/hw/net/imx_fec.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 8a77136d38..bd62d7a75f 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1037,6 +1037,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, uint32_t buf_addr; unsigned int buf_len; size_t size = len; +bool shift16 = s->regs[ENET_RACC] & ENET_RACC_SHIFT16; FEC_PRINTF("len %d\n", (int)size); @@ -1049,6 +1050,10 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, /* 4 bytes for the CRC. */ size += 4; +if (shift16) { +size += 2; +} + /* Huge frames are truncted. */ if (size > s->regs[ENET_FTRL]) { size = s->regs[ENET_FTRL]; @@ -1085,6 +1090,24 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, buf_len += size - 4; } buf_addr = bd.data; + +if (shift16) { +/* + * If SHIFT16 bit of ENETx_RACC register is set we need to + * align the payload to 4-byte boundary. + */ +const uint8_t zeros[2] = { 0 }; + +dma_memory_write(&address_space_memory, buf_addr, + zeros, sizeof(zeros)); + +buf_addr += sizeof(zeros); +buf_len -= sizeof(zeros); + +shift16 = false; /* We only do this once per Ethernet + * frame */ +} + dma_memory_write(&address_space_memory, buf_addr, buf, buf_len); buf += buf_len; if (size < 4) { diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h index 4bc8f03ec2..20a6aa98b4 100644 --- a/include/hw/net/imx_fec.h +++ b/include/hw/net/imx_fec.h @@ -169,6 +169,8 @@ #define ENET_TWFR_TFWR_LENGTH (6) #define ENET_TWFR_STRFWD (1 << 8) +#define ENET_RACC_SHIFT16 BIT(7) + /* Buffer Descriptor. */ typedef struct { uint16_t length; -- 2.13.5
[Qemu-devel] [PATCH 10/17] sdhci: Add i.MX specific subtype of SDHCI
IP block found on several generations of i.MX family does not use vanilla SDHCI implementation and it comes with a number of quirks. Introduce i.MX SDHCI subtype of SDHCI block to add code necessary to support unmodified Linux guest driver. Cc: Peter Maydell Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/sd/sdhci-internal.h | 15 ++ hw/sd/sdhci.c | 123 - include/hw/sd/sdhci.h | 8 3 files changed, 144 insertions(+), 2 deletions(-) diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h index 161177cf39..7b9ed06c36 100644 --- a/hw/sd/sdhci-internal.h +++ b/hw/sd/sdhci-internal.h @@ -91,6 +91,8 @@ #define SDHC_CTRL_ADMA2_32 0x10 #define SDHC_CTRL_ADMA2_64 0x18 #define SDHC_DMA_TYPE(x) ((x) & SDHC_CTRL_DMA_CHECK_MASK) +#define SDHC_CTRL_4BITBUS 0x02 +#define SDHC_CTRL_8BITBUS 0x20 /* R/W Power Control Register 0x0 */ #define SDHC_PWRCON0x29 @@ -229,4 +231,17 @@ enum { extern const VMStateDescription sdhci_vmstate; + +#define ESDHC_MIX_CTRL 0x48 +#define ESDHC_VENDOR_SPEC 0xc0 +#define ESDHC_DLL_CTRL 0x60 + +#define ESDHC_TUNING_CTRL 0xcc +#define ESDHC_TUNE_CTRL_STATUS 0x68 +#define ESDHC_WTMK_LVL 0x44 + +#define ESDHC_CTRL_4BITBUS (0x1 << 1) +#define ESDHC_CTRL_8BITBUS (0x2 << 1) + + #endif diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 6d6a791ee9..73e7910ba9 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -265,7 +265,8 @@ static void sdhci_send_command(SDHCIState *s) } } -if ((s->norintstsen & SDHC_NISEN_TRSCMP) && +if (!(s->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) && +(s->norintstsen & SDHC_NISEN_TRSCMP) && (s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY) { s->norintsts |= SDHC_NIS_TRSCMP; } @@ -1191,6 +1192,8 @@ static void sdhci_initfn(SDHCIState *s) s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_raise_insertion_irq, s); s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s); + +s->io_ops = &sdhci_mmio_ops; } static void sdhci_uninitfn(SDHCIState *s) @@ -1347,7 +1350,7 @@ static void sdhci_sysbus_realize(DeviceState *dev, Error ** errp) s->buf_maxsz = sdhci_get_fifolen(s); s->fifo_buffer = g_malloc0(s->buf_maxsz); sysbus_init_irq(sbd, &s->irq); -memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci", +memory_region_init_io(&s->iomem, OBJECT(s), s->io_ops, s, "sdhci", SDHC_REGISTERS_MAP_SIZE); sysbus_init_mmio(sbd, &s->iomem); } @@ -1386,11 +1389,127 @@ static const TypeInfo sdhci_bus_info = { .class_init = sdhci_bus_class_init, }; +static uint64_t usdhc_read(void *opaque, hwaddr offset, unsigned size) +{ +SDHCIState *s = SYSBUS_SDHCI(opaque); +uint32_t ret; +uint16_t hostctl; + +switch (offset) { +default: +return sdhci_read(opaque, offset, size); + +case SDHC_HOSTCTL: +hostctl = SDHC_DMA_TYPE(s->hostctl) << 5; + +if (s->hostctl & SDHC_CTRL_8BITBUS) +hostctl |= ESDHC_CTRL_8BITBUS; + +if (s->hostctl & SDHC_CTRL_4BITBUS) +hostctl |= ESDHC_CTRL_4BITBUS; + +ret = hostctl | (s->blkgap << 16) | +(s->wakcon << 24); + +break; + +case ESDHC_DLL_CTRL: +case ESDHC_TUNE_CTRL_STATUS: +case 0x6c: +case ESDHC_TUNING_CTRL: +case ESDHC_VENDOR_SPEC: +case ESDHC_MIX_CTRL: +case ESDHC_WTMK_LVL: +ret = 0; +break; +} + +return ret; +} + +static void +usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) +{ +SDHCIState *s = SYSBUS_SDHCI(opaque); +uint8_t hostctl = 0; +uint32_t value = (uint32_t)val; + +switch (offset) { +case ESDHC_DLL_CTRL: +case ESDHC_TUNE_CTRL_STATUS: +case 0x6c: +case ESDHC_TUNING_CTRL: +case ESDHC_WTMK_LVL: +case ESDHC_VENDOR_SPEC: +break; + +case SDHC_HOSTCTL: +if (value & ESDHC_CTRL_8BITBUS) +hostctl |= SDHC_CTRL_8BITBUS; + +if (value & ESDHC_CTRL_4BITBUS) +hostctl |= ESDHC_CTRL_4BITBUS; + +hostctl |= SDHC_DMA_TYPE(value >> 5); + +value &= ~0xFE; +value |= hostctl; +value &= ~0xFF00; +value |= s->pwrcon; + +sdhci_write(opaque, offset, value, size); +break; + +case ESDHC_MIX_CTRL: +/* + * The layout of the register is slightly different, but we + * don't care about those bits +
[Qemu-devel] [PATCH 03/17] imx_fec: Refactor imx_eth_enable_rx()
Refactor imx_eth_enable_rx() to have more meaningfull variable name than 'tmp' and to reduce number of logical negations done. Cc: Peter Maydell Cc: Jason Wang Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/net/imx_fec.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 75822344fc..84085afe09 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -536,19 +536,19 @@ static void imx_eth_do_tx(IMXFECState *s) static void imx_eth_enable_rx(IMXFECState *s) { IMXFECBufDesc bd; -bool tmp; +bool rx_ring_full; imx_fec_read_bd(&bd, s->rx_descriptor); -tmp = ((bd.flags & ENET_BD_E) != 0); +rx_ring_full = !(bd.flags & ENET_BD_E); -if (!tmp) { +if (rx_ring_full) { FEC_PRINTF("RX buffer full\n"); } else if (!s->regs[ENET_RDAR]) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } -s->regs[ENET_RDAR] = tmp ? ENET_RDAR_RDAR : 0; +s->regs[ENET_RDAR] = rx_ring_full ? 0 : ENET_RDAR_RDAR; } static void imx_eth_reset(DeviceState *d) -- 2.13.5
[Qemu-devel] [PATCH 04/17] imx_fec: Change queue flushing heuristics
In current implementation, packet queue flushing logic seem to suffer from a deadlock like scenario if a packet is received by the interface before before Rx ring is initialized by Guest's driver. Consider the following sequence of events: 1. A QEMU instance is started against a TAP device on Linux host, running Linux guest, e. g., something to the effect of: qemu-system-arm \ -net nic,model=imx.fec,netdev=lan0 \ netdev tap,id=lan0,ifname=tap0,script=no,downscript=no \ ... rest of the arguments ... 2. Once QEMU starts, but before guest reaches the point where FEC deriver is done initializing the HW, Guest, via TAP interface, receives a number of multicast MDNS packets from Host (not necessarily true for every OS, but it happens at least on Fedora 25) 3. Recieving a packet in such a state results in imx_eth_can_receive() returning '0', which in turn causes tap_send() to disable corresponding event (tap.c:203) 4. Once Guest's driver reaches the point where it is ready to recieve packets it prepares Rx ring descriptors and writes ENET_RDAR_RDAR to ENET_RDAR register to indicate to HW that more descriptors are ready. And at this points emulation layer does this: s->regs[index] = ENET_RDAR_RDAR; imx_eth_enable_rx(s); which, combined with: if (!s->regs[ENET_RDAR]) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } results in Rx queue never being flushed and corresponding I/O event beign disabled. Change the code to remember the fact that can_receive callback was called before Rx ring was ready and use it to make a decision if receive queue needs to be flushed. Cc: Peter Maydell Cc: Jason Wang Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/net/imx_fec.c | 6 -- include/hw/net/imx_fec.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 84085afe09..767402909d 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -544,8 +544,9 @@ static void imx_eth_enable_rx(IMXFECState *s) if (rx_ring_full) { FEC_PRINTF("RX buffer full\n"); -} else if (!s->regs[ENET_RDAR]) { +} else if (s->needs_flush) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); +s->needs_flush = false; } s->regs[ENET_RDAR] = rx_ring_full ? 0 : ENET_RDAR_RDAR; @@ -930,7 +931,8 @@ static int imx_eth_can_receive(NetClientState *nc) FEC_PRINTF("\n"); -return s->regs[ENET_RDAR] ? 1 : 0; +s->needs_flush = !s->regs[ENET_RDAR]; +return !!s->regs[ENET_RDAR]; } static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h index 62ad473b05..4bc8f03ec2 100644 --- a/include/hw/net/imx_fec.h +++ b/include/hw/net/imx_fec.h @@ -252,6 +252,7 @@ typedef struct IMXFECState { uint32_t phy_int_mask; bool is_fec; +bool needs_flush; } IMXFECState; #endif -- 2.13.5
[Qemu-devel] [PATCH 11/17] sdhci: Implement write method of ACMD12ERRSTS register
Cc: Peter Maydell Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/sd/sdhci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 73e7910ba9..9249471957 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1139,6 +1139,9 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) s->admasysaddr = (s->admasysaddr & (0xULL | ((uint64_t)mask << 32))) | ((uint64_t)value << 32); break; +case SDHC_ACMD12ERRSTS: +MASKED_WRITE(s->acmd12errsts, mask, value); +break; case SDHC_FEAER: s->acmd12errsts |= value; s->errintsts |= (value >> 16) & s->errintstsen; -- 2.13.5
[Qemu-devel] [PATCH 17/17] Implement support for i.MX7 Sabre board
Cc: Peter Maydell Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/arm/Makefile.objs | 2 +- hw/arm/mcimx7d-sabre.c | 100 + 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 hw/arm/mcimx7d-sabre.c diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 33f6051ae3..fc4a963de8 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -19,5 +19,5 @@ obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o obj-$(CONFIG_MPS2) += mps2.o -obj-$(CONFIG_FSL_IMX7) += fsl-imx7.o +obj-$(CONFIG_FSL_IMX7) += fsl-imx7.o mcimx7d-sabre.o diff --git a/hw/arm/mcimx7d-sabre.c b/hw/arm/mcimx7d-sabre.c new file mode 100644 index 00..34e3933db8 --- /dev/null +++ b/hw/arm/mcimx7d-sabre.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * MCIMX7D_SABRE Board System emulation. + * + * Author: Andrey Smirnov + * + * This code is licensed under the GPL, version 2 or later. + * See the file `COPYING' in the top level directory. + * + * It (partially) emulates a mcimx7d_sabre board, with a Freescale + * i.MX7 SoC + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "hw/arm/fsl-imx7.h" +#include "hw/boards.h" +#include "sysemu/sysemu.h" +#include "sysemu/device_tree.h" +#include "qemu/error-report.h" +#include "sysemu/qtest.h" +#include "net/net.h" + +typedef struct { +FslIMX7State soc; +MemoryRegion ram; +} MCIMX7Sabre; + +static void mcimx7d_add_psci_node(const struct arm_boot_info *boot_info, void *fdt) +{ +const char comp[] = "arm,psci-0.2\0arm,psci"; + +qemu_fdt_add_subnode(fdt, "/psci"); +qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp)); +qemu_fdt_setprop_string(fdt, "/psci", "method", "smc"); +} + +static void mcimx7d_sabre_init(MachineState *machine) +{ +static struct arm_boot_info boot_info; +MCIMX7Sabre *s = g_new0(MCIMX7Sabre, 1); +Object *soc; +int i; + +if (machine->ram_size > FSL_IMX7_MMDC_SIZE) { +error_report("RAM size " RAM_ADDR_FMT " above max supported (%08x)", + machine->ram_size, FSL_IMX7_MMDC_SIZE); +exit(1); +} + +boot_info = (struct arm_boot_info) { +.loader_start = FSL_IMX7_MMDC_ADDR, +.board_id = -1, +.ram_size = machine->ram_size, +.kernel_filename = machine->kernel_filename, +.kernel_cmdline = machine->kernel_cmdline, +.initrd_filename = machine->initrd_filename, +.nb_cpus = smp_cpus, +.modify_dtb = mcimx7d_add_psci_node, +}; + +object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX7); +soc = OBJECT(&s->soc); +object_property_add_child(OBJECT(machine), "soc", soc, &error_fatal); +object_property_set_bool(soc, true, "realized", &error_fatal); + +memory_region_allocate_system_memory(&s->ram, NULL, "mcimx7d-sabre.ram", + machine->ram_size); +memory_region_add_subregion(get_system_memory(), +FSL_IMX7_MMDC_ADDR, &s->ram); + +for (i = 0; i < FSL_IMX7_NUM_USDHCS; i++) { +BusState *bus; +DeviceState *carddev; +DriveInfo *di; +BlockBackend *blk; + +di = drive_get_next(IF_SD); +blk = di ? blk_by_legacy_dinfo(di) : NULL; +bus = qdev_get_child_bus(DEVICE(&s->soc.usdhc[i]), "sd-bus"); +carddev = qdev_create(bus, TYPE_SD_CARD); +qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); +object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal); +} + +if (!qtest_enabled()) { +arm_load_kernel(&s->soc.cpu[0], &boot_info); +} +} + +static void mcimx7d_sabre_machine_init(MachineClass *mc) +{ +mc->desc = "Freescale i.MX7 DUAL SABRE (Cortex A7)"; +mc->init = mcimx7d_sabre_init; +mc->max_cpus = FSL_IMX7_NUM_CPUS; +mc->ignore_memory_transaction_failures = true; +} +DEFINE_MACHINE("mcimx7d-sabre", mcimx7d_sabre_machine_init) -- 2.13.5
[Qemu-devel] [PATCH 01/17] imx_fec: Do not link to netdev
Binding to a particular netdev doesn't seem to belong to this layer and should probably be done as a part of board or SoC specific code. Convert all of the users of this IP block to use qdev_set_nic_properties() instead. Cc: Peter Maydell Cc: Jason Wang Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/arm/fsl-imx6.c | 1 + hw/net/imx_fec.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index 26fd214004..2ed7146c52 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -385,6 +385,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) spi_table[i].irq)); } +qdev_set_nic_properties(DEVICE(&s->eth), &nd_table[0]); object_property_set_bool(OBJECT(&s->eth), true, "realized", &err); if (err) { error_propagate(errp, err); diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 90e6ee35ba..88b4b049d7 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1171,8 +1171,6 @@ static void imx_eth_realize(DeviceState *dev, Error **errp) qemu_macaddr_default_if_unset(&s->conf.macaddr); -s->conf.peers.ncs[0] = nd_table[0].netdev; - s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf, object_get_typename(OBJECT(dev)), DEVICE(dev)->id, s); -- 2.13.5
[Qemu-devel] [PATCH 06/17] imx_fec: Use MIN instead of explicit ternary operator
Cc: Peter Maydell Cc: Jason Wang Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/net/imx_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 989c11be5f..8a77136d38 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1074,7 +1074,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, TYPE_IMX_FEC, __func__); break; } -buf_len = (size <= s->regs[ENET_MRBR]) ? size : s->regs[ENET_MRBR]; +buf_len = MIN(size, s->regs[ENET_MRBR]); bd.length = buf_len; size -= buf_len; -- 2.13.5
[Qemu-devel] [PATCH 14/17] i.MX7: Add code to emulate SNVS IP-block
Add code to emulate SNVS IP-block. Currently only the bits needed to be able to emulate machine shutdown are implemented. Cc: Peter Maydell Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/misc/Makefile.objs | 1 + hw/misc/imx7_snvs.c | 84 + include/hw/misc/imx7_snvs.h | 35 +++ 3 files changed, 120 insertions(+) create mode 100644 hw/misc/imx7_snvs.c create mode 100644 include/hw/misc/imx7_snvs.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index c393a93456..16cee88e0f 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -36,6 +36,7 @@ obj-$(CONFIG_IMX) += imx6_ccm.o obj-$(CONFIG_IMX) += imx6_src.o obj-$(CONFIG_IMX) += imx7_ccm.o obj-$(CONFIG_IMX) += imx2_wdt.o +obj-$(CONFIG_IMX) += imx7_snvs.o obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o obj-$(CONFIG_MAINSTONE) += mst_fpga.o diff --git a/hw/misc/imx7_snvs.c b/hw/misc/imx7_snvs.c new file mode 100644 index 00..efce0a760f --- /dev/null +++ b/hw/misc/imx7_snvs.c @@ -0,0 +1,84 @@ +/* + * IMX7 Secure Non-Volatile Storage + * + * Copyright (c) 2017, Impinj, Inc. + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * Bare minimum emulation code needed to support being able to shut + * down linux guest gracefully. + */ + +#include "qemu/osdep.h" +#include "qemu/sizes.h" +#include "hw/misc/imx7_snvs.h" +#include "qemu/log.h" +#include "sysemu/sysemu.h" + +static uint64_t imx7_snvs_read(void *opaque, hwaddr offset, unsigned size) +{ +return 0; +} + +static void imx7_snvs_write(void *opaque, hwaddr offset, +uint64_t v, unsigned size) +{ +const uint32_t value = v; +const uint32_t mask = SNVS_LPCR_TOP | SNVS_LPCR_DP_EN; + +if (offset == SNVS_LPCR && ((value & mask) == mask)) { +qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); +} +} + +static const struct MemoryRegionOps imx7_snvs_ops = { +.read = imx7_snvs_read, +.write = imx7_snvs_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.valid = { +/* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ +.min_access_size = 4, +.max_access_size = 4, +.unaligned = false, +}, +}; + +static void imx7_snvs_init(Object *obj) +{ +SysBusDevice *sd = SYS_BUS_DEVICE(obj); +IMX7SNVSState *s = IMX7_SNVS(obj); + +memory_region_init_io(&s->mmio, obj, &imx7_snvs_ops, s, + TYPE_IMX7_SNVS, 0x1000); + +sysbus_init_mmio(sd, &s->mmio); +} + +static void imx7_snvs_class_init(ObjectClass *klass, void *data) +{ +DeviceClass *dc = DEVICE_CLASS(klass); + +dc->desc = "i.MX7 Secure Non-Volatile Storage Module"; +} + +static const TypeInfo imx7_snvs_info = { +.name = TYPE_IMX7_SNVS, +.parent= TYPE_SYS_BUS_DEVICE, +.instance_size = sizeof(IMX7SNVSState), +.instance_init = imx7_snvs_init, +.class_init= imx7_snvs_class_init, +}; + +static void imx7_snvs_register_type(void) +{ +type_register_static(&imx7_snvs_info); +} +type_init(imx7_snvs_register_type) diff --git a/include/hw/misc/imx7_snvs.h b/include/hw/misc/imx7_snvs.h new file mode 100644 index 00..255f8f26f9 --- /dev/null +++ b/include/hw/misc/imx7_snvs.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX7 SNVS block emulation code + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef IMX7_SNVS_H +#define IMX7_SNVS_H + +#include "qemu/bitops.h" +#include "hw/sysbus.h" + + +enum IMX7SNVSRegisters { +SNVS_LPCR = 0x38, +SNVS_LPCR_TOP = BIT(6), +SNVS_LPCR_DP_EN = BIT(5) +}; + +#define TYPE_IMX7_SNVS "imx7.snvs" +#define IMX7_SNVS(obj) OBJECT_CHECK(IMX7SNVSState, (obj), TYPE_IMX7_SNVS) + +typedef struct IMX7SNVSState { +/* */ +SysBusDevice parent_obj; + +MemoryRegion mmio; +} IMX7SNVSState; + +#endif /* IMX7_SNVS_H */ -- 2.13.5
[Qemu-devel] [PATCH 08/17] imx_fec: Add support for multiple Tx DMA rings
More recent version of the IP block support more than one Tx DMA ring, so add the code implementing that feature. Cc: Peter Maydell Cc: Jason Wang Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/net/imx_fec.c | 97 +++- include/hw/net/imx_fec.h | 23 +++- 2 files changed, 101 insertions(+), 19 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index bd62d7a75f..6045ffe673 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -196,6 +196,17 @@ static const char *imx_eth_reg_name(IMXFECState *s, uint32_t index) } } +static const VMStateDescription vmstate_imx_eth_tx_ring = { +.name = "fec-tx-ring", +.version_id = 1, +.minimum_version_id = 1, +.fields = (VMStateField[]) { +VMSTATE_UINT32(descriptor, IMXFECTxRing), +VMSTATE_UINT32(tdsr, IMXFECTxRing), +VMSTATE_END_OF_LIST() +}, +}; + static const VMStateDescription vmstate_imx_eth = { .name = TYPE_IMX_FEC, .version_id = 2, @@ -203,8 +214,10 @@ static const VMStateDescription vmstate_imx_eth = { .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX), VMSTATE_UINT32(rx_descriptor, IMXFECState), -VMSTATE_UINT32(tx_descriptor, IMXFECState), - +VMSTATE_STRUCT_ARRAY(tx_ring, IMXFECState, + ENET_TX_RING_NUM, + 1, vmstate_imx_eth_tx_ring, + IMXFECTxRing), VMSTATE_UINT32(phy_status, IMXFECState), VMSTATE_UINT32(phy_control, IMXFECState), VMSTATE_UINT32(phy_advertise, IMXFECState), @@ -407,7 +420,7 @@ static void imx_fec_do_tx(IMXFECState *s) int frame_size = 0, descnt = 0; uint8_t frame[ENET_MAX_FRAME_SIZE]; uint8_t *ptr = frame; -uint32_t addr = s->tx_descriptor; +uint32_t addr = s->tx_ring[0].descriptor; while (descnt++ < IMX_MAX_DESC) { IMXFECBufDesc bd; @@ -448,17 +461,38 @@ static void imx_fec_do_tx(IMXFECState *s) } } -s->tx_descriptor = addr; +s->tx_ring[0].descriptor = addr; imx_eth_update(s); } -static void imx_enet_do_tx(IMXFECState *s) +static void imx_enet_do_tx(IMXFECState *s, uint32_t index) { int frame_size = 0, descnt = 0; uint8_t frame[ENET_MAX_FRAME_SIZE]; uint8_t *ptr = frame; -uint32_t addr = s->tx_descriptor; +IMXFECTxRing *ring; +uint32_t addr; + +switch (index) { +case ENET_TDAR: +ring = &s->tx_ring[0]; +break; +case ENET_TDAR1: +ring = &s->tx_ring[1]; +break; +case ENET_TDAR2: +ring = &s->tx_ring[2]; +break; +default: +qemu_log_mask(LOG_GUEST_ERROR, + "%s: bogus value for index %x\n", + __func__, index); +abort(); +break; +} + +addr = ring->descriptor; while (descnt++ < IMX_MAX_DESC) { IMXENETBufDesc bd; @@ -502,32 +536,32 @@ static void imx_enet_do_tx(IMXFECState *s) ptr = frame; frame_size = 0; if (bd.option & ENET_BD_TX_INT) { -s->regs[ENET_EIR] |= ENET_INT_TXF; +s->regs[ENET_EIR] |= ring->int_txf; } } if (bd.option & ENET_BD_TX_INT) { -s->regs[ENET_EIR] |= ENET_INT_TXB; +s->regs[ENET_EIR] |= ring->int_txb; } bd.flags &= ~ENET_BD_R; /* Write back the modified descriptor. */ imx_enet_write_bd(&bd, addr); /* Advance to the next descriptor. */ if ((bd.flags & ENET_BD_W) != 0) { -addr = s->regs[ENET_TDSR]; +addr = s->regs[ring->tdsr]; } else { addr += sizeof(bd); } } -s->tx_descriptor = addr; +ring->descriptor = addr; imx_eth_update(s); } -static void imx_eth_do_tx(IMXFECState *s) +static void imx_eth_do_tx(IMXFECState *s, uint32_t index) { if (!s->is_fec && (s->regs[ENET_ECR] & ENET_ECR_EN1588)) { -imx_enet_do_tx(s); +imx_enet_do_tx(s, index); } else { imx_fec_do_tx(s); } @@ -586,7 +620,22 @@ static void imx_eth_reset(DeviceState *d) } s->rx_descriptor = 0; -s->tx_descriptor = 0; + +s->tx_ring[0].tdsr = ENET_TDSR; +s->tx_ring[1].tdsr = ENET_TDSR1; +s->tx_ring[2].tdsr = ENET_TDSR2; + +s->tx_ring[0].int_txf = ENET_INT_TXF; +s->tx_ring[1].int_txf = ENET_INT_TXF1; +s->tx_ring[2].int_txf = ENET_INT_TXF2; + +s->tx_ring[0].int_txb = ENET_INT_TXB; +s->tx_ring[1].int_txb = ENET_INT_TXB1; +s->tx_ring[2].int_txb = ENET_INT_TXB2; + +s->tx_ring[0].descriptor = 0; +s->tx_ring[1].descriptor = 0; +s
[Qemu-devel] [PATCH 15/17] include/qemu: Add sizes.h from Linux
Add sizes.h from Linux to have a more readable way of specifying MemoryRegion sizes. Cc: Peter Maydell Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- include/qemu/sizes.h | 47 +++ 1 file changed, 47 insertions(+) create mode 100644 include/qemu/sizes.h diff --git a/include/qemu/sizes.h b/include/qemu/sizes.h new file mode 100644 index 00..9aedb9f8f6 --- /dev/null +++ b/include/qemu/sizes.h @@ -0,0 +1,47 @@ +/* + * Copy of include/linux/sizes.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef SIZES_H +#define SIZES_H + +#define SZ_1 0x0001 +#define SZ_2 0x0002 +#define SZ_4 0x0004 +#define SZ_8 0x0008 +#define SZ_16 0x0010 +#define SZ_32 0x0020 +#define SZ_64 0x0040 +#define SZ_128 0x0080 +#define SZ_256 0x0100 +#define SZ_512 0x0200 + +#define SZ_1K 0x0400 +#define SZ_2K 0x0800 +#define SZ_4K 0x1000 +#define SZ_8K 0x2000 +#define SZ_16K 0x4000 +#define SZ_32K 0x8000 +#define SZ_64K 0x0001 +#define SZ_128K0x0002 +#define SZ_256K0x0004 +#define SZ_512K0x0008 + +#define SZ_1M 0x0010 +#define SZ_2M 0x0020 +#define SZ_4M 0x0040 +#define SZ_8M 0x0080 +#define SZ_16M 0x0100 +#define SZ_32M 0x0200 +#define SZ_64M 0x0400 +#define SZ_128M0x0800 +#define SZ_256M0x1000 +#define SZ_512M0x2000 + +#define SZ_1G 0x4000 +#define SZ_2G 0x8000 + +#endif /* SIZES_H */ -- 2.13.5
[Qemu-devel] [PATCH 16/17] i.MX: Add i.MX7 SOC implementation.
For now we only support the following devices: * up to 2 Cortex A9 cores (SMP works with PSCI) * A7 MPCORE (identical to A15 MPCORE) * 7 i.MX UARTs * 1 CCM device * 2 Ethernet controllers (FEC) * 3 SD controllers (USDHC) * 1 SNVS device * 1 WDT device Cc: Peter Maydell Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- default-configs/arm-softmmu.mak | 1 + hw/arm/Makefile.objs| 2 + hw/arm/fsl-imx7.c | 327 include/hw/arm/fsl-imx7.h | 114 ++ 4 files changed, 444 insertions(+) create mode 100644 hw/arm/fsl-imx7.c create mode 100644 include/hw/arm/fsl-imx7.h diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index bbdd3c1d8b..98396a3ad2 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -118,6 +118,7 @@ CONFIG_ALLWINNER_A10=y CONFIG_FSL_IMX6=y CONFIG_FSL_IMX31=y CONFIG_FSL_IMX25=y +CONFIG_FSL_IMX7=y CONFIG_IMX_I2C=y diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index a2e56ecaae..33f6051ae3 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -19,3 +19,5 @@ obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o obj-$(CONFIG_MPS2) += mps2.o +obj-$(CONFIG_FSL_IMX7) += fsl-imx7.o + diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c new file mode 100644 index 00..bd01bb7f59 --- /dev/null +++ b/hw/arm/fsl-imx7.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX7 SoC definitions + * + * Author: Andrey Smirnov + * + * Based on hw/arm/fsl-imx6.c + * + * 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; version 2 of the License. + * + * 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. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "hw/arm/fsl-imx7.h" +#include "sysemu/sysemu.h" +#include "qemu/error-report.h" + +#define NAME_SIZE 20 + +#define for_each_cpu(i) for (i = 0; i < smp_cpus; i++) + +static void fsl_imx7_init(Object *obj) +{ +BusState *sysbus = sysbus_get_default(); +FslIMX7State *s = FSL_IMX7(obj); +char name[NAME_SIZE]; +int i; + +if (smp_cpus > FSL_IMX7_NUM_CPUS) { +error_report("%s: Only %d CPUs are supported (%d requested)", + TYPE_FSL_IMX7, FSL_IMX7_NUM_CPUS, smp_cpus); +exit(1); +} + +for_each_cpu(i) { +object_initialize(&s->cpu[i], sizeof(s->cpu[i]), + "cortex-a7-" TYPE_ARM_CPU); +snprintf(name, NAME_SIZE, "cpu%d", i); +object_property_add_child(obj, name, OBJECT(&s->cpu[i]), + &error_fatal); +} + +/* + * A7MPCORE + */ +object_initialize(&s->a7mpcore, sizeof(s->a7mpcore), TYPE_A15MPCORE_PRIV); +qdev_set_parent_bus(DEVICE(&s->a7mpcore), sysbus); +object_property_add_child(obj, "a7mpcore", + OBJECT(&s->a7mpcore), &error_fatal); + +/* + * CCM + */ +object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX7_CCM); +qdev_set_parent_bus(DEVICE(&s->ccm), sysbus); +object_property_add_child(obj, "ccm", OBJECT(&s->ccm), &error_fatal); + +/* + * UART + */ +for (i = 0; i < FSL_IMX7_NUM_UARTS; i++) { +object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_IMX_SERIAL); +qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus); +snprintf(name, NAME_SIZE, "uart%d", i); +object_property_add_child(obj, name, OBJECT(&s->uart[i]), + &error_fatal); +} + +/* + * Ethernet + */ +for (i = 0; i < FSL_IMX7_NUM_ETHS; i++) { +object_initialize(&s->eth[i], sizeof(s->eth[i]), TYPE_IMX_ENET); +qdev_set_parent_bus(DEVICE(&s->eth[i]), sysbus); +snprintf(name, NAME_SIZE, "eth%d", i); +object_property_add_child(obj, name, OBJECT(&s->eth[i]), + &error_fatal); +} + +/* + * SDHCI + */ +for (i = 0; i < FSL_IMX7_NUM_USDHCS; i++) { +object_initialize(&s->usdhc[i], sizeof(s->usdhc[i]), + TYPE_IMX_USDHC); +qdev_se
[Qemu-devel] [PATCH 13/17] i.MX: Add code to emulate i.MX2 watchdog IP block
Add enough code to emulate i.MX2 watchdog IP block so it would be possible to reboot the machine running Linux Guest. Cc: Peter Maydell Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/misc/Makefile.objs | 1 + hw/misc/imx2_wdt.c | 117 + include/hw/misc/imx2_wdt.h | 36 ++ 3 files changed, 154 insertions(+) create mode 100644 hw/misc/imx2_wdt.c create mode 100644 include/hw/misc/imx2_wdt.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index ac1be05a03..c393a93456 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -35,6 +35,7 @@ obj-$(CONFIG_IMX) += imx25_ccm.o obj-$(CONFIG_IMX) += imx6_ccm.o obj-$(CONFIG_IMX) += imx6_src.o obj-$(CONFIG_IMX) += imx7_ccm.o +obj-$(CONFIG_IMX) += imx2_wdt.o obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o obj-$(CONFIG_MAINSTONE) += mst_fpga.o diff --git a/hw/misc/imx2_wdt.c b/hw/misc/imx2_wdt.c new file mode 100644 index 00..9d97a19511 --- /dev/null +++ b/hw/misc/imx2_wdt.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX2 Watchdog IP block + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "hw/hw.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" +#include "hw/sysbus.h" +#include "qemu/log.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" +#include "sysemu/watchdog.h" +#include "qemu/error-report.h" +#include "qemu/sizes.h" + +#include "hw/misc/imx2_wdt.h" + + +#define IMX2_WDT_WCR_WDA BIT(5) /* -> External Reset WDOG_B */ +#define IMX2_WDT_WCR_SRS BIT(4) /* -> Software Reset Signal */ + +static uint64_t imx2_wdt_read(void *opaque, hwaddr addr, + unsigned int size) +{ +IMX2WdtState *s = opaque; +const size_t index = addr / sizeof(s->reg[0]); + +if (index < ARRAY_SIZE(s->reg)) +return s->reg[index]; +else +qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); + +return 0xDEADBEEF; +} + +static void imx2_wdt_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ +uint16_t value = val64; +IMX2WdtState *s = opaque; +const size_t index = addr / sizeof(s->reg[0]); + +switch (index) { +case IMX2_WDT_WCR: +if (value & (IMX2_WDT_WCR_WDA | IMX2_WDT_WCR_SRS)) +watchdog_perform_action(); +default: +qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); +} +} + +static const MemoryRegionOps imx2_wdt_ops = { +.read = imx2_wdt_read, +.write = imx2_wdt_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.valid = { +/* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ +.min_access_size = 4, +.max_access_size = 4, +.unaligned = false, +}, +}; + +static void imx2_wdt_realize(DeviceState *dev, Error **errp) +{ +IMX2WdtState *s = IMX2_WDT(dev); + +memory_region_init_io(&s->mmio, OBJECT(dev), + &imx2_wdt_ops, s, + TYPE_IMX2_WDT".mmio", SZ_64K); +sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); +} + +static void imx2_wdt_class_init(ObjectClass *klass, void *data) +{ +DeviceClass *dc = DEVICE_CLASS(klass); + +dc->realize = imx2_wdt_realize; + +set_bit(DEVICE_CATEGORY_MISC, dc->categories); +} + +static const TypeInfo imx2_wdt_info = { +.name = TYPE_IMX2_WDT, +.parent= TYPE_SYS_BUS_DEVICE, +.instance_size = sizeof(IMX2WdtState), +.class_init= imx2_wdt_class_init, +}; + +static WatchdogTimerModel model = { +.wdt_name = "imx2-watchdog", +.wdt_description = "i.MX2 Watchdog", +}; + +static void imx2_wdt_register_type(void) +{ +watchdog_add_model(&model); +type_register_static(&imx2_wdt_info); +} +type_init(imx2_wdt_register_type) diff --git a/include/hw/misc/imx2_wdt.h b/include/hw/misc/imx2_wdt.h new file mode 100644 index 00..3a30ed1ef8 --- /dev/null +++ b/include/hw/misc/imx2_wdt.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX2 Watchdog IP block + * + * A
[Qemu-devel] [PATCH 12/17] i.MX: Add i.MX7 CCM, PMU and ANALOG device
Cc: Peter Maydell Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/misc/Makefile.objs | 1 + hw/misc/imx7_ccm.c | 201 + include/hw/misc/imx7_ccm.h | 76 + 3 files changed, 278 insertions(+) create mode 100644 hw/misc/imx7_ccm.c create mode 100644 include/hw/misc/imx7_ccm.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 29fb922cef..ac1be05a03 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -34,6 +34,7 @@ obj-$(CONFIG_IMX) += imx31_ccm.o obj-$(CONFIG_IMX) += imx25_ccm.o obj-$(CONFIG_IMX) += imx6_ccm.o obj-$(CONFIG_IMX) += imx6_src.o +obj-$(CONFIG_IMX) += imx7_ccm.o obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o obj-$(CONFIG_MAINSTONE) += mst_fpga.o diff --git a/hw/misc/imx7_ccm.c b/hw/misc/imx7_ccm.c new file mode 100644 index 00..418aafe7cc --- /dev/null +++ b/hw/misc/imx7_ccm.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX7 CCM, PMU and ANALOG IP blocks emulation code + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/sizes.h" +#include "hw/misc/imx7_ccm.h" +#include "qemu/log.h" + +static uint32_t imx7_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock) +{ +/* + * This function is "consumed" by GPT emulation code, however on + * i.MX7 each GPT block can have their own clock root. This means + * that this functions needs somehow to know requester's identity + * and the way to pass it: be it via additional IMXClk constants + * or by adding another argument to this method needs to be + * figured out + */ +qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Not implemented\n", + TYPE_IMX7_CCM, __func__); +return 0; +} + +static void imx7_ccm_reset(DeviceState *dev) +{ +IMX7CCMState *s = IMX7_CCM(dev); + +s->analog[CCM_ANALOG_PLL_ARM] = 0x2042; +s->analog[CCM_ANALOG_PLL_DDR] = 0x0060302c; +s->analog[CCM_ANALOG_PLL_DDR_SS] = 0x; +s->analog[CCM_ANALOG_PLL_DDR_NUM] = 0x06aaac4d; +s->analog[CCM_ANALOG_PLL_DDR_DENOM] = 0x13ec; +s->analog[CCM_ANALOG_PLL_480] = 0x2000; +s->analog[CCM_ANALOG_PLL_480A]= 0x52605a56; +s->analog[CCM_ANALOG_PLL_480B]= 0x52525216; +s->analog[CCM_ANALOG_PLL_ENET]= 0x1fc0; +s->analog[CCM_ANALOG_PLL_AUDIO] = 0x0001301b; +s->analog[CCM_ANALOG_PLL_AUDIO_SS]= 0x; +s->analog[CCM_ANALOG_PLL_AUDIO_NUM] = 0x05f5e100; +s->analog[CCM_ANALOG_PLL_AUDIO_DENOM] = 0x2964619c; +s->analog[CCM_ANALOG_PLL_VIDEO] = 0x0008201b; +s->analog[CCM_ANALOG_PLL_VIDEO_SS]= 0x; +s->analog[CCM_ANALOG_PLL_VIDEO_NUM] = 0xf699; +s->analog[CCM_ANALOG_PLL_VIDEO_DENOM] = 0x000f4240; +s->analog[CCM_ANALOG_PLL_MISC0] = 0x; + +/* all PLLs need to be locked */ +s->analog[CCM_ANALOG_PLL_ARM] |= CCM_ANALOG_PLL_LOCK; +s->analog[CCM_ANALOG_PLL_DDR] |= CCM_ANALOG_PLL_LOCK; +s->analog[CCM_ANALOG_PLL_480] |= CCM_ANALOG_PLL_LOCK; +s->analog[CCM_ANALOG_PLL_480A] |= CCM_ANALOG_PLL_LOCK; +s->analog[CCM_ANALOG_PLL_480B] |= CCM_ANALOG_PLL_LOCK; +s->analog[CCM_ANALOG_PLL_ENET] |= CCM_ANALOG_PLL_LOCK; +s->analog[CCM_ANALOG_PLL_AUDIO] |= CCM_ANALOG_PLL_LOCK; +s->analog[CCM_ANALOG_PLL_VIDEO] |= CCM_ANALOG_PLL_LOCK; +s->analog[CCM_ANALOG_PLL_MISC0] |= CCM_ANALOG_PLL_LOCK; +} + +#define CCM_INDEX(offset) (((offset) & ~(hwaddr)0xF) / sizeof(uint32_t)) +#define CCM_BITOP(offset) ((offset) & (hwaddr)0xF) + +enum { +CCM_BITOP_NONE = 0x00, +CCM_BITOP_SET = 0x04, +CCM_BITOP_CLR = 0x08, +CCM_BITOP_TOG = 0x0C, +}; + +static uint64_t imx7_set_clr_tog_read(void *opaque, hwaddr offset, + unsigned size) +{ +const uint32_t *mmio = opaque; + +return (uint64_t)mmio[CCM_INDEX(offset)]; +} + +static void imx7_set_clr_tog_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ +const uint8_t bitop = CCM_BITOP(offset); +const uint32_t index = CCM_INDEX(offset); +uint32_t *mmio = opaque; + +switch (bitop) { +case CCM_BITOP_NONE: +mmio[index] = value; +break; +case CCM_BITOP_SET: +mmio[index] |= value; +break; +case CCM_BITOP_CLR: +mmio[index] &= ~value; +break; +case CCM_BITOP_TOG: +mmio[index] ^= value; +break; +}; +} + +static const struct MemoryReg
Re: [Qemu-devel] [PATCH 04/17] imx_fec: Change queue flushing heuristics
On Fri, Sep 22, 2017 at 12:27 AM, Jason Wang wrote: > > > On 2017年09月19日 03:50, Andrey Smirnov wrote: >> >> In current implementation, packet queue flushing logic seem to suffer >> from a deadlock like scenario if a packet is received by the interface >> before before Rx ring is initialized by Guest's driver. Consider the >> following sequence of events: >> >> 1. A QEMU instance is started against a TAP device on Linux >>host, running Linux guest, e. g., something to the effect >>of: >> >>qemu-system-arm \ >> -net nic,model=imx.fec,netdev=lan0 \ >> netdev tap,id=lan0,ifname=tap0,script=no,downscript=no \ >> ... rest of the arguments ... >> >> 2. Once QEMU starts, but before guest reaches the point where >>FEC deriver is done initializing the HW, Guest, via TAP >>interface, receives a number of multicast MDNS packets from >>Host (not necessarily true for every OS, but it happens at >>least on Fedora 25) >> >> 3. Recieving a packet in such a state results in >>imx_eth_can_receive() returning '0', which in turn causes >>tap_send() to disable corresponding event (tap.c:203) >> >> 4. Once Guest's driver reaches the point where it is ready to >>recieve packets it prepares Rx ring descriptors and writes >>ENET_RDAR_RDAR to ENET_RDAR register to indicate to HW that >>more descriptors are ready. And at this points emulation >>layer does this: >> >> s->regs[index] = ENET_RDAR_RDAR; >> imx_eth_enable_rx(s); >> >>which, combined with: >> >> if (!s->regs[ENET_RDAR]) { >> qemu_flush_queued_packets(qemu_get_queue(s->nic)); >> } > > > Not familiar with FEC, but if you are tracking 0->1 transition, why not > simply introduce a parameter of imx_eth_enable_rx() to force the flushing? > Not sure I fully understand you, are you proposing I get rid of "needs_flush" parameter in the device state, converting it to be a parameter to imx_eth_enable_rx(), and then force flushing every time imx_eth_enable_rx() is called in imx_eth_write()? That should work, but it'll end up making the emulator code to flush corresponding NIC queue every time the driver is done processing RX ring. If that is not a big problem I am more than happy to make that change. Thanks, Andrey Smirnov
Re: [Qemu-devel] [PATCH 08/17] imx_fec: Add support for multiple Tx DMA rings
On Fri, Sep 22, 2017 at 12:33 AM, Jason Wang wrote: > > > On 2017年09月19日 03:50, Andrey Smirnov wrote: >> >> More recent version of the IP block support more than one Tx DMA ring, >> so add the code implementing that feature. >> >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc:qemu-devel@nongnu.org >> Cc:qemu-...@nongnu.org >> Cc:yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> --- >> hw/net/imx_fec.c | 97 >> +++- >> include/hw/net/imx_fec.h | 23 +++- >> 2 files changed, 101 insertions(+), 19 deletions(-) > > > Is there a register for driver to know about the version? (Looks like I > didn't find it). I haven't seen anything of the sort in the datasheet and, since Linux driver relies on DT for that information, I am inclined to think there's none. Thanks, Andrey Smirnov
Re: [Qemu-devel] [PATCH 02/17] imx_fec: Do not calculate FEC
On Fri, Oct 6, 2017 at 6:48 AM, Peter Maydell wrote: > On 18 September 2017 at 20:50, Andrey Smirnov > wrote: >> Save some computation time and avoid calculating CRC's frame >> >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> --- >> hw/net/imx_fec.c | 9 +++-- >> 1 file changed, 3 insertions(+), 6 deletions(-) >> >> diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c >> index 88b4b049d7..75822344fc 100644 >> --- a/hw/net/imx_fec.c >> +++ b/hw/net/imx_fec.c >> @@ -1032,9 +1032,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, >> const uint8_t *buf, >> IMXENETBufDesc 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; >> >> @@ -1048,8 +1046,6 @@ static ssize_t imx_enet_receive(NetClientState *nc, >> const uint8_t *buf, >> >> /* 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 > ENET_MAX_FRAME_SIZE) { >> @@ -1090,9 +1086,10 @@ static ssize_t imx_enet_receive(NetClientState *nc, >> const uint8_t *buf, >> dma_memory_write(&address_space_memory, buf_addr, buf, buf_len); >> buf += buf_len; >> if (size < 4) { >> +const uint8_t zeros[4] = { 0 }; >> + >> dma_memory_write(&address_space_memory, buf_addr + buf_len, >> - crc_ptr, 4 - size); >> -crc_ptr += 4 - size; >> + zeros, 4 - size); >> } >> bd.flags &= ~ENET_BD_E; >> if (size == 0) { > > This looks a bit odd. Doesn't the hardware calculate the CRC here? > It does, it just seemed to me that since the hardware also has a "CRC error" bit in its status register, there would be few if any users of the actual calculated CRC value. Given how eTSEC emulation layer gets away without calculating CRC I thought that it might be possible to have this optimization here as well. I can drop this patch if this seems risky. Thanks, Andrey Smirnov
Re: [Qemu-devel] [PATCH 04/17] imx_fec: Change queue flushing heuristics
On Fri, Oct 6, 2017 at 6:56 AM, Peter Maydell wrote: > On 18 September 2017 at 20:50, Andrey Smirnov > wrote: >> In current implementation, packet queue flushing logic seem to suffer >> from a deadlock like scenario if a packet is received by the interface >> before before Rx ring is initialized by Guest's driver. Consider the >> following sequence of events: >> >> 1. A QEMU instance is started against a TAP device on Linux >>host, running Linux guest, e. g., something to the effect >>of: >> >>qemu-system-arm \ >> -net nic,model=imx.fec,netdev=lan0 \ >> netdev tap,id=lan0,ifname=tap0,script=no,downscript=no \ >> ... rest of the arguments ... >> >> 2. Once QEMU starts, but before guest reaches the point where >>FEC deriver is done initializing the HW, Guest, via TAP >>interface, receives a number of multicast MDNS packets from >>Host (not necessarily true for every OS, but it happens at >>least on Fedora 25) >> >> 3. Recieving a packet in such a state results in >>imx_eth_can_receive() returning '0', which in turn causes >>tap_send() to disable corresponding event (tap.c:203) >> >> 4. Once Guest's driver reaches the point where it is ready to >>recieve packets it prepares Rx ring descriptors and writes >>ENET_RDAR_RDAR to ENET_RDAR register to indicate to HW that >>more descriptors are ready. And at this points emulation >>layer does this: >> >> s->regs[index] = ENET_RDAR_RDAR; >> imx_eth_enable_rx(s); >> >>which, combined with: >> >> if (!s->regs[ENET_RDAR]) { >> qemu_flush_queued_packets(qemu_get_queue(s->nic)); >> } >> >>results in Rx queue never being flushed and corresponding >>I/O event beign disabled. >> >> Change the code to remember the fact that can_receive callback was >> called before Rx ring was ready and use it to make a decision if >> receive queue needs to be flushed. >> >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> --- >> hw/net/imx_fec.c | 6 -- >> include/hw/net/imx_fec.h | 1 + >> 2 files changed, 5 insertions(+), 2 deletions(-) >> >> diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c >> index 84085afe09..767402909d 100644 >> --- a/hw/net/imx_fec.c >> +++ b/hw/net/imx_fec.c >> @@ -544,8 +544,9 @@ static void imx_eth_enable_rx(IMXFECState *s) >> >> if (rx_ring_full) { >> FEC_PRINTF("RX buffer full\n"); >> -} else if (!s->regs[ENET_RDAR]) { >> +} else if (s->needs_flush) { >> qemu_flush_queued_packets(qemu_get_queue(s->nic)); >> +s->needs_flush = false; >> } >> >> s->regs[ENET_RDAR] = rx_ring_full ? 0 : ENET_RDAR_RDAR; >> @@ -930,7 +931,8 @@ static int imx_eth_can_receive(NetClientState *nc) >> >> FEC_PRINTF("\n"); >> >> -return s->regs[ENET_RDAR] ? 1 : 0; >> +s->needs_flush = !s->regs[ENET_RDAR]; >> +return !!s->regs[ENET_RDAR]; >> } >> >> static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, >> diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h >> index 62ad473b05..4bc8f03ec2 100644 >> --- a/include/hw/net/imx_fec.h >> +++ b/include/hw/net/imx_fec.h >> @@ -252,6 +252,7 @@ typedef struct IMXFECState { >> uint32_t phy_int_mask; >> >> bool is_fec; >> +bool needs_flush; >> } IMXFECState; > > This looks odd -- I don't think you should need extra > state here. Conceptually what you want is: > > * in the can_receive callback, test some function of > various bits of device state to decide whether you can > take data > * in the rest of the device, whenever the device state > changes such that you were previously not able to take > data but now you can, call qemu_flush_queued_packets(). > > You shouldn't need any extra state to do this, you just > need to fix the bug where you have a code path that > flips ENET_RDAR from 0 to 1 without calling flush > (you might for instance have a helper function for > "set ENET_RDAR" that encapsulates setting the state > and arranging that flush is called). > I don't know if you've seen my response to Jason Wang, but I think he was proposing something similar, and, as I said, that should work fine and the only reason I didn't do it that way was to avoid doing a flush every time that host driver drains full RX-ring and gives it back to the IP block. I'll give this a try in v2. Thanks, Andrey Smirnov
Re: [Qemu-devel] [PATCH 05/17] imx_fec: Use ENET_FTRL to determine truncation length
On Fri, Oct 6, 2017 at 7:00 AM, Peter Maydell wrote: > On 30 September 2017 at 01:17, Philippe Mathieu-Daudé wrote: >> Hi Andrey, >> >> On 09/18/2017 04:50 PM, Andrey Smirnov wrote: >>> >>> Frame truncation length, TRUNC_FL, is determined by the contents of >>> ENET_FTRL register, so convert the code to use it instead of a >>> hardcoded constant. >>> >>> Cc: Peter Maydell >>> Cc: Jason Wang >>> Cc: qemu-devel@nongnu.org >>> Cc: qemu-...@nongnu.org >>> Cc: yurov...@gmail.com >>> Signed-off-by: Andrey Smirnov >>> --- >>> hw/net/imx_fec.c | 4 ++-- >>> 1 file changed, 2 insertions(+), 2 deletions(-) >>> >>> diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c >>> index 767402909d..989c11be5f 100644 >>> --- a/hw/net/imx_fec.c >>> +++ b/hw/net/imx_fec.c >>> @@ -1050,8 +1050,8 @@ static ssize_t imx_enet_receive(NetClientState *nc, >>> const uint8_t *buf, >>> size += 4; >>> /* Huge frames are truncted. */ >>> -if (size > ENET_MAX_FRAME_SIZE) { >>> -size = ENET_MAX_FRAME_SIZE; >>> +if (size > s->regs[ENET_FTRL]) { >>> +size = s->regs[ENET_FTRL]; > flags |= ENET_BD_TR | >>> ENET_BD_LG; >>> } >> >> >> for this to be ok you need to update imx_enet_write(), such: >> >> case ENET_FTRL: >> -s->regs[index] = value & 0x3fff; >> +value &= 0x3fff; >> +if (value > ENET_MAX_FRAME_SIZE) { >> +warn_report("%s: guest requested bigger " >> +"frame size than QEMU supports " >> +"(%u > %u)", value, >> +ENET_MAX_FRAME_SIZE); >> +value = ENET_MAX_FRAME_SIZE; >> +} >> +s->regs[index] = value; >> break; > > Yes, and also an incoming-migration post_load callback that > fails migration if the value is too large. > > It might be simpler to truncate to the smaller of the ENET_FTRL > register value and ENET_MAX_FRAME_SIZE. > > (PS: what is the hardware behaviour if ENET_FTRL is set to > a larger value than ENET_MAX_FRAME_SIZE ?) > I haven't tested it in practice, but I assume that hardware should be capable of receiving packets of up to ENET_RCR[MAX_FL] bytes big (both RCR[MAX_FL] and FTRL are 14-bits), since that would allow supporting networks with jumbo frames. What if ENET_MAX_FRAME_SIZE is increased to 16K instead? Would that make all of that additional error checking code unnecessary? Thanks, Andrey Smirnov P.S: And sure, I'll fix the typo in v2.
Re: [Qemu-devel] [PATCH 07/17] imx_fec: Emulate SHIFT16 in ENETx_RACC
On Fri, Oct 6, 2017 at 7:02 AM, Peter Maydell wrote: > On 18 September 2017 at 20:50, Andrey Smirnov > wrote: >> Needed to support latest Linux kernel driver which relies on that >> functionality. >> >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> --- >> hw/net/imx_fec.c | 23 +++ >> include/hw/net/imx_fec.h | 2 ++ >> 2 files changed, 25 insertions(+) >> >> diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c >> index 8a77136d38..bd62d7a75f 100644 >> --- a/hw/net/imx_fec.c >> +++ b/hw/net/imx_fec.c >> @@ -1037,6 +1037,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, >> const uint8_t *buf, >> uint32_t buf_addr; >> unsigned int buf_len; >> size_t size = len; >> +bool shift16 = s->regs[ENET_RACC] & ENET_RACC_SHIFT16; >> >> FEC_PRINTF("len %d\n", (int)size); >> >> @@ -1049,6 +1050,10 @@ static ssize_t imx_enet_receive(NetClientState *nc, >> const uint8_t *buf, >> /* 4 bytes for the CRC. */ >> size += 4; >> >> +if (shift16) { >> +size += 2; >> +} >> + >> /* Huge frames are truncted. */ >> if (size > s->regs[ENET_FTRL]) { >> size = s->regs[ENET_FTRL]; >> @@ -1085,6 +1090,24 @@ static ssize_t imx_enet_receive(NetClientState *nc, >> const uint8_t *buf, >> buf_len += size - 4; >> } >> buf_addr = bd.data; >> + >> +if (shift16) { >> +/* >> + * If SHIFT16 bit of ENETx_RACC register is set we need to >> + * align the payload to 4-byte boundary. >> + */ >> +const uint8_t zeros[2] = { 0 }; >> + >> +dma_memory_write(&address_space_memory, buf_addr, >> + zeros, sizeof(zeros)); >> + >> +buf_addr += sizeof(zeros); >> + buf_len -= sizeof(zeros); >> + >> +shift16 = false; /* We only do this once per Ethernet >> + * frame */ >> +} >> + > > Can you avoid having an end-of-source-line comment that wraps > to multiple lines, please? (put it on a line of its own, or > edit down to fit.) Otherwise > Sure, will fix in v2. Thanks, Andrey Smirnov
Re: [Qemu-devel] [PATCH 08/17] imx_fec: Add support for multiple Tx DMA rings
On Fri, Oct 6, 2017 at 7:10 AM, Peter Maydell wrote: > On 18 September 2017 at 20:50, Andrey Smirnov > wrote: >> More recent version of the IP block support more than one Tx DMA ring, >> so add the code implementing that feature. >> >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov > > I'm surprised this doesn't mean "we have a property on the device > to indicate what IP version it is, which the boards set". Or are > all our current boards mismodelling their ethernet devices with the > wrong number of TX rings ? > As far as I know the only already emulated SoC that this affects is i.MX6, and, no, it doesn't mismodel its Ethernet device since it has version of the IP block with only one Tx ring. I didn't add any notion of versioning because it didn't seem necessary, since 3-ring IP block should be backwards compatible with 1-ring version and host drivers written for the latter will end up using only ring #1 of the 3-ring block. >> --- >> hw/net/imx_fec.c | 97 >> +++- >> include/hw/net/imx_fec.h | 23 +++- >> 2 files changed, 101 insertions(+), 19 deletions(-) >> >> diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c >> index bd62d7a75f..6045ffe673 100644 >> --- a/hw/net/imx_fec.c >> +++ b/hw/net/imx_fec.c >> @@ -196,6 +196,17 @@ static const char *imx_eth_reg_name(IMXFECState *s, >> uint32_t index) >> } >> } >> >> +static const VMStateDescription vmstate_imx_eth_tx_ring = { >> +.name = "fec-tx-ring", >> +.version_id = 1, >> +.minimum_version_id = 1, >> +.fields = (VMStateField[]) { >> +VMSTATE_UINT32(descriptor, IMXFECTxRing), >> +VMSTATE_UINT32(tdsr, IMXFECTxRing), >> +VMSTATE_END_OF_LIST() >> +}, >> +}; >> + >> static const VMStateDescription vmstate_imx_eth = { >> .name = TYPE_IMX_FEC, >> .version_id = 2, >> @@ -203,8 +214,10 @@ static const VMStateDescription vmstate_imx_eth = { >> .fields = (VMStateField[]) { >> VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX), >> VMSTATE_UINT32(rx_descriptor, IMXFECState), >> -VMSTATE_UINT32(tx_descriptor, IMXFECState), >> - >> +VMSTATE_STRUCT_ARRAY(tx_ring, IMXFECState, >> + ENET_TX_RING_NUM, >> + 1, vmstate_imx_eth_tx_ring, >> + IMXFECTxRing), >> VMSTATE_UINT32(phy_status, IMXFECState), >> VMSTATE_UINT32(phy_control, IMXFECState), >> VMSTATE_UINT32(phy_advertise, IMXFECState), > > This breaks migration compatibility, so you need to figure out > how you want to handle that. The simple solution is to increment > the version_id and minimum_version_id fields in vmstate_imx_eth; > that will mean migration from an old QEMU to a new one doesn't > work but it fails in a clean way. The complex way is to put the > new state into a migration subsection with a .needed function > to determine whether to use it or not. For imx I think we can > get away with the simple solution. > OK, will do in v2. >> @@ -407,7 +420,7 @@ static void imx_fec_do_tx(IMXFECState *s) >> int frame_size = 0, descnt = 0; >> uint8_t frame[ENET_MAX_FRAME_SIZE]; >> uint8_t *ptr = frame; >> -uint32_t addr = s->tx_descriptor; >> +uint32_t addr = s->tx_ring[0].descriptor; >> >> while (descnt++ < IMX_MAX_DESC) { >> IMXFECBufDesc bd; >> @@ -448,17 +461,38 @@ static void imx_fec_do_tx(IMXFECState *s) >> } >> } >> >> -s->tx_descriptor = addr; >> +s->tx_ring[0].descriptor = addr; >> >> imx_eth_update(s); >> } >> >> -static void imx_enet_do_tx(IMXFECState *s) >> +static void imx_enet_do_tx(IMXFECState *s, uint32_t index) >> { >> int frame_size = 0, descnt = 0; >> uint8_t frame[ENET_MAX_FRAME_SIZE]; >> uint8_t *ptr = frame; >> -uint32_t addr = s->tx_descriptor; >> +IMXFECTxRing *ring; >> +uint32_t addr; >> + >> +switch (index) { >> +case ENET_TDAR: >> +ring = &s->tx_ring[0]; >> +break; >> +case ENET_TDAR1: >> +ring = &s->tx_ring[1]; >> +break; >> +case ENET_TDAR2: >> +ring = &s->tx_ring[2]; >> +break; >>
Re: [Qemu-devel] [PATCH 15/17] include/qemu: Add sizes.h from Linux
On Fri, Oct 6, 2017 at 7:13 AM, Peter Maydell wrote: > On 18 September 2017 at 20:50, Andrey Smirnov > wrote: >> Add sizes.h from Linux to have a more readable way of specifying >> MemoryRegion sizes. >> >> Cc: Peter Maydell >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> --- >> include/qemu/sizes.h | 47 +++ >> 1 file changed, 47 insertions(+) >> create mode 100644 include/qemu/sizes.h >> >> diff --git a/include/qemu/sizes.h b/include/qemu/sizes.h >> new file mode 100644 >> index 00..9aedb9f8f6 >> --- /dev/null >> +++ b/include/qemu/sizes.h >> @@ -0,0 +1,47 @@ >> +/* >> + * Copy of include/linux/sizes.h >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License version 2 as >> + * published by the Free Software Foundation. >> + */ > > Not really convinced of the utility, and it's gpl-2-only, so no thanks. > OK, will drop in v2. Thanks, Andrey Smironv
Re: [Qemu-devel] [PATCH 13/17] i.MX: Add code to emulate i.MX2 watchdog IP block
On Fri, Oct 6, 2017 at 7:22 AM, Peter Maydell wrote: > On 18 September 2017 at 20:50, Andrey Smirnov > wrote: >> Add enough code to emulate i.MX2 watchdog IP block so it would be >> possible to reboot the machine running Linux Guest. >> >> Cc: Peter Maydell >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> --- >> hw/misc/Makefile.objs | 1 + >> hw/misc/imx2_wdt.c | 117 >> + >> include/hw/misc/imx2_wdt.h | 36 ++ >> 3 files changed, 154 insertions(+) >> create mode 100644 hw/misc/imx2_wdt.c >> create mode 100644 include/hw/misc/imx2_wdt.h >> >> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs >> index ac1be05a03..c393a93456 100644 >> --- a/hw/misc/Makefile.objs >> +++ b/hw/misc/Makefile.objs >> @@ -35,6 +35,7 @@ obj-$(CONFIG_IMX) += imx25_ccm.o >> obj-$(CONFIG_IMX) += imx6_ccm.o >> obj-$(CONFIG_IMX) += imx6_src.o >> obj-$(CONFIG_IMX) += imx7_ccm.o >> +obj-$(CONFIG_IMX) += imx2_wdt.o >> obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o >> obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o >> obj-$(CONFIG_MAINSTONE) += mst_fpga.o >> diff --git a/hw/misc/imx2_wdt.c b/hw/misc/imx2_wdt.c >> new file mode 100644 >> index 00..9d97a19511 >> --- /dev/null >> +++ b/hw/misc/imx2_wdt.c >> @@ -0,0 +1,117 @@ >> +/* >> + * Copyright (c) 2017, Impinj, Inc. >> + * >> + * i.MX2 Watchdog IP block >> + * >> + * Author: Andrey Smirnov >> + * >> + * This work is licensed under the terms of the GNU GPL, version 2 or later. >> + * See the COPYING file in the top-level directory. >> + */ >> + >> +#include "qemu/osdep.h" >> +#include "qapi/error.h" >> +#include "qemu-common.h" >> +#include "hw/hw.h" >> +#include "exec/memory.h" >> +#include "exec/address-spaces.h" >> +#include "hw/sysbus.h" >> +#include "qemu/log.h" >> +#include "qemu/timer.h" >> +#include "sysemu/sysemu.h" >> +#include "sysemu/watchdog.h" >> +#include "qemu/error-report.h" >> +#include "qemu/sizes.h" > > That's an awful lot of includes for a very simple device. Are > you sure they're all needed? No, I am not sure. I'll double-check. > >> + >> +#include "hw/misc/imx2_wdt.h" >> + >> + >> +#define IMX2_WDT_WCR_WDA BIT(5) /* -> External Reset WDOG_B >> */ >> +#define IMX2_WDT_WCR_SRS BIT(4) /* -> Software Reset Signal >> */ >> + >> +static uint64_t imx2_wdt_read(void *opaque, hwaddr addr, >> + unsigned int size) >> +{ >> +IMX2WdtState *s = opaque; >> +const size_t index = addr / sizeof(s->reg[0]); >> + >> +if (index < ARRAY_SIZE(s->reg)) >> +return s->reg[index]; >> +else >> +qemu_log_mask(LOG_GUEST_ERROR, >> + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); >> + >> +return 0xDEADBEEF; >> +} >> + >> +static void imx2_wdt_write(void *opaque, hwaddr addr, >> + uint64_t val64, unsigned int size) >> +{ >> +uint16_t value = val64; >> +IMX2WdtState *s = opaque; >> +const size_t index = addr / sizeof(s->reg[0]); >> + >> +switch (index) { >> +case IMX2_WDT_WCR: >> +if (value & (IMX2_WDT_WCR_WDA | IMX2_WDT_WCR_SRS)) >> +watchdog_perform_action(); > > Missing "break"? > Oops, good catch! Will fix in v2. > Also checkpatch should tell you you need more braces. > Yeah, I definitely forgot to run this through checkpatch, sorry. >> +default: >> +qemu_log_mask(LOG_GUEST_ERROR, >> + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); >> +} >> +} >> + >> +static const MemoryRegionOps imx2_wdt_ops = { >> +.read = imx2_wdt_read, >> +.write = imx2_wdt_write, >> +.endianness = DEVICE_NATIVE_ENDIAN, >> +.valid = { >> +/* >> + * Our device would not work correctly if the guest was doing >> + * unaligned access. This might not be a limitation on the real >> + * device but in practice there is no reason for a guest to access >> + * this dev
Re: [Qemu-devel] [PATCH 16/17] i.MX: Add i.MX7 SOC implementation.
On Fri, Oct 6, 2017 at 7:38 AM, Peter Maydell wrote: > On 18 September 2017 at 20:50, Andrey Smirnov > wrote: >> For now we only support the following devices: >> * up to 2 Cortex A9 cores (SMP works with PSCI) >> * A7 MPCORE (identical to A15 MPCORE) >> * 7 i.MX UARTs >> * 1 CCM device >> * 2 Ethernet controllers (FEC) >> * 3 SD controllers (USDHC) >> * 1 SNVS device >> * 1 WDT device >> >> Cc: Peter Maydell >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> --- >> default-configs/arm-softmmu.mak | 1 + >> hw/arm/Makefile.objs| 2 + >> hw/arm/fsl-imx7.c | 327 >> >> include/hw/arm/fsl-imx7.h | 114 ++ >> 4 files changed, 444 insertions(+) >> create mode 100644 hw/arm/fsl-imx7.c >> create mode 100644 include/hw/arm/fsl-imx7.h >> >> diff --git a/default-configs/arm-softmmu.mak >> b/default-configs/arm-softmmu.mak >> index bbdd3c1d8b..98396a3ad2 100644 >> --- a/default-configs/arm-softmmu.mak >> +++ b/default-configs/arm-softmmu.mak >> @@ -118,6 +118,7 @@ CONFIG_ALLWINNER_A10=y >> CONFIG_FSL_IMX6=y >> CONFIG_FSL_IMX31=y >> CONFIG_FSL_IMX25=y >> +CONFIG_FSL_IMX7=y >> >> CONFIG_IMX_I2C=y >> >> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs >> index a2e56ecaae..33f6051ae3 100644 >> --- a/hw/arm/Makefile.objs >> +++ b/hw/arm/Makefile.objs >> @@ -19,3 +19,5 @@ obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o >> obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o >> obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o >> obj-$(CONFIG_MPS2) += mps2.o >> +obj-$(CONFIG_FSL_IMX7) += fsl-imx7.o >> + >> diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c >> new file mode 100644 >> index 00..bd01bb7f59 >> --- /dev/null >> +++ b/hw/arm/fsl-imx7.c >> @@ -0,0 +1,327 @@ >> +/* >> + * Copyright (c) 2017, Impinj, Inc. >> + * >> + * i.MX7 SoC definitions >> + * >> + * Author: Andrey Smirnov >> + * >> + * Based on hw/arm/fsl-imx6.c >> + * >> + * 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; version 2 of the License. > > We pretty strongly prefer GPL-2-or-later for new code, not 2-only. > OK, will change in v2. >> + * >> + * 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. >> + */ >> + >> +#include "qemu/osdep.h" >> +#include "qapi/error.h" >> +#include "qemu-common.h" >> +#include "hw/arm/fsl-imx7.h" >> +#include "sysemu/sysemu.h" >> +#include "qemu/error-report.h" >> + >> +#define NAME_SIZE 20 >> + >> +#define for_each_cpu(i) for (i = 0; i < smp_cpus; i++) > > Just open-code this, please. Sure, will do in v2. > >> + >> +static void fsl_imx7_init(Object *obj) >> +{ >> +BusState *sysbus = sysbus_get_default(); >> +FslIMX7State *s = FSL_IMX7(obj); >> +char name[NAME_SIZE]; >> +int i; >> + >> +if (smp_cpus > FSL_IMX7_NUM_CPUS) { >> +error_report("%s: Only %d CPUs are supported (%d requested)", >> + TYPE_FSL_IMX7, FSL_IMX7_NUM_CPUS, smp_cpus); >> +exit(1); >> +} >> + >> +for_each_cpu(i) { >> +object_initialize(&s->cpu[i], sizeof(s->cpu[i]), >> + "cortex-a7-" TYPE_ARM_CPU); >> +snprintf(name, NAME_SIZE, "cpu%d", i); >> +object_property_add_child(obj, name, OBJECT(&s->cpu[i]), >> + &error_fatal); >> +} >> + >> +/* >> + * A7MPCORE >> + */ >> +object_initialize(&s->a7mpcore, sizeof(s->a7mpcore), >> TYPE_A15MPCORE_PRIV); > > Stealing the A15MPCORE device for a7 is kind of ugly, but I can't > decide what would be better instead... > I agree, but I looked through the RMs for both and didn't find any software-visible differences that would warrant crea
Re: [Qemu-devel] [PATCH 17/17] Implement support for i.MX7 Sabre board
On Fri, Oct 6, 2017 at 7:42 AM, Peter Maydell wrote: > On 18 September 2017 at 20:51, Andrey Smirnov > wrote: >> Cc: Peter Maydell >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> --- >> hw/arm/Makefile.objs | 2 +- >> hw/arm/mcimx7d-sabre.c | 100 >> + >> 2 files changed, 101 insertions(+), 1 deletion(-) >> create mode 100644 hw/arm/mcimx7d-sabre.c >> >> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs >> index 33f6051ae3..fc4a963de8 100644 >> --- a/hw/arm/Makefile.objs >> +++ b/hw/arm/Makefile.objs >> @@ -19,5 +19,5 @@ obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o >> obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o >> obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o >> obj-$(CONFIG_MPS2) += mps2.o >> -obj-$(CONFIG_FSL_IMX7) += fsl-imx7.o >> +obj-$(CONFIG_FSL_IMX7) += fsl-imx7.o mcimx7d-sabre.o >> >> diff --git a/hw/arm/mcimx7d-sabre.c b/hw/arm/mcimx7d-sabre.c >> new file mode 100644 >> index 00..34e3933db8 >> --- /dev/null >> +++ b/hw/arm/mcimx7d-sabre.c >> @@ -0,0 +1,100 @@ >> +/* >> + * Copyright (c) 2017, Impinj, Inc. >> + * >> + * MCIMX7D_SABRE Board System emulation. >> + * >> + * Author: Andrey Smirnov >> + * >> + * This code is licensed under the GPL, version 2 or later. >> + * See the file `COPYING' in the top level directory. >> + * >> + * It (partially) emulates a mcimx7d_sabre board, with a Freescale >> + * i.MX7 SoC >> + */ >> + >> +#include "qemu/osdep.h" >> +#include "qapi/error.h" >> +#include "qemu-common.h" >> +#include "hw/arm/fsl-imx7.h" >> +#include "hw/boards.h" >> +#include "sysemu/sysemu.h" >> +#include "sysemu/device_tree.h" >> +#include "qemu/error-report.h" >> +#include "sysemu/qtest.h" >> +#include "net/net.h" >> + >> +typedef struct { >> +FslIMX7State soc; >> +MemoryRegion ram; >> +} MCIMX7Sabre; >> + >> +static void mcimx7d_add_psci_node(const struct arm_boot_info *boot_info, >> void *fdt) >> +{ >> +const char comp[] = "arm,psci-0.2\0arm,psci"; >> + >> +qemu_fdt_add_subnode(fdt, "/psci"); >> +qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp)); >> +qemu_fdt_setprop_string(fdt, "/psci", "method", "smc"); >> +} > > You shouldn't need this -- we should just be able to work with whatever > the real hardware's device tree is. ("virt" is a special case because > we create our own device tree there.) > Upstream kernel for i.MX7 relies on PSCI to support SMP and this is a kind of DT fixup that would normally be done by a PSCI-compatible bootloader. I can remove this code, but it would effectively disable SMP on vanilla DT/kernel combos. >> + >> +static void mcimx7d_sabre_init(MachineState *machine) >> +{ >> +static struct arm_boot_info boot_info; >> +MCIMX7Sabre *s = g_new0(MCIMX7Sabre, 1); >> +Object *soc; >> +int i; >> + >> +if (machine->ram_size > FSL_IMX7_MMDC_SIZE) { >> +error_report("RAM size " RAM_ADDR_FMT " above max supported (%08x)", >> + machine->ram_size, FSL_IMX7_MMDC_SIZE); >> +exit(1); >> +} >> + >> +boot_info = (struct arm_boot_info) { >> +.loader_start = FSL_IMX7_MMDC_ADDR, >> +.board_id = -1, >> +.ram_size = machine->ram_size, >> +.kernel_filename = machine->kernel_filename, >> +.kernel_cmdline = machine->kernel_cmdline, >> +.initrd_filename = machine->initrd_filename, >> +.nb_cpus = smp_cpus, >> +.modify_dtb = mcimx7d_add_psci_node, >> +}; >> + >> +object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX7); >> +soc = OBJECT(&s->soc); >> +object_property_add_child(OBJECT(machine), "soc", soc, &error_fatal); >> +object_property_set_bool(soc, true, "realized", &error_fatal); >> + >> +memory_region_allocate_system_memory(&s->ram, NULL, "mcimx7d-sabre.ram", >> + machine->ram_size); >> +memory_region_add_subregion(get_system_memory(), >> +FSL_I
Re: [PATCH v1 3/5] contrib/gitdm: add Andrey to the individual group
On Mon, Oct 14, 2019 at 6:59 AM Alex Bennée wrote: > > Please confirm this is the correct section for you. > I think this is. Here's Acked-by: Andrey Smirnov in case that's needed. > Signed-off-by: Alex Bennée > Cc: Andrey Smirnov > --- > contrib/gitdm/group-map-individuals | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/contrib/gitdm/group-map-individuals > b/contrib/gitdm/group-map-individuals > index 301071b98b..624e27fc83 100644 > --- a/contrib/gitdm/group-map-individuals > +++ b/contrib/gitdm/group-map-individuals > @@ -18,3 +18,4 @@ e.emanuelegiuse...@gmail.com > dirty.ice...@gmail.com > liq...@163.com > liq...@gmail.com > +andrew.smir...@gmail.com > -- > 2.20.1 >
Re: [Qemu-devel] [PATCH 0/5] Various i.MX7 fixes
On Mon, Apr 15, 2019 at 6:39 PM Andrey Smirnov wrote: > > Everyone: > > I recently revisited my i.MX7 work and this series contains all of the > fixes I had to make to get it to work with latest (5.1-rc1) Linux > kernel again as well as fixes for genuine bugs that I somehow missed > during original submission ("pci: designware" patches). Hopefully each > patch is self-explanatory. > > Feedback is welcome! > Is there any changes necessary for this to go in? Thanks, Andrey Smirnov
[Qemu-devel] [PATCH 5/5] i.mx7d: pci: Update PCI IRQ mapping to match HW
Datasheet for i.MX7 is incorrect and i.MX7's PCI IRQ mapping matches that of i.MX6: * INTD/MSI122 * INTC123 * INTB124 * INTA125 Fix all of the relevant code to reflect that fact. Needed by latest Linux kernels. Signed-off-by: Andrey Smirnov Cc: Peter Maydell Cc: Michael S. Tsirkin Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org --- include/hw/arm/fsl-imx7.h | 8 hw/pci-host/designware.c | 6 -- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/hw/arm/fsl-imx7.h b/include/hw/arm/fsl-imx7.h index 3efa697adc..9750003a4f 100644 --- a/include/hw/arm/fsl-imx7.h +++ b/include/hw/arm/fsl-imx7.h @@ -213,10 +213,10 @@ enum FslIMX7IRQs { FSL_IMX7_USB2_IRQ = 42, FSL_IMX7_USB3_IRQ = 40, -FSL_IMX7_PCI_INTA_IRQ = 122, -FSL_IMX7_PCI_INTB_IRQ = 123, -FSL_IMX7_PCI_INTC_IRQ = 124, -FSL_IMX7_PCI_INTD_IRQ = 125, +FSL_IMX7_PCI_INTA_IRQ = 125, +FSL_IMX7_PCI_INTB_IRQ = 124, +FSL_IMX7_PCI_INTC_IRQ = 123, +FSL_IMX7_PCI_INTD_IRQ = 122, FSL_IMX7_UART7_IRQ= 126, diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c index e80facc4a0..f4c58b25c1 100644 --- a/hw/pci-host/designware.c +++ b/hw/pci-host/designware.c @@ -50,6 +50,8 @@ #define DESIGNWARE_PCIE_ATU_DEVFN(x) (((x) >> 16) & 0xff) #define DESIGNWARE_PCIE_ATU_UPPER_TARGET 0x91C +#define DESIGNWARE_PCIE_IRQ_MSI3 + static DesignwarePCIEHost * designware_pcie_root_to_host(DesignwarePCIERoot *root) { @@ -66,7 +68,7 @@ static void designware_pcie_root_msi_write(void *opaque, hwaddr addr, root->msi.intr[0].status |= BIT(val) & root->msi.intr[0].enable; if (root->msi.intr[0].status & ~root->msi.intr[0].mask) { -qemu_set_irq(host->pci.irqs[0], 1); +qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 1); } } @@ -310,7 +312,7 @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address, case DESIGNWARE_PCIE_MSI_INTR0_STATUS: root->msi.intr[0].status ^= val; if (!root->msi.intr[0].status) { -qemu_set_irq(host->pci.irqs[0], 0); +qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 0); } break; -- 2.20.1
[Qemu-devel] [PATCH 0/5] Various i.MX7 fixes
Everyone: I recently revisited my i.MX7 work and this series contains all of the fixes I had to make to get it to work with latest (5.1-rc1) Linux kernel again as well as fixes for genuine bugs that I somehow missed during original submission ("pci: designware" patches). Hopefully each patch is self-explanatory. Feedback is welcome! Thanks, Andrey Smirnov Andrey Smirnov (5): i.mx7d: Add no-op/unimplemented APBH DMA module i.mx7d: Add no-op/unimplemented PCIE PHY IP block pci: designware: Update MSI mapping unconditionally pci: designware: Update MSI mapping when MSI address changes i.mx7d: pci: Update PCI IRQ mapping to match HW include/hw/arm/fsl-imx7.h | 14 ++ hw/arm/fsl-imx7.c | 11 +++ hw/pci-host/designware.c | 18 -- 3 files changed, 29 insertions(+), 14 deletions(-) -- 2.20.1
[Qemu-devel] [PATCH 1/5] i.mx7d: Add no-op/unimplemented APBH DMA module
Instantiate no-op APBH DMA module. Needed to boot latest Linux kernel. Signed-off-by: Andrey Smirnov Cc: Peter Maydell Cc: Michael S. Tsirkin Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org --- include/hw/arm/fsl-imx7.h | 3 +++ hw/arm/fsl-imx7.c | 6 ++ 2 files changed, 9 insertions(+) diff --git a/include/hw/arm/fsl-imx7.h b/include/hw/arm/fsl-imx7.h index d848262bfd..aae4f860fc 100644 --- a/include/hw/arm/fsl-imx7.h +++ b/include/hw/arm/fsl-imx7.h @@ -179,6 +179,9 @@ enum FslIMX7MemoryMap { FSL_IMX7_PCIE_REG_SIZE= 16 * 1024, FSL_IMX7_GPR_ADDR = 0x3034, + +FSL_IMX7_DMA_APBH_ADDR= 0x3300, +FSL_IMX7_DMA_APBH_SIZE= 0x2000, }; enum FslIMX7IRQs { diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c index 7663ad6861..1abfa5910c 100644 --- a/hw/arm/fsl-imx7.c +++ b/hw/arm/fsl-imx7.c @@ -526,6 +526,12 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) */ create_unimplemented_device("lcdif", FSL_IMX7_LCDIF_ADDR, FSL_IMX7_LCDIF_SIZE); + +/* + * DMA APBH + */ +create_unimplemented_device("dma-apbh", FSL_IMX7_DMA_APBH_ADDR, +FSL_IMX7_DMA_APBH_SIZE); } static void fsl_imx7_class_init(ObjectClass *oc, void *data) -- 2.20.1
[Qemu-devel] [PATCH 2/5] i.mx7d: Add no-op/unimplemented PCIE PHY IP block
Add no-op/unimplemented PCIE PHY IP block. Needed by new kernels to use PCIE. Signed-off-by: Andrey Smirnov Cc: Peter Maydell Cc: Michael S. Tsirkin Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org --- include/hw/arm/fsl-imx7.h | 3 +++ hw/arm/fsl-imx7.c | 5 + 2 files changed, 8 insertions(+) diff --git a/include/hw/arm/fsl-imx7.h b/include/hw/arm/fsl-imx7.h index aae4f860fc..3efa697adc 100644 --- a/include/hw/arm/fsl-imx7.h +++ b/include/hw/arm/fsl-imx7.h @@ -125,6 +125,9 @@ enum FslIMX7MemoryMap { FSL_IMX7_ADC2_ADDR= 0x3062, FSL_IMX7_ADCn_SIZE= 0x1000, +FSL_IMX7_PCIE_PHY_ADDR= 0x306D, +FSL_IMX7_PCIE_PHY_SIZE= 0x1, + FSL_IMX7_GPC_ADDR = 0x303A, FSL_IMX7_I2C1_ADDR= 0x30A2, diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c index 1abfa5910c..813fb55ca9 100644 --- a/hw/arm/fsl-imx7.c +++ b/hw/arm/fsl-imx7.c @@ -532,6 +532,11 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) */ create_unimplemented_device("dma-apbh", FSL_IMX7_DMA_APBH_ADDR, FSL_IMX7_DMA_APBH_SIZE); +/* + * PCIe PHY + */ +create_unimplemented_device("pcie-phy", FSL_IMX7_PCIE_PHY_ADDR, +FSL_IMX7_PCIE_PHY_SIZE); } static void fsl_imx7_class_init(ObjectClass *oc, void *data) -- 2.20.1
[Qemu-devel] [PATCH 3/5] pci: designware: Update MSI mapping unconditionally
Expression to calculate update_msi_mapping in code handling writes to DESIGNWARE_PCIE_MSI_INTR0_ENABLE is missing an ! operator and should be: !!root->msi.intr[0].enable ^ !!val; so that MSI mapping is updated when enabled transitions from either "none" -> "any" or "any" -> "none". Since that register shouldn't be written to very often, change the code to update MSI mapping unconditionally instead of trying to fix the update_msi_mapping logic. Signed-off-by: Andrey Smirnov Cc: Peter Maydell Cc: Michael S. Tsirkin Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org --- hw/pci-host/designware.c | 10 ++ 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c index 29ea313798..6affe823c0 100644 --- a/hw/pci-host/designware.c +++ b/hw/pci-host/designware.c @@ -296,16 +296,10 @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address, root->msi.base |= (uint64_t)val << 32; break; -case DESIGNWARE_PCIE_MSI_INTR0_ENABLE: { -const bool update_msi_mapping = !root->msi.intr[0].enable ^ !!val; - +case DESIGNWARE_PCIE_MSI_INTR0_ENABLE: root->msi.intr[0].enable = val; - -if (update_msi_mapping) { -designware_pcie_root_update_msi_mapping(root); -} +designware_pcie_root_update_msi_mapping(root); break; -} case DESIGNWARE_PCIE_MSI_INTR0_MASK: root->msi.intr[0].mask = val; -- 2.20.1
[Qemu-devel] [PATCH 4/5] pci: designware: Update MSI mapping when MSI address changes
MSI mapping needs to be update when MSI address changes, so add the code to do so. Signed-off-by: Andrey Smirnov Cc: Peter Maydell Cc: Michael S. Tsirkin Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org --- hw/pci-host/designware.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c index 6affe823c0..e80facc4a0 100644 --- a/hw/pci-host/designware.c +++ b/hw/pci-host/designware.c @@ -289,11 +289,13 @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address, case DESIGNWARE_PCIE_MSI_ADDR_LO: root->msi.base &= 0xULL; root->msi.base |= val; +designware_pcie_root_update_msi_mapping(root); break; case DESIGNWARE_PCIE_MSI_ADDR_HI: root->msi.base &= 0xULL; root->msi.base |= (uint64_t)val << 32; +designware_pcie_root_update_msi_mapping(root); break; case DESIGNWARE_PCIE_MSI_INTR0_ENABLE: -- 2.20.1
Re: [Qemu-devel] Maintainers, please tell us how to boot your machines!
On Tue, Mar 12, 2019 at 10:36 AM Markus Armbruster wrote: > > Dear board code maintainers, > > This is a (rather late) follow-up to the last QEMU summit. Minutes[*]: > > * Deprecating unmaintained features (devices, targets, backends) in QEMU > >QEMU has a mechanism to deprecate features but there remains a lot of >old unmaintained code. Refactoring is hindered by untested legacy >code, so there is a desire to deprecate unmaintained features more >often. > >[...] > >We should require at least a minimal test for each board; if nobody >cares enough to come up with one, that board should be deprecated. > >[...] > >Also see the qemu-devel discussion about deprecating code: >https://lists.nongnu.org/archive/html/qemu-devel/2018-10/msg05828.html. > > That's a link to "Minutes of KVM Forum BoF on deprecating stuff". > Quote: > > * One obvious class of candidates for removal is machines we don't know >how to boot, or can't boot, say because we lack required firmware >and/or OS. > >Of course, "can boot" should be an automated test. As a first step >towards that, we should at least document how to boot each machine. >We're going to ask machine maintainers to do that. > > Let's get going on this. > > I gathered the machine types, mapped them to source files, which I fed > to get_maintainer.pl. Results are appended. If you're cc'ed, > MAINTAINERS fingers you for at least one machine type's source file. > Please tell us for all of them how to to a "meaningful" boot test. > > For now, what's "meaningful" is entirely up to you. Booting Linux > certainly is. > > Make sure to include a complete QEMU command line. If your QEMU command > line requires resources beyond the QEMU source tree and what we build > from it, please detail them, and provide download URLs as far as > possible. > > Goals for this exercise: > > * Gather information we need to cover more machines in our automated > testing. > > Related work: > [PATCH v4 00/19] Acceptance Tests: target architecture support > Message-Id: <20190312121150.8638-1-cr...@redhat.com> > https://lists.gnu.org/archive/html/qemu-devel/2019-03/msg03881.html > > * Maybe identify a few machines we don't know how to boot anymore. > > Thanks in advance for your help! > > > > Machines with at least one maintainer: > > > = hw/arm/mcimx7d-sabre.c = > Peter Maydell (odd fixer:MCIMX7D SABRE / i...) > Andrey Smirnov (reviewer:MCIMX7D SABRE / i...) > qemu-...@nongnu.org (open list:MCIMX7D SABRE / i...) > Sorry I am late to this party. I haven't used i.MX7 emulation in a while and things didn't go smoothly out of the box, so I had to create a number of fixes (submitted to the ML). I use Linux kernel built using Buildroot for validation. Buildroot should have a default i.MX7 Sabred SD configuration and that should probably work. I usually change mine slightly to use compiled-in rootfs to simplify storage setup. In case this is helpful here's a number of commands I use to start my test cases: * PCIe (e1000 ethernet attached), USB (usb stick attached), SD: arm-softmmu/qemu-system-arm -smp 2 -m 1024 -machine mcimx7d-sabre -nographic -serial mon:stdio -kernel -dtb -device e1000e,bus="dw-pcie",netdev=lan0 -netdev tap,id=lan0,ifname=tap0,script=no,downscript=no -append "console=ttymxc0,115200 noinitrd" -usb -drive if=none,id=stick,file=,format=raw -device usb-storage,bus=usb-bus.0,drive=stick -drive id=sd1,if=sd,format=file,file= -drive id=sd2,if=sd,format=file,file= -driv eid=sd3,if=sd,format=file,file= * EHCI USB attached via PCIe with legacy interrupts, Ethernet connected to built-in controller: arm-softmmu/qemu-system-arm -smp 2 -m 1024 -machine mcimx7d-sabre -nographic -serial mon:stdio -kernel -dtb -device usb-ehci,id=ehci,bus="dw-pcie" -net nic,model=imx.fec,netdev=lan0 -netdev tap,id=lan0,ifname=tap0,script=no,downscript=no -append "console=ttymxc0,115200 noinitrd pci=nomsi" -usb -drive if=none,id=stick,file=,format=raw Also, I don't think anyone would try to do this, but just as a warning, building QEMU with --enable-tcg-interpreter doesn't really work that well (/init gets SIGKILLed every time), so I'd recommend avoiding using that option. Hopefully this is enough info, but if not, feel free to ask me more questions. Thanks, Andrey Smirnov
Re: [Qemu-devel] [PATCH v2] i.MX: Fix FEC/ENET receive funtions
On Mon, Jan 22, 2018 at 3:48 AM, Peter Maydell wrote: > On 13 January 2018 at 11:34, Jean-Christophe Dubois > wrote: >> The actual imx_eth_enable_rx() function is buggy. >> >> It updates s->regs[ENET_RDAR] after calling qemu_flush_queued_packets(). >> >> qemu_flush_queued_packets() is going to call imx_XXX_receive() which itself >> is going to call imx_eth_enable_rx(). >> >> By updating s->regs[ENET_RDAR] after calling qemu_flush_queued_packets() >> we end up updating the register with an outdated value which might >> lead to disabling the receive function in the i.MX FEC/ENET device. >> >> This patch change the place where the register update is done so that the >> register value stays up to date and the receive function can keep >> running. >> >> Reported-by: Fyleo >> Tested-by: Fyleo >> Signed-off-by: Jean-Christophe Dubois >> --- > > Andrey, do you have an opinion on this patch, since you've been > looking at i.MX code recently? > The rationale makes sense to me and patch looks like a good cleanup in general, so FWIW: Reviewed-by: Andrey Smirnov I also gave it a spin against my i.MX7 changes with doing basic things like ping and scp of 1GB file, so I can give my: Tested-by: Andrey Smirnov for that. Thanks, Andrey Smirnov >> Change since v1: >> 1. Rebase the patch on the updated master branch >> >> hw/net/imx_fec.c | 8 ++-- >> 1 file changed, 2 insertions(+), 6 deletions(-) >> >> diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c >> index 4fb48f62ba..9506f9b69f 100644 >> --- a/hw/net/imx_fec.c >> +++ b/hw/net/imx_fec.c >> @@ -595,19 +595,16 @@ static void imx_eth_do_tx(IMXFECState *s, uint32_t >> index) >> static void imx_eth_enable_rx(IMXFECState *s, bool flush) >> { >> IMXFECBufDesc bd; >> -bool rx_ring_full; >> >> imx_fec_read_bd(&bd, s->rx_descriptor); >> >> -rx_ring_full = !(bd.flags & ENET_BD_E); >> +s->regs[ENET_RDAR] = (bd.flags & ENET_BD_E) ? ENET_RDAR_RDAR : 0; >> >> -if (rx_ring_full) { >> +if (!s->regs[ENET_RDAR]) { >> FEC_PRINTF("RX buffer full\n"); >> } else if (flush) { >> qemu_flush_queued_packets(qemu_get_queue(s->nic)); >> } >> - >> -s->regs[ENET_RDAR] = rx_ring_full ? 0 : ENET_RDAR_RDAR; >> } >> >> static void imx_eth_reset(DeviceState *d) >> @@ -866,7 +863,6 @@ static void imx_eth_write(void *opaque, hwaddr offset, >> uint64_t value, >> case ENET_RDAR: >> if (s->regs[ENET_ECR] & ENET_ECR_ETHEREN) { >> if (!s->regs[index]) { >> -s->regs[index] = ENET_RDAR_RDAR; >> imx_eth_enable_rx(s, true); >> } >> } else { >> -- >> 2.14.1 > > Reviewed-by: Peter Maydell > > thanks > -- PMM
[Qemu-devel] [PATCH 1/2] char: i.MX: Simplify imx_update()
Code of imx_update() is slightly confusing since the "flags" variable doesn't really corespond to anything in real hardware and server as a kitchensink accumulating events normally reported via USR1 and USR2 registers. Change the code to explicitly evaluate state of interrupts reported via USR1 and USR2 against corresponding masking bits and use the to detemine if IRQ line should be asserted or not. NOTE: Check for UTS1_TXEMPTY being set has been dropped for two reasons: 1. Emulation code implements a single character FIFO, so this flag will always be set since characters are trasmitted as a part of the code emulating "push" into the FIFO 2. imx_update() is really just a function doing ORing and maksing of reported events, so checking for UTS1_TXEMPTY should happen, if it's ever really needed should probably happen outside of it. Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: Bill Paul Cc: Peter Maydell Signed-off-by: Andrey Smirnov --- hw/char/imx_serial.c | 24 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c index 70405ccf8b..d1e8586280 100644 --- a/hw/char/imx_serial.c +++ b/hw/char/imx_serial.c @@ -56,16 +56,24 @@ static const VMStateDescription vmstate_imx_serial = { static void imx_update(IMXSerialState *s) { -uint32_t flags; +uint32_t usr1; +uint32_t usr2; +uint32_t mask; -flags = (s->usr1 & s->ucr1) & (USR1_TRDY|USR1_RRDY); -if (s->ucr1 & UCR1_TXMPTYEN) { -flags |= (s->uts1 & UTS1_TXEMPTY); -} else { -flags &= ~USR1_TRDY; -} +/* + * Lucky for us TRDY and RRDY has the same offset in both USR1 and + * UCR1, so we can get away with something as simple as the + * following: + */ +usr1 = s->usr1 & s->ucr1 & (USR1_TRDY | USR1_RRDY); +/* + * Bits that we want in USR2 are not as conveniently laid out, + * unfortunately. + */ +mask = (s->ucr1 & UCR1_TXMPTYEN) ? USR2_TXFE : 0; +usr2 = s->usr2 & mask; -qemu_set_irq(s->irq, !!flags); +qemu_set_irq(s->irq, usr1 || usr2); } static void imx_serial_reset(IMXSerialState *s) -- 2.14.3
[Qemu-devel] [PATCH 2/2] char: i.MX: Add support for "TX complete" interrupt
Add support for "TX complete"/TXDC interrupt generate by real HW since it is needed to support guests other than Linux. Based on the patch by Bill Paul as found here: https://bugs.launchpad.net/qemu/+bug/1753314 Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: Bill Paul Cc: Peter Maydell Signed-off-by: Andrey Smirnov --- Bill: I only tested this with i.MX7/Linux guest combo and am hoping you can take this and previous patch and give it a try on your VxWorks setup. Peter: Bill is the author of original code, so I am not sure how to handle Signed-off-by from him. I'd like to add it to this patch, but since his original submission to launchpad didn't have one it is currently omitted. include/hw/char/imx_serial.h | 3 +++ hw/char/imx_serial.c | 20 +--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/include/hw/char/imx_serial.h b/include/hw/char/imx_serial.h index baeec3183f..5b99cee7cf 100644 --- a/include/hw/char/imx_serial.h +++ b/include/hw/char/imx_serial.h @@ -67,6 +67,8 @@ #define UCR2_RXEN (1<<1)/* Receiver enable */ #define UCR2_SRST (1<<0)/* Reset complete */ +#define UCR4_TCEN BIT(3)/* TX complete interrupt enable */ + #define UTS1_TXEMPTY(1<<6) #define UTS1_RXEMPTY(1<<5) #define UTS1_TXFULL (1<<4) @@ -95,6 +97,7 @@ typedef struct IMXSerialState { uint32_t ubmr; uint32_t ubrc; uint32_t ucr3; +uint32_t ucr4; qemu_irq irq; CharBackend chr; diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c index d1e8586280..1e5540472b 100644 --- a/hw/char/imx_serial.c +++ b/hw/char/imx_serial.c @@ -37,8 +37,8 @@ static const VMStateDescription vmstate_imx_serial = { .name = TYPE_IMX_SERIAL, -.version_id = 1, -.minimum_version_id = 1, +.version_id = 2, +.minimum_version_id = 2, .fields = (VMStateField[]) { VMSTATE_INT32(readbuff, IMXSerialState), VMSTATE_UINT32(usr1, IMXSerialState), @@ -50,6 +50,7 @@ static const VMStateDescription vmstate_imx_serial = { VMSTATE_UINT32(ubmr, IMXSerialState), VMSTATE_UINT32(ubrc, IMXSerialState), VMSTATE_UINT32(ucr3, IMXSerialState), +VMSTATE_UINT32(ucr4, IMXSerialState), VMSTATE_END_OF_LIST() }, }; @@ -71,6 +72,11 @@ static void imx_update(IMXSerialState *s) * unfortunately. */ mask = (s->ucr1 & UCR1_TXMPTYEN) ? USR2_TXFE : 0; +/* + * TCEN and TXDC are both bit 3 + */ +mask |= s->ucr4 & UCR4_TCEN; + usr2 = s->usr2 & mask; qemu_set_irq(s->irq, usr1 || usr2); @@ -163,6 +169,8 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset, return s->ucr3; case 0x23: /* UCR4 */ +return s->ucr4; + case 0x29: /* BRM Incremental */ return 0x0; /* TODO */ @@ -191,8 +199,10 @@ static void imx_serial_write(void *opaque, hwaddr offset, * qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, &ch, 1); s->usr1 &= ~USR1_TRDY; +s->usr2 &= ~USR2_TXDC; imx_update(s); s->usr1 |= USR1_TRDY; +s->usr2 |= USR2_TXDC; imx_update(s); } break; @@ -265,8 +275,12 @@ static void imx_serial_write(void *opaque, hwaddr offset, s->ucr3 = value & 0x; break; -case 0x2d: /* UTS1 */ case 0x23: /* UCR4 */ +s->ucr4 = value & 0x; +imx_update(s); +break; + +case 0x2d: /* UTS1 */ qemu_log_mask(LOG_UNIMP, "[%s]%s: Unimplemented reg 0x%" HWADDR_PRIx "\n", TYPE_IMX_SERIAL, __func__, offset); /* TODO */ -- 2.14.3
Re: [Qemu-devel] [PATCH] fsl_etsec: Fix Tx BD ring wrapping handling
On Sun, Dec 25, 2016 at 8:12 PM, Jason Wang wrote: > > > On 2016年12月21日 05:11, Andrey Smirnov wrote: >> >> Current code that handles Tx buffer desciprtor ring scanning employs the >> following algorithm: >> >> 1. Restore current buffer descriptor pointer from TBPTRn >> >> 2. Process current descriptor >> >> 3. If current descriptor has BD_WRAP flag set set current >>descriptor pointer to start of the descriptor ring >> >> 4. If current descriptor points to start of the ring exit the >>loop, otherwise increment current descriptor pointer and go >>to #2 >> >> 5. Store current descriptor in TBPTRn >> >> As it can be seen the way the code is implemented results in buffer >> descriptor ring being scanned starting at offset/descriptor #0. While >> covering proverbial "99%" of the cases, this algorithm becomes >> problematic for a number of edge cases. >> >> Consider the following scenario: guest OS driver initializes descriptor >> ring to N individual descriptors and starts sending data out. Depending >> on the volume of traffic and probably guest OS driver implementation it >> is possible that an edge case where a packet, spread across 2 >> descriptors is placed in descriptors N - 1 and 0 in that order(it is >> easy to imagine similar examples involving more than 2 descriptors). >> >> What happens then is aforementioned algorithm starts at descriptor 0, >> sees a descriptor marked as BD_LAST, which it happily sends out as a >> separate packet(very much malformed at this point) then the iteration >> continues and the first part of the original packet is tacked to the >> next transmission which ends up being bogus as well. >> >> This behvaiour can be pretty reliably observed when scp'ing data from a >> guest OS via TAP interface for files larger than 160K (every time for >> 700K+). >> >> This patch changes the scanning algorithm to do the following: >> >> 1. Restore "current" and "start" buffer descriptor pointer from >>TBPTRn >> >> 2. If "current" descriptor has BD_WRAP flag set "next" >>descriptor pointer to start of the descriptor ring otherwise >>set "next" to descriptor right after "current" >> >> 3. Process current descriptor >> >> 4. If current descriptore has BD_LAST(end of a packet) set save >>"next" descriptor pointer in TBPTRn >> >> 5. Set "current" descriptor pointer to "next" >> >> 6. If "current" descriptor points to "start" (from #1) exit the >> loop >>loop, otherwise go to #2 > > > Hi, I'm not familiar with this card but this seems could be simply addressed > by exiting the loop when bd_flags != BD_TX_READY instead of bd_addr != > ring_base (which seems buggy for heavy load)? This would change the emulated behavior, since original implementation would scan the entirety of buffer descriptor ring and process every entry with "READY" bit set regardless if those descriptors were placed right after each other or had gaps. That being said, I don't have any reason to believe that aforementioned peculiarity is correct behavior that actual HW would exhibit. I can't seem to find any detailed description of what goes under the hood in RM except for this: "... The TBPTR register is internally written by the eTSEC’s DMA controller during transmission. The pointer increments by eight (bytes) each time a descriptor is closed successfully by the eTSEC..." And reading that seems to suggest, that what you are proposing, besides being simpler solution, might also be the correct way to emulate this aspect of eTSEC's DMA engine behavior. Let me experiment and see if encounter any problems with this approach. I'll post updated version of the patch if it works out. Thanks, Andrey Smirnov
[Qemu-devel] [PATCH v2] fsl_etsec: Fix Tx BD ring wrapping handling
Current code that handles Tx buffer desciprtor ring scanning employs the following algorithm: 1. Restore current buffer descriptor pointer from TBPTRn 2. Process current descriptor 3. If current descriptor has BD_WRAP flag set set current descriptor pointer to start of the descriptor ring 4. If current descriptor points to start of the ring exit the loop, otherwise increment current descriptor pointer and go to #2 5. Store current descriptor in TBPTRn The way the code is implemented results in buffer descriptor ring being scanned starting at offset/descriptor #0. While covering 99% of the cases, this algorithm becomes problematic for a number of edge cases. Consider the following scenario: guest OS driver initializes descriptor ring to N individual descriptors and starts sending data out. Depending on the volume of traffic and probably guest OS driver implementation it is possible that an edge case where a packet, spread across 2 descriptors is placed in descriptors N - 1 and 0 in that order(it is easy to imagine similar examples involving more than 2 descriptors). What happens then is aforementioned algorithm starts at descriptor 0, sees a descriptor marked as BD_LAST, which it happily sends out as a separate packet(very much malformed at this point) then the iteration continues and the first part of the original packet is tacked to the next transmission which ends up being bogus as well. This behvaiour can be pretty reliably observed when scp'ing data from a guest OS via TAP interface for files larger than 160K (every time for 700K+). This patch changes the scanning algorithm to do the following: 1. Restore "current" buffer descriptor pointer from TBPTRn 2. If "current" descriptor does not have BD_TX_READY set, goto #6 3. Process current descriptor 4. If "current" descriptor has BD_WRAP flag set "current" descriptor pointer to start of the descriptor ring otherwise set increment "current" by the size of one descriptor 5. Goto #1 6. Save "current" buffer descriptor in TBPTRn This way we preserve the information about which descriptor was processed last and always start where we left off avoiding the original problem. On top of that, judging by the following excerpt from MPC8548ERM (p. 14-48): "... When the end of the TxBD ring is reached, eTSEC initializes TBPTRn to the value in the corresponding TBASEn. The TBPTR register is internally written by the eTSEC’s DMA controller during transmission. The pointer increments by eight (bytes) each time a descriptor is closed successfully by the eTSEC..." revised algorithm might also a more correct way of emulating this aspect of eTSEC peripheral. Cc: Alexander Graf Cc: Scott Wood Cc: Jason Wang Cc: qemu-devel@nongnu.org Signed-off-by: Andrey Smirnov --- Changes since v2: - Simplified new algorithm as per Jason Wang's suggestion hw/net/fsl_etsec/rings.c | 18 -- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c index 54c0127..d764b1c 100644 --- a/hw/net/fsl_etsec/rings.c +++ b/hw/net/fsl_etsec/rings.c @@ -358,12 +358,12 @@ void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr) /* Save flags before BD update */ bd_flags = bd.flags; -if (bd_flags & BD_TX_READY) { -process_tx_bd(etsec, &bd); +if (!(bd_flags & BD_TX_READY)) +break; -/* Write back BD after update */ -write_buffer_descriptor(etsec, bd_addr, &bd); -} +process_tx_bd(etsec, &bd); +/* Write back BD after update */ +write_buffer_descriptor(etsec, bd_addr, &bd); /* Wrap or next BD */ if (bd_flags & BD_WRAP) { @@ -371,12 +371,10 @@ void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr) } else { bd_addr += sizeof(eTSEC_rxtx_bd); } +} while (TRUE); -} while (bd_addr != ring_base); - -bd_addr = ring_base; - -/* Save the Buffer Descriptor Pointers to current bd */ +/* Save the Buffer Descriptor Pointers to last bd that was not + * succesfully closed */ etsec->regs[TBPTR0 + ring_nbr].value = bd_addr; /* Set transmit halt THLTx */ -- 2.9.3
[Qemu-devel] [PATCH v3] fsl_etsec: Fix Tx BD ring wrapping handling
Current code that handles Tx buffer desciprtor ring scanning employs the following algorithm: 1. Restore current buffer descriptor pointer from TBPTRn 2. Process current descriptor 3. If current descriptor has BD_WRAP flag set set current descriptor pointer to start of the descriptor ring 4. If current descriptor points to start of the ring exit the loop, otherwise increment current descriptor pointer and go to #2 5. Store current descriptor in TBPTRn The way the code is implemented results in buffer descriptor ring being scanned starting at offset/descriptor #0. While covering 99% of the cases, this algorithm becomes problematic for a number of edge cases. Consider the following scenario: guest OS driver initializes descriptor ring to N individual descriptors and starts sending data out. Depending on the volume of traffic and probably guest OS driver implementation it is possible that an edge case where a packet, spread across 2 descriptors is placed in descriptors N - 1 and 0 in that order(it is easy to imagine similar examples involving more than 2 descriptors). What happens then is aforementioned algorithm starts at descriptor 0, sees a descriptor marked as BD_LAST, which it happily sends out as a separate packet(very much malformed at this point) then the iteration continues and the first part of the original packet is tacked to the next transmission which ends up being bogus as well. This behvaiour can be pretty reliably observed when scp'ing data from a guest OS via TAP interface for files larger than 160K (every time for 700K+). This patch changes the scanning algorithm to do the following: 1. Restore "current" buffer descriptor pointer from TBPTRn 2. If "current" descriptor does not have BD_TX_READY set, goto #6 3. Process current descriptor 4. If "current" descriptor has BD_WRAP flag set "current" descriptor pointer to start of the descriptor ring otherwise set increment "current" by the size of one descriptor 5. Goto #1 6. Save "current" buffer descriptor in TBPTRn This way we preserve the information about which descriptor was processed last and always start where we left off avoiding the original problem. On top of that, judging by the following excerpt from MPC8548ERM (p. 14-48): "... When the end of the TxBD ring is reached, eTSEC initializes TBPTRn to the value in the corresponding TBASEn. The TBPTR register is internally written by the eTSEC’s DMA controller during transmission. The pointer increments by eight (bytes) each time a descriptor is closed successfully by the eTSEC..." revised algorithm might also a more correct way of emulating this aspect of eTSEC peripheral. Cc: Alexander Graf Cc: Scott Wood Cc: Jason Wang Cc: qemu-devel@nongnu.org Signed-off-by: Andrey Smirnov --- Changes since v1: - Simplified new algorithm as per Jason Wang's suggestion Changes since v2: - Fixed code style problems hw/net/fsl_etsec/rings.c | 19 +-- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c index 54c0127..d0f93ee 100644 --- a/hw/net/fsl_etsec/rings.c +++ b/hw/net/fsl_etsec/rings.c @@ -358,25 +358,24 @@ void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr) /* Save flags before BD update */ bd_flags = bd.flags; -if (bd_flags & BD_TX_READY) { -process_tx_bd(etsec, &bd); - -/* Write back BD after update */ -write_buffer_descriptor(etsec, bd_addr, &bd); +if (!(bd_flags & BD_TX_READY)) { +break; } +process_tx_bd(etsec, &bd); +/* Write back BD after update */ +write_buffer_descriptor(etsec, bd_addr, &bd); + /* Wrap or next BD */ if (bd_flags & BD_WRAP) { bd_addr = ring_base; } else { bd_addr += sizeof(eTSEC_rxtx_bd); } +} while (TRUE); -} while (bd_addr != ring_base); - -bd_addr = ring_base; - -/* Save the Buffer Descriptor Pointers to current bd */ +/* Save the Buffer Descriptor Pointers to last bd that was not + * succesfully closed */ etsec->regs[TBPTR0 + ring_nbr].value = bd_addr; /* Set transmit halt THLTx */ -- 2.9.3
[Qemu-devel] [PATCH] hw/arm: Allow manually specified /psci node
Change the code to avoid exiting QEMU if user provided DTB contains manually specified /psci node and skip any /psci related fixups instead. Fixes: 4cbca7d9b4 ("hw/arm: Move virt's PSCI DT fixup code to arm/boot.c") Cc: Peter Maydell Cc: Marc Zyngier Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Signed-off-by: Andrey Smirnov --- Mark: Sorry about the inconvenience, here's the fix (hopefully) to the prolem you reported in [1]. Let me know if skipping all PSCI related DTB fixup if /psic node is present is not the behaviour you had in mind for your suggested fix. Thanks, Andrey Smirnov [1] http://lists.gnu.org/archive/html/qemu-devel/2018-03/msg06914.html hw/arm/boot.c | 10 ++ 1 file changed, 10 insertions(+) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 6d0c92ab88..d9f9375cdb 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -422,6 +422,7 @@ static void fdt_add_psci_node(void *fdt) ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0)); const char *psci_method; int64_t psci_conduit; +int rc; psci_conduit = object_property_get_int(OBJECT(armcpu), "psci-conduit", @@ -439,6 +440,15 @@ static void fdt_add_psci_node(void *fdt) g_assert_not_reached(); } +/* + * If /psci node is present in provided DTB, assume that no fixup + * is necessary and all PSCI configuration should be taken as-is + */ +rc = fdt_path_offset(fdt, "/psci"); +if (rc >= 0) { +return; +} + qemu_fdt_add_subnode(fdt, "/psci"); if (armcpu->psci_version == 2) { const char comp[] = "arm,psci-0.2\0arm,psci"; -- 2.14.3
[Qemu-devel] [PATCH v2 00/27] Initial i.MX7 support
Hi everyone, This v2 of the patch series containing the work that I've done in order to enable support for i.MX7 emulation in QEMU. As the one before last commit in the series states the supported i.MX7 features are: * up to 2 Cortex A9 cores (SMP works with PSCI) * A7 MPCORE (identical to A15 MPCORE) * 4 GPTs modules * 7 GPIO controllers * 2 IOMUXC controllers * 1 CCM module * 1 SVNS module * 1 SRC module * 1 GPCv2 controller * 4 eCSPI controllers * 4 I2C controllers * 7 i.MX UART controllers * 2 FlexCAN controllers * 2 Ethernet controllers (FEC) * 3 SD controllers (USDHC) * 4 WDT modules * 1 SDMA module * 1 GPR module * 2 USBMISC modules * 2 ADC modules * 1 PCIe controller Feedback is welcome! Changes since [v1]: - Patchset no longer relies on "ignore_memory_transaction_failures = false" for its functionality - As a consequnce of implementing the above a number of patches implementing dummy IP block emulation as well as PCIe emulation patches that I alluded to in [v1] are now included in this patch series - "has_el3" property is no longer being set to "false" as a part of intialization of A7 CPU. I couldn't reproduce the issues that I thought I was having, so I just dropped that code. - A number of smaller feedback items from Peter and other has been incorporated into the patches. Peter, I didn't hear anything from you about the code of mcimx7d_add_psci_node(), as discussed here: https://www.mail-archive.com/qemu-devel@nongnu.org/msg486874.html so I kept the original code intact. As I mentioned before, my goal was to be able to boot into vanilla Linux kerenel and have working SMP without needing to use a PSCI implementing bootloader. If that is something that new board code shouldn't do, please let me know. Thanks, Andrey Smirnov [v1] https://lists.gnu.org/archive/html/qemu-devel/2017-09/msg04770.html P.S.: I don't know the best way to specify mailing list message archives, so if I did it wrong please let me know. Andrey Smirnov (27): imx_fec: Do not link to netdev imx_fec: Refactor imx_eth_enable_rx() imx_fec: Change queue flushing heuristics imx_fec: Use ENET_FTRL to determine truncation length imx_fec: Use MIN instead of explicit ternary operator imx_fec: Emulate SHIFT16 in ENETx_RACC imx_fec: Add support for multiple Tx DMA rings imx_fec: Use correct length for packet size imx_fec: Fix a typo in imx_enet_receive() imx_fec: Reserve full 4K page for the register file sdhci: Add i.MX specific subtype of SDHCI sdhci: Implement write method of ACMD12ERRSTS register i.MX: Add code to emulate i.MX7 CCM, PMU and ANALOG IP blocks i.MX: Add code to emulate i.MX2 watchdog IP block i.MX: Add code to emulate i.MX7 SNVS IP-block i.MX: Add code to emulate GPCv2 IP block i.MX: Add code to emulate i.MX7 IOMUXC IP block i.MX: Add i.MX7 GPT variant i.MX: Add code to emulate SDMA IP block i.MX: Add code to emulate FlexCAN IP block i.MX: Add implementation of i.MX7 GPR IP block pci: Add support for Designware IP block i.MX: Add code to emulate i.MX7 USBMISC IP block i.MX: Add code to emulate i.MX7 ADC IP block i.MX: Add code to emulate i.MX7 SRC IP-block i.MX: Add i.MX7 SOC implementation. Implement support for i.MX7 Sabre board default-configs/arm-softmmu.mak | 3 + hw/arm/Makefile.objs | 2 + hw/arm/fsl-imx6.c| 1 + hw/arm/fsl-imx7.c| 596 + hw/arm/mcimx7d-sabre.c | 101 +++ hw/dma/Makefile.objs | 1 + hw/dma/imx_sdma.c| 99 +++ hw/intc/Makefile.objs| 2 +- hw/intc/imx_gpcv2.c | 125 hw/misc/Makefile.objs| 8 + hw/misc/imx2_wdt.c | 88 ++ hw/misc/imx7_adc.c | 99 +++ hw/misc/imx7_ccm.c | 233 +++ hw/misc/imx7_gpr.c | 119 hw/misc/imx7_iomuxc.c| 99 +++ hw/misc/imx7_snvs.c | 83 ++ hw/misc/imx7_src.c | 93 ++ hw/misc/imx_flexcan.c| 99 +++ hw/net/imx_fec.c | 163 --- hw/pci-host/Makefile.objs| 2 + hw/pci-host/designware.c | 614 +++ hw/sd/sdhci-internal.h | 15 + hw/sd/sdhci.c| 130 - hw/timer/imx_gpt.c | 25 ++ hw/usb/Makefile.objs | 1 + hw/usb/imx-usbmisc.c | 99 +++ include/hw/arm/fsl-imx7.h| 217 ++ include/hw/dma/imx_sdma.h| 22 ++ include/hw/intc/imx_gpcv2.h | 22 ++ include/hw/misc/imx2_wdt.h | 34 +++ include/hw/misc/imx7_adc.h | 22 ++ include/hw/misc/imx7_ccm.h | 130 + inc
[Qemu-devel] [PATCH v2 02/27] imx_fec: Refactor imx_eth_enable_rx()
Refactor imx_eth_enable_rx() to have more meaningfull variable name than 'tmp' and to reduce number of logical negations done. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov --- hw/net/imx_fec.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 88b4b049d7..8b2e4b8ffe 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -536,19 +536,19 @@ static void imx_eth_do_tx(IMXFECState *s) static void imx_eth_enable_rx(IMXFECState *s) { IMXFECBufDesc bd; -bool tmp; +bool rx_ring_full; imx_fec_read_bd(&bd, s->rx_descriptor); -tmp = ((bd.flags & ENET_BD_E) != 0); +rx_ring_full = !(bd.flags & ENET_BD_E); -if (!tmp) { +if (rx_ring_full) { FEC_PRINTF("RX buffer full\n"); } else if (!s->regs[ENET_RDAR]) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } -s->regs[ENET_RDAR] = tmp ? ENET_RDAR_RDAR : 0; +s->regs[ENET_RDAR] = rx_ring_full ? 0 : ENET_RDAR_RDAR; } static void imx_eth_reset(DeviceState *d) -- 2.13.5
[Qemu-devel] [PATCH v2 01/27] imx_fec: Do not link to netdev
Binding to a particular netdev doesn't seem to belong to this layer and should probably be done as a part of board or SoC specific code. Convert all of the users of this IP block to use qdev_set_nic_properties() instead. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov --- hw/arm/fsl-imx6.c | 1 + hw/net/imx_fec.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index 26fd214004..2ed7146c52 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -385,6 +385,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) spi_table[i].irq)); } +qdev_set_nic_properties(DEVICE(&s->eth), &nd_table[0]); object_property_set_bool(OBJECT(&s->eth), true, "realized", &err); if (err) { error_propagate(errp, err); diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 90e6ee35ba..88b4b049d7 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1171,8 +1171,6 @@ static void imx_eth_realize(DeviceState *dev, Error **errp) qemu_macaddr_default_if_unset(&s->conf.macaddr); -s->conf.peers.ncs[0] = nd_table[0].netdev; - s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf, object_get_typename(OBJECT(dev)), DEVICE(dev)->id, s); -- 2.13.5
[Qemu-devel] [PATCH v2 04/27] imx_fec: Use ENET_FTRL to determine truncation length
Frame truncation length, TRUNC_FL, is determined by the contents of ENET_FTRL register, so convert the code to use it instead of a hardcoded constant. To avoid the case where TRUNC_FL is greater that ENET_MAX_FRAME_SIZE, increase the value of the latter to its theoretical maximum of 16K. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/net/imx_fec.c | 4 ++-- include/hw/net/imx_fec.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index eb034ffd0c..dda0816fb3 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1052,8 +1052,8 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, crc_ptr = (uint8_t *) &crc; /* Huge frames are truncted. */ -if (size > ENET_MAX_FRAME_SIZE) { -size = ENET_MAX_FRAME_SIZE; +if (size > s->regs[ENET_FTRL]) { +size = s->regs[ENET_FTRL]; flags |= ENET_BD_TR | ENET_BD_LG; } diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h index 4bc8f03ec2..0fcc4f0c71 100644 --- a/include/hw/net/imx_fec.h +++ b/include/hw/net/imx_fec.h @@ -86,7 +86,6 @@ #define ENET_TCCR3 393 #define ENET_MAX 400 -#define ENET_MAX_FRAME_SIZE2032 /* EIR and EIMR */ #define ENET_INT_HB(1 << 31) @@ -155,6 +154,8 @@ #define ENET_RCR_NLC (1 << 30) #define ENET_RCR_GRS (1 << 31) +#define ENET_MAX_FRAME_SIZE(1 << ENET_RCR_MAX_FL_LENGTH) + /* TCR */ #define ENET_TCR_GTS (1 << 0) #define ENET_TCR_FDEN (1 << 2) -- 2.13.5
[Qemu-devel] [PATCH v2 03/27] imx_fec: Change queue flushing heuristics
In current implementation, packet queue flushing logic seem to suffer from a deadlock like scenario if a packet is received by the interface before before Rx ring is initialized by Guest's driver. Consider the following sequence of events: 1. A QEMU instance is started against a TAP device on Linux host, running Linux guest, e. g., something to the effect of: qemu-system-arm \ -net nic,model=imx.fec,netdev=lan0 \ netdev tap,id=lan0,ifname=tap0,script=no,downscript=no \ ... rest of the arguments ... 2. Once QEMU starts, but before guest reaches the point where FEC deriver is done initializing the HW, Guest, via TAP interface, receives a number of multicast MDNS packets from Host (not necessarily true for every OS, but it happens at least on Fedora 25) 3. Recieving a packet in such a state results in imx_eth_can_receive() returning '0', which in turn causes tap_send() to disable corresponding event (tap.c:203) 4. Once Guest's driver reaches the point where it is ready to recieve packets it prepares Rx ring descriptors and writes ENET_RDAR_RDAR to ENET_RDAR register to indicate to HW that more descriptors are ready. And at this points emulation layer does this: s->regs[index] = ENET_RDAR_RDAR; imx_eth_enable_rx(s); which, combined with: if (!s->regs[ENET_RDAR]) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } results in Rx queue never being flushed and corresponding I/O event beign disabled. To prevent the problem, change the code to always flush packet queue when ENET_RDAR transitions 0 -> ENET_RDAR_RDAR. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/net/imx_fec.c | 12 ++-- include/hw/net/imx_fec.h | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 8b2e4b8ffe..eb034ffd0c 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -533,7 +533,7 @@ static void imx_eth_do_tx(IMXFECState *s) } } -static void imx_eth_enable_rx(IMXFECState *s) +static void imx_eth_enable_rx(IMXFECState *s, bool flush) { IMXFECBufDesc bd; bool rx_ring_full; @@ -544,7 +544,7 @@ static void imx_eth_enable_rx(IMXFECState *s) if (rx_ring_full) { FEC_PRINTF("RX buffer full\n"); -} else if (!s->regs[ENET_RDAR]) { +} else if (flush) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } @@ -807,7 +807,7 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, if (s->regs[ENET_ECR] & ENET_ECR_ETHEREN) { if (!s->regs[index]) { s->regs[index] = ENET_RDAR_RDAR; -imx_eth_enable_rx(s); +imx_eth_enable_rx(s, true); } } else { s->regs[index] = 0; @@ -930,7 +930,7 @@ static int imx_eth_can_receive(NetClientState *nc) FEC_PRINTF("\n"); -return s->regs[ENET_RDAR] ? 1 : 0; +return !!s->regs[ENET_RDAR]; } static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, @@ -1020,7 +1020,7 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, } } s->rx_descriptor = addr; -imx_eth_enable_rx(s); +imx_eth_enable_rx(s, false); imx_eth_update(s); return len; } @@ -1116,7 +1116,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, } } s->rx_descriptor = addr; -imx_eth_enable_rx(s); +imx_eth_enable_rx(s, false); imx_eth_update(s); return len; } diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h index 62ad473b05..4bc8f03ec2 100644 --- a/include/hw/net/imx_fec.h +++ b/include/hw/net/imx_fec.h @@ -252,6 +252,7 @@ typedef struct IMXFECState { uint32_t phy_int_mask; bool is_fec; +bool needs_flush; } IMXFECState; #endif -- 2.13.5
[Qemu-devel] [PATCH v2 06/27] imx_fec: Emulate SHIFT16 in ENETx_RACC
Needed to support latest Linux kernel driver which relies on that functionality. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov --- hw/net/imx_fec.c | 23 +++ include/hw/net/imx_fec.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 18de508e8c..131e7fd734 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1037,6 +1037,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, uint8_t *crc_ptr; unsigned int buf_len; size_t size = len; +bool shift16 = s->regs[ENET_RACC] & ENET_RACC_SHIFT16; FEC_PRINTF("len %d\n", (int)size); @@ -1051,6 +1052,10 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, crc = cpu_to_be32(crc32(~0, buf, size)); crc_ptr = (uint8_t *) &crc; +if (shift16) { +size += 2; +} + /* Huge frames are truncted. */ if (size > s->regs[ENET_FTRL]) { size = s->regs[ENET_FTRL]; @@ -1087,6 +1092,24 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, buf_len += size - 4; } buf_addr = bd.data; + +if (shift16) { +/* + * If SHIFT16 bit of ENETx_RACC register is set we need to + * align the payload to 4-byte boundary. + */ +const uint8_t zeros[2] = { 0 }; + +dma_memory_write(&address_space_memory, buf_addr, + zeros, sizeof(zeros)); + +buf_addr += sizeof(zeros); +buf_len -= sizeof(zeros); + +/* We only do this once per Ethernet frame */ +shift16 = false; +} + dma_memory_write(&address_space_memory, buf_addr, buf, buf_len); buf += buf_len; if (size < 4) { diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h index 0fcc4f0c71..e482d1c13b 100644 --- a/include/hw/net/imx_fec.h +++ b/include/hw/net/imx_fec.h @@ -170,6 +170,8 @@ #define ENET_TWFR_TFWR_LENGTH (6) #define ENET_TWFR_STRFWD (1 << 8) +#define ENET_RACC_SHIFT16 BIT(7) + /* Buffer Descriptor. */ typedef struct { uint16_t length; -- 2.13.5
[Qemu-devel] [PATCH v2 08/27] imx_fec: Use correct length for packet size
Use 'frame_size' instead of 'len' when calling qemu_send_packet(), failing to do so results in malformed packets send in case when that packed is fragmented into multiple DMA transactions. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov --- hw/net/imx_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 38d8c27dcd..eefb3b2c62 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -528,7 +528,7 @@ static void imx_enet_do_tx(IMXFECState *s, uint32_t index) } } /* Last buffer in frame. */ -qemu_send_packet(qemu_get_queue(s->nic), frame, len); +qemu_send_packet(qemu_get_queue(s->nic), frame, frame_size); ptr = frame; frame_size = 0; if (bd.option & ENET_BD_TX_INT) { -- 2.13.5
[Qemu-devel] [PATCH v2 09/27] imx_fec: Fix a typo in imx_enet_receive()
Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/net/imx_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index eefb3b2c62..48d012cad6 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1121,7 +1121,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, size += 2; } -/* Huge frames are truncted. */ +/* Huge frames are truncated. */ if (size > s->regs[ENET_FTRL]) { size = s->regs[ENET_FTRL]; flags |= ENET_BD_TR | ENET_BD_LG; -- 2.13.5
[Qemu-devel] [PATCH v2 05/27] imx_fec: Use MIN instead of explicit ternary operator
Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Andrey Smirnov --- hw/net/imx_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index dda0816fb3..18de508e8c 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1076,7 +1076,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, TYPE_IMX_FEC, __func__); break; } -buf_len = (size <= s->regs[ENET_MRBR]) ? size : s->regs[ENET_MRBR]; +buf_len = MIN(size, s->regs[ENET_MRBR]); bd.length = buf_len; size -= buf_len; -- 2.13.5
[Qemu-devel] [PATCH v2 07/27] imx_fec: Add support for multiple Tx DMA rings
More recent version of the IP block support more than one Tx DMA ring, so add the code implementing that feature. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/net/imx_fec.c | 106 ++- include/hw/net/imx_fec.h | 18 +++- 2 files changed, 102 insertions(+), 22 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 131e7fd734..38d8c27dcd 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -198,13 +198,13 @@ static const char *imx_eth_reg_name(IMXFECState *s, uint32_t index) static const VMStateDescription vmstate_imx_eth = { .name = TYPE_IMX_FEC, -.version_id = 2, -.minimum_version_id = 2, +.version_id = 3, +.minimum_version_id = 3, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX), VMSTATE_UINT32(rx_descriptor, IMXFECState), -VMSTATE_UINT32(tx_descriptor, IMXFECState), - +VMSTATE_UINT32_ARRAY(tx_descriptor, IMXFECState, ENET_TX_RING_NUM), +VMSTATE_UINT32(tx_ring_num, IMXFECState), VMSTATE_UINT32(phy_status, IMXFECState), VMSTATE_UINT32(phy_control, IMXFECState), VMSTATE_UINT32(phy_advertise, IMXFECState), @@ -407,7 +407,7 @@ static void imx_fec_do_tx(IMXFECState *s) int frame_size = 0, descnt = 0; uint8_t frame[ENET_MAX_FRAME_SIZE]; uint8_t *ptr = frame; -uint32_t addr = s->tx_descriptor; +uint32_t addr = s->tx_descriptor[0]; while (descnt++ < IMX_MAX_DESC) { IMXFECBufDesc bd; @@ -448,17 +448,47 @@ static void imx_fec_do_tx(IMXFECState *s) } } -s->tx_descriptor = addr; +s->tx_descriptor[0] = addr; imx_eth_update(s); } -static void imx_enet_do_tx(IMXFECState *s) +static void imx_enet_do_tx(IMXFECState *s, uint32_t index) { int frame_size = 0, descnt = 0; uint8_t frame[ENET_MAX_FRAME_SIZE]; uint8_t *ptr = frame; -uint32_t addr = s->tx_descriptor; +uint32_t addr, int_txb, int_txf, tdsr; +size_t ring; + +switch (index) { +case ENET_TDAR: +ring= 0; +int_txb = ENET_INT_TXB; +int_txf = ENET_INT_TXF; +tdsr= ENET_TDSR; +break; +case ENET_TDAR1: +ring= 1; +int_txb = ENET_INT_TXB1; +int_txf = ENET_INT_TXF1; +tdsr= ENET_TDSR1; +break; +case ENET_TDAR2: +ring= 2; +int_txb = ENET_INT_TXB2; +int_txf = ENET_INT_TXF2; +tdsr= ENET_TDSR2; +break; +default: +qemu_log_mask(LOG_GUEST_ERROR, + "%s: bogus value for index %x\n", + __func__, index); +abort(); +break; +} + +addr = s->tx_descriptor[ring]; while (descnt++ < IMX_MAX_DESC) { IMXENETBufDesc bd; @@ -502,32 +532,32 @@ static void imx_enet_do_tx(IMXFECState *s) ptr = frame; frame_size = 0; if (bd.option & ENET_BD_TX_INT) { -s->regs[ENET_EIR] |= ENET_INT_TXF; +s->regs[ENET_EIR] |= int_txf; } } if (bd.option & ENET_BD_TX_INT) { -s->regs[ENET_EIR] |= ENET_INT_TXB; +s->regs[ENET_EIR] |= int_txb; } bd.flags &= ~ENET_BD_R; /* Write back the modified descriptor. */ imx_enet_write_bd(&bd, addr); /* Advance to the next descriptor. */ if ((bd.flags & ENET_BD_W) != 0) { -addr = s->regs[ENET_TDSR]; +addr = s->regs[tdsr]; } else { addr += sizeof(bd); } } -s->tx_descriptor = addr; +s->tx_descriptor[ring] = addr; imx_eth_update(s); } -static void imx_eth_do_tx(IMXFECState *s) +static void imx_eth_do_tx(IMXFECState *s, uint32_t index) { if (!s->is_fec && (s->regs[ENET_ECR] & ENET_ECR_EN1588)) { -imx_enet_do_tx(s); +imx_enet_do_tx(s, index); } else { imx_fec_do_tx(s); } @@ -585,7 +615,7 @@ static void imx_eth_reset(DeviceState *d) } s->rx_descriptor = 0; -s->tx_descriptor = 0; +memset(s->tx_descriptor, 0, sizeof(s->tx_descriptor)); /* We also reset the PHY */ phy_reset(s); @@ -791,6 +821,7 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { IMXFECState *s = IMX_FEC(opaque); +const bool single_tx_ring = s->tx_ring_num != 3; uint32_t index = offset >> 2; FEC_PRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx_eth_reg_name(s, index), @@ -813,10 +844,18 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, s->regs[index] = 0; }
[Qemu-devel] [PATCH v2 10/27] imx_fec: Reserve full 4K page for the register file
Some i.MX SoCs (e.g. i.MX7) have FEC registers going as far as offset 0x614, so to avoid getting aborts when accessing those on QEMU, extend the register file to cover 4KB of address space instead of just 1K. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/net/imx_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 48d012cad6..e236bc933c 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1252,7 +1252,7 @@ static void imx_eth_realize(DeviceState *dev, Error **errp) SysBusDevice *sbd = SYS_BUS_DEVICE(dev); memory_region_init_io(&s->iomem, OBJECT(dev), &imx_eth_ops, s, - TYPE_IMX_FEC, 0x400); + TYPE_IMX_FEC, 0x1000); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq[0]); sysbus_init_irq(sbd, &s->irq[1]); -- 2.13.5
[Qemu-devel] [PATCH v2 12/27] sdhci: Implement write method of ACMD12ERRSTS register
Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/sd/sdhci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index f561cc44e3..53e5e011a7 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1139,6 +1139,9 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) s->admasysaddr = (s->admasysaddr & (0xULL | ((uint64_t)mask << 32))) | ((uint64_t)value << 32); break; +case SDHC_ACMD12ERRSTS: +MASKED_WRITE(s->acmd12errsts, mask, value); +break; case SDHC_FEAER: s->acmd12errsts |= value; s->errintsts |= (value >> 16) & s->errintstsen; -- 2.13.5
[Qemu-devel] [PATCH v2 13/27] i.MX: Add code to emulate i.MX7 CCM, PMU and ANALOG IP blocks
Add minimal code needed to allow upstream Linux guest to boot. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/misc/Makefile.objs | 1 + hw/misc/imx7_ccm.c | 233 + include/hw/misc/imx7_ccm.h | 130 + 3 files changed, 364 insertions(+) create mode 100644 hw/misc/imx7_ccm.c create mode 100644 include/hw/misc/imx7_ccm.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 29fb922cef..ac1be05a03 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -34,6 +34,7 @@ obj-$(CONFIG_IMX) += imx31_ccm.o obj-$(CONFIG_IMX) += imx25_ccm.o obj-$(CONFIG_IMX) += imx6_ccm.o obj-$(CONFIG_IMX) += imx6_src.o +obj-$(CONFIG_IMX) += imx7_ccm.o obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o obj-$(CONFIG_MAINSTONE) += mst_fpga.o diff --git a/hw/misc/imx7_ccm.c b/hw/misc/imx7_ccm.c new file mode 100644 index 00..2876164cfa --- /dev/null +++ b/hw/misc/imx7_ccm.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX7 CCM, PMU and ANALOG IP blocks emulation code + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" + +#include "hw/misc/imx7_ccm.h" + +static uint32_t imx7_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock) +{ +/* + * This function is "consumed" by GPT emulation code, however on + * i.MX7 each GPT block can have their own clock root. This means + * that this functions needs somehow to know requester's identity + * and the way to pass it: be it via additional IMXClk constants + * or by adding another argument to this method needs to be + * figured out + */ +qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Not implemented\n", + TYPE_IMX7_CCM, __func__); +return 0; +} + +static void imx7_ccm_reset(DeviceState *dev) +{ +IMX7CCMState *s = IMX7_CCM(dev); + +s->analog[CCM_ANALOG_PLL_ARM] = 0x2042; +s->analog[CCM_ANALOG_PLL_DDR] = 0x0060302c; +s->analog[CCM_ANALOG_PLL_DDR_SS] = 0x; +s->analog[CCM_ANALOG_PLL_DDR_NUM] = 0x06aaac4d; +s->analog[CCM_ANALOG_PLL_DDR_DENOM] = 0x13ec; +s->analog[CCM_ANALOG_PLL_480] = 0x2000; +s->analog[CCM_ANALOG_PLL_480A]= 0x52605a56; +s->analog[CCM_ANALOG_PLL_480B]= 0x52525216; +s->analog[CCM_ANALOG_PLL_ENET]= 0x1fc0; +s->analog[CCM_ANALOG_PLL_AUDIO] = 0x0001301b; +s->analog[CCM_ANALOG_PLL_AUDIO_SS]= 0x; +s->analog[CCM_ANALOG_PLL_AUDIO_NUM] = 0x05f5e100; +s->analog[CCM_ANALOG_PLL_AUDIO_DENOM] = 0x2964619c; +s->analog[CCM_ANALOG_PLL_VIDEO] = 0x0008201b; +s->analog[CCM_ANALOG_PLL_VIDEO_SS]= 0x; +s->analog[CCM_ANALOG_PLL_VIDEO_NUM] = 0xf699; +s->analog[CCM_ANALOG_PLL_VIDEO_DENOM] = 0x000f4240; +s->analog[CCM_ANALOG_PLL_MISC0] = 0x; + +/* all PLLs need to be locked */ +s->analog[CCM_ANALOG_PLL_ARM] |= CCM_ANALOG_PLL_LOCK; +s->analog[CCM_ANALOG_PLL_DDR] |= CCM_ANALOG_PLL_LOCK; +s->analog[CCM_ANALOG_PLL_480] |= CCM_ANALOG_PLL_LOCK; +s->analog[CCM_ANALOG_PLL_480A] |= CCM_ANALOG_PLL_LOCK; +s->analog[CCM_ANALOG_PLL_480B] |= CCM_ANALOG_PLL_LOCK; +s->analog[CCM_ANALOG_PLL_ENET] |= CCM_ANALOG_PLL_LOCK; +s->analog[CCM_ANALOG_PLL_AUDIO] |= CCM_ANALOG_PLL_LOCK; +s->analog[CCM_ANALOG_PLL_VIDEO] |= CCM_ANALOG_PLL_LOCK; +s->analog[CCM_ANALOG_PLL_MISC0] |= CCM_ANALOG_PLL_LOCK; + +/* + * Since I couldn't find any info about this in the reference + * manual the value of this register is based strictly on matching + * what Linux kernel expects it to be. + */ +s->analog[CCM_ANALOG_DIGPROG] = 0x72; +/* + * Set revision to be 1.0 (Arbitrary choice, no particular + * reason). + */ +s->analog[CCM_ANALOG_DIGPROG] |= 0x10; +} + +#define CCM_INDEX(offset) (((offset) & ~(hwaddr)0xF) / sizeof(uint32_t)) +#define CCM_BITOP(offset) ((offset) & (hwaddr)0xF) + +enum { +CCM_BITOP_NONE = 0x00, +CCM_BITOP_SET = 0x04, +CCM_BITOP_CLR = 0x08, +CCM_BITOP_TOG = 0x0C, +}; + +static uint64_t imx7_set_clr_tog_read(void *opaque, hwaddr offset, + unsigned size) +{ +const uint32_t *mmio = opaque; + +return mmio[CCM_INDEX(offset)]; +} + +static void imx7_set_clr_tog_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ +const uint8_
[Qemu-devel] [PATCH v2 16/27] i.MX: Add code to emulate GPCv2 IP block
Add minimal code needed to allow upstream Linux guest to boot. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/intc/Makefile.objs | 2 +- hw/intc/imx_gpcv2.c | 125 include/hw/intc/imx_gpcv2.h | 22 3 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 hw/intc/imx_gpcv2.c create mode 100644 include/hw/intc/imx_gpcv2.h diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 78426a7daf..db234901aa 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -4,7 +4,7 @@ common-obj-$(CONFIG_PL190) += pl190.o common-obj-$(CONFIG_PUV3) += puv3_intc.o common-obj-$(CONFIG_XILINX) += xilinx_intc.o common-obj-$(CONFIG_ETRAXFS) += etraxfs_pic.o -common-obj-$(CONFIG_IMX) += imx_avic.o +common-obj-$(CONFIG_IMX) += imx_avic.o imx_gpcv2.o common-obj-$(CONFIG_LM32) += lm32_pic.o common-obj-$(CONFIG_REALVIEW) += realview_gic.o common-obj-$(CONFIG_SLAVIO) += slavio_intctl.o diff --git a/hw/intc/imx_gpcv2.c b/hw/intc/imx_gpcv2.c new file mode 100644 index 00..496ed31b78 --- /dev/null +++ b/hw/intc/imx_gpcv2.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX7 GPCv2 block emulation code + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/intc/imx_gpcv2.h" +#include "qemu/log.h" + +#define GPC_PU_PGC_SW_PUP_REQ 0x0f8 +#define GPC_PU_PGC_SW_PDN_REQ 0x104 + +#define USB_HSIC_PHY_SW_Pxx_REQ BIT(4) +#define USB_OTG2_PHY_SW_Pxx_REQ BIT(3) +#define USB_OTG1_PHY_SW_Pxx_REQ BIT(2) +#define PCIE_PHY_SW_Pxx_REQ BIT(1) +#define MIPI_PHY_SW_Pxx_REQ BIT(0) + + +static void imx_gpcv2_reset(DeviceState *dev) +{ +IMXGPCv2State *s = IMX_GPCV2(dev); + +memset(s->regs, 0, sizeof(s->regs)); +} + +static uint64_t imx_gpcv2_read(void *opaque, hwaddr offset, + unsigned size) +{ +IMXGPCv2State *s = opaque; + +return s->regs[offset / sizeof(uint32_t)]; +} + +static void imx_gpcv2_write(void *opaque, hwaddr offset, +uint64_t value, unsigned size) +{ +IMXGPCv2State *s = opaque; +const size_t idx = offset / sizeof(uint32_t); + +s->regs[idx] = value; + +/* + * Real HW will clear those bits once as a way to indicate that + * power up request is complete + */ +if (offset == GPC_PU_PGC_SW_PUP_REQ || +offset == GPC_PU_PGC_SW_PDN_REQ) { +s->regs[idx] &= ~(USB_HSIC_PHY_SW_Pxx_REQ | + USB_OTG2_PHY_SW_Pxx_REQ | + USB_OTG1_PHY_SW_Pxx_REQ | + PCIE_PHY_SW_Pxx_REQ | + MIPI_PHY_SW_Pxx_REQ); +} +} + +static const struct MemoryRegionOps imx_gpcv2_ops = { +.read = imx_gpcv2_read, +.write = imx_gpcv2_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.impl = { +/* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ +.min_access_size = 4, +.max_access_size = 4, +.unaligned = false, +}, +}; + +static void imx_gpcv2_init(Object *obj) +{ +SysBusDevice *sd = SYS_BUS_DEVICE(obj); +IMXGPCv2State *s = IMX_GPCV2(obj); + +memory_region_init_io(&s->iomem, + obj, + &imx_gpcv2_ops, + s, + TYPE_IMX_GPCV2 ".iomem", + sizeof(s->regs)); +sysbus_init_mmio(sd, &s->iomem); +} + +static const VMStateDescription vmstate_imx_gpcv2 = { +.name = TYPE_IMX_GPCV2, +.version_id = 1, +.minimum_version_id = 1, +.fields = (VMStateField[]) { +VMSTATE_UINT32_ARRAY(regs, IMXGPCv2State, GPC_NUM), +VMSTATE_END_OF_LIST() +}, +}; + +static void imx_gpcv2_class_init(ObjectClass *klass, void *data) +{ +DeviceClass *dc = DEVICE_CLASS(klass); + +dc->reset = imx_gpcv2_reset; +dc->vmsd = &vmstate_imx_gpcv2; +dc->desc = "i.MX GPCv2 Module"; +} + +static const TypeInfo imx_gpcv2_info = { +.name = TYPE_IMX_GPCV2, +.parent= TYPE_SYS_BUS_DEVICE, +.instance_size = sizeof(IMXGPCv2State), +.instance_init = imx_gpcv2_init, +.class_init= imx_gpcv2_class_init, +}; + +static void imx_gpcv2_register_type(void) +{ +type_register_static(&imx_gpcv2_info); +} +type_init(imx_gpcv2_register_type) diff --git a/include/hw/intc/imx_gpcv2.h b/includ
[Qemu-devel] [PATCH v2 14/27] i.MX: Add code to emulate i.MX2 watchdog IP block
Add enough code to emulate i.MX2 watchdog IP block so it would be possible to reboot the machine running Linux Guest. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/misc/Makefile.objs | 1 + hw/misc/imx2_wdt.c | 88 ++ include/hw/misc/imx2_wdt.h | 34 ++ 3 files changed, 123 insertions(+) create mode 100644 hw/misc/imx2_wdt.c create mode 100644 include/hw/misc/imx2_wdt.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index ac1be05a03..c393a93456 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -35,6 +35,7 @@ obj-$(CONFIG_IMX) += imx25_ccm.o obj-$(CONFIG_IMX) += imx6_ccm.o obj-$(CONFIG_IMX) += imx6_src.o obj-$(CONFIG_IMX) += imx7_ccm.o +obj-$(CONFIG_IMX) += imx2_wdt.o obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o obj-$(CONFIG_MAINSTONE) += mst_fpga.o diff --git a/hw/misc/imx2_wdt.c b/hw/misc/imx2_wdt.c new file mode 100644 index 00..3a1c33aa51 --- /dev/null +++ b/hw/misc/imx2_wdt.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX2 Watchdog IP block + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "sysemu/watchdog.h" + +#include "hw/misc/imx2_wdt.h" + +#define IMX2_WDT_WCR_WDABIT(5) /* -> External Reset WDOG_B */ +#define IMX2_WDT_WCR_SRSBIT(4) /* -> Software Reset Signal */ + +static uint64_t imx2_wdt_read(void *opaque, hwaddr addr, + unsigned int size) +{ +return 0; +} + +static void imx2_wdt_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ +if (addr == IMX2_WDT_WCR && +(value & (IMX2_WDT_WCR_WDA | IMX2_WDT_WCR_SRS))) { +watchdog_perform_action(); +} +} + +static const MemoryRegionOps imx2_wdt_ops = { +.read = imx2_wdt_read, +.write = imx2_wdt_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.impl = { +/* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the + * real device but in practice there is no reason for a guest + * to access this device unaligned. + */ +.min_access_size = 4, +.max_access_size = 4, +.unaligned = false, +}, +}; + +static void imx2_wdt_realize(DeviceState *dev, Error **errp) +{ +IMX2WdtState *s = IMX2_WDT(dev); + +memory_region_init_io(&s->mmio, OBJECT(dev), + &imx2_wdt_ops, s, + TYPE_IMX2_WDT".mmio", + IMX2_WDT_REG_NUM * sizeof(uint16_t)); +sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); +} + +static void imx2_wdt_class_init(ObjectClass *klass, void *data) +{ +DeviceClass *dc = DEVICE_CLASS(klass); + +dc->realize = imx2_wdt_realize; +set_bit(DEVICE_CATEGORY_MISC, dc->categories); +} + +static const TypeInfo imx2_wdt_info = { +.name = TYPE_IMX2_WDT, +.parent= TYPE_SYS_BUS_DEVICE, +.instance_size = sizeof(IMX2WdtState), +.class_init= imx2_wdt_class_init, +}; + +static WatchdogTimerModel model = { +.wdt_name = "imx2-watchdog", +.wdt_description = "i.MX2 Watchdog", +}; + +static void imx2_wdt_register_type(void) +{ +watchdog_add_model(&model); +type_register_static(&imx2_wdt_info); +} +type_init(imx2_wdt_register_type) diff --git a/include/hw/misc/imx2_wdt.h b/include/hw/misc/imx2_wdt.h new file mode 100644 index 00..e67ac6939d --- /dev/null +++ b/include/hw/misc/imx2_wdt.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX2 Watchdog IP block + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef IMX2_WDT_H +#define IMX2_WDT_H + +#include "qemu/bitops.h" +#include "hw/sysbus.h" + +#define TYPE_IMX2_WDT "imx2.wdt" +#define IMX2_WDT(obj) OBJECT_CHECK(IMX2WdtState, (obj), TYPE_IMX2_WDT) + +enum IMX2WdtRegisters { +IMX2_WDT_WCR = 0x, +IMX2_WDT_REG_NUM = 0x0008 / sizeof(uint16_t) + 1, +}; + + +typedef struct IMX2WdtState { +/* */ +SysBusDevice parent_obj; + +MemoryRegion mmio; +} IMX2WdtState; + +#endif /* IMX7_SNVS_H */ -- 2.13.5
[Qemu-devel] [PATCH v2 11/27] sdhci: Add i.MX specific subtype of SDHCI
IP block found on several generations of i.MX family does not use vanilla SDHCI implementation and it comes with a number of quirks. Introduce i.MX SDHCI subtype of SDHCI block to add code necessary to support unmodified Linux guest driver. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/sd/sdhci-internal.h | 15 ++ hw/sd/sdhci.c | 127 - include/hw/sd/sdhci.h | 8 3 files changed, 148 insertions(+), 2 deletions(-) diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h index 161177cf39..2a1b4b06ee 100644 --- a/hw/sd/sdhci-internal.h +++ b/hw/sd/sdhci-internal.h @@ -91,6 +91,8 @@ #define SDHC_CTRL_ADMA2_32 0x10 #define SDHC_CTRL_ADMA2_64 0x18 #define SDHC_DMA_TYPE(x) ((x) & SDHC_CTRL_DMA_CHECK_MASK) +#define SDHC_CTRL_4BITBUS 0x02 +#define SDHC_CTRL_8BITBUS 0x20 /* R/W Power Control Register 0x0 */ #define SDHC_PWRCON0x29 @@ -229,4 +231,17 @@ enum { extern const VMStateDescription sdhci_vmstate; + +#define ESDHC_MIX_CTRL 0x48 +#define ESDHC_VENDOR_SPEC 0xc0 +#define ESDHC_DLL_CTRL 0x60 + +#define ESDHC_TUNING_CTRL 0xcc +#define ESDHC_TUNE_CTRL_STATUS 0x68 +#define ESDHC_WTMK_LVL 0x44 + +#define ESDHC_CTRL_4BITBUS (0x1 << 1) +#define ESDHC_CTRL_8BITBUS (0x2 << 1) + + #endif diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 6d6a791ee9..f561cc44e3 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -265,7 +265,8 @@ static void sdhci_send_command(SDHCIState *s) } } -if ((s->norintstsen & SDHC_NISEN_TRSCMP) && +if (!(s->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) && +(s->norintstsen & SDHC_NISEN_TRSCMP) && (s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY) { s->norintsts |= SDHC_NIS_TRSCMP; } @@ -1191,6 +1192,8 @@ static void sdhci_initfn(SDHCIState *s) s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_raise_insertion_irq, s); s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s); + +s->io_ops = &sdhci_mmio_ops; } static void sdhci_uninitfn(SDHCIState *s) @@ -1347,7 +1350,7 @@ static void sdhci_sysbus_realize(DeviceState *dev, Error ** errp) s->buf_maxsz = sdhci_get_fifolen(s); s->fifo_buffer = g_malloc0(s->buf_maxsz); sysbus_init_irq(sbd, &s->irq); -memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci", +memory_region_init_io(&s->iomem, OBJECT(s), s->io_ops, s, "sdhci", SDHC_REGISTERS_MAP_SIZE); sysbus_init_mmio(sbd, &s->iomem); } @@ -1386,11 +1389,131 @@ static const TypeInfo sdhci_bus_info = { .class_init = sdhci_bus_class_init, }; +static uint64_t usdhc_read(void *opaque, hwaddr offset, unsigned size) +{ +SDHCIState *s = SYSBUS_SDHCI(opaque); +uint32_t ret; +uint16_t hostctl; + +switch (offset) { +default: +return sdhci_read(opaque, offset, size); + +case SDHC_HOSTCTL: +hostctl = SDHC_DMA_TYPE(s->hostctl) << 5; + +if (s->hostctl & SDHC_CTRL_8BITBUS) { +hostctl |= ESDHC_CTRL_8BITBUS; +} + +if (s->hostctl & SDHC_CTRL_4BITBUS) { +hostctl |= ESDHC_CTRL_4BITBUS; +} + +ret = hostctl | (s->blkgap << 16) | +(s->wakcon << 24); + +break; + +case ESDHC_DLL_CTRL: +case ESDHC_TUNE_CTRL_STATUS: +case 0x6c: +case ESDHC_TUNING_CTRL: +case ESDHC_VENDOR_SPEC: +case ESDHC_MIX_CTRL: +case ESDHC_WTMK_LVL: +ret = 0; +break; +} + +return ret; +} + +static void +usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) +{ +SDHCIState *s = SYSBUS_SDHCI(opaque); +uint8_t hostctl = 0; +uint32_t value = (uint32_t)val; + +switch (offset) { +case ESDHC_DLL_CTRL: +case ESDHC_TUNE_CTRL_STATUS: +case 0x6c: +case ESDHC_TUNING_CTRL: +case ESDHC_WTMK_LVL: +case ESDHC_VENDOR_SPEC: +break; + +case SDHC_HOSTCTL: +if (value & ESDHC_CTRL_8BITBUS) { +hostctl |= SDHC_CTRL_8BITBUS; +} + +if (value & ESDHC_CTRL_4BITBUS) { +hostctl |= ESDHC_CTRL_4BITBUS; +} + +hostctl |= SDHC_DMA_TYPE(value >> 5); + +value &= ~0xFE; +value |= hostctl; +value &= ~0xFF00; +value |= s->pwrcon; + +sdhci_write(opaque, offset, value, size); +break; + +case ESDHC_MIX_CTRL: +/* + * The layout o
[Qemu-devel] [PATCH v2 19/27] i.MX: Add code to emulate SDMA IP block
Add minimal code needed to allow upstream Linux guest to boot. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/dma/Makefile.objs | 1 + hw/dma/imx_sdma.c | 99 +++ include/hw/dma/imx_sdma.h | 22 +++ 3 files changed, 122 insertions(+) create mode 100644 hw/dma/imx_sdma.c create mode 100644 include/hw/dma/imx_sdma.h diff --git a/hw/dma/Makefile.objs b/hw/dma/Makefile.objs index 087c8e6855..3cee0b1047 100644 --- a/hw/dma/Makefile.objs +++ b/hw/dma/Makefile.objs @@ -14,3 +14,4 @@ obj-$(CONFIG_XLNX_ZYNQMP) += xlnx_dpdma.o obj-$(CONFIG_OMAP) += omap_dma.o soc_dma.o obj-$(CONFIG_PXA2XX) += pxa2xx_dma.o obj-$(CONFIG_RASPI) += bcm2835_dma.o +obj-$(CONFIG_IMX) += imx_sdma.o diff --git a/hw/dma/imx_sdma.c b/hw/dma/imx_sdma.c new file mode 100644 index 00..0776e41b9a --- /dev/null +++ b/hw/dma/imx_sdma.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX7 IOMUXC block emulation code + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/dma/imx_sdma.h" +#include "qemu/log.h" + +static void imx_sdma_reset(DeviceState *dev) +{ +IMXSDMAState *s = IMX_SDMA(dev); + +memset(s->regs, 0, sizeof(s->regs)); +} + +static uint64_t imx_sdma_read(void *opaque, hwaddr offset, + unsigned size) +{ +IMXSDMAState *s = opaque; +return s->regs[offset / sizeof(uint32_t)]; +} + +static void imx_sdma_write(void *opaque, hwaddr offset, +uint64_t value, unsigned size) +{ +IMXSDMAState *s = opaque; +s->regs[offset / sizeof(uint32_t)] = value; +} + +static const struct MemoryRegionOps imx_sdma_ops = { +.read = imx_sdma_read, +.write = imx_sdma_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.impl = { +/* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ +.min_access_size = 4, +.max_access_size = 4, +.unaligned = false, +}, +}; + +static void imx_sdma_init(Object *obj) +{ +SysBusDevice *sd = SYS_BUS_DEVICE(obj); +IMXSDMAState *s = IMX_SDMA(obj); + +memory_region_init_io(&s->iomem, + obj, + &imx_sdma_ops, + s, + TYPE_IMX_SDMA ".iomem", + sizeof(s->regs)); +sysbus_init_mmio(sd, &s->iomem); +} + +static const VMStateDescription vmstate_imx_sdma = { +.name = TYPE_IMX_SDMA, +.version_id = 1, +.minimum_version_id = 1, +.fields = (VMStateField[]) { +VMSTATE_UINT32_ARRAY(regs, IMXSDMAState, SDMA_NUM), +VMSTATE_END_OF_LIST() +}, +}; + +static void imx_sdma_class_init(ObjectClass *klass, void *data) +{ +DeviceClass *dc = DEVICE_CLASS(klass); + +dc->reset = imx_sdma_reset; +dc->vmsd = &vmstate_imx_sdma; +dc->desc = "i.MX IOMUXC Module"; +} + +static const TypeInfo imx_sdma_info = { +.name = TYPE_IMX_SDMA, +.parent= TYPE_SYS_BUS_DEVICE, +.instance_size = sizeof(IMXSDMAState), +.instance_init = imx_sdma_init, +.class_init= imx_sdma_class_init, +}; + +static void imx_sdma_register_type(void) +{ +type_register_static(&imx_sdma_info); +} +type_init(imx_sdma_register_type) diff --git a/include/hw/dma/imx_sdma.h b/include/hw/dma/imx_sdma.h new file mode 100644 index 00..13c5be7a00 --- /dev/null +++ b/include/hw/dma/imx_sdma.h @@ -0,0 +1,22 @@ +#ifndef IMX_SDMA_H +#define IMX_SDMA_H + +#include "hw/sysbus.h" + +enum IMXSDMARegisters { +SDMA_NUM = 0x300 / sizeof(uint32_t) + 1, +}; + +typedef struct IMXSDMAState { +/*< private >*/ +SysBusDevice parent_obj; + +/*< public >*/ +MemoryRegion iomem; +uint32_t regs[SDMA_NUM]; +} IMXSDMAState; + +#define TYPE_IMX_SDMA "imx-sdma" +#define IMX_SDMA(obj) OBJECT_CHECK(IMXSDMAState, (obj), TYPE_IMX_SDMA) + +#endif /* IMX_SDMA_H */ -- 2.13.5
[Qemu-devel] [PATCH v2 20/27] i.MX: Add code to emulate FlexCAN IP block
Add minimal code needed to allow upstream Linux guest to boot. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/misc/Makefile.objs | 1 + hw/misc/imx_flexcan.c | 99 +++ include/hw/misc/imx_flexcan.h | 22 ++ 3 files changed, 122 insertions(+) create mode 100644 hw/misc/imx_flexcan.c create mode 100644 include/hw/misc/imx_flexcan.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 492c535330..943b22af40 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -38,6 +38,7 @@ obj-$(CONFIG_IMX) += imx7_ccm.o obj-$(CONFIG_IMX) += imx2_wdt.o obj-$(CONFIG_IMX) += imx7_snvs.o obj-$(CONFIG_IMX) += imx7_iomuxc.o +obj-$(CONFIG_IMX) += imx_flexcan.o obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o obj-$(CONFIG_MAINSTONE) += mst_fpga.o diff --git a/hw/misc/imx_flexcan.c b/hw/misc/imx_flexcan.c new file mode 100644 index 00..dd4d3d6dc1 --- /dev/null +++ b/hw/misc/imx_flexcan.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX FlexCAN block emulation code + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/misc/imx_flexcan.h" +#include "qemu/log.h" + +static void imx_flexcan_reset(DeviceState *dev) +{ +IMXFlexCANState *s = IMX_FLEXCAN(dev); + +memset(s->regs, 0, sizeof(s->regs)); +} + +static uint64_t imx_flexcan_read(void *opaque, hwaddr offset, + unsigned size) +{ +IMXFlexCANState *s = opaque; +return s->regs[offset / sizeof(uint32_t)]; +} + +static void imx_flexcan_write(void *opaque, hwaddr offset, +uint64_t value, unsigned size) +{ +IMXFlexCANState *s = opaque; +s->regs[offset / sizeof(uint32_t)] = value; +} + +static const struct MemoryRegionOps imx_flexcan_ops = { +.read = imx_flexcan_read, +.write = imx_flexcan_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.impl = { +/* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ +.min_access_size = 4, +.max_access_size = 4, +.unaligned = false, +}, +}; + +static void imx_flexcan_init(Object *obj) +{ +SysBusDevice *sd = SYS_BUS_DEVICE(obj); +IMXFlexCANState *s = IMX_FLEXCAN(obj); + +memory_region_init_io(&s->iomem, + obj, + &imx_flexcan_ops, + s, + TYPE_IMX_FLEXCAN ".iomem", + sizeof(s->regs)); +sysbus_init_mmio(sd, &s->iomem); +} + +static const VMStateDescription vmstate_imx_flexcan = { +.name = TYPE_IMX_FLEXCAN, +.version_id = 1, +.minimum_version_id = 1, +.fields = (VMStateField[]) { +VMSTATE_UINT32_ARRAY(regs, IMXFlexCANState, FLEXCAN_NUM), +VMSTATE_END_OF_LIST() +}, +}; + +static void imx_flexcan_class_init(ObjectClass *klass, void *data) +{ +DeviceClass *dc = DEVICE_CLASS(klass); + +dc->reset = imx_flexcan_reset; +dc->vmsd = &vmstate_imx_flexcan; +dc->desc = "i.MX FlexCAN Module"; +} + +static const TypeInfo imx_flexcan_info = { +.name = TYPE_IMX_FLEXCAN, +.parent= TYPE_SYS_BUS_DEVICE, +.instance_size = sizeof(IMXFlexCANState), +.instance_init = imx_flexcan_init, +.class_init= imx_flexcan_class_init, +}; + +static void imx_flexcan_register_type(void) +{ +type_register_static(&imx_flexcan_info); +} +type_init(imx_flexcan_register_type) diff --git a/include/hw/misc/imx_flexcan.h b/include/hw/misc/imx_flexcan.h new file mode 100644 index 00..da9980cf86 --- /dev/null +++ b/include/hw/misc/imx_flexcan.h @@ -0,0 +1,22 @@ +#ifndef IMX_FLEXCAN_H +#define IMX_FLEXCAN_H + +#include "hw/sysbus.h" + +enum IMXFlexCANRegisters { +FLEXCAN_NUM = 0x9E0 / sizeof(uint32_t) + 1, +}; + +typedef struct IMXFlexCANState { +/*< private >*/ +SysBusDevice parent_obj; + +/*< public >*/ +MemoryRegion iomem; +uint32_t regs[FLEXCAN_NUM]; +} IMXFlexCANState; + +#define TYPE_IMX_FLEXCAN "imx-flexcan" +#define IMX_FLEXCAN(obj) OBJECT_CHECK(IMXFlexCANState, (obj), TYPE_IMX_FLEXCAN) + +#endif /* IMX_FLEXCAN_H */ -- 2.13.5
[Qemu-devel] [PATCH v2 15/27] i.MX: Add code to emulate i.MX7 SNVS IP-block
Add code to emulate SNVS IP-block. Currently only the bits needed to be able to emulate machine shutdown are implemented. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/misc/Makefile.objs | 1 + hw/misc/imx7_snvs.c | 83 + include/hw/misc/imx7_snvs.h | 35 +++ 3 files changed, 119 insertions(+) create mode 100644 hw/misc/imx7_snvs.c create mode 100644 include/hw/misc/imx7_snvs.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index c393a93456..16cee88e0f 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -36,6 +36,7 @@ obj-$(CONFIG_IMX) += imx6_ccm.o obj-$(CONFIG_IMX) += imx6_src.o obj-$(CONFIG_IMX) += imx7_ccm.o obj-$(CONFIG_IMX) += imx2_wdt.o +obj-$(CONFIG_IMX) += imx7_snvs.o obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o obj-$(CONFIG_MAINSTONE) += mst_fpga.o diff --git a/hw/misc/imx7_snvs.c b/hw/misc/imx7_snvs.c new file mode 100644 index 00..670b9f4639 --- /dev/null +++ b/hw/misc/imx7_snvs.c @@ -0,0 +1,83 @@ +/* + * IMX7 Secure Non-Volatile Storage + * + * Copyright (c) 2017, Impinj, Inc. + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * Bare minimum emulation code needed to support being able to shut + * down linux guest gracefully. + */ + +#include "qemu/osdep.h" +#include "hw/misc/imx7_snvs.h" +#include "qemu/log.h" +#include "sysemu/sysemu.h" + +static uint64_t imx7_snvs_read(void *opaque, hwaddr offset, unsigned size) +{ +return 0; +} + +static void imx7_snvs_write(void *opaque, hwaddr offset, +uint64_t v, unsigned size) +{ +const uint32_t value = v; +const uint32_t mask = SNVS_LPCR_TOP | SNVS_LPCR_DP_EN; + +if (offset == SNVS_LPCR && ((value & mask) == mask)) { +qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); +} +} + +static const struct MemoryRegionOps imx7_snvs_ops = { +.read = imx7_snvs_read, +.write = imx7_snvs_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.impl = { +/* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ +.min_access_size = 4, +.max_access_size = 4, +.unaligned = false, +}, +}; + +static void imx7_snvs_init(Object *obj) +{ +SysBusDevice *sd = SYS_BUS_DEVICE(obj); +IMX7SNVSState *s = IMX7_SNVS(obj); + +memory_region_init_io(&s->mmio, obj, &imx7_snvs_ops, s, + TYPE_IMX7_SNVS, 0x1000); + +sysbus_init_mmio(sd, &s->mmio); +} + +static void imx7_snvs_class_init(ObjectClass *klass, void *data) +{ +DeviceClass *dc = DEVICE_CLASS(klass); + +dc->desc = "i.MX7 Secure Non-Volatile Storage Module"; +} + +static const TypeInfo imx7_snvs_info = { +.name = TYPE_IMX7_SNVS, +.parent= TYPE_SYS_BUS_DEVICE, +.instance_size = sizeof(IMX7SNVSState), +.instance_init = imx7_snvs_init, +.class_init= imx7_snvs_class_init, +}; + +static void imx7_snvs_register_type(void) +{ +type_register_static(&imx7_snvs_info); +} +type_init(imx7_snvs_register_type) diff --git a/include/hw/misc/imx7_snvs.h b/include/hw/misc/imx7_snvs.h new file mode 100644 index 00..255f8f26f9 --- /dev/null +++ b/include/hw/misc/imx7_snvs.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX7 SNVS block emulation code + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef IMX7_SNVS_H +#define IMX7_SNVS_H + +#include "qemu/bitops.h" +#include "hw/sysbus.h" + + +enum IMX7SNVSRegisters { +SNVS_LPCR = 0x38, +SNVS_LPCR_TOP = BIT(6), +SNVS_LPCR_DP_EN = BIT(5) +}; + +#define TYPE_IMX7_SNVS "imx7.snvs" +#define IMX7_SNVS(obj) OBJECT_CHECK(IMX7SNVSState, (obj), TYPE_IMX7_SNVS) + +typedef struct IMX7SNVSState { +/* */ +SysBusDevice parent_obj; + +MemoryRegion mmio; +} IMX7SNVSState; + +#endif /* IMX7_SNVS_H */ -- 2.13.5
[Qemu-devel] [PATCH v2 17/27] i.MX: Add code to emulate i.MX7 IOMUXC IP block
Add minimal code needed to allow upstream Linux guest to boot. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/misc/Makefile.objs | 1 + hw/misc/imx7_iomuxc.c | 99 +++ include/hw/misc/imx7_iomuxc.h | 22 ++ 3 files changed, 122 insertions(+) create mode 100644 hw/misc/imx7_iomuxc.c create mode 100644 include/hw/misc/imx7_iomuxc.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 16cee88e0f..492c535330 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -37,6 +37,7 @@ obj-$(CONFIG_IMX) += imx6_src.o obj-$(CONFIG_IMX) += imx7_ccm.o obj-$(CONFIG_IMX) += imx2_wdt.o obj-$(CONFIG_IMX) += imx7_snvs.o +obj-$(CONFIG_IMX) += imx7_iomuxc.o obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o obj-$(CONFIG_MAINSTONE) += mst_fpga.o diff --git a/hw/misc/imx7_iomuxc.c b/hw/misc/imx7_iomuxc.c new file mode 100644 index 00..aa26a7485f --- /dev/null +++ b/hw/misc/imx7_iomuxc.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX7 IOMUXC block emulation code + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/misc/imx7_iomuxc.h" +#include "qemu/log.h" + +static void imx7_iomuxc_reset(DeviceState *dev) +{ +IMX7IOMUXCState *s = IMX7_IOMUXC(dev); + +memset(s->regs, 0, sizeof(s->regs)); +} + +static uint64_t imx7_iomuxc_read(void *opaque, hwaddr offset, + unsigned size) +{ +IMX7IOMUXCState *s = opaque; +return s->regs[offset / sizeof(uint32_t)]; +} + +static void imx7_iomuxc_write(void *opaque, hwaddr offset, +uint64_t value, unsigned size) +{ +IMX7IOMUXCState *s = opaque; +s->regs[offset / sizeof(uint32_t)] = value; +} + +static const struct MemoryRegionOps imx7_iomuxc_ops = { +.read = imx7_iomuxc_read, +.write = imx7_iomuxc_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.impl = { +/* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ +.min_access_size = 4, +.max_access_size = 4, +.unaligned = false, +}, +}; + +static void imx7_iomuxc_init(Object *obj) +{ +SysBusDevice *sd = SYS_BUS_DEVICE(obj); +IMX7IOMUXCState *s = IMX7_IOMUXC(obj); + +memory_region_init_io(&s->iomem, + obj, + &imx7_iomuxc_ops, + s, + TYPE_IMX7_IOMUXC ".iomem", + sizeof(s->regs)); +sysbus_init_mmio(sd, &s->iomem); +} + +static const VMStateDescription vmstate_imx7_iomuxc = { +.name = TYPE_IMX7_IOMUXC, +.version_id = 1, +.minimum_version_id = 1, +.fields = (VMStateField[]) { +VMSTATE_UINT32_ARRAY(regs, IMX7IOMUXCState, IOMUXC_NUM), +VMSTATE_END_OF_LIST() +}, +}; + +static void imx7_iomuxc_class_init(ObjectClass *klass, void *data) +{ +DeviceClass *dc = DEVICE_CLASS(klass); + +dc->reset = imx7_iomuxc_reset; +dc->vmsd = &vmstate_imx7_iomuxc; +dc->desc = "i.MX IOMUXC Module"; +} + +static const TypeInfo imx7_iomuxc_info = { +.name = TYPE_IMX7_IOMUXC, +.parent= TYPE_SYS_BUS_DEVICE, +.instance_size = sizeof(IMX7IOMUXCState), +.instance_init = imx7_iomuxc_init, +.class_init= imx7_iomuxc_class_init, +}; + +static void imx7_iomuxc_register_type(void) +{ +type_register_static(&imx7_iomuxc_info); +} +type_init(imx7_iomuxc_register_type) diff --git a/include/hw/misc/imx7_iomuxc.h b/include/hw/misc/imx7_iomuxc.h new file mode 100644 index 00..7041a1ff42 --- /dev/null +++ b/include/hw/misc/imx7_iomuxc.h @@ -0,0 +1,22 @@ +#ifndef IMX7_IOMUXC_H +#define IMX7_IOMUXC_H + +#include "hw/sysbus.h" + +enum IMX7IOMUXCRegisters { +IOMUXC_NUM = 0x740 / sizeof(uint32_t), +}; + +typedef struct IMX7IOMUXCState { +/*< private >*/ +SysBusDevice parent_obj; + +/*< public >*/ +MemoryRegion iomem; +uint32_t regs[IOMUXC_NUM]; +} IMX7IOMUXCState; + +#define TYPE_IMX7_IOMUXC "imx7-iomuxc" +#define IMX7_IOMUXC(obj) OBJECT_CHECK(IMX7IOMUXCState, (obj), TYPE_IMX7_IOMUXC) + +#endif /* IMX7_IOMUXC_H */ -- 2.13.5
[Qemu-devel] [PATCH v2 26/27] i.MX: Add i.MX7 SOC implementation.
The following interfaces are partially or fully emulated: * up to 2 Cortex A9 cores (SMP works with PSCI) * A7 MPCORE (identical to A15 MPCORE) * 4 GPTs modules * 7 GPIO controllers * 2 IOMUXC controllers * 1 CCM module * 1 SVNS module * 1 SRC module * 1 GPCv2 controller * 4 eCSPI controllers * 4 I2C controllers * 7 i.MX UART controllers * 2 FlexCAN controllers * 2 Ethernet controllers (FEC) * 3 SD controllers (USDHC) * 4 WDT modules * 1 SDMA module * 1 GPR module * 2 USBMISC modules * 2 ADC modules * 1 PCIe controller Tested to boot and work with upstream Linux (4.13+) guest. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- default-configs/arm-softmmu.mak | 1 + hw/arm/Makefile.objs| 2 + hw/arm/fsl-imx7.c | 596 include/hw/arm/fsl-imx7.h | 217 +++ 4 files changed, 816 insertions(+) create mode 100644 hw/arm/fsl-imx7.c create mode 100644 include/hw/arm/fsl-imx7.h diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 225ebbd90a..a2f318d6dd 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -118,6 +118,7 @@ CONFIG_ALLWINNER_A10=y CONFIG_FSL_IMX6=y CONFIG_FSL_IMX31=y CONFIG_FSL_IMX25=y +CONFIG_FSL_IMX7=y CONFIG_IMX_I2C=y diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index a2e56ecaae..33f6051ae3 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -19,3 +19,5 @@ obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o obj-$(CONFIG_MPS2) += mps2.o +obj-$(CONFIG_FSL_IMX7) += fsl-imx7.o + diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c new file mode 100644 index 00..f1a6a79179 --- /dev/null +++ b/hw/arm/fsl-imx7.c @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX7 SoC definitions + * + * Author: Andrey Smirnov + * + * Based on hw/arm/fsl-imx6.c + * + * 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. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "hw/arm/fsl-imx7.h" +#include "sysemu/sysemu.h" +#include "qemu/error-report.h" + +#define NAME_SIZE 20 + +static void fsl_imx7_init(Object *obj) +{ +BusState *sysbus = sysbus_get_default(); +FslIMX7State *s = FSL_IMX7(obj); +char name[NAME_SIZE]; +int i; + +if (smp_cpus > FSL_IMX7_NUM_CPUS) { +error_report("%s: Only %d CPUs are supported (%d requested)", + TYPE_FSL_IMX7, FSL_IMX7_NUM_CPUS, smp_cpus); +exit(1); +} + +for (i = 0; i < smp_cpus; i++) { +object_initialize(&s->cpu[i], sizeof(s->cpu[i]), + "cortex-a7-" TYPE_ARM_CPU); +snprintf(name, NAME_SIZE, "cpu%d", i); +object_property_add_child(obj, name, OBJECT(&s->cpu[i]), + &error_fatal); +} + +/* + * A7MPCORE + */ +object_initialize(&s->a7mpcore, sizeof(s->a7mpcore), TYPE_A15MPCORE_PRIV); +qdev_set_parent_bus(DEVICE(&s->a7mpcore), sysbus); +object_property_add_child(obj, "a7mpcore", + OBJECT(&s->a7mpcore), &error_fatal); + +/* + * GPIOs 1 to 7 + */ +for (i = 0; i < FSL_IMX7_NUM_GPIOS; i++) { +object_initialize(&s->gpio[i], sizeof(s->gpio[i]), + TYPE_IMX_GPIO); +qdev_set_parent_bus(DEVICE(&s->gpio[i]), sysbus); +snprintf(name, NAME_SIZE, "gpio%d", i); +object_property_add_child(obj, name, + OBJECT(&s->gpio[i]), &error_fatal); +} + +/* + * IOMUXC and IOMUXC_LPSR + */ +for (i = 0; i < FSL_IMX7_NUM_IOMUXCS; i++) { +object_initialize(&s->iomuxc[i], sizeof(s->iomuxc[i]), + TYPE_IMX7_IOMUXC); +qdev_set_parent_bus(DEVICE(&s->iomuxc[i]), sysbus); +snprintf(name, NAME_SIZE, "iomuxc%d", i); +object_property_add_child(obj, name, + OBJECT(&s->iomuxc[i]), &error_fatal); +}
[Qemu-devel] [PATCH v2 23/27] i.MX: Add code to emulate i.MX7 USBMISC IP block
Add minimal code needed to allow upstream Linux guest to boot. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/usb/Makefile.objs | 1 + hw/usb/imx-usbmisc.c | 99 include/hw/usb/imx-usbmisc.h | 22 ++ 3 files changed, 122 insertions(+) create mode 100644 hw/usb/imx-usbmisc.c create mode 100644 include/hw/usb/imx-usbmisc.h diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index 97f1c4561a..813359fadc 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -12,6 +12,7 @@ common-obj-$(CONFIG_USB_XHCI_NEC) += hcd-xhci-nec.o common-obj-$(CONFIG_USB_MUSB) += hcd-musb.o obj-$(CONFIG_TUSB6010) += tusb6010.o +obj-$(CONFIG_IMX) += imx-usbmisc.o # emulated usb devices common-obj-$(CONFIG_USB) += dev-hub.o diff --git a/hw/usb/imx-usbmisc.c b/hw/usb/imx-usbmisc.c new file mode 100644 index 00..d5e236a4be --- /dev/null +++ b/hw/usb/imx-usbmisc.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX7 IOMUXC block emulation code + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/usb/imx-usbmisc.h" +#include "qemu/log.h" + +static void imx_usbmisc_reset(DeviceState *dev) +{ +IMXUSBMiscState *s = IMX_USBMISC(dev); + +memset(s->regs, 0, sizeof(s->regs)); +} + +static uint64_t imx_usbmisc_read(void *opaque, hwaddr offset, + unsigned size) +{ +IMXUSBMiscState *s = opaque; +return s->regs[offset / sizeof(uint32_t)]; +} + +static void imx_usbmisc_write(void *opaque, hwaddr offset, +uint64_t value, unsigned size) +{ +IMXUSBMiscState *s = opaque; +s->regs[offset / sizeof(uint32_t)] = value; +} + +static const struct MemoryRegionOps imx_usbmisc_ops = { +.read = imx_usbmisc_read, +.write = imx_usbmisc_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.impl = { +/* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ +.min_access_size = 4, +.max_access_size = 4, +.unaligned = false, +}, +}; + +static void imx_usbmisc_init(Object *obj) +{ +SysBusDevice *sd = SYS_BUS_DEVICE(obj); +IMXUSBMiscState *s = IMX_USBMISC(obj); + +memory_region_init_io(&s->iomem, + obj, + &imx_usbmisc_ops, + s, + TYPE_IMX_USBMISC ".iomem", + sizeof(s->regs)); +sysbus_init_mmio(sd, &s->iomem); +} + +static const VMStateDescription vmstate_imx_usbmisc = { +.name = TYPE_IMX_USBMISC, +.version_id = 1, +.minimum_version_id = 1, +.fields = (VMStateField[]) { +VMSTATE_UINT32_ARRAY(regs, IMXUSBMiscState, USBMISC_NUM), +VMSTATE_END_OF_LIST() +}, +}; + +static void imx_usbmisc_class_init(ObjectClass *klass, void *data) +{ +DeviceClass *dc = DEVICE_CLASS(klass); + +dc->reset = imx_usbmisc_reset; +dc->vmsd = &vmstate_imx_usbmisc; +dc->desc = "i.MX IOMUXC Module"; +} + +static const TypeInfo imx_usbmisc_info = { +.name = TYPE_IMX_USBMISC, +.parent= TYPE_SYS_BUS_DEVICE, +.instance_size = sizeof(IMXUSBMiscState), +.instance_init = imx_usbmisc_init, +.class_init= imx_usbmisc_class_init, +}; + +static void imx_usbmisc_register_type(void) +{ +type_register_static(&imx_usbmisc_info); +} +type_init(imx_usbmisc_register_type) diff --git a/include/hw/usb/imx-usbmisc.h b/include/hw/usb/imx-usbmisc.h new file mode 100644 index 00..64b06f3d3c --- /dev/null +++ b/include/hw/usb/imx-usbmisc.h @@ -0,0 +1,22 @@ +#ifndef IMX_USBMISC_H +#define IMX_USBMISC_H + +#include "hw/sysbus.h" + +enum IMXUSBMiscRegisters { +USBMISC_NUM = 0x24 / sizeof(uint32_t) + 1, +}; + +typedef struct IMXUSBMiscState { +/*< private >*/ +SysBusDevice parent_obj; + +/*< public >*/ +MemoryRegion iomem; +uint32_t regs[USBMISC_NUM]; +} IMXUSBMiscState; + +#define TYPE_IMX_USBMISC "imx-usbmisc" +#define IMX_USBMISC(obj) OBJECT_CHECK(IMXUSBMiscState, (obj), TYPE_IMX_USBMISC) + +#endif /* IMX_USBMISC_H */ -- 2.13.5
[Qemu-devel] [PATCH v2 21/27] i.MX: Add implementation of i.MX7 GPR IP block
Add minimal code needed to allow upstream Linux guest to boot. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/misc/Makefile.objs | 1 + hw/misc/imx7_gpr.c | 119 + include/hw/misc/imx7_gpr.h | 28 +++ 3 files changed, 148 insertions(+) create mode 100644 hw/misc/imx7_gpr.c create mode 100644 include/hw/misc/imx7_gpr.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 943b22af40..c9944161bd 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -39,6 +39,7 @@ obj-$(CONFIG_IMX) += imx2_wdt.o obj-$(CONFIG_IMX) += imx7_snvs.o obj-$(CONFIG_IMX) += imx7_iomuxc.o obj-$(CONFIG_IMX) += imx_flexcan.o +obj-$(CONFIG_IMX) += imx7_gpr.o obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o obj-$(CONFIG_MAINSTONE) += mst_fpga.o diff --git a/hw/misc/imx7_gpr.c b/hw/misc/imx7_gpr.c new file mode 100644 index 00..9e8ccea9e8 --- /dev/null +++ b/hw/misc/imx7_gpr.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX7 GPR IP block emulation code + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * Bare minimum emulation code needed to support being able to shut + * down linux guest gracefully. + */ + +#include "qemu/osdep.h" +#include "hw/misc/imx7_gpr.h" +#include "qemu/log.h" +#include "sysemu/sysemu.h" + +enum IMX7GPRRegisters { +IOMUXC_GPR0 = 0x00, +IOMUXC_GPR1 = 0x04, +IOMUXC_GPR2 = 0x08, +IOMUXC_GPR3 = 0x0c, +IOMUXC_GPR4 = 0x10, +IOMUXC_GPR5 = 0x14, +IOMUXC_GPR6 = 0x18, +IOMUXC_GPR7 = 0x1c, +IOMUXC_GPR8 = 0x20, +IOMUXC_GPR9 = 0x24, +IOMUXC_GPR10 = 0x28, +IOMUXC_GPR11 = 0x2c, +IOMUXC_GPR12 = 0x30, +IOMUXC_GPR13 = 0x34, +IOMUXC_GPR14 = 0x38, +IOMUXC_GPR15 = 0x3c, +IOMUXC_GPR16 = 0x40, +IOMUXC_GPR17 = 0x44, +IOMUXC_GPR18 = 0x48, +IOMUXC_GPR19 = 0x4c, +IOMUXC_GPR20 = 0x50, +IOMUXC_GPR21 = 0x54, +IOMUXC_GPR22 = 0x58, +}; + +#define IMX7D_GPR1_IRQ_MASK BIT(12) +#define IMX7D_GPR1_ENET1_TX_CLK_SEL_MASKBIT(13) +#define IMX7D_GPR1_ENET2_TX_CLK_SEL_MASKBIT(14) +#define IMX7D_GPR1_ENET_TX_CLK_SEL_MASK (0x3 << 13) +#define IMX7D_GPR1_ENET1_CLK_DIR_MASK BIT(17) +#define IMX7D_GPR1_ENET2_CLK_DIR_MASK BIT(18) +#define IMX7D_GPR1_ENET_CLK_DIR_MASK(0x3 << 17) + +#define IMX7D_GPR5_CSI_MUX_CONTROL_MIPI BIT(4) +#define IMX7D_GPR12_PCIE_PHY_REFCLK_SEL BIT(5) +#define IMX7D_GPR22_PCIE_PHY_PLL_LOCKED BIT(31) + + +static uint64_t imx7_gpr_read(void *opaque, hwaddr offset, unsigned size) +{ +if (offset == IOMUXC_GPR22) { +return IMX7D_GPR22_PCIE_PHY_PLL_LOCKED; +} + +return 0; +} + +static void imx7_gpr_write(void *opaque, hwaddr offset, + uint64_t v, unsigned size) +{ +} + +static const struct MemoryRegionOps imx7_gpr_ops = { +.read = imx7_gpr_read, +.write = imx7_gpr_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.impl = { +/* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the + * real device but in practice there is no reason for a guest + * to access this device unaligned. + */ +.min_access_size = 4, +.max_access_size = 4, +.unaligned = false, +}, +}; + +static void imx7_gpr_init(Object *obj) +{ +SysBusDevice *sd = SYS_BUS_DEVICE(obj); +IMX7GPRState *s = IMX7_GPR(obj); + +memory_region_init_io(&s->mmio, obj, &imx7_gpr_ops, s, + TYPE_IMX7_GPR, 64 * 1024); +sysbus_init_mmio(sd, &s->mmio); +} + +static void imx7_gpr_class_init(ObjectClass *klass, void *data) +{ +DeviceClass *dc = DEVICE_CLASS(klass); + +dc->desc = "i.MX7 General Purpose Registers Module"; +} + +static const TypeInfo imx7_gpr_info = { +.name = TYPE_IMX7_GPR, +.parent= TYPE_SYS_BUS_DEVICE, +.instance_size = sizeof(IMX7GPRState), +.instance_init = imx7_gpr_init, +.class_init= imx7_gpr_class_init, +}; + +static void imx7_gpr_register_type(void) +{ +type_register_static(&imx7_gpr_info); +} +type_init(imx7_gpr_register_type) diff --git a/include/hw/misc/imx7_gpr.h b/include/hw/misc/imx7_gpr.h new file mode 100644 index 00..e19373d274 --- /dev/null +++ b/include/hw/misc/imx7_gpr.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX7 GPR IP block emulation code + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in th
[Qemu-devel] [PATCH v2 24/27] i.MX: Add code to emulate i.MX7 ADC IP block
Add minimal code needed to allow upstream Linux guest to boot. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- hw/misc/Makefile.objs | 1 + hw/misc/imx7_adc.c | 99 ++ include/hw/misc/imx7_adc.h | 22 +++ 3 files changed, 122 insertions(+) create mode 100644 hw/misc/imx7_adc.c create mode 100644 include/hw/misc/imx7_adc.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index c9944161bd..b578bd0cba 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -39,6 +39,7 @@ obj-$(CONFIG_IMX) += imx2_wdt.o obj-$(CONFIG_IMX) += imx7_snvs.o obj-$(CONFIG_IMX) += imx7_iomuxc.o obj-$(CONFIG_IMX) += imx_flexcan.o +obj-$(CONFIG_IMX) += imx7_adc.o obj-$(CONFIG_IMX) += imx7_gpr.o obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o diff --git a/hw/misc/imx7_adc.c b/hw/misc/imx7_adc.c new file mode 100644 index 00..7945e99075 --- /dev/null +++ b/hw/misc/imx7_adc.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX7 ADC block emulation code + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/misc/imx7_adc.h" +#include "qemu/log.h" + +static void imx7_adc_reset(DeviceState *dev) +{ +IMX7ADCState *s = IMX7_ADC(dev); + +memset(s->regs, 0, sizeof(s->regs)); +} + +static uint64_t imx7_adc_read(void *opaque, hwaddr offset, + unsigned size) +{ +IMX7ADCState *s = opaque; +return s->regs[offset / sizeof(uint32_t)]; +} + +static void imx7_adc_write(void *opaque, hwaddr offset, +uint64_t value, unsigned size) +{ +IMX7ADCState *s = opaque; +s->regs[offset / sizeof(uint32_t)] = value; +} + +static const struct MemoryRegionOps imx7_adc_ops = { +.read = imx7_adc_read, +.write = imx7_adc_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.impl = { +/* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ +.min_access_size = 4, +.max_access_size = 4, +.unaligned = false, +}, +}; + +static void imx7_adc_init(Object *obj) +{ +SysBusDevice *sd = SYS_BUS_DEVICE(obj); +IMX7ADCState *s = IMX7_ADC(obj); + +memory_region_init_io(&s->iomem, + obj, + &imx7_adc_ops, + s, + TYPE_IMX7_ADC ".iomem", + sizeof(s->regs)); +sysbus_init_mmio(sd, &s->iomem); +} + +static const VMStateDescription vmstate_imx7_adc = { +.name = TYPE_IMX7_ADC, +.version_id = 1, +.minimum_version_id = 1, +.fields = (VMStateField[]) { +VMSTATE_UINT32_ARRAY(regs, IMX7ADCState, ADC_NUM), +VMSTATE_END_OF_LIST() +}, +}; + +static void imx7_adc_class_init(ObjectClass *klass, void *data) +{ +DeviceClass *dc = DEVICE_CLASS(klass); + +dc->reset = imx7_adc_reset; +dc->vmsd = &vmstate_imx7_adc; +dc->desc = "i.MX ADC Module"; +} + +static const TypeInfo imx7_adc_info = { +.name = TYPE_IMX7_ADC, +.parent= TYPE_SYS_BUS_DEVICE, +.instance_size = sizeof(IMX7ADCState), +.instance_init = imx7_adc_init, +.class_init= imx7_adc_class_init, +}; + +static void imx7_adc_register_type(void) +{ +type_register_static(&imx7_adc_info); +} +type_init(imx7_adc_register_type) diff --git a/include/hw/misc/imx7_adc.h b/include/hw/misc/imx7_adc.h new file mode 100644 index 00..4a61c52caf --- /dev/null +++ b/include/hw/misc/imx7_adc.h @@ -0,0 +1,22 @@ +#ifndef IMX7_ADC_H +#define IMX7_ADC_H + +#include "hw/sysbus.h" + +enum IMX7ADCRegisters { +ADC_NUM = 0x130 / sizeof(uint32_t) + 1, +}; + +typedef struct IMX7ADCState { +/*< private >*/ +SysBusDevice parent_obj; + +/*< public >*/ +MemoryRegion iomem; +uint32_t regs[ADC_NUM]; +} IMX7ADCState; + +#define TYPE_IMX7_ADC "imx7-adc" +#define IMX7_ADC(obj) OBJECT_CHECK(IMX7ADCState, (obj), TYPE_IMX7_ADC) + +#endif /* IMX7_ADC_H */ -- 2.13.5
[Qemu-devel] [PATCH v2 22/27] pci: Add support for Designware IP block
Add code needed to get a functional PCI subsytem when using in conjunction with upstream Linux guest (4.13+). Tested to work against "e1000e" (network adapter, using MSI interrupts) as well as "usb-ehci" (USB controller, using legacy PCI interrupts). Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Signed-off-by: Andrey Smirnov --- default-configs/arm-softmmu.mak | 2 + hw/pci-host/Makefile.objs| 2 + hw/pci-host/designware.c | 614 +++ include/hw/pci-host/designware.h | 92 ++ include/hw/pci/pci_ids.h | 2 + 5 files changed, 712 insertions(+) create mode 100644 hw/pci-host/designware.c create mode 100644 include/hw/pci-host/designware.h diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index bbdd3c1d8b..225ebbd90a 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -129,3 +129,5 @@ CONFIG_ACPI=y CONFIG_SMBIOS=y CONFIG_ASPEED_SOC=y CONFIG_GPIO_KEY=y + +CONFIG_PCI_DESIGNWARE=y diff --git a/hw/pci-host/Makefile.objs b/hw/pci-host/Makefile.objs index 9c7909cf44..0e2c0a123b 100644 --- a/hw/pci-host/Makefile.objs +++ b/hw/pci-host/Makefile.objs @@ -17,3 +17,5 @@ common-obj-$(CONFIG_PCI_PIIX) += piix.o common-obj-$(CONFIG_PCI_Q35) += q35.o common-obj-$(CONFIG_PCI_GENERIC) += gpex.o common-obj-$(CONFIG_PCI_XILINX) += xilinx-pcie.o + +common-obj-$(CONFIG_PCI_DESIGNWARE) += designware.o diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c new file mode 100644 index 00..7ae4126d96 --- /dev/null +++ b/hw/pci-host/designware.c @@ -0,0 +1,614 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * Designware PCIe IP block emulation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/pci/msi.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_host.h" +#include "hw/pci/pcie_port.h" +#include "hw/pci-host/designware.h" + +#define PCIE_PORT_LINK_CONTROL 0x710 + +#define PCIE_PHY_DEBUG_R1 0x72C +#define PCIE_PHY_DEBUG_R1_XMLH_LINK_UP BIT(4) + +#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C + +#define PCIE_MSI_ADDR_LO0x820 +#define PCIE_MSI_ADDR_HI0x824 +#define PCIE_MSI_INTR0_ENABLE 0x828 +#define PCIE_MSI_INTR0_MASK 0x82C +#define PCIE_MSI_INTR0_STATUS 0x830 + +#define PCIE_ATU_VIEWPORT 0x900 +#define PCIE_ATU_REGION_INBOUND (0x1 << 31) +#define PCIE_ATU_REGION_OUTBOUND(0x0 << 31) +#define PCIE_ATU_REGION_INDEX2 (0x2 << 0) +#define PCIE_ATU_REGION_INDEX1 (0x1 << 0) +#define PCIE_ATU_REGION_INDEX0 (0x0 << 0) +#define PCIE_ATU_CR10x904 +#define PCIE_ATU_TYPE_MEM (0x0 << 0) +#define PCIE_ATU_TYPE_IO(0x2 << 0) +#define PCIE_ATU_TYPE_CFG0 (0x4 << 0) +#define PCIE_ATU_TYPE_CFG1 (0x5 << 0) +#define PCIE_ATU_CR20x908 +#define PCIE_ATU_ENABLE (0x1 << 31) +#define PCIE_ATU_BAR_MODE_ENABLE(0x1 << 30) +#define PCIE_ATU_LOWER_BASE 0x90C +#define PCIE_ATU_UPPER_BASE 0x910 +#define PCIE_ATU_LIMIT 0x914 +#define PCIE_ATU_LOWER_TARGET 0x918 +#define PCIE_ATU_BUS(x) (((x) >> 24) & 0xff) +#define PCIE_ATU_DEVFN(x) (((x) >> 16) & 0xff) +#define PCIE_ATU_UPPER_TARGET 0x91C + +static DesignwarePCIEHost * +designware_pcie_root_to_host(DesignwarePCIERoot *root) +{ +BusState *bus = qdev_get_parent_bus(DEVICE(root)); +return DESIGNWARE_PCIE_HOST(bus->parent); +} + +static void designware_pcie_root_msi_write(void *opaque, hwaddr addr, + uint64_t val, unsigned len) +{ +DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(opaque); +DesignwarePCIEHost *host = designware_pcie_root_to_host(root); + +root->msi.intr[0].status |= (1 << val) & root->msi.intr[0].enable; + +if (root->msi.intr[0].status
Re: [Qemu-devel] [PATCH v3 30/30] Implement support for i.MX7 Sabre board
On Tue, Nov 21, 2017 at 10:22 AM, Peter Maydell wrote: > On 6 November 2017 at 15:48, Andrey Smirnov wrote: >> Implement code needed to set up emulation of MCIMX7SABRE board from >> NXP. For more info about the HW see: >> >> https://www.nxp.com/support/developer-resources/hardware-development-tools/sabre-development-system/sabre-board-for-smart-devices-based-on-the-i.mx-7dual-applications-processors:MCIMX7SABRE > > You could put this URL in a comment in the code as well. > >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc: Philippe Mathieu-Daudé >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> --- >> hw/arm/Makefile.objs | 2 +- >> hw/arm/mcimx7d-sabre.c | 101 >> + >> 2 files changed, 102 insertions(+), 1 deletion(-) >> create mode 100644 hw/arm/mcimx7d-sabre.c >> >> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs >> index f379ddc74b..eb6f6c5997 100644 >> --- a/hw/arm/Makefile.objs >> +++ b/hw/arm/Makefile.objs >> @@ -19,5 +19,5 @@ obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o >> obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o >> obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o >> obj-$(CONFIG_MPS2) += mps2.o >> -obj-$(CONFIG_FSL_IMX7) += fsl-imx7.o >> +obj-$(CONFIG_FSL_IMX7) += fsl-imx7.o mcimx7d-sabre.o >> >> diff --git a/hw/arm/mcimx7d-sabre.c b/hw/arm/mcimx7d-sabre.c >> new file mode 100644 >> index 00..7ca8e668e8 >> --- /dev/null >> +++ b/hw/arm/mcimx7d-sabre.c >> @@ -0,0 +1,101 @@ >> +/* >> + * Copyright (c) 2017, Impinj, Inc. >> + * >> + * MCIMX7D_SABRE Board System emulation. >> + * >> + * Author: Andrey Smirnov >> + * >> + * This code is licensed under the GPL, version 2 or later. >> + * See the file `COPYING' in the top level directory. >> + * >> + * It (partially) emulates a mcimx7d_sabre board, with a Freescale >> + * i.MX7 SoC >> + */ >> + >> +#include "qemu/osdep.h" >> +#include "qapi/error.h" >> +#include "qemu-common.h" >> +#include "hw/arm/fsl-imx7.h" >> +#include "hw/boards.h" >> +#include "sysemu/sysemu.h" >> +#include "sysemu/device_tree.h" >> +#include "qemu/error-report.h" >> +#include "sysemu/qtest.h" >> +#include "net/net.h" >> + >> +typedef struct { >> +FslIMX7State soc; >> +MemoryRegion ram; >> +} MCIMX7Sabre; >> + >> +static void mcimx7d_add_psci_node(const struct arm_boot_info *boot_info, >> + void *fdt) >> +{ >> +const char comp[] = "arm,psci-0.2\0arm,psci"; >> + >> +qemu_fdt_add_subnode(fdt, "/psci"); >> +qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp)); >> +qemu_fdt_setprop_string(fdt, "/psci", "method", "smc"); >> +} > > I'm still unconvinced by this (none of the other i.mx boards we have > have anything like it). None of the other boards are both SMP capable and support SMP in upstream Linux only through PSCI (as it the case for i.MX7), so comparing against the precedent is not very helpful. > How does the real hardware boot SMP ? > Real hardware executes a bootloader which is expected to implement PSCI and do the DTB fixup as I implemented above. Thanks, Andrey Smirnov
Re: [Qemu-devel] [PATCH v3 00/30] Initial i.MX7 support
On Tue, Nov 21, 2017 at 10:34 AM, Peter Maydell wrote: > On 6 November 2017 at 15:47, Andrey Smirnov wrote: >> Hi everyone, >> - Added proper USB emulation code, so now it should be possible to >> emulated guest's USB bus > > The patchset is huge as it is, if you add more stuff to it > it makes it even more likely to sink to the bottom of my > to-review queue... > USB peripheral emulation had to be a part of a patch-set, either in dummy or a full featured form, in order to be able to boot vanilla Linux kernel because you insisted that I don't use "ignore_memory_transaction_failures". The reason why the dummy emulation version of it it was not a part of v2 was because I did my test with a bad kernel config where USB was disabled, didn't realize USB was essential and did not write code to support it. Now, once I realized it, I wrote a dummy version, and then later, while waiting for v2 to be reviewed, worked on proper USB emulation the code. Said code turned out to be comparatively trivial to the first dummy implementation, so instead of going through the exercise of submitting dummy first and then proper version later I squashed both and the result in v3. >> Peter, I didn't hear anything from you about the code of >> mcimx7d_add_psci_node(), as discussed here: >> >> https://www.mail-archive.com/qemu-devel@nongnu.org/msg486874.html >> >> so I kept the original code intact. As I mentioned before, my goal was >> to be able to boot into vanilla Linux kerenel and have working SMP >> without needing to use a PSCI implementing bootloader. If that is >> something that new board code shouldn't do, please let me know. > > Broadly, board code should work the same way the real hardware > does, unless there's a clear reason why not. Yes, this all makes sense. As far as I understand convenience being able to boot Linux directly in QEMU has long been the "clear reason why not". Now that certain SoC specific versions of Linux are not as self-sufficient and can't support SMP without external help, emulating PSCI and doing appropriate DTB fixups for that is just an adaptaion of the old convenience mechanism to new times and circumstances, IMHO. > "virt" is special because it writes its own dtb entirely. > > Maybe PSCI does need to be a different special case, since we're > emulating part of a bootloader here. OK, I'll ignore the "maybe" part and proceed as if we are in agreement on PSCI for v4. > But if so I think that code belongs more in hw/arm/boot.c, so that we > automatically fix up the > dtb to say "we have psci" if we are (a) booting a kernel directly > and (b) the CPU has the psci-conduit property set to enable QEMU's > PSCI implementation. > OK, sure, makes sense. I'll change the patch to use shared infrastructure for that. > (Also the code in virt.c for adding a PSCI node is considerably > fuller-featured than yours is.) > Okay... My code is targeting both fixed PSCI conduit (smc) and PSCI implementation (0.2/1.0), implementing support for anything but that in my board specific code would've been, IMHO, silly. OK, I'll interpret that comment not as a slight, but as a request to use virt.c's implementation for shared infrastructure. >> Thanks, >> Andrey Smirnov >> >> [v2] https://lists.gnu.org/archive/html/qemu-devel/2017-10/msg05516.html >> [v1] https://lists.gnu.org/archive/html/qemu-devel/2017-09/msg04770.html >> >> >> Andrey Smirnov (30): >> imx_fec: Do not link to netdev >> imx_fec: Refactor imx_eth_enable_rx() >> imx_fec: Change queue flushing heuristics >> imx_fec: Use ENET_FTRL to determine truncation length >> imx_fec: Use MIN instead of explicit ternary operator >> imx_fec: Emulate SHIFT16 in ENETx_RACC >> imx_fec: Add support for multiple Tx DMA rings >> imx_fec: Use correct length for packet size >> imx_fec: Fix a typo in imx_enet_receive() >> imx_fec: Reserve full 4K page for the register file >> sdhci: Add i.MX specific subtype of SDHCI >> sdhci: Implement write method of ACMD12ERRSTS register > > Everything above here is pretty nearly ready to go in; > if you send that as a patchseries then it should be easy > to review and queue ready for 2.12 (which will open up > for new commits in mid-december). > I'm not quite sure where you stand on "imx_fec: Use ENET_FTRL to determine truncation length", but sure, sounds good, I'll prepare the rest of them as a separate patch set and submit it, as soon as I get a chance. >> i.MX: Add code to emulate i.MX7 CCM, PMU and ANALOG IP blocks >> i.MX: Add code to emulate i.MX2 watchdog IP block
Re: [Qemu-devel] [PATCH v3 04/30] imx_fec: Use ENET_FTRL to determine truncation length
On Tue, Nov 21, 2017 at 9:31 AM, Peter Maydell wrote: > On 6 November 2017 at 15:47, Andrey Smirnov wrote: >> Frame truncation length, TRUNC_FL, is determined by the contents of >> ENET_FTRL register, so convert the code to use it instead of a >> hardcoded constant. >> >> To avoid the case where TRUNC_FL is greater that ENET_MAX_FRAME_SIZE, >> increase the value of the latter to its theoretical maximum of 16K. >> >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc: Philippe Mathieu-Daudé >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> --- >> hw/net/imx_fec.c | 4 ++-- >> include/hw/net/imx_fec.h | 3 ++- >> 2 files changed, 4 insertions(+), 3 deletions(-) >> >> diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c >> index eb034ffd0c..dda0816fb3 100644 >> --- a/hw/net/imx_fec.c >> +++ b/hw/net/imx_fec.c >> @@ -1052,8 +1052,8 @@ static ssize_t imx_enet_receive(NetClientState *nc, >> const uint8_t *buf, >> crc_ptr = (uint8_t *) &crc; >> >> /* Huge frames are truncted. */ >> -if (size > ENET_MAX_FRAME_SIZE) { >> -size = ENET_MAX_FRAME_SIZE; >> +if (size > s->regs[ENET_FTRL]) { >> +size = s->regs[ENET_FTRL]; >> flags |= ENET_BD_TR | ENET_BD_LG; >> } >> >> diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h >> index 4bc8f03ec2..0fcc4f0c71 100644 >> --- a/include/hw/net/imx_fec.h >> +++ b/include/hw/net/imx_fec.h >> @@ -86,7 +86,6 @@ >> #define ENET_TCCR3 393 >> #define ENET_MAX 400 >> >> -#define ENET_MAX_FRAME_SIZE2032 >> >> /* EIR and EIMR */ >> #define ENET_INT_HB(1 << 31) >> @@ -155,6 +154,8 @@ >> #define ENET_RCR_NLC (1 << 30) >> #define ENET_RCR_GRS (1 << 31) >> >> +#define ENET_MAX_FRAME_SIZE(1 << ENET_RCR_MAX_FL_LENGTH) > > This means we now have functions with 16K local array > variables on the stack, which seems like a bad idea. > Can't say I see a big difference between having a 2K vs 16K buffer on the stack, but regardless, I am not quite clear if you are not too hot about this patch and want me to drop it (I am fine with it) or do you want me to modify it to have the emulation layer allocate said 16K buffer on the heap instead of a stack? Thanks, Andrey Smirnov
Re: [Qemu-devel] [PATCH v3 03/30] imx_fec: Change queue flushing heuristics
On Tue, Nov 21, 2017 at 9:27 AM, Peter Maydell wrote: > On 6 November 2017 at 15:47, Andrey Smirnov wrote: >> In current implementation, packet queue flushing logic seem to suffer >> from a deadlock like scenario if a packet is received by the interface >> before before Rx ring is initialized by Guest's driver. Consider the >> following sequence of events: >> >> 1. A QEMU instance is started against a TAP device on Linux >>host, running Linux guest, e. g., something to the effect >>of: >> >>qemu-system-arm \ >> -net nic,model=imx.fec,netdev=lan0 \ >> netdev tap,id=lan0,ifname=tap0,script=no,downscript=no \ >> ... rest of the arguments ... >> >> 2. Once QEMU starts, but before guest reaches the point where >>FEC deriver is done initializing the HW, Guest, via TAP >>interface, receives a number of multicast MDNS packets from >>Host (not necessarily true for every OS, but it happens at >>least on Fedora 25) >> >> 3. Recieving a packet in such a state results in >>imx_eth_can_receive() returning '0', which in turn causes >>tap_send() to disable corresponding event (tap.c:203) >> >> 4. Once Guest's driver reaches the point where it is ready to >>recieve packets it prepares Rx ring descriptors and writes >>ENET_RDAR_RDAR to ENET_RDAR register to indicate to HW that >>more descriptors are ready. And at this points emulation >>layer does this: >> >> s->regs[index] = ENET_RDAR_RDAR; >> imx_eth_enable_rx(s); >> >>which, combined with: >> >> if (!s->regs[ENET_RDAR]) { >> qemu_flush_queued_packets(qemu_get_queue(s->nic)); >> } >> >>results in Rx queue never being flushed and corresponding >>I/O event beign disabled. >> >> To prevent the problem, change the code to always flush packet queue >> when ENET_RDAR transitions 0 -> ENET_RDAR_RDAR. >> >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc: Philippe Mathieu-Daudé >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h >> index 62ad473b05..4bc8f03ec2 100644 >> --- a/include/hw/net/imx_fec.h >> +++ b/include/hw/net/imx_fec.h >> @@ -252,6 +252,7 @@ typedef struct IMXFECState { >> uint32_t phy_int_mask; >> >> bool is_fec; >> +bool needs_flush; >> } IMXFECState; > > This field isn't needed any more in this version of the patch, I think? > Yeah, my bad, forgot to remove this part. Will do in v4. Thanks, Andrey Smirnov
Re: [Qemu-devel] [PATCH v3 07/30] imx_fec: Add support for multiple Tx DMA rings
On Tue, Nov 21, 2017 at 9:44 AM, Peter Maydell wrote: > On 6 November 2017 at 15:47, Andrey Smirnov wrote: >> More recent version of the IP block support more than one Tx DMA ring, >> so add the code implementing that feature. >> >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc: Philippe Mathieu-Daudé >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov > >> static const VMStateDescription vmstate_imx_eth = { >> .name = TYPE_IMX_FEC, >> -.version_id = 2, >> -.minimum_version_id = 2, >> +.version_id = 3, >> +.minimum_version_id = 3, >> .fields = (VMStateField[]) { >> VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX), >> VMSTATE_UINT32(rx_descriptor, IMXFECState), >> -VMSTATE_UINT32(tx_descriptor, IMXFECState), >> - >> +VMSTATE_UINT32_ARRAY(tx_descriptor, IMXFECState, ENET_TX_RING_NUM), >> +VMSTATE_UINT32(tx_ring_num, IMXFECState), >> VMSTATE_UINT32(phy_status, IMXFECState), >> VMSTATE_UINT32(phy_control, IMXFECState), >> VMSTATE_UINT32(phy_advertise, IMXFECState), > > tx_ring_num is constant for any particular instantiation of the device, > so you don't need to put it in the vmstate. > > It's pretty trivial to make this vmstate compatible with the old > ones for the existing single-tx-descriptor devices, so we might as well: > > /* Versions of this device with more than one TX descriptor > * save the 2nd and 3rd descriptors in a subsection, to maintain > * migration compatibility with previous versions of the device > * that only supported a single descriptor. > */ > static bool txdescs_needed(void *opaque) { > IMXFECState *s = opaque; > > return s->tx_ring_num > 1; > } > > static const VMStateDescription vmstate_imx_eth_txdescs = { > .name = "imx.fec/txdescs", > .version_id = 1, > .minimum_version_id = 1, > .needed = txdescs_needed, > .fields = (VMStateField[]) { > VMSTATE_UINT32(tx_descriptor[1], IMXFECState), > VMSTATE_UINT32(tx_descriptor[2], IMXFECState), > VMSTATE_END_OF_LIST() > } > }; > > and then add this to the vmx_state_eth at the end: > .subsections = (const VMStateDescription*[]) { > &vmstate_imx_eth_txdescs, > NULL > } > > Then you don't need to bump version_id/minimum_version_id on the > vmstate_imx_eth struct. > Cool, sounds good. Will add that to the patch in v4. >> @@ -791,6 +821,7 @@ static void imx_eth_write(void *opaque, hwaddr offset, >> uint64_t value, >> unsigned size) >> { >> IMXFECState *s = IMX_FEC(opaque); >> +const bool single_tx_ring = s->tx_ring_num != 3; > > This looks odd -- I would have expected "single_tx_ring = > s->tx_ring_num == 1" ... AFAIK the HW that's out there will have either 3 or 1 Tx ring, so that's why I wrote it this way. I'll change the logic to the way your suggest to avoid surprising the reader. Thanks, Andrey Smirnov
Re: [Qemu-devel] [PATCH v3 10/30] imx_fec: Reserve full 4K page for the register file
On Tue, Nov 21, 2017 at 9:48 AM, Peter Maydell wrote: > On 6 November 2017 at 15:47, Andrey Smirnov wrote: >> Some i.MX SoCs (e.g. i.MX7) have FEC registers going as far as offset >> 0x614, so to avoid getting aborts when accessing those on QEMU, extend >> the register file to cover 4KB of address space instead of just 1K. >> >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc: Philippe Mathieu-Daudé >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> --- >> hw/net/imx_fec.c | 2 +- >> 1 file changed, 1 insertion(+), 1 deletion(-) >> >> diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c >> index 48d012cad6..e236bc933c 100644 >> --- a/hw/net/imx_fec.c >> +++ b/hw/net/imx_fec.c >> @@ -1252,7 +1252,7 @@ static void imx_eth_realize(DeviceState *dev, Error >> **errp) >> SysBusDevice *sbd = SYS_BUS_DEVICE(dev); >> >> memory_region_init_io(&s->iomem, OBJECT(dev), &imx_eth_ops, s, >> - TYPE_IMX_FEC, 0x400); >> + TYPE_IMX_FEC, 0x1000); >> sysbus_init_mmio(sbd, &s->iomem); >> sysbus_init_irq(sbd, &s->irq[0]); >> sysbus_init_irq(sbd, &s->irq[1]); >> -- > > I notice that we have an unused #define FSL_IMX25_FEC_SIZE 0x4000 in > fsl-imx25.h, and the Linux device trees for the imx25 define the size > of the FEC register block as 0x4000. Should this be 0x4000 ? > I think the size reserved for that register file differs between differen SoC. E.g. it's 16K on i.MX25, as you pointed out, but 64K on i.MX7. It's all the same to me as long as it's greater than 0x1000. I'll change the code to use FSL_IMX25_FEC_SIZE since it gets rid of a magic number. Thanks, Andrey Smirnov
Re: [Qemu-devel] [PATCH v3 11/30] sdhci: Add i.MX specific subtype of SDHCI
On Tue, Nov 21, 2017 at 10:02 AM, Peter Maydell wrote: > On 6 November 2017 at 15:47, Andrey Smirnov wrote: >> IP block found on several generations of i.MX family does not use >> vanilla SDHCI implementation and it comes with a number of quirks. >> >> Introduce i.MX SDHCI subtype of SDHCI block to add code necessary to >> support unmodified Linux guest driver. >> >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc: Philippe Mathieu-Daudé >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov > > Hi. Mostly this looks ok; some comments below. > >> --- >> hw/sd/sdhci-internal.h | 15 ++ >> hw/sd/sdhci.c | 127 >> - >> include/hw/sd/sdhci.h | 8 >> 3 files changed, 148 insertions(+), 2 deletions(-) >> >> diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h >> index 161177cf39..2a1b4b06ee 100644 >> --- a/hw/sd/sdhci-internal.h >> +++ b/hw/sd/sdhci-internal.h >> @@ -91,6 +91,8 @@ >> #define SDHC_CTRL_ADMA2_32 0x10 >> #define SDHC_CTRL_ADMA2_64 0x18 >> #define SDHC_DMA_TYPE(x) ((x) & SDHC_CTRL_DMA_CHECK_MASK) >> +#define SDHC_CTRL_4BITBUS 0x02 >> +#define SDHC_CTRL_8BITBUS 0x20 >> >> /* R/W Power Control Register 0x0 */ >> #define SDHC_PWRCON0x29 >> @@ -229,4 +231,17 @@ enum { >> >> extern const VMStateDescription sdhci_vmstate; >> >> + >> +#define ESDHC_MIX_CTRL 0x48 >> +#define ESDHC_VENDOR_SPEC 0xc0 >> +#define ESDHC_DLL_CTRL 0x60 >> + >> +#define ESDHC_TUNING_CTRL 0xcc >> +#define ESDHC_TUNE_CTRL_STATUS 0x68 >> +#define ESDHC_WTMK_LVL 0x44 >> + >> +#define ESDHC_CTRL_4BITBUS (0x1 << 1) >> +#define ESDHC_CTRL_8BITBUS (0x2 << 1) >> + >> + >> #endif >> diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c >> index 6d6a791ee9..f561cc44e3 100644 >> --- a/hw/sd/sdhci.c >> +++ b/hw/sd/sdhci.c >> @@ -265,7 +265,8 @@ static void sdhci_send_command(SDHCIState *s) >> } >> } >> >> -if ((s->norintstsen & SDHC_NISEN_TRSCMP) && >> +if (!(s->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) && >> +(s->norintstsen & SDHC_NISEN_TRSCMP) && >> (s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY) { >> s->norintsts |= SDHC_NIS_TRSCMP; >> } >> @@ -1191,6 +1192,8 @@ static void sdhci_initfn(SDHCIState *s) >> >> s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, >> sdhci_raise_insertion_irq, s); >> s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, >> sdhci_data_transfer, s); >> + >> +s->io_ops = &sdhci_mmio_ops; >> } >> >> static void sdhci_uninitfn(SDHCIState *s) >> @@ -1347,7 +1350,7 @@ static void sdhci_sysbus_realize(DeviceState *dev, >> Error ** errp) >> s->buf_maxsz = sdhci_get_fifolen(s); >> s->fifo_buffer = g_malloc0(s->buf_maxsz); >> sysbus_init_irq(sbd, &s->irq); >> -memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci", >> +memory_region_init_io(&s->iomem, OBJECT(s), s->io_ops, s, "sdhci", >> SDHC_REGISTERS_MAP_SIZE); >> sysbus_init_mmio(sbd, &s->iomem); >> } >> @@ -1386,11 +1389,131 @@ static const TypeInfo sdhci_bus_info = { >> .class_init = sdhci_bus_class_init, >> }; >> >> +static uint64_t usdhc_read(void *opaque, hwaddr offset, unsigned size) >> +{ >> +SDHCIState *s = SYSBUS_SDHCI(opaque); >> +uint32_t ret; >> +uint16_t hostctl; >> + >> +switch (offset) { >> +default: >> +return sdhci_read(opaque, offset, size); >> + >> +case SDHC_HOSTCTL: >> +hostctl = SDHC_DMA_TYPE(s->hostctl) << 5; >> + >> +if (s->hostctl & SDHC_CTRL_8BITBUS) { >> +hostctl |= ESDHC_CTRL_8BITBUS; >> +} >> + >> +if (s->hostctl & SDHC_CTRL_4BITBUS) { >> +hostctl |= ESDHC_CTRL_4BITBUS; >> +} >> + >> +ret = hostctl | (s->blkgap << 16) | >> +(s->wakcon << 24); >
Re: [Qemu-devel] [PATCH v3 12/30] sdhci: Implement write method of ACMD12ERRSTS register
On Tue, Nov 21, 2017 at 10:04 AM, Peter Maydell wrote: > On 6 November 2017 at 15:47, Andrey Smirnov wrote: >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc: Philippe Mathieu-Daudé >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> --- >> hw/sd/sdhci.c | 3 +++ >> 1 file changed, 3 insertions(+) >> >> diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c >> index f561cc44e3..53e5e011a7 100644 >> --- a/hw/sd/sdhci.c >> +++ b/hw/sd/sdhci.c >> @@ -1139,6 +1139,9 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, >> unsigned size) >> s->admasysaddr = (s->admasysaddr & (0xULL | >> ((uint64_t)mask << 32))) | ((uint64_t)value << 32); >> break; >> +case SDHC_ACMD12ERRSTS: >> +MASKED_WRITE(s->acmd12errsts, mask, value); >> +break; >> case SDHC_FEAER: >> s->acmd12errsts |= value; >> s->errintsts |= (value >> 16) & s->errintstsen; >> -- >> 2.13.6 > > Is this part of the stock SDHCI spec that we just forgot to implement? Yes it is. I don't know if missing that code critical for anything, but since the rest of the plumbing is there I thought that we may as well implement it. Thanks, Andrey Smirnov
Re: [Qemu-devel] [PATCH v3 13/30] i.MX: Add code to emulate i.MX7 CCM, PMU and ANALOG IP blocks
On Tue, Nov 21, 2017 at 10:08 AM, Peter Maydell wrote: > On 6 November 2017 at 15:47, Andrey Smirnov wrote: >> Add minimal code needed to allow upstream Linux guest to boot. >> >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc: Philippe Mathieu-Daudé >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> --- >> hw/misc/Makefile.objs | 1 + >> hw/misc/imx7_ccm.c | 233 >> + >> include/hw/misc/imx7_ccm.h | 130 + >> 3 files changed, 364 insertions(+) >> create mode 100644 hw/misc/imx7_ccm.c >> create mode 100644 include/hw/misc/imx7_ccm.h >> >> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs >> index 29fb922cef..ac1be05a03 100644 >> --- a/hw/misc/Makefile.objs >> +++ b/hw/misc/Makefile.objs >> @@ -34,6 +34,7 @@ obj-$(CONFIG_IMX) += imx31_ccm.o >> obj-$(CONFIG_IMX) += imx25_ccm.o >> obj-$(CONFIG_IMX) += imx6_ccm.o >> obj-$(CONFIG_IMX) += imx6_src.o >> +obj-$(CONFIG_IMX) += imx7_ccm.o >> obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o >> obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o >> obj-$(CONFIG_MAINSTONE) += mst_fpga.o >> diff --git a/hw/misc/imx7_ccm.c b/hw/misc/imx7_ccm.c >> new file mode 100644 >> index 00..2876164cfa >> --- /dev/null >> +++ b/hw/misc/imx7_ccm.c >> @@ -0,0 +1,233 @@ >> +/* >> + * Copyright (c) 2017, Impinj, Inc. >> + * >> + * i.MX7 CCM, PMU and ANALOG IP blocks emulation code > > Should these really all be in one single device rather > than one device per IP block ? > They all share the same register write semantics, imx7_set_clr_tog_write, so I'd like to keep them in the same file. But other than that, they can be split into all sorts of configurations. As far as memory map in i.MX7 RM is concerned "CCM" and "Analog" are distinct register files where the rest of them ("digiprog", "pmu") are "sub-blocks" of those two (or at least that's my interpretation). I'll change v4 to have that split. If you want me to convert every block _and_ sub-block into a standalone device, let me know. Thanks, Andrey Smirnov
Re: [Qemu-devel] [PATCH v3 14/30] i.MX: Add code to emulate i.MX2 watchdog IP block
On Tue, Nov 21, 2017 at 10:10 AM, Peter Maydell wrote: > On 6 November 2017 at 15:47, Andrey Smirnov wrote: >> Add enough code to emulate i.MX2 watchdog IP block so it would be >> possible to reboot the machine running Linux Guest. >> >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc: Philippe Mathieu-Daudé >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> --- >> hw/misc/Makefile.objs | 1 + >> hw/misc/imx2_wdt.c | 88 >> ++ >> include/hw/misc/imx2_wdt.h | 34 ++ >> 3 files changed, 123 insertions(+) >> create mode 100644 hw/misc/imx2_wdt.c >> create mode 100644 include/hw/misc/imx2_wdt.h >> >> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs >> index ac1be05a03..c393a93456 100644 >> --- a/hw/misc/Makefile.objs >> +++ b/hw/misc/Makefile.objs >> @@ -35,6 +35,7 @@ obj-$(CONFIG_IMX) += imx25_ccm.o >> obj-$(CONFIG_IMX) += imx6_ccm.o >> obj-$(CONFIG_IMX) += imx6_src.o >> obj-$(CONFIG_IMX) += imx7_ccm.o >> +obj-$(CONFIG_IMX) += imx2_wdt.o >> obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o >> obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o >> obj-$(CONFIG_MAINSTONE) += mst_fpga.o >> diff --git a/hw/misc/imx2_wdt.c b/hw/misc/imx2_wdt.c >> new file mode 100644 >> index 00..3a1c33aa51 >> --- /dev/null >> +++ b/hw/misc/imx2_wdt.c >> @@ -0,0 +1,88 @@ >> +/* >> + * Copyright (c) 2017, Impinj, Inc. >> + * >> + * i.MX2 Watchdog IP block >> + * >> + * Author: Andrey Smirnov >> + * >> + * This work is licensed under the terms of the GNU GPL, version 2 or later. >> + * See the COPYING file in the top-level directory. >> + */ >> + >> +#include "qemu/osdep.h" >> +#include "sysemu/watchdog.h" >> + >> +#include "hw/misc/imx2_wdt.h" >> + >> +#define IMX2_WDT_WCR_WDABIT(5) /* -> External Reset WDOG_B */ >> +#define IMX2_WDT_WCR_SRSBIT(4) /* -> Software Reset Signal */ >> + >> +static uint64_t imx2_wdt_read(void *opaque, hwaddr addr, >> + unsigned int size) >> +{ >> +return 0; >> +} >> + >> +static void imx2_wdt_write(void *opaque, hwaddr addr, >> + uint64_t value, unsigned int size) >> +{ >> +if (addr == IMX2_WDT_WCR && >> +(value & (IMX2_WDT_WCR_WDA | IMX2_WDT_WCR_SRS))) { >> +watchdog_perform_action(); >> +} >> +} >> + >> +static const MemoryRegionOps imx2_wdt_ops = { >> +.read = imx2_wdt_read, >> +.write = imx2_wdt_write, >> +.endianness = DEVICE_NATIVE_ENDIAN, >> +.impl = { >> +/* >> + * Our device would not work correctly if the guest was doing >> + * unaligned access. This might not be a limitation on the >> + * real device but in practice there is no reason for a guest >> + * to access this device unaligned. >> + */ >> +.min_access_size = 4, >> +.max_access_size = 4, >> +.unaligned = false, >> +}, >> +}; >> + >> +static void imx2_wdt_realize(DeviceState *dev, Error **errp) >> +{ >> +IMX2WdtState *s = IMX2_WDT(dev); >> + >> +memory_region_init_io(&s->mmio, OBJECT(dev), >> + &imx2_wdt_ops, s, >> + TYPE_IMX2_WDT".mmio", >> + IMX2_WDT_REG_NUM * sizeof(uint16_t)); >> +sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); >> +} >> + >> +static void imx2_wdt_class_init(ObjectClass *klass, void *data) >> +{ >> +DeviceClass *dc = DEVICE_CLASS(klass); >> + >> +dc->realize = imx2_wdt_realize; >> +set_bit(DEVICE_CATEGORY_MISC, dc->categories); >> +} >> + >> +static const TypeInfo imx2_wdt_info = { >> +.name = TYPE_IMX2_WDT, >> +.parent= TYPE_SYS_BUS_DEVICE, >> +.instance_size = sizeof(IMX2WdtState), >> +.class_init= imx2_wdt_class_init, >> +}; >> + >> +static WatchdogTimerModel model = { >> +.wdt_name = "imx2-watchdog", >> +.wdt_description = "i.MX2 Watchdog", >> +}; >> + >> +static void imx2_wdt_register_type(void) >> +{ >> +watchdog_add_model(&model); >> +type_register_static(&imx2_wdt_info); >> +} >> +type_init(imx2_wdt_register_type) >> diff --git a/include/hw/misc/imx2_wdt.h b/include/hw/misc/imx2_wdt.h >> new file mode 100644 >> index 00..e67ac6939d >> --- /dev/null >> +++ b/include/hw/misc/imx2_wdt.h >> @@ -0,0 +1,34 @@ >> +/* >> + * Copyright (c) 2017, Impinj, Inc. >> + * >> + * i.MX2 Watchdog IP block >> + * >> + * Author: Andrey Smirnov >> + * >> + * This work is licensed under the terms of the GNU GPL, version 2 or later. >> + * See the COPYING file in the top-level directory. >> + */ >> + >> +#ifndef IMX2_WDT_H >> +#define IMX2_WDT_H >> + >> +#include "qemu/bitops.h" >> +#include "hw/sysbus.h" > > The bitops.h include should be in the .c file, not here. > Will fix in v4. Thanks, Andrey Smirnov
Re: [Qemu-devel] [PATCH v3 19/30] i.MX: Add code to emulate SDMA IP block
On Tue, Nov 21, 2017 at 10:20 AM, Peter Maydell wrote: > On 6 November 2017 at 15:48, Andrey Smirnov wrote: >> Add minimal code needed to allow upstream Linux guest to boot. >> >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc: Philippe Mathieu-Daudé >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> --- >> hw/dma/Makefile.objs | 1 + >> hw/dma/imx_sdma.c | 99 >> +++ >> include/hw/dma/imx_sdma.h | 22 +++ >> 3 files changed, 122 insertions(+) >> create mode 100644 hw/dma/imx_sdma.c >> create mode 100644 include/hw/dma/imx_sdma.h >> > > Does Linux really insist on reads-as-written behaviour? > (ie can you get away with just using > create_unimplemented_device() ?) > Not sure. I'll give it a try for v4. Thanks, Andrey Smirnov
Re: [Qemu-devel] [PATCH v3 29/30] i.MX: Add i.MX7 SOC implementation.
On Wed, Nov 22, 2017 at 7:34 AM, Igor Mammedov wrote: > On Mon, 6 Nov 2017 07:48:12 -0800 > Andrey Smirnov wrote: > >> The following interfaces are partially or fully emulated: >> >> * up to 2 Cortex A9 cores (SMP works with PSCI) >> * A7 MPCORE (identical to A15 MPCORE) >> * 4 GPTs modules >> * 7 GPIO controllers >> * 2 IOMUXC controllers >> * 1 CCM module >> * 1 SVNS module >> * 1 SRC module >> * 1 GPCv2 controller >> * 4 eCSPI controllers >> * 4 I2C controllers >> * 7 i.MX UART controllers >> * 2 FlexCAN controllers >> * 2 Ethernet controllers (FEC) >> * 3 SD controllers (USDHC) >> * 4 WDT modules >> * 1 SDMA module >> * 1 GPR module >> * 2 USBMISC modules >> * 2 ADC modules >> * 1 PCIe controller >> >> Tested to boot and work with upstream Linux (4.13+) guest. >> >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc: Philippe Mathieu-Daudé >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> --- > ... >> + >> +static void fsl_imx7_init(Object *obj) >> +{ >> +BusState *sysbus = sysbus_get_default(); >> +FslIMX7State *s = FSL_IMX7(obj); >> +char name[NAME_SIZE]; >> +int i; >> + >> +if (smp_cpus > FSL_IMX7_NUM_CPUS) { >> +error_report("%s: Only %d CPUs are supported (%d requested)", >> + TYPE_FSL_IMX7, FSL_IMX7_NUM_CPUS, smp_cpus); >> +exit(1); >> +} >> + >> +for (i = 0; i < smp_cpus; i++) { >> +object_initialize(&s->cpu[i], sizeof(s->cpu[i]), >> + "cortex-a7-" TYPE_ARM_CPU); > pls reuse ARM_CPU_TYPE_NAME() macro here Will do in v4. Thanks, Andrey Smirnov
[Qemu-devel] [PATCH] fsl_etsec: Fix Tx BD ring wrapping handling
Current code that handles Tx buffer desciprtor ring scanning employs the following algorithm: 1. Restore current buffer descriptor pointer from TBPTRn 2. Process current descriptor 3. If current descriptor has BD_WRAP flag set set current descriptor pointer to start of the descriptor ring 4. If current descriptor points to start of the ring exit the loop, otherwise increment current descriptor pointer and go to #2 5. Store current descriptor in TBPTRn As it can be seen the way the code is implemented results in buffer descriptor ring being scanned starting at offset/descriptor #0. While covering proverbial "99%" of the cases, this algorithm becomes problematic for a number of edge cases. Consider the following scenario: guest OS driver initializes descriptor ring to N individual descriptors and starts sending data out. Depending on the volume of traffic and probably guest OS driver implementation it is possible that an edge case where a packet, spread across 2 descriptors is placed in descriptors N - 1 and 0 in that order(it is easy to imagine similar examples involving more than 2 descriptors). What happens then is aforementioned algorithm starts at descriptor 0, sees a descriptor marked as BD_LAST, which it happily sends out as a separate packet(very much malformed at this point) then the iteration continues and the first part of the original packet is tacked to the next transmission which ends up being bogus as well. This behvaiour can be pretty reliably observed when scp'ing data from a guest OS via TAP interface for files larger than 160K (every time for 700K+). This patch changes the scanning algorithm to do the following: 1. Restore "current" and "start" buffer descriptor pointer from TBPTRn 2. If "current" descriptor has BD_WRAP flag set "next" descriptor pointer to start of the descriptor ring otherwise set "next" to descriptor right after "current" 3. Process current descriptor 4. If current descriptore has BD_LAST(end of a packet) set save "next" descriptor pointer in TBPTRn 5. Set "current" descriptor pointer to "next" 6. If "current" descriptor points to "start" (from #1) exit the loop loop, otherwise go to #2 This way emulation code always keeps track where guest OS driver was driving data to last while still going full "loop" over every descriptor in a ring, which, hopefully, should fix any potential "wrapping" issues. Signed-off-by: Andrey Smirnov --- hw/net/fsl_etsec/rings.c | 40 +--- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c index 54c0127..3aebd59 100644 --- a/hw/net/fsl_etsec/rings.c +++ b/hw/net/fsl_etsec/rings.c @@ -332,7 +332,7 @@ static void process_tx_bd(eTSEC *etsec, void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr) { hwaddrring_base = 0; -hwaddrbd_addr = 0; +hwaddrbd_addr, bd_addr_start, bd_addr_next; eTSEC_rxtx_bd bd; uint16_t bd_flags; @@ -343,7 +343,7 @@ void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr) ring_base = (hwaddr)(etsec->regs[TBASEH].value & 0xF) << 32; ring_base += etsec->regs[TBASE0 + ring_nbr].value & ~0x7; -bd_addr= etsec->regs[TBPTR0 + ring_nbr].value & ~0x7; +bd_addr_start = bd_addr = etsec->regs[TBPTR0 + ring_nbr].value & ~0x7; do { read_buffer_descriptor(etsec, bd_addr, &bd); @@ -358,26 +358,36 @@ void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr) /* Save flags before BD update */ bd_flags = bd.flags; -if (bd_flags & BD_TX_READY) { -process_tx_bd(etsec, &bd); - -/* Write back BD after update */ -write_buffer_descriptor(etsec, bd_addr, &bd); -} - /* Wrap or next BD */ if (bd_flags & BD_WRAP) { -bd_addr = ring_base; +bd_addr_next = ring_base; } else { -bd_addr += sizeof(eTSEC_rxtx_bd); +bd_addr_next = bd_addr + sizeof(eTSEC_rxtx_bd); } -} while (bd_addr != ring_base); +if (bd_flags & BD_TX_READY) { +if (bd_flags & BD_LAST) { +/* If we encounter a descriptor marking end of a + * packet - save a pointer to descriptor after that as + * a place to resume descriptor processing for next + * time. + * + * As we iterate through a ring we progressively move + * this point forward and at the end of one cycle end + * up with the position ri
Re: [Qemu-devel] [PATCH v4 09/14] pci: Add support for Designware IP block
On Tue, Jan 30, 2018 at 5:18 AM, Marcel Apfelbaum wrote: > Hi Andrei, > > Sorry for letting you wait, > I have some comments/questions below. > > > On 16/01/2018 3:37, Andrey Smirnov wrote: >> >> Add code needed to get a functional PCI subsytem when using in >> conjunction with upstream Linux guest (4.13+). Tested to work against >> "e1000e" (network adapter, using MSI interrupts) as well as >> "usb-ehci" (USB controller, using legacy PCI interrupts). >> >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc: Philippe Mathieu-Daudé >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Signed-off-by: Andrey Smirnov >> --- >> default-configs/arm-softmmu.mak | 2 + >> hw/pci-host/Makefile.objs| 2 + >> hw/pci-host/designware.c | 618 >> +++ >> include/hw/pci-host/designware.h | 93 ++ >> include/hw/pci/pci_ids.h | 2 + >> 5 files changed, 717 insertions(+) >> create mode 100644 hw/pci-host/designware.c >> create mode 100644 include/hw/pci-host/designware.h >> >> diff --git a/default-configs/arm-softmmu.mak >> b/default-configs/arm-softmmu.mak >> index b0d6e65038..0c5ae914ed 100644 >> --- a/default-configs/arm-softmmu.mak >> +++ b/default-configs/arm-softmmu.mak >> @@ -132,3 +132,5 @@ CONFIG_GPIO_KEY=y >> CONFIG_MSF2=y >> CONFIG_FW_CFG_DMA=y >> CONFIG_XILINX_AXI=y >> +CONFIG_PCI_DESIGNWARE=y >> + >> diff --git a/hw/pci-host/Makefile.objs b/hw/pci-host/Makefile.objs >> index 9c7909cf44..0e2c0a123b 100644 >> --- a/hw/pci-host/Makefile.objs >> +++ b/hw/pci-host/Makefile.objs >> @@ -17,3 +17,5 @@ common-obj-$(CONFIG_PCI_PIIX) += piix.o >> common-obj-$(CONFIG_PCI_Q35) += q35.o >> common-obj-$(CONFIG_PCI_GENERIC) += gpex.o >> common-obj-$(CONFIG_PCI_XILINX) += xilinx-pcie.o >> + >> +common-obj-$(CONFIG_PCI_DESIGNWARE) += designware.o >> diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c >> new file mode 100644 >> index 00..98fff5e5f3 >> --- /dev/null >> +++ b/hw/pci-host/designware.c >> @@ -0,0 +1,618 @@ >> +/* >> + * Copyright (c) 2017, Impinj, Inc. > > 2018 :) > >> + * >> + * Designware PCIe IP block emulation >> + * >> + * This library is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU Lesser General Public >> + * License as published by the Free Software Foundation; either >> + * version 2 of the License, or (at your option) any later version. >> + * >> + * This library 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 >> + * Lesser General Public License for more details. >> + * >> + * You should have received a copy of the GNU Lesser General Public >> + * License along with this library; if not, see >> + * <http://www.gnu.org/licenses/>. >> + */ >> + >> +#include "qemu/osdep.h" >> +#include "qapi/error.h" >> +#include "hw/pci/msi.h" >> +#include "hw/pci/pci_bridge.h" >> +#include "hw/pci/pci_host.h" >> +#include "hw/pci/pcie_port.h" >> +#include "hw/pci-host/designware.h" >> + >> +#define PCIE_PORT_LINK_CONTROL 0x710 >> + >> +#define PCIE_PHY_DEBUG_R1 0x72C >> +#define PCIE_PHY_DEBUG_R1_XMLH_LINK_UP BIT(4) >> + >> +#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C >> + >> +#define PCIE_MSI_ADDR_LO0x820 >> +#define PCIE_MSI_ADDR_HI0x824 >> +#define PCIE_MSI_INTR0_ENABLE 0x828 >> +#define PCIE_MSI_INTR0_MASK 0x82C >> +#define PCIE_MSI_INTR0_STATUS 0x830 >> + >> +#define PCIE_ATU_VIEWPORT 0x900 >> +#define PCIE_ATU_REGION_INBOUND (0x1 << 31) >> +#define PCIE_ATU_REGION_OUTBOUND(0x0 << 31) >> +#define PCIE_ATU_REGION_INDEX2 (0x2 << 0) >> +#define PCIE_ATU_REGION_INDEX1 (0x1 << 0) >> +#define PCIE_ATU_REGION_INDEX0 (0x0 << 0) >> +#define PCIE_ATU_CR10x904 >> +#define PCIE_ATU_TYPE_MEM (0x0 << 0) >> +#define PCIE_ATU_TYPE_IO(0x2 << 0) >> +#define PCIE_ATU_TYPE_CFG0 (0x4 << 0) >> +#define PCIE_ATU_TYPE_CFG1
Re: [Qemu-devel] [PATCH v4 05/14] i.MX: Add code to emulate i.MX7 SNVS IP-block
On Wed, Jan 31, 2018 at 9:10 AM, Philippe Mathieu-Daudé wrote: > On 01/15/2018 10:37 PM, Andrey Smirnov wrote: >> Add code to emulate SNVS IP-block. Currently only the bits needed to >> be able to emulate machine shutdown are implemented. >> >> Cc: Peter Maydell >> Cc: Jason Wang >> Cc: Philippe Mathieu-Daudé >> Cc: qemu-devel@nongnu.org >> Cc: qemu-...@nongnu.org >> Cc: yurov...@gmail.com >> Reviewed-by: Peter Maydell >> Signed-off-by: Andrey Smirnov >> --- >> hw/misc/Makefile.objs | 1 + >> hw/misc/imx7_snvs.c | 83 >> + >> include/hw/misc/imx7_snvs.h | 35 +++ >> 3 files changed, 119 insertions(+) >> create mode 100644 hw/misc/imx7_snvs.c >> create mode 100644 include/hw/misc/imx7_snvs.h >> >> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs >> index 4b2b705a6c..019886912c 100644 >> --- a/hw/misc/Makefile.objs >> +++ b/hw/misc/Makefile.objs >> @@ -35,6 +35,7 @@ obj-$(CONFIG_IMX) += imx6_ccm.o >> obj-$(CONFIG_IMX) += imx6_src.o >> obj-$(CONFIG_IMX) += imx7_ccm.o >> obj-$(CONFIG_IMX) += imx2_wdt.o >> +obj-$(CONFIG_IMX) += imx7_snvs.o >> obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o >> obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o >> obj-$(CONFIG_MAINSTONE) += mst_fpga.o >> diff --git a/hw/misc/imx7_snvs.c b/hw/misc/imx7_snvs.c >> new file mode 100644 >> index 00..670b9f4639 >> --- /dev/null >> +++ b/hw/misc/imx7_snvs.c >> @@ -0,0 +1,83 @@ >> +/* >> + * IMX7 Secure Non-Volatile Storage >> + * >> + * Copyright (c) 2017, Impinj, Inc. >> + * >> + * Author: Andrey Smirnov >> + * >> + * This work is licensed under the terms of the GNU GPL, version 2 or later. >> + * See the COPYING file in the top-level directory. >> + * >> + * Bare minimum emulation code needed to support being able to shut >> + * down linux guest gracefully. >> + */ >> + >> +#include "qemu/osdep.h" >> +#include "hw/misc/imx7_snvs.h" >> +#include "qemu/log.h" >> +#include "sysemu/sysemu.h" >> + >> +static uint64_t imx7_snvs_read(void *opaque, hwaddr offset, unsigned size) >> +{ >> +return 0; >> +} >> + >> +static void imx7_snvs_write(void *opaque, hwaddr offset, >> +uint64_t v, unsigned size) >> +{ >> +const uint32_t value = v; >> +const uint32_t mask = SNVS_LPCR_TOP | SNVS_LPCR_DP_EN; >> + >> +if (offset == SNVS_LPCR && ((value & mask) == mask)) { >> +qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); >> +} >> +} >> + >> +static const struct MemoryRegionOps imx7_snvs_ops = { >> +.read = imx7_snvs_read, > > Same here, you can remove the imx7_snvs_read() function since > memory_region_dispatch_read() takes care of this and return 0. > Hmm, I don't think I agree both from reading code and trying this out. Without .read callback the call chain ends up being the following memory_region_dispatch_read() -> memory_region_dispatch_read1() -> access_with_adjusted_size(..., memory_region_oldmmio_read_accessor, ...) -> memory_region_oldmmio_read_accessor() -> mr->ops->old_mmio.read[ctz32(size)]() -> SEGFAULT As much as I'd love to get rid of dummy .read callback, I don't see a way to do that, unfortunately. Thanks, Andrey Smirnov
Re: [Qemu-devel] [PATCH v4 00/14] Initial i.MX7 support
On Wed, Jan 31, 2018 at 9:03 AM, Philippe Mathieu-Daudé wrote: > Hi Peter, Andrey. > > On 01/15/2018 10:36 PM, Andrey Smirnov wrote: >> Hi everyone, >> >> This v4 of the patch series containing the work that I've done in >> order to enable support for i.MX7 emulation in QEMU. >> >> *NOTE*: Patches 1 and 2 are provided for the sake of completness and >> are going to have to be adapted once Philippe's SD changes >> land in master. As such, they are NOT ready to be >> accepted/merged. > > Peter: > Since my series are taking longer, if this series is ready it is > probably easier to apply Andrey series first and I'll adapt my SDHCI > series after. > > Andrey: > I only plan to keep the sdhci.c file generic (dealing with quirks) and > split out the imx usdhci code, similar to this patch: > https://lists.gnu.org/archive/html/qemu-devel/2018-01/msg01265.html Yes, I understand that, but I still am not clear how you propose dealing with the fact that i.MX specific read/write functions need to call similar functions from parent SDHC class. Are you planning on adding overridable read()/write() methods to SDHCICommonClass? Thanks, Andrey Smirnov
Re: [Qemu-devel] [PATCH v4 09/14] pci: Add support for Designware IP block
On Wed, Jan 31, 2018 at 4:13 AM, Marcel Apfelbaum wrote: > On 30/01/2018 19:49, Andrey Smirnov wrote: >> On Tue, Jan 30, 2018 at 5:18 AM, Marcel Apfelbaum >> wrote: >>> Hi Andrei, >>> >>> Sorry for letting you wait, >>> I have some comments/questions below. >>> >>> >>> On 16/01/2018 3:37, Andrey Smirnov wrote: >>>> >>>> Add code needed to get a functional PCI subsytem when using in >>>> conjunction with upstream Linux guest (4.13+). Tested to work against >>>> "e1000e" (network adapter, using MSI interrupts) as well as >>>> "usb-ehci" (USB controller, using legacy PCI interrupts). >>>> >>>> Cc: Peter Maydell >>>> Cc: Jason Wang >>>> Cc: Philippe Mathieu-Daudé >>>> Cc: qemu-devel@nongnu.org >>>> Cc: qemu-...@nongnu.org >>>> Cc: yurov...@gmail.com >>>> Signed-off-by: Andrey Smirnov >>>> --- >>>> default-configs/arm-softmmu.mak | 2 + >>>> hw/pci-host/Makefile.objs| 2 + >>>> hw/pci-host/designware.c | 618 >>>> +++ >>>> include/hw/pci-host/designware.h | 93 ++ >>>> include/hw/pci/pci_ids.h | 2 + >>>> 5 files changed, 717 insertions(+) >>>> create mode 100644 hw/pci-host/designware.c >>>> create mode 100644 include/hw/pci-host/designware.h >>>> >>>> diff --git a/default-configs/arm-softmmu.mak >>>> b/default-configs/arm-softmmu.mak >>>> index b0d6e65038..0c5ae914ed 100644 >>>> --- a/default-configs/arm-softmmu.mak >>>> +++ b/default-configs/arm-softmmu.mak >>>> @@ -132,3 +132,5 @@ CONFIG_GPIO_KEY=y >>>> CONFIG_MSF2=y >>>> CONFIG_FW_CFG_DMA=y >>>> CONFIG_XILINX_AXI=y >>>> +CONFIG_PCI_DESIGNWARE=y >>>> + >>>> diff --git a/hw/pci-host/Makefile.objs b/hw/pci-host/Makefile.objs >>>> index 9c7909cf44..0e2c0a123b 100644 >>>> --- a/hw/pci-host/Makefile.objs >>>> +++ b/hw/pci-host/Makefile.objs >>>> @@ -17,3 +17,5 @@ common-obj-$(CONFIG_PCI_PIIX) += piix.o >>>> common-obj-$(CONFIG_PCI_Q35) += q35.o >>>> common-obj-$(CONFIG_PCI_GENERIC) += gpex.o >>>> common-obj-$(CONFIG_PCI_XILINX) += xilinx-pcie.o >>>> + >>>> +common-obj-$(CONFIG_PCI_DESIGNWARE) += designware.o >>>> diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c >>>> new file mode 100644 >>>> index 00..98fff5e5f3 >>>> --- /dev/null >>>> +++ b/hw/pci-host/designware.c >>>> @@ -0,0 +1,618 @@ >>>> +/* >>>> + * Copyright (c) 2017, Impinj, Inc. >>> >>> 2018 :) >>> >>>> + * >>>> + * Designware PCIe IP block emulation >>>> + * >>>> + * This library is free software; you can redistribute it and/or >>>> + * modify it under the terms of the GNU Lesser General Public >>>> + * License as published by the Free Software Foundation; either >>>> + * version 2 of the License, or (at your option) any later version. >>>> + * >>>> + * This library 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 >>>> + * Lesser General Public License for more details. >>>> + * >>>> + * You should have received a copy of the GNU Lesser General Public >>>> + * License along with this library; if not, see >>>> + * <http://www.gnu.org/licenses/>. >>>> + */ >>>> + >>>> +#include "qemu/osdep.h" >>>> +#include "qapi/error.h" >>>> +#include "hw/pci/msi.h" >>>> +#include "hw/pci/pci_bridge.h" >>>> +#include "hw/pci/pci_host.h" >>>> +#include "hw/pci/pcie_port.h" >>>> +#include "hw/pci-host/designware.h" >>>> + >>>> +#define PCIE_PORT_LINK_CONTROL 0x710 >>>> + >>>> +#define PCIE_PHY_DEBUG_R1 0x72C >>>> +#define PCIE_PHY_DEBUG_R1_XMLH_LINK_UP BIT(4) >>>> + >>>> +#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C >>>> + >>>> +#define PCIE_MSI_ADDR_LO0x820 >>>> +#define PCIE
[Qemu-devel] [PATCH v5 00/14] Initial i.MX7 support
Hi everyone, This v5 of the patch series containing the work that I've done in order to enable support for i.MX7 emulation in QEMU. As the one before last commit in the series states the supported i.MX7 features are: * up to 2 Cortex A9 cores (SMP works with PSCI) * A7 MPCORE (identical to A15 MPCORE) * 4 GPTs modules * 7 GPIO controllers * 2 IOMUXC controllers * 1 CCM module * 1 SVNS module * 1 SRC module * 1 GPCv2 controller * 4 eCSPI controllers * 4 I2C controllers * 7 i.MX UART controllers * 2 FlexCAN controllers * 2 Ethernet controllers (FEC) * 3 SD controllers (USDHC) * 4 WDT modules * 1 SDMA module * 1 GPR module * 2 USBMISC modules * 2 ADC modules * 1 PCIe controller * 3 USB controllers * 1 LCD controller * 1 ARMv7 DAP IP block Feedback is welcome! Changes since [v4]: - Rebase patchest on top of latest QEMU master - Reworked PCIE emulation code to create MemoryRegions only once - Fixed incorrect usages of PCI instead of PCIE - Fixed device class reported by PCIE bridge - Added patch to make pci_data_read() and pci_data_write() usable for PCIE devices as well - Converted PCIE code to use pci_data_read() and pci_data_write() - Added VMStateDescription code for PCIE - Collected Reviewed-by tag from Philippe Changes since [v3]: - Changes to FEC were split into a separate set and merged to master - Patchest is rebased on latest master - Converted to use PSCI DT fixup code that is shared with virt platform (now relocated to live in arm/boot.c) - Large number of dummy block were converted to use create_unimplemented_device() as opposed to its own dedicated type - Incorporated varios small feedback items - Collected Reviewed-by tags from Peter Changes since [v2]: - Added stubs for more blocks that were causing memory transactions when booting Linux guest as were revealed by additional testing of the patchest - Added proper USB emulation code, so now it should be possible to emulated guest's USB bus Changes since [v1]: - Patchset no longer relies on "ignore_memory_transaction_failures = false" for its functionality - As a consequnce of implementing the above a number of patches implementing dummy IP block emulation as well as PCIe emulation patches that I alluded to in [v1] are now included in this patch series - "has_el3" property is no longer being set to "false" as a part of intialization of A7 CPU. I couldn't reproduce the issues that I thought I was having, so I just dropped that code. - A number of smaller feedback items from Peter and other has been incorporated into the patches. Thanks, Andrey Smirnov [v4] https://lists.gnu.org/archive/html/qemu-devel/2018-01/msg03264.html [v3] https://lists.gnu.org/archive/html/qemu-devel/2017-11/msg04236.html [v2] https://lists.gnu.org/archive/html/qemu-devel/2017-10/msg05516.html [v1] https://lists.gnu.org/archive/html/qemu-devel/2017-09/msg04770.html Andrey Smirnov (14): sdhci: Add i.MX specific subtype of SDHCI hw: i.MX: Convert i.MX6 to use TYPE_IMX_USDHC i.MX: Add code to emulate i.MX7 CCM, PMU and ANALOG IP blocks i.MX: Add code to emulate i.MX2 watchdog IP block i.MX: Add code to emulate i.MX7 SNVS IP-block i.MX: Add code to emulate GPCv2 IP block i.MX: Add i.MX7 GPT variant i.MX: Add implementation of i.MX7 GPR IP block pci: Use pci_config_size in pci_data_* accessors pci: Add support for Designware IP block usb: Add basic code to emulate Chipidea USB IP i.MX: Add i.MX7 SOC implementation. hw/arm: Move virt's PSCI DT fixup code to arm/boot.c Implement support for i.MX7 Sabre board default-configs/arm-softmmu.mak | 3 + hw/arm/Makefile.objs | 3 + hw/arm/boot.c| 65 hw/arm/fsl-imx6.c| 2 +- hw/arm/fsl-imx7.c| 580 ++ hw/arm/mcimx7d-sabre.c | 90 + hw/arm/virt.c| 61 hw/intc/Makefile.objs| 2 +- hw/intc/imx_gpcv2.c | 125 +++ hw/misc/Makefile.objs| 4 + hw/misc/imx2_wdt.c | 89 + hw/misc/imx7_ccm.c | 277 ++ hw/misc/imx7_gpr.c | 124 +++ hw/misc/imx7_snvs.c | 83 + hw/misc/trace-events | 4 + hw/pci-host/Makefile.objs| 2 + hw/pci-host/designware.c | 759 +++ hw/pci/pci_host.c| 13 +- hw/sd/sdhci-internal.h | 20 ++ hw/sd/sdhci.c| 230 +++- hw/timer/imx_gpt.c | 25 ++ hw/usb/Makefile.objs | 1 + hw/usb/chipidea.c| 176 + include/hw/arm/fsl
[Qemu-devel] [PATCH v5 03/14] i.MX: Add code to emulate i.MX7 CCM, PMU and ANALOG IP blocks
Add minimal code needed to allow upstream Linux guest to boot. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: Marcel Apfelbaum Cc: Michael S. Tsirkin Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov --- hw/misc/Makefile.objs | 1 + hw/misc/imx7_ccm.c | 277 + include/hw/misc/imx7_ccm.h | 139 +++ 3 files changed, 417 insertions(+) create mode 100644 hw/misc/imx7_ccm.c create mode 100644 include/hw/misc/imx7_ccm.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index d517f83e81..a28e5e49b0 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -33,6 +33,7 @@ obj-$(CONFIG_IMX) += imx31_ccm.o obj-$(CONFIG_IMX) += imx25_ccm.o obj-$(CONFIG_IMX) += imx6_ccm.o obj-$(CONFIG_IMX) += imx6_src.o +obj-$(CONFIG_IMX) += imx7_ccm.o obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o obj-$(CONFIG_MAINSTONE) += mst_fpga.o diff --git a/hw/misc/imx7_ccm.c b/hw/misc/imx7_ccm.c new file mode 100644 index 00..d90c48bfec --- /dev/null +++ b/hw/misc/imx7_ccm.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2018, Impinj, Inc. + * + * i.MX7 CCM, PMU and ANALOG IP blocks emulation code + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" + +#include "hw/misc/imx7_ccm.h" + +static void imx7_analog_reset(DeviceState *dev) +{ +IMX7AnalogState *s = IMX7_ANALOG(dev); + +memset(s->pmu, 0, sizeof(s->pmu)); +memset(s->analog, 0, sizeof(s->analog)); + +s->analog[ANALOG_PLL_ARM] = 0x2042; +s->analog[ANALOG_PLL_DDR] = 0x0060302c; +s->analog[ANALOG_PLL_DDR_SS] = 0x; +s->analog[ANALOG_PLL_DDR_NUM] = 0x06aaac4d; +s->analog[ANALOG_PLL_DDR_DENOM] = 0x13ec; +s->analog[ANALOG_PLL_480] = 0x2000; +s->analog[ANALOG_PLL_480A]= 0x52605a56; +s->analog[ANALOG_PLL_480B]= 0x52525216; +s->analog[ANALOG_PLL_ENET]= 0x1fc0; +s->analog[ANALOG_PLL_AUDIO] = 0x0001301b; +s->analog[ANALOG_PLL_AUDIO_SS]= 0x; +s->analog[ANALOG_PLL_AUDIO_NUM] = 0x05f5e100; +s->analog[ANALOG_PLL_AUDIO_DENOM] = 0x2964619c; +s->analog[ANALOG_PLL_VIDEO] = 0x0008201b; +s->analog[ANALOG_PLL_VIDEO_SS]= 0x; +s->analog[ANALOG_PLL_VIDEO_NUM] = 0xf699; +s->analog[ANALOG_PLL_VIDEO_DENOM] = 0x000f4240; +s->analog[ANALOG_PLL_MISC0] = 0x; + +/* all PLLs need to be locked */ +s->analog[ANALOG_PLL_ARM] |= ANALOG_PLL_LOCK; +s->analog[ANALOG_PLL_DDR] |= ANALOG_PLL_LOCK; +s->analog[ANALOG_PLL_480] |= ANALOG_PLL_LOCK; +s->analog[ANALOG_PLL_480A] |= ANALOG_PLL_LOCK; +s->analog[ANALOG_PLL_480B] |= ANALOG_PLL_LOCK; +s->analog[ANALOG_PLL_ENET] |= ANALOG_PLL_LOCK; +s->analog[ANALOG_PLL_AUDIO] |= ANALOG_PLL_LOCK; +s->analog[ANALOG_PLL_VIDEO] |= ANALOG_PLL_LOCK; +s->analog[ANALOG_PLL_MISC0] |= ANALOG_PLL_LOCK; + +/* + * Since I couldn't find any info about this in the reference + * manual the value of this register is based strictly on matching + * what Linux kernel expects it to be. + */ +s->analog[ANALOG_DIGPROG] = 0x72; +/* + * Set revision to be 1.0 (Arbitrary choice, no particular + * reason). + */ +s->analog[ANALOG_DIGPROG] |= 0x10; +} + +static void imx7_ccm_reset(DeviceState *dev) +{ +IMX7CCMState *s = IMX7_CCM(dev); + +memset(s->ccm, 0, sizeof(s->ccm)); +} + +#define CCM_INDEX(offset) (((offset) & ~(hwaddr)0xF) / sizeof(uint32_t)) +#define CCM_BITOP(offset) ((offset) & (hwaddr)0xF) + +enum { +CCM_BITOP_NONE = 0x00, +CCM_BITOP_SET = 0x04, +CCM_BITOP_CLR = 0x08, +CCM_BITOP_TOG = 0x0C, +}; + +static uint64_t imx7_set_clr_tog_read(void *opaque, hwaddr offset, + unsigned size) +{ +const uint32_t *mmio = opaque; + +return mmio[CCM_INDEX(offset)]; +} + +static void imx7_set_clr_tog_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ +const uint8_t bitop = CCM_BITOP(offset); +const uint32_t index = CCM_INDEX(offset); +uint32_t *mmio = opaque; + +switch (bitop) { +case CCM_BITOP_NONE: +mmio[index] = value; +break; +case CCM_BITOP_SET: +mmio[index] |= value; +break; +case CCM_BITOP_CLR: +mmio[index] &= ~value; +break; +case CCM_BITOP_TOG: +mmio[index] ^= value; +break; +}; +} + +static const struct Me
[Qemu-devel] [PATCH v5 02/14] hw: i.MX: Convert i.MX6 to use TYPE_IMX_USDHC
Convert i.MX6 to use TYPE_IMX_USDHC since that's what real HW comes with. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: Marcel Apfelbaum Cc: Michael S. Tsirkin Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Andrey Smirnov --- hw/arm/fsl-imx6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index b0d4088290..e6559a8b12 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -93,7 +93,7 @@ static void fsl_imx6_init(Object *obj) } for (i = 0; i < FSL_IMX6_NUM_ESDHCS; i++) { -object_initialize(&s->esdhc[i], sizeof(s->esdhc[i]), TYPE_SYSBUS_SDHCI); +object_initialize(&s->esdhc[i], sizeof(s->esdhc[i]), TYPE_IMX_USDHC); qdev_set_parent_bus(DEVICE(&s->esdhc[i]), sysbus_get_default()); snprintf(name, NAME_SIZE, "sdhc%d", i + 1); object_property_add_child(obj, name, OBJECT(&s->esdhc[i]), NULL); -- 2.14.3
[Qemu-devel] [PATCH v5 04/14] i.MX: Add code to emulate i.MX2 watchdog IP block
Add enough code to emulate i.MX2 watchdog IP block so it would be possible to reboot the machine running Linux Guest. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: Marcel Apfelbaum Cc: Michael S. Tsirkin Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov --- hw/misc/Makefile.objs | 1 + hw/misc/imx2_wdt.c | 89 ++ include/hw/misc/imx2_wdt.h | 33 + 3 files changed, 123 insertions(+) create mode 100644 hw/misc/imx2_wdt.c create mode 100644 include/hw/misc/imx2_wdt.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index a28e5e49b0..4b2b705a6c 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -34,6 +34,7 @@ obj-$(CONFIG_IMX) += imx25_ccm.o obj-$(CONFIG_IMX) += imx6_ccm.o obj-$(CONFIG_IMX) += imx6_src.o obj-$(CONFIG_IMX) += imx7_ccm.o +obj-$(CONFIG_IMX) += imx2_wdt.o obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o obj-$(CONFIG_MAINSTONE) += mst_fpga.o diff --git a/hw/misc/imx2_wdt.c b/hw/misc/imx2_wdt.c new file mode 100644 index 00..e47e442592 --- /dev/null +++ b/hw/misc/imx2_wdt.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2018, Impinj, Inc. + * + * i.MX2 Watchdog IP block + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/bitops.h" +#include "sysemu/watchdog.h" + +#include "hw/misc/imx2_wdt.h" + +#define IMX2_WDT_WCR_WDABIT(5) /* -> External Reset WDOG_B */ +#define IMX2_WDT_WCR_SRSBIT(4) /* -> Software Reset Signal */ + +static uint64_t imx2_wdt_read(void *opaque, hwaddr addr, + unsigned int size) +{ +return 0; +} + +static void imx2_wdt_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ +if (addr == IMX2_WDT_WCR && +(value & (IMX2_WDT_WCR_WDA | IMX2_WDT_WCR_SRS))) { +watchdog_perform_action(); +} +} + +static const MemoryRegionOps imx2_wdt_ops = { +.read = imx2_wdt_read, +.write = imx2_wdt_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.impl = { +/* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the + * real device but in practice there is no reason for a guest + * to access this device unaligned. + */ +.min_access_size = 4, +.max_access_size = 4, +.unaligned = false, +}, +}; + +static void imx2_wdt_realize(DeviceState *dev, Error **errp) +{ +IMX2WdtState *s = IMX2_WDT(dev); + +memory_region_init_io(&s->mmio, OBJECT(dev), + &imx2_wdt_ops, s, + TYPE_IMX2_WDT".mmio", + IMX2_WDT_REG_NUM * sizeof(uint16_t)); +sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); +} + +static void imx2_wdt_class_init(ObjectClass *klass, void *data) +{ +DeviceClass *dc = DEVICE_CLASS(klass); + +dc->realize = imx2_wdt_realize; +set_bit(DEVICE_CATEGORY_MISC, dc->categories); +} + +static const TypeInfo imx2_wdt_info = { +.name = TYPE_IMX2_WDT, +.parent= TYPE_SYS_BUS_DEVICE, +.instance_size = sizeof(IMX2WdtState), +.class_init= imx2_wdt_class_init, +}; + +static WatchdogTimerModel model = { +.wdt_name = "imx2-watchdog", +.wdt_description = "i.MX2 Watchdog", +}; + +static void imx2_wdt_register_type(void) +{ +watchdog_add_model(&model); +type_register_static(&imx2_wdt_info); +} +type_init(imx2_wdt_register_type) diff --git a/include/hw/misc/imx2_wdt.h b/include/hw/misc/imx2_wdt.h new file mode 100644 index 00..8afc99a10e --- /dev/null +++ b/include/hw/misc/imx2_wdt.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX2 Watchdog IP block + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef IMX2_WDT_H +#define IMX2_WDT_H + +#include "hw/sysbus.h" + +#define TYPE_IMX2_WDT "imx2.wdt" +#define IMX2_WDT(obj) OBJECT_CHECK(IMX2WdtState, (obj), TYPE_IMX2_WDT) + +enum IMX2WdtRegisters { +IMX2_WDT_WCR = 0x, +IMX2_WDT_REG_NUM = 0x0008 / sizeof(uint16_t) + 1, +}; + + +typedef struct IMX2WdtState { +/* */ +SysBusDevice parent_obj; + +MemoryRegion mmio; +} IMX2WdtState; + +#endif /* IMX7_SNVS_H */ -- 2.14.3
[Qemu-devel] [PATCH v5 01/14] sdhci: Add i.MX specific subtype of SDHCI
IP block found on several generations of i.MX family does not use vanilla SDHCI implementation and it comes with a number of quirks. Introduce i.MX SDHCI subtype of SDHCI block to add code necessary to support unmodified Linux guest driver. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: Marcel Apfelbaum Cc: Michael S. Tsirkin Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov --- hw/sd/sdhci-internal.h | 20 + hw/sd/sdhci.c | 230 - include/hw/sd/sdhci.h | 13 +++ 3 files changed, 262 insertions(+), 1 deletion(-) diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h index fc807f08f3..f91b73af59 100644 --- a/hw/sd/sdhci-internal.h +++ b/hw/sd/sdhci-internal.h @@ -84,12 +84,18 @@ /* R/W Host control Register 0x0 */ #define SDHC_HOSTCTL 0x28 +#define SDHC_CTRL_LED 0x01 #define SDHC_CTRL_DMA_CHECK_MASK 0x18 #define SDHC_CTRL_SDMA 0x00 #define SDHC_CTRL_ADMA1_32 0x08 #define SDHC_CTRL_ADMA2_32 0x10 #define SDHC_CTRL_ADMA2_64 0x18 #define SDHC_DMA_TYPE(x) ((x) & SDHC_CTRL_DMA_CHECK_MASK) +#define SDHC_CTRL_4BITBUS 0x02 +#define SDHC_CTRL_8BITBUS 0x20 +#define SDHC_CTRL_CDTEST_INS 0x40 +#define SDHC_CTRL_CDTEST_EN0x80 + /* R/W Power Control Register 0x0 */ #define SDHC_PWRCON0x29 @@ -226,4 +232,18 @@ enum { sdhc_gap_write = 2 /* SDHC stopped at block gap during write operation */ }; +extern const VMStateDescription sdhci_vmstate; + + +#define ESDHC_MIX_CTRL 0x48 +#define ESDHC_VENDOR_SPEC 0xc0 +#define ESDHC_DLL_CTRL 0x60 + +#define ESDHC_TUNING_CTRL 0xcc +#define ESDHC_TUNE_CTRL_STATUS 0x68 +#define ESDHC_WTMK_LVL 0x44 + +#define ESDHC_CTRL_4BITBUS (0x1 << 1) +#define ESDHC_CTRL_8BITBUS (0x2 << 1) + #endif diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index fac7fa5c72..7c9683b47d 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -244,7 +244,8 @@ static void sdhci_send_command(SDHCIState *s) } } -if ((s->norintstsen & SDHC_NISEN_TRSCMP) && +if (!(s->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) && +(s->norintstsen & SDHC_NISEN_TRSCMP) && (s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY) { s->norintsts |= SDHC_NIS_TRSCMP; } @@ -1189,6 +1190,8 @@ static void sdhci_initfn(SDHCIState *s) s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_raise_insertion_irq, s); s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s); + +s->io_ops = &sdhci_mmio_ops; } static void sdhci_uninitfn(SDHCIState *s) @@ -1396,6 +1399,10 @@ static void sdhci_sysbus_realize(DeviceState *dev, Error ** errp) } sysbus_init_irq(sbd, &s->irq); + +memory_region_init_io(&s->iomem, OBJECT(s), s->io_ops, s, "sdhci", +SDHC_REGISTERS_MAP_SIZE); + sysbus_init_mmio(sbd, &s->iomem); } @@ -1447,11 +1454,232 @@ static const TypeInfo sdhci_bus_info = { .class_init = sdhci_bus_class_init, }; +static uint64_t usdhc_read(void *opaque, hwaddr offset, unsigned size) +{ +SDHCIState *s = SYSBUS_SDHCI(opaque); +uint32_t ret; +uint16_t hostctl; + +switch (offset) { +default: +return sdhci_read(opaque, offset, size); + +case SDHC_HOSTCTL: +/* + * For a detailed explanation on the following bit + * manipulation code see comments in a similar part of + * usdhc_write() + */ +hostctl = SDHC_DMA_TYPE(s->hostctl) << (8 - 3); + +if (s->hostctl & SDHC_CTRL_8BITBUS) { +hostctl |= ESDHC_CTRL_8BITBUS; +} + +if (s->hostctl & SDHC_CTRL_4BITBUS) { +hostctl |= ESDHC_CTRL_4BITBUS; +} + +ret = hostctl; +ret |= (uint32_t)s->blkgap << 16; +ret |= (uint32_t)s->wakcon << 24; + +break; + +case ESDHC_DLL_CTRL: +case ESDHC_TUNE_CTRL_STATUS: +case 0x6c: +case ESDHC_TUNING_CTRL: +case ESDHC_VENDOR_SPEC: +case ESDHC_MIX_CTRL: +case ESDHC_WTMK_LVL: +ret = 0; +break; +} + +return ret; +} + +static void +usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) +{ +SDHCIState *s = SYSBUS_SDHCI(opaque); +uint8_t hostctl; +uint32_t value = (uint32_t)val; + +switch (offset) { +case ESDHC_DLL_CTRL: +case ESDHC_TUNE_CTRL_STATUS: +case 0x6c: +case ESDHC_TUNING_CTRL: +case ESDHC_WTMK_LVL: +case ESDHC_VENDOR_SPEC: +
[Qemu-devel] [PATCH v5 05/14] i.MX: Add code to emulate i.MX7 SNVS IP-block
Add code to emulate SNVS IP-block. Currently only the bits needed to be able to emulate machine shutdown are implemented. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: Marcel Apfelbaum Cc: Michael S. Tsirkin Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov --- hw/misc/Makefile.objs | 1 + hw/misc/imx7_snvs.c | 83 + include/hw/misc/imx7_snvs.h | 35 +++ 3 files changed, 119 insertions(+) create mode 100644 hw/misc/imx7_snvs.c create mode 100644 include/hw/misc/imx7_snvs.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 4b2b705a6c..019886912c 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -35,6 +35,7 @@ obj-$(CONFIG_IMX) += imx6_ccm.o obj-$(CONFIG_IMX) += imx6_src.o obj-$(CONFIG_IMX) += imx7_ccm.o obj-$(CONFIG_IMX) += imx2_wdt.o +obj-$(CONFIG_IMX) += imx7_snvs.o obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o obj-$(CONFIG_MAINSTONE) += mst_fpga.o diff --git a/hw/misc/imx7_snvs.c b/hw/misc/imx7_snvs.c new file mode 100644 index 00..4df482b282 --- /dev/null +++ b/hw/misc/imx7_snvs.c @@ -0,0 +1,83 @@ +/* + * IMX7 Secure Non-Volatile Storage + * + * Copyright (c) 2018, Impinj, Inc. + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * Bare minimum emulation code needed to support being able to shut + * down linux guest gracefully. + */ + +#include "qemu/osdep.h" +#include "hw/misc/imx7_snvs.h" +#include "qemu/log.h" +#include "sysemu/sysemu.h" + +static uint64_t imx7_snvs_read(void *opaque, hwaddr offset, unsigned size) +{ +return 0; +} + +static void imx7_snvs_write(void *opaque, hwaddr offset, +uint64_t v, unsigned size) +{ +const uint32_t value = v; +const uint32_t mask = SNVS_LPCR_TOP | SNVS_LPCR_DP_EN; + +if (offset == SNVS_LPCR && ((value & mask) == mask)) { +qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); +} +} + +static const struct MemoryRegionOps imx7_snvs_ops = { +.read = imx7_snvs_read, +.write = imx7_snvs_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.impl = { +/* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ +.min_access_size = 4, +.max_access_size = 4, +.unaligned = false, +}, +}; + +static void imx7_snvs_init(Object *obj) +{ +SysBusDevice *sd = SYS_BUS_DEVICE(obj); +IMX7SNVSState *s = IMX7_SNVS(obj); + +memory_region_init_io(&s->mmio, obj, &imx7_snvs_ops, s, + TYPE_IMX7_SNVS, 0x1000); + +sysbus_init_mmio(sd, &s->mmio); +} + +static void imx7_snvs_class_init(ObjectClass *klass, void *data) +{ +DeviceClass *dc = DEVICE_CLASS(klass); + +dc->desc = "i.MX7 Secure Non-Volatile Storage Module"; +} + +static const TypeInfo imx7_snvs_info = { +.name = TYPE_IMX7_SNVS, +.parent= TYPE_SYS_BUS_DEVICE, +.instance_size = sizeof(IMX7SNVSState), +.instance_init = imx7_snvs_init, +.class_init= imx7_snvs_class_init, +}; + +static void imx7_snvs_register_type(void) +{ +type_register_static(&imx7_snvs_info); +} +type_init(imx7_snvs_register_type) diff --git a/include/hw/misc/imx7_snvs.h b/include/hw/misc/imx7_snvs.h new file mode 100644 index 00..255f8f26f9 --- /dev/null +++ b/include/hw/misc/imx7_snvs.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, Impinj, Inc. + * + * i.MX7 SNVS block emulation code + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef IMX7_SNVS_H +#define IMX7_SNVS_H + +#include "qemu/bitops.h" +#include "hw/sysbus.h" + + +enum IMX7SNVSRegisters { +SNVS_LPCR = 0x38, +SNVS_LPCR_TOP = BIT(6), +SNVS_LPCR_DP_EN = BIT(5) +}; + +#define TYPE_IMX7_SNVS "imx7.snvs" +#define IMX7_SNVS(obj) OBJECT_CHECK(IMX7SNVSState, (obj), TYPE_IMX7_SNVS) + +typedef struct IMX7SNVSState { +/* */ +SysBusDevice parent_obj; + +MemoryRegion mmio; +} IMX7SNVSState; + +#endif /* IMX7_SNVS_H */ -- 2.14.3
[Qemu-devel] [PATCH v5 11/14] usb: Add basic code to emulate Chipidea USB IP
Add code to emulate Chipidea USB IP (used in i.MX SoCs). Tested to work against: -usb -drive if=none,id=stick,file=usb.img,format=raw -device \ usb-storage,bus=usb-bus.0,drive=stick Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: Marcel Apfelbaum Cc: Michael S. Tsirkin Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org Cc: yurov...@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov --- hw/usb/Makefile.objs | 1 + hw/usb/chipidea.c | 176 ++ include/hw/usb/chipidea.h | 16 + 3 files changed, 193 insertions(+) create mode 100644 hw/usb/chipidea.c create mode 100644 include/hw/usb/chipidea.h diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index fbcd498c59..41be700812 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -12,6 +12,7 @@ common-obj-$(CONFIG_USB_XHCI_NEC) += hcd-xhci-nec.o common-obj-$(CONFIG_USB_MUSB) += hcd-musb.o obj-$(CONFIG_TUSB6010) += tusb6010.o +obj-$(CONFIG_IMX) += chipidea.o # emulated usb devices common-obj-$(CONFIG_USB) += dev-hub.o diff --git a/hw/usb/chipidea.c b/hw/usb/chipidea.c new file mode 100644 index 00..60d67f88b8 --- /dev/null +++ b/hw/usb/chipidea.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2018, Impinj, Inc. + * + * Chipidea USB block emulation code + * + * Author: Andrey Smirnov + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/usb/hcd-ehci.h" +#include "hw/usb/chipidea.h" +#include "qemu/log.h" + +enum { +CHIPIDEA_USBx_DCIVERSION = 0x000, +CHIPIDEA_USBx_DCCPARAMS= 0x004, +CHIPIDEA_USBx_DCCPARAMS_HC = BIT(8), +}; + +static uint64_t chipidea_read(void *opaque, hwaddr offset, + unsigned size) +{ +return 0; +} + +static void chipidea_write(void *opaque, hwaddr offset, +uint64_t value, unsigned size) +{ +} + +static const struct MemoryRegionOps chipidea_ops = { +.read = chipidea_read, +.write = chipidea_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.impl = { +/* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the + * real device but in practice there is no reason for a guest + * to access this device unaligned. + */ +.min_access_size = 4, +.max_access_size = 4, +.unaligned = false, +}, +}; + +static uint64_t chipidea_dc_read(void *opaque, hwaddr offset, + unsigned size) +{ +switch (offset) { +case CHIPIDEA_USBx_DCIVERSION: +return 0x1; +case CHIPIDEA_USBx_DCCPARAMS: +/* + * Real hardware (at least i.MX7) will also report the + * controller as "Device Capable" (and 8 supported endpoints), + * but there doesn't seem to be much point in doing so, since + * we don't emulate that part. + */ +return CHIPIDEA_USBx_DCCPARAMS_HC; +} + +return 0; +} + +static void chipidea_dc_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ +} + +static const struct MemoryRegionOps chipidea_dc_ops = { +.read = chipidea_dc_read, +.write = chipidea_dc_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.impl = { +/* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ +.min_access_size = 4, +.max_access_size = 4, +.unaligned = false, +}, +}; + +static void chipidea_init(Object *obj) +{ +EHCIState *ehci = &SYS_BUS_EHCI(obj)->ehci; +ChipideaState *ci = CHIPIDEA(obj); +int i; + +for (i = 0; i < ARRAY_SIZE(ci->iomem); i++) { +const struct { +const char *name; +hwaddr offset; +uint64_t size; +const struct MemoryRegionOps *ops; +} regions[ARRAY_SIZE(ci->iomem)] = { +/* + * Registers located between offsets 0x000 and 0xFC + */ +{ +.name = TYPE_CHIPIDEA ".misc", +.offset = 0x000, +.size = 0x100, +.ops= &chipidea_ops, +}, +/* + * Registers located between offsets 0x1A4 and 0x1DC + */ +{ +.name = TYPE_CHIPIDEA ".endpoints", +.offset = 0x1A4, +.size = 0x1DC - 0x1A4 + 4, +.ops= &chipidea_ops, +}, +/* + * USB_x_DCIV