]> rtime.felk.cvut.cz Git - zynq/linux.git/commitdiff
misc: xilinx-sdfec: Updated DT update implementation
authorDerek Kiernan <derek.kiernan@xilinx.com>
Fri, 11 May 2018 09:38:01 +0000 (10:38 +0100)
committerMichal Simek <michal.simek@xilinx.com>
Fri, 11 May 2018 13:45:41 +0000 (15:45 +0200)
To align with the device tree entry updates for sd-fec-1.1 the following
changes have been implemented.
- Changed the xsdfec_of_match compatible string.
- Updates the driver to read, store and configure the AXI Stream
interfaces.
- Removes reading op-mode DT property.
- remove unused op-mode member from xsdfec_config.
- reads of the following Device Tree properties and sets the AXIS_WIDTH
register.
-   din-words.
-   din-width.
-   dout-words.
-   dout-width.

Signed-off-by: Derek Kiernan <derek.kiernan@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/misc/xilinx_sdfec.c
include/uapi/misc/xilinx_sdfec.h

index 42c266b09113b4ace5729d547b56c8cd4f30e8fa..eb09fdea23fc2c7c811e271736aa88fe7e08ea10 100644 (file)
@@ -1079,6 +1079,75 @@ xsdfec_is_active(struct xsdfec_dev *xsdfec, bool __user *is_active)
        return 0;
 }
 
+static u32
+xsdfec_translate_axis_width_cfg_val(enum xsdfec_axis_width axis_width_cfg)
+{
+       u32 axis_width_field = 0;
+
+       switch (axis_width_cfg) {
+       case XSDFEC_1x128b:
+               axis_width_field = 0;
+               break;
+       case XSDFEC_2x128b:
+               axis_width_field = 1;
+               break;
+       case XSDFEC_4x128b:
+               axis_width_field = 2;
+               break;
+       }
+
+       return axis_width_field;
+}
+
+static u32
+xsdfec_translate_axis_words_cfg_val(
+       enum xsdfec_axis_word_include axis_word_inc_cfg)
+{
+       u32 axis_words_field = 0;
+
+       if (axis_word_inc_cfg == XSDFEC_FIXED_VALUE ||
+           axis_word_inc_cfg == XSDFEC_IN_BLOCK)
+               axis_words_field = 0;
+       else if (axis_word_inc_cfg == XSDFEC_PER_AXI_TRANSACTION)
+               axis_words_field = 1;
+
+       return axis_words_field;
+}
+
+#define XSDFEC_AXIS_DOUT_WORDS_LSB     (5)
+#define XSDFEC_AXIS_DOUT_WIDTH_LSB     (3)
+#define XSDFEC_AXIS_DIN_WORDS_LSB      (2)
+#define XSDFEC_AXIS_DIN_WIDTH_LSB      (0)
+static int
+xsdfec_cfg_axi_streams(struct xsdfec_dev *xsdfec)
+{
+       u32 reg_value;
+       u32 dout_words_field;
+       u32 dout_width_field;
+       u32 din_words_field;
+       u32 din_width_field;
+       struct xsdfec_config *config = &xsdfec->config;
+
+       /* translate config info to register values */
+       dout_words_field =
+               xsdfec_translate_axis_words_cfg_val(config->dout_word_include);
+       dout_width_field =
+               xsdfec_translate_axis_width_cfg_val(config->dout_width);
+       din_words_field =
+               xsdfec_translate_axis_words_cfg_val(config->din_word_include);
+       din_width_field =
+               xsdfec_translate_axis_words_cfg_val(config->din_width);
+
+       reg_value = dout_words_field << XSDFEC_AXIS_DOUT_WORDS_LSB;
+       reg_value |= dout_width_field << XSDFEC_AXIS_DOUT_WIDTH_LSB;
+       reg_value |= din_words_field << XSDFEC_AXIS_DIN_WORDS_LSB;
+       reg_value |= din_width_field << XSDFEC_AXIS_DIN_WIDTH_LSB;
+
+       xsdfec_regwrite(xsdfec, XSDFEC_AXIS_WIDTH_ADDR, reg_value);
+
+       return 0;
+}
+
 static int xsdfec_start(struct xsdfec_dev *xsdfec)
 {
        u32 regread;
@@ -1107,8 +1176,6 @@ static int xsdfec_start(struct xsdfec_dev *xsdfec)
                return -EINVAL;
        }
 
