xref: /openbmc/qemu/hw/gpio/stm32l4x5_gpio.c (revision ad80e367)
1 /*
2  * STM32L4x5 GPIO (General Purpose Input/Ouput)
3  *
4  * Copyright (c) 2024 Arnaud Minier <arnaud.minier@telecom-paris.fr>
5  * Copyright (c) 2024 Inès Varhol <ines.varhol@telecom-paris.fr>
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10  * See the COPYING file in the top-level directory.
11  */
12 
13 /*
14  * The reference used is the STMicroElectronics RM0351 Reference manual
15  * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
16  * https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html
17  */
18 
19 #include "qemu/osdep.h"
20 #include "qemu/log.h"
21 #include "hw/gpio/stm32l4x5_gpio.h"
22 #include "hw/irq.h"
23 #include "hw/qdev-clock.h"
24 #include "hw/qdev-properties.h"
25 #include "qapi/visitor.h"
26 #include "qapi/error.h"
27 #include "migration/vmstate.h"
28 #include "trace.h"
29 
30 #define GPIO_MODER 0x00
31 #define GPIO_OTYPER 0x04
32 #define GPIO_OSPEEDR 0x08
33 #define GPIO_PUPDR 0x0C
34 #define GPIO_IDR 0x10
35 #define GPIO_ODR 0x14
36 #define GPIO_BSRR 0x18
37 #define GPIO_LCKR 0x1C
38 #define GPIO_AFRL 0x20
39 #define GPIO_AFRH 0x24
40 #define GPIO_BRR 0x28
41 #define GPIO_ASCR 0x2C
42 
43 /* 0b11111111_11111111_00000000_00000000 */
44 #define RESERVED_BITS_MASK 0xFFFF0000
45 
46 static void update_gpio_idr(Stm32l4x5GpioState *s);
47 
48 static bool is_pull_up(Stm32l4x5GpioState *s, unsigned pin)
49 {
50     return extract32(s->pupdr, 2 * pin, 2) == 1;
51 }
52 
53 static bool is_pull_down(Stm32l4x5GpioState *s, unsigned pin)
54 {
55     return extract32(s->pupdr, 2 * pin, 2) == 2;
56 }
57 
58 static bool is_output(Stm32l4x5GpioState *s, unsigned pin)
59 {
60     return extract32(s->moder, 2 * pin, 2) == 1;
61 }
62 
63 static bool is_open_drain(Stm32l4x5GpioState *s, unsigned pin)
64 {
65     return extract32(s->otyper, pin, 1) == 1;
66 }
67 
68 static bool is_push_pull(Stm32l4x5GpioState *s, unsigned pin)
69 {
70     return extract32(s->otyper, pin, 1) == 0;
71 }
72 
73 static void stm32l4x5_gpio_reset_hold(Object *obj, ResetType type)
74 {
75     Stm32l4x5GpioState *s = STM32L4X5_GPIO(obj);
76 
77     s->moder = s->moder_reset;
78     s->otyper = 0x00000000;
79     s->ospeedr = s->ospeedr_reset;
80     s->pupdr = s->pupdr_reset;
81     s->idr = 0x00000000;
82     s->odr = 0x00000000;
83     s->lckr = 0x00000000;
84     s->afrl = 0x00000000;
85     s->afrh = 0x00000000;
86     s->ascr = 0x00000000;
87 
88     s->disconnected_pins = 0xFFFF;
89     s->pins_connected_high = 0x0000;
90     update_gpio_idr(s);
91 }
92 
93 static void stm32l4x5_gpio_set(void *opaque, int line, int level)
94 {
95     Stm32l4x5GpioState *s = opaque;
96     /*
97      * The pin isn't set if line is configured in output mode
98      * except if level is 0 and the output is open-drain.
99      * This way there will be no short-circuit prone situations.
100      */
101     if (is_output(s, line) && !(is_open_drain(s, line) && (level == 0))) {
102         qemu_log_mask(LOG_GUEST_ERROR, "Line %d can't be driven externally\n",
103                       line);
104         return;
105     }
106 
107     s->disconnected_pins &= ~(1 << line);
108     if (level) {
109         s->pins_connected_high |= (1 << line);
110     } else {
111         s->pins_connected_high &= ~(1 << line);
112     }
113     trace_stm32l4x5_gpio_pins(s->name, s->disconnected_pins,
114                               s->pins_connected_high);
115     update_gpio_idr(s);
116 }
117 
118 
119 static void update_gpio_idr(Stm32l4x5GpioState *s)
120 {
121     uint32_t new_idr_mask = 0;
122     uint32_t new_idr = s->odr;
123     uint32_t old_idr = s->idr;
124     int new_pin_state, old_pin_state;
125 
126     for (int i = 0; i < GPIO_NUM_PINS; i++) {
127         if (is_output(s, i)) {
128             if (is_push_pull(s, i)) {
129                 new_idr_mask |= (1 << i);
130             } else if (!(s->odr & (1 << i))) {
131                 /* open-drain ODR 0 */
132                 new_idr_mask |= (1 << i);
133             /* open-drain ODR 1 */
134             } else if (!(s->disconnected_pins & (1 << i)) &&
135                        !(s->pins_connected_high & (1 << i))) {
136                 /* open-drain ODR 1 with pin connected low */
137                 new_idr_mask |= (1 << i);
138                 new_idr &= ~(1 << i);
139             /* open-drain ODR 1 with unactive pin */
140             } else if (is_pull_up(s, i)) {
141                 new_idr_mask |= (1 << i);
142             } else if (is_pull_down(s, i)) {
143                 new_idr_mask |= (1 << i);
144                 new_idr &= ~(1 << i);
145             }
146             /*
147              * The only case left is for open-drain ODR 1
148              * with unactive pin without pull-up or pull-down :
149              * the value is floating.
150              */
151         /* input or analog mode with connected pin */
152         } else if (!(s->disconnected_pins & (1 << i))) {
153             if (s->pins_connected_high & (1 << i)) {
154                 /* pin high */
155                 new_idr_mask |= (1 << i);
156                 new_idr |= (1 << i);
157             } else {
158                 /* pin low */
159                 new_idr_mask |= (1 << i);
160                 new_idr &= ~(1 << i);
161             }
162         /* input or analog mode with disconnected pin */
163         } else {
164             if (is_pull_up(s, i)) {
165                 /* pull-up */
166                 new_idr_mask |= (1 << i);
167                 new_idr |= (1 << i);
168             } else if (is_pull_down(s, i)) {
169                 /* pull-down */
170                 new_idr_mask |= (1 << i);
171                 new_idr &= ~(1 << i);
172             }
173             /*
174              * The only case left is for a disconnected pin
175              * without pull-up or pull-down :
176              * the value is floating.
177              */
178         }
179     }
180 
181     s->idr = (old_idr & ~new_idr_mask) | (new_idr & new_idr_mask);
182     trace_stm32l4x5_gpio_update_idr(s->name, old_idr, s->idr);
183 
184     for (int i = 0; i < GPIO_NUM_PINS; i++) {
185         if (new_idr_mask & (1 << i)) {
186             new_pin_state = (new_idr & (1 << i)) > 0;
187             old_pin_state = (old_idr & (1 << i)) > 0;
188             if (new_pin_state > old_pin_state) {
189                 qemu_irq_raise(s->pin[i]);
190             } else if (new_pin_state < old_pin_state) {
191                 qemu_irq_lower(s->pin[i]);
192             }
193         }
194     }
195 }
196 
197 /*
198  * Return mask of pins that are both configured in output
199  * mode and externally driven (except pins in open-drain
200  * mode externally set to 0).
201  */
202 static uint32_t get_gpio_pinmask_to_disconnect(Stm32l4x5GpioState *s)
203 {
204     uint32_t pins_to_disconnect = 0;
205     for (int i = 0; i < GPIO_NUM_PINS; i++) {
206         /* for each connected pin in output mode */
207         if (!(s->disconnected_pins & (1 << i)) && is_output(s, i)) {
208             /* if either push-pull or high level */
209             if (is_push_pull(s, i) || s->pins_connected_high & (1 << i)) {
210                 pins_to_disconnect |= (1 << i);
211                 qemu_log_mask(LOG_GUEST_ERROR,
212                               "Line %d can't be driven externally\n",
213                               i);
214             }
215         }
216     }
217     return pins_to_disconnect;
218 }
219 
220 /*
221  * Set field `disconnected_pins` and call `update_gpio_idr()`
222  */
223 static void disconnect_gpio_pins(Stm32l4x5GpioState *s, uint16_t lines)
224 {
225     s->disconnected_pins |= lines;
226     trace_stm32l4x5_gpio_pins(s->name, s->disconnected_pins,
227                               s->pins_connected_high);
228     update_gpio_idr(s);
229 }
230 
231 static void disconnected_pins_set(Object *obj, Visitor *v,
232     const char *name, void *opaque, Error **errp)
233 {
234     Stm32l4x5GpioState *s = STM32L4X5_GPIO(obj);
235     uint16_t value;
236     if (!visit_type_uint16(v, name, &value, errp)) {
237         return;
238     }
239     disconnect_gpio_pins(s, value);
240 }
241 
242 static void disconnected_pins_get(Object *obj, Visitor *v,
243     const char *name, void *opaque, Error **errp)
244 {
245     visit_type_uint16(v, name, (uint16_t *)opaque, errp);
246 }
247 
248 static void clock_freq_get(Object *obj, Visitor *v,
249     const char *name, void *opaque, Error **errp)
250 {
251     Stm32l4x5GpioState *s = STM32L4X5_GPIO(obj);
252     uint32_t clock_freq_hz = clock_get_hz(s->clk);
253     visit_type_uint32(v, name, &clock_freq_hz, errp);
254 }
255 
256 static void stm32l4x5_gpio_write(void *opaque, hwaddr addr,
257                                  uint64_t val64, unsigned int size)
258 {
259     Stm32l4x5GpioState *s = opaque;
260 
261     uint32_t value = val64;
262     trace_stm32l4x5_gpio_write(s->name, addr, val64);
263 
264     switch (addr) {
265     case GPIO_MODER:
266         s->moder = value;
267         disconnect_gpio_pins(s, get_gpio_pinmask_to_disconnect(s));
268         qemu_log_mask(LOG_UNIMP,
269                       "%s: Analog and AF modes aren't supported\n\
270                        Analog and AF mode behave like input mode\n",
271                       __func__);
272         return;
273     case GPIO_OTYPER:
274         s->otyper = value & ~RESERVED_BITS_MASK;
275         disconnect_gpio_pins(s, get_gpio_pinmask_to_disconnect(s));
276         return;
277     case GPIO_OSPEEDR:
278         qemu_log_mask(LOG_UNIMP,
279                       "%s: Changing I/O output speed isn't supported\n\
280                        I/O speed is already maximal\n",
281                       __func__);
282         s->ospeedr = value;
283         return;
284     case GPIO_PUPDR:
285         s->pupdr = value;
286         update_gpio_idr(s);
287         return;
288     case GPIO_IDR:
289         qemu_log_mask(LOG_UNIMP,
290                       "%s: GPIO->IDR is read-only\n",
291                       __func__);
292         return;
293     case GPIO_ODR:
294         s->odr = value & ~RESERVED_BITS_MASK;
295         update_gpio_idr(s);
296         return;
297     case GPIO_BSRR: {
298         uint32_t bits_to_reset = (value & RESERVED_BITS_MASK) >> GPIO_NUM_PINS;
299         uint32_t bits_to_set = value & ~RESERVED_BITS_MASK;
300         /* If both BSx and BRx are set, BSx has priority.*/
301         s->odr &= ~bits_to_reset;
302         s->odr |= bits_to_set;
303         update_gpio_idr(s);
304         return;
305     }
306     case GPIO_LCKR:
307         qemu_log_mask(LOG_UNIMP,
308                       "%s: Locking port bits configuration isn't supported\n",
309                       __func__);
310         s->lckr = value & ~RESERVED_BITS_MASK;
311         return;
312     case GPIO_AFRL:
313         qemu_log_mask(LOG_UNIMP,
314                       "%s: Alternate functions aren't supported\n",
315                       __func__);
316         s->afrl = value;
317         return;
318     case GPIO_AFRH:
319         qemu_log_mask(LOG_UNIMP,
320                       "%s: Alternate functions aren't supported\n",
321                       __func__);
322         s->afrh = value;
323         return;
324     case GPIO_BRR: {
325         uint32_t bits_to_reset = value & ~RESERVED_BITS_MASK;
326         s->odr &= ~bits_to_reset;
327         update_gpio_idr(s);
328         return;
329     }
330     case GPIO_ASCR:
331         qemu_log_mask(LOG_UNIMP,
332                       "%s: ADC function isn't supported\n",
333                       __func__);
334         s->ascr = value & ~RESERVED_BITS_MASK;
335         return;
336     default:
337         qemu_log_mask(LOG_GUEST_ERROR,
338                       "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
339     }
340 }
341 
342 static uint64_t stm32l4x5_gpio_read(void *opaque, hwaddr addr,
343                                     unsigned int size)
344 {
345     Stm32l4x5GpioState *s = opaque;
346 
347     trace_stm32l4x5_gpio_read(s->name, addr);
348 
349     switch (addr) {
350     case GPIO_MODER:
351         return s->moder;
352     case GPIO_OTYPER:
353         return s->otyper;
354     case GPIO_OSPEEDR:
355         return s->ospeedr;
356     case GPIO_PUPDR:
357         return s->pupdr;
358     case GPIO_IDR:
359         return s->idr;
360     case GPIO_ODR:
361         return s->odr;
362     case GPIO_BSRR:
363         return 0;
364     case GPIO_LCKR:
365         return s->lckr;
366     case GPIO_AFRL:
367         return s->afrl;
368     case GPIO_AFRH:
369         return s->afrh;
370     case GPIO_BRR:
371         return 0;
372     case GPIO_ASCR:
373         return s->ascr;
374     default:
375         qemu_log_mask(LOG_GUEST_ERROR,
376                       "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
377         return 0;
378     }
379 }
380 
381 static const MemoryRegionOps stm32l4x5_gpio_ops = {
382     .read = stm32l4x5_gpio_read,
383     .write = stm32l4x5_gpio_write,
384     .endianness = DEVICE_NATIVE_ENDIAN,
385     .impl = {
386         .min_access_size = 4,
387         .max_access_size = 4,
388         .unaligned = false,
389     },
390     .valid = {
391         .min_access_size = 4,
392         .max_access_size = 4,
393         .unaligned = false,
394     },
395 };
396 
397 static void stm32l4x5_gpio_init(Object *obj)
398 {
399     Stm32l4x5GpioState *s = STM32L4X5_GPIO(obj);
400 
401     memory_region_init_io(&s->mmio, obj, &stm32l4x5_gpio_ops, s,
402                           TYPE_STM32L4X5_GPIO, 0x400);
403 
404     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
405 
406     qdev_init_gpio_out(DEVICE(obj), s->pin, GPIO_NUM_PINS);
407     qdev_init_gpio_in(DEVICE(obj), stm32l4x5_gpio_set, GPIO_NUM_PINS);
408 
409     s->clk = qdev_init_clock_in(DEVICE(s), "clk", NULL, s, 0);
410 
411     object_property_add(obj, "disconnected-pins", "uint16",
412                         disconnected_pins_get, disconnected_pins_set,
413                         NULL, &s->disconnected_pins);
414     object_property_add(obj, "clock-freq-hz", "uint32",
415                         clock_freq_get, NULL, NULL, NULL);
416 }
417 
418 static void stm32l4x5_gpio_realize(DeviceState *dev, Error **errp)
419 {
420     Stm32l4x5GpioState *s = STM32L4X5_GPIO(dev);
421     if (!clock_has_source(s->clk)) {
422         error_setg(errp, "GPIO: clk input must be connected");
423         return;
424     }
425 }
426 
427 static const VMStateDescription vmstate_stm32l4x5_gpio = {
428     .name = TYPE_STM32L4X5_GPIO,
429     .version_id = 1,
430     .minimum_version_id = 1,
431     .fields = (VMStateField[]){
432         VMSTATE_UINT32(moder, Stm32l4x5GpioState),
433         VMSTATE_UINT32(otyper, Stm32l4x5GpioState),
434         VMSTATE_UINT32(ospeedr, Stm32l4x5GpioState),
435         VMSTATE_UINT32(pupdr, Stm32l4x5GpioState),
436         VMSTATE_UINT32(idr, Stm32l4x5GpioState),
437         VMSTATE_UINT32(odr, Stm32l4x5GpioState),
438         VMSTATE_UINT32(lckr, Stm32l4x5GpioState),
439         VMSTATE_UINT32(afrl, Stm32l4x5GpioState),
440         VMSTATE_UINT32(afrh, Stm32l4x5GpioState),
441         VMSTATE_UINT32(ascr, Stm32l4x5GpioState),
442         VMSTATE_UINT16(disconnected_pins, Stm32l4x5GpioState),
443         VMSTATE_UINT16(pins_connected_high, Stm32l4x5GpioState),
444         VMSTATE_END_OF_LIST()
445     }
446 };
447 
448 static Property stm32l4x5_gpio_properties[] = {
449     DEFINE_PROP_STRING("name", Stm32l4x5GpioState, name),
450     DEFINE_PROP_UINT32("mode-reset", Stm32l4x5GpioState, moder_reset, 0),
451     DEFINE_PROP_UINT32("ospeed-reset", Stm32l4x5GpioState, ospeedr_reset, 0),
452     DEFINE_PROP_UINT32("pupd-reset", Stm32l4x5GpioState, pupdr_reset, 0),
453     DEFINE_PROP_END_OF_LIST(),
454 };
455 
456 static void stm32l4x5_gpio_class_init(ObjectClass *klass, void *data)
457 {
458     DeviceClass *dc = DEVICE_CLASS(klass);
459     ResettableClass *rc = RESETTABLE_CLASS(klass);
460 
461     device_class_set_props(dc, stm32l4x5_gpio_properties);
462     dc->vmsd = &vmstate_stm32l4x5_gpio;
463     dc->realize = stm32l4x5_gpio_realize;
464     rc->phases.hold = stm32l4x5_gpio_reset_hold;
465 }
466 
467 static const TypeInfo stm32l4x5_gpio_types[] = {
468     {
469         .name = TYPE_STM32L4X5_GPIO,
470         .parent = TYPE_SYS_BUS_DEVICE,
471         .instance_size = sizeof(Stm32l4x5GpioState),
472         .instance_init = stm32l4x5_gpio_init,
473         .class_init = stm32l4x5_gpio_class_init,
474     },
475 };
476 
477 DEFINE_TYPES(stm32l4x5_gpio_types)
478