From patchwork Wed Mar 20 20:20:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Felipe Balbi X-Patchwork-Id: 1914227 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20201202 header.b=EJvRvdCh; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4V0Kjx3Wqyz1yWs for ; Thu, 21 Mar 2024 07:21:25 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rn2Qw-00076U-O6; Wed, 20 Mar 2024 16:21:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rn2Qu-000769-1E for qemu-devel@nongnu.org; Wed, 20 Mar 2024 16:21:08 -0400 Received: from dfw.source.kernel.org ([2604:1380:4641:c500::1]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rn2Qq-0007rv-3H for qemu-devel@nongnu.org; Wed, 20 Mar 2024 16:21:07 -0400 Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by dfw.source.kernel.org (Postfix) with ESMTP id AED77610A5; Wed, 20 Mar 2024 20:21:02 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 43545C433C7; Wed, 20 Mar 2024 20:21:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710966062; bh=EsGTpnXn+ZkNHuZDS47tp3egc+k55pVU2pu/7Tv4ZTA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EJvRvdChvaMlOQwEBG6ira0iz0+SzFWtpCiE/vah/If/naOAAZNpB3XeIATA4ytCR 3+HWsBgGJ2GONDhXswdfLgPALWBG8hFjqLntY4i+0DDE047x5UKvADzpXb3FudBE8D BNdpPuYBVj8J+OtFaPIeJ5sr+Rcbw9trse+9ai+DTzJ15FbuHEdCuqH0qQ7OmeFxMj 1cuRLp6+cd1bYJl4Go72TGn1cU/R9QBZOQ68q86tL2sDjobXObe9gmjONeDULhk5/e 8SOxG6PT8AdNxOyTkFgE4+SSPNfJvIu7v4c1JoYU6TC0SkrUjBOVT94KlZEXsHKDQd jEkC8n8UvtYNA== From: Felipe Balbi To: qemu-devel@nongnu.org Cc: Samuel Tardieu , Felipe Balbi Subject: [PATCH v2 1/2] hw/arm: Add support for stm32g000 SoC family Date: Wed, 20 Mar 2024 22:20:59 +0200 Message-ID: <20240320202100.820228-2-balbi@kernel.org> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240320202100.820228-1-balbi@kernel.org> References: <20240320202100.820228-1-balbi@kernel.org> MIME-Version: 1.0 Received-SPF: pass client-ip=2604:1380:4641:c500::1; envelope-from=balbi@kernel.org; helo=dfw.source.kernel.org X-Spam_score_int: -47 X-Spam_score: -4.8 X-Spam_bar: ---- X-Spam_report: (-4.8 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.417, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Minimal support with USARTs and SPIs working. This SoC will be used to create and nucleo-g071rb board. Signed-off-by: Felipe Balbi --- Changes since v1: - Convert tabs to spaces (checkpatch.pl) - Correct lines longer than 80 characters (checkpatch.pl) - Correct num-prio-bits (Samuel Tardieu) - Correct num-irqs (Found reviewing RM0444) MAINTAINERS | 7 + hw/arm/Kconfig | 6 + hw/arm/meson.build | 1 + hw/arm/stm32g000_soc.c | 253 +++++++++++++++++++++++++++++++++ include/hw/arm/stm32g000_soc.h | 62 ++++++++ 5 files changed, 329 insertions(+) create mode 100644 hw/arm/stm32g000_soc.c create mode 100644 include/hw/arm/stm32g000_soc.h diff --git a/MAINTAINERS b/MAINTAINERS index 409d7db4d457..bce2eb3ad70b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1134,6 +1134,13 @@ F: hw/misc/stm32l4x5_rcc.c F: hw/gpio/stm32l4x5_gpio.c F: include/hw/*/stm32l4x5_*.h +STM32G000 SoC Family +M: Felipe Balbi +L: qemu-arm@nongnu.org +S: Maintained +F: hw/arm/stm32g000_soc.c +F: include/hw/*/stm32g000_*.h + B-L475E-IOT01A IoT Node M: Arnaud Minier M: Inès Varhol diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 893a7bff66b9..28a46d2b1ad3 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -463,6 +463,12 @@ config STM32F405_SOC select STM32F4XX_SYSCFG select STM32F4XX_EXTI +config STM32G000_SOC + bool + select ARM_V7M + select STM32F2XX_USART + select STM32F2XX_SPI + config B_L475E_IOT01A bool default y diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 6808135c1f79..9c4137a988e1 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -34,6 +34,7 @@ arm_ss.add(when: ['CONFIG_RASPI', 'TARGET_AARCH64'], if_true: files('bcm2838.c', arm_ss.add(when: 'CONFIG_STM32F100_SOC', if_true: files('stm32f100_soc.c')) arm_ss.add(when: 'CONFIG_STM32F205_SOC', if_true: files('stm32f205_soc.c')) arm_ss.add(when: 'CONFIG_STM32F405_SOC', if_true: files('stm32f405_soc.c')) +arm_ss.add(when: 'CONFIG_STM32G000_SOC', if_true: files('stm32g000_soc.c')) arm_ss.add(when: 'CONFIG_B_L475E_IOT01A', if_true: files('b-l475e-iot01a.c')) arm_ss.add(when: 'CONFIG_STM32L4X5_SOC', if_true: files('stm32l4x5_soc.c')) arm_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp.c', 'xlnx-zcu102.c')) diff --git a/hw/arm/stm32g000_soc.c b/hw/arm/stm32g000_soc.c new file mode 100644 index 000000000000..48531d41fcc7 --- /dev/null +++ b/hw/arm/stm32g000_soc.c @@ -0,0 +1,253 @@ +/* + * STM32G000 SoC + * + * Copyright (c) 2024 Felipe Balbi + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/module.h" +#include "hw/arm/boot.h" +#include "exec/address-spaces.h" +#include "hw/arm/stm32g000_soc.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-clock.h" +#include "hw/misc/unimp.h" +#include "sysemu/sysemu.h" + +/* stm32g000_soc implementation is derived from stm32f100_soc */ + +struct stm32g0_ip_config { + const char *name; + uint32_t addr; + uint32_t irq; +}; + +#define STM32G0_DEFINE_IP(n, a, i) \ +{ \ + .name = (n), \ + .addr = (a), \ + .irq = (i), \ +} + +static const struct stm32g0_ip_config usart_config[STM_NUM_USARTS] = { + STM32G0_DEFINE_IP("USART1", 0x40013800, 27), + STM32G0_DEFINE_IP("USART2", 0x40004000, 28), + STM32G0_DEFINE_IP("USART3", 0x40004400, 29), + STM32G0_DEFINE_IP("USART4", 0x40004800, 29), + STM32G0_DEFINE_IP("USART5", 0x40004c00, 29), + STM32G0_DEFINE_IP("USART6", 0x40005000, 29), + STM32G0_DEFINE_IP("LPUSART1", 0x40008000, 29), + STM32G0_DEFINE_IP("LPUSART2", 0x40008400, 28), +}; + +static const struct stm32g0_ip_config spi_config[STM_NUM_SPIS] = { + STM32G0_DEFINE_IP("SPI1", 0x40013000, 25), + STM32G0_DEFINE_IP("SPI2", 0x40003800, 26), + + /* Only on STM32G0B1xx and STM32G0C1xx */ + /* STM32G0_DEFINE_IP("SPI3", 0x4003c000, 26), */ +}; + +static void stm32g000_soc_initfn(Object *obj) +{ + STM32G000State *s = STM32G000_SOC(obj); + int i; + + object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M); + + for (i = 0; i < STM_NUM_USARTS; i++) { + object_initialize_child(obj, "usart[*]", &s->usart[i], + TYPE_STM32F2XX_USART); + } + + for (i = 0; i < STM_NUM_SPIS; i++) { + object_initialize_child(obj, "spi[*]", &s->spi[i], TYPE_STM32F2XX_SPI); + } + + s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0); + s->refclk = qdev_init_clock_in(DEVICE(s), "refclk", NULL, NULL, 0); +} + +static void stm32g000_soc_realize(DeviceState *dev_soc, Error **errp) +{ + STM32G000State *s = STM32G000_SOC(dev_soc); + DeviceState *dev, *armv7m; + SysBusDevice *busdev; + + MemoryRegion *system_memory = get_system_memory(); + + /* + * We use s->refclk internally and only define it with qdev_init_clock_in() + * so it is correctly parented and not leaked on an init/deinit; it is not + * intended as an externally exposed clock. + */ + if (clock_has_source(s->refclk)) { + error_setg(errp, "refclk clock must not be wired up by the board code"); + return; + } + + if (!clock_has_source(s->sysclk)) { + error_setg(errp, "sysclk clock must be wired up by the board code"); + return; + } + + /* + * TODO: ideally we should model the SoC RCC and its ability to + * change the sysclk frequency and define different sysclk sources. + */ + + /* The refclk always runs at frequency HCLK / 8 */ + clock_set_mul_div(s->refclk, 8, 1); + clock_set_source(s->refclk, s->sysclk); + + /* + * Init flash region + * Flash starts at 0x08000000 and then is aliased to boot memory at 0x0 + */ + memory_region_init_rom(&s->flash, OBJECT(dev_soc), "STM32G000.flash", + FLASH_SIZE, &error_fatal); + memory_region_init_alias(&s->flash_alias, OBJECT(dev_soc), + "STM32G000.flash.alias", &s->flash, 0, FLASH_SIZE); + memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, &s->flash); + memory_region_add_subregion(system_memory, 0, &s->flash_alias); + + /* Init SRAM region */ + memory_region_init_ram(&s->sram, NULL, "STM32G000.sram", SRAM_SIZE, + &error_fatal); + memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, &s->sram); + + /* Init ARMv7m */ + armv7m = DEVICE(&s->armv7m); + qdev_prop_set_uint32(armv7m, "num-irq", 32); + qdev_prop_set_uint8(armv7m, "num-prio-bits", 2); + qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m0")); + qdev_prop_set_bit(armv7m, "enable-bitband", true); + qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk); + qdev_connect_clock_in(armv7m, "refclk", s->refclk); + object_property_set_link(OBJECT(&s->armv7m), "memory", + OBJECT(get_system_memory()), &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) { + return; + } + + /* Attach UART (uses USART registers) and USART controllers */ + for (unsigned i = 0; i < STM_NUM_USARTS; i++) { + dev = DEVICE(&(s->usart[i])); + qdev_prop_set_chr(dev, "chardev", serial_hd(i)); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->usart[i]), errp)) { + return; + } + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, usart_config[i].addr); + sysbus_connect_irq(busdev, + 0, + qdev_get_gpio_in(armv7m, usart_config[i].irq)); + } + + /* + * SPI 1 and 2 + * + * REVISIT: STM32G0B1xx and STM32G0C1xx have a 3rd SPI + */ + for (unsigned i = 0; i < STM_NUM_SPIS; i++) { + dev = DEVICE(&(s->spi[i])); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { + return; + } + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, spi_config[i].addr); + sysbus_connect_irq(busdev, + 0, + qdev_get_gpio_in(armv7m, spi_config[i].irq)); + } + + /* Review addresses */ + create_unimplemented_device("timer[2]", 0x40000000, 0x400); + create_unimplemented_device("timer[3]", 0x40000400, 0x400); + create_unimplemented_device("timer[4]", 0x40000800, 0x400); + create_unimplemented_device("timer[6]", 0x40001000, 0x400); + create_unimplemented_device("timer[7]", 0x40001400, 0x400); + create_unimplemented_device("RTC", 0x40002800, 0x400); + create_unimplemented_device("WWDG", 0x40002c00, 0x400); + create_unimplemented_device("IWDG", 0x40003000, 0x400); + create_unimplemented_device("USB", 0x40005000, 0x400); + create_unimplemented_device("FDCAN1", 0x40006400, 0x400); + create_unimplemented_device("FDCAN2", 0x40006800, 0x400); + create_unimplemented_device("CRS", 0x40006c00, 0x400); + create_unimplemented_device("PWR", 0x40007000, 0x400); + create_unimplemented_device("DAC", 0x40007400, 0x400); + create_unimplemented_device("CEC", 0x40007800, 0x400); + create_unimplemented_device("LPTIM1", 0x40007c00, 0x400); + create_unimplemented_device("LPUART1", 0x40008000, 0x400); + create_unimplemented_device("LPUART2", 0x40008400, 0x400); + create_unimplemented_device("I2C3", 0x40008800, 0x400); + create_unimplemented_device("LPTIM2", 0x40009400, 0x400); + create_unimplemented_device("USB RAM1", 0x40009800, 0x400); + create_unimplemented_device("USB RAM2", 0x40009c00, 0x400); + create_unimplemented_device("UCPD1", 0x4000a000, 0x400); + create_unimplemented_device("UCPD2", 0x4000a400, 0x400); + create_unimplemented_device("TAMP", 0x4000b000, 0x400); + create_unimplemented_device("FDCAN", 0x4000b400, 0x800); + create_unimplemented_device("ADC", 0x40012400, 0x400); + create_unimplemented_device("timer[1]", 0x40012C00, 0x400); + create_unimplemented_device("timer[15]", 0x40014000, 0x400); + create_unimplemented_device("timer[16]", 0x40014400, 0x400); + create_unimplemented_device("timer[17]", 0x40014800, 0x400); + create_unimplemented_device("DMA1", 0x40020000, 0x400); + create_unimplemented_device("DMA2", 0x40020400, 0x400); + create_unimplemented_device("DMAMUX", 0x40020800, 0x800); + create_unimplemented_device("RCC", 0x40021000, 0x400); + create_unimplemented_device("EXTI", 0x40021800, 0x400); + create_unimplemented_device("FLASH", 0x40022000, 0x400); + create_unimplemented_device("CRC", 0x40023000, 0x400); + create_unimplemented_device("RNG", 0x40025000, 0x400); + create_unimplemented_device("AES", 0x40026000, 0x400); + create_unimplemented_device("GPIOA", 0x50000000, 0x400); + create_unimplemented_device("GPIOB", 0x50000400, 0x400); + create_unimplemented_device("GPIOC", 0x50000800, 0x400); + create_unimplemented_device("GPIOD", 0x50000c00, 0x400); + create_unimplemented_device("GPIOE", 0x50001000, 0x400); + create_unimplemented_device("GPIOF", 0x50001400, 0x400); +} + +static void stm32g000_soc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = stm32g000_soc_realize; + /* No vmstate or reset required: device has no internal state */ +} + +static const TypeInfo stm32g000_soc_info = { + .name = TYPE_STM32G000_SOC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(STM32G000State), + .instance_init = stm32g000_soc_initfn, + .class_init = stm32g000_soc_class_init, +}; + +static void stm32g000_soc_types(void) +{ + type_register_static(&stm32g000_soc_info); +} + +type_init(stm32g000_soc_types) diff --git a/include/hw/arm/stm32g000_soc.h b/include/hw/arm/stm32g000_soc.h new file mode 100644 index 000000000000..dd3857c87189 --- /dev/null +++ b/include/hw/arm/stm32g000_soc.h @@ -0,0 +1,62 @@ +/* + * STM32G000 SoC + * + * Copyright (c) 2024 Felipe Balbi + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_ARM_STM32G000_SOC_H +#define HW_ARM_STM32G000_SOC_H + +#include "hw/gpio/stm32l4x5_gpio.h" +#include "hw/char/stm32f2xx_usart.h" +#include "hw/ssi/stm32f2xx_spi.h" +#include "hw/arm/armv7m.h" +#include "qom/object.h" +#include "hw/clock.h" + +#define TYPE_STM32G000_SOC "stm32g000-soc" +OBJECT_DECLARE_SIMPLE_TYPE(STM32G000State, STM32G000_SOC) + +#define STM_NUM_USARTS 8 +#define STM_NUM_SPIS 2 + +#define FLASH_BASE_ADDRESS 0x08000000 +#define FLASH_SIZE (128 * 1024) +#define SRAM_BASE_ADDRESS 0x20000000 +#define SRAM_SIZE (36 * 1024) + +struct STM32G000State { + SysBusDevice parent_obj; + + ARMv7MState armv7m; + + STM32F2XXUsartState usart[STM_NUM_USARTS]; + STM32F2XXSPIState spi[STM_NUM_SPIS]; + + MemoryRegion sram; + MemoryRegion flash; + MemoryRegion flash_alias; + + Clock *sysclk; + Clock *refclk; +}; + +#endif