Skip to content

Commit

Permalink
Merge pull request #153 from hhhui-L/mailbox
Browse files Browse the repository at this point in the history
mailbox: Add support for Phytium SoC mailbox driver
  • Loading branch information
opsiff authored Jun 19, 2024
2 parents 2822edc + a05b704 commit 4199f98
Show file tree
Hide file tree
Showing 5 changed files with 266 additions and 0 deletions.
48 changes: 48 additions & 0 deletions Documentation/devicetree/bindings/mailbox/phytium,mbox.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mailbox/phytium,mbox.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Phytium Mailbox Driver

maintainers:
- Chen Baozi <[email protected]>

description: |
The Phytium mailbox controller that has a channel/link to communicate
with the remote end. A link raises interrupt for any received data. However,
there is no specified way of knowing if the sent data has been read by the
remote. This driver assumes the sender polls STAT register and the remote
clears it after having read the data.
properties:
compatible:
const: phytium,mbox

reg:
maxItems: 1

interrupts:
maxItems: 1

'#mbox-cells':
const: 1
description: the index of the channel needed

required:
- compatible
- reg
- interrupts
- '#mbox-cells'

additionalProperties: false

examples:
- |
mbox: mailbox@2a000000 {
compatible = "phytium,mbox";
reg = <0x0 0x2a000000 0x0 0x1000>;
#mbox-cells = <1>;
interrupts = <0 48 4>;
};
11 changes: 11 additions & 0 deletions drivers/firmware/arm_scmi/mailbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
struct mbox_client *cl;
resource_size_t size;
struct resource res;
struct of_phandle_args args;

ret = mailbox_chan_validate(cdev, &a2p_rx_chan, &p2a_chan);
if (ret)
Expand Down Expand Up @@ -226,6 +227,16 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
}
}

ret = of_parse_phandle_with_args(cdev->of_node, "mboxes",
"#mbox-cells", 1, &args);
if (ret) {
dev_err(cdev, "failed to get SCMI %s mailbox\n", desc);
return ret;
}

if (of_device_is_compatible(args.np, "phytium,mbox"))
cinfo->no_completion_irq = true;

cinfo->transport_info = smbox;
smbox->cinfo = cinfo;

Expand Down
9 changes: 9 additions & 0 deletions drivers/mailbox/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ config IMX_MBOX
help
Mailbox implementation for i.MX Messaging Unit (MU).

config PHYTIUM_MBOX
tristate "Phytium SoC Mailbox Support"
depends on ARCH_PHYTIUM || COMPILE_TEST
help
Mailbox driver implementation for the Phytium platform. It is used
to send message between application processors and on-chip management
firmware. Say Y here if you want to build this mailbox controller
driver.

config PLATFORM_MHU
tristate "Platform MHU Mailbox"
depends on OF
Expand Down
2 changes: 2 additions & 0 deletions drivers/mailbox/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,5 @@ obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o
obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o

obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o

obj-$(CONFIG_PHYTIUM_MBOX) += phytium_mailbox.o
196 changes: 196 additions & 0 deletions drivers/mailbox/phytium_mailbox.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Phytium SoC mailbox driver
*
* Copyright (c) 2020-2023, Phytium Technology Co., Ltd.
*
* Derived from drivers/mailbox/arm_mhu.c
* Copyright (C) 2013-2015 Fujitsu Semiconductor Ltd.
* Copyright (C) 2015 Linaro Ltd.
*/

#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/mailbox_controller.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>

#define INTR_STAT 0x0
#define INTR_SET 0x8
#define INTR_CLR 0x10

#define TX_REG 0x100

#define NR_CHANS 1

struct phytium_mbox_link {
unsigned int irq;
void __iomem *tx_reg;
void __iomem *rx_reg;
};

struct phytium_mbox {
void __iomem *base;
struct phytium_mbox_link mlink;
struct mbox_chan chan;
struct mbox_controller mbox;
};

static irqreturn_t phytium_mbox_rx_irq(int irq, void *ch)
{
struct mbox_chan *chan = ch;
struct phytium_mbox_link *mlink = chan->con_priv;
u32 val;

val = readl_relaxed(mlink->rx_reg + INTR_STAT);
if (!val)
return IRQ_NONE;

mbox_chan_received_data(chan, (void *)&val);

writel_relaxed(val, mlink->rx_reg + INTR_CLR);

return IRQ_HANDLED;
}

