Skip to content

Commit 1168af4

Browse files
sumanannaandersson
authored andcommitted
remoteproc: k3-r5: Add support for IPC-only mode for all R5Fs
Add support to the K3 R5F remoteproc driver to configure all the R5F cores to be either in IPC-only mode or the traditional remoteproc mode. The IPC-only mode expects that the remote processors are already booted by the bootloader, and only performs the minimum steps required to initialize and deinitialize the virtio IPC transports. The remoteproc mode allows the kernel remoteproc driver to do the regular load and boot and other device management operations for a R5F core. The IPC-only mode for a R5F core is detected and configured at driver probe time by querying the System Firmware for the R5F power and reset state and/or status and making sure that the R5F core is indeed started by the bootloaders, otherwise the device is configured for remoteproc mode. Support for IPC-only mode is achieved through .attach(), .detach() and .get_loaded_rsc_table() callback ops and zeroing out the regular rproc ops .prepare(), .unprepare(), .start() and .stop(). The resource table follows a design-by-contract approach and is expected to be at the base of the DDR firmware region reserved for each remoteproc, it is mostly expected to contain only the virtio device and trace resource entries. NOTE: The driver cannot configure a R5F core for remoteproc mode by any means without rebooting the kernel if that R5F core has been started by a bootloader. This is the current desired behavior and can be enhanced in the future if the feature is needed. Signed-off-by: Suman Anna <s-anna@ti.com> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> Link: https://lore.kernel.org/r/20220213201246.25952-4-s-anna@ti.com
1 parent e3865c8 commit 1168af4

File tree

1 file changed

+215
-4
lines changed

1 file changed

+215
-4
lines changed

drivers/remoteproc/ti_k3_r5_remoteproc.c

