linux/drivers/misc/xilinx_sdfec.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Xilinx SDFEC
   4 *
   5 * Copyright (C) 2016 - 2017 Xilinx, Inc.
   6 *
   7 * Description:
   8 * This driver is developed for SDFEC16 (Soft Decision FEC 16nm)
   9 * IP. It exposes a char device interface in sysfs and supports file
  10 * operations like  open(), close() and ioctl().
  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/* Xilinx SDFEC Register Map */
  39/* AXI_WRI_PROTECT Register */
  40#define XSDFEC_AXI_WR_PROTECT_ADDR              (0x0)
  41/* CODE_WRI_PROTECT Register */
  42#define XSDFEC_CODE_WR_PROTECT_ADDR             (0x4)
  43#define XSDFEC_WRITE_PROTECT_ENABLE             (1)
  44#define XSDFEC_WRITE_PROTECT_DISABLE            (0)
  45
  46/* ACTIVE Register */
  47#define XSDFEC_ACTIVE_ADDR                      (0x8)
  48#define XSDFEC_IS_ACTIVITY_SET                  (0x1)
  49
  50/* AXIS_WIDTH Register */
  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/* AXIS_ENABLE Register */
  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/* FEC_CODE Register */
  65#define XSDFEC_FEC_CODE_ADDR                    (0x14)
  66
  67/* ORDER Register Map */
  68#define XSDFEC_ORDER_ADDR                       (0x18)
  69
  70/* Interrupt Status Register */
  71#define XSDFEC_ISR_ADDR                         (0x1C)
  72/* Interrupt Status Register Bit Mask */
  73#define XSDFEC_ISR_MASK                         (0x3F)
  74
  75/* Write Only - Interrupt Enable Register */
  76#define XSDFEC_IER_ADDR                         (0x20)
  77/* Write Only - Interrupt Disable Register */
  78#define XSDFEC_IDR_ADDR                         (0x24)
  79/* Read Only - Interrupt Mask Register */
  80#define XSDFEC_IMR_ADDR                         (0x28)
  81
  82/* ECC Interrupt Status Register */
  83#define XSDFEC_ECC_ISR_ADDR                     (0x2C)
  84/* Single Bit Errors */
  85#define XSDFEC_ECC_ISR_SBE                      (0x7FF)
  86/* PL Initialize Single Bit Errors */
  87#define XSDFEC_PL_INIT_ECC_ISR_SBE              (0x3C00000)
  88/* Multi Bit Errors */
  89#define XSDFEC_ECC_ISR_MBE                      (0x3FF800)
  90/* PL Initialize Multi Bit Errors */
  91#define XSDFEC_PL_INIT_ECC_ISR_MBE              (0x3C000000)
  92/* Multi Bit Error to Event Shift */
  93#define XSDFEC_ECC_ISR_MBE_TO_EVENT_SHIFT               (11)
  94/* PL Initialize Multi Bit Error to Event Shift */
  95#define XSDFEC_PL_INIT_ECC_ISR_MBE_TO_EVENT_SHIFT       (4)
  96/* ECC Interrupt Status Bit Mask */
  97#define XSDFEC_ECC_ISR_MASK \
  98        (XSDFEC_ECC_ISR_SBE | XSDFEC_ECC_ISR_MBE)
  99/* ECC Interrupt Status PL Initialize Bit Mask */
 100#define XSDFEC_PL_INIT_ECC_ISR_MASK \
 101        (XSDFEC_PL_INIT_ECC_ISR_SBE | XSDFEC_PL_INIT_ECC_ISR_MBE)
 102/* ECC Interrupt Status All Bit Mask */
 103#define XSDFEC_ALL_ECC_ISR_MASK \
 104        (XSDFEC_ECC_ISR_MASK | XSDFEC_PL_INIT_ECC_ISR_MASK)
 105/* ECC Interrupt Status Single Bit Errors Mask */
 106#define XSDFEC_ECC_ISR_SBE_MASK \
 107        (XSDFEC_ECC_ISR_SBE | XSDFEC_PL_INIT_ECC_ISR_SBE)
 108/* ECC Interrupt Status Multi Bit Errors Mask */
 109#define XSDFEC_ECC_ISR_MBE_MASK \
 110        (XSDFEC_ECC_ISR_MBE | XSDFEC_PL_INIT_ECC_ISR_MBE)
 111
 112/* Write Only - ECC Interrupt Enable Register */
 113#define XSDFEC_ECC_IER_ADDR                     (0x30)
 114/* Write Only - ECC Interrupt Disable Register */
 115#define XSDFEC_ECC_IDR_ADDR                     (0x34)
 116/* Read Only - ECC Interrupt Mask Register */
 117#define XSDFEC_ECC_IMR_ADDR                     (0x38)
 118
 119/* BYPASS Register */
 120#define XSDFEC_BYPASS_ADDR                      (0x3C)
 121
 122/* Turbo Code Register */
 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/* REG0 Register */
 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/* REG1 Register */
 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/* REG2 Register */
 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/* REG3 Register */
 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 * struct xsdfec_dev - Driver data for SDFEC
 177 * @regs: device physical base address
 178 * @dev: pointer to device struct
 179 * @state: State of the SDFEC device
 180 * @config: Configuration of the SDFEC device
 181 * @intr_enabled: indicates IRQ enabled
 182 * @state_updated: indicates State updated by interrupt handler
 183 * @stats_updated: indicates Stats updated by interrupt handler
 184 * @isr_err_count: Count of ISR errors
 185 * @cecc_count: Count of Correctable ECC errors (SBE)
 186 * @uecc_count: Count of Uncorrectable ECC errors (MBE)
 187 * @open_count: Count of char device being opened
 188 * @irq: IRQ number
 189 * @xsdfec_cdev: Character device handle
 190 * @waitq: Driver wait queue
 191 * @irq_lock: Driver spinlock
 192 *
 193 * This structure contains necessary state for SDFEC driver to operate
 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        /* Spinlock to protect state_updated and stats_updated */
 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        /* Update the Order */
 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, /* Bit Number, maybe change to mask */
 260                                    &xsdfec->config.bypass);
 261
 262        update_bool_config_from_reg(xsdfec,
 263                                    XSDFEC_CODE_WR_PROTECT_ADDR,
 264                                    0, /* Bit Number */
 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        /* Only one open per device at a time */
 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                /* Enable */
 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                /* Disable */
 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                /* Enable */
 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                /* Disable */
 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        /* Setup tlast related IRQ */
 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        /* Setup ECC related IRQ */
 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        /* Check to see what device tree says about the FEC codes */
 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        /* Use only lower 16 bits */
 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         * Writes that go beyond the length of
 664         * Shared Scale(SC) table should fail
 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        /* Verify Device has not started */
 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        /* Write Reg 0 */
 756        err = xsdfec_reg0_write(xsdfec, ldpc->n, ldpc->k, ldpc->code_id);
 757        if (err)
 758                goto err_out;
 759
 760        /* Write Reg 1 */
 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        /* Write Reg 2 */
 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        /* Write Reg 3 */
 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        /* Write Shared Codes */
 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        /* Error Path */
 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        /* Verify Device has not started */
 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        /* Verify Device has not started */
 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        /* using a double ! operator instead of casting */
 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        /* translate config info to register values */
 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        /* Verify Code is loaded */
 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        /* Verify Order has been set */
 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        /* Set AXIS enable */
 963        xsdfec_regwrite(xsdfec,
 964                        XSDFEC_AXIS_ENABLE_ADDR,
 965                        XSDFEC_AXIS_ENABLE_MASK);
 966        /* Done */
 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        /* Disable AXIS_ENABLE Input interfaces only */
 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        /* Stop */
 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        /* Ensure registers are aligned with core configuration */
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        /* In failed state allow only reset and get status IOCTLs */
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        /* check if ioctl argument is present and valid */
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        /* Access check of the argument if present */
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                /* Should not get here */
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        /* XSDFEC ISR detected an error */
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        /* Fall through and set for valid values */
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        /* Fall through and set for valid values */
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        /* Write LDPC to CODE Register */
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        /* Update ECC ISR error counts */
1264        atomic_add(hweight32(uecc), &xsdfec->uecc_count);
1265        xsdfec->stats_updated = true;
1266
1267        /* Clear ECC errors */
1268        xsdfec_regwrite(xsdfec, XSDFEC_ECC_ISR_ADDR, XSDFEC_ECC_ISR_MBE_MASK);
1269        /* Clear ECC events */
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        /* Update ECC ISR error counts */
1285        atomic_add(hweight32(cecc), &xsdfec->cecc_count);
1286        xsdfec->stats_updated = true;
1287
1288        /* Clear ECC errors */
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        /* Update ISR error counts */
1296        atomic_add(hweight32(isr_err), &xsdfec->isr_err_count);
1297        xsdfec->stats_updated = true;
1298
1299        /* Clear ISR error status */
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        /* Mask Interrupts */
1349        xsdfec_isr_enable(xsdfec, false);
1350        xsdfec_ecc_isr_enable(xsdfec, false);
1351
1352        /* Read Interrupt Status Registers */
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                /* Count and clear multi-bit errors and associated events */
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         * Update SBE mask to remove events associated with MBE if present.
1370         * If no MBEs are present will return mask for all SBE bits
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        /* Unmaks Interrupts */
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        /* Save driver private data */
1445        platform_set_drvdata(pdev, xsdfec);
1446
1447        if (irq_enabled) {
1448                init_waitqueue_head(&xsdfec->waitq);
1449                /* Register IRQ thread */
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        /* Failure cleanup */
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        { /* end of table */ }
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        /* Error Path */
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