All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v7 0/7]  Netduino 2 Machine Model
@ 2014-12-10  8:46 Alistair Francis
  2014-12-10  8:46 ` [Qemu-devel] [PATCH v7 1/7] stm32f2xx_timer: Add the stm32f2xx Timer Alistair Francis
                   ` (7 more replies)
  0 siblings, 8 replies; 13+ messages in thread
From: Alistair Francis @ 2014-12-10  8:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, peter.crosthwaite, konstanty, martin.galvan

This patch series adds the Netduino 2 Machine to QEMU

Information on the board is avalible at:
http://www.netduino.com/netduino2/specs.htm

The git tree can be found at:
https://github.com/alistair23/qemu/tree/netduino2.7

This patch series makes some changes to the armv7m_init function
that allows the code to be reused with the Netduino 2 and the
Stellaris machines.

Some example code that runs on QEMU is avaliable at:
at: https://github.com/alistair23/CSSE3010-QEMU-Examples

There are more devices in the works, I figured I would just start
with these three

V7:
 - Rebase to QEMU 2.2
V6:
 - Rename the three devices to STM32FXX*
 - Correct the timer to use ns
 - Correct the number of devices that are inited
 - Rename memory regions
V5:
 - Remove the reset changes based on the ELF entry
V4:
 - Rebase
 - Correct timer units
V3:
 - Correct the timer interrupts
 - Update debug printing
 - Remove the sram_size argument from armv7m_init


Alistair Francis (7):
  stm32f2xx_timer: Add the stm32f2xx Timer
  stm32f2xx_USART: Add the stm32f2xx USART Controller
  stm32f2xx_SYSCFG: Add the stm32f2xx SYSCFG
  target_arm: Remove memory region init from armv7m_init
  target_arm: Parameterise the irq lines for armv7m_init
  stm32f205: Add the stm32f205 SoC
  netduino2: Add the Netduino 2 Machine

 default-configs/arm-softmmu.mak    |   4 +
 hw/arm/Makefile.objs               |   2 +
 hw/arm/armv7m.c                    |  38 +----
 hw/arm/netduino2.c                 |  54 ++++++
 hw/arm/stellaris.c                 |  27 ++-
 hw/arm/stm32f205_soc.c             | 157 ++++++++++++++++++
 hw/char/Makefile.objs              |   1 +
 hw/char/stm32f2xx_usart.c          | 219 ++++++++++++++++++++++++
 hw/misc/Makefile.objs              |   1 +
 hw/misc/stm32f2xx_syscfg.c         | 160 ++++++++++++++++++
 hw/timer/Makefile.objs             |   2 +
 hw/timer/stm32f2xx_timer.c         | 331 +++++++++++++++++++++++++++++++++++++
 include/hw/arm/arm.h               |   3 +-
 include/hw/arm/stm32f205_soc.h     |  69 ++++++++
 include/hw/char/stm32f2xx_usart.h  |  69 ++++++++
 include/hw/misc/stm32f2xx_syscfg.h |  61 +++++++
 include/hw/timer/stm32f2xx_timer.h | 101 +++++++++++
 17 files changed, 1261 insertions(+), 38 deletions(-)
 create mode 100644 hw/arm/netduino2.c
 create mode 100644 hw/arm/stm32f205_soc.c
 create mode 100644 hw/char/stm32f2xx_usart.c
 create mode 100644 hw/misc/stm32f2xx_syscfg.c
 create mode 100644 hw/timer/stm32f2xx_timer.c
 create mode 100644 include/hw/arm/stm32f205_soc.h
 create mode 100644 include/hw/char/stm32f2xx_usart.h
 create mode 100644 include/hw/misc/stm32f2xx_syscfg.h
 create mode 100644 include/hw/timer/stm32f2xx_timer.h

-- 
2.1.0

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

* [Qemu-devel] [PATCH v7 1/7] stm32f2xx_timer: Add the stm32f2xx Timer
  2014-12-10  8:46 [Qemu-devel] [PATCH v7 0/7] Netduino 2 Machine Model Alistair Francis
@ 2014-12-10  8:46 ` Alistair Francis
  2014-12-16  5:39   ` Peter Crosthwaite
  2014-12-10  8:46 ` [Qemu-devel] [PATCH v7 2/7] stm32f2xx_USART: Add the stm32f2xx USART Controller Alistair Francis
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 13+ messages in thread
From: Alistair Francis @ 2014-12-10  8:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, peter.crosthwaite, konstanty, martin.galvan

This patch adds the stm32f2xx timers: TIM2, TIM3, TIM4 and TIM5
to QEMU.

Signed-off-by: Alistair Francis <alistair23@gmail.com>
---
V6:
 - Rename to STM32F2XX
 - Change the timer calculations to use ns
 - Update the value to timer_mod to ensure it is in ns
 - Account for reloadable/resetable timer
    - Thanks to Peter C for pointing this out
V4:
 - Update timer units again
    - Thanks to Peter C
V3:
 - Update debug statements
 - Correct the units for timer_mod
 - Correctly set timer_offset from resets
V2:
 - Reorder the Makefile config
 - Fix up the debug printing
 - Correct the timer event trigger

 default-configs/arm-softmmu.mak    |   1 +
 hw/timer/Makefile.objs             |   2 +
 hw/timer/stm32f2xx_timer.c         | 331 +++++++++++++++++++++++++++++++++++++
 include/hw/timer/stm32f2xx_timer.h | 101 +++++++++++
 4 files changed, 435 insertions(+)
 create mode 100644 hw/timer/stm32f2xx_timer.c
 create mode 100644 include/hw/timer/stm32f2xx_timer.h

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index f3513fa..faea100 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -78,6 +78,7 @@ CONFIG_NSERIES=y
 CONFIG_REALVIEW=y
 CONFIG_ZAURUS=y
 CONFIG_ZYNQ=y
+CONFIG_STM32F2XX_TIMER=y
 
 CONFIG_VERSATILE_PCI=y
 CONFIG_VERSATILE_I2C=y
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index 2c86c3d..133bd0d 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -31,3 +31,5 @@ obj-$(CONFIG_DIGIC) += digic-timer.o
 obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
 
 obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o
+
+common-obj-$(CONFIG_STM32F2XX_TIMER) += stm32f2xx_timer.o
diff --git a/hw/timer/stm32f2xx_timer.c b/hw/timer/stm32f2xx_timer.c
new file mode 100644
index 0000000..df27540
--- /dev/null
+++ b/hw/timer/stm32f2xx_timer.c
@@ -0,0 +1,331 @@
+/*
+ * STM32F2XX Timer
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/timer/stm32f2xx_timer.h"
+
+#ifndef STM_TIMER_ERR_DEBUG
+#define STM_TIMER_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(lvl, fmt, args...) do { \
+    if (STM_TIMER_ERR_DEBUG >= lvl) { \
+        qemu_log("%s: " fmt, __func__, ## args); \
+    } \
+} while (0);
+
+#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
+
+static void stm32f2xx_timer_set_alarm(STM32F2XXTimerState *s);
+
+static void stm32f2xx_timer_interrupt(void *opaque)
+{
+    STM32F2XXTimerState *s = opaque;
+
+    DB_PRINT("Interrupt\n");
+
+    if (s->tim_dier & TIM_DIER_UIE && s->tim_cr1 & TIM_CR1_CEN) {
+        s->tim_sr |= 1;
+        qemu_irq_pulse(s->irq);
+        stm32f2xx_timer_set_alarm(s);
+    }
+}
+
+static void stm32f2xx_timer_set_alarm(STM32F2XXTimerState *s)
+{
+    uint32_t ticks;
+    int64_t now;
+
+    DB_PRINT("Alarm set at: 0x%x\n", s->tim_cr1);
+
+    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    ticks = s->tim_arr -
+            ((muldiv64(s->freq_hz, now, 1000000000ULL) - s->tick_offset) /
+            (s->tim_psc + 1));
+
+    DB_PRINT("Alarm set in %d ticks\n", ticks);
+
+    if (ticks == 0) {
+        timer_del(s->timer);
+        stm32f2xx_timer_interrupt(s);
+    } else {
+        timer_mod(s->timer, now +
+                  muldiv64(ticks, 1000000000ULL, get_ticks_per_sec()));
+
+        DB_PRINT("Wait Time: %" PRId64 " ticks\n",
+                 now + muldiv64(ticks, 1000000000ULL, get_ticks_per_sec()));
+    }
+}
+
+static void stm32f2xx_timer_reset(DeviceState *dev)
+{
+    STM32F2XXTimerState *s = STM32F2XXTIMER(dev);
+
+    s->tim_cr1 = 0;
+    s->tim_cr2 = 0;
+    s->tim_smcr = 0;
+    s->tim_dier = 0;
+    s->tim_sr = 0;
+    s->tim_egr = 0;
+    s->tim_ccmr1 = 0;
+    s->tim_ccmr2 = 0;
+    s->tim_ccer = 0;
+    s->tim_cnt = 0;
+    s->tim_psc = 0;
+    s->tim_arr = 0;
+    s->tim_ccr1 = 0;
+    s->tim_ccr2 = 0;
+    s->tim_ccr3 = 0;
+    s->tim_ccr4 = 0;
+    s->tim_dcr = 0;
+    s->tim_dmar = 0;
+    s->tim_or = 0;
+
+    s->tick_offset = muldiv64(s->freq_hz,
+                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
+                              1000000000ULL);
+
+    stm32f2xx_timer_set_alarm(s);
+}
+
+static uint64_t stm32f2xx_timer_read(void *opaque, hwaddr offset,
+                           unsigned size)
+{
+    STM32F2XXTimerState *s = opaque;
+
+    DB_PRINT("Read 0x%"HWADDR_PRIx"\n", offset);
+
+    switch (offset) {
+    case TIM_CR1:
+        return s->tim_cr1;
+    case TIM_CR2:
+        return s->tim_cr2;
+    case TIM_SMCR:
+        return s->tim_smcr;
+    case TIM_DIER:
+        return s->tim_dier;
+    case TIM_SR:
+        return s->tim_sr;
+    case TIM_EGR:
+        return s->tim_egr;
+    case TIM_CCMR1:
+        return s->tim_ccmr1;
+    case TIM_CCMR2:
+        return s->tim_ccmr2;
+    case TIM_CCER:
+        return s->tim_ccer;
+    case TIM_CNT:
+        s->tim_cnt = muldiv64(s->freq_hz,
+                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
+                              1000000000ULL) - s->tick_offset;
+        return s->tim_cnt;
+    case TIM_PSC:
+        return s->tim_psc;
+    case TIM_ARR:
+        return s->tim_arr;
+    case TIM_CCR1:
+        return s->tim_ccr1;
+    case TIM_CCR2:
+        return s->tim_ccr2;
+    case TIM_CCR3:
+        return s->tim_ccr3;
+    case TIM_CCR4:
+        return s->tim_ccr4;
+    case TIM_DCR:
+        return s->tim_dcr;
+    case TIM_DMAR:
+        return s->tim_dmar;
+    case TIM_OR:
+        return s->tim_or;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, offset);
+    }
+
+    return 0;
+}
+
+static void stm32f2xx_timer_write(void *opaque, hwaddr offset,
+                        uint64_t val64, unsigned size)
+{
+    STM32F2XXTimerState *s = opaque;
+    uint32_t value = val64;
+
+    DB_PRINT("Write 0x%x, 0x%"HWADDR_PRIx"\n", value, offset);
+
+    switch (offset) {
+    case TIM_CR1:
+        s->tim_cr1 = value;
+        return;
+    case TIM_CR2:
+        s->tim_cr2 = value;
+        return;
+    case TIM_SMCR:
+        s->tim_smcr = value;
+        return;
+    case TIM_DIER:
+        s->tim_dier = value;
+        return;
+    case TIM_SR:
+        /* This is set by hardware and cleared by software */
+        s->tim_sr &= value;
+        return;
+    case TIM_EGR:
+        s->tim_egr = value;
+        if (s->tim_egr & TIM_EGR_UG) {
+            /* Re-init the counter */
+            stm32f2xx_timer_reset(DEVICE(s));
+        }
+        return;
+    case TIM_CCMR1:
+        s->tim_ccmr1 = value;
+        return;
+    case TIM_CCMR2:
+        s->tim_ccmr2 = value;
+        return;
+    case TIM_CCER:
+        s->tim_ccer = value;
+        return;
+    case TIM_CNT:
+        /* The guest is changing the clock counter.
+         * Subtract the difference between the value and the current time
+         * from tick_offset and update the timer alarm.
+         */
+        s->tick_offset -= value - (muldiv64(s->freq_hz,
+                                   qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
+                                   1000000000ULL) - s->tick_offset);
+        s->tim_cnt = value;
+        stm32f2xx_timer_set_alarm(s);
+        return;
+    case TIM_PSC:
+        s->tim_psc = value;
+        stm32f2xx_timer_set_alarm(s);
+        return;
+    case TIM_ARR:
+        s->tim_arr = value;
+        stm32f2xx_timer_set_alarm(s);
+        return;
+    case TIM_CCR1:
+        s->tim_ccr1 = value;
+        return;
+    case TIM_CCR2:
+        s->tim_ccr2 = value;
+        return;
+    case TIM_CCR3:
+        s->tim_ccr3 = value;
+        return;
+    case TIM_CCR4:
+        s->tim_ccr4 = value;
+        return;
+    case TIM_DCR:
+        s->tim_dcr = value;
+        return;
+    case TIM_DMAR:
+        s->tim_dmar = value;
+        return;
+    case TIM_OR:
+        s->tim_or = value;
+        return;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, offset);
+    }
+}
+
+static const MemoryRegionOps stm32f2xx_timer_ops = {
+    .read = stm32f2xx_timer_read,
+    .write = stm32f2xx_timer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_stm32f2xx_timer = {
+    .name = TYPE_STM32F2XX_TIMER,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(tick_offset, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_cr1, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_cr2, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_smcr, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_dier, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_sr, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_egr, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_ccmr1, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_ccmr2, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_ccer, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_cnt, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_psc, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_arr, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_ccr1, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_ccr2, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_ccr3, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_ccr4, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_dcr, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_dmar, STM32F2XXTimerState),
+        VMSTATE_UINT32(tim_or, STM32F2XXTimerState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property stm32f2xx_timer_properties[] = {
+    DEFINE_PROP_UINT64("clock-frequency", struct STM32F2XXTimerState,
+                       freq_hz, 1000000000),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void stm32f2xx_timer_init(Object *obj)
+{
+    STM32F2XXTimerState *s = STM32F2XXTIMER(obj);
+
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+
+    memory_region_init_io(&s->iomem, obj, &stm32f2xx_timer_ops, s,
+                          "stm32f2xx_timer", 0x2000);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
+
+    s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, stm32f2xx_timer_interrupt, s);
+}
+
+static void stm32f2xx_timer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = stm32f2xx_timer_reset;
+    dc->props = stm32f2xx_timer_properties;
+    dc->vmsd = &vmstate_stm32f2xx_timer;
+}
+
+static const TypeInfo stm32f2xx_timer_info = {
+    .name          = TYPE_STM32F2XX_TIMER,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(STM32F2XXTimerState),
+    .instance_init = stm32f2xx_timer_init,
+    .class_init    = stm32f2xx_timer_class_init,
+};
+
+static void stm32f2xx_timer_register_types(void)
+{
+    type_register_static(&stm32f2xx_timer_info);
+}
+
+type_init(stm32f2xx_timer_register_types)
diff --git a/include/hw/timer/stm32f2xx_timer.h b/include/hw/timer/stm32f2xx_timer.h
new file mode 100644
index 0000000..512fa16
--- /dev/null
+++ b/include/hw/timer/stm32f2xx_timer.h
@@ -0,0 +1,101 @@
+/*
+ * STM32F2XX Timer
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef HW_STM_TIMER_H
+#define HW_STM_TIMER_H
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+
+#define TIM_CR1      0x00
+#define TIM_CR2      0x04
+#define TIM_SMCR     0x08
+#define TIM_DIER     0x0C
+#define TIM_SR       0x10
+#define TIM_EGR      0x14
+#define TIM_CCMR1    0x18
+#define TIM_CCMR2    0x1C
+#define TIM_CCER     0x20
+#define TIM_CNT      0x24
+#define TIM_PSC      0x28
+#define TIM_ARR      0x2C
+#define TIM_CCR1     0x34
+#define TIM_CCR2     0x38
+#define TIM_CCR3     0x3C
+#define TIM_CCR4     0x40
+#define TIM_DCR      0x48
+#define TIM_DMAR     0x4C
+#define TIM_OR       0x50
+
+#define TIM_CR1_CEN   1
+
+#define TIM_EGR_UG 1
+
+#define TIM_CCER_CC2E   (1 << 4)
+#define TIM_CCMR1_OC2M2 (1 << 14)
+#define TIM_CCMR1_OC2M1 (1 << 13)
+#define TIM_CCMR1_OC2M0 (1 << 12)
+#define TIM_CCMR1_OC2PE (1 << 11)
+
+#define TIM_DIER_UIE  1
+
+#define TYPE_STM32F2XX_TIMER "stm32f2xx-timer"
+#define STM32F2XXTIMER(obj) OBJECT_CHECK(STM32F2XXTimerState, \
+                            (obj), TYPE_STM32F2XX_TIMER)
+
+typedef struct STM32F2XXTimerState {
+    /* <private> */
+    SysBusDevice parent_obj;
+
+    /* <public> */
+    MemoryRegion iomem;
+    QEMUTimer *timer;
+    qemu_irq irq;
+
+    uint32_t tick_offset;
+    uint64_t freq_hz;
+
+    uint32_t tim_cr1;
+    uint32_t tim_cr2;
+    uint32_t tim_smcr;
+    uint32_t tim_dier;
+    uint32_t tim_sr;
+    uint32_t tim_egr;
+    uint32_t tim_ccmr1;
+    uint32_t tim_ccmr2;
+    uint32_t tim_ccer;
+    uint32_t tim_cnt;
+    uint32_t tim_psc;
+    uint32_t tim_arr;
+    uint32_t tim_ccr1;
+    uint32_t tim_ccr2;
+    uint32_t tim_ccr3;
+    uint32_t tim_ccr4;
+    uint32_t tim_dcr;
+    uint32_t tim_dmar;
+    uint32_t tim_or;
+} STM32F2XXTimerState;
+
+#endif
-- 
2.1.0

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

* [Qemu-devel] [PATCH v7 2/7] stm32f2xx_USART: Add the stm32f2xx USART Controller
  2014-12-10  8:46 [Qemu-devel] [PATCH v7 0/7] Netduino 2 Machine Model Alistair Francis
  2014-12-10  8:46 ` [Qemu-devel] [PATCH v7 1/7] stm32f2xx_timer: Add the stm32f2xx Timer Alistair Francis
