1*13d6c073SArnaud Minier /*
2*13d6c073SArnaud Minier  * QTest testcase for STM32L4x5_RCC
3*13d6c073SArnaud Minier  *
4*13d6c073SArnaud Minier  * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
5*13d6c073SArnaud Minier  * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
6*13d6c073SArnaud Minier  *
7*13d6c073SArnaud Minier  * SPDX-License-Identifier: GPL-2.0-or-later
8*13d6c073SArnaud Minier  *
9*13d6c073SArnaud Minier  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10*13d6c073SArnaud Minier  * See the COPYING file in the top-level directory.
11*13d6c073SArnaud Minier  */
12*13d6c073SArnaud Minier 
13*13d6c073SArnaud Minier #include "qemu/osdep.h"
14*13d6c073SArnaud Minier #include "hw/registerfields.h"
15*13d6c073SArnaud Minier #include "libqtest-single.h"
16*13d6c073SArnaud Minier #include "hw/misc/stm32l4x5_rcc_internals.h"
17*13d6c073SArnaud Minier 
18*13d6c073SArnaud Minier #define RCC_BASE_ADDR 0x40021000
19*13d6c073SArnaud Minier #define NVIC_ISER 0xE000E100
20*13d6c073SArnaud Minier #define NVIC_ISPR 0xE000E200
21*13d6c073SArnaud Minier #define NVIC_ICPR 0xE000E280
22*13d6c073SArnaud Minier #define RCC_IRQ 5
23*13d6c073SArnaud Minier 
enable_nvic_irq(unsigned int n)24*13d6c073SArnaud Minier static void enable_nvic_irq(unsigned int n)
25*13d6c073SArnaud Minier {
26*13d6c073SArnaud Minier     writel(NVIC_ISER, 1 << n);
27*13d6c073SArnaud Minier }
28*13d6c073SArnaud Minier 
unpend_nvic_irq(unsigned int n)29*13d6c073SArnaud Minier static void unpend_nvic_irq(unsigned int n)
30*13d6c073SArnaud Minier {
31*13d6c073SArnaud Minier     writel(NVIC_ICPR, 1 << n);
32*13d6c073SArnaud Minier }
33*13d6c073SArnaud Minier 
check_nvic_pending(unsigned int n)34*13d6c073SArnaud Minier static bool check_nvic_pending(unsigned int n)
35*13d6c073SArnaud Minier {
36*13d6c073SArnaud Minier     return readl(NVIC_ISPR) & (1 << n);
37*13d6c073SArnaud Minier }
38*13d6c073SArnaud Minier 
rcc_writel(unsigned int offset,uint32_t value)39*13d6c073SArnaud Minier static void rcc_writel(unsigned int offset, uint32_t value)
40*13d6c073SArnaud Minier {
41*13d6c073SArnaud Minier     writel(RCC_BASE_ADDR + offset, value);
42*13d6c073SArnaud Minier }
43*13d6c073SArnaud Minier 
rcc_readl(unsigned int offset)44*13d6c073SArnaud Minier static uint32_t rcc_readl(unsigned int offset)
45*13d6c073SArnaud Minier {
46*13d6c073SArnaud Minier     return readl(RCC_BASE_ADDR + offset);
47*13d6c073SArnaud Minier }
48*13d6c073SArnaud Minier 
test_init_msi(void)49*13d6c073SArnaud Minier static void test_init_msi(void)
50*13d6c073SArnaud Minier {
51*13d6c073SArnaud Minier     /* MSIRANGE can be set only when MSI is OFF or READY */
52*13d6c073SArnaud Minier     rcc_writel(A_CR, R_CR_MSION_MASK);
53*13d6c073SArnaud Minier     /* Wait until MSI is stable */
54*13d6c073SArnaud Minier     g_assert_true((rcc_readl(A_CR) & R_CR_MSIRDY_MASK) == R_CR_MSIRDY_MASK);
55*13d6c073SArnaud Minier     /* TODO find a way to test MSI value */
56*13d6c073SArnaud Minier }
57*13d6c073SArnaud Minier 
test_set_msi_as_sysclk(void)58*13d6c073SArnaud Minier static void test_set_msi_as_sysclk(void)
59*13d6c073SArnaud Minier {
60*13d6c073SArnaud Minier     /* Clocking from MSI, in case MSI was not the default source */
61*13d6c073SArnaud Minier     rcc_writel(A_CFGR, 0);
62*13d6c073SArnaud Minier     /* Wait until MSI is selected and stable */
63*13d6c073SArnaud Minier     g_assert_true((rcc_readl(A_CFGR) & R_CFGR_SWS_MASK) == 0);
64*13d6c073SArnaud Minier }
65*13d6c073SArnaud Minier 
test_init_pll(void)66*13d6c073SArnaud Minier static void test_init_pll(void)
67*13d6c073SArnaud Minier {
68*13d6c073SArnaud Minier     uint32_t value;
69*13d6c073SArnaud Minier 
70*13d6c073SArnaud Minier     /*
71*13d6c073SArnaud Minier      * Update PLL and set MSI as the source clock.
72*13d6c073SArnaud Minier      * PLLM = 1 --> 000
73*13d6c073SArnaud Minier      * PLLN = 40 --> 40
74*13d6c073SArnaud Minier      * PPLLR = 2 --> 00
75*13d6c073SArnaud Minier      * PLLDIV = unused, PLLP = unused (SAI3), PLLQ = unused (48M1)
76*13d6c073SArnaud Minier      * SRC = MSI --> 01
77*13d6c073SArnaud Minier      */
78*13d6c073SArnaud Minier     rcc_writel(A_PLLCFGR, R_PLLCFGR_PLLREN_MASK |
79*13d6c073SArnaud Minier             (40 << R_PLLCFGR_PLLN_SHIFT) |
80*13d6c073SArnaud Minier             (0b01 << R_PLLCFGR_PLLSRC_SHIFT));
81*13d6c073SArnaud Minier 
82*13d6c073SArnaud Minier     /* PLL activation */
83*13d6c073SArnaud Minier     value = rcc_readl(A_CR);
84*13d6c073SArnaud Minier     rcc_writel(A_CR, value | R_CR_PLLON_MASK);
85*13d6c073SArnaud Minier 
86*13d6c073SArnaud Minier     /* Waiting for PLL lock. */
87*13d6c073SArnaud Minier     g_assert_true((rcc_readl(A_CR) & R_CR_PLLRDY_MASK) == R_CR_PLLRDY_MASK);
88*13d6c073SArnaud Minier 
89*13d6c073SArnaud Minier     /* Switches on the PLL clock source */
90*13d6c073SArnaud Minier     value = rcc_readl(A_CFGR);
91*13d6c073SArnaud Minier     rcc_writel(A_CFGR, (value & ~R_CFGR_SW_MASK) |
92*13d6c073SArnaud Minier         (0b11 << R_CFGR_SW_SHIFT));
93*13d6c073SArnaud Minier 
94*13d6c073SArnaud Minier     /* Wait until SYSCLK is stable. */
95*13d6c073SArnaud Minier     g_assert_true((rcc_readl(A_CFGR) & R_CFGR_SWS_MASK) ==
96*13d6c073SArnaud Minier         (0b11 << R_CFGR_SWS_SHIFT));
97*13d6c073SArnaud Minier }
98*13d6c073SArnaud Minier 
test_activate_lse(void)99*13d6c073SArnaud Minier static void test_activate_lse(void)
100*13d6c073SArnaud Minier {
101*13d6c073SArnaud Minier     /* LSE activation, no LSE Bypass */
102*13d6c073SArnaud Minier     rcc_writel(A_BDCR, R_BDCR_LSEDRV_MASK | R_BDCR_LSEON_MASK);
103*13d6c073SArnaud Minier     g_assert_true((rcc_readl(A_BDCR) & R_BDCR_LSERDY_MASK) == R_BDCR_LSERDY_MASK);
104*13d6c073SArnaud Minier }
105*13d6c073SArnaud Minier 
test_irq(void)106*13d6c073SArnaud Minier static void test_irq(void)
107*13d6c073SArnaud Minier {
108*13d6c073SArnaud Minier     enable_nvic_irq(RCC_IRQ);
109*13d6c073SArnaud Minier 
110*13d6c073SArnaud Minier     rcc_writel(A_CIER, R_CIER_LSIRDYIE_MASK);
111*13d6c073SArnaud Minier     rcc_writel(A_CSR, R_CSR_LSION_MASK);
112*13d6c073SArnaud Minier     g_assert_true(check_nvic_pending(RCC_IRQ));
113*13d6c073SArnaud Minier     rcc_writel(A_CICR, R_CICR_LSIRDYC_MASK);
114*13d6c073SArnaud Minier     unpend_nvic_irq(RCC_IRQ);
115*13d6c073SArnaud Minier 
116*13d6c073SArnaud Minier     rcc_writel(A_CIER, R_CIER_LSERDYIE_MASK);
117*13d6c073SArnaud Minier     rcc_writel(A_BDCR, R_BDCR_LSEON_MASK);
118*13d6c073SArnaud Minier     g_assert_true(check_nvic_pending(RCC_IRQ));
119*13d6c073SArnaud Minier     rcc_writel(A_CICR, R_CICR_LSERDYC_MASK);
120*13d6c073SArnaud Minier     unpend_nvic_irq(RCC_IRQ);
121*13d6c073SArnaud Minier 
122*13d6c073SArnaud Minier     /*
123*13d6c073SArnaud Minier      * MSI has been enabled by previous tests,
124*13d6c073SArnaud Minier      * shouln't generate an interruption.
125*13d6c073SArnaud Minier      */
126*13d6c073SArnaud Minier     rcc_writel(A_CIER, R_CIER_MSIRDYIE_MASK);
127*13d6c073SArnaud Minier     rcc_writel(A_CR, R_CR_MSION_MASK);
128*13d6c073SArnaud Minier     g_assert_false(check_nvic_pending(RCC_IRQ));
129*13d6c073SArnaud Minier 
130*13d6c073SArnaud Minier     rcc_writel(A_CIER, R_CIER_HSIRDYIE_MASK);
131*13d6c073SArnaud Minier     rcc_writel(A_CR, R_CR_HSION_MASK);
132*13d6c073SArnaud Minier     g_assert_true(check_nvic_pending(RCC_IRQ));
133*13d6c073SArnaud Minier     rcc_writel(A_CICR, R_CICR_HSIRDYC_MASK);
134*13d6c073SArnaud Minier     unpend_nvic_irq(RCC_IRQ);
135*13d6c073SArnaud Minier 
136*13d6c073SArnaud Minier     rcc_writel(A_CIER, R_CIER_HSERDYIE_MASK);
137*13d6c073SArnaud Minier     rcc_writel(A_CR, R_CR_HSEON_MASK);
138*13d6c073SArnaud Minier     g_assert_true(check_nvic_pending(RCC_IRQ));
139*13d6c073SArnaud Minier     rcc_writel(A_CICR, R_CICR_HSERDYC_MASK);
140*13d6c073SArnaud Minier     unpend_nvic_irq(RCC_IRQ);
141*13d6c073SArnaud Minier 
142*13d6c073SArnaud Minier     /*
143*13d6c073SArnaud Minier      * PLL has been enabled by previous tests,
144*13d6c073SArnaud Minier      * shouln't generate an interruption.
145*13d6c073SArnaud Minier      */
146*13d6c073SArnaud Minier     rcc_writel(A_CIER, R_CIER_PLLRDYIE_MASK);
147*13d6c073SArnaud Minier     rcc_writel(A_CR, R_CR_PLLON_MASK);
148*13d6c073SArnaud Minier     g_assert_false(check_nvic_pending(RCC_IRQ));
149*13d6c073SArnaud Minier 
150*13d6c073SArnaud Minier     rcc_writel(A_CIER, R_CIER_PLLSAI1RDYIE_MASK);
151*13d6c073SArnaud Minier     rcc_writel(A_CR, R_CR_PLLSAI1ON_MASK);
152*13d6c073SArnaud Minier     g_assert_true(check_nvic_pending(RCC_IRQ));
153*13d6c073SArnaud Minier     rcc_writel(A_CICR, R_CICR_PLLSAI1RDYC_MASK);
154*13d6c073SArnaud Minier     unpend_nvic_irq(RCC_IRQ);
155*13d6c073SArnaud Minier 
156*13d6c073SArnaud Minier     rcc_writel(A_CIER, R_CIER_PLLSAI2RDYIE_MASK);
157*13d6c073SArnaud Minier     rcc_writel(A_CR, R_CR_PLLSAI2ON_MASK);
158*13d6c073SArnaud Minier     g_assert_true(check_nvic_pending(RCC_IRQ));
159*13d6c073SArnaud Minier     rcc_writel(A_CICR, R_CICR_PLLSAI2RDYC_MASK);
160*13d6c073SArnaud Minier     unpend_nvic_irq(RCC_IRQ);
161*13d6c073SArnaud Minier }
162*13d6c073SArnaud Minier 
main(int argc,char ** argv)163*13d6c073SArnaud Minier int main(int argc, char **argv)
164*13d6c073SArnaud Minier {
165*13d6c073SArnaud Minier     int ret;
166*13d6c073SArnaud Minier 
167*13d6c073SArnaud Minier     g_test_init(&argc, &argv, NULL);
168*13d6c073SArnaud Minier     g_test_set_nonfatal_assertions();
169*13d6c073SArnaud Minier     /*
170*13d6c073SArnaud Minier      * These test separately that we can enable the plls, change the sysclk,
171*13d6c073SArnaud Minier      * and enable different devices.
172*13d6c073SArnaud Minier      * They are dependent on one another.
173*13d6c073SArnaud Minier      * We assume that all operations that would take some time to have an effect
174*13d6c073SArnaud Minier      * (e.g. changing the PLL frequency) are done instantaneously.
175*13d6c073SArnaud Minier      */
176*13d6c073SArnaud Minier     qtest_add_func("stm32l4x5/rcc/init_msi", test_init_msi);
177*13d6c073SArnaud Minier     qtest_add_func("stm32l4x5/rcc/set_msi_as_sysclk",
178*13d6c073SArnaud Minier         test_set_msi_as_sysclk);
179*13d6c073SArnaud Minier     qtest_add_func("stm32l4x5/rcc/activate_lse", test_activate_lse);
180*13d6c073SArnaud Minier     qtest_add_func("stm32l4x5/rcc/init_pll", test_init_pll);
181*13d6c073SArnaud Minier 
182*13d6c073SArnaud Minier     qtest_add_func("stm32l4x5/rcc/irq", test_irq);
183*13d6c073SArnaud Minier 
184*13d6c073SArnaud Minier     qtest_start("-machine b-l475e-iot01a");
185*13d6c073SArnaud Minier     ret = g_test_run();
186*13d6c073SArnaud Minier     qtest_end();
187*13d6c073SArnaud Minier 
188*13d6c073SArnaud Minier     return ret;
189*13d6c073SArnaud Minier }
190