* [Qemu-devel] [PATCH v5 0/7] Netduino 2 Machine Model
@ 2014-10-16 12:53 Alistair Francis
2014-10-16 12:53 ` [Qemu-devel] [PATCH v5 1/7] stm32f205_timer: Add the stm32f205 Timer Alistair Francis
` (6 more replies)
0 siblings, 7 replies; 18+ messages in thread
From: Alistair Francis @ 2014-10-16 12:53 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.5
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
I have more devices in the works, I figured I would just start
with these three
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
V2:
- Fix up the Timer device
- Fix up the USART device
- Change the memory region names to match the Stellaris board
Changes from RFC:
- Code cleanup thanks to Peter C's comments
- Split the Makefile configs to device level
- Changes to armv7m_init with interupt and memory passing
- See the individual patches for more details
Alistair Francis (7):
stm32f205_timer: Add the stm32f205 Timer
stm32f205_USART: Add the stm32f205 USART Controller
stm32f205_SYSCFG: Add the stm32f205 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/stm32f205_usart.c | 218 +++++++++++++++++++++++++
hw/misc/Makefile.objs | 1 +
hw/misc/stm32f205_syscfg.c | 160 +++++++++++++++++++
hw/timer/Makefile.objs | 2 +
hw/timer/stm32f205_timer.c | 318 +++++++++++++++++++++++++++++++++++++
include/hw/arm/arm.h | 3 +-
include/hw/arm/stm32f205_soc.h | 69 ++++++++
include/hw/char/stm32f205_usart.h | 69 ++++++++
include/hw/misc/stm32f205_syscfg.h | 61 +++++++
include/hw/timer/stm32f205_timer.h | 101 ++++++++++++
17 files changed, 1247 insertions(+), 38 deletions(-)
create mode 100644 hw/arm/netduino2.c
create mode 100644 hw/arm/stm32f205_soc.c
create mode 100644 hw/char/stm32f205_usart.c
create mode 100644 hw/misc/stm32f205_syscfg.c
create mode 100644 hw/timer/stm32f205_timer.c
create mode 100644 include/hw/arm/stm32f205_soc.h
create mode 100644 include/hw/char/stm32f205_usart.h
create mode 100644 include/hw/misc/stm32f205_syscfg.h
create mode 100644 include/hw/timer/stm32f205_timer.h
--
1.9.1
^ permalink raw reply [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH v5 1/7] stm32f205_timer: Add the stm32f205 Timer
2014-10-16 12:53 [Qemu-devel] [PATCH v5 0/7] Netduino 2 Machine Model Alistair Francis
@ 2014-10-16 12:53 ` Alistair Francis
2014-10-20 7:18 ` Peter Crosthwaite
2014-10-16 12:53 ` [Qemu-devel] [PATCH v5 2/7] stm32f205_USART: Add the stm32f205 USART Controller Alistair Francis
` (5 subsequent siblings)
6 siblings, 1 reply; 18+ messages in thread
From: Alistair Francis @ 2014-10-16 12:53 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell, peter.crosthwaite, konstanty, martin.galvan
This patch adds the stm32f205 timers: TIM2, TIM3, TIM4 and TIM5
to QEMU.
Signed-off-by: Alistair Francis <alistair23@gmail.com>
---
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
Changes from RFC:
- Small changes to functionality and style. Thanks to Peter C
- Rename to make the timer more generic
- Split the config settings to device level
default-configs/arm-softmmu.mak | 1 +
hw/timer/Makefile.objs | 2 +
hw/timer/stm32f205_timer.c | 318 +++++++++++++++++++++++++++++++++++++
include/hw/timer/stm32f205_timer.h | 101 ++++++++++++
4 files changed, 422 insertions(+)
create mode 100644 hw/timer/stm32f205_timer.c
create mode 100644 include/hw/timer/stm32f205_timer.h
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index f3513fa..cf23b24 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_STM32F205_TIMER=y
CONFIG_VERSATILE_PCI=y
CONFIG_VERSATILE_I2C=y
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index 2c86c3d..4bd9617 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_STM32F205_TIMER) += stm32f205_timer.o
diff --git a/hw/timer/stm32f205_timer.c b/hw/timer/stm32f205_timer.c
new file mode 100644
index 0000000..aace8df
--- /dev/null
+++ b/hw/timer/stm32f205_timer.c
@@ -0,0 +1,318 @@
+/*
+ * STM32F205 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/stm32f205_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 stm32f205_timer_set_alarm(STM32f205TimerState *s);
+
+static void stm32f205_timer_interrupt(void *opaque)
+{
+ STM32f205TimerState *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);
+ stm32f205_timer_set_alarm(s);
+ }
+}
+
+static void stm32f205_timer_set_alarm(STM32f205TimerState *s)
+{
+ uint32_t ticks;
+ int64_t now;
+
+ DB_PRINT("Alarm set at: 0x%x\n", s->tim_cr1);
+
+ now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
+ ticks = s->tim_arr - ((s->tick_offset + (now * (s->freq_hz / 1000))) /
+ (s->tim_psc + 1));
+
+ DB_PRINT("Alarm set in %d ticks\n", ticks);
+
+ if (ticks == 0) {
+ timer_del(s->timer);
+ stm32f205_timer_interrupt(s);
+ } else {
+ timer_mod(s->timer, ((now * (s->freq_hz / 1000)) / (s->tim_psc + 1)) +
+ (int64_t) ticks);
+ DB_PRINT("Wait Time: %" PRId64 " ticks\n",
+ ((now * (s->freq_hz / 1000)) / (s->tim_psc + 1)) +
+ (int64_t) ticks);
+ }
+}
+
+static void stm32f205_timer_reset(DeviceState *dev)
+{
+ STM32f205TimerState *s = STM32F205TIMER(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 = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) *
+ (s->freq_hz / 1000);
+}
+
+static uint64_t stm32f205_timer_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ STM32f205TimerState *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 = s->tick_offset + (qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) *
+ (s->freq_hz / 1000));
+ 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 stm32f205_timer_write(void *opaque, hwaddr offset,
+ uint64_t val64, unsigned size)
+{
+ STM32f205TimerState *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 */
+ stm32f205_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:
+ s->tim_cnt = value;
+ stm32f205_timer_set_alarm(s);
+ return;
+ case TIM_PSC:
+ s->tim_psc = value;
+ return;
+ case TIM_ARR:
+ s->tim_arr = value;
+ stm32f205_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 stm32f205_timer_ops = {
+ .read = stm32f205_timer_read,
+ .write = stm32f205_timer_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_stm32f205_timer = {
+ .name = TYPE_STM32F205_TIMER,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(tick_offset, STM32f205TimerState),
+ VMSTATE_UINT32(tim_cr1, STM32f205TimerState),
+ VMSTATE_UINT32(tim_cr2, STM32f205TimerState),
+ VMSTATE_UINT32(tim_smcr, STM32f205TimerState),
+ VMSTATE_UINT32(tim_dier, STM32f205TimerState),
+ VMSTATE_UINT32(tim_sr, STM32f205TimerState),
+ VMSTATE_UINT32(tim_egr, STM32f205TimerState),
+ VMSTATE_UINT32(tim_ccmr1, STM32f205TimerState),
+ VMSTATE_UINT32(tim_ccmr2, STM32f205TimerState),
+ VMSTATE_UINT32(tim_ccer, STM32f205TimerState),
+ VMSTATE_UINT32(tim_cnt, STM32f205TimerState),
+ VMSTATE_UINT32(tim_psc, STM32f205TimerState),
+ VMSTATE_UINT32(tim_arr, STM32f205TimerState),
+ VMSTATE_UINT32(tim_ccr1, STM32f205TimerState),
+ VMSTATE_UINT32(tim_ccr2, STM32f205TimerState),
+ VMSTATE_UINT32(tim_ccr3, STM32f205TimerState),
+ VMSTATE_UINT32(tim_ccr4, STM32f205TimerState),
+ VMSTATE_UINT32(tim_dcr, STM32f205TimerState),
+ VMSTATE_UINT32(tim_dmar, STM32f205TimerState),
+ VMSTATE_UINT32(tim_or, STM32f205TimerState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property stm32f205_timer_properties[] = {
+ DEFINE_PROP_UINT64("clock-frequency", struct STM32f205TimerState,
+ freq_hz, 1000000000),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void stm32f205_timer_init(Object *obj)
+{
+ STM32f205TimerState *s = STM32F205TIMER(obj);
+
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+
+ memory_region_init_io(&s->iomem, obj, &stm32f205_timer_ops, s,
+ "stm32f205_timer", 0x2000);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
+
+ s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, stm32f205_timer_interrupt, s);
+}
+
+static void stm32f205_timer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = stm32f205_timer_reset;
+ dc->props = stm32f205_timer_properties;
+ dc->vmsd = &vmstate_stm32f205_timer;
+}
+
+static const TypeInfo stm32f205_timer_info = {
+ .name = TYPE_STM32F205_TIMER,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(STM32f205TimerState),
+ .instance_init = stm32f205_timer_init,
+ .class_init = stm32f205_timer_class_init,
+};
+
+static void stm32f205_timer_register_types(void)
+{
+ type_register_static(&stm32f205_timer_info);
+}
+
+type_init(stm32f205_timer_register_types)
diff --git a/include/hw/timer/stm32f205_timer.h b/include/hw/timer/stm32f205_timer.h
new file mode 100644
index 0000000..9425cb1
--- /dev/null
+++ b/include/hw/timer/stm32f205_timer.h
@@ -0,0 +1,101 @@
+/*
+ * STM32F205 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_STM32F205_TIMER "stm32f205-timer"
+#define STM32F205TIMER(obj) OBJECT_CHECK(STM32f205TimerState, \
+ (obj), TYPE_STM32F205_TIMER)
+
+typedef struct STM32f205TimerState {
+ /* <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;
+} STM32f205TimerState;
+
+#endif
--
1.9.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH v5 2/7] stm32f205_USART: Add the stm32f205 USART Controller
2014-10-16 12:53 [Qemu-devel] [PATCH v5 0/7] Netduino 2 Machine Model Alistair Francis
2014-10-16 12:53 ` [Qemu-devel] [PATCH v5 1/7] stm32f205_timer: Add the stm32f205 Timer Alistair Francis
@ 2014-10-16 12:53 ` Alistair Francis
2014-10-20 7:27 ` Peter Crosthwaite
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 3/7] stm32f205_SYSCFG: Add the stm32f205 SYSCFG Alistair Francis
` (4 subsequent siblings)
6 siblings, 1 reply; 18+ messages in thread
From: Alistair Francis @ 2014-10-16 12:53 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell, peter.crosthwaite, konstanty, martin.galvan
This patch adds the stm32f205 USART controller
(UART also uses the same controller).
Signed-off-by: Alistair Francis <alistair23@gmail.com>
---
default-configs/arm-softmmu.mak | 1 +
hw/char/Makefile.objs | 1 +
hw/char/stm32f205_usart.c | 218 ++++++++++++++++++++++++++++++++++++++
include/hw/char/stm32f205_usart.h | 69 ++++++++++++
4 files changed, 289 insertions(+)
create mode 100644 hw/char/stm32f205_usart.c
create mode 100644 include/hw/char/stm32f205_usart.h
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index cf23b24..422dec0 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_STM32F205_TIMER=y
+CONFIG_STM32F205_USART=y
CONFIG_VERSATILE_PCI=y
CONFIG_VERSATILE_I2C=y
diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
index 317385d..c7b3ce4 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_STM32F205_USART) += stm32f205_usart.o
common-obj-$(CONFIG_ETRAXFS) += etraxfs_ser.o
common-obj-$(CONFIG_ISA_DEBUG) += debugcon.o
diff --git a/hw/char/stm32f205_usart.c b/hw/char/stm32f205_usart.c
new file mode 100644
index 0000000..9d399b8
--- /dev/null
+++ b/hw/char/stm32f205_usart.c
@@ -0,0 +1,218 @@
+/*
+ * STM32F205 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/stm32f205_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 stm32f205_usart_can_receive(void *opaque)
+{
+ STM32f205UsartState *s = opaque;
+
+ if (!(s->usart_sr & USART_SR_RXNE)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static void stm32f205_usart_receive(void *opaque, const uint8_t *buf, int size)
+{
+ STM32f205UsartState *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 stm32f205_usart_reset(DeviceState *dev)
+{
+ STM32f205UsartState *s = STM32F205_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 stm32f205_usart_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ STM32f205UsartState *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;
+ 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,
+ "STM32F205_usart_read: Bad offset " \
+ "0x%"HWADDR_PRIx"\n", addr);
+ return 0;
+ }
+
+ return 0;
+}
+
+static void stm32f205_usart_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ STM32f205UsartState *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,
+ "STM32F205_usart_write: Bad offset " \
+ "0x%"HWADDR_PRIx"\n", addr);
+ }
+}
+
+static const MemoryRegionOps stm32f205_usart_ops = {
+ .read = stm32f205_usart_read,
+ .write = stm32f205_usart_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void stm32f205_usart_init(Object *obj)
+{
+ STM32f205UsartState *s = STM32F205_USART(obj);
+
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+
+ memory_region_init_io(&s->mmio, obj, &stm32f205_usart_ops, s,
+ TYPE_STM32F205_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, stm32f205_usart_can_receive,
+ stm32f205_usart_receive, NULL, s);
+ }
+}
+
+static void stm32f205_usart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = stm32f205_usart_reset;
+}
+
+static const TypeInfo stm32f205_usart_info = {
+ .name = TYPE_STM32F205_USART,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(STM32f205UsartState),
+ .instance_init = stm32f205_usart_init,
+ .class_init = stm32f205_usart_class_init,
+};
+
+static void stm32f205_usart_register_types(void)
+{
+ type_register_static(&stm32f205_usart_info);
+}
+
+type_init(stm32f205_usart_register_types)
diff --git a/include/hw/char/stm32f205_usart.h b/include/hw/char/stm32f205_usart.h
new file mode 100644
index 0000000..e121bf3
--- /dev/null
+++ b/include/hw/char/stm32f205_usart.h
@@ -0,0 +1,69 @@
+/*
+ * STM32F205 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_STM32F205_USART "stm32f205-usart"
+#define STM32F205_USART(obj) \
+ OBJECT_CHECK(STM32f205UsartState, (obj), TYPE_STM32F205_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;
+} STM32f205UsartState;
--
1.9.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH v5 3/7] stm32f205_SYSCFG: Add the stm32f205 SYSCFG
2014-10-16 12:53 [Qemu-devel] [PATCH v5 0/7] Netduino 2 Machine Model Alistair Francis
2014-10-16 12:53 ` [Qemu-devel] [PATCH v5 1/7] stm32f205_timer: Add the stm32f205 Timer Alistair Francis
2014-10-16 12:53 ` [Qemu-devel] [PATCH v5 2/7] stm32f205_USART: Add the stm32f205 USART Controller Alistair Francis
@ 2014-10-16 12:54 ` Alistair Francis
2014-10-20 7:35 ` Peter Crosthwaite
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 4/7] target_arm: Remove memory region init from armv7m_init Alistair Francis
` (3 subsequent siblings)
6 siblings, 1 reply; 18+ messages in thread
From: Alistair Francis @ 2014-10-16 12:54 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.maydell, peter.crosthwaite, konstanty, martin.galvan
This patch adds the stm32f205 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>
---
default-configs/arm-softmmu.mak | 1 +
hw/misc/Makefile.objs | 1 +
hw/misc/stm32f205_syscfg.c | 160 +++++++++++++++++++++++++++++++++++++
include/hw/misc/stm32f205_syscfg.h | 61 ++++++++++++++
4 files changed, 223 insertions(+)
create mode 100644 hw/misc/stm32f205_syscfg.c
create mode 100644 include/hw/misc/stm32f205_syscfg.h
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 422dec0..a2ea8f7 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -80,6 +80,7 @@ CONFIG_ZAURUS=y
CONFIG_ZYNQ=y
CONFIG_STM32F205_TIMER=y
CONFIG_STM32F205_USART=y
+CONFIG_STM32F205_SYSCFG=y
CONFIG_VERSATILE_PCI=y
CONFIG_VERSATILE_I2C=y
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 979e532..63f03bd 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_STM32F205_SYSCFG) += stm32f205_syscfg.o
obj-$(CONFIG_PVPANIC) += pvpanic.o
diff --git a/hw/misc/stm32f205_syscfg.c b/hw/misc/stm32f205_syscfg.c
new file mode 100644
index 0000000..82aa50f
--- /dev/null
+++ b/hw/misc/stm32f205_syscfg.c
@@ -0,0 +1,160 @@
+/*
+ * STM32F205 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/stm32f205_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 stm32f205_syscfg_reset(DeviceState *dev)
+{
+ STM32f205SyscfgState *s = STM32F205_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 stm32f205_syscfg_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ STM32f205SyscfgState *s = opaque;
+
+ DB_PRINT("0x%x\n", (uint) 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,
+ "STM32F205_syscfg_read: Bad offset %x\n", (int)addr);
+ return 0;
+ }
+
+ return 0;
+}
+
+static void stm32f205_syscfg_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ STM32f205SyscfgState *s = opaque;
+ uint32_t value = val64;
+
+ DB_PRINT("0x%x, 0x%x\n", value, (uint) addr);
+
+ switch (addr) {
+ case SYSCFG_MEMRMP:
+ qemu_log_mask(LOG_UNIMP,
+ "STM32F205_syscfg_write: Changeing the memory mapping " \
+ "isn't supported in QEMU\n");
+ return;
+ case SYSCFG_PMC:
+ qemu_log_mask(LOG_UNIMP,
+ "STM32F205_syscfg_write: Peripheral mode configuration " \
+ "isn't supported in QEMU\n");
+ 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,
+ "STM32F205_syscfg_write: Bad offset %x\n", (int)addr);
+ }
+}
+
+static const MemoryRegionOps stm32f205_syscfg_ops = {
+ .read = stm32f205_syscfg_read,
+ .write = stm32f205_syscfg_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void stm32f205_syscfg_init(Object *obj)
+{
+ STM32f205SyscfgState *s = STM32F205_SYSCFG(obj);
+
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+
+ memory_region_init_io(&s->mmio, obj, &stm32f205_syscfg_ops, s,
+ TYPE_STM32F205_SYSCFG, 0x2000);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static void stm32f205_syscfg_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = stm32f205_syscfg_reset;
+}
+
+static const TypeInfo stm32f205_syscfg_info = {
+ .name = TYPE_STM32F205_SYSCFG,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(STM32f205SyscfgState),
+ .instance_init = stm32f205_syscfg_init,
+ .class_init = stm32f205_syscfg_class_init,
+};
+
+static void stm32f205_syscfg_register_types(void)
+{
+ type_register_static(&stm32f205_syscfg_info);
+}
+
+type_init(stm32f205_syscfg_register_types)
diff --git a/include/hw/misc/stm32f205_syscfg.h b/include/hw/misc/stm32f205_syscfg.h
new file mode 100644
index 0000000..9c5556f
--- /dev/null
+++ b/include/hw/misc/stm32f205_syscfg.h
@@ -0,0 +1,61 @@
+/*
+ * STM32F205 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_STM32F205_SYSCFG "stm32f205-syscfg"
+#define STM32F205_SYSCFG(obj) \
+ OBJECT_CHECK(STM32f205SyscfgState, (obj), TYPE_STM32F205_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;
+} STM32f205SyscfgState;
+
+#endif
--
1.9.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH v5 4/7] target_arm: Remove memory region init from armv7m_init
2014-10-16 12:53 [Qemu-devel] [PATCH v5 0/7] Netduino 2 Machine Model Alistair Francis
` (2 preceding siblings ...)
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 3/7] stm32f205_SYSCFG: Add the stm32f205 SYSCFG Alistair Francis
@ 2014-10-16 12:54 ` Alistair Francis
2014-10-20 7:40 ` Peter Crosthwaite
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 5/7] target_arm: Parameterise the irq lines for armv7m_init Alistair Francis
` (2 subsequent siblings)
6 siblings, 1 reply; 18+ messages in thread
From: Alistair Francis @ 2014-10-16 12:54 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>
---
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 */
--
1.9.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH v5 5/7] target_arm: Parameterise the irq lines for armv7m_init
2014-10-16 12:53 [Qemu-devel] [PATCH v5 0/7] Netduino 2 Machine Model Alistair Francis
` (3 preceding siblings ...)
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 4/7] target_arm: Remove memory region init from armv7m_init Alistair Francis
@ 2014-10-16 12:54 ` Alistair Francis
2014-10-20 7:41 ` Peter Crosthwaite
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 6/7] stm32f205: Add the stm32f205 SoC Alistair Francis
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 7/7] netduino2: Add the Netduino 2 Machine Alistair Francis
6 siblings, 1 reply; 18+ messages in thread
From: Alistair Francis @ 2014-10-16 12:54 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>
---
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 */
--
1.9.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH v5 6/7] stm32f205: Add the stm32f205 SoC
2014-10-16 12:53 [Qemu-devel] [PATCH v5 0/7] Netduino 2 Machine Model Alistair Francis
` (4 preceding siblings ...)
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 5/7] target_arm: Parameterise the irq lines for armv7m_init Alistair Francis
@ 2014-10-16 12:54 ` Alistair Francis
2014-10-20 7:47 ` Peter Crosthwaite
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 7/7] netduino2: Add the Netduino 2 Machine Alistair Francis
6 siblings, 1 reply; 18+ messages in thread
From: Alistair Francis @ 2014-10-16 12:54 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>
---
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 a2ea8f7..8068100 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -81,6 +81,7 @@ CONFIG_ZYNQ=y
CONFIG_STM32F205_TIMER=y
CONFIG_STM32F205_USART=y
CONFIG_STM32F205_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..bd9514e
--- /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[] = { 0x40000000, 0x40000400,
+ 0x40000800, 0x40000C00 };
+static const uint32_t usart_addr[] = { 0x40011000, 0x40004400,
+ 0x40004800, 0x40004C00, 0x40005000, 0x40011400 };
+
+static const int timer_irq[] = {28, 29, 30, 50};
+static const int usart_irq[] = {37, 38, 39, 52, 53, 71, 82, 83};
+
+static void stm32f205_soc_initfn(Object *obj)
+{
+ STM32F205State *s = STM32F205_SOC(obj);
+ int i;
+
+ object_initialize(&s->syscfg, sizeof(s->syscfg), TYPE_STM32F205_SYSCFG);
+ qdev_set_parent_bus(DEVICE(&s->syscfg), sysbus_get_default());
+
+ for (i = 0; i < 5; i++) {
+ object_initialize(&s->usart[i], sizeof(s->usart[i]),
+ TYPE_STM32F205_USART);
+ qdev_set_parent_bus(DEVICE(&s->usart[i]), sysbus_get_default());
+ }
+
+ for (i = 0; i < 4; i++) {
+ object_initialize(&s->timer[i], sizeof(s->timer[i]),
+ TYPE_STM32F205_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, "netduino.flash", FLASH_SIZE,
+ &error_abort);
+ memory_region_init_alias(flash_alias, NULL, "netduino.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, "netduino.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 < 5; 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 < 4; 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..addc555
--- /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/stm32f205_syscfg.h"
+#include "hw/timer/stm32f205_timer.h"
+#include "hw/char/stm32f205_usart.h"
+
+#define TYPE_STM32F205_SOC "stm32f205_soc"
+#define STM32F205_SOC(obj) \
+ OBJECT_CHECK(STM32F205State, (obj), TYPE_STM32F205_SOC)
+
+#define STM_NUM_USARTS 5
+#define STM_NUM_TIMERS 5
+
+#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;
+
+ STM32f205SyscfgState syscfg;
+ STM32f205UsartState usart[STM_NUM_USARTS];
+ STM32f205TimerState timer[STM_NUM_TIMERS];
+} STM32F205State;
+
+#endif
--
1.9.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [Qemu-devel] [PATCH v5 7/7] netduino2: Add the Netduino 2 Machine
2014-10-16 12:53 [Qemu-devel] [PATCH v5 0/7] Netduino 2 Machine Model Alistair Francis
` (5 preceding siblings ...)
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 6/7] stm32f205: Add the stm32f205 SoC Alistair Francis
@ 2014-10-16 12:54 ` Alistair Francis
6 siblings, 0 replies; 18+ messages in thread
From: Alistair Francis @ 2014-10-16 12:54 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);
--
1.9.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [Qemu-devel] [PATCH v5 1/7] stm32f205_timer: Add the stm32f205 Timer
2014-10-16 12:53 ` [Qemu-devel] [PATCH v5 1/7] stm32f205_timer: Add the stm32f205 Timer Alistair Francis
@ 2014-10-20 7:18 ` Peter Crosthwaite
2014-10-21 7:05 ` Alistair Francis
0 siblings, 1 reply; 18+ messages in thread
From: Peter Crosthwaite @ 2014-10-20 7:18 UTC (permalink / raw)
To: Alistair Francis
Cc: Peter Maydell, Martin Galvan, qemu-devel@nongnu.org Developers,
Konstanty Bialkowski
Sorry about the review delay...
On Thu, Oct 16, 2014 at 10:53 PM, Alistair Francis <alistair23@gmail.com> wrote:
> This patch adds the stm32f205 timers: TIM2, TIM3, TIM4 and TIM5
> to QEMU.
>
> Signed-off-by: Alistair Francis <alistair23@gmail.com>
> ---
> 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
> Changes from RFC:
> - Small changes to functionality and style. Thanks to Peter C
> - Rename to make the timer more generic
> - Split the config settings to device level
>
> default-configs/arm-softmmu.mak | 1 +
> hw/timer/Makefile.objs | 2 +
> hw/timer/stm32f205_timer.c | 318 +++++++++++++++++++++++++++++++++++++
> include/hw/timer/stm32f205_timer.h | 101 ++++++++++++
> 4 files changed, 422 insertions(+)
> create mode 100644 hw/timer/stm32f205_timer.c
> create mode 100644 include/hw/timer/stm32f205_timer.h
>
> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
> index f3513fa..cf23b24 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_STM32F205_TIMER=y
>
> CONFIG_VERSATILE_PCI=y
> CONFIG_VERSATILE_I2C=y
> diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
> index 2c86c3d..4bd9617 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_STM32F205_TIMER) += stm32f205_timer.o
> diff --git a/hw/timer/stm32f205_timer.c b/hw/timer/stm32f205_timer.c
> new file mode 100644
> index 0000000..aace8df
> --- /dev/null
> +++ b/hw/timer/stm32f205_timer.c
> @@ -0,0 +1,318 @@
> +/*
> + * STM32F205 Timer
ST doc RM0033 which docs this timer refers to a larger family of SOCs.
I think you can change this from 205 to 2XX probably globally for the
series.
> + *
> + * 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/stm32f205_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 stm32f205_timer_set_alarm(STM32f205TimerState *s);
> +
> +static void stm32f205_timer_interrupt(void *opaque)
> +{
> + STM32f205TimerState *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);
> + stm32f205_timer_set_alarm(s);
> + }
> +}
> +
> +static void stm32f205_timer_set_alarm(STM32f205TimerState *s)
> +{
> + uint32_t ticks;
> + int64_t now;
> +
> + DB_PRINT("Alarm set at: 0x%x\n", s->tim_cr1);
> +
> + now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
So now is in terms of ms.
> + ticks = s->tim_arr - ((s->tick_offset + (now * (s->freq_hz / 1000))) /
tick_offset is terms of clock-cycles-before-prescalar. ticks and
tim_arr must be in terms of clock-cycles-post-pre-scalar.
I'm slightly hazy on definition of tick_offset but i'm guessing its
the time offset of when the timer started expressed in
before-prescalar cycles? I would then expect this to be:
ticks = tim_arr - (now * (scale) - tick_offset).
with (now * scale - tick_offset) / tim_psc corresponding to the
current value of the running timer (tim_cnt?).
> + (s->tim_psc + 1));
So in total this expression is calculating a number of clock cycles
until a hit as "ticks".
> +
> + DB_PRINT("Alarm set in %d ticks\n", ticks);
> +
> + if (ticks == 0) {
What if ticks is -ve due to a late callback of set_alarm? It will
probably work, but it seems inconsistent that you rely on the callback
path for -ve and +ve tick balances but have a fast path for when ticks
happens to balance to exactly 0. This fast path should probably handle
-ve's or you could just ditch it entirely.
> + timer_del(s->timer);
> + stm32f205_timer_interrupt(s);
> + } else {
> + timer_mod(s->timer, ((now * (s->freq_hz / 1000)) / (s->tim_psc + 1)) +
Common sub-expression (now * (s->freq_hz / 1000)) / (s->tim_psc + 1)
with calculation of "ticks" above can be cached in a variable. but ...
> + (int64_t) ticks);
this calculation has me confused. My understanding is timer_mode
should be given an absolute value as time. s->timer is defined as a ns
timer whereas this calculation is a clock cycles value.
> + DB_PRINT("Wait Time: %" PRId64 " ticks\n",
> + ((now * (s->freq_hz / 1000)) / (s->tim_psc + 1)) +
> + (int64_t) ticks);
> + }
> +}
> +
> +static void stm32f205_timer_reset(DeviceState *dev)
> +{
> + STM32f205TimerState *s = STM32F205TIMER(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 = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) *
> + (s->freq_hz / 1000);
> +}
> +
> +static uint64_t stm32f205_timer_read(void *opaque, hwaddr offset,
> + unsigned size)
> +{
> + STM32f205TimerState *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 = s->tick_offset + (qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) *
> + (s->freq_hz / 1000));
Same comment above about subbing tick_offset rather than adding.
> + 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 stm32f205_timer_write(void *opaque, hwaddr offset,
> + uint64_t val64, unsigned size)
> +{
> + STM32f205TimerState *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 */
> + stm32f205_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:
> + s->tim_cnt = value;
You set tim_cnt here, presumably setting the value of the timer. But
set_alarm doesn't do anything with it. You need to warp tick_offset
here to account for the new 0-base of the timer. When I run into this
situation though, i generally use a two-variable approach where I have
both the value of the timer and the VM timer corresponding to it e.g.
uint32_t timer_val; /* value of timer in clock cycles */
uint64_t sync_time; /* VM time for when timer_val last updated */
And not bother trying to maintain an absolute (0-based) tick offset.
Then every time someone touches a prescalar, timer-value,
enable-switch, etc etc you just sync these two numbers first:
now = qemu_get_clock
timer_val += (now - sync_time) * scale(); /* scale is 0 for a disabled timer */
sync_time = now;
Then do your thing. Then delete or re-arm the callback if needed.
Otherwise you need a sync() pair much like the ones we used for the
ARM PMCCNTR around some of these ops.
> + stm32f205_timer_set_alarm(s);
> + return;
> + case TIM_PSC:
> + s->tim_psc = value;
Change the prescaler requires a rearming of the callback as it can
have an affect on the calculation of "ticks".
> + return;
> + case TIM_ARR:
> + s->tim_arr = value;
> + stm32f205_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 stm32f205_timer_ops = {
> + .read = stm32f205_timer_read,
> + .write = stm32f205_timer_write,
> + .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +static const VMStateDescription vmstate_stm32f205_timer = {
> + .name = TYPE_STM32F205_TIMER,
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_UINT32(tick_offset, STM32f205TimerState),
> + VMSTATE_UINT32(tim_cr1, STM32f205TimerState),
> + VMSTATE_UINT32(tim_cr2, STM32f205TimerState),
> + VMSTATE_UINT32(tim_smcr, STM32f205TimerState),
> + VMSTATE_UINT32(tim_dier, STM32f205TimerState),
> + VMSTATE_UINT32(tim_sr, STM32f205TimerState),
> + VMSTATE_UINT32(tim_egr, STM32f205TimerState),
> + VMSTATE_UINT32(tim_ccmr1, STM32f205TimerState),
> + VMSTATE_UINT32(tim_ccmr2, STM32f205TimerState),
> + VMSTATE_UINT32(tim_ccer, STM32f205TimerState),
> + VMSTATE_UINT32(tim_cnt, STM32f205TimerState),
> + VMSTATE_UINT32(tim_psc, STM32f205TimerState),
> + VMSTATE_UINT32(tim_arr, STM32f205TimerState),
> + VMSTATE_UINT32(tim_ccr1, STM32f205TimerState),
> + VMSTATE_UINT32(tim_ccr2, STM32f205TimerState),
> + VMSTATE_UINT32(tim_ccr3, STM32f205TimerState),
> + VMSTATE_UINT32(tim_ccr4, STM32f205TimerState),
> + VMSTATE_UINT32(tim_dcr, STM32f205TimerState),
> + VMSTATE_UINT32(tim_dmar, STM32f205TimerState),
> + VMSTATE_UINT32(tim_or, STM32f205TimerState),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static Property stm32f205_timer_properties[] = {
> + DEFINE_PROP_UINT64("clock-frequency", struct STM32f205TimerState,
> + freq_hz, 1000000000),
With 1GHz precision should you be using ns timing throughout instead
of ms? You may need to add some muldivs to account for the bigger
numbers.
Regards,
Peter
> + DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void stm32f205_timer_init(Object *obj)
> +{
> + STM32f205TimerState *s = STM32F205TIMER(obj);
> +
> + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
> +
> + memory_region_init_io(&s->iomem, obj, &stm32f205_timer_ops, s,
> + "stm32f205_timer", 0x2000);
> + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
> +
> + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, stm32f205_timer_interrupt, s);
> +}
> +
> +static void stm32f205_timer_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + dc->reset = stm32f205_timer_reset;
> + dc->props = stm32f205_timer_properties;
> + dc->vmsd = &vmstate_stm32f205_timer;
> +}
> +
> +static const TypeInfo stm32f205_timer_info = {
> + .name = TYPE_STM32F205_TIMER,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(STM32f205TimerState),
> + .instance_init = stm32f205_timer_init,
> + .class_init = stm32f205_timer_class_init,
> +};
> +
> +static void stm32f205_timer_register_types(void)
> +{
> + type_register_static(&stm32f205_timer_info);
> +}
> +
> +type_init(stm32f205_timer_register_types)
> diff --git a/include/hw/timer/stm32f205_timer.h b/include/hw/timer/stm32f205_timer.h
> new file mode 100644
> index 0000000..9425cb1
> --- /dev/null
> +++ b/include/hw/timer/stm32f205_timer.h
> @@ -0,0 +1,101 @@
> +/*
> + * STM32F205 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_STM32F205_TIMER "stm32f205-timer"
> +#define STM32F205TIMER(obj) OBJECT_CHECK(STM32f205TimerState, \
> + (obj), TYPE_STM32F205_TIMER)
> +
> +typedef struct STM32f205TimerState {
> + /* <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;
> +} STM32f205TimerState;
> +
> +#endif
> --
> 1.9.1
>
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Qemu-devel] [PATCH v5 2/7] stm32f205_USART: Add the stm32f205 USART Controller
2014-10-16 12:53 ` [Qemu-devel] [PATCH v5 2/7] stm32f205_USART: Add the stm32f205 USART Controller Alistair Francis
@ 2014-10-20 7:27 ` Peter Crosthwaite
0 siblings, 0 replies; 18+ messages in thread
From: Peter Crosthwaite @ 2014-10-20 7:27 UTC (permalink / raw)
To: Alistair Francis
Cc: Peter Maydell, Martin Galvan, qemu-devel@nongnu.org Developers,
Konstanty Bialkowski
On Thu, Oct 16, 2014 at 10:53 PM, Alistair Francis <alistair23@gmail.com> wrote:
> This patch adds the stm32f205 USART controller
> (UART also uses the same controller).
>
> Signed-off-by: Alistair Francis <alistair23@gmail.com>
> ---
> default-configs/arm-softmmu.mak | 1 +
> hw/char/Makefile.objs | 1 +
> hw/char/stm32f205_usart.c | 218 ++++++++++++++++++++++++++++++++++++++
> include/hw/char/stm32f205_usart.h | 69 ++++++++++++
> 4 files changed, 289 insertions(+)
> create mode 100644 hw/char/stm32f205_usart.c
> create mode 100644 include/hw/char/stm32f205_usart.h
>
> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
> index cf23b24..422dec0 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_STM32F205_TIMER=y
> +CONFIG_STM32F205_USART=y
>
> CONFIG_VERSATILE_PCI=y
> CONFIG_VERSATILE_I2C=y
> diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
> index 317385d..c7b3ce4 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_STM32F205_USART) += stm32f205_usart.o
>
> common-obj-$(CONFIG_ETRAXFS) += etraxfs_ser.o
> common-obj-$(CONFIG_ISA_DEBUG) += debugcon.o
> diff --git a/hw/char/stm32f205_usart.c b/hw/char/stm32f205_usart.c
> new file mode 100644
> index 0000000..9d399b8
> --- /dev/null
> +++ b/hw/char/stm32f205_usart.c
> @@ -0,0 +1,218 @@
> +/*
> + * STM32F205 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/stm32f205_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 stm32f205_usart_can_receive(void *opaque)
> +{
> + STM32f205UsartState *s = opaque;
> +
> + if (!(s->usart_sr & USART_SR_RXNE)) {
> + return 1;
> + }
> +
> + return 0;
> +}
> +
> +static void stm32f205_usart_receive(void *opaque, const uint8_t *buf, int size)
> +{
> + STM32f205UsartState *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 stm32f205_usart_reset(DeviceState *dev)
> +{
> + STM32f205UsartState *s = STM32F205_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 stm32f205_usart_read(void *opaque, hwaddr addr,
> + unsigned int size)
> +{
> + STM32f205UsartState *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;
Do you need to qemu_chr_accept_input here?
> + 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,
> + "STM32F205_usart_read: Bad offset " \
Just use %s __func__ rather than STM32F205_usart_read.
> + "0x%"HWADDR_PRIx"\n", addr);
> + return 0;
> + }
> +
> + return 0;
> +}
> +
> +static void stm32f205_usart_write(void *opaque, hwaddr addr,
> + uint64_t val64, unsigned int size)
> +{
> + STM32f205UsartState *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,
> + "STM32F205_usart_write: Bad offset " \
%s __func__
> + "0x%"HWADDR_PRIx"\n", addr);
> + }
> +}
> +
> +static const MemoryRegionOps stm32f205_usart_ops = {
> + .read = stm32f205_usart_read,
> + .write = stm32f205_usart_write,
> + .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +static void stm32f205_usart_init(Object *obj)
> +{
> + STM32f205UsartState *s = STM32F205_USART(obj);
> +
> + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
> +
> + memory_region_init_io(&s->mmio, obj, &stm32f205_usart_ops, s,
> + TYPE_STM32F205_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, stm32f205_usart_can_receive,
> + stm32f205_usart_receive, NULL, s);
> + }
> +}
> +
> +static void stm32f205_usart_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + dc->reset = stm32f205_usart_reset;
> +}
> +
> +static const TypeInfo stm32f205_usart_info = {
> + .name = TYPE_STM32F205_USART,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(STM32f205UsartState),
> + .instance_init = stm32f205_usart_init,
> + .class_init = stm32f205_usart_class_init,
> +};
> +
> +static void stm32f205_usart_register_types(void)
> +{
> + type_register_static(&stm32f205_usart_info);
> +}
> +
> +type_init(stm32f205_usart_register_types)
> diff --git a/include/hw/char/stm32f205_usart.h b/include/hw/char/stm32f205_usart.h
> new file mode 100644
> index 0000000..e121bf3
> --- /dev/null
> +++ b/include/hw/char/stm32f205_usart.h
> @@ -0,0 +1,69 @@
> +/*
> + * STM32F205 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_STM32F205_USART "stm32f205-usart"
> +#define STM32F205_USART(obj) \
> + OBJECT_CHECK(STM32f205UsartState, (obj), TYPE_STM32F205_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;
> +} STM32f205UsartState;
STM32F2XXUSARTState.
Note the big "F" too.
Regards,
Peter
> --
> 1.9.1
>
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Qemu-devel] [PATCH v5 3/7] stm32f205_SYSCFG: Add the stm32f205 SYSCFG
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 3/7] stm32f205_SYSCFG: Add the stm32f205 SYSCFG Alistair Francis
@ 2014-10-20 7:35 ` Peter Crosthwaite
0 siblings, 0 replies; 18+ messages in thread
From: Peter Crosthwaite @ 2014-10-20 7:35 UTC (permalink / raw)
To: Alistair Francis
Cc: Peter Maydell, Martin Galvan, qemu-devel@nongnu.org Developers,
Konstanty Bialkowski
On Thu, Oct 16, 2014 at 10:54 PM, Alistair Francis <alistair23@gmail.com> wrote:
> This patch adds the stm32f205 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>
> ---
> default-configs/arm-softmmu.mak | 1 +
> hw/misc/Makefile.objs | 1 +
> hw/misc/stm32f205_syscfg.c | 160 +++++++++++++++++++++++++++++++++++++
> include/hw/misc/stm32f205_syscfg.h | 61 ++++++++++++++
> 4 files changed, 223 insertions(+)
> create mode 100644 hw/misc/stm32f205_syscfg.c
> create mode 100644 include/hw/misc/stm32f205_syscfg.h
>
> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
> index 422dec0..a2ea8f7 100644
> --- a/default-configs/arm-softmmu.mak
> +++ b/default-configs/arm-softmmu.mak
> @@ -80,6 +80,7 @@ CONFIG_ZAURUS=y
> CONFIG_ZYNQ=y
> CONFIG_STM32F205_TIMER=y
> CONFIG_STM32F205_USART=y
> +CONFIG_STM32F205_SYSCFG=y
>
> CONFIG_VERSATILE_PCI=y
> CONFIG_VERSATILE_I2C=y
> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
> index 979e532..63f03bd 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_STM32F205_SYSCFG) += stm32f205_syscfg.o
>
> obj-$(CONFIG_PVPANIC) += pvpanic.o
> diff --git a/hw/misc/stm32f205_syscfg.c b/hw/misc/stm32f205_syscfg.c
> new file mode 100644
> index 0000000..82aa50f
> --- /dev/null
> +++ b/hw/misc/stm32f205_syscfg.c
> @@ -0,0 +1,160 @@
> +/*
> + * STM32F205 SYSCFG
2XX
> + *
> + * 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/stm32f205_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 stm32f205_syscfg_reset(DeviceState *dev)
> +{
> + STM32f205SyscfgState *s = STM32F205_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 stm32f205_syscfg_read(void *opaque, hwaddr addr,
> + unsigned int size)
> +{
> + STM32f205SyscfgState *s = opaque;
> +
> + DB_PRINT("0x%x\n", (uint) addr);
> +
HWADDR_PRIx
> + 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,
> + "STM32F205_syscfg_read: Bad offset %x\n", (int)addr);
%s __func, HWADDR_PRIx
> + return 0;
> + }
> +
> + return 0;
> +}
> +
> +static void stm32f205_syscfg_write(void *opaque, hwaddr addr,
> + uint64_t val64, unsigned int size)
> +{
> + STM32f205SyscfgState *s = opaque;
> + uint32_t value = val64;
> +
> + DB_PRINT("0x%x, 0x%x\n", value, (uint) addr);
> +
HWADDR_PRIx
> + switch (addr) {
> + case SYSCFG_MEMRMP:
> + qemu_log_mask(LOG_UNIMP,
> + "STM32F205_syscfg_write: Changeing the memory mapping " \
%s __func__ here and below.
> + "isn't supported in QEMU\n");
> + return;
> + case SYSCFG_PMC:
> + qemu_log_mask(LOG_UNIMP,
> + "STM32F205_syscfg_write: Peripheral mode configuration " \
> + "isn't supported in QEMU\n");
> + 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,
> + "STM32F205_syscfg_write: Bad offset %x\n", (int)addr);
Same as above.
> + }
> +}
> +
> +static const MemoryRegionOps stm32f205_syscfg_ops = {
> + .read = stm32f205_syscfg_read,
> + .write = stm32f205_syscfg_write,
> + .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +static void stm32f205_syscfg_init(Object *obj)
> +{
> + STM32f205SyscfgState *s = STM32F205_SYSCFG(obj);
> +
> + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
> +
> + memory_region_init_io(&s->mmio, obj, &stm32f205_syscfg_ops, s,
> + TYPE_STM32F205_SYSCFG, 0x2000);
> + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
> +}
> +
> +static void stm32f205_syscfg_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + dc->reset = stm32f205_syscfg_reset;
> +}
> +
> +static const TypeInfo stm32f205_syscfg_info = {
> + .name = TYPE_STM32F205_SYSCFG,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(STM32f205SyscfgState),
> + .instance_init = stm32f205_syscfg_init,
> + .class_init = stm32f205_syscfg_class_init,
> +};
> +
> +static void stm32f205_syscfg_register_types(void)
> +{
> + type_register_static(&stm32f205_syscfg_info);
> +}
> +
> +type_init(stm32f205_syscfg_register_types)
> diff --git a/include/hw/misc/stm32f205_syscfg.h b/include/hw/misc/stm32f205_syscfg.h
> new file mode 100644
> index 0000000..9c5556f
> --- /dev/null
> +++ b/include/hw/misc/stm32f205_syscfg.h
> @@ -0,0 +1,61 @@
> +/*
> + * STM32F205 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_STM32F205_SYSCFG "stm32f205-syscfg"
> +#define STM32F205_SYSCFG(obj) \
> + OBJECT_CHECK(STM32f205SyscfgState, (obj), TYPE_STM32F205_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;
> +} STM32f205SyscfgState;
> +
F2XX
Otherwise,
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Regards,
Peter
> +#endif
> --
> 1.9.1
>
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Qemu-devel] [PATCH v5 4/7] target_arm: Remove memory region init from armv7m_init
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 4/7] target_arm: Remove memory region init from armv7m_init Alistair Francis
@ 2014-10-20 7:40 ` Peter Crosthwaite
0 siblings, 0 replies; 18+ messages in thread
From: Peter Crosthwaite @ 2014-10-20 7:40 UTC (permalink / raw)
To: Alistair Francis
Cc: Peter Maydell, Martin Galvan, qemu-devel@nongnu.org Developers,
Konstanty Bialkowski
On Thu, Oct 16, 2014 at 10:54 PM, Alistair Francis <alistair23@gmail.com> wrote:
> 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>
> ---
> 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 */
> --
> 1.9.1
>
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Qemu-devel] [PATCH v5 5/7] target_arm: Parameterise the irq lines for armv7m_init
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 5/7] target_arm: Parameterise the irq lines for armv7m_init Alistair Francis
@ 2014-10-20 7:41 ` Peter Crosthwaite
0 siblings, 0 replies; 18+ messages in thread
From: Peter Crosthwaite @ 2014-10-20 7:41 UTC (permalink / raw)
To: Alistair Francis
Cc: Peter Maydell, Martin Galvan, qemu-devel@nongnu.org Developers,
Konstanty Bialkowski
On Thu, Oct 16, 2014 at 10:54 PM, Alistair Francis <alistair23@gmail.com> wrote:
> 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 */
> --
> 1.9.1
>
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Qemu-devel] [PATCH v5 6/7] stm32f205: Add the stm32f205 SoC
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 6/7] stm32f205: Add the stm32f205 SoC Alistair Francis
@ 2014-10-20 7:47 ` Peter Crosthwaite
2014-10-20 12:30 ` Alistair Francis
0 siblings, 1 reply; 18+ messages in thread
From: Peter Crosthwaite @ 2014-10-20 7:47 UTC (permalink / raw)
To: Alistair Francis
Cc: Peter Maydell, Martin Galvan, qemu-devel@nongnu.org Developers,
Konstanty Bialkowski
On Thu, Oct 16, 2014 at 10:54 PM, Alistair Francis <alistair23@gmail.com> wrote:
> 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>
> ---
> 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 a2ea8f7..8068100 100644
> --- a/default-configs/arm-softmmu.mak
> +++ b/default-configs/arm-softmmu.mak
> @@ -81,6 +81,7 @@ CONFIG_ZYNQ=y
> CONFIG_STM32F205_TIMER=y
> CONFIG_STM32F205_USART=y
> CONFIG_STM32F205_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..bd9514e
> --- /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[] = { 0x40000000, 0x40000400,
> + 0x40000800, 0x40000C00 };
> +static const uint32_t usart_addr[] = { 0x40011000, 0x40004400,
> + 0x40004800, 0x40004C00, 0x40005000, 0x40011400 };
> +
You have 6 addresses for USART ...
> +static const int timer_irq[] = {28, 29, 30, 50};
> +static const int usart_irq[] = {37, 38, 39, 52, 53, 71, 82, 83};
> +
... but 8 IRQS and the loop below uses only 5 values. What's the system exactly?
> +static void stm32f205_soc_initfn(Object *obj)
> +{
> + STM32F205State *s = STM32F205_SOC(obj);
> + int i;
> +
> + object_initialize(&s->syscfg, sizeof(s->syscfg), TYPE_STM32F205_SYSCFG);
> + qdev_set_parent_bus(DEVICE(&s->syscfg), sysbus_get_default());
> +
> + for (i = 0; i < 5; i++) {
> + object_initialize(&s->usart[i], sizeof(s->usart[i]),
> + TYPE_STM32F205_USART);
> + qdev_set_parent_bus(DEVICE(&s->usart[i]), sysbus_get_default());
> + }
> +
> + for (i = 0; i < 4; i++) {
> + object_initialize(&s->timer[i], sizeof(s->timer[i]),
> + TYPE_STM32F205_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;;
stray ;
> + 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, "netduino.flash", FLASH_SIZE,
> + &error_abort);
> + memory_region_init_alias(flash_alias, NULL, "netduino.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, "netduino.sram", SRAM_SIZE,
> + &error_abort);
There shouldn't be any refs to "netduino" like this.
Regards,
Peter
> + 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 < 5; 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 < 4; 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..addc555
> --- /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/stm32f205_syscfg.h"
> +#include "hw/timer/stm32f205_timer.h"
> +#include "hw/char/stm32f205_usart.h"
> +
> +#define TYPE_STM32F205_SOC "stm32f205_soc"
> +#define STM32F205_SOC(obj) \
> + OBJECT_CHECK(STM32F205State, (obj), TYPE_STM32F205_SOC)
> +
> +#define STM_NUM_USARTS 5
> +#define STM_NUM_TIMERS 5
> +
> +#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;
> +
> + STM32f205SyscfgState syscfg;
> + STM32f205UsartState usart[STM_NUM_USARTS];
> + STM32f205TimerState timer[STM_NUM_TIMERS];
> +} STM32F205State;
> +
> +#endif
> --
> 1.9.1
>
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Qemu-devel] [PATCH v5 6/7] stm32f205: Add the stm32f205 SoC
2014-10-20 7:47 ` Peter Crosthwaite
@ 2014-10-20 12:30 ` Alistair Francis
0 siblings, 0 replies; 18+ messages in thread
From: Alistair Francis @ 2014-10-20 12:30 UTC (permalink / raw)
To: Peter Crosthwaite
Cc: Peter Maydell, Martin Galvan, qemu-devel@nongnu.org Developers,
Konstanty Bialkowski
On Mon, Oct 20, 2014 at 5:47 PM, Peter Crosthwaite
<peter.crosthwaite@xilinx.com> wrote:
> On Thu, Oct 16, 2014 at 10:54 PM, Alistair Francis <alistair23@gmail.com> wrote:
>> 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>
>> ---
>> 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 a2ea8f7..8068100 100644
>> --- a/default-configs/arm-softmmu.mak
>> +++ b/default-configs/arm-softmmu.mak
>> @@ -81,6 +81,7 @@ CONFIG_ZYNQ=y
>> CONFIG_STM32F205_TIMER=y
>> CONFIG_STM32F205_USART=y
>> CONFIG_STM32F205_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..bd9514e
>> --- /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[] = { 0x40000000, 0x40000400,
>> + 0x40000800, 0x40000C00 };
>> +static const uint32_t usart_addr[] = { 0x40011000, 0x40004400,
>> + 0x40004800, 0x40004C00, 0x40005000, 0x40011400 };
>> +
>
> You have 6 addresses for USART ...
>
>> +static const int timer_irq[] = {28, 29, 30, 50};
>> +static const int usart_irq[] = {37, 38, 39, 52, 53, 71, 82, 83};
>> +
>
> ... but 8 IRQS and the loop below uses only 5 values. What's the system exactly?
These must be left over from the Netduino Plus 2. I think it's just
the first five, but I'll
double check and fix in a respin
>
>> +static void stm32f205_soc_initfn(Object *obj)
>> +{
>> + STM32F205State *s = STM32F205_SOC(obj);
>> + int i;
>> +
>> + object_initialize(&s->syscfg, sizeof(s->syscfg), TYPE_STM32F205_SYSCFG);
>> + qdev_set_parent_bus(DEVICE(&s->syscfg), sysbus_get_default());
>> +
>> + for (i = 0; i < 5; i++) {
>> + object_initialize(&s->usart[i], sizeof(s->usart[i]),
>> + TYPE_STM32F205_USART);
>> + qdev_set_parent_bus(DEVICE(&s->usart[i]), sysbus_get_default());
>> + }
>> +
>> + for (i = 0; i < 4; i++) {
>> + object_initialize(&s->timer[i], sizeof(s->timer[i]),
>> + TYPE_STM32F205_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;;
>
> stray ;
Will fix
>
>> + 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, "netduino.flash", FLASH_SIZE,
>> + &error_abort);
>> + memory_region_init_alias(flash_alias, NULL, "netduino.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, "netduino.sram", SRAM_SIZE,
>> + &error_abort);
>
> There shouldn't be any refs to "netduino" like this.
Ok, I will remove
Thanks,
Alistair
>
> Regards,
> Peter
>
>> + 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 < 5; 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 < 4; 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..addc555
>> --- /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/stm32f205_syscfg.h"
>> +#include "hw/timer/stm32f205_timer.h"
>> +#include "hw/char/stm32f205_usart.h"
>> +
>> +#define TYPE_STM32F205_SOC "stm32f205_soc"
>> +#define STM32F205_SOC(obj) \
>> + OBJECT_CHECK(STM32F205State, (obj), TYPE_STM32F205_SOC)
>> +
>> +#define STM_NUM_USARTS 5
>> +#define STM_NUM_TIMERS 5
>> +
>> +#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;
>> +
>> + STM32f205SyscfgState syscfg;
>> + STM32f205UsartState usart[STM_NUM_USARTS];
>> + STM32f205TimerState timer[STM_NUM_TIMERS];
>> +} STM32F205State;
>> +
>> +#endif
>> --
>> 1.9.1
>>
>>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Qemu-devel] [PATCH v5 1/7] stm32f205_timer: Add the stm32f205 Timer
2014-10-20 7:18 ` Peter Crosthwaite
@ 2014-10-21 7:05 ` Alistair Francis
2014-10-21 7:40 ` Peter Crosthwaite
0 siblings, 1 reply; 18+ messages in thread
From: Alistair Francis @ 2014-10-21 7:05 UTC (permalink / raw)
To: Peter Crosthwaite
Cc: Peter Maydell, Martin Galvan, qemu-devel@nongnu.org Developers,
Konstanty Bialkowski
On Mon, Oct 20, 2014 at 5:18 PM, Peter Crosthwaite
<peter.crosthwaite@xilinx.com> wrote:
> Sorry about the review delay...
>
> On Thu, Oct 16, 2014 at 10:53 PM, Alistair Francis <alistair23@gmail.com> wrote:
>> This patch adds the stm32f205 timers: TIM2, TIM3, TIM4 and TIM5
>> to QEMU.
>>
>> Signed-off-by: Alistair Francis <alistair23@gmail.com>
>> ---
>> 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
>> Changes from RFC:
>> - Small changes to functionality and style. Thanks to Peter C
>> - Rename to make the timer more generic
>> - Split the config settings to device level
>>
>> default-configs/arm-softmmu.mak | 1 +
>> hw/timer/Makefile.objs | 2 +
>> hw/timer/stm32f205_timer.c | 318 +++++++++++++++++++++++++++++++++++++
>> include/hw/timer/stm32f205_timer.h | 101 ++++++++++++
>> 4 files changed, 422 insertions(+)
>> create mode 100644 hw/timer/stm32f205_timer.c
>> create mode 100644 include/hw/timer/stm32f205_timer.h
>>
>> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
>> index f3513fa..cf23b24 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_STM32F205_TIMER=y
>>
>> CONFIG_VERSATILE_PCI=y
>> CONFIG_VERSATILE_I2C=y
>> diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
>> index 2c86c3d..4bd9617 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_STM32F205_TIMER) += stm32f205_timer.o
>> diff --git a/hw/timer/stm32f205_timer.c b/hw/timer/stm32f205_timer.c
>> new file mode 100644
>> index 0000000..aace8df
>> --- /dev/null
>> +++ b/hw/timer/stm32f205_timer.c
>> @@ -0,0 +1,318 @@
>> +/*
>> + * STM32F205 Timer
>
> ST doc RM0033 which docs this timer refers to a larger family of SOCs.
> I think you can change this from 205 to 2XX probably globally for the
> series.
>
Ok, I will change all three devices
>> + *
>> + * 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/stm32f205_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 stm32f205_timer_set_alarm(STM32f205TimerState *s);
>> +
>> +static void stm32f205_timer_interrupt(void *opaque)
>> +{
>> + STM32f205TimerState *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);
>> + stm32f205_timer_set_alarm(s);
>> + }
>> +}
>> +
>> +static void stm32f205_timer_set_alarm(STM32f205TimerState *s)
>> +{
>> + uint32_t ticks;
>> + int64_t now;
>> +
>> + DB_PRINT("Alarm set at: 0x%x\n", s->tim_cr1);
>> +
>> + now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
>
> So now is in terms of ms.
>
>> + ticks = s->tim_arr - ((s->tick_offset + (now * (s->freq_hz / 1000))) /
>
> tick_offset is terms of clock-cycles-before-prescalar. ticks and
> tim_arr must be in terms of clock-cycles-post-pre-scalar.
Yes, that's correct
>
> I'm slightly hazy on definition of tick_offset but i'm guessing its
> the time offset of when the timer started expressed in
> before-prescalar cycles? I would then expect this to be:
>
> ticks = tim_arr - (now * (scale) - tick_offset).
I think tick_offset should be added. That is what the PL031 timer does and
the timer interrupt events don't trigger is tick_offset is subtracted.
I'm not sure
why though
>
> with (now * scale - tick_offset) / tim_psc corresponding to the
> current value of the running timer (tim_cnt?).
That's correct, that is the CNT value. ARR can be set by the guest as an offset
>
>> + (s->tim_psc + 1));
>
> So in total this expression is calculating a number of clock cycles
> until a hit as "ticks".
>
>> +
>> + DB_PRINT("Alarm set in %d ticks\n", ticks);
>> +
>> + if (ticks == 0) {
>
> What if ticks is -ve due to a late callback of set_alarm? It will
> probably work, but it seems inconsistent that you rely on the callback
> path for -ve and +ve tick balances but have a fast path for when ticks
> happens to balance to exactly 0. This fast path should probably handle
> -ve's or you could just ditch it entirely.
Ticks is an unsigned int, it will never be negative. The 'ticks == 0' basically
covers the negative values.
>
>> + timer_del(s->timer);
>> + stm32f205_timer_interrupt(s);
>> + } else {
>> + timer_mod(s->timer, ((now * (s->freq_hz / 1000)) / (s->tim_psc + 1)) +
>
> Common sub-expression (now * (s->freq_hz / 1000)) / (s->tim_psc + 1)
> with calculation of "ticks" above can be cached in a variable. but ...
>
>> + (int64_t) ticks);
>
> this calculation has me confused. My understanding is timer_mode
> should be given an absolute value as time. s->timer is defined as a ns
> timer whereas this calculation is a clock cycles value.
Yes, that's correct. I will fix fix that
>
>> + DB_PRINT("Wait Time: %" PRId64 " ticks\n",
>> + ((now * (s->freq_hz / 1000)) / (s->tim_psc + 1)) +
>> + (int64_t) ticks);
>> + }
>> +}
>> +
>> +static void stm32f205_timer_reset(DeviceState *dev)
>> +{
>> + STM32f205TimerState *s = STM32F205TIMER(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 = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) *
>> + (s->freq_hz / 1000);
>> +}
>> +
>> +static uint64_t stm32f205_timer_read(void *opaque, hwaddr offset,
>> + unsigned size)
>> +{
>> + STM32f205TimerState *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 = s->tick_offset + (qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) *
>> + (s->freq_hz / 1000));
>
> Same comment above about subbing tick_offset rather than adding.
>
>> + 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 stm32f205_timer_write(void *opaque, hwaddr offset,
>> + uint64_t val64, unsigned size)
>> +{
>> + STM32f205TimerState *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 */
>> + stm32f205_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:
>> + s->tim_cnt = value;
>
> You set tim_cnt here, presumably setting the value of the timer. But
> set_alarm doesn't do anything with it. You need to warp tick_offset
> here to account for the new 0-base of the timer. When I run into this
> situation though, i generally use a two-variable approach where I have
> both the value of the timer and the VM timer corresponding to it e.g.
>
> uint32_t timer_val; /* value of timer in clock cycles */
> uint64_t sync_time; /* VM time for when timer_val last updated */
>
> And not bother trying to maintain an absolute (0-based) tick offset.
> Then every time someone touches a prescalar, timer-value,
> enable-switch, etc etc you just sync these two numbers first:
>
> now = qemu_get_clock
> timer_val += (now - sync_time) * scale(); /* scale is 0 for a disabled timer */
> sync_time = now;
>
> Then do your thing. Then delete or re-arm the callback if needed.
>
> Otherwise you need a sync() pair much like the ones we used for the
> ARM PMCCNTR around some of these ops.
>
Can I not just update tick_offset, by adding the difference between what
the current clock value is and what the guest is setting it to?
For example if an event is scheduled for 100 ticks, the clock is at 10 and the
guest writes 90 to the counter. Can't the tick_offset value just be
incremented by
80? Which would push everything forward 80 ticks.
I might be missing something, but that should work shouldn't it?
That way everything will also be updated if the pre-scalar is changed.
>> + stm32f205_timer_set_alarm(s);
>> + return;
>> + case TIM_PSC:
>> + s->tim_psc = value;
>
> Change the prescaler requires a rearming of the callback as it can
> have an affect on the calculation of "ticks".
>
Yep, will add
>> + return;
>> + case TIM_ARR:
>> + s->tim_arr = value;
>> + stm32f205_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 stm32f205_timer_ops = {
>> + .read = stm32f205_timer_read,
>> + .write = stm32f205_timer_write,
>> + .endianness = DEVICE_NATIVE_ENDIAN,
>> +};
>> +
>> +static const VMStateDescription vmstate_stm32f205_timer = {
>> + .name = TYPE_STM32F205_TIMER,
>> + .version_id = 1,
>> + .minimum_version_id = 1,
>> + .fields = (VMStateField[]) {
>> + VMSTATE_UINT32(tick_offset, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_cr1, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_cr2, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_smcr, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_dier, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_sr, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_egr, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_ccmr1, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_ccmr2, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_ccer, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_cnt, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_psc, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_arr, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_ccr1, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_ccr2, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_ccr3, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_ccr4, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_dcr, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_dmar, STM32f205TimerState),
>> + VMSTATE_UINT32(tim_or, STM32f205TimerState),
>> + VMSTATE_END_OF_LIST()
>> + }
>> +};
>> +
>> +static Property stm32f205_timer_properties[] = {
>> + DEFINE_PROP_UINT64("clock-frequency", struct STM32f205TimerState,
>> + freq_hz, 1000000000),
>
> With 1GHz precision should you be using ns timing throughout instead
> of ms? You may need to add some muldivs to account for the bigger
> numbers.
Yeah, I agree. Will fix
Thanks,
Alistair
>
> Regards,
> Peter
>
>> + DEFINE_PROP_END_OF_LIST(),
>> +};
>> +
>> +static void stm32f205_timer_init(Object *obj)
>> +{
>> + STM32f205TimerState *s = STM32F205TIMER(obj);
>> +
>> + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
>> +
>> + memory_region_init_io(&s->iomem, obj, &stm32f205_timer_ops, s,
>> + "stm32f205_timer", 0x2000);
>> + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
>> +
>> + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, stm32f205_timer_interrupt, s);
>> +}
>> +
>> +static void stm32f205_timer_class_init(ObjectClass *klass, void *data)
>> +{
>> + DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> + dc->reset = stm32f205_timer_reset;
>> + dc->props = stm32f205_timer_properties;
>> + dc->vmsd = &vmstate_stm32f205_timer;
>> +}
>> +
>> +static const TypeInfo stm32f205_timer_info = {
>> + .name = TYPE_STM32F205_TIMER,
>> + .parent = TYPE_SYS_BUS_DEVICE,
>> + .instance_size = sizeof(STM32f205TimerState),
>> + .instance_init = stm32f205_timer_init,
>> + .class_init = stm32f205_timer_class_init,
>> +};
>> +
>> +static void stm32f205_timer_register_types(void)
>> +{
>> + type_register_static(&stm32f205_timer_info);
>> +}
>> +
>> +type_init(stm32f205_timer_register_types)
>> diff --git a/include/hw/timer/stm32f205_timer.h b/include/hw/timer/stm32f205_timer.h
>> new file mode 100644
>> index 0000000..9425cb1
>> --- /dev/null
>> +++ b/include/hw/timer/stm32f205_timer.h
>> @@ -0,0 +1,101 @@
>> +/*
>> + * STM32F205 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_STM32F205_TIMER "stm32f205-timer"
>> +#define STM32F205TIMER(obj) OBJECT_CHECK(STM32f205TimerState, \
>> + (obj), TYPE_STM32F205_TIMER)
>> +
>> +typedef struct STM32f205TimerState {
>> + /* <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;
>> +} STM32f205TimerState;
>> +
>> +#endif
>> --
>> 1.9.1
>>
>>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Qemu-devel] [PATCH v5 1/7] stm32f205_timer: Add the stm32f205 Timer
2014-10-21 7:05 ` Alistair Francis
@ 2014-10-21 7:40 ` Peter Crosthwaite
2014-10-22 7:20 ` Alistair Francis
0 siblings, 1 reply; 18+ messages in thread
From: Peter Crosthwaite @ 2014-10-21 7:40 UTC (permalink / raw)
To: Alistair Francis
Cc: Konstanty Bialkowski, Peter Maydell, Martin Galvan,
qemu-devel@nongnu.org Developers
On Tue, Oct 21, 2014 at 5:05 PM, Alistair Francis <alistair23@gmail.com> wrote:
> On Mon, Oct 20, 2014 at 5:18 PM, Peter Crosthwaite
> <peter.crosthwaite@xilinx.com> wrote:
>> Sorry about the review delay...
>>
>> On Thu, Oct 16, 2014 at 10:53 PM, Alistair Francis <alistair23@gmail.com> wrote:
>>> This patch adds the stm32f205 timers: TIM2, TIM3, TIM4 and TIM5
>>> to QEMU.
>>>
>>> Signed-off-by: Alistair Francis <alistair23@gmail.com>
>>> ---
>>> 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
>>> Changes from RFC:
>>> - Small changes to functionality and style. Thanks to Peter C
>>> - Rename to make the timer more generic
>>> - Split the config settings to device level
>>>
>>> default-configs/arm-softmmu.mak | 1 +
>>> hw/timer/Makefile.objs | 2 +
>>> hw/timer/stm32f205_timer.c | 318 +++++++++++++++++++++++++++++++++++++
>>> include/hw/timer/stm32f205_timer.h | 101 ++++++++++++
>>> 4 files changed, 422 insertions(+)
>>> create mode 100644 hw/timer/stm32f205_timer.c
>>> create mode 100644 include/hw/timer/stm32f205_timer.h
>>>
>>> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
>>> index f3513fa..cf23b24 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_STM32F205_TIMER=y
>>>
>>> CONFIG_VERSATILE_PCI=y
>>> CONFIG_VERSATILE_I2C=y
>>> diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
>>> index 2c86c3d..4bd9617 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_STM32F205_TIMER) += stm32f205_timer.o
>>> diff --git a/hw/timer/stm32f205_timer.c b/hw/timer/stm32f205_timer.c
>>> new file mode 100644
>>> index 0000000..aace8df
>>> --- /dev/null
>>> +++ b/hw/timer/stm32f205_timer.c
>>> @@ -0,0 +1,318 @@
>>> +/*
>>> + * STM32F205 Timer
>>
>> ST doc RM0033 which docs this timer refers to a larger family of SOCs.
>> I think you can change this from 205 to 2XX probably globally for the
>> series.
>>
>
> Ok, I will change all three devices
>
>>> + *
>>> + * 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/stm32f205_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 stm32f205_timer_set_alarm(STM32f205TimerState *s);
>>> +
>>> +static void stm32f205_timer_interrupt(void *opaque)
>>> +{
>>> + STM32f205TimerState *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);
>>> + stm32f205_timer_set_alarm(s);
>>> + }
>>> +}
>>> +
>>> +static void stm32f205_timer_set_alarm(STM32f205TimerState *s)
>>> +{
>>> + uint32_t ticks;
>>> + int64_t now;
>>> +
>>> + DB_PRINT("Alarm set at: 0x%x\n", s->tim_cr1);
>>> +
>>> + now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
>>
>> So now is in terms of ms.
>>
>>> + ticks = s->tim_arr - ((s->tick_offset + (now * (s->freq_hz / 1000))) /
>>
>> tick_offset is terms of clock-cycles-before-prescalar. ticks and
>> tim_arr must be in terms of clock-cycles-post-pre-scalar.
>
> Yes, that's correct
>
>>
>> I'm slightly hazy on definition of tick_offset but i'm guessing its
>> the time offset of when the timer started expressed in
>> before-prescalar cycles? I would then expect this to be:
>>
>> ticks = tim_arr - (now * (scale) - tick_offset).
>
> I think tick_offset should be added. That is what the PL031 timer does and
> the timer interrupt events don't trigger is tick_offset is subtracted.
> I'm not sure
> why though
>
Ok i'm understanding better now. tick_offset from pl031 is the
absolute real time (seconds since epoch) of when the VM started. now /
scale + tick_offset in that case is the expression for the current
real time:
79 static uint32_t pl031_get_count(PL031State *s)
80 {
81 int64_t now = qemu_clock_get_ns(rtc_clock);
82 return s->tick_offset + now / get_ticks_per_sec();
83 }
This is needed to generate real-world RTC times (in seconds) as PL031
is an RTC. This core is not and RTC so you need something different to
pl031 tick_offset concept to account for the reloadable/resettable
timer.
>>
>> with (now * scale - tick_offset) / tim_psc corresponding to the
>> current value of the running timer (tim_cnt?).
>
> That's correct, that is the CNT value. ARR can be set by the guest as an offset
>
>>
>>> + (s->tim_psc + 1));
>>
>> So in total this expression is calculating a number of clock cycles
>> until a hit as "ticks".
>>
>>> +
>>> + DB_PRINT("Alarm set in %d ticks\n", ticks);
>>> +
>>> + if (ticks == 0) {
>>
>> What if ticks is -ve due to a late callback of set_alarm? It will
>> probably work, but it seems inconsistent that you rely on the callback
>> path for -ve and +ve tick balances but have a fast path for when ticks
>> happens to balance to exactly 0. This fast path should probably handle
>> -ve's or you could just ditch it entirely.
>
> Ticks is an unsigned int, it will never be negative. The 'ticks == 0' basically
> covers the negative values.
>
Assuming saturation arithmetic though right? Wont the -ve cases just
overflow into super big numbers that never trigger? Give that ticks
can validly go negative in intermediate calculation maybe it should be
signed.
>>
>>> + timer_del(s->timer);
>>> + stm32f205_timer_interrupt(s);
>>> + } else {
>>> + timer_mod(s->timer, ((now * (s->freq_hz / 1000)) / (s->tim_psc + 1)) +
>>
>> Common sub-expression (now * (s->freq_hz / 1000)) / (s->tim_psc + 1)
>> with calculation of "ticks" above can be cached in a variable. but ...
>>
>>> + (int64_t) ticks);
>>
>> this calculation has me confused. My understanding is timer_mode
>> should be given an absolute value as time. s->timer is defined as a ns
>> timer whereas this calculation is a clock cycles value.
>
> Yes, that's correct. I will fix fix that
>
>>
>>> + DB_PRINT("Wait Time: %" PRId64 " ticks\n",
>>> + ((now * (s->freq_hz / 1000)) / (s->tim_psc + 1)) +
>>> + (int64_t) ticks);
>>> + }
>>> +}
>>> +
>>> +static void stm32f205_timer_reset(DeviceState *dev)
>>> +{
>>> + STM32f205TimerState *s = STM32F205TIMER(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 = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) *
>>> + (s->freq_hz / 1000);
>>> +}
>>> +
>>> +static uint64_t stm32f205_timer_read(void *opaque, hwaddr offset,
>>> + unsigned size)
>>> +{
>>> + STM32f205TimerState *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 = s->tick_offset + (qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) *
>>> + (s->freq_hz / 1000));
>>
>> Same comment above about subbing tick_offset rather than adding.
>>
>>> + 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 stm32f205_timer_write(void *opaque, hwaddr offset,
>>> + uint64_t val64, unsigned size)
>>> +{
>>> + STM32f205TimerState *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 */
>>> + stm32f205_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:
>>> + s->tim_cnt = value;
>>
>> You set tim_cnt here, presumably setting the value of the timer. But
>> set_alarm doesn't do anything with it. You need to warp tick_offset
>> here to account for the new 0-base of the timer. When I run into this
>> situation though, i generally use a two-variable approach where I have
>> both the value of the timer and the VM timer corresponding to it e.g.
>>
>> uint32_t timer_val; /* value of timer in clock cycles */
>> uint64_t sync_time; /* VM time for when timer_val last updated */
>>
>> And not bother trying to maintain an absolute (0-based) tick offset.
>> Then every time someone touches a prescalar, timer-value,
>> enable-switch, etc etc you just sync these two numbers first:
>>
>> now = qemu_get_clock
>> timer_val += (now - sync_time) * scale(); /* scale is 0 for a disabled timer */
>> sync_time = now;
>>
>> Then do your thing. Then delete or re-arm the callback if needed.
>>
>> Otherwise you need a sync() pair much like the ones we used for the
>> ARM PMCCNTR around some of these ops.
>>
>
> Can I not just update tick_offset, by adding the difference between what
> the current clock value is and what the guest is setting it to?
>
I think this will change with the redefinition of tick_offset.
Regards,
Peter
> For example if an event is scheduled for 100 ticks, the clock is at 10 and the
> guest writes 90 to the counter. Can't the tick_offset value just be
> incremented by
> 80? Which would push everything forward 80 ticks.
>
> I might be missing something, but that should work shouldn't it?
>
> That way everything will also be updated if the pre-scalar is changed.
>
>>> + stm32f205_timer_set_alarm(s);
>>> + return;
>>> + case TIM_PSC:
>>> + s->tim_psc = value;
>>
>> Change the prescaler requires a rearming of the callback as it can
>> have an affect on the calculation of "ticks".
>>
>
> Yep, will add
>
>>> + return;
>>> + case TIM_ARR:
>>> + s->tim_arr = value;
>>> + stm32f205_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 stm32f205_timer_ops = {
>>> + .read = stm32f205_timer_read,
>>> + .write = stm32f205_timer_write,
>>> + .endianness = DEVICE_NATIVE_ENDIAN,
>>> +};
>>> +
>>> +static const VMStateDescription vmstate_stm32f205_timer = {
>>> + .name = TYPE_STM32F205_TIMER,
>>> + .version_id = 1,
>>> + .minimum_version_id = 1,
>>> + .fields = (VMStateField[]) {
>>> + VMSTATE_UINT32(tick_offset, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_cr1, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_cr2, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_smcr, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_dier, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_sr, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_egr, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_ccmr1, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_ccmr2, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_ccer, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_cnt, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_psc, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_arr, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_ccr1, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_ccr2, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_ccr3, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_ccr4, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_dcr, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_dmar, STM32f205TimerState),
>>> + VMSTATE_UINT32(tim_or, STM32f205TimerState),
>>> + VMSTATE_END_OF_LIST()
>>> + }
>>> +};
>>> +
>>> +static Property stm32f205_timer_properties[] = {
>>> + DEFINE_PROP_UINT64("clock-frequency", struct STM32f205TimerState,
>>> + freq_hz, 1000000000),
>>
>> With 1GHz precision should you be using ns timing throughout instead
>> of ms? You may need to add some muldivs to account for the bigger
>> numbers.
>
> Yeah, I agree. Will fix
>
> Thanks,
>
> Alistair
>
>>
>> Regards,
>> Peter
>>
>>> + DEFINE_PROP_END_OF_LIST(),
>>> +};
>>> +
>>> +static void stm32f205_timer_init(Object *obj)
>>> +{
>>> + STM32f205TimerState *s = STM32F205TIMER(obj);
>>> +
>>> + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
>>> +
>>> + memory_region_init_io(&s->iomem, obj, &stm32f205_timer_ops, s,
>>> + "stm32f205_timer", 0x2000);
>>> + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
>>> +
>>> + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, stm32f205_timer_interrupt, s);
>>> +}
>>> +
>>> +static void stm32f205_timer_class_init(ObjectClass *klass, void *data)
>>> +{
>>> + DeviceClass *dc = DEVICE_CLASS(klass);
>>> +
>>> + dc->reset = stm32f205_timer_reset;
>>> + dc->props = stm32f205_timer_properties;
>>> + dc->vmsd = &vmstate_stm32f205_timer;
>>> +}
>>> +
>>> +static const TypeInfo stm32f205_timer_info = {
>>> + .name = TYPE_STM32F205_TIMER,
>>> + .parent = TYPE_SYS_BUS_DEVICE,
>>> + .instance_size = sizeof(STM32f205TimerState),
>>> + .instance_init = stm32f205_timer_init,
>>> + .class_init = stm32f205_timer_class_init,
>>> +};
>>> +
>>> +static void stm32f205_timer_register_types(void)
>>> +{
>>> + type_register_static(&stm32f205_timer_info);
>>> +}
>>> +
>>> +type_init(stm32f205_timer_register_types)
>>> diff --git a/include/hw/timer/stm32f205_timer.h b/include/hw/timer/stm32f205_timer.h
>>> new file mode 100644
>>> index 0000000..9425cb1
>>> --- /dev/null
>>> +++ b/include/hw/timer/stm32f205_timer.h
>>> @@ -0,0 +1,101 @@
>>> +/*
>>> + * STM32F205 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_STM32F205_TIMER "stm32f205-timer"
>>> +#define STM32F205TIMER(obj) OBJECT_CHECK(STM32f205TimerState, \
>>> + (obj), TYPE_STM32F205_TIMER)
>>> +
>>> +typedef struct STM32f205TimerState {
>>> + /* <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;
>>> +} STM32f205TimerState;
>>> +
>>> +#endif
>>> --
>>> 1.9.1
>>>
>>>
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Qemu-devel] [PATCH v5 1/7] stm32f205_timer: Add the stm32f205 Timer
2014-10-21 7:40 ` Peter Crosthwaite
@ 2014-10-22 7:20 ` Alistair Francis
0 siblings, 0 replies; 18+ messages in thread
From: Alistair Francis @ 2014-10-22 7:20 UTC (permalink / raw)
To: Peter Crosthwaite
Cc: Konstanty Bialkowski, Peter Maydell, Martin Galvan,
qemu-devel@nongnu.org Developers
On Tue, Oct 21, 2014 at 5:40 PM, Peter Crosthwaite
<peter.crosthwaite@xilinx.com> wrote:
> On Tue, Oct 21, 2014 at 5:05 PM, Alistair Francis <alistair23@gmail.com> wrote:
>> On Mon, Oct 20, 2014 at 5:18 PM, Peter Crosthwaite
>> <peter.crosthwaite@xilinx.com> wrote:
>>> Sorry about the review delay...
>>>
>>> On Thu, Oct 16, 2014 at 10:53 PM, Alistair Francis <alistair23@gmail.com> wrote:
>>>> This patch adds the stm32f205 timers: TIM2, TIM3, TIM4 and TIM5
>>>> to QEMU.
>>>>
>>>> Signed-off-by: Alistair Francis <alistair23@gmail.com>
>>>> ---
>>>> 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
>>>> Changes from RFC:
>>>> - Small changes to functionality and style. Thanks to Peter C
>>>> - Rename to make the timer more generic
>>>> - Split the config settings to device level
>>>>
>>>> default-configs/arm-softmmu.mak | 1 +
>>>> hw/timer/Makefile.objs | 2 +
>>>> hw/timer/stm32f205_timer.c | 318 +++++++++++++++++++++++++++++++++++++
>>>> include/hw/timer/stm32f205_timer.h | 101 ++++++++++++
>>>> 4 files changed, 422 insertions(+)
>>>> create mode 100644 hw/timer/stm32f205_timer.c
>>>> create mode 100644 include/hw/timer/stm32f205_timer.h
>>>>
>>>> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
>>>> index f3513fa..cf23b24 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_STM32F205_TIMER=y
>>>>
>>>> CONFIG_VERSATILE_PCI=y
>>>> CONFIG_VERSATILE_I2C=y
>>>> diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
>>>> index 2c86c3d..4bd9617 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_STM32F205_TIMER) += stm32f205_timer.o
>>>> diff --git a/hw/timer/stm32f205_timer.c b/hw/timer/stm32f205_timer.c
>>>> new file mode 100644
>>>> index 0000000..aace8df
>>>> --- /dev/null
>>>> +++ b/hw/timer/stm32f205_timer.c
>>>> @@ -0,0 +1,318 @@
>>>> +/*
>>>> + * STM32F205 Timer
>>>
>>> ST doc RM0033 which docs this timer refers to a larger family of SOCs.
>>> I think you can change this from 205 to 2XX probably globally for the
>>> series.
>>>
>>
>> Ok, I will change all three devices
>>
>>>> + *
>>>> + * 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/stm32f205_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 stm32f205_timer_set_alarm(STM32f205TimerState *s);
>>>> +
>>>> +static void stm32f205_timer_interrupt(void *opaque)
>>>> +{
>>>> + STM32f205TimerState *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);
>>>> + stm32f205_timer_set_alarm(s);
>>>> + }
>>>> +}
>>>> +
>>>> +static void stm32f205_timer_set_alarm(STM32f205TimerState *s)
>>>> +{
>>>> + uint32_t ticks;
>>>> + int64_t now;
>>>> +
>>>> + DB_PRINT("Alarm set at: 0x%x\n", s->tim_cr1);
>>>> +
>>>> + now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
>>>
>>> So now is in terms of ms.
>>>
>>>> + ticks = s->tim_arr - ((s->tick_offset + (now * (s->freq_hz / 1000))) /
>>>
>>> tick_offset is terms of clock-cycles-before-prescalar. ticks and
>>> tim_arr must be in terms of clock-cycles-post-pre-scalar.
>>
>> Yes, that's correct
>>
>>>
>>> I'm slightly hazy on definition of tick_offset but i'm guessing its
>>> the time offset of when the timer started expressed in
>>> before-prescalar cycles? I would then expect this to be:
>>>
>>> ticks = tim_arr - (now * (scale) - tick_offset).
>>
>> I think tick_offset should be added. That is what the PL031 timer does and
>> the timer interrupt events don't trigger is tick_offset is subtracted.
>> I'm not sure
>> why though
>>
>
> Ok i'm understanding better now. tick_offset from pl031 is the
> absolute real time (seconds since epoch) of when the VM started. now /
> scale + tick_offset in that case is the expression for the current
> real time:
>
> 79 static uint32_t pl031_get_count(PL031State *s)
> 80 {
> 81 int64_t now = qemu_clock_get_ns(rtc_clock);
> 82 return s->tick_offset + now / get_ticks_per_sec();
> 83 }
>
> This is needed to generate real-world RTC times (in seconds) as PL031
> is an RTC. This core is not and RTC so you need something different to
> pl031 tick_offset concept to account for the reloadable/resettable
> timer.
Ok, I will look into fixing up the timer_offset.
>
>>>
>>> with (now * scale - tick_offset) / tim_psc corresponding to the
>>> current value of the running timer (tim_cnt?).
>>
>> That's correct, that is the CNT value. ARR can be set by the guest as an offset
>>
>>>
>>>> + (s->tim_psc + 1));
>>>
>>> So in total this expression is calculating a number of clock cycles
>>> until a hit as "ticks".
>>>
>>>> +
>>>> + DB_PRINT("Alarm set in %d ticks\n", ticks);
>>>> +
>>>> + if (ticks == 0) {
>>>
>>> What if ticks is -ve due to a late callback of set_alarm? It will
>>> probably work, but it seems inconsistent that you rely on the callback
>>> path for -ve and +ve tick balances but have a fast path for when ticks
>>> happens to balance to exactly 0. This fast path should probably handle
>>> -ve's or you could just ditch it entirely.
>>
>> Ticks is an unsigned int, it will never be negative. The 'ticks == 0' basically
>> covers the negative values.
>>
>
> Assuming saturation arithmetic though right? Wont the -ve cases just
> overflow into super big numbers that never trigger? Give that ticks
> can validly go negative in intermediate calculation maybe it should be
> signed.
Values that would be negative for an integer do become big numbers, but they
will eventually wrap around back to zero. I might have to make it an
integer though
when I fix up the timer_offset variable.
Thanks,
Alistair
>
>>>
>>>> + timer_del(s->timer);
>>>> + stm32f205_timer_interrupt(s);
>>>> + } else {
>>>> + timer_mod(s->timer, ((now * (s->freq_hz / 1000)) / (s->tim_psc + 1)) +
>>>
>>> Common sub-expression (now * (s->freq_hz / 1000)) / (s->tim_psc + 1)
>>> with calculation of "ticks" above can be cached in a variable. but ...
>>>
>>>> + (int64_t) ticks);
>>>
>>> this calculation has me confused. My understanding is timer_mode
>>> should be given an absolute value as time. s->timer is defined as a ns
>>> timer whereas this calculation is a clock cycles value.
>>
>> Yes, that's correct. I will fix fix that
>>
>>>
>>>> + DB_PRINT("Wait Time: %" PRId64 " ticks\n",
>>>> + ((now * (s->freq_hz / 1000)) / (s->tim_psc + 1)) +
>>>> + (int64_t) ticks);
>>>> + }
>>>> +}
>>>> +
>>>> +static void stm32f205_timer_reset(DeviceState *dev)
>>>> +{
>>>> + STM32f205TimerState *s = STM32F205TIMER(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 = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) *
>>>> + (s->freq_hz / 1000);
>>>> +}
>>>> +
>>>> +static uint64_t stm32f205_timer_read(void *opaque, hwaddr offset,
>>>> + unsigned size)
>>>> +{
>>>> + STM32f205TimerState *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 = s->tick_offset + (qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) *
>>>> + (s->freq_hz / 1000));
>>>
>>> Same comment above about subbing tick_offset rather than adding.
>>>
>>>> + 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 stm32f205_timer_write(void *opaque, hwaddr offset,
>>>> + uint64_t val64, unsigned size)
>>>> +{
>>>> + STM32f205TimerState *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 */
>>>> + stm32f205_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:
>>>> + s->tim_cnt = value;
>>>
>>> You set tim_cnt here, presumably setting the value of the timer. But
>>> set_alarm doesn't do anything with it. You need to warp tick_offset
>>> here to account for the new 0-base of the timer. When I run into this
>>> situation though, i generally use a two-variable approach where I have
>>> both the value of the timer and the VM timer corresponding to it e.g.
>>>
>>> uint32_t timer_val; /* value of timer in clock cycles */
>>> uint64_t sync_time; /* VM time for when timer_val last updated */
>>>
>>> And not bother trying to maintain an absolute (0-based) tick offset.
>>> Then every time someone touches a prescalar, timer-value,
>>> enable-switch, etc etc you just sync these two numbers first:
>>>
>>> now = qemu_get_clock
>>> timer_val += (now - sync_time) * scale(); /* scale is 0 for a disabled timer */
>>> sync_time = now;
>>>
>>> Then do your thing. Then delete or re-arm the callback if needed.
>>>
>>> Otherwise you need a sync() pair much like the ones we used for the
>>> ARM PMCCNTR around some of these ops.
>>>
>>
>> Can I not just update tick_offset, by adding the difference between what
>> the current clock value is and what the guest is setting it to?
>>
>
> I think this will change with the redefinition of tick_offset.
>
> Regards,
> Peter
>
>> For example if an event is scheduled for 100 ticks, the clock is at 10 and the
>> guest writes 90 to the counter. Can't the tick_offset value just be
>> incremented by
>> 80? Which would push everything forward 80 ticks.
>>
>> I might be missing something, but that should work shouldn't it?
>>
>> That way everything will also be updated if the pre-scalar is changed.
>>
>>>> + stm32f205_timer_set_alarm(s);
>>>> + return;
>>>> + case TIM_PSC:
>>>> + s->tim_psc = value;
>>>
>>> Change the prescaler requires a rearming of the callback as it can
>>> have an affect on the calculation of "ticks".
>>>
>>
>> Yep, will add
>>
>>>> + return;
>>>> + case TIM_ARR:
>>>> + s->tim_arr = value;
>>>> + stm32f205_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 stm32f205_timer_ops = {
>>>> + .read = stm32f205_timer_read,
>>>> + .write = stm32f205_timer_write,
>>>> + .endianness = DEVICE_NATIVE_ENDIAN,
>>>> +};
>>>> +
>>>> +static const VMStateDescription vmstate_stm32f205_timer = {
>>>> + .name = TYPE_STM32F205_TIMER,
>>>> + .version_id = 1,
>>>> + .minimum_version_id = 1,
>>>> + .fields = (VMStateField[]) {
>>>> + VMSTATE_UINT32(tick_offset, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_cr1, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_cr2, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_smcr, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_dier, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_sr, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_egr, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_ccmr1, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_ccmr2, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_ccer, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_cnt, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_psc, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_arr, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_ccr1, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_ccr2, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_ccr3, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_ccr4, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_dcr, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_dmar, STM32f205TimerState),
>>>> + VMSTATE_UINT32(tim_or, STM32f205TimerState),
>>>> + VMSTATE_END_OF_LIST()
>>>> + }
>>>> +};
>>>> +
>>>> +static Property stm32f205_timer_properties[] = {
>>>> + DEFINE_PROP_UINT64("clock-frequency", struct STM32f205TimerState,
>>>> + freq_hz, 1000000000),
>>>
>>> With 1GHz precision should you be using ns timing throughout instead
>>> of ms? You may need to add some muldivs to account for the bigger
>>> numbers.
>>
>> Yeah, I agree. Will fix
>>
>> Thanks,
>>
>> Alistair
>>
>>>
>>> Regards,
>>> Peter
>>>
>>>> + DEFINE_PROP_END_OF_LIST(),
>>>> +};
>>>> +
>>>> +static void stm32f205_timer_init(Object *obj)
>>>> +{
>>>> + STM32f205TimerState *s = STM32F205TIMER(obj);
>>>> +
>>>> + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
>>>> +
>>>> + memory_region_init_io(&s->iomem, obj, &stm32f205_timer_ops, s,
>>>> + "stm32f205_timer", 0x2000);
>>>> + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
>>>> +
>>>> + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, stm32f205_timer_interrupt, s);
>>>> +}
>>>> +
>>>> +static void stm32f205_timer_class_init(ObjectClass *klass, void *data)
>>>> +{
>>>> + DeviceClass *dc = DEVICE_CLASS(klass);
>>>> +
>>>> + dc->reset = stm32f205_timer_reset;
>>>> + dc->props = stm32f205_timer_properties;
>>>> + dc->vmsd = &vmstate_stm32f205_timer;
>>>> +}
>>>> +
>>>> +static const TypeInfo stm32f205_timer_info = {
>>>> + .name = TYPE_STM32F205_TIMER,
>>>> + .parent = TYPE_SYS_BUS_DEVICE,
>>>> + .instance_size = sizeof(STM32f205TimerState),
>>>> + .instance_init = stm32f205_timer_init,
>>>> + .class_init = stm32f205_timer_class_init,
>>>> +};
>>>> +
>>>> +static void stm32f205_timer_register_types(void)
>>>> +{
>>>> + type_register_static(&stm32f205_timer_info);
>>>> +}
>>>> +
>>>> +type_init(stm32f205_timer_register_types)
>>>> diff --git a/include/hw/timer/stm32f205_timer.h b/include/hw/timer/stm32f205_timer.h
>>>> new file mode 100644
>>>> index 0000000..9425cb1
>>>> --- /dev/null
>>>> +++ b/include/hw/timer/stm32f205_timer.h
>>>> @@ -0,0 +1,101 @@
>>>> +/*
>>>> + * STM32F205 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_STM32F205_TIMER "stm32f205-timer"
>>>> +#define STM32F205TIMER(obj) OBJECT_CHECK(STM32f205TimerState, \
>>>> + (obj), TYPE_STM32F205_TIMER)
>>>> +
>>>> +typedef struct STM32f205TimerState {
>>>> + /* <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;
>>>> +} STM32f205TimerState;
>>>> +
>>>> +#endif
>>>> --
>>>> 1.9.1
>>>>
>>>>
>>
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2014-10-22 7:20 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-10-16 12:53 [Qemu-devel] [PATCH v5 0/7] Netduino 2 Machine Model Alistair Francis
2014-10-16 12:53 ` [Qemu-devel] [PATCH v5 1/7] stm32f205_timer: Add the stm32f205 Timer Alistair Francis
2014-10-20 7:18 ` Peter Crosthwaite
2014-10-21 7:05 ` Alistair Francis
2014-10-21 7:40 ` Peter Crosthwaite
2014-10-22 7:20 ` Alistair Francis
2014-10-16 12:53 ` [Qemu-devel] [PATCH v5 2/7] stm32f205_USART: Add the stm32f205 USART Controller Alistair Francis
2014-10-20 7:27 ` Peter Crosthwaite
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 3/7] stm32f205_SYSCFG: Add the stm32f205 SYSCFG Alistair Francis
2014-10-20 7:35 ` Peter Crosthwaite
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 4/7] target_arm: Remove memory region init from armv7m_init Alistair Francis
2014-10-20 7:40 ` Peter Crosthwaite
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 5/7] target_arm: Parameterise the irq lines for armv7m_init Alistair Francis
2014-10-20 7:41 ` Peter Crosthwaite
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 6/7] stm32f205: Add the stm32f205 SoC Alistair Francis
2014-10-20 7:47 ` Peter Crosthwaite
2014-10-20 12:30 ` Alistair Francis
2014-10-16 12:54 ` [Qemu-devel] [PATCH v5 7/7] netduino2: Add the Netduino 2 Machine Alistair Francis
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).