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