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