xref: /OK3568_Linux_fs/u-boot/drivers/net/xilinx_ll_temac_mdio.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Xilinx xps_ll_temac ethernet driver for u-boot
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * MDIO bus access
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
7*4882a593Smuzhiyun  * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
8*4882a593Smuzhiyun  * Copyright (C) 2008 - 2011 PetaLogix
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
11*4882a593Smuzhiyun  * Copyright (C) 2008 Nissin Systems Co.,Ltd.
12*4882a593Smuzhiyun  * March 2008 created
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * CREDITS: tsec driver
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  * [0]: http://www.xilinx.com/support/documentation
19*4882a593Smuzhiyun  *
20*4882a593Smuzhiyun  * [S]:	[0]/ip_documentation/xps_ll_temac.pdf
21*4882a593Smuzhiyun  * [A]:	[0]/application_notes/xapp1041.pdf
22*4882a593Smuzhiyun  */
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #include <config.h>
25*4882a593Smuzhiyun #include <common.h>
26*4882a593Smuzhiyun #include <miiphy.h>
27*4882a593Smuzhiyun #include <phy.h>
28*4882a593Smuzhiyun #include <malloc.h>
29*4882a593Smuzhiyun #include <asm/io.h>
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #include "xilinx_ll_temac.h"
32*4882a593Smuzhiyun #include "xilinx_ll_temac_mdio.h"
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #if !defined(CONFIG_MII)
35*4882a593Smuzhiyun # error "LL_TEMAC requires MII -- missing CONFIG_MII"
36*4882a593Smuzhiyun #endif
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #if !defined(CONFIG_PHYLIB)
39*4882a593Smuzhiyun # error "LL_TEMAC requires PHYLIB -- missing CONFIG_PHYLIB"
40*4882a593Smuzhiyun #endif
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun /*
43*4882a593Smuzhiyun  * Prior to PHY access, the MDIO clock must be setup. This driver will set a
44*4882a593Smuzhiyun  * safe default that should work with PLB bus speeds of up to 150 MHz and keep
45*4882a593Smuzhiyun  * the MDIO clock below 2.5 MHz. If the user wishes faster access to the PHY
46*4882a593Smuzhiyun  * then the clock divisor can be set to a different value by setting the
47*4882a593Smuzhiyun  * correct bus speed value with CONFIG_XILINX_LL_TEMAC_CLK.
48*4882a593Smuzhiyun  */
49*4882a593Smuzhiyun #if !defined(CONFIG_XILINX_LL_TEMAC_CLK)
50*4882a593Smuzhiyun #define MDIO_CLOCK_DIV		MC_CLKDIV_10(150000000)
51*4882a593Smuzhiyun #else
52*4882a593Smuzhiyun #define MDIO_CLOCK_DIV		MC_CLKDIV_25(CONFIG_XILINX_LL_TEMAC_CLK)
53*4882a593Smuzhiyun #endif
54*4882a593Smuzhiyun 
ll_temac_mdio_setup(struct mii_dev * bus)55*4882a593Smuzhiyun static int ll_temac_mdio_setup(struct mii_dev *bus)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	struct temac_reg *regs = (struct temac_reg *)bus->priv;
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	/* setup MDIO clock */
60*4882a593Smuzhiyun 	ll_temac_indirect_set(regs, TEMAC_MC,
61*4882a593Smuzhiyun 			MC_MDIOEN | (MDIO_CLOCK_DIV & MC_CLKDIV_MASK));
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	return 0;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun /*
67*4882a593Smuzhiyun  * Indirect MII PHY read via ll_temac.
68*4882a593Smuzhiyun  *
69*4882a593Smuzhiyun  * http://www.xilinx.com/support/documentation/ip_documentation/xps_ll_temac.pdf
70*4882a593Smuzhiyun  * page 67, Using the MII Management to Access PHY Registers
71*4882a593Smuzhiyun  */
ll_temac_local_mdio_read(struct temac_reg * regs,int addr,int devad,int regnum)72*4882a593Smuzhiyun int ll_temac_local_mdio_read(struct temac_reg *regs, int addr, int devad,
73*4882a593Smuzhiyun 				int regnum)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	out_be32(&regs->lsw,
76*4882a593Smuzhiyun 		((addr << LSW_PHYAD_POS) & LSW_PHYAD_MASK) |
77*4882a593Smuzhiyun 		(regnum & LSW_REGAD_MASK));
78*4882a593Smuzhiyun 	out_be32(&regs->ctl, TEMAC_MIIMAI);
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	ll_temac_check_status(regs, RSE_MIIM_RR);
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	return in_be32(&regs->lsw) & LSW_REGDAT_MASK;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun /*
86*4882a593Smuzhiyun  * Indirect MII PHY write via ll_temac.
87*4882a593Smuzhiyun  *
88*4882a593Smuzhiyun  * http://www.xilinx.com/support/documentation/ip_documentation/xps_ll_temac.pdf
89*4882a593Smuzhiyun  * page 67, Using the MII Management to Access PHY Registers
90*4882a593Smuzhiyun  */
ll_temac_local_mdio_write(struct temac_reg * regs,int addr,int devad,int regnum,u16 value)91*4882a593Smuzhiyun void ll_temac_local_mdio_write(struct temac_reg *regs, int addr, int devad,
92*4882a593Smuzhiyun 				int regnum, u16 value)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	out_be32(&regs->lsw, (value & LSW_REGDAT_MASK));
95*4882a593Smuzhiyun 	out_be32(&regs->ctl, CTL_WEN | TEMAC_MIIMWD);
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	out_be32(&regs->lsw,
98*4882a593Smuzhiyun 		((addr << LSW_PHYAD_POS) & LSW_PHYAD_MASK) |
99*4882a593Smuzhiyun 		(regnum & LSW_REGAD_MASK));
100*4882a593Smuzhiyun 	out_be32(&regs->ctl, CTL_WEN | TEMAC_MIIMAI);
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	ll_temac_check_status(regs, RSE_MIIM_WR);
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
ll_temac_phy_read(struct mii_dev * bus,int addr,int devad,int regnum)105*4882a593Smuzhiyun int ll_temac_phy_read(struct mii_dev *bus, int addr, int devad, int regnum)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	struct temac_reg *regs = (struct temac_reg *)bus->priv;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	return ll_temac_local_mdio_read(regs, addr, devad, regnum);
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
ll_temac_phy_write(struct mii_dev * bus,int addr,int devad,int regnum,u16 value)112*4882a593Smuzhiyun int ll_temac_phy_write(struct mii_dev *bus, int addr, int devad, int regnum,
113*4882a593Smuzhiyun 			u16 value)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	struct temac_reg *regs = (struct temac_reg *)bus->priv;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	ll_temac_local_mdio_write(regs, addr, devad, regnum, value);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	return 0;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun /*
123*4882a593Smuzhiyun  * Use MII register 1 (MII status register) to detect PHY
124*4882a593Smuzhiyun  *
125*4882a593Smuzhiyun  * A Mask used to verify certain PHY features (register content)
126*4882a593Smuzhiyun  * in the PHY detection register:
127*4882a593Smuzhiyun  *  Auto-negotiation support, 10Mbps half/full duplex support
128*4882a593Smuzhiyun  */
129*4882a593Smuzhiyun #define PHY_DETECT_REG		MII_BMSR
130*4882a593Smuzhiyun #define PHY_DETECT_MASK		(BMSR_10FULL | BMSR_10HALF | BMSR_ANEGCAPABLE)
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun /* Looking for a valid PHY address */
ll_temac_phy_addr(struct mii_dev * bus)133*4882a593Smuzhiyun int ll_temac_phy_addr(struct mii_dev *bus)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun 	struct temac_reg *regs = (struct temac_reg *)bus->priv;
136*4882a593Smuzhiyun 	unsigned short val;
137*4882a593Smuzhiyun 	unsigned int phy;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	for (phy = PHY_MAX_ADDR; phy >= 0; phy--) {
140*4882a593Smuzhiyun 		val = ll_temac_local_mdio_read(regs, phy, 0, PHY_DETECT_REG);
141*4882a593Smuzhiyun 		if ((val != 0xFFFF) &&
142*4882a593Smuzhiyun 		((val & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
143*4882a593Smuzhiyun 			/* Found a valid PHY address */
144*4882a593Smuzhiyun 			return phy;
145*4882a593Smuzhiyun 		}
146*4882a593Smuzhiyun 	}
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	return -1;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
xilinx_ll_temac_mdio_initialize(bd_t * bis,struct ll_temac_mdio_info * info)151*4882a593Smuzhiyun int xilinx_ll_temac_mdio_initialize(bd_t *bis, struct ll_temac_mdio_info *info)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	struct mii_dev *bus = mdio_alloc();
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	if (!bus) {
156*4882a593Smuzhiyun 		printf("Failed to allocate LL_TEMAC MDIO bus: %s\n",
157*4882a593Smuzhiyun 				info->name);
158*4882a593Smuzhiyun 		return -1;
159*4882a593Smuzhiyun 	}
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	bus->read = ll_temac_phy_read;
162*4882a593Smuzhiyun 	bus->write = ll_temac_phy_write;
163*4882a593Smuzhiyun 	bus->reset = NULL;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	/* use given name or generate its own unique name */
166*4882a593Smuzhiyun 	if (info->name) {
167*4882a593Smuzhiyun 		strncpy(bus->name, info->name, MDIO_NAME_LEN);
168*4882a593Smuzhiyun 	} else {
169*4882a593Smuzhiyun 		snprintf(bus->name, MDIO_NAME_LEN, "lltemii.%p", info->regs);
170*4882a593Smuzhiyun 		info->name = bus->name;
171*4882a593Smuzhiyun 	}
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	bus->priv = info->regs;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	ll_temac_mdio_setup(bus);
176*4882a593Smuzhiyun 	return mdio_register(bus);
177*4882a593Smuzhiyun }
178