1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * PHY hacking commands File: ui_phycmds.c
6 * These commands let you directly muck with the PHYs
7 * attached to the Ethernet controllers.
9 * Author: Mitch Lichtenberg (mpl@broadcom.com)
11 *********************************************************************
13 * Copyright 2000,2001,2002,2003
14 * Broadcom Corporation. All rights reserved.
16 * This software is furnished under license and may be used and
17 * copied only in accordance with the following terms and
18 * conditions. Subject to these conditions, you may download,
19 * copy, install, use, modify and distribute modified or unmodified
20 * copies of this software in source and/or binary form. No title
21 * or ownership is transferred hereby.
23 * 1) Any source code used, modified or distributed must reproduce
24 * and retain this copyright notice and list of conditions
25 * as they appear in the source file.
27 * 2) No right is granted to use any trade name, trademark, or
28 * logo of Broadcom Corporation. The "Broadcom Corporation"
29 * name may not be used to endorse or promote products derived
30 * from this software without the prior written permission of
31 * Broadcom Corporation.
33 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
34 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
35 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
37 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
38 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
39 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
41 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
43 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
44 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
45 * THE POSSIBILITY OF SUCH DAMAGE.
46 ********************************************************************* */
53 #include "lib_types.h"
54 #include "lib_string.h"
55 #include "lib_queue.h"
56 #include "lib_malloc.h"
57 #include "lib_printf.h"
58 #include "lib_arena.h"
60 #include "ui_command.h"
62 #include "sb1250_defs.h"
63 #include "sb1250_regs.h"
64 #include "sb1250_mac.h"
67 #include "cfe_error.h"
71 #define PHY_READCSR(t) (*((volatile uint64_t *) (t)))
72 #define PHY_WRITECSR(t,v) *((volatile uint64_t *) (t)) = (v)
74 #define M_MAC_MDIO_DIR_OUTPUT 0 /* for clarity */
77 typedef volatile uint64_t phy_port_t
;
78 typedef uint64_t phy_physaddr_t
;
79 #define PHY_PORT(x) PHYS_TO_K1(x)
81 typedef volatile uint32_t phy_port_t
;
82 typedef uint32_t phy_physaddr_t
;
83 #define PHY_PORT(x) PHYS_TO_K1(x)
86 typedef struct phy_s
{
91 int ui_init_phycmds(void);
93 static int ui_cmd_phydump(ui_cmdline_t
*cmd
,int argc
,char *argv
[]);
94 static int ui_cmd_physet(ui_cmdline_t
*cmd
,int argc
,char *argv
[]);
96 static void phy_mii_write(phy_t
*s
,int phyaddr
,int regidx
,
98 static unsigned int phy_mii_read(phy_t
*s
,int phyaddr
,int regidx
);
101 int ui_init_phycmds(void)
103 cmd_addcmd("phy dump",
106 "Dump the registers on the PHY",
107 "phy dump macid [reg]\n\n"
108 "This command displays the contents of the registers on the PHY\n"
109 "attached to the specified Ethernet controller. macid is the\n"
110 "Ethernet controller ID (0..2 for the BCM1250) and reg\n"
111 "is an optional register number (0..31). By default, all registers\n"
113 "-phy=*;Specify PHY address (default=1)");
115 cmd_addcmd("phy set",
118 "Set the value of a PHY register",
119 "phy set macid reg value\n\n"
120 "Sets the value of a register on a PHY. macid is the Ethernet\n"
121 "controller number (0..2 for the BCM1250), reg is the register\n"
122 "number (0..31), and value is the 16-bit value to write to the\n"
124 "-phy=*;Specify PHY address (default=1)");
129 static int ui_cmd_physet(ui_cmdline_t
*cmd
,int argc
,char *argv
[])
138 x
= cmd_getarg(cmd
,0);
139 if (!x
) return ui_showusage(cmd
);
142 if ((mac
< 0) || (mac
> 2)) {
143 return ui_showerror(CFE_ERR_INV_PARAM
,"Invalid MAC number");
145 phy
.sbe_mdio
= PHY_PORT(A_MAC_REGISTER(mac
,R_MAC_MDIO
));
147 if (cmd_sw_value(cmd
,"-phy",&x
)) {
152 x
= cmd_getarg(cmd
,1);
153 if (!x
) return ui_showusage(cmd
);
155 if ((reg
< 0) || (reg
> 31)) {
156 return ui_showerror(CFE_ERR_INV_PARAM
,"Invalid phy register number");
159 x
= cmd_getarg(cmd
,2);
160 if (!x
) return ui_showusage(cmd
);
161 value
= atoi(x
) & 0xFFFF;
163 phy_mii_write(&phy
,phynum
,reg
,value
);
165 printf("Wrote 0x%04X to phy %d register 0x%02X on mac %d\n",
166 value
,phynum
,reg
,mac
);
171 static int ui_cmd_phydump(ui_cmdline_t
*cmd
,int argc
,char *argv
[])
181 x
= cmd_getarg(cmd
,0);
182 if (!x
) return ui_showusage(cmd
);
185 if ((mac
< 0) || (mac
> 2)) {
186 return ui_showerror(CFE_ERR_INV_PARAM
,"Invalid MAC number");
188 phy
.sbe_mdio
= PHY_PORT(A_MAC_REGISTER(mac
,R_MAC_MDIO
));
190 if (cmd_sw_value(cmd
,"-phy",&x
)) {
195 x
= cmd_getarg(cmd
,1);
199 if ((reg
< 0) || (reg
> 31)) {
200 return ui_showerror(CFE_ERR_INV_PARAM
,"Invalid phy register number");
206 printf("** PHY registers on MAC %d PHY %d **\n",mac
,phynum
);
207 for (idx
= 0; idx
< 31; idx
+=2) {
208 printf("Reg 0x%02X = 0x%04X | ",idx
,phy_mii_read(&phy
,phynum
,idx
));
209 printf("Reg 0x%02X = 0x%04X",idx
+1,phy_mii_read(&phy
,phynum
,idx
+1));
214 printf("Reg %02X = %04X\n",reg
,phy_mii_read(&phy
,phynum
,reg
));
224 /* *********************************************************************
227 * Synchronize with the MII - send a pattern of bits to the MII
228 * that will guarantee that it is ready to accept a command.
231 * s - sbmac structure
235 ********************************************************************* */
237 static void phy_mii_sync(phy_t
*s
)
241 int mac_mdio_genc
; /*genc bit needs to be saved*/
243 mac_mdio_genc
= PHY_READCSR(s
->sbe_mdio
) & M_MAC_GENC
;
245 bits
= M_MAC_MDIO_DIR_OUTPUT
| M_MAC_MDIO_OUT
;
247 PHY_WRITECSR(s
->sbe_mdio
,bits
| mac_mdio_genc
);
249 for (cnt
= 0; cnt
< 32; cnt
++) {
250 PHY_WRITECSR(s
->sbe_mdio
,bits
| M_MAC_MDC
| mac_mdio_genc
);
251 PHY_WRITECSR(s
->sbe_mdio
,bits
| mac_mdio_genc
);
256 /* *********************************************************************
257 * PHY_MII_SENDDATA(s,data,bitcnt)
259 * Send some bits to the MII. The bits to be sent are right-
260 * justified in the 'data' parameter.
263 * s - sbmac structure
264 * data - data to send
265 * bitcnt - number of bits to send
266 ********************************************************************* */
268 static void phy_mii_senddata(phy_t
*s
,unsigned int data
, int bitcnt
)
272 unsigned int curmask
;
275 mac_mdio_genc
= PHY_READCSR(s
->sbe_mdio
) & M_MAC_GENC
;
277 bits
= M_MAC_MDIO_DIR_OUTPUT
;
278 PHY_WRITECSR(s
->sbe_mdio
,bits
| mac_mdio_genc
);
280 curmask
= 1 << (bitcnt
- 1);
282 for (i
= 0; i
< bitcnt
; i
++) {
283 if (data
& curmask
) bits
|= M_MAC_MDIO_OUT
;
284 else bits
&= ~M_MAC_MDIO_OUT
;
285 PHY_WRITECSR(s
->sbe_mdio
,bits
| mac_mdio_genc
);
286 PHY_WRITECSR(s
->sbe_mdio
,bits
| M_MAC_MDC
| mac_mdio_genc
);
287 PHY_WRITECSR(s
->sbe_mdio
,bits
| mac_mdio_genc
);
294 /* *********************************************************************
295 * PHY_MII_READ(s,phyaddr,regidx)
297 * Read a PHY register.
300 * s - sbmac structure
301 * phyaddr - PHY's address
302 * regidx = index of register to read
305 * value read, or 0 if an error occured.
306 ********************************************************************* */
308 static unsigned int phy_mii_read(phy_t
*s
,int phyaddr
,int regidx
)
316 * Synchronize ourselves so that the PHY knows the next
317 * thing coming down is a command
323 * Send the data to the PHY. The sequence is
324 * a "start" command (2 bits)
325 * a "read" command (2 bits)
326 * the PHY addr (5 bits)
327 * the register index (5 bits)
330 phy_mii_senddata(s
,MII_COMMAND_START
, 2);
331 phy_mii_senddata(s
,MII_COMMAND_READ
, 2);
332 phy_mii_senddata(s
,phyaddr
, 5);
333 phy_mii_senddata(s
,regidx
, 5);
335 mac_mdio_genc
= PHY_READCSR(s
->sbe_mdio
) & M_MAC_GENC
;
338 * Switch the port around without a clock transition.
340 PHY_WRITECSR(s
->sbe_mdio
,M_MAC_MDIO_DIR_INPUT
| mac_mdio_genc
);
343 * Send out a clock pulse to signal we want the status
346 PHY_WRITECSR(s
->sbe_mdio
,M_MAC_MDIO_DIR_INPUT
| M_MAC_MDC
| mac_mdio_genc
);
347 PHY_WRITECSR(s
->sbe_mdio
,M_MAC_MDIO_DIR_INPUT
| mac_mdio_genc
);
350 * If an error occured, the PHY will signal '1' back
352 error
= PHY_READCSR(s
->sbe_mdio
) & M_MAC_MDIO_IN
;
355 * Issue an 'idle' clock pulse, but keep the direction
358 PHY_WRITECSR(s
->sbe_mdio
,M_MAC_MDIO_DIR_INPUT
| M_MAC_MDC
| mac_mdio_genc
);
359 PHY_WRITECSR(s
->sbe_mdio
,M_MAC_MDIO_DIR_INPUT
| mac_mdio_genc
);
363 for (idx
= 0; idx
< 16; idx
++) {
367 if (PHY_READCSR(s
->sbe_mdio
) & M_MAC_MDIO_IN
) regval
|= 1;
370 PHY_WRITECSR(s
->sbe_mdio
,M_MAC_MDIO_DIR_INPUT
| M_MAC_MDC
| mac_mdio_genc
);
371 PHY_WRITECSR(s
->sbe_mdio
,M_MAC_MDIO_DIR_INPUT
| mac_mdio_genc
);
374 /* Switch back to output */
375 PHY_WRITECSR(s
->sbe_mdio
,M_MAC_MDIO_DIR_OUTPUT
| mac_mdio_genc
);
377 if (error
== 0) return regval
;
382 /* *********************************************************************
383 * PHY_MII_WRITE(s,phyaddr,regidx,regval)
385 * Write a value to a PHY register.
388 * s - sbmac structure
389 * phyaddr - PHY to use
390 * regidx - register within the PHY
391 * regval - data to write to register
395 ********************************************************************* */
397 static void phy_mii_write(phy_t
*s
,int phyaddr
,int regidx
,
404 phy_mii_senddata(s
,MII_COMMAND_START
,2);
405 phy_mii_senddata(s
,MII_COMMAND_WRITE
,2);
406 phy_mii_senddata(s
,phyaddr
, 5);
407 phy_mii_senddata(s
,regidx
, 5);
408 phy_mii_senddata(s
,MII_COMMAND_ACK
,2);
409 phy_mii_senddata(s
,regval
,16);
411 mac_mdio_genc
= PHY_READCSR(s
->sbe_mdio
) & M_MAC_GENC
;
413 PHY_WRITECSR(s
->sbe_mdio
,M_MAC_MDIO_DIR_OUTPUT
| mac_mdio_genc
);