Commit 60c6119c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'rproc-v6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux

Pull remoteproc updates from Bjorn Andersson:

 - The maximum amount of DDR memory used by the Mediatek MT8188/MT8195
   SCP is increased to handle new use cases. Handling of optional L1TCM
   memory is made actually optional.

 - An optimization is introduced to only clear the unused portion of IPI
   shared buffers, rather than the entire buffer before writing the
   message.

 - Detection for IPC-only mode in the TI K3 DSP remoteproc driver is
   corrected. The loglevel of a debug print in the same is lowered from
   error.

 - Support for attaching to an running remote processor is added to the
   Xilinx R5F.

 - An in-kernel implementation of the Qualcomm "protected domain mapper"
   (aka service registry) service is introduced, to remove the
   dependency on a userspace implementation to detect when the battery
   monitor and USB Type-C port manager becomes available. This is then
   integrated with the Qualcomm remoteproc driver.

 - The Qualcomm PAS remoteproc driver gains support for attempting to
   bust hwspinlocks held by the remote processor when it
   crashed/stopped.

 - The TI OMAP remoteproc driver is transitioned to use devres helpers
   for various forms of allocations.

 - Parsing of memory-regions in the i.MX remoteproc driver is improved
   to avoid a NULL pointer dereference if the phandle reference is
   empty. of_node reference counting is corrected in the same.

* tag 'rproc-v6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux:
  remoteproc: mediatek: Increase MT8188/MT8195 SCP core0 DRAM size
  remoteproc: k3-dsp: Fix log levels where appropriate
  remoteproc: xlnx: Add attach detach support
  remoteproc: qcom: select AUXILIARY_BUS
  remoteproc: k3-r5: Fix IPC-only mode detection
  remoteproc: mediatek: Don't attempt to remap l1tcm memory if missing
  remoteproc: qcom: enable in-kernel PD mapper
  dt-bindings: remoteproc: imx_rproc: Add minItems for power-domain
  remoteproc: imx_rproc: Fix refcount mistake in imx_rproc_addr_init
  remoteproc: omap: Use devm_rproc_add() helper
  remoteproc: omap: Use devm action to release reserved memory
  remoteproc: omap: Use devm_rproc_alloc() helper
  remoteproc: imx_rproc: Skip over memory region when node value is NULL
  dt-bindings: remoteproc: k3-dsp: Correct optional sram properties for AM62A SoCs
  remoteproc: qcom_q6v5_pas: Add hwspinlock bust on stop
  soc: qcom: smem: Add qcom_smem_bust_hwspin_lock_by_host()
  remoteproc: mediatek: Zero out only remaining bytes of IPI buffer
