esp_eth_phy_rtl8201.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 15 #include <string.h> 16 #include <stdlib.h> 17 #include <sys/cdefs.h> 18 #include "esp_log.h" 19 #include "esp_eth.h" 20 #include "eth_phy_regs_struct.h" 21 #include "freertos/FreeRTOS.h" 22 #include "freertos/task.h" 23 #include "driver/gpio.h" 24 #include "esp_rom_gpio.h" 25 #include "esp_rom_sys.h" 26 27 static const char *TAG = "rtl8201"; 28 #define PHY_CHECK(a, str, goto_tag, ...) \ 29 do \ 30 { \ 31 if (!(a)) \ 32 { \ 33 ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ 34 goto goto_tag; \ 35 } \ 36 } while (0) 37 38 /***************Vendor Specific Register***************/ 39 40 /** 41 * @brief PSMR(Power Saving Mode Register) 42 * 43 */ 44 typedef union { 45 struct { 46 uint16_t reserved : 15; /* Reserved */ 47 uint16_t en_pwr_save : 1; /* Enable power saving mode */ 48 }; 49 uint16_t val; 50 } psmr_reg_t; 51 #define ETH_PHY_PSMR_REG_ADDR (0x18) 52 53 /** 54 * @brief PSR(Page Select Register) 55 * 56 */ 57 typedef union { 58 struct { 59 uint16_t page_select : 8; /* Select register page, default is 0 */ 60 uint16_t reserved : 8; /* Reserved */ 61 }; 62 uint16_t val; 63 } psr_reg_t; 64 #define ETH_PHY_PSR_REG_ADDR (0x1F) 65 66 typedef struct { 67 esp_eth_phy_t parent; 68 esp_eth_mediator_t *eth; 69 uint32_t addr; 70 uint32_t reset_timeout_ms; 71 uint32_t autonego_timeout_ms; 72 eth_link_t link_status; 73 int reset_gpio_num; 74 } phy_rtl8201_t; 75 76 static esp_err_t rtl8201_page_select(phy_rtl8201_t *rtl8201, uint32_t page) 77 { 78 esp_eth_mediator_t *eth = rtl8201->eth; 79 psr_reg_t psr = { 80 .page_select = page 81 }; 82 PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_PSR_REG_ADDR, psr.val) == ESP_OK, "write PSR failed", err); 83 return ESP_OK; 84 err: 85 return ESP_FAIL; 86 } 87 88 static esp_err_t rtl8201_update_link_duplex_speed(phy_rtl8201_t *rtl8201) 89 { 90 esp_eth_mediator_t *eth = rtl8201->eth; 91 eth_speed_t speed = ETH_SPEED_10M; 92 eth_duplex_t duplex = ETH_DUPLEX_HALF; 93 bmcr_reg_t bmcr; 94 bmsr_reg_t bmsr; 95 uint32_t peer_pause_ability = false; 96 anlpar_reg_t anlpar; 97 PHY_CHECK(rtl8201_page_select(rtl8201, 0) == ESP_OK, "select page 0 failed", err); 98 PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, 99 "read BMSR failed", err); 100 PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK, 101 "read ANLPAR failed", err); 102 eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; 103 /* check if link status changed */ 104 if (rtl8201->link_status != link) { 105 /* when link up, read negotiation result */ 106 if (link == ETH_LINK_UP) { 107 PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 108 "read BMCR failed", err); 109 if (bmcr.speed_select) { 110 speed = ETH_SPEED_100M; 111 } else { 112 speed = ETH_SPEED_10M; 113 } 114 if (bmcr.duplex_mode) { 115 duplex = ETH_DUPLEX_FULL; 116 } else { 117 duplex = ETH_DUPLEX_HALF; 118 } 119 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, 120 "change speed failed", err); 121 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, 122 "change duplex failed", err); 123 /* if we're in duplex mode, and peer has the flow control ability */ 124 if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) { 125 peer_pause_ability = 1; 126 } else { 127 peer_pause_ability = 0; 128 } 129 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability) == ESP_OK, 130 "change pause ability failed", err); 131 } 132 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, 133 "change link failed", err); 134 rtl8201->link_status = link; 135 } 136 return ESP_OK; 137 err: 138 return ESP_FAIL; 139 } 140 141 static esp_err_t rtl8201_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) 142 { 143 PHY_CHECK(eth, "can't set mediator to null", err); 144 phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); 145 rtl8201->eth = eth; 146 return ESP_OK; 147 err: 148 return ESP_ERR_INVALID_ARG; 149 } 150 151 static esp_err_t rtl8201_get_link(esp_eth_phy_t *phy) 152 { 153 phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); 154 /* Updata information about link, speed, duplex */ 155 PHY_CHECK(rtl8201_update_link_duplex_speed(rtl8201) == ESP_OK, "update link duplex speed failed", err); 156 return ESP_OK; 157 err: 158 return ESP_FAIL; 159 } 160 161 static esp_err_t rtl8201_reset(esp_eth_phy_t *phy) 162 { 163 phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); 164 rtl8201->link_status = ETH_LINK_DOWN; 165 esp_eth_mediator_t *eth = rtl8201->eth; 166 bmcr_reg_t bmcr = {.reset = 1}; 167 PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, 168 "write BMCR failed", err); 169 /* Wait for reset complete */ 170 uint32_t to = 0; 171 for (to = 0; to < rtl8201->reset_timeout_ms / 10; to++) { 172 vTaskDelay(pdMS_TO_TICKS(10)); 173 PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 174 "read BMCR failed", err); 175 if (!bmcr.reset) { 176 break; 177 } 178 } 179 PHY_CHECK(to < rtl8201->reset_timeout_ms / 10, "reset timeout", err); 180 return ESP_OK; 181 err: 182 return ESP_FAIL; 183 } 184 185 static esp_err_t rtl8201_reset_hw(esp_eth_phy_t *phy) 186 { 187 phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); 188 if (rtl8201->reset_gpio_num >= 0) { 189 esp_rom_gpio_pad_select_gpio(rtl8201->reset_gpio_num); 190 gpio_set_direction(rtl8201->reset_gpio_num, GPIO_MODE_OUTPUT); 191 gpio_set_level(rtl8201->reset_gpio_num, 0); 192 esp_rom_delay_us(100); // insert min input assert time 193 gpio_set_level(rtl8201->reset_gpio_num, 1); 194 } 195 return ESP_OK; 196 } 197 198 static esp_err_t rtl8201_negotiate(esp_eth_phy_t *phy) 199 { 200 phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); 201 esp_eth_mediator_t *eth = rtl8201->eth; 202 /* Restart auto negotiation */ 203 bmcr_reg_t bmcr = { 204 .speed_select = 1, /* 100Mbps */ 205 .duplex_mode = 1, /* Full Duplex */ 206 .en_auto_nego = 1, /* Auto Negotiation */ 207 .restart_auto_nego = 1 /* Restart Auto Negotiation */ 208 }; 209 PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, 210 "write BMCR failed", err); 211 /* Wait for auto negotiation complete */ 212 bmsr_reg_t bmsr; 213 uint32_t to = 0; 214 for (to = 0; to < rtl8201->autonego_timeout_ms / 10; to++) { 215 vTaskDelay(pdMS_TO_TICKS(10)); 216 PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, 217 "read BMSR failed", err); 218 if (bmsr.auto_nego_complete) { 219 break; 220 } 221 } 222 /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ 223 if (to >= rtl8201->autonego_timeout_ms / 10) { 224 ESP_LOGW(TAG, "auto negotiation timeout"); 225 } 226 /* Updata information about link, speed, duplex */ 227 PHY_CHECK(rtl8201_update_link_duplex_speed(rtl8201) == ESP_OK, "update link duplex speed failed", err); 228 return ESP_OK; 229 err: 230 return ESP_FAIL; 231 } 232 233 static esp_err_t rtl8201_pwrctl(esp_eth_phy_t *phy, bool enable) 234 { 235 phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); 236 esp_eth_mediator_t *eth = rtl8201->eth; 237 bmcr_reg_t bmcr; 238 PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 239 "read BMCR failed", err); 240 if (!enable) { 241 /* Enable IEEE Power Down Mode */ 242 bmcr.power_down = 1; 243 } else { 244 /* Disable IEEE Power Down Mode */ 245 bmcr.power_down = 0; 246 } 247 PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, 248 "write BMCR failed", err); 249 if (!enable) { 250 PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 251 "read BMCR failed", err); 252 PHY_CHECK(bmcr.power_down == 1, "power down failed", err); 253 } else { 254 /* wait for power up complete */ 255 uint32_t to = 0; 256 for (to = 0; to < rtl8201->reset_timeout_ms / 10; to++) { 257 vTaskDelay(pdMS_TO_TICKS(10)); 258 PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 259 "read BMCR failed", err); 260 if (bmcr.power_down == 0) { 261 break; 262 } 263 } 264 PHY_CHECK(to < rtl8201->reset_timeout_ms / 10, "power up timeout", err); 265 } 266 return ESP_OK; 267 err: 268 return ESP_FAIL; 269 } 270 271 static esp_err_t rtl8201_set_addr(esp_eth_phy_t *phy, uint32_t addr) 272 { 273 phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); 274 rtl8201->addr = addr; 275 return ESP_OK; 276 } 277 278 static esp_err_t rtl8201_get_addr(esp_eth_phy_t *phy, uint32_t *addr) 279 { 280 PHY_CHECK(addr, "addr can't be null", err); 281 phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); 282 *addr = rtl8201->addr; 283 return ESP_OK; 284 err: 285 return ESP_ERR_INVALID_ARG; 286 } 287 288 static esp_err_t rtl8201_del(esp_eth_phy_t *phy) 289 { 290 phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); 291 free(rtl8201); 292 return ESP_OK; 293 } 294 295 static esp_err_t rtl8201_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability) 296 { 297 phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); 298 esp_eth_mediator_t *eth = rtl8201->eth; 299 /* Set PAUSE function ability */ 300 anar_reg_t anar; 301 PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK, 302 "read ANAR failed", err); 303 if (ability) { 304 anar.asymmetric_pause = 1; 305 anar.symmetric_pause = 1; 306 } else { 307 anar.asymmetric_pause = 0; 308 anar.symmetric_pause = 0; 309 } 310 PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK, 311 "write ANAR failed", err); 312 return ESP_OK; 313 err: 314 return ESP_FAIL; 315 } 316 317 static esp_err_t rtl8201_init(esp_eth_phy_t *phy) 318 { 319 phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); 320 esp_eth_mediator_t *eth = rtl8201->eth; 321 // Detect PHY address 322 if (rtl8201->addr == ESP_ETH_PHY_ADDR_AUTO) { 323 PHY_CHECK(esp_eth_detect_phy_addr(eth, &rtl8201->addr) == ESP_OK, "Detect PHY address failed", err); 324 } 325 /* Power on Ethernet PHY */ 326 PHY_CHECK(rtl8201_pwrctl(phy, true) == ESP_OK, "power control failed", err); 327 /* Reset Ethernet PHY */ 328 PHY_CHECK(rtl8201_reset(phy) == ESP_OK, "reset failed", err); 329 /* Check PHY ID */ 330 phyidr1_reg_t id1; 331 phyidr2_reg_t id2; 332 PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, 333 "read ID1 failed", err); 334 PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, 335 "read ID2 failed", err); 336 PHY_CHECK(id1.oui_msb == 0x1C && id2.oui_lsb == 0x32 && id2.vendor_model == 0x1, 337 "wrong chip ID", err); 338 return ESP_OK; 339 err: 340 return ESP_FAIL; 341 } 342 343 static esp_err_t rtl8201_deinit(esp_eth_phy_t *phy) 344 { 345 /* Power off Ethernet PHY */ 346 PHY_CHECK(rtl8201_pwrctl(phy, false) == ESP_OK, "power control failed", err); 347 return ESP_OK; 348 err: 349 return ESP_FAIL; 350 } 351 352 esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config) 353 { 354 PHY_CHECK(config, "can't set phy config to null", err); 355 phy_rtl8201_t *rtl8201 = calloc(1, sizeof(phy_rtl8201_t)); 356 PHY_CHECK(rtl8201, "calloc rtl8201 failed", err); 357 rtl8201->addr = config->phy_addr; 358 rtl8201->reset_gpio_num = config->reset_gpio_num; 359 rtl8201->reset_timeout_ms = config->reset_timeout_ms; 360 rtl8201->link_status = ETH_LINK_DOWN; 361 rtl8201->autonego_timeout_ms = config->autonego_timeout_ms; 362 rtl8201->parent.reset = rtl8201_reset; 363 rtl8201->parent.reset_hw = rtl8201_reset_hw; 364 rtl8201->parent.init = rtl8201_init; 365 rtl8201->parent.deinit = rtl8201_deinit; 366 rtl8201->parent.set_mediator = rtl8201_set_mediator; 367 rtl8201->parent.negotiate = rtl8201_negotiate; 368 rtl8201->parent.get_link = rtl8201_get_link; 369 rtl8201->parent.pwrctl = rtl8201_pwrctl; 370 rtl8201->parent.get_addr = rtl8201_get_addr; 371 rtl8201->parent.set_addr = rtl8201_set_addr; 372 rtl8201->parent.advertise_pause_ability = rtl8201_advertise_pause_ability; 373 rtl8201->parent.del = rtl8201_del; 374 375 return &(rtl8201->parent); 376 err: 377 return NULL; 378 }