blob: 9c0324114b9311240b3af99b9f06c802954a20ba [file] [log] [blame] [edit]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <common.h>
#include <command.h>
#include <linux/arm-smccc.h>
#include <linux/libfdt_env.h>
#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",
""
);