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 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 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 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 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 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