parents 58bffbac 19cb6058
......@@ -59,6 +59,7 @@ properties:
maxItems: 32
power-domains:
minItems: 2
maxItems: 8
fsl,auto-boot:
......@@ -99,6 +100,20 @@ allOf:
properties:
fsl,iomuxc-gpr: false
- if:
properties:
compatible:
contains:
enum:
- fsl,imx8qxp-cm4
- fsl,imx8qm-cm4
then:
required:
- power-domains
else:
properties:
power-domains: false
additionalProperties: false
examples:
......
......@@ -25,9 +25,6 @@ description: |
host processor (Arm CorePac) to perform the device management of the remote
processor and to communicate with the remote processor.
allOf:
- $ref: /schemas/arm/keystone/ti,k3-sci-common.yaml#
properties:
compatible:
enum:
......@@ -89,41 +86,57 @@ properties:
should be defined as per the generic bindings in,
Documentation/devicetree/bindings/sram/sram.yaml
if:
properties:
compatible:
enum:
- ti,j721e-c66-dsp
then:
properties:
reg:
items:
- description: Address and Size of the L2 SRAM internal memory region
- description: Address and Size of the L1 PRAM internal memory region
- description: Address and Size of the L1 DRAM internal memory region
reg-names:
items:
- const: l2sram
- const: l1pram
- const: l1dram
else:
if:
properties:
compatible:
enum:
- ti,am62a-c7xv-dsp
- ti,j721e-c71-dsp
- ti,j721s2-c71-dsp
then:
properties:
reg:
items:
- description: Address and Size of the L2 SRAM internal memory region
- description: Address and Size of the L1 DRAM internal memory region
reg-names:
items:
- const: l2sram
- const: l1dram
allOf:
- if:
properties:
compatible:
enum:
- ti,j721e-c66-dsp
then:
properties:
reg:
items:
- description: Address and Size of the L2 SRAM internal memory region
- description: Address and Size of the L1 PRAM internal memory region
- description: Address and Size of the L1 DRAM internal memory region
reg-names:
items:
- const: l2sram
- const: l1pram
- const: l1dram
- if:
properties:
compatible:
enum:
- ti,j721e-c71-dsp
- ti,j721s2-c71-dsp
then:
properties:
reg:
items:
- description: Address and Size of the L2 SRAM internal memory region
- description: Address and Size of the L1 DRAM internal memory region
reg-names:
items:
- const: l2sram
- const: l1dram
- if:
properties:
compatible:
enum:
- ti,am62a-c7xv-dsp
then:
properties:
reg:
items:
- description: Address and Size of the L2 SRAM internal memory region
reg-names:
items:
- const: l2sram
- $ref: /schemas/arm/keystone/ti,k3-sci-common.yaml#
required:
- compatible
......
......@@ -166,6 +166,7 @@ config QCOM_PIL_INFO
config QCOM_RPROC_COMMON
tristate
select AUXILIARY_BUS
config QCOM_Q6V5_COMMON
tristate
......
......@@ -726,31 +726,37 @@ static int imx_rproc_addr_init(struct imx_rproc *priv,
struct resource res;
node = of_parse_phandle(np, "memory-region", a);
if (!node)
continue;
/* Not map vdevbuffer, vdevring region */
if (!strncmp(node->name, "vdev", strlen("vdev"))) {
of_node_put(node);
continue;
}
err = of_address_to_resource(node, 0, &res);
of_node_put(node);
if (err) {
dev_err(dev, "unable to resolve memory region\n");
of_node_put(node);
return err;
}
if (b >= IMX_RPROC_MEM_MAX)
if (b >= IMX_RPROC_MEM_MAX) {
of_node_put(node);
break;
}
/* Not use resource version, because we might share region */
priv->mem[b].cpu_addr = devm_ioremap_wc(&pdev->dev, res.start, resource_size(&res));
if (!priv->mem[b].cpu_addr) {
dev_err(dev, "failed to remap %pr\n", &res);
of_node_put(node);
return -ENOMEM;
}
priv->mem[b].sys_addr = res.start;
priv->mem[b].size = resource_size(&res);
if (!strcmp(node->name, "rsc-table"))
priv->rsc_table = priv->mem[b].cpu_addr;
of_node_put(node);
b++;
}
......
......@@ -117,8 +117,8 @@ static void scp_ipi_handler(struct mtk_scp *scp)
return;
}
memset(scp->share_buf, 0, scp_sizes->ipi_share_buffer_size);
memcpy_fromio(scp->share_buf, &rcv_obj->share_buf, len);
memset(&scp->share_buf[len], 0, scp_sizes->ipi_share_buffer_size - len);
handler(scp->share_buf, len, ipi_desc[id].priv);
scp_ipi_unlock(scp, id);
......@@ -1344,14 +1344,12 @@ static int scp_probe(struct platform_device *pdev)
/* l1tcm is an optional memory region */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "l1tcm");
scp_cluster->l1tcm_base = devm_ioremap_resource(dev, res);
if (IS_ERR(scp_cluster->l1tcm_base)) {
ret = PTR_ERR(scp_cluster->l1tcm_base);
if (ret != -EINVAL)
return dev_err_probe(dev, ret, "Failed to map l1tcm memory\n");
if (res) {
scp_cluster->l1tcm_base = devm_ioremap_resource(dev, res);
if (IS_ERR(scp_cluster->l1tcm_base))
return dev_err_probe(dev, PTR_ERR(scp_cluster->l1tcm_base),
"Failed to map l1tcm memory\n");
scp_cluster->l1tcm_base = NULL;
} else {
scp_cluster->l1tcm_size = resource_size(res);
scp_cluster->l1tcm_phys = res->start;
}
......@@ -1390,7 +1388,7 @@ static const struct mtk_scp_sizes_data default_scp_sizes = {
};
static const struct mtk_scp_sizes_data mt8188_scp_sizes = {
.max_dram_size = 0x500000,
.max_dram_size = 0x800000,
.ipi_share_buffer_size = 600,
};
......@@ -1399,6 +1397,11 @@ static const struct mtk_scp_sizes_data mt8188_scp_c1_sizes = {
.ipi_share_buffer_size = 600,
};
static const struct mtk_scp_sizes_data mt8195_scp_sizes = {
.max_dram_size = 0x800000,
.ipi_share_buffer_size = 288,
};
static const struct mtk_scp_of_data mt8183_of_data = {
.scp_clk_get = mt8183_scp_clk_get,
.scp_before_load = mt8183_scp_before_load,
......@@ -1476,7 +1479,7 @@ static const struct mtk_scp_of_data mt8195_of_data = {
.scp_da_to_va = mt8192_scp_da_to_va,
.host_to_scp_reg = MT8192_GIPC_IN_SET,
.host_to_scp_int_bit = MT8192_HOST_IPC_INT_BIT,
.scp_sizes = &default_scp_sizes,
.scp_sizes = &mt8195_scp_sizes,
};
static const struct mtk_scp_of_data mt8195_of_data_c1 = {
......
......@@ -1277,6 +1277,13 @@ static int omap_rproc_of_get_timers(struct platform_device *pdev,
return 0;
}
static void omap_rproc_mem_release(void *data)
{
struct device *dev = data;
of_reserved_mem_device_release(dev);
}
static int omap_rproc_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
......@@ -1305,8 +1312,8 @@ static int omap_rproc_probe(struct platform_device *pdev)
return ret;
}
rproc = rproc_alloc(&pdev->dev, dev_name(&pdev->dev), &omap_rproc_ops,
firmware, sizeof(*oproc));
rproc = devm_rproc_alloc(&pdev->dev, dev_name(&pdev->dev), &omap_rproc_ops,
firmware, sizeof(*oproc));
if (!rproc)
return -ENOMEM;
......@@ -1318,15 +1325,15 @@ static int omap_rproc_probe(struct platform_device *pdev)
ret = omap_rproc_of_get_internal_memories(pdev, rproc);
if (ret)
goto free_rproc;
return ret;
ret = omap_rproc_get_boot_data(pdev, rproc);
if (ret)
goto free_rproc;
return ret;
ret = omap_rproc_of_get_timers(pdev, rproc);
if (ret)
goto free_rproc;
return ret;
init_completion(&oproc->pm_comp);
oproc->autosuspend_delay = DEFAULT_AUTOSUSPEND_DELAY;
......@@ -1337,10 +1344,8 @@ static int omap_rproc_probe(struct platform_device *pdev)
pm_runtime_set_autosuspend_delay(&pdev->dev, oproc->autosuspend_delay);
oproc->fck = devm_clk_get(&pdev->dev, 0);
if (IS_ERR(oproc->fck)) {
ret = PTR_ERR(oproc->fck);
goto free_rproc;
}
if (IS_ERR(oproc->fck))
return PTR_ERR(oproc->fck);
ret = of_reserved_mem_device_init(&pdev->dev);
if (ret) {
......@@ -1348,29 +1353,17 @@ static int omap_rproc_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "Typically this should be provided,\n");
dev_warn(&pdev->dev, "only omit if you know what you are doing.\n");
}
ret = devm_add_action_or_reset(&pdev->dev, omap_rproc_mem_release, &pdev->dev);
if (ret)
return ret;
platform_set_drvdata(pdev, rproc);
ret = rproc_add(rproc);
ret = devm_rproc_add(&pdev->dev, rproc);
if (ret)
goto release_mem;
return ret;
return 0;
release_mem:
of_reserved_mem_device_release(&pdev->dev);
free_rproc:
rproc_free(rproc);
return ret;
}
static void omap_rproc_remove(struct platform_device *pdev)
{
struct rproc *rproc = platform_get_drvdata(pdev);
rproc_del(rproc);
rproc_free(rproc);
of_reserved_mem_device_release(&pdev->dev);
}
static const struct dev_pm_ops omap_rproc_pm_ops = {
......@@ -1381,7 +1374,6 @@ static const struct dev_pm_ops omap_rproc_pm_ops = {
static struct platform_driver omap_rproc_driver = {
.probe = omap_rproc_probe,
.remove_new = omap_rproc_remove,
.driver = {
.name = "omap-rproc",
.pm = &omap_rproc_pm_ops,
......
......@@ -13,6 +13,7 @@
#include <linux/notifier.h>
#include <linux/remoteproc.h>
#include <linux/remoteproc/qcom_rproc.h>
#include <linux/auxiliary_bus.h>
#include <linux/rpmsg/qcom_glink.h>
#include <linux/rpmsg/qcom_smd.h>
#include <linux/slab.h>
......@@ -25,6 +26,7 @@
#define to_glink_subdev(d) container_of(d, struct qcom_rproc_glink, subdev)
#define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev)
#define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev)
#define to_pdm_subdev(d) container_of(d, struct qcom_rproc_pdm, subdev)
#define MAX_NUM_OF_SS 10
#define MAX_REGION_NAME_LENGTH 16
......@@ -519,5 +521,90 @@ void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr)
}
EXPORT_SYMBOL_GPL(qcom_remove_ssr_subdev);
static void pdm_dev_release(struct device *dev)
{
struct auxiliary_device *adev = to_auxiliary_dev(dev);
kfree(adev);
}
static int pdm_notify_prepare(struct rproc_subdev *subdev)
{
struct qcom_rproc_pdm *pdm = to_pdm_subdev(subdev);
struct auxiliary_device *adev;
int ret;
adev = kzalloc(sizeof(*adev), GFP_KERNEL);
if (!adev)
return -ENOMEM;
adev->dev.parent = pdm->dev;
adev->dev.release = pdm_dev_release;
adev->name = "pd-mapper";
adev->id = pdm->index;
ret = auxiliary_device_init(adev);
if (ret) {
kfree(adev);
return ret;
}
ret = auxiliary_device_add(adev);
if (ret) {
auxiliary_device_uninit(adev);
return ret;
}
pdm->adev = adev;
return 0;
}
static void pdm_notify_unprepare(struct rproc_subdev *subdev)
{
struct qcom_rproc_pdm *pdm = to_pdm_subdev(subdev);
if (!pdm->adev)
return;
auxiliary_device_delete(pdm->adev);
auxiliary_device_uninit(pdm->adev);
pdm->adev = NULL;
}
/**
* qcom_add_pdm_subdev() - register PD Mapper subdevice
* @rproc: rproc handle
* @pdm: PDM subdevice handle
*
* Register @pdm so that Protection Device mapper service is started when the
* DSP is started too.
*/
void qcom_add_pdm_subdev(struct rproc *rproc, struct qcom_rproc_pdm *pdm)
{
pdm->dev = &rproc->dev;
pdm->index = rproc->index;
pdm->subdev.prepare = pdm_notify_prepare;
pdm->subdev.unprepare = pdm_notify_unprepare;
rproc_add_subdev(rproc, &pdm->subdev);
}
EXPORT_SYMBOL_GPL(qcom_add_pdm_subdev);
/**
* qcom_remove_pdm_subdev() - remove PD Mapper subdevice
* @rproc: rproc handle
* @pdm: PDM subdevice handle
*
* Remove the PD Mapper subdevice.
*/
void qcom_remove_pdm_subdev(struct rproc *rproc, struct qcom_rproc_pdm *pdm)
{
rproc_remove_subdev(rproc, &pdm->subdev);
}
EXPORT_SYMBOL_GPL(qcom_remove_pdm_subdev);
MODULE_DESCRIPTION("Qualcomm Remoteproc helper driver");
MODULE_LICENSE("GPL v2");
......@@ -34,6 +34,13 @@ struct qcom_rproc_ssr {
struct qcom_ssr_subsystem *info;
};
struct qcom_rproc_pdm {
struct rproc_subdev subdev;
struct device *dev;
int index;
struct auxiliary_device *adev;
};
void qcom_minidump(struct rproc *rproc, unsigned int minidump_id,
void (*rproc_dumpfn_t)(struct rproc *rproc,
struct rproc_dump_segment *segment, void *dest, size_t offset,
......@@ -52,6 +59,9 @@ void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr,
const char *ssr_name);
void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr);
void qcom_add_pdm_subdev(struct rproc *rproc, struct qcom_rproc_pdm *pdm);
void qcom_remove_pdm_subdev(struct rproc *rproc, struct qcom_rproc_pdm *pdm);
#if IS_ENABLED(CONFIG_QCOM_SYSMON)
struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
const char *name,
......
......@@ -112,6 +112,7 @@ struct qcom_adsp {
struct dev_pm_domain_list *pd_list;
struct qcom_rproc_glink glink_subdev;
struct qcom_rproc_pdm pdm_subdev;
struct qcom_rproc_ssr ssr_subdev;
struct qcom_sysmon *sysmon;
......@@ -726,6 +727,7 @@ static int adsp_probe(struct platform_device *pdev)
goto disable_pm;
qcom_add_glink_subdev(rproc, &adsp->glink_subdev, desc->ssr_name);
qcom_add_pdm_subdev(rproc, &adsp->pdm_subdev);
qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name);
adsp->sysmon = qcom_add_sysmon_subdev(rproc,
desc->sysmon_name,
......@@ -755,6 +757,7 @@ static void adsp_remove(struct platform_device *pdev)
qcom_q6v5_deinit(&adsp->q6v5);
qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
qcom_remove_pdm_subdev(adsp->rproc, &adsp->pdm_subdev);
qcom_remove_sysmon_subdev(adsp->sysmon);
qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
qcom_rproc_pds_detach(adsp);
......
......@@ -228,6 +228,7 @@ struct q6v5 {
struct qcom_rproc_glink glink_subdev;
struct qcom_rproc_subdev smd_subdev;
struct qcom_rproc_pdm pdm_subdev;
struct qcom_rproc_ssr ssr_subdev;
struct qcom_sysmon *sysmon;
struct platform_device *bam_dmux;
......@@ -2102,6 +2103,7 @@ static int q6v5_probe(struct platform_device *pdev)
qproc->mba_perm = BIT(QCOM_SCM_VMID_HLOS);
qcom_add_glink_subdev(rproc, &qproc->glink_subdev, "mpss");
qcom_add_smd_subdev(rproc, &qproc->smd_subdev);
qcom_add_pdm_subdev(rproc, &qproc->pdm_subdev);
qcom_add_ssr_subdev(rproc, &qproc->ssr_subdev, "mpss");
qproc->sysmon = qcom_add_sysmon_subdev(rproc, "modem", 0x12);
if (IS_ERR(qproc->sysmon)) {
......@@ -2143,6 +2145,7 @@ static void q6v5_remove(struct platform_device *pdev)
qcom_q6v5_deinit(&qproc->q6v5);
qcom_remove_sysmon_subdev(qproc->sysmon);
qcom_remove_ssr_subdev(rproc, &qproc->ssr_subdev);
qcom_remove_pdm_subdev(rproc, &qproc->pdm_subdev);
qcom_remove_smd_subdev(rproc, &qproc->smd_subdev);
qcom_remove_glink_subdev(rproc, &qproc->glink_subdev);
......
......@@ -52,6 +52,7 @@ struct adsp_data {
const char *ssr_name;
const char *sysmon_name;
int ssctl_id;
unsigned int smem_host_id;
int region_assign_idx;
int region_assign_count;
......@@ -81,6 +82,7 @@ struct qcom_adsp {
int lite_pas_id;
unsigned int minidump_id;
int crash_reason_smem;
unsigned int smem_host_id;
bool decrypt_shutdown;
const char *info_name;
......@@ -109,6 +111,7 @@ struct qcom_adsp {
struct qcom_rproc_glink glink_subdev;
struct qcom_rproc_subdev smd_subdev;
struct qcom_rproc_pdm pdm_subdev;
struct qcom_rproc_ssr ssr_subdev;
struct qcom_sysmon *sysmon;
......@@ -399,6 +402,9 @@ static int adsp_stop(struct rproc *rproc)
if (handover)
qcom_pas_handover(&adsp->q6v5);
if (adsp->smem_host_id)
ret = qcom_smem_bust_hwspin_lock_by_host(adsp->smem_host_id);
return ret;
}
......@@ -727,6 +733,7 @@ static int adsp_probe(struct platform_device *pdev)
adsp->pas_id = desc->pas_id;
adsp->lite_pas_id = desc->lite_pas_id;
adsp->info_name = desc->sysmon_name;
adsp->smem_host_id = desc->smem_host_id;
adsp->decrypt_shutdown = desc->decrypt_shutdown;
adsp->region_assign_idx = desc->region_assign_idx;
adsp->region_assign_count = min_t(int, MAX_ASSIGN_COUNT, desc->region_assign_count);
......@@ -771,6 +778,7 @@ static int adsp_probe(struct platform_device *pdev)
qcom_add_glink_subdev(rproc, &adsp->glink_subdev, desc->ssr_name);
qcom_add_smd_subdev(rproc, &adsp->smd_subdev);
qcom_add_pdm_subdev(rproc, &adsp->pdm_subdev);
adsp->sysmon = qcom_add_sysmon_subdev(rproc,
desc->sysmon_name,
desc->ssctl_id);
......@@ -805,6 +813,7 @@ static void adsp_remove(struct platform_device *pdev)
qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
qcom_remove_sysmon_subdev(adsp->sysmon);
qcom_remove_smd_subdev(adsp->rproc, &adsp->smd_subdev);
qcom_remove_pdm_subdev(adsp->rproc, &adsp->pdm_subdev);
qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
adsp_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
device_init_wakeup(adsp->dev, false);
......@@ -1196,6 +1205,7 @@ static const struct adsp_data sm8550_adsp_resource = {
.ssr_name = "lpass",
.sysmon_name = "adsp",
.ssctl_id = 0x14,
.smem_host_id = 2,
};
static const struct adsp_data sm8550_cdsp_resource = {
......@@ -1216,6 +1226,7 @@ static const struct adsp_data sm8550_cdsp_resource = {
.ssr_name = "cdsp",
.sysmon_name = "cdsp",
.ssctl_id = 0x17,
.smem_host_id = 5,
};
static const struct adsp_data sm8550_mpss_resource = {
......@@ -1236,6 +1247,7 @@ static const struct adsp_data sm8550_mpss_resource = {
.ssr_name = "mpss",
.sysmon_name = "modem",
.ssctl_id = 0x12,
.smem_host_id = 1,
.region_assign_idx = 2,
.region_assign_count = 1,
.region_assign_vmid = QCOM_SCM_VMID_MSS_MSA,
......@@ -1275,6 +1287,7 @@ static const struct adsp_data sm8650_cdsp_resource = {
.ssr_name = "cdsp",
.sysmon_name = "cdsp",
.ssctl_id = 0x17,
.smem_host_id = 5,
.region_assign_idx = 2,
.region_assign_count = 1,
.region_assign_shared = true,
......@@ -1299,6 +1312,7 @@ static const struct adsp_data sm8650_mpss_resource = {
.ssr_name = "mpss",
.sysmon_name = "modem",
.ssctl_id = 0x12,
.smem_host_id = 1,
.region_assign_idx = 2,
.region_assign_count = 3,
.region_assign_vmid = QCOM_SCM_VMID_MSS_MSA,
......
......@@ -148,6 +148,7 @@ struct q6v5_wcss {
bool requires_force_stop;
struct qcom_rproc_glink glink_subdev;
struct qcom_rproc_pdm pdm_subdev;
struct qcom_rproc_ssr ssr_subdev;
};
......@@ -1052,6 +1053,7 @@ static int q6v5_wcss_probe(struct platform_device *pdev)
return ret;
qcom_add_glink_subdev(rproc, &wcss->glink_subdev, "q6wcss");
qcom_add_pdm_subdev(rproc, &wcss->pdm_subdev);
qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss");
if (desc->ssctl_id)
......@@ -1074,6 +1076,7 @@ static void q6v5_wcss_remove(struct platform_device *pdev)
struct q6v5_wcss *wcss = rproc->priv;
qcom_q6v5_deinit(&wcss->q6v5);
qcom_remove_pdm_subdev(rproc, &wcss->pdm_subdev);
rproc_del(rproc);
}
......
......@@ -327,7 +327,7 @@ static int k3_dsp_rproc_start(struct rproc *rproc)
goto put_mbox;
}
dev_err(dev, "booting DSP core using boot addr = 0x%x\n", boot_addr);
dev_dbg(dev, "booting DSP core using boot addr = 0x%x\n", boot_addr);
ret = ti_sci_proc_set_config(kproc->tsp, boot_addr, 0, 0);
if (ret)
goto put_mbox;
......
......@@ -1144,6 +1144,7 @@ static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc)
u32 atcm_enable, btcm_enable, loczrama;
struct k3_r5_core *core0;
enum cluster_mode mode = cluster->mode;
int reset_ctrl_status;
int ret;
core0 = list_first_entry(&cluster->cores, struct k3_r5_core, elem);
......@@ -1160,11 +1161,11 @@ static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc)
r_state, c_state);
}
ret = reset_control_status(core->reset);
if (ret < 0) {
reset_ctrl_status = reset_control_status(core->reset);
if (reset_ctrl_status < 0) {
dev_err(cdev, "failed to get initial local reset status, ret = %d\n",
ret);
return ret;
reset_ctrl_status);
return reset_ctrl_status;
}
/*
......@@ -1199,7 +1200,7 @@ static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc)
* irrelevant if module reset is asserted (POR value has local reset
* deasserted), and is deemed as remoteproc mode
*/
if (c_state && !ret && !halted) {
if (c_state && !reset_ctrl_status && !halted) {
dev_info(cdev, "configured R5F for IPC-only mode\n");
kproc->rproc->state = RPROC_DETACHED;
ret = 1;
......@@ -1217,7 +1218,7 @@ static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc)
ret = 0;
} else {
dev_err(cdev, "mismatched mode: local_reset = %s, module_reset = %s, core_state = %s\n",
!ret ? "deasserted" : "asserted",
!reset_ctrl_status ? "deasserted" : "asserted",
c_state ? "deasserted" : "asserted",
halted ? "halted" : "unhalted");
ret = -EINVAL;
......
......@@ -25,6 +25,10 @@
/* RX mailbox client buffer max length */
#define MBOX_CLIENT_BUF_MAX (IPI_BUF_LEN_MAX + \
sizeof(struct zynqmp_ipi_message))
#define RSC_TBL_XLNX_MAGIC ((uint32_t)'x' << 24 | (uint32_t)'a' << 16 | \
(uint32_t)'m' << 8 | (uint32_t)'p')
/*
* settings for RPU cluster mode which
* reflects possible values of xlnx,cluster-mode dt-property
......@@ -73,6 +77,26 @@ struct mbox_info {
struct mbox_chan *rx_chan;
};
/**
* struct rsc_tbl_data
*
* Platform specific data structure used to sync resource table address.
* It's important to maintain order and size of each field on remote side.
*
* @version: version of data structure
* @magic_num: 32-bit magic number.
* @comp_magic_num: complement of above magic number
* @rsc_tbl_size: resource table size
* @rsc_tbl: resource table address
*/
struct rsc_tbl_data {
const int version;
const u32 magic_num;
const u32 comp_magic_num;
const u32 rsc_tbl_size;
const uintptr_t rsc_tbl;
} __packed;
/*
* Hardcoded TCM bank values. This will stay in driver to maintain backward
* compatibility with device-tree that does not have TCM information.
......@@ -95,20 +119,24 @@ static const struct mem_bank_data zynqmp_tcm_banks_lockstep[] = {
/**
* struct zynqmp_r5_core
*
* @rsc_tbl_va: resource table virtual address
* @dev: device of RPU instance
* @np: device node of RPU instance
* @tcm_bank_count: number TCM banks accessible to this RPU
* @tcm_banks: array of each TCM bank data
* @rproc: rproc handle
* @rsc_tbl_size: resource table size retrieved from remote
* @pm_domain_id: RPU CPU power domain id
* @ipi: pointer to mailbox information
*/
struct zynqmp_r5_core {
void __iomem *rsc_tbl_va;
struct device *dev;
struct device_node *np;
int tcm_bank_count;
struct mem_bank_data **tcm_banks;
struct rproc *rproc;
u32 rsc_tbl_size;
u32 pm_domain_id;
struct mbox_info *ipi;
};
......@@ -557,6 +585,14 @@ static int add_tcm_banks(struct rproc *rproc)
dev_dbg(dev, "TCM carveout %s addr=%llx, da=0x%x, size=0x%lx",
bank_name, bank_addr, da, bank_size);
/*
* In DETACHED state firmware is already running so no need to
* request add TCM registers. However, request TCM PD node to let
* platform management firmware know that TCM is in use.
*/
if (rproc->state == RPROC_DETACHED)
continue;
rproc_mem = rproc_mem_entry_init(dev, NULL, bank_addr,
bank_size, da,
tcm_mem_map, tcm_mem_unmap,
......@@ -662,6 +698,107 @@ static int zynqmp_r5_rproc_unprepare(struct rproc *rproc)
return 0;
}
static struct resource_table *zynqmp_r5_get_loaded_rsc_table(struct rproc *rproc,
size_t *size)
{
struct zynqmp_r5_core *r5_core;
r5_core = rproc->priv;
*size = r5_core->rsc_tbl_size;
return (struct resource_table *)r5_core->rsc_tbl_va;
}
static int zynqmp_r5_get_rsc_table_va(struct zynqmp_r5_core *r5_core)
{
struct resource_table *rsc_tbl_addr;
struct device *dev = r5_core->dev;
struct rsc_tbl_data *rsc_data_va;
struct resource res_mem;
struct device_node *np;
int ret;
/*
* It is expected from remote processor firmware to provide resource
* table address via struct rsc_tbl_data data structure.
* Start address of first entry under "memory-region" property list
* contains that data structure which holds resource table address, size
* and some magic number to validate correct resource table entry.
*/
np = of_parse_phandle(r5_core->np, "memory-region", 0);
if (!np) {
dev_err(dev, "failed to get memory region dev node\n");
return -EINVAL;
}
ret = of_address_to_resource(np, 0, &res_mem);
of_node_put(np);
if (ret) {
dev_err(dev, "failed to get memory-region resource addr\n");
return -EINVAL;
}
rsc_data_va = (struct rsc_tbl_data *)ioremap_wc(res_mem.start,
sizeof(struct rsc_tbl_data));
if (!rsc_data_va) {
dev_err(dev, "failed to map resource table data address\n");
return -EIO;
}
/*
* If RSC_TBL_XLNX_MAGIC number and its complement isn't found then
* do not consider resource table address valid and don't attach
*/
if (rsc_data_va->magic_num != RSC_TBL_XLNX_MAGIC ||
rsc_data_va->comp_magic_num != ~RSC_TBL_XLNX_MAGIC) {
dev_dbg(dev, "invalid magic number, won't attach\n");
return -EINVAL;
}
r5_core->rsc_tbl_va = ioremap_wc(rsc_data_va->rsc_tbl,
rsc_data_va->rsc_tbl_size);
if (!r5_core->rsc_tbl_va) {
dev_err(dev, "failed to get resource table va\n");
return -EINVAL;
}
rsc_tbl_addr = (struct resource_table *)r5_core->rsc_tbl_va;
/*
* As of now resource table version 1 is expected. Don't fail to attach
* but warn users about it.
*/
if (rsc_tbl_addr->ver != 1)
dev_warn(dev, "unexpected resource table version %d\n",
rsc_tbl_addr->ver);
r5_core->rsc_tbl_size = rsc_data_va->rsc_tbl_size;
iounmap((void __iomem *)rsc_data_va);
return 0;
}
static int zynqmp_r5_attach(struct rproc *rproc)
{
dev_dbg(&rproc->dev, "rproc %d attached\n", rproc->index);
return 0;
}
static int zynqmp_r5_detach(struct rproc *rproc)
{
/*
* Generate last notification to remote after clearing virtio flag.
* Remote can avoid polling on virtio reset flag if kick is generated
* during detach by host and check virtio reset flag on kick interrupt.
*/
zynqmp_r5_rproc_kick(rproc, 0);
return 0;
}
static const struct rproc_ops zynqmp_r5_rproc_ops = {
.prepare = zynqmp_r5_rproc_prepare,
.unprepare = zynqmp_r5_rproc_unprepare,
......@@ -673,6 +810,9 @@ static const struct rproc_ops zynqmp_r5_rproc_ops = {
.sanity_check = rproc_elf_sanity_check,
.get_boot_addr = rproc_elf_get_boot_addr,
.kick = zynqmp_r5_rproc_kick,
.get_loaded_rsc_table = zynqmp_r5_get_loaded_rsc_table,
.attach = zynqmp_r5_attach,
.detach = zynqmp_r5_detach,
};
/**
......@@ -723,6 +863,16 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev)
goto free_rproc;
}
/*
* If firmware is already available in the memory then move rproc state
* to DETACHED. Firmware can be preloaded via debugger or by any other
* agent (processors) in the system.
* If firmware isn't available in the memory and resource table isn't
* found, then rproc state remains OFFLINE.
*/
if (!zynqmp_r5_get_rsc_table_va(r5_core))
r5_rproc->state = RPROC_DETACHED;
r5_core->rproc = r5_rproc;
return r5_core;
......@@ -1134,6 +1284,7 @@ static void zynqmp_r5_cluster_exit(void *data)
for (i = 0; i < cluster->core_count; i++) {
r5_core = cluster->r5_cores[i];
zynqmp_r5_free_mbox(r5_core->ipi);
iounmap(r5_core->rsc_tbl_va);
of_reserved_mem_device_release(r5_core->dev);
put_device(r5_core->dev);
rproc_del(r5_core->rproc);
......
......@@ -359,6 +359,32 @@ static struct qcom_smem *__smem;
/* Timeout (ms) for the trylock of remote spinlocks */
#define HWSPINLOCK_TIMEOUT 1000
/* The qcom hwspinlock id is always plus one from the smem host id */
#define SMEM_HOST_ID_TO_HWSPINLOCK_ID(__x) ((__x) + 1)
/**
* qcom_smem_bust_hwspin_lock_by_host() - bust the smem hwspinlock for a host
* @host: remote processor id
*
* Busts the hwspin_lock for the given smem host id. This helper is intended
* for remoteproc drivers that manage remoteprocs with an equivalent smem
* driver instance in the remote firmware. Drivers can force a release of the
* smem hwspin_lock if the rproc unexpectedly goes into a bad state.
*
* Context: Process context.
*
* Returns: 0 on success, otherwise negative errno.
*/
int qcom_smem_bust_hwspin_lock_by_host(unsigned int host)
{
/* This function is for remote procs, so ignore SMEM_HOST_APPS */
if (host == SMEM_HOST_APPS || host >= SMEM_HOST_COUNT)
return -EINVAL;
return hwspin_lock_bust(__smem->hwlock, SMEM_HOST_ID_TO_HWSPINLOCK_ID(host));
}
EXPORT_SYMBOL_GPL(qcom_smem_bust_hwspin_lock_by_host);
/**
* qcom_smem_is_available() - Check if SMEM is available
*
......
......@@ -15,4 +15,6 @@ phys_addr_t qcom_smem_virt_to_phys(void *p);
int qcom_smem_get_soc_id(u32 *id);
int qcom_smem_get_feature_code(u32 *code);
int qcom_smem_bust_hwspin_lock_by_host(unsigned int host);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment