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