xref: /openbmc/qemu/hw/arm/stm32l4x5_soc.c (revision 29f0bef7)
104a7c7b1SInès Varhol /*
204a7c7b1SInès Varhol  * STM32L4x5 SoC family
304a7c7b1SInès Varhol  *
45b5b014bSInès Varhol  * Copyright (c) 2023-2024 Arnaud Minier <arnaud.minier@telecom-paris.fr>
55b5b014bSInès Varhol  * Copyright (c) 2023-2024 Inès Varhol <ines.varhol@telecom-paris.fr>
604a7c7b1SInès Varhol  *
704a7c7b1SInès Varhol  * SPDX-License-Identifier: GPL-2.0-or-later
804a7c7b1SInès Varhol  *
904a7c7b1SInès Varhol  * This work is licensed under the terms of the GNU GPL, version 2 or later.
1004a7c7b1SInès Varhol  * See the COPYING file in the top-level directory.
1104a7c7b1SInès Varhol  *
1204a7c7b1SInès Varhol  * This work is heavily inspired by the stm32f405_soc by Alistair Francis.
1304a7c7b1SInès Varhol  * Original code is licensed under the MIT License:
1404a7c7b1SInès Varhol  *
1504a7c7b1SInès Varhol  * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
1604a7c7b1SInès Varhol  */
1704a7c7b1SInès Varhol 
1804a7c7b1SInès Varhol /*
1904a7c7b1SInès Varhol  * The reference used is the STMicroElectronics RM0351 Reference manual
2004a7c7b1SInès Varhol  * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
2104a7c7b1SInès Varhol  * https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html
2204a7c7b1SInès Varhol  */
2304a7c7b1SInès Varhol 
2404a7c7b1SInès Varhol #include "qemu/osdep.h"
2504a7c7b1SInès Varhol #include "qemu/units.h"
2604a7c7b1SInès Varhol #include "qapi/error.h"
2704a7c7b1SInès Varhol #include "exec/address-spaces.h"
2804a7c7b1SInès Varhol #include "sysemu/sysemu.h"
295928ed26SInès Varhol #include "hw/or-irq.h"
3004a7c7b1SInès Varhol #include "hw/arm/stm32l4x5_soc.h"
3192741432SArnaud Minier #include "hw/char/stm32l4x5_usart.h"
321c38129dSInès Varhol #include "hw/gpio/stm32l4x5_gpio.h"
3304a7c7b1SInès Varhol #include "hw/qdev-clock.h"
3404a7c7b1SInès Varhol #include "hw/misc/unimp.h"
3504a7c7b1SInès Varhol 
3604a7c7b1SInès Varhol #define FLASH_BASE_ADDRESS 0x08000000
3704a7c7b1SInès Varhol #define SRAM1_BASE_ADDRESS 0x20000000
3804a7c7b1SInès Varhol #define SRAM1_SIZE (96 * KiB)
3904a7c7b1SInès Varhol #define SRAM2_BASE_ADDRESS 0x10000000
4004a7c7b1SInès Varhol #define SRAM2_SIZE (32 * KiB)
4104a7c7b1SInès Varhol 
4252671f69SInès Varhol #define EXTI_ADDR 0x40010400
437dfe2312SInès Varhol #define SYSCFG_ADDR 0x40010000
4452671f69SInès Varhol 
4552671f69SInès Varhol #define NUM_EXTI_IRQ 40
4652671f69SInès Varhol /* Match exti line connections with their CPU IRQ number */
4752671f69SInès Varhol /* See Vector Table (Reference Manual p.396) */
485928ed26SInès Varhol /*
495928ed26SInès Varhol  * Some IRQs are connected to the same CPU IRQ (denoted by -1)
505928ed26SInès Varhol  * and require an intermediary OR gate to function correctly.
515928ed26SInès Varhol  */
5252671f69SInès Varhol static const int exti_irq[NUM_EXTI_IRQ] = {
5352671f69SInès Varhol     6,                      /* GPIO[0]                 */
5452671f69SInès Varhol     7,                      /* GPIO[1]                 */
5552671f69SInès Varhol     8,                      /* GPIO[2]                 */
5652671f69SInès Varhol     9,                      /* GPIO[3]                 */
5752671f69SInès Varhol     10,                     /* GPIO[4]                 */
585928ed26SInès Varhol     -1, -1, -1, -1, -1,     /* GPIO[5..9] OR gate 23   */
595928ed26SInès Varhol     -1, -1, -1, -1, -1, -1, /* GPIO[10..15] OR gate 40 */
605928ed26SInès Varhol     -1,                     /* PVD OR gate 1           */
6152671f69SInès Varhol     67,                     /* OTG_FS_WKUP, Direct     */
6252671f69SInès Varhol     41,                     /* RTC_ALARM               */
6352671f69SInès Varhol     2,                      /* RTC_TAMP_STAMP2/CSS_LSE */
6452671f69SInès Varhol     3,                      /* RTC wakeup timer        */
655928ed26SInès Varhol     -1, -1,                 /* COMP[1..2] OR gate 63   */
6652671f69SInès Varhol     31,                     /* I2C1 wakeup, Direct     */
6752671f69SInès Varhol     33,                     /* I2C2 wakeup, Direct     */
6852671f69SInès Varhol     72,                     /* I2C3 wakeup, Direct     */
6952671f69SInès Varhol     37,                     /* USART1 wakeup, Direct   */
7052671f69SInès Varhol     38,                     /* USART2 wakeup, Direct   */
7152671f69SInès Varhol     39,                     /* USART3 wakeup, Direct   */
7252671f69SInès Varhol     52,                     /* UART4 wakeup, Direct    */
7352671f69SInès Varhol     53,                     /* UART4 wakeup, Direct    */
7452671f69SInès Varhol     70,                     /* LPUART1 wakeup, Direct  */
7552671f69SInès Varhol     65,                     /* LPTIM1, Direct          */
7652671f69SInès Varhol     66,                     /* LPTIM2, Direct          */
7752671f69SInès Varhol     76,                     /* SWPMI1 wakeup, Direct   */
785928ed26SInès Varhol     -1, -1, -1, -1,         /* PVM[1..4] OR gate 1     */
7952671f69SInès Varhol     78                      /* LCD wakeup, Direct      */
8052671f69SInès Varhol };
81d6b55a0fSArnaud Minier #define RCC_BASE_ADDRESS 0x40021000
82d6b55a0fSArnaud Minier #define RCC_IRQ 5
8352671f69SInès Varhol 
84*29f0bef7SInès Varhol #define EXTI_USART1_IRQ 26
85*29f0bef7SInès Varhol #define EXTI_UART4_IRQ 29
86*29f0bef7SInès Varhol #define EXTI_LPUART1_IRQ 31
87*29f0bef7SInès Varhol 
885928ed26SInès Varhol static const int exti_or_gates_out[NUM_EXTI_OR_GATES] = {
895928ed26SInès Varhol     23, 40, 63, 1,
905928ed26SInès Varhol };
915928ed26SInès Varhol 
925928ed26SInès Varhol static const int exti_or_gates_num_lines_in[NUM_EXTI_OR_GATES] = {
935928ed26SInès Varhol     5, 6, 2, 5,
945928ed26SInès Varhol };
955928ed26SInès Varhol 
965928ed26SInès Varhol /* 3 OR gates with consecutive inputs */
975928ed26SInès Varhol #define NUM_EXTI_SIMPLE_OR_GATES 3
985928ed26SInès Varhol static const int exti_or_gates_first_line_in[NUM_EXTI_SIMPLE_OR_GATES] = {
995928ed26SInès Varhol     5, 10, 21,
1005928ed26SInès Varhol };
1015928ed26SInès Varhol 
1025928ed26SInès Varhol /* 1 OR gate with non-consecutive inputs */
1035928ed26SInès Varhol #define EXTI_OR_GATE1_NUM_LINES_IN 5
1045928ed26SInès Varhol static const int exti_or_gate1_lines_in[EXTI_OR_GATE1_NUM_LINES_IN] = {
1055928ed26SInès Varhol     16, 35, 36, 37, 38,
1065928ed26SInès Varhol };
1075928ed26SInès Varhol 
1081c38129dSInès Varhol static const struct {
1091c38129dSInès Varhol     uint32_t addr;
1101c38129dSInès Varhol     uint32_t moder_reset;
1111c38129dSInès Varhol     uint32_t ospeedr_reset;
1121c38129dSInès Varhol     uint32_t pupdr_reset;
1131c38129dSInès Varhol } stm32l4x5_gpio_cfg[NUM_GPIOS] = {
1141c38129dSInès Varhol     { 0x48000000, 0xABFFFFFF, 0x0C000000, 0x64000000 },
1151c38129dSInès Varhol     { 0x48000400, 0xFFFFFEBF, 0x00000000, 0x00000100 },
1161c38129dSInès Varhol     { 0x48000800, 0xFFFFFFFF, 0x00000000, 0x00000000 },
1171c38129dSInès Varhol     { 0x48000C00, 0xFFFFFFFF, 0x00000000, 0x00000000 },
1181c38129dSInès Varhol     { 0x48001000, 0xFFFFFFFF, 0x00000000, 0x00000000 },
1191c38129dSInès Varhol     { 0x48001400, 0xFFFFFFFF, 0x00000000, 0x00000000 },
1201c38129dSInès Varhol     { 0x48001800, 0xFFFFFFFF, 0x00000000, 0x00000000 },
1211c38129dSInès Varhol     { 0x48001C00, 0x0000000F, 0x00000000, 0x00000000 },
1221c38129dSInès Varhol };
1231c38129dSInès Varhol 
12492741432SArnaud Minier static const hwaddr usart_addr[] = {
12592741432SArnaud Minier     0x40013800, /* "USART1", 0x400 */
12692741432SArnaud Minier     0x40004400, /* "USART2", 0x400 */
12792741432SArnaud Minier     0x40004800, /* "USART3", 0x400 */
12892741432SArnaud Minier };
12992741432SArnaud Minier static const hwaddr uart_addr[] = {
13092741432SArnaud Minier     0x40004C00, /* "UART4" , 0x400 */
13192741432SArnaud Minier     0x40005000  /* "UART5" , 0x400 */
13292741432SArnaud Minier };
13392741432SArnaud Minier 
13492741432SArnaud Minier #define LPUART_BASE_ADDRESS 0x40008000
13592741432SArnaud Minier 
stm32l4x5_soc_initfn(Object * obj)13604a7c7b1SInès Varhol static void stm32l4x5_soc_initfn(Object *obj)
13704a7c7b1SInès Varhol {
13804a7c7b1SInès Varhol     Stm32l4x5SocState *s = STM32L4X5_SOC(obj);
13904a7c7b1SInès Varhol 
14052671f69SInès Varhol     object_initialize_child(obj, "exti", &s->exti, TYPE_STM32L4X5_EXTI);
1415928ed26SInès Varhol     for (unsigned i = 0; i < NUM_EXTI_OR_GATES; i++) {
1425928ed26SInès Varhol         object_initialize_child(obj, "exti_or_gates[*]", &s->exti_or_gates[i],
1435928ed26SInès Varhol                                 TYPE_OR_IRQ);
1445928ed26SInès Varhol     }
1457dfe2312SInès Varhol     object_initialize_child(obj, "syscfg", &s->syscfg, TYPE_STM32L4X5_SYSCFG);
146d6b55a0fSArnaud Minier     object_initialize_child(obj, "rcc", &s->rcc, TYPE_STM32L4X5_RCC);
1471c38129dSInès Varhol 
1481c38129dSInès Varhol     for (unsigned i = 0; i < NUM_GPIOS; i++) {
1491c38129dSInès Varhol         g_autofree char *name = g_strdup_printf("gpio%c", 'a' + i);
1501c38129dSInès Varhol         object_initialize_child(obj, name, &s->gpio[i], TYPE_STM32L4X5_GPIO);
1511c38129dSInès Varhol     }
15292741432SArnaud Minier 
15392741432SArnaud Minier     for (int i = 0; i < STM_NUM_USARTS; i++) {
15492741432SArnaud Minier         object_initialize_child(obj, "usart[*]", &s->usart[i],
15592741432SArnaud Minier                                 TYPE_STM32L4X5_USART);
15692741432SArnaud Minier     }
15792741432SArnaud Minier 
15892741432SArnaud Minier     for (int i = 0; i < STM_NUM_UARTS; i++) {
15992741432SArnaud Minier         object_initialize_child(obj, "uart[*]", &s->uart[i],
16092741432SArnaud Minier                                 TYPE_STM32L4X5_UART);
16192741432SArnaud Minier     }
16292741432SArnaud Minier     object_initialize_child(obj, "lpuart1", &s->lpuart,
16392741432SArnaud Minier                             TYPE_STM32L4X5_LPUART);
16404a7c7b1SInès Varhol }
16504a7c7b1SInès Varhol 
stm32l4x5_soc_realize(DeviceState * dev_soc,Error ** errp)16604a7c7b1SInès Varhol static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
16704a7c7b1SInès Varhol {
16804a7c7b1SInès Varhol     ERRP_GUARD();
16904a7c7b1SInès Varhol     Stm32l4x5SocState *s = STM32L4X5_SOC(dev_soc);
17004a7c7b1SInès Varhol     const Stm32l4x5SocClass *sc = STM32L4X5_SOC_GET_CLASS(dev_soc);
17104a7c7b1SInès Varhol     MemoryRegion *system_memory = get_system_memory();
1721c38129dSInès Varhol     DeviceState *armv7m, *dev;
17352671f69SInès Varhol     SysBusDevice *busdev;
1741c38129dSInès Varhol     uint32_t pin_index;
17504a7c7b1SInès Varhol 
17604a7c7b1SInès Varhol     if (!memory_region_init_rom(&s->flash, OBJECT(dev_soc), "flash",
17704a7c7b1SInès Varhol                                 sc->flash_size, errp)) {
17804a7c7b1SInès Varhol         return;
17904a7c7b1SInès Varhol     }
18004a7c7b1SInès Varhol     memory_region_init_alias(&s->flash_alias, OBJECT(dev_soc),
18104a7c7b1SInès Varhol                              "flash_boot_alias", &s->flash, 0,
18204a7c7b1SInès Varhol                              sc->flash_size);
18304a7c7b1SInès Varhol 
18404a7c7b1SInès Varhol     memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, &s->flash);
18504a7c7b1SInès Varhol     memory_region_add_subregion(system_memory, 0, &s->flash_alias);
18604a7c7b1SInès Varhol 
18704a7c7b1SInès Varhol     if (!memory_region_init_ram(&s->sram1, OBJECT(dev_soc), "SRAM1", SRAM1_SIZE,
18804a7c7b1SInès Varhol                                 errp)) {
18904a7c7b1SInès Varhol         return;
19004a7c7b1SInès Varhol     }
19104a7c7b1SInès Varhol     memory_region_add_subregion(system_memory, SRAM1_BASE_ADDRESS, &s->sram1);
19204a7c7b1SInès Varhol 
19304a7c7b1SInès Varhol     if (!memory_region_init_ram(&s->sram2, OBJECT(dev_soc), "SRAM2", SRAM2_SIZE,
19404a7c7b1SInès Varhol                                 errp)) {
19504a7c7b1SInès Varhol         return;
19604a7c7b1SInès Varhol     }
19704a7c7b1SInès Varhol     memory_region_add_subregion(system_memory, SRAM2_BASE_ADDRESS, &s->sram2);
19804a7c7b1SInès Varhol 
19904a7c7b1SInès Varhol     object_initialize_child(OBJECT(dev_soc), "armv7m", &s->armv7m, TYPE_ARMV7M);
20004a7c7b1SInès Varhol     armv7m = DEVICE(&s->armv7m);
20104a7c7b1SInès Varhol     qdev_prop_set_uint32(armv7m, "num-irq", 96);
2024a04655cSSamuel Tardieu     qdev_prop_set_uint32(armv7m, "num-prio-bits", 4);
20304a7c7b1SInès Varhol     qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4"));
20404a7c7b1SInès Varhol     qdev_prop_set_bit(armv7m, "enable-bitband", true);
20560849fe4SArnaud Minier     qdev_connect_clock_in(armv7m, "cpuclk",
20660849fe4SArnaud Minier         qdev_get_clock_out(DEVICE(&(s->rcc)), "cortex-fclk-out"));
20760849fe4SArnaud Minier     qdev_connect_clock_in(armv7m, "refclk",
20860849fe4SArnaud Minier         qdev_get_clock_out(DEVICE(&(s->rcc)), "cortex-refclk-out"));
20904a7c7b1SInès Varhol     object_property_set_link(OBJECT(&s->armv7m), "memory",
21004a7c7b1SInès Varhol                              OBJECT(system_memory), &error_abort);
21104a7c7b1SInès Varhol     if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) {
21204a7c7b1SInès Varhol         return;
21304a7c7b1SInès Varhol     }
21404a7c7b1SInès Varhol 
2151c38129dSInès Varhol     /* GPIOs */
2161c38129dSInès Varhol     for (unsigned i = 0; i < NUM_GPIOS; i++) {
2171c38129dSInès Varhol         g_autofree char *name = g_strdup_printf("%c", 'A' + i);
2181c38129dSInès Varhol         dev = DEVICE(&s->gpio[i]);
2191c38129dSInès Varhol         qdev_prop_set_string(dev, "name", name);
2201c38129dSInès Varhol         qdev_prop_set_uint32(dev, "mode-reset",
2211c38129dSInès Varhol                              stm32l4x5_gpio_cfg[i].moder_reset);
2221c38129dSInès Varhol         qdev_prop_set_uint32(dev, "ospeed-reset",
2231c38129dSInès Varhol                              stm32l4x5_gpio_cfg[i].ospeedr_reset);
2241c38129dSInès Varhol         qdev_prop_set_uint32(dev, "pupd-reset",
2251c38129dSInès Varhol                             stm32l4x5_gpio_cfg[i].pupdr_reset);
2261c38129dSInès Varhol         busdev = SYS_BUS_DEVICE(&s->gpio[i]);
2271c38129dSInès Varhol         g_free(name);
2281c38129dSInès Varhol         name = g_strdup_printf("gpio%c-out", 'a' + i);
2291c38129dSInès Varhol         qdev_connect_clock_in(DEVICE(&s->gpio[i]), "clk",
2301c38129dSInès Varhol             qdev_get_clock_out(DEVICE(&(s->rcc)), name));
2311c38129dSInès Varhol         if (!sysbus_realize(busdev, errp)) {
2321c38129dSInès Varhol             return;
2331c38129dSInès Varhol         }
2341c38129dSInès Varhol         sysbus_mmio_map(busdev, 0, stm32l4x5_gpio_cfg[i].addr);
2351c38129dSInès Varhol     }
2361c38129dSInès Varhol 
2377dfe2312SInès Varhol     /* System configuration controller */
2387dfe2312SInès Varhol     busdev = SYS_BUS_DEVICE(&s->syscfg);
2397dfe2312SInès Varhol     if (!sysbus_realize(busdev, errp)) {
2407dfe2312SInès Varhol         return;
2417dfe2312SInès Varhol     }
2427dfe2312SInès Varhol     sysbus_mmio_map(busdev, 0, SYSCFG_ADDR);
2431c38129dSInès Varhol 
2441c38129dSInès Varhol     for (unsigned i = 0; i < NUM_GPIOS; i++) {
2451c38129dSInès Varhol         for (unsigned j = 0; j < GPIO_NUM_PINS; j++) {
2461c38129dSInès Varhol             pin_index = GPIO_NUM_PINS * i + j;
2471c38129dSInès Varhol             qdev_connect_gpio_out(DEVICE(&s->gpio[i]), j,
2481c38129dSInès Varhol                                   qdev_get_gpio_in(DEVICE(&s->syscfg),
2491c38129dSInès Varhol                                   pin_index));
2501c38129dSInès Varhol         }
2511c38129dSInès Varhol     }
2527dfe2312SInès Varhol 
2535b5b014bSInès Varhol     qdev_pass_gpios(DEVICE(&s->syscfg), dev_soc, NULL);
2545b5b014bSInès Varhol 
2557dfe2312SInès Varhol     /* EXTI device */
25652671f69SInès Varhol     busdev = SYS_BUS_DEVICE(&s->exti);
25752671f69SInès Varhol     if (!sysbus_realize(busdev, errp)) {
25852671f69SInès Varhol         return;
25952671f69SInès Varhol     }
26052671f69SInès Varhol     sysbus_mmio_map(busdev, 0, EXTI_ADDR);
2615928ed26SInès Varhol 
2625928ed26SInès Varhol     /* IRQs with fan-in that require an OR gate */
2635928ed26SInès Varhol     for (unsigned i = 0; i < NUM_EXTI_OR_GATES; i++) {
2645928ed26SInès Varhol         if (!object_property_set_int(OBJECT(&s->exti_or_gates[i]), "num-lines",
2655928ed26SInès Varhol                                      exti_or_gates_num_lines_in[i], errp)) {
2665928ed26SInès Varhol             return;
2675928ed26SInès Varhol         }
2685928ed26SInès Varhol         if (!qdev_realize(DEVICE(&s->exti_or_gates[i]), NULL, errp)) {
2695928ed26SInès Varhol             return;
2705928ed26SInès Varhol         }
2715928ed26SInès Varhol 
2725928ed26SInès Varhol         qdev_connect_gpio_out(DEVICE(&s->exti_or_gates[i]), 0,
2735928ed26SInès Varhol             qdev_get_gpio_in(armv7m, exti_or_gates_out[i]));
2745928ed26SInès Varhol 
2755928ed26SInès Varhol         if (i < NUM_EXTI_SIMPLE_OR_GATES) {
2765928ed26SInès Varhol             /* consecutive inputs for OR gates 23, 40, 63 */
2775928ed26SInès Varhol             for (unsigned j = 0; j < exti_or_gates_num_lines_in[i]; j++) {
2785928ed26SInès Varhol                 sysbus_connect_irq(SYS_BUS_DEVICE(&s->exti),
2795928ed26SInès Varhol                     exti_or_gates_first_line_in[i] + j,
2805928ed26SInès Varhol                     qdev_get_gpio_in(DEVICE(&s->exti_or_gates[i]), j));
2815928ed26SInès Varhol             }
2825928ed26SInès Varhol         } else {
2835928ed26SInès Varhol             /* non-consecutive inputs for OR gate 1 */
2845928ed26SInès Varhol             for (unsigned j = 0; j < EXTI_OR_GATE1_NUM_LINES_IN; j++) {
2855928ed26SInès Varhol                 sysbus_connect_irq(SYS_BUS_DEVICE(&s->exti),
2865928ed26SInès Varhol                     exti_or_gate1_lines_in[j],
2875928ed26SInès Varhol                     qdev_get_gpio_in(DEVICE(&s->exti_or_gates[i]), j));
2885928ed26SInès Varhol             }
2895928ed26SInès Varhol         }
2905928ed26SInès Varhol     }
2915928ed26SInès Varhol 
2925928ed26SInès Varhol     /* IRQs that don't require fan-in */
29352671f69SInès Varhol     for (unsigned i = 0; i < NUM_EXTI_IRQ; i++) {
2945928ed26SInès Varhol         if (exti_irq[i] != -1) {
2955928ed26SInès Varhol             sysbus_connect_irq(busdev, i,
2965928ed26SInès Varhol                                qdev_get_gpio_in(armv7m, exti_irq[i]));
2975928ed26SInès Varhol         }
29852671f69SInès Varhol     }
29952671f69SInès Varhol 
300*29f0bef7SInès Varhol     /* Connect SYSCFG to EXTI */
3011c38129dSInès Varhol     for (unsigned i = 0; i < GPIO_NUM_PINS; i++) {
3027dfe2312SInès Varhol         qdev_connect_gpio_out(DEVICE(&s->syscfg), i,
3037dfe2312SInès Varhol                               qdev_get_gpio_in(DEVICE(&s->exti), i));
3047dfe2312SInès Varhol     }
3057dfe2312SInès Varhol 
306d6b55a0fSArnaud Minier     /* RCC device */
307d6b55a0fSArnaud Minier     busdev = SYS_BUS_DEVICE(&s->rcc);
308d6b55a0fSArnaud Minier     if (!sysbus_realize(busdev, errp)) {
309d6b55a0fSArnaud Minier         return;
310d6b55a0fSArnaud Minier     }
311d6b55a0fSArnaud Minier     sysbus_mmio_map(busdev, 0, RCC_BASE_ADDRESS);
312d6b55a0fSArnaud Minier     sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, RCC_IRQ));
313d6b55a0fSArnaud Minier 
31492741432SArnaud Minier     /* USART devices */
31592741432SArnaud Minier     for (int i = 0; i < STM_NUM_USARTS; i++) {
31692741432SArnaud Minier         g_autofree char *name = g_strdup_printf("usart%d-out", i + 1);
31792741432SArnaud Minier         dev = DEVICE(&(s->usart[i]));
31892741432SArnaud Minier         qdev_prop_set_chr(dev, "chardev", serial_hd(i));
31992741432SArnaud Minier         qdev_connect_clock_in(dev, "clk",
32092741432SArnaud Minier             qdev_get_clock_out(DEVICE(&(s->rcc)), name));
32192741432SArnaud Minier         busdev = SYS_BUS_DEVICE(dev);
32292741432SArnaud Minier         if (!sysbus_realize(busdev, errp)) {
32392741432SArnaud Minier             return;
32492741432SArnaud Minier         }
32592741432SArnaud Minier         sysbus_mmio_map(busdev, 0, usart_addr[i]);
326*29f0bef7SInès Varhol         sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(DEVICE(&s->exti),
327*29f0bef7SInès Varhol                                                        EXTI_USART1_IRQ + i));
32892741432SArnaud Minier     }
32992741432SArnaud Minier 
33092741432SArnaud Minier     /* UART devices */
33192741432SArnaud Minier     for (int i = 0; i < STM_NUM_UARTS; i++) {
33292741432SArnaud Minier         g_autofree char *name = g_strdup_printf("uart%d-out", STM_NUM_USARTS + i + 1);
33392741432SArnaud Minier         dev = DEVICE(&(s->uart[i]));
33492741432SArnaud Minier         qdev_prop_set_chr(dev, "chardev", serial_hd(STM_NUM_USARTS + i));
33592741432SArnaud Minier         qdev_connect_clock_in(dev, "clk",
33692741432SArnaud Minier             qdev_get_clock_out(DEVICE(&(s->rcc)), name));
33792741432SArnaud Minier         busdev = SYS_BUS_DEVICE(dev);
33892741432SArnaud Minier         if (!sysbus_realize(busdev, errp)) {
33992741432SArnaud Minier             return;
34092741432SArnaud Minier         }
34192741432SArnaud Minier         sysbus_mmio_map(busdev, 0, uart_addr[i]);
342*29f0bef7SInès Varhol         sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(DEVICE(&s->exti),
343*29f0bef7SInès Varhol                                                        EXTI_UART4_IRQ + i));
34492741432SArnaud Minier     }
34592741432SArnaud Minier 
34692741432SArnaud Minier     /* LPUART device*/
34792741432SArnaud Minier     dev = DEVICE(&(s->lpuart));
34892741432SArnaud Minier     qdev_prop_set_chr(dev, "chardev", serial_hd(STM_NUM_USARTS + STM_NUM_UARTS));
34992741432SArnaud Minier     qdev_connect_clock_in(dev, "clk",
35092741432SArnaud Minier         qdev_get_clock_out(DEVICE(&(s->rcc)), "lpuart1-out"));
35192741432SArnaud Minier     busdev = SYS_BUS_DEVICE(dev);
35292741432SArnaud Minier     if (!sysbus_realize(busdev, errp)) {
35392741432SArnaud Minier         return;
35492741432SArnaud Minier     }
35592741432SArnaud Minier     sysbus_mmio_map(busdev, 0, LPUART_BASE_ADDRESS);
356*29f0bef7SInès Varhol     sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(DEVICE(&s->exti),
357*29f0bef7SInès Varhol                                                    EXTI_LPUART1_IRQ));
35892741432SArnaud Minier 
35904a7c7b1SInès Varhol     /* APB1 BUS */
36004a7c7b1SInès Varhol     create_unimplemented_device("TIM2",      0x40000000, 0x400);
36104a7c7b1SInès Varhol     create_unimplemented_device("TIM3",      0x40000400, 0x400);
36204a7c7b1SInès Varhol     create_unimplemented_device("TIM4",      0x40000800, 0x400);
36304a7c7b1SInès Varhol     create_unimplemented_device("TIM5",      0x40000C00, 0x400);
36404a7c7b1SInès Varhol     create_unimplemented_device("TIM6",      0x40001000, 0x400);
36504a7c7b1SInès Varhol     create_unimplemented_device("TIM7",      0x40001400, 0x400);
36604a7c7b1SInès Varhol     /* RESERVED:    0x40001800, 0x1000 */
36704a7c7b1SInès Varhol     create_unimplemented_device("RTC",       0x40002800, 0x400);
36804a7c7b1SInès Varhol     create_unimplemented_device("WWDG",      0x40002C00, 0x400);
36904a7c7b1SInès Varhol     create_unimplemented_device("IWDG",      0x40003000, 0x400);
37004a7c7b1SInès Varhol     /* RESERVED:    0x40001800, 0x400 */
37104a7c7b1SInès Varhol     create_unimplemented_device("SPI2",      0x40003800, 0x400);
37204a7c7b1SInès Varhol     create_unimplemented_device("SPI3",      0x40003C00, 0x400);
37304a7c7b1SInès Varhol     /* RESERVED:    0x40004000, 0x400 */
37404a7c7b1SInès Varhol     create_unimplemented_device("I2C1",      0x40005400, 0x400);
37504a7c7b1SInès Varhol     create_unimplemented_device("I2C2",      0x40005800, 0x400);
37604a7c7b1SInès Varhol     create_unimplemented_device("I2C3",      0x40005C00, 0x400);
37704a7c7b1SInès Varhol     /* RESERVED:    0x40006000, 0x400 */
37804a7c7b1SInès Varhol     create_unimplemented_device("CAN1",      0x40006400, 0x400);
37904a7c7b1SInès Varhol     /* RESERVED:    0x40006800, 0x400 */
38004a7c7b1SInès Varhol     create_unimplemented_device("PWR",       0x40007000, 0x400);
38104a7c7b1SInès Varhol     create_unimplemented_device("DAC1",      0x40007400, 0x400);
38204a7c7b1SInès Varhol     create_unimplemented_device("OPAMP",     0x40007800, 0x400);
38304a7c7b1SInès Varhol     create_unimplemented_device("LPTIM1",    0x40007C00, 0x400);
38404a7c7b1SInès Varhol     /* RESERVED:    0x40008400, 0x400 */
38504a7c7b1SInès Varhol     create_unimplemented_device("SWPMI1",    0x40008800, 0x400);
38604a7c7b1SInès Varhol     /* RESERVED:    0x40008C00, 0x800 */
38704a7c7b1SInès Varhol     create_unimplemented_device("LPTIM2",    0x40009400, 0x400);
38804a7c7b1SInès Varhol     /* RESERVED:    0x40009800, 0x6800 */
38904a7c7b1SInès Varhol 
39004a7c7b1SInès Varhol     /* APB2 BUS */
39104a7c7b1SInès Varhol     create_unimplemented_device("VREFBUF",   0x40010030, 0x1D0);
39204a7c7b1SInès Varhol     create_unimplemented_device("COMP",      0x40010200, 0x200);
39304a7c7b1SInès Varhol     /* RESERVED:    0x40010800, 0x1400 */
39404a7c7b1SInès Varhol     create_unimplemented_device("FIREWALL",  0x40011C00, 0x400);
39504a7c7b1SInès Varhol     /* RESERVED:    0x40012000, 0x800 */
39604a7c7b1SInès Varhol     create_unimplemented_device("SDMMC1",    0x40012800, 0x400);
39704a7c7b1SInès Varhol     create_unimplemented_device("TIM1",      0x40012C00, 0x400);
39804a7c7b1SInès Varhol     create_unimplemented_device("SPI1",      0x40013000, 0x400);
39904a7c7b1SInès Varhol     create_unimplemented_device("TIM8",      0x40013400, 0x400);
40004a7c7b1SInès Varhol     /* RESERVED:    0x40013C00, 0x400 */
40104a7c7b1SInès Varhol     create_unimplemented_device("TIM15",     0x40014000, 0x400);
40204a7c7b1SInès Varhol     create_unimplemented_device("TIM16",     0x40014400, 0x400);
40304a7c7b1SInès Varhol     create_unimplemented_device("TIM17",     0x40014800, 0x400);
40404a7c7b1SInès Varhol     /* RESERVED:    0x40014C00, 0x800 */
40504a7c7b1SInès Varhol     create_unimplemented_device("SAI1",      0x40015400, 0x400);
40604a7c7b1SInès Varhol     create_unimplemented_device("SAI2",      0x40015800, 0x400);
40704a7c7b1SInès Varhol     /* RESERVED:    0x40015C00, 0x400 */
40804a7c7b1SInès Varhol     create_unimplemented_device("DFSDM1",    0x40016000, 0x400);
40904a7c7b1SInès Varhol     /* RESERVED:    0x40016400, 0x9C00 */
41004a7c7b1SInès Varhol 
41104a7c7b1SInès Varhol     /* AHB1 BUS */
41204a7c7b1SInès Varhol     create_unimplemented_device("DMA1",      0x40020000, 0x400);
41304a7c7b1SInès Varhol     create_unimplemented_device("DMA2",      0x40020400, 0x400);
41404a7c7b1SInès Varhol     /* RESERVED:    0x40020800, 0x800 */
41504a7c7b1SInès Varhol     /* RESERVED:    0x40021400, 0xC00 */
41604a7c7b1SInès Varhol     create_unimplemented_device("FLASH",     0x40022000, 0x400);
41704a7c7b1SInès Varhol     /* RESERVED:    0x40022400, 0xC00 */
41804a7c7b1SInès Varhol     create_unimplemented_device("CRC",       0x40023000, 0x400);
41904a7c7b1SInès Varhol     /* RESERVED:    0x40023400, 0x400 */
42004a7c7b1SInès Varhol     create_unimplemented_device("TSC",       0x40024000, 0x400);
42104a7c7b1SInès Varhol 
42204a7c7b1SInès Varhol     /* RESERVED:    0x40024400, 0x7FDBC00 */
42304a7c7b1SInès Varhol 
42404a7c7b1SInès Varhol     /* AHB2 BUS */
42504a7c7b1SInès Varhol     /* RESERVED:    0x48002000, 0x7FDBC00 */
42604a7c7b1SInès Varhol     create_unimplemented_device("OTG_FS",    0x50000000, 0x40000);
42704a7c7b1SInès Varhol     create_unimplemented_device("ADC",       0x50040000, 0x400);
42804a7c7b1SInès Varhol     /* RESERVED:    0x50040400, 0x20400 */
42904a7c7b1SInès Varhol     create_unimplemented_device("RNG",       0x50060800, 0x400);
43004a7c7b1SInès Varhol 
43104a7c7b1SInès Varhol     /* AHB3 BUS */
43204a7c7b1SInès Varhol     create_unimplemented_device("FMC",       0xA0000000, 0x1000);
43304a7c7b1SInès Varhol     create_unimplemented_device("QUADSPI",   0xA0001000, 0x400);
43404a7c7b1SInès Varhol }
43504a7c7b1SInès Varhol 
stm32l4x5_soc_class_init(ObjectClass * klass,void * data)43604a7c7b1SInès Varhol static void stm32l4x5_soc_class_init(ObjectClass *klass, void *data)
43704a7c7b1SInès Varhol {
43804a7c7b1SInès Varhol 
43904a7c7b1SInès Varhol     DeviceClass *dc = DEVICE_CLASS(klass);
44004a7c7b1SInès Varhol 
44104a7c7b1SInès Varhol     dc->realize = stm32l4x5_soc_realize;
44204a7c7b1SInès Varhol     /* Reason: Mapped at fixed location on the system bus */
44304a7c7b1SInès Varhol     dc->user_creatable = false;
44404a7c7b1SInès Varhol     /* No vmstate or reset required: device has no internal state */
44504a7c7b1SInès Varhol }
44604a7c7b1SInès Varhol 
stm32l4x5xc_soc_class_init(ObjectClass * oc,void * data)44704a7c7b1SInès Varhol static void stm32l4x5xc_soc_class_init(ObjectClass *oc, void *data)
44804a7c7b1SInès Varhol {
44904a7c7b1SInès Varhol     Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc);
45004a7c7b1SInès Varhol 
45104a7c7b1SInès Varhol     ssc->flash_size = 256 * KiB;
45204a7c7b1SInès Varhol }
45304a7c7b1SInès Varhol 
stm32l4x5xe_soc_class_init(ObjectClass * oc,void * data)45404a7c7b1SInès Varhol static void stm32l4x5xe_soc_class_init(ObjectClass *oc, void *data)
45504a7c7b1SInès Varhol {
45604a7c7b1SInès Varhol     Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc);
45704a7c7b1SInès Varhol 
45804a7c7b1SInès Varhol     ssc->flash_size = 512 * KiB;
45904a7c7b1SInès Varhol }
46004a7c7b1SInès Varhol 
stm32l4x5xg_soc_class_init(ObjectClass * oc,void * data)46104a7c7b1SInès Varhol static void stm32l4x5xg_soc_class_init(ObjectClass *oc, void *data)
46204a7c7b1SInès Varhol {
46304a7c7b1SInès Varhol     Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc);
46404a7c7b1SInès Varhol 
46504a7c7b1SInès Varhol     ssc->flash_size = 1 * MiB;
46604a7c7b1SInès Varhol }
46704a7c7b1SInès Varhol 
46804a7c7b1SInès Varhol static const TypeInfo stm32l4x5_soc_types[] = {
46904a7c7b1SInès Varhol     {
47004a7c7b1SInès Varhol         .name           = TYPE_STM32L4X5XC_SOC,
47104a7c7b1SInès Varhol         .parent         = TYPE_STM32L4X5_SOC,
47204a7c7b1SInès Varhol         .class_init     = stm32l4x5xc_soc_class_init,
47304a7c7b1SInès Varhol     }, {
47404a7c7b1SInès Varhol         .name           = TYPE_STM32L4X5XE_SOC,
47504a7c7b1SInès Varhol         .parent         = TYPE_STM32L4X5_SOC,
47604a7c7b1SInès Varhol         .class_init     = stm32l4x5xe_soc_class_init,
47704a7c7b1SInès Varhol     }, {
47804a7c7b1SInès Varhol         .name           = TYPE_STM32L4X5XG_SOC,
47904a7c7b1SInès Varhol         .parent         = TYPE_STM32L4X5_SOC,
48004a7c7b1SInès Varhol         .class_init     = stm32l4x5xg_soc_class_init,
48104a7c7b1SInès Varhol     }, {
48204a7c7b1SInès Varhol         .name           = TYPE_STM32L4X5_SOC,
48304a7c7b1SInès Varhol         .parent         = TYPE_SYS_BUS_DEVICE,
48404a7c7b1SInès Varhol         .instance_size  = sizeof(Stm32l4x5SocState),
48504a7c7b1SInès Varhol         .instance_init  = stm32l4x5_soc_initfn,
48604a7c7b1SInès Varhol         .class_size     = sizeof(Stm32l4x5SocClass),
48704a7c7b1SInès Varhol         .class_init     = stm32l4x5_soc_class_init,
48804a7c7b1SInès Varhol         .abstract       = true,
48904a7c7b1SInès Varhol     }
49004a7c7b1SInès Varhol };
49104a7c7b1SInès Varhol 
49204a7c7b1SInès Varhol DEFINE_TYPES(stm32l4x5_soc_types)
493