1d72fc9dcSClement Deschamps /* 2d72fc9dcSClement Deschamps * Raspberry Pi (BCM2835) GPIO Controller 3d72fc9dcSClement Deschamps * 4d72fc9dcSClement Deschamps * Copyright (c) 2017 Antfield SAS 5d72fc9dcSClement Deschamps * 6d72fc9dcSClement Deschamps * Authors: 7d72fc9dcSClement Deschamps * Clement Deschamps <clement.deschamps@antfield.fr> 8d72fc9dcSClement Deschamps * Luc Michel <luc.michel@antfield.fr> 9d72fc9dcSClement Deschamps * 10d72fc9dcSClement Deschamps * This work is licensed under the terms of the GNU GPL, version 2 or later. 11d72fc9dcSClement Deschamps * See the COPYING file in the top-level directory. 12d72fc9dcSClement Deschamps */ 13d72fc9dcSClement Deschamps 14d72fc9dcSClement Deschamps #include "qemu/osdep.h" 15d72fc9dcSClement Deschamps #include "qemu/log.h" 160b8fa32fSMarkus Armbruster #include "qemu/module.h" 17d72fc9dcSClement Deschamps #include "qemu/timer.h" 18d72fc9dcSClement Deschamps #include "qapi/error.h" 19d72fc9dcSClement Deschamps #include "hw/sysbus.h" 20d6454270SMarkus Armbruster #include "migration/vmstate.h" 21d72fc9dcSClement Deschamps #include "hw/sd/sd.h" 22d72fc9dcSClement Deschamps #include "hw/gpio/bcm2835_gpio.h" 2364552b6bSMarkus Armbruster #include "hw/irq.h" 24d72fc9dcSClement Deschamps 25d72fc9dcSClement Deschamps #define GPFSEL0 0x00 26d72fc9dcSClement Deschamps #define GPFSEL1 0x04 27d72fc9dcSClement Deschamps #define GPFSEL2 0x08 28d72fc9dcSClement Deschamps #define GPFSEL3 0x0C 29d72fc9dcSClement Deschamps #define GPFSEL4 0x10 30d72fc9dcSClement Deschamps #define GPFSEL5 0x14 31d72fc9dcSClement Deschamps #define GPSET0 0x1C 32d72fc9dcSClement Deschamps #define GPSET1 0x20 33d72fc9dcSClement Deschamps #define GPCLR0 0x28 34d72fc9dcSClement Deschamps #define GPCLR1 0x2C 35d72fc9dcSClement Deschamps #define GPLEV0 0x34 36d72fc9dcSClement Deschamps #define GPLEV1 0x38 37d72fc9dcSClement Deschamps #define GPEDS0 0x40 38d72fc9dcSClement Deschamps #define GPEDS1 0x44 39d72fc9dcSClement Deschamps #define GPREN0 0x4C 40d72fc9dcSClement Deschamps #define GPREN1 0x50 41d72fc9dcSClement Deschamps #define GPFEN0 0x58 42d72fc9dcSClement Deschamps #define GPFEN1 0x5C 43d72fc9dcSClement Deschamps #define GPHEN0 0x64 44d72fc9dcSClement Deschamps #define GPHEN1 0x68 45d72fc9dcSClement Deschamps #define GPLEN0 0x70 46d72fc9dcSClement Deschamps #define GPLEN1 0x74 47d72fc9dcSClement Deschamps #define GPAREN0 0x7C 48d72fc9dcSClement Deschamps #define GPAREN1 0x80 49d72fc9dcSClement Deschamps #define GPAFEN0 0x88 50d72fc9dcSClement Deschamps #define GPAFEN1 0x8C 51d72fc9dcSClement Deschamps #define GPPUD 0x94 52d72fc9dcSClement Deschamps #define GPPUDCLK0 0x98 53d72fc9dcSClement Deschamps #define GPPUDCLK1 0x9C 54d72fc9dcSClement Deschamps 55d72fc9dcSClement Deschamps static uint32_t gpfsel_get(BCM2835GpioState *s, uint8_t reg) 56d72fc9dcSClement Deschamps { 57d72fc9dcSClement Deschamps int i; 58d72fc9dcSClement Deschamps uint32_t value = 0; 59d72fc9dcSClement Deschamps for (i = 0; i < 10; i++) { 60d72fc9dcSClement Deschamps uint32_t index = 10 * reg + i; 61d72fc9dcSClement Deschamps if (index < sizeof(s->fsel)) { 62d72fc9dcSClement Deschamps value |= (s->fsel[index] & 0x7) << (3 * i); 63d72fc9dcSClement Deschamps } 64d72fc9dcSClement Deschamps } 65d72fc9dcSClement Deschamps return value; 66d72fc9dcSClement Deschamps } 67d72fc9dcSClement Deschamps 68d72fc9dcSClement Deschamps static void gpfsel_set(BCM2835GpioState *s, uint8_t reg, uint32_t value) 69d72fc9dcSClement Deschamps { 70d72fc9dcSClement Deschamps int i; 71d72fc9dcSClement Deschamps for (i = 0; i < 10; i++) { 72d72fc9dcSClement Deschamps uint32_t index = 10 * reg + i; 73d72fc9dcSClement Deschamps if (index < sizeof(s->fsel)) { 74d72fc9dcSClement Deschamps int fsel = (value >> (3 * i)) & 0x7; 75d72fc9dcSClement Deschamps s->fsel[index] = fsel; 76d72fc9dcSClement Deschamps } 77d72fc9dcSClement Deschamps } 78d72fc9dcSClement Deschamps 79d72fc9dcSClement Deschamps /* SD controller selection (48-53) */ 80d72fc9dcSClement Deschamps if (s->sd_fsel != 0 81d72fc9dcSClement Deschamps && (s->fsel[48] == 0) /* SD_CLK_R */ 82d72fc9dcSClement Deschamps && (s->fsel[49] == 0) /* SD_CMD_R */ 83d72fc9dcSClement Deschamps && (s->fsel[50] == 0) /* SD_DATA0_R */ 84d72fc9dcSClement Deschamps && (s->fsel[51] == 0) /* SD_DATA1_R */ 85d72fc9dcSClement Deschamps && (s->fsel[52] == 0) /* SD_DATA2_R */ 86d72fc9dcSClement Deschamps && (s->fsel[53] == 0) /* SD_DATA3_R */ 87d72fc9dcSClement Deschamps ) { 88d72fc9dcSClement Deschamps /* SDHCI controller selected */ 89d72fc9dcSClement Deschamps sdbus_reparent_card(s->sdbus_sdhost, s->sdbus_sdhci); 90d72fc9dcSClement Deschamps s->sd_fsel = 0; 91d72fc9dcSClement Deschamps } else if (s->sd_fsel != 4 92d72fc9dcSClement Deschamps && (s->fsel[48] == 4) /* SD_CLK_R */ 93d72fc9dcSClement Deschamps && (s->fsel[49] == 4) /* SD_CMD_R */ 94d72fc9dcSClement Deschamps && (s->fsel[50] == 4) /* SD_DATA0_R */ 95d72fc9dcSClement Deschamps && (s->fsel[51] == 4) /* SD_DATA1_R */ 96d72fc9dcSClement Deschamps && (s->fsel[52] == 4) /* SD_DATA2_R */ 97d72fc9dcSClement Deschamps && (s->fsel[53] == 4) /* SD_DATA3_R */ 98d72fc9dcSClement Deschamps ) { 99d72fc9dcSClement Deschamps /* SDHost controller selected */ 100d72fc9dcSClement Deschamps sdbus_reparent_card(s->sdbus_sdhci, s->sdbus_sdhost); 101d72fc9dcSClement Deschamps s->sd_fsel = 4; 102d72fc9dcSClement Deschamps } 103d72fc9dcSClement Deschamps } 104d72fc9dcSClement Deschamps 105d72fc9dcSClement Deschamps static int gpfsel_is_out(BCM2835GpioState *s, int index) 106d72fc9dcSClement Deschamps { 107d72fc9dcSClement Deschamps if (index >= 0 && index < 54) { 108d72fc9dcSClement Deschamps return s->fsel[index] == 1; 109d72fc9dcSClement Deschamps } 110d72fc9dcSClement Deschamps return 0; 111d72fc9dcSClement Deschamps } 112d72fc9dcSClement Deschamps 113d72fc9dcSClement Deschamps static void gpset(BCM2835GpioState *s, 114d72fc9dcSClement Deschamps uint32_t val, uint8_t start, uint8_t count, uint32_t *lev) 115d72fc9dcSClement Deschamps { 116d72fc9dcSClement Deschamps uint32_t changes = val & ~*lev; 117d72fc9dcSClement Deschamps uint32_t cur = 1; 118d72fc9dcSClement Deschamps 119d72fc9dcSClement Deschamps int i; 120d72fc9dcSClement Deschamps for (i = 0; i < count; i++) { 121d72fc9dcSClement Deschamps if ((changes & cur) && (gpfsel_is_out(s, start + i))) { 122d72fc9dcSClement Deschamps qemu_set_irq(s->out[start + i], 1); 123d72fc9dcSClement Deschamps } 124d72fc9dcSClement Deschamps cur <<= 1; 125d72fc9dcSClement Deschamps } 126d72fc9dcSClement Deschamps 127d72fc9dcSClement Deschamps *lev |= val; 128d72fc9dcSClement Deschamps } 129d72fc9dcSClement Deschamps 130d72fc9dcSClement Deschamps static void gpclr(BCM2835GpioState *s, 131d72fc9dcSClement Deschamps uint32_t val, uint8_t start, uint8_t count, uint32_t *lev) 132d72fc9dcSClement Deschamps { 133d72fc9dcSClement Deschamps uint32_t changes = val & *lev; 134d72fc9dcSClement Deschamps uint32_t cur = 1; 135d72fc9dcSClement Deschamps 136d72fc9dcSClement Deschamps int i; 137d72fc9dcSClement Deschamps for (i = 0; i < count; i++) { 138d72fc9dcSClement Deschamps if ((changes & cur) && (gpfsel_is_out(s, start + i))) { 139d72fc9dcSClement Deschamps qemu_set_irq(s->out[start + i], 0); 140d72fc9dcSClement Deschamps } 141d72fc9dcSClement Deschamps cur <<= 1; 142d72fc9dcSClement Deschamps } 143d72fc9dcSClement Deschamps 144d72fc9dcSClement Deschamps *lev &= ~val; 145d72fc9dcSClement Deschamps } 146d72fc9dcSClement Deschamps 147d72fc9dcSClement Deschamps static uint64_t bcm2835_gpio_read(void *opaque, hwaddr offset, 148d72fc9dcSClement Deschamps unsigned size) 149d72fc9dcSClement Deschamps { 150d72fc9dcSClement Deschamps BCM2835GpioState *s = (BCM2835GpioState *)opaque; 151d72fc9dcSClement Deschamps 152d72fc9dcSClement Deschamps switch (offset) { 153d72fc9dcSClement Deschamps case GPFSEL0: 154d72fc9dcSClement Deschamps case GPFSEL1: 155d72fc9dcSClement Deschamps case GPFSEL2: 156d72fc9dcSClement Deschamps case GPFSEL3: 157d72fc9dcSClement Deschamps case GPFSEL4: 158d72fc9dcSClement Deschamps case GPFSEL5: 159d72fc9dcSClement Deschamps return gpfsel_get(s, offset / 4); 160d72fc9dcSClement Deschamps case GPSET0: 161d72fc9dcSClement Deschamps case GPSET1: 162d72fc9dcSClement Deschamps /* Write Only */ 163d72fc9dcSClement Deschamps return 0; 164d72fc9dcSClement Deschamps case GPCLR0: 165d72fc9dcSClement Deschamps case GPCLR1: 166d72fc9dcSClement Deschamps /* Write Only */ 167d72fc9dcSClement Deschamps return 0; 168d72fc9dcSClement Deschamps case GPLEV0: 169d72fc9dcSClement Deschamps return s->lev0; 170d72fc9dcSClement Deschamps case GPLEV1: 171d72fc9dcSClement Deschamps return s->lev1; 172d72fc9dcSClement Deschamps case GPEDS0: 173d72fc9dcSClement Deschamps case GPEDS1: 174d72fc9dcSClement Deschamps case GPREN0: 175d72fc9dcSClement Deschamps case GPREN1: 176d72fc9dcSClement Deschamps case GPFEN0: 177d72fc9dcSClement Deschamps case GPFEN1: 178d72fc9dcSClement Deschamps case GPHEN0: 179d72fc9dcSClement Deschamps case GPHEN1: 180d72fc9dcSClement Deschamps case GPLEN0: 181d72fc9dcSClement Deschamps case GPLEN1: 182d72fc9dcSClement Deschamps case GPAREN0: 183d72fc9dcSClement Deschamps case GPAREN1: 184d72fc9dcSClement Deschamps case GPAFEN0: 185d72fc9dcSClement Deschamps case GPAFEN1: 186d72fc9dcSClement Deschamps case GPPUD: 187d72fc9dcSClement Deschamps case GPPUDCLK0: 188d72fc9dcSClement Deschamps case GPPUDCLK1: 189d72fc9dcSClement Deschamps /* Not implemented */ 190d72fc9dcSClement Deschamps return 0; 191d72fc9dcSClement Deschamps default: 192d72fc9dcSClement Deschamps qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 193d72fc9dcSClement Deschamps __func__, offset); 194d72fc9dcSClement Deschamps break; 195d72fc9dcSClement Deschamps } 196d72fc9dcSClement Deschamps 197d72fc9dcSClement Deschamps return 0; 198d72fc9dcSClement Deschamps } 199d72fc9dcSClement Deschamps 200d72fc9dcSClement Deschamps static void bcm2835_gpio_write(void *opaque, hwaddr offset, 201d72fc9dcSClement Deschamps uint64_t value, unsigned size) 202d72fc9dcSClement Deschamps { 203d72fc9dcSClement Deschamps BCM2835GpioState *s = (BCM2835GpioState *)opaque; 204d72fc9dcSClement Deschamps 205d72fc9dcSClement Deschamps switch (offset) { 206d72fc9dcSClement Deschamps case GPFSEL0: 207d72fc9dcSClement Deschamps case GPFSEL1: 208d72fc9dcSClement Deschamps case GPFSEL2: 209d72fc9dcSClement Deschamps case GPFSEL3: 210d72fc9dcSClement Deschamps case GPFSEL4: 211d72fc9dcSClement Deschamps case GPFSEL5: 212d72fc9dcSClement Deschamps gpfsel_set(s, offset / 4, value); 213d72fc9dcSClement Deschamps break; 214d72fc9dcSClement Deschamps case GPSET0: 215d72fc9dcSClement Deschamps gpset(s, value, 0, 32, &s->lev0); 216d72fc9dcSClement Deschamps break; 217d72fc9dcSClement Deschamps case GPSET1: 218d72fc9dcSClement Deschamps gpset(s, value, 32, 22, &s->lev1); 219d72fc9dcSClement Deschamps break; 220d72fc9dcSClement Deschamps case GPCLR0: 221d72fc9dcSClement Deschamps gpclr(s, value, 0, 32, &s->lev0); 222d72fc9dcSClement Deschamps break; 223d72fc9dcSClement Deschamps case GPCLR1: 224d72fc9dcSClement Deschamps gpclr(s, value, 32, 22, &s->lev1); 225d72fc9dcSClement Deschamps break; 226d72fc9dcSClement Deschamps case GPLEV0: 227d72fc9dcSClement Deschamps case GPLEV1: 228d72fc9dcSClement Deschamps /* Read Only */ 229d72fc9dcSClement Deschamps break; 230d72fc9dcSClement Deschamps case GPEDS0: 231d72fc9dcSClement Deschamps case GPEDS1: 232d72fc9dcSClement Deschamps case GPREN0: 233d72fc9dcSClement Deschamps case GPREN1: 234d72fc9dcSClement Deschamps case GPFEN0: 235d72fc9dcSClement Deschamps case GPFEN1: 236d72fc9dcSClement Deschamps case GPHEN0: 237d72fc9dcSClement Deschamps case GPHEN1: 238d72fc9dcSClement Deschamps case GPLEN0: 239d72fc9dcSClement Deschamps case GPLEN1: 240d72fc9dcSClement Deschamps case GPAREN0: 241d72fc9dcSClement Deschamps case GPAREN1: 242d72fc9dcSClement Deschamps case GPAFEN0: 243d72fc9dcSClement Deschamps case GPAFEN1: 244d72fc9dcSClement Deschamps case GPPUD: 245d72fc9dcSClement Deschamps case GPPUDCLK0: 246d72fc9dcSClement Deschamps case GPPUDCLK1: 247d72fc9dcSClement Deschamps /* Not implemented */ 248d72fc9dcSClement Deschamps break; 249d72fc9dcSClement Deschamps default: 250d72fc9dcSClement Deschamps goto err_out; 251d72fc9dcSClement Deschamps } 252d72fc9dcSClement Deschamps return; 253d72fc9dcSClement Deschamps 254d72fc9dcSClement Deschamps err_out: 255d72fc9dcSClement Deschamps qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 256d72fc9dcSClement Deschamps __func__, offset); 257d72fc9dcSClement Deschamps } 258d72fc9dcSClement Deschamps 259d72fc9dcSClement Deschamps static void bcm2835_gpio_reset(DeviceState *dev) 260d72fc9dcSClement Deschamps { 261d72fc9dcSClement Deschamps BCM2835GpioState *s = BCM2835_GPIO(dev); 262d72fc9dcSClement Deschamps 263d72fc9dcSClement Deschamps int i; 264d72fc9dcSClement Deschamps for (i = 0; i < 6; i++) { 265d72fc9dcSClement Deschamps gpfsel_set(s, i, 0); 266d72fc9dcSClement Deschamps } 267d72fc9dcSClement Deschamps 268d72fc9dcSClement Deschamps s->sd_fsel = 0; 269d72fc9dcSClement Deschamps 270d72fc9dcSClement Deschamps /* SDHCI is selected by default */ 271d72fc9dcSClement Deschamps sdbus_reparent_card(&s->sdbus, s->sdbus_sdhci); 272d72fc9dcSClement Deschamps 273d72fc9dcSClement Deschamps s->lev0 = 0; 274d72fc9dcSClement Deschamps s->lev1 = 0; 275d72fc9dcSClement Deschamps } 276d72fc9dcSClement Deschamps 277d72fc9dcSClement Deschamps static const MemoryRegionOps bcm2835_gpio_ops = { 278d72fc9dcSClement Deschamps .read = bcm2835_gpio_read, 279d72fc9dcSClement Deschamps .write = bcm2835_gpio_write, 280d72fc9dcSClement Deschamps .endianness = DEVICE_NATIVE_ENDIAN, 281d72fc9dcSClement Deschamps }; 282d72fc9dcSClement Deschamps 283d72fc9dcSClement Deschamps static const VMStateDescription vmstate_bcm2835_gpio = { 284d72fc9dcSClement Deschamps .name = "bcm2835_gpio", 285d72fc9dcSClement Deschamps .version_id = 1, 286d72fc9dcSClement Deschamps .minimum_version_id = 1, 2873b9e779bSRichard Henderson .fields = (const VMStateField[]) { 288d72fc9dcSClement Deschamps VMSTATE_UINT8_ARRAY(fsel, BCM2835GpioState, 54), 289d72fc9dcSClement Deschamps VMSTATE_UINT32(lev0, BCM2835GpioState), 290d72fc9dcSClement Deschamps VMSTATE_UINT32(lev1, BCM2835GpioState), 291d72fc9dcSClement Deschamps VMSTATE_UINT8(sd_fsel, BCM2835GpioState), 292d72fc9dcSClement Deschamps VMSTATE_END_OF_LIST() 293d72fc9dcSClement Deschamps } 294d72fc9dcSClement Deschamps }; 295d72fc9dcSClement Deschamps 296d72fc9dcSClement Deschamps static void bcm2835_gpio_init(Object *obj) 297d72fc9dcSClement Deschamps { 298d72fc9dcSClement Deschamps BCM2835GpioState *s = BCM2835_GPIO(obj); 299d72fc9dcSClement Deschamps DeviceState *dev = DEVICE(obj); 300d72fc9dcSClement Deschamps SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 301d72fc9dcSClement Deschamps 302d637e1dcSPeter Maydell qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS, DEVICE(s), "sd-bus"); 303d72fc9dcSClement Deschamps 304d72fc9dcSClement Deschamps memory_region_init_io(&s->iomem, obj, 305d72fc9dcSClement Deschamps &bcm2835_gpio_ops, s, "bcm2835_gpio", 0x1000); 306d72fc9dcSClement Deschamps sysbus_init_mmio(sbd, &s->iomem); 307d72fc9dcSClement Deschamps qdev_init_gpio_out(dev, s->out, 54); 308d72fc9dcSClement Deschamps } 309d72fc9dcSClement Deschamps 310d72fc9dcSClement Deschamps static void bcm2835_gpio_realize(DeviceState *dev, Error **errp) 311d72fc9dcSClement Deschamps { 312d72fc9dcSClement Deschamps BCM2835GpioState *s = BCM2835_GPIO(dev); 313d72fc9dcSClement Deschamps Object *obj; 314d72fc9dcSClement Deschamps 3154d21fcd5SMarkus Armbruster obj = object_property_get_link(OBJECT(dev), "sdbus-sdhci", &error_abort); 316d72fc9dcSClement Deschamps s->sdbus_sdhci = SD_BUS(obj); 317d72fc9dcSClement Deschamps 3184d21fcd5SMarkus Armbruster obj = object_property_get_link(OBJECT(dev), "sdbus-sdhost", &error_abort); 319d72fc9dcSClement Deschamps s->sdbus_sdhost = SD_BUS(obj); 320d72fc9dcSClement Deschamps } 321d72fc9dcSClement Deschamps 322d72fc9dcSClement Deschamps static void bcm2835_gpio_class_init(ObjectClass *klass, void *data) 323d72fc9dcSClement Deschamps { 324d72fc9dcSClement Deschamps DeviceClass *dc = DEVICE_CLASS(klass); 325d72fc9dcSClement Deschamps 326d72fc9dcSClement Deschamps dc->vmsd = &vmstate_bcm2835_gpio; 327d72fc9dcSClement Deschamps dc->realize = &bcm2835_gpio_realize; 328*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, bcm2835_gpio_reset); 329d72fc9dcSClement Deschamps } 330d72fc9dcSClement Deschamps 331d72fc9dcSClement Deschamps static const TypeInfo bcm2835_gpio_info = { 332d72fc9dcSClement Deschamps .name = TYPE_BCM2835_GPIO, 333d72fc9dcSClement Deschamps .parent = TYPE_SYS_BUS_DEVICE, 334d72fc9dcSClement Deschamps .instance_size = sizeof(BCM2835GpioState), 335d72fc9dcSClement Deschamps .instance_init = bcm2835_gpio_init, 336d72fc9dcSClement Deschamps .class_init = bcm2835_gpio_class_init, 337d72fc9dcSClement Deschamps }; 338d72fc9dcSClement Deschamps 339d72fc9dcSClement Deschamps static void bcm2835_gpio_register_types(void) 340d72fc9dcSClement Deschamps { 341d72fc9dcSClement Deschamps type_register_static(&bcm2835_gpio_info); 342d72fc9dcSClement Deschamps } 343d72fc9dcSClement Deschamps 344d72fc9dcSClement Deschamps type_init(bcm2835_gpio_register_types) 345