xref: /rk3399_rockchip-uboot/board/gdsys/common/ihs_mdio.c (revision 192bc6948b02ff4168cab16162fffb507946dc2b)
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