brintos

brintos / linux-shallow public Read only

0
0
Text · 6.2 KiB · 03912a9 Raw
221 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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, including10 * fault detection and error recovery. The core is triplicated in each of11 * the sub-blocks in the TMR subsystem, and provides majority voting of12 * its internal state provides soft error detection, correction and13 * recovery.14 */15 16#include <asm/xilinx_mb_manager.h>17#include <linux/module.h>18#include <linux/of.h>19#include <linux/platform_device.h>20 21/* TMR Manager Register offsets */22#define XTMR_MANAGER_CR_OFFSET		0x023#define XTMR_MANAGER_FFR_OFFSET		0x424#define XTMR_MANAGER_CMR0_OFFSET	0x825#define XTMR_MANAGER_CMR1_OFFSET	0xC26#define XTMR_MANAGER_BDIR_OFFSET	0x1027#define XTMR_MANAGER_SEMIMR_OFFSET	0x1C28 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)36 37#define XTMR_MANAGER_CR_MAGIC2_SHIFT	438#define XTMR_MANAGER_CR_RIR_SHIFT	1639#define XTMR_MANAGER_CR_BB_SHIFT	1840 41#define XTMR_MANAGER_MAGIC1_MAX_VAL	25542 43/**44 * struct xtmr_manager_dev - Driver data for TMR Manager45 * @regs: device physical base address46 * @cr_val: control register value47 * @magic1: Magic 1 hardware configuration value48 * @err_cnt: error statistics count49 * @phys_baseaddr: Physical base address50 */51struct xtmr_manager_dev {52	void __iomem *regs;53	u32 cr_val;54	u32 magic1;55	u32 err_cnt;56	resource_size_t phys_baseaddr;57};58 59/* IO accessors */60static inline void xtmr_manager_write(struct xtmr_manager_dev *xtmr_manager,61				      u32 addr, u32 value)62{63	iowrite32(value, xtmr_manager->regs + addr);64}65 66static inline u32 xtmr_manager_read(struct xtmr_manager_dev *xtmr_manager,67				    u32 addr)68{69	return ioread32(xtmr_manager->regs + addr);70}71 72static void xmb_manager_reset_handler(struct xtmr_manager_dev *xtmr_manager)73{74	/* Clear the FFR Register contents as a part of recovery process. */75	xtmr_manager_write(xtmr_manager, XTMR_MANAGER_FFR_OFFSET, 0);76}77 78static void xmb_manager_update_errcnt(struct xtmr_manager_dev *xtmr_manager)79{80	xtmr_manager->err_cnt++;81}82 83static ssize_t errcnt_show(struct device *dev, struct device_attribute *attr,84			   char *buf)85{86	struct xtmr_manager_dev *xtmr_manager = dev_get_drvdata(dev);87 88	return sysfs_emit(buf, "%x\n", xtmr_manager->err_cnt);89}90static DEVICE_ATTR_RO(errcnt);91 92static ssize_t dis_block_break_store(struct device *dev,93				     struct device_attribute *attr,94				     const char *buf, size_t size)95{96	struct xtmr_manager_dev *xtmr_manager = dev_get_drvdata(dev);97	int ret;98	long value;99 100	ret = kstrtoul(buf, 16, &value);101	if (ret)102		return ret;103 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);108	return size;109}110static DEVICE_ATTR_WO(dis_block_break);111 112static struct attribute *xtmr_manager_dev_attrs[] = {113	&dev_attr_dis_block_break.attr,114	&dev_attr_errcnt.attr,115	NULL,116};117ATTRIBUTE_GROUPS(xtmr_manager_dev);118 119static void xtmr_manager_init(struct xtmr_manager_dev *xtmr_manager)120{121	/* Clear the SEM interrupt mask register to disable the interrupt */122	xtmr_manager_write(xtmr_manager, XTMR_MANAGER_SEMIMR_OFFSET, 0);123 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);129	/*130	 * Configure Break Delay Initialization Register to zero so that131	 * break occurs immediately132	 */133	xtmr_manager_write(xtmr_manager, XTMR_MANAGER_BDIR_OFFSET, 0);134 135	/*136	 * To come out of break handler need to block the break signal137	 * in the tmr manager, update the xtmr_manager cr_val for the same138	 */139	xtmr_manager->cr_val |= (1 << XTMR_MANAGER_CR_BB_SHIFT);140 141	/*142	 * When the break vector gets asserted because of error injection,143	 * the break signal must be blocked before exiting from the144	 * break handler, Below api updates the TMR manager address and145	 * control register and error counter callback arguments,146	 * which will be used by the break handler to block the147	 * break and call the callback function.148	 */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);152}153 154/**155 * xtmr_manager_probe - Driver probe function156 * @pdev: Pointer to the platform_device structure157 *158 * This is the driver probe routine. It does all the memory159 * allocation for the device.160 *161 * Return: 0 on success and failure value on error162 */163static int xtmr_manager_probe(struct platform_device *pdev)164{165	struct xtmr_manager_dev *xtmr_manager;166	struct resource *res;167	int err;168 169	xtmr_manager = devm_kzalloc(&pdev->dev, sizeof(*xtmr_manager),170				    GFP_KERNEL);171	if (!xtmr_manager)172		return -ENOMEM;173 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);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 200static const struct of_device_id xtmr_manager_of_match[] = {201	{202		.compatible = "xlnx,tmr-manager-1.0",203	},204	{ /* end of table */ }205};206MODULE_DEVICE_TABLE(of, xtmr_manager_of_match);207 208static 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};216module_platform_driver(xtmr_manager_driver);217 218MODULE_AUTHOR("Advanced Micro Devices, Inc");219MODULE_DESCRIPTION("Xilinx TMR Manager Driver");220MODULE_LICENSE("GPL");221