Commit 2abe361c03b43e6dcf68f54e96b5c05156c49284
Committed by
Ben Warren
1 parent
75b9d4ae0d
Exists in
master
and in
54 other branches
Add SGMII support to the tsec
Adds support for configuring the TBI to talk properly with the SerDes. Signed-off-by: Andy Fleming <afleming@freescale.com> Signed-off-by: Ben Warren <biggerbadderben@gmail.com>
Showing 2 changed files with 72 additions and 27 deletions Side-by-side Diff
drivers/net/tsec.c
... | ... | @@ -216,62 +216,81 @@ |
216 | 216 | return (priv->link ? 0 : -1); |
217 | 217 | } |
218 | 218 | |
219 | -/* Write value to the device's PHY through the registers | |
220 | - * specified in priv, modifying the register specified in regnum. | |
221 | - * It will wait for the write to be done (or for a timeout to | |
222 | - * expire) before exiting | |
223 | - */ | |
224 | -void write_any_phy_reg(struct tsec_private *priv, uint phyid, uint regnum, uint value) | |
219 | +/* Writes the given phy's reg with value, using the specified MDIO regs */ | |
220 | +static void tsec_local_mdio_write(volatile tsec_t *phyregs, uint addr, | |
221 | + uint reg, uint value) | |
225 | 222 | { |
226 | - volatile tsec_t *regbase = priv->phyregs; | |
227 | 223 | int timeout = 1000000; |
228 | 224 | |
229 | - regbase->miimadd = (phyid << 8) | regnum; | |
230 | - regbase->miimcon = value; | |
225 | + phyregs->miimadd = (addr << 8) | reg; | |
226 | + phyregs->miimcon = value; | |
231 | 227 | asm("sync"); |
232 | 228 | |
233 | 229 | timeout = 1000000; |
234 | - while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ; | |
230 | + while ((phyregs->miimind & MIIMIND_BUSY) && timeout--) ; | |
235 | 231 | } |
236 | 232 | |
237 | -/* #define to provide old write_phy_reg functionality without duplicating code */ | |
238 | -#define write_phy_reg(priv, regnum, value) write_any_phy_reg(priv,priv->phyaddr,regnum,value) | |
239 | 233 | |
234 | +/* Provide the default behavior of writing the PHY of this ethernet device */ | |
235 | +#define write_phy_reg(priv, regnum, value) tsec_local_mdio_write(priv->phyregs,priv->phyaddr,regnum,value) | |
236 | + | |
240 | 237 | /* Reads register regnum on the device's PHY through the |
241 | - * registers specified in priv. It lowers and raises the read | |
238 | + * specified registers. It lowers and raises the read | |
242 | 239 | * command, and waits for the data to become valid (miimind |
243 | 240 | * notvalid bit cleared), and the bus to cease activity (miimind |
244 | 241 | * busy bit cleared), and then returns the value |
245 | 242 | */ |
246 | -uint read_any_phy_reg(struct tsec_private *priv, uint phyid, uint regnum) | |
243 | +uint tsec_local_mdio_read(volatile tsec_t *phyregs, uint phyid, uint regnum) | |
247 | 244 | { |
248 | 245 | uint value; |
249 | - volatile tsec_t *regbase = priv->phyregs; | |
250 | 246 | |
251 | 247 | /* Put the address of the phy, and the register |
252 | 248 | * number into MIIMADD */ |
253 | - regbase->miimadd = (phyid << 8) | regnum; | |
249 | + phyregs->miimadd = (phyid << 8) | regnum; | |
254 | 250 | |
255 | 251 | /* Clear the command register, and wait */ |
256 | - regbase->miimcom = 0; | |
252 | + phyregs->miimcom = 0; | |
257 | 253 | asm("sync"); |
258 | 254 | |
259 | 255 | /* Initiate a read command, and wait */ |
260 | - regbase->miimcom = MIIM_READ_COMMAND; | |
256 | + phyregs->miimcom = MIIM_READ_COMMAND; | |
261 | 257 | asm("sync"); |
262 | 258 | |
263 | 259 | /* Wait for the the indication that the read is done */ |
264 | - while ((regbase->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))) ; | |
260 | + while ((phyregs->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))) ; | |
265 | 261 | |
266 | 262 | /* Grab the value read from the PHY */ |
267 | - value = regbase->miimstat; | |
263 | + value = phyregs->miimstat; | |
268 | 264 | |
269 | 265 | return value; |
270 | 266 | } |
271 | 267 | |
272 | 268 | /* #define to provide old read_phy_reg functionality without duplicating code */ |
273 | -#define read_phy_reg(priv,regnum) read_any_phy_reg(priv,priv->phyaddr,regnum) | |
269 | +#define read_phy_reg(priv,regnum) tsec_local_mdio_read(priv->phyregs,priv->phyaddr,regnum) | |
274 | 270 | |
271 | +#define TBIANA_SETTINGS ( \ | |
272 | + TBIANA_ASYMMETRIC_PAUSE \ | |
273 | + | TBIANA_SYMMETRIC_PAUSE \ | |
274 | + | TBIANA_FULL_DUPLEX \ | |
275 | + ) | |
276 | + | |
277 | +#define TBICR_SETTINGS ( \ | |
278 | + TBICR_PHY_RESET \ | |
279 | + | TBICR_ANEG_ENABLE \ | |
280 | + | TBICR_FULL_DUPLEX \ | |
281 | + | TBICR_SPEED1_SET \ | |
282 | + ) | |
283 | +/* Configure the TBI for SGMII operation */ | |
284 | +static void tsec_configure_serdes(struct tsec_private *priv) | |
285 | +{ | |
286 | + tsec_local_mdio_write(priv->phyregs, CFG_TBIPA_VALUE, TBI_ANA, | |
287 | + TBIANA_SETTINGS); | |
288 | + tsec_local_mdio_write(priv->phyregs, CFG_TBIPA_VALUE, TBI_TBICON, | |
289 | + TBICON_CLK_SELECT); | |
290 | + tsec_local_mdio_write(priv->phyregs, CFG_TBIPA_VALUE, TBI_CR, | |
291 | + TBICR_SETTINGS); | |
292 | +} | |
293 | + | |
275 | 294 | /* Discover which PHY is attached to the device, and configure it |
276 | 295 | * properly. If the PHY is not recognized, then return 0 |
277 | 296 | * (failure). Otherwise, return 1 |
278 | 297 | |
... | ... | @@ -280,12 +299,12 @@ |
280 | 299 | { |
281 | 300 | struct tsec_private *priv = (struct tsec_private *)dev->priv; |
282 | 301 | struct phy_info *curphy; |
283 | - volatile tsec_t *regs = (volatile tsec_t *)(TSEC_BASE_ADDR); | |
302 | + volatile tsec_t *phyregs = priv->phyregs; | |
303 | + volatile tsec_t *regs = priv->regs; | |
284 | 304 | |
285 | 305 | /* Assign a Physical address to the TBI */ |
286 | 306 | regs->tbipa = CFG_TBIPA_VALUE; |
287 | - regs = (volatile tsec_t *)(TSEC_BASE_ADDR + TSEC_SIZE); | |
288 | - regs->tbipa = CFG_TBIPA_VALUE; | |
307 | + phyregs->tbipa = CFG_TBIPA_VALUE; | |
289 | 308 | asm("sync"); |
290 | 309 | |
291 | 310 | /* Reset MII (due to new addresses) */ |
... | ... | @@ -309,6 +328,9 @@ |
309 | 328 | return 0; |
310 | 329 | } |
311 | 330 | |
331 | + if (regs->ecntrl & ECNTRL_SGMII_MODE) | |
332 | + tsec_configure_serdes(priv); | |
333 | + | |
312 | 334 | priv->phyinfo = curphy; |
313 | 335 | |
314 | 336 | phy_run_commands(priv, priv->phyinfo->config); |
... | ... | @@ -1700,7 +1722,7 @@ |
1700 | 1722 | return -1; |
1701 | 1723 | } |
1702 | 1724 | |
1703 | - ret = (unsigned short)read_any_phy_reg(priv, addr, reg); | |
1725 | + ret = (unsigned short)tsec_local_mdio_read(priv->phyregs, addr, reg); | |
1704 | 1726 | *value = ret; |
1705 | 1727 | |
1706 | 1728 | return 0; |
... | ... | @@ -1722,7 +1744,7 @@ |
1722 | 1744 | return -1; |
1723 | 1745 | } |
1724 | 1746 | |
1725 | - write_any_phy_reg(priv, addr, reg, value); | |
1747 | + tsec_local_mdio_write(priv->phyregs, addr, reg, value); | |
1726 | 1748 | |
1727 | 1749 | return 0; |
1728 | 1750 | } |
include/tsec.h
... | ... | @@ -60,6 +60,27 @@ |
60 | 60 | |
61 | 61 | #define PHY_AUTONEGOTIATE_TIMEOUT 5000 /* in ms */ |
62 | 62 | |
63 | +/* TBI register addresses */ | |
64 | +#define TBI_CR 0x00 | |
65 | +#define TBI_SR 0x01 | |
66 | +#define TBI_ANA 0x04 | |
67 | +#define TBI_ANLPBPA 0x05 | |
68 | +#define TBI_ANEX 0x06 | |
69 | +#define TBI_TBICON 0x11 | |
70 | + | |
71 | +/* TBI MDIO register bit fields*/ | |
72 | +#define TBICON_CLK_SELECT 0x0020 | |
73 | +#define TBIANA_ASYMMETRIC_PAUSE 0x0100 | |
74 | +#define TBIANA_SYMMETRIC_PAUSE 0x0080 | |
75 | +#define TBIANA_HALF_DUPLEX 0x0040 | |
76 | +#define TBIANA_FULL_DUPLEX 0x0020 | |
77 | +#define TBICR_PHY_RESET 0x8000 | |
78 | +#define TBICR_ANEG_ENABLE 0x1000 | |
79 | +#define TBICR_RESTART_ANEG 0x0200 | |
80 | +#define TBICR_FULL_DUPLEX 0x0100 | |
81 | +#define TBICR_SPEED1_SET 0x0040 | |
82 | + | |
83 | + | |
63 | 84 | /* MAC register bits */ |
64 | 85 | #define MACCFG1_SOFT_RESET 0x80000000 |
65 | 86 | #define MACCFG1_RESET_RX_MC 0x00080000 |
... | ... | @@ -540,7 +561,9 @@ |
540 | 561 | |
541 | 562 | /* This flag currently only has |
542 | 563 | * meaning if we're using the eTSEC */ |
543 | -#define TSEC_REDUCED (1 << 1) | |
564 | +#define TSEC_REDUCED (1 << 1) | |
565 | + | |
566 | +#define TSEC_SGMII (1 << 2) | |
544 | 567 | |
545 | 568 | struct tsec_private { |
546 | 569 | volatile tsec_t *regs; |