esp_eth_phy_ksz8041.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 = "ksz8041"; 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 * @brief PC2R(PHY Control 2 Register) 40 * 41 */ 42 typedef union { 43 struct { 44 uint32_t hp_mdix : 1; /* HP Auto MDI/MDI-X Mode */ 45 uint32_t mdi_x_select : 1; /* MDI/MDI-X Select */ 46 uint32_t pairswap_dis : 1; /* Disable Auto MDI/MDI-X */ 47 uint32_t energy_det : 1; /* Presence of Signal on RX+/- Wire Pair */ 48 uint32_t force_link : 1; /* Force Link Pass */ 49 uint32_t power_saving : 1; /* Enable Powering Saving */ 50 uint32_t irq_level : 1; /* Interrupt Pin Active Level */ 51 uint32_t jabber : 1; /* Enable Jabber Counter */ 52 uint32_t auto_nego_comp : 1; /* Auto Negotiation Complete */ 53 uint32_t flow_ctl_cap : 1; /* Flow Control Capable */ 54 uint32_t phy_iso : 1; /* PHY in Isolate Mode */ 55 uint32_t op_mode_ind : 3; /* Operation Mode Indication */ 56 uint32_t en_sqe_test : 1; /* Enable SQE Test */ 57 uint32_t dis_data_scr: 1; /* Disable Scrambler */ 58 }; 59 uint32_t val; 60 } pc2r_reg_t; 61 #define ETH_PHY_PC2R_REG_ADDR (0x1F) 62 63 typedef struct { 64 esp_eth_phy_t parent; 65 esp_eth_mediator_t *eth; 66 uint32_t addr; 67 uint32_t reset_timeout_ms; 68 uint32_t autonego_timeout_ms; 69 eth_link_t link_status; 70 int reset_gpio_num; 71 } phy_ksz8041_t; 72 73 static esp_err_t ksz8041_update_link_duplex_speed(phy_ksz8041_t *ksz8041) 74 { 75 esp_eth_mediator_t *eth = ksz8041->eth; 76 eth_speed_t speed = ETH_SPEED_10M; 77 eth_duplex_t duplex = ETH_DUPLEX_HALF; 78 uint32_t peer_pause_ability = false; 79 anlpar_reg_t anlpar; 80 bmsr_reg_t bmsr; 81 pc2r_reg_t pc2r; 82 PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK, 83 "read ANLPAR failed", err); 84 PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, 85 "read BMSR failed", err); 86 eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; 87 /* check if link status changed */ 88 if (ksz8041->link_status != link) { 89 /* when link up, read negotiation result */ 90 if (link == ETH_LINK_UP) { 91 PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_PC2R_REG_ADDR, &(pc2r.val)) == ESP_OK, 92 "read PC2R failed", err); 93 switch (pc2r.op_mode_ind) { 94 case 1: //10Base-T half-duplex 95 speed = ETH_SPEED_10M; 96 duplex = ETH_DUPLEX_HALF; 97 break; 98 case 2: //100Base-TX half-duplex 99 speed = ETH_SPEED_100M; 100 duplex = ETH_DUPLEX_HALF; 101 break; 102 case 5: //10Base-T full-duplex 103 speed = ETH_SPEED_10M; 104 duplex = ETH_DUPLEX_FULL; 105 break; 106 case 6: //100Base-TX full-duplex 107 speed = ETH_SPEED_100M; 108 duplex = ETH_DUPLEX_FULL; 109 break; 110 default: 111 break; 112 } 113 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, 114 "change speed failed", err); 115 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, 116 "change duplex failed", err); 117 /* if we're in duplex mode, and peer has the flow control ability */ 118 if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) { 119 peer_pause_ability = 1; 120 } else { 121 peer_pause_ability = 0; 122 } 123 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability) == ESP_OK, 124 "change pause ability failed", err); 125 } 126 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, 127 "change link failed", err); 128 ksz8041->link_status = link; 129 } 130 return ESP_OK; 131 err: 132 return ESP_FAIL; 133 } 134 135 static esp_err_t ksz8041_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) 136 { 137 PHY_CHECK(eth, "can't set mediator to null", err); 138 phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); 139 ksz8041->eth = eth; 140 return ESP_OK; 141 err: 142 return ESP_ERR_INVALID_ARG; 143 } 144 145 static esp_err_t ksz8041_get_link(esp_eth_phy_t *phy) 146 { 147 phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); 148 /* Update information about link, speed, duplex */ 149 PHY_CHECK(ksz8041_update_link_duplex_speed(ksz8041) == ESP_OK, "update link duplex speed failed", err); 150 return ESP_OK; 151 err: 152 return ESP_FAIL; 153 } 154 155 static esp_err_t ksz8041_reset(esp_eth_phy_t *phy) 156 { 157 phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); 158 ksz8041->link_status = ETH_LINK_DOWN; 159 esp_eth_mediator_t *eth = ksz8041->eth; 160 bmcr_reg_t bmcr = {.reset = 1}; 161 PHY_CHECK(eth->phy_reg_write(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, 162 "write BMCR failed", err); 163 /* wait for reset complete */ 164 uint32_t to = 0; 165 for (to = 0; to < ksz8041->reset_timeout_ms / 10; to++) { 166 vTaskDelay(pdMS_TO_TICKS(10)); 167 PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 168 "read BMCR failed", err); 169 if (!bmcr.reset) { 170 break; 171 } 172 } 173 PHY_CHECK(to < ksz8041->reset_timeout_ms / 10, "reset timeout", err); 174 return ESP_OK; 175 err: 176 return ESP_FAIL; 177 } 178 179 static esp_err_t ksz8041_reset_hw(esp_eth_phy_t *phy) 180 { 181 phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); 182 if (ksz8041->reset_gpio_num >= 0) { 183 esp_rom_gpio_pad_select_gpio(ksz8041->reset_gpio_num); 184 gpio_set_direction(ksz8041->reset_gpio_num, GPIO_MODE_OUTPUT); 185 gpio_set_level(ksz8041->reset_gpio_num, 0); 186 esp_rom_delay_us(100); // insert min input assert time 187 gpio_set_level(ksz8041->reset_gpio_num, 1); 188 } 189 return ESP_OK; 190 } 191 192 static esp_err_t ksz8041_negotiate(esp_eth_phy_t *phy) 193 { 194 phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); 195 esp_eth_mediator_t *eth = ksz8041->eth; 196 /* Restart auto negotiation */ 197 bmcr_reg_t bmcr = { 198 .speed_select = 1, /* 100Mbps */ 199 .duplex_mode = 1, /* Full Duplex */ 200 .en_auto_nego = 1, /* Auto Negotiation */ 201 .restart_auto_nego = 1 /* Restart Auto Negotiation */ 202 }; 203 PHY_CHECK(eth->phy_reg_write(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); 204 /* Wait for auto negotiation complete */ 205 bmsr_reg_t bmsr; 206 pc2r_reg_t pc2r; 207 int32_t to = 0; 208 for (to = 0; to < ksz8041->autonego_timeout_ms / 10; to++) { 209 vTaskDelay(pdMS_TO_TICKS(10)); 210 PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, 211 "read BMSR failed", err); 212 PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_PC2R_REG_ADDR, &(pc2r.val)) == ESP_OK, 213 "read PC2R failed", err); 214 if (bmsr.auto_nego_complete && pc2r.auto_nego_comp) { 215 break; 216 } 217 } 218 /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ 219 if (to >= ksz8041->autonego_timeout_ms / 10) { 220 ESP_LOGW(TAG, "auto negotiation timeout"); 221 } 222 /* Updata information about link, speed, duplex */ 223 PHY_CHECK(ksz8041_update_link_duplex_speed(ksz8041) == ESP_OK, "update link duplex speed failed", err); 224 return ESP_OK; 225 err: 226 return ESP_FAIL; 227 } 228 229 static esp_err_t ksz8041_pwrctl(esp_eth_phy_t *phy, bool enable) 230 { 231 phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); 232 esp_eth_mediator_t *eth = ksz8041->eth; 233 bmcr_reg_t bmcr; 234 PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 235 "read BMCR failed", err); 236 if (!enable) { 237 /* General Power Down Mode */ 238 bmcr.power_down = 1; 239 } else { 240 /* Normal operation Mode */ 241 bmcr.power_down = 0; 242 } 243 PHY_CHECK(eth->phy_reg_write(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, 244 "write BMCR failed", err); 245 if (!enable) { 246 PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 247 "read BMCR failed", err); 248 PHY_CHECK(bmcr.power_down == 1, "power down failed", err); 249 } else { 250 /* wait for power up complete */ 251 uint32_t to = 0; 252 for (to = 0; to < ksz8041->reset_timeout_ms / 10; to++) { 253 vTaskDelay(pdMS_TO_TICKS(10)); 254 PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 255 "read BMCR failed", err); 256 if (bmcr.power_down == 0) { 257 break; 258 } 259 } 260 PHY_CHECK(to < ksz8041->reset_timeout_ms / 10, "power up timeout", err); 261 } 262 return ESP_OK; 263 err: 264 return ESP_FAIL; 265 } 266 267 static esp_err_t ksz8041_set_addr(esp_eth_phy_t *phy, uint32_t addr) 268 { 269 phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); 270 ksz8041->addr = addr; 271 return ESP_OK; 272 } 273 274 static esp_err_t ksz8041_get_addr(esp_eth_phy_t *phy, uint32_t *addr) 275 { 276 PHY_CHECK(addr, "addr can't be null", err); 277 phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); 278 *addr = ksz8041->addr; 279 return ESP_OK; 280 err: 281 return ESP_ERR_INVALID_ARG; 282 } 283 284 static esp_err_t ksz8041_del(esp_eth_phy_t *phy) 285 { 286 phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); 287 free(ksz8041); 288 return ESP_OK; 289 } 290 291 static esp_err_t ksz8041_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability) 292 { 293 phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); 294 esp_eth_mediator_t *eth = ksz8041->eth; 295 /* Set PAUSE function ability */ 296 anar_reg_t anar; 297 PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK, 298 "read ANAR failed", err); 299 if (ability) { 300 anar.asymmetric_pause = 1; 301 anar.symmetric_pause = 1; 302 } else { 303 anar.asymmetric_pause = 0; 304 anar.symmetric_pause = 0; 305 } 306 PHY_CHECK(eth->phy_reg_write(eth, ksz8041->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK, 307 "write ANAR failed", err); 308 return ESP_OK; 309 err: 310 return ESP_FAIL; 311 } 312 313 static esp_err_t ksz8041_init(esp_eth_phy_t *phy) 314 { 315 phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); 316 esp_eth_mediator_t *eth = ksz8041->eth; 317 /* Power on Ethernet PHY */ 318 PHY_CHECK(ksz8041_pwrctl(phy, true) == ESP_OK, "power control failed", err); 319 /* Reset Ethernet PHY */ 320 PHY_CHECK(ksz8041_reset(phy) == ESP_OK, "reset failed", err); 321 /* Check PHY ID */ 322 phyidr1_reg_t id1; 323 phyidr2_reg_t id2; 324 PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, 325 "read ID1 failed", err); 326 PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, 327 "read ID2 failed", err); 328 PHY_CHECK(id1.oui_msb == 0x22 && id2.oui_lsb == 0x5 && id2.vendor_model == 0x11, "wrong chip ID", err); 329 return ESP_OK; 330 err: 331 return ESP_FAIL; 332 } 333 334 static esp_err_t ksz8041_deinit(esp_eth_phy_t *phy) 335 { 336 /* Power off Ethernet PHY */ 337 PHY_CHECK(ksz8041_pwrctl(phy, false) == ESP_OK, "power control failed", err); 338 return ESP_OK; 339 err: 340 return ESP_FAIL; 341 } 342 343 esp_eth_phy_t *esp_eth_phy_new_ksz8041(const eth_phy_config_t *config) 344 { 345 PHY_CHECK(config, "can't set phy config to null", err); 346 phy_ksz8041_t *ksz8041 = calloc(1, sizeof(phy_ksz8041_t)); 347 PHY_CHECK(ksz8041, "calloc ksz8041 failed", err); 348 ksz8041->addr = config->phy_addr; 349 ksz8041->reset_gpio_num = config->reset_gpio_num; 350 ksz8041->reset_timeout_ms = config->reset_timeout_ms; 351 ksz8041->link_status = ETH_LINK_DOWN; 352 ksz8041->autonego_timeout_ms = config->autonego_timeout_ms; 353 ksz8041->parent.reset = ksz8041_reset; 354 ksz8041->parent.reset_hw = ksz8041_reset_hw; 355 ksz8041->parent.init = ksz8041_init; 356 ksz8041->parent.deinit = ksz8041_deinit; 357 ksz8041->parent.set_mediator = ksz8041_set_mediator; 358 ksz8041->parent.negotiate = ksz8041_negotiate; 359 ksz8041->parent.get_link = ksz8041_get_link; 360 ksz8041->parent.pwrctl = ksz8041_pwrctl; 361 ksz8041->parent.get_addr = ksz8041_get_addr; 362 ksz8041->parent.set_addr = ksz8041_set_addr; 363 ksz8041->parent.advertise_pause_ability = ksz8041_advertise_pause_ability; 364 ksz8041->parent.del = ksz8041_del; 365 366 return &(ksz8041->parent); 367 err: 368 return NULL; 369 }