summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-03-30 10:50:48 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2022-03-30 10:50:48 -0700
commit2c54e18406345b939d78a2cd755c44800bc31829 (patch)
tree038e9f605b83208f2896c36272a8abacb79bae91 /drivers
parentd177850d5d58320a573dd69eb3f3564856a48a88 (diff)
parent59983c74fc42eb2448df693113bf725abbda05f9 (diff)
downloadlinux-2c54e18406345b939d78a2cd755c44800bc31829.tar.gz
linux-2c54e18406345b939d78a2cd755c44800bc31829.tar.bz2
linux-2c54e18406345b939d78a2cd755c44800bc31829.zip
Merge tag 'rproc-v5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux
Pull remoteproc updates from Bjorn Andersson: "In the remoteproc core, it's now possible to mark the sysfs attributes read only on a per-instance basis, which is then used by the TI wkup M3 driver. Also, the rproc_shutdown() interface propagates errors to the caller and an array underflow is fixed in the debugfs interface. The rproc_da_to_va() API is moved to the public API to allow e.g. child rpmsg devices to acquire pointers to memory shared with the remote processor. The TI K3 R5F and DSP drivers gains support for attaching to instances already started by the bootloader, aka IPC-only mode. The Mediatek remoteproc driver gains support for the MT8186 SCP. The driver's probe function is reordered and moved to use the devres version of rproc_alloc() to save a few gotos. The driver's probe function is also transitioned to use dev_err_probe() to provide better debug support. Support for the Qualcomm SC7280 Wireless Subsystem (WPSS) is introduced. The Hexagon based remoteproc drivers gains support for voting for interconnect bandwidth during launch of the remote processor. The modem subsystem (MSS) driver gains support for probing the BAM-DMUX driver, which provides the network interface towards the modem on a set of older Qualcomm platforms. In addition a number a bug fixes are introduces in the Qualcomm drivers. Lastly Qualcomm ADSP DeviceTree binding is converted to YAML format, to allow validation of DeviceTree source files" * tag 'rproc-v5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux: (22 commits) remoteproc: qcom_q6v5_mss: Create platform device for BAM-DMUX remoteproc: qcom: q6v5_wpss: Add support for sc7280 WPSS dt-bindings: remoteproc: qcom: Add SC7280 WPSS support dt-bindings: remoteproc: qcom: adsp: Convert binding to YAML remoteproc: k3-dsp: Add support for IPC-only mode for all K3 DSPs remoteproc: k3-dsp: Refactor mbox request code in start remoteproc: k3-r5: Add support for IPC-only mode for all R5Fs remoteproc: k3-r5: Refactor mbox request code in start remoteproc: Change rproc_shutdown() to return a status remoteproc: qcom: q6v5: Add interconnect path proxy vote remoteproc: mediatek: Support mt8186 scp dt-bindings: remoteproc: mediatek: Add binding for mt8186 scp remoteproc: qcom_q6v5_mss: Fix some leaks in q6v5_alloc_memory_region remoteproc: qcom_wcnss: Add missing of_node_put() in wcnss_alloc_memory_region remoteproc: qcom: Fix missing of_node_put in adsp_alloc_memory_region remoteproc: move rproc_da_to_va declaration to remoteproc.h remoteproc: wkup_m3: Set sysfs_read_only flag remoteproc: Introduce sysfs_read_only flag remoteproc: Fix count check in rproc_coredump_write() remoteproc: mtk_scp: Use dev_err_probe() where possible ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/remoteproc/mtk_common.h3
-rw-r--r--drivers/remoteproc/mtk_scp.c90
-rw-r--r--drivers/remoteproc/qcom_q6v5.c21
-rw-r--r--drivers/remoteproc/qcom_q6v5.h3
-rw-r--r--drivers/remoteproc/qcom_q6v5_adsp.c228
-rw-r--r--drivers/remoteproc/qcom_q6v5_mss.c19
-rw-r--r--drivers/remoteproc/qcom_wcnss.c1
-rw-r--r--drivers/remoteproc/remoteproc_cdev.c2
-rw-r--r--drivers/remoteproc/remoteproc_core.c9
-rw-r--r--drivers/remoteproc/remoteproc_debugfs.c2
-rw-r--r--drivers/remoteproc/remoteproc_internal.h1
-rw-r--r--drivers/remoteproc/remoteproc_sysfs.c21
-rw-r--r--drivers/remoteproc/ti_k3_dsp_remoteproc.c208
-rw-r--r--drivers/remoteproc/ti_k3_r5_remoteproc.c287
-rw-r--r--drivers/remoteproc/wkup_m3_rproc.c1
15 files changed, 758 insertions, 138 deletions
diff --git a/drivers/remoteproc/mtk_common.h b/drivers/remoteproc/mtk_common.h
index 5ff3867c72f3..71ce4977cb0b 100644
--- a/drivers/remoteproc/mtk_common.h
+++ b/drivers/remoteproc/mtk_common.h
@@ -32,6 +32,9 @@
#define MT8183_SCP_CACHESIZE_8KB BIT(8)
#define MT8183_SCP_CACHE_CON_WAYEN BIT(10)
+#define MT8186_SCP_L1_SRAM_PD_P1 0x40B0
+#define MT8186_SCP_L1_SRAM_PD_p2 0x40B4
+
#define MT8192_L2TCM_SRAM_PD_0 0x10C0
#define MT8192_L2TCM_SRAM_PD_1 0x10C4
#define MT8192_L2TCM_SRAM_PD_2 0x10C8
diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c
index 36e48cf58ed6..38609153bf64 100644
--- a/drivers/remoteproc/mtk_scp.c
+++ b/drivers/remoteproc/mtk_scp.c
@@ -383,6 +383,27 @@ static void mt8192_power_off_sram(void __iomem *addr)
writel(GENMASK(i, 0), addr);
}
+static int mt8186_scp_before_load(struct mtk_scp *scp)
+{
+ /* Clear SCP to host interrupt */
+ writel(MT8183_SCP_IPC_INT_BIT, scp->reg_base + MT8183_SCP_TO_HOST);
+
+ /* Reset clocks before loading FW */
+ writel(0x0, scp->reg_base + MT8183_SCP_CLK_SW_SEL);
+ writel(0x0, scp->reg_base + MT8183_SCP_CLK_DIV_SEL);
+
+ /* Turn on the power of SCP's SRAM before using it. Enable 1 block per time*/
+ mt8192_power_on_sram(scp->reg_base + MT8183_SCP_SRAM_PDN);
+
+ /* Initialize TCM before loading FW. */
+ writel(0x0, scp->reg_base + MT8183_SCP_L1_SRAM_PD);
+ writel(0x0, scp->reg_base + MT8183_SCP_TCM_TAIL_SRAM_PD);
+ writel(0x0, scp->reg_base + MT8186_SCP_L1_SRAM_PD_P1);
+ writel(0x0, scp->reg_base + MT8186_SCP_L1_SRAM_PD_p2);
+
+ return 0;
+}
+
static int mt8192_scp_before_load(struct mtk_scp *scp)
{
/* clear SPM interrupt, SCP2SPM_IPC_CLR */
@@ -756,15 +777,9 @@ static int scp_probe(struct platform_device *pdev)
char *fw_name = "scp.img";
int ret, i;
- rproc = rproc_alloc(dev,
- np->name,
- &scp_ops,
- fw_name,
- sizeof(*scp));
- if (!rproc) {
- dev_err(dev, "unable to allocate remoteproc\n");
- return -ENOMEM;
- }
+ rproc = devm_rproc_alloc(dev, np->name, &scp_ops, fw_name, sizeof(*scp));
+ if (!rproc)
+ return dev_err_probe(dev, -ENOMEM, "unable to allocate remoteproc\n");
scp = (struct mtk_scp *)rproc->priv;
scp->rproc = rproc;
@@ -774,46 +789,42 @@ static int scp_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram");
scp->sram_base = devm_ioremap_resource(dev, res);
- if (IS_ERR((__force void *)scp->sram_base)) {
- dev_err(dev, "Failed to parse and map sram memory\n");
- ret = PTR_ERR((__force void *)scp->sram_base);
- goto free_rproc;
- }
+ if (IS_ERR(scp->sram_base))
+ return dev_err_probe(dev, PTR_ERR(scp->sram_base),
+ "Failed to parse and map sram memory\n");
+
scp->sram_size = resource_size(res);
scp->sram_phys = res->start;
/* l1tcm is an optional memory region */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "l1tcm");
scp->l1tcm_base = devm_ioremap_resource(dev, res);
- if (IS_ERR((__force void *)scp->l1tcm_base)) {
- ret = PTR_ERR((__force void *)scp->l1tcm_base);
+ if (IS_ERR(scp->l1tcm_base)) {
+ ret = PTR_ERR(scp->l1tcm_base);
if (ret != -EINVAL) {
- dev_err(dev, "Failed to map l1tcm memory\n");
- goto free_rproc;
+ return dev_err_probe(dev, ret, "Failed to map l1tcm memory\n");
}
} else {
scp->l1tcm_size = resource_size(res);
scp->l1tcm_phys = res->start;
}
- mutex_init(&scp->send_lock);
- for (i = 0; i < SCP_IPI_MAX; i++)
- mutex_init(&scp->ipi_desc[i].lock);
-
scp->reg_base = devm_platform_ioremap_resource_byname(pdev, "cfg");
- if (IS_ERR((__force void *)scp->reg_base)) {
- dev_err(dev, "Failed to parse and map cfg memory\n");
- ret = PTR_ERR((__force void *)scp->reg_base);
- goto destroy_mutex;
- }
+ if (IS_ERR(scp->reg_base))
+ return dev_err_probe(dev, PTR_ERR(scp->reg_base),
+ "Failed to parse and map cfg memory\n");
- ret = scp_map_memory_region(scp);
+ ret = scp->data->scp_clk_get(scp);
if (ret)
- goto destroy_mutex;
+ return ret;
- ret = scp->data->scp_clk_get(scp);
+ ret = scp_map_memory_region(scp);
if (ret)
- goto release_dev_mem;
+ return ret;
+
+ mutex_init(&scp->send_lock);
+ for (i = 0; i < SCP_IPI_MAX; i++)
+ mutex_init(&scp->ipi_desc[i].lock);
/* register SCP initialization IPI */
ret = scp_ipi_register(scp, SCP_IPI_INIT, scp_init_ipi_handler, scp);
@@ -847,12 +858,9 @@ remove_subdev:
scp_ipi_unregister(scp, SCP_IPI_INIT);
release_dev_mem:
scp_unmap_memory_region(scp);
-destroy_mutex:
for (i = 0; i < SCP_IPI_MAX; i++)
mutex_destroy(&scp->ipi_desc[i].lock);
mutex_destroy(&scp->send_lock);
-free_rproc:
- rproc_free(rproc);
return ret;
}
@@ -887,6 +895,19 @@ static const struct mtk_scp_of_data mt8183_of_data = {
.ipi_buf_offset = 0x7bdb0,
};
+static const struct mtk_scp_of_data mt8186_of_data = {
+ .scp_clk_get = mt8195_scp_clk_get,
+ .scp_before_load = mt8186_scp_before_load,
+ .scp_irq_handler = mt8183_scp_irq_handler,
+ .scp_reset_assert = mt8183_scp_reset_assert,
+ .scp_reset_deassert = mt8183_scp_reset_deassert,
+ .scp_stop = mt8183_scp_stop,
+ .scp_da_to_va = mt8183_scp_da_to_va,
+ .host_to_scp_reg = MT8183_HOST_TO_SCP,
+ .host_to_scp_int_bit = MT8183_HOST_IPC_INT_BIT,
+ .ipi_buf_offset = 0x7bdb0,
+};
+
static const struct mtk_scp_of_data mt8192_of_data = {
.scp_clk_get = mt8192_scp_clk_get,
.scp_before_load = mt8192_scp_before_load,
@@ -913,6 +934,7 @@ static const struct mtk_scp_of_data mt8195_of_data = {
static const struct of_device_id mtk_scp_of_match[] = {
{ .compatible = "mediatek,mt8183-scp", .data = &mt8183_of_data },
+ { .compatible = "mediatek,mt8186-scp", .data = &mt8186_of_data },
{ .compatible = "mediatek,mt8192-scp", .data = &mt8192_of_data },
{ .compatible = "mediatek,mt8195-scp", .data = &mt8195_of_data },
{},
diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c
index 442a388f8102..5280ec9b5449 100644
--- a/drivers/remoteproc/qcom_q6v5.c
+++ b/drivers/remoteproc/qcom_q6v5.c
@@ -8,6 +8,7 @@
*/
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/interconnect.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/soc/qcom/qcom_aoss.h>
@@ -51,9 +52,17 @@ int qcom_q6v5_prepare(struct qcom_q6v5 *q6v5)
{
int ret;
+ ret = icc_set_bw(q6v5->path, 0, UINT_MAX);
+ if (ret < 0) {
+ dev_err(q6v5->dev, "failed to set bandwidth request\n");
+ return ret;
+ }
+
ret = q6v5_load_state_toggle(q6v5, true);
- if (ret)
+ if (ret) {
+ icc_set_bw(q6v5->path, 0, 0);
return ret;
+ }
reinit_completion(&q6v5->start_done);
reinit_completion(&q6v5->stop_done);
@@ -78,6 +87,9 @@ int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5)
disable_irq(q6v5->handover_irq);
q6v5_load_state_toggle(q6v5, false);
+ /* Disable interconnect vote, in case handover never happened */
+ icc_set_bw(q6v5->path, 0, 0);
+
return !q6v5->handover_issued;
}
EXPORT_SYMBOL_GPL(qcom_q6v5_unprepare);
@@ -160,6 +172,8 @@ static irqreturn_t q6v5_handover_interrupt(int irq, void *data)
if (q6v5->handover)
q6v5->handover(q6v5);
+ icc_set_bw(q6v5->path, 0, 0);
+
q6v5->handover_issued = true;
return IRQ_HANDLED;
@@ -332,6 +346,11 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
return load_state ? -ENOMEM : -EINVAL;
}
+ q6v5->path = devm_of_icc_get(&pdev->dev, NULL);
+ if (IS_ERR(q6v5->path))
+ return dev_err_probe(&pdev->dev, PTR_ERR(q6v5->path),
+ "failed to acquire interconnect path\n");
+
return 0;
}
EXPORT_SYMBOL_GPL(qcom_q6v5_init);
diff --git a/drivers/remoteproc/qcom_q6v5.h b/drivers/remoteproc/qcom_q6v5.h
index f35e04471ed7..5a859c41896e 100644
--- a/drivers/remoteproc/qcom_q6v5.h
+++ b/drivers/remoteproc/qcom_q6v5.h
@@ -7,6 +7,7 @@
#include <linux/completion.h>
#include <linux/soc/qcom/qcom_aoss.h>
+struct icc_path;
struct rproc;
struct qcom_smem_state;
struct qcom_sysmon;
@@ -18,6 +19,8 @@ struct qcom_q6v5 {
struct qcom_smem_state *state;
struct qmp *qmp;
+ struct icc_path *path;
+
unsigned stop_bit;
int wdog_irq;
diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
index 098362e6e233..2f3b9f54251e 100644
--- a/drivers/remoteproc/qcom_q6v5_adsp.c
+++ b/drivers/remoteproc/qcom_q6v5_adsp.c
@@ -32,6 +32,7 @@
/* time out value */
#define ACK_TIMEOUT 1000
+#define ACK_TIMEOUT_US 1000000
#define BOOT_FSM_TIMEOUT 10000
/* mask values */
#define EVB_MASK GENMASK(27, 4)
@@ -51,6 +52,8 @@
#define QDSP6SS_CORE_CBCR 0x20
#define QDSP6SS_SLEEP_CBCR 0x3c
+#define QCOM_Q6V5_RPROC_PROXY_PD_MAX 3
+
struct adsp_pil_data {
int crash_reason_smem;
const char *firmware_name;
@@ -58,9 +61,13 @@ struct adsp_pil_data {
const char *ssr_name;
const char *sysmon_name;
int ssctl_id;
+ bool is_wpss;
+ bool auto_boot;
const char **clk_ids;
int num_clks;
+ const char **proxy_pd_names;
+ const char *load_state;
};
struct qcom_adsp {
@@ -93,11 +100,151 @@ struct qcom_adsp {
void *mem_region;
size_t mem_size;
+ struct device *proxy_pds[QCOM_Q6V5_RPROC_PROXY_PD_MAX];
+ size_t proxy_pd_count;
+
struct qcom_rproc_glink glink_subdev;
struct qcom_rproc_ssr ssr_subdev;
struct qcom_sysmon *sysmon;
+
+ int (*shutdown)(struct qcom_adsp *adsp);
};
+static int qcom_rproc_pds_attach(struct device *dev, struct qcom_adsp *adsp,
+ const char **pd_names)
+{
+ struct device **devs = adsp->proxy_pds;
+ size_t num_pds = 0;
+ int ret;
+ int i;
+
+ if (!pd_names)
+ return 0;
+
+ /* Handle single power domain */
+ if (dev->pm_domain) {
+ devs[0] = dev;
+ pm_runtime_enable(dev);
+ return 1;
+ }
+
+ while (pd_names[num_pds])
+ num_pds++;
+
+ if (num_pds > ARRAY_SIZE(adsp->proxy_pds))
+ return -E2BIG;
+
+ for (i = 0; i < num_pds; i++) {
+ devs[i] = dev_pm_domain_attach_by_name(dev, pd_names[i]);
+ if (IS_ERR_OR_NULL(devs[i])) {
+ ret = PTR_ERR(devs[i]) ? : -ENODATA;
+ goto unroll_attach;
+ }
+ }
+
+ return num_pds;
+
+unroll_attach:
+ for (i--; i >= 0; i--)
+ dev_pm_domain_detach(devs[i], false);
+
+ return ret;
+}
+
+static void qcom_rproc_pds_detach(struct qcom_adsp *adsp, struct device **pds,
+ size_t pd_count)
+{
+ struct device *dev = adsp->dev;
+ int i;
+
+ /* Handle single power domain */
+ if (dev->pm_domain && pd_count) {
+ pm_runtime_disable(dev);
+ return;
+ }
+
+ for (i = 0; i < pd_count; i++)
+ dev_pm_domain_detach(pds[i], false);
+}
+
+static int qcom_rproc_pds_enable(struct qcom_adsp *adsp, struct device **pds,
+ size_t pd_count)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < pd_count; i++) {
+ dev_pm_genpd_set_performance_state(pds[i], INT_MAX);
+ ret = pm_runtime_get_sync(pds[i]);
+ if (ret < 0) {
+ pm_runtime_put_noidle(pds[i]);
+ dev_pm_genpd_set_performance_state(pds[i], 0);
+ goto unroll_pd_votes;
+ }
+ }
+
+ return 0;
+
+unroll_pd_votes:
+ for (i--; i >= 0; i--) {
+ dev_pm_genpd_set_performance_state(pds[i], 0);
+ pm_runtime_put(pds[i]);
+ }
+
+ return ret;
+}
+
+static void qcom_rproc_pds_disable(struct qcom_adsp *adsp, struct device **pds,
+ size_t pd_count)
+{
+ int i;
+
+ for (i = 0; i < pd_count; i++) {
+ dev_pm_genpd_set_performance_state(pds[i], 0);
+ pm_runtime_put(pds[i]);
+ }
+}
+
+static int qcom_wpss_shutdown(struct qcom_adsp *adsp)
+{
+ unsigned int val;
+
+ regmap_write(adsp->halt_map, adsp->halt_lpass + LPASS_HALTREQ_REG, 1);
+
+ /* Wait for halt ACK from QDSP6 */
+ regmap_read_poll_timeout(adsp->halt_map,
+ adsp->halt_lpass + LPASS_HALTACK_REG, val,
+ val, 1000, ACK_TIMEOUT_US);
+
+ /* Assert the WPSS PDC Reset */
+ reset_control_assert(adsp->pdc_sync_reset);
+
+ /* Place the WPSS processor into reset */
+ reset_control_assert(adsp->restart);
+
+ /* wait after asserting subsystem restart from AOSS */
+ usleep_range(200, 205);
+
+ /* Remove the WPSS reset */
+ reset_control_deassert(adsp->restart);
+
+ /* De-assert the WPSS PDC Reset */
+ reset_control_deassert(adsp->pdc_sync_reset);
+
+ usleep_range(100, 105);
+
+ clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks);
+
+ regmap_write(adsp->halt_map, adsp->halt_lpass + LPASS_HALTREQ_REG, 0);
+
+ /* Wait for halt ACK from QDSP6 */
+ regmap_read_poll_timeout(adsp->halt_map,
+ adsp->halt_lpass + LPASS_HALTACK_REG, val,
+ !val, 1000, ACK_TIMEOUT_US);
+
+ return 0;
+}
+
static int qcom_adsp_shutdown(struct qcom_adsp *adsp)
{
unsigned long timeout;
@@ -193,12 +340,10 @@ static int adsp_start(struct rproc *rproc)
if (ret)
goto disable_irqs;
- dev_pm_genpd_set_performance_state(adsp->dev, INT_MAX);
- ret = pm_runtime_get_sync(adsp->dev);
- if (ret) {
- pm_runtime_put_noidle(adsp->dev);
+ ret = qcom_rproc_pds_enable(adsp, adsp->proxy_pds,
+ adsp->proxy_pd_count);
+ if (ret < 0)
goto disable_xo_clk;
- }
ret = clk_bulk_prepare_enable(adsp->num_clks, adsp->clks);
if (ret) {
@@ -243,8 +388,7 @@ static int adsp_start(struct rproc *rproc)
disable_adsp_clks:
clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks);
disable_power_domain:
- dev_pm_genpd_set_performance_state(adsp->dev, 0);
- pm_runtime_put(adsp->dev);
+ qcom_rproc_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
disable_xo_clk:
clk_disable_unprepare(adsp->xo);
disable_irqs:
@@ -258,8 +402,7 @@ static void qcom_adsp_pil_handover(struct qcom_q6v5 *q6v5)
struct qcom_adsp *adsp = container_of(q6v5, struct qcom_adsp, q6v5);
clk_disable_unprepare(adsp->xo);
- dev_pm_genpd_set_performance_state(adsp->dev, 0);
- pm_runtime_put(adsp->dev);
+ qcom_rproc_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
}
static int adsp_stop(struct rproc *rproc)
@@ -272,7 +415,7 @@ static int adsp_stop(struct rproc *rproc)
if (ret == -ETIMEDOUT)
dev_err(adsp->dev, "timed out on wait\n");
- ret = qcom_adsp_shutdown(adsp);
+ ret = adsp->shutdown(adsp);
if (ret)
dev_err(adsp->dev, "failed to shutdown: %d\n", ret);
@@ -408,6 +551,7 @@ static int adsp_alloc_memory_region(struct qcom_adsp *adsp)
}
ret = of_address_to_resource(node, 0, &r);
+ of_node_put(node);
if (ret)
return ret;
@@ -427,6 +571,7 @@ static int adsp_alloc_memory_region(struct qcom_adsp *adsp)
static int adsp_probe(struct platform_device *pdev)
{
const struct adsp_pil_data *desc;
+ const char *firmware_name;
struct qcom_adsp *adsp;
struct rproc *rproc;
int ret;
@@ -435,12 +580,22 @@ static int adsp_probe(struct platform_device *pdev)
if (!desc)
return -EINVAL;
+ firmware_name = desc->firmware_name;
+ ret = of_property_read_string(pdev->dev.of_node, "firmware-name",
+ &firmware_name);
+ if (ret < 0 && ret != -EINVAL) {
+ dev_err(&pdev->dev, "unable to read firmware-name\n");
+ return ret;
+ }
+
rproc = rproc_alloc(&pdev->dev, pdev->name, &adsp_ops,
- desc->firmware_name, sizeof(*adsp));
+ firmware_name, sizeof(*adsp));
if (!rproc) {
dev_err(&pdev->dev, "unable to allocate remoteproc\n");
return -ENOMEM;
}
+
+ rproc->auto_boot = desc->auto_boot;
rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
adsp = (struct qcom_adsp *)rproc->priv;
@@ -449,6 +604,11 @@ static int adsp_probe(struct platform_device *pdev)
adsp->info_name = desc->sysmon_name;
platform_set_drvdata(pdev, adsp);
+ if (desc->is_wpss)
+ adsp->shutdown = qcom_wpss_shutdown;
+ else
+ adsp->shutdown = qcom_adsp_shutdown;
+
ret = adsp_alloc_memory_region(adsp);
if (ret)
goto free_rproc;
@@ -457,7 +617,13 @@ static int adsp_probe(struct platform_device *pdev)
if (ret)
goto free_rproc;
- pm_runtime_enable(adsp->dev);
+ ret = qcom_rproc_pds_attach(adsp->dev, adsp,
+ desc->proxy_pd_names);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to attach proxy power domains\n");
+ goto free_rproc;
+ }
+ adsp->proxy_pd_count = ret;
ret = adsp_init_reset(adsp);
if (ret)
@@ -467,8 +633,8 @@ static int adsp_probe(struct platform_device *pdev)
if (ret)
goto disable_pm;
- ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem, NULL,
- qcom_adsp_pil_handover);
+ ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem,
+ desc->load_state, qcom_adsp_pil_handover);
if (ret)
goto disable_pm;
@@ -489,7 +655,8 @@ static int adsp_probe(struct platform_device *pdev)
return 0;
disable_pm:
- pm_runtime_disable(adsp->dev);
+ qcom_rproc_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
+
free_rproc:
rproc_free(rproc);
@@ -506,7 +673,7 @@ static int adsp_remove(struct platform_device *pdev)
qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
qcom_remove_sysmon_subdev(adsp->sysmon);
qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
- pm_runtime_disable(adsp->dev);
+ qcom_rproc_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
rproc_free(adsp->rproc);
return 0;
@@ -518,11 +685,16 @@ static const struct adsp_pil_data adsp_resource_init = {
.ssr_name = "lpass",
.sysmon_name = "adsp",
.ssctl_id = 0x14,
+ .is_wpss = false,
+ .auto_boot = true,
.clk_ids = (const char*[]) {
"sway_cbcr", "lpass_ahbs_aon_cbcr", "lpass_ahbm_aon_cbcr",
"qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core", NULL
},
.num_clks = 7,
+ .proxy_pd_names = (const char*[]) {
+ "cx", NULL
+ },
};
static const struct adsp_pil_data cdsp_resource_init = {
@@ -531,15 +703,39 @@ static const struct adsp_pil_data cdsp_resource_init = {
.ssr_name = "cdsp",
.sysmon_name = "cdsp",
.ssctl_id = 0x17,
+ .is_wpss = false,
+ .auto_boot = true,
.clk_ids = (const char*[]) {
"sway", "tbu", "bimc", "ahb_aon", "q6ss_slave", "q6ss_master",
"q6_axim", NULL
},
.num_clks = 7,
+ .proxy_pd_names = (const char*[]) {
+ "cx", NULL
+ },
+};
+
+static const struct adsp_pil_data wpss_resource_init = {
+ .crash_reason_smem = 626,
+ .firmware_name = "wpss.mdt",
+ .ssr_name = "wpss",
+ .sysmon_name = "wpss",
+ .ssctl_id = 0x19,
+ .is_wpss = true,
+ .auto_boot = false,
+ .load_state = "wpss",
+ .clk_ids = (const char*[]) {
+ "ahb_bdg", "ahb", "rscp", NULL
+ },
+ .num_clks = 3,
+ .proxy_pd_names = (const char*[]) {
+ "cx", "mx", NULL
+ },
};
static const struct of_device_id adsp_of_match[] = {
{ .compatible = "qcom,qcs404-cdsp-pil", .data = &cdsp_resource_init },
+ { .compatible = "qcom,sc7280-wpss-pil", .data = &wpss_resource_init },
{ .compatible = "qcom,sdm845-adsp-pil", .data = &adsp_resource_init },
{ },
};
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
index a2c231a17b2b..af217de75e4d 100644
--- a/drivers/remoteproc/qcom_q6v5_mss.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -218,6 +218,7 @@ struct q6v5 {
struct qcom_rproc_subdev smd_subdev;
struct qcom_rproc_ssr ssr_subdev;
struct qcom_sysmon *sysmon;
+ struct platform_device *bam_dmux;
bool need_mem_protection;
bool has_alt_reset;
bool has_mba_logs;
@@ -1807,18 +1808,20 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc)
* reserved memory regions from device's memory-region property.
*/
child = of_get_child_by_name(qproc->dev->of_node, "mba");
- if (!child)
+ if (!child) {
node = of_parse_phandle(qproc->dev->of_node,
"memory-region", 0);
- else
+ } else {
node = of_parse_phandle(child, "memory-region", 0);
+ of_node_put(child);
+ }
ret = of_address_to_resource(node, 0, &r);
+ of_node_put(node);
if (ret) {
dev_err(qproc->dev, "unable to resolve mba region\n");
return ret;
}
- of_node_put(node);
qproc->mba_phys = r.start;
qproc->mba_size = resource_size(&r);
@@ -1829,14 +1832,15 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc)
} else {
child = of_get_child_by_name(qproc->dev->of_node, "mpss");
node = of_parse_phandle(child, "memory-region", 0);
+ of_node_put(child);
}
ret = of_address_to_resource(node, 0, &r);
+ of_node_put(node);
if (ret) {
dev_err(qproc->dev, "unable to resolve mpss region\n");
return ret;
}
- of_node_put(node);
qproc->mpss_phys = qproc->mpss_reloc = r.start;
qproc->mpss_size = resource_size(&r);
@@ -1847,6 +1851,7 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc)
static int q6v5_probe(struct platform_device *pdev)
{
const struct rproc_hexagon_res *desc;
+ struct device_node *node;
struct q6v5 *qproc;
struct rproc *rproc;
const char *mba_image;
@@ -1990,6 +1995,10 @@ static int q6v5_probe(struct platform_device *pdev)
if (ret)
goto remove_sysmon_subdev;
+ node = of_get_compatible_child(pdev->dev.of_node, "qcom,bam-dmux");
+ qproc->bam_dmux = of_platform_device_create(node, NULL, &pdev->dev);
+ of_node_put(node);
+
return 0;
remove_sysmon_subdev:
@@ -2011,6 +2020,8 @@ static int q6v5_remove(struct platform_device *pdev)
struct q6v5 *qproc = platform_get_drvdata(pdev);
struct rproc *rproc = qproc->rproc;
+ if (qproc->bam_dmux)
+ of_platform_device_destroy(&qproc->bam_dmux->dev, NULL);
rproc_del(rproc);
qcom_q6v5_deinit(&qproc->q6v5);
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index 80bbafee9846..9a223d394087 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -500,6 +500,7 @@ static int wcnss_alloc_memory_region(struct qcom_wcnss *wcnss)
}
ret = of_address_to_resource(node, 0, &r);
+ of_node_put(node);
if (ret)
return ret;
diff --git a/drivers/remoteproc/remoteproc_cdev.c b/drivers/remoteproc/remoteproc_cdev.c
index 4ad98b0b8caa..906ff3c4dfdd 100644
--- a/drivers/remoteproc/remoteproc_cdev.c
+++ b/drivers/remoteproc/remoteproc_cdev.c
@@ -42,7 +42,7 @@ static ssize_t rproc_cdev_write(struct file *filp, const char __user *buf, size_
rproc->state != RPROC_ATTACHED)
return -EINVAL;
- rproc_shutdown(rproc);
+ ret = rproc_shutdown(rproc);
} else if (!strncmp(cmd, "detach", len)) {
if (rproc->state != RPROC_ATTACHED)
return -EINVAL;
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 69f51acf235e..c510125769b9 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -2061,16 +2061,18 @@ EXPORT_SYMBOL(rproc_boot);
* which means that the @rproc handle stays valid even after rproc_shutdown()
* returns, and users can still use it with a subsequent rproc_boot(), if
* needed.
+ *
+ * Return: 0 on success, and an appropriate error value otherwise
*/
-void rproc_shutdown(struct rproc *rproc)
+int rproc_shutdown(struct rproc *rproc)
{
struct device *dev = &rproc->dev;
- int ret;
+ int ret = 0;
ret = mutex_lock_interruptible(&rproc->lock);
if (ret) {
dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, ret);
- return;
+ return ret;
}
/* if the remote proc is still needed, bail out */
@@ -2097,6 +2099,7 @@ void rproc_shutdown(struct rproc *rproc)
rproc->table_ptr = NULL;
out:
mutex_unlock(&rproc->lock);
+ return ret;
}
EXPORT_SYMBOL(rproc_shutdown);
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
index b5a1e3b697d9..581930483ef8 100644
--- a/drivers/remoteproc/remoteproc_debugfs.c
+++ b/drivers/remoteproc/remoteproc_debugfs.c
@@ -76,7 +76,7 @@ static ssize_t rproc_coredump_write(struct file *filp,
int ret, err = 0;
char buf[20];
- if (count > sizeof(buf))
+ if (count < 1 || count > sizeof(buf))
return -EINVAL;
ret = copy_from_user(buf, user_buf, count);
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index a328e634b1de..72d4d3d7d94d 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -84,7 +84,6 @@ static inline void rproc_char_device_remove(struct rproc *rproc)
void rproc_free_vring(struct rproc_vring *rvring);
int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
-void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem);
phys_addr_t rproc_va_to_pa(void *cpu_addr);
int rproc_trigger_recovery(struct rproc *rproc);
diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c
index ea8b89f97d7b..51a04bc6ba7a 100644
--- a/drivers/remoteproc/remoteproc_sysfs.c
+++ b/drivers/remoteproc/remoteproc_sysfs.c
@@ -206,7 +206,7 @@ static ssize_t state_store(struct device *dev,
rproc->state != RPROC_ATTACHED)
return -EINVAL;
- rproc_shutdown(rproc);
+ ret = rproc_shutdown(rproc);
} else if (sysfs_streq(buf, "detach")) {
if (rproc->state != RPROC_ATTACHED)
return -EINVAL;
@@ -230,6 +230,22 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(name);
+static umode_t rproc_is_visible(struct kobject *kobj, struct attribute *attr,
+ int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct rproc *rproc = to_rproc(dev);
+ umode_t mode = attr->mode;
+
+ if (rproc->sysfs_read_only && (attr == &dev_attr_recovery.attr ||
+ attr == &dev_attr_firmware.attr ||
+ attr == &dev_attr_state.attr ||
+ attr == &dev_attr_coredump.attr))
+ mode = 0444;
+
+ return mode;
+}
+
static struct attribute *rproc_attrs[] = {
&dev_attr_coredump.attr,
&dev_attr_recovery.attr,
@@ -240,7 +256,8 @@ static struct attribute *rproc_attrs[] = {
};
static const struct attribute_group rproc_devgroup = {
- .attrs = rproc_attrs
+ .attrs = rproc_attrs,
+ .is_visible = rproc_is_visible,
};
static const struct attribute_group *rproc_devgroups[] = {
diff --git a/drivers/remoteproc/ti_k3_dsp_remoteproc.c b/drivers/remoteproc/ti_k3_dsp_remoteproc.c
index 939c5d90b562..eb9c64f7b9b4 100644
--- a/drivers/remoteproc/ti_k3_dsp_remoteproc.c
+++ b/drivers/remoteproc/ti_k3_dsp_remoteproc.c
@@ -2,7 +2,7 @@
/*
* TI K3 DSP Remote Processor(s) driver
*
- * Copyright (C) 2018-2020 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
* Suman Anna <s-anna@ti.com>
*/
@@ -216,6 +216,43 @@ lreset:
return ret;