get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/1415007/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 1415007,
    "url": "http://patchwork.ozlabs.org/api/patches/1415007/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/20201211160612.1498780-38-sr@denx.de/",
    "project": {
        "id": 18,
        "url": "http://patchwork.ozlabs.org/api/projects/18/?format=api",
        "name": "U-Boot",
        "link_name": "uboot",
        "list_id": "u-boot.lists.denx.de",
        "list_email": "u-boot@lists.denx.de",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20201211160612.1498780-38-sr@denx.de>",
    "list_archive_url": null,
    "date": "2020-12-11T16:05:59",
    "name": "[v1,37/50] mips: octeon: Add cvmx-helper-fdt.c",
    "commit_ref": "f9174d6a925b997a6779cead314988e3a37b323b",
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "95aa33d3dfa904391812ccccdbe3ffe4cbbdca99",
    "submitter": {
        "id": 13,
        "url": "http://patchwork.ozlabs.org/api/people/13/?format=api",
        "name": "Stefan Roese",
        "email": "sr@denx.de"
    },
    "delegate": {
        "id": 4307,
        "url": "http://patchwork.ozlabs.org/api/users/4307/?format=api",
        "username": "danielschwierzeck",
        "first_name": "Daniel",
        "last_name": "Schwierzeck",
        "email": "daniel.schwierzeck@googlemail.com"
    },
    "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/20201211160612.1498780-38-sr@denx.de/mbox/",
    "series": [
        {
            "id": 220054,
            "url": "http://patchwork.ozlabs.org/api/series/220054/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=220054",
            "date": "2020-12-11T16:05:23",
            "name": "mips: octeon: Add serdes and device helper support incl. DM PCIe driver",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/220054/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/1415007/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/1415007/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<u-boot-bounces@lists.denx.de>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org",
        "Authentication-Results": [
            "ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de\n (client-ip=85.214.62.61; helo=phobos.denx.de;\n envelope-from=u-boot-bounces@lists.denx.de; receiver=<UNKNOWN>)",
            "ozlabs.org;\n dmarc=none (p=none dis=none) header.from=denx.de",
            "ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=denx.de header.i=@denx.de header.a=rsa-sha256\n header.s=phobos-20191101 header.b=rUR2qzRx;\n\tdkim-atps=neutral",
            "phobos.denx.de;\n dmarc=none (p=none dis=none) header.from=denx.de",
            "phobos.denx.de;\n spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de",
            "phobos.denx.de;\n dmarc=none (p=none dis=none) header.from=denx.de",
            "phobos.denx.de; spf=none smtp.mailfrom=sr@denx.de"
        ],
        "Received": [
            "from phobos.denx.de (phobos.denx.de [85.214.62.61])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange X25519 server-signature RSA-PSS (4096 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 4CswmH4HXTz9sRK\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 12 Dec 2020 03:12:31 +1100 (AEDT)",
            "from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id D3BD482739;\n\tFri, 11 Dec 2020 17:08:32 +0100 (CET)",
            "by phobos.denx.de (Postfix, from userid 109)\n id C7E0E827AE; Fri, 11 Dec 2020 17:08:08 +0100 (CET)",
            "from mx2.mailbox.org (mx2a.mailbox.org\n [IPv6:2001:67c:2050:104:0:2:25:2])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits))\n (No client certificate requested)\n by phobos.denx.de (Postfix) with ESMTPS id E91C08270F\n for <u-boot@lists.denx.de>; Fri, 11 Dec 2020 17:06:28 +0100 (CET)",
            "from smtp1.mailbox.org (smtp1.mailbox.org [80.241.60.240])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest\n SHA256) (No client certificate requested)\n by mx2.mailbox.org (Postfix) with ESMTPS id 87C01A0BDC;\n Fri, 11 Dec 2020 17:06:28 +0100 (CET)",
            "from smtp1.mailbox.org ([80.241.60.240])\n by spamfilter06.heinlein-hosting.de (spamfilter06.heinlein-hosting.de\n [80.241.56.125]) (amavisd-new, port 10030)\n with ESMTP id ePE3rmHOKH8l; Fri, 11 Dec 2020 17:06:24 +0100 (CET)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=denx.de;\n\ts=phobos-20191101; t=1607702913;\n\tbh=Jkqz44yoNjlSwwDVZNv+jLBaMKbjHATbwm/PT0OzxqA=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id:\n\t List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe:\n\t From;\n\tb=rUR2qzRxlSzrWPV/HxpndiYdcjKGSANhPsnIRnqdKfryqhxdv3ovAnAxxeqsVfarR\n\t SPf0uyQxXrRf80CgRxeVky9x0hNcGwmf5KcB2Z+VvDFPpFv9RLTMk95UKY/PbixA9G\n\t tG5aArsNdBxBvzrE5ZVfrMtiJQZ4IH7NC0rReNtkhP/tUD3jQ/WSFBoF7TzxLHHzDO\n\t nzHrKLFFXLLdrqx46HuLALjqHYfL1pTxNuoxnZ6pAEOVlqD/4leO8uxXjuQKlncXk0\n\t xpXEJmM0g3R3Ouz2NF04CjCcnLkeiD6UMspTTgSF+g6PFIAZ+AvLrLQAdZ1uvLGBK5\n\t 3KC6+HTy35a3g==",
        "X-Spam-Checker-Version": "SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de",
        "X-Spam-Level": "",
        "X-Spam-Status": "No, score=-2.6 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_LOW,\n SPF_HELO_NONE autolearn=ham autolearn_force=no version=3.4.2",
        "From": "Stefan Roese <sr@denx.de>",
        "To": "u-boot@lists.denx.de",
        "Cc": "daniel.schwierzeck@gmail.com, awilliams@marvell.com, cchavva@marvell.com",
        "Subject": "[PATCH v1 37/50] mips: octeon: Add cvmx-helper-fdt.c",
        "Date": "Fri, 11 Dec 2020 17:05:59 +0100",
        "Message-Id": "<20201211160612.1498780-38-sr@denx.de>",
        "In-Reply-To": "<20201211160612.1498780-1-sr@denx.de>",
        "References": "<20201211160612.1498780-1-sr@denx.de>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-MBO-SPAM-Probability": "",
        "X-Rspamd-Score": "-0.76 / 15.00 / 15.00",
        "X-Rspamd-Queue-Id": "7E8081887",
        "X-Rspamd-UID": "e8ab8f",
        "X-BeenThere": "u-boot@lists.denx.de",
        "X-Mailman-Version": "2.1.34",
        "Precedence": "list",
        "List-Id": "U-Boot discussion <u-boot.lists.denx.de>",
        "List-Unsubscribe": "<https://lists.denx.de/options/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>",
        "List-Archive": "<https://lists.denx.de/pipermail/u-boot/>",
        "List-Post": "<mailto:u-boot@lists.denx.de>",
        "List-Help": "<mailto:u-boot-request@lists.denx.de?subject=help>",
        "List-Subscribe": "<https://lists.denx.de/listinfo/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=subscribe>",
        "Errors-To": "u-boot-bounces@lists.denx.de",
        "Sender": "\"U-Boot\" <u-boot-bounces@lists.denx.de>",
        "X-Virus-Scanned": "clamav-milter 0.102.3 at phobos.denx.de",
        "X-Virus-Status": "Clean"
    },
    "content": "From: Aaron Williams <awilliams@marvell.com>\n\nImport cvmx-helper-fdt.c from 2013 U-Boot. It will be used by the later\nadded drivers to support PCIe and networking on the MIPS Octeon II / III\nplatforms.\n\nSigned-off-by: Aaron Williams <awilliams@marvell.com>\nSigned-off-by: Stefan Roese <sr@denx.de>\n---\n\n arch/mips/mach-octeon/cvmx-helper-fdt.c | 970 ++++++++++++++++++++++++\n 1 file changed, 970 insertions(+)\n create mode 100644 arch/mips/mach-octeon/cvmx-helper-fdt.c",
    "diff": "diff --git a/arch/mips/mach-octeon/cvmx-helper-fdt.c b/arch/mips/mach-octeon/cvmx-helper-fdt.c\nnew file mode 100644\nindex 0000000000..87bc6d2adc\n--- /dev/null\n+++ b/arch/mips/mach-octeon/cvmx-helper-fdt.c\n@@ -0,0 +1,970 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/*\n+ * Copyright (C) 2020 Marvell International Ltd.\n+ *\n+ * FDT Helper functions similar to those provided to U-Boot.\n+ */\n+\n+#include <log.h>\n+#include <malloc.h>\n+#include <net.h>\n+#include <linux/delay.h>\n+\n+#include <mach/cvmx-regs.h>\n+#include <mach/cvmx-csr.h>\n+#include <mach/cvmx-bootmem.h>\n+#include <mach/octeon-model.h>\n+#include <mach/octeon_fdt.h>\n+#include <mach/cvmx-helper.h>\n+#include <mach/cvmx-helper-board.h>\n+#include <mach/cvmx-helper-cfg.h>\n+#include <mach/cvmx-helper-fdt.h>\n+#include <mach/cvmx-helper-gpio.h>\n+\n+/** Structure used to get type of GPIO from device tree */\n+struct gpio_compat {\n+\tchar *compatible;\t  /** Compatible string */\n+\tenum cvmx_gpio_type type; /** Type */\n+\tint8_t size;\t\t  /** (max) Number of pins */\n+};\n+\n+#define GPIO_REG_PCA953X_IN\t0\n+#define GPIO_REG_PCA953X_OUT\t1\n+#define GPIO_REG_PCA953X_INVERT 2\n+#define GPIO_REG_PCA953X_DIR\t3\n+\n+#define GPIO_REG_PCA957X_IN\t0\n+#define GPIO_REG_PCA957X_INVERT 1\n+#define GPIO_REG_PCA957X_CFG\t4\n+#define GPIO_REG_PCA957X_OUT\t5\n+\n+enum cvmx_i2c_mux_type { I2C_MUX, I2C_SWITCH };\n+\n+/** Structure used to get type of GPIO from device tree */\n+struct mux_compat {\n+\tchar *compatible;\t\t /** Compatible string */\n+\tenum cvmx_i2c_bus_type type;\t /** Mux chip type */\n+\tenum cvmx_i2c_mux_type mux_type; /** Type of mux */\n+\tu8 enable;\t\t\t /** Enable bit for mux */\n+\tu8 size;\t\t\t /** (max) Number of channels */\n+};\n+\n+/**\n+ * Local allocator to handle both SE and U-Boot that also zeroes out memory\n+ *\n+ * @param\tsize\tnumber of bytes to allocate\n+ *\n+ * @return\tpointer to allocated memory or NULL if out of memory.\n+ *\t\tAlignment is set to 8-bytes.\n+ */\n+void *__cvmx_fdt_alloc(size_t size)\n+{\n+\treturn calloc(size, 1);\n+}\n+\n+/**\n+ * Free allocated memory.\n+ *\n+ * @param\tptr\tpointer to memory to free\n+ *\n+ * NOTE: This only works in U-Boot since SE does not really have a freeing\n+ *\t mechanism.  In SE the memory is zeroed out.\n+ */\n+void __cvmx_fdt_free(void *ptr, size_t size)\n+{\n+\tfree(ptr);\n+}\n+\n+/**\n+ * Look up a phandle and follow it to its node then return the offset of that\n+ * node.\n+ *\n+ * @param[in]\tfdt_addr\tpointer to FDT blob\n+ * @param\tnode\t\tnode to read phandle from\n+ * @param[in]\tprop_name\tname of property to find\n+ * @param[in,out] lenp\t\tNumber of phandles, input max number\n+ * @param[out]\tnodes\t\tArray of phandle nodes\n+ *\n+ * @return\t-ve error code on error or 0 for success\n+ */\n+int cvmx_fdt_lookup_phandles(const void *fdt_addr, int node,\n+\t\t\t     const char *prop_name, int *lenp,\n+\t\t\t     int *nodes)\n+{\n+\tconst u32 *phandles;\n+\tint count;\n+\tint i;\n+\n+\tphandles = fdt_getprop(fdt_addr, node, prop_name, &count);\n+\tif (!phandles || count < 0)\n+\t\treturn -FDT_ERR_NOTFOUND;\n+\n+\tcount /= 4;\n+\tif (count > *lenp)\n+\t\tcount = *lenp;\n+\n+\tfor (i = 0; i < count; i++)\n+\t\tnodes[i] = fdt_node_offset_by_phandle(fdt_addr,\n+\t\t\t\t\t\t      fdt32_to_cpu(phandles[i]));\n+\t*lenp = count;\n+\treturn 0;\n+}\n+\n+/**\n+ * Given a FDT node return the CPU node number\n+ *\n+ * @param[in]\tfdt_addr\tAddress of FDT\n+ * @param\tnode\t\tFDT node number\n+ *\n+ * @return\tCPU node number or error if negative\n+ */\n+int cvmx_fdt_get_cpu_node(const void *fdt_addr, int node)\n+{\n+\tint parent = node;\n+\tconst u32 *ranges;\n+\tint len = 0;\n+\n+\twhile (fdt_node_check_compatible(fdt_addr, parent, \"simple-bus\") != 0) {\n+\t\tparent = fdt_parent_offset(fdt_addr, parent);\n+\t\tif (parent < 0)\n+\t\t\treturn parent;\n+\t}\n+\tranges = fdt_getprop(fdt_addr, parent, \"ranges\", &len);\n+\tif (!ranges)\n+\t\treturn len;\n+\n+\tif (len == 0)\n+\t\treturn 0;\n+\n+\tif (len < 24)\n+\t\treturn -FDT_ERR_TRUNCATED;\n+\n+\treturn fdt32_to_cpu(ranges[2]) / 0x10;\n+}\n+\n+/**\n+ * Get the total size of the flat device tree\n+ *\n+ * @param[in]\tfdt_addr\tAddress of FDT\n+ *\n+ * @return\tSize of flat device tree in bytes or error if negative.\n+ */\n+int cvmx_fdt_get_fdt_size(const void *fdt_addr)\n+{\n+\tint rc;\n+\n+\trc = fdt_check_header(fdt_addr);\n+\tif (rc)\n+\t\treturn rc;\n+\treturn fdt_totalsize(fdt_addr);\n+}\n+\n+/**\n+ * Returns if a node is compatible with one of the items in the string list\n+ *\n+ * @param[in]\tfdt_addr\tPointer to flat device tree\n+ * @param\tnode\t\tNode offset to check\n+ * @param[in]\tstrlist\t\tArray of FDT device compatibility strings,\n+ *\t\t\t\tmust end with NULL or empty string.\n+ *\n+ * @return\t0 if at least one item matches, 1 if no matches\n+ */\n+int cvmx_fdt_node_check_compatible_list(const void *fdt_addr, int node, const char *const *strlist)\n+{\n+\twhile (*strlist && **strlist) {\n+\t\tif (!fdt_node_check_compatible(fdt_addr, node, *strlist))\n+\t\t\treturn 0;\n+\t\tstrlist++;\n+\t}\n+\treturn 1;\n+}\n+\n+/**\n+ * Given a FDT node, return the next compatible node.\n+ *\n+ * @param[in]\tfdt_addr\tPointer to flat device tree\n+ * @param\tstart_offset\tStarting node offset or -1 to find the first\n+ * @param\tstrlist\t\tArray of FDT device compatibility strings, must\n+ *\t\t\t\tend with NULL or empty string.\n+ *\n+ * @return\tnext matching node or -1 if no more matches.\n+ */\n+int cvmx_fdt_node_offset_by_compatible_list(const void *fdt_addr, int startoffset,\n+\t\t\t\t\t    const char *const *strlist)\n+{\n+\tint offset;\n+\n+\tfor (offset = fdt_next_node(fdt_addr, startoffset, NULL); offset >= 0;\n+\t     offset = fdt_next_node(fdt_addr, offset, NULL)) {\n+\t\tif (!cvmx_fdt_node_check_compatible_list(fdt_addr, offset, strlist))\n+\t\t\treturn offset;\n+\t}\n+\treturn -1;\n+}\n+\n+/**\n+ * Attaches a PHY to a SFP or QSFP.\n+ *\n+ * @param\tsfp\t\tsfp to attach PHY to\n+ * @param\tphy_info\tphy descriptor to attach or NULL to detach\n+ */\n+void cvmx_sfp_attach_phy(struct cvmx_fdt_sfp_info *sfp, struct cvmx_phy_info *phy_info)\n+{\n+\tsfp->phy_info = phy_info;\n+\tif (phy_info)\n+\t\tphy_info->sfp_info = sfp;\n+}\n+\n+/**\n+ * Assigns an IPD port to a SFP slot\n+ *\n+ * @param\tsfp\t\tHandle to SFP data structure\n+ * @param\tipd_port\tPort to assign it to\n+ *\n+ * @return\t0 for success, -1 on error\n+ */\n+int cvmx_sfp_set_ipd_port(struct cvmx_fdt_sfp_info *sfp, int ipd_port)\n+{\n+\tint i;\n+\n+\tif (sfp->is_qsfp) {\n+\t\tint xiface;\n+\t\tcvmx_helper_interface_mode_t mode;\n+\n+\t\txiface = cvmx_helper_get_interface_num(ipd_port);\n+\t\tmode = cvmx_helper_interface_get_mode(xiface);\n+\t\tsfp->ipd_port[0] = ipd_port;\n+\n+\t\tswitch (mode) {\n+\t\tcase CVMX_HELPER_INTERFACE_MODE_SGMII:\n+\t\tcase CVMX_HELPER_INTERFACE_MODE_XFI:\n+\t\tcase CVMX_HELPER_INTERFACE_MODE_10G_KR:\n+\t\t\tfor (i = 1; i < 4; i++)\n+\t\t\t\tsfp->ipd_port[i] = cvmx_helper_get_ipd_port(xiface, i);\n+\t\t\tbreak;\n+\t\tcase CVMX_HELPER_INTERFACE_MODE_XLAUI:\n+\t\tcase CVMX_HELPER_INTERFACE_MODE_40G_KR4:\n+\t\t\tsfp->ipd_port[0] = ipd_port;\n+\t\t\tfor (i = 1; i < 4; i++)\n+\t\t\t\tsfp->ipd_port[i] = -1;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tdebug(\"%s: Interface mode %s for interface 0x%x, ipd_port %d not supported for QSFP\\n\",\n+\t\t\t      __func__, cvmx_helper_interface_mode_to_string(mode), xiface,\n+\t\t\t      ipd_port);\n+\t\t\treturn -1;\n+\t\t}\n+\t} else {\n+\t\tsfp->ipd_port[0] = ipd_port;\n+\t\tfor (i = 1; i < 4; i++)\n+\t\t\tsfp->ipd_port[i] = -1;\n+\t}\n+\treturn 0;\n+}\n+\n+/**\n+ * Parses all of the channels assigned to a VSC7224 device\n+ *\n+ * @param[in]\t\tfdt_addr\tAddress of flat device tree\n+ * @param\t\tof_offset\tOffset of vsc7224 node\n+ * @param[in,out]\tvsc7224\t\tData structure to hold the data\n+ *\n+ * @return\t0 for success, -1 on error\n+ */\n+static int cvmx_fdt_parse_vsc7224_channels(const void *fdt_addr, int of_offset,\n+\t\t\t\t\t   struct cvmx_vsc7224 *vsc7224)\n+{\n+\tint parent_offset = of_offset;\n+\tint err = 0;\n+\tint reg;\n+\tint num_chan = 0;\n+\tstruct cvmx_vsc7224_chan *channel;\n+\tstruct cvmx_fdt_sfp_info *sfp_info;\n+\tint len;\n+\tint num_taps;\n+\tint i;\n+\tconst u32 *tap_values;\n+\tint of_mac;\n+\tint xiface, index;\n+\tbool is_tx;\n+\tbool is_qsfp;\n+\tconst char *mac_str;\n+\n+\tdebug(\"%s(%p, %d, %s)\\n\", __func__, fdt_addr, of_offset, vsc7224->name);\n+\tdo {\n+\t\t/* Walk through all channels */\n+\t\tof_offset = fdt_node_offset_by_compatible(fdt_addr, of_offset,\n+\t\t\t\t\t\t\t  \"vitesse,vsc7224-channel\");\n+\t\tif (of_offset == -FDT_ERR_NOTFOUND) {\n+\t\t\tbreak;\n+\t\t} else if (of_offset < 0) {\n+\t\t\tdebug(\"%s: Failed finding compatible channel\\n\",\n+\t\t\t      __func__);\n+\t\t\terr = -1;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (fdt_parent_offset(fdt_addr, of_offset) != parent_offset)\n+\t\t\tbreak;\n+\t\treg = cvmx_fdt_get_int(fdt_addr, of_offset, \"reg\", -1);\n+\t\tif (reg < 0 || reg > 3) {\n+\t\t\tdebug(\"%s: channel reg is either not present or out of range\\n\",\n+\t\t\t      __func__);\n+\t\t\terr = -1;\n+\t\t\tbreak;\n+\t\t}\n+\t\tis_tx = cvmx_fdt_get_bool(fdt_addr, of_offset, \"direction-tx\");\n+\n+\t\tdebug(\"%s(%s): Adding %cx channel %d\\n\",\n+\t\t      __func__, vsc7224->name, is_tx ? 't' : 'r',\n+\t\t      reg);\n+\t\ttap_values = (const uint32_t *)fdt_getprop(fdt_addr, of_offset, \"taps\", &len);\n+\t\tif (!tap_values) {\n+\t\t\tdebug(\"%s: Error: no taps defined for vsc7224 channel %d\\n\",\n+\t\t\t      __func__, reg);\n+\t\t\terr = -1;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (vsc7224->channel[reg]) {\n+\t\t\tdebug(\"%s: Error: channel %d already assigned at %p\\n\",\n+\t\t\t      __func__, reg,\n+\t\t\t      vsc7224->channel[reg]);\n+\t\t\terr = -1;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (len % 16) {\n+\t\t\tdebug(\"%s: Error: tap format error for channel %d\\n\",\n+\t\t\t      __func__, reg);\n+\t\t\terr = -1;\n+\t\t\tbreak;\n+\t\t}\n+\t\tnum_taps = len / 16;\n+\t\tdebug(\"%s: Adding %d taps\\n\", __func__, num_taps);\n+\n+\t\tchannel = __cvmx_fdt_alloc(sizeof(*channel) +\n+\t\t\t\t\t   num_taps * sizeof(struct cvmx_vsc7224_tap));\n+\t\tif (!channel) {\n+\t\t\tdebug(\"%s: Out of memory\\n\", __func__);\n+\t\t\terr = -1;\n+\t\t\tbreak;\n+\t\t}\n+\t\tvsc7224->channel[reg] = channel;\n+\t\tchannel->num_taps = num_taps;\n+\t\tchannel->lane = reg;\n+\t\tchannel->of_offset = of_offset;\n+\t\tchannel->is_tx = is_tx;\n+\t\tchannel->pretap_disable = cvmx_fdt_get_bool(fdt_addr, of_offset, \"pretap-disable\");\n+\t\tchannel->posttap_disable =\n+\t\t\tcvmx_fdt_get_bool(fdt_addr, of_offset, \"posttap-disable\");\n+\t\tchannel->vsc7224 = vsc7224;\n+\t\t/* Read all the tap values */\n+\t\tfor (i = 0; i < num_taps; i++) {\n+\t\t\tchannel->taps[i].len = fdt32_to_cpu(tap_values[i * 4 + 0]);\n+\t\t\tchannel->taps[i].main_tap = fdt32_to_cpu(tap_values[i * 4 + 1]);\n+\t\t\tchannel->taps[i].pre_tap = fdt32_to_cpu(tap_values[i * 4 + 2]);\n+\t\t\tchannel->taps[i].post_tap = fdt32_to_cpu(tap_values[i * 4 + 3]);\n+\t\t\tdebug(\"%s: tap %d: len: %d, main_tap: 0x%x, pre_tap: 0x%x, post_tap: 0x%x\\n\",\n+\t\t\t      __func__, i, channel->taps[i].len, channel->taps[i].main_tap,\n+\t\t\t      channel->taps[i].pre_tap, channel->taps[i].post_tap);\n+\t\t}\n+\t\t/* Now find out which interface it's mapped to */\n+\t\tchannel->ipd_port = -1;\n+\n+\t\tmac_str = \"sfp-mac\";\n+\t\tif (fdt_getprop(fdt_addr, of_offset, mac_str, NULL)) {\n+\t\t\tis_qsfp = false;\n+\t\t} else if (fdt_getprop(fdt_addr, of_offset, \"qsfp-mac\", NULL)) {\n+\t\t\tis_qsfp = true;\n+\t\t\tmac_str = \"qsfp-mac\";\n+\t\t} else {\n+\t\t\tdebug(\"%s: Error: MAC not found for %s channel %d\\n\", __func__,\n+\t\t\t      vsc7224->name, reg);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tof_mac = cvmx_fdt_lookup_phandle(fdt_addr, of_offset, mac_str);\n+\t\tif (of_mac < 0) {\n+\t\t\tdebug(\"%s: Error %d with MAC %s phandle for %s\\n\", __func__, of_mac,\n+\t\t\t      mac_str, vsc7224->name);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tdebug(\"%s: Found mac at offset %d\\n\", __func__, of_mac);\n+\t\terr = cvmx_helper_cfg_get_xiface_index_by_fdt_node_offset(of_mac, &xiface, &index);\n+\t\tif (!err) {\n+\t\t\tchannel->xiface = xiface;\n+\t\t\tchannel->index = index;\n+\t\t\tchannel->ipd_port = cvmx_helper_get_ipd_port(xiface, index);\n+\n+\t\t\tdebug(\"%s: Found MAC, xiface: 0x%x, index: %d, ipd port: %d\\n\", __func__,\n+\t\t\t      xiface, index, channel->ipd_port);\n+\t\t\tif (channel->ipd_port >= 0) {\n+\t\t\t\tcvmx_helper_cfg_set_vsc7224_chan_info(xiface, index, channel);\n+\t\t\t\tdebug(\"%s: Storing config channel for xiface 0x%x, index %d\\n\",\n+\t\t\t\t      __func__, xiface, index);\n+\t\t\t}\n+\t\t\tsfp_info = cvmx_helper_cfg_get_sfp_info(xiface, index);\n+\t\t\tif (!sfp_info) {\n+\t\t\t\tdebug(\"%s: Warning: no (Q)SFP+ slot found for xinterface 0x%x, index %d for channel %d\\n\",\n+\t\t\t\t      __func__, xiface, index, channel->lane);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\t/* Link it */\n+\t\t\tchannel->next = sfp_info->vsc7224_chan;\n+\t\t\tif (sfp_info->vsc7224_chan)\n+\t\t\t\tsfp_info->vsc7224_chan->prev = channel;\n+\t\t\tsfp_info->vsc7224_chan = channel;\n+\t\t\tsfp_info->is_vsc7224 = true;\n+\t\t\tdebug(\"%s: Registering VSC7224 %s channel %d with SFP %s\\n\", __func__,\n+\t\t\t      vsc7224->name, channel->lane, sfp_info->name);\n+\t\t\tif (!sfp_info->mod_abs_changed) {\n+\t\t\t\tdebug(\"%s: Registering cvmx_sfp_vsc7224_mod_abs_changed at %p for xinterface 0x%x, index %d\\n\",\n+\t\t\t\t      __func__, &cvmx_sfp_vsc7224_mod_abs_changed, xiface, index);\n+\t\t\t\tcvmx_sfp_register_mod_abs_changed(\n+\t\t\t\t\tsfp_info,\n+\t\t\t\t\t&cvmx_sfp_vsc7224_mod_abs_changed,\n+\t\t\t\t\tNULL);\n+\t\t\t}\n+\t\t}\n+\t} while (!err && num_chan < 4);\n+\n+\treturn err;\n+}\n+\n+/**\n+ * @INTERNAL\n+ * Parses all instances of the Vitesse VSC7224 reclocking chip\n+ *\n+ * @param[in]\tfdt_addr\tAddress of flat device tree\n+ *\n+ * @return\t0 for success, error otherwise\n+ */\n+int __cvmx_fdt_parse_vsc7224(const void *fdt_addr)\n+{\n+\tint of_offset = -1;\n+\tstruct cvmx_vsc7224 *vsc7224 = NULL;\n+\tstruct cvmx_fdt_gpio_info *gpio_info = NULL;\n+\tint err = 0;\n+\tint of_parent;\n+\tstatic bool parsed;\n+\n+\tdebug(\"%s(%p)\\n\", __func__, fdt_addr);\n+\n+\tif (parsed) {\n+\t\tdebug(\"%s: Already parsed\\n\", __func__);\n+\t\treturn 0;\n+\t}\n+\tdo {\n+\t\tof_offset = fdt_node_offset_by_compatible(fdt_addr, of_offset,\n+\t\t\t\t\t\t\t  \"vitesse,vsc7224\");\n+\t\tdebug(\"%s: of_offset: %d\\n\", __func__, of_offset);\n+\t\tif (of_offset == -FDT_ERR_NOTFOUND) {\n+\t\t\tbreak;\n+\t\t} else if (of_offset < 0) {\n+\t\t\terr = -1;\n+\t\t\tdebug(\"%s: Error %d parsing FDT\\n\",\n+\t\t\t      __func__, of_offset);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tvsc7224 = __cvmx_fdt_alloc(sizeof(*vsc7224));\n+\n+\t\tif (!vsc7224) {\n+\t\t\tdebug(\"%s: Out of memory!\\n\", __func__);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tvsc7224->of_offset = of_offset;\n+\t\tvsc7224->i2c_addr = cvmx_fdt_get_int(fdt_addr, of_offset,\n+\t\t\t\t\t\t     \"reg\", -1);\n+\t\tof_parent = fdt_parent_offset(fdt_addr, of_offset);\n+\t\tvsc7224->i2c_bus = cvmx_fdt_get_i2c_bus(fdt_addr, of_parent);\n+\t\tif (vsc7224->i2c_addr < 0) {\n+\t\t\tdebug(\"%s: Error: reg field missing\\n\", __func__);\n+\t\t\terr = -1;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (!vsc7224->i2c_bus) {\n+\t\t\tdebug(\"%s: Error getting i2c bus\\n\", __func__);\n+\t\t\terr = -1;\n+\t\t\tbreak;\n+\t\t}\n+\t\tvsc7224->name = fdt_get_name(fdt_addr, of_offset, NULL);\n+\t\tdebug(\"%s: Adding %s\\n\", __func__, vsc7224->name);\n+\t\tif (fdt_getprop(fdt_addr, of_offset, \"reset\", NULL)) {\n+\t\t\tgpio_info = cvmx_fdt_gpio_get_info_phandle(fdt_addr, of_offset, \"reset\");\n+\t\t\tvsc7224->reset_gpio = gpio_info;\n+\t\t}\n+\t\tif (fdt_getprop(fdt_addr, of_offset, \"los\", NULL)) {\n+\t\t\tgpio_info = cvmx_fdt_gpio_get_info_phandle(fdt_addr, of_offset, \"los\");\n+\t\t\tvsc7224->los_gpio = gpio_info;\n+\t\t}\n+\t\tdebug(\"%s: Parsing channels\\n\", __func__);\n+\t\terr = cvmx_fdt_parse_vsc7224_channels(fdt_addr, of_offset, vsc7224);\n+\t\tif (err) {\n+\t\t\tdebug(\"%s: Error parsing VSC7224 channels\\n\", __func__);\n+\t\t\tbreak;\n+\t\t}\n+\t} while (of_offset > 0);\n+\n+\tif (err) {\n+\t\tdebug(\"%s(): Error\\n\", __func__);\n+\t\tif (vsc7224) {\n+\t\t\tif (vsc7224->reset_gpio)\n+\t\t\t\t__cvmx_fdt_free(vsc7224->reset_gpio, sizeof(*vsc7224->reset_gpio));\n+\t\t\tif (vsc7224->los_gpio)\n+\t\t\t\t__cvmx_fdt_free(vsc7224->los_gpio, sizeof(*vsc7224->los_gpio));\n+\t\t\tif (vsc7224->i2c_bus)\n+\t\t\t\tcvmx_fdt_free_i2c_bus(vsc7224->i2c_bus);\n+\t\t\t__cvmx_fdt_free(vsc7224, sizeof(*vsc7224));\n+\t\t}\n+\t}\n+\tif (!err)\n+\t\tparsed = true;\n+\n+\treturn err;\n+}\n+\n+/**\n+ * @INTERNAL\n+ * Parses all instances of the Avago AVSP5410 gearbox phy\n+ *\n+ * @param[in]\tfdt_addr\tAddress of flat device tree\n+ *\n+ * @return\t0 for success, error otherwise\n+ */\n+int __cvmx_fdt_parse_avsp5410(const void *fdt_addr)\n+{\n+\tint of_offset = -1;\n+\tstruct cvmx_avsp5410 *avsp5410 = NULL;\n+\tstruct cvmx_fdt_sfp_info *sfp_info;\n+\tint err = 0;\n+\tint of_parent;\n+\tstatic bool parsed;\n+\tint of_mac;\n+\tint xiface, index;\n+\tbool is_qsfp;\n+\tconst char *mac_str;\n+\n+\tdebug(\"%s(%p)\\n\", __func__, fdt_addr);\n+\n+\tif (parsed) {\n+\t\tdebug(\"%s: Already parsed\\n\", __func__);\n+\t\treturn 0;\n+\t}\n+\n+\tdo {\n+\t\tof_offset = fdt_node_offset_by_compatible(fdt_addr, of_offset,\n+\t\t\t\t\t\t\t  \"avago,avsp-5410\");\n+\t\tdebug(\"%s: of_offset: %d\\n\", __func__, of_offset);\n+\t\tif (of_offset == -FDT_ERR_NOTFOUND) {\n+\t\t\tbreak;\n+\t\t} else if (of_offset < 0) {\n+\t\t\terr = -1;\n+\t\t\tdebug(\"%s: Error %d parsing FDT\\n\", __func__, of_offset);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tavsp5410 = __cvmx_fdt_alloc(sizeof(*avsp5410));\n+\n+\t\tif (!avsp5410) {\n+\t\t\tdebug(\"%s: Out of memory!\\n\", __func__);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tavsp5410->of_offset = of_offset;\n+\t\tavsp5410->i2c_addr = cvmx_fdt_get_int(fdt_addr, of_offset,\n+\t\t\t\t\t\t      \"reg\", -1);\n+\t\tof_parent = fdt_parent_offset(fdt_addr, of_offset);\n+\t\tavsp5410->i2c_bus = cvmx_fdt_get_i2c_bus(fdt_addr, of_parent);\n+\t\tif (avsp5410->i2c_addr < 0) {\n+\t\t\tdebug(\"%s: Error: reg field missing\\n\", __func__);\n+\t\t\terr = -1;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (!avsp5410->i2c_bus) {\n+\t\t\tdebug(\"%s: Error getting i2c bus\\n\", __func__);\n+\t\t\terr = -1;\n+\t\t\tbreak;\n+\t\t}\n+\t\tavsp5410->name = fdt_get_name(fdt_addr, of_offset, NULL);\n+\t\tdebug(\"%s: Adding %s\\n\", __func__, avsp5410->name);\n+\n+\t\t/* Now find out which interface it's mapped to */\n+\t\tavsp5410->ipd_port = -1;\n+\n+\t\tmac_str = \"sfp-mac\";\n+\t\tif (fdt_getprop(fdt_addr, of_offset, mac_str, NULL)) {\n+\t\t\tis_qsfp = false;\n+\t\t} else if (fdt_getprop(fdt_addr, of_offset, \"qsfp-mac\", NULL)) {\n+\t\t\tis_qsfp = true;\n+\t\t\tmac_str = \"qsfp-mac\";\n+\t\t} else {\n+\t\t\tdebug(\"%s: Error: MAC not found for %s\\n\", __func__, avsp5410->name);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tof_mac = cvmx_fdt_lookup_phandle(fdt_addr, of_offset, mac_str);\n+\t\tif (of_mac < 0) {\n+\t\t\tdebug(\"%s: Error %d with MAC %s phandle for %s\\n\", __func__, of_mac,\n+\t\t\t      mac_str, avsp5410->name);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tdebug(\"%s: Found mac at offset %d\\n\", __func__, of_mac);\n+\t\terr = cvmx_helper_cfg_get_xiface_index_by_fdt_node_offset(of_mac, &xiface, &index);\n+\t\tif (!err) {\n+\t\t\tavsp5410->xiface = xiface;\n+\t\t\tavsp5410->index = index;\n+\t\t\tavsp5410->ipd_port = cvmx_helper_get_ipd_port(xiface, index);\n+\n+\t\t\tdebug(\"%s: Found MAC, xiface: 0x%x, index: %d, ipd port: %d\\n\", __func__,\n+\t\t\t      xiface, index, avsp5410->ipd_port);\n+\t\t\tif (avsp5410->ipd_port >= 0) {\n+\t\t\t\tcvmx_helper_cfg_set_avsp5410_info(xiface, index, avsp5410);\n+\t\t\t\tdebug(\"%s: Storing config phy for xiface 0x%x, index %d\\n\",\n+\t\t\t\t      __func__, xiface, index);\n+\t\t\t}\n+\t\t\tsfp_info = cvmx_helper_cfg_get_sfp_info(xiface, index);\n+\t\t\tif (!sfp_info) {\n+\t\t\t\tdebug(\"%s: Warning: no (Q)SFP+ slot found for xinterface 0x%x, index %d\\n\",\n+\t\t\t\t      __func__, xiface, index);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\tsfp_info->is_avsp5410 = true;\n+\t\t\tsfp_info->avsp5410 = avsp5410;\n+\t\t\tdebug(\"%s: Registering AVSP5410 %s with SFP %s\\n\", __func__, avsp5410->name,\n+\t\t\t      sfp_info->name);\n+\t\t\tif (!sfp_info->mod_abs_changed) {\n+\t\t\t\tdebug(\"%s: Registering cvmx_sfp_avsp5410_mod_abs_changed at %p for xinterface 0x%x, index %d\\n\",\n+\t\t\t\t      __func__, &cvmx_sfp_avsp5410_mod_abs_changed, xiface, index);\n+\t\t\t\tcvmx_sfp_register_mod_abs_changed(\n+\t\t\t\t\tsfp_info,\n+\t\t\t\t\t&cvmx_sfp_avsp5410_mod_abs_changed,\n+\t\t\t\t\tNULL);\n+\t\t\t}\n+\t\t}\n+\t} while (of_offset > 0);\n+\n+\tif (err) {\n+\t\tdebug(\"%s(): Error\\n\", __func__);\n+\t\tif (avsp5410) {\n+\t\t\tif (avsp5410->i2c_bus)\n+\t\t\t\tcvmx_fdt_free_i2c_bus(avsp5410->i2c_bus);\n+\t\t\t__cvmx_fdt_free(avsp5410, sizeof(*avsp5410));\n+\t\t}\n+\t}\n+\tif (!err)\n+\t\tparsed = true;\n+\n+\treturn err;\n+}\n+\n+/**\n+ * Parse QSFP GPIOs for SFP\n+ *\n+ * @param[in]\tfdt_addr\tPointer to flat device tree\n+ * @param\tof_offset\tOffset of QSFP node\n+ * @param[out]\tsfp_info\tPointer to sfp info to fill in\n+ *\n+ * @return\t0 for success\n+ */\n+static int cvmx_parse_qsfp(const void *fdt_addr, int of_offset, struct cvmx_fdt_sfp_info *sfp_info)\n+{\n+\tsfp_info->select = cvmx_fdt_gpio_get_info_phandle(fdt_addr, of_offset, \"select\");\n+\tsfp_info->mod_abs = cvmx_fdt_gpio_get_info_phandle(fdt_addr, of_offset, \"mod_prs\");\n+\tsfp_info->reset = cvmx_fdt_gpio_get_info_phandle(fdt_addr, of_offset, \"reset\");\n+\tsfp_info->interrupt = cvmx_fdt_gpio_get_info_phandle(fdt_addr, of_offset, \"interrupt\");\n+\tsfp_info->lp_mode = cvmx_fdt_gpio_get_info_phandle(fdt_addr, of_offset, \"lp_mode\");\n+\treturn 0;\n+}\n+\n+/**\n+ * Parse SFP GPIOs for SFP\n+ *\n+ * @param[in]\tfdt_addr\tPointer to flat device tree\n+ * @param\tof_offset\tOffset of SFP node\n+ * @param[out]\tsfp_info\tPointer to sfp info to fill in\n+ *\n+ * @return\t0 for success\n+ */\n+static int cvmx_parse_sfp(const void *fdt_addr, int of_offset, struct cvmx_fdt_sfp_info *sfp_info)\n+{\n+\tsfp_info->mod_abs = cvmx_fdt_gpio_get_info_phandle(fdt_addr, of_offset, \"mod_abs\");\n+\tsfp_info->rx_los = cvmx_fdt_gpio_get_info_phandle(fdt_addr, of_offset, \"rx_los\");\n+\tsfp_info->tx_disable = cvmx_fdt_gpio_get_info_phandle(fdt_addr, of_offset, \"tx_disable\");\n+\tsfp_info->tx_error = cvmx_fdt_gpio_get_info_phandle(fdt_addr, of_offset, \"tx_error\");\n+\treturn 0;\n+}\n+\n+/**\n+ * Parse SFP/QSFP EEPROM and diag\n+ *\n+ * @param[in]\tfdt_addr\tPointer to flat device tree\n+ * @param\tof_offset\tOffset of SFP node\n+ * @param[out]\tsfp_info\tPointer to sfp info to fill in\n+ *\n+ * @return\t0 for success, -1 on error\n+ */\n+static int cvmx_parse_sfp_eeprom(const void *fdt_addr, int of_offset,\n+\t\t\t\t struct cvmx_fdt_sfp_info *sfp_info)\n+{\n+\tint of_eeprom;\n+\tint of_diag;\n+\n+\tdebug(\"%s(%p, %d, %s)\\n\", __func__, fdt_addr, of_offset, sfp_info->name);\n+\tof_eeprom = cvmx_fdt_lookup_phandle(fdt_addr, of_offset, \"eeprom\");\n+\tif (of_eeprom < 0) {\n+\t\tdebug(\"%s: Missing \\\"eeprom\\\" from device tree for %s\\n\", __func__, sfp_info->name);\n+\t\treturn -1;\n+\t}\n+\n+\tsfp_info->i2c_bus = cvmx_fdt_get_i2c_bus(fdt_addr, fdt_parent_offset(fdt_addr, of_eeprom));\n+\tsfp_info->i2c_eeprom_addr = cvmx_fdt_get_int(fdt_addr, of_eeprom, \"reg\", 0x50);\n+\n+\tdebug(\"%s(%p, %d, %s, %d)\\n\", __func__, fdt_addr, of_offset, sfp_info->name,\n+\t      sfp_info->i2c_eeprom_addr);\n+\n+\tif (!sfp_info->i2c_bus) {\n+\t\tdebug(\"%s: Error: could not determine i2c bus for eeprom for %s\\n\", __func__,\n+\t\t      sfp_info->name);\n+\t\treturn -1;\n+\t}\n+\tof_diag = cvmx_fdt_lookup_phandle(fdt_addr, of_offset, \"diag\");\n+\tif (of_diag >= 0)\n+\t\tsfp_info->i2c_diag_addr = cvmx_fdt_get_int(fdt_addr, of_diag, \"reg\", 0x51);\n+\telse\n+\t\tsfp_info->i2c_diag_addr = 0x51;\n+\treturn 0;\n+}\n+\n+/**\n+ * Parse SFP information from device tree\n+ *\n+ * @param[in]\tfdt_addr\tAddress of flat device tree\n+ *\n+ * @return pointer to sfp info or NULL if error\n+ */\n+struct cvmx_fdt_sfp_info *cvmx_helper_fdt_parse_sfp_info(const void *fdt_addr, int of_offset)\n+{\n+\tstruct cvmx_fdt_sfp_info *sfp_info = NULL;\n+\tint err = -1;\n+\tbool is_qsfp;\n+\n+\tif (!fdt_node_check_compatible(fdt_addr, of_offset, \"ethernet,sfp-slot\")) {\n+\t\tis_qsfp = false;\n+\t} else if (!fdt_node_check_compatible(fdt_addr, of_offset, \"ethernet,qsfp-slot\")) {\n+\t\tis_qsfp = true;\n+\t} else {\n+\t\tdebug(\"%s: Error: incompatible sfp/qsfp slot, compatible=%s\\n\", __func__,\n+\t\t      (char *)fdt_getprop(fdt_addr, of_offset, \"compatible\", NULL));\n+\t\tgoto error_exit;\n+\t}\n+\n+\tdebug(\"%s: %ssfp module found at offset %d\\n\", __func__, is_qsfp ? \"q\" : \"\", of_offset);\n+\tsfp_info = __cvmx_fdt_alloc(sizeof(*sfp_info));\n+\tif (!sfp_info) {\n+\t\tdebug(\"%s: Error: out of memory\\n\", __func__);\n+\t\tgoto error_exit;\n+\t}\n+\tsfp_info->name = fdt_get_name(fdt_addr, of_offset, NULL);\n+\tsfp_info->of_offset = of_offset;\n+\tsfp_info->is_qsfp = is_qsfp;\n+\tsfp_info->last_mod_abs = -1;\n+\tsfp_info->last_rx_los = -1;\n+\n+\tif (is_qsfp)\n+\t\terr = cvmx_parse_qsfp(fdt_addr, of_offset, sfp_info);\n+\telse\n+\t\terr = cvmx_parse_sfp(fdt_addr, of_offset, sfp_info);\n+\tif (err) {\n+\t\tdebug(\"%s: Error in %s parsing %ssfp GPIO info\\n\", __func__, sfp_info->name,\n+\t\t      is_qsfp ? \"q\" : \"\");\n+\t\tgoto error_exit;\n+\t}\n+\tdebug(\"%s: Parsing %ssfp module eeprom\\n\", __func__, is_qsfp ? \"q\" : \"\");\n+\terr = cvmx_parse_sfp_eeprom(fdt_addr, of_offset, sfp_info);\n+\tif (err) {\n+\t\tdebug(\"%s: Error parsing eeprom info for %s\\n\", __func__, sfp_info->name);\n+\t\tgoto error_exit;\n+\t}\n+\n+\t/* Register default check for mod_abs changed */\n+\tif (!err)\n+\t\tcvmx_sfp_register_check_mod_abs(sfp_info, cvmx_sfp_check_mod_abs, NULL);\n+\n+error_exit:\n+\t/* Note: we don't free any data structures on error since it gets\n+\t * rather complicated with i2c buses and whatnot.\n+\t */\n+\treturn err ? NULL : sfp_info;\n+}\n+\n+/**\n+ * @INTERNAL\n+ * Parse a slice of the Inphi/Cortina CS4343 in the device tree\n+ *\n+ * @param[in]\tfdt_addr\tAddress of flat device tree\n+ * @param\tof_offset\tfdt offset of slice\n+ * @param\tphy_info\tphy_info data structure\n+ *\n+ * @return\tslice number if non-negative, otherwise error\n+ */\n+static int cvmx_fdt_parse_cs4343_slice(const void *fdt_addr, int of_offset,\n+\t\t\t\t       struct cvmx_phy_info *phy_info)\n+{\n+\tstruct cvmx_cs4343_slice_info *slice;\n+\tint reg;\n+\tint reg_offset;\n+\n+\treg = cvmx_fdt_get_int(fdt_addr, of_offset, \"reg\", -1);\n+\treg_offset = cvmx_fdt_get_int(fdt_addr, of_offset, \"slice_offset\", -1);\n+\n+\tif (reg < 0 || reg >= 4) {\n+\t\tdebug(\"%s(%p, %d, %p): Error: reg %d undefined or out of range\\n\", __func__,\n+\t\t      fdt_addr, of_offset, phy_info, reg);\n+\t\treturn -1;\n+\t}\n+\tif (reg_offset % 0x1000 || reg_offset > 0x3000 || reg_offset < 0) {\n+\t\tdebug(\"%s(%p, %d, %p): Error: reg_offset 0x%x undefined or out of range\\n\",\n+\t\t      __func__, fdt_addr, of_offset, phy_info, reg_offset);\n+\t\treturn -1;\n+\t}\n+\tif (!phy_info->cs4343_info) {\n+\t\tdebug(\"%s: Error: phy info cs4343 datastructure is NULL\\n\", __func__);\n+\t\treturn -1;\n+\t}\n+\tdebug(\"%s(%p, %d, %p): %s, reg: %d, slice offset: 0x%x\\n\", __func__, fdt_addr, of_offset,\n+\t      phy_info, fdt_get_name(fdt_addr, of_offset, NULL), reg, reg_offset);\n+\tslice = &phy_info->cs4343_info->slice[reg];\n+\tslice->name = fdt_get_name(fdt_addr, of_offset, NULL);\n+\tslice->mphy = phy_info->cs4343_info;\n+\tslice->phy_info = phy_info;\n+\tslice->of_offset = of_offset;\n+\tslice->slice_no = reg;\n+\tslice->reg_offset = reg_offset;\n+\t/* SR settings */\n+\tslice->sr_stx_cmode_res = cvmx_fdt_get_int(fdt_addr, of_offset, \"sr-stx-cmode-res\", 3);\n+\tslice->sr_stx_drv_lower_cm =\n+\t\tcvmx_fdt_get_int(fdt_addr, of_offset, \"sr-stx-drv-lower-cm\", 8);\n+\tslice->sr_stx_level = cvmx_fdt_get_int(fdt_addr, of_offset, \"sr-stx-level\", 0x1c);\n+\tslice->sr_stx_pre_peak = cvmx_fdt_get_int(fdt_addr, of_offset, \"sr-stx-pre-peak\", 1);\n+\tslice->sr_stx_muxsubrate_sel =\n+\t\tcvmx_fdt_get_int(fdt_addr, of_offset, \"sr-stx-muxsubrate-sel\", 0);\n+\tslice->sr_stx_post_peak = cvmx_fdt_get_int(fdt_addr, of_offset, \"sr-stx-post-peak\", 8);\n+\t/* CX settings */\n+\tslice->cx_stx_cmode_res = cvmx_fdt_get_int(fdt_addr, of_offset, \"cx-stx-cmode-res\", 3);\n+\tslice->cx_stx_drv_lower_cm =\n+\t\tcvmx_fdt_get_int(fdt_addr, of_offset, \"cx-stx-drv-lower-cm\", 8);\n+\tslice->cx_stx_level = cvmx_fdt_get_int(fdt_addr, of_offset, \"cx-stx-level\", 0x1c);\n+\tslice->cx_stx_pre_peak = cvmx_fdt_get_int(fdt_addr, of_offset, \"cx-stx-pre-peak\", 1);\n+\tslice->cx_stx_muxsubrate_sel =\n+\t\tcvmx_fdt_get_int(fdt_addr, of_offset, \"cx-stx-muxsubrate-sel\", 0);\n+\tslice->cx_stx_post_peak = cvmx_fdt_get_int(fdt_addr, of_offset, \"cx-stx-post-peak\", 0xC);\n+\t/* 1000Base-X settings */\n+\t/* CX settings */\n+\tslice->basex_stx_cmode_res =\n+\t\tcvmx_fdt_get_int(fdt_addr, of_offset, \"basex-stx-cmode-res\", 3);\n+\tslice->basex_stx_drv_lower_cm =\n+\t\tcvmx_fdt_get_int(fdt_addr, of_offset, \"basex-stx-drv-lower-cm\", 8);\n+\tslice->basex_stx_level = cvmx_fdt_get_int(fdt_addr, of_offset,\n+\t\t\t\t\t\t  \"basex-stx-level\", 0x1c);\n+\tslice->basex_stx_pre_peak = cvmx_fdt_get_int(fdt_addr, of_offset,\n+\t\t\t\t\t\t     \"basex-stx-pre-peak\", 1);\n+\tslice->basex_stx_muxsubrate_sel =\n+\t\tcvmx_fdt_get_int(fdt_addr, of_offset,\n+\t\t\t\t \"basex-stx-muxsubrate-sel\", 0);\n+\tslice->basex_stx_post_peak =\n+\t\tcvmx_fdt_get_int(fdt_addr, of_offset, \"basex-stx-post-peak\", 8);\n+\t/* Get the link LED gpio pin */\n+\tslice->link_gpio = cvmx_fdt_get_int(fdt_addr, of_offset,\n+\t\t\t\t\t    \"link-led-gpio\", -1);\n+\tslice->error_gpio = cvmx_fdt_get_int(fdt_addr, of_offset,\n+\t\t\t\t\t     \"error-led-gpio\", -1);\n+\tslice->los_gpio = cvmx_fdt_get_int(fdt_addr, of_offset,\n+\t\t\t\t\t   \"los-input-gpio\", -1);\n+\tslice->link_inverted = cvmx_fdt_get_bool(fdt_addr, of_offset,\n+\t\t\t\t\t\t \"link-led-gpio-inverted\");\n+\tslice->error_inverted = cvmx_fdt_get_bool(fdt_addr, of_offset,\n+\t\t\t\t\t\t  \"error-led-gpio-inverted\");\n+\tslice->los_inverted = cvmx_fdt_get_bool(fdt_addr, of_offset,\n+\t\t\t\t\t\t\"los-input-gpio-inverted\");\n+\t/* Convert GPIOs to be die based if they're not already */\n+\tif (slice->link_gpio > 4 && slice->link_gpio <= 8)\n+\t\tslice->link_gpio -= 4;\n+\tif (slice->error_gpio > 4 && slice->error_gpio <= 8)\n+\t\tslice->error_gpio -= 4;\n+\tif (slice->los_gpio > 4 && slice->los_gpio <= 8)\n+\t\tslice->los_gpio -= 4;\n+\n+\treturn reg;\n+}\n+\n+/**\n+ * @INTERNAL\n+ * Parses either a CS4343 phy or a slice of the phy from the device tree\n+ * @param[in]\tfdt_addr\tAddress of FDT\n+ * @param\tof_offset\toffset of slice or phy in device tree\n+ * @param\tphy_info\tphy_info data structure to fill in\n+ *\n+ * @return\t0 for success, -1 on error\n+ */\n+int cvmx_fdt_parse_cs4343(const void *fdt_addr, int of_offset, struct cvmx_phy_info *phy_info)\n+{\n+\tint of_slice = -1;\n+\tstruct cvmx_cs4343_info *cs4343;\n+\tint err = -1;\n+\tint reg;\n+\n+\tdebug(\"%s(%p, %d, %p): %s (%s)\\n\", __func__,\n+\t      fdt_addr, of_offset, phy_info,\n+\t      fdt_get_name(fdt_addr, of_offset, NULL),\n+\t      (const char *)fdt_getprop(fdt_addr, of_offset, \"compatible\", NULL));\n+\n+\tif (!phy_info->cs4343_info)\n+\t\tphy_info->cs4343_info = __cvmx_fdt_alloc(sizeof(struct cvmx_cs4343_info));\n+\tif (!phy_info->cs4343_info) {\n+\t\tdebug(\"%s: Error: out of memory!\\n\", __func__);\n+\t\treturn -1;\n+\t}\n+\tcs4343 = phy_info->cs4343_info;\n+\t/* If we're passed to a slice then process only that slice */\n+\tif (!fdt_node_check_compatible(fdt_addr, of_offset, \"cortina,cs4343-slice\")) {\n+\t\terr = 0;\n+\t\tof_slice = of_offset;\n+\t\tof_offset = fdt_parent_offset(fdt_addr, of_offset);\n+\t\treg = cvmx_fdt_parse_cs4343_slice(fdt_addr, of_slice, phy_info);\n+\t\tif (reg >= 0)\n+\t\t\tphy_info->cs4343_slice_info = &cs4343->slice[reg];\n+\t\telse\n+\t\t\terr = reg;\n+\t} else if (!fdt_node_check_compatible(fdt_addr, of_offset,\n+\t\t\t\t\t      \"cortina,cs4343\")) {\n+\t\t/* Walk through and process all of the slices */\n+\t\tof_slice =\n+\t\t\tfdt_node_offset_by_compatible(fdt_addr, of_offset, \"cortina,cs4343-slice\");\n+\t\twhile (of_slice > 0 && fdt_parent_offset(fdt_addr, of_slice) ==\n+\t\t       of_offset) {\n+\t\t\tdebug(\"%s: Parsing slice %s\\n\", __func__,\n+\t\t\t      fdt_get_name(fdt_addr, of_slice, NULL));\n+\t\t\terr = cvmx_fdt_parse_cs4343_slice(fdt_addr, of_slice,\n+\t\t\t\t\t\t\t  phy_info);\n+\t\t\tif (err < 0)\n+\t\t\t\tbreak;\n+\t\t\tof_slice = fdt_node_offset_by_compatible(fdt_addr,\n+\t\t\t\t\t\t\t\t of_slice,\n+\t\t\t\t\t\t\t\t \"cortina,cs4343-slice\");\n+\t\t}\n+\t} else {\n+\t\tdebug(\"%s: Error: unknown compatible string %s for %s\\n\", __func__,\n+\t\t      (const char *)fdt_getprop(fdt_addr, of_offset,\n+\t\t\t\t\t\t\"compatible\", NULL),\n+\t\t      fdt_get_name(fdt_addr, of_offset, NULL));\n+\t}\n+\n+\tif (err >= 0) {\n+\t\tcs4343->name = fdt_get_name(fdt_addr, of_offset, NULL);\n+\t\tcs4343->phy_info = phy_info;\n+\t\tcs4343->of_offset = of_offset;\n+\t}\n+\n+\treturn err < 0 ? -1 : 0;\n+}\n",
    "prefixes": [
        "v1",
        "37/50"
    ]
}