@ 2014-12-10  8:46 ` Alistair Francis
  2014-12-16  5:47   ` Peter Crosthwaite
  2014-12-10  8:46 ` [Qemu-devel] [PATCH v7 3/7] stm32f2xx_SYSCFG: Add the stm32f2xx SYSCFG Alistair Francis
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 13+ messages in thread
From: Alistair Francis @ 2014-12-10  8:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, peter.crosthwaite, konstanty, martin.galvan

This patch adds the stm32f2xx USART controller
(UART also uses the same controller).

Signed-off-by: Alistair Francis <alistair23@gmail.com>
---
V6:
 - Rename to STM32F2XX
 - Fix up unimplemented printing
 - Add a qemu_chr_accept()
V3:
 - Update debug printing
V2:
 - Drop charecters if the device is not enabled
    - Thanks to Peter C

 default-configs/arm-softmmu.mak   |   1 +
 hw/char/Makefile.objs             |   1 +
 hw/char/stm32f2xx_usart.c         | 219 ++++++++++++++++++++++++++++++++++++++
 include/hw/char/stm32f2xx_usart.h |  69 ++++++++++++
 4 files changed, 290 insertions(+)
 create mode 100644 hw/char/stm32f2xx_usart.c
 create mode 100644 include/hw/char/stm32f2xx_usart.h

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index faea100..1348104 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -79,6 +79,7 @@ CONFIG_REALVIEW=y
 CONFIG_ZAURUS=y
 CONFIG_ZYNQ=y
 CONFIG_STM32F2XX_TIMER=y
+CONFIG_STM32F2XX_USART=y
 
 CONFIG_VERSATILE_PCI=y
 CONFIG_VERSATILE_I2C=y
diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
index 317385d..5931cc8 100644
--- a/hw/char/Makefile.objs
+++ b/hw/char/Makefile.objs
@@ -15,6 +15,7 @@ obj-$(CONFIG_OMAP) += omap_uart.o
 obj-$(CONFIG_SH4) += sh_serial.o
 obj-$(CONFIG_PSERIES) += spapr_vty.o
 obj-$(CONFIG_DIGIC) += digic-uart.o
+obj-$(CONFIG_STM32F2XX_USART) += stm32f2xx_usart.o
 
 common-obj-$(CONFIG_ETRAXFS) += etraxfs_ser.o
 common-obj-$(CONFIG_ISA_DEBUG) += debugcon.o
diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c
new file mode 100644
index 0000000..843ff4a
--- /dev/null
+++ b/hw/char/stm32f2xx_usart.c
@@ -0,0 +1,219 @@
+/*
+ * STM32F2XX USART
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/char/stm32f2xx_usart.h"
+
+#ifndef STM_USART_ERR_DEBUG
+#define STM_USART_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(lvl, fmt, args...) do { \
+    if (STM_USART_ERR_DEBUG >= lvl) { \
+        qemu_log("%s: " fmt, __func__, ## args); \
+    } \
+} while (0);
+
+#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
+
+static int stm32f2xx_usart_can_receive(void *opaque)
+{
+    STM32F2XXUsartState *s = opaque;
+
+    if (!(s->usart_sr & USART_SR_RXNE)) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static void stm32f2xx_usart_receive(void *opaque, const uint8_t *buf, int size)
+{
+    STM32F2XXUsartState *s = opaque;
+
+    s->usart_dr = *buf;
+
+    if (!(s->usart_cr1 & USART_CR1_UE && s->usart_cr1 & USART_CR1_RE)) {
+        /* USART not enabled - drop the chars */
+        DB_PRINT("Dropping the chars\n");
+        return;
+    }
+
+    s->usart_sr |= USART_SR_RXNE;
+
+    if (s->usart_cr1 & USART_CR1_RXNEIE) {
+        qemu_set_irq(s->irq, 1);
+    }
+
+    DB_PRINT("Receiving: %c\n", s->usart_dr);
+}
+
+static void stm32f2xx_usart_reset(DeviceState *dev)
+{
+    STM32F2XXUsartState *s = STM32F2XX_USART(dev);
+
+    s->usart_sr = USART_SR_RESET;
+    s->usart_dr = 0x00000000;
+    s->usart_brr = 0x00000000;
+    s->usart_cr1 = 0x00000000;
+    s->usart_cr2 = 0x00000000;
+    s->usart_cr3 = 0x00000000;
+    s->usart_gtpr = 0x00000000;
+}
+
+static uint64_t stm32f2xx_usart_read(void *opaque, hwaddr addr,
+                                       unsigned int size)
+{
+    STM32F2XXUsartState *s = opaque;
+    uint64_t retvalue;
+
+    DB_PRINT("Read 0x%"HWADDR_PRIx"\n", addr);
+
+    switch (addr) {
+    case USART_SR:
+        retvalue = s->usart_sr;
+        s->usart_sr &= ~USART_SR_TC;
+        if (s->chr) {
+            qemu_chr_accept_input(s->chr);
+        }
+        return retvalue;
+    case USART_DR:
+        DB_PRINT("Value: 0x%" PRIx32 ", %c\n", s->usart_dr, (char) s->usart_dr);
+        s->usart_sr |= USART_SR_TXE;
+        s->usart_sr &= ~USART_SR_RXNE;
+        if (s->chr) {
+            qemu_chr_accept_input(s->chr);
+        }
+        return s->usart_dr & 0x3FF;
+    case USART_BRR:
+        return s->usart_brr;
+    case USART_CR1:
+        return s->usart_cr1;
+    case USART_CR2:
+        return s->usart_cr2;
+    case USART_CR3:
+        return s->usart_cr3;
+    case USART_GTPR:
+        return s->usart_gtpr;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+        return 0;
+    }
+
+    return 0;
+}
+
+static void stm32f2xx_usart_write(void *opaque, hwaddr addr,
+                                  uint64_t val64, unsigned int size)
+{
+    STM32F2XXUsartState *s = opaque;
+    uint32_t value = val64;
+    unsigned char ch;
+
+    DB_PRINT("Write 0x%" PRIx32 ", 0x%"HWADDR_PRIx"\n", value, addr);
+
+    switch (addr) {
+    case USART_SR:
+        if (value <= 0x3FF) {
+            s->usart_sr = value;
+        } else {
+            s->usart_sr &= value;
+        }
+        return;
+    case USART_DR:
+        if (value < 0xF000) {
+            ch = value;
+            if (s->chr) {
+                qemu_chr_fe_write_all(s->chr, &ch, 1);
+            }
+            s->usart_sr |= USART_SR_TC;
+            s->usart_sr &= ~USART_SR_TXE;
+        }
+        return;
+    case USART_BRR:
+        s->usart_brr = value;
+        return;
+    case USART_CR1:
+        s->usart_cr1 = value;
+        return;
+    case USART_CR2:
+        s->usart_cr2 = value;
+        return;
+    case USART_CR3:
+        s->usart_cr3 = value;
+        return;
+    case USART_GTPR:
+        s->usart_gtpr = value;
+        return;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+    }
+}
+
+static const MemoryRegionOps stm32f2xx_usart_ops = {
+    .read = stm32f2xx_usart_read,
+    .write = stm32f2xx_usart_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void stm32f2xx_usart_init(Object *obj)
+{
+    STM32F2XXUsartState *s = STM32F2XX_USART(obj);
+
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+
+    memory_region_init_io(&s->mmio, obj, &stm32f2xx_usart_ops, s,
+                          TYPE_STM32F2XX_USART, 0x2000);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+    s->chr = qemu_char_get_next_serial();
+
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, stm32f2xx_usart_can_receive,
+                              stm32f2xx_usart_receive, NULL, s);
+    }
+}
+
+static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = stm32f2xx_usart_reset;
+}
+
+static const TypeInfo stm32f2xx_usart_info = {
+    .name          = TYPE_STM32F2XX_USART,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(STM32F2XXUsartState),
+    .instance_init = stm32f2xx_usart_init,
+    .class_init    = stm32f2xx_usart_class_init,
+};
+
+static void stm32f2xx_usart_register_types(void)
+{
+    type_register_static(&stm32f2xx_usart_info);
+}
+
+type_init(stm32f2xx_usart_register_types)
diff --git a/include/hw/char/stm32f2xx_usart.h b/include/hw/char/stm32f2xx_usart.h
new file mode 100644
index 0000000..c9fad3c
--- /dev/null
+++ b/include/hw/char/stm32f2xx_usart.h
@@ -0,0 +1,69 @@
+/*
+ * STM32F2XX USART
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/sysbus.h"
+#include "sysemu/char.h"
+#include "hw/hw.h"
+
+#define USART_SR   0x00
+#define USART_DR   0x04
+#define USART_BRR  0x08
+#define USART_CR1  0x0C
+#define USART_CR2  0x10
+#define USART_CR3  0x14
+#define USART_GTPR 0x18
+
+#define USART_SR_RESET 0x00C00000
+
+#define USART_SR_TXE  (1 << 7)
+#define USART_SR_TC   (1 << 6)
+#define USART_SR_RXNE (1 << 5)
+
+#define USART_CR1_UE  (1 << 13)
+#define USART_CR1_RXNEIE  (1 << 5)
+#define USART_CR1_TE  (1 << 3)
+#define USART_CR1_RE  (1 << 2)
+
+#define TYPE_STM32F2XX_USART "stm32f2xx-usart"
+#define STM32F2XX_USART(obj) \
+    OBJECT_CHECK(STM32F2XXUsartState, (obj), TYPE_STM32F2XX_USART)
+
+typedef struct {
+    /* <private> */
+    SysBusDevice parent_obj;
+
+    /* <public> */
+    MemoryRegion mmio;
+
+    uint32_t usart_sr;
+    uint32_t usart_dr;
+    uint32_t usart_brr;
+    uint32_t usart_cr1;
+    uint32_t usart_cr2;
+    uint32_t usart_cr3;
+    uint32_t usart_gtpr;
+
+    CharDriverState *chr;
+    qemu_irq irq;
+} STM32F2XXUsartState;
-- 
2.1.0

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

* [Qemu-devel] [PATCH v7 3/7] stm32f2xx_SYSCFG: Add the stm32f2xx SYSCFG
  2014-12-10  8:46 [Qemu-devel] [PATCH v7 0/7] Netduino 2 Machine Model Alistair Francis
  2014-12-10  8:46 ` [Qemu-devel] [PATCH v7 1/7] stm32f2xx_timer: Add the stm32f2xx Timer Alistair Francis
  2014-12-10  8:46 ` [Qemu-devel] [PATCH v7 2/7] stm32f2xx_USART: Add the stm32f2xx USART Controller Alistair Francis
@ 2014-12-10  8:46 ` Alistair Francis
  2014-12-10  8:46 ` [Qemu-devel] [PATCH v7 4/7] target_arm: Remove memory region init from armv7m_init Alistair Francis
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Alistair Francis @ 2014-12-10  8:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, peter.crosthwaite, konstanty, martin.galvan

This patch adds the stm32f2xx System Configuration
Controller. This is used to configure what memory is mapped
at address 0 (although that is not supported) as well
as configure how the EXTI interrupts work (also not
supported at the moment).

This device is not required for basic examples, but more
complex systems will require it (as well as the EXTI device)

Signed-off-by: Alistair Francis <alistair23@gmail.com>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
---
V6:
 - Rename to STM32F2XX
 - Remove all casts from debug printing
V5:
 - Correct the masks used for writing
V3:
 - Update debug printing

 default-configs/arm-softmmu.mak    |   1 +
 hw/misc/Makefile.objs              |   1 +
 hw/misc/stm32f2xx_syscfg.c         | 160 +++++++++++++++++++++++++++++++++++++
 include/hw/misc/stm32f2xx_syscfg.h |  61 ++++++++++++++
 4 files changed, 223 insertions(+)
 create mode 100644 hw/misc/stm32f2xx_syscfg.c
 create mode 100644 include/hw/misc/stm32f2xx_syscfg.h

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 1348104..a5aab7f 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -80,6 +80,7 @@ CONFIG_ZAURUS=y
 CONFIG_ZYNQ=y
 CONFIG_STM32F2XX_TIMER=y
 CONFIG_STM32F2XX_USART=y
+CONFIG_STM32F2XX_SYSCFG=y
 
 CONFIG_VERSATILE_PCI=y
 CONFIG_VERSATILE_I2C=y
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 979e532..f2c0082 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -39,5 +39,6 @@ obj-$(CONFIG_OMAP) += omap_sdrc.o
 obj-$(CONFIG_OMAP) += omap_tap.o
 obj-$(CONFIG_SLAVIO) += slavio_misc.o
 obj-$(CONFIG_ZYNQ) += zynq_slcr.o
+obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o
 
 obj-$(CONFIG_PVPANIC) += pvpanic.o
diff --git a/hw/misc/stm32f2xx_syscfg.c b/hw/misc/stm32f2xx_syscfg.c
new file mode 100644
index 0000000..4ae4042
--- /dev/null
+++ b/hw/misc/stm32f2xx_syscfg.c
@@ -0,0 +1,160 @@
+/*
+ * STM32F2XX SYSCFG
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/misc/stm32f2xx_syscfg.h"
+
+#ifndef STM_SYSCFG_ERR_DEBUG
+#define STM_SYSCFG_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(lvl, fmt, args...) do { \
+    if (STM_SYSCFG_ERR_DEBUG >= lvl) { \
+        qemu_log("%s: " fmt, __func__, ## args); \
+    } \
+} while (0);
+
+#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
+
+static void stm32f2xx_syscfg_reset(DeviceState *dev)
+{
+    STM32F2XXSyscfgState *s = STM32F2XX_SYSCFG(dev);
+
+    s->syscfg_memrmp = 0x00000000;
+    s->syscfg_pmc = 0x00000000;
+    s->syscfg_exticr1 = 0x00000000;
+    s->syscfg_exticr2 = 0x00000000;
+    s->syscfg_exticr3 = 0x00000000;
+    s->syscfg_exticr4 = 0x00000000;
+    s->syscfg_cmpcr = 0x00000000;
+}
+
+static uint64_t stm32f2xx_syscfg_read(void *opaque, hwaddr addr,
+                                     unsigned int size)
+{
+    STM32F2XXSyscfgState *s = opaque;
+
+    DB_PRINT("0x%"HWADDR_PRIx"\n", addr);
+
+    switch (addr) {
+    case SYSCFG_MEMRMP:
+        return s->syscfg_memrmp;
+    case SYSCFG_PMC:
+        return s->syscfg_pmc;
+    case SYSCFG_EXTICR1:
+        return s->syscfg_exticr1;
+    case SYSCFG_EXTICR2:
+        return s->syscfg_exticr2;
+    case SYSCFG_EXTICR3:
+        return s->syscfg_exticr3;
+    case SYSCFG_EXTICR4:
+        return s->syscfg_exticr4;
+    case SYSCFG_CMPCR:
+        return s->syscfg_cmpcr;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+        return 0;
+    }
+
+    return 0;
+}
+
+static void stm32f2xx_syscfg_write(void *opaque, hwaddr addr,
+                       uint64_t val64, unsigned int size)
+{
+    STM32F2XXSyscfgState *s = opaque;
+    uint32_t value = val64;
+
+    DB_PRINT("0x%x, 0x%"HWADDR_PRIx"\n", value, addr);
+
+    switch (addr) {
+    case SYSCFG_MEMRMP:
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Changeing the memory mapping isn't supported " \
+                      "in QEMU\n", __func__);
+        return;
+    case SYSCFG_PMC:
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Changeing the memory mapping isn't supported " \
+                      "in QEMU\n", __func__);
+        return;
+    case SYSCFG_EXTICR1:
+        s->syscfg_exticr1 = (value & 0xFFFF);
+        return;
+    case SYSCFG_EXTICR2:
+        s->syscfg_exticr2 = (value & 0xFFFF);
+        return;
+    case SYSCFG_EXTICR3:
+        s->syscfg_exticr3 = (value & 0xFFFF);
+        return;
+    case SYSCFG_EXTICR4:
+        s->syscfg_exticr4 = (value & 0xFFFF);
+        return;
+    case SYSCFG_CMPCR:
+        s->syscfg_cmpcr = value;
+        return;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+    }
+}
+
+static const MemoryRegionOps stm32f2xx_syscfg_ops = {
+    .read = stm32f2xx_syscfg_read,
+    .write = stm32f2xx_syscfg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void stm32f2xx_syscfg_init(Object *obj)
+{
+    STM32F2XXSyscfgState *s = STM32F2XX_SYSCFG(obj);
+
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+
+    memory_region_init_io(&s->mmio, obj, &stm32f2xx_syscfg_ops, s,
+                          TYPE_STM32F2XX_SYSCFG, 0x400);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static void stm32f2xx_syscfg_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = stm32f2xx_syscfg_reset;
+}
+
+static const TypeInfo stm32f2xx_syscfg_info = {
+    .name          = TYPE_STM32F2XX_SYSCFG,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(STM32F2XXSyscfgState),
+    .instance_init = stm32f2xx_syscfg_init,
+    .class_init    = stm32f2xx_syscfg_class_init,
+};
+
+static void stm32f2xx_syscfg_register_types(void)
+{
+    type_register_static(&stm32f2xx_syscfg_info);
+}
+
+type_init(stm32f2xx_syscfg_register_types)
diff --git a/include/hw/misc/stm32f2xx_syscfg.h b/include/hw/misc/stm32f2xx_syscfg.h
new file mode 100644
index 0000000..f3349e9
--- /dev/null
+++ b/include/hw/misc/stm32f2xx_syscfg.h
@@ -0,0 +1,61 @@
+/*
+ * STM32F2XX SYSCFG
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef HW_STM_SYSCFG_H
+#define HW_STM_SYSCFG_H
+
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+
+#define SYSCFG_MEMRMP  0x00
+#define SYSCFG_PMC     0x04
+#define SYSCFG_EXTICR1 0x08
+#define SYSCFG_EXTICR2 0x0C
+#define SYSCFG_EXTICR3 0x10
+#define SYSCFG_EXTICR4 0x14
+#define SYSCFG_CMPCR   0x20
+
+#define TYPE_STM32F2XX_SYSCFG "stm32f2xx-syscfg"
+#define STM32F2XX_SYSCFG(obj) \
+    OBJECT_CHECK(STM32F2XXSyscfgState, (obj), TYPE_STM32F2XX_SYSCFG)
+
+typedef struct {
+    /* <private> */
+    SysBusDevice parent_obj;
+
+    /* <public> */
+    MemoryRegion mmio;
+
+    uint32_t syscfg_memrmp;
+    uint32_t syscfg_pmc;
+    uint32_t syscfg_exticr1;
+    uint32_t syscfg_exticr2;
+    uint32_t syscfg_exticr3;
+    uint32_t syscfg_exticr4;
+    uint32_t syscfg_cmpcr;
+
+    qemu_irq irq;
+} STM32F2XXSyscfgState;
+
+#endif
-- 
2.1.0

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

* [Qemu-devel] [PATCH v7 4/7] target_arm: Remove memory region init from armv7m_init
  2014-12-10  8:46 [Qemu-devel] [PATCH v7 0/7] Netduino 2 Machine Model Alistair Francis
                   ` (2 preceding siblings ...)
  2014-12-10  8:46 ` [Qemu-devel] [PATCH v7 3/7] stm32f2xx_SYSCFG: Add the stm32f2xx SYSCFG Alistair Francis
@ 2014-12-10  8:46 ` Alistair Francis
  2014-12-10  8:47 ` [Qemu-devel] [PATCH v7 5/7] target_arm: Parameterise the irq lines for armv7m_init Alistair Francis
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Alistair Francis @ 2014-12-10  8:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, peter.crosthwaite, konstanty, martin.galvan

This patch moves the memory region init code from the
armv7m_init function to the stellaris_init function

Signed-off-by: Alistair Francis <alistair23@gmail.com>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
---
V3:
 - Rename the flash_size argument to mem_size
 - Remove the sram_size and related code
    - Thanks to Peter C
V2:
 - Change the memory region names to match the machine

 hw/arm/armv7m.c      | 33 +++------------------------------
 hw/arm/stellaris.c   | 24 ++++++++++++++++++++----
 include/hw/arm/arm.h |  3 +--
 3 files changed, 24 insertions(+), 36 deletions(-)

diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c
index ef24ca4..50281f7 100644
--- a/hw/arm/armv7m.c
+++ b/hw/arm/armv7m.c
@@ -163,11 +163,10 @@ static void armv7m_reset(void *opaque)
 }
 
 /* Init CPU and memory for a v7-M based board.
-   flash_size and sram_size are in kb.
+   mem_size is in bytes.
    Returns the NVIC array.  */
 
-qemu_irq *armv7m_init(MemoryRegion *system_memory,
-                      int flash_size, int sram_size,
+qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size,
                       const char *kernel_filename, const char *cpu_model)
 {
     ARMCPU *cpu;
@@ -180,13 +179,8 @@ qemu_irq *armv7m_init(MemoryRegion *system_memory,
     uint64_t lowaddr;
     int i;
     int big_endian;
-    MemoryRegion *sram = g_new(MemoryRegion, 1);
-    MemoryRegion *flash = g_new(MemoryRegion, 1);
     MemoryRegion *hack = g_new(MemoryRegion, 1);
 
-    flash_size *= 1024;
-    sram_size *= 1024;
-
     if (cpu_model == NULL) {
 	cpu_model = "cortex-m3";
     }
@@ -197,27 +191,6 @@ qemu_irq *armv7m_init(MemoryRegion *system_memory,
     }
     env = &cpu->env;
 
-#if 0
-    /* > 32Mb SRAM gets complicated because it overlaps the bitband area.
-       We don't have proper commandline options, so allocate half of memory
-       as SRAM, up to a maximum of 32Mb, and the rest as code.  */
-    if (ram_size > (512 + 32) * 1024 * 1024)
-        ram_size = (512 + 32) * 1024 * 1024;
-    sram_size = (ram_size / 2) & TARGET_PAGE_MASK;
-    if (sram_size > 32 * 1024 * 1024)
-        sram_size = 32 * 1024 * 1024;
-    code_size = ram_size - sram_size;
-#endif
-
-    /* Flash programming is done via the SCU, so pretend it is ROM.  */
-    memory_region_init_ram(flash, NULL, "armv7m.flash", flash_size,
-                           &error_abort);
-    vmstate_register_ram_global(flash);
-    memory_region_set_readonly(flash, true);
-    memory_region_add_subregion(system_memory, 0, flash);
-    memory_region_init_ram(sram, NULL, "armv7m.sram", sram_size, &error_abort);
-    vmstate_register_ram_global(sram);
-    memory_region_add_subregion(system_memory, 0x20000000, sram);
     armv7m_bitband_init();
 
     nvic = qdev_create(NULL, "armv7m_nvic");
@@ -244,7 +217,7 @@ qemu_irq *armv7m_init(MemoryRegion *system_memory,
         image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
                               NULL, big_endian, ELF_MACHINE, 1);
         if (image_size < 0) {
-            image_size = load_image_targphys(kernel_filename, 0, flash_size);
+            image_size = load_image_targphys(kernel_filename, 0, mem_size);
             lowaddr = 0;
         }
         if (image_size < 0) {
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
index 64bd4b4..d0c61c5 100644
--- a/hw/arm/stellaris.c
+++ b/hw/arm/stellaris.c
@@ -1220,10 +1220,26 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
     int i;
     int j;
 
-    flash_size = ((board->dc0 & 0xffff) + 1) << 1;
-    sram_size = (board->dc0 >> 18) + 1;
-    pic = armv7m_init(get_system_memory(),
-                      flash_size, sram_size, kernel_filename, cpu_model);
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
+    MemoryRegion *flash = g_new(MemoryRegion, 1);
+    MemoryRegion *system_memory = get_system_memory();
+
+    flash_size = (((board->dc0 & 0xffff) + 1) << 1) * 1024;
+    sram_size = ((board->dc0 >> 18) + 1) * 1024;
+
+    /* Flash programming is done via the SCU, so pretend it is ROM.  */
+    memory_region_init_ram(flash, NULL, "stellaris.flash", flash_size,
+                           &error_abort);
+    vmstate_register_ram_global(flash);
+    memory_region_set_readonly(flash, true);
+    memory_region_add_subregion(system_memory, 0, flash);
+
+    memory_region_init_ram(sram, NULL, "stellaris.sram", sram_size,
+                           &error_abort);
+    vmstate_register_ram_global(sram);
+    memory_region_add_subregion(system_memory, 0x20000000, sram);
+
+    pic = armv7m_init(system_memory, flash_size, kernel_filename, cpu_model);
 
     if (board->dc1 & (1 << 16)) {
         dev = sysbus_create_varargs(TYPE_STELLARIS_ADC, 0x40038000,
diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h
index cefc9e6..a112930 100644
--- a/include/hw/arm/arm.h
+++ b/include/hw/arm/arm.h
@@ -15,8 +15,7 @@
 #include "hw/irq.h"
 
 /* armv7m.c */
-qemu_irq *armv7m_init(MemoryRegion *system_memory,
-                      int flash_size, int sram_size,
+qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size,
                       const char *kernel_filename, const char *cpu_model);
 
 /* arm_boot.c */
-- 
2.1.0

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

* [Qemu-devel] [PATCH v7 5/7] target_arm: Parameterise the irq lines for armv7m_init
  2014-12-10  8:46 [Qemu-devel] [PATCH v7 0/7] Netduino 2 Machine Model Alistair Francis
                   ` (3 preceding siblings ...)
  2014-12-10  8:46 ` [Qemu-devel] [PATCH v7 4/7] target_arm: Remove memory region init from armv7m_init Alistair Francis
@ 2014-12-10  8:47 ` Alistair Francis
  2014-12-10  8:47 ` [Qemu-devel] [PATCH v7 6/7] stm32f205: Add the stm32f205 SoC Alistair Francis
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Alistair Francis @ 2014-12-10  8:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, peter.crosthwaite, konstanty, martin.galvan

This patch allows the board to specifiy the number of NVIC interrupt
lines when using armv7m_init.

Signed-off-by: Alistair Francis <alistair23@gmail.com>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
---

 hw/arm/armv7m.c      | 7 ++++---
 hw/arm/stellaris.c   | 5 ++++-
 include/hw/arm/arm.h | 2 +-
 3 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c
index 50281f7..7169027 100644
--- a/hw/arm/armv7m.c
+++ b/hw/arm/armv7m.c
@@ -166,14 +166,14 @@ static void armv7m_reset(void *opaque)
    mem_size is in bytes.
    Returns the NVIC array.  */
 
-qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size,
+qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
                       const char *kernel_filename, const char *cpu_model)
 {
     ARMCPU *cpu;
     CPUARMState *env;
     DeviceState *nvic;
     /* FIXME: make this local state.  */
-    static qemu_irq pic[64];
+    qemu_irq *pic = g_new(qemu_irq, num_irq);
     int image_size;
     uint64_t entry;
     uint64_t lowaddr;
@@ -194,11 +194,12 @@ qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size,
     armv7m_bitband_init();
 
     nvic = qdev_create(NULL, "armv7m_nvic");
+    qdev_prop_set_uint32(nvic, "num-irq", num_irq);
     env->nvic = nvic;
     qdev_init_nofail(nvic);
     sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0,
                        qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
-    for (i = 0; i < 64; i++) {
+    for (i = 0; i < num_irq; i++) {
         pic[i] = qdev_get_gpio_in(nvic, i);
     }
 
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
index d0c61c5..6fad10f 100644
--- a/hw/arm/stellaris.c
+++ b/hw/arm/stellaris.c
@@ -29,6 +29,8 @@
 #define BP_OLED_SSI  0x02
 #define BP_GAMEPAD   0x04
 
+#define NUM_IRQ_LINES 64
+
 typedef const struct {
     const char *name;
     uint32_t did0;
@@ -1239,7 +1241,8 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
     vmstate_register_ram_global(sram);
     memory_region_add_subregion(system_memory, 0x20000000, sram);
 
-    pic = armv7m_init(system_memory, flash_size, kernel_filename, cpu_model);
+    pic = armv7m_init(system_memory, flash_size, NUM_IRQ_LINES,
+                      kernel_filename, cpu_model);
 
     if (board->dc1 & (1 << 16)) {
         dev = sysbus_create_varargs(TYPE_STELLARIS_ADC, 0x40038000,
diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h
index a112930..94e55a4 100644
--- a/include/hw/arm/arm.h
+++ b/include/hw/arm/arm.h
@@ -15,7 +15,7 @@
 #include "hw/irq.h"
 
 /* armv7m.c */
-qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size,
+qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
                       const char *kernel_filename, const char *cpu_model);
 
 /* arm_boot.c */
-- 
2.1.0

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

* [Qemu-devel] [PATCH v7 6/7] stm32f205: Add the stm32f205 SoC
  2014-12-10  8:46 [Qemu-devel] [PATCH v7 0/7] Netduino 2 Machine Model Alistair Francis
                   ` (4 preceding siblings ...)
  2014-12-10  8:47 ` [Qemu-devel] [PATCH v7 5/7] target_arm: Parameterise the irq lines for armv7m_init Alistair Francis
@ 2014-12-10  8:47 ` Alistair Francis
  2014-12-10  8:47 ` [Qemu-devel] [PATCH v7 7/7] netduino2: Add the Netduino 2 Machine Alistair Francis
  2014-12-15 17:37 ` [Qemu-devel] [PATCH v7 0/7] Netduino 2 Machine Model Peter Maydell
  7 siblings, 0 replies; 13+ messages in thread
