]> Git Repo - linux.git/commitdiff
mailbox: mpfs: support new, syscon based, devicetree configuration
authorConor Dooley <[email protected]>
Wed, 2 Oct 2024 10:48:00 +0000 (11:48 +0100)
committerJassi Brar <[email protected]>
Sun, 24 Nov 2024 18:54:16 +0000 (12:54 -0600)
The two previous bindings for this hardware were incorrect, as the
control/status and interrupt register regions should have been described
as syscons and dealt with via regmap in the driver. Add support for
accessing these registers using that method now, so that the hwmon
driver can be supported without using auxdev or hacks with io_remap().

Signed-off-by: Conor Dooley <[email protected]>
Signed-off-by: Jassi Brar <[email protected]>
drivers/mailbox/Kconfig
drivers/mailbox/mailbox-mpfs.c

index 6fb995778636a3c35fb91f489a682b24e8e17581..f856e01429aaed848985c77337cfc13206ec62c3 100644 (file)
@@ -168,6 +168,7 @@ config MAILBOX_TEST
 config POLARFIRE_SOC_MAILBOX
        tristate "PolarFire SoC (MPFS) Mailbox"
        depends on HAS_IOMEM
+       depends on MFD_SYSCON
        depends on ARCH_MICROCHIP_POLARFIRE || COMPILE_TEST
        help
          This driver adds support for the PolarFire SoC (MPFS) mailbox controller.
index 20ee283a04cc6afc890ad25ead3d2fdb16cec3e3..4df546e3b7eaebf214b27c1f6f07a29268c9f99f 100644 (file)
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/regmap.h>
 #include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
 #include <linux/mod_devicetable.h>
 #include <linux/platform_device.h>
 #include <linux/mailbox_controller.h>
 #include <soc/microchip/mpfs.h>
 
+#define MESSAGE_INT_OFFSET             0x18cu
 #define SERVICES_CR_OFFSET             0x50u
 #define SERVICES_SR_OFFSET             0x54u
 #define MAILBOX_REG_OFFSET             0x800u
@@ -68,6 +71,7 @@ struct mpfs_mbox {
        void __iomem *int_reg;
        struct mbox_chan chans[1];
        struct mpfs_mss_response *response;
+       struct regmap *sysreg_scb, *control_scb;
        u16 resp_offset;
 };
 
@@ -75,7 +79,10 @@ static bool mpfs_mbox_busy(struct mpfs_mbox *mbox)
 {
        u32 status;
 
-       status = readl_relaxed(mbox->ctrl_base + SERVICES_SR_OFFSET);
+       if (mbox->control_scb)
+               regmap_read(mbox->control_scb, SERVICES_SR_OFFSET, &status);
+       else
+               status = readl_relaxed(mbox->ctrl_base + SERVICES_SR_OFFSET);
 
        return status & SCB_STATUS_BUSY_MASK;
 }
@@ -95,7 +102,11 @@ static bool mpfs_mbox_last_tx_done(struct mbox_chan *chan)
         * Failed services are intended to generated interrupts, but in reality
         * this does not happen, so the status must be checked here.
         */
-       val = readl_relaxed(mbox->ctrl_base + SERVICES_SR_OFFSET);
+       if (mbox->control_scb)
+               regmap_read(mbox->control_scb, SERVICES_SR_OFFSET, &val);
+       else
+               val = readl_relaxed(mbox->ctrl_base + SERVICES_SR_OFFSET);
+
        response->resp_status = (val & SCB_STATUS_MASK) >> SCB_STATUS_POS;
 
        return true;
@@ -143,7 +154,12 @@ static int mpfs_mbox_send_data(struct mbox_chan *chan, void *data)
 
        tx_trigger = (opt_sel << SCB_CTRL_POS) & SCB_CTRL_MASK;
        tx_trigger |= SCB_CTRL_REQ_MASK | SCB_STATUS_NOTIFY_MASK;
