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/module.h"
17 #include "qemu/timer.h"
18 #include "qapi/error.h"
19 #include "hw/sysbus.h"
21 #include "hw/gpio/bcm2835_gpio.h"
50 #define GPPUDCLK0 0x98
51 #define GPPUDCLK1 0x9C
53 static uint32_t gpfsel_get(BCM2835GpioState
*s
, uint8_t reg
)
57 for (i
= 0; i
< 10; i
++) {
58 uint32_t index
= 10 * reg
+ i
;
59 if (index
< sizeof(s
->fsel
)) {
60 value
|= (s
->fsel
[index
] & 0x7) << (3 * i
);
66 static void gpfsel_set(BCM2835GpioState
*s
, uint8_t reg
, uint32_t value
)
69 for (i
= 0; i
< 10; i
++) {
70 uint32_t index
= 10 * reg
+ i
;
71 if (index
< sizeof(s
->fsel
)) {
72 int fsel
= (value
>> (3 * i
)) & 0x7;
73 s
->fsel
[index
] = fsel
;
77 /* SD controller selection (48-53) */
79 && (s
->fsel
[48] == 0) /* SD_CLK_R */
80 && (s
->fsel
[49] == 0) /* SD_CMD_R */
81 && (s
->fsel
[50] == 0) /* SD_DATA0_R */
82 && (s
->fsel
[51] == 0) /* SD_DATA1_R */
83 && (s
->fsel
[52] == 0) /* SD_DATA2_R */
84 && (s
->fsel
[53] == 0) /* SD_DATA3_R */
86 /* SDHCI controller selected */
87 sdbus_reparent_card(s
->sdbus_sdhost
, s
->sdbus_sdhci
);
89 } else if (s
->sd_fsel
!= 4
90 && (s
->fsel
[48] == 4) /* SD_CLK_R */
91 && (s
->fsel
[49] == 4) /* SD_CMD_R */
92 && (s
->fsel
[50] == 4) /* SD_DATA0_R */
93 && (s
->fsel
[51] == 4) /* SD_DATA1_R */
94 && (s
->fsel
[52] == 4) /* SD_DATA2_R */
95 && (s
->fsel
[53] == 4) /* SD_DATA3_R */
97 /* SDHost controller selected */
98 sdbus_reparent_card(s
->sdbus_sdhci
, s
->sdbus_sdhost
);
103 static int gpfsel_is_out(BCM2835GpioState
*s
, int index
)
105 if (index
>= 0 && index
< 54) {
106 return s
->fsel
[index
] == 1;
111 static void gpset(BCM2835GpioState
*s
,
112 uint32_t val
, uint8_t start
, uint8_t count
, uint32_t *lev
)
114 uint32_t changes
= val
& ~*lev
;
118 for (i
= 0; i
< count
; i
++) {
119 if ((changes
& cur
) && (gpfsel_is_out(s
, start
+ i
))) {
120 qemu_set_irq(s
->out
[start
+ i
], 1);
128 static void gpclr(BCM2835GpioState
*s
,
129 uint32_t val
, uint8_t start
, uint8_t count
, uint32_t *lev
)
131 uint32_t changes
= val
& *lev
;
135 for (i
= 0; i
< count
; i
++) {
136 if ((changes
& cur
) && (gpfsel_is_out(s
, start
+ i
))) {
137 qemu_set_irq(s
->out
[start
+ i
], 0);
145 static uint64_t bcm2835_gpio_read(void *opaque
, hwaddr offset
,
148 BCM2835GpioState
*s
= (BCM2835GpioState
*)opaque
;
157 return gpfsel_get(s
, offset
/ 4);
187 /* Not implemented */
190 qemu_log_mask(LOG_GUEST_ERROR
, "%s: Bad offset %"HWADDR_PRIx
"\n",
198 static void bcm2835_gpio_write(void *opaque
, hwaddr offset
,
199 uint64_t value
, unsigned size
)
201 BCM2835GpioState
*s
= (BCM2835GpioState
*)opaque
;
210 gpfsel_set(s
, offset
/ 4, value
);
213 gpset(s
, value
, 0, 32, &s
->lev0
);
216 gpset(s
, value
, 32, 22, &s
->lev1
);
219 gpclr(s
, value
, 0, 32, &s
->lev0
);
222 gpclr(s
, value
, 32, 22, &s
->lev1
);
245 /* Not implemented */
253 qemu_log_mask(LOG_GUEST_ERROR
, "%s: Bad offset %"HWADDR_PRIx
"\n",
257 static void bcm2835_gpio_reset(DeviceState
*dev
)
259 BCM2835GpioState
*s
= BCM2835_GPIO(dev
);
262 for (i
= 0; i
< 6; i
++) {
268 /* SDHCI is selected by default */
269 sdbus_reparent_card(&s
->sdbus
, s
->sdbus_sdhci
);
275 static const MemoryRegionOps bcm2835_gpio_ops
= {
276 .read
= bcm2835_gpio_read
,
277 .write
= bcm2835_gpio_write
,
278 .endianness
= DEVICE_NATIVE_ENDIAN
,
281 static const VMStateDescription vmstate_bcm2835_gpio
= {
282 .name
= "bcm2835_gpio",
284 .minimum_version_id
= 1,
285 .fields
= (VMStateField
[]) {
286 VMSTATE_UINT8_ARRAY(fsel
, BCM2835GpioState
, 54),
287 VMSTATE_UINT32(lev0
, BCM2835GpioState
),
288 VMSTATE_UINT32(lev1
, BCM2835GpioState
),
289 VMSTATE_UINT8(sd_fsel
, BCM2835GpioState
),
290 VMSTATE_END_OF_LIST()
294 static void bcm2835_gpio_init(Object
*obj
)
296 BCM2835GpioState
*s
= BCM2835_GPIO(obj
);
297 DeviceState
*dev
= DEVICE(obj
);
298 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
300 qbus_create_inplace(&s
->sdbus
, sizeof(s
->sdbus
),
301 TYPE_SD_BUS
, DEVICE(s
), "sd-bus");
303 memory_region_init_io(&s
->iomem
, obj
,
304 &bcm2835_gpio_ops
, s
, "bcm2835_gpio", 0x1000);
305 sysbus_init_mmio(sbd
, &s
->iomem
);
306 qdev_init_gpio_out(dev
, s
->out
, 54);
309 static void bcm2835_gpio_realize(DeviceState
*dev
, Error
**errp
)
311 BCM2835GpioState
*s
= BCM2835_GPIO(dev
);
315 obj
= object_property_get_link(OBJECT(dev
), "sdbus-sdhci", &err
);
317 error_setg(errp
, "%s: required sdhci link not found: %s",
318 __func__
, error_get_pretty(err
));
321 s
->sdbus_sdhci
= SD_BUS(obj
);
323 obj
= object_property_get_link(OBJECT(dev
), "sdbus-sdhost", &err
);
325 error_setg(errp
, "%s: required sdhost link not found: %s",
326 __func__
, error_get_pretty(err
));
329 s
->sdbus_sdhost
= SD_BUS(obj
);
332 static void bcm2835_gpio_class_init(ObjectClass
*klass
, void *data
)
334 DeviceClass
*dc
= DEVICE_CLASS(klass
);
336 dc
->vmsd
= &vmstate_bcm2835_gpio
;
337 dc
->realize
= &bcm2835_gpio_realize
;
338 dc
->reset
= &bcm2835_gpio_reset
;
341 static const TypeInfo bcm2835_gpio_info
= {
342 .name
= TYPE_BCM2835_GPIO
,
343 .parent
= TYPE_SYS_BUS_DEVICE
,
344 .instance_size
= sizeof(BCM2835GpioState
),
345 .instance_init
= bcm2835_gpio_init
,
346 .class_init
= bcm2835_gpio_class_init
,
349 static void bcm2835_gpio_register_types(void)
351 type_register_static(&bcm2835_gpio_info
);
354 type_init(bcm2835_gpio_register_types
)