150dcf89dSDirk Eibach /*
250dcf89dSDirk Eibach * (C) Copyright 2014
350dcf89dSDirk Eibach * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de
450dcf89dSDirk Eibach *
550dcf89dSDirk Eibach * SPDX-License-Identifier: GPL-2.0+
650dcf89dSDirk Eibach */
750dcf89dSDirk Eibach
850dcf89dSDirk Eibach #include <common.h>
950dcf89dSDirk Eibach
1050dcf89dSDirk Eibach #include <gdsys_fpga.h>
1150dcf89dSDirk Eibach #include <miiphy.h>
1250dcf89dSDirk Eibach
1350dcf89dSDirk Eibach #include "ihs_mdio.h"
1450dcf89dSDirk Eibach
ihs_mdio_idle(struct mii_dev * bus)1550dcf89dSDirk Eibach static int ihs_mdio_idle(struct mii_dev *bus)
1650dcf89dSDirk Eibach {
1750dcf89dSDirk Eibach struct ihs_mdio_info *info = bus->priv;
1850dcf89dSDirk Eibach u16 val;
1950dcf89dSDirk Eibach unsigned int ctr = 0;
2050dcf89dSDirk Eibach
2150dcf89dSDirk Eibach do {
2250dcf89dSDirk Eibach FPGA_GET_REG(info->fpga, mdio.control, &val);
2350dcf89dSDirk Eibach udelay(100);
2450dcf89dSDirk Eibach if (ctr++ > 10)
2550dcf89dSDirk Eibach return -1;
2650dcf89dSDirk Eibach } while (!(val & (1 << 12)));
2750dcf89dSDirk Eibach
2850dcf89dSDirk Eibach return 0;
2950dcf89dSDirk Eibach }
3050dcf89dSDirk Eibach
ihs_mdio_reset(struct mii_dev * bus)3150dcf89dSDirk Eibach static int ihs_mdio_reset(struct mii_dev *bus)
3250dcf89dSDirk Eibach {
3350dcf89dSDirk Eibach ihs_mdio_idle(bus);
3450dcf89dSDirk Eibach
3550dcf89dSDirk Eibach return 0;
3650dcf89dSDirk Eibach }
3750dcf89dSDirk Eibach
ihs_mdio_read(struct mii_dev * bus,int addr,int dev_addr,int regnum)3850dcf89dSDirk Eibach static int ihs_mdio_read(struct mii_dev *bus, int addr, int dev_addr,
3950dcf89dSDirk Eibach int regnum)
4050dcf89dSDirk Eibach {
4150dcf89dSDirk Eibach struct ihs_mdio_info *info = bus->priv;
4250dcf89dSDirk Eibach u16 val;
4350dcf89dSDirk Eibach
4450dcf89dSDirk Eibach ihs_mdio_idle(bus);
4550dcf89dSDirk Eibach
4650dcf89dSDirk Eibach FPGA_SET_REG(info->fpga, mdio.control,
4750dcf89dSDirk Eibach ((addr & 0x1f) << 5) | (regnum & 0x1f) | (2 << 10));
4850dcf89dSDirk Eibach
4950dcf89dSDirk Eibach /* wait for rx data available */
5050dcf89dSDirk Eibach udelay(100);
5150dcf89dSDirk Eibach
5250dcf89dSDirk Eibach FPGA_GET_REG(info->fpga, mdio.rx_data, &val);
5350dcf89dSDirk Eibach
5450dcf89dSDirk Eibach return val;
5550dcf89dSDirk Eibach }
5650dcf89dSDirk Eibach
ihs_mdio_write(struct mii_dev * bus,int addr,int dev_addr,int regnum,u16 value)5750dcf89dSDirk Eibach static int ihs_mdio_write(struct mii_dev *bus, int addr, int dev_addr,
5850dcf89dSDirk Eibach int regnum, u16 value)
5950dcf89dSDirk Eibach {
6050dcf89dSDirk Eibach struct ihs_mdio_info *info = bus->priv;
6150dcf89dSDirk Eibach
6250dcf89dSDirk Eibach ihs_mdio_idle(bus);
6350dcf89dSDirk Eibach
6450dcf89dSDirk Eibach FPGA_SET_REG(info->fpga, mdio.address_data, value);
6550dcf89dSDirk Eibach FPGA_SET_REG(info->fpga, mdio.control,
6650dcf89dSDirk Eibach ((addr & 0x1f) << 5) | (regnum & 0x1f) | (1 << 10));
6750dcf89dSDirk Eibach
6850dcf89dSDirk Eibach return 0;
6950dcf89dSDirk Eibach }
7050dcf89dSDirk Eibach
ihs_mdio_init(struct ihs_mdio_info * info)7150dcf89dSDirk Eibach int ihs_mdio_init(struct ihs_mdio_info *info)
7250dcf89dSDirk Eibach {
7350dcf89dSDirk Eibach struct mii_dev *bus = mdio_alloc();
7450dcf89dSDirk Eibach
7550dcf89dSDirk Eibach if (!bus) {
7650dcf89dSDirk Eibach printf("Failed to allocate FSL MDIO bus\n");
7750dcf89dSDirk Eibach return -1;
7850dcf89dSDirk Eibach }
7950dcf89dSDirk Eibach
8050dcf89dSDirk Eibach bus->read = ihs_mdio_read;
8150dcf89dSDirk Eibach bus->write = ihs_mdio_write;
8250dcf89dSDirk Eibach bus->reset = ihs_mdio_reset;
83*192bc694SBen Whitten strcpy(bus->name, info->name);
8450dcf89dSDirk Eibach
8550dcf89dSDirk Eibach bus->priv = info;
8650dcf89dSDirk Eibach
8750dcf89dSDirk Eibach return mdio_register(bus);
8850dcf89dSDirk Eibach }
89