1 /*
2  * Copyright (c) 2022, Intel Corporation. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <errno.h>
9 #include <common/debug.h>
10 #include "ddr.h"
11 #include <lib/mmio.h>
12 #include "socfpga_handoff.h"
13 
ddr_calibration_check(void)14 int ddr_calibration_check(void)
15 {
16 	// DDR calibration check
17 	int status = 0;
18 	uint32_t u32data_read = 0;
19 
20 	NOTICE("DDR: Access address 0x%x:...\n", IO96B_0_REG_BASE);
21 	u32data_read = mmio_read_32(IO96B_0_REG_BASE);
22 	NOTICE("DDR: Access address 0x%x: read 0x%04x\n", IO96B_0_REG_BASE, u32data_read);
23 
24 	if (u32data_read == -EPERM) {
25 		status = -EPERM;
26 		assert(u32data_read);
27 	}
28 
29 	u32data_read = 0x0;
30 	NOTICE("DDR: Access address 0x%x: ...\n", IO96B_1_REG_BASE);
31 	u32data_read = mmio_read_32(IO96B_1_REG_BASE);
32 	NOTICE("DDR: Access address 0x%x: read 0x%04x\n", IO96B_1_REG_BASE, u32data_read);
33 
34 	if (u32data_read == -EPERM) {
35 		status = -EPERM;
36 		assert(u32data_read);
37 	}
38 
39 	return status;
40 }
41 
iossm_mb_init(void)42 int iossm_mb_init(void)
43 {
44 	// int status;
45 
46 	// Update according to IOSSM mailbox spec
47 
48 	// if (status) {
49 		// return status;
50 	// }
51 
52 	return 0;
53 }
54 
wait_respond(uint16_t timeout)55 int wait_respond(uint16_t timeout)
56 {
57 	uint32_t status = 0;
58 	uint32_t count = 0;
59 	uint32_t data = 0;
60 
61 	/* Wait status command response ready */
62 	do {
63 		data = mmio_read_32(IO96B_CSR_REG(CMD_RESPONSE_STATUS));
64 		count++;
65 		if (count >= timeout) {
66 			return -ETIMEDOUT;
67 		}
68 
69 	} while (STATUS_COMMAND_RESPONSE(data) != STATUS_COMMAND_RESPONSE_READY);
70 
71 	status = (data & STATUS_GENERAL_ERROR_MASK) >> STATUS_GENERAL_ERROR_OFFSET;
72 	if (status != 0) {
73 		return status;
74 	}
75 
76 	status = (data & STATUS_CMD_RESPONSE_ERROR_MASK) >> STATUS_CMD_RESPONSE_ERROR_OFFSET;
77 	if (status != 0) {
78 		return status;
79 	}
80 
81 	return status;
82 }
83 
iossm_mb_read_response(void)84 int iossm_mb_read_response(void)
85 {
86 	uint32_t status = 0;
87 	unsigned int i;
88 	uint32_t resp_data[IOSSM_RESP_MAX_WORD_SIZE];
89 	uint32_t resp_param_reg;
90 
91 	// Check STATUS_CMD_RESPONSE_DATA_PTR_VALID in
92 	// STATUS_COMMAND_RESPONSE to ensure data pointer response
93 
94 	/* Read CMD_RESPONSE_STATUS and CMD_RESPONSE_DATA_* */
95 	resp_data[0] = mmio_read_32(IO96B_CSR_REG(CMD_RESPONSE_STATUS));
96 	resp_data[0] = (resp_data[0] & CMD_RESPONSE_DATA_SHORT_MASK) >>
97 			CMD_RESPONSE_DATA_SHORT_OFFSET;
98 	resp_param_reg = CMD_RESPONSE_STATUS;
99 	for (i = 1; i < IOSSM_RESP_MAX_WORD_SIZE; i++) {
100 		resp_param_reg = resp_param_reg - CMD_RESPONSE_OFFSET;
101 		resp_data[i] = mmio_read_32(IO96B_CSR_REG(resp_param_reg));
102 	}
103 
104 	/* Wait for STATUS_COMMAND_RESPONSE_READY*/
105 	status = wait_respond(1000);
106 
107 	/* Read CMD_RESPONSE_STATUS and CMD_RESPONSE_DATA_* */
108 	mmio_setbits_32(STATUS_COMMAND_RESPONSE(IO96B_CSR_REG(
109 			CMD_RESPONSE_STATUS)),
110 			STATUS_COMMAND_RESPONSE_READY_CLEAR);
111 
112 	return status;
113 }
114 
iossm_mb_send(uint32_t cmd_target_ip_type,uint32_t cmd_target_ip_instance_id,uint32_t cmd_type,uint32_t cmd_opcode,uint32_t * args,unsigned int len)115 int iossm_mb_send(uint32_t cmd_target_ip_type, uint32_t cmd_target_ip_instance_id,
116 			uint32_t cmd_type, uint32_t cmd_opcode, uint32_t *args,
117 			unsigned int len)
118 {
119 	unsigned int i;
120 	uint32_t status = 0;
121 	uint32_t cmd_req;
122 	uint32_t cmd_param_reg;
123 
124 	cmd_target_ip_type = (cmd_target_ip_type & CMD_TARGET_IP_TYPE_MASK) <<
125 				CMD_TARGET_IP_TYPE_OFFSET;
126 	cmd_target_ip_instance_id = (cmd_target_ip_instance_id &
127 				CMD_TARGET_IP_INSTANCE_ID_MASK) <<
128 				CMD_TARGET_IP_INSTANCE_ID_OFFSET;
129 	cmd_type = (cmd_type & CMD_TYPE_MASK) << CMD_TYPE_OFFSET;
130 	cmd_opcode = (cmd_opcode & CMD_OPCODE_MASK) << CMD_OPCODE_OFFSET;
131 	cmd_req = cmd_target_ip_type | cmd_target_ip_instance_id | cmd_type |
132 			cmd_opcode;
133 
134 	/* send mailbox request */
135 	IOSSM_MB_WRITE(IO96B_CSR_REG(CMD_REQ), cmd_req);
136 	if (len != 0) {
137 		cmd_param_reg = CMD_REQ;
138 		for (i = 0; i < len; i++) {
139 			cmd_param_reg = cmd_param_reg - CMD_PARAM_OFFSET;
140 			IOSSM_MB_WRITE(IO96B_CSR_REG(cmd_param_reg), args[i]);
141 		}
142 	}
143 
144 	status = iossm_mb_read_response();
145 	if (status != 0) {
146 		return status;
147 	}
148 
149 	return status;
150 }
151 
ddr_iossm_mailbox_cmd(uint32_t cmd_opcode)152 int ddr_iossm_mailbox_cmd(uint32_t cmd_opcode)
153 {
154 	// IOSSM
155 	uint32_t status = 0;
156 	unsigned int i = 0;
157 	uint32_t payload[IOSSM_CMD_MAX_WORD_SIZE] = {0U};
158 
159 	switch (cmd_opcode) {
160 	case CMD_INIT:
161 		status = iossm_mb_init();
162 		break;
163 
164 	case OPCODE_GET_MEM_INTF_INFO:
165 		status = iossm_mb_send(0, 0, MBOX_CMD_GET_SYS_INFO,
166 		OPCODE_GET_MEM_INTF_INFO, payload, i);
167 		break;
168 
169 	case OPCODE_GET_MEM_TECHNOLOGY:
170 		status = iossm_mb_send(0, 0, MBOX_CMD_GET_MEM_INFO,
171 		OPCODE_GET_MEM_TECHNOLOGY, payload, i);
172 		break;
173 
174 	case OPCODE_GET_MEM_WIDTH_INFO:
175 		status = iossm_mb_send(0, 0, MBOX_CMD_GET_MEM_INFO,
176 		OPCODE_GET_MEM_WIDTH_INFO, payload, i);
177 		break;
178 
179 	case OPCODE_ECC_ENABLE_STATUS:
180 		status = iossm_mb_send(0, 0,
181 		MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_ECC_ENABLE_STATUS,
182 		payload, i);
183 		break;
184 
185 	case OPCODE_ECC_INTERRUPT_MASK:
186 		// payload[i] = CMD_PARAM_0 [16:0]: ECC_INTERRUPT_MASK
187 		status = iossm_mb_send(0, 0,
188 		MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_ECC_INTERRUPT_MASK,
189 		payload, i);
190 		break;
191 
192 	case OPCODE_ECC_SCRUB_MODE_0_START:
193 		// payload[i] = CMD_PARAM_0 [15:0]: ECC_SCRUB_INTERVAL
194 		//i++;
195 		// payload[i] = CMD_PARAM_1 [11:0]: ECC_SCRUB_LEN
196 		//i++;
197 		// payload[i] = CMD_PARAM_2 [0:0]: ECC_SCRUB_FULL_MEM
198 		//i++;
199 		// payload[i]= CMD_PARAM_3 [31:0]: ECC_SCRUB_START_ADDR [31:0]
200 		//i++;
201 		// payload[i] = CMD_PARAM_4 [5:0]: ECC_SCRUB_START_ADDR [36:32]
202 		//i++;
203 		// payload[i] = CMD_PARAM_5 [31:0]: ECC_SCRUB_END_ADDR [31:0]
204 		//i++;
205 		// payload[i] = CMD_PARAM_6 [5:0]: ECC_SCRUB_END_ADDR [36:32]
206 		//i++;
207 		status = iossm_mb_send(0, 0,
208 		MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_ECC_SCRUB_MODE_0_START,
209 		payload, i);
210 		break;
211 
212 	case OPCODE_ECC_SCRUB_MODE_1_START:
213 		// payload[i] = CMD_PARAM_0 [15:0]: ECC_SCRUB_IDLE_CNT
214 		//i++;
215 		// payload[i] = CMD_PARAM_1 [11:0]: ECC_SCRUB_LEN
216 		//i++;
217 		// payload[i] = CMD_PARAM_2 [0:0]: ECC_SCRUB_FULL_MEM
218 		//i++;
219 		// payload[i] = CMD_PARAM_3 [31:0]: ECC_SCRUB_START_ADDR [31:0]
220 		//i++;
221 		// payload[i] = CMD_PARAM_4 [5:0]: ECC_SCRUB_START_ADDR [36:32]
222 		//i++;
223 		// payload[i] = CMD_PARAM_5 [31:0]: ECC_SCRUB_END_ADDR [31:0]
224 		//i++;
225 		// payload[i] = CMD_PARAM_6 [5:0]: ECC_SCRUB_END_ADDR [36:32]
226 		//i++;
227 		status = iossm_mb_send(0, 0,
228 		MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_ECC_SCRUB_MODE_1_START,
229 		payload, i);
230 		break;
231 
232 	case OPCODE_BIST_RESULTS_STATUS:
233 		status = iossm_mb_send(0, 0,
234 		MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_BIST_RESULTS_STATUS,
235 		payload, i);
236 		break;
237 
238 	case OPCODE_BIST_MEM_INIT_START:
239 		status = iossm_mb_send(0, 0,
240 		MBOX_CMD_TRIG_CONTROLLER_OP, OPCODE_BIST_MEM_INIT_START,
241 		payload, i);
242 		break;
243 
244 	case OPCODE_TRIG_MEM_CAL:
245 		status = iossm_mb_send(0, 0, MBOX_CMD_TRIG_MEM_CAL_OP,
246 		OPCODE_TRIG_MEM_CAL, payload, i);
247 		break;
248 
249 	default:
250 		break;
251 	}
252 
253 	if (status == -EPERM) {
254 		assert(status);
255 	}
256 
257 	return status;
258 }
259 
ddr_config_handoff(handoff * hoff_ptr)260 int ddr_config_handoff(handoff *hoff_ptr)
261 {
262 	/* Populate DDR handoff data */
263 	/* TODO: To add in DDR handoff configuration once available */
264 	return 0;
265 }
266 
267 // DDR firewall and non secure access
ddr_enable_ns_access(void)268 void ddr_enable_ns_access(void)
269 {
270 	/* Please set the ddr non secure registers accordingly */
271 
272 	mmio_setbits_32(CCU_REG(DMI0_DMIUSMCTCR),
273 			CCU_DMI_ALLOCEN | CCU_DMI_LOOKUPEN);
274 	mmio_setbits_32(CCU_REG(DMI1_DMIUSMCTCR),
275 			CCU_DMI_ALLOCEN | CCU_DMI_LOOKUPEN);
276 
277 	/* TODO: To add in CCU NCORE OCRAM bypass mask for non secure registers */
278 	NOTICE("DDR non secure configured\n");
279 }
280 
ddr_enable_firewall(void)281 void ddr_enable_firewall(void)
282 {
283 	/* Please set the ddr firewall registers accordingly */
284 	/* TODO: To add in CCU NCORE OCRAM bypass mask for firewall registers */
285 	NOTICE("DDR firewall enabled\n");
286 }
287 
is_ddr_init_in_progress(void)288 bool is_ddr_init_in_progress(void)
289 {
290 	uint32_t reg = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_POR_0));
291 
292 	if (reg & SOCFPGA_SYSMGR_BOOT_SCRATCH_POR_0_MASK) {
293 		return true;
294 	}
295 	return false;
296 }
297 
ddr_init(void)298 int ddr_init(void)
299 {
300 	// DDR driver initialization
301 	int status = -EPERM;
302 	uint32_t cmd_opcode = 0;
303 
304 	// Check and set Boot Scratch Register
305 	if (is_ddr_init_in_progress()) {
306 		return status;
307 	}
308 	mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_POR_0), 0x01);
309 
310 	// Populate DDR handoff data
311 	handoff reverse_handoff_ptr;
312 
313 	if (!socfpga_get_handoff(&reverse_handoff_ptr)) {
314 		assert(status);
315 	}
316 	status = ddr_config_handoff(&reverse_handoff_ptr);
317 	if (status == -EPERM) {
318 		assert(status);
319 	}
320 
321 	// CCU and firewall setup
322 	ddr_enable_ns_access();
323 	ddr_enable_firewall();
324 
325 	// DDR calibration check
326 	status = ddr_calibration_check();
327 	if (status == -EPERM) {
328 		assert(status);
329 	}
330 
331 	// DDR mailbox command
332 	status = ddr_iossm_mailbox_cmd(cmd_opcode);
333 	if (status != 0) {
334 		assert(status);
335 	}
336 
337 	// Check and set Boot Scratch Register
338 	mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_POR_0), 0x00);
339 
340 	NOTICE("DDR init successfully\n");
341 	return status;
342 }
343