1*50dcf89dSDirk Eibach /* 2*50dcf89dSDirk Eibach * (C) Copyright 2014 3*50dcf89dSDirk Eibach * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de 4*50dcf89dSDirk Eibach * 5*50dcf89dSDirk Eibach * SPDX-License-Identifier: GPL-2.0+ 6*50dcf89dSDirk Eibach */ 7*50dcf89dSDirk Eibach 8*50dcf89dSDirk Eibach #include <common.h> 9*50dcf89dSDirk Eibach 10*50dcf89dSDirk Eibach #include <gdsys_fpga.h> 11*50dcf89dSDirk Eibach #include <miiphy.h> 12*50dcf89dSDirk Eibach 13*50dcf89dSDirk Eibach #include "ihs_mdio.h" 14*50dcf89dSDirk Eibach 15*50dcf89dSDirk Eibach static int ihs_mdio_idle(struct mii_dev *bus) 16*50dcf89dSDirk Eibach { 17*50dcf89dSDirk Eibach struct ihs_mdio_info *info = bus->priv; 18*50dcf89dSDirk Eibach u16 val; 19*50dcf89dSDirk Eibach unsigned int ctr = 0; 20*50dcf89dSDirk Eibach 21*50dcf89dSDirk Eibach do { 22*50dcf89dSDirk Eibach FPGA_GET_REG(info->fpga, mdio.control, &val); 23*50dcf89dSDirk Eibach udelay(100); 24*50dcf89dSDirk Eibach if (ctr++ > 10) 25*50dcf89dSDirk Eibach return -1; 26*50dcf89dSDirk Eibach } while (!(val & (1 << 12))); 27*50dcf89dSDirk Eibach 28*50dcf89dSDirk Eibach return 0; 29*50dcf89dSDirk Eibach } 30*50dcf89dSDirk Eibach 31*50dcf89dSDirk Eibach static int ihs_mdio_reset(struct mii_dev *bus) 32*50dcf89dSDirk Eibach { 33*50dcf89dSDirk Eibach ihs_mdio_idle(bus); 34*50dcf89dSDirk Eibach 35*50dcf89dSDirk Eibach return 0; 36*50dcf89dSDirk Eibach } 37*50dcf89dSDirk Eibach 38*50dcf89dSDirk Eibach static int ihs_mdio_read(struct mii_dev *bus, int addr, int dev_addr, 39*50dcf89dSDirk Eibach int regnum) 40*50dcf89dSDirk Eibach { 41*50dcf89dSDirk Eibach struct ihs_mdio_info *info = bus->priv; 42*50dcf89dSDirk Eibach u16 val; 43*50dcf89dSDirk Eibach 44*50dcf89dSDirk Eibach ihs_mdio_idle(bus); 45*50dcf89dSDirk Eibach 46*50dcf89dSDirk Eibach FPGA_SET_REG(info->fpga, mdio.control, 47*50dcf89dSDirk Eibach ((addr & 0x1f) << 5) | (regnum & 0x1f) | (2 << 10)); 48*50dcf89dSDirk Eibach 49*50dcf89dSDirk Eibach /* wait for rx data available */ 50*50dcf89dSDirk Eibach udelay(100); 51*50dcf89dSDirk Eibach 52*50dcf89dSDirk Eibach FPGA_GET_REG(info->fpga, mdio.rx_data, &val); 53*50dcf89dSDirk Eibach 54*50dcf89dSDirk Eibach return val; 55*50dcf89dSDirk Eibach } 56*50dcf89dSDirk Eibach 57*50dcf89dSDirk Eibach static int ihs_mdio_write(struct mii_dev *bus, int addr, int dev_addr, 58*50dcf89dSDirk Eibach int regnum, u16 value) 59*50dcf89dSDirk Eibach { 60*50dcf89dSDirk Eibach struct ihs_mdio_info *info = bus->priv; 61*50dcf89dSDirk Eibach 62*50dcf89dSDirk Eibach ihs_mdio_idle(bus); 63*50dcf89dSDirk Eibach 64*50dcf89dSDirk Eibach FPGA_SET_REG(info->fpga, mdio.address_data, value); 65*50dcf89dSDirk Eibach FPGA_SET_REG(info->fpga, mdio.control, 66*50dcf89dSDirk Eibach ((addr & 0x1f) << 5) | (regnum & 0x1f) | (1 << 10)); 67*50dcf89dSDirk Eibach 68*50dcf89dSDirk Eibach return 0; 69*50dcf89dSDirk Eibach } 70*50dcf89dSDirk Eibach 71*50dcf89dSDirk Eibach int ihs_mdio_init(struct ihs_mdio_info *info) 72*50dcf89dSDirk Eibach { 73*50dcf89dSDirk Eibach struct mii_dev *bus = mdio_alloc(); 74*50dcf89dSDirk Eibach 75*50dcf89dSDirk Eibach if (!bus) { 76*50dcf89dSDirk Eibach printf("Failed to allocate FSL MDIO bus\n"); 77*50dcf89dSDirk Eibach return -1; 78*50dcf89dSDirk Eibach } 79*50dcf89dSDirk Eibach 80*50dcf89dSDirk Eibach bus->read = ihs_mdio_read; 81*50dcf89dSDirk Eibach bus->write = ihs_mdio_write; 82*50dcf89dSDirk Eibach bus->reset = ihs_mdio_reset; 83*50dcf89dSDirk Eibach sprintf(bus->name, info->name); 84*50dcf89dSDirk Eibach 85*50dcf89dSDirk Eibach bus->priv = info; 86*50dcf89dSDirk Eibach 87*50dcf89dSDirk Eibach return mdio_register(bus); 88*50dcf89dSDirk Eibach } 89