blob: a2705e1cab77a3608155be696eb12c6cab72ddc5 [file] [log] [blame]
wdenk9c53f402003-10-15 23:53:47 +00001/*
wdenka445ddf2004-06-09 00:34:46 +00002 * Freescale Three Speed Ethernet Controller driver
wdenk9c53f402003-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 *
Mingkai Hua65e6102011-01-27 12:52:45 +08008 * Copyright 2004-2011 Freescale Semiconductor, Inc.
wdenk9c53f402003-10-15 23:53:47 +00009 * (C) Copyright 2003, Motorola, Inc.
wdenk9c53f402003-10-15 23:53:47 +000010 * author Andy Fleming
11 *
12 */
13
14#include <config.h>
wdenk9c53f402003-10-15 23:53:47 +000015#include <common.h>
16#include <malloc.h>
17#include <net.h>
18#include <command.h>
Andy Flemingc067fc12008-08-31 16:33:25 -050019#include <tsec.h>
Kim Phillipsae4dd972009-08-24 14:32:26 -050020#include <asm/errno.h>
wdenk9c53f402003-10-15 23:53:47 +000021
Marian Balakowiczaab8c492005-10-28 22:30:33 +020022#include "miiphy.h"
wdenk9c53f402003-10-15 23:53:47 +000023
Wolfgang Denk6405a152006-03-31 18:32:53 +020024DECLARE_GLOBAL_DATA_PTR;
25
Marian Balakowiczaab8c492005-10-28 22:30:33 +020026#define TX_BUF_CNT 2
wdenk9c53f402003-10-15 23:53:47 +000027
Jon Loeligerb7ced082006-10-10 17:03:43 -050028static uint rxIdx; /* index of the current RX buffer */
29static uint txIdx; /* index of the current TX buffer */
wdenk9c53f402003-10-15 23:53:47 +000030
31typedef volatile struct rtxbd {
32 txbd8_t txbd[TX_BUF_CNT];
33 rxbd8_t rxbd[PKTBUFSRX];
Jon Loeligerb7ced082006-10-10 17:03:43 -050034} RTXBD;
wdenk9c53f402003-10-15 23:53:47 +000035
Andy Flemingfecff2b2008-08-31 16:33:26 -050036#define MAXCONTROLLERS (8)
wdenka445ddf2004-06-09 00:34:46 +000037
wdenka445ddf2004-06-09 00:34:46 +000038static struct tsec_private *privlist[MAXCONTROLLERS];
Andy Flemingfecff2b2008-08-31 16:33:26 -050039static int num_tsecs = 0;
wdenka445ddf2004-06-09 00:34:46 +000040
wdenk9c53f402003-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 Loeligerb7ced082006-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 Tyser08b2d782009-11-09 13:09:45 -060051static int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info);
Jon Loeligerb7ced082006-10-10 17:03:43 -050052static void tsec_halt(struct eth_device *dev);
Mingkai Hua65e6102011-01-27 12:52:45 +080053static void init_registers(tsec_t *regs);
wdenka445ddf2004-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 Tyser08b2d782009-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);
wdenka445ddf2004-06-09 00:34:46 +000060static void adjust_link(struct eth_device *dev);
Wolfgang Denk92254112007-11-18 16:36:27 +010061#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
62 && !defined(BITBANGMII)
Mike Frysinger5ff5fdb2010-07-27 18:35:08 -040063static int tsec_miiphy_write(const char *devname, unsigned char addr,
Jon Loeligerb7ced082006-10-10 17:03:43 -050064 unsigned char reg, unsigned short value);
Mike Frysinger5ff5fdb2010-07-27 18:35:08 -040065static int tsec_miiphy_read(const char *devname, unsigned char addr,
Jon Loeligerb7ced082006-10-10 17:03:43 -050066 unsigned char reg, unsigned short *value);
Wolfgang Denk92254112007-11-18 16:36:27 +010067#endif
David Updegraff7280da72007-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
wdenk78924a72004-04-18 21:45:42 +000071
Andy Flemingfecff2b2008-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 Gopalpetb5541ef2009-10-31 00:35:04 +053084 .miiregs = (tsec_mdio_t *)(MDIO_BASE_ADDR),
Andy Flemingfecff2b2008-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 Tabi77622682010-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 Flemingfecff2b2008-08-31 16:33:26 -0500103int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num)
104{
105 int i;
Timur Tabi77622682010-06-08 08:21:21 -0500106 int ret, count = 0;
Andy Flemingfecff2b2008-08-31 16:33:26 -0500107
Timur Tabi77622682010-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 Flemingfecff2b2008-08-31 16:33:26 -0500113
Timur Tabi77622682010-06-08 08:21:21 -0500114 return count;
Andy Flemingfecff2b2008-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
wdenka445ddf2004-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 Tyser08b2d782009-11-09 13:09:45 -0600125static int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info)
wdenk9c53f402003-10-15 23:53:47 +0000126{
Jon Loeligerb7ced082006-10-10 17:03:43 -0500127 struct eth_device *dev;
wdenk9c53f402003-10-15 23:53:47 +0000128 int i;
wdenka445ddf2004-06-09 00:34:46 +0000129 struct tsec_private *priv;
wdenk9c53f402003-10-15 23:53:47 +0000130
Jon Loeligerb7ced082006-10-10 17:03:43 -0500131 dev = (struct eth_device *)malloc(sizeof *dev);
wdenk9c53f402003-10-15 23:53:47 +0000132
Jon Loeligerb7ced082006-10-10 17:03:43 -0500133 if (NULL == dev)
wdenk9c53f402003-10-15 23:53:47 +0000134 return 0;
135
136 memset(dev, 0, sizeof *dev);
137
Jon Loeligerb7ced082006-10-10 17:03:43 -0500138 priv = (struct tsec_private *)malloc(sizeof(*priv));
wdenka445ddf2004-06-09 00:34:46 +0000139
Jon Loeligerb7ced082006-10-10 17:03:43 -0500140 if (NULL == priv)
wdenka445ddf2004-06-09 00:34:46 +0000141 return 0;
142
Andy Flemingfecff2b2008-08-31 16:33:26 -0500143 privlist[num_tsecs++] = priv;
144 priv->regs = tsec_info->regs;
145 priv->phyregs = tsec_info->miiregs;
Sandeep Gopalpetb5541ef2009-10-31 00:35:04 +0530146 priv->phyregs_sgmii = tsec_info->miiregs_sgmii;
wdenka445ddf2004-06-09 00:34:46 +0000147
Andy Flemingfecff2b2008-08-31 16:33:26 -0500148 priv->phyaddr = tsec_info->phyaddr;
149 priv->flags = tsec_info->flags;
wdenka445ddf2004-06-09 00:34:46 +0000150
Andy Flemingfecff2b2008-08-31 16:33:26 -0500151 sprintf(dev->name, tsec_info->devname);
wdenk9c53f402003-10-15 23:53:47 +0000152 dev->iobase = 0;
Jon Loeligerb7ced082006-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 Updegraff7280da72007-06-11 10:41:07 -0500158#ifdef CONFIG_MCAST_TFTP
159 dev->mcast = tsec_mcast_addr;
160#endif
wdenk9c53f402003-10-15 23:53:47 +0000161
162 /* Tell u-boot to get the addr from the env */
Jon Loeligerb7ced082006-10-10 17:03:43 -0500163 for (i = 0; i < 6; i++)
wdenk9c53f402003-10-15 23:53:47 +0000164 dev->enetaddr[i] = 0;
165
166 eth_register(dev);
167
wdenka445ddf2004-06-09 00:34:46 +0000168 /* Reset the MAC */
Mingkai Hua65e6102011-01-27 12:52:45 +0800169 setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
Andy Fleming2d1db142009-02-03 18:26:41 -0600170 udelay(2); /* Soft Reset must be asserted for 3 TX clocks */
Mingkai Hua65e6102011-01-27 12:52:45 +0800171 clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
wdenk78924a72004-04-18 21:45:42 +0000172
Jon Loeliger82ecaad2007-07-09 17:39:42 -0500173#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
Marian Balakowiczaab8c492005-10-28 22:30:33 +0200174 && !defined(BITBANGMII)
175 miiphy_register(dev->name, tsec_miiphy_read, tsec_miiphy_write);
176#endif
177
wdenka445ddf2004-06-09 00:34:46 +0000178 /* Try to initialize PHY here, and return */
179 return init_phy(dev);
wdenk9c53f402003-10-15 23:53:47 +0000180}
181
wdenk9c53f402003-10-15 23:53:47 +0000182/* Initializes data structures and registers for the controller,
wdenkbfad55d2005-03-14 23:56:42 +0000183 * and brings the interface up. Returns the link status, meaning
wdenka445ddf2004-06-09 00:34:46 +0000184 * that it returns success if the link is up, failure otherwise.
Jon Loeligerb7ced082006-10-10 17:03:43 -0500185 * This allows u-boot to find the first active controller.
186 */
Peter Tyser08b2d782009-11-09 13:09:45 -0600187static int tsec_init(struct eth_device *dev, bd_t * bd)
wdenk9c53f402003-10-15 23:53:47 +0000188{
wdenk9c53f402003-10-15 23:53:47 +0000189 uint tempval;
190 char tmpbuf[MAC_ADDR_LEN];
191 int i;
wdenka445ddf2004-06-09 00:34:46 +0000192 struct tsec_private *priv = (struct tsec_private *)dev->priv;
Mingkai Hua65e6102011-01-27 12:52:45 +0800193 tsec_t *regs = priv->regs;
wdenk9c53f402003-10-15 23:53:47 +0000194
195 /* Make sure the controller is stopped */
196 tsec_halt(dev);
197
wdenka445ddf2004-06-09 00:34:46 +0000198 /* Init MACCFG2. Defaults to GMII */
Mingkai Hua65e6102011-01-27 12:52:45 +0800199 out_be32(&regs->maccfg2, MACCFG2_INIT_SETTINGS);
wdenk9c53f402003-10-15 23:53:47 +0000200
201 /* Init ECNTRL */
Mingkai Hua65e6102011-01-27 12:52:45 +0800202 out_be32(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
wdenk9c53f402003-10-15 23:53:47 +0000203
204 /* Copy the station address into the address registers.
205 * Backwards, because little endian MACS are dumb */
Jon Loeligerb7ced082006-10-10 17:03:43 -0500206 for (i = 0; i < MAC_ADDR_LEN; i++) {
wdenka445ddf2004-06-09 00:34:46 +0000207 tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i];
wdenk9c53f402003-10-15 23:53:47 +0000208 }
Kim Phillips4f8b6332009-07-17 12:17:00 -0500209 tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) |
210 tmpbuf[3];
211
Mingkai Hua65e6102011-01-27 12:52:45 +0800212 out_be32(&regs->macstnaddr1, tempval);
wdenk9c53f402003-10-15 23:53:47 +0000213
Jon Loeligerb7ced082006-10-10 17:03:43 -0500214 tempval = *((uint *) (tmpbuf + 4));
wdenk9c53f402003-10-15 23:53:47 +0000215
Mingkai Hua65e6102011-01-27 12:52:45 +0800216 out_be32(&regs->macstnaddr2, tempval);
wdenk9c53f402003-10-15 23:53:47 +0000217
wdenk9c53f402003-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 */
wdenka445ddf2004-06-09 00:34:46 +0000226 startup_tsec(dev);
wdenk9c53f402003-10-15 23:53:47 +0000227
wdenka445ddf2004-06-09 00:34:46 +0000228 /* If there's no link, fail */
Ben Warrende9fcb52008-01-09 18:15:53 -0500229 return (priv->link ? 0 : -1);
wdenka445ddf2004-06-09 00:34:46 +0000230}
wdenk9c53f402003-10-15 23:53:47 +0000231
Andy Flemingac65e072008-08-31 16:33:27 -0500232/* Writes the given phy's reg with value, using the specified MDIO regs */
Mingkai Hua65e6102011-01-27 12:52:45 +0800233static void tsec_local_mdio_write(tsec_mdio_t *phyregs, uint addr,
Andy Flemingac65e072008-08-31 16:33:27 -0500234 uint reg, uint value)
wdenka445ddf2004-06-09 00:34:46 +0000235{
Jon Loeligerb7ced082006-10-10 17:03:43 -0500236 int timeout = 1000000;
wdenka445ddf2004-06-09 00:34:46 +0000237
Mingkai Hua65e6102011-01-27 12:52:45 +0800238 out_be32(&phyregs->miimadd, (addr << 8) | reg);
239 out_be32(&phyregs->miimcon, value);
wdenka445ddf2004-06-09 00:34:46 +0000240
Jon Loeligerb7ced082006-10-10 17:03:43 -0500241 timeout = 1000000;
Mingkai Hua65e6102011-01-27 12:52:45 +0800242 while ((in_be32(&phyregs->miimind) & MIIMIND_BUSY) && timeout--)
243 ;
wdenk9c53f402003-10-15 23:53:47 +0000244}
245
Andy Flemingac65e072008-08-31 16:33:27 -0500246
247/* Provide the default behavior of writing the PHY of this ethernet device */
Peter Tyser4ef03c02009-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.com08384842008-01-16 11:40:51 +0000250
wdenka445ddf2004-06-09 00:34:46 +0000251/* Reads register regnum on the device's PHY through the
Andy Flemingac65e072008-08-31 16:33:27 -0500252 * specified registers. It lowers and raises the read
wdenka445ddf2004-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 */
Mingkai Hua65e6102011-01-27 12:52:45 +0800257static uint tsec_local_mdio_read(tsec_mdio_t *phyregs, uint phyid, uint regnum)
wdenk9c53f402003-10-15 23:53:47 +0000258{
259 uint value;
260
wdenka445ddf2004-06-09 00:34:46 +0000261 /* Put the address of the phy, and the register
262 * number into MIIMADD */
Mingkai Hua65e6102011-01-27 12:52:45 +0800263 out_be32(&phyregs->miimadd, (phyid << 8) | regnum);
wdenk9c53f402003-10-15 23:53:47 +0000264
265 /* Clear the command register, and wait */
Mingkai Hua65e6102011-01-27 12:52:45 +0800266 out_be32(&phyregs->miimcom, 0);
wdenk9c53f402003-10-15 23:53:47 +0000267
268 /* Initiate a read command, and wait */
Mingkai Hua65e6102011-01-27 12:52:45 +0800269 out_be32(&phyregs->miimcom, MIIM_READ_COMMAND);
wdenk9c53f402003-10-15 23:53:47 +0000270
271 /* Wait for the the indication that the read is done */
Mingkai Hua65e6102011-01-27 12:52:45 +0800272 while ((in_be32(&phyregs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)))
273 ;
wdenk9c53f402003-10-15 23:53:47 +0000274
275 /* Grab the value read from the PHY */
Mingkai Hua65e6102011-01-27 12:52:45 +0800276 value = in_be32(&phyregs->miimstat);
wdenk9c53f402003-10-15 23:53:47 +0000277
278 return value;
279}
280
michael.firth@bt.com08384842008-01-16 11:40:51 +0000281/* #define to provide old read_phy_reg functionality without duplicating code */
Peter Tyser4ef03c02009-11-09 13:09:46 -0600282#define read_phy_reg(priv,regnum) \
283 tsec_local_mdio_read(priv->phyregs,priv->phyaddr,regnum)
Andy Flemingac65e072008-08-31 16:33:27 -0500284
285#define TBIANA_SETTINGS ( \
286 TBIANA_ASYMMETRIC_PAUSE \
287 | TBIANA_SYMMETRIC_PAUSE \
288 | TBIANA_FULL_DUPLEX \
289 )
290
Felix Radensky27f98e02010-06-28 01:57:39 +0300291/* By default force the TBI PHY into 1000Mbps full duplex when in SGMII mode */
292#ifndef CONFIG_TSEC_TBICR_SETTINGS
Kumar Galac1457f92010-12-01 22:55:54 -0600293#define CONFIG_TSEC_TBICR_SETTINGS ( \
Andy Flemingac65e072008-08-31 16:33:27 -0500294 TBICR_PHY_RESET \
Kumar Galac1457f92010-12-01 22:55:54 -0600295 | TBICR_ANEG_ENABLE \
Andy Flemingac65e072008-08-31 16:33:27 -0500296 | TBICR_FULL_DUPLEX \
297 | TBICR_SPEED1_SET \
298 )
Felix Radensky27f98e02010-06-28 01:57:39 +0300299#endif /* CONFIG_TSEC_TBICR_SETTINGS */
Peter Tyser583c1f42009-11-03 17:52:07 -0600300
Andy Flemingac65e072008-08-31 16:33:27 -0500301/* Configure the TBI for SGMII operation */
302static void tsec_configure_serdes(struct tsec_private *priv)
303{
Peter Tyser4ef03c02009-11-09 13:09:46 -0600304 /* Access TBI PHY registers at given TSEC register offset as opposed
305 * to the register offset used for external PHY accesses */
Sandeep Gopalpetb5541ef2009-10-31 00:35:04 +0530306 tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, TBI_ANA,
Andy Flemingac65e072008-08-31 16:33:27 -0500307 TBIANA_SETTINGS);
Sandeep Gopalpetb5541ef2009-10-31 00:35:04 +0530308 tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, TBI_TBICON,
Andy Flemingac65e072008-08-31 16:33:27 -0500309 TBICON_CLK_SELECT);
Sandeep Gopalpetb5541ef2009-10-31 00:35:04 +0530310 tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, TBI_CR,
Kumar Galac1457f92010-12-01 22:55:54 -0600311 CONFIG_TSEC_TBICR_SETTINGS);
Andy Flemingac65e072008-08-31 16:33:27 -0500312}
michael.firth@bt.com08384842008-01-16 11:40:51 +0000313
wdenka445ddf2004-06-09 00:34:46 +0000314/* Discover which PHY is attached to the device, and configure it
315 * properly. If the PHY is not recognized, then return 0
316 * (failure). Otherwise, return 1
317 */
318static int init_phy(struct eth_device *dev)
wdenk9c53f402003-10-15 23:53:47 +0000319{
wdenka445ddf2004-06-09 00:34:46 +0000320 struct tsec_private *priv = (struct tsec_private *)dev->priv;
321 struct phy_info *curphy;
Mingkai Hua65e6102011-01-27 12:52:45 +0800322 tsec_t *regs = priv->regs;
wdenk9c53f402003-10-15 23:53:47 +0000323
324 /* Assign a Physical address to the TBI */
Mingkai Hua65e6102011-01-27 12:52:45 +0800325 out_be32(&regs->tbipa, CONFIG_SYS_TBIPA_VALUE);
wdenkf41ff3b2005-04-04 23:43:44 +0000326
327 /* Reset MII (due to new addresses) */
Mingkai Hua65e6102011-01-27 12:52:45 +0800328 out_be32(&priv->phyregs->miimcfg, MIIMCFG_RESET);
329 out_be32(&priv->phyregs->miimcfg, MIIMCFG_INIT_VALUE);
330 while (in_be32(&priv->phyregs->miimind) & MIIMIND_BUSY)
331 ;
wdenk9c53f402003-10-15 23:53:47 +0000332
wdenka445ddf2004-06-09 00:34:46 +0000333 /* Get the cmd structure corresponding to the attached
334 * PHY */
335 curphy = get_phy_info(dev);
wdenk9c53f402003-10-15 23:53:47 +0000336
Ben Warrenf11eefb2006-10-26 14:38:25 -0400337 if (curphy == NULL) {
338 priv->phyinfo = NULL;
wdenka445ddf2004-06-09 00:34:46 +0000339 printf("%s: No PHY found\n", dev->name);
wdenk9c53f402003-10-15 23:53:47 +0000340
wdenka445ddf2004-06-09 00:34:46 +0000341 return 0;
342 }
wdenk9c53f402003-10-15 23:53:47 +0000343
Mingkai Hua65e6102011-01-27 12:52:45 +0800344 if (in_be32(&regs->ecntrl) & ECNTRL_SGMII_MODE)
Andy Flemingac65e072008-08-31 16:33:27 -0500345 tsec_configure_serdes(priv);
346
wdenka445ddf2004-06-09 00:34:46 +0000347 priv->phyinfo = curphy;
wdenk9c53f402003-10-15 23:53:47 +0000348
wdenka445ddf2004-06-09 00:34:46 +0000349 phy_run_commands(priv, priv->phyinfo->config);
wdenk9c53f402003-10-15 23:53:47 +0000350
wdenka445ddf2004-06-09 00:34:46 +0000351 return 1;
352}
wdenk9c53f402003-10-15 23:53:47 +0000353
Jon Loeligerb7ced082006-10-10 17:03:43 -0500354/*
355 * Returns which value to write to the control register.
356 * For 10/100, the value is slightly different
357 */
Peter Tyser08b2d782009-11-09 13:09:45 -0600358static uint mii_cr_init(uint mii_reg, struct tsec_private * priv)
wdenka445ddf2004-06-09 00:34:46 +0000359{
Jon Loeligerb7ced082006-10-10 17:03:43 -0500360 if (priv->flags & TSEC_GIGABIT)
wdenka445ddf2004-06-09 00:34:46 +0000361 return MIIM_CONTROL_INIT;
wdenk9c53f402003-10-15 23:53:47 +0000362 else
wdenka445ddf2004-06-09 00:34:46 +0000363 return MIIM_CR_INIT;
364}
wdenk9c53f402003-10-15 23:53:47 +0000365
Peter Tyser4c84fd52009-02-04 15:14:05 -0600366/*
367 * Wait for auto-negotiation to complete, then determine link
Jon Loeligerb7ced082006-10-10 17:03:43 -0500368 */
Peter Tyser08b2d782009-11-09 13:09:45 -0600369static uint mii_parse_sr(uint mii_reg, struct tsec_private * priv)
wdenka445ddf2004-06-09 00:34:46 +0000370{
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200371 /*
Andy Fleming4eb3dcf2007-08-15 20:03:44 -0500372 * Wait if the link is up, and autonegotiation is in progress
373 * (ie - we're capable and it's not done)
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200374 */
375 mii_reg = read_phy_reg(priv, MIIM_STATUS);
Mike Frysingerd63ee712010-12-23 15:40:12 -0500376 if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) {
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200377 int i = 0;
wdenk9c53f402003-10-15 23:53:47 +0000378
Jon Loeligerb7ced082006-10-10 17:03:43 -0500379 puts("Waiting for PHY auto negotiation to complete");
Mike Frysingerd63ee712010-12-23 15:40:12 -0500380 while (!(mii_reg & BMSR_ANEGCOMPLETE)) {
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200381 /*
382 * Timeout reached ?
383 */
384 if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
Jon Loeligerb7ced082006-10-10 17:03:43 -0500385 puts(" TIMEOUT !\n");
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200386 priv->link = 0;
Jin Zhengxiong-R64188487d2232006-06-27 18:12:23 +0800387 return 0;
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200388 }
wdenk9c53f402003-10-15 23:53:47 +0000389
Kim Phillipsae4dd972009-08-24 14:32:26 -0500390 if (ctrlc()) {
391 puts("user interrupt!\n");
392 priv->link = 0;
393 return -EINTR;
394 }
395
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200396 if ((i++ % 1000) == 0) {
Jon Loeligerb7ced082006-10-10 17:03:43 -0500397 putc('.');
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200398 }
Jon Loeligerb7ced082006-10-10 17:03:43 -0500399 udelay(1000); /* 1 ms */
wdenka445ddf2004-06-09 00:34:46 +0000400 mii_reg = read_phy_reg(priv, MIIM_STATUS);
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200401 }
Jon Loeligerb7ced082006-10-10 17:03:43 -0500402 puts(" done\n");
Peter Tyser4c84fd52009-02-04 15:14:05 -0600403
404 /* Link status bit is latched low, read it again */
405 mii_reg = read_phy_reg(priv, MIIM_STATUS);
406
Jon Loeligerb7ced082006-10-10 17:03:43 -0500407 udelay(500000); /* another 500 ms (results in faster booting) */
wdenk9c53f402003-10-15 23:53:47 +0000408 }
409
Peter Tyser4c84fd52009-02-04 15:14:05 -0600410 priv->link = mii_reg & MIIM_STATUS_LINK ? 1 : 0;
411
wdenka445ddf2004-06-09 00:34:46 +0000412 return 0;
413}
414
David Updegraff0451b012007-04-20 14:34:48 -0500415/* Generic function which updates the speed and duplex. If
416 * autonegotiation is enabled, it uses the AND of the link
417 * partner's advertised capabilities and our advertised
418 * capabilities. If autonegotiation is disabled, we use the
419 * appropriate bits in the control register.
420 *
421 * Stolen from Linux's mii.c and phy_device.c
422 */
Peter Tyser08b2d782009-11-09 13:09:45 -0600423static uint mii_parse_link(uint mii_reg, struct tsec_private *priv)
David Updegraff0451b012007-04-20 14:34:48 -0500424{
425 /* We're using autonegotiation */
Mike Frysingerd63ee712010-12-23 15:40:12 -0500426 if (mii_reg & BMSR_ANEGCAPABLE) {
David Updegraff0451b012007-04-20 14:34:48 -0500427 uint lpa = 0;
428 uint gblpa = 0;
429
430 /* Check for gigabit capability */
Mike Frysingerd63ee712010-12-23 15:40:12 -0500431 if (mii_reg & BMSR_ERCAP) {
David Updegraff0451b012007-04-20 14:34:48 -0500432 /* We want a list of states supported by
433 * both PHYs in the link
434 */
Mike Frysingerd63ee712010-12-23 15:40:12 -0500435 gblpa = read_phy_reg(priv, MII_STAT1000);
436 gblpa &= read_phy_reg(priv, MII_CTRL1000) << 2;
David Updegraff0451b012007-04-20 14:34:48 -0500437 }
438
439 /* Set the baseline so we only have to set them
440 * if they're different
441 */
442 priv->speed = 10;
443 priv->duplexity = 0;
444
445 /* Check the gigabit fields */
446 if (gblpa & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) {
447 priv->speed = 1000;
448
449 if (gblpa & PHY_1000BTSR_1000FD)
450 priv->duplexity = 1;
451
452 /* We're done! */
453 return 0;
454 }
455
Mike Frysingerd63ee712010-12-23 15:40:12 -0500456 lpa = read_phy_reg(priv, MII_ADVERTISE);
457 lpa &= read_phy_reg(priv, MII_LPA);
David Updegraff0451b012007-04-20 14:34:48 -0500458
Mike Frysingerd63ee712010-12-23 15:40:12 -0500459 if (lpa & (LPA_100FULL | LPA_100HALF)) {
David Updegraff0451b012007-04-20 14:34:48 -0500460 priv->speed = 100;
461
Mike Frysingerd63ee712010-12-23 15:40:12 -0500462 if (lpa & LPA_100FULL)
David Updegraff0451b012007-04-20 14:34:48 -0500463 priv->duplexity = 1;
464
Mike Frysingerd63ee712010-12-23 15:40:12 -0500465 } else if (lpa & LPA_10FULL)
David Updegraff0451b012007-04-20 14:34:48 -0500466 priv->duplexity = 1;
467 } else {
Mike Frysingerd63ee712010-12-23 15:40:12 -0500468 uint bmcr = read_phy_reg(priv, MII_BMCR);
David Updegraff0451b012007-04-20 14:34:48 -0500469
470 priv->speed = 10;
471 priv->duplexity = 0;
472
Mike Frysingerd63ee712010-12-23 15:40:12 -0500473 if (bmcr & BMCR_FULLDPLX)
David Updegraff0451b012007-04-20 14:34:48 -0500474 priv->duplexity = 1;
475
Mike Frysingerd63ee712010-12-23 15:40:12 -0500476 if (bmcr & BMCR_SPEED1000)
David Updegraff0451b012007-04-20 14:34:48 -0500477 priv->speed = 1000;
Mike Frysingerd63ee712010-12-23 15:40:12 -0500478 else if (bmcr & BMCR_SPEED100)
David Updegraff0451b012007-04-20 14:34:48 -0500479 priv->speed = 100;
480 }
481
482 return 0;
483}
484
Paul Gortmaker2bd9f1b2007-01-16 11:38:14 -0500485/*
Zach LeRoyddb7fc72009-05-22 10:26:33 -0500486 * "Ethernet@Wirespeed" needs to be enabled to achieve link in certain
487 * circumstances. eg a gigabit TSEC connected to a gigabit switch with
488 * a 4-wire ethernet cable. Both ends advertise gigabit, but can't
489 * link. "Ethernet@Wirespeed" reduces advertised speed until link
490 * can be achieved.
491 */
Peter Tyser08b2d782009-11-09 13:09:45 -0600492static uint mii_BCM54xx_wirespeed(uint mii_reg, struct tsec_private *priv)
Zach LeRoyddb7fc72009-05-22 10:26:33 -0500493{
494 return (read_phy_reg(priv, mii_reg) & 0x8FFF) | 0x8010;
495}
496
497/*
Paul Gortmaker2bd9f1b2007-01-16 11:38:14 -0500498 * Parse the BCM54xx status register for speed and duplex information.
499 * The linux sungem_phy has this information, but in a table format.
500 */
Peter Tyser08b2d782009-11-09 13:09:45 -0600501static uint mii_parse_BCM54xx_sr(uint mii_reg, struct tsec_private *priv)
Paul Gortmaker2bd9f1b2007-01-16 11:38:14 -0500502{
Peter Tyserf6722902009-11-09 13:09:44 -0600503 /* If there is no link, speed and duplex don't matter */
504 if (!priv->link)
505 return 0;
Paul Gortmaker2bd9f1b2007-01-16 11:38:14 -0500506
Peter Tyserf6722902009-11-09 13:09:44 -0600507 switch ((mii_reg & MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK) >>
508 MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT) {
509 case 1:
510 priv->duplexity = 0;
511 priv->speed = 10;
512 break;
513 case 2:
514 priv->duplexity = 1;
515 priv->speed = 10;
516 break;
517 case 3:
518 priv->duplexity = 0;
519 priv->speed = 100;
520 break;
521 case 5:
522 priv->duplexity = 1;
523 priv->speed = 100;
524 break;
525 case 6:
526 priv->duplexity = 0;
527 priv->speed = 1000;
528 break;
529 case 7:
530 priv->duplexity = 1;
531 priv->speed = 1000;
532 break;
533 default:
534 printf("Auto-neg error, defaulting to 10BT/HD\n");
535 priv->duplexity = 0;
536 priv->speed = 10;
537 break;
Paul Gortmaker2bd9f1b2007-01-16 11:38:14 -0500538 }
539
540 return 0;
Peter Tyser3c93d8b2009-11-09 13:09:47 -0600541}
Paul Gortmaker2bd9f1b2007-01-16 11:38:14 -0500542
Peter Tyser3c93d8b2009-11-09 13:09:47 -0600543/*
544 * Find out if PHY is in copper or serdes mode by looking at Expansion Reg
545 * 0x42 - "Operating Mode Status Register"
546 */
547static int BCM8482_is_serdes(struct tsec_private *priv)
548{
549 u16 val;
550 int serdes = 0;
551
552 write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_ER | 0x42);
553 val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA);
554
555 switch (val & 0x1f) {
556 case 0x0d: /* RGMII-to-100Base-FX */
557 case 0x0e: /* RGMII-to-SGMII */
558 case 0x0f: /* RGMII-to-SerDes */
559 case 0x12: /* SGMII-to-SerDes */
560 case 0x13: /* SGMII-to-100Base-FX */
561 case 0x16: /* SerDes-to-Serdes */
562 serdes = 1;
563 break;
564 case 0x6: /* RGMII-to-Copper */
565 case 0x14: /* SGMII-to-Copper */
566 case 0x17: /* SerDes-to-Copper */
567 break;
568 default:
569 printf("ERROR, invalid PHY mode (0x%x\n)", val);
570 break;
571 }
572
573 return serdes;
Paul Gortmaker2bd9f1b2007-01-16 11:38:14 -0500574}
Peter Tyser3c93d8b2009-11-09 13:09:47 -0600575
576/*
577 * Determine SerDes link speed and duplex from Expansion reg 0x42 "Operating
578 * Mode Status Register"
579 */
580uint mii_parse_BCM5482_serdes_sr(struct tsec_private *priv)
581{
582 u16 val;
583 int i = 0;
584
585 /* Wait 1s for link - Clause 37 autonegotiation happens very fast */
586 while (1) {
587 write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL,
588 MIIM_BCM54XX_EXP_SEL_ER | 0x42);
589 val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA);
590
591 if (val & 0x8000)
592 break;
593
594 if (i++ > 1000) {
595 priv->link = 0;
596 return 1;
597 }
598
599 udelay(1000); /* 1 ms */
600 }
601
602 priv->link = 1;
603 switch ((val >> 13) & 0x3) {
604 case (0x00):
605 priv->speed = 10;
606 break;
607 case (0x01):
608 priv->speed = 100;
609 break;
610 case (0x02):
611 priv->speed = 1000;
612 break;
613 }
614
615 priv->duplexity = (val & 0x1000) == 0x1000;
616
617 return 0;
618}
619
620/*
621 * Figure out if BCM5482 is in serdes or copper mode and determine link
622 * configuration accordingly
623 */
624static uint mii_parse_BCM5482_sr(uint mii_reg, struct tsec_private *priv)
625{
626 if (BCM8482_is_serdes(priv)) {
627 mii_parse_BCM5482_serdes_sr(priv);
Peter Tyser94f63a72009-11-09 13:09:48 -0600628 priv->flags |= TSEC_FIBER;
Peter Tyser3c93d8b2009-11-09 13:09:47 -0600629 } else {
630 /* Wait for auto-negotiation to complete or fail */
631 mii_parse_sr(mii_reg, priv);
632
633 /* Parse BCM54xx copper aux status register */
634 mii_reg = read_phy_reg(priv, MIIM_BCM54xx_AUXSTATUS);
635 mii_parse_BCM54xx_sr(mii_reg, priv);
636 }
637
638 return 0;
639}
640
wdenka445ddf2004-06-09 00:34:46 +0000641/* Parse the 88E1011's status register for speed and duplex
Jon Loeligerb7ced082006-10-10 17:03:43 -0500642 * information
643 */
Peter Tyser08b2d782009-11-09 13:09:45 -0600644static uint mii_parse_88E1011_psr(uint mii_reg, struct tsec_private * priv)
wdenka445ddf2004-06-09 00:34:46 +0000645{
646 uint speed;
wdenk9c53f402003-10-15 23:53:47 +0000647
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200648 mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);
649
Andy Fleming4eb3dcf2007-08-15 20:03:44 -0500650 if ((mii_reg & MIIM_88E1011_PHYSTAT_LINK) &&
651 !(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200652 int i = 0;
653
Jon Loeligerb7ced082006-10-10 17:03:43 -0500654 puts("Waiting for PHY realtime link");
Andy Fleming4eb3dcf2007-08-15 20:03:44 -0500655 while (!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
656 /* Timeout reached ? */
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200657 if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
Jon Loeligerb7ced082006-10-10 17:03:43 -0500658 puts(" TIMEOUT !\n");
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200659 priv->link = 0;
660 break;
661 }
662
663 if ((i++ % 1000) == 0) {
Jon Loeligerb7ced082006-10-10 17:03:43 -0500664 putc('.');
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200665 }
Jon Loeligerb7ced082006-10-10 17:03:43 -0500666 udelay(1000); /* 1 ms */
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200667 mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);
668 }
Jon Loeligerb7ced082006-10-10 17:03:43 -0500669 puts(" done\n");
670 udelay(500000); /* another 500 ms (results in faster booting) */
Andy Fleming4eb3dcf2007-08-15 20:03:44 -0500671 } else {
672 if (mii_reg & MIIM_88E1011_PHYSTAT_LINK)
673 priv->link = 1;
674 else
675 priv->link = 0;
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200676 }
677
Jon Loeligerb7ced082006-10-10 17:03:43 -0500678 if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX)
wdenka445ddf2004-06-09 00:34:46 +0000679 priv->duplexity = 1;
680 else
681 priv->duplexity = 0;
682
Jon Loeligerb7ced082006-10-10 17:03:43 -0500683 speed = (mii_reg & MIIM_88E1011_PHYSTAT_SPEED);
wdenka445ddf2004-06-09 00:34:46 +0000684
Jon Loeligerb7ced082006-10-10 17:03:43 -0500685 switch (speed) {
686 case MIIM_88E1011_PHYSTAT_GBIT:
687 priv->speed = 1000;
688 break;
689 case MIIM_88E1011_PHYSTAT_100:
690 priv->speed = 100;
691 break;
692 default:
693 priv->speed = 10;
wdenk9c53f402003-10-15 23:53:47 +0000694 }
695
wdenka445ddf2004-06-09 00:34:46 +0000696 return 0;
697}
698
Dave Liua304a282008-01-11 18:45:28 +0800699/* Parse the RTL8211B's status register for speed and duplex
700 * information
701 */
Peter Tyser08b2d782009-11-09 13:09:45 -0600702static uint mii_parse_RTL8211B_sr(uint mii_reg, struct tsec_private * priv)
Dave Liua304a282008-01-11 18:45:28 +0800703{
704 uint speed;
705
706 mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS);
Anton Vorontsov91112ec2008-03-14 23:20:30 +0300707 if (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
Dave Liua304a282008-01-11 18:45:28 +0800708 int i = 0;
709
Anton Vorontsov91112ec2008-03-14 23:20:30 +0300710 /* in case of timeout ->link is cleared */
711 priv->link = 1;
Dave Liua304a282008-01-11 18:45:28 +0800712 puts("Waiting for PHY realtime link");
713 while (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
714 /* Timeout reached ? */
715 if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
716 puts(" TIMEOUT !\n");
717 priv->link = 0;
718 break;
719 }
720
721 if ((i++ % 1000) == 0) {
722 putc('.');
723 }
724 udelay(1000); /* 1 ms */
725 mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS);
726 }
727 puts(" done\n");
728 udelay(500000); /* another 500 ms (results in faster booting) */
729 } else {
730 if (mii_reg & MIIM_RTL8211B_PHYSTAT_LINK)
731 priv->link = 1;
732 else
733 priv->link = 0;
734 }
735
736 if (mii_reg & MIIM_RTL8211B_PHYSTAT_DUPLEX)
737 priv->duplexity = 1;
738 else
739 priv->duplexity = 0;
740
741 speed = (mii_reg & MIIM_RTL8211B_PHYSTAT_SPEED);
742
743 switch (speed) {
744 case MIIM_RTL8211B_PHYSTAT_GBIT:
745 priv->speed = 1000;
746 break;
747 case MIIM_RTL8211B_PHYSTAT_100:
748 priv->speed = 100;
749 break;
750 default:
751 priv->speed = 10;
752 }
753
754 return 0;
755}
756
wdenka445ddf2004-06-09 00:34:46 +0000757/* Parse the cis8201's status register for speed and duplex
Jon Loeligerb7ced082006-10-10 17:03:43 -0500758 * information
759 */
Peter Tyser08b2d782009-11-09 13:09:45 -0600760static uint mii_parse_cis8201(uint mii_reg, struct tsec_private * priv)
wdenka445ddf2004-06-09 00:34:46 +0000761{
762 uint speed;
763
Jon Loeligerb7ced082006-10-10 17:03:43 -0500764 if (mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX)
wdenka445ddf2004-06-09 00:34:46 +0000765 priv->duplexity = 1;
766 else
767 priv->duplexity = 0;
768
769 speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED;
Jon Loeligerb7ced082006-10-10 17:03:43 -0500770 switch (speed) {
771 case MIIM_CIS8201_AUXCONSTAT_GBIT:
772 priv->speed = 1000;
773 break;
774 case MIIM_CIS8201_AUXCONSTAT_100:
775 priv->speed = 100;
776 break;
777 default:
778 priv->speed = 10;
779 break;
wdenk9c53f402003-10-15 23:53:47 +0000780 }
781
wdenka445ddf2004-06-09 00:34:46 +0000782 return 0;
783}
Jon Loeligerb7ced082006-10-10 17:03:43 -0500784
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500785/* Parse the vsc8244's status register for speed and duplex
Jon Loeligerb7ced082006-10-10 17:03:43 -0500786 * information
787 */
Peter Tyser08b2d782009-11-09 13:09:45 -0600788static uint mii_parse_vsc8244(uint mii_reg, struct tsec_private * priv)
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500789{
Jon Loeligerb7ced082006-10-10 17:03:43 -0500790 uint speed;
wdenk9c53f402003-10-15 23:53:47 +0000791
Jon Loeligerb7ced082006-10-10 17:03:43 -0500792 if (mii_reg & MIIM_VSC8244_AUXCONSTAT_DUPLEX)
793 priv->duplexity = 1;
794 else
795 priv->duplexity = 0;
796
797 speed = mii_reg & MIIM_VSC8244_AUXCONSTAT_SPEED;
798 switch (speed) {
799 case MIIM_VSC8244_AUXCONSTAT_GBIT:
800 priv->speed = 1000;
801 break;
802 case MIIM_VSC8244_AUXCONSTAT_100:
803 priv->speed = 100;
804 break;
805 default:
806 priv->speed = 10;
807 break;
808 }
809
810 return 0;
811}
wdenka445ddf2004-06-09 00:34:46 +0000812
813/* Parse the DM9161's status register for speed and duplex
Jon Loeligerb7ced082006-10-10 17:03:43 -0500814 * information
815 */
Peter Tyser08b2d782009-11-09 13:09:45 -0600816static uint mii_parse_dm9161_scsr(uint mii_reg, struct tsec_private * priv)
wdenka445ddf2004-06-09 00:34:46 +0000817{
Jon Loeligerb7ced082006-10-10 17:03:43 -0500818 if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H))
wdenka445ddf2004-06-09 00:34:46 +0000819 priv->speed = 100;
820 else
821 priv->speed = 10;
822
Jon Loeligerb7ced082006-10-10 17:03:43 -0500823 if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F))
wdenka445ddf2004-06-09 00:34:46 +0000824 priv->duplexity = 1;
825 else
826 priv->duplexity = 0;
827
828 return 0;
829}
830
Jon Loeligerb7ced082006-10-10 17:03:43 -0500831/*
832 * Hack to write all 4 PHYs with the LED values
833 */
Peter Tyser08b2d782009-11-09 13:09:45 -0600834static uint mii_cis8204_fixled(uint mii_reg, struct tsec_private * priv)
wdenka445ddf2004-06-09 00:34:46 +0000835{
836 uint phyid;
Mingkai Hua65e6102011-01-27 12:52:45 +0800837 tsec_mdio_t *regbase = priv->phyregs;
Jon Loeligerb7ced082006-10-10 17:03:43 -0500838 int timeout = 1000000;
wdenka445ddf2004-06-09 00:34:46 +0000839
Jon Loeligerb7ced082006-10-10 17:03:43 -0500840 for (phyid = 0; phyid < 4; phyid++) {
Mingkai Hua65e6102011-01-27 12:52:45 +0800841 out_be32(&regbase->miimadd, (phyid << 8) | mii_reg);
842 out_be32(&regbase->miimcon, MIIM_CIS8204_SLEDCON_INIT);
wdenka445ddf2004-06-09 00:34:46 +0000843
Jon Loeligerb7ced082006-10-10 17:03:43 -0500844 timeout = 1000000;
Mingkai Hua65e6102011-01-27 12:52:45 +0800845 while ((in_be32(&regbase->miimind) & MIIMIND_BUSY) && timeout--)
846 ;
wdenk9c53f402003-10-15 23:53:47 +0000847 }
wdenk9c53f402003-10-15 23:53:47 +0000848
wdenka445ddf2004-06-09 00:34:46 +0000849 return MIIM_CIS8204_SLEDCON_INIT;
wdenk9c53f402003-10-15 23:53:47 +0000850}
851
Peter Tyser08b2d782009-11-09 13:09:45 -0600852static uint mii_cis8204_setmode(uint mii_reg, struct tsec_private * priv)
Jon Loeliger77a4f6e2005-07-25 14:05:07 -0500853{
854 if (priv->flags & TSEC_REDUCED)
855 return MIIM_CIS8204_EPHYCON_INIT | MIIM_CIS8204_EPHYCON_RGMII;
856 else
857 return MIIM_CIS8204_EPHYCON_INIT;
858}
wdenk9c53f402003-10-15 23:53:47 +0000859
Peter Tyser08b2d782009-11-09 13:09:45 -0600860static uint mii_m88e1111s_setmode(uint mii_reg, struct tsec_private *priv)
Dave Liub19ecd32007-09-18 12:37:57 +0800861{
862 uint mii_data = read_phy_reg(priv, mii_reg);
863
864 if (priv->flags & TSEC_REDUCED)
865 mii_data = (mii_data & 0xfff0) | 0x000b;
866 return mii_data;
867}
868
wdenka445ddf2004-06-09 00:34:46 +0000869/* Initialized required registers to appropriate values, zeroing
870 * those we don't care about (unless zero is bad, in which case,
Jon Loeligerb7ced082006-10-10 17:03:43 -0500871 * choose a more appropriate value)
872 */
Mingkai Hua65e6102011-01-27 12:52:45 +0800873static void init_registers(tsec_t *regs)
wdenk9c53f402003-10-15 23:53:47 +0000874{
875 /* Clear IEVENT */
Mingkai Hua65e6102011-01-27 12:52:45 +0800876 out_be32(&regs->ievent, IEVENT_INIT_CLEAR);
wdenk9c53f402003-10-15 23:53:47 +0000877
Mingkai Hua65e6102011-01-27 12:52:45 +0800878 out_be32(&regs->imask, IMASK_INIT_CLEAR);
wdenk9c53f402003-10-15 23:53:47 +0000879
Mingkai Hua65e6102011-01-27 12:52:45 +0800880 out_be32(&regs->hash.iaddr0, 0);
881 out_be32(&regs->hash.iaddr1, 0);
882 out_be32(&regs->hash.iaddr2, 0);
883 out_be32(&regs->hash.iaddr3, 0);
884 out_be32(&regs->hash.iaddr4, 0);
885 out_be32(&regs->hash.iaddr5, 0);
886 out_be32(&regs->hash.iaddr6, 0);
887 out_be32(&regs->hash.iaddr7, 0);
wdenk9c53f402003-10-15 23:53:47 +0000888
Mingkai Hua65e6102011-01-27 12:52:45 +0800889 out_be32(&regs->hash.gaddr0, 0);
890 out_be32(&regs->hash.gaddr1, 0);
891 out_be32(&regs->hash.gaddr2, 0);
892 out_be32(&regs->hash.gaddr3, 0);
893 out_be32(&regs->hash.gaddr4, 0);
894 out_be32(&regs->hash.gaddr5, 0);
895 out_be32(&regs->hash.gaddr6, 0);
896 out_be32(&regs->hash.gaddr7, 0);
wdenk9c53f402003-10-15 23:53:47 +0000897
Mingkai Hua65e6102011-01-27 12:52:45 +0800898 out_be32(&regs->rctrl, 0x00000000);
wdenk9c53f402003-10-15 23:53:47 +0000899
900 /* Init RMON mib registers */
901 memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t));
902
Mingkai Hua65e6102011-01-27 12:52:45 +0800903 out_be32(&regs->rmon.cam1, 0xffffffff);
904 out_be32(&regs->rmon.cam2, 0xffffffff);
wdenk9c53f402003-10-15 23:53:47 +0000905
Mingkai Hua65e6102011-01-27 12:52:45 +0800906 out_be32(&regs->mrblr, MRBLR_INIT_SETTINGS);
wdenk9c53f402003-10-15 23:53:47 +0000907
Mingkai Hua65e6102011-01-27 12:52:45 +0800908 out_be32(&regs->minflr, MINFLR_INIT_SETTINGS);
wdenk9c53f402003-10-15 23:53:47 +0000909
Mingkai Hua65e6102011-01-27 12:52:45 +0800910 out_be32(&regs->attr, ATTR_INIT_SETTINGS);
911 out_be32(&regs->attreli, ATTRELI_INIT_SETTINGS);
wdenk9c53f402003-10-15 23:53:47 +0000912
wdenka445ddf2004-06-09 00:34:46 +0000913}
914
wdenka445ddf2004-06-09 00:34:46 +0000915/* Configure maccfg2 based on negotiated speed and duplex
Jon Loeligerb7ced082006-10-10 17:03:43 -0500916 * reported by PHY handling code
917 */
wdenka445ddf2004-06-09 00:34:46 +0000918static void adjust_link(struct eth_device *dev)
919{
920 struct tsec_private *priv = (struct tsec_private *)dev->priv;
Mingkai Hua65e6102011-01-27 12:52:45 +0800921 tsec_t *regs = priv->regs;
922 u32 ecntrl, maccfg2;
wdenka445ddf2004-06-09 00:34:46 +0000923
Mingkai Hua65e6102011-01-27 12:52:45 +0800924 if (!priv->link) {
925 printf("%s: No link.\n", dev->name);
926 return;
927 }
wdenka445ddf2004-06-09 00:34:46 +0000928
Mingkai Hua65e6102011-01-27 12:52:45 +0800929 /* clear all bits relative with interface mode */
930 ecntrl = in_be32(&regs->ecntrl);
931 ecntrl &= ~ECNTRL_R100;
Jon Loeliger77a4f6e2005-07-25 14:05:07 -0500932
Mingkai Hua65e6102011-01-27 12:52:45 +0800933 maccfg2 = in_be32(&regs->maccfg2);
934 maccfg2 &= ~(MACCFG2_IF | MACCFG2_FULL_DUPLEX);
wdenka445ddf2004-06-09 00:34:46 +0000935
Mingkai Hua65e6102011-01-27 12:52:45 +0800936 if (priv->duplexity)
937 maccfg2 |= MACCFG2_FULL_DUPLEX;
wdenka445ddf2004-06-09 00:34:46 +0000938
Mingkai Hua65e6102011-01-27 12:52:45 +0800939 switch (priv->speed) {
940 case 1000:
941 maccfg2 |= MACCFG2_GMII;
942 break;
943 case 100:
944 case 10:
945 maccfg2 |= MACCFG2_MII;
946
947 /* Set R100 bit in all modes although
948 * it is only used in RGMII mode
949 */
950 if (priv->speed == 100)
951 ecntrl |= ECNTRL_R100;
952 break;
953 default:
954 printf("%s: Speed was bad\n", dev->name);
955 break;
wdenka445ddf2004-06-09 00:34:46 +0000956 }
Mingkai Hua65e6102011-01-27 12:52:45 +0800957
958 out_be32(&regs->ecntrl, ecntrl);
959 out_be32(&regs->maccfg2, maccfg2);
960
961 printf("Speed: %d, %s duplex%s\n", priv->speed,
962 (priv->duplexity) ? "full" : "half",
963 (priv->flags & TSEC_FIBER) ? ", fiber mode" : "");
wdenk9c53f402003-10-15 23:53:47 +0000964}
965
wdenka445ddf2004-06-09 00:34:46 +0000966/* Set up the buffers and their descriptors, and bring up the
Jon Loeligerb7ced082006-10-10 17:03:43 -0500967 * interface
968 */
wdenka445ddf2004-06-09 00:34:46 +0000969static void startup_tsec(struct eth_device *dev)
wdenk9c53f402003-10-15 23:53:47 +0000970{
971 int i;
wdenka445ddf2004-06-09 00:34:46 +0000972 struct tsec_private *priv = (struct tsec_private *)dev->priv;
Mingkai Hua65e6102011-01-27 12:52:45 +0800973 tsec_t *regs = priv->regs;
wdenk9c53f402003-10-15 23:53:47 +0000974
975 /* Point to the buffer descriptors */
Mingkai Hua65e6102011-01-27 12:52:45 +0800976 out_be32(&regs->tbase, (unsigned int)(&rtx.txbd[txIdx]));
977 out_be32(&regs->rbase, (unsigned int)(&rtx.rxbd[rxIdx]));
wdenk9c53f402003-10-15 23:53:47 +0000978
979 /* Initialize the Rx Buffer descriptors */
980 for (i = 0; i < PKTBUFSRX; i++) {
981 rtx.rxbd[i].status = RXBD_EMPTY;
982 rtx.rxbd[i].length = 0;
Jon Loeligerb7ced082006-10-10 17:03:43 -0500983 rtx.rxbd[i].bufPtr = (uint) NetRxPackets[i];
wdenk9c53f402003-10-15 23:53:47 +0000984 }
Jon Loeligerb7ced082006-10-10 17:03:43 -0500985 rtx.rxbd[PKTBUFSRX - 1].status |= RXBD_WRAP;
wdenk9c53f402003-10-15 23:53:47 +0000986
987 /* Initialize the TX Buffer Descriptors */
Jon Loeligerb7ced082006-10-10 17:03:43 -0500988 for (i = 0; i < TX_BUF_CNT; i++) {
wdenk9c53f402003-10-15 23:53:47 +0000989 rtx.txbd[i].status = 0;
990 rtx.txbd[i].length = 0;
991 rtx.txbd[i].bufPtr = 0;
992 }
Jon Loeligerb7ced082006-10-10 17:03:43 -0500993 rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP;
wdenk9c53f402003-10-15 23:53:47 +0000994
wdenka445ddf2004-06-09 00:34:46 +0000995 /* Start up the PHY */
Ben Warrenf11eefb2006-10-26 14:38:25 -0400996 if(priv->phyinfo)
997 phy_run_commands(priv, priv->phyinfo->startup);
David Updegraff0451b012007-04-20 14:34:48 -0500998
wdenka445ddf2004-06-09 00:34:46 +0000999 adjust_link(dev);
1000
wdenk9c53f402003-10-15 23:53:47 +00001001 /* Enable Transmit and Receive */
Mingkai Hua65e6102011-01-27 12:52:45 +08001002 setbits_be32(&regs->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
wdenk9c53f402003-10-15 23:53:47 +00001003
1004 /* Tell the DMA it is clear to go */
Mingkai Hua65e6102011-01-27 12:52:45 +08001005 setbits_be32(&regs->dmactrl, DMACTRL_INIT_SETTINGS);
1006 out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
1007 out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
1008 clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
wdenk9c53f402003-10-15 23:53:47 +00001009}
1010
wdenkbfad55d2005-03-14 23:56:42 +00001011/* This returns the status bits of the device. The return value
wdenk9c53f402003-10-15 23:53:47 +00001012 * is never checked, and this is what the 8260 driver did, so we
wdenkbfad55d2005-03-14 23:56:42 +00001013 * do the same. Presumably, this would be zero if there were no
Jon Loeligerb7ced082006-10-10 17:03:43 -05001014 * errors
1015 */
1016static int tsec_send(struct eth_device *dev, volatile void *packet, int length)
wdenk9c53f402003-10-15 23:53:47 +00001017{
1018 int i;
1019 int result = 0;
wdenka445ddf2004-06-09 00:34:46 +00001020 struct tsec_private *priv = (struct tsec_private *)dev->priv;
Mingkai Hua65e6102011-01-27 12:52:45 +08001021 tsec_t *regs = priv->regs;
wdenk9c53f402003-10-15 23:53:47 +00001022
1023 /* Find an empty buffer descriptor */
Jon Loeligerb7ced082006-10-10 17:03:43 -05001024 for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
wdenk9c53f402003-10-15 23:53:47 +00001025 if (i >= TOUT_LOOP) {
Jon Loeligerb7ced082006-10-10 17:03:43 -05001026 debug("%s: tsec: tx buffers full\n", dev->name);
wdenk9c53f402003-10-15 23:53:47 +00001027 return result;
1028 }
1029 }
1030
Jon Loeligerb7ced082006-10-10 17:03:43 -05001031 rtx.txbd[txIdx].bufPtr = (uint) packet;
wdenk9c53f402003-10-15 23:53:47 +00001032 rtx.txbd[txIdx].length = length;
Jon Loeligerb7ced082006-10-10 17:03:43 -05001033 rtx.txbd[txIdx].status |=
1034 (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT);
wdenk9c53f402003-10-15 23:53:47 +00001035
1036 /* Tell the DMA to go */
Mingkai Hua65e6102011-01-27 12:52:45 +08001037 out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
wdenk9c53f402003-10-15 23:53:47 +00001038
1039 /* Wait for buffer to be transmitted */
Jon Loeligerb7ced082006-10-10 17:03:43 -05001040 for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
wdenk9c53f402003-10-15 23:53:47 +00001041 if (i >= TOUT_LOOP) {
Jon Loeligerb7ced082006-10-10 17:03:43 -05001042 debug("%s: tsec: tx error\n", dev->name);
wdenk9c53f402003-10-15 23:53:47 +00001043 return result;
1044 }
1045 }
1046
1047 txIdx = (txIdx + 1) % TX_BUF_CNT;
1048 result = rtx.txbd[txIdx].status & TXBD_STATS;
1049
1050 return result;
1051}
1052
Jon Loeligerb7ced082006-10-10 17:03:43 -05001053static int tsec_recv(struct eth_device *dev)
wdenk9c53f402003-10-15 23:53:47 +00001054{
1055 int length;
wdenka445ddf2004-06-09 00:34:46 +00001056 struct tsec_private *priv = (struct tsec_private *)dev->priv;
Mingkai Hua65e6102011-01-27 12:52:45 +08001057 tsec_t *regs = priv->regs;
wdenk9c53f402003-10-15 23:53:47 +00001058
Jon Loeligerb7ced082006-10-10 17:03:43 -05001059 while (!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) {
wdenk9c53f402003-10-15 23:53:47 +00001060
1061 length = rtx.rxbd[rxIdx].length;
1062
1063 /* Send the packet up if there were no errors */
1064 if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) {
1065 NetReceive(NetRxPackets[rxIdx], length - 4);
wdenka445ddf2004-06-09 00:34:46 +00001066 } else {
1067 printf("Got error %x\n",
Jon Loeligerb7ced082006-10-10 17:03:43 -05001068 (rtx.rxbd[rxIdx].status & RXBD_STATS));
wdenk9c53f402003-10-15 23:53:47 +00001069 }
1070
1071 rtx.rxbd[rxIdx].length = 0;
1072
1073 /* Set the wrap bit if this is the last element in the list */
Jon Loeligerb7ced082006-10-10 17:03:43 -05001074 rtx.rxbd[rxIdx].status =
1075 RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0);
wdenk9c53f402003-10-15 23:53:47 +00001076
1077 rxIdx = (rxIdx + 1) % PKTBUFSRX;
1078 }
1079
Mingkai Hua65e6102011-01-27 12:52:45 +08001080 if (in_be32(&regs->ievent) & IEVENT_BSY) {
1081 out_be32(&regs->ievent, IEVENT_BSY);
1082 out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
wdenk9c53f402003-10-15 23:53:47 +00001083 }
1084
1085 return -1;
1086
1087}
1088
wdenka445ddf2004-06-09 00:34:46 +00001089/* Stop the interface */
Jon Loeligerb7ced082006-10-10 17:03:43 -05001090static void tsec_halt(struct eth_device *dev)
wdenk9c53f402003-10-15 23:53:47 +00001091{
wdenka445ddf2004-06-09 00:34:46 +00001092 struct tsec_private *priv = (struct tsec_private *)dev->priv;
Mingkai Hua65e6102011-01-27 12:52:45 +08001093 tsec_t *regs = priv->regs;
wdenk9c53f402003-10-15 23:53:47 +00001094
Mingkai Hua65e6102011-01-27 12:52:45 +08001095 clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
1096 setbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
wdenk9c53f402003-10-15 23:53:47 +00001097
Mingkai Hua65e6102011-01-27 12:52:45 +08001098 while ((in_be32(&regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
1099 != (IEVENT_GRSC | IEVENT_GTSC))
1100 ;
wdenk9c53f402003-10-15 23:53:47 +00001101
Mingkai Hua65e6102011-01-27 12:52:45 +08001102 clrbits_be32(&regs->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN);
wdenk9c53f402003-10-15 23:53:47 +00001103
wdenka445ddf2004-06-09 00:34:46 +00001104 /* Shut down the PHY, as needed */
Ben Warrenf11eefb2006-10-26 14:38:25 -04001105 if(priv->phyinfo)
1106 phy_run_commands(priv, priv->phyinfo->shutdown);
wdenka445ddf2004-06-09 00:34:46 +00001107}
1108
Peter Tyser08b2d782009-11-09 13:09:45 -06001109static struct phy_info phy_info_M88E1149S = {
Wolfgang Denk15e87572007-08-06 01:01:49 +02001110 0x1410ca,
1111 "Marvell 88E1149S",
1112 4,
Peter Tyser4ef03c02009-11-09 13:09:46 -06001113 (struct phy_cmd[]) { /* config */
Wolfgang Denk15e87572007-08-06 01:01:49 +02001114 /* Reset and configure the PHY */
1115 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1116 {0x1d, 0x1f, NULL},
1117 {0x1e, 0x200c, NULL},
1118 {0x1d, 0x5, NULL},
1119 {0x1e, 0x0, NULL},
1120 {0x1e, 0x100, NULL},
1121 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1122 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1123 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1124 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1125 {miim_end,}
1126 },
Peter Tyser4ef03c02009-11-09 13:09:46 -06001127 (struct phy_cmd[]) { /* startup */
Wolfgang Denk15e87572007-08-06 01:01:49 +02001128 /* Status is read once to clear old link state */
1129 {MIIM_STATUS, miim_read, NULL},
1130 /* Auto-negotiate */
1131 {MIIM_STATUS, miim_read, &mii_parse_sr},
1132 /* Read the status */
Peter Tyser4ef03c02009-11-09 13:09:46 -06001133 {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr},
Wolfgang Denk15e87572007-08-06 01:01:49 +02001134 {miim_end,}
1135 },
Peter Tyser4ef03c02009-11-09 13:09:46 -06001136 (struct phy_cmd[]) { /* shutdown */
Wolfgang Denk15e87572007-08-06 01:01:49 +02001137 {miim_end,}
1138 },
Andy Flemingbee67002007-08-03 04:05:25 -05001139};
1140
Paul Gortmaker2bd9f1b2007-01-16 11:38:14 -05001141/* The 5411 id is 0x206070, the 5421 is 0x2060e0 */
Peter Tyser08b2d782009-11-09 13:09:45 -06001142static struct phy_info phy_info_BCM5461S = {
Paul Gortmaker2bd9f1b2007-01-16 11:38:14 -05001143 0x02060c1, /* 5461 ID */
1144 "Broadcom BCM5461S",
1145 0, /* not clear to me what minor revisions we can shift away */
1146 (struct phy_cmd[]) { /* config */
1147 /* Reset and configure the PHY */
1148 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1149 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1150 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1151 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1152 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1153 {miim_end,}
1154 },
1155 (struct phy_cmd[]) { /* startup */
1156 /* Status is read once to clear old link state */
1157 {MIIM_STATUS, miim_read, NULL},
1158 /* Auto-negotiate */
1159 {MIIM_STATUS, miim_read, &mii_parse_sr},
1160 /* Read the status */
1161 {MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr},
1162 {miim_end,}
1163 },
1164 (struct phy_cmd[]) { /* shutdown */
1165 {miim_end,}
1166 },
1167};
1168
Peter Tyser08b2d782009-11-09 13:09:45 -06001169static struct phy_info phy_info_BCM5464S = {
Joe Hammaned7ad4e2007-04-30 16:47:28 -05001170 0x02060b1, /* 5464 ID */
1171 "Broadcom BCM5464S",
1172 0, /* not clear to me what minor revisions we can shift away */
1173 (struct phy_cmd[]) { /* config */
1174 /* Reset and configure the PHY */
1175 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1176 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1177 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1178 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
Zach LeRoyddb7fc72009-05-22 10:26:33 -05001179 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1180 {miim_end,}
1181 },
1182 (struct phy_cmd[]) { /* startup */
1183 /* Status is read once to clear old link state */
1184 {MIIM_STATUS, miim_read, NULL},
1185 /* Auto-negotiate */
1186 {MIIM_STATUS, miim_read, &mii_parse_sr},
1187 /* Read the status */
1188 {MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr},
1189 {miim_end,}
1190 },
1191 (struct phy_cmd[]) { /* shutdown */
1192 {miim_end,}
1193 },
1194};
1195
Peter Tyser08b2d782009-11-09 13:09:45 -06001196static struct phy_info phy_info_BCM5482S = {
Zach LeRoyddb7fc72009-05-22 10:26:33 -05001197 0x0143bcb,
1198 "Broadcom BCM5482S",
1199 4,
1200 (struct phy_cmd[]) { /* config */
1201 /* Reset and configure the PHY */
1202 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1203 /* Setup read from auxilary control shadow register 7 */
1204 {MIIM_BCM54xx_AUXCNTL, MIIM_BCM54xx_AUXCNTL_ENCODE(7), NULL},
1205 /* Read Misc Control register and or in Ethernet@Wirespeed */
1206 {MIIM_BCM54xx_AUXCNTL, 0, &mii_BCM54xx_wirespeed},
Joe Hammaned7ad4e2007-04-30 16:47:28 -05001207 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
Peter Tyser3c93d8b2009-11-09 13:09:47 -06001208 /* Initial config/enable of secondary SerDes interface */
1209 {MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x14, 0xf), NULL},
1210 /* Write intial value to secondary SerDes Contol */
1211 {MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_SSD | 0, NULL},
1212 {MIIM_BCM54XX_EXP_DATA, MIIM_CONTROL_RESTART, NULL},
1213 /* Enable copper/fiber auto-detect */
1214 {MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x1e, 0x201)},
Joe Hammaned7ad4e2007-04-30 16:47:28 -05001215 {miim_end,}
1216 },
1217 (struct phy_cmd[]) { /* startup */
1218 /* Status is read once to clear old link state */
1219 {MIIM_STATUS, miim_read, NULL},
Peter Tyser3c93d8b2009-11-09 13:09:47 -06001220 /* Determine copper/fiber, auto-negotiate, and read the result */
1221 {MIIM_STATUS, miim_read, &mii_parse_BCM5482_sr},
Joe Hammaned7ad4e2007-04-30 16:47:28 -05001222 {miim_end,}
1223 },
1224 (struct phy_cmd[]) { /* shutdown */
1225 {miim_end,}
1226 },
1227};
1228
Peter Tyser08b2d782009-11-09 13:09:45 -06001229static struct phy_info phy_info_M88E1011S = {
wdenka445ddf2004-06-09 00:34:46 +00001230 0x01410c6,
1231 "Marvell 88E1011S",
1232 4,
Peter Tyser4ef03c02009-11-09 13:09:46 -06001233 (struct phy_cmd[]) { /* config */
1234 /* Reset and configure the PHY */
1235 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1236 {0x1d, 0x1f, NULL},
1237 {0x1e, 0x200c, NULL},
1238 {0x1d, 0x5, NULL},
1239 {0x1e, 0x0, NULL},
1240 {0x1e, 0x100, NULL},
1241 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1242 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1243 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1244 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1245 {miim_end,}
1246 },
1247 (struct phy_cmd[]) { /* startup */
1248 /* Status is read once to clear old link state */
1249 {MIIM_STATUS, miim_read, NULL},
1250 /* Auto-negotiate */
1251 {MIIM_STATUS, miim_read, &mii_parse_sr},
1252 /* Read the status */
1253 {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr},
1254 {miim_end,}
1255 },
1256 (struct phy_cmd[]) { /* shutdown */
1257 {miim_end,}
1258 },
wdenka445ddf2004-06-09 00:34:46 +00001259};
1260
Peter Tyser08b2d782009-11-09 13:09:45 -06001261static struct phy_info phy_info_M88E1111S = {
wdenkbfad55d2005-03-14 23:56:42 +00001262 0x01410cc,
1263 "Marvell 88E1111S",
1264 4,
Peter Tyser4ef03c02009-11-09 13:09:46 -06001265 (struct phy_cmd[]) { /* config */
1266 /* Reset and configure the PHY */
1267 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1268 {0x1b, 0x848f, &mii_m88e1111s_setmode},
1269 {0x14, 0x0cd2, NULL}, /* Delay RGMII TX and RX */
1270 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1271 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1272 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1273 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1274 {miim_end,}
1275 },
1276 (struct phy_cmd[]) { /* startup */
1277 /* Status is read once to clear old link state */
1278 {MIIM_STATUS, miim_read, NULL},
1279 /* Auto-negotiate */
1280 {MIIM_STATUS, miim_read, &mii_parse_sr},
1281 /* Read the status */
1282 {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr},
1283 {miim_end,}
1284 },
1285 (struct phy_cmd[]) { /* shutdown */
1286 {miim_end,}
1287 },
wdenkbfad55d2005-03-14 23:56:42 +00001288};
1289
Peter Tyser08b2d782009-11-09 13:09:45 -06001290static struct phy_info phy_info_M88E1118 = {
Ron Madridc1e2b582008-05-23 15:37:05 -07001291 0x01410e1,
1292 "Marvell 88E1118",
1293 4,
Peter Tyser4ef03c02009-11-09 13:09:46 -06001294 (struct phy_cmd[]) { /* config */
Ron Madridc1e2b582008-05-23 15:37:05 -07001295 /* Reset and configure the PHY */
1296 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1297 {0x16, 0x0002, NULL}, /* Change Page Number */
1298 {0x15, 0x1070, NULL}, /* Delay RGMII TX and RX */
Ron Madridaa4aac42009-01-28 16:17:21 -08001299 {0x16, 0x0003, NULL}, /* Change Page Number */
1300 {0x10, 0x021e, NULL}, /* Adjust LED control */
1301 {0x16, 0x0000, NULL}, /* Change Page Number */
Ron Madridc1e2b582008-05-23 15:37:05 -07001302 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1303 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1304 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1305 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1306 {miim_end,}
Peter Tyser4ef03c02009-11-09 13:09:46 -06001307 },
1308 (struct phy_cmd[]) { /* startup */
Ron Madridc1e2b582008-05-23 15:37:05 -07001309 {0x16, 0x0000, NULL}, /* Change Page Number */
1310 /* Status is read once to clear old link state */
1311 {MIIM_STATUS, miim_read, NULL},
1312 /* Auto-negotiate */
Ron Madridaa4aac42009-01-28 16:17:21 -08001313 {MIIM_STATUS, miim_read, &mii_parse_sr},
Ron Madridc1e2b582008-05-23 15:37:05 -07001314 /* Read the status */
1315 {MIIM_88E1011_PHY_STATUS, miim_read,
1316 &mii_parse_88E1011_psr},
1317 {miim_end,}
Peter Tyser4ef03c02009-11-09 13:09:46 -06001318 },
1319 (struct phy_cmd[]) { /* shutdown */
Ron Madridc1e2b582008-05-23 15:37:05 -07001320 {miim_end,}
Peter Tyser4ef03c02009-11-09 13:09:46 -06001321 },
Ron Madridc1e2b582008-05-23 15:37:05 -07001322};
1323
Sergei Poselenov7d4a2c32008-06-06 15:52:44 +02001324/*
1325 * Since to access LED register we need do switch the page, we
1326 * do LED configuring in the miim_read-like function as follows
1327 */
Peter Tyser08b2d782009-11-09 13:09:45 -06001328static uint mii_88E1121_set_led (uint mii_reg, struct tsec_private *priv)
Sergei Poselenov7d4a2c32008-06-06 15:52:44 +02001329{
1330 uint pg;
1331
1332 /* Switch the page to access the led register */
1333 pg = read_phy_reg(priv, MIIM_88E1121_PHY_PAGE);
1334 write_phy_reg(priv, MIIM_88E1121_PHY_PAGE, MIIM_88E1121_PHY_LED_PAGE);
1335
1336 /* Configure leds */
1337 write_phy_reg(priv, MIIM_88E1121_PHY_LED_CTRL,
1338 MIIM_88E1121_PHY_LED_DEF);
1339
1340 /* Restore the page pointer */
1341 write_phy_reg(priv, MIIM_88E1121_PHY_PAGE, pg);
1342 return 0;
1343}
1344
Peter Tyser08b2d782009-11-09 13:09:45 -06001345static struct phy_info phy_info_M88E1121R = {
Sergei Poselenov7d4a2c32008-06-06 15:52:44 +02001346 0x01410cb,
1347 "Marvell 88E1121R",
1348 4,
Peter Tyser4ef03c02009-11-09 13:09:46 -06001349 (struct phy_cmd[]) { /* config */
1350 /* Reset and configure the PHY */
1351 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1352 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1353 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1354 /* Configure leds */
1355 {MIIM_88E1121_PHY_LED_CTRL, miim_read, &mii_88E1121_set_led},
1356 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1357 /* Disable IRQs and de-assert interrupt */
1358 {MIIM_88E1121_PHY_IRQ_EN, 0, NULL},
1359 {MIIM_88E1121_PHY_IRQ_STATUS, miim_read, NULL},
1360 {miim_end,}
1361 },
1362 (struct phy_cmd[]) { /* startup */
1363 /* Status is read once to clear old link state */
1364 {MIIM_STATUS, miim_read, NULL},
1365 {MIIM_STATUS, miim_read, &mii_parse_sr},
1366 {MIIM_STATUS, miim_read, &mii_parse_link},
1367 {miim_end,}
1368 },
1369 (struct phy_cmd[]) { /* shutdown */
1370 {miim_end,}
1371 },
Sergei Poselenov7d4a2c32008-06-06 15:52:44 +02001372};
1373
Andy Fleming239e75f2006-09-13 10:34:18 -05001374static unsigned int m88e1145_setmode(uint mii_reg, struct tsec_private *priv)
1375{
Andy Fleming239e75f2006-09-13 10:34:18 -05001376 uint mii_data = read_phy_reg(priv, mii_reg);
1377
Andy Fleming239e75f2006-09-13 10:34:18 -05001378 /* Setting MIIM_88E1145_PHY_EXT_CR */
1379 if (priv->flags & TSEC_REDUCED)
1380 return mii_data |
Jon Loeligerb7ced082006-10-10 17:03:43 -05001381 MIIM_M88E1145_RGMII_RX_DELAY | MIIM_M88E1145_RGMII_TX_DELAY;
Andy Fleming239e75f2006-09-13 10:34:18 -05001382 else
1383 return mii_data;
1384}
1385
1386static struct phy_info phy_info_M88E1145 = {
1387 0x01410cd,
1388 "Marvell 88E1145",
1389 4,
Peter Tyser4ef03c02009-11-09 13:09:46 -06001390 (struct phy_cmd[]) { /* config */
1391 /* Reset the PHY */
1392 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
Andy Fleming180d03a2007-05-08 17:23:02 -05001393
Peter Tyser4ef03c02009-11-09 13:09:46 -06001394 /* Errata E0, E1 */
1395 {29, 0x001b, NULL},
1396 {30, 0x418f, NULL},
1397 {29, 0x0016, NULL},
1398 {30, 0xa2da, NULL},
Andy Fleming239e75f2006-09-13 10:34:18 -05001399
Peter Tyser4ef03c02009-11-09 13:09:46 -06001400 /* Configure the PHY */
1401 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1402 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1403 {MIIM_88E1011_PHY_SCR, MIIM_88E1011_PHY_MDI_X_AUTO, NULL},
1404 {MIIM_88E1145_PHY_EXT_CR, 0, &m88e1145_setmode},
1405 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1406 {MIIM_CONTROL, MIIM_CONTROL_INIT, NULL},
1407 {miim_end,}
1408 },
1409 (struct phy_cmd[]) { /* startup */
1410 /* Status is read once to clear old link state */
1411 {MIIM_STATUS, miim_read, NULL},
1412 /* Auto-negotiate */
1413 {MIIM_STATUS, miim_read, &mii_parse_sr},
1414 {MIIM_88E1111_PHY_LED_CONTROL, MIIM_88E1111_PHY_LED_DIRECT, NULL},
1415 /* Read the Status */
1416 {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr},
1417 {miim_end,}
1418 },
1419 (struct phy_cmd[]) { /* shutdown */
1420 {miim_end,}
1421 },
Andy Fleming239e75f2006-09-13 10:34:18 -05001422};
1423
Peter Tyser08b2d782009-11-09 13:09:45 -06001424static struct phy_info phy_info_cis8204 = {
wdenka445ddf2004-06-09 00:34:46 +00001425 0x3f11,
1426 "Cicada Cis8204",
1427 6,
Peter Tyser4ef03c02009-11-09 13:09:46 -06001428 (struct phy_cmd[]) { /* config */
1429 /* Override PHY config settings */
1430 {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL},
1431 /* Configure some basic stuff */
1432 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1433 {MIIM_CIS8204_SLED_CON, MIIM_CIS8204_SLEDCON_INIT,
1434 &mii_cis8204_fixled},
1435 {MIIM_CIS8204_EPHY_CON, MIIM_CIS8204_EPHYCON_INIT,
1436 &mii_cis8204_setmode},
1437 {miim_end,}
1438 },
1439 (struct phy_cmd[]) { /* startup */
1440 /* Read the Status (2x to make sure link is right) */
1441 {MIIM_STATUS, miim_read, NULL},
1442 /* Auto-negotiate */
1443 {MIIM_STATUS, miim_read, &mii_parse_sr},
1444 /* Read the status */
1445 {MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201},
1446 {miim_end,}
1447 },
1448 (struct phy_cmd[]) { /* shutdown */
1449 {miim_end,}
1450 },
wdenka445ddf2004-06-09 00:34:46 +00001451};
1452
1453/* Cicada 8201 */
Peter Tyser08b2d782009-11-09 13:09:45 -06001454static struct phy_info phy_info_cis8201 = {
wdenka445ddf2004-06-09 00:34:46 +00001455 0xfc41,
1456 "CIS8201",
1457 4,
Peter Tyser4ef03c02009-11-09 13:09:46 -06001458 (struct phy_cmd[]) { /* config */
1459 /* Override PHY config settings */
1460 {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL},
1461 /* Set up the interface mode */
1462 {MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL},
1463 /* Configure some basic stuff */
1464 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1465 {miim_end,}
1466 },
1467 (struct phy_cmd[]) { /* startup */
1468 /* Read the Status (2x to make sure link is right) */
1469 {MIIM_STATUS, miim_read, NULL},
1470 /* Auto-negotiate */
1471 {MIIM_STATUS, miim_read, &mii_parse_sr},
1472 /* Read the status */
1473 {MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201},
1474 {miim_end,}
1475 },
1476 (struct phy_cmd[]) { /* shutdown */
1477 {miim_end,}
1478 },
wdenka445ddf2004-06-09 00:34:46 +00001479};
Peter Tyser08b2d782009-11-09 13:09:45 -06001480
1481static struct phy_info phy_info_VSC8211 = {
Pieter Henning9370c8b2009-02-22 23:17:15 -08001482 0xfc4b,
1483 "Vitesse VSC8211",
1484 4,
1485 (struct phy_cmd[]) { /* config */
Peter Tyser4ef03c02009-11-09 13:09:46 -06001486 /* Override PHY config settings */
1487 {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL},
1488 /* Set up the interface mode */
1489 {MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL},
1490 /* Configure some basic stuff */
1491 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1492 {miim_end,}
1493 },
Pieter Henning9370c8b2009-02-22 23:17:15 -08001494 (struct phy_cmd[]) { /* startup */
Peter Tyser4ef03c02009-11-09 13:09:46 -06001495 /* Read the Status (2x to make sure link is right) */
1496 {MIIM_STATUS, miim_read, NULL},
1497 /* Auto-negotiate */
1498 {MIIM_STATUS, miim_read, &mii_parse_sr},
1499 /* Read the status */
1500 {MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201},
1501 {miim_end,}
1502 },
Pieter Henning9370c8b2009-02-22 23:17:15 -08001503 (struct phy_cmd[]) { /* shutdown */
Peter Tyser4ef03c02009-11-09 13:09:46 -06001504 {miim_end,}
Pieter Henning9370c8b2009-02-22 23:17:15 -08001505 },
1506};
Peter Tyser08b2d782009-11-09 13:09:45 -06001507
1508static struct phy_info phy_info_VSC8244 = {
Jon Loeligerb7ced082006-10-10 17:03:43 -05001509 0x3f1b,
1510 "Vitesse VSC8244",
1511 6,
Peter Tyser4ef03c02009-11-09 13:09:46 -06001512 (struct phy_cmd[]) { /* config */
1513 /* Override PHY config settings */
1514 /* Configure some basic stuff */
1515 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1516 {miim_end,}
1517 },
1518 (struct phy_cmd[]) { /* startup */
1519 /* Read the Status (2x to make sure link is right) */
1520 {MIIM_STATUS, miim_read, NULL},
1521 /* Auto-negotiate */
1522 {MIIM_STATUS, miim_read, &mii_parse_sr},
1523 /* Read the status */
1524 {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244},
1525 {miim_end,}
1526 },
1527 (struct phy_cmd[]) { /* shutdown */
1528 {miim_end,}
1529 },
Jon Loeliger5c8aa972006-04-26 17:58:56 -05001530};
wdenka445ddf2004-06-09 00:34:46 +00001531
Peter Tyser08b2d782009-11-09 13:09:45 -06001532static struct phy_info phy_info_VSC8641 = {
Poonam Aggrwalc91b5de2009-07-02 16:15:13 +05301533 0x7043,
1534 "Vitesse VSC8641",
1535 4,
Peter Tyser4ef03c02009-11-09 13:09:46 -06001536 (struct phy_cmd[]) { /* config */
1537 /* Configure some basic stuff */
1538 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1539 {miim_end,}
1540 },
1541 (struct phy_cmd[]) { /* startup */
1542 /* Read the Status (2x to make sure link is right) */
1543 {MIIM_STATUS, miim_read, NULL},
1544 /* Auto-negotiate */
1545 {MIIM_STATUS, miim_read, &mii_parse_sr},
1546 /* Read the status */
1547 {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244},
1548 {miim_end,}
1549 },
1550 (struct phy_cmd[]) { /* shutdown */
1551 {miim_end,}
1552 },
Poonam Aggrwalc91b5de2009-07-02 16:15:13 +05301553};
1554
Peter Tyser08b2d782009-11-09 13:09:45 -06001555static struct phy_info phy_info_VSC8221 = {
Poonam Aggrwalc91b5de2009-07-02 16:15:13 +05301556 0xfc55,
1557 "Vitesse VSC8221",
1558 4,
Peter Tyser4ef03c02009-11-09 13:09:46 -06001559 (struct phy_cmd[]) { /* config */
1560 /* Configure some basic stuff */
1561 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1562 {miim_end,}
1563 },
1564 (struct phy_cmd[]) { /* startup */
1565 /* Read the Status (2x to make sure link is right) */
1566 {MIIM_STATUS, miim_read, NULL},
1567 /* Auto-negotiate */
1568 {MIIM_STATUS, miim_read, &mii_parse_sr},
1569 /* Read the status */
1570 {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244},
1571 {miim_end,}
1572 },
1573 (struct phy_cmd[]) { /* shutdown */
1574 {miim_end,}
1575 },
Poonam Aggrwalc91b5de2009-07-02 16:15:13 +05301576};
1577
Peter Tyser08b2d782009-11-09 13:09:45 -06001578static struct phy_info phy_info_VSC8601 = {
Peter Tyser4ef03c02009-11-09 13:09:46 -06001579 0x00007042,
1580 "Vitesse VSC8601",
1581 4,
1582 (struct phy_cmd[]) { /* config */
1583 /* Override PHY config settings */
1584 /* Configure some basic stuff */
1585 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001586#ifdef CONFIG_SYS_VSC8601_SKEWFIX
Peter Tyser4ef03c02009-11-09 13:09:46 -06001587 {MIIM_VSC8601_EPHY_CON,MIIM_VSC8601_EPHY_CON_INIT_SKEW,NULL},
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001588#if defined(CONFIG_SYS_VSC8601_SKEW_TX) && defined(CONFIG_SYS_VSC8601_SKEW_RX)
Peter Tyser4ef03c02009-11-09 13:09:46 -06001589 {MIIM_EXT_PAGE_ACCESS,1,NULL},
1590#define VSC8101_SKEW \
1591 (CONFIG_SYS_VSC8601_SKEW_TX << 14) | (CONFIG_SYS_VSC8601_SKEW_RX << 12)
1592 {MIIM_VSC8601_SKEW_CTRL,VSC8101_SKEW,NULL},
1593 {MIIM_EXT_PAGE_ACCESS,0,NULL},
Andre Schwarz1e18be12008-04-29 19:18:32 +02001594#endif
Tor Krill8b3a82f2008-03-28 15:29:45 +01001595#endif
Peter Tyser4ef03c02009-11-09 13:09:46 -06001596 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1597 {MIIM_CONTROL, MIIM_CONTROL_RESTART, &mii_cr_init},
1598 {miim_end,}
1599 },
1600 (struct phy_cmd[]) { /* startup */
1601 /* Read the Status (2x to make sure link is right) */
1602 {MIIM_STATUS, miim_read, NULL},
1603 /* Auto-negotiate */
1604 {MIIM_STATUS, miim_read, &mii_parse_sr},
1605 /* Read the status */
1606 {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244},
1607 {miim_end,}
1608 },
1609 (struct phy_cmd[]) { /* shutdown */
1610 {miim_end,}
1611 },
Tor Krill8b3a82f2008-03-28 15:29:45 +01001612};
1613
Peter Tyser08b2d782009-11-09 13:09:45 -06001614static struct phy_info phy_info_dm9161 = {
wdenka445ddf2004-06-09 00:34:46 +00001615 0x0181b88,
1616 "Davicom DM9161E",
1617 4,
Peter Tyser4ef03c02009-11-09 13:09:46 -06001618 (struct phy_cmd[]) { /* config */
1619 {MIIM_CONTROL, MIIM_DM9161_CR_STOP, NULL},
1620 /* Do not bypass the scrambler/descrambler */
1621 {MIIM_DM9161_SCR, MIIM_DM9161_SCR_INIT, NULL},
1622 /* Clear 10BTCSR to default */
1623 {MIIM_DM9161_10BTCSR, MIIM_DM9161_10BTCSR_INIT, NULL},
1624 /* Configure some basic stuff */
1625 {MIIM_CONTROL, MIIM_CR_INIT, NULL},
1626 /* Restart Auto Negotiation */
1627 {MIIM_CONTROL, MIIM_DM9161_CR_RSTAN, NULL},
1628 {miim_end,}
1629 },
1630 (struct phy_cmd[]) { /* startup */
1631 /* Status is read once to clear old link state */
1632 {MIIM_STATUS, miim_read, NULL},
1633 /* Auto-negotiate */
1634 {MIIM_STATUS, miim_read, &mii_parse_sr},
1635 /* Read the status */
1636 {MIIM_DM9161_SCSR, miim_read, &mii_parse_dm9161_scsr},
1637 {miim_end,}
1638 },
1639 (struct phy_cmd[]) { /* shutdown */
1640 {miim_end,}
1641 },
wdenka445ddf2004-06-09 00:34:46 +00001642};
Peter Tyser4ef03c02009-11-09 13:09:46 -06001643
Heiko Schocher6d9933f2010-07-05 12:23:04 +02001644/* micrel KSZ804 */
1645static struct phy_info phy_info_ksz804 = {
1646 0x0022151,
1647 "Micrel KSZ804 PHY",
1648 4,
1649 (struct phy_cmd[]) { /* config */
Mike Frysingerd63ee712010-12-23 15:40:12 -05001650 {MII_BMCR, BMCR_RESET, NULL},
1651 {MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART, NULL},
Heiko Schocher6d9933f2010-07-05 12:23:04 +02001652 {miim_end,}
1653 },
1654 (struct phy_cmd[]) { /* startup */
Mike Frysingerd63ee712010-12-23 15:40:12 -05001655 {MII_BMSR, miim_read, NULL},
1656 {MII_BMSR, miim_read, &mii_parse_sr},
1657 {MII_BMSR, miim_read, &mii_parse_link},
Heiko Schocher6d9933f2010-07-05 12:23:04 +02001658 {miim_end,}
1659 },
1660 (struct phy_cmd[]) { /* shutdown */
1661 {miim_end,}
1662 }
1663};
1664
David Updegraff0451b012007-04-20 14:34:48 -05001665/* a generic flavor. */
Peter Tyser08b2d782009-11-09 13:09:45 -06001666static struct phy_info phy_info_generic = {
David Updegraff0451b012007-04-20 14:34:48 -05001667 0,
1668 "Unknown/Generic PHY",
1669 32,
1670 (struct phy_cmd[]) { /* config */
Mike Frysingerd63ee712010-12-23 15:40:12 -05001671 {MII_BMCR, BMCR_RESET, NULL},
1672 {MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART, NULL},
David Updegraff0451b012007-04-20 14:34:48 -05001673 {miim_end,}
1674 },
1675 (struct phy_cmd[]) { /* startup */
Mike Frysingerd63ee712010-12-23 15:40:12 -05001676 {MII_BMSR, miim_read, NULL},
1677 {MII_BMSR, miim_read, &mii_parse_sr},
1678 {MII_BMSR, miim_read, &mii_parse_link},
David Updegraff0451b012007-04-20 14:34:48 -05001679 {miim_end,}
1680 },
1681 (struct phy_cmd[]) { /* shutdown */
1682 {miim_end,}
1683 }
1684};
1685
Peter Tyser08b2d782009-11-09 13:09:45 -06001686static uint mii_parse_lxt971_sr2(uint mii_reg, struct tsec_private *priv)
wdenkf41ff3b2005-04-04 23:43:44 +00001687{
wdenke085e5b2005-04-05 23:32:21 +00001688 unsigned int speed;
1689 if (priv->link) {
1690 speed = mii_reg & MIIM_LXT971_SR2_SPEED_MASK;
wdenkf41ff3b2005-04-04 23:43:44 +00001691
wdenke085e5b2005-04-05 23:32:21 +00001692 switch (speed) {
1693 case MIIM_LXT971_SR2_10HDX:
1694 priv->speed = 10;
1695 priv->duplexity = 0;
1696 break;
1697 case MIIM_LXT971_SR2_10FDX:
1698 priv->speed = 10;
1699 priv->duplexity = 1;
1700 break;
1701 case MIIM_LXT971_SR2_100HDX:
1702 priv->speed = 100;
1703 priv->duplexity = 0;
urwithsughosh@gmail.com34b3f2e2007-09-10 14:54:56 -04001704 break;
wdenke085e5b2005-04-05 23:32:21 +00001705 default:
1706 priv->speed = 100;
1707 priv->duplexity = 1;
wdenke085e5b2005-04-05 23:32:21 +00001708 }
1709 } else {
1710 priv->speed = 0;
1711 priv->duplexity = 0;
1712 }
wdenkf41ff3b2005-04-04 23:43:44 +00001713
wdenke085e5b2005-04-05 23:32:21 +00001714 return 0;
wdenkf41ff3b2005-04-04 23:43:44 +00001715}
1716
wdenkbfad55d2005-03-14 23:56:42 +00001717static struct phy_info phy_info_lxt971 = {
1718 0x0001378e,
1719 "LXT971",
1720 4,
Peter Tyser4ef03c02009-11-09 13:09:46 -06001721 (struct phy_cmd[]) { /* config */
1722 {MIIM_CR, MIIM_CR_INIT, mii_cr_init}, /* autonegotiate */
1723 {miim_end,}
1724 },
1725 (struct phy_cmd[]) { /* startup - enable interrupts */
1726 /* { 0x12, 0x00f2, NULL }, */
1727 {MIIM_STATUS, miim_read, NULL},
1728 {MIIM_STATUS, miim_read, &mii_parse_sr},
1729 {MIIM_LXT971_SR2, miim_read, &mii_parse_lxt971_sr2},
1730 {miim_end,}
1731 },
1732 (struct phy_cmd[]) { /* shutdown - disable interrupts */
1733 {miim_end,}
1734 },
wdenkbfad55d2005-03-14 23:56:42 +00001735};
1736
Wolfgang Denkf0c4e462006-03-12 22:50:55 +01001737/* Parse the DP83865's link and auto-neg status register for speed and duplex
Jon Loeligerb7ced082006-10-10 17:03:43 -05001738 * information
1739 */
Peter Tyser08b2d782009-11-09 13:09:45 -06001740static uint mii_parse_dp83865_lanr(uint mii_reg, struct tsec_private *priv)
Wolfgang Denkf0c4e462006-03-12 22:50:55 +01001741{
1742 switch (mii_reg & MIIM_DP83865_SPD_MASK) {
1743
1744 case MIIM_DP83865_SPD_1000:
1745 priv->speed = 1000;
1746 break;
1747
1748 case MIIM_DP83865_SPD_100:
1749 priv->speed = 100;
1750 break;
1751
1752 default:
1753 priv->speed = 10;
1754 break;
1755
1756 }
1757
1758 if (mii_reg & MIIM_DP83865_DPX_FULL)
1759 priv->duplexity = 1;
1760 else
1761 priv->duplexity = 0;
1762
1763 return 0;
1764}
1765
Peter Tyser08b2d782009-11-09 13:09:45 -06001766static struct phy_info phy_info_dp83865 = {
Wolfgang Denkf0c4e462006-03-12 22:50:55 +01001767 0x20005c7,
1768 "NatSemi DP83865",
1769 4,
Peter Tyser4ef03c02009-11-09 13:09:46 -06001770 (struct phy_cmd[]) { /* config */
1771 {MIIM_CONTROL, MIIM_DP83865_CR_INIT, NULL},
1772 {miim_end,}
1773 },
1774 (struct phy_cmd[]) { /* startup */
1775 /* Status is read once to clear old link state */
1776 {MIIM_STATUS, miim_read, NULL},
1777 /* Auto-negotiate */
1778 {MIIM_STATUS, miim_read, &mii_parse_sr},
1779 /* Read the link and auto-neg status */
1780 {MIIM_DP83865_LANR, miim_read, &mii_parse_dp83865_lanr},
1781 {miim_end,}
1782 },
1783 (struct phy_cmd[]) { /* shutdown */
1784 {miim_end,}
1785 },
Wolfgang Denkf0c4e462006-03-12 22:50:55 +01001786};
1787
Peter Tyser08b2d782009-11-09 13:09:45 -06001788static struct phy_info phy_info_rtl8211b = {
Dave Liua304a282008-01-11 18:45:28 +08001789 0x001cc91,
1790 "RealTek RTL8211B",
1791 4,
Peter Tyser4ef03c02009-11-09 13:09:46 -06001792 (struct phy_cmd[]) { /* config */
Dave Liua304a282008-01-11 18:45:28 +08001793 /* Reset and configure the PHY */
1794 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1795 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
1796 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
1797 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
1798 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
1799 {miim_end,}
1800 },
Peter Tyser4ef03c02009-11-09 13:09:46 -06001801 (struct phy_cmd[]) { /* startup */
Dave Liua304a282008-01-11 18:45:28 +08001802 /* Status is read once to clear old link state */
1803 {MIIM_STATUS, miim_read, NULL},
1804 /* Auto-negotiate */
1805 {MIIM_STATUS, miim_read, &mii_parse_sr},
1806 /* Read the status */
1807 {MIIM_RTL8211B_PHY_STATUS, miim_read, &mii_parse_RTL8211B_sr},
1808 {miim_end,}
1809 },
Peter Tyser4ef03c02009-11-09 13:09:46 -06001810 (struct phy_cmd[]) { /* shutdown */
Dave Liua304a282008-01-11 18:45:28 +08001811 {miim_end,}
1812 },
1813};
1814
Li Yang25e38bd2011-01-27 19:02:50 +08001815struct phy_info phy_info_AR8021 = {
1816 0x4dd04,
1817 "AR8021",
1818 4,
1819 (struct phy_cmd[]) { /* config */
1820 {MII_BMCR, BMCR_RESET, NULL},
1821 {MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART, NULL},
1822 {0x1d, 0x05, NULL},
1823 {0x1e, 0x3D47, NULL},
1824 {miim_end,}
1825 },
1826 (struct phy_cmd[]) { /* startup */
1827 {MII_BMSR, miim_read, NULL},
1828 {MII_BMSR, miim_read, &mii_parse_sr},
1829 {MII_BMSR, miim_read, &mii_parse_link},
1830 {miim_end,}
1831 },
1832 (struct phy_cmd[]) { /* shutdown */
1833 {miim_end,}
1834 }
1835};
1836
Peter Tyser08b2d782009-11-09 13:09:45 -06001837static struct phy_info *phy_info[] = {
wdenka445ddf2004-06-09 00:34:46 +00001838 &phy_info_cis8204,
Timur Tabi054838e2006-10-31 18:44:42 -06001839 &phy_info_cis8201,
Paul Gortmaker2bd9f1b2007-01-16 11:38:14 -05001840 &phy_info_BCM5461S,
Joe Hammaned7ad4e2007-04-30 16:47:28 -05001841 &phy_info_BCM5464S,
Zach LeRoyddb7fc72009-05-22 10:26:33 -05001842 &phy_info_BCM5482S,
wdenka445ddf2004-06-09 00:34:46 +00001843 &phy_info_M88E1011S,
wdenkbfad55d2005-03-14 23:56:42 +00001844 &phy_info_M88E1111S,
Ron Madridc1e2b582008-05-23 15:37:05 -07001845 &phy_info_M88E1118,
Sergei Poselenov7d4a2c32008-06-06 15:52:44 +02001846 &phy_info_M88E1121R,
Andy Fleming239e75f2006-09-13 10:34:18 -05001847 &phy_info_M88E1145,
Wolfgang Denk15e87572007-08-06 01:01:49 +02001848 &phy_info_M88E1149S,
wdenka445ddf2004-06-09 00:34:46 +00001849 &phy_info_dm9161,
Heiko Schocher6d9933f2010-07-05 12:23:04 +02001850 &phy_info_ksz804,
wdenkbfad55d2005-03-14 23:56:42 +00001851 &phy_info_lxt971,
Pieter Henning9370c8b2009-02-22 23:17:15 -08001852 &phy_info_VSC8211,
Jon Loeliger5c8aa972006-04-26 17:58:56 -05001853 &phy_info_VSC8244,
Tor Krill8b3a82f2008-03-28 15:29:45 +01001854 &phy_info_VSC8601,
Poonam Aggrwalc91b5de2009-07-02 16:15:13 +05301855 &phy_info_VSC8641,
1856 &phy_info_VSC8221,
Wolfgang Denkf0c4e462006-03-12 22:50:55 +01001857 &phy_info_dp83865,
Dave Liua304a282008-01-11 18:45:28 +08001858 &phy_info_rtl8211b,
Li Yang25e38bd2011-01-27 19:02:50 +08001859 &phy_info_AR8021,
Paul Gortmakerf81b8232009-03-09 18:07:53 -05001860 &phy_info_generic, /* must be last; has ID 0 and 32 bit mask */
wdenka445ddf2004-06-09 00:34:46 +00001861 NULL
1862};
1863
wdenka445ddf2004-06-09 00:34:46 +00001864/* Grab the identifier of the device's PHY, and search through
wdenkbfad55d2005-03-14 23:56:42 +00001865 * all of the known PHYs to see if one matches. If so, return
Jon Loeligerb7ced082006-10-10 17:03:43 -05001866 * it, if not, return NULL
1867 */
Peter Tyser08b2d782009-11-09 13:09:45 -06001868static struct phy_info *get_phy_info(struct eth_device *dev)
wdenka445ddf2004-06-09 00:34:46 +00001869{
1870 struct tsec_private *priv = (struct tsec_private *)dev->priv;
1871 uint phy_reg, phy_ID;
1872 int i;
1873 struct phy_info *theInfo = NULL;
1874
1875 /* Grab the bits from PHYIR1, and put them in the upper half */
1876 phy_reg = read_phy_reg(priv, MIIM_PHYIR1);
1877 phy_ID = (phy_reg & 0xffff) << 16;
1878
1879 /* Grab the bits from PHYIR2, and put them in the lower half */
1880 phy_reg = read_phy_reg(priv, MIIM_PHYIR2);
1881 phy_ID |= (phy_reg & 0xffff);
1882
1883 /* loop through all the known PHY types, and find one that */
1884 /* matches the ID we read from the PHY. */
Jon Loeligerb7ced082006-10-10 17:03:43 -05001885 for (i = 0; phy_info[i]; i++) {
Andy Flemingb2d14f42007-05-09 00:54:20 -05001886 if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) {
wdenka445ddf2004-06-09 00:34:46 +00001887 theInfo = phy_info[i];
Andy Flemingb2d14f42007-05-09 00:54:20 -05001888 break;
1889 }
wdenka445ddf2004-06-09 00:34:46 +00001890 }
1891
Paul Gortmakerf81b8232009-03-09 18:07:53 -05001892 if (theInfo == &phy_info_generic) {
Peter Tyser4ef03c02009-11-09 13:09:46 -06001893 printf("%s: No support for PHY id %x; assuming generic\n",
1894 dev->name, phy_ID);
wdenka445ddf2004-06-09 00:34:46 +00001895 } else {
Stefan Roesec0dc34f2005-09-21 18:20:22 +02001896 debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID);
wdenka445ddf2004-06-09 00:34:46 +00001897 }
1898
1899 return theInfo;
1900}
1901
wdenka445ddf2004-06-09 00:34:46 +00001902/* Execute the given series of commands on the given device's
Jon Loeligerb7ced082006-10-10 17:03:43 -05001903 * PHY, running functions as necessary
1904 */
Peter Tyser08b2d782009-11-09 13:09:45 -06001905static void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd)
wdenka445ddf2004-06-09 00:34:46 +00001906{
1907 int i;
1908 uint result;
Mingkai Hua65e6102011-01-27 12:52:45 +08001909 tsec_mdio_t *phyregs = priv->phyregs;
wdenka445ddf2004-06-09 00:34:46 +00001910
Mingkai Hua65e6102011-01-27 12:52:45 +08001911 out_be32(&phyregs->miimcfg, MIIMCFG_RESET);
wdenka445ddf2004-06-09 00:34:46 +00001912
Mingkai Hua65e6102011-01-27 12:52:45 +08001913 out_be32(&phyregs->miimcfg, MIIMCFG_INIT_VALUE);
wdenka445ddf2004-06-09 00:34:46 +00001914
Mingkai Hua65e6102011-01-27 12:52:45 +08001915 while (in_be32(&phyregs->miimind) & MIIMIND_BUSY)
1916 ;
wdenka445ddf2004-06-09 00:34:46 +00001917
Jon Loeligerb7ced082006-10-10 17:03:43 -05001918 for (i = 0; cmd->mii_reg != miim_end; i++) {
1919 if (cmd->mii_data == miim_read) {
wdenka445ddf2004-06-09 00:34:46 +00001920 result = read_phy_reg(priv, cmd->mii_reg);
1921
Jon Loeligerb7ced082006-10-10 17:03:43 -05001922 if (cmd->funct != NULL)
1923 (*(cmd->funct)) (result, priv);
wdenka445ddf2004-06-09 00:34:46 +00001924
1925 } else {
Jon Loeligerb7ced082006-10-10 17:03:43 -05001926 if (cmd->funct != NULL)
1927 result = (*(cmd->funct)) (cmd->mii_reg, priv);
wdenka445ddf2004-06-09 00:34:46 +00001928 else
1929 result = cmd->mii_data;
1930
1931 write_phy_reg(priv, cmd->mii_reg, result);
1932
1933 }
1934 cmd++;
1935 }
1936}
1937
Jon Loeliger82ecaad2007-07-09 17:39:42 -05001938#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
Marian Balakowiczaab8c492005-10-28 22:30:33 +02001939 && !defined(BITBANGMII)
wdenka445ddf2004-06-09 00:34:46 +00001940
wdenk78924a72004-04-18 21:45:42 +00001941/*
1942 * Read a MII PHY register.
1943 *
1944 * Returns:
wdenka445ddf2004-06-09 00:34:46 +00001945 * 0 on success
wdenk78924a72004-04-18 21:45:42 +00001946 */
Mike Frysinger5ff5fdb2010-07-27 18:35:08 -04001947static int tsec_miiphy_read(const char *devname, unsigned char addr,
Jon Loeligerb7ced082006-10-10 17:03:43 -05001948 unsigned char reg, unsigned short *value)
wdenk78924a72004-04-18 21:45:42 +00001949{
wdenka445ddf2004-06-09 00:34:46 +00001950 unsigned short ret;
michael.firth@bt.com08384842008-01-16 11:40:51 +00001951 struct tsec_private *priv = privlist[0];
wdenk78924a72004-04-18 21:45:42 +00001952
Jon Loeligerb7ced082006-10-10 17:03:43 -05001953 if (NULL == priv) {
wdenka445ddf2004-06-09 00:34:46 +00001954 printf("Can't read PHY at address %d\n", addr);
1955 return -1;
1956 }
1957
Andy Flemingac65e072008-08-31 16:33:27 -05001958 ret = (unsigned short)tsec_local_mdio_read(priv->phyregs, addr, reg);
wdenka445ddf2004-06-09 00:34:46 +00001959 *value = ret;
wdenk78924a72004-04-18 21:45:42 +00001960
1961 return 0;
1962}
1963
1964/*
1965 * Write a MII PHY register.
1966 *
1967 * Returns:
wdenka445ddf2004-06-09 00:34:46 +00001968 * 0 on success
wdenk78924a72004-04-18 21:45:42 +00001969 */
Mike Frysinger5ff5fdb2010-07-27 18:35:08 -04001970static int tsec_miiphy_write(const char *devname, unsigned char addr,
Jon Loeligerb7ced082006-10-10 17:03:43 -05001971 unsigned char reg, unsigned short value)
wdenk78924a72004-04-18 21:45:42 +00001972{
michael.firth@bt.com08384842008-01-16 11:40:51 +00001973 struct tsec_private *priv = privlist[0];
wdenka445ddf2004-06-09 00:34:46 +00001974
Jon Loeligerb7ced082006-10-10 17:03:43 -05001975 if (NULL == priv) {
wdenka445ddf2004-06-09 00:34:46 +00001976 printf("Can't write PHY at address %d\n", addr);
1977 return -1;
1978 }
wdenk78924a72004-04-18 21:45:42 +00001979
Andy Flemingac65e072008-08-31 16:33:27 -05001980 tsec_local_mdio_write(priv->phyregs, addr, reg, value);
wdenk78924a72004-04-18 21:45:42 +00001981
1982 return 0;
wdenk9c53f402003-10-15 23:53:47 +00001983}
wdenka445ddf2004-06-09 00:34:46 +00001984
Jon Loeliger82ecaad2007-07-09 17:39:42 -05001985#endif
wdenka445ddf2004-06-09 00:34:46 +00001986
David Updegraff7280da72007-06-11 10:41:07 -05001987#ifdef CONFIG_MCAST_TFTP
1988
1989/* CREDITS: linux gianfar driver, slightly adjusted... thanx. */
1990
1991/* Set the appropriate hash bit for the given addr */
1992
1993/* The algorithm works like so:
1994 * 1) Take the Destination Address (ie the multicast address), and
1995 * do a CRC on it (little endian), and reverse the bits of the
1996 * result.
1997 * 2) Use the 8 most significant bits as a hash into a 256-entry
1998 * table. The table is controlled through 8 32-bit registers:
1999 * gaddr0-7. gaddr0's MSB is entry 0, and gaddr7's LSB is
2000 * gaddr7. This means that the 3 most significant bits in the
2001 * hash index which gaddr register to use, and the 5 other bits
2002 * indicate which bit (assuming an IBM numbering scheme, which
2003 * for PowerPC (tm) is usually the case) in the tregister holds
2004 * the entry. */
2005static int
2006tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set)
2007{
Peter Tyser4ef03c02009-11-09 13:09:46 -06002008 struct tsec_private *priv = privlist[1];
2009 volatile tsec_t *regs = priv->regs;
2010 volatile u32 *reg_array, value;
2011 u8 result, whichbit, whichreg;
David Updegraff7280da72007-06-11 10:41:07 -05002012
2013 result = (u8)((ether_crc(MAC_ADDR_LEN,mcast_mac) >> 24) & 0xff);
2014 whichbit = result & 0x1f; /* the 5 LSB = which bit to set */
2015 whichreg = result >> 5; /* the 3 MSB = which reg to set it in */
2016 value = (1 << (31-whichbit));
2017
2018 reg_array = &(regs->hash.gaddr0);
2019
2020 if (set) {
2021 reg_array[whichreg] |= value;
2022 } else {
2023 reg_array[whichreg] &= ~value;
2024 }
2025 return 0;
2026}
2027#endif /* Multicast TFTP ? */