Skip to contentSkip to conversation

Update the Netduino 2 Machine

PATCH Superseded Alistair Francis 2 participants 13 messages Jul 23, 2016 – Jul 26, 2016 1 message not in the archive Arm STM32

v4 of 8 Superseded Latest is v8 →

lore
Share & tools
lore
#0 lore raw

v4 cover Update the Netduino 2 Machine

This patchset continues with the Netduino 2 and STM32F205 SoC work.

This patch series makes a small change to the STM32F2xx SoC to tidy up the code.

Next a feature is added to the STM32F2xx timer to display the PWM duty cycle, when debugging is enabled.

Then the STM32F2xx SPI and ADC devices are added and connected to the STM32F205 SoC.

Finally the maintainers file is updated to add myself as the maintainer for the Netdunio 2 and STM32F2xx.

V4:
- Add VMState to the new devices
- Remove rand() function
V3:
- Rebase
V2:
- Update based on Peter C's coments
- Rebase
- Create an ADC folder for the ADC device

Alistair Francis (8):
STM32F205: Remove the individual device variables
STM32F2xx: Display PWM duty cycle from timer
STM32F2xx: Add the ADC device
STM32F2xx: Add the SPI device
irq: Add irq information getter functions
STM32F205: Connect the ADC devices
STM32F205: Connect the SPI devices
MAINTAINERS: Add Alistair to the maintainers list

 MAINTAINERS                     |  15 ++
 default-configs/arm-softmmu.mak |   2 +
 hw/Makefile.objs                |   1 +
 hw/adc/Makefile.objs            |   1 +
 hw/adc/stm32f2xx_adc.c          | 306 ++++++++++++++++++++++++++++++++++++++++
 hw/arm/stm32f205_soc.c          |  90 +++++++++---
 hw/core/irq.c                   |  10 ++
 hw/ssi/Makefile.objs            |   1 +
 hw/ssi/stm32f2xx_spi.c          | 227 +++++++++++++++++++++++++++++
 hw/timer/stm32f2xx_timer.c      |   9 ++
 include/hw/adc/stm32f2xx_adc.h  |  87 ++++++++++++
 include/hw/arm/stm32f205_soc.h  |   6 +
 include/hw/irq.h                |   4 +
 include/hw/ssi/stm32f2xx_spi.h  |  72 ++++++++++
 14 files changed, 813 insertions(+), 18 deletions(-)
 create mode 100644 hw/adc/Makefile.objs
 create mode 100644 hw/adc/stm32f2xx_adc.c
 create mode 100644 hw/ssi/stm32f2xx_spi.c
 create mode 100644 include/hw/adc/stm32f2xx_adc.h
 create mode 100644 include/hw/ssi/stm32f2xx_spi.h
Signature · 1 line
2.7.4
#1 lore raw

PATCH v4 1/8 STM32F205: Remove the individual device variables

Cleanup the individual DeviceState and SysBusDevice variables to re-use the same variable for each device.

---

 hw/arm/stm32f205_soc.c | 35 +++++++++++++++++------------------
 1 file changed, 17 insertions(+), 18 deletions(-)
hw/arm/stm32f205_soc.c +17 -18
index de26b8c..5b6fa3b 100644
@@ -62,8 +62,8 @@ static void stm32f205_soc_initfn(Object *obj)
 static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
 {
     STM32F205State *s = STM32F205_SOC(dev_soc);
-    DeviceState *syscfgdev, *usartdev, *timerdev, *nvic;
-    SysBusDevice *syscfgbusdev, *usartbusdev, *timerbusdev;
+    DeviceState *dev, *nvic;
+    SysBusDevice *busdev;
     Error *err = NULL;
     int i;
 
@@ -94,44 +94,43 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
                        s->kernel_filename, s->cpu_model);
 
     /* System configuration controller */
