1 /* 2 * Copyright (C) 2022-2024, STMicroelectronics - All Rights Reserved 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <common/debug.h> 8 #include <drivers/st/stm32mp_ddr_test.h> 9 #include <lib/mmio.h> 10 11 #include <platform_def.h> 12 13 #ifdef __aarch64__ 14 #define DDR_PATTERN 0xAAAAAAAAAAAAAAAAUL 15 #define DDR_ANTIPATTERN 0x5555555555555555UL 16 #else /* !__aarch64__ */ 17 #define DDR_PATTERN 0xAAAAAAAAU 18 #define DDR_ANTIPATTERN 0x55555555U 19 #endif /* __aarch64__ */ 20 21 static void mmio_write_pattern(uintptr_t addr, u_register_t value) 22 { 23 #ifdef __aarch64__ 24 mmio_write_64(addr, (uint64_t)value); 25 #else /* !__aarch64__ */ 26 mmio_write_32(addr, (uint32_t)value); 27 #endif /* __aarch64__ */ 28 } 29 30 static u_register_t mmio_read_pattern(uintptr_t addr) 31 { 32 #ifdef __aarch64__ 33 return (u_register_t)mmio_read_64(addr); 34 #else /* !__aarch64__ */ 35 return (u_register_t)mmio_read_32(addr); 36 #endif /* __aarch64__ */ 37 } 38 39 /******************************************************************************* 40 * This function tests a simple read/write access to the DDR. 41 * Note that the previous content is restored after test. 42 * Returns 0 if success, and address value else. 43 ******************************************************************************/ 44 uintptr_t stm32mp_ddr_test_rw_access(void) 45 { 46 u_register_t saved_value = mmio_read_pattern(STM32MP_DDR_BASE); 47 48 mmio_write_pattern(STM32MP_DDR_BASE, DDR_PATTERN); 49 50 if (mmio_read_pattern(STM32MP_DDR_BASE) != DDR_PATTERN) { 51 return STM32MP_DDR_BASE; 52 } 53 54 mmio_write_pattern(STM32MP_DDR_BASE, saved_value); 55 56 return 0UL; 57 } 58 59 /******************************************************************************* 60 * This function tests the DDR data bus wiring. 61 * This is inspired from the Data Bus Test algorithm written by Michael Barr 62 * in "Programming Embedded Systems in C and C++" book. 63 * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/ 64 * File: memtest.c - This source code belongs to Public Domain. 65 * Returns 0 if success, and address value else. 66 ******************************************************************************/ 67 uintptr_t stm32mp_ddr_test_data_bus(void) 68 { 69 u_register_t pattern; 70 71 for (pattern = 1U; pattern != 0U; pattern <<= 1U) { 72 mmio_write_pattern(STM32MP_DDR_BASE, pattern); 73 74 if (mmio_read_pattern(STM32MP_DDR_BASE) != pattern) { 75 return STM32MP_DDR_BASE; 76 } 77 } 78 79 return 0UL; 80 } 81 82 /******************************************************************************* 83 * This function tests the DDR address bus wiring. 84 * This is inspired from the Data Bus Test algorithm written by Michael Barr 85 * in "Programming Embedded Systems in C and C++" book. 86 * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/ 87 * File: memtest.c - This source code belongs to Public Domain. 88 * size: size in bytes of the DDR memory device. 89 * Returns 0 if success, and address value else. 90 ******************************************************************************/ 91 uintptr_t stm32mp_ddr_test_addr_bus(size_t size) 92 { 93 size_t addressmask = size - 1U; 94 size_t offset; 95 size_t testoffset = 0U; 96 97 /* Write the default pattern at each of the power-of-two offsets. */ 98 for (offset = sizeof(u_register_t); (offset & addressmask) != 0U; 99 offset <<= 1U) { 100 mmio_write_pattern(STM32MP_DDR_BASE + offset, DDR_PATTERN); 101 } 102 103 /* Check for address bits stuck high. */ 104 mmio_write_pattern(STM32MP_DDR_BASE + testoffset, DDR_ANTIPATTERN); 105 106 for (offset = sizeof(u_register_t); (offset & addressmask) != 0U; 107 offset <<= 1U) { 108 if (mmio_read_pattern(STM32MP_DDR_BASE + offset) != DDR_PATTERN) { 109 return STM32MP_DDR_BASE + offset; 110 } 111 } 112 113 mmio_write_pattern(STM32MP_DDR_BASE + testoffset, DDR_PATTERN); 114 115 /* Check for address bits stuck low or shorted. */ 116 for (testoffset = sizeof(u_register_t); (testoffset & addressmask) != 0U; 117 testoffset <<= 1U) { 118 mmio_write_pattern(STM32MP_DDR_BASE + testoffset, DDR_ANTIPATTERN); 119 120 if (mmio_read_pattern(STM32MP_DDR_BASE) != DDR_PATTERN) { 121 return STM32MP_DDR_BASE; 122 } 123 124 for (offset = sizeof(u_register_t); (offset & addressmask) != 0U; 125 offset <<= 1U) { 126 if ((mmio_read_pattern(STM32MP_DDR_BASE + offset) != DDR_PATTERN) && 127 (offset != testoffset)) { 128 return STM32MP_DDR_BASE + offset; 129 } 130 } 131 132 mmio_write_pattern(STM32MP_DDR_BASE + testoffset, DDR_PATTERN); 133 } 134 135 return 0UL; 136 } 137 138 /******************************************************************************* 139 * This function checks the DDR size. It has to be run with Data Cache off. 140 * This test is run before data have been put in DDR, and is only done for 141 * cold boot. The DDR data can then be overwritten, and it is not useful to 142 * restore its content. 143 * Returns DDR computed size. 144 ******************************************************************************/ 145 size_t stm32mp_ddr_check_size(void) 146 { 147 size_t offset = sizeof(u_register_t); 148 149 mmio_write_pattern(STM32MP_DDR_BASE, DDR_PATTERN); 150 151 while (offset < STM32MP_DDR_MAX_SIZE) { 152 mmio_write_pattern(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN); 153 dsb(); 154 155 if (mmio_read_pattern(STM32MP_DDR_BASE) != DDR_PATTERN) { 156 break; 157 } 158 159 offset <<= 1U; 160 } 161 162 return offset; 163 } 164