-       /* Set AXIS width */
-       xsdfec_regwrite(xsdfec, XSDFEC_AXIS_WIDTH_ADDR, 0);
        /* Set AXIS enable */
        xsdfec_regwrite(xsdfec,
                        XSDFEC_AXIS_ENABLE_ADDR,
@@ -1288,43 +1355,95 @@ xsdfec_parse_of(struct xsdfec_dev *xsdfec)
        struct device_node *node = dev->of_node;
        int rval;
        const char *fec_code;
-       const char *fec_op_mode;
+       u32 din_width;
+       u32 din_word_include;
+       u32 dout_width;
+       u32 dout_word_include;
 
-       rval = of_property_read_string(node,
-                                      "xlnx,sdfec-op-mode",
-                                      &fec_op_mode);
+       rval = of_property_read_string(node, "xlnx,sdfec-code", &fec_code);
        if (rval < 0) {
-               dev_err(dev, "xlnx,sdfec-op-mode not in DT");
+               dev_err(dev, "xlnx,sdfec-code not in DT");
                return rval;
        }
 
-       if (!strcasecmp(fec_op_mode, "encode")) {
-               xsdfec->config.mode = XSDFEC_ENCODE;
-       } else if (!strcasecmp(fec_op_mode, "decode")) {
-               xsdfec->config.mode = XSDFEC_DECODE;
+       if (!strcasecmp(fec_code, "ldpc")) {
+               xsdfec->config.code = XSDFEC_LDPC_CODE;
+       } else if (!strcasecmp(fec_code, "turbo")) {
+               xsdfec->config.code = XSDFEC_TURBO_CODE;
        } else {
-               dev_err(dev, "Encode or Decode not specified in DT");
+               dev_err(xsdfec->dev, "Invalid Code in DT");
                return -EINVAL;
        }
 
-       rval = of_property_read_string(node, "xlnx,sdfec-code", &fec_code);
+       rval = of_property_read_u32(node, "xlnx,sdfec-din-words",
+                                   &din_word_include);
        if (rval < 0) {
-               dev_err(dev, "xlnx,sdfec-code not in DT");
+               dev_err(dev, "xlnx,sdfec-din-words not in DT");
                return rval;
        }
 
-       if (!strcasecmp(fec_code, "ldpc")) {
-               xsdfec->config.code = XSDFEC_LDPC_CODE;
-       } else if (!strcasecmp(fec_code, "turbo")) {
-               xsdfec->config.code = XSDFEC_TURBO_CODE;
+       if (din_word_include < XSDFEC_AXIS_WORDS_INCLUDE_MAX) {
+               xsdfec->config.din_word_include = din_word_include;
+       } else {
+               dev_err(xsdfec->dev, "Invalid DIN Words in DT");
+               return -EINVAL;
+       }
+
+       rval = of_property_read_u32(node, "xlnx,sdfec-din-width", &din_width);
+       if (rval < 0) {
+               dev_err(dev, "xlnx,sdfec-din-width not in DT");
+               return rval;
+       }
+
+       switch (din_width) {
+       /* Fall through and set for valid values */
+       case XSDFEC_1x128b:
+       case XSDFEC_2x128b:
+       case XSDFEC_4x128b:
+               xsdfec->config.din_width = din_width;
+               break;
+       default:
+               dev_err(xsdfec->dev, "Invalid DIN Width in DT");
+               return -EINVAL;
+       }
+
+       rval = of_property_read_u32(node, "xlnx,sdfec-dout-words",
+                                   &dout_word_include);
+       if (rval < 0) {
+               dev_err(dev, "xlnx,sdfec-dout-words not in DT");
+               return rval;
+       }
+
+       if (dout_word_include < XSDFEC_AXIS_WORDS_INCLUDE_MAX) {
+               xsdfec->config.dout_word_include = dout_word_include;
        } else {
-               dev_err(xsdfec->dev, "Invalid Op Mode in DT");
+               dev_err(xsdfec->dev, "Invalid DOUT Words in DT");
+               return -EINVAL;
+       }
+
+       rval = of_property_read_u32(node, "xlnx,sdfec-dout-width", &dout_width);
+       if (rval < 0) {
+               dev_err(dev, "xlnx,sdfec-dout-width not in DT");
+               return rval;
+       }
+
+       switch (dout_width) {
+       /* Fall through and set for valid values */
+       case XSDFEC_1x128b:
+       case XSDFEC_2x128b:
+       case XSDFEC_4x128b:
+               xsdfec->config.dout_width = dout_width;
+               break;
+       default:
+               dev_err(xsdfec->dev, "Invalid DOUT Width in DT");
                return -EINVAL;
        }
 
        /* Write LDPC to CODE Register */
        xsdfec_regwrite(xsdfec, XSDFEC_FEC_CODE_ADDR, xsdfec->config.code - 1);
 
+       xsdfec_cfg_axi_streams(xsdfec);
+
        return 0;
 }
 
@@ -1536,7 +1655,7 @@ xsdfec_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id xsdfec_of_match[] = {
-       { .compatible = "xlnx,fec-engine", },
+       { .compatible = "xlnx,sd-fec-1.1", },
        { /* end of table */ }
 };
 MODULE_DEVICE_TABLE(of, xsdfec_of_match);
index 6e2437b99489d79bb2897f43e680519419d2a1a7..4671cc6b06daca2bf5977f353176b2c1590085c7 100644 (file)
@@ -51,10 +51,17 @@ enum xsdfec_state {
        XSDFEC_NEEDS_RESET,
 };
 
-enum xsdfec_op_mode {
-       XSDFEC_UNKNOWN_MODE = 0,
-       XSDFEC_ENCODE,
-       XSDFEC_DECODE,
+enum xsdfec_axis_width {
+       XSDFEC_1x128b = 1,
+       XSDFEC_2x128b = 2,
+       XSDFEC_4x128b = 4,
+};
+
+enum xsdfec_axis_word_include {
+       XSDFEC_FIXED_VALUE = 0,
+       XSDFEC_IN_BLOCK,
+       XSDFEC_PER_AXI_TRANSACTION,
+       XSDFEC_AXIS_WORDS_INCLUDE_MAX,
 };
 
 /**
@@ -134,14 +141,20 @@ struct xsdfec_status {
  * struct xsdfec_config - Configuration of SDFEC device
  * @fec_id: ID of SDFEC instance
  * @code: The codes being used by the SDFEC instance
- * @mode: Mode that the SDFEC is operating
  * @order: Order of Operation
+ * @din_width: Width of the DIN AXI Stream
+ * @din_word_include: How DIN_WORDS are inputted
+ * @dout_width: Width of the DOUT AXI Stream
+ * @dout_word_include: HOW DOUT_WORDS are outputted
  */
 struct xsdfec_config {
        s32 fec_id;
        enum xsdfec_code code;
-       enum xsdfec_op_mode mode;
        enum xsdfec_order order;
+       enum xsdfec_axis_width din_width;
+       enum xsdfec_axis_word_include din_word_include;
+       enum xsdfec_axis_width dout_width;
+       enum xsdfec_axis_word_include dout_word_include;
 };
 
 /**