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