blob: 9c8fe6244191db15ccb282a110e09450237b4c98 [file] [log] [blame]
wdenk42d1f032003-10-15 23:53:47 +00001/*
wdenk97d80fc2004-06-09 00:34:46 +00002 * Freescale Three Speed Ethernet Controller driver
wdenk42d1f032003-10-15 23:53:47 +00003 *
4 * This software may be used and distributed according to the
5 * terms of the GNU Public License, Version 2, incorporated
6 * herein by reference.
7 *
Kumar Gala72c96a62010-12-01 22:55:54 -06008 * Copyright 2004-2010 Freescale Semiconductor, Inc.
wdenk42d1f032003-10-15 23:53:47 +00009 * (C) Copyright 2003, Motorola, Inc.
wdenk42d1f032003-10-15 23:53:47 +000010 * author Andy Fleming
11 *
12 */
13
14#include <config.h>
wdenk42d1f032003-10-15 23:53:47 +000015#include <common.h>
16#include <malloc.h>
17#include <net.h>
18#include <command.h>
Andy Flemingdd3d1f52008-08-31 16:33:25 -050019#include <tsec.h>
Kim Phillips0d071cd2009-08-24 14:32:26 -050020#include <asm/errno.h>
wdenk42d1f032003-10-15 23:53:47 +000021
Marian Balakowicz63ff0042005-10-28 22:30:33 +020022#include "miiphy.h"
wdenk42d1f032003-10-15 23:53:47 +000023
Wolfgang Denkd87080b2006-03-31 18:32:53 +020024DECLARE_GLOBAL_DATA_PTR;
25
Marian Balakowicz63ff0042005-10-28 22:30:33 +020026#define TX_BUF_CNT 2
wdenk42d1f032003-10-15 23:53:47 +000027
Jon Loeliger89875e92006-10-10 17:03:43 -050028static uint rxIdx; /* index of the current RX buffer */
29static uint txIdx; /* index of the current TX buffer */
wdenk42d1f032003-10-15 23:53:47 +000030
31typedef volatile struct rtxbd {
32 txbd8_t txbd[TX_BUF_CNT];
33 rxbd8_t rxbd[PKTBUFSRX];
Jon Loeliger89875e92006-10-10 17:03:43 -050034} RTXBD;
wdenk42d1f032003-10-15 23:53:47 +000035
Andy Fleming75b9d4a2008-08-31 16:33:26 -050036#define MAXCONTROLLERS (8)
wdenk97d80fc2004-06-09 00:34:46 +000037
wdenk97d80fc2004-06-09 00:34:46 +000038static struct tsec_private *privlist[MAXCONTROLLERS];
Andy Fleming75b9d4a2008-08-31 16:33:26 -050039static int num_tsecs = 0;
wdenk97d80fc2004-06-09 00:34:46 +000040
wdenk42d1f032003-10-15 23:53:47 +000041#ifdef __GNUC__
42static RTXBD rtx __attribute__ ((aligned(8)));
43#else
44#error "rtx must be 64-bit aligned"
45#endif
46
Jon Loeliger89875e92006-10-10 17:03:43 -050047static int tsec_send(struct eth_device *dev,
48 volatile void *packet, int length);
49static int tsec_recv(struct eth_device *dev);
50static int tsec_init(struct eth_device *dev, bd_t * bd);
Peter Tysere1957ef2009-11-09 13:09:45 -060051static int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info);
Jon Loeliger89875e92006-10-10 17:03:43 -050052static void tsec_halt(struct eth_device *dev);
53static void init_registers(volatile tsec_t * regs);
wdenk97d80fc2004-06-09 00:34:46 +000054static void startup_tsec(struct eth_device *dev);
55static int init_phy(struct eth_device *dev);
56void write_phy_reg(struct tsec_private *priv, uint regnum, uint value);
57uint read_phy_reg(struct tsec_private *priv, uint regnum);
Peter Tysere1957ef2009-11-09 13:09:45 -060058static struct phy_info *get_phy_info(struct eth_device *dev);
59static void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd);
wdenk97d80fc2004-06-09 00:34:46 +000060static void adjust_link(struct eth_device *dev);
Wolfgang Denk409ecdc2007-11-18 16:36:27 +010061#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
62 && !defined(BITBANGMII)
Mike Frysinger5700bb62010-07-27 18:35:08 -040063static int tsec_miiphy_write(const char *devname, unsigned char addr,
Jon Loeliger89875e92006-10-10 17:03:43 -050064 unsigned char reg, unsigned short value);
Mike Frysinger5700bb62010-07-27 18:35:08 -040065static int tsec_miiphy_read(const char *devname, unsigned char addr,
Jon Loeliger89875e92006-10-10 17:03:43 -050066 unsigned char reg, unsigned short *value);
Wolfgang Denk409ecdc2007-11-18 16:36:27 +010067#endif
David Updegraff53a5c422007-06-11 10:41:07 -050068#ifdef CONFIG_MCAST_TFTP
69static int tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set);
70#endif
wdenk7abf0c52004-04-18 21:45:42 +000071
Andy Fleming75b9d4a2008-08-31 16:33:26 -050072/* Default initializations for TSEC controllers. */
73
74static struct tsec_info_struct tsec_info[] = {
75#ifdef CONFIG_TSEC1
76 STD_TSEC_INFO(1), /* TSEC1 */
77#endif
78#ifdef CONFIG_TSEC2
79 STD_TSEC_INFO(2), /* TSEC2 */
80#endif
81#ifdef CONFIG_MPC85XX_FEC
82 {
83 .regs = (tsec_t *)(TSEC_BASE_ADDR + 0x2000),
Sandeep Gopalpetb9e186f2009-10-31 00:35:04 +053084 .miiregs = (tsec_mdio_t *)(MDIO_BASE_ADDR),
Andy Fleming75b9d4a2008-08-31 16:33:26 -050085 .devname = CONFIG_MPC85XX_FEC_NAME,
86 .phyaddr = FEC_PHY_ADDR,
87 .flags = FEC_FLAGS
88 }, /* FEC */
89#endif
90#ifdef CONFIG_TSEC3
91 STD_TSEC_INFO(3), /* TSEC3 */
92#endif
93#ifdef CONFIG_TSEC4
94 STD_TSEC_INFO(4), /* TSEC4 */
95#endif
96};
97
Timur Tabidaa2ce62010-06-08 08:21:21 -050098/*
99 * Initialize all the TSEC devices
100 *
101 * Returns the number of TSEC devices that were initialized
102 */
Andy Fleming75b9d4a2008-08-31 16:33:26 -0500103int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num)
104{
105 int i;
Timur Tabidaa2ce62010-06-08 08:21:21 -0500106 int ret, count = 0;
Andy Fleming75b9d4a2008-08-31 16:33:26 -0500107
Timur Tabidaa2ce62010-06-08 08:21:21 -0500108 for (i = 0; i < num; i++) {
109 ret = tsec_initialize(bis, &tsecs[i]);
110 if (ret > 0)
111 count += ret;
112 }
Andy Fleming75b9d4a2008-08-31 16:33:26 -0500113
Timur Tabidaa2ce62010-06-08 08:21:21 -0500114 return count;
Andy Fleming75b9d4a2008-08-31 16:33:26 -0500115}
116
117int tsec_standard_init(bd_t *bis)
118{
119 return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info));
120}
121
wdenk97d80fc2004-06-09 00:34:46 +0000122/* Initialize device structure. Returns success if PHY
123 * initialization succeeded (i.e. if it recognizes the PHY)
124 */
Peter Tysere1957ef2009-11-09 13:09:45 -0600125static int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info)
wdenk42d1f032003-10-15 23:53:47 +0000126{
Jon Loeliger89875e92006-10-10 17:03:43 -0500127 struct eth_device *dev;
wdenk42d1f032003-10-15 23:53:47 +0000128 int i;
wdenk97d80fc2004-06-09 00:34:46 +0000129 struct tsec_private *priv;
wdenk42d1f032003-10-15 23:53:47 +0000130
Jon Loeliger89875e92006-10-10 17:03:43 -0500131 dev = (struct eth_device *)malloc(sizeof *dev);
wdenk42d1f032003-10-15 23:53:47 +0000132
Jon Loeliger89875e92006-10-10 17:03:43 -0500133 if (NULL == dev)
wdenk42d1f032003-10-15 23:53:47 +0000134 return 0;
135
136 memset(dev, 0, sizeof *dev);
137
Jon Loeliger89875e92006-10-10 17:03:43 -0500138 priv = (struct tsec_private *)malloc(sizeof(*priv));
wdenk97d80fc2004-06-09 00:34:46 +0000139
Jon Loeliger89875e92006-10-10 17:03:43 -0500140 if (NULL == priv)
wdenk97d80fc2004-06-09 00:34:46 +0000141 return 0;
142
Andy Fleming75b9d4a2008-08-31 16:33:26 -0500143 privlist[num_tsecs++] = priv;
144 priv->regs = tsec_info->regs;
145 priv->phyregs = tsec_info->miiregs;
Sandeep Gopalpetb9e186f2009-10-31 00:35:04 +0530146 priv->phyregs_sgmii = tsec_info->miiregs_sgmii;
wdenk97d80fc2004-06-09 00:34:46 +0000147
Andy Fleming75b9d4a2008-08-31 16:33:26 -0500148 priv->phyaddr = tsec_info->phyaddr;
149 priv->flags = tsec_info->flags;
wdenk97d80fc2004-06-09 00:34:46 +0000150
Andy Fleming75b9d4a2008-08-31 16:33:26 -0500151 sprintf(dev->name, tsec_info->devname);
wdenk42d1f032003-10-15 23:53:47 +0000152 dev->iobase = 0;
Jon Loeliger89875e92006-10-10 17:03:43 -0500153 dev->priv = priv;
154 dev->init = tsec_init;
155 dev->halt = tsec_halt;
156 dev->send = tsec_send;
157 dev->recv = tsec_recv;
David Updegraff53a5c422007-06-11 10:41:07 -0500158#ifdef CONFIG_MCAST_TFTP
159 dev->mcast = tsec_mcast_addr;
160#endif
wdenk42d1f032003-10-15 23:53:47 +0000161
162 /* Tell u-boot to get the addr from the env */
Jon Loeliger89875e92006-10-10 17:03:43 -0500163 for (i = 0; i < 6; i++)
wdenk42d1f032003-10-15 23:53:47 +0000164 dev->enetaddr[i] = 0;
165
166 eth_register(dev);
167
wdenk97d80fc2004-06-09 00:34:46 +0000168 /* Reset the MAC */
169 priv->regs->maccfg1 |= MACCFG1_SOFT_RESET;
Andy Fleming9e5be822009-02-03 18:26:41 -0600170 udelay(2); /* Soft Reset must be asserted for 3 TX clocks */
wdenk97d80fc2004-06-09 00:34:46 +0000171 priv->regs->maccfg1 &= ~(MACCFG1_SOFT_RESET);
wdenk7abf0c52004-04-18 21:45:42 +0000172
Jon Loeligercb51c0b2007-07-09 17:39:42 -0500173#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200174 && !defined(BITBANGMII)
175 miiphy_register(dev->name, tsec_miiphy_read, tsec_miiphy_write);
176#endif
177
wdenk97d80fc2004-06-09 00:34:46 +0000178 /* Try to initialize PHY here, and return */
179 return init_phy(dev);
wdenk42d1f032003-10-15 23:53:47 +0000180}
181
wdenk42d1f032003-10-15 23:53:47 +0000182/* Initializes data structures and registers for the controller,
wdenk9d46ea42005-03-14 23:56:42 +0000183 * and brings the interface up. Returns the link status, meaning
wdenk97d80fc2004-06-09 00:34:46 +0000184 * that it returns success if the link is up, failure otherwise.
Jon Loeliger89875e92006-10-10 17:03:43 -0500185 * This allows u-boot to find the first active controller.
186 */
Peter Tysere1957ef2009-11-09 13:09:45 -0600187static int tsec_init(struct eth_device *dev, bd_t * bd)
wdenk42d1f032003-10-15 23:53:47 +0000188{
wdenk42d1f032003-10-15 23:53:47 +0000189 uint tempval;
190 char tmpbuf[MAC_ADDR_LEN];
191 int i;
wdenk97d80fc2004-06-09 00:34:46 +0000192 struct tsec_private *priv = (struct tsec_private *)dev->priv;
193 volatile tsec_t *regs = priv->regs;
wdenk42d1f032003-10-15 23:53:47 +0000194
195 /* Make sure the controller is stopped */
196 tsec_halt(dev);
197
wdenk97d80fc2004-06-09 00:34:46 +0000198 /* Init MACCFG2. Defaults to GMII */
wdenk42d1f032003-10-15 23:53:47 +0000199 regs->maccfg2 = MACCFG2_INIT_SETTINGS;
200
201 /* Init ECNTRL */
202 regs->ecntrl = ECNTRL_INIT_SETTINGS;
203
204 /* Copy the station address into the address registers.
205 * Backwards, because little endian MACS are dumb */
Jon Loeliger89875e92006-10-10 17:03:43 -0500206 for (i = 0; i < MAC_ADDR_LEN; i++) {
wdenk97d80fc2004-06-09 00:34:46 +0000207 tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i];
wdenk42d1f032003-10-15 23:53:47 +0000208 }
Kim Phillips88ad3fd2009-07-17 12:17:00 -0500209 tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) |
210 tmpbuf[3];
211
212 regs->macstnaddr1 = tempval;
wdenk42d1f032003-10-15 23:53:47 +0000213
Jon Loeliger89875e92006-10-10 17:03:43 -0500214 tempval = *((uint *) (tmpbuf + 4));
wdenk42d1f032003-10-15 23:53:47 +0000215
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200216 regs->macstnaddr2 = tempval;
wdenk42d1f032003-10-15 23:53:47 +0000217
wdenk42d1f032003-10-15 23:53:47 +0000218 /* reset the indices to zero */
219 rxIdx = 0;
220 txIdx = 0;
221
222 /* Clear out (for the most part) the other registers */
223 init_registers(regs);
224
225 /* Ready the device for tx/rx */
wdenk97d80fc2004-06-09 00:34:46 +0000226 startup_tsec(dev);
wdenk42d1f032003-10-15 23:53:47 +0000227
wdenk97d80fc2004-06-09 00:34:46 +0000228 /* If there's no link, fail */
Ben Warren422b1a02008-01-09 18:15:53 -0500229 return (priv->link ? 0 : -1);
wdenk42d1f032003-10-15 23:53:47 +0000230}
231
Andy Fleming2abe3612008-08-31 16:33:27 -0500232/* Writes the given phy's reg with value, using the specified MDIO regs */
Sandeep Gopalpetb9e186f2009-10-31 00:35:04 +0530233static void tsec_local_mdio_write(volatile tsec_mdio_t *phyregs, uint addr,
Andy Fleming2abe3612008-08-31 16:33:27 -0500234 uint reg, uint value)
wdenk97d80fc2004-06-09 00:34:46 +0000235{
Jon Loeliger89875e92006-10-10 17:03:43 -0500236 int timeout = 1000000;
wdenk97d80fc2004-06-09 00:34:46 +0000237
Andy Fleming2abe3612008-08-31 16:33:27 -0500238 phyregs->miimadd = (addr << 8) | reg;
239 phyregs->miimcon = value;
Eran Libertyf046ccd2005-07-28 10:08:46 -0500240 asm("sync");
wdenk97d80fc2004-06-09 00:34:46 +0000241
Jon Loeliger89875e92006-10-10 17:03:43 -0500242 timeout = 1000000;
Andy Fleming2abe3612008-08-31 16:33:27 -0500243 while ((phyregs->miimind & MIIMIND_BUSY) && timeout--) ;
wdenk97d80fc2004-06-09 00:34:46 +0000244}
245
Andy Fleming2abe3612008-08-31 16:33:27 -0500246
247/* Provide the default behavior of writing the PHY of this ethernet device */
Peter Tyserc6dbdfd2009-11-09 13:09:46 -0600248#define write_phy_reg(priv, regnum, value) \
249 tsec_local_mdio_write(priv->phyregs,priv->phyaddr,regnum,value)
michael.firth@bt.com55fe7c52008-01-16 11:40:51 +0000250
wdenk97d80fc2004-06-09 00:34:46 +0000251/* Reads register regnum on the device's PHY through the
Andy Fleming2abe3612008-08-31 16:33:27 -0500252 * specified registers. It lowers and raises the read
wdenk97d80fc2004-06-09 00:34:46 +0000253 * command, and waits for the data to become valid (miimind
254 * notvalid bit cleared), and the bus to cease activity (miimind
255 * busy bit cleared), and then returns the value
256 */
Peter Tysere1957ef2009-11-09 13:09:45 -0600257static uint tsec_local_mdio_read(volatile tsec_mdio_t *phyregs,
258 uint phyid, uint regnum)
wdenk42d1f032003-10-15 23:53:47 +0000259{
260 uint value;
261
wdenk97d80fc2004-06-09 00:34:46 +0000262 /* Put the address of the phy, and the register
263 * number into MIIMADD */
Andy Fleming2abe3612008-08-31 16:33:27 -0500264 phyregs->miimadd = (phyid << 8) | regnum;
wdenk42d1f032003-10-15 23:53:47 +0000265
266 /* Clear the command register, and wait */
Andy Fleming2abe3612008-08-31 16:33:27 -0500267 phyregs->miimcom = 0;
Eran Libertyf046ccd2005-07-28 10:08:46 -0500268 asm("sync");
wdenk42d1f032003-10-15 23:53:47 +0000269
270 /* Initiate a read command, and wait */
Andy Fleming2abe3612008-08-31 16:33:27 -0500271 phyregs->miimcom = MIIM_READ_COMMAND;
Eran Libertyf046ccd2005-07-28 10:08:46 -0500272 asm("sync");
wdenk42d1f032003-10-15 23:53:47 +0000273
274 /* Wait for the the indication that the read is done */
Andy Fleming2abe3612008-08-31 16:33:27 -0500275 while ((phyregs->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))) ;
wdenk42d1f032003-10-15 23:53:47 +0000276
277 /* Grab the value read from the PHY */
Andy Fleming2abe3612008-08-31 16:33:27 -0500278 value = phyregs->miimstat;
wdenk42d1f032003-10-15 23:53:47 +0000279
280 return value;
281}
282
michael.firth@bt.com55fe7c52008-01-16 11:40:51 +0000283/* #define to provide old read_phy_reg functionality without duplicating code */
Peter Tyserc6dbdfd2009-11-09 13:09:46 -0600284#define read_phy_reg(priv,regnum) \
285 tsec_local_mdio_read(priv->phyregs,priv->phyaddr,regnum)
Andy Fleming2abe3612008-08-31 16:33:27 -0500286
287#define TBIANA_SETTINGS ( \
288 TBIANA_ASYMMETRIC_PAUSE \
289 | TBIANA_SYMMETRIC_PAUSE \
290 | TBIANA_FULL_DUPLEX \
291 )
292
Felix Radensky90b5bf22010-06-28 01:57:39 +0300293/* By default force the TBI PHY into 1000Mbps full duplex when in SGMII mode */
294#ifndef CONFIG_TSEC_TBICR_SETTINGS
Kumar Gala72c96a62010-12-01 22:55:54 -0600295#define CONFIG_TSEC_TBICR_SETTINGS ( \
Andy Fleming2abe3612008-08-31 16:33:27 -0500296 TBICR_PHY_RESET \
Kumar Gala72c96a62010-12-01 22:55:54 -0600297 | TBICR_ANEG_ENABLE \
Andy Fleming2abe3612008-08-31 16:33:27 -0500298 | TBICR_FULL_DUPLEX \
299 | TBICR_SPEED1_SET \
300 )
Felix Radensky90b5bf22010-06-28 01:57:39 +0300301#endif /* CONFIG_TSEC_TBICR_SETTINGS */
Peter Tyser46e91672009-11-03 17:52:07 -0600302
Andy Fleming2abe3612008-08-31 16:33:27 -0500303/* Configure the TBI for SGMII operation */
304static void tsec_configure_serdes(struct tsec_private *priv)
305{
Peter Tyserc6dbdfd2009-11-09 13:09:46 -0600306 /* Access TBI PHY registers at given TSEC register offset as opposed
307 * to the register offset used for external PHY accesses */
Sandeep Gopalpetb9e186f2009-10-31 00:35:04 +0530308 tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, TBI_ANA,
Andy Fleming2abe3612008-08-31 16:33:27 -0500309 TBIANA_SETTINGS);
Sandeep Gopalpetb9e186f2009-10-31 00:35:04 +0530310 tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, TBI_TBICON,
Andy Fleming2abe3612008-08-31 16:33:27 -0500311 TBICON_CLK_SELECT);
Sandeep Gopalpetb9e186f2009-10-31 00:35:04 +0530312 tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, TBI_CR,
Kumar Gala72c96a62010-12-01 22:55:54 -0600313 CONFIG_TSEC_TBICR_SETTINGS);
Andy Fleming2abe3612008-08-31 16:33:27 -0500314}
michael.firth@bt.com55fe7c52008-01-16 11:40:51 +0000315
wdenk97d80fc2004-06-09 00:34:46 +0000316/* Discover which PHY is attached to the device, and configure it
317 * properly. If the PHY is not recognized, then return 0
318 * (failure). Otherwise, return 1
319 */
320static int init_phy(struct eth_device *dev)
wdenk42d1f032003-10-15 23:53:47 +0000321{
wdenk97d80fc2004-06-09 00:34:46 +0000322 struct tsec_private *priv = (struct tsec_private *)dev->priv;
323 struct phy_info *curphy;
Andy Fleming2abe3612008-08-31 16:33:27 -0500324 volatile tsec_t *regs = priv->regs;
wdenk42d1f032003-10-15 23:53:47 +0000325
326 /* Assign a Physical address to the TBI */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200327 regs->tbipa = CONFIG_SYS_TBIPA_VALUE;
Jon Loeliger89875e92006-10-10 17:03:43 -0500328 asm("sync");
wdenk3dd7f0f2005-04-04 23:43:44 +0000329
330 /* Reset MII (due to new addresses) */
331 priv->phyregs->miimcfg = MIIMCFG_RESET;
Eran Libertyf046ccd2005-07-28 10:08:46 -0500332 asm("sync");
wdenk3dd7f0f2005-04-04 23:43:44 +0000333 priv->phyregs->miimcfg = MIIMCFG_INIT_VALUE;
Eran Libertyf046ccd2005-07-28 10:08:46 -0500334 asm("sync");
Jon Loeliger89875e92006-10-10 17:03:43 -0500335 while (priv->phyregs->miimind & MIIMIND_BUSY) ;
wdenk42d1f032003-10-15 23:53:47 +0000336
wdenk97d80fc2004-06-09 00:34:46 +0000337 /* Get the cmd structure corresponding to the attached
338 * PHY */
339 curphy = get_phy_info(dev);
wdenk42d1f032003-10-15 23:53:47 +0000340
Ben Warren4653f912006-10-26 14:38:25 -0400341 if (curphy == NULL) {
342 priv->phyinfo = NULL;
wdenk97d80fc2004-06-09 00:34:46 +0000343 printf("%s: No PHY found\n", dev->name);
wdenk42d1f032003-10-15 23:53:47 +0000344
wdenk97d80fc2004-06-09 00:34:46 +0000345 return 0;
wdenk42d1f032003-10-15 23:53:47 +0000346 }
347
Andy Fleming2abe3612008-08-31 16:33:27 -0500348 if (regs->ecntrl & ECNTRL_SGMII_MODE)
349 tsec_configure_serdes(priv);
350
wdenk97d80fc2004-06-09 00:34:46 +0000351 priv->phyinfo = curphy;
wdenk42d1f032003-10-15 23:53:47 +0000352
wdenk97d80fc2004-06-09 00:34:46 +0000353 phy_run_commands(priv, priv->phyinfo->config);
wdenk42d1f032003-10-15 23:53:47 +0000354
wdenk97d80fc2004-06-09 00:34:46 +0000355 return 1;
wdenk42d1f032003-10-15 23:53:47 +0000356}
357
Jon Loeliger89875e92006-10-10 17:03:43 -0500358/*
359 * Returns which value to write to the control register.
360 * For 10/100, the value is slightly different
361 */
Peter Tysere1957ef2009-11-09 13:09:45 -0600362static uint mii_cr_init(uint mii_reg, struct tsec_private * priv)
wdenk97d80fc2004-06-09 00:34:46 +0000363{
Jon Loeliger89875e92006-10-10 17:03:43 -0500364 if (priv->flags & TSEC_GIGABIT)
wdenk97d80fc2004-06-09 00:34:46 +0000365 return MIIM_CONTROL_INIT;
366 else
367 return MIIM_CR_INIT;
368}
369
Peter Tyserb1e849f2009-02-04 15:14:05 -0600370/*
371 * Wait for auto-negotiation to complete, then determine link
Jon Loeliger89875e92006-10-10 17:03:43 -0500372 */
Peter Tysere1957ef2009-11-09 13:09:45 -0600373static uint mii_parse_sr(uint mii_reg, struct tsec_private * priv)
wdenk97d80fc2004-06-09 00:34:46 +0000374{
Stefan Roese5810dc32005-09-21 18:20:22 +0200375 /*
Andy Fleming7613afd2007-08-15 20:03:44 -0500376 * Wait if the link is up, and autonegotiation is in progress
377 * (ie - we're capable and it's not done)
Stefan Roese5810dc32005-09-21 18:20:22 +0200378 */
379 mii_reg = read_phy_reg(priv, MIIM_STATUS);
Mike Frysinger8ef583a2010-12-23 15:40:12 -0500380 if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) {
Stefan Roese5810dc32005-09-21 18:20:22 +0200381 int i = 0;
wdenk97d80fc2004-06-09 00:34:46 +0000382
Jon Loeliger89875e92006-10-10 17:03:43 -0500383 puts("Waiting for PHY auto negotiation to complete");
Mike Frysinger8ef583a2010-12-23 15:40:12 -0500384 while (!(mii_reg & BMSR_ANEGCOMPLETE)) {
Stefan Roese5810dc32005-09-21 18:20:22 +0200385 /*
386 * Timeout reached ?
387 */
388 if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
Jon Loeliger89875e92006-10-10 17:03:43 -0500389 puts(" TIMEOUT !\n");
Stefan Roese5810dc32005-09-21 18:20:22 +0200390 priv->link = 0;
Jin Zhengxiong-R64188fcfb9a52006-06-27 18:12:23 +0800391 return 0;
Stefan Roese5810dc32005-09-21 18:20:22 +0200392 }
wdenk97d80fc2004-06-09 00:34:46 +0000393
Kim Phillips0d071cd2009-08-24 14:32:26 -0500394 if (ctrlc()) {
395 puts("user interrupt!\n");
396 priv->link = 0;
397 return -EINTR;
398 }
399
Stefan Roese5810dc32005-09-21 18:20:22 +0200400 if ((i++ % 1000) == 0) {
Jon Loeliger89875e92006-10-10 17:03:43 -0500401 putc('.');
Stefan Roese5810dc32005-09-21 18:20:22 +0200402 }
Jon Loeliger89875e92006-10-10 17:03:43 -0500403 udelay(1000); /* 1 ms */
wdenk97d80fc2004-06-09 00:34:46 +0000404 mii_reg = read_phy_reg(priv, MIIM_STATUS);
Stefan Roese5810dc32005-09-21 18:20:22 +0200405 }
Jon Loeliger89875e92006-10-10 17:03:43 -0500406 puts(" done\n");
Peter Tyserb1e849f2009-02-04 15:14:05 -0600407
408 /* Link status bit is latched low, read it again */
409 mii_reg = read_phy_reg(priv, MIIM_STATUS);
410
Jon Loeliger89875e92006-10-10 17:03:43 -0500411 udelay(500000); /* another 500 ms (results in faster booting) */
wdenk97d80fc2004-06-09 00:34:46 +0000412 }
413
Peter Tyserb1e849f2009-02-04 15:14:05 -0600414 priv->link = mii_reg & MIIM_STATUS_LINK ? 1 : 0;
415
wdenk97d80fc2004-06-09 00:34:46 +0000416 return 0;
417}
418
David Updegraffaf1c2b82007-04-20 14:34:48 -0500419/* Generic function which updates the speed and duplex. If
420 * autonegotiation is enabled, it uses the AND of the link
421 * partner's advertised capabilities and our advertised
422 * capabilities. If autonegotiation is disabled, we use the
423 * appropriate bits in the control register.
424 *
425 * Stolen from Linux's mii.c and phy_device.c
426 */
Peter Tysere1957ef2009-11-09 13:09:45 -0600427static uint mii_parse_link(uint mii_reg, struct tsec_private *priv)
David Updegraffaf1c2b82007-04-20 14:34:48 -0500428{
429 /* We're using autonegotiation */
Mike Frysinger8ef583a2010-12-23 15:40:12 -0500430 if (mii_reg & BMSR_ANEGCAPABLE) {
David Updegraffaf1c2b82007-04-20 14:34:48 -0500431 uint lpa = 0;
432 uint gblpa = 0;
433
434 /* Check for gigabit capability */
Mike Frysinger8ef583a2010-12-23 15:40:12 -0500435 if (mii_reg & BMSR_ERCAP) {
David Updegraffaf1c2b82007-04-20 14:34:48 -0500436 /* We want a list of states supported by
437 * both PHYs in the link
438 */
Mike Frysinger8ef583a2010-12-23 15:40:12 -0500439 gblpa = read_phy_reg(priv, MII_STAT1000);
440 gblpa &= read_phy_reg(priv, MII_CTRL1000) << 2;
David Updegraffaf1c2b82007-04-20 14:34:48 -0500441 }
442
443 /* Set the baseline so we only have to set them
444 * if they're different
445 */
446 priv->speed = 10;
447 priv->duplexity = 0;
448
449 /* Check the gigabit fields */
450 if (gblpa & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) {
451 priv->speed = 1000;
452
453 if (gblpa & PHY_1000BTSR_1000FD)
454 priv->duplexity = 1;
455
456 /* We're done! */
457 return 0;
458 }
459
Mike Frysinger8ef583a2010-12-23 15:40:12 -0500460 lpa = read_phy_reg(priv, MII_ADVERTISE);
461 lpa &= read_phy_reg(priv, MII_LPA);
David Updegraffaf1c2b82007-04-20 14:34:48 -0500462
Mike Frysinger8ef583a2010-12-23 15:40:12 -0500463 if (lpa & (LPA_100FULL | LPA_100HALF)) {
David Updegraffaf1c2b82007-04-20 14:34:48 -0500464 priv->speed = 100;
465
Mike Frysinger8ef583a2010-12-23 15:40:12 -0500466 if (lpa & LPA_100FULL)
David Updegraffaf1c2b82007-04-20 14:34:48 -0500467 priv->duplexity = 1;
468
Mike Frysinger8ef583a2010-12-23 15:40:12 -0500469 } else if (lpa & LPA_10FULL)
David Updegraffaf1c2b82007-04-20 14:34:48 -0500470 priv->duplexity = 1;
471 } else {
Mike Frysinger8ef583a2010-12-23 15:40:12 -0500472 uint bmcr = read_phy_reg(priv, MII_BMCR);
David Updegraffaf1c2b82007-04-20 14:34:48 -0500473
474 priv->speed = 10;
475 priv->duplexity = 0;
476
Mike Frysinger8ef583a2010-12-23 15:40:12 -0500477 if (bmcr & BMCR_FULLDPLX)
David Updegraffaf1c2b82007-04-20 14:34:48 -0500478 priv->duplexity = 1;
479
Mike Frysinger8ef583a2010-12-23 15:40:12 -0500480 if (bmcr & BMCR_SPEED1000)
David Updegraffaf1c2b82007-04-20 14:34:48 -0500481 priv->speed = 1000;
Mike Frysinger8ef583a2010-12-23 15:40:12 -0500482 else if (bmcr & BMCR_SPEED100)
David Updegraffaf1c2b82007-04-20 14:34:48 -0500483 priv->speed = 100;
484 }
485
486 return 0;
487}
488
Paul Gortmaker91e25762007-01-16 11:38:14 -0500489/*
Zach LeRoy091dc9f2009-05-22 10:26:33 -0500490 * "Ethernet@Wirespeed" needs to be enabled to achieve link in certain
491 * circumstances. eg a gigabit TSEC connected to a gigabit switch with
492 * a 4-wire ethernet cable. Both ends advertise gigabit, but can't
493 * link. "Ethernet@Wirespeed" reduces advertised speed until link
494 * can be achieved.
495 */
Peter Tysere1957ef2009-11-09 13:09:45 -0600496static uint mii_BCM54xx_wirespeed(uint mii_reg, struct tsec_private *priv)
Zach LeRoy091dc9f2009-05-22 10:26:33 -0500497{
498 return (read_phy_reg(priv, mii_reg) & 0x8FFF) | 0x8010;
499}
500
501/*
Paul Gortmaker91e25762007-01-16 11:38:14 -0500502 * Parse the BCM54xx status register for speed and duplex information.
503 * The linux sungem_phy has this information, but in a table format.
504 */
Peter Tysere1957ef2009-11-09 13:09:45 -0600505static uint mii_parse_BCM54xx_sr(uint mii_reg, struct tsec_private *priv)
Paul Gortmaker91e25762007-01-16 11:38:14 -0500506{
Peter Tyser27165b52009-11-09 13:09:44 -0600507 /* If there is no link, speed and duplex don't matter */
508 if (!priv->link)
509 return 0;
Paul Gortmaker91e25762007-01-16 11:38:14 -0500510
Peter Tyser27165b52009-11-09 13:09:44 -0600511 switch ((mii_reg & MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK) >>
512 MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT) {
513 case 1:
514 priv->duplexity = 0;
515 priv->speed = 10;
516 break;
517 case 2:
518 priv->duplexity = 1;
519 priv->speed = 10;
520 break;
521 case 3:
522 priv->duplexity = 0;
523 priv->speed = 100;
524 break;
525 case 5:
526 priv->duplexity = 1;
527 priv->speed = 100;
528 break;
529 case 6:
530 priv->duplexity = 0;
531 priv->speed = 1000;
532 break;
533 case 7:
534 priv->duplexity = 1;
535 priv->speed = 1000;
536 break;
537 default:
538 printf("Auto-neg error, defaulting to 10BT/HD\n");
539 priv->duplexity = 0;
540 priv->speed = 10;
541 break;
Paul Gortmaker91e25762007-01-16 11:38:14 -0500542 }
543
544 return 0;
Paul Gortmaker91e25762007-01-16 11:38:14 -0500545}
Peter Tyser8abb8dc2009-11-09 13:09:47 -0600546
547/*
548 * Find out if PHY is in copper or serdes mode by looking at Expansion Reg
549 * 0x42 - "Operating Mode Status Register"
550 */
551static int BCM8482_is_serdes(struct tsec_private *priv)
552{
553 u16 val;
554 int serdes = 0;
555
556 write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_ER | 0x42);
557 val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA);
558
559 switch (val & 0x1f) {
560 case 0x0d: /* RGMII-to-100Base-FX */
561 case 0x0e: /* RGMII-to-SGMII */
562 case 0x0f: /* RGMII-to-SerDes */
563 case 0x12: /* SGMII-to-SerDes */
564 case 0x13: /* SGMII-to-100Base-FX */
565 case 0x16: /* SerDes-to-Serdes */
566 serdes = 1;
567 break;
568 case 0x6: /* RGMII-to-Copper */
569 case 0x14: /* SGMII-to-Copper */
570 case 0x17: /* SerDes-to-Copper */
571 break;
572 default:
573 printf("ERROR, invalid PHY mode (0x%x\n)", val);
574 break;
575 }
576
577 return serdes;
578}
579
580/*
581 * Determine SerDes link speed and duplex from Expansion reg 0x42 "Operating
582 * Mode Status Register"
583 */
584uint mii_parse_BCM5482_serdes_sr(struct tsec_private *priv)
585{
586 u16 val;
587 int i = 0;
588
589 /* Wait 1s for link - Clause 37 autonegotiation happens very fast */
590 while (1) {
591 write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL,
592 MIIM_BCM54XX_EXP_SEL_ER | 0x42);
593 val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA);
594
595 if (val & 0x8000)
596 break;
597
598 if (i++ > 1000) {
599 priv->link = 0;
600 return 1;
601 }
602
603 udelay(1000); /* 1 ms */
604 }
605
606 priv->link = 1;
607 switch ((val >> 13) & 0x3) {
608 case (0x00):
609 priv->speed = 10;
610 break;
611 case (0x01):
612 priv->speed = 100;
613 break;
614 case (0x02):
615 priv->speed = 1000;
616 break;
617 }
618
619 priv->duplexity = (val & 0x1000) == 0x1000;
620
621 return 0;
622}
623
624/*
625 * Figure out if BCM5482 is in serdes or copper mode and determine link
626 * configuration accordingly
627 */
628static uint mii_parse_BCM5482_sr(uint mii_reg, struct tsec_private *priv)
629{
630 if (BCM8482_is_serdes(priv)) {
631 mii_parse_BCM5482_serdes_sr(priv);
Peter Tyser5f6b1442009-11-09 13:09:48 -0600632 priv->flags |= TSEC_FIBER;
Peter Tyser8abb8dc2009-11-09 13:09:47 -0600633 } else {
634 /* Wait for auto-negotiation to complete or fail */
635 mii_parse_sr(mii_reg, priv);
636
637 /* Parse BCM54xx copper aux status register */
638 mii_reg = read_phy_reg(priv, MIIM_BCM54xx_AUXSTATUS);
639 mii_parse_BCM54xx_sr(mii_reg, priv);
640 }
641
642 return 0;
643}
644
wdenk97d80fc2004-06-09 00:34:46 +0000645/* Parse the 88E1011's status register for speed and duplex
Jon Loeliger89875e92006-10-10 17:03:43 -0500646 * information
647 */
Peter Tysere1957ef2009-11-09 13:09:45 -0600648static uint mii_parse_88E1011_psr(uint mii_reg, struct tsec_private * priv)
wdenk97d80fc2004-06-09 00:34:46 +0000649{
650 uint speed;
651
Stefan Roese5810dc32005-09-21 18:20:22 +0200652 mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);
653
Andy Fleming7613afd2007-08-15 20:03:44 -0500654 if ((mii_reg & MIIM_88E1011_PHYSTAT_LINK) &&
655 !(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
Stefan Roese5810dc32005-09-21 18:20:22 +0200656 int i = 0;
657
Jon Loeliger89875e92006-10-10 17:03:43 -0500658 puts("Waiting for PHY realtime link");
Andy Fleming7613afd2007-08-15 20:03:44 -0500659 while (!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
660 /* Timeout reached ? */
Stefan Roese5810dc32005-09-21 18:20:22 +0200661 if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
Jon Loeliger89875e92006-10-10 17:03:43 -0500662 puts(" TIMEOUT !\n");
Stefan Roese5810dc32005-09-21 18:20:22 +0200663 priv->link = 0;
664 break;
665 }
666
667 if ((i++ % 1000) == 0) {
Jon Loeliger89875e92006-10-10 17:03:43 -0500668 putc('.');
Stefan Roese5810dc32005-09-21 18:20:22 +0200669 }
Jon Loeliger89875e92006-10-10 17:03:43 -0500670 udelay(1000); /* 1 ms */
Stefan Roese5810dc32005-09-21 18:20:22 +0200671 mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);
672 }
Jon Loeliger89875e92006-10-10 17:03:43 -0500673 puts(" done\n");
674 udelay(500000); /* another 500 ms (results in faster booting) */
Andy Fleming7613afd2007-08-15 20:03:44 -0500675 } else {
676 if (mii_reg & MIIM_88E1011_PHYSTAT_LINK)
677 priv->link = 1;
678 else
679 priv->link = 0;
Stefan Roese5810dc32005-09-21 18:20:22 +0200680 }
681
Jon Loeliger89875e92006-10-10 17:03:43 -0500682 if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX)
wdenk97d80fc2004-06-09 00:34:46 +0000683 priv->duplexity = 1;
684 else
685 priv->duplexity = 0;
686
Jon Loeliger89875e92006-10-10 17:03:43 -0500687 speed = (mii_reg & MIIM_88E1011_PHYSTAT_SPEED);
wdenk97d80fc2004-06-09 00:34:46 +0000688
Jon Loeliger89875e92006-10-10 17:03:43 -0500689 switch (speed) {
690 case MIIM_88E1011_PHYSTAT_GBIT:
691 priv->speed = 1000;
692 break;
693 case MIIM_88E1011_PHYSTAT_100:
694 priv->speed = 100;
695 break;
696 default:
697 priv->speed = 10;
wdenk97d80fc2004-06-09 00:34:46 +0000698 }
699
700 return 0;
701}
702
Dave Liu18ee3202008-01-11 18:45:28 +0800703/* Parse the RTL8211B's status register for speed and duplex
704 * information
705 */
Peter Tysere1957ef2009-11-09 13:09:45 -0600706static uint mii_parse_RTL8211B_sr(uint mii_reg, struct tsec_private * priv)
Dave Liu18ee3202008-01-11 18:45:28 +0800707{
708 uint speed;
709
710 mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS);
Anton Vorontsovc7604782008-03-14 23:20:30 +0300711 if (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
Dave Liu18ee3202008-01-11 18:45:28 +0800712 int i = 0;
713
Anton Vorontsovc7604782008-03-14 23:20:30 +0300714 /* in case of timeout ->link is cleared */
715 priv->link = 1;
Dave Liu18ee3202008-01-11 18:45:28 +0800716 puts("Waiting for PHY realtime link");
717 while (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
718 /* Timeout reached ? */
719 if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
720 puts(" TIMEOUT !\n");
721 priv->link = 0;
722 break;
723 }
724
725 if ((i++ % 1000) == 0) {
726 putc('.');
727 }
728 udelay(1000); /* 1 ms */
729 mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS);
730 }
731 puts(" done\n");
732 udelay(500000); /* another 500 ms (results in faster booting) */
733 } else {
734 if (mii_reg & MIIM_RTL8211B_PHYSTAT_LINK)
735 priv->link = 1;
736 else
737 priv->link = 0;
738 }
739
740 if (mii_reg & MIIM_RTL8211B_PHYSTAT_DUPLEX)
741 priv->duplexity = 1;
742 else
743 priv->duplexity = 0;
744
745 speed = (mii_reg & MIIM_RTL8211B_PHYSTAT_SPEED);
746
747 switch (speed) {
748 case MIIM_RTL8211B_PHYSTAT_GBIT:
749 priv->speed = 1000;
750 break;
751 case MIIM_RTL8211B_PHYSTAT_100:
752 priv->speed = 100;
753 break;
754 default:
755 priv->speed = 10;
756 }
757
758 return 0;
759}
760
wdenk97d80fc2004-06-09 00:34:46 +0000761/* Parse the cis8201's status register for speed and duplex
Jon Loeliger89875e92006-10-10 17:03:43 -0500762 * information
763 */
Peter Tysere1957ef2009-11-09 13:09:45 -0600764static uint mii_parse_cis8201(uint mii_reg, struct tsec_private * priv)
wdenk97d80fc2004-06-09 00:34:46 +0000765{
766 uint speed;
767
Jon Loeliger89875e92006-10-10 17:03:43 -0500768 if (mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX)
wdenk97d80fc2004-06-09 00:34:46 +0000769 priv->duplexity = 1;
770 else
771 priv->duplexity = 0;
772
773 speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED;
Jon Loeliger89875e92006-10-10 17:03:43 -0500774 switch (speed) {
775 case MIIM_CIS8201_AUXCONSTAT_GBIT:
776 priv->speed = 1000;
777 break;
778 case MIIM_CIS8201_AUXCONSTAT_100:
779 priv->speed = 100;
780 break;
781 default:
782 priv->speed = 10;
783 break;
wdenk97d80fc2004-06-09 00:34:46 +0000784 }
785
786 return 0;
787}
Jon Loeliger89875e92006-10-10 17:03:43 -0500788
Jon Loeligerdebb7352006-04-26 17:58:56 -0500789/* Parse the vsc8244's status register for speed and duplex
Jon Loeliger89875e92006-10-10 17:03:43 -0500790 * information
791 */
Peter Tysere1957ef2009-11-09 13:09:45 -0600792static uint mii_parse_vsc8244(uint mii_reg, struct tsec_private * priv)
Jon Loeligerdebb7352006-04-26 17:58:56 -0500793{
Jon Loeliger89875e92006-10-10 17:03:43 -0500794 uint speed;
795
796 if (mii_reg & MIIM_VSC8244_AUXCONSTAT_DUPLEX)
797 priv->duplexity = 1;
798 else
799 priv->duplexity = 0;
800
801 speed = mii_reg & MIIM_VSC8244_AUXCONSTAT_SPEED;
802 switch (speed) {
803 case MIIM_VSC8244_AUXCONSTAT_GBIT:
804 priv->speed = 1000;
805 break;
806 case MIIM_VSC8244_AUXCONSTAT_100:
807 priv->speed = 100;
808 break;
809 default:
810 priv->speed = 10;
811 break;
812 }
813
814 return 0;
Jon Loeligerdebb7352006-04-26 17:58:56 -0500815}
wdenk97d80fc2004-06-09 00:34:46 +0000816
wdenk97d80fc2004-06-09 00:34:46 +0000817/* Parse the DM9161's status register for speed and duplex
Jon Loeliger89875e92006-10-10 17:03:43 -0500818 * information
819 */
Peter Tysere1957ef2009-11-09 13:09:45 -0600820static uint mii_parse_dm9161_scsr(uint mii_reg, struct tsec_private * priv)
wdenk97d80fc2004-06-09 00:34:46 +0000821{
Jon Loeliger89875e92006-10-10 17:03:43 -0500822 if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H))
wdenk97d80fc2004-06-09 00:34:46 +0000823 priv->speed = 100;
824 else
825 priv->speed = 10;
826
Jon Loeliger89875e92006-10-10 17:03:43 -0500827 if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F))
wdenk97d80fc2004-06-09 00:34:46 +0000828 priv->duplexity = 1;
829 else
830 priv->duplexity = 0;
831
832 return 0;
833}
834
Jon Loeliger89875e92006-10-10 17:03:43 -0500835/*
836 * Hack to write all 4 PHYs with the LED values
837 */
Peter Tysere1957ef2009-11-09 13:09:45 -0600838static uint mii_cis8204_fixled(uint mii_reg, struct tsec_private * priv)
wdenk97d80fc2004-06-09 00:34:46 +0000839{
840 uint phyid;
Sandeep Gopalpetb9e186f2009-10-31 00:35:04 +0530841 volatile tsec_mdio_t *regbase = priv->phyregs;
Jon Loeliger89875e92006-10-10 17:03:43 -0500842 int timeout = 1000000;
wdenk97d80fc2004-06-09 00:34:46 +0000843
Jon Loeliger89875e92006-10-10 17:03:43 -0500844 for (phyid = 0; phyid < 4; phyid++) {
wdenk97d80fc2004-06-09 00:34:46 +0000845 regbase->miimadd = (phyid << 8) | mii_reg;
846 regbase->miimcon = MIIM_CIS8204_SLEDCON_INIT;
Eran Libertyf046ccd2005-07-28 10:08:46 -0500847 asm("sync");
wdenk97d80fc2004-06-09 00:34:46 +0000848
Jon Loeliger89875e92006-10-10 17:03:43 -0500849 timeout = 1000000;
850 while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ;
wdenk97d80fc2004-06-09 00:34:46 +0000851 }
852
853 return MIIM_CIS8204_SLEDCON_INIT;
854}
855
Peter Tysere1957ef2009-11-09 13:09:45 -0600856static uint mii_cis8204_setmode(uint mii_reg, struct tsec_private * priv)
Jon Loeligerd9b94f22005-07-25 14:05:07 -0500857{
858 if (priv->flags & TSEC_REDUCED)
859 return MIIM_CIS8204_EPHYCON_INIT | MIIM_CIS8204_EPHYCON_RGMII;
860 else
861 return MIIM_CIS8204_EPHYCON_INIT;
862}
wdenk97d80fc2004-06-09 00:34:46 +0000863
Peter Tysere1957ef2009-11-09 13:09:45 -0600864static uint mii_m88e1111s_setmode(uint mii_reg, struct tsec_private *priv)
Dave Liu19580e62007-09-18 12:37:57 +0800865{
866 uint mii_data = read_phy_reg(priv, mii_reg);
867
868 if (priv->flags & TSEC_REDUCED)
869 mii_data = (mii_data & 0xfff0) | 0x000b;
870 return mii_data;
871}
872
wdenk97d80fc2004-06-09 00:34:46 +0000873/* Initialized required registers to appropriate values, zeroing
874 * those we don't care about (unless zero is bad, in which case,
Jon Loeliger89875e92006-10-10 17:03:43 -0500875 * choose a more appropriate value)
876 */
877static void init_registers(volatile tsec_t * regs)
wdenk42d1f032003-10-15 23:53:47 +0000878{
879 /* Clear IEVENT */
880 regs->ievent = IEVENT_INIT_CLEAR;
881
882 regs->imask = IMASK_INIT_CLEAR;
883
884 regs->hash.iaddr0 = 0;
885 regs->hash.iaddr1 = 0;
886 regs->hash.iaddr2 = 0;
887 regs->hash.iaddr3 = 0;
888 regs->hash.iaddr4 = 0;
889 regs->hash.iaddr5 = 0;
890 regs->hash.iaddr6 = 0;
891 regs->hash.iaddr7 = 0;
892
893 regs->hash.gaddr0 = 0;
894 regs->hash.gaddr1 = 0;
895 regs->hash.gaddr2 = 0;
896 regs->hash.gaddr3 = 0;
897 regs->hash.gaddr4 = 0;
898 regs->hash.gaddr5 = 0;
899 regs->hash.gaddr6 = 0;
900 regs->hash.gaddr7 = 0;
901
902 regs->rctrl = 0x00000000;
903
904 /* Init RMON mib registers */
905 memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t));
906
907 regs->rmon.cam1 = 0xffffffff;
908 regs->rmon.cam2 = 0xffffffff;
909
910 regs->mrblr = MRBLR_INIT_SETTINGS;
911
912 regs->minflr = MINFLR_INIT_SETTINGS;
913
914 regs->attr = ATTR_INIT_SETTINGS;
915 regs->attreli = ATTRELI_INIT_SETTINGS;
916
917}
918
wdenk97d80fc2004-06-09 00:34:46 +0000919/* Configure maccfg2 based on negotiated speed and duplex
Jon Loeliger89875e92006-10-10 17:03:43 -0500920 * reported by PHY handling code
921 */
wdenk97d80fc2004-06-09 00:34:46 +0000922static void adjust_link(struct eth_device *dev)
923{
924 struct tsec_private *priv = (struct tsec_private *)dev->priv;
925 volatile tsec_t *regs = priv->regs;
926
Jon Loeliger89875e92006-10-10 17:03:43 -0500927 if (priv->link) {
928 if (priv->duplexity != 0)
wdenk97d80fc2004-06-09 00:34:46 +0000929 regs->maccfg2 |= MACCFG2_FULL_DUPLEX;
930 else
931 regs->maccfg2 &= ~(MACCFG2_FULL_DUPLEX);
932
Jon Loeliger89875e92006-10-10 17:03:43 -0500933 switch (priv->speed) {
934 case 1000:
935 regs->maccfg2 = ((regs->maccfg2 & ~(MACCFG2_IF))
936 | MACCFG2_GMII);
937 break;
938 case 100:
939 case 10:
940 regs->maccfg2 = ((regs->maccfg2 & ~(MACCFG2_IF))
941 | MACCFG2_MII);
Jon Loeligerd9b94f22005-07-25 14:05:07 -0500942
Nick Spencef484dc72006-09-07 07:39:46 -0700943 /* Set R100 bit in all modes although
944 * it is only used in RGMII mode
Jon Loeliger89875e92006-10-10 17:03:43 -0500945 */
Nick Spencef484dc72006-09-07 07:39:46 -0700946 if (priv->speed == 100)
Jon Loeliger89875e92006-10-10 17:03:43 -0500947 regs->ecntrl |= ECNTRL_R100;
948 else
949 regs->ecntrl &= ~(ECNTRL_R100);
950 break;
951 default:
952 printf("%s: Speed was bad\n", dev->name);
953 break;
wdenk97d80fc2004-06-09 00:34:46 +0000954 }
955
Peter Tyser5f6b1442009-11-09 13:09:48 -0600956 printf("Speed: %d, %s duplex%s\n", priv->speed,
957 (priv->duplexity) ? "full" : "half",
958 (priv->flags & TSEC_FIBER) ? ", fiber mode" : "");
wdenk97d80fc2004-06-09 00:34:46 +0000959
960 } else {
961 printf("%s: No link.\n", dev->name);
962 }
963}
964
wdenk97d80fc2004-06-09 00:34:46 +0000965/* Set up the buffers and their descriptors, and bring up the
Jon Loeliger89875e92006-10-10 17:03:43 -0500966 * interface
967 */
wdenk97d80fc2004-06-09 00:34:46 +0000968static void startup_tsec(struct eth_device *dev)
wdenk42d1f032003-10-15 23:53:47 +0000969{
970 int i;
wdenk97d80fc2004-06-09 00:34:46 +0000971 struct tsec_private *priv = (struct tsec_private *)dev->priv;
972 volatile tsec_t *regs = priv->regs;
wdenk42d1f032003-10-15 23:53:47 +0000973
974 /* Point to the buffer descriptors */
975 regs->tbase = (unsigned int)(&rtx.txbd[txIdx]);
976 regs->rbase = (unsigned int)(&rtx.rxbd[rxIdx]);
977
978 /* Initialize the Rx Buffer descriptors */
979 for (i = 0; i < PKTBUFSRX; i++) {
980 rtx.rxbd[i].status = RXBD_EMPTY;
981 rtx.rxbd[i].length = 0;
Jon Loeliger89875e92006-10-10 17:03:43 -0500982 rtx.rxbd[i].bufPtr = (uint) NetRxPackets[i];
wdenk42d1f032003-10-15 23:53:47 +0000983 }
Jon Loeliger89875e92006-10-10 17:03:43 -0500984 rtx.rxbd[PKTBUFSRX - 1].status |= RXBD_WRAP;
wdenk42d1f032003-10-15 23:53:47 +0000985
986 /* Initialize the TX Buffer Descriptors */
Jon Loeliger89875e92006-10-10 17:03:43 -0500987 for (i = 0; i < TX_BUF_CNT; i++) {
wdenk42d1f032003-10-15 23:53:47 +0000988 rtx.txbd[i].status = 0;
989 rtx.txbd[i].length = 0;
990 rtx.txbd[i].bufPtr = 0;
991 }
Jon Loeliger89875e92006-10-10 17:03:43 -0500992 rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP;
wdenk42d1f032003-10-15 23:53:47 +0000993
wdenk97d80fc2004-06-09 00:34:46 +0000994 /* Start up the PHY */
Ben Warren4653f912006-10-26 14:38:25 -0400995 if(priv->phyinfo)
996 phy_run_commands(priv, priv->phyinfo->startup);
David Updegraffaf1c2b82007-04-20 14:34:48 -0500997
wdenk97d80fc2004-06-09 00:34:46 +0000998 adjust_link(dev);
999
wdenk42d1f032003-10-15 23:53:47 +00001000 /* Enable Transmit and Receive */
1001 regs->maccfg1 |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
1002
1003 /* Tell the DMA it is clear to go */
1004 regs->dmactrl |= DMACTRL_INIT_SETTINGS;
1005 regs->tstat = TSTAT_CLEAR_THALT;
Dan Wilson5c7ea642007-10-19 11:33:48 -05001006 regs->rstat = RSTAT_CLEAR_RHALT;
wdenk42d1f032003-10-15 23:53:47 +00001007 regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
1008}
1009
wdenk9d46ea42005-03-14 23:56:42 +00001010/* This returns the status bits of the device. The return value
wdenk42d1f032003-10-15 23:53:47 +00001011 * is never checked, and this is what the 8260 driver did, so we
wdenk9d46ea42005-03-14 23:56:42 +00001012 * do the same. Presumably, this would be zero if there were no
Jon Loeliger89875e92006-10-10 17:03:43 -05001013 * errors
1014 */
1015static int tsec_send(struct eth_device *dev, volatile void *packet, int length)
wdenk42d1f032003-10-15 23:53:47 +00001016{
1017 int i;
1018 int result = 0;
wdenk97d80fc2004-06-09 00:34:46 +00001019 struct tsec_private *priv = (struct tsec_private *)dev->priv;
1020 volatile tsec_t *regs = priv->regs;
wdenk42d1f032003-10-15 23:53:47 +00001021
1022 /* Find an empty buffer descriptor */
Jon Loeliger89875e92006-10-10 17:03:43 -05001023 for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
wdenk42d1f032003-10-15 23:53:47 +00001024 if (i >= TOUT_LOOP) {
Jon Loeliger89875e92006-10-10 17:03:43 -05001025 debug("%s: tsec: tx buffers full\n", dev->name);
wdenk42d1f032003-10-15 23:53:47 +00001026 return result;
1027 }
1028 }
1029
Jon Loeliger89875e92006-10-10 17:03:43 -05001030 rtx.txbd[txIdx].bufPtr = (uint) packet;
wdenk42d1f032003-10-15 23:53:47 +00001031 rtx.txbd[txIdx].length = length;
Jon Loeliger89875e92006-10-10 17:03:43 -05001032 rtx.txbd[txIdx].status |=
1033 (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT);
wdenk42d1f032003-10-15 23:53:47 +00001034
1035 /* Tell the DMA to go */
1036 regs->tstat = TSTAT_CLEAR_THALT;
1037
1038 /* Wait for buffer to be transmitted */
Jon Loeliger89875e92006-10-10 17:03:43 -05001039 for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
wdenk42d1f032003-10-15 23:53:47 +00001040 if (i >= TOUT_LOOP) {
Jon Loeliger89875e92006-10-10 17:03:43 -05001041 debug("%s: tsec: tx error\n", dev->name);
wdenk42d1f032003-10-15 23:53:47 +00001042 return result;
1043 }
1044 }
1045
1046 txIdx = (txIdx + 1) % TX_BUF_CNT;
1047 result = rtx.txbd[txIdx].status & TXBD_STATS;
1048
1049 return result;
1050}
1051
Jon Loeliger89875e92006-10-10 17:03:43 -05001052static int tsec_recv(struct eth_device *dev)
wdenk42d1f032003-10-15 23:53:47 +00001053{
1054 int length;
wdenk97d80fc2004-06-09 00:34:46 +00001055 struct tsec_private *priv = (struct tsec_private *)dev->priv;
1056 volatile tsec_t *regs = priv->regs;
wdenk42d1f032003-10-15 23:53:47 +00001057
Jon Loeliger89875e92006-10-10 17:03:43 -05001058 while (!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) {
wdenk42d1f032003-10-15 23:53:47 +00001059
1060 length = rtx.rxbd[rxIdx].length;
1061
1062 /* Send the packet up if there were no errors */
1063 if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) {
1064 NetReceive(NetRxPackets[rxIdx], length - 4);
wdenk97d80fc2004-06-09 00:34:46 +00001065 } else {
1066 printf("Got error %x\n",
Jon Loeliger89875e92006-10-10 17:03:43 -05001067 (rtx.rxbd[rxIdx].status & RXBD_STATS));
wdenk42d1f032003-10-15 23:53:47 +00001068 }
1069
1070 rtx.rxbd[rxIdx].length = 0;
1071
1072 /* Set the wrap bit if this is the last element in the list */
Jon Loeliger89875e92006-10-10 17:03:43 -05001073 rtx.rxbd[rxIdx].status =
1074 RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0);
wdenk42d1f032003-10-15 23:53:47 +00001075
1076 rxIdx = (rxIdx + 1) % PKTBUFSRX;
1077 }
1078
Jon Loeliger89875e92006-10-10 17:03:43 -05001079 if (regs->ievent & IEVENT_BSY) {
wdenk42d1f032003-10-15 23:53:47 +00001080 regs->ievent = IEVENT_BSY;
1081 regs->rstat = RSTAT_CLEAR_RHALT;
1082 }
1083
1084 return -1;
1085
1086}
1087
wdenk97d80fc2004-06-09 00:34:46 +00001088/* Stop the interface */
Jon Loeliger89875e92006-10-10 17:03:43 -05001089static void tsec_halt(struct eth_device *dev)
wdenk42d1f032003-10-15 23:53:47 +00001090{
wdenk97d80fc2004-06-09 00:34:46 +00001091 struct tsec_private *priv = (struct tsec_private *)dev->priv;
1092 volatile tsec_t *regs = priv->regs;
wdenk42d1f032003-10-15 23:53:47 +00001093
1094 regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
1095 regs->dmactrl |= (DMACTRL_GRS | DMACTRL_GTS);
1096
Andy Fleming538be582010-04-19 14:54:49 -05001097 while ((regs->ievent & (IEVENT_GRSC | IEVENT_GTSC))
1098 != (IEVENT_GRSC | IEVENT_GTSC)) ;
wdenk42d1f032003-10-15 23:53:47 +00001099
1100 regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN);
1101
wdenk97d80fc2004-06-09 00:34:46 +00001102 /* Shut down the PHY, as needed */
Ben Warren4653f912006-10-26 14:38:25 -04001103 if(priv->phyinfo)
1104 phy_run_commands(priv, priv->phyinfo->shutdown);
wdenk42d1f032003-10-15 23:53:47 +00001105}
wdenk7abf0c52004-04-18 21:45:42 +00001106
Peter Tysere1957ef2009-11-09 13:09:45 -06001107static struct phy_info phy_info_M88E1149S = {
Wolfgang Denk5728be32007-08-06 01:01:49 +02001108 0x1410ca,
1109 "Marvell 88E1149S",
1110 4,
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001111 (struct phy_cmd[]) { /* config */
Wolfgang Denk5728be32007-08-06 01:01:49 +02001112 /* Reset and configure the PHY */
1113 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1114 {0x1d, 0x1f, NULL},
1115 {0x1e, 0x200c, NULL},
1116 {0x1d, 0x5, NULL},
1117 {0x1e, 0x0, NULL},
1118 {0x1e, 0x100, NULL},
1119 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1120 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1121 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1122 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1123 {miim_end,}
1124 },
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001125 (struct phy_cmd[]) { /* startup */
Wolfgang Denk5728be32007-08-06 01:01:49 +02001126 /* Status is read once to clear old link state */
1127 {MIIM_STATUS, miim_read, NULL},
1128 /* Auto-negotiate */
1129 {MIIM_STATUS, miim_read, &mii_parse_sr},
1130 /* Read the status */
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001131 {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr},
Wolfgang Denk5728be32007-08-06 01:01:49 +02001132 {miim_end,}
1133 },
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001134 (struct phy_cmd[]) { /* shutdown */
Wolfgang Denk5728be32007-08-06 01:01:49 +02001135 {miim_end,}
1136 },
Andy Flemingc7e717e2007-08-03 04:05:25 -05001137};
1138
Paul Gortmaker91e25762007-01-16 11:38:14 -05001139/* The 5411 id is 0x206070, the 5421 is 0x2060e0 */
Peter Tysere1957ef2009-11-09 13:09:45 -06001140static struct phy_info phy_info_BCM5461S = {
Paul Gortmaker91e25762007-01-16 11:38:14 -05001141 0x02060c1, /* 5461 ID */
1142 "Broadcom BCM5461S",
1143 0, /* not clear to me what minor revisions we can shift away */
1144 (struct phy_cmd[]) { /* config */
1145 /* Reset and configure the PHY */
1146 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1147 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1148 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1149 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1150 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1151 {miim_end,}
1152 },
1153 (struct phy_cmd[]) { /* startup */
1154 /* Status is read once to clear old link state */
1155 {MIIM_STATUS, miim_read, NULL},
1156 /* Auto-negotiate */
1157 {MIIM_STATUS, miim_read, &mii_parse_sr},
1158 /* Read the status */
1159 {MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr},
1160 {miim_end,}
1161 },
1162 (struct phy_cmd[]) { /* shutdown */
1163 {miim_end,}
1164 },
1165};
1166
Peter Tysere1957ef2009-11-09 13:09:45 -06001167static struct phy_info phy_info_BCM5464S = {
Joe Hammanc3243cf2007-04-30 16:47:28 -05001168 0x02060b1, /* 5464 ID */
1169 "Broadcom BCM5464S",
1170 0, /* not clear to me what minor revisions we can shift away */
1171 (struct phy_cmd[]) { /* config */
1172 /* Reset and configure the PHY */
1173 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1174 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1175 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1176 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1177 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1178 {miim_end,}
1179 },
1180 (struct phy_cmd[]) { /* startup */
1181 /* Status is read once to clear old link state */
1182 {MIIM_STATUS, miim_read, NULL},
1183 /* Auto-negotiate */
1184 {MIIM_STATUS, miim_read, &mii_parse_sr},
1185 /* Read the status */
1186 {MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr},
1187 {miim_end,}
1188 },
1189 (struct phy_cmd[]) { /* shutdown */
1190 {miim_end,}
1191 },
1192};
1193
Peter Tysere1957ef2009-11-09 13:09:45 -06001194static struct phy_info phy_info_BCM5482S = {
Zach LeRoy091dc9f2009-05-22 10:26:33 -05001195 0x0143bcb,
1196 "Broadcom BCM5482S",
1197 4,
1198 (struct phy_cmd[]) { /* config */
1199 /* Reset and configure the PHY */
1200 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1201 /* Setup read from auxilary control shadow register 7 */
1202 {MIIM_BCM54xx_AUXCNTL, MIIM_BCM54xx_AUXCNTL_ENCODE(7), NULL},
1203 /* Read Misc Control register and or in Ethernet@Wirespeed */
1204 {MIIM_BCM54xx_AUXCNTL, 0, &mii_BCM54xx_wirespeed},
1205 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
Peter Tyser8abb8dc2009-11-09 13:09:47 -06001206 /* Initial config/enable of secondary SerDes interface */
1207 {MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x14, 0xf), NULL},
1208 /* Write intial value to secondary SerDes Contol */
1209 {MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_SSD | 0, NULL},
1210 {MIIM_BCM54XX_EXP_DATA, MIIM_CONTROL_RESTART, NULL},
1211 /* Enable copper/fiber auto-detect */
1212 {MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x1e, 0x201)},
Zach LeRoy091dc9f2009-05-22 10:26:33 -05001213 {miim_end,}
1214 },
1215 (struct phy_cmd[]) { /* startup */
1216 /* Status is read once to clear old link state */
1217 {MIIM_STATUS, miim_read, NULL},
Peter Tyser8abb8dc2009-11-09 13:09:47 -06001218 /* Determine copper/fiber, auto-negotiate, and read the result */
1219 {MIIM_STATUS, miim_read, &mii_parse_BCM5482_sr},
Zach LeRoy091dc9f2009-05-22 10:26:33 -05001220 {miim_end,}
1221 },
1222 (struct phy_cmd[]) { /* shutdown */
1223 {miim_end,}
1224 },
1225};
1226
Peter Tysere1957ef2009-11-09 13:09:45 -06001227static struct phy_info phy_info_M88E1011S = {
wdenk97d80fc2004-06-09 00:34:46 +00001228 0x01410c6,
1229 "Marvell 88E1011S",
1230 4,
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001231 (struct phy_cmd[]) { /* config */
1232 /* Reset and configure the PHY */
1233 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1234 {0x1d, 0x1f, NULL},
1235 {0x1e, 0x200c, NULL},
1236 {0x1d, 0x5, NULL},
1237 {0x1e, 0x0, NULL},
1238 {0x1e, 0x100, NULL},
1239 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1240 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1241 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1242 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1243 {miim_end,}
1244 },
1245 (struct phy_cmd[]) { /* startup */
1246 /* Status is read once to clear old link state */
1247 {MIIM_STATUS, miim_read, NULL},
1248 /* Auto-negotiate */
1249 {MIIM_STATUS, miim_read, &mii_parse_sr},
1250 /* Read the status */
1251 {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr},
1252 {miim_end,}
1253 },
1254 (struct phy_cmd[]) { /* shutdown */
1255 {miim_end,}
1256 },
wdenk97d80fc2004-06-09 00:34:46 +00001257};
1258
Peter Tysere1957ef2009-11-09 13:09:45 -06001259static struct phy_info phy_info_M88E1111S = {
wdenk9d46ea42005-03-14 23:56:42 +00001260 0x01410cc,
1261 "Marvell 88E1111S",
1262 4,
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001263 (struct phy_cmd[]) { /* config */
1264 /* Reset and configure the PHY */
1265 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1266 {0x1b, 0x848f, &mii_m88e1111s_setmode},
1267 {0x14, 0x0cd2, NULL}, /* Delay RGMII TX and RX */
1268 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1269 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1270 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1271 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1272 {miim_end,}
1273 },
1274 (struct phy_cmd[]) { /* startup */
1275 /* Status is read once to clear old link state */
1276 {MIIM_STATUS, miim_read, NULL},
1277 /* Auto-negotiate */
1278 {MIIM_STATUS, miim_read, &mii_parse_sr},
1279 /* Read the status */
1280 {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr},
1281 {miim_end,}
1282 },
1283 (struct phy_cmd[]) { /* shutdown */
1284 {miim_end,}
1285 },
wdenk9d46ea42005-03-14 23:56:42 +00001286};
1287
Peter Tysere1957ef2009-11-09 13:09:45 -06001288static struct phy_info phy_info_M88E1118 = {
Ron Madrid290ef642008-05-23 15:37:05 -07001289 0x01410e1,
1290 "Marvell 88E1118",
1291 4,
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001292 (struct phy_cmd[]) { /* config */
Ron Madrid290ef642008-05-23 15:37:05 -07001293 /* Reset and configure the PHY */
1294 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1295 {0x16, 0x0002, NULL}, /* Change Page Number */
1296 {0x15, 0x1070, NULL}, /* Delay RGMII TX and RX */
Ron Madrid12a8b9d2009-01-28 16:17:21 -08001297 {0x16, 0x0003, NULL}, /* Change Page Number */
1298 {0x10, 0x021e, NULL}, /* Adjust LED control */
1299 {0x16, 0x0000, NULL}, /* Change Page Number */
Ron Madrid290ef642008-05-23 15:37:05 -07001300 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1301 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1302 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1303 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1304 {miim_end,}
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001305 },
1306 (struct phy_cmd[]) { /* startup */
Ron Madrid290ef642008-05-23 15:37:05 -07001307 {0x16, 0x0000, NULL}, /* Change Page Number */
1308 /* Status is read once to clear old link state */
1309 {MIIM_STATUS, miim_read, NULL},
1310 /* Auto-negotiate */
Ron Madrid12a8b9d2009-01-28 16:17:21 -08001311 {MIIM_STATUS, miim_read, &mii_parse_sr},
Ron Madrid290ef642008-05-23 15:37:05 -07001312 /* Read the status */
1313 {MIIM_88E1011_PHY_STATUS, miim_read,
1314 &mii_parse_88E1011_psr},
1315 {miim_end,}
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001316 },
1317 (struct phy_cmd[]) { /* shutdown */
Ron Madrid290ef642008-05-23 15:37:05 -07001318 {miim_end,}
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001319 },
Ron Madrid290ef642008-05-23 15:37:05 -07001320};
1321
Sergei Poselenovd23dc392008-06-06 15:52:44 +02001322/*
1323 * Since to access LED register we need do switch the page, we
1324 * do LED configuring in the miim_read-like function as follows
1325 */
Peter Tysere1957ef2009-11-09 13:09:45 -06001326static uint mii_88E1121_set_led (uint mii_reg, struct tsec_private *priv)
Sergei Poselenovd23dc392008-06-06 15:52:44 +02001327{
1328 uint pg;
1329
1330 /* Switch the page to access the led register */
1331 pg = read_phy_reg(priv, MIIM_88E1121_PHY_PAGE);
1332 write_phy_reg(priv, MIIM_88E1121_PHY_PAGE, MIIM_88E1121_PHY_LED_PAGE);
1333
1334 /* Configure leds */
1335 write_phy_reg(priv, MIIM_88E1121_PHY_LED_CTRL,
1336 MIIM_88E1121_PHY_LED_DEF);
1337
1338 /* Restore the page pointer */
1339 write_phy_reg(priv, MIIM_88E1121_PHY_PAGE, pg);
1340 return 0;
1341}
1342
Peter Tysere1957ef2009-11-09 13:09:45 -06001343static struct phy_info phy_info_M88E1121R = {
Sergei Poselenovd23dc392008-06-06 15:52:44 +02001344 0x01410cb,
1345 "Marvell 88E1121R",
1346 4,
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001347 (struct phy_cmd[]) { /* config */
1348 /* Reset and configure the PHY */
1349 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1350 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1351 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1352 /* Configure leds */
1353 {MIIM_88E1121_PHY_LED_CTRL, miim_read, &mii_88E1121_set_led},
1354 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1355 /* Disable IRQs and de-assert interrupt */
1356 {MIIM_88E1121_PHY_IRQ_EN, 0, NULL},
1357 {MIIM_88E1121_PHY_IRQ_STATUS, miim_read, NULL},
1358 {miim_end,}
1359 },
1360 (struct phy_cmd[]) { /* startup */
1361 /* Status is read once to clear old link state */
1362 {MIIM_STATUS, miim_read, NULL},
1363 {MIIM_STATUS, miim_read, &mii_parse_sr},
1364 {MIIM_STATUS, miim_read, &mii_parse_link},
1365 {miim_end,}
1366 },
1367 (struct phy_cmd[]) { /* shutdown */
1368 {miim_end,}
1369 },
Sergei Poselenovd23dc392008-06-06 15:52:44 +02001370};
1371
Andy Fleming09f3e092006-09-13 10:34:18 -05001372static unsigned int m88e1145_setmode(uint mii_reg, struct tsec_private *priv)
1373{
Andy Fleming09f3e092006-09-13 10:34:18 -05001374 uint mii_data = read_phy_reg(priv, mii_reg);
1375
Andy Fleming09f3e092006-09-13 10:34:18 -05001376 /* Setting MIIM_88E1145_PHY_EXT_CR */
1377 if (priv->flags & TSEC_REDUCED)
1378 return mii_data |
Jon Loeliger89875e92006-10-10 17:03:43 -05001379 MIIM_M88E1145_RGMII_RX_DELAY | MIIM_M88E1145_RGMII_TX_DELAY;
Andy Fleming09f3e092006-09-13 10:34:18 -05001380 else
1381 return mii_data;
1382}
1383
1384static struct phy_info phy_info_M88E1145 = {
1385 0x01410cd,
1386 "Marvell 88E1145",
1387 4,
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001388 (struct phy_cmd[]) { /* config */
1389 /* Reset the PHY */
1390 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
Andy Fleming7507d562007-05-08 17:23:02 -05001391
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001392 /* Errata E0, E1 */
1393 {29, 0x001b, NULL},
1394 {30, 0x418f, NULL},
1395 {29, 0x0016, NULL},
1396 {30, 0xa2da, NULL},
Andy Fleming09f3e092006-09-13 10:34:18 -05001397
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001398 /* Configure the PHY */
1399 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1400 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1401 {MIIM_88E1011_PHY_SCR, MIIM_88E1011_PHY_MDI_X_AUTO, NULL},
1402 {MIIM_88E1145_PHY_EXT_CR, 0, &m88e1145_setmode},
1403 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1404 {MIIM_CONTROL, MIIM_CONTROL_INIT, NULL},
1405 {miim_end,}
1406 },
1407 (struct phy_cmd[]) { /* startup */
1408 /* Status is read once to clear old link state */
1409 {MIIM_STATUS, miim_read, NULL},
1410 /* Auto-negotiate */
1411 {MIIM_STATUS, miim_read, &mii_parse_sr},
1412 {MIIM_88E1111_PHY_LED_CONTROL, MIIM_88E1111_PHY_LED_DIRECT, NULL},
1413 /* Read the Status */
1414 {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr},
1415 {miim_end,}
1416 },
1417 (struct phy_cmd[]) { /* shutdown */
1418 {miim_end,}
1419 },
Andy Fleming09f3e092006-09-13 10:34:18 -05001420};
1421
Peter Tysere1957ef2009-11-09 13:09:45 -06001422static struct phy_info phy_info_cis8204 = {
wdenk97d80fc2004-06-09 00:34:46 +00001423 0x3f11,
1424 "Cicada Cis8204",
1425 6,
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001426 (struct phy_cmd[]) { /* config */
1427 /* Override PHY config settings */
1428 {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL},
1429 /* Configure some basic stuff */
1430 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1431 {MIIM_CIS8204_SLED_CON, MIIM_CIS8204_SLEDCON_INIT,
1432 &mii_cis8204_fixled},
1433 {MIIM_CIS8204_EPHY_CON, MIIM_CIS8204_EPHYCON_INIT,
1434 &mii_cis8204_setmode},
1435 {miim_end,}
1436 },
1437 (struct phy_cmd[]) { /* startup */
1438 /* Read the Status (2x to make sure link is right) */
1439 {MIIM_STATUS, miim_read, NULL},
1440 /* Auto-negotiate */
1441 {MIIM_STATUS, miim_read, &mii_parse_sr},
1442 /* Read the status */
1443 {MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201},
1444 {miim_end,}
1445 },
1446 (struct phy_cmd[]) { /* shutdown */
1447 {miim_end,}
1448 },
wdenk97d80fc2004-06-09 00:34:46 +00001449};
1450
1451/* Cicada 8201 */
Peter Tysere1957ef2009-11-09 13:09:45 -06001452static struct phy_info phy_info_cis8201 = {
wdenk97d80fc2004-06-09 00:34:46 +00001453 0xfc41,
1454 "CIS8201",
1455 4,
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001456 (struct phy_cmd[]) { /* config */
1457 /* Override PHY config settings */
1458 {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL},
1459 /* Set up the interface mode */
1460 {MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL},
1461 /* Configure some basic stuff */
1462 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1463 {miim_end,}
1464 },
1465 (struct phy_cmd[]) { /* startup */
1466 /* Read the Status (2x to make sure link is right) */
1467 {MIIM_STATUS, miim_read, NULL},
1468 /* Auto-negotiate */
1469 {MIIM_STATUS, miim_read, &mii_parse_sr},
1470 /* Read the status */
1471 {MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201},
1472 {miim_end,}
1473 },
1474 (struct phy_cmd[]) { /* shutdown */
1475 {miim_end,}
1476 },
wdenk97d80fc2004-06-09 00:34:46 +00001477};
Peter Tysere1957ef2009-11-09 13:09:45 -06001478
1479static struct phy_info phy_info_VSC8211 = {
Pieter Henning736323a2009-02-22 23:17:15 -08001480 0xfc4b,
1481 "Vitesse VSC8211",
1482 4,
1483 (struct phy_cmd[]) { /* config */
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001484 /* Override PHY config settings */
1485 {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL},
1486 /* Set up the interface mode */
1487 {MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL},
1488 /* Configure some basic stuff */
1489 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1490 {miim_end,}
1491 },
Pieter Henning736323a2009-02-22 23:17:15 -08001492 (struct phy_cmd[]) { /* startup */
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001493 /* Read the Status (2x to make sure link is right) */
1494 {MIIM_STATUS, miim_read, NULL},
1495 /* Auto-negotiate */
1496 {MIIM_STATUS, miim_read, &mii_parse_sr},
1497 /* Read the status */
1498 {MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201},
1499 {miim_end,}
1500 },
Pieter Henning736323a2009-02-22 23:17:15 -08001501 (struct phy_cmd[]) { /* shutdown */
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001502 {miim_end,}
Pieter Henning736323a2009-02-22 23:17:15 -08001503 },
1504};
Peter Tysere1957ef2009-11-09 13:09:45 -06001505
1506static struct phy_info phy_info_VSC8244 = {
Jon Loeliger89875e92006-10-10 17:03:43 -05001507 0x3f1b,
1508 "Vitesse VSC8244",
1509 6,
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001510 (struct phy_cmd[]) { /* config */
1511 /* Override PHY config settings */
1512 /* Configure some basic stuff */
1513 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1514 {miim_end,}
1515 },
1516 (struct phy_cmd[]) { /* startup */
1517 /* Read the Status (2x to make sure link is right) */
1518 {MIIM_STATUS, miim_read, NULL},
1519 /* Auto-negotiate */
1520 {MIIM_STATUS, miim_read, &mii_parse_sr},
1521 /* Read the status */
1522 {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244},
1523 {miim_end,}
1524 },
1525 (struct phy_cmd[]) { /* shutdown */
1526 {miim_end,}
1527 },
Jon Loeligerdebb7352006-04-26 17:58:56 -05001528};
wdenk97d80fc2004-06-09 00:34:46 +00001529
Peter Tysere1957ef2009-11-09 13:09:45 -06001530static struct phy_info phy_info_VSC8641 = {
Poonam Aggrwalb7fe25d2009-07-02 16:15:13 +05301531 0x7043,
1532 "Vitesse VSC8641",
1533 4,
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001534 (struct phy_cmd[]) { /* config */
1535 /* Configure some basic stuff */
1536 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1537 {miim_end,}
1538 },
1539 (struct phy_cmd[]) { /* startup */
1540 /* Read the Status (2x to make sure link is right) */
1541 {MIIM_STATUS, miim_read, NULL},
1542 /* Auto-negotiate */
1543 {MIIM_STATUS, miim_read, &mii_parse_sr},
1544 /* Read the status */
1545 {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244},
1546 {miim_end,}
1547 },
1548 (struct phy_cmd[]) { /* shutdown */
1549 {miim_end,}
1550 },
Poonam Aggrwalb7fe25d2009-07-02 16:15:13 +05301551};
1552
Peter Tysere1957ef2009-11-09 13:09:45 -06001553static struct phy_info phy_info_VSC8221 = {
Poonam Aggrwalb7fe25d2009-07-02 16:15:13 +05301554 0xfc55,
1555 "Vitesse VSC8221",
1556 4,
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001557 (struct phy_cmd[]) { /* config */
1558 /* Configure some basic stuff */
1559 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1560 {miim_end,}
1561 },
1562 (struct phy_cmd[]) { /* startup */
1563 /* Read the Status (2x to make sure link is right) */
1564 {MIIM_STATUS, miim_read, NULL},
1565 /* Auto-negotiate */
1566 {MIIM_STATUS, miim_read, &mii_parse_sr},
1567 /* Read the status */
1568 {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244},
1569 {miim_end,}
1570 },
1571 (struct phy_cmd[]) { /* shutdown */
1572 {miim_end,}
1573 },
Poonam Aggrwalb7fe25d2009-07-02 16:15:13 +05301574};
1575
Peter Tysere1957ef2009-11-09 13:09:45 -06001576static struct phy_info phy_info_VSC8601 = {
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001577 0x00007042,
1578 "Vitesse VSC8601",
1579 4,
1580 (struct phy_cmd[]) { /* config */
1581 /* Override PHY config settings */
1582 /* Configure some basic stuff */
1583 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001584#ifdef CONFIG_SYS_VSC8601_SKEWFIX
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001585 {MIIM_VSC8601_EPHY_CON,MIIM_VSC8601_EPHY_CON_INIT_SKEW,NULL},
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001586#if defined(CONFIG_SYS_VSC8601_SKEW_TX) && defined(CONFIG_SYS_VSC8601_SKEW_RX)
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001587 {MIIM_EXT_PAGE_ACCESS,1,NULL},
1588#define VSC8101_SKEW \
1589 (CONFIG_SYS_VSC8601_SKEW_TX << 14) | (CONFIG_SYS_VSC8601_SKEW_RX << 12)
1590 {MIIM_VSC8601_SKEW_CTRL,VSC8101_SKEW,NULL},
1591 {MIIM_EXT_PAGE_ACCESS,0,NULL},
Andre Schwarz9acde122008-04-29 19:18:32 +02001592#endif
Tor Krill2d934ea2008-03-28 15:29:45 +01001593#endif
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001594 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1595 {MIIM_CONTROL, MIIM_CONTROL_RESTART, &mii_cr_init},
1596 {miim_end,}
1597 },
1598 (struct phy_cmd[]) { /* startup */
1599 /* Read the Status (2x to make sure link is right) */
1600 {MIIM_STATUS, miim_read, NULL},
1601 /* Auto-negotiate */
1602 {MIIM_STATUS, miim_read, &mii_parse_sr},
1603 /* Read the status */
1604 {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244},
1605 {miim_end,}
1606 },
1607 (struct phy_cmd[]) { /* shutdown */
1608 {miim_end,}
1609 },
Tor Krill2d934ea2008-03-28 15:29:45 +01001610};
1611
Peter Tysere1957ef2009-11-09 13:09:45 -06001612static struct phy_info phy_info_dm9161 = {
wdenk97d80fc2004-06-09 00:34:46 +00001613 0x0181b88,
1614 "Davicom DM9161E",
1615 4,
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001616 (struct phy_cmd[]) { /* config */
1617 {MIIM_CONTROL, MIIM_DM9161_CR_STOP, NULL},
1618 /* Do not bypass the scrambler/descrambler */
1619 {MIIM_DM9161_SCR, MIIM_DM9161_SCR_INIT, NULL},
1620 /* Clear 10BTCSR to default */
1621 {MIIM_DM9161_10BTCSR, MIIM_DM9161_10BTCSR_INIT, NULL},
1622 /* Configure some basic stuff */
1623 {MIIM_CONTROL, MIIM_CR_INIT, NULL},
1624 /* Restart Auto Negotiation */
1625 {MIIM_CONTROL, MIIM_DM9161_CR_RSTAN, NULL},
1626 {miim_end,}
1627 },
1628 (struct phy_cmd[]) { /* startup */
1629 /* Status is read once to clear old link state */
1630 {MIIM_STATUS, miim_read, NULL},
1631 /* Auto-negotiate */
1632 {MIIM_STATUS, miim_read, &mii_parse_sr},
1633 /* Read the status */
1634 {MIIM_DM9161_SCSR, miim_read, &mii_parse_dm9161_scsr},
1635 {miim_end,}
1636 },
1637 (struct phy_cmd[]) { /* shutdown */
1638 {miim_end,}
1639 },
wdenk97d80fc2004-06-09 00:34:46 +00001640};
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001641
Heiko Schocher26918b72010-07-05 12:23:04 +02001642/* micrel KSZ804 */
1643static struct phy_info phy_info_ksz804 = {
1644 0x0022151,
1645 "Micrel KSZ804 PHY",
1646 4,
1647 (struct phy_cmd[]) { /* config */
Mike Frysinger8ef583a2010-12-23 15:40:12 -05001648 {MII_BMCR, BMCR_RESET, NULL},
1649 {MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART, NULL},
Heiko Schocher26918b72010-07-05 12:23:04 +02001650 {miim_end,}
1651 },
1652 (struct phy_cmd[]) { /* startup */
Mike Frysinger8ef583a2010-12-23 15:40:12 -05001653 {MII_BMSR, miim_read, NULL},
1654 {MII_BMSR, miim_read, &mii_parse_sr},
1655 {MII_BMSR, miim_read, &mii_parse_link},
Heiko Schocher26918b72010-07-05 12:23:04 +02001656 {miim_end,}
1657 },
1658 (struct phy_cmd[]) { /* shutdown */
1659 {miim_end,}
1660 }
1661};
1662
David Updegraffaf1c2b82007-04-20 14:34:48 -05001663/* a generic flavor. */
Peter Tysere1957ef2009-11-09 13:09:45 -06001664static struct phy_info phy_info_generic = {
David Updegraffaf1c2b82007-04-20 14:34:48 -05001665 0,
1666 "Unknown/Generic PHY",
1667 32,
1668 (struct phy_cmd[]) { /* config */
Mike Frysinger8ef583a2010-12-23 15:40:12 -05001669 {MII_BMCR, BMCR_RESET, NULL},
1670 {MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART, NULL},
David Updegraffaf1c2b82007-04-20 14:34:48 -05001671 {miim_end,}
1672 },
1673 (struct phy_cmd[]) { /* startup */
Mike Frysinger8ef583a2010-12-23 15:40:12 -05001674 {MII_BMSR, miim_read, NULL},
1675 {MII_BMSR, miim_read, &mii_parse_sr},
1676 {MII_BMSR, miim_read, &mii_parse_link},
David Updegraffaf1c2b82007-04-20 14:34:48 -05001677 {miim_end,}
1678 },
1679 (struct phy_cmd[]) { /* shutdown */
1680 {miim_end,}
1681 }
1682};
1683
Peter Tysere1957ef2009-11-09 13:09:45 -06001684static uint mii_parse_lxt971_sr2(uint mii_reg, struct tsec_private *priv)
wdenk3dd7f0f2005-04-04 23:43:44 +00001685{
wdenk3c2b3d42005-04-05 23:32:21 +00001686 unsigned int speed;
1687 if (priv->link) {
1688 speed = mii_reg & MIIM_LXT971_SR2_SPEED_MASK;
wdenk3dd7f0f2005-04-04 23:43:44 +00001689
wdenk3c2b3d42005-04-05 23:32:21 +00001690 switch (speed) {
1691 case MIIM_LXT971_SR2_10HDX:
1692 priv->speed = 10;
1693 priv->duplexity = 0;
1694 break;
1695 case MIIM_LXT971_SR2_10FDX:
1696 priv->speed = 10;
1697 priv->duplexity = 1;
1698 break;
1699 case MIIM_LXT971_SR2_100HDX:
1700 priv->speed = 100;
1701 priv->duplexity = 0;
urwithsughosh@gmail.comcd2d1602007-09-10 14:54:56 -04001702 break;
wdenk3c2b3d42005-04-05 23:32:21 +00001703 default:
1704 priv->speed = 100;
1705 priv->duplexity = 1;
wdenk3c2b3d42005-04-05 23:32:21 +00001706 }
1707 } else {
1708 priv->speed = 0;
1709 priv->duplexity = 0;
1710 }
wdenk3dd7f0f2005-04-04 23:43:44 +00001711
wdenk3c2b3d42005-04-05 23:32:21 +00001712 return 0;
wdenk3dd7f0f2005-04-04 23:43:44 +00001713}
1714
wdenk9d46ea42005-03-14 23:56:42 +00001715static struct phy_info phy_info_lxt971 = {
1716 0x0001378e,
1717 "LXT971",
1718 4,
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001719 (struct phy_cmd[]) { /* config */
1720 {MIIM_CR, MIIM_CR_INIT, mii_cr_init}, /* autonegotiate */
1721 {miim_end,}
1722 },
1723 (struct phy_cmd[]) { /* startup - enable interrupts */
1724 /* { 0x12, 0x00f2, NULL }, */
1725 {MIIM_STATUS, miim_read, NULL},
1726 {MIIM_STATUS, miim_read, &mii_parse_sr},
1727 {MIIM_LXT971_SR2, miim_read, &mii_parse_lxt971_sr2},
1728 {miim_end,}
1729 },
1730 (struct phy_cmd[]) { /* shutdown - disable interrupts */
1731 {miim_end,}
1732 },
wdenk9d46ea42005-03-14 23:56:42 +00001733};
1734
Wolfgang Denkbe5048f2006-03-12 22:50:55 +01001735/* Parse the DP83865's link and auto-neg status register for speed and duplex
Jon Loeliger89875e92006-10-10 17:03:43 -05001736 * information
1737 */
Peter Tysere1957ef2009-11-09 13:09:45 -06001738static uint mii_parse_dp83865_lanr(uint mii_reg, struct tsec_private *priv)
Wolfgang Denkbe5048f2006-03-12 22:50:55 +01001739{
1740 switch (mii_reg & MIIM_DP83865_SPD_MASK) {
1741
1742 case MIIM_DP83865_SPD_1000:
1743 priv->speed = 1000;
1744 break;
1745
1746 case MIIM_DP83865_SPD_100:
1747 priv->speed = 100;
1748 break;
1749
1750 default:
1751 priv->speed = 10;
1752 break;
1753
1754 }
1755
1756 if (mii_reg & MIIM_DP83865_DPX_FULL)
1757 priv->duplexity = 1;
1758 else
1759 priv->duplexity = 0;
1760
1761 return 0;
1762}
1763
Peter Tysere1957ef2009-11-09 13:09:45 -06001764static struct phy_info phy_info_dp83865 = {
Wolfgang Denkbe5048f2006-03-12 22:50:55 +01001765 0x20005c7,
1766 "NatSemi DP83865",
1767 4,
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001768 (struct phy_cmd[]) { /* config */
1769 {MIIM_CONTROL, MIIM_DP83865_CR_INIT, NULL},
1770 {miim_end,}
1771 },
1772 (struct phy_cmd[]) { /* startup */
1773 /* Status is read once to clear old link state */
1774 {MIIM_STATUS, miim_read, NULL},
1775 /* Auto-negotiate */
1776 {MIIM_STATUS, miim_read, &mii_parse_sr},
1777 /* Read the link and auto-neg status */
1778 {MIIM_DP83865_LANR, miim_read, &mii_parse_dp83865_lanr},
1779 {miim_end,}
1780 },
1781 (struct phy_cmd[]) { /* shutdown */
1782 {miim_end,}
1783 },
Wolfgang Denkbe5048f2006-03-12 22:50:55 +01001784};
1785
Peter Tysere1957ef2009-11-09 13:09:45 -06001786static struct phy_info phy_info_rtl8211b = {
Dave Liu18ee3202008-01-11 18:45:28 +08001787 0x001cc91,
1788 "RealTek RTL8211B",
1789 4,
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001790 (struct phy_cmd[]) { /* config */
Dave Liu18ee3202008-01-11 18:45:28 +08001791 /* Reset and configure the PHY */
1792 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1793 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1794 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1795 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1796 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1797 {miim_end,}
1798 },
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001799 (struct phy_cmd[]) { /* startup */
Dave Liu18ee3202008-01-11 18:45:28 +08001800 /* Status is read once to clear old link state */
1801 {MIIM_STATUS, miim_read, NULL},
1802 /* Auto-negotiate */
1803 {MIIM_STATUS, miim_read, &mii_parse_sr},
1804 /* Read the status */
1805 {MIIM_RTL8211B_PHY_STATUS, miim_read, &mii_parse_RTL8211B_sr},
1806 {miim_end,}
1807 },
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001808 (struct phy_cmd[]) { /* shutdown */
Dave Liu18ee3202008-01-11 18:45:28 +08001809 {miim_end,}
1810 },
1811};
1812
Peter Tysere1957ef2009-11-09 13:09:45 -06001813static struct phy_info *phy_info[] = {
wdenk97d80fc2004-06-09 00:34:46 +00001814 &phy_info_cis8204,
Timur Tabi2ad6b512006-10-31 18:44:42 -06001815 &phy_info_cis8201,
Paul Gortmaker91e25762007-01-16 11:38:14 -05001816 &phy_info_BCM5461S,
Joe Hammanc3243cf2007-04-30 16:47:28 -05001817 &phy_info_BCM5464S,
Zach LeRoy091dc9f2009-05-22 10:26:33 -05001818 &phy_info_BCM5482S,
wdenk97d80fc2004-06-09 00:34:46 +00001819 &phy_info_M88E1011S,
wdenk9d46ea42005-03-14 23:56:42 +00001820 &phy_info_M88E1111S,
Ron Madrid290ef642008-05-23 15:37:05 -07001821 &phy_info_M88E1118,
Sergei Poselenovd23dc392008-06-06 15:52:44 +02001822 &phy_info_M88E1121R,
Andy Fleming09f3e092006-09-13 10:34:18 -05001823 &phy_info_M88E1145,
Wolfgang Denk5728be32007-08-06 01:01:49 +02001824 &phy_info_M88E1149S,
wdenk97d80fc2004-06-09 00:34:46 +00001825 &phy_info_dm9161,
Heiko Schocher26918b72010-07-05 12:23:04 +02001826 &phy_info_ksz804,
wdenk9d46ea42005-03-14 23:56:42 +00001827 &phy_info_lxt971,
Pieter Henning736323a2009-02-22 23:17:15 -08001828 &phy_info_VSC8211,
Jon Loeligerdebb7352006-04-26 17:58:56 -05001829 &phy_info_VSC8244,
Tor Krill2d934ea2008-03-28 15:29:45 +01001830 &phy_info_VSC8601,
Poonam Aggrwalb7fe25d2009-07-02 16:15:13 +05301831 &phy_info_VSC8641,
1832 &phy_info_VSC8221,
Wolfgang Denkbe5048f2006-03-12 22:50:55 +01001833 &phy_info_dp83865,
Dave Liu18ee3202008-01-11 18:45:28 +08001834 &phy_info_rtl8211b,
Paul Gortmaker04523522009-03-09 18:07:53 -05001835 &phy_info_generic, /* must be last; has ID 0 and 32 bit mask */
wdenk97d80fc2004-06-09 00:34:46 +00001836 NULL
1837};
1838
wdenk97d80fc2004-06-09 00:34:46 +00001839/* Grab the identifier of the device's PHY, and search through
wdenk9d46ea42005-03-14 23:56:42 +00001840 * all of the known PHYs to see if one matches. If so, return
Jon Loeliger89875e92006-10-10 17:03:43 -05001841 * it, if not, return NULL
1842 */
Peter Tysere1957ef2009-11-09 13:09:45 -06001843static struct phy_info *get_phy_info(struct eth_device *dev)
wdenk97d80fc2004-06-09 00:34:46 +00001844{
1845 struct tsec_private *priv = (struct tsec_private *)dev->priv;
1846 uint phy_reg, phy_ID;
1847 int i;
1848 struct phy_info *theInfo = NULL;
1849
1850 /* Grab the bits from PHYIR1, and put them in the upper half */
1851 phy_reg = read_phy_reg(priv, MIIM_PHYIR1);
1852 phy_ID = (phy_reg & 0xffff) << 16;
1853
1854 /* Grab the bits from PHYIR2, and put them in the lower half */
1855 phy_reg = read_phy_reg(priv, MIIM_PHYIR2);
1856 phy_ID |= (phy_reg & 0xffff);
1857
1858 /* loop through all the known PHY types, and find one that */
1859 /* matches the ID we read from the PHY. */
Jon Loeliger89875e92006-10-10 17:03:43 -05001860 for (i = 0; phy_info[i]; i++) {
Andy Fleming2a3cee42007-05-09 00:54:20 -05001861 if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) {
wdenk97d80fc2004-06-09 00:34:46 +00001862 theInfo = phy_info[i];
Andy Fleming2a3cee42007-05-09 00:54:20 -05001863 break;
1864 }
wdenk97d80fc2004-06-09 00:34:46 +00001865 }
1866
Paul Gortmaker04523522009-03-09 18:07:53 -05001867 if (theInfo == &phy_info_generic) {
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001868 printf("%s: No support for PHY id %x; assuming generic\n",
1869 dev->name, phy_ID);
wdenk97d80fc2004-06-09 00:34:46 +00001870 } else {
Stefan Roese5810dc32005-09-21 18:20:22 +02001871 debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID);
wdenk97d80fc2004-06-09 00:34:46 +00001872 }
1873
1874 return theInfo;
1875}
1876
wdenk97d80fc2004-06-09 00:34:46 +00001877/* Execute the given series of commands on the given device's
Jon Loeliger89875e92006-10-10 17:03:43 -05001878 * PHY, running functions as necessary
1879 */
Peter Tysere1957ef2009-11-09 13:09:45 -06001880static void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd)
wdenk97d80fc2004-06-09 00:34:46 +00001881{
1882 int i;
1883 uint result;
Sandeep Gopalpetb9e186f2009-10-31 00:35:04 +05301884 volatile tsec_mdio_t *phyregs = priv->phyregs;
wdenk97d80fc2004-06-09 00:34:46 +00001885
1886 phyregs->miimcfg = MIIMCFG_RESET;
1887
1888 phyregs->miimcfg = MIIMCFG_INIT_VALUE;
1889
Jon Loeliger89875e92006-10-10 17:03:43 -05001890 while (phyregs->miimind & MIIMIND_BUSY) ;
wdenk97d80fc2004-06-09 00:34:46 +00001891
Jon Loeliger89875e92006-10-10 17:03:43 -05001892 for (i = 0; cmd->mii_reg != miim_end; i++) {
1893 if (cmd->mii_data == miim_read) {
wdenk97d80fc2004-06-09 00:34:46 +00001894 result = read_phy_reg(priv, cmd->mii_reg);
1895
Jon Loeliger89875e92006-10-10 17:03:43 -05001896 if (cmd->funct != NULL)
1897 (*(cmd->funct)) (result, priv);
wdenk97d80fc2004-06-09 00:34:46 +00001898
1899 } else {
Jon Loeliger89875e92006-10-10 17:03:43 -05001900 if (cmd->funct != NULL)
1901 result = (*(cmd->funct)) (cmd->mii_reg, priv);
wdenk97d80fc2004-06-09 00:34:46 +00001902 else
1903 result = cmd->mii_data;
1904
1905 write_phy_reg(priv, cmd->mii_reg, result);
1906
1907 }
1908 cmd++;
1909 }
1910}
1911
Jon Loeligercb51c0b2007-07-09 17:39:42 -05001912#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
Marian Balakowicz63ff0042005-10-28 22:30:33 +02001913 && !defined(BITBANGMII)
wdenk97d80fc2004-06-09 00:34:46 +00001914
wdenk7abf0c52004-04-18 21:45:42 +00001915/*
1916 * Read a MII PHY register.
1917 *
1918 * Returns:
wdenk97d80fc2004-06-09 00:34:46 +00001919 * 0 on success
wdenk7abf0c52004-04-18 21:45:42 +00001920 */
Mike Frysinger5700bb62010-07-27 18:35:08 -04001921static int tsec_miiphy_read(const char *devname, unsigned char addr,
Jon Loeliger89875e92006-10-10 17:03:43 -05001922 unsigned char reg, unsigned short *value)
wdenk7abf0c52004-04-18 21:45:42 +00001923{
wdenk97d80fc2004-06-09 00:34:46 +00001924 unsigned short ret;
michael.firth@bt.com55fe7c52008-01-16 11:40:51 +00001925 struct tsec_private *priv = privlist[0];
wdenk7abf0c52004-04-18 21:45:42 +00001926
Jon Loeliger89875e92006-10-10 17:03:43 -05001927 if (NULL == priv) {
wdenk97d80fc2004-06-09 00:34:46 +00001928 printf("Can't read PHY at address %d\n", addr);
1929 return -1;
1930 }
1931
Andy Fleming2abe3612008-08-31 16:33:27 -05001932 ret = (unsigned short)tsec_local_mdio_read(priv->phyregs, addr, reg);
wdenk97d80fc2004-06-09 00:34:46 +00001933 *value = ret;
wdenk7abf0c52004-04-18 21:45:42 +00001934
1935 return 0;
1936}
1937
1938/*
1939 * Write a MII PHY register.
1940 *
1941 * Returns:
wdenk97d80fc2004-06-09 00:34:46 +00001942 * 0 on success
wdenk7abf0c52004-04-18 21:45:42 +00001943 */
Mike Frysinger5700bb62010-07-27 18:35:08 -04001944static int tsec_miiphy_write(const char *devname, unsigned char addr,
Jon Loeliger89875e92006-10-10 17:03:43 -05001945 unsigned char reg, unsigned short value)
wdenk7abf0c52004-04-18 21:45:42 +00001946{
michael.firth@bt.com55fe7c52008-01-16 11:40:51 +00001947 struct tsec_private *priv = privlist[0];
wdenk7abf0c52004-04-18 21:45:42 +00001948
Jon Loeliger89875e92006-10-10 17:03:43 -05001949 if (NULL == priv) {
wdenk97d80fc2004-06-09 00:34:46 +00001950 printf("Can't write PHY at address %d\n", addr);
1951 return -1;
1952 }
1953
Andy Fleming2abe3612008-08-31 16:33:27 -05001954 tsec_local_mdio_write(priv->phyregs, addr, reg, value);
wdenk7abf0c52004-04-18 21:45:42 +00001955
1956 return 0;
1957}
wdenk97d80fc2004-06-09 00:34:46 +00001958
Jon Loeligercb51c0b2007-07-09 17:39:42 -05001959#endif
wdenk97d80fc2004-06-09 00:34:46 +00001960
David Updegraff53a5c422007-06-11 10:41:07 -05001961#ifdef CONFIG_MCAST_TFTP
1962
1963/* CREDITS: linux gianfar driver, slightly adjusted... thanx. */
1964
1965/* Set the appropriate hash bit for the given addr */
1966
1967/* The algorithm works like so:
1968 * 1) Take the Destination Address (ie the multicast address), and
1969 * do a CRC on it (little endian), and reverse the bits of the
1970 * result.
1971 * 2) Use the 8 most significant bits as a hash into a 256-entry
1972 * table. The table is controlled through 8 32-bit registers:
1973 * gaddr0-7. gaddr0's MSB is entry 0, and gaddr7's LSB is
1974 * gaddr7. This means that the 3 most significant bits in the
1975 * hash index which gaddr register to use, and the 5 other bits
1976 * indicate which bit (assuming an IBM numbering scheme, which
1977 * for PowerPC (tm) is usually the case) in the tregister holds
1978 * the entry. */
1979static int
1980tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set)
1981{
Peter Tyserc6dbdfd2009-11-09 13:09:46 -06001982 struct tsec_private *priv = privlist[1];
1983 volatile tsec_t *regs = priv->regs;
1984 volatile u32 *reg_array, value;
1985 u8 result, whichbit, whichreg;
David Updegraff53a5c422007-06-11 10:41:07 -05001986
1987 result = (u8)((ether_crc(MAC_ADDR_LEN,mcast_mac) >> 24) & 0xff);
1988 whichbit = result & 0x1f; /* the 5 LSB = which bit to set */
1989 whichreg = result >> 5; /* the 3 MSB = which reg to set it in */
1990 value = (1 << (31-whichbit));
1991
1992 reg_array = &(regs->hash.gaddr0);
1993
1994 if (set) {
1995 reg_array[whichreg] |= value;
1996 } else {
1997 reg_array[whichreg] &= ~value;
1998 }
1999 return 0;
2000}
2001#endif /* Multicast TFTP ? */