diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt index 41ca5df5be5ac78537ea6312214d00b08bafe3be..c416746f93cfdc86fd62551ca5b05e5f3b14c2e2 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt +++ b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt @@ -12,6 +12,7 @@ on the Qualcomm Hexagon core. "qcom,msm8916-mss-pil", "qcom,msm8974-mss-pil" "qcom,msm8996-mss-pil" + "qcom,msm8998-mss-pil" "qcom,sdm845-mss-pil" - reg: @@ -41,6 +42,7 @@ on the Qualcomm Hexagon core. qcom,msm8974-mss-pil: must be "wdog", "fatal", "ready", "handover", "stop-ack" qcom,msm8996-mss-pil: + qcom,msm8998-mss-pil: qcom,sdm845-mss-pil: must be "wdog", "fatal", "ready", "handover", "stop-ack", "shutdown-ack" @@ -70,6 +72,9 @@ on the Qualcomm Hexagon core. qcom,msm8996-mss-pil: must be "iface", "bus", "mem", "xo", "gpll0_mss", "snoc_axi", "mnoc_axi", "pnoc", "qdss" + qcom,msm8998-mss-pil: + must be "iface", "bus", "mem", "xo", "gpll0_mss", + "snoc_axi", "mnoc_axi", "qdss" qcom,sdm845-mss-pil: must be "iface", "bus", "mem", "xo", "gpll0_mss", "snoc_axi", "mnoc_axi", "prng" @@ -137,6 +142,7 @@ For the compatible string below the following supplies are required: qcom,msm8974-mss-pil: no power-domain names required qcom,msm8996-mss-pil: + qcom,msm8998-mss-pil: must be "cx", "mx" qcom,sdm845-mss-pil: must be "cx", "mx", "mss", "load_state" diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index de919f2e8b949c3184586c7ac7450a7d3e101a08..471128a2e72392a179294bdffcb2358fe75dc338 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -61,6 +61,7 @@ #define QDSP6SS_GFMUX_CTL_REG 0x020 #define QDSP6SS_PWR_CTL_REG 0x030 #define QDSP6SS_MEM_PWR_CTL 0x0B0 +#define QDSP6V6SS_MEM_PWR_CTL 0x034 #define QDSP6SS_STRAP_ACC 0x110 /* AXI Halt Register Offsets */ @@ -196,6 +197,7 @@ enum { MSS_MSM8916, MSS_MSM8974, MSS_MSM8996, + MSS_MSM8998, MSS_SDM845, }; @@ -498,7 +500,10 @@ static int q6v5proc_reset(struct q6v5 *qproc) } goto pbl_wait; - } else if (qproc->version == MSS_MSM8996) { + } else if (qproc->version == MSS_MSM8996 || + qproc->version == MSS_MSM8998) { + int mem_pwr_ctl; + /* Override the ACC value if required */ writel(QDSP6SS_ACC_OVERRIDE_VAL, qproc->reg_base + QDSP6SS_STRAP_ACC); @@ -543,17 +548,24 @@ static int q6v5proc_reset(struct q6v5 *qproc) writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); /* Turn on L1, L2, ETB and JU memories 1 at a time */ - val = readl(qproc->reg_base + QDSP6SS_MEM_PWR_CTL); - for (i = 19; i >= 0; i--) { + if (qproc->version == MSS_MSM8996) { + mem_pwr_ctl = QDSP6SS_MEM_PWR_CTL; + i = 19; + } else { + /* MSS_MSM8998 */ + mem_pwr_ctl = QDSP6V6SS_MEM_PWR_CTL; + i = 28; + } + val = readl(qproc->reg_base + mem_pwr_ctl); + for (; i >= 0; i--) { val |= BIT(i); - writel(val, qproc->reg_base + - QDSP6SS_MEM_PWR_CTL); + writel(val, qproc->reg_base + mem_pwr_ctl); /* * Read back value to ensure the write is done then * wait for 1us for both memory peripheral and data * array to turn on. */ - val |= readl(qproc->reg_base + QDSP6SS_MEM_PWR_CTL); + val |= readl(qproc->reg_base + mem_pwr_ctl); udelay(1); } /* Remove word line clamp */ @@ -1571,6 +1583,33 @@ static const struct rproc_hexagon_res sdm845_mss = { .version = MSS_SDM845, }; +static const struct rproc_hexagon_res msm8998_mss = { + .hexagon_mba_image = "mba.mbn", + .proxy_clk_names = (char*[]){ + "xo", + "qdss", + "mem", + NULL + }, + .active_clk_names = (char*[]){ + "iface", + "bus", + "mem", + "gpll0_mss", + "mnoc_axi", + "snoc_axi", + NULL + }, + .proxy_pd_names = (char*[]){ + "cx", + "mx", + NULL + }, + .need_mem_protection = true, + .has_alt_reset = false, + .version = MSS_MSM8998, +}; + static const struct rproc_hexagon_res msm8996_mss = { .hexagon_mba_image = "mba.mbn", .proxy_supply = (struct qcom_mss_reg_res[]) { @@ -1677,6 +1716,7 @@ static const struct of_device_id q6v5_of_match[] = { { .compatible = "qcom,msm8916-mss-pil", .data = &msm8916_mss}, { .compatible = "qcom,msm8974-mss-pil", .data = &msm8974_mss}, { .compatible = "qcom,msm8996-mss-pil", .data = &msm8996_mss}, + { .compatible = "qcom,msm8998-mss-pil", .data = &msm8998_mss}, { .compatible = "qcom,sdm845-mss-pil", .data = &sdm845_mss}, { }, }; diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 3c5fbbbfb0f17c6104589a9fcace6aab00c88db7..307df98347ba24188d196e11f4cc29f3e7667202 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -44,8 +44,6 @@ static DEFINE_MUTEX(rproc_list_mutex); static LIST_HEAD(rproc_list); -typedef int (*rproc_handle_resources_t)(struct rproc *rproc, - struct resource_table *table, int len); typedef int (*rproc_handle_resource_t)(struct rproc *rproc, void *, int offset, int avail); @@ -336,7 +334,8 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i) return -ENOMEM; } else { /* Register carveout in in list */ - mem = rproc_mem_entry_init(dev, 0, 0, size, rsc->vring[i].da, + mem = rproc_mem_entry_init(dev, NULL, 0, + size, rsc->vring[i].da, rproc_alloc_carveout, rproc_release_carveout, "vdev%dvring%d", @@ -400,7 +399,7 @@ rproc_parse_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i) void rproc_free_vring(struct rproc_vring *rvring) { struct rproc *rproc = rvring->rvdev->rproc; - int idx = rvring->rvdev->vring - rvring; + int idx = rvring - rvring->rvdev->vring; struct fw_rsc_vdev *rsc; idr_remove(&rproc->notifyids, rvring->notifyid); @@ -913,7 +912,7 @@ static int rproc_handle_carveout(struct rproc *rproc, } /* Register carveout in in list */ - carveout = rproc_mem_entry_init(dev, 0, 0, rsc->len, rsc->da, + carveout = rproc_mem_entry_init(dev, NULL, 0, rsc->len, rsc->da, rproc_alloc_carveout, rproc_release_carveout, rsc->name); if (!carveout) { diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 8cd4a0a3892b45be739c1c521828026911799486..dd93cf04e17f262f60176dd66b83a05f08b177eb 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -333,9 +333,6 @@ struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc, void rproc_delete_debug_dir(struct rproc *rproc) { - if (!rproc->dbg_dir) - return; - debugfs_remove_recursive(rproc->dbg_dir); } diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c index 2cf4b2992bfcdfa33a9dd091a8360c1d1feecad8..a18f8804411199daa78b933afa807a91ea58d16a 100644 --- a/drivers/remoteproc/stm32_rproc.c +++ b/drivers/remoteproc/stm32_rproc.c @@ -15,9 +15,11 @@ #include #include #include +#include #include #include #include +#include #include "remoteproc_internal.h" @@ -31,7 +33,9 @@ #define STM32_SMC_REG_WRITE 0x1 #define STM32_MBX_VQ0 "vq0" +#define STM32_MBX_VQ0_ID 0 #define STM32_MBX_VQ1 "vq1" +#define STM32_MBX_VQ1_ID 1 #define STM32_MBX_SHUTDOWN "shutdown" struct stm32_syscon { @@ -58,6 +62,7 @@ struct stm32_mbox { const unsigned char name[10]; struct mbox_chan *chan; struct mbox_client client; + struct work_struct vq_work; int vq_id; }; @@ -65,9 +70,11 @@ struct stm32_rproc { struct reset_control *rst; struct stm32_syscon hold_boot; struct stm32_syscon pdds; + int wdg_irq; u32 nb_rmems; struct stm32_rproc_mem *rmems; struct stm32_mbox mb[MBOX_NB_MBX]; + struct workqueue_struct *workqueue; bool secured_soc; }; @@ -261,13 +268,22 @@ static irqreturn_t stm32_rproc_wdg(int irq, void *data) return IRQ_HANDLED; } +static void stm32_rproc_mb_vq_work(struct work_struct *work) +{ + struct stm32_mbox *mb = container_of(work, struct stm32_mbox, vq_work); + struct rproc *rproc = dev_get_drvdata(mb->client.dev); + + if (rproc_vq_interrupt(rproc, mb->vq_id) == IRQ_NONE) + dev_dbg(&rproc->dev, "no message found in vq%d\n", mb->vq_id); +} + static void stm32_rproc_mb_callback(struct mbox_client *cl, void *data) { struct rproc *rproc = dev_get_drvdata(cl->dev); struct stm32_mbox *mb = container_of(cl, struct stm32_mbox, client); + struct stm32_rproc *ddata = rproc->priv; - if (rproc_vq_interrupt(rproc, mb->vq_id) == IRQ_NONE) - dev_dbg(&rproc->dev, "no message found in vq%d\n", mb->vq_id); + queue_work(ddata->workqueue, &mb->vq_work); } static void stm32_rproc_free_mbox(struct rproc *rproc) @@ -285,7 +301,7 @@ static void stm32_rproc_free_mbox(struct rproc *rproc) static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = { { .name = STM32_MBX_VQ0, - .vq_id = 0, + .vq_id = STM32_MBX_VQ0_ID, .client = { .rx_callback = stm32_rproc_mb_callback, .tx_block = false, @@ -293,7 +309,7 @@ static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = { }, { .name = STM32_MBX_VQ1, - .vq_id = 1, + .vq_id = STM32_MBX_VQ1_ID, .client = { .rx_callback = stm32_rproc_mb_callback, .tx_block = false, @@ -310,11 +326,12 @@ static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = { } }; -static void stm32_rproc_request_mbox(struct rproc *rproc) +static int stm32_rproc_request_mbox(struct rproc *rproc) { struct stm32_rproc *ddata = rproc->priv; struct device *dev = &rproc->dev; unsigned int i; + int j; const unsigned char *name; struct mbox_client *cl; @@ -329,10 +346,24 @@ static void stm32_rproc_request_mbox(struct rproc *rproc) ddata->mb[i].chan = mbox_request_channel_byname(cl, name); if (IS_ERR(ddata->mb[i].chan)) { + if (PTR_ERR(ddata->mb[i].chan) == -EPROBE_DEFER) + goto err_probe; dev_warn(dev, "cannot get %s mbox\n", name); ddata->mb[i].chan = NULL; } + if (ddata->mb[i].vq_id >= 0) { + INIT_WORK(&ddata->mb[i].vq_work, + stm32_rproc_mb_vq_work); + } } + + return 0; + +err_probe: + for (j = i - 1; j >= 0; j--) + if (ddata->mb[j].chan) + mbox_free_channel(ddata->mb[j].chan); + return -EPROBE_DEFER; } static int stm32_rproc_set_hold_boot(struct rproc *rproc, bool hold) @@ -528,6 +559,13 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev) return err; } + ddata->wdg_irq = irq; + + if (of_property_read_bool(np, "wakeup-source")) { + device_init_wakeup(dev, true); + dev_pm_set_wake_irq(dev, irq); + } + dev_info(dev, "wdg irq registered\n"); } @@ -589,14 +627,22 @@ static int stm32_rproc_probe(struct platform_device *pdev) rproc->has_iommu = false; ddata = rproc->priv; + ddata->workqueue = create_workqueue(dev_name(dev)); + if (!ddata->workqueue) { + dev_err(dev, "cannot create workqueue\n"); + ret = -ENOMEM; + goto free_rproc; + } platform_set_drvdata(pdev, rproc); ret = stm32_rproc_parse_dt(pdev); if (ret) - goto free_rproc; + goto free_wkq; - stm32_rproc_request_mbox(rproc); + ret = stm32_rproc_request_mbox(rproc); + if (ret) + goto free_rproc; ret = rproc_add(rproc); if (ret) @@ -606,7 +652,13 @@ static int stm32_rproc_probe(struct platform_device *pdev) free_mb: stm32_rproc_free_mbox(rproc); +free_wkq: + destroy_workqueue(ddata->workqueue); free_rproc: + if (device_may_wakeup(dev)) { + dev_pm_clear_wake_irq(dev); + device_init_wakeup(dev, false); + } rproc_free(rproc); return ret; } @@ -614,22 +666,56 @@ static int stm32_rproc_probe(struct platform_device *pdev) static int stm32_rproc_remove(struct platform_device *pdev) { struct rproc *rproc = platform_get_drvdata(pdev); + struct stm32_rproc *ddata = rproc->priv; + struct device *dev = &pdev->dev; if (atomic_read(&rproc->power) > 0) rproc_shutdown(rproc); rproc_del(rproc); stm32_rproc_free_mbox(rproc); + destroy_workqueue(ddata->workqueue); + + if (device_may_wakeup(dev)) { + dev_pm_clear_wake_irq(dev); + device_init_wakeup(dev, false); + } rproc_free(rproc); return 0; } +static int __maybe_unused stm32_rproc_suspend(struct device *dev) +{ + struct rproc *rproc = dev_get_drvdata(dev); + struct stm32_rproc *ddata = rproc->priv; + + if (device_may_wakeup(dev)) + return enable_irq_wake(ddata->wdg_irq); + + return 0; +} + +static int __maybe_unused stm32_rproc_resume(struct device *dev) +{ + struct rproc *rproc = dev_get_drvdata(dev); + struct stm32_rproc *ddata = rproc->priv; + + if (device_may_wakeup(dev)) + return disable_irq_wake(ddata->wdg_irq); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(stm32_rproc_pm_ops, + stm32_rproc_suspend, stm32_rproc_resume); + static struct platform_driver stm32_rproc_driver = { .probe = stm32_rproc_probe, .remove = stm32_rproc_remove, .driver = { .name = "stm32-rproc", + .pm = &stm32_rproc_pm_ops, .of_match_table = of_match_ptr(stm32_rproc_match), }, };