xref: /openbmc/qemu/tests/qtest/aspeed_scu-test.c (revision a876b05d38c813501e60fb50c8a45b30a965e902)
1*116bf243STan Siewert /*
2*116bf243STan Siewert  * QTest testcase for the ASPEED AST2500 and AST2600 SCU.
3*116bf243STan Siewert  *
4*116bf243STan Siewert  * SPDX-License-Identifier: GPL-2.0-or-later
5*116bf243STan Siewert  * Copyright (C) 2025 Tan Siewert
6*116bf243STan Siewert  */
7*116bf243STan Siewert 
8*116bf243STan Siewert #include "qemu/osdep.h"
9*116bf243STan Siewert #include "libqtest-single.h"
10*116bf243STan Siewert 
11*116bf243STan Siewert /*
12*116bf243STan Siewert  * SCU base, as well as protection key are
13*116bf243STan Siewert  * the same on AST2500 and 2600.
14*116bf243STan Siewert  */
15*116bf243STan Siewert #define AST_SCU_BASE                    0x1E6E2000
16*116bf243STan Siewert #define AST_SCU_PROT_LOCK_STATE         0x0
17*116bf243STan Siewert #define AST_SCU_PROT_LOCK_VALUE         0x2
18*116bf243STan Siewert #define AST_SCU_PROT_UNLOCK_STATE       0x1
19*116bf243STan Siewert #define AST_SCU_PROT_UNLOCK_VALUE       0x1688A8A8
20*116bf243STan Siewert 
21*116bf243STan Siewert #define AST2500_MACHINE                 "-machine ast2500-evb"
22*116bf243STan Siewert #define AST2500_SCU_PROT_REG            0x00
23*116bf243STan Siewert #define AST2500_SCU_MISC_2_CONTROL_REG  0x4C
24*116bf243STan Siewert 
25*116bf243STan Siewert #define AST2600_MACHINE                 "-machine ast2600-evb"
26*116bf243STan Siewert /* AST2600 has two protection registers */
27*116bf243STan Siewert #define AST2600_SCU_PROT_REG            0x000
28*116bf243STan Siewert #define AST2600_SCU_PROT_REG2           0x010
29*116bf243STan Siewert #define AST2600_SCU_MISC_2_CONTROL_REG  0x0C4
30*116bf243STan Siewert 
31*116bf243STan Siewert #define TEST_LOCK_ARBITRARY_VALUE       0xABCDEFAB
32*116bf243STan Siewert 
33*116bf243STan Siewert /**
34*116bf243STan Siewert  * Assert that a given register matches an expected value.
35*116bf243STan Siewert  *
36*116bf243STan Siewert  * Reads the register and checks if its value equals the expected value.
37*116bf243STan Siewert  *
38*116bf243STan Siewert  * @param *s - QTest machine state
39*116bf243STan Siewert  * @param reg - Address of the register to be checked
40*116bf243STan Siewert  * @param expected - Expected register value
41*116bf243STan Siewert  */
assert_register_eq(QTestState * s,uint32_t reg,uint32_t expected)42*116bf243STan Siewert static inline void assert_register_eq(QTestState *s,
43*116bf243STan Siewert                                       uint32_t reg,
44*116bf243STan Siewert                                       uint32_t expected)
45*116bf243STan Siewert {
46*116bf243STan Siewert     uint32_t value = qtest_readl(s, reg);
47*116bf243STan Siewert     g_assert_cmphex(value, ==, expected);
48*116bf243STan Siewert }
49*116bf243STan Siewert 
50*116bf243STan Siewert /**
51*116bf243STan Siewert  * Assert that a given register does not match a specific value.
52*116bf243STan Siewert  *
53*116bf243STan Siewert  * Reads the register and checks that its value is not equal to the
54*116bf243STan Siewert  * provided value.
55*116bf243STan Siewert  *
56*116bf243STan Siewert  * @param *s - QTest machine state
57*116bf243STan Siewert  * @param reg - Address of the register to be checked
58*116bf243STan Siewert  * @param not_expected - Value the register must not contain
59*116bf243STan Siewert  */
assert_register_neq(QTestState * s,uint32_t reg,uint32_t not_expected)60*116bf243STan Siewert static inline void assert_register_neq(QTestState *s,
61*116bf243STan Siewert                                        uint32_t reg,
62*116bf243STan Siewert                                        uint32_t not_expected)
63*116bf243STan Siewert {
64*116bf243STan Siewert     uint32_t value = qtest_readl(s, reg);
65*116bf243STan Siewert     g_assert_cmphex(value, !=, not_expected);
66*116bf243STan Siewert }
67*116bf243STan Siewert 
68*116bf243STan Siewert /**
69*116bf243STan Siewert  * Test whether the SCU can be locked and unlocked correctly.
70*116bf243STan Siewert  *
71*116bf243STan Siewert  * When testing multiple registers, this function assumes that writing
72*116bf243STan Siewert  * to the first register also affects the others. However, writing to
73*116bf243STan Siewert  * any other register only affects itself.
74*116bf243STan Siewert  *
75*116bf243STan Siewert  * @param *machine - input machine configuration, passed directly
76*116bf243STan Siewert  *                   to QTest
77*116bf243STan Siewert  * @param regs[] - List of registers to be checked
78*116bf243STan Siewert  * @param regc - amount of arguments for registers to be checked
79*116bf243STan Siewert  */
test_protection_register(const char * machine,const uint32_t regs[],const int regc)80*116bf243STan Siewert static void test_protection_register(const char *machine,
81*116bf243STan Siewert                                      const uint32_t regs[],
82*116bf243STan Siewert                                      const int regc)
83*116bf243STan Siewert {
84*116bf243STan Siewert     QTestState *s = qtest_init(machine);
85*116bf243STan Siewert 
86*116bf243STan Siewert     for (int i = 0; i < regc; i++) {
87*116bf243STan Siewert         uint32_t reg = regs[i];
88*116bf243STan Siewert 
89*116bf243STan Siewert         qtest_writel(s, reg, AST_SCU_PROT_UNLOCK_VALUE);
90*116bf243STan Siewert         assert_register_eq(s, reg, AST_SCU_PROT_UNLOCK_STATE);
91*116bf243STan Siewert 
92*116bf243STan Siewert         /**
93*116bf243STan Siewert          * Check that other registers are unlocked too, if more
94*116bf243STan Siewert          * than one is available.
95*116bf243STan Siewert          */
96*116bf243STan Siewert         if (regc > 1 && i == 0) {
97*116bf243STan Siewert             /* Initialise at 1 instead of 0 to skip first */
98*116bf243STan Siewert             for (int j = 1; j < regc; j++) {
99*116bf243STan Siewert                 uint32_t add_reg = regs[j];
100*116bf243STan Siewert                 assert_register_eq(s, add_reg, AST_SCU_PROT_UNLOCK_STATE);
101*116bf243STan Siewert             }
102*116bf243STan Siewert         }
103*116bf243STan Siewert 
104*116bf243STan Siewert         /* Lock the register again */
105*116bf243STan Siewert         qtest_writel(s, reg, AST_SCU_PROT_LOCK_VALUE);
106*116bf243STan Siewert         assert_register_eq(s, reg, AST_SCU_PROT_LOCK_STATE);
107*116bf243STan Siewert 
108*116bf243STan Siewert         /* And the same for locked state */
109*116bf243STan Siewert         if (regc > 1 && i == 0) {
110*116bf243STan Siewert             /* Initialise at 1 instead of 0 to skip first */
111*116bf243STan Siewert             for (int j = 1; j < regc; j++) {
112*116bf243STan Siewert                 uint32_t add_reg = regs[j];
113*116bf243STan Siewert                 assert_register_eq(s, add_reg, AST_SCU_PROT_LOCK_STATE);
114*116bf243STan Siewert             }
115*116bf243STan Siewert         }
116*116bf243STan Siewert     }
117*116bf243STan Siewert 
118*116bf243STan Siewert     qtest_quit(s);
119*116bf243STan Siewert }
120*116bf243STan Siewert 
test_2500_protection_register(void)121*116bf243STan Siewert static void test_2500_protection_register(void)
122*116bf243STan Siewert {
123*116bf243STan Siewert     uint32_t regs[] = { AST_SCU_BASE + AST2500_SCU_PROT_REG };
124*116bf243STan Siewert 
125*116bf243STan Siewert     test_protection_register(AST2500_MACHINE,
126*116bf243STan Siewert                              regs,
127*116bf243STan Siewert                              ARRAY_SIZE(regs));
128*116bf243STan Siewert }
129*116bf243STan Siewert 
test_2600_protection_register(void)130*116bf243STan Siewert static void test_2600_protection_register(void)
131*116bf243STan Siewert {
132*116bf243STan Siewert     /**
133*116bf243STan Siewert      * The AST2600 has two protection registers, both
134*116bf243STan Siewert      * being required to be unlocked to do any operation.
135*116bf243STan Siewert      *
136*116bf243STan Siewert      * Modifying SCU000 also modifies SCU010, but modifying
137*116bf243STan Siewert      * SCU010 only will keep SCU000 untouched.
138*116bf243STan Siewert      */
139*116bf243STan Siewert     uint32_t regs[] = { AST_SCU_BASE + AST2600_SCU_PROT_REG,
140*116bf243STan Siewert                         AST_SCU_BASE + AST2600_SCU_PROT_REG2 };
141*116bf243STan Siewert 
142*116bf243STan Siewert     test_protection_register(AST2600_MACHINE,
143*116bf243STan Siewert                              regs,
144*116bf243STan Siewert                              ARRAY_SIZE(regs));
145*116bf243STan Siewert }
146*116bf243STan Siewert 
147*116bf243STan Siewert /**
148*116bf243STan Siewert  * Test if SCU register writes are correctly allowed or blocked
149*116bf243STan Siewert  * depending on the protection register state.
150*116bf243STan Siewert  *
151*116bf243STan Siewert  * The test first locks the protection register and verifies that
152*116bf243STan Siewert  * writes to the target SCU register are rejected. It then unlocks
153*116bf243STan Siewert  * the protection register and confirms that the written value is
154*116bf243STan Siewert  * retained when unlocked.
155*116bf243STan Siewert  *
156*116bf243STan Siewert  * @param *machine - input machine configuration, passed directly
157*116bf243STan Siewert  *                   to QTest
158*116bf243STan Siewert  * @param protection_register - first SCU protection key register
159*116bf243STan Siewert  *                              (only one for keeping it simple)
160*116bf243STan Siewert  * @param test_register - Register to be used for writing arbitrary
161*116bf243STan Siewert  *                        values
162*116bf243STan Siewert  */
test_write_permission_lock_state(const char * machine,const uint32_t protection_register,const uint32_t test_register)163*116bf243STan Siewert static void test_write_permission_lock_state(const char *machine,
164*116bf243STan Siewert                                              const uint32_t protection_register,
165*116bf243STan Siewert                                              const uint32_t test_register)
166*116bf243STan Siewert {
167*116bf243STan Siewert     QTestState *s = qtest_init(machine);
168*116bf243STan Siewert 
169*116bf243STan Siewert     /* Arbitrary value to lock provided SCU protection register */
170*116bf243STan Siewert     qtest_writel(s, protection_register, AST_SCU_PROT_LOCK_VALUE);
171*116bf243STan Siewert 
172*116bf243STan Siewert     /* Ensure that the SCU is really locked */
173*116bf243STan Siewert     assert_register_eq(s, protection_register, AST_SCU_PROT_LOCK_STATE);
174*116bf243STan Siewert 
175*116bf243STan Siewert     /* Write a known arbitrary value to test that the write is blocked */
176*116bf243STan Siewert     qtest_writel(s, test_register, TEST_LOCK_ARBITRARY_VALUE);
177*116bf243STan Siewert 
178*116bf243STan Siewert     /* We do not want to have the written value to be saved */
179*116bf243STan Siewert     assert_register_neq(s, test_register, TEST_LOCK_ARBITRARY_VALUE);
180*116bf243STan Siewert 
181*116bf243STan Siewert     /**
182*116bf243STan Siewert      * Unlock the SCU and verify that it can be written to.
183*116bf243STan Siewert      * Assumes that the first SCU protection register is sufficient to
184*116bf243STan Siewert      * unlock all protection registers, if multiple are present.
185*116bf243STan Siewert      */
186*116bf243STan Siewert     qtest_writel(s, protection_register, AST_SCU_PROT_UNLOCK_VALUE);
187*116bf243STan Siewert     assert_register_eq(s, protection_register, AST_SCU_PROT_UNLOCK_STATE);
188*116bf243STan Siewert 
189*116bf243STan Siewert     /* Write a known arbitrary value to test that the write works */
190*116bf243STan Siewert     qtest_writel(s, test_register, TEST_LOCK_ARBITRARY_VALUE);
191*116bf243STan Siewert 
192*116bf243STan Siewert     /* Ensure that the written value is retained */
193*116bf243STan Siewert     assert_register_eq(s, test_register, TEST_LOCK_ARBITRARY_VALUE);
194*116bf243STan Siewert 
195*116bf243STan Siewert     qtest_quit(s);
196*116bf243STan Siewert }
197*116bf243STan Siewert 
test_2500_write_permission_lock_state(void)198*116bf243STan Siewert static void test_2500_write_permission_lock_state(void)
199*116bf243STan Siewert {
200*116bf243STan Siewert     test_write_permission_lock_state(
201*116bf243STan Siewert             AST2500_MACHINE,
202*116bf243STan Siewert             AST_SCU_BASE + AST2500_SCU_PROT_REG,
203*116bf243STan Siewert             AST_SCU_BASE + AST2500_SCU_MISC_2_CONTROL_REG
204*116bf243STan Siewert     );
205*116bf243STan Siewert }
206*116bf243STan Siewert 
test_2600_write_permission_lock_state(void)207*116bf243STan Siewert static void test_2600_write_permission_lock_state(void)
208*116bf243STan Siewert {
209*116bf243STan Siewert     test_write_permission_lock_state(
210*116bf243STan Siewert             AST2600_MACHINE,
211*116bf243STan Siewert             AST_SCU_BASE + AST2600_SCU_PROT_REG,
212*116bf243STan Siewert             AST_SCU_BASE + AST2600_SCU_MISC_2_CONTROL_REG
213*116bf243STan Siewert     );
214*116bf243STan Siewert }
215*116bf243STan Siewert 
main(int argc,char ** argv)216*116bf243STan Siewert int main(int argc, char **argv)
217*116bf243STan Siewert {
218*116bf243STan Siewert     g_test_init(&argc, &argv, NULL);
219*116bf243STan Siewert 
220*116bf243STan Siewert     qtest_add_func("/ast2500/scu/protection_register",
221*116bf243STan Siewert                    test_2500_protection_register);
222*116bf243STan Siewert     qtest_add_func("/ast2600/scu/protection_register",
223*116bf243STan Siewert                    test_2600_protection_register);
224*116bf243STan Siewert 
225*116bf243STan Siewert     qtest_add_func("/ast2500/scu/write_permission_lock_state",
226*116bf243STan Siewert                    test_2500_write_permission_lock_state);
227*116bf243STan Siewert     qtest_add_func("/ast2600/scu/write_permission_lock_state",
228*116bf243STan Siewert                    test_2600_write_permission_lock_state);
229*116bf243STan Siewert 
230*116bf243STan Siewert     return g_test_run();
231*116bf243STan Siewert }
232