From: Jamie Gibbons Date: Fri, 1 Aug 2025 12:36:23 +0000 (+0100) Subject: mailbox: add PolarFire SoC mailbox driver X-Git-Url: http://git.openpandora.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=111e9bf6a5acc8187c4849cbf4e7516e37496059;p=pandora-u-boot.git mailbox: add PolarFire SoC mailbox driver This driver adds support for the single mailbox channel of the MSS system controller on the Microchip PolarFire SoC. Signed-off-by: Jamie Gibbons Acked-by: Leo Yu-Chi Liang --- diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 4d9f004ebad..f9531c1627c 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -28,6 +28,13 @@ config IMX_MU_MBOX Enable support for i.MX Messaging Unit for communication with other processors on the SoC using mailbox interface +config MPFS_MBOX + bool "Enable MPFS system controller support" + depends on DM_MAILBOX && ARCH_RV64I + help + Enable support for the mailboxes that provide a communication + channel with the system controller integrated on PolarFire SoC. + config SANDBOX_MBOX bool "Enable the sandbox mailbox test driver" depends on DM_MAILBOX && SANDBOX diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index e8c745f7d79..b54fbdfff15 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_$(PHASE_)DM_MAILBOX) += mailbox-uclass.o obj-$(CONFIG_APPLE_MBOX) += apple-mbox.o obj-$(CONFIG_IMX_MU_MBOX) += imx-mailbox.o +obj-$(CONFIG_MPFS_MBOX) += mpfs-mbox.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o obj-$(CONFIG_STM32_IPCC) += stm32-ipcc.o diff --git a/drivers/mailbox/mpfs-mbox.c b/drivers/mailbox/mpfs-mbox.c new file mode 100644 index 00000000000..55238847ecd --- /dev/null +++ b/drivers/mailbox/mpfs-mbox.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip's PolarFire SoC (MPFS) Mailbox Driver + * + * Copyright (C) 2024 Microchip Technology Inc. All rights reserved. + * + * Author: Jamie Gibbons + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SERVICES_CR_OFFSET 0x50u +#define SERVICES_SR_OFFSET 0x54u + +#define SERVICE_CR_REQ_MASK 0x1u +#define SERVICE_SR_BUSY_MASK 0x2u +#define SERVICE_SR_STATUS_SHIFT 16 +#define SERVICE_CR_COMMAND_SHIFT 16 +#define MASK_8BIT 0xFF + +struct mpfs_mbox { + struct udevice *dev; + void __iomem *ctrl_base; + void __iomem *mbox_base; + struct mbox_chan *chan; +}; + +static bool mpfs_mbox_busy(struct mbox_chan *chan) +{ + struct mpfs_mbox *mbox = dev_get_priv(chan->dev); + uint16_t status; + + status = readl(mbox->ctrl_base + SERVICES_SR_OFFSET); + + return status & SERVICE_SR_BUSY_MASK; +} + +static int mpfs_mbox_send(struct mbox_chan *chan, const void *data) +{ + struct mpfs_mbox *mbox = dev_get_priv(chan->dev); + struct mpfs_mss_msg *msg = (struct mpfs_mss_msg *)data; + u32 mailbox_val, cmd_shifted, value; + u8 *byte_buf; + u8 idx, byte_idx, byte_offset; + + u32 *word_buf = (u32 *)msg->cmd_data; + + if (mpfs_mbox_busy(chan)) + return -EBUSY; + + for (idx = 0; idx < (msg->cmd_data_size / BYTES_4); idx++) + writel(word_buf[idx], mbox->mbox_base + msg->mbox_offset + idx * BYTES_4); + + if ((msg->cmd_data_size % BYTES_4) > 0) { + byte_offset = (msg->cmd_data_size / BYTES_4) * BYTES_4; + byte_buf = (u8 *)(msg->cmd_data + byte_offset); + mailbox_val = readl(mbox->mbox_base + msg->mbox_offset + idx * BYTES_4); + + for (byte_idx = 0; byte_idx < (msg->cmd_data_size % BYTES_4); byte_idx++) { + mailbox_val &= ~(MASK_8BIT << (byte_idx * 0x8u)); + mailbox_val |= (u32)byte_buf[byte_idx] << (byte_idx * 0x8u); + } + writel(mailbox_val, mbox->mbox_base + msg->mbox_offset + idx * BYTES_4); + } + + cmd_shifted = msg->cmd_opcode << SERVICE_CR_COMMAND_SHIFT; + cmd_shifted |= SERVICE_CR_REQ_MASK; + writel(cmd_shifted, mbox->ctrl_base + SERVICES_CR_OFFSET); + + do { + value = readl(mbox->ctrl_base + SERVICES_CR_OFFSET); + } while (SERVICE_CR_REQ_MASK == (value & SERVICE_CR_REQ_MASK)); + + do { + value = readl(mbox->ctrl_base + SERVICES_SR_OFFSET); + } while (SERVICE_SR_BUSY_MASK == (value & SERVICE_SR_BUSY_MASK)); + + msg->response->resp_status = (value >> SERVICE_SR_STATUS_SHIFT); + if (msg->response->resp_status) + return -EBADMSG; + + return 0; +} + +static int mpfs_mbox_recv(struct mbox_chan *chan, void *data) +{ + struct mpfs_mbox *mbox = dev_get_priv(chan->dev); + struct mpfs_mss_msg *msg = data; + struct mpfs_mss_response *response = msg->response; + u8 idx; + + if (!response->resp_msg) { + dev_err(chan->dev, "failed to assign memory for response %d\n", -ENOMEM); + return -EINVAL; + } + + if (mpfs_mbox_busy(chan)) { + dev_err(chan->dev, "mailbox is busy\n"); + response->resp_status = 0xDEAD; + return -EINVAL; + } + + for (idx = 0; idx < response->resp_size; idx++) + *((u8 *)(response->resp_msg) + idx) = readb(mbox->mbox_base + msg->resp_offset + idx); + + return 0; +} + +static const struct mbox_ops mpfs_mbox_ops = { + .send = mpfs_mbox_send, + .recv = mpfs_mbox_recv, +}; + +static int mpfs_mbox_probe(struct udevice *dev) +{ + struct mpfs_mbox *mbox; + struct resource regs; + ofnode node; + int ret; + + node = dev_ofnode(dev); + + mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); + if (!mbox) + return -ENOMEM; + + ret = ofnode_read_resource(node, 0, ®s); + if (ret) { + dev_err(dev, "No reg property for controller base\n"); + return ret; + }; + + mbox->ctrl_base = devm_ioremap(dev, regs.start, regs.start - regs.end); + + ret = ofnode_read_resource(node, 2, ®s); + if (ret) { + dev_err(dev, "No reg property for mailbox base\n"); + return ret; + }; + + mbox->mbox_base = devm_ioremap(dev, regs.start, regs.start - regs.end); + + mbox->dev = dev; + dev_set_priv(dev, mbox); + mbox->chan->con_priv = mbox; + + return 0; +} + +static const struct udevice_id mpfs_mbox_ids[] = { + {.compatible = "microchip,mpfs-mailbox"}, + { } +}; + +U_BOOT_DRIVER(mpfs_mbox) = { + .name = "mpfs-mbox", + .id = UCLASS_MAILBOX, + .of_match = mpfs_mbox_ids, + .probe = mpfs_mbox_probe, + .priv_auto = sizeof(struct mpfs_mbox), + .ops = &mpfs_mbox_ops, +}; diff --git a/include/mpfs-mailbox.h b/include/mpfs-mailbox.h new file mode 100644 index 00000000000..c0ff327a4ce --- /dev/null +++ b/include/mpfs-mailbox.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * + * Microchip PolarFire SoC (MPFS) + * + * Copyright (c) 2020 Microchip Corporation. All rights reserved. + * + * + */ + +#ifndef _MPFS_MAILBOX_H__ +#define _MPFS_MAILBOX_H__ + +#include + +#define BYTES_4 4 + +struct udevice; + +/** + * struct mpfs_mss_msg - PolarFire SoC message structure + * @cmd_opcode: Command opcode + * @cmd_data_size: Size of the command data. + * @response: Pointer to the response data. + * @cmd_data: Pointer to the command data. + * @mbox_offset: Mailbox offset + * @resp_offset: Response offset + * + */ +struct mpfs_mss_msg { + u8 cmd_opcode; + u16 cmd_data_size; + struct mpfs_mss_response *response; + u8 *cmd_data; + u16 mbox_offset; + u16 resp_offset; +}; + +/** + * struct mpfs_mss_response - PolarFire SoC response structure + * @resp_status: Response status + * @resp_msg: Pointer to response message. + * @resp_size: Size of the response message. + * + */ +struct mpfs_mss_response { + u32 resp_status; + u32 *resp_msg; + u16 resp_size; +}; + +struct mpfs_syscontroller_priv; + +struct mpfs_sys_serv { + struct udevice *dev; + struct mpfs_syscontroller_priv *sys_controller; + struct mpfs_mss_msg *msg; +}; + +int mpfs_syscontroller_run_service(struct mpfs_syscontroller_priv *sys_controller, struct mpfs_mss_msg *msg); +int mpfs_syscontroller_read_sernum(struct mpfs_sys_serv *sys_serv_priv, u8 *device_serial_number); +void mpfs_syscontroller_process_dtbo(struct mpfs_sys_serv *sys_serv_priv); +struct mpfs_syscontroller_priv *mpfs_syscontroller_get(struct udevice *dev); + +#endif /* __MPFS_MAILBOX_H__ */ +