diff mbox series

[4/4] tests/qtest: Check STM32L4x5 clock connections

Message ID 20240505140556.373711-5-ines.varhol@telecom-paris.fr
State New
Headers show
Series Check clock connection between STM32L4x5 RCC and peripherals | expand

Commit Message

Inès Varhol May 5, 2024, 2:05 p.m. UTC
For USART, GPIO and SYSCFG devices, check that clock frequency before
and after enabling the peripheral clock in RCC is correct.

Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
---
Hello,

Should these tests be regrouped in stm32l4x5_rcc-test.c ?

Best regards,

Inès Varhol

 tests/qtest/stm32l4x5_gpio-test.c   | 39 +++++++++++++++++++++++
 tests/qtest/stm32l4x5_syscfg-test.c | 38 +++++++++++++++++++++--
 tests/qtest/stm32l4x5_usart-test.c  | 48 +++++++++++++++++++++++++++++
 3 files changed, 123 insertions(+), 2 deletions(-)

Comments

Thomas Huth May 6, 2024, 4:16 a.m. UTC | #1
On 05/05/2024 16.05, Inès Varhol wrote:
> For USART, GPIO and SYSCFG devices, check that clock frequency before
> and after enabling the peripheral clock in RCC is correct.
> 
> Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
> ---
> Hello,
> 
> Should these tests be regrouped in stm32l4x5_rcc-test.c ?

  Hi,

sounds mostly like a matter of taste at a first glance. Or what would be the 
benefit of putting everything into the *rcc-test.c file? Could you maybe 
consolidate the get_clock_freq_hz() function that way? (maybe that 
get_clock_freq_hz() function could also be consolidated as a inline function 
in a shared header instead?)

  Thomas
Inès Varhol May 6, 2024, 5:57 p.m. UTC | #2
----- Le 6 Mai 24, à 6:16, Thomas Huth thuth@redhat.com a écrit :

> On 05/05/2024 16.05, Inès Varhol wrote:
>> For USART, GPIO and SYSCFG devices, check that clock frequency before
>> and after enabling the peripheral clock in RCC is correct.
>> 
>> Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
>> ---
>> Hello,
>> 
>> Should these tests be regrouped in stm32l4x5_rcc-test.c ?
> 
>  Hi,
> 
> sounds mostly like a matter of taste at a first glance. Or what would be the
> benefit of putting everything into the *rcc-test.c file? Could you maybe
> consolidate the get_clock_freq_hz() function that way? (maybe that
> get_clock_freq_hz() function could also be consolidated as a inline function
> in a shared header instead?)
> 
>  Thomas

Hello,

I was indeed looking to consolidate the functions get_clock_freq_hz() and
check_clock() from *usart-test.c (along with the definitions for RCC
registers).
Thank you for your suggestion, I'll use a header file.

Inès Varhol
diff mbox series

Patch

diff --git a/tests/qtest/stm32l4x5_gpio-test.c b/tests/qtest/stm32l4x5_gpio-test.c
index 72a7823406..896c16ad59 100644
--- a/tests/qtest/stm32l4x5_gpio-test.c
+++ b/tests/qtest/stm32l4x5_gpio-test.c
@@ -25,6 +25,14 @@ 
 #define GPIO_G 0x48001800
 #define GPIO_H 0x48001C00
 
+/*
+ * MSI (4 MHz) is used as system clock source after startup
+ * from Reset.
+ * AHB prescaler is set to 1 at reset.
+ */
+#define SYSCLK_FREQ_HZ 4000000
+#define RCC_AHB2ENR 0x4002104C
+
 #define MODER 0x00
 #define OTYPER 0x04
 #define PUPDR 0x0C
@@ -168,6 +176,21 @@  static uint32_t reset(uint32_t gpio, unsigned int offset)
     return 0x0;
 }
 
+static uint32_t get_clock_freq_hz(unsigned int gpio)
+{
+    g_autofree char *path = g_strdup_printf("/machine/soc/gpio%c",
+                                            get_gpio_id(gpio) + 'a');
+    uint32_t clock_freq_hz = 0;
+    QDict *r;
+
+    r = qtest_qmp(global_qtest, "{ 'execute': 'qom-get', 'arguments':"
+        " { 'path': %s, 'property': 'clock-freq-hz'} }", path);
+    g_assert_false(qdict_haskey(r, "error"));
+    clock_freq_hz = qdict_get_int(r, "return");
+    qobject_unref(r);
+    return clock_freq_hz;
+}
+
 static void system_reset(void)
 {
     QDict *r;
@@ -505,6 +528,20 @@  static void test_bsrr_brr(const void *data)
     gpio_writel(gpio, ODR, reset(gpio, ODR));
 }
 
