blob: 186922e0c5152295903c49a6e16cf603a5c34f74 [file] [log] [blame]
Dave Liue732e9c2006-11-03 12:11:15 -06001/*
2 * Copyright (C) 2005 Freescale Semiconductor, Inc.
3 *
4 * Author: Shlomi Gridish
5 *
6 * Description: UCC GETH Driver -- PHY handling
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +01007 * Driver for UEC on QE
8 * Based on 8260_io/fcc_enet.c
Dave Liue732e9c2006-11-03 12:11:15 -06009 *
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +010010 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
Dave Liue732e9c2006-11-03 12:11:15 -060012 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
17#include "common.h"
18#include "net.h"
19#include "malloc.h"
20#include "asm/errno.h"
21#include "asm/immap_qe.h"
22#include "asm/io.h"
23#include "qe.h"
24#include "uccf.h"
25#include "uec.h"
26#include "uec_phy.h"
27#include "miiphy.h"
28
Dave Liue732e9c2006-11-03 12:11:15 -060029#define ugphy_printk(format, arg...) \
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +010030 printf(format "\n", ## arg)
Dave Liue732e9c2006-11-03 12:11:15 -060031
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +010032#define ugphy_dbg(format, arg...) \
33 ugphy_printk(format , ## arg)
34#define ugphy_err(format, arg...) \
35 ugphy_printk(format , ## arg)
36#define ugphy_info(format, arg...) \
37 ugphy_printk(format , ## arg)
38#define ugphy_warn(format, arg...) \
39 ugphy_printk(format , ## arg)
Dave Liue732e9c2006-11-03 12:11:15 -060040
41#ifdef UEC_VERBOSE_DEBUG
42#define ugphy_vdbg ugphy_dbg
43#else
44#define ugphy_vdbg(ugeth, fmt, args...) do { } while (0)
45#endif /* UEC_VERBOSE_DEBUG */
46
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +010047static void config_genmii_advert (struct uec_mii_info *mii_info);
48static void genmii_setup_forced (struct uec_mii_info *mii_info);
49static void genmii_restart_aneg (struct uec_mii_info *mii_info);
50static int gbit_config_aneg (struct uec_mii_info *mii_info);
51static int genmii_config_aneg (struct uec_mii_info *mii_info);
52static int genmii_update_link (struct uec_mii_info *mii_info);
53static int genmii_read_status (struct uec_mii_info *mii_info);
54u16 phy_read (struct uec_mii_info *mii_info, u16 regnum);
55void phy_write (struct uec_mii_info *mii_info, u16 regnum, u16 val);
Dave Liue732e9c2006-11-03 12:11:15 -060056
57/* Write value to the PHY for this device to the register at regnum, */
58/* waiting until the write is done before it returns. All PHY */
59/* configuration has to be done through the TSEC1 MIIM regs */
Andy Flemingee0e9172007-08-14 00:14:25 -050060void uec_write_phy_reg (struct eth_device *dev, int mii_id, int regnum, int value)
Dave Liue732e9c2006-11-03 12:11:15 -060061{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +010062 uec_private_t *ugeth = (uec_private_t *) dev->priv;
Andy Flemingee0e9172007-08-14 00:14:25 -050063 uec_mii_t *ug_regs;
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +010064 enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
65 u32 tmp_reg;
Dave Liue732e9c2006-11-03 12:11:15 -060066
Andy Flemingee0e9172007-08-14 00:14:25 -050067 ug_regs = ugeth->uec_mii_regs;
Dave Liue732e9c2006-11-03 12:11:15 -060068
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +010069 /* Stop the MII management read cycle */
70 out_be32 (&ug_regs->miimcom, 0);
71 /* Setting up the MII Mangement Address Register */
72 tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
73 out_be32 (&ug_regs->miimadd, tmp_reg);
Dave Liue732e9c2006-11-03 12:11:15 -060074
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +010075 /* Setting up the MII Mangement Control Register with the value */
76 out_be32 (&ug_regs->miimcon, (u32) value);
Kim Phillipsd986cba2008-01-15 14:11:00 -060077 sync();
Dave Liue732e9c2006-11-03 12:11:15 -060078
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +010079 /* Wait till MII management write is complete */
80 while ((in_be32 (&ug_regs->miimind)) & MIIMIND_BUSY);
Dave Liue732e9c2006-11-03 12:11:15 -060081}
82
83/* Reads from register regnum in the PHY for device dev, */
84/* returning the value. Clears miimcom first. All PHY */
85/* configuration has to be done through the TSEC1 MIIM regs */
Andy Flemingee0e9172007-08-14 00:14:25 -050086int uec_read_phy_reg (struct eth_device *dev, int mii_id, int regnum)
Dave Liue732e9c2006-11-03 12:11:15 -060087{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +010088 uec_private_t *ugeth = (uec_private_t *) dev->priv;
Andy Flemingee0e9172007-08-14 00:14:25 -050089 uec_mii_t *ug_regs;
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +010090 enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
91 u32 tmp_reg;
92 u16 value;
Dave Liue732e9c2006-11-03 12:11:15 -060093
Andy Flemingee0e9172007-08-14 00:14:25 -050094 ug_regs = ugeth->uec_mii_regs;
Dave Liue732e9c2006-11-03 12:11:15 -060095
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +010096 /* Setting up the MII Mangement Address Register */
97 tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
98 out_be32 (&ug_regs->miimadd, tmp_reg);
Dave Liue732e9c2006-11-03 12:11:15 -060099
Kim Phillipsd986cba2008-01-15 14:11:00 -0600100 /* clear MII management command cycle */
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100101 out_be32 (&ug_regs->miimcom, 0);
Kim Phillipsd986cba2008-01-15 14:11:00 -0600102 sync();
103
104 /* Perform an MII management read cycle */
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100105 out_be32 (&ug_regs->miimcom, MIIMCOM_READ_CYCLE);
Dave Liue732e9c2006-11-03 12:11:15 -0600106
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100107 /* Wait till MII management write is complete */
108 while ((in_be32 (&ug_regs->miimind)) &
109 (MIIMIND_NOT_VALID | MIIMIND_BUSY));
Dave Liue732e9c2006-11-03 12:11:15 -0600110
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100111 /* Read MII management status */
112 value = (u16) in_be32 (&ug_regs->miimstat);
113 if (value == 0xffff)
Joakim Tjernlund3d7f2552008-01-16 09:40:41 +0100114 ugphy_vdbg
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100115 ("read wrong value : mii_id %d,mii_reg %d, base %08x",
116 mii_id, mii_reg, (u32) & (ug_regs->miimcfg));
Dave Liue732e9c2006-11-03 12:11:15 -0600117
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100118 return (value);
Dave Liue732e9c2006-11-03 12:11:15 -0600119}
120
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100121void mii_clear_phy_interrupt (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600122{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100123 if (mii_info->phyinfo->ack_interrupt)
124 mii_info->phyinfo->ack_interrupt (mii_info);
Dave Liue732e9c2006-11-03 12:11:15 -0600125}
126
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100127void mii_configure_phy_interrupt (struct uec_mii_info *mii_info,
128 u32 interrupts)
Dave Liue732e9c2006-11-03 12:11:15 -0600129{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100130 mii_info->interrupts = interrupts;
131 if (mii_info->phyinfo->config_intr)
132 mii_info->phyinfo->config_intr (mii_info);
Dave Liue732e9c2006-11-03 12:11:15 -0600133}
134
135/* Writes MII_ADVERTISE with the appropriate values, after
136 * sanitizing advertise to make sure only supported features
137 * are advertised
138 */
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100139static void config_genmii_advert (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600140{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100141 u32 advertise;
142 u16 adv;
Dave Liue732e9c2006-11-03 12:11:15 -0600143
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100144 /* Only allow advertising what this PHY supports */
145 mii_info->advertising &= mii_info->phyinfo->features;
146 advertise = mii_info->advertising;
Dave Liue732e9c2006-11-03 12:11:15 -0600147
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100148 /* Setup standard advertisement */
149 adv = phy_read (mii_info, PHY_ANAR);
150 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
151 if (advertise & ADVERTISED_10baseT_Half)
152 adv |= ADVERTISE_10HALF;
153 if (advertise & ADVERTISED_10baseT_Full)
154 adv |= ADVERTISE_10FULL;
155 if (advertise & ADVERTISED_100baseT_Half)
156 adv |= ADVERTISE_100HALF;
157 if (advertise & ADVERTISED_100baseT_Full)
158 adv |= ADVERTISE_100FULL;
159 phy_write (mii_info, PHY_ANAR, adv);
Dave Liue732e9c2006-11-03 12:11:15 -0600160}
161
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100162static void genmii_setup_forced (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600163{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100164 u16 ctrl;
165 u32 features = mii_info->phyinfo->features;
Dave Liue732e9c2006-11-03 12:11:15 -0600166
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100167 ctrl = phy_read (mii_info, PHY_BMCR);
Dave Liue732e9c2006-11-03 12:11:15 -0600168
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100169 ctrl &= ~(PHY_BMCR_DPLX | PHY_BMCR_100_MBPS |
170 PHY_BMCR_1000_MBPS | PHY_BMCR_AUTON);
171 ctrl |= PHY_BMCR_RESET;
Dave Liue732e9c2006-11-03 12:11:15 -0600172
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100173 switch (mii_info->speed) {
174 case SPEED_1000:
175 if (features & (SUPPORTED_1000baseT_Half
176 | SUPPORTED_1000baseT_Full)) {
177 ctrl |= PHY_BMCR_1000_MBPS;
178 break;
179 }
180 mii_info->speed = SPEED_100;
181 case SPEED_100:
182 if (features & (SUPPORTED_100baseT_Half
183 | SUPPORTED_100baseT_Full)) {
184 ctrl |= PHY_BMCR_100_MBPS;
185 break;
186 }
187 mii_info->speed = SPEED_10;
188 case SPEED_10:
189 if (features & (SUPPORTED_10baseT_Half
190 | SUPPORTED_10baseT_Full))
191 break;
192 default: /* Unsupported speed! */
193 ugphy_err ("%s: Bad speed!", mii_info->dev->name);
194 break;
195 }
Dave Liue732e9c2006-11-03 12:11:15 -0600196
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100197 phy_write (mii_info, PHY_BMCR, ctrl);
Dave Liue732e9c2006-11-03 12:11:15 -0600198}
199
200/* Enable and Restart Autonegotiation */
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100201static void genmii_restart_aneg (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600202{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100203 u16 ctl;
Dave Liue732e9c2006-11-03 12:11:15 -0600204
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100205 ctl = phy_read (mii_info, PHY_BMCR);
206 ctl |= (PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
207 phy_write (mii_info, PHY_BMCR, ctl);
Dave Liue732e9c2006-11-03 12:11:15 -0600208}
209
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100210static int gbit_config_aneg (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600211{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100212 u16 adv;
213 u32 advertise;
Dave Liue732e9c2006-11-03 12:11:15 -0600214
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100215 if (mii_info->autoneg) {
216 /* Configure the ADVERTISE register */
217 config_genmii_advert (mii_info);
218 advertise = mii_info->advertising;
Dave Liue732e9c2006-11-03 12:11:15 -0600219
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100220 adv = phy_read (mii_info, MII_1000BASETCONTROL);
221 adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
222 MII_1000BASETCONTROL_HALFDUPLEXCAP);
223 if (advertise & SUPPORTED_1000baseT_Half)
224 adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
225 if (advertise & SUPPORTED_1000baseT_Full)
226 adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
227 phy_write (mii_info, MII_1000BASETCONTROL, adv);
Dave Liue732e9c2006-11-03 12:11:15 -0600228
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100229 /* Start/Restart aneg */
230 genmii_restart_aneg (mii_info);
231 } else
232 genmii_setup_forced (mii_info);
Dave Liue732e9c2006-11-03 12:11:15 -0600233
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100234 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600235}
236
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100237static int marvell_config_aneg (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600238{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100239 /* The Marvell PHY has an errata which requires
240 * that certain registers get written in order
241 * to restart autonegotiation */
242 phy_write (mii_info, PHY_BMCR, PHY_BMCR_RESET);
Dave Liue732e9c2006-11-03 12:11:15 -0600243
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100244 phy_write (mii_info, 0x1d, 0x1f);
245 phy_write (mii_info, 0x1e, 0x200c);
246 phy_write (mii_info, 0x1d, 0x5);
247 phy_write (mii_info, 0x1e, 0);
248 phy_write (mii_info, 0x1e, 0x100);
Dave Liue732e9c2006-11-03 12:11:15 -0600249
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100250 gbit_config_aneg (mii_info);
Dave Liue732e9c2006-11-03 12:11:15 -0600251
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100252 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600253}
254
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100255static int genmii_config_aneg (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600256{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100257 if (mii_info->autoneg) {
258 config_genmii_advert (mii_info);
259 genmii_restart_aneg (mii_info);
260 } else
261 genmii_setup_forced (mii_info);
Dave Liue732e9c2006-11-03 12:11:15 -0600262
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100263 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600264}
265
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100266static int genmii_update_link (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600267{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100268 u16 status;
Dave Liue732e9c2006-11-03 12:11:15 -0600269
Kim Phillipsd986cba2008-01-15 14:11:00 -0600270 /* Status is read once to clear old link state */
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100271 phy_read (mii_info, PHY_BMSR);
Dave Liue732e9c2006-11-03 12:11:15 -0600272
Kim Phillipsd986cba2008-01-15 14:11:00 -0600273 /*
274 * Wait if the link is up, and autonegotiation is in progress
275 * (ie - we're capable and it's not done)
276 */
277 status = phy_read(mii_info, PHY_BMSR);
278 if ((status & PHY_BMSR_LS) && (status & PHY_BMSR_AUTN_ABLE)
279 && !(status & PHY_BMSR_AUTN_COMP)) {
280 int i = 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600281
Kim Phillipsd986cba2008-01-15 14:11:00 -0600282 while (!(status & PHY_BMSR_AUTN_COMP)) {
283 /*
284 * Timeout reached ?
285 */
286 if (i > UGETH_AN_TIMEOUT) {
287 mii_info->link = 0;
288 return 0;
289 }
290
Kim Phillipsb5da4272008-02-27 16:08:22 -0600291 i++;
Kim Phillipsd986cba2008-01-15 14:11:00 -0600292 udelay(1000); /* 1 ms */
293 status = phy_read(mii_info, PHY_BMSR);
294 }
295 mii_info->link = 1;
296 udelay(500000); /* another 500 ms (results in faster booting) */
297 } else {
298 if (status & PHY_BMSR_LS)
299 mii_info->link = 1;
300 else
301 mii_info->link = 0;
302 }
Dave Liue732e9c2006-11-03 12:11:15 -0600303
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100304 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600305}
306
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100307static int genmii_read_status (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600308{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100309 u16 status;
310 int err;
Dave Liue732e9c2006-11-03 12:11:15 -0600311
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100312 /* Update the link, but return if there
313 * was an error */
314 err = genmii_update_link (mii_info);
315 if (err)
316 return err;
Dave Liue732e9c2006-11-03 12:11:15 -0600317
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100318 if (mii_info->autoneg) {
Anton Vorontsov951800b2008-03-24 20:46:24 +0300319 status = phy_read(mii_info, MII_1000BASETSTATUS);
320
321 if (status & (LPA_1000FULL | LPA_1000HALF)) {
322 mii_info->speed = SPEED_1000;
323 if (status & LPA_1000FULL)
324 mii_info->duplex = DUPLEX_FULL;
325 else
326 mii_info->duplex = DUPLEX_HALF;
327 } else {
328 status = phy_read(mii_info, PHY_ANLPAR);
Dave Liue732e9c2006-11-03 12:11:15 -0600329
Anton Vorontsov951800b2008-03-24 20:46:24 +0300330 if (status & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD))
331 mii_info->duplex = DUPLEX_FULL;
332 else
333 mii_info->duplex = DUPLEX_HALF;
334 if (status & (PHY_ANLPAR_TXFD | PHY_ANLPAR_TX))
335 mii_info->speed = SPEED_100;
336 else
337 mii_info->speed = SPEED_10;
338 }
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100339 mii_info->pause = 0;
340 }
341 /* On non-aneg, we assume what we put in BMCR is the speed,
342 * though magic-aneg shouldn't prevent this case from occurring
343 */
Dave Liue732e9c2006-11-03 12:11:15 -0600344
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100345 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600346}
347
Anton Vorontsov98003732008-03-24 20:46:34 +0300348static int bcm_init(struct uec_mii_info *mii_info)
349{
350 struct eth_device *edev = mii_info->dev;
351 uec_private_t *uec = edev->priv;
352
353 gbit_config_aneg(mii_info);
354
355 if (uec->uec_info->enet_interface == ENET_1000_RGMII_RXID) {
356 u16 val;
357 int cnt = 50;
358
359 /* Wait for aneg to complete. */
360 do
361 val = phy_read(mii_info, PHY_BMSR);
362 while (--cnt && !(val & PHY_BMSR_AUTN_COMP));
363
364 /* Set RDX clk delay. */
365 phy_write(mii_info, 0x18, 0x7 | (7 << 12));
366
367 val = phy_read(mii_info, 0x18);
368 /* Set RDX-RXC skew. */
369 val |= (1 << 8);
370 val |= (7 | (7 << 12));
371 /* Write bits 14:0. */
372 val |= (1 << 15);
373 phy_write(mii_info, 0x18, val);
374 }
375
376 return 0;
377}
378
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100379static int marvell_read_status (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600380{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100381 u16 status;
382 int err;
383
384 /* Update the link, but return if there
385 * was an error */
386 err = genmii_update_link (mii_info);
387 if (err)
388 return err;
Dave Liue732e9c2006-11-03 12:11:15 -0600389
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100390 /* If the link is up, read the speed and duplex */
391 /* If we aren't autonegotiating, assume speeds
392 * are as set */
393 if (mii_info->autoneg && mii_info->link) {
394 int speed;
Dave Liue732e9c2006-11-03 12:11:15 -0600395
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100396 status = phy_read (mii_info, MII_M1011_PHY_SPEC_STATUS);
Dave Liue732e9c2006-11-03 12:11:15 -0600397
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100398 /* Get the duplexity */
399 if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
400 mii_info->duplex = DUPLEX_FULL;
401 else
402 mii_info->duplex = DUPLEX_HALF;
Dave Liue732e9c2006-11-03 12:11:15 -0600403
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100404 /* Get the speed */
405 speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK;
406 switch (speed) {
407 case MII_M1011_PHY_SPEC_STATUS_1000:
408 mii_info->speed = SPEED_1000;
409 break;
410 case MII_M1011_PHY_SPEC_STATUS_100:
411 mii_info->speed = SPEED_100;
412 break;
413 default:
414 mii_info->speed = SPEED_10;
415 break;
416 }
417 mii_info->pause = 0;
418 }
Dave Liue732e9c2006-11-03 12:11:15 -0600419
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100420 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600421}
422
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100423static int marvell_ack_interrupt (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600424{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100425 /* Clear the interrupts by reading the reg */
426 phy_read (mii_info, MII_M1011_IEVENT);
Dave Liue732e9c2006-11-03 12:11:15 -0600427
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100428 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600429}
430
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100431static int marvell_config_intr (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600432{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100433 if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
434 phy_write (mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
435 else
436 phy_write (mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
Dave Liue732e9c2006-11-03 12:11:15 -0600437
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100438 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600439}
440
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100441static int dm9161_init (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600442{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100443 /* Reset the PHY */
444 phy_write (mii_info, PHY_BMCR, phy_read (mii_info, PHY_BMCR) |
445 PHY_BMCR_RESET);
446 /* PHY and MAC connect */
447 phy_write (mii_info, PHY_BMCR, phy_read (mii_info, PHY_BMCR) &
448 ~PHY_BMCR_ISO);
Kim Phillipsd986cba2008-01-15 14:11:00 -0600449
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100450 phy_write (mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT);
Kim Phillipsd986cba2008-01-15 14:11:00 -0600451
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100452 config_genmii_advert (mii_info);
453 /* Start/restart aneg */
454 genmii_config_aneg (mii_info);
Dave Liue732e9c2006-11-03 12:11:15 -0600455
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100456 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600457}
458
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100459static int dm9161_config_aneg (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600460{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100461 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600462}
463
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100464static int dm9161_read_status (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600465{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100466 u16 status;
467 int err;
Dave Liue732e9c2006-11-03 12:11:15 -0600468
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100469 /* Update the link, but return if there was an error */
470 err = genmii_update_link (mii_info);
471 if (err)
472 return err;
473 /* If the link is up, read the speed and duplex
474 If we aren't autonegotiating assume speeds are as set */
475 if (mii_info->autoneg && mii_info->link) {
476 status = phy_read (mii_info, MII_DM9161_SCSR);
477 if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H))
478 mii_info->speed = SPEED_100;
479 else
480 mii_info->speed = SPEED_10;
Dave Liue732e9c2006-11-03 12:11:15 -0600481
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100482 if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F))
483 mii_info->duplex = DUPLEX_FULL;
484 else
485 mii_info->duplex = DUPLEX_HALF;
486 }
Dave Liue732e9c2006-11-03 12:11:15 -0600487
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100488 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600489}
490
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100491static int dm9161_ack_interrupt (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600492{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100493 /* Clear the interrupt by reading the reg */
494 phy_read (mii_info, MII_DM9161_INTR);
Dave Liue732e9c2006-11-03 12:11:15 -0600495
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100496 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600497}
498
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100499static int dm9161_config_intr (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600500{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100501 if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
502 phy_write (mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT);
503 else
504 phy_write (mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP);
Dave Liue732e9c2006-11-03 12:11:15 -0600505
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100506 return 0;
Dave Liue732e9c2006-11-03 12:11:15 -0600507}
508
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100509static void dm9161_close (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600510{
511}
512
513static struct phy_info phy_info_dm9161 = {
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100514 .phy_id = 0x0181b880,
515 .phy_id_mask = 0x0ffffff0,
516 .name = "Davicom DM9161E",
517 .init = dm9161_init,
518 .config_aneg = dm9161_config_aneg,
519 .read_status = dm9161_read_status,
520 .close = dm9161_close,
Dave Liue732e9c2006-11-03 12:11:15 -0600521};
522
523static struct phy_info phy_info_dm9161a = {
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100524 .phy_id = 0x0181b8a0,
525 .phy_id_mask = 0x0ffffff0,
526 .name = "Davicom DM9161A",
527 .features = MII_BASIC_FEATURES,
528 .init = dm9161_init,
529 .config_aneg = dm9161_config_aneg,
530 .read_status = dm9161_read_status,
531 .ack_interrupt = dm9161_ack_interrupt,
532 .config_intr = dm9161_config_intr,
533 .close = dm9161_close,
Dave Liue732e9c2006-11-03 12:11:15 -0600534};
535
536static struct phy_info phy_info_marvell = {
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100537 .phy_id = 0x01410c00,
538 .phy_id_mask = 0xffffff00,
539 .name = "Marvell 88E11x1",
540 .features = MII_GBIT_FEATURES,
541 .config_aneg = &marvell_config_aneg,
542 .read_status = &marvell_read_status,
543 .ack_interrupt = &marvell_ack_interrupt,
544 .config_intr = &marvell_config_intr,
Dave Liue732e9c2006-11-03 12:11:15 -0600545};
546
Anton Vorontsov98003732008-03-24 20:46:34 +0300547static struct phy_info phy_info_bcm5481 = {
548 .phy_id = 0x0143bca0,
549 .phy_id_mask = 0xffffff0,
550 .name = "Broadcom 5481",
551 .features = MII_GBIT_FEATURES,
552 .read_status = genmii_read_status,
553 .init = bcm_init,
554};
555
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100556static struct phy_info phy_info_genmii = {
557 .phy_id = 0x00000000,
558 .phy_id_mask = 0x00000000,
559 .name = "Generic MII",
560 .features = MII_BASIC_FEATURES,
561 .config_aneg = genmii_config_aneg,
562 .read_status = genmii_read_status,
Dave Liue732e9c2006-11-03 12:11:15 -0600563};
564
565static struct phy_info *phy_info[] = {
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100566 &phy_info_dm9161,
567 &phy_info_dm9161a,
568 &phy_info_marvell,
Anton Vorontsov98003732008-03-24 20:46:34 +0300569 &phy_info_bcm5481,
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100570 &phy_info_genmii,
571 NULL
Dave Liue732e9c2006-11-03 12:11:15 -0600572};
573
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100574u16 phy_read (struct uec_mii_info *mii_info, u16 regnum)
Dave Liue732e9c2006-11-03 12:11:15 -0600575{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100576 return mii_info->mdio_read (mii_info->dev, mii_info->mii_id, regnum);
Dave Liue732e9c2006-11-03 12:11:15 -0600577}
578
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100579void phy_write (struct uec_mii_info *mii_info, u16 regnum, u16 val)
Dave Liue732e9c2006-11-03 12:11:15 -0600580{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100581 mii_info->mdio_write (mii_info->dev, mii_info->mii_id, regnum, val);
Dave Liue732e9c2006-11-03 12:11:15 -0600582}
583
584/* Use the PHY ID registers to determine what type of PHY is attached
585 * to device dev. return a struct phy_info structure describing that PHY
586 */
Andy Flemingee0e9172007-08-14 00:14:25 -0500587struct phy_info *uec_get_phy_info (struct uec_mii_info *mii_info)
Dave Liue732e9c2006-11-03 12:11:15 -0600588{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100589 u16 phy_reg;
590 u32 phy_ID;
591 int i;
592 struct phy_info *theInfo = NULL;
Dave Liue732e9c2006-11-03 12:11:15 -0600593
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100594 /* Grab the bits from PHYIR1, and put them in the upper half */
595 phy_reg = phy_read (mii_info, PHY_PHYIDR1);
596 phy_ID = (phy_reg & 0xffff) << 16;
Dave Liue732e9c2006-11-03 12:11:15 -0600597
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100598 /* Grab the bits from PHYIR2, and put them in the lower half */
599 phy_reg = phy_read (mii_info, PHY_PHYIDR2);
600 phy_ID |= (phy_reg & 0xffff);
Dave Liue732e9c2006-11-03 12:11:15 -0600601
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100602 /* loop through all the known PHY types, and find one that */
603 /* matches the ID we read from the PHY. */
604 for (i = 0; phy_info[i]; i++)
605 if (phy_info[i]->phy_id ==
606 (phy_ID & phy_info[i]->phy_id_mask)) {
607 theInfo = phy_info[i];
608 break;
609 }
Dave Liue732e9c2006-11-03 12:11:15 -0600610
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100611 /* This shouldn't happen, as we have generic PHY support */
612 if (theInfo == NULL) {
613 ugphy_info ("UEC: PHY id %x is not supported!", phy_ID);
614 return NULL;
615 } else {
616 ugphy_info ("UEC: PHY is %s (%x)", theInfo->name, phy_ID);
617 }
Dave Liue732e9c2006-11-03 12:11:15 -0600618
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100619 return theInfo;
Dave Liue732e9c2006-11-03 12:11:15 -0600620}
621
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100622void marvell_phy_interface_mode (struct eth_device *dev,
623 enet_interface_e mode)
Dave Liue732e9c2006-11-03 12:11:15 -0600624{
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100625 uec_private_t *uec = (uec_private_t *) dev->priv;
626 struct uec_mii_info *mii_info;
Kim Phillips21084052008-02-27 15:06:39 -0600627 u16 status;
Dave Liue732e9c2006-11-03 12:11:15 -0600628
629 if (!uec->mii_info) {
Kim Phillipsb5da4272008-02-27 16:08:22 -0600630 printf ("%s: the PHY not initialized\n", __FUNCTION__);
Dave Liue732e9c2006-11-03 12:11:15 -0600631 return;
632 }
633 mii_info = uec->mii_info;
634
635 if (mode == ENET_100_RGMII) {
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100636 phy_write (mii_info, 0x00, 0x9140);
637 phy_write (mii_info, 0x1d, 0x001f);
638 phy_write (mii_info, 0x1e, 0x200c);
639 phy_write (mii_info, 0x1d, 0x0005);
640 phy_write (mii_info, 0x1e, 0x0000);
641 phy_write (mii_info, 0x1e, 0x0100);
642 phy_write (mii_info, 0x09, 0x0e00);
643 phy_write (mii_info, 0x04, 0x01e1);
644 phy_write (mii_info, 0x00, 0x9140);
645 phy_write (mii_info, 0x00, 0x1000);
646 udelay (100000);
647 phy_write (mii_info, 0x00, 0x2900);
648 phy_write (mii_info, 0x14, 0x0cd2);
649 phy_write (mii_info, 0x00, 0xa100);
650 phy_write (mii_info, 0x09, 0x0000);
651 phy_write (mii_info, 0x1b, 0x800b);
652 phy_write (mii_info, 0x04, 0x05e1);
653 phy_write (mii_info, 0x00, 0xa100);
654 phy_write (mii_info, 0x00, 0x2100);
655 udelay (1000000);
Dave Liue732e9c2006-11-03 12:11:15 -0600656 } else if (mode == ENET_10_RGMII) {
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100657 phy_write (mii_info, 0x14, 0x8e40);
658 phy_write (mii_info, 0x1b, 0x800b);
659 phy_write (mii_info, 0x14, 0x0c82);
660 phy_write (mii_info, 0x00, 0x8100);
661 udelay (1000000);
Dave Liue732e9c2006-11-03 12:11:15 -0600662 }
Kim Phillips21084052008-02-27 15:06:39 -0600663
664 /* handle 88e1111 rev.B2 erratum 5.6 */
665 if (mii_info->autoneg) {
666 status = phy_read (mii_info, PHY_BMCR);
667 phy_write (mii_info, PHY_BMCR, status | PHY_BMCR_AUTON);
668 }
669 /* now the B2 will correctly report autoneg completion status */
Dave Liue732e9c2006-11-03 12:11:15 -0600670}
671
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100672void change_phy_interface_mode (struct eth_device *dev, enet_interface_e mode)
Dave Liue732e9c2006-11-03 12:11:15 -0600673{
674#ifdef CONFIG_PHY_MODE_NEED_CHANGE
Wolfgang Denk87b3d4b2006-11-30 18:02:20 +0100675 marvell_phy_interface_mode (dev, mode);
Dave Liue732e9c2006-11-03 12:11:15 -0600676#endif
677}