summaryrefslogtreecommitdiff
path: root/drivers/net/qe/dm_qe_uec_phy.c
diff options
context:
space:
mode:
authorHeiko Schocher <hs@denx.de>2020-02-06 11:48:16 +0300
committerHeiko Schocher <hs@denx.de>2020-09-17 07:09:53 +0300
commit6e31c62a175ca24f74b89a684c82cbb4bf423f16 (patch)
tree4f131f11de72bf8bc982c553a134c0b561614beb /drivers/net/qe/dm_qe_uec_phy.c
parent5990b059516c233bf845ad510decd6a44ba9864b (diff)
downloadu-boot-6e31c62a175ca24f74b89a684c82cbb4bf423f16.tar.xz
net, qe: add DM support for QE UEC ethernet
add DM/DTS support for the UEC ethernet on QUICC Engine Block. Signed-off-by: Heiko Schocher <hs@denx.de> Patch-cc: Mario Six <mario.six@gdsys.cc> Patch-cc: Qiang Zhao <qiang.zhao@nxp.com> Patch-cc: Holger Brunck <holger.brunck@hitachi-powergrids.com> Patch-cc: Madalin Bucur <madalin.bucur@oss.nxp.com> Series-changes: 3 - revert: commit "3374264df97b" ("drivers: net: qe: deselect QE when DM_ETH is enabled") as now qe works with DM and DM_ETH support. - fix mailaddress from Holger Series-changes: 2 - add comments from Qiang Zhao: - add device node documentation - I did not drop the dm_qe_uec_phy.c and use drivers/net/fsl_mdio.c because using drivers/net/fsl_mdio.c leads in none existent udevice mdio@3320 instead boards with DM ETH support should use now this driver. - remove RFC tag Commit-notes: - I let the old none DM based implementation in code so boards should work with old implementation. This Code should be removed if all boards are converted to DM/DTS. - add the DM based qe uec driver under drivers/net/qe - Therefore copied the files uccf.c uccf.h uec.h from drivers/qe. So there are a lot of Codingstyle problems currently. I fix them in next version if this RFC patch is OK or it needs some changes. - The dm based driver code is now under drivers/net/qe/dm_qe_uec.c Used a lot of functions from drivers/qe/uec.c - seperated the PHY specific code into seperate file drivers/net/qe/dm_qe_uec_phy.c END
Diffstat (limited to 'drivers/net/qe/dm_qe_uec_phy.c')
-rw-r--r--drivers/net/qe/dm_qe_uec_phy.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/drivers/net/qe/dm_qe_uec_phy.c b/drivers/net/qe/dm_qe_uec_phy.c
new file mode 100644
index 0000000000..02ce08edad
--- /dev/null
+++ b/drivers/net/qe/dm_qe_uec_phy.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * QE UEC ethernet phy controller driver
+ *
+ * based on phy parts of drivers/qe/uec.c and drivers/qe/uec_phy.c
+ * from NXP
+ *
+ * Copyright (C) 2020 Heiko Schocher <hs@denx.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <miiphy.h>
+#include <phy.h>
+#include <asm/io.h>
+#include <linux/ioport.h>
+
+#include "dm_qe_uec.h"
+
+struct qe_uec_mdio_priv {
+ struct ucc_mii_mng *base;
+};
+
+static int
+qe_uec_mdio_read(struct udevice *dev, int addr, int devad, int reg)
+{
+ struct qe_uec_mdio_priv *priv = dev_get_priv(dev);
+ struct ucc_mii_mng *regs = priv->base;
+ u32 tmp_reg;
+ u16 value;
+
+ debug("%s: regs: %p addr: %x devad: %x reg: %x\n", __func__, regs,
+ addr, devad, reg);
+ /* Setting up the MII management Address Register */
+ tmp_reg = ((u32)addr << MIIMADD_PHY_ADDRESS_SHIFT) | reg;
+ out_be32(&regs->miimadd, tmp_reg);
+
+ /* clear MII management command cycle */
+ out_be32(&regs->miimcom, 0);
+ sync();
+
+ /* Perform an MII management read cycle */
+ out_be32(&regs->miimcom, MIIMCOM_READ_CYCLE);
+
+ /* Wait till MII management write is complete */
+ while ((in_be32(&regs->miimind)) &
+ (MIIMIND_NOT_VALID | MIIMIND_BUSY))
+ ;
+
+ /* Read MII management status */
+ value = (u16)in_be32(&regs->miimstat);
+ if (value == 0xffff)
+ return -EINVAL;
+
+ return value;
+};
+
+static int
+qe_uec_mdio_write(struct udevice *dev, int addr, int devad, int reg,
+ u16 value)
+{
+ struct qe_uec_mdio_priv *priv = dev_get_priv(dev);
+ struct ucc_mii_mng *regs = priv->base;
+ u32 tmp_reg;
+
+ debug("%s: regs: %p addr: %x devad: %x reg: %x val: %x\n", __func__,
+ regs, addr, devad, reg, value);
+
+ /* Stop the MII management read cycle */
+ out_be32(&regs->miimcom, 0);
+ /* Setting up the MII management Address Register */
+ tmp_reg = ((u32)addr << MIIMADD_PHY_ADDRESS_SHIFT) | reg;
+ out_be32(&regs->miimadd, tmp_reg);
+
+ /* Setting up the MII management Control Register with the value */
+ out_be32(&regs->miimcon, (u32)value);
+ sync();
+
+ /* Wait till MII management write is complete */
+ while ((in_be32(&regs->miimind)) & MIIMIND_BUSY)
+ ;
+
+ return 0;
+};
+
+static const struct mdio_ops qe_uec_mdio_ops = {
+ .read = qe_uec_mdio_read,
+ .write = qe_uec_mdio_write,
+};
+
+static int qe_uec_mdio_probe(struct udevice *dev)
+{
+ struct qe_uec_mdio_priv *priv = dev_get_priv(dev);
+ fdt_size_t base;
+ ofnode node;
+ u32 num = 0;
+ int ret = -ENODEV;
+
+ priv->base = (struct ucc_mii_mng *)dev_read_addr(dev);
+ base = (fdt_size_t)priv->base;
+
+ /*
+ * idea from linux:
+ * drivers/net/ethernet/freescale/fsl_pq_mdio.c
+ *
+ * Find the UCC node that controls the given MDIO node
+ *
+ * For some reason, the QE MDIO nodes are not children of the UCC
+ * devices that control them. Therefore, we need to scan all UCC
+ * nodes looking for the one that encompases the given MDIO node.
+ * We do this by comparing physical addresses. The 'start' and
+ * 'end' addresses of the MDIO node are passed, and the correct
+ * UCC node will cover the entire address range.
+ */
+ node = ofnode_by_compatible(ofnode_null(), "ucc_geth");
+ while (ofnode_valid(node)) {
+ fdt_size_t size;
+ fdt_addr_t addr;
+
+ addr = ofnode_get_addr_index(node, 0);
+ ret = ofnode_get_addr_size_index(node, 0, &size);
+
+ if (addr == FDT_ADDR_T_NONE) {
+ node = ofnode_by_compatible(node, "ucc_geth");
+ continue;
+ }
+
+ /* check if priv->base in start end */
+ if (base > addr && base < (addr + size)) {
+ ret = ofnode_read_u32(node, "cell-index", &num);
+ if (ret)
+ ret = ofnode_read_u32(node, "device-id",
+ &num);
+ break;
+ }
+ node = ofnode_by_compatible(node, "ucc_geth");
+ }
+
+ if (ret) {
+ printf("%s: no cell-index nor device-id found!", __func__);
+ return ret;
+ }
+
+ /* Setup MII master clock source */
+ qe_set_mii_clk_src(num - 1);
+
+ return 0;
+}
+
+static const struct udevice_id qe_uec_mdio_ids[] = {
+ { .compatible = "fsl,ucc-mdio" },
+ { }
+};
+
+U_BOOT_DRIVER(mvmdio) = {
+ .name = "qe_uec_mdio",
+ .id = UCLASS_MDIO,
+ .of_match = qe_uec_mdio_ids,
+ .probe = qe_uec_mdio_probe,
+ .ops = &qe_uec_mdio_ops,
+ .priv_auto_alloc_size = sizeof(struct qe_uec_mdio_priv),
+};