qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

bcm2835_gpio: add bcm2835 gpio controller

This adds the BCM2835 GPIO controller.

It currently implements:
- The 54 GPIOs as outputs (qemu_irq)
- The SD controller selection via alternate function of GPIOs 48-53

Signed-off-by: Clement Deschamps <clement.deschamps@antfield.fr>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1488293711-14195-4-git-send-email-peter.maydell@linaro.org
Message-id: 20170224164021.9066-4-clement.deschamps@antfield.fr
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

authored by

Clement Deschamps and committed by
Peter Maydell
d72fc9dc 97fb87cc

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