[v3,5/7] STM32F205: Connect the ADC devices
diff mbox

Message ID c3bfb7b3bcf4cb6e4bb7a2fad6c3979692505c3b.1453187657.git.alistair@alistair23.me
State New
Headers show

Commit Message

Alistair Francis Jan. 19, 2016, 7:23 a.m. UTC
Connect the ADC devices to the STM32F205 SoC.

Signed-off-by: Alistair Francis <alistair@alistair23.me>
---
V2:
 - Fix up the device/devices commit message

 hw/arm/stm32f205_soc.c         | 22 ++++++++++++++++++++++
 include/hw/arm/stm32f205_soc.h |  3 +++
 2 files changed, 25 insertions(+)

Comments

Peter Maydell Feb. 2, 2016, 3:27 p.m. UTC | #1
On 19 January 2016 at 07:23, Alistair Francis <alistair23@gmail.com> wrote:
> Connect the ADC devices to the STM32F205 SoC.
>
> Signed-off-by: Alistair Francis <alistair@alistair23.me>
> ---
> V2:
>  - Fix up the device/devices commit message
>
>  hw/arm/stm32f205_soc.c         | 22 ++++++++++++++++++++++
>  include/hw/arm/stm32f205_soc.h |  3 +++
>  2 files changed, 25 insertions(+)
>
> diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c
> index a2bd970..28d4301 100644
> --- a/hw/arm/stm32f205_soc.c
> +++ b/hw/arm/stm32f205_soc.c
> @@ -32,9 +32,12 @@ static const uint32_t timer_addr[STM_NUM_TIMERS] = { 0x40000000, 0x40000400,
>      0x40000800, 0x40000C00 };
>  static const uint32_t usart_addr[STM_NUM_USARTS] = { 0x40011000, 0x40004400,
>      0x40004800, 0x40004C00, 0x40005000, 0x40011400 };
> +static const uint32_t adc_addr[STM_NUM_ADCS] = { 0x40012000, 0x40012100,
> +    0x40012200 };
>
>  static const int timer_irq[STM_NUM_TIMERS] = {28, 29, 30, 50};
>  static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39, 52, 53, 71};
> +#define ADC_IRQ 18

Really three devices but only one IRQ ?

