• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/cfe/cfe/arch/mips/cpu/sb1250/src/
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)
10    *
11    *********************************************************************
12    *
13    *  Copyright 2000,2001,2002,2003
14    *  Broadcom Corporation. All rights reserved.
15    *
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.
22    *
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.
26    *
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.
32    *
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    ********************************************************************* */
47
48
49
50
51#include "sbmips.h"
52
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"
59
60#include "ui_command.h"
61
62#include "sb1250_defs.h"
63#include "sb1250_regs.h"
64#include "sb1250_mac.h"
65
66#include "cfe.h"
67#include "cfe_error.h"
68#include "mii.h"
69
70
71#define PHY_READCSR(t) (*((volatile uint64_t *) (t)))
72#define PHY_WRITECSR(t,v) *((volatile uint64_t *) (t)) = (v)
73
74#define M_MAC_MDIO_DIR_OUTPUT	0		/* for clarity */
75
76#ifdef __long64
77typedef volatile uint64_t phy_port_t;
78typedef uint64_t phy_physaddr_t;
79#define PHY_PORT(x) PHYS_TO_K1(x)
80#else
81typedef volatile uint32_t phy_port_t;
82typedef uint32_t phy_physaddr_t;
83#define PHY_PORT(x) PHYS_TO_K1(x)
84#endif
85
86typedef struct phy_s {
87    phy_port_t sbe_mdio;
88} phy_t;
89
90
91int ui_init_phycmds(void);
92
93static int ui_cmd_phydump(ui_cmdline_t *cmd,int argc,char *argv[]);
94static int ui_cmd_physet(ui_cmdline_t *cmd,int argc,char *argv[]);
95
96static void phy_mii_write(phy_t *s,int phyaddr,int regidx,
97		     unsigned int regval);
98static unsigned int phy_mii_read(phy_t *s,int phyaddr,int regidx);
99
100
101int ui_init_phycmds(void)
102{
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)");
114
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)");
125
126    return 0;
127}
128
129static int ui_cmd_physet(ui_cmdline_t *cmd,int argc,char *argv[])
130{
131    phy_t phy;
132    int phynum;
133    int mac;
134    char *x;
135    unsigned int value;
136    unsigned int reg;
137
138    x = cmd_getarg(cmd,0);
139    if (!x) return ui_showusage(cmd);
140
141    mac = atoi(x);
142    if ((mac < 0) || (mac > 2)) {
143	return ui_showerror(CFE_ERR_INV_PARAM,"Invalid MAC number");
144	}
145    phy.sbe_mdio = PHY_PORT(A_MAC_REGISTER(mac,R_MAC_MDIO));
146
147    if (cmd_sw_value(cmd,"-phy",&x)) {
148	phynum = atoi(x);
149	}
150    else phynum = 1;
151
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");
157	}
158
159    x = cmd_getarg(cmd,2);
160    if (!x) return ui_showusage(cmd);
161    value = atoi(x) & 0xFFFF;
162
163    phy_mii_write(&phy,phynum,reg,value);
164
165    printf("Wrote 0x%04X to phy %d register 0x%02X on mac %d\n",
166	   value,phynum,reg,mac);
167
168    return 0;
169}
170
171static int ui_cmd_phydump(ui_cmdline_t *cmd,int argc,char *argv[])
172{
173    phy_t phy;
174    int phynum;
175    int idx;
176    int mac;
177    char *x;
178    unsigned int reg;
179    int allreg = 1;
180
181    x = cmd_getarg(cmd,0);
182    if (!x) return ui_showusage(cmd);
183
184    mac = atoi(x);
185    if ((mac < 0) || (mac > 2)) {
186	return ui_showerror(CFE_ERR_INV_PARAM,"Invalid MAC number");
187	}
188    phy.sbe_mdio = PHY_PORT(A_MAC_REGISTER(mac,R_MAC_MDIO));
189
190    if (cmd_sw_value(cmd,"-phy",&x)) {
191	phynum = atoi(x);
192	}
193    else phynum = 1;
194
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");
201	    }
202	allreg = 0;
203	}
204
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");
211	    }
212	}
213    else {
214	printf("Reg %02X = %04X\n",reg,phy_mii_read(&phy,phynum,reg));
215	}
216
217    return 0;
218
219}
220
221
222
223
224/*  *********************************************************************
225    *  PHY_MII_SYNC(s)
226    *
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.
229    *
230    *  Input parameters:
231    *  	   s - sbmac structure
232    *
233    *  Return value:
234    *  	   nothing
235    ********************************************************************* */
236
237static void phy_mii_sync(phy_t *s)
238{
239    int cnt;
240    uint64_t bits;
241    int mac_mdio_genc; /*genc bit needs to be saved*/
242
243    mac_mdio_genc = PHY_READCSR(s->sbe_mdio) & M_MAC_GENC;
244
245    bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT;
246
247    PHY_WRITECSR(s->sbe_mdio,bits | mac_mdio_genc);
248
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);
252	}
253
254}
255
256/*  *********************************************************************
257    *  PHY_MII_SENDDATA(s,data,bitcnt)
258    *
259    *  Send some bits to the MII.  The bits to be sent are right-
260    *  justified in the 'data' parameter.
261    *
262    *  Input parameters:
263    *  	   s - sbmac structure
264    *  	   data - data to send
265    *  	   bitcnt - number of bits to send
266    ********************************************************************* */
267
268static void phy_mii_senddata(phy_t *s,unsigned int data, int bitcnt)
269{
270    int i;
271    uint64_t bits;
272    unsigned int curmask;
273    int mac_mdio_genc;
274
275    mac_mdio_genc = PHY_READCSR(s->sbe_mdio) & M_MAC_GENC;
276
277    bits = M_MAC_MDIO_DIR_OUTPUT;
278    PHY_WRITECSR(s->sbe_mdio,bits | mac_mdio_genc);
279
280    curmask = 1 << (bitcnt - 1);
281
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;
289	}
290}
291
292
293
294/*  *********************************************************************
295    *  PHY_MII_READ(s,phyaddr,regidx)
296    *
297    *  Read a PHY register.
298    *
299    *  Input parameters:
300    *  	   s - sbmac structure
301    *  	   phyaddr - PHY's address
302    *  	   regidx = index of register to read
303    *
304    *  Return value:
305    *  	   value read, or 0 if an error occured.
306    ********************************************************************* */
307
308static unsigned int phy_mii_read(phy_t *s,int phyaddr,int regidx)
309{
310    int idx;
311    int error;
312    int regval;
313    int mac_mdio_genc;
314
315    /*
316     * Synchronize ourselves so that the PHY knows the next
317     * thing coming down is a command
318     */
319
320    phy_mii_sync(s);
321
322    /*
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)
328     */
329
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);
334
335    mac_mdio_genc = PHY_READCSR(s->sbe_mdio) & M_MAC_GENC;
336
337    /*
338     * Switch the port around without a clock transition.
339     */
340    PHY_WRITECSR(s->sbe_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc);
341
342    /*
343     * Send out a clock pulse to signal we want the status
344     */
345
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);
348
349    /*
350     * If an error occured, the PHY will signal '1' back
351     */
352    error = PHY_READCSR(s->sbe_mdio) & M_MAC_MDIO_IN;
353
354    /*
355     * Issue an 'idle' clock pulse, but keep the direction
356     * the same.
357     */
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);
360
361    regval = 0;
362
363    for (idx = 0; idx < 16; idx++) {
364	regval <<= 1;
365
366	if (error == 0) {
367	    if (PHY_READCSR(s->sbe_mdio) & M_MAC_MDIO_IN) regval |= 1;
368	    }
369
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);
372	}
373
374    /* Switch back to output */
375    PHY_WRITECSR(s->sbe_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc);
376
377    if (error == 0) return regval;
378    return 0;
379}
380
381
382/*  *********************************************************************
383    *  PHY_MII_WRITE(s,phyaddr,regidx,regval)
384    *
385    *  Write a value to a PHY register.
386    *
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
392    *
393    *  Return value:
394    *  	   nothing
395    ********************************************************************* */
396
397static void phy_mii_write(phy_t *s,int phyaddr,int regidx,
398			    unsigned int regval)
399{
400    int mac_mdio_genc;
401
402    phy_mii_sync(s);
403
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);
410
411    mac_mdio_genc = PHY_READCSR(s->sbe_mdio) & M_MAC_GENC;
412
413    PHY_WRITECSR(s->sbe_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc);
414}
415