1/* 2 * @TAG(OTHER_GPL) 3 */ 4 5/* 6 * (C) Copyright 2009 Ilya Yanok, Emcraft Systems Ltd <yanok@emcraft.com> 7 * (C) Copyright 2008,2009 Eric Jarrige <eric.jarrige@armadeus.org> 8 * (C) Copyright 2008 Armadeus Systems nc 9 * (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> 10 * (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de> 11 * (C) Copyright 2018, NXP 12 * 13 * This program is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU General Public License as 15 * published by the Free Software Foundation; either version 2 of 16 * the License, or (at your option) any later version. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, write to the Free Software 25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 26 * MA 02111-1307 USA 27 */ 28 29#include "common.h" 30#include "miiphy.h" 31#include "fec_mxc.h" 32 33#include "imx-regs.h" 34#include "../io.h" 35 36#include "micrel.h" 37#include <errno.h> 38#include <stdlib.h> 39#include <string.h> 40#include "../enet.h" 41#include "../ocotp_ctrl.h" 42/* 43 * Timeout the transfer after 5 mS. This is usually a bit more, since 44 * the code in the tightloops this timeout is used in adds some overhead. 45 */ 46#define FEC_XFER_TIMEOUT 5000 47 48#ifndef CONFIG_MII 49#error "CONFIG_MII has to be defined!" 50#endif 51 52#ifndef CONFIG_FEC_XCV_TYPE 53#define CONFIG_FEC_XCV_TYPE MII100 54#endif 55 56#undef DEBUG 57 58int fec_phy_read(struct mii_dev *bus, int phyAddr, int dev_addr, int regAddr) 59{ 60 return enet_mdio_read((struct enet *)bus->priv, phyAddr, regAddr); 61} 62 63int fec_phy_write(struct mii_dev *bus, int phyAddr, int dev_addr, int regAddr, 64 uint16_t data) 65{ 66 return enet_mdio_write((struct enet *)bus->priv, phyAddr, regAddr, data); 67} 68 69/** 70 * Halt the FEC engine 71 * @param[in] dev Our device to handle 72 */ 73void fec_halt(struct eth_device *dev) 74{ 75#if 0 76 struct fec_priv *fec = (struct fec_priv *)dev->priv; 77 int counter = 0xffff; 78 /* issue graceful stop command to the FEC transmitter if necessary */ 79 writel(FEC_TCNTRL_GTS | readl(&fec->eth->x_cntrl), &fec->eth->x_cntrl); 80 /* wait for graceful stop to register */ 81 while ((counter--) && (!(readl(&fec->eth->ievent) & FEC_IEVENT_GRA))) { 82 udelay(1); 83 } 84 writel(readl(&fec->eth->ecntrl) & ~FEC_ECNTRL_ETHER_EN, &fec->eth->ecntrl); 85 fec->rbd_index = 0; 86 fec->tbd_index = 0; 87#else 88 assert(!"unimplemented"); 89#endif 90} 91int fec_init(unsigned phy_mask, struct enet *enet) 92{ 93 struct eth_device *edev; 94 struct phy_device *phydev; 95 struct mii_dev *bus; 96 int ret = 0; 97 struct eth_device _eth; 98 /* create and fill edev struct */ 99 edev = &_eth; 100 memset(edev, 0, sizeof(*edev)); 101 102 edev->priv = (void *)enet; 103 edev->write_hwaddr = NULL; 104 105 /* Alocate the mdio bus */ 106 bus = mdio_alloc(); 107 if (!bus) { 108 return -1; 109 } 110 bus->read = fec_phy_read; 111 bus->write = fec_phy_write; 112 bus->priv = enet; 113 strcpy(bus->name, edev->name); 114 ret = mdio_register(bus); 115 if (ret) { 116 free(bus); 117 return -1; 118 } 119 120 /****** Configure phy ******/ 121 phydev = phy_connect_by_mask(bus, phy_mask, edev, PHY_INTERFACE_MODE_RGMII); 122 if (!phydev) { 123 return -1; 124 } 125 126 if (config_set(CONFIG_PLAT_IMX8MQ_EVK)) { 127 /* enable rgmii rxc skew and phy mode select to RGMII copper */ 128 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f); 129 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x8); 130 phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05); 131 phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); 132 133 if (phydev->drv->config) { 134 phydev->drv->config(phydev); 135 } 136 137 if (phydev->drv->startup) { 138 phydev->drv->startup(phydev); 139 } 140 } else if (config_set(CONFIG_PLAT_IMX6)) { 141 /* min rx data delay */ 142 ksz9021_phy_extended_write(phydev, MII_KSZ9021_EXT_RGMII_RX_DATA_SKEW, 0x0); 143 /* min tx data delay */ 144 ksz9021_phy_extended_write(phydev, MII_KSZ9021_EXT_RGMII_TX_DATA_SKEW, 0x0); 145 /* max rx/tx clock delay, min rx/tx control */ 146 ksz9021_phy_extended_write(phydev, MII_KSZ9021_EXT_RGMII_CLOCK_SKEW, 0xf0f0); 147 ksz9021_config(phydev); 148 149 /* Start up the PHY */ 150 ret = ksz9021_startup(phydev); 151 if (ret) { 152 printf("Could not initialize PHY %s\n", phydev->dev->name); 153 return ret; 154 } 155 156 } 157 158 printf("\n * Link speed: %4i Mbps, ", phydev->speed); 159 if (phydev->duplex == DUPLEX_FULL) { 160 enet_set_speed(enet, phydev->speed, 1); 161 printf("full-duplex *\n"); 162 } else { 163 enet_set_speed(enet, phydev->speed, 0); 164 printf("half-duplex *\n"); 165 } 166 167 udelay(100000); 168 return 0; 169} 170