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