-    syscfgdev = DEVICE(&s->syscfg);
+    dev = 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, qdev_get_gpio_in(nvic, 71));
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, 0x40013800);
+    sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, 71));
 
     /* Attach UART (uses USART registers) and USART controllers */
     for (i = 0; i < STM_NUM_USARTS; i++) {
-        usartdev = DEVICE(&(s->usart[i]));
-        qdev_prop_set_chr(usartdev, "chardev", i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL);
+        dev = DEVICE(&(s->usart[i]));
+        qdev_prop_set_chr(dev, "chardev",
+                          i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL);
         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,
-                           qdev_get_gpio_in(nvic, usart_irq[i]));
+        busdev = SYS_BUS_DEVICE(dev);
+        sysbus_mmio_map(busdev, 0, usart_addr[i]);
+        sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, usart_irq[i]));
     }
 
     /* Timer 2 to 5 */
     for (i = 0; i < STM_NUM_TIMERS; i++) {
-        timerdev = DEVICE(&(s->timer[i]));
-        qdev_prop_set_uint64(timerdev, "clock-frequency", 1000000000);
+        dev = DEVICE(&(s->timer[i]));
+        qdev_prop_set_uint64(dev, "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,
-                           qdev_get_gpio_in(nvic, timer_irq[i]));
+        busdev = SYS_BUS_DEVICE(dev);
+        sysbus_mmio_map(busdev, 0, timer_addr[i]);
+        sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, timer_irq[i]));
     }
 }
 
Signature · 1 line
2.7.4
#2 lore raw

PATCH v4 2/8 STM32F2xx: Display PWM duty cycle from timer

In reply to Alistair Francis

If correctly configured allow the STM32F2xx timer to print out the PWM duty cycle information.

---
V3:
- Use OR instead of + for masking
- Improve clarity of print statement
V2:
- Fix up if statement braces
- Remove stm32f2xx_timer_set_alarm() call

 hw/timer/stm32f2xx_timer.c | 9 +++++++++
 1 file changed, 9 insertions(+)
hw/timer/stm32f2xx_timer.c +9 -0
index bf0fb28..8c4c1f9 100644
@@ -51,6 +51,15 @@ static void stm32f2xx_timer_interrupt(void *opaque)
         qemu_irq_pulse(s->irq);
         stm32f2xx_timer_set_alarm(s, s->hit_time);
     }
+
+    if (s->tim_ccmr1 & (TIM_CCMR1_OC2M2 | TIM_CCMR1_OC2M1) &&
+        !(s->tim_ccmr1 & TIM_CCMR1_OC2M0) &&
+        s->tim_ccmr1 & TIM_CCMR1_OC2PE &&
+        s->tim_ccer & TIM_CCER_CC2E) {
+        /* PWM 2 - Mode 1 */
+        DB_PRINT("PWM2 Duty Cycle: %d%%\n",
+                s->tim_ccr2 / (100 * (s->tim_psc + 1)));
+    }
 }
 
 static inline int64_t stm32f2xx_ns_to_ticks(STM32F2XXTimerState *s, int64_t t)
Signature · 1 line
2.7.4
#3 lore raw

PATCH v4 3/8 STM32F2xx: Add the ADC device

In reply to Alistair Francis

Add the STM32F2xx ADC device. This device randomly generates values on each read.

This also includes creating a hw/adc directory.

---
V4:
- Remove the rand() function
- Add VMState
- Small cleanups
V2:
- Address Peter C's comments
- Create a ADC folder and move the file in there
- Move some of the registers into arrays

 default-configs/arm-softmmu.mak |   1 +
 hw/Makefile.objs                |   1 +
 hw/adc/Makefile.objs            |   1 +
 hw/adc/stm32f2xx_adc.c          | 306 ++++++++++++++++++++++++++++++++++++++++
 include/hw/adc/stm32f2xx_adc.h  |  87 ++++++++++++
 5 files changed, 396 insertions(+)
 create mode 100644 hw/adc/Makefile.objs
 create mode 100644 hw/adc/stm32f2xx_adc.c
 create mode 100644 include/hw/adc/stm32f2xx_adc.h
default-configs/arm-softmmu.mak +1 -0
index 7a19863..5b1696d 100644
@@ -87,6 +87,7 @@ CONFIG_ZYNQ=y
 CONFIG_STM32F2XX_TIMER=y
 CONFIG_STM32F2XX_USART=y
 CONFIG_STM32F2XX_SYSCFG=y
+CONFIG_STM32F2XX_ADC=y
 CONFIG_STM32F205_SOC=y
 
 CONFIG_VERSATILE_PCI=y
hw/Makefile.objs +1 -0
index 4a07ed4..0ffd281 100644
@@ -1,5 +1,6 @@
 devices-dirs-$(call land, $(CONFIG_VIRTIO),$(call land,$(CONFIG_VIRTFS),$(CONFIG_PCI))) += 9pfs/
 devices-dirs-$(CONFIG_ACPI) += acpi/
+devices-dirs-$(CONFIG_SOFTMMU) += adc/
 devices-dirs-$(CONFIG_SOFTMMU) += audio/
 devices-dirs-$(CONFIG_SOFTMMU) += block/
 devices-dirs-$(CONFIG_SOFTMMU) += bt/
