brintos

brintos / linux-shallow public Read only

0
0
Text · 37.8 KiB · ea43369 Raw
1455 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Xilinx SDFEC4 *5 * Copyright (C) 2019 Xilinx, Inc.6 *7 * Description:8 * This driver is developed for SDFEC16 (Soft Decision FEC 16nm)9 * IP. It exposes a char device which supports file operations10 * like  open(), close() and ioctl().11 */12 13#include <linux/miscdevice.h>14#include <linux/io.h>15#include <linux/interrupt.h>16#include <linux/kernel.h>17#include <linux/module.h>18#include <linux/of.h>19#include <linux/platform_device.h>20#include <linux/poll.h>21#include <linux/slab.h>22#include <linux/clk.h>23#include <linux/compat.h>24#include <linux/highmem.h>25 26#include <uapi/misc/xilinx_sdfec.h>27 28#define DEV_NAME_LEN 1229 30static DEFINE_IDA(dev_nrs);31 32/* Xilinx SDFEC Register Map */33/* CODE_WRI_PROTECT Register */34#define XSDFEC_CODE_WR_PROTECT_ADDR (0x4)35 36/* ACTIVE Register */37#define XSDFEC_ACTIVE_ADDR (0x8)38#define XSDFEC_IS_ACTIVITY_SET (0x1)39 40/* AXIS_WIDTH Register */41#define XSDFEC_AXIS_WIDTH_ADDR (0xC)42#define XSDFEC_AXIS_DOUT_WORDS_LSB (5)43#define XSDFEC_AXIS_DOUT_WIDTH_LSB (3)44#define XSDFEC_AXIS_DIN_WORDS_LSB (2)45#define XSDFEC_AXIS_DIN_WIDTH_LSB (0)46 47/* AXIS_ENABLE Register */48#define XSDFEC_AXIS_ENABLE_ADDR (0x10)49#define XSDFEC_AXIS_OUT_ENABLE_MASK (0x38)50#define XSDFEC_AXIS_IN_ENABLE_MASK (0x7)51#define XSDFEC_AXIS_ENABLE_MASK                                                \52	(XSDFEC_AXIS_OUT_ENABLE_MASK | XSDFEC_AXIS_IN_ENABLE_MASK)53 54/* FEC_CODE Register */55#define XSDFEC_FEC_CODE_ADDR (0x14)56 57/* ORDER Register Map */58#define XSDFEC_ORDER_ADDR (0x18)59 60/* Interrupt Status Register */61#define XSDFEC_ISR_ADDR (0x1C)62/* Interrupt Status Register Bit Mask */63#define XSDFEC_ISR_MASK (0x3F)64 65/* Write Only - Interrupt Enable Register */66#define XSDFEC_IER_ADDR (0x20)67/* Write Only - Interrupt Disable Register */68#define XSDFEC_IDR_ADDR (0x24)69/* Read Only - Interrupt Mask Register */70#define XSDFEC_IMR_ADDR (0x28)71 72/* ECC Interrupt Status Register */73#define XSDFEC_ECC_ISR_ADDR (0x2C)74/* Single Bit Errors */75#define XSDFEC_ECC_ISR_SBE_MASK (0x7FF)76/* PL Initialize Single Bit Errors */77#define XSDFEC_PL_INIT_ECC_ISR_SBE_MASK (0x3C00000)78/* Multi Bit Errors */79#define XSDFEC_ECC_ISR_MBE_MASK (0x3FF800)80/* PL Initialize Multi Bit Errors */81#define XSDFEC_PL_INIT_ECC_ISR_MBE_MASK (0x3C000000)82/* Multi Bit Error to Event Shift */83#define XSDFEC_ECC_ISR_MBE_TO_EVENT_SHIFT (11)84/* PL Initialize Multi Bit Error to Event Shift */85#define XSDFEC_PL_INIT_ECC_ISR_MBE_TO_EVENT_SHIFT (4)86/* ECC Interrupt Status Bit Mask */87#define XSDFEC_ECC_ISR_MASK (XSDFEC_ECC_ISR_SBE_MASK | XSDFEC_ECC_ISR_MBE_MASK)88/* ECC Interrupt Status PL Initialize Bit Mask */89#define XSDFEC_PL_INIT_ECC_ISR_MASK                                            \90	(XSDFEC_PL_INIT_ECC_ISR_SBE_MASK | XSDFEC_PL_INIT_ECC_ISR_MBE_MASK)91/* ECC Interrupt Status All Bit Mask */92#define XSDFEC_ALL_ECC_ISR_MASK                                                \93	(XSDFEC_ECC_ISR_MASK | XSDFEC_PL_INIT_ECC_ISR_MASK)94/* ECC Interrupt Status Single Bit Errors Mask */95#define XSDFEC_ALL_ECC_ISR_SBE_MASK                                            \96	(XSDFEC_ECC_ISR_SBE_MASK | XSDFEC_PL_INIT_ECC_ISR_SBE_MASK)97/* ECC Interrupt Status Multi Bit Errors Mask */98#define XSDFEC_ALL_ECC_ISR_MBE_MASK                                            \99	(XSDFEC_ECC_ISR_MBE_MASK | XSDFEC_PL_INIT_ECC_ISR_MBE_MASK)100 101/* Write Only - ECC Interrupt Enable Register */102#define XSDFEC_ECC_IER_ADDR (0x30)103/* Write Only - ECC Interrupt Disable Register */104#define XSDFEC_ECC_IDR_ADDR (0x34)105/* Read Only - ECC Interrupt Mask Register */106#define XSDFEC_ECC_IMR_ADDR (0x38)107 108/* BYPASS Register */109#define XSDFEC_BYPASS_ADDR (0x3C)110 111/* Turbo Code Register */112#define XSDFEC_TURBO_ADDR (0x100)113#define XSDFEC_TURBO_SCALE_MASK (0xFFF)114#define XSDFEC_TURBO_SCALE_BIT_POS (8)115#define XSDFEC_TURBO_SCALE_MAX (15)116 117/* REG0 Register */118#define XSDFEC_LDPC_CODE_REG0_ADDR_BASE (0x2000)119#define XSDFEC_LDPC_CODE_REG0_ADDR_HIGH (0x27F0)120#define XSDFEC_REG0_N_MIN (4)121#define XSDFEC_REG0_N_MAX (32768)122#define XSDFEC_REG0_N_MUL_P (256)123#define XSDFEC_REG0_N_LSB (0)124#define XSDFEC_REG0_K_MIN (2)125#define XSDFEC_REG0_K_MAX (32766)126#define XSDFEC_REG0_K_MUL_P (256)127#define XSDFEC_REG0_K_LSB (16)128 129/* REG1 Register */130#define XSDFEC_LDPC_CODE_REG1_ADDR_BASE (0x2004)131#define XSDFEC_LDPC_CODE_REG1_ADDR_HIGH (0x27f4)132#define XSDFEC_REG1_PSIZE_MIN (2)133#define XSDFEC_REG1_PSIZE_MAX (512)134#define XSDFEC_REG1_NO_PACKING_MASK (0x400)135#define XSDFEC_REG1_NO_PACKING_LSB (10)136#define XSDFEC_REG1_NM_MASK (0xFF800)137#define XSDFEC_REG1_NM_LSB (11)138#define XSDFEC_REG1_BYPASS_MASK (0x100000)139 140/* REG2 Register */141#define XSDFEC_LDPC_CODE_REG2_ADDR_BASE (0x2008)142#define XSDFEC_LDPC_CODE_REG2_ADDR_HIGH (0x27f8)143#define XSDFEC_REG2_NLAYERS_MIN (1)144#define XSDFEC_REG2_NLAYERS_MAX (256)145#define XSDFEC_REG2_NNMQC_MASK (0xFFE00)146#define XSDFEC_REG2_NMQC_LSB (9)147#define XSDFEC_REG2_NORM_TYPE_MASK (0x100000)148#define XSDFEC_REG2_NORM_TYPE_LSB (20)149#define XSDFEC_REG2_SPECIAL_QC_MASK (0x200000)150#define XSDFEC_REG2_SPEICAL_QC_LSB (21)151#define XSDFEC_REG2_NO_FINAL_PARITY_MASK (0x400000)152#define XSDFEC_REG2_NO_FINAL_PARITY_LSB (22)153#define XSDFEC_REG2_MAX_SCHEDULE_MASK (0x1800000)154#define XSDFEC_REG2_MAX_SCHEDULE_LSB (23)155 156/* REG3 Register */157#define XSDFEC_LDPC_CODE_REG3_ADDR_BASE (0x200C)158#define XSDFEC_LDPC_CODE_REG3_ADDR_HIGH (0x27FC)159#define XSDFEC_REG3_LA_OFF_LSB (8)160#define XSDFEC_REG3_QC_OFF_LSB (16)161 162#define XSDFEC_LDPC_REG_JUMP (0x10)163#define XSDFEC_REG_WIDTH_JUMP (4)164 165/* The maximum number of pinned pages */166#define MAX_NUM_PAGES ((XSDFEC_QC_TABLE_DEPTH / PAGE_SIZE) + 1)167 168/**169 * struct xsdfec_clks - For managing SD-FEC clocks170 * @core_clk: Main processing clock for core171 * @axi_clk: AXI4-Lite memory-mapped clock172 * @din_words_clk: DIN Words AXI4-Stream Slave clock173 * @din_clk: DIN AXI4-Stream Slave clock174 * @dout_clk: DOUT Words AXI4-Stream Slave clock175 * @dout_words_clk: DOUT AXI4-Stream Slave clock176 * @ctrl_clk: Control AXI4-Stream Slave clock177 * @status_clk: Status AXI4-Stream Slave clock178 */179struct xsdfec_clks {180	struct clk *core_clk;181	struct clk *axi_clk;182	struct clk *din_words_clk;183	struct clk *din_clk;184	struct clk *dout_clk;185	struct clk *dout_words_clk;186	struct clk *ctrl_clk;187	struct clk *status_clk;188};189 190/**191 * struct xsdfec_dev - Driver data for SDFEC192 * @miscdev: Misc device handle193 * @clks: Clocks managed by the SDFEC driver194 * @waitq: Driver wait queue195 * @config: Configuration of the SDFEC device196 * @dev_name: Device name197 * @flags: spinlock flags198 * @regs: device physical base address199 * @dev: pointer to device struct200 * @state: State of the SDFEC device201 * @error_data_lock: Error counter and states spinlock202 * @dev_id: Device ID203 * @isr_err_count: Count of ISR errors204 * @cecc_count: Count of Correctable ECC errors (SBE)205 * @uecc_count: Count of Uncorrectable ECC errors (MBE)206 * @irq: IRQ number207 * @state_updated: indicates State updated by interrupt handler208 * @stats_updated: indicates Stats updated by interrupt handler209 * @intr_enabled: indicates IRQ enabled210 *211 * This structure contains necessary state for SDFEC driver to operate212 */213struct xsdfec_dev {214	struct miscdevice miscdev;215	struct xsdfec_clks clks;216	wait_queue_head_t waitq;217	struct xsdfec_config config;218	char dev_name[DEV_NAME_LEN];219	unsigned long flags;220	void __iomem *regs;221	struct device *dev;222	enum xsdfec_state state;223	/* Spinlock to protect state_updated and stats_updated */224	spinlock_t error_data_lock;225	int dev_id;226	u32 isr_err_count;227	u32 cecc_count;228	u32 uecc_count;229	int irq;230	bool state_updated;231	bool stats_updated;232	bool intr_enabled;233};234 235static inline void xsdfec_regwrite(struct xsdfec_dev *xsdfec, u32 addr,236				   u32 value)237{238	dev_dbg(xsdfec->dev, "Writing 0x%x to offset 0x%x", value, addr);239	iowrite32(value, xsdfec->regs + addr);240}241 242static inline u32 xsdfec_regread(struct xsdfec_dev *xsdfec, u32 addr)243{244	u32 rval;245 246	rval = ioread32(xsdfec->regs + addr);247	dev_dbg(xsdfec->dev, "Read value = 0x%x from offset 0x%x", rval, addr);248	return rval;249}250 251static void update_bool_config_from_reg(struct xsdfec_dev *xsdfec,252					u32 reg_offset, u32 bit_num,253					char *config_value)254{255	u32 reg_val;256	u32 bit_mask = 1 << bit_num;257 258	reg_val = xsdfec_regread(xsdfec, reg_offset);259	*config_value = (reg_val & bit_mask) > 0;260}261 262static void update_config_from_hw(struct xsdfec_dev *xsdfec)263{264	u32 reg_value;265	bool sdfec_started;266 267	/* Update the Order */268	reg_value = xsdfec_regread(xsdfec, XSDFEC_ORDER_ADDR);269	xsdfec->config.order = reg_value;270 271	update_bool_config_from_reg(xsdfec, XSDFEC_BYPASS_ADDR,272				    0, /* Bit Number, maybe change to mask */273				    &xsdfec->config.bypass);274 275	update_bool_config_from_reg(xsdfec, XSDFEC_CODE_WR_PROTECT_ADDR,276				    0, /* Bit Number */277				    &xsdfec->config.code_wr_protect);278 279	reg_value = xsdfec_regread(xsdfec, XSDFEC_IMR_ADDR);280	xsdfec->config.irq.enable_isr = (reg_value & XSDFEC_ISR_MASK) > 0;281 282	reg_value = xsdfec_regread(xsdfec, XSDFEC_ECC_IMR_ADDR);283	xsdfec->config.irq.enable_ecc_isr =284		(reg_value & XSDFEC_ECC_ISR_MASK) > 0;285 286	reg_value = xsdfec_regread(xsdfec, XSDFEC_AXIS_ENABLE_ADDR);287	sdfec_started = (reg_value & XSDFEC_AXIS_IN_ENABLE_MASK) > 0;288	if (sdfec_started)289		xsdfec->state = XSDFEC_STARTED;290	else291		xsdfec->state = XSDFEC_STOPPED;292}293 294static int xsdfec_get_status(struct xsdfec_dev *xsdfec, void __user *arg)295{296	struct xsdfec_status status;297	int err;298 299	memset(&status, 0, sizeof(status));300	spin_lock_irqsave(&xsdfec->error_data_lock, xsdfec->flags);301	status.state = xsdfec->state;302	xsdfec->state_updated = false;303	spin_unlock_irqrestore(&xsdfec->error_data_lock, xsdfec->flags);304	status.activity = (xsdfec_regread(xsdfec, XSDFEC_ACTIVE_ADDR) &305			   XSDFEC_IS_ACTIVITY_SET);306 307	err = copy_to_user(arg, &status, sizeof(status));308	if (err)309		err = -EFAULT;310 311	return err;312}313 314static int xsdfec_get_config(struct xsdfec_dev *xsdfec, void __user *arg)315{316	int err;317 318	err = copy_to_user(arg, &xsdfec->config, sizeof(xsdfec->config));319	if (err)320		err = -EFAULT;321 322	return err;323}324 325static int xsdfec_isr_enable(struct xsdfec_dev *xsdfec, bool enable)326{327	u32 mask_read;328 329	if (enable) {330		/* Enable */331		xsdfec_regwrite(xsdfec, XSDFEC_IER_ADDR, XSDFEC_ISR_MASK);332		mask_read = xsdfec_regread(xsdfec, XSDFEC_IMR_ADDR);333		if (mask_read & XSDFEC_ISR_MASK) {334			dev_dbg(xsdfec->dev,335				"SDFEC enabling irq with IER failed");336			return -EIO;337		}338	} else {339		/* Disable */340		xsdfec_regwrite(xsdfec, XSDFEC_IDR_ADDR, XSDFEC_ISR_MASK);341		mask_read = xsdfec_regread(xsdfec, XSDFEC_IMR_ADDR);342		if ((mask_read & XSDFEC_ISR_MASK) != XSDFEC_ISR_MASK) {343			dev_dbg(xsdfec->dev,344				"SDFEC disabling irq with IDR failed");345			return -EIO;346		}347	}348	return 0;349}350 351static int xsdfec_ecc_isr_enable(struct xsdfec_dev *xsdfec, bool enable)352{353	u32 mask_read;354 355	if (enable) {356		/* Enable */357		xsdfec_regwrite(xsdfec, XSDFEC_ECC_IER_ADDR,358				XSDFEC_ALL_ECC_ISR_MASK);359		mask_read = xsdfec_regread(xsdfec, XSDFEC_ECC_IMR_ADDR);360		if (mask_read & XSDFEC_ALL_ECC_ISR_MASK) {361			dev_dbg(xsdfec->dev,362				"SDFEC enabling ECC irq with ECC IER failed");363			return -EIO;364		}365	} else {366		/* Disable */367		xsdfec_regwrite(xsdfec, XSDFEC_ECC_IDR_ADDR,368				XSDFEC_ALL_ECC_ISR_MASK);369		mask_read = xsdfec_regread(xsdfec, XSDFEC_ECC_IMR_ADDR);370		if (!(((mask_read & XSDFEC_ALL_ECC_ISR_MASK) ==371		       XSDFEC_ECC_ISR_MASK) ||372		      ((mask_read & XSDFEC_ALL_ECC_ISR_MASK) ==373		       XSDFEC_PL_INIT_ECC_ISR_MASK))) {374			dev_dbg(xsdfec->dev,375				"SDFEC disable ECC irq with ECC IDR failed");376			return -EIO;377		}378	}379	return 0;380}381 382static int xsdfec_set_irq(struct xsdfec_dev *xsdfec, void __user *arg)383{384	struct xsdfec_irq irq;385	int err;386	int isr_err;387	int ecc_err;388 389	err = copy_from_user(&irq, arg, sizeof(irq));390	if (err)391		return -EFAULT;392 393	/* Setup tlast related IRQ */394	isr_err = xsdfec_isr_enable(xsdfec, irq.enable_isr);395	if (!isr_err)396		xsdfec->config.irq.enable_isr = irq.enable_isr;397 398	/* Setup ECC related IRQ */399	ecc_err = xsdfec_ecc_isr_enable(xsdfec, irq.enable_ecc_isr);400	if (!ecc_err)401		xsdfec->config.irq.enable_ecc_isr = irq.enable_ecc_isr;402 403	if (isr_err < 0 || ecc_err < 0)404		err = -EIO;405 406	return err;407}408 409static int xsdfec_set_turbo(struct xsdfec_dev *xsdfec, void __user *arg)410{411	struct xsdfec_turbo turbo;412	int err;413	u32 turbo_write;414 415	err = copy_from_user(&turbo, arg, sizeof(turbo));416	if (err)417		return -EFAULT;418 419	if (turbo.alg >= XSDFEC_TURBO_ALG_MAX)420		return -EINVAL;421 422	if (turbo.scale > XSDFEC_TURBO_SCALE_MAX)423		return -EINVAL;424 425	/* Check to see what device tree says about the FEC codes */426	if (xsdfec->config.code == XSDFEC_LDPC_CODE)427		return -EIO;428 429	turbo_write = ((turbo.scale & XSDFEC_TURBO_SCALE_MASK)430		       << XSDFEC_TURBO_SCALE_BIT_POS) |431		      turbo.alg;432	xsdfec_regwrite(xsdfec, XSDFEC_TURBO_ADDR, turbo_write);433	return err;434}435 436static int xsdfec_get_turbo(struct xsdfec_dev *xsdfec, void __user *arg)437{438	u32 reg_value;439	struct xsdfec_turbo turbo_params;440	int err;441 442	if (xsdfec->config.code == XSDFEC_LDPC_CODE)443		return -EIO;444 445	memset(&turbo_params, 0, sizeof(turbo_params));446	reg_value = xsdfec_regread(xsdfec, XSDFEC_TURBO_ADDR);447 448	turbo_params.scale = (reg_value & XSDFEC_TURBO_SCALE_MASK) >>449			     XSDFEC_TURBO_SCALE_BIT_POS;450	turbo_params.alg = reg_value & 0x1;451 452	err = copy_to_user(arg, &turbo_params, sizeof(turbo_params));453	if (err)454		err = -EFAULT;455 456	return err;457}458 459static int xsdfec_reg0_write(struct xsdfec_dev *xsdfec, u32 n, u32 k, u32 psize,460			     u32 offset)461{462	u32 wdata;463 464	if (n < XSDFEC_REG0_N_MIN || n > XSDFEC_REG0_N_MAX || psize == 0 ||465	    (n > XSDFEC_REG0_N_MUL_P * psize) || n <= k || ((n % psize) != 0)) {466		dev_dbg(xsdfec->dev, "N value is not in range");467		return -EINVAL;468	}469	n <<= XSDFEC_REG0_N_LSB;470 471	if (k < XSDFEC_REG0_K_MIN || k > XSDFEC_REG0_K_MAX ||472	    (k > XSDFEC_REG0_K_MUL_P * psize) || ((k % psize) != 0)) {473		dev_dbg(xsdfec->dev, "K value is not in range");474		return -EINVAL;475	}476	k = k << XSDFEC_REG0_K_LSB;477	wdata = k | n;478 479	if (XSDFEC_LDPC_CODE_REG0_ADDR_BASE + (offset * XSDFEC_LDPC_REG_JUMP) >480	    XSDFEC_LDPC_CODE_REG0_ADDR_HIGH) {481		dev_dbg(xsdfec->dev, "Writing outside of LDPC reg0 space 0x%x",482			XSDFEC_LDPC_CODE_REG0_ADDR_BASE +483				(offset * XSDFEC_LDPC_REG_JUMP));484		return -EINVAL;485	}486	xsdfec_regwrite(xsdfec,487			XSDFEC_LDPC_CODE_REG0_ADDR_BASE +488				(offset * XSDFEC_LDPC_REG_JUMP),489			wdata);490	return 0;491}492 493static int xsdfec_reg1_write(struct xsdfec_dev *xsdfec, u32 psize,494			     u32 no_packing, u32 nm, u32 offset)495{496	u32 wdata;497 498	if (psize < XSDFEC_REG1_PSIZE_MIN || psize > XSDFEC_REG1_PSIZE_MAX) {499		dev_dbg(xsdfec->dev, "Psize is not in range");500		return -EINVAL;501	}502 503	if (no_packing != 0 && no_packing != 1)504		dev_dbg(xsdfec->dev, "No-packing bit register invalid");505	no_packing = ((no_packing << XSDFEC_REG1_NO_PACKING_LSB) &506		      XSDFEC_REG1_NO_PACKING_MASK);507 508	if (nm & ~(XSDFEC_REG1_NM_MASK >> XSDFEC_REG1_NM_LSB))509		dev_dbg(xsdfec->dev, "NM is beyond 10 bits");510	nm = (nm << XSDFEC_REG1_NM_LSB) & XSDFEC_REG1_NM_MASK;511 512	wdata = nm | no_packing | psize;513	if (XSDFEC_LDPC_CODE_REG1_ADDR_BASE + (offset * XSDFEC_LDPC_REG_JUMP) >514	    XSDFEC_LDPC_CODE_REG1_ADDR_HIGH) {515		dev_dbg(xsdfec->dev, "Writing outside of LDPC reg1 space 0x%x",516			XSDFEC_LDPC_CODE_REG1_ADDR_BASE +517				(offset * XSDFEC_LDPC_REG_JUMP));518		return -EINVAL;519	}520	xsdfec_regwrite(xsdfec,521			XSDFEC_LDPC_CODE_REG1_ADDR_BASE +522				(offset * XSDFEC_LDPC_REG_JUMP),523			wdata);524	return 0;525}526 527static int xsdfec_reg2_write(struct xsdfec_dev *xsdfec, u32 nlayers, u32 nmqc,528			     u32 norm_type, u32 special_qc, u32 no_final_parity,529			     u32 max_schedule, u32 offset)530{531	u32 wdata;532 533	if (nlayers < XSDFEC_REG2_NLAYERS_MIN ||534	    nlayers > XSDFEC_REG2_NLAYERS_MAX) {535		dev_dbg(xsdfec->dev, "Nlayers is not in range");536		return -EINVAL;537	}538 539	if (nmqc & ~(XSDFEC_REG2_NNMQC_MASK >> XSDFEC_REG2_NMQC_LSB))540		dev_dbg(xsdfec->dev, "NMQC exceeds 11 bits");541	nmqc = (nmqc << XSDFEC_REG2_NMQC_LSB) & XSDFEC_REG2_NNMQC_MASK;542 543	if (norm_type > 1)544		dev_dbg(xsdfec->dev, "Norm type is invalid");545	norm_type = ((norm_type << XSDFEC_REG2_NORM_TYPE_LSB) &546		     XSDFEC_REG2_NORM_TYPE_MASK);547	if (special_qc > 1)548		dev_dbg(xsdfec->dev, "Special QC in invalid");549	special_qc = ((special_qc << XSDFEC_REG2_SPEICAL_QC_LSB) &550		      XSDFEC_REG2_SPECIAL_QC_MASK);551 552	if (no_final_parity > 1)553		dev_dbg(xsdfec->dev, "No final parity check invalid");554	no_final_parity =555		((no_final_parity << XSDFEC_REG2_NO_FINAL_PARITY_LSB) &556		 XSDFEC_REG2_NO_FINAL_PARITY_MASK);557	if (max_schedule &558	    ~(XSDFEC_REG2_MAX_SCHEDULE_MASK >> XSDFEC_REG2_MAX_SCHEDULE_LSB))559		dev_dbg(xsdfec->dev, "Max Schedule exceeds 2 bits");560	max_schedule = ((max_schedule << XSDFEC_REG2_MAX_SCHEDULE_LSB) &561			XSDFEC_REG2_MAX_SCHEDULE_MASK);562 563	wdata = (max_schedule | no_final_parity | special_qc | norm_type |564		 nmqc | nlayers);565 566	if (XSDFEC_LDPC_CODE_REG2_ADDR_BASE + (offset * XSDFEC_LDPC_REG_JUMP) >567	    XSDFEC_LDPC_CODE_REG2_ADDR_HIGH) {568		dev_dbg(xsdfec->dev, "Writing outside of LDPC reg2 space 0x%x",569			XSDFEC_LDPC_CODE_REG2_ADDR_BASE +570				(offset * XSDFEC_LDPC_REG_JUMP));571		return -EINVAL;572	}573	xsdfec_regwrite(xsdfec,574			XSDFEC_LDPC_CODE_REG2_ADDR_BASE +575				(offset * XSDFEC_LDPC_REG_JUMP),576			wdata);577	return 0;578}579 580static int xsdfec_reg3_write(struct xsdfec_dev *xsdfec, u8 sc_off, u8 la_off,581			     u16 qc_off, u32 offset)582{583	u32 wdata;584 585	wdata = ((qc_off << XSDFEC_REG3_QC_OFF_LSB) |586		 (la_off << XSDFEC_REG3_LA_OFF_LSB) | sc_off);587	if (XSDFEC_LDPC_CODE_REG3_ADDR_BASE + (offset * XSDFEC_LDPC_REG_JUMP) >588	    XSDFEC_LDPC_CODE_REG3_ADDR_HIGH) {589		dev_dbg(xsdfec->dev, "Writing outside of LDPC reg3 space 0x%x",590			XSDFEC_LDPC_CODE_REG3_ADDR_BASE +591				(offset * XSDFEC_LDPC_REG_JUMP));592		return -EINVAL;593	}594	xsdfec_regwrite(xsdfec,595			XSDFEC_LDPC_CODE_REG3_ADDR_BASE +596				(offset * XSDFEC_LDPC_REG_JUMP),597			wdata);598	return 0;599}600 601static int xsdfec_table_write(struct xsdfec_dev *xsdfec, u32 offset,602			      u32 *src_ptr, u32 len, const u32 base_addr,603			      const u32 depth)604{605	u32 reg = 0;606	int res, i, nr_pages;607	u32 n;608	u32 *addr = NULL;609	struct page *pages[MAX_NUM_PAGES];610 611	/*612	 * Writes that go beyond the length of613	 * Shared Scale(SC) table should fail614	 */615	if (offset > depth / XSDFEC_REG_WIDTH_JUMP ||616	    len > depth / XSDFEC_REG_WIDTH_JUMP ||617	    offset + len > depth / XSDFEC_REG_WIDTH_JUMP) {618		dev_dbg(xsdfec->dev, "Write exceeds SC table length");619		return -EINVAL;620	}621 622	n = (len * XSDFEC_REG_WIDTH_JUMP) / PAGE_SIZE;623	if ((len * XSDFEC_REG_WIDTH_JUMP) % PAGE_SIZE)624		n += 1;625 626	if (WARN_ON_ONCE(n > INT_MAX))627		return -EINVAL;628 629	nr_pages = n;630 631	res = pin_user_pages_fast((unsigned long)src_ptr, nr_pages, 0, pages);632	if (res < nr_pages) {633		if (res > 0)634			unpin_user_pages(pages, res);635 636		return -EINVAL;637	}638 639	for (i = 0; i < nr_pages; i++) {640		addr = kmap_local_page(pages[i]);641		do {642			xsdfec_regwrite(xsdfec,643					base_addr + ((offset + reg) *644						     XSDFEC_REG_WIDTH_JUMP),645					addr[reg]);646			reg++;647		} while ((reg < len) &&648			 ((reg * XSDFEC_REG_WIDTH_JUMP) % PAGE_SIZE));649		kunmap_local(addr);650		unpin_user_page(pages[i]);651	}652	return 0;653}654 655static int xsdfec_add_ldpc(struct xsdfec_dev *xsdfec, void __user *arg)656{657	struct xsdfec_ldpc_params *ldpc;658	int ret, n;659 660	ldpc = memdup_user(arg, sizeof(*ldpc));661	if (IS_ERR(ldpc))662		return PTR_ERR(ldpc);663 664	if (xsdfec->config.code == XSDFEC_TURBO_CODE) {665		ret = -EIO;666		goto err_out;667	}668 669	/* Verify Device has not started */670	if (xsdfec->state == XSDFEC_STARTED) {671		ret = -EIO;672		goto err_out;673	}674 675	if (xsdfec->config.code_wr_protect) {676		ret = -EIO;677		goto err_out;678	}679 680	/* Write Reg 0 */681	ret = xsdfec_reg0_write(xsdfec, ldpc->n, ldpc->k, ldpc->psize,682				ldpc->code_id);683	if (ret)684		goto err_out;685 686	/* Write Reg 1 */687	ret = xsdfec_reg1_write(xsdfec, ldpc->psize, ldpc->no_packing, ldpc->nm,688				ldpc->code_id);689	if (ret)690		goto err_out;691 692	/* Write Reg 2 */693	ret = xsdfec_reg2_write(xsdfec, ldpc->nlayers, ldpc->nmqc,694				ldpc->norm_type, ldpc->special_qc,695				ldpc->no_final_parity, ldpc->max_schedule,696				ldpc->code_id);697	if (ret)698		goto err_out;699 700	/* Write Reg 3 */701	ret = xsdfec_reg3_write(xsdfec, ldpc->sc_off, ldpc->la_off,702				ldpc->qc_off, ldpc->code_id);703	if (ret)704		goto err_out;705 706	/* Write Shared Codes */707	n = ldpc->nlayers / 4;708	if (ldpc->nlayers % 4)709		n++;710 711	ret = xsdfec_table_write(xsdfec, ldpc->sc_off, ldpc->sc_table, n,712				 XSDFEC_LDPC_SC_TABLE_ADDR_BASE,713				 XSDFEC_SC_TABLE_DEPTH);714	if (ret < 0)715		goto err_out;716 717	ret = xsdfec_table_write(xsdfec, 4 * ldpc->la_off, ldpc->la_table,718				 ldpc->nlayers, XSDFEC_LDPC_LA_TABLE_ADDR_BASE,719				 XSDFEC_LA_TABLE_DEPTH);720	if (ret < 0)721		goto err_out;722 723	ret = xsdfec_table_write(xsdfec, 4 * ldpc->qc_off, ldpc->qc_table,724				 ldpc->nqc, XSDFEC_LDPC_QC_TABLE_ADDR_BASE,725				 XSDFEC_QC_TABLE_DEPTH);726err_out:727	kfree(ldpc);728	return ret;729}730 731static int xsdfec_set_order(struct xsdfec_dev *xsdfec, void __user *arg)732{733	bool order_invalid;734	enum xsdfec_order order;735	int err;736 737	err = get_user(order, (enum xsdfec_order __user *)arg);738	if (err)739		return -EFAULT;740 741	order_invalid = (order != XSDFEC_MAINTAIN_ORDER) &&742			(order != XSDFEC_OUT_OF_ORDER);743	if (order_invalid)744		return -EINVAL;745 746	/* Verify Device has not started */747	if (xsdfec->state == XSDFEC_STARTED)748		return -EIO;749 750	xsdfec_regwrite(xsdfec, XSDFEC_ORDER_ADDR, order);751 752	xsdfec->config.order = order;753 754	return 0;755}756 757static int xsdfec_set_bypass(struct xsdfec_dev *xsdfec, bool __user *arg)758{759	bool bypass;760	int err;761 762	err = get_user(bypass, arg);763	if (err)764		return -EFAULT;765 766	/* Verify Device has not started */767	if (xsdfec->state == XSDFEC_STARTED)768		return -EIO;769 770	if (bypass)771		xsdfec_regwrite(xsdfec, XSDFEC_BYPASS_ADDR, 1);772	else773		xsdfec_regwrite(xsdfec, XSDFEC_BYPASS_ADDR, 0);774 775	xsdfec->config.bypass = bypass;776 777	return 0;778}779 780static int xsdfec_is_active(struct xsdfec_dev *xsdfec, bool __user *arg)781{782	u32 reg_value;783	bool is_active;784	int err;785 786	reg_value = xsdfec_regread(xsdfec, XSDFEC_ACTIVE_ADDR);787	/* using a double ! operator instead of casting */788	is_active = !!(reg_value & XSDFEC_IS_ACTIVITY_SET);789	err = put_user(is_active, arg);790	if (err)791		return -EFAULT;792 793	return err;794}795 796static u32797xsdfec_translate_axis_width_cfg_val(enum xsdfec_axis_width axis_width_cfg)798{799	u32 axis_width_field = 0;800 801	switch (axis_width_cfg) {802	case XSDFEC_1x128b:803		axis_width_field = 0;804		break;805	case XSDFEC_2x128b:806		axis_width_field = 1;807		break;808	case XSDFEC_4x128b:809		axis_width_field = 2;810		break;811	}812 813	return axis_width_field;814}815 816static u32 xsdfec_translate_axis_words_cfg_val(enum xsdfec_axis_word_include817	axis_word_inc_cfg)818{819	u32 axis_words_field = 0;820 821	if (axis_word_inc_cfg == XSDFEC_FIXED_VALUE ||822	    axis_word_inc_cfg == XSDFEC_IN_BLOCK)823		axis_words_field = 0;824	else if (axis_word_inc_cfg == XSDFEC_PER_AXI_TRANSACTION)825		axis_words_field = 1;826 827	return axis_words_field;828}829 830static int xsdfec_cfg_axi_streams(struct xsdfec_dev *xsdfec)831{832	u32 reg_value;833	u32 dout_words_field;834	u32 dout_width_field;835	u32 din_words_field;836	u32 din_width_field;837	struct xsdfec_config *config = &xsdfec->config;838 839	/* translate config info to register values */840	dout_words_field =841		xsdfec_translate_axis_words_cfg_val(config->dout_word_include);842	dout_width_field =843		xsdfec_translate_axis_width_cfg_val(config->dout_width);844	din_words_field =845		xsdfec_translate_axis_words_cfg_val(config->din_word_include);846	din_width_field =847		xsdfec_translate_axis_width_cfg_val(config->din_width);848 849	reg_value = dout_words_field << XSDFEC_AXIS_DOUT_WORDS_LSB;850	reg_value |= dout_width_field << XSDFEC_AXIS_DOUT_WIDTH_LSB;851	reg_value |= din_words_field << XSDFEC_AXIS_DIN_WORDS_LSB;852	reg_value |= din_width_field << XSDFEC_AXIS_DIN_WIDTH_LSB;853 854	xsdfec_regwrite(xsdfec, XSDFEC_AXIS_WIDTH_ADDR, reg_value);855 856	return 0;857}858 859static int xsdfec_start(struct xsdfec_dev *xsdfec)860{861	u32 regread;862 863	regread = xsdfec_regread(xsdfec, XSDFEC_FEC_CODE_ADDR);864	regread &= 0x1;865	if (regread != xsdfec->config.code) {866		dev_dbg(xsdfec->dev,867			"%s SDFEC HW code does not match driver code, reg %d, code %d",868			__func__, regread, xsdfec->config.code);869		return -EINVAL;870	}871 872	/* Set AXIS enable */873	xsdfec_regwrite(xsdfec, XSDFEC_AXIS_ENABLE_ADDR,874			XSDFEC_AXIS_ENABLE_MASK);875	/* Done */876	xsdfec->state = XSDFEC_STARTED;877	return 0;878}879 880static int xsdfec_stop(struct xsdfec_dev *xsdfec)881{882	u32 regread;883 884	if (xsdfec->state != XSDFEC_STARTED)885		dev_dbg(xsdfec->dev, "Device not started correctly");886	/* Disable AXIS_ENABLE Input interfaces only */887	regread = xsdfec_regread(xsdfec, XSDFEC_AXIS_ENABLE_ADDR);888	regread &= (~XSDFEC_AXIS_IN_ENABLE_MASK);889	xsdfec_regwrite(xsdfec, XSDFEC_AXIS_ENABLE_ADDR, regread);890	/* Stop */891	xsdfec->state = XSDFEC_STOPPED;892	return 0;893}894 895static int xsdfec_clear_stats(struct xsdfec_dev *xsdfec)896{897	spin_lock_irqsave(&xsdfec->error_data_lock, xsdfec->flags);898	xsdfec->isr_err_count = 0;899	xsdfec->uecc_count = 0;900	xsdfec->cecc_count = 0;901	spin_unlock_irqrestore(&xsdfec->error_data_lock, xsdfec->flags);902 903	return 0;904}905 906static int xsdfec_get_stats(struct xsdfec_dev *xsdfec, void __user *arg)907{908	int err;909	struct xsdfec_stats user_stats;910 911	spin_lock_irqsave(&xsdfec->error_data_lock, xsdfec->flags);912	user_stats.isr_err_count = xsdfec->isr_err_count;913	user_stats.cecc_count = xsdfec->cecc_count;914	user_stats.uecc_count = xsdfec->uecc_count;915	xsdfec->stats_updated = false;916	spin_unlock_irqrestore(&xsdfec->error_data_lock, xsdfec->flags);917 918	err = copy_to_user(arg, &user_stats, sizeof(user_stats));919	if (err)920		err = -EFAULT;921 922	return err;923}924 925static int xsdfec_set_default_config(struct xsdfec_dev *xsdfec)926{927	/* Ensure registers are aligned with core configuration */928	xsdfec_regwrite(xsdfec, XSDFEC_FEC_CODE_ADDR, xsdfec->config.code);929	xsdfec_cfg_axi_streams(xsdfec);930	update_config_from_hw(xsdfec);931 932	return 0;933}934 935static long xsdfec_dev_ioctl(struct file *fptr, unsigned int cmd,936			     unsigned long data)937{938	struct xsdfec_dev *xsdfec;939	void __user *arg = (void __user *)data;940	int rval;941 942	xsdfec = container_of(fptr->private_data, struct xsdfec_dev, miscdev);943 944	/* In failed state allow only reset and get status IOCTLs */945	if (xsdfec->state == XSDFEC_NEEDS_RESET &&946	    (cmd != XSDFEC_SET_DEFAULT_CONFIG && cmd != XSDFEC_GET_STATUS &&947	     cmd != XSDFEC_GET_STATS && cmd != XSDFEC_CLEAR_STATS)) {948		return -EPERM;949	}950 951	switch (cmd) {952	case XSDFEC_START_DEV:953		rval = xsdfec_start(xsdfec);954		break;955	case XSDFEC_STOP_DEV:956		rval = xsdfec_stop(xsdfec);957		break;958	case XSDFEC_CLEAR_STATS:959		rval = xsdfec_clear_stats(xsdfec);960		break;961	case XSDFEC_GET_STATS:962		rval = xsdfec_get_stats(xsdfec, arg);963		break;964	case XSDFEC_GET_STATUS:965		rval = xsdfec_get_status(xsdfec, arg);966		break;967	case XSDFEC_GET_CONFIG:968		rval = xsdfec_get_config(xsdfec, arg);969		break;970	case XSDFEC_SET_DEFAULT_CONFIG:971		rval = xsdfec_set_default_config(xsdfec);972		break;973	case XSDFEC_SET_IRQ:974		rval = xsdfec_set_irq(xsdfec, arg);975		break;976	case XSDFEC_SET_TURBO:977		rval = xsdfec_set_turbo(xsdfec, arg);978		break;979	case XSDFEC_GET_TURBO:980		rval = xsdfec_get_turbo(xsdfec, arg);981		break;982	case XSDFEC_ADD_LDPC_CODE_PARAMS:983		rval = xsdfec_add_ldpc(xsdfec, arg);984		break;985	case XSDFEC_SET_ORDER:986		rval = xsdfec_set_order(xsdfec, arg);987		break;988	case XSDFEC_SET_BYPASS:989		rval = xsdfec_set_bypass(xsdfec, arg);990		break;991	case XSDFEC_IS_ACTIVE:992		rval = xsdfec_is_active(xsdfec, (bool __user *)arg);993		break;994	default:995		rval = -ENOTTY;996		break;997	}998	return rval;999}1000 1001static __poll_t xsdfec_poll(struct file *file, poll_table *wait)1002{1003	__poll_t mask = 0;1004	struct xsdfec_dev *xsdfec;1005 1006	xsdfec = container_of(file->private_data, struct xsdfec_dev, miscdev);1007 1008	poll_wait(file, &xsdfec->waitq, wait);1009 1010	/* XSDFEC ISR detected an error */1011	spin_lock_irqsave(&xsdfec->error_data_lock, xsdfec->flags);1012	if (xsdfec->state_updated)1013		mask |= EPOLLIN | EPOLLPRI;1014 1015	if (xsdfec->stats_updated)1016		mask |= EPOLLIN | EPOLLRDNORM;1017	spin_unlock_irqrestore(&xsdfec->error_data_lock, xsdfec->flags);1018 1019	return mask;1020}1021 1022static const struct file_operations xsdfec_fops = {1023	.owner = THIS_MODULE,1024	.unlocked_ioctl = xsdfec_dev_ioctl,1025	.poll = xsdfec_poll,1026	.compat_ioctl = compat_ptr_ioctl,1027};1028 1029static int xsdfec_parse_of(struct xsdfec_dev *xsdfec)1030{1031	struct device *dev = xsdfec->dev;1032	struct device_node *node = dev->of_node;1033	int rval;1034	const char *fec_code;1035	u32 din_width;1036	u32 din_word_include;1037	u32 dout_width;1038	u32 dout_word_include;1039 1040	rval = of_property_read_string(node, "xlnx,sdfec-code", &fec_code);1041	if (rval < 0)1042		return rval;1043 1044	if (!strcasecmp(fec_code, "ldpc"))1045		xsdfec->config.code = XSDFEC_LDPC_CODE;1046	else if (!strcasecmp(fec_code, "turbo"))1047		xsdfec->config.code = XSDFEC_TURBO_CODE;1048	else1049		return -EINVAL;1050 1051	rval = of_property_read_u32(node, "xlnx,sdfec-din-words",1052				    &din_word_include);1053	if (rval < 0)1054		return rval;1055 1056	if (din_word_include < XSDFEC_AXIS_WORDS_INCLUDE_MAX)1057		xsdfec->config.din_word_include = din_word_include;1058	else1059		return -EINVAL;1060 1061	rval = of_property_read_u32(node, "xlnx,sdfec-din-width", &din_width);1062	if (rval < 0)1063		return rval;1064 1065	switch (din_width) {1066	/* Fall through and set for valid values */1067	case XSDFEC_1x128b:1068	case XSDFEC_2x128b:1069	case XSDFEC_4x128b:1070		xsdfec->config.din_width = din_width;1071		break;1072	default:1073		return -EINVAL;1074	}1075 1076	rval = of_property_read_u32(node, "xlnx,sdfec-dout-words",1077				    &dout_word_include);1078	if (rval < 0)1079		return rval;1080 1081	if (dout_word_include < XSDFEC_AXIS_WORDS_INCLUDE_MAX)1082		xsdfec->config.dout_word_include = dout_word_include;1083	else1084		return -EINVAL;1085 1086	rval = of_property_read_u32(node, "xlnx,sdfec-dout-width", &dout_width);1087	if (rval < 0)1088		return rval;1089 1090	switch (dout_width) {1091	/* Fall through and set for valid values */1092	case XSDFEC_1x128b:1093	case XSDFEC_2x128b:1094	case XSDFEC_4x128b:1095		xsdfec->config.dout_width = dout_width;1096		break;1097	default:1098		return -EINVAL;1099	}1100 1101	/* Write LDPC to CODE Register */1102	xsdfec_regwrite(xsdfec, XSDFEC_FEC_CODE_ADDR, xsdfec->config.code);1103 1104	xsdfec_cfg_axi_streams(xsdfec);1105 1106	return 0;1107}1108 1109static irqreturn_t xsdfec_irq_thread(int irq, void *dev_id)1110{1111	struct xsdfec_dev *xsdfec = dev_id;1112	irqreturn_t ret = IRQ_HANDLED;1113	u32 ecc_err;1114	u32 isr_err;1115	u32 uecc_count;1116	u32 cecc_count;1117	u32 isr_err_count;1118	u32 aecc_count;1119	u32 tmp;1120 1121	WARN_ON(xsdfec->irq != irq);1122 1123	/* Mask Interrupts */1124	xsdfec_isr_enable(xsdfec, false);1125	xsdfec_ecc_isr_enable(xsdfec, false);1126	/* Read ISR */1127	ecc_err = xsdfec_regread(xsdfec, XSDFEC_ECC_ISR_ADDR);1128	isr_err = xsdfec_regread(xsdfec, XSDFEC_ISR_ADDR);1129	/* Clear the interrupts */1130	xsdfec_regwrite(xsdfec, XSDFEC_ECC_ISR_ADDR, ecc_err);1131	xsdfec_regwrite(xsdfec, XSDFEC_ISR_ADDR, isr_err);1132 1133	tmp = ecc_err & XSDFEC_ALL_ECC_ISR_MBE_MASK;1134	/* Count uncorrectable 2-bit errors */1135	uecc_count = hweight32(tmp);1136	/* Count all ECC errors */1137	aecc_count = hweight32(ecc_err);1138	/* Number of correctable 1-bit ECC error */1139	cecc_count = aecc_count - 2 * uecc_count;1140	/* Count ISR errors */1141	isr_err_count = hweight32(isr_err);1142	dev_dbg(xsdfec->dev, "tmp=%x, uecc=%x, aecc=%x, cecc=%x, isr=%x", tmp,1143		uecc_count, aecc_count, cecc_count, isr_err_count);1144	dev_dbg(xsdfec->dev, "uecc=%x, cecc=%x, isr=%x", xsdfec->uecc_count,1145		xsdfec->cecc_count, xsdfec->isr_err_count);1146 1147	spin_lock_irqsave(&xsdfec->error_data_lock, xsdfec->flags);1148	/* Add new errors to a 2-bits counter */1149	if (uecc_count)1150		xsdfec->uecc_count += uecc_count;1151	/* Add new errors to a 1-bits counter */1152	if (cecc_count)1153		xsdfec->cecc_count += cecc_count;1154	/* Add new errors to a ISR counter */1155	if (isr_err_count)1156		xsdfec->isr_err_count += isr_err_count;1157 1158	/* Update state/stats flag */1159	if (uecc_count) {1160		if (ecc_err & XSDFEC_ECC_ISR_MBE_MASK)1161			xsdfec->state = XSDFEC_NEEDS_RESET;1162		else if (ecc_err & XSDFEC_PL_INIT_ECC_ISR_MBE_MASK)1163			xsdfec->state = XSDFEC_PL_RECONFIGURE;1164		xsdfec->stats_updated = true;1165		xsdfec->state_updated = true;1166	}1167 1168	if (cecc_count)1169		xsdfec->stats_updated = true;1170 1171	if (isr_err_count) {1172		xsdfec->state = XSDFEC_NEEDS_RESET;1173		xsdfec->stats_updated = true;1174		xsdfec->state_updated = true;1175	}1176 1177	spin_unlock_irqrestore(&xsdfec->error_data_lock, xsdfec->flags);1178	dev_dbg(xsdfec->dev, "state=%x, stats=%x", xsdfec->state_updated,1179		xsdfec->stats_updated);1180 1181	/* Enable another polling */1182	if (xsdfec->state_updated || xsdfec->stats_updated)1183		wake_up_interruptible(&xsdfec->waitq);1184	else1185		ret = IRQ_NONE;1186 1187	/* Unmask Interrupts */1188	xsdfec_isr_enable(xsdfec, true);1189	xsdfec_ecc_isr_enable(xsdfec, true);1190 1191	return ret;1192}1193 1194static int xsdfec_clk_init(struct platform_device *pdev,1195			   struct xsdfec_clks *clks)1196{1197	int err;1198 1199	clks->core_clk = devm_clk_get(&pdev->dev, "core_clk");1200	if (IS_ERR(clks->core_clk)) {1201		dev_err(&pdev->dev, "failed to get core_clk");1202		return PTR_ERR(clks->core_clk);1203	}1204 1205	clks->axi_clk = devm_clk_get(&pdev->dev, "s_axi_aclk");1206	if (IS_ERR(clks->axi_clk)) {1207		dev_err(&pdev->dev, "failed to get axi_clk");1208		return PTR_ERR(clks->axi_clk);1209	}1210 1211	clks->din_words_clk = devm_clk_get(&pdev->dev, "s_axis_din_words_aclk");1212	if (IS_ERR(clks->din_words_clk)) {1213		if (PTR_ERR(clks->din_words_clk) != -ENOENT) {1214			err = PTR_ERR(clks->din_words_clk);1215			return err;1216		}1217		clks->din_words_clk = NULL;1218	}1219 1220	clks->din_clk = devm_clk_get(&pdev->dev, "s_axis_din_aclk");1221	if (IS_ERR(clks->din_clk)) {1222		if (PTR_ERR(clks->din_clk) != -ENOENT) {1223			err = PTR_ERR(clks->din_clk);1224			return err;1225		}1226		clks->din_clk = NULL;1227	}1228 1229	clks->dout_clk = devm_clk_get(&pdev->dev, "m_axis_dout_aclk");1230	if (IS_ERR(clks->dout_clk)) {1231		if (PTR_ERR(clks->dout_clk) != -ENOENT) {1232			err = PTR_ERR(clks->dout_clk);1233			return err;1234		}1235		clks->dout_clk = NULL;1236	}1237 1238	clks->dout_words_clk =1239		devm_clk_get(&pdev->dev, "s_axis_dout_words_aclk");1240	if (IS_ERR(clks->dout_words_clk)) {1241		if (PTR_ERR(clks->dout_words_clk) != -ENOENT) {1242			err = PTR_ERR(clks->dout_words_clk);1243			return err;1244		}1245		clks->dout_words_clk = NULL;1246	}1247 1248	clks->ctrl_clk = devm_clk_get(&pdev->dev, "s_axis_ctrl_aclk");1249	if (IS_ERR(clks->ctrl_clk)) {1250		if (PTR_ERR(clks->ctrl_clk) != -ENOENT) {1251			err = PTR_ERR(clks->ctrl_clk);1252			return err;1253		}1254		clks->ctrl_clk = NULL;1255	}1256 1257	clks->status_clk = devm_clk_get(&pdev->dev, "m_axis_status_aclk");1258	if (IS_ERR(clks->status_clk)) {1259		if (PTR_ERR(clks->status_clk) != -ENOENT) {1260			err = PTR_ERR(clks->status_clk);1261			return err;1262		}1263		clks->status_clk = NULL;1264	}1265 1266	err = clk_prepare_enable(clks->core_clk);1267	if (err) {1268		dev_err(&pdev->dev, "failed to enable core_clk (%d)", err);1269		return err;1270	}1271 1272	err = clk_prepare_enable(clks->axi_clk);1273	if (err) {1274		dev_err(&pdev->dev, "failed to enable axi_clk (%d)", err);1275		goto err_disable_core_clk;1276	}1277 1278	err = clk_prepare_enable(clks->din_clk);1279	if (err) {1280		dev_err(&pdev->dev, "failed to enable din_clk (%d)", err);1281		goto err_disable_axi_clk;1282	}1283 1284	err = clk_prepare_enable(clks->din_words_clk);1285	if (err) {1286		dev_err(&pdev->dev, "failed to enable din_words_clk (%d)", err);1287		goto err_disable_din_clk;1288	}1289 1290	err = clk_prepare_enable(clks->dout_clk);1291	if (err) {1292		dev_err(&pdev->dev, "failed to enable dout_clk (%d)", err);1293		goto err_disable_din_words_clk;1294	}1295 1296	err = clk_prepare_enable(clks->dout_words_clk);1297	if (err) {1298		dev_err(&pdev->dev, "failed to enable dout_words_clk (%d)",1299			err);1300		goto err_disable_dout_clk;1301	}1302 1303	err = clk_prepare_enable(clks->ctrl_clk);1304	if (err) {1305		dev_err(&pdev->dev, "failed to enable ctrl_clk (%d)", err);1306		goto err_disable_dout_words_clk;1307	}1308 1309	err = clk_prepare_enable(clks->status_clk);1310	if (err) {1311		dev_err(&pdev->dev, "failed to enable status_clk (%d)\n", err);1312		goto err_disable_ctrl_clk;1313	}1314 1315	return err;1316 1317err_disable_ctrl_clk:1318	clk_disable_unprepare(clks->ctrl_clk);1319err_disable_dout_words_clk:1320	clk_disable_unprepare(clks->dout_words_clk);1321err_disable_dout_clk:1322	clk_disable_unprepare(clks->dout_clk);1323err_disable_din_words_clk:1324	clk_disable_unprepare(clks->din_words_clk);1325err_disable_din_clk:1326	clk_disable_unprepare(clks->din_clk);1327err_disable_axi_clk:1328	clk_disable_unprepare(clks->axi_clk);1329err_disable_core_clk:1330	clk_disable_unprepare(clks->core_clk);1331 1332	return err;1333}1334 1335static void xsdfec_disable_all_clks(struct xsdfec_clks *clks)1336{1337	clk_disable_unprepare(clks->status_clk);1338	clk_disable_unprepare(clks->ctrl_clk);1339	clk_disable_unprepare(clks->dout_words_clk);1340	clk_disable_unprepare(clks->dout_clk);1341	clk_disable_unprepare(clks->din_words_clk);1342	clk_disable_unprepare(clks->din_clk);1343	clk_disable_unprepare(clks->core_clk);1344	clk_disable_unprepare(clks->axi_clk);1345}1346 1347static int xsdfec_probe(struct platform_device *pdev)1348{1349	struct xsdfec_dev *xsdfec;1350	struct device *dev;1351	int err;1352	bool irq_enabled = true;1353 1354	xsdfec = devm_kzalloc(&pdev->dev, sizeof(*xsdfec), GFP_KERNEL);1355	if (!xsdfec)1356		return -ENOMEM;1357 1358	xsdfec->dev = &pdev->dev;1359	spin_lock_init(&xsdfec->error_data_lock);1360 1361	err = xsdfec_clk_init(pdev, &xsdfec->clks);1362	if (err)1363		return err;1364 1365	dev = xsdfec->dev;1366	xsdfec->regs = devm_platform_ioremap_resource(pdev, 0);1367	if (IS_ERR(xsdfec->regs)) {1368		err = PTR_ERR(xsdfec->regs);1369		goto err_xsdfec_dev;1370	}1371 1372	xsdfec->irq = platform_get_irq(pdev, 0);1373	if (xsdfec->irq < 0) {1374		dev_dbg(dev, "platform_get_irq failed");1375		irq_enabled = false;1376	}1377 1378	err = xsdfec_parse_of(xsdfec);1379	if (err < 0)1380		goto err_xsdfec_dev;1381 1382	update_config_from_hw(xsdfec);1383 1384	/* Save driver private data */1385	platform_set_drvdata(pdev, xsdfec);1386 1387	if (irq_enabled) {1388		init_waitqueue_head(&xsdfec->waitq);1389		/* Register IRQ thread */1390		err = devm_request_threaded_irq(dev, xsdfec->irq, NULL,1391						xsdfec_irq_thread, IRQF_ONESHOT,1392						"xilinx-sdfec16", xsdfec);1393		if (err < 0) {1394			dev_err(dev, "unable to request IRQ%d", xsdfec->irq);1395			goto err_xsdfec_dev;1396		}1397	}1398 1399	err = ida_alloc(&dev_nrs, GFP_KERNEL);1400	if (err < 0)1401		goto err_xsdfec_dev;1402	xsdfec->dev_id = err;1403 1404	snprintf(xsdfec->dev_name, DEV_NAME_LEN, "xsdfec%d", xsdfec->dev_id);1405	xsdfec->miscdev.minor = MISC_DYNAMIC_MINOR;1406	xsdfec->miscdev.name = xsdfec->dev_name;1407	xsdfec->miscdev.fops = &xsdfec_fops;1408	xsdfec->miscdev.parent = dev;1409	err = misc_register(&xsdfec->miscdev);1410	if (err) {1411		dev_err(dev, "error:%d. Unable to register device", err);1412		goto err_xsdfec_ida;1413	}1414	return 0;1415 1416err_xsdfec_ida:1417	ida_free(&dev_nrs, xsdfec->dev_id);1418err_xsdfec_dev:1419	xsdfec_disable_all_clks(&xsdfec->clks);1420	return err;1421}1422 1423static void xsdfec_remove(struct platform_device *pdev)1424{1425	struct xsdfec_dev *xsdfec;1426 1427	xsdfec = platform_get_drvdata(pdev);1428	misc_deregister(&xsdfec->miscdev);1429	ida_free(&dev_nrs, xsdfec->dev_id);1430	xsdfec_disable_all_clks(&xsdfec->clks);1431}1432 1433static const struct of_device_id xsdfec_of_match[] = {1434	{1435		.compatible = "xlnx,sd-fec-1.1",1436	},1437	{ /* end of table */ }1438};1439MODULE_DEVICE_TABLE(of, xsdfec_of_match);1440 1441static struct platform_driver xsdfec_driver = {1442	.driver = {1443		.name = "xilinx-sdfec",1444		.of_match_table = xsdfec_of_match,1445	},1446	.probe = xsdfec_probe,1447	.remove_new =  xsdfec_remove,1448};1449 1450module_platform_driver(xsdfec_driver);1451 1452MODULE_AUTHOR("Xilinx, Inc");1453MODULE_DESCRIPTION("Xilinx SD-FEC16 Driver");1454MODULE_LICENSE("GPL");1455