xref: /rk3399_ARM-atf/drivers/st/ddr/phy/phyinit/usercustom/ddrphy_phyinit_usercustom_g_waitfwdone.c (revision eaaf26e3e6ac347cbfda00b6ba7d327e715d68f0)
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)26 static 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)46 static 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)68 static 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)92 static 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)138 int 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