Lines changed: 215 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ static int k3_r5_rproc_request_mbox(struct rproc *rproc)
428428
* private to each core. Only Core0 needs to be unhalted for running the
429429
* cluster in this mode. The function uses the same reset logic as LockStep
430430
* mode for this (though the behavior is agnostic of the reset release order).
431+
* This callback is invoked only in remoteproc mode.
431432
*/
432433
static int k3_r5_rproc_prepare(struct rproc *rproc)
433434
{
@@ -493,7 +494,8 @@ static int k3_r5_rproc_prepare(struct rproc *rproc)
493494
* both cores. The access is made possible only with releasing the resets for
494495
* both cores, but with only Core0 unhalted. This function re-uses the same
495496
* reset assert logic as LockStep mode for this mode (though the behavior is
496-
* agnostic of the reset assert order).
497+
* agnostic of the reset assert order). This callback is invoked only in
498+
* remoteproc mode.
497499
*/
498500
static int k3_r5_rproc_unprepare(struct rproc *rproc)
499501
{
@@ -527,7 +529,8 @@ static int k3_r5_rproc_unprepare(struct rproc *rproc)
527529
*
528530
* The Single-CPU mode on applicable SoCs (eg: AM64x) only uses Core0 to execute
529531
* code, so only Core0 needs to be unhalted. The function uses the same logic
530-
* flow as Split-mode for this.
532+
* flow as Split-mode for this. This callback is invoked only in remoteproc
533+
* mode.
531534
*/
532535
static int k3_r5_rproc_start(struct rproc *rproc)
533536
{
@@ -598,7 +601,8 @@ static int k3_r5_rproc_start(struct rproc *rproc)
598601
* be done here, but is preferred to be done in the .unprepare() ops - this
599602
* maintains the symmetric behavior between the .start(), .stop(), .prepare()
600603
* and .unprepare() ops, and also balances them well between sysfs 'state'
601-
* flow and device bind/unbind or module removal.
604+
* flow and device bind/unbind or module removal. This callback is invoked
605+
* only in remoteproc mode.
602606
*/
603607
static int k3_r5_rproc_stop(struct rproc *rproc)
604608
{
@@ -635,6 +639,78 @@ static int k3_r5_rproc_stop(struct rproc *rproc)
635639
return ret;
636640
}
637641

642+
/*
643+
* Attach to a running R5F remote processor (IPC-only mode)
644+
*
645+
* The R5F attach callback only needs to request the mailbox, the remote
646+
* processor is already booted, so there is no need to issue any TI-SCI
647+
* commands to boot the R5F cores in IPC-only mode. This callback is invoked
648+
* only in IPC-only mode.
649+
*/
650+
static int k3_r5_rproc_attach(struct rproc *rproc)
651+
{
652+
struct k3_r5_rproc *kproc = rproc->priv;
653+
struct device *dev = kproc->dev;
654+
int ret;
655+
656+
ret = k3_r5_rproc_request_mbox(rproc);
657+
if (ret)
658+
return ret;
659+
660+
dev_info(dev, "R5F core initialized in IPC-only mode\n");
661+
return 0;
662+
}
663+
664+
/*
665+
* Detach from a running R5F remote processor (IPC-only mode)
666+
*
667+
* The R5F detach callback performs the opposite operation to attach callback
668+
* and only needs to release the mailbox, the R5F cores are not stopped and
669+
* will be left in booted state in IPC-only mode. This callback is invoked
670+
* only in IPC-only mode.
671+
*/
672+
static int k3_r5_rproc_detach(struct rproc *rproc)
673+
{
674+
struct k3_r5_rproc *kproc = rproc->priv;
675+
struct device *dev = kproc->dev;
676+
677+
mbox_free_channel(kproc->mbox);
678+
dev_info(dev, "R5F core deinitialized in IPC-only mode\n");
679+
return 0;
680+
}
681+
682+
/*
683+
* This function implements the .get_loaded_rsc_table() callback and is used
684+
* to provide the resource table for the booted R5F in IPC-only mode. The K3 R5F
685+
* firmwares follow a design-by-contract approach and are expected to have the
686+
* resource table at the base of the DDR region reserved for firmware usage.
687+
* This provides flexibility for the remote processor to be booted by different
688+
* bootloaders that may or may not have the ability to publish the resource table
689+
* address and size through a DT property. This callback is invoked only in
690+
* IPC-only mode.
691+
*/
692+
static struct resource_table *k3_r5_get_loaded_rsc_table(struct rproc *rproc,
693+
size_t *rsc_table_sz)
694+
{
695+
struct k3_r5_rproc *kproc = rproc->priv;
696+
struct device *dev = kproc->dev;
697+
698+
if (!kproc->rmem[0].cpu_addr) {
699+
dev_err(dev, "memory-region #1 does not exist, loaded rsc table can't be found");
700+
return ERR_PTR(-ENOMEM);
701+
}
702+
703+
/*
704+
* NOTE: The resource table size is currently hard-coded to a maximum
705+
* of 256 bytes. The most common resource table usage for K3 firmwares
706+
* is to only have the vdev resource entry and an optional trace entry.
707+
* The exact size could be computed based on resource table address, but
708+
* the hard-coded value suffices to support the IPC-only mode.
709+
*/
710+
*rsc_table_sz = 256;
711+
return (struct resource_table *)kproc->rmem[0].cpu_addr;
712+
}
713+
638714
/*
639715
* Internal Memory translation helper
640716
*
@@ -1014,6 +1090,116 @@ static void k3_r5_adjust_tcm_sizes(struct k3_r5_rproc *kproc)
10141090
}
10151091
}
10161092

1093+
/*
1094+
* This function checks and configures a R5F core for IPC-only or remoteproc
1095+
* mode. The driver is configured to be in IPC-only mode for a R5F core when
1096+
* the core has been loaded and started by a bootloader. The IPC-only mode is
1097+
* detected by querying the System Firmware for reset, power on and halt status
1098+
* and ensuring that the core is running. Any incomplete steps at bootloader
1099+
* are validated and errored out.
1100+
*
1101+
* In IPC-only mode, the driver state flags for ATCM, BTCM and LOCZRAMA settings
1102+
* and cluster mode parsed originally from kernel DT are updated to reflect the
1103+
* actual values configured by bootloader. The driver internal device memory
1104+
* addresses for TCMs are also updated.
1105+
*/
1106+
static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc)
1107+
{
1108+
struct k3_r5_cluster *cluster = kproc->cluster;
1109+
struct k3_r5_core *core = kproc->core;
1110+
struct device *cdev = core->dev;
1111+
bool r_state = false, c_state = false;
1112+
u32 ctrl = 0, cfg = 0, stat = 0, halted = 0;
1113+
u64 boot_vec = 0;
1114+
u32 atcm_enable, btcm_enable, loczrama;
1115+
struct k3_r5_core *core0;
1116+
enum cluster_mode mode;
1117+
int ret;
1118+
1119+
core0 = list_first_entry(&cluster->cores, struct k3_r5_core, elem);
1120+
1121+
ret = core->ti_sci->ops.dev_ops.is_on(core->ti_sci, core->ti_sci_id,
1122+
&r_state, &c_state);
1123+
if (ret) {
1124+
dev_err(cdev, "failed to get initial state, mode cannot be determined, ret = %d\n",
1125+
ret);
1126+
return ret;
1127+
}
1128+
if (r_state != c_state) {
1129+
dev_warn(cdev, "R5F core may have been powered on by a different host, programmed state (%d) != actual state (%d)\n",
1130+
r_state, c_state);
1131+
}
1132+
1133+
ret = reset_control_status(core->reset);
1134+
if (ret < 0) {
1135+
dev_err(cdev, "failed to get initial local reset status, ret = %d\n",
1136+
ret);
1137+
return ret;
1138+
}
1139+
1140+
ret = ti_sci_proc_get_status(core->tsp, &boot_vec, &cfg, &ctrl,
1141+
&stat);
1142+
if (ret < 0) {
1143+
dev_err(cdev, "failed to get initial processor status, ret = %d\n",
1144+
ret);
1145+
return ret;
1146+
}
1147+
atcm_enable = cfg & PROC_BOOT_CFG_FLAG_R5_ATCM_EN ? 1 : 0;
1148+
btcm_enable = cfg & PROC_BOOT_CFG_FLAG_R5_BTCM_EN ? 1 : 0;
1149+
loczrama = cfg & PROC_BOOT_CFG_FLAG_R5_TCM_RSTBASE ? 1 : 0;
1150+
if (cluster->soc_data->single_cpu_mode) {
1151+
mode = cfg & PROC_BOOT_CFG_FLAG_R5_SINGLE_CORE ?
1152+
CLUSTER_MODE_SINGLECPU : CLUSTER_MODE_SPLIT;
1153+
} else {
1154+
mode = cfg & PROC_BOOT_CFG_FLAG_R5_LOCKSTEP ?
1155+
CLUSTER_MODE_LOCKSTEP : CLUSTER_MODE_SPLIT;
1156+
}
1157+
halted = ctrl & PROC_BOOT_CTRL_FLAG_R5_CORE_HALT;
1158+
1159+
/*
1160+
* IPC-only mode detection requires both local and module resets to
1161+
* be deasserted and R5F core to be unhalted. Local reset status is
1162+
* irrelevant if module reset is asserted (POR value has local reset
1163+
* deasserted), and is deemed as remoteproc mode
1164+
*/
1165+
if (c_state && !ret && !halted) {
1166+
dev_info(cdev, "configured R5F for IPC-only mode\n");
1167+
kproc->rproc->state = RPROC_DETACHED;
1168+
ret = 1;
1169+
/* override rproc ops with only required IPC-only mode ops */
1170+
kproc->rproc->ops->prepare = NULL;
1171+
kproc->rproc->ops->unprepare = NULL;
1172+
kproc->rproc->ops->start = NULL;
1173+
kproc->rproc->ops->stop = NULL;
1174+
kproc->rproc->ops->attach = k3_r5_rproc_attach;
1175+
kproc->rproc->ops->detach = k3_r5_rproc_detach;
1176+
kproc->rproc->ops->get_loaded_rsc_table =
1177+
k3_r5_get_loaded_rsc_table;
1178+
} else if (!c_state) {
1179+
dev_info(cdev, "configured R5F for remoteproc mode\n");
1180+
ret = 0;
1181+
} else {
1182+
dev_err(cdev, "mismatched mode: local_reset = %s, module_reset = %s, core_state = %s\n",
1183+
!ret ? "deasserted" : "asserted",
1184+
c_state ? "deasserted" : "asserted",
1185+
halted ? "halted" : "unhalted");
1186+
ret = -EINVAL;
1187+
}
1188+
1189+
/* fixup TCMs, cluster & core flags to actual values in IPC-only mode */
1190+
if (ret > 0) {
1191+
if (core == core0)
1192+
cluster->mode = mode;
1193+
core->atcm_enable = atcm_enable;
1194+
core->btcm_enable = btcm_enable;
1195+
core->loczrama = loczrama;
1196+
core->mem[0].dev_addr = loczrama ? 0 : K3_R5_TCM_DEV_ADDR;
1197+
core->mem[1].dev_addr = loczrama ? K3_R5_TCM_DEV_ADDR : 0;
1198+
}
1199+
1200+
return ret;
1201+
}
1202+
10171203
static int k3_r5_cluster_rproc_init(struct platform_device *pdev)
10181204
{
10191205
struct k3_r5_cluster *cluster = platform_get_drvdata(pdev);
@@ -1023,7 +1209,7 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev)
10231209
struct device *cdev;
10241210
const char *fw_name;
10251211
struct rproc *rproc;
1026-
int ret;
1212+
int ret, ret1;
10271213

10281214
core1 = list_last_entry(&cluster->cores, struct k3_r5_core, elem);
10291215
list_for_each_entry(core, &cluster->cores, elem) {
@@ -1054,13 +1240,20 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev)
10541240
kproc->rproc = rproc;
10551241
core->rproc = rproc;
10561242

1243+
ret = k3_r5_rproc_configure_mode(kproc);
1244+
if (ret < 0)
1245+
goto err_config;
1246+
if (ret)
1247+
goto init_rmem;
1248+
10571249
ret = k3_r5_rproc_configure(kproc);
10581250
if (ret) {
10591251
dev_err(dev, "initial configure failed, ret = %d\n",
10601252
ret);
10611253
goto err_config;
10621254
}
10631255

1256+
init_rmem:
10641257
k3_r5_adjust_tcm_sizes(kproc);
10651258

10661259
ret = k3_r5_reserved_mem_init(kproc);
@@ -1085,6 +1278,15 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev)
10851278
return 0;
10861279

