 e3d0814368
			
		
	
	
		e3d0814368
		
	
	
	
	
		
			
			Use device_class_set_legacy_reset() instead of opencoding an
assignment to DeviceClass::reset. This change was produced
with:
 spatch --macro-file scripts/cocci-macro-file.h \
    --sp-file scripts/coccinelle/device-reset.cocci \
    --keep-comments --smpl-spacing --in-place --dir hw
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20240830145812.1967042-8-peter.maydell@linaro.org
		
	
			
		
			
				
	
	
		
			220 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			220 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * PowerMac NewWorld MacIO GPIO emulation
 | |
|  *
 | |
|  * Copyright (c) 2016 Benjamin Herrenschmidt
 | |
|  * Copyright (c) 2018 Mark Cave-Ayland
 | |
|  *
 | |
|  * Permission is hereby granted, free of charge, to any person obtaining a copy
 | |
|  * of this software and associated documentation files (the "Software"), to deal
 | |
|  * in the Software without restriction, including without limitation the rights
 | |
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | |
|  * copies of the Software, and to permit persons to whom the Software is
 | |
|  * furnished to do so, subject to the following conditions:
 | |
|  *
 | |
|  * The above copyright notice and this permission notice shall be included in
 | |
|  * all copies or substantial portions of the Software.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | |
|  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | |
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | |
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | |
|  * THE SOFTWARE.
 | |
|  */
 | |
| 
 | |
| #include "qemu/osdep.h"
 | |
| #include "hw/qdev-properties.h"
 | |
| #include "migration/vmstate.h"
 | |
| #include "hw/misc/macio/macio.h"
 | |
| #include "hw/misc/macio/gpio.h"
 | |
| #include "hw/irq.h"
 | |
| #include "hw/nmi.h"
 | |
| #include "qemu/log.h"
 | |
| #include "qemu/module.h"
 | |
| #include "trace.h"
 | |
| 
 | |
| 
 | |
| void macio_set_gpio(MacIOGPIOState *s, uint32_t gpio, bool state)
 | |
