104a7c7b1SInès Varhol /* 204a7c7b1SInès Varhol * STM32L4x5 SoC family 304a7c7b1SInès Varhol * 4*5b5b014bSInès Varhol * Copyright (c) 2023-2024 Arnaud Minier <arnaud.minier@telecom-paris.fr> 5*5b5b014bSInè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 845928ed26SInès Varhol static const int exti_or_gates_out[NUM_EXTI_OR_GATES] = { 855928ed26SInès Varhol 23, 40, 63, 1, 865928ed26SInès Varhol }; 875928ed26SInès Varhol 885928ed26SInès Varhol static const int exti_or_gates_num_lines_in[NUM_EXTI_OR_GATES] = { 895928ed26SInès Varhol 5, 6, 2, 5, 905928ed26SInès Varhol }; 915928ed26SInès Varhol 925928ed26SInès Varhol /* 3 OR gates with consecutive inputs */ 935928ed26SInès Varhol #define NUM_EXTI_SIMPLE_OR_GATES 3 945928ed26SInès Varhol static const int exti_or_gates_first_line_in[NUM_EXTI_SIMPLE_OR_GATES] = { 955928ed26SInès Varhol 5, 10, 21, 965928ed26SInès Varhol }; 975928ed26SInès Varhol 985928ed26SInès Varhol /* 1 OR gate with non-consecutive inputs */ 995928ed26SInès Varhol #define EXTI_OR_GATE1_NUM_LINES_IN 5 1005928ed26SInès Varhol static const int exti_or_gate1_lines_in[EXTI_OR_GATE1_NUM_LINES_IN] = { 1015928ed26SInès Varhol 16, 35, 36, 37, 38, 1025928ed26SInès Varhol }; 1035928ed26SInès Varhol 1041c38129dSInès Varhol static const struct { 1051c38129dSInès Varhol uint32_t addr; 1061c38129dSInès Varhol uint32_t moder_reset; 1071c38129dSInès Varhol uint32_t ospeedr_reset; 1081c38129dSInès Varhol uint32_t pupdr_reset; 1091c38129dSInès Varhol } stm32l4x5_gpio_cfg[NUM_GPIOS] = { 1101c38129dSInès Varhol { 0x48000000, 0xABFFFFFF, 0x0C000000, 0x64000000 }, 1111c38129dSInès Varhol { 0x48000400, 0xFFFFFEBF, 0x00000000, 0x00000100 }, 1121c38129dSInès Varhol { 0x48000800, 0xFFFFFFFF, 0x00000000, 0x00000000 }, 1131c38129dSInès Varhol { 0x48000C00, 0xFFFFFFFF, 0x00000000, 0x00000000 }, 1141c38129dSInès Varhol { 0x48001000, 0xFFFFFFFF, 0x00000000, 0x00000000 }, 1151c38129dSInès Varhol { 0x48001400, 0xFFFFFFFF, 0x00000000, 0x00000000 }, 1161c38129dSInès Varhol { 0x48001800, 0xFFFFFFFF, 0x00000000, 0x00000000 }, 1171c38129dSInès Varhol { 0x48001C00, 0x0000000F, 0x00000000, 0x00000000 }, 1181c38129dSInès Varhol }; 1191c38129dSInès Varhol 12092741432SArnaud Minier static const hwaddr usart_addr[] = { 12192741432SArnaud Minier 0x40013800, /* "USART1", 0x400 */ 12292741432SArnaud Minier 0x40004400, /* "USART2", 0x400 */ 12392741432SArnaud Minier 0x40004800, /* "USART3", 0x400 */ 12492741432SArnaud Minier }; 12592741432SArnaud Minier static const hwaddr uart_addr[] = { 12692741432SArnaud Minier 0x40004C00, /* "UART4" , 0x400 */ 12792741432SArnaud Minier 0x40005000 /* "UART5" , 0x400 */ 12892741432SArnaud Minier }; 12992741432SArnaud Minier 13092741432SArnaud Minier #define LPUART_BASE_ADDRESS 0x40008000 13192741432SArnaud Minier 13292741432SArnaud Minier static const int usart_irq[] = { 37, 38, 39 }; 13392741432SArnaud Minier static const int uart_irq[] = { 52, 53 }; 13492741432SArnaud Minier #define LPUART_IRQ 70 13592741432SArnaud Minier 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 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 253*5b5b014bSInès Varhol qdev_pass_gpios(DEVICE(&s->syscfg), dev_soc, NULL); 254*5b5b014bSInè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 3001c38129dSInès Varhol for (unsigned i = 0; i < GPIO_NUM_PINS; i++) { 3017dfe2312SInès Varhol qdev_connect_gpio_out(DEVICE(&s->syscfg), i, 3027dfe2312SInès Varhol qdev_get_gpio_in(DEVICE(&s->exti), i)); 3037dfe2312SInès Varhol } 3047dfe2312SInès Varhol 305d6b55a0fSArnaud Minier /* RCC device */ 306d6b55a0fSArnaud Minier busdev = SYS_BUS_DEVICE(&s->rcc); 307d6b55a0fSArnaud Minier if (!sysbus_realize(busdev, errp)) { 308d6b55a0fSArnaud Minier return; 309d6b55a0fSArnaud Minier } 310d6b55a0fSArnaud Minier sysbus_mmio_map(busdev, 0, RCC_BASE_ADDRESS); 311d6b55a0fSArnaud Minier sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, RCC_IRQ)); 312d6b55a0fSArnaud Minier 31392741432SArnaud Minier /* USART devices */ 31492741432SArnaud Minier for (int i = 0; i < STM_NUM_USARTS; i++) { 31592741432SArnaud Minier g_autofree char *name = g_strdup_printf("usart%d-out", i + 1); 31692741432SArnaud Minier dev = DEVICE(&(s->usart[i])); 31792741432SArnaud Minier qdev_prop_set_chr(dev, "chardev", serial_hd(i)); 31892741432SArnaud Minier qdev_connect_clock_in(dev, "clk", 31992741432SArnaud Minier qdev_get_clock_out(DEVICE(&(s->rcc)), name)); 32092741432SArnaud Minier busdev = SYS_BUS_DEVICE(dev); 32192741432SArnaud Minier if (!sysbus_realize(busdev, errp)) { 32292741432SArnaud Minier return; 32392741432SArnaud Minier } 32492741432SArnaud Minier sysbus_mmio_map(busdev, 0, usart_addr[i]); 32592741432SArnaud Minier sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, usart_irq[i])); 32692741432SArnaud Minier } 32792741432SArnaud Minier 32892741432SArnaud Minier /* 32992741432SArnaud Minier * TODO: Connect the USARTs, UARTs and LPUART to the EXTI once the EXTI 33092741432SArnaud Minier * can handle other gpio-in than the gpios. (e.g. Direct Lines for the 33192741432SArnaud Minier * usarts) 33292741432SArnaud Minier */ 33392741432SArnaud Minier 33492741432SArnaud Minier /* UART devices */ 33592741432SArnaud Minier for (int i = 0; i < STM_NUM_UARTS; i++) { 33692741432SArnaud Minier g_autofree char *name = g_strdup_printf("uart%d-out", STM_NUM_USARTS + i + 1); 33792741432SArnaud Minier dev = DEVICE(&(s->uart[i])); 33892741432SArnaud Minier qdev_prop_set_chr(dev, "chardev", serial_hd(STM_NUM_USARTS + i)); 33992741432SArnaud Minier qdev_connect_clock_in(dev, "clk", 34092741432SArnaud Minier qdev_get_clock_out(DEVICE(&(s->rcc)), name)); 34192741432SArnaud Minier busdev = SYS_BUS_DEVICE(dev); 34292741432SArnaud Minier if (!sysbus_realize(busdev, errp)) { 34392741432SArnaud Minier return; 34492741432SArnaud Minier } 34592741432SArnaud Minier sysbus_mmio_map(busdev, 0, uart_addr[i]); 34692741432SArnaud Minier sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, uart_irq[i])); 34792741432SArnaud Minier } 34892741432SArnaud Minier 34992741432SArnaud Minier /* LPUART device*/ 35092741432SArnaud Minier dev = DEVICE(&(s->lpuart)); 35192741432SArnaud Minier qdev_prop_set_chr(dev, "chardev", serial_hd(STM_NUM_USARTS + STM_NUM_UARTS)); 35292741432SArnaud Minier qdev_connect_clock_in(dev, "clk", 35392741432SArnaud Minier qdev_get_clock_out(DEVICE(&(s->rcc)), "lpuart1-out")); 35492741432SArnaud Minier busdev = SYS_BUS_DEVICE(dev); 35592741432SArnaud Minier if (!sysbus_realize(busdev, errp)) { 35692741432SArnaud Minier return; 35792741432SArnaud Minier } 35892741432SArnaud Minier sysbus_mmio_map(busdev, 0, LPUART_BASE_ADDRESS); 35992741432SArnaud Minier sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, LPUART_IRQ)); 36092741432SArnaud Minier 36104a7c7b1SInès Varhol /* APB1 BUS */ 36204a7c7b1SInès Varhol create_unimplemented_device("TIM2", 0x40000000, 0x400); 36304a7c7b1SInès Varhol create_unimplemented_device("TIM3", 0x40000400, 0x400); 36404a7c7b1SInès Varhol create_unimplemented_device("TIM4", 0x40000800, 0x400); 36504a7c7b1SInès Varhol create_unimplemented_device("TIM5", 0x40000C00, 0x400); 36604a7c7b1SInès Varhol create_unimplemented_device("TIM6", 0x40001000, 0x400); 36704a7c7b1SInès Varhol create_unimplemented_device("TIM7", 0x40001400, 0x400); 36804a7c7b1SInès Varhol /* RESERVED: 0x40001800, 0x1000 */ 36904a7c7b1SInès Varhol create_unimplemented_device("RTC", 0x40002800, 0x400); 37004a7c7b1SInès Varhol create_unimplemented_device("WWDG", 0x40002C00, 0x400); 37104a7c7b1SInès Varhol create_unimplemented_device("IWDG", 0x40003000, 0x400); 37204a7c7b1SInès Varhol /* RESERVED: 0x40001800, 0x400 */ 37304a7c7b1SInès Varhol create_unimplemented_device("SPI2", 0x40003800, 0x400); 37404a7c7b1SInès Varhol create_unimplemented_device("SPI3", 0x40003C00, 0x400); 37504a7c7b1SInès Varhol /* RESERVED: 0x40004000, 0x400 */ 37604a7c7b1SInès Varhol create_unimplemented_device("I2C1", 0x40005400, 0x400); 37704a7c7b1SInès Varhol create_unimplemented_device("I2C2", 0x40005800, 0x400); 37804a7c7b1SInès Varhol create_unimplemented_device("I2C3", 0x40005C00, 0x400); 37904a7c7b1SInès Varhol /* RESERVED: 0x40006000, 0x400 */ 38004a7c7b1SInès Varhol create_unimplemented_device("CAN1", 0x40006400, 0x400); 38104a7c7b1SInès Varhol /* RESERVED: 0x40006800, 0x400 */ 38204a7c7b1SInès Varhol create_unimplemented_device("PWR", 0x40007000, 0x400); 38304a7c7b1SInès Varhol create_unimplemented_device("DAC1", 0x40007400, 0x400); 38404a7c7b1SInès Varhol create_unimplemented_device("OPAMP", 0x40007800, 0x400); 38504a7c7b1SInès Varhol create_unimplemented_device("LPTIM1", 0x40007C00, 0x400); 38604a7c7b1SInès Varhol /* RESERVED: 0x40008400, 0x400 */ 38704a7c7b1SInès Varhol create_unimplemented_device("SWPMI1", 0x40008800, 0x400); 38804a7c7b1SInès Varhol /* RESERVED: 0x40008C00, 0x800 */ 38904a7c7b1SInès Varhol create_unimplemented_device("LPTIM2", 0x40009400, 0x400); 39004a7c7b1SInès Varhol /* RESERVED: 0x40009800, 0x6800 */ 39104a7c7b1SInès Varhol 39204a7c7b1SInès Varhol /* APB2 BUS */ 39304a7c7b1SInès Varhol create_unimplemented_device("VREFBUF", 0x40010030, 0x1D0); 39404a7c7b1SInès Varhol create_unimplemented_device("COMP", 0x40010200, 0x200); 39504a7c7b1SInès Varhol /* RESERVED: 0x40010800, 0x1400 */ 39604a7c7b1SInès Varhol create_unimplemented_device("FIREWALL", 0x40011C00, 0x400); 39704a7c7b1SInès Varhol /* RESERVED: 0x40012000, 0x800 */ 39804a7c7b1SInès Varhol create_unimplemented_device("SDMMC1", 0x40012800, 0x400); 39904a7c7b1SInès Varhol create_unimplemented_device("TIM1", 0x40012C00, 0x400); 40004a7c7b1SInès Varhol create_unimplemented_device("SPI1", 0x40013000, 0x400); 40104a7c7b1SInès Varhol create_unimplemented_device("TIM8", 0x40013400, 0x400); 40204a7c7b1SInès Varhol /* RESERVED: 0x40013C00, 0x400 */ 40304a7c7b1SInès Varhol create_unimplemented_device("TIM15", 0x40014000, 0x400); 40404a7c7b1SInès Varhol create_unimplemented_device("TIM16", 0x40014400, 0x400); 40504a7c7b1SInès Varhol create_unimplemented_device("TIM17", 0x40014800, 0x400); 40604a7c7b1SInès Varhol /* RESERVED: 0x40014C00, 0x800 */ 40704a7c7b1SInès Varhol create_unimplemented_device("SAI1", 0x40015400, 0x400); 40804a7c7b1SInès Varhol create_unimplemented_device("SAI2", 0x40015800, 0x400); 40904a7c7b1SInès Varhol /* RESERVED: 0x40015C00, 0x400 */ 41004a7c7b1SInès Varhol create_unimplemented_device("DFSDM1", 0x40016000, 0x400); 41104a7c7b1SInès Varhol /* RESERVED: 0x40016400, 0x9C00 */ 41204a7c7b1SInès Varhol 41304a7c7b1SInès Varhol /* AHB1 BUS */ 41404a7c7b1SInès Varhol create_unimplemented_device("DMA1", 0x40020000, 0x400); 41504a7c7b1SInès Varhol create_unimplemented_device("DMA2", 0x40020400, 0x400); 41604a7c7b1SInès Varhol /* RESERVED: 0x40020800, 0x800 */ 41704a7c7b1SInès Varhol /* RESERVED: 0x40021400, 0xC00 */ 41804a7c7b1SInès Varhol create_unimplemented_device("FLASH", 0x40022000, 0x400); 41904a7c7b1SInès Varhol /* RESERVED: 0x40022400, 0xC00 */ 42004a7c7b1SInès Varhol create_unimplemented_device("CRC", 0x40023000, 0x400); 42104a7c7b1SInès Varhol /* RESERVED: 0x40023400, 0x400 */ 42204a7c7b1SInès Varhol create_unimplemented_device("TSC", 0x40024000, 0x400); 42304a7c7b1SInès Varhol 42404a7c7b1SInès Varhol /* RESERVED: 0x40024400, 0x7FDBC00 */ 42504a7c7b1SInès Varhol 42604a7c7b1SInès Varhol /* AHB2 BUS */ 42704a7c7b1SInès Varhol /* RESERVED: 0x48002000, 0x7FDBC00 */ 42804a7c7b1SInès Varhol create_unimplemented_device("OTG_FS", 0x50000000, 0x40000); 42904a7c7b1SInès Varhol create_unimplemented_device("ADC", 0x50040000, 0x400); 43004a7c7b1SInès Varhol /* RESERVED: 0x50040400, 0x20400 */ 43104a7c7b1SInès Varhol create_unimplemented_device("RNG", 0x50060800, 0x400); 43204a7c7b1SInès Varhol 43304a7c7b1SInès Varhol /* AHB3 BUS */ 43404a7c7b1SInès Varhol create_unimplemented_device("FMC", 0xA0000000, 0x1000); 43504a7c7b1SInès Varhol create_unimplemented_device("QUADSPI", 0xA0001000, 0x400); 43604a7c7b1SInès Varhol } 43704a7c7b1SInès Varhol 43804a7c7b1SInès Varhol static void stm32l4x5_soc_class_init(ObjectClass *klass, void *data) 43904a7c7b1SInès Varhol { 44004a7c7b1SInès Varhol 44104a7c7b1SInès Varhol DeviceClass *dc = DEVICE_CLASS(klass); 44204a7c7b1SInès Varhol 44304a7c7b1SInès Varhol dc->realize = stm32l4x5_soc_realize; 44404a7c7b1SInès Varhol /* Reason: Mapped at fixed location on the system bus */ 44504a7c7b1SInès Varhol dc->user_creatable = false; 44604a7c7b1SInès Varhol /* No vmstate or reset required: device has no internal state */ 44704a7c7b1SInès Varhol } 44804a7c7b1SInès Varhol 44904a7c7b1SInès Varhol static void stm32l4x5xc_soc_class_init(ObjectClass *oc, void *data) 45004a7c7b1SInès Varhol { 45104a7c7b1SInès Varhol Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc); 45204a7c7b1SInès Varhol 45304a7c7b1SInès Varhol ssc->flash_size = 256 * KiB; 45404a7c7b1SInès Varhol } 45504a7c7b1SInès Varhol 45604a7c7b1SInès Varhol static void stm32l4x5xe_soc_class_init(ObjectClass *oc, void *data) 45704a7c7b1SInès Varhol { 45804a7c7b1SInès Varhol Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc); 45904a7c7b1SInès Varhol 46004a7c7b1SInès Varhol ssc->flash_size = 512 * KiB; 46104a7c7b1SInès Varhol } 46204a7c7b1SInès Varhol 46304a7c7b1SInès Varhol static void stm32l4x5xg_soc_class_init(ObjectClass *oc, void *data) 46404a7c7b1SInès Varhol { 46504a7c7b1SInès Varhol Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc); 46604a7c7b1SInès Varhol 46704a7c7b1SInès Varhol ssc->flash_size = 1 * MiB; 46804a7c7b1SInès Varhol } 46904a7c7b1SInès Varhol 47004a7c7b1SInès Varhol static const TypeInfo stm32l4x5_soc_types[] = { 47104a7c7b1SInès Varhol { 47204a7c7b1SInès Varhol .name = TYPE_STM32L4X5XC_SOC, 47304a7c7b1SInès Varhol .parent = TYPE_STM32L4X5_SOC, 47404a7c7b1SInès Varhol .class_init = stm32l4x5xc_soc_class_init, 47504a7c7b1SInès Varhol }, { 47604a7c7b1SInès Varhol .name = TYPE_STM32L4X5XE_SOC, 47704a7c7b1SInès Varhol .parent = TYPE_STM32L4X5_SOC, 47804a7c7b1SInès Varhol .class_init = stm32l4x5xe_soc_class_init, 47904a7c7b1SInès Varhol }, { 48004a7c7b1SInès Varhol .name = TYPE_STM32L4X5XG_SOC, 48104a7c7b1SInès Varhol .parent = TYPE_STM32L4X5_SOC, 48204a7c7b1SInès Varhol .class_init = stm32l4x5xg_soc_class_init, 48304a7c7b1SInès Varhol }, { 48404a7c7b1SInès Varhol .name = TYPE_STM32L4X5_SOC, 48504a7c7b1SInès Varhol .parent = TYPE_SYS_BUS_DEVICE, 48604a7c7b1SInès Varhol .instance_size = sizeof(Stm32l4x5SocState), 48704a7c7b1SInès Varhol .instance_init = stm32l4x5_soc_initfn, 48804a7c7b1SInès Varhol .class_size = sizeof(Stm32l4x5SocClass), 48904a7c7b1SInès Varhol .class_init = stm32l4x5_soc_class_init, 49004a7c7b1SInès Varhol .abstract = true, 49104a7c7b1SInès Varhol } 49204a7c7b1SInès Varhol }; 49304a7c7b1SInès Varhol 49404a7c7b1SInès Varhol DEFINE_TYPES(stm32l4x5_soc_types) 495