* [PATCH v4 1/5] mbox: add polarfire soc system controller mailbox
@ 2021-03-11 11:34 conor.dooley
2021-03-31 0:42 ` Jassi Brar
0 siblings, 1 reply; 2+ messages in thread
From: conor.dooley @ 2021-03-11 11:34 UTC (permalink / raw)
To: robh+dt, damien.lemoal, jassisinghbrar, aou, paul.walmsley,
palmer, devicetree, linux-riscv, j.neuschaefer
Cc: lewis.hanly, cyril.jean, daire.mcnamara, atish.patra, anup.patel,
david.abdurachmanov, Conor Dooley
From: Conor Dooley <conor.dooley@microchip.com>
This driver adds support for the single mailbox channel of the MSS
system controller on the Microchip PolarFire SoC.
Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
---
drivers/mailbox/Kconfig | 12 ++
drivers/mailbox/Makefile | 2 +
drivers/mailbox/mailbox-mpfs.c | 277 +++++++++++++++++++++++++++++++++
include/soc/microchip/mpfs.h | 57 +++++++
4 files changed, 348 insertions(+)
create mode 100644 drivers/mailbox/mailbox-mpfs.c
create mode 100644 include/soc/microchip/mpfs.h
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index f4abe3529acd..b37268bd5004 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -160,6 +160,18 @@ config MAILBOX_TEST
Test client to help with testing new Controller driver
implementations.
+config POLARFIRE_SOC_MAILBOX
+ tristate "PolarFire SoC (MPFS) Mailbox"
+ depends on HAS_IOMEM
+ depends on SOC_MICROCHIP_POLARFIRE || COMPILE_TEST
+ help
+ This driver adds support for the PolarFire SoC (MPFS) mailbox controller.
+
+ To compile this driver as a module, choose M here. the
+ module will be called mailbox-mpfs.
+
+ If unsure, say N.
+
config QCOM_APCS_IPC
tristate "Qualcomm APCS IPC driver"
depends on ARCH_QCOM || COMPILE_TEST
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 7194fa92c787..c2089f04887e 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -41,6 +41,8 @@ obj-$(CONFIG_BCM_PDC_MBOX) += bcm-pdc-mailbox.o
obj-$(CONFIG_BCM_FLEXRM_MBOX) += bcm-flexrm-mailbox.o
+obj-$(CONFIG_POLARFIRE_SOC_MAILBOX) += mailbox-mpfs.o
+
obj-$(CONFIG_QCOM_APCS_IPC) += qcom-apcs-ipc-mailbox.o
obj-$(CONFIG_TEGRA_HSP_MBOX) += tegra-hsp.o
diff --git a/drivers/mailbox/mailbox-mpfs.c b/drivers/mailbox/mailbox-mpfs.c
new file mode 100644
index 000000000000..7aa6c8c87ea0
--- /dev/null
+++ b/drivers/mailbox/mailbox-mpfs.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip PolarFire SoC (MPFS) system controller/mailbox controller driver
+ *
+ * Copyright (c) 2020 Microchip Corporation. All rights reserved.
+ *
+ * Author: Conor Dooley <conor.dooley@microchip.com>
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mailbox_controller.h>
+#include <soc/microchip/mpfs.h>
+
+#define SERVICES_CR_OFFSET 0x50u
+#define SERVICES_SR_OFFSET 0x54u
+#define MAILBOX_REG_OFFSET 0x800u
+#define MSS_SYS_MAILBOX_DATA_OFFSET 0u
+#define SCB_MASK_WIDTH 16u
+
+/* SCBCTRL service control register */
+
+#define SCB_CTRL_REQ (0)
+#define SCB_CTRL_REQ_MASK BIT(SCB_CTRL_REQ)
+
+#define SCB_CTRL_BUSY (1)
+#define SCB_CTRL_BUSY_MASK BIT(SCB_CTRL_BUSY)
+
+#define SCB_CTRL_ABORT (2)
+#define SCB_CTRL_ABORT_MASK BIT(SCB_CTRL_ABORT)
+
+#define SCB_CTRL_NOTIFY (3)
+#define SCB_CTRL_NOTIFY_MASK BIT(SCB_CTRL_NOTIFY)
+
+#define SCB_CTRL_POS (16)
+#define SCB_CTRL_MASK GENMASK(SCB_CTRL_POS + SCB_MASK_WIDTH, SCB_CTRL_POS)
+
+/* SCBCTRL service status register */
+
+#define SCB_STATUS_REQ (0)
+#define SCB_STATUS_REQ_MASK BIT(SCB_STATUS_REQ)
+
+#define SCB_STATUS_BUSY (1)
+#define SCB_STATUS_BUSY_MASK BIT(SCB_STATUS_BUSY)
+
+#define SCB_STATUS_ABORT (2)
+#define SCB_STATUS_ABORT_MASK BIT(SCB_STATUS_ABORT)
+
+#define SCB_STATUS_NOTIFY (3)
+#define SCB_STATUS_NOTIFY_MASK BIT(SCB_STATUS_NOTIFY)
+
+#define SCB_STATUS_POS (16)
+#define SCB_STATUS_MASK GENMASK(SCB_STATUS_POS + SCB_MASK_WIDTH, SCB_STATUS_POS)
+
+struct mpfs_mbox {
+ struct mbox_controller controller;
+ struct device *dev;
+ int irq;
+ void __iomem *mailbox_base;
+ void __iomem *int_reg;
+ struct mbox_chan *chan;
+ u16 response_size;
+ u16 response_offset;
+};
+
+static bool mpfs_mbox_busy(struct mpfs_mbox *mbox)
+{
+ u32 status;
+
+ status = readl_relaxed(mbox->mailbox_base + SERVICES_SR_OFFSET);
+
+ return status & SCB_STATUS_BUSY_MASK;
+}
+
+static struct mpfs_mbox *mbox_chan_to_mpfs_mbox(struct mbox_chan *chan)
+{
+ if (!chan)
+ return NULL;
+
+ return (struct mpfs_mbox *)chan->con_priv;
+}
+
+static int mpfs_mbox_send_data(struct mbox_chan *chan, void *data)
+{
+ u32 mailbox_val = 0u;
+ u16 options_select;
+ u32 tx_trigger;
+ struct mpfs_mss_msg *msg = data;
+ struct mpfs_mbox *mbox = mbox_chan_to_mpfs_mbox(chan);
+
+ mbox->response_size = msg->response_size;
+ mbox->response_offset = msg->response_offset;
+
+ if (mpfs_mbox_busy(mbox))
+ return -EBUSY;
+
+ if (msg->cmd_data_size) {
+ u32 index;
+ u8 extra_bits = msg->cmd_data_size & 3;
+ u32 *word_buf = (u32 *)msg->cmd_data;
+
+ for (index = 0; index < (msg->cmd_data_size / 4); index++)
+ writel_relaxed(word_buf[index],
+ mbox->mailbox_base + MAILBOX_REG_OFFSET + index * 0x4);
+ if (extra_bits) {
+ u8 i;
+ u8 byte_off = ALIGN_DOWN(msg->cmd_data_size, 4);
+ u8 *byte_buf = msg->cmd_data + byte_off;
+
+ mailbox_val = readl_relaxed(mbox->mailbox_base +
+ MAILBOX_REG_OFFSET + index * 0x4);
+
+ for (i = 0u; i < extra_bits; i++) {
+ mailbox_val &= ~(0xffu << (i * 8u));
+ mailbox_val |= (byte_buf[i] << (i * 8u));
+ }
+
+ writel_relaxed(mailbox_val,
+ mbox->mailbox_base + MAILBOX_REG_OFFSET + index * 0x4);
+ }
+ }
+
+ options_select = ((msg->mailbox_offset << 7u) | (msg->cmd_opcode & 0x7fu));
+ tx_trigger = (options_select << SCB_CTRL_POS) & SCB_CTRL_MASK;
+ tx_trigger |= SCB_CTRL_REQ_MASK | SCB_STATUS_NOTIFY_MASK;
+ writel_relaxed(tx_trigger, mbox->mailbox_base + SERVICES_CR_OFFSET);
+
+ return 0;
+}
+
+static inline bool mpfs_mbox_pending(struct mpfs_mbox *mbox)
+{
+ u32 status;
+
+ status = readl_relaxed(mbox->mailbox_base + SERVICES_SR_OFFSET);
+
+ return !(status & SCB_STATUS_BUSY_MASK);
+}
+
+static void mpfs_mbox_rx_data(struct mbox_chan *chan)
+{
+ struct mpfs_mbox *mbox = mbox_chan_to_mpfs_mbox(chan);
+ u32 i;
+ u16 num_words = ALIGN((mbox->response_size), (4)) / 4U; //TODO better way?
+ struct mpfs_mss_response *response;
+
+ response = kmalloc(sizeof(*response), GFP_ATOMIC);
+ response->response_size = mbox->response_size;
+ response->response_msg = kcalloc(num_words, sizeof(response->response_msg), GFP_ATOMIC);
+
+ if (!response->response_msg) {
+ dev_err(mbox->dev, "failed to assign memory for response %d\n", -ENOMEM);
+ return;
+ }
+
+ if (mpfs_mbox_pending(mbox)) {
+ for (i = 0; i < num_words; i++) {
+ response->response_msg[i] = readl_relaxed(
+ mbox->mailbox_base + MAILBOX_REG_OFFSET +
+ mbox->response_offset + i * 0x4);
+ }
+ }
+
+ mbox_chan_received_data(chan, response);
+ kfree(response);
+}
+
+static irqreturn_t mpfs_mbox_inbox_isr(int irq, void *data)
+{
+ struct mbox_chan *chan = data;
+ struct mpfs_mbox *mbox = mbox_chan_to_mpfs_mbox(chan);
+
+ writel_relaxed(0, mbox->int_reg);
+
+ mpfs_mbox_rx_data(chan);
+
+ mbox_chan_txdone(chan, 0);
+ return IRQ_HANDLED;
+}
+
+static int mpfs_mbox_startup(struct mbox_chan *chan)
+{
+ struct mpfs_mbox *mbox = mbox_chan_to_mpfs_mbox(chan);
+ int ret = 0;
+
+ if (!mbox)
+ return -EINVAL;
+ ret = devm_request_irq(mbox->dev, mbox->irq, mpfs_mbox_inbox_isr, 0, "mpfs-mailbox", chan);
+ if (ret)
+ dev_err(mbox->dev, "failed to register mailbox interrupt:%d\n", ret);
+
+ return ret;
+}
+
+static void mpfs_mbox_shutdown(struct mbox_chan *chan)
+{
+ struct mpfs_mbox *mbox = mbox_chan_to_mpfs_mbox(chan);
+
+ devm_free_irq(mbox->dev, mbox->irq, chan);
+}
+
+static const struct mbox_chan_ops mpfs_mbox_ops = {
+ .send_data = mpfs_mbox_send_data,
+ .startup = mpfs_mbox_startup,
+ .shutdown = mpfs_mbox_shutdown,
+};
+
+static int mpfs_mbox_probe(struct platform_device *pdev)
+{
+ struct mpfs_mbox *mbox;
+ struct resource *regs;
+ struct mbox_chan *chans;
+ int ret;
+
+ mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL);
+ if (!mbox)
+ return -ENOMEM;
+
+ chans = devm_kzalloc(&pdev->dev, sizeof(*chans), GFP_KERNEL);
+ if (!chans)
+ return -ENOMEM;
+
+ mbox->mailbox_base = devm_platform_get_and_ioremap_resource(pdev, 0, ®s);
+ if (IS_ERR(mbox->mailbox_base))
+ return PTR_ERR(mbox->mailbox_base);
+
+ mbox->int_reg = devm_platform_get_and_ioremap_resource(pdev, 1, ®s);
+ if (IS_ERR(mbox->int_reg))
+ return PTR_ERR(mbox->int_reg);
+
+ mbox->irq = platform_get_irq(pdev, 0);
+ if (mbox->irq < 0)
+ return mbox->irq;
+
+ mbox->dev = &pdev->dev;
+
+ chans[0].con_priv = mbox;
+ mbox->controller.dev = mbox->dev;
+ mbox->controller.num_chans = 1;
+ mbox->controller.chans = chans;
+ mbox->controller.ops = &mpfs_mbox_ops;
+ mbox->controller.txdone_irq = true;
+
+ ret = devm_mbox_controller_register(&pdev->dev, &mbox->controller);
+ if (ret) {
+ dev_err(&pdev->dev, "Registering MPFS mailbox controller failed\n");
+ return ret;
+ }
+ dev_info(&pdev->dev, "Registered MPFS mailbox controller driver\n");
+
+ return 0;
+}
+
+static const struct of_device_id mpfs_mbox_of_match[] = {
+ {.compatible = "microchip,polarfire-soc-mailbox", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mpfs_mbox_of_match);
+
+static struct platform_driver mpfs_mbox_driver = {
+ .driver = {
+ .name = "mpfs-mailbox",
+ .of_match_table = mpfs_mbox_of_match,
+ },
+ .probe = mpfs_mbox_probe,
+};
+module_platform_driver(mpfs_mbox_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
+MODULE_DESCRIPTION("MPFS mailbox controller driver");
diff --git a/include/soc/microchip/mpfs.h b/include/soc/microchip/mpfs.h
new file mode 100644
index 000000000000..b37258afb3f8
--- /dev/null
+++ b/include/soc/microchip/mpfs.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *
+ * Microchip PolarFire SoC (MPFS)
+ *
+ * Copyright (c) 2020 Microchip Corporation. All rights reserved.
+ *
+ * Author: Conor Dooley <conor.dooley@microchip.com>
+ *
+ */
+
+#ifndef __SOC_MPFS_H__
+#define __SOC_MPFS_H__
+
+#include <linux/types.h>
+#include <linux/of_device.h>
+
+struct mpfs_sys_controller;
+
+struct mpfs_mss_msg {
+ u8 cmd_opcode;
+ u16 cmd_data_size;
+ u16 response_size;
+ u8 *cmd_data;
+ u16 mailbox_offset;
+ u16 response_offset;
+};
+
+struct mpfs_mss_response {
+ u32 response_status;
+ u32 *response_msg;
+ u16 response_size;
+};
+
+#if IS_ENABLED(CONFIG_POLARFIRE_SOC_SYS_CTRL)
+
+int mpfs_blocking_transaction(struct mpfs_sys_controller *mpfs_client, void *msg,
+ struct mpfs_mss_response *response);
+
+struct mpfs_sys_controller *mpfs_sys_controller_get(struct device_node *mailbox_node);
+
+#else
+
+static int mpfs_blocking_transaction(struct mpfs_sys_controller *mpfs_client, void *msg,
+ struct mpfs_mss_response *response)
+{
+ return -ENOSYS;
+}
+
+struct mpfs_sys_controller *mpfs_sys_controller_get(struct device_node *mailbox_node)
+{
+ return NULL;
+}
+
+#endif /* if IS_ENABLED(CONFIG_POLARFIRE_SOC_SYS_CTRL) */
+
+#endif /* __SOC_MPFS_H__ */
--
2.17.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH v4 1/5] mbox: add polarfire soc system controller mailbox
2021-03-11 11:34 [PATCH v4 1/5] mbox: add polarfire soc system controller mailbox conor.dooley
@ 2021-03-31 0:42 ` Jassi Brar
0 siblings, 0 replies; 2+ messages in thread
From: Jassi Brar @ 2021-03-31 0:42 UTC (permalink / raw)
To: conor.dooley
Cc: Rob Herring, damien.lemoal, aou, paul.walmsley, palmer,
Devicetree List, linux-riscv, j.neuschaefer, lewis.hanly,
cyril.jean, daire.mcnamara, atish.patra, anup.patel,
david.abdurachmanov
On Thu, Mar 11, 2021 at 5:34 AM <conor.dooley@microchip.com> wrote:
> diff --git a/drivers/mailbox/mailbox-mpfs.c b/drivers/mailbox/mailbox-mpfs.c
> new file mode 100644
> index 000000000000..7aa6c8c87ea0
> --- /dev/null
> +++ b/drivers/mailbox/mailbox-mpfs.c
> @@ -0,0 +1,277 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Microchip PolarFire SoC (MPFS) system controller/mailbox controller driver
> + *
> + * Copyright (c) 2020 Microchip Corporation. All rights reserved.
> + *
> + * Author: Conor Dooley <conor.dooley@microchip.com>
> + *
> + */
> +
> +#include <linux/io.h>
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/mailbox_controller.h>
> +#include <soc/microchip/mpfs.h>
> +
> +#define SERVICES_CR_OFFSET 0x50u
> +#define SERVICES_SR_OFFSET 0x54u
> +#define MAILBOX_REG_OFFSET 0x800u
> +#define MSS_SYS_MAILBOX_DATA_OFFSET 0u
> +#define SCB_MASK_WIDTH 16u
> +
> +/* SCBCTRL service control register */
> +
> +#define SCB_CTRL_REQ (0)
> +#define SCB_CTRL_REQ_MASK BIT(SCB_CTRL_REQ)
> +
> +#define SCB_CTRL_BUSY (1)
> +#define SCB_CTRL_BUSY_MASK BIT(SCB_CTRL_BUSY)
> +
> +#define SCB_CTRL_ABORT (2)
> +#define SCB_CTRL_ABORT_MASK BIT(SCB_CTRL_ABORT)
> +
> +#define SCB_CTRL_NOTIFY (3)
> +#define SCB_CTRL_NOTIFY_MASK BIT(SCB_CTRL_NOTIFY)
> +
> +#define SCB_CTRL_POS (16)
> +#define SCB_CTRL_MASK GENMASK(SCB_CTRL_POS + SCB_MASK_WIDTH, SCB_CTRL_POS)
> +
> +/* SCBCTRL service status register */
> +
> +#define SCB_STATUS_REQ (0)
> +#define SCB_STATUS_REQ_MASK BIT(SCB_STATUS_REQ)
> +
> +#define SCB_STATUS_BUSY (1)
> +#define SCB_STATUS_BUSY_MASK BIT(SCB_STATUS_BUSY)
> +
> +#define SCB_STATUS_ABORT (2)
> +#define SCB_STATUS_ABORT_MASK BIT(SCB_STATUS_ABORT)
> +
> +#define SCB_STATUS_NOTIFY (3)
> +#define SCB_STATUS_NOTIFY_MASK BIT(SCB_STATUS_NOTIFY)
> +
> +#define SCB_STATUS_POS (16)
> +#define SCB_STATUS_MASK GENMASK(SCB_STATUS_POS + SCB_MASK_WIDTH, SCB_STATUS_POS)
> +
Please run checkpatch with strict option on the patchset.
> +
> +static int mpfs_mbox_send_data(struct mbox_chan *chan, void *data)
> +{
> + u32 mailbox_val = 0u;
> + u16 options_select;
> + u32 tx_trigger;
>
just a nit... here and elsewhere, can the variables be lesser verbose?
> +
> +static void mpfs_mbox_rx_data(struct mbox_chan *chan)
> +{
> + struct mpfs_mbox *mbox = mbox_chan_to_mpfs_mbox(chan);
> + u32 i;
> + u16 num_words = ALIGN((mbox->response_size), (4)) / 4U; //TODO better way?
> + struct mpfs_mss_response *response;
> +
> + response = kmalloc(sizeof(*response), GFP_ATOMIC);
> + response->response_size = mbox->response_size;
> + response->response_msg = kcalloc(num_words, sizeof(response->response_msg), GFP_ATOMIC);
> +
> + if (!response->response_msg) {
> + dev_err(mbox->dev, "failed to assign memory for response %d\n", -ENOMEM);
> + return;
> + }
> +
response_size is provided by the client driver.
So why not simply get the buffer from the client and just fill it
here? That is simpler and better (avoid alloc in isr) and the right
thing to do.
> +
> +static int mpfs_mbox_probe(struct platform_device *pdev)
> +{
> + struct mpfs_mbox *mbox;
> + struct resource *regs;
> + struct mbox_chan *chans;
> + int ret;
> +
> + mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL);
> + if (!mbox)
> + return -ENOMEM;
> +
> + chans = devm_kzalloc(&pdev->dev, sizeof(*chans), GFP_KERNEL);
>
You may simply embed the mbox_chan in mpfs_mbox.
cheers.
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2021-03-31 0:43 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-03-11 11:34 [PATCH v4 1/5] mbox: add polarfire soc system controller mailbox conor.dooley
2021-03-31 0:42 ` Jassi Brar
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).