hw/adc/Makefile.objs new file +1 -0
new file mode 100644
index 0000000..3f6dfde
@@ -0,0 +1 @@
+obj-$(CONFIG_STM32F2XX_ADC) += stm32f2xx_adc.o
hw/adc/stm32f2xx_adc.c new file +306 -0

306 lines not on this page · raw message

include/hw/adc/stm32f2xx_adc.h new file +87 -0

87 lines not on this page · raw message

Signature · 1 line
2.7.4
#5 lore raw

PATCH v4 4/8 STM32F2xx: Add the SPI device

In reply to Alistair Francis

Add the STM32F2xx SPI device.

---
V4:
- Add VMState
- Small fixes
V2:
- Address Peter C's comments

 default-configs/arm-softmmu.mak |   1 +
 hw/ssi/Makefile.objs            |   1 +
 hw/ssi/stm32f2xx_spi.c          | 227 ++++++++++++++++++++++++++++++++++++++++
 include/hw/ssi/stm32f2xx_spi.h  |  72 +++++++++++++
 4 files changed, 301 insertions(+)
 create mode 100644 hw/ssi/stm32f2xx_spi.c
 create mode 100644 include/hw/ssi/stm32f2xx_spi.h
default-configs/arm-softmmu.mak +1 -0
index 5b1696d..e9e2de3 100644
@@ -88,6 +88,7 @@ CONFIG_STM32F2XX_TIMER=y
 CONFIG_STM32F2XX_USART=y
 CONFIG_STM32F2XX_SYSCFG=y
 CONFIG_STM32F2XX_ADC=y
+CONFIG_STM32F2XX_SPI=y
 CONFIG_STM32F205_SOC=y
 
 CONFIG_VERSATILE_PCI=y
hw/ssi/Makefile.objs +1 -0
index c79a8dc..487add2 100644
@@ -3,6 +3,7 @@ common-obj-$(CONFIG_SSI) += ssi.o
 common-obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
 common-obj-$(CONFIG_XILINX_SPIPS) += xilinx_spips.o
 common-obj-$(CONFIG_ASPEED_SOC) += aspeed_smc.o
+common-obj-$(CONFIG_STM32F2XX_SPI) += stm32f2xx_spi.o
 
 obj-$(CONFIG_OMAP) += omap_spi.o
 obj-$(CONFIG_IMX) += imx_spi.o
hw/ssi/stm32f2xx_spi.c new file +227 -0

227 lines not on this page · raw message

include/hw/ssi/stm32f2xx_spi.h new file +72 -0

72 lines not on this page · raw message

Signature · 1 line
2.7.4
Reviewed-by on v4 4/8
#6 lore raw

Re: [Qemu-devel] [PATCH v4 4/8] STM32F2xx: Add the SPI device

Quoted 13 lines · Alistair Francis

Add the STM32F2xx SPI device.

---

hw/ssi/stm32f2xx_spi.c new file +8 -0
+static uint64_t stm32f2xx_spi_read(void *opaque, hwaddr addr,
+                                     unsigned int size)
+{
+    STM32F2XXSPIState *s = opaque;
+    uint32_t retval;
+
+    DB_PRINT("Address: 0x%" HWADDR_PRIx "\n", addr);
+

hw/ssi/stm32f2xx_spi.c line 84

Quoted 10 lines
hw/ssi/stm32f2xx_spi.c new file +10 -0
+    switch (addr) {
+    case STM_SPI_CR1:
+        return s->spi_cr1;
+    case STM_SPI_CR2:
+        qemu_log_mask(LOG_UNIMP, "%s: Interrupts and DMA are not implemented\n",
+                      __func__);
+        return s->spi_cr2;
+    case STM_SPI_SR:
+        retval = s->spi_sr;
+        return retval;

Why not just 'return s->spi_sr;' like the other cases?

Quoted 21 lines
hw/ssi/stm32f2xx_spi.c new file +21 -0
+    case STM_SPI_DR:
+        stm32f2xx_spi_transfer(s);
+        s->spi_sr &= ~STM_SPI_SR_RXNE;
+        return s->spi_dr;
+    case STM_SPI_CRCPR:
+        qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \
+                      "are included for compatibility\n", __func__);
+        return s->spi_crcpr;
+    case STM_SPI_RXCRCR:
+        qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \
+                      "are included for compatibility\n", __func__);
+        return s->spi_rxcrcr;
+    case STM_SPI_TXCRCR:
+        qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \
+                      "are included for compatibility\n", __func__);
+        return s->spi_txcrcr;
+    case STM_SPI_I2SCFGR:
+        qemu_log_mask(LOG_UNIMP, "%s: I2S is not implemented, the registers " \
+                      "are included for compatibility\n", __func__);
+        return s->spi_i2scfgr;
+    case STM_SPI_I2SPR:

