--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Xilinx TMR Inject IP.
+ *
+ * Copyright (C) 2022 Advanced Micro Devices, Inc.
+ *
+ * Description:
+ * This driver is developed for TMR Inject IP,The Triple Modular Redundancy(TMR)
+ * Inject provides fault injection.
+ */
+
+#include <asm/xilinx_mb_manager.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/fault-inject.h>
+
+/* TMR Inject Register offsets */
+#define XTMR_INJECT_CR_OFFSET 0x0
+#define XTMR_INJECT_AIR_OFFSET 0x4
+#define XTMR_INJECT_IIR_OFFSET 0xC
+#define XTMR_INJECT_EAIR_OFFSET 0x10
+#define XTMR_INJECT_ERR_OFFSET 0x204
+
+/* Register Bitmasks/shifts */
+#define XTMR_INJECT_CR_CPUID_SHIFT 8
+#define XTMR_INJECT_CR_IE_SHIFT 10
+#define XTMR_INJECT_IIR_ADDR_MASK GENMASK(31, 16)
+
+#define XTMR_INJECT_MAGIC_MAX_VAL 255
+
+/**
+ * struct xtmr_inject_dev - Driver data for TMR Inject
+ * @regs: device physical base address
+ * @magic: Magic hardware configuration value
+ */
+struct xtmr_inject_dev {
+ void __iomem *regs;
+ u32 magic;
+};
+
+static DECLARE_FAULT_ATTR(inject_fault);
+static char *inject_request;
+module_param(inject_request, charp, 0);
+MODULE_PARM_DESC(inject_request, "default fault injection attributes");
+static struct dentry *dbgfs_root;
+
+/* IO accessors */
+static inline void xtmr_inject_write(struct xtmr_inject_dev *xtmr_inject,
+ u32 addr, u32 value)
+{
+ iowrite32(value, xtmr_inject->regs + addr);
+}
+
+static inline u32 xtmr_inject_read(struct xtmr_inject_dev *xtmr_inject,
+ u32 addr)
+{
+ return ioread32(xtmr_inject->regs + addr);
+}
+
+static int xtmr_inject_set(void *data, u64 val)
+{
+ if (val != 1)
+ return -EINVAL;
+
+ xmb_inject_err();
+ return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(xtmr_inject_fops, NULL, xtmr_inject_set, "%llu\n");
+
+static void xtmr_init_debugfs(struct xtmr_inject_dev *xtmr_inject)
+{
+ struct dentry *dir;
+
+ dbgfs_root = debugfs_create_dir("xtmr_inject", NULL);
+ dir = fault_create_debugfs_attr("inject_fault", dbgfs_root,
+ &inject_fault);
+ debugfs_create_file("inject_fault", 0200, dir, NULL,
+ &xtmr_inject_fops);
+}
+
+static void xtmr_inject_init(struct xtmr_inject_dev *xtmr_inject)
+{
+ u32 cr_val;
+
+ if (inject_request)
+ setup_fault_attr(&inject_fault, inject_request);
+ /* Allow fault injection */
+ cr_val = xtmr_inject->magic |
+ (1 << XTMR_INJECT_CR_IE_SHIFT) |
+ (1 << XTMR_INJECT_CR_CPUID_SHIFT);
+ xtmr_inject_write(xtmr_inject, XTMR_INJECT_CR_OFFSET,
+ cr_val);
+ /* Initialize the address inject and instruction inject registers */
+ xtmr_inject_write(xtmr_inject, XTMR_INJECT_AIR_OFFSET,
+ XMB_INJECT_ERR_OFFSET);
+ xtmr_inject_write(xtmr_inject, XTMR_INJECT_IIR_OFFSET,
+ XMB_INJECT_ERR_OFFSET & XTMR_INJECT_IIR_ADDR_MASK);
+}
+
+/**
+ * xtmr_inject_probe - Driver probe function
+ * @pdev: Pointer to the platform_device structure
+ *
+ * This is the driver probe routine. It does all the memory
+ * allocation for the device.
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int xtmr_inject_probe(struct platform_device *pdev)
+{
+ struct xtmr_inject_dev *xtmr_inject;
+ int err;
+
+ xtmr_inject = devm_kzalloc(&pdev->dev, sizeof(*xtmr_inject),
+ GFP_KERNEL);
+ if (!xtmr_inject)
+ return -ENOMEM;
+
+ xtmr_inject->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(xtmr_inject->regs))
+ return PTR_ERR(xtmr_inject->regs);
+
+ err = of_property_read_u32(pdev->dev.of_node, "xlnx,magic",
+ &xtmr_inject->magic);
+ if (err < 0) {
+ dev_err(&pdev->dev, "unable to read xlnx,magic property");
+ return err;
+ }
+
+ if (xtmr_inject->magic > XTMR_INJECT_MAGIC_MAX_VAL) {
+ dev_err(&pdev->dev, "invalid xlnx,magic property value");
+ return -EINVAL;
+ }
+
+ /* Initialize TMR Inject */
+ xtmr_inject_init(xtmr_inject);
+
+ xtmr_init_debugfs(xtmr_inject);
+
+ platform_set_drvdata(pdev, xtmr_inject);
+
+ return 0;
+}
+
+static int xtmr_inject_remove(struct platform_device *pdev)
+{
+ debugfs_remove_recursive(dbgfs_root);
+ dbgfs_root = NULL;
+ return 0;
+}
+
+static const struct of_device_id xtmr_inject_of_match[] = {
+ {
+ .compatible = "xlnx,tmr-inject-1.0",
+ },
+ { /* end of table */ }
+};
+MODULE_DEVICE_TABLE(of, xtmr_inject_of_match);
+
+static struct platform_driver xtmr_inject_driver = {
+ .driver = {
+ .name = "xilinx-tmr_inject",
+ .of_match_table = xtmr_inject_of_match,
+ },
+ .probe = xtmr_inject_probe,
+ .remove = xtmr_inject_remove,
+};
+module_platform_driver(xtmr_inject_driver);
+MODULE_AUTHOR("Advanced Micro Devices, Inc");
+MODULE_DESCRIPTION("Xilinx TMR Inject Driver");
+MODULE_LICENSE("GPL");