From nobody Tue Nov 26 14:24:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=telecom-paris.fr ARC-Seal: i=1; a=rsa-sha256; t=1706366482; cv=none; d=zohomail.com; s=zohoarc; b=Mr1/GxTKzlxjpMbINl/nd72ztMVThgrNSzISADzGy3ZWZNh9aKkVzpd/mI9jFep7JaIjC6rDxJC4wdyZOiRDazAu87/aYEdzdjMHQE4UycBSNNQ4RQ1an5tY79SEuJNnyIhIaap7E+aKm4BUtYKmCbXxCL43i9j8CRIZCPXzHto= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1706366482; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=mKa2JpmLtxpLYXxM3hBiKXnnRmHwyUEY3c3pVin1Iiw=; b=Xq6R/ca34T2lAfIm72c33JYmpVWmgmBbszLa28ZaMW9JSAHnX9HhLTNTihRXR0u7vY2nliNfdE23CibGRE6tAy80umIvZpbkIleyiKhLW2qz2hSFf08VlW+/K6hQN52z1r+6b5nCaKusAncXE4bP6fqqG2aI/Ak4BP1/1Xc6zgA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1706366481933457.565039163538; Sat, 27 Jan 2024 06:41:21 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rTjqP-0002TE-L5; Sat, 27 Jan 2024 09:39:41 -0500 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 1rTjqI-0002QF-5N; Sat, 27 Jan 2024 09:39:34 -0500 Received: from zproxy4.enst.fr ([2001:660:330f:2::df]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rTjqD-0002QF-By; Sat, 27 Jan 2024 09:39:33 -0500 Received: from localhost (localhost [IPv6:::1]) by zproxy4.enst.fr (Postfix) with ESMTP id 838B020811; Sat, 27 Jan 2024 15:39:24 +0100 (CET) Received: from zproxy4.enst.fr ([IPv6:::1]) by localhost (zproxy4.enst.fr [IPv6:::1]) (amavis, port 10032) with ESMTP id 2GaALrnWV1-O; Sat, 27 Jan 2024 15:39:22 +0100 (CET) Received: from localhost (localhost [IPv6:::1]) by zproxy4.enst.fr (Postfix) with ESMTP id A9591207F2; Sat, 27 Jan 2024 15:39:22 +0100 (CET) Received: from zproxy4.enst.fr ([IPv6:::1]) by localhost (zproxy4.enst.fr [IPv6:::1]) (amavis, port 10026) with ESMTP id YA0snka3U3Cs; Sat, 27 Jan 2024 15:39:22 +0100 (CET) Received: from AM-Inspiron-3585.numericable.fr (38.162.10.109.rev.sfr.net [109.10.162.38]) by zproxy4.enst.fr (Postfix) with ESMTPSA id EDB0A20744; Sat, 27 Jan 2024 15:39:21 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.10.3 zproxy4.enst.fr A9591207F2 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=telecom-paris.fr; s=A35C7578-1106-11E5-A17F-C303FDDA8F2E; t=1706366362; bh=mKa2JpmLtxpLYXxM3hBiKXnnRmHwyUEY3c3pVin1Iiw=; h=From:To:Date:Message-Id:MIME-Version; b=gv0QiieQ0DxBshrZI91RFoU0/gsYaa+PVOTl4Fox5QznzOQDuTDMpDyrscOp1Bfbh LYjQ8PJpH8Z4i0/uj5Hh/izgZlDmwnVA9/HWvtVkj4PFZ72/Pf69tno7Z/fX9v97OZ QybgLnMC5oK5WL5hNsxNPFJ9gr7JZOuR5aYNxXYs= X-Virus-Scanned: amavis at enst.fr From: Arnaud Minier To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, Arnaud Minier , Samuel Tardieu , Laurent Vivier , Paolo Bonzini , Alistair Francis , Peter Maydell , =?UTF-8?q?Philipe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?In=C3=A8s=20Varhol?= , Thomas Huth Subject: [PATCH v3 1/8] Implement STM32L4x5_RCC skeleton Date: Sat, 27 Jan 2024 15:38:57 +0100 Message-Id: <20240127143904.80187-2-arnaud.minier@telecom-paris.fr> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> References: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2001:660:330f:2::df; envelope-from=arnaud.minier@telecom-paris.fr; helo=zproxy4.enst.fr X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01, WEIRD_QUOTING=0.001 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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @telecom-paris.fr) X-ZM-MESSAGEID: 1706366482322100001 Content-Type: text/plain; charset="utf-8" Signed-off-by: Arnaud Minier Signed-off-by: In=C3=A8s Varhol --- MAINTAINERS | 5 +- docs/system/arm/b-l475e-iot01a.rst | 2 +- hw/arm/Kconfig | 1 + hw/arm/stm32l4x5_soc.c | 12 +- hw/misc/Kconfig | 3 + hw/misc/meson.build | 1 + hw/misc/stm32l4x5_rcc.c | 433 ++++++++++++++++++++++ hw/misc/trace-events | 4 + include/hw/arm/stm32l4x5_soc.h | 2 + include/hw/misc/stm32l4x5_rcc.h | 80 ++++ include/hw/misc/stm32l4x5_rcc_internals.h | 286 ++++++++++++++ 11 files changed, 826 insertions(+), 3 deletions(-) create mode 100644 hw/misc/stm32l4x5_rcc.c create mode 100644 include/hw/misc/stm32l4x5_rcc.h create mode 100644 include/hw/misc/stm32l4x5_rcc_internals.h diff --git a/MAINTAINERS b/MAINTAINERS index b406fb20c0..c4085c32a7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1128,7 +1128,10 @@ M: In=C3=A8s Varhol L: qemu-arm@nongnu.org S: Maintained F: hw/arm/stm32l4x5_soc.c -F: include/hw/arm/stm32l4x5_soc.h +F: hw/misc/stm32l4x5_exti.c +F: hw/misc/stm32l4x5_syscfg.c +F: hw/misc/stm32l4x5_rcc.c +F: include/hw/*/stm32l4x5_*.h =20 B-L475E-IOT01A IoT Node M: Arnaud Minier diff --git a/docs/system/arm/b-l475e-iot01a.rst b/docs/system/arm/b-l475e-i= ot01a.rst index 1a021b306a..b857a56ca4 100644 --- a/docs/system/arm/b-l475e-iot01a.rst +++ b/docs/system/arm/b-l475e-iot01a.rst @@ -17,13 +17,13 @@ Currently B-L475E-IOT01A machine's only supports the fo= llowing devices: - Cortex-M4F based STM32L4x5 SoC - STM32L4x5 EXTI (Extended interrupts and events controller) - STM32L4x5 SYSCFG (System configuration controller) +- STM32L4x5 RCC (Reset and clock control) =20 Missing devices """"""""""""""" =20 The B-L475E-IOT01A does *not* support the following devices: =20 -- Reset and clock control (RCC) - Serial ports (UART) - General-purpose I/Os (GPIO) - Analog to Digital Converter (ADC) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index bb4693bfbb..6bd7ba424f 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -461,6 +461,7 @@ config STM32L4X5_SOC select OR_IRQ select STM32L4X5_SYSCFG select STM32L4X5_EXTI + select STM32L4X5_RCC =20 config XLNX_ZYNQMP_ARM bool diff --git a/hw/arm/stm32l4x5_soc.c b/hw/arm/stm32l4x5_soc.c index 431f982caf..07c841027a 100644 --- a/hw/arm/stm32l4x5_soc.c +++ b/hw/arm/stm32l4x5_soc.c @@ -75,6 +75,8 @@ static const int exti_irq[NUM_EXTI_IRQ] =3D { 1, /* PVM4 wakeup */ 78 /* LCD wakeup, Direct */ }; +#define RCC_BASE_ADDRESS 0x40021000 +#define RCC_IRQ 5 =20 static void stm32l4x5_soc_initfn(Object *obj) { @@ -82,6 +84,7 @@ static void stm32l4x5_soc_initfn(Object *obj) =20 object_initialize_child(obj, "exti", &s->exti, TYPE_STM32L4X5_EXTI); object_initialize_child(obj, "syscfg", &s->syscfg, TYPE_STM32L4X5_SYSC= FG); + object_initialize_child(obj, "rcc", &s->rcc, TYPE_STM32L4X5_RCC); =20 s->sysclk =3D qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0); s->refclk =3D qdev_init_clock_in(DEVICE(s), "refclk", NULL, NULL, 0); @@ -183,6 +186,14 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc= , Error **errp) qdev_get_gpio_in(DEVICE(&s->exti), i)); } =20 + /* RCC device */ + busdev =3D SYS_BUS_DEVICE(&s->rcc); + if (!sysbus_realize(busdev, errp)) { + return; + } + sysbus_mmio_map(busdev, 0, RCC_BASE_ADDRESS); + sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, RCC_IRQ)); + /* APB1 BUS */ create_unimplemented_device("TIM2", 0x40000000, 0x400); create_unimplemented_device("TIM3", 0x40000400, 0x400); @@ -245,7 +256,6 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc,= Error **errp) create_unimplemented_device("DMA1", 0x40020000, 0x400); create_unimplemented_device("DMA2", 0x40020400, 0x400); /* RESERVED: 0x40020800, 0x800 */ - create_unimplemented_device("RCC", 0x40021000, 0x400); /* RESERVED: 0x40021400, 0xC00 */ create_unimplemented_device("FLASH", 0x40022000, 0x400); /* RESERVED: 0x40022400, 0xC00 */ diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 4fc6b29b43..727386fa4b 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -93,6 +93,9 @@ config STM32L4X5_EXTI config STM32L4X5_SYSCFG bool =20 +config STM32L4X5_RCC + bool + config MIPS_ITU bool =20 diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 2ca2ce4b62..1db9d31f80 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -112,6 +112,7 @@ system_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true:= files('stm32f4xx_syscfg. system_ss.add(when: 'CONFIG_STM32F4XX_EXTI', if_true: files('stm32f4xx_ext= i.c')) system_ss.add(when: 'CONFIG_STM32L4X5_EXTI', if_true: files('stm32l4x5_ext= i.c')) system_ss.add(when: 'CONFIG_STM32L4X5_SYSCFG', if_true: files('stm32l4x5_s= yscfg.c')) +system_ss.add(when: 'CONFIG_STM32L4X5_RCC', if_true: files('stm32l4x5_rcc.= c')) system_ss.add(when: 'CONFIG_MPS2_FPGAIO', if_true: files('mps2-fpgaio.c')) system_ss.add(when: 'CONFIG_MPS2_SCC', if_true: files('mps2-scc.c')) =20 diff --git a/hw/misc/stm32l4x5_rcc.c b/hw/misc/stm32l4x5_rcc.c new file mode 100644 index 0000000000..38ca8aad7d --- /dev/null +++ b/hw/misc/stm32l4x5_rcc.c @@ -0,0 +1,433 @@ +/* + * STM32L4X5 RCC (Reset and clock control) + * + * Copyright (c) 2023 Arnaud Minier + * Copyright (c) 2023 In=C3=A8s Varhol + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + * + * The reference used is the STMicroElectronics RM0351 Reference manual + * for STM32L4x5 and STM32L4x6 advanced Arm =C2=AE -based 32-bit MCUs. + * + * Inspired by the BCM2835 CPRMAN clock manager implementation by Luc Mich= el. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "qapi/error.h" +#include "migration/vmstate.h" +#include "hw/misc/stm32l4x5_rcc.h" +#include "hw/misc/stm32l4x5_rcc_internals.h" +#include "hw/clock.h" +#include "hw/irq.h" +#include "hw/qdev-clock.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "trace.h" + +#define HSE_DEFAULT_FRQ 48000000ULL +#define HSI_FRQ 16000000ULL +#define MSI_DEFAULT_FRQ 4000000ULL +#define LSE_FRQ 32768ULL +#define LSI_FRQ 32000ULL + +static void rcc_update_irq(Stm32l4x5RccState *s) +{ + if (s->cifr & CIFR_IRQ_MASK) { + qemu_irq_raise(s->irq); + } else { + qemu_irq_lower(s->irq); + } +} + +static void stm32l4x5_rcc_reset_hold(Object *obj) +{ + Stm32l4x5RccState *s =3D STM32L4X5_RCC(obj); + s->cr =3D 0x00000063; + /* + * Factory-programmed calibration data + * From the reference manual: 0x10XX 00XX + * Value taken from a real card. + */ + s->icscr =3D 0x106E0082; + s->cfgr =3D 0x0; + s->pllcfgr =3D 0x00001000; + s->pllsai1cfgr =3D 0x00001000; + s->pllsai2cfgr =3D 0x00001000; + s->cier =3D 0x0; + s->cifr =3D 0x0; + s->ahb1rstr =3D 0x0; + s->ahb2rstr =3D 0x0; + s->ahb3rstr =3D 0x0; + s->apb1rstr1 =3D 0x0; + s->apb1rstr2 =3D 0x0; + s->apb2rstr =3D 0x0; + s->ahb1enr =3D 0x00000100; + s->ahb2enr =3D 0x0; + s->ahb3enr =3D 0x0; + s->apb1enr1 =3D 0x0; + s->apb1enr2 =3D 0x0; + s->apb2enr =3D 0x0; + s->ahb1smenr =3D 0x00011303; + s->ahb2smenr =3D 0x000532FF; + s->ahb3smenr =3D 0x00000101; + s->apb1smenr1 =3D 0xF2FECA3F; + s->apb1smenr2 =3D 0x00000025; + s->apb2smenr =3D 0x01677C01; + s->ccipr =3D 0x0; + s->bdcr =3D 0x0; + s->csr =3D 0x0C000600; +} + +static uint64_t stm32l4x5_rcc_read(void *opaque, hwaddr addr, + unsigned int size) +{ + Stm32l4x5RccState *s =3D opaque; + uint64_t retvalue =3D 0; + + switch (addr) { + case A_CR: + retvalue =3D s->cr; + break; + case A_ICSCR: + retvalue =3D s->icscr; + break; + case A_CFGR: + retvalue =3D s->cfgr; + break; + case A_PLLCFGR: + retvalue =3D s->pllcfgr; + break; + case A_PLLSAI1CFGR: + retvalue =3D s->pllsai1cfgr; + break; + case A_PLLSAI2CFGR: + retvalue =3D s->pllsai2cfgr; + break; + case A_CIER: + retvalue =3D s->cier; + break; + case A_CIFR: + retvalue =3D s->cifr; + break; + case A_CICR: + /* CICR is write only, return the reset value =3D 0 */ + break; + case A_AHB1RSTR: + retvalue =3D s->ahb1rstr; + break; + case A_AHB2RSTR: + retvalue =3D s->ahb2rstr; + break; + case A_AHB3RSTR: + retvalue =3D s->ahb3rstr; + break; + case A_APB1RSTR1: + retvalue =3D s->apb1rstr1; + break; + case A_APB1RSTR2: + retvalue =3D s->apb1rstr2; + break; + case A_APB2RSTR: + retvalue =3D s->apb2rstr; + break; + case A_AHB1ENR: + retvalue =3D s->ahb1enr; + break; + case A_AHB2ENR: + retvalue =3D s->ahb2enr; + break; + case A_AHB3ENR: + retvalue =3D s->ahb3enr; + break; + case A_APB1ENR1: + retvalue =3D s->apb1enr1; + break; + case A_APB1ENR2: + retvalue =3D s->apb1enr2; + break; + case A_APB2ENR: + retvalue =3D s->apb2enr; + break; + case A_AHB1SMENR: + retvalue =3D s->ahb1smenr; + break; + case A_AHB2SMENR: + retvalue =3D s->ahb2smenr; + break; + case A_AHB3SMENR: + retvalue =3D s->ahb3smenr; + break; + case A_APB1SMENR1: + retvalue =3D s->apb1smenr1; + break; + case A_APB1SMENR2: + retvalue =3D s->apb1smenr2; + break; + case A_APB2SMENR: + retvalue =3D s->apb2smenr; + break; + case A_CCIPR: + retvalue =3D s->ccipr; + break; + case A_BDCR: + retvalue =3D s->bdcr; + break; + case A_CSR: + retvalue =3D s->csr; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); + break; + } + + trace_stm32l4x5_rcc_read(addr, retvalue); + + return retvalue; +} + +static void stm32l4x5_rcc_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + Stm32l4x5RccState *s =3D opaque; + const uint32_t value =3D val64; + + trace_stm32l4x5_rcc_write(addr, value); + + switch (addr) { + case A_CR: + s->cr =3D (s->cr & CR_READ_SET_MASK) | + (value & (CR_READ_SET_MASK | ~CR_READ_ONLY_MASK)); + break; + case A_ICSCR: + s->icscr =3D value & ~ICSCR_READ_ONLY_MASK; + break; + case A_CFGR: + s->cfgr =3D value & ~CFGR_READ_ONLY_MASK; + break; + case A_PLLCFGR: + s->pllcfgr =3D value; + break; + case A_PLLSAI1CFGR: + s->pllsai1cfgr =3D value; + break; + case A_PLLSAI2CFGR: + s->pllsai2cfgr =3D value; + break; + case A_CIER: + s->cier =3D value; + break; + case A_CIFR: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Write attempt into read-only register (CIFR) 0x%"PRIx32"\= n", + __func__, value); + break; + case A_CICR: + /* Clear interrupt flags by writing a 1 to the CICR register */ + s->cifr &=3D ~value; + rcc_update_irq(s); + break; + /* Reset behaviors are not implemented */ + case A_AHB1RSTR: + s->ahb1rstr =3D value; + break; + case A_AHB2RSTR: + s->ahb2rstr =3D value; + break; + case A_AHB3RSTR: + s->ahb3rstr =3D value; + break; + case A_APB1RSTR1: + s->apb1rstr1 =3D value; + break; + case A_APB1RSTR2: + s->apb1rstr2 =3D value; + break; + case A_APB2RSTR: + s->apb2rstr =3D value; + break; + case A_AHB1ENR: + s->ahb1enr =3D value; + break; + case A_AHB2ENR: + s->ahb2enr =3D value; + break; + case A_AHB3ENR: + s->ahb3enr =3D value; + break; + case A_APB1ENR1: + s->apb1enr1 =3D value; + break; + case A_APB1ENR2: + s->apb1enr2 =3D value; + break; + case A_APB2ENR: + s->apb2enr =3D (s->apb2enr & APB2ENR_READ_SET_MASK) | value; + break; + /* Behaviors for Sleep and Stop modes are not implemented */ + case A_AHB1SMENR: + s->ahb1smenr =3D value; + break; + case A_AHB2SMENR: + s->ahb2smenr =3D value; + break; + case A_AHB3SMENR: + s->ahb3smenr =3D value; + break; + case A_APB1SMENR1: + s->apb1smenr1 =3D value; + break; + case A_APB1SMENR2: + s->apb1smenr2 =3D value; + break; + case A_APB2SMENR: + s->apb2smenr =3D value; + break; + case A_CCIPR: + s->ccipr =3D value; + break; + case A_BDCR: + s->bdcr =3D value & ~BDCR_READ_ONLY_MASK; + break; + case A_CSR: + s->csr =3D value & ~CSR_READ_ONLY_MASK; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); + } +} + +static const MemoryRegionOps stm32l4x5_rcc_ops =3D { + .read =3D stm32l4x5_rcc_read, + .write =3D stm32l4x5_rcc_write, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .valid =3D { + .max_access_size =3D 4, + .unaligned =3D false + }, +}; + +static const ClockPortInitArray stm32l4x5_rcc_clocks =3D { + QDEV_CLOCK_IN(Stm32l4x5RccState, hsi16_rc, NULL, 0), + QDEV_CLOCK_IN(Stm32l4x5RccState, msi_rc, NULL, 0), + QDEV_CLOCK_IN(Stm32l4x5RccState, hse, NULL, 0), + QDEV_CLOCK_IN(Stm32l4x5RccState, lsi_rc, NULL, 0), + QDEV_CLOCK_IN(Stm32l4x5RccState, lse_crystal, NULL, 0), + QDEV_CLOCK_IN(Stm32l4x5RccState, sai1_extclk, NULL, 0), + QDEV_CLOCK_IN(Stm32l4x5RccState, sai2_extclk, NULL, 0), + QDEV_CLOCK_END +}; + + +static void stm32l4x5_rcc_init(Object *obj) +{ + Stm32l4x5RccState *s =3D STM32L4X5_RCC(obj); + + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); + + memory_region_init_io(&s->mmio, obj, &stm32l4x5_rcc_ops, s, + TYPE_STM32L4X5_RCC, 0x400); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); + + qdev_init_clocks(DEVICE(s), stm32l4x5_rcc_clocks); + + s->gnd =3D clock_new(obj, "gnd"); +} + +static const VMStateDescription vmstate_stm32l4x5_rcc =3D { + .name =3D TYPE_STM32L4X5_RCC, + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_UINT32(cr, Stm32l4x5RccState), + VMSTATE_UINT32(icscr, Stm32l4x5RccState), + VMSTATE_UINT32(cfgr, Stm32l4x5RccState), + VMSTATE_UINT32(pllcfgr, Stm32l4x5RccState), + VMSTATE_UINT32(pllsai1cfgr, Stm32l4x5RccState), + VMSTATE_UINT32(pllsai2cfgr, Stm32l4x5RccState), + VMSTATE_UINT32(cier, Stm32l4x5RccState), + VMSTATE_UINT32(cifr, Stm32l4x5RccState), + VMSTATE_UINT32(ahb1rstr, Stm32l4x5RccState), + VMSTATE_UINT32(ahb2rstr, Stm32l4x5RccState), + VMSTATE_UINT32(ahb3rstr, Stm32l4x5RccState), + VMSTATE_UINT32(apb1rstr1, Stm32l4x5RccState), + VMSTATE_UINT32(apb1rstr2, Stm32l4x5RccState), + VMSTATE_UINT32(apb2rstr, Stm32l4x5RccState), + VMSTATE_UINT32(ahb1enr, Stm32l4x5RccState), + VMSTATE_UINT32(ahb2enr, Stm32l4x5RccState), + VMSTATE_UINT32(ahb3enr, Stm32l4x5RccState), + VMSTATE_UINT32(apb1enr1, Stm32l4x5RccState), + VMSTATE_UINT32(apb1enr2, Stm32l4x5RccState), + VMSTATE_UINT32(apb2enr, Stm32l4x5RccState), + VMSTATE_UINT32(ahb1smenr, Stm32l4x5RccState), + VMSTATE_UINT32(ahb2smenr, Stm32l4x5RccState), + VMSTATE_UINT32(ahb3smenr, Stm32l4x5RccState), + VMSTATE_UINT32(apb1smenr1, Stm32l4x5RccState), + VMSTATE_UINT32(apb1smenr2, Stm32l4x5RccState), + VMSTATE_UINT32(apb2smenr, Stm32l4x5RccState), + VMSTATE_UINT32(ccipr, Stm32l4x5RccState), + VMSTATE_UINT32(bdcr, Stm32l4x5RccState), + VMSTATE_UINT32(csr, Stm32l4x5RccState), + VMSTATE_END_OF_LIST() + } +}; + + +static void stm32l4x5_rcc_realize(DeviceState *dev, Error **errp) +{ + Stm32l4x5RccState *s =3D STM32L4X5_RCC(dev); + + if (s->hse_frequency < 4000000ULL || + s->hse_frequency > 48000000ULL) { + error_setg(errp, + "HSE frequency is outside of the allowed [4-48]Mhz range: = %" PRIx64 "", + s->hse_frequency); + return; + } + + clock_update_hz(s->msi_rc, MSI_DEFAULT_FRQ); + clock_update_hz(s->sai1_extclk, s->sai1_extclk_frequency); + clock_update_hz(s->sai2_extclk, s->sai2_extclk_frequency); + clock_update(s->gnd, 0); +} + +static Property stm32l4x5_rcc_properties[] =3D { + DEFINE_PROP_UINT64("hse_frequency", Stm32l4x5RccState, + hse_frequency, HSE_DEFAULT_FRQ), + DEFINE_PROP_UINT64("sai1_extclk_frequency", Stm32l4x5RccState, + sai1_extclk_frequency, 0), + DEFINE_PROP_UINT64("sai2_extclk_frequency", Stm32l4x5RccState, + sai2_extclk_frequency, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void stm32l4x5_rcc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + + rc->phases.hold =3D stm32l4x5_rcc_reset_hold; + device_class_set_props(dc, stm32l4x5_rcc_properties); + dc->realize =3D stm32l4x5_rcc_realize; + dc->vmsd =3D &vmstate_stm32l4x5_rcc; +} + +static const TypeInfo stm32l4x5_rcc_types[] =3D { + { + .name =3D TYPE_STM32L4X5_RCC, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(Stm32l4x5RccState), + .instance_init =3D stm32l4x5_rcc_init, + .class_init =3D stm32l4x5_rcc_class_init, + } +}; + +DEFINE_TYPES(stm32l4x5_rcc_types) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 5f5bc92222..62a7599353 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -174,6 +174,10 @@ stm32l4x5_exti_set_irq(int irq, int level) "Set EXTI: = %d to %d" stm32l4x5_exti_read(uint64_t addr, uint64_t data) "reg read: addr: 0x%" PR= Ix64 " val: 0x%" PRIx64 "" stm32l4x5_exti_write(uint64_t addr, uint64_t data) "reg write: addr: 0x%" = PRIx64 " val: 0x%" PRIx64 "" =20 +# stm32l4x5_rcc.c +stm32l4x5_rcc_read(uint64_t addr, uint32_t data) "RCC: Read <0x%" PRIx64 "= > -> 0x%" PRIx32 "" +stm32l4x5_rcc_write(uint64_t addr, uint32_t data) "RCC: Write <0x%" PRIx64= "> <- 0x%" PRIx32 "" + # tz-mpc.c tz_mpc_reg_read(uint32_t offset, uint64_t data, unsigned size) "TZ MPC reg= s read: offset 0x%x data 0x%" PRIx64 " size %u" tz_mpc_reg_write(uint32_t offset, uint64_t data, unsigned size) "TZ MPC re= gs write: offset 0x%x data 0x%" PRIx64 " size %u" diff --git a/include/hw/arm/stm32l4x5_soc.h b/include/hw/arm/stm32l4x5_soc.h index baf70410b5..e480fcc976 100644 --- a/include/hw/arm/stm32l4x5_soc.h +++ b/include/hw/arm/stm32l4x5_soc.h @@ -28,6 +28,7 @@ #include "hw/arm/armv7m.h" #include "hw/misc/stm32l4x5_syscfg.h" #include "hw/misc/stm32l4x5_exti.h" +#include "hw/misc/stm32l4x5_rcc.h" #include "qom/object.h" =20 #define TYPE_STM32L4X5_SOC "stm32l4x5-soc" @@ -43,6 +44,7 @@ struct Stm32l4x5SocState { =20 Stm32l4x5ExtiState exti; Stm32l4x5SyscfgState syscfg; + Stm32l4x5RccState rcc; =20 MemoryRegion sram1; MemoryRegion sram2; diff --git a/include/hw/misc/stm32l4x5_rcc.h b/include/hw/misc/stm32l4x5_rc= c.h new file mode 100644 index 0000000000..5157e96635 --- /dev/null +++ b/include/hw/misc/stm32l4x5_rcc.h @@ -0,0 +1,80 @@ +/* + * STM32L4X5 RCC (Reset and clock control) + * + * Copyright (c) 2023 Arnaud Minier + * Copyright (c) 2023 In=C3=A8s Varhol + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + * + * The reference used is the STMicroElectronics RM0351 Reference manual + * for STM32L4x5 and STM32L4x6 advanced Arm =C2=AE -based 32-bit MCUs. + * + * Inspired by the BCM2835 CPRMAN clock manager by Luc Michel. + */ + +#ifndef HW_STM32L4X5_RCC_H +#define HW_STM32L4X5_RCC_H + +#include "hw/sysbus.h" +#include "qom/object.h" + +#define TYPE_STM32L4X5_RCC "stm32l4x5-rcc" +OBJECT_DECLARE_SIMPLE_TYPE(Stm32l4x5RccState, STM32L4X5_RCC) + +/* In the Stm32l4x5 clock tree, mux have at most 7 sources */ +#define RCC_NUM_CLOCK_MUX_SRC 7 +struct Stm32l4x5RccState { + SysBusDevice parent_obj; + + MemoryRegion mmio; + + uint32_t cr; + uint32_t icscr; + uint32_t cfgr; + uint32_t pllcfgr; + uint32_t pllsai1cfgr; + uint32_t pllsai2cfgr; + uint32_t cier; + uint32_t cifr; + uint32_t ahb1rstr; + uint32_t ahb2rstr; + uint32_t ahb3rstr; + uint32_t apb1rstr1; + uint32_t apb1rstr2; + uint32_t apb2rstr; + uint32_t ahb1enr; + uint32_t ahb2enr; + uint32_t ahb3enr; + uint32_t apb1enr1; + uint32_t apb1enr2; + uint32_t apb2enr; + uint32_t ahb1smenr; + uint32_t ahb2smenr; + uint32_t ahb3smenr; + uint32_t apb1smenr1; + uint32_t apb1smenr2; + uint32_t apb2smenr; + uint32_t ccipr; + uint32_t bdcr; + uint32_t csr; + + /* Clock sources */ + Clock *gnd; + Clock *hsi16_rc; + Clock *msi_rc; + Clock *hse; + Clock *lsi_rc; + Clock *lse_crystal; + Clock *sai1_extclk; + Clock *sai2_extclk; + + qemu_irq irq; + uint64_t hse_frequency; + uint64_t sai1_extclk_frequency; + uint64_t sai2_extclk_frequency; +}; + +#endif /* HW_STM32L4X5_RCC_H */ diff --git a/include/hw/misc/stm32l4x5_rcc_internals.h b/include/hw/misc/st= m32l4x5_rcc_internals.h new file mode 100644 index 0000000000..331ea30db5 --- /dev/null +++ b/include/hw/misc/stm32l4x5_rcc_internals.h @@ -0,0 +1,286 @@ +/* + * STM32L4X5 RCC (Reset and clock control) + * + * Copyright (c) 2023 Arnaud Minier + * Copyright (c) 2023 In=C3=A8s Varhol + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + * + * The reference used is the STMicroElectronics RM0351 Reference manual + * for STM32L4x5 and STM32L4x6 advanced Arm =C2=AE -based 32-bit MCUs. + * + * Inspired by the BCM2835 CPRMAN clock manager implementation by Luc Mich= el. + */ + +#ifndef HW_STM32L4X5_RCC_INTERNALS_H +#define HW_STM32L4X5_RCC_INTERNALS_H + +#include "hw/registerfields.h" +#include "hw/misc/stm32l4x5_rcc.h" + + +/* Register map */ +REG32(CR, 0x00) + FIELD(CR, PLLSAI2RDY, 29, 1) + FIELD(CR, PLLSAI2ON, 28, 1) + FIELD(CR, PLLSAI1RDY, 27, 1) + FIELD(CR, PLLSAI1ON, 26, 1) + FIELD(CR, PLLRDY, 25, 1) + FIELD(CR, PLLON, 24, 1) + FIELD(CR, CSSON, 19, 1) + FIELD(CR, HSEBYP, 18, 1) + FIELD(CR, HSERDY, 17, 1) + FIELD(CR, HSEON, 16, 1) + FIELD(CR, HSIASFS, 11, 1) + FIELD(CR, HSIRDY, 10, 1) + FIELD(CR, HSIKERON, 9, 1) + FIELD(CR, HSION, 8, 1) + FIELD(CR, MSIRANGE, 4, 4) + FIELD(CR, MSIRGSEL, 3, 1) + FIELD(CR, MSIPLLEN, 2, 1) + FIELD(CR, MSIRDY, 1, 1) + FIELD(CR, MSION, 0, 1) +REG32(ICSCR, 0x04) + FIELD(ICSCR, HSITRIM, 24, 7) + FIELD(ICSCR, HSICAL, 16, 8) + FIELD(ICSCR, MSITRIM, 8, 8) + FIELD(ICSCR, MSICAL, 0, 8) +REG32(CFGR, 0x08) + FIELD(CFGR, MCOPRE, 28, 3) + /* MCOSEL[2:0] only for STM32L475xx/476xx/486xx devices */ + FIELD(CFGR, MCOSEL, 24, 3) + FIELD(CFGR, STOPWUCK, 15, 1) + FIELD(CFGR, PPRE2, 11, 3) + FIELD(CFGR, PPRE1, 8, 3) + FIELD(CFGR, HPRE, 4, 4) + FIELD(CFGR, SWS, 2, 2) + FIELD(CFGR, SW, 0, 2) +REG32(PLLCFGR, 0x0C) + FIELD(PLLCFGR, PLLPDIV, 27, 5) + FIELD(PLLCFGR, PLLR, 25, 2) + FIELD(PLLCFGR, PLLREN, 24, 1) + FIELD(PLLCFGR, PLLQ, 21, 2) + FIELD(PLLCFGR, PLLQEN, 20, 1) + FIELD(PLLCFGR, PLLP, 17, 1) + FIELD(PLLCFGR, PLLPEN, 16, 1) + FIELD(PLLCFGR, PLLN, 8, 7) + FIELD(PLLCFGR, PLLM, 4, 3) + FIELD(PLLCFGR, PLLSRC, 0, 2) +REG32(PLLSAI1CFGR, 0x10) + FIELD(PLLSAI1CFGR, PLLSAI1PDIV, 27, 5) + FIELD(PLLSAI1CFGR, PLLSAI1R, 25, 2) + FIELD(PLLSAI1CFGR, PLLSAI1REN, 24, 1) + FIELD(PLLSAI1CFGR, PLLSAI1Q, 21, 2) + FIELD(PLLSAI1CFGR, PLLSAI1QEN, 20, 1) + FIELD(PLLSAI1CFGR, PLLSAI1P, 17, 1) + FIELD(PLLSAI1CFGR, PLLSAI1PEN, 16, 1) + FIELD(PLLSAI1CFGR, PLLSAI1N, 8, 7) +REG32(PLLSAI2CFGR, 0x14) + FIELD(PLLSAI2CFGR, PLLSAI2PDIV, 27, 5) + FIELD(PLLSAI2CFGR, PLLSAI2R, 25, 2) + FIELD(PLLSAI2CFGR, PLLSAI2REN, 24, 1) + FIELD(PLLSAI2CFGR, PLLSAI2Q, 21, 2) + FIELD(PLLSAI2CFGR, PLLSAI2QEN, 20, 1) + FIELD(PLLSAI2CFGR, PLLSAI2P, 17, 1) + FIELD(PLLSAI2CFGR, PLLSAI2PEN, 16, 1) + FIELD(PLLSAI2CFGR, PLLSAI2N, 8, 7) +REG32(CIER, 0x18) + /* HSI48RDYIE: only on STM32L496xx/4A6xx devices */ + FIELD(CIER, LSECSSIE, 9, 1) + FIELD(CIER, PLLSAI2RDYIE, 7, 1) + FIELD(CIER, PLLSAI1RDYIE, 6, 1) + FIELD(CIER, PLLRDYIE, 5, 1) + FIELD(CIER, HSERDYIE, 4, 1) + FIELD(CIER, HSIRDYIE, 3, 1) + FIELD(CIER, MSIRDYIE, 2, 1) + FIELD(CIER, LSERDYIE, 1, 1) + FIELD(CIER, LSIRDYIE, 0, 1) +REG32(CIFR, 0x1C) + /* HSI48RDYF: only on STM32L496xx/4A6xx devices */ + FIELD(CIFR, LSECSSF, 9, 1) + FIELD(CIFR, CSSF, 8, 1) + FIELD(CIFR, PLLSAI2RDYF, 7, 1) + FIELD(CIFR, PLLSAI1RDYF, 6, 1) + FIELD(CIFR, PLLRDYF, 5, 1) + FIELD(CIFR, HSERDYF, 4, 1) + FIELD(CIFR, HSIRDYF, 3, 1) + FIELD(CIFR, MSIRDYF, 2, 1) + FIELD(CIFR, LSERDYF, 1, 1) + FIELD(CIFR, LSIRDYF, 0, 1) +REG32(CICR, 0x20) + /* HSI48RDYC: only on STM32L496xx/4A6xx devices */ + FIELD(CICR, LSECSSC, 9, 1) + FIELD(CICR, CSSC, 8, 1) + FIELD(CICR, PLLSAI2RDYC, 7, 1) + FIELD(CICR, PLLSAI1RDYC, 6, 1) + FIELD(CICR, PLLRDYC, 5, 1) + FIELD(CICR, HSERDYC, 4, 1) + FIELD(CICR, HSIRDYC, 3, 1) + FIELD(CICR, MSIRDYC, 2, 1) + FIELD(CICR, LSERDYC, 1, 1) + FIELD(CICR, LSIRDYC, 0, 1) +REG32(AHB1RSTR, 0x28) +REG32(AHB2RSTR, 0x2C) +REG32(AHB3RSTR, 0x30) +REG32(APB1RSTR1, 0x38) +REG32(APB1RSTR2, 0x3C) +REG32(APB2RSTR, 0x40) +REG32(AHB1ENR, 0x48) + /* DMA2DEN: reserved for STM32L475xx */ + FIELD(AHB1ENR, TSCEN, 16, 1) + FIELD(AHB1ENR, CRCEN, 12, 1) + FIELD(AHB1ENR, FLASHEN, 8, 1) + FIELD(AHB1ENR, DMA2EN, 1, 1) + FIELD(AHB1ENR, DMA1EN, 0, 1) +REG32(AHB2ENR, 0x4C) + FIELD(AHB2ENR, RNGEN, 18, 1) + /* HASHEN: reserved for STM32L475xx */ + FIELD(AHB2ENR, AESEN, 16, 1) + /* DCMIEN: reserved for STM32L475xx */ + FIELD(AHB2ENR, ADCEN, 13, 1) + FIELD(AHB2ENR, OTGFSEN, 12, 1) + /* GPIOIEN: reserved for STM32L475xx */ + FIELD(AHB2ENR, GPIOHEN, 7, 1) + FIELD(AHB2ENR, GPIOGEN, 6, 1) + FIELD(AHB2ENR, GPIOFEN, 5, 1) + FIELD(AHB2ENR, GPIOEEN, 4, 1) + FIELD(AHB2ENR, GPIODEN, 3, 1) + FIELD(AHB2ENR, GPIOCEN, 2, 1) + FIELD(AHB2ENR, GPIOBEN, 1, 1) + FIELD(AHB2ENR, GPIOAEN, 0, 1) +REG32(AHB3ENR, 0x50) + FIELD(AHB3ENR, QSPIEN, 8, 1) + FIELD(AHB3ENR, FMCEN, 0, 1) +REG32(APB1ENR1, 0x58) + FIELD(APB1ENR1, LPTIM1EN, 31, 1) + FIELD(APB1ENR1, OPAMPEN, 30, 1) + FIELD(APB1ENR1, DAC1EN, 29, 1) + FIELD(APB1ENR1, PWREN, 28, 1) + FIELD(APB1ENR1, CAN2EN, 26, 1) + FIELD(APB1ENR1, CAN1EN, 25, 1) + /* CRSEN: reserved for STM32L475xx */ + FIELD(APB1ENR1, I2C3EN, 23, 1) + FIELD(APB1ENR1, I2C2EN, 22, 1) + FIELD(APB1ENR1, I2C1EN, 21, 1) + FIELD(APB1ENR1, UART5EN, 20, 1) + FIELD(APB1ENR1, UART4EN, 19, 1) + FIELD(APB1ENR1, USART3EN, 18, 1) + FIELD(APB1ENR1, USART2EN, 17, 1) + FIELD(APB1ENR1, SPI3EN, 15, 1) + FIELD(APB1ENR1, SPI2EN, 14, 1) + FIELD(APB1ENR1, WWDGEN, 11, 1) + /* RTCAPBEN: reserved for STM32L475xx */ + FIELD(APB1ENR1, LCDEN, 9, 1) + FIELD(APB1ENR1, TIM7EN, 5, 1) + FIELD(APB1ENR1, TIM6EN, 4, 1) + FIELD(APB1ENR1, TIM5EN, 3, 1) + FIELD(APB1ENR1, TIM4EN, 2, 1) + FIELD(APB1ENR1, TIM3EN, 1, 1) + FIELD(APB1ENR1, TIM2EN, 0, 1) +REG32(APB1ENR2, 0x5C) + FIELD(APB1ENR2, LPTIM2EN, 5, 1) + FIELD(APB1ENR2, SWPMI1EN, 2, 1) + /* I2C4EN: reserved for STM32L475xx */ + FIELD(APB1ENR2, LPUART1EN, 0, 1) +REG32(APB2ENR, 0x60) + FIELD(APB2ENR, DFSDM1EN, 24, 1) + FIELD(APB2ENR, SAI2EN, 22, 1) + FIELD(APB2ENR, SAI1EN, 21, 1) + FIELD(APB2ENR, TIM17EN, 18, 1) + FIELD(APB2ENR, TIM16EN, 17, 1) + FIELD(APB2ENR, TIM15EN, 16, 1) + FIELD(APB2ENR, USART1EN, 14, 1) + FIELD(APB2ENR, TIM8EN, 13, 1) + FIELD(APB2ENR, SPI1EN, 12, 1) + FIELD(APB2ENR, TIM1EN, 11, 1) + FIELD(APB2ENR, SDMMC1EN, 10, 1) + FIELD(APB2ENR, FWEN, 7, 1) + FIELD(APB2ENR, SYSCFGEN, 0, 1) +REG32(AHB1SMENR, 0x68) +REG32(AHB2SMENR, 0x6C) +REG32(AHB3SMENR, 0x70) +REG32(APB1SMENR1, 0x78) +REG32(APB1SMENR2, 0x7C) +REG32(APB2SMENR, 0x80) +REG32(CCIPR, 0x88) + FIELD(CCIPR, DFSDM1SEL, 31, 1) + FIELD(CCIPR, SWPMI1SEL, 30, 1) + FIELD(CCIPR, ADCSEL, 28, 2) + FIELD(CCIPR, CLK48SEL, 26, 2) + FIELD(CCIPR, SAI2SEL, 24, 2) + FIELD(CCIPR, SAI1SEL, 22, 2) + FIELD(CCIPR, LPTIM2SEL, 20, 2) + FIELD(CCIPR, LPTIM1SEL, 18, 2) + FIELD(CCIPR, I2C3SEL, 16, 2) + FIELD(CCIPR, I2C2SEL, 14, 2) + FIELD(CCIPR, I2C1SEL, 12, 2) + FIELD(CCIPR, LPUART1SEL, 10, 2) + FIELD(CCIPR, UART5SEL, 8, 2) + FIELD(CCIPR, UART4SEL, 6, 2) + FIELD(CCIPR, USART3SEL, 4, 2) + FIELD(CCIPR, USART2SEL, 2, 2) + FIELD(CCIPR, USART1SEL, 0, 2) +REG32(BDCR, 0x90) + FIELD(BDCR, LSCOSEL, 25, 1) + FIELD(BDCR, LSCOEN, 24, 1) + FIELD(BDCR, BDRST, 16, 1) + FIELD(BDCR, RTCEN, 15, 1) + FIELD(BDCR, RTCSEL, 8, 2) + FIELD(BDCR, LSECSSD, 6, 1) + FIELD(BDCR, LSECSSON, 5, 1) + FIELD(BDCR, LSEDRV, 3, 2) + FIELD(BDCR, LSEBYP, 2, 1) + FIELD(BDCR, LSERDY, 1, 1) + FIELD(BDCR, LSEON, 0, 1) +REG32(CSR, 0x94) + FIELD(CSR, LPWRRSTF, 31, 1) + FIELD(CSR, WWDGRSTF, 30, 1) + FIELD(CSR, IWWGRSTF, 29, 1) + FIELD(CSR, SFTRSTF, 28, 1) + FIELD(CSR, BORRSTF, 27, 1) + FIELD(CSR, PINRSTF, 26, 1) + FIELD(CSR, OBLRSTF, 25, 1) + FIELD(CSR, FWRSTF, 24, 1) + FIELD(CSR, RMVF, 23, 1) + FIELD(CSR, MSISRANGE, 8, 4) + FIELD(CSR, LSIRDY, 1, 1) + FIELD(CSR, LSION, 0, 1) +/* CRRCR and CCIPR2 registers are present on L496/L4A6 devices only. */ + +/* Read Only masks to prevent writes in unauthorized bits */ +#define CR_READ_ONLY_MASK (R_CR_PLLSAI2RDY_MASK | \ + R_CR_PLLSAI1RDY_MASK | \ + R_CR_PLLRDY_MASK | \ + R_CR_HSERDY_MASK | \ + R_CR_HSIRDY_MASK | \ + R_CR_MSIRDY_MASK) +#define CR_READ_SET_MASK (R_CR_CSSON_MASK | R_CR_MSIRGSEL_MASK) +#define ICSCR_READ_ONLY_MASK (R_ICSCR_HSICAL_MASK | R_ICSCR_MSICAL_MASK) +#define CFGR_READ_ONLY_MASK (R_CFGR_SWS_MASK) +#define CIFR_READ_ONLY_MASK (R_CIFR_LSECSSF_MASK | \ + R_CIFR_CSSF_MASK | \ + R_CIFR_PLLSAI2RDYF_MASK | \ + R_CIFR_PLLSAI1RDYF_MASK | \ + R_CIFR_PLLRDYF_MASK | \ + R_CIFR_HSERDYF_MASK | \ + R_CIFR_HSIRDYF_MASK | \ + R_CIFR_MSIRDYF_MASK | \ + R_CIFR_LSERDYF_MASK | \ + R_CIFR_LSIRDYF_MASK) +#define CIFR_IRQ_MASK CIFR_READ_ONLY_MASK +#define APB2ENR_READ_SET_MASK (R_APB2ENR_FWEN_MASK) +#define BDCR_READ_ONLY_MASK (R_BDCR_LSECSSD_MASK | R_BDCR_LSERDY_MASK) +#define CSR_READ_ONLY_MASK (R_CSR_LPWRRSTF_MASK | \ + R_CSR_WWDGRSTF_MASK | \ + R_CSR_IWWGRSTF_MASK | \ + R_CSR_SFTRSTF_MASK | \ + R_CSR_BORRSTF_MASK | \ + R_CSR_PINRSTF_MASK | \ + R_CSR_OBLRSTF_MASK | \ + R_CSR_FWRSTF_MASK | \ + R_CSR_LSIRDY_MASK) + +#endif /* HW_STM32L4X5_RCC_INTERNALS_H */ --=20 2.34.1 From nobody Tue Nov 26 14:24:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=telecom-paris.fr ARC-Seal: i=1; a=rsa-sha256; t=1706366444; cv=none; d=zohomail.com; s=zohoarc; b=mmtSLgnF5MhQqcEceR5riu81ufzCpZVa7CVEaE11bbR8UmR93xfYe4+5yhLlHSn5HtU4ddPmHDriQNpY+dG9jGrVML/pxq497254mGcg75w2fY7P1GZ7BZueWp3gCs6iJDLREm1K6PgUA8ra1LQ2BnioAGSOJZnIB3TQxHgcIzI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1706366444; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=gzkMMzKsN7vqbmQkAadWLe9OPmFUkB2N4+fqA6JQWWc=; b=GkRL4Bs+uPfc3azgbBqoboOPPsRFW1Uv/d3h8jg+U2lLJcyX4qx4TgBSLDzdoNMnNuf5fmTA0aLVF2tRvB5MV73N/KNbuQZwiWLqXGtR6zGkychmTLS/GMF0AjdNsoLpKA9HAW+hMU7MX6Euc0k69v2iRo2uxIni5thiA1YRXd8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1706366444845576.9149063216181; Sat, 27 Jan 2024 06:40:44 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rTjqL-0002Re-Di; Sat, 27 Jan 2024 09:39:37 -0500 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 1rTjqH-0002PN-8h; Sat, 27 Jan 2024 09:39:33 -0500 Received: from zproxy4.enst.fr ([2001:660:330f:2::df]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rTjqD-0002Pz-BT; Sat, 27 Jan 2024 09:39:33 -0500 Received: from localhost (localhost [IPv6:::1]) by zproxy4.enst.fr (Postfix) with ESMTP id 0CFC220829; Sat, 27 Jan 2024 15:39:24 +0100 (CET) Received: from zproxy4.enst.fr ([IPv6:::1]) by localhost (zproxy4.enst.fr [IPv6:::1]) (amavis, port 10032) with ESMTP id a5Hz14aRITXT; Sat, 27 Jan 2024 15:39:23 +0100 (CET) Received: from localhost (localhost [IPv6:::1]) by zproxy4.enst.fr (Postfix) with ESMTP id 081DF20824; Sat, 27 Jan 2024 15:39:23 +0100 (CET) Received: from zproxy4.enst.fr ([IPv6:::1]) by localhost (zproxy4.enst.fr [IPv6:::1]) (amavis, port 10026) with ESMTP id 328EcUQIoUt6; Sat, 27 Jan 2024 15:39:22 +0100 (CET) Received: from AM-Inspiron-3585.numericable.fr (38.162.10.109.rev.sfr.net [109.10.162.38]) by zproxy4.enst.fr (Postfix) with ESMTPSA id 6F85A20823; Sat, 27 Jan 2024 15:39:22 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.10.3 zproxy4.enst.fr 081DF20824 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=telecom-paris.fr; s=A35C7578-1106-11E5-A17F-C303FDDA8F2E; t=1706366363; bh=gzkMMzKsN7vqbmQkAadWLe9OPmFUkB2N4+fqA6JQWWc=; h=From:To:Date:Message-Id:MIME-Version; b=7k7bXpuXCqMEk3a8x+fF/UARcj226x8UWb7lGcpEUdbdeAmnzyrUYxfXeOIzWdidm 4LU0FQIHOcUIDXLf2/uxVUg7LJaKBF9XwVFHVRianBSCporn1aPDt5iL16VG83TChu lBWBS6IUlwvQoodnNtRvPenO+QulJprSTpX/njFo= X-Virus-Scanned: amavis at enst.fr From: Arnaud Minier To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, Arnaud Minier , Samuel Tardieu , Laurent Vivier , Paolo Bonzini , Alistair Francis , Peter Maydell , =?UTF-8?q?Philipe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?In=C3=A8s=20Varhol?= , Thomas Huth , Alistair Francis Subject: [PATCH v3 2/8] Add an internal clock multiplexer object Date: Sat, 27 Jan 2024 15:38:58 +0100 Message-Id: <20240127143904.80187-3-arnaud.minier@telecom-paris.fr> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> References: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2001:660:330f:2::df; envelope-from=arnaud.minier@telecom-paris.fr; helo=zproxy4.enst.fr X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, 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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @telecom-paris.fr) X-ZM-MESSAGEID: 1706366446261100001 Content-Type: text/plain; charset="utf-8" Signed-off-by: Arnaud Minier Signed-off-by: In=C3=A8s Varhol Acked-by: Alistair Francis --- hw/misc/stm32l4x5_rcc.c | 154 ++++++++++++++++++++++ hw/misc/trace-events | 5 + include/hw/misc/stm32l4x5_rcc.h | 119 +++++++++++++++++ include/hw/misc/stm32l4x5_rcc_internals.h | 29 ++++ 4 files changed, 307 insertions(+) diff --git a/hw/misc/stm32l4x5_rcc.c b/hw/misc/stm32l4x5_rcc.c index 38ca8aad7d..5013fa0c04 100644 --- a/hw/misc/stm32l4x5_rcc.c +++ b/hw/misc/stm32l4x5_rcc.c @@ -36,6 +36,128 @@ #define LSE_FRQ 32768ULL #define LSI_FRQ 32000ULL =20 +static void clock_mux_update(RccClockMuxState *mux) +{ + uint64_t src_freq, old_freq, freq; + + src_freq =3D clock_get_hz(mux->srcs[mux->src]); + old_freq =3D clock_get_hz(mux->out); + + if (!mux->enabled || !mux->divider) { + freq =3D 0; + } else { + freq =3D muldiv64(src_freq, mux->multiplier, mux->divider); + } + + /* No change, early return to avoid log spam and useless propagation */ + if (old_freq =3D=3D freq) { + return; + } + + clock_update_hz(mux->out, freq); + trace_stm32l4x5_rcc_mux_update(mux->id, mux->src, src_freq, freq); +} + +static void clock_mux_src_update(void *opaque, ClockEvent event) +{ + RccClockMuxState **backref =3D opaque; + RccClockMuxState *s =3D *backref; + /* + * The backref value is equal to: + * s->backref + (sizeof(RccClockMuxState *) * update_src). + * By subtracting we can get back the index of the updated clock. + */ + const uint32_t update_src =3D backref - s->backref; + /* Only update if the clock that was updated is the current source*/ + if (update_src =3D=3D s->src) { + clock_mux_update(s); + } +} + +static void clock_mux_init(Object *obj) +{ + RccClockMuxState *s =3D RCC_CLOCK_MUX(obj); + size_t i; + + for (i =3D 0; i < RCC_NUM_CLOCK_MUX_SRC; i++) { + char *name =3D g_strdup_printf("srcs[%zu]", i); + s->backref[i] =3D s; + s->srcs[i] =3D qdev_init_clock_in(DEVICE(s), name, + clock_mux_src_update, + &s->backref[i], + ClockUpdate); + g_free(name); + } + + s->out =3D qdev_init_clock_out(DEVICE(s), "out"); +} + +static void clock_mux_reset_hold(Object *obj) +{ } + +static const VMStateDescription clock_mux_vmstate =3D { + .name =3D TYPE_RCC_CLOCK_MUX, + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_ARRAY_CLOCK(srcs, RccClockMuxState, + RCC_NUM_CLOCK_MUX_SRC), + VMSTATE_BOOL(enabled, RccClockMuxState), + VMSTATE_UINT32(src, RccClockMuxState), + VMSTATE_END_OF_LIST() + } +}; + +static void clock_mux_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + rc->phases.hold =3D clock_mux_reset_hold; + dc->vmsd =3D &clock_mux_vmstate; +} + +static void clock_mux_set_enable(RccClockMuxState *mux, bool enabled) +{ + if (mux->enabled =3D=3D enabled) { + return; + } + + if (enabled) { + trace_stm32l4x5_rcc_mux_enable(mux->id); + } else { + trace_stm32l4x5_rcc_mux_disable(mux->id); + } + + mux->enabled =3D enabled; + clock_mux_update(mux); +} + +static void clock_mux_set_factor(RccClockMuxState *mux, + uint32_t multiplier, uint32_t divider) +{ + if (mux->multiplier =3D=3D multiplier && mux->divider =3D=3D divider) { + return; + } + trace_stm32l4x5_rcc_mux_set_factor(mux->id, + mux->multiplier, multiplier, mux->divider, divider); + + mux->multiplier =3D multiplier; + mux->divider =3D divider; + clock_mux_update(mux); +} + +static void clock_mux_set_source(RccClockMuxState *mux, RccClockMuxSource = src) +{ + if (mux->src =3D=3D src) { + return; + } + + trace_stm32l4x5_rcc_mux_set_src(mux->id, mux->src, src); + mux->src =3D src; + clock_mux_update(mux); +} + static void rcc_update_irq(Stm32l4x5RccState *s) { if (s->cifr & CIFR_IRQ_MASK) { @@ -329,6 +451,7 @@ static const ClockPortInitArray stm32l4x5_rcc_clocks = =3D { static void stm32l4x5_rcc_init(Object *obj) { Stm32l4x5RccState *s =3D STM32L4X5_RCC(obj); + size_t i; =20 sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); =20 @@ -338,6 +461,14 @@ static void stm32l4x5_rcc_init(Object *obj) =20 qdev_init_clocks(DEVICE(s), stm32l4x5_rcc_clocks); =20 + for (i =3D 0; i < RCC_NUM_CLOCK_MUX; i++) { + + object_initialize_child(obj, "clock[*]", + &s->clock_muxes[i], + TYPE_RCC_CLOCK_MUX); + + } + s->gnd =3D clock_new(obj, "gnd"); } =20 @@ -383,6 +514,7 @@ static const VMStateDescription vmstate_stm32l4x5_rcc = =3D { static void stm32l4x5_rcc_realize(DeviceState *dev, Error **errp) { Stm32l4x5RccState *s =3D STM32L4X5_RCC(dev); + size_t i; =20 if (s->hse_frequency < 4000000ULL || s->hse_frequency > 48000000ULL) { @@ -392,10 +524,26 @@ static void stm32l4x5_rcc_realize(DeviceState *dev, E= rror **errp) return; } =20 + for (i =3D 0; i < RCC_NUM_CLOCK_MUX; i++) { + RccClockMuxState *clock_mux =3D &s->clock_muxes[i]; + + if (!qdev_realize(DEVICE(clock_mux), NULL, errp)) { + return; + } + } + clock_update_hz(s->msi_rc, MSI_DEFAULT_FRQ); clock_update_hz(s->sai1_extclk, s->sai1_extclk_frequency); clock_update_hz(s->sai2_extclk, s->sai2_extclk_frequency); clock_update(s->gnd, 0); + + /* + * Dummy values to make compilation pass. + * Removed in later commits. + */ + clock_mux_set_source(&s->clock_muxes[0], RCC_CLOCK_MUX_SRC_GND); + clock_mux_set_enable(&s->clock_muxes[0], true); + clock_mux_set_factor(&s->clock_muxes[0], 1, 1); } =20 static Property stm32l4x5_rcc_properties[] =3D { @@ -427,6 +575,12 @@ static const TypeInfo stm32l4x5_rcc_types[] =3D { .instance_size =3D sizeof(Stm32l4x5RccState), .instance_init =3D stm32l4x5_rcc_init, .class_init =3D stm32l4x5_rcc_class_init, + }, { + .name =3D TYPE_RCC_CLOCK_MUX, + .parent =3D TYPE_DEVICE, + .instance_size =3D sizeof(RccClockMuxState), + .instance_init =3D clock_mux_init, + .class_init =3D clock_mux_class_init, } }; =20 diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 62a7599353..d5e471811c 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -177,6 +177,11 @@ stm32l4x5_exti_write(uint64_t addr, uint64_t data) "re= g write: addr: 0x%" PRIx64 # stm32l4x5_rcc.c stm32l4x5_rcc_read(uint64_t addr, uint32_t data) "RCC: Read <0x%" PRIx64 "= > -> 0x%" PRIx32 "" stm32l4x5_rcc_write(uint64_t addr, uint32_t data) "RCC: Write <0x%" PRIx64= "> <- 0x%" PRIx32 "" +stm32l4x5_rcc_mux_enable(uint32_t mux_id) "RCC: Mux %d enabled" +stm32l4x5_rcc_mux_disable(uint32_t mux_id) "RCC: Mux %d disabled" +stm32l4x5_rcc_mux_set_factor(uint32_t mux_id, uint32_t old_multiplier, uin= t32_t new_multiplier, uint32_t old_divider, uint32_t new_divider) "RCC: Mux= %d factor changed: multiplier (%u -> %u), divider (%u -> %u)" +stm32l4x5_rcc_mux_set_src(uint32_t mux_id, uint32_t old_src, uint32_t new_= src) "RCC: Mux %d source changed: from %u to %u" +stm32l4x5_rcc_mux_update(uint32_t mux_id, uint32_t src, uint64_t src_freq,= uint64_t new_freq) "RCC: Mux %d src %d update: src_freq %" PRIu64 " new_fr= eq %" PRIu64 "" =20 # tz-mpc.c tz_mpc_reg_read(uint32_t offset, uint64_t data, unsigned size) "TZ MPC reg= s read: offset 0x%x data 0x%" PRIx64 " size %u" diff --git a/include/hw/misc/stm32l4x5_rcc.h b/include/hw/misc/stm32l4x5_rc= c.h index 5157e96635..6719be9fbe 100644 --- a/include/hw/misc/stm32l4x5_rcc.h +++ b/include/hw/misc/stm32l4x5_rcc.h @@ -26,6 +26,122 @@ OBJECT_DECLARE_SIMPLE_TYPE(Stm32l4x5RccState, STM32L4X5= _RCC) =20 /* In the Stm32l4x5 clock tree, mux have at most 7 sources */ #define RCC_NUM_CLOCK_MUX_SRC 7 +/* NB: Prescaler are assimilated to mux with one source and one output */ +typedef enum RccClockMux { + /* Internal muxes that arent't exposed publicly to other peripherals */ + RCC_CLOCK_MUX_SYSCLK, + RCC_CLOCK_MUX_PLL_INPUT, + RCC_CLOCK_MUX_HCLK, + RCC_CLOCK_MUX_PCLK1, + RCC_CLOCK_MUX_PCLK2, + RCC_CLOCK_MUX_HSE_OVER_32, + RCC_CLOCK_MUX_LCD_AND_RTC_COMMON, + + /* Muxes with a publicly available output */ + RCC_CLOCK_MUX_CORTEX_REFCLK, + RCC_CLOCK_MUX_USART1, + RCC_CLOCK_MUX_USART2, + RCC_CLOCK_MUX_USART3, + RCC_CLOCK_MUX_UART4, + RCC_CLOCK_MUX_UART5, + RCC_CLOCK_MUX_LPUART1, + RCC_CLOCK_MUX_I2C1, + RCC_CLOCK_MUX_I2C2, + RCC_CLOCK_MUX_I2C3, + RCC_CLOCK_MUX_LPTIM1, + RCC_CLOCK_MUX_LPTIM2, + RCC_CLOCK_MUX_SWPMI1, + RCC_CLOCK_MUX_MCO, + RCC_CLOCK_MUX_LSCO, + RCC_CLOCK_MUX_DFSDM1, + RCC_CLOCK_MUX_ADC, + RCC_CLOCK_MUX_CLK48, + RCC_CLOCK_MUX_SAI1, + RCC_CLOCK_MUX_SAI2, + + /* + * Mux that have only one input and one output assigned to as peripher= al. + * They could be direct lines but it is simpler + * to use the same logic for all outputs. + */ + /* - AHB1 */ + RCC_CLOCK_MUX_TSC, + RCC_CLOCK_MUX_CRC, + RCC_CLOCK_MUX_FLASH, + RCC_CLOCK_MUX_DMA2, + RCC_CLOCK_MUX_DMA1, + + /* - AHB2 */ + RCC_CLOCK_MUX_RNG, + RCC_CLOCK_MUX_AES, + RCC_CLOCK_MUX_OTGFS, + RCC_CLOCK_MUX_GPIOA, + RCC_CLOCK_MUX_GPIOB, + RCC_CLOCK_MUX_GPIOC, + RCC_CLOCK_MUX_GPIOD, + RCC_CLOCK_MUX_GPIOE, + RCC_CLOCK_MUX_GPIOF, + RCC_CLOCK_MUX_GPIOG, + RCC_CLOCK_MUX_GPIOH, + + /* - AHB3 */ + RCC_CLOCK_MUX_QSPI, + RCC_CLOCK_MUX_FMC, + + /* - APB1 */ + RCC_CLOCK_MUX_OPAMP, + RCC_CLOCK_MUX_DAC1, + RCC_CLOCK_MUX_PWR, + RCC_CLOCK_MUX_CAN1, + RCC_CLOCK_MUX_SPI3, + RCC_CLOCK_MUX_SPI2, + RCC_CLOCK_MUX_WWDG, + RCC_CLOCK_MUX_LCD, + RCC_CLOCK_MUX_TIM7, + RCC_CLOCK_MUX_TIM6, + RCC_CLOCK_MUX_TIM5, + RCC_CLOCK_MUX_TIM4, + RCC_CLOCK_MUX_TIM3, + RCC_CLOCK_MUX_TIM2, + + /* - APB2 */ + RCC_CLOCK_MUX_TIM17, + RCC_CLOCK_MUX_TIM16, + RCC_CLOCK_MUX_TIM15, + RCC_CLOCK_MUX_TIM8, + RCC_CLOCK_MUX_SPI1, + RCC_CLOCK_MUX_TIM1, + RCC_CLOCK_MUX_SDMMC1, + RCC_CLOCK_MUX_FW, + RCC_CLOCK_MUX_SYSCFG, + + /* - BDCR */ + RCC_CLOCK_MUX_RTC, + + /* - OTHER */ + RCC_CLOCK_MUX_CORTEX_FCLK, + + RCC_NUM_CLOCK_MUX +} RccClockMux; + +typedef struct RccClockMuxState { + DeviceState parent_obj; + + RccClockMux id; + Clock *srcs[RCC_NUM_CLOCK_MUX_SRC]; + Clock *out; + bool enabled; + uint32_t src; + uint32_t multiplier; + uint32_t divider; + + /* + * Used by clock srcs update callback to retrieve both the clock and t= he + * source number. + */ + struct RccClockMuxState *backref[RCC_NUM_CLOCK_MUX_SRC]; +} RccClockMuxState; + struct Stm32l4x5RccState { SysBusDevice parent_obj; =20 @@ -71,6 +187,9 @@ struct Stm32l4x5RccState { Clock *sai1_extclk; Clock *sai2_extclk; =20 + /* Muxes ~=3D outputs */ + RccClockMuxState clock_muxes[RCC_NUM_CLOCK_MUX]; + qemu_irq irq; uint64_t hse_frequency; uint64_t sai1_extclk_frequency; diff --git a/include/hw/misc/stm32l4x5_rcc_internals.h b/include/hw/misc/st= m32l4x5_rcc_internals.h index 331ea30db5..4aa836848b 100644 --- a/include/hw/misc/stm32l4x5_rcc_internals.h +++ b/include/hw/misc/stm32l4x5_rcc_internals.h @@ -21,6 +21,8 @@ #include "hw/registerfields.h" #include "hw/misc/stm32l4x5_rcc.h" =20 +#define TYPE_RCC_CLOCK_MUX "stm32l4x5-rcc-clock-mux" +OBJECT_DECLARE_SIMPLE_TYPE(RccClockMuxState, RCC_CLOCK_MUX) =20 /* Register map */ REG32(CR, 0x00) @@ -283,4 +285,31 @@ REG32(CSR, 0x94) R_CSR_FWRSTF_MASK | \ R_CSR_LSIRDY_MASK) =20 +typedef enum RccClockMuxSource { + RCC_CLOCK_MUX_SRC_GND =3D 0, + RCC_CLOCK_MUX_SRC_HSI, + RCC_CLOCK_MUX_SRC_HSE, + RCC_CLOCK_MUX_SRC_MSI, + RCC_CLOCK_MUX_SRC_LSI, + RCC_CLOCK_MUX_SRC_LSE, + RCC_CLOCK_MUX_SRC_SAI1_EXTCLK, + RCC_CLOCK_MUX_SRC_SAI2_EXTCLK, + RCC_CLOCK_MUX_SRC_PLL, + RCC_CLOCK_MUX_SRC_PLLSAI1, + RCC_CLOCK_MUX_SRC_PLLSAI2, + RCC_CLOCK_MUX_SRC_PLLSAI3, + RCC_CLOCK_MUX_SRC_PLL48M1, + RCC_CLOCK_MUX_SRC_PLL48M2, + RCC_CLOCK_MUX_SRC_PLLADC1, + RCC_CLOCK_MUX_SRC_PLLADC2, + RCC_CLOCK_MUX_SRC_SYSCLK, + RCC_CLOCK_MUX_SRC_HCLK, + RCC_CLOCK_MUX_SRC_PCLK1, + RCC_CLOCK_MUX_SRC_PCLK2, + RCC_CLOCK_MUX_SRC_HSE_OVER_32, + RCC_CLOCK_MUX_SRC_LCD_AND_RTC_COMMON, + + RCC_CLOCK_MUX_SRC_NUMBER, +} RccClockMuxSource; + #endif /* HW_STM32L4X5_RCC_INTERNALS_H */ --=20 2.34.1 From nobody Tue Nov 26 14:24:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=telecom-paris.fr ARC-Seal: i=1; a=rsa-sha256; t=1706366405; cv=none; d=zohomail.com; s=zohoarc; b=VGUcMInUuNeslzGIvcGHpvq4MPML7mM4QVeDilwLTpzVvgEARp22G4j2FrgwIFmn66ylPvXBg+r/R2qLGCFsyKGgsrpuEWhbOUuOdA5uuyU+PCoz2mDrzr3itr1zuDc9LQaDb3mSOZHiayFS4ip+1M9V36+YO3ol02jpF/iwE/0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1706366405; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=aEJqsOIJ8H4kF9hOV6iJ0GPf8fEJkqYnMF5ePIIgyio=; b=O+DrjnCjvXYMQngjVlGJl7OJUqjOlZgx8kRTmNch9afn6OeUj+gjnd3vdE/YJrL7HSo8KTZ22NOS7iyKqafzI9l6PEmZjsdrVPwy0pPjS3lQw2VXQhVgjBO+WzRJqXBZ/aRLzTpQGssjv5+O4FkzhLKJLdDbfLodRuNWzeNVp68= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1706366405021342.67171172803796; Sat, 27 Jan 2024 06:40:05 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rTjqH-0002P5-08; Sat, 27 Jan 2024 09:39:33 -0500 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 1rTjqF-0002Op-KB; Sat, 27 Jan 2024 09:39:31 -0500 Received: from zproxy4.enst.fr ([137.194.2.223]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rTjqC-0002Q1-RI; Sat, 27 Jan 2024 09:39:31 -0500 Received: from localhost (localhost [IPv6:::1]) by zproxy4.enst.fr (Postfix) with ESMTP id 3884720824; Sat, 27 Jan 2024 15:39:24 +0100 (CET) Received: from zproxy4.enst.fr ([IPv6:::1]) by localhost (zproxy4.enst.fr [IPv6:::1]) (amavis, port 10032) with ESMTP id 2zEujYSN2cTy; Sat, 27 Jan 2024 15:39:23 +0100 (CET) Received: from localhost (localhost [IPv6:::1]) by zproxy4.enst.fr (Postfix) with ESMTP id 5367A20827; Sat, 27 Jan 2024 15:39:23 +0100 (CET) Received: from zproxy4.enst.fr ([IPv6:::1]) by localhost (zproxy4.enst.fr [IPv6:::1]) (amavis, port 10026) with ESMTP id WhOz5sATT2uv; Sat, 27 Jan 2024 15:39:23 +0100 (CET) Received: from AM-Inspiron-3585.numericable.fr (38.162.10.109.rev.sfr.net [109.10.162.38]) by zproxy4.enst.fr (Postfix) with ESMTPSA id E0CC520744; Sat, 27 Jan 2024 15:39:22 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.10.3 zproxy4.enst.fr 5367A20827 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=telecom-paris.fr; s=A35C7578-1106-11E5-A17F-C303FDDA8F2E; t=1706366363; bh=aEJqsOIJ8H4kF9hOV6iJ0GPf8fEJkqYnMF5ePIIgyio=; h=From:To:Date:Message-Id:MIME-Version; b=fiawn+bfmjLQcAewBBfR7HI5C6/R/GzGYwwDOqo4NS9SGIZy0653uPwzoSigR6Hte tHD9K3cBW41UfSsy86Qz9CMX+6CQVLvedvelJuMdCH4wjx9fnnIUrwEksaa88boZU2 Ltxkt944dG+u9o31XIDCHhUCJwDqsyx6drIXCW70= X-Virus-Scanned: amavis at enst.fr From: Arnaud Minier To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, Arnaud Minier , Samuel Tardieu , Laurent Vivier , Paolo Bonzini , Alistair Francis , Peter Maydell , =?UTF-8?q?Philipe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?In=C3=A8s=20Varhol?= , Thomas Huth Subject: [PATCH v3 3/8] Add an internal PLL Clock object Date: Sat, 27 Jan 2024 15:38:59 +0100 Message-Id: <20240127143904.80187-4-arnaud.minier@telecom-paris.fr> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> References: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=137.194.2.223; envelope-from=arnaud.minier@telecom-paris.fr; helo=zproxy4.enst.fr X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, 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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @telecom-paris.fr) X-ZM-MESSAGEID: 1706366407016100002 Content-Type: text/plain; charset="utf-8" Signed-off-by: Arnaud Minier Signed-off-by: In=C3=A8s Varhol --- hw/misc/stm32l4x5_rcc.c | 171 ++++++++++++++++++++++ hw/misc/trace-events | 5 + include/hw/misc/stm32l4x5_rcc.h | 40 +++++ include/hw/misc/stm32l4x5_rcc_internals.h | 22 +++ 4 files changed, 238 insertions(+) diff --git a/hw/misc/stm32l4x5_rcc.c b/hw/misc/stm32l4x5_rcc.c index 5013fa0c04..771b566c88 100644 --- a/hw/misc/stm32l4x5_rcc.c +++ b/hw/misc/stm32l4x5_rcc.c @@ -158,6 +158,152 @@ static void clock_mux_set_source(RccClockMuxState *mu= x, RccClockMuxSource src) clock_mux_update(mux); } =20 +static void pll_update(RccPllState *pll) +{ + uint64_t vco_freq, old_channel_freq, channel_freq; + int i; + + /* The common PLLM factor is handled by the PLL mux */ + vco_freq =3D muldiv64(clock_get_hz(pll->in), pll->vco_multiplier, 1); + + for (i =3D 0; i < RCC_NUM_CHANNEL_PLL_OUT; i++) { + if (!pll->channel_exists[i]) { + continue; + } + + old_channel_freq =3D clock_get_hz(pll->channels[i]); + if (!pll->enabled || + !pll->channel_enabled[i] || + !pll->channel_divider[i]) { + channel_freq =3D 0; + } else { + channel_freq =3D muldiv64(vco_freq, + 1, + pll->channel_divider[i]); + } + + /* No change, early continue to avoid log spam and useless propaga= tion */ + if (old_channel_freq =3D=3D channel_freq) { + continue; + } + + clock_update_hz(pll->channels[i], channel_freq); + trace_stm32l4x5_rcc_pll_update(pll->id, i, vco_freq, + old_channel_freq, channel_freq); + } +} + +static void pll_src_update(void *opaque, ClockEvent event) +{ + RccPllState *s =3D opaque; + pll_update(s); +} + +static void pll_init(Object *obj) +{ + RccPllState *s =3D RCC_PLL(obj); + size_t i; + + s->in =3D qdev_init_clock_in(DEVICE(s), "in", + pll_src_update, s, ClockUpdate); + + const char *names[] =3D { + "out-p", "out-q", "out-r", + }; + + for (i =3D 0; i < RCC_NUM_CHANNEL_PLL_OUT; i++) { + s->channels[i] =3D qdev_init_clock_out(DEVICE(s), names[i]); + } +} + +static void pll_reset_hold(Object *obj) +{ } + +static const VMStateDescription pll_vmstate =3D { + .name =3D TYPE_RCC_PLL, + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_CLOCK(in, RccPllState), + VMSTATE_UINT32(vco_multiplier, RccPllState), + VMSTATE_BOOL_ARRAY(channel_enabled, RccPllState, RCC_NUM_CHANNEL_P= LL_OUT), + VMSTATE_BOOL_ARRAY(channel_exists, RccPllState, RCC_NUM_CHANNEL_PL= L_OUT), + VMSTATE_UINT32_ARRAY(channel_divider, RccPllState, RCC_NUM_CHANNEL= _PLL_OUT), + VMSTATE_END_OF_LIST() + } +}; + +static void pll_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + rc->phases.hold =3D pll_reset_hold; + dc->vmsd =3D &pll_vmstate; +} + +static void pll_set_vco_multiplier(RccPllState *pll, uint32_t vco_multipli= er) +{ + if (pll->vco_multiplier =3D=3D vco_multiplier) { + return; + } + + if (vco_multiplier < 8 || vco_multiplier > 86) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: VCO multiplier is out of bound (%u) for PLL %u\n", + __func__, vco_multiplier, pll->id); + } + + trace_stm32l4x5_rcc_pll_set_vco_multiplier(pll->id, + pll->vco_multiplier, vco_multiplier); + + pll->vco_multiplier =3D vco_multiplier; + pll_update(pll); +} + +static void pll_set_enable(RccPllState *pll, bool enabled) +{ + if (pll->enabled =3D=3D enabled) { + return; + } + + pll->enabled =3D enabled; + pll_update(pll); +} + +static void pll_set_channel_enable(RccPllState *pll, + PllCommonChannels channel, + bool enabled) +{ + if (pll->channel_enabled[channel] =3D=3D enabled) { + return; + } + + if (enabled) { + trace_stm32l4x5_rcc_pll_channel_enable(pll->id, channel); + } else { + trace_stm32l4x5_rcc_pll_channel_disable(pll->id, channel); + } + + pll->channel_enabled[channel] =3D enabled; + pll_update(pll); +} + +static void pll_set_channel_divider(RccPllState *pll, + PllCommonChannels channel, + uint32_t divider) +{ + if (pll->channel_divider[channel] =3D=3D divider) { + return; + } + + trace_stm32l4x5_rcc_pll_set_channel_divider(pll->id, + channel, pll->channel_divider[channel], divider); + + pll->channel_divider[channel] =3D divider; + pll_update(pll); +} + static void rcc_update_irq(Stm32l4x5RccState *s) { if (s->cifr & CIFR_IRQ_MASK) { @@ -461,6 +607,11 @@ static void stm32l4x5_rcc_init(Object *obj) =20 qdev_init_clocks(DEVICE(s), stm32l4x5_rcc_clocks); =20 + for (i =3D 0; i < RCC_NUM_PLL; i++) { + object_initialize_child(obj, "pll[*]", + &s->plls[i], TYPE_RCC_PLL); + } + for (i =3D 0; i < RCC_NUM_CLOCK_MUX; i++) { =20 object_initialize_child(obj, "clock[*]", @@ -524,6 +675,16 @@ static void stm32l4x5_rcc_realize(DeviceState *dev, Er= ror **errp) return; } =20 + for (i =3D 0; i < RCC_NUM_PLL; i++) { + RccPllState *pll =3D &s->plls[i]; + + clock_set_source(pll->in, s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT].= out); + + if (!qdev_realize(DEVICE(pll), NULL, errp)) { + return; + } + } + for (i =3D 0; i < RCC_NUM_CLOCK_MUX; i++) { RccClockMuxState *clock_mux =3D &s->clock_muxes[i]; =20 @@ -544,6 +705,10 @@ static void stm32l4x5_rcc_realize(DeviceState *dev, Er= ror **errp) clock_mux_set_source(&s->clock_muxes[0], RCC_CLOCK_MUX_SRC_GND); clock_mux_set_enable(&s->clock_muxes[0], true); clock_mux_set_factor(&s->clock_muxes[0], 1, 1); + pll_set_channel_divider(&s->plls[0], 0, 1); + pll_set_enable(&s->plls[0], true); + pll_set_channel_enable(&s->plls[0], 0, true); + pll_set_vco_multiplier(&s->plls[0], 1); } =20 static Property stm32l4x5_rcc_properties[] =3D { @@ -581,6 +746,12 @@ static const TypeInfo stm32l4x5_rcc_types[] =3D { .instance_size =3D sizeof(RccClockMuxState), .instance_init =3D clock_mux_init, .class_init =3D clock_mux_class_init, + }, { + .name =3D TYPE_RCC_PLL, + .parent =3D TYPE_DEVICE, + .instance_size =3D sizeof(RccPllState), + .instance_init =3D pll_init, + .class_init =3D pll_class_init, } }; =20 diff --git a/hw/misc/trace-events b/hw/misc/trace-events index d5e471811c..1b6054d88a 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -182,6 +182,11 @@ stm32l4x5_rcc_mux_disable(uint32_t mux_id) "RCC: Mux %= d disabled" stm32l4x5_rcc_mux_set_factor(uint32_t mux_id, uint32_t old_multiplier, uin= t32_t new_multiplier, uint32_t old_divider, uint32_t new_divider) "RCC: Mux= %d factor changed: multiplier (%u -> %u), divider (%u -> %u)" stm32l4x5_rcc_mux_set_src(uint32_t mux_id, uint32_t old_src, uint32_t new_= src) "RCC: Mux %d source changed: from %u to %u" stm32l4x5_rcc_mux_update(uint32_t mux_id, uint32_t src, uint64_t src_freq,= uint64_t new_freq) "RCC: Mux %d src %d update: src_freq %" PRIu64 " new_fr= eq %" PRIu64 "" +stm32l4x5_rcc_pll_set_vco_multiplier(uint32_t pll_id, uint32_t old_multipl= ier, uint32_t new_multiplier) "RCC: PLL %u: vco_multiplier changed (%u -> %= u)" +stm32l4x5_rcc_pll_channel_enable(uint32_t pll_id, uint32_t channel_id) "RC= C: PLL %u, channel %u enabled" +stm32l4x5_rcc_pll_channel_disable(uint32_t pll_id, uint32_t channel_id) "R= CC: PLL %u, channel %u disabled" +stm32l4x5_rcc_pll_set_channel_divider(uint32_t pll_id, uint32_t channel_id= , uint32_t old_divider, uint32_t new_divider) "RCC: PLL %u, channel %u: div= ider changed (%u -> %u)" +stm32l4x5_rcc_pll_update(uint32_t pll_id, uint32_t channel_id, uint64_t vc= o_freq, uint64_t old_freq, uint64_t new_freq) "RCC: PLL %d channel %d updat= e: vco_freq %" PRIu64 " old_freq %" PRIu64 " new_freq %" PRIu64 "" =20 # tz-mpc.c tz_mpc_reg_read(uint32_t offset, uint64_t data, unsigned size) "TZ MPC reg= s read: offset 0x%x data 0x%" PRIx64 " size %u" diff --git a/include/hw/misc/stm32l4x5_rcc.h b/include/hw/misc/stm32l4x5_rc= c.h index 6719be9fbe..0fbfba5c40 100644 --- a/include/hw/misc/stm32l4x5_rcc.h +++ b/include/hw/misc/stm32l4x5_rcc.h @@ -26,6 +26,15 @@ OBJECT_DECLARE_SIMPLE_TYPE(Stm32l4x5RccState, STM32L4X5_= RCC) =20 /* In the Stm32l4x5 clock tree, mux have at most 7 sources */ #define RCC_NUM_CLOCK_MUX_SRC 7 + +typedef enum PllCommonChannels { + RCC_PLL_COMMON_CHANNEL_P =3D 0, + RCC_PLL_COMMON_CHANNEL_Q =3D 1, + RCC_PLL_COMMON_CHANNEL_R =3D 2, + + RCC_NUM_CHANNEL_PLL_OUT =3D 3 +} PllCommonChannels; + /* NB: Prescaler are assimilated to mux with one source and one output */ typedef enum RccClockMux { /* Internal muxes that arent't exposed publicly to other peripherals */ @@ -124,6 +133,14 @@ typedef enum RccClockMux { RCC_NUM_CLOCK_MUX } RccClockMux; =20 +typedef enum RccPll { + RCC_PLL_PLL, + RCC_PLL_PLLSAI1, + RCC_PLL_PLLSAI2, + + RCC_NUM_PLL +} RccPll; + typedef struct RccClockMuxState { DeviceState parent_obj; =20 @@ -142,6 +159,26 @@ typedef struct RccClockMuxState { struct RccClockMuxState *backref[RCC_NUM_CLOCK_MUX_SRC]; } RccClockMuxState; =20 +typedef struct RccPllState { + DeviceState parent_obj; + + RccPll id; + Clock *in; + uint32_t vco_multiplier; + Clock *channels[RCC_NUM_CHANNEL_PLL_OUT]; + /* Global pll enabled flag */ + bool enabled; + /* 'enabled' refers to the runtime configuration */ + bool channel_enabled[RCC_NUM_CHANNEL_PLL_OUT]; + /* + * 'exists' refers to the physical configuration + * It should only be set at pll initialization. + * e.g. pllsai2 doesn't have a Q output. + */ + bool channel_exists[RCC_NUM_CHANNEL_PLL_OUT]; + uint32_t channel_divider[RCC_NUM_CHANNEL_PLL_OUT]; +} RccPllState; + struct Stm32l4x5RccState { SysBusDevice parent_obj; =20 @@ -187,6 +224,9 @@ struct Stm32l4x5RccState { Clock *sai1_extclk; Clock *sai2_extclk; =20 + /* PLLs */ + RccPllState plls[RCC_NUM_PLL]; + /* Muxes ~=3D outputs */ RccClockMuxState clock_muxes[RCC_NUM_CLOCK_MUX]; =20 diff --git a/include/hw/misc/stm32l4x5_rcc_internals.h b/include/hw/misc/st= m32l4x5_rcc_internals.h index 4aa836848b..a9da5e3be7 100644 --- a/include/hw/misc/stm32l4x5_rcc_internals.h +++ b/include/hw/misc/stm32l4x5_rcc_internals.h @@ -22,7 +22,10 @@ #include "hw/misc/stm32l4x5_rcc.h" =20 #define TYPE_RCC_CLOCK_MUX "stm32l4x5-rcc-clock-mux" +#define TYPE_RCC_PLL "stm32l4x5-rcc-pll" + OBJECT_DECLARE_SIMPLE_TYPE(RccClockMuxState, RCC_CLOCK_MUX) +OBJECT_DECLARE_SIMPLE_TYPE(RccPllState, RCC_PLL) =20 /* Register map */ REG32(CR, 0x00) @@ -285,6 +288,25 @@ REG32(CSR, 0x94) R_CSR_FWRSTF_MASK | \ R_CSR_LSIRDY_MASK) =20 +/* Pll Channels */ +enum PllChannels { + RCC_PLL_CHANNEL_PLLSAI3CLK =3D 0, + RCC_PLL_CHANNEL_PLL48M1CLK =3D 1, + RCC_PLL_CHANNEL_PLLCLK =3D 2, +}; + +enum PllSai1Channels { + RCC_PLLSAI1_CHANNEL_PLLSAI1CLK =3D 0, + RCC_PLLSAI1_CHANNEL_PLL48M2CLK =3D 1, + RCC_PLLSAI1_CHANNEL_PLLADC1CLK =3D 2, +}; + +enum PllSai2Channels { + RCC_PLLSAI2_CHANNEL_PLLSAI2CLK =3D 0, + /* No Q channel */ + RCC_PLLSAI2_CHANNEL_PLLADC2CLK =3D 2, +}; + typedef enum RccClockMuxSource { RCC_CLOCK_MUX_SRC_GND =3D 0, RCC_CLOCK_MUX_SRC_HSI, --=20 2.34.1 From nobody Tue Nov 26 14:24:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=telecom-paris.fr ARC-Seal: i=1; a=rsa-sha256; t=1706366445; cv=none; d=zohomail.com; s=zohoarc; b=HSdEZxjRt8fxWV1csuqY/QbGzzIvG49FsXsDc4pGNbDOk03IqKsPm+OG8u2rRPVoECk9YmuG2x+zhxGyXXpUT1M9bqqXmNtQTqOwHRkaeG+zt0780BaMAHbFNg+W76SHnYt38JRMsXVHnA5yqmkIqTERpcddBCBavynU+hA0yug= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1706366445; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=VFSRe6BOAWerAW91uNxU1TKNA4zYh0rmTcbktsXPqfU=; b=ndiU+qzMn9nt6pSYY4PPc1BxQSSf0HwTWvvj1I2XlG/1Y66bv9q+eZi5BEqUrCyZCfLoCMRt5pl9vX0G9SQtnLvgV5cMS5hs6uEhlQymLatzkbfhzDv+MD4IRDrTRwHZsfHiyp0lsZi4su5s/pxTcXfeVjg4LAJoxa1bEt84WXo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1706366445676531.7123339626021; Sat, 27 Jan 2024 06:40:45 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rTjqL-0002Rd-Ei; Sat, 27 Jan 2024 09:39:37 -0500 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 1rTjqH-0002Pn-N7; Sat, 27 Jan 2024 09:39:33 -0500 Received: from zproxy4.enst.fr ([137.194.2.223]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rTjqD-0002Qh-1E; Sat, 27 Jan 2024 09:39:33 -0500 Received: from localhost (localhost [IPv6:::1]) by zproxy4.enst.fr (Postfix) with ESMTP id 069D9207F2; Sat, 27 Jan 2024 15:39:25 +0100 (CET) Received: from zproxy4.enst.fr ([IPv6:::1]) by localhost (zproxy4.enst.fr [IPv6:::1]) (amavis, port 10032) with ESMTP id EXyvJQlB5qyL; Sat, 27 Jan 2024 15:39:23 +0100 (CET) Received: from localhost (localhost [IPv6:::1]) by zproxy4.enst.fr (Postfix) with ESMTP id D22C1207D6; Sat, 27 Jan 2024 15:39:23 +0100 (CET) Received: from zproxy4.enst.fr ([IPv6:::1]) by localhost (zproxy4.enst.fr [IPv6:::1]) (amavis, port 10026) with ESMTP id 0ETSDGfvUjle; Sat, 27 Jan 2024 15:39:23 +0100 (CET) Received: from AM-Inspiron-3585.numericable.fr (38.162.10.109.rev.sfr.net [109.10.162.38]) by zproxy4.enst.fr (Postfix) with ESMTPSA id 4100220823; Sat, 27 Jan 2024 15:39:23 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.10.3 zproxy4.enst.fr D22C1207D6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=telecom-paris.fr; s=A35C7578-1106-11E5-A17F-C303FDDA8F2E; t=1706366363; bh=VFSRe6BOAWerAW91uNxU1TKNA4zYh0rmTcbktsXPqfU=; h=From:To:Date:Message-Id:MIME-Version; b=YFqsnZpvdxHTFh9TpIkUePgxigoM3Ier80o/VdJxc3jQxqUw4eexKz1G+b7CQI6QS k1qr3qhwXzX2O2/ngIgguPpCbpC/W3FkjY+dAIt1V9kPF9Adgczvl7NNfiGVdQouHo 5rlkcFcWxC1kuchjyBCPr/3sbk8m7Sna7ywkRnnc= X-Virus-Scanned: amavis at enst.fr From: Arnaud Minier To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, Arnaud Minier , Samuel Tardieu , Laurent Vivier , Paolo Bonzini , Alistair Francis , Peter Maydell , =?UTF-8?q?Philipe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?In=C3=A8s=20Varhol?= , Thomas Huth Subject: [PATCH v3 4/8] Add initialization information for PLLs and clock multiplexers Date: Sat, 27 Jan 2024 15:39:00 +0100 Message-Id: <20240127143904.80187-5-arnaud.minier@telecom-paris.fr> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> References: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=137.194.2.223; envelope-from=arnaud.minier@telecom-paris.fr; helo=zproxy4.enst.fr X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01, UPPERCASE_50_75=0.008 autolearn=no 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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @telecom-paris.fr) X-ZM-MESSAGEID: 1706366446272100002 Content-Type: text/plain; charset="utf-8" Signed-off-by: Arnaud Minier Signed-off-by: In=C3=A8s Varhol --- hw/misc/stm32l4x5_rcc.c | 69 ++- include/hw/misc/stm32l4x5_rcc_internals.h | 707 ++++++++++++++++++++++ 2 files changed, 774 insertions(+), 2 deletions(-) diff --git a/hw/misc/stm32l4x5_rcc.c b/hw/misc/stm32l4x5_rcc.c index 771b566c88..c2df70ab37 100644 --- a/hw/misc/stm32l4x5_rcc.c +++ b/hw/misc/stm32l4x5_rcc.c @@ -608,21 +608,79 @@ static void stm32l4x5_rcc_init(Object *obj) qdev_init_clocks(DEVICE(s), stm32l4x5_rcc_clocks); =20 for (i =3D 0; i < RCC_NUM_PLL; i++) { - object_initialize_child(obj, "pll[*]", + object_initialize_child(obj, PLL_INIT_INFO[i].name, &s->plls[i], TYPE_RCC_PLL); + set_pll_init_info(s, &s->plls[i], i); } =20 for (i =3D 0; i < RCC_NUM_CLOCK_MUX; i++) { + char *alias; =20 - object_initialize_child(obj, "clock[*]", + object_initialize_child(obj, CLOCK_MUX_INIT_INFO[i].name, &s->clock_muxes[i], TYPE_RCC_CLOCK_MUX); + set_clock_mux_init_info(s, &s->clock_muxes[i], i); =20 + if (!CLOCK_MUX_INIT_INFO[i].hidden) { + /* Expose muxes output as RCC outputs */ + alias =3D g_strdup_printf("%s-out", CLOCK_MUX_INIT_INFO[i].nam= e); + qdev_alias_clock(DEVICE(&s->clock_muxes[i]), "out", DEVICE(obj= ), alias); + g_free(alias); + } } =20 s->gnd =3D clock_new(obj, "gnd"); } =20 +static void connect_mux_sources(Stm32l4x5RccState *s, + RccClockMuxState *mux, + const RccClockMuxSource *clk_mapping) +{ + size_t i; + + Clock * const CLK_SRC_MAPPING[] =3D { + [RCC_CLOCK_MUX_SRC_GND] =3D s->gnd, + [RCC_CLOCK_MUX_SRC_HSI] =3D s->hsi16_rc, + [RCC_CLOCK_MUX_SRC_HSE] =3D s->hse, + [RCC_CLOCK_MUX_SRC_MSI] =3D s->msi_rc, + [RCC_CLOCK_MUX_SRC_LSI] =3D s->lsi_rc, + [RCC_CLOCK_MUX_SRC_LSE] =3D s->lse_crystal, + [RCC_CLOCK_MUX_SRC_SAI1_EXTCLK] =3D s->sai1_extclk, + [RCC_CLOCK_MUX_SRC_SAI2_EXTCLK] =3D s->sai2_extclk, + [RCC_CLOCK_MUX_SRC_PLL] =3D + s->plls[RCC_PLL_PLL].channels[RCC_PLL_CHANNEL_PLLCLK], + [RCC_CLOCK_MUX_SRC_PLLSAI1] =3D + s->plls[RCC_PLL_PLLSAI1].channels[RCC_PLLSAI1_CHANNEL_PLLSAI1C= LK], + [RCC_CLOCK_MUX_SRC_PLLSAI2] =3D + s->plls[RCC_PLL_PLLSAI2].channels[RCC_PLLSAI2_CHANNEL_PLLSAI2C= LK], + [RCC_CLOCK_MUX_SRC_PLLSAI3] =3D + s->plls[RCC_PLL_PLL].channels[RCC_PLL_CHANNEL_PLLSAI3CLK], + [RCC_CLOCK_MUX_SRC_PLL48M1] =3D + s->plls[RCC_PLL_PLL].channels[RCC_PLL_CHANNEL_PLL48M1CLK], + [RCC_CLOCK_MUX_SRC_PLL48M2] =3D + s->plls[RCC_PLL_PLLSAI1].channels[RCC_PLLSAI1_CHANNEL_PLL48M2C= LK], + [RCC_CLOCK_MUX_SRC_PLLADC1] =3D + s->plls[RCC_PLL_PLLSAI1].channels[RCC_PLLSAI1_CHANNEL_PLLADC1C= LK], + [RCC_CLOCK_MUX_SRC_PLLADC2] =3D + s->plls[RCC_PLL_PLLSAI2] .channels[RCC_PLLSAI2_CHANNEL_PLLADC2= CLK], + [RCC_CLOCK_MUX_SRC_SYSCLK] =3D s->clock_muxes[RCC_CLOCK_MUX_SYSCLK= ].out, + [RCC_CLOCK_MUX_SRC_HCLK] =3D s->clock_muxes[RCC_CLOCK_MUX_HCLK].ou= t, + [RCC_CLOCK_MUX_SRC_PCLK1] =3D s->clock_muxes[RCC_CLOCK_MUX_PCLK1].= out, + [RCC_CLOCK_MUX_SRC_PCLK2] =3D s->clock_muxes[RCC_CLOCK_MUX_PCLK2].= out, + [RCC_CLOCK_MUX_SRC_HSE_OVER_32] =3D s->clock_muxes[RCC_CLOCK_MUX_H= SE_OVER_32].out, + [RCC_CLOCK_MUX_SRC_LCD_AND_RTC_COMMON] =3D + s->clock_muxes[RCC_CLOCK_MUX_LCD_AND_RTC_COMMON].out, + }; + + assert(ARRAY_SIZE(CLK_SRC_MAPPING) =3D=3D RCC_CLOCK_MUX_SRC_NUMBER); + + for (i =3D 0; i < RCC_NUM_CLOCK_MUX_SRC; i++) { + RccClockMuxSource mapping =3D clk_mapping[i]; + clock_set_source(mux->srcs[i], CLK_SRC_MAPPING[mapping]); + } +} + + static const VMStateDescription vmstate_stm32l4x5_rcc =3D { .name =3D TYPE_STM32L4X5_RCC, .version_id =3D 1, @@ -688,11 +746,17 @@ static void stm32l4x5_rcc_realize(DeviceState *dev, E= rror **errp) for (i =3D 0; i < RCC_NUM_CLOCK_MUX; i++) { RccClockMuxState *clock_mux =3D &s->clock_muxes[i]; =20 + connect_mux_sources(s, clock_mux, CLOCK_MUX_INIT_INFO[i].src_mappi= ng); + if (!qdev_realize(DEVICE(clock_mux), NULL, errp)) { return; } } =20 + /* + * Start clocks after everything is connected + * to propagate the frequencies along the tree. + */ clock_update_hz(s->msi_rc, MSI_DEFAULT_FRQ); clock_update_hz(s->sai1_extclk, s->sai1_extclk_frequency); clock_update_hz(s->sai2_extclk, s->sai2_extclk_frequency); @@ -726,6 +790,7 @@ static void stm32l4x5_rcc_class_init(ObjectClass *klass= , void *data) DeviceClass *dc =3D DEVICE_CLASS(klass); ResettableClass *rc =3D RESETTABLE_CLASS(klass); =20 + assert(ARRAY_SIZE(CLOCK_MUX_INIT_INFO) =3D=3D RCC_NUM_CLOCK_MUX); =20 rc->phases.hold =3D stm32l4x5_rcc_reset_hold; device_class_set_props(dc, stm32l4x5_rcc_properties); diff --git a/include/hw/misc/stm32l4x5_rcc_internals.h b/include/hw/misc/st= m32l4x5_rcc_internals.h index a9da5e3be7..c73e20ae01 100644 --- a/include/hw/misc/stm32l4x5_rcc_internals.h +++ b/include/hw/misc/stm32l4x5_rcc_internals.h @@ -334,4 +334,711 @@ typedef enum RccClockMuxSource { RCC_CLOCK_MUX_SRC_NUMBER, } RccClockMuxSource; =20 +/* PLL init info */ +typedef struct PllInitInfo { + const char *name; + + const char *channel_name[RCC_NUM_CHANNEL_PLL_OUT]; + bool channel_exists[RCC_NUM_CHANNEL_PLL_OUT]; + uint32_t default_channel_divider[RCC_NUM_CHANNEL_PLL_OUT]; + + RccClockMuxSource src_mapping[RCC_NUM_CLOCK_MUX_SRC]; +} PllInitInfo; + +static const PllInitInfo PLL_INIT_INFO[] =3D { + [RCC_PLL_PLL] =3D { + .name =3D "pll", + .channel_name =3D { + "pllsai3clk", + "pll48m1clk", + "pllclk" + }, + .channel_exists =3D { + true, true, true + }, + /* From PLLCFGR register documentation */ + .default_channel_divider =3D { + 7, 2, 2 + } + }, + [RCC_PLL_PLLSAI1] =3D { + .name =3D "pllsai1", + .channel_name =3D { + "pllsai1clk", + "pll48m2clk", + "plladc1clk" + }, + .channel_exists =3D { + true, true, true + }, + /* From PLLSAI1CFGR register documentation */ + .default_channel_divider =3D { + 7, 2, 2 + } + }, + [RCC_PLL_PLLSAI2] =3D { + .name =3D "pllsai2", + .channel_name =3D { + "pllsai2clk", + NULL, + "plladc2clk" + }, + .channel_exists =3D { + true, false, true + }, + /* From PLLSAI2CFGR register documentation */ + .default_channel_divider =3D { + 7, 0, 2 + } + } +}; + +static inline void set_pll_init_info(Stm32l4x5RccState *s, + RccPllState *pll, + RccPll id) +{ + int i; + + pll->id =3D id; + pll->vco_multiplier =3D 1; + for (i =3D 0; i < RCC_NUM_CHANNEL_PLL_OUT; i++) { + pll->channel_enabled[i] =3D false; + pll->channel_exists[i] =3D PLL_INIT_INFO[id].channel_exists[i]; + pll->channel_divider[i] =3D PLL_INIT_INFO[id].default_channel_divi= der[i]; + } +} + +/* Clock mux init info */ +typedef struct ClockMuxInitInfo { + const char *name; + + uint32_t multiplier; + uint32_t divider; + bool enabled; + /* If this is true, the clock will not be exposed outside of the devic= e */ + bool hidden; + + RccClockMuxSource src_mapping[RCC_NUM_CLOCK_MUX_SRC]; +} ClockMuxInitInfo; + +#define FILL_DEFAULT_FACTOR \ + .multiplier =3D 1, \ + .divider =3D 1 + +#define FILL_DEFAULT_INIT_ENABLED \ + FILL_DEFAULT_FACTOR, \ + .enabled =3D true + +#define FILL_DEFAULT_INIT_DISABLED \ + FILL_DEFAULT_FACTOR, \ + .enabled =3D false + + +static const ClockMuxInitInfo CLOCK_MUX_INIT_INFO[] =3D { + [RCC_CLOCK_MUX_SYSCLK] =3D { + .name =3D "sysclk", + /* Same mapping as: CFGR_SW */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_MSI, + RCC_CLOCK_MUX_SRC_HSI, + RCC_CLOCK_MUX_SRC_HSE, + RCC_CLOCK_MUX_SRC_PLL, + }, + .hidden =3D true, + FILL_DEFAULT_INIT_ENABLED, + }, + [RCC_CLOCK_MUX_PLL_INPUT] =3D { + .name =3D "pll-input", + /* Same mapping as: PLLCFGR_PLLSRC */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_MSI, + RCC_CLOCK_MUX_SRC_HSI, + RCC_CLOCK_MUX_SRC_HSE, + }, + .hidden =3D true, + FILL_DEFAULT_INIT_ENABLED, + }, + [RCC_CLOCK_MUX_HCLK] =3D { + .name =3D "hclk", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + .hidden =3D true, + FILL_DEFAULT_INIT_ENABLED, + }, + [RCC_CLOCK_MUX_PCLK1] =3D { + .name =3D "pclk1", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_HCLK, + }, + .hidden =3D true, + FILL_DEFAULT_INIT_ENABLED, + }, + [RCC_CLOCK_MUX_PCLK2] =3D { + .name =3D "pclk2", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_HCLK, + }, + .hidden =3D true, + FILL_DEFAULT_INIT_ENABLED, + }, + [RCC_CLOCK_MUX_HSE_OVER_32] =3D { + .name =3D "hse-divided-by-32", + .multiplier =3D 1, + .divider =3D 32, + .enabled =3D true, + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_HSE, + }, + .hidden =3D true, + }, + [RCC_CLOCK_MUX_LCD_AND_RTC_COMMON] =3D { + .name =3D "lcd-and-rtc-common-mux", + /* Same mapping as: BDCR_RTCSEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_GND, + RCC_CLOCK_MUX_SRC_LSE, + RCC_CLOCK_MUX_SRC_LSI, + RCC_CLOCK_MUX_SRC_HSE_OVER_32, + }, + .hidden =3D true, + FILL_DEFAULT_INIT_ENABLED, + }, + /* From now on, muxes with a publicly available output */ + [RCC_CLOCK_MUX_CORTEX_REFCLK] =3D { + .name =3D "cortex-refclk", + .multiplier =3D 1, + /* REFCLK is always HCLK/8 */ + .divider =3D 8, + .enabled =3D true, + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_HCLK, + } + }, + [RCC_CLOCK_MUX_USART1] =3D { + .name =3D "usart1", + /* Same mapping as: CCIPR_USART1SEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK2, + RCC_CLOCK_MUX_SRC_SYSCLK, + RCC_CLOCK_MUX_SRC_HSI, + RCC_CLOCK_MUX_SRC_LSE, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_USART2] =3D { + .name =3D "usart2", + /* Same mapping as: CCIPR_USART2SEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + RCC_CLOCK_MUX_SRC_SYSCLK, + RCC_CLOCK_MUX_SRC_HSI, + RCC_CLOCK_MUX_SRC_LSE, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_USART3] =3D { + .name =3D "usart3", + /* Same mapping as: CCIPR_USART3SEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + RCC_CLOCK_MUX_SRC_SYSCLK, + RCC_CLOCK_MUX_SRC_HSI, + RCC_CLOCK_MUX_SRC_LSE, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_UART4] =3D { + .name =3D "uart4", + /* Same mapping as: CCIPR_UART4SEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + RCC_CLOCK_MUX_SRC_SYSCLK, + RCC_CLOCK_MUX_SRC_HSI, + RCC_CLOCK_MUX_SRC_LSE, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_UART5] =3D { + .name =3D "uart5", + /* Same mapping as: CCIPR_UART5SEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + RCC_CLOCK_MUX_SRC_SYSCLK, + RCC_CLOCK_MUX_SRC_HSI, + RCC_CLOCK_MUX_SRC_LSE, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_LPUART1] =3D { + .name =3D "lpuart1", + /* Same mapping as: CCIPR_LPUART1SEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + RCC_CLOCK_MUX_SRC_SYSCLK, + RCC_CLOCK_MUX_SRC_HSI, + RCC_CLOCK_MUX_SRC_LSE, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_I2C1] =3D { + .name =3D "i2c1", + /* Same mapping as: CCIPR_I2C1SEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + RCC_CLOCK_MUX_SRC_SYSCLK, + RCC_CLOCK_MUX_SRC_HSI, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_I2C2] =3D { + .name =3D "i2c2", + /* Same mapping as: CCIPR_I2C2SEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + RCC_CLOCK_MUX_SRC_SYSCLK, + RCC_CLOCK_MUX_SRC_HSI, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_I2C3] =3D { + .name =3D "i2c3", + /* Same mapping as: CCIPR_I2C3SEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + RCC_CLOCK_MUX_SRC_SYSCLK, + RCC_CLOCK_MUX_SRC_HSI, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_LPTIM1] =3D { + .name =3D "lptim1", + /* Same mapping as: CCIPR_LPTIM1SEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + RCC_CLOCK_MUX_SRC_LSI, + RCC_CLOCK_MUX_SRC_HSI, + RCC_CLOCK_MUX_SRC_LSE, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_LPTIM2] =3D { + .name =3D "lptim2", + /* Same mapping as: CCIPR_LPTIM2SEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + RCC_CLOCK_MUX_SRC_LSI, + RCC_CLOCK_MUX_SRC_HSI, + RCC_CLOCK_MUX_SRC_LSE, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_SWPMI1] =3D { + .name =3D "swpmi1", + /* Same mapping as: CCIPR_SWPMI1SEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + RCC_CLOCK_MUX_SRC_HSI, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_MCO] =3D { + .name =3D "mco", + /* Same mapping as: CFGR_MCOSEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + RCC_CLOCK_MUX_SRC_MSI, + RCC_CLOCK_MUX_SRC_HSI, + RCC_CLOCK_MUX_SRC_HSE, + RCC_CLOCK_MUX_SRC_PLL, + RCC_CLOCK_MUX_SRC_LSI, + RCC_CLOCK_MUX_SRC_LSE, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_LSCO] =3D { + .name =3D "lsco", + /* Same mapping as: BDCR_LSCOSEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_LSI, + RCC_CLOCK_MUX_SRC_LSE, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_DFSDM1] =3D { + .name =3D "dfsdm1", + /* Same mapping as: CCIPR_DFSDM1SEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK2, + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_ADC] =3D { + .name =3D "adc", + /* Same mapping as: CCIPR_ADCSEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_GND, + RCC_CLOCK_MUX_SRC_PLLADC1, + RCC_CLOCK_MUX_SRC_PLLADC2, + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_CLK48] =3D { + .name =3D "clk48", + /* Same mapping as: CCIPR_CLK48SEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_GND, + RCC_CLOCK_MUX_SRC_PLL48M2, + RCC_CLOCK_MUX_SRC_PLL48M1, + RCC_CLOCK_MUX_SRC_MSI, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_SAI2] =3D { + .name =3D "sai2", + /* Same mapping as: CCIPR_SAI2SEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PLLSAI1, + RCC_CLOCK_MUX_SRC_PLLSAI2, + RCC_CLOCK_MUX_SRC_PLLSAI3, + RCC_CLOCK_MUX_SRC_SAI2_EXTCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_SAI1] =3D { + .name =3D "sai1", + /* Same mapping as: CCIPR_SAI1SEL */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PLLSAI1, + RCC_CLOCK_MUX_SRC_PLLSAI2, + RCC_CLOCK_MUX_SRC_PLLSAI3, + RCC_CLOCK_MUX_SRC_SAI1_EXTCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + /* From now on, these muxes only have one valid source */ + [RCC_CLOCK_MUX_TSC] =3D { + .name =3D "tsc", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_CRC] =3D { + .name =3D "crc", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_FLASH] =3D { + .name =3D "flash", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_DMA2] =3D { + .name =3D "dma2", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_DMA1] =3D { + .name =3D "dma1", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_RNG] =3D { + .name =3D "rng", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_AES] =3D { + .name =3D "aes", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_OTGFS] =3D { + .name =3D "otgfs", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_GPIOA] =3D { + .name =3D "gpioa", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_GPIOB] =3D { + .name =3D "gpiob", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_GPIOC] =3D { + .name =3D "gpioc", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_GPIOD] =3D { + .name =3D "gpiod", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_GPIOE] =3D { + .name =3D "gpioe", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_GPIOF] =3D { + .name =3D "gpiof", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_GPIOG] =3D { + .name =3D "gpiog", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_GPIOH] =3D { + .name =3D "gpioh", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_QSPI] =3D { + .name =3D "qspi", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_FMC] =3D { + .name =3D "fmc", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_OPAMP] =3D { + .name =3D "opamp", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_DAC1] =3D { + .name =3D "dac1", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_PWR] =3D { + .name =3D "pwr", + /* + * PWREN is in the APB1ENR1 register, + * but PWR uses SYSCLK according to the clock tree. + */ + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_SYSCLK, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_CAN1] =3D { + .name =3D "can1", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_SPI3] =3D { + .name =3D "spi3", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_SPI2] =3D { + .name =3D "spi2", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_WWDG] =3D { + .name =3D "wwdg", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_LCD] =3D { + .name =3D "lcd", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_LCD_AND_RTC_COMMON, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_TIM7] =3D { + .name =3D "tim7", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_TIM6] =3D { + .name =3D "tim6", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_TIM5] =3D { + .name =3D "tim5", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_TIM4] =3D { + .name =3D "tim4", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_TIM3] =3D { + .name =3D "tim3", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_TIM2] =3D { + .name =3D "tim2", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK1, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_TIM17] =3D { + .name =3D "tim17", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK2, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_TIM16] =3D { + .name =3D "tim16", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK2, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_TIM15] =3D { + .name =3D "tim15", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK2, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_TIM8] =3D { + .name =3D "tim8", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK2, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_SPI1] =3D { + .name =3D "spi1", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK2, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_TIM1] =3D { + .name =3D "tim1", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK2, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_SDMMC1] =3D { + .name =3D "sdmmc1", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK2, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_FW] =3D { + .name =3D "fw", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK2, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_SYSCFG] =3D { + .name =3D "syscfg", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_PCLK2, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_RTC] =3D { + .name =3D "rtc", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_LCD_AND_RTC_COMMON, + }, + FILL_DEFAULT_INIT_DISABLED, + }, + [RCC_CLOCK_MUX_CORTEX_FCLK] =3D { + .name =3D "cortex-fclk", + .src_mapping =3D { + RCC_CLOCK_MUX_SRC_HCLK, + }, + FILL_DEFAULT_INIT_ENABLED, + }, +}; + +static inline void set_clock_mux_init_info(Stm32l4x5RccState *s, + RccClockMuxState *mux, + RccClockMux id) +{ + mux->id =3D id; + mux->multiplier =3D CLOCK_MUX_INIT_INFO[id].multiplier; + mux->divider =3D CLOCK_MUX_INIT_INFO[id].divider; + mux->enabled =3D CLOCK_MUX_INIT_INFO[id].enabled; + /* + * Every peripheral has the first source of their source list as + * as their default source. + */ + mux->src =3D 0; +} + #endif /* HW_STM32L4X5_RCC_INTERNALS_H */ --=20 2.34.1 From nobody Tue Nov 26 14:24:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=telecom-paris.fr ARC-Seal: i=1; a=rsa-sha256; t=1706366421; cv=none; d=zohomail.com; s=zohoarc; b=Mc3wdAKhA4tVSuASqo225fSDqlaC5rEYLLwAL6Ksxqz81O6Ka9YEOPfpI39UvV9NcR/cdlsn28V7Ubibr7/eX/+vtE0GpWtvE1w0ICz0C56LK6xuFqGWZxVt0fg4tugTNGZfzbDqovrFxzrpckHbTDpP+jizk97i+tJuaUu8R9s= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1706366421; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=na6u6cNTAvm5sOEF9RnEXZb5HPndszMt0Bd4vkXu+a4=; b=D4MdQiqCfafG+ktbYBs8szKX64n9fHAe6tPlxXVA63zGAz2+IRwJvD5trH5BXq6tIuL1oBxbdlQ71pVidM7jyFV6jsDDWkpRtGbTEBI8wgEKqq/FmBDeTinhx8jn7yT4XL5WA/Dm38jS5R+2syp8q5eCJ+zoETWKhI45Yju+MOc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1706366421182107.60612346604933; Sat, 27 Jan 2024 06:40:21 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rTjqP-0002TC-8b; Sat, 27 Jan 2024 09:39:41 -0500 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 1rTjqJ-0002R8-DE; Sat, 27 Jan 2024 09:39:35 -0500 Received: from zproxy4.enst.fr ([137.194.2.223]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rTjqG-0002RK-8q; Sat, 27 Jan 2024 09:39:35 -0500 Received: from localhost (localhost [IPv6:::1]) by zproxy4.enst.fr (Postfix) with ESMTP id 76B6B207D6; Sat, 27 Jan 2024 15:39:25 +0100 (CET) Received: from zproxy4.enst.fr ([IPv6:::1]) by localhost (zproxy4.enst.fr [IPv6:::1]) (amavis, port 10032) with ESMTP id mQ5fOBOx5SFy; Sat, 27 Jan 2024 15:39:24 +0100 (CET) Received: from localhost (localhost [IPv6:::1]) by zproxy4.enst.fr (Postfix) with ESMTP id 1BEDE2082D; Sat, 27 Jan 2024 15:39:24 +0100 (CET) Received: from zproxy4.enst.fr ([IPv6:::1]) by localhost (zproxy4.enst.fr [IPv6:::1]) (amavis, port 10026) with ESMTP id qKVCm-Xkp474; Sat, 27 Jan 2024 15:39:23 +0100 (CET) Received: from AM-Inspiron-3585.numericable.fr (38.162.10.109.rev.sfr.net [109.10.162.38]) by zproxy4.enst.fr (Postfix) with ESMTPSA id 9B24B20811; Sat, 27 Jan 2024 15:39:23 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.10.3 zproxy4.enst.fr 1BEDE2082D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=telecom-paris.fr; s=A35C7578-1106-11E5-A17F-C303FDDA8F2E; t=1706366364; bh=na6u6cNTAvm5sOEF9RnEXZb5HPndszMt0Bd4vkXu+a4=; h=From:To:Date:Message-Id:MIME-Version; b=CgkRSOEjOagZM+w3CUxHuyWyCY3PeR19/SKY06BJapkMbBGKXFk/EkkihzA4Wsn0e L4s490dzrtycl8BjAFNXDU292054q9PwjTj94cDWyfcIICIPYFHWuii8Ga7JRjpg9Z u97hduykDj6AYXeXy+vg0VMnMuBNkxjoyDf4Ui8U= X-Virus-Scanned: amavis at enst.fr From: Arnaud Minier To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, Arnaud Minier , Samuel Tardieu , Laurent Vivier , Paolo Bonzini , Alistair Francis , Peter Maydell , =?UTF-8?q?Philipe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?In=C3=A8s=20Varhol?= , Thomas Huth Subject: [PATCH v3 5/8] RCC: Handle Register Updates Date: Sat, 27 Jan 2024 15:39:01 +0100 Message-Id: <20240127143904.80187-6-arnaud.minier@telecom-paris.fr> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> References: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=137.194.2.223; envelope-from=arnaud.minier@telecom-paris.fr; helo=zproxy4.enst.fr X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, 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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @telecom-paris.fr) X-ZM-MESSAGEID: 1706366422393100001 Content-Type: text/plain; charset="utf-8" Signed-off-by: Arnaud Minier Signed-off-by: In=C3=A8s Varhol --- hw/misc/stm32l4x5_rcc.c | 508 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 496 insertions(+), 12 deletions(-) diff --git a/hw/misc/stm32l4x5_rcc.c b/hw/misc/stm32l4x5_rcc.c index c2df70ab37..1f55662bbd 100644 --- a/hw/misc/stm32l4x5_rcc.c +++ b/hw/misc/stm32l4x5_rcc.c @@ -36,6 +36,19 @@ #define LSE_FRQ 32768ULL #define LSI_FRQ 32000ULL =20 +/* + * Extract the bits of the field designated by `_bit_field_name` from the + * register `_register_name`, stored in the field `_struct_field_name` of = the + * Stm32l4x5RccState struct named `_struct`. + * + * Usually, `_struct_field_name` is the lowercase version of `_register_na= me`. + */ +#define REGISTER_EXTRACT(_struct_name, _struct_field_name, \ + _register_name, _bit_field_name) \ + extract32(_struct_name->_struct_field_name, \ + R_##_register_name##_##_bit_field_name##_SHIFT, \ + R_##_register_name##_##_bit_field_name##_LENGTH) + static void clock_mux_update(RccClockMuxState *mux) { uint64_t src_freq, old_freq, freq; @@ -306,6 +319,9 @@ static void pll_set_channel_divider(RccPllState *pll, =20 static void rcc_update_irq(Stm32l4x5RccState *s) { + /* + * TODO: Handle LSECSSF and CSSF flags when the CSS is implemented. + */ if (s->cifr & CIFR_IRQ_MASK) { qemu_irq_raise(s->irq); } else { @@ -313,6 +329,472 @@ static void rcc_update_irq(Stm32l4x5RccState *s) } } =20 +static void rcc_update_cr_register(Stm32l4x5RccState *s) +{ + int val; + + /* PLLSAI2ON and update PLLSAI2RDY */ + val =3D extract32(s->cr, R_CR_PLLSAI2ON_SHIFT, R_CR_PLLSAI2ON_LENGTH); + pll_set_enable(&s->plls[RCC_PLL_PLLSAI2], val); + s->cr =3D (s->cr & ~R_CR_PLLSAI2RDY_MASK) | + (val << R_CR_PLLSAI2RDY_SHIFT); + if (s->cier & R_CIER_PLLSAI2RDYIE_MASK) { + s->cifr |=3D R_CIFR_PLLSAI2RDYF_MASK; + } + + /* PLLSAI1ON and update PLLSAI1RDY */ + val =3D extract32(s->cr, R_CR_PLLSAI1ON_SHIFT, R_CR_PLLSAI1ON_LENGTH); + pll_set_enable(&s->plls[RCC_PLL_PLLSAI1], val); + s->cr =3D (s->cr & ~R_CR_PLLSAI1RDY_MASK) | + (val << R_CR_PLLSAI1RDY_SHIFT); + if (s->cier & R_CIER_PLLSAI1RDYIE_MASK) { + s->cifr |=3D R_CIFR_PLLSAI1RDYF_MASK; + } + + /* PLLON and update PLLRDY */ + val =3D extract32(s->cr, R_CR_PLLON_SHIFT, R_CR_PLLON_LENGTH); + pll_set_enable(&s->plls[RCC_PLL_PLL], val); + s->cr =3D (s->cr & ~R_CR_PLLRDY_MASK) | + (val << R_CR_PLLRDY_SHIFT); + if (s->cier & R_CIER_PLLRDYIE_MASK) { + s->cifr |=3D R_CIFR_PLLRDYF_MASK; + } + + /* CSSON: TODO */ + /* HSEBYP: TODO */ + + /* HSEON and update HSERDY */ + val =3D extract32(s->cr, R_CR_HSEON_SHIFT, R_CR_HSEON_LENGTH); + s->cr =3D (s->cr & ~R_CR_HSERDY_MASK) | + (val << R_CR_HSERDY_SHIFT); + if (val) { + clock_update_hz(s->hse, s->hse_frequency); + if (s->cier & R_CIER_HSERDYIE_MASK) { + s->cifr |=3D R_CIFR_HSERDYF_MASK; + } + } else { + clock_update_hz(s->hse, 0); + } + + /* HSIAFS: TODO*/ + /* HSIKERON: TODO*/ + + /* HSION and update HSIRDY*/ + val =3D extract32(s->cr, R_CR_HSION_SHIFT, R_CR_HSION_LENGTH); + s->cr =3D (s->cr & ~R_CR_HSIRDY_MASK) | + (val << R_CR_HSIRDY_SHIFT); + if (val) { + clock_update_hz(s->hsi16_rc, HSI_FRQ); + if (s->cier & R_CIER_HSIRDYIE_MASK) { + s->cifr |=3D R_CIFR_HSIRDYF_MASK; + } + } else { + clock_update_hz(s->hsi16_rc, 0); + } + + static const uint32_t msirange[] =3D { + 100000, 200000, 400000, 800000, 1000000, 2000000, + 4000000, 8000000, 16000000, 24000000, 32000000, 48000000 + }; + /* MSIRANGE and MSIRGSEL */ + val =3D extract32(s->cr, R_CR_MSIRGSEL_SHIFT, R_CR_MSIRGSEL_LENGTH); + if (val) { + /* MSIRGSEL is set, use the MSIRANGE field */ + val =3D extract32(s->cr, R_CR_MSIRANGE_SHIFT, R_CR_MSIRANGE_LENGTH= ); + } else { + /* MSIRGSEL is not set, use the MSISRANGE field */ + val =3D extract32(s->csr, R_CSR_MSISRANGE_SHIFT, R_CSR_MSISRANGE_L= ENGTH); + } + + if (val < ARRAY_SIZE(msirange)) { + clock_update_hz(s->msi_rc, msirange[val]); + } else { + clock_update_hz(s->msi_rc, MSI_DEFAULT_FRQ); + /* TODO: there is a write protection if the value is out of bound, + implement that instead of setting the default */ + } + + /* MSIPLLEN */ + + /* MSION and update MSIRDY */ + val =3D extract32(s->cr, R_CR_MSION_SHIFT, R_CR_MSION_LENGTH); + s->cr =3D (s->cr & ~R_CR_MSIRDY_MASK) | + (val << R_CR_MSIRDY_SHIFT); + if (s->cier & R_CIER_MSIRDYIE_MASK) { + s->cifr |=3D R_CIFR_MSIRDYF_MASK; + } + rcc_update_irq(s); +} + +static void rcc_update_cfgr_register(Stm32l4x5RccState *s) +{ + uint32_t val; + /* MCOPRE */ + val =3D extract32(s->cfgr, R_CFGR_MCOPRE_SHIFT, R_CFGR_MCOPRE_LENGTH); + assert(val <=3D 0b100); + clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_MCO], + 1, 1 << val); + + /* MCOSEL */ + val =3D extract32(s->cfgr, R_CFGR_MCOSEL_SHIFT, R_CFGR_MCOSEL_LENGTH); + assert(val <=3D 0b111); + if (val =3D=3D 0) { + clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_MCO], false); + } else { + clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_MCO], true); + clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_MCO], + val - 1); + } + + /* STOPWUCK */ + /* TODO */ + + /* PPRE2 */ + val =3D extract32(s->cfgr, R_CFGR_PPRE2_SHIFT, R_CFGR_PPRE2_LENGTH); + if (val < 0b100) { + clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PCLK2], + 1, 1); + } else { + clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PCLK2], + 1, 1 << (val - 0b11)); + } + + /* PPRE1 */ + val =3D extract32(s->cfgr, R_CFGR_PPRE1_SHIFT, R_CFGR_PPRE1_LENGTH); + if (val < 0b100) { + clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PCLK1], + 1, 1); + } else { + clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PCLK1], + 1, 1 << (val - 0b11)); + } + + /* HPRE */ + val =3D extract32(s->cfgr, R_CFGR_HPRE_SHIFT, R_CFGR_HPRE_LENGTH); + if (val < 0b1000) { + clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_HCLK], + 1, 1); + } else { + clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_HCLK], + 1, 1 << (val - 0b111)); + } + + /* Update SWS */ + val =3D extract32(s->cfgr, R_CFGR_SW_SHIFT, R_CFGR_SW_LENGTH); + clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_SYSCLK], + val); + s->cfgr &=3D ~R_CFGR_SWS_MASK; + s->cfgr |=3D val << R_CFGR_SWS_SHIFT; +} + +static void rcc_update_ahb1enr(Stm32l4x5RccState *s) +{ + #define AHB1ENR_SET_ENABLE(_peripheral_name) \ + clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_n= ame], \ + REGISTER_EXTRACT(s, ahb1enr, AHB1ENR, _peripheral_name##EN)) + + /* DMA2DEN: reserved for STM32L475xx */ + AHB1ENR_SET_ENABLE(TSC); + AHB1ENR_SET_ENABLE(CRC); + AHB1ENR_SET_ENABLE(FLASH); + AHB1ENR_SET_ENABLE(DMA2); + AHB1ENR_SET_ENABLE(DMA1); + + #undef AHB1ENR_SET_ENABLE +} + +static void rcc_update_ahb2enr(Stm32l4x5RccState *s) +{ + #define AHB2ENR_SET_ENABLE(_peripheral_name) \ + clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_n= ame], \ + REGISTER_EXTRACT(s, ahb2enr, AHB2ENR, _peripheral_name##EN)) + + AHB2ENR_SET_ENABLE(RNG); + /* HASHEN: reserved for STM32L475xx */ + AHB2ENR_SET_ENABLE(AES); + /* DCMIEN: reserved for STM32L475xx */ + AHB2ENR_SET_ENABLE(ADC); + AHB2ENR_SET_ENABLE(OTGFS); + /* GPIOIEN: reserved for STM32L475xx */ + AHB2ENR_SET_ENABLE(GPIOA); + AHB2ENR_SET_ENABLE(GPIOB); + AHB2ENR_SET_ENABLE(GPIOC); + AHB2ENR_SET_ENABLE(GPIOD); + AHB2ENR_SET_ENABLE(GPIOE); + AHB2ENR_SET_ENABLE(GPIOF); + AHB2ENR_SET_ENABLE(GPIOG); + AHB2ENR_SET_ENABLE(GPIOH); + + #undef AHB2ENR_SET_ENABLE +} + +static void rcc_update_ahb3enr(Stm32l4x5RccState *s) +{ + #define AHB3ENR_SET_ENABLE(_peripheral_name) \ + clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_n= ame], \ + REGISTER_EXTRACT(s, ahb3enr, AHB3ENR, _peripheral_name##EN)) + + AHB3ENR_SET_ENABLE(QSPI); + AHB3ENR_SET_ENABLE(FMC); + + #undef AHB3ENR_SET_ENABLE +} + +static void rcc_update_apb1enr(Stm32l4x5RccState *s) +{ + #define APB1ENR1_SET_ENABLE(_peripheral_name) \ + clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_n= ame], \ + REGISTER_EXTRACT(s, apb1enr1, APB1ENR1, _peripheral_name##EN)) + #define APB1ENR2_SET_ENABLE(_peripheral_name) \ + clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_n= ame], \ + REGISTER_EXTRACT(s, apb1enr2, APB1ENR2, _peripheral_name##EN)) + + /* APB1ENR1 */ + APB1ENR1_SET_ENABLE(LPTIM1); + APB1ENR1_SET_ENABLE(OPAMP); + APB1ENR1_SET_ENABLE(DAC1); + APB1ENR1_SET_ENABLE(PWR); + /* CAN2: reserved for STM32L4x5 */ + APB1ENR1_SET_ENABLE(CAN1); + /* CRSEN: reserved for STM32L4x5 */ + APB1ENR1_SET_ENABLE(I2C3); + APB1ENR1_SET_ENABLE(I2C2); + APB1ENR1_SET_ENABLE(I2C1); + APB1ENR1_SET_ENABLE(UART5); + APB1ENR1_SET_ENABLE(UART4); + APB1ENR1_SET_ENABLE(USART3); + APB1ENR1_SET_ENABLE(USART2); + APB1ENR1_SET_ENABLE(SPI3); + APB1ENR1_SET_ENABLE(SPI2); + APB1ENR1_SET_ENABLE(WWDG); + /* RTCAPB: reserved for STM32L4x5 */ + APB1ENR1_SET_ENABLE(LCD); + APB1ENR1_SET_ENABLE(TIM7); + APB1ENR1_SET_ENABLE(TIM6); + APB1ENR1_SET_ENABLE(TIM5); + APB1ENR1_SET_ENABLE(TIM4); + APB1ENR1_SET_ENABLE(TIM3); + APB1ENR1_SET_ENABLE(TIM2); + + /* APB1ENR2 */ + APB1ENR2_SET_ENABLE(LPTIM2); + APB1ENR2_SET_ENABLE(SWPMI1); + /* I2C4EN: reserved for STM32L4x5 */ + APB1ENR2_SET_ENABLE(LPUART1); + + #undef APB1ENR1_SET_ENABLE + #undef APB1ENR2_SET_ENABLE +} + +static void rcc_update_apb2enr(Stm32l4x5RccState *s) +{ + #define APB2ENR_SET_ENABLE(_peripheral_name) \ + clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_n= ame], \ + REGISTER_EXTRACT(s, apb2enr, APB2ENR, _peripheral_name##EN)) + + APB2ENR_SET_ENABLE(DFSDM1); + APB2ENR_SET_ENABLE(SAI2); + APB2ENR_SET_ENABLE(SAI1); + APB2ENR_SET_ENABLE(TIM17); + APB2ENR_SET_ENABLE(TIM16); + APB2ENR_SET_ENABLE(TIM15); + APB2ENR_SET_ENABLE(USART1); + APB2ENR_SET_ENABLE(TIM8); + APB2ENR_SET_ENABLE(SPI1); + APB2ENR_SET_ENABLE(TIM1); + APB2ENR_SET_ENABLE(SDMMC1); + APB2ENR_SET_ENABLE(FW); + APB2ENR_SET_ENABLE(SYSCFG); + + #undef APB2ENR_SET_ENABLE +} + +/* + * The 3 PLLs share the same register layout + * so we can use the same function for all of them + * Note: no frequency bounds checking is done here. + */ +static void rcc_update_pllsaixcfgr(Stm32l4x5RccState *s, RccPll pll_id) +{ + uint32_t reg, val; + switch (pll_id) { + case RCC_PLL_PLL: + reg =3D s->pllcfgr; + break; + case RCC_PLL_PLLSAI1: + reg =3D s->pllsai1cfgr; + break; + case RCC_PLL_PLLSAI2: + reg =3D s->pllsai2cfgr; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Invalid PLL ID: %u\n", __func__, pll_id); + return; + } + + /* PLLPDIV */ + val =3D extract32(reg, R_PLLCFGR_PLLPDIV_SHIFT, R_PLLCFGR_PLLPDIV_LENG= TH); + /* 1 is a reserved value */ + if (val =3D=3D 0) { + /* Get PLLP value */ + val =3D extract32(reg, R_PLLCFGR_PLLP_SHIFT, R_PLLCFGR_PLLP_LENGTH= ); + pll_set_channel_divider(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_P, + (val ? 17 : 7)); + } else if (val > 1) { + pll_set_channel_divider(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_P, + val); + } + + + /* PLLR */ + val =3D extract32(reg, R_PLLCFGR_PLLR_SHIFT, R_PLLCFGR_PLLR_LENGTH); + pll_set_channel_divider(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_R, + 2 * (val + 1)); + + /* PLLREN */ + val =3D extract32(reg, R_PLLCFGR_PLLREN_SHIFT, R_PLLCFGR_PLLREN_LENGTH= ); + pll_set_channel_enable(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_R, val= ); + + /* PLLQ */ + val =3D extract32(reg, R_PLLCFGR_PLLQ_SHIFT, R_PLLCFGR_PLLQ_LENGTH); + pll_set_channel_divider(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_Q, + 2 * (val + 1)); + + /* PLLQEN */ + val =3D extract32(reg, R_PLLCFGR_PLLQEN_SHIFT, R_PLLCFGR_PLLQEN_LENGTH= ); + pll_set_channel_enable(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_Q, val= ); + + /* PLLPEN */ + val =3D extract32(reg, R_PLLCFGR_PLLPEN_SHIFT, R_PLLCFGR_PLLPEN_LENGTH= ); + pll_set_channel_enable(&s->plls[pll_id], RCC_PLL_COMMON_CHANNEL_P, val= ); + + /* PLLN */ + val =3D extract32(reg, R_PLLCFGR_PLLN_SHIFT, R_PLLCFGR_PLLN_LENGTH); + pll_set_vco_multiplier(&s->plls[pll_id], val); +} + +static void rcc_update_pllcfgr(Stm32l4x5RccState *s) +{ + int val; + + /* Use common layout */ + rcc_update_pllsaixcfgr(s, RCC_PLL_PLL); + + /* Fetch specific fields for pllcfgr */ + + /* PLLM */ + val =3D extract32(s->pllcfgr, R_PLLCFGR_PLLM_SHIFT, R_PLLCFGR_PLLM_LEN= GTH); + clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT], 1, (val= + 1)); + + /* PLLSRC */ + val =3D extract32(s->pllcfgr, R_PLLCFGR_PLLSRC_SHIFT, R_PLLCFGR_PLLSRC= _LENGTH); + if (val =3D=3D 0) { + clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT], fal= se); + } else { + clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT], val= - 1); + clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT], tru= e); + } +} + +static void rcc_update_ccipr(Stm32l4x5RccState *s) +{ + #define CCIPR_SET_SOURCE(_peripheral_name) \ + clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_##_peripheral_n= ame], \ + REGISTER_EXTRACT(s, ccipr, CCIPR, _peripheral_name##SEL)) + + CCIPR_SET_SOURCE(DFSDM1); + CCIPR_SET_SOURCE(SWPMI1); + CCIPR_SET_SOURCE(ADC); + CCIPR_SET_SOURCE(CLK48); + CCIPR_SET_SOURCE(SAI2); + CCIPR_SET_SOURCE(SAI1); + CCIPR_SET_SOURCE(LPTIM2); + CCIPR_SET_SOURCE(LPTIM1); + CCIPR_SET_SOURCE(I2C3); + CCIPR_SET_SOURCE(I2C2); + CCIPR_SET_SOURCE(I2C1); + CCIPR_SET_SOURCE(LPUART1); + CCIPR_SET_SOURCE(UART5); + CCIPR_SET_SOURCE(UART4); + CCIPR_SET_SOURCE(USART3); + CCIPR_SET_SOURCE(USART2); + CCIPR_SET_SOURCE(USART1); + + #undef CCIPR_SET_SOURCE +} + +static void rcc_update_bdcr(Stm32l4x5RccState *s) +{ + int val; + + /* LSCOSEL */ + val =3D extract32(s->bdcr, R_BDCR_LSCOSEL_SHIFT, R_BDCR_LSCOSEL_LENGTH= ); + clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_LSCO], val); + + val =3D extract32(s->bdcr, R_BDCR_LSCOEN_SHIFT, R_BDCR_LSCOEN_LENGTH); + clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_LSCO], val); + + /* BDRST */ + /* + * The documentation is not clear if the RTCEN flag disables the RTC a= nd + * the LCD common mux or if it only affects the RTC. + * As the LCDEN flag exists, we assume here that it only affects the R= TC. + */ + val =3D extract32(s->bdcr, R_BDCR_RTCEN_SHIFT, R_BDCR_RTCEN_SHIFT); + clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_RTC], val); + /* LCD and RTC share the same clock */ + val =3D extract32(s->bdcr, R_BDCR_RTCSEL_SHIFT, R_BDCR_RTCSEL_LENGTH); + clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_LCD_AND_RTC_COMMON]= , val); + + /* LSECSSON */ + /* LSEDRV[1:0] */ + /* LSEBYP */ + + /* LSEON: Update LSERDY at the same time */ + val =3D extract32(s->bdcr, R_BDCR_LSEON_SHIFT, R_BDCR_LSEON_LENGTH); + if (val) { + clock_update_hz(s->lse_crystal, LSE_FRQ); + s->bdcr |=3D R_BDCR_LSERDY_MASK; + if (s->cier & R_CIER_LSERDYIE_MASK) { + s->cifr |=3D R_CIFR_LSERDYF_MASK; + } + } else { + clock_update_hz(s->lse_crystal, 0); + s->bdcr &=3D ~R_BDCR_LSERDY_MASK; + } + + rcc_update_irq(s); +} + +static void rcc_update_csr(Stm32l4x5RccState *s) +{ + int val; + + /* Reset flags: Not implemented */ + /* MSISRANGE: Not implemented after reset */ + + /* LSION: Update LSIRDY at the same time */ + val =3D extract32(s->csr, R_CSR_LSION_SHIFT, R_CSR_LSION_LENGTH); + if (val) { + clock_update_hz(s->lsi_rc, LSI_FRQ); + s->csr |=3D R_CSR_LSIRDY_MASK; + if (s->cier & R_CIER_LSIRDYIE_MASK) { + s->cifr |=3D R_CIFR_LSIRDYF_MASK; + } + } else { + /* + * TODO: Handle when the LSI is set independently of LSION. + * E.g. when the LSI is set by the RTC. + * See the reference manual for more details. + */ + clock_update_hz(s->lsi_rc, 0); + s->csr &=3D ~R_CSR_LSIRDY_MASK; + } + + rcc_update_irq(s); +} + static void stm32l4x5_rcc_reset_hold(Object *obj) { Stm32l4x5RccState *s =3D STM32L4X5_RCC(obj); @@ -472,21 +954,26 @@ static void stm32l4x5_rcc_write(void *opaque, hwaddr = addr, case A_CR: s->cr =3D (s->cr & CR_READ_SET_MASK) | (value & (CR_READ_SET_MASK | ~CR_READ_ONLY_MASK)); + rcc_update_cr_register(s); break; case A_ICSCR: s->icscr =3D value & ~ICSCR_READ_ONLY_MASK; break; case A_CFGR: s->cfgr =3D value & ~CFGR_READ_ONLY_MASK; + rcc_update_cfgr_register(s); break; case A_PLLCFGR: s->pllcfgr =3D value; + rcc_update_pllcfgr(s); break; case A_PLLSAI1CFGR: s->pllsai1cfgr =3D value; + rcc_update_pllsaixcfgr(s, RCC_PLL_PLLSAI1); break; case A_PLLSAI2CFGR: s->pllsai2cfgr =3D value; + rcc_update_pllsaixcfgr(s, RCC_PLL_PLLSAI2); break; case A_CIER: s->cier =3D value; @@ -522,21 +1009,27 @@ static void stm32l4x5_rcc_write(void *opaque, hwaddr= addr, break; case A_AHB1ENR: s->ahb1enr =3D value; + rcc_update_ahb1enr(s); break; case A_AHB2ENR: s->ahb2enr =3D value; + rcc_update_ahb2enr(s); break; case A_AHB3ENR: s->ahb3enr =3D value; + rcc_update_ahb3enr(s); break; case A_APB1ENR1: s->apb1enr1 =3D value; + rcc_update_apb1enr(s); break; case A_APB1ENR2: s->apb1enr2 =3D value; + rcc_update_apb1enr(s); break; case A_APB2ENR: s->apb2enr =3D (s->apb2enr & APB2ENR_READ_SET_MASK) | value; + rcc_update_apb2enr(s); break; /* Behaviors for Sleep and Stop modes are not implemented */ case A_AHB1SMENR: @@ -559,12 +1052,15 @@ static void stm32l4x5_rcc_write(void *opaque, hwaddr= addr, break; case A_CCIPR: s->ccipr =3D value; + rcc_update_ccipr(s); break; case A_BDCR: s->bdcr =3D value & ~BDCR_READ_ONLY_MASK; + rcc_update_bdcr(s); break; case A_CSR: s->csr =3D value & ~CSR_READ_ONLY_MASK; + rcc_update_csr(s); break; default: qemu_log_mask(LOG_GUEST_ERROR, @@ -761,18 +1257,6 @@ static void stm32l4x5_rcc_realize(DeviceState *dev, E= rror **errp) clock_update_hz(s->sai1_extclk, s->sai1_extclk_frequency); clock_update_hz(s->sai2_extclk, s->sai2_extclk_frequency); clock_update(s->gnd, 0); - - /* - * Dummy values to make compilation pass. - * Removed in later commits. - */ - clock_mux_set_source(&s->clock_muxes[0], RCC_CLOCK_MUX_SRC_GND); - clock_mux_set_enable(&s->clock_muxes[0], true); - clock_mux_set_factor(&s->clock_muxes[0], 1, 1); - pll_set_channel_divider(&s->plls[0], 0, 1); - pll_set_enable(&s->plls[0], true); - pll_set_channel_enable(&s->plls[0], 0, true); - pll_set_vco_multiplier(&s->plls[0], 1); } =20 static Property stm32l4x5_rcc_properties[] =3D { --=20 2.34.1 From nobody Tue Nov 26 14:24:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=telecom-paris.fr ARC-Seal: i=1; a=rsa-sha256; t=1706366809; cv=none; d=zohomail.com; s=zohoarc; b=LzMIXeZlfDwMgHI3yvyb1V0u5lUU9/zPdJFdrUxaV6ImTiWEJpjOTnB0MPuO/SBTlLbK+vAoLEvmhBgsADI3oVLea0ZMHMD8Y3CDC5kz8zGheBqt0hyVZbbuwCIQDAYD1RWApvd21xxJjVKrgplLBiBstMJfHf2VE2nyWnzMOy8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1706366809; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=Tdjwc80cb7wxylFsL6gfjDBLjnrq/zojSP8taSqEYRo=; b=KdybTIcxbRbITRbqm3+3LAvsXCZdLqwVd6COxH2kqQZJCpAFeL500SqEcXYSJBd12fylhMRVklS54QwoJao6Voj/5f0KhVvEaKpqMsrq+z1zK7iU3mRUpkFD5B39vFVuSQK1a01CKS7h64AgkyykVhdyrGs4dwQO0aLqOEvQA6w= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1706366809726998.6080571900607; Sat, 27 Jan 2024 06:46:49 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rTjvy-0000Nv-OU; Sat, 27 Jan 2024 09:45:26 -0500 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 1rTjvm-0000Ku-7d; Sat, 27 Jan 2024 09:45:15 -0500 Received: from zproxy4.enst.fr ([2001:660:330f:2::df]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rTjvi-0003bc-Mq; Sat, 27 Jan 2024 09:45:13 -0500 Received: from localhost (localhost [IPv6:::1]) by zproxy4.enst.fr (Postfix) with ESMTP id A4C962080B; Sat, 27 Jan 2024 15:45:07 +0100 (CET) Received: from zproxy4.enst.fr ([IPv6:::1]) by localhost (zproxy4.enst.fr [IPv6:::1]) (amavis, port 10032) with ESMTP id lEjwH1GTQUwN; Sat, 27 Jan 2024 15:45:06 +0100 (CET) Received: from localhost (localhost [IPv6:::1]) by zproxy4.enst.fr (Postfix) with ESMTP id C1B5820794; Sat, 27 Jan 2024 15:45:06 +0100 (CET) Received: from zproxy4.enst.fr ([IPv6:::1]) by localhost (zproxy4.enst.fr [IPv6:::1]) (amavis, port 10026) with ESMTP id d6GE1f3OKDiM; Sat, 27 Jan 2024 15:45:06 +0100 (CET) Received: from AM-Inspiron-3585.numericable.fr (38.162.10.109.rev.sfr.net [109.10.162.38]) by zproxy4.enst.fr (Postfix) with ESMTPSA id 163ED20687; Sat, 27 Jan 2024 15:45:06 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.10.3 zproxy4.enst.fr C1B5820794 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=telecom-paris.fr; s=A35C7578-1106-11E5-A17F-C303FDDA8F2E; t=1706366706; bh=Tdjwc80cb7wxylFsL6gfjDBLjnrq/zojSP8taSqEYRo=; h=From:To:Date:Message-Id:MIME-Version; b=snjFq0uUZSW1K5eHsWZYkhBFTjMOhpnqrnYeaXjcx3o2cwPGIu2lwzHPijo3JkG3t 2JKgYAvc3a5FYWkerwmI0OtIGfZsyj6M9IYY15ijR/Re6B96XFq5L1agWOBVsnbdWp CHfyVIGpiDUO8Bcidn5Ggqi3psG4l1JoL802HMY4= X-Virus-Scanned: amavis at enst.fr From: Arnaud Minier To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, Peter Maydell , Arnaud Minier , =?UTF-8?q?In=C3=A8s=20Varhol?= , =?UTF-8?q?Philipe=20Mathieu-Daud=C3=A9?= , Thomas Huth , Laurent Vivier , Alistair Francis , Paolo Bonzini , Samuel Tardieu Subject: [PATCH v3 6/8] Add write protections to CR register Date: Sat, 27 Jan 2024 15:44:58 +0100 Message-Id: <20240127144500.82071-1-arnaud.minier@telecom-paris.fr> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> References: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2001:660:330f:2::df; envelope-from=arnaud.minier@telecom-paris.fr; helo=zproxy4.enst.fr X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, 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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @telecom-paris.fr) X-ZM-MESSAGEID: 1706366811271100002 Content-Type: text/plain; charset="utf-8" --- hw/misc/stm32l4x5_rcc.c | 164 ++++++++++++++++++++++++++++------------ 1 file changed, 114 insertions(+), 50 deletions(-) diff --git a/hw/misc/stm32l4x5_rcc.c b/hw/misc/stm32l4x5_rcc.c index 1f55662bbd..325b179d10 100644 --- a/hw/misc/stm32l4x5_rcc.c +++ b/hw/misc/stm32l4x5_rcc.c @@ -329,9 +329,47 @@ static void rcc_update_irq(Stm32l4x5RccState *s) } } =20 -static void rcc_update_cr_register(Stm32l4x5RccState *s) +static void rcc_update_msi(Stm32l4x5RccState *s, uint32_t previous_value) +{ + uint32_t val; + + static const uint32_t msirange[] =3D { + 100000, 200000, 400000, 800000, 1000000, 2000000, + 4000000, 8000000, 16000000, 24000000, 32000000, 48000000 + }; + /* MSIRANGE and MSIRGSEL */ + val =3D extract32(s->cr, R_CR_MSIRGSEL_SHIFT, R_CR_MSIRGSEL_LENGTH); + if (val) { + /* MSIRGSEL is set, use the MSIRANGE field */ + val =3D extract32(s->cr, R_CR_MSIRANGE_SHIFT, R_CR_MSIRANGE_LENGTH= ); + } else { + /* MSIRGSEL is not set, use the MSISRANGE field */ + val =3D extract32(s->csr, R_CSR_MSISRANGE_SHIFT, R_CSR_MSISRANGE_L= ENGTH); + } + + if (val < ARRAY_SIZE(msirange)) { + clock_update_hz(s->msi_rc, msirange[val]); + } else { + /* + * There is a hardware write protection if the value is out of bou= nd. + * Restore the previous value. + */ + s->cr =3D (s->cr & ~R_CSR_MSISRANGE_MASK) | + (previous_value & R_CSR_MSISRANGE_MASK); + } +} + +/* + * TODO: Add write-protection for all registers: + * DONE: CR + */ + +static void rcc_update_cr_register(Stm32l4x5RccState *s, uint32_t previous= _value) { int val; + const RccClockMuxSource current_pll_src =3D + CLOCK_MUX_INIT_INFO[RCC_CLOCK_MUX_PLL_INPUT].src_mapping[ + s->clock_muxes[RCC_CLOCK_MUX_PLL_INPUT].src]; =20 /* PLLSAI2ON and update PLLSAI2RDY */ val =3D extract32(s->cr, R_CR_PLLSAI2ON_SHIFT, R_CR_PLLSAI2ON_LENGTH); @@ -351,77 +389,101 @@ static void rcc_update_cr_register(Stm32l4x5RccState= *s) s->cifr |=3D R_CIFR_PLLSAI1RDYF_MASK; } =20 - /* PLLON and update PLLRDY */ + /* + * PLLON and update PLLRDY + * PLLON cannot be reset if the PLL clock is used as the system clock. + */ val =3D extract32(s->cr, R_CR_PLLON_SHIFT, R_CR_PLLON_LENGTH); - pll_set_enable(&s->plls[RCC_PLL_PLL], val); - s->cr =3D (s->cr & ~R_CR_PLLRDY_MASK) | - (val << R_CR_PLLRDY_SHIFT); - if (s->cier & R_CIER_PLLRDYIE_MASK) { - s->cifr |=3D R_CIFR_PLLRDYF_MASK; + if (extract32(s->cfgr, R_CFGR_SWS_SHIFT, R_CFGR_SWS_LENGTH) !=3D 0b11)= { + pll_set_enable(&s->plls[RCC_PLL_PLL], val); + s->cr =3D (s->cr & ~R_CR_PLLRDY_MASK) | + (val << R_CR_PLLRDY_SHIFT); + if (s->cier & R_CIER_PLLRDYIE_MASK) { + s->cifr |=3D R_CIFR_PLLRDYF_MASK; + } + } else { + s->cr |=3D R_CR_PLLON_MASK; } =20 /* CSSON: TODO */ /* HSEBYP: TODO */ =20 - /* HSEON and update HSERDY */ + /* + * HSEON and update HSERDY. + * HSEON cannot be reset if the HSE oscillator is used directly or + * indirectly as the system clock. + */ val =3D extract32(s->cr, R_CR_HSEON_SHIFT, R_CR_HSEON_LENGTH); - s->cr =3D (s->cr & ~R_CR_HSERDY_MASK) | - (val << R_CR_HSERDY_SHIFT); - if (val) { - clock_update_hz(s->hse, s->hse_frequency); - if (s->cier & R_CIER_HSERDYIE_MASK) { - s->cifr |=3D R_CIFR_HSERDYF_MASK; + if (extract32(s->cfgr, R_CFGR_SWS_SHIFT, R_CFGR_SWS_LENGTH) !=3D 0b10 = && + current_pll_src !=3D RCC_CLOCK_MUX_SRC_HSE) { + s->cr =3D (s->cr & ~R_CR_HSERDY_MASK) | + (val << R_CR_HSERDY_SHIFT); + if (val) { + clock_update_hz(s->hse, s->hse_frequency); + if (s->cier & R_CIER_HSERDYIE_MASK) { + s->cifr |=3D R_CIFR_HSERDYF_MASK; + } + } else { + clock_update_hz(s->hse, 0); } } else { - clock_update_hz(s->hse, 0); + s->cr |=3D R_CR_HSEON_MASK; } =20 /* HSIAFS: TODO*/ /* HSIKERON: TODO*/ =20 - /* HSION and update HSIRDY*/ - val =3D extract32(s->cr, R_CR_HSION_SHIFT, R_CR_HSION_LENGTH); - s->cr =3D (s->cr & ~R_CR_HSIRDY_MASK) | - (val << R_CR_HSIRDY_SHIFT); - if (val) { + /* + * HSION and update HSIRDY + * HSION is set by hardware if the HSI16 is used directly + * or indirectly as system clock. + */ + if (extract32(s->cfgr, R_CFGR_SWS_SHIFT, R_CFGR_SWS_LENGTH) =3D=3D 0b0= 1 || + current_pll_src =3D=3D RCC_CLOCK_MUX_SRC_HSI) { + s->cr |=3D (R_CR_HSION_MASK | R_CR_HSIRDY_MASK); clock_update_hz(s->hsi16_rc, HSI_FRQ); if (s->cier & R_CIER_HSIRDYIE_MASK) { s->cifr |=3D R_CIFR_HSIRDYF_MASK; } } else { - clock_update_hz(s->hsi16_rc, 0); + val =3D extract32(s->cr, R_CR_HSION_SHIFT, R_CR_HSION_LENGTH); + if (val) { + clock_update_hz(s->hsi16_rc, HSI_FRQ); + s->cr |=3D R_CR_HSIRDY_MASK; + if (s->cier & R_CIER_HSIRDYIE_MASK) { + s->cifr |=3D R_CIFR_HSIRDYF_MASK; + } + } else { + clock_update_hz(s->hsi16_rc, 0); + s->cr &=3D ~R_CR_HSIRDY_MASK; + } } =20 - static const uint32_t msirange[] =3D { - 100000, 200000, 400000, 800000, 1000000, 2000000, - 4000000, 8000000, 16000000, 24000000, 32000000, 48000000 - }; - /* MSIRANGE and MSIRGSEL */ - val =3D extract32(s->cr, R_CR_MSIRGSEL_SHIFT, R_CR_MSIRGSEL_LENGTH); - if (val) { - /* MSIRGSEL is set, use the MSIRANGE field */ - val =3D extract32(s->cr, R_CR_MSIRANGE_SHIFT, R_CR_MSIRANGE_LENGTH= ); - } else { - /* MSIRGSEL is not set, use the MSISRANGE field */ - val =3D extract32(s->csr, R_CSR_MSISRANGE_SHIFT, R_CSR_MSISRANGE_L= ENGTH); - } + /* MSIPLLEN: TODO */ =20 - if (val < ARRAY_SIZE(msirange)) { - clock_update_hz(s->msi_rc, msirange[val]); + /* + * MSION and update MSIRDY + * Set by hardware when used directly or indirectly as system clock. + */ + if (extract32(s->cfgr, R_CFGR_SWS_SHIFT, R_CFGR_SWS_LENGTH) =3D=3D 0b0= 0 || + current_pll_src =3D=3D RCC_CLOCK_MUX_SRC_MSI) { + s->cr |=3D (R_CR_MSION_MASK | R_CR_MSIRDY_MASK); + if (!(previous_value & R_CR_MSION_MASK) && (s->cier & R_CIER_M= SIRDYIE_MASK)) { + s->cifr |=3D R_CIFR_MSIRDYF_MASK; + } + rcc_update_msi(s, previous_value); } else { - clock_update_hz(s->msi_rc, MSI_DEFAULT_FRQ); - /* TODO: there is a write protection if the value is out of bound, - implement that instead of setting the default */ - } - - /* MSIPLLEN */ - - /* MSION and update MSIRDY */ - val =3D extract32(s->cr, R_CR_MSION_SHIFT, R_CR_MSION_LENGTH); - s->cr =3D (s->cr & ~R_CR_MSIRDY_MASK) | - (val << R_CR_MSIRDY_SHIFT); - if (s->cier & R_CIER_MSIRDYIE_MASK) { - s->cifr |=3D R_CIFR_MSIRDYF_MASK; + val =3D extract32(s->cr, R_CR_MSION_SHIFT, R_CR_MSION_LENGTH); + if (val) { + s->cr |=3D R_CR_MSIRDY_MASK; + rcc_update_msi(s, previous_value); + if (s->cier & R_CIER_MSIRDYIE_MASK) { + s->cifr |=3D R_CIFR_MSIRDYF_MASK; + } + } else { + s->cr &=3D ~R_CR_MSIRDY_MASK; + clock_update_hz(s->msi_rc, 0); + } } rcc_update_irq(s); } @@ -946,15 +1008,17 @@ static void stm32l4x5_rcc_write(void *opaque, hwaddr= addr, uint64_t val64, unsigned int size) { Stm32l4x5RccState *s =3D opaque; + uint32_t previous_value =3D 0; const uint32_t value =3D val64; =20 trace_stm32l4x5_rcc_write(addr, value); =20 switch (addr) { case A_CR: + previous_value =3D s->cr; s->cr =3D (s->cr & CR_READ_SET_MASK) | (value & (CR_READ_SET_MASK | ~CR_READ_ONLY_MASK)); - rcc_update_cr_register(s); + rcc_update_cr_register(s, previous_value); break; case A_ICSCR: s->icscr =3D value & ~ICSCR_READ_ONLY_MASK; --=20 2.34.1 From nobody Tue Nov 26 14:24:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=telecom-paris.fr ARC-Seal: i=1; a=rsa-sha256; t=1706367332; cv=none; d=zohomail.com; s=zohoarc; b=IwUShiapeOzH0I3TV9h+PTFYy4d3GDelJYKZjVzKNi+6O+Kay6KlnwKe7uGkuPw69DVLIlwUQaYLCFTtvvfU01pPrPdZ1shLpvnstGXl9Rw7um2r7zj4qnI5jn2AA9wxH3kpgbw5iRC7hOq/6nnuju7+kaNV6YHN5oiw3Ra+Xs0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1706367332; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=iqvodn8mGiS3d7eM1Ps4AodhRGeWTsf8TD6wnVXNtEA=; b=FBkcIEvwUeIqkRp8J+ZVXO/vtAJM84zL+ny475lE5mf3F8WQa+GlJfSwsV4D7CxECFj3KVxdSlkbl28hmnx80Exg911OhJBBODCjurdw/wIHdQRYIFBTCadbxQkDP+lfHO/LtIzuhvDUlWoScPyOLVVW/2d2yhQtndj/VrMOYBg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1706367332158221.69748100267043; Sat, 27 Jan 2024 06:55:32 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rTk4q-00059w-ST; Sat, 27 Jan 2024 09:54:36 -0500 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 1rTk4p-00059a-8x for qemu-devel@nongnu.org; Sat, 27 Jan 2024 09:54:35 -0500 Received: from zproxy2.enst.fr ([2001:660:330f:2::dd]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rTk4n-00051t-7i for qemu-devel@nongnu.org; Sat, 27 Jan 2024 09:54:35 -0500 Received: from localhost (localhost [IPv6:::1]) by zproxy2.enst.fr (Postfix) with ESMTP id 143DF807BB; Sat, 27 Jan 2024 15:54:30 +0100 (CET) Received: from zproxy2.enst.fr ([IPv6:::1]) by localhost (zproxy2.enst.fr [IPv6:::1]) (amavis, port 10032) with ESMTP id G5rGlfWZPsXp; Sat, 27 Jan 2024 15:54:29 +0100 (CET) Received: from localhost (localhost [IPv6:::1]) by zproxy2.enst.fr (Postfix) with ESMTP id 796E7807B1; Sat, 27 Jan 2024 15:54:29 +0100 (CET) Received: from zproxy2.enst.fr ([IPv6:::1]) by localhost (zproxy2.enst.fr [IPv6:::1]) (amavis, port 10026) with ESMTP id IzNkdyAjdFnj; Sat, 27 Jan 2024 15:54:29 +0100 (CET) Received: from AM-Inspiron-3585.numericable.fr (38.162.10.109.rev.sfr.net [109.10.162.38]) by zproxy2.enst.fr (Postfix) with ESMTPSA id 39E30807AB; Sat, 27 Jan 2024 15:54:29 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.10.3 zproxy2.enst.fr 796E7807B1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=telecom-paris.fr; s=A35C7578-1106-11E5-A17F-C303FDDA8F2E; t=1706367269; bh=iqvodn8mGiS3d7eM1Ps4AodhRGeWTsf8TD6wnVXNtEA=; h=From:To:Date:Message-Id:MIME-Version; b=4/ZrtUhy1hajF7FBG0xkpE3d9sqCEaIuyK6CpT7EFls5azGrdD4QTkJgve4IiXBVr jJ6DJ5+sQtuyeQa9qtvt18A5+azI9qkXZhZGt6kUNiuTbWBrCiAXnAEc42jBicbACM eE2ULo6NlL2tGdLf06VuZoe/qrVVxAV+y9hukK3c= X-Virus-Scanned: amavis at enst.fr From: Arnaud Minier To: qemu-devel@nongnu.org Cc: Arnaud Minier , =?UTF-8?q?In=C3=A8s=20Varhol?= Subject: [PATCH v3 7/8] STM32L4x5: Use the RCC Sysclk Date: Sat, 27 Jan 2024 15:54:23 +0100 Message-Id: <20240127145423.85517-1-arnaud.minier@telecom-paris.fr> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> References: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2001:660:330f:2::dd; envelope-from=arnaud.minier@telecom-paris.fr; helo=zproxy2.enst.fr X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, 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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @telecom-paris.fr) X-ZM-MESSAGEID: 1706367333150100001 Content-Type: text/plain; charset="utf-8" Signed-off-by: Arnaud Minier Signed-off-by: In=C3=A8s Varhol --- hw/arm/b-l475e-iot01a.c | 10 +--------- hw/arm/stm32l4x5_soc.c | 33 ++++----------------------------- include/hw/arm/stm32l4x5_soc.h | 3 --- 3 files changed, 5 insertions(+), 41 deletions(-) diff --git a/hw/arm/b-l475e-iot01a.c b/hw/arm/b-l475e-iot01a.c index 6ecde2db15..d862aa43fc 100644 --- a/hw/arm/b-l475e-iot01a.c +++ b/hw/arm/b-l475e-iot01a.c @@ -26,27 +26,19 @@ #include "qapi/error.h" #include "hw/boards.h" #include "hw/qdev-properties.h" -#include "hw/qdev-clock.h" #include "qemu/error-report.h" #include "hw/arm/stm32l4x5_soc.h" #include "hw/arm/boot.h" =20 -/* Main SYSCLK frequency in Hz (80MHz) */ -#define MAIN_SYSCLK_FREQ_HZ 80000000ULL +/* B-L475E-IOT01A implementation is derived from netduinoplus2 */ =20 static void b_l475e_iot01a_init(MachineState *machine) { const Stm32l4x5SocClass *sc; DeviceState *dev; - Clock *sysclk; - - /* This clock doesn't need migration because it is fixed-frequency */ - sysclk =3D clock_new(OBJECT(machine), "SYSCLK"); - clock_set_hz(sysclk, MAIN_SYSCLK_FREQ_HZ); =20 dev =3D qdev_new(TYPE_STM32L4X5XG_SOC); object_property_add_child(OBJECT(machine), "soc", OBJECT(dev)); - qdev_connect_clock_in(dev, "sysclk", sysclk); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); =20 sc =3D STM32L4X5_SOC_GET_CLASS(dev); diff --git a/hw/arm/stm32l4x5_soc.c b/hw/arm/stm32l4x5_soc.c index 07c841027a..bcdad69e92 100644 --- a/hw/arm/stm32l4x5_soc.c +++ b/hw/arm/stm32l4x5_soc.c @@ -85,9 +85,6 @@ static void stm32l4x5_soc_initfn(Object *obj) object_initialize_child(obj, "exti", &s->exti, TYPE_STM32L4X5_EXTI); object_initialize_child(obj, "syscfg", &s->syscfg, TYPE_STM32L4X5_SYSC= FG); object_initialize_child(obj, "rcc", &s->rcc, TYPE_STM32L4X5_RCC); - - s->sysclk =3D qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0); - s->refclk =3D qdev_init_clock_in(DEVICE(s), "refclk", NULL, NULL, 0); } =20 static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp) @@ -99,30 +96,6 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, = Error **errp) DeviceState *armv7m; SysBusDevice *busdev; =20 - /* - * 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 c= ode"); - 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); - if (!memory_region_init_rom(&s->flash, OBJECT(dev_soc), "flash", sc->flash_size, errp)) { return; @@ -151,8 +124,10 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc= , Error **errp) qdev_prop_set_uint32(armv7m, "num-irq", 96); qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4"= )); qdev_prop_set_bit(armv7m, "enable-bitband", true); - qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk); - qdev_connect_clock_in(armv7m, "refclk", s->refclk); + qdev_connect_clock_in(armv7m, "cpuclk", + qdev_get_clock_out(DEVICE(&(s->rcc)), "cortex-fclk-out")); + qdev_connect_clock_in(armv7m, "refclk", + qdev_get_clock_out(DEVICE(&(s->rcc)), "cortex-refclk-out")); object_property_set_link(OBJECT(&s->armv7m), "memory", OBJECT(system_memory), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) { diff --git a/include/hw/arm/stm32l4x5_soc.h b/include/hw/arm/stm32l4x5_soc.h index e480fcc976..1f71298b45 100644 --- a/include/hw/arm/stm32l4x5_soc.h +++ b/include/hw/arm/stm32l4x5_soc.h @@ -50,9 +50,6 @@ struct Stm32l4x5SocState { MemoryRegion sram2; MemoryRegion flash; MemoryRegion flash_alias; - - Clock *sysclk; - Clock *refclk; }; =20 struct Stm32l4x5SocClass { --=20 2.34.1 From nobody Tue Nov 26 14:24:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=telecom-paris.fr ARC-Seal: i=1; a=rsa-sha256; t=1706367904; cv=none; d=zohomail.com; s=zohoarc; b=Xlx6yaCrYJMVWGaPIq2Ps/vr/DyjTkqVHocLUFTRvTeXYqjLfvf1E6qVor9ENUdCLugQphH4RiZ5Y8tI107GjsEoBnsJBWMCGRE3mp9iG0e0YjqXXdrhtxwv/paeYgtpcyas3ZWD7VsqbV0QBFFUo3pwvAzSvFuTADJHdShkmo4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1706367904; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=mu2hOZHGN/vGpbFAHGGJCR5uM2pD7VU1oJyamH60faQ=; b=PnhJbg65ZFqu1au+/sRWE8maBs6NeI83HJpHhYCgCIvEEmwEL6KPjOZfKvfDMvZx7lQQZtg+HvsrPNaRQBqbyi1234qT60mOftDtV+EztJG7b/sWUsjvvFf5BUu1kChbI2j9n60zyqX3UiUnEAy/Idq93fVDt9cTXPyg62vHbYA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1706367904518236.09831737995273; Sat, 27 Jan 2024 07:05:04 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rTkEI-0008U0-5H; Sat, 27 Jan 2024 10:04:22 -0500 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 1rTkEB-0008Tm-37 for qemu-devel@nongnu.org; Sat, 27 Jan 2024 10:04:17 -0500 Received: from zproxy1.enst.fr ([2001:660:330f:2::dc]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rTkE6-0006ml-I9 for qemu-devel@nongnu.org; Sat, 27 Jan 2024 10:04:14 -0500 Received: from localhost (localhost [IPv6:::1]) by zproxy1.enst.fr (Postfix) with ESMTP id 6E35AC0DEB; Sat, 27 Jan 2024 16:04:07 +0100 (CET) Received: from zproxy1.enst.fr ([IPv6:::1]) by localhost (zproxy1.enst.fr [IPv6:::1]) (amavis, port 10032) with ESMTP id dFmJZw_k2QaA; Sat, 27 Jan 2024 16:04:06 +0100 (CET) Received: from localhost (localhost [IPv6:::1]) by zproxy1.enst.fr (Postfix) with ESMTP id DB86BC0D78; Sat, 27 Jan 2024 16:04:06 +0100 (CET) Received: from zproxy1.enst.fr ([IPv6:::1]) by localhost (zproxy1.enst.fr [IPv6:::1]) (amavis, port 10026) with ESMTP id TF6jW0aNGpRz; Sat, 27 Jan 2024 16:04:06 +0100 (CET) Received: from AM-Inspiron-3585.numericable.fr (38.162.10.109.rev.sfr.net [109.10.162.38]) by zproxy1.enst.fr (Postfix) with ESMTPSA id A83E1C0D73; Sat, 27 Jan 2024 16:04:06 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.10.3 zproxy1.enst.fr DB86BC0D78 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=telecom-paris.fr; s=A35C7578-1106-11E5-A17F-C303FDDA8F2E; t=1706367846; bh=mu2hOZHGN/vGpbFAHGGJCR5uM2pD7VU1oJyamH60faQ=; h=From:To:Date:Message-Id:MIME-Version; b=a+i3aJxhOELtGk0x/tAO698O5n9+AZ7LdqPEoCo623iJp/pO1rV323maADn33cRKT v5Xpa8WX29FuarDHVb+PWvrjeArRRMb9HQd2lHfQ89DbF38NfnXM+RVICLajzevw9A iaj/PM8c8oi6IJTiK5UWAlM+JSOTQB+aNgtY1bJ8= X-Virus-Scanned: amavis at enst.fr From: Arnaud Minier To: qemu-devel@nongnu.org Cc: Arnaud Minier , =?UTF-8?q?In=C3=A8s=20Varhol?= Subject: [PATCH v3 8/8] Add tests for the STM32L4x5_RCC Date: Sat, 27 Jan 2024 16:03:58 +0100 Message-Id: <20240127150358.87082-1-arnaud.minier@telecom-paris.fr> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> References: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2001:660:330f:2::dc; envelope-from=arnaud.minier@telecom-paris.fr; helo=zproxy1.enst.fr X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, 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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @telecom-paris.fr) X-ZM-MESSAGEID: 1706367906454100003 Content-Type: text/plain; charset="utf-8" Again, troubles with my mail formatting. Sorry for the multiple mails of this patch you may have received. Tests: - the ability to change the sysclk of the device - the ability to enable/disable/configure the PLLs - if the clock multiplexers work - the register flags and the generation of irqs Signed-off-by: Arnaud Minier Signed-off-by: In=C3=A8s Varhol --- tests/qtest/meson.build | 3 +- tests/qtest/stm32l4x5_rcc-test.c | 207 +++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 tests/qtest/stm32l4x5_rcc-test.c diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index a926af92f6..b0d9a8c2de 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -197,7 +197,8 @@ qtests_aspeed =3D \ =20 qtests_stm32l4x5 =3D \ ['stm32l4x5_exti-test', - 'stm32l4x5_syscfg-test'] + 'stm32l4x5_syscfg-test', + 'stm32l4x5_rcc-test'] =20 qtests_arm =3D \ (config_all_devices.has_key('CONFIG_MPS2') ? ['sse-timer-test'] : []) + \ diff --git a/tests/qtest/stm32l4x5_rcc-test.c b/tests/qtest/stm32l4x5_rcc-t= est.c new file mode 100644 index 0000000000..4157291052 --- /dev/null +++ b/tests/qtest/stm32l4x5_rcc-test.c @@ -0,0 +1,207 @@ +/* + * QTest testcase for STM32L4x5_RCC + * + * Copyright (c) 2023 Arnaud Minier + * Copyright (c) 2023 In=C3=A8s Varhol + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/registerfields.h" +#include "libqtest-single.h" +#include "hw/misc/stm32l4x5_rcc_internals.h" + +#define RCC_BASE_ADDR 0x40021000 +#define NVIC_ISER 0xE000E100 +#define NVIC_ISPR 0xE000E200 +#define NVIC_ICPR 0xE000E280 +#define RCC_IRQ 5 + +static void enable_nvic_irq(unsigned int n) +{ + writel(NVIC_ISER, 1 << n); +} + +static void unpend_nvic_irq(unsigned int n) +{ + writel(NVIC_ICPR, 1 << n); +} + +static bool check_nvic_pending(unsigned int n) +{ + return readl(NVIC_ISPR) & (1 << n); +} + +static bool qts_wait_for_flag(QTestState *qts, uint32_t event_addr, + uint32_t flag, uint32_t value) +{ + /* Wait at most 5 seconds */ + for (int i =3D 0; i < 5000; i++) { + if ((qtest_readl(qts, event_addr) & flag) =3D=3D value) { + return true; + } + g_usleep(1000); + } + + return false; +} + +static bool rcc_wait_for_flag(uint32_t event_addr, uint32_t flag, + uint32_t value) +{ + return qts_wait_for_flag(global_qtest, RCC_BASE_ADDR + event_addr, fla= g, value); +} + +static void rcc_writel(unsigned int offset, uint32_t value) +{ + writel(RCC_BASE_ADDR + offset, value); +} + +static uint32_t rcc_readl(unsigned int offset) +{ + return readl(RCC_BASE_ADDR + offset); +} + +static void test_init_msi(void) +{ + /* MSIRANGE can be set only when MSI is OFF or READY */ + rcc_writel(A_CR, R_CR_MSION_MASK); + /* Wait until MSI is stable */ + g_assert_true(rcc_wait_for_flag(A_CR, R_CR_MSIRDY_MASK, R_CR_MSIRDY_MA= SK)); + /* TODO find a way to test MSI value */ +} + +static void test_set_msi_as_sysclk(void) +{ + /* Clocking from MSI, in case MSI was not the default source */ + rcc_writel(A_CFGR, 0); + /* Wait until MSI is selected and stable */ + g_assert_true(rcc_wait_for_flag(A_CFGR, R_CFGR_SWS_MASK, 0)); +} + +static void test_init_pll(void) +{ + uint32_t value; + + /* + * Update PLL and set MSI as the source clock. + * PLLM =3D 1 --> 000 + * PLLN =3D 40 --> 40 + * PPLLR =3D 2 --> 00 + * PLLDIV =3D unused, PLLP =3D unused (SAI3), PLLQ =3D unused (48M1) + * SRC =3D MSI --> 01 + */ + rcc_writel(A_PLLCFGR, R_PLLCFGR_PLLREN_MASK | + (40 << R_PLLCFGR_PLLN_SHIFT) | + (0b01 << R_PLLCFGR_PLLSRC_SHIFT)); + + /* PLL activation */ + value =3D rcc_readl(A_CR); + rcc_writel(A_CR, value | R_CR_PLLON_MASK); + + /* Waiting for PLL lock. */ + g_assert_true(rcc_wait_for_flag(A_CR, R_CR_PLLRDY_MASK, R_CR_PLLRDY_MA= SK)); + + /* Switches on the PLL clock source */ + value =3D rcc_readl(A_CFGR); + rcc_writel(A_CFGR, (value & ~R_CFGR_SW_MASK) | + (0b11 << R_CFGR_SW_SHIFT)); + + /* Wait until SYSCLK is stable. */ + g_assert_true(rcc_wait_for_flag(A_CFGR, R_CFGR_SWS_MASK, + (0b11 << R_CFGR_SWS_SHIFT))); +} + +static void test_activate_lse(void) +{ + /* LSE activation, no LSE Bypass */ + rcc_writel(A_BDCR, R_BDCR_LSEDRV_MASK | R_BDCR_LSEON_MASK); + g_assert_true(rcc_wait_for_flag(A_BDCR, R_BDCR_LSERDY_MASK, R_BDCR_LSE= RDY_MASK)); +} + +static void test_irq(void) +{ + enable_nvic_irq(RCC_IRQ); + + rcc_writel(A_CIER, R_CIER_LSIRDYIE_MASK); + rcc_writel(A_CSR, R_CSR_LSION_MASK); + g_assert_true(check_nvic_pending(RCC_IRQ)); + rcc_writel(A_CICR, R_CICR_LSIRDYC_MASK); + unpend_nvic_irq(RCC_IRQ); + + rcc_writel(A_CIER, R_CIER_LSERDYIE_MASK); + rcc_writel(A_BDCR, R_BDCR_LSEON_MASK); + g_assert_true(check_nvic_pending(RCC_IRQ)); + rcc_writel(A_CICR, R_CICR_LSERDYC_MASK); + unpend_nvic_irq(RCC_IRQ); + + /* + * MSI has been enabled by previous tests, + * shouln't generate an interruption. + */ + rcc_writel(A_CIER, R_CIER_MSIRDYIE_MASK); + rcc_writel(A_CR, R_CR_MSION_MASK); + g_assert_false(check_nvic_pending(RCC_IRQ)); + + rcc_writel(A_CIER, R_CIER_HSIRDYIE_MASK); + rcc_writel(A_CR, R_CR_HSION_MASK); + g_assert_true(check_nvic_pending(RCC_IRQ)); + rcc_writel(A_CICR, R_CICR_HSIRDYC_MASK); + unpend_nvic_irq(RCC_IRQ); + + rcc_writel(A_CIER, R_CIER_HSERDYIE_MASK); + rcc_writel(A_CR, R_CR_HSEON_MASK); + g_assert_true(check_nvic_pending(RCC_IRQ)); + rcc_writel(A_CICR, R_CICR_HSERDYC_MASK); + unpend_nvic_irq(RCC_IRQ); + + /* + * PLL has been enabled by previous tests, + * shouln't generate an interruption. + */ + rcc_writel(A_CIER, R_CIER_PLLRDYIE_MASK); + rcc_writel(A_CR, R_CR_PLLON_MASK); + g_assert_false(check_nvic_pending(RCC_IRQ)); + + rcc_writel(A_CIER, R_CIER_PLLSAI1RDYIE_MASK); + rcc_writel(A_CR, R_CR_PLLSAI1ON_MASK); + g_assert_true(check_nvic_pending(RCC_IRQ)); + rcc_writel(A_CICR, R_CICR_PLLSAI1RDYC_MASK); + unpend_nvic_irq(RCC_IRQ); + + rcc_writel(A_CIER, R_CIER_PLLSAI2RDYIE_MASK); + rcc_writel(A_CR, R_CR_PLLSAI2ON_MASK); + g_assert_true(check_nvic_pending(RCC_IRQ)); + rcc_writel(A_CICR, R_CICR_PLLSAI2RDYC_MASK); + unpend_nvic_irq(RCC_IRQ); +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + g_test_set_nonfatal_assertions(); + /* + * These test separately that we can enable the plls, change the syscl= k, + * and enable different devices. + * They are dependent on one another. + */ + qtest_add_func("stm32l4x5/rcc/init_msi", test_init_msi); + qtest_add_func("stm32l4x5/rcc/set_msi_as_sysclk", + test_set_msi_as_sysclk); + qtest_add_func("stm32l4x5/rcc/activate_lse", test_activate_lse); + qtest_add_func("stm32l4x5/rcc/init_pll", test_init_pll); + + qtest_add_func("stm32l4x5/rcc/irq", test_irq); + + qtest_start("-machine b-l475e-iot01a"); + ret =3D g_test_run(); + qtest_end(); + + return ret; +} --=20 2.34.1 From nobody Tue Nov 26 14:24:06 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=telecom-paris.fr ARC-Seal: i=1; a=rsa-sha256; t=1706367556; cv=none; d=zohomail.com; s=zohoarc; b=XnBKzGlgU+x9PLMUvGFLrIpj/PauT4825gMccOkPX4Sbmf006esb/QfaPnPpVjU5yUJfWulIlIuXdq01p47Vk27Dq7u2m70aQ8asfYQkbyVPk25mmKwBtBvwEtJS8gbFd/1MS8Nkm6CGErZQFkd0L1SgsaP364yPey9pj0Zjh2A= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1706367556; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=W4n5gdp+iP9OHsgLa+0BC0jp84G8pI/kA5BJVllwXKU=; b=P+xGJ1HwKRh/PYuhFHK9zL+SOqSi2Pdg8eUksLgGab7l7Bp+pNtfPoXJQG5ZWBPawNhaMTZW9sI/CbhwFpLurQHkDtz3jmRyUx8Q/hSJc6NUliJBlm9OkytiNjyzfgx/CDwaC/RofoRjp4p3pePCyBmiatja5nFajnrYiFIG+fM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 170636755608548.89082773151438; Sat, 27 Jan 2024 06:59:16 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rTk98-0006M9-1I; Sat, 27 Jan 2024 09:59:02 -0500 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 1rTk96-0006M1-Ps for qemu-devel@nongnu.org; Sat, 27 Jan 2024 09:59:00 -0500 Received: from zproxy2.enst.fr ([2001:660:330f:2::dd]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rTk94-0005xR-Ow for qemu-devel@nongnu.org; Sat, 27 Jan 2024 09:59:00 -0500 Received: from localhost (localhost [IPv6:::1]) by zproxy2.enst.fr (Postfix) with ESMTP id AA082807B9; Sat, 27 Jan 2024 15:58:57 +0100 (CET) Received: from zproxy2.enst.fr ([IPv6:::1]) by localhost (zproxy2.enst.fr [IPv6:::1]) (amavis, port 10032) with ESMTP id bTgKRSuyWE_e; Sat, 27 Jan 2024 15:58:57 +0100 (CET) Received: from localhost (localhost [IPv6:::1]) by zproxy2.enst.fr (Postfix) with ESMTP id ECE8480780; Sat, 27 Jan 2024 15:58:56 +0100 (CET) Received: from zproxy2.enst.fr ([IPv6:::1]) by localhost (zproxy2.enst.fr [IPv6:::1]) (amavis, port 10026) with ESMTP id QgT5o-tZCJbN; Sat, 27 Jan 2024 15:58:56 +0100 (CET) Received: from AM-Inspiron-3585.numericable.fr (38.162.10.109.rev.sfr.net [109.10.162.38]) by zproxy2.enst.fr (Postfix) with ESMTPSA id 82F328078B; Sat, 27 Jan 2024 15:58:56 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.10.3 zproxy2.enst.fr ECE8480780 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=telecom-paris.fr; s=A35C7578-1106-11E5-A17F-C303FDDA8F2E; t=1706367537; bh=W4n5gdp+iP9OHsgLa+0BC0jp84G8pI/kA5BJVllwXKU=; h=From:To:Date:Message-Id:MIME-Version; b=pgNLnjN5hyccrotZempRVpQsmX8i0WnElJLTb1+Kn/xxm4jvcepYPTh29jWf8PgNH wR/xfHAoXYVTnIubb9O6SVPiWZA9xtxRJFSY/m+2mxIqmEerUSJgndpceCpXHp2FRW jZUCmTIME5gawcSjY4X+wWuF8E48XHAMtjp3Tw3c= X-Virus-Scanned: amavis at enst.fr From: Arnaud Minier To: qemu-devel@nongnu.org Cc: Arnaud Minier , =?UTF-8?q?In=C3=A8s=20Varhol?= Subject: [PATCH v3] Add tests for the STM32L4x5_RCC Date: Sat, 27 Jan 2024 15:58:50 +0100 Message-Id: <20240127145850.86209-1-arnaud.minier@telecom-paris.fr> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> References: <20240127143904.80187-1-arnaud.minier@telecom-paris.fr> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2001:660:330f:2::dd; envelope-from=arnaud.minier@telecom-paris.fr; helo=zproxy2.enst.fr X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, 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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @telecom-paris.fr) X-ZM-MESSAGEID: 1706367557185100003 Content-Type: text/plain; charset="utf-8" Tests: - the ability to change the sysclk of the device - the ability to enable/disable/configure the PLLs - if the clock multiplexers work - the register flags and the generation of irqs Signed-off-by: Arnaud Minier Signed-off-by: In=C3=A8s Varhol --- tests/qtest/meson.build | 3 +- tests/qtest/stm32l4x5_rcc-test.c | 207 +++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 tests/qtest/stm32l4x5_rcc-test.c diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index a926af92f6..b0d9a8c2de 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -197,7 +197,8 @@ qtests_aspeed =3D \ =20 qtests_stm32l4x5 =3D \ ['stm32l4x5_exti-test', - 'stm32l4x5_syscfg-test'] + 'stm32l4x5_syscfg-test', + 'stm32l4x5_rcc-test'] =20 qtests_arm =3D \ (config_all_devices.has_key('CONFIG_MPS2') ? ['sse-timer-test'] : []) + \ diff --git a/tests/qtest/stm32l4x5_rcc-test.c b/tests/qtest/stm32l4x5_rcc-t= est.c new file mode 100644 index 0000000000..4157291052 --- /dev/null +++ b/tests/qtest/stm32l4x5_rcc-test.c @@ -0,0 +1,207 @@ +/* + * QTest testcase for STM32L4x5_RCC + * + * Copyright (c) 2023 Arnaud Minier + * Copyright (c) 2023 In=C3=A8s Varhol + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/registerfields.h" +#include "libqtest-single.h" +#include "hw/misc/stm32l4x5_rcc_internals.h" + +#define RCC_BASE_ADDR 0x40021000 +#define NVIC_ISER 0xE000E100 +#define NVIC_ISPR 0xE000E200 +#define NVIC_ICPR 0xE000E280 +#define RCC_IRQ 5 + +static void enable_nvic_irq(unsigned int n) +{ + writel(NVIC_ISER, 1 << n); +} + +static void unpend_nvic_irq(unsigned int n) +{ + writel(NVIC_ICPR, 1 << n); +} + +static bool check_nvic_pending(unsigned int n) +{ + return readl(NVIC_ISPR) & (1 << n); +} + +static bool qts_wait_for_flag(QTestState *qts, uint32_t event_addr, + uint32_t flag, uint32_t value) +{ + /* Wait at most 5 seconds */ + for (int i =3D 0; i < 5000; i++) { + if ((qtest_readl(qts, event_addr) & flag) =3D=3D value) { + return true; + } + g_usleep(1000); + } + + return false; +} + +static bool rcc_wait_for_flag(uint32_t event_addr, uint32_t flag, + uint32_t value) +{ + return qts_wait_for_flag(global_qtest, RCC_BASE_ADDR + event_addr, fla= g, value); +} + +static void rcc_writel(unsigned int offset, uint32_t value) +{ + writel(RCC_BASE_ADDR + offset, value); +} + +static uint32_t rcc_readl(unsigned int offset) +{ + return readl(RCC_BASE_ADDR + offset); +} + +static void test_init_msi(void) +{ + /* MSIRANGE can be set only when MSI is OFF or READY */ + rcc_writel(A_CR, R_CR_MSION_MASK); + /* Wait until MSI is stable */ + g_assert_true(rcc_wait_for_flag(A_CR, R_CR_MSIRDY_MASK, R_CR_MSIRDY_MA= SK)); + /* TODO find a way to test MSI value */ +} + +static void test_set_msi_as_sysclk(void) +{ + /* Clocking from MSI, in case MSI was not the default source */ + rcc_writel(A_CFGR, 0); + /* Wait until MSI is selected and stable */ + g_assert_true(rcc_wait_for_flag(A_CFGR, R_CFGR_SWS_MASK, 0)); +} + +static void test_init_pll(void) +{ + uint32_t value; + + /* + * Update PLL and set MSI as the source clock. + * PLLM =3D 1 --> 000 + * PLLN =3D 40 --> 40 + * PPLLR =3D 2 --> 00 + * PLLDIV =3D unused, PLLP =3D unused (SAI3), PLLQ =3D unused (48M1) + * SRC =3D MSI --> 01 + */ + rcc_writel(A_PLLCFGR, R_PLLCFGR_PLLREN_MASK | + (40 << R_PLLCFGR_PLLN_SHIFT) | + (0b01 << R_PLLCFGR_PLLSRC_SHIFT)); + + /* PLL activation */ + value =3D rcc_readl(A_CR); + rcc_writel(A_CR, value | R_CR_PLLON_MASK); + + /* Waiting for PLL lock. */ + g_assert_true(rcc_wait_for_flag(A_CR, R_CR_PLLRDY_MASK, R_CR_PLLRDY_MA= SK)); + + /* Switches on the PLL clock source */ + value =3D rcc_readl(A_CFGR); + rcc_writel(A_CFGR, (value & ~R_CFGR_SW_MASK) | + (0b11 << R_CFGR_SW_SHIFT)); + + /* Wait until SYSCLK is stable. */ + g_assert_true(rcc_wait_for_flag(A_CFGR, R_CFGR_SWS_MASK, + (0b11 << R_CFGR_SWS_SHIFT))); +} + +static void test_activate_lse(void) +{ + /* LSE activation, no LSE Bypass */ + rcc_writel(A_BDCR, R_BDCR_LSEDRV_MASK | R_BDCR_LSEON_MASK); + g_assert_true(rcc_wait_for_flag(A_BDCR, R_BDCR_LSERDY_MASK, R_BDCR_LSE= RDY_MASK)); +} + +static void test_irq(void) +{ + enable_nvic_irq(RCC_IRQ); + + rcc_writel(A_CIER, R_CIER_LSIRDYIE_MASK); + rcc_writel(A_CSR, R_CSR_LSION_MASK); + g_assert_true(check_nvic_pending(RCC_IRQ)); + rcc_writel(A_CICR, R_CICR_LSIRDYC_MASK); + unpend_nvic_irq(RCC_IRQ); + + rcc_writel(A_CIER, R_CIER_LSERDYIE_MASK); + rcc_writel(A_BDCR, R_BDCR_LSEON_MASK); + g_assert_true(check_nvic_pending(RCC_IRQ)); + rcc_writel(A_CICR, R_CICR_LSERDYC_MASK); + unpend_nvic_irq(RCC_IRQ); + + /* + * MSI has been enabled by previous tests, + * shouln't generate an interruption. + */ + rcc_writel(A_CIER, R_CIER_MSIRDYIE_MASK); + rcc_writel(A_CR, R_CR_MSION_MASK); + g_assert_false(check_nvic_pending(RCC_IRQ)); + + rcc_writel(A_CIER, R_CIER_HSIRDYIE_MASK); + rcc_writel(A_CR, R_CR_HSION_MASK); + g_assert_true(check_nvic_pending(RCC_IRQ)); + rcc_writel(A_CICR, R_CICR_HSIRDYC_MASK); + unpend_nvic_irq(RCC_IRQ); + + rcc_writel(A_CIER, R_CIER_HSERDYIE_MASK); + rcc_writel(A_CR, R_CR_HSEON_MASK); + g_assert_true(check_nvic_pending(RCC_IRQ)); + rcc_writel(A_CICR, R_CICR_HSERDYC_MASK); + unpend_nvic_irq(RCC_IRQ); + + /* + * PLL has been enabled by previous tests, + * shouln't generate an interruption. + */ + rcc_writel(A_CIER, R_CIER_PLLRDYIE_MASK); + rcc_writel(A_CR, R_CR_PLLON_MASK); + g_assert_false(check_nvic_pending(RCC_IRQ)); + + rcc_writel(A_CIER, R_CIER_PLLSAI1RDYIE_MASK); + rcc_writel(A_CR, R_CR_PLLSAI1ON_MASK); + g_assert_true(check_nvic_pending(RCC_IRQ)); + rcc_writel(A_CICR, R_CICR_PLLSAI1RDYC_MASK); + unpend_nvic_irq(RCC_IRQ); + + rcc_writel(A_CIER, R_CIER_PLLSAI2RDYIE_MASK); + rcc_writel(A_CR, R_CR_PLLSAI2ON_MASK); + g_assert_true(check_nvic_pending(RCC_IRQ)); + rcc_writel(A_CICR, R_CICR_PLLSAI2RDYC_MASK); + unpend_nvic_irq(RCC_IRQ); +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + g_test_set_nonfatal_assertions(); + /* + * These test separately that we can enable the plls, change the syscl= k, + * and enable different devices. + * They are dependent on one another. + */ + qtest_add_func("stm32l4x5/rcc/init_msi", test_init_msi); + qtest_add_func("stm32l4x5/rcc/set_msi_as_sysclk", + test_set_msi_as_sysclk); + qtest_add_func("stm32l4x5/rcc/activate_lse", test_activate_lse); + qtest_add_func("stm32l4x5/rcc/init_pll", test_init_pll); + + qtest_add_func("stm32l4x5/rcc/irq", test_irq); + + qtest_start("-machine b-l475e-iot01a"); + ret =3D g_test_run(); + qtest_end(); + + return ret; +} --=20 2.34.1