summaryrefslogtreecommitdiffstats
path: root/drivers/mailbox
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-11-06 03:45:32 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2023-11-06 03:45:32 +0100
commit7b2c9e41e73fbe50f519072009b1e624ea230163 (patch)
tree1421f16b223fbad1be032ed1e3774122f0299b71 /drivers/mailbox
parentMerge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost (diff)
parentdt-bindings: mailbox: qcom-ipcc: document the SM8650 Inter-Processor Communic... (diff)
downloadlinux-7b2c9e41e73fbe50f519072009b1e624ea230163.tar.xz
linux-7b2c9e41e73fbe50f519072009b1e624ea230163.zip
Merge tag 'mailbox-v6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/jassibrar/mailbox
Pull mailbox updates from Jassi Brar: - imx: add support for TX Doorbell v2 - mtk: implement runtime PM - zynqmp: add destination mailbox compatible - qcom: - add another clock provider for IPQ - add SM8650 compatible - misc: use preferred device_get_match_data() * tag 'mailbox-v6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/jassibrar/mailbox: dt-bindings: mailbox: qcom-ipcc: document the SM8650 Inter-Processor Communication Controller mailbox: mtk-cmdq-mailbox: Implement Runtime PM with autosuspend mailbox: Use device_get_match_data() dt-bindings: zynqmp: add destination mailbox compatible dt-bindings: mailbox: qcom: add one more clock provider for IPQ mailbox mailbox: imx: support channel type tx doorbell v2 dt-bindings: mailbox: fsl,mu: add new tx doorbell channel
Diffstat (limited to 'drivers/mailbox')
-rw-r--r--drivers/mailbox/bcm-pdc-mailbox.c10
-rw-r--r--drivers/mailbox/imx-mailbox.c32
-rw-r--r--drivers/mailbox/mailbox-sti.c8
-rw-r--r--drivers/mailbox/mtk-cmdq-mailbox.c80
-rw-r--r--drivers/mailbox/ti-msgmgr.c12
5 files changed, 105 insertions, 37 deletions
diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c
index d67db63b482d..778faeced81e 100644
--- a/drivers/mailbox/bcm-pdc-mailbox.c
+++ b/drivers/mailbox/bcm-pdc-mailbox.c
@@ -33,10 +33,9 @@
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/mailbox_controller.h>
#include <linux/mailbox/brcm-message.h>
@@ -1494,7 +1493,6 @@ static int pdc_dt_read(struct platform_device *pdev, struct pdc_state *pdcs)
{
struct device *dev = &pdev->dev;
struct device_node *dn = pdev->dev.of_node;
- const struct of_device_id *match;
const int *hw_type;
int err;
@@ -1509,11 +1507,9 @@ static int pdc_dt_read(struct platform_device *pdev, struct pdc_state *pdcs)
pdcs->hw_type = PDC_HW;
- match = of_match_device(of_match_ptr(pdc_mbox_of_match), dev);
- if (match != NULL) {
- hw_type = match->data;
+ hw_type = device_get_match_data(dev);
+ if (hw_type)
pdcs->hw_type = *hw_type;
- }
return 0;
}
diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
index 3ef4dd8adf5d..0af739ab571c 100644
--- a/drivers/mailbox/imx-mailbox.c
+++ b/drivers/mailbox/imx-mailbox.c
@@ -20,7 +20,9 @@
#include <linux/suspend.h>
#include <linux/slab.h>
-#define IMX_MU_CHANS 17
+#include "mailbox.h"
+
+#define IMX_MU_CHANS 24
/* TX0/RX0/RXDB[0-3] */
#define IMX_MU_SCU_CHANS 6
/* TX0/RX0 */
@@ -39,6 +41,7 @@ enum imx_mu_chan_type {
IMX_MU_TYPE_TXDB = 2, /* Tx doorbell */
IMX_MU_TYPE_RXDB = 3, /* Rx doorbell */
IMX_MU_TYPE_RST = 4, /* Reset */
+ IMX_MU_TYPE_TXDB_V2 = 5, /* Tx doorbell with S/W ACK */
};
enum imx_mu_xcr {
@@ -226,6 +229,9 @@ static int imx_mu_generic_tx(struct imx_mu_priv *priv,
imx_mu_xcr_rmw(priv, IMX_MU_GCR, IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx), 0);
tasklet_schedule(&cp->txdb_tasklet);
break;
+ case IMX_MU_TYPE_TXDB_V2:
+ imx_mu_xcr_rmw(priv, IMX_MU_GCR, IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx), 0);
+ break;
default:
dev_warn_ratelimited(priv->dev, "Send data on wrong channel type: %d\n", cp->type);
return -EINVAL;
@@ -554,6 +560,9 @@ static int imx_mu_startup(struct mbox_chan *chan)
int ret;
pm_runtime_get_sync(priv->dev);
+ if (cp->type == IMX_MU_TYPE_TXDB_V2)
+ return 0;
+
if (cp->type == IMX_MU_TYPE_TXDB) {
/* Tx doorbell don't have ACK support */
tasklet_init(&cp->txdb_tasklet, imx_mu_txdb_tasklet,
@@ -595,6 +604,11 @@ static void imx_mu_shutdown(struct mbox_chan *chan)
int ret;
u32 sr;
+ if (cp->type == IMX_MU_TYPE_TXDB_V2) {
+ pm_runtime_put_sync(priv->dev);
+ return;
+ }
+
if (cp->type == IMX_MU_TYPE_TXDB) {
tasklet_kill(&cp->txdb_tasklet);
pm_runtime_put_sync(priv->dev);
@@ -671,6 +685,7 @@ static struct mbox_chan *imx_mu_specific_xlate(struct mbox_controller *mbox,
static struct mbox_chan * imx_mu_xlate(struct mbox_controller *mbox,
const struct of_phandle_args *sp)
{
+ struct mbox_chan *p_chan;
u32 type, idx, chan;
if (sp->args_count != 2) {
@@ -680,14 +695,25 @@ static struct mbox_chan * imx_mu_xlate(struct mbox_controller *mbox,
type = sp->args[0]; /* channel type */
idx = sp->args[1]; /* index */
- chan = type * 4 + idx;
+ /* RST only supports 1 channel */
+ if ((type == IMX_MU_TYPE_RST) && idx) {
+ dev_err(mbox->dev, "Invalid RST channel %d\n", idx);
+ return ERR_PTR(-EINVAL);
+ }
+
+ chan = type * 4 + idx;
if (chan >= mbox->num_chans) {
dev_err(mbox->dev, "Not supported channel number: %d. (type: %d, idx: %d)\n", chan, type, idx);
return ERR_PTR(-EINVAL);
}
- return &mbox->chans[chan];
+ p_chan = &mbox->chans[chan];
+
+ if (type == IMX_MU_TYPE_TXDB_V2)
+ p_chan->txdone_method = TXDONE_BY_ACK;
+
+ return p_chan;
}
static struct mbox_chan *imx_mu_seco_xlate(struct mbox_controller *mbox,
diff --git a/drivers/mailbox/mailbox-sti.c b/drivers/mailbox/mailbox-sti.c
index 823061dd8c8e..b4b5bdd503cf 100644
--- a/drivers/mailbox/mailbox-sti.c
+++ b/drivers/mailbox/mailbox-sti.c
@@ -17,8 +17,8 @@
#include <linux/mailbox_controller.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include "mailbox.h"
@@ -403,7 +403,6 @@ MODULE_DEVICE_TABLE(of, sti_mailbox_match);
static int sti_mbox_probe(struct platform_device *pdev)
{
- const struct of_device_id *match;
struct mbox_controller *mbox;
struct sti_mbox_device *mdev;
struct device_node *np = pdev->dev.of_node;
@@ -411,12 +410,11 @@ static int sti_mbox_probe(struct platform_device *pdev)
int irq;
int ret;
- match = of_match_device(sti_mailbox_match, &pdev->dev);
- if (!match) {
+ pdev->dev.platform_data = (struct sti_mbox_pdata *)device_get_match_data(&pdev->dev);
+ if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "No configuration found\n");
return -ENODEV;
}
- pdev->dev.platform_data = (struct sti_mbox_pdata *) match->data;
mdev = devm_kzalloc(&pdev->dev, sizeof(*mdev), GFP_KERNEL);
if (!mdev)
diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c
index 4d62b07c1411..de862e9137d5 100644
--- a/drivers/mailbox/mtk-cmdq-mailbox.c
+++ b/drivers/mailbox/mtk-cmdq-mailbox.c
@@ -13,10 +13,13 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/mailbox_controller.h>
#include <linux/mailbox/mtk-cmdq-mailbox.h>
#include <linux/of.h>
+#define CMDQ_MBOX_AUTOSUSPEND_DELAY_MS 100
+
#define CMDQ_OP_CODE_MASK (0xff << CMDQ_OP_CODE_SHIFT)
#define CMDQ_NUM_CMD(t) (t->cmd_buf_size / CMDQ_INST_SIZE)
#define CMDQ_GCE_NUM_MAX (2)
@@ -283,10 +286,8 @@ static void cmdq_thread_irq_handler(struct cmdq *cmdq,
break;
}
- if (list_empty(&thread->task_busy_list)) {
+ if (list_empty(&thread->task_busy_list))
cmdq_thread_disable(cmdq, thread);
- clk_bulk_disable(cmdq->pdata->gce_num, cmdq->clocks);
- }
}
static irqreturn_t cmdq_irq_handler(int irq, void *dev)
@@ -307,9 +308,26 @@ static irqreturn_t cmdq_irq_handler(int irq, void *dev)
spin_unlock_irqrestore(&thread->chan->lock, flags);
}
+ pm_runtime_mark_last_busy(cmdq->mbox.dev);
+
return IRQ_HANDLED;
}
+static int cmdq_runtime_resume(struct device *dev)
+{
+ struct cmdq *cmdq = dev_get_drvdata(dev);
+
+ return clk_bulk_enable(cmdq->pdata->gce_num, cmdq->clocks);
+}
+
+static int cmdq_runtime_suspend(struct device *dev)
+{
+ struct cmdq *cmdq = dev_get_drvdata(dev);
+
+ clk_bulk_disable(cmdq->pdata->gce_num, cmdq->clocks);
+ return 0;
+}
+
static int cmdq_suspend(struct device *dev)
{
struct cmdq *cmdq = dev_get_drvdata(dev);
@@ -333,16 +351,14 @@ static int cmdq_suspend(struct device *dev)
if (cmdq->pdata->sw_ddr_en)
cmdq_sw_ddr_enable(cmdq, false);
- clk_bulk_unprepare(cmdq->pdata->gce_num, cmdq->clocks);
-
- return 0;
+ return pm_runtime_force_suspend(dev);
}
static int cmdq_resume(struct device *dev)
{
struct cmdq *cmdq = dev_get_drvdata(dev);
- WARN_ON(clk_bulk_prepare(cmdq->pdata->gce_num, cmdq->clocks));
+ WARN_ON(pm_runtime_force_resume(dev));
cmdq->suspended = false;
if (cmdq->pdata->sw_ddr_en)
@@ -358,6 +374,9 @@ static int cmdq_remove(struct platform_device *pdev)
if (cmdq->pdata->sw_ddr_en)
cmdq_sw_ddr_enable(cmdq, false);
+ if (!IS_ENABLED(CONFIG_PM))
+ cmdq_runtime_suspend(&pdev->dev);
+
clk_bulk_unprepare(cmdq->pdata->gce_num, cmdq->clocks);
return 0;
}
@@ -369,13 +388,20 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data)
struct cmdq *cmdq = dev_get_drvdata(chan->mbox->dev);
struct cmdq_task *task;
unsigned long curr_pa, end_pa;
+ int ret;
/* Client should not flush new tasks if suspended. */
WARN_ON(cmdq->suspended);
+ ret = pm_runtime_get_sync(cmdq->mbox.dev);
+ if (ret < 0)
+ return ret;
+
task = kzalloc(sizeof(*task), GFP_ATOMIC);
- if (!task)
+ if (!task) {
+ pm_runtime_put_autosuspend(cmdq->mbox.dev);
return -ENOMEM;
+ }
task->cmdq = cmdq;
INIT_LIST_HEAD(&task->list_entry);
@@ -384,8 +410,6 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data)
task->pkt = pkt;
if (list_empty(&thread->task_busy_list)) {
- WARN_ON(clk_bulk_enable(cmdq->pdata->gce_num, cmdq->clocks));
-
/*
* The thread reset will clear thread related register to 0,
* including pc, end, priority, irq, suspend and enable. Thus
@@ -424,6 +448,9 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data)
}
list_move_tail(&task->list_entry, &thread->task_busy_list);
+ pm_runtime_mark_last_busy(cmdq->mbox.dev);
+ pm_runtime_put_autosuspend(cmdq->mbox.dev);
+
return 0;
}
@@ -439,6 +466,8 @@ static void cmdq_mbox_shutdown(struct mbox_chan *chan)
struct cmdq_task *task, *tmp;
unsigned long flags;
+ WARN_ON(pm_runtime_get_sync(cmdq->mbox.dev));
+
spin_lock_irqsave(&thread->chan->lock, flags);
if (list_empty(&thread->task_busy_list))
goto done;
@@ -457,7 +486,6 @@ static void cmdq_mbox_shutdown(struct mbox_chan *chan)
}
cmdq_thread_disable(cmdq, thread);
- clk_bulk_disable(cmdq->pdata->gce_num, cmdq->clocks);
done:
/*
@@ -467,6 +495,9 @@ done:
* to do any operation here, only unlock and leave.
*/
spin_unlock_irqrestore(&thread->chan->lock, flags);
+
+ pm_runtime_mark_last_busy(cmdq->mbox.dev);
+ pm_runtime_put_autosuspend(cmdq->mbox.dev);
}
static int cmdq_mbox_flush(struct mbox_chan *chan, unsigned long timeout)
@@ -477,6 +508,11 @@ static int cmdq_mbox_flush(struct mbox_chan *chan, unsigned long timeout)
struct cmdq_task *task, *tmp;
unsigned long flags;
u32 enable;
+ int ret;
+
+ ret = pm_runtime_get_sync(cmdq->mbox.dev);
+ if (ret < 0)
+ return ret;
spin_lock_irqsave(&thread->chan->lock, flags);
if (list_empty(&thread->task_busy_list))
@@ -497,10 +533,12 @@ static int cmdq_mbox_flush(struct mbox_chan *chan, unsigned long timeout)
cmdq_thread_resume(thread);
cmdq_thread_disable(cmdq, thread);
- clk_bulk_disable(cmdq->pdata->gce_num, cmdq->clocks);
out:
spin_unlock_irqrestore(&thread->chan->lock, flags);
+ pm_runtime_mark_last_busy(cmdq->mbox.dev);
+ pm_runtime_put_autosuspend(cmdq->mbox.dev);
+
return 0;
wait:
@@ -513,6 +551,8 @@ wait:
return -EFAULT;
}
+ pm_runtime_mark_last_busy(cmdq->mbox.dev);
+ pm_runtime_put_autosuspend(cmdq->mbox.dev);
return 0;
}
@@ -642,12 +682,28 @@ static int cmdq_probe(struct platform_device *pdev)
return err;
}
+ /* If Runtime PM is not available enable the clocks now. */
+ if (!IS_ENABLED(CONFIG_PM)) {
+ err = cmdq_runtime_resume(dev);
+ if (err)
+ return err;
+ }
+
+ err = devm_pm_runtime_enable(dev);
+ if (err)
+ return err;
+
+ pm_runtime_set_autosuspend_delay(dev, CMDQ_MBOX_AUTOSUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(dev);
+
return 0;
}
static const struct dev_pm_ops cmdq_pm_ops = {
.suspend = cmdq_suspend,
.resume = cmdq_resume,
+ SET_RUNTIME_PM_OPS(cmdq_runtime_suspend,
+ cmdq_runtime_resume, NULL)
};
static const struct gce_plat gce_plat_v2 = {
diff --git a/drivers/mailbox/ti-msgmgr.c b/drivers/mailbox/ti-msgmgr.c
index a94577f16a47..9d2d4ff6cda4 100644
--- a/drivers/mailbox/ti-msgmgr.c
+++ b/drivers/mailbox/ti-msgmgr.c
@@ -15,10 +15,10 @@
#include <linux/kernel.h>
#include <linux/mailbox_controller.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/soc/ti/ti-msgmgr.h>
#define Q_DATA_OFFSET(proxy, queue, reg) \
@@ -810,7 +810,6 @@ MODULE_DEVICE_TABLE(of, ti_msgmgr_of_match);
static int ti_msgmgr_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- const struct of_device_id *of_id;
struct device_node *np;
const struct ti_msgmgr_desc *desc;
struct ti_msgmgr_inst *inst;
@@ -828,19 +827,12 @@ static int ti_msgmgr_probe(struct platform_device *pdev)
}
np = dev->of_node;
- of_id = of_match_device(ti_msgmgr_of_match, dev);
- if (!of_id) {
- dev_err(dev, "OF data missing\n");
- return -EINVAL;
- }
- desc = of_id->data;
-
inst = devm_kzalloc(dev, sizeof(*inst), GFP_KERNEL);
if (!inst)
return -ENOMEM;
inst->dev = dev;
- inst->desc = desc;
+ inst->desc = desc = device_get_match_data(dev);
inst->queue_proxy_region =
devm_platform_ioremap_resource_byname(pdev, desc->data_region_name);