1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Driver for Xilinx TMR Manager IP. 4 * 5 * Copyright (C) 2022 Advanced Micro Devices, Inc. 6 * 7 * Description: 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 13 * recovery. 14 */ 15 16 #include <asm/xilinx_mb_manager.h> 17 #include <linux/module.h> 18 #include <linux/of_device.h> 19 20 /* TMR Manager Register offsets */ 21 #define XTMR_MANAGER_CR_OFFSET 0x0 22 #define XTMR_MANAGER_FFR_OFFSET 0x4 23 #define XTMR_MANAGER_CMR0_OFFSET 0x8 24 #define XTMR_MANAGER_CMR1_OFFSET 0xC 25 #define XTMR_MANAGER_BDIR_OFFSET 0x10 26 #define XTMR_MANAGER_SEMIMR_OFFSET 0x1C 27 28 /* Register Bitmasks/shifts */ 29 #define XTMR_MANAGER_CR_MAGIC1_MASK GENMASK(7, 0) 30 #define XTMR_MANAGER_CR_MAGIC2_MASK GENMASK(15, 8) 31 #define XTMR_MANAGER_CR_RIR_MASK BIT(16) 32 #define XTMR_MANAGER_FFR_LM12_MASK BIT(0) 33 #define XTMR_MANAGER_FFR_LM13_MASK BIT(1) 34 #define XTMR_MANAGER_FFR_LM23_MASK BIT(2) 35 36 #define XTMR_MANAGER_CR_MAGIC2_SHIFT 4 37 #define XTMR_MANAGER_CR_RIR_SHIFT 16 38 #define XTMR_MANAGER_CR_BB_SHIFT 18 39 40 #define XTMR_MANAGER_MAGIC1_MAX_VAL 255 41 42 /** 43 * struct xtmr_manager_dev - Driver data for TMR Manager 44 * @regs: device physical base address 45 * @cr_val: control register value 46 * @magic1: Magic 1 hardware configuration value 47 * @err_cnt: error statistics count 48 * @phys_baseaddr: Physical base address 49 */ 50 struct xtmr_manager_dev { 51 void __iomem *regs; 52 u32 cr_val; 53 u32 magic1; 54 u32 err_cnt; 55 resource_size_t phys_baseaddr; 56 }; 57 58 /* IO accessors */ 59 static inline void xtmr_manager_write(struct xtmr_manager_dev *xtmr_manager, 60 u32 addr, u32 value) 61 { 62 iowrite32(value, xtmr_manager->regs + addr); 63 } 64 65 static inline u32 xtmr_manager_read(struct xtmr_manager_dev *xtmr_manager, 66 u32 addr) 67 { 68 return ioread32(xtmr_manager->regs + addr); 69 } 70 71 static void xmb_manager_reset_handler(struct xtmr_manager_dev *xtmr_manager) 72 { 73 /* Clear the FFR Register contents as a part of recovery process. */ 74 xtmr_manager_write(xtmr_manager, XTMR_MANAGER_FFR_OFFSET, 0); 75 } 76 77 static void xmb_manager_update_errcnt(struct xtmr_manager_dev *xtmr_manager) 78 { 79 xtmr_manager->err_cnt++; 80 } 81 82 static ssize_t errcnt_show(struct device *dev, struct device_attribute *attr, 83 char *buf) 84 { 85 struct xtmr_manager_dev *xtmr_manager = dev_get_drvdata(dev); 86 87 return sysfs_emit(buf, "%x\n", xtmr_manager->err_cnt); 88 } 89 static DEVICE_ATTR_RO(errcnt); 90 91 static ssize_t dis_block_break_store(struct device *dev, 92 struct device_attribute *attr, 93 const char *buf, size_t size) 94 { 95 struct xtmr_manager_dev *xtmr_manager = dev_get_drvdata(dev); 96 int ret; 97 long value; 98 99 ret = kstrtoul(buf, 16, &value); 100 if (ret) 101 return ret; 102 103 /* unblock the break signal*/ 104 xtmr_manager->cr_val &= ~(1 << XTMR_MANAGER_CR_BB_SHIFT); 105 xtmr_manager_write(xtmr_manager, XTMR_MANAGER_CR_OFFSET, 106 xtmr_manager->cr_val); 107 return size; 108 } 109 static DEVICE_ATTR_WO(dis_block_break); 110 111 static struct attribute *xtmr_manager_dev_attrs[] = { 112 &dev_attr_dis_block_break.attr, 113 &dev_attr_errcnt.attr, 114 NULL, 115 }; 116 ATTRIBUTE_GROUPS(xtmr_manager_dev); 117 118 static void xtmr_manager_init(struct xtmr_manager_dev *xtmr_manager) 119 { 120 /* Clear the SEM interrupt mask register to disable the interrupt */ 121 xtmr_manager_write(xtmr_manager, XTMR_MANAGER_SEMIMR_OFFSET, 0); 122 123 /* Allow recovery reset by default */ 124 xtmr_manager->cr_val = (1 << XTMR_MANAGER_CR_RIR_SHIFT) | 125 xtmr_manager->magic1; 126 xtmr_manager_write(xtmr_manager, XTMR_MANAGER_CR_OFFSET, 127 xtmr_manager->cr_val); 128 /* 129 * Configure Break Delay Initialization Register to zero so that 130 * break occurs immediately 131 */ 132 xtmr_manager_write(xtmr_manager, XTMR_MANAGER_BDIR_OFFSET, 0); 133 134 /* 135 * To come out of break handler need to block the break signal 136 * in the tmr manager, update the xtmr_manager cr_val for the same 137 */ 138 xtmr_manager->cr_val |= (1 << XTMR_MANAGER_CR_BB_SHIFT); 139 140 /* 141 * When the break vector gets asserted because of error injection, 142 * the break signal must be blocked before exiting from the 143 * break handler, Below api updates the TMR manager address and 144 * control register and error counter callback arguments, 145 * which will be used by the break handler to block the 146 * break and call the callback function. 147 */ 148 xmb_manager_register(xtmr_manager->phys_baseaddr, xtmr_manager->cr_val, 149 (void *)xmb_manager_update_errcnt, 150 xtmr_manager, (void *)xmb_manager_reset_handler); 151 } 152 153 /** 154 * xtmr_manager_probe - Driver probe function 155 * @pdev: Pointer to the platform_device structure 156 * 157 * This is the driver probe routine. It does all the memory 158 * allocation for the device. 159 * 160 * Return: 0 on success and failure value on error 161 */ 162 static int xtmr_manager_probe(struct platform_device *pdev) 163 { 164 struct xtmr_manager_dev *xtmr_manager; 165 struct resource *res; 166 int err; 167 168 xtmr_manager = devm_kzalloc(&pdev->dev, sizeof(*xtmr_manager), 169 GFP_KERNEL); 170 if (!xtmr_manager) 171 return -ENOMEM; 172 173 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 174 xtmr_manager->regs = devm_ioremap_resource(&pdev->dev, res); 175 if (IS_ERR(xtmr_manager->regs)) 176 return PTR_ERR(xtmr_manager->regs); 177 178 xtmr_manager->phys_baseaddr = res->start; 179 180 err = of_property_read_u32(pdev->dev.of_node, "xlnx,magic1", 181 &xtmr_manager->magic1); 182 if (err < 0) { 183 dev_err(&pdev->dev, "unable to read xlnx,magic1 property"); 184 return err; 185 } 186 187 if (xtmr_manager->magic1 > XTMR_MANAGER_MAGIC1_MAX_VAL) { 188 dev_err(&pdev->dev, "invalid xlnx,magic1 property value"); 189 return -EINVAL; 190 } 191 192 /* Initialize TMR Manager */ 193 xtmr_manager_init(xtmr_manager); 194 195 platform_set_drvdata(pdev, xtmr_manager); 196 197 return 0; 198 } 199 200 static const struct of_device_id xtmr_manager_of_match[] = { 201 { 202 .compatible = "xlnx,tmr-manager-1.0", 203 }, 204 { /* end of table */ } 205 }; 206 MODULE_DEVICE_TABLE(of, xtmr_manager_of_match); 207 208 static struct platform_driver xtmr_manager_driver = { 209 .driver = { 210 .name = "xilinx-tmr_manager", 211 .of_match_table = xtmr_manager_of_match, 212 .dev_groups = xtmr_manager_dev_groups, 213 }, 214 .probe = xtmr_manager_probe, 215 }; 216 module_platform_driver(xtmr_manager_driver); 217 218 MODULE_AUTHOR("Advanced Micro Devices, Inc"); 219 MODULE_DESCRIPTION("Xilinx TMR Manager Driver"); 220 MODULE_LICENSE("GPL"); 221