aboutsummaryrefslogtreecommitdiffstats
path: root/hw/arm_sysctl.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2011-02-21 20:57:50 +0000
committerAurelien Jarno <aurelien@aurel32.net>2011-03-06 19:01:30 +0100
commitb50ff6f524fae78c7d79b27b00af701d7c28e80c (patch)
treebed8c0afa225bcdd5c99b6d0443a5cd82af3aa59 /hw/arm_sysctl.c
parentc31a4724e25ef867acda0eafc7ddb3999e4bb204 (diff)
hw/arm_sysctl.c: Wire MCI register MMC card status bits to GPIO inputs
Implement some GPIO inputs which a board can connect up to set the MMC card status bits in the MCI register. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Diffstat (limited to 'hw/arm_sysctl.c')
-rw-r--r--hw/arm_sysctl.c47
1 files changed, 46 insertions, 1 deletions
diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index d8b062c1b..799b00779 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -26,6 +26,7 @@ typedef struct {
uint32_t nvflags;
uint32_t resetlevel;
uint32_t proc_id;
+ uint32_t sys_mci;
} arm_sysctl_state;
static const VMStateDescription vmstate_arm_sysctl = {
@@ -44,6 +45,21 @@ static const VMStateDescription vmstate_arm_sysctl = {
}
};
+/* The PB926 actually uses a different format for
+ * its SYS_ID register. Fortunately the bits which are
+ * board type on later boards are distinct.
+ */
+#define BOARD_ID_PB926 0x100
+#define BOARD_ID_EB 0x140
+#define BOARD_ID_PBA8 0x178
+#define BOARD_ID_PBX 0x182
+
+static int board_id(arm_sysctl_state *s)
+{
+ /* Extract the board ID field from the SYS_ID register value */
+ return (s->sys_id >> 16) & 0xfff;
+}
+
static void arm_sysctl_reset(DeviceState *d)
{
arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, sysbus_from_qdev(d));
@@ -92,7 +108,7 @@ static uint32_t arm_sysctl_read(void *opaque, target_phys_addr_t offset)
case 0x44: /* PCICTL */
return 1;
case 0x48: /* MCI */
- return 0;
+ return s->sys_mci;
case 0x4c: /* FLASH */
return 0;
case 0x50: /* CLCD */
@@ -218,6 +234,34 @@ static CPUWriteMemoryFunc * const arm_sysctl_writefn[] = {
arm_sysctl_write
};
+static void arm_sysctl_gpio_set(void *opaque, int line, int level)
+{
+ arm_sysctl_state *s = (arm_sysctl_state *)opaque;
+ switch (line) {
+ case ARM_SYSCTL_GPIO_MMC_WPROT:
+ {
+ /* For PB926 and EB write-protect is bit 2 of SYS_MCI;
+ * for all later boards it is bit 1.
+ */
+ int bit = 2;
+ if ((board_id(s) == BOARD_ID_PB926) || (board_id(s) == BOARD_ID_EB)) {
+ bit = 4;
+ }
+ s->sys_mci &= ~bit;
+ if (level) {
+ s->sys_mci |= bit;
+ }
+ break;
+ }
+ case ARM_SYSCTL_GPIO_MMC_CARDIN:
+ s->sys_mci &= ~1;
+ if (level) {
+ s->sys_mci |= 1;
+ }
+ break;
+ }
+}
+
static int arm_sysctl_init1(SysBusDevice *dev)
{
arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev);
@@ -227,6 +271,7 @@ static int arm_sysctl_init1(SysBusDevice *dev)
arm_sysctl_writefn, s,
DEVICE_NATIVE_ENDIAN);
sysbus_init_mmio(dev, 0x1000, iomemtype);
+ qdev_init_gpio_in(&s->busdev.qdev, arm_sysctl_gpio_set, 2);
/* ??? Save/restore. */
return 0;
}