qemu

Форк
0
/
stm32l4x5_gpio.c 
479 строк · 14.6 Кб
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

49
static bool is_pull_up(Stm32l4x5GpioState *s, unsigned pin)
50
{
51
    return extract32(s->pupdr, 2 * pin, 2) == 1;
52
}
53

54
static bool is_pull_down(Stm32l4x5GpioState *s, unsigned pin)
55
{
56
    return extract32(s->pupdr, 2 * pin, 2) == 2;
57
}
58

59
static bool is_output(Stm32l4x5GpioState *s, unsigned pin)
60
{
61
    return extract32(s->moder, 2 * pin, 2) == 1;
62
}
63

64
static bool is_open_drain(Stm32l4x5GpioState *s, unsigned pin)
65
{
66
    return extract32(s->otyper, pin, 1) == 1;
67
}
68

69
static bool is_push_pull(Stm32l4x5GpioState *s, unsigned pin)
70
{
71
    return extract32(s->otyper, pin, 1) == 0;
72
}
73

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

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

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
 */
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
 */
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

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

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

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

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

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

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

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

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

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.