esp_eth_phy_lan8720.c
1 // Copyright 2019 Espressif Systems (Shanghai) PTE LTD 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 #include <string.h> 15 #include <stdlib.h> 16 #include <sys/cdefs.h> 17 #include "esp_log.h" 18 #include "esp_eth.h" 19 #include "eth_phy_regs_struct.h" 20 #include "freertos/FreeRTOS.h" 21 #include "freertos/task.h" 22 #include "driver/gpio.h" 23 #include "esp_rom_gpio.h" 24 #include "esp_rom_sys.h" 25 26 static const char *TAG = "lan8720"; 27 #define PHY_CHECK(a, str, goto_tag, ...) \ 28 do \ 29 { \ 30 if (!(a)) \ 31 { \ 32 ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ 33 goto goto_tag; \ 34 } \ 35 } while (0) 36 37 /***************Vendor Specific Register***************/ 38 39 /** 40 * @brief MCSR(Mode Control Status Register) 41 * 42 */ 43 typedef union { 44 struct { 45 uint32_t reserved1 : 1; /* Reserved */ 46 uint32_t energy_is_on : 1; /* Energy is On */ 47 uint32_t reserved2 : 4; /* Reserved */ 48 uint32_t en_alternate_interrupt : 1; /* Enable Alternate Interrupt Mode */ 49 uint32_t reserved3 : 2; /* Reserved */ 50 uint32_t en_far_loopback : 1; /* Enable Far Loopback Mode */ 51 uint32_t reserved4 : 3; /* Reserved */ 52 uint32_t en_energy_detect_powerdown : 1; /* Enable Energy Detect Power Down */ 53 uint32_t reserved5 : 2; /* Reserved */ 54 }; 55 uint32_t val; 56 } mcsr_reg_t; 57 #define ETH_PHY_MCSR_REG_ADDR (0x11) 58 59 /** 60 * @brief SMR(Special Modes Register) 61 * 62 */ 63 typedef union { 64 struct { 65 uint32_t phy_addr : 5; /* PHY Address */ 66 uint32_t mode : 3; /* Transceiver Mode of Operation */ 67 uint32_t reserved : 8; /* Reserved */ 68 }; 69 uint32_t val; 70 } smr_reg_t; 71 #define ETH_PHY_SMR_REG_ADDR (0x12) 72 73 /** 74 * @brief SECR(Symbol Error Counter Register) 75 * 76 */ 77 typedef union { 78 struct { 79 uint32_t symbol_err_count : 16; /* Symbol Error Counter */ 80 }; 81 uint32_t val; 82 } secr_reg_t; 83 #define EHT_PHY_SECR_REG_ADDR (0x1A) 84 85 /** 86 * @brief CSIR(Control Status Indications Register) 87 * 88 */ 89 typedef union { 90 struct { 91 uint32_t reserved1 : 4; /* Reserved */ 92 uint32_t base10_t_polarity : 1; /* Polarity State of 10Base-T */ 93 uint32_t reserved2 : 6; /* Reserved */ 94 uint32_t dis_sqe : 1; /* Disable SQE test(Heartbeat) */ 95 uint32_t reserved3 : 1; /* Reserved */ 96 uint32_t select_channel : 1; /* Manual channel select:MDI(0) or MDIX(1) */ 97 uint32_t reserved4 : 1; /* Reserved */ 98 uint32_t auto_mdix_ctrl : 1; /* Auto-MDIX Control: EN(0) or DE(1) */ 99 }; 100 uint32_t val; 101 } scsir_reg_t; 102 #define ETH_PHY_CSIR_REG_ADDR (0x1B) 103 104 /** 105 * @brief ISR(Interrupt Source Register) 106 * 107 */ 108 typedef union { 109 struct { 110 uint32_t reserved1 : 1; /* Reserved */ 111 uint32_t auto_nego_page_received : 1; /* Auto-Negotiation Page Received */ 112 uint32_t parallel_detect_falut : 1; /* Parallel Detection Fault */ 113 uint32_t auto_nego_lp_acknowledge : 1; /* Auto-Negotiation LP Acknowledge */ 114 uint32_t link_down : 1; /* Link Down */ 115 uint32_t remote_fault_detect : 1; /* Remote Fault Detect */ 116 uint32_t auto_nego_complete : 1; /* Auto-Negotiation Complete */ 117 uint32_t energy_on_generate : 1; /* ENERYON generated */ 118 uint32_t reserved2 : 8; /* Reserved */ 119 }; 120 uint32_t val; 121 } isfr_reg_t; 122 #define ETH_PHY_ISR_REG_ADDR (0x1D) 123 124 /** 125 * @brief IMR(Interrupt Mask Register) 126 * 127 */ 128 typedef union { 129 struct { 130 uint32_t reserved1 : 1; /* Reserved */ 131 uint32_t auto_nego_page_received : 1; /* Auto-Negotiation Page Received */ 132 uint32_t parallel_detect_falut : 1; /* Parallel Detection Fault */ 133 uint32_t auto_nego_lp_acknowledge : 1; /* Auto-Negotiation LP Acknowledge */ 134 uint32_t link_down : 1; /* Link Down */ 135 uint32_t remote_fault_detect : 1; /* Remote Fault Detect */ 136 uint32_t auto_nego_complete : 1; /* Auto-Negotiation Complete */ 137 uint32_t energy_on_generate : 1; /* ENERYON generated */ 138 uint32_t reserved2 : 8; /* Reserved */ 139 }; 140 uint32_t val; 141 } imr_reg_t; 142 #define ETH_PHY_IMR_REG_ADDR (0x1E) 143 144 /** 145 * @brief PSCSR(PHY Special Control Status Register) 146 * 147 */ 148 typedef union { 149 struct { 150 uint32_t reserved1 : 2; /* Reserved */ 151 uint32_t speed_indication : 3; /* Speed Indication */ 152 uint32_t reserved2 : 7; /* Reserved */ 153 uint32_t auto_nego_done : 1; /* Auto Negotiation Done */ 154 uint32_t reserved3 : 3; /* Reserved */ 155 }; 156 uint32_t val; 157 } pscsr_reg_t; 158 #define ETH_PHY_PSCSR_REG_ADDR (0x1F) 159 160 typedef struct { 161 esp_eth_phy_t parent; 162 esp_eth_mediator_t *eth; 163 uint32_t addr; 164 uint32_t reset_timeout_ms; 165 uint32_t autonego_timeout_ms; 166 eth_link_t link_status; 167 int reset_gpio_num; 168 } phy_lan8720_t; 169 170 static esp_err_t lan8720_update_link_duplex_speed(phy_lan8720_t *lan8720) 171 { 172 esp_eth_mediator_t *eth = lan8720->eth; 173 eth_speed_t speed = ETH_SPEED_10M; 174 eth_duplex_t duplex = ETH_DUPLEX_HALF; 175 bmsr_reg_t bmsr; 176 pscsr_reg_t pscsr; 177 uint32_t peer_pause_ability = false; 178 anlpar_reg_t anlpar; 179 PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK, 180 "read ANLPAR failed", err); 181 PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, 182 "read BMSR failed", err); 183 eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; 184 /* check if link status changed */ 185 if (lan8720->link_status != link) { 186 /* when link up, read negotiation result */ 187 if (link == ETH_LINK_UP) { 188 PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)) == ESP_OK, 189 "read PSCSR failed", err); 190 switch (pscsr.speed_indication) { 191 case 1: //10Base-T half-duplex 192 speed = ETH_SPEED_10M; 193 duplex = ETH_DUPLEX_HALF; 194 break; 195 case 2: //100Base-TX half-duplex 196 speed = ETH_SPEED_100M; 197 duplex = ETH_DUPLEX_HALF; 198 break; 199 case 5: //10Base-T full-duplex 200 speed = ETH_SPEED_10M; 201 duplex = ETH_DUPLEX_FULL; 202 break; 203 case 6: //100Base-TX full-duplex 204 speed = ETH_SPEED_100M; 205 duplex = ETH_DUPLEX_FULL; 206 break; 207 default: 208 break; 209 } 210 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, 211 "change speed failed", err); 212 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, 213 "change duplex failed", err); 214 /* if we're in duplex mode, and peer has the flow control ability */ 215 if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) { 216 peer_pause_ability = 1; 217 } else { 218 peer_pause_ability = 0; 219 } 220 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability) == ESP_OK, 221 "change pause ability failed", err); 222 } 223 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, 224 "change link failed", err); 225 lan8720->link_status = link; 226 } 227 return ESP_OK; 228 err: 229 return ESP_FAIL; 230 } 231 232 static esp_err_t lan8720_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) 233 { 234 PHY_CHECK(eth, "can't set mediator to null", err); 235 phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); 236 lan8720->eth = eth; 237 return ESP_OK; 238 err: 239 return ESP_ERR_INVALID_ARG; 240 } 241 242 static esp_err_t lan8720_get_link(esp_eth_phy_t *phy) 243 { 244 phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); 245 /* Updata information about link, speed, duplex */ 246 PHY_CHECK(lan8720_update_link_duplex_speed(lan8720) == ESP_OK, "update link duplex speed failed", err); 247 return ESP_OK; 248 err: 249 return ESP_FAIL; 250 } 251 252 static esp_err_t lan8720_reset(esp_eth_phy_t *phy) 253 { 254 phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); 255 lan8720->link_status = ETH_LINK_DOWN; 256 esp_eth_mediator_t *eth = lan8720->eth; 257 bmcr_reg_t bmcr = {.reset = 1}; 258 PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, 259 "write BMCR failed", err); 260 /* wait for reset complete */ 261 uint32_t to = 0; 262 for (to = 0; to < lan8720->reset_timeout_ms / 10; to++) { 263 vTaskDelay(pdMS_TO_TICKS(10)); 264 PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 265 "read BMCR failed", err); 266 if (!bmcr.reset) { 267 break; 268 } 269 } 270 PHY_CHECK(to < lan8720->reset_timeout_ms / 10, "reset timeout", err); 271 return ESP_OK; 272 err: 273 return ESP_FAIL; 274 } 275 276 static esp_err_t lan8720_reset_hw(esp_eth_phy_t *phy) 277 { 278 phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); 279 if (lan8720->reset_gpio_num >= 0) { 280 esp_rom_gpio_pad_select_gpio(lan8720->reset_gpio_num); 281 gpio_set_direction(lan8720->reset_gpio_num, GPIO_MODE_OUTPUT); 282 gpio_set_level(lan8720->reset_gpio_num, 0); 283 esp_rom_delay_us(100); // insert min input assert time 284 gpio_set_level(lan8720->reset_gpio_num, 1); 285 } 286 return ESP_OK; 287 } 288 289 static esp_err_t lan8720_negotiate(esp_eth_phy_t *phy) 290 { 291 phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); 292 esp_eth_mediator_t *eth = lan8720->eth; 293 /* Restart auto negotiation */ 294 bmcr_reg_t bmcr = { 295 .speed_select = 1, /* 100Mbps */ 296 .duplex_mode = 1, /* Full Duplex */ 297 .en_auto_nego = 1, /* Auto Negotiation */ 298 .restart_auto_nego = 1 /* Restart Auto Negotiation */ 299 }; 300 PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); 301 /* Wait for auto negotiation complete */ 302 bmsr_reg_t bmsr; 303 pscsr_reg_t pscsr; 304 int32_t to = 0; 305 for (to = 0; to < lan8720->autonego_timeout_ms / 10; to++) { 306 vTaskDelay(pdMS_TO_TICKS(10)); 307 PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, 308 "read BMSR failed", err); 309 PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)) == ESP_OK, 310 "read PSCSR failed", err); 311 if (bmsr.auto_nego_complete && pscsr.auto_nego_done) { 312 break; 313 } 314 } 315 /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ 316 if (to >= lan8720->autonego_timeout_ms / 10) { 317 ESP_LOGW(TAG, "auto negotiation timeout"); 318 } 319 /* Updata information about link, speed, duplex */ 320 PHY_CHECK(lan8720_update_link_duplex_speed(lan8720) == ESP_OK, "update link duplex speed failed", err); 321 return ESP_OK; 322 err: 323 return ESP_FAIL; 324 } 325 326 static esp_err_t lan8720_pwrctl(esp_eth_phy_t *phy, bool enable) 327 { 328 phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); 329 esp_eth_mediator_t *eth = lan8720->eth; 330 bmcr_reg_t bmcr; 331 PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 332 "read BMCR failed", err); 333 if (!enable) { 334 /* General Power Down Mode */ 335 bmcr.power_down = 1; 336 } else { 337 /* Normal operation Mode */ 338 bmcr.power_down = 0; 339 } 340 PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, 341 "write BMCR failed", err); 342 if (!enable) { 343 PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 344 "read BMCR failed", err); 345 PHY_CHECK(bmcr.power_down == 1, "power down failed", err); 346 } else { 347 /* wait for power up complete */ 348 uint32_t to = 0; 349 for (to = 0; to < lan8720->reset_timeout_ms / 10; to++) { 350 vTaskDelay(pdMS_TO_TICKS(10)); 351 PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 352 "read BMCR failed", err); 353 if (bmcr.power_down == 0) { 354 break; 355 } 356 } 357 PHY_CHECK(to < lan8720->reset_timeout_ms / 10, "power up timeout", err); 358 } 359 return ESP_OK; 360 err: 361 return ESP_FAIL; 362 } 363 364 static esp_err_t lan8720_set_addr(esp_eth_phy_t *phy, uint32_t addr) 365 { 366 phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); 367 lan8720->addr = addr; 368 return ESP_OK; 369 } 370 371 static esp_err_t lan8720_get_addr(esp_eth_phy_t *phy, uint32_t *addr) 372 { 373 PHY_CHECK(addr, "addr can't be null", err); 374 phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); 375 *addr = lan8720->addr; 376 return ESP_OK; 377 err: 378 return ESP_ERR_INVALID_ARG; 379 } 380 381 static esp_err_t lan8720_del(esp_eth_phy_t *phy) 382 { 383 phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); 384 free(lan8720); 385 return ESP_OK; 386 } 387 388 static esp_err_t lan8720_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability) 389 { 390 phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); 391 esp_eth_mediator_t *eth = lan8720->eth; 392 /* Set PAUSE function ability */ 393 anar_reg_t anar; 394 PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK, 395 "read ANAR failed", err); 396 if (ability) { 397 anar.asymmetric_pause = 1; 398 anar.symmetric_pause = 1; 399 } else { 400 anar.asymmetric_pause = 0; 401 anar.symmetric_pause = 0; 402 } 403 PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK, 404 "write ANAR failed", err); 405 return ESP_OK; 406 err: 407 return ESP_FAIL; 408 } 409 410 static esp_err_t lan8720_init(esp_eth_phy_t *phy) 411 { 412 phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); 413 esp_eth_mediator_t *eth = lan8720->eth; 414 // Detect PHY address 415 if (lan8720->addr == ESP_ETH_PHY_ADDR_AUTO) { 416 PHY_CHECK(esp_eth_detect_phy_addr(eth, &lan8720->addr) == ESP_OK, "Detect PHY address failed", err); 417 } 418 /* Power on Ethernet PHY */ 419 PHY_CHECK(lan8720_pwrctl(phy, true) == ESP_OK, "power control failed", err); 420 /* Reset Ethernet PHY */ 421 PHY_CHECK(lan8720_reset(phy) == ESP_OK, "reset failed", err); 422 /* Check PHY ID */ 423 phyidr1_reg_t id1; 424 phyidr2_reg_t id2; 425 PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, 426 "read ID1 failed", err); 427 PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, 428 "read ID2 failed", err); 429 PHY_CHECK(id1.oui_msb == 0x7 && id2.oui_lsb == 0x30 && id2.vendor_model == 0xF, "wrong chip ID", err); 430 return ESP_OK; 431 err: 432 return ESP_FAIL; 433 } 434 435 static esp_err_t lan8720_deinit(esp_eth_phy_t *phy) 436 { 437 /* Power off Ethernet PHY */ 438 PHY_CHECK(lan8720_pwrctl(phy, false) == ESP_OK, "power control failed", err); 439 return ESP_OK; 440 err: 441 return ESP_FAIL; 442 } 443 444 esp_eth_phy_t *esp_eth_phy_new_lan8720(const eth_phy_config_t *config) 445 { 446 PHY_CHECK(config, "can't set phy config to null", err); 447 phy_lan8720_t *lan8720 = calloc(1, sizeof(phy_lan8720_t)); 448 PHY_CHECK(lan8720, "calloc lan8720 failed", err); 449 lan8720->addr = config->phy_addr; 450 lan8720->reset_gpio_num = config->reset_gpio_num; 451 lan8720->reset_timeout_ms = config->reset_timeout_ms; 452 lan8720->link_status = ETH_LINK_DOWN; 453 lan8720->autonego_timeout_ms = config->autonego_timeout_ms; 454 lan8720->parent.reset = lan8720_reset; 455 lan8720->parent.reset_hw = lan8720_reset_hw; 456 lan8720->parent.init = lan8720_init; 457 lan8720->parent.deinit = lan8720_deinit; 458 lan8720->parent.set_mediator = lan8720_set_mediator; 459 lan8720->parent.negotiate = lan8720_negotiate; 460 lan8720->parent.get_link = lan8720_get_link; 461 lan8720->parent.pwrctl = lan8720_pwrctl; 462 lan8720->parent.get_addr = lan8720_get_addr; 463 lan8720->parent.set_addr = lan8720_set_addr; 464 lan8720->parent.advertise_pause_ability = lan8720_advertise_pause_ability; 465 lan8720->parent.del = lan8720_del; 466 467 return &(lan8720->parent); 468 err: 469 return NULL; 470 }