> +    /* 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]);
> +        sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, ADC_IRQ));

You can't just wire multiple irq lines up like this; I think if
you do then if devices A and B both assert the IRQ and then A
deasserts it, then the receiving device will see an IRQ deassert
when it should not (since B still holds it high).

thanks
-- PMM
Alistair Francis Feb. 21, 2016, 11:35 p.m. UTC | #2
On Tue, Feb 2, 2016 at 7:27 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 19 January 2016 at 07:23, Alistair Francis <alistair23@gmail.com> wrote:
>> Connect the ADC devices to the STM32F205 SoC.
>>
>> Signed-off-by: Alistair Francis <alistair@alistair23.me>
>> ---
>> V2:
>>  - Fix up the device/devices commit message
>>
>>  hw/arm/stm32f205_soc.c         | 22 ++++++++++++++++++++++
>>  include/hw/arm/stm32f205_soc.h |  3 +++
>>  2 files changed, 25 insertions(+)
>>
>> diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c
>> index a2bd970..28d4301 100644
>> --- a/hw/arm/stm32f205_soc.c
>> +++ b/hw/arm/stm32f205_soc.c
>> @@ -32,9 +32,12 @@ static const uint32_t timer_addr[STM_NUM_TIMERS] = { 0x40000000, 0x40000400,
>>      0x40000800, 0x40000C00 };
>>  static const uint32_t usart_addr[STM_NUM_USARTS] = { 0x40011000, 0x40004400,
>>      0x40004800, 0x40004C00, 0x40005000, 0x40011400 };
>> +static const uint32_t adc_addr[STM_NUM_ADCS] = { 0x40012000, 0x40012100,
>> +    0x40012200 };
>>
>>  static const int timer_irq[STM_NUM_TIMERS] = {28, 29, 30, 50};
>>  static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39, 52, 53, 71};
>> +#define ADC_IRQ 18
>
> Really three devices but only one IRQ ?

Yep, that's how HW does it. At least according to the reference manual.

>
>> +    /* 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]);
>> +        sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, ADC_IRQ));
>
> You can't just wire multiple irq lines up like this; I think if
> you do then if devices A and B both assert the IRQ and then A
> deasserts it, then the receiving device will see an IRQ deassert
> when it should not (since B still holds it high).

I can't figure out if that is how HW actually does it. I can't find
too much in the data sheet on how these interrupts behave.

In saying that, I am fine with what you described being the behaviour.
I don't know any better way to connect the 3 devices to one interrupt
line. Do you have any suggestions?

Thanks,

Alistair

>
> thanks
> -- PMM
Peter Maydell Feb. 22, 2016, 12:29 a.m. UTC | #3
On 21 February 2016 at 23:35, Alistair Francis <alistair23@gmail.com> wrote:
> On Tue, Feb 2, 2016 at 7:27 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> On 19 January 2016 at 07:23, Alistair Francis <alistair23@gmail.com> wrote:
>> You can't just wire multiple irq lines up like this; I think if
>> you do then if devices A and B both assert the IRQ and then A
>> deasserts it, then the receiving device will see an IRQ deassert
>> when it should not (since B still holds it high).
>
> I can't figure out if that is how HW actually does it. I can't find
> too much in the data sheet on how these interrupts behave.
>
> In saying that, I am fine with what you described being the behaviour.
> I don't know any better way to connect the 3 devices to one interrupt
> line. Do you have any suggestions?

You're right that the data sheet is unclear, but I think the
only vaguely plausible setup is that the three lines are ORed
together. That way if any ADC asserts the line then the guest
presumably looks at all of them to find which one has asserted
it, and then writes to the register to acknowledge the interrupt.
So if two ADCs assert at the same time, the guest will still
(correctly) see an interrupt until it acks the second ADC.

Unfortunately we don't have a qemu_irq OR gate at the moment
I think, but it's a pretty simple thing to write.

thanks
-- PMM

Patch
diff mbox

diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c
index a2bd970..28d4301 100644
--- a/hw/arm/stm32f205_soc.c
+++ b/hw/arm/stm32f205_soc.c
@@ -32,9 +32,12 @@  static const uint32_t timer_addr[STM_NUM_TIMERS] = { 0x40000000, 0x40000400,
     0x40000800, 0x40000C00 };
 static const uint32_t usart_addr[STM_NUM_USARTS] = { 0x40011000, 0x40004400,
     0x40004800, 0x40004C00, 0x40005000, 0x40011400 };
+static const uint32_t adc_addr[STM_NUM_ADCS] = { 0x40012000, 0x40012100,
+    0x40012200 };
 
 static const int timer_irq[STM_NUM_TIMERS] = {28, 29, 30, 50};
 static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39, 52, 53, 71};
+#define ADC_IRQ 18
 
 static void stm32f205_soc_initfn(Object *obj)
 {
@@ -55,6 +58,12 @@  static void stm32f205_soc_initfn(Object *obj)
                           TYPE_STM32F2XX_TIMER);
         qdev_set_parent_bus(DEVICE(&s->timer[i]), sysbus_get_default());
     }
+
+    for (i = 0; i < STM_NUM_ADCS; i++) {
+        object_initialize(&s->adc[i], sizeof(s->adc[i]),
+                          TYPE_STM32F2XX_ADC);
+        qdev_set_parent_bus(DEVICE(&s->adc[i]), sysbus_get_default());
+    }
 }
 
 static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
@@ -128,6 +137,19 @@  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]);
+        sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, ADC_IRQ));
+    }
 }
 
 static Property stm32f205_soc_properties[] = {
diff --git a/include/hw/arm/stm32f205_soc.h b/include/hw/arm/stm32f205_soc.h
index 0390eff..091e4be 100644
--- a/include/hw/arm/stm32f205_soc.h
+++ b/include/hw/arm/stm32f205_soc.h
@@ -28,6 +28,7 @@ 
 #include "hw/misc/stm32f2xx_syscfg.h"
 #include "hw/timer/stm32f2xx_timer.h"
 #include "hw/char/stm32f2xx_usart.h"
+#include "hw/adc/stm32f2xx_adc.h"
 
 #define TYPE_STM32F205_SOC "stm32f205-soc"
 #define STM32F205_SOC(obj) \
@@ -35,6 +36,7 @@ 
 
 #define STM_NUM_USARTS 6
 #define STM_NUM_TIMERS 4
+#define STM_NUM_ADCS 3
 
 #define FLASH_BASE_ADDRESS 0x08000000
 #define FLASH_SIZE (1024 * 1024)
@@ -52,6 +54,7 @@  typedef struct STM32F205State {
     STM32F2XXSyscfgState syscfg;
     STM32F2XXUsartState usart[STM_NUM_USARTS];
     STM32F2XXTimerState timer[STM_NUM_TIMERS];
+    STM32F2XXADCState adc[STM_NUM_ADCS];
 } STM32F205State;
 
 #endif