Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers: ethernet: add support for microchip lan9250 #77035

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

mariopaja
Copy link
Contributor

This PR adds support for LAN9250 spi ethernet controller.
This driver is tested on the Mikroe ETH Click 3

Console:

[00:00:00.079,000] <inf> eth_lan9250: LAN9250 Initialized
*** Booting Zephyr OS build v3.7.0-565-g2c4498a094de ***
[00:00:00.079,000] <inf> net_dhcpv4_client_sample: Run dhcpv4 client
[00:00:00.079,000] <inf> net_dhcpv4_client_sample: Start on eth_lan9250@0: index=1
[00:00:05.679,000] <inf> net_dhcpv4: Received: 192.168.8.242
[00:00:05.679,000] <inf> net_dhcpv4_client_sample:    Address[1]: 192.168.8.242
[00:00:05.679,000] <inf> net_dhcpv4_client_sample:     Subnet[1]: 255.255.255.0
[00:00:05.679,000] <inf> net_dhcpv4_client_sample:     Router[1]: 192.168.8.1
[00:00:05.679,000] <inf> net_dhcpv4_client_sample: Lease time[1]: 43200 seconds
uart:~$ net iface

Interface eth0 (0x20000e50) (Ethernet) [1]
===================================
Link addr : 80:34:28:01:02:05
MTU       : 1500
Flags     : AUTO_START,IPv4
Device    : eth_lan9250@0 (0x8017248)
Ethernet capabilities supported:
        10 Mbits
        100 Mbits
Ethernet PHY device: <none> (0)
IPv4 unicast addresses (max 1):
        192.168.8.242/255.255.255.0 DHCP preferred
IPv4 multicast addresses (max 2):
        224.0.0.1
IPv4 gateway : 192.168.8.1
DHCPv4 lease time : 43200
DHCPv4 renew time : 21600
DHCPv4 server     : 192.168.8.1
DHCPv4 requested  : 192.168.8.242
DHCPv4 state      : bound
DHCPv4 attempts   : 2
uart:~$ net ping 8.8.8.8
PING 8.8.8.8
28 bytes from 8.8.8.8 to 192.168.8.242: icmp_seq=1 ttl=53 time=30 ms
28 bytes from 8.8.8.8 to 192.168.8.242: icmp_seq=2 ttl=53 time=30 ms
28 bytes from 8.8.8.8 to 192.168.8.242: icmp_seq=3 ttl=53 time=30 ms

Nucleo-H563 Overlay:

&spi1 {
    eth_lan9250: eth_lan9250@0 {
        compatible = "microchip,lan9250";
        spi-max-frequency = <30000000>;
        reg = <0>;
        int-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>;
        status = "okay";
        local-mac-address = [ 80 34 28 01 02 05  ];
    };
};

&mac {
    status = "disabled";
};

&mdio {
    status = "disabled";
};

drivers/ethernet/Kconfig.lan9250 Outdated Show resolved Hide resolved
drivers/ethernet/eth_lan9250.c Outdated Show resolved Hide resolved
uint32_t tmp;
int wait_time = 0;

while (true) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There exists WAIT_FOR macro that could perhaps used here and the other wait loops in other functions, could you check if it would make sense to use that here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a look into it and I tried to implement it. I don't know if I did something wrong but I noticed a performance hit. Receiving an IP took double the time after implementing WAIT_FOR

WAIT_FOR:

[00:00:00.019,000] <inf> eth_lan9250: LAN9250 Initialized
*** Booting Zephyr OS build v3.7.0-945-ga7dd4cb9ce3d ***
[00:00:00.019,000] <inf> net_dhcpv4_client_sample: Run dhcpv4 client
[00:00:00.019,000] <inf> net_dhcpv4_client_sample: Start on eth_lan9250@0: index=1
[00:00:10.669,000] <inf> net_dhcpv4: Received: 192.168.8.242
[00:00:10.669,000] <inf> net_dhcpv4_client_sample:    Address[1]: 192.168.8.242
[00:00:10.669,000] <inf> net_dhcpv4_client_sample:     Subnet[1]: 255.255.255.0
[00:00:10.669,000] <inf> net_dhcpv4_client_sample:     Router[1]: 192.168.8.1
[00:00:10.669,000] <inf> net_dhcpv4_client_sample: Lease time[1]: 43200 seconds
uart:~$ 

while loop:

[00:00:00.074,000] <inf> eth_lan9250: LAN9250 Initialized
*** Booting Zephyr OS build v3.7.0-945-ga7dd4cb9ce3d ***
[00:00:00.074,000] <inf> net_dhcpv4_client_sample: Run dhcpv4 client
[00:00:00.074,000] <inf> net_dhcpv4_client_sample: Start on eth_lan9250@0: index=1
[00:00:05.659,000] <inf> net_dhcpv4: Received: 192.168.8.242
[00:00:05.659,000] <inf> net_dhcpv4_client_sample:    Address[1]: 192.168.8.242
[00:00:05.659,000] <inf> net_dhcpv4_client_sample:     Subnet[1]: 255.255.255.0
[00:00:05.659,000] <inf> net_dhcpv4_client_sample:     Router[1]: 192.168.8.1
[00:00:05.659,000] <inf> net_dhcpv4_client_sample: Lease time[1]: 43200 seconds

drivers/ethernet/eth_lan9250.c Outdated Show resolved Hide resolved

/* Reference: Microchip Ethernet LAN9250
* https://github.com/microchip-pic-avr-solutions/ethernet-lan9250/
* ((phy_add & 0x1F) << 11) | ((index & 0x1F) << 6)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment line is a bit lonely, perhaps you could add more information what it means (I see it is being used in next line so the comment refers to that)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to give a bit more information this time


lan9250_write_sys_reg(dev, LAN9250_RESET_CTL,
LAN9250_RESET_CTL_HMAC_RST | LAN9250_RESET_CTL_PHY_RST |
LAN9250_RESET_CTL_DIGITAL_RST);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation is wrong


lan9250_write_sys_reg(dev, LAN9250_IRQ_CFG,
LAN9250_IRQ_CFG_INT_DEAS_100US | LAN9250_IRQ_CFG_IRQ_EN |
LAN9250_IRQ_CFG_IRQ_TYPE_PP);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

*/
lan9250_write_sys_reg(dev, LAN9250_INT_EN,
LAN9250_INT_EN_PHY_INT_EN | LAN9250_INT_EN_TDFA_EN |
LAN9250_INT_EN_RSFL_EN);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here and other similar lines too, could you check them all

drivers/ethernet/eth_lan9250.c Outdated Show resolved Hide resolved
drivers/ethernet/eth_lan9250.c Outdated Show resolved Hide resolved
drivers/ethernet/eth_lan9250.c Outdated Show resolved Hide resolved
drivers/ethernet/eth_lan9250.c Outdated Show resolved Hide resolved

ret |= lan9250_write_mac_reg(dev, LAN9250_HMAC_ADDRH,
ctx->mac_address[4] | (ctx->mac_address[5] << 8));

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please explicitly check the return code (i.e. do not OR the ret)

drivers/ethernet/eth_lan9250.c Outdated Show resolved Hide resolved
ret |= lan9250_read_sys_reg(dev, LAN9250_HW_CFG, &tmp);
k_busy_wait(USEC_PER_MSEC * 1U);
} while ((tmp & LAN9250_HW_CFG_DEVICE_READY) == 0);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My overall impression is that you do use a lot of busy waiting. Is there any special rationale for it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is the datasheet that specifies that there are timing rules back to back read-write operations 5.2.1 BACK-TO-BACK WRITE-READ CYCLES, and then I took as a baseline the delays in the ethernet-lan9250 driver.

