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