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