From: Alistair Francis @ 2014-12-10  8:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, peter.crosthwaite, konstanty, martin.galvan

This patch adds the stm32f205 SoC. This will be used by the
Netduino 2 to create a machine.

Signed-off-by: Alistair Francis <alistair23@gmail.com>
---
V6:
 - Correct the number of USART/UART devices
 - Use macros to define how many devices are inited
 - Update the memory regions name from netduino.* to
   STM32F205.*

 default-configs/arm-softmmu.mak |   1 +
 hw/arm/Makefile.objs            |   1 +
 hw/arm/stm32f205_soc.c          | 157 ++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/stm32f205_soc.h  |  69 ++++++++++++++++++
 4 files changed, 228 insertions(+)
 create mode 100644 hw/arm/stm32f205_soc.c
 create mode 100644 include/hw/arm/stm32f205_soc.h

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index a5aab7f..9ac755e 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -81,6 +81,7 @@ CONFIG_ZYNQ=y
 CONFIG_STM32F2XX_TIMER=y
 CONFIG_STM32F2XX_USART=y
 CONFIG_STM32F2XX_SYSCFG=y
+CONFIG_STM32F205_SOC=y
 
 CONFIG_VERSATILE_PCI=y
 CONFIG_VERSATILE_I2C=y
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 6088e53..9769317 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -8,3 +8,4 @@ obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
 obj-$(CONFIG_DIGIC) += digic.o
 obj-y += omap1.o omap2.o strongarm.o
 obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
+obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c
new file mode 100644
index 0000000..186e15d
--- /dev/null
+++ b/hw/arm/stm32f205_soc.c
@@ -0,0 +1,157 @@
+/*
+ * STM32F205 SoC
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/arm/stm32f205_soc.h"
+
+/* At the moment only Timer 2 to 5 are modelled */
+static const uint32_t timer_addr[STM_NUM_TIMERS] = { 0x40000000, 0x40000400,
+    0x40000800, 0x40000C00 };
+static const uint32_t usart_addr[STM_NUM_USARTS] = { 0x40011000, 0x40004400,
+    0x40004800, 0x40004C00, 0x40005000, 0x40011400 };
+
+static const int timer_irq[STM_NUM_TIMERS] = {28, 29, 30, 50};
+static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39, 52, 53, 71};
+
+static void stm32f205_soc_initfn(Object *obj)
+{
+    STM32F205State *s = STM32F205_SOC(obj);
+    int i;
+
+    object_initialize(&s->syscfg, sizeof(s->syscfg), TYPE_STM32F2XX_SYSCFG);
+    qdev_set_parent_bus(DEVICE(&s->syscfg), sysbus_get_default());
+
+    for (i = 0; i < STM_NUM_USARTS; i++) {
+        object_initialize(&s->usart[i], sizeof(s->usart[i]),
+                          TYPE_STM32F2XX_USART);
+        qdev_set_parent_bus(DEVICE(&s->usart[i]), sysbus_get_default());
+    }
+
+    for (i = 0; i < STM_NUM_TIMERS; i++) {
+        object_initialize(&s->timer[i], sizeof(s->timer[i]),
+                          TYPE_STM32F2XX_TIMER);
+        qdev_set_parent_bus(DEVICE(&s->timer[i]), sysbus_get_default());
+    }
+}
+
+static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
+{
+    STM32F205State *s = STM32F205_SOC(dev_soc);
+    DeviceState *syscfgdev, *usartdev, *timerdev;
+    SysBusDevice *syscfgbusdev, *usartbusdev, *timerbusdev;
+    qemu_irq *pic;
+    Error *err = NULL;
+    int i;
+
+    MemoryRegion *system_memory = get_system_memory();
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
+    MemoryRegion *flash = g_new(MemoryRegion, 1);
+    MemoryRegion *flash_alias = g_new(MemoryRegion, 1);
+
+    memory_region_init_ram(flash, NULL, "STM32F205.flash", FLASH_SIZE,
+                           &error_abort);
+    memory_region_init_alias(flash_alias, NULL, "STM32F205.flash.alias",
+                             flash, 0, FLASH_SIZE);
+
+    vmstate_register_ram_global(flash);
+
+    memory_region_set_readonly(flash, true);
+    memory_region_set_readonly(flash_alias, true);
+
+    memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, flash);
+    memory_region_add_subregion(system_memory, 0, flash_alias);
+
+    memory_region_init_ram(sram, NULL, "STM32F205.sram", SRAM_SIZE,
+                           &error_abort);
+    vmstate_register_ram_global(sram);
+    memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, sram);
+
+    pic = armv7m_init(get_system_memory(), FLASH_SIZE, 96,
+                      s->kernel_filename, s->cpu_model);
+
+    /* System configuration controller */
+    syscfgdev = DEVICE(&s->syscfg);
+    object_property_set_bool(OBJECT(&s->syscfg), true, "realized", &err);
+    if (err != NULL) {
+        error_propagate(errp, err);
+        return;
+    }
+    syscfgbusdev = SYS_BUS_DEVICE(syscfgdev);
+    sysbus_mmio_map(syscfgbusdev, 0, 0x40013800);
+    sysbus_connect_irq(syscfgbusdev, 0, pic[71]);
+
+    /* Attach UART (uses USART registers) and USART controllers */
+    for (i = 0; i < STM_NUM_USARTS; i++) {
+        usartdev = DEVICE(&(s->usart[i]));
+        object_property_set_bool(OBJECT(&s->usart[i]), true, "realized", &err);
+        if (err != NULL) {
+            error_propagate(errp, err);
+            return;
+        }
+        usartbusdev = SYS_BUS_DEVICE(usartdev);
+        sysbus_mmio_map(usartbusdev, 0, usart_addr[i]);
+        sysbus_connect_irq(usartbusdev, 0, pic[usart_irq[i]]);
+    }
+
+    /* Timer 2 to 5 */
+    for (i = 0; i < STM_NUM_TIMERS; i++) {
+        timerdev = DEVICE(&(s->timer[i]));
+        qdev_prop_set_uint64(timerdev, "clock-frequency", 1000000000);
+        object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err);
+        if (err != NULL) {
+            error_propagate(errp, err);
+            return;
+        }
+        timerbusdev = SYS_BUS_DEVICE(timerdev);
+        sysbus_mmio_map(timerbusdev, 0, timer_addr[i]);
+        sysbus_connect_irq(timerbusdev, 0, pic[timer_irq[i]]);
+    }
+}
+
+static Property stm32f205_soc_properties[] = {
+    DEFINE_PROP_STRING("kernel-filename", STM32F205State, kernel_filename),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void stm32f205_soc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = stm32f205_soc_realize;
+    dc->props = stm32f205_soc_properties;
+}
+
+static const TypeInfo stm32f205_soc_info = {
+    .name          = TYPE_STM32F205_SOC,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(STM32F205State),
+    .instance_init = stm32f205_soc_initfn,
+    .class_init    = stm32f205_soc_class_init,
+};
+
+static void stm32f205_soc_types(void)
+{
+    type_register_static(&stm32f205_soc_info);
+}
+
+type_init(stm32f205_soc_types)
diff --git a/include/hw/arm/stm32f205_soc.h b/include/hw/arm/stm32f205_soc.h
new file mode 100644
index 0000000..4b71c40
--- /dev/null
+++ b/include/hw/arm/stm32f205_soc.h
@@ -0,0 +1,69 @@
+/*
+ * STM32F205 SoC
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef HW_ARM_STM32F205SOC_H
+#define HW_ARM_STM32F205SOC_H
+
+#include "hw/sysbus.h"
+#include "hw/arm/arm.h"
+#include "hw/ssi.h"
+#include "hw/devices.h"
+#include "qemu/timer.h"
+#include "net/net.h"
+#include "elf.h"
+#include "hw/loader.h"
+#include "hw/boards.h"
+#include "exec/address-spaces.h"
+#include "qemu/error-report.h"
+#include "sysemu/qtest.h"
+#include "hw/misc/stm32f2xx_syscfg.h"
+#include "hw/timer/stm32f2xx_timer.h"
+#include "hw/char/stm32f2xx_usart.h"
+
+#define TYPE_STM32F205_SOC "stm32f205_soc"
+#define STM32F205_SOC(obj) \
+    OBJECT_CHECK(STM32F205State, (obj), TYPE_STM32F205_SOC)
+
+#define STM_NUM_USARTS 6
+#define STM_NUM_TIMERS 4
+
+#define FLASH_BASE_ADDRESS 0x08000000
+#define FLASH_SIZE (1024 * 1024)
+#define SRAM_BASE_ADDRESS 0x20000000
+#define SRAM_SIZE (128 * 1024)
+
+typedef struct STM32F205State {
+    /*< private >*/
+    SysBusDevice parent_obj;
+    /*< public >*/
+
+    char *kernel_filename;
+    char *cpu_model;
+
+    STM32F2XXSyscfgState syscfg;
+    STM32F2XXUsartState usart[STM_NUM_USARTS];
+    STM32F2XXTimerState timer[STM_NUM_TIMERS];
+} STM32F205State;
+
+#endif
-- 
2.1.0

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

* [Qemu-devel] [PATCH v7 7/7] netduino2: Add the Netduino 2 Machine
  2014-12-10  8:46 [Qemu-devel] [PATCH v7 0/7] Netduino 2 Machine Model Alistair Francis
                   ` (5 preceding siblings ...)
  2014-12-10  8:47 ` [Qemu-devel] [PATCH v7 6/7] stm32f205: Add the stm32f205 SoC Alistair Francis
@ 2014-12-10  8:47 ` Alistair Francis
  2014-12-15 17:37 ` [Qemu-devel] [PATCH v7 0/7] Netduino 2 Machine Model Peter Maydell
  7 siblings, 0 replies; 13+ messages in thread
From: Alistair Francis @ 2014-12-10  8:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, peter.crosthwaite, konstanty, martin.galvan

This patch adds the Netduino 2 Machine.

This is a Cortex-M3 based machine. Information can be found at:
http://www.netduino.com/netduino2/specs.htm

Signed-off-by: Alistair Francis <alistair23@gmail.com>
---

 hw/arm/Makefile.objs |  1 +
 hw/arm/netduino2.c   | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+)
 create mode 100644 hw/arm/netduino2.c

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 9769317..2577f68 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -3,6 +3,7 @@ obj-$(CONFIG_DIGIC) += digic_boards.o
 obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
 obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
 obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
+obj-y += netduino2.o
 
 obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
 obj-$(CONFIG_DIGIC) += digic.o
