blob: b9c73878455bffc9941d33f65bb47c46a6cfdad2 [file] [log] [blame]
/*
* Copyright 2018 NXP.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <asm/arch/sci/sci.h>
#include <asm/mach-imx/boot_mode.h>
#include <malloc.h>
#include <command.h>
#include <asm/arch-imx/cpu.h>
#include <asm/arch/sys_proto.h>
#include <fdt_support.h>
#include <fdtdec.h>
#include <linux/libfdt.h>
#include <linux/io.h>
#include <linux/compat.h>
DECLARE_GLOBAL_DATA_PTR;
#define SC_MAX_PARTS 32
struct scu_rm_part_data {
bool used;
bool isolated;
bool restricted;
bool grant;
sc_rm_did_t did;
sc_rm_pt_t self;
sc_rm_pt_t parent;
char *name;
};
static struct scu_rm_part_data rm_part_data[SC_MAX_PARTS];
static int partition_alloc(bool isolated, bool restricted, bool grant, sc_rm_pt_t *pt)
{
sc_rm_pt_t parent_part, os_part;
int err;
int i;
for (i = 0; i < SC_MAX_PARTS; i++) {
if (!rm_part_data[i].used)
break;
}
if (i == SC_MAX_PARTS) {
puts("No empty slots\n");
return -EINVAL;
}
err = sc_rm_get_partition(-1, &parent_part);
if (err != SC_ERR_NONE) {
puts("sc_rm_get_partition failure\n");
return -EINVAL;
}
debug("isolated %d, restricted %d, grant %d\n", isolated, restricted, grant);
err = sc_rm_partition_alloc(-1, &os_part, false, isolated,
restricted, grant, false);
if (err != SC_ERR_NONE) {
printf("sc_rm_partition_alloc failure %d\n", err);
return -EINVAL;
}
err = sc_rm_set_parent(-1, os_part, parent_part);
if (err != SC_ERR_NONE) {
sc_rm_partition_free(-1, os_part);
return -EINVAL;
}
rm_part_data[i].self = os_part;
rm_part_data[i].parent = parent_part;
rm_part_data[i].used = true;
rm_part_data[i].restricted = restricted;
rm_part_data[i].isolated = isolated;
rm_part_data[i].grant = grant;
if (pt)
*pt = os_part;
printf("%s: os_part, %d: parent_part, %d\n", __func__, os_part,
parent_part);
return 0;
}
static int do_part_alloc(int argc, char * const argv[])
{
bool restricted = false, isolated = false, grant = false;
int ret;
if (argv[0])
isolated = simple_strtoul(argv[0], NULL, 10);
if (argv[1])
restricted = simple_strtoul(argv[1], NULL, 10);
if (argv[2])
grant = simple_strtoul(argv[2], NULL, 10);
ret = partition_alloc(isolated, restricted, grant, NULL);
if (ret)
return CMD_RET_FAILURE;
return CMD_RET_SUCCESS;
}
static int do_part_dtb(int argc, char * const argv[])
{
int err;
sc_rm_pt_t pt;
char *pathp = "/domu";
int nodeoffset, subnode;
int rsrc_size = 0, pad_size = 0;
int i, ret;
u32 *rsrc_data = NULL, *pad_data = NULL;
const struct fdt_property *prop;
bool init_ignore_domu_power = false;
char *tmp;
void *fdt;
tmp = env_get("domu-init-ignore-poweroff");
if (tmp && !strncmp(tmp, "yes", 3)) {
init_ignore_domu_power = true;
printf("ignore init power off domu power\n");
}
if (argc)
fdt = (void *)simple_strtoul(argv[0], NULL, 16);
else
fdt = working_fdt;
printf("fdt addr %p\n", fdt);
nodeoffset = fdt_path_offset(fdt, pathp);
debug("%s %s %p\n", __func__, fdt_get_name(fdt, nodeoffset, NULL), fdt);
fdt_for_each_subnode(subnode, fdt, nodeoffset) {
if (!fdtdec_get_is_enabled(fdt, subnode))
continue;
if (!fdt_node_check_compatible(fdt, subnode, "xen,domu")) {
u32 temp;
prop = fdt_getprop(fdt, subnode, "rsrcs", &rsrc_size);
if (!prop)
debug("No rsrcs %s\n", fdt_get_name(fdt, subnode, NULL));
if (rsrc_size > 0) {
rsrc_data = kmalloc(rsrc_size, __GFP_ZERO);
if (!rsrc_data) {
debug("No mem\n");
return CMD_RET_FAILURE;
}
if (fdtdec_get_int_array(fdt, subnode, "rsrcs",
rsrc_data, rsrc_size >> 2)) {
debug("Error reading rsrcs\n");
free(rsrc_data);
return CMD_RET_FAILURE;
}
}
prop = fdt_getprop(fdt, subnode, "pads", &pad_size);
if (!prop)
debug("No pads %s %d\n", fdt_get_name(fdt, subnode, NULL), pad_size);
if (pad_size > 0) {
pad_data = kmalloc(pad_size, __GFP_ZERO);
if (!pad_data) {
debug("No mem\n");
if (rsrc_data != NULL)
free(rsrc_data);
return CMD_RET_FAILURE;
}
if (fdtdec_get_int_array(fdt, subnode, "pads",
pad_data, pad_size >> 2)) {
debug("Error reading pad\n");
free(pad_data);
free(rsrc_data);
return CMD_RET_FAILURE;
}
}
if ((rsrc_size <= 0) && (pad_size <= 0))
continue;
ret = partition_alloc(false, false, true, &pt);
if (ret)
goto free_data;
temp = cpu_to_fdt32(pt);
ret = fdt_setprop(fdt, subnode, "reg", &temp,
sizeof(u32));
if (ret) {
printf("Could not set reg property %d\n", ret);
sc_rm_partition_free(-1, pt);
goto free_data;
}
if (rsrc_size > 0) {
for (i = 0; i < rsrc_size >> 2; i++) {
switch (rsrc_data[i]) {
case SC_R_MU_2A:
case SC_R_MU_3A:
case SC_R_MU_4A:
err = sc_pm_set_resource_power_mode(-1, rsrc_data[i], SC_PM_PW_MODE_ON);
if (err)
debug("power on resource %d, err %d\n", rsrc_data[i], err);
break;
default:
if (init_ignore_domu_power)
break;
err = sc_pm_set_resource_power_mode(-1, rsrc_data[i], SC_PM_PW_MODE_OFF);
if (err)
debug("power off resource %d, err %d\n", rsrc_data[i], err);
break;
}
if (sc_rm_is_resource_owned(-1, rsrc_data[i])) {
err = sc_rm_assign_resource(-1, pt, rsrc_data[i]);
debug("pt %d, resource %d, err %d\n", pt, rsrc_data[i], err);
}
}
}
if (pad_size > 0) {
for (i = 0; i < pad_size >> 2; i++) {
if (sc_rm_is_pad_owned(-1, pad_data[i])) {
err = sc_rm_assign_pad(-1, pt, pad_data[i]);
debug("pt %d, pad %d, err %d\n", pt, pad_data[i], err);
}
}
}
free_data:
if (pad_size > 0)
free(pad_data);
if (rsrc_size > 0) {
free(rsrc_data);
rsrc_data = NULL;
}
}
}
return 0;
}
static int do_part_free(int argc, char * const argv[])
{
sc_rm_pt_t os_part;
int err;
int i;
if (argc == 0)
return CMD_RET_FAILURE;
os_part = simple_strtoul(argv[0], NULL, 10);
err = sc_rm_partition_free(-1, os_part);
if (err != SC_ERR_NONE) {
printf("free partiiton %d err %d\n", os_part, err);
return CMD_RET_FAILURE;
}
for (i = 0; i < SC_MAX_PARTS; i++) {
if ((rm_part_data[i].self == os_part) && rm_part_data[i].used) {
rm_part_data[i].used = false;
break;
}
}
return CMD_RET_SUCCESS;
}
static int do_resource_assign(int argc, char * const argv[])
{
sc_rm_pt_t os_part;
int err;
sc_rsrc_t resource;
sc_pad_t pad;
int i, flag;
if (argc < 3)
return CMD_RET_FAILURE;
os_part = simple_strtoul(argv[0], NULL, 10);
flag = simple_strtoul(argv[1], NULL, 10);
if (flag)
pad = simple_strtoul(argv[2], NULL, 10);
else
resource = simple_strtoul(argv[2], NULL, 10);
for (i = 0; i < SC_MAX_PARTS; i++) {
if ((rm_part_data[i].self == os_part) && rm_part_data[i].used)
break;
}
if (i == SC_MAX_PARTS) {
puts("Not valid partition\n");
return CMD_RET_FAILURE;
}
if (flag)
err = sc_rm_assign_pad(-1, os_part, pad);
else
err = sc_rm_assign_resource(-1, os_part, resource);
if (err != SC_ERR_NONE) {
printf("assign resource/pad error %d\n", err);
return CMD_RET_FAILURE;
}
printf("%s: os_part, %d, %d\n", __func__, os_part,
flag ? pad : resource);
return CMD_RET_SUCCESS;
}
static int do_part_list(int argc, char * const argv[])
{
int i;
for (i = 0; i < SC_MAX_PARTS; i++) {
if (rm_part_data[i].used)
printf("part id: %d %d\n", rm_part_data[i].self,
rm_part_data[i].parent);
}
return CMD_RET_SUCCESS;
}
static int do_part_test(int argc, char * const argv[])
{
sc_err_t err;
sc_rsrc_t resource;
if (argc < 1)
return CMD_RET_FAILURE;
resource = simple_strtoul(argv[0], NULL, 10);
err = sc_pm_set_resource_power_mode(-1, resource, SC_PM_PW_MODE_ON);
if (err == SC_ERR_NOACCESS)
puts("NO ACCESS\n");
return CMD_RET_SUCCESS;
}
static int do_scu_rm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
if (argc < 2)
return CMD_RET_USAGE;
if (!strcmp(argv[1], "alloc"))
return do_part_alloc(argc - 2, argv + 2);
else if (!strcmp(argv[1], "dtb"))
return do_part_dtb(argc - 2, argv + 2);
else if (!strcmp(argv[1], "free"))
return do_part_free(argc - 2, argv + 2);
else if (!strcmp(argv[1], "assign"))
return do_resource_assign(argc - 2, argv + 2);
else if (!strcmp(argv[1], "test"))
return do_part_test(argc - 2, argv + 2);
else if (!strcmp(argv[1], "print"))
return do_part_list(argc - 2, argv + 2);
return CMD_RET_USAGE;
}
U_BOOT_CMD(
scu_rm, CONFIG_SYS_MAXARGS, 1, do_scu_rm,
"scu partition function",
"\n"
"scu_rm alloc [isolated] [restricted] [grant]\n"
"scu_rm dtb [fdt]\n"
"scu_rm free pt\n"
"scu_rm assign pt 0 resource\n"
"scu_rm assign pt 1 pad\n"
"scu_rm test resource\n"
"scu_rm print\n"
);