10871280
err_split:
1281+
if (rproc->state == RPROC_ATTACHED) {
1282+
ret1 = rproc_detach(rproc);
1283+
if (ret1) {
1284+
dev_err(kproc->dev, "failed to detach rproc, ret = %d\n",
1285+
ret1);
1286+
return ret1;
1287+
}
1288+
}
1289+
10881290
rproc_del(rproc);
10891291
err_add:
10901292
k3_r5_reserved_mem_exit(kproc);
@@ -1108,6 +1310,7 @@ static void k3_r5_cluster_rproc_exit(void *data)
11081310
struct k3_r5_rproc *kproc;
11091311
struct k3_r5_core *core;
11101312
struct rproc *rproc;
1313+
int ret;
11111314

11121315
/*
11131316
* lockstep mode and single-cpu modes have only one rproc associated
@@ -1123,6 +1326,14 @@ static void k3_r5_cluster_rproc_exit(void *data)
11231326
rproc = core->rproc;
11241327
kproc = rproc->priv;
11251328

1329+
if (rproc->state == RPROC_ATTACHED) {
1330+
ret = rproc_detach(rproc);
1331+
if (ret) {
1332+
dev_err(kproc->dev, "failed to detach rproc, ret = %d\n", ret);
1333+
return;
1334+
}
1335+
}
1336+
11261337
rproc_del(rproc);
11271338

11281339
k3_r5_reserved_mem_exit(kproc);

0 commit comments

Comments
 (0)