static int phytium_mbox_send_data(struct mbox_chan *chan, void *data)
{
struct phytium_mbox_link *mlink = chan->con_priv;
u32 *arg = data;

writel_relaxed(*arg, mlink->tx_reg + INTR_SET);

return 0;
}

static int phytium_mbox_startup(struct mbox_chan *chan)
{
struct phytium_mbox_link *mlink = chan->con_priv;
u32 val;
int ret;

val = readl_relaxed(mlink->tx_reg + INTR_STAT);
writel_relaxed(val, mlink->tx_reg + INTR_CLR);

ret = request_irq(mlink->irq, phytium_mbox_rx_irq,
IRQF_SHARED, "phytium_mbox_link", chan);
if (ret) {
dev_err(chan->mbox->dev,
"Unable to acquire IRQ %d\n", mlink->irq);
}

return ret;
}

static void phytium_mbox_shutdown(struct mbox_chan *chan)
{
struct phytium_mbox_link *mlink = chan->con_priv;

free_irq(mlink->irq, chan);
}

static bool phytium_mbox_last_tx_done(struct mbox_chan *chan)
{
struct phytium_mbox_link *mlink = chan->con_priv;
u32 val = readl_relaxed(mlink->tx_reg + INTR_STAT);

return (val == (u32)(1U << 31));
}

static const struct mbox_chan_ops phytium_mbox_ops = {
.send_data = phytium_mbox_send_data,
.startup = phytium_mbox_startup,
.shutdown = phytium_mbox_shutdown,
.last_tx_done = phytium_mbox_last_tx_done,
};

static const struct acpi_device_id phytium_mbox_acpi_match[] = {
{ "PHYT0009", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, phytium_mbox_acpi_match);

static const struct of_device_id phytium_mbox_of_match[] = {
{ .compatible = "phytium,mbox", },
{ },
};
MODULE_DEVICE_TABLE(of, phytium_mbox_of_match);

static int phytium_mbox_probe(struct platform_device *pdev)
{
struct phytium_mbox *mbox;
struct resource *res;
int err, irq;

/* Allocate memory for device */
mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL);
if (!mbox)
return -ENOMEM;

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mbox->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(mbox->base)) {
dev_err(&pdev->dev, "ioremap base failed\n");
return PTR_ERR(mbox->base);
}

irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "cannot obtain irq\n");
return irq;
}

mbox->chan.con_priv = &mbox->mlink;
mbox->mlink.irq = irq;
mbox->mlink.rx_reg = mbox->base;
mbox->mlink.tx_reg = mbox->mlink.rx_reg + TX_REG;

mbox->mbox.dev = &pdev->dev;
mbox->mbox.chans = &mbox->chan;
mbox->mbox.num_chans = NR_CHANS;
mbox->mbox.ops = &phytium_mbox_ops;
mbox->mbox.txdone_irq = false;
mbox->mbox.txdone_poll = true;
mbox->mbox.txpoll_period = 1;

platform_set_drvdata(pdev, mbox);

err = mbox_controller_register(&mbox->mbox);
if (err) {
dev_err(&pdev->dev, "Failed to register mailboxes %d\n", err);
goto fail;
}

dev_info(&pdev->dev, "Phytium SoC Mailbox registered\n");
fail:
return err;
}

static int phytium_mbox_remove(struct platform_device *pdev)
{
struct phytium_mbox *mbox = platform_get_drvdata(pdev);

mbox_controller_unregister(&mbox->mbox);

return 0;
}

static struct platform_driver phytium_mbox_driver = {
.probe = phytium_mbox_probe,
.remove = phytium_mbox_remove,
.driver = {
.name = "phytium-mbox",
.of_match_table = of_match_ptr(phytium_mbox_of_match),
.acpi_match_table = ACPI_PTR(phytium_mbox_acpi_match),
},
};

module_platform_driver(phytium_mbox_driver);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Phytium SoC Mailbox Driver");
MODULE_AUTHOR("Chen Baozi <[email protected]>");

0 comments on commit 4199f98

Please sign in to comment.