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 int 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
ip101_page_select(phy_ip101_t * ip101,uint32_t page)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
ip101_update_link_duplex_speed(phy_ip101_t * ip101)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
ip101_set_mediator(esp_eth_phy_t * phy,esp_eth_mediator_t * eth)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
ip101_get_link(esp_eth_phy_t * phy)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
ip101_reset(esp_eth_phy_t * phy)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
ip101_reset_hw(esp_eth_phy_t * phy)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
ip101_negotiate(esp_eth_phy_t * phy)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
ip101_pwrctl(esp_eth_phy_t * phy,bool enable)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
ip101_set_addr(esp_eth_phy_t * phy,uint32_t addr)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
ip101_get_addr(esp_eth_phy_t * phy,uint32_t * addr)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
ip101_del(esp_eth_phy_t * phy)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
ip101_advertise_pause_ability(esp_eth_phy_t * phy,uint32_t ability)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
ip101_init(esp_eth_phy_t * phy)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
ip101_deinit(esp_eth_phy_t * phy)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
esp_eth_phy_new_ip101(const eth_phy_config_t * config)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 }
422