xref: /rk3399_ARM-atf/plat/intel/soc/common/socfpga_ros.c (revision 62be2a1ae3efcba0bb8b7ec8ef73b2a0f5a437e3)
1*62be2a1aSMahesh Rao /*
2*62be2a1aSMahesh Rao  * Copyright (c) 2024, Intel Corporation. All rights reserved.
3*62be2a1aSMahesh Rao  *
4*62be2a1aSMahesh Rao  * SPDX-License-Identifier: BSD-3-Clause
5*62be2a1aSMahesh Rao  */
6*62be2a1aSMahesh Rao 
7*62be2a1aSMahesh Rao /* system header files*/
8*62be2a1aSMahesh Rao #include <assert.h>
9*62be2a1aSMahesh Rao #include <endian.h>
10*62be2a1aSMahesh Rao #include <string.h>
11*62be2a1aSMahesh Rao 
12*62be2a1aSMahesh Rao /* CRC function header */
13*62be2a1aSMahesh Rao #include <common/tf_crc32.h>
14*62be2a1aSMahesh Rao 
15*62be2a1aSMahesh Rao /* Cadense qspi driver*/
16*62be2a1aSMahesh Rao #include <qspi/cadence_qspi.h>
17*62be2a1aSMahesh Rao 
18*62be2a1aSMahesh Rao /* Mailbox driver*/
19*62be2a1aSMahesh Rao #include <socfpga_mailbox.h>
20*62be2a1aSMahesh Rao 
21*62be2a1aSMahesh Rao #include <socfpga_ros.h>
22*62be2a1aSMahesh Rao 
23*62be2a1aSMahesh Rao static void swap_bits(char *const data, uint32_t len)
24*62be2a1aSMahesh Rao {
25*62be2a1aSMahesh Rao 	uint32_t x, y;
26*62be2a1aSMahesh Rao 	char tmp;
27*62be2a1aSMahesh Rao 
28*62be2a1aSMahesh Rao 	for (x = 0U; x < len; x++) {
29*62be2a1aSMahesh Rao 		tmp = 0U;
30*62be2a1aSMahesh Rao 		for (y = 0U; y < 8; y++) {
31*62be2a1aSMahesh Rao 			tmp <<= 1;
32*62be2a1aSMahesh Rao 			if (data[x] & 1) {
33*62be2a1aSMahesh Rao 				tmp |= 1;
34*62be2a1aSMahesh Rao 			}
35*62be2a1aSMahesh Rao 			data[x] >>= 1;
36*62be2a1aSMahesh Rao 		}
37*62be2a1aSMahesh Rao 		data[x] = tmp;
38*62be2a1aSMahesh Rao 	}
39*62be2a1aSMahesh Rao }
40*62be2a1aSMahesh Rao 
41*62be2a1aSMahesh Rao static uint32_t get_current_image_index(spt_table_t *spt_buf, uint32_t *const img_index)
42*62be2a1aSMahesh Rao {
43*62be2a1aSMahesh Rao 	if (spt_buf == NULL || img_index == NULL) {
44*62be2a1aSMahesh Rao 		return ROS_RET_INVALID;
45*62be2a1aSMahesh Rao 	}
46*62be2a1aSMahesh Rao 
47*62be2a1aSMahesh Rao 	uint32_t ret;
48*62be2a1aSMahesh Rao 	unsigned long current_image;
49*62be2a1aSMahesh Rao 	uint32_t rsu_status[RSU_STATUS_RES_SIZE];
50*62be2a1aSMahesh Rao 
51*62be2a1aSMahesh Rao 	if (spt_buf->partitions < SPT_MIN_PARTITIONS || spt_buf->partitions > SPT_MAX_PARTITIONS) {
52*62be2a1aSMahesh Rao 		return ROS_IMAGE_PARTNUM_OVFL;
53*62be2a1aSMahesh Rao 	}
54*62be2a1aSMahesh Rao 
55*62be2a1aSMahesh Rao 	ret = mailbox_rsu_status(rsu_status, RSU_STATUS_RES_SIZE);
56*62be2a1aSMahesh Rao 	if (ret != MBOX_RET_OK) {
57*62be2a1aSMahesh Rao 		return ROS_RET_NOT_RSU_MODE;
58*62be2a1aSMahesh Rao 	}
59*62be2a1aSMahesh Rao 
60*62be2a1aSMahesh Rao 	current_image = ADDR_64(rsu_status[1], rsu_status[0]);
61*62be2a1aSMahesh Rao 	NOTICE("ROS: Current image is at 0x%08lx\n", current_image);
62*62be2a1aSMahesh Rao 
63*62be2a1aSMahesh Rao 	*img_index = 0U;
64*62be2a1aSMahesh Rao 	for (uint32_t index = 0U ; index < spt_buf->partitions; index++) {
65*62be2a1aSMahesh Rao 		if (spt_buf->partition[index].offset == current_image) {
66*62be2a1aSMahesh Rao 			*img_index = index;
67*62be2a1aSMahesh Rao 			break;
68*62be2a1aSMahesh Rao 		}
69*62be2a1aSMahesh Rao 	}
70*62be2a1aSMahesh Rao 
71*62be2a1aSMahesh Rao 	if (*img_index == 0U) {
72*62be2a1aSMahesh Rao 		return ROS_IMAGE_INDEX_ERR;
73*62be2a1aSMahesh Rao 	}
74*62be2a1aSMahesh Rao 
75*62be2a1aSMahesh Rao 	return ROS_RET_OK;
76*62be2a1aSMahesh Rao }
77*62be2a1aSMahesh Rao 
78*62be2a1aSMahesh Rao static uint32_t load_and_check_spt(spt_table_t *spt_ptr, size_t offset)
79*62be2a1aSMahesh Rao {
80*62be2a1aSMahesh Rao 
81*62be2a1aSMahesh Rao 	if (spt_ptr == NULL || offset == 0U) {
82*62be2a1aSMahesh Rao 		return ROS_RET_INVALID;
83*62be2a1aSMahesh Rao 	}
84*62be2a1aSMahesh Rao 
85*62be2a1aSMahesh Rao 	int ret;
86*62be2a1aSMahesh Rao 	uint32_t calc_crc;
87*62be2a1aSMahesh Rao 	static spt_table_t spt_data;
88*62be2a1aSMahesh Rao 
89*62be2a1aSMahesh Rao 	ret = cad_qspi_read(spt_ptr, offset, SPT_SIZE);
90*62be2a1aSMahesh Rao 	if (ret != 0U) {
91*62be2a1aSMahesh Rao 		return ROS_QSPI_READ_ERROR;
92*62be2a1aSMahesh Rao 	}
93*62be2a1aSMahesh Rao 
94*62be2a1aSMahesh Rao 	if (spt_ptr->magic_number != SPT_MAGIC_NUMBER) {
95*62be2a1aSMahesh Rao 		return ROS_SPT_BAD_MAGIC_NUM;
96*62be2a1aSMahesh Rao 	}
97*62be2a1aSMahesh Rao 
98*62be2a1aSMahesh Rao 	if (spt_ptr->partitions < SPT_MIN_PARTITIONS || spt_ptr->partitions > SPT_MAX_PARTITIONS) {
99*62be2a1aSMahesh Rao 		return ROS_IMAGE_PARTNUM_OVFL;
100*62be2a1aSMahesh Rao 	}
101*62be2a1aSMahesh Rao 
102*62be2a1aSMahesh Rao 	memcpy_s(&spt_data, SPT_SIZE, spt_ptr, SPT_SIZE);
103*62be2a1aSMahesh Rao 	spt_data.checksum = 0U;
104*62be2a1aSMahesh Rao 	swap_bits((char *)&spt_data, SPT_SIZE);
105*62be2a1aSMahesh Rao 
106*62be2a1aSMahesh Rao 	calc_crc = tf_crc32(0, (uint8_t *)&spt_data, SPT_SIZE);
107*62be2a1aSMahesh Rao 	if (bswap32(spt_ptr->checksum) != calc_crc) {
108*62be2a1aSMahesh Rao 		return ROS_SPT_CRC_ERROR;
109*62be2a1aSMahesh Rao 	}
110*62be2a1aSMahesh Rao 
111*62be2a1aSMahesh Rao 	NOTICE("ROS: SPT table at 0x%08lx is verified\n", offset);
112*62be2a1aSMahesh Rao 	return ROS_RET_OK;
113*62be2a1aSMahesh Rao }
114*62be2a1aSMahesh Rao 
115*62be2a1aSMahesh Rao static uint32_t get_spt(spt_table_t *spt_buf)
116*62be2a1aSMahesh Rao {
117*62be2a1aSMahesh Rao 	if (spt_buf == NULL) {
118*62be2a1aSMahesh Rao 		return ROS_RET_INVALID;
119*62be2a1aSMahesh Rao 	}
120*62be2a1aSMahesh Rao 
121*62be2a1aSMahesh Rao 	uint32_t ret;
122*62be2a1aSMahesh Rao 	uint32_t spt_offset[RSU_GET_SPT_RESP_SIZE];
123*62be2a1aSMahesh Rao 
124*62be2a1aSMahesh Rao 	/* Get SPT offset from SDM via mailbox commands */
125*62be2a1aSMahesh Rao 	ret = mailbox_rsu_get_spt_offset(spt_offset, RSU_GET_SPT_RESP_SIZE);
126*62be2a1aSMahesh Rao 	if (ret != MBOX_RET_OK) {
127*62be2a1aSMahesh Rao 		WARN("ROS: Not booted in RSU mode\n");
128*62be2a1aSMahesh Rao 		return ROS_RET_NOT_RSU_MODE;
129*62be2a1aSMahesh Rao 	}
130*62be2a1aSMahesh Rao 
131*62be2a1aSMahesh Rao 	/* Print the SPT table addresses */
132*62be2a1aSMahesh Rao 	VERBOSE("ROS: SPT0 0x%08lx\n", ADDR_64(spt_offset[0], spt_offset[1]));
133*62be2a1aSMahesh Rao 	VERBOSE("ROS: SPT1 0x%08lx\n", ADDR_64(spt_offset[2], spt_offset[3]));
134*62be2a1aSMahesh Rao 
135*62be2a1aSMahesh Rao 	/* Load and validate SPT1*/
136*62be2a1aSMahesh Rao 	ret = load_and_check_spt(spt_buf, ADDR_64(spt_offset[2], spt_offset[3]));
137*62be2a1aSMahesh Rao 	if (ret != ROS_RET_OK) {
138*62be2a1aSMahesh Rao 		/* Load and validate SPT0*/
139*62be2a1aSMahesh Rao 		ret = load_and_check_spt(spt_buf, ADDR_64(spt_offset[0], spt_offset[1]));
140*62be2a1aSMahesh Rao 		if (ret != ROS_RET_OK) {
141*62be2a1aSMahesh Rao 			WARN("Both SPT tables are unusable\n");
142*62be2a1aSMahesh Rao 			return ret;
143*62be2a1aSMahesh Rao 		}
144*62be2a1aSMahesh Rao 	}
145*62be2a1aSMahesh Rao 
146*62be2a1aSMahesh Rao 	return ROS_RET_OK;
147*62be2a1aSMahesh Rao }
148*62be2a1aSMahesh Rao 
149*62be2a1aSMahesh Rao uint32_t ros_qspi_get_ssbl_offset(unsigned long *offset)
150*62be2a1aSMahesh Rao {
151*62be2a1aSMahesh Rao 	if (offset == NULL) {
152*62be2a1aSMahesh Rao 		return ROS_RET_INVALID;
153*62be2a1aSMahesh Rao 	}
154*62be2a1aSMahesh Rao 
155*62be2a1aSMahesh Rao 	uint32_t ret, img_index;
156*62be2a1aSMahesh Rao 	char ssbl_name[SPT_PARTITION_NAME_LENGTH];
157*62be2a1aSMahesh Rao 	static spt_table_t spt;
158*62be2a1aSMahesh Rao 
159*62be2a1aSMahesh Rao 	ret = get_spt(&spt);
160*62be2a1aSMahesh Rao 	if (ret != ROS_RET_OK) {
161*62be2a1aSMahesh Rao 		return ret;
162*62be2a1aSMahesh Rao 	}
163*62be2a1aSMahesh Rao 
164*62be2a1aSMahesh Rao 	ret = get_current_image_index(&spt, &img_index);
165*62be2a1aSMahesh Rao 	if (ret != ROS_RET_OK) {
166*62be2a1aSMahesh Rao 		return ret;
167*62be2a1aSMahesh Rao 	}
168*62be2a1aSMahesh Rao 
169*62be2a1aSMahesh Rao 	if (strncmp(spt.partition[img_index].name, FACTORY_IMAGE,
170*62be2a1aSMahesh Rao 		SPT_PARTITION_NAME_LENGTH) == 0U) {
171*62be2a1aSMahesh Rao 		strlcpy(ssbl_name, FACTORY_SSBL, SPT_PARTITION_NAME_LENGTH);
172*62be2a1aSMahesh Rao 	} else {
173*62be2a1aSMahesh Rao 		strlcpy(ssbl_name, spt.partition[img_index].name,
174*62be2a1aSMahesh Rao 			SPT_PARTITION_NAME_LENGTH);
175*62be2a1aSMahesh Rao 		strlcat(ssbl_name, SSBL_SUFFIX, SPT_PARTITION_NAME_LENGTH);
176*62be2a1aSMahesh Rao 	}
177*62be2a1aSMahesh Rao 
178*62be2a1aSMahesh Rao 	for (uint32_t index = 0U; index < spt.partitions; index++) {
179*62be2a1aSMahesh Rao 		if (strncmp(spt.partition[index].name, ssbl_name,
180*62be2a1aSMahesh Rao 			SPT_PARTITION_NAME_LENGTH) == 0U) {
181*62be2a1aSMahesh Rao 			*offset = spt.partition[index].offset;
182*62be2a1aSMahesh Rao 			NOTICE("ROS: Corresponding SSBL is at 0x%08lx\n", *offset);
183*62be2a1aSMahesh Rao 			return ROS_RET_OK;
184*62be2a1aSMahesh Rao 		}
185*62be2a1aSMahesh Rao 	}
186*62be2a1aSMahesh Rao 
187*62be2a1aSMahesh Rao 	return ROS_IMAGE_INDEX_ERR;
188*62be2a1aSMahesh Rao }
189