* [Qemu-devel] [PATCH v6 1/6] ARM: Factor out ARM on/off PSCI control functions
2016-04-02 12:46 [Qemu-devel] [PATCH v6 0/6] Add i.MX6 (Single/Dual/Quad) support Jean-Christophe Dubois
@ 2016-04-02 12:46 ` Jean-Christophe Dubois
2016-04-02 12:46 ` [Qemu-devel] [PATCH v6 2/6] i.MX: Add i.MX6 System Reset Controller device Jean-Christophe Dubois
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Jean-Christophe Dubois @ 2016-04-02 12:46 UTC (permalink / raw)
To: qemu-devel, peter.maydell, crosthwaite.peter; +Cc: Jean-Christophe Dubois
Split ARM on/off function from PSCI support code.
This will allow to reuse these functions in other code.
Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
---
Changes since V1:
* Not present on V1
Changes since V2:
* Not present on V2
Changes since V3:
* Move to a more generic/usefull API
* Manage CPU level/mode change at startup
* Allow PSCI to cope with EL2/HYP level.
* Keep distinct errors for different causes.
Changes since V4:
* Rework documentation in header file.
* Rework exception level handling.
* Added a TODO for mode handling.
Changes since V5:
* Code reworked based on feedback
* Don't try to support AArch64 CPU booting to AArch32 for now.
target-arm/Makefile.objs | 1 +
target-arm/arm-powerctl.c | 224 ++++++++++++++++++++++++++++++++++++++++++++++
target-arm/arm-powerctl.h | 75 ++++++++++++++++
target-arm/psci.c | 70 ++-------------
4 files changed, 307 insertions(+), 63 deletions(-)
create mode 100644 target-arm/arm-powerctl.c
create mode 100644 target-arm/arm-powerctl.h
diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs
index a80eb39..60fd1dd 100644
--- a/target-arm/Makefile.objs
+++ b/target-arm/Makefile.objs
@@ -9,3 +9,4 @@ obj-y += neon_helper.o iwmmxt_helper.o
obj-y += gdbstub.o
obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o gdbstub64.o
obj-y += crypto_helper.o
+obj-y += arm-powerctl.o
diff --git a/target-arm/arm-powerctl.c b/target-arm/arm-powerctl.c
new file mode 100644
index 0000000..8840f87
--- /dev/null
+++ b/target-arm/arm-powerctl.c
@@ -0,0 +1,224 @@
+/*
+ * QEMU support -- ARM Power Control specific functions.
+ *
+ * Copyright (c) 2016 Jean-Christophe Dubois
+ *
+ * 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 <cpu.h>
+#include <cpu-qom.h>
+#include "internals.h"
+#include "arm-powerctl.h"
+
+#ifndef DEBUG_ARM_POWERCTL
+#define DEBUG_ARM_POWERCTL 0
+#endif
+
+#define DPRINTF(fmt, args...) \
+ do { \
+ if (DEBUG_ARM_POWERCTL) { \
+ fprintf(stderr, "[ARM]%s: " fmt , __func__, ##args); \
+ } \
+ } while (0)
+
+CPUState *arm_get_cpu_by_id(uint64_t id)
+{
+ CPUState *cpu;
+
+ DPRINTF("cpu %" PRId64 "\n", id);
+
+ CPU_FOREACH(cpu) {
+ ARMCPU *armcpu = ARM_CPU(cpu);
+
+ if (armcpu->mp_affinity == id) {
+ return cpu;
+ }
+ }
+
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "[ARM]%s: Requesting unknown CPU %" PRId64 "\n",
+ __func__, id);
+
+ return NULL;
+}
+
+int arm_set_cpu_on(uint64_t cpuid, uint64_t entry, uint64_t context_id,
+ uint32_t target_el, bool target_aa64)
+{
+ CPUState *target_cpu_state;
+ ARMCPU *target_cpu;
+
+ DPRINTF("cpu %" PRId64 " (EL %d, %s) @ 0x%" PRIx64 " with R0 = 0x%" PRIx64
+ "\n", cpuid, target_el, target_aa64 ? "aarch64" : "aarch32", entry,
+ context_id);
+
+ /* requested EL level need to be in the 1 to 3 range */
+ assert((target_el > 0) && (target_el < 4));
+
+ if (target_aa64 && (entry & 3)) {
+ /*
+ * if we are booting in AArch64 mode then "entry" needs to be 4 bytes
+ * aligned.
+ */
+ return QEMU_ARM_POWERCTL_INVALID_PARAM;
+ }
+
+ /* Retrieve the cpu we are powering up */
+ target_cpu_state = arm_get_cpu_by_id(cpuid);
+ if (!target_cpu_state) {
+ /* The cpu was not found */
+ return QEMU_ARM_POWERCTL_INVALID_PARAM;
+ }
+
+ target_cpu = ARM_CPU(target_cpu_state);
+ if (!target_cpu->powered_off) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "[ARM]%s: CPU %" PRId64 " is already on\n",
+ __func__, cpuid);
+ return QEMU_ARM_POWERCTL_ALREADY_ON;
+ }
+
+ /*
+ * The newly brought CPU is requested to enter the exception level
+ * "target_el" and be in the requested mode (AArch64 or AArch32).
+ */
+
+ if (((target_el == 3) && !arm_feature(&target_cpu->env, ARM_FEATURE_EL3)) ||
+ ((target_el == 2) && !arm_feature(&target_cpu->env, ARM_FEATURE_EL2))) {
+ /*
+ * The CPU does not support requested level
+ */
+ return QEMU_ARM_POWERCTL_INVALID_PARAM;
+ }
+
+ if (!target_aa64 && arm_feature(&target_cpu->env, ARM_FEATURE_AARCH64)) {
+ /*
+ * For now we don't support booting an AArch64 CPU in AArch32 mode
+ * TODO: We should add this support later
+ */
+ qemu_log_mask(LOG_UNIMP,
+ "[ARM]%s: Starting AArch64 CPU %" PRId64
+ " in AArch32 mode is not supported yet\n",
+ __func__, cpuid);
+ return QEMU_ARM_POWERCTL_INVALID_PARAM;
+ }
+
+ /* Initialize the cpu we are turning on */
+ cpu_reset(target_cpu_state);
+ target_cpu->powered_off = false;
+ target_cpu_state->halted = 0;
+
+ if (target_aa64) {
+ if ((target_el < 3) && arm_feature(&target_cpu->env, ARM_FEATURE_EL3)) {
+ /*
+ * As target mode is AArch64, we need to set lower
+ * exception level (the requested level 2) to AArch64
+ */
+ target_cpu->env.cp15.scr_el3 |= SCR_RW;
+ }
+
+ if ((target_el < 2) && arm_feature(&target_cpu->env, ARM_FEATURE_EL2)) {
+ /*
+ * As target mode is AArch64, we need to set lower
+ * exception level (the requested level 1) to AArch64
+ */
+ target_cpu->env.cp15.hcr_el2 |= HCR_RW;
+ }
+
+ target_cpu->env.pstate = aarch64_pstate_mode(target_el, true);
+ } else {
+ /* We are requested to boot in AArch32 mode */
+ static uint32_t mode_for_el[] = { 0,
+ ARM_CPU_MODE_SVC,
+ ARM_CPU_MODE_HYP,
+ ARM_CPU_MODE_SVC };
+
+ cpsr_write(&target_cpu->env, mode_for_el[target_el], CPSR_M,
+ CPSRWriteRaw);
+ }
+
+ if (target_el == 3) {
+ /* Processor is in secure mode */
+ target_cpu->env.cp15.scr_el3 &= ~SCR_NS;
+ } else {
+ /* Processor is not in secure mode */
+ target_cpu->env.cp15.scr_el3 |= SCR_NS;
+ }
+
+ /* We check if the started CPU is now at the correct level */
+ assert(target_el == arm_current_el(&target_cpu->env));
+
+ if (target_aa64) {
+ target_cpu->env.xregs[0] = context_id;
+ target_cpu->env.thumb = false;
+ } else {
+ target_cpu->env.regs[0] = context_id;
+ target_cpu->env.thumb = entry & 1;
+ entry &= 0xfffffffe;
+ }
+
+ /* Start the new CPU at the requested address */
+ cpu_set_pc(target_cpu_state, entry);
+
+ /* We are good to go */
+ return QEMU_ARM_POWERCTL_RET_SUCCESS;
+}
+
+int arm_set_cpu_off(uint64_t cpuid)
+{
+ CPUState *target_cpu_state;
+ ARMCPU *target_cpu;
+
+ DPRINTF("cpu %" PRId64 "\n", cpuid);
+
+ /* change to the cpu we are powering up */
+ target_cpu_state = arm_get_cpu_by_id(cpuid);
+ if (!target_cpu_state) {
+ return QEMU_ARM_POWERCTL_INVALID_PARAM;
+ }
+ target_cpu = ARM_CPU(target_cpu_state);
+ if (target_cpu->powered_off) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "[ARM]%s: CPU %" PRId64 " is already off\n",
+ __func__, cpuid);
+ return QEMU_ARM_POWERCTL_IS_OFF;
+ }
+
+ target_cpu->powered_off = true;
+ target_cpu_state->halted = 1;
+ target_cpu_state->exception_index = EXCP_HLT;
+ cpu_loop_exit(target_cpu_state);
+ /* notreached */
+
+ return QEMU_ARM_POWERCTL_RET_SUCCESS;
+}
+
+int arm_reset_cpu(uint64_t cpuid)
+{
+ CPUState *target_cpu_state;
+ ARMCPU *target_cpu;
+
+ DPRINTF("cpu %" PRId64 "\n", cpuid);
+
+ /* change to the cpu we are resetting */
+ target_cpu_state = arm_get_cpu_by_id(cpuid);
+ if (!target_cpu_state) {
+ return QEMU_ARM_POWERCTL_INVALID_PARAM;
+ }
+ target_cpu = ARM_CPU(target_cpu_state);
+ if (target_cpu->powered_off) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "[ARM]%s: CPU %" PRId64 " is off\n",
+ __func__, cpuid);
+ return QEMU_ARM_POWERCTL_IS_OFF;
+ }
+
+ /* Reset the cpu */
+ cpu_reset(target_cpu_state);
+
+ return QEMU_ARM_POWERCTL_RET_SUCCESS;
+}
diff --git a/target-arm/arm-powerctl.h b/target-arm/arm-powerctl.h
new file mode 100644
index 0000000..98ee049
--- /dev/null
+++ b/target-arm/arm-powerctl.h
@@ -0,0 +1,75 @@
+/*
+ * QEMU support -- ARM Power Control specific functions.
+ *
+ * Copyright (c) 2016 Jean-Christophe Dubois
+ *
+ * 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 QEMU_ARM_POWERCTL_H
+#define QEMU_ARM_POWERCTL_H
+
+#include "kvm-consts.h"
+
+#define QEMU_ARM_POWERCTL_RET_SUCCESS QEMU_PSCI_RET_SUCCESS
+#define QEMU_ARM_POWERCTL_INVALID_PARAM QEMU_PSCI_RET_INVALID_PARAMS
+#define QEMU_ARM_POWERCTL_ALREADY_ON QEMU_PSCI_RET_ALREADY_ON
+#define QEMU_ARM_POWERCTL_IS_OFF QEMU_PSCI_RET_DENIED
+
+/*
+ * arm_get_cpu_by_id:
+ * @cpuid: the id of the CPU we want to retrieve the state
+ *
+ * Retrieve a CPUState object from its CPU ID provided in @cpuid.
+ *
+ * Returns: a pointer to the CPUState structure of the requested CPU.
+ */
+CPUState *arm_get_cpu_by_id(uint64_t cpuid);
+
+/*
+ * arm_set_cpu_on:
+ * @cpuid: the id of the CPU we want to start/wake up.
+ * @entry: the address the CPU shall start from.
+ * @context_id: the value to put in r0/x0.
+ * @target_el: The desired exception level.
+ * @target_aa64: 1 if the requested mode is AArch64. 0 otherwise.
+ *
+ * Start the cpu designated by @cpuid in @target_el exception level. The mode
+ * shall be AArch64 if @target_aa64 is set to 1. Otherwise the mode is
+ * AArch32. The CPU shall start at @entry with @context_id in r0/x0.
+ *
+ * Returns: QEMU_ARM_POWERCTL_RET_SUCCESS on success.
+ * QEMU_ARM_POWERCTL_INVALID_PARAM if bad parameters are provided.
+ * QEMU_ARM_POWERCTL_ALREADY_ON if the CPU was already started.
+ */
+int arm_set_cpu_on(uint64_t cpuid, uint64_t entry, uint64_t context_id,
+ uint32_t target_el, bool target_aa64);
+
+/*
+ * arm_set_cpu_off:
+ * @cpuid: the id of the CPU we want to stop/shut down.
+ *
+ * Stop the cpu designated by @cpuid.
+ *
+ * Returns: QEMU_ARM_POWERCTL_RET_SUCCESS on success.
+ * QEMU_ARM_POWERCTL_INVALID_PARAM if bad parameters are provided.
+ * QEMU_ARM_POWERCTL_IS_OFF if CPU is already off
+ */
+
+int arm_set_cpu_off(uint64_t cpuid);
+
+/*
+ * arm_reset_cpu:
+ * @cpuid: the id of the CPU we want to reset.
+ *
+ * Reset the cpu designated by @cpuid.
+ *
+ * Returns: QEMU_ARM_POWERCTL_RET_SUCCESS on success.
+ * QEMU_ARM_POWERCTL_INVALID_PARAM if bad parameters are provided.
+ * QEMU_ARM_POWERCTL_IS_OFF if CPU is off
+ */
+int arm_reset_cpu(uint64_t cpuid);
+
+#endif
diff --git a/target-arm/psci.c b/target-arm/psci.c
index c55487f..ce2e0dc 100644
--- a/target-arm/psci.c
+++ b/target-arm/psci.c
@@ -22,6 +22,7 @@
#include <kvm-consts.h>
#include <sysemu/sysemu.h>
#include "internals.h"
+#include "arm-powerctl.h"
bool arm_is_psci_call(ARMCPU *cpu, int excp_type)
{
@@ -73,21 +74,6 @@ bool arm_is_psci_call(ARMCPU *cpu, int excp_type)
}
}
-static CPUState *get_cpu_by_id(uint64_t id)
-{
- CPUState *cpu;
-
- CPU_FOREACH(cpu) {
- ARMCPU *armcpu = ARM_CPU(cpu);
-
- if (armcpu->mp_affinity == id) {
- return cpu;
- }
- }
-
- return NULL;
-}
-
void arm_handle_psci_call(ARMCPU *cpu)
{
/*
@@ -98,7 +84,6 @@ void arm_handle_psci_call(ARMCPU *cpu)
* Additional information about the calling convention used is available in
* the document 'SMC Calling Convention' (ARM DEN 0028)
*/
- CPUState *cs = CPU(cpu);
CPUARMState *env = &cpu->env;
uint64_t param[4];
uint64_t context_id, mpidr;
@@ -123,7 +108,6 @@ void arm_handle_psci_call(ARMCPU *cpu)
switch (param[0]) {
CPUState *target_cpu_state;
ARMCPU *target_cpu;
- CPUClass *target_cpu_class;
case QEMU_PSCI_0_2_FN_PSCI_VERSION:
ret = QEMU_PSCI_0_2_RET_VERSION_0_2;
@@ -137,7 +121,7 @@ void arm_handle_psci_call(ARMCPU *cpu)
switch (param[2]) {
case 0:
- target_cpu_state = get_cpu_by_id(mpidr);
+ target_cpu_state = arm_get_cpu_by_id(mpidr);
if (!target_cpu_state) {
ret = QEMU_PSCI_RET_INVALID_PARAMS;
break;
@@ -167,52 +151,13 @@ void arm_handle_psci_call(ARMCPU *cpu)
mpidr = param[1];
entry = param[2];
context_id = param[3];
-
- /* change to the cpu we are powering up */
- target_cpu_state = get_cpu_by_id(mpidr);
- if (!target_cpu_state) {
- ret = QEMU_PSCI_RET_INVALID_PARAMS;
- break;
- }
- target_cpu = ARM_CPU(target_cpu_state);
- if (!target_cpu->powered_off) {
- ret = QEMU_PSCI_RET_ALREADY_ON;
- break;
- }
- target_cpu_class = CPU_GET_CLASS(target_cpu);
-
- /* Initialize the cpu we are turning on */
- cpu_reset(target_cpu_state);
- target_cpu->powered_off = false;
- target_cpu_state->halted = 0;
-
/*
* The PSCI spec mandates that newly brought up CPUs enter the
* exception level of the caller in the same execution mode as
* the caller, with context_id in x0/r0, respectively.
- *
- * For now, it is sufficient to assert() that CPUs come out of
- * reset in the same mode as the calling CPU, since we only
- * implement EL1, which means that
- * (a) there is no EL2 for the calling CPU to trap into to change
- * its state
- * (b) the newly brought up CPU enters EL1 immediately after coming
- * out of reset in the default state
*/
- assert(is_a64(env) == is_a64(&target_cpu->env));
- if (is_a64(env)) {
- if (entry & 1) {
- ret = QEMU_PSCI_RET_INVALID_PARAMS;
- break;
- }
- target_cpu->env.xregs[0] = context_id;
- } else {
- target_cpu->env.regs[0] = context_id;
- target_cpu->env.thumb = entry & 1;
- }
- target_cpu_class->set_pc(target_cpu_state, entry);
-
- ret = 0;
+ ret = arm_set_cpu_on(mpidr, entry, context_id, arm_current_el(env),
+ is_a64(env));
break;
case QEMU_PSCI_0_1_FN_CPU_OFF:
case QEMU_PSCI_0_2_FN_CPU_OFF:
@@ -250,9 +195,8 @@ err:
return;
cpu_off:
- cpu->powered_off = true;
- cs->halted = 1;
- cs->exception_index = EXCP_HLT;
- cpu_loop_exit(cs);
+ ret = arm_set_cpu_off(cpu->mp_affinity);
/* notreached */
+ /* sanity check in case something failed */
+ assert(ret == QEMU_ARM_POWERCTL_RET_SUCCESS);
}
--
2.5.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* [Qemu-devel] [PATCH v6 2/6] i.MX: Add i.MX6 System Reset Controller device.
2016-04-02 12:46 [Qemu-devel] [PATCH v6 0/6] Add i.MX6 (Single/Dual/Quad) support Jean-Christophe Dubois
2016-04-02 12:46 ` [Qemu-devel] [PATCH v6 1/6] ARM: Factor out ARM on/off PSCI control functions Jean-Christophe Dubois
@ 2016-04-02 12:46 ` Jean-Christophe Dubois
2016-04-02 12:46 ` [Qemu-devel] [PATCH v6 3/6] FIFO: Add a FIFO32 implementation Jean-Christophe Dubois
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Jean-Christophe Dubois @ 2016-04-02 12:46 UTC (permalink / raw)
To: qemu-devel, peter.maydell, crosthwaite.peter; +Cc: Jean-Christophe Dubois
This controller is also present in i.MX5X devices but they are not
yet emulated by QEMU.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
---
Changes since V1:
* Change "reset" sematic to mean full power cyvle.
Changes since V2:
* use arm-powerctl API
* Added #include "qemu/osdep.h"
Changes since V3:
* Minor fixes.
Changes since V4:
* None
Changes since V5:
* None
hw/misc/Makefile.objs | 1 +
hw/misc/imx6_src.c | 264 +++++++++++++++++++++++++++++++++++++++++++++
include/hw/misc/imx6_src.h | 73 +++++++++++++
3 files changed, 338 insertions(+)
create mode 100644 hw/misc/imx6_src.c
create mode 100644 include/hw/misc/imx6_src.h
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 44ac2e1..2562fa2 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -29,6 +29,7 @@ obj-$(CONFIG_IMX) += imx_ccm.o
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_MILKYMIST) += milkymist-hpdmc.o
obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
obj-$(CONFIG_MAINSTONE) += mst_fpga.o
diff --git a/hw/misc/imx6_src.c b/hw/misc/imx6_src.c
new file mode 100644
index 0000000..6b026b4
--- /dev/null
+++ b/hw/misc/imx6_src.c
@@ -0,0 +1,264 @@
+/*
+ * IMX6 System Reset Controller
+ *
+ * Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * 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/imx6_src.h"
+#include "sysemu/sysemu.h"
+#include "qemu/bitops.h"
+#include "arm-powerctl.h"
+
+#ifndef DEBUG_IMX6_SRC
+#define DEBUG_IMX6_SRC 0
+#endif
+
+#define DPRINTF(fmt, args...) \
+ do { \
+ if (DEBUG_IMX6_SRC) { \
+ fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX6_SRC, \
+ __func__, ##args); \
+ } \
+ } while (0)
+
+static char const *imx6_src_reg_name(uint32_t reg)
+{
+ static char unknown[20];
+
+ switch (reg) {
+ case SRC_SCR:
+ return "SRC_SCR";
+ case SRC_SBMR1:
+ return "SRC_SBMR1";
+ case SRC_SRSR:
+ return "SRC_SRSR";
+ case SRC_SISR:
+ return "SRC_SISR";
+ case SRC_SIMR:
+ return "SRC_SIMR";
+ case SRC_SBMR2:
+ return "SRC_SBMR2";
+ case SRC_GPR1:
+ return "SRC_GPR1";
+ case SRC_GPR2:
+ return "SRC_GPR2";
+ case SRC_GPR3:
+ return "SRC_GPR3";
+ case SRC_GPR4:
+ return "SRC_GPR4";
+ case SRC_GPR5:
+ return "SRC_GPR5";
+ case SRC_GPR6:
+ return "SRC_GPR6";
+ case SRC_GPR7:
+ return "SRC_GPR7";
+ case SRC_GPR8:
+ return "SRC_GPR8";
+ case SRC_GPR9:
+ return "SRC_GPR9";
+ case SRC_GPR10:
+ return "SRC_GPR10";
+ default:
+ sprintf(unknown, "%d ?", reg);
+ return unknown;
+ }
+}
+
+static const VMStateDescription vmstate_imx6_src = {
+ .name = TYPE_IMX6_SRC,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, IMX6SRCState, SRC_MAX),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void imx6_src_reset(DeviceState *dev)
+{
+ IMX6SRCState *s = IMX6_SRC(dev);
+
+ DPRINTF("\n");
+
+ memset(s->regs, 0, sizeof(s->regs));
+
+ /* Set reset values */
+ s->regs[SRC_SCR] = 0x521;
+ s->regs[SRC_SRSR] = 0x1;
+ s->regs[SRC_SIMR] = 0x1F;
+}
+
+static uint64_t imx6_src_read(void *opaque, hwaddr offset, unsigned size)
+{
+ uint32_t value = 0;
+ IMX6SRCState *s = (IMX6SRCState *)opaque;
+ uint32_t index = offset >> 2;
+
+ if (index < SRC_MAX) {
+ value = s->regs[index];
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
+ HWADDR_PRIx "\n", TYPE_IMX6_SRC, __func__, offset);
+
+ }
+
+ DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx6_src_reg_name(index), value);
+
+ return value;
+}
+
+static void imx6_src_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ IMX6SRCState *s = (IMX6SRCState *)opaque;
+ uint32_t index = offset >> 2;
+ unsigned long change_mask;
+ unsigned long current_value = value;
+
+ if (index >= SRC_MAX) {
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
+ HWADDR_PRIx "\n", TYPE_IMX6_SRC, __func__, offset);
+ return;
+ }
+
+ DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx6_src_reg_name(index),
+ (uint32_t)current_value);
+
+ change_mask = s->regs[index] ^ (uint32_t)current_value;
+
+ switch (index) {
+ case SRC_SCR:
+ /*
+ * On real hardware when the system reset controller starts a
+ * secondary CPU it runs through some boot ROM code which reads
+ * the SRC_GPRX registers controlling the start address and branches
+ * to it.
+ * Here we are taking a short cut and branching directly to the
+ * requested address (we don't want to run the boot ROM code inside
+ * QEMU)
+ */
+ if (EXTRACT(change_mask, CORE3_ENABLE)) {
+ if (EXTRACT(current_value, CORE3_ENABLE)) {
+ /* CORE 3 is brought up */
+ arm_set_cpu_on(3, s->regs[SRC_GPR7], s->regs[SRC_GPR8],
+ 3, false);
+ } else {
+ /* CORE 3 is shut down */
+ arm_set_cpu_off(3);
+ }
+ /* We clear the reset bits as the processor changed state */
+ clear_bit(CORE3_RST_SHIFT, ¤t_value);
+ clear_bit(CORE3_RST_SHIFT, &change_mask);
+ }
+ if (EXTRACT(change_mask, CORE2_ENABLE)) {
+ if (EXTRACT(current_value, CORE2_ENABLE)) {
+ /* CORE 2 is brought up */
+ arm_set_cpu_on(2, s->regs[SRC_GPR5], s->regs[SRC_GPR6],
+ 3, false);
+ } else {
+ /* CORE 3 is shut down */
+ arm_set_cpu_off(2);
+ }
+ /* We clear the reset bits as the processor changed state */
+ clear_bit(CORE2_RST_SHIFT, ¤t_value);
+ clear_bit(CORE2_RST_SHIFT, &change_mask);
+ }
+ if (EXTRACT(change_mask, CORE1_ENABLE)) {
+ if (EXTRACT(current_value, CORE1_ENABLE)) {
+ /* CORE 1 is brought up */
+ arm_set_cpu_on(1, s->regs[SRC_GPR3], s->regs[SRC_GPR4],
+ 3, false);
+ } else {
+ /* CORE 3 is shut down */
+ arm_set_cpu_off(1);
+ }
+ /* We clear the reset bits as the processor changed state */
+ clear_bit(CORE1_RST_SHIFT, ¤t_value);
+ clear_bit(CORE1_RST_SHIFT, &change_mask);
+ }
+ if (EXTRACT(change_mask, CORE0_RST)) {
+ arm_reset_cpu(0);
+ clear_bit(CORE0_RST_SHIFT, ¤t_value);
+ }
+ if (EXTRACT(change_mask, CORE1_RST)) {
+ arm_reset_cpu(1);
+ clear_bit(CORE1_RST_SHIFT, ¤t_value);
+ }
+ if (EXTRACT(change_mask, CORE2_RST)) {
+ arm_reset_cpu(2);
+ clear_bit(CORE2_RST_SHIFT, ¤t_value);
+ }
+ if (EXTRACT(change_mask, CORE3_RST)) {
+ arm_reset_cpu(3);
+ clear_bit(CORE3_RST_SHIFT, ¤t_value);
+ }
+ if (EXTRACT(change_mask, SW_IPU2_RST)) {
+ /* We pretend the IPU2 is reset */
+ clear_bit(SW_IPU2_RST_SHIFT, ¤t_value);
+ }
+ if (EXTRACT(change_mask, SW_IPU1_RST)) {
+ /* We pretend the IPU1 is reset */
+ clear_bit(SW_IPU1_RST_SHIFT, ¤t_value);
+ }
+ s->regs[index] = current_value;
+ break;
+ default:
+ s->regs[index] = current_value;
+ break;
+ }
+}
+
+static const struct MemoryRegionOps imx6_src_ops = {
+ .read = imx6_src_read,
+ .write = imx6_src_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 imx6_src_realize(DeviceState *dev, Error **errp)
+{
+ IMX6SRCState *s = IMX6_SRC(dev);
+
+ memory_region_init_io(&s->iomem, OBJECT(dev), &imx6_src_ops, s,
+ TYPE_IMX6_SRC, 0x1000);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+}
+
+static void imx6_src_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = imx6_src_realize;
+ dc->reset = imx6_src_reset;
+ dc->vmsd = &vmstate_imx6_src;
+ dc->desc = "i.MX6 System Reset Controller";
+}
+
+static const TypeInfo imx6_src_info = {
+ .name = TYPE_IMX6_SRC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IMX6SRCState),
+ .class_init = imx6_src_class_init,
+};
+
+static void imx6_src_register_types(void)
+{
+ type_register_static(&imx6_src_info);
+}
+
+type_init(imx6_src_register_types)
diff --git a/include/hw/misc/imx6_src.h b/include/hw/misc/imx6_src.h
new file mode 100644
index 0000000..eb36407
--- /dev/null
+++ b/include/hw/misc/imx6_src.h
@@ -0,0 +1,73 @@
+/*
+ * IMX6 System Reset Controller
+ *
+ * Copyright (C) 2012 NICTA
+ * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * 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 IMX6_SRC_H
+#define IMX6_SRC_H
+
+#include "hw/sysbus.h"
+#include "qemu/bitops.h"
+
+#define SRC_SCR 0
+#define SRC_SBMR1 1
+#define SRC_SRSR 2
+#define SRC_SISR 5
+#define SRC_SIMR 6
+#define SRC_SBMR2 7
+#define SRC_GPR1 8
+#define SRC_GPR2 9
+#define SRC_GPR3 10
+#define SRC_GPR4 11
+#define SRC_GPR5 12
+#define SRC_GPR6 13
+#define SRC_GPR7 14
+#define SRC_GPR8 15
+#define SRC_GPR9 16
+#define SRC_GPR10 17
+#define SRC_MAX 18
+
+/* SRC_SCR */
+#define CORE3_ENABLE_SHIFT 24
+#define CORE3_ENABLE_LENGTH 1
+#define CORE2_ENABLE_SHIFT 23
+#define CORE2_ENABLE_LENGTH 1
+#define CORE1_ENABLE_SHIFT 22
+#define CORE1_ENABLE_LENGTH 1
+#define CORE3_RST_SHIFT 16
+#define CORE3_RST_LENGTH 1
+#define CORE2_RST_SHIFT 15
+#define CORE2_RST_LENGTH 1
+#define CORE1_RST_SHIFT 14
+#define CORE1_RST_LENGTH 1
+#define CORE0_RST_SHIFT 13
+#define CORE0_RST_LENGTH 1
+#define SW_IPU1_RST_SHIFT 3
+#define SW_IPU1_RST_LENGTH 1
+#define SW_IPU2_RST_SHIFT 12
+#define SW_IPU2_RST_LENGTH 1
+#define WARM_RST_ENABLE_SHIFT 0
+#define WARM_RST_ENABLE_LENGTH 1
+
+#define EXTRACT(value, name) extract32(value, name##_SHIFT, name##_LENGTH)
+
+#define TYPE_IMX6_SRC "imx6.src"
+#define IMX6_SRC(obj) OBJECT_CHECK(IMX6SRCState, (obj), TYPE_IMX6_SRC)
+
+typedef struct IMX6SRCState {
+ /* <private> */
+ SysBusDevice parent_obj;
+
+ /* <public> */
+ MemoryRegion iomem;
+
+ uint32_t regs[SRC_MAX];
+
+} IMX6SRCState;
+
+#endif /* IMX6_SRC_H */
--
2.5.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* [Qemu-devel] [PATCH v6 3/6] FIFO: Add a FIFO32 implementation
2016-04-02 12:46 [Qemu-devel] [PATCH v6 0/6] Add i.MX6 (Single/Dual/Quad) support Jean-Christophe Dubois
2016-04-02 12:46 ` [Qemu-devel] [PATCH v6 1/6] ARM: Factor out ARM on/off PSCI control functions Jean-Christophe Dubois
2016-04-02 12:46 ` [Qemu-devel] [PATCH v6 2/6] i.MX: Add i.MX6 System Reset Controller device Jean-Christophe Dubois
@ 2016-04-02 12:46 ` Jean-Christophe Dubois
2016-04-02 12:46 ` [Qemu-devel] [PATCH v6 4/6] i.MX: Add the Freescale SPI Controller Jean-Christophe Dubois
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Jean-Christophe Dubois @ 2016-04-02 12:46 UTC (permalink / raw)
To: qemu-devel, peter.maydell, crosthwaite.peter; +Cc: Jean-Christophe Dubois
This one is build on top of the existing FIFO8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
---
Changes since V1:
* None
Changes since V2:
* Added copyright
* define Fifo32 as a struct containing Fifo8
* remove fifo32_pop_buf()
Changes since V3:
* Added comment on unsupported fifo32_pop_buf()
Changes since V4:
* None
Changes since V5:
* None
include/qemu/fifo32.h | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 191 insertions(+)
create mode 100644 include/qemu/fifo32.h
diff --git a/include/qemu/fifo32.h b/include/qemu/fifo32.h
new file mode 100644
index 0000000..2e5a0cc
--- /dev/null
+++ b/include/qemu/fifo32.h
@@ -0,0 +1,191 @@
+/*
+ * Generic FIFO32 component, based on FIFO8.
+ *
+ * Copyright (c) 2016 Jean-Christophe Dubois
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FIFO32_H
+#define FIFO32_H
+
+#include "qemu/osdep.h"
+#include "qemu/fifo8.h"
+
+typedef struct {
+ Fifo8 fifo;
+} Fifo32;
+
+/**
+ * fifo32_create:
+ * @fifo: struct Fifo32 to initialise with new FIFO
+ * @capacity: capacity of the newly created FIFO expressed in 32 bit words
+ *
+ * Create a FIFO of the specified size. Clients should call fifo32_destroy()
+ * when finished using the fifo. The FIFO is initially empty.
+ */
+
+static inline void fifo32_create(Fifo32 *fifo, uint32_t capacity)
+{
+ fifo8_create(&fifo->fifo, capacity * sizeof(uint32_t));
+}
+
+/**
+ * fifo32_destroy:
+ * @fifo: FIFO to cleanup
+ *
+ * Cleanup a FIFO created with fifo32_create(). Frees memory created for FIFO
+ * storage. The FIFO is no longer usable after this has been called.
+ */
+
+static inline void fifo32_destroy(Fifo32 *fifo)
+{
+ fifo8_destroy(&fifo->fifo);
+}
+
+/**
+ * fifo32_num_free:
+ * @fifo: FIFO to check
+ *
+ * Return the number of free uint32_t slots in the FIFO.
+ *
+ * Returns: Number of free 32 bit words.
+ */
+
+static inline uint32_t fifo32_num_free(Fifo32 *fifo)
+{
+ return DIV_ROUND_UP(fifo8_num_free(&fifo->fifo), sizeof(uint32_t));
+}
+
+/**
+ * fifo32_num_used:
+ * @fifo: FIFO to check
+ *
+ * Return the number of used uint32_t slots in the FIFO.
+ *
+ * Returns: Number of used 32 bit words.
+ */
+
+static inline uint32_t fifo32_num_used(Fifo32 *fifo)
+{
+ return DIV_ROUND_UP(fifo8_num_used(&fifo->fifo), sizeof(uint32_t));
+}
+
+/**
+ * fifo32_push:
+ * @fifo: FIFO to push to
+ * @data: 32 bits data word to push
+ *
+ * Push a 32 bits data word to the FIFO. Behaviour is undefined if the FIFO
+ * is full. Clients are responsible for checking for fullness using
+ * fifo32_is_full().
+ */
+
+static inline void fifo32_push(Fifo32 *fifo, uint32_t data)
+{
+ int i;
+
+ for (i = 0; i < sizeof(data); i++) {
+ fifo8_push(&fifo->fifo, data & 0xff);
+ data >>= 8;
+ }
+}
+
+/**
+ * fifo32_push_all:
+ * @fifo: FIFO to push to
+ * @data: data to push
+ * @size: number of 32 bit words to push
+ *
+ * Push a 32 bit word array to the FIFO. Behaviour is undefined if the FIFO
+ * is full. Clients are responsible for checking the space left in the FIFO
+ * using fifo32_num_free().
+ */
+
+static inline void fifo32_push_all(Fifo32 *fifo, const uint32_t *data,
+ uint32_t num)
+{
+ int i;
+
+ for (i = 0; i < num; i++) {
+ fifo32_push(fifo, data[i]);
+ }
+}
+
+/**
+ * fifo32_pop:
+ * @fifo: fifo to pop from
+ *
+ * Pop a 32 bits data word from the FIFO. Behaviour is undefined if the FIFO
+ * is empty. Clients are responsible for checking for emptiness using
+ * fifo32_is_empty().
+ *
+ * Returns: The popped 32 bits data word.
+ */
+
+static inline uint32_t fifo32_pop(Fifo32 *fifo)
+{
+ uint32_t ret = 0;
+ int i;
+
+ for (i = 0; i < sizeof(uint32_t); i++) {
+ ret |= (fifo8_pop(&fifo->fifo) << (i * 8));
+ }
+
+ return ret;
+}
+
+/**
+ * There is no fifo32_pop_buf() because the data is not stored in the buffer
+ * as a set of native-order words.
+ */
+
+/**
+ * fifo32_reset:
+ * @fifo: FIFO to reset
+ *
+ * Reset a FIFO. All data is discarded and the FIFO is emptied.
+ */
+
+static inline void fifo32_reset(Fifo32 *fifo)
+{
+ fifo8_reset(&fifo->fifo);
+}
+
+/**
+ * fifo32_is_empty:
+ * @fifo: FIFO to check
+ *
+ * Check if a FIFO is empty.
+ *
+ * Returns: True if the fifo is empty, false otherwise.
+ */
+
+static inline bool fifo32_is_empty(Fifo32 *fifo)
+{
+ return fifo8_is_empty(&fifo->fifo);
+}
+
+/**
+ * fifo32_is_full:
+ * @fifo: FIFO to check
+ *
+ * Check if a FIFO is full.
+ *
+ * Returns: True if the fifo is full, false otherwise.
+ */
+
+static inline bool fifo32_is_full(Fifo32 *fifo)
+{
+ return fifo8_num_free(&fifo->fifo) < sizeof(uint32_t);
+}
+
+#define VMSTATE_FIFO32(_field, _state) VMSTATE_FIFO8(_field.fifo, _state)
+
+#endif /* FIFO32_H */
--
2.5.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* [Qemu-devel] [PATCH v6 4/6] i.MX: Add the Freescale SPI Controller
2016-04-02 12:46 [Qemu-devel] [PATCH v6 0/6] Add i.MX6 (Single/Dual/Quad) support Jean-Christophe Dubois
` (2 preceding siblings ...)
2016-04-02 12:46 ` [Qemu-devel] [PATCH v6 3/6] FIFO: Add a FIFO32 implementation Jean-Christophe Dubois
@ 2016-04-02 12:46 ` Jean-Christophe Dubois
2016-04-02 12:46 ` [Qemu-devel] [PATCH v6 5/6] i.MX: Add i.MX6 SOC implementation Jean-Christophe Dubois
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Jean-Christophe Dubois @ 2016-04-02 12:46 UTC (permalink / raw)
To: qemu-devel, peter.maydell, crosthwaite.peter; +Cc: Jean-Christophe Dubois
Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
---
Changes since V1:
* Access SPI slave only at a byte level.
* rework the CS activation to avoid to reset access to SPI slaves.
Changes since V2:
* Added #include "qemu/osdep.h"
* remove previous_level from state struct
* save burst_length in VMSTATE
Changes since V3:
* Don't call qemu_set_irq() in reset function
Changes since V4:
* None
Changes since V5:
* None
hw/ssi/Makefile.objs | 1 +
hw/ssi/imx_spi.c | 454 +++++++++++++++++++++++++++++++++++++++++++++++
include/hw/ssi/imx_spi.h | 103 +++++++++++
3 files changed, 558 insertions(+)
create mode 100644 hw/ssi/imx_spi.c
create mode 100644 include/hw/ssi/imx_spi.h
diff --git a/hw/ssi/Makefile.objs b/hw/ssi/Makefile.objs
index 9555825..fcbb79e 100644
--- a/hw/ssi/Makefile.objs
+++ b/hw/ssi/Makefile.objs
@@ -4,3 +4,4 @@ common-obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
common-obj-$(CONFIG_XILINX_SPIPS) += xilinx_spips.o
obj-$(CONFIG_OMAP) += omap_spi.o
+obj-$(CONFIG_IMX) += imx_spi.o
diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
new file mode 100644
index 0000000..d5dd42a
--- /dev/null
+++ b/hw/ssi/imx_spi.c
@@ -0,0 +1,454 @@
+/*
+ * IMX SPI Controller
+ *
+ * Copyright (c) 2016 Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * 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/ssi/imx_spi.h"
+#include "sysemu/sysemu.h"
+
+#ifndef DEBUG_IMX_SPI
+#define DEBUG_IMX_SPI 0
+#endif
+
+#define DPRINTF(fmt, args...) \
+ do { \
+ if (DEBUG_IMX_SPI) { \
+ fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_SPI, \
+ __func__, ##args); \
+ } \
+ } while (0)
+
+static char const *imx_spi_reg_name(uint32_t reg)
+{
+ static char unknown[20];
+
+ switch (reg) {
+ case ECSPI_RXDATA:
+ return "ECSPI_RXDATA";
+ case ECSPI_TXDATA:
+ return "ECSPI_TXDATA";
+ case ECSPI_CONREG:
+ return "ECSPI_CONREG";
+ case ECSPI_CONFIGREG:
+ return "ECSPI_CONFIGREG";
+ case ECSPI_INTREG:
+ return "ECSPI_INTREG";
+ case ECSPI_DMAREG:
+ return "ECSPI_DMAREG";
+ case ECSPI_STATREG:
+ return "ECSPI_STATREG";
+ case ECSPI_PERIODREG:
+ return "ECSPI_PERIODREG";
+ case ECSPI_TESTREG:
+ return "ECSPI_TESTREG";
+ case ECSPI_MSGDATA:
+ return "ECSPI_MSGDATA";
+ default:
+ sprintf(unknown, "%d ?", reg);
+ return unknown;
+ }
+}
+
+static const VMStateDescription vmstate_imx_spi = {
+ .name = TYPE_IMX_SPI,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_FIFO32(tx_fifo, IMXSPIState),
+ VMSTATE_FIFO32(rx_fifo, IMXSPIState),
+ VMSTATE_INT16(burst_length, IMXSPIState),
+ VMSTATE_UINT32_ARRAY(regs, IMXSPIState, ECSPI_MAX),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void imx_spi_txfifo_reset(IMXSPIState *s)
+{
+ fifo32_reset(&s->tx_fifo);
+ s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TE;
+ s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_TF;
+}
+
+static void imx_spi_rxfifo_reset(IMXSPIState *s)
+{
+ fifo32_reset(&s->rx_fifo);
+ s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_RR;
+ s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_RF;
+ s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_RO;
+}
+
+static void imx_spi_update_irq(IMXSPIState *s)
+{
+ int level;
+
+ if (fifo32_is_empty(&s->rx_fifo)) {
+ s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_RR;
+ } else {
+ s->regs[ECSPI_STATREG] |= ECSPI_STATREG_RR;
+ }
+
+ if (fifo32_is_full(&s->rx_fifo)) {
+ s->regs[ECSPI_STATREG] |= ECSPI_STATREG_RF;
+ } else {
+ s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_RF;
+ }
+
+ if (fifo32_is_empty(&s->tx_fifo)) {
+ s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TE;
+ } else {
+ s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_TE;
+ }
+
+ if (fifo32_is_full(&s->tx_fifo)) {
+ s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TF;
+ } else {
+ s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_TF;
+ }
+
+ level = s->regs[ECSPI_STATREG] & s->regs[ECSPI_INTREG] ? 1 : 0;
+
+ qemu_set_irq(s->irq, level);
+
+ DPRINTF("IRQ level is %d\n", level);
+}
+
+static uint8_t imx_spi_selected_channel(IMXSPIState *s)
+{
+ return EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_CHANNEL_SELECT);
+}
+
+static uint32_t imx_spi_burst_length(IMXSPIState *s)
+{
+ return EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
+}
+
+static bool imx_spi_is_enabled(IMXSPIState *s)
+{
+ return s->regs[ECSPI_CONREG] & ECSPI_CONREG_EN;
+}
+
+static bool imx_spi_channel_is_master(IMXSPIState *s)
+{
+ uint8_t mode = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_CHANNEL_MODE);
+
+ return (mode & (1 << imx_spi_selected_channel(s))) ? true : false;
+}
+
+static bool imx_spi_is_multiple_master_burst(IMXSPIState *s)
+{
+ uint8_t wave = EXTRACT(s->regs[ECSPI_CONFIGREG], ECSPI_CONFIGREG_SS_CTL);
+
+ return imx_spi_channel_is_master(s) &&
+ !(s->regs[ECSPI_CONREG] & ECSPI_CONREG_SMC) &&
+ ((wave & (1 << imx_spi_selected_channel(s))) ? true : false);
+}
+
+static void imx_spi_flush_txfifo(IMXSPIState *s)
+{
+ uint32_t tx;
+ uint32_t rx;
+
+ DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n",
+ fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
+
+ while (!fifo32_is_empty(&s->tx_fifo)) {
+ int tx_burst = 0;
+ int index = 0;
+
+ if (s->burst_length <= 0) {
+ s->burst_length = imx_spi_burst_length(s);
+
+ DPRINTF("Burst length = %d\n", s->burst_length);
+
+ if (imx_spi_is_multiple_master_burst(s)) {
+ s->regs[ECSPI_CONREG] |= ECSPI_CONREG_XCH;
+ }
+ }
+
+ tx = fifo32_pop(&s->tx_fifo);
+
+ DPRINTF("data tx:0x%08x\n", tx);
+
+ tx_burst = MIN(s->burst_length, 32);
+
+ rx = 0;
+
+ while (tx_burst) {
+ uint8_t byte = tx & 0xff;
+
+ DPRINTF("writing 0x%02x\n", (uint32_t)byte);
+
+ /* We need to write one byte at a time */
+ byte = ssi_transfer(s->bus, byte);
+
+ DPRINTF("0x%02x read\n", (uint32_t)byte);
+
+ tx = tx >> 8;
+ rx |= (byte << (index * 8));
+
+ /* Remove 8 bits from the actual burst */
+ tx_burst -= 8;
+ s->burst_length -= 8;
+ index++;
+ }
+
+ DPRINTF("data rx:0x%08x\n", rx);
+
+ if (fifo32_is_full(&s->rx_fifo)) {
+ s->regs[ECSPI_STATREG] |= ECSPI_STATREG_RO;
+ } else {
+ fifo32_push(&s->rx_fifo, (uint8_t)rx);
+ }
+
+ if (s->burst_length <= 0) {
+ s->regs[ECSPI_CONREG] &= ~ECSPI_CONREG_XCH;
+
+ if (!imx_spi_is_multiple_master_burst(s)) {
+ s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TC;
+ break;
+ }
+ }
+ }
+
+ if (fifo32_is_empty(&s->tx_fifo)) {
+ s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TC;
+ }
+
+ /* TODO: We should also use TDR and RDR bits */
+
+ DPRINTF("End: TX Fifo Size = %d, RX Fifo Size = %d\n",
+ fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
+}
+
+static void imx_spi_reset(DeviceState *dev)
+{
+ IMXSPIState *s = IMX_SPI(dev);
+
+ DPRINTF("\n");
+
+ memset(s->regs, 0, sizeof(s->regs));
+
+ s->regs[ECSPI_STATREG] = 0x00000003;
+
+ imx_spi_rxfifo_reset(s);
+ imx_spi_txfifo_reset(s);
+
+ imx_spi_update_irq(s);
+
+ s->burst_length = 0;
+}
+
+static uint64_t imx_spi_read(void *opaque, hwaddr offset, unsigned size)
+{
+ uint32_t value = 0;
+ IMXSPIState *s = opaque;
+ uint32_t index = offset >> 2;
+
+ if (index >= ECSPI_MAX) {
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
+ HWADDR_PRIx "\n", TYPE_IMX_SPI, __func__, offset);
+ return 0;
+ }
+
+ switch (index) {
+ case ECSPI_RXDATA:
+ if (!imx_spi_is_enabled(s)) {
+ value = 0;
+ } else if (fifo32_is_empty(&s->rx_fifo)) {
+ /* value is undefined */
+ value = 0xdeadbeef;
+ } else {
+ /* read from the RX FIFO */
+ value = fifo32_pop(&s->rx_fifo);
+ }
+
+ break;
+ case ECSPI_TXDATA:
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read from TX FIFO\n",
+ TYPE_IMX_SPI, __func__);
+
+ /* Reading from TXDATA gives 0 */
+
+ break;
+ case ECSPI_MSGDATA:
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read from MSG FIFO\n",
+ TYPE_IMX_SPI, __func__);
+
+ /* Reading from MSGDATA gives 0 */
+
+ break;
+ default:
+ value = s->regs[index];
+ break;
+ }
+
+ DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx_spi_reg_name(index), value);
+
+ imx_spi_update_irq(s);
+
+ return (uint64_t)value;
+}
+
+static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ IMXSPIState *s = opaque;
+ uint32_t index = offset >> 2;
+ uint32_t change_mask;
+
+ if (index >= ECSPI_MAX) {
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
+ HWADDR_PRIx "\n", TYPE_IMX_SPI, __func__, offset);
+ return;
+ }
+
+ DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx_spi_reg_name(index),
+ (uint32_t)value);
+
+ change_mask = s->regs[index] ^ value;
+
+ switch (index) {
+ case ECSPI_RXDATA:
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to write to RX FIFO\n",
+ TYPE_IMX_SPI, __func__);
+ break;
+ case ECSPI_TXDATA:
+ case ECSPI_MSGDATA:
+ /* Is there any difference between TXDATA and MSGDATA ? */
+ /* I'll have to look in the linux driver */
+ if (!imx_spi_is_enabled(s)) {
+ /* Ignore writes if device is disabled */
+ break;
+ } else if (fifo32_is_full(&s->tx_fifo)) {
+ /* Ignore writes if queue is full */
+ break;
+ }
+
+ fifo32_push(&s->tx_fifo, (uint32_t)value);
+
+ if (imx_spi_channel_is_master(s) &&
+ (s->regs[ECSPI_CONREG] & ECSPI_CONREG_SMC)) {
+ /*
+ * Start emitting if current channel is master and SMC bit is
+ * set.
+ */
+ imx_spi_flush_txfifo(s);
+ }
+
+ break;
+ case ECSPI_STATREG:
+ /* the RO and TC bits are write-one-to-clear */
+ value &= ECSPI_STATREG_RO | ECSPI_STATREG_TC;
+ s->regs[ECSPI_STATREG] &= ~value;
+
+ break;
+ case ECSPI_CONREG:
+ s->regs[ECSPI_CONREG] = value;
+
+ if (!imx_spi_is_enabled(s)) {
+ /* device is disabled, so this is a reset */
+ imx_spi_reset(DEVICE(s));
+ return;
+ }
+
+ if (imx_spi_channel_is_master(s)) {
+ int i;
+
+ /* We are in master mode */
+
+ for (i = 0; i < 4; i++) {
+ qemu_set_irq(s->cs_lines[i],
+ i == imx_spi_selected_channel(s) ? 0 : 1);
+ }
+
+ if ((value & change_mask & ECSPI_CONREG_SMC) &&
+ !fifo32_is_empty(&s->tx_fifo)) {
+ /* SMC bit is set and TX FIFO has some slots filled in */
+ imx_spi_flush_txfifo(s);
+ } else if ((value & change_mask & ECSPI_CONREG_XCH) &&
+ !(value & ECSPI_CONREG_SMC)) {
+ /* This is a request to start emitting */
+ imx_spi_flush_txfifo(s);
+ }
+ }
+
+ break;
+ default:
+ s->regs[index] = value;
+
+ break;
+ }
+
+ imx_spi_update_irq(s);
+}
+
+static const struct MemoryRegionOps imx_spi_ops = {
+ .read = imx_spi_read,
+ .write = imx_spi_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 imx_spi_realize(DeviceState *dev, Error **errp)
+{
+ IMXSPIState *s = IMX_SPI(dev);
+ int i;
+
+ s->bus = ssi_create_bus(dev, "spi");
+
+ memory_region_init_io(&s->iomem, OBJECT(dev), &imx_spi_ops, s,
+ TYPE_IMX_SPI, 0x1000);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
+
+ ssi_auto_connect_slaves(dev, s->cs_lines, s->bus);
+
+ for (i = 0; i < 4; ++i) {
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->cs_lines[i]);
+ }
+
+ s->burst_length = 0;
+
+ fifo32_create(&s->tx_fifo, ECSPI_FIFO_SIZE);
+ fifo32_create(&s->rx_fifo, ECSPI_FIFO_SIZE);
+}
+
+static void imx_spi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = imx_spi_realize;
+ dc->vmsd = &vmstate_imx_spi;
+ dc->reset = imx_spi_reset;
+ dc->desc = "i.MX SPI Controller";
+}
+
+static const TypeInfo imx_spi_info = {
+ .name = TYPE_IMX_SPI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IMXSPIState),
+ .class_init = imx_spi_class_init,
+};
+
+static void imx_spi_register_types(void)
+{
+ type_register_static(&imx_spi_info);
+}
+
+type_init(imx_spi_register_types)
diff --git a/include/hw/ssi/imx_spi.h b/include/hw/ssi/imx_spi.h
new file mode 100644
index 0000000..7103953
--- /dev/null
+++ b/include/hw/ssi/imx_spi.h
@@ -0,0 +1,103 @@
+/*
+ * IMX SPI Controller
+ *
+ * Copyright 2016 Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * 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 IMX_SPI_H
+#define IMX_SPI_H
+
+#include "hw/sysbus.h"
+#include "hw/ssi/ssi.h"
+#include "qemu/bitops.h"
+#include "qemu/fifo32.h"
+
+#define ECSPI_FIFO_SIZE 64
+
+#define ECSPI_RXDATA 0
+#define ECSPI_TXDATA 1
+#define ECSPI_CONREG 2
+#define ECSPI_CONFIGREG 3
+#define ECSPI_INTREG 4
+#define ECSPI_DMAREG 5
+#define ECSPI_STATREG 6
+#define ECSPI_PERIODREG 7
+#define ECSPI_TESTREG 8
+#define ECSPI_MSGDATA 16
+#define ECSPI_MAX 17
+
+/* ECSPI_CONREG */
+#define ECSPI_CONREG_EN (1 << 0)
+#define ECSPI_CONREG_HT (1 << 1)
+#define ECSPI_CONREG_XCH (1 << 2)
+#define ECSPI_CONREG_SMC (1 << 3)
+#define ECSPI_CONREG_CHANNEL_MODE_SHIFT 4
+#define ECSPI_CONREG_CHANNEL_MODE_LENGTH 4
+#define ECSPI_CONREG_DRCTL_SHIFT 16
+#define ECSPI_CONREG_DRCTL_LENGTH 2
+#define ECSPI_CONREG_CHANNEL_SELECT_SHIFT 18
+#define ECSPI_CONREG_CHANNEL_SELECT_LENGTH 2
+#define ECSPI_CONREG_BURST_LENGTH_SHIFT 20
+#define ECSPI_CONREG_BURST_LENGTH_LENGTH 12
+
+/* ECSPI_CONFIGREG */
+#define ECSPI_CONFIGREG_SS_CTL_SHIFT 8
+#define ECSPI_CONFIGREG_SS_CTL_LENGTH 4
+
+/* ECSPI_INTREG */
+#define ECSPI_INTREG_TEEN (1 << 0)
+#define ECSPI_INTREG_TDREN (1 << 1)
+#define ECSPI_INTREG_TFEN (1 << 2)
+#define ECSPI_INTREG_RREN (1 << 3)
+#define ECSPI_INTREG_RDREN (1 << 4)
+#define ECSPI_INTREG_RFEN (1 << 5)
+#define ECSPI_INTREG_ROEN (1 << 6)
+#define ECSPI_INTREG_TCEN (1 << 7)
+
+/* ECSPI_DMAREG */
+#define ECSPI_DMAREG_RXTDEN (1 << 31)
+#define ECSPI_DMAREG_RXDEN (1 << 23)
+#define ECSPI_DMAREG_TEDEN (1 << 7)
+#define ECSPI_DMAREG_RX_THRESHOLD_SHIFT 16
+#define ECSPI_DMAREG_RX_THRESHOLD_LENGTH 6
+
+/* ECSPI_STATREG */
+#define ECSPI_STATREG_TE (1 << 0)
+#define ECSPI_STATREG_TDR (1 << 1)
+#define ECSPI_STATREG_TF (1 << 2)
+#define ECSPI_STATREG_RR (1 << 3)
+#define ECSPI_STATREG_RDR (1 << 4)
+#define ECSPI_STATREG_RF (1 << 5)
+#define ECSPI_STATREG_RO (1 << 6)
+#define ECSPI_STATREG_TC (1 << 7)
+
+#define EXTRACT(value, name) extract32(value, name##_SHIFT, name##_LENGTH)
+
+#define TYPE_IMX_SPI "imx.spi"
+#define IMX_SPI(obj) OBJECT_CHECK(IMXSPIState, (obj), TYPE_IMX_SPI)
+
+typedef struct IMXSPIState {
+ /* <private> */
+ SysBusDevice parent_obj;
+
+ /* <public> */
+ MemoryRegion iomem;
+
+ qemu_irq irq;
+
+ qemu_irq cs_lines[4];
+
+ SSIBus *bus;
+
+ uint32_t regs[ECSPI_MAX];
+
+ Fifo32 rx_fifo;
+ Fifo32 tx_fifo;
+
+ int16_t burst_length;
+} IMXSPIState;
+
+#endif /* IMX_SPI_H */
--
2.5.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* [Qemu-devel] [PATCH v6 5/6] i.MX: Add i.MX6 SOC implementation.
2016-04-02 12:46 [Qemu-devel] [PATCH v6 0/6] Add i.MX6 (Single/Dual/Quad) support Jean-Christophe Dubois
` (3 preceding siblings ...)
2016-04-02 12:46 ` [Qemu-devel] [PATCH v6 4/6] i.MX: Add the Freescale SPI Controller Jean-Christophe Dubois
@ 2016-04-02 12:46 ` Jean-Christophe Dubois
2016-04-02 13:15 ` [Qemu-devel] [PATCH v6 6/6] i.MX: Add sabrelite i.MX6 emulation Jean-Christophe Dubois
2016-04-02 14:22 ` [Qemu-devel] [PATCH v6 0/6] Add i.MX6 (Single/Dual/Quad) support Jean-Christophe DUBOIS
6 siblings, 0 replies; 8+ messages in thread
From: Jean-Christophe Dubois @ 2016-04-02 12:46 UTC (permalink / raw)
To: qemu-devel, peter.maydell, crosthwaite.peter; +Cc: Jean-Christophe Dubois
For now we only support the following devices:
* up to 4 Cortex A9 cores
* A9 MPCORE (SCU, GIC, TWD)
* 5 i.MX UARTs
* 2 EPIT timers
* 1 GPT timer
* 3 I2C controllers
* 7 GPIO controllers
* 6 SDHC controllers
* 5 SPI controllers
* 1 CCM device
* 1 SRC device
* various ROM/RAM areas.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
---
Changes since V1:
* use g_strdup_printf/g_free instead of local char array.
* output a message on exit for unsupported number of cores.
Changes since V2:
* Added Include "osdep/qemu.h"
* Added support for EL3
* Added SPI controllers
* Added a property for each controller.
Changes since V3:
* None.
Changes since V4:
* None.
Changes since V5:
* None.
default-configs/arm-softmmu.mak | 1 +
hw/arm/Makefile.objs | 1 +
hw/arm/fsl-imx6.c | 449 +++++++++++++++++++++++++++++++++++++++
include/hw/arm/fsl-imx6.h | 450 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 901 insertions(+)
create mode 100644 hw/arm/fsl-imx6.c
create mode 100644 include/hw/arm/fsl-imx6.h
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index c63cdd0..c5bcba7 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -100,6 +100,7 @@ CONFIG_ALLWINNER_A10_PIT=y
CONFIG_ALLWINNER_A10_PIC=y
CONFIG_ALLWINNER_A10=y
+CONFIG_FSL_IMX6=y
CONFIG_FSL_IMX31=y
CONFIG_FSL_IMX25=y
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 954c9fe..2b20e49 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -16,4 +16,5 @@ obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o
obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
+obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o
obj-$(CONFIG_ASPEED_SOC) += ast2400.o palmetto-bmc.o
diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c
new file mode 100644
index 0000000..b8e93a6
--- /dev/null
+++ b/hw/arm/fsl-imx6.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * i.MX6 SOC emulation.
+ *
+ * Based on hw/arm/fsl-imx31.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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/arm/fsl-imx6.h"
+#include "sysemu/sysemu.h"
+#include "exec/address-spaces.h"
+#include "hw/boards.h"
+#include "sysemu/char.h"
+#include "qemu/error-report.h"
+
+#define NAME_SIZE 20
+
+static void fsl_imx6_init(Object *obj)
+{
+ FslIMX6State *s = FSL_IMX6(obj);
+ char name[NAME_SIZE];
+ int i;
+
+ if (smp_cpus > FSL_IMX6_NUM_CPUS) {
+ error_report("%s: Only %d CPUs are supported (%d requested)",
+ TYPE_FSL_IMX6, FSL_IMX6_NUM_CPUS, smp_cpus);
+ exit(1);
+ }
+
+ for (i = 0; i < smp_cpus; i++) {
+ object_initialize(&s->cpu[i], sizeof(s->cpu[i]),
+ "cortex-a9-" TYPE_ARM_CPU);
+ snprintf(name, NAME_SIZE, "cpu%d", i);
+ object_property_add_child(obj, name, OBJECT(&s->cpu[i]), NULL);
+ }
+
+ object_initialize(&s->a9mpcore, sizeof(s->a9mpcore), TYPE_A9MPCORE_PRIV);
+ qdev_set_parent_bus(DEVICE(&s->a9mpcore), sysbus_get_default());
+ object_property_add_child(obj, "a9mpcore", OBJECT(&s->a9mpcore), NULL);
+
+ object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX6_CCM);
+ qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default());
+ object_property_add_child(obj, "ccm", OBJECT(&s->ccm), NULL);
+
+ object_initialize(&s->src, sizeof(s->src), TYPE_IMX6_SRC);
+ qdev_set_parent_bus(DEVICE(&s->src), sysbus_get_default());
+ object_property_add_child(obj, "src", OBJECT(&s->src), NULL);
+
+ for (i = 0; i < FSL_IMX6_NUM_UARTS; i++) {
+ object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_IMX_SERIAL);
+ qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default());
+ snprintf(name, NAME_SIZE, "uart%d", i + 1);
+ object_property_add_child(obj, name, OBJECT(&s->uart[i]), NULL);
+ }
+
+ object_initialize(&s->gpt, sizeof(s->gpt), TYPE_IMX_GPT);
+ qdev_set_parent_bus(DEVICE(&s->gpt), sysbus_get_default());
+ object_property_add_child(obj, "gpt", OBJECT(&s->gpt), NULL);
+
+ for (i = 0; i < FSL_IMX6_NUM_EPITS; i++) {
+ object_initialize(&s->epit[i], sizeof(s->epit[i]), TYPE_IMX_EPIT);
+ qdev_set_parent_bus(DEVICE(&s->epit[i]), sysbus_get_default());
+ snprintf(name, NAME_SIZE, "epit%d", i + 1);
+ object_property_add_child(obj, name, OBJECT(&s->epit[i]), NULL);
+ }
+
+ for (i = 0; i < FSL_IMX6_NUM_I2CS; i++) {
+ object_initialize(&s->i2c[i], sizeof(s->i2c[i]), TYPE_IMX_I2C);
+ qdev_set_parent_bus(DEVICE(&s->i2c[i]), sysbus_get_default());
+ snprintf(name, NAME_SIZE, "i2c%d", i + 1);
+ object_property_add_child(obj, name, OBJECT(&s->i2c[i]), NULL);
+ }
+
+ for (i = 0; i < FSL_IMX6_NUM_GPIOS; i++) {
+ object_initialize(&s->gpio[i], sizeof(s->gpio[i]), TYPE_IMX_GPIO);
+ qdev_set_parent_bus(DEVICE(&s->gpio[i]), sysbus_get_default());
+ snprintf(name, NAME_SIZE, "gpio%d", i + 1);
+ object_property_add_child(obj, name, OBJECT(&s->gpio[i]), NULL);
+ }
+
+ for (i = 0; i < FSL_IMX6_NUM_ESDHCS; i++) {
+ object_initialize(&s->esdhc[i], sizeof(s->esdhc[i]), TYPE_SYSBUS_SDHCI);
+ 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);
+ }
+
+ for (i = 0; i < FSL_IMX6_NUM_ECSPIS; i++) {
+ object_initialize(&s->spi[i], sizeof(s->spi[i]), TYPE_IMX_SPI);
+ qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
+ snprintf(name, NAME_SIZE, "spi%d", i + 1);
+ object_property_add_child(obj, name, OBJECT(&s->spi[i]), NULL);
+ }
+}
+
+static void fsl_imx6_realize(DeviceState *dev, Error **errp)
+{
+ FslIMX6State *s = FSL_IMX6(dev);
+ uint16_t i;
+ Error *err = NULL;
+
+ for (i = 0; i < smp_cpus; i++) {
+
+ /* On uniprocessor, the CBAR is set to 0 */
+ if (smp_cpus > 1) {
+ object_property_set_int(OBJECT(&s->cpu[i]), FSL_IMX6_A9MPCORE_ADDR,
+ "reset-cbar", &error_abort);
+ }
+
+ /* All CPU but CPU 0 start in power off mode */
+ if (i) {
+ object_property_set_bool(OBJECT(&s->cpu[i]), true,
+ "start-powered-off", &error_abort);
+ }
+
+ object_property_set_bool(OBJECT(&s->cpu[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ }
+
+ object_property_set_int(OBJECT(&s->a9mpcore), smp_cpus, "num-cpu",
+ &error_abort);
+
+ object_property_set_int(OBJECT(&s->a9mpcore),
+ FSL_IMX6_MAX_IRQ + GIC_INTERNAL, "num-irq",
+ &error_abort);
+
+ object_property_set_bool(OBJECT(&s->a9mpcore), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->a9mpcore), 0, FSL_IMX6_A9MPCORE_ADDR);
+
+ for (i = 0; i < smp_cpus; i++) {
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i,
+ qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_IRQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i + smp_cpus,
+ qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_FIQ));
+ }
+
+ object_property_set_bool(OBJECT(&s->ccm), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX6_CCM_ADDR);
+
+ object_property_set_bool(OBJECT(&s->src), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->src), 0, FSL_IMX6_SRC_ADDR);
+
+ /* Initialize all UARTs */
+ for (i = 0; i < FSL_IMX6_NUM_UARTS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } serial_table[FSL_IMX6_NUM_UARTS] = {
+ { FSL_IMX6_UART1_ADDR, FSL_IMX6_UART1_IRQ },
+ { FSL_IMX6_UART2_ADDR, FSL_IMX6_UART2_IRQ },
+ { FSL_IMX6_UART3_ADDR, FSL_IMX6_UART3_IRQ },
+ { FSL_IMX6_UART4_ADDR, FSL_IMX6_UART4_IRQ },
+ { FSL_IMX6_UART5_ADDR, FSL_IMX6_UART5_IRQ },
+ };
+
+ if (i < MAX_SERIAL_PORTS) {
+ CharDriverState *chr;
+
+ chr = serial_hds[i];
+
+ if (!chr) {
+ char *label = g_strdup_printf("imx6.uart%d", i + 1);
+ chr = qemu_chr_new(label, "null", NULL);
+ g_free(label);
+ serial_hds[i] = chr;
+ }
+
+ qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr);
+ }
+
+ object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->a9mpcore),
+ serial_table[i].irq));
+ }
+
+ s->gpt.ccm = IMX_CCM(&s->ccm);
+
+ object_property_set_bool(OBJECT(&s->gpt), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt), 0, FSL_IMX6_GPT_ADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt), 0,
+ qdev_get_gpio_in(DEVICE(&s->a9mpcore),
+ FSL_IMX6_GPT_IRQ));
+
+ /* Initialize all EPIT timers */
+ for (i = 0; i < FSL_IMX6_NUM_EPITS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } epit_table[FSL_IMX6_NUM_EPITS] = {
+ { FSL_IMX6_EPIT1_ADDR, FSL_IMX6_EPIT1_IRQ },
+ { FSL_IMX6_EPIT2_ADDR, FSL_IMX6_EPIT2_IRQ },
+ };
+
+ s->epit[i].ccm = IMX_CCM(&s->ccm);
+
+ object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->a9mpcore),
+ epit_table[i].irq));
+ }
+
+ /* Initialize all I2C */
+ for (i = 0; i < FSL_IMX6_NUM_I2CS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } i2c_table[FSL_IMX6_NUM_I2CS] = {
+ { FSL_IMX6_I2C1_ADDR, FSL_IMX6_I2C1_IRQ },
+ { FSL_IMX6_I2C2_ADDR, FSL_IMX6_I2C2_IRQ },
+ { FSL_IMX6_I2C3_ADDR, FSL_IMX6_I2C3_IRQ }
+ };
+
+ object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->a9mpcore),
+ i2c_table[i].irq));
+ }
+
+ /* Initialize all GPIOs */
+ for (i = 0; i < FSL_IMX6_NUM_GPIOS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq_low;
+ unsigned int irq_high;
+ } gpio_table[FSL_IMX6_NUM_GPIOS] = {
+ {
+ FSL_IMX6_GPIO1_ADDR,
+ FSL_IMX6_GPIO1_LOW_IRQ,
+ FSL_IMX6_GPIO1_HIGH_IRQ
+ },
+ {
+ FSL_IMX6_GPIO2_ADDR,
+ FSL_IMX6_GPIO2_LOW_IRQ,
+ FSL_IMX6_GPIO2_HIGH_IRQ
+ },
+ {
+ FSL_IMX6_GPIO3_ADDR,
+ FSL_IMX6_GPIO3_LOW_IRQ,
+ FSL_IMX6_GPIO3_HIGH_IRQ
+ },
+ {
+ FSL_IMX6_GPIO4_ADDR,
+ FSL_IMX6_GPIO4_LOW_IRQ,
+ FSL_IMX6_GPIO4_HIGH_IRQ
+ },
+ {
+ FSL_IMX6_GPIO5_ADDR,
+ FSL_IMX6_GPIO5_LOW_IRQ,
+ FSL_IMX6_GPIO5_HIGH_IRQ
+ },
+ {
+ FSL_IMX6_GPIO6_ADDR,
+ FSL_IMX6_GPIO6_LOW_IRQ,
+ FSL_IMX6_GPIO6_HIGH_IRQ
+ },
+ {
+ FSL_IMX6_GPIO7_ADDR,
+ FSL_IMX6_GPIO7_LOW_IRQ,
+ FSL_IMX6_GPIO7_HIGH_IRQ
+ },
+ };
+
+ object_property_set_bool(OBJECT(&s->gpio[i]), true, "has-edge-sel",
+ &error_abort);
+ object_property_set_bool(OBJECT(&s->gpio[i]), true, "has-upper-pin-irq",
+ &error_abort);
+ object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->a9mpcore),
+ gpio_table[i].irq_low));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1,
+ qdev_get_gpio_in(DEVICE(&s->a9mpcore),
+ gpio_table[i].irq_high));
+ }
+
+ /* Initialize all SDHC */
+ for (i = 0; i < FSL_IMX6_NUM_ESDHCS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } esdhc_table[FSL_IMX6_NUM_ESDHCS] = {
+ { FSL_IMX6_uSDHC1_ADDR, FSL_IMX6_uSDHC1_IRQ },
+ { FSL_IMX6_uSDHC2_ADDR, FSL_IMX6_uSDHC2_IRQ },
+ { FSL_IMX6_uSDHC3_ADDR, FSL_IMX6_uSDHC3_IRQ },
+ { FSL_IMX6_uSDHC4_ADDR, FSL_IMX6_uSDHC4_IRQ },
+ };
+
+ object_property_set_bool(OBJECT(&s->esdhc[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->esdhc[i]), 0, esdhc_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->esdhc[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->a9mpcore),
+ esdhc_table[i].irq));
+ }
+
+ /* Initialize all ECSPI */
+ for (i = 0; i < FSL_IMX6_NUM_ECSPIS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } spi_table[FSL_IMX6_NUM_ECSPIS] = {
+ { FSL_IMX6_eCSPI1_ADDR, FSL_IMX6_ECSPI1_IRQ },
+ { FSL_IMX6_eCSPI2_ADDR, FSL_IMX6_ECSPI2_IRQ },
+ { FSL_IMX6_eCSPI3_ADDR, FSL_IMX6_ECSPI3_IRQ },
+ { FSL_IMX6_eCSPI4_ADDR, FSL_IMX6_ECSPI4_IRQ },
+ { FSL_IMX6_eCSPI5_ADDR, FSL_IMX6_ECSPI5_IRQ },
+ };
+
+ /* Initialize the SPI */
+ object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->a9mpcore),
+ spi_table[i].irq));
+ }
+
+ /* ROM memory */
+ memory_region_init_rom_device(&s->rom, NULL, NULL, NULL, "imx6.rom",
+ FSL_IMX6_ROM_SIZE, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ memory_region_add_subregion(get_system_memory(), FSL_IMX6_ROM_ADDR,
+ &s->rom);
+
+ /* CAAM memory */
+ memory_region_init_rom_device(&s->caam, NULL, NULL, NULL, "imx6.caam",
+ FSL_IMX6_CAAM_MEM_SIZE, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ memory_region_add_subregion(get_system_memory(), FSL_IMX6_CAAM_MEM_ADDR,
+ &s->caam);
+
+ /* OCRAM memory */
+ memory_region_init_ram(&s->ocram, NULL, "imx6.ocram", FSL_IMX6_OCRAM_SIZE,
+ &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ memory_region_add_subregion(get_system_memory(), FSL_IMX6_OCRAM_ADDR,
+ &s->ocram);
+ vmstate_register_ram_global(&s->ocram);
+
+ /* internal OCRAM (256 KB) is aliased over 1 MB */
+ memory_region_init_alias(&s->ocram_alias, NULL, "imx6.ocram_alias",
+ &s->ocram, 0, FSL_IMX6_OCRAM_ALIAS_SIZE);
+ memory_region_add_subregion(get_system_memory(), FSL_IMX6_OCRAM_ALIAS_ADDR,
+ &s->ocram_alias);
+}
+
+static void fsl_imx6_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = fsl_imx6_realize;
+
+ /*
+ * Reason: creates an ARM CPU, thus use after free(), see
+ * arm_cpu_class_init()
+ */
+ dc->cannot_destroy_with_object_finalize_yet = true;
+ dc->desc = "i.MX6 SOC";
+}
+
+static const TypeInfo fsl_imx6_type_info = {
+ .name = TYPE_FSL_IMX6,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(FslIMX6State),
+ .instance_init = fsl_imx6_init,
+ .class_init = fsl_imx6_class_init,
+};
+
+static void fsl_imx6_register_types(void)
+{
+ type_register_static(&fsl_imx6_type_info);
+}
+
+type_init(fsl_imx6_register_types)
diff --git a/include/hw/arm/fsl-imx6.h b/include/hw/arm/fsl-imx6.h
new file mode 100644
index 0000000..d24aaee
--- /dev/null
+++ b/include/hw/arm/fsl-imx6.h
@@ -0,0 +1,450 @@
+/*
+ * Freescale i.MX31 SoC emulation
+ *
+ * Copyright (C) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * 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.
+ */
+
+#ifndef FSL_IMX6_H
+#define FSL_IMX6_H
+
+#include "hw/arm/arm.h"
+#include "hw/cpu/a9mpcore.h"
+#include "hw/misc/imx6_ccm.h"
+#include "hw/misc/imx6_src.h"
+#include "hw/char/imx_serial.h"
+#include "hw/timer/imx_gpt.h"
+#include "hw/timer/imx_epit.h"
+#include "hw/i2c/imx_i2c.h"
+#include "hw/gpio/imx_gpio.h"
+#include "hw/sd/sdhci.h"
+#include "hw/ssi/imx_spi.h"
+#include "exec/memory.h"
+
+#define TYPE_FSL_IMX6 "fsl,imx6"
+#define FSL_IMX6(obj) OBJECT_CHECK(FslIMX6State, (obj), TYPE_FSL_IMX6)
+
+#define FSL_IMX6_NUM_CPUS 4
+#define FSL_IMX6_NUM_UARTS 5
+#define FSL_IMX6_NUM_EPITS 2
+#define FSL_IMX6_NUM_I2CS 3
+#define FSL_IMX6_NUM_GPIOS 7
+#define FSL_IMX6_NUM_ESDHCS 4
+#define FSL_IMX6_NUM_ECSPIS 5
+
+typedef struct FslIMX6State {
+ /*< private >*/
+ DeviceState parent_obj;
+
+ /*< public >*/
+ ARMCPU cpu[FSL_IMX6_NUM_CPUS];
+ A9MPPrivState a9mpcore;
+ IMX6CCMState ccm;
+ IMX6SRCState src;
+ IMXSerialState uart[FSL_IMX6_NUM_UARTS];
+ IMXGPTState gpt;
+ IMXEPITState epit[FSL_IMX6_NUM_EPITS];
+ IMXI2CState i2c[FSL_IMX6_NUM_I2CS];
+ IMXGPIOState gpio[FSL_IMX6_NUM_GPIOS];
+ SDHCIState esdhc[FSL_IMX6_NUM_ESDHCS];
+ IMXSPIState spi[FSL_IMX6_NUM_ECSPIS];
+ MemoryRegion rom;
+ MemoryRegion caam;
+ MemoryRegion ocram;
+ MemoryRegion ocram_alias;
+} FslIMX6State;
+
+
+#define FSL_IMX6_MMDC_ADDR 0x10000000
+#define FSL_IMX6_MMDC_SIZE 0xF0000000
+#define FSL_IMX6_EIM_MEM_ADDR 0x08000000
+#define FSL_IMX6_EIM_MEM_SIZE 0x8000000
+#define FSL_IMX6_IPU_2_ADDR 0x02800000
+#define FSL_IMX6_IPU_2_SIZE 0x400000
+#define FSL_IMX6_IPU_1_ADDR 0x02400000
+#define FSL_IMX6_IPU_1_SIZE 0x400000
+#define FSL_IMX6_MIPI_HSI_ADDR 0x02208000
+#define FSL_IMX6_MIPI_HSI_SIZE 0x4000
+#define FSL_IMX6_OPENVG_ADDR 0x02204000
+#define FSL_IMX6_OPENVG_SIZE 0x4000
+#define FSL_IMX6_SATA_ADDR 0x02200000
+#define FSL_IMX6_SATA_SIZE 0x4000
+#define FSL_IMX6_AIPS_2_ADDR 0x02100000
+#define FSL_IMX6_AIPS_2_SIZE 0x100000
+/* AIPS2 */
+#define FSL_IMX6_UART5_ADDR 0x021F4000
+#define FSL_IMX6_UART5_SIZE 0x4000
+#define FSL_IMX6_UART4_ADDR 0x021F0000
+#define FSL_IMX6_UART4_SIZE 0x4000
+#define FSL_IMX6_UART3_ADDR 0x021EC000
+#define FSL_IMX6_UART3_SIZE 0x4000
+#define FSL_IMX6_UART2_ADDR 0x021E8000
+#define FSL_IMX6_UART2_SIZE 0x4000
+#define FSL_IMX6_VDOA_ADDR 0x021E4000
+#define FSL_IMX6_VDOA_SIZE 0x4000
+#define FSL_IMX6_MIPI_DSI_ADDR 0x021E0000
+#define FSL_IMX6_MIPI_DSI_SIZE 0x4000
+#define FSL_IMX6_MIPI_CSI_ADDR 0x021DC000
+#define FSL_IMX6_MIPI_CSI_SIZE 0x4000
+#define FSL_IMX6_AUDMUX_ADDR 0x021D8000
+#define FSL_IMX6_AUDMUX_SIZE 0x4000
+#define FSL_IMX6_TZASC2_ADDR 0x021D4000
+#define FSL_IMX6_TZASC2_SIZE 0x4000
+#define FSL_IMX6_TZASC1_ADDR 0x021D0000
+#define FSL_IMX6_TZASC1_SIZE 0x4000
+#define FSL_IMX6_CSU_ADDR 0x021C0000
+#define FSL_IMX6_CSU_SIZE 0x4000
+#define FSL_IMX6_OCOTPCTRL_ADDR 0x021BC000
+#define FSL_IMX6_OCOTPCTRL_SIZE 0x4000
+#define FSL_IMX6_EIM_ADDR 0x021B8000
+#define FSL_IMX6_EIM_SIZE 0x4000
+#define FSL_IMX6_MMDC1_ADDR 0x021B4000
+#define FSL_IMX6_MMDC1_SIZE 0x4000
+#define FSL_IMX6_MMDC0_ADDR 0x021B0000
+#define FSL_IMX6_MMDC0_SIZE 0x4000
+#define FSL_IMX6_ROMCP_ADDR 0x021AC000
+#define FSL_IMX6_ROMCP_SIZE 0x4000
+#define FSL_IMX6_I2C3_ADDR 0x021A8000
+#define FSL_IMX6_I2C3_SIZE 0x4000
+#define FSL_IMX6_I2C2_ADDR 0x021A4000
+#define FSL_IMX6_I2C2_SIZE 0x4000
+#define FSL_IMX6_I2C1_ADDR 0x021A0000
+#define FSL_IMX6_I2C1_SIZE 0x4000
+#define FSL_IMX6_uSDHC4_ADDR 0x0219C000
+#define FSL_IMX6_uSDHC4_SIZE 0x4000
+#define FSL_IMX6_uSDHC3_ADDR 0x02198000
+#define FSL_IMX6_uSDHC3_SIZE 0x4000
+#define FSL_IMX6_uSDHC2_ADDR 0x02194000
+#define FSL_IMX6_uSDHC2_SIZE 0x4000
+#define FSL_IMX6_uSDHC1_ADDR 0x02190000
+#define FSL_IMX6_uSDHC1_SIZE 0x4000
+#define FSL_IMX6_MLB150_ADDR 0x0218C000
+#define FSL_IMX6_MLB150_SIZE 0x4000
+#define FSL_IMX6_ENET_ADDR 0x02188000
+#define FSL_IMX6_ENET_SIZE 0x4000
+#define FSL_IMX6_USBOH3_USB_ADDR 0x02184000
+#define FSL_IMX6_USBOH3_USB_SIZE 0x4000
+#define FSL_IMX6_AIPS2_CFG_ADDR 0x0217C000
+#define FSL_IMX6_AIPS2_CFG_SIZE 0x4000
+/* DAP */
+#define FSL_IMX6_PTF_CTRL_ADDR 0x02160000
+#define FSL_IMX6_PTF_CTRL_SIZE 0x1000
+#define FSL_IMX6_PTM3_ADDR 0x0215F000
+#define FSL_IMX6_PTM3_SIZE 0x1000
+#define FSL_IMX6_PTM2_ADDR 0x0215E000
+#define FSL_IMX6_PTM2_SIZE 0x1000
+#define FSL_IMX6_PTM1_ADDR 0x0215D000
+#define FSL_IMX6_PTM1_SIZE 0x1000
+#define FSL_IMX6_PTM0_ADDR 0x0215C000
+#define FSL_IMX6_PTM0_SIZE 0x1000
+#define FSL_IMX6_CTI3_ADDR 0x0215B000
+#define FSL_IMX6_CTI3_SIZE 0x1000
+#define FSL_IMX6_CTI2_ADDR 0x0215A000
+#define FSL_IMX6_CTI2_SIZE 0x1000
+#define FSL_IMX6_CTI1_ADDR 0x02159000
+#define FSL_IMX6_CTI1_SIZE 0x1000
+#define FSL_IMX6_CTI0_ADDR 0x02158000
+#define FSL_IMX6_CTI0_SIZE 0x1000
+#define FSL_IMX6_CPU3_PMU_ADDR 0x02157000
+#define FSL_IMX6_CPU3_PMU_SIZE 0x1000
+#define FSL_IMX6_CPU3_DEBUG_IF_ADDR 0x02156000
+#define FSL_IMX6_CPU3_DEBUG_IF_SIZE 0x1000
+#define FSL_IMX6_CPU2_PMU_ADDR 0x02155000
+#define FSL_IMX6_CPU2_PMU_SIZE 0x1000
+#define FSL_IMX6_CPU2_DEBUG_IF_ADDR 0x02154000
+#define FSL_IMX6_CPU2_DEBUG_IF_SIZE 0x1000
+#define FSL_IMX6_CPU1_PMU_ADDR 0x02153000
+#define FSL_IMX6_CPU1_PMU_SIZE 0x1000
+#define FSL_IMX6_CPU1_DEBUG_IF_ADDR 0x02152000
+#define FSL_IMX6_CPU1_DEBUG_IF_SIZE 0x1000
+#define FSL_IMX6_CPU0_PMU_ADDR 0x02151000
+#define FSL_IMX6_CPU0_PMU_SIZE 0x1000
+#define FSL_IMX6_CPU0_DEBUG_IF_ADDR 0x02150000
+#define FSL_IMX6_CPU0_DEBUG_IF_SIZE 0x1000
+#define FSL_IMX6_CA9_INTEG_ADDR 0x0214F000
+#define FSL_IMX6_CA9_INTEG_SIZE 0x1000
+#define FSL_IMX6_FUNNEL_ADDR 0x02144000
+#define FSL_IMX6_FUNNEL_SIZE 0x1000
+#define FSL_IMX6_TPIU_ADDR 0x02143000
+#define FSL_IMX6_TPIU_SIZE 0x1000
+#define FSL_IMX6_EXT_CTI_ADDR 0x02142000
+#define FSL_IMX6_EXT_CTI_SIZE 0x1000
+#define FSL_IMX6_ETB_ADDR 0x02141000
+#define FSL_IMX6_ETB_SIZE 0x1000
+#define FSL_IMX6_DAP_ROM_TABLE_ADDR 0x02140000
+#define FSL_IMX6_DAP_ROM_TABLE_SIZE 0x1000
+/* DAP end */
+#define FSL_IMX6_CAAM_ADDR 0x02100000
+#define FSL_IMX6_CAAM_SIZE 0x10000
+/* AIPS2 end */
+#define FSL_IMX6_AIPS_1_ADDR 0x02000000
+#define FSL_IMX6_AIPS_1_SIZE 0x100000
+/* AIPS1 */
+#define FSL_IMX6_SDMA_ADDR 0x020EC000
+#define FSL_IMX6_SDMA_SIZE 0x4000
+#define FSL_IMX6_DCIC2_ADDR 0x020E8000
+#define FSL_IMX6_DCIC2_SIZE 0x4000
+#define FSL_IMX6_DCIC1_ADDR 0x020E4000
+#define FSL_IMX6_DCIC1_SIZE 0x4000
+#define FSL_IMX6_IOMUXC_ADDR 0x020E0000
+#define FSL_IMX6_IOMUXC_SIZE 0x4000
+#define FSL_IMX6_PGCARM_ADDR 0x020DCA00
+#define FSL_IMX6_PGCARM_SIZE 0x20
+#define FSL_IMX6_PGCPU_ADDR 0x020DC260
+#define FSL_IMX6_PGCPU_SIZE 0x20
+#define FSL_IMX6_GPC_ADDR 0x020DC000
+#define FSL_IMX6_GPC_SIZE 0x4000
+#define FSL_IMX6_SRC_ADDR 0x020D8000
+#define FSL_IMX6_SRC_SIZE 0x4000
+#define FSL_IMX6_EPIT2_ADDR 0x020D4000
+#define FSL_IMX6_EPIT2_SIZE 0x4000
+#define FSL_IMX6_EPIT1_ADDR 0x020D0000
+#define FSL_IMX6_EPIT1_SIZE 0x4000
+#define FSL_IMX6_SNVSHP_ADDR 0x020CC000
+#define FSL_IMX6_SNVSHP_SIZE 0x4000
+#define FSL_IMX6_USBPHY2_ADDR 0x020CA000
+#define FSL_IMX6_USBPHY2_SIZE 0x1000
+#define FSL_IMX6_USBPHY1_ADDR 0x020C9000
+#define FSL_IMX6_USBPHY1_SIZE 0x1000
+#define FSL_IMX6_ANALOG_ADDR 0x020C8000
+#define FSL_IMX6_ANALOG_SIZE 0x1000
+#define FSL_IMX6_CCM_ADDR 0x020C4000
+#define FSL_IMX6_CCM_SIZE 0x4000
+#define FSL_IMX6_WDOG2_ADDR 0x020C0000
+#define FSL_IMX6_WDOG2_SIZE 0x4000
+#define FSL_IMX6_WDOG1_ADDR 0x020BC000
+#define FSL_IMX6_WDOG1_SIZE 0x4000
+#define FSL_IMX6_KPP_ADDR 0x020B8000
+#define FSL_IMX6_KPP_SIZE 0x4000
+#define FSL_IMX6_GPIO7_ADDR 0x020B4000
+#define FSL_IMX6_GPIO7_SIZE 0x4000
+#define FSL_IMX6_GPIO6_ADDR 0x020B0000
+#define FSL_IMX6_GPIO6_SIZE 0x4000
+#define FSL_IMX6_GPIO5_ADDR 0x020AC000
+#define FSL_IMX6_GPIO5_SIZE 0x4000
+#define FSL_IMX6_GPIO4_ADDR 0x020A8000
+#define FSL_IMX6_GPIO4_SIZE 0x4000
+#define FSL_IMX6_GPIO3_ADDR 0x020A4000
+#define FSL_IMX6_GPIO3_SIZE 0x4000
+#define FSL_IMX6_GPIO2_ADDR 0x020A0000
+#define FSL_IMX6_GPIO2_SIZE 0x4000
+#define FSL_IMX6_GPIO1_ADDR 0x0209C000
+#define FSL_IMX6_GPIO1_SIZE 0x4000
+#define FSL_IMX6_GPT_ADDR 0x02098000
+#define FSL_IMX6_GPT_SIZE 0x4000
+#define FSL_IMX6_CAN2_ADDR 0x02094000
+#define FSL_IMX6_CAN2_SIZE 0x4000
+#define FSL_IMX6_CAN1_ADDR 0x02090000
+#define FSL_IMX6_CAN1_SIZE 0x4000
+#define FSL_IMX6_PWM4_ADDR 0x0208C000
+#define FSL_IMX6_PWM4_SIZE 0x4000
+#define FSL_IMX6_PWM3_ADDR 0x02088000
+#define FSL_IMX6_PWM3_SIZE 0x4000
+#define FSL_IMX6_PWM2_ADDR 0x02084000
+#define FSL_IMX6_PWM2_SIZE 0x4000
+#define FSL_IMX6_PWM1_ADDR 0x02080000
+#define FSL_IMX6_PWM1_SIZE 0x4000
+#define FSL_IMX6_AIPS1_CFG_ADDR 0x0207C000
+#define FSL_IMX6_AIPS1_CFG_SIZE 0x4000
+#define FSL_IMX6_VPU_ADDR 0x02040000
+#define FSL_IMX6_VPU_SIZE 0x3C000
+#define FSL_IMX6_AIPS1_SPBA_ADDR 0x0203C000
+#define FSL_IMX6_AIPS1_SPBA_SIZE 0x4000
+#define FSL_IMX6_ASRC_ADDR 0x02034000
+#define FSL_IMX6_ASRC_SIZE 0x4000
+#define FSL_IMX6_SSI3_ADDR 0x02030000
+#define FSL_IMX6_SSI3_SIZE 0x4000
+#define FSL_IMX6_SSI2_ADDR 0x0202C000
+#define FSL_IMX6_SSI2_SIZE 0x4000
+#define FSL_IMX6_SSI1_ADDR 0x02028000
+#define FSL_IMX6_SSI1_SIZE 0x4000
+#define FSL_IMX6_ESAI_ADDR 0x02024000
+#define FSL_IMX6_ESAI_SIZE 0x4000
+#define FSL_IMX6_UART1_ADDR 0x02020000
+#define FSL_IMX6_UART1_SIZE 0x4000
+#define FSL_IMX6_eCSPI5_ADDR 0x02018000
+#define FSL_IMX6_eCSPI5_SIZE 0x4000
+#define FSL_IMX6_eCSPI4_ADDR 0x02014000
+#define FSL_IMX6_eCSPI4_SIZE 0x4000
+#define FSL_IMX6_eCSPI3_ADDR 0x02010000
+#define FSL_IMX6_eCSPI3_SIZE 0x4000
+#define FSL_IMX6_eCSPI2_ADDR 0x0200C000
+#define FSL_IMX6_eCSPI2_SIZE 0x4000
+#define FSL_IMX6_eCSPI1_ADDR 0x02008000
+#define FSL_IMX6_eCSPI1_SIZE 0x4000
+#define FSL_IMX6_SPDIF_ADDR 0x02004000
+#define FSL_IMX6_SPDIF_SIZE 0x4000
+/* AIPS1 end */
+#define FSL_IMX6_PCIe_REG_ADDR 0x01FFC000
+#define FSL_IMX6_PCIe_REG_SIZE 0x4000
+#define FSL_IMX6_PCIe_ADDR 0x01000000
+#define FSL_IMX6_PCIe_SIZE 0xFFC000
+#define FSL_IMX6_GPV_1_PL301_CFG_ADDR 0x00C00000
+#define FSL_IMX6_GPV_1_PL301_CFG_SIZE 0x100000
+#define FSL_IMX6_GPV_0_PL301_CFG_ADDR 0x00B00000
+#define FSL_IMX6_GPV_0_PL301_CFG_SIZE 0x100000
+#define FSL_IMX6_PL310_ADDR 0x00A02000
+#define FSL_IMX6_PL310_SIZE 0x1000
+#define FSL_IMX6_A9MPCORE_ADDR 0x00A00000
+#define FSL_IMX6_A9MPCORE_SIZE 0x2000
+#define FSL_IMX6_OCRAM_ALIAS_ADDR 0x00940000
+#define FSL_IMX6_OCRAM_ALIAS_SIZE 0xC0000
+#define FSL_IMX6_OCRAM_ADDR 0x00900000
+#define FSL_IMX6_OCRAM_SIZE 0x40000
+#define FSL_IMX6_GPV_4_PL301_CFG_ADDR 0x00800000
+#define FSL_IMX6_GPV_4_PL301_CFG_SIZE 0x100000
+#define FSL_IMX6_GPV_3_PL301_CFG_ADDR 0x00300000
+#define FSL_IMX6_GPV_3_PL301_CFG_SIZE 0x100000
+#define FSL_IMX6_GPV_2_PL301_CFG_ADDR 0x00200000
+#define FSL_IMX6_GPV_2_PL301_CFG_SIZE 0x100000
+#define FSL_IMX6_DTCP_ADDR 0x00138000
+#define FSL_IMX6_DTCP_SIZE 0x4000
+#define FSL_IMX6_GPU_2D_ADDR 0x00134000
+#define FSL_IMX6_GPU_2D_SIZE 0x4000
+#define FSL_IMX6_GPU_3D_ADDR 0x00130000
+#define FSL_IMX6_GPU_3D_SIZE 0x4000
+#define FSL_IMX6_HDMI_ADDR 0x00120000
+#define FSL_IMX6_HDMI_SIZE 0x9000
+#define FSL_IMX6_BCH_ADDR 0x00114000
+#define FSL_IMX6_BCH_SIZE 0x4000
+#define FSL_IMX6_GPMI_ADDR 0x00112000
+#define FSL_IMX6_GPMI_SIZE 0x2000
+#define FSL_IMX6_APBH_BRIDGE_DMA_ADDR 0x00110000
+#define FSL_IMX6_APBH_BRIDGE_DMA_SIZE 0x2000
+#define FSL_IMX6_CAAM_MEM_ADDR 0x00100000
+#define FSL_IMX6_CAAM_MEM_SIZE 0x4000
+#define FSL_IMX6_ROM_ADDR 0x00000000
+#define FSL_IMX6_ROM_SIZE 0x18000
+
+#define FSL_IMX6_IOMUXC_IRQ 0
+#define FSL_IMX6_DAP_IRQ 1
+#define FSL_IMX6_SDMA_IRQ 2
+#define FSL_IMX6_VPU_JPEG_IRQ 3
+#define FSL_IMX6_SNVS_PMIC_IRQ 4
+#define FSL_IMX6_IPU1_ERROR_IRQ 5
+#define FSL_IMX6_IPU1_SYNC_IRQ 6
+#define FSL_IMX6_IPU2_ERROR_IRQ 7
+#define FSL_IMX6_IPU2_SYNC_IRQ 8
+#define FSL_IMX6_GPU3D_IRQ 9
+#define FSL_IMX6_R2D_IRQ 10
+#define FSL_IMX6_V2D_IRQ 11
+#define FSL_IMX6_VPU_IRQ 12
+#define FSL_IMX6_APBH_BRIDGE_DMA_IRQ 13
+#define FSL_IMX6_EIM_IRQ 14
+#define FSL_IMX6_BCH_IRQ 15
+#define FSL_IMX6_GPMI_IRQ 16
+#define FSL_IMX6_DTCP_IRQ 17
+#define FSL_IMX6_VDOA_IRQ 18
+#define FSL_IMX6_SNVS_CONS_IRQ 19
+#define FSL_IMX6_SNVS_SEC_IRQ 20
+#define FSL_IMX6_CSU_IRQ 21
+#define FSL_IMX6_uSDHC1_IRQ 22
+#define FSL_IMX6_uSDHC2_IRQ 23
+#define FSL_IMX6_uSDHC3_IRQ 24
+#define FSL_IMX6_uSDHC4_IRQ 25
+#define FSL_IMX6_UART1_IRQ 26
+#define FSL_IMX6_UART2_IRQ 27
+#define FSL_IMX6_UART3_IRQ 28
+#define FSL_IMX6_UART4_IRQ 29
+#define FSL_IMX6_UART5_IRQ 30
+#define FSL_IMX6_ECSPI1_IRQ 31
+#define FSL_IMX6_ECSPI2_IRQ 32
+#define FSL_IMX6_ECSPI3_IRQ 33
+#define FSL_IMX6_ECSPI4_IRQ 34
+#define FSL_IMX6_ECSPI5_IRQ 35
+#define FSL_IMX6_I2C1_IRQ 36
+#define FSL_IMX6_I2C2_IRQ 37
+#define FSL_IMX6_I2C3_IRQ 38
+#define FSL_IMX6_SATA_IRQ 39
+#define FSL_IMX6_USB_HOST1_IRQ 40
+#define FSL_IMX6_USB_HOST2_IRQ 41
+#define FSL_IMX6_USB_HOST3_IRQ 42
+#define FSL_IMX6_USB_OTG_IRQ 43
+#define FSL_IMX6_USB_PHY_UTMI0_IRQ 44
+#define FSL_IMX6_USB_PHY_UTMI1_IRQ 45
+#define FSL_IMX6_SSI1_IRQ 46
+#define FSL_IMX6_SSI2_IRQ 47
+#define FSL_IMX6_SSI3_IRQ 48
+#define FSL_IMX6_TEMP_IRQ 49
+#define FSL_IMX6_ASRC_IRQ 50
+#define FSL_IMX6_ESAI_IRQ 51
+#define FSL_IMX6_SPDIF_IRQ 52
+#define FSL_IMX6_MLB150_IRQ 53
+#define FSL_IMX6_PMU1_IRQ 54
+#define FSL_IMX6_GPT_IRQ 55
+#define FSL_IMX6_EPIT1_IRQ 56
+#define FSL_IMX6_EPIT2_IRQ 57
+#define FSL_IMX6_GPIO1_INT7_IRQ 58
+#define FSL_IMX6_GPIO1_INT6_IRQ 59
+#define FSL_IMX6_GPIO1_INT5_IRQ 60
+#define FSL_IMX6_GPIO1_INT4_IRQ 61
+#define FSL_IMX6_GPIO1_INT3_IRQ 62
+#define FSL_IMX6_GPIO1_INT2_IRQ 63
+#define FSL_IMX6_GPIO1_INT1_IRQ 64
+#define FSL_IMX6_GPIO1_INT0_IRQ 65
+#define FSL_IMX6_GPIO1_LOW_IRQ 66
+#define FSL_IMX6_GPIO1_HIGH_IRQ 67
+#define FSL_IMX6_GPIO2_LOW_IRQ 68
+#define FSL_IMX6_GPIO2_HIGH_IRQ 69
+#define FSL_IMX6_GPIO3_LOW_IRQ 70
+#define FSL_IMX6_GPIO3_HIGH_IRQ 71
+#define FSL_IMX6_GPIO4_LOW_IRQ 72
+#define FSL_IMX6_GPIO4_HIGH_IRQ 73
+#define FSL_IMX6_GPIO5_LOW_IRQ 74
+#define FSL_IMX6_GPIO5_HIGH_IRQ 75
+#define FSL_IMX6_GPIO6_LOW_IRQ 76
+#define FSL_IMX6_GPIO6_HIGH_IRQ 77
+#define FSL_IMX6_GPIO7_LOW_IRQ 78
+#define FSL_IMX6_GPIO7_HIGH_IRQ 79
+#define FSL_IMX6_WDOG1_IRQ 80
+#define FSL_IMX6_WDOG2_IRQ 81
+#define FSL_IMX6_KPP_IRQ 82
+#define FSL_IMX6_PWM1_IRQ 83
+#define FSL_IMX6_PWM2_IRQ 84
+#define FSL_IMX6_PWM3_IRQ 85
+#define FSL_IMX6_PWM4_IRQ 86
+#define FSL_IMX6_CCM1_IRQ 87
+#define FSL_IMX6_CCM2_IRQ 88
+#define FSL_IMX6_GPC_IRQ 89
+#define FSL_IMX6_SRC_IRQ 91
+#define FSL_IMX6_CPU_L2_IRQ 92
+#define FSL_IMX6_CPU_PARITY_IRQ 93
+#define FSL_IMX6_CPU_PERF_IRQ 94
+#define FSL_IMX6_CPU_CTI_IRQ 95
+#define FSL_IMX6_SRC_COMB_IRQ 96
+#define FSL_IMX6_MIPI_CSI1_IRQ 100
+#define FSL_IMX6_MIPI_CSI2_IRQ 101
+#define FSL_IMX6_MIPI_DSI_IRQ 102
+#define FSL_IMX6_MIPI_HSI_IRQ 103
+#define FSL_IMX6_SJC_IRQ 104
+#define FSL_IMX6_CAAM0_IRQ 105
+#define FSL_IMX6_CAAM1_IRQ 106
+#define FSL_IMX6_ASC1_IRQ 108
+#define FSL_IMX6_ASC2_IRQ 109
+#define FSL_IMX6_FLEXCAN1_IRQ 110
+#define FSL_IMX6_FLEXCAN2_IRQ 111
+#define FSL_IMX6_HDMI_MASTER_IRQ 115
+#define FSL_IMX6_HDMI_CEC_IRQ 116
+#define FSL_IMX6_MLB150_LOW_IRQ 117
+#define FSL_IMX6_ENET_MAC_IRQ 118
+#define FSL_IMX6_ENET_MAC_1588_IRQ 119
+#define FSL_IMX6_PCIE1_IRQ 120
+#define FSL_IMX6_PCIE2_IRQ 121
+#define FSL_IMX6_PCIE3_IRQ 122
+#define FSL_IMX6_PCIE4_IRQ 123
+#define FSL_IMX6_DCIC1_IRQ 124
+#define FSL_IMX6_DCIC2_IRQ 125
+#define FSL_IMX6_MLB150_HIGH_IRQ 126
+#define FSL_IMX6_PMU2_IRQ 127
+#define FSL_IMX6_MAX_IRQ 128
+
+#endif /* FSL_IMX6_H */
--
2.5.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* [Qemu-devel] [PATCH v6 6/6] i.MX: Add sabrelite i.MX6 emulation.
2016-04-02 12:46 [Qemu-devel] [PATCH v6 0/6] Add i.MX6 (Single/Dual/Quad) support Jean-Christophe Dubois
` (4 preceding siblings ...)
2016-04-02 12:46 ` [Qemu-devel] [PATCH v6 5/6] i.MX: Add i.MX6 SOC implementation Jean-Christophe Dubois
@ 2016-04-02 13:15 ` Jean-Christophe Dubois
2016-04-02 14:22 ` [Qemu-devel] [PATCH v6 0/6] Add i.MX6 (Single/Dual/Quad) support Jean-Christophe DUBOIS
6 siblings, 0 replies; 8+ messages in thread
From: Jean-Christophe Dubois @ 2016-04-02 13:15 UTC (permalink / raw)
To: qemu-devel, peter.maydell, crosthwaite.peter; +Cc: Jean-Christophe Dubois
The sabrelite supports one SPI FLASH memory on SPI1
Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
---
Changes since V1:
* Output a message and exit if RAM size is unsupported.
Changes since V2:
* Added include "qemu/osdep.h"
* Added access to controllers through properties.
Changes since V3:
* None
Changes since V4:
* Added a TODO.
Changes since V5:
* None
hw/arm/Makefile.objs | 2 +-
hw/arm/sabrelite.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 123 insertions(+), 1 deletion(-)
create mode 100644 hw/arm/sabrelite.c
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 2b20e49..12764ef 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -16,5 +16,5 @@ obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o
obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
-obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o
+obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o
obj-$(CONFIG_ASPEED_SOC) += ast2400.o palmetto-bmc.o
diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c
new file mode 100644
index 0000000..4037327
--- /dev/null
+++ b/hw/arm/sabrelite.c
@@ -0,0 +1,122 @@
+/*
+ * SABRELITE Board System emulation.
+ *
+ * Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * This code is licensed under the GPL, version 2 or later.
+ * See the file `COPYING' in the top level directory.
+ *
+ * It (partially) emulates a sabrelite board, with a Freescale
+ * i.MX6 SoC
+ */
+
+#include "qemu/osdep.h"
+#include "hw/arm/fsl-imx6.h"
+#include "hw/boards.h"
+#include "qemu/error-report.h"
+#include "exec/address-spaces.h"
+#include "net/net.h"
+#include "hw/devices.h"
+#include "hw/char/serial.h"
+#include "sysemu/qtest.h"
+
+typedef struct IMX6Sabrelite {
+ FslIMX6State soc;
+ MemoryRegion ram;
+} IMX6Sabrelite;
+
+static struct arm_boot_info sabrelite_binfo = {
+ /* DDR memory start */
+ .loader_start = FSL_IMX6_MMDC_ADDR,
+ /* No board ID, we boot from DT tree */
+ .board_id = -1,
+};
+
+/* No need to do any particular setup for secondary boot */
+static void sabrelite_write_secondary(ARMCPU *cpu,
+ const struct arm_boot_info *info)
+{
+}
+
+/* Secondary cores are reset through SRC device */
+static void sabrelite_reset_secondary(ARMCPU *cpu,
+ const struct arm_boot_info *info)
+{
+}
+
+static void sabrelite_init(MachineState *machine)
+{
+ IMX6Sabrelite *s = g_new0(IMX6Sabrelite, 1);
+ Error *err = NULL;
+
+ /* Check the amount of memory is compatible with the SOC */
+ if (machine->ram_size > FSL_IMX6_MMDC_SIZE) {
+ error_report("RAM size " RAM_ADDR_FMT " above max supported (%08x)",
+ machine->ram_size, FSL_IMX6_MMDC_SIZE);
+ exit(1);
+ }
+
+ object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX6);
+ object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc),
+ &error_abort);
+
+ object_property_set_bool(OBJECT(&s->soc), true, "realized", &err);
+ if (err != NULL) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+
+ memory_region_allocate_system_memory(&s->ram, NULL, "sabrelite.ram",
+ machine->ram_size);
+ memory_region_add_subregion(get_system_memory(), FSL_IMX6_MMDC_ADDR,
+ &s->ram);
+
+ {
+ /*
+ * TODO: Ideally we would expose the chip select and spi bus on the
+ * SoC object using alias properties; then we would not need to
+ * directly access the underlying spi device object.
+ */
+ /* Add the sst25vf016b NOR FLASH memory to first SPI */
+ Object *spi_dev;
+
+ spi_dev = object_resolve_path_component(OBJECT(&s->soc), "spi1");
+ if (spi_dev) {
+ SSIBus *spi_bus;
+
+ spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(spi_dev), "spi");
+ if (spi_bus) {
+ DeviceState *flash_dev;
+
+ flash_dev = ssi_create_slave(spi_bus, "sst25vf016b");
+ if (flash_dev) {
+ qemu_irq cs_line = qdev_get_gpio_in_named(flash_dev,
+ SSI_GPIO_CS, 0);
+ sysbus_connect_irq(SYS_BUS_DEVICE(spi_dev), 1, cs_line);
+ }
+ }
+ }
+ }
+
+ sabrelite_binfo.ram_size = machine->ram_size;
+ sabrelite_binfo.kernel_filename = machine->kernel_filename;
+ sabrelite_binfo.kernel_cmdline = machine->kernel_cmdline;
+ sabrelite_binfo.initrd_filename = machine->initrd_filename;
+ sabrelite_binfo.nb_cpus = smp_cpus;
+ sabrelite_binfo.secure_boot = true;
+ sabrelite_binfo.write_secondary_boot = sabrelite_write_secondary;
+ sabrelite_binfo.secondary_cpu_reset_hook = sabrelite_reset_secondary;
+
+ if (!qtest_enabled()) {
+ arm_load_kernel(&s->soc.cpu[0], &sabrelite_binfo);
+ }
+}
+
+static void sabrelite_machine_init(MachineClass *mc)
+{
+ mc->desc = "Freescale i.MX6 Quad SABRE Lite Board (Cortex A9)";
+ mc->init = sabrelite_init;
+ mc->max_cpus = FSL_IMX6_NUM_CPUS;
+}
+
+DEFINE_MACHINE("sabrelite", sabrelite_machine_init)
--
2.5.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [Qemu-devel] [PATCH v6 0/6] Add i.MX6 (Single/Dual/Quad) support
2016-04-02 12:46 [Qemu-devel] [PATCH v6 0/6] Add i.MX6 (Single/Dual/Quad) support Jean-Christophe Dubois
` (5 preceding siblings ...)
2016-04-02 13:15 ` [Qemu-devel] [PATCH v6 6/6] i.MX: Add sabrelite i.MX6 emulation Jean-Christophe Dubois
@ 2016-04-02 14:22 ` Jean-Christophe DUBOIS
6 siblings, 0 replies; 8+ messages in thread
From: Jean-Christophe DUBOIS @ 2016-04-02 14:22 UTC (permalink / raw)
To: qemu-devel, peter.maydell, crosthwaite.peter
This will not compile on "target-arm.next" as I need to rework a bit the
header file included.
I am fixing it and will send a v7.
Sorry for the noise.
JC
Le 02/04/2016 14:46, Jean-Christophe Dubois a écrit :
> This patch series adds support for the Freescale i.MX6 processor.
>
> For now we only support the following devices:
> * up to 4 Cortex A9 cores
> * A9 MPCORE (SCU, GIC, TWD)
> * 5 i.MX UARTs
> * 2 EPIT timers
> * 1 GPT timer
> * 7 GPIO controllers
> * 6 SDHC controllers
> * 5 SPI controllers
> * 1 CCM device
> * 1 SRC device
> * 3 I2C devices
> * various ROM/RAM areas.
>
> This also adds the sabrelite board as a an actual platform for i.MX6.
>
> This series was tested by booting a 4.4 linux kernel (using the
> imx_v6_v7_defconfig file as kernel configuration).
>
> Note1: as sabrelite uses uart2 as console, you have to redirect the second
> QEMU serial port to stdout.
> qemu-system-arm -M sabrelite -display none ... -serial null -serial stdio
>
> Note2: You need to disable the GPIO section related to physical push buttons
> in the Linux DTS tree in order to avoid excecive interrupt triggering on
> GPIO devices for non existant buttons.
>
> Jean-Christophe Dubois (6):
> ARM: Factor out ARM on/off PSCI control functions
> i.MX: Add i.MX6 System Reset Controller device.
> FIFO: Add a FIFO32 implementation
> i.MX: Add the Freescale SPI Controller
> i.MX: Add i.MX6 SOC implementation.
> i.MX: Add sabrelite i.MX6 emulation.
>
> default-configs/arm-softmmu.mak | 1 +
> hw/arm/Makefile.objs | 1 +
> hw/arm/fsl-imx6.c | 449 +++++++++++++++++++++++++++++++++++++++
> hw/arm/sabrelite.c | 122 +++++++++++
> hw/misc/Makefile.objs | 1 +
> hw/misc/imx6_src.c | 264 +++++++++++++++++++++++
> hw/ssi/Makefile.objs | 1 +
> hw/ssi/imx_spi.c | 454 ++++++++++++++++++++++++++++++++++++++++
> include/hw/arm/fsl-imx6.h | 450 +++++++++++++++++++++++++++++++++++++++
> include/hw/misc/imx6_src.h | 73 +++++++
> include/hw/ssi/imx_spi.h | 103 +++++++++
> include/qemu/fifo32.h | 191 +++++++++++++++++
> target-arm/Makefile.objs | 1 +
> target-arm/arm-powerctl.c | 224 ++++++++++++++++++++
> target-arm/arm-powerctl.h | 75 +++++++
> target-arm/psci.c | 70 +------
> 16 files changed, 2417 insertions(+), 63 deletions(-)
> create mode 100644 hw/arm/fsl-imx6.c
> create mode 100644 hw/arm/sabrelite.c
> create mode 100644 hw/misc/imx6_src.c
> create mode 100644 hw/ssi/imx_spi.c
> create mode 100644 include/hw/arm/fsl-imx6.h
> create mode 100644 include/hw/misc/imx6_src.h
> create mode 100644 include/hw/ssi/imx_spi.h
> create mode 100644 include/qemu/fifo32.h
> create mode 100644 target-arm/arm-powerctl.c
> create mode 100644 target-arm/arm-powerctl.h
>
^ permalink raw reply [flat|nested] 8+ messages in thread