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 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#include "cfe.h" 51#include "sbmips.h" 52 53#include "ui_command.h" 54 55#include "sb1250_defs.h" 56#include "sb1250_regs.h" 57#include "sb1250_mac.h" 58 59#include "mii.h" 60 61 62#define PHY_READCSR(t) (*((volatile uint64_t *) (t))) 63#define PHY_WRITECSR(t,v) *((volatile uint64_t *) (t)) = (v) 64 65#define M_MAC_MDIO_DIR_OUTPUT 0 /* for clarity */ 66 67#ifdef __long64 68typedef volatile uint64_t phy_port_t; 69typedef uint64_t phy_physaddr_t; 70#define PHY_PORT(x) PHYS_TO_K1(x) 71#else 72typedef volatile uint32_t phy_port_t; 73typedef uint32_t phy_physaddr_t; 74#define PHY_PORT(x) PHYS_TO_K1(x) 75#endif 76 77typedef struct phy_s { 78 phy_port_t sbe_mdio; 79} phy_t; 80 81 82int ui_init_phycmds(void); 83 84static int ui_cmd_phydump(ui_cmdline_t *cmd,int argc,char *argv[]); 85static int ui_cmd_physet(ui_cmdline_t *cmd,int argc,char *argv[]); 86 87static void phy_mii_write(phy_t *s,int phyaddr,int regidx, 88 unsigned int regval); 89static unsigned int phy_mii_read(phy_t *s,int phyaddr,int regidx); 90 91 92int ui_init_phycmds(void) 93{ 94 cmd_addcmd("phy dump", 95 ui_cmd_phydump, 96 NULL, 97 "Dump the registers on the PHY", 98 "phy dump macid [reg]\n\n" 99 "This command displays the contents of the registers on the PHY\n" 100 "attached to the specified Ethernet controller. macid is the\n" 101 "Ethernet controller ID (0..2 for the BCM1250) and reg\n" 102 "is an optional register number (0..31). By default, all registers\n" 103 "are displayed.", 104 "-phy=*;Specify PHY address (default=1)"); 105 106 cmd_addcmd("phy set", 107 ui_cmd_physet, 108 NULL, 109 "Set the value of a PHY register", 110 "phy set macid reg value\n\n" 111 "Sets the value of a register on a PHY. macid is the Ethernet\n" 112 "controller number (0..2 for the BCM1250), reg is the register\n" 113 "number (0..31), and value is the 16-bit value to write to the\n" 114 "register.\n", 115 "-phy=*;Specify PHY address (default=1)"); 116 117 return 0; 118} 119 120static int ui_cmd_physet(ui_cmdline_t *cmd,int argc,char *argv[]) 121{ 122 phy_t phy; 123 int phynum; 124 int mac; 125 char *x; 126 unsigned int value; 127 unsigned int reg; 128 129 x = cmd_getarg(cmd,0); 130 if (!x) return ui_showusage(cmd); 131 132 mac = atoi(x); 133 if ((mac < 0) || (mac > 3)) { 134 return ui_showerror(CFE_ERR_INV_PARAM,"Invalid MAC number"); 135 } 136 phy.sbe_mdio = PHY_PORT(A_MAC_REGISTER(mac,R_MAC_MDIO)); 137 138 if (cmd_sw_value(cmd,"-phy",&x)) { 139 phynum = atoi(x); 140 } 141 else phynum = 1; 142 143 x = cmd_getarg(cmd,1); 144 if (!x) return ui_showusage(cmd); 145 reg = atoi(x); 146 if ((reg < 0) || (reg > 31)) { 147 return ui_showerror(CFE_ERR_INV_PARAM,"Invalid phy register number"); 148 } 149 150 x = cmd_getarg(cmd,2); 151 if (!x) return ui_showusage(cmd); 152 value = atoi(x) & 0xFFFF; 153 154 phy_mii_write(&phy,phynum,reg,value); 155 156 printf("Wrote 0x%04X to phy %d register 0x%02X on mac %d\n", 157 value,phynum,reg,mac); 158 159 return 0; 160} 161 162static int ui_cmd_phydump(ui_cmdline_t *cmd,int argc,char *argv[]) 163{ 164 phy_t phy; 165 int phynum; 166 int idx; 167 int mac; 168 char *x; 169 unsigned int reg; 170 int allreg = 1; 171 172 x = cmd_getarg(cmd,0); 173 if (!x) return ui_showusage(cmd); 174 175 mac = atoi(x); 176 if ((mac < 0) || (mac > 3)) { 177 return ui_showerror(CFE_ERR_INV_PARAM,"Invalid MAC number"); 178 } 179 phy.sbe_mdio = PHY_PORT(A_MAC_REGISTER(mac,R_MAC_MDIO)); 180 181 if (cmd_sw_value(cmd,"-phy",&x)) { 182 phynum = atoi(x); 183 } 184 else phynum = 1; 185 186 x = cmd_getarg(cmd,1); 187 reg = 0; 188 if (x) { 189 reg = atoi(x); 190 if ((reg < 0) || (reg > 31)) { 191 return ui_showerror(CFE_ERR_INV_PARAM,"Invalid phy register number"); 192 } 193 allreg = 0; 194 } 195 196 if (allreg) { 197 printf("** PHY registers on MAC %d PHY %d **\n",mac,phynum); 198 for (idx = 0; idx < 31; idx+=2) { 199 printf("Reg 0x%02X = 0x%04X | ",idx,phy_mii_read(&phy,phynum,idx)); 200 printf("Reg 0x%02X = 0x%04X",idx+1,phy_mii_read(&phy,phynum,idx+1)); 201 printf("\n"); 202 } 203 } 204 else { 205 printf("Reg %02X = %04X\n",reg,phy_mii_read(&phy,phynum,reg)); 206 } 207 208 return 0; 209 210} 211 212 213 214 215/* ********************************************************************* 216 * PHY_MII_SYNC(s) 217 * 218 * Synchronize with the MII - send a pattern of bits to the MII 219 * that will guarantee that it is ready to accept a command. 220 * 221 * Input parameters: 222 * s - sbmac structure 223 * 224 * Return value: 225 * nothing 226 ********************************************************************* */ 227 228static void phy_mii_sync(phy_t *s) 229{ 230 int cnt; 231 uint64_t bits; 232 int mac_mdio_genc; /*genc bit needs to be saved*/ 233 234 mac_mdio_genc = PHY_READCSR(s->sbe_mdio) & M_MAC_GENC; 235 236 bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT; 237 238 PHY_WRITECSR(s->sbe_mdio,bits | mac_mdio_genc); 239 240 for (cnt = 0; cnt < 32; cnt++) { 241 PHY_WRITECSR(s->sbe_mdio,bits | M_MAC_MDC | mac_mdio_genc); 242 cfe_usleep(100); 243 PHY_WRITECSR(s->sbe_mdio,bits | mac_mdio_genc); 244 cfe_usleep(100); 245 } 246 247} 248 249/* ********************************************************************* 250 * PHY_MII_SENDDATA(s,data,bitcnt) 251 * 252 * Send some bits to the MII. The bits to be sent are right- 253 * justified in the 'data' parameter. 254 * 255 * Input parameters: 256 * s - sbmac structure 257 * data - data to send 258 * bitcnt - number of bits to send 259 ********************************************************************* */ 260 261static void phy_mii_senddata(phy_t *s,unsigned int data, int bitcnt) 262{ 263 int i; 264 uint64_t bits; 265 unsigned int curmask; 266 int mac_mdio_genc; 267 268 mac_mdio_genc = PHY_READCSR(s->sbe_mdio) & M_MAC_GENC; 269 270 bits = M_MAC_MDIO_DIR_OUTPUT; 271 PHY_WRITECSR(s->sbe_mdio,bits | mac_mdio_genc); 272 273 curmask = 1 << (bitcnt - 1); 274 275 for (i = 0; i < bitcnt; i++) { 276 if (data & curmask) bits |= M_MAC_MDIO_OUT; 277 else bits &= ~M_MAC_MDIO_OUT; 278 PHY_WRITECSR(s->sbe_mdio,bits | mac_mdio_genc); 279 cfe_usleep(100); 280 PHY_WRITECSR(s->sbe_mdio,bits | M_MAC_MDC | mac_mdio_genc); 281 cfe_usleep(100); 282 PHY_WRITECSR(s->sbe_mdio,bits | mac_mdio_genc); 283 cfe_usleep(100); 284 curmask >>= 1; 285 } 286} 287 288 289 290/* ********************************************************************* 291 * PHY_MII_READ(s,phyaddr,regidx) 292 * 293 * Read a PHY register. 294 * 295 * Input parameters: 296 * s - sbmac structure 297 * phyaddr - PHY's address 298 * regidx = index of register to read 299 * 300 * Return value: 301 * value read, or 0 if an error occured. 302 ********************************************************************* */ 303 304static unsigned int phy_mii_read(phy_t *s,int phyaddr,int regidx) 305{ 306 int idx; 307 int error; 308 int regval; 309 int mac_mdio_genc; 310 311 /* 312 * Synchronize ourselves so that the PHY knows the next 313 * thing coming down is a command 314 */ 315 316 phy_mii_sync(s); 317 318 /* 319 * Send the data to the PHY. The sequence is 320 * a "start" command (2 bits) 321 * a "read" command (2 bits) 322 * the PHY addr (5 bits) 323 * the register index (5 bits) 324 */ 325 326 phy_mii_senddata(s,MII_COMMAND_START, 2); 327 phy_mii_senddata(s,MII_COMMAND_READ, 2); 328 phy_mii_senddata(s,phyaddr, 5); 329 phy_mii_senddata(s,regidx, 5); 330 331 mac_mdio_genc = PHY_READCSR(s->sbe_mdio) & M_MAC_GENC; 332 333 /* 334 * Switch the port around without a clock transition. 335 */ 336 PHY_WRITECSR(s->sbe_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); 337 338 /* 339 * Send out a clock pulse to signal we want the status 340 */ 341 342 PHY_WRITECSR(s->sbe_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc); 343 cfe_usleep(100); 344 PHY_WRITECSR(s->sbe_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); 345 cfe_usleep(100); 346 347 /* 348 * If an error occured, the PHY will signal '1' back 349 */ 350 error = PHY_READCSR(s->sbe_mdio) & M_MAC_MDIO_IN; 351 352 /* 353 * Issue an 'idle' clock pulse, but keep the direction 354 * the same. 355 */ 356 PHY_WRITECSR(s->sbe_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc); 357 cfe_usleep(100); 358 PHY_WRITECSR(s->sbe_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); 359 cfe_usleep(100); 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 cfe_usleep(100); 372 PHY_WRITECSR(s->sbe_mdio,M_MAC_MDIO_DIR_INPUT | mac_mdio_genc); 373 cfe_usleep(100); 374 } 375 376 /* Switch back to output */ 377 PHY_WRITECSR(s->sbe_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc); 378 379 if (error == 0) return regval; 380 return 0; 381} 382 383 384/* ********************************************************************* 385 * PHY_MII_WRITE(s,phyaddr,regidx,regval) 386 * 387 * Write a value to a PHY register. 388 * 389 * Input parameters: 390 * s - sbmac structure 391 * phyaddr - PHY to use 392 * regidx - register within the PHY 393 * regval - data to write to register 394 * 395 * Return value: 396 * nothing 397 ********************************************************************* */ 398 399static void phy_mii_write(phy_t *s,int phyaddr,int regidx, 400 unsigned int regval) 401{ 402 int mac_mdio_genc; 403 404 phy_mii_sync(s); 405 406 phy_mii_senddata(s,MII_COMMAND_START,2); 407 phy_mii_senddata(s,MII_COMMAND_WRITE,2); 408 phy_mii_senddata(s,phyaddr, 5); 409 phy_mii_senddata(s,regidx, 5); 410 phy_mii_senddata(s,MII_COMMAND_ACK,2); 411 phy_mii_senddata(s,regval,16); 412 413 mac_mdio_genc = PHY_READCSR(s->sbe_mdio) & M_MAC_GENC; 414 415 PHY_WRITECSR(s->sbe_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc); 416} 417 418 419 420