162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * TI K3 R5F (MCU) Remote Processor driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2017-2022 Texas Instruments Incorporated - https://www.ti.com/ 662306a36Sopenharmony_ci * Suman Anna <s-anna@ti.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1062306a36Sopenharmony_ci#include <linux/err.h> 1162306a36Sopenharmony_ci#include <linux/interrupt.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/mailbox_client.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/of.h> 1662306a36Sopenharmony_ci#include <linux/of_address.h> 1762306a36Sopenharmony_ci#include <linux/of_reserved_mem.h> 1862306a36Sopenharmony_ci#include <linux/of_platform.h> 1962306a36Sopenharmony_ci#include <linux/omap-mailbox.h> 2062306a36Sopenharmony_ci#include <linux/platform_device.h> 2162306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2262306a36Sopenharmony_ci#include <linux/remoteproc.h> 2362306a36Sopenharmony_ci#include <linux/reset.h> 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "omap_remoteproc.h" 2762306a36Sopenharmony_ci#include "remoteproc_internal.h" 2862306a36Sopenharmony_ci#include "ti_sci_proc.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* This address can either be for ATCM or BTCM with the other at address 0x0 */ 3162306a36Sopenharmony_ci#define K3_R5_TCM_DEV_ADDR 0x41010000 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* R5 TI-SCI Processor Configuration Flags */ 3462306a36Sopenharmony_ci#define PROC_BOOT_CFG_FLAG_R5_DBG_EN 0x00000001 3562306a36Sopenharmony_ci#define PROC_BOOT_CFG_FLAG_R5_DBG_NIDEN 0x00000002 3662306a36Sopenharmony_ci#define PROC_BOOT_CFG_FLAG_R5_LOCKSTEP 0x00000100 3762306a36Sopenharmony_ci#define PROC_BOOT_CFG_FLAG_R5_TEINIT 0x00000200 3862306a36Sopenharmony_ci#define PROC_BOOT_CFG_FLAG_R5_NMFI_EN 0x00000400 3962306a36Sopenharmony_ci#define PROC_BOOT_CFG_FLAG_R5_TCM_RSTBASE 0x00000800 4062306a36Sopenharmony_ci#define PROC_BOOT_CFG_FLAG_R5_BTCM_EN 0x00001000 4162306a36Sopenharmony_ci#define PROC_BOOT_CFG_FLAG_R5_ATCM_EN 0x00002000 4262306a36Sopenharmony_ci/* Available from J7200 SoCs onwards */ 4362306a36Sopenharmony_ci#define PROC_BOOT_CFG_FLAG_R5_MEM_INIT_DIS 0x00004000 4462306a36Sopenharmony_ci/* Applicable to only AM64x SoCs */ 4562306a36Sopenharmony_ci#define PROC_BOOT_CFG_FLAG_R5_SINGLE_CORE 0x00008000 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* R5 TI-SCI Processor Control Flags */ 4862306a36Sopenharmony_ci#define PROC_BOOT_CTRL_FLAG_R5_CORE_HALT 0x00000001 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* R5 TI-SCI Processor Status Flags */ 5162306a36Sopenharmony_ci#define PROC_BOOT_STATUS_FLAG_R5_WFE 0x00000001 5262306a36Sopenharmony_ci#define PROC_BOOT_STATUS_FLAG_R5_WFI 0x00000002 5362306a36Sopenharmony_ci#define PROC_BOOT_STATUS_FLAG_R5_CLK_GATED 0x00000004 5462306a36Sopenharmony_ci#define PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED 0x00000100 5562306a36Sopenharmony_ci/* Applicable to only AM64x SoCs */ 5662306a36Sopenharmony_ci#define PROC_BOOT_STATUS_FLAG_R5_SINGLECORE_ONLY 0x00000200 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/** 5962306a36Sopenharmony_ci * struct k3_r5_mem - internal memory structure 6062306a36Sopenharmony_ci * @cpu_addr: MPU virtual address of the memory region 6162306a36Sopenharmony_ci * @bus_addr: Bus address used to access the memory region 6262306a36Sopenharmony_ci * @dev_addr: Device address from remoteproc view 6362306a36Sopenharmony_ci * @size: Size of the memory region 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_cistruct k3_r5_mem { 6662306a36Sopenharmony_ci void __iomem *cpu_addr; 6762306a36Sopenharmony_ci phys_addr_t bus_addr; 6862306a36Sopenharmony_ci u32 dev_addr; 6962306a36Sopenharmony_ci size_t size; 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* 7362306a36Sopenharmony_ci * All cluster mode values are not applicable on all SoCs. The following 7462306a36Sopenharmony_ci * are the modes supported on various SoCs: 7562306a36Sopenharmony_ci * Split mode : AM65x, J721E, J7200 and AM64x SoCs 7662306a36Sopenharmony_ci * LockStep mode : AM65x, J721E and J7200 SoCs 7762306a36Sopenharmony_ci * Single-CPU mode : AM64x SoCs only 7862306a36Sopenharmony_ci * Single-Core mode : AM62x, AM62A SoCs 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_cienum cluster_mode { 8162306a36Sopenharmony_ci CLUSTER_MODE_SPLIT = 0, 8262306a36Sopenharmony_ci CLUSTER_MODE_LOCKSTEP, 8362306a36Sopenharmony_ci CLUSTER_MODE_SINGLECPU, 8462306a36Sopenharmony_ci CLUSTER_MODE_SINGLECORE 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/** 8862306a36Sopenharmony_ci * struct k3_r5_soc_data - match data to handle SoC variations 8962306a36Sopenharmony_ci * @tcm_is_double: flag to denote the larger unified TCMs in certain modes 9062306a36Sopenharmony_ci * @tcm_ecc_autoinit: flag to denote the auto-initialization of TCMs for ECC 9162306a36Sopenharmony_ci * @single_cpu_mode: flag to denote if SoC/IP supports Single-CPU mode 9262306a36Sopenharmony_ci * @is_single_core: flag to denote if SoC/IP has only single core R5 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_cistruct k3_r5_soc_data { 9562306a36Sopenharmony_ci bool tcm_is_double; 9662306a36Sopenharmony_ci bool tcm_ecc_autoinit; 9762306a36Sopenharmony_ci bool single_cpu_mode; 9862306a36Sopenharmony_ci bool is_single_core; 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/** 10262306a36Sopenharmony_ci * struct k3_r5_cluster - K3 R5F Cluster structure 10362306a36Sopenharmony_ci * @dev: cached device pointer 10462306a36Sopenharmony_ci * @mode: Mode to configure the Cluster - Split or LockStep 10562306a36Sopenharmony_ci * @cores: list of R5 cores within the cluster 10662306a36Sopenharmony_ci * @soc_data: SoC-specific feature data for a R5FSS 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_cistruct k3_r5_cluster { 10962306a36Sopenharmony_ci struct device *dev; 11062306a36Sopenharmony_ci enum cluster_mode mode; 11162306a36Sopenharmony_ci struct list_head cores; 11262306a36Sopenharmony_ci const struct k3_r5_soc_data *soc_data; 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/** 11662306a36Sopenharmony_ci * struct k3_r5_core - K3 R5 core structure 11762306a36Sopenharmony_ci * @elem: linked list item 11862306a36Sopenharmony_ci * @dev: cached device pointer 11962306a36Sopenharmony_ci * @rproc: rproc handle representing this core 12062306a36Sopenharmony_ci * @mem: internal memory regions data 12162306a36Sopenharmony_ci * @sram: on-chip SRAM memory regions data 12262306a36Sopenharmony_ci * @num_mems: number of internal memory regions 12362306a36Sopenharmony_ci * @num_sram: number of on-chip SRAM memory regions 12462306a36Sopenharmony_ci * @reset: reset control handle 12562306a36Sopenharmony_ci * @tsp: TI-SCI processor control handle 12662306a36Sopenharmony_ci * @ti_sci: TI-SCI handle 12762306a36Sopenharmony_ci * @ti_sci_id: TI-SCI device identifier 12862306a36Sopenharmony_ci * @atcm_enable: flag to control ATCM enablement 12962306a36Sopenharmony_ci * @btcm_enable: flag to control BTCM enablement 13062306a36Sopenharmony_ci * @loczrama: flag to dictate which TCM is at device address 0x0 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_cistruct k3_r5_core { 13362306a36Sopenharmony_ci struct list_head elem; 13462306a36Sopenharmony_ci struct device *dev; 13562306a36Sopenharmony_ci struct rproc *rproc; 13662306a36Sopenharmony_ci struct k3_r5_mem *mem; 13762306a36Sopenharmony_ci struct k3_r5_mem *sram; 13862306a36Sopenharmony_ci int num_mems; 13962306a36Sopenharmony_ci int num_sram; 14062306a36Sopenharmony_ci struct reset_control *reset; 14162306a36Sopenharmony_ci struct ti_sci_proc *tsp; 14262306a36Sopenharmony_ci const struct ti_sci_handle *ti_sci; 14362306a36Sopenharmony_ci u32 ti_sci_id; 14462306a36Sopenharmony_ci u32 atcm_enable; 14562306a36Sopenharmony_ci u32 btcm_enable; 14662306a36Sopenharmony_ci u32 loczrama; 14762306a36Sopenharmony_ci}; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/** 15062306a36Sopenharmony_ci * struct k3_r5_rproc - K3 remote processor state 15162306a36Sopenharmony_ci * @dev: cached device pointer 15262306a36Sopenharmony_ci * @cluster: cached pointer to parent cluster structure 15362306a36Sopenharmony_ci * @mbox: mailbox channel handle 15462306a36Sopenharmony_ci * @client: mailbox client to request the mailbox channel 15562306a36Sopenharmony_ci * @rproc: rproc handle 15662306a36Sopenharmony_ci * @core: cached pointer to r5 core structure being used 15762306a36Sopenharmony_ci * @rmem: reserved memory regions data 15862306a36Sopenharmony_ci * @num_rmems: number of reserved memory regions 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_cistruct k3_r5_rproc { 16162306a36Sopenharmony_ci struct device *dev; 16262306a36Sopenharmony_ci struct k3_r5_cluster *cluster; 16362306a36Sopenharmony_ci struct mbox_chan *mbox; 16462306a36Sopenharmony_ci struct mbox_client client; 16562306a36Sopenharmony_ci struct rproc *rproc; 16662306a36Sopenharmony_ci struct k3_r5_core *core; 16762306a36Sopenharmony_ci struct k3_r5_mem *rmem; 16862306a36Sopenharmony_ci int num_rmems; 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/** 17262306a36Sopenharmony_ci * k3_r5_rproc_mbox_callback() - inbound mailbox message handler 17362306a36Sopenharmony_ci * @client: mailbox client pointer used for requesting the mailbox channel 17462306a36Sopenharmony_ci * @data: mailbox payload 17562306a36Sopenharmony_ci * 17662306a36Sopenharmony_ci * This handler is invoked by the OMAP mailbox driver whenever a mailbox 17762306a36Sopenharmony_ci * message is received. Usually, the mailbox payload simply contains 17862306a36Sopenharmony_ci * the index of the virtqueue that is kicked by the remote processor, 17962306a36Sopenharmony_ci * and we let remoteproc core handle it. 18062306a36Sopenharmony_ci * 18162306a36Sopenharmony_ci * In addition to virtqueue indices, we also have some out-of-band values 18262306a36Sopenharmony_ci * that indicate different events. Those values are deliberately very 18362306a36Sopenharmony_ci * large so they don't coincide with virtqueue indices. 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_cistatic void k3_r5_rproc_mbox_callback(struct mbox_client *client, void *data) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct k3_r5_rproc *kproc = container_of(client, struct k3_r5_rproc, 18862306a36Sopenharmony_ci client); 18962306a36Sopenharmony_ci struct device *dev = kproc->rproc->dev.parent; 19062306a36Sopenharmony_ci const char *name = kproc->rproc->name; 19162306a36Sopenharmony_ci u32 msg = omap_mbox_message(data); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci dev_dbg(dev, "mbox msg: 0x%x\n", msg); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci switch (msg) { 19662306a36Sopenharmony_ci case RP_MBOX_CRASH: 19762306a36Sopenharmony_ci /* 19862306a36Sopenharmony_ci * remoteproc detected an exception, but error recovery is not 19962306a36Sopenharmony_ci * supported. So, just log this for now 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ci dev_err(dev, "K3 R5F rproc %s crashed\n", name); 20262306a36Sopenharmony_ci break; 20362306a36Sopenharmony_ci case RP_MBOX_ECHO_REPLY: 20462306a36Sopenharmony_ci dev_info(dev, "received echo reply from %s\n", name); 20562306a36Sopenharmony_ci break; 20662306a36Sopenharmony_ci default: 20762306a36Sopenharmony_ci /* silently handle all other valid messages */ 20862306a36Sopenharmony_ci if (msg >= RP_MBOX_READY && msg < RP_MBOX_END_MSG) 20962306a36Sopenharmony_ci return; 21062306a36Sopenharmony_ci if (msg > kproc->rproc->max_notifyid) { 21162306a36Sopenharmony_ci dev_dbg(dev, "dropping unknown message 0x%x", msg); 21262306a36Sopenharmony_ci return; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci /* msg contains the index of the triggered vring */ 21562306a36Sopenharmony_ci if (rproc_vq_interrupt(kproc->rproc, msg) == IRQ_NONE) 21662306a36Sopenharmony_ci dev_dbg(dev, "no message was found in vqid %d\n", msg); 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci/* kick a virtqueue */ 22162306a36Sopenharmony_cistatic void k3_r5_rproc_kick(struct rproc *rproc, int vqid) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct k3_r5_rproc *kproc = rproc->priv; 22462306a36Sopenharmony_ci struct device *dev = rproc->dev.parent; 22562306a36Sopenharmony_ci mbox_msg_t msg = (mbox_msg_t)vqid; 22662306a36Sopenharmony_ci int ret; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* send the index of the triggered virtqueue in the mailbox payload */ 22962306a36Sopenharmony_ci ret = mbox_send_message(kproc->mbox, (void *)msg); 23062306a36Sopenharmony_ci if (ret < 0) 23162306a36Sopenharmony_ci dev_err(dev, "failed to send mailbox message, status = %d\n", 23262306a36Sopenharmony_ci ret); 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic int k3_r5_split_reset(struct k3_r5_core *core) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci int ret; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci ret = reset_control_assert(core->reset); 24062306a36Sopenharmony_ci if (ret) { 24162306a36Sopenharmony_ci dev_err(core->dev, "local-reset assert failed, ret = %d\n", 24262306a36Sopenharmony_ci ret); 24362306a36Sopenharmony_ci return ret; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci ret = core->ti_sci->ops.dev_ops.put_device(core->ti_sci, 24762306a36Sopenharmony_ci core->ti_sci_id); 24862306a36Sopenharmony_ci if (ret) { 24962306a36Sopenharmony_ci dev_err(core->dev, "module-reset assert failed, ret = %d\n", 25062306a36Sopenharmony_ci ret); 25162306a36Sopenharmony_ci if (reset_control_deassert(core->reset)) 25262306a36Sopenharmony_ci dev_warn(core->dev, "local-reset deassert back failed\n"); 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci return ret; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic int k3_r5_split_release(struct k3_r5_core *core) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci int ret; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci ret = core->ti_sci->ops.dev_ops.get_device(core->ti_sci, 26362306a36Sopenharmony_ci core->ti_sci_id); 26462306a36Sopenharmony_ci if (ret) { 26562306a36Sopenharmony_ci dev_err(core->dev, "module-reset deassert failed, ret = %d\n", 26662306a36Sopenharmony_ci ret); 26762306a36Sopenharmony_ci return ret; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci ret = reset_control_deassert(core->reset); 27162306a36Sopenharmony_ci if (ret) { 27262306a36Sopenharmony_ci dev_err(core->dev, "local-reset deassert failed, ret = %d\n", 27362306a36Sopenharmony_ci ret); 27462306a36Sopenharmony_ci if (core->ti_sci->ops.dev_ops.put_device(core->ti_sci, 27562306a36Sopenharmony_ci core->ti_sci_id)) 27662306a36Sopenharmony_ci dev_warn(core->dev, "module-reset assert back failed\n"); 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci return ret; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic int k3_r5_lockstep_reset(struct k3_r5_cluster *cluster) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci struct k3_r5_core *core; 28562306a36Sopenharmony_ci int ret; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* assert local reset on all applicable cores */ 28862306a36Sopenharmony_ci list_for_each_entry(core, &cluster->cores, elem) { 28962306a36Sopenharmony_ci ret = reset_control_assert(core->reset); 29062306a36Sopenharmony_ci if (ret) { 29162306a36Sopenharmony_ci dev_err(core->dev, "local-reset assert failed, ret = %d\n", 29262306a36Sopenharmony_ci ret); 29362306a36Sopenharmony_ci core = list_prev_entry(core, elem); 29462306a36Sopenharmony_ci goto unroll_local_reset; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci /* disable PSC modules on all applicable cores */ 29962306a36Sopenharmony_ci list_for_each_entry(core, &cluster->cores, elem) { 30062306a36Sopenharmony_ci ret = core->ti_sci->ops.dev_ops.put_device(core->ti_sci, 30162306a36Sopenharmony_ci core->ti_sci_id); 30262306a36Sopenharmony_ci if (ret) { 30362306a36Sopenharmony_ci dev_err(core->dev, "module-reset assert failed, ret = %d\n", 30462306a36Sopenharmony_ci ret); 30562306a36Sopenharmony_ci goto unroll_module_reset; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci return 0; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ciunroll_module_reset: 31262306a36Sopenharmony_ci list_for_each_entry_continue_reverse(core, &cluster->cores, elem) { 31362306a36Sopenharmony_ci if (core->ti_sci->ops.dev_ops.put_device(core->ti_sci, 31462306a36Sopenharmony_ci core->ti_sci_id)) 31562306a36Sopenharmony_ci dev_warn(core->dev, "module-reset assert back failed\n"); 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci core = list_last_entry(&cluster->cores, struct k3_r5_core, elem); 31862306a36Sopenharmony_ciunroll_local_reset: 31962306a36Sopenharmony_ci list_for_each_entry_from_reverse(core, &cluster->cores, elem) { 32062306a36Sopenharmony_ci if (reset_control_deassert(core->reset)) 32162306a36Sopenharmony_ci dev_warn(core->dev, "local-reset deassert back failed\n"); 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci return ret; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic int k3_r5_lockstep_release(struct k3_r5_cluster *cluster) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct k3_r5_core *core; 33062306a36Sopenharmony_ci int ret; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* enable PSC modules on all applicable cores */ 33362306a36Sopenharmony_ci list_for_each_entry_reverse(core, &cluster->cores, elem) { 33462306a36Sopenharmony_ci ret = core->ti_sci->ops.dev_ops.get_device(core->ti_sci, 33562306a36Sopenharmony_ci core->ti_sci_id); 33662306a36Sopenharmony_ci if (ret) { 33762306a36Sopenharmony_ci dev_err(core->dev, "module-reset deassert failed, ret = %d\n", 33862306a36Sopenharmony_ci ret); 33962306a36Sopenharmony_ci core = list_next_entry(core, elem); 34062306a36Sopenharmony_ci goto unroll_module_reset; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* deassert local reset on all applicable cores */ 34562306a36Sopenharmony_ci list_for_each_entry_reverse(core, &cluster->cores, elem) { 34662306a36Sopenharmony_ci ret = reset_control_deassert(core->reset); 34762306a36Sopenharmony_ci if (ret) { 34862306a36Sopenharmony_ci dev_err(core->dev, "module-reset deassert failed, ret = %d\n", 34962306a36Sopenharmony_ci ret); 35062306a36Sopenharmony_ci goto unroll_local_reset; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci return 0; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ciunroll_local_reset: 35762306a36Sopenharmony_ci list_for_each_entry_continue(core, &cluster->cores, elem) { 35862306a36Sopenharmony_ci if (reset_control_assert(core->reset)) 35962306a36Sopenharmony_ci dev_warn(core->dev, "local-reset assert back failed\n"); 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci core = list_first_entry(&cluster->cores, struct k3_r5_core, elem); 36262306a36Sopenharmony_ciunroll_module_reset: 36362306a36Sopenharmony_ci list_for_each_entry_from(core, &cluster->cores, elem) { 36462306a36Sopenharmony_ci if (core->ti_sci->ops.dev_ops.put_device(core->ti_sci, 36562306a36Sopenharmony_ci core->ti_sci_id)) 36662306a36Sopenharmony_ci dev_warn(core->dev, "module-reset assert back failed\n"); 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return ret; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic inline int k3_r5_core_halt(struct k3_r5_core *core) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci return ti_sci_proc_set_control(core->tsp, 37562306a36Sopenharmony_ci PROC_BOOT_CTRL_FLAG_R5_CORE_HALT, 0); 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic inline int k3_r5_core_run(struct k3_r5_core *core) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci return ti_sci_proc_set_control(core->tsp, 38162306a36Sopenharmony_ci 0, PROC_BOOT_CTRL_FLAG_R5_CORE_HALT); 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic int k3_r5_rproc_request_mbox(struct rproc *rproc) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct k3_r5_rproc *kproc = rproc->priv; 38762306a36Sopenharmony_ci struct mbox_client *client = &kproc->client; 38862306a36Sopenharmony_ci struct device *dev = kproc->dev; 38962306a36Sopenharmony_ci int ret; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci client->dev = dev; 39262306a36Sopenharmony_ci client->tx_done = NULL; 39362306a36Sopenharmony_ci client->rx_callback = k3_r5_rproc_mbox_callback; 39462306a36Sopenharmony_ci client->tx_block = false; 39562306a36Sopenharmony_ci client->knows_txdone = false; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci kproc->mbox = mbox_request_channel(client, 0); 39862306a36Sopenharmony_ci if (IS_ERR(kproc->mbox)) { 39962306a36Sopenharmony_ci ret = -EBUSY; 40062306a36Sopenharmony_ci dev_err(dev, "mbox_request_channel failed: %ld\n", 40162306a36Sopenharmony_ci PTR_ERR(kproc->mbox)); 40262306a36Sopenharmony_ci return ret; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* 40662306a36Sopenharmony_ci * Ping the remote processor, this is only for sanity-sake for now; 40762306a36Sopenharmony_ci * there is no functional effect whatsoever. 40862306a36Sopenharmony_ci * 40962306a36Sopenharmony_ci * Note that the reply will _not_ arrive immediately: this message 41062306a36Sopenharmony_ci * will wait in the mailbox fifo until the remote processor is booted. 41162306a36Sopenharmony_ci */ 41262306a36Sopenharmony_ci ret = mbox_send_message(kproc->mbox, (void *)RP_MBOX_ECHO_REQUEST); 41362306a36Sopenharmony_ci if (ret < 0) { 41462306a36Sopenharmony_ci dev_err(dev, "mbox_send_message failed: %d\n", ret); 41562306a36Sopenharmony_ci mbox_free_channel(kproc->mbox); 41662306a36Sopenharmony_ci return ret; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci return 0; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci/* 42362306a36Sopenharmony_ci * The R5F cores have controls for both a reset and a halt/run. The code 42462306a36Sopenharmony_ci * execution from DDR requires the initial boot-strapping code to be run 42562306a36Sopenharmony_ci * from the internal TCMs. This function is used to release the resets on 42662306a36Sopenharmony_ci * applicable cores to allow loading into the TCMs. The .prepare() ops is 42762306a36Sopenharmony_ci * invoked by remoteproc core before any firmware loading, and is followed 42862306a36Sopenharmony_ci * by the .start() ops after loading to actually let the R5 cores run. 42962306a36Sopenharmony_ci * 43062306a36Sopenharmony_ci * The Single-CPU mode on applicable SoCs (eg: AM64x) only uses Core0 to 43162306a36Sopenharmony_ci * execute code, but combines the TCMs from both cores. The resets for both 43262306a36Sopenharmony_ci * cores need to be released to make this possible, as the TCMs are in general 43362306a36Sopenharmony_ci * private to each core. Only Core0 needs to be unhalted for running the 43462306a36Sopenharmony_ci * cluster in this mode. The function uses the same reset logic as LockStep 43562306a36Sopenharmony_ci * mode for this (though the behavior is agnostic of the reset release order). 43662306a36Sopenharmony_ci * This callback is invoked only in remoteproc mode. 43762306a36Sopenharmony_ci */ 43862306a36Sopenharmony_cistatic int k3_r5_rproc_prepare(struct rproc *rproc) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci struct k3_r5_rproc *kproc = rproc->priv; 44162306a36Sopenharmony_ci struct k3_r5_cluster *cluster = kproc->cluster; 44262306a36Sopenharmony_ci struct k3_r5_core *core = kproc->core; 44362306a36Sopenharmony_ci struct device *dev = kproc->dev; 44462306a36Sopenharmony_ci u32 ctrl = 0, cfg = 0, stat = 0; 44562306a36Sopenharmony_ci u64 boot_vec = 0; 44662306a36Sopenharmony_ci bool mem_init_dis; 44762306a36Sopenharmony_ci int ret; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci ret = ti_sci_proc_get_status(core->tsp, &boot_vec, &cfg, &ctrl, &stat); 45062306a36Sopenharmony_ci if (ret < 0) 45162306a36Sopenharmony_ci return ret; 45262306a36Sopenharmony_ci mem_init_dis = !!(cfg & PROC_BOOT_CFG_FLAG_R5_MEM_INIT_DIS); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* Re-use LockStep-mode reset logic for Single-CPU mode */ 45562306a36Sopenharmony_ci ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP || 45662306a36Sopenharmony_ci cluster->mode == CLUSTER_MODE_SINGLECPU) ? 45762306a36Sopenharmony_ci k3_r5_lockstep_release(cluster) : k3_r5_split_release(core); 45862306a36Sopenharmony_ci if (ret) { 45962306a36Sopenharmony_ci dev_err(dev, "unable to enable cores for TCM loading, ret = %d\n", 46062306a36Sopenharmony_ci ret); 46162306a36Sopenharmony_ci return ret; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* 46562306a36Sopenharmony_ci * Newer IP revisions like on J7200 SoCs support h/w auto-initialization 46662306a36Sopenharmony_ci * of TCMs, so there is no need to perform the s/w memzero. This bit is 46762306a36Sopenharmony_ci * configurable through System Firmware, the default value does perform 46862306a36Sopenharmony_ci * auto-init, but account for it in case it is disabled 46962306a36Sopenharmony_ci */ 47062306a36Sopenharmony_ci if (cluster->soc_data->tcm_ecc_autoinit && !mem_init_dis) { 47162306a36Sopenharmony_ci dev_dbg(dev, "leveraging h/w init for TCM memories\n"); 47262306a36Sopenharmony_ci return 0; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* 47662306a36Sopenharmony_ci * Zero out both TCMs unconditionally (access from v8 Arm core is not 47762306a36Sopenharmony_ci * affected by ATCM & BTCM enable configuration values) so that ECC 47862306a36Sopenharmony_ci * can be effective on all TCM addresses. 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_ci dev_dbg(dev, "zeroing out ATCM memory\n"); 48162306a36Sopenharmony_ci memset(core->mem[0].cpu_addr, 0x00, core->mem[0].size); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci dev_dbg(dev, "zeroing out BTCM memory\n"); 48462306a36Sopenharmony_ci memset(core->mem[1].cpu_addr, 0x00, core->mem[1].size); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci return 0; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci/* 49062306a36Sopenharmony_ci * This function implements the .unprepare() ops and performs the complimentary 49162306a36Sopenharmony_ci * operations to that of the .prepare() ops. The function is used to assert the 49262306a36Sopenharmony_ci * resets on all applicable cores for the rproc device (depending on LockStep 49362306a36Sopenharmony_ci * or Split mode). This completes the second portion of powering down the R5F 49462306a36Sopenharmony_ci * cores. The cores themselves are only halted in the .stop() ops, and the 49562306a36Sopenharmony_ci * .unprepare() ops is invoked by the remoteproc core after the remoteproc is 49662306a36Sopenharmony_ci * stopped. 49762306a36Sopenharmony_ci * 49862306a36Sopenharmony_ci * The Single-CPU mode on applicable SoCs (eg: AM64x) combines the TCMs from 49962306a36Sopenharmony_ci * both cores. The access is made possible only with releasing the resets for 50062306a36Sopenharmony_ci * both cores, but with only Core0 unhalted. This function re-uses the same 50162306a36Sopenharmony_ci * reset assert logic as LockStep mode for this mode (though the behavior is 50262306a36Sopenharmony_ci * agnostic of the reset assert order). This callback is invoked only in 50362306a36Sopenharmony_ci * remoteproc mode. 50462306a36Sopenharmony_ci */ 50562306a36Sopenharmony_cistatic int k3_r5_rproc_unprepare(struct rproc *rproc) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct k3_r5_rproc *kproc = rproc->priv; 50862306a36Sopenharmony_ci struct k3_r5_cluster *cluster = kproc->cluster; 50962306a36Sopenharmony_ci struct k3_r5_core *core = kproc->core; 51062306a36Sopenharmony_ci struct device *dev = kproc->dev; 51162306a36Sopenharmony_ci int ret; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci /* Re-use LockStep-mode reset logic for Single-CPU mode */ 51462306a36Sopenharmony_ci ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP || 51562306a36Sopenharmony_ci cluster->mode == CLUSTER_MODE_SINGLECPU) ? 51662306a36Sopenharmony_ci k3_r5_lockstep_reset(cluster) : k3_r5_split_reset(core); 51762306a36Sopenharmony_ci if (ret) 51862306a36Sopenharmony_ci dev_err(dev, "unable to disable cores, ret = %d\n", ret); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return ret; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci/* 52462306a36Sopenharmony_ci * The R5F start sequence includes two different operations 52562306a36Sopenharmony_ci * 1. Configure the boot vector for R5F core(s) 52662306a36Sopenharmony_ci * 2. Unhalt/Run the R5F core(s) 52762306a36Sopenharmony_ci * 52862306a36Sopenharmony_ci * The sequence is different between LockStep and Split modes. The LockStep 52962306a36Sopenharmony_ci * mode requires the boot vector to be configured only for Core0, and then 53062306a36Sopenharmony_ci * unhalt both the cores to start the execution - Core1 needs to be unhalted 53162306a36Sopenharmony_ci * first followed by Core0. The Split-mode requires that Core0 to be maintained 53262306a36Sopenharmony_ci * always in a higher power state that Core1 (implying Core1 needs to be started 53362306a36Sopenharmony_ci * always only after Core0 is started). 53462306a36Sopenharmony_ci * 53562306a36Sopenharmony_ci * The Single-CPU mode on applicable SoCs (eg: AM64x) only uses Core0 to execute 53662306a36Sopenharmony_ci * code, so only Core0 needs to be unhalted. The function uses the same logic 53762306a36Sopenharmony_ci * flow as Split-mode for this. This callback is invoked only in remoteproc 53862306a36Sopenharmony_ci * mode. 53962306a36Sopenharmony_ci */ 54062306a36Sopenharmony_cistatic int k3_r5_rproc_start(struct rproc *rproc) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct k3_r5_rproc *kproc = rproc->priv; 54362306a36Sopenharmony_ci struct k3_r5_cluster *cluster = kproc->cluster; 54462306a36Sopenharmony_ci struct device *dev = kproc->dev; 54562306a36Sopenharmony_ci struct k3_r5_core *core; 54662306a36Sopenharmony_ci u32 boot_addr; 54762306a36Sopenharmony_ci int ret; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci ret = k3_r5_rproc_request_mbox(rproc); 55062306a36Sopenharmony_ci if (ret) 55162306a36Sopenharmony_ci return ret; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci boot_addr = rproc->bootaddr; 55462306a36Sopenharmony_ci /* TODO: add boot_addr sanity checking */ 55562306a36Sopenharmony_ci dev_dbg(dev, "booting R5F core using boot addr = 0x%x\n", boot_addr); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /* boot vector need not be programmed for Core1 in LockStep mode */ 55862306a36Sopenharmony_ci core = kproc->core; 55962306a36Sopenharmony_ci ret = ti_sci_proc_set_config(core->tsp, boot_addr, 0, 0); 56062306a36Sopenharmony_ci if (ret) 56162306a36Sopenharmony_ci goto put_mbox; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* unhalt/run all applicable cores */ 56462306a36Sopenharmony_ci if (cluster->mode == CLUSTER_MODE_LOCKSTEP) { 56562306a36Sopenharmony_ci list_for_each_entry_reverse(core, &cluster->cores, elem) { 56662306a36Sopenharmony_ci ret = k3_r5_core_run(core); 56762306a36Sopenharmony_ci if (ret) 56862306a36Sopenharmony_ci goto unroll_core_run; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci } else { 57162306a36Sopenharmony_ci ret = k3_r5_core_run(core); 57262306a36Sopenharmony_ci if (ret) 57362306a36Sopenharmony_ci goto put_mbox; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci return 0; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ciunroll_core_run: 57962306a36Sopenharmony_ci list_for_each_entry_continue(core, &cluster->cores, elem) { 58062306a36Sopenharmony_ci if (k3_r5_core_halt(core)) 58162306a36Sopenharmony_ci dev_warn(core->dev, "core halt back failed\n"); 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ciput_mbox: 58462306a36Sopenharmony_ci mbox_free_channel(kproc->mbox); 58562306a36Sopenharmony_ci return ret; 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci/* 58962306a36Sopenharmony_ci * The R5F stop function includes the following operations 59062306a36Sopenharmony_ci * 1. Halt R5F core(s) 59162306a36Sopenharmony_ci * 59262306a36Sopenharmony_ci * The sequence is different between LockStep and Split modes, and the order 59362306a36Sopenharmony_ci * of cores the operations are performed are also in general reverse to that 59462306a36Sopenharmony_ci * of the start function. The LockStep mode requires each operation to be 59562306a36Sopenharmony_ci * performed first on Core0 followed by Core1. The Split-mode requires that 59662306a36Sopenharmony_ci * Core0 to be maintained always in a higher power state that Core1 (implying 59762306a36Sopenharmony_ci * Core1 needs to be stopped first before Core0). 59862306a36Sopenharmony_ci * 59962306a36Sopenharmony_ci * The Single-CPU mode on applicable SoCs (eg: AM64x) only uses Core0 to execute 60062306a36Sopenharmony_ci * code, so only Core0 needs to be halted. The function uses the same logic 60162306a36Sopenharmony_ci * flow as Split-mode for this. 60262306a36Sopenharmony_ci * 60362306a36Sopenharmony_ci * Note that the R5F halt operation in general is not effective when the R5F 60462306a36Sopenharmony_ci * core is running, but is needed to make sure the core won't run after 60562306a36Sopenharmony_ci * deasserting the reset the subsequent time. The asserting of reset can 60662306a36Sopenharmony_ci * be done here, but is preferred to be done in the .unprepare() ops - this 60762306a36Sopenharmony_ci * maintains the symmetric behavior between the .start(), .stop(), .prepare() 60862306a36Sopenharmony_ci * and .unprepare() ops, and also balances them well between sysfs 'state' 60962306a36Sopenharmony_ci * flow and device bind/unbind or module removal. This callback is invoked 61062306a36Sopenharmony_ci * only in remoteproc mode. 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_cistatic int k3_r5_rproc_stop(struct rproc *rproc) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci struct k3_r5_rproc *kproc = rproc->priv; 61562306a36Sopenharmony_ci struct k3_r5_cluster *cluster = kproc->cluster; 61662306a36Sopenharmony_ci struct k3_r5_core *core = kproc->core; 61762306a36Sopenharmony_ci int ret; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* halt all applicable cores */ 62062306a36Sopenharmony_ci if (cluster->mode == CLUSTER_MODE_LOCKSTEP) { 62162306a36Sopenharmony_ci list_for_each_entry(core, &cluster->cores, elem) { 62262306a36Sopenharmony_ci ret = k3_r5_core_halt(core); 62362306a36Sopenharmony_ci if (ret) { 62462306a36Sopenharmony_ci core = list_prev_entry(core, elem); 62562306a36Sopenharmony_ci goto unroll_core_halt; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci } else { 62962306a36Sopenharmony_ci ret = k3_r5_core_halt(core); 63062306a36Sopenharmony_ci if (ret) 63162306a36Sopenharmony_ci goto out; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci mbox_free_channel(kproc->mbox); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci return 0; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ciunroll_core_halt: 63962306a36Sopenharmony_ci list_for_each_entry_from_reverse(core, &cluster->cores, elem) { 64062306a36Sopenharmony_ci if (k3_r5_core_run(core)) 64162306a36Sopenharmony_ci dev_warn(core->dev, "core run back failed\n"); 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ciout: 64462306a36Sopenharmony_ci return ret; 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci/* 64862306a36Sopenharmony_ci * Attach to a running R5F remote processor (IPC-only mode) 64962306a36Sopenharmony_ci * 65062306a36Sopenharmony_ci * The R5F attach callback only needs to request the mailbox, the remote 65162306a36Sopenharmony_ci * processor is already booted, so there is no need to issue any TI-SCI 65262306a36Sopenharmony_ci * commands to boot the R5F cores in IPC-only mode. This callback is invoked 65362306a36Sopenharmony_ci * only in IPC-only mode. 65462306a36Sopenharmony_ci */ 65562306a36Sopenharmony_cistatic int k3_r5_rproc_attach(struct rproc *rproc) 65662306a36Sopenharmony_ci{ 65762306a36Sopenharmony_ci struct k3_r5_rproc *kproc = rproc->priv; 65862306a36Sopenharmony_ci struct device *dev = kproc->dev; 65962306a36Sopenharmony_ci int ret; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci ret = k3_r5_rproc_request_mbox(rproc); 66262306a36Sopenharmony_ci if (ret) 66362306a36Sopenharmony_ci return ret; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci dev_info(dev, "R5F core initialized in IPC-only mode\n"); 66662306a36Sopenharmony_ci return 0; 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci/* 67062306a36Sopenharmony_ci * Detach from a running R5F remote processor (IPC-only mode) 67162306a36Sopenharmony_ci * 67262306a36Sopenharmony_ci * The R5F detach callback performs the opposite operation to attach callback 67362306a36Sopenharmony_ci * and only needs to release the mailbox, the R5F cores are not stopped and 67462306a36Sopenharmony_ci * will be left in booted state in IPC-only mode. This callback is invoked 67562306a36Sopenharmony_ci * only in IPC-only mode. 67662306a36Sopenharmony_ci */ 67762306a36Sopenharmony_cistatic int k3_r5_rproc_detach(struct rproc *rproc) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci struct k3_r5_rproc *kproc = rproc->priv; 68062306a36Sopenharmony_ci struct device *dev = kproc->dev; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci mbox_free_channel(kproc->mbox); 68362306a36Sopenharmony_ci dev_info(dev, "R5F core deinitialized in IPC-only mode\n"); 68462306a36Sopenharmony_ci return 0; 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci/* 68862306a36Sopenharmony_ci * This function implements the .get_loaded_rsc_table() callback and is used 68962306a36Sopenharmony_ci * to provide the resource table for the booted R5F in IPC-only mode. The K3 R5F 69062306a36Sopenharmony_ci * firmwares follow a design-by-contract approach and are expected to have the 69162306a36Sopenharmony_ci * resource table at the base of the DDR region reserved for firmware usage. 69262306a36Sopenharmony_ci * This provides flexibility for the remote processor to be booted by different 69362306a36Sopenharmony_ci * bootloaders that may or may not have the ability to publish the resource table 69462306a36Sopenharmony_ci * address and size through a DT property. This callback is invoked only in 69562306a36Sopenharmony_ci * IPC-only mode. 69662306a36Sopenharmony_ci */ 69762306a36Sopenharmony_cistatic struct resource_table *k3_r5_get_loaded_rsc_table(struct rproc *rproc, 69862306a36Sopenharmony_ci size_t *rsc_table_sz) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci struct k3_r5_rproc *kproc = rproc->priv; 70162306a36Sopenharmony_ci struct device *dev = kproc->dev; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci if (!kproc->rmem[0].cpu_addr) { 70462306a36Sopenharmony_ci dev_err(dev, "memory-region #1 does not exist, loaded rsc table can't be found"); 70562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci /* 70962306a36Sopenharmony_ci * NOTE: The resource table size is currently hard-coded to a maximum 71062306a36Sopenharmony_ci * of 256 bytes. The most common resource table usage for K3 firmwares 71162306a36Sopenharmony_ci * is to only have the vdev resource entry and an optional trace entry. 71262306a36Sopenharmony_ci * The exact size could be computed based on resource table address, but 71362306a36Sopenharmony_ci * the hard-coded value suffices to support the IPC-only mode. 71462306a36Sopenharmony_ci */ 71562306a36Sopenharmony_ci *rsc_table_sz = 256; 71662306a36Sopenharmony_ci return (struct resource_table *)kproc->rmem[0].cpu_addr; 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci/* 72062306a36Sopenharmony_ci * Internal Memory translation helper 72162306a36Sopenharmony_ci * 72262306a36Sopenharmony_ci * Custom function implementing the rproc .da_to_va ops to provide address 72362306a36Sopenharmony_ci * translation (device address to kernel virtual address) for internal RAMs 72462306a36Sopenharmony_ci * present in a DSP or IPU device). The translated addresses can be used 72562306a36Sopenharmony_ci * either by the remoteproc core for loading, or by any rpmsg bus drivers. 72662306a36Sopenharmony_ci */ 72762306a36Sopenharmony_cistatic void *k3_r5_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci struct k3_r5_rproc *kproc = rproc->priv; 73062306a36Sopenharmony_ci struct k3_r5_core *core = kproc->core; 73162306a36Sopenharmony_ci void __iomem *va = NULL; 73262306a36Sopenharmony_ci phys_addr_t bus_addr; 73362306a36Sopenharmony_ci u32 dev_addr, offset; 73462306a36Sopenharmony_ci size_t size; 73562306a36Sopenharmony_ci int i; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci if (len == 0) 73862306a36Sopenharmony_ci return NULL; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci /* handle both R5 and SoC views of ATCM and BTCM */ 74162306a36Sopenharmony_ci for (i = 0; i < core->num_mems; i++) { 74262306a36Sopenharmony_ci bus_addr = core->mem[i].bus_addr; 74362306a36Sopenharmony_ci dev_addr = core->mem[i].dev_addr; 74462306a36Sopenharmony_ci size = core->mem[i].size; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci /* handle R5-view addresses of TCMs */ 74762306a36Sopenharmony_ci if (da >= dev_addr && ((da + len) <= (dev_addr + size))) { 74862306a36Sopenharmony_ci offset = da - dev_addr; 74962306a36Sopenharmony_ci va = core->mem[i].cpu_addr + offset; 75062306a36Sopenharmony_ci return (__force void *)va; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci /* handle SoC-view addresses of TCMs */ 75462306a36Sopenharmony_ci if (da >= bus_addr && ((da + len) <= (bus_addr + size))) { 75562306a36Sopenharmony_ci offset = da - bus_addr; 75662306a36Sopenharmony_ci va = core->mem[i].cpu_addr + offset; 75762306a36Sopenharmony_ci return (__force void *)va; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci /* handle any SRAM regions using SoC-view addresses */ 76262306a36Sopenharmony_ci for (i = 0; i < core->num_sram; i++) { 76362306a36Sopenharmony_ci dev_addr = core->sram[i].dev_addr; 76462306a36Sopenharmony_ci size = core->sram[i].size; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci if (da >= dev_addr && ((da + len) <= (dev_addr + size))) { 76762306a36Sopenharmony_ci offset = da - dev_addr; 76862306a36Sopenharmony_ci va = core->sram[i].cpu_addr + offset; 76962306a36Sopenharmony_ci return (__force void *)va; 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci /* handle static DDR reserved memory regions */ 77462306a36Sopenharmony_ci for (i = 0; i < kproc->num_rmems; i++) { 77562306a36Sopenharmony_ci dev_addr = kproc->rmem[i].dev_addr; 77662306a36Sopenharmony_ci size = kproc->rmem[i].size; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci if (da >= dev_addr && ((da + len) <= (dev_addr + size))) { 77962306a36Sopenharmony_ci offset = da - dev_addr; 78062306a36Sopenharmony_ci va = kproc->rmem[i].cpu_addr + offset; 78162306a36Sopenharmony_ci return (__force void *)va; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci return NULL; 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic const struct rproc_ops k3_r5_rproc_ops = { 78962306a36Sopenharmony_ci .prepare = k3_r5_rproc_prepare, 79062306a36Sopenharmony_ci .unprepare = k3_r5_rproc_unprepare, 79162306a36Sopenharmony_ci .start = k3_r5_rproc_start, 79262306a36Sopenharmony_ci .stop = k3_r5_rproc_stop, 79362306a36Sopenharmony_ci .kick = k3_r5_rproc_kick, 79462306a36Sopenharmony_ci .da_to_va = k3_r5_rproc_da_to_va, 79562306a36Sopenharmony_ci}; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci/* 79862306a36Sopenharmony_ci * Internal R5F Core configuration 79962306a36Sopenharmony_ci * 80062306a36Sopenharmony_ci * Each R5FSS has a cluster-level setting for configuring the processor 80162306a36Sopenharmony_ci * subsystem either in a safety/fault-tolerant LockStep mode or a performance 80262306a36Sopenharmony_ci * oriented Split mode on most SoCs. A fewer SoCs support a non-safety mode 80362306a36Sopenharmony_ci * as an alternate for LockStep mode that exercises only a single R5F core 80462306a36Sopenharmony_ci * called Single-CPU mode. Each R5F core has a number of settings to either 80562306a36Sopenharmony_ci * enable/disable each of the TCMs, control which TCM appears at the R5F core's 80662306a36Sopenharmony_ci * address 0x0. These settings need to be configured before the resets for the 80762306a36Sopenharmony_ci * corresponding core are released. These settings are all protected and managed 80862306a36Sopenharmony_ci * by the System Processor. 80962306a36Sopenharmony_ci * 81062306a36Sopenharmony_ci * This function is used to pre-configure these settings for each R5F core, and 81162306a36Sopenharmony_ci * the configuration is all done through various ti_sci_proc functions that 81262306a36Sopenharmony_ci * communicate with the System Processor. The function also ensures that both 81362306a36Sopenharmony_ci * the cores are halted before the .prepare() step. 81462306a36Sopenharmony_ci * 81562306a36Sopenharmony_ci * The function is called from k3_r5_cluster_rproc_init() and is invoked either 81662306a36Sopenharmony_ci * once (in LockStep mode or Single-CPU modes) or twice (in Split mode). Support 81762306a36Sopenharmony_ci * for LockStep-mode is dictated by an eFUSE register bit, and the config 81862306a36Sopenharmony_ci * settings retrieved from DT are adjusted accordingly as per the permitted 81962306a36Sopenharmony_ci * cluster mode. Another eFUSE register bit dictates if the R5F cluster only 82062306a36Sopenharmony_ci * supports a Single-CPU mode. All cluster level settings like Cluster mode and 82162306a36Sopenharmony_ci * TEINIT (exception handling state dictating ARM or Thumb mode) can only be set 82262306a36Sopenharmony_ci * and retrieved using Core0. 82362306a36Sopenharmony_ci * 82462306a36Sopenharmony_ci * The function behavior is different based on the cluster mode. The R5F cores 82562306a36Sopenharmony_ci * are configured independently as per their individual settings in Split mode. 82662306a36Sopenharmony_ci * They are identically configured in LockStep mode using the primary Core0 82762306a36Sopenharmony_ci * settings. However, some individual settings cannot be set in LockStep mode. 82862306a36Sopenharmony_ci * This is overcome by switching to Split-mode initially and then programming 82962306a36Sopenharmony_ci * both the cores with the same settings, before reconfiguing again for 83062306a36Sopenharmony_ci * LockStep mode. 83162306a36Sopenharmony_ci */ 83262306a36Sopenharmony_cistatic int k3_r5_rproc_configure(struct k3_r5_rproc *kproc) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci struct k3_r5_cluster *cluster = kproc->cluster; 83562306a36Sopenharmony_ci struct device *dev = kproc->dev; 83662306a36Sopenharmony_ci struct k3_r5_core *core0, *core, *temp; 83762306a36Sopenharmony_ci u32 ctrl = 0, cfg = 0, stat = 0; 83862306a36Sopenharmony_ci u32 set_cfg = 0, clr_cfg = 0; 83962306a36Sopenharmony_ci u64 boot_vec = 0; 84062306a36Sopenharmony_ci bool lockstep_en; 84162306a36Sopenharmony_ci bool single_cpu; 84262306a36Sopenharmony_ci int ret; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci core0 = list_first_entry(&cluster->cores, struct k3_r5_core, elem); 84562306a36Sopenharmony_ci if (cluster->mode == CLUSTER_MODE_LOCKSTEP || 84662306a36Sopenharmony_ci cluster->mode == CLUSTER_MODE_SINGLECPU || 84762306a36Sopenharmony_ci cluster->mode == CLUSTER_MODE_SINGLECORE) { 84862306a36Sopenharmony_ci core = core0; 84962306a36Sopenharmony_ci } else { 85062306a36Sopenharmony_ci core = kproc->core; 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci ret = ti_sci_proc_get_status(core->tsp, &boot_vec, &cfg, &ctrl, 85462306a36Sopenharmony_ci &stat); 85562306a36Sopenharmony_ci if (ret < 0) 85662306a36Sopenharmony_ci return ret; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci dev_dbg(dev, "boot_vector = 0x%llx, cfg = 0x%x ctrl = 0x%x stat = 0x%x\n", 85962306a36Sopenharmony_ci boot_vec, cfg, ctrl, stat); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci single_cpu = !!(stat & PROC_BOOT_STATUS_FLAG_R5_SINGLECORE_ONLY); 86262306a36Sopenharmony_ci lockstep_en = !!(stat & PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci /* Override to single CPU mode if set in status flag */ 86562306a36Sopenharmony_ci if (single_cpu && cluster->mode == CLUSTER_MODE_SPLIT) { 86662306a36Sopenharmony_ci dev_err(cluster->dev, "split-mode not permitted, force configuring for single-cpu mode\n"); 86762306a36Sopenharmony_ci cluster->mode = CLUSTER_MODE_SINGLECPU; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* Override to split mode if lockstep enable bit is not set in status flag */ 87162306a36Sopenharmony_ci if (!lockstep_en && cluster->mode == CLUSTER_MODE_LOCKSTEP) { 87262306a36Sopenharmony_ci dev_err(cluster->dev, "lockstep mode not permitted, force configuring for split-mode\n"); 87362306a36Sopenharmony_ci cluster->mode = CLUSTER_MODE_SPLIT; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci /* always enable ARM mode and set boot vector to 0 */ 87762306a36Sopenharmony_ci boot_vec = 0x0; 87862306a36Sopenharmony_ci if (core == core0) { 87962306a36Sopenharmony_ci clr_cfg = PROC_BOOT_CFG_FLAG_R5_TEINIT; 88062306a36Sopenharmony_ci /* 88162306a36Sopenharmony_ci * Single-CPU configuration bit can only be configured 88262306a36Sopenharmony_ci * on Core0 and system firmware will NACK any requests 88362306a36Sopenharmony_ci * with the bit configured, so program it only on 88462306a36Sopenharmony_ci * permitted cores 88562306a36Sopenharmony_ci */ 88662306a36Sopenharmony_ci if (cluster->mode == CLUSTER_MODE_SINGLECPU || 88762306a36Sopenharmony_ci cluster->mode == CLUSTER_MODE_SINGLECORE) { 88862306a36Sopenharmony_ci set_cfg = PROC_BOOT_CFG_FLAG_R5_SINGLE_CORE; 88962306a36Sopenharmony_ci } else { 89062306a36Sopenharmony_ci /* 89162306a36Sopenharmony_ci * LockStep configuration bit is Read-only on Split-mode 89262306a36Sopenharmony_ci * _only_ devices and system firmware will NACK any 89362306a36Sopenharmony_ci * requests with the bit configured, so program it only 89462306a36Sopenharmony_ci * on permitted devices 89562306a36Sopenharmony_ci */ 89662306a36Sopenharmony_ci if (lockstep_en) 89762306a36Sopenharmony_ci clr_cfg |= PROC_BOOT_CFG_FLAG_R5_LOCKSTEP; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (core->atcm_enable) 90262306a36Sopenharmony_ci set_cfg |= PROC_BOOT_CFG_FLAG_R5_ATCM_EN; 90362306a36Sopenharmony_ci else 90462306a36Sopenharmony_ci clr_cfg |= PROC_BOOT_CFG_FLAG_R5_ATCM_EN; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci if (core->btcm_enable) 90762306a36Sopenharmony_ci set_cfg |= PROC_BOOT_CFG_FLAG_R5_BTCM_EN; 90862306a36Sopenharmony_ci else 90962306a36Sopenharmony_ci clr_cfg |= PROC_BOOT_CFG_FLAG_R5_BTCM_EN; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci if (core->loczrama) 91262306a36Sopenharmony_ci set_cfg |= PROC_BOOT_CFG_FLAG_R5_TCM_RSTBASE; 91362306a36Sopenharmony_ci else 91462306a36Sopenharmony_ci clr_cfg |= PROC_BOOT_CFG_FLAG_R5_TCM_RSTBASE; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if (cluster->mode == CLUSTER_MODE_LOCKSTEP) { 91762306a36Sopenharmony_ci /* 91862306a36Sopenharmony_ci * work around system firmware limitations to make sure both 91962306a36Sopenharmony_ci * cores are programmed symmetrically in LockStep. LockStep 92062306a36Sopenharmony_ci * and TEINIT config is only allowed with Core0. 92162306a36Sopenharmony_ci */ 92262306a36Sopenharmony_ci list_for_each_entry(temp, &cluster->cores, elem) { 92362306a36Sopenharmony_ci ret = k3_r5_core_halt(temp); 92462306a36Sopenharmony_ci if (ret) 92562306a36Sopenharmony_ci goto out; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci if (temp != core) { 92862306a36Sopenharmony_ci clr_cfg &= ~PROC_BOOT_CFG_FLAG_R5_LOCKSTEP; 92962306a36Sopenharmony_ci clr_cfg &= ~PROC_BOOT_CFG_FLAG_R5_TEINIT; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci ret = ti_sci_proc_set_config(temp->tsp, boot_vec, 93262306a36Sopenharmony_ci set_cfg, clr_cfg); 93362306a36Sopenharmony_ci if (ret) 93462306a36Sopenharmony_ci goto out; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci set_cfg = PROC_BOOT_CFG_FLAG_R5_LOCKSTEP; 93862306a36Sopenharmony_ci clr_cfg = 0; 93962306a36Sopenharmony_ci ret = ti_sci_proc_set_config(core->tsp, boot_vec, 94062306a36Sopenharmony_ci set_cfg, clr_cfg); 94162306a36Sopenharmony_ci } else { 94262306a36Sopenharmony_ci ret = k3_r5_core_halt(core); 94362306a36Sopenharmony_ci if (ret) 94462306a36Sopenharmony_ci goto out; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci ret = ti_sci_proc_set_config(core->tsp, boot_vec, 94762306a36Sopenharmony_ci set_cfg, clr_cfg); 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ciout: 95162306a36Sopenharmony_ci return ret; 95262306a36Sopenharmony_ci} 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_cistatic int k3_r5_reserved_mem_init(struct k3_r5_rproc *kproc) 95562306a36Sopenharmony_ci{ 95662306a36Sopenharmony_ci struct device *dev = kproc->dev; 95762306a36Sopenharmony_ci struct device_node *np = dev_of_node(dev); 95862306a36Sopenharmony_ci struct device_node *rmem_np; 95962306a36Sopenharmony_ci struct reserved_mem *rmem; 96062306a36Sopenharmony_ci int num_rmems; 96162306a36Sopenharmony_ci int ret, i; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci num_rmems = of_property_count_elems_of_size(np, "memory-region", 96462306a36Sopenharmony_ci sizeof(phandle)); 96562306a36Sopenharmony_ci if (num_rmems <= 0) { 96662306a36Sopenharmony_ci dev_err(dev, "device does not have reserved memory regions, ret = %d\n", 96762306a36Sopenharmony_ci num_rmems); 96862306a36Sopenharmony_ci return -EINVAL; 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci if (num_rmems < 2) { 97162306a36Sopenharmony_ci dev_err(dev, "device needs at least two memory regions to be defined, num = %d\n", 97262306a36Sopenharmony_ci num_rmems); 97362306a36Sopenharmony_ci return -EINVAL; 97462306a36Sopenharmony_ci } 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci /* use reserved memory region 0 for vring DMA allocations */ 97762306a36Sopenharmony_ci ret = of_reserved_mem_device_init_by_idx(dev, np, 0); 97862306a36Sopenharmony_ci if (ret) { 97962306a36Sopenharmony_ci dev_err(dev, "device cannot initialize DMA pool, ret = %d\n", 98062306a36Sopenharmony_ci ret); 98162306a36Sopenharmony_ci return ret; 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci num_rmems--; 98562306a36Sopenharmony_ci kproc->rmem = kcalloc(num_rmems, sizeof(*kproc->rmem), GFP_KERNEL); 98662306a36Sopenharmony_ci if (!kproc->rmem) { 98762306a36Sopenharmony_ci ret = -ENOMEM; 98862306a36Sopenharmony_ci goto release_rmem; 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci /* use remaining reserved memory regions for static carveouts */ 99262306a36Sopenharmony_ci for (i = 0; i < num_rmems; i++) { 99362306a36Sopenharmony_ci rmem_np = of_parse_phandle(np, "memory-region", i + 1); 99462306a36Sopenharmony_ci if (!rmem_np) { 99562306a36Sopenharmony_ci ret = -EINVAL; 99662306a36Sopenharmony_ci goto unmap_rmem; 99762306a36Sopenharmony_ci } 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci rmem = of_reserved_mem_lookup(rmem_np); 100062306a36Sopenharmony_ci if (!rmem) { 100162306a36Sopenharmony_ci of_node_put(rmem_np); 100262306a36Sopenharmony_ci ret = -EINVAL; 100362306a36Sopenharmony_ci goto unmap_rmem; 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci of_node_put(rmem_np); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci kproc->rmem[i].bus_addr = rmem->base; 100862306a36Sopenharmony_ci /* 100962306a36Sopenharmony_ci * R5Fs do not have an MMU, but have a Region Address Translator 101062306a36Sopenharmony_ci * (RAT) module that provides a fixed entry translation between 101162306a36Sopenharmony_ci * the 32-bit processor addresses to 64-bit bus addresses. The 101262306a36Sopenharmony_ci * RAT is programmable only by the R5F cores. Support for RAT 101362306a36Sopenharmony_ci * is currently not supported, so 64-bit address regions are not 101462306a36Sopenharmony_ci * supported. The absence of MMUs implies that the R5F device 101562306a36Sopenharmony_ci * addresses/supported memory regions are restricted to 32-bit 101662306a36Sopenharmony_ci * bus addresses, and are identical 101762306a36Sopenharmony_ci */ 101862306a36Sopenharmony_ci kproc->rmem[i].dev_addr = (u32)rmem->base; 101962306a36Sopenharmony_ci kproc->rmem[i].size = rmem->size; 102062306a36Sopenharmony_ci kproc->rmem[i].cpu_addr = ioremap_wc(rmem->base, rmem->size); 102162306a36Sopenharmony_ci if (!kproc->rmem[i].cpu_addr) { 102262306a36Sopenharmony_ci dev_err(dev, "failed to map reserved memory#%d at %pa of size %pa\n", 102362306a36Sopenharmony_ci i + 1, &rmem->base, &rmem->size); 102462306a36Sopenharmony_ci ret = -ENOMEM; 102562306a36Sopenharmony_ci goto unmap_rmem; 102662306a36Sopenharmony_ci } 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci dev_dbg(dev, "reserved memory%d: bus addr %pa size 0x%zx va %pK da 0x%x\n", 102962306a36Sopenharmony_ci i + 1, &kproc->rmem[i].bus_addr, 103062306a36Sopenharmony_ci kproc->rmem[i].size, kproc->rmem[i].cpu_addr, 103162306a36Sopenharmony_ci kproc->rmem[i].dev_addr); 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci kproc->num_rmems = num_rmems; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci return 0; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ciunmap_rmem: 103862306a36Sopenharmony_ci for (i--; i >= 0; i--) 103962306a36Sopenharmony_ci iounmap(kproc->rmem[i].cpu_addr); 104062306a36Sopenharmony_ci kfree(kproc->rmem); 104162306a36Sopenharmony_cirelease_rmem: 104262306a36Sopenharmony_ci of_reserved_mem_device_release(dev); 104362306a36Sopenharmony_ci return ret; 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cistatic void k3_r5_reserved_mem_exit(struct k3_r5_rproc *kproc) 104762306a36Sopenharmony_ci{ 104862306a36Sopenharmony_ci int i; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci for (i = 0; i < kproc->num_rmems; i++) 105162306a36Sopenharmony_ci iounmap(kproc->rmem[i].cpu_addr); 105262306a36Sopenharmony_ci kfree(kproc->rmem); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci of_reserved_mem_device_release(kproc->dev); 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci/* 105862306a36Sopenharmony_ci * Each R5F core within a typical R5FSS instance has a total of 64 KB of TCMs, 105962306a36Sopenharmony_ci * split equally into two 32 KB banks between ATCM and BTCM. The TCMs from both 106062306a36Sopenharmony_ci * cores are usable in Split-mode, but only the Core0 TCMs can be used in 106162306a36Sopenharmony_ci * LockStep-mode. The newer revisions of the R5FSS IP maximizes these TCMs by 106262306a36Sopenharmony_ci * leveraging the Core1 TCMs as well in certain modes where they would have 106362306a36Sopenharmony_ci * otherwise been unusable (Eg: LockStep-mode on J7200 SoCs, Single-CPU mode on 106462306a36Sopenharmony_ci * AM64x SoCs). This is done by making a Core1 TCM visible immediately after the 106562306a36Sopenharmony_ci * corresponding Core0 TCM. The SoC memory map uses the larger 64 KB sizes for 106662306a36Sopenharmony_ci * the Core0 TCMs, and the dts representation reflects this increased size on 106762306a36Sopenharmony_ci * supported SoCs. The Core0 TCM sizes therefore have to be adjusted to only 106862306a36Sopenharmony_ci * half the original size in Split mode. 106962306a36Sopenharmony_ci */ 107062306a36Sopenharmony_cistatic void k3_r5_adjust_tcm_sizes(struct k3_r5_rproc *kproc) 107162306a36Sopenharmony_ci{ 107262306a36Sopenharmony_ci struct k3_r5_cluster *cluster = kproc->cluster; 107362306a36Sopenharmony_ci struct k3_r5_core *core = kproc->core; 107462306a36Sopenharmony_ci struct device *cdev = core->dev; 107562306a36Sopenharmony_ci struct k3_r5_core *core0; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci if (cluster->mode == CLUSTER_MODE_LOCKSTEP || 107862306a36Sopenharmony_ci cluster->mode == CLUSTER_MODE_SINGLECPU || 107962306a36Sopenharmony_ci cluster->mode == CLUSTER_MODE_SINGLECORE || 108062306a36Sopenharmony_ci !cluster->soc_data->tcm_is_double) 108162306a36Sopenharmony_ci return; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci core0 = list_first_entry(&cluster->cores, struct k3_r5_core, elem); 108462306a36Sopenharmony_ci if (core == core0) { 108562306a36Sopenharmony_ci WARN_ON(core->mem[0].size != SZ_64K); 108662306a36Sopenharmony_ci WARN_ON(core->mem[1].size != SZ_64K); 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci core->mem[0].size /= 2; 108962306a36Sopenharmony_ci core->mem[1].size /= 2; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci dev_dbg(cdev, "adjusted TCM sizes, ATCM = 0x%zx BTCM = 0x%zx\n", 109262306a36Sopenharmony_ci core->mem[0].size, core->mem[1].size); 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci/* 109762306a36Sopenharmony_ci * This function checks and configures a R5F core for IPC-only or remoteproc 109862306a36Sopenharmony_ci * mode. The driver is configured to be in IPC-only mode for a R5F core when 109962306a36Sopenharmony_ci * the core has been loaded and started by a bootloader. The IPC-only mode is 110062306a36Sopenharmony_ci * detected by querying the System Firmware for reset, power on and halt status 110162306a36Sopenharmony_ci * and ensuring that the core is running. Any incomplete steps at bootloader 110262306a36Sopenharmony_ci * are validated and errored out. 110362306a36Sopenharmony_ci * 110462306a36Sopenharmony_ci * In IPC-only mode, the driver state flags for ATCM, BTCM and LOCZRAMA settings 110562306a36Sopenharmony_ci * and cluster mode parsed originally from kernel DT are updated to reflect the 110662306a36Sopenharmony_ci * actual values configured by bootloader. The driver internal device memory 110762306a36Sopenharmony_ci * addresses for TCMs are also updated. 110862306a36Sopenharmony_ci */ 110962306a36Sopenharmony_cistatic int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc) 111062306a36Sopenharmony_ci{ 111162306a36Sopenharmony_ci struct k3_r5_cluster *cluster = kproc->cluster; 111262306a36Sopenharmony_ci struct k3_r5_core *core = kproc->core; 111362306a36Sopenharmony_ci struct device *cdev = core->dev; 111462306a36Sopenharmony_ci bool r_state = false, c_state = false, lockstep_en = false, single_cpu = false; 111562306a36Sopenharmony_ci u32 ctrl = 0, cfg = 0, stat = 0, halted = 0; 111662306a36Sopenharmony_ci u64 boot_vec = 0; 111762306a36Sopenharmony_ci u32 atcm_enable, btcm_enable, loczrama; 111862306a36Sopenharmony_ci struct k3_r5_core *core0; 111962306a36Sopenharmony_ci enum cluster_mode mode = cluster->mode; 112062306a36Sopenharmony_ci int ret; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci core0 = list_first_entry(&cluster->cores, struct k3_r5_core, elem); 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci ret = core->ti_sci->ops.dev_ops.is_on(core->ti_sci, core->ti_sci_id, 112562306a36Sopenharmony_ci &r_state, &c_state); 112662306a36Sopenharmony_ci if (ret) { 112762306a36Sopenharmony_ci dev_err(cdev, "failed to get initial state, mode cannot be determined, ret = %d\n", 112862306a36Sopenharmony_ci ret); 112962306a36Sopenharmony_ci return ret; 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci if (r_state != c_state) { 113262306a36Sopenharmony_ci dev_warn(cdev, "R5F core may have been powered on by a different host, programmed state (%d) != actual state (%d)\n", 113362306a36Sopenharmony_ci r_state, c_state); 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci ret = reset_control_status(core->reset); 113762306a36Sopenharmony_ci if (ret < 0) { 113862306a36Sopenharmony_ci dev_err(cdev, "failed to get initial local reset status, ret = %d\n", 113962306a36Sopenharmony_ci ret); 114062306a36Sopenharmony_ci return ret; 114162306a36Sopenharmony_ci } 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci ret = ti_sci_proc_get_status(core->tsp, &boot_vec, &cfg, &ctrl, 114462306a36Sopenharmony_ci &stat); 114562306a36Sopenharmony_ci if (ret < 0) { 114662306a36Sopenharmony_ci dev_err(cdev, "failed to get initial processor status, ret = %d\n", 114762306a36Sopenharmony_ci ret); 114862306a36Sopenharmony_ci return ret; 114962306a36Sopenharmony_ci } 115062306a36Sopenharmony_ci atcm_enable = cfg & PROC_BOOT_CFG_FLAG_R5_ATCM_EN ? 1 : 0; 115162306a36Sopenharmony_ci btcm_enable = cfg & PROC_BOOT_CFG_FLAG_R5_BTCM_EN ? 1 : 0; 115262306a36Sopenharmony_ci loczrama = cfg & PROC_BOOT_CFG_FLAG_R5_TCM_RSTBASE ? 1 : 0; 115362306a36Sopenharmony_ci single_cpu = cfg & PROC_BOOT_CFG_FLAG_R5_SINGLE_CORE ? 1 : 0; 115462306a36Sopenharmony_ci lockstep_en = cfg & PROC_BOOT_CFG_FLAG_R5_LOCKSTEP ? 1 : 0; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci if (single_cpu && mode != CLUSTER_MODE_SINGLECORE) 115762306a36Sopenharmony_ci mode = CLUSTER_MODE_SINGLECPU; 115862306a36Sopenharmony_ci if (lockstep_en) 115962306a36Sopenharmony_ci mode = CLUSTER_MODE_LOCKSTEP; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci halted = ctrl & PROC_BOOT_CTRL_FLAG_R5_CORE_HALT; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci /* 116462306a36Sopenharmony_ci * IPC-only mode detection requires both local and module resets to 116562306a36Sopenharmony_ci * be deasserted and R5F core to be unhalted. Local reset status is 116662306a36Sopenharmony_ci * irrelevant if module reset is asserted (POR value has local reset 116762306a36Sopenharmony_ci * deasserted), and is deemed as remoteproc mode 116862306a36Sopenharmony_ci */ 116962306a36Sopenharmony_ci if (c_state && !ret && !halted) { 117062306a36Sopenharmony_ci dev_info(cdev, "configured R5F for IPC-only mode\n"); 117162306a36Sopenharmony_ci kproc->rproc->state = RPROC_DETACHED; 117262306a36Sopenharmony_ci ret = 1; 117362306a36Sopenharmony_ci /* override rproc ops with only required IPC-only mode ops */ 117462306a36Sopenharmony_ci kproc->rproc->ops->prepare = NULL; 117562306a36Sopenharmony_ci kproc->rproc->ops->unprepare = NULL; 117662306a36Sopenharmony_ci kproc->rproc->ops->start = NULL; 117762306a36Sopenharmony_ci kproc->rproc->ops->stop = NULL; 117862306a36Sopenharmony_ci kproc->rproc->ops->attach = k3_r5_rproc_attach; 117962306a36Sopenharmony_ci kproc->rproc->ops->detach = k3_r5_rproc_detach; 118062306a36Sopenharmony_ci kproc->rproc->ops->get_loaded_rsc_table = 118162306a36Sopenharmony_ci k3_r5_get_loaded_rsc_table; 118262306a36Sopenharmony_ci } else if (!c_state) { 118362306a36Sopenharmony_ci dev_info(cdev, "configured R5F for remoteproc mode\n"); 118462306a36Sopenharmony_ci ret = 0; 118562306a36Sopenharmony_ci } else { 118662306a36Sopenharmony_ci dev_err(cdev, "mismatched mode: local_reset = %s, module_reset = %s, core_state = %s\n", 118762306a36Sopenharmony_ci !ret ? "deasserted" : "asserted", 118862306a36Sopenharmony_ci c_state ? "deasserted" : "asserted", 118962306a36Sopenharmony_ci halted ? "halted" : "unhalted"); 119062306a36Sopenharmony_ci ret = -EINVAL; 119162306a36Sopenharmony_ci } 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci /* fixup TCMs, cluster & core flags to actual values in IPC-only mode */ 119462306a36Sopenharmony_ci if (ret > 0) { 119562306a36Sopenharmony_ci if (core == core0) 119662306a36Sopenharmony_ci cluster->mode = mode; 119762306a36Sopenharmony_ci core->atcm_enable = atcm_enable; 119862306a36Sopenharmony_ci core->btcm_enable = btcm_enable; 119962306a36Sopenharmony_ci core->loczrama = loczrama; 120062306a36Sopenharmony_ci core->mem[0].dev_addr = loczrama ? 0 : K3_R5_TCM_DEV_ADDR; 120162306a36Sopenharmony_ci core->mem[1].dev_addr = loczrama ? K3_R5_TCM_DEV_ADDR : 0; 120262306a36Sopenharmony_ci } 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci return ret; 120562306a36Sopenharmony_ci} 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_cistatic int k3_r5_cluster_rproc_init(struct platform_device *pdev) 120862306a36Sopenharmony_ci{ 120962306a36Sopenharmony_ci struct k3_r5_cluster *cluster = platform_get_drvdata(pdev); 121062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 121162306a36Sopenharmony_ci struct k3_r5_rproc *kproc; 121262306a36Sopenharmony_ci struct k3_r5_core *core, *core1; 121362306a36Sopenharmony_ci struct device *cdev; 121462306a36Sopenharmony_ci const char *fw_name; 121562306a36Sopenharmony_ci struct rproc *rproc; 121662306a36Sopenharmony_ci int ret, ret1; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci core1 = list_last_entry(&cluster->cores, struct k3_r5_core, elem); 121962306a36Sopenharmony_ci list_for_each_entry(core, &cluster->cores, elem) { 122062306a36Sopenharmony_ci cdev = core->dev; 122162306a36Sopenharmony_ci ret = rproc_of_parse_firmware(cdev, 0, &fw_name); 122262306a36Sopenharmony_ci if (ret) { 122362306a36Sopenharmony_ci dev_err(dev, "failed to parse firmware-name property, ret = %d\n", 122462306a36Sopenharmony_ci ret); 122562306a36Sopenharmony_ci goto out; 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci rproc = rproc_alloc(cdev, dev_name(cdev), &k3_r5_rproc_ops, 122962306a36Sopenharmony_ci fw_name, sizeof(*kproc)); 123062306a36Sopenharmony_ci if (!rproc) { 123162306a36Sopenharmony_ci ret = -ENOMEM; 123262306a36Sopenharmony_ci goto out; 123362306a36Sopenharmony_ci } 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci /* K3 R5s have a Region Address Translator (RAT) but no MMU */ 123662306a36Sopenharmony_ci rproc->has_iommu = false; 123762306a36Sopenharmony_ci /* error recovery is not supported at present */ 123862306a36Sopenharmony_ci rproc->recovery_disabled = true; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci kproc = rproc->priv; 124162306a36Sopenharmony_ci kproc->cluster = cluster; 124262306a36Sopenharmony_ci kproc->core = core; 124362306a36Sopenharmony_ci kproc->dev = cdev; 124462306a36Sopenharmony_ci kproc->rproc = rproc; 124562306a36Sopenharmony_ci core->rproc = rproc; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci ret = k3_r5_rproc_configure_mode(kproc); 124862306a36Sopenharmony_ci if (ret < 0) 124962306a36Sopenharmony_ci goto err_config; 125062306a36Sopenharmony_ci if (ret) 125162306a36Sopenharmony_ci goto init_rmem; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci ret = k3_r5_rproc_configure(kproc); 125462306a36Sopenharmony_ci if (ret) { 125562306a36Sopenharmony_ci dev_err(dev, "initial configure failed, ret = %d\n", 125662306a36Sopenharmony_ci ret); 125762306a36Sopenharmony_ci goto err_config; 125862306a36Sopenharmony_ci } 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ciinit_rmem: 126162306a36Sopenharmony_ci k3_r5_adjust_tcm_sizes(kproc); 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci ret = k3_r5_reserved_mem_init(kproc); 126462306a36Sopenharmony_ci if (ret) { 126562306a36Sopenharmony_ci dev_err(dev, "reserved memory init failed, ret = %d\n", 126662306a36Sopenharmony_ci ret); 126762306a36Sopenharmony_ci goto err_config; 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci ret = rproc_add(rproc); 127162306a36Sopenharmony_ci if (ret) { 127262306a36Sopenharmony_ci dev_err(dev, "rproc_add failed, ret = %d\n", ret); 127362306a36Sopenharmony_ci goto err_add; 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci /* create only one rproc in lockstep, single-cpu or 127762306a36Sopenharmony_ci * single core mode 127862306a36Sopenharmony_ci */ 127962306a36Sopenharmony_ci if (cluster->mode == CLUSTER_MODE_LOCKSTEP || 128062306a36Sopenharmony_ci cluster->mode == CLUSTER_MODE_SINGLECPU || 128162306a36Sopenharmony_ci cluster->mode == CLUSTER_MODE_SINGLECORE) 128262306a36Sopenharmony_ci break; 128362306a36Sopenharmony_ci } 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci return 0; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_cierr_split: 128862306a36Sopenharmony_ci if (rproc->state == RPROC_ATTACHED) { 128962306a36Sopenharmony_ci ret1 = rproc_detach(rproc); 129062306a36Sopenharmony_ci if (ret1) { 129162306a36Sopenharmony_ci dev_err(kproc->dev, "failed to detach rproc, ret = %d\n", 129262306a36Sopenharmony_ci ret1); 129362306a36Sopenharmony_ci return ret1; 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci rproc_del(rproc); 129862306a36Sopenharmony_cierr_add: 129962306a36Sopenharmony_ci k3_r5_reserved_mem_exit(kproc); 130062306a36Sopenharmony_cierr_config: 130162306a36Sopenharmony_ci rproc_free(rproc); 130262306a36Sopenharmony_ci core->rproc = NULL; 130362306a36Sopenharmony_ciout: 130462306a36Sopenharmony_ci /* undo core0 upon any failures on core1 in split-mode */ 130562306a36Sopenharmony_ci if (cluster->mode == CLUSTER_MODE_SPLIT && core == core1) { 130662306a36Sopenharmony_ci core = list_prev_entry(core, elem); 130762306a36Sopenharmony_ci rproc = core->rproc; 130862306a36Sopenharmony_ci kproc = rproc->priv; 130962306a36Sopenharmony_ci goto err_split; 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci return ret; 131262306a36Sopenharmony_ci} 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_cistatic void k3_r5_cluster_rproc_exit(void *data) 131562306a36Sopenharmony_ci{ 131662306a36Sopenharmony_ci struct k3_r5_cluster *cluster = platform_get_drvdata(data); 131762306a36Sopenharmony_ci struct k3_r5_rproc *kproc; 131862306a36Sopenharmony_ci struct k3_r5_core *core; 131962306a36Sopenharmony_ci struct rproc *rproc; 132062306a36Sopenharmony_ci int ret; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci /* 132362306a36Sopenharmony_ci * lockstep mode and single-cpu modes have only one rproc associated 132462306a36Sopenharmony_ci * with first core, whereas split-mode has two rprocs associated with 132562306a36Sopenharmony_ci * each core, and requires that core1 be powered down first 132662306a36Sopenharmony_ci */ 132762306a36Sopenharmony_ci core = (cluster->mode == CLUSTER_MODE_LOCKSTEP || 132862306a36Sopenharmony_ci cluster->mode == CLUSTER_MODE_SINGLECPU) ? 132962306a36Sopenharmony_ci list_first_entry(&cluster->cores, struct k3_r5_core, elem) : 133062306a36Sopenharmony_ci list_last_entry(&cluster->cores, struct k3_r5_core, elem); 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci list_for_each_entry_from_reverse(core, &cluster->cores, elem) { 133362306a36Sopenharmony_ci rproc = core->rproc; 133462306a36Sopenharmony_ci kproc = rproc->priv; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci if (rproc->state == RPROC_ATTACHED) { 133762306a36Sopenharmony_ci ret = rproc_detach(rproc); 133862306a36Sopenharmony_ci if (ret) { 133962306a36Sopenharmony_ci dev_err(kproc->dev, "failed to detach rproc, ret = %d\n", ret); 134062306a36Sopenharmony_ci return; 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci } 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci rproc_del(rproc); 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci k3_r5_reserved_mem_exit(kproc); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci rproc_free(rproc); 134962306a36Sopenharmony_ci core->rproc = NULL; 135062306a36Sopenharmony_ci } 135162306a36Sopenharmony_ci} 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_cistatic int k3_r5_core_of_get_internal_memories(struct platform_device *pdev, 135462306a36Sopenharmony_ci struct k3_r5_core *core) 135562306a36Sopenharmony_ci{ 135662306a36Sopenharmony_ci static const char * const mem_names[] = {"atcm", "btcm"}; 135762306a36Sopenharmony_ci struct device *dev = &pdev->dev; 135862306a36Sopenharmony_ci struct resource *res; 135962306a36Sopenharmony_ci int num_mems; 136062306a36Sopenharmony_ci int i; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci num_mems = ARRAY_SIZE(mem_names); 136362306a36Sopenharmony_ci core->mem = devm_kcalloc(dev, num_mems, sizeof(*core->mem), GFP_KERNEL); 136462306a36Sopenharmony_ci if (!core->mem) 136562306a36Sopenharmony_ci return -ENOMEM; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci for (i = 0; i < num_mems; i++) { 136862306a36Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 136962306a36Sopenharmony_ci mem_names[i]); 137062306a36Sopenharmony_ci if (!res) { 137162306a36Sopenharmony_ci dev_err(dev, "found no memory resource for %s\n", 137262306a36Sopenharmony_ci mem_names[i]); 137362306a36Sopenharmony_ci return -EINVAL; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci if (!devm_request_mem_region(dev, res->start, 137662306a36Sopenharmony_ci resource_size(res), 137762306a36Sopenharmony_ci dev_name(dev))) { 137862306a36Sopenharmony_ci dev_err(dev, "could not request %s region for resource\n", 137962306a36Sopenharmony_ci mem_names[i]); 138062306a36Sopenharmony_ci return -EBUSY; 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci /* 138462306a36Sopenharmony_ci * TCMs are designed in general to support RAM-like backing 138562306a36Sopenharmony_ci * memories. So, map these as Normal Non-Cached memories. This 138662306a36Sopenharmony_ci * also avoids/fixes any potential alignment faults due to 138762306a36Sopenharmony_ci * unaligned data accesses when using memcpy() or memset() 138862306a36Sopenharmony_ci * functions (normally seen with device type memory). 138962306a36Sopenharmony_ci */ 139062306a36Sopenharmony_ci core->mem[i].cpu_addr = devm_ioremap_wc(dev, res->start, 139162306a36Sopenharmony_ci resource_size(res)); 139262306a36Sopenharmony_ci if (!core->mem[i].cpu_addr) { 139362306a36Sopenharmony_ci dev_err(dev, "failed to map %s memory\n", mem_names[i]); 139462306a36Sopenharmony_ci return -ENOMEM; 139562306a36Sopenharmony_ci } 139662306a36Sopenharmony_ci core->mem[i].bus_addr = res->start; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci /* 139962306a36Sopenharmony_ci * TODO: 140062306a36Sopenharmony_ci * The R5F cores can place ATCM & BTCM anywhere in its address 140162306a36Sopenharmony_ci * based on the corresponding Region Registers in the System 140262306a36Sopenharmony_ci * Control coprocessor. For now, place ATCM and BTCM at 140362306a36Sopenharmony_ci * addresses 0 and 0x41010000 (same as the bus address on AM65x 140462306a36Sopenharmony_ci * SoCs) based on loczrama setting 140562306a36Sopenharmony_ci */ 140662306a36Sopenharmony_ci if (!strcmp(mem_names[i], "atcm")) { 140762306a36Sopenharmony_ci core->mem[i].dev_addr = core->loczrama ? 140862306a36Sopenharmony_ci 0 : K3_R5_TCM_DEV_ADDR; 140962306a36Sopenharmony_ci } else { 141062306a36Sopenharmony_ci core->mem[i].dev_addr = core->loczrama ? 141162306a36Sopenharmony_ci K3_R5_TCM_DEV_ADDR : 0; 141262306a36Sopenharmony_ci } 141362306a36Sopenharmony_ci core->mem[i].size = resource_size(res); 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci dev_dbg(dev, "memory %5s: bus addr %pa size 0x%zx va %pK da 0x%x\n", 141662306a36Sopenharmony_ci mem_names[i], &core->mem[i].bus_addr, 141762306a36Sopenharmony_ci core->mem[i].size, core->mem[i].cpu_addr, 141862306a36Sopenharmony_ci core->mem[i].dev_addr); 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci core->num_mems = num_mems; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci return 0; 142362306a36Sopenharmony_ci} 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_cistatic int k3_r5_core_of_get_sram_memories(struct platform_device *pdev, 142662306a36Sopenharmony_ci struct k3_r5_core *core) 142762306a36Sopenharmony_ci{ 142862306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 142962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 143062306a36Sopenharmony_ci struct device_node *sram_np; 143162306a36Sopenharmony_ci struct resource res; 143262306a36Sopenharmony_ci int num_sram; 143362306a36Sopenharmony_ci int i, ret; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci num_sram = of_property_count_elems_of_size(np, "sram", sizeof(phandle)); 143662306a36Sopenharmony_ci if (num_sram <= 0) { 143762306a36Sopenharmony_ci dev_dbg(dev, "device does not use reserved on-chip memories, num_sram = %d\n", 143862306a36Sopenharmony_ci num_sram); 143962306a36Sopenharmony_ci return 0; 144062306a36Sopenharmony_ci } 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci core->sram = devm_kcalloc(dev, num_sram, sizeof(*core->sram), GFP_KERNEL); 144362306a36Sopenharmony_ci if (!core->sram) 144462306a36Sopenharmony_ci return -ENOMEM; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci for (i = 0; i < num_sram; i++) { 144762306a36Sopenharmony_ci sram_np = of_parse_phandle(np, "sram", i); 144862306a36Sopenharmony_ci if (!sram_np) 144962306a36Sopenharmony_ci return -EINVAL; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci if (!of_device_is_available(sram_np)) { 145262306a36Sopenharmony_ci of_node_put(sram_np); 145362306a36Sopenharmony_ci return -EINVAL; 145462306a36Sopenharmony_ci } 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci ret = of_address_to_resource(sram_np, 0, &res); 145762306a36Sopenharmony_ci of_node_put(sram_np); 145862306a36Sopenharmony_ci if (ret) 145962306a36Sopenharmony_ci return -EINVAL; 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci core->sram[i].bus_addr = res.start; 146262306a36Sopenharmony_ci core->sram[i].dev_addr = res.start; 146362306a36Sopenharmony_ci core->sram[i].size = resource_size(&res); 146462306a36Sopenharmony_ci core->sram[i].cpu_addr = devm_ioremap_wc(dev, res.start, 146562306a36Sopenharmony_ci resource_size(&res)); 146662306a36Sopenharmony_ci if (!core->sram[i].cpu_addr) { 146762306a36Sopenharmony_ci dev_err(dev, "failed to parse and map sram%d memory at %pad\n", 146862306a36Sopenharmony_ci i, &res.start); 146962306a36Sopenharmony_ci return -ENOMEM; 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci dev_dbg(dev, "memory sram%d: bus addr %pa size 0x%zx va %pK da 0x%x\n", 147362306a36Sopenharmony_ci i, &core->sram[i].bus_addr, 147462306a36Sopenharmony_ci core->sram[i].size, core->sram[i].cpu_addr, 147562306a36Sopenharmony_ci core->sram[i].dev_addr); 147662306a36Sopenharmony_ci } 147762306a36Sopenharmony_ci core->num_sram = num_sram; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci return 0; 148062306a36Sopenharmony_ci} 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_cistatic 148362306a36Sopenharmony_cistruct ti_sci_proc *k3_r5_core_of_get_tsp(struct device *dev, 148462306a36Sopenharmony_ci const struct ti_sci_handle *sci) 148562306a36Sopenharmony_ci{ 148662306a36Sopenharmony_ci struct ti_sci_proc *tsp; 148762306a36Sopenharmony_ci u32 temp[2]; 148862306a36Sopenharmony_ci int ret; 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci ret = of_property_read_u32_array(dev_of_node(dev), "ti,sci-proc-ids", 149162306a36Sopenharmony_ci temp, 2); 149262306a36Sopenharmony_ci if (ret < 0) 149362306a36Sopenharmony_ci return ERR_PTR(ret); 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci tsp = devm_kzalloc(dev, sizeof(*tsp), GFP_KERNEL); 149662306a36Sopenharmony_ci if (!tsp) 149762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci tsp->dev = dev; 150062306a36Sopenharmony_ci tsp->sci = sci; 150162306a36Sopenharmony_ci tsp->ops = &sci->ops.proc_ops; 150262306a36Sopenharmony_ci tsp->proc_id = temp[0]; 150362306a36Sopenharmony_ci tsp->host_id = temp[1]; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci return tsp; 150662306a36Sopenharmony_ci} 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_cistatic int k3_r5_core_of_init(struct platform_device *pdev) 150962306a36Sopenharmony_ci{ 151062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 151162306a36Sopenharmony_ci struct device_node *np = dev_of_node(dev); 151262306a36Sopenharmony_ci struct k3_r5_core *core; 151362306a36Sopenharmony_ci int ret; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci if (!devres_open_group(dev, k3_r5_core_of_init, GFP_KERNEL)) 151662306a36Sopenharmony_ci return -ENOMEM; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL); 151962306a36Sopenharmony_ci if (!core) { 152062306a36Sopenharmony_ci ret = -ENOMEM; 152162306a36Sopenharmony_ci goto err; 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci core->dev = dev; 152562306a36Sopenharmony_ci /* 152662306a36Sopenharmony_ci * Use SoC Power-on-Reset values as default if no DT properties are 152762306a36Sopenharmony_ci * used to dictate the TCM configurations 152862306a36Sopenharmony_ci */ 152962306a36Sopenharmony_ci core->atcm_enable = 0; 153062306a36Sopenharmony_ci core->btcm_enable = 1; 153162306a36Sopenharmony_ci core->loczrama = 1; 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci ret = of_property_read_u32(np, "ti,atcm-enable", &core->atcm_enable); 153462306a36Sopenharmony_ci if (ret < 0 && ret != -EINVAL) { 153562306a36Sopenharmony_ci dev_err(dev, "invalid format for ti,atcm-enable, ret = %d\n", 153662306a36Sopenharmony_ci ret); 153762306a36Sopenharmony_ci goto err; 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci ret = of_property_read_u32(np, "ti,btcm-enable", &core->btcm_enable); 154162306a36Sopenharmony_ci if (ret < 0 && ret != -EINVAL) { 154262306a36Sopenharmony_ci dev_err(dev, "invalid format for ti,btcm-enable, ret = %d\n", 154362306a36Sopenharmony_ci ret); 154462306a36Sopenharmony_ci goto err; 154562306a36Sopenharmony_ci } 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci ret = of_property_read_u32(np, "ti,loczrama", &core->loczrama); 154862306a36Sopenharmony_ci if (ret < 0 && ret != -EINVAL) { 154962306a36Sopenharmony_ci dev_err(dev, "invalid format for ti,loczrama, ret = %d\n", ret); 155062306a36Sopenharmony_ci goto err; 155162306a36Sopenharmony_ci } 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci core->ti_sci = devm_ti_sci_get_by_phandle(dev, "ti,sci"); 155462306a36Sopenharmony_ci if (IS_ERR(core->ti_sci)) { 155562306a36Sopenharmony_ci ret = PTR_ERR(core->ti_sci); 155662306a36Sopenharmony_ci if (ret != -EPROBE_DEFER) { 155762306a36Sopenharmony_ci dev_err(dev, "failed to get ti-sci handle, ret = %d\n", 155862306a36Sopenharmony_ci ret); 155962306a36Sopenharmony_ci } 156062306a36Sopenharmony_ci core->ti_sci = NULL; 156162306a36Sopenharmony_ci goto err; 156262306a36Sopenharmony_ci } 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci ret = of_property_read_u32(np, "ti,sci-dev-id", &core->ti_sci_id); 156562306a36Sopenharmony_ci if (ret) { 156662306a36Sopenharmony_ci dev_err(dev, "missing 'ti,sci-dev-id' property\n"); 156762306a36Sopenharmony_ci goto err; 156862306a36Sopenharmony_ci } 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci core->reset = devm_reset_control_get_exclusive(dev, NULL); 157162306a36Sopenharmony_ci if (IS_ERR_OR_NULL(core->reset)) { 157262306a36Sopenharmony_ci ret = PTR_ERR_OR_ZERO(core->reset); 157362306a36Sopenharmony_ci if (!ret) 157462306a36Sopenharmony_ci ret = -ENODEV; 157562306a36Sopenharmony_ci if (ret != -EPROBE_DEFER) { 157662306a36Sopenharmony_ci dev_err(dev, "failed to get reset handle, ret = %d\n", 157762306a36Sopenharmony_ci ret); 157862306a36Sopenharmony_ci } 157962306a36Sopenharmony_ci goto err; 158062306a36Sopenharmony_ci } 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci core->tsp = k3_r5_core_of_get_tsp(dev, core->ti_sci); 158362306a36Sopenharmony_ci if (IS_ERR(core->tsp)) { 158462306a36Sopenharmony_ci ret = PTR_ERR(core->tsp); 158562306a36Sopenharmony_ci dev_err(dev, "failed to construct ti-sci proc control, ret = %d\n", 158662306a36Sopenharmony_ci ret); 158762306a36Sopenharmony_ci goto err; 158862306a36Sopenharmony_ci } 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci ret = k3_r5_core_of_get_internal_memories(pdev, core); 159162306a36Sopenharmony_ci if (ret) { 159262306a36Sopenharmony_ci dev_err(dev, "failed to get internal memories, ret = %d\n", 159362306a36Sopenharmony_ci ret); 159462306a36Sopenharmony_ci goto err; 159562306a36Sopenharmony_ci } 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci ret = k3_r5_core_of_get_sram_memories(pdev, core); 159862306a36Sopenharmony_ci if (ret) { 159962306a36Sopenharmony_ci dev_err(dev, "failed to get sram memories, ret = %d\n", ret); 160062306a36Sopenharmony_ci goto err; 160162306a36Sopenharmony_ci } 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci ret = ti_sci_proc_request(core->tsp); 160462306a36Sopenharmony_ci if (ret < 0) { 160562306a36Sopenharmony_ci dev_err(dev, "ti_sci_proc_request failed, ret = %d\n", ret); 160662306a36Sopenharmony_ci goto err; 160762306a36Sopenharmony_ci } 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci platform_set_drvdata(pdev, core); 161062306a36Sopenharmony_ci devres_close_group(dev, k3_r5_core_of_init); 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci return 0; 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_cierr: 161562306a36Sopenharmony_ci devres_release_group(dev, k3_r5_core_of_init); 161662306a36Sopenharmony_ci return ret; 161762306a36Sopenharmony_ci} 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci/* 162062306a36Sopenharmony_ci * free the resources explicitly since driver model is not being used 162162306a36Sopenharmony_ci * for the child R5F devices 162262306a36Sopenharmony_ci */ 162362306a36Sopenharmony_cistatic void k3_r5_core_of_exit(struct platform_device *pdev) 162462306a36Sopenharmony_ci{ 162562306a36Sopenharmony_ci struct k3_r5_core *core = platform_get_drvdata(pdev); 162662306a36Sopenharmony_ci struct device *dev = &pdev->dev; 162762306a36Sopenharmony_ci int ret; 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci ret = ti_sci_proc_release(core->tsp); 163062306a36Sopenharmony_ci if (ret) 163162306a36Sopenharmony_ci dev_err(dev, "failed to release proc, ret = %d\n", ret); 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci platform_set_drvdata(pdev, NULL); 163462306a36Sopenharmony_ci devres_release_group(dev, k3_r5_core_of_init); 163562306a36Sopenharmony_ci} 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_cistatic void k3_r5_cluster_of_exit(void *data) 163862306a36Sopenharmony_ci{ 163962306a36Sopenharmony_ci struct k3_r5_cluster *cluster = platform_get_drvdata(data); 164062306a36Sopenharmony_ci struct platform_device *cpdev; 164162306a36Sopenharmony_ci struct k3_r5_core *core, *temp; 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci list_for_each_entry_safe_reverse(core, temp, &cluster->cores, elem) { 164462306a36Sopenharmony_ci list_del(&core->elem); 164562306a36Sopenharmony_ci cpdev = to_platform_device(core->dev); 164662306a36Sopenharmony_ci k3_r5_core_of_exit(cpdev); 164762306a36Sopenharmony_ci } 164862306a36Sopenharmony_ci} 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_cistatic int k3_r5_cluster_of_init(struct platform_device *pdev) 165162306a36Sopenharmony_ci{ 165262306a36Sopenharmony_ci struct k3_r5_cluster *cluster = platform_get_drvdata(pdev); 165362306a36Sopenharmony_ci struct device *dev = &pdev->dev; 165462306a36Sopenharmony_ci struct device_node *np = dev_of_node(dev); 165562306a36Sopenharmony_ci struct platform_device *cpdev; 165662306a36Sopenharmony_ci struct device_node *child; 165762306a36Sopenharmony_ci struct k3_r5_core *core; 165862306a36Sopenharmony_ci int ret; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci for_each_available_child_of_node(np, child) { 166162306a36Sopenharmony_ci cpdev = of_find_device_by_node(child); 166262306a36Sopenharmony_ci if (!cpdev) { 166362306a36Sopenharmony_ci ret = -ENODEV; 166462306a36Sopenharmony_ci dev_err(dev, "could not get R5 core platform device\n"); 166562306a36Sopenharmony_ci of_node_put(child); 166662306a36Sopenharmony_ci goto fail; 166762306a36Sopenharmony_ci } 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci ret = k3_r5_core_of_init(cpdev); 167062306a36Sopenharmony_ci if (ret) { 167162306a36Sopenharmony_ci dev_err(dev, "k3_r5_core_of_init failed, ret = %d\n", 167262306a36Sopenharmony_ci ret); 167362306a36Sopenharmony_ci put_device(&cpdev->dev); 167462306a36Sopenharmony_ci of_node_put(child); 167562306a36Sopenharmony_ci goto fail; 167662306a36Sopenharmony_ci } 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci core = platform_get_drvdata(cpdev); 167962306a36Sopenharmony_ci put_device(&cpdev->dev); 168062306a36Sopenharmony_ci list_add_tail(&core->elem, &cluster->cores); 168162306a36Sopenharmony_ci } 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci return 0; 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_cifail: 168662306a36Sopenharmony_ci k3_r5_cluster_of_exit(pdev); 168762306a36Sopenharmony_ci return ret; 168862306a36Sopenharmony_ci} 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_cistatic int k3_r5_probe(struct platform_device *pdev) 169162306a36Sopenharmony_ci{ 169262306a36Sopenharmony_ci struct device *dev = &pdev->dev; 169362306a36Sopenharmony_ci struct device_node *np = dev_of_node(dev); 169462306a36Sopenharmony_ci struct k3_r5_cluster *cluster; 169562306a36Sopenharmony_ci const struct k3_r5_soc_data *data; 169662306a36Sopenharmony_ci int ret; 169762306a36Sopenharmony_ci int num_cores; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci data = of_device_get_match_data(&pdev->dev); 170062306a36Sopenharmony_ci if (!data) { 170162306a36Sopenharmony_ci dev_err(dev, "SoC-specific data is not defined\n"); 170262306a36Sopenharmony_ci return -ENODEV; 170362306a36Sopenharmony_ci } 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci cluster = devm_kzalloc(dev, sizeof(*cluster), GFP_KERNEL); 170662306a36Sopenharmony_ci if (!cluster) 170762306a36Sopenharmony_ci return -ENOMEM; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci cluster->dev = dev; 171062306a36Sopenharmony_ci cluster->soc_data = data; 171162306a36Sopenharmony_ci INIT_LIST_HEAD(&cluster->cores); 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci ret = of_property_read_u32(np, "ti,cluster-mode", &cluster->mode); 171462306a36Sopenharmony_ci if (ret < 0 && ret != -EINVAL) { 171562306a36Sopenharmony_ci dev_err(dev, "invalid format for ti,cluster-mode, ret = %d\n", 171662306a36Sopenharmony_ci ret); 171762306a36Sopenharmony_ci return ret; 171862306a36Sopenharmony_ci } 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci if (ret == -EINVAL) { 172162306a36Sopenharmony_ci /* 172262306a36Sopenharmony_ci * default to most common efuse configurations - Split-mode on AM64x 172362306a36Sopenharmony_ci * and LockStep-mode on all others 172462306a36Sopenharmony_ci * default to most common efuse configurations - 172562306a36Sopenharmony_ci * Split-mode on AM64x 172662306a36Sopenharmony_ci * Single core on AM62x 172762306a36Sopenharmony_ci * LockStep-mode on all others 172862306a36Sopenharmony_ci */ 172962306a36Sopenharmony_ci if (!data->is_single_core) 173062306a36Sopenharmony_ci cluster->mode = data->single_cpu_mode ? 173162306a36Sopenharmony_ci CLUSTER_MODE_SPLIT : CLUSTER_MODE_LOCKSTEP; 173262306a36Sopenharmony_ci else 173362306a36Sopenharmony_ci cluster->mode = CLUSTER_MODE_SINGLECORE; 173462306a36Sopenharmony_ci } 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci if ((cluster->mode == CLUSTER_MODE_SINGLECPU && !data->single_cpu_mode) || 173762306a36Sopenharmony_ci (cluster->mode == CLUSTER_MODE_SINGLECORE && !data->is_single_core)) { 173862306a36Sopenharmony_ci dev_err(dev, "Cluster mode = %d is not supported on this SoC\n", cluster->mode); 173962306a36Sopenharmony_ci return -EINVAL; 174062306a36Sopenharmony_ci } 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci num_cores = of_get_available_child_count(np); 174362306a36Sopenharmony_ci if (num_cores != 2 && !data->is_single_core) { 174462306a36Sopenharmony_ci dev_err(dev, "MCU cluster requires both R5F cores to be enabled but num_cores is set to = %d\n", 174562306a36Sopenharmony_ci num_cores); 174662306a36Sopenharmony_ci return -ENODEV; 174762306a36Sopenharmony_ci } 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci if (num_cores != 1 && data->is_single_core) { 175062306a36Sopenharmony_ci dev_err(dev, "SoC supports only single core R5 but num_cores is set to %d\n", 175162306a36Sopenharmony_ci num_cores); 175262306a36Sopenharmony_ci return -ENODEV; 175362306a36Sopenharmony_ci } 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci platform_set_drvdata(pdev, cluster); 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci ret = devm_of_platform_populate(dev); 175862306a36Sopenharmony_ci if (ret) { 175962306a36Sopenharmony_ci dev_err(dev, "devm_of_platform_populate failed, ret = %d\n", 176062306a36Sopenharmony_ci ret); 176162306a36Sopenharmony_ci return ret; 176262306a36Sopenharmony_ci } 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci ret = k3_r5_cluster_of_init(pdev); 176562306a36Sopenharmony_ci if (ret) { 176662306a36Sopenharmony_ci dev_err(dev, "k3_r5_cluster_of_init failed, ret = %d\n", ret); 176762306a36Sopenharmony_ci return ret; 176862306a36Sopenharmony_ci } 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, k3_r5_cluster_of_exit, pdev); 177162306a36Sopenharmony_ci if (ret) 177262306a36Sopenharmony_ci return ret; 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci ret = k3_r5_cluster_rproc_init(pdev); 177562306a36Sopenharmony_ci if (ret) { 177662306a36Sopenharmony_ci dev_err(dev, "k3_r5_cluster_rproc_init failed, ret = %d\n", 177762306a36Sopenharmony_ci ret); 177862306a36Sopenharmony_ci return ret; 177962306a36Sopenharmony_ci } 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, k3_r5_cluster_rproc_exit, pdev); 178262306a36Sopenharmony_ci if (ret) 178362306a36Sopenharmony_ci return ret; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci return 0; 178662306a36Sopenharmony_ci} 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_cistatic const struct k3_r5_soc_data am65_j721e_soc_data = { 178962306a36Sopenharmony_ci .tcm_is_double = false, 179062306a36Sopenharmony_ci .tcm_ecc_autoinit = false, 179162306a36Sopenharmony_ci .single_cpu_mode = false, 179262306a36Sopenharmony_ci .is_single_core = false, 179362306a36Sopenharmony_ci}; 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_cistatic const struct k3_r5_soc_data j7200_j721s2_soc_data = { 179662306a36Sopenharmony_ci .tcm_is_double = true, 179762306a36Sopenharmony_ci .tcm_ecc_autoinit = true, 179862306a36Sopenharmony_ci .single_cpu_mode = false, 179962306a36Sopenharmony_ci .is_single_core = false, 180062306a36Sopenharmony_ci}; 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_cistatic const struct k3_r5_soc_data am64_soc_data = { 180362306a36Sopenharmony_ci .tcm_is_double = true, 180462306a36Sopenharmony_ci .tcm_ecc_autoinit = true, 180562306a36Sopenharmony_ci .single_cpu_mode = true, 180662306a36Sopenharmony_ci .is_single_core = false, 180762306a36Sopenharmony_ci}; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_cistatic const struct k3_r5_soc_data am62_soc_data = { 181062306a36Sopenharmony_ci .tcm_is_double = false, 181162306a36Sopenharmony_ci .tcm_ecc_autoinit = true, 181262306a36Sopenharmony_ci .single_cpu_mode = false, 181362306a36Sopenharmony_ci .is_single_core = true, 181462306a36Sopenharmony_ci}; 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_cistatic const struct of_device_id k3_r5_of_match[] = { 181762306a36Sopenharmony_ci { .compatible = "ti,am654-r5fss", .data = &am65_j721e_soc_data, }, 181862306a36Sopenharmony_ci { .compatible = "ti,j721e-r5fss", .data = &am65_j721e_soc_data, }, 181962306a36Sopenharmony_ci { .compatible = "ti,j7200-r5fss", .data = &j7200_j721s2_soc_data, }, 182062306a36Sopenharmony_ci { .compatible = "ti,am64-r5fss", .data = &am64_soc_data, }, 182162306a36Sopenharmony_ci { .compatible = "ti,am62-r5fss", .data = &am62_soc_data, }, 182262306a36Sopenharmony_ci { .compatible = "ti,j721s2-r5fss", .data = &j7200_j721s2_soc_data, }, 182362306a36Sopenharmony_ci { /* sentinel */ }, 182462306a36Sopenharmony_ci}; 182562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, k3_r5_of_match); 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_cistatic struct platform_driver k3_r5_rproc_driver = { 182862306a36Sopenharmony_ci .probe = k3_r5_probe, 182962306a36Sopenharmony_ci .driver = { 183062306a36Sopenharmony_ci .name = "k3_r5_rproc", 183162306a36Sopenharmony_ci .of_match_table = k3_r5_of_match, 183262306a36Sopenharmony_ci }, 183362306a36Sopenharmony_ci}; 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_cimodule_platform_driver(k3_r5_rproc_driver); 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 183862306a36Sopenharmony_ciMODULE_DESCRIPTION("TI K3 R5F remote processor driver"); 183962306a36Sopenharmony_ciMODULE_AUTHOR("Suman Anna <s-anna@ti.com>"); 1840