[Qemu-devel] [PATCH v4 1/2] zynq_gpio: GPIO model for Zynq SoC

2015-01-25 Thread Colin Leitner
Based on the pl061 model. This model implements all four banks with 32 I/Os
each.

The I/Os are placed in named groups:

 * bankX_in for the 32 inputs of each bank
 * bankX_out for the 32 outputs of each bank

Basic I/O and IRQ support tested with the Zynq GPIO driver in Linux 3.12.

Reviewed-by: Peter Crosthwaite 
Signed-off-by: Colin Leitner 
---
 hw/gpio/Makefile.objs   |1 +
 hw/gpio/zynq-gpio.c |  413 +++
 include/hw/gpio/zynq-gpio.h |   79 +
 3 files changed, 493 insertions(+)
 create mode 100644 hw/gpio/zynq-gpio.c
 create mode 100644 include/hw/gpio/zynq-gpio.h

diff --git a/hw/gpio/Makefile.objs b/hw/gpio/Makefile.objs
index 1abcf17..c927c66 100644
--- a/hw/gpio/Makefile.objs
+++ b/hw/gpio/Makefile.objs
@@ -5,3 +5,4 @@ common-obj-$(CONFIG_ZAURUS) += zaurus.o
 common-obj-$(CONFIG_E500) += mpc8xxx.o
 
 obj-$(CONFIG_OMAP) += omap_gpio.o
