blob: b5ca5f76f9e1f648d9fbf8190655c56d9507ff3b [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Dave Liue732e9c2006-11-03 12:11:15 -06002/*
Kumar Gala09036992011-01-19 03:36:40 -06003 * Copyright (C) 2005,2010-2011 Freescale Semiconductor, Inc.
Dave Liue732e9c2006-11-03 12:11:15 -06004 *
5 * Author: Shlomi Gridish
6 *
7 * Description: UCC GETH Driver -- PHY handling
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +01008 * Driver for UEC on QE
9 * Based on 8260_io/fcc_enet.c
Dave Liue732e9c2006-11-03 12:11:15 -060010 */
11
Masahiro Yamadaadae2ec2016-09-21 11:28:53 +090012#include <common.h>
13#include <net.h>
14#include <malloc.h>
Simon Glassdbd79542020-05-10 11:40:11 -060015#include <linux/delay.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090016#include <linux/errno.h>
Masahiro Yamadaadae2ec2016-09-21 11:28:53 +090017#include <linux/immap_qe.h>
18#include <asm/io.h>
Dave Liue732e9c2006-11-03 12:11:15 -060019#include "uccf.h"
20#include "uec.h"
21#include "uec_phy.h"
22#include "miiphy.h"
Qianyu Gongae6a7582016-02-18 13:01:59 +080023#include <fsl_qe.h>
Andy Fleming7832a462011-04-13 00:37:12 -050024#include <phy.h>
Dave Liue732e9c2006-11-03 12:11:15 -060025
Dave Liue732e9c2006-11-03 12:11:15 -060026#define ugphy_printk(format, arg...) \
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +010027 printf(format "\n", ## arg)
Dave Liue732e9c2006-11-03 12:11:15 -060028
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +010029#define ugphy_dbg(format, arg...) \
Heiko Schocherbaf84a92020-05-25 07:27:26 +020030 ugphy_printk(format, ## arg)
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +010031#define ugphy_err(format, arg...) \
Heiko Schocherbaf84a92020-05-25 07:27:26 +020032 ugphy_printk(format, ## arg)
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +010033#define ugphy_info(format, arg...) \
Heiko Schocherbaf84a92020-05-25 07:27:26 +020034 ugphy_printk(format, ## arg)
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +010035#define ugphy_warn(format, arg...) \
Heiko Schocherbaf84a92020-05-25 07:27:26 +020036 ugphy_printk(format, ## arg)
Dave Liue732e9c2006-11-03 12:11:15 -060037
38#ifdef UEC_VERBOSE_DEBUG
39#define ugphy_vdbg ugphy_dbg
40#else
41#define ugphy_vdbg(ugeth, fmt, args...) do { } while (0)
42#endif /* UEC_VERBOSE_DEBUG */
43
Heiko Schocherbaf84a92020-05-25 07:27:26 +020044/*
45 * --------------------------------------------------------------------
Richard Retanubun9a45dcc2008-10-23 09:08:18 -040046 * Fixed PHY (PHY-less) support for Ethernet Ports.
47 *
Stefan Roese88fbf932010-04-15 16:07:28 +020048 * Copied from arch/powerpc/cpu/ppc4xx/4xx_enet.c
Heiko Schocherbaf84a92020-05-25 07:27:26 +020049 *--------------------------------------------------------------------
50 *
Richard Retanubun2e75df72009-07-01 14:04:05 -040051 * Some boards do not have a PHY for each ethernet port. These ports are known
52 * as Fixed PHY (or PHY-less) ports. For such ports, set the appropriate
53 * CONFIG_SYS_UECx_PHY_ADDR equal to CONFIG_FIXED_PHY_ADDR (an unused address)
54 * When the drver tries to identify the PHYs, CONFIG_FIXED_PHY will be returned
55 * and the driver will search CONFIG_SYS_FIXED_PHY_PORTS to find what network
56 * speed and duplex should be for the port.
Richard Retanubun9a45dcc2008-10-23 09:08:18 -040057 *
Richard Retanubun2e75df72009-07-01 14:04:05 -040058 * Example board header configuration file:
Richard Retanubun9a45dcc2008-10-23 09:08:18 -040059 * #define CONFIG_FIXED_PHY 0xFFFFFFFF
Richard Retanubun2e75df72009-07-01 14:04:05 -040060 * #define CONFIG_SYS_FIXED_PHY_ADDR 0x1E (pick an unused phy address)
Richard Retanubun9a45dcc2008-10-23 09:08:18 -040061 *
Richard Retanubun2e75df72009-07-01 14:04:05 -040062 * #define CONFIG_SYS_UEC1_PHY_ADDR CONFIG_SYS_FIXED_PHY_ADDR
63 * #define CONFIG_SYS_UEC2_PHY_ADDR 0x02
64 * #define CONFIG_SYS_UEC3_PHY_ADDR CONFIG_SYS_FIXED_PHY_ADDR
65 * #define CONFIG_SYS_UEC4_PHY_ADDR 0x04
Richard Retanubun9a45dcc2008-10-23 09:08:18 -040066 *
Richard Retanubun2e75df72009-07-01 14:04:05 -040067 * #define CONFIG_SYS_FIXED_PHY_PORT(name,speed,duplex) \
68 * {name, speed, duplex},
Richard Retanubun9a45dcc2008-10-23 09:08:18 -040069 *
70 * #define CONFIG_SYS_FIXED_PHY_PORTS \
Kim Phillipsb42cf5f2010-07-26 18:34:57 -050071 * CONFIG_SYS_FIXED_PHY_PORT("UEC0",SPEED_100,DUPLEX_FULL) \
72 * CONFIG_SYS_FIXED_PHY_PORT("UEC2",SPEED_100,DUPLEX_HALF)
Richard Retanubun9a45dcc2008-10-23 09:08:18 -040073 */
74
75#ifndef CONFIG_FIXED_PHY
76#define CONFIG_FIXED_PHY 0xFFFFFFFF /* Fixed PHY (PHY-less) */
77#endif
78
79#ifndef CONFIG_SYS_FIXED_PHY_PORTS
80#define CONFIG_SYS_FIXED_PHY_PORTS /* default is an empty array */
81#endif
82
83struct fixed_phy_port {
Mike Frysinger6b300dc2011-11-10 14:11:04 +000084 char name[16]; /* ethernet port name */
Richard Retanubun9a45dcc2008-10-23 09:08:18 -040085 unsigned int speed; /* specified speed 10,100 or 1000 */
86 unsigned int duplex; /* specified duplex FULL or HALF */
87};
88
89static const struct fixed_phy_port fixed_phy_port[] = {
90 CONFIG_SYS_FIXED_PHY_PORTS /* defined in board configuration file */
91};
92
Heiko Schocherbaf84a92020-05-25 07:27:26 +020093/*
94 * -------------------------------------------------------------------
Richard Retanubun15e467c2009-06-17 16:00:41 -040095 * BitBang MII support for ethernet ports
96 *
97 * Based from MPC8560ADS implementation
Heiko Schocherbaf84a92020-05-25 07:27:26 +020098 *--------------------------------------------------------------------
99 *
Richard Retanubun15e467c2009-06-17 16:00:41 -0400100 * Example board header file to define bitbang ethernet ports:
101 *
102 * #define CONFIG_SYS_BITBANG_PHY_PORT(name) name,
Kim Phillipsb42cf5f2010-07-26 18:34:57 -0500103 * #define CONFIG_SYS_BITBANG_PHY_PORTS CONFIG_SYS_BITBANG_PHY_PORT("UEC0")
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200104 */
Richard Retanubun15e467c2009-06-17 16:00:41 -0400105#ifndef CONFIG_SYS_BITBANG_PHY_PORTS
106#define CONFIG_SYS_BITBANG_PHY_PORTS /* default is an empty array */
107#endif
108
109#if defined(CONFIG_BITBANGMII)
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200110static const char * const bitbang_phy_port[] = {
Richard Retanubun15e467c2009-06-17 16:00:41 -0400111 CONFIG_SYS_BITBANG_PHY_PORTS /* defined in board configuration file */
112};
113#endif /* CONFIG_BITBANGMII */
114
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200115static void config_genmii_advert(struct uec_mii_info *mii_info);
116static void genmii_setup_forced(struct uec_mii_info *mii_info);
117static void genmii_restart_aneg(struct uec_mii_info *mii_info);
118static int gbit_config_aneg(struct uec_mii_info *mii_info);
119static int genmii_config_aneg(struct uec_mii_info *mii_info);
120static int genmii_update_link(struct uec_mii_info *mii_info);
121static int genmii_read_status(struct uec_mii_info *mii_info);
122static u16 uec_phy_read(struct uec_mii_info *mii_info, u16 regnum);
123static void uec_phy_write(struct uec_mii_info *mii_info, u16 regnum,
124 u16 val);
Dave Liue732e9c2006-11-03 12:11:15 -0600125
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200126/*
127 * Write value to the PHY for this device to the register at regnum,
128 * waiting until the write is done before it returns. All PHY
129 * configuration has to be done through the TSEC1 MIIM regs
130 */
131void uec_write_phy_reg(struct eth_device *dev, int mii_id, int regnum,
132 int value)
Dave Liue732e9c2006-11-03 12:11:15 -0600133{
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200134 struct uec_priv *ugeth = (struct uec_priv *)dev->priv;
Andy Flemingee0e9172007-08-14 00:14:25 -0500135 uec_mii_t *ug_regs;
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200136 enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg)regnum;
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100137 u32 tmp_reg;
Dave Liue732e9c2006-11-03 12:11:15 -0600138
Richard Retanubun15e467c2009-06-17 16:00:41 -0400139#if defined(CONFIG_BITBANGMII)
140 u32 i = 0;
141
142 for (i = 0; i < ARRAY_SIZE(bitbang_phy_port); i++) {
143 if (strncmp(dev->name, bitbang_phy_port[i],
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200144 sizeof(dev->name)) == 0) {
Richard Retanubun15e467c2009-06-17 16:00:41 -0400145 (void)bb_miiphy_write(NULL, mii_id, regnum, value);
146 return;
147 }
148 }
149#endif /* CONFIG_BITBANGMII */
150
Andy Flemingee0e9172007-08-14 00:14:25 -0500151 ug_regs = ugeth->uec_mii_regs;
Dave Liue732e9c2006-11-03 12:11:15 -0600152
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100153 /* Stop the MII management read cycle */
154 out_be32 (&ug_regs->miimcom, 0);
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200155 /* Setting up the MII Management Address Register */
156 tmp_reg = ((u32)mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100157 out_be32 (&ug_regs->miimadd, tmp_reg);
Dave Liue732e9c2006-11-03 12:11:15 -0600158
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200159 /* Setting up the MII Management Control Register with the value */
160 out_be32 (&ug_regs->miimcon, (u32)value);
Kim Phillipsd986cba2008-01-15 14:11:00 -0600161 sync();
Dave Liue732e9c2006-11-03 12:11:15 -0600162
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100163 /* Wait till MII management write is complete */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200164 while ((in_be32 (&ug_regs->miimind)) & MIIMIND_BUSY)
165 ;
Dave Liue732e9c2006-11-03 12:11:15 -0600166}
167
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200168/*
169 * Reads from register regnum in the PHY for device dev,
170 * returning the value. Clears miimcom first. All PHY
171 * configuration has to be done through the TSEC1 MIIM regs
172 */
173int uec_read_phy_reg(struct eth_device *dev, int mii_id, int regnum)
Dave Liue732e9c2006-11-03 12:11:15 -0600174{
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200175 struct uec_priv *ugeth = (struct uec_priv *)dev->priv;
Andy Flemingee0e9172007-08-14 00:14:25 -0500176 uec_mii_t *ug_regs;
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200177 enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg)regnum;
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100178 u32 tmp_reg;
179 u16 value;
Dave Liue732e9c2006-11-03 12:11:15 -0600180
Richard Retanubun15e467c2009-06-17 16:00:41 -0400181#if defined(CONFIG_BITBANGMII)
182 u32 i = 0;
183
184 for (i = 0; i < ARRAY_SIZE(bitbang_phy_port); i++) {
185 if (strncmp(dev->name, bitbang_phy_port[i],
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200186 sizeof(dev->name)) == 0) {
Richard Retanubun15e467c2009-06-17 16:00:41 -0400187 (void)bb_miiphy_read(NULL, mii_id, regnum, &value);
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200188 return value;
Richard Retanubun15e467c2009-06-17 16:00:41 -0400189 }
190 }
191#endif /* CONFIG_BITBANGMII */
192
Andy Flemingee0e9172007-08-14 00:14:25 -0500193 ug_regs = ugeth->uec_mii_regs;
Dave Liue732e9c2006-11-03 12:11:15 -0600194
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200195 /* Setting up the MII Management Address Register */
196 tmp_reg = ((u32)mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100197 out_be32 (&ug_regs->miimadd, tmp_reg);
Dave Liue732e9c2006-11-03 12:11:15 -0600198
Kim Phillipsd986cba2008-01-15 14:11:00 -0600199 /* clear MII management command cycle */
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100200 out_be32 (&ug_regs->miimcom, 0);
Kim Phillipsd986cba2008-01-15 14:11:00 -0600201 sync();
202
203 /* Perform an MII management read cycle */
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100204 out_be32 (&ug_regs->miimcom, MIIMCOM_READ_CYCLE);
Dave Liue732e9c2006-11-03 12:11:15 -0600205
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100206 /* Wait till MII management write is complete */
207 while ((in_be32 (&ug_regs->miimind)) &
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200208 (MIIMIND_NOT_VALID | MIIMIND_BUSY))
209 ;
Dave Liue732e9c2006-11-03 12:11:15 -0600210
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100211 /* Read MII management status */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200212 value = (u16)in_be32 (&ug_regs->miimstat);
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100213 if (value == 0xffff)
Joakim Tjernlund3d7f2552008-01-16 09:40:41 +0100214 ugphy_vdbg
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100215 ("read wrong value : mii_id %d,mii_reg %d, base %08x",
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200216 mii_id, mii_reg, (u32)&ug_regs->miimcfg);
Dave Liue732e9c2006-11-03 12:11:15 -0600217
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200218 return value;
Dave Liue732e9c2006-11-03 12:11:15 -0600219}
220
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200221void mii_clear_phy_interrupt(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600222{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100223 if (mii_info->phyinfo->ack_interrupt)
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200224 mii_info->phyinfo->ack_interrupt(mii_info);
Dave Liue732e9c2006-11-03 12:11:15 -0600225}
226
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200227void mii_configure_phy_interrupt(struct uec_mii_info *mii_info,
228 u32 interrupts)
Dave Liue732e9c2006-11-03 12:11:15 -0600229{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100230 mii_info->interrupts = interrupts;
231 if (mii_info->phyinfo->config_intr)
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200232 mii_info->phyinfo->config_intr(mii_info);
Dave Liue732e9c2006-11-03 12:11:15 -0600233}
234
235/* Writes MII_ADVERTISE with the appropriate values, after
236 * sanitizing advertise to make sure only supported features
237 * are advertised
238 */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200239static void config_genmii_advert(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600240{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100241 u32 advertise;
242 u16 adv;
Dave Liue732e9c2006-11-03 12:11:15 -0600243
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100244 /* Only allow advertising what this PHY supports */
245 mii_info->advertising &= mii_info->phyinfo->features;
246 advertise = mii_info->advertising;
Dave Liue732e9c2006-11-03 12:11:15 -0600247
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100248 /* Setup standard advertisement */
Andy Fleming0d2df962011-03-22 22:49:13 -0500249 adv = uec_phy_read(mii_info, MII_ADVERTISE);
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100250 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
251 if (advertise & ADVERTISED_10baseT_Half)
252 adv |= ADVERTISE_10HALF;
253 if (advertise & ADVERTISED_10baseT_Full)
254 adv |= ADVERTISE_10FULL;
255 if (advertise & ADVERTISED_100baseT_Half)
256 adv |= ADVERTISE_100HALF;
257 if (advertise & ADVERTISED_100baseT_Full)
258 adv |= ADVERTISE_100FULL;
Andy Fleming0d2df962011-03-22 22:49:13 -0500259 uec_phy_write(mii_info, MII_ADVERTISE, adv);
Dave Liue732e9c2006-11-03 12:11:15 -0600260}
261
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200262static void genmii_setup_forced(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600263{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100264 u16 ctrl;
265 u32 features = mii_info->phyinfo->features;
Dave Liue732e9c2006-11-03 12:11:15 -0600266
Andy Fleming0d2df962011-03-22 22:49:13 -0500267 ctrl = uec_phy_read(mii_info, MII_BMCR);
Dave Liue732e9c2006-11-03 12:11:15 -0600268
Mike Frysingerd63ee712010-12-23 15:40:12 -0500269 ctrl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 |
270 BMCR_SPEED1000 | BMCR_ANENABLE);
271 ctrl |= BMCR_RESET;
Dave Liue732e9c2006-11-03 12:11:15 -0600272
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100273 switch (mii_info->speed) {
274 case SPEED_1000:
275 if (features & (SUPPORTED_1000baseT_Half
276 | SUPPORTED_1000baseT_Full)) {
Mike Frysingerd63ee712010-12-23 15:40:12 -0500277 ctrl |= BMCR_SPEED1000;
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100278 break;
279 }
280 mii_info->speed = SPEED_100;
281 case SPEED_100:
282 if (features & (SUPPORTED_100baseT_Half
283 | SUPPORTED_100baseT_Full)) {
Mike Frysingerd63ee712010-12-23 15:40:12 -0500284 ctrl |= BMCR_SPEED100;
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100285 break;
286 }
287 mii_info->speed = SPEED_10;
288 case SPEED_10:
289 if (features & (SUPPORTED_10baseT_Half
290 | SUPPORTED_10baseT_Full))
291 break;
292 default: /* Unsupported speed! */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200293 ugphy_err("%s: Bad speed!", mii_info->dev->name);
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100294 break;
295 }
Dave Liue732e9c2006-11-03 12:11:15 -0600296
Andy Fleming0d2df962011-03-22 22:49:13 -0500297 uec_phy_write(mii_info, MII_BMCR, ctrl);
Dave Liue732e9c2006-11-03 12:11:15 -0600298}
299
300/* Enable and Restart Autonegotiation */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200301static void genmii_restart_aneg(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600302{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100303 u16 ctl;
Dave Liue732e9c2006-11-03 12:11:15 -0600304
Andy Fleming0d2df962011-03-22 22:49:13 -0500305 ctl = uec_phy_read(mii_info, MII_BMCR);
Mike Frysingerd63ee712010-12-23 15:40:12 -0500306 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
Andy Fleming0d2df962011-03-22 22:49:13 -0500307 uec_phy_write(mii_info, MII_BMCR, ctl);
Dave Liue732e9c2006-11-03 12:11:15 -0600308}
309
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200310static int gbit_config_aneg(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600311{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100312 u16 adv;
313 u32 advertise;
Dave Liue732e9c2006-11-03 12:11:15 -0600314
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100315 if (mii_info->autoneg) {
316 /* Configure the ADVERTISE register */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200317 config_genmii_advert(mii_info);
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100318 advertise = mii_info->advertising;
Dave Liue732e9c2006-11-03 12:11:15 -0600319
Andy Fleming0d2df962011-03-22 22:49:13 -0500320 adv = uec_phy_read(mii_info, MII_CTRL1000);
Kumar Gala09036992011-01-19 03:36:40 -0600321 adv &= ~(ADVERTISE_1000FULL |
322 ADVERTISE_1000HALF);
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100323 if (advertise & SUPPORTED_1000baseT_Half)
Kumar Gala09036992011-01-19 03:36:40 -0600324 adv |= ADVERTISE_1000HALF;
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100325 if (advertise & SUPPORTED_1000baseT_Full)
Kumar Gala09036992011-01-19 03:36:40 -0600326 adv |= ADVERTISE_1000FULL;
Andy Fleming0d2df962011-03-22 22:49:13 -0500327 uec_phy_write(mii_info, MII_CTRL1000, adv);
Dave Liue732e9c2006-11-03 12:11:15 -0600328
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100329 /* Start/Restart aneg */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200330 genmii_restart_aneg(mii_info);
331 } else {
332 genmii_setup_forced(mii_info);
333 }
Dave Liue732e9c2006-11-03 12:11:15 -0600334
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100335 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600336}
337
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200338static int marvell_config_aneg(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600339{
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200340 /*
341 * The Marvell PHY has an errata which requires
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100342 * that certain registers get written in order
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200343 * to restart autonegotiation
344 */
Andy Fleming0d2df962011-03-22 22:49:13 -0500345 uec_phy_write(mii_info, MII_BMCR, BMCR_RESET);
Dave Liue732e9c2006-11-03 12:11:15 -0600346
Andy Fleming0d2df962011-03-22 22:49:13 -0500347 uec_phy_write(mii_info, 0x1d, 0x1f);
348 uec_phy_write(mii_info, 0x1e, 0x200c);
349 uec_phy_write(mii_info, 0x1d, 0x5);
350 uec_phy_write(mii_info, 0x1e, 0);
351 uec_phy_write(mii_info, 0x1e, 0x100);
Dave Liue732e9c2006-11-03 12:11:15 -0600352
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200353 gbit_config_aneg(mii_info);
Dave Liue732e9c2006-11-03 12:11:15 -0600354
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100355 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600356}
357
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200358static int genmii_config_aneg(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600359{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100360 if (mii_info->autoneg) {
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200361 /*
362 * Speed up the common case, if link is already up, speed and
363 * duplex match, skip auto neg as it already matches
364 */
Joakim Tjernlund69554e12010-08-10 16:36:49 +0200365 if (!genmii_read_status(mii_info) && mii_info->link)
366 if (mii_info->duplex == DUPLEX_FULL &&
367 mii_info->speed == SPEED_100)
368 if (mii_info->advertising &
369 ADVERTISED_100baseT_Full)
370 return 0;
371
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200372 config_genmii_advert(mii_info);
373 genmii_restart_aneg(mii_info);
374 } else {
375 genmii_setup_forced(mii_info);
376 }
Dave Liue732e9c2006-11-03 12:11:15 -0600377
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100378 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600379}
380
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200381static int genmii_update_link(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600382{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100383 u16 status;
Dave Liue732e9c2006-11-03 12:11:15 -0600384
Kim Phillipsd986cba2008-01-15 14:11:00 -0600385 /* Status is read once to clear old link state */
Andy Fleming0d2df962011-03-22 22:49:13 -0500386 uec_phy_read(mii_info, MII_BMSR);
Dave Liue732e9c2006-11-03 12:11:15 -0600387
Kim Phillipsd986cba2008-01-15 14:11:00 -0600388 /*
389 * Wait if the link is up, and autonegotiation is in progress
390 * (ie - we're capable and it's not done)
391 */
Andy Fleming0d2df962011-03-22 22:49:13 -0500392 status = uec_phy_read(mii_info, MII_BMSR);
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200393 if ((status & BMSR_LSTATUS) && (status & BMSR_ANEGCAPABLE) &&
394 !(status & BMSR_ANEGCOMPLETE)) {
Kim Phillipsd986cba2008-01-15 14:11:00 -0600395 int i = 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600396
Mike Frysingerd63ee712010-12-23 15:40:12 -0500397 while (!(status & BMSR_ANEGCOMPLETE)) {
Kim Phillipsd986cba2008-01-15 14:11:00 -0600398 /*
399 * Timeout reached ?
400 */
401 if (i > UGETH_AN_TIMEOUT) {
402 mii_info->link = 0;
403 return 0;
404 }
405
Kim Phillipsb5da4272008-02-27 16:08:22 -0600406 i++;
Kim Phillipsd986cba2008-01-15 14:11:00 -0600407 udelay(1000); /* 1 ms */
Andy Fleming0d2df962011-03-22 22:49:13 -0500408 status = uec_phy_read(mii_info, MII_BMSR);
Kim Phillipsd986cba2008-01-15 14:11:00 -0600409 }
410 mii_info->link = 1;
Kim Phillipsd986cba2008-01-15 14:11:00 -0600411 } else {
Mike Frysingerd63ee712010-12-23 15:40:12 -0500412 if (status & BMSR_LSTATUS)
Kim Phillipsd986cba2008-01-15 14:11:00 -0600413 mii_info->link = 1;
414 else
415 mii_info->link = 0;
416 }
Dave Liue732e9c2006-11-03 12:11:15 -0600417
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100418 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600419}
420
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200421static int genmii_read_status(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600422{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100423 u16 status;
424 int err;
Dave Liue732e9c2006-11-03 12:11:15 -0600425
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200426 /* Update the link, but return if there was an error */
427 err = genmii_update_link(mii_info);
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100428 if (err)
429 return err;
Dave Liue732e9c2006-11-03 12:11:15 -0600430
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100431 if (mii_info->autoneg) {
Andy Fleming0d2df962011-03-22 22:49:13 -0500432 status = uec_phy_read(mii_info, MII_STAT1000);
Anton Vorontsov951800b2008-03-24 20:46:24 +0300433
434 if (status & (LPA_1000FULL | LPA_1000HALF)) {
435 mii_info->speed = SPEED_1000;
436 if (status & LPA_1000FULL)
437 mii_info->duplex = DUPLEX_FULL;
438 else
439 mii_info->duplex = DUPLEX_HALF;
440 } else {
Andy Fleming0d2df962011-03-22 22:49:13 -0500441 status = uec_phy_read(mii_info, MII_LPA);
Dave Liue732e9c2006-11-03 12:11:15 -0600442
Mike Frysingerd63ee712010-12-23 15:40:12 -0500443 if (status & (LPA_10FULL | LPA_100FULL))
Anton Vorontsov951800b2008-03-24 20:46:24 +0300444 mii_info->duplex = DUPLEX_FULL;
445 else
446 mii_info->duplex = DUPLEX_HALF;
Mike Frysingerd63ee712010-12-23 15:40:12 -0500447 if (status & (LPA_100FULL | LPA_100HALF))
Anton Vorontsov951800b2008-03-24 20:46:24 +0300448 mii_info->speed = SPEED_100;
449 else
450 mii_info->speed = SPEED_10;
451 }
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100452 mii_info->pause = 0;
453 }
454 /* On non-aneg, we assume what we put in BMCR is the speed,
455 * though magic-aneg shouldn't prevent this case from occurring
456 */
Dave Liue732e9c2006-11-03 12:11:15 -0600457
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100458 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600459}
460
Anton Vorontsov98003732008-03-24 20:46:34 +0300461static int bcm_init(struct uec_mii_info *mii_info)
462{
463 struct eth_device *edev = mii_info->dev;
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200464 struct uec_priv *uec = edev->priv;
Anton Vorontsov98003732008-03-24 20:46:34 +0300465
466 gbit_config_aneg(mii_info);
467
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200468 if (uec->uec_info->enet_interface_type ==
469 PHY_INTERFACE_MODE_RGMII_RXID &&
470 uec->uec_info->speed == SPEED_1000) {
Anton Vorontsov98003732008-03-24 20:46:34 +0300471 u16 val;
472 int cnt = 50;
473
474 /* Wait for aneg to complete. */
475 do
Andy Fleming0d2df962011-03-22 22:49:13 -0500476 val = uec_phy_read(mii_info, MII_BMSR);
Mike Frysingerd63ee712010-12-23 15:40:12 -0500477 while (--cnt && !(val & BMSR_ANEGCOMPLETE));
Anton Vorontsov98003732008-03-24 20:46:34 +0300478
479 /* Set RDX clk delay. */
Andy Fleming0d2df962011-03-22 22:49:13 -0500480 uec_phy_write(mii_info, 0x18, 0x7 | (7 << 12));
Anton Vorontsov98003732008-03-24 20:46:34 +0300481
Andy Fleming0d2df962011-03-22 22:49:13 -0500482 val = uec_phy_read(mii_info, 0x18);
Anton Vorontsov98003732008-03-24 20:46:34 +0300483 /* Set RDX-RXC skew. */
484 val |= (1 << 8);
485 val |= (7 | (7 << 12));
486 /* Write bits 14:0. */
487 val |= (1 << 15);
Andy Fleming0d2df962011-03-22 22:49:13 -0500488 uec_phy_write(mii_info, 0x18, val);
Anton Vorontsov98003732008-03-24 20:46:34 +0300489 }
490
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200491 return 0;
Anton Vorontsov98003732008-03-24 20:46:34 +0300492}
493
Andy Fleming0d2df962011-03-22 22:49:13 -0500494static int uec_marvell_init(struct uec_mii_info *mii_info)
Haiying Wang024e1e72008-09-24 11:42:12 -0500495{
496 struct eth_device *edev = mii_info->dev;
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200497 struct uec_priv *uec = edev->priv;
Andy Fleming7832a462011-04-13 00:37:12 -0500498 phy_interface_t iface = uec->uec_info->enet_interface_type;
Heiko Schocher40b44bc2010-01-20 09:04:28 +0100499 int speed = uec->uec_info->speed;
Haiying Wang024e1e72008-09-24 11:42:12 -0500500
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200501 if (speed == SPEED_1000 &&
502 (iface == PHY_INTERFACE_MODE_RGMII_ID ||
Andy Fleming7832a462011-04-13 00:37:12 -0500503 iface == PHY_INTERFACE_MODE_RGMII_RXID ||
504 iface == PHY_INTERFACE_MODE_RGMII_TXID)) {
Haiying Wang024e1e72008-09-24 11:42:12 -0500505 int temp;
506
Andy Fleming0d2df962011-03-22 22:49:13 -0500507 temp = uec_phy_read(mii_info, MII_M1111_PHY_EXT_CR);
Andy Fleming7832a462011-04-13 00:37:12 -0500508 if (iface == PHY_INTERFACE_MODE_RGMII_ID) {
Anton Vorontsov1b8a3362009-09-16 23:21:53 +0400509 temp |= MII_M1111_RX_DELAY | MII_M1111_TX_DELAY;
Andy Fleming7832a462011-04-13 00:37:12 -0500510 } else if (iface == PHY_INTERFACE_MODE_RGMII_RXID) {
Anton Vorontsov1b8a3362009-09-16 23:21:53 +0400511 temp &= ~MII_M1111_TX_DELAY;
512 temp |= MII_M1111_RX_DELAY;
Andy Fleming7832a462011-04-13 00:37:12 -0500513 } else if (iface == PHY_INTERFACE_MODE_RGMII_TXID) {
Anton Vorontsov1b8a3362009-09-16 23:21:53 +0400514 temp &= ~MII_M1111_RX_DELAY;
515 temp |= MII_M1111_TX_DELAY;
516 }
Andy Fleming0d2df962011-03-22 22:49:13 -0500517 uec_phy_write(mii_info, MII_M1111_PHY_EXT_CR, temp);
Haiying Wang024e1e72008-09-24 11:42:12 -0500518
Andy Fleming0d2df962011-03-22 22:49:13 -0500519 temp = uec_phy_read(mii_info, MII_M1111_PHY_EXT_SR);
Haiying Wang024e1e72008-09-24 11:42:12 -0500520 temp &= ~MII_M1111_HWCFG_MODE_MASK;
521 temp |= MII_M1111_HWCFG_MODE_RGMII;
Andy Fleming0d2df962011-03-22 22:49:13 -0500522 uec_phy_write(mii_info, MII_M1111_PHY_EXT_SR, temp);
Haiying Wang024e1e72008-09-24 11:42:12 -0500523
Andy Fleming0d2df962011-03-22 22:49:13 -0500524 uec_phy_write(mii_info, MII_BMCR, BMCR_RESET);
Haiying Wang024e1e72008-09-24 11:42:12 -0500525 }
526
527 return 0;
528}
529
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200530static int marvell_read_status(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600531{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100532 u16 status;
533 int err;
534
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200535 /* Update the link, but return if there was an error */
536 err = genmii_update_link(mii_info);
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100537 if (err)
538 return err;
Dave Liue732e9c2006-11-03 12:11:15 -0600539
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200540 /*
541 * If the link is up, read the speed and duplex
542 * If we aren't autonegotiating, assume speeds
543 * are as set
544 */
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100545 if (mii_info->autoneg && mii_info->link) {
546 int speed;
Dave Liue732e9c2006-11-03 12:11:15 -0600547
Andy Fleming0d2df962011-03-22 22:49:13 -0500548 status = uec_phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS);
Dave Liue732e9c2006-11-03 12:11:15 -0600549
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100550 /* Get the duplexity */
551 if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
552 mii_info->duplex = DUPLEX_FULL;
553 else
554 mii_info->duplex = DUPLEX_HALF;
Dave Liue732e9c2006-11-03 12:11:15 -0600555
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100556 /* Get the speed */
557 speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK;
558 switch (speed) {
559 case MII_M1011_PHY_SPEC_STATUS_1000:
560 mii_info->speed = SPEED_1000;
561 break;
562 case MII_M1011_PHY_SPEC_STATUS_100:
563 mii_info->speed = SPEED_100;
564 break;
565 default:
566 mii_info->speed = SPEED_10;
567 break;
568 }
569 mii_info->pause = 0;
570 }
Dave Liue732e9c2006-11-03 12:11:15 -0600571
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100572 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600573}
574
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200575static int marvell_ack_interrupt(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600576{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100577 /* Clear the interrupts by reading the reg */
Andy Fleming0d2df962011-03-22 22:49:13 -0500578 uec_phy_read(mii_info, MII_M1011_IEVENT);
Dave Liue732e9c2006-11-03 12:11:15 -0600579
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100580 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600581}
582
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200583static int marvell_config_intr(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600584{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100585 if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
Andy Fleming0d2df962011-03-22 22:49:13 -0500586 uec_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100587 else
Andy Fleming0d2df962011-03-22 22:49:13 -0500588 uec_phy_write(mii_info, MII_M1011_IMASK,
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200589 MII_M1011_IMASK_CLEAR);
Dave Liue732e9c2006-11-03 12:11:15 -0600590
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100591 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600592}
593
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200594static int dm9161_init(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600595{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100596 /* Reset the PHY */
Andy Fleming0d2df962011-03-22 22:49:13 -0500597 uec_phy_write(mii_info, MII_BMCR, uec_phy_read(mii_info, MII_BMCR) |
Mike Frysingerd63ee712010-12-23 15:40:12 -0500598 BMCR_RESET);
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100599 /* PHY and MAC connect */
Andy Fleming0d2df962011-03-22 22:49:13 -0500600 uec_phy_write(mii_info, MII_BMCR, uec_phy_read(mii_info, MII_BMCR) &
Mike Frysingerd63ee712010-12-23 15:40:12 -0500601 ~BMCR_ISOLATE);
Kim Phillipsd986cba2008-01-15 14:11:00 -0600602
Andy Fleming0d2df962011-03-22 22:49:13 -0500603 uec_phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT);
Kim Phillipsd986cba2008-01-15 14:11:00 -0600604
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200605 config_genmii_advert(mii_info);
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100606 /* Start/restart aneg */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200607 genmii_config_aneg(mii_info);
Dave Liue732e9c2006-11-03 12:11:15 -0600608
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100609 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600610}
611
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200612static int dm9161_config_aneg(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600613{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100614 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600615}
616
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200617static int dm9161_read_status(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600618{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100619 u16 status;
620 int err;
Dave Liue732e9c2006-11-03 12:11:15 -0600621
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100622 /* Update the link, but return if there was an error */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200623 err = genmii_update_link(mii_info);
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100624 if (err)
625 return err;
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200626 /*
627 * If the link is up, read the speed and duplex
628 * If we aren't autonegotiating assume speeds are as set
629 */
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100630 if (mii_info->autoneg && mii_info->link) {
Andy Fleming0d2df962011-03-22 22:49:13 -0500631 status = uec_phy_read(mii_info, MII_DM9161_SCSR);
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100632 if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H))
633 mii_info->speed = SPEED_100;
634 else
635 mii_info->speed = SPEED_10;
Dave Liue732e9c2006-11-03 12:11:15 -0600636
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100637 if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F))
638 mii_info->duplex = DUPLEX_FULL;
639 else
640 mii_info->duplex = DUPLEX_HALF;
641 }
Dave Liue732e9c2006-11-03 12:11:15 -0600642
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100643 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600644}
645
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200646static int dm9161_ack_interrupt(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600647{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100648 /* Clear the interrupt by reading the reg */
Andy Fleming0d2df962011-03-22 22:49:13 -0500649 uec_phy_read(mii_info, MII_DM9161_INTR);
Dave Liue732e9c2006-11-03 12:11:15 -0600650
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100651 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600652}
653
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200654static int dm9161_config_intr(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600655{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100656 if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
Andy Fleming0d2df962011-03-22 22:49:13 -0500657 uec_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT);
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100658 else
Andy Fleming0d2df962011-03-22 22:49:13 -0500659 uec_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP);
Dave Liue732e9c2006-11-03 12:11:15 -0600660
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100661 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600662}
663
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200664static void dm9161_close(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600665{
666}
667
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200668static int fixed_phy_aneg(struct uec_mii_info *mii_info)
Richard Retanubun9a45dcc2008-10-23 09:08:18 -0400669{
670 mii_info->autoneg = 0; /* Turn off auto negotiation for fixed phy */
671 return 0;
672}
673
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200674static int fixed_phy_read_status(struct uec_mii_info *mii_info)
Richard Retanubun9a45dcc2008-10-23 09:08:18 -0400675{
676 int i = 0;
677
678 for (i = 0; i < ARRAY_SIZE(fixed_phy_port); i++) {
Richard Retanubun2e75df72009-07-01 14:04:05 -0400679 if (strncmp(mii_info->dev->name, fixed_phy_port[i].name,
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200680 strlen(mii_info->dev->name)) == 0) {
Richard Retanubun9a45dcc2008-10-23 09:08:18 -0400681 mii_info->speed = fixed_phy_port[i].speed;
682 mii_info->duplex = fixed_phy_port[i].duplex;
683 mii_info->link = 1; /* Link is always UP */
684 mii_info->pause = 0;
685 break;
686 }
687 }
688 return 0;
689}
690
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200691static int smsc_config_aneg(struct uec_mii_info *mii_info)
Heiko Schocher3be3b9f2008-11-20 09:57:14 +0100692{
693 return 0;
694}
695
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200696static int smsc_read_status(struct uec_mii_info *mii_info)
Heiko Schocher3be3b9f2008-11-20 09:57:14 +0100697{
698 u16 status;
699 int err;
700
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200701 /* Update the link, but return if there was an error */
702 err = genmii_update_link(mii_info);
Heiko Schocher3be3b9f2008-11-20 09:57:14 +0100703 if (err)
704 return err;
705
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200706 /*
707 * If the link is up, read the speed and duplex
708 * If we aren't autonegotiating, assume speeds
709 * are as set
710 */
Heiko Schocher3be3b9f2008-11-20 09:57:14 +0100711 if (mii_info->autoneg && mii_info->link) {
712 int val;
713
Andy Fleming0d2df962011-03-22 22:49:13 -0500714 status = uec_phy_read(mii_info, 0x1f);
Heiko Schocher3be3b9f2008-11-20 09:57:14 +0100715 val = (status & 0x1c) >> 2;
716
717 switch (val) {
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200718 case 1:
719 mii_info->duplex = DUPLEX_HALF;
720 mii_info->speed = SPEED_10;
721 break;
722 case 5:
723 mii_info->duplex = DUPLEX_FULL;
724 mii_info->speed = SPEED_10;
725 break;
726 case 2:
727 mii_info->duplex = DUPLEX_HALF;
728 mii_info->speed = SPEED_100;
729 break;
730 case 6:
731 mii_info->duplex = DUPLEX_FULL;
732 mii_info->speed = SPEED_100;
733 break;
Heiko Schocher3be3b9f2008-11-20 09:57:14 +0100734 }
735 mii_info->pause = 0;
736 }
737
738 return 0;
739}
740
Dave Liue732e9c2006-11-03 12:11:15 -0600741static struct phy_info phy_info_dm9161 = {
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100742 .phy_id = 0x0181b880,
743 .phy_id_mask = 0x0ffffff0,
744 .name = "Davicom DM9161E",
745 .init = dm9161_init,
746 .config_aneg = dm9161_config_aneg,
747 .read_status = dm9161_read_status,
748 .close = dm9161_close,
Dave Liue732e9c2006-11-03 12:11:15 -0600749};
750
751static struct phy_info phy_info_dm9161a = {
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100752 .phy_id = 0x0181b8a0,
753 .phy_id_mask = 0x0ffffff0,
754 .name = "Davicom DM9161A",
755 .features = MII_BASIC_FEATURES,
756 .init = dm9161_init,
757 .config_aneg = dm9161_config_aneg,
758 .read_status = dm9161_read_status,
759 .ack_interrupt = dm9161_ack_interrupt,
760 .config_intr = dm9161_config_intr,
761 .close = dm9161_close,
Dave Liue732e9c2006-11-03 12:11:15 -0600762};
763
764static struct phy_info phy_info_marvell = {
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100765 .phy_id = 0x01410c00,
766 .phy_id_mask = 0xffffff00,
767 .name = "Marvell 88E11x1",
768 .features = MII_GBIT_FEATURES,
Andy Fleming0d2df962011-03-22 22:49:13 -0500769 .init = &uec_marvell_init,
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100770 .config_aneg = &marvell_config_aneg,
771 .read_status = &marvell_read_status,
772 .ack_interrupt = &marvell_ack_interrupt,
773 .config_intr = &marvell_config_intr,
Dave Liue732e9c2006-11-03 12:11:15 -0600774};
775
Anton Vorontsov98003732008-03-24 20:46:34 +0300776static struct phy_info phy_info_bcm5481 = {
777 .phy_id = 0x0143bca0,
778 .phy_id_mask = 0xffffff0,
779 .name = "Broadcom 5481",
780 .features = MII_GBIT_FEATURES,
781 .read_status = genmii_read_status,
782 .init = bcm_init,
783};
784
Richard Retanubun9a45dcc2008-10-23 09:08:18 -0400785static struct phy_info phy_info_fixedphy = {
786 .phy_id = CONFIG_FIXED_PHY,
787 .phy_id_mask = CONFIG_FIXED_PHY,
788 .name = "Fixed PHY",
789 .config_aneg = fixed_phy_aneg,
790 .read_status = fixed_phy_read_status,
791};
792
Heiko Schocher3be3b9f2008-11-20 09:57:14 +0100793static struct phy_info phy_info_smsclan8700 = {
794 .phy_id = 0x0007c0c0,
795 .phy_id_mask = 0xfffffff0,
796 .name = "SMSC LAN8700",
797 .features = MII_BASIC_FEATURES,
798 .config_aneg = smsc_config_aneg,
799 .read_status = smsc_read_status,
800};
801
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100802static struct phy_info phy_info_genmii = {
803 .phy_id = 0x00000000,
804 .phy_id_mask = 0x00000000,
805 .name = "Generic MII",
806 .features = MII_BASIC_FEATURES,
807 .config_aneg = genmii_config_aneg,
808 .read_status = genmii_read_status,
Dave Liue732e9c2006-11-03 12:11:15 -0600809};
810
811static struct phy_info *phy_info[] = {
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100812 &phy_info_dm9161,
813 &phy_info_dm9161a,
814 &phy_info_marvell,
Anton Vorontsov98003732008-03-24 20:46:34 +0300815 &phy_info_bcm5481,
Heiko Schocher3be3b9f2008-11-20 09:57:14 +0100816 &phy_info_smsclan8700,
Richard Retanubun9a45dcc2008-10-23 09:08:18 -0400817 &phy_info_fixedphy,
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100818 &phy_info_genmii,
819 NULL
Dave Liue732e9c2006-11-03 12:11:15 -0600820};
821
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200822static u16 uec_phy_read(struct uec_mii_info *mii_info, u16 regnum)
Dave Liue732e9c2006-11-03 12:11:15 -0600823{
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200824 return mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum);
Dave Liue732e9c2006-11-03 12:11:15 -0600825}
826
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200827static void uec_phy_write(struct uec_mii_info *mii_info, u16 regnum, u16 val)
Dave Liue732e9c2006-11-03 12:11:15 -0600828{
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200829 mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val);
Dave Liue732e9c2006-11-03 12:11:15 -0600830}
831
832/* Use the PHY ID registers to determine what type of PHY is attached
833 * to device dev. return a struct phy_info structure describing that PHY
834 */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200835struct phy_info *uec_get_phy_info(struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600836{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100837 u16 phy_reg;
838 u32 phy_ID;
839 int i;
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200840 struct phy_info *info = NULL;
Dave Liue732e9c2006-11-03 12:11:15 -0600841
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100842 /* Grab the bits from PHYIR1, and put them in the upper half */
Andy Fleming0d2df962011-03-22 22:49:13 -0500843 phy_reg = uec_phy_read(mii_info, MII_PHYSID1);
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100844 phy_ID = (phy_reg & 0xffff) << 16;
Dave Liue732e9c2006-11-03 12:11:15 -0600845
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100846 /* Grab the bits from PHYIR2, and put them in the lower half */
Andy Fleming0d2df962011-03-22 22:49:13 -0500847 phy_reg = uec_phy_read(mii_info, MII_PHYSID2);
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100848 phy_ID |= (phy_reg & 0xffff);
Dave Liue732e9c2006-11-03 12:11:15 -0600849
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100850 /* loop through all the known PHY types, and find one that */
851 /* matches the ID we read from the PHY. */
852 for (i = 0; phy_info[i]; i++)
853 if (phy_info[i]->phy_id ==
854 (phy_ID & phy_info[i]->phy_id_mask)) {
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200855 info = phy_info[i];
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100856 break;
857 }
Dave Liue732e9c2006-11-03 12:11:15 -0600858
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100859 /* This shouldn't happen, as we have generic PHY support */
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200860 if (!info) {
861 ugphy_info("UEC: PHY id %x is not supported!", phy_ID);
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100862 return NULL;
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100863 }
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200864 ugphy_info("UEC: PHY is %s (%x)", info->name, phy_ID);
Dave Liue732e9c2006-11-03 12:11:15 -0600865
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200866 return info;
Dave Liue732e9c2006-11-03 12:11:15 -0600867}
868
Andy Fleming7832a462011-04-13 00:37:12 -0500869void marvell_phy_interface_mode(struct eth_device *dev, phy_interface_t type,
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200870 int speed)
Dave Liue732e9c2006-11-03 12:11:15 -0600871{
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200872 struct uec_priv *uec = (struct uec_priv *)dev->priv;
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100873 struct uec_mii_info *mii_info;
Kim Phillips21084052008-02-27 15:06:39 -0600874 u16 status;
Dave Liue732e9c2006-11-03 12:11:15 -0600875
876 if (!uec->mii_info) {
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200877 printf("%s: the PHY not initialized\n", __func__);
Dave Liue732e9c2006-11-03 12:11:15 -0600878 return;
879 }
880 mii_info = uec->mii_info;
881
Andy Fleming7832a462011-04-13 00:37:12 -0500882 if (type == PHY_INTERFACE_MODE_RGMII) {
883 if (speed == SPEED_100) {
Andy Fleming0d2df962011-03-22 22:49:13 -0500884 uec_phy_write(mii_info, 0x00, 0x9140);
885 uec_phy_write(mii_info, 0x1d, 0x001f);
886 uec_phy_write(mii_info, 0x1e, 0x200c);
887 uec_phy_write(mii_info, 0x1d, 0x0005);
888 uec_phy_write(mii_info, 0x1e, 0x0000);
889 uec_phy_write(mii_info, 0x1e, 0x0100);
890 uec_phy_write(mii_info, 0x09, 0x0e00);
891 uec_phy_write(mii_info, 0x04, 0x01e1);
892 uec_phy_write(mii_info, 0x00, 0x9140);
893 uec_phy_write(mii_info, 0x00, 0x1000);
Simon Glass0db4b942020-05-10 11:40:10 -0600894 mdelay(100);
Andy Fleming0d2df962011-03-22 22:49:13 -0500895 uec_phy_write(mii_info, 0x00, 0x2900);
896 uec_phy_write(mii_info, 0x14, 0x0cd2);
897 uec_phy_write(mii_info, 0x00, 0xa100);
898 uec_phy_write(mii_info, 0x09, 0x0000);
899 uec_phy_write(mii_info, 0x1b, 0x800b);
900 uec_phy_write(mii_info, 0x04, 0x05e1);
901 uec_phy_write(mii_info, 0x00, 0xa100);
902 uec_phy_write(mii_info, 0x00, 0x2100);
Simon Glass0db4b942020-05-10 11:40:10 -0600903 mdelay(1000);
Andy Fleming7832a462011-04-13 00:37:12 -0500904 } else if (speed == SPEED_10) {
Andy Fleming0d2df962011-03-22 22:49:13 -0500905 uec_phy_write(mii_info, 0x14, 0x8e40);
906 uec_phy_write(mii_info, 0x1b, 0x800b);
907 uec_phy_write(mii_info, 0x14, 0x0c82);
908 uec_phy_write(mii_info, 0x00, 0x8100);
Simon Glass0db4b942020-05-10 11:40:10 -0600909 mdelay(1000);
Heiko Schocher40b44bc2010-01-20 09:04:28 +0100910 }
Dave Liue732e9c2006-11-03 12:11:15 -0600911 }
Kim Phillips21084052008-02-27 15:06:39 -0600912
913 /* handle 88e1111 rev.B2 erratum 5.6 */
914 if (mii_info->autoneg) {
Andy Fleming0d2df962011-03-22 22:49:13 -0500915 status = uec_phy_read(mii_info, MII_BMCR);
916 uec_phy_write(mii_info, MII_BMCR, status | BMCR_ANENABLE);
Kim Phillips21084052008-02-27 15:06:39 -0600917 }
918 /* now the B2 will correctly report autoneg completion status */
Dave Liue732e9c2006-11-03 12:11:15 -0600919}
920
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200921void change_phy_interface_mode(struct eth_device *dev,
922 phy_interface_t type, int speed)
Dave Liue732e9c2006-11-03 12:11:15 -0600923{
924#ifdef CONFIG_PHY_MODE_NEED_CHANGE
Heiko Schocherbaf84a92020-05-25 07:27:26 +0200925 marvell_phy_interface_mode(dev, type, speed);
Dave Liue732e9c2006-11-03 12:11:15 -0600926#endif
927}