From: Michel Pollet <buserror@gmail.com>
To: qemu-devel@nongnu.org
Cc: Michel Pollet <buserror@gmail.com>
Subject: [Qemu-devel] [PATCH 07/13] mxs/imx23: Implements the pin mux, GPIOs
Date: Wed, 11 Dec 2013 13:56:26 +0000 [thread overview]
Message-ID: <1386770192-19585-8-git-send-email-buserror@gmail.com> (raw)
In-Reply-To: <1386770192-19585-1-git-send-email-buserror@gmail.com>
Implements the pinctrl and GPIO block for the imx23
It handles GPIO output, and GPIO input from qemu translated
into pin values and interrupts, if appropriate.
Signed-off-by: Michel Pollet <buserror@gmail.com>
---
hw/arm/Makefile.objs | 2 +-
hw/arm/imx23_pinctrl.c | 293 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 294 insertions(+), 1 deletion(-)
create mode 100644 hw/arm/imx23_pinctrl.c
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 9adcb96..ea53988 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -5,4 +5,4 @@ obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
obj-y += omap1.o omap2.o strongarm.o
-obj-$(CONFIG_MXS) += imx23_digctl.o
+obj-$(CONFIG_MXS) += imx23_digctl.o imx23_pinctrl.o
diff --git a/hw/arm/imx23_pinctrl.c b/hw/arm/imx23_pinctrl.c
new file mode 100644
index 0000000..ecfb755
--- /dev/null
+++ b/hw/arm/imx23_pinctrl.c
@@ -0,0 +1,293 @@
+/*
+ * imx23_pinctrl.c
+ *
+ * Copyright: Michel Pollet <buserror@gmail.com>
+ *
+ * QEMU Licence
+ */
+
+/*
+ * Implements the pinctrl and GPIO block for the imx23
+ * It handles GPIO output, and GPIO input from qemu translated
+ * into pin values and interrupts, if appropriate.
+ */
+#include "hw/sysbus.h"
+#include "hw/arm/mxs.h"
+
+#define D(w)
+
+enum {
+ PINCTRL_BANK_COUNT = 3,
+
+ PINCTRL_CTRL = 0,
+ PINCTRL_BANK_MUXSEL = 0x10,
+ PINCTRL_BANK_BASE = 0x40,
+
+ /* these are not << 4 register numbers, these are << 8 register numbers */
+ PINCTRL_BANK_PULL = 0x4,
+ PINCTRL_BANK_OUT = 0x5,
+ PINCTRL_BANK_DIN = 0x6,
+ PINCTRL_BANK_DOE = 0x7,
+ PINCTRL_BANK_PIN2IRQ = 0x8,
+ PINCTRL_BANK_IRQEN = 0x9,
+ PINCTRL_BANK_IRQLEVEL = 0xa,
+ PINCTRL_BANK_IRQPOL = 0xb,
+ PINCTRL_BANK_IRQSTAT = 0xc,
+
+ PINCTRL_BANK_INTERNAL_STATE = 0xd,
+ PINCTRL_MAX = 0xe0,
+};
+
+#define PINCTRL_BANK_REG(_bank, _reg) ((_reg << 8) | (_bank << 4))
+
+enum {
+ MUX_GPIO = 0x3,
+};
+
+
+typedef struct imx23_pinctrl_state {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+
+ uint32_t r[PINCTRL_MAX];
+ qemu_irq irq_in[3];
+ qemu_irq irq_out[PINCTRL_BANK_COUNT * 32];
+
+ uint32_t state[PINCTRL_BANK_COUNT];
+} imx23_pinctrl_state;
+
+static uint64_t imx23_pinctrl_read(
+ void *opaque, hwaddr offset, unsigned size)
+{
+ imx23_pinctrl_state *s = (imx23_pinctrl_state *) opaque;
+ uint32_t res = 0;
+
+ switch (offset >> 4) {
+ case 0 ... PINCTRL_MAX:
+ res = s->r[offset >> 4];
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad offset 0x%x\n", __func__, (int) offset);
+ break;
+ }
+
+ return res;
+}
+
+static uint8_t imx23_pinctrl_getmux(
+ imx23_pinctrl_state *s, int pin)
+{
+ int base = pin / 16, offset = pin % 16;
+ return (s->r[PINCTRL_BANK_MUXSEL + base] >> (offset * 2)) & 0x3;
+}
+
+/*
+ * usage imx23_pinctrl_getbit(s, PINCTRL_BANK_IRQEN, 48)...
+ */
+static uint8_t imx23_pinctrl_getbit(
+ imx23_pinctrl_state *s, uint16_t reg, int pin)
+{
+ int bank = pin / 32, offset = pin % 32;
+ uint32_t * latch = &s->r[PINCTRL_BANK_REG(bank, reg) >> 4];
+// printf("%s bank %d offset %d reg %d : %04x=%08x\n", __func__, bank, offset, reg,
+// PINCTRL_BANK_REG(bank, reg),
+// *latch);
+ return (*latch >> offset) & 0x1;
+}
+
+static void imx23_pinctrl_setbit(
+ imx23_pinctrl_state *s, uint16_t reg, int pin, int value)
+{
+ int bank = pin / 32, offset = pin % 32;
+ uint32_t * latch = &s->r[PINCTRL_BANK_REG(bank, reg) >> 4];
+ *latch = (*latch & ~(1 << offset)) | (!!value << offset);
+}
+
+static void imx23_pinctrl_write_bank(
+ imx23_pinctrl_state *s, int bank,
+ int reg, uint32_t value,
+ uint32_t mask)
+{
+ int set, pin;
+ switch (reg) {
+ /*
+ * Linux has a way of using the DOE&PULL register to toggle the pin
+ */
+ case PINCTRL_BANK_PULL:
+ case PINCTRL_BANK_DOE:
+ /*
+ * Writing to the Data OUT register just triggers the
+ * output qemu IRQ for any further peripherals
+ */
+ case PINCTRL_BANK_OUT: {
+ while ((set = ffs(mask)) > 0) {
+ set--;
+ mask &= ~(1 << set);
+ pin = (bank * 32) + set;
+ /*
+ * For a reason that is not clear, the pullup bit appears
+ * inverted (!) ignoring for now, assume hardware pullup
+ */
+ // imx23_pinctrl_getbit(s, PINCTRL_BANK_PULL, pin)
+ int val =
+ imx23_pinctrl_getbit(s, PINCTRL_BANK_DOE, pin) ?
+ imx23_pinctrl_getbit(s, PINCTRL_BANK_OUT, pin) :
+ 1;
+ D(printf("%s set %2d to OUT:%d DOE:%d (PULL:%d) = %d\n", __func__,
+ pin,
+ imx23_pinctrl_getbit(s, PINCTRL_BANK_OUT, pin),
+ imx23_pinctrl_getbit(s, PINCTRL_BANK_DOE, pin),
+ imx23_pinctrl_getbit(s, PINCTRL_BANK_PULL, pin),
+ val);)
+
+ if (imx23_pinctrl_getbit(s, PINCTRL_BANK_INTERNAL_STATE, pin) != val) {
+ qemu_set_irq(s->irq_out[pin], val);
+ imx23_pinctrl_setbit(s, PINCTRL_BANK_INTERNAL_STATE, pin, val);
+ }
+ }
+ } break;
+ /*
+ * This happends when we receive a qemu IRQ on the input ones,
+ * the register gets updated by the code executed until now,
+ * and all we need to do here is to trigger the imx233 IRQ
+ * if appropriate.
+ * Doing a write to these registers from guest code will acts as
+ * a software interrupt, not entirely sure this is appropriate
+ */
+ case PINCTRL_BANK_DIN: {
+ while ((set = ffs(mask)) > 0) {
+ set--;
+ mask &= ~(1 << set);
+ pin = (bank * 32) + set;
+ D(printf("%s input %2d set to %d\n", __func__,
+ pin, !!(value & (1 << set)));)
+ // its it a GPIO ?
+ if (imx23_pinctrl_getmux(s, pin) != MUX_GPIO) {
+ break;
+ }
+ // if the new value matches the polarity bit, it's the
+ // edge the guy wanted.
+ int valid_irq = ((value >> set) & 1) ==
+ imx23_pinctrl_getbit(s, PINCTRL_BANK_IRQPOL, pin);
+ if (valid_irq) {
+ if (imx23_pinctrl_getbit(s, PINCTRL_BANK_PIN2IRQ, pin)) {
+ imx23_pinctrl_setbit(s, PINCTRL_BANK_IRQSTAT, pin, 1);
+ }
+ // is the interrupt enabled?
+ if (imx23_pinctrl_getbit(s, PINCTRL_BANK_IRQEN, pin)) {
+ qemu_irq_raise(s->irq_in[bank]);
+ }
+ }
+ }
+ } break;
+ }
+}
+
+static void imx23_pinctrl_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ imx23_pinctrl_state *s = (imx23_pinctrl_state *) opaque;
+ uint32_t oldvalue = 0;
+
+// printf("%s offset %04x value %08x\n", __func__, (int)offset, (int)value);
+ switch (offset >> 4) {
+ case 0 ... PINCTRL_MAX:
+ oldvalue = mxs_write(&s->r[offset >> 4], offset, value, size);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad offset 0x%x\n", __func__, (int) offset);
+ break;
+ }
+ switch (offset >> 4) {
+ case PINCTRL_CTRL:
+ if ((oldvalue ^ s->r[PINCTRL_CTRL]) == 0x80000000
+ && !(oldvalue & 0x80000000)) {
+ // printf("%s reseting, anding clockgate\n", __func__);
+ s->r[PINCTRL_CTRL] |= 0x40000000;
+ }
+ break;
+ case PINCTRL_BANK_BASE ... PINCTRL_MAX: {
+ int bank = (offset >> 4) & 0xf;
+ int reg = (offset >> 8);
+ uint32_t mask = oldvalue ^ s->r[offset >> 4];
+ // printf("%s b %d r %x input %08x mask %08x value %08x\n",
+ // __func__, bank, reg, (int)value, mask, s->r[offset >> 4]);
+ imx23_pinctrl_write_bank(s, bank, reg,
+ s->r[offset >> 4], mask);
+ } break;
+ }
+}
+
+/*
+ * This will interfaces qemu other components back to the guest input pins
+ */
+static void imx23_pinctrl_set_irq(void *opaque, int irq, int level)
+{
+ // simulate a write to the data IN address
+ int bank = irq / 32;
+ hwaddr offset =
+ PINCTRL_BANK_REG(bank, PINCTRL_BANK_DIN);
+ uint64_t value = (1 << (irq % 32));
+ D(printf("%s %d = %d\n", __func__, irq, level);)
+ imx23_pinctrl_write(opaque,
+ offset + (level ? 0x4 : 0x8),
+ value, 4);
+}
+
+static const MemoryRegionOps imx23_pinctrl_ops = {
+ .read = imx23_pinctrl_read,
+ .write = imx23_pinctrl_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int imx23_pinctrl_init(SysBusDevice *dev)
+{
+ imx23_pinctrl_state *s = OBJECT_CHECK(imx23_pinctrl_state, dev, "imx23_pinctrl");
+ int i;
+ DeviceState *qdev = DEVICE(dev);
+
+ // NEEDED for qdev_find_recursive to work
+ qdev->id = "imx23_pinctrl";
+ qdev_init_gpio_in(qdev, imx23_pinctrl_set_irq, 32 * PINCTRL_BANK_COUNT);
+ qdev_init_gpio_out(qdev, s->irq_out, ARRAY_SIZE(s->irq_out));
+ memory_region_init_io(&s->iomem, OBJECT(s), &imx23_pinctrl_ops, s,
+ "imx23_pinctrl", 0x2000);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ for (i = 0; i < PINCTRL_BANK_COUNT; i++) {
+ sysbus_init_irq(dev, &s->irq_in[i]);
+ s->r[PINCTRL_BANK_REG(i, PINCTRL_BANK_DIN) >> 4] = 0;
+ s->r[PINCTRL_BANK_REG(i, PINCTRL_BANK_PULL) >> 4] = 0xffffffff;
+ }
+ /* set default mux values */
+ for (i = 0; i < 8; i++)
+ s->r[(0x100 >> 4) + i] = 0x33333333;
+
+ s->r[PINCTRL_CTRL] = 0xcf000000;
+
+ return 0;
+}
+
+
+static void imx23_pinctrl_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = imx23_pinctrl_init;
+}
+
+static TypeInfo pinctrl_info = {
+ .name = "imx23_pinctrl",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(imx23_pinctrl_state),
+ .class_init = imx23_pinctrl_class_init,
+};
+
+static void imx23_pinctrl_register(void)
+{
+ type_register_static(&pinctrl_info);
+}
+
+type_init(imx23_pinctrl_register)
--
1.8.5.1
next prev parent reply other threads:[~2013-12-11 13:49 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-12-11 13:56 [Qemu-devel] [PATCH 00/13] Freescale mxs/imx23 + Olimex Olinuxino support Michel Pollet
2013-12-11 13:56 ` [Qemu-devel] [PATCH 01/13] mxs/imx23: Add main header file Michel Pollet
2013-12-11 13:56 ` [Qemu-devel] [PATCH 02/13] mxs: Add CONFIG_MXS to the arm-softmmu config Michel Pollet
2014-01-06 15:08 ` Peter Maydell
2013-12-11 13:56 ` [Qemu-devel] [PATCH 03/13] mxs/imx23: Add uart driver Michel Pollet
2014-01-06 15:19 ` Peter Maydell
2014-01-11 7:39 ` Peter Crosthwaite
2013-12-11 13:56 ` [Qemu-devel] [PATCH 04/13] mxs/imx23: Add DMA driver Michel Pollet
2014-01-06 15:35 ` Peter Maydell
2014-01-10 0:52 ` Peter Crosthwaite
2014-01-10 0:54 ` Peter Crosthwaite
2014-01-10 10:55 ` Peter Maydell
2013-12-11 13:56 ` [Qemu-devel] [PATCH 05/13] mxs/imx23: Add the interrupt collector Michel Pollet
2014-01-06 15:41 ` Peter Maydell
2014-01-11 8:29 ` Peter Crosthwaite
2013-12-11 13:56 ` [Qemu-devel] [PATCH 06/13] mxs/imx23: Add digctl driver Michel Pollet
2014-01-06 15:46 ` Peter Maydell
2014-01-08 18:39 ` M P
2014-01-08 18:55 ` Peter Maydell
2014-01-11 8:44 ` Peter Crosthwaite
2014-01-11 8:39 ` Peter Crosthwaite
2013-12-11 13:56 ` Michel Pollet [this message]
2014-01-06 15:52 ` [Qemu-devel] [PATCH 07/13] mxs/imx23: Implements the pin mux, GPIOs Peter Maydell
2014-01-08 18:16 ` M P
2013-12-11 13:56 ` [Qemu-devel] [PATCH 08/13] mxs/imx23: Add SSP/SPI driver Michel Pollet
2014-01-11 9:08 ` Peter Crosthwaite
2013-12-11 13:56 ` [Qemu-devel] [PATCH 09/13] mxs/imx23: Add the RTC block Michel Pollet
2014-01-11 9:16 ` Peter Crosthwaite
2013-12-11 13:56 ` [Qemu-devel] [PATCH 10/13] mxs/imx23: Add the timers Michel Pollet
2013-12-11 13:56 ` [Qemu-devel] [PATCH 11/13] mxs/imx23: Add the USB driver Michel Pollet
2014-01-11 9:57 ` Peter Crosthwaite
2013-12-11 13:56 ` [Qemu-devel] [PATCH 12/13] mxs/imx23: Main core instantiation and minor IO blocks Michel Pollet
2013-12-11 13:56 ` [Qemu-devel] [PATCH 13/13] mxs/imx23: Adds support for an Olinuxino board Michel Pollet
2013-12-13 12:53 ` [Qemu-devel] [PATCH 00/13] Freescale mxs/imx23 + Olimex Olinuxino support M P
2013-12-13 13:29 ` Peter Maydell
2013-12-13 13:45 ` M P
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1386770192-19585-8-git-send-email-buserror@gmail.com \
--to=buserror@gmail.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.