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