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 */ 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 */ 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 */ 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 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 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 */ 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 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 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 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