drivers/ethernet/eth_lan9250.c Outdated Show resolved Hide resolved
/* Review the space available for the new frag */
lan9250_read_buf(dev, data_ptr, spi_frame_len);
net_buf_add(pkt_buf, pkt_len);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to check if CONFIG_NET_BUF_DATA_SIZE is in sync with your setup as you use net_buf_add()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it is needed because it is already checked how much space is available at the end of the buffer with net_buf_tailroom(). Similar to the other SPI Ethernet modules (w5500, enc28j60, eth_enc424j600)

uint32_t regval;
uint16_t free_size;
uint8_t status_size;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The LOG_DBG() shall be after declarations

}

k_sem_give(&ctx->tx_rx_sem);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you followed the paradigm from LAN8651 (T1S) driver. The rationale for half-duplex transmission there was the issue with driver complexity versus potential gain.

I'm just wondering if the LAN9250 has the opportunity to work full duplex (as other drivers connected via SPI)?

And another question - out of curiosity - have you tested the driver with zperf Zephyr's test program?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And just to point out - the SPI transmission with chained different buffers was the reason for considerable slow down for STM32 based SoC.

Last but not least - the LAN9250 seems to be 10/100 Mbps - I do assume that it works with 100 Mbps?

Copy link
Contributor Author

@mariopaja mariopaja Aug 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And another question - out of curiosity - have you tested the driver with zperf Zephyr's test program?

No I did not test it, but I can do that too, to test it out.
However, I had a short look on the switch and the device is working at 100Mbps (FE):
lan9250_FE

Last but not least - the LAN9250 seems to be 10/100 Mbps - I do assume that it works with 100 Mbps?

I have enabled auto-negotiation & advertisement capability for both 10/100 Mbps HD/FD

/* Configure PHY basic control:
*
* - Auto-Negotiation for 10/100 Mbits and Half/Full Duplex
*/
lan9250_write_phy_reg(dev, LAN9250_PHY_BASIC_CONTROL,
LAN9250_PHY_BASIC_CONTROL_PHY_AN |
LAN9250_PHY_BASIC_CONTROL_PHY_SPEED_SEL_LSB |
LAN9250_PHY_BASIC_CONTROL_PHY_DUPLEX);
/* Configure PHY auto-negotiation advertisement capability:
*
* - Asymmetric pause
* - Symmetric pause
* - 100Base-X half/full duplex
* - 10Base-X half/full duplex
* - Select IEEE802.3
*/
lan9250_write_phy_reg(dev, LAN9250_PHY_AN_ADV,
LAN9250_PHY_AN_ADV_ASYM_PAUSE | LAN9250_PHY_AN_ADV_SYM_PAUSE |
LAN9250_PHY_AN_ADV_100BTX_HD | LAN9250_PHY_AN_ADV_100BTX_FD |
LAN9250_PHY_AN_ADV_10BT_HD | LAN9250_PHY_AN_ADV_10BT_FD |
LAN9250_PHY_AN_ADV_SELECTOR_DEFAULT);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a bit off-topic. It looks like second MicroClick modules are used as based board. Is there any plan to add them to zephyr as "capes"? IIRC for LAN8651 I also wanted to add it - in a way similar to:
https://github.com/zephyrproject-rtos/zephyr/tree/main/boards/shields/mikroe_wifi_bt_click
or
https://github.com/zephyrproject-rtos/zephyr/tree/main/boards/shields/mikroe_eth_click

