summaryrefslogtreecommitdiff
path: root/drivers/mailbox
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mailbox')
-rw-r--r--drivers/mailbox/Kconfig2
-rw-r--r--drivers/mailbox/mpfs-mbox.c106
2 files changed, 74 insertions, 34 deletions
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index f45e611c966..1d9e284cfd1 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -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.
diff --git a/drivers/mailbox/mpfs-mbox.c b/drivers/mailbox/mpfs-mbox.c
index 55238847ecd..b1ce377525e 100644
--- a/drivers/mailbox/mpfs-mbox.c
+++ b/drivers/mailbox/mpfs-mbox.c
@@ -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, &regs);
- 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, &regs);
- if (ret) {
- dev_err(dev, "No reg property for mailbox base\n");
+ 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 = devm_ioremap(dev, regs.start, regs.start - regs.end);
+ 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->dev = dev;
- dev_set_priv(dev, mbox);
- mbox->chan->con_priv = mbox;
+ 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,
-};
+}; \ No newline at end of file