+static void test_clock_enable(void)
+{
+    /*
+     * For each GPIO, enable its clock in RCC
+     * and check that its clock frequency changes to SYSCLK_FREQ_HZ
+     */
+    for (uint32_t gpio = GPIO_A; gpio <= GPIO_H; gpio += GPIO_B - GPIO_A) {
+        g_assert_cmpuint(get_clock_freq_hz(gpio), ==, 0);
+        /* Enable the gpio clock */
+        writel(RCC_AHB2ENR, readl(RCC_AHB2ENR) | (0x1 << get_gpio_id(gpio)));
+        g_assert_cmpuint(get_clock_freq_hz(gpio), ==, SYSCLK_FREQ_HZ);
+    }
+}
+
 int main(int argc, char **argv)
 {
     int ret;
@@ -556,6 +593,8 @@  int main(int argc, char **argv)
     qtest_add_data_func("stm32l4x5/gpio/test_bsrr_brr2",
                         test_data(GPIO_D, 0),
                         test_bsrr_brr);
+    qtest_add_func("stm32l4x5/gpio/test_clock_enable",
+                   test_clock_enable);
 
     qtest_start("-machine b-l475e-iot01a");
     ret = g_test_run();
diff --git a/tests/qtest/stm32l4x5_syscfg-test.c b/tests/qtest/stm32l4x5_syscfg-test.c
index 506ca08bc2..616106460d 100644
--- a/tests/qtest/stm32l4x5_syscfg-test.c
+++ b/tests/qtest/stm32l4x5_syscfg-test.c
@@ -26,9 +26,18 @@ 
 #define INVALID_ADDR 0x2C
 
 /* SoC forwards GPIOs to SysCfg */
-#define SYSCFG "/machine/soc"
+#define SOC "/machine/soc"
+#define SYSCFG "/machine/soc/syscfg"
 #define EXTI "/machine/soc/exti"
 
+/*
+ * MSI (4 MHz) is used as system clock source after startup
+ * from Reset.
+ * AHB and APB2 prescalers are set to 1 at reset.
+ */
+#define SYSCLK_FREQ_HZ 4000000
+#define RCC_APB2ENR 0x40021060
+
 static void syscfg_writel(unsigned int offset, uint32_t value)
 {
     writel(SYSCFG_BASE_ADDR + offset, value);
@@ -41,7 +50,7 @@  static uint32_t syscfg_readl(unsigned int offset)
 
 static void syscfg_set_irq(int num, int level)
 {
-   qtest_set_irq_in(global_qtest, SYSCFG, NULL, num, level);
+   qtest_set_irq_in(global_qtest, SOC, NULL, num, level);
 }
 
 static void system_reset(void)
@@ -52,6 +61,19 @@  static void system_reset(void)
     qobject_unref(response);
 }
 
+static uint32_t get_clock_freq_hz()
+{
+    uint32_t clock_freq_hz = 0;
+    QDict *r;
+
+    r = qtest_qmp(global_qtest, "{ 'execute': 'qom-get', 'arguments':"
+        " { 'path': %s, 'property': 'clock-freq-hz'} }", SYSCFG);
+    g_assert_false(qdict_haskey(r, "error"));
+    clock_freq_hz = qdict_get_int(r, "return");
+    qobject_unref(r);
+    return clock_freq_hz;
+}
+
 static void test_reset(void)
 {
     /*
@@ -301,6 +323,16 @@  static void test_irq_gpio_multiplexer(void)
     syscfg_writel(SYSCFG_EXTICR1, 0x00000000);
 }
 
+static void test_clock_enable(void)
+{
+    g_assert_cmpuint(get_clock_freq_hz(), ==, 0);
+
+    /* Enable SYSCFG clock */
+    writel(RCC_APB2ENR, readl(RCC_APB2ENR) | (0x1 << 0));
+
+    g_assert_cmpuint(get_clock_freq_hz(), ==, SYSCLK_FREQ_HZ);
+}
+
 int main(int argc, char **argv)
 {
     int ret;
@@ -325,6 +357,8 @@  int main(int argc, char **argv)
                    test_irq_pin_multiplexer);
     qtest_add_func("stm32l4x5/syscfg/test_irq_gpio_multiplexer",
                    test_irq_gpio_multiplexer);
+    qtest_add_func("stm32l4x5/syscfg/test_clock_enable",
+                   test_clock_enable);
 
     qtest_start("-machine b-l475e-iot01a");
     ret = g_test_run();
diff --git a/tests/qtest/stm32l4x5_usart-test.c b/tests/qtest/stm32l4x5_usart-test.c
index 8902518233..6e6e66b6ab 100644
--- a/tests/qtest/stm32l4x5_usart-test.c
+++ b/tests/qtest/stm32l4x5_usart-test.c
@@ -17,6 +17,16 @@ 
 /* Use USART 1 ADDR, assume the others work the same */
 #define USART1_BASE_ADDR 0x40013800
 
+/*
+ * MSI (4 MHz) is used as system clock source after startup
+ * from Reset.
+ * AHB, APB1 and APB2 prescaler are set to 1 at reset.
+ */
+#define SYSCLK_FREQ_HZ 4000000
+#define RCC_APB1ENR1 0x40021058
+#define RCC_APB1ENR2 0x4002105C
+#define RCC_APB2ENR  0x40021060
+
 /* See stm32l4x5_usart for definitions */
 REG32(CR1, 0x00)
     FIELD(CR1, M1, 28, 1)
@@ -64,6 +74,19 @@  static bool clear_nvic_pending(QTestState *qts, unsigned int n)
     return true;
 }
 
