blob: 18778c270a6491d8d92811af8b15b945e6c926f3 [file] [log] [blame]
wdenk9c53f402003-10-15 23:53:47 +00001/*
2 * tsec.c
wdenka445ddf2004-06-09 00:34:46 +00003 * Freescale Three Speed Ethernet Controller driver
wdenk9c53f402003-10-15 23:53:47 +00004 *
5 * This software may be used and distributed according to the
6 * terms of the GNU Public License, Version 2, incorporated
7 * herein by reference.
8 *
wdenka445ddf2004-06-09 00:34:46 +00009 * Copyright 2004 Freescale Semiconductor.
wdenk9c53f402003-10-15 23:53:47 +000010 * (C) Copyright 2003, Motorola, Inc.
wdenk9c53f402003-10-15 23:53:47 +000011 * author Andy Fleming
12 *
13 */
14
15#include <config.h>
16#include <mpc85xx.h>
Jon Loeliger5c8aa972006-04-26 17:58:56 -050017#include <mpc86xx.h>
wdenk9c53f402003-10-15 23:53:47 +000018#include <common.h>
19#include <malloc.h>
20#include <net.h>
21#include <command.h>
22
23#if defined(CONFIG_TSEC_ENET)
24#include "tsec.h"
Marian Balakowiczaab8c492005-10-28 22:30:33 +020025#include "miiphy.h"
wdenk9c53f402003-10-15 23:53:47 +000026
Wolfgang Denk6405a152006-03-31 18:32:53 +020027DECLARE_GLOBAL_DATA_PTR;
28
Marian Balakowiczaab8c492005-10-28 22:30:33 +020029#define TX_BUF_CNT 2
wdenk9c53f402003-10-15 23:53:47 +000030
wdenk9c53f402003-10-15 23:53:47 +000031static uint rxIdx; /* index of the current RX buffer */
32static uint txIdx; /* index of the current TX buffer */
33
34typedef volatile struct rtxbd {
35 txbd8_t txbd[TX_BUF_CNT];
36 rxbd8_t rxbd[PKTBUFSRX];
37} RTXBD;
38
wdenka445ddf2004-06-09 00:34:46 +000039struct tsec_info_struct {
40 unsigned int phyaddr;
Jon Loeliger77a4f6e2005-07-25 14:05:07 -050041 u32 flags;
wdenka445ddf2004-06-09 00:34:46 +000042 unsigned int phyregidx;
43};
44
45
46/* The tsec_info structure contains 3 values which the
47 * driver uses to determine how to operate a given ethernet
48 * device. For now, the structure is initialized with the
49 * knowledge that all current implementations have 2 TSEC
50 * devices, and one FEC. The information needed is:
51 * phyaddr - The address of the PHY which is attached to
wdenkbfad55d2005-03-14 23:56:42 +000052 * the given device.
wdenka445ddf2004-06-09 00:34:46 +000053 *
Jon Loeliger77a4f6e2005-07-25 14:05:07 -050054 * flags - This variable indicates whether the device
55 * supports gigabit speed ethernet, and whether it should be
56 * in reduced mode.
wdenka445ddf2004-06-09 00:34:46 +000057 *
58 * phyregidx - This variable specifies which ethernet device
wdenkbfad55d2005-03-14 23:56:42 +000059 * controls the MII Management registers which are connected
60 * to the PHY. For 8540/8560, only TSEC1 (index 0) has
61 * access to the PHYs, so all of the entries have "0".
wdenka445ddf2004-06-09 00:34:46 +000062 *
63 * The values specified in the table are taken from the board's
64 * config file in include/configs/. When implementing a new
65 * board with ethernet capability, it is necessary to define:
66 * TSEC1_PHY_ADDR
67 * TSEC1_PHYIDX
68 * TSEC2_PHY_ADDR
69 * TSEC2_PHYIDX
70 *
71 * and for 8560:
72 * FEC_PHY_ADDR
73 * FEC_PHYIDX
74 */
75static struct tsec_info_struct tsec_info[] = {
Eran Liberty9095d4a2005-07-28 10:08:46 -050076#if defined(CONFIG_MPC85XX_TSEC1) || defined(CONFIG_MPC83XX_TSEC1)
Jon Loeliger77a4f6e2005-07-25 14:05:07 -050077 {TSEC1_PHY_ADDR, TSEC_GIGABIT, TSEC1_PHYIDX},
Jon Loeliger5c8aa972006-04-26 17:58:56 -050078#elif defined(CONFIG_MPC86XX_TSEC1)
79 {TSEC1_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC1_PHYIDX},
wdenkbfad55d2005-03-14 23:56:42 +000080#else
81 { 0, 0, 0},
wdenka445ddf2004-06-09 00:34:46 +000082#endif
Eran Liberty9095d4a2005-07-28 10:08:46 -050083#if defined(CONFIG_MPC85XX_TSEC2) || defined(CONFIG_MPC83XX_TSEC2)
Jon Loeliger77a4f6e2005-07-25 14:05:07 -050084 {TSEC2_PHY_ADDR, TSEC_GIGABIT, TSEC2_PHYIDX},
Jon Loeliger5c8aa972006-04-26 17:58:56 -050085#elif defined(CONFIG_MPC86XX_TSEC2)
86 {TSEC2_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC2_PHYIDX},
wdenkbfad55d2005-03-14 23:56:42 +000087#else
88 { 0, 0, 0},
wdenka445ddf2004-06-09 00:34:46 +000089#endif
90#ifdef CONFIG_MPC85XX_FEC
91 {FEC_PHY_ADDR, 0, FEC_PHYIDX},
wdenkbfad55d2005-03-14 23:56:42 +000092#else
Jon Loeliger5c8aa972006-04-26 17:58:56 -050093#if defined(CONFIG_MPC85XX_TSEC3) || defined(CONFIG_MPC83XX_TSEC3) || defined(CONFIG_MPC86XX_TSEC3)
Jon Loeliger77a4f6e2005-07-25 14:05:07 -050094 {TSEC3_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC3_PHYIDX},
Jon Loeliger5c8aa972006-04-26 17:58:56 -050095#else
wdenkbfad55d2005-03-14 23:56:42 +000096 { 0, 0, 0},
Jon Loeliger5c8aa972006-04-26 17:58:56 -050097#endif
98#if defined(CONFIG_MPC85XX_TSEC4) || defined(CONFIG_MPC83XX_TSEC4)
Jon Loeliger77a4f6e2005-07-25 14:05:07 -050099 {TSEC4_PHY_ADDR, TSEC_REDUCED, TSEC4_PHYIDX},
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500100#elif defined(CONFIG_MPC86XX_TSEC4)
101 {TSEC4_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC4_PHYIDX},
102#else
Jon Loeliger77a4f6e2005-07-25 14:05:07 -0500103 { 0, 0, 0},
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500104#endif
wdenka445ddf2004-06-09 00:34:46 +0000105#endif
106};
107
Jon Loeliger77a4f6e2005-07-25 14:05:07 -0500108#define MAXCONTROLLERS (4)
wdenka445ddf2004-06-09 00:34:46 +0000109
110static int relocated = 0;
111
112static struct tsec_private *privlist[MAXCONTROLLERS];
113
wdenk9c53f402003-10-15 23:53:47 +0000114#ifdef __GNUC__
115static RTXBD rtx __attribute__ ((aligned(8)));
116#else
117#error "rtx must be 64-bit aligned"
118#endif
119
120static int tsec_send(struct eth_device* dev, volatile void *packet, int length);
121static int tsec_recv(struct eth_device* dev);
122static int tsec_init(struct eth_device* dev, bd_t * bd);
123static void tsec_halt(struct eth_device* dev);
wdenka445ddf2004-06-09 00:34:46 +0000124static void init_registers(volatile tsec_t *regs);
125static void startup_tsec(struct eth_device *dev);
126static int init_phy(struct eth_device *dev);
127void write_phy_reg(struct tsec_private *priv, uint regnum, uint value);
128uint read_phy_reg(struct tsec_private *priv, uint regnum);
129struct phy_info * get_phy_info(struct eth_device *dev);
130void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd);
131static void adjust_link(struct eth_device *dev);
132static void relocate_cmds(void);
Marian Balakowiczaab8c492005-10-28 22:30:33 +0200133static int tsec_miiphy_write(char *devname, unsigned char addr,
134 unsigned char reg, unsigned short value);
135static int tsec_miiphy_read(char *devname, unsigned char addr,
136 unsigned char reg, unsigned short *value);
wdenk78924a72004-04-18 21:45:42 +0000137
wdenka445ddf2004-06-09 00:34:46 +0000138/* Initialize device structure. Returns success if PHY
139 * initialization succeeded (i.e. if it recognizes the PHY)
140 */
Jon Loeliger77a4f6e2005-07-25 14:05:07 -0500141int tsec_initialize(bd_t *bis, int index, char *devname)
wdenk9c53f402003-10-15 23:53:47 +0000142{
143 struct eth_device* dev;
144 int i;
wdenka445ddf2004-06-09 00:34:46 +0000145 struct tsec_private *priv;
wdenk9c53f402003-10-15 23:53:47 +0000146
147 dev = (struct eth_device*) malloc(sizeof *dev);
148
wdenka445ddf2004-06-09 00:34:46 +0000149 if(NULL == dev)
wdenk9c53f402003-10-15 23:53:47 +0000150 return 0;
151
152 memset(dev, 0, sizeof *dev);
153
wdenka445ddf2004-06-09 00:34:46 +0000154 priv = (struct tsec_private *) malloc(sizeof(*priv));
155
156 if(NULL == priv)
157 return 0;
158
159 privlist[index] = priv;
160 priv->regs = (volatile tsec_t *)(TSEC_BASE_ADDR + index*TSEC_SIZE);
161 priv->phyregs = (volatile tsec_t *)(TSEC_BASE_ADDR +
162 tsec_info[index].phyregidx*TSEC_SIZE);
163
164 priv->phyaddr = tsec_info[index].phyaddr;
Jon Loeliger77a4f6e2005-07-25 14:05:07 -0500165 priv->flags = tsec_info[index].flags;
wdenka445ddf2004-06-09 00:34:46 +0000166
Jon Loeliger77a4f6e2005-07-25 14:05:07 -0500167 sprintf(dev->name, devname);
wdenk9c53f402003-10-15 23:53:47 +0000168 dev->iobase = 0;
wdenka445ddf2004-06-09 00:34:46 +0000169 dev->priv = priv;
wdenk9c53f402003-10-15 23:53:47 +0000170 dev->init = tsec_init;
171 dev->halt = tsec_halt;
172 dev->send = tsec_send;
173 dev->recv = tsec_recv;
174
175 /* Tell u-boot to get the addr from the env */
176 for(i=0;i<6;i++)
177 dev->enetaddr[i] = 0;
178
179 eth_register(dev);
180
wdenk78924a72004-04-18 21:45:42 +0000181
wdenka445ddf2004-06-09 00:34:46 +0000182 /* Reset the MAC */
183 priv->regs->maccfg1 |= MACCFG1_SOFT_RESET;
184 priv->regs->maccfg1 &= ~(MACCFG1_SOFT_RESET);
wdenk78924a72004-04-18 21:45:42 +0000185
Marian Balakowiczaab8c492005-10-28 22:30:33 +0200186#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) \
187 && !defined(BITBANGMII)
188 miiphy_register(dev->name, tsec_miiphy_read, tsec_miiphy_write);
189#endif
190
wdenka445ddf2004-06-09 00:34:46 +0000191 /* Try to initialize PHY here, and return */
192 return init_phy(dev);
wdenk9c53f402003-10-15 23:53:47 +0000193}
194
195
196/* Initializes data structures and registers for the controller,
wdenkbfad55d2005-03-14 23:56:42 +0000197 * and brings the interface up. Returns the link status, meaning
wdenka445ddf2004-06-09 00:34:46 +0000198 * that it returns success if the link is up, failure otherwise.
199 * This allows u-boot to find the first active controller. */
wdenk9c53f402003-10-15 23:53:47 +0000200int tsec_init(struct eth_device* dev, bd_t * bd)
201{
wdenk9c53f402003-10-15 23:53:47 +0000202 uint tempval;
203 char tmpbuf[MAC_ADDR_LEN];
204 int i;
wdenka445ddf2004-06-09 00:34:46 +0000205 struct tsec_private *priv = (struct tsec_private *)dev->priv;
206 volatile tsec_t *regs = priv->regs;
wdenk9c53f402003-10-15 23:53:47 +0000207
208 /* Make sure the controller is stopped */
209 tsec_halt(dev);
210
wdenka445ddf2004-06-09 00:34:46 +0000211 /* Init MACCFG2. Defaults to GMII */
wdenk9c53f402003-10-15 23:53:47 +0000212 regs->maccfg2 = MACCFG2_INIT_SETTINGS;
213
214 /* Init ECNTRL */
215 regs->ecntrl = ECNTRL_INIT_SETTINGS;
216
217 /* Copy the station address into the address registers.
218 * Backwards, because little endian MACS are dumb */
219 for(i=0;i<MAC_ADDR_LEN;i++) {
wdenka445ddf2004-06-09 00:34:46 +0000220 tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i];
wdenk9c53f402003-10-15 23:53:47 +0000221 }
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200222 regs->macstnaddr1 = *((uint *)(tmpbuf));
wdenk9c53f402003-10-15 23:53:47 +0000223
224 tempval = *((uint *)(tmpbuf +4));
225
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200226 regs->macstnaddr2 = tempval;
wdenk9c53f402003-10-15 23:53:47 +0000227
wdenk9c53f402003-10-15 23:53:47 +0000228 /* reset the indices to zero */
229 rxIdx = 0;
230 txIdx = 0;
231
232 /* Clear out (for the most part) the other registers */
233 init_registers(regs);
234
235 /* Ready the device for tx/rx */
wdenka445ddf2004-06-09 00:34:46 +0000236 startup_tsec(dev);
wdenk9c53f402003-10-15 23:53:47 +0000237
wdenka445ddf2004-06-09 00:34:46 +0000238 /* If there's no link, fail */
239 return priv->link;
240
241}
wdenk9c53f402003-10-15 23:53:47 +0000242
wdenka445ddf2004-06-09 00:34:46 +0000243
244/* Write value to the device's PHY through the registers
245 * specified in priv, modifying the register specified in regnum.
246 * It will wait for the write to be done (or for a timeout to
247 * expire) before exiting
248 */
249void write_phy_reg(struct tsec_private *priv, uint regnum, uint value)
250{
251 volatile tsec_t *regbase = priv->phyregs;
252 uint phyid = priv->phyaddr;
253 int timeout=1000000;
254
255 regbase->miimadd = (phyid << 8) | regnum;
256 regbase->miimcon = value;
Eran Liberty9095d4a2005-07-28 10:08:46 -0500257 asm("sync");
wdenka445ddf2004-06-09 00:34:46 +0000258
259 timeout=1000000;
260 while((regbase->miimind & MIIMIND_BUSY) && timeout--);
wdenk9c53f402003-10-15 23:53:47 +0000261}
262
263
wdenka445ddf2004-06-09 00:34:46 +0000264/* Reads register regnum on the device's PHY through the
wdenkbfad55d2005-03-14 23:56:42 +0000265 * registers specified in priv. It lowers and raises the read
wdenka445ddf2004-06-09 00:34:46 +0000266 * command, and waits for the data to become valid (miimind
267 * notvalid bit cleared), and the bus to cease activity (miimind
268 * busy bit cleared), and then returns the value
269 */
270uint read_phy_reg(struct tsec_private *priv, uint regnum)
wdenk9c53f402003-10-15 23:53:47 +0000271{
272 uint value;
wdenka445ddf2004-06-09 00:34:46 +0000273 volatile tsec_t *regbase = priv->phyregs;
274 uint phyid = priv->phyaddr;
wdenk9c53f402003-10-15 23:53:47 +0000275
wdenka445ddf2004-06-09 00:34:46 +0000276 /* Put the address of the phy, and the register
277 * number into MIIMADD */
278 regbase->miimadd = (phyid << 8) | regnum;
wdenk9c53f402003-10-15 23:53:47 +0000279
280 /* Clear the command register, and wait */
281 regbase->miimcom = 0;
Eran Liberty9095d4a2005-07-28 10:08:46 -0500282 asm("sync");
wdenk9c53f402003-10-15 23:53:47 +0000283
284 /* Initiate a read command, and wait */
285 regbase->miimcom = MIIM_READ_COMMAND;
Eran Liberty9095d4a2005-07-28 10:08:46 -0500286 asm("sync");
wdenk9c53f402003-10-15 23:53:47 +0000287
288 /* Wait for the the indication that the read is done */
289 while((regbase->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY)));
290
291 /* Grab the value read from the PHY */
292 value = regbase->miimstat;
293
294 return value;
295}
296
wdenka445ddf2004-06-09 00:34:46 +0000297
298/* Discover which PHY is attached to the device, and configure it
299 * properly. If the PHY is not recognized, then return 0
300 * (failure). Otherwise, return 1
301 */
302static int init_phy(struct eth_device *dev)
wdenk9c53f402003-10-15 23:53:47 +0000303{
wdenka445ddf2004-06-09 00:34:46 +0000304 struct tsec_private *priv = (struct tsec_private *)dev->priv;
305 struct phy_info *curphy;
wdenk9c53f402003-10-15 23:53:47 +0000306
307 /* Assign a Physical address to the TBI */
wdenke085e5b2005-04-05 23:32:21 +0000308
wdenkf41ff3b2005-04-04 23:43:44 +0000309 {
310 volatile tsec_t *regs = (volatile tsec_t *)(TSEC_BASE_ADDR);
311 regs->tbipa = TBIPA_VALUE;
312 regs = (volatile tsec_t *)(TSEC_BASE_ADDR + TSEC_SIZE);
313 regs->tbipa = TBIPA_VALUE;
Eran Liberty9095d4a2005-07-28 10:08:46 -0500314 asm("sync");
wdenkf41ff3b2005-04-04 23:43:44 +0000315 }
316
317 /* Reset MII (due to new addresses) */
318 priv->phyregs->miimcfg = MIIMCFG_RESET;
Eran Liberty9095d4a2005-07-28 10:08:46 -0500319 asm("sync");
wdenkf41ff3b2005-04-04 23:43:44 +0000320 priv->phyregs->miimcfg = MIIMCFG_INIT_VALUE;
Eran Liberty9095d4a2005-07-28 10:08:46 -0500321 asm("sync");
wdenkf41ff3b2005-04-04 23:43:44 +0000322 while(priv->phyregs->miimind & MIIMIND_BUSY);
wdenk9c53f402003-10-15 23:53:47 +0000323
wdenka445ddf2004-06-09 00:34:46 +0000324 if(0 == relocated)
325 relocate_cmds();
wdenk9c53f402003-10-15 23:53:47 +0000326
wdenka445ddf2004-06-09 00:34:46 +0000327 /* Get the cmd structure corresponding to the attached
328 * PHY */
329 curphy = get_phy_info(dev);
wdenk9c53f402003-10-15 23:53:47 +0000330
wdenka445ddf2004-06-09 00:34:46 +0000331 if(NULL == curphy) {
332 printf("%s: No PHY found\n", dev->name);
wdenk9c53f402003-10-15 23:53:47 +0000333
wdenka445ddf2004-06-09 00:34:46 +0000334 return 0;
335 }
wdenk9c53f402003-10-15 23:53:47 +0000336
wdenka445ddf2004-06-09 00:34:46 +0000337 priv->phyinfo = curphy;
wdenk9c53f402003-10-15 23:53:47 +0000338
wdenka445ddf2004-06-09 00:34:46 +0000339 phy_run_commands(priv, priv->phyinfo->config);
wdenk9c53f402003-10-15 23:53:47 +0000340
wdenka445ddf2004-06-09 00:34:46 +0000341 return 1;
342}
wdenk9c53f402003-10-15 23:53:47 +0000343
wdenk9c53f402003-10-15 23:53:47 +0000344
wdenka445ddf2004-06-09 00:34:46 +0000345/* Returns which value to write to the control register. */
346/* For 10/100, the value is slightly different */
347uint mii_cr_init(uint mii_reg, struct tsec_private *priv)
348{
Jon Loeliger77a4f6e2005-07-25 14:05:07 -0500349 if(priv->flags & TSEC_GIGABIT)
wdenka445ddf2004-06-09 00:34:46 +0000350 return MIIM_CONTROL_INIT;
wdenk9c53f402003-10-15 23:53:47 +0000351 else
wdenka445ddf2004-06-09 00:34:46 +0000352 return MIIM_CR_INIT;
353}
wdenk9c53f402003-10-15 23:53:47 +0000354
wdenk9c53f402003-10-15 23:53:47 +0000355
wdenka445ddf2004-06-09 00:34:46 +0000356/* Parse the status register for link, and then do
357 * auto-negotiation */
358uint mii_parse_sr(uint mii_reg, struct tsec_private *priv)
359{
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200360 /*
361 * Wait if PHY is capable of autonegotiation and autonegotiation is not complete
362 */
363 mii_reg = read_phy_reg(priv, MIIM_STATUS);
364 if ((mii_reg & PHY_BMSR_AUTN_ABLE) && !(mii_reg & PHY_BMSR_AUTN_COMP)) {
365 int i = 0;
wdenk9c53f402003-10-15 23:53:47 +0000366
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200367 puts ("Waiting for PHY auto negotiation to complete");
368 while (!((mii_reg & PHY_BMSR_AUTN_COMP) && (mii_reg & MIIM_STATUS_LINK))) {
369 /*
370 * Timeout reached ?
371 */
372 if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
373 puts (" TIMEOUT !\n");
374 priv->link = 0;
375 break;
376 }
wdenk9c53f402003-10-15 23:53:47 +0000377
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200378 if ((i++ % 1000) == 0) {
379 putc ('.');
380 }
381 udelay (1000); /* 1 ms */
wdenka445ddf2004-06-09 00:34:46 +0000382 mii_reg = read_phy_reg(priv, MIIM_STATUS);
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200383 }
384 puts (" done\n");
385 priv->link = 1;
386 udelay (500000); /* another 500 ms (results in faster booting) */
387 } else {
388 priv->link = 1;
wdenk9c53f402003-10-15 23:53:47 +0000389 }
390
wdenka445ddf2004-06-09 00:34:46 +0000391 return 0;
392}
393
wdenk9c53f402003-10-15 23:53:47 +0000394
wdenka445ddf2004-06-09 00:34:46 +0000395/* Parse the 88E1011's status register for speed and duplex
396 * information */
397uint mii_parse_88E1011_psr(uint mii_reg, struct tsec_private *priv)
398{
399 uint speed;
wdenk9c53f402003-10-15 23:53:47 +0000400
Stefan Roesec0dc34f2005-09-21 18:20:22 +0200401 mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);
402
403 if (!((mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE) &&
404 (mii_reg & MIIM_88E1011_PHYSTAT_LINK))) {
405 int i = 0;
406
407 puts ("Waiting for PHY realtime link");
408 while (!((mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE) &&
409 (mii_reg & MIIM_88E1011_PHYSTAT_LINK))) {
410 /*
411 * Timeout reached ?
412 */
413 if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
414 puts (" TIMEOUT !\n");
415 priv->link = 0;
416 break;
417 }
418
419 if ((i++ % 1000) == 0) {
420 putc ('.');
421 }
422 udelay (1000); /* 1 ms */
423 mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);
424 }
425 puts (" done\n");
426 udelay (500000); /* another 500 ms (results in faster booting) */
427 }
428
wdenka445ddf2004-06-09 00:34:46 +0000429 if(mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX)
430 priv->duplexity = 1;
431 else
432 priv->duplexity = 0;
433
434 speed = (mii_reg &MIIM_88E1011_PHYSTAT_SPEED);
435
436 switch(speed) {
437 case MIIM_88E1011_PHYSTAT_GBIT:
438 priv->speed = 1000;
439 break;
440 case MIIM_88E1011_PHYSTAT_100:
441 priv->speed = 100;
442 break;
443 default:
444 priv->speed = 10;
wdenk9c53f402003-10-15 23:53:47 +0000445 }
446
wdenka445ddf2004-06-09 00:34:46 +0000447 return 0;
448}
449
wdenk9c53f402003-10-15 23:53:47 +0000450
wdenka445ddf2004-06-09 00:34:46 +0000451/* Parse the cis8201's status register for speed and duplex
452 * information */
453uint mii_parse_cis8201(uint mii_reg, struct tsec_private *priv)
454{
455 uint speed;
456
457 if(mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX)
458 priv->duplexity = 1;
459 else
460 priv->duplexity = 0;
461
462 speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED;
463 switch(speed) {
464 case MIIM_CIS8201_AUXCONSTAT_GBIT:
465 priv->speed = 1000;
466 break;
467 case MIIM_CIS8201_AUXCONSTAT_100:
468 priv->speed = 100;
469 break;
470 default:
471 priv->speed = 10;
472 break;
wdenk9c53f402003-10-15 23:53:47 +0000473 }
474
wdenka445ddf2004-06-09 00:34:46 +0000475 return 0;
476}
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500477/* Parse the vsc8244's status register for speed and duplex
478 * information */
479uint mii_parse_vsc8244(uint mii_reg, struct tsec_private *priv)
480{
481 uint speed;
482
483 if(mii_reg & MIIM_VSC8244_AUXCONSTAT_DUPLEX)
484 priv->duplexity = 1;
485 else
486 priv->duplexity = 0;
487
488 speed = mii_reg & MIIM_VSC8244_AUXCONSTAT_SPEED;
489 switch(speed) {
490 case MIIM_VSC8244_AUXCONSTAT_GBIT:
491 priv->speed = 1000;
492 break;
493 case MIIM_VSC8244_AUXCONSTAT_100:
494 priv->speed = 100;
495 break;
496 default:
497 priv->speed = 10;
498 break;
499 }
500
501 return 0;
502}
wdenk9c53f402003-10-15 23:53:47 +0000503
wdenka445ddf2004-06-09 00:34:46 +0000504
505/* Parse the DM9161's status register for speed and duplex
506 * information */
507uint mii_parse_dm9161_scsr(uint mii_reg, struct tsec_private *priv)
508{
509 if(mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H))
510 priv->speed = 100;
511 else
512 priv->speed = 10;
513
514 if(mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F))
515 priv->duplexity = 1;
516 else
517 priv->duplexity = 0;
518
519 return 0;
520}
521
522
523/* Hack to write all 4 PHYs with the LED values */
524uint mii_cis8204_fixled(uint mii_reg, struct tsec_private *priv)
525{
526 uint phyid;
527 volatile tsec_t *regbase = priv->phyregs;
528 int timeout=1000000;
529
530 for(phyid=0;phyid<4;phyid++) {
531 regbase->miimadd = (phyid << 8) | mii_reg;
532 regbase->miimcon = MIIM_CIS8204_SLEDCON_INIT;
Eran Liberty9095d4a2005-07-28 10:08:46 -0500533 asm("sync");
wdenka445ddf2004-06-09 00:34:46 +0000534
535 timeout=1000000;
536 while((regbase->miimind & MIIMIND_BUSY) && timeout--);
wdenk9c53f402003-10-15 23:53:47 +0000537 }
wdenk9c53f402003-10-15 23:53:47 +0000538
wdenka445ddf2004-06-09 00:34:46 +0000539 return MIIM_CIS8204_SLEDCON_INIT;
wdenk9c53f402003-10-15 23:53:47 +0000540}
541
Jon Loeliger77a4f6e2005-07-25 14:05:07 -0500542uint mii_cis8204_setmode(uint mii_reg, struct tsec_private *priv)
543{
544 if (priv->flags & TSEC_REDUCED)
545 return MIIM_CIS8204_EPHYCON_INIT | MIIM_CIS8204_EPHYCON_RGMII;
546 else
547 return MIIM_CIS8204_EPHYCON_INIT;
548}
wdenk9c53f402003-10-15 23:53:47 +0000549
wdenka445ddf2004-06-09 00:34:46 +0000550/* Initialized required registers to appropriate values, zeroing
551 * those we don't care about (unless zero is bad, in which case,
552 * choose a more appropriate value) */
553static void init_registers(volatile tsec_t *regs)
wdenk9c53f402003-10-15 23:53:47 +0000554{
555 /* Clear IEVENT */
556 regs->ievent = IEVENT_INIT_CLEAR;
557
558 regs->imask = IMASK_INIT_CLEAR;
559
560 regs->hash.iaddr0 = 0;
561 regs->hash.iaddr1 = 0;
562 regs->hash.iaddr2 = 0;
563 regs->hash.iaddr3 = 0;
564 regs->hash.iaddr4 = 0;
565 regs->hash.iaddr5 = 0;
566 regs->hash.iaddr6 = 0;
567 regs->hash.iaddr7 = 0;
568
569 regs->hash.gaddr0 = 0;
570 regs->hash.gaddr1 = 0;
571 regs->hash.gaddr2 = 0;
572 regs->hash.gaddr3 = 0;
573 regs->hash.gaddr4 = 0;
574 regs->hash.gaddr5 = 0;
575 regs->hash.gaddr6 = 0;
576 regs->hash.gaddr7 = 0;
577
578 regs->rctrl = 0x00000000;
579
580 /* Init RMON mib registers */
581 memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t));
582
583 regs->rmon.cam1 = 0xffffffff;
584 regs->rmon.cam2 = 0xffffffff;
585
586 regs->mrblr = MRBLR_INIT_SETTINGS;
587
588 regs->minflr = MINFLR_INIT_SETTINGS;
589
590 regs->attr = ATTR_INIT_SETTINGS;
591 regs->attreli = ATTRELI_INIT_SETTINGS;
592
wdenka445ddf2004-06-09 00:34:46 +0000593}
594
595
596/* Configure maccfg2 based on negotiated speed and duplex
597 * reported by PHY handling code */
598static void adjust_link(struct eth_device *dev)
599{
600 struct tsec_private *priv = (struct tsec_private *)dev->priv;
601 volatile tsec_t *regs = priv->regs;
602
603 if(priv->link) {
604 if(priv->duplexity != 0)
605 regs->maccfg2 |= MACCFG2_FULL_DUPLEX;
606 else
607 regs->maccfg2 &= ~(MACCFG2_FULL_DUPLEX);
608
609 switch(priv->speed) {
610 case 1000:
611 regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF))
612 | MACCFG2_GMII);
613 break;
614 case 100:
615 case 10:
616 regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF))
617 | MACCFG2_MII);
Jon Loeliger77a4f6e2005-07-25 14:05:07 -0500618
Jon Loeligerebc72242005-08-01 13:20:47 -0500619 /* If We're in reduced mode, we need
620 * to say whether we're 10 or 100 MB.
621 */
622 if ((priv->speed == 100)
623 && (priv->flags & TSEC_REDUCED))
Jon Loeliger77a4f6e2005-07-25 14:05:07 -0500624 regs->ecntrl |= ECNTRL_R100;
625 else
626 regs->ecntrl &= ~(ECNTRL_R100);
wdenka445ddf2004-06-09 00:34:46 +0000627 break;
628 default:
629 printf("%s: Speed was bad\n", dev->name);
630 break;
631 }
632
633 printf("Speed: %d, %s duplex\n", priv->speed,
634 (priv->duplexity) ? "full" : "half");
635
636 } else {
637 printf("%s: No link.\n", dev->name);
638 }
wdenk9c53f402003-10-15 23:53:47 +0000639}
640
wdenka445ddf2004-06-09 00:34:46 +0000641
642/* Set up the buffers and their descriptors, and bring up the
643 * interface */
644static void startup_tsec(struct eth_device *dev)
wdenk9c53f402003-10-15 23:53:47 +0000645{
646 int i;
wdenka445ddf2004-06-09 00:34:46 +0000647 struct tsec_private *priv = (struct tsec_private *)dev->priv;
648 volatile tsec_t *regs = priv->regs;
wdenk9c53f402003-10-15 23:53:47 +0000649
650 /* Point to the buffer descriptors */
651 regs->tbase = (unsigned int)(&rtx.txbd[txIdx]);
652 regs->rbase = (unsigned int)(&rtx.rxbd[rxIdx]);
653
654 /* Initialize the Rx Buffer descriptors */
655 for (i = 0; i < PKTBUFSRX; i++) {
656 rtx.rxbd[i].status = RXBD_EMPTY;
657 rtx.rxbd[i].length = 0;
658 rtx.rxbd[i].bufPtr = (uint)NetRxPackets[i];
659 }
660 rtx.rxbd[PKTBUFSRX -1].status |= RXBD_WRAP;
661
662 /* Initialize the TX Buffer Descriptors */
663 for(i=0; i<TX_BUF_CNT; i++) {
664 rtx.txbd[i].status = 0;
665 rtx.txbd[i].length = 0;
666 rtx.txbd[i].bufPtr = 0;
667 }
668 rtx.txbd[TX_BUF_CNT -1].status |= TXBD_WRAP;
669
wdenka445ddf2004-06-09 00:34:46 +0000670 /* Start up the PHY */
671 phy_run_commands(priv, priv->phyinfo->startup);
672 adjust_link(dev);
673
wdenk9c53f402003-10-15 23:53:47 +0000674 /* Enable Transmit and Receive */
675 regs->maccfg1 |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
676
677 /* Tell the DMA it is clear to go */
678 regs->dmactrl |= DMACTRL_INIT_SETTINGS;
679 regs->tstat = TSTAT_CLEAR_THALT;
680 regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
681}
682
wdenkbfad55d2005-03-14 23:56:42 +0000683/* This returns the status bits of the device. The return value
wdenk9c53f402003-10-15 23:53:47 +0000684 * is never checked, and this is what the 8260 driver did, so we
wdenkbfad55d2005-03-14 23:56:42 +0000685 * do the same. Presumably, this would be zero if there were no
wdenk9c53f402003-10-15 23:53:47 +0000686 * errors */
687static int tsec_send(struct eth_device* dev, volatile void *packet, int length)
688{
689 int i;
690 int result = 0;
wdenka445ddf2004-06-09 00:34:46 +0000691 struct tsec_private *priv = (struct tsec_private *)dev->priv;
692 volatile tsec_t *regs = priv->regs;
wdenk9c53f402003-10-15 23:53:47 +0000693
694 /* Find an empty buffer descriptor */
695 for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
696 if (i >= TOUT_LOOP) {
wdenk3203c8f2004-07-10 21:45:47 +0000697 debug ("%s: tsec: tx buffers full\n", dev->name);
wdenk9c53f402003-10-15 23:53:47 +0000698 return result;
699 }
700 }
701
702 rtx.txbd[txIdx].bufPtr = (uint)packet;
703 rtx.txbd[txIdx].length = length;
704 rtx.txbd[txIdx].status |= (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT);
705
706 /* Tell the DMA to go */
707 regs->tstat = TSTAT_CLEAR_THALT;
708
709 /* Wait for buffer to be transmitted */
710 for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
711 if (i >= TOUT_LOOP) {
wdenk3203c8f2004-07-10 21:45:47 +0000712 debug ("%s: tsec: tx error\n", dev->name);
wdenk9c53f402003-10-15 23:53:47 +0000713 return result;
714 }
715 }
716
717 txIdx = (txIdx + 1) % TX_BUF_CNT;
718 result = rtx.txbd[txIdx].status & TXBD_STATS;
719
720 return result;
721}
722
723static int tsec_recv(struct eth_device* dev)
724{
725 int length;
wdenka445ddf2004-06-09 00:34:46 +0000726 struct tsec_private *priv = (struct tsec_private *)dev->priv;
727 volatile tsec_t *regs = priv->regs;
wdenk9c53f402003-10-15 23:53:47 +0000728
729 while(!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) {
730
731 length = rtx.rxbd[rxIdx].length;
732
733 /* Send the packet up if there were no errors */
734 if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) {
735 NetReceive(NetRxPackets[rxIdx], length - 4);
wdenka445ddf2004-06-09 00:34:46 +0000736 } else {
737 printf("Got error %x\n",
738 (rtx.rxbd[rxIdx].status & RXBD_STATS));
wdenk9c53f402003-10-15 23:53:47 +0000739 }
740
741 rtx.rxbd[rxIdx].length = 0;
742
743 /* Set the wrap bit if this is the last element in the list */
744 rtx.rxbd[rxIdx].status = RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0);
745
746 rxIdx = (rxIdx + 1) % PKTBUFSRX;
747 }
748
749 if(regs->ievent&IEVENT_BSY) {
750 regs->ievent = IEVENT_BSY;
751 regs->rstat = RSTAT_CLEAR_RHALT;
752 }
753
754 return -1;
755
756}
757
758
wdenka445ddf2004-06-09 00:34:46 +0000759/* Stop the interface */
wdenk9c53f402003-10-15 23:53:47 +0000760static void tsec_halt(struct eth_device* dev)
761{
wdenka445ddf2004-06-09 00:34:46 +0000762 struct tsec_private *priv = (struct tsec_private *)dev->priv;
763 volatile tsec_t *regs = priv->regs;
wdenk9c53f402003-10-15 23:53:47 +0000764
765 regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
766 regs->dmactrl |= (DMACTRL_GRS | DMACTRL_GTS);
767
768 while(!(regs->ievent & (IEVENT_GRSC | IEVENT_GTSC)));
769
770 regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN);
771
wdenka445ddf2004-06-09 00:34:46 +0000772 /* Shut down the PHY, as needed */
773 phy_run_commands(priv, priv->phyinfo->shutdown);
774}
775
776
777struct phy_info phy_info_M88E1011S = {
778 0x01410c6,
779 "Marvell 88E1011S",
780 4,
781 (struct phy_cmd[]) { /* config */
782 /* Reset and configure the PHY */
783 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
784 {0x1d, 0x1f, NULL},
785 {0x1e, 0x200c, NULL},
786 {0x1d, 0x5, NULL},
787 {0x1e, 0x0, NULL},
788 {0x1e, 0x100, NULL},
789 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
790 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
791 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
792 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
793 {miim_end,}
794 },
795 (struct phy_cmd[]) { /* startup */
796 /* Status is read once to clear old link state */
797 {MIIM_STATUS, miim_read, NULL},
798 /* Auto-negotiate */
799 {MIIM_STATUS, miim_read, &mii_parse_sr},
800 /* Read the status */
801 {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr},
802 {miim_end,}
803 },
804 (struct phy_cmd[]) { /* shutdown */
805 {miim_end,}
806 },
807};
808
wdenkbfad55d2005-03-14 23:56:42 +0000809struct phy_info phy_info_M88E1111S = {
810 0x01410cc,
811 "Marvell 88E1111S",
812 4,
813 (struct phy_cmd[]) { /* config */
814 /* Reset and configure the PHY */
815 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
816 {0x1d, 0x1f, NULL},
817 {0x1e, 0x200c, NULL},
818 {0x1d, 0x5, NULL},
819 {0x1e, 0x0, NULL},
820 {0x1e, 0x100, NULL},
821 {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
822 {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
823 {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
824 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
825 {miim_end,}
826 },
827 (struct phy_cmd[]) { /* startup */
828 /* Status is read once to clear old link state */
829 {MIIM_STATUS, miim_read, NULL},
830 /* Auto-negotiate */
831 {MIIM_STATUS, miim_read, &mii_parse_sr},
832 /* Read the status */
833 {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr},
834 {miim_end,}
835 },
836 (struct phy_cmd[]) { /* shutdown */
837 {miim_end,}
838 },
839};
840
wdenka445ddf2004-06-09 00:34:46 +0000841struct phy_info phy_info_cis8204 = {
842 0x3f11,
843 "Cicada Cis8204",
844 6,
845 (struct phy_cmd[]) { /* config */
846 /* Override PHY config settings */
847 {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL},
848 /* Configure some basic stuff */
849 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
850 {MIIM_CIS8204_SLED_CON, MIIM_CIS8204_SLEDCON_INIT, &mii_cis8204_fixled},
Jon Loeliger77a4f6e2005-07-25 14:05:07 -0500851 {MIIM_CIS8204_EPHY_CON, MIIM_CIS8204_EPHYCON_INIT, &mii_cis8204_setmode},
wdenka445ddf2004-06-09 00:34:46 +0000852 {miim_end,}
853 },
854 (struct phy_cmd[]) { /* startup */
855 /* Read the Status (2x to make sure link is right) */
856 {MIIM_STATUS, miim_read, NULL},
857 /* Auto-negotiate */
858 {MIIM_STATUS, miim_read, &mii_parse_sr},
859 /* Read the status */
860 {MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201},
861 {miim_end,}
862 },
863 (struct phy_cmd[]) { /* shutdown */
864 {miim_end,}
865 },
866};
867
868/* Cicada 8201 */
869struct phy_info phy_info_cis8201 = {
870 0xfc41,
871 "CIS8201",
872 4,
873 (struct phy_cmd[]) { /* config */
874 /* Override PHY config settings */
875 {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL},
876 /* Set up the interface mode */
877 {MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL},
878 /* Configure some basic stuff */
879 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
880 {miim_end,}
881 },
882 (struct phy_cmd[]) { /* startup */
883 /* Read the Status (2x to make sure link is right) */
884 {MIIM_STATUS, miim_read, NULL},
885 /* Auto-negotiate */
886 {MIIM_STATUS, miim_read, &mii_parse_sr},
887 /* Read the status */
888 {MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201},
889 {miim_end,}
890 },
891 (struct phy_cmd[]) { /* shutdown */
892 {miim_end,}
893 },
894};
Jon Loeliger5c8aa972006-04-26 17:58:56 -0500895struct phy_info phy_info_VSC8244 = {
896 0x3f1b,
897 "Vitesse VSC8244",
898 6,
899 (struct phy_cmd[]) { /* config */
900 /* Override PHY config settings */
901 /* Configure some basic stuff */
902 {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
903 {miim_end,}
904 },
905 (struct phy_cmd[]) { /* startup */
906 /* Read the Status (2x to make sure link is right) */
907 {MIIM_STATUS, miim_read, NULL},
908 /* Auto-negotiate */
909 {MIIM_STATUS, miim_read, &mii_parse_sr},
910 /* Read the status */
911 {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244},
912 {miim_end,}
913 },
914 (struct phy_cmd[]) { /* shutdown */
915 {miim_end,}
916 },
917};
wdenka445ddf2004-06-09 00:34:46 +0000918
919
920struct phy_info phy_info_dm9161 = {
921 0x0181b88,
922 "Davicom DM9161E",
923 4,
924 (struct phy_cmd[]) { /* config */
925 {MIIM_CONTROL, MIIM_DM9161_CR_STOP, NULL},
926 /* Do not bypass the scrambler/descrambler */
927 {MIIM_DM9161_SCR, MIIM_DM9161_SCR_INIT, NULL},
928 /* Clear 10BTCSR to default */
929 {MIIM_DM9161_10BTCSR, MIIM_DM9161_10BTCSR_INIT, NULL},
930 /* Configure some basic stuff */
931 {MIIM_CONTROL, MIIM_CR_INIT, NULL},
932 /* Restart Auto Negotiation */
933 {MIIM_CONTROL, MIIM_DM9161_CR_RSTAN, NULL},
934 {miim_end,}
935 },
936 (struct phy_cmd[]) { /* startup */
937 /* Status is read once to clear old link state */
938 {MIIM_STATUS, miim_read, NULL},
939 /* Auto-negotiate */
940 {MIIM_STATUS, miim_read, &mii_parse_sr},
941 /* Read the status */
942 {MIIM_DM9161_SCSR, miim_read, &mii_parse_dm9161_scsr},
943 {miim_end,}
944 },
945 (struct phy_cmd[]) { /* shutdown */
946 {miim_end,}
947 },
948};
949
wdenkf41ff3b2005-04-04 23:43:44 +0000950uint mii_parse_lxt971_sr2(uint mii_reg, struct tsec_private *priv)
951{
wdenke085e5b2005-04-05 23:32:21 +0000952 unsigned int speed;
953 if (priv->link) {
954 speed = mii_reg & MIIM_LXT971_SR2_SPEED_MASK;
wdenkf41ff3b2005-04-04 23:43:44 +0000955
wdenke085e5b2005-04-05 23:32:21 +0000956 switch (speed) {
957 case MIIM_LXT971_SR2_10HDX:
958 priv->speed = 10;
959 priv->duplexity = 0;
960 break;
961 case MIIM_LXT971_SR2_10FDX:
962 priv->speed = 10;
963 priv->duplexity = 1;
964 break;
965 case MIIM_LXT971_SR2_100HDX:
966 priv->speed = 100;
967 priv->duplexity = 0;
968 default:
969 priv->speed = 100;
970 priv->duplexity = 1;
971 break;
972 }
973 } else {
974 priv->speed = 0;
975 priv->duplexity = 0;
976 }
wdenkf41ff3b2005-04-04 23:43:44 +0000977
wdenke085e5b2005-04-05 23:32:21 +0000978 return 0;
wdenkf41ff3b2005-04-04 23:43:44 +0000979}
980
wdenkbfad55d2005-03-14 23:56:42 +0000981static struct phy_info phy_info_lxt971 = {
982 0x0001378e,
983 "LXT971",
984 4,
985 (struct phy_cmd []) { /* config */
wdenkf41ff3b2005-04-04 23:43:44 +0000986 { MIIM_CR, MIIM_CR_INIT, mii_cr_init }, /* autonegotiate */
wdenkbfad55d2005-03-14 23:56:42 +0000987 { miim_end, }
988 },
989 (struct phy_cmd []) { /* startup - enable interrupts */
990 /* { 0x12, 0x00f2, NULL }, */
wdenkbfad55d2005-03-14 23:56:42 +0000991 { MIIM_STATUS, miim_read, NULL },
wdenkf41ff3b2005-04-04 23:43:44 +0000992 { MIIM_STATUS, miim_read, &mii_parse_sr },
993 { MIIM_LXT971_SR2, miim_read, &mii_parse_lxt971_sr2 },
wdenkbfad55d2005-03-14 23:56:42 +0000994 { miim_end, }
995 },
996 (struct phy_cmd []) { /* shutdown - disable interrupts */
997 { miim_end, }
998 },
999};
1000
Wolfgang Denkf0c4e462006-03-12 22:50:55 +01001001/* Parse the DP83865's link and auto-neg status register for speed and duplex
1002 * information */
1003uint mii_parse_dp83865_lanr(uint mii_reg, struct tsec_private *priv)
1004{
1005 switch (mii_reg & MIIM_DP83865_SPD_MASK) {
1006
1007 case MIIM_DP83865_SPD_1000:
1008 priv->speed = 1000;
1009 break;
1010
1011 case MIIM_DP83865_SPD_100:
1012 priv->speed = 100;
1013 break;
1014
1015 default:
1016 priv->speed = 10;
1017 break;
1018
1019 }
1020
1021 if (mii_reg & MIIM_DP83865_DPX_FULL)
1022 priv->duplexity = 1;
1023 else
1024 priv->duplexity = 0;
1025
1026 return 0;
1027}
1028
1029struct phy_info phy_info_dp83865 = {
1030 0x20005c7,
1031 "NatSemi DP83865",
1032 4,
1033 (struct phy_cmd[]) { /* config */
1034 {MIIM_CONTROL, MIIM_DP83865_CR_INIT, NULL},
1035 {miim_end,}
1036 },
1037 (struct phy_cmd[]) { /* startup */
1038 /* Status is read once to clear old link state */
1039 {MIIM_STATUS, miim_read, NULL},
1040 /* Auto-negotiate */
1041 {MIIM_STATUS, miim_read, &mii_parse_sr},
1042 /* Read the link and auto-neg status */
1043 {MIIM_DP83865_LANR, miim_read, &mii_parse_dp83865_lanr},
1044 {miim_end,}
1045 },
1046 (struct phy_cmd[]) { /* shutdown */
1047 {miim_end,}
1048 },
1049};
1050
wdenka445ddf2004-06-09 00:34:46 +00001051struct phy_info *phy_info[] = {
1052#if 0
1053 &phy_info_cis8201,
1054#endif
1055 &phy_info_cis8204,
1056 &phy_info_M88E1011S,
wdenkbfad55d2005-03-14 23:56:42 +00001057 &phy_info_M88E1111S,
wdenka445ddf2004-06-09 00:34:46 +00001058 &phy_info_dm9161,
wdenkbfad55d2005-03-14 23:56:42 +00001059 &phy_info_lxt971,
Jon Loeliger5c8aa972006-04-26 17:58:56 -05001060 &phy_info_VSC8244,
Wolfgang Denkf0c4e462006-03-12 22:50:55 +01001061 &phy_info_dp83865,
wdenka445ddf2004-06-09 00:34:46 +00001062 NULL
1063};
1064
1065
1066/* Grab the identifier of the device's PHY, and search through
wdenkbfad55d2005-03-14 23:56:42 +00001067 * all of the known PHYs to see if one matches. If so, return
wdenka445ddf2004-06-09 00:34:46 +00001068 * it, if not, return NULL */
1069struct phy_info * get_phy_info(struct eth_device *dev)
1070{
1071 struct tsec_private *priv = (struct tsec_private *)dev->priv;
1072 uint phy_reg, phy_ID;
1073 int i;
1074 struct phy_info *theInfo = NULL;
1075
1076 /* Grab the bits from PHYIR1, and put them in the upper half */
1077 phy_reg = read_phy_reg(priv, MIIM_PHYIR1);
1078 phy_ID = (phy_reg & 0xffff) << 16;
1079
1080 /* Grab the bits from PHYIR2, and put them in the lower half */
1081 phy_reg = read_phy_reg(priv, MIIM_PHYIR2);
1082 phy_ID |= (phy_reg & 0xffff);
1083
1084 /* loop through all the known PHY types, and find one that */
1085 /* matches the ID we read from the PHY. */
1086 for(i=0; phy_info[i]; i++) {
1087 if(phy_info[i]->id == (phy_ID >> phy_info[i]->shift))
1088 theInfo = phy_info[i];
1089 }
1090
1091 if(theInfo == NULL)
1092 {
1093 printf("%s: PHY id %x is not supported!\n", dev->name, phy_ID);
1094 return NULL;
1095 } else {
Stefan Roesec0dc34f2005-09-21 18:20:22 +02001096 debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID);
wdenka445ddf2004-06-09 00:34:46 +00001097 }
1098
1099 return theInfo;
1100}
1101
1102
1103/* Execute the given series of commands on the given device's
1104 * PHY, running functions as necessary*/
1105void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd)
1106{
1107 int i;
1108 uint result;
1109 volatile tsec_t *phyregs = priv->phyregs;
1110
1111 phyregs->miimcfg = MIIMCFG_RESET;
1112
1113 phyregs->miimcfg = MIIMCFG_INIT_VALUE;
1114
1115 while(phyregs->miimind & MIIMIND_BUSY);
1116
1117 for(i=0;cmd->mii_reg != miim_end;i++) {
1118 if(cmd->mii_data == miim_read) {
1119 result = read_phy_reg(priv, cmd->mii_reg);
1120
1121 if(cmd->funct != NULL)
1122 (*(cmd->funct))(result, priv);
1123
1124 } else {
1125 if(cmd->funct != NULL)
1126 result = (*(cmd->funct))(cmd->mii_reg, priv);
1127 else
1128 result = cmd->mii_data;
1129
1130 write_phy_reg(priv, cmd->mii_reg, result);
1131
1132 }
1133 cmd++;
1134 }
1135}
1136
1137
1138/* Relocate the function pointers in the phy cmd lists */
1139static void relocate_cmds(void)
1140{
1141 struct phy_cmd **cmdlistptr;
1142 struct phy_cmd *cmd;
1143 int i,j,k;
wdenka445ddf2004-06-09 00:34:46 +00001144
1145 for(i=0; phy_info[i]; i++) {
1146 /* First thing's first: relocate the pointers to the
1147 * PHY command structures (the structs were done) */
1148 phy_info[i] = (struct phy_info *) ((uint)phy_info[i]
1149 + gd->reloc_off);
1150 phy_info[i]->name += gd->reloc_off;
1151 phy_info[i]->config =
1152 (struct phy_cmd *)((uint)phy_info[i]->config
1153 + gd->reloc_off);
1154 phy_info[i]->startup =
1155 (struct phy_cmd *)((uint)phy_info[i]->startup
1156 + gd->reloc_off);
1157 phy_info[i]->shutdown =
1158 (struct phy_cmd *)((uint)phy_info[i]->shutdown
1159 + gd->reloc_off);
1160
1161 cmdlistptr = &phy_info[i]->config;
1162 j=0;
1163 for(;cmdlistptr <= &phy_info[i]->shutdown;cmdlistptr++) {
1164 k=0;
1165 for(cmd=*cmdlistptr;cmd->mii_reg != miim_end;cmd++) {
1166 /* Only relocate non-NULL pointers */
1167 if(cmd->funct)
1168 cmd->funct += gd->reloc_off;
1169
1170 k++;
1171 }
1172 j++;
1173 }
1174 }
1175
1176 relocated = 1;
wdenk78924a72004-04-18 21:45:42 +00001177}
1178
wdenka445ddf2004-06-09 00:34:46 +00001179
Marian Balakowiczaab8c492005-10-28 22:30:33 +02001180#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) \
1181 && !defined(BITBANGMII)
wdenka445ddf2004-06-09 00:34:46 +00001182
1183struct tsec_private * get_priv_for_phy(unsigned char phyaddr)
1184{
1185 int i;
1186
1187 for(i=0;i<MAXCONTROLLERS;i++) {
1188 if(privlist[i]->phyaddr == phyaddr)
1189 return privlist[i];
1190 }
1191
1192 return NULL;
1193}
1194
wdenk78924a72004-04-18 21:45:42 +00001195/*
1196 * Read a MII PHY register.
1197 *
1198 * Returns:
wdenka445ddf2004-06-09 00:34:46 +00001199 * 0 on success
wdenk78924a72004-04-18 21:45:42 +00001200 */
Marian Balakowiczaab8c492005-10-28 22:30:33 +02001201static int tsec_miiphy_read(char *devname, unsigned char addr,
1202 unsigned char reg, unsigned short *value)
wdenk78924a72004-04-18 21:45:42 +00001203{
wdenka445ddf2004-06-09 00:34:46 +00001204 unsigned short ret;
1205 struct tsec_private *priv = get_priv_for_phy(addr);
wdenk78924a72004-04-18 21:45:42 +00001206
wdenka445ddf2004-06-09 00:34:46 +00001207 if(NULL == priv) {
1208 printf("Can't read PHY at address %d\n", addr);
1209 return -1;
1210 }
1211
1212 ret = (unsigned short)read_phy_reg(priv, reg);
1213 *value = ret;
wdenk78924a72004-04-18 21:45:42 +00001214
1215 return 0;
1216}
1217
1218/*
1219 * Write a MII PHY register.
1220 *
1221 * Returns:
wdenka445ddf2004-06-09 00:34:46 +00001222 * 0 on success
wdenk78924a72004-04-18 21:45:42 +00001223 */
Marian Balakowiczaab8c492005-10-28 22:30:33 +02001224static int tsec_miiphy_write(char *devname, unsigned char addr,
1225 unsigned char reg, unsigned short value)
wdenk78924a72004-04-18 21:45:42 +00001226{
wdenka445ddf2004-06-09 00:34:46 +00001227 struct tsec_private *priv = get_priv_for_phy(addr);
1228
1229 if(NULL == priv) {
1230 printf("Can't write PHY at address %d\n", addr);
1231 return -1;
1232 }
wdenk78924a72004-04-18 21:45:42 +00001233
wdenka445ddf2004-06-09 00:34:46 +00001234 write_phy_reg(priv, reg, value);
wdenk78924a72004-04-18 21:45:42 +00001235
1236 return 0;
wdenk9c53f402003-10-15 23:53:47 +00001237}
wdenka445ddf2004-06-09 00:34:46 +00001238
Marian Balakowiczaab8c492005-10-28 22:30:33 +02001239#endif /* defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
1240 && !defined(BITBANGMII) */
wdenka445ddf2004-06-09 00:34:46 +00001241
wdenk9c53f402003-10-15 23:53:47 +00001242#endif /* CONFIG_TSEC_ENET */