Commit 5e3b06d3 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents 3265568d e3cb40d4
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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"
+46 −6
Original line number Diff line number Diff line
@@ -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},
	{ },
};
+4 −5
Original line number Diff line number Diff line
@@ -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) {
+0 −3
Original line number Diff line number Diff line
@@ -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);
}

+93 −7
Original line number Diff line number Diff line
@@ -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,12 +346,26 @@ 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)
{
	struct stm32_rproc *ddata = rproc->priv;
@@ -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),
	},
};