1 /* 2 * Raspberry Pi (BCM2838) GPIO Controller 3 * This implementation is based on bcm2835_gpio (hw/gpio/bcm2835_gpio.c) 4 * 5 * Copyright (c) 2022 Auriga LLC 6 * 7 * Authors: 8 * Lotosh, Aleksey <aleksey.lotosh@auriga.com> 9 * 10 * SPDX-License-Identifier: GPL-2.0-or-later 11 */ 12 13 #include "qemu/osdep.h" 14 #include "qemu/log.h" 15 #include "qemu/module.h" 16 #include "qemu/timer.h" 17 #include "qapi/error.h" 18 #include "hw/sysbus.h" 19 #include "migration/vmstate.h" 20 #include "hw/sd/sd.h" 21 #include "hw/gpio/bcm2838_gpio.h" 22 #include "hw/irq.h" 23 24 #define GPFSEL0 0x00 25 #define GPFSEL1 0x04 26 #define GPFSEL2 0x08 27 #define GPFSEL3 0x0C 28 #define GPFSEL4 0x10 29 #define GPFSEL5 0x14 30 #define GPSET0 0x1C 31 #define GPSET1 0x20 32 #define GPCLR0 0x28 33 #define GPCLR1 0x2C 34 #define GPLEV0 0x34 35 #define GPLEV1 0x38 36 #define GPEDS0 0x40 37 #define GPEDS1 0x44 38 #define GPREN0 0x4C 39 #define GPREN1 0x50 40 #define GPFEN0 0x58 41 #define GPFEN1 0x5C 42 #define GPHEN0 0x64 43 #define GPHEN1 0x68 44 #define GPLEN0 0x70 45 #define GPLEN1 0x74 46 #define GPAREN0 0x7C 47 #define GPAREN1 0x80 48 #define GPAFEN0 0x88 49 #define GPAFEN1 0x8C 50 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 55 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 60 61 #define NUM_FSELN_IN_GPFSELN 10 62 #define NUM_BITS_FSELN 3 63 #define MASK_FSELN 0x7 64 65 #define BYTES_IN_WORD 4 66 67 /* bcm,function property */ 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 76 77 static uint32_t gpfsel_get(BCM2838GpioState *s, uint8_t reg) 78 { 79 int i; 80 uint32_t value = 0; 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); 85 } 86 } 87 return value; 88 } 89 90 static void gpfsel_set(BCM2838GpioState *s, uint8_t reg, uint32_t value) 91 { 92 int i; 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; 98 } 99 } 100 101 /* SD controller selection (48-53) */ 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) 109 ) { 110 /* SDHCI controller selected */ 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) /* SD_CLK_R */ 115 && (s->fsel[49] == BCM2838_FSEL_ALT0) /* SD_CMD_R */ 116 && (s->fsel[50] == BCM2838_FSEL_ALT0) /* SD_DATA0_R */ 117 && (s->fsel[51] == BCM2838_FSEL_ALT0) /* SD_DATA1_R */ 118 && (s->fsel[52] == BCM2838_FSEL_ALT0) /* SD_DATA2_R */ 119 && (s->fsel[53] == BCM2838_FSEL_ALT0) /* SD_DATA3_R */ 120 ) { 121 /* SDHost controller selected */ 122 sdbus_reparent_card(s->sdbus_sdhci, s->sdbus_sdhost); 123 s->sd_fsel = BCM2838_FSEL_ALT0; 124 } 125 } 126 127 static int gpfsel_is_out(BCM2838GpioState *s, int index) 128 { 129 if (index >= 0 && index < BCM2838_GPIO_NUM) { 130 return s->fsel[index] == 1; 131 } 132 return 0; 133 } 134 135 static void gpset(BCM2838GpioState *s, uint32_t val, uint8_t start, 136 uint8_t count, uint32_t *lev) 137 { 138 uint32_t changes = val & ~*lev; 139 uint32_t cur = 1; 140 141 int i; 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); 145 } 146 cur <<= 1; 147 } 148 149 *lev |= val; 150 } 151 152 static void gpclr(BCM2838GpioState *s, uint32_t val, uint8_t start, 153 uint8_t count, uint32_t *lev) 154 { 155 uint32_t changes = val & *lev; 156 uint32_t cur = 1; 157 158 int i; 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); 162 } 163 cur <<= 1; 164 } 165 166 *lev &= ~val; 167 } 168 169 static uint64_t bcm2838_gpio_read(void *opaque, hwaddr offset, unsigned size) 170 { 171 BCM2838GpioState *s = (BCM2838GpioState *)opaque; 172 uint64_t value = 0; 173 174 switch (offset) { 175 case GPFSEL0: 176 case GPFSEL1: 177 case GPFSEL2: 178 case GPFSEL3: 179 case GPFSEL4: 180 case GPFSEL5: 181 value = gpfsel_get(s, offset / BYTES_IN_WORD); 182 break; 183 case GPSET0: 184 case GPSET1: 185 case GPCLR0: 186 case GPCLR1: 187 /* Write Only */ 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); 192 break; 193 case GPLEV0: 194 value = s->lev0; 195 break; 196 case GPLEV1: 197 value = s->lev1; 198 break; 199 case GPEDS0: 200 case GPEDS1: 201 case GPREN0: 202 case GPREN1: 203 case GPFEN0: 204 case GPFEN1: 205 case GPHEN0: 206 case GPHEN1: 207 case GPLEN0: 208 case GPLEN1: 209 case GPAREN0: 210 case GPAREN1: 211 case GPAFEN0: 212 case GPAFEN1: 213 /* Not implemented */ 214 qemu_log_mask(LOG_UNIMP, "%s: %s: not implemented for %"HWADDR_PRIx"\n", 215 TYPE_BCM2838_GPIO, __func__, offset); 216 break; 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])]; 223 break; 224 default: 225 qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: bad offset %"HWADDR_PRIx"\n", 226 TYPE_BCM2838_GPIO, __func__, offset); 227 break; 228 } 229 230 return value; 231 } 232 233 static void bcm2838_gpio_write(void *opaque, hwaddr offset, uint64_t value, 234 unsigned size) 235 { 236 BCM2838GpioState *s = (BCM2838GpioState *)opaque; 237 238 switch (offset) { 239 case GPFSEL0: 240 case GPFSEL1: 241 case GPFSEL2: 242 case GPFSEL3: 243 case GPFSEL4: 244 case GPFSEL5: 245 gpfsel_set(s, offset / BYTES_IN_WORD, value); 246 break; 247 case GPSET0: 248 gpset(s, value, 0, 32, &s->lev0); 249 break; 250 case GPSET1: 251 gpset(s, value, 32, 22, &s->lev1); 252 break; 253 case GPCLR0: 254 gpclr(s, value, 0, 32, &s->lev0); 255 break; 256 case GPCLR1: 257 gpclr(s, value, 32, 22, &s->lev1); 258 break; 259 case GPLEV0: 260 case GPLEV1: 261 /* Read Only */ 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); 266 break; 267 case GPEDS0: 268 case GPEDS1: 269 case GPREN0: 270 case GPREN1: 271 case GPFEN0: 272 case GPFEN1: 273 case GPHEN0: 274 case GPHEN1: 275 case GPLEN0: 276 case GPLEN1: 277 case GPAREN0: 278 case GPAREN1: 279 case GPAFEN0: 280 case GPAFEN1: 281 /* Not implemented */ 282 qemu_log_mask(LOG_UNIMP, "%s: %s: not implemented for %"HWADDR_PRIx"\n", 283 TYPE_BCM2838_GPIO, __func__, offset); 284 break; 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; 291 break; 292 default: 293 qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: bad offset %"HWADDR_PRIx"\n", 294 TYPE_BCM2838_GPIO, __func__, offset); 295 } 296 return; 297 } 298 299 static void bcm2838_gpio_reset(DeviceState *dev) 300 { 301 BCM2838GpioState *s = BCM2838_GPIO(dev); 302 303 memset(s->fsel, 0, sizeof(s->fsel)); 304 305 s->sd_fsel = 0; 306 307 /* SDHCI is selected by default */ 308 sdbus_reparent_card(&s->sdbus, s->sdbus_sdhci); 309 310 s->lev0 = 0; 311 s->lev1 = 0; 312 313 memset(s->fsel, 0, sizeof(s->fsel)); 314 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; 319 } 320 321 static const MemoryRegionOps bcm2838_gpio_ops = { 322 .read = bcm2838_gpio_read, 323 .write = bcm2838_gpio_write, 324 .endianness = DEVICE_NATIVE_ENDIAN, 325 }; 326 327 static const VMStateDescription vmstate_bcm2838_gpio = { 328 .name = "bcm2838_gpio", 329 .version_id = 1, 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() 339 } 340 }; 341 342 static void bcm2838_gpio_init(Object *obj) 343 { 344 BCM2838GpioState *s = BCM2838_GPIO(obj); 345 DeviceState *dev = DEVICE(obj); 346 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 347 348 qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS, DEVICE(s), "sd-bus"); 349 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); 354 } 355 356 static void bcm2838_gpio_realize(DeviceState *dev, Error **errp) 357 { 358 BCM2838GpioState *s = BCM2838_GPIO(dev); 359 Object *obj; 360 361 obj = object_property_get_link(OBJECT(dev), "sdbus-sdhci", &error_abort); 362 s->sdbus_sdhci = SD_BUS(obj); 363 364 obj = object_property_get_link(OBJECT(dev), "sdbus-sdhost", &error_abort); 365 s->sdbus_sdhost = SD_BUS(obj); 366 } 367 368 static void bcm2838_gpio_class_init(ObjectClass *klass, void *data) 369 { 370 DeviceClass *dc = DEVICE_CLASS(klass); 371 372 dc->vmsd = &vmstate_bcm2838_gpio; 373 dc->realize = &bcm2838_gpio_realize; 374 device_class_set_legacy_reset(dc, bcm2838_gpio_reset); 375 } 376 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, 383 }; 384 385 static void bcm2838_gpio_register_types(void) 386 { 387 type_register_static(&bcm2838_gpio_info); 388 } 389 390 type_init(bcm2838_gpio_register_types) 391