13
#include "qemu/osdep.h"
15
#include "qemu/module.h"
16
#include "qemu/timer.h"
17
#include "qapi/error.h"
19
#include "migration/vmstate.h"
21
#include "hw/gpio/bcm2838_gpio.h"
51
#define GPIO_PUP_PDN_CNTRL_REG0 0xE4
52
#define GPIO_PUP_PDN_CNTRL_REG1 0xE8
53
#define GPIO_PUP_PDN_CNTRL_REG2 0xEC
54
#define GPIO_PUP_PDN_CNTRL_REG3 0xF0
56
#define RESET_VAL_CNTRL_REG0 0xAAA95555
57
#define RESET_VAL_CNTRL_REG1 0xA0AAAAAA
58
#define RESET_VAL_CNTRL_REG2 0x50AAA95A
59
#define RESET_VAL_CNTRL_REG3 0x00055555
61
#define NUM_FSELN_IN_GPFSELN 10
62
#define NUM_BITS_FSELN 3
65
#define BYTES_IN_WORD 4
68
#define BCM2838_FSEL_GPIO_IN 0
69
#define BCM2838_FSEL_GPIO_OUT 1
70
#define BCM2838_FSEL_ALT5 2
71
#define BCM2838_FSEL_ALT4 3
72
#define BCM2838_FSEL_ALT0 4
73
#define BCM2838_FSEL_ALT1 5
74
#define BCM2838_FSEL_ALT2 6
75
#define BCM2838_FSEL_ALT3 7
77
static uint32_t gpfsel_get(BCM2838GpioState *s, uint8_t reg)
81
for (i = 0; i < NUM_FSELN_IN_GPFSELN; i++) {
82
uint32_t index = NUM_FSELN_IN_GPFSELN * reg + i;
83
if (index < sizeof(s->fsel)) {
84
value |= (s->fsel[index] & MASK_FSELN) << (NUM_BITS_FSELN * i);
90
static void gpfsel_set(BCM2838GpioState *s, uint8_t reg, uint32_t value)
93
for (i = 0; i < NUM_FSELN_IN_GPFSELN; i++) {
94
uint32_t index = NUM_FSELN_IN_GPFSELN * reg + i;
95
if (index < sizeof(s->fsel)) {
96
int fsel = (value >> (NUM_BITS_FSELN * i)) & MASK_FSELN;
97
s->fsel[index] = fsel;
102
if (s->sd_fsel != BCM2838_FSEL_GPIO_IN
103
&& (s->fsel[48] == BCM2838_FSEL_GPIO_IN)
104
&& (s->fsel[49] == BCM2838_FSEL_GPIO_IN)
105
&& (s->fsel[50] == BCM2838_FSEL_GPIO_IN)
106
&& (s->fsel[51] == BCM2838_FSEL_GPIO_IN)
107
&& (s->fsel[52] == BCM2838_FSEL_GPIO_IN)
108
&& (s->fsel[53] == BCM2838_FSEL_GPIO_IN)
111
sdbus_reparent_card(s->sdbus_sdhost, s->sdbus_sdhci);
112
s->sd_fsel = BCM2838_FSEL_GPIO_IN;
113
} else if (s->sd_fsel != BCM2838_FSEL_ALT0
114
&& (s->fsel[48] == BCM2838_FSEL_ALT0)
115
&& (s->fsel[49] == BCM2838_FSEL_ALT0)
116
&& (s->fsel[50] == BCM2838_FSEL_ALT0)
117
&& (s->fsel[51] == BCM2838_FSEL_ALT0)
118
&& (s->fsel[52] == BCM2838_FSEL_ALT0)
119
&& (s->fsel[53] == BCM2838_FSEL_ALT0)
122
sdbus_reparent_card(s->sdbus_sdhci, s->sdbus_sdhost);
123
s->sd_fsel = BCM2838_FSEL_ALT0;
127
static int gpfsel_is_out(BCM2838GpioState *s, int index)
129
if (index >= 0 && index < BCM2838_GPIO_NUM) {
130
return s->fsel[index] == 1;
135
static void gpset(BCM2838GpioState *s, uint32_t val, uint8_t start,
136
uint8_t count, uint32_t *lev)
138
uint32_t changes = val & ~*lev;
142
for (i = 0; i < count; i++) {
143
if ((changes & cur) && (gpfsel_is_out(s, start + i))) {
144
qemu_set_irq(s->out[start + i], 1);
152
static void gpclr(BCM2838GpioState *s, uint32_t val, uint8_t start,
153
uint8_t count, uint32_t *lev)
155
uint32_t changes = val & *lev;
159
for (i = 0; i < count; i++) {
160
if ((changes & cur) && (gpfsel_is_out(s, start + i))) {
161
qemu_set_irq(s->out[start + i], 0);
169
static uint64_t bcm2838_gpio_read(void *opaque, hwaddr offset, unsigned size)
171
BCM2838GpioState *s = (BCM2838GpioState *)opaque;
181
value = gpfsel_get(s, offset / BYTES_IN_WORD);
188
qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: Attempt reading from write only"
189
" register. 0x%"PRIx64" will be returned."
190
" Address 0x%"HWADDR_PRIx", size %u\n",
191
TYPE_BCM2838_GPIO, __func__, value, offset, size);
214
qemu_log_mask(LOG_UNIMP, "%s: %s: not implemented for %"HWADDR_PRIx"\n",
215
TYPE_BCM2838_GPIO, __func__, offset);
217
case GPIO_PUP_PDN_CNTRL_REG0:
218
case GPIO_PUP_PDN_CNTRL_REG1:
219
case GPIO_PUP_PDN_CNTRL_REG2:
220
case GPIO_PUP_PDN_CNTRL_REG3:
221
value = s->pup_cntrl_reg[(offset - GPIO_PUP_PDN_CNTRL_REG0)
222
/ sizeof(s->pup_cntrl_reg[0])];
225
qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: bad offset %"HWADDR_PRIx"\n",
226
TYPE_BCM2838_GPIO, __func__, offset);
233
static void bcm2838_gpio_write(void *opaque, hwaddr offset, uint64_t value,
236
BCM2838GpioState *s = (BCM2838GpioState *)opaque;
245
gpfsel_set(s, offset / BYTES_IN_WORD, value);
248
gpset(s, value, 0, 32, &s->lev0);
251
gpset(s, value, 32, 22, &s->lev1);
254
gpclr(s, value, 0, 32, &s->lev0);
257
gpclr(s, value, 32, 22, &s->lev1);
262
qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: Attempt writing 0x%"PRIx64""
263
" to read only register. Ignored."
264
" Address 0x%"HWADDR_PRIx", size %u\n",
265
TYPE_BCM2838_GPIO, __func__, value, offset, size);
282
qemu_log_mask(LOG_UNIMP, "%s: %s: not implemented for %"HWADDR_PRIx"\n",
283
TYPE_BCM2838_GPIO, __func__, offset);
285
case GPIO_PUP_PDN_CNTRL_REG0:
286
case GPIO_PUP_PDN_CNTRL_REG1:
287
case GPIO_PUP_PDN_CNTRL_REG2:
288
case GPIO_PUP_PDN_CNTRL_REG3:
289
s->pup_cntrl_reg[(offset - GPIO_PUP_PDN_CNTRL_REG0)
290
/ sizeof(s->pup_cntrl_reg[0])] = value;
293
qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: bad offset %"HWADDR_PRIx"\n",
294
TYPE_BCM2838_GPIO, __func__, offset);
299
static void bcm2838_gpio_reset(DeviceState *dev)
301
BCM2838GpioState *s = BCM2838_GPIO(dev);
303
memset(s->fsel, 0, sizeof(s->fsel));
308
sdbus_reparent_card(&s->sdbus, s->sdbus_sdhci);
313
memset(s->fsel, 0, sizeof(s->fsel));
315
s->pup_cntrl_reg[0] = RESET_VAL_CNTRL_REG0;
316
s->pup_cntrl_reg[1] = RESET_VAL_CNTRL_REG1;
317
s->pup_cntrl_reg[2] = RESET_VAL_CNTRL_REG2;
318
s->pup_cntrl_reg[3] = RESET_VAL_CNTRL_REG3;
321
static const MemoryRegionOps bcm2838_gpio_ops = {
322
.read = bcm2838_gpio_read,
323
.write = bcm2838_gpio_write,
324
.endianness = DEVICE_NATIVE_ENDIAN,
327
static const VMStateDescription vmstate_bcm2838_gpio = {
328
.name = "bcm2838_gpio",
330
.minimum_version_id = 1,
331
.fields = (VMStateField[]) {
332
VMSTATE_UINT8_ARRAY(fsel, BCM2838GpioState, BCM2838_GPIO_NUM),
333
VMSTATE_UINT32(lev0, BCM2838GpioState),
334
VMSTATE_UINT32(lev1, BCM2838GpioState),
335
VMSTATE_UINT8(sd_fsel, BCM2838GpioState),
336
VMSTATE_UINT32_ARRAY(pup_cntrl_reg, BCM2838GpioState,
337
GPIO_PUP_PDN_CNTRL_NUM),
338
VMSTATE_END_OF_LIST()
342
static void bcm2838_gpio_init(Object *obj)
344
BCM2838GpioState *s = BCM2838_GPIO(obj);
345
DeviceState *dev = DEVICE(obj);
346
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
348
qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS, DEVICE(s), "sd-bus");
350
memory_region_init_io(&s->iomem, obj, &bcm2838_gpio_ops, s,
351
"bcm2838_gpio", BCM2838_GPIO_REGS_SIZE);
352
sysbus_init_mmio(sbd, &s->iomem);
353
qdev_init_gpio_out(dev, s->out, BCM2838_GPIO_NUM);
356
static void bcm2838_gpio_realize(DeviceState *dev, Error **errp)
358
BCM2838GpioState *s = BCM2838_GPIO(dev);
361
obj = object_property_get_link(OBJECT(dev), "sdbus-sdhci", &error_abort);
362
s->sdbus_sdhci = SD_BUS(obj);
364
obj = object_property_get_link(OBJECT(dev), "sdbus-sdhost", &error_abort);
365
s->sdbus_sdhost = SD_BUS(obj);
368
static void bcm2838_gpio_class_init(ObjectClass *klass, void *data)
370
DeviceClass *dc = DEVICE_CLASS(klass);
372
dc->vmsd = &vmstate_bcm2838_gpio;
373
dc->realize = &bcm2838_gpio_realize;
374
dc->reset = &bcm2838_gpio_reset;
377
static const TypeInfo bcm2838_gpio_info = {
378
.name = TYPE_BCM2838_GPIO,
379
.parent = TYPE_SYS_BUS_DEVICE,
380
.instance_size = sizeof(BCM2838GpioState),
381
.instance_init = bcm2838_gpio_init,
382
.class_init = bcm2838_gpio_class_init,
385
static void bcm2838_gpio_register_types(void)
387
type_register_static(&bcm2838_gpio_info);
390
type_init(bcm2838_gpio_register_types)