xref: /openbmc/linux/drivers/misc/xilinx_tmr_inject.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1895ae5beSAppana Durga Kedareswara rao // SPDX-License-Identifier: GPL-2.0
2895ae5beSAppana Durga Kedareswara rao /*
3895ae5beSAppana Durga Kedareswara rao  * Driver for Xilinx TMR Inject IP.
4895ae5beSAppana Durga Kedareswara rao  *
5895ae5beSAppana Durga Kedareswara rao  * Copyright (C) 2022 Advanced Micro Devices, Inc.
6895ae5beSAppana Durga Kedareswara rao  *
7895ae5beSAppana Durga Kedareswara rao  * Description:
8895ae5beSAppana Durga Kedareswara rao  * This driver is developed for TMR Inject IP,The Triple Modular Redundancy(TMR)
9895ae5beSAppana Durga Kedareswara rao  * Inject provides fault injection.
10895ae5beSAppana Durga Kedareswara rao  */
11895ae5beSAppana Durga Kedareswara rao 
12895ae5beSAppana Durga Kedareswara rao #include <asm/xilinx_mb_manager.h>
13895ae5beSAppana Durga Kedareswara rao #include <linux/module.h>
14*d9c58aebSRob Herring #include <linux/of.h>
15*d9c58aebSRob Herring #include <linux/platform_device.h>
16895ae5beSAppana Durga Kedareswara rao #include <linux/fault-inject.h>
17895ae5beSAppana Durga Kedareswara rao 
18895ae5beSAppana Durga Kedareswara rao /* TMR Inject Register offsets */
19895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_CR_OFFSET		0x0
20895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_AIR_OFFSET		0x4
21895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_IIR_OFFSET		0xC
22895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_EAIR_OFFSET		0x10
23895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_ERR_OFFSET		0x204
24895ae5beSAppana Durga Kedareswara rao 
25895ae5beSAppana Durga Kedareswara rao /* Register Bitmasks/shifts */
26895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_CR_CPUID_SHIFT	8
27895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_CR_IE_SHIFT		10
28895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_IIR_ADDR_MASK	GENMASK(31, 16)
29895ae5beSAppana Durga Kedareswara rao 
30895ae5beSAppana Durga Kedareswara rao #define XTMR_INJECT_MAGIC_MAX_VAL	255
31895ae5beSAppana Durga Kedareswara rao 
32895ae5beSAppana Durga Kedareswara rao /**
33895ae5beSAppana Durga Kedareswara rao  * struct xtmr_inject_dev - Driver data for TMR Inject
34895ae5beSAppana Durga Kedareswara rao  * @regs: device physical base address
35895ae5beSAppana Durga Kedareswara rao  * @magic: Magic hardware configuration value
36895ae5beSAppana Durga Kedareswara rao  */
37895ae5beSAppana Durga Kedareswara rao struct xtmr_inject_dev {
38895ae5beSAppana Durga Kedareswara rao 	void __iomem *regs;
39895ae5beSAppana Durga Kedareswara rao 	u32 magic;
40895ae5beSAppana Durga Kedareswara rao };
41895ae5beSAppana Durga Kedareswara rao 
42895ae5beSAppana Durga Kedareswara rao static DECLARE_FAULT_ATTR(inject_fault);
43895ae5beSAppana Durga Kedareswara rao static char *inject_request;
44895ae5beSAppana Durga Kedareswara rao module_param(inject_request, charp, 0);
45895ae5beSAppana Durga Kedareswara rao MODULE_PARM_DESC(inject_request, "default fault injection attributes");
46895ae5beSAppana Durga Kedareswara rao static struct dentry *dbgfs_root;
47895ae5beSAppana Durga Kedareswara rao 
48895ae5beSAppana Durga Kedareswara rao /* IO accessors */
xtmr_inject_write(struct xtmr_inject_dev * xtmr_inject,u32 addr,u32 value)49895ae5beSAppana Durga Kedareswara rao static inline void xtmr_inject_write(struct xtmr_inject_dev *xtmr_inject,
50895ae5beSAppana Durga Kedareswara rao 				     u32 addr, u32 value)
51895ae5beSAppana Durga Kedareswara rao {
52895ae5beSAppana Durga Kedareswara rao 	iowrite32(value, xtmr_inject->regs + addr);
53895ae5beSAppana Durga Kedareswara rao }
54895ae5beSAppana Durga Kedareswara rao 
xtmr_inject_read(struct xtmr_inject_dev * xtmr_inject,u32 addr)55895ae5beSAppana Durga Kedareswara rao static inline u32 xtmr_inject_read(struct xtmr_inject_dev *xtmr_inject,
56895ae5beSAppana Durga Kedareswara rao 				   u32 addr)
57895ae5beSAppana Durga Kedareswara rao {
58895ae5beSAppana Durga Kedareswara rao 	return ioread32(xtmr_inject->regs + addr);
59895ae5beSAppana Durga Kedareswara rao }
60895ae5beSAppana Durga Kedareswara rao 
xtmr_inject_set(void * data,u64 val)61895ae5beSAppana Durga Kedareswara rao static int xtmr_inject_set(void *data, u64 val)
62895ae5beSAppana Durga Kedareswara rao {
63895ae5beSAppana Durga Kedareswara rao 	if (val != 1)
64895ae5beSAppana Durga Kedareswara rao 		return -EINVAL;
65895ae5beSAppana Durga Kedareswara rao 
66895ae5beSAppana Durga Kedareswara rao 	xmb_inject_err();
67895ae5beSAppana Durga Kedareswara rao 	return 0;
68895ae5beSAppana Durga Kedareswara rao }
69895ae5beSAppana Durga Kedareswara rao DEFINE_DEBUGFS_ATTRIBUTE(xtmr_inject_fops, NULL, xtmr_inject_set, "%llu\n");
70895ae5beSAppana Durga Kedareswara rao 
xtmr_init_debugfs(struct xtmr_inject_dev * xtmr_inject)71895ae5beSAppana Durga Kedareswara rao static void xtmr_init_debugfs(struct xtmr_inject_dev *xtmr_inject)
72895ae5beSAppana Durga Kedareswara rao {
73895ae5beSAppana Durga Kedareswara rao 	struct dentry *dir;
74895ae5beSAppana Durga Kedareswara rao 
75895ae5beSAppana Durga Kedareswara rao 	dbgfs_root = debugfs_create_dir("xtmr_inject", NULL);
76895ae5beSAppana Durga Kedareswara rao 	dir = fault_create_debugfs_attr("inject_fault", dbgfs_root,
77895ae5beSAppana Durga Kedareswara rao 					&inject_fault);
78895ae5beSAppana Durga Kedareswara rao 	debugfs_create_file("inject_fault", 0200, dir, NULL,
79895ae5beSAppana Durga Kedareswara rao 			    &xtmr_inject_fops);
80895ae5beSAppana Durga Kedareswara rao }
81895ae5beSAppana Durga Kedareswara rao 
xtmr_inject_init(struct xtmr_inject_dev * xtmr_inject)82895ae5beSAppana Durga Kedareswara rao static void xtmr_inject_init(struct xtmr_inject_dev *xtmr_inject)
83895ae5beSAppana Durga Kedareswara rao {
84895ae5beSAppana Durga Kedareswara rao 	u32 cr_val;
85895ae5beSAppana Durga Kedareswara rao 
86895ae5beSAppana Durga Kedareswara rao 	if (inject_request)
87895ae5beSAppana Durga Kedareswara rao 		setup_fault_attr(&inject_fault, inject_request);
88895ae5beSAppana Durga Kedareswara rao 	/* Allow fault injection */
89895ae5beSAppana Durga Kedareswara rao 	cr_val = xtmr_inject->magic |
90895ae5beSAppana Durga Kedareswara rao 		 (1 << XTMR_INJECT_CR_IE_SHIFT) |
91895ae5beSAppana Durga Kedareswara rao 		 (1 << XTMR_INJECT_CR_CPUID_SHIFT);
92895ae5beSAppana Durga Kedareswara rao 	xtmr_inject_write(xtmr_inject, XTMR_INJECT_CR_OFFSET,
93895ae5beSAppana Durga Kedareswara rao 			  cr_val);
94895ae5beSAppana Durga Kedareswara rao 	/* Initialize the address inject and instruction inject registers */
95895ae5beSAppana Durga Kedareswara rao 	xtmr_inject_write(xtmr_inject, XTMR_INJECT_AIR_OFFSET,
96895ae5beSAppana Durga Kedareswara rao 			  XMB_INJECT_ERR_OFFSET);
97895ae5beSAppana Durga Kedareswara rao 	xtmr_inject_write(xtmr_inject, XTMR_INJECT_IIR_OFFSET,
98895ae5beSAppana Durga Kedareswara rao 			  XMB_INJECT_ERR_OFFSET & XTMR_INJECT_IIR_ADDR_MASK);
99895ae5beSAppana Durga Kedareswara rao }
100895ae5beSAppana Durga Kedareswara rao 
101895ae5beSAppana Durga Kedareswara rao /**
102895ae5beSAppana Durga Kedareswara rao  * xtmr_inject_probe - Driver probe function
103895ae5beSAppana Durga Kedareswara rao  * @pdev: Pointer to the platform_device structure
104895ae5beSAppana Durga Kedareswara rao  *
105895ae5beSAppana Durga Kedareswara rao  * This is the driver probe routine. It does all the memory
106895ae5beSAppana Durga Kedareswara rao  * allocation for the device.
107895ae5beSAppana Durga Kedareswara rao  *
108895ae5beSAppana Durga Kedareswara rao  * Return: 0 on success and failure value on error
109895ae5beSAppana Durga Kedareswara rao  */
xtmr_inject_probe(struct platform_device * pdev)110895ae5beSAppana Durga Kedareswara rao static int xtmr_inject_probe(struct platform_device *pdev)
111895ae5beSAppana Durga Kedareswara rao {
112895ae5beSAppana Durga Kedareswara rao 	struct xtmr_inject_dev *xtmr_inject;
113895ae5beSAppana Durga Kedareswara rao 	int err;
114895ae5beSAppana Durga Kedareswara rao 
115895ae5beSAppana Durga Kedareswara rao 	xtmr_inject = devm_kzalloc(&pdev->dev, sizeof(*xtmr_inject),
116895ae5beSAppana Durga Kedareswara rao 				   GFP_KERNEL);
117895ae5beSAppana Durga Kedareswara rao 	if (!xtmr_inject)
118895ae5beSAppana Durga Kedareswara rao 		return -ENOMEM;
119895ae5beSAppana Durga Kedareswara rao 
120895ae5beSAppana Durga Kedareswara rao 	xtmr_inject->regs = devm_platform_ioremap_resource(pdev, 0);
121895ae5beSAppana Durga Kedareswara rao 	if (IS_ERR(xtmr_inject->regs))
122895ae5beSAppana Durga Kedareswara rao 		return PTR_ERR(xtmr_inject->regs);
123895ae5beSAppana Durga Kedareswara rao 
124895ae5beSAppana Durga Kedareswara rao 	err = of_property_read_u32(pdev->dev.of_node, "xlnx,magic",
125895ae5beSAppana Durga Kedareswara rao 				   &xtmr_inject->magic);
126895ae5beSAppana Durga Kedareswara rao 	if (err < 0) {
127895ae5beSAppana Durga Kedareswara rao 		dev_err(&pdev->dev, "unable to read xlnx,magic property");
128895ae5beSAppana Durga Kedareswara rao 		return err;
129895ae5beSAppana Durga Kedareswara rao 	}
130895ae5beSAppana Durga Kedareswara rao 
131895ae5beSAppana Durga Kedareswara rao 	if (xtmr_inject->magic > XTMR_INJECT_MAGIC_MAX_VAL) {
132895ae5beSAppana Durga Kedareswara rao 		dev_err(&pdev->dev, "invalid xlnx,magic property value");
133895ae5beSAppana Durga Kedareswara rao 		return -EINVAL;
134895ae5beSAppana Durga Kedareswara rao 	}
135895ae5beSAppana Durga Kedareswara rao 
136895ae5beSAppana Durga Kedareswara rao 	/* Initialize TMR Inject */
137895ae5beSAppana Durga Kedareswara rao 	xtmr_inject_init(xtmr_inject);
138895ae5beSAppana Durga Kedareswara rao 
139895ae5beSAppana Durga Kedareswara rao 	xtmr_init_debugfs(xtmr_inject);
140895ae5beSAppana Durga Kedareswara rao 
141895ae5beSAppana Durga Kedareswara rao 	platform_set_drvdata(pdev, xtmr_inject);
142895ae5beSAppana Durga Kedareswara rao 
143895ae5beSAppana Durga Kedareswara rao 	return 0;
144895ae5beSAppana Durga Kedareswara rao }
145895ae5beSAppana Durga Kedareswara rao 
xtmr_inject_remove(struct platform_device * pdev)146895ae5beSAppana Durga Kedareswara rao static int xtmr_inject_remove(struct platform_device *pdev)
147895ae5beSAppana Durga Kedareswara rao {
148895ae5beSAppana Durga Kedareswara rao 	debugfs_remove_recursive(dbgfs_root);
149895ae5beSAppana Durga Kedareswara rao 	dbgfs_root = NULL;
150895ae5beSAppana Durga Kedareswara rao 	return 0;
151895ae5beSAppana Durga Kedareswara rao }
152895ae5beSAppana Durga Kedareswara rao 
153895ae5beSAppana Durga Kedareswara rao static const struct of_device_id xtmr_inject_of_match[] = {
154895ae5beSAppana Durga Kedareswara rao 	{
155895ae5beSAppana Durga Kedareswara rao 		.compatible = "xlnx,tmr-inject-1.0",
156895ae5beSAppana Durga Kedareswara rao 	},
157895ae5beSAppana Durga Kedareswara rao 	{ /* end of table */ }
158895ae5beSAppana Durga Kedareswara rao };
159895ae5beSAppana Durga Kedareswara rao MODULE_DEVICE_TABLE(of, xtmr_inject_of_match);
160895ae5beSAppana Durga Kedareswara rao 
161895ae5beSAppana Durga Kedareswara rao static struct platform_driver xtmr_inject_driver = {
162895ae5beSAppana Durga Kedareswara rao 	.driver = {
163895ae5beSAppana Durga Kedareswara rao 		.name = "xilinx-tmr_inject",
164895ae5beSAppana Durga Kedareswara rao 		.of_match_table = xtmr_inject_of_match,
165895ae5beSAppana Durga Kedareswara rao 	},
166895ae5beSAppana Durga Kedareswara rao 	.probe = xtmr_inject_probe,
167895ae5beSAppana Durga Kedareswara rao 	.remove = xtmr_inject_remove,
168895ae5beSAppana Durga Kedareswara rao };
169895ae5beSAppana Durga Kedareswara rao module_platform_driver(xtmr_inject_driver);
170895ae5beSAppana Durga Kedareswara rao MODULE_AUTHOR("Advanced Micro Devices, Inc");
171895ae5beSAppana Durga Kedareswara rao MODULE_DESCRIPTION("Xilinx TMR Inject Driver");
172895ae5beSAppana Durga Kedareswara rao MODULE_LICENSE("GPL");
173