+obj-$(CONFIG_ZYNQ) += zynq-gpio.o
diff --git a/hw/gpio/zynq-gpio.c b/hw/gpio/zynq-gpio.c
new file mode 100644
index 000..c740f8f
--- /dev/null
+++ b/hw/gpio/zynq-gpio.c
@@ -0,0 +1,413 @@
+/*
+ * Zynq General Purpose IO
+ *
+ * Copyright (C) 2014 Colin Leitner 
+ *
+ * Based on the PL061 model:
+ *   Copyright (c) 2007 CodeSourcery.
+ *   Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+/*
+ * We model all banks as if they were fully populated. MIO pins are usually
+ * limited to 54 pins, but this is probably device dependent and shouldn't
+ * cause too much trouble. One noticeable difference is the reset value of
+ * INT_TYPE_1, which is 0x003f according to the TRM and 0x here.
+ *
+ * The output enable pins are not modeled.
+ */
+
+#include "hw/gpio/zynq-gpio.h"
+#include "qemu/bitops.h"
+
+#ifndef ZYNQ_GPIO_ERR_DEBUG
+#define ZYNQ_GPIO_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(lvl, fmt, args...) do {\
+if (ZYNQ_GPIO_ERR_DEBUG >= lvl) {\
+qemu_log("zynq-gpio: %s:" fmt, __func__, ## args);\
+} \
+} while (0);
+
+#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
+
+static void zynq_gpio_update_out(ZynqGPIOBank *bank)
+{
+uint32_t changed;
+uint32_t mask;
+uint32_t out;
+int i;
+
+DB_PRINT("dir = %d, data = %d\n", bank->dir, bank->out_data);
+
+/*
+ * We assume non-driven (DIRM = 0) outputs float high. On real hardware
+ * this could be different, but here we have to decide which value to set
+ * the output IRQ to if the direction register switches the I/O to an
+ * input.
+ */
+/* FIXME: This is board dependent. */
+out = (bank->out_data & bank->dir) | ~bank->dir;
+
+changed = bank->old_out_data ^ out;
+bank->old_out_data = out;
+
+for (i = 0; i < ZYNQ_GPIO_IOS_PER_BANK; i++) {
+mask = 1 << i;
+if (changed & mask) {
+DB_PRINT("Set output %d = %d\n", i, (out & mask) != 0);
+qemu_set_irq(bank->out[i], (out & mask) != 0);
+}
+}
+}
+
+static void zynq_gpio_update_in(ZynqGPIOBank *bank)
+{
+uint32_t changed;
+uint32_t mask;
+int i;
+
+changed = bank->old_in_data ^ bank->in_data;
+bank->old_in_data = bank->in_data;
+
+for (i = 0; i < ZYNQ_GPIO_IOS_PER_BANK; i++) {
+mask = 1 << i;
+if (changed & mask) {
+DB_PRINT("Changed input %d = %d\n", i, (bank->in_data & mask) != 
0);
+
+if (bank->itype & mask) {
+/* Edge interrupt */
+if (bank->iany & mask) {
+/* Any edge triggers the interrupt */
+bank->istat |= mask;
+} else {
+/* Edge is selected by INT_POLARITY */
+bank->istat |= ~(bank->in_data ^ bank->ipolarity) & mask;
+}
+}
+}
+}
+
+/* Level interrupt */
+bank->istat |= ~(bank->in_data ^ bank->ipolarity) & ~bank->itype;
+
+DB_PRINT("istat = %08X\n", bank->istat);
+}
+
+static void zynq_gpio_set_in_irq(ZynqGPIOState *s)
+{
+int b;
+uint32_t istat = 0;
+
+for (b = 0; b < ZYNQ_GPIO_BANKS; b++) {
+ZynqGPIOBank *bank = &s->banks[b];
+
+istat |= bank->istat & ~bank->imask;
+}
+
+DB_PRINT("IRQ = %d\n", istat != 0);
+
+qemu_set_irq(s->irq, istat != 0);
+}
+
+static void zynq_gpio_update(ZynqGPIOState *s)
+{
+int b;
+
+for (b = 0; b < ZYNQ_GPIO_BANKS; b++) {
+ZynqGPIOBank *bank = &s->banks[b];
+
+zynq_gpio_update_out(bank);
+zynq_gpio_update_in(bank);
+}
+
+zynq_gpio_set_in_irq(s);
+}
+
+static uint64_t zynq_gpio_read(void *opaque, hwaddr offset,
+   unsigned int size)
+{
+ZynqGPIOState *s = opaque;
+int b;
+int shift;
+ZynqGPIOBank *ban

[Qemu-devel] [PATCH v4 2/2] xilinx_zynq: Add zynq-gpio to the machine

2015-01-25 Thread Colin Leitner
Reviewed-by: Peter Crosthwaite 
Signed-off-by: Colin Leitner 
---
 hw/arm/xilinx_zynq.c |2 ++
 1 file changed, 2 insertions(+)

diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 06e6e24..6d8c0d9 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -202,6 +202,8 @@ static void zynq_init(MachineState *machine)
 zynq_init_spi_flashes(0xE0007000, pic[81-IRQ_OFFSET], false);
 zynq_init_spi_flashes(0xE000D000, pic[51-IRQ_OFFSET], true);
 
+sysbus_create_simple("zynq-gpio", 0xE000A000, pic[52-IRQ_OFFSET]);
+
 sysbus_create_simple("xlnx,ps7-usb", 0xE0002000, pic[53-IRQ_OFFSET]);
 sysbus_create_simple("xlnx,ps7-usb", 0xE0003000, pic[76-IRQ_OFFSET]);
 
-- 
1.7.10.4




[Qemu-devel] [PATCH v4 0/2] Reworked Zynq GPIO model

2015-01-25 Thread Colin Leitner
Hello everyone,

this is the fourth version of the Zynq GPIO model patch. It includes

 * removal of unneeded memset in zynq_gpio_realize
 * some minor code cleanup
 * fixes for all remaining checkpatch warnings (lines too long)

Regards,
Colin

Colin Leitner (2):
  zynq_gpio: GPIO model for Zynq SoC
  xilinx_zynq: Add zynq-gpio to the machine

 hw/arm/xilinx_zynq.c|2 +
 hw/gpio/Makefile.objs   |1 +
 hw/gpio/zynq-gpio.c |  413 +++
 include/hw/gpio/zynq-gpio.h |   79 +
 4 files changed, 495 insertions(+)
 create mode 100644 hw/gpio/zynq-gpio.c
 create mode 100644 include/hw/gpio/zynq-gpio.h

-- 
1.7.10.4




[Qemu-devel] [PATCH v3 1/2] zynq_gpio: GPIO model for Zynq SoC

2015-01-06 Thread Colin Leitner
Based on the pl061 model. This model implements all four banks with 32 I/Os
each.

The I/Os are placed in named groups:

 * bankX_in for the 32 inputs of each bank
 * bankX_out for the 32 outputs of each bank

Basic I/O and IRQ support tested with the Zynq GPIO driver in Linux 3.12.

Signed-off-by: Colin Leitner 
---
 hw/gpio/Makefile.objs   |1 +
 hw/gpio/zynq-gpio.c |  402 +++
 include/hw/gpio/zynq-gpio.h |   79 +
 3 files changed, 482 insertions(+)
 create mode 100644 hw/gpio/zynq-gpio.c
 create mode 100644 include/hw/gpio/zynq-gpio.h

diff --git a/hw/gpio/Makefile.objs b/hw/gpio/Makefile.objs
index 1abcf17..c927c66 100644
--- a/hw/gpio/Makefile.objs
+++ b/hw/gpio/Makefile.objs
@@ -5,3 +5,4 @@ common-obj-$(CONFIG_ZAURUS) += zaurus.o
 common-obj-$(CONFIG_E500) += mpc8xxx.o
 
 obj-$(CONFIG_OMAP) += omap_gpio.o
+obj-$(CONFIG_ZYNQ) += zynq-gpio.o
diff --git a/hw/gpio/zynq-gpio.c b/hw/gpio/zynq-gpio.c
new file mode 100644
index 000..8cf4262
--- /dev/null
+++ b/hw/gpio/zynq-gpio.c
@@ -0,0 +1,402 @@
+/*
+ * Zynq General Purpose IO
+ *
+ * Copyright (C) 2014 Colin Leitner 
+ *
+ * Based on the PL061 model:
+ *   Copyright (c) 2007 CodeSourcery.
+ *   Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+/*
+ * We model all banks as if they were fully populated. MIO pins are usually
+ * limited to 54 pins, but this is probably device dependent and shouldn't
+ * cause too much trouble. One noticeable difference is the reset value of
+ * INT_TYPE_1, which is 0x003f according to the TRM and 0x here.
+ *
+ * The output enable pins are not modeled.
+ */
+
+#include "hw/gpio/zynq-gpio.h"
+#include "qemu/bitops.h"
+
+#ifndef ZYNQ_GPIO_ERR_DEBUG
+#define ZYNQ_GPIO_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(lvl, fmt, args...) do {\
+if (ZYNQ_GPIO_ERR_DEBUG >= lvl) {\
+qemu_log("zynq-gpio: %s:" fmt, __func__, ## args);\
+} \
+} while (0);
+
+#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
+
+static void zynq_gpio_update_out(ZynqGPIOBank *bank)
+{
+uint32_t changed;
+uint32_t mask;
+uint32_t out;
+int i;
+
+DB_PRINT("dir = %d, data = %d\n", bank->dir, bank->out_data);
+
+/*
+ * We assume non-driven (DIRM = 0) outputs float high. On real hardware 
this
+ * could be different, but here we have to decide which value to set the
+ * output IRQ to if the direction register switches the I/O to an input.
+ */
+/* FIXME: This is board dependent. */
+out = (bank->out_data & bank->dir) | ~bank->dir;
+
+changed = bank->old_out_data ^ out;
+bank->old_out_data = out;
+
+for (i = 0; i < ZYNQ_GPIO_IOS_PER_BANK; i++) {
+mask = 1 << i;
+if (changed & mask) {
+DB_PRINT("Set output %d = %d\n", i, (out & mask) != 0);
+qemu_set_irq(bank->out[i], (out & mask) != 0);
+}
+}
+}
+
+static void zynq_gpio_update_in(ZynqGPIOBank *bank)
+{
+uint32_t changed;
+uint32_t mask;
+int i;
+
+changed = bank->old_in_data ^ bank->in_data;
+bank->old_in_data = bank->in_data;
+
+for (i = 0; i < ZYNQ_GPIO_IOS_PER_BANK; i++) {
+mask = 1 << i;
+if (changed & mask) {
+DB_PRINT("Changed input %d = %d\n", i, (bank->in_data & mask) != 
0);
+
+if (bank->itype & mask) {
+/* Edge interrupt */
+if (bank->iany & mask) {
+/* Any edge triggers the interrupt */
+bank->istat |= mask;
+} else {
+/* Edge is selected by INT_POLARITY */
+bank->istat |= ~(bank->in_data ^ bank->ipolarity) & mask;
+}
+}
+}
+}
+
+/* Level interrupt */
+bank->istat |= ~(bank->in_data ^ bank->ipolarity) & ~bank->itype;
+
+DB_PRINT("istat = %08X\n", bank->istat);
+}
+
+static void zynq_gpio_set_in_irq(ZynqGPIOState *s)
+{
+int b;
+uint32_t istat = 0;
+
+for (b = 0; b < ZYNQ_GPIO_BANKS; b++) {
+ZynqGPIOBank *bank = &s->banks[b];
+
+istat |= bank->istat & ~bank->imask;
+}
+
+DB_PRINT("IRQ = %d\n", istat != 0);
+
+qemu_set_irq(s->irq, istat != 0);
+}
+
+static void zynq_gpio_update(ZynqGPIOState *s)
+{
+int b;
+
+for (b = 0; b < ZYNQ_GPIO_BANKS; b++) {
+ZynqGPIOBank *bank = &s->banks[b];
+
+zynq_gpio_update_out(bank);
+zynq_gpio_update_in(bank);
+}
+
+zynq_gpio_set_in_irq(s);
+}
+
+static uint64_t zynq_gpio_read(void *opaque, hwaddr offset,
+   unsigned int size)
+{
+ZynqGPIOState *s = opaque;
+int b;
+int shift;
+ZynqGPIOBank *bank;
+
+switch (offset) {
+cas

[Qemu-devel] [PATCH v3 2/2] xilinx_zynq: Add zynq-gpio to the machine

2015-01-06 Thread Colin Leitner
Signed-off-by: Colin Leitner 
---
 hw/arm/xilinx_zynq.c |2 ++
 1 file changed, 2 insertions(+)

diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 06e6e24..6d8c0d9 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -202,6 +202,8 @@ static void zynq_init(MachineState *machine)
 zynq_init_spi_flashes(0xE0007000, pic[81-IRQ_OFFSET], false);
 zynq_init_spi_flashes(0xE000D000, pic[51-IRQ_OFFSET], true);
 
+sysbus_create_simple("zynq-gpio", 0xE000A000, pic[52-IRQ_OFFSET]);
+
 sysbus_create_simple("xlnx,ps7-usb", 0xE0002000, pic[53-IRQ_OFFSET]);
 sysbus_create_simple("xlnx,ps7-usb", 0xE0003000, pic[76-IRQ_OFFSET]);
 
-- 
1.7.10.4




[Qemu-devel] [PATCH v3 0/2] Reworked Zynq GPIO model

2015-01-06 Thread Colin Leitner
Hello everyone,

this is the third version of the Zynq GPIO model patch. It includes
 * mostly code cleanup (variable naming, removed unneeded casts, added some
   local vars for better readability)
 * moved zynq-gpio.h to include/hw/gpio
 * enhancement in the reset/init logic to ensure that reset sets the IRQ output
   lines to 0.

Regards,
Colin

Colin Leitner (2):
  zynq_gpio: GPIO model for Zynq SoC
  xilinx_zynq: Add zynq-gpio to the machine

 hw/arm/xilinx_zynq.c|2 +
 hw/gpio/Makefile.objs   |1 +
 hw/gpio/zynq-gpio.c |  402 +++
 include/hw/gpio/zynq-gpio.h |   79 +
 4 files changed, 484 insertions(+)
 create mode 100644 hw/gpio/zynq-gpio.c
 create mode 100644 include/hw/gpio/zynq-gpio.h

-- 
1.7.10.4




[Qemu-devel] [PATCH v2 1/2] zynq_gpio: GPIO model for Zynq SoC

2014-12-31 Thread Colin Leitner
Based on the pl061 model. This model implements all four banks with 32 I/Os
each.

The I/Os are placed in named groups:

 * bankX_in for the 32 inputs of each bank
 * bankX_out for the 32 outputs of each bank

Basic I/O and IRQ support tested with the Zynq GPIO driver in Linux 3.12.

Signed-off-by: Colin Leitner 
---
 hw/gpio/Makefile.objs |1 +
 hw/gpio/zynq-gpio.c   |  386 +
 hw/gpio/zynq-gpio.h   |   79 ++
 3 files changed, 466 insertions(+)
 create mode 100644 hw/gpio/zynq-gpio.c
 create mode 100644 hw/gpio/zynq-gpio.h

diff --git a/hw/gpio/Makefile.objs b/hw/gpio/Makefile.objs
index 1abcf17..c927c66 100644
--- a/hw/gpio/Makefile.objs
+++ b/hw/gpio/Makefile.objs
@@ -5,3 +5,4 @@ common-obj-$(CONFIG_ZAURUS) += zaurus.o
 common-obj-$(CONFIG_E500) += mpc8xxx.o
 
 obj-$(CONFIG_OMAP) += omap_gpio.o
+obj-$(CONFIG_ZYNQ) += zynq-gpio.o
diff --git a/hw/gpio/zynq-gpio.c b/hw/gpio/zynq-gpio.c
new file mode 100644
index 000..2fd1712
--- /dev/null
+++ b/hw/gpio/zynq-gpio.c
@@ -0,0 +1,386 @@
+/*
+ * Zynq General Purpose IO
+ *
+ * Copyright (C) 2014 Colin Leitner 
+ *
+ * Based on the PL061 model:
+ *   Copyright (c) 2007 CodeSourcery.
+ *   Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+/*
+ * We model all banks as if they were fully populated. MIO pins are usually
+ * limited to 54 pins, but this is probably device dependent and shouldn't
+ * cause too much trouble. One noticeable difference is the reset value of
+ * INT_TYPE_1, which is 0x003f according to the TRM and 0x here.
+ *
+ * The output enable pins are not modeled.
+ */
+
+#include "qemu/bitops.h"
+
+#include "zynq-gpio.h"
+
+#ifndef ZYNQ_GPIO_ERR_DEBUG
+#define ZYNQ_GPIO_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(lvl, fmt, args...) do {\
+if (ZYNQ_GPIO_ERR_DEBUG >= lvl) {\
+qemu_log("zynq-gpio: %s:" fmt, __func__, ## args);\
+} \
+} while (0);
+
+#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
+
+static void zynq_gpio_update_out(ZynqGPIOBank *b)
+{
+uint32_t changed;
+uint32_t mask;
+uint32_t out;
+int i;
+
+DB_PRINT("dir = %d, data = %d\n", b->dir, b->out_data);
+
+/*
+ * We assume non-driven (DIRM = 0) outputs float high. On real hardware 
this
+ * could be different, but here we have to decide which value to set the
+ * output IRQ to if the direction register switches the I/O to an input.
+ */
+/* FIXME: This is board dependent. */
+out = (b->out_data & b->dir) | ~b->dir;
+
+changed = b->old_out_data ^ out;
+b->old_out_data = out;
+
+for (i = 0; i < ZYNQ_GPIO_IOS_PER_BANK; i++) {
+mask = 1 << i;
+if (changed & mask) {
+DB_PRINT("Set output %d = %d\n", i, (out & mask) != 0);
+qemu_set_irq(b->out[i], (out & mask) != 0);
+}
+}
+}
+
+static void zynq_gpio_update_in(ZynqGPIOBank *b)
+{
+uint32_t changed;
+uint32_t mask;
+int i;
+
+changed = b->old_in_data ^ b->in_data;
+b->old_in_data = b->in_data;
+
+for (i = 0; i < ZYNQ_GPIO_IOS_PER_BANK; i++) {
+mask = 1 << i;
+if (changed & mask) {
+DB_PRINT("Changed input %d = %d\n", i, (b->in_data & mask) != 0);
+
+if (b->itype & mask) {
+/* Edge interrupt */
+if (b->iany & mask) {
+/* Any edge triggers the interrupt */
+b->istat |= mask;
+} else {
+/* Edge is selected by INT_POLARITY */
+b->istat |= ~(b->in_data ^ b->ipolarity) & mask;
+}
+}
+}
+}
+
+/* Level interrupt */
+b->istat |= ~(b->in_data ^ b->ipolarity) & ~b->itype;
+
+DB_PRINT("istat = %08X\n", b->istat);
+}
+
+static void zynq_gpio_set_in_irq(ZynqGPIOState *s)
+{
+int b;
+uint32_t istat = 0;
+
+for (b = 0; b < ZYNQ_GPIO_BANKS; b++) {
+istat |= s->banks[b].istat & ~s->banks[b].imask;
+}
+
+DB_PRINT("IRQ = %d\n", istat != 0);
+
+qemu_set_irq(s->irq, istat != 0);
+}
+
+static void zynq_gpio_update(ZynqGPIOState *s)
+{
+int b;
+
+for (b = 0; b < ZYNQ_GPIO_BANKS; b++) {
+zynq_gpio_update_out(&s->banks[b]);
+zynq_gpio_update_in(&s->banks[b]);
+}
+
+zynq_gpio_set_in_irq(s);
+}
+
+static uint64_t zynq_gpio_read(void *opaque, hwaddr offset,
+   unsigned size)
+{
+ZynqGPIOState *s = opaque;
+int b;
+int shift;
+ZynqGPIOBank *bank;
+
+switch (offset) {
+case ZYNQ_GPIO_REG_MASK_DATA_0_LSW...ZYNQ_GPIO_REG_MASK_DATA_3_MSW:
+b = extract32(offset - ZYNQ_GPIO_REG_MASK_DATA_0_LSW, 3, 2);
+shift = (offset & 0

[Qemu-devel] [PATCH v2 2/2] xilinx_zynq: Add zynq-gpio to the machine

2014-12-31 Thread Colin Leitner
Signed-off-by: Colin Leitner 
---
 hw/arm/xilinx_zynq.c |2 ++
 1 file changed, 2 insertions(+)

diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 06e6e24..6d8c0d9 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -202,6 +202,8 @@ static void zynq_init(MachineState *machine)
 zynq_init_spi_flashes(0xE0007000, pic[81-IRQ_OFFSET], false);
 zynq_init_spi_flashes(0xE000D000, pic[51-IRQ_OFFSET], true);
 
+sysbus_create_simple("zynq-gpio", 0xE000A000, pic[52-IRQ_OFFSET]);
+
 sysbus_create_simple("xlnx,ps7-usb", 0xE0002000, pic[53-IRQ_OFFSET]);
 sysbus_create_simple("xlnx,ps7-usb", 0xE0003000, pic[76-IRQ_OFFSET]);
 
-- 
1.7.10.4




[Qemu-devel] [PATCH v2 0/2] Reworked Zynq GPIO model

2014-12-31 Thread Colin Leitner
Hello everyone,

this is the second version with most of the review points addressed.

Two notable exceptions:

 * The bank registers are handled like in the original patch
 * I couldn't get rid of the intermediate set_irq callbacks because
   qdev_init_gpio_in_named won't allow me to set the opaque data to another
   value.

I retested basic I/O on different banks and IRQ handling. Both with the stock
Linux 3.12 driver.

Cheers,
    Colin

Colin Leitner (2):
  zynq_gpio: GPIO model for Zynq SoC
  xilinx_zynq: Add zynq-gpio to the machine

 hw/arm/xilinx_zynq.c  |2 +
 hw/gpio/Makefile.objs |1 +
 hw/gpio/zynq-gpio.c   |  386 +
 hw/gpio/zynq-gpio.h   |   79 ++
 4 files changed, 468 insertions(+)
 create mode 100644 hw/gpio/zynq-gpio.c
 create mode 100644 hw/gpio/zynq-gpio.h

-- 
1.7.10.4




Re: [Qemu-devel] [PATCH 1/2] zynq_gpio: GPIO model for Zynq SoC

2014-12-30 Thread Colin Leitner
Hi Peter,

thanks for the review! I'll rework the patch ASAP.

> Is it better to just model the GPIO controller as a standalone GPIO,
> and leave the mio vs emio distinction to the SoC/Board level?
> 
> This would mean the bank GPIOs are on the top level entity, and the
> core would then have no EMIO/MIO awareness. This also makes QEMU a
> little less awkward considering there is no sense of MIO and EMIO in
> QEMU to date.

The reason for chosing the MIO/EMIO names was simply for easier mapping
to real hardware where I've been usually confronted with MIO/EMIO.
Changing this to the banks makes sense of course if Xilinx choses to
reuse that IP again.

>> +/* Outputs float high.  */
>> +/* FIXME: This is board dependent.  */
> 
> How so? Looks pretty generic to me (not sure what needs fixing here).
> Are you saying that the IO width should truncate based on Zynq
> specifics?

This is a fragment from pl061. If we don't explicitly drive a output
line through the direction register, we assume it floats high. We
still have to drive the qemu IRQ line to some state.

I'll write a better comment.

>> +zynq_gpio_reset(s);
> 
> Don't reset in init fns. You shuold use a device-reset function ...

Another 1:1 copy from pl061. I'll take the time to read up how the
device model is meant to be implemented correctly.

Thanks again for the review and you'll hear from me shortly.

Regards,
Colin



[Qemu-devel] [PATCH 1/2] zynq_gpio: GPIO model for Zynq SoC

2014-12-30 Thread Colin Leitner
Based on the pl061 model. This model implements all four banks with 32 I/Os
each.

The I/Os are placed in four named groups:

 * mio_in/out[0..63], where mio_in/out[0..31] map to bank 0 and the rest to
   bank 1
 * emio_in/out[0..63], where emio_in/out[0..31] map to bank 2 and the rest to
   bank 3

Basic I/O tested with the Zynq GPIO driver in Linux 3.12.

Signed-off-by: Colin Leitner 
---
 hw/gpio/Makefile.objs |1 +
 hw/gpio/zynq_gpio.c   |  441 +
 2 files changed, 442 insertions(+)
 create mode 100644 hw/gpio/zynq_gpio.c

diff --git a/hw/gpio/Makefile.objs b/hw/gpio/Makefile.objs
index 1abcf17..32b99e0 100644
--- a/hw/gpio/Makefile.objs
+++ b/hw/gpio/Makefile.objs
@@ -5,3 +5,4 @@ common-obj-$(CONFIG_ZAURUS) += zaurus.o
 common-obj-$(CONFIG_E500) += mpc8xxx.o
 
 obj-$(CONFIG_OMAP) += omap_gpio.o
+obj-$(CONFIG_ZYNQ) += zynq_gpio.o
diff --git a/hw/gpio/zynq_gpio.c b/hw/gpio/zynq_gpio.c
new file mode 100644
index 000..2119561
--- /dev/null
+++ b/hw/gpio/zynq_gpio.c
@@ -0,0 +1,441 @@
+/*
+ * Zynq General Purpose IO
+ *
+ * Copyright (C) 2014 Colin Leitner 
+ *
+ * Based on the PL061 model:
+ *   Copyright (c) 2007 CodeSourcery.
+ *   Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+/*
+ * We model all banks as if they were fully populated. MIO pins are usually
+ * limited to 54 pins, but this is probably device dependent and shouldn't
+ * cause too much trouble. One noticable difference is the reset value of
+ * INT_TYPE_1, which is 0x003f according to the TRM and 0x here.
+ *
+ * The output enable pins are not modeled.
+ */
+
+#include "hw/sysbus.h"
+
+//#define DEBUG_ZYNQ_GPIO 1
+
+#ifdef DEBUG_ZYNQ_GPIO
+#define DPRINTF(fmt, ...) \
+do { printf("zynq-gpio: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "zynq-gpio: error: " fmt , ## __VA_ARGS__); exit(1);} 
while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "zynq-gpio: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+#define TYPE_ZYNQ_GPIO "zynq-gpio"
+#define ZYNQ_GPIO(obj) OBJECT_CHECK(ZynqGPIOState, (obj), TYPE_ZYNQ_GPIO)
+
+typedef struct {
+uint32_t mask_data;
+uint32_t out_data;
+uint32_t old_out_data;
+uint32_t in_data;
+uint32_t old_in_data;
+uint32_t dir;
+uint32_t oen;
+uint32_t imask;
+uint32_t istat;
+uint32_t itype;
+uint32_t ipolarity;
+uint32_t iany;
+
+qemu_irq *out;
+} GPIOBank;
+
+typedef struct ZynqGPIOState {
+SysBusDevice parent_obj;
+
+MemoryRegion iomem;
+GPIOBank banks[4];
+qemu_irq mio_out[64];
+qemu_irq emio_out[64];
+qemu_irq irq;
+} ZynqGPIOState;
+
+static void zynq_gpio_update_out(GPIOBank *b)
+{
+uint32_t changed;
+uint32_t mask;
+uint32_t out;
+int i;
+
+DPRINTF("dir = %d, data = %d\n", b->dir, b->out_data);
+
+/* Outputs float high.  */
+/* FIXME: This is board dependent.  */
+out = (b->out_data & b->dir) | ~b->dir;
+changed = b->old_out_data ^ out;
+if (changed) {
+b->old_out_data = out;
+for (i = 0; i < 32; i++) {
+mask = 1 << i;
+if (changed & mask) {
+DPRINTF("Set output %d = %d\n", i, (out & mask) != 0);
+qemu_set_irq(b->out[i], (out & mask) != 0);
+}
+}
+}
+}
+
+static void zynq_gpio_update_in(GPIOBank *b)
+{
+uint32_t changed;
+uint32_t mask;
+int i;
+
+changed = b->old_in_data ^ b->in_data;
+if (changed) {
+b->old_in_data = b->in_data;
+for (i = 0; i < 32; i++) {
+mask = 1 << i;
+if (changed & mask) {
+DPRINTF("Changed input %d = %d\n", i, (b->in_data & mask) != 
0);
+
+if (b->itype & mask) {
+/* Edge interrupt */
+if (b->iany & mask) {
+/* Any edge triggers the interrupt */
+b->istat |= mask;
+} else {
+/* Edge is selected by INT_POLARITY */
+b->istat |= ~(b->in_data ^ b->ipolarity) & mask;
+}
+}
+}
+}
+}
+
+/* Level interrupt */
+b->istat |= ~(b->in_data ^ b->ipolarity) & ~b->itype;
+
+DPRINTF("istat = %08X\n", b->istat);
+}
+
+static void zynq_gpio_set_in_irq(ZynqGPIOState *s)
+{
+int b;
+uint32_t istat = 0;
+
+for (b = 0; b < 4; b++) {
+istat |= s->banks[b].istat & ~s->banks[b].imask;
+}
+
+DPRINTF("IRQ = %d\n", istat != 0);
+
+qemu_set_irq(s->irq, istat != 0);
+}
+
+static void zynq_gpio_update(ZynqGPI

[Qemu-devel] [PATCH 0/2] GPIO model for Zynq SoC

2014-12-30 Thread Colin Leitner
Hello everyone,

I wrote the Zynq GPIO model a while ago and it proved useful in an internal
project, so maybe others will find it useful too.

Cheers,
Colin

Colin Leitner (2):
  zynq_gpio: GPIO model for Zynq SoC
  xilinx_zynq: Add zynq_gpio to the machine

 hw/arm/xilinx_zynq.c  |2 +
 hw/gpio/Makefile.objs |1 +
 hw/gpio/zynq_gpio.c   |  441 +
 3 files changed, 444 insertions(+)
 create mode 100644 hw/gpio/zynq_gpio.c

-- 
1.7.10.4




[Qemu-devel] [PATCH 2/2] xilinx_zynq: Add zynq_gpio to the machine

2014-12-30 Thread Colin Leitner
Signed-off-by: Colin Leitner 
---
 hw/arm/xilinx_zynq.c |2 ++
 1 file changed, 2 insertions(+)

diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 06e6e24..6d8c0d9 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -202,6 +202,8 @@ static void zynq_init(MachineState *machine)
 zynq_init_spi_flashes(0xE0007000, pic[81-IRQ_OFFSET], false);
 zynq_init_spi_flashes(0xE000D000, pic[51-IRQ_OFFSET], true);
 
+sysbus_create_simple("zynq-gpio", 0xE000A000, pic[52-IRQ_OFFSET]);
+
 sysbus_create_simple("xlnx,ps7-usb", 0xE0002000, pic[53-IRQ_OFFSET]);
 sysbus_create_simple("xlnx,ps7-usb", 0xE0003000, pic[76-IRQ_OFFSET]);
 
-- 
1.7.10.4




[Qemu-devel] [PATCH] pl061: implement input interrupt logic

2014-08-31 Thread Colin Leitner
This patch adds the missing input interrupt logic to the pl061 GPIO device. To
keep the floating output pins to stay high, the old state variable had to be
split into two separate ones for input and output - which brings the vmstate
version to 3.

Edge level interrupts and I/O were tested under Linux 3.14. Level interrupt
handling hasn't been tested.

Signed-off-by: Colin Leitner 
---
 hw/gpio/pl061.c |   59 ++-
 1 file changed, 45 insertions(+), 14 deletions(-)

diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
index dd4ea29..bd03e99 100644
--- a/hw/gpio/pl061.c
+++ b/hw/gpio/pl061.c
@@ -37,7 +37,8 @@ typedef struct PL061State {
 MemoryRegion iomem;
 uint32_t locked;
 uint32_t data;
-uint32_t old_data;
+uint32_t old_out_data;
+uint32_t old_in_data;
 uint32_t dir;
 uint32_t isense;
 uint32_t ibe;
@@ -63,12 +64,13 @@ typedef struct PL061State {

 static const VMStateDescription vmstate_pl061 = {
 .name = "pl061",
-.version_id = 2,
-.minimum_version_id = 1,
+.version_id = 3,
+.minimum_version_id = 3,
 .fields = (VMStateField[]) {
 VMSTATE_UINT32(locked, PL061State),
 VMSTATE_UINT32(data, PL061State),
-VMSTATE_UINT32(old_data, PL061State),
+VMSTATE_UINT32(old_out_data, PL061State),
+VMSTATE_UINT32(old_in_data, PL061State),
 VMSTATE_UINT32(dir, PL061State),
 VMSTATE_UINT32(isense, PL061State),
 VMSTATE_UINT32(ibe, PL061State),
@@ -98,23 +100,52 @@ static void pl061_update(PL061State *s)
 uint8_t out;
 int i;

+DPRINTF("dir = %d, data = %d\n", s->dir, s->data);
+
 /* Outputs float high.  */
 /* FIXME: This is board dependent.  */
 out = (s->data & s->dir) | ~s->dir;
-changed = s->old_data ^ out;
-if (!changed)
-return;
+changed = s->old_out_data ^ out;
+if (changed) {
+s->old_out_data = out;
+for (i = 0; i < 8; i++) {
+mask = 1 << i;
+if (changed & mask) {
+DPRINTF("Set output %d = %d\n", i, (out & mask) != 0);
+qemu_set_irq(s->out[i], (out & mask) != 0);
+}
+}
+}

-s->old_data = out;
-for (i = 0; i < 8; i++) {
-mask = 1 << i;
-if (changed & mask) {
-DPRINTF("Set output %d = %d\n", i, (out & mask) != 0);
-qemu_set_irq(s->out[i], (out & mask) != 0);
+/* Inputs */
+changed = (s->old_in_data ^ s->data) & ~s->dir;
+if (changed) {
+s->old_in_data = s->data;
+for (i = 0; i < 8; i++) {
+mask = 1 << i;
+if (changed & mask) {
+DPRINTF("Changed input %d = %d\n", i, (s->data & mask) != 0);
+
+if (!(s->isense & mask)) {
+/* Edge interrupt */
+if (s->ibe & mask) {
+/* Any edge triggers the interrupt */
+s->istate |= mask;
+} else {
+/* Edge is selected by IEV */
+s->istate |= ~(s->data ^ s->iev) & mask;
+}
+}
+}
 }
 }

-/* FIXME: Implement input interrupts.  */
+/* Level interrupt */
+s->istate |= ~(s->data ^ s->iev) & s->isense;
+
+DPRINTF("istate = %02X\n", s->istate);
+
+qemu_set_irq(s->irq, (s->istate & s->im) != 0);
 }

 static uint64_t pl061_read(void *opaque, hwaddr offset,
-- 
1.7.10.4