RT-AC66 3.0.0.4.374.130 core
[tomato.git] / release / src-rt-6.x / cfe / cfe / arch / mips / cpu / sb1250 / src / ui_phycmds.c
blob1424ff9e60250d82e3c197a23b335c83ccdc8621
1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
3 *
4 * PHY hacking commands File: ui_phycmds.c
5 *
6 * These commands let you directly muck with the PHYs
7 * attached to the Ethernet controllers.
8 *
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 ********************************************************************* */
51 #include "sbmips.h"
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"
66 #include "cfe.h"
67 #include "cfe_error.h"
68 #include "mii.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 */
76 #ifdef __long64
77 typedef volatile uint64_t phy_port_t;
78 typedef uint64_t phy_physaddr_t;
79 #define PHY_PORT(x) PHYS_TO_K1(x)
80 #else
81 typedef volatile uint32_t phy_port_t;
82 typedef uint32_t phy_physaddr_t;
83 #define PHY_PORT(x) PHYS_TO_K1(x)
84 #endif
86 typedef struct phy_s {
87 phy_port_t sbe_mdio;
88 } phy_t;
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,
97 unsigned int regval);
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",
104 ui_cmd_phydump,
105 NULL,
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"
112 "are displayed.",
113 "-phy=*;Specify PHY address (default=1)");
115 cmd_addcmd("phy set",
116 ui_cmd_physet,
117 NULL,
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"
123 "register.\n",
124 "-phy=*;Specify PHY address (default=1)");
126 return 0;
129 static int ui_cmd_physet(ui_cmdline_t *cmd,int argc,char *argv[])
131 phy_t phy;
132 int phynum;
133 int mac;
134 char *x;
135 unsigned int value;
136 unsigned int reg;
138 x = cmd_getarg(cmd,0);
139 if (!x) return ui_showusage(cmd);
141 mac = atoi(x);
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)) {
148 phynum = atoi(x);
150 else phynum = 1;
152 x = cmd_getarg(cmd,1);
153 if (!x) return ui_showusage(cmd);
154 reg = atoi(x);
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);
168 return 0;
171 static int ui_cmd_phydump(ui_cmdline_t *cmd,int argc,char *argv[])
173 phy_t phy;
174 int phynum;
175 int idx;
176 int mac;
177 char *x;
178 unsigned int reg;
179 int allreg = 1;
181 x = cmd_getarg(cmd,0);
182 if (!x) return ui_showusage(cmd);
184 mac = atoi(x);
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)) {
191 phynum = atoi(x);
193 else phynum = 1;
195 x = cmd_getarg(cmd,1);
196 reg = 0;
197 if (x) {
198 reg = atoi(x);
199 if ((reg < 0) || (reg > 31)) {
200 return ui_showerror(CFE_ERR_INV_PARAM,"Invalid phy register number");
202 allreg = 0;
205 if (allreg) {
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));
210 printf("\n");
213 else {
214 printf("Reg %02X = %04X\n",reg,phy_mii_read(&phy,phynum,reg));
217 return 0;
224 /* *********************************************************************
225 * PHY_MII_SYNC(s)
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.
230 * Input parameters:
231 * s - sbmac structure
233 * Return value:
234 * nothing
235 ********************************************************************* */
237 static void phy_mii_sync(phy_t *s)
239 int cnt;
240 uint64_t bits;
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.
262 * Input parameters:
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)
270 int i;
271 uint64_t bits;
272 unsigned int curmask;
273 int mac_mdio_genc;
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);
288 curmask >>= 1;
294 /* *********************************************************************
295 * PHY_MII_READ(s,phyaddr,regidx)
297 * Read a PHY register.
299 * Input parameters:
300 * s - sbmac structure
301 * phyaddr - PHY's address
302 * regidx = index of register to read
304 * Return value:
305 * value read, or 0 if an error occured.
306 ********************************************************************* */
308 static unsigned int phy_mii_read(phy_t *s,int phyaddr,int regidx)
310 int idx;
311 int error;
312 int regval;
313 int mac_mdio_genc;
316 * Synchronize ourselves so that the PHY knows the next
317 * thing coming down is a command
320 phy_mii_sync(s);
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
356 * the same.
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);
361 regval = 0;
363 for (idx = 0; idx < 16; idx++) {
364 regval <<= 1;
366 if (error == 0) {
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;
378 return 0;
382 /* *********************************************************************
383 * PHY_MII_WRITE(s,phyaddr,regidx,regval)
385 * Write a value to a PHY register.
387 * Input parameters:
388 * s - sbmac structure
389 * phyaddr - PHY to use
390 * regidx - register within the PHY
391 * regval - data to write to register
393 * Return value:
394 * nothing
395 ********************************************************************* */
397 static void phy_mii_write(phy_t *s,int phyaddr,int regidx,
398 unsigned int regval)
400 int mac_mdio_genc;
402 phy_mii_sync(s);
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);