but the reply was that we cannot tie to any specific board (like with microe_wifi_bt_click.

Copy link
Contributor Author

@mariopaja mariopaja Aug 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lmajewski I was also thinking adding it as a shield in a second PR. At the moment I want to pass only a minimal implementation of the driver.

but the reply was that we cannot tie to any specific board (like with microe_wifi_bt_click.

I know that we should not tie drivers to specific shields but also Microship itself is using this module to demonstrate LAN9250 on their Quick Start Guide

@mariopaja mariopaja force-pushed the lan9250 branch 3 times, most recently from 01f1782 to 1d35288 Compare August 17, 2024 15:45
@mariopaja mariopaja marked this pull request as draft August 17, 2024 16:48
@mariopaja
Copy link
Contributor Author

mariopaja commented Aug 17, 2024

Converted to draft because I noticed some unexpected behaviour, while connected to different switches/routers

@mariopaja mariopaja force-pushed the lan9250 branch 2 times, most recently from b309efd to fd55383 Compare September 1, 2024 14:00
This PR adds support for LAN9250 spi ethernet controller.
This driver is tested on the Mikroe ETH Click 3
https://www.mikroe.com/eth-3-click

Signed-off-by: Mario Paja <[email protected]>
@mariopaja
Copy link
Contributor Author

@jukkar @lmajewski

Issue mentioned earlier is fixed

[00:00:00.292,000] <inf> eth_lan9250: LAN9250 Initialized
*** Booting Zephyr OS build v3.7.0-945-gfd55383524db ***
[00:00:00.293,000] <inf> net_dhcpv4_client_sample: Run dhcpv4 client
[00:00:00.293,000] <inf> net_dhcpv4_client_sample: Start on eth_lan9250@0: index=1
[00:00:02.895,000] <inf> net_dhcpv4: Received: 192.168.8.240
[00:00:02.896,000] <inf> net_dhcpv4_client_sample:    Address[1]: 192.168.8.240
[00:00:02.896,000] <inf> net_dhcpv4_client_sample:     Subnet[1]: 255.255.255.0
[00:00:02.896,000] <inf> net_dhcpv4_client_sample:     Router[1]: 192.168.8.1
[00:00:02.896,000] <inf> net_dhcpv4_client_sample: Lease time[1]: 43200 seconds
uart:~$ net iface
Hostname: zephyr

Interface eth0 (0x3fc94d60) (Ethernet) [1]
===================================
Link addr : 80:34:28:01:02:03
MTU       : 1500
Flags     : AUTO_START,IPv4
Device    : eth_lan9250@0 (0x3c026bc8)
Ethernet capabilities supported:
        10 Mbits
        100 Mbits
Ethernet PHY device: <none> (0)
IPv4 unicast addresses (max 1):
        192.168.8.240/255.255.255.0 DHCP preferred
IPv4 multicast addresses (max 2):
        224.0.0.1
IPv4 gateway : 192.168.8.1
DHCPv4 lease time : 43200
DHCPv4 renew time : 21600
DHCPv4 server     : 192.168.8.1
DHCPv4 requested  : 192.168.8.240
DHCPv4 state      : bound
DHCPv4 attempts   : 1
uart:~$ net ping 8.8.8.8
PING 8.8.8.8
28 bytes from 8.8.8.8 to 192.168.8.240: icmp_seq=1 ttl=111 time=68 ms
28 bytes from 8.8.8.8 to 192.168.8.240: icmp_seq=2 ttl=111 time=64 ms
28 bytes from 8.8.8.8 to 192.168.8.240: icmp_seq=3 ttl=111 time=64 ms
uart:~$ 

xiao esp32s3 overlay:

&spi2 {
    cs-gpios=<&gpio0 3 GPIO_ACTIVE_LOW>;
    eth_lan9250: eth_lan9250@0 {
        compatible = "microchip,lan9250";
        spi-max-frequency = <60000000>;
        reg = <0>; 
        int-gpios = <&gpio0 4 GPIO_ACTIVE_LOW>; 
        status = "okay";
        local-mac-address = [80 34 28 01 02 03];
    };
};

This was the best performance I could get:
Screenshot 2024-09-01 at 10 24 37

@albertofloyd albertofloyd removed their request for review September 20, 2024 20:50
Copy link
Member

@jukkar jukkar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some very minor style nits from me, other than that looks reasonable.

/* Disable TX data FIFO available interrupt */
lan9250_write_sys_reg(dev, LAN9250_FIFO_INT,
LAN9250_FIFO_INT_TX_DATA_AVAILABLE_LEVEL |
LAN9250_FIFO_INT_TX_STATUS_LEVEL);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation is wrong here and in many similar statements below

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants