esp_eth_phy_ip101.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 = "ip101"; 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 PCR(Page Control Register) 41 * 42 */ 43 typedef union { 44 struct { 45 uint32_t register_page_select : 5; /* Select register page, default is 16 */ 46 uint32_t reserved : 11; /* Reserved */ 47 }; 48 uint32_t val; 49 } pcr_reg_t; 50 #define ETH_PHY_PCR_REG_ADDR (0x14) 51 52 /** 53 * @brief ISR(Interrupt Status Register), Page 16 54 * 55 */ 56 typedef union { 57 struct { 58 uint32_t link_changed : 1; /* Flag to indicate link status change interrupt */ 59 uint32_t duplex_changed : 1; /* Flag to indicate duplex change interrupt */ 60 uint32_t speed_changed : 1; /* Flag to indicate speed change interrupt */ 61 uint32_t intr_status : 1; /* Flag to indicate interrupt status */ 62 uint32_t reserved1 : 4; /* Reserved */ 63 uint32_t link_mask : 1; /* Mask link change interrupt */ 64 uint32_t duplex_mask : 1; /* Mask duplex change interrupt */ 65 uint32_t speed_mask : 1; /* Mask speed change interrupt */ 66 uint32_t all_mask : 1; /* Mask all interrupt */ 67 uint32_t reserved2 : 3; /* Reserved */ 68 uint32_t use_intr_pin : 1; /* Set high to use INTR and INTR_32 as an interrupt pin */ 69 }; 70 uint32_t val; 71 } isr_reg_t; 72 #define ETH_PHY_ISR_REG_ADDR (0x11) 73 74 /** 75 * @brief PHY MDI/MDIX Control and Specific Status Register, Page 16 76 * 77 */ 78 typedef union { 79 struct { 80 uint32_t op_mode : 3; /* Operation Mode Idicator */ 81 uint32_t force_mdix : 1; /* Force the MDIX channel to be selected */ 82 uint32_t reserved1 : 4; /* Reserved */ 83 uint32_t link_up : 1; /* Indicate the link status is OK or FAIL */ 84 uint32_t reserved2 : 7; /* Reserved */ 85 }; 86 uint32_t val; 87 } cssr_reg_t; 88 #define ETH_PHY_CSSR_REG_ADDR (0x1E) 89 90 /** 91 * @brief PSCR(PHY Specific Control Register), Page 1 92 * 93 */ 94 typedef union { 95 struct { 96 uint32_t reserved1 : 7; /* Reserved */ 97 uint32_t force_link_100 : 1; /* Force Link 100 */ 98 uint32_t force_link_10 : 1; /* Force Link 10 */ 99 uint32_t reserved2 : 7; /* Reserved */ 100 }; 101 uint32_t val; 102 } pscr_reg_t; 103 #define ETH_PHY_PSCR_REG_ADDR (0x11) 104 105 typedef struct { 106 esp_eth_phy_t parent; 107 esp_eth_mediator_t *eth; 108 uint32_t addr; 109 uint32_t reset_timeout_ms; 110 uint32_t autonego_timeout_ms; 111 eth_link_t link_status; 112 int reset_gpio_num; 113 } phy_ip101_t; 114 115 static esp_err_t ip101_page_select(phy_ip101_t *ip101, uint32_t page) 116 { 117 esp_eth_mediator_t *eth = ip101->eth; 118 pcr_reg_t pcr = { 119 .register_page_select = page 120 }; 121 PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_PCR_REG_ADDR, pcr.val) == ESP_OK, "write PCR failed", err); 122 return ESP_OK; 123 err: 124 return ESP_FAIL; 125 } 126 127 static esp_err_t ip101_update_link_duplex_speed(phy_ip101_t *ip101) 128 { 129 esp_eth_mediator_t *eth = ip101->eth; 130 eth_speed_t speed = ETH_SPEED_10M; 131 eth_duplex_t duplex = ETH_DUPLEX_HALF; 132 uint32_t peer_pause_ability = false; 133 cssr_reg_t cssr; 134 anlpar_reg_t anlpar; 135 PHY_CHECK(ip101_page_select(ip101, 16) == ESP_OK, "select page 16 failed", err); 136 PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_CSSR_REG_ADDR, &(cssr.val)) == ESP_OK, 137 "read CSSR failed", err); 138 PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK, 139 "read ANLPAR failed", err); 140 eth_link_t link = cssr.link_up ? ETH_LINK_UP : ETH_LINK_DOWN; 141 /* check if link status changed */ 142 if (ip101->link_status != link) { 143 /* when link up, read negotiation result */ 144 if (link == ETH_LINK_UP) { 145 switch (cssr.op_mode) { 146 case 1: //10M Half 147 speed = ETH_SPEED_10M; 148 duplex = ETH_DUPLEX_HALF; 149 break; 150 case 2: //100M Half 151 speed = ETH_SPEED_100M; 152 duplex = ETH_DUPLEX_HALF; 153 break; 154 case 5: //10M Full 155 speed = ETH_SPEED_10M; 156 duplex = ETH_DUPLEX_FULL; 157 break; 158 case 6: //100M Full 159 speed = ETH_SPEED_100M; 160 duplex = ETH_DUPLEX_FULL; 161 break; 162 default: 163 break; 164 } 165 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, 166 "change speed failed", err); 167 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, 168 "change duplex failed", err); 169 /* if we're in duplex mode, and peer has the flow control ability */ 170 if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) { 171 peer_pause_ability = 1; 172 } else { 173 peer_pause_ability = 0; 174 } 175 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability) == ESP_OK, 176 "change pause ability failed", err); 177 } 178 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, 179 "chagne link failed", err); 180 ip101->link_status = link; 181 } 182 return ESP_OK; 183 err: 184 return ESP_FAIL; 185 } 186 187 static esp_err_t ip101_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) 188 { 189 PHY_CHECK(eth, "can't set mediator to null", err); 190 phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); 191 ip101->eth = eth; 192 return ESP_OK; 193 err: 194 return ESP_ERR_INVALID_ARG; 195 } 196 197 static esp_err_t ip101_get_link(esp_eth_phy_t *phy) 198 { 199 phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); 200 /* Updata information about link, speed, duplex */ 201 PHY_CHECK(ip101_update_link_duplex_speed(ip101) == ESP_OK, "update link duplex speed failed", err); 202 return ESP_OK; 203 err: 204 return ESP_FAIL; 205 } 206 207 static esp_err_t ip101_reset(esp_eth_phy_t *phy) 208 { 209 phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); 210 ip101->link_status = ETH_LINK_DOWN; 211 esp_eth_mediator_t *eth = ip101->eth; 212 bmcr_reg_t bmcr = {.reset = 1}; 213 PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, 214 "write BMCR failed", err); 215 /* wait for reset complete */ 216 uint32_t to = 0; 217 for (to = 0; to < ip101->reset_timeout_ms / 10; to++) { 218 vTaskDelay(pdMS_TO_TICKS(10)); 219 PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 220 "read BMCR failed", err); 221 if (!bmcr.reset) { 222 break; 223 } 224 } 225 PHY_CHECK(to < ip101->reset_timeout_ms / 10, "reset timeout", err); 226 return ESP_OK; 227 err: 228 return ESP_FAIL; 229 } 230 231 static esp_err_t ip101_reset_hw(esp_eth_phy_t *phy) 232 { 233 phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); 234 if (ip101->reset_gpio_num >= 0) { 235 esp_rom_gpio_pad_select_gpio(ip101->reset_gpio_num); 236 gpio_set_direction(ip101->reset_gpio_num, GPIO_MODE_OUTPUT); 237 gpio_set_level(ip101->reset_gpio_num, 0); 238 esp_rom_delay_us(100); // insert min input assert time 239 gpio_set_level(ip101->reset_gpio_num, 1); 240 } 241 return ESP_OK; 242 } 243 244 static esp_err_t ip101_negotiate(esp_eth_phy_t *phy) 245 { 246 phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); 247 esp_eth_mediator_t *eth = ip101->eth; 248 /* Restart auto negotiation */ 249 bmcr_reg_t bmcr = { 250 .speed_select = 1, /* 100Mbps */ 251 .duplex_mode = 1, /* Full Duplex */ 252 .en_auto_nego = 1, /* Auto Negotiation */ 253 .restart_auto_nego = 1 /* Restart Auto Negotiation */ 254 }; 255 PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, 256 "write BMCR failed", err); 257 /* Wait for auto negotiation complete */ 258 bmsr_reg_t bmsr; 259 uint32_t to = 0; 260 for (to = 0; to < ip101->autonego_timeout_ms / 10; to++) { 261 vTaskDelay(pdMS_TO_TICKS(10)); 262 PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, 263 "read BMSR failed", err); 264 if (bmsr.auto_nego_complete) { 265 break; 266 } 267 } 268 /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ 269 if (to >= ip101->autonego_timeout_ms / 10) { 270 ESP_LOGW(TAG, "auto negotiation timeout"); 271 } 272 /* Updata information about link, speed, duplex */ 273 PHY_CHECK(ip101_update_link_duplex_speed(ip101) == ESP_OK, "update link duplex speed failed", err); 274 return ESP_OK; 275 err: 276 return ESP_FAIL; 277 } 278 279 static esp_err_t ip101_pwrctl(esp_eth_phy_t *phy, bool enable) 280 { 281 phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); 282 esp_eth_mediator_t *eth = ip101->eth; 283 bmcr_reg_t bmcr; 284 PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 285 "read BMCR failed", err); 286 if (!enable) { 287 /* Enable IEEE Power Down Mode */ 288 bmcr.power_down = 1; 289 } else { 290 /* Disable IEEE Power Down Mode */ 291 bmcr.power_down = 0; 292 } 293 PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, 294 "write BMCR failed", err); 295 if (!enable) { 296 PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 297 "read BMCR failed", err); 298 PHY_CHECK(bmcr.power_down == 1, "power down failed", err); 299 } else { 300 /* wait for power up complete */ 301 uint32_t to = 0; 302 for (to = 0; to < ip101->reset_timeout_ms / 10; to++) { 303 vTaskDelay(pdMS_TO_TICKS(10)); 304 PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 305 "read BMCR failed", err); 306 if (bmcr.power_down == 0) { 307 break; 308 } 309 } 310 PHY_CHECK(to < ip101->reset_timeout_ms / 10, "power up timeout", err); 311 } 312 return ESP_OK; 313 err: 314 return ESP_FAIL; 315 } 316 317 static esp_err_t ip101_set_addr(esp_eth_phy_t *phy, uint32_t addr) 318 { 319 phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); 320 ip101->addr = addr; 321 return ESP_OK; 322 } 323 324 static esp_err_t ip101_get_addr(esp_eth_phy_t *phy, uint32_t *addr) 325 { 326 PHY_CHECK(addr, "addr can't be null", err); 327 phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); 328 *addr = ip101->addr; 329 return ESP_OK; 330 err: 331 return ESP_ERR_INVALID_ARG; 332 } 333 334 static esp_err_t ip101_del(esp_eth_phy_t *phy) 335 { 336 phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); 337 free(ip101); 338 return ESP_OK; 339 } 340 341 static esp_err_t ip101_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability) 342 { 343 phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); 344 esp_eth_mediator_t *eth = ip101->eth; 345 /* Set PAUSE function ability */ 346 anar_reg_t anar; 347 PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK, 348 "read ANAR failed", err); 349 if (ability) { 350 anar.asymmetric_pause = 1; 351 anar.symmetric_pause = 1; 352 } else { 353 anar.asymmetric_pause = 0; 354 anar.symmetric_pause = 0; 355 } 356 PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK, 357 "write ANAR failed", err); 358 return ESP_OK; 359 err: 360 return ESP_FAIL; 361 } 362 363 static esp_err_t ip101_init(esp_eth_phy_t *phy) 364 { 365 phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); 366 esp_eth_mediator_t *eth = ip101->eth; 367 // Detect PHY address 368 if (ip101->addr == ESP_ETH_PHY_ADDR_AUTO) { 369 PHY_CHECK(esp_eth_detect_phy_addr(eth, &ip101->addr) == ESP_OK, "Detect PHY address failed", err); 370 } 371 /* Power on Ethernet PHY */ 372 PHY_CHECK(ip101_pwrctl(phy, true) == ESP_OK, "power control failed", err); 373 /* Reset Ethernet PHY */ 374 PHY_CHECK(ip101_reset(phy) == ESP_OK, "reset failed", err); 375 /* Check PHY ID */ 376 phyidr1_reg_t id1; 377 phyidr2_reg_t id2; 378 PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err); 379 PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err); 380 PHY_CHECK(id1.oui_msb == 0x243 && id2.oui_lsb == 0x3 && id2.vendor_model == 0x5, "wrong chip ID", err); 381 return ESP_OK; 382 err: 383 return ESP_FAIL; 384 } 385 386 static esp_err_t ip101_deinit(esp_eth_phy_t *phy) 387 { 388 /* Power off Ethernet PHY */ 389 PHY_CHECK(ip101_pwrctl(phy, false) == ESP_OK, "power control failed", err); 390 return ESP_OK; 391 err: 392 return ESP_FAIL; 393 } 394 395 esp_eth_phy_t *esp_eth_phy_new_ip101(const eth_phy_config_t *config) 396 { 397 PHY_CHECK(config, "can't set phy config to null", err); 398 phy_ip101_t *ip101 = calloc(1, sizeof(phy_ip101_t)); 399 PHY_CHECK(ip101, "calloc ip101 failed", err); 400 ip101->addr = config->phy_addr; 401 ip101->reset_timeout_ms = config->reset_timeout_ms; 402 ip101->reset_gpio_num = config->reset_gpio_num; 403 ip101->link_status = ETH_LINK_DOWN; 404 ip101->autonego_timeout_ms = config->autonego_timeout_ms; 405 ip101->parent.reset = ip101_reset; 406 ip101->parent.reset_hw = ip101_reset_hw; 407 ip101->parent.init = ip101_init; 408 ip101->parent.deinit = ip101_deinit; 409 ip101->parent.set_mediator = ip101_set_mediator; 410 ip101->parent.negotiate = ip101_negotiate; 411 ip101->parent.get_link = ip101_get_link; 412 ip101->parent.pwrctl = ip101_pwrctl; 413 ip101->parent.get_addr = ip101_get_addr; 414 ip101->parent.set_addr = ip101_set_addr; 415 ip101->parent.advertise_pause_ability = ip101_advertise_pause_ability; 416 ip101->parent.del = ip101_del; 417 418 return &(ip101->parent); 419 err: 420 return NULL; 421 }