2 * Raspberry Pi (BCM2835) GPIO Controller
4 * Copyright (c) 2017 Antfield SAS
7 * Clement Deschamps <clement.deschamps@antfield.fr>
8 * Luc Michel <luc.michel@antfield.fr>
10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
11 * See the COPYING file in the top-level directory.
14 #include "qemu/osdep.h"
16 #include "qemu/timer.h"
17 #include "qapi/error.h"
18 #include "hw/sysbus.h"
20 #include "hw/gpio/bcm2835_gpio.h"
49 #define GPPUDCLK0 0x98
50 #define GPPUDCLK1 0x9C
52 static uint32_t gpfsel_get(BCM2835GpioState
*s
, uint8_t reg
)
56 for (i
= 0; i
< 10; i
++) {
57 uint32_t index
= 10 * reg
+ i
;
58 if (index
< sizeof(s
->fsel
)) {
59 value
|= (s
->fsel
[index
] & 0x7) << (3 * i
);
65 static void gpfsel_set(BCM2835GpioState
*s
, uint8_t reg
, uint32_t value
)
68 for (i
= 0; i
< 10; i
++) {
69 uint32_t index
= 10 * reg
+ i
;
70 if (index
< sizeof(s
->fsel
)) {
71 int fsel
= (value
>> (3 * i
)) & 0x7;
72 s
->fsel
[index
] = fsel
;
76 /* SD controller selection (48-53) */
78 && (s
->fsel
[48] == 0) /* SD_CLK_R */
79 && (s
->fsel
[49] == 0) /* SD_CMD_R */
80 && (s
->fsel
[50] == 0) /* SD_DATA0_R */
81 && (s
->fsel
[51] == 0) /* SD_DATA1_R */
82 && (s
->fsel
[52] == 0) /* SD_DATA2_R */
83 && (s
->fsel
[53] == 0) /* SD_DATA3_R */
85 /* SDHCI controller selected */
86 sdbus_reparent_card(s
->sdbus_sdhost
, s
->sdbus_sdhci
);
88 } else if (s
->sd_fsel
!= 4
89 && (s
->fsel
[48] == 4) /* SD_CLK_R */
90 && (s
->fsel
[49] == 4) /* SD_CMD_R */
91 && (s
->fsel
[50] == 4) /* SD_DATA0_R */
92 && (s
->fsel
[51] == 4) /* SD_DATA1_R */
93 && (s
->fsel
[52] == 4) /* SD_DATA2_R */
94 && (s
->fsel
[53] == 4) /* SD_DATA3_R */
96 /* SDHost controller selected */
97 sdbus_reparent_card(s
->sdbus_sdhci
, s
->sdbus_sdhost
);
102 static int gpfsel_is_out(BCM2835GpioState
*s
, int index
)
104 if (index
>= 0 && index
< 54) {
105 return s
->fsel
[index
] == 1;
110 static void gpset(BCM2835GpioState
*s
,
111 uint32_t val
, uint8_t start
, uint8_t count
, uint32_t *lev
)
113 uint32_t changes
= val
& ~*lev
;
117 for (i
= 0; i
< count
; i
++) {
118 if ((changes
& cur
) && (gpfsel_is_out(s
, start
+ i
))) {
119 qemu_set_irq(s
->out
[start
+ i
], 1);
127 static void gpclr(BCM2835GpioState
*s
,
128 uint32_t val
, uint8_t start
, uint8_t count
, uint32_t *lev
)
130 uint32_t changes
= val
& *lev
;
134 for (i
= 0; i
< count
; i
++) {
135 if ((changes
& cur
) && (gpfsel_is_out(s
, start
+ i
))) {
136 qemu_set_irq(s
->out
[start
+ i
], 0);
144 static uint64_t bcm2835_gpio_read(void *opaque
, hwaddr offset
,
147 BCM2835GpioState
*s
= (BCM2835GpioState
*)opaque
;
156 return gpfsel_get(s
, offset
/ 4);
186 /* Not implemented */
189 qemu_log_mask(LOG_GUEST_ERROR
, "%s: Bad offset %"HWADDR_PRIx
"\n",
197 static void bcm2835_gpio_write(void *opaque
, hwaddr offset
,
198 uint64_t value
, unsigned size
)
200 BCM2835GpioState
*s
= (BCM2835GpioState
*)opaque
;
209 gpfsel_set(s
, offset
/ 4, value
);
212 gpset(s
, value
, 0, 32, &s
->lev0
);
215 gpset(s
, value
, 32, 22, &s
->lev1
);
218 gpclr(s
, value
, 0, 32, &s
->lev0
);
221 gpclr(s
, value
, 32, 22, &s
->lev1
);
244 /* Not implemented */
252 qemu_log_mask(LOG_GUEST_ERROR
, "%s: Bad offset %"HWADDR_PRIx
"\n",
256 static void bcm2835_gpio_reset(DeviceState
*dev
)
258 BCM2835GpioState
*s
= BCM2835_GPIO(dev
);
261 for (i
= 0; i
< 6; i
++) {
267 /* SDHCI is selected by default */
268 sdbus_reparent_card(&s
->sdbus
, s
->sdbus_sdhci
);
274 static const MemoryRegionOps bcm2835_gpio_ops
= {
275 .read
= bcm2835_gpio_read
,
276 .write
= bcm2835_gpio_write
,
277 .endianness
= DEVICE_NATIVE_ENDIAN
,
280 static const VMStateDescription vmstate_bcm2835_gpio
= {
281 .name
= "bcm2835_gpio",
283 .minimum_version_id
= 1,
284 .fields
= (VMStateField
[]) {
285 VMSTATE_UINT8_ARRAY(fsel
, BCM2835GpioState
, 54),
286 VMSTATE_UINT32(lev0
, BCM2835GpioState
),
287 VMSTATE_UINT32(lev1
, BCM2835GpioState
),
288 VMSTATE_UINT8(sd_fsel
, BCM2835GpioState
),
289 VMSTATE_END_OF_LIST()
293 static void bcm2835_gpio_init(Object
*obj
)
295 BCM2835GpioState
*s
= BCM2835_GPIO(obj
);
296 DeviceState
*dev
= DEVICE(obj
);
297 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
299 qbus_create_inplace(&s
->sdbus
, sizeof(s
->sdbus
),
300 TYPE_SD_BUS
, DEVICE(s
), "sd-bus");
302 memory_region_init_io(&s
->iomem
, obj
,
303 &bcm2835_gpio_ops
, s
, "bcm2835_gpio", 0x1000);
304 sysbus_init_mmio(sbd
, &s
->iomem
);
305 qdev_init_gpio_out(dev
, s
->out
, 54);
308 static void bcm2835_gpio_realize(DeviceState
*dev
, Error
**errp
)
310 BCM2835GpioState
*s
= BCM2835_GPIO(dev
);
314 obj
= object_property_get_link(OBJECT(dev
), "sdbus-sdhci", &err
);
316 error_setg(errp
, "%s: required sdhci link not found: %s",
317 __func__
, error_get_pretty(err
));
320 s
->sdbus_sdhci
= SD_BUS(obj
);
322 obj
= object_property_get_link(OBJECT(dev
), "sdbus-sdhost", &err
);
324 error_setg(errp
, "%s: required sdhost link not found: %s",
325 __func__
, error_get_pretty(err
));
328 s
->sdbus_sdhost
= SD_BUS(obj
);
331 static void bcm2835_gpio_class_init(ObjectClass
*klass
, void *data
)
333 DeviceClass
*dc
= DEVICE_CLASS(klass
);
335 dc
->vmsd
= &vmstate_bcm2835_gpio
;
336 dc
->realize
= &bcm2835_gpio_realize
;
337 dc
->reset
= &bcm2835_gpio_reset
;
340 static const TypeInfo bcm2835_gpio_info
= {
341 .name
= TYPE_BCM2835_GPIO
,
342 .parent
= TYPE_SYS_BUS_DEVICE
,
343 .instance_size
= sizeof(BCM2835GpioState
),
344 .instance_init
= bcm2835_gpio_init
,
345 .class_init
= bcm2835_gpio_class_init
,
348 static void bcm2835_gpio_register_types(void)
350 type_register_static(&bcm2835_gpio_info
);
353 type_init(bcm2835_gpio_register_types
)