mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-02 09:46:37 +03:00
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 <jamie.gibbons@microchip.com> Acked-by: Leo Yu-Chi Liang <ycliang@andestech.com>
This commit is contained in:
committed by
Leo Yu-Chi Liang
parent
69539ef2f1
commit
111e9bf6a5
@@ -28,6 +28,13 @@ config IMX_MU_MBOX
|
|||||||
Enable support for i.MX Messaging Unit for communication with other
|
Enable support for i.MX Messaging Unit for communication with other
|
||||||
processors on the SoC using mailbox interface
|
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
|
config SANDBOX_MBOX
|
||||||
bool "Enable the sandbox mailbox test driver"
|
bool "Enable the sandbox mailbox test driver"
|
||||||
depends on DM_MAILBOX && SANDBOX
|
depends on DM_MAILBOX && SANDBOX
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
obj-$(CONFIG_$(PHASE_)DM_MAILBOX) += mailbox-uclass.o
|
obj-$(CONFIG_$(PHASE_)DM_MAILBOX) += mailbox-uclass.o
|
||||||
obj-$(CONFIG_APPLE_MBOX) += apple-mbox.o
|
obj-$(CONFIG_APPLE_MBOX) += apple-mbox.o
|
||||||
obj-$(CONFIG_IMX_MU_MBOX) += imx-mailbox.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.o
|
||||||
obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o
|
obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o
|
||||||
obj-$(CONFIG_STM32_IPCC) += stm32-ipcc.o
|
obj-$(CONFIG_STM32_IPCC) += stm32-ipcc.o
|
||||||
|
|||||||
177
drivers/mailbox/mpfs-mbox.c
Normal file
177
drivers/mailbox/mpfs-mbox.c
Normal file
@@ -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 <jamie.gibbons@microchip.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <dm/device-internal.h>
|
||||||
|
#include <dm/device.h>
|
||||||
|
#include <dm/device_compat.h>
|
||||||
|
#include <dm/devres.h>
|
||||||
|
#include <dm/ofnode.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/compat.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/ioport.h>
|
||||||
|
#include <log.h>
|
||||||
|
#include <mailbox-uclass.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <mpfs-mailbox.h>
|
||||||
|
|
||||||
|
#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,
|
||||||
|
};
|
||||||
66
include/mpfs-mailbox.h
Normal file
66
include/mpfs-mailbox.h
Normal file
@@ -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 <linux/types.h>
|
||||||
|
|
||||||
|
#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__ */
|
||||||
|
|
||||||
Reference in New Issue
Block a user