xref: /qemu/hw/misc/macio/gpio.c (revision 0b8fa32f551e863bb548a11394239239270dd3dc)
17c4166a9SMark Cave-Ayland /*
27c4166a9SMark Cave-Ayland  * PowerMac NewWorld MacIO GPIO emulation
37c4166a9SMark Cave-Ayland  *
47c4166a9SMark Cave-Ayland  * Copyright (c) 2016 Benjamin Herrenschmidt
57c4166a9SMark Cave-Ayland  * Copyright (c) 2018 Mark Cave-Ayland
67c4166a9SMark Cave-Ayland  *
77c4166a9SMark Cave-Ayland  * Permission is hereby granted, free of charge, to any person obtaining a copy
87c4166a9SMark Cave-Ayland  * of this software and associated documentation files (the "Software"), to deal
97c4166a9SMark Cave-Ayland  * in the Software without restriction, including without limitation the rights
107c4166a9SMark Cave-Ayland  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
117c4166a9SMark Cave-Ayland  * copies of the Software, and to permit persons to whom the Software is
127c4166a9SMark Cave-Ayland  * furnished to do so, subject to the following conditions:
137c4166a9SMark Cave-Ayland  *
147c4166a9SMark Cave-Ayland  * The above copyright notice and this permission notice shall be included in
157c4166a9SMark Cave-Ayland  * all copies or substantial portions of the Software.
167c4166a9SMark Cave-Ayland  *
177c4166a9SMark Cave-Ayland  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
187c4166a9SMark Cave-Ayland  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197c4166a9SMark Cave-Ayland  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
207c4166a9SMark Cave-Ayland  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
217c4166a9SMark Cave-Ayland  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
227c4166a9SMark Cave-Ayland  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
237c4166a9SMark Cave-Ayland  * THE SOFTWARE.
247c4166a9SMark Cave-Ayland  */
257c4166a9SMark Cave-Ayland 
267c4166a9SMark Cave-Ayland #include "qemu/osdep.h"
277c4166a9SMark Cave-Ayland #include "hw/hw.h"
287c4166a9SMark Cave-Ayland #include "hw/ppc/mac.h"
297c4166a9SMark Cave-Ayland #include "hw/misc/macio/macio.h"
307c4166a9SMark Cave-Ayland #include "hw/misc/macio/gpio.h"
318f55ac13SMark Cave-Ayland #include "hw/nmi.h"
327c4166a9SMark Cave-Ayland #include "qemu/log.h"
33*0b8fa32fSMarkus Armbruster #include "qemu/module.h"
347c4166a9SMark Cave-Ayland #include "trace.h"
357c4166a9SMark Cave-Ayland 
367c4166a9SMark Cave-Ayland 
377c4166a9SMark Cave-Ayland void macio_set_gpio(MacIOGPIOState *s, uint32_t gpio, bool state)
387c4166a9SMark Cave-Ayland {
397c4166a9SMark Cave-Ayland     uint8_t new_reg;
407c4166a9SMark Cave-Ayland 
417c4166a9SMark Cave-Ayland     trace_macio_set_gpio(gpio, state);
427c4166a9SMark Cave-Ayland 
437c4166a9SMark Cave-Ayland     if (s->gpio_regs[gpio] & 4) {
447c4166a9SMark Cave-Ayland         qemu_log_mask(LOG_GUEST_ERROR,
457c4166a9SMark Cave-Ayland                       "GPIO: Setting GPIO %d while it's an output\n", gpio);
467c4166a9SMark Cave-Ayland     }
477c4166a9SMark Cave-Ayland 
487c4166a9SMark Cave-Ayland     new_reg = s->gpio_regs[gpio] & ~2;
497c4166a9SMark Cave-Ayland     if (state) {
507c4166a9SMark Cave-Ayland         new_reg |= 2;
517c4166a9SMark Cave-Ayland     }
527c4166a9SMark Cave-Ayland 
537c4166a9SMark Cave-Ayland     if (new_reg == s->gpio_regs[gpio]) {
547c4166a9SMark Cave-Ayland         return;
557c4166a9SMark Cave-Ayland     }
567c4166a9SMark Cave-Ayland 
577c4166a9SMark Cave-Ayland     s->gpio_regs[gpio] = new_reg;
587c4166a9SMark Cave-Ayland 
597c4166a9SMark Cave-Ayland     /* This is will work until we fix the binding between MacIO and
607c4166a9SMark Cave-Ayland      * the MPIC properly so we can route all GPIOs and avoid going
617c4166a9SMark Cave-Ayland      * via the top level platform code.
627c4166a9SMark Cave-Ayland      *
637c4166a9SMark Cave-Ayland      * Note that we probably need to get access to the MPIC config to
647c4166a9SMark Cave-Ayland      * decode polarity since qemu always use "raise" regardless.
657c4166a9SMark Cave-Ayland      *
667c4166a9SMark Cave-Ayland      * For now, we hard wire known GPIOs
677c4166a9SMark Cave-Ayland      */
687c4166a9SMark Cave-Ayland 
697c4166a9SMark Cave-Ayland     switch (gpio) {
707c4166a9SMark Cave-Ayland     case 1:
717c4166a9SMark Cave-Ayland         /* Level low */
727c4166a9SMark Cave-Ayland         if (!state) {
737c4166a9SMark Cave-Ayland             trace_macio_gpio_irq_assert(gpio);
747c4166a9SMark Cave-Ayland             qemu_irq_raise(s->gpio_extirqs[gpio]);
757c4166a9SMark Cave-Ayland         } else {
767c4166a9SMark Cave-Ayland             trace_macio_gpio_irq_deassert(gpio);
777c4166a9SMark Cave-Ayland             qemu_irq_lower(s->gpio_extirqs[gpio]);
787c4166a9SMark Cave-Ayland         }
797c4166a9SMark Cave-Ayland         break;
807c4166a9SMark Cave-Ayland 
817c4166a9SMark Cave-Ayland     case 9:
827c4166a9SMark Cave-Ayland         /* Edge, triggered by NMI below */
837c4166a9SMark Cave-Ayland         if (state) {
847c4166a9SMark Cave-Ayland             trace_macio_gpio_irq_assert(gpio);
857c4166a9SMark Cave-Ayland             qemu_irq_raise(s->gpio_extirqs[gpio]);
867c4166a9SMark Cave-Ayland         } else {
877c4166a9SMark Cave-Ayland             trace_macio_gpio_irq_deassert(gpio);
887c4166a9SMark Cave-Ayland             qemu_irq_lower(s->gpio_extirqs[gpio]);
897c4166a9SMark Cave-Ayland         }
907c4166a9SMark Cave-Ayland         break;
917c4166a9SMark Cave-Ayland 
927c4166a9SMark Cave-Ayland     default:
937c4166a9SMark Cave-Ayland         qemu_log_mask(LOG_UNIMP, "GPIO: setting unimplemented GPIO %d", gpio);
947c4166a9SMark Cave-Ayland     }
957c4166a9SMark Cave-Ayland }
967c4166a9SMark Cave-Ayland 
977c4166a9SMark Cave-Ayland static void macio_gpio_write(void *opaque, hwaddr addr, uint64_t value,
987c4166a9SMark Cave-Ayland                              unsigned size)
997c4166a9SMark Cave-Ayland {
1007c4166a9SMark Cave-Ayland     MacIOGPIOState *s = opaque;
1017c4166a9SMark Cave-Ayland     uint8_t ibit;
1027c4166a9SMark Cave-Ayland 
1037c4166a9SMark Cave-Ayland     trace_macio_gpio_write(addr, value);
1047c4166a9SMark Cave-Ayland 
1057c4166a9SMark Cave-Ayland     /* Levels regs are read-only */
1067c4166a9SMark Cave-Ayland     if (addr < 8) {
1077c4166a9SMark Cave-Ayland         return;
1087c4166a9SMark Cave-Ayland     }
1097c4166a9SMark Cave-Ayland 
1107c4166a9SMark Cave-Ayland     addr -= 8;
1117c4166a9SMark Cave-Ayland     if (addr < 36) {
1127c4166a9SMark Cave-Ayland         value &= ~2;
1137c4166a9SMark Cave-Ayland 
1147c4166a9SMark Cave-Ayland         if (value & 4) {
1157c4166a9SMark Cave-Ayland             ibit = (value & 1) << 1;
1167c4166a9SMark Cave-Ayland         } else {
1177c4166a9SMark Cave-Ayland             ibit = s->gpio_regs[addr] & 2;
1187c4166a9SMark Cave-Ayland         }
1197c4166a9SMark Cave-Ayland 
1207c4166a9SMark Cave-Ayland         s->gpio_regs[addr] = value | ibit;
1217c4166a9SMark Cave-Ayland     }
1227c4166a9SMark Cave-Ayland }
1237c4166a9SMark Cave-Ayland 
1247c4166a9SMark Cave-Ayland static uint64_t macio_gpio_read(void *opaque, hwaddr addr, unsigned size)
1257c4166a9SMark Cave-Ayland {
1267c4166a9SMark Cave-Ayland     MacIOGPIOState *s = opaque;
1277c4166a9SMark Cave-Ayland     uint64_t val = 0;
1287c4166a9SMark Cave-Ayland 
1297c4166a9SMark Cave-Ayland     /* Levels regs */
1307c4166a9SMark Cave-Ayland     if (addr < 8) {
1317c4166a9SMark Cave-Ayland         val = s->gpio_levels[addr];
1327c4166a9SMark Cave-Ayland     } else {
1337c4166a9SMark Cave-Ayland         addr -= 8;
1347c4166a9SMark Cave-Ayland 
1357c4166a9SMark Cave-Ayland         if (addr < 36) {
1367c4166a9SMark Cave-Ayland             val = s->gpio_regs[addr];
1377c4166a9SMark Cave-Ayland         }
1387c4166a9SMark Cave-Ayland     }
1397c4166a9SMark Cave-Ayland 
1407c4166a9SMark Cave-Ayland     trace_macio_gpio_write(addr, val);
1417c4166a9SMark Cave-Ayland     return val;
1427c4166a9SMark Cave-Ayland }
1437c4166a9SMark Cave-Ayland 
1447c4166a9SMark Cave-Ayland static const MemoryRegionOps macio_gpio_ops = {
1457c4166a9SMark Cave-Ayland     .read = macio_gpio_read,
1467c4166a9SMark Cave-Ayland     .write = macio_gpio_write,
1477c4166a9SMark Cave-Ayland     .endianness = DEVICE_LITTLE_ENDIAN,
1487c4166a9SMark Cave-Ayland     .impl = {
1497c4166a9SMark Cave-Ayland         .min_access_size = 1,
1507c4166a9SMark Cave-Ayland         .max_access_size = 1,
1517c4166a9SMark Cave-Ayland     },
1527c4166a9SMark Cave-Ayland };
1537c4166a9SMark Cave-Ayland 
1547c4166a9SMark Cave-Ayland static void macio_gpio_realize(DeviceState *dev, Error **errp)
1557c4166a9SMark Cave-Ayland {
1567c4166a9SMark Cave-Ayland     MacIOGPIOState *s = MACIO_GPIO(dev);
1577c4166a9SMark Cave-Ayland 
1587c4166a9SMark Cave-Ayland     s->gpio_extirqs[1] = qdev_get_gpio_in(DEVICE(s->pic),
1597c4166a9SMark Cave-Ayland                                           NEWWORLD_EXTING_GPIO1);
1607c4166a9SMark Cave-Ayland     s->gpio_extirqs[9] = qdev_get_gpio_in(DEVICE(s->pic),
1617c4166a9SMark Cave-Ayland                                           NEWWORLD_EXTING_GPIO9);
1627c4166a9SMark Cave-Ayland }
1637c4166a9SMark Cave-Ayland 
1647c4166a9SMark Cave-Ayland static void macio_gpio_init(Object *obj)
1657c4166a9SMark Cave-Ayland {
1667c4166a9SMark Cave-Ayland     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1677c4166a9SMark Cave-Ayland     MacIOGPIOState *s = MACIO_GPIO(obj);
1687c4166a9SMark Cave-Ayland 
1697c4166a9SMark Cave-Ayland     object_property_add_link(obj, "pic", TYPE_OPENPIC,
1707c4166a9SMark Cave-Ayland                              (Object **) &s->pic,
1717c4166a9SMark Cave-Ayland                              qdev_prop_allow_set_link_before_realize,
1727c4166a9SMark Cave-Ayland                              0, NULL);
1737c4166a9SMark Cave-Ayland 
1747c4166a9SMark Cave-Ayland     memory_region_init_io(&s->gpiomem, OBJECT(s), &macio_gpio_ops, obj,
1757c4166a9SMark Cave-Ayland                           "gpio", 0x30);
1767c4166a9SMark Cave-Ayland     sysbus_init_mmio(sbd, &s->gpiomem);
1777c4166a9SMark Cave-Ayland }
1787c4166a9SMark Cave-Ayland 
1797c4166a9SMark Cave-Ayland static const VMStateDescription vmstate_macio_gpio = {
1807c4166a9SMark Cave-Ayland     .name = "macio_gpio",
1817c4166a9SMark Cave-Ayland     .version_id = 0,
1827c4166a9SMark Cave-Ayland     .minimum_version_id = 0,
1837c4166a9SMark Cave-Ayland     .fields = (VMStateField[]) {
1847c4166a9SMark Cave-Ayland         VMSTATE_UINT8_ARRAY(gpio_levels, MacIOGPIOState, 8),
1857c4166a9SMark Cave-Ayland         VMSTATE_UINT8_ARRAY(gpio_regs, MacIOGPIOState, 36),
1867c4166a9SMark Cave-Ayland         VMSTATE_END_OF_LIST()
1877c4166a9SMark Cave-Ayland     }
1887c4166a9SMark Cave-Ayland };
1897c4166a9SMark Cave-Ayland 
1907c4166a9SMark Cave-Ayland static void macio_gpio_reset(DeviceState *dev)
1917c4166a9SMark Cave-Ayland {
1927c4166a9SMark Cave-Ayland     MacIOGPIOState *s = MACIO_GPIO(dev);
1937c4166a9SMark Cave-Ayland 
1947c4166a9SMark Cave-Ayland     /* GPIO 1 is up by default */
1957c4166a9SMark Cave-Ayland     macio_set_gpio(s, 1, true);
1967c4166a9SMark Cave-Ayland }
1977c4166a9SMark Cave-Ayland 
1988f55ac13SMark Cave-Ayland static void macio_gpio_nmi(NMIState *n, int cpu_index, Error **errp)
1998f55ac13SMark Cave-Ayland {
2008f55ac13SMark Cave-Ayland     macio_set_gpio(MACIO_GPIO(n), 9, true);
2018f55ac13SMark Cave-Ayland     macio_set_gpio(MACIO_GPIO(n), 9, false);
2028f55ac13SMark Cave-Ayland }
2038f55ac13SMark Cave-Ayland 
2047c4166a9SMark Cave-Ayland static void macio_gpio_class_init(ObjectClass *oc, void *data)
2057c4166a9SMark Cave-Ayland {
2067c4166a9SMark Cave-Ayland     DeviceClass *dc = DEVICE_CLASS(oc);
2078f55ac13SMark Cave-Ayland     NMIClass *nc = NMI_CLASS(oc);
2087c4166a9SMark Cave-Ayland 
2097c4166a9SMark Cave-Ayland     dc->realize = macio_gpio_realize;
2107c4166a9SMark Cave-Ayland     dc->reset = macio_gpio_reset;
2117c4166a9SMark Cave-Ayland     dc->vmsd = &vmstate_macio_gpio;
2128f55ac13SMark Cave-Ayland     nc->nmi_monitor_handler = macio_gpio_nmi;
2137c4166a9SMark Cave-Ayland }
2147c4166a9SMark Cave-Ayland 
2157c4166a9SMark Cave-Ayland static const TypeInfo macio_gpio_init_info = {
2167c4166a9SMark Cave-Ayland     .name          = TYPE_MACIO_GPIO,
2177c4166a9SMark Cave-Ayland     .parent        = TYPE_SYS_BUS_DEVICE,
2187c4166a9SMark Cave-Ayland     .instance_size = sizeof(MacIOGPIOState),
2197c4166a9SMark Cave-Ayland     .instance_init = macio_gpio_init,
2207c4166a9SMark Cave-Ayland     .class_init    = macio_gpio_class_init,
2218f55ac13SMark Cave-Ayland     .interfaces = (InterfaceInfo[]) {
2228f55ac13SMark Cave-Ayland         { TYPE_NMI },
2238f55ac13SMark Cave-Ayland         { }
2248f55ac13SMark Cave-Ayland     },
2257c4166a9SMark Cave-Ayland };
2267c4166a9SMark Cave-Ayland 
2277c4166a9SMark Cave-Ayland static void macio_gpio_register_types(void)
2287c4166a9SMark Cave-Ayland {
2297c4166a9SMark Cave-Ayland     type_register_static(&macio_gpio_init_info);
2307c4166a9SMark Cave-Ayland }
2317c4166a9SMark Cave-Ayland 
2327c4166a9SMark Cave-Ayland type_init(macio_gpio_register_types)
233