+static uint32_t get_clock_freq_hz(QTestState *qts, const char *path)
+{
+    uint32_t clock_freq_hz = 0;
+    QDict *r;
+
+    r = qtest_qmp(qts, "{ 'execute': 'qom-get', 'arguments':"
+        " { 'path': %s, 'property': 'clock-freq-hz'} }", path);
+    g_assert_false(qdict_haskey(r, "error"));
+    clock_freq_hz = qdict_get_int(r, "return");
+    qobject_unref(r);
+    return clock_freq_hz;
+}
+
 /*
  * Wait indefinitely for the flag to be updated.
  * If this is run on a slow CI runner,
@@ -296,6 +319,30 @@  static void test_send_str(void)
     qtest_quit(qts);
 }
 
+static void check_clock(QTestState *qts, const char *path, uint32_t rcc_reg,
+                        uint32_t reg_offset)
+{
+    g_assert_cmpuint(get_clock_freq_hz(qts, path), ==, 0);
+    qtest_writel(qts, rcc_reg, qtest_readl(qts, rcc_reg) | (0x1 << reg_offset));
+    g_assert_cmpuint(get_clock_freq_hz(qts, path), ==, SYSCLK_FREQ_HZ);
+}
+
+static void test_clock_enable(void)
+{
+    /*
+     * For each USART device, enable its clock in RCC
+     * and check that its clock frequency is SYSCLK_FREQ_HZ
+     */
+    QTestState *qts = qtest_init("-M b-l475e-iot01a");
+
+    check_clock(qts, "machine/soc/usart[0]", RCC_APB2ENR, 14);
+    check_clock(qts, "machine/soc/usart[1]", RCC_APB1ENR1, 17);
+    check_clock(qts, "machine/soc/usart[2]", RCC_APB1ENR1, 18);
+    check_clock(qts, "machine/soc/uart[0]", RCC_APB1ENR1, 19);
+    check_clock(qts, "machine/soc/uart[1]", RCC_APB1ENR1, 20);
+    check_clock(qts, "machine/soc/lpuart1", RCC_APB1ENR2, 0);
+}
+
 int main(int argc, char **argv)
 {
     int ret;
@@ -308,6 +355,7 @@  int main(int argc, char **argv)
     qtest_add_func("stm32l4x5/usart/send_char", test_send_char);
     qtest_add_func("stm32l4x5/usart/receive_str", test_receive_str);
     qtest_add_func("stm32l4x5/usart/send_str", test_send_str);
+    qtest_add_func("stm32l4x5/usart/clock_enable", test_clock_enable);
     ret = g_test_run();
 
     return ret;