| {
 | |
|     uint8_t new_reg;
 | |
| 
 | |
|     trace_macio_set_gpio(gpio, state);
 | |
| 
 | |
|     if (s->gpio_regs[gpio] & 4) {
 | |
|         qemu_log_mask(LOG_GUEST_ERROR,
 | |
|                       "GPIO: Setting GPIO %d while it's an output\n", gpio);
 | |
|     }
 | |
| 
 | |
|     new_reg = s->gpio_regs[gpio] & ~2;
 | |
|     if (state) {
 | |
|         new_reg |= 2;
 | |
|     }
 | |
| 
 | |
|     if (new_reg == s->gpio_regs[gpio]) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     s->gpio_regs[gpio] = new_reg;
 | |
| 
 | |
|     /*
 | |
|      * Note that we probably need to get access to the MPIC config to
 | |
|      * decode polarity since qemu always use "raise" regardless.
 | |
|      *
 | |
|      * For now, we hard wire known GPIOs
 | |
|      */
 | |
| 
 | |
|     switch (gpio) {
 | |
|     case 1:
 | |
|         /* Level low */
 | |
|         if (!state) {
 | |
|             trace_macio_gpio_irq_assert(gpio);
 | |
|             qemu_irq_raise(s->gpio_extirqs[gpio]);
 | |
|         } else {
 | |
|             trace_macio_gpio_irq_deassert(gpio);
 | |
|             qemu_irq_lower(s->gpio_extirqs[gpio]);
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|     case 9:
 | |
|         /* Edge, triggered by NMI below */
 | |
|         if (state) {
 | |
|             trace_macio_gpio_irq_assert(gpio);
 | |
|             qemu_irq_raise(s->gpio_extirqs[gpio]);
 | |
|         } else {
 | |
|             trace_macio_gpio_irq_deassert(gpio);
 | |
|             qemu_irq_lower(s->gpio_extirqs[gpio]);
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|     default:
 | |
|         qemu_log_mask(LOG_UNIMP, "GPIO: setting unimplemented GPIO %d", gpio);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void macio_gpio_write(void *opaque, hwaddr addr, uint64_t value,
 | |
|                              unsigned size)
 | |
| {
 | |
|     MacIOGPIOState *s = opaque;
 | |
|     uint8_t ibit;
 | |
| 
 | |
|     trace_macio_gpio_write(addr, value);
 | |
| 
 | |
|     /* Levels regs are read-only */
 | |
|     if (addr < 8) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     addr -= 8;
 | |
|     if (addr < 36) {
 | |
|         value &= ~2;
 | |
| 
 | |
|         if (value & 4) {
 | |
|             ibit = (value & 1) << 1;
 | |
|         } else {
 | |
|             ibit = s->gpio_regs[addr] & 2;
 | |
|         }
 | |
| 
 | |
|         s->gpio_regs[addr] = value | ibit;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static uint64_t macio_gpio_read(void *opaque, hwaddr addr, unsigned size)
 | |
| {
 | |
|     MacIOGPIOState *s = opaque;
 | |
|     uint64_t val = 0;
 | |
| 
 | |
|     /* Levels regs */
 | |
|     if (addr < 8) {
 | |
|         val = s->gpio_levels[addr];
 | |
|     } else {
 | |
|         addr -= 8;
 | |
| 
 | |
|         if (addr < 36) {
 | |
|             val = s->gpio_regs[addr];
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     trace_macio_gpio_write(addr, val);
 | |
|     return val;
 | |
| }
 | |
| 
 | |
| static const MemoryRegionOps macio_gpio_ops = {
 | |
|     .read = macio_gpio_read,
 | |
|     .write = macio_gpio_write,
 | |
|     .endianness = DEVICE_LITTLE_ENDIAN,
 | |
|     .impl = {
 | |
|         .min_access_size = 1,
 | |
|         .max_access_size = 1,
 | |
|     },
 | |
| };
 | |
| 
 | |
| static void macio_gpio_init(Object *obj)
 | |
| {
 | |
|     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 | |
|     MacIOGPIOState *s = MACIO_GPIO(obj);
 | |
|     int i;
 | |
| 
 | |
|     for (i = 0; i < 10; i++) {
 | |
|         sysbus_init_irq(sbd, &s->gpio_extirqs[i]);
 | |
|     }
 | |
| 
 | |
|     memory_region_init_io(&s->gpiomem, OBJECT(s), &macio_gpio_ops, obj,
 | |
|                           "gpio", 0x30);
 | |
|     sysbus_init_mmio(sbd, &s->gpiomem);
 | |
| }
 | |
| 
 | |
| static const VMStateDescription vmstate_macio_gpio = {
 | |
|     .name = "macio_gpio",
 | |
|     .version_id = 0,
 | |
|     .minimum_version_id = 0,
 | |
|     .fields = (const VMStateField[]) {
 | |
|         VMSTATE_UINT8_ARRAY(gpio_levels, MacIOGPIOState, 8),
 | |
|         VMSTATE_UINT8_ARRAY(gpio_regs, MacIOGPIOState, 36),
 | |
|         VMSTATE_END_OF_LIST()
 | |
|     }
 | |
| };
 | |
| 
 | |
| static void macio_gpio_reset(DeviceState *dev)
 | |
| {
 | |
|     MacIOGPIOState *s = MACIO_GPIO(dev);
 | |
| 
 | |
|     /* GPIO 1 is up by default */
 | |
|     macio_set_gpio(s, 1, true);
 | |
| }
 | |
| 
 | |
| static void macio_gpio_nmi(NMIState *n, int cpu_index, Error **errp)
 | |
| {
 | |
|     macio_set_gpio(MACIO_GPIO(n), 9, true);
 | |
|     macio_set_gpio(MACIO_GPIO(n), 9, false);
 | |
| }
 | |
| 
 | |
| static void macio_gpio_class_init(ObjectClass *oc, void *data)
 | |
| {
 | |
|     DeviceClass *dc = DEVICE_CLASS(oc);
 | |
|     NMIClass *nc = NMI_CLASS(oc);
 | |
| 
 | |
|     device_class_set_legacy_reset(dc, macio_gpio_reset);
 | |
|     dc->vmsd = &vmstate_macio_gpio;
 | |
|     nc->nmi_monitor_handler = macio_gpio_nmi;
 | |
| }
 | |
| 
 | |
| static const TypeInfo macio_gpio_init_info = {
 | |
|     .name          = TYPE_MACIO_GPIO,
 | |
|     .parent        = TYPE_SYS_BUS_DEVICE,
 | |
|     .instance_size = sizeof(MacIOGPIOState),
 | |
|     .instance_init = macio_gpio_init,
 | |
|     .class_init    = macio_gpio_class_init,
 | |
|     .interfaces = (InterfaceInfo[]) {
 | |
|         { TYPE_NMI },
 | |
|         { }
 | |
|     },
 | |
| };
 | |
| 
 | |
| static void macio_gpio_register_types(void)
 | |
| {
 | |
|     type_register_static(&macio_gpio_init_info);
 | |
| }
 | |
| 
 | |
| type_init(macio_gpio_register_types)
 |