xref: /qemu/hw/gpio/sifive_gpio.c (revision e3d08143)
14921a0ceSBin Meng /*
24921a0ceSBin Meng  * SiFive System-on-Chip general purpose input/output register definition
34921a0ceSBin Meng  *
44921a0ceSBin Meng  * Copyright 2019 AdaCore
54921a0ceSBin Meng  *
64921a0ceSBin Meng  * Base on nrf51_gpio.c:
74921a0ceSBin Meng  *
84921a0ceSBin Meng  * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
94921a0ceSBin Meng  *
104921a0ceSBin Meng  * This code is licensed under the GPL version 2 or later.  See
114921a0ceSBin Meng  * the COPYING file in the top-level directory.
124921a0ceSBin Meng  */
134921a0ceSBin Meng 
144921a0ceSBin Meng #include "qemu/osdep.h"
154921a0ceSBin Meng #include "qemu/log.h"
164921a0ceSBin Meng #include "hw/irq.h"
174921a0ceSBin Meng #include "hw/qdev-properties.h"
184921a0ceSBin Meng #include "hw/gpio/sifive_gpio.h"
194921a0ceSBin Meng #include "migration/vmstate.h"
204921a0ceSBin Meng #include "trace.h"
214921a0ceSBin Meng 
update_output_irq(SIFIVEGPIOState * s)224921a0ceSBin Meng static void update_output_irq(SIFIVEGPIOState *s)
234921a0ceSBin Meng {
244921a0ceSBin Meng     uint32_t pending;
254921a0ceSBin Meng     uint32_t pin;
264921a0ceSBin Meng 
274921a0ceSBin Meng     pending = s->high_ip & s->high_ie;
284921a0ceSBin Meng     pending |= s->low_ip & s->low_ie;
294921a0ceSBin Meng     pending |= s->rise_ip & s->rise_ie;
304921a0ceSBin Meng     pending |= s->fall_ip & s->fall_ie;
314921a0ceSBin Meng 
324921a0ceSBin Meng     for (int i = 0; i < s->ngpio; i++) {
334921a0ceSBin Meng         pin = 1 << i;
344921a0ceSBin Meng         qemu_set_irq(s->irq[i], (pending & pin) != 0);
354921a0ceSBin Meng         trace_sifive_gpio_update_output_irq(i, (pending & pin) != 0);
364921a0ceSBin Meng     }
374921a0ceSBin Meng }
384921a0ceSBin Meng 
update_state(SIFIVEGPIOState * s)394921a0ceSBin Meng static void update_state(SIFIVEGPIOState *s)
404921a0ceSBin Meng {
414921a0ceSBin Meng     size_t i;
424921a0ceSBin Meng     bool prev_ival, in, in_mask, port, out_xor, pull, output_en, input_en,
434921a0ceSBin Meng         rise_ip, fall_ip, low_ip, high_ip, oval, actual_value, ival;
444921a0ceSBin Meng 
454921a0ceSBin Meng     for (i = 0; i < s->ngpio; i++) {
464921a0ceSBin Meng 
474921a0ceSBin Meng         prev_ival = extract32(s->value, i, 1);
484921a0ceSBin Meng         in        = extract32(s->in, i, 1);
494921a0ceSBin Meng         in_mask   = extract32(s->in_mask, i, 1);
504921a0ceSBin Meng         port      = extract32(s->port, i, 1);
514921a0ceSBin Meng         out_xor   = extract32(s->out_xor, i, 1);
524921a0ceSBin Meng         pull      = extract32(s->pue, i, 1);
534921a0ceSBin Meng         output_en = extract32(s->output_en, i, 1);
544921a0ceSBin Meng         input_en  = extract32(s->input_en, i, 1);
554921a0ceSBin Meng         rise_ip   = extract32(s->rise_ip, i, 1);
564921a0ceSBin Meng         fall_ip   = extract32(s->fall_ip, i, 1);
574921a0ceSBin Meng         low_ip    = extract32(s->low_ip, i, 1);
584921a0ceSBin Meng         high_ip   = extract32(s->high_ip, i, 1);
594921a0ceSBin Meng 
604921a0ceSBin Meng         /* Output value (IOF not supported) */
614921a0ceSBin Meng         oval = output_en && (port ^ out_xor);
624921a0ceSBin Meng 
634921a0ceSBin Meng         /* Pin both driven externally and internally */
644921a0ceSBin Meng         if (output_en && in_mask) {
654921a0ceSBin Meng             qemu_log_mask(LOG_GUEST_ERROR, "GPIO pin %zu short circuited\n", i);
664921a0ceSBin Meng         }
674921a0ceSBin Meng 
684921a0ceSBin Meng         if (in_mask) {
694921a0ceSBin Meng             /* The pin is driven by external device */
704921a0ceSBin Meng             actual_value = in;
714921a0ceSBin Meng         } else if (output_en) {
724921a0ceSBin Meng             /* The pin is driven by internal circuit */
734921a0ceSBin Meng             actual_value = oval;
744921a0ceSBin Meng         } else {
754921a0ceSBin Meng             /* Floating? Apply pull-up resistor */
764921a0ceSBin Meng             actual_value = pull;
774921a0ceSBin Meng         }
784921a0ceSBin Meng 
794921a0ceSBin Meng         if (output_en) {
804921a0ceSBin Meng             qemu_set_irq(s->output[i], actual_value);
814921a0ceSBin Meng         }
824921a0ceSBin Meng 
834921a0ceSBin Meng         /* Input value */
844921a0ceSBin Meng         ival = input_en && actual_value;
854921a0ceSBin Meng 
864921a0ceSBin Meng         /* Interrupts */
874921a0ceSBin Meng         high_ip = high_ip || ival;
884921a0ceSBin Meng         s->high_ip = deposit32(s->high_ip, i, 1, high_ip);
894921a0ceSBin Meng 
904921a0ceSBin Meng         low_ip = low_ip || !ival;
914921a0ceSBin Meng         s->low_ip = deposit32(s->low_ip,  i, 1, low_ip);
924921a0ceSBin Meng 
934921a0ceSBin Meng         rise_ip = rise_ip || (ival && !prev_ival);
944921a0ceSBin Meng         s->rise_ip = deposit32(s->rise_ip, i, 1, rise_ip);
954921a0ceSBin Meng 
964921a0ceSBin Meng         fall_ip = fall_ip || (!ival && prev_ival);
974921a0ceSBin Meng         s->fall_ip = deposit32(s->fall_ip, i, 1, fall_ip);
984921a0ceSBin Meng 
994921a0ceSBin Meng         /* Update value */
1004921a0ceSBin Meng         s->value = deposit32(s->value, i, 1, ival);
1014921a0ceSBin Meng     }
1024921a0ceSBin Meng     update_output_irq(s);
1034921a0ceSBin Meng }
1044921a0ceSBin Meng 
sifive_gpio_read(void * opaque,hwaddr offset,unsigned int size)1054921a0ceSBin Meng static uint64_t sifive_gpio_read(void *opaque, hwaddr offset, unsigned int size)
1064921a0ceSBin Meng {
1074921a0ceSBin Meng     SIFIVEGPIOState *s = SIFIVE_GPIO(opaque);
1084921a0ceSBin Meng     uint64_t r = 0;
1094921a0ceSBin Meng 
1104921a0ceSBin Meng     switch (offset) {
1114921a0ceSBin Meng     case SIFIVE_GPIO_REG_VALUE:
1124921a0ceSBin Meng         r = s->value;
1134921a0ceSBin Meng         break;
1144921a0ceSBin Meng 
1154921a0ceSBin Meng     case SIFIVE_GPIO_REG_INPUT_EN:
1164921a0ceSBin Meng         r = s->input_en;
1174921a0ceSBin Meng         break;
1184921a0ceSBin Meng 
1194921a0ceSBin Meng     case SIFIVE_GPIO_REG_OUTPUT_EN:
1204921a0ceSBin Meng         r = s->output_en;
1214921a0ceSBin Meng         break;
1224921a0ceSBin Meng 
1234921a0ceSBin Meng     case SIFIVE_GPIO_REG_PORT:
1244921a0ceSBin Meng         r = s->port;
1254921a0ceSBin Meng         break;
1264921a0ceSBin Meng 
1274921a0ceSBin Meng     case SIFIVE_GPIO_REG_PUE:
1284921a0ceSBin Meng         r = s->pue;
1294921a0ceSBin Meng         break;
1304921a0ceSBin Meng 
1314921a0ceSBin Meng     case SIFIVE_GPIO_REG_DS:
1324921a0ceSBin Meng         r = s->ds;
1334921a0ceSBin Meng         break;
1344921a0ceSBin Meng 
1354921a0ceSBin Meng     case SIFIVE_GPIO_REG_RISE_IE:
1364921a0ceSBin Meng         r = s->rise_ie;
1374921a0ceSBin Meng         break;
1384921a0ceSBin Meng 
1394921a0ceSBin Meng     case SIFIVE_GPIO_REG_RISE_IP:
1404921a0ceSBin Meng         r = s->rise_ip;
1414921a0ceSBin Meng         break;
1424921a0ceSBin Meng 
1434921a0ceSBin Meng     case SIFIVE_GPIO_REG_FALL_IE:
1444921a0ceSBin Meng         r = s->fall_ie;
1454921a0ceSBin Meng         break;
1464921a0ceSBin Meng 
1474921a0ceSBin Meng     case SIFIVE_GPIO_REG_FALL_IP:
1484921a0ceSBin Meng         r = s->fall_ip;
1494921a0ceSBin Meng         break;
1504921a0ceSBin Meng 
1514921a0ceSBin Meng     case SIFIVE_GPIO_REG_HIGH_IE:
1524921a0ceSBin Meng         r = s->high_ie;
1534921a0ceSBin Meng         break;
1544921a0ceSBin Meng 
1554921a0ceSBin Meng     case SIFIVE_GPIO_REG_HIGH_IP:
1564921a0ceSBin Meng         r = s->high_ip;
1574921a0ceSBin Meng         break;
1584921a0ceSBin Meng 
1594921a0ceSBin Meng     case SIFIVE_GPIO_REG_LOW_IE:
1604921a0ceSBin Meng         r = s->low_ie;
1614921a0ceSBin Meng         break;
1624921a0ceSBin Meng 
1634921a0ceSBin Meng     case SIFIVE_GPIO_REG_LOW_IP:
1644921a0ceSBin Meng         r = s->low_ip;
1654921a0ceSBin Meng         break;
1664921a0ceSBin Meng 
1674921a0ceSBin Meng     case SIFIVE_GPIO_REG_IOF_EN:
1684921a0ceSBin Meng         r = s->iof_en;
1694921a0ceSBin Meng         break;
1704921a0ceSBin Meng 
1714921a0ceSBin Meng     case SIFIVE_GPIO_REG_IOF_SEL:
1724921a0ceSBin Meng         r = s->iof_sel;
1734921a0ceSBin Meng         break;
1744921a0ceSBin Meng 
1754921a0ceSBin Meng     case SIFIVE_GPIO_REG_OUT_XOR:
1764921a0ceSBin Meng         r = s->out_xor;
1774921a0ceSBin Meng         break;
1784921a0ceSBin Meng 
1794921a0ceSBin Meng     default:
1804921a0ceSBin Meng         qemu_log_mask(LOG_GUEST_ERROR,
1814921a0ceSBin Meng                 "%s: bad read offset 0x%" HWADDR_PRIx "\n",
1824921a0ceSBin Meng                       __func__, offset);
1834921a0ceSBin Meng     }
1844921a0ceSBin Meng 
1854921a0ceSBin Meng     trace_sifive_gpio_read(offset, r);
1864921a0ceSBin Meng 
1874921a0ceSBin Meng     return r;
1884921a0ceSBin Meng }
1894921a0ceSBin Meng 
sifive_gpio_write(void * opaque,hwaddr offset,uint64_t value,unsigned int size)1904921a0ceSBin Meng static void sifive_gpio_write(void *opaque, hwaddr offset,
1914921a0ceSBin Meng                               uint64_t value, unsigned int size)
1924921a0ceSBin Meng {
1934921a0ceSBin Meng     SIFIVEGPIOState *s = SIFIVE_GPIO(opaque);
1944921a0ceSBin Meng 
1954921a0ceSBin Meng     trace_sifive_gpio_write(offset, value);
1964921a0ceSBin Meng 
1974921a0ceSBin Meng     switch (offset) {
1984921a0ceSBin Meng 
1994921a0ceSBin Meng     case SIFIVE_GPIO_REG_INPUT_EN:
2004921a0ceSBin Meng         s->input_en = value;
2014921a0ceSBin Meng         break;
2024921a0ceSBin Meng 
2034921a0ceSBin Meng     case SIFIVE_GPIO_REG_OUTPUT_EN:
2044921a0ceSBin Meng         s->output_en = value;
2054921a0ceSBin Meng         break;
2064921a0ceSBin Meng 
2074921a0ceSBin Meng     case SIFIVE_GPIO_REG_PORT:
2084921a0ceSBin Meng         s->port = value;
2094921a0ceSBin Meng         break;
2104921a0ceSBin Meng 
2114921a0ceSBin Meng     case SIFIVE_GPIO_REG_PUE:
2124921a0ceSBin Meng         s->pue = value;
2134921a0ceSBin Meng         break;
2144921a0ceSBin Meng 
2154921a0ceSBin Meng     case SIFIVE_GPIO_REG_DS:
2164921a0ceSBin Meng         s->ds = value;
2174921a0ceSBin Meng         break;
2184921a0ceSBin Meng 
2194921a0ceSBin Meng     case SIFIVE_GPIO_REG_RISE_IE:
2204921a0ceSBin Meng         s->rise_ie = value;
2214921a0ceSBin Meng         break;
2224921a0ceSBin Meng 
2234921a0ceSBin Meng     case SIFIVE_GPIO_REG_RISE_IP:
2244921a0ceSBin Meng          /* Write 1 to clear */
2254921a0ceSBin Meng         s->rise_ip &= ~value;
2264921a0ceSBin Meng         break;
2274921a0ceSBin Meng 
2284921a0ceSBin Meng     case SIFIVE_GPIO_REG_FALL_IE:
2294921a0ceSBin Meng         s->fall_ie = value;
2304921a0ceSBin Meng         break;
2314921a0ceSBin Meng 
2324921a0ceSBin Meng     case SIFIVE_GPIO_REG_FALL_IP:
2334921a0ceSBin Meng          /* Write 1 to clear */
2344921a0ceSBin Meng         s->fall_ip &= ~value;
2354921a0ceSBin Meng         break;
2364921a0ceSBin Meng 
2374921a0ceSBin Meng     case SIFIVE_GPIO_REG_HIGH_IE:
2384921a0ceSBin Meng         s->high_ie = value;
2394921a0ceSBin Meng         break;
2404921a0ceSBin Meng 
2414921a0ceSBin Meng     case SIFIVE_GPIO_REG_HIGH_IP:
2424921a0ceSBin Meng          /* Write 1 to clear */
2434921a0ceSBin Meng         s->high_ip &= ~value;
2444921a0ceSBin Meng         break;
2454921a0ceSBin Meng 
2464921a0ceSBin Meng     case SIFIVE_GPIO_REG_LOW_IE:
2474921a0ceSBin Meng         s->low_ie = value;
2484921a0ceSBin Meng         break;
2494921a0ceSBin Meng 
2504921a0ceSBin Meng     case SIFIVE_GPIO_REG_LOW_IP:
2514921a0ceSBin Meng          /* Write 1 to clear */
2524921a0ceSBin Meng         s->low_ip &= ~value;
2534921a0ceSBin Meng         break;
2544921a0ceSBin Meng 
2554921a0ceSBin Meng     case SIFIVE_GPIO_REG_IOF_EN:
2564921a0ceSBin Meng         s->iof_en = value;
2574921a0ceSBin Meng         break;
2584921a0ceSBin Meng 
2594921a0ceSBin Meng     case SIFIVE_GPIO_REG_IOF_SEL:
2604921a0ceSBin Meng         s->iof_sel = value;
2614921a0ceSBin Meng         break;
2624921a0ceSBin Meng 
2634921a0ceSBin Meng     case SIFIVE_GPIO_REG_OUT_XOR:
2644921a0ceSBin Meng         s->out_xor = value;
2654921a0ceSBin Meng         break;
2664921a0ceSBin Meng 
2674921a0ceSBin Meng     default:
2684921a0ceSBin Meng         qemu_log_mask(LOG_GUEST_ERROR,
2694921a0ceSBin Meng                       "%s: bad write offset 0x%" HWADDR_PRIx "\n",
2704921a0ceSBin Meng                       __func__, offset);
2714921a0ceSBin Meng     }
2724921a0ceSBin Meng 
2734921a0ceSBin Meng     update_state(s);
2744921a0ceSBin Meng }
2754921a0ceSBin Meng 
2764921a0ceSBin Meng static const MemoryRegionOps gpio_ops = {
2774921a0ceSBin Meng     .read =  sifive_gpio_read,
2784921a0ceSBin Meng     .write = sifive_gpio_write,
2794921a0ceSBin Meng     .endianness = DEVICE_LITTLE_ENDIAN,
2804921a0ceSBin Meng     .impl.min_access_size = 4,
2814921a0ceSBin Meng     .impl.max_access_size = 4,
2824921a0ceSBin Meng };
2834921a0ceSBin Meng 
sifive_gpio_set(void * opaque,int line,int value)2844921a0ceSBin Meng static void sifive_gpio_set(void *opaque, int line, int value)
2854921a0ceSBin Meng {
2864921a0ceSBin Meng     SIFIVEGPIOState *s = SIFIVE_GPIO(opaque);
2874921a0ceSBin Meng 
2884921a0ceSBin Meng     trace_sifive_gpio_set(line, value);
2894921a0ceSBin Meng 
2904921a0ceSBin Meng     assert(line >= 0 && line < SIFIVE_GPIO_PINS);
2914921a0ceSBin Meng 
2924921a0ceSBin Meng     s->in_mask = deposit32(s->in_mask, line, 1, value >= 0);
2934921a0ceSBin Meng     if (value >= 0) {
2944921a0ceSBin Meng         s->in = deposit32(s->in, line, 1, value != 0);
2954921a0ceSBin Meng     }
2964921a0ceSBin Meng 
2974921a0ceSBin Meng     update_state(s);
2984921a0ceSBin Meng }
2994921a0ceSBin Meng 
sifive_gpio_reset(DeviceState * dev)3004921a0ceSBin Meng static void sifive_gpio_reset(DeviceState *dev)
3014921a0ceSBin Meng {
3024921a0ceSBin Meng     SIFIVEGPIOState *s = SIFIVE_GPIO(dev);
3034921a0ceSBin Meng 
3044921a0ceSBin Meng     s->value = 0;
3054921a0ceSBin Meng     s->input_en = 0;
3064921a0ceSBin Meng     s->output_en = 0;
3074921a0ceSBin Meng     s->port = 0;
3084921a0ceSBin Meng     s->pue = 0;
3094921a0ceSBin Meng     s->ds = 0;
3104921a0ceSBin Meng     s->rise_ie = 0;
3114921a0ceSBin Meng     s->rise_ip = 0;
3124921a0ceSBin Meng     s->fall_ie = 0;
3134921a0ceSBin Meng     s->fall_ip = 0;
3144921a0ceSBin Meng     s->high_ie = 0;
3154921a0ceSBin Meng     s->high_ip = 0;
3164921a0ceSBin Meng     s->low_ie = 0;
3174921a0ceSBin Meng     s->low_ip = 0;
3184921a0ceSBin Meng     s->iof_en = 0;
3194921a0ceSBin Meng     s->iof_sel = 0;
3204921a0ceSBin Meng     s->out_xor = 0;
3214921a0ceSBin Meng     s->in = 0;
3224921a0ceSBin Meng     s->in_mask = 0;
3234921a0ceSBin Meng }
3244921a0ceSBin Meng 
3254921a0ceSBin Meng static const VMStateDescription vmstate_sifive_gpio = {
3264921a0ceSBin Meng     .name = TYPE_SIFIVE_GPIO,
3274921a0ceSBin Meng     .version_id = 1,
3284921a0ceSBin Meng     .minimum_version_id = 1,
3293b9e779bSRichard Henderson     .fields = (const VMStateField[]) {
3304921a0ceSBin Meng         VMSTATE_UINT32(value,     SIFIVEGPIOState),
3314921a0ceSBin Meng         VMSTATE_UINT32(input_en,  SIFIVEGPIOState),
3324921a0ceSBin Meng         VMSTATE_UINT32(output_en, SIFIVEGPIOState),
3334921a0ceSBin Meng         VMSTATE_UINT32(port,      SIFIVEGPIOState),
3344921a0ceSBin Meng         VMSTATE_UINT32(pue,       SIFIVEGPIOState),
3354921a0ceSBin Meng         VMSTATE_UINT32(rise_ie,   SIFIVEGPIOState),
3364921a0ceSBin Meng         VMSTATE_UINT32(rise_ip,   SIFIVEGPIOState),
3374921a0ceSBin Meng         VMSTATE_UINT32(fall_ie,   SIFIVEGPIOState),
3384921a0ceSBin Meng         VMSTATE_UINT32(fall_ip,   SIFIVEGPIOState),
3394921a0ceSBin Meng         VMSTATE_UINT32(high_ie,   SIFIVEGPIOState),
3404921a0ceSBin Meng         VMSTATE_UINT32(high_ip,   SIFIVEGPIOState),
3414921a0ceSBin Meng         VMSTATE_UINT32(low_ie,    SIFIVEGPIOState),
3424921a0ceSBin Meng         VMSTATE_UINT32(low_ip,    SIFIVEGPIOState),
3434921a0ceSBin Meng         VMSTATE_UINT32(iof_en,    SIFIVEGPIOState),
3444921a0ceSBin Meng         VMSTATE_UINT32(iof_sel,   SIFIVEGPIOState),
3454921a0ceSBin Meng         VMSTATE_UINT32(out_xor,   SIFIVEGPIOState),
3464921a0ceSBin Meng         VMSTATE_UINT32(in,        SIFIVEGPIOState),
3474921a0ceSBin Meng         VMSTATE_UINT32(in_mask,   SIFIVEGPIOState),
3484921a0ceSBin Meng         VMSTATE_END_OF_LIST()
3494921a0ceSBin Meng     }
3504921a0ceSBin Meng };
3514921a0ceSBin Meng 
3524921a0ceSBin Meng static Property sifive_gpio_properties[] = {
3534921a0ceSBin Meng     DEFINE_PROP_UINT32("ngpio", SIFIVEGPIOState, ngpio, SIFIVE_GPIO_PINS),
3544921a0ceSBin Meng     DEFINE_PROP_END_OF_LIST(),
3554921a0ceSBin Meng };
3564921a0ceSBin Meng 
sifive_gpio_realize(DeviceState * dev,Error ** errp)3574921a0ceSBin Meng static void sifive_gpio_realize(DeviceState *dev, Error **errp)
3584921a0ceSBin Meng {
3594921a0ceSBin Meng     SIFIVEGPIOState *s = SIFIVE_GPIO(dev);
3604921a0ceSBin Meng 
3614921a0ceSBin Meng     memory_region_init_io(&s->mmio, OBJECT(dev), &gpio_ops, s,
3624921a0ceSBin Meng             TYPE_SIFIVE_GPIO, SIFIVE_GPIO_SIZE);
3634921a0ceSBin Meng 
3644921a0ceSBin Meng     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
3654921a0ceSBin Meng 
3664921a0ceSBin Meng     for (int i = 0; i < s->ngpio; i++) {
3674921a0ceSBin Meng         sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
3684921a0ceSBin Meng     }
3694921a0ceSBin Meng 
3704921a0ceSBin Meng     qdev_init_gpio_in(DEVICE(s), sifive_gpio_set, s->ngpio);
3714921a0ceSBin Meng     qdev_init_gpio_out(DEVICE(s), s->output, s->ngpio);
3724921a0ceSBin Meng }
3734921a0ceSBin Meng 
sifive_gpio_class_init(ObjectClass * klass,void * data)3744921a0ceSBin Meng static void sifive_gpio_class_init(ObjectClass *klass, void *data)
3754921a0ceSBin Meng {
3764921a0ceSBin Meng     DeviceClass *dc = DEVICE_CLASS(klass);
3774921a0ceSBin Meng 
3784921a0ceSBin Meng     device_class_set_props(dc, sifive_gpio_properties);
3794921a0ceSBin Meng     dc->vmsd = &vmstate_sifive_gpio;
3804921a0ceSBin Meng     dc->realize = sifive_gpio_realize;
381*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, sifive_gpio_reset);
3824921a0ceSBin Meng     dc->desc = "SiFive GPIO";
3834921a0ceSBin Meng }
3844921a0ceSBin Meng 
3854921a0ceSBin Meng static const TypeInfo sifive_gpio_info = {
3864921a0ceSBin Meng     .name = TYPE_SIFIVE_GPIO,
3874921a0ceSBin Meng     .parent = TYPE_SYS_BUS_DEVICE,
3884921a0ceSBin Meng     .instance_size = sizeof(SIFIVEGPIOState),
3894921a0ceSBin Meng     .class_init = sifive_gpio_class_init
3904921a0ceSBin Meng };
3914921a0ceSBin Meng 
sifive_gpio_register_types(void)3924921a0ceSBin Meng static void sifive_gpio_register_types(void)
3934921a0ceSBin Meng {
3944921a0ceSBin Meng     type_register_static(&sifive_gpio_info);
3954921a0ceSBin Meng }
3964921a0ceSBin Meng 
3974921a0ceSBin Meng type_init(sifive_gpio_register_types)
398