diff --git a/hw/arm/netduino2.c b/hw/arm/netduino2.c
new file mode 100644
index 0000000..305983f
--- /dev/null
+++ b/hw/arm/netduino2.c
@@ -0,0 +1,54 @@
+/*
+ * Netduino 2 Machine Model
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/arm/stm32f205_soc.h"
+
+static void netduino2_init(MachineState *machine)
+{
+    DeviceState *dev;
+    Error *err = NULL;
+
+    dev = qdev_create(NULL, TYPE_STM32F205_SOC);
+    if (machine->kernel_filename) {
+        qdev_prop_set_string(dev, "kernel-filename", machine->kernel_filename);
+    }
+    object_property_set_bool(OBJECT(dev), true, "realized", &err);
+    if (err != NULL) {
+        error_report("%s", error_get_pretty(err));
+        exit(1);
+    }
+}
+
+static QEMUMachine netduino2_machine = {
+    .name = "netduino2",
+    .desc = "Netduino 2 Machine",
+    .init = netduino2_init,
+};
+
+static void netduino2_machine_init(void)
+{
+    qemu_register_machine(&netduino2_machine);
+}
+
+machine_init(netduino2_machine_init);
-- 
2.1.0

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

* Re: [Qemu-devel] [PATCH v7 0/7] Netduino 2 Machine Model
  2014-12-10  8:46 [Qemu-devel] [PATCH v7 0/7] Netduino 2 Machine Model Alistair Francis
                   ` (6 preceding siblings ...)
  2014-12-10  8:47 ` [Qemu-devel] [PATCH v7 7/7] netduino2: Add the Netduino 2 Machine Alistair Francis
@ 2014-12-15 17:37 ` Peter Maydell
  7 siblings, 0 replies; 13+ messages in thread
From: Peter Maydell @ 2014-12-15 17:37 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Martin Galvan, Peter Crosthwaite, QEMU Developers, Konstanty Bialkowski

On 10 December 2014 at 08:46, Alistair Francis <alistair23@gmail.com> wrote:
> This patch series adds the Netduino 2 Machine to QEMU
>
> Information on the board is avalible at:
> http://www.netduino.com/netduino2/specs.htm
>
> The git tree can be found at:
> https://github.com/alistair23/qemu/tree/netduino2.7
>
> This patch series makes some changes to the armv7m_init function
> that allows the code to be reused with the Netduino 2 and the
> Stellaris machines.

Just a note to say that I'm assuming that Peter C is going
to review this; happy to apply to target-arm.next once it's
passed his review.

thanks
-- PMM

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

* Re: [Qemu-devel] [PATCH v7 1/7] stm32f2xx_timer: Add the stm32f2xx Timer
  2014-12-10  8:46 ` [Qemu-devel] [PATCH v7 1/7] stm32f2xx_timer: Add the stm32f2xx Timer Alistair Francis
@ 2014-12-16  5:39   ` Peter Crosthwaite
  2014-12-26  3:08     ` Alistair Francis
  0 siblings, 1 reply; 13+ messages in thread
From: Peter Crosthwaite @ 2014-12-16  5:39 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Peter Maydell, Martin Galvan, qemu-devel@nongnu.org Developers,
	Konstanty Bialkowski

On Wed, Dec 10, 2014 at 12:46 AM, Alistair Francis <alistair23@gmail.com> wrote:
> This patch adds the stm32f2xx timers: TIM2, TIM3, TIM4 and TIM5
> to QEMU.
>
> Signed-off-by: Alistair Francis <alistair23@gmail.com>
> ---
> V6:
>  - Rename to STM32F2XX
>  - Change the timer calculations to use ns
>  - Update the value to timer_mod to ensure it is in ns
>  - Account for reloadable/resetable timer
>     - Thanks to Peter C for pointing this out
> V4:
>  - Update timer units again
>     - Thanks to Peter C
> V3:
>  - Update debug statements
>  - Correct the units for timer_mod
>  - Correctly set timer_offset from resets
> V2:
>  - Reorder the Makefile config
>  - Fix up the debug printing
>  - Correct the timer event trigger
>
>  default-configs/arm-softmmu.mak    |   1 +
>  hw/timer/Makefile.objs             |   2 +
>  hw/timer/stm32f2xx_timer.c         | 331 +++++++++++++++++++++++++++++++++++++
>  include/hw/timer/stm32f2xx_timer.h | 101 +++++++++++
>  4 files changed, 435 insertions(+)
>  create mode 100644 hw/timer/stm32f2xx_timer.c
>  create mode 100644 include/hw/timer/stm32f2xx_timer.h
>
> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
> index f3513fa..faea100 100644
> --- a/default-configs/arm-softmmu.mak
> +++ b/default-configs/arm-softmmu.mak
> @@ -78,6 +78,7 @@ CONFIG_NSERIES=y
>  CONFIG_REALVIEW=y
>  CONFIG_ZAURUS=y
>  CONFIG_ZYNQ=y
> +CONFIG_STM32F2XX_TIMER=y
>
>  CONFIG_VERSATILE_PCI=y
>  CONFIG_VERSATILE_I2C=y
> diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
> index 2c86c3d..133bd0d 100644
> --- a/hw/timer/Makefile.objs
> +++ b/hw/timer/Makefile.objs
> @@ -31,3 +31,5 @@ obj-$(CONFIG_DIGIC) += digic-timer.o
>  obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
>
>  obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o
> +
> +common-obj-$(CONFIG_STM32F2XX_TIMER) += stm32f2xx_timer.o
> diff --git a/hw/timer/stm32f2xx_timer.c b/hw/timer/stm32f2xx_timer.c
> new file mode 100644
> index 0000000..df27540
> --- /dev/null
> +++ b/hw/timer/stm32f2xx_timer.c
> @@ -0,0 +1,331 @@
> +/*
> + * STM32F2XX Timer
> + *
> + * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "hw/timer/stm32f2xx_timer.h"
> +
> +#ifndef STM_TIMER_ERR_DEBUG
> +#define STM_TIMER_ERR_DEBUG 0
> +#endif
> +
> +#define DB_PRINT_L(lvl, fmt, args...) do { \
> +    if (STM_TIMER_ERR_DEBUG >= lvl) { \
> +        qemu_log("%s: " fmt, __func__, ## args); \
> +    } \
> +} while (0);
> +
> +#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
> +
> +static void stm32f2xx_timer_set_alarm(STM32F2XXTimerState *s);
> +
> +static void stm32f2xx_timer_interrupt(void *opaque)
> +{
> +    STM32F2XXTimerState *s = opaque;
> +
> +    DB_PRINT("Interrupt\n");
> +
> +    if (s->tim_dier & TIM_DIER_UIE && s->tim_cr1 & TIM_CR1_CEN) {
> +        s->tim_sr |= 1;
> +        qemu_irq_pulse(s->irq);
> +        stm32f2xx_timer_set_alarm(s);
> +    }
> +}
> +
> +static void stm32f2xx_timer_set_alarm(STM32F2XXTimerState *s)
> +{
> +    uint32_t ticks;
> +    int64_t now;
> +
> +    DB_PRINT("Alarm set at: 0x%x\n", s->tim_cr1);
> +
> +    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +    ticks = s->tim_arr -
> +            ((muldiv64(s->freq_hz, now, 1000000000ULL) - s->tick_offset) /
> +            (s->tim_psc + 1));

ticks seems to be the auto-reload register minus the total number of
ticks elapsed since reset (now - tick_offset). For subsequent reloads
in periodic timing this will always be -ve. Does tick_offset need to
be warped every time the timer hits and autoreloads?

> +
> +    DB_PRINT("Alarm set in %d ticks\n", ticks);
> +
> +    if (ticks == 0) {
> +        timer_del(s->timer);
> +        stm32f2xx_timer_interrupt(s);
> +    } else {
> +        timer_mod(s->timer, now +
> +                  muldiv64(ticks, 1000000000ULL, get_ticks_per_sec()));

Doesn't seems right that that conversion from now -> ticks multiplies
by ->freq_hz yet this conversion here divides out by
get_ticks_per_sec. Should this be freq_hz too?

> +
> +        DB_PRINT("Wait Time: %" PRId64 " ticks\n",
> +                 now + muldiv64(ticks, 1000000000ULL, get_ticks_per_sec()));

You should cache this in a local variable to remove the repeated expression.

> +    }
> +}
> +
> +static void stm32f2xx_timer_reset(DeviceState *dev)
> +{
> +    STM32F2XXTimerState *s = STM32F2XXTIMER(dev);
> +
> +    s->tim_cr1 = 0;
> +    s->tim_cr2 = 0;
> +    s->tim_smcr = 0;
> +    s->tim_dier = 0;
> +    s->tim_sr = 0;
> +    s->tim_egr = 0;
> +    s->tim_ccmr1 = 0;
> +    s->tim_ccmr2 = 0;
> +    s->tim_ccer = 0;
> +    s->tim_cnt = 0;
> +    s->tim_psc = 0;
> +    s->tim_arr = 0;
> +    s->tim_ccr1 = 0;
> +    s->tim_ccr2 = 0;
> +    s->tim_ccr3 = 0;
> +    s->tim_ccr4 = 0;
> +    s->tim_dcr = 0;
> +    s->tim_dmar = 0;
> +    s->tim_or = 0;
> +
> +    s->tick_offset = muldiv64(s->freq_hz,
> +                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> +                              1000000000ULL);
> +
> +    stm32f2xx_timer_set_alarm(s);

Can the timer really arm itself coming out of reset?

> +}
> +
> +static uint64_t stm32f2xx_timer_read(void *opaque, hwaddr offset,
> +                           unsigned size)
> +{
> +    STM32F2XXTimerState *s = opaque;
> +
> +    DB_PRINT("Read 0x%"HWADDR_PRIx"\n", offset);
> +
> +    switch (offset) {
> +    case TIM_CR1:
> +        return s->tim_cr1;
> +    case TIM_CR2:
> +        return s->tim_cr2;
> +    case TIM_SMCR:
> +        return s->tim_smcr;
> +    case TIM_DIER:
> +        return s->tim_dier;
> +    case TIM_SR:
> +        return s->tim_sr;
> +    case TIM_EGR:
> +        return s->tim_egr;
> +    case TIM_CCMR1:
> +        return s->tim_ccmr1;
> +    case TIM_CCMR2:
> +        return s->tim_ccmr2;
> +    case TIM_CCER:
> +        return s->tim_ccer;
> +    case TIM_CNT:
> +        s->tim_cnt = muldiv64(s->freq_hz,
> +                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> +                              1000000000ULL) - s->tick_offset;

The guest visible value of the timer should take into account the
prescaler in some way I think?

Regards,
Peter

> +        return s->tim_cnt;
> +    case TIM_PSC:
> +        return s->tim_psc;
> +    case TIM_ARR:
> +        return s->tim_arr;
> +    case TIM_CCR1:
> +        return s->tim_ccr1;
> +    case TIM_CCR2:
> +        return s->tim_ccr2;
> +    case TIM_CCR3:
> +        return s->tim_ccr3;
> +    case TIM_CCR4:
> +        return s->tim_ccr4;
> +    case TIM_DCR:
> +        return s->tim_dcr;
> +    case TIM_DMAR:
> +        return s->tim_dmar;
> +    case TIM_OR:
> +        return s->tim_or;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, offset);
> +    }
> +
> +    return 0;
> +}
> +
> +static void stm32f2xx_timer_write(void *opaque, hwaddr offset,
> +                        uint64_t val64, unsigned size)
> +{
> +    STM32F2XXTimerState *s = opaque;
> +    uint32_t value = val64;
> +
> +    DB_PRINT("Write 0x%x, 0x%"HWADDR_PRIx"\n", value, offset);
> +
> +    switch (offset) {
> +    case TIM_CR1:
> +        s->tim_cr1 = value;
> +        return;
> +    case TIM_CR2:
> +        s->tim_cr2 = value;
> +        return;
> +    case TIM_SMCR:
> +        s->tim_smcr = value;
> +        return;
> +    case TIM_DIER:
> +        s->tim_dier = value;
> +        return;
> +    case TIM_SR:
> +        /* This is set by hardware and cleared by software */
> +        s->tim_sr &= value;
> +        return;
> +    case TIM_EGR:
> +        s->tim_egr = value;
> +        if (s->tim_egr & TIM_EGR_UG) {
> +            /* Re-init the counter */
> +            stm32f2xx_timer_reset(DEVICE(s));
> +        }
> +        return;
> +    case TIM_CCMR1:
> +        s->tim_ccmr1 = value;
> +        return;
> +    case TIM_CCMR2:
> +        s->tim_ccmr2 = value;
> +        return;
> +    case TIM_CCER:
> +        s->tim_ccer = value;
> +        return;
> +    case TIM_CNT:
> +        /* The guest is changing the clock counter.
> +         * Subtract the difference between the value and the current time
> +         * from tick_offset and update the timer alarm.
> +         */
> +        s->tick_offset -= value - (muldiv64(s->freq_hz,
> +                                   qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> +                                   1000000000ULL) - s->tick_offset);
> +        s->tim_cnt = value;
> +        stm32f2xx_timer_set_alarm(s);
> +        return;
> +    case TIM_PSC:
> +        s->tim_psc = value;
> +        stm32f2xx_timer_set_alarm(s);
> +        return;
> +    case TIM_ARR:
> +        s->tim_arr = value;
> +        stm32f2xx_timer_set_alarm(s);
> +        return;
> +    case TIM_CCR1:
> +        s->tim_ccr1 = value;
> +        return;
> +    case TIM_CCR2:
> +        s->tim_ccr2 = value;
> +        return;
> +    case TIM_CCR3:
> +        s->tim_ccr3 = value;
> +        return;
> +    case TIM_CCR4:
> +        s->tim_ccr4 = value;
> +        return;
> +    case TIM_DCR:
> +        s->tim_dcr = value;
> +        return;
> +    case TIM_DMAR:
> +        s->tim_dmar = value;
> +        return;
> +    case TIM_OR:
> +        s->tim_or = value;
> +        return;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, offset);
> +    }
> +}
> +
> +static const MemoryRegionOps stm32f2xx_timer_ops = {
> +    .read = stm32f2xx_timer_read,
> +    .write = stm32f2xx_timer_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +static const VMStateDescription vmstate_stm32f2xx_timer = {
> +    .name = TYPE_STM32F2XX_TIMER,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(tick_offset, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_cr1, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_cr2, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_smcr, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_dier, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_sr, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_egr, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_ccmr1, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_ccmr2, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_ccer, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_cnt, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_psc, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_arr, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_ccr1, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_ccr2, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_ccr3, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_ccr4, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_dcr, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_dmar, STM32F2XXTimerState),
> +        VMSTATE_UINT32(tim_or, STM32F2XXTimerState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static Property stm32f2xx_timer_properties[] = {
> +    DEFINE_PROP_UINT64("clock-frequency", struct STM32F2XXTimerState,
> +                       freq_hz, 1000000000),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void stm32f2xx_timer_init(Object *obj)
> +{
> +    STM32F2XXTimerState *s = STM32F2XXTIMER(obj);
> +
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
> +
> +    memory_region_init_io(&s->iomem, obj, &stm32f2xx_timer_ops, s,
> +                          "stm32f2xx_timer", 0x2000);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
> +
> +    s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, stm32f2xx_timer_interrupt, s);
> +}
> +
> +static void stm32f2xx_timer_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = stm32f2xx_timer_reset;
> +    dc->props = stm32f2xx_timer_properties;
> +    dc->vmsd = &vmstate_stm32f2xx_timer;
> +}
> +
> +static const TypeInfo stm32f2xx_timer_info = {
> +    .name          = TYPE_STM32F2XX_TIMER,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(STM32F2XXTimerState),
> +    .instance_init = stm32f2xx_timer_init,
> +    .class_init    = stm32f2xx_timer_class_init,
> +};
> +
> +static void stm32f2xx_timer_register_types(void)
> +{
> +    type_register_static(&stm32f2xx_timer_info);
> +}
> +
> +type_init(stm32f2xx_timer_register_types)
> diff --git a/include/hw/timer/stm32f2xx_timer.h b/include/hw/timer/stm32f2xx_timer.h
> new file mode 100644
> index 0000000..512fa16
> --- /dev/null
> +++ b/include/hw/timer/stm32f2xx_timer.h
> @@ -0,0 +1,101 @@
> +/*
> + * STM32F2XX Timer
> + *
> + * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#ifndef HW_STM_TIMER_H
> +#define HW_STM_TIMER_H
> +
> +#include "hw/sysbus.h"
> +#include "qemu/timer.h"
> +#include "sysemu/sysemu.h"
> +
> +#define TIM_CR1      0x00
> +#define TIM_CR2      0x04
> +#define TIM_SMCR     0x08
> +#define TIM_DIER     0x0C
> +#define TIM_SR       0x10
> +#define TIM_EGR      0x14
> +#define TIM_CCMR1    0x18
> +#define TIM_CCMR2    0x1C
> +#define TIM_CCER     0x20
> +#define TIM_CNT      0x24
> +#define TIM_PSC      0x28
> +#define TIM_ARR      0x2C
> +#define TIM_CCR1     0x34
> +#define TIM_CCR2     0x38
> +#define TIM_CCR3     0x3C
> +#define TIM_CCR4     0x40
> +#define TIM_DCR      0x48
> +#define TIM_DMAR     0x4C
> +#define TIM_OR       0x50
> +
> +#define TIM_CR1_CEN   1
> +
> +#define TIM_EGR_UG 1
> +
> +#define TIM_CCER_CC2E   (1 << 4)
> +#define TIM_CCMR1_OC2M2 (1 << 14)
> +#define TIM_CCMR1_OC2M1 (1 << 13)
> +#define TIM_CCMR1_OC2M0 (1 << 12)
> +#define TIM_CCMR1_OC2PE (1 << 11)
> +
> +#define TIM_DIER_UIE  1
> +
> +#define TYPE_STM32F2XX_TIMER "stm32f2xx-timer"
> +#define STM32F2XXTIMER(obj) OBJECT_CHECK(STM32F2XXTimerState, \
> +                            (obj), TYPE_STM32F2XX_TIMER)
> +
> +typedef struct STM32F2XXTimerState {
> +    /* <private> */
> +    SysBusDevice parent_obj;
> +
> +    /* <public> */
> +    MemoryRegion iomem;
> +    QEMUTimer *timer;
> +    qemu_irq irq;
> +
> +    uint32_t tick_offset;
> +    uint64_t freq_hz;
> +
> +    uint32_t tim_cr1;
> +    uint32_t tim_cr2;
> +    uint32_t tim_smcr;
> +    uint32_t tim_dier;
> +    uint32_t tim_sr;
> +    uint32_t tim_egr;
> +    uint32_t tim_ccmr1;
> +    uint32_t tim_ccmr2;
> +    uint32_t tim_ccer;
> +    uint32_t tim_cnt;
> +    uint32_t tim_psc;
> +    uint32_t tim_arr;
> +    uint32_t tim_ccr1;
> +    uint32_t tim_ccr2;
> +    uint32_t tim_ccr3;
> +    uint32_t tim_ccr4;
> +    uint32_t tim_dcr;
> +    uint32_t tim_dmar;
> +    uint32_t tim_or;
> +} STM32F2XXTimerState;
> +
> +#endif
> --
> 2.1.0
>
>

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

* Re: [Qemu-devel] [PATCH v7 2/7] stm32f2xx_USART: Add the stm32f2xx USART Controller
  2014-12-10  8:46 ` [Qemu-devel] [PATCH v7 2/7] stm32f2xx_USART: Add the stm32f2xx USART Controller Alistair Francis
@ 2014-12-16  5:47   ` Peter Crosthwaite
  2014-12-25  8:45     ` Alistair Francis
  0 siblings, 1 reply; 13+ messages in thread
From: Peter Crosthwaite @ 2014-12-16  5:47 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Peter Maydell, Martin Galvan, qemu-devel@nongnu.org Developers,
	Konstanty Bialkowski

On Wed, Dec 10, 2014 at 12:46 AM, Alistair Francis <alistair23@gmail.com> wrote:
> This patch adds the stm32f2xx USART controller
> (UART also uses the same controller).
>
> Signed-off-by: Alistair Francis <alistair23@gmail.com>
> ---
> V6:
>  - Rename to STM32F2XX
>  - Fix up unimplemented printing
>  - Add a qemu_chr_accept()
> V3:
>  - Update debug printing
> V2:
>  - Drop charecters if the device is not enabled
>     - Thanks to Peter C
>
>  default-configs/arm-softmmu.mak   |   1 +
>  hw/char/Makefile.objs             |   1 +
>  hw/char/stm32f2xx_usart.c         | 219 ++++++++++++++++++++++++++++++++++++++
>  include/hw/char/stm32f2xx_usart.h |  69 ++++++++++++
>  4 files changed, 290 insertions(+)
>  create mode 100644 hw/char/stm32f2xx_usart.c
>  create mode 100644 include/hw/char/stm32f2xx_usart.h
>
> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
> index faea100..1348104 100644
> --- a/default-configs/arm-softmmu.mak
> +++ b/default-configs/arm-softmmu.mak
> @@ -79,6 +79,7 @@ CONFIG_REALVIEW=y
>  CONFIG_ZAURUS=y
>  CONFIG_ZYNQ=y
>  CONFIG_STM32F2XX_TIMER=y
> +CONFIG_STM32F2XX_USART=y
>
>  CONFIG_VERSATILE_PCI=y
>  CONFIG_VERSATILE_I2C=y
> diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
> index 317385d..5931cc8 100644
> --- a/hw/char/Makefile.objs
> +++ b/hw/char/Makefile.objs
> @@ -15,6 +15,7 @@ obj-$(CONFIG_OMAP) += omap_uart.o
>  obj-$(CONFIG_SH4) += sh_serial.o
>  obj-$(CONFIG_PSERIES) += spapr_vty.o
>  obj-$(CONFIG_DIGIC) += digic-uart.o
> +obj-$(CONFIG_STM32F2XX_USART) += stm32f2xx_usart.o
>
>  common-obj-$(CONFIG_ETRAXFS) += etraxfs_ser.o
>  common-obj-$(CONFIG_ISA_DEBUG) += debugcon.o
> diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c
> new file mode 100644
> index 0000000..843ff4a
> --- /dev/null
> +++ b/hw/char/stm32f2xx_usart.c
> @@ -0,0 +1,219 @@
> +/*
> + * STM32F2XX USART
> + *
> + * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "hw/char/stm32f2xx_usart.h"
> +
> +#ifndef STM_USART_ERR_DEBUG
> +#define STM_USART_ERR_DEBUG 0
> +#endif
> +
> +#define DB_PRINT_L(lvl, fmt, args...) do { \
> +    if (STM_USART_ERR_DEBUG >= lvl) { \
> +        qemu_log("%s: " fmt, __func__, ## args); \
> +    } \
> +} while (0);
> +
> +#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
> +
> +static int stm32f2xx_usart_can_receive(void *opaque)
> +{
> +    STM32F2XXUsartState *s = opaque;
> +
> +    if (!(s->usart_sr & USART_SR_RXNE)) {
> +        return 1;
> +    }
> +
> +    return 0;
> +}
> +
> +static void stm32f2xx_usart_receive(void *opaque, const uint8_t *buf, int size)
> +{
> +    STM32F2XXUsartState *s = opaque;
> +
> +    s->usart_dr = *buf;
> +
> +    if (!(s->usart_cr1 & USART_CR1_UE && s->usart_cr1 & USART_CR1_RE)) {
> +        /* USART not enabled - drop the chars */
> +        DB_PRINT("Dropping the chars\n");
> +        return;
> +    }
> +
> +    s->usart_sr |= USART_SR_RXNE;
> +
> +    if (s->usart_cr1 & USART_CR1_RXNEIE) {
> +        qemu_set_irq(s->irq, 1);
> +    }
> +
> +    DB_PRINT("Receiving: %c\n", s->usart_dr);
> +}
> +
> +static void stm32f2xx_usart_reset(DeviceState *dev)
> +{
> +    STM32F2XXUsartState *s = STM32F2XX_USART(dev);
> +
> +    s->usart_sr = USART_SR_RESET;
> +    s->usart_dr = 0x00000000;
> +    s->usart_brr = 0x00000000;
> +    s->usart_cr1 = 0x00000000;
> +    s->usart_cr2 = 0x00000000;
> +    s->usart_cr3 = 0x00000000;
> +    s->usart_gtpr = 0x00000000;

Does the interrupt lower on a reset?

> +}
> +
> +static uint64_t stm32f2xx_usart_read(void *opaque, hwaddr addr,
> +                                       unsigned int size)
> +{
> +    STM32F2XXUsartState *s = opaque;
> +    uint64_t retvalue;
> +
> +    DB_PRINT("Read 0x%"HWADDR_PRIx"\n", addr);
> +
> +    switch (addr) {
> +    case USART_SR:
> +        retvalue = s->usart_sr;
> +        s->usart_sr &= ~USART_SR_TC;
> +        if (s->chr) {
> +            qemu_chr_accept_input(s->chr);
> +        }
> +        return retvalue;
> +    case USART_DR:
> +        DB_PRINT("Value: 0x%" PRIx32 ", %c\n", s->usart_dr, (char) s->usart_dr);
> +        s->usart_sr |= USART_SR_TXE;

How does a read of the data register affect the TX data-path?

> +        s->usart_sr &= ~USART_SR_RXNE;
> +        if (s->chr) {
> +            qemu_chr_accept_input(s->chr);
> +        }
> +        return s->usart_dr & 0x3FF;
> +    case USART_BRR:
> +        return s->usart_brr;
> +    case USART_CR1:
> +        return s->usart_cr1;
> +    case USART_CR2:
> +        return s->usart_cr2;
> +    case USART_CR3:
> +        return s->usart_cr3;
> +    case USART_GTPR:
> +        return s->usart_gtpr;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> +        return 0;
> +    }
> +
> +    return 0;
> +}
> +
> +static void stm32f2xx_usart_write(void *opaque, hwaddr addr,
> +                                  uint64_t val64, unsigned int size)
> +{
> +    STM32F2XXUsartState *s = opaque;
> +    uint32_t value = val64;
> +    unsigned char ch;
> +
> +    DB_PRINT("Write 0x%" PRIx32 ", 0x%"HWADDR_PRIx"\n", value, addr);
> +
> +    switch (addr) {
> +    case USART_SR:
> +        if (value <= 0x3FF) {
> +            s->usart_sr = value;
> +        } else {
> +            s->usart_sr &= value;
> +        }

If you set the interrupt enable bit before RXNE is cleared, should the
interrupt raise here?

Regards,
Peter

> +        return;
> +    case USART_DR:
> +        if (value < 0xF000) {
> +            ch = value;
> +            if (s->chr) {
> +                qemu_chr_fe_write_all(s->chr, &ch, 1);
> +            }
> +            s->usart_sr |= USART_SR_TC;
> +            s->usart_sr &= ~USART_SR_TXE;
> +        }
> +        return;
> +    case USART_BRR:
> +        s->usart_brr = value;
> +        return;
> +    case USART_CR1:
> +        s->usart_cr1 = value;
> +        return;
> +    case USART_CR2:
> +        s->usart_cr2 = value;
> +        return;
> +    case USART_CR3:
> +        s->usart_cr3 = value;
> +        return;
> +    case USART_GTPR:
> +        s->usart_gtpr = value;
> +        return;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> +    }
> +}
> +
> +static const MemoryRegionOps stm32f2xx_usart_ops = {
> +    .read = stm32f2xx_usart_read,
> +    .write = stm32f2xx_usart_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +static void stm32f2xx_usart_init(Object *obj)
> +{
> +    STM32F2XXUsartState *s = STM32F2XX_USART(obj);
> +
> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
> +
> +    memory_region_init_io(&s->mmio, obj, &stm32f2xx_usart_ops, s,
> +                          TYPE_STM32F2XX_USART, 0x2000);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
> +
> +    s->chr = qemu_char_get_next_serial();
> +
> +    if (s->chr) {
> +        qemu_chr_add_handlers(s->chr, stm32f2xx_usart_can_receive,
> +                              stm32f2xx_usart_receive, NULL, s);
> +    }
> +}
> +
> +static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = stm32f2xx_usart_reset;
> +}
> +
> +static const TypeInfo stm32f2xx_usart_info = {
> +    .name          = TYPE_STM32F2XX_USART,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(STM32F2XXUsartState),
> +    .instance_init = stm32f2xx_usart_init,
> +    .class_init    = stm32f2xx_usart_class_init,
> +};
> +
> +static void stm32f2xx_usart_register_types(void)
> +{
> +    type_register_static(&stm32f2xx_usart_info);
> +}
> +
> +type_init(stm32f2xx_usart_register_types)
> diff --git a/include/hw/char/stm32f2xx_usart.h b/include/hw/char/stm32f2xx_usart.h
> new file mode 100644
> index 0000000..c9fad3c
> --- /dev/null
> +++ b/include/hw/char/stm32f2xx_usart.h
> @@ -0,0 +1,69 @@
> +/*
> + * STM32F2XX USART
> + *
> + * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "hw/sysbus.h"
> +#include "sysemu/char.h"
> +#include "hw/hw.h"
> +
> +#define USART_SR   0x00
> +#define USART_DR   0x04
> +#define USART_BRR  0x08
> +#define USART_CR1  0x0C
> +#define USART_CR2  0x10
> +#define USART_CR3  0x14
> +#define USART_GTPR 0x18
> +
> +#define USART_SR_RESET 0x00C00000
> +
> +#define USART_SR_TXE  (1 << 7)
> +#define USART_SR_TC   (1 << 6)
> +#define USART_SR_RXNE (1 << 5)
> +
> +#define USART_CR1_UE  (1 << 13)
> +#define USART_CR1_RXNEIE  (1 << 5)
> +#define USART_CR1_TE  (1 << 3)
> +#define USART_CR1_RE  (1 << 2)
> +
> +#define TYPE_STM32F2XX_USART "stm32f2xx-usart"
> +#define STM32F2XX_USART(obj) \
> +    OBJECT_CHECK(STM32F2XXUsartState, (obj), TYPE_STM32F2XX_USART)
> +
> +typedef struct {
> +    /* <private> */
> +    SysBusDevice parent_obj;
> +
> +    /* <public> */
> +    MemoryRegion mmio;
> +
> +    uint32_t usart_sr;
> +    uint32_t usart_dr;
> +    uint32_t usart_brr;
> +    uint32_t usart_cr1;
> +    uint32_t usart_cr2;
> +    uint32_t usart_cr3;
> +    uint32_t usart_gtpr;
> +
> +    CharDriverState *chr;
> +    qemu_irq irq;
> +} STM32F2XXUsartState;
> --
> 2.1.0
>
>

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

* Re: [Qemu-devel] [PATCH v7 2/7] stm32f2xx_USART: Add the stm32f2xx USART Controller
  2014-12-16  5:47   ` Peter Crosthwaite
@ 2014-12-25  8:45     ` Alistair Francis
  0 siblings, 0 replies; 13+ messages in thread
From: Alistair Francis @ 2014-12-25  8:45 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Peter Maydell, Martin Galvan, qemu-devel@nongnu.org Developers,
	Konstanty Bialkowski

On Tue, Dec 16, 2014 at 3:47 PM, Peter Crosthwaite
<peter.crosthwaite@xilinx.com> wrote:
> On Wed, Dec 10, 2014 at 12:46 AM, Alistair Francis <alistair23@gmail.com> wrote:
>> This patch adds the stm32f2xx USART controller
>> (UART also uses the same controller).
>>
>> Signed-off-by: Alistair Francis <alistair23@gmail.com>
>> ---
>> V6:
>>  - Rename to STM32F2XX
>>  - Fix up unimplemented printing
>>  - Add a qemu_chr_accept()
>> V3:
>>  - Update debug printing
>> V2:
>>  - Drop charecters if the device is not enabled
>>     - Thanks to Peter C
>>
>>  default-configs/arm-softmmu.mak   |   1 +
>>  hw/char/Makefile.objs             |   1 +
>>  hw/char/stm32f2xx_usart.c         | 219 ++++++++++++++++++++++++++++++++++++++
>>  include/hw/char/stm32f2xx_usart.h |  69 ++++++++++++
>>  4 files changed, 290 insertions(+)
>>  create mode 100644 hw/char/stm32f2xx_usart.c
>>  create mode 100644 include/hw/char/stm32f2xx_usart.h
>>
>> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
>> index faea100..1348104 100644
>> --- a/default-configs/arm-softmmu.mak
>> +++ b/default-configs/arm-softmmu.mak
>> @@ -79,6 +79,7 @@ CONFIG_REALVIEW=y
>>  CONFIG_ZAURUS=y
>>  CONFIG_ZYNQ=y
>>  CONFIG_STM32F2XX_TIMER=y
>> +CONFIG_STM32F2XX_USART=y
>>
>>  CONFIG_VERSATILE_PCI=y
>>  CONFIG_VERSATILE_I2C=y
>> diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
>> index 317385d..5931cc8 100644
>> --- a/hw/char/Makefile.objs
>> +++ b/hw/char/Makefile.objs
>> @@ -15,6 +15,7 @@ obj-$(CONFIG_OMAP) += omap_uart.o
>>  obj-$(CONFIG_SH4) += sh_serial.o
>>  obj-$(CONFIG_PSERIES) += spapr_vty.o
>>  obj-$(CONFIG_DIGIC) += digic-uart.o
>> +obj-$(CONFIG_STM32F2XX_USART) += stm32f2xx_usart.o
>>
>>  common-obj-$(CONFIG_ETRAXFS) += etraxfs_ser.o
>>  common-obj-$(CONFIG_ISA_DEBUG) += debugcon.o
>> diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c
>> new file mode 100644
>> index 0000000..843ff4a
>> --- /dev/null
>> +++ b/hw/char/stm32f2xx_usart.c
>> @@ -0,0 +1,219 @@
>> +/*
>> + * STM32F2XX USART
>> + *
>> + * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a copy
>> + * of this software and associated documentation files (the "Software"), to deal
>> + * in the Software without restriction, including without limitation the rights
>> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>> + * copies of the Software, and to permit persons to whom the Software is
>> + * furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>> + * THE SOFTWARE.
>> + */
>> +
>> +#include "hw/char/stm32f2xx_usart.h"
>> +
>> +#ifndef STM_USART_ERR_DEBUG
>> +#define STM_USART_ERR_DEBUG 0
>> +#endif
>> +
>> +#define DB_PRINT_L(lvl, fmt, args...) do { \
>> +    if (STM_USART_ERR_DEBUG >= lvl) { \
>> +        qemu_log("%s: " fmt, __func__, ## args); \
>> +    } \
>> +} while (0);
>> +
>> +#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
>> +
>> +static int stm32f2xx_usart_can_receive(void *opaque)
>> +{
>> +    STM32F2XXUsartState *s = opaque;
>> +
>> +    if (!(s->usart_sr & USART_SR_RXNE)) {
>> +        return 1;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static void stm32f2xx_usart_receive(void *opaque, const uint8_t *buf, int size)
>> +{
>> +    STM32F2XXUsartState *s = opaque;
>> +
>> +    s->usart_dr = *buf;
>> +
>> +    if (!(s->usart_cr1 & USART_CR1_UE && s->usart_cr1 & USART_CR1_RE)) {
>> +        /* USART not enabled - drop the chars */
>> +        DB_PRINT("Dropping the chars\n");
>> +        return;
>> +    }
>> +
>> +    s->usart_sr |= USART_SR_RXNE;
>> +
>> +    if (s->usart_cr1 & USART_CR1_RXNEIE) {
>> +        qemu_set_irq(s->irq, 1);
>> +    }
>> +
>> +    DB_PRINT("Receiving: %c\n", s->usart_dr);
>> +}
>> +
>> +static void stm32f2xx_usart_reset(DeviceState *dev)
>> +{
>> +    STM32F2XXUsartState *s = STM32F2XX_USART(dev);
>> +
>> +    s->usart_sr = USART_SR_RESET;
>> +    s->usart_dr = 0x00000000;
>> +    s->usart_brr = 0x00000000;
>> +    s->usart_cr1 = 0x00000000;
>> +    s->usart_cr2 = 0x00000000;
>> +    s->usart_cr3 = 0x00000000;
>> +    s->usart_gtpr = 0x00000000;
>
> Does the interrupt lower on a reset?

It doesn't specify that it does, but I assume it will

>
>> +}
>> +
>> +static uint64_t stm32f2xx_usart_read(void *opaque, hwaddr addr,
>> +                                       unsigned int size)
>> +{
>> +    STM32F2XXUsartState *s = opaque;
>> +    uint64_t retvalue;
>> +
>> +    DB_PRINT("Read 0x%"HWADDR_PRIx"\n", addr);
>> +
>> +    switch (addr) {
>> +    case USART_SR:
>> +        retvalue = s->usart_sr;
>> +        s->usart_sr &= ~USART_SR_TC;
>> +        if (s->chr) {
>> +            qemu_chr_accept_input(s->chr);
>> +        }
>> +        return retvalue;
>> +    case USART_DR:
>> +        DB_PRINT("Value: 0x%" PRIx32 ", %c\n", s->usart_dr, (char) s->usart_dr);
>> +        s->usart_sr |= USART_SR_TXE;
>
> How does a read of the data register affect the TX data-path?
>

To quote the reference manual: "This bit is set by hardware when the
content of the TDR register has been transferred into
the shift register.... It is cleared by a write to the USART_DR register."

So I just set it there because it has to be set somewhere, and I
figured that was the easiest/best place. It also works with code
written for the hardware. If you can think of anywhere better I am
happy to change it.

>> +        s->usart_sr &= ~USART_SR_RXNE;
>> +        if (s->chr) {
>> +            qemu_chr_accept_input(s->chr);
>> +        }
>> +        return s->usart_dr & 0x3FF;
>> +    case USART_BRR:
>> +        return s->usart_brr;
>> +    case USART_CR1:
>> +        return s->usart_cr1;
>> +    case USART_CR2:
>> +        return s->usart_cr2;
>> +    case USART_CR3:
>> +        return s->usart_cr3;
>> +    case USART_GTPR:
>> +        return s->usart_gtpr;
>> +    default:
>> +        qemu_log_mask(LOG_GUEST_ERROR,
>> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
>> +        return 0;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static void stm32f2xx_usart_write(void *opaque, hwaddr addr,
>> +                                  uint64_t val64, unsigned int size)
>> +{
>> +    STM32F2XXUsartState *s = opaque;
>> +    uint32_t value = val64;
>> +    unsigned char ch;
>> +
>> +    DB_PRINT("Write 0x%" PRIx32 ", 0x%"HWADDR_PRIx"\n", value, addr);
>> +
>> +    switch (addr) {
>> +    case USART_SR:
>> +        if (value <= 0x3FF) {
>> +            s->usart_sr = value;
>> +        } else {
>> +            s->usart_sr &= value;
>> +        }
>
> If you set the interrupt enable bit before RXNE is cleared, should the
> interrupt raise here?

I'm not sure. I can't find anything that specifies either way, but I'm
going to assume yes as they represent it with AND gates.

Thanks,

Alistair

>
> Regards,
> Peter
>
>> +        return;
>> +    case USART_DR:
>> +        if (value < 0xF000) {
>> +            ch = value;
>> +            if (s->chr) {
>> +                qemu_chr_fe_write_all(s->chr, &ch, 1);
>> +            }
>> +            s->usart_sr |= USART_SR_TC;
>> +            s->usart_sr &= ~USART_SR_TXE;
>> +        }
>> +        return;
>> +    case USART_BRR:
>> +        s->usart_brr = value;
>> +        return;
>> +    case USART_CR1:
>> +        s->usart_cr1 = value;
>> +        return;
>> +    case USART_CR2:
>> +        s->usart_cr2 = value;
>> +        return;
>> +    case USART_CR3:
>> +        s->usart_cr3 = value;
>> +        return;
>> +    case USART_GTPR:
>> +        s->usart_gtpr = value;
>> +        return;
>> +    default:
>> +        qemu_log_mask(LOG_GUEST_ERROR,
>> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
>> +    }
>> +}
>> +
>> +static const MemoryRegionOps stm32f2xx_usart_ops = {
>> +    .read = stm32f2xx_usart_read,
>> +    .write = stm32f2xx_usart_write,
>> +    .endianness = DEVICE_NATIVE_ENDIAN,
>> +};
>> +
>> +static void stm32f2xx_usart_init(Object *obj)
>> +{
>> +    STM32F2XXUsartState *s = STM32F2XX_USART(obj);
>> +
>> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
>> +
>> +    memory_region_init_io(&s->mmio, obj, &stm32f2xx_usart_ops, s,
>> +                          TYPE_STM32F2XX_USART, 0x2000);
>> +    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
>> +
>> +    s->chr = qemu_char_get_next_serial();
>> +
>> +    if (s->chr) {
>> +        qemu_chr_add_handlers(s->chr, stm32f2xx_usart_can_receive,
>> +                              stm32f2xx_usart_receive, NULL, s);
>> +    }
>> +}
>> +
>> +static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> +    dc->reset = stm32f2xx_usart_reset;
>> +}
>> +
>> +static const TypeInfo stm32f2xx_usart_info = {
>> +    .name          = TYPE_STM32F2XX_USART,
>> +    .parent        = TYPE_SYS_BUS_DEVICE,
>> +    .instance_size = sizeof(STM32F2XXUsartState),
>> +    .instance_init = stm32f2xx_usart_init,
>> +    .class_init    = stm32f2xx_usart_class_init,
>> +};
>> +
>> +static void stm32f2xx_usart_register_types(void)
>> +{
>> +    type_register_static(&stm32f2xx_usart_info);
>> +}
>> +
>> +type_init(stm32f2xx_usart_register_types)
>> diff --git a/include/hw/char/stm32f2xx_usart.h b/include/hw/char/stm32f2xx_usart.h
>> new file mode 100644
>> index 0000000..c9fad3c
>> --- /dev/null
>> +++ b/include/hw/char/stm32f2xx_usart.h
>> @@ -0,0 +1,69 @@
>> +/*
>> + * STM32F2XX USART
>> + *
>> + * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a copy
>> + * of this software and associated documentation files (the "Software"), to deal
>> + * in the Software without restriction, including without limitation the rights
>> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>> + * copies of the Software, and to permit persons to whom the Software is
>> + * furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>> + * THE SOFTWARE.
>> + */
>> +
>> +#include "hw/sysbus.h"
>> +#include "sysemu/char.h"
>> +#include "hw/hw.h"
>> +
>> +#define USART_SR   0x00
>> +#define USART_DR   0x04
>> +#define USART_BRR  0x08
>> +#define USART_CR1  0x0C
>> +#define USART_CR2  0x10
>> +#define USART_CR3  0x14
>> +#define USART_GTPR 0x18
>> +
>> +#define USART_SR_RESET 0x00C00000
>> +
>> +#define USART_SR_TXE  (1 << 7)
>> +#define USART_SR_TC   (1 << 6)
>> +#define USART_SR_RXNE (1 << 5)
>> +
>> +#define USART_CR1_UE  (1 << 13)
>> +#define USART_CR1_RXNEIE  (1 << 5)
>> +#define USART_CR1_TE  (1 << 3)
>> +#define USART_CR1_RE  (1 << 2)
>> +
>> +#define TYPE_STM32F2XX_USART "stm32f2xx-usart"
>> +#define STM32F2XX_USART(obj) \
>> +    OBJECT_CHECK(STM32F2XXUsartState, (obj), TYPE_STM32F2XX_USART)
>> +
>> +typedef struct {
>> +    /* <private> */
>> +    SysBusDevice parent_obj;
>> +
>> +    /* <public> */
>> +    MemoryRegion mmio;
>> +
>> +    uint32_t usart_sr;
>> +    uint32_t usart_dr;
>> +    uint32_t usart_brr;
>> +    uint32_t usart_cr1;
>> +    uint32_t usart_cr2;
>> +    uint32_t usart_cr3;
>> +    uint32_t usart_gtpr;
>> +
>> +    CharDriverState *chr;
>> +    qemu_irq irq;
>> +} STM32F2XXUsartState;
>> --
>> 2.1.0
>>
>>

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

* Re: [Qemu-devel] [PATCH v7 1/7] stm32f2xx_timer: Add the stm32f2xx Timer
  2014-12-16  5:39   ` Peter Crosthwaite
@ 2014-12-26  3:08     ` Alistair Francis
  0 siblings, 0 replies; 13+ messages in thread
From: Alistair Francis @ 2014-12-26  3:08 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Peter Maydell, Martin Galvan, qemu-devel@nongnu.org Developers,
	Konstanty Bialkowski

On Tue, Dec 16, 2014 at 3:39 PM, Peter Crosthwaite
<peter.crosthwaite@xilinx.com> wrote:
> On Wed, Dec 10, 2014 at 12:46 AM, Alistair Francis <alistair23@gmail.com> wrote:
>> This patch adds the stm32f2xx timers: TIM2, TIM3, TIM4 and TIM5
>> to QEMU.
>>
>> Signed-off-by: Alistair Francis <alistair23@gmail.com>
>> ---
>> V6:
>>  - Rename to STM32F2XX
>>  - Change the timer calculations to use ns
>>  - Update the value to timer_mod to ensure it is in ns
>>  - Account for reloadable/resetable timer
>>     - Thanks to Peter C for pointing this out
>> V4:
>>  - Update timer units again
>>     - Thanks to Peter C
>> V3:
>>  - Update debug statements
>>  - Correct the units for timer_mod
>>  - Correctly set timer_offset from resets
>> V2:
>>  - Reorder the Makefile config
>>  - Fix up the debug printing
>>  - Correct the timer event trigger
>>
>>  default-configs/arm-softmmu.mak    |   1 +
>>  hw/timer/Makefile.objs             |   2 +
>>  hw/timer/stm32f2xx_timer.c         | 331 +++++++++++++++++++++++++++++++++++++
>>  include/hw/timer/stm32f2xx_timer.h | 101 +++++++++++
>>  4 files changed, 435 insertions(+)
>>  create mode 100644 hw/timer/stm32f2xx_timer.c
>>  create mode 100644 include/hw/timer/stm32f2xx_timer.h
>>
>> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
>> index f3513fa..faea100 100644
>> --- a/default-configs/arm-softmmu.mak
>> +++ b/default-configs/arm-softmmu.mak
>> @@ -78,6 +78,7 @@ CONFIG_NSERIES=y
>>  CONFIG_REALVIEW=y
>>  CONFIG_ZAURUS=y
>>  CONFIG_ZYNQ=y
>> +CONFIG_STM32F2XX_TIMER=y
>>
>>  CONFIG_VERSATILE_PCI=y
>>  CONFIG_VERSATILE_I2C=y
>> diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
>> index 2c86c3d..133bd0d 100644
>> --- a/hw/timer/Makefile.objs
>> +++ b/hw/timer/Makefile.objs
>> @@ -31,3 +31,5 @@ obj-$(CONFIG_DIGIC) += digic-timer.o
>>  obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
>>
>>  obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o
>> +
>> +common-obj-$(CONFIG_STM32F2XX_TIMER) += stm32f2xx_timer.o
>> diff --git a/hw/timer/stm32f2xx_timer.c b/hw/timer/stm32f2xx_timer.c
>> new file mode 100644
>> index 0000000..df27540
>> --- /dev/null
>> +++ b/hw/timer/stm32f2xx_timer.c
>> @@ -0,0 +1,331 @@
>> +/*
>> + * STM32F2XX Timer
>> + *
>> + * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a copy
>> + * of this software and associated documentation files (the "Software"), to deal
>> + * in the Software without restriction, including without limitation the rights
>> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>> + * copies of the Software, and to permit persons to whom the Software is
>> + * furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>> + * THE SOFTWARE.
>> + */
>> +
>> +#include "hw/timer/stm32f2xx_timer.h"
>> +
>> +#ifndef STM_TIMER_ERR_DEBUG
>> +#define STM_TIMER_ERR_DEBUG 0
>> +#endif
>> +
>> +#define DB_PRINT_L(lvl, fmt, args...) do { \
>> +    if (STM_TIMER_ERR_DEBUG >= lvl) { \
>> +        qemu_log("%s: " fmt, __func__, ## args); \
>> +    } \
>> +} while (0);
>> +
>> +#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
>> +
>> +static void stm32f2xx_timer_set_alarm(STM32F2XXTimerState *s);
>> +
>> +static void stm32f2xx_timer_interrupt(void *opaque)
>> +{
>> +    STM32F2XXTimerState *s = opaque;
>> +
>> +    DB_PRINT("Interrupt\n");
>> +
>> +    if (s->tim_dier & TIM_DIER_UIE && s->tim_cr1 & TIM_CR1_CEN) {
>> +        s->tim_sr |= 1;
>> +        qemu_irq_pulse(s->irq);
>> +        stm32f2xx_timer_set_alarm(s);
>> +    }
>> +}
>> +
>> +static void stm32f2xx_timer_set_alarm(STM32F2XXTimerState *s)
>> +{
>> +    uint32_t ticks;
>> +    int64_t now;
>> +
>> +    DB_PRINT("Alarm set at: 0x%x\n", s->tim_cr1);
>> +
>> +    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
>> +    ticks = s->tim_arr -
>> +            ((muldiv64(s->freq_hz, now, 1000000000ULL) - s->tick_offset) /
>> +            (s->tim_psc + 1));
>
> ticks seems to be the auto-reload register minus the total number of
> ticks elapsed since reset (now - tick_offset). For subsequent reloads
> in periodic timing this will always be -ve. Does tick_offset need to
> be warped every time the timer hits and autoreloads?
>

That's a good point, I'll fix that up.

>> +
>> +    DB_PRINT("Alarm set in %d ticks\n", ticks);
>> +
>> +    if (ticks == 0) {
>> +        timer_del(s->timer);
>> +        stm32f2xx_timer_interrupt(s);
>> +    } else {
>> +        timer_mod(s->timer, now +
>> +                  muldiv64(ticks, 1000000000ULL, get_ticks_per_sec()));
>
> Doesn't seems right that that conversion from now -> ticks multiplies
> by ->freq_hz yet this conversion here divides out by
> get_ticks_per_sec. Should this be freq_hz too?
>

Yeah, it should. Will fix

>> +
>> +        DB_PRINT("Wait Time: %" PRId64 " ticks\n",
>> +                 now + muldiv64(ticks, 1000000000ULL, get_ticks_per_sec()));
>
> You should cache this in a local variable to remove the repeated expression.
>

Will fix

>> +    }
>> +}
>> +
>> +static void stm32f2xx_timer_reset(DeviceState *dev)
>> +{
>> +    STM32F2XXTimerState *s = STM32F2XXTIMER(dev);
>> +
>> +    s->tim_cr1 = 0;
>> +    s->tim_cr2 = 0;
>> +    s->tim_smcr = 0;
>> +    s->tim_dier = 0;
>> +    s->tim_sr = 0;
>> +    s->tim_egr = 0;
>> +    s->tim_ccmr1 = 0;
>> +    s->tim_ccmr2 = 0;
>> +    s->tim_ccer = 0;
>> +    s->tim_cnt = 0;
>> +    s->tim_psc = 0;
>> +    s->tim_arr = 0;
>> +    s->tim_ccr1 = 0;
>> +    s->tim_ccr2 = 0;
>> +    s->tim_ccr3 = 0;
>> +    s->tim_ccr4 = 0;
>> +    s->tim_dcr = 0;
>> +    s->tim_dmar = 0;
>> +    s->tim_or = 0;
>> +
>> +    s->tick_offset = muldiv64(s->freq_hz,
>> +                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
>> +                              1000000000ULL);
>> +
>> +    stm32f2xx_timer_set_alarm(s);
>
> Can the timer really arm itself coming out of reset?
>

No, will fix

>> +}
>> +
>> +static uint64_t stm32f2xx_timer_read(void *opaque, hwaddr offset,
>> +                           unsigned size)
>> +{
>> +    STM32F2XXTimerState *s = opaque;
>> +
>> +    DB_PRINT("Read 0x%"HWADDR_PRIx"\n", offset);
>> +
>> +    switch (offset) {
>> +    case TIM_CR1:
>> +        return s->tim_cr1;
>> +    case TIM_CR2:
>> +        return s->tim_cr2;
>> +    case TIM_SMCR:
>> +        return s->tim_smcr;
>> +    case TIM_DIER:
>> +        return s->tim_dier;
>> +    case TIM_SR:
>> +        return s->tim_sr;
>> +    case TIM_EGR:
>> +        return s->tim_egr;
>> +    case TIM_CCMR1:
>> +        return s->tim_ccmr1;
>> +    case TIM_CCMR2:
>> +        return s->tim_ccmr2;
>> +    case TIM_CCER:
>> +        return s->tim_ccer;
>> +    case TIM_CNT:
>> +        s->tim_cnt = muldiv64(s->freq_hz,
>> +                              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
>> +                              1000000000ULL) - s->tick_offset;
>
> The guest visible value of the timer should take into account the
> prescaler in some way I think?

I wasn't sure about what the guest should see, but I think you are
right. I will fix it.

Thanks,

Alistair

>
> Regards,
> Peter
>
>> +        return s->tim_cnt;
>> +    case TIM_PSC:
>> +        return s->tim_psc;
>> +    case TIM_ARR:
>> +        return s->tim_arr;
>> +    case TIM_CCR1:
>> +        return s->tim_ccr1;
>> +    case TIM_CCR2:
>> +        return s->tim_ccr2;
>> +    case TIM_CCR3:
>> +        return s->tim_ccr3;
>> +    case TIM_CCR4:
>> +        return s->tim_ccr4;
>> +    case TIM_DCR:
>> +        return s->tim_dcr;
>> +    case TIM_DMAR:
>> +        return s->tim_dmar;
>> +    case TIM_OR:
>> +        return s->tim_or;
>> +    default:
>> +        qemu_log_mask(LOG_GUEST_ERROR,
>> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, offset);
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static void stm32f2xx_timer_write(void *opaque, hwaddr offset,
>> +                        uint64_t val64, unsigned size)
>> +{
>> +    STM32F2XXTimerState *s = opaque;
>> +    uint32_t value = val64;
>> +
>> +    DB_PRINT("Write 0x%x, 0x%"HWADDR_PRIx"\n", value, offset);
>> +
>> +    switch (offset) {
>> +    case TIM_CR1:
>> +        s->tim_cr1 = value;
>> +        return;
>> +    case TIM_CR2:
>> +        s->tim_cr2 = value;
>> +        return;
>> +    case TIM_SMCR:
>> +        s->tim_smcr = value;
>> +        return;
>> +    case TIM_DIER:
>> +        s->tim_dier = value;
>> +        return;
>> +    case TIM_SR:
>> +        /* This is set by hardware and cleared by software */
>> +        s->tim_sr &= value;
>> +        return;
>> +    case TIM_EGR:
>> +        s->tim_egr = value;
>> +        if (s->tim_egr & TIM_EGR_UG) {
>> +            /* Re-init the counter */
>> +            stm32f2xx_timer_reset(DEVICE(s));
>> +        }
>> +        return;
>> +    case TIM_CCMR1:
>> +        s->tim_ccmr1 = value;
>> +        return;
>> +    case TIM_CCMR2:
>> +        s->tim_ccmr2 = value;
>> +        return;
>> +    case TIM_CCER:
>> +        s->tim_ccer = value;
>> +        return;
>> +    case TIM_CNT:
>> +        /* The guest is changing the clock counter.
>> +         * Subtract the difference between the value and the current time
>> +         * from tick_offset and update the timer alarm.
>> +         */
>> +        s->tick_offset -= value - (muldiv64(s->freq_hz,
>> +                                   qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
>> +                                   1000000000ULL) - s->tick_offset);
>> +        s->tim_cnt = value;
>> +        stm32f2xx_timer_set_alarm(s);
>> +        return;
>> +    case TIM_PSC:
>> +        s->tim_psc = value;
>> +        stm32f2xx_timer_set_alarm(s);
>> +        return;
>> +    case TIM_ARR:
>> +        s->tim_arr = value;
>> +        stm32f2xx_timer_set_alarm(s);
>> +        return;
>> +    case TIM_CCR1:
>> +        s->tim_ccr1 = value;
>> +        return;
>> +    case TIM_CCR2:
>> +        s->tim_ccr2 = value;
>> +        return;
>> +    case TIM_CCR3:
>> +        s->tim_ccr3 = value;
>> +        return;
>> +    case TIM_CCR4:
>> +        s->tim_ccr4 = value;
>> +        return;
>> +    case TIM_DCR:
>> +        s->tim_dcr = value;
>> +        return;
>> +    case TIM_DMAR:
>> +        s->tim_dmar = value;
>> +        return;
>> +    case TIM_OR:
>> +        s->tim_or = value;
>> +        return;
>> +    default:
>> +        qemu_log_mask(LOG_GUEST_ERROR,
>> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, offset);
>> +    }
>> +}
>> +
>> +static const MemoryRegionOps stm32f2xx_timer_ops = {
>> +    .read = stm32f2xx_timer_read,
>> +    .write = stm32f2xx_timer_write,
>> +    .endianness = DEVICE_NATIVE_ENDIAN,
>> +};
>> +
>> +static const VMStateDescription vmstate_stm32f2xx_timer = {
>> +    .name = TYPE_STM32F2XX_TIMER,
>> +    .version_id = 1,
>> +    .minimum_version_id = 1,
>> +    .fields = (VMStateField[]) {
>> +        VMSTATE_UINT32(tick_offset, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_cr1, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_cr2, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_smcr, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_dier, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_sr, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_egr, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_ccmr1, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_ccmr2, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_ccer, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_cnt, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_psc, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_arr, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_ccr1, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_ccr2, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_ccr3, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_ccr4, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_dcr, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_dmar, STM32F2XXTimerState),
>> +        VMSTATE_UINT32(tim_or, STM32F2XXTimerState),
>> +        VMSTATE_END_OF_LIST()
>> +    }
>> +};
>> +
>> +static Property stm32f2xx_timer_properties[] = {
>> +    DEFINE_PROP_UINT64("clock-frequency", struct STM32F2XXTimerState,
>> +                       freq_hz, 1000000000),
>> +    DEFINE_PROP_END_OF_LIST(),
>> +};
>> +
>> +static void stm32f2xx_timer_init(Object *obj)
>> +{
>> +    STM32F2XXTimerState *s = STM32F2XXTIMER(obj);
>> +
>> +    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
>> +
>> +    memory_region_init_io(&s->iomem, obj, &stm32f2xx_timer_ops, s,
>> +                          "stm32f2xx_timer", 0x2000);
>> +    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
>> +
>> +    s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, stm32f2xx_timer_interrupt, s);
>> +}
>> +
>> +static void stm32f2xx_timer_class_init(ObjectClass *klass, void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> +    dc->reset = stm32f2xx_timer_reset;
>> +    dc->props = stm32f2xx_timer_properties;
>> +    dc->vmsd = &vmstate_stm32f2xx_timer;
>> +}
>> +
>> +static const TypeInfo stm32f2xx_timer_info = {
>> +    .name          = TYPE_STM32F2XX_TIMER,
>> +    .parent        = TYPE_SYS_BUS_DEVICE,
>> +    .instance_size = sizeof(STM32F2XXTimerState),
>> +    .instance_init = stm32f2xx_timer_init,
>> +    .class_init    = stm32f2xx_timer_class_init,
>> +};
>> +
>> +static void stm32f2xx_timer_register_types(void)
>> +{
>> +    type_register_static(&stm32f2xx_timer_info);
>> +}
>> +
>> +type_init(stm32f2xx_timer_register_types)
>> diff --git a/include/hw/timer/stm32f2xx_timer.h b/include/hw/timer/stm32f2xx_timer.h
>> new file mode 100644
>> index 0000000..512fa16
>> --- /dev/null
>> +++ b/include/hw/timer/stm32f2xx_timer.h
>> @@ -0,0 +1,101 @@
>> +/*
>> + * STM32F2XX Timer
>> + *
>> + * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a copy
>> + * of this software and associated documentation files (the "Software"), to deal
>> + * in the Software without restriction, including without limitation the rights
>> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>> + * copies of the Software, and to permit persons to whom the Software is
>> + * furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>> + * THE SOFTWARE.
>> + */
>> +
>> +#ifndef HW_STM_TIMER_H
>> +#define HW_STM_TIMER_H
>> +
>> +#include "hw/sysbus.h"
>> +#include "qemu/timer.h"
>> +#include "sysemu/sysemu.h"
>> +
>> +#define TIM_CR1      0x00
>> +#define TIM_CR2      0x04
>> +#define TIM_SMCR     0x08
>> +#define TIM_DIER     0x0C
>> +#define TIM_SR       0x10
>> +#define TIM_EGR      0x14
>> +#define TIM_CCMR1    0x18
>> +#define TIM_CCMR2    0x1C
>> +#define TIM_CCER     0x20
>> +#define TIM_CNT      0x24
>> +#define TIM_PSC      0x28
>> +#define TIM_ARR      0x2C
>> +#define TIM_CCR1     0x34
>> +#define TIM_CCR2     0x38
>> +#define TIM_CCR3     0x3C
>> +#define TIM_CCR4     0x40
>> +#define TIM_DCR      0x48
>> +#define TIM_DMAR     0x4C
>> +#define TIM_OR       0x50
>> +
>> +#define TIM_CR1_CEN   1
>> +
>> +#define TIM_EGR_UG 1
>> +
>> +#define TIM_CCER_CC2E   (1 << 4)
>> +#define TIM_CCMR1_OC2M2 (1 << 14)
>> +#define TIM_CCMR1_OC2M1 (1 << 13)
>> +#define TIM_CCMR1_OC2M0 (1 << 12)
>> +#define TIM_CCMR1_OC2PE (1 << 11)
>> +
>> +#define TIM_DIER_UIE  1
>> +
>> +#define TYPE_STM32F2XX_TIMER "stm32f2xx-timer"
>> +#define STM32F2XXTIMER(obj) OBJECT_CHECK(STM32F2XXTimerState, \
>> +                            (obj), TYPE_STM32F2XX_TIMER)
>> +
>> +typedef struct STM32F2XXTimerState {
>> +    /* <private> */
>> +    SysBusDevice parent_obj;
>> +
>> +    /* <public> */
>> +    MemoryRegion iomem;
>> +    QEMUTimer *timer;
>> +    qemu_irq irq;
>> +
>> +    uint32_t tick_offset;
>> +    uint64_t freq_hz;
>> +
>> +    uint32_t tim_cr1;
>> +    uint32_t tim_cr2;
>> +    uint32_t tim_smcr;
>> +    uint32_t tim_dier;
>> +    uint32_t tim_sr;
>> +    uint32_t tim_egr;
>> +    uint32_t tim_ccmr1;
>> +    uint32_t tim_ccmr2;
>> +    uint32_t tim_ccer;
>> +    uint32_t tim_cnt;
>> +    uint32_t tim_psc;
>> +    uint32_t tim_arr;
>> +    uint32_t tim_ccr1;
>> +    uint32_t tim_ccr2;
>> +    uint32_t tim_ccr3;
>> +    uint32_t tim_ccr4;
>> +    uint32_t tim_dcr;
>> +    uint32_t tim_dmar;
>> +    uint32_t tim_or;
>> +} STM32F2XXTimerState;
>> +
>> +#endif
>> --
>> 2.1.0
>>
>>

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

end of thread, other threads:[~2014-12-26  3:09 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-10  8:46 [Qemu-devel] [PATCH v7 0/7] Netduino 2 Machine Model Alistair Francis
2014-12-10  8:46 ` [Qemu-devel] [PATCH v7 1/7] stm32f2xx_timer: Add the stm32f2xx Timer Alistair Francis
2014-12-16  5:39   ` Peter Crosthwaite
2014-12-26  3:08     ` Alistair Francis
2014-12-10  8:46 ` [Qemu-devel] [PATCH v7 2/7] stm32f2xx_USART: Add the stm32f2xx USART Controller Alistair Francis
2014-12-16  5:47   ` Peter Crosthwaite
2014-12-25  8:45     ` Alistair Francis
2014-12-10  8:46 ` [Qemu-devel] [PATCH v7 3/7] stm32f2xx_SYSCFG: Add the stm32f2xx SYSCFG Alistair Francis
2014-12-10  8:46 ` [Qemu-devel] [PATCH v7 4/7] target_arm: Remove memory region init from armv7m_init Alistair Francis
2014-12-10  8:47 ` [Qemu-devel] [PATCH v7 5/7] target_arm: Parameterise the irq lines for armv7m_init Alistair Francis
2014-12-10  8:47 ` [Qemu-devel] [PATCH v7 6/7] stm32f205: Add the stm32f205 SoC Alistair Francis
2014-12-10  8:47 ` [Qemu-devel] [PATCH v7 7/7] netduino2: Add the Netduino 2 Machine Alistair Francis
2014-12-15 17:37 ` [Qemu-devel] [PATCH v7 0/7] Netduino 2 Machine Model Peter Maydell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.