From: Davide Berardi <berardi.dav@gmail.com>
To: qemu-devel@nongnu.org
Cc: "Peter Maydell" <peter.maydell@linaro.org>,
qemu-arm@nongnu.org, "Philippe Mathieu-Daudé" <f4bug@amsat.org>,
"Andrew Baumann" <Andrew.Baumann@microsoft.com>
Subject: [PATCH] Raspberry PI GPIO interrupt support
Date: Tue, 9 Feb 2021 10:03:10 +0100 [thread overview]
Message-ID: <20210209090310.GA25789@carpenter.lan> (raw)
The bcm2835 GPIOs now generate interrupts.
This modification enables QTEST clients to trigger interrupt-based
interfaces.
Signed-off-by: Davide Berardi <berardi.dav@gmail.com>
---
hw/arm/bcm2835_peripherals.c | 2 +
hw/gpio/bcm2835_gpio.c | 105 +++++++++++++++++++++++++++++++++
hw/intc/bcm2835_ic.c | 2 -
include/hw/gpio/bcm2835_gpio.h | 12 ++++
4 files changed, 119 insertions(+), 2 deletions(-)
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
index dcff13433e..101c3e6fba 100644
--- a/hw/arm/bcm2835_peripherals.c
+++ b/hw/arm/bcm2835_peripherals.c
@@ -114,6 +114,8 @@ static void bcm2835_peripherals_init(Object *obj)
OBJECT(&s->sdhci.sdbus));
object_property_add_const_link(OBJECT(&s->gpio), "sdbus-sdhost",
OBJECT(&s->sdhost.sdbus));
+ object_property_add_const_link(OBJECT(&s->gpio), "ic",
+ OBJECT(&s->ic));
/* Mphi */
object_initialize_child(obj, "mphi", &s->mphi, TYPE_BCM2835_MPHI);
diff --git a/hw/gpio/bcm2835_gpio.c b/hw/gpio/bcm2835_gpio.c
index abdddbc67c..2952ebe1da 100644
--- a/hw/gpio/bcm2835_gpio.c
+++ b/hw/gpio/bcm2835_gpio.c
@@ -7,6 +7,9 @@
* Clement Deschamps <clement.deschamps@antfield.fr>
* Luc Michel <luc.michel@antfield.fr>
*
+ * GPIO Interrupt support
+ * Davide Berardi <berardi.dav@gmail.com>
+ *
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
@@ -20,6 +23,7 @@
#include "migration/vmstate.h"
#include "hw/sd/sd.h"
#include "hw/gpio/bcm2835_gpio.h"
+#include "hw/intc/bcm2835_ic.h"
#include "hw/irq.h"
#define GPFSEL0 0x00
@@ -110,6 +114,29 @@ static int gpfsel_is_out(BCM2835GpioState *s, int index)
return 0;
}
+static inline int get_bit_2_u32(const uint32_t idx,
+ const uint32_t v1, const uint32_t v2)
+{
+ uint64_t v = v1 | ((uint64_t)v2) << 32;
+ return !!(v & (1 << idx));
+}
+
+static int ren_detect(BCM2835GpioState *s, int index)
+{
+ if (index >= 0 && index < 54) {
+ return get_bit_2_u32(index, s->ren0, s->ren1);
+ }
+ return 0;
+}
+
+static int fen_detect(BCM2835GpioState *s, int index)
+{
+ if (index >= 0 && index < 54) {
+ return get_bit_2_u32(index, s->fen0, s->fen1);
+ }
+ return 0;
+}
+
static void gpset(BCM2835GpioState *s,
uint32_t val, uint8_t start, uint8_t count, uint32_t *lev)
{
@@ -120,6 +147,20 @@ static void gpset(BCM2835GpioState *s,
for (i = 0; i < count; i++) {
if ((changes & cur) && (gpfsel_is_out(s, start + i))) {
qemu_set_irq(s->out[start + i], 1);
+ } else if ((changes & cur) && ren_detect(s, start + i)) {
+ /* If this is an input and must check rising edge */
+ int irqline = 0;
+ if (i > 27)
+ irqline = 1;
+ if (i > 45)
+ irqline = 2;
+
+ /* Set the bit in the events */
+ if (i < 32)
+ s->eds0 |= cur;
+ else
+ s->eds1 |= cur;
+ qemu_set_irq(s->irq[irqline], 1);
}
cur <<= 1;
}
@@ -137,6 +178,15 @@ static void gpclr(BCM2835GpioState *s,
for (i = 0; i < count; i++) {
if ((changes & cur) && (gpfsel_is_out(s, start + i))) {
qemu_set_irq(s->out[start + i], 0);
+ } else if ((changes & cur) && fen_detect(s, start + i)) {
+ /* If this is an input we must check falling edge */
+ int irqline = 0;
+ if (i > 27)
+ irqline = 1;
+ if (i > 45)
+ irqline = 2;
+
+ qemu_set_irq(s->irq[irqline], 1);
}
cur <<= 1;
}
@@ -144,6 +194,34 @@ static void gpclr(BCM2835GpioState *s,
*lev &= ~val;
}
+static int gpio_from_value(uint64_t value, int bank)
+{
+ int i;
+ for (i = 0 ; i < 32; ++i)
+ if (value & (1 << i))
+ return i + (32 * bank);
+ return 0;
+}
+
+static void eds_clear(BCM2835GpioState *s, uint64_t value, int bank)
+{
+ int gpio = 0;
+ int irqline = 0;
+ if (bank) {
+ s->eds0 &= ~value;
+ } else {
+ s->eds1 &= (~value & 0x3f);
+ }
+ gpio = gpio_from_value(value, bank);
+
+ if (gpio > 27)
+ irqline = 1;
+ if (gpio > 45)
+ irqline = 2;
+
+ qemu_set_irq(s->irq[irqline], 0);
+}
+
static uint64_t bcm2835_gpio_read(void *opaque, hwaddr offset,
unsigned size)
{
@@ -170,11 +248,17 @@ static uint64_t bcm2835_gpio_read(void *opaque, hwaddr offset,
case GPLEV1:
return s->lev1;
case GPEDS0:
+ return s->eds0;
case GPEDS1:
+ return s->eds1;
case GPREN0:
+ return s->ren0;
case GPREN1:
+ return s->ren1;
case GPFEN0:
+ return s->fen0;
case GPFEN1:
+ return s->fen1;
case GPHEN0:
case GPHEN1:
case GPLEN0:
@@ -228,11 +312,23 @@ static void bcm2835_gpio_write(void *opaque, hwaddr offset,
/* Read Only */
break;
case GPEDS0:
+ eds_clear(s, value, 0);
+ break;
case GPEDS1:
+ eds_clear(s, value, 1);
+ break;
case GPREN0:
+ s->ren0 = value;
+ break;
case GPREN1:
+ s->ren1 = value;
+ break;
case GPFEN0:
+ s->fen0 = value;
+ break;
case GPFEN1:
+ s->fen1 = value;
+ break;
case GPHEN0:
case GPHEN1:
case GPLEN0:
@@ -310,6 +406,7 @@ static void bcm2835_gpio_init(Object *obj)
static void bcm2835_gpio_realize(DeviceState *dev, Error **errp)
{
+ int i;
BCM2835GpioState *s = BCM2835_GPIO(dev);
Object *obj;
@@ -318,6 +415,14 @@ static void bcm2835_gpio_realize(DeviceState *dev, Error **errp)
obj = object_property_get_link(OBJECT(dev), "sdbus-sdhost", &error_abort);
s->sdbus_sdhost = SD_BUS(obj);
+
+ obj = object_property_get_link(OBJECT(dev), "ic", &error_abort);
+ s->ic = BCM2835_IC(obj);
+
+ for (i = 0 ; i < 3; ++i) {
+ s->irq[i] = qdev_get_gpio_in_named(DEVICE(obj),
+ BCM2835_IC_GPU_IRQ, i + 49);
+ }
}
static void bcm2835_gpio_class_init(ObjectClass *klass, void *data)
diff --git a/hw/intc/bcm2835_ic.c b/hw/intc/bcm2835_ic.c
index 9000d995e8..b381dc6603 100644
--- a/hw/intc/bcm2835_ic.c
+++ b/hw/intc/bcm2835_ic.c
@@ -57,7 +57,6 @@ static void bcm2835_ic_update(BCM2835ICState *s)
static void bcm2835_ic_set_gpu_irq(void *opaque, int irq, int level)
{
BCM2835ICState *s = opaque;
-
assert(irq >= 0 && irq < 64);
trace_bcm2835_ic_set_gpu_irq(irq, level);
s->gpu_irq_level = deposit64(s->gpu_irq_level, irq, 1, level != 0);
@@ -67,7 +66,6 @@ static void bcm2835_ic_set_gpu_irq(void *opaque, int irq, int level)
static void bcm2835_ic_set_arm_irq(void *opaque, int irq, int level)
{
BCM2835ICState *s = opaque;
-
assert(irq >= 0 && irq < 8);
trace_bcm2835_ic_set_cpu_irq(irq, level);
s->arm_irq_level = deposit32(s->arm_irq_level, irq, 1, level != 0);
diff --git a/include/hw/gpio/bcm2835_gpio.h b/include/hw/gpio/bcm2835_gpio.h
index 1c53a05090..cad3e987d3 100644
--- a/include/hw/gpio/bcm2835_gpio.h
+++ b/include/hw/gpio/bcm2835_gpio.h
@@ -7,6 +7,9 @@
* Clement Deschamps <clement.deschamps@antfield.fr>
* Luc Michel <luc.michel@antfield.fr>
*
+ * GPIO External support
+ * Davide Berardi <berardi.dav@gmail.com>
+ *
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
@@ -17,6 +20,7 @@
#include "hw/sd/sd.h"
#include "hw/sysbus.h"
#include "qom/object.h"
+#include "hw/intc/bcm2835_ic.h"
struct BCM2835GpioState {
SysBusDevice parent_obj;
@@ -27,11 +31,19 @@ struct BCM2835GpioState {
SDBus sdbus;
SDBus *sdbus_sdhci;
SDBus *sdbus_sdhost;
+ BCM2835ICState *ic;
uint8_t fsel[54];
uint32_t lev0, lev1;
+ /* Event detection */
+ uint32_t eds0, eds1;
+ /* Edge selector */
+ uint32_t ren0, ren1;
+ uint32_t fen0, fen1;
+
uint8_t sd_fsel;
qemu_irq out[54];
+ qemu_irq irq[3];
};
#define TYPE_BCM2835_GPIO "bcm2835_gpio"
--
2.30.0
next reply other threads:[~2021-02-09 14:43 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-02-09 9:03 Davide Berardi [this message]
-- strict thread matches above, loose matches on Subject: below --
2021-02-09 11:02 [PATCH] Raspberry PI GPIO interrupt support Davide Berardi
2021-02-09 11:30 ` Philippe Mathieu-Daudé
2021-02-10 14:32 ` Davide Berardi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210209090310.GA25789@carpenter.lan \
--to=berardi.dav@gmail.com \
--cc=Andrew.Baumann@microsoft.com \
--cc=f4bug@amsat.org \
--cc=peter.maydell@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.