mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-13 15:03:58 +03:00
Merge patch series "mailbox: mpfs-mbox: fixes and syscon support"
Jamie Gibbons <jamie.gibbons@microchip.com> says: This series updates the Microchip PolarFire SoC (MPFS) mailbox driver in U-Boot. The first three patches contain a set of bug fixes and cleanups to the existing driver, fixing MMIO size calculations, and removing invalid mailbox channel and private-data handling. These changes are independent of any devicetree updates and fix issues present in the legacy driver. The final patch adds support for the corrected, syscon-based devicetree bindings for the MPFS mailbox. Linux has moved to this binding to more accurately model the hardware, and U-Boot already supports the same approach for the MPFS clock controller. This patch updates the mailbox driver accordingly, while retaining support for the legacy binding for backwards compatibility. The final patch is required ASAP as boot is currently broken on master for MPFS generic boards. Tested on a PolarFire SoC Icicle Kit ES. Link: https://lore.kernel.org/r/20260518141712.3597880-1-jamie.gibbons@microchip.com
This commit is contained in:
@@ -32,6 +32,8 @@ config MPFS_MBOX
|
||||
bool "Enable MPFS system controller support"
|
||||
depends on DM_MAILBOX && ARCH_RV64I
|
||||
select DEVRES
|
||||
depends on SYSCON
|
||||
depends on REGMAP
|
||||
help
|
||||
Enable support for the mailboxes that provide a communication
|
||||
channel with the system controller integrated on PolarFire SoC.
|
||||
|
||||
@@ -13,19 +13,21 @@
|
||||
#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 <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <log.h>
|
||||
#include <mailbox-uclass.h>
|
||||
#include <malloc.h>
|
||||
#include <mpfs-mailbox.h>
|
||||
#include <regmap.h>
|
||||
#include <syscon.h>
|
||||
|
||||
#define SERVICES_CR_OFFSET 0x50u
|
||||
#define SERVICES_SR_OFFSET 0x54u
|
||||
#define MESSAGE_INT_OFFSET 0x18cu
|
||||
#define MAILBOX_REG_OFFSET 0x800u
|
||||
|
||||
#define SERVICE_CR_REQ_MASK 0x1u
|
||||
#define SERVICE_SR_BUSY_MASK 0x2u
|
||||
@@ -35,17 +37,18 @@
|
||||
|
||||
struct mpfs_mbox {
|
||||
struct udevice *dev;
|
||||
void __iomem *ctrl_base;
|
||||
void __iomem *mbox_base;
|
||||
struct mbox_chan *chan;
|
||||
void __iomem *int_reg;
|
||||
struct regmap *control_scb;
|
||||
struct regmap *sysreg_scb;
|
||||
};
|
||||
|
||||
static bool mpfs_mbox_busy(struct mbox_chan *chan)
|
||||
{
|
||||
struct mpfs_mbox *mbox = dev_get_priv(chan->dev);
|
||||
uint16_t status;
|
||||
u32 status;
|
||||
|
||||
status = readl(mbox->ctrl_base + SERVICES_SR_OFFSET);
|
||||
regmap_read(mbox->control_scb, SERVICES_SR_OFFSET, &status);
|
||||
|
||||
return status & SERVICE_SR_BUSY_MASK;
|
||||
}
|
||||
@@ -80,14 +83,15 @@ static int mpfs_mbox_send(struct mbox_chan *chan, const void *data)
|
||||
|
||||
cmd_shifted = msg->cmd_opcode << SERVICE_CR_COMMAND_SHIFT;
|
||||
cmd_shifted |= SERVICE_CR_REQ_MASK;
|
||||
writel(cmd_shifted, mbox->ctrl_base + SERVICES_CR_OFFSET);
|
||||
|
||||
regmap_write(mbox->control_scb, SERVICES_CR_OFFSET, cmd_shifted);
|
||||
|
||||
do {
|
||||
value = readl(mbox->ctrl_base + SERVICES_CR_OFFSET);
|
||||
regmap_read(mbox->control_scb, SERVICES_CR_OFFSET, &value);
|
||||
} while (SERVICE_CR_REQ_MASK == (value & SERVICE_CR_REQ_MASK));
|
||||
|
||||
do {
|
||||
value = readl(mbox->ctrl_base + SERVICES_SR_OFFSET);
|
||||
regmap_read(mbox->control_scb, SERVICES_SR_OFFSET, &value);
|
||||
} while (SERVICE_SR_BUSY_MASK == (value & SERVICE_SR_BUSY_MASK));
|
||||
|
||||
msg->response->resp_status = (value >> SERVICE_SR_STATUS_SHIFT);
|
||||
@@ -118,6 +122,11 @@ static int mpfs_mbox_recv(struct mbox_chan *chan, void *data)
|
||||
for (idx = 0; idx < response->resp_size; idx++)
|
||||
*((u8 *)(response->resp_msg) + idx) = readb(mbox->mbox_base + msg->resp_offset + idx);
|
||||
|
||||
if (mbox->sysreg_scb)
|
||||
regmap_write(mbox->sysreg_scb, MESSAGE_INT_OFFSET, 0);
|
||||
else
|
||||
writel_relaxed(0, mbox->int_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -126,42 +135,71 @@ static const struct mbox_ops mpfs_mbox_ops = {
|
||||
.recv = mpfs_mbox_recv,
|
||||
};
|
||||
|
||||
static int mpfs_mbox_probe(struct udevice *dev)
|
||||
/*
|
||||
* Use global compatible lookup instead of phandles, as U-Boot may run
|
||||
* with a reduced or firmware-provided device tree where mailbox syscon
|
||||
* phandle properties are not guaranteed to be present.
|
||||
*/
|
||||
static int mpfs_mbox_syscon_probe(struct udevice *dev, struct mpfs_mbox *mbox)
|
||||
{
|
||||
struct mpfs_mbox *mbox;
|
||||
struct resource regs;
|
||||
ofnode node;
|
||||
int ret;
|
||||
|
||||
node = dev_ofnode(dev);
|
||||
node = ofnode_by_compatible(ofnode_null(), "microchip,mpfs-control-scb");
|
||||
if (!ofnode_valid(node))
|
||||
return -ENODEV;
|
||||
|
||||
mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
|
||||
if (!mbox)
|
||||
return -ENOMEM;
|
||||
mbox->control_scb = syscon_node_to_regmap(node);
|
||||
if (IS_ERR(mbox->control_scb))
|
||||
return PTR_ERR(mbox->control_scb);
|
||||
|
||||
ret = ofnode_read_resource(node, 0, ®s);
|
||||
if (ret) {
|
||||
dev_err(dev, "No reg property for controller base\n");
|
||||
return ret;
|
||||
};
|
||||
node = ofnode_by_compatible(ofnode_null(), "microchip,mpfs-sysreg-scb");
|
||||
if (!ofnode_valid(node))
|
||||
return -ENODEV;
|
||||
|
||||
mbox->ctrl_base = devm_ioremap(dev, regs.start, regs.start - regs.end);
|
||||
mbox->sysreg_scb = syscon_node_to_regmap(node);
|
||||
if (IS_ERR(mbox->sysreg_scb))
|
||||
return PTR_ERR(mbox->sysreg_scb);
|
||||
|
||||
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;
|
||||
mbox->mbox_base = dev_read_addr_ptr(dev);
|
||||
if (!mbox->mbox_base)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpfs_mbox_legacy_probe(struct udevice *dev, struct mpfs_mbox *mbox)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_init_mem_index(dev_ofnode(dev), &mbox->control_scb, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mbox->mbox_base = dev_read_addr_index_ptr(dev, 2);
|
||||
if (!mbox->mbox_base)
|
||||
mbox->mbox_base = dev_read_addr_index_ptr(dev, 0) + MAILBOX_REG_OFFSET;
|
||||
|
||||
mbox->int_reg = dev_read_addr_index_ptr(dev, 1);
|
||||
if (!mbox->int_reg)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpfs_mbox_probe(struct udevice *dev)
|
||||
{
|
||||
struct mpfs_mbox *mbox = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
mbox->dev = dev;
|
||||
|
||||
ret = mpfs_mbox_syscon_probe(dev, mbox);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
return mpfs_mbox_legacy_probe(dev, mbox);
|
||||
}
|
||||
|
||||
static const struct udevice_id mpfs_mbox_ids[] = {
|
||||
{.compatible = "microchip,mpfs-mailbox"},
|
||||
{ }
|
||||
@@ -174,4 +212,4 @@ U_BOOT_DRIVER(mpfs_mbox) = {
|
||||
.probe = mpfs_mbox_probe,
|
||||
.priv_auto = sizeof(struct mpfs_mbox),
|
||||
.ops = &mpfs_mbox_ops,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user