Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 1 | // Copyright lowRISC contributors. |
| 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| 3 | // SPDX-License-Identifier: Apache-2.0 |
| 4 | |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 5 | #include "sw/device/lib/base/abs_mmio.h" |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 6 | #include "sw/device/lib/base/memory.h" |
| 7 | #include "sw/device/lib/dif/dif_aon_timer.h" |
| 8 | #include "sw/device/lib/dif/dif_base.h" |
| 9 | #include "sw/device/lib/dif/dif_clkmgr.h" |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 10 | #include "sw/device/lib/dif/dif_flash_ctrl.h" |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 11 | #include "sw/device/lib/dif/dif_pwrmgr.h" |
| 12 | #include "sw/device/lib/dif/dif_rstmgr.h" |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 13 | #include "sw/device/lib/dif/dif_spi_host.h" |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 14 | #include "sw/device/lib/dif/dif_uart.h" |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 15 | #include "sw/device/lib/dif/dif_usbdev.h" |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 16 | #include "sw/device/lib/runtime/log.h" |
| 17 | #include "sw/device/lib/testing/aon_timer_testutils.h" |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 18 | #include "sw/device/lib/testing/flash_ctrl_testutils.h" |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 19 | #include "sw/device/lib/testing/rstmgr_testutils.h" |
Miguel Young de la Sota | 09d4d01 | 2022-04-19 11:05:36 -0400 | [diff] [blame] | 20 | #include "sw/device/lib/testing/test_framework/check.h" |
Miguel Young de la Sota | 4d46eb9 | 2022-04-19 13:11:15 -0400 | [diff] [blame] | 21 | #include "sw/device/lib/testing/test_framework/ottf_main.h" |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 22 | |
| 23 | #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 24 | #include "spi_host_regs.h" |
| 25 | #include "uart_regs.h" |
| 26 | #include "usbdev_regs.h" |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 27 | |
| 28 | /** |
| 29 | * The peripherals used to test when the peri clocks are disabled are |
| 30 | * bit 0: clk_io_div4_peri: uart0 |
| 31 | * bit 1: clk_io_div2_peri: spi_host1 |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 32 | * bit 2: clk_io_peri: spi_host0 |
| 33 | * bit 3: clk_usb_peri: usbdev |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 34 | */ |
| 35 | |
Alphan Ulusoy | 9f4fc67 | 2022-06-17 21:39:16 -0400 | [diff] [blame] | 36 | OTTF_DEFINE_TEST_CONFIG(); |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 37 | |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 38 | typedef struct peri_context { |
| 39 | void (*csr_access)(); // The function causing a timeout. |
| 40 | uint32_t address; // The address causing a timeout. |
| 41 | } peri_context_t; |
| 42 | |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 43 | static dif_aon_timer_t aon_timer; |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 44 | static dif_flash_ctrl_state_t flash_ctrl; |
| 45 | static dif_spi_host_t spi_host0; |
| 46 | static dif_spi_host_t spi_host1; |
| 47 | static dif_usbdev_t usbdev; |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 48 | static dif_uart_t uart0; |
| 49 | |
Alphan Ulusoy | 9ffc257 | 2022-09-13 14:46:23 -0400 | [diff] [blame] | 50 | OT_SECTION(".non_volatile_scratch") uint64_t hung_data_addr[4]; |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 51 | |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 52 | static void set_hung_address(dif_clkmgr_gateable_clock_t clock, |
| 53 | uint32_t value) { |
Alphan Ulusoy | 9ffc257 | 2022-09-13 14:46:23 -0400 | [diff] [blame] | 54 | uint32_t addr = |
| 55 | (uintptr_t)&hung_data_addr[clock] - TOP_EARLGREY_FLASH_CTRL_MEM_BASE_ADDR; |
| 56 | uint32_t flash_word[2] = {value, 0}; |
| 57 | CHECK(flash_ctrl_testutils_write(&flash_ctrl, addr, 0, flash_word, |
| 58 | kDifFlashCtrlPartitionTypeData, 2)); |
| 59 | CHECK(hung_data_addr[clock] == value, "Unexpected mismatch on read back"); |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 60 | LOG_INFO("The expected hung address for clock %d is 0x%x at 0x%x", clock, |
| 61 | value, addr); |
| 62 | } |
| 63 | |
| 64 | static void uart0_csr_access() { |
| 65 | dif_toggle_t state; |
| 66 | CHECK_DIF_OK(dif_uart_irq_set_enabled(&uart0, kDifUartIrqTxWatermark, |
| 67 | kDifToggleEnabled)); |
| 68 | CHECK_DIF_OK( |
| 69 | dif_uart_irq_get_enabled(&uart0, kDifUartIrqTxWatermark, &state)); |
| 70 | CHECK(state == kDifToggleEnabled); |
| 71 | } |
| 72 | |
| 73 | static void spi_host0_csr_access() { |
| 74 | dif_toggle_t state; |
| 75 | CHECK_DIF_OK(dif_spi_host_irq_set_enabled(&spi_host0, kDifSpiHostIrqSpiEvent, |
| 76 | kDifToggleEnabled)); |
| 77 | CHECK_DIF_OK( |
| 78 | dif_spi_host_irq_get_enabled(&spi_host0, kDifSpiHostIrqSpiEvent, &state)); |
| 79 | CHECK(state == kDifToggleEnabled); |
| 80 | } |
| 81 | |
| 82 | static void spi_host1_csr_access() { |
| 83 | dif_toggle_t state; |
| 84 | CHECK_DIF_OK(dif_spi_host_irq_set_enabled(&spi_host1, kDifSpiHostIrqSpiEvent, |
| 85 | kDifToggleEnabled)); |
| 86 | CHECK_DIF_OK( |
| 87 | dif_spi_host_irq_get_enabled(&spi_host1, kDifSpiHostIrqSpiEvent, &state)); |
| 88 | CHECK(state == kDifToggleEnabled); |
| 89 | } |
| 90 | |
| 91 | static void usbdev_csr_access() { |
| 92 | CHECK_DIF_OK(dif_usbdev_irq_set_enabled(&usbdev, kDifUsbdevIrqPowered, |
| 93 | kDifToggleEnabled)); |
| 94 | dif_toggle_t state; |
| 95 | CHECK_DIF_OK( |
| 96 | dif_usbdev_irq_get_enabled(&usbdev, kDifUsbdevIrqPowered, &state)); |
| 97 | CHECK(state == kDifToggleEnabled); |
| 98 | } |
| 99 | |
| 100 | peri_context_t peri_context[kTopEarlgreyGateableClocksLast + 1] = { |
| 101 | {uart0_csr_access, |
| 102 | TOP_EARLGREY_UART0_BASE_ADDR + UART_INTR_ENABLE_REG_OFFSET}, |
| 103 | {spi_host1_csr_access, |
| 104 | TOP_EARLGREY_SPI_HOST1_BASE_ADDR + SPI_HOST_INTR_ENABLE_REG_OFFSET}, |
| 105 | {spi_host0_csr_access, |
| 106 | TOP_EARLGREY_SPI_HOST0_BASE_ADDR + SPI_HOST_INTR_ENABLE_REG_OFFSET}, |
| 107 | {usbdev_csr_access, |
| 108 | TOP_EARLGREY_USBDEV_BASE_ADDR + USBDEV_INTR_ENABLE_REG_OFFSET}}; |
| 109 | |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 110 | /** |
| 111 | * Test that disabling a 'gateable' unit's clock causes the unit to become |
| 112 | * unresponsive to CSR accesses. Configure a watchdog reset, and if it triggers |
| 113 | * the test is successful. |
| 114 | */ |
| 115 | static void test_gateable_clocks_off(const dif_clkmgr_t *clkmgr, |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 116 | const dif_pwrmgr_t *pwrmgr, |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 117 | dif_clkmgr_gateable_clock_t clock) { |
| 118 | // Make sure the clock for the unit is on. |
| 119 | CHECK_DIF_OK( |
| 120 | dif_clkmgr_gateable_clock_set_enabled(clkmgr, clock, kDifToggleEnabled)); |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 121 | // Enable watchdog bite reset. |
| 122 | CHECK_DIF_OK(dif_pwrmgr_set_request_sources(pwrmgr, kDifPwrmgrReqTypeReset, |
| 123 | kDifPwrmgrResetRequestSourceTwo, |
| 124 | kDifToggleEnabled)); |
| 125 | LOG_INFO("Testing peripheral clock %d", clock); |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 126 | |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 127 | // Bite after enough time has elapsed past the hung csr access. |
| 128 | uint32_t bite_us = (kDeviceType == kDeviceSimDV) ? 400 : 800; |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 129 | uint32_t bite_cycles = aon_timer_testutils_get_aon_cycles_from_us(bite_us); |
| 130 | LOG_INFO("Setting bite reset for %u us (%u cycles)", bite_us, bite_cycles); |
| 131 | |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 132 | // Make sure the CSR is accessible before turning the clock off. |
| 133 | (*peri_context[clock].csr_access)(); |
| 134 | LOG_INFO("CSR access was okay before disabling the clock"); |
| 135 | |
| 136 | // Save the expected hung address to check against cpu_info's LAST_DATA_ADDR. |
| 137 | set_hung_address(clock, peri_context[clock].address); |
| 138 | // Set bite timer. |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 139 | aon_timer_testutils_watchdog_config(&aon_timer, UINT32_MAX, bite_cycles, |
| 140 | false); |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 141 | // Disable the peripheral's clock. |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 142 | CHECK_DIF_OK( |
| 143 | dif_clkmgr_gateable_clock_set_enabled(clkmgr, clock, kDifToggleDisabled)); |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 144 | // Wait for the clock to really turn off. |
| 145 | busy_spin_micros(100); |
| 146 | // And issue the CSR access that will freeze and cause a reset. |
| 147 | (*peri_context[clock].csr_access)(); |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 148 | } |
| 149 | |
Luís Marques | ec88d27 | 2022-04-19 12:00:37 +0200 | [diff] [blame] | 150 | bool test_main(void) { |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 151 | dif_clkmgr_t clkmgr; |
| 152 | dif_pwrmgr_t pwrmgr; |
| 153 | dif_rstmgr_t rstmgr; |
| 154 | |
| 155 | CHECK_DIF_OK(dif_rstmgr_init( |
| 156 | mmio_region_from_addr(TOP_EARLGREY_RSTMGR_AON_BASE_ADDR), &rstmgr)); |
| 157 | |
| 158 | CHECK_DIF_OK(dif_clkmgr_init( |
| 159 | mmio_region_from_addr(TOP_EARLGREY_CLKMGR_AON_BASE_ADDR), &clkmgr)); |
| 160 | |
| 161 | CHECK_DIF_OK(dif_pwrmgr_init( |
| 162 | mmio_region_from_addr(TOP_EARLGREY_PWRMGR_AON_BASE_ADDR), &pwrmgr)); |
| 163 | |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 164 | CHECK_DIF_OK(dif_flash_ctrl_init_state( |
| 165 | &flash_ctrl, |
| 166 | mmio_region_from_addr(TOP_EARLGREY_FLASH_CTRL_CORE_BASE_ADDR))); |
| 167 | |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 168 | // Initialize aon timer. |
| 169 | CHECK_DIF_OK(dif_aon_timer_init( |
| 170 | mmio_region_from_addr(TOP_EARLGREY_AON_TIMER_AON_BASE_ADDR), &aon_timer)); |
| 171 | |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 172 | // Initialize peripherals. |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 173 | CHECK_DIF_OK(dif_uart_init( |
| 174 | mmio_region_from_addr(TOP_EARLGREY_UART0_BASE_ADDR), &uart0)); |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 175 | CHECK_DIF_OK(dif_spi_host_init( |
| 176 | mmio_region_from_addr(TOP_EARLGREY_SPI_HOST0_BASE_ADDR), &spi_host0)); |
| 177 | CHECK_DIF_OK(dif_spi_host_init( |
| 178 | mmio_region_from_addr(TOP_EARLGREY_SPI_HOST1_BASE_ADDR), &spi_host1)); |
| 179 | CHECK_DIF_OK(dif_usbdev_init( |
| 180 | mmio_region_from_addr(TOP_EARLGREY_USBDEV_BASE_ADDR), &usbdev)); |
| 181 | |
| 182 | // Enable cpu dump capture. |
| 183 | CHECK_DIF_OK(dif_rstmgr_cpu_info_set_enabled(&rstmgr, kDifToggleEnabled)); |
| 184 | |
| 185 | // Enable raw flash access. |
| 186 | flash_ctrl_testutils_default_region_access(&flash_ctrl, |
| 187 | /*rd_en*/ true, |
| 188 | /*prog_en*/ true, |
| 189 | /*erase_en*/ true, |
| 190 | /*scramble_en*/ false, |
| 191 | /*ecc_en*/ false, |
| 192 | /*he_en*/ false); |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 193 | |
| 194 | if (rstmgr_testutils_is_reset_info(&rstmgr, kDifRstmgrResetInfoPor)) { |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 195 | rstmgr_testutils_pre_reset(&rstmgr); |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 196 | |
| 197 | // Starting clock. |
| 198 | dif_clkmgr_gateable_clock_t clock = kTopEarlgreyGateableClocksIoDiv4Peri; |
Alphan Ulusoy | 9ffc257 | 2022-09-13 14:46:23 -0400 | [diff] [blame] | 199 | LOG_INFO("Next clock to test %d", flash_ctrl_testutils_counter_get(0)); |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 200 | |
| 201 | test_gateable_clocks_off(&clkmgr, &pwrmgr, clock); |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 202 | |
| 203 | // This should never be reached. |
| 204 | LOG_ERROR("This is unreachable since a reset should have been triggered"); |
| 205 | return false; |
| 206 | } else if (rstmgr_testutils_is_reset_info(&rstmgr, |
| 207 | kDifRstmgrResetInfoWatchdog)) { |
Alphan Ulusoy | 9ffc257 | 2022-09-13 14:46:23 -0400 | [diff] [blame] | 208 | dif_clkmgr_gateable_clock_t clock = flash_ctrl_testutils_counter_get(0); |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 209 | LOG_INFO("Got an expected watchdog reset when reading for clock %d", clock); |
| 210 | |
| 211 | size_t actual_size; |
| 212 | CHECK_DIF_OK(dif_rstmgr_cpu_info_get_size(&rstmgr, &actual_size)); |
| 213 | // Verify the cpu crash dump. |
| 214 | dif_rstmgr_cpu_info_dump_segment_t cpu_dump[DIF_RSTMGR_CPU_INFO_MAX_SIZE]; |
| 215 | size_t size_read; |
| 216 | CHECK_DIF_OK(dif_rstmgr_cpu_info_dump_read( |
| 217 | &rstmgr, cpu_dump, DIF_RSTMGR_CPU_INFO_MAX_SIZE, &size_read)); |
| 218 | CHECK(size_read <= DIF_RSTMGR_CPU_INFO_MAX_SIZE); |
| 219 | CHECK(size_read == actual_size); |
| 220 | LOG_INFO("EXC_ADDR = 0x%x", cpu_dump[0]); |
| 221 | LOG_INFO("EXC_PC = 0x%x", cpu_dump[1]); |
| 222 | LOG_INFO("LAST_DATA ADDR = 0x%x", cpu_dump[2]); |
| 223 | LOG_INFO("NEXT_PC = 0x%x", cpu_dump[3]); |
| 224 | LOG_INFO("CURRENT_PC = 0x%x", cpu_dump[4]); |
| 225 | LOG_INFO("PREV_EXC_ADDR = 0x%x", cpu_dump[5]); |
| 226 | LOG_INFO("PREV_EXC_PC = 0x%x", cpu_dump[6]); |
| 227 | LOG_INFO("PREV_VALID = 0x%x", cpu_dump[7]); |
Alphan Ulusoy | 9ffc257 | 2022-09-13 14:46:23 -0400 | [diff] [blame] | 228 | uint32_t expected_hung_address = hung_data_addr[clock]; |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 229 | LOG_INFO("The expected hung address = 0x%x", expected_hung_address); |
| 230 | CHECK(cpu_dump[2] == expected_hung_address, "Unexpected hung address"); |
| 231 | // Mark this clock as tested. |
Alphan Ulusoy | 9ffc257 | 2022-09-13 14:46:23 -0400 | [diff] [blame] | 232 | flash_ctrl_testutils_counter_increment(&flash_ctrl, 0); |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 233 | |
| 234 | if (clock < kTopEarlgreyGateableClocksLast) { |
Alphan Ulusoy | 9ffc257 | 2022-09-13 14:46:23 -0400 | [diff] [blame] | 235 | clock = flash_ctrl_testutils_counter_get(0); |
Guillermo Maturana | 761a139 | 2022-06-09 08:11:27 -0700 | [diff] [blame] | 236 | LOG_INFO("Next clock to test %d", clock); |
| 237 | |
| 238 | rstmgr_testutils_pre_reset(&rstmgr); |
| 239 | |
| 240 | test_gateable_clocks_off(&clkmgr, &pwrmgr, clock); |
| 241 | |
| 242 | // This should never be reached. |
| 243 | LOG_ERROR("This is unreachable since a reset should have been triggered"); |
| 244 | return false; |
| 245 | } else { |
| 246 | return true; |
| 247 | } |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 248 | } else { |
| 249 | dif_rstmgr_reset_info_bitfield_t reset_info; |
Drew Macrae | 8990396 | 2022-07-08 15:17:50 -0400 | [diff] [blame] | 250 | reset_info = rstmgr_testutils_reason_get(); |
Guillermo Maturana | 597283e | 2022-02-22 19:02:29 -0800 | [diff] [blame] | 251 | LOG_ERROR("Unexpected reset_info 0x%x", reset_info); |
| 252 | } |
| 253 | return false; |
| 254 | } |