1 /* 2 * Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <common/debug.h> 8 9 #include <ddrphy_phyinit.h> 10 11 #include <drivers/delay_timer.h> 12 13 #include <lib/mmio.h> 14 15 #include <platform_def.h> 16 17 /* Firmware major messages */ 18 #define FW_MAJ_MSG_TRAINING_SUCCESS 0x0000007U 19 #define FW_MAJ_MSG_START_STREAMING 0x0000008U 20 #define FW_MAJ_MSG_TRAINING_FAILED 0x00000FFU 21 22 #define PHYINIT_DELAY_1US 1U 23 #define PHYINIT_DELAY_10US 10U 24 #define PHYINIT_TIMEOUT_US_1S 1000000U 25 wait_uctwriteprotshadow(bool state)26static int wait_uctwriteprotshadow(bool state) 27 { 28 uint64_t timeout; 29 uint16_t read_data; 30 uint16_t value = state ? BIT(0) : 0U; 31 32 timeout = timeout_init_us(PHYINIT_TIMEOUT_US_1S); 33 34 do { 35 read_data = mmio_read_16((uintptr_t)(DDRPHYC_BASE + 36 (4U * (TAPBONLY | CSR_UCTSHADOWREGS_ADDR)))); 37 udelay(PHYINIT_DELAY_1US); 38 if (timeout_elapsed(timeout)) { 39 return -1; 40 } 41 } while ((read_data & BIT(0)) != value); 42 43 return 0; 44 } 45 ack_message_receipt(void)46static int ack_message_receipt(void) 47 { 48 int ret; 49 50 /* Acknowledge the receipt of the message */ 51 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_DCTWRITEPROT_ADDR))), 0U); 52 53 udelay(PHYINIT_DELAY_1US); 54 55 ret = wait_uctwriteprotshadow(true); 56 if (ret != 0) { 57 return ret; 58 } 59 60 /* Complete the 4-phase protocol */ 61 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_DCTWRITEPROT_ADDR))), 1U); 62 63 udelay(PHYINIT_DELAY_1US); 64 65 return 0; 66 } 67 get_major_message(uint32_t * msg)68static int get_major_message(uint32_t *msg) 69 { 70 uint16_t message_number; 71 int ret; 72 73 ret = wait_uctwriteprotshadow(false); 74 if (ret != 0) { 75 return ret; 76 } 77 78 message_number = mmio_read_16((uintptr_t)(DDRPHYC_BASE + 79 (4U * (TAPBONLY | 80 CSR_UCTWRITEONLYSHADOW_ADDR)))); 81 82 ret = ack_message_receipt(); 83 if (ret != 0) { 84 return ret; 85 } 86 87 *msg = (uint32_t)message_number; 88 89 return 0; 90 } 91 get_streaming_message(uint32_t * msg)92static int get_streaming_message(uint32_t *msg) 93 { 94 uint16_t stream_word_lower_part; 95 uint16_t stream_word_upper_part; 96 int ret; 97 98 ret = wait_uctwriteprotshadow(false); 99 if (ret != 0) { 100 return ret; 101 } 102 103 stream_word_lower_part = mmio_read_16((uintptr_t)(DDRPHYC_BASE + 104 (4U * (TAPBONLY | 105 CSR_UCTWRITEONLYSHADOW_ADDR)))); 106 107 stream_word_upper_part = mmio_read_16((uintptr_t)(DDRPHYC_BASE + 108 (4U * (TAPBONLY | 109 CSR_UCTDATWRITEONLYSHADOW_ADDR)))); 110 111 ret = ack_message_receipt(); 112 if (ret != 0) { 113 return ret; 114 } 115 116 *msg = (uint32_t)stream_word_lower_part | ((uint32_t)stream_word_upper_part << 16); 117 118 return 0; 119 } 120 121 /* 122 * Implements the mechanism to wait for completion of training firmware execution. 123 * 124 * The purpose of user this function is to wait for firmware to finish training. 125 * The user can either implement a counter to wait or implement the polling 126 * mechanism (our choice here). The wait time is highly dependent on the training features 127 * enabled via sequencectrl input to the message block. 128 * 129 * The default behavior of this function is to print comments relating to this 130 * process. A function call of the same name will be printed in the output text 131 * file. 132 * 133 * The user can choose to leave this function as is, or implement mechanism to 134 * trigger mailbox poling event in simulation. 135 * 136 * \return 0 on success. 137 */ ddrphy_phyinit_usercustom_g_waitfwdone(void)138int ddrphy_phyinit_usercustom_g_waitfwdone(void) 139 { 140 uint32_t fw_major_message; 141 int ret; 142 143 do { 144 ret = get_major_message(&fw_major_message); 145 if (ret != 0) { 146 return ret; 147 } 148 149 VERBOSE("fw_major_message = %x\n", (unsigned int)fw_major_message); 150 151 if (fw_major_message == FW_MAJ_MSG_START_STREAMING) { 152 uint32_t i; 153 uint32_t read_data; 154 uint32_t stream_len; 155 156 ret = get_streaming_message(&read_data); 157 if (ret != 0) { 158 return ret; 159 } 160 161 stream_len = read_data & 0xFFFFU; 162 163 for (i = 0U; i < stream_len; i++) { 164 ret = get_streaming_message(&read_data); 165 if (ret != 0) { 166 return ret; 167 } 168 169 VERBOSE("streaming message = %x\n", (unsigned int)read_data); 170 } 171 } 172 } while ((fw_major_message != FW_MAJ_MSG_TRAINING_SUCCESS) && 173 (fw_major_message != FW_MAJ_MSG_TRAINING_FAILED)); 174 175 udelay(PHYINIT_DELAY_10US); 176 177 if (fw_major_message == FW_MAJ_MSG_TRAINING_FAILED) { 178 ERROR("%s Training has failed.\n", __func__); 179 return -1; 180 } 181 182 return 0; 183 } 184