xref: /openbmc/qemu/hw/gpio/bcm2838_gpio.c (revision b54a9a56)
123c82c1dSSergey Kambalin /*
223c82c1dSSergey Kambalin  * Raspberry Pi (BCM2838) GPIO Controller
323c82c1dSSergey Kambalin  * This implementation is based on bcm2835_gpio (hw/gpio/bcm2835_gpio.c)
423c82c1dSSergey Kambalin  *
523c82c1dSSergey Kambalin  * Copyright (c) 2022 Auriga LLC
623c82c1dSSergey Kambalin  *
723c82c1dSSergey Kambalin  * Authors:
823c82c1dSSergey Kambalin  *  Lotosh, Aleksey <aleksey.lotosh@auriga.com>
923c82c1dSSergey Kambalin  *
1023c82c1dSSergey Kambalin  * SPDX-License-Identifier: GPL-2.0-or-later
1123c82c1dSSergey Kambalin  */
1223c82c1dSSergey Kambalin 
1323c82c1dSSergey Kambalin #include "qemu/osdep.h"
1423c82c1dSSergey Kambalin #include "qemu/log.h"
1523c82c1dSSergey Kambalin #include "qemu/module.h"
1623c82c1dSSergey Kambalin #include "qemu/timer.h"
1723c82c1dSSergey Kambalin #include "qapi/error.h"
1823c82c1dSSergey Kambalin #include "hw/sysbus.h"
1923c82c1dSSergey Kambalin #include "migration/vmstate.h"
20*b54a9a56SSergey Kambalin #include "hw/sd/sd.h"
2123c82c1dSSergey Kambalin #include "hw/gpio/bcm2838_gpio.h"
220c8b40dbSSergey Kambalin #include "hw/irq.h"
2323c82c1dSSergey Kambalin 
2423c82c1dSSergey Kambalin #define GPFSEL0   0x00
2523c82c1dSSergey Kambalin #define GPFSEL1   0x04
2623c82c1dSSergey Kambalin #define GPFSEL2   0x08
2723c82c1dSSergey Kambalin #define GPFSEL3   0x0C
2823c82c1dSSergey Kambalin #define GPFSEL4   0x10
2923c82c1dSSergey Kambalin #define GPFSEL5   0x14
3023c82c1dSSergey Kambalin #define GPSET0    0x1C
3123c82c1dSSergey Kambalin #define GPSET1    0x20
3223c82c1dSSergey Kambalin #define GPCLR0    0x28
3323c82c1dSSergey Kambalin #define GPCLR1    0x2C
3423c82c1dSSergey Kambalin #define GPLEV0    0x34
3523c82c1dSSergey Kambalin #define GPLEV1    0x38
3623c82c1dSSergey Kambalin #define GPEDS0    0x40
3723c82c1dSSergey Kambalin #define GPEDS1    0x44
3823c82c1dSSergey Kambalin #define GPREN0    0x4C
3923c82c1dSSergey Kambalin #define GPREN1    0x50
4023c82c1dSSergey Kambalin #define GPFEN0    0x58
4123c82c1dSSergey Kambalin #define GPFEN1    0x5C
4223c82c1dSSergey Kambalin #define GPHEN0    0x64
4323c82c1dSSergey Kambalin #define GPHEN1    0x68
4423c82c1dSSergey Kambalin #define GPLEN0    0x70
4523c82c1dSSergey Kambalin #define GPLEN1    0x74
4623c82c1dSSergey Kambalin #define GPAREN0   0x7C
4723c82c1dSSergey Kambalin #define GPAREN1   0x80
4823c82c1dSSergey Kambalin #define GPAFEN0   0x88
4923c82c1dSSergey Kambalin #define GPAFEN1   0x8C
5023c82c1dSSergey Kambalin 
5123c82c1dSSergey Kambalin #define GPIO_PUP_PDN_CNTRL_REG0 0xE4
5223c82c1dSSergey Kambalin #define GPIO_PUP_PDN_CNTRL_REG1 0xE8
5323c82c1dSSergey Kambalin #define GPIO_PUP_PDN_CNTRL_REG2 0xEC
5423c82c1dSSergey Kambalin #define GPIO_PUP_PDN_CNTRL_REG3 0xF0
5523c82c1dSSergey Kambalin 
5623c82c1dSSergey Kambalin #define RESET_VAL_CNTRL_REG0 0xAAA95555
5723c82c1dSSergey Kambalin #define RESET_VAL_CNTRL_REG1 0xA0AAAAAA
5823c82c1dSSergey Kambalin #define RESET_VAL_CNTRL_REG2 0x50AAA95A
5923c82c1dSSergey Kambalin #define RESET_VAL_CNTRL_REG3 0x00055555
6023c82c1dSSergey Kambalin 
610c8b40dbSSergey Kambalin #define NUM_FSELN_IN_GPFSELN 10
620c8b40dbSSergey Kambalin #define NUM_BITS_FSELN       3
630c8b40dbSSergey Kambalin #define MASK_FSELN           0x7
640c8b40dbSSergey Kambalin 
6523c82c1dSSergey Kambalin #define BYTES_IN_WORD        4
6623c82c1dSSergey Kambalin 
67*b54a9a56SSergey Kambalin /* bcm,function property */
68*b54a9a56SSergey Kambalin #define BCM2838_FSEL_GPIO_IN    0
69*b54a9a56SSergey Kambalin #define BCM2838_FSEL_GPIO_OUT   1
70*b54a9a56SSergey Kambalin #define BCM2838_FSEL_ALT5       2
71*b54a9a56SSergey Kambalin #define BCM2838_FSEL_ALT4       3
72*b54a9a56SSergey Kambalin #define BCM2838_FSEL_ALT0       4
73*b54a9a56SSergey Kambalin #define BCM2838_FSEL_ALT1       5
74*b54a9a56SSergey Kambalin #define BCM2838_FSEL_ALT2       6
75*b54a9a56SSergey Kambalin #define BCM2838_FSEL_ALT3       7
76*b54a9a56SSergey Kambalin 
gpfsel_get(BCM2838GpioState * s,uint8_t reg)770c8b40dbSSergey Kambalin static uint32_t gpfsel_get(BCM2838GpioState *s, uint8_t reg)
780c8b40dbSSergey Kambalin {
790c8b40dbSSergey Kambalin     int i;
800c8b40dbSSergey Kambalin     uint32_t value = 0;
810c8b40dbSSergey Kambalin     for (i = 0; i < NUM_FSELN_IN_GPFSELN; i++) {
820c8b40dbSSergey Kambalin         uint32_t index = NUM_FSELN_IN_GPFSELN * reg + i;
830c8b40dbSSergey Kambalin         if (index < sizeof(s->fsel)) {
840c8b40dbSSergey Kambalin             value |= (s->fsel[index] & MASK_FSELN) << (NUM_BITS_FSELN * i);
850c8b40dbSSergey Kambalin         }
860c8b40dbSSergey Kambalin     }
870c8b40dbSSergey Kambalin     return value;
880c8b40dbSSergey Kambalin }
890c8b40dbSSergey Kambalin 
gpfsel_set(BCM2838GpioState * s,uint8_t reg,uint32_t value)900c8b40dbSSergey Kambalin static void gpfsel_set(BCM2838GpioState *s, uint8_t reg, uint32_t value)
910c8b40dbSSergey Kambalin {
920c8b40dbSSergey Kambalin     int i;
930c8b40dbSSergey Kambalin     for (i = 0; i < NUM_FSELN_IN_GPFSELN; i++) {
940c8b40dbSSergey Kambalin         uint32_t index = NUM_FSELN_IN_GPFSELN * reg + i;
950c8b40dbSSergey Kambalin         if (index < sizeof(s->fsel)) {
960c8b40dbSSergey Kambalin             int fsel = (value >> (NUM_BITS_FSELN * i)) & MASK_FSELN;
970c8b40dbSSergey Kambalin             s->fsel[index] = fsel;
980c8b40dbSSergey Kambalin         }
990c8b40dbSSergey Kambalin     }
100*b54a9a56SSergey Kambalin 
101*b54a9a56SSergey Kambalin     /* SD controller selection (48-53) */
102*b54a9a56SSergey Kambalin     if (s->sd_fsel != BCM2838_FSEL_GPIO_IN
103*b54a9a56SSergey Kambalin         && (s->fsel[48] == BCM2838_FSEL_GPIO_IN)
104*b54a9a56SSergey Kambalin         && (s->fsel[49] == BCM2838_FSEL_GPIO_IN)
105*b54a9a56SSergey Kambalin         && (s->fsel[50] == BCM2838_FSEL_GPIO_IN)
106*b54a9a56SSergey Kambalin         && (s->fsel[51] == BCM2838_FSEL_GPIO_IN)
107*b54a9a56SSergey Kambalin         && (s->fsel[52] == BCM2838_FSEL_GPIO_IN)
108*b54a9a56SSergey Kambalin         && (s->fsel[53] == BCM2838_FSEL_GPIO_IN)
109*b54a9a56SSergey Kambalin        ) {
110*b54a9a56SSergey Kambalin         /* SDHCI controller selected */
111*b54a9a56SSergey Kambalin         sdbus_reparent_card(s->sdbus_sdhost, s->sdbus_sdhci);
112*b54a9a56SSergey Kambalin         s->sd_fsel = BCM2838_FSEL_GPIO_IN;
113*b54a9a56SSergey Kambalin     } else if (s->sd_fsel != BCM2838_FSEL_ALT0
114*b54a9a56SSergey Kambalin                && (s->fsel[48] == BCM2838_FSEL_ALT0) /* SD_CLK_R */
115*b54a9a56SSergey Kambalin                && (s->fsel[49] == BCM2838_FSEL_ALT0) /* SD_CMD_R */
116*b54a9a56SSergey Kambalin                && (s->fsel[50] == BCM2838_FSEL_ALT0) /* SD_DATA0_R */
117*b54a9a56SSergey Kambalin                && (s->fsel[51] == BCM2838_FSEL_ALT0) /* SD_DATA1_R */
118*b54a9a56SSergey Kambalin                && (s->fsel[52] == BCM2838_FSEL_ALT0) /* SD_DATA2_R */
119*b54a9a56SSergey Kambalin                && (s->fsel[53] == BCM2838_FSEL_ALT0) /* SD_DATA3_R */
120*b54a9a56SSergey Kambalin               ) {
121*b54a9a56SSergey Kambalin         /* SDHost controller selected */
122*b54a9a56SSergey Kambalin         sdbus_reparent_card(s->sdbus_sdhci, s->sdbus_sdhost);
123*b54a9a56SSergey Kambalin         s->sd_fsel = BCM2838_FSEL_ALT0;
124*b54a9a56SSergey Kambalin     }
1250c8b40dbSSergey Kambalin }
1260c8b40dbSSergey Kambalin 
gpfsel_is_out(BCM2838GpioState * s,int index)1270c8b40dbSSergey Kambalin static int gpfsel_is_out(BCM2838GpioState *s, int index)
1280c8b40dbSSergey Kambalin {
1290c8b40dbSSergey Kambalin     if (index >= 0 && index < BCM2838_GPIO_NUM) {
1300c8b40dbSSergey Kambalin         return s->fsel[index] == 1;
1310c8b40dbSSergey Kambalin     }
1320c8b40dbSSergey Kambalin     return 0;
1330c8b40dbSSergey Kambalin }
1340c8b40dbSSergey Kambalin 
gpset(BCM2838GpioState * s,uint32_t val,uint8_t start,uint8_t count,uint32_t * lev)1350c8b40dbSSergey Kambalin static void gpset(BCM2838GpioState *s, uint32_t val, uint8_t start,
1360c8b40dbSSergey Kambalin                   uint8_t count, uint32_t *lev)
1370c8b40dbSSergey Kambalin {
1380c8b40dbSSergey Kambalin     uint32_t changes = val & ~*lev;
1390c8b40dbSSergey Kambalin     uint32_t cur = 1;
1400c8b40dbSSergey Kambalin 
1410c8b40dbSSergey Kambalin     int i;
1420c8b40dbSSergey Kambalin     for (i = 0; i < count; i++) {
1430c8b40dbSSergey Kambalin         if ((changes & cur) && (gpfsel_is_out(s, start + i))) {
1440c8b40dbSSergey Kambalin             qemu_set_irq(s->out[start + i], 1);
1450c8b40dbSSergey Kambalin         }
1460c8b40dbSSergey Kambalin         cur <<= 1;
1470c8b40dbSSergey Kambalin     }
1480c8b40dbSSergey Kambalin 
1490c8b40dbSSergey Kambalin     *lev |= val;
1500c8b40dbSSergey Kambalin }
1510c8b40dbSSergey Kambalin 
gpclr(BCM2838GpioState * s,uint32_t val,uint8_t start,uint8_t count,uint32_t * lev)1520c8b40dbSSergey Kambalin static void gpclr(BCM2838GpioState *s, uint32_t val, uint8_t start,
1530c8b40dbSSergey Kambalin                   uint8_t count, uint32_t *lev)
1540c8b40dbSSergey Kambalin {
1550c8b40dbSSergey Kambalin     uint32_t changes = val & *lev;
1560c8b40dbSSergey Kambalin     uint32_t cur = 1;
1570c8b40dbSSergey Kambalin 
1580c8b40dbSSergey Kambalin     int i;
1590c8b40dbSSergey Kambalin     for (i = 0; i < count; i++) {
1600c8b40dbSSergey Kambalin         if ((changes & cur) && (gpfsel_is_out(s, start + i))) {
1610c8b40dbSSergey Kambalin             qemu_set_irq(s->out[start + i], 0);
1620c8b40dbSSergey Kambalin         }
1630c8b40dbSSergey Kambalin         cur <<= 1;
1640c8b40dbSSergey Kambalin     }
1650c8b40dbSSergey Kambalin 
1660c8b40dbSSergey Kambalin     *lev &= ~val;
1670c8b40dbSSergey Kambalin }
1680c8b40dbSSergey Kambalin 
bcm2838_gpio_read(void * opaque,hwaddr offset,unsigned size)16923c82c1dSSergey Kambalin static uint64_t bcm2838_gpio_read(void *opaque, hwaddr offset, unsigned size)
17023c82c1dSSergey Kambalin {
1710c8b40dbSSergey Kambalin     BCM2838GpioState *s = (BCM2838GpioState *)opaque;
17223c82c1dSSergey Kambalin     uint64_t value = 0;
17323c82c1dSSergey Kambalin 
1740c8b40dbSSergey Kambalin     switch (offset) {
1750c8b40dbSSergey Kambalin     case GPFSEL0:
1760c8b40dbSSergey Kambalin     case GPFSEL1:
1770c8b40dbSSergey Kambalin     case GPFSEL2:
1780c8b40dbSSergey Kambalin     case GPFSEL3:
1790c8b40dbSSergey Kambalin     case GPFSEL4:
1800c8b40dbSSergey Kambalin     case GPFSEL5:
1810c8b40dbSSergey Kambalin         value = gpfsel_get(s, offset / BYTES_IN_WORD);
1820c8b40dbSSergey Kambalin         break;
1830c8b40dbSSergey Kambalin     case GPSET0:
1840c8b40dbSSergey Kambalin     case GPSET1:
1850c8b40dbSSergey Kambalin     case GPCLR0:
1860c8b40dbSSergey Kambalin     case GPCLR1:
1870c8b40dbSSergey Kambalin         /* Write Only */
1880c8b40dbSSergey Kambalin         qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: Attempt reading from write only"
1890c8b40dbSSergey Kambalin                       " register. 0x%"PRIx64" will be returned."
1900c8b40dbSSergey Kambalin                       " Address 0x%"HWADDR_PRIx", size %u\n",
1910c8b40dbSSergey Kambalin                       TYPE_BCM2838_GPIO, __func__, value, offset, size);
1920c8b40dbSSergey Kambalin         break;
1930c8b40dbSSergey Kambalin     case GPLEV0:
1940c8b40dbSSergey Kambalin         value = s->lev0;
1950c8b40dbSSergey Kambalin         break;
1960c8b40dbSSergey Kambalin     case GPLEV1:
1970c8b40dbSSergey Kambalin         value = s->lev1;
1980c8b40dbSSergey Kambalin         break;
1990c8b40dbSSergey Kambalin     case GPEDS0:
2000c8b40dbSSergey Kambalin     case GPEDS1:
2010c8b40dbSSergey Kambalin     case GPREN0:
2020c8b40dbSSergey Kambalin     case GPREN1:
2030c8b40dbSSergey Kambalin     case GPFEN0:
2040c8b40dbSSergey Kambalin     case GPFEN1:
2050c8b40dbSSergey Kambalin     case GPHEN0:
2060c8b40dbSSergey Kambalin     case GPHEN1:
2070c8b40dbSSergey Kambalin     case GPLEN0:
2080c8b40dbSSergey Kambalin     case GPLEN1:
2090c8b40dbSSergey Kambalin     case GPAREN0:
2100c8b40dbSSergey Kambalin     case GPAREN1:
2110c8b40dbSSergey Kambalin     case GPAFEN0:
2120c8b40dbSSergey Kambalin     case GPAFEN1:
2130c8b40dbSSergey Kambalin         /* Not implemented */
21423c82c1dSSergey Kambalin         qemu_log_mask(LOG_UNIMP, "%s: %s: not implemented for %"HWADDR_PRIx"\n",
21523c82c1dSSergey Kambalin                       TYPE_BCM2838_GPIO, __func__, offset);
2160c8b40dbSSergey Kambalin         break;
2170c8b40dbSSergey Kambalin     case GPIO_PUP_PDN_CNTRL_REG0:
2180c8b40dbSSergey Kambalin     case GPIO_PUP_PDN_CNTRL_REG1:
2190c8b40dbSSergey Kambalin     case GPIO_PUP_PDN_CNTRL_REG2:
2200c8b40dbSSergey Kambalin     case GPIO_PUP_PDN_CNTRL_REG3:
2210c8b40dbSSergey Kambalin         value = s->pup_cntrl_reg[(offset - GPIO_PUP_PDN_CNTRL_REG0)
2220c8b40dbSSergey Kambalin                                  / sizeof(s->pup_cntrl_reg[0])];
2230c8b40dbSSergey Kambalin         break;
2240c8b40dbSSergey Kambalin     default:
2250c8b40dbSSergey Kambalin         qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: bad offset %"HWADDR_PRIx"\n",
2260c8b40dbSSergey Kambalin                       TYPE_BCM2838_GPIO, __func__, offset);
2270c8b40dbSSergey Kambalin         break;
2280c8b40dbSSergey Kambalin     }
22923c82c1dSSergey Kambalin 
23023c82c1dSSergey Kambalin     return value;
23123c82c1dSSergey Kambalin }
23223c82c1dSSergey Kambalin 
bcm2838_gpio_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)23323c82c1dSSergey Kambalin static void bcm2838_gpio_write(void *opaque, hwaddr offset, uint64_t value,
23423c82c1dSSergey Kambalin                                unsigned size)
23523c82c1dSSergey Kambalin {
2360c8b40dbSSergey Kambalin     BCM2838GpioState *s = (BCM2838GpioState *)opaque;
2370c8b40dbSSergey Kambalin 
2380c8b40dbSSergey Kambalin     switch (offset) {
2390c8b40dbSSergey Kambalin     case GPFSEL0:
2400c8b40dbSSergey Kambalin     case GPFSEL1:
2410c8b40dbSSergey Kambalin     case GPFSEL2:
2420c8b40dbSSergey Kambalin     case GPFSEL3:
2430c8b40dbSSergey Kambalin     case GPFSEL4:
2440c8b40dbSSergey Kambalin     case GPFSEL5:
2450c8b40dbSSergey Kambalin         gpfsel_set(s, offset / BYTES_IN_WORD, value);
2460c8b40dbSSergey Kambalin         break;
2470c8b40dbSSergey Kambalin     case GPSET0:
2480c8b40dbSSergey Kambalin         gpset(s, value, 0, 32, &s->lev0);
2490c8b40dbSSergey Kambalin         break;
2500c8b40dbSSergey Kambalin     case GPSET1:
2510c8b40dbSSergey Kambalin         gpset(s, value, 32, 22, &s->lev1);
2520c8b40dbSSergey Kambalin         break;
2530c8b40dbSSergey Kambalin     case GPCLR0:
2540c8b40dbSSergey Kambalin         gpclr(s, value, 0, 32, &s->lev0);
2550c8b40dbSSergey Kambalin         break;
2560c8b40dbSSergey Kambalin     case GPCLR1:
2570c8b40dbSSergey Kambalin         gpclr(s, value, 32, 22, &s->lev1);
2580c8b40dbSSergey Kambalin         break;
2590c8b40dbSSergey Kambalin     case GPLEV0:
2600c8b40dbSSergey Kambalin     case GPLEV1:
2610c8b40dbSSergey Kambalin         /* Read Only */
2620c8b40dbSSergey Kambalin         qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: Attempt writing 0x%"PRIx64""
2630c8b40dbSSergey Kambalin                       " to read only register. Ignored."
2640c8b40dbSSergey Kambalin                       " Address 0x%"HWADDR_PRIx", size %u\n",
2650c8b40dbSSergey Kambalin                       TYPE_BCM2838_GPIO, __func__, value, offset, size);
2660c8b40dbSSergey Kambalin         break;
2670c8b40dbSSergey Kambalin     case GPEDS0:
2680c8b40dbSSergey Kambalin     case GPEDS1:
2690c8b40dbSSergey Kambalin     case GPREN0:
2700c8b40dbSSergey Kambalin     case GPREN1:
2710c8b40dbSSergey Kambalin     case GPFEN0:
2720c8b40dbSSergey Kambalin     case GPFEN1:
2730c8b40dbSSergey Kambalin     case GPHEN0:
2740c8b40dbSSergey Kambalin     case GPHEN1:
2750c8b40dbSSergey Kambalin     case GPLEN0:
2760c8b40dbSSergey Kambalin     case GPLEN1:
2770c8b40dbSSergey Kambalin     case GPAREN0:
2780c8b40dbSSergey Kambalin     case GPAREN1:
2790c8b40dbSSergey Kambalin     case GPAFEN0:
2800c8b40dbSSergey Kambalin     case GPAFEN1:
2810c8b40dbSSergey Kambalin         /* Not implemented */
28223c82c1dSSergey Kambalin         qemu_log_mask(LOG_UNIMP, "%s: %s: not implemented for %"HWADDR_PRIx"\n",
28323c82c1dSSergey Kambalin                       TYPE_BCM2838_GPIO, __func__, offset);
2840c8b40dbSSergey Kambalin         break;
2850c8b40dbSSergey Kambalin     case GPIO_PUP_PDN_CNTRL_REG0:
2860c8b40dbSSergey Kambalin     case GPIO_PUP_PDN_CNTRL_REG1:
2870c8b40dbSSergey Kambalin     case GPIO_PUP_PDN_CNTRL_REG2:
2880c8b40dbSSergey Kambalin     case GPIO_PUP_PDN_CNTRL_REG3:
2890c8b40dbSSergey Kambalin         s->pup_cntrl_reg[(offset - GPIO_PUP_PDN_CNTRL_REG0)
2900c8b40dbSSergey Kambalin                          / sizeof(s->pup_cntrl_reg[0])] = value;
2910c8b40dbSSergey Kambalin         break;
2920c8b40dbSSergey Kambalin     default:
2930c8b40dbSSergey Kambalin         qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: bad offset %"HWADDR_PRIx"\n",
2940c8b40dbSSergey Kambalin                   TYPE_BCM2838_GPIO, __func__, offset);
2950c8b40dbSSergey Kambalin     }
2960c8b40dbSSergey Kambalin     return;
29723c82c1dSSergey Kambalin }
29823c82c1dSSergey Kambalin 
bcm2838_gpio_reset(DeviceState * dev)29923c82c1dSSergey Kambalin static void bcm2838_gpio_reset(DeviceState *dev)
30023c82c1dSSergey Kambalin {
30123c82c1dSSergey Kambalin     BCM2838GpioState *s = BCM2838_GPIO(dev);
30223c82c1dSSergey Kambalin 
3030c8b40dbSSergey Kambalin     memset(s->fsel, 0, sizeof(s->fsel));
3040c8b40dbSSergey Kambalin 
305*b54a9a56SSergey Kambalin     s->sd_fsel = 0;
306*b54a9a56SSergey Kambalin 
307*b54a9a56SSergey Kambalin     /* SDHCI is selected by default */
308*b54a9a56SSergey Kambalin     sdbus_reparent_card(&s->sdbus, s->sdbus_sdhci);
309*b54a9a56SSergey Kambalin 
31023c82c1dSSergey Kambalin     s->lev0 = 0;
31123c82c1dSSergey Kambalin     s->lev1 = 0;
31223c82c1dSSergey Kambalin 
31323c82c1dSSergey Kambalin     memset(s->fsel, 0, sizeof(s->fsel));
31423c82c1dSSergey Kambalin 
31523c82c1dSSergey Kambalin     s->pup_cntrl_reg[0] = RESET_VAL_CNTRL_REG0;
31623c82c1dSSergey Kambalin     s->pup_cntrl_reg[1] = RESET_VAL_CNTRL_REG1;
31723c82c1dSSergey Kambalin     s->pup_cntrl_reg[2] = RESET_VAL_CNTRL_REG2;
31823c82c1dSSergey Kambalin     s->pup_cntrl_reg[3] = RESET_VAL_CNTRL_REG3;
31923c82c1dSSergey Kambalin }
32023c82c1dSSergey Kambalin 
32123c82c1dSSergey Kambalin static const MemoryRegionOps bcm2838_gpio_ops = {
32223c82c1dSSergey Kambalin     .read = bcm2838_gpio_read,
32323c82c1dSSergey Kambalin     .write = bcm2838_gpio_write,
32423c82c1dSSergey Kambalin     .endianness = DEVICE_NATIVE_ENDIAN,
32523c82c1dSSergey Kambalin };
32623c82c1dSSergey Kambalin 
32723c82c1dSSergey Kambalin static const VMStateDescription vmstate_bcm2838_gpio = {
32823c82c1dSSergey Kambalin     .name = "bcm2838_gpio",
32923c82c1dSSergey Kambalin     .version_id = 1,
33023c82c1dSSergey Kambalin     .minimum_version_id = 1,
33123c82c1dSSergey Kambalin     .fields = (VMStateField[]) {
33223c82c1dSSergey Kambalin         VMSTATE_UINT8_ARRAY(fsel, BCM2838GpioState, BCM2838_GPIO_NUM),
33323c82c1dSSergey Kambalin         VMSTATE_UINT32(lev0, BCM2838GpioState),
33423c82c1dSSergey Kambalin         VMSTATE_UINT32(lev1, BCM2838GpioState),
33523c82c1dSSergey Kambalin         VMSTATE_UINT8(sd_fsel, BCM2838GpioState),
33623c82c1dSSergey Kambalin         VMSTATE_UINT32_ARRAY(pup_cntrl_reg, BCM2838GpioState,
33723c82c1dSSergey Kambalin                              GPIO_PUP_PDN_CNTRL_NUM),
33823c82c1dSSergey Kambalin         VMSTATE_END_OF_LIST()
33923c82c1dSSergey Kambalin     }
34023c82c1dSSergey Kambalin };
34123c82c1dSSergey Kambalin 
bcm2838_gpio_init(Object * obj)34223c82c1dSSergey Kambalin static void bcm2838_gpio_init(Object *obj)
34323c82c1dSSergey Kambalin {
34423c82c1dSSergey Kambalin     BCM2838GpioState *s = BCM2838_GPIO(obj);
34523c82c1dSSergey Kambalin     DeviceState *dev = DEVICE(obj);
34623c82c1dSSergey Kambalin     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
34723c82c1dSSergey Kambalin 
348*b54a9a56SSergey Kambalin     qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS, DEVICE(s), "sd-bus");
349*b54a9a56SSergey Kambalin 
35023c82c1dSSergey Kambalin     memory_region_init_io(&s->iomem, obj, &bcm2838_gpio_ops, s,
35123c82c1dSSergey Kambalin                           "bcm2838_gpio", BCM2838_GPIO_REGS_SIZE);
35223c82c1dSSergey Kambalin     sysbus_init_mmio(sbd, &s->iomem);
35323c82c1dSSergey Kambalin     qdev_init_gpio_out(dev, s->out, BCM2838_GPIO_NUM);
35423c82c1dSSergey Kambalin }
35523c82c1dSSergey Kambalin 
bcm2838_gpio_realize(DeviceState * dev,Error ** errp)35623c82c1dSSergey Kambalin static void bcm2838_gpio_realize(DeviceState *dev, Error **errp)
35723c82c1dSSergey Kambalin {
358*b54a9a56SSergey Kambalin     BCM2838GpioState *s = BCM2838_GPIO(dev);
359*b54a9a56SSergey Kambalin     Object *obj;
360*b54a9a56SSergey Kambalin 
361*b54a9a56SSergey Kambalin     obj = object_property_get_link(OBJECT(dev), "sdbus-sdhci", &error_abort);
362*b54a9a56SSergey Kambalin     s->sdbus_sdhci = SD_BUS(obj);
363*b54a9a56SSergey Kambalin 
364*b54a9a56SSergey Kambalin     obj = object_property_get_link(OBJECT(dev), "sdbus-sdhost", &error_abort);
365*b54a9a56SSergey Kambalin     s->sdbus_sdhost = SD_BUS(obj);
36623c82c1dSSergey Kambalin }
36723c82c1dSSergey Kambalin 
bcm2838_gpio_class_init(ObjectClass * klass,void * data)36823c82c1dSSergey Kambalin static void bcm2838_gpio_class_init(ObjectClass *klass, void *data)
36923c82c1dSSergey Kambalin {
37023c82c1dSSergey Kambalin     DeviceClass *dc = DEVICE_CLASS(klass);
37123c82c1dSSergey Kambalin 
37223c82c1dSSergey Kambalin     dc->vmsd = &vmstate_bcm2838_gpio;
37323c82c1dSSergey Kambalin     dc->realize = &bcm2838_gpio_realize;
37423c82c1dSSergey Kambalin     dc->reset = &bcm2838_gpio_reset;
37523c82c1dSSergey Kambalin }
37623c82c1dSSergey Kambalin 
37723c82c1dSSergey Kambalin static const TypeInfo bcm2838_gpio_info = {
37823c82c1dSSergey Kambalin     .name          = TYPE_BCM2838_GPIO,
37923c82c1dSSergey Kambalin     .parent        = TYPE_SYS_BUS_DEVICE,
38023c82c1dSSergey Kambalin     .instance_size = sizeof(BCM2838GpioState),
38123c82c1dSSergey Kambalin     .instance_init = bcm2838_gpio_init,
38223c82c1dSSergey Kambalin     .class_init    = bcm2838_gpio_class_init,
38323c82c1dSSergey Kambalin };
38423c82c1dSSergey Kambalin 
bcm2838_gpio_register_types(void)38523c82c1dSSergey Kambalin static void bcm2838_gpio_register_types(void)
38623c82c1dSSergey Kambalin {
38723c82c1dSSergey Kambalin     type_register_static(&bcm2838_gpio_info);
38823c82c1dSSergey Kambalin }
38923c82c1dSSergey Kambalin 
39023c82c1dSSergey Kambalin type_init(bcm2838_gpio_register_types)
391