xref: /rk3399_ARM-atf/plat/intel/soc/common/socfpga_ros.c (revision ddcce3b13477ca7ee8efbc2081ad2ce904072d2d)
162be2a1aSMahesh Rao /*
262be2a1aSMahesh Rao  * Copyright (c) 2024, Intel Corporation. All rights reserved.
3*bf2c2136SMahesh Rao  * Copyright (c) 2025, Altera Corporation. All rights reserved.
462be2a1aSMahesh Rao  *
562be2a1aSMahesh Rao  * SPDX-License-Identifier: BSD-3-Clause
662be2a1aSMahesh Rao  */
762be2a1aSMahesh Rao 
862be2a1aSMahesh Rao /* system header files*/
962be2a1aSMahesh Rao #include <assert.h>
1062be2a1aSMahesh Rao #include <endian.h>
1162be2a1aSMahesh Rao #include <string.h>
1262be2a1aSMahesh Rao 
1362be2a1aSMahesh Rao /* CRC function header */
1462be2a1aSMahesh Rao #include <common/tf_crc32.h>
1562be2a1aSMahesh Rao 
1662be2a1aSMahesh Rao /* Cadense qspi driver*/
1762be2a1aSMahesh Rao #include <qspi/cadence_qspi.h>
1862be2a1aSMahesh Rao 
1962be2a1aSMahesh Rao /* Mailbox driver*/
2062be2a1aSMahesh Rao #include <socfpga_mailbox.h>
2162be2a1aSMahesh Rao 
2262be2a1aSMahesh Rao #include <socfpga_ros.h>
2362be2a1aSMahesh Rao 
24*bf2c2136SMahesh Rao #define WORD_SIZE	(sizeof(uint32_t))
25*bf2c2136SMahesh Rao 
swap_bits(char * const data,uint32_t len)2662be2a1aSMahesh Rao static void swap_bits(char *const data, uint32_t len)
2762be2a1aSMahesh Rao {
2862be2a1aSMahesh Rao 	uint32_t x, y;
2962be2a1aSMahesh Rao 	char tmp;
3062be2a1aSMahesh Rao 
3162be2a1aSMahesh Rao 	for (x = 0U; x < len; x++) {
3262be2a1aSMahesh Rao 		tmp = 0U;
3362be2a1aSMahesh Rao 		for (y = 0U; y < 8; y++) {
3462be2a1aSMahesh Rao 			tmp <<= 1;
3562be2a1aSMahesh Rao 			if (data[x] & 1) {
3662be2a1aSMahesh Rao 				tmp |= 1;
3762be2a1aSMahesh Rao 			}
3862be2a1aSMahesh Rao 			data[x] >>= 1;
3962be2a1aSMahesh Rao 		}
4062be2a1aSMahesh Rao 		data[x] = tmp;
4162be2a1aSMahesh Rao 	}
4262be2a1aSMahesh Rao }
4362be2a1aSMahesh Rao 
get_current_image_index(spt_table_t * spt_buf,uint32_t * const img_index)4462be2a1aSMahesh Rao static uint32_t get_current_image_index(spt_table_t *spt_buf, uint32_t *const img_index)
4562be2a1aSMahesh Rao {
4662be2a1aSMahesh Rao 	if (spt_buf == NULL || img_index == NULL) {
4762be2a1aSMahesh Rao 		return ROS_RET_INVALID;
4862be2a1aSMahesh Rao 	}
4962be2a1aSMahesh Rao 
5062be2a1aSMahesh Rao 	uint32_t ret;
5162be2a1aSMahesh Rao 	unsigned long current_image;
5262be2a1aSMahesh Rao 	uint32_t rsu_status[RSU_STATUS_RES_SIZE];
5362be2a1aSMahesh Rao 
5462be2a1aSMahesh Rao 	if (spt_buf->partitions < SPT_MIN_PARTITIONS || spt_buf->partitions > SPT_MAX_PARTITIONS) {
5562be2a1aSMahesh Rao 		return ROS_IMAGE_PARTNUM_OVFL;
5662be2a1aSMahesh Rao 	}
5762be2a1aSMahesh Rao 
5862be2a1aSMahesh Rao 	ret = mailbox_rsu_status(rsu_status, RSU_STATUS_RES_SIZE);
5962be2a1aSMahesh Rao 	if (ret != MBOX_RET_OK) {
6062be2a1aSMahesh Rao 		return ROS_RET_NOT_RSU_MODE;
6162be2a1aSMahesh Rao 	}
6262be2a1aSMahesh Rao 
6362be2a1aSMahesh Rao 	current_image = ADDR_64(rsu_status[1], rsu_status[0]);
6462be2a1aSMahesh Rao 	NOTICE("ROS: Current image is at 0x%08lx\n", current_image);
6562be2a1aSMahesh Rao 
6662be2a1aSMahesh Rao 	*img_index = 0U;
6762be2a1aSMahesh Rao 	for (uint32_t index = 0U ; index < spt_buf->partitions; index++) {
6862be2a1aSMahesh Rao 		if (spt_buf->partition[index].offset == current_image) {
6962be2a1aSMahesh Rao 			*img_index = index;
7062be2a1aSMahesh Rao 			break;
7162be2a1aSMahesh Rao 		}
7262be2a1aSMahesh Rao 	}
7362be2a1aSMahesh Rao 
7462be2a1aSMahesh Rao 	if (*img_index == 0U) {
7562be2a1aSMahesh Rao 		return ROS_IMAGE_INDEX_ERR;
7662be2a1aSMahesh Rao 	}
7762be2a1aSMahesh Rao 
7862be2a1aSMahesh Rao 	return ROS_RET_OK;
7962be2a1aSMahesh Rao }
8062be2a1aSMahesh Rao 
load_and_check_spt(spt_table_t * spt_ptr,size_t offset)8162be2a1aSMahesh Rao static uint32_t load_and_check_spt(spt_table_t *spt_ptr, size_t offset)
8262be2a1aSMahesh Rao {
8362be2a1aSMahesh Rao 
8462be2a1aSMahesh Rao 	if (spt_ptr == NULL || offset == 0U) {
8562be2a1aSMahesh Rao 		return ROS_RET_INVALID;
8662be2a1aSMahesh Rao 	}
8762be2a1aSMahesh Rao 
8862be2a1aSMahesh Rao 	int ret;
8962be2a1aSMahesh Rao 	uint32_t calc_crc;
9062be2a1aSMahesh Rao 	static spt_table_t spt_data;
9162be2a1aSMahesh Rao 
9262be2a1aSMahesh Rao 	ret = cad_qspi_read(spt_ptr, offset, SPT_SIZE);
9362be2a1aSMahesh Rao 	if (ret != 0U) {
9462be2a1aSMahesh Rao 		return ROS_QSPI_READ_ERROR;
9562be2a1aSMahesh Rao 	}
9662be2a1aSMahesh Rao 
9762be2a1aSMahesh Rao 	if (spt_ptr->magic_number != SPT_MAGIC_NUMBER) {
9862be2a1aSMahesh Rao 		return ROS_SPT_BAD_MAGIC_NUM;
9962be2a1aSMahesh Rao 	}
10062be2a1aSMahesh Rao 
10162be2a1aSMahesh Rao 	if (spt_ptr->partitions < SPT_MIN_PARTITIONS || spt_ptr->partitions > SPT_MAX_PARTITIONS) {
10262be2a1aSMahesh Rao 		return ROS_IMAGE_PARTNUM_OVFL;
10362be2a1aSMahesh Rao 	}
10462be2a1aSMahesh Rao 
105*bf2c2136SMahesh Rao 	memcpy_s(&spt_data, (sizeof(spt_table_t) / WORD_SIZE),
106*bf2c2136SMahesh Rao 		 spt_ptr, (SPT_SIZE / WORD_SIZE));
10762be2a1aSMahesh Rao 	spt_data.checksum = 0U;
10862be2a1aSMahesh Rao 	swap_bits((char *)&spt_data, SPT_SIZE);
10962be2a1aSMahesh Rao 
11062be2a1aSMahesh Rao 	calc_crc = tf_crc32(0, (uint8_t *)&spt_data, SPT_SIZE);
11162be2a1aSMahesh Rao 	if (bswap32(spt_ptr->checksum) != calc_crc) {
11262be2a1aSMahesh Rao 		return ROS_SPT_CRC_ERROR;
11362be2a1aSMahesh Rao 	}
11462be2a1aSMahesh Rao 
11562be2a1aSMahesh Rao 	NOTICE("ROS: SPT table at 0x%08lx is verified\n", offset);
11662be2a1aSMahesh Rao 	return ROS_RET_OK;
11762be2a1aSMahesh Rao }
11862be2a1aSMahesh Rao 
get_spt(spt_table_t * spt_buf)11962be2a1aSMahesh Rao static uint32_t get_spt(spt_table_t *spt_buf)
12062be2a1aSMahesh Rao {
12162be2a1aSMahesh Rao 	if (spt_buf == NULL) {
12262be2a1aSMahesh Rao 		return ROS_RET_INVALID;
12362be2a1aSMahesh Rao 	}
12462be2a1aSMahesh Rao 
12562be2a1aSMahesh Rao 	uint32_t ret;
12662be2a1aSMahesh Rao 	uint32_t spt_offset[RSU_GET_SPT_RESP_SIZE];
12762be2a1aSMahesh Rao 
12862be2a1aSMahesh Rao 	/* Get SPT offset from SDM via mailbox commands */
12962be2a1aSMahesh Rao 	ret = mailbox_rsu_get_spt_offset(spt_offset, RSU_GET_SPT_RESP_SIZE);
13062be2a1aSMahesh Rao 	if (ret != MBOX_RET_OK) {
13162be2a1aSMahesh Rao 		WARN("ROS: Not booted in RSU mode\n");
13262be2a1aSMahesh Rao 		return ROS_RET_NOT_RSU_MODE;
13362be2a1aSMahesh Rao 	}
13462be2a1aSMahesh Rao 
13562be2a1aSMahesh Rao 	/* Print the SPT table addresses */
13662be2a1aSMahesh Rao 	VERBOSE("ROS: SPT0 0x%08lx\n", ADDR_64(spt_offset[0], spt_offset[1]));
13762be2a1aSMahesh Rao 	VERBOSE("ROS: SPT1 0x%08lx\n", ADDR_64(spt_offset[2], spt_offset[3]));
13862be2a1aSMahesh Rao 
13962be2a1aSMahesh Rao 	/* Load and validate SPT1*/
14062be2a1aSMahesh Rao 	ret = load_and_check_spt(spt_buf, ADDR_64(spt_offset[2], spt_offset[3]));
14162be2a1aSMahesh Rao 	if (ret != ROS_RET_OK) {
14262be2a1aSMahesh Rao 		/* Load and validate SPT0*/
14362be2a1aSMahesh Rao 		ret = load_and_check_spt(spt_buf, ADDR_64(spt_offset[0], spt_offset[1]));
14462be2a1aSMahesh Rao 		if (ret != ROS_RET_OK) {
14562be2a1aSMahesh Rao 			WARN("Both SPT tables are unusable\n");
14662be2a1aSMahesh Rao 			return ret;
14762be2a1aSMahesh Rao 		}
14862be2a1aSMahesh Rao 	}
14962be2a1aSMahesh Rao 
15062be2a1aSMahesh Rao 	return ROS_RET_OK;
15162be2a1aSMahesh Rao }
15262be2a1aSMahesh Rao 
ros_qspi_get_ssbl_offset(unsigned long * offset)15362be2a1aSMahesh Rao uint32_t ros_qspi_get_ssbl_offset(unsigned long *offset)
15462be2a1aSMahesh Rao {
15562be2a1aSMahesh Rao 	if (offset == NULL) {
15662be2a1aSMahesh Rao 		return ROS_RET_INVALID;
15762be2a1aSMahesh Rao 	}
15862be2a1aSMahesh Rao 
15962be2a1aSMahesh Rao 	uint32_t ret, img_index;
160*bf2c2136SMahesh Rao 	size_t len;
16162be2a1aSMahesh Rao 	char ssbl_name[SPT_PARTITION_NAME_LENGTH];
16262be2a1aSMahesh Rao 	static spt_table_t spt;
16362be2a1aSMahesh Rao 
16462be2a1aSMahesh Rao 	ret = get_spt(&spt);
16562be2a1aSMahesh Rao 	if (ret != ROS_RET_OK) {
16662be2a1aSMahesh Rao 		return ret;
16762be2a1aSMahesh Rao 	}
16862be2a1aSMahesh Rao 
16962be2a1aSMahesh Rao 	ret = get_current_image_index(&spt, &img_index);
17062be2a1aSMahesh Rao 	if (ret != ROS_RET_OK) {
17162be2a1aSMahesh Rao 		return ret;
17262be2a1aSMahesh Rao 	}
17362be2a1aSMahesh Rao 
17462be2a1aSMahesh Rao 	if (strncmp(spt.partition[img_index].name, FACTORY_IMAGE,
17562be2a1aSMahesh Rao 		SPT_PARTITION_NAME_LENGTH) == 0U) {
176*bf2c2136SMahesh Rao 		strcpy_secure(ssbl_name, SPT_PARTITION_NAME_LENGTH, FACTORY_SSBL);
17762be2a1aSMahesh Rao 	} else {
178*bf2c2136SMahesh Rao 		strcpy_secure(ssbl_name, SPT_PARTITION_NAME_LENGTH, SSBL_PREFIX);
179*bf2c2136SMahesh Rao 		len = strnlen_secure(ssbl_name, SPT_PARTITION_NAME_LENGTH);
180*bf2c2136SMahesh Rao 		strcpy_secure(ssbl_name + len, SPT_PARTITION_NAME_LENGTH - len,
181*bf2c2136SMahesh Rao 			 spt.partition[img_index].name);
18262be2a1aSMahesh Rao 	}
18362be2a1aSMahesh Rao 
18462be2a1aSMahesh Rao 	for (uint32_t index = 0U; index < spt.partitions; index++) {
18562be2a1aSMahesh Rao 		if (strncmp(spt.partition[index].name, ssbl_name,
18662be2a1aSMahesh Rao 			SPT_PARTITION_NAME_LENGTH) == 0U) {
18762be2a1aSMahesh Rao 			*offset = spt.partition[index].offset;
18862be2a1aSMahesh Rao 			NOTICE("ROS: Corresponding SSBL is at 0x%08lx\n", *offset);
18962be2a1aSMahesh Rao 			return ROS_RET_OK;
19062be2a1aSMahesh Rao 		}
19162be2a1aSMahesh Rao 	}
19262be2a1aSMahesh Rao 
19362be2a1aSMahesh Rao 	return ROS_IMAGE_INDEX_ERR;
19462be2a1aSMahesh Rao }
195