]> rtime.felk.cvut.cz Git - zynq/linux.git/blob - drivers/misc/xilinx_sdfec.c
misc: xilinx-sdfec: Change struct for GET_STATUS IOCTL
[zynq/linux.git] / drivers / misc / xilinx_sdfec.c
1 /*
2  * Xilinx SDFEC
3  *
4  * Copyright (C) 2016 - 2017 Xilinx, Inc.
5  *
6  * Description:
7  * This driver is developed for SDFEC16 (Soft Decision FEC 16nm)
8  * IP. It exposes a char device interface in sysfs and supports file
9  * operations like  open(), close() and ioctl().
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 #include <linux/cdev.h>
26 #include <linux/device.h>
27 #include <linux/fs.h>
28 #include <linux/io.h>
29 #include <linux/interrupt.h>
30 #include <linux/kernel.h>
31 #include <linux/module.h>
32 #include <linux/of.h>
33 #include <linux/of_platform.h>
34 #include <linux/platform_device.h>
35 #include <linux/poll.h>
36 #include <linux/slab.h>
37 #include <linux/uaccess.h>
38
39 #include <uapi/misc/xilinx_sdfec.h>
40
41 #define DRIVER_NAME     "xilinx_sdfec"
42 #define DRIVER_VERSION  "0.3"
43 #define DRIVER_MAX_DEV  (6)
44
45 static  struct class *xsdfec_class;
46 static atomic_t xsdfec_ndevs = ATOMIC_INIT(0);
47 static dev_t xsdfec_devt;
48
49 /* Xilinx SDFEC Register Map */
50 #define XSDFEC_AXI_WR_PROTECT_ADDR              (0x00000)
51 #define XSDFEC_CODE_WR_PROTECT_ADDR             (0x00004)
52 #define XSDFEC_ACTIVE_ADDR                      (0x00008)
53 #define XSDFEC_AXIS_WIDTH_ADDR                  (0x0000c)
54 #define XSDFEC_AXIS_ENABLE_ADDR                 (0x00010)
55 #define XSDFEC_AXIS_ENABLE_MASK                 (0x0001F)
56 #define XSDFEC_FEC_CODE_ADDR                    (0x00014)
57 #define XSDFEC_ORDER_ADDR                       (0x00018)
58
59 /* Interrupt Status Register Bit Mask*/
60 #define XSDFEC_ISR_MASK                         (0x0003F)
61 /* Interrupt Status Register */
62 #define XSDFEC_ISR_ADDR                         (0x0001c)
63 /* Write Only - Interrupt Enable Register */
64 #define XSDFEC_IER_ADDR                         (0x00020)
65 /* Write Only - Interrupt Disable Register */
66 #define XSDFEC_IDR_ADDR                         (0x00024)
67 /* Read Only - Interrupt Mask Register */
68 #define XSDFEC_IMR_ADDR                         (0x00028)
69
70 /* Single Bit Errors */
71 #define XSDFEC_ECC_ISR_SBE                      (0x7FF)
72 /* Multi Bit Errors */
73 #define XSDFEC_ECC_ISR_MBE                      (0x3FF800)
74 /* ECC Interrupt Status Bit Mask */
75 #define XSDFEC_ECC_ISR_MASK     (XSDFEC_ECC_ISR_SBE | XSDFEC_ECC_ISR_MBE)
76
77 /* Multi Bit Error Postion */
78 #define XSDFEC_ECC_MULTI_BIT_POS                (11)
79 #define XSDFEC_ERROR_MAX_THRESHOLD              (100)
80
81 /* ECC Interrupt Status Register */
82 #define XSDFEC_ECC_ISR_ADDR                     (0x0002c)
83 /* Write Only - ECC Interrupt Enable Register */
84 #define XSDFEC_ECC_IER_ADDR                     (0x00030)
85 /* Write Only - ECC Interrupt Disable Register */
86 #define XSDFEC_ECC_IDR_ADDR                     (0x00034)
87 /* Read Only - ECC Interrupt Mask Register */
88 #define XSDFEC_ECC_IMR_ADDR                     (0x00038)
89
90 #define XSDFEC_BYPASS_ADDR                      (0x0003c)
91 #define XSDFEC_TEST_EMA_ADDR_BASE               (0x00080)
92 #define XSDFEC_TEST_EMA_ADDR_HIGH               (0x00089)
93 #define XSDFEC_TURBO_ADDR                       (0x00100)
94 #define XSDFEC_LDPC_CODE_REG0_ADDR_BASE         (0x02000)
95 #define XSDFEC_LDPC_CODE_REG0_ADDR_HIGH         (0x021fc)
96 #define XSDFEC_LDPC_CODE_REG1_ADDR_BASE         (0x02004)
97 #define XSDFEC_LDPC_CODE_REG1_ADDR_HIGH         (0x02200)
98 #define XSDFEC_LDPC_CODE_REG2_ADDR_BASE         (0x02008)
99 #define XSDFEC_LDPC_CODE_REG2_ADDR_HIGH         (0x02204)
100 #define XSDFEC_LDPC_CODE_REG3_ADDR_BASE         (0x0200c)
101 #define XSDFEC_LDPC_CODE_REG3_ADDR_HIGH         (0x02208)
102
103 /**
104  * struct xsdfec_dev - Driver data for SDFEC
105  * @regs: device physical base address
106  * @dev: pointer to device struct
107  * @fec_id: Instance number
108  * @intr_enabled: indicates IRQ enabled
109  * @wr_protect: indicates Write Protect enabled
110  * @code: LDPC or Turbo Codes being used
111  * @order: In-Order or Out-of-Order
112  * @state: State of the SDFEC device
113  * @op_mode: Operating in Encode or Decode
114  * @isr_err_count: Count of ISR errors
115  * @cecc_count: Count of Correctable ECC errors (SBE)
116  * @uecc_count: Count of Uncorrectable ECC errors (MBE)
117  * @reset_count: Count of Resets requested
118  * @open_count: Count of char device being opened
119  * @irq: IRQ number
120  * @xsdfec_cdev: Character device handle
121  * @sc_off: Shared Scale Table Offset
122  * @qc_off: Shared Circulant Table Offset
123  * @la_off: Shared Layer Table Offset
124  * @waitq: Driver wait queue
125  *
126  * This structure contains necessary state for SDFEC driver to operate
127  */
128 struct xsdfec_dev {
129         void __iomem *regs;
130         struct device *dev;
131         s32  fec_id;
132         bool intr_enabled;
133         bool wr_protect;
134         enum xsdfec_code code;
135         enum xsdfec_order order;
136         enum xsdfec_state state;
137         enum xsdfec_op_mode op_mode;
138         atomic_t isr_err_count;
139         atomic_t cecc_count;
140         atomic_t uecc_count;
141         atomic_t reset_count;
142         atomic_t open_count;
143         int  irq;
144         struct cdev xsdfec_cdev;
145         int sc_off;
146         int qc_off;
147         int la_off;
148         wait_queue_head_t waitq;
149 };
150
151 static inline void
152 xsdfec_regwrite(struct xsdfec_dev *xsdfec, u32 addr, u32 value)
153 {
154         if (xsdfec->wr_protect) {
155                 dev_err(xsdfec->dev, "SDFEC in write protect");
156                 return;
157         }
158
159         dev_dbg(xsdfec->dev,
160                 "Writing 0x%x to offset 0x%x", value, addr);
161         iowrite32(value, xsdfec->regs + addr);
162 }
163
164 static inline u32
165 xsdfec_regread(struct xsdfec_dev *xsdfec, u32 addr)
166 {
167         u32 rval;
168
169         rval = ioread32(xsdfec->regs + addr);
170         dev_info(xsdfec->dev,
171                  "Read value = 0x%x from offset 0x%x",
172                  rval, addr);
173         return rval;
174 }
175
176 #define XSDFEC_WRITE_PROTECT_ENABLE     (1)
177 #define XSDFEC_WRITE_PROTECT_DISABLE    (0)
178 static void
179 xsdfec_wr_protect(struct xsdfec_dev *xsdfec, bool wr_pr)
180 {
181         if (wr_pr) {
182                 xsdfec_regwrite(xsdfec,
183                                 XSDFEC_CODE_WR_PROTECT_ADDR,
184                                 XSDFEC_WRITE_PROTECT_ENABLE);
185                 xsdfec_regwrite(xsdfec,
186                                 XSDFEC_AXI_WR_PROTECT_ADDR,
187                                 XSDFEC_WRITE_PROTECT_ENABLE);
188         } else {
189                 xsdfec_regwrite(xsdfec,
190                                 XSDFEC_AXI_WR_PROTECT_ADDR,
191                                 XSDFEC_WRITE_PROTECT_DISABLE);
192                 xsdfec_regwrite(xsdfec,
193                                 XSDFEC_CODE_WR_PROTECT_ADDR,
194                                 XSDFEC_WRITE_PROTECT_DISABLE);
195         }
196         xsdfec->wr_protect = wr_pr;
197 }
198
199 static int
200 xsdfec_dev_open(struct inode *iptr, struct file *fptr)
201 {
202         struct xsdfec_dev *xsdfec;
203
204         xsdfec = container_of(iptr->i_cdev, struct xsdfec_dev, xsdfec_cdev);
205         if (!xsdfec)
206                 return  -EAGAIN;
207
208         /* Only one open per device at a time */
209         if (!atomic_dec_and_test(&xsdfec->open_count)) {
210                 atomic_inc(&xsdfec->open_count);
211                 return -EBUSY;
212         }
213
214         fptr->private_data = xsdfec;
215         return 0;
216 }
217
218 static int
219 xsdfec_dev_release(struct inode *iptr, struct file *fptr)
220 {
221         struct xsdfec_dev *xsdfec;
222
223         xsdfec = container_of(iptr->i_cdev, struct xsdfec_dev, xsdfec_cdev);
224         if (!xsdfec)
225                 return -EAGAIN;
226
227         atomic_inc(&xsdfec->open_count);
228         return 0;
229 }
230
231 #define XSDFEC_IS_ACTIVITY_SET  (0x1)
232 static int
233 xsdfec_get_status(struct xsdfec_dev *xsdfec, void __user *arg)
234 {
235         struct xsdfec_status status;
236         int err = 0;
237
238         status.fec_id = xsdfec->fec_id;
239         status.state = xsdfec->state;
240         status.activity  =
241                 (xsdfec_regread(xsdfec,
242                                 XSDFEC_ACTIVE_ADDR) &
243                                 XSDFEC_IS_ACTIVITY_SET);
244
245         err = copy_to_user(arg, &status, sizeof(status));
246         if (err) {
247                 dev_err(xsdfec->dev, "%s failed for SDFEC%d",
248                         __func__, xsdfec->fec_id);
249                 err = -EFAULT;
250         }
251         return err;
252 }
253
254 static int
255 xsdfec_get_config(struct xsdfec_dev *xsdfec, void __user *arg)
256 {
257         struct xsdfec_config config;
258         int err = 0;
259
260         config.fec_id = xsdfec->fec_id;
261         config.state = xsdfec->state;
262         config.code = xsdfec->code;
263         config.mode = xsdfec->op_mode;
264         config.order = xsdfec->order;
265
266         err = copy_to_user(arg, &config, sizeof(config));
267         if (err) {
268                 dev_err(xsdfec->dev, "%s failed for SDFEC%d",
269                         __func__, xsdfec->fec_id);
270                 err = -EFAULT;
271         }
272         return err;
273 }
274
275 static int
276 xsdfec_isr_enable(struct xsdfec_dev *xsdfec, bool enable)
277 {
278         u32 mask_read;
279
280         if (enable) {
281                 /* Enable */
282                 xsdfec_regwrite(xsdfec, XSDFEC_IER_ADDR,
283                                 XSDFEC_ISR_MASK);
284                 mask_read = xsdfec_regread(xsdfec, XSDFEC_IMR_ADDR);
285                 if (mask_read & XSDFEC_ISR_MASK) {
286                         dev_err(xsdfec->dev,
287                                 "SDFEC enabling irq with IER failed");
288                         return -EIO;
289                 }
290         } else {
291                 /* Disable */
292                 xsdfec_regwrite(xsdfec, XSDFEC_IDR_ADDR,
293                                 XSDFEC_ISR_MASK);
294                 mask_read = xsdfec_regread(xsdfec, XSDFEC_IMR_ADDR);
295                 if ((mask_read & XSDFEC_ISR_MASK) != XSDFEC_ISR_MASK) {
296                         dev_err(xsdfec->dev,
297                                 "SDFEC disabling irq with IDR failed");
298                         return -EIO;
299                 }
300         }
301         return 0;
302 }
303
304 static int
305 xsdfec_ecc_isr_enable(struct xsdfec_dev *xsdfec, bool enable)
306 {
307         u32 mask_read;
308
309         if (enable) {
310                 /* Enable */
311                 xsdfec_regwrite(xsdfec, XSDFEC_ECC_IER_ADDR,
312                                 XSDFEC_ECC_ISR_MASK);
313                 mask_read = xsdfec_regread(xsdfec, XSDFEC_ECC_IMR_ADDR);
314                 if (mask_read & XSDFEC_ECC_ISR_MASK) {
315                         dev_err(xsdfec->dev,
316                                 "SDFEC enabling ECC irq with ECC IER failed");
317                         return -EIO;
318                 }
319         } else {
320                 /* Disable */
321                 xsdfec_regwrite(xsdfec, XSDFEC_ECC_IDR_ADDR,
322                                 XSDFEC_ECC_ISR_MASK);
323                 mask_read = xsdfec_regread(xsdfec, XSDFEC_ECC_IMR_ADDR);
324                 if ((mask_read & XSDFEC_ECC_ISR_MASK) != XSDFEC_ECC_ISR_MASK) {
325                         dev_err(xsdfec->dev,
326                                 "SDFEC disable ECC irq with ECC IDR failed");
327                         return -EIO;
328                 }
329         }
330         return 0;
331 }
332
333 static int
334 xsdfec_set_irq(struct xsdfec_dev *xsdfec, void __user *arg)
335 {
336         struct xsdfec_irq  irq;
337         int err = 0;
338
339         err = copy_from_user(&irq, arg, sizeof(irq));
340         if (err) {
341                 dev_err(xsdfec->dev, "%s failed for SDFEC%d",
342                         __func__, xsdfec->fec_id);
343                 return -EFAULT;
344         }
345
346         /* Setup tlast related IRQ */
347         if (irq.enable_isr) {
348                 err = xsdfec_isr_enable(xsdfec, true);
349                 if (err < 0)
350                         return err;
351         }
352
353         /* Setup ECC related IRQ */
354         if (irq.enable_ecc_isr) {
355                 err = xsdfec_ecc_isr_enable(xsdfec, true);
356                 if (err < 0)
357                         return err;
358         }
359
360         return 0;
361 }
362
363 #define XSDFEC_TURBO_SCALE_MASK         (0xF)
364 #define XSDFEC_TURBO_SCALE_BIT_POS      (8)
365 static int
366 xsdfec_set_turbo(struct xsdfec_dev *xsdfec, void __user *arg)
367 {
368         struct xsdfec_turbo turbo;
369         int err = 0;
370         u32 turbo_write = 0;
371
372         err = copy_from_user(&turbo, arg, sizeof(turbo));
373         if (err) {
374                 dev_err(xsdfec->dev, "%s failed for SDFEC%d",
375                         __func__, xsdfec->fec_id);
376                 return -EFAULT;
377         }
378
379         /* Check to see what device tree says about the FEC codes */
380         if (xsdfec->code == XSDFEC_LDPC_CODE) {
381                 dev_err(xsdfec->dev,
382                         "%s: Unable to write Turbo to SDFEC%d check DT",
383                                 __func__, xsdfec->fec_id);
384                 return -EIO;
385         } else if (xsdfec->code == XSDFEC_CODE_INVALID) {
386                 xsdfec->code = XSDFEC_TURBO_CODE;
387         }
388
389         if (xsdfec->wr_protect)
390                 xsdfec_wr_protect(xsdfec, false);
391
392         xsdfec_regwrite(xsdfec, XSDFEC_FEC_CODE_ADDR, (xsdfec->code - 1));
393         turbo_write = ((turbo.scale & XSDFEC_TURBO_SCALE_MASK) <<
394                         XSDFEC_TURBO_SCALE_BIT_POS) | turbo.alg;
395         xsdfec_regwrite(xsdfec, XSDFEC_TURBO_ADDR, turbo_write);
396         return err;
397 }
398
399 static int
400 xsdfec_get_turbo(struct xsdfec_dev *xsdfec, void __user *arg)
401 {
402         u32 reg_value;
403         struct xsdfec_turbo turbo_params;
404         int err;
405
406         if (xsdfec->code == XSDFEC_LDPC_CODE) {
407                 dev_err(xsdfec->dev,
408                         "%s: SDFEC%d is configured for LDPC, check DT",
409                         __func__, xsdfec->fec_id);
410                 return -EIO;
411         }
412
413         reg_value = xsdfec_regread(xsdfec, XSDFEC_TURBO_ADDR);
414
415         turbo_params.scale = (reg_value & XSDFEC_TURBO_SCALE_MASK) >>
416                               XSDFEC_TURBO_SCALE_BIT_POS;
417         turbo_params.alg = reg_value & 0x1;
418
419         err = copy_to_user(arg, &turbo_params, sizeof(turbo_params));
420         if (err) {
421                 dev_err(xsdfec->dev, "%s failed for SDFEC%d",
422                         __func__, xsdfec->fec_id);
423                 err = -EFAULT;
424         }
425
426         return err;
427 }
428
429 #define XSDFEC_LDPC_REG_JUMP    (0x10)
430 #define XSDFEC_REG0_N_MASK      (0x0000FFFF)
431 #define XSDFEC_REG0_N_LSB       (0)
432 #define XSDFEC_REG0_K_MASK      (0x7fff0000)
433 #define XSDFEC_REG0_K_LSB       (16)
434 static int
435 xsdfec_reg0_write(struct xsdfec_dev *xsdfec,
436                   u32 n, u32 k, u32 offset)
437 {
438         u32 wdata;
439
440         /* Use only lower 16 bits */
441         if (n & ~XSDFEC_REG0_N_MASK)
442                 dev_err(xsdfec->dev, "N value is beyond 16 bits");
443         n &= XSDFEC_REG0_N_MASK;
444         n <<= XSDFEC_REG0_N_LSB;
445
446         if (k & XSDFEC_REG0_K_MASK)
447                 dev_err(xsdfec->dev, "K value is beyond 16 bits");
448
449         k = ((k << XSDFEC_REG0_K_LSB) & XSDFEC_REG0_K_MASK);
450         wdata = k | n;
451
452         if (XSDFEC_LDPC_CODE_REG0_ADDR_BASE + (offset * XSDFEC_LDPC_REG_JUMP)
453                                 > XSDFEC_LDPC_CODE_REG0_ADDR_HIGH) {
454                 dev_err(xsdfec->dev,
455                         "Writing outside of LDPC reg0 space 0x%x",
456                         XSDFEC_LDPC_CODE_REG0_ADDR_BASE +
457                         (offset * XSDFEC_LDPC_REG_JUMP));
458                 return -EINVAL;
459         }
460         xsdfec_regwrite(xsdfec,
461                         XSDFEC_LDPC_CODE_REG0_ADDR_BASE +
462                         (offset * XSDFEC_LDPC_REG_JUMP), wdata);
463         return 0;
464 }
465
466 static int
467 xsdfec_collect_ldpc_reg0(struct xsdfec_dev *xsdfec,
468                          u32 code_id,
469                          struct xsdfec_ldpc_params *ldpc_params)
470 {
471         u32 reg_value;
472         u32 reg_addr = XSDFEC_LDPC_CODE_REG0_ADDR_BASE +
473                 (code_id * XSDFEC_LDPC_REG_JUMP);
474
475         if (reg_addr > XSDFEC_LDPC_CODE_REG0_ADDR_HIGH) {
476                 dev_err(xsdfec->dev,
477                         "Accessing outside of LDPC reg0 space 0x%x",
478                         reg_addr);
479                 return -EINVAL;
480         }
481
482         reg_value = xsdfec_regread(xsdfec, reg_addr);
483
484         ldpc_params->n = (reg_value >> XSDFEC_REG0_N_LSB) & XSDFEC_REG0_N_MASK;
485
486         ldpc_params->k = (reg_value >> XSDFEC_REG0_K_LSB) & XSDFEC_REG0_K_MASK;
487
488         return 0;
489 }
490
491 #define XSDFEC_REG1_PSIZE_MASK          (0x000001ff)
492 #define XSDFEC_REG1_NO_PACKING_MASK     (0x00000400)
493 #define XSDFEC_REG1_NO_PACKING_LSB      (10)
494 #define XSDFEC_REG1_NM_MASK             (0x000ff800)
495 #define XSDFEC_REG1_NM_LSB              (11)
496 #define XSDFEC_REG1_BYPASS_MASK (0x00100000)
497 static int
498 xsdfec_reg1_write(struct xsdfec_dev *xsdfec, u32 psize,
499                   u32 no_packing, u32 nm, u32 offset)
500 {
501         u32 wdata;
502
503         if (psize & ~XSDFEC_REG1_PSIZE_MASK)
504                 dev_err(xsdfec->dev, "Psize is beyond 10 bits");
505         psize &= XSDFEC_REG1_PSIZE_MASK;
506
507         if (no_packing != 0 && no_packing != 1)
508                 dev_err(xsdfec->dev, "No-packing bit register invalid");
509         no_packing = ((no_packing << XSDFEC_REG1_NO_PACKING_LSB) &
510                                         XSDFEC_REG1_NO_PACKING_MASK);
511
512         if (nm & ~(XSDFEC_REG1_NM_MASK >> XSDFEC_REG1_NM_LSB))
513                 dev_err(xsdfec->dev, "NM is beyond 10 bits");
514         nm = (nm << XSDFEC_REG1_NM_LSB) & XSDFEC_REG1_NM_MASK;
515
516         wdata = nm | no_packing | psize;
517         if (XSDFEC_LDPC_CODE_REG1_ADDR_BASE + (offset * XSDFEC_LDPC_REG_JUMP)
518                 > XSDFEC_LDPC_CODE_REG1_ADDR_HIGH) {
519                 dev_err(xsdfec->dev,
520                         "Writing outside of LDPC reg1 space 0x%x",
521                         XSDFEC_LDPC_CODE_REG1_ADDR_BASE +
522                         (offset * XSDFEC_LDPC_REG_JUMP));
523                 return -EINVAL;
524         }
525         xsdfec_regwrite(xsdfec, XSDFEC_LDPC_CODE_REG1_ADDR_BASE +
526                 (offset * XSDFEC_LDPC_REG_JUMP), wdata);
527         return 0;
528 }
529
530 static int
531 xsdfec_collect_ldpc_reg1(struct xsdfec_dev *xsdfec,
532                          u32 code_id,
533                          struct xsdfec_ldpc_params *ldpc_params)
534 {
535         u32 reg_value;
536         u32 reg_addr = XSDFEC_LDPC_CODE_REG1_ADDR_BASE +
537                 (code_id * XSDFEC_LDPC_REG_JUMP);
538
539         if (reg_addr > XSDFEC_LDPC_CODE_REG1_ADDR_HIGH) {
540                 dev_err(xsdfec->dev,
541                         "Accessing outside of LDPC reg1 space 0x%x",
542                         reg_addr);
543                 return -EINVAL;
544         }
545
546         reg_value = xsdfec_regread(xsdfec, reg_addr);
547
548         ldpc_params->psize = reg_value & XSDFEC_REG1_PSIZE_MASK;
549
550         ldpc_params->no_packing = ((reg_value >> XSDFEC_REG1_NO_PACKING_LSB) &
551                                     XSDFEC_REG1_NO_PACKING_MASK);
552
553         ldpc_params->nm = (reg_value >> XSDFEC_REG1_NM_LSB) &
554                            XSDFEC_REG1_NM_MASK;
555         return 0;
556 }
557
558 #define XSDFEC_REG2_NLAYERS_MASK                (0x000001FF)
559 #define XSDFEC_REG2_NLAYERS_LSB                 (0)
560 #define XSDFEC_REG2_NNMQC_MASK                  (0x000FFE00)
561 #define XSDFEC_REG2_NMQC_LSB                    (9)
562 #define XSDFEC_REG2_NORM_TYPE_MASK              (0x00100000)
563 #define XSDFEC_REG2_NORM_TYPE_LSB               (20)
564 #define XSDFEC_REG2_SPECIAL_QC_MASK             (0x00200000)
565 #define XSDFEC_REG2_SPEICAL_QC_LSB              (21)
566 #define XSDFEC_REG2_NO_FINAL_PARITY_MASK        (0x00400000)
567 #define XSDFEC_REG2_NO_FINAL_PARITY_LSB         (22)
568 #define XSDFEC_REG2_MAX_SCHEDULE_MASK           (0x01800000)
569 #define XSDFEC_REG2_MAX_SCHEDULE_LSB            (23)
570
571 static int
572 xsdfec_reg2_write(struct xsdfec_dev *xsdfec, u32 nlayers, u32 nmqc,
573                   u32 norm_type, u32 special_qc, u32 no_final_parity,
574                   u32 max_schedule, u32 offset)
575 {
576         u32 wdata;
577
578         if (nlayers & ~(XSDFEC_REG2_NLAYERS_MASK >>
579                                 XSDFEC_REG2_NLAYERS_LSB))
580                 dev_err(xsdfec->dev, "Nlayers exceeds 9 bits");
581         nlayers &= XSDFEC_REG2_NLAYERS_MASK;
582
583         if (nmqc & ~(XSDFEC_REG2_NNMQC_MASK >> XSDFEC_REG2_NMQC_LSB))
584                 dev_err(xsdfec->dev, "NMQC exceeds 11 bits");
585         nmqc = (nmqc << XSDFEC_REG2_NMQC_LSB) & XSDFEC_REG2_NNMQC_MASK;
586
587         if (norm_type > 1)
588                 dev_err(xsdfec->dev, "Norm type is invalid");
589         norm_type = ((norm_type << XSDFEC_REG2_NORM_TYPE_LSB) &
590                                         XSDFEC_REG2_NORM_TYPE_MASK);
591         if (special_qc > 1)
592                 dev_err(xsdfec->dev, "Special QC in invalid");
593         special_qc = ((special_qc << XSDFEC_REG2_SPEICAL_QC_LSB) &
594                         XSDFEC_REG2_SPECIAL_QC_MASK);
595
596         if (no_final_parity > 1)
597                 dev_err(xsdfec->dev, "No final parity check invalid");
598         no_final_parity =
599                 ((no_final_parity << XSDFEC_REG2_NO_FINAL_PARITY_LSB) &
600                                         XSDFEC_REG2_NO_FINAL_PARITY_MASK);
601         if (max_schedule & ~(XSDFEC_REG2_MAX_SCHEDULE_MASK >>
602                                         XSDFEC_REG2_MAX_SCHEDULE_LSB))
603                 dev_err(xsdfec->dev, "Max Schdule exceeds 2 bits");
604         max_schedule = ((max_schedule << XSDFEC_REG2_MAX_SCHEDULE_LSB) &
605                                 XSDFEC_REG2_MAX_SCHEDULE_MASK);
606
607         wdata = (max_schedule | no_final_parity | special_qc | norm_type |
608                         nmqc | nlayers);
609
610         if (XSDFEC_LDPC_CODE_REG2_ADDR_BASE + (offset * XSDFEC_LDPC_REG_JUMP)
611                 > XSDFEC_LDPC_CODE_REG2_ADDR_HIGH) {
612                 dev_err(xsdfec->dev,
613                         "Writing outside of LDPC reg2 space 0x%x",
614                         XSDFEC_LDPC_CODE_REG2_ADDR_BASE +
615                         (offset * XSDFEC_LDPC_REG_JUMP));
616                 return -EINVAL;
617         }
618         xsdfec_regwrite(xsdfec, XSDFEC_LDPC_CODE_REG2_ADDR_BASE +
619                         (offset * XSDFEC_LDPC_REG_JUMP), wdata);
620         return 0;
621 }
622
623 static int
624 xsdfec_collect_ldpc_reg2(struct xsdfec_dev *xsdfec,
625                          u32 code_id,
626                          struct xsdfec_ldpc_params *ldpc_params)
627 {
628         u32 reg_value;
629         u32 reg_addr = XSDFEC_LDPC_CODE_REG2_ADDR_BASE +
630                 (code_id * XSDFEC_LDPC_REG_JUMP);
631
632         if (reg_addr > XSDFEC_LDPC_CODE_REG2_ADDR_HIGH) {
633                 dev_err(xsdfec->dev,
634                         "Accessing outside of LDPC reg1 space 0x%x",
635                         reg_addr);
636                 return -EINVAL;
637         }
638
639         reg_value = xsdfec_regread(xsdfec, reg_addr);
640
641         ldpc_params->nlayers = ((reg_value >> XSDFEC_REG2_NLAYERS_LSB) &
642                                 XSDFEC_REG2_NLAYERS_MASK);
643
644         ldpc_params->nmqc = (reg_value >> XSDFEC_REG2_NMQC_LSB) &
645                              XSDFEC_REG2_NNMQC_MASK;
646
647         ldpc_params->norm_type = ((reg_value >> XSDFEC_REG2_NORM_TYPE_LSB) &
648                                   XSDFEC_REG2_NORM_TYPE_MASK);
649
650         ldpc_params->special_qc = ((reg_value >> XSDFEC_REG2_SPEICAL_QC_LSB) &
651                                    XSDFEC_REG2_SPECIAL_QC_MASK);
652
653         ldpc_params->no_final_parity =
654                 ((reg_value >> XSDFEC_REG2_NO_FINAL_PARITY_LSB) &
655                  XSDFEC_REG2_NO_FINAL_PARITY_MASK);
656
657         ldpc_params->max_schedule =
658                 ((reg_value >> XSDFEC_REG2_MAX_SCHEDULE_LSB) &
659                  XSDFEC_REG2_MAX_SCHEDULE_MASK);
660
661         return 0;
662 }
663
664 #define XSDFEC_REG3_LA_OFF_LSB          (8)
665 #define XSDFEC_REG3_QC_OFF_LSB          (16)
666 static int
667 xsdfec_reg3_write(struct xsdfec_dev *xsdfec, u8 sc_off,
668                   u8 la_off, u16 qc_off, u32 offset)
669 {
670         u32 wdata;
671
672         wdata = ((qc_off << XSDFEC_REG3_QC_OFF_LSB) |
673                 (la_off << XSDFEC_REG3_LA_OFF_LSB) | sc_off);
674         if (XSDFEC_LDPC_CODE_REG3_ADDR_BASE +
675                 (offset *  XSDFEC_LDPC_REG_JUMP) >
676                         XSDFEC_LDPC_CODE_REG3_ADDR_HIGH) {
677                 dev_err(xsdfec->dev,
678                         "Writing outside of LDPC reg3 space 0x%x",
679                         XSDFEC_LDPC_CODE_REG3_ADDR_BASE +
680                         (offset * XSDFEC_LDPC_REG_JUMP));
681                 return -EINVAL;
682         }
683         xsdfec_regwrite(xsdfec, XSDFEC_LDPC_CODE_REG3_ADDR_BASE +
684                         (offset * XSDFEC_LDPC_REG_JUMP), wdata);
685         return 0;
686 }
687
688 static int
689 xsdfec_collect_ldpc_reg3(struct xsdfec_dev *xsdfec,
690                          u32 code_id,
691                          struct xsdfec_ldpc_params *ldpc_params)
692 {
693         u32 reg_value;
694         u32 reg_addr = XSDFEC_LDPC_CODE_REG3_ADDR_BASE +
695                 (code_id * XSDFEC_LDPC_REG_JUMP);
696
697         if (reg_addr > XSDFEC_LDPC_CODE_REG3_ADDR_HIGH) {
698                 dev_err(xsdfec->dev,
699                         "Accessing outside of LDPC reg3 space 0x%x",
700                         reg_addr);
701                 return -EINVAL;
702         }
703
704         reg_value = xsdfec_regread(xsdfec, reg_addr);
705
706         ldpc_params->qc_off = (reg_addr >> XSDFEC_REG3_QC_OFF_LSB) & 0xFF;
707         ldpc_params->la_off = (reg_addr >> XSDFEC_REG3_LA_OFF_LSB) & 0xFF;
708         ldpc_params->sc_off = (reg_addr & 0xFF);
709
710         return 0;
711 }
712
713 #define XSDFEC_SC_TABLE_DEPTH           (0x3fc)
714 #define XSDFEC_REG_WIDTH_JUMP           (4)
715 static int
716 xsdfec_sc_table_write(struct xsdfec_dev *xsdfec, u32 offset,
717                       u32 *sc_ptr, u32 len)
718 {
719         int reg;
720
721         /*
722          * Writes that go beyond the length of
723          * Shared Scale(SC) table should fail
724          */
725         if ((XSDFEC_REG_WIDTH_JUMP * (offset + len)) > XSDFEC_SC_TABLE_DEPTH) {
726                 dev_err(xsdfec->dev, "Write exceeds SC table length");
727                 return -EINVAL;
728         }
729
730         /*
731          * sc_off tracks the points to the last written location
732          * in the Shared Scale(SC) table. Those shared codes might
733          * be in use. Updating them without quiescing the device
734          * can put the SDFEC device in an indeterminate state
735          */
736         if ((XSDFEC_REG_WIDTH_JUMP * offset) < xsdfec->sc_off) {
737                 dev_err(xsdfec->dev, "Might write to in use shared SC code");
738                 return -EINVAL;
739         }
740
741         for (reg = 0; reg < len; reg++) {
742                 xsdfec_regwrite(xsdfec, XSDFEC_LDPC_SC_TABLE_ADDR_BASE +
743                 (offset + reg) *  XSDFEC_REG_WIDTH_JUMP, sc_ptr[reg]);
744         }
745         xsdfec->sc_off = reg + (XSDFEC_REG_WIDTH_JUMP * offset);
746         return reg;
747 }
748
749 static int
750 xsdfec_collect_sc_table(struct xsdfec_dev *xsdfec, u32 offset,
751                         u32 *sc_ptr, u32 len)
752 {
753         u32 reg;
754         u32 reg_addr;
755         u32 deepest_reach = (XSDFEC_REG_WIDTH_JUMP * (offset + len));
756
757         if (deepest_reach > XSDFEC_SC_TABLE_DEPTH) {
758                 dev_err(xsdfec->dev, "Access will exceed SC table length");
759                 return -EINVAL;
760         }
761
762         for (reg = 0; reg < len; reg++) {
763                 reg_addr = XSDFEC_LDPC_SC_TABLE_ADDR_BASE +
764                         ((offset + reg) * XSDFEC_REG_WIDTH_JUMP);
765
766                 sc_ptr[reg] = xsdfec_regread(xsdfec, reg_addr);
767         }
768
769         return 0;
770 }
771
772 #define XSDFEC_LA_TABLE_DEPTH           (0xFFC)
773 static int
774 xsdfec_la_table_write(struct xsdfec_dev *xsdfec, u32 offset,
775                       u32 *la_ptr, u32 len)
776 {
777         int reg;
778
779         if (XSDFEC_REG_WIDTH_JUMP * (offset + len) > XSDFEC_LA_TABLE_DEPTH) {
780                 dev_err(xsdfec->dev, "Write exceeds LA table length");
781                 return -EINVAL;
782         }
783
784         if  (XSDFEC_REG_WIDTH_JUMP * offset < xsdfec->la_off) {
785                 dev_err(xsdfec->dev, "Might write to in use shared LA code");
786                 return -EINVAL;
787         }
788
789         for (reg = 0; reg < len; reg++) {
790                 xsdfec_regwrite(xsdfec, XSDFEC_LDPC_LA_TABLE_ADDR_BASE +
791                                 (offset + reg) * XSDFEC_REG_WIDTH_JUMP,
792                                 la_ptr[reg]);
793         }
794         xsdfec->la_off = reg + (offset * XSDFEC_REG_WIDTH_JUMP);
795         return reg;
796 }
797
798 static int
799 xsdfec_collect_la_table(struct xsdfec_dev *xsdfec, u32 offset,
800                         u32 *la_ptr, u32 len)
801 {
802         u32 reg;
803         u32 reg_addr;
804         u32 deepest_reach = (XSDFEC_REG_WIDTH_JUMP * (offset + len));
805
806         if (deepest_reach > XSDFEC_LA_TABLE_DEPTH) {
807                 dev_err(xsdfec->dev, "Access will exceed LA table length");
808                 return -EINVAL;
809         }
810
811         for (reg = 0; reg < len; reg++) {
812                 reg_addr = XSDFEC_LDPC_LA_TABLE_ADDR_BASE +
813                                 ((offset + reg) * XSDFEC_REG_WIDTH_JUMP);
814
815                 la_ptr[reg] = xsdfec_regread(xsdfec, reg_addr);
816         }
817
818         return 0;
819 }
820
821 #define XSDFEC_QC_TABLE_DEPTH           (0x7FFC)
822 static int
823 xsdfec_qc_table_write(struct xsdfec_dev *xsdfec,
824                       u32 offset, u32 *qc_ptr, u32 len)
825 {
826         int reg;
827
828         if (XSDFEC_REG_WIDTH_JUMP * (offset + len) > XSDFEC_QC_TABLE_DEPTH) {
829                 dev_err(xsdfec->dev, "Write exceeds QC table length");
830                 return -EINVAL;
831         }
832
833         if (XSDFEC_REG_WIDTH_JUMP * offset < xsdfec->qc_off) {
834                 dev_err(xsdfec->dev, "Might write to in use shared LA code");
835                 return -EINVAL;
836         }
837
838         for (reg = 0; reg < len; reg++) {
839                 xsdfec_regwrite(xsdfec, XSDFEC_LDPC_QC_TABLE_ADDR_BASE +
840                  (offset + reg) * XSDFEC_REG_WIDTH_JUMP, qc_ptr[reg]);
841         }
842
843         xsdfec->qc_off = reg + (offset * XSDFEC_REG_WIDTH_JUMP);
844         return reg;
845 }
846
847 static int
848 xsdfec_collect_qc_table(struct xsdfec_dev *xsdfec,
849                         u32 offset, u32 *qc_ptr, u32 len)
850 {
851         u32 reg;
852         u32 reg_addr;
853         u32 deepest_reach = (XSDFEC_REG_WIDTH_JUMP * (offset + len));
854
855         if (deepest_reach > XSDFEC_QC_TABLE_DEPTH) {
856                 dev_err(xsdfec->dev, "Access will exceed QC table length");
857                 return -EINVAL;
858         }
859
860         for (reg = 0; reg < len; reg++) {
861                 reg_addr = XSDFEC_LDPC_QC_TABLE_ADDR_BASE +
862                  (offset + reg) * XSDFEC_REG_WIDTH_JUMP;
863
864                 qc_ptr[reg] = xsdfec_regread(xsdfec, reg_addr);
865         }
866
867         return 0;
868 }
869
870 static int
871 xsdfec_add_ldpc(struct xsdfec_dev *xsdfec, void __user *arg)
872 {
873         struct xsdfec_ldpc_params *ldpc;
874         int err;
875
876         ldpc = kzalloc(sizeof(*ldpc), GFP_KERNEL);
877         if (!ldpc)
878                 return -ENOMEM;
879
880         err = copy_from_user(ldpc, arg, sizeof(*ldpc));
881         if (err) {
882                 dev_err(xsdfec->dev,
883                         "%s failed to copy from user for SDFEC%d",
884                         __func__, xsdfec->fec_id);
885                 return -EFAULT;
886         }
887         if (xsdfec->code == XSDFEC_TURBO_CODE) {
888                 dev_err(xsdfec->dev,
889                         "%s: Unable to write LDPC to SDFEC%d check DT",
890                         __func__, xsdfec->fec_id);
891                 return -EIO;
892         }
893         xsdfec->code = XSDFEC_LDPC_CODE;
894         /* Disable Write Protection before proceeding */
895         if (xsdfec->wr_protect)
896                 xsdfec_wr_protect(xsdfec, false);
897
898         /* Write LDPC to CODE Register */
899         xsdfec_regwrite(xsdfec, XSDFEC_FEC_CODE_ADDR, (xsdfec->code - 1));
900         /* Write Reg 0 */
901         err = xsdfec_reg0_write(xsdfec, ldpc->n, ldpc->k, ldpc->code_id);
902         if (err)
903                 goto err_out;
904
905         /* Write Reg 1 */
906         err = xsdfec_reg1_write(xsdfec, ldpc->psize, ldpc->no_packing,
907                                 ldpc->nm, ldpc->code_id);
908         if (err)
909                 goto err_out;
910
911         /* Write Reg 2 */
912         err = xsdfec_reg2_write(xsdfec, ldpc->nlayers, ldpc->nmqc,
913                                 ldpc->norm_type, ldpc->special_qc,
914                                 ldpc->no_final_parity, ldpc->max_schedule,
915                                 ldpc->code_id);
916         if (err)
917                 goto err_out;
918
919         /* Write Reg 3 */
920         err = xsdfec_reg3_write(xsdfec, ldpc->sc_off,
921                                 ldpc->la_off, ldpc->qc_off, ldpc->code_id);
922         if (err)
923                 goto err_out;
924
925         /* Write Shared Codes */
926         err = xsdfec_sc_table_write(xsdfec, ldpc->sc_off,
927                                     ldpc->sc_table, ldpc->nlayers);
928         if (err < 0)
929                 goto err_out;
930
931         err = xsdfec_la_table_write(xsdfec, 4 * ldpc->la_off,
932                                     ldpc->la_table, ldpc->nlayers);
933         if (err < 0)
934                 goto err_out;
935
936         err = xsdfec_qc_table_write(xsdfec, 4 * ldpc->qc_off,
937                                     ldpc->qc_table, ldpc->nqc);
938         if (err < 0)
939                 goto err_out;
940
941         kfree(ldpc);
942         return 0;
943         /* Error Path */
944 err_out:
945         kfree(ldpc);
946         return err;
947 }
948
949 static int
950 xsdfec_get_ldpc_code_params(struct xsdfec_dev *xsdfec, void __user *arg)
951 {
952         struct xsdfec_ldpc_params *ldpc_params;
953         int err = 0;
954
955         if (xsdfec->code == XSDFEC_TURBO_CODE) {
956                 dev_err(xsdfec->dev,
957                         "%s: SDFEC%d is configured for TURBO, check DT",
958                                 __func__, xsdfec->fec_id);
959                 return -EIO;
960         }
961
962         ldpc_params = kzalloc(sizeof(*ldpc_params), GFP_KERNEL);
963         if (!ldpc_params)
964                 return -ENOMEM;
965
966         err = copy_from_user(ldpc_params, arg, sizeof(*ldpc_params));
967         if (err) {
968                 dev_err(xsdfec->dev,
969                         "%s failed to copy from user for SDFEC%d",
970                         __func__, xsdfec->fec_id);
971                 return -EFAULT;
972         }
973
974         err = xsdfec_collect_ldpc_reg0(xsdfec, ldpc_params->code_id,
975                                        ldpc_params);
976         if (err)
977                 goto err_out;
978
979         err = xsdfec_collect_ldpc_reg1(xsdfec, ldpc_params->code_id,
980                                        ldpc_params);
981         if (err)
982                 goto err_out;
983
984         err = xsdfec_collect_ldpc_reg2(xsdfec, ldpc_params->code_id,
985                                        ldpc_params);
986         if (err)
987                 goto err_out;
988
989         err = xsdfec_collect_ldpc_reg3(xsdfec, ldpc_params->code_id,
990                                        ldpc_params);
991         if (err)
992                 goto err_out;
993
994         /*
995          * Collect the shared table values, needs to happen after reading
996          * the registers
997          */
998         err = xsdfec_collect_sc_table(xsdfec, ldpc_params->sc_off,
999                                       ldpc_params->sc_table,
1000                                       ldpc_params->nlayers);
1001         if (err < 0)
1002                 goto err_out;
1003
1004         err = xsdfec_collect_la_table(xsdfec, 4 * ldpc_params->la_off,
1005                                       ldpc_params->la_table,
1006                                       ldpc_params->nlayers);
1007         if (err < 0)
1008                 goto err_out;
1009
1010         err = xsdfec_collect_qc_table(xsdfec, 4 * ldpc_params->qc_off,
1011                                       ldpc_params->qc_table,
1012                                       ldpc_params->nqc);
1013         if (err < 0)
1014                 goto err_out;
1015
1016         err = copy_to_user(arg, ldpc_params, sizeof(*ldpc_params));
1017         if (err) {
1018                 dev_err(xsdfec->dev, "%s failed for SDFEC%d",
1019                         __func__, xsdfec->fec_id);
1020                 err = -EFAULT;
1021         }
1022
1023         kfree(ldpc_params);
1024         return 0;
1025         /* Error Path */
1026 err_out:
1027         kfree(ldpc_params);
1028         return err;
1029 }
1030
1031 static int
1032 xsdfec_set_order(struct xsdfec_dev *xsdfec, enum xsdfec_order __user order)
1033 {
1034         bool order_out_of_range;
1035
1036         order_out_of_range = (order <= XSDFEC_INVALID_ORDER) ||
1037                              (order >= XSDFEC_ORDER_MAX);
1038         if (order_out_of_range) {
1039                 dev_err(xsdfec->dev,
1040                         "%s invalid order value %d for SDFEC%d",
1041                         __func__, order, xsdfec->fec_id);
1042                 return -EINVAL;
1043         }
1044
1045         /* Verify Device has not started */
1046         if (xsdfec->state == XSDFEC_STARTED) {
1047                 dev_err(xsdfec->dev,
1048                         "%s attempting to set Order while started for SDFEC%d",
1049                         __func__, xsdfec->fec_id);
1050                 return -EIO;
1051         }
1052
1053         xsdfec_regwrite(xsdfec, XSDFEC_ORDER_ADDR, (order - 1));
1054
1055         xsdfec->order = order;
1056
1057         return 0;
1058 }
1059
1060 static int
1061 xsdfec_set_bypass(struct xsdfec_dev *xsdfec, unsigned long bypass)
1062 {
1063         if (bypass > 1) {
1064                 dev_err(xsdfec->dev,
1065                         "%s invalid bypass value %ld for SDFEC%d",
1066                         __func__, bypass, xsdfec->fec_id);
1067                 return -EINVAL;
1068         }
1069
1070         /* Verify Device has not started */
1071         if (xsdfec->state == XSDFEC_STARTED) {
1072                 dev_err(xsdfec->dev,
1073                         "%s attempting to set bypass while started for SDFEC%d",
1074                         __func__, xsdfec->fec_id);
1075                 return -EIO;
1076         }
1077
1078         xsdfec_regwrite(xsdfec, XSDFEC_BYPASS_ADDR, bypass);
1079
1080         return 0;
1081 }
1082
1083 static int
1084 xsdfec_is_active(struct xsdfec_dev *xsdfec, bool __user *is_active)
1085 {
1086         u32 reg_value;
1087
1088         reg_value = xsdfec_regread(xsdfec, XSDFEC_ACTIVE_ADDR);
1089         /* using a double ! operator instead of casting */
1090         *is_active = !!(reg_value & XSDFEC_IS_ACTIVITY_SET);
1091
1092         return 0;
1093 }
1094
1095 static int xsdfec_start(struct xsdfec_dev *xsdfec)
1096 {
1097         u32 regread;
1098
1099         /* Verify Code is loaded */
1100         if (xsdfec->code == XSDFEC_CODE_INVALID) {
1101                 dev_err(xsdfec->dev,
1102                         "%s : set code before start for SDFEC%d",
1103                         __func__, xsdfec->fec_id);
1104                 return -EINVAL;
1105         }
1106         regread = xsdfec_regread(xsdfec, XSDFEC_FEC_CODE_ADDR);
1107         regread &= 0x1;
1108         if (regread + 1 != xsdfec->code) {
1109                 dev_err(xsdfec->dev,
1110                         "%s SDFEC HW code does not match driver code",
1111                         __func__);
1112                 return -EINVAL;
1113         }
1114
1115         /* Verify Order has been set */
1116         if (xsdfec->code == XSDFEC_CODE_INVALID) {
1117                 dev_err(xsdfec->dev,
1118                         "%s : set order before starting SDFEC%d",
1119                         __func__, xsdfec->fec_id);
1120                 return -EINVAL;
1121         }
1122
1123         /* Set AXIS width */
1124         xsdfec_regwrite(xsdfec, XSDFEC_AXIS_WIDTH_ADDR, 0);
1125         /* Set AXIS enable */
1126         xsdfec_regwrite(xsdfec,
1127                         XSDFEC_AXIS_ENABLE_ADDR,
1128                         XSDFEC_AXIS_ENABLE_MASK);
1129         /* Write Protect Code and Registers */
1130         xsdfec_wr_protect(xsdfec, true);
1131         /* Done */
1132         xsdfec->state = XSDFEC_STARTED;
1133         return 0;
1134 }
1135
1136 static int
1137 xsdfec_stop(struct xsdfec_dev *xsdfec)
1138 {
1139         u32 regread;
1140
1141         if (xsdfec->state != XSDFEC_STARTED)
1142                 dev_err(xsdfec->dev, "Device not started correctly");
1143         /* Disable Write Protect */
1144         xsdfec_wr_protect(xsdfec, false);
1145         /* Disable AXIS_ENABLE register */
1146         regread = xsdfec_regread(xsdfec, XSDFEC_AXIS_ENABLE_ADDR);
1147         regread &= (~XSDFEC_AXIS_ENABLE_MASK);
1148         xsdfec_regwrite(xsdfec, XSDFEC_AXIS_ENABLE_ADDR, regread);
1149         /* Stop */
1150         xsdfec->state = XSDFEC_STOPPED;
1151         return 0;
1152 }
1153
1154 /*
1155  * Reset will happen asynchronously
1156  * since there is no in-band reset register
1157  * Prepare driver for reset
1158  */
1159
1160 static int
1161 xsdfec_reset_req(struct xsdfec_dev *xsdfec)
1162 {
1163         xsdfec->state = XSDFEC_INIT;
1164         xsdfec->order = XSDFEC_INVALID_ORDER;
1165         xsdfec->sc_off = 0;
1166         xsdfec->la_off = 0;
1167         xsdfec->qc_off = 0;
1168         xsdfec->wr_protect = false;
1169         atomic_set(&xsdfec->isr_err_count, 0);
1170         atomic_set(&xsdfec->uecc_count, 0);
1171         atomic_set(&xsdfec->cecc_count, 0);
1172         atomic_inc(&xsdfec->reset_count);
1173         return 0;
1174 }
1175
1176 static long
1177 xsdfec_dev_ioctl(struct file *fptr, unsigned int cmd, unsigned long data)
1178 {
1179         struct xsdfec_dev *xsdfec = fptr->private_data;
1180         void __user *arg = (void __user *)data;
1181         int rval = -EINVAL;
1182
1183         if (!xsdfec)
1184                 return rval;
1185
1186         /* In failed state allow only reset and get status IOCTLs */
1187         if (xsdfec->state == XSDFEC_NEEDS_RESET &&
1188             (cmd != XSDFEC_RESET_REQ && cmd != XSDFEC_GET_STATUS)) {
1189                 dev_err(xsdfec->dev,
1190                         "SDFEC%d in failed state. Reset Required",
1191                         xsdfec->fec_id);
1192                 return -EPERM;
1193         }
1194
1195         switch (cmd) {
1196         case XSDFEC_START_DEV:
1197                 rval = xsdfec_start(xsdfec);
1198                 break;
1199         case XSDFEC_STOP_DEV:
1200                 rval = xsdfec_stop(xsdfec);
1201                 break;
1202         case XSDFEC_RESET_REQ:
1203                 rval = xsdfec_reset_req(xsdfec);
1204                 break;
1205         case XSDFEC_GET_STATUS:
1206                 arg = (void __user *)data;
1207                 if (!arg)
1208                         return rval;
1209                 rval = xsdfec_get_status(xsdfec, arg);
1210                 break;
1211         case XSDFEC_GET_CONFIG:
1212                 arg = (void __user *)data;
1213                 if (!arg)
1214                         return rval;
1215                 rval = xsdfec_get_config(xsdfec, arg);
1216                 break;
1217         case XSDFEC_SET_IRQ:
1218                 arg = (void __user *)data;
1219                 if (!arg)
1220                         return rval;
1221                 rval = xsdfec_set_irq(xsdfec, arg);
1222                 break;
1223         case XSDFEC_SET_TURBO:
1224                 arg = (void __user *)data;
1225                 if (!arg)
1226                         return rval;
1227                 rval = xsdfec_set_turbo(xsdfec, arg);
1228                 break;
1229         case XSDFEC_GET_TURBO:
1230                 arg = (void __user *)data;
1231                 if (!arg)
1232                         return rval;
1233                 rval = xsdfec_get_turbo(xsdfec, arg);
1234                 break;
1235         case XSDFEC_ADD_LDPC_CODE_PARAMS:
1236                 arg = (void __user *)data;
1237                 if (!arg)
1238                         return rval;
1239                 rval  = xsdfec_add_ldpc(xsdfec, arg);
1240                 break;
1241         case XSDFEC_GET_LDPC_CODE_PARAMS:
1242                 arg = (void __user *)data;
1243                 if (!arg)
1244                         return rval;
1245                 rval = xsdfec_get_ldpc_code_params(xsdfec, arg);
1246                 break;
1247         case XSDFEC_SET_ORDER:
1248                 rval = xsdfec_set_order(xsdfec, (enum xsdfec_order)data);
1249                 break;
1250         case XSDFEC_SET_BYPASS:
1251                 rval = xsdfec_set_bypass(xsdfec, data);
1252                 break;
1253         case XSDFEC_IS_ACTIVE:
1254                 rval = xsdfec_is_active(xsdfec, (bool __user *)arg);
1255                 break;
1256         default:
1257                 /* Should not get here */
1258                 dev_err(xsdfec->dev, "Undefined SDFEC IOCTL");
1259                 break;
1260         }
1261         return rval;
1262 }
1263
1264 static unsigned int
1265 xsdfec_poll(struct file *file, poll_table *wait)
1266 {
1267         unsigned int mask;
1268         struct xsdfec_dev *xsdfec = file->private_data;
1269
1270         if (!xsdfec)
1271                 return POLLNVAL | POLLHUP;
1272
1273         poll_wait(file, &xsdfec->waitq, wait);
1274
1275         /* XSDFEC ISR detected an error */
1276         if (xsdfec->state == XSDFEC_NEEDS_RESET)
1277                 mask = POLLIN | POLLRDNORM;
1278         else
1279                 mask = POLLPRI | POLLERR;
1280
1281         return mask;
1282 }
1283
1284 static const struct file_operations xsdfec_fops = {
1285         .owner = THIS_MODULE,
1286         .open = xsdfec_dev_open,
1287         .release = xsdfec_dev_release,
1288         .unlocked_ioctl = xsdfec_dev_ioctl,
1289         .poll = xsdfec_poll,
1290 };
1291
1292 static int
1293 xsdfec_parse_of(struct xsdfec_dev *xsdfec)
1294 {
1295         struct device *dev = xsdfec->dev;
1296         struct device_node *node = dev->of_node;
1297         int rval;
1298         const char *fec_code;
1299         const char *fec_op_mode;
1300
1301         rval = of_property_read_string(node,
1302                                        "xlnx,sdfec-op-mode",
1303                                        &fec_op_mode);
1304         if (rval < 0) {
1305                 dev_err(dev, "xlnx,sdfec-op-mode not in DT");
1306                 return rval;
1307         }
1308
1309         if (!strcasecmp(fec_op_mode, "encode")) {
1310                 xsdfec->op_mode = XSDFEC_ENCODE;
1311         } else if (!strcasecmp(fec_op_mode, "decode")) {
1312                 xsdfec->op_mode = XSDFEC_DECODE;
1313         } else {
1314                 dev_err(dev, "Encode or Decode not specified in DT");
1315                 return -EINVAL;
1316         }
1317
1318         rval = of_property_read_string(node, "xlnx,sdfec-code", &fec_code);
1319         if (rval < 0) {
1320                 dev_err(dev, "xlnx,sdfec-code not in DT");
1321                 return rval;
1322         }
1323
1324         if (!strcasecmp(fec_code, "ldpc")) {
1325                 xsdfec->code = XSDFEC_LDPC_CODE;
1326         } else if (!strcasecmp(fec_code, "turbo")) {
1327                 xsdfec->code = XSDFEC_TURBO_CODE;
1328         } else {
1329                 dev_err(xsdfec->dev, "Invalid Op Mode in DT");
1330                 return -EINVAL;
1331         }
1332
1333         return 0;
1334 }
1335
1336 static void
1337 xsdfec_log_ecc_errors(struct xsdfec_dev *xsdfec, u32 ecc_err)
1338 {
1339         u32 cecc, uecc;
1340         int uecc_cnt;
1341
1342         cecc = ecc_err & XSDFEC_ECC_ISR_SBE;
1343         uecc = ecc_err & XSDFEC_ECC_ISR_MBE;
1344
1345         uecc_cnt = atomic_add_return(hweight32(uecc), &xsdfec->uecc_count);
1346         atomic_add(hweight32(cecc), &xsdfec->cecc_count);
1347
1348         if (uecc_cnt > 0 && uecc_cnt < XSDFEC_ERROR_MAX_THRESHOLD) {
1349                 dev_err(xsdfec->dev,
1350                         "Multi-bit error on xsdfec%d. Needs reset",
1351                         xsdfec->fec_id);
1352         }
1353
1354         /* Clear ECC errors */
1355         xsdfec_regwrite(xsdfec, XSDFEC_ECC_ISR_ADDR, 0);
1356 }
1357
1358 static void
1359 xsdfec_log_isr_errors(struct xsdfec_dev *xsdfec, u32 isr_err)
1360 {
1361         int isr_err_cnt;
1362
1363         /* Update ISR error counts */
1364         isr_err_cnt = atomic_add_return(hweight32(isr_err),
1365                                         &xsdfec->isr_err_count);
1366         if (isr_err_cnt > 0 && isr_err_cnt < XSDFEC_ERROR_MAX_THRESHOLD) {
1367                 dev_err(xsdfec->dev,
1368                         "Tlast,or DIN_WORDS or DOUT_WORDS not correct");
1369         }
1370
1371         /* Clear ISR error status */
1372         xsdfec_regwrite(xsdfec, XSDFEC_ECC_ISR_ADDR, 0);
1373 }
1374
1375 static void
1376 xsdfec_reset_required(struct xsdfec_dev *xsdfec)
1377 {
1378         xsdfec->state = XSDFEC_NEEDS_RESET;
1379 }
1380
1381 static irqreturn_t
1382 xsdfec_irq_thread(int irq, void *dev_id)
1383 {
1384         struct xsdfec_dev *xsdfec = dev_id;
1385         irqreturn_t ret = IRQ_HANDLED;
1386         u32 ecc_err;
1387         u32 isr_err;
1388         bool fatal_err = false;
1389
1390         WARN_ON(xsdfec->irq != irq);
1391
1392         /* Mask Interrupts */
1393         xsdfec_isr_enable(xsdfec, false);
1394         xsdfec_ecc_isr_enable(xsdfec, false);
1395
1396         /* Read Interrupt Status Registers */
1397         ecc_err = xsdfec_regread(xsdfec, XSDFEC_ECC_ISR_ADDR);
1398         isr_err = xsdfec_regread(xsdfec, XSDFEC_ISR_ADDR);
1399
1400         if (ecc_err & XSDFEC_ECC_ISR_MBE) {
1401                 /* Multi-Bit Errors need Reset */
1402                 xsdfec_log_ecc_errors(xsdfec, ecc_err);
1403                 xsdfec_reset_required(xsdfec);
1404                 fatal_err = true;
1405         } else if (isr_err & XSDFEC_ISR_MASK) {
1406                 /*
1407                  * Tlast, DIN_WORDS and DOUT_WORDS related
1408                  * errors need Reset
1409                  */
1410                 xsdfec_log_isr_errors(xsdfec, isr_err);
1411                 xsdfec_reset_required(xsdfec);
1412                 fatal_err = true;
1413         } else if (ecc_err & XSDFEC_ECC_ISR_SBE) {
1414                 /* Correctable ECC Errors */
1415                 xsdfec_log_ecc_errors(xsdfec, ecc_err);
1416         } else {
1417                 ret = IRQ_NONE;
1418         }
1419
1420         if (fatal_err)
1421                 wake_up_interruptible(&xsdfec->waitq);
1422
1423         /* Unmaks Interrupts */
1424         xsdfec_isr_enable(xsdfec, true);
1425         xsdfec_ecc_isr_enable(xsdfec, true);
1426
1427         return ret;
1428 }
1429
1430 static int
1431 xsdfec_probe(struct platform_device *pdev)
1432 {
1433         struct xsdfec_dev *xsdfec;
1434         struct device *dev;
1435         struct device *dev_create;
1436         struct resource *res;
1437         int err;
1438         bool irq_enabled = true;
1439
1440         xsdfec = devm_kzalloc(&pdev->dev, sizeof(*xsdfec), GFP_KERNEL);
1441         if (!xsdfec)
1442                 return -ENOMEM;
1443
1444         xsdfec->dev = &pdev->dev;
1445         if (atomic_read(&xsdfec_ndevs) > DRIVER_MAX_DEV) {
1446                 dev_err(&pdev->dev,
1447                         "Cannot instantiate more than %d SDFEC instances",
1448                         (DRIVER_MAX_DEV + 1));
1449                 return -EINVAL;
1450         }
1451
1452         xsdfec->fec_id = atomic_read(&xsdfec_ndevs);
1453
1454         dev = xsdfec->dev;
1455         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1456         xsdfec->regs = devm_ioremap_resource(dev, res);
1457         if (IS_ERR(xsdfec->regs)) {
1458                 dev_err(dev, "Unable to map resource");
1459                 err = PTR_ERR(xsdfec->regs);
1460                 goto err_xsdfec_dev;
1461         }
1462
1463         xsdfec->irq = platform_get_irq(pdev, 0);
1464         if (xsdfec->irq < 0) {
1465                 dev_dbg(dev, "platform_get_irq failed");
1466                 irq_enabled = false;
1467         }
1468
1469         err = xsdfec_parse_of(xsdfec);
1470         if (err < 0)
1471                 goto err_xsdfec_dev;
1472
1473         /* Save driver private data */
1474         platform_set_drvdata(pdev, xsdfec);
1475
1476         if (irq_enabled) {
1477                 init_waitqueue_head(&xsdfec->waitq);
1478                 /* Register IRQ thread */
1479                 err = devm_request_threaded_irq(dev, xsdfec->irq, NULL,
1480                                                 xsdfec_irq_thread,
1481                                                 IRQF_ONESHOT,
1482                                                 "xilinx-sdfec16",
1483                                                 xsdfec);
1484                 if (err < 0) {
1485                         dev_err(dev, "unable to request IRQ%d", xsdfec->irq);
1486                         goto err_xsdfec_dev;
1487                 }
1488         }
1489
1490         cdev_init(&xsdfec->xsdfec_cdev, &xsdfec_fops);
1491         xsdfec->xsdfec_cdev.owner = THIS_MODULE;
1492         err = cdev_add(&xsdfec->xsdfec_cdev,
1493                        MKDEV(MAJOR(xsdfec_devt), xsdfec->fec_id), 1);
1494         if (err < 0) {
1495                 dev_err(dev, "cdev_add failed");
1496                 err = -EIO;
1497                 goto err_xsdfec_dev;
1498         }
1499
1500         if (!xsdfec_class) {
1501                 err = -EIO;
1502                 dev_err(dev, "xsdfec class not created correctly");
1503                 goto err_xsdfec_cdev;
1504         }
1505
1506         dev_create = device_create(xsdfec_class, dev,
1507                                    MKDEV(MAJOR(xsdfec_devt), xsdfec->fec_id),
1508                                    xsdfec, "xsdfec%d", xsdfec->fec_id);
1509         if (IS_ERR(dev_create)) {
1510                 dev_err(dev, "unable to create device");
1511                 err = PTR_ERR(dev_create);
1512                 goto err_xsdfec_cdev;
1513         }
1514
1515         atomic_set(&xsdfec->open_count, 1);
1516         dev_info(dev, "XSDFEC%d Probe Successful", xsdfec->fec_id);
1517         atomic_inc(&xsdfec_ndevs);
1518         return 0;
1519
1520         /* Failure cleanup */
1521 err_xsdfec_cdev:
1522         cdev_del(&xsdfec->xsdfec_cdev);
1523 err_xsdfec_dev:
1524         return err;
1525 }
1526
1527 static int
1528 xsdfec_remove(struct platform_device *pdev)
1529 {
1530         struct xsdfec_dev *xsdfec;
1531         struct device *dev = &pdev->dev;
1532
1533         xsdfec = platform_get_drvdata(pdev);
1534         if (!xsdfec)
1535                 return -ENODEV;
1536         dev = xsdfec->dev;
1537         if (!xsdfec_class) {
1538                 dev_err(dev, "xsdfec_class is NULL");
1539                 return -EIO;
1540         }
1541
1542         device_destroy(xsdfec_class,
1543                        MKDEV(MAJOR(xsdfec_devt), xsdfec->fec_id));
1544         cdev_del(&xsdfec->xsdfec_cdev);
1545         atomic_dec(&xsdfec_ndevs);
1546         return 0;
1547 }
1548
1549 static const struct of_device_id xsdfec_of_match[] = {
1550         { .compatible = "xlnx,fec-engine", },
1551         { /* end of table */ }
1552 };
1553 MODULE_DEVICE_TABLE(of, xsdfec_of_match);
1554
1555 static struct platform_driver xsdfec_driver = {
1556         .driver = {
1557                 .name = "xilinx-sdfec",
1558                 .of_match_table = xsdfec_of_match,
1559         },
1560         .probe = xsdfec_probe,
1561         .remove =  xsdfec_remove,
1562 };
1563
1564 static int __init xsdfec_init_mod(void)
1565 {
1566         int err;
1567
1568         xsdfec_class = class_create(THIS_MODULE, DRIVER_NAME);
1569         if (IS_ERR(xsdfec_class)) {
1570                 err = PTR_ERR(xsdfec_class);
1571                 pr_err("%s : Unable to register xsdfec class", __func__);
1572                 return err;
1573         }
1574
1575         err = alloc_chrdev_region(&xsdfec_devt,
1576                                   0, DRIVER_MAX_DEV, DRIVER_NAME);
1577         if (err < 0) {
1578                 pr_err("%s : Unable to get major number", __func__);
1579                 goto err_xsdfec_class;
1580         }
1581
1582         err = platform_driver_register(&xsdfec_driver);
1583         if (err < 0) {
1584                 pr_err("%s Unabled to register %s driver",
1585                        __func__, DRIVER_NAME);
1586                 goto err_xsdfec_drv;
1587         }
1588         return 0;
1589
1590         /* Error Path */
1591 err_xsdfec_drv:
1592         unregister_chrdev_region(xsdfec_devt, DRIVER_MAX_DEV);
1593 err_xsdfec_class:
1594         class_destroy(xsdfec_class);
1595         return err;
1596 }
1597
1598 static void __exit xsdfec_cleanup_mod(void)
1599 {
1600         platform_driver_unregister(&xsdfec_driver);
1601         unregister_chrdev_region(xsdfec_devt, DRIVER_MAX_DEV);
1602         class_destroy(xsdfec_class);
1603         xsdfec_class = NULL;
1604 }
1605
1606 module_init(xsdfec_init_mod);
1607 module_exit(xsdfec_cleanup_mod);
1608
1609 MODULE_AUTHOR("Xilinx, Inc");
1610 MODULE_DESCRIPTION("Xilinx SD-FEC16 Driver");
1611 MODULE_LICENSE("GPL");
1612 MODULE_VERSION(DRIVER_VERSION);