Skip to content

Commit 6edf0fe

Browse files
committed
Merge branch 'feature/support_ksz8041' into 'master'
support ksz8041 Closes IDFGH-3495 and IDFGH-3584 See merge request espressif/esp-idf!9558
2 parents b6b4d41 + abcea51 commit 6edf0fe

File tree

10 files changed

+349
-0
lines changed

10 files changed

+349
-0
lines changed

components/esp_eth/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ if(CONFIG_ETH_ENABLED)
2222
list(APPEND srcs "src/esp_eth_mac_esp32.c"
2323
"src/esp_eth_phy_dp83848.c"
2424
"src/esp_eth_phy_ip101.c"
25+
"src/esp_eth_phy_ksz8041.c"
2526
"src/esp_eth_phy_lan8720.c"
2627
"src/esp_eth_phy_rtl8201.c")
2728
endif()

components/esp_eth/include/esp_eth_phy.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,17 @@ esp_eth_phy_t *esp_eth_phy_new_lan8720(const eth_phy_config_t *config);
240240
*/
241241
esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config);
242242

243+
/**
244+
* @brief Create a PHY instance of KSZ8041
245+
*
246+
* @param[in] config: configuration of PHY
247+
*
248+
* @return
249+
* - instance: create PHY instance successfully
250+
* - NULL: create PHY instance failed because some error occurred
251+
*/
252+
esp_eth_phy_t *esp_eth_phy_new_ksz8041(const eth_phy_config_t *config);
253+
243254
#if CONFIG_ETH_SPI_ETHERNET_DM9051
244255
/**
245256
* @brief Create a PHY instance of DM9051
@@ -252,6 +263,7 @@ esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config);
252263
*/
253264
esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config);
254265
#endif
266+
255267
#ifdef __cplusplus
256268
}
257269
#endif

components/esp_eth/src/esp_eth_phy_dm9051.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ static esp_err_t dm9051_reset_hw(esp_eth_phy_t *phy)
193193
esp_rom_gpio_pad_select_gpio(dm9051->reset_gpio_num);
194194
gpio_set_direction(dm9051->reset_gpio_num, GPIO_MODE_OUTPUT);
195195
gpio_set_level(dm9051->reset_gpio_num, 0);
196+
ets_delay_us(100); // insert min input assert time
196197
gpio_set_level(dm9051->reset_gpio_num, 1);
197198
}
198199
return ESP_OK;

components/esp_eth/src/esp_eth_phy_dp83848.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ static esp_err_t dp83848_reset_hw(esp_eth_phy_t *phy)
182182
esp_rom_gpio_pad_select_gpio(dp83848->reset_gpio_num);
183183
gpio_set_direction(dp83848->reset_gpio_num, GPIO_MODE_OUTPUT);
184184
gpio_set_level(dp83848->reset_gpio_num, 0);
185+
ets_delay_us(100); // insert min input assert time
185186
gpio_set_level(dp83848->reset_gpio_num, 1);
186187
}
187188
return ESP_OK;

components/esp_eth/src/esp_eth_phy_ip101.c

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

components/esp_eth/src/esp_eth_phy_lan8720.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ static esp_err_t lan8720_reset_hw(esp_eth_phy_t *phy)
267267
esp_rom_gpio_pad_select_gpio(lan8720->reset_gpio_num);
268268
gpio_set_direction(lan8720->reset_gpio_num, GPIO_MODE_OUTPUT);
269269
gpio_set_level(lan8720->reset_gpio_num, 0);
270+
ets_delay_us(100); // insert min input assert time
270271
gpio_set_level(lan8720->reset_gpio_num, 1);
271272
}
272273
return ESP_OK;

components/esp_eth/src/esp_eth_phy_rtl8201.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ static esp_err_t rtl8201_reset_hw(esp_eth_phy_t *phy)
176176
esp_rom_gpio_pad_select_gpio(rtl8201->reset_gpio_num);
177177
gpio_set_direction(rtl8201->reset_gpio_num, GPIO_MODE_OUTPUT);
178178
gpio_set_level(rtl8201->reset_gpio_num, 0);
179+
ets_delay_us(100); // insert min input assert time
179180
gpio_set_level(rtl8201->reset_gpio_num, 1);
180181
}
181182
return ESP_OK;

0 commit comments

Comments
 (0)