hw/ssi/stm32f2xx_spi.c line 115

Quoted 10 lines
hw/ssi/stm32f2xx_spi.c new file +10 -0
+        qemu_log_mask(LOG_UNIMP, "%s: I2S is not implemented, the registers " \
+                      "are included for compatibility\n", __func__);
+        return s->spi_i2spr;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+                      __func__, addr);
+    }
+
+    return 0;
+}

Otherwise

thanks
-- PMM

#7 lore raw

Re: [Qemu-devel] [PATCH v4 4/8] STM32F2xx: Add the SPI device

Quoted 18 lines · Peter Maydell
Quoted 17 lines · Alistair Francis

Add the STM32F2xx SPI device.

---

hw/ssi/stm32f2xx_spi.c new file +12 -0
+static uint64_t stm32f2xx_spi_read(void *opaque, hwaddr addr,
+                                     unsigned int size)
+{
+    STM32F2XXSPIState *s = opaque;
+    uint32_t retval;
+
+    DB_PRINT("Address: 0x%" HWADDR_PRIx "\n", addr);
+
+    switch (addr) {
+    case STM_SPI_CR1:
+        return s->spi_cr1;
+    case STM_SPI_CR2:
Quoted 8 lines

hw/ssi/stm32f2xx_spi.c line 84

Quoted 6 lines
hw/ssi/stm32f2xx_spi.c new file +6 -0
+        qemu_log_mask(LOG_UNIMP, "%s: Interrupts and DMA are not implemented\n",
+                      __func__);
+        return s->spi_cr2;
+    case STM_SPI_SR:
+        retval = s->spi_sr;
+        return retval;

Why not just 'return s->spi_sr;' like the other cases?

Not sure, I have fixed this.

Quoted 34 lines
Quoted 22 lines
hw/ssi/stm32f2xx_spi.c new file +21 -0
+    case STM_SPI_DR:
+        stm32f2xx_spi_transfer(s);
+        s->spi_sr &= ~STM_SPI_SR_RXNE;
+        return s->spi_dr;
+    case STM_SPI_CRCPR:
+        qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \
+                      "are included for compatibility\n", __func__);
+        return s->spi_crcpr;
+    case STM_SPI_RXCRCR:
+        qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \
+                      "are included for compatibility\n", __func__);
+        return s->spi_rxcrcr;
+    case STM_SPI_TXCRCR:
+        qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \
+                      "are included for compatibility\n", __func__);
+        return s->spi_txcrcr;
+    case STM_SPI_I2SCFGR:
+        qemu_log_mask(LOG_UNIMP, "%s: I2S is not implemented, the registers " \
+                      "are included for compatibility\n", __func__);
+        return s->spi_i2scfgr;
+    case STM_SPI_I2SPR:

hw/ssi/stm32f2xx_spi.c line 115

Quoted 10 lines
hw/ssi/stm32f2xx_spi.c new file +10 -0
+        qemu_log_mask(LOG_UNIMP, "%s: I2S is not implemented, the registers " \
+                      "are included for compatibility\n", __func__);
+        return s->spi_i2spr;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
+                      __func__, addr);
+    }
+
+    return 0;
+}

Otherwise

Quoted 1 line

Thanks,

Alistair

Quoted 3 lines

thanks
-- PMM

#8 lore raw

PATCH v4 5/8 irq: Add irq information getter functions

In reply to Alistair Francis

Add two functions one to get the irq handler function and another to get the opaque data from a qemu_irq.

---

 hw/core/irq.c    | 10 ++++++++++
 include/hw/irq.h |  4 ++++
 2 files changed, 14 insertions(+)
hw/core/irq.c +10 -0
index 49ff2e6..026200e 100644
@@ -91,6 +91,16 @@ void qemu_free_irq(qemu_irq irq)
     object_unref(OBJECT(irq));
 }
 
+qemu_irq_handler qemu_irq_get_handler(qemu_irq irq)
+{
+    return irq->handler;
+}
+
+void *qemu_irq_get_opaque(qemu_irq irq)
+{
+    return irq->opaque;
+}
+
 static void qemu_notirq(void *opaque, int line, int level)
 {
     struct IRQState *irq = opaque;
include/hw/irq.h +4 -0
index 4c4c2ea..934a8f5 100644
@@ -27,6 +27,10 @@ static inline void qemu_irq_pulse(qemu_irq irq)
     qemu_set_irq(irq, 0);
 }
 
+qemu_irq_handler qemu_irq_get_handler(qemu_irq irq);
+
+void *qemu_irq_get_opaque(qemu_irq irq);
+
 /* Returns an array of N IRQs. Each IRQ is assigned the argument handler and
  * opaque data.
  */
Signature · 1 line
2.7.4
#9 lore raw

PATCH v4 8/8 MAINTAINERS: Add Alistair to the maintainers list

In reply to Alistair Francis

Add Alistair Francis as the maintainer for the Netduino 2 and SMM32F205 SoC.

---

 MAINTAINERS | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
MAINTAINERS +15 -0
index d1439a8..e55be55 100644
@@ -475,6 +475,21 @@ S: Maintained
 F: hw/arm/virt-acpi-build.c
 F: include/hw/arm/virt-acpi-build.h
 
+STM32F205
+M: Alistair Francis <[email protected]>
+S: Maintained
+F: hw/arm/stm32f205_soc.c
+F: hw/misc/stm32f2xx_syscfg.c
+F: hw/char/stm32f2xx_usart.c
+F: hw/timer/stm32f2xx_timer.c
+F: hw/adc/*
+F: hw/ssi/stm32f2xx_spi.c
+
+Netduino 2
+M: Alistair Francis <[email protected]>
+S: Maintained
+F: hw/arm/netduino2.c
+
 CRIS Machines
 -------------
 Axis Dev88
Signature · 1 line
2.7.4

A message that is not in the archive (sent off-list or not yet received): 9c91c6c4f9dfceaa32b756695d2f8f40f3392686.1469258908.git.alistair@alistair23.me

#11 lore raw

Re: [Qemu-devel] [PATCH v4 6/8] STM32F205: Connect the ADC devices

Quoted 26 lines · Alistair Francis

Connect the ADC devices to the STM32F205 SoC.

---
V4:
- Connect all the interrupt lines correctly
V2:
- Fix up the device/devices commit message

(quoted diff) +13 -0
@@ -132,6 +142,29 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
         sysbus_mmio_map(busdev, 0, timer_addr[i]);
         sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, timer_irq[i]));
     }
+
+    /* ADC 1 to 3 */
+    for (i = 0; i < STM_NUM_ADCS; i++) {
+        dev = DEVICE(&(s->adc[i]));
+        object_property_set_bool(OBJECT(&s->adc[i]), true, "realized", &err);
+        if (err != NULL) {
+            error_propagate(errp, err);
+            return;
+        }
+        busdev = SYS_BUS_DEVICE(dev);
+        sysbus_mmio_map(busdev, 0, adc_addr[i]);
+    }
+

Review static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) · line 167

Quoted 10 lines
(quoted diff) +10 -0
+    /* Connect each ADC device to the one GIC IRQ line */
+    gic_adc_irq = qdev_get_gpio_in(nvic, ADC_IRQ);
+    gic_adc_irq_arr = qemu_extend_irqs(NULL, 0,
+                                       qemu_irq_get_handler(gic_adc_irq),
+                                       qemu_irq_get_opaque(gic_adc_irq),
+                                       STM_NUM_ADCS);
+    for (i = 0; i < STM_NUM_ADCS; i++) {
+        dev = DEVICE(&(s->adc[i]));
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, gic_adc_irq_arr[i]);
+    }

This will lower the IRQ input to the GIC as soon as any one of the ADCs lowers its IRQ (even if another of them has it held high), and conversely raise it again as soon as any one ADC raises its IRQ (even if another of them has it held low). We talked about this on the last version: http://patchwork.ozlabs.org/patch/569823/
and I still think you should implement an OR gate here.

Checking the real hardware behaviour by writing a test would be ideal; but whatever the hardware does it isn't going to be what this code does; and an OR gate is the obvious guess.

I was going to suggest something like:

/**
* qemu_irq_or:
* @irqs: array of IRQs to OR together
* @numirqs: number of IRQs in @irqs
*
* Returns a new IRQ which behaves as the logical OR of all the
* input IRQS in @irqs.
*/
qemu_irq qemu_irq_or(qemu_irq *irqs, int numirqs);

