diff options
author | Heiko Schocher <hs@denx.de> | 2020-02-06 11:48:16 +0300 |
---|---|---|
committer | Heiko Schocher <hs@denx.de> | 2020-09-17 07:09:53 +0300 |
commit | 6e31c62a175ca24f74b89a684c82cbb4bf423f16 (patch) | |
tree | 4f131f11de72bf8bc982c553a134c0b561614beb /drivers/net/qe/dm_qe_uec_phy.c | |
parent | 5990b059516c233bf845ad510decd6a44ba9864b (diff) | |
download | u-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.c | 163 |
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(®s->miimadd, tmp_reg); + + /* clear MII management command cycle */ + out_be32(®s->miimcom, 0); + sync(); + + /* Perform an MII management read cycle */ + out_be32(®s->miimcom, MIIMCOM_READ_CYCLE); + + /* Wait till MII management write is complete */ + while ((in_be32(®s->miimind)) & + (MIIMIND_NOT_VALID | MIIMIND_BUSY)) + ; + + /* Read MII management status */ + value = (u16)in_be32(®s->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(®s->miimcom, 0); + /* Setting up the MII management Address Register */ + tmp_reg = ((u32)addr << MIIMADD_PHY_ADDRESS_SHIFT) | reg; + out_be32(®s->miimadd, tmp_reg); + + /* Setting up the MII management Control Register with the value */ + out_be32(®s->miimcon, (u32)value); + sync(); + + /* Wait till MII management write is complete */ + while ((in_be32(®s->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), +}; |