-       writel_relaxed(tx_trigger, mbox->ctrl_base + SERVICES_CR_OFFSET);
+
+       if (mbox->control_scb)
+               regmap_write(mbox->control_scb, SERVICES_CR_OFFSET, tx_trigger);
+       else
+               writel_relaxed(tx_trigger, mbox->ctrl_base + SERVICES_CR_OFFSET);
+
 
        return 0;
 }
@@ -185,7 +201,10 @@ static irqreturn_t mpfs_mbox_inbox_isr(int irq, void *data)
        struct mbox_chan *chan = data;
        struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
 
-       writel_relaxed(0, mbox->int_reg);
+       if (mbox->control_scb)
+               regmap_write(mbox->sysreg_scb, MESSAGE_INT_OFFSET, 0);
+       else
+               writel_relaxed(0, mbox->int_reg);
 
        mpfs_mbox_rx_data(chan);
 
@@ -221,28 +240,62 @@ static const struct mbox_chan_ops mpfs_mbox_ops = {
        .last_tx_done = mpfs_mbox_last_tx_done,
 };
 
-static int mpfs_mbox_probe(struct platform_device *pdev)
+static inline int mpfs_mbox_syscon_probe(struct mpfs_mbox *mbox, struct platform_device *pdev)
 {
-       struct mpfs_mbox *mbox;
-       struct resource *regs;
-       int ret;
+       mbox->control_scb = syscon_regmap_lookup_by_compatible("microchip,mpfs-control-scb");
+       if (IS_ERR(mbox->control_scb))
+               return PTR_ERR(mbox->control_scb);
 
-       mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL);
-       if (!mbox)
-               return -ENOMEM;
+       mbox->sysreg_scb = syscon_regmap_lookup_by_compatible("microchip,mpfs-sysreg-scb");
+       if (IS_ERR(mbox->sysreg_scb))
+               return PTR_ERR(mbox->sysreg_scb);
+
+       mbox->mbox_base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(mbox->ctrl_base))
+               return PTR_ERR(mbox->mbox_base);
+
+       return 0;
+}
+
+static inline int mpfs_mbox_old_format_probe(struct mpfs_mbox *mbox, struct platform_device *pdev)
+{
+       dev_warn(&pdev->dev, "falling back to old devicetree format");
 
-       mbox->ctrl_base = devm_platform_get_and_ioremap_resource(pdev, 0, &regs);
+       mbox->ctrl_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(mbox->ctrl_base))
                return PTR_ERR(mbox->ctrl_base);
 
-       mbox->int_reg = devm_platform_get_and_ioremap_resource(pdev, 1, &regs);
+       mbox->int_reg = devm_platform_ioremap_resource(pdev, 1);
        if (IS_ERR(mbox->int_reg))
                return PTR_ERR(mbox->int_reg);
 
-       mbox->mbox_base = devm_platform_get_and_ioremap_resource(pdev, 2, &regs);
+       mbox->mbox_base = devm_platform_ioremap_resource(pdev, 2);
        if (IS_ERR(mbox->mbox_base)) // account for the old dt-binding w/ 2 regs
                mbox->mbox_base = mbox->ctrl_base + MAILBOX_REG_OFFSET;
 
+       return 0;
+}
+
+static int mpfs_mbox_probe(struct platform_device *pdev)
+{
+       struct mpfs_mbox *mbox;
+       int ret;
+
+       mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+
+       ret = mpfs_mbox_syscon_probe(mbox, pdev);
+       if (ret) {
+               /*
+                * set this to null, so it can be used as the decision for to
+                * regmap or not to regmap
+                */
+               mbox->control_scb = NULL;
+               ret = mpfs_mbox_old_format_probe(mbox, pdev);
+               if (ret)
+                       return ret;
+       }
        mbox->irq = platform_get_irq(pdev, 0);
        if (mbox->irq < 0)
                return mbox->irq;
This page took 0.061565 seconds and 4 git commands to generate.