Commit cdeffe87 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 7182e897 79f9fbe3
......@@ -11,14 +11,15 @@ maintainers:
description: |
The MTK ADSP mailbox Inter-Processor Communication (IPC) enables the SoC
to ommunicate with ADSP by passing messages through two mailbox channels.
to communicate with ADSP by passing messages through two mailbox channels.
The MTK ADSP mailbox IPC also provides the ability for one processor to
signal the other processor using interrupts.
properties:
compatible:
items:
- const: mediatek,mt8195-adsp-mbox
enum:
- mediatek,mt8195-adsp-mbox
- mediatek,mt8186-adsp-mbox
"#mbox-cells":
const: 0
......
......@@ -26,6 +26,15 @@ description: |
second cell is used to identify the mailbox that the client is going
to use.
For shared mailboxes, the first cell composed of two fields:
- bits 15..8:
A bit mask of flags that further specifies the type of shared
mailbox to be used (based on the data size). If no flag is
specified then, 32-bit shared mailbox is used.
- bits 7..0:
Defines the type of the mailbox to be used. This field should be
TEGRA_HSP_MBOX_TYPE_SM for shared mailboxes.
For doorbells, the second cell specifies the index of the doorbell to
use.
......
......@@ -62,23 +62,14 @@ additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/mailbox/qcom-ipcc.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/mailbox/qcom-ipcc.h>
mailbox@408000 {
compatible = "qcom,sm8250-ipcc", "qcom,ipcc";
reg = <0x408000 0x1000>;
interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
#interrupt-cells = <3>;
#mbox-cells = <2>;
};
smp2p-modem {
compatible = "qcom,smp2p";
interrupts-extended = <&ipcc_mproc IPCC_CLIENT_MPSS
IPCC_MPROC_SIGNAL_SMP2P IRQ_TYPE_EDGE_RISING>;
mboxes = <&ipcc_mproc IPCC_CLIENT_MPSS IPCC_MPROC_SIGNAL_SMP2P>;
/* Other SMP2P fields */
};
mailbox@408000 {
compatible = "qcom,sm8250-ipcc", "qcom,ipcc";
reg = <0x408000 0x1000>;
interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
#interrupt-cells = <3>;
#mbox-cells = <2>;
};
......@@ -30,15 +30,11 @@ properties:
items:
- description: rx channel occupied
- description: tx channel free
- description: wakeup source
minItems: 2
interrupt-names:
items:
- const: rx
- const: tx
- const: wakeup
minItems: 2
wakeup-source: true
......@@ -70,10 +66,9 @@ examples:
#mbox-cells = <1>;
reg = <0x4c001000 0x400>;
st,proc-id = <0>;
interrupts-extended = <&intc GIC_SPI 100 IRQ_TYPE_NONE>,
<&intc GIC_SPI 101 IRQ_TYPE_NONE>,
<&aiec 62 1>;
interrupt-names = "rx", "tx", "wakeup";
interrupts-extended = <&exti 61 1>,
<&intc GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "rx", "tx";
clocks = <&rcc_clk IPCC>;
wakeup-source;
};
......
......@@ -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
......
......@@ -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.
......
......@@ -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,
......
......@@ -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++) {
......
......@@ -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 },
{},
};
......
......@@ -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
......
......@@ -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;
......
......@@ -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),
},
};
......
......@@ -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 },
{ }
};
......
This diff is collapsed.
......@@ -15,6 +15,11 @@
#define TEGRA_HSP_MBOX_TYPE_SS 0x2
#define TEGRA_HSP_MBOX_TYPE_AS 0x3
/*
* These define the types of shared mailbox supported based on data size.
*/
#define TEGRA_HSP_MBOX_TYPE_SM_128BIT (1 << 8)
/*
* These defines represent the bit associated with the given master ID in the
* doorbell registers.
......
......@@ -83,6 +83,7 @@ struct mbox_controller {
const struct of_phandle_args *sp);
/* Internal to API */
struct hrtimer poll_hrt;
spinlock_t poll_hrt_lock;
struct list_head node;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment