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>
This commit is contained in:
Peter Maydell 2011-02-21 20:57:50 +00:00 committed by Aurelien Jarno
parent c31a4724e2
commit b50ff6f524
2 changed files with 50 additions and 1 deletions

View File

@ -26,6 +26,7 @@ typedef struct {
uint32_t nvflags; uint32_t nvflags;
uint32_t resetlevel; uint32_t resetlevel;
uint32_t proc_id; uint32_t proc_id;
uint32_t sys_mci;
} arm_sysctl_state; } arm_sysctl_state;
static const VMStateDescription vmstate_arm_sysctl = { 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) static void arm_sysctl_reset(DeviceState *d)
{ {
arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, sysbus_from_qdev(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 */ case 0x44: /* PCICTL */
return 1; return 1;
case 0x48: /* MCI */ case 0x48: /* MCI */
return 0; return s->sys_mci;
case 0x4c: /* FLASH */ case 0x4c: /* FLASH */
return 0; return 0;
case 0x50: /* CLCD */ case 0x50: /* CLCD */
@ -218,6 +234,34 @@ static CPUWriteMemoryFunc * const arm_sysctl_writefn[] = {
arm_sysctl_write 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) static int arm_sysctl_init1(SysBusDevice *dev)
{ {
arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, 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, arm_sysctl_writefn, s,
DEVICE_NATIVE_ENDIAN); DEVICE_NATIVE_ENDIAN);
sysbus_init_mmio(dev, 0x1000, iomemtype); sysbus_init_mmio(dev, 0x1000, iomemtype);
qdev_init_gpio_in(&s->busdev.qdev, arm_sysctl_gpio_set, 2);
/* ??? Save/restore. */ /* ??? Save/restore. */
return 0; return 0;
} }

View File

@ -11,4 +11,8 @@ void *pl080_init(uint32_t base, qemu_irq irq, int nchannels);
/* arm_sysctl.c */ /* arm_sysctl.c */
void arm_sysctl_init(uint32_t base, uint32_t sys_id, uint32_t proc_id); void arm_sysctl_init(uint32_t base, uint32_t sys_id, uint32_t proc_id);
/* arm_sysctl GPIO lines */
#define ARM_SYSCTL_GPIO_MMC_WPROT 0
#define ARM_SYSCTL_GPIO_MMC_CARDIN 1
#endif #endif