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