// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (c) 2019 Amlogic, Inc. All rights reserved. */ #include #include #include #include #define SIP_SMC_SCMI_CMD 0x820000C1 #define SCMI_SUBID_GET_SHMEM_ADDR 0x1 static uint32_t get_scmi_shmem_addr(void) { struct arm_smccc_res res; arm_smccc_smc(SIP_SMC_SCMI_CMD, SCMI_SUBID_GET_SHMEM_ADDR, 0, 0, 0, 0, 0, 0, &res); return res.a0; } static int ftd_get_root_address_cells(void) { char *address_cells_str = NULL; int ret = 0; ret = run_command("fdt get value address_cells / \\#address-cells", 0); if (ret != 0) { printf("Error: Failed to get address_cells for root\n"); return -EBADMSG; } address_cells_str = env_get("address_cells"); if (!address_cells_str) { printf("Error: Failed to retrieve address_cells from environment\n"); return -EBADMSG; } return strtoul(address_cells_str, NULL, 16); } static int ftd_get_scmi_shmem_addr(void) { char *shmem_addr_str = NULL; u32 *shmem_addr = NULL; int root_addrs_cells = ftd_get_root_address_cells(); int ret = 0; ret = run_command("fdt get addr shmem_addr /shmem reg", 0); if (ret != 0) { printf("Error: Failed to get shmem_addr for /shmem\n"); return -EBADMSG; } shmem_addr_str = env_get("shmem_addr"); if (!shmem_addr_str) { printf("Error: Failed to retrieve shmem_addr from environment\n"); return -EBADMSG; } shmem_addr = (u32 *)strtoul(shmem_addr_str, NULL, 16); if (!shmem_addr) return -EFAULT; if (root_addrs_cells == 2) /* CONFIG_ARM64 */ return be32_to_cpu(*(++shmem_addr)); else /* CONFIG_ARM */ return be32_to_cpu(*shmem_addr); } static int fdt_set_scmi_shmem_reg(void) { int ret = 0; char cmdbuf[256] = {0}; u32 bl31_shmem_addr = get_scmi_shmem_addr(); u32 dtb_shmem_addr = ftd_get_scmi_shmem_addr(); if (dtb_shmem_addr == bl31_shmem_addr) return 0; printf("Warning: Address of shmem in DTB is inconsistent with BL31!!!\n"); printf("bl31_shmem_addr = 0x%x, dtb_shmem_addr = 0x%x\n", bl31_shmem_addr, dtb_shmem_addr); printf("Update the address of shmem in DTB\n"); memset(cmdbuf, 0, sizeof(cmdbuf)); if (ftd_get_root_address_cells() == 1) { /* CONFIG_ARM */ sprintf(cmdbuf, "fdt set /shmem reg <0x%x 0x100>", bl31_shmem_addr); } else if (ftd_get_root_address_cells() == 2) { /* CONFIG_ARM64 */ sprintf(cmdbuf, "fdt set /shmem reg <0 0x%x 0 0x100>", bl31_shmem_addr); } else { printf("Error: Failed to adapt address-cells for DTB.\n"); return -ENXIO; } ret = run_command(cmdbuf, 0); if (ret != 0) { printf("Error: Failed to set reg of scmi_shmem for DTB\n"); return -EBADMSG; } memset(cmdbuf, 0, sizeof(cmdbuf)); sprintf(cmdbuf, "fdt set /shmem ranges <0 0 0x%x 0x100>", bl31_shmem_addr); ret = run_command(cmdbuf, 0); if (ret != 0) { printf("Error: Failed to set ranges of scmi_shmem for DTB\n"); return -EBADMSG; } return 0; } static int do_update_scmi_shmem(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { return fdt_set_scmi_shmem_reg(); } U_BOOT_CMD(update_scmi_shmem, 1, 0, do_update_scmi_shmem, "Update the shared memory address of the SCMI in the DTB", "" );