remoteproc updates for v5.5
This adds support for booting the modem processor on Qualcomm MSM8998 and carries some cleanup up and bug fixes to the framework and the stm32 driver. -----BEGIN PGP SIGNATURE----- iQJPBAABCAA5FiEEBd4DzF816k8JZtUlCx85Pw2ZrcUFAl3ivF0bHGJqb3JuLmFu ZGVyc3NvbkBsaW5hcm8ub3JnAAoJEAsfOT8Nma3FWQEP/AkWFMCzfergOjwEAbVC 0sTEX9nj2b2mA4s3PsPVp79AgTXQQbTShohtDTtiwa7a7ZGlLEXVgSe7XjKm5ELT S66Vh+KOvjzjQDTkwADy5PZ+u0pTnZFyUCXZ/lVYnVjAbyy5ZmqGJMOUnQPpPAJv +Scd0l8Find6FDjnwPIKSbUvnF1diHIlSofjgCziSGNHBCxm8HZ1Bi1TcOyfuz3M 2oOXr8V6ztKo6ScOe68nKCwAtbPj+X2EawTtYVgBaSV2uI65W1Dqe+oX/UA+TklO 0XAVULxFKvrrbbbTM1+iWGzo/7bqhGwwoJbkh/pSknO/F4w1QNEPiyPcoU8tHzX/ RtgBufWj//F5eiZUCKNuHtnFF7eBSfNMM6tKNdOpJeWeNtCJ209WcDOMJH2R4tGB 3R6ZkTmVxTw6Ghm7G4HGhcbol4M3KM1vAHxd7PH1jZUonMU6XGyLiXYSuC7jwFXm FCK7O+xBYPbLP4wwH0N12dF649b+ZNQMj2bhSzKh1YpXqKlLEnxUSLsIuZpWN35K MAy06UBoj6ETcls+ReZMrhwRDjcciJgYVMCcTJmoFv3eiQmHo1bh8RHlKMVpu/ak f3MC/v2pG7lNA24rCqnNX24MqOqCUwLKdaHLHFhdIGm/GAm8n6lyrDs53MxtW+kY b2NpUCj7V/W+IDuECU4KX7Tr =TxbM -----END PGP SIGNATURE----- Merge tag 'rproc-v5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc Pull remoteproc updates from Bjorn Andersson: "This adds support for booting the modem processor on Qualcomm MSM8998 and carries some cleanup up and bug fixes to the framework and the stm32 driver" * tag 'rproc-v5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc: Revert "dt-bindings: remoteproc: stm32: add wakeup-source" remoteproc: stm32: fix probe error case remoteproc: stm32: wakeup the system by wdg irq dt-bindings: remoteproc: stm32: add wakeup-source remoteproc: Fix wrong rvring index computation remoteproc: stm32: use workqueue to treat mailbox callback remoteproc: fix argument 2 of rproc_mem_entry_init remoteproc: qcom_q6v5_mss: Add support for MSM8998 dt-bindings: remoteproc: qcom: Add Q6v5 Modem PIL binding for MSM8998 remoteproc: debug: Remove unneeded NULL check remoteproc: remove useless typedef
This commit is contained in:
commit
5e3b06d3bb
|
@ -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"
|
||||
|
|
|
@ -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},
|
||||
{ },
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,9 +15,11 @@
|
|||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/remoteproc.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#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 @@ free_rproc:
|
|||
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),
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue