uboot/drivers/net/qe/dm_qe_uec_phy.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * QE UEC ethernet phy controller driver
   4 *
   5 * based on phy parts of drivers/qe/uec.c and drivers/qe/uec_phy.c
   6 * from NXP
   7 *
   8 * Copyright (C) 2020 Heiko Schocher <hs@denx.de>
   9 */
  10
  11#include <common.h>
  12#include <dm.h>
  13#include <errno.h>
  14#include <miiphy.h>
  15#include <phy.h>
  16#include <asm/io.h>
  17#include <linux/ioport.h>
  18
  19#include "dm_qe_uec.h"
  20
  21struct qe_uec_mdio_priv {
  22        struct ucc_mii_mng *base;
  23};
  24
  25static int
  26qe_uec_mdio_read(struct udevice *dev, int addr, int devad, int reg)
  27{
  28        struct qe_uec_mdio_priv *priv = dev_get_priv(dev);
  29        struct ucc_mii_mng *regs = priv->base;
  30        u32 tmp_reg;
  31        u16 value;
  32
  33        debug("%s: regs: %p addr: %x devad: %x reg: %x\n", __func__, regs,
  34              addr, devad, reg);
  35        /* Setting up the MII management Address Register */
  36        tmp_reg = ((u32)addr << MIIMADD_PHY_ADDRESS_SHIFT) | reg;
  37        out_be32(&regs->miimadd, tmp_reg);
  38
  39        /* clear MII management command cycle */
  40        out_be32(&regs->miimcom, 0);
  41        sync();
  42
  43        /* Perform an MII management read cycle */
  44        out_be32(&regs->miimcom, MIIMCOM_READ_CYCLE);
  45
  46        /* Wait till MII management write is complete */
  47        while ((in_be32(&regs->miimind)) &
  48               (MIIMIND_NOT_VALID | MIIMIND_BUSY))
  49                ;
  50
  51        /* Read MII management status  */
  52        value = (u16)in_be32(&regs->miimstat);
  53        if (value == 0xffff)
  54                return -EINVAL;
  55
  56        return value;
  57};
  58
  59static int
  60qe_uec_mdio_write(struct udevice *dev, int addr, int devad, int reg,
  61                  u16 value)
  62{
  63        struct qe_uec_mdio_priv *priv = dev_get_priv(dev);
  64        struct ucc_mii_mng *regs = priv->base;
  65        u32 tmp_reg;
  66
  67        debug("%s: regs: %p addr: %x devad: %x reg: %x val: %x\n", __func__,
  68              regs, addr, devad, reg, value);
  69
  70        /* Stop the MII management read cycle */
  71        out_be32(&regs->miimcom, 0);
  72        /* Setting up the MII management Address Register */
  73        tmp_reg = ((u32)addr << MIIMADD_PHY_ADDRESS_SHIFT) | reg;
  74        out_be32(&regs->miimadd, tmp_reg);
  75
  76        /* Setting up the MII management Control Register with the value */
  77        out_be32(&regs->miimcon, (u32)value);
  78        sync();
  79
  80        /* Wait till MII management write is complete */
  81        while ((in_be32(&regs->miimind)) & MIIMIND_BUSY)
  82                ;
  83
  84        return 0;
  85};
  86
  87static const struct mdio_ops qe_uec_mdio_ops = {
  88        .read = qe_uec_mdio_read,
  89        .write = qe_uec_mdio_write,
  90};
  91
  92static int qe_uec_mdio_probe(struct udevice *dev)
  93{
  94        struct qe_uec_mdio_priv *priv = dev_get_priv(dev);
  95        fdt_size_t base;
  96        ofnode node;
  97        u32 num = 0;
  98        int ret = -ENODEV;
  99
 100        priv->base = (struct ucc_mii_mng *)dev_read_addr(dev);
 101        base = (fdt_size_t)priv->base;
 102
 103        /*
 104         * idea from linux:
 105         * drivers/net/ethernet/freescale/fsl_pq_mdio.c
 106         *
 107         * Find the UCC node that controls the given MDIO node
 108         *
 109         * For some reason, the QE MDIO nodes are not children of the UCC
 110         * devices that control them.  Therefore, we need to scan all UCC
 111         * nodes looking for the one that encompases the given MDIO node.
 112         * We do this by comparing physical addresses.  The 'start' and
 113         * 'end' addresses of the MDIO node are passed, and the correct
 114         * UCC node will cover the entire address range.
 115         */
 116        node = ofnode_by_compatible(ofnode_null(), "ucc_geth");
 117        while (ofnode_valid(node)) {
 118                fdt_size_t size;
 119                fdt_addr_t addr;
 120
 121                addr = ofnode_get_addr_index(node, 0);
 122                ret = ofnode_get_addr_size_index(node, 0, &size);
 123
 124                if (addr == FDT_ADDR_T_NONE) {
 125                        node = ofnode_by_compatible(node, "ucc_geth");
 126                        continue;
 127                }
 128
 129                /* check if priv->base in start end */
 130                if (base > addr && base < (addr + size)) {
 131                        ret = ofnode_read_u32(node, "cell-index", &num);
 132                        if (ret)
 133                                ret = ofnode_read_u32(node, "device-id",
 134                                                      &num);
 135                        break;
 136                }
 137                node = ofnode_by_compatible(node, "ucc_geth");
 138        }
 139
 140        if (ret) {
 141                printf("%s: no cell-index nor device-id found!", __func__);
 142                return ret;
 143        }
 144
 145        /* Setup MII master clock source */
 146        qe_set_mii_clk_src(num - 1);
 147
 148        return 0;
 149}
 150
 151static const struct udevice_id qe_uec_mdio_ids[] = {
 152        { .compatible = "fsl,ucc-mdio" },
 153        { }
 154};
 155
 156U_BOOT_DRIVER(mvmdio) = {
 157        .name                   = "qe_uec_mdio",
 158        .id                     = UCLASS_MDIO,
 159        .of_match               = qe_uec_mdio_ids,
 160        .probe                  = qe_uec_mdio_probe,
 161        .ops                    = &qe_uec_mdio_ops,
 162        .priv_auto      = sizeof(struct qe_uec_mdio_priv),
 163};
 164