#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
void __iomem *int_reg;
struct mbox_chan chans[1];
struct mpfs_mss_response *response;
+ struct regmap *sysreg_scb, *control_scb;
u16 resp_offset;
};
{
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;
}
* 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;
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;
}
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);
.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, ®s);
+ 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, ®s);
+ 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, ®s);
+ 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;