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