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