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