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