diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-05-27 00:57:25 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-05-27 00:57:25 +0300 |
commit | cdeffe87f790dfd1baa193020411ce9a538446d7 (patch) | |
tree | 89488a1afbf4032f7361219a6590e48107bdc494 /drivers | |
parent | 7182e897695d5b70fb772736f1f08639ca0fff78 (diff) | |
parent | 79f9fbe303520d2c32b70f04f2bb02cc2baaa4c3 (diff) | |
download | linux-cdeffe87f790dfd1baa193020411ce9a538446d7.tar.xz |
Merge tag 'mailbox-v5.19' of git://git.linaro.org/landing-teams/working/fujitsu/integration
Pull mailbox updates from Jassi Brar:
"api:
- hrtimer fix
qcom:
- log pending irq during resume
- minor cosmetic changes
omap:
- use pm_runtime_resume_and_get
imx:
- use pm_runtime_resume_and_get
- remove redundant initializer
mtk:
- added GCE header for MT8186
- enable support for MT8186
tegra:
- remove redundant NULL check
- added hsp_sm_ops for send/recv api
- support shared mailboxes
stm:
- remove unsupported "wakeup" irq
pcc:
- sanitize mbox allocated memory before use
misc:
- documentation fixes for arm_mhu and qcom-ipcc"
* tag 'mailbox-v5.19' of git://git.linaro.org/landing-teams/working/fujitsu/integration:
mailbox: qcom-ipcc: Fix -Wunused-function with CONFIG_PM_SLEEP=n
mailbox: forward the hrtimer if not queued and under a lock
mailbox: qcom-ipcc: Log the pending interrupt during resume
mailbox: pcc: Fix an invalid-load caught by the address sanitizer
dt-bindings: mailbox: remove the IPCC "wakeup" IRQ
mailbox: correct kerneldoc
mailbox: omap: using pm_runtime_resume_and_get to simplify the code
mailbox:imx: using pm_runtime_resume_and_get
mailbox: mediatek: support mt8186 adsp mailbox
dt-bindings: mailbox: mtk,adsp-mbox: add mt8186 compatible name
mailbox: tegra-hsp: Add 128-bit shared mailbox support
dt-bindings: tegra186-hsp: add type for shared mailboxes
mailbox: tegra-hsp: Add tegra_hsp_sm_ops
dt-bindings: gce: add the GCE header file for MT8186
mailbox: remove an unneeded NULL check on list iterator
mailbox: imx: remove redundant initializer
dt-bindings: mailbox: qcom-ipcc: simplify the example
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mailbox/arm_mhu_db.c | 2 | ||||
-rw-r--r-- | drivers/mailbox/arm_mhuv2.c | 3 | ||||
-rw-r--r-- | drivers/mailbox/imx-mailbox.c | 7 | ||||
-rw-r--r-- | drivers/mailbox/mailbox.c | 19 | ||||
-rw-r--r-- | drivers/mailbox/mtk-adsp-mailbox.c | 8 | ||||
-rw-r--r-- | drivers/mailbox/omap-mailbox.c | 6 | ||||
-rw-r--r-- | drivers/mailbox/pcc.c | 2 | ||||
-rw-r--r-- | drivers/mailbox/qcom-ipcc.c | 26 | ||||
-rw-r--r-- | drivers/mailbox/tegra-hsp.c | 151 |
9 files changed, 175 insertions, 49 deletions
diff --git a/drivers/mailbox/arm_mhu_db.c b/drivers/mailbox/arm_mhu_db.c index 8674153cc893..aa0a4d83880f 100644 --- a/drivers/mailbox/arm_mhu_db.c +++ b/drivers/mailbox/arm_mhu_db.c @@ -44,7 +44,7 @@ struct arm_mhu { }; /** - * ARM MHU Mailbox allocated channel information + * struct mhu_db_channel - ARM MHU Mailbox allocated channel information * * @mhu: Pointer to parent mailbox device * @pchan: Physical channel within which this doorbell resides in diff --git a/drivers/mailbox/arm_mhuv2.c b/drivers/mailbox/arm_mhuv2.c index d997f8ebfa98..a47aef8df52f 100644 --- a/drivers/mailbox/arm_mhuv2.c +++ b/drivers/mailbox/arm_mhuv2.c @@ -160,7 +160,8 @@ enum mhuv2_frame { * struct mhuv2 - MHUv2 mailbox controller data * * @mbox: Mailbox controller belonging to the MHU frame. - * @send/recv: Base address of the register mapping region. + * @send: Base address of the register mapping region. + * @recv: Base address of the register mapping region. * @frame: Frame type: RECEIVER_FRAME or SENDER_FRAME. * @irq: Interrupt. * @windows: Channel windows implemented by the platform. diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index e88f544a1548..b10239d6ef93 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -830,11 +830,9 @@ static int imx_mu_probe(struct platform_device *pdev) pm_runtime_enable(dev); - ret = pm_runtime_get_sync(dev); - if (ret < 0) { - pm_runtime_put_noidle(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) goto disable_runtime_pm; - } ret = pm_runtime_put_sync(dev); if (ret < 0) @@ -886,7 +884,6 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp = { .rx = imx_mu_generic_rx, .rxdb = imx_mu_generic_rxdb, .init = imx_mu_init_generic, - .rxdb = imx_mu_generic_rxdb, .type = IMX_MU_V2, .xTR = 0x200, .xRR = 0x280, diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index 3e7d4b20ab34..4229b9b5da98 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -82,11 +82,11 @@ static void msg_submit(struct mbox_chan *chan) exit: spin_unlock_irqrestore(&chan->lock, flags); - /* kick start the timer immediately to avoid delays */ if (!err && (chan->txdone_method & TXDONE_BY_POLL)) { - /* but only if not already active */ - if (!hrtimer_active(&chan->mbox->poll_hrt)) - hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL); + /* kick start the timer immediately to avoid delays */ + spin_lock_irqsave(&chan->mbox->poll_hrt_lock, flags); + hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL); + spin_unlock_irqrestore(&chan->mbox->poll_hrt_lock, flags); } } @@ -120,20 +120,26 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer) container_of(hrtimer, struct mbox_controller, poll_hrt); bool txdone, resched = false; int i; + unsigned long flags; for (i = 0; i < mbox->num_chans; i++) { struct mbox_chan *chan = &mbox->chans[i]; if (chan->active_req && chan->cl) { - resched = true; txdone = chan->mbox->ops->last_tx_done(chan); if (txdone) tx_tick(chan, 0); + else + resched = true; } } if (resched) { - hrtimer_forward_now(hrtimer, ms_to_ktime(mbox->txpoll_period)); + spin_lock_irqsave(&mbox->poll_hrt_lock, flags); + if (!hrtimer_is_queued(hrtimer)) + hrtimer_forward_now(hrtimer, ms_to_ktime(mbox->txpoll_period)); + spin_unlock_irqrestore(&mbox->poll_hrt_lock, flags); + return HRTIMER_RESTART; } return HRTIMER_NORESTART; @@ -500,6 +506,7 @@ int mbox_controller_register(struct mbox_controller *mbox) hrtimer_init(&mbox->poll_hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); mbox->poll_hrt.function = txdone_hrtimer; + spin_lock_init(&mbox->poll_hrt_lock); } for (i = 0; i < mbox->num_chans; i++) { diff --git a/drivers/mailbox/mtk-adsp-mailbox.c b/drivers/mailbox/mtk-adsp-mailbox.c index 5e7378090c7b..14bc0057de81 100644 --- a/drivers/mailbox/mtk-adsp-mailbox.c +++ b/drivers/mailbox/mtk-adsp-mailbox.c @@ -149,6 +149,13 @@ static int mtk_adsp_mbox_probe(struct platform_device *pdev) return devm_mbox_controller_register(dev, &priv->mbox); } +static const struct mtk_adsp_mbox_cfg mt8186_adsp_mbox_cfg = { + .set_in = 0x00, + .set_out = 0x04, + .clr_in = 0x08, + .clr_out = 0x0C, +}; + static const struct mtk_adsp_mbox_cfg mt8195_adsp_mbox_cfg = { .set_in = 0x00, .set_out = 0x1c, @@ -157,6 +164,7 @@ static const struct mtk_adsp_mbox_cfg mt8195_adsp_mbox_cfg = { }; static const struct of_device_id mtk_adsp_mbox_of_match[] = { + { .compatible = "mediatek,mt8186-adsp-mbox", .data = &mt8186_adsp_mbox_cfg }, { .compatible = "mediatek,mt8195-adsp-mbox", .data = &mt8195_adsp_mbox_cfg }, {}, }; diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c index 58f3d569f095..098c82d87137 100644 --- a/drivers/mailbox/omap-mailbox.c +++ b/drivers/mailbox/omap-mailbox.c @@ -856,11 +856,9 @@ static int omap_mbox_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mdev); pm_runtime_enable(mdev->dev); - ret = pm_runtime_get_sync(mdev->dev); - if (ret < 0) { - pm_runtime_put_noidle(mdev->dev); + ret = pm_runtime_resume_and_get(mdev->dev); + if (ret < 0) goto unregister; - } /* * just print the raw revision register, the format is not diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index ed18936b8ce6..ebfa33a40fce 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -654,7 +654,7 @@ static int pcc_mbox_probe(struct platform_device *pdev) goto err; } - pcc_mbox_ctrl = devm_kmalloc(dev, sizeof(*pcc_mbox_ctrl), GFP_KERNEL); + pcc_mbox_ctrl = devm_kzalloc(dev, sizeof(*pcc_mbox_ctrl), GFP_KERNEL); if (!pcc_mbox_ctrl) { rc = -ENOMEM; goto err; diff --git a/drivers/mailbox/qcom-ipcc.c b/drivers/mailbox/qcom-ipcc.c index c5d963222014..31d58b7d55fe 100644 --- a/drivers/mailbox/qcom-ipcc.c +++ b/drivers/mailbox/qcom-ipcc.c @@ -41,9 +41,10 @@ struct qcom_ipcc_chan_info { * @dev: Device associated with this instance * @base: Base address of the IPCC frame associated to APSS * @irq_domain: The irq_domain associated with this instance - * @chan: The mailbox channels array + * @chans: The mailbox channels array * @mchan: The per-mailbox channel info array * @mbox: The mailbox controller + * @num_chans: Number of @chans elements * @irq: Summary irq */ struct qcom_ipcc { @@ -254,6 +255,24 @@ static int qcom_ipcc_setup_mbox(struct qcom_ipcc *ipcc, return devm_mbox_controller_register(dev, mbox); } +static int qcom_ipcc_pm_resume(struct device *dev) +{ + struct qcom_ipcc *ipcc = dev_get_drvdata(dev); + u32 hwirq; + int virq; + + hwirq = readl(ipcc->base + IPCC_REG_RECV_ID); + if (hwirq == IPCC_NO_PENDING_IRQ) + return 0; + + virq = irq_find_mapping(ipcc->irq_domain, hwirq); + + dev_dbg(dev, "virq: %d triggered client-id: %ld; signal-id: %ld\n", virq, + FIELD_GET(IPCC_CLIENT_ID_MASK, hwirq), FIELD_GET(IPCC_SIGNAL_ID_MASK, hwirq)); + + return 0; +} + static int qcom_ipcc_probe(struct platform_device *pdev) { struct qcom_ipcc *ipcc; @@ -324,6 +343,10 @@ static const struct of_device_id qcom_ipcc_of_match[] = { }; MODULE_DEVICE_TABLE(of, qcom_ipcc_of_match); +static const struct dev_pm_ops qcom_ipcc_dev_pm_ops = { + NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, qcom_ipcc_pm_resume) +}; + static struct platform_driver qcom_ipcc_driver = { .probe = qcom_ipcc_probe, .remove = qcom_ipcc_remove, @@ -331,6 +354,7 @@ static struct platform_driver qcom_ipcc_driver = { .name = "qcom-ipcc", .of_match_table = qcom_ipcc_of_match, .suppress_bind_attrs = true, + .pm = pm_sleep_ptr(&qcom_ipcc_dev_pm_ops), }, }; diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c index 78f7265039c6..573481e436f5 100644 --- a/drivers/mailbox/tegra-hsp.c +++ b/drivers/mailbox/tegra-hsp.c @@ -46,10 +46,18 @@ #define HSP_SM_SHRD_MBOX_FULL_INT_IE 0x04 #define HSP_SM_SHRD_MBOX_EMPTY_INT_IE 0x08 +#define HSP_SHRD_MBOX_TYPE1_TAG 0x40 +#define HSP_SHRD_MBOX_TYPE1_DATA0 0x48 +#define HSP_SHRD_MBOX_TYPE1_DATA1 0x4c +#define HSP_SHRD_MBOX_TYPE1_DATA2 0x50 +#define HSP_SHRD_MBOX_TYPE1_DATA3 0x54 + #define HSP_DB_CCPLEX 1 #define HSP_DB_BPMP 3 #define HSP_DB_MAX 7 +#define HSP_MBOX_TYPE_MASK 0xff + struct tegra_hsp_channel; struct tegra_hsp; @@ -67,8 +75,14 @@ struct tegra_hsp_doorbell { unsigned int index; }; +struct tegra_hsp_sm_ops { + void (*send)(struct tegra_hsp_channel *channel, void *data); + void (*recv)(struct tegra_hsp_channel *channel); +}; + struct tegra_hsp_mailbox { struct tegra_hsp_channel channel; + const struct tegra_hsp_sm_ops *ops; unsigned int index; bool producer; }; @@ -82,6 +96,7 @@ struct tegra_hsp_db_map { struct tegra_hsp_soc { const struct tegra_hsp_db_map *map; bool has_per_mb_ie; + bool has_128_bit_mb; }; struct tegra_hsp { @@ -208,8 +223,7 @@ static irqreturn_t tegra_hsp_shared_irq(int irq, void *data) { struct tegra_hsp *hsp = data; unsigned long bit, mask; - u32 status, value; - void *msg; + u32 status; status = tegra_hsp_readl(hsp, HSP_INT_IR) & hsp->mask; @@ -245,25 +259,8 @@ static irqreturn_t tegra_hsp_shared_irq(int irq, void *data) for_each_set_bit(bit, &mask, hsp->num_sm) { struct tegra_hsp_mailbox *mb = &hsp->mailboxes[bit]; - if (!mb->producer) { - value = tegra_hsp_channel_readl(&mb->channel, - HSP_SM_SHRD_MBOX); - value &= ~HSP_SM_SHRD_MBOX_FULL; - msg = (void *)(unsigned long)value; - mbox_chan_received_data(mb->channel.chan, msg); - - /* - * Need to clear all bits here since some producers, - * such as TCU, depend on fields in the register - * getting cleared by the consumer. - * - * The mailbox API doesn't give the consumers a way - * of doing that explicitly, so we have to make sure - * we cover all possible cases. - */ - tegra_hsp_channel_writel(&mb->channel, 0x0, - HSP_SM_SHRD_MBOX); - } + if (!mb->producer) + mb->ops->recv(&mb->channel); } return IRQ_HANDLED; @@ -372,21 +369,97 @@ static const struct mbox_chan_ops tegra_hsp_db_ops = { .shutdown = tegra_hsp_doorbell_shutdown, }; +static void tegra_hsp_sm_send32(struct tegra_hsp_channel *channel, void *data) +{ + u32 value; + + /* copy data and mark mailbox full */ + value = (u32)(unsigned long)data; + value |= HSP_SM_SHRD_MBOX_FULL; + + tegra_hsp_channel_writel(channel, value, HSP_SM_SHRD_MBOX); +} + +static void tegra_hsp_sm_recv32(struct tegra_hsp_channel *channel) +{ + u32 value; + void *msg; + + value = tegra_hsp_channel_readl(channel, HSP_SM_SHRD_MBOX); + value &= ~HSP_SM_SHRD_MBOX_FULL; + msg = (void *)(unsigned long)value; + mbox_chan_received_data(channel->chan, msg); + + /* + * Need to clear all bits here since some producers, such as TCU, depend + * on fields in the register getting cleared by the consumer. + * + * The mailbox API doesn't give the consumers a way of doing that + * explicitly, so we have to make sure we cover all possible cases. + */ + tegra_hsp_channel_writel(channel, 0x0, HSP_SM_SHRD_MBOX); +} + +static const struct tegra_hsp_sm_ops tegra_hsp_sm_32bit_ops = { + .send = tegra_hsp_sm_send32, + .recv = tegra_hsp_sm_recv32, +}; + +static void tegra_hsp_sm_send128(struct tegra_hsp_channel *channel, void *data) +{ + u32 value[4]; + + memcpy(value, data, sizeof(value)); + + /* Copy data */ + tegra_hsp_channel_writel(channel, value[0], HSP_SHRD_MBOX_TYPE1_DATA0); + tegra_hsp_channel_writel(channel, value[1], HSP_SHRD_MBOX_TYPE1_DATA1); + tegra_hsp_channel_writel(channel, value[2], HSP_SHRD_MBOX_TYPE1_DATA2); + tegra_hsp_channel_writel(channel, value[3], HSP_SHRD_MBOX_TYPE1_DATA3); + + /* Update tag to mark mailbox full */ + tegra_hsp_channel_writel(channel, HSP_SM_SHRD_MBOX_FULL, + HSP_SHRD_MBOX_TYPE1_TAG); +} + +static void tegra_hsp_sm_recv128(struct tegra_hsp_channel *channel) +{ + u32 value[4]; + void *msg; + + value[0] = tegra_hsp_channel_readl(channel, HSP_SHRD_MBOX_TYPE1_DATA0); + value[1] = tegra_hsp_channel_readl(channel, HSP_SHRD_MBOX_TYPE1_DATA1); + value[2] = tegra_hsp_channel_readl(channel, HSP_SHRD_MBOX_TYPE1_DATA2); + value[3] = tegra_hsp_channel_readl(channel, HSP_SHRD_MBOX_TYPE1_DATA3); + + msg = (void *)(unsigned long)value; + mbox_chan_received_data(channel->chan, msg); + + /* + * Clear data registers and tag. + */ + tegra_hsp_channel_writel(channel, 0x0, HSP_SHRD_MBOX_TYPE1_DATA0); + tegra_hsp_channel_writel(channel, 0x0, HSP_SHRD_MBOX_TYPE1_DATA1); + tegra_hsp_channel_writel(channel, 0x0, HSP_SHRD_MBOX_TYPE1_DATA2); + tegra_hsp_channel_writel(channel, 0x0, HSP_SHRD_MBOX_TYPE1_DATA3); + tegra_hsp_channel_writel(channel, 0x0, HSP_SHRD_MBOX_TYPE1_TAG); +} + +static const struct tegra_hsp_sm_ops tegra_hsp_sm_128bit_ops = { + .send = tegra_hsp_sm_send128, + .recv = tegra_hsp_sm_recv128, +}; + static int tegra_hsp_mailbox_send_data(struct mbox_chan *chan, void *data) { struct tegra_hsp_mailbox *mb = chan->con_priv; struct tegra_hsp *hsp = mb->channel.hsp; unsigned long flags; - u32 value; if (WARN_ON(!mb->producer)) return -EPERM; - /* copy data and mark mailbox full */ - value = (u32)(unsigned long)data; - value |= HSP_SM_SHRD_MBOX_FULL; - - tegra_hsp_channel_writel(&mb->channel, value, HSP_SM_SHRD_MBOX); + mb->ops->send(&mb->channel, data); /* enable EMPTY interrupt for the shared mailbox */ spin_lock_irqsave(&hsp->lock, flags); @@ -552,12 +625,21 @@ static struct mbox_chan *tegra_hsp_sm_xlate(struct mbox_controller *mbox, index = args->args[1] & TEGRA_HSP_SM_MASK; - if (type != TEGRA_HSP_MBOX_TYPE_SM || !hsp->shared_irqs || - index >= hsp->num_sm) + if ((type & HSP_MBOX_TYPE_MASK) != TEGRA_HSP_MBOX_TYPE_SM || + !hsp->shared_irqs || index >= hsp->num_sm) return ERR_PTR(-ENODEV); mb = &hsp->mailboxes[index]; + if (type & TEGRA_HSP_MBOX_TYPE_SM_128BIT) { + if (!hsp->soc->has_128_bit_mb) + return ERR_PTR(-ENODEV); + + mb->ops = &tegra_hsp_sm_128bit_ops; + } else { + mb->ops = &tegra_hsp_sm_32bit_ops; + } + if ((args->args[1] & TEGRA_HSP_SM_FLAG_TX) == 0) mb->producer = false; else @@ -804,7 +886,7 @@ static int __maybe_unused tegra_hsp_resume(struct device *dev) struct tegra_hsp_doorbell *db; list_for_each_entry(db, &hsp->doorbells, list) { - if (db && db->channel.chan) + if (db->channel.chan) tegra_hsp_doorbell_startup(db->channel.chan); } @@ -833,16 +915,25 @@ static const struct tegra_hsp_db_map tegra186_hsp_db_map[] = { static const struct tegra_hsp_soc tegra186_hsp_soc = { .map = tegra186_hsp_db_map, .has_per_mb_ie = false, + .has_128_bit_mb = false, }; static const struct tegra_hsp_soc tegra194_hsp_soc = { .map = tegra186_hsp_db_map, .has_per_mb_ie = true, + .has_128_bit_mb = false, +}; + +static const struct tegra_hsp_soc tegra234_hsp_soc = { + .map = tegra186_hsp_db_map, + .has_per_mb_ie = false, + .has_128_bit_mb = true, }; static const struct of_device_id tegra_hsp_match[] = { { .compatible = "nvidia,tegra186-hsp", .data = &tegra186_hsp_soc }, { .compatible = "nvidia,tegra194-hsp", .data = &tegra194_hsp_soc }, + { .compatible = "nvidia,tegra234-hsp", .data = &tegra234_hsp_soc }, { } }; |