qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v2 2/2] integrator/cp: Implement CARDIN and WPRO


From: Peter Crosthwaite
Subject: Re: [Qemu-devel] [PATCH v2 2/2] integrator/cp: Implement CARDIN and WPROT signals
Date: Sat, 21 Feb 2015 10:52:09 -0800

On Thu, Feb 19, 2015 at 9:53 AM, Jan Kiszka <address@hidden> wrote:
> This allows to use the SD card emulation of the board: Forward the
> signals from the pl181 top the CP control register emulation, report the
> current state via CP_INTREG, deliver CARDIN IRQ to the secondary
> interrupt controller and also support clearing that line via CP_INTREG.
>
> Signed-off-by: Jan Kiszka <address@hidden>
> ---
>  hw/arm/integratorcp.c | 58 
> +++++++++++++++++++++++++++++++++++++++++++++------
>  1 file changed, 52 insertions(+), 6 deletions(-)
>
> diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c
> index c5aa1f6..39803a9 100644
> --- a/hw/arm/integratorcp.c
> +++ b/hw/arm/integratorcp.c
> @@ -416,18 +416,29 @@ typedef struct ICPCtrlRegsState {
>      /*< public >*/
>
>      MemoryRegion iomem;
> +
> +    qemu_irq mmc_irq;
> +    uint32_t intreg_state;
>  } ICPCtrlRegsState;
>
> +#define ICP_GPIO_MMC_WPROT      0
> +#define ICP_GPIO_MMC_CARDIN     1
> +
> +#define ICP_INTREG_WPROT        (1 << 0)
> +#define ICP_INTREG_CARDIN       (1 << 3)
> +
>  static uint64_t icp_control_read(void *opaque, hwaddr offset,
>                                   unsigned size)
>  {
> +    ICPCtrlRegsState *s = opaque;
> +
>      switch (offset >> 2) {
>      case 0: /* CP_IDFIELD */
>          return 0x41034003;
>      case 1: /* CP_FLASHPROG */
>          return 0;
>      case 2: /* CP_INTREG */
> -        return 0;
> +        return s->intreg_state;
>      case 3: /* CP_DECODE */
>          return 0x11;
>      default:
> @@ -439,9 +450,14 @@ static uint64_t icp_control_read(void *opaque, hwaddr 
> offset,
>  static void icp_control_write(void *opaque, hwaddr offset,
>                            uint64_t value, unsigned size)
>  {
> +    ICPCtrlRegsState *s = opaque;
> +
>      switch (offset >> 2) {
> -    case 1: /* CP_FLASHPROG */
>      case 2: /* CP_INTREG */
> +        s->intreg_state &= ~(value & ICP_INTREG_CARDIN);
> +        qemu_set_irq(s->mmc_irq, !!(s->intreg_state & ICP_INTREG_CARDIN));
> +        break;
> +    case 1: /* CP_FLASHPROG */
>      case 3: /* CP_DECODE */
>          /* Nothing interesting implemented yet.  */
>          break;
> @@ -456,14 +472,39 @@ static const MemoryRegionOps icp_control_ops = {
>      .endianness = DEVICE_NATIVE_ENDIAN,
>  };
>
> +static void icp_control_gpio_set(void *opaque, int line, int level)
> +{
> +    ICPCtrlRegsState *s = opaque;
> +
> +    switch (line) {
> +    case ICP_GPIO_MMC_WPROT:
> +        s->intreg_state &= ~ICP_INTREG_WPROT;
> +        if (level) {
> +            s->intreg_state |= ICP_INTREG_WPROT;
> +        }
> +        break;
> +    case ICP_GPIO_MMC_CARDIN:
> +        /* line is released by writing to CP_INTREG */
> +        if (level) {
> +            s->intreg_state |= ICP_INTREG_CARDIN;
> +            qemu_set_irq(s->mmc_irq, 1);
> +        }
> +        break;
> +    }
> +}
> +

qdev_init_gpio_in_named lets you init multiple GPIOs with different
handler fns without having to enumerate then and switch-case them like
this.

>  static int icp_control_init(SysBusDevice *sbd)
>  {
>      ICPCtrlRegsState *s = ICP_CONTROL_REGS(sbd);
> +    DeviceState *dev = DEVICE(sbd);
>
>      memory_region_init_io(&s->iomem, OBJECT(s), &icp_control_ops, s,
>                            "icp_ctrl_regs", 0x00800000);
>      sysbus_init_mmio(sbd, &s->iomem);
>
> +    qdev_init_gpio_in(dev, icp_control_gpio_set, 2);

So you would be something like:

qdev_init_gpio_in_named(dev, icp_writeprot_gpio, "write-prot", 1);
qdev_init_gpio_in_named(dev, icp_cardin_gpio, "card-in", 1);

Strings should be macroified (would replace existing enumeration macros).

Regards,
Peter

> +    sysbus_init_irq(sbd, &s->mmc_irq);
> +
>      return 0;
>  }
>
> @@ -489,7 +530,7 @@ static void integratorcp_init(MachineState *machine)
>      MemoryRegion *ram = g_new(MemoryRegion, 1);
>      MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
>      qemu_irq pic[32];
> -    DeviceState *dev;
> +    DeviceState *dev, *sic, *icp;
>      int i;
>      Error *err = NULL;
>
> @@ -547,17 +588,22 @@ static void integratorcp_init(MachineState *machine)
>      for (i = 0; i < 32; i++) {
>          pic[i] = qdev_get_gpio_in(dev, i);
>      }
> -    sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]);
> +    sic = sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]);
>      sysbus_create_varargs("integrator_pit", 0x13000000,
>                            pic[5], pic[6], pic[7], NULL);
>      sysbus_create_simple("pl031", 0x15000000, pic[8]);
>      sysbus_create_simple("pl011", 0x16000000, pic[1]);
>      sysbus_create_simple("pl011", 0x17000000, pic[2]);
> -    sysbus_create_simple(TYPE_ICP_CONTROL_REGS, 0xcb000000, NULL);
> +    icp = sysbus_create_simple(TYPE_ICP_CONTROL_REGS, 0xcb000000,
> +                               qdev_get_gpio_in(sic, 3));
>      sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]);
>      sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]);
>      sysbus_create_simple(TYPE_INTEGRATOR_DEBUG, 0x1a000000, 0);
> -    sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
> +
> +    dev = sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
> +    qdev_connect_gpio_out(dev, 0, qdev_get_gpio_in(icp, ICP_GPIO_MMC_WPROT));
> +    qdev_connect_gpio_out(dev, 1, qdev_get_gpio_in(icp, 
> ICP_GPIO_MMC_CARDIN));
> +
>      if (nd_table[0].used)
>          smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
>
> --
> 2.1.4
>
>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]