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: ...@@ -59,6 +59,7 @@ properties:
maxItems: 32 maxItems: 32
power-domains: power-domains:
minItems: 2
maxItems: 8 maxItems: 8
fsl,auto-boot: fsl,auto-boot:
...@@ -99,6 +100,20 @@ allOf: ...@@ -99,6 +100,20 @@ allOf:
properties: properties:
fsl,iomuxc-gpr: false 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 additionalProperties: false
examples: examples:
......
...@@ -25,9 +25,6 @@ description: | ...@@ -25,9 +25,6 @@ description: |
host processor (Arm CorePac) to perform the device management of the remote host processor (Arm CorePac) to perform the device management of the remote
processor and to communicate with the remote processor. processor and to communicate with the remote processor.
allOf:
- $ref: /schemas/arm/keystone/ti,k3-sci-common.yaml#
properties: properties:
compatible: compatible:
enum: enum:
...@@ -89,41 +86,57 @@ properties: ...@@ -89,41 +86,57 @@ properties:
should be defined as per the generic bindings in, should be defined as per the generic bindings in,
Documentation/devicetree/bindings/sram/sram.yaml Documentation/devicetree/bindings/sram/sram.yaml
if: allOf:
properties: - if:
compatible: properties:
enum: compatible:
- ti,j721e-c66-dsp enum:
then: - ti,j721e-c66-dsp
properties: then:
reg: properties:
items: reg:
- description: Address and Size of the L2 SRAM internal memory region items:
- description: Address and Size of the L1 PRAM internal memory region - description: Address and Size of the L2 SRAM internal memory region
- description: Address and Size of the L1 DRAM internal memory region - description: Address and Size of the L1 PRAM internal memory region
reg-names: - description: Address and Size of the L1 DRAM internal memory region
items: reg-names:
- const: l2sram items:
- const: l1pram - const: l2sram
- const: l1dram - const: l1pram
else: - const: l1dram
if:
properties: - if:
compatible: properties:
enum: compatible:
- ti,am62a-c7xv-dsp enum:
- ti,j721e-c71-dsp - ti,j721e-c71-dsp
- ti,j721s2-c71-dsp - ti,j721s2-c71-dsp
then: then:
properties: properties:
reg: reg:
items: items:
- description: Address and Size of the L2 SRAM internal memory region - description: Address and Size of the L2 SRAM internal memory region
- description: Address and Size of the L1 DRAM internal memory region - description: Address and Size of the L1 DRAM internal memory region
reg-names: reg-names:
items: items:
- const: l2sram - const: l2sram
- const: l1dram - 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: required:
- compatible - compatible
......
...@@ -166,6 +166,7 @@ config QCOM_PIL_INFO ...@@ -166,6 +166,7 @@ config QCOM_PIL_INFO
config QCOM_RPROC_COMMON config QCOM_RPROC_COMMON
tristate tristate
select AUXILIARY_BUS
config QCOM_Q6V5_COMMON config QCOM_Q6V5_COMMON
tristate tristate
......
...@@ -726,31 +726,37 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, ...@@ -726,31 +726,37 @@ static int imx_rproc_addr_init(struct imx_rproc *priv,
struct resource res; struct resource res;
node = of_parse_phandle(np, "memory-region", a); node = of_parse_phandle(np, "memory-region", a);
if (!node)
continue;
/* Not map vdevbuffer, vdevring region */ /* Not map vdevbuffer, vdevring region */
if (!strncmp(node->name, "vdev", strlen("vdev"))) { if (!strncmp(node->name, "vdev", strlen("vdev"))) {
of_node_put(node); of_node_put(node);
continue; continue;
} }
err = of_address_to_resource(node, 0, &res); err = of_address_to_resource(node, 0, &res);
of_node_put(node);
if (err) { if (err) {
dev_err(dev, "unable to resolve memory region\n"); dev_err(dev, "unable to resolve memory region\n");
of_node_put(node);
return err; return err;
} }
if (b >= IMX_RPROC_MEM_MAX) if (b >= IMX_RPROC_MEM_MAX) {
of_node_put(node);
break; break;
}
/* Not use resource version, because we might share region */ /* Not use resource version, because we might share region */
priv->mem[b].cpu_addr = devm_ioremap_wc(&pdev->dev, res.start, resource_size(&res)); priv->mem[b].cpu_addr = devm_ioremap_wc(&pdev->dev, res.start, resource_size(&res));
if (!priv->mem[b].cpu_addr) { if (!priv->mem[b].cpu_addr) {
dev_err(dev, "failed to remap %pr\n", &res); dev_err(dev, "failed to remap %pr\n", &res);
of_node_put(node);
return -ENOMEM; return -ENOMEM;
} }
priv->mem[b].sys_addr = res.start; priv->mem[b].sys_addr = res.start;
priv->mem[b].size = resource_size(&res); priv->mem[b].size = resource_size(&res);
if (!strcmp(node->name, "rsc-table")) if (!strcmp(node->name, "rsc-table"))
priv->rsc_table = priv->mem[b].cpu_addr; priv->rsc_table = priv->mem[b].cpu_addr;
of_node_put(node);
b++; b++;
} }
......
...@@ -117,8 +117,8 @@ static void scp_ipi_handler(struct mtk_scp *scp) ...@@ -117,8 +117,8 @@ static void scp_ipi_handler(struct mtk_scp *scp)
return; return;
} }
memset(scp->share_buf, 0, scp_sizes->ipi_share_buffer_size);
memcpy_fromio(scp->share_buf, &rcv_obj->share_buf, len); 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); handler(scp->share_buf, len, ipi_desc[id].priv);
scp_ipi_unlock(scp, id); scp_ipi_unlock(scp, id);
...@@ -1344,14 +1344,12 @@ static int scp_probe(struct platform_device *pdev) ...@@ -1344,14 +1344,12 @@ static int scp_probe(struct platform_device *pdev)
/* l1tcm is an optional memory region */ /* l1tcm is an optional memory region */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "l1tcm"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "l1tcm");
scp_cluster->l1tcm_base = devm_ioremap_resource(dev, res); if (res) {
if (IS_ERR(scp_cluster->l1tcm_base)) { scp_cluster->l1tcm_base = devm_ioremap_resource(dev, res);
ret = PTR_ERR(scp_cluster->l1tcm_base); if (IS_ERR(scp_cluster->l1tcm_base))
if (ret != -EINVAL) return dev_err_probe(dev, PTR_ERR(scp_cluster->l1tcm_base),
return dev_err_probe(dev, ret, "Failed to map l1tcm memory\n"); "Failed to map l1tcm memory\n");
scp_cluster->l1tcm_base = NULL;
} else {
scp_cluster->l1tcm_size = resource_size(res); scp_cluster->l1tcm_size = resource_size(res);
scp_cluster->l1tcm_phys = res->start; scp_cluster->l1tcm_phys = res->start;
} }
...@@ -1390,7 +1388,7 @@ static const struct mtk_scp_sizes_data default_scp_sizes = { ...@@ -1390,7 +1388,7 @@ static const struct mtk_scp_sizes_data default_scp_sizes = {
}; };
static const struct mtk_scp_sizes_data mt8188_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, .ipi_share_buffer_size = 600,
}; };
...@@ -1399,6 +1397,11 @@ static const struct mtk_scp_sizes_data mt8188_scp_c1_sizes = { ...@@ -1399,6 +1397,11 @@ static const struct mtk_scp_sizes_data mt8188_scp_c1_sizes = {
.ipi_share_buffer_size = 600, .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 = { static const struct mtk_scp_of_data mt8183_of_data = {
.scp_clk_get = mt8183_scp_clk_get, .scp_clk_get = mt8183_scp_clk_get,
.scp_before_load = mt8183_scp_before_load, .scp_before_load = mt8183_scp_before_load,
...@@ -1476,7 +1479,7 @@ static const struct mtk_scp_of_data mt8195_of_data = { ...@@ -1476,7 +1479,7 @@ static const struct mtk_scp_of_data mt8195_of_data = {
.scp_da_to_va = mt8192_scp_da_to_va, .scp_da_to_va = mt8192_scp_da_to_va,
.host_to_scp_reg = MT8192_GIPC_IN_SET, .host_to_scp_reg = MT8192_GIPC_IN_SET,
.host_to_scp_int_bit = MT8192_HOST_IPC_INT_BIT, .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 = { 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, ...@@ -1277,6 +1277,13 @@ static int omap_rproc_of_get_timers(struct platform_device *pdev,
return 0; 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) static int omap_rproc_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
...@@ -1305,8 +1312,8 @@ static int omap_rproc_probe(struct platform_device *pdev) ...@@ -1305,8 +1312,8 @@ static int omap_rproc_probe(struct platform_device *pdev)
return ret; return ret;
} }
rproc = rproc_alloc(&pdev->dev, dev_name(&pdev->dev), &omap_rproc_ops, rproc = devm_rproc_alloc(&pdev->dev, dev_name(&pdev->dev), &omap_rproc_ops,
firmware, sizeof(*oproc)); firmware, sizeof(*oproc));
if (!rproc) if (!rproc)
return -ENOMEM; return -ENOMEM;
...@@ -1318,15 +1325,15 @@ static int omap_rproc_probe(struct platform_device *pdev) ...@@ -1318,15 +1325,15 @@ static int omap_rproc_probe(struct platform_device *pdev)
ret = omap_rproc_of_get_internal_memories(pdev, rproc); ret = omap_rproc_of_get_internal_memories(pdev, rproc);
if (ret) if (ret)
goto free_rproc; return ret;
ret = omap_rproc_get_boot_data(pdev, rproc); ret = omap_rproc_get_boot_data(pdev, rproc);
if (ret) if (ret)
goto free_rproc; return ret;
ret = omap_rproc_of_get_timers(pdev, rproc); ret = omap_rproc_of_get_timers(pdev, rproc);
if (ret) if (ret)
goto free_rproc; return ret;
init_completion(&oproc->pm_comp); init_completion(&oproc->pm_comp);
oproc->autosuspend_delay = DEFAULT_AUTOSUSPEND_DELAY; oproc->autosuspend_delay = DEFAULT_AUTOSUSPEND_DELAY;
...@@ -1337,10 +1344,8 @@ static int omap_rproc_probe(struct platform_device *pdev) ...@@ -1337,10 +1344,8 @@ static int omap_rproc_probe(struct platform_device *pdev)
pm_runtime_set_autosuspend_delay(&pdev->dev, oproc->autosuspend_delay); pm_runtime_set_autosuspend_delay(&pdev->dev, oproc->autosuspend_delay);
oproc->fck = devm_clk_get(&pdev->dev, 0); oproc->fck = devm_clk_get(&pdev->dev, 0);
if (IS_ERR(oproc->fck)) { if (IS_ERR(oproc->fck))
ret = PTR_ERR(oproc->fck); return PTR_ERR(oproc->fck);
goto free_rproc;
}
ret = of_reserved_mem_device_init(&pdev->dev); ret = of_reserved_mem_device_init(&pdev->dev);
if (ret) { if (ret) {
...@@ -1348,29 +1353,17 @@ static int omap_rproc_probe(struct platform_device *pdev) ...@@ -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, "Typically this should be provided,\n");
dev_warn(&pdev->dev, "only omit if you know what you are doing.\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); platform_set_drvdata(pdev, rproc);
ret = rproc_add(rproc); ret = devm_rproc_add(&pdev->dev, rproc);
if (ret) if (ret)
goto release_mem; return ret;
return 0; 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 = { static const struct dev_pm_ops omap_rproc_pm_ops = {
...@@ -1381,7 +1374,6 @@ 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 = { static struct platform_driver omap_rproc_driver = {
.probe = omap_rproc_probe, .probe = omap_rproc_probe,
.remove_new = omap_rproc_remove,
.driver = { .driver = {
.name = "omap-rproc", .name = "omap-rproc",
.pm = &omap_rproc_pm_ops, .pm = &omap_rproc_pm_ops,
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/remoteproc.h> #include <linux/remoteproc.h>
#include <linux/remoteproc/qcom_rproc.h> #include <linux/remoteproc/qcom_rproc.h>
#include <linux/auxiliary_bus.h>
#include <linux/rpmsg/qcom_glink.h> #include <linux/rpmsg/qcom_glink.h>
#include <linux/rpmsg/qcom_smd.h> #include <linux/rpmsg/qcom_smd.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -25,6 +26,7 @@ ...@@ -25,6 +26,7 @@
#define to_glink_subdev(d) container_of(d, struct qcom_rproc_glink, subdev) #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_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_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_NUM_OF_SS 10
#define MAX_REGION_NAME_LENGTH 16 #define MAX_REGION_NAME_LENGTH 16
...@@ -519,5 +521,90 @@ void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr) ...@@ -519,5 +521,90 @@ void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr)
} }
EXPORT_SYMBOL_GPL(qcom_remove_ssr_subdev); 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_DESCRIPTION("Qualcomm Remoteproc helper driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -34,6 +34,13 @@ struct qcom_rproc_ssr { ...@@ -34,6 +34,13 @@ struct qcom_rproc_ssr {
struct qcom_ssr_subsystem *info; 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 qcom_minidump(struct rproc *rproc, unsigned int minidump_id,
void (*rproc_dumpfn_t)(struct rproc *rproc, void (*rproc_dumpfn_t)(struct rproc *rproc,
struct rproc_dump_segment *segment, void *dest, size_t offset, 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, ...@@ -52,6 +59,9 @@ void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr,
const char *ssr_name); const char *ssr_name);
void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr); 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) #if IS_ENABLED(CONFIG_QCOM_SYSMON)
struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc, struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
const char *name, const char *name,
......
...@@ -112,6 +112,7 @@ struct qcom_adsp { ...@@ -112,6 +112,7 @@ struct qcom_adsp {
struct dev_pm_domain_list *pd_list; struct dev_pm_domain_list *pd_list;
struct qcom_rproc_glink glink_subdev; struct qcom_rproc_glink glink_subdev;
struct qcom_rproc_pdm pdm_subdev;
struct qcom_rproc_ssr ssr_subdev; struct qcom_rproc_ssr ssr_subdev;
struct qcom_sysmon *sysmon; struct qcom_sysmon *sysmon;
...@@ -726,6 +727,7 @@ static int adsp_probe(struct platform_device *pdev) ...@@ -726,6 +727,7 @@ static int adsp_probe(struct platform_device *pdev)
goto disable_pm; goto disable_pm;
qcom_add_glink_subdev(rproc, &adsp->glink_subdev, desc->ssr_name); 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); qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name);
adsp->sysmon = qcom_add_sysmon_subdev(rproc, adsp->sysmon = qcom_add_sysmon_subdev(rproc,
desc->sysmon_name, desc->sysmon_name,
...@@ -755,6 +757,7 @@ static void adsp_remove(struct platform_device *pdev) ...@@ -755,6 +757,7 @@ static void adsp_remove(struct platform_device *pdev)
qcom_q6v5_deinit(&adsp->q6v5); qcom_q6v5_deinit(&adsp->q6v5);
qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev); 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_sysmon_subdev(adsp->sysmon);
qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev); qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
qcom_rproc_pds_detach(adsp); qcom_rproc_pds_detach(adsp);
......
...@@ -228,6 +228,7 @@ struct q6v5 { ...@@ -228,6 +228,7 @@ struct q6v5 {
struct qcom_rproc_glink glink_subdev; struct qcom_rproc_glink glink_subdev;
struct qcom_rproc_subdev smd_subdev; struct qcom_rproc_subdev smd_subdev;
struct qcom_rproc_pdm pdm_subdev;
struct qcom_rproc_ssr ssr_subdev; struct qcom_rproc_ssr ssr_subdev;
struct qcom_sysmon *sysmon; struct qcom_sysmon *sysmon;
struct platform_device *bam_dmux; struct platform_device *bam_dmux;
...@@ -2102,6 +2103,7 @@ static int q6v5_probe(struct platform_device *pdev) ...@@ -2102,6 +2103,7 @@ static int q6v5_probe(struct platform_device *pdev)
qproc->mba_perm = BIT(QCOM_SCM_VMID_HLOS); qproc->mba_perm = BIT(QCOM_SCM_VMID_HLOS);
qcom_add_glink_subdev(rproc, &qproc->glink_subdev, "mpss"); qcom_add_glink_subdev(rproc, &qproc->glink_subdev, "mpss");
qcom_add_smd_subdev(rproc, &qproc->smd_subdev); 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"); qcom_add_ssr_subdev(rproc, &qproc->ssr_subdev, "mpss");
qproc->sysmon = qcom_add_sysmon_subdev(rproc, "modem", 0x12); qproc->sysmon = qcom_add_sysmon_subdev(rproc, "modem", 0x12);
if (IS_ERR(qproc->sysmon)) { if (IS_ERR(qproc->sysmon)) {
...@@ -2143,6 +2145,7 @@ static void q6v5_remove(struct platform_device *pdev) ...@@ -2143,6 +2145,7 @@ static void q6v5_remove(struct platform_device *pdev)
qcom_q6v5_deinit(&qproc->q6v5); qcom_q6v5_deinit(&qproc->q6v5);
qcom_remove_sysmon_subdev(qproc->sysmon); qcom_remove_sysmon_subdev(qproc->sysmon);
qcom_remove_ssr_subdev(rproc, &qproc->ssr_subdev); 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_smd_subdev(rproc, &qproc->smd_subdev);
qcom_remove_glink_subdev(rproc, &qproc->glink_subdev); qcom_remove_glink_subdev(rproc, &qproc->glink_subdev);
......
...@@ -52,6 +52,7 @@ struct adsp_data { ...@@ -52,6 +52,7 @@ struct adsp_data {
const char *ssr_name; const char *ssr_name;
const char *sysmon_name; const char *sysmon_name;
int ssctl_id; int ssctl_id;
unsigned int smem_host_id;
int region_assign_idx; int region_assign_idx;
int region_assign_count; int region_assign_count;
...@@ -81,6 +82,7 @@ struct qcom_adsp { ...@@ -81,6 +82,7 @@ struct qcom_adsp {
int lite_pas_id; int lite_pas_id;
unsigned int minidump_id; unsigned int minidump_id;
int crash_reason_smem; int crash_reason_smem;
unsigned int smem_host_id;
bool decrypt_shutdown; bool decrypt_shutdown;
const char *info_name; const char *info_name;
...@@ -109,6 +111,7 @@ struct qcom_adsp { ...@@ -109,6 +111,7 @@ struct qcom_adsp {
struct qcom_rproc_glink glink_subdev; struct qcom_rproc_glink glink_subdev;
struct qcom_rproc_subdev smd_subdev; struct qcom_rproc_subdev smd_subdev;
struct qcom_rproc_pdm pdm_subdev;
struct qcom_rproc_ssr ssr_subdev; struct qcom_rproc_ssr ssr_subdev;
struct qcom_sysmon *sysmon; struct qcom_sysmon *sysmon;
...@@ -399,6 +402,9 @@ static int adsp_stop(struct rproc *rproc) ...@@ -399,6 +402,9 @@ static int adsp_stop(struct rproc *rproc)
if (handover) if (handover)
qcom_pas_handover(&adsp->q6v5); qcom_pas_handover(&adsp->q6v5);
if (adsp->smem_host_id)
ret = qcom_smem_bust_hwspin_lock_by_host(adsp->smem_host_id);
return ret; return ret;
} }
...@@ -727,6 +733,7 @@ static int adsp_probe(struct platform_device *pdev) ...@@ -727,6 +733,7 @@ static int adsp_probe(struct platform_device *pdev)
adsp->pas_id = desc->pas_id; adsp->pas_id = desc->pas_id;
adsp->lite_pas_id = desc->lite_pas_id; adsp->lite_pas_id = desc->lite_pas_id;
adsp->info_name = desc->sysmon_name; adsp->info_name = desc->sysmon_name;
adsp->smem_host_id = desc->smem_host_id;
adsp->decrypt_shutdown = desc->decrypt_shutdown; adsp->decrypt_shutdown = desc->decrypt_shutdown;
adsp->region_assign_idx = desc->region_assign_idx; adsp->region_assign_idx = desc->region_assign_idx;
adsp->region_assign_count = min_t(int, MAX_ASSIGN_COUNT, desc->region_assign_count); 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) ...@@ -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_glink_subdev(rproc, &adsp->glink_subdev, desc->ssr_name);
qcom_add_smd_subdev(rproc, &adsp->smd_subdev); qcom_add_smd_subdev(rproc, &adsp->smd_subdev);
qcom_add_pdm_subdev(rproc, &adsp->pdm_subdev);
adsp->sysmon = qcom_add_sysmon_subdev(rproc, adsp->sysmon = qcom_add_sysmon_subdev(rproc,
desc->sysmon_name, desc->sysmon_name,
desc->ssctl_id); desc->ssctl_id);
...@@ -805,6 +813,7 @@ static void adsp_remove(struct platform_device *pdev) ...@@ -805,6 +813,7 @@ static void adsp_remove(struct platform_device *pdev)
qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev); qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
qcom_remove_sysmon_subdev(adsp->sysmon); qcom_remove_sysmon_subdev(adsp->sysmon);
qcom_remove_smd_subdev(adsp->rproc, &adsp->smd_subdev); 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); qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
adsp_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count); adsp_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
device_init_wakeup(adsp->dev, false); device_init_wakeup(adsp->dev, false);
...@@ -1196,6 +1205,7 @@ static const struct adsp_data sm8550_adsp_resource = { ...@@ -1196,6 +1205,7 @@ static const struct adsp_data sm8550_adsp_resource = {
.ssr_name = "lpass", .ssr_name = "lpass",
.sysmon_name = "adsp", .sysmon_name = "adsp",
.ssctl_id = 0x14, .ssctl_id = 0x14,
.smem_host_id = 2,
}; };
static const struct adsp_data sm8550_cdsp_resource = { static const struct adsp_data sm8550_cdsp_resource = {
...@@ -1216,6 +1226,7 @@ static const struct adsp_data sm8550_cdsp_resource = { ...@@ -1216,6 +1226,7 @@ static const struct adsp_data sm8550_cdsp_resource = {
.ssr_name = "cdsp", .ssr_name = "cdsp",
.sysmon_name = "cdsp", .sysmon_name = "cdsp",
.ssctl_id = 0x17, .ssctl_id = 0x17,
.smem_host_id = 5,
}; };
static const struct adsp_data sm8550_mpss_resource = { static const struct adsp_data sm8550_mpss_resource = {
...@@ -1236,6 +1247,7 @@ static const struct adsp_data sm8550_mpss_resource = { ...@@ -1236,6 +1247,7 @@ static const struct adsp_data sm8550_mpss_resource = {
.ssr_name = "mpss", .ssr_name = "mpss",
.sysmon_name = "modem", .sysmon_name = "modem",
.ssctl_id = 0x12, .ssctl_id = 0x12,
.smem_host_id = 1,
.region_assign_idx = 2, .region_assign_idx = 2,
.region_assign_count = 1, .region_assign_count = 1,
.region_assign_vmid = QCOM_SCM_VMID_MSS_MSA, .region_assign_vmid = QCOM_SCM_VMID_MSS_MSA,
...@@ -1275,6 +1287,7 @@ static const struct adsp_data sm8650_cdsp_resource = { ...@@ -1275,6 +1287,7 @@ static const struct adsp_data sm8650_cdsp_resource = {
.ssr_name = "cdsp", .ssr_name = "cdsp",
.sysmon_name = "cdsp", .sysmon_name = "cdsp",
.ssctl_id = 0x17, .ssctl_id = 0x17,
.smem_host_id = 5,
.region_assign_idx = 2, .region_assign_idx = 2,
.region_assign_count = 1, .region_assign_count = 1,
.region_assign_shared = true, .region_assign_shared = true,
...@@ -1299,6 +1312,7 @@ static const struct adsp_data sm8650_mpss_resource = { ...@@ -1299,6 +1312,7 @@ static const struct adsp_data sm8650_mpss_resource = {
.ssr_name = "mpss", .ssr_name = "mpss",
.sysmon_name = "modem", .sysmon_name = "modem",
.ssctl_id = 0x12, .ssctl_id = 0x12,
.smem_host_id = 1,
.region_assign_idx = 2, .region_assign_idx = 2,
.region_assign_count = 3, .region_assign_count = 3,
.region_assign_vmid = QCOM_SCM_VMID_MSS_MSA, .region_assign_vmid = QCOM_SCM_VMID_MSS_MSA,
......
...@@ -148,6 +148,7 @@ struct q6v5_wcss { ...@@ -148,6 +148,7 @@ struct q6v5_wcss {
bool requires_force_stop; bool requires_force_stop;
struct qcom_rproc_glink glink_subdev; struct qcom_rproc_glink glink_subdev;
struct qcom_rproc_pdm pdm_subdev;
struct qcom_rproc_ssr ssr_subdev; struct qcom_rproc_ssr ssr_subdev;
}; };
...@@ -1052,6 +1053,7 @@ static int q6v5_wcss_probe(struct platform_device *pdev) ...@@ -1052,6 +1053,7 @@ static int q6v5_wcss_probe(struct platform_device *pdev)
return ret; return ret;
qcom_add_glink_subdev(rproc, &wcss->glink_subdev, "q6wcss"); 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"); qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss");
if (desc->ssctl_id) if (desc->ssctl_id)
...@@ -1074,6 +1076,7 @@ static void q6v5_wcss_remove(struct platform_device *pdev) ...@@ -1074,6 +1076,7 @@ static void q6v5_wcss_remove(struct platform_device *pdev)
struct q6v5_wcss *wcss = rproc->priv; struct q6v5_wcss *wcss = rproc->priv;
qcom_q6v5_deinit(&wcss->q6v5); qcom_q6v5_deinit(&wcss->q6v5);
qcom_remove_pdm_subdev(rproc, &wcss->pdm_subdev);
rproc_del(rproc); rproc_del(rproc);
} }
......
...@@ -327,7 +327,7 @@ static int k3_dsp_rproc_start(struct rproc *rproc) ...@@ -327,7 +327,7 @@ static int k3_dsp_rproc_start(struct rproc *rproc)
goto put_mbox; 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); ret = ti_sci_proc_set_config(kproc->tsp, boot_addr, 0, 0);
if (ret) if (ret)
goto put_mbox; goto put_mbox;
......
...@@ -1144,6 +1144,7 @@ static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc) ...@@ -1144,6 +1144,7 @@ static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc)
u32 atcm_enable, btcm_enable, loczrama; u32 atcm_enable, btcm_enable, loczrama;
struct k3_r5_core *core0; struct k3_r5_core *core0;
enum cluster_mode mode = cluster->mode; enum cluster_mode mode = cluster->mode;
int reset_ctrl_status;
int ret; int ret;
core0 = list_first_entry(&cluster->cores, struct k3_r5_core, elem); 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) ...@@ -1160,11 +1161,11 @@ static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc)
r_state, c_state); r_state, c_state);
} }
ret = reset_control_status(core->reset); reset_ctrl_status = reset_control_status(core->reset);
if (ret < 0) { if (reset_ctrl_status < 0) {
dev_err(cdev, "failed to get initial local reset status, ret = %d\n", dev_err(cdev, "failed to get initial local reset status, ret = %d\n",
ret); reset_ctrl_status);
return ret; return reset_ctrl_status;
} }
/* /*
...@@ -1199,7 +1200,7 @@ static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc) ...@@ -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 * irrelevant if module reset is asserted (POR value has local reset
* deasserted), and is deemed as remoteproc mode * 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"); dev_info(cdev, "configured R5F for IPC-only mode\n");
kproc->rproc->state = RPROC_DETACHED; kproc->rproc->state = RPROC_DETACHED;
ret = 1; ret = 1;
...@@ -1217,7 +1218,7 @@ static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc) ...@@ -1217,7 +1218,7 @@ static int k3_r5_rproc_configure_mode(struct k3_r5_rproc *kproc)
ret = 0; ret = 0;
} else { } else {
dev_err(cdev, "mismatched mode: local_reset = %s, module_reset = %s, core_state = %s\n", 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", c_state ? "deasserted" : "asserted",
halted ? "halted" : "unhalted"); halted ? "halted" : "unhalted");
ret = -EINVAL; ret = -EINVAL;
......
...@@ -25,6 +25,10 @@ ...@@ -25,6 +25,10 @@
/* RX mailbox client buffer max length */ /* RX mailbox client buffer max length */
#define MBOX_CLIENT_BUF_MAX (IPI_BUF_LEN_MAX + \ #define MBOX_CLIENT_BUF_MAX (IPI_BUF_LEN_MAX + \
sizeof(struct zynqmp_ipi_message)) 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 * settings for RPU cluster mode which
* reflects possible values of xlnx,cluster-mode dt-property * reflects possible values of xlnx,cluster-mode dt-property
...@@ -73,6 +77,26 @@ struct mbox_info { ...@@ -73,6 +77,26 @@ struct mbox_info {
struct mbox_chan *rx_chan; 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 * Hardcoded TCM bank values. This will stay in driver to maintain backward
* compatibility with device-tree that does not have TCM information. * compatibility with device-tree that does not have TCM information.
...@@ -95,20 +119,24 @@ static const struct mem_bank_data zynqmp_tcm_banks_lockstep[] = { ...@@ -95,20 +119,24 @@ static const struct mem_bank_data zynqmp_tcm_banks_lockstep[] = {
/** /**
* struct zynqmp_r5_core * struct zynqmp_r5_core
* *
* @rsc_tbl_va: resource table virtual address
* @dev: device of RPU instance * @dev: device of RPU instance
* @np: device node of RPU instance * @np: device node of RPU instance
* @tcm_bank_count: number TCM banks accessible to this RPU * @tcm_bank_count: number TCM banks accessible to this RPU
* @tcm_banks: array of each TCM bank data * @tcm_banks: array of each TCM bank data
* @rproc: rproc handle * @rproc: rproc handle
* @rsc_tbl_size: resource table size retrieved from remote
* @pm_domain_id: RPU CPU power domain id * @pm_domain_id: RPU CPU power domain id
* @ipi: pointer to mailbox information * @ipi: pointer to mailbox information
*/ */
struct zynqmp_r5_core { struct zynqmp_r5_core {
void __iomem *rsc_tbl_va;
struct device *dev; struct device *dev;
struct device_node *np; struct device_node *np;
int tcm_bank_count; int tcm_bank_count;
struct mem_bank_data **tcm_banks; struct mem_bank_data **tcm_banks;
struct rproc *rproc; struct rproc *rproc;
u32 rsc_tbl_size;
u32 pm_domain_id; u32 pm_domain_id;
struct mbox_info *ipi; struct mbox_info *ipi;
}; };
...@@ -557,6 +585,14 @@ static int add_tcm_banks(struct rproc *rproc) ...@@ -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", dev_dbg(dev, "TCM carveout %s addr=%llx, da=0x%x, size=0x%lx",
bank_name, bank_addr, da, bank_size); 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, rproc_mem = rproc_mem_entry_init(dev, NULL, bank_addr,
bank_size, da, bank_size, da,
tcm_mem_map, tcm_mem_unmap, tcm_mem_map, tcm_mem_unmap,
...@@ -662,6 +698,107 @@ static int zynqmp_r5_rproc_unprepare(struct rproc *rproc) ...@@ -662,6 +698,107 @@ static int zynqmp_r5_rproc_unprepare(struct rproc *rproc)
return 0; 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 = { static const struct rproc_ops zynqmp_r5_rproc_ops = {
.prepare = zynqmp_r5_rproc_prepare, .prepare = zynqmp_r5_rproc_prepare,
.unprepare = zynqmp_r5_rproc_unprepare, .unprepare = zynqmp_r5_rproc_unprepare,
...@@ -673,6 +810,9 @@ static const struct rproc_ops zynqmp_r5_rproc_ops = { ...@@ -673,6 +810,9 @@ static const struct rproc_ops zynqmp_r5_rproc_ops = {
.sanity_check = rproc_elf_sanity_check, .sanity_check = rproc_elf_sanity_check,
.get_boot_addr = rproc_elf_get_boot_addr, .get_boot_addr = rproc_elf_get_boot_addr,
.kick = zynqmp_r5_rproc_kick, .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) ...@@ -723,6 +863,16 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev)
goto free_rproc; 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; r5_core->rproc = r5_rproc;
return r5_core; return r5_core;
...@@ -1134,6 +1284,7 @@ static void zynqmp_r5_cluster_exit(void *data) ...@@ -1134,6 +1284,7 @@ static void zynqmp_r5_cluster_exit(void *data)
for (i = 0; i < cluster->core_count; i++) { for (i = 0; i < cluster->core_count; i++) {
r5_core = cluster->r5_cores[i]; r5_core = cluster->r5_cores[i];
zynqmp_r5_free_mbox(r5_core->ipi); zynqmp_r5_free_mbox(r5_core->ipi);
iounmap(r5_core->rsc_tbl_va);
of_reserved_mem_device_release(r5_core->dev); of_reserved_mem_device_release(r5_core->dev);
put_device(r5_core->dev); put_device(r5_core->dev);
rproc_del(r5_core->rproc); rproc_del(r5_core->rproc);
......
...@@ -359,6 +359,32 @@ static struct qcom_smem *__smem; ...@@ -359,6 +359,32 @@ static struct qcom_smem *__smem;
/* Timeout (ms) for the trylock of remote spinlocks */ /* Timeout (ms) for the trylock of remote spinlocks */
#define HWSPINLOCK_TIMEOUT 1000 #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 * qcom_smem_is_available() - Check if SMEM is available
* *
......
...@@ -15,4 +15,6 @@ phys_addr_t qcom_smem_virt_to_phys(void *p); ...@@ -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_soc_id(u32 *id);
int qcom_smem_get_feature_code(u32 *code); int qcom_smem_get_feature_code(u32 *code);
int qcom_smem_bust_hwspin_lock_by_host(unsigned int host);
#endif #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