along the same lines as qemu_irq_invert(), which creates a NOT gate, but then I realized you need some actual state in there (because you need to remember the current state of all the input lines). So this probably needs to be a real device object so it can be migrated.

thanks
-- PMM

#12 lore raw

Re: [Qemu-devel] [PATCH v4 6/8] STM32F205: Connect the ADC devices

Quoted 61 lines · Peter Maydell
Quoted 26 lines · Alistair Francis

Connect the ADC devices to the STM32F205 SoC.

---
V4:
- Connect all the interrupt lines correctly
V2:
- Fix up the device/devices commit message

(quoted diff) +13 -0
@@ -132,6 +142,29 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
         sysbus_mmio_map(busdev, 0, timer_addr[i]);
         sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, timer_irq[i]));
     }
+
+    /* ADC 1 to 3 */
+    for (i = 0; i < STM_NUM_ADCS; i++) {
+        dev = DEVICE(&(s->adc[i]));
+        object_property_set_bool(OBJECT(&s->adc[i]), true, "realized", &err);
+        if (err != NULL) {
+            error_propagate(errp, err);
+            return;
+        }
+        busdev = SYS_BUS_DEVICE(dev);
+        sysbus_mmio_map(busdev, 0, adc_addr[i]);
+    }
+

Review static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) · line 167

Quoted 10 lines
(quoted diff) +10 -0
+    /* Connect each ADC device to the one GIC IRQ line */
+    gic_adc_irq = qdev_get_gpio_in(nvic, ADC_IRQ);
+    gic_adc_irq_arr = qemu_extend_irqs(NULL, 0,
+                                       qemu_irq_get_handler(gic_adc_irq),
+                                       qemu_irq_get_opaque(gic_adc_irq),
+                                       STM_NUM_ADCS);
+    for (i = 0; i < STM_NUM_ADCS; i++) {
+        dev = DEVICE(&(s->adc[i]));
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, gic_adc_irq_arr[i]);
+    }

This will lower the IRQ input to the GIC as soon as any one of the ADCs lowers its IRQ (even if another of them has it held high), and conversely raise it again as soon as any one ADC raises its IRQ (even if another of them has it held low). We talked about this on the last version: http://patchwork.ozlabs.org/patch/569823/
and I still think you should implement an OR gate here.

Checking the real hardware behaviour by writing a test would be ideal; but whatever the hardware does it isn't going to be what this code does; and an OR gate is the obvious guess.

I was going to suggest something like:

/**
* qemu_irq_or:
* @irqs: array of IRQs to OR together
* @numirqs: number of IRQs in @irqs
*
* Returns a new IRQ which behaves as the logical OR of all the
* input IRQS in @irqs.
*/
qemu_irq qemu_irq_or(qemu_irq *irqs, int numirqs);

Quoted 5 lines

along the same lines as qemu_irq_invert(), which creates a NOT gate, but then I realized you need some actual state in there (because you need to remember the current state of all the input lines). So this probably needs to be a real device object so it can be migrated.

So the way that the GPIO connections work it's better to return the array of inputs, that way you can easily call sysbus_connect_irq() with the device and GIC GPIO inputs being ORed together.

I think this function should work:

/*
* qemu_allocate_or_irqs
* @in_irq: An input IRQ. It will be the result of the @out_irqs ORed together
* @n: The number of interrupt lines that should be ORed together *
* returns: An array of interrupts that should be ORed together
*
* OR all of the interrupts returned in the array into a single @in_irq. */
qemu_irq *qemu_allocate_or_irqs(qemu_irq in_irq, int n);

I'll send the patches as soon as the tests finish.

Thanks,

Alistair

Quoted 3 lines

thanks
-- PMM

#13 lore raw

Re: [Qemu-devel] [PATCH v4 6/8] STM32F205: Connect the ADC devices

Quoted 12 lines · Alistair Francis

I think this function should work:

/*
* qemu_allocate_or_irqs
* @in_irq: An input IRQ. It will be the result of the @out_irqs ORed together
* @n: The number of interrupt lines that should be ORed together *
* returns: An array of interrupts that should be ORed together
*
* OR all of the interrupts returned in the array into a single @in_irq. */
qemu_irq *qemu_allocate_or_irqs(qemu_irq in_irq, int n);

As I say, it really needs to be an actual device because it has to have state (tracking the level of all the inputs so when one changes it can recalculate the new output).

-- PMM