Signed-off-by: Sergey Kambalin <sergey.kambalin@auriga.com>
---
hw/gpio/bcm2838_gpio.c | 59 +++++++++++++++++++++++++++++++---
include/hw/gpio/bcm2838_gpio.h | 5 +++
2 files changed, 60 insertions(+), 4 deletions(-)
diff --git a/hw/gpio/bcm2838_gpio.c b/hw/gpio/bcm2838_gpio.c
index 51eb55b00a..f166ce7959 100644
--- a/hw/gpio/bcm2838_gpio.c
+++ b/hw/gpio/bcm2838_gpio.c
@@ -17,9 +17,10 @@
#include "qemu/timer.h"
#include "qapi/error.h"
#include "hw/sysbus.h"
-#include "migration/vmstate.h"
+#include "hw/sd/sd.h"
#include "hw/gpio/bcm2838_gpio.h"
#include "hw/irq.h"
+#include "migration/vmstate.h"
#define GPFSEL0 0x00
#define GPFSEL1 0x04
@@ -64,6 +65,16 @@
#define BYTES_IN_WORD 4
+/* bcm,function property */
+#define BCM2838_FSEL_GPIO_IN 0
+#define BCM2838_FSEL_GPIO_OUT 1
+#define BCM2838_FSEL_ALT5 2
+#define BCM2838_FSEL_ALT4 3
+#define BCM2838_FSEL_ALT0 4
+#define BCM2838_FSEL_ALT1 5
+#define BCM2838_FSEL_ALT2 6
+#define BCM2838_FSEL_ALT3 7
+
static uint32_t gpfsel_get(BCM2838GpioState *s, uint8_t reg)
{
int i;
@@ -87,6 +98,31 @@ static void gpfsel_set(BCM2838GpioState *s, uint8_t reg, uint32_t value)
s->fsel[index] = fsel;
}
}
+
+ /* SD controller selection (48-53) */
+ if (s->sd_fsel != BCM2838_FSEL_GPIO_IN
+ && (s->fsel[48] == BCM2838_FSEL_GPIO_IN)
+ && (s->fsel[49] == BCM2838_FSEL_GPIO_IN)
+ && (s->fsel[50] == BCM2838_FSEL_GPIO_IN)
+ && (s->fsel[51] == BCM2838_FSEL_GPIO_IN)
+ && (s->fsel[52] == BCM2838_FSEL_GPIO_IN)
+ && (s->fsel[53] == BCM2838_FSEL_GPIO_IN)
+ ) {
+ /* SDHCI controller selected */
+ sdbus_reparent_card(s->sdbus_sdhost, s->sdbus_sdhci);
+ s->sd_fsel = BCM2838_FSEL_GPIO_IN;
+ } else if (s->sd_fsel != BCM2838_FSEL_ALT0
+ && (s->fsel[48] == BCM2838_FSEL_ALT0) /* SD_CLK_R */
+ && (s->fsel[49] == BCM2838_FSEL_ALT0) /* SD_CMD_R */
+ && (s->fsel[50] == BCM2838_FSEL_ALT0) /* SD_DATA0_R */
+ && (s->fsel[51] == BCM2838_FSEL_ALT0) /* SD_DATA1_R */
+ && (s->fsel[52] == BCM2838_FSEL_ALT0) /* SD_DATA2_R */
+ && (s->fsel[53] == BCM2838_FSEL_ALT0) /* SD_DATA3_R */
+ ) {
+ /* SDHost controller selected */
+ sdbus_reparent_card(s->sdbus_sdhci, s->sdbus_sdhost);
+ s->sd_fsel = BCM2838_FSEL_ALT0;
+ }
}
static int gpfsel_is_out(BCM2838GpioState *s, int index)
@@ -266,6 +302,11 @@ static void bcm2838_gpio_reset(DeviceState *dev)
memset(s->fsel, 0, sizeof(s->fsel));
+ s->sd_fsel = 0;
+
+ /* SDHCI is selected by default */
+ sdbus_reparent_card(&s->sdbus, s->sdbus_sdhci);
+
s->lev0 = 0;
s->lev1 = 0;
@@ -302,15 +343,25 @@ static void bcm2838_gpio_init(Object *obj)
DeviceState *dev = DEVICE(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- memory_region_init_io(&s->iomem, obj, &bcm2838_gpio_ops, s,
- "bcm2838_gpio", BCM2838_GPIO_REGS_SIZE);
+ qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS, DEVICE(s), "sd-bus");
+
+ memory_region_init_io(
+ &s->iomem, obj,
+ &bcm2838_gpio_ops, s, "bcm2838_gpio", BCM2838_GPIO_REGS_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
qdev_init_gpio_out(dev, s->out, BCM2838_GPIO_NUM);
}
static void bcm2838_gpio_realize(DeviceState *dev, Error **errp)
{
- /* Temporary stub. Do nothing */
+ BCM2838GpioState *s = BCM2838_GPIO(dev);
+ Object *obj;
+
+ obj = object_property_get_link(OBJECT(dev), "sdbus-sdhci", &error_abort);
+ s->sdbus_sdhci = SD_BUS(obj);
+
+ obj = object_property_get_link(OBJECT(dev), "sdbus-sdhost", &error_abort);
+ s->sdbus_sdhost = SD_BUS(obj);
}
static void bcm2838_gpio_class_init(ObjectClass *klass, void *data)
diff --git a/include/hw/gpio/bcm2838_gpio.h b/include/hw/gpio/bcm2838_gpio.h
index 06d48e0c19..f2a57a697f 100644
--- a/include/hw/gpio/bcm2838_gpio.h
+++ b/include/hw/gpio/bcm2838_gpio.h
@@ -14,6 +14,7 @@
#ifndef BCM2838_GPIO_H
#define BCM2838_GPIO_H
+#include "hw/sd/sd.h"
#include "hw/sysbus.h"
#include "qom/object.h"
@@ -29,6 +30,10 @@ struct BCM2838GpioState {
MemoryRegion iomem;
+ /* SDBus selector */
+ SDBus sdbus;
+ SDBus *sdbus_sdhci;
+ SDBus *sdbus_sdhost;
uint8_t fsel[BCM2838_GPIO_NUM];
uint32_t lev0, lev1;
--
2.34.1