#include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/slab.h>
+#include <linux/static_key.h>
 #include <linux/list.h>
 #include <linux/log2.h>
 
 
 struct brcmnand_host;
 
+static DEFINE_STATIC_KEY_FALSE(brcmnand_soc_has_ops_key);
+
 struct brcmnand_controller {
        struct device           *dev;
        struct nand_controller  controller;
        INTFC_CTLR_READY                = BIT(31),
 };
 
+static inline bool brcmnand_non_mmio_ops(struct brcmnand_controller *ctrl)
+{
+       return static_branch_unlikely(&brcmnand_soc_has_ops_key);
+}
+
 static inline u32 nand_readreg(struct brcmnand_controller *ctrl, u32 offs)
 {
+       if (brcmnand_non_mmio_ops(ctrl))
+               return brcmnand_soc_read(ctrl->soc, offs);
        return brcmnand_readl(ctrl->nand_base + offs);
 }
 
 static inline void nand_writereg(struct brcmnand_controller *ctrl, u32 offs,
                                 u32 val)
 {
-       brcmnand_writel(val, ctrl->nand_base + offs);
+       if (brcmnand_non_mmio_ops(ctrl))
+               brcmnand_soc_write(ctrl->soc, val, offs);
+       else
+               brcmnand_writel(val, ctrl->nand_base + offs);
 }
 
 static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
 
 static inline u32 brcmnand_read_fc(struct brcmnand_controller *ctrl, int word)
 {
+       if (brcmnand_non_mmio_ops(ctrl))
+               return brcmnand_soc_read(ctrl->soc, BRCMNAND_NON_MMIO_FC_ADDR);
        return __raw_readl(ctrl->nand_fc + word * 4);
 }
 
 static inline void brcmnand_write_fc(struct brcmnand_controller *ctrl,
                                     int word, u32 val)
 {
-       __raw_writel(val, ctrl->nand_fc + word * 4);
+       if (brcmnand_non_mmio_ops(ctrl))
+               brcmnand_soc_write(ctrl->soc, val, BRCMNAND_NON_MMIO_FC_ADDR);
+       else
+               __raw_writel(val, ctrl->nand_fc + word * 4);
 }
 
 static inline void edu_writel(struct brcmnand_controller *ctrl,
        ctrl->dev = dev;
        ctrl->soc = soc;
 
+       /* Enable the static key if the soc provides I/O operations indicating
+        * that a non-memory mapped IO access path must be used
+        */
+       if (brcmnand_soc_has_ops(ctrl->soc))
+               static_branch_enable(&brcmnand_soc_has_ops_key);
+
        init_completion(&ctrl->done);
        init_completion(&ctrl->dma_done);
        init_completion(&ctrl->edu_done);
 
 
 struct platform_device;
 struct dev_pm_ops;
+struct brcmnand_io_ops;
+
+/* Special register offset constant to intercept a non-MMIO access
+ * to the flash cache register space. This is intentionally large
+ * not to overlap with an existing offset.
+ */
+#define BRCMNAND_NON_MMIO_FC_ADDR      0xffffffff
 
 struct brcmnand_soc {
        bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
        void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
        void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare,
                                 bool is_param);
+       const struct brcmnand_io_ops *ops;
+};
+
+struct brcmnand_io_ops {
+       u32 (*read_reg)(struct brcmnand_soc *soc, u32 offset);
+       void (*write_reg)(struct brcmnand_soc *soc, u32 val, u32 offset);
 };
 
 static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc,
                writel_relaxed(val, addr);
 }
 
+static inline bool brcmnand_soc_has_ops(struct brcmnand_soc *soc)
+{
+       return soc && soc->ops && soc->ops->read_reg && soc->ops->write_reg;
+}
+
+static inline u32 brcmnand_soc_read(struct brcmnand_soc *soc, u32 offset)
+{
+       return soc->ops->read_reg(soc, offset);
+}
+
+static inline void brcmnand_soc_write(struct brcmnand_soc *soc, u32 val,
+                                     u32 offset)
+{
+       soc->ops->write_reg(soc, val, offset);
+}
+
 int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc);
 int brcmnand_remove(struct platform_device *pdev);