1/***********************license start*************** 2 * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights 3 * reserved. 4 * 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 18 * * Neither the name of Cavium Inc. nor the names of 19 * its contributors may be used to endorse or promote products 20 * derived from this software without specific prior written 21 * permission. 22 23 * This Software, including technical data, may be subject to U.S. export control 24 * laws, including the U.S. Export Administration Act and its associated 25 * regulations, and may be subject to export or import regulations in other 26 * countries. 27 28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38 ***********************license end**************************************/ 39 40 41 42 43 44 45 46/** 47 * @file 48 * 49 * Interface to the SMI/MDIO hardware, including support for both IEEE 802.3 50 * clause 22 and clause 45 operations. 51 * 52 * <hr>$Revision: 70030 $<hr> 53 */ 54 55#ifndef __CVMX_MIO_H__ 56#define __CVMX_MIO_H__ 57 58#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 59#include <asm/octeon/octeon.h> 60#include <asm/octeon/cvmx-clock.h> 61#else 62#include "cvmx-clock.h" 63#endif 64 65#ifdef __cplusplus 66extern "C" { 67#endif 68 69/** 70 * PHY register 0 from the 802.3 spec 71 */ 72#define CVMX_MDIO_PHY_REG_CONTROL 0 73typedef union 74{ 75 uint16_t u16; 76 struct 77 { 78 uint16_t reset : 1; 79 uint16_t loopback : 1; 80 uint16_t speed_lsb : 1; 81 uint16_t autoneg_enable : 1; 82 uint16_t power_down : 1; 83 uint16_t isolate : 1; 84 uint16_t restart_autoneg : 1; 85 uint16_t duplex : 1; 86 uint16_t collision_test : 1; 87 uint16_t speed_msb : 1; 88 uint16_t unidirectional_enable : 1; 89 uint16_t reserved_0_4 : 5; 90 } s; 91} cvmx_mdio_phy_reg_control_t; 92 93/** 94 * PHY register 1 from the 802.3 spec 95 */ 96#define CVMX_MDIO_PHY_REG_STATUS 1 97typedef union 98{ 99 uint16_t u16; 100 struct 101 { 102 uint16_t capable_100base_t4 : 1; 103 uint16_t capable_100base_x_full : 1; 104 uint16_t capable_100base_x_half : 1; 105 uint16_t capable_10_full : 1; 106 uint16_t capable_10_half : 1; 107 uint16_t capable_100base_t2_full : 1; 108 uint16_t capable_100base_t2_half : 1; 109 uint16_t capable_extended_status : 1; 110 uint16_t capable_unidirectional : 1; 111 uint16_t capable_mf_preamble_suppression : 1; 112 uint16_t autoneg_complete : 1; 113 uint16_t remote_fault : 1; 114 uint16_t capable_autoneg : 1; 115 uint16_t link_status : 1; 116 uint16_t jabber_detect : 1; 117 uint16_t capable_extended_registers : 1; 118 119 } s; 120} cvmx_mdio_phy_reg_status_t; 121 122/** 123 * PHY register 2 from the 802.3 spec 124 */ 125#define CVMX_MDIO_PHY_REG_ID1 2 126typedef union 127{ 128 uint16_t u16; 129 struct 130 { 131 uint16_t oui_bits_3_18; 132 } s; 133} cvmx_mdio_phy_reg_id1_t; 134 135/** 136 * PHY register 3 from the 802.3 spec 137 */ 138#define CVMX_MDIO_PHY_REG_ID2 3 139typedef union 140{ 141 uint16_t u16; 142 struct 143 { 144 uint16_t oui_bits_19_24 : 6; 145 uint16_t model : 6; 146 uint16_t revision : 4; 147 } s; 148} cvmx_mdio_phy_reg_id2_t; 149 150/** 151 * PHY register 4 from the 802.3 spec 152 */ 153#define CVMX_MDIO_PHY_REG_AUTONEG_ADVER 4 154typedef union 155{ 156 uint16_t u16; 157 struct 158 { 159 uint16_t next_page : 1; 160 uint16_t reserved_14 : 1; 161 uint16_t remote_fault : 1; 162 uint16_t reserved_12 : 1; 163 uint16_t asymmetric_pause : 1; 164 uint16_t pause : 1; 165 uint16_t advert_100base_t4 : 1; 166 uint16_t advert_100base_tx_full : 1; 167 uint16_t advert_100base_tx_half : 1; 168 uint16_t advert_10base_tx_full : 1; 169 uint16_t advert_10base_tx_half : 1; 170 uint16_t selector : 5; 171 } s; 172} cvmx_mdio_phy_reg_autoneg_adver_t; 173 174/** 175 * PHY register 5 from the 802.3 spec 176 */ 177#define CVMX_MDIO_PHY_REG_LINK_PARTNER_ABILITY 5 178typedef union 179{ 180 uint16_t u16; 181 struct 182 { 183 uint16_t next_page : 1; 184 uint16_t ack : 1; 185 uint16_t remote_fault : 1; 186 uint16_t reserved_12 : 1; 187 uint16_t asymmetric_pause : 1; 188 uint16_t pause : 1; 189 uint16_t advert_100base_t4 : 1; 190 uint16_t advert_100base_tx_full : 1; 191 uint16_t advert_100base_tx_half : 1; 192 uint16_t advert_10base_tx_full : 1; 193 uint16_t advert_10base_tx_half : 1; 194 uint16_t selector : 5; 195 } s; 196} cvmx_mdio_phy_reg_link_partner_ability_t; 197 198/** 199 * PHY register 6 from the 802.3 spec 200 */ 201#define CVMX_MDIO_PHY_REG_AUTONEG_EXPANSION 6 202typedef union 203{ 204 uint16_t u16; 205 struct 206 { 207 uint16_t reserved_5_15 : 11; 208 uint16_t parallel_detection_fault : 1; 209 uint16_t link_partner_next_page_capable : 1; 210 uint16_t local_next_page_capable : 1; 211 uint16_t page_received : 1; 212 uint16_t link_partner_autoneg_capable : 1; 213 214 } s; 215} cvmx_mdio_phy_reg_autoneg_expansion_t; 216 217/** 218 * PHY register 9 from the 802.3 spec 219 */ 220#define CVMX_MDIO_PHY_REG_CONTROL_1000 9 221typedef union 222{ 223 uint16_t u16; 224 struct 225 { 226 uint16_t test_mode : 3; 227 uint16_t manual_master_slave : 1; 228 uint16_t master : 1; 229 uint16_t port_type : 1; 230 uint16_t advert_1000base_t_full : 1; 231 uint16_t advert_1000base_t_half : 1; 232 uint16_t reserved_0_7 : 8; 233 } s; 234} cvmx_mdio_phy_reg_control_1000_t; 235 236/** 237 * PHY register 10 from the 802.3 spec 238 */ 239#define CVMX_MDIO_PHY_REG_STATUS_1000 10 240typedef union 241{ 242 uint16_t u16; 243 struct 244 { 245 uint16_t master_slave_fault : 1; 246 uint16_t is_master : 1; 247 uint16_t local_receiver_ok : 1; 248 uint16_t remote_receiver_ok : 1; 249 uint16_t remote_capable_1000base_t_full : 1; 250 uint16_t remote_capable_1000base_t_half : 1; 251 uint16_t reserved_8_9 : 2; 252 uint16_t idle_error_count : 8; 253 } s; 254} cvmx_mdio_phy_reg_status_1000_t; 255 256/** 257 * PHY register 15 from the 802.3 spec 258 */ 259#define CVMX_MDIO_PHY_REG_EXTENDED_STATUS 15 260typedef union 261{ 262 uint16_t u16; 263 struct 264 { 265 uint16_t capable_1000base_x_full : 1; 266 uint16_t capable_1000base_x_half : 1; 267 uint16_t capable_1000base_t_full : 1; 268 uint16_t capable_1000base_t_half : 1; 269 uint16_t reserved_0_11 : 12; 270 } s; 271} cvmx_mdio_phy_reg_extended_status_t; 272 273 274/** 275 * PHY register 13 from the 802.3 spec 276 */ 277#define CVMX_MDIO_PHY_REG_MMD_CONTROL 13 278typedef union 279{ 280 uint16_t u16; 281 struct 282 { 283 uint16_t function : 2; 284 uint16_t reserved_5_13 : 9; 285 uint16_t devad : 5; 286 } s; 287} cvmx_mdio_phy_reg_mmd_control_t; 288 289/** 290 * PHY register 14 from the 802.3 spec 291 */ 292#define CVMX_MDIO_PHY_REG_MMD_ADDRESS_DATA 14 293typedef union 294{ 295 uint16_t u16; 296 struct 297 { 298 uint16_t address_data : 16; 299 } s; 300} cvmx_mdio_phy_reg_mmd_address_data_t; 301 302/* Operating request encodings. */ 303#define MDIO_CLAUSE_22_WRITE 0 304#define MDIO_CLAUSE_22_READ 1 305 306#define MDIO_CLAUSE_45_ADDRESS 0 307#define MDIO_CLAUSE_45_WRITE 1 308#define MDIO_CLAUSE_45_READ_INC 2 309#define MDIO_CLAUSE_45_READ 3 310 311/* MMD identifiers, mostly for accessing devices within XENPAK modules. */ 312#define CVMX_MMD_DEVICE_PMA_PMD 1 313#define CVMX_MMD_DEVICE_WIS 2 314#define CVMX_MMD_DEVICE_PCS 3 315#define CVMX_MMD_DEVICE_PHY_XS 4 316#define CVMX_MMD_DEVICE_DTS_XS 5 317#define CVMX_MMD_DEVICE_TC 6 318#define CVMX_MMD_DEVICE_CL22_EXT 29 319#define CVMX_MMD_DEVICE_VENDOR_1 30 320#define CVMX_MMD_DEVICE_VENDOR_2 31 321 322#define CVMX_MDIO_TIMEOUT 100000 /* 100 millisec */ 323 324/* Helper function to put MDIO interface into clause 45 mode */ 325static inline void __cvmx_mdio_set_clause45_mode(int bus_id) 326{ 327 cvmx_smix_clk_t smi_clk; 328 /* Put bus into clause 45 mode */ 329 smi_clk.u64 = cvmx_read_csr(CVMX_SMIX_CLK(bus_id)); 330 smi_clk.s.mode = 1; 331 smi_clk.s.preamble = 1; 332 cvmx_write_csr(CVMX_SMIX_CLK(bus_id), smi_clk.u64); 333} 334/* Helper function to put MDIO interface into clause 22 mode */ 335static inline void __cvmx_mdio_set_clause22_mode(int bus_id) 336{ 337 cvmx_smix_clk_t smi_clk; 338 /* Put bus into clause 22 mode */ 339 smi_clk.u64 = cvmx_read_csr(CVMX_SMIX_CLK(bus_id)); 340 smi_clk.s.mode = 0; 341 cvmx_write_csr(CVMX_SMIX_CLK(bus_id), smi_clk.u64); 342} 343 344/** 345 * @INTERNAL 346 * Function to read SMIX_RD_DAT and check for timeouts. This 347 * code sequence is done fairly often, so put in in one spot. 348 * 349 * @param bus_id SMI/MDIO bus to read 350 * 351 * @return Value of SMIX_RD_DAT. pending will be set on 352 * a timeout. 353 */ 354static inline cvmx_smix_rd_dat_t __cvmx_mdio_read_rd_dat(int bus_id) 355{ 356 cvmx_smix_rd_dat_t smi_rd; 357 uint64_t done = cvmx_get_cycle() + (uint64_t)CVMX_MDIO_TIMEOUT * 358 cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 1000000; 359 do 360 { 361 cvmx_wait(1000); 362 smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(bus_id)); 363 } while (smi_rd.s.pending && (cvmx_get_cycle() < done)); 364 return smi_rd; 365} 366 367 368/** 369 * Perform an MII read. This function is used to read PHY 370 * registers controlling auto negotiation. 371 * 372 * @param bus_id MDIO bus number. Zero on most chips, but some chips (ex CN56XX) 373 * support multiple busses. 374 * @param phy_id The MII phy id 375 * @param location Register location to read 376 * 377 * @return Result from the read or -1 on failure 378 */ 379static inline int cvmx_mdio_read(int bus_id, int phy_id, int location) 380{ 381#if defined(CVMX_BUILD_FOR_LINUX_KERNEL) && defined(CONFIG_PHYLIB) 382 struct mii_bus *bus; 383 int rv; 384 385 BUG_ON(bus_id > 3 || bus_id < 0); 386 387 bus = octeon_mdiobuses[bus_id]; 388 if (bus == NULL) 389 return -1; 390 391 rv = mdiobus_read(bus, phy_id, location); 392 393 if (rv < 0) 394 return -1; 395 return rv; 396#else 397 cvmx_smix_cmd_t smi_cmd; 398 cvmx_smix_rd_dat_t smi_rd; 399 400 if (octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) 401 __cvmx_mdio_set_clause22_mode(bus_id); 402 403 smi_cmd.u64 = 0; 404 smi_cmd.s.phy_op = MDIO_CLAUSE_22_READ; 405 smi_cmd.s.phy_adr = phy_id; 406 smi_cmd.s.reg_adr = location; 407 cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); 408 409 smi_rd = __cvmx_mdio_read_rd_dat(bus_id); 410 if (smi_rd.s.val) 411 return smi_rd.s.dat; 412 else 413 return -1; 414#endif 415} 416 417 418/** 419 * Perform an MII write. This function is used to write PHY 420 * registers controlling auto negotiation. 421 * 422 * @param bus_id MDIO bus number. Zero on most chips, but some chips (ex CN56XX) 423 * support multiple busses. 424 * @param phy_id The MII phy id 425 * @param location Register location to write 426 * @param val Value to write 427 * 428 * @return -1 on error 429 * 0 on success 430 */ 431static inline int cvmx_mdio_write(int bus_id, int phy_id, int location, int val) 432{ 433#if defined(CVMX_BUILD_FOR_LINUX_KERNEL) && defined(CONFIG_PHYLIB) 434 struct mii_bus *bus; 435 int rv; 436 437 BUG_ON(bus_id > 3 || bus_id < 0); 438 439 bus = octeon_mdiobuses[bus_id]; 440 if (bus == NULL) 441 return -1; 442 443 rv = mdiobus_write(bus, phy_id, location, (u16)val); 444 445 if (rv < 0) 446 return -1; 447 return 0; 448#else 449 cvmx_smix_cmd_t smi_cmd; 450 cvmx_smix_wr_dat_t smi_wr; 451 452 if (octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) 453 __cvmx_mdio_set_clause22_mode(bus_id); 454 455 smi_wr.u64 = 0; 456 smi_wr.s.dat = val; 457 cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64); 458 459 smi_cmd.u64 = 0; 460 smi_cmd.s.phy_op = MDIO_CLAUSE_22_WRITE; 461 smi_cmd.s.phy_adr = phy_id; 462 smi_cmd.s.reg_adr = location; 463 cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); 464 465 if (CVMX_WAIT_FOR_FIELD64(CVMX_SMIX_WR_DAT(bus_id), 466 cvmx_smix_wr_dat_t, pending, ==, 0, CVMX_MDIO_TIMEOUT)) 467 return -1; 468 469 return 0; 470#endif 471} 472 473#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 474/** 475 * Perform an IEEE 802.3 clause 45 MII read. This function is used to read PHY 476 * registers controlling auto negotiation. 477 * 478 * @param bus_id MDIO bus number. Zero on most chips, but some chips (ex CN56XX) 479 * support multiple busses. 480 * @param phy_id The MII phy id 481 * @param device MDIO Managable Device (MMD) id 482 * @param location Register location to read 483 * 484 * @return Result from the read or -1 on failure 485 */ 486 487static inline int cvmx_mdio_45_read(int bus_id, int phy_id, int device, int location) 488{ 489 cvmx_smix_cmd_t smi_cmd; 490 cvmx_smix_rd_dat_t smi_rd; 491 cvmx_smix_wr_dat_t smi_wr; 492 493 if (!octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) 494 return -1; 495 496 __cvmx_mdio_set_clause45_mode(bus_id); 497 498 smi_wr.u64 = 0; 499 smi_wr.s.dat = location; 500 cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64); 501 502 smi_cmd.u64 = 0; 503 smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS; 504 smi_cmd.s.phy_adr = phy_id; 505 smi_cmd.s.reg_adr = device; 506 cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); 507 508 if (CVMX_WAIT_FOR_FIELD64(CVMX_SMIX_WR_DAT(bus_id), 509 cvmx_smix_wr_dat_t, pending, ==, 0, CVMX_MDIO_TIMEOUT)) 510 { 511 cvmx_dprintf ("cvmx_mdio_45_read: bus_id %d phy_id %2d device %2d register %2d TIME OUT(address)\n", bus_id, phy_id, device, location); 512 return -1; 513 } 514 515 smi_cmd.u64 = 0; 516 smi_cmd.s.phy_op = MDIO_CLAUSE_45_READ; 517 smi_cmd.s.phy_adr = phy_id; 518 smi_cmd.s.reg_adr = device; 519 cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); 520 521 smi_rd = __cvmx_mdio_read_rd_dat(bus_id); 522 if (smi_rd.s.pending) 523 { 524 cvmx_dprintf ("cvmx_mdio_45_read: bus_id %d phy_id %2d device %2d register %2d TIME OUT(data)\n", bus_id, phy_id, device, location); 525 return -1; 526 } 527 528 if (smi_rd.s.val) 529 return smi_rd.s.dat; 530 else 531 { 532 cvmx_dprintf ("cvmx_mdio_45_read: bus_id %d phy_id %2d device %2d register %2d INVALID READ\n", bus_id, phy_id, device, location); 533 return -1; 534 } 535} 536 537/** 538 * Perform an IEEE 802.3 clause 45 MII write. This function is used to write PHY 539 * registers controlling auto negotiation. 540 * 541 * @param bus_id MDIO bus number. Zero on most chips, but some chips (ex CN56XX) 542 * support multiple busses. 543 * @param phy_id The MII phy id 544 * @param device MDIO Managable Device (MMD) id 545 * @param location Register location to write 546 * @param val Value to write 547 * 548 * @return -1 on error 549 * 0 on success 550 */ 551static inline int cvmx_mdio_45_write(int bus_id, int phy_id, int device, int location, 552 int val) 553{ 554 cvmx_smix_cmd_t smi_cmd; 555 cvmx_smix_wr_dat_t smi_wr; 556 557 if (!octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) 558 return -1; 559 560 __cvmx_mdio_set_clause45_mode(bus_id); 561 562 smi_wr.u64 = 0; 563 smi_wr.s.dat = location; 564 cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64); 565 566 smi_cmd.u64 = 0; 567 smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS; 568 smi_cmd.s.phy_adr = phy_id; 569 smi_cmd.s.reg_adr = device; 570 cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); 571 572 if (CVMX_WAIT_FOR_FIELD64(CVMX_SMIX_WR_DAT(bus_id), 573 cvmx_smix_wr_dat_t, pending, ==, 0, CVMX_MDIO_TIMEOUT)) 574 return -1; 575 576 smi_wr.u64 = 0; 577 smi_wr.s.dat = val; 578 cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64); 579 580 smi_cmd.u64 = 0; 581 smi_cmd.s.phy_op = MDIO_CLAUSE_45_WRITE; 582 smi_cmd.s.phy_adr = phy_id; 583 smi_cmd.s.reg_adr = device; 584 cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); 585 586 if (CVMX_WAIT_FOR_FIELD64(CVMX_SMIX_WR_DAT(bus_id), 587 cvmx_smix_wr_dat_t, pending, ==, 0, CVMX_MDIO_TIMEOUT)) 588 return -1; 589 590 return 0; 591} 592#endif 593 594#ifdef __cplusplus 595} 596#endif 597 598#endif 599 600