Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mailbox: Add support for Phytium SoC mailbox driver #153

Merged
merged 3 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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]>");