1/* SPDX-License-Identifier: GPL-2.0 */ 2/* 3 * Copyright (C) 2018-2022 Marvell International Ltd. 4 * 5 * Interface to the SMI/MDIO hardware, including support for both IEEE 802.3 6 * clause 22 and clause 45 operations. 7 */ 8 9#ifndef __CVMX_MIO_H__ 10#define __CVMX_MIO_H__ 11 12/** 13 * PHY register 0 from the 802.3 spec 14 */ 15#define CVMX_MDIO_PHY_REG_CONTROL 0 16 17typedef union { 18 u16 u16; 19 struct { 20 u16 reset : 1; 21 u16 loopback : 1; 22 u16 speed_lsb : 1; 23 u16 autoneg_enable : 1; 24 u16 power_down : 1; 25 u16 isolate : 1; 26 u16 restart_autoneg : 1; 27 u16 duplex : 1; 28 u16 collision_test : 1; 29 u16 speed_msb : 1; 30 u16 unidirectional_enable : 1; 31 u16 reserved_0_4 : 5; 32 } s; 33} cvmx_mdio_phy_reg_control_t; 34 35/** 36 * PHY register 1 from the 802.3 spec 37 */ 38#define CVMX_MDIO_PHY_REG_STATUS 1 39typedef union { 40 u16 u16; 41 struct { 42 u16 capable_100base_t4 : 1; 43 u16 capable_100base_x_full : 1; 44 u16 capable_100base_x_half : 1; 45 u16 capable_10_full : 1; 46 u16 capable_10_half : 1; 47 u16 capable_100base_t2_full : 1; 48 u16 capable_100base_t2_half : 1; 49 u16 capable_extended_status : 1; 50 u16 capable_unidirectional : 1; 51 u16 capable_mf_preamble_suppression : 1; 52 u16 autoneg_complete : 1; 53 u16 remote_fault : 1; 54 u16 capable_autoneg : 1; 55 u16 link_status : 1; 56 u16 jabber_detect : 1; 57 u16 capable_extended_registers : 1; 58 59 } s; 60} cvmx_mdio_phy_reg_status_t; 61 62/** 63 * PHY register 2 from the 802.3 spec 64 */ 65#define CVMX_MDIO_PHY_REG_ID1 2 66typedef union { 67 u16 u16; 68 struct { 69 u16 oui_bits_3_18; 70 } s; 71} cvmx_mdio_phy_reg_id1_t; 72 73/** 74 * PHY register 3 from the 802.3 spec 75 */ 76#define CVMX_MDIO_PHY_REG_ID2 3 77typedef union { 78 u16 u16; 79 struct { 80 u16 oui_bits_19_24 : 6; 81 u16 model : 6; 82 u16 revision : 4; 83 } s; 84} cvmx_mdio_phy_reg_id2_t; 85 86/** 87 * PHY register 4 from the 802.3 spec 88 */ 89#define CVMX_MDIO_PHY_REG_AUTONEG_ADVER 4 90typedef union { 91 u16 u16; 92 struct { 93 u16 next_page : 1; 94 u16 reserved_14 : 1; 95 u16 remote_fault : 1; 96 u16 reserved_12 : 1; 97 u16 asymmetric_pause : 1; 98 u16 pause : 1; 99 u16 advert_100base_t4 : 1; 100 u16 advert_100base_tx_full : 1; 101 u16 advert_100base_tx_half : 1; 102 u16 advert_10base_tx_full : 1; 103 u16 advert_10base_tx_half : 1; 104 u16 selector : 5; 105 } s; 106} cvmx_mdio_phy_reg_autoneg_adver_t; 107 108/** 109 * PHY register 5 from the 802.3 spec 110 */ 111#define CVMX_MDIO_PHY_REG_LINK_PARTNER_ABILITY 5 112typedef union { 113 u16 u16; 114 struct { 115 u16 next_page : 1; 116 u16 ack : 1; 117 u16 remote_fault : 1; 118 u16 reserved_12 : 1; 119 u16 asymmetric_pause : 1; 120 u16 pause : 1; 121 u16 advert_100base_t4 : 1; 122 u16 advert_100base_tx_full : 1; 123 u16 advert_100base_tx_half : 1; 124 u16 advert_10base_tx_full : 1; 125 u16 advert_10base_tx_half : 1; 126 u16 selector : 5; 127 } s; 128} cvmx_mdio_phy_reg_link_partner_ability_t; 129 130/** 131 * PHY register 6 from the 802.3 spec 132 */ 133#define CVMX_MDIO_PHY_REG_AUTONEG_EXPANSION 6 134typedef union { 135 u16 u16; 136 struct { 137 u16 reserved_5_15 : 11; 138 u16 parallel_detection_fault : 1; 139 u16 link_partner_next_page_capable : 1; 140 u16 local_next_page_capable : 1; 141 u16 page_received : 1; 142 u16 link_partner_autoneg_capable : 1; 143 144 } s; 145} cvmx_mdio_phy_reg_autoneg_expansion_t; 146 147/** 148 * PHY register 9 from the 802.3 spec 149 */ 150#define CVMX_MDIO_PHY_REG_CONTROL_1000 9 151typedef union { 152 u16 u16; 153 struct { 154 u16 test_mode : 3; 155 u16 manual_master_slave : 1; 156 u16 master : 1; 157 u16 port_type : 1; 158 u16 advert_1000base_t_full : 1; 159 u16 advert_1000base_t_half : 1; 160 u16 reserved_0_7 : 8; 161 } s; 162} cvmx_mdio_phy_reg_control_1000_t; 163 164/** 165 * PHY register 10 from the 802.3 spec 166 */ 167#define CVMX_MDIO_PHY_REG_STATUS_1000 10 168typedef union { 169 u16 u16; 170 struct { 171 u16 master_slave_fault : 1; 172 u16 is_master : 1; 173 u16 local_receiver_ok : 1; 174 u16 remote_receiver_ok : 1; 175 u16 remote_capable_1000base_t_full : 1; 176 u16 remote_capable_1000base_t_half : 1; 177 u16 reserved_8_9 : 2; 178 u16 idle_error_count : 8; 179 } s; 180} cvmx_mdio_phy_reg_status_1000_t; 181 182/** 183 * PHY register 15 from the 802.3 spec 184 */ 185#define CVMX_MDIO_PHY_REG_EXTENDED_STATUS 15 186typedef union { 187 u16 u16; 188 struct { 189 u16 capable_1000base_x_full : 1; 190 u16 capable_1000base_x_half : 1; 191 u16 capable_1000base_t_full : 1; 192 u16 capable_1000base_t_half : 1; 193 u16 reserved_0_11 : 12; 194 } s; 195} cvmx_mdio_phy_reg_extended_status_t; 196 197/** 198 * PHY register 13 from the 802.3 spec 199 */ 200#define CVMX_MDIO_PHY_REG_MMD_CONTROL 13 201typedef union { 202 u16 u16; 203 struct { 204 u16 function : 2; 205 u16 reserved_5_13 : 9; 206 u16 devad : 5; 207 } s; 208} cvmx_mdio_phy_reg_mmd_control_t; 209 210/** 211 * PHY register 14 from the 802.3 spec 212 */ 213#define CVMX_MDIO_PHY_REG_MMD_ADDRESS_DATA 14 214typedef union { 215 u16 u16; 216 struct { 217 u16 address_data : 16; 218 } s; 219} cvmx_mdio_phy_reg_mmd_address_data_t; 220 221/* Operating request encodings. */ 222#define MDIO_CLAUSE_22_WRITE 0 223#define MDIO_CLAUSE_22_READ 1 224 225#define MDIO_CLAUSE_45_ADDRESS 0 226#define MDIO_CLAUSE_45_WRITE 1 227#define MDIO_CLAUSE_45_READ_INC 2 228#define MDIO_CLAUSE_45_READ 3 229 230/* MMD identifiers, mostly for accessing devices within XENPAK modules. */ 231#define CVMX_MMD_DEVICE_PMA_PMD 1 232#define CVMX_MMD_DEVICE_WIS 2 233#define CVMX_MMD_DEVICE_PCS 3 234#define CVMX_MMD_DEVICE_PHY_XS 4 235#define CVMX_MMD_DEVICE_DTS_XS 5 236#define CVMX_MMD_DEVICE_TC 6 237#define CVMX_MMD_DEVICE_CL22_EXT 29 238#define CVMX_MMD_DEVICE_VENDOR_1 30 239#define CVMX_MMD_DEVICE_VENDOR_2 31 240 241#define CVMX_MDIO_TIMEOUT 100000 /* 100 millisec */ 242 243static inline int cvmx_mdio_bus_id_to_node(int bus_id) 244{ 245 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) 246 return (bus_id >> 2) & CVMX_NODE_MASK; 247 else 248 return 0; 249} 250 251static inline int cvmx_mdio_bus_id_to_bus(int bus_id) 252{ 253 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) 254 return bus_id & 3; 255 else 256 return bus_id; 257} 258 259/* Helper function to put MDIO interface into clause 45 mode */ 260static inline void __cvmx_mdio_set_clause45_mode(int bus_id) 261{ 262 cvmx_smix_clk_t smi_clk; 263 int node = cvmx_mdio_bus_id_to_node(bus_id); 264 int bus = cvmx_mdio_bus_id_to_bus(bus_id); 265 266 /* Put bus into clause 45 mode */ 267 smi_clk.u64 = csr_rd_node(node, CVMX_SMIX_CLK(bus)); 268 smi_clk.s.mode = 1; 269 smi_clk.s.preamble = 1; 270 csr_wr_node(node, CVMX_SMIX_CLK(bus), smi_clk.u64); 271} 272 273/* Helper function to put MDIO interface into clause 22 mode */ 274static inline void __cvmx_mdio_set_clause22_mode(int bus_id) 275{ 276 cvmx_smix_clk_t smi_clk; 277 int node = cvmx_mdio_bus_id_to_node(bus_id); 278 int bus = cvmx_mdio_bus_id_to_bus(bus_id); 279 280 /* Put bus into clause 22 mode */ 281 smi_clk.u64 = csr_rd_node(node, CVMX_SMIX_CLK(bus)); 282 smi_clk.s.mode = 0; 283 csr_wr_node(node, CVMX_SMIX_CLK(bus), smi_clk.u64); 284} 285 286/** 287 * @INTERNAL 288 * Function to read SMIX_RD_DAT and check for timeouts. This 289 * code sequence is done fairly often, so put in one spot. 290 * 291 * @param bus_id SMI/MDIO bus to read 292 * 293 * @return Value of SMIX_RD_DAT. pending will be set on 294 * a timeout. 295 */ 296static inline cvmx_smix_rd_dat_t __cvmx_mdio_read_rd_dat(int bus_id) 297{ 298 cvmx_smix_rd_dat_t smi_rd; 299 int node = cvmx_mdio_bus_id_to_node(bus_id); 300 int bus = cvmx_mdio_bus_id_to_bus(bus_id); 301 u64 done; 302 303 done = get_timer(0); 304 305 do { 306 mdelay(1); 307 smi_rd.u64 = csr_rd_node(node, CVMX_SMIX_RD_DAT(bus)); 308 if (get_timer(done) > (CVMX_MDIO_TIMEOUT / 1000)) 309 break; 310 } while (smi_rd.s.pending); 311 312 return smi_rd; 313} 314 315/** 316 * Perform an MII read. This function is used to read PHY 317 * registers controlling auto negotiation. 318 * 319 * @param bus_id MDIO bus number. Zero on most chips, but some chips (ex CN56XX) 320 * support multiple busses. 321 * @param phy_id The MII phy id 322 * @param location Register location to read 323 * 324 * @return Result from the read or -1 on failure 325 */ 326static inline int cvmx_mdio_read(int bus_id, int phy_id, int location) 327{ 328 int node = cvmx_mdio_bus_id_to_node(bus_id); 329 int bus = cvmx_mdio_bus_id_to_bus(bus_id); 330 cvmx_smix_cmd_t smi_cmd; 331 cvmx_smix_rd_dat_t smi_rd; 332 333 if (octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) 334 __cvmx_mdio_set_clause22_mode(bus_id); 335 336 smi_cmd.u64 = 0; 337 smi_cmd.s.phy_op = MDIO_CLAUSE_22_READ; 338 smi_cmd.s.phy_adr = phy_id; 339 smi_cmd.s.reg_adr = location; 340 csr_wr_node(node, CVMX_SMIX_CMD(bus), smi_cmd.u64); 341 342 smi_rd = __cvmx_mdio_read_rd_dat(bus_id); 343 if (smi_rd.s.val) 344 return smi_rd.s.dat; 345 else 346 return -1; 347} 348 349/** 350 * Perform an MII write. This function is used to write PHY 351 * registers controlling auto negotiation. 352 * 353 * @param bus_id MDIO bus number. Zero on most chips, but some chips (ex CN56XX) 354 * support multiple busses. 355 * @param phy_id The MII phy id 356 * @param location Register location to write 357 * @param val Value to write 358 * 359 * @return -1 on error 360 * 0 on success 361 */ 362static inline int cvmx_mdio_write(int bus_id, int phy_id, int location, int val) 363{ 364 int node = cvmx_mdio_bus_id_to_node(bus_id); 365 int bus = cvmx_mdio_bus_id_to_bus(bus_id); 366 cvmx_smix_cmd_t smi_cmd; 367 cvmx_smix_wr_dat_t smi_wr; 368 369 if (octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) 370 __cvmx_mdio_set_clause22_mode(bus_id); 371 372 smi_wr.u64 = 0; 373 smi_wr.s.dat = val; 374 csr_wr_node(node, CVMX_SMIX_WR_DAT(bus), smi_wr.u64); 375 376 smi_cmd.u64 = 0; 377 smi_cmd.s.phy_op = MDIO_CLAUSE_22_WRITE; 378 smi_cmd.s.phy_adr = phy_id; 379 smi_cmd.s.reg_adr = location; 380 csr_wr_node(node, CVMX_SMIX_CMD(bus), smi_cmd.u64); 381 382 if (CVMX_WAIT_FOR_FIELD64_NODE(node, CVMX_SMIX_WR_DAT(bus), 383 cvmx_smix_wr_dat_t, pending, ==, 0, 384 CVMX_MDIO_TIMEOUT)) 385 return -1; 386 387 return 0; 388} 389 390/** 391 * Perform an IEEE 802.3 clause 45 MII read. This function is used to read PHY 392 * registers controlling auto negotiation. 393 * 394 * @param bus_id MDIO bus number. Zero on most chips, but some chips (ex CN56XX) 395 * support multiple busses. 396 * @param phy_id The MII phy id 397 * @param device MDIO Manageable Device (MMD) id 398 * @param location Register location to read 399 * 400 * @return Result from the read or -1 on failure 401 */ 402 403static inline int cvmx_mdio_45_read(int bus_id, int phy_id, int device, 404 int location) 405{ 406 cvmx_smix_cmd_t smi_cmd; 407 cvmx_smix_rd_dat_t smi_rd; 408 cvmx_smix_wr_dat_t smi_wr; 409 int node = cvmx_mdio_bus_id_to_node(bus_id); 410 int bus = cvmx_mdio_bus_id_to_bus(bus_id); 411 412 if (!octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) 413 return -1; 414 415 __cvmx_mdio_set_clause45_mode(bus_id); 416 417 smi_wr.u64 = 0; 418 smi_wr.s.dat = location; 419 csr_wr_node(node, CVMX_SMIX_WR_DAT(bus), smi_wr.u64); 420 421 smi_cmd.u64 = 0; 422 smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS; 423 smi_cmd.s.phy_adr = phy_id; 424 smi_cmd.s.reg_adr = device; 425 csr_wr_node(node, CVMX_SMIX_CMD(bus), smi_cmd.u64); 426 427 if (CVMX_WAIT_FOR_FIELD64_NODE(node, CVMX_SMIX_WR_DAT(bus), 428 cvmx_smix_wr_dat_t, pending, ==, 0, 429 CVMX_MDIO_TIMEOUT)) { 430 debug("cvmx_mdio_45_read: bus_id %d phy_id %2d device %2d register %2d TIME OUT(address)\n", 431 bus_id, phy_id, device, location); 432 return -1; 433 } 434 435 smi_cmd.u64 = 0; 436 smi_cmd.s.phy_op = MDIO_CLAUSE_45_READ; 437 smi_cmd.s.phy_adr = phy_id; 438 smi_cmd.s.reg_adr = device; 439 csr_wr_node(node, CVMX_SMIX_CMD(bus), smi_cmd.u64); 440 441 smi_rd = __cvmx_mdio_read_rd_dat(bus_id); 442 if (smi_rd.s.pending) { 443 debug("cvmx_mdio_45_read: bus_id %d phy_id %2d device %2d register %2d TIME OUT(data)\n", 444 bus_id, phy_id, device, location); 445 return -1; 446 } 447 448 if (smi_rd.s.val) 449 return smi_rd.s.dat; 450 451 debug("cvmx_mdio_45_read: bus_id %d phy_id %2d device %2d register %2d INVALID READ\n", 452 bus_id, phy_id, device, location); 453 return -1; 454} 455 456/** 457 * Perform an IEEE 802.3 clause 45 MII write. This function is used to write PHY 458 * registers controlling auto negotiation. 459 * 460 * @param bus_id MDIO bus number. Zero on most chips, but some chips (ex CN56XX) 461 * support multiple busses. 462 * @param phy_id The MII phy id 463 * @param device MDIO Manageable Device (MMD) id 464 * @param location Register location to write 465 * @param val Value to write 466 * 467 * @return -1 on error 468 * 0 on success 469 */ 470static inline int cvmx_mdio_45_write(int bus_id, int phy_id, int device, 471 int location, int val) 472{ 473 cvmx_smix_cmd_t smi_cmd; 474 cvmx_smix_wr_dat_t smi_wr; 475 int node = cvmx_mdio_bus_id_to_node(bus_id); 476 int bus = cvmx_mdio_bus_id_to_bus(bus_id); 477 478 if (!octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) 479 return -1; 480 481 __cvmx_mdio_set_clause45_mode(bus_id); 482 483 smi_wr.u64 = 0; 484 smi_wr.s.dat = location; 485 csr_wr_node(node, CVMX_SMIX_WR_DAT(bus), smi_wr.u64); 486 487 smi_cmd.u64 = 0; 488 smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS; 489 smi_cmd.s.phy_adr = phy_id; 490 smi_cmd.s.reg_adr = device; 491 csr_wr_node(node, CVMX_SMIX_CMD(bus), smi_cmd.u64); 492 493 if (CVMX_WAIT_FOR_FIELD64_NODE(node, CVMX_SMIX_WR_DAT(bus), 494 cvmx_smix_wr_dat_t, pending, ==, 0, 495 CVMX_MDIO_TIMEOUT)) 496 return -1; 497 498 smi_wr.u64 = 0; 499 smi_wr.s.dat = val; 500 csr_wr_node(node, CVMX_SMIX_WR_DAT(bus), smi_wr.u64); 501 502 smi_cmd.u64 = 0; 503 smi_cmd.s.phy_op = MDIO_CLAUSE_45_WRITE; 504 smi_cmd.s.phy_adr = phy_id; 505 smi_cmd.s.reg_adr = device; 506 csr_wr_node(node, CVMX_SMIX_CMD(bus), smi_cmd.u64); 507 508 if (CVMX_WAIT_FOR_FIELD64_NODE(node, CVMX_SMIX_WR_DAT(bus), 509 cvmx_smix_wr_dat_t, pending, ==, 0, 510 CVMX_MDIO_TIMEOUT)) 511 return -1; 512 513 return 0; 514} 515 516#endif 517