1 // SPDX-License-Identifier: GPL-2.0
3 * Driver for Xilinx TMR Manager IP.
5 * Copyright (C) 2022 Advanced Micro Devices, Inc.
8 * This driver is developed for TMR Manager,The Triple Modular Redundancy(TMR)
9 * Manager is responsible for handling the TMR subsystem state, including
10 * fault detection and error recovery. The core is triplicated in each of
11 * the sub-blocks in the TMR subsystem, and provides majority voting of
12 * its internal state provides soft error detection, correction and
16 #include <asm/xilinx_mb_manager.h>
17 #include <linux/module.h>
19 #include <linux/platform_device.h>
21 /* TMR Manager Register offsets */
22 #define XTMR_MANAGER_CR_OFFSET 0x0
23 #define XTMR_MANAGER_FFR_OFFSET 0x4
24 #define XTMR_MANAGER_CMR0_OFFSET 0x8
25 #define XTMR_MANAGER_CMR1_OFFSET 0xC
26 #define XTMR_MANAGER_BDIR_OFFSET 0x10
27 #define XTMR_MANAGER_SEMIMR_OFFSET 0x1C
29 /* Register Bitmasks/shifts */
30 #define XTMR_MANAGER_CR_MAGIC1_MASK GENMASK(7, 0)
31 #define XTMR_MANAGER_CR_MAGIC2_MASK GENMASK(15, 8)
32 #define XTMR_MANAGER_CR_RIR_MASK BIT(16)
33 #define XTMR_MANAGER_FFR_LM12_MASK BIT(0)
34 #define XTMR_MANAGER_FFR_LM13_MASK BIT(1)
35 #define XTMR_MANAGER_FFR_LM23_MASK BIT(2)
37 #define XTMR_MANAGER_CR_MAGIC2_SHIFT 4
38 #define XTMR_MANAGER_CR_RIR_SHIFT 16
39 #define XTMR_MANAGER_CR_BB_SHIFT 18
41 #define XTMR_MANAGER_MAGIC1_MAX_VAL 255
44 * struct xtmr_manager_dev - Driver data for TMR Manager
45 * @regs: device physical base address
46 * @cr_val: control register value
47 * @magic1: Magic 1 hardware configuration value
48 * @err_cnt: error statistics count
49 * @phys_baseaddr: Physical base address
51 struct xtmr_manager_dev
{
56 resource_size_t phys_baseaddr
;
60 static inline void xtmr_manager_write(struct xtmr_manager_dev
*xtmr_manager
,
63 iowrite32(value
, xtmr_manager
->regs
+ addr
);
66 static inline u32
xtmr_manager_read(struct xtmr_manager_dev
*xtmr_manager
,
69 return ioread32(xtmr_manager
->regs
+ addr
);
72 static void xmb_manager_reset_handler(struct xtmr_manager_dev
*xtmr_manager
)
74 /* Clear the FFR Register contents as a part of recovery process. */
75 xtmr_manager_write(xtmr_manager
, XTMR_MANAGER_FFR_OFFSET
, 0);
78 static void xmb_manager_update_errcnt(struct xtmr_manager_dev
*xtmr_manager
)
80 xtmr_manager
->err_cnt
++;
83 static ssize_t
errcnt_show(struct device
*dev
, struct device_attribute
*attr
,
86 struct xtmr_manager_dev
*xtmr_manager
= dev_get_drvdata(dev
);
88 return sysfs_emit(buf
, "%x\n", xtmr_manager
->err_cnt
);
90 static DEVICE_ATTR_RO(errcnt
);
92 static ssize_t
dis_block_break_store(struct device
*dev
,
93 struct device_attribute
*attr
,
94 const char *buf
, size_t size
)
96 struct xtmr_manager_dev
*xtmr_manager
= dev_get_drvdata(dev
);
100 ret
= kstrtoul(buf
, 16, &value
);
104 /* unblock the break signal*/
105 xtmr_manager
->cr_val
&= ~(1 << XTMR_MANAGER_CR_BB_SHIFT
);
106 xtmr_manager_write(xtmr_manager
, XTMR_MANAGER_CR_OFFSET
,
107 xtmr_manager
->cr_val
);
110 static DEVICE_ATTR_WO(dis_block_break
);
112 static struct attribute
*xtmr_manager_dev_attrs
[] = {
113 &dev_attr_dis_block_break
.attr
,
114 &dev_attr_errcnt
.attr
,
117 ATTRIBUTE_GROUPS(xtmr_manager_dev
);
119 static void xtmr_manager_init(struct xtmr_manager_dev
*xtmr_manager
)
121 /* Clear the SEM interrupt mask register to disable the interrupt */
122 xtmr_manager_write(xtmr_manager
, XTMR_MANAGER_SEMIMR_OFFSET
, 0);
124 /* Allow recovery reset by default */
125 xtmr_manager
->cr_val
= (1 << XTMR_MANAGER_CR_RIR_SHIFT
) |
126 xtmr_manager
->magic1
;
127 xtmr_manager_write(xtmr_manager
, XTMR_MANAGER_CR_OFFSET
,
128 xtmr_manager
->cr_val
);
130 * Configure Break Delay Initialization Register to zero so that
131 * break occurs immediately
133 xtmr_manager_write(xtmr_manager
, XTMR_MANAGER_BDIR_OFFSET
, 0);
136 * To come out of break handler need to block the break signal
137 * in the tmr manager, update the xtmr_manager cr_val for the same
139 xtmr_manager
->cr_val
|= (1 << XTMR_MANAGER_CR_BB_SHIFT
);
142 * When the break vector gets asserted because of error injection,
143 * the break signal must be blocked before exiting from the
144 * break handler, Below api updates the TMR manager address and
145 * control register and error counter callback arguments,
146 * which will be used by the break handler to block the
147 * break and call the callback function.
149 xmb_manager_register(xtmr_manager
->phys_baseaddr
, xtmr_manager
->cr_val
,
150 (void *)xmb_manager_update_errcnt
,
151 xtmr_manager
, (void *)xmb_manager_reset_handler
);
155 * xtmr_manager_probe - Driver probe function
156 * @pdev: Pointer to the platform_device structure
158 * This is the driver probe routine. It does all the memory
159 * allocation for the device.
161 * Return: 0 on success and failure value on error
163 static int xtmr_manager_probe(struct platform_device
*pdev
)
165 struct xtmr_manager_dev
*xtmr_manager
;
166 struct resource
*res
;
169 xtmr_manager
= devm_kzalloc(&pdev
->dev
, sizeof(*xtmr_manager
),
174 xtmr_manager
->regs
= devm_platform_get_and_ioremap_resource(pdev
, 0, &res
);
175 if (IS_ERR(xtmr_manager
->regs
))
176 return PTR_ERR(xtmr_manager
->regs
);
178 xtmr_manager
->phys_baseaddr
= res
->start
;
180 err
= of_property_read_u32(pdev
->dev
.of_node
, "xlnx,magic1",
181 &xtmr_manager
->magic1
);
183 dev_err(&pdev
->dev
, "unable to read xlnx,magic1 property");
187 if (xtmr_manager
->magic1
> XTMR_MANAGER_MAGIC1_MAX_VAL
) {
188 dev_err(&pdev
->dev
, "invalid xlnx,magic1 property value");
192 /* Initialize TMR Manager */
193 xtmr_manager_init(xtmr_manager
);
195 platform_set_drvdata(pdev
, xtmr_manager
);
200 static const struct of_device_id xtmr_manager_of_match
[] = {
202 .compatible
= "xlnx,tmr-manager-1.0",
204 { /* end of table */ }
206 MODULE_DEVICE_TABLE(of
, xtmr_manager_of_match
);
208 static struct platform_driver xtmr_manager_driver
= {
210 .name
= "xilinx-tmr_manager",
211 .of_match_table
= xtmr_manager_of_match
,
212 .dev_groups
= xtmr_manager_dev_groups
,
214 .probe
= xtmr_manager_probe
,
216 module_platform_driver(xtmr_manager_driver
);
218 MODULE_AUTHOR("Advanced Micro Devices, Inc");
219 MODULE_DESCRIPTION("Xilinx TMR Manager Driver");
220 MODULE_LICENSE("GPL");