GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,84 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2015
# Texas Instruments Incorporated - http://www.ti.com/
#
menu "Remote Processor drivers"
# REMOTEPROC gets selected by drivers as needed
# All users should depend on DM
config REMOTEPROC
bool
depends on DM
# Please keep the configuration alphabetically sorted.
config K3_SYSTEM_CONTROLLER
bool "Support for TI' K3 System Controller"
select REMOTEPROC
depends on DM
depends on ARCH_K3
depends on OF_CONTROL
help
Say 'y' here to add support for TI' K3 System Controller.
config REMOTEPROC_SANDBOX
bool "Support for Test processor for Sandbox"
select REMOTEPROC
depends on DM
depends on SANDBOX
help
Say 'y' here to add support for test processor which does dummy
operations for sandbox platform.
config REMOTEPROC_STM32_COPRO
bool "Support for STM32 coprocessor"
select REMOTEPROC
depends on DM
depends on ARCH_STM32MP
depends on OF_CONTROL
help
Say 'y' here to add support for STM32 Cortex-M4 coprocessors via the
remoteproc framework.
config REMOTEPROC_TI_K3_ARM64
bool "Support for TI's K3 based ARM64 remoteproc driver"
select REMOTEPROC
depends on DM
depends on ARCH_K3
depends on OF_CONTROL
help
Say y here to support TI's ARM64 processor subsystems
on various TI K3 family of SoCs through the remote processor
framework.
config REMOTEPROC_TI_K3_DSP
bool "TI K3 C66 and C71 remoteproc support"
select REMOTEPROC
depends on ARCH_K3
depends on TI_SCI_PROTOCOL
help
Say y here to support TI's C66/C71 remote processor subsystems
on various TI K3 family of SoCs through the remote processor
framework.
config REMOTEPROC_TI_K3_R5F
bool "TI K3 R5F remoteproc support"
select REMOTEPROC
depends on ARCH_K3
depends on TI_SCI_PROTOCOL
help
Say y here to support TI's R5F remote processor subsystems
on various TI K3 family of SoCs through the remote processor
framework.
config REMOTEPROC_TI_POWER
bool "Support for TI Power processor"
select REMOTEPROC
depends on DM
depends on ARCH_KEYSTONE
depends on OF_CONTROL
help
Say 'y' here to add support for TI power processors such as those
found on certain TI keystone and OMAP generation SoCs.
endmenu
@@ -0,0 +1,16 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2015
# Texas Instruments Incorporated - http://www.ti.com/
#
obj-$(CONFIG_$(SPL_)REMOTEPROC) += rproc-uclass.o rproc-elf-loader.o
# Remote proc drivers - Please keep this list alphabetically sorted.
obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o
obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o
obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o
obj-$(CONFIG_REMOTEPROC_TI_K3_ARM64) += ti_k3_arm64_rproc.o
obj-$(CONFIG_REMOTEPROC_TI_K3_DSP) += ti_k3_dsp_rproc.o
obj-$(CONFIG_REMOTEPROC_TI_K3_R5F) += ti_k3_r5f_rproc.o
obj-$(CONFIG_REMOTEPROC_TI_POWER) += ti_power_proc.o
@@ -0,0 +1,323 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Texas Instruments' K3 System Controller Driver
*
* Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
*/
#include <common.h>
#include <dm.h>
#include <remoteproc.h>
#include <errno.h>
#include <mailbox.h>
#include <linux/soc/ti/k3-sec-proxy.h>
#define K3_MSG_R5_TO_M3_M3FW 0x8105
#define K3_MSG_M3_TO_R5_CERT_RESULT 0x8805
#define K3_MSG_M3_TO_R5_BOOT_NOTIFICATION 0x000A
#define K3_FLAGS_MSG_CERT_AUTH_PASS 0x555555
#define K3_FLAGS_MSG_CERT_AUTH_FAIL 0xffffff
/**
* struct k3_sysctrler_msg_hdr - Generic Header for Messages and responses.
* @cmd_id: Message ID. One of K3_MSG_*
* @host_id: Host ID of the message
* @seq_ne: Message identifier indicating a transfer sequence.
* @flags: Flags for the message.
*/
struct k3_sysctrler_msg_hdr {
u16 cmd_id;
u8 host_id;
u8 seq_nr;
u32 flags;
} __packed;
/**
* struct k3_sysctrler_load_msg - Message format for Firmware loading
* @hdr: Generic message hdr
* @buffer_address: Address at which firmware is located.
* @buffer_size: Size of the firmware.
*/
struct k3_sysctrler_load_msg {
struct k3_sysctrler_msg_hdr hdr;
u32 buffer_address;
u32 buffer_size;
} __packed;
/**
* struct k3_sysctrler_boot_notification_msg - Message format for boot
* notification
* @checksum: Checksum for the entire message
* @reserved: Reserved for future use.
* @hdr: Generic message hdr
*/
struct k3_sysctrler_boot_notification_msg {
u16 checksum;
u16 reserved;
struct k3_sysctrler_msg_hdr hdr;
} __packed;
/**
* struct k3_sysctrler_desc - Description of SoC integration.
* @host_id: Host identifier representing the compute entity
* @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds)
* @max_msg_size: Maximum size of data per message that can be handled.
*/
struct k3_sysctrler_desc {
u8 host_id;
int max_rx_timeout_us;
int max_msg_size;
};
/**
* struct k3_sysctrler_privdata - Structure representing System Controller data.
* @chan_tx: Transmit mailbox channel
* @chan_rx: Receive mailbox channel
* @desc: SoC description for this instance
* @seq_nr: Counter for number of messages sent.
*/
struct k3_sysctrler_privdata {
struct mbox_chan chan_tx;
struct mbox_chan chan_rx;
struct k3_sysctrler_desc *desc;
u32 seq_nr;
};
static inline
void k3_sysctrler_load_msg_setup(struct k3_sysctrler_load_msg *fw,
struct k3_sysctrler_privdata *priv,
ulong addr, ulong size)
{
fw->hdr.cmd_id = K3_MSG_R5_TO_M3_M3FW;
fw->hdr.host_id = priv->desc->host_id;
fw->hdr.seq_nr = priv->seq_nr++;
fw->hdr.flags = 0x0;
fw->buffer_address = addr;
fw->buffer_size = size;
}
static int k3_sysctrler_load_response(u32 *buf)
{
struct k3_sysctrler_load_msg *fw;
fw = (struct k3_sysctrler_load_msg *)buf;
/* Check for proper response ID */
if (fw->hdr.cmd_id != K3_MSG_M3_TO_R5_CERT_RESULT) {
dev_err(dev, "%s: Command expected 0x%x, but received 0x%x\n",
__func__, K3_MSG_M3_TO_R5_CERT_RESULT, fw->hdr.cmd_id);
return -EINVAL;
}
/* Check for certificate authentication result */
if (fw->hdr.flags == K3_FLAGS_MSG_CERT_AUTH_FAIL) {
dev_err(dev, "%s: Firmware certificate authentication failed\n",
__func__);
return -EINVAL;
} else if (fw->hdr.flags != K3_FLAGS_MSG_CERT_AUTH_PASS) {
dev_err(dev, "%s: Firmware Load response Invalid %d\n",
__func__, fw->hdr.flags);
return -EINVAL;
}
debug("%s: Firmware authentication passed\n", __func__);
return 0;
}
static int k3_sysctrler_boot_notification_response(u32 *buf)
{
struct k3_sysctrler_boot_notification_msg *boot;
boot = (struct k3_sysctrler_boot_notification_msg *)buf;
/* ToDo: Verify checksum */
/* Check for proper response ID */
if (boot->hdr.cmd_id != K3_MSG_M3_TO_R5_BOOT_NOTIFICATION) {
dev_err(dev, "%s: Command expected 0x%x, but received 0x%x\n",
__func__, K3_MSG_M3_TO_R5_BOOT_NOTIFICATION,
boot->hdr.cmd_id);
return -EINVAL;
}
debug("%s: Boot notification received\n", __func__);
return 0;
}
/**
* k3_sysctrler_load() - Loadup the K3 remote processor
* @dev: corresponding K3 remote processor device
* @addr: Address in memory where image binary is stored
* @size: Size in bytes of the image binary
*
* Return: 0 if all goes good, else appropriate error message.
*/
static int k3_sysctrler_load(struct udevice *dev, ulong addr, ulong size)
{
struct k3_sysctrler_privdata *priv = dev_get_priv(dev);
struct k3_sysctrler_load_msg firmware;
struct k3_sec_proxy_msg msg;
int ret;
debug("%s: Loading binary from 0x%08lX, size 0x%08lX\n",
__func__, addr, size);
memset(&firmware, 0, sizeof(firmware));
memset(&msg, 0, sizeof(msg));
/* Setup the message */
k3_sysctrler_load_msg_setup(&firmware, priv, addr, size);
msg.len = sizeof(firmware);
msg.buf = (u32 *)&firmware;
/* Send the message */
ret = mbox_send(&priv->chan_tx, &msg);
if (ret) {
dev_err(dev, "%s: Firmware Loading failed. ret = %d\n",
__func__, ret);
return ret;
}
/* Receive the response */
ret = mbox_recv(&priv->chan_rx, &msg, priv->desc->max_rx_timeout_us);
if (ret) {
dev_err(dev, "%s: Firmware Load response failed. ret = %d\n",
__func__, ret);
return ret;
}
/* Process the response */
ret = k3_sysctrler_load_response(msg.buf);
if (ret)
return ret;
debug("%s: Firmware Loaded successfully on dev %s\n",
__func__, dev->name);
return 0;
}
/**
* k3_sysctrler_start() - Start the remote processor
* Note that while technically the K3 system controller starts up
* automatically after its firmware got loaded we still want to
* utilize the rproc start operation for other startup-related
* tasks.
* @dev: device to operate upon
*
* Return: 0 if all went ok, else return appropriate error
*/
static int k3_sysctrler_start(struct udevice *dev)
{
struct k3_sysctrler_privdata *priv = dev_get_priv(dev);
struct k3_sec_proxy_msg msg;
int ret;
debug("%s(dev=%p)\n", __func__, dev);
/* Receive the boot notification. Note that it is sent only once. */
ret = mbox_recv(&priv->chan_rx, &msg, priv->desc->max_rx_timeout_us);
if (ret) {
dev_err(dev, "%s: Boot Notification response failed. ret = %d\n",
__func__, ret);
return ret;
}
/* Process the response */
ret = k3_sysctrler_boot_notification_response(msg.buf);
if (ret)
return ret;
debug("%s: Boot notification received successfully on dev %s\n",
__func__, dev->name);
return 0;
}
static const struct dm_rproc_ops k3_sysctrler_ops = {
.load = k3_sysctrler_load,
.start = k3_sysctrler_start,
};
/**
* k3_of_to_priv() - generate private data from device tree
* @dev: corresponding k3 remote processor device
* @priv: pointer to driver specific private data
*
* Return: 0 if all goes good, else appropriate error message.
*/
static int k3_of_to_priv(struct udevice *dev,
struct k3_sysctrler_privdata *priv)
{
int ret;
ret = mbox_get_by_name(dev, "tx", &priv->chan_tx);
if (ret) {
dev_err(dev, "%s: Acquiring Tx channel failed. ret = %d\n",
__func__, ret);
return ret;
}
ret = mbox_get_by_name(dev, "rx", &priv->chan_rx);
if (ret) {
dev_err(dev, "%s: Acquiring Rx channel failed. ret = %d\n",
__func__, ret);
return ret;
}
return 0;
}
/**
* k3_sysctrler_probe() - Basic probe
* @dev: corresponding k3 remote processor device
*
* Return: 0 if all goes good, else appropriate error message.
*/
static int k3_sysctrler_probe(struct udevice *dev)
{
struct k3_sysctrler_privdata *priv;
int ret;
debug("%s(dev=%p)\n", __func__, dev);
priv = dev_get_priv(dev);
ret = k3_of_to_priv(dev, priv);
if (ret) {
dev_err(dev, "%s: Probe failed with error %d\n", __func__, ret);
return ret;
}
priv->desc = (void *)dev_get_driver_data(dev);
priv->seq_nr = 0;
return 0;
}
static const struct k3_sysctrler_desc k3_sysctrler_am654_desc = {
.host_id = 4, /* HOST_ID_R5_1 */
.max_rx_timeout_us = 800000,
.max_msg_size = 60,
};
static const struct udevice_id k3_sysctrler_ids[] = {
{
.compatible = "ti,am654-system-controller",
.data = (ulong)&k3_sysctrler_am654_desc,
},
{}
};
U_BOOT_DRIVER(k3_sysctrler) = {
.name = "k3_system_controller",
.of_match = k3_sysctrler_ids,
.id = UCLASS_REMOTEPROC,
.ops = &k3_sysctrler_ops,
.probe = k3_sysctrler_probe,
.priv_auto_alloc_size = sizeof(struct k3_sysctrler_privdata),
};
@@ -0,0 +1,278 @@
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
/*
* Copyright (C) 2019, STMicroelectronics - All Rights Reserved
*/
#include <common.h>
#include <cpu_func.h>
#include <dm.h>
#include <elf.h>
#include <remoteproc.h>
/* Basic function to verify ELF32 image format */
int rproc_elf32_sanity_check(ulong addr, ulong size)
{
Elf32_Ehdr *ehdr;
char class;
if (!addr) {
pr_debug("Invalid fw address?\n");
return -EFAULT;
}
if (size < sizeof(Elf32_Ehdr)) {
pr_debug("Image is too small\n");
return -ENOSPC;
}
ehdr = (Elf32_Ehdr *)addr;
class = ehdr->e_ident[EI_CLASS];
if (!IS_ELF(*ehdr) || ehdr->e_type != ET_EXEC || class != ELFCLASS32) {
pr_debug("Not an executable ELF32 image\n");
return -EPROTONOSUPPORT;
}
/* We assume the firmware has the same endianness as the host */
# ifdef __LITTLE_ENDIAN
if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
# else /* BIG ENDIAN */
if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
# endif
pr_debug("Unsupported firmware endianness\n");
return -EILSEQ;
}
if (size < ehdr->e_shoff + sizeof(Elf32_Shdr)) {
pr_debug("Image is too small\n");
return -ENOSPC;
}
if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
pr_debug("Image is corrupted (bad magic)\n");
return -EBADF;
}
if (ehdr->e_phnum == 0) {
pr_debug("No loadable segments\n");
return -ENOEXEC;
}
if (ehdr->e_phoff > size) {
pr_debug("Firmware size is too small\n");
return -ENOSPC;
}
return 0;
}
/* Basic function to verify ELF64 image format */
int rproc_elf64_sanity_check(ulong addr, ulong size)
{
Elf64_Ehdr *ehdr = (Elf64_Ehdr *)addr;
char class;
if (!addr) {
pr_debug("Invalid fw address?\n");
return -EFAULT;
}
if (size < sizeof(Elf64_Ehdr)) {
pr_debug("Image is too small\n");
return -ENOSPC;
}
class = ehdr->e_ident[EI_CLASS];
if (!IS_ELF(*ehdr) || ehdr->e_type != ET_EXEC || class != ELFCLASS64) {
pr_debug("Not an executable ELF64 image\n");
return -EPROTONOSUPPORT;
}
/* We assume the firmware has the same endianness as the host */
# ifdef __LITTLE_ENDIAN
if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
# else /* BIG ENDIAN */
if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
# endif
pr_debug("Unsupported firmware endianness\n");
return -EILSEQ;
}
if (size < ehdr->e_shoff + sizeof(Elf64_Shdr)) {
pr_debug("Image is too small\n");
return -ENOSPC;
}
if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
pr_debug("Image is corrupted (bad magic)\n");
return -EBADF;
}
if (ehdr->e_phnum == 0) {
pr_debug("No loadable segments\n");
return -ENOEXEC;
}
if (ehdr->e_phoff > size) {
pr_debug("Firmware size is too small\n");
return -ENOSPC;
}
return 0;
}
/* Basic function to verify ELF image format */
int rproc_elf_sanity_check(ulong addr, ulong size)
{
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
if (!addr) {
dev_err(dev, "Invalid firmware address\n");
return -EFAULT;
}
if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
return rproc_elf64_sanity_check(addr, size);
else
return rproc_elf32_sanity_check(addr, size);
}
int rproc_elf32_load_image(struct udevice *dev, unsigned long addr, ulong size)
{
Elf32_Ehdr *ehdr; /* Elf header structure pointer */
Elf32_Phdr *phdr; /* Program header structure pointer */
const struct dm_rproc_ops *ops;
unsigned int i, ret;
ret = rproc_elf32_sanity_check(addr, size);
if (ret) {
dev_err(dev, "Invalid ELF32 Image %d\n", ret);
return ret;
}
ehdr = (Elf32_Ehdr *)addr;
phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
ops = rproc_get_ops(dev);
/* Load each program header */
for (i = 0; i < ehdr->e_phnum; ++i) {
void *dst = (void *)(uintptr_t)phdr->p_paddr;
void *src = (void *)addr + phdr->p_offset;
if (phdr->p_type != PT_LOAD)
continue;
if (ops->device_to_virt)
dst = ops->device_to_virt(dev, (ulong)dst,
phdr->p_memsz);
dev_dbg(dev, "Loading phdr %i to 0x%p (%i bytes)\n",
i, dst, phdr->p_filesz);
if (phdr->p_filesz)
memcpy(dst, src, phdr->p_filesz);
if (phdr->p_filesz != phdr->p_memsz)
memset(dst + phdr->p_filesz, 0x00,
phdr->p_memsz - phdr->p_filesz);
flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
roundup((unsigned long)dst + phdr->p_filesz,
ARCH_DMA_MINALIGN) -
rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
++phdr;
}
return 0;
}
int rproc_elf64_load_image(struct udevice *dev, ulong addr, ulong size)
{
const struct dm_rproc_ops *ops = rproc_get_ops(dev);
u64 da, memsz, filesz, offset;
Elf64_Ehdr *ehdr;
Elf64_Phdr *phdr;
int i, ret = 0;
void *ptr;
dev_dbg(dev, "%s: addr = 0x%lx size = 0x%lx\n", __func__, addr, size);
if (rproc_elf64_sanity_check(addr, size))
return -EINVAL;
ehdr = (Elf64_Ehdr *)addr;
phdr = (Elf64_Phdr *)(addr + (ulong)ehdr->e_phoff);
/* go through the available ELF segments */
for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
da = phdr->p_paddr;
memsz = phdr->p_memsz;
filesz = phdr->p_filesz;
offset = phdr->p_offset;
if (phdr->p_type != PT_LOAD)
continue;
dev_dbg(dev, "%s:phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
__func__, phdr->p_type, da, memsz, filesz);
ptr = (void *)(uintptr_t)da;
if (ops->device_to_virt) {
ptr = ops->device_to_virt(dev, da, phdr->p_memsz);
if (!ptr) {
dev_err(dev, "bad da 0x%llx mem 0x%llx\n", da,
memsz);
ret = -EINVAL;
break;
}
}
if (filesz)
memcpy(ptr, (void *)addr + offset, filesz);
if (filesz != memsz)
memset(ptr + filesz, 0x00, memsz - filesz);
flush_cache(rounddown((ulong)ptr, ARCH_DMA_MINALIGN),
roundup((ulong)ptr + filesz, ARCH_DMA_MINALIGN) -
rounddown((ulong)ptr, ARCH_DMA_MINALIGN));
}
return ret;
}
int rproc_elf_load_image(struct udevice *dev, ulong addr, ulong size)
{
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
if (!addr) {
dev_err(dev, "Invalid firmware address\n");
return -EFAULT;
}
if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
return rproc_elf64_load_image(dev, addr, size);
else
return rproc_elf32_load_image(dev, addr, size);
}
static ulong rproc_elf32_get_boot_addr(ulong addr)
{
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
return ehdr->e_entry;
}
static ulong rproc_elf64_get_boot_addr(ulong addr)
{
Elf64_Ehdr *ehdr = (Elf64_Ehdr *)addr;
return ehdr->e_entry;
}
ulong rproc_elf_get_boot_addr(struct udevice *dev, ulong addr)
{
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
return rproc_elf64_get_boot_addr(addr);
else
return rproc_elf32_get_boot_addr(addr);
}
@@ -0,0 +1,436 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2015
* Texas Instruments Incorporated - http://www.ti.com/
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <common.h>
#include <errno.h>
#include <fdtdec.h>
#include <malloc.h>
#include <remoteproc.h>
#include <asm/io.h>
#include <dm/device-internal.h>
#include <dm.h>
#include <dm/uclass.h>
#include <dm/uclass-internal.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* for_each_remoteproc_device() - iterate through the list of rproc devices
* @fn: check function to call per match, if this function returns fail,
* iteration is aborted with the resultant error value
* @skip_dev: Device to skip calling the callback about.
* @data: Data to pass to the callback function
*
* Return: 0 if none of the callback returned a non 0 result, else returns the
* result from the callback function
*/
static int for_each_remoteproc_device(int (*fn) (struct udevice *dev,
struct dm_rproc_uclass_pdata *uc_pdata,
const void *data),
struct udevice *skip_dev,
const void *data)
{
struct udevice *dev;
struct dm_rproc_uclass_pdata *uc_pdata;
int ret;
for (ret = uclass_find_first_device(UCLASS_REMOTEPROC, &dev); dev;
ret = uclass_find_next_device(&dev)) {
if (ret || dev == skip_dev)
continue;
uc_pdata = dev_get_uclass_platdata(dev);
ret = fn(dev, uc_pdata, data);
if (ret)
return ret;
}
return 0;
}
/**
* _rproc_name_is_unique() - iteration helper to check if rproc name is unique
* @dev: device that we are checking name for
* @uc_pdata: uclass platform data
* @data: compare data (this is the name we want to ensure is unique)
*
* Return: 0 is there is no match(is unique); if there is a match(we dont
* have a unique name), return -EINVAL.
*/
static int _rproc_name_is_unique(struct udevice *dev,
struct dm_rproc_uclass_pdata *uc_pdata,
const void *data)
{
const char *check_name = data;
/* devices not yet populated with data - so skip them */
if (!uc_pdata->name || !check_name)
return 0;
/* Return 0 to search further if we dont match */
if (strlen(uc_pdata->name) != strlen(check_name))
return 0;
if (!strcmp(uc_pdata->name, check_name))
return -EINVAL;
return 0;
}
/**
* rproc_name_is_unique() - Check if the rproc name is unique
* @check_dev: Device we are attempting to ensure is unique
* @check_name: Name we are trying to ensure is unique.
*
* Return: true if we have a unique name, false if name is not unique.
*/
static bool rproc_name_is_unique(struct udevice *check_dev,
const char *check_name)
{
int ret;
ret = for_each_remoteproc_device(_rproc_name_is_unique,
check_dev, check_name);
return ret ? false : true;
}
/**
* rproc_pre_probe() - Pre probe accessor for the uclass
* @dev: device for which we are preprobing
*
* Parses and fills up the uclass pdata for use as needed by core and
* remote proc drivers.
*
* Return: 0 if all wernt ok, else appropriate error value.
*/
static int rproc_pre_probe(struct udevice *dev)
{
struct dm_rproc_uclass_pdata *uc_pdata;
const struct dm_rproc_ops *ops;
uc_pdata = dev_get_uclass_platdata(dev);
/* See if we need to populate via fdt */
if (!dev->platdata) {
#if CONFIG_IS_ENABLED(OF_CONTROL)
int node = dev_of_offset(dev);
const void *blob = gd->fdt_blob;
bool tmp;
if (!blob) {
debug("'%s' no dt?\n", dev->name);
return -EINVAL;
}
debug("'%s': using fdt\n", dev->name);
uc_pdata->name = fdt_getprop(blob, node,
"remoteproc-name", NULL);
/* Default is internal memory mapped */
uc_pdata->mem_type = RPROC_INTERNAL_MEMORY_MAPPED;
tmp = fdtdec_get_bool(blob, node,
"remoteproc-internal-memory-mapped");
if (tmp)
uc_pdata->mem_type = RPROC_INTERNAL_MEMORY_MAPPED;
#else
/* Nothing much we can do about this, can we? */
return -EINVAL;
#endif
} else {
struct dm_rproc_uclass_pdata *pdata = dev->platdata;
debug("'%s': using legacy data\n", dev->name);
if (pdata->name)
uc_pdata->name = pdata->name;
uc_pdata->mem_type = pdata->mem_type;
uc_pdata->driver_plat_data = pdata->driver_plat_data;
}
/* Else try using device Name */
if (!uc_pdata->name)
uc_pdata->name = dev->name;
if (!uc_pdata->name) {
debug("Unnamed device!");
return -EINVAL;
}
if (!rproc_name_is_unique(dev, uc_pdata->name)) {
debug("%s duplicate name '%s'\n", dev->name, uc_pdata->name);
return -EINVAL;
}
ops = rproc_get_ops(dev);
if (!ops) {
debug("%s driver has no ops?\n", dev->name);
return -EINVAL;
}
if (!ops->load || !ops->start) {
debug("%s driver has missing mandatory ops?\n", dev->name);
return -EINVAL;
}
return 0;
}
/**
* rproc_post_probe() - post probe accessor for the uclass
* @dev: deivce we finished probing
*
* initiate init function after the probe is completed. This allows
* the remote processor drivers to split up the initializations between
* probe and init as needed.
*
* Return: if the remote proc driver has a init routine, invokes it and
* hands over the return value. overall, 0 if all went well, else appropriate
* error value.
*/
static int rproc_post_probe(struct udevice *dev)
{
const struct dm_rproc_ops *ops;
ops = rproc_get_ops(dev);
if (!ops) {
debug("%s driver has no ops?\n", dev->name);
return -EINVAL;
}
if (ops->init)
return ops->init(dev);
return 0;
}
UCLASS_DRIVER(rproc) = {
.id = UCLASS_REMOTEPROC,
.name = "remoteproc",
.flags = DM_UC_FLAG_SEQ_ALIAS,
.pre_probe = rproc_pre_probe,
.post_probe = rproc_post_probe,
.per_device_platdata_auto_alloc_size =
sizeof(struct dm_rproc_uclass_pdata),
};
/* Remoteproc subsystem access functions */
/**
* _rproc_probe_dev() - iteration helper to probe a rproc device
* @dev: device to probe
* @uc_pdata: uclass data allocated for the device
* @data: unused
*
* Return: 0 if all ok, else appropriate error value.
*/
static int _rproc_probe_dev(struct udevice *dev,
struct dm_rproc_uclass_pdata *uc_pdata,
const void *data)
{
int ret;
ret = device_probe(dev);
if (ret)
debug("%s: Failed to initialize - %d\n", dev->name, ret);
return ret;
}
/**
* _rproc_dev_is_probed() - check if the device has been probed
* @dev: device to check
* @uc_pdata: unused
* @data: unused
*
* Return: -EAGAIN if not probed else return 0
*/
static int _rproc_dev_is_probed(struct udevice *dev,
struct dm_rproc_uclass_pdata *uc_pdata,
const void *data)
{
if (dev->flags & DM_FLAG_ACTIVATED)
return 0;
return -EAGAIN;
}
bool rproc_is_initialized(void)
{
int ret = for_each_remoteproc_device(_rproc_dev_is_probed, NULL, NULL);
return ret ? false : true;
}
int rproc_init(void)
{
int ret;
if (rproc_is_initialized()) {
debug("Already initialized\n");
return -EINVAL;
}
ret = for_each_remoteproc_device(_rproc_probe_dev, NULL, NULL);
return ret;
}
int rproc_dev_init(int id)
{
struct udevice *dev = NULL;
int ret;
ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev);
if (ret) {
debug("Unknown remote processor id '%d' requested(%d)\n",
id, ret);
return ret;
}
ret = device_probe(dev);
if (ret)
debug("%s: Failed to initialize - %d\n", dev->name, ret);
return ret;
}
int rproc_load(int id, ulong addr, ulong size)
{
struct udevice *dev = NULL;
struct dm_rproc_uclass_pdata *uc_pdata;
const struct dm_rproc_ops *ops;
int ret;
ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev);
if (ret) {
debug("Unknown remote processor id '%d' requested(%d)\n",
id, ret);
return ret;
}
uc_pdata = dev_get_uclass_platdata(dev);
ops = rproc_get_ops(dev);
if (!ops) {
debug("%s driver has no ops?\n", dev->name);
return -EINVAL;
}
debug("Loading to '%s' from address 0x%08lX size of %lu bytes\n",
uc_pdata->name, addr, size);
if (ops->load)
return ops->load(dev, addr, size);
debug("%s: data corruption?? mandatory function is missing!\n",
dev->name);
return -EINVAL;
};
/*
* Completely internal helper enums..
* Keeping this isolated helps this code evolve independent of other
* parts..
*/
enum rproc_ops {
RPROC_START,
RPROC_STOP,
RPROC_RESET,
RPROC_PING,
RPROC_RUNNING,
};
/**
* _rproc_ops_wrapper() - wrapper for invoking remote proc driver callback
* @id: id of the remote processor
* @op: one of rproc_ops that indicate what operation to invoke
*
* Most of the checks and verification for remoteproc operations are more
* or less same for almost all operations. This allows us to put a wrapper
* and use the common checks to allow the driver to function appropriately.
*
* Return: 0 if all ok, else appropriate error value.
*/
static int _rproc_ops_wrapper(int id, enum rproc_ops op)
{
struct udevice *dev = NULL;
struct dm_rproc_uclass_pdata *uc_pdata;
const struct dm_rproc_ops *ops;
int (*fn)(struct udevice *dev);
bool mandatory = false;
char *op_str;
int ret;
ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev);
if (ret) {
debug("Unknown remote processor id '%d' requested(%d)\n",
id, ret);
return ret;
}
uc_pdata = dev_get_uclass_platdata(dev);
ops = rproc_get_ops(dev);
if (!ops) {
debug("%s driver has no ops?\n", dev->name);
return -EINVAL;
}
switch (op) {
case RPROC_START:
fn = ops->start;
mandatory = true;
op_str = "Starting";
break;
case RPROC_STOP:
fn = ops->stop;
op_str = "Stopping";
break;
case RPROC_RESET:
fn = ops->reset;
op_str = "Resetting";
break;
case RPROC_RUNNING:
fn = ops->is_running;
op_str = "Checking if running:";
break;
case RPROC_PING:
fn = ops->ping;
op_str = "Pinging";
break;
default:
debug("what is '%d' operation??\n", op);
return -EINVAL;
}
debug("%s %s...\n", op_str, uc_pdata->name);
if (fn)
return fn(dev);
if (mandatory)
debug("%s: data corruption?? mandatory function is missing!\n",
dev->name);
return -ENOSYS;
}
int rproc_start(int id)
{
return _rproc_ops_wrapper(id, RPROC_START);
};
int rproc_stop(int id)
{
return _rproc_ops_wrapper(id, RPROC_STOP);
};
int rproc_reset(int id)
{
return _rproc_ops_wrapper(id, RPROC_RESET);
};
int rproc_ping(int id)
{
return _rproc_ops_wrapper(id, RPROC_PING);
};
int rproc_is_running(int id)
{
return _rproc_ops_wrapper(id, RPROC_RUNNING);
};
@@ -0,0 +1,357 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2015
* Texas Instruments Incorporated - http://www.ti.com/
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <remoteproc.h>
#include <asm/io.h>
/**
* enum sandbox_state - different device states
* @sb_booted: Entry condition, just booted
* @sb_init: Initialized (basic environment is ready)
* @sb_reset: Held in reset (accessible, but not running)
* @sb_loaded: Loaded with image (but not running)
* @sb_running: Processor is running
*/
enum sandbox_state {
sb_booted,
sb_init,
sb_reset,
sb_loaded,
sb_running
};
/**
* struct sandbox_test_devdata - private data per device
* @current_state: device current state
*/
struct sandbox_test_devdata {
enum sandbox_state current_state;
};
/**
* sandbox_dev_move_to_state() - statemachine for our dummy device
* @dev: device to switch state
* @next_state: next proposed state
*
* This tries to follow the following statemachine:
* Entry
* |
* v
* +-------+
* +---+ init |
* | | | <---------------------+
* | +-------+ |
* | |
* | |
* | +--------+ |
* Load| | reset | |
* | | | <----------+ |
* | +--------+ | |
* | |Load | |
* | | | |
* | +----v----+ reset | |
* +-> | | (opt) | |
* | Loaded +-----------+ |
* | | |
* +----+----+ |
* | Start |
* +---v-----+ (opt) |
* +->| Running | Stop |
* Ping +- | +--------------------+
* (opt) +---------+
*
* (is_running does not change state)
*
* Return: 0 when valid state transition is seen, else returns -EINVAL
*/
static int sandbox_dev_move_to_state(struct udevice *dev,
enum sandbox_state next_state)
{
struct sandbox_test_devdata *ddata = dev_get_priv(dev);
/* No state transition is OK */
if (ddata->current_state == next_state)
return 0;
debug("current_state=%d, next_state=%d\n", ddata->current_state,
next_state);
switch (ddata->current_state) {
case sb_booted:
if (next_state == sb_init)
goto ok_state;
break;
case sb_init:
if (next_state == sb_reset || next_state == sb_loaded)
goto ok_state;
break;
case sb_reset:
if (next_state == sb_loaded || next_state == sb_init)
goto ok_state;
break;
case sb_loaded:
if (next_state == sb_reset || next_state == sb_init ||
next_state == sb_running)
goto ok_state;
break;
case sb_running:
if (next_state == sb_reset || next_state == sb_init)
goto ok_state;
break;
};
return -EINVAL;
ok_state:
ddata->current_state = next_state;
return 0;
}
/**
* sandbox_testproc_probe() - basic probe function
* @dev: test proc device that is being probed.
*
* Return: 0 if all went ok, else return appropriate error
*/
static int sandbox_testproc_probe(struct udevice *dev)
{
struct dm_rproc_uclass_pdata *uc_pdata;
struct sandbox_test_devdata *ddata;
int ret;
uc_pdata = dev_get_uclass_platdata(dev);
ddata = dev_get_priv(dev);
if (!ddata) {
debug("%s: platform private data missing\n", uc_pdata->name);
return -EINVAL;
}
ret = sandbox_dev_move_to_state(dev, sb_booted);
debug("%s: called(%d)\n", uc_pdata->name, ret);
return ret;
}
/**
* sandbox_testproc_init() - Simple initialization function
* @dev: device to operate upon
*
* Return: 0 if all went ok, else return appropriate error
*/
static int sandbox_testproc_init(struct udevice *dev)
{
struct dm_rproc_uclass_pdata *uc_pdata;
int ret;
uc_pdata = dev_get_uclass_platdata(dev);
ret = sandbox_dev_move_to_state(dev, sb_init);
debug("%s: called(%d)\n", uc_pdata->name, ret);
if (ret)
debug("%s init failed\n", uc_pdata->name);
return ret;
}
/**
* sandbox_testproc_reset() - Reset the remote processor
* @dev: device to operate upon
*
* Return: 0 if all went ok, else return appropriate error
*/
static int sandbox_testproc_reset(struct udevice *dev)
{
struct dm_rproc_uclass_pdata *uc_pdata;
int ret;
uc_pdata = dev_get_uclass_platdata(dev);
ret = sandbox_dev_move_to_state(dev, sb_reset);
debug("%s: called(%d)\n", uc_pdata->name, ret);
if (ret)
debug("%s reset failed\n", uc_pdata->name);
return ret;
}
/**
* sandbox_testproc_load() - (replace: short desc)
* @dev: device to operate upon
* @addr: Address of the binary image to load
* @size: Size (in bytes) of the binary image to load
*
* Return: 0 if all went ok, else return appropriate error
*/
static int sandbox_testproc_load(struct udevice *dev, ulong addr, ulong size)
{
struct dm_rproc_uclass_pdata *uc_pdata;
int ret;
uc_pdata = dev_get_uclass_platdata(dev);
ret = sandbox_dev_move_to_state(dev, sb_loaded);
debug("%s: called(%d) Loading to %08lX %lu size\n",
uc_pdata->name, ret, addr, size);
if (ret)
debug("%s load failed\n", uc_pdata->name);
return ret;
}
/**
* sandbox_testproc_start() - Start the remote processor
* @dev: device to operate upon
*
* Return: 0 if all went ok, else return appropriate error
*/
static int sandbox_testproc_start(struct udevice *dev)
{
struct dm_rproc_uclass_pdata *uc_pdata;
int ret;
uc_pdata = dev_get_uclass_platdata(dev);
ret = sandbox_dev_move_to_state(dev, sb_running);
debug("%s: called(%d)\n", uc_pdata->name, ret);
if (ret)
debug("%s start failed\n", uc_pdata->name);
return ret;
}
/**
* sandbox_testproc_stop() - Stop the remote processor
* @dev: device to operate upon
*
* Return: 0 if all went ok, else return appropriate error
*/
static int sandbox_testproc_stop(struct udevice *dev)
{
struct dm_rproc_uclass_pdata *uc_pdata;
int ret;
uc_pdata = dev_get_uclass_platdata(dev);
ret = sandbox_dev_move_to_state(dev, sb_init);
debug("%s: called(%d)\n", uc_pdata->name, ret);
if (ret)
debug("%s stop failed\n", uc_pdata->name);
return ret;
}
/**
* sandbox_testproc_is_running() - Check if remote processor is running
* @dev: device to operate upon
*
* Return: 0 if running, 1 if not running
*/
static int sandbox_testproc_is_running(struct udevice *dev)
{
struct dm_rproc_uclass_pdata *uc_pdata;
struct sandbox_test_devdata *ddata;
int ret = 1;
uc_pdata = dev_get_uclass_platdata(dev);
ddata = dev_get_priv(dev);
if (ddata->current_state == sb_running)
ret = 0;
debug("%s: called(%d)\n", uc_pdata->name, ret);
return ret;
}
/**
* sandbox_testproc_ping() - Try pinging remote processor
* @dev: device to operate upon
*
* Return: 0 if running, -EINVAL if not running
*/
static int sandbox_testproc_ping(struct udevice *dev)
{
struct dm_rproc_uclass_pdata *uc_pdata;
struct sandbox_test_devdata *ddata;
int ret;
uc_pdata = dev_get_uclass_platdata(dev);
ddata = dev_get_priv(dev);
if (ddata->current_state == sb_running)
ret = 0;
else
ret = -EINVAL;
debug("%s: called(%d)\n", uc_pdata->name, ret);
if (ret)
debug("%s: No response.(Not started?)\n", uc_pdata->name);
return ret;
}
#define SANDBOX_RPROC_DEV_TO_PHY_OFFSET 0x1000
/**
* sandbox_testproc_device_to_virt() - Convert device address to virtual address
* @dev: device to operate upon
* @da: device address
* @size: Size of the memory region @da is pointing to
* @return converted virtual address
*/
static void *sandbox_testproc_device_to_virt(struct udevice *dev, ulong da,
ulong size)
{
u64 paddr;
/* Use a simple offset conversion */
paddr = da + SANDBOX_RPROC_DEV_TO_PHY_OFFSET;
return phys_to_virt(paddr);
}
static const struct dm_rproc_ops sandbox_testproc_ops = {
.init = sandbox_testproc_init,
.reset = sandbox_testproc_reset,
.load = sandbox_testproc_load,
.start = sandbox_testproc_start,
.stop = sandbox_testproc_stop,
.is_running = sandbox_testproc_is_running,
.ping = sandbox_testproc_ping,
.device_to_virt = sandbox_testproc_device_to_virt,
};
static const struct udevice_id sandbox_ids[] = {
{.compatible = "sandbox,test-processor"},
{}
};
U_BOOT_DRIVER(sandbox_testproc) = {
.name = "sandbox_test_proc",
.of_match = sandbox_ids,
.id = UCLASS_REMOTEPROC,
.ops = &sandbox_testproc_ops,
.probe = sandbox_testproc_probe,
.priv_auto_alloc_size = sizeof(struct sandbox_test_devdata),
};
/* TODO(nm@ti.com): Remove this along with non-DT support */
static struct dm_rproc_uclass_pdata proc_3_test = {
.name = "proc_3_legacy",
.mem_type = RPROC_INTERNAL_MEMORY_MAPPED,
};
U_BOOT_DEVICE(proc_3_demo) = {
.name = "sandbox_test_proc",
.platdata = &proc_3_test,
};
@@ -0,0 +1,258 @@
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
/*
* Copyright (C) 2019, STMicroelectronics - All Rights Reserved
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <regmap.h>
#include <remoteproc.h>
#include <reset.h>
#include <syscon.h>
#include <asm/io.h>
#define RCC_GCR_HOLD_BOOT 0
#define RCC_GCR_RELEASE_BOOT 1
/**
* struct stm32_copro_privdata - power processor private data
* @reset_ctl: reset controller handle
* @hold_boot_regmap: regmap for remote processor reset hold boot
* @hold_boot_offset: offset of the register controlling the hold boot setting
* @hold_boot_mask: bitmask of the register for the hold boot field
* @is_running: is the remote processor running
*/
struct stm32_copro_privdata {
struct reset_ctl reset_ctl;
struct regmap *hold_boot_regmap;
uint hold_boot_offset;
uint hold_boot_mask;
bool is_running;
};
/**
* stm32_copro_probe() - Basic probe
* @dev: corresponding STM32 remote processor device
* @return 0 if all went ok, else corresponding -ve error
*/
static int stm32_copro_probe(struct udevice *dev)
{
struct stm32_copro_privdata *priv;
struct regmap *regmap;
const fdt32_t *cell;
int len, ret;
priv = dev_get_priv(dev);
regmap = syscon_regmap_lookup_by_phandle(dev, "st,syscfg-holdboot");
if (IS_ERR(regmap)) {
dev_err(dev, "unable to find holdboot regmap (%ld)\n",
PTR_ERR(regmap));
return PTR_ERR(regmap);
}
cell = dev_read_prop(dev, "st,syscfg-holdboot", &len);
if (len < 3 * sizeof(fdt32_t)) {
dev_err(dev, "holdboot offset and mask not available\n");
return -EINVAL;
}
priv->hold_boot_regmap = regmap;
priv->hold_boot_offset = fdtdec_get_number(cell + 1, 1);
priv->hold_boot_mask = fdtdec_get_number(cell + 2, 1);
ret = reset_get_by_index(dev, 0, &priv->reset_ctl);
if (ret) {
dev_err(dev, "failed to get reset (%d)\n", ret);
return ret;
}
dev_dbg(dev, "probed\n");
return 0;
}
/**
* stm32_copro_set_hold_boot() - Hold boot bit management
* @dev: corresponding STM32 remote processor device
* @hold: hold boot value
* @return 0 if all went ok, else corresponding -ve error
*/
static int stm32_copro_set_hold_boot(struct udevice *dev, bool hold)
{
struct stm32_copro_privdata *priv;
uint val;
int ret;
priv = dev_get_priv(dev);
val = hold ? RCC_GCR_HOLD_BOOT : RCC_GCR_RELEASE_BOOT;
/*
* Note: shall run an SMC call (STM32_SMC_RCC) if platform is secured.
* To be updated when the code for this SMC service is available which
* is not the case for the time being.
*/
ret = regmap_update_bits(priv->hold_boot_regmap, priv->hold_boot_offset,
priv->hold_boot_mask, val);
if (ret)
dev_err(dev, "failed to set hold boot\n");
return ret;
}
/**
* stm32_copro_device_to_virt() - Convert device address to virtual address
* @dev: corresponding STM32 remote processor device
* @da: device address
* @size: Size of the memory region @da is pointing to
* @return converted virtual address
*/
static void *stm32_copro_device_to_virt(struct udevice *dev, ulong da,
ulong size)
{
fdt32_t in_addr = cpu_to_be32(da), end_addr;
u64 paddr;
paddr = dev_translate_dma_address(dev, &in_addr);
if (paddr == OF_BAD_ADDR) {
dev_err(dev, "Unable to convert address %ld\n", da);
return NULL;
}
end_addr = cpu_to_be32(da + size - 1);
if (dev_translate_dma_address(dev, &end_addr) == OF_BAD_ADDR) {
dev_err(dev, "Unable to convert address %ld\n", da + size - 1);
return NULL;
}
return phys_to_virt(paddr);
}
/**
* stm32_copro_load() - Loadup the STM32 remote processor
* @dev: corresponding STM32 remote processor device
* @addr: Address in memory where image is stored
* @size: Size in bytes of the image
* @return 0 if all went ok, else corresponding -ve error
*/
static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size)
{
struct stm32_copro_privdata *priv;
int ret;
priv = dev_get_priv(dev);
ret = stm32_copro_set_hold_boot(dev, true);
if (ret)
return ret;
ret = reset_assert(&priv->reset_ctl);
if (ret) {
dev_err(dev, "Unable to assert reset line (ret=%d)\n", ret);
return ret;
}
return rproc_elf32_load_image(dev, addr, size);
}
/**
* stm32_copro_start() - Start the STM32 remote processor
* @dev: corresponding STM32 remote processor device
* @return 0 if all went ok, else corresponding -ve error
*/
static int stm32_copro_start(struct udevice *dev)
{
struct stm32_copro_privdata *priv;
int ret;
priv = dev_get_priv(dev);
/* move hold boot from true to false start the copro */
ret = stm32_copro_set_hold_boot(dev, false);
if (ret)
return ret;
/*
* Once copro running, reset hold boot flag to avoid copro
* rebooting autonomously
*/
ret = stm32_copro_set_hold_boot(dev, true);
priv->is_running = !ret;
return ret;
}
/**
* stm32_copro_reset() - Reset the STM32 remote processor
* @dev: corresponding STM32 remote processor device
* @return 0 if all went ok, else corresponding -ve error
*/
static int stm32_copro_reset(struct udevice *dev)
{
struct stm32_copro_privdata *priv;
int ret;
priv = dev_get_priv(dev);
ret = stm32_copro_set_hold_boot(dev, true);
if (ret)
return ret;
ret = reset_assert(&priv->reset_ctl);
if (ret) {
dev_err(dev, "Unable to assert reset line (ret=%d)\n", ret);
return ret;
}
priv->is_running = false;
return 0;
}
/**
* stm32_copro_stop() - Stop the STM32 remote processor
* @dev: corresponding STM32 remote processor device
* @return 0 if all went ok, else corresponding -ve error
*/
static int stm32_copro_stop(struct udevice *dev)
{
return stm32_copro_reset(dev);
}
/**
* stm32_copro_is_running() - Is the STM32 remote processor running
* @dev: corresponding STM32 remote processor device
* @return 1 if the remote processor is running, 0 otherwise
*/
static int stm32_copro_is_running(struct udevice *dev)
{
struct stm32_copro_privdata *priv;
priv = dev_get_priv(dev);
return priv->is_running;
}
static const struct dm_rproc_ops stm32_copro_ops = {
.load = stm32_copro_load,
.start = stm32_copro_start,
.stop = stm32_copro_stop,
.reset = stm32_copro_reset,
.is_running = stm32_copro_is_running,
.device_to_virt = stm32_copro_device_to_virt,
};
static const struct udevice_id stm32_copro_ids[] = {
{.compatible = "st,stm32mp1-m4"},
{}
};
U_BOOT_DRIVER(stm32_copro) = {
.name = "stm32_m4_proc",
.of_match = stm32_copro_ids,
.id = UCLASS_REMOTEPROC,
.ops = &stm32_copro_ops,
.probe = stm32_copro_probe,
.priv_auto_alloc_size = sizeof(struct stm32_copro_privdata),
};
@@ -0,0 +1,229 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Texas Instruments' K3 ARM64 Remoteproc driver
*
* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
*
*/
#include <common.h>
#include <dm.h>
#include <remoteproc.h>
#include <errno.h>
#include <clk.h>
#include <reset.h>
#include <asm/io.h>
#include <power-domain.h>
#include <linux/soc/ti/ti_sci_protocol.h>
#include "ti_sci_proc.h"
#define INVALID_ID 0xffff
#define GTC_CNTCR_REG 0x0
#define GTC_CNTR_EN 0x3
/**
* struct k3_arm64_privdata - Structure representing Remote processor data.
* @rproc_pwrdmn: rproc power domain data
* @rproc_rst: rproc reset control data
* @sci: Pointer to TISCI handle
* @tsp: TISCI processor control helper structure
* @gtc_base: Timer base address.
*/
struct k3_arm64_privdata {
struct power_domain rproc_pwrdmn;
struct power_domain gtc_pwrdmn;
struct reset_ctl rproc_rst;
struct ti_sci_proc tsp;
void *gtc_base;
};
/**
* k3_arm64_load() - Load up the Remote processor image
* @dev: rproc device pointer
* @addr: Address at which image is available
* @size: size of the image
*
* Return: 0 if all goes good, else appropriate error message.
*/
static int k3_arm64_load(struct udevice *dev, ulong addr, ulong size)
{
struct k3_arm64_privdata *rproc = dev_get_priv(dev);
int ret;
dev_dbg(dev, "%s addr = 0x%lx, size = 0x%lx\n", __func__, addr, size);
/* request for the processor */
ret = ti_sci_proc_request(&rproc->tsp);
if (ret)
return ret;
return ti_sci_proc_set_config(&rproc->tsp, addr, 0, 0);
}
/**
* k3_arm64_start() - Start the remote processor
* @dev: rproc device pointer
*
* Return: 0 if all went ok, else return appropriate error
*/
static int k3_arm64_start(struct udevice *dev)
{
struct k3_arm64_privdata *rproc = dev_get_priv(dev);
int ret;
dev_dbg(dev, "%s\n", __func__);
ret = power_domain_on(&rproc->gtc_pwrdmn);
if (ret) {
dev_err(dev, "power_domain_on() failed: %d\n", ret);
return ret;
}
/* Enable the timer before starting remote core */
writel(GTC_CNTR_EN, rproc->gtc_base + GTC_CNTCR_REG);
/*
* Setting the right clock frequency would have taken care by
* assigned-clock-rates during the device probe. So no need to
* set the frequency again here.
*/
ret = power_domain_on(&rproc->rproc_pwrdmn);
if (ret) {
dev_err(dev, "power_domain_on() failed: %d\n", ret);
return ret;
}
return ti_sci_proc_release(&rproc->tsp);
}
/**
* k3_arm64_init() - Initialize the remote processor
* @dev: rproc device pointer
*
* Return: 0 if all went ok, else return appropriate error
*/
static int k3_arm64_init(struct udevice *dev)
{
dev_dbg(dev, "%s\n", __func__);
/* Enable the module */
dev_dbg(dev, "%s: rproc successfully initialized\n", __func__);
return 0;
}
static const struct dm_rproc_ops k3_arm64_ops = {
.init = k3_arm64_init,
.load = k3_arm64_load,
.start = k3_arm64_start,
};
static int ti_sci_proc_of_to_priv(struct udevice *dev, struct ti_sci_proc *tsp)
{
dev_dbg(dev, "%s\n", __func__);
tsp->sci = ti_sci_get_by_phandle(dev, "ti,sci");
if (IS_ERR(tsp->sci)) {
dev_err(dev, "ti_sci get failed: %ld\n", PTR_ERR(tsp->sci));
return PTR_ERR(tsp->sci);
}
tsp->proc_id = dev_read_u32_default(dev, "ti,sci-proc-id", INVALID_ID);
if (tsp->proc_id == INVALID_ID) {
dev_err(dev, "proc id not populated\n");
return -ENOENT;
}
tsp->host_id = dev_read_u32_default(dev, "ti,sci-host-id", INVALID_ID);
tsp->ops = &tsp->sci->ops.proc_ops;
return 0;
}
/**
* k3_of_to_priv() - generate private data from device tree
* @dev: corresponding k3 remote processor device
* @priv: pointer to driver specific private data
*
* Return: 0 if all goes good, else appropriate error message.
*/
static int k3_arm64_of_to_priv(struct udevice *dev,
struct k3_arm64_privdata *rproc)
{
int ret;
dev_dbg(dev, "%s\n", __func__);
ret = power_domain_get_by_index(dev, &rproc->rproc_pwrdmn, 1);
if (ret) {
dev_err(dev, "power_domain_get() failed: %d\n", ret);
return ret;
}
ret = power_domain_get_by_index(dev, &rproc->gtc_pwrdmn, 0);
if (ret) {
dev_err(dev, "power_domain_get() failed: %d\n", ret);
return ret;
}
ret = reset_get_by_index(dev, 0, &rproc->rproc_rst);
if (ret) {
dev_err(dev, "reset_get() failed: %d\n", ret);
return ret;
}
ret = ti_sci_proc_of_to_priv(dev, &rproc->tsp);
if (ret)
return ret;
rproc->gtc_base = dev_read_addr_ptr(dev);
if (!rproc->gtc_base) {
dev_err(dev, "Get address failed\n");
return -ENODEV;
}
return 0;
}
/**
* k3_arm64_probe() - Basic probe
* @dev: corresponding k3 remote processor device
*
* Return: 0 if all goes good, else appropriate error message.
*/
static int k3_arm64_probe(struct udevice *dev)
{
struct k3_arm64_privdata *priv;
int ret;
dev_dbg(dev, "%s\n", __func__);
priv = dev_get_priv(dev);
ret = k3_arm64_of_to_priv(dev, priv);
if (ret) {
dev_dbg(dev, "%s: Probe failed with error %d\n", __func__, ret);
return ret;
}
dev_dbg(dev, "Remoteproc successfully probed\n");
return 0;
}
static const struct udevice_id k3_arm64_ids[] = {
{ .compatible = "ti,am654-arm64"},
{ .compatible = "ti,am654-rproc"},
{}
};
U_BOOT_DRIVER(k3_arm64) = {
.name = "k3_arm64",
.of_match = k3_arm64_ids,
.id = UCLASS_REMOTEPROC,
.ops = &k3_arm64_ops,
.probe = k3_arm64_probe,
.priv_auto_alloc_size = sizeof(struct k3_arm64_privdata),
.flags = DM_FLAG_DEFAULT_PD_CTRL_OFF,
};
@@ -0,0 +1,354 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Texas Instruments' K3 DSP Remoteproc driver
*
* Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
*
*/
#include <common.h>
#include <dm.h>
#include <remoteproc.h>
#include <errno.h>
#include <clk.h>
#include <reset.h>
#include <asm/io.h>
#include <power-domain.h>
#include <linux/soc/ti/ti_sci_protocol.h>
#include "ti_sci_proc.h"
#define KEYSTONE_RPROC_LOCAL_ADDRESS_MASK (SZ_16M - 1)
/**
* struct k3_dsp_mem - internal memory structure
* @cpu_addr: MPU virtual address of the memory region
* @bus_addr: Bus address used to access the memory region
* @dev_addr: Device address from remoteproc view
* @size: Size of the memory region
*/
struct k3_dsp_mem {
void __iomem *cpu_addr;
phys_addr_t bus_addr;
phys_addr_t dev_addr;
size_t size;
};
/**
* struct k3_dsp_privdata - Structure representing Remote processor data.
* @rproc_rst: rproc reset control data
* @tsp: Pointer to TISCI proc contrl handle
* @mem: Array of available memories
* @num_mem: Number of available memories
*/
struct k3_dsp_privdata {
struct reset_ctl dsp_rst;
struct ti_sci_proc tsp;
struct k3_dsp_mem *mem;
int num_mems;
};
/**
* k3_dsp_load() - Load up the Remote processor image
* @dev: rproc device pointer
* @addr: Address at which image is available
* @size: size of the image
*
* Return: 0 if all goes good, else appropriate error message.
*/
static int k3_dsp_load(struct udevice *dev, ulong addr, ulong size)
{
struct k3_dsp_privdata *dsp = dev_get_priv(dev);
u32 boot_vector;
int ret;
dev_dbg(dev, "%s addr = 0x%lx, size = 0x%lx\n", __func__, addr, size);
ret = ti_sci_proc_request(&dsp->tsp);
if (ret)
return ret;
ret = rproc_elf_load_image(dev, addr, size);
if (ret < 0) {
dev_err(dev, "Loading elf failed %d\n", ret);
goto proc_release;
}
boot_vector = rproc_elf_get_boot_addr(dev, addr);
dev_dbg(dev, "%s: Boot vector = 0x%x\n", __func__, boot_vector);
ret = ti_sci_proc_set_config(&dsp->tsp, boot_vector, 0, 0);
proc_release:
ti_sci_proc_release(&dsp->tsp);
return ret;
}
/**
* k3_dsp_start() - Start the remote processor
* @dev: rproc device pointer
*
* Return: 0 if all went ok, else return appropriate error
*/
static int k3_dsp_start(struct udevice *dev)
{
struct k3_dsp_privdata *dsp = dev_get_priv(dev);
int ret;
dev_dbg(dev, "%s\n", __func__);
ret = ti_sci_proc_request(&dsp->tsp);
if (ret)
return ret;
/*
* Setting the right clock frequency would have taken care by
* assigned-clock-rates during the device probe. So no need to
* set the frequency again here.
*/
ret = ti_sci_proc_power_domain_on(&dsp->tsp);
if (ret)
goto proc_release;
ret = reset_deassert(&dsp->dsp_rst);
proc_release:
ti_sci_proc_release(&dsp->tsp);
return ret;
}
static int k3_dsp_stop(struct udevice *dev)
{
struct k3_dsp_privdata *dsp = dev_get_priv(dev);
dev_dbg(dev, "%s\n", __func__);
ti_sci_proc_request(&dsp->tsp);
reset_assert(&dsp->dsp_rst);
ti_sci_proc_power_domain_off(&dsp->tsp);
ti_sci_proc_release(&dsp->tsp);
return 0;
}
/**
* k3_dsp_init() - Initialize the remote processor
* @dev: rproc device pointer
*
* Return: 0 if all went ok, else return appropriate error
*/
static int k3_dsp_init(struct udevice *dev)
{
dev_dbg(dev, "%s\n", __func__);
return 0;
}
static int k3_dsp_reset(struct udevice *dev)
{
dev_dbg(dev, "%s\n", __func__);
return 0;
}
static void *k3_dsp_da_to_va(struct udevice *dev, ulong da, ulong len)
{
struct k3_dsp_privdata *dsp = dev_get_priv(dev);
phys_addr_t bus_addr, dev_addr;
void __iomem *va = NULL;
size_t size;
u32 offset;
int i;
dev_dbg(dev, "%s\n", __func__);
if (len <= 0)
return NULL;
for (i = 0; i < dsp->num_mems; i++) {
bus_addr = dsp->mem[i].bus_addr;
dev_addr = dsp->mem[i].dev_addr;
size = dsp->mem[i].size;
if (da >= dev_addr && ((da + len) <= (dev_addr + size))) {
offset = da - dev_addr;
va = dsp->mem[i].cpu_addr + offset;
return (__force void *)va;
}
if (da >= bus_addr && (da + len) <= (bus_addr + size)) {
offset = da - bus_addr;
va = dsp->mem[i].cpu_addr + offset;
return (__force void *)va;
}
}
/* Assume it is DDR region and return da */
return map_physmem(da, len, MAP_NOCACHE);
}
static const struct dm_rproc_ops k3_dsp_ops = {
.init = k3_dsp_init,
.load = k3_dsp_load,
.start = k3_dsp_start,
.stop = k3_dsp_stop,
.reset = k3_dsp_reset,
.device_to_virt = k3_dsp_da_to_va,
};
static int ti_sci_proc_of_to_priv(struct udevice *dev, struct ti_sci_proc *tsp)
{
u32 ids[2];
int ret;
dev_dbg(dev, "%s\n", __func__);
tsp->sci = ti_sci_get_by_phandle(dev, "ti,sci");
if (IS_ERR(tsp->sci)) {
dev_err(dev, "ti_sci get failed: %ld\n", PTR_ERR(tsp->sci));
return PTR_ERR(tsp->sci);
}
ret = dev_read_u32_array(dev, "ti,sci-proc-ids", ids, 2);
if (ret) {
dev_err(dev, "Proc IDs not populated %d\n", ret);
return ret;
}
tsp->ops = &tsp->sci->ops.proc_ops;
tsp->proc_id = ids[0];
tsp->host_id = ids[1];
tsp->dev_id = dev_read_u32_default(dev, "ti,sci-dev-id",
TI_SCI_RESOURCE_NULL);
if (tsp->dev_id == TI_SCI_RESOURCE_NULL) {
dev_err(dev, "Device ID not populated %d\n", ret);
return -ENODEV;
}
return 0;
}
static int k3_dsp_of_get_memories(struct udevice *dev)
{
static const char * const mem_names[] = {"l2sram", "l1pram", "l1dram"};
struct k3_dsp_privdata *dsp = dev_get_priv(dev);
int i;
dev_dbg(dev, "%s\n", __func__);
dsp->num_mems = ARRAY_SIZE(mem_names);
dsp->mem = calloc(dsp->num_mems, sizeof(*dsp->mem));
if (!dsp->mem)
return -ENOMEM;
for (i = 0; i < dsp->num_mems; i++) {
/* C71 cores only have a L1P Cache, there are no L1P SRAMs */
if (device_is_compatible(dev, "ti,j721e-c71-dsp") &&
!strcmp(mem_names[i], "l1pram")) {
dsp->mem[i].bus_addr = FDT_ADDR_T_NONE;
dsp->mem[i].dev_addr = FDT_ADDR_T_NONE;
dsp->mem[i].cpu_addr = NULL;
dsp->mem[i].size = 0;
continue;
}
dsp->mem[i].bus_addr = dev_read_addr_size_name(dev, mem_names[i],
(fdt_addr_t *)&dsp->mem[i].size);
if (dsp->mem[i].bus_addr == FDT_ADDR_T_NONE) {
dev_err(dev, "%s bus address not found\n", mem_names[i]);
return -EINVAL;
}
dsp->mem[i].cpu_addr = map_physmem(dsp->mem[i].bus_addr,
dsp->mem[i].size,
MAP_NOCACHE);
dsp->mem[i].dev_addr = dsp->mem[i].bus_addr &
KEYSTONE_RPROC_LOCAL_ADDRESS_MASK;
dev_dbg(dev, "memory %8s: bus addr %pa size 0x%zx va %p da %pa\n",
mem_names[i], &dsp->mem[i].bus_addr,
dsp->mem[i].size, dsp->mem[i].cpu_addr,
&dsp->mem[i].dev_addr);
}
return 0;
}
/**
* k3_of_to_priv() - generate private data from device tree
* @dev: corresponding k3 dsp processor device
* @dsp: pointer to driver specific private data
*
* Return: 0 if all goes good, else appropriate error message.
*/
static int k3_dsp_of_to_priv(struct udevice *dev, struct k3_dsp_privdata *dsp)
{
int ret;
dev_dbg(dev, "%s\n", __func__);
ret = reset_get_by_index(dev, 0, &dsp->dsp_rst);
if (ret) {
dev_err(dev, "reset_get() failed: %d\n", ret);
return ret;
}
ret = ti_sci_proc_of_to_priv(dev, &dsp->tsp);
if (ret)
return ret;
ret = k3_dsp_of_get_memories(dev);
if (ret)
return ret;
return 0;
}
/**
* k3_dsp_probe() - Basic probe
* @dev: corresponding k3 remote processor device
*
* Return: 0 if all goes good, else appropriate error message.
*/
static int k3_dsp_probe(struct udevice *dev)
{
struct k3_dsp_privdata *dsp;
int ret;
dev_dbg(dev, "%s\n", __func__);
dsp = dev_get_priv(dev);
ret = k3_dsp_of_to_priv(dev, dsp);
if (ret) {
dev_dbg(dev, "%s: Probe failed with error %d\n", __func__, ret);
return ret;
}
dev_dbg(dev, "Remoteproc successfully probed\n");
return 0;
}
static int k3_dsp_remove(struct udevice *dev)
{
struct k3_dsp_privdata *dsp = dev_get_priv(dev);
free(dsp->mem);
return 0;
}
static const struct udevice_id k3_dsp_ids[] = {
{ .compatible = "ti,j721e-c66-dsp"},
{ .compatible = "ti,j721e-c71-dsp"},
{}
};
U_BOOT_DRIVER(k3_dsp) = {
.name = "k3_dsp",
.of_match = k3_dsp_ids,
.id = UCLASS_REMOTEPROC,
.ops = &k3_dsp_ops,
.probe = k3_dsp_probe,
.remove = k3_dsp_remove,
.priv_auto_alloc_size = sizeof(struct k3_dsp_privdata),
};
@@ -0,0 +1,816 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Texas Instruments' K3 R5 Remoteproc driver
*
* Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
*/
#include <common.h>
#include <dm.h>
#include <remoteproc.h>
#include <errno.h>
#include <clk.h>
#include <reset.h>
#include <asm/io.h>
#include <linux/kernel.h>
#include <linux/soc/ti/ti_sci_protocol.h>
#include "ti_sci_proc.h"
/*
* R5F's view of this address can either be for ATCM or BTCM with the other
* at address 0x0 based on loczrama signal.
*/
#define K3_R5_TCM_DEV_ADDR 0x41010000
/* R5 TI-SCI Processor Configuration Flags */
#define PROC_BOOT_CFG_FLAG_R5_DBG_EN 0x00000001
#define PROC_BOOT_CFG_FLAG_R5_DBG_NIDEN 0x00000002
#define PROC_BOOT_CFG_FLAG_R5_LOCKSTEP 0x00000100
#define PROC_BOOT_CFG_FLAG_R5_TEINIT 0x00000200
#define PROC_BOOT_CFG_FLAG_R5_NMFI_EN 0x00000400
#define PROC_BOOT_CFG_FLAG_R5_TCM_RSTBASE 0x00000800
#define PROC_BOOT_CFG_FLAG_R5_BTCM_EN 0x00001000
#define PROC_BOOT_CFG_FLAG_R5_ATCM_EN 0x00002000
#define PROC_BOOT_CFG_FLAG_GEN_IGN_BOOTVECTOR 0x10000000
/* R5 TI-SCI Processor Control Flags */
#define PROC_BOOT_CTRL_FLAG_R5_CORE_HALT 0x00000001
/* R5 TI-SCI Processor Status Flags */
#define PROC_BOOT_STATUS_FLAG_R5_WFE 0x00000001
#define PROC_BOOT_STATUS_FLAG_R5_WFI 0x00000002
#define PROC_BOOT_STATUS_FLAG_R5_CLK_GATED 0x00000004
#define PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED 0x00000100
#define NR_CORES 2
enum cluster_mode {
CLUSTER_MODE_SPLIT = 0,
CLUSTER_MODE_LOCKSTEP,
};
/**
* struct k3_r5_mem - internal memory structure
* @cpu_addr: MPU virtual address of the memory region
* @bus_addr: Bus address used to access the memory region
* @dev_addr: Device address from remoteproc view
* @size: Size of the memory region
*/
struct k3_r5f_mem {
void __iomem *cpu_addr;
phys_addr_t bus_addr;
u32 dev_addr;
size_t size;
};
/**
* struct k3_r5f_core - K3 R5 core structure
* @dev: cached device pointer
* @cluster: pointer to the parent cluster.
* @reset: reset control handle
* @tsp: TI-SCI processor control handle
* @mem: Array of available internal memories
* @num_mem: Number of available memories
* @atcm_enable: flag to control ATCM enablement
* @btcm_enable: flag to control BTCM enablement
* @loczrama: flag to dictate which TCM is at device address 0x0
* @in_use: flag to tell if the core is already in use.
*/
struct k3_r5f_core {
struct udevice *dev;
struct k3_r5f_cluster *cluster;
struct reset_ctl reset;
struct ti_sci_proc tsp;
struct k3_r5f_mem *mem;
int num_mems;
u32 atcm_enable;
u32 btcm_enable;
u32 loczrama;
bool in_use;
};
/**
* struct k3_r5f_cluster - K3 R5F Cluster structure
* @mode: Mode to configure the Cluster - Split or LockStep
* @cores: Array of pointers to R5 cores within the cluster
*/
struct k3_r5f_cluster {
enum cluster_mode mode;
struct k3_r5f_core *cores[NR_CORES];
};
static bool is_primary_core(struct k3_r5f_core *core)
{
return core == core->cluster->cores[0];
}
static int k3_r5f_proc_request(struct k3_r5f_core *core)
{
struct k3_r5f_cluster *cluster = core->cluster;
int i, ret;
if (cluster->mode == CLUSTER_MODE_LOCKSTEP) {
for (i = 0; i < NR_CORES; i++) {
ret = ti_sci_proc_request(&cluster->cores[i]->tsp);
if (ret)
goto proc_release;
}
} else {
ret = ti_sci_proc_request(&core->tsp);
}
return 0;
proc_release:
while (i >= 0) {
ti_sci_proc_release(&cluster->cores[i]->tsp);
i--;
}
return ret;
}
static void k3_r5f_proc_release(struct k3_r5f_core *core)
{
struct k3_r5f_cluster *cluster = core->cluster;
int i;
if (cluster->mode == CLUSTER_MODE_LOCKSTEP)
for (i = 0; i < NR_CORES; i++)
ti_sci_proc_release(&cluster->cores[i]->tsp);
else
ti_sci_proc_release(&core->tsp);
}
static int k3_r5f_lockstep_release(struct k3_r5f_cluster *cluster)
{
int ret, c;
dev_dbg(dev, "%s\n", __func__);
for (c = NR_CORES - 1; c >= 0; c--) {
ret = ti_sci_proc_power_domain_on(&cluster->cores[c]->tsp);
if (ret)
goto unroll_module_reset;
}
/* deassert local reset on all applicable cores */
for (c = NR_CORES - 1; c >= 0; c--) {
ret = reset_deassert(&cluster->cores[c]->reset);
if (ret)
goto unroll_local_reset;
}
return 0;
unroll_local_reset:
while (c < NR_CORES) {
reset_assert(&cluster->cores[c]->reset);
c++;
}
c = 0;
unroll_module_reset:
while (c < NR_CORES) {
ti_sci_proc_power_domain_off(&cluster->cores[c]->tsp);
c++;
}
return ret;
}
static int k3_r5f_split_release(struct k3_r5f_core *core)
{
int ret;
dev_dbg(dev, "%s\n", __func__);
ret = ti_sci_proc_power_domain_on(&core->tsp);
if (ret) {
dev_err(core->dev, "module-reset deassert failed, ret = %d\n",
ret);
return ret;
}
ret = reset_deassert(&core->reset);
if (ret) {
dev_err(core->dev, "local-reset deassert failed, ret = %d\n",
ret);
if (ti_sci_proc_power_domain_off(&core->tsp))
dev_warn(core->dev, "module-reset assert back failed\n");
}
return ret;
}
static int k3_r5f_prepare(struct udevice *dev)
{
struct k3_r5f_core *core = dev_get_priv(dev);
struct k3_r5f_cluster *cluster = core->cluster;
int ret = 0;
dev_dbg(dev, "%s\n", __func__);
if (cluster->mode == CLUSTER_MODE_LOCKSTEP)
ret = k3_r5f_lockstep_release(cluster);
else
ret = k3_r5f_split_release(core);
if (ret)
dev_err(dev, "Unable to enable cores for TCM loading %d\n",
ret);
return ret;
}
static int k3_r5f_core_sanity_check(struct k3_r5f_core *core)
{
struct k3_r5f_cluster *cluster = core->cluster;
if (core->in_use) {
dev_err(dev, "Invalid op: Trying to load/start on already running core %d\n",
core->tsp.proc_id);
return -EINVAL;
}
if (cluster->mode == CLUSTER_MODE_LOCKSTEP && !cluster->cores[1]) {
printf("Secondary core is not probed in this cluster\n");
return -EAGAIN;
}
if (cluster->mode == CLUSTER_MODE_LOCKSTEP && !is_primary_core(core)) {
dev_err(dev, "Invalid op: Trying to start secondary core %d in lockstep mode\n",
core->tsp.proc_id);
return -EINVAL;
}
if (cluster->mode == CLUSTER_MODE_SPLIT && !is_primary_core(core)) {
if (!core->cluster->cores[0]->in_use) {
dev_err(dev, "Invalid seq: Enable primary core before loading secondary core\n");
return -EINVAL;
}
}
return 0;
}
/**
* k3_r5f_load() - Load up the Remote processor image
* @dev: rproc device pointer
* @addr: Address at which image is available
* @size: size of the image
*
* Return: 0 if all goes good, else appropriate error message.
*/
static int k3_r5f_load(struct udevice *dev, ulong addr, ulong size)
{
struct k3_r5f_core *core = dev_get_priv(dev);
u32 boot_vector;
int ret;
dev_dbg(dev, "%s addr = 0x%lx, size = 0x%lx\n", __func__, addr, size);
ret = k3_r5f_core_sanity_check(core);
if (ret)
return ret;
ret = k3_r5f_proc_request(core);
if (ret)
return ret;
ret = k3_r5f_prepare(dev);
if (ret) {
dev_err(dev, "R5f prepare failed for core %d\n",
core->tsp.proc_id);
goto proc_release;
}
/* Zero out TCMs so that ECC can be effective on all TCM addresses */
if (core->atcm_enable)
memset(core->mem[0].cpu_addr, 0x00, core->mem[0].size);
if (core->btcm_enable)
memset(core->mem[1].cpu_addr, 0x00, core->mem[1].size);
ret = rproc_elf_load_image(dev, addr, size);
if (ret < 0) {
dev_err(dev, "Loading elf failedi %d\n", ret);
goto proc_release;
}
boot_vector = rproc_elf_get_boot_addr(dev, addr);
dev_dbg(dev, "%s: Boot vector = 0x%x\n", __func__, boot_vector);
ret = ti_sci_proc_set_config(&core->tsp, boot_vector, 0, 0);
proc_release:
k3_r5f_proc_release(core);
return ret;
}
static int k3_r5f_core_halt(struct k3_r5f_core *core)
{
int ret;
ret = ti_sci_proc_set_control(&core->tsp,
PROC_BOOT_CTRL_FLAG_R5_CORE_HALT, 0);
if (ret)
dev_err(core->dev, "Core %d failed to stop\n",
core->tsp.proc_id);
return ret;
}
static int k3_r5f_core_run(struct k3_r5f_core *core)
{
int ret;
ret = ti_sci_proc_set_control(&core->tsp,
0, PROC_BOOT_CTRL_FLAG_R5_CORE_HALT);
if (ret) {
dev_err(core->dev, "Core %d failed to start\n",
core->tsp.proc_id);
return ret;
}
return 0;
}
/**
* k3_r5f_start() - Start the remote processor
* @dev: rproc device pointer
*
* Return: 0 if all went ok, else return appropriate error
*/
static int k3_r5f_start(struct udevice *dev)
{
struct k3_r5f_core *core = dev_get_priv(dev);
struct k3_r5f_cluster *cluster = core->cluster;
int ret, c;
dev_dbg(dev, "%s\n", __func__);
ret = k3_r5f_core_sanity_check(core);
if (ret)
return ret;
ret = k3_r5f_proc_request(core);
if (ret)
return ret;
if (cluster->mode == CLUSTER_MODE_LOCKSTEP) {
if (is_primary_core(core)) {
for (c = NR_CORES - 1; c >= 0; c--) {
ret = k3_r5f_core_run(cluster->cores[c]);
if (ret)
goto unroll_core_run;
}
} else {
dev_err(dev, "Invalid op: Trying to start secondary core %d in lockstep mode\n",
core->tsp.proc_id);
ret = -EINVAL;
goto proc_release;
}
} else {
ret = k3_r5f_core_run(core);
if (ret)
goto proc_release;
}
core->in_use = true;
k3_r5f_proc_release(core);
return 0;
unroll_core_run:
while (c < NR_CORES) {
k3_r5f_core_halt(cluster->cores[c]);
c++;
}
proc_release:
k3_r5f_proc_release(core);
return ret;
}
static int k3_r5f_split_reset(struct k3_r5f_core *core)
{
int ret;
dev_dbg(dev, "%s\n", __func__);
if (reset_assert(&core->reset))
ret = -EINVAL;
if (ti_sci_proc_power_domain_off(&core->tsp))
ret = -EINVAL;
return ret;
}
static int k3_r5f_lockstep_reset(struct k3_r5f_cluster *cluster)
{
int ret = 0, c;
dev_dbg(dev, "%s\n", __func__);
for (c = 0; c < NR_CORES; c++)
if (reset_assert(&cluster->cores[c]->reset))
ret = -EINVAL;
/* disable PSC modules on all applicable cores */
for (c = 0; c < NR_CORES; c++)
if (ti_sci_proc_power_domain_off(&cluster->cores[c]->tsp))
ret = -EINVAL;
return ret;
}
static int k3_r5f_unprepare(struct udevice *dev)
{
struct k3_r5f_core *core = dev_get_priv(dev);
struct k3_r5f_cluster *cluster = core->cluster;
int ret;
dev_dbg(dev, "%s\n", __func__);
if (cluster->mode == CLUSTER_MODE_LOCKSTEP) {
if (is_primary_core(core))
ret = k3_r5f_lockstep_reset(cluster);
} else {
ret = k3_r5f_split_reset(core);
}
if (ret)
dev_warn(dev, "Unable to enable cores for TCM loading %d\n",
ret);
return 0;
}
static int k3_r5f_stop(struct udevice *dev)
{
struct k3_r5f_core *core = dev_get_priv(dev);
struct k3_r5f_cluster *cluster = core->cluster;
int c, ret;
dev_dbg(dev, "%s\n", __func__);
ret = k3_r5f_proc_request(core);
if (ret)
return ret;
core->in_use = false;
if (cluster->mode == CLUSTER_MODE_LOCKSTEP) {
if (is_primary_core(core)) {
for (c = 0; c < NR_CORES; c++)
k3_r5f_core_halt(cluster->cores[c]);
} else {
dev_err(dev, "Invalid op: Trying to stop secondary core in lockstep mode\n");
ret = -EINVAL;
goto proc_release;
}
} else {
k3_r5f_core_halt(core);
}
ret = k3_r5f_unprepare(dev);
proc_release:
k3_r5f_proc_release(core);
return ret;
}
static void *k3_r5f_da_to_va(struct udevice *dev, ulong da, ulong size)
{
struct k3_r5f_core *core = dev_get_priv(dev);
void __iomem *va = NULL;
phys_addr_t bus_addr;
u32 dev_addr, offset;
ulong mem_size;
int i;
dev_dbg(dev, "%s\n", __func__);
if (size <= 0)
return NULL;
for (i = 0; i < core->num_mems; i++) {
bus_addr = core->mem[i].bus_addr;
dev_addr = core->mem[i].dev_addr;
mem_size = core->mem[i].size;
if (da >= bus_addr && (da + size) <= (bus_addr + mem_size)) {
offset = da - bus_addr;
va = core->mem[i].cpu_addr + offset;
return (__force void *)va;
}
if (da >= dev_addr && (da + size) <= (dev_addr + mem_size)) {
offset = da - dev_addr;
va = core->mem[i].cpu_addr + offset;
return (__force void *)va;
}
}
/* Assume it is DDR region and return da */
return map_physmem(da, size, MAP_NOCACHE);
}
static int k3_r5f_init(struct udevice *dev)
{
return 0;
}
static int k3_r5f_reset(struct udevice *dev)
{
return 0;
}
static const struct dm_rproc_ops k3_r5f_rproc_ops = {
.init = k3_r5f_init,
.reset = k3_r5f_reset,
.start = k3_r5f_start,
.stop = k3_r5f_stop,
.load = k3_r5f_load,
.device_to_virt = k3_r5f_da_to_va,
};
static int k3_r5f_rproc_configure(struct k3_r5f_core *core)
{
struct k3_r5f_cluster *cluster = core->cluster;
u32 set_cfg = 0, clr_cfg = 0, cfg, ctrl, sts;
u64 boot_vec = 0;
int ret;
dev_dbg(dev, "%s\n", __func__);
ret = ti_sci_proc_request(&core->tsp);
if (ret < 0)
return ret;
/* Do not touch boot vector now. Load will take care of it. */
clr_cfg |= PROC_BOOT_CFG_FLAG_GEN_IGN_BOOTVECTOR;
ret = ti_sci_proc_get_status(&core->tsp, &boot_vec, &cfg, &ctrl, &sts);
if (ret)
goto out;
/* Sanity check for Lockstep mode */
if (cluster->mode && is_primary_core(core) &&
!(sts & PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED)) {
dev_err(core->dev, "LockStep mode not permitted on this device\n");
ret = -EINVAL;
goto out;
}
/* Primary core only configuration */
if (is_primary_core(core)) {
/* always enable ARM mode */
clr_cfg |= PROC_BOOT_CFG_FLAG_R5_TEINIT;
if (cluster->mode == CLUSTER_MODE_LOCKSTEP)
set_cfg |= PROC_BOOT_CFG_FLAG_R5_LOCKSTEP;
else
clr_cfg |= PROC_BOOT_CFG_FLAG_R5_LOCKSTEP;
}
if (core->atcm_enable)
set_cfg |= PROC_BOOT_CFG_FLAG_R5_ATCM_EN;
else
clr_cfg |= PROC_BOOT_CFG_FLAG_R5_ATCM_EN;
if (core->btcm_enable)
set_cfg |= PROC_BOOT_CFG_FLAG_R5_BTCM_EN;
else
clr_cfg |= PROC_BOOT_CFG_FLAG_R5_BTCM_EN;
if (core->loczrama)
set_cfg |= PROC_BOOT_CFG_FLAG_R5_TCM_RSTBASE;
else
clr_cfg |= PROC_BOOT_CFG_FLAG_R5_TCM_RSTBASE;
ret = k3_r5f_core_halt(core);
if (ret)
goto out;
ret = ti_sci_proc_set_config(&core->tsp, boot_vec, set_cfg, clr_cfg);
out:
ti_sci_proc_release(&core->tsp);
return ret;
}
static int ti_sci_proc_of_to_priv(struct udevice *dev, struct ti_sci_proc *tsp)
{
u32 ids[2];
int ret;
dev_dbg(dev, "%s\n", __func__);
tsp->sci = ti_sci_get_by_phandle(dev, "ti,sci");
if (IS_ERR(tsp->sci)) {
dev_err(dev, "ti_sci get failed: %ld\n", PTR_ERR(tsp->sci));
return PTR_ERR(tsp->sci);
}
ret = dev_read_u32_array(dev, "ti,sci-proc-ids", ids, 2);
if (ret) {
dev_err(dev, "Proc IDs not populated %d\n", ret);
return ret;
}
tsp->ops = &tsp->sci->ops.proc_ops;
tsp->proc_id = ids[0];
tsp->host_id = ids[1];
tsp->dev_id = dev_read_u32_default(dev, "ti,sci-dev-id",
TI_SCI_RESOURCE_NULL);
if (tsp->dev_id == TI_SCI_RESOURCE_NULL) {
dev_err(dev, "Device ID not populated %d\n", ret);
return -ENODEV;
}
return 0;
}
static int k3_r5f_of_to_priv(struct k3_r5f_core *core)
{
int ret;
dev_dbg(dev, "%s\n", __func__);
core->atcm_enable = dev_read_u32_default(core->dev, "atcm-enable", 0);
core->btcm_enable = dev_read_u32_default(core->dev, "btcm-enable", 1);
core->loczrama = dev_read_u32_default(core->dev, "loczrama", 1);
ret = ti_sci_proc_of_to_priv(core->dev, &core->tsp);
if (ret)
return ret;
ret = reset_get_by_index(core->dev, 0, &core->reset);
if (ret) {
dev_err(core->dev, "Reset lines not available: %d\n", ret);
return ret;
}
return 0;
}
static int k3_r5f_core_of_get_memories(struct k3_r5f_core *core)
{
static const char * const mem_names[] = {"atcm", "btcm"};
struct udevice *dev = core->dev;
int i;
dev_dbg(dev, "%s\n", __func__);
core->num_mems = ARRAY_SIZE(mem_names);
core->mem = calloc(core->num_mems, sizeof(*core->mem));
if (!core->mem)
return -ENOMEM;
for (i = 0; i < core->num_mems; i++) {
core->mem[i].bus_addr = dev_read_addr_size_name(dev,
mem_names[i],
(fdt_addr_t *)&core->mem[i].size);
if (core->mem[i].bus_addr == FDT_ADDR_T_NONE) {
dev_err(dev, "%s bus address not found\n",
mem_names[i]);
return -EINVAL;
}
core->mem[i].cpu_addr = map_physmem(core->mem[i].bus_addr,
core->mem[i].size,
MAP_NOCACHE);
if (!strcmp(mem_names[i], "atcm")) {
core->mem[i].dev_addr = core->loczrama ?
0 : K3_R5_TCM_DEV_ADDR;
} else {
core->mem[i].dev_addr = core->loczrama ?
K3_R5_TCM_DEV_ADDR : 0;
}
dev_dbg(dev, "memory %8s: bus addr %pa size 0x%zx va %p da 0x%x\n",
mem_names[i], &core->mem[i].bus_addr,
core->mem[i].size, core->mem[i].cpu_addr,
core->mem[i].dev_addr);
}
return 0;
}
/**
* k3_r5f_probe() - Basic probe
* @dev: corresponding k3 remote processor device
*
* Return: 0 if all goes good, else appropriate error message.
*/
static int k3_r5f_probe(struct udevice *dev)
{
struct k3_r5f_cluster *cluster = dev_get_priv(dev->parent);
struct k3_r5f_core *core = dev_get_priv(dev);
bool r_state;
int ret;
dev_dbg(dev, "%s\n", __func__);
core->dev = dev;
ret = k3_r5f_of_to_priv(core);
if (ret)
return ret;
core->cluster = cluster;
/* Assume Primary core gets probed first */
if (!cluster->cores[0])
cluster->cores[0] = core;
else
cluster->cores[1] = core;
ret = k3_r5f_core_of_get_memories(core);
if (ret) {
dev_err(dev, "Rproc getting internal memories failed\n");
return ret;
}
ret = core->tsp.sci->ops.dev_ops.is_on(core->tsp.sci, core->tsp.dev_id,
&r_state, &core->in_use);
if (ret)
return ret;
if (core->in_use) {
dev_info(dev, "Core %d is already in use. No rproc commands work\n",
core->tsp.proc_id);
return 0;
}
/* Make sure Local reset is asserted. Redundant? */
reset_assert(&core->reset);
ret = k3_r5f_rproc_configure(core);
if (ret) {
dev_err(dev, "rproc configure failed %d\n", ret);
return ret;
}
dev_dbg(dev, "Remoteproc successfully probed\n");
return 0;
}
static int k3_r5f_remove(struct udevice *dev)
{
struct k3_r5f_core *core = dev_get_priv(dev);
free(core->mem);
ti_sci_proc_release(&core->tsp);
return 0;
}
static const struct udevice_id k3_r5f_rproc_ids[] = {
{ .compatible = "ti,am654-r5f"},
{ .compatible = "ti,j721e-r5f"},
{}
};
U_BOOT_DRIVER(k3_r5f_rproc) = {
.name = "k3_r5f_rproc",
.of_match = k3_r5f_rproc_ids,
.id = UCLASS_REMOTEPROC,
.ops = &k3_r5f_rproc_ops,
.probe = k3_r5f_probe,
.remove = k3_r5f_remove,
.priv_auto_alloc_size = sizeof(struct k3_r5f_core),
};
static int k3_r5f_cluster_probe(struct udevice *dev)
{
struct k3_r5f_cluster *cluster = dev_get_priv(dev);
dev_dbg(dev, "%s\n", __func__);
cluster->mode = dev_read_u32_default(dev, "lockstep-mode",
CLUSTER_MODE_LOCKSTEP);
if (device_get_child_count(dev) != 2) {
dev_err(dev, "Invalid number of R5 cores");
return -EINVAL;
}
dev_dbg(dev, "%s: Cluster successfully probed in %s mode\n",
__func__, cluster->mode ? "lockstep" : "split");
return 0;
}
static const struct udevice_id k3_r5fss_ids[] = {
{ .compatible = "ti,am654-r5fss"},
{ .compatible = "ti,j721e-r5fss"},
{}
};
U_BOOT_DRIVER(k3_r5fss) = {
.name = "k3_r5fss",
.of_match = k3_r5fss_ids,
.id = UCLASS_MISC,
.probe = k3_r5f_cluster_probe,
.priv_auto_alloc_size = sizeof(struct k3_r5f_cluster),
};
@@ -0,0 +1,180 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2015-2016
* Texas Instruments Incorporated - http://www.ti.com/
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <remoteproc.h>
#include <mach/psc_defs.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* struct ti_powerproc_privdata - power processor private data
* @loadaddr: base address for loading the power processor
* @psc_module: psc module address.
*/
struct ti_powerproc_privdata {
phys_addr_t loadaddr;
u32 psc_module;
};
/**
* ti_of_to_priv() - generate private data from device tree
* @dev: corresponding ti remote processor device
* @priv: pointer to driver specific private data
*
* Return: 0 if all went ok, else corresponding -ve error
*/
static int ti_of_to_priv(struct udevice *dev,
struct ti_powerproc_privdata *priv)
{
int node = dev_of_offset(dev);
const void *blob = gd->fdt_blob;
int tmp;
if (!blob) {
debug("'%s' no dt?\n", dev->name);
return -EINVAL;
}
priv->loadaddr = fdtdec_get_addr(blob, node, "reg");
if (priv->loadaddr == FDT_ADDR_T_NONE) {
debug("'%s': no 'reg' property\n", dev->name);
return -EINVAL;
}
tmp = fdtdec_get_int(blob, node, "ti,lpsc_module", -EINVAL);
if (tmp < 0) {
debug("'%s': no 'ti,lpsc_module' property\n", dev->name);
return tmp;
}
priv->psc_module = tmp;
return 0;
}
/**
* ti_powerproc_probe() - Basic probe
* @dev: corresponding ti remote processor device
*
* Return: 0 if all went ok, else corresponding -ve error
*/
static int ti_powerproc_probe(struct udevice *dev)
{
struct dm_rproc_uclass_pdata *uc_pdata;
struct ti_powerproc_privdata *priv;
int ret;
uc_pdata = dev_get_uclass_platdata(dev);
priv = dev_get_priv(dev);
ret = ti_of_to_priv(dev, priv);
debug("%s probed with slave_addr=0x%08lX module=%d(%d)\n",
uc_pdata->name, priv->loadaddr, priv->psc_module, ret);
return ret;
}
/**
* ti_powerproc_load() - Loadup the TI remote processor
* @dev: corresponding ti remote processor device
* @addr: Address in memory where image binary is stored
* @size: Size in bytes of the image binary
*
* Return: 0 if all went ok, else corresponding -ve error
*/
static int ti_powerproc_load(struct udevice *dev, ulong addr, ulong size)
{
struct dm_rproc_uclass_pdata *uc_pdata;
struct ti_powerproc_privdata *priv;
int ret;
uc_pdata = dev_get_uclass_platdata(dev);
if (!uc_pdata) {
debug("%s: no uc pdata!\n", dev->name);
return -EINVAL;
}
priv = dev_get_priv(dev);
ret = psc_module_keep_in_reset_enabled(priv->psc_module, false);
if (ret) {
debug("%s Unable to disable module '%d'(ret=%d)\n",
uc_pdata->name, priv->psc_module, ret);
return ret;
}
debug("%s: Loading binary from 0x%08lX, size 0x%08lX to 0x%08lX\n",
uc_pdata->name, addr, size, priv->loadaddr);
memcpy((void *)priv->loadaddr, (void *)addr, size);
debug("%s: Complete!\n", uc_pdata->name);
return 0;
}
/**
* ti_powerproc_start() - (replace: short desc)
* @dev: corresponding ti remote processor device
*
* Return: 0 if all went ok, else corresponding -ve error
*/
static int ti_powerproc_start(struct udevice *dev)
{
struct dm_rproc_uclass_pdata *uc_pdata;
struct ti_powerproc_privdata *priv;
int ret;
uc_pdata = dev_get_uclass_platdata(dev);
if (!uc_pdata) {
debug("%s: no uc pdata!\n", dev->name);
return -EINVAL;
}
priv = dev_get_priv(dev);
ret = psc_disable_module(priv->psc_module);
if (ret) {
debug("%s Unable to disable module '%d'(ret=%d)\n",
uc_pdata->name, priv->psc_module, ret);
return ret;
}
ret = psc_module_release_from_reset(priv->psc_module);
if (ret) {
debug("%s Failed to wait for module '%d'(ret=%d)\n",
uc_pdata->name, priv->psc_module, ret);
return ret;
}
ret = psc_enable_module(priv->psc_module);
if (ret) {
debug("%s Unable to disable module '%d'(ret=%d)\n",
uc_pdata->name, priv->psc_module, ret);
return ret;
}
return 0;
}
static const struct dm_rproc_ops ti_powerproc_ops = {
.load = ti_powerproc_load,
.start = ti_powerproc_start,
};
static const struct udevice_id ti_powerproc_ids[] = {
{.compatible = "ti,power-processor"},
{}
};
U_BOOT_DRIVER(ti_powerproc) = {
.name = "ti_power_proc",
.of_match = ti_powerproc_ids,
.id = UCLASS_REMOTEPROC,
.ops = &ti_powerproc_ops,
.probe = ti_powerproc_probe,
.priv_auto_alloc_size = sizeof(struct ti_powerproc_privdata),
};
@@ -0,0 +1,148 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Texas Instruments TI-SCI Processor Controller Helper Functions
*
* Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
* Suman Anna <s-anna@ti.com>
*/
#ifndef REMOTEPROC_TI_SCI_PROC_H
#define REMOTEPROC_TI_SCI_PROC_H
#define TISCI_INVALID_HOST 0xff
/**
* struct ti_sci_proc - structure representing a processor control client
* @sci: cached TI-SCI protocol handle
* @ops: cached TI-SCI proc ops
* @proc_id: processor id for the consumer remoteproc device
* @host_id: host id to pass the control over for this consumer remoteproc
* device
* @dev_id: Device ID as identified by system controller.
*/
struct ti_sci_proc {
const struct ti_sci_handle *sci;
const struct ti_sci_proc_ops *ops;
u8 proc_id;
u8 host_id;
u16 dev_id;
};
static inline int ti_sci_proc_request(struct ti_sci_proc *tsp)
{
int ret;
debug("%s: proc_id = %d\n", __func__, tsp->proc_id);
ret = tsp->ops->proc_request(tsp->sci, tsp->proc_id);
if (ret)
pr_err("ti-sci processor request failed: %d\n", ret);
return ret;
}
static inline int ti_sci_proc_release(struct ti_sci_proc *tsp)
{
int ret;
debug("%s: proc_id = %d\n", __func__, tsp->proc_id);
if (tsp->host_id != TISCI_INVALID_HOST)
ret = tsp->ops->proc_handover(tsp->sci, tsp->proc_id,
tsp->host_id);
else
ret = tsp->ops->proc_release(tsp->sci, tsp->proc_id);
if (ret)
pr_err("ti-sci processor release failed: %d\n", ret);
return ret;
}
static inline int ti_sci_proc_handover(struct ti_sci_proc *tsp)
{
int ret;
debug("%s: proc_id = %d\n", __func__, tsp->proc_id);
ret = tsp->ops->proc_handover(tsp->sci, tsp->proc_id, tsp->host_id);
if (ret)
pr_err("ti-sci processor handover of %d to %d failed: %d\n",
tsp->proc_id, tsp->host_id, ret);
return ret;
}
static inline int ti_sci_proc_get_status(struct ti_sci_proc *tsp,
u64 *boot_vector, u32 *cfg_flags,
u32 *ctrl_flags, u32 *status_flags)
{
int ret;
ret = tsp->ops->get_proc_boot_status(tsp->sci, tsp->proc_id,
boot_vector, cfg_flags, ctrl_flags,
status_flags);
if (ret)
pr_err("ti-sci processor get_status failed: %d\n", ret);
debug("%s: proc_id = %d, boot_vector = 0x%llx, cfg_flags = 0x%x, ctrl_flags = 0x%x, sts = 0x%x\n",
__func__, tsp->proc_id, *boot_vector, *cfg_flags, *ctrl_flags,
*status_flags);
return ret;
}
static inline int ti_sci_proc_set_config(struct ti_sci_proc *tsp,
u64 boot_vector,
u32 cfg_set, u32 cfg_clr)
{
int ret;
debug("%s: proc_id = %d, boot_vector = 0x%llx, cfg_set = 0x%x, cfg_clr = 0x%x\n",
__func__, tsp->proc_id, boot_vector, cfg_set, cfg_clr);
ret = tsp->ops->set_proc_boot_cfg(tsp->sci, tsp->proc_id, boot_vector,
cfg_set, cfg_clr);
if (ret)
pr_err("ti-sci processor set_config failed: %d\n", ret);
return ret;
}
static inline int ti_sci_proc_set_control(struct ti_sci_proc *tsp,
u32 ctrl_set, u32 ctrl_clr)
{
int ret;
debug("%s: proc_id = %d, ctrl_set = 0x%x, ctrl_clr = 0x%x\n", __func__,
tsp->proc_id, ctrl_set, ctrl_clr);
ret = tsp->ops->set_proc_boot_ctrl(tsp->sci, tsp->proc_id, ctrl_set,
ctrl_clr);
if (ret)
pr_err("ti-sci processor set_control failed: %d\n", ret);
return ret;
}
static inline int ti_sci_proc_power_domain_on(struct ti_sci_proc *tsp)
{
int ret;
debug("%s: dev_id = %d\n", __func__, tsp->dev_id);
ret = tsp->sci->ops.dev_ops.get_device_exclusive(tsp->sci, tsp->dev_id);
if (ret)
pr_err("Power-domain on failed for dev = %d\n", tsp->dev_id);
return ret;
}
static inline int ti_sci_proc_power_domain_off(struct ti_sci_proc *tsp)
{
int ret;
debug("%s: dev_id = %d\n", __func__, tsp->dev_id);
ret = tsp->sci->ops.dev_ops.put_device(tsp->sci, tsp->dev_id);
if (ret)
pr_err("Power-domain off failed for dev = %d\n", tsp->dev_id);
return ret;
}
#endif /* REMOTEPROC_TI_SCI_PROC_H */