Skip to content

Commit

Permalink
drivers/enet: Add support for ethernet in imxrt1064-evk
Browse files Browse the repository at this point in the history
JIRA: RTOS-507
  • Loading branch information
Julian Uziemblo committed Sep 6, 2024
1 parent b8a7494 commit 2201bc9
Show file tree
Hide file tree
Showing 12 changed files with 1,290 additions and 285 deletions.
2 changes: 1 addition & 1 deletion _targets/Makefile.armv7a7-imx6ull
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
NET_DRIVERS_SUPPORTED := enet tuntap
NET_DRIVERS ?= $(NET_DRIVERS_SUPPORTED)

DRIVERS_SRCS_enet = imx-enet.c ephy.c gpio.c imx6ull-gpio.c $(DRIVERS_SRCS_UTIL) hw-debug.c
DRIVERS_SRCS_enet = imx-enet.c ephy.c imx6ull-gpio.c $(DRIVERS_SRCS_UTIL) hw-debug.c
6 changes: 4 additions & 2 deletions _targets/Makefile.armv7m7-imxrt106x
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
#
# iMX RT1064 target
#
# Copyright 2021 Phoenix Systems
# Copyright 2021, 2024 Phoenix Systems
#

NET_DRIVERS_SUPPORTED := pppou pppos
NET_DRIVERS_SUPPORTED := pppou pppos enet
NET_DRIVERS ?= $(NET_DRIVERS_SUPPORTED)
PPPOS_MODEM := huawei

DRIVERS_SRCS_enet = imx-enet.c ephy.c imxrt106x-gpio.c $(DRIVERS_SRCS_UTIL)
5 changes: 4 additions & 1 deletion drivers/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ endif
ifeq ($(EPHY_KSZ8081),RND)
LOCAL_CFLAGS := -DEPHY_KSZ8081RND
endif
ifeq ($(EPHY_KSZ8081),RNB)
LOCAL_CFLAGS := -DEPHY_KSZ8081RNB
endif

# make possible to specify defalult APN name externally
ifneq ($(PPPOS_DEFAULT_APN),)
Expand All @@ -15,7 +18,7 @@ endif

# abstract drivers available on every platform
DRIVERS_SRCS := netif-driver.c
DRIVERS_SRCS_UTIL := bdring.c pktmem.c physmmap.c res-create.c
DRIVERS_SRCS_UTIL := bdring.c pktmem.c physmmap.c res-create.c time-util.c
DRIVERS_SRCS_pppos := pppos.c
DRIVERS_SRCS_pppou := pppou.c
DRIVERS_SRCS_tuntap := tuntap.c
Expand Down
138 changes: 108 additions & 30 deletions drivers/ephy.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
*
* Ethernet PHY common routines
*
* Copyright 2018 Phoenix Systems
* Author: Michał Mirosław
* Copyright 2018, 2024 Phoenix Systems
* Author: Michał Mirosław, Julian Uziembło
*
* %LICENSE%
*/
Expand All @@ -23,8 +23,6 @@
#include <sys/threads.h>


//#define EPHY_KSZ8081RND

enum {
EPHY_00_BASIC_CONTROL = 0x00,
EPHY_01_BASIC_STATUS,
Expand All @@ -48,45 +46,80 @@ enum {
};


#if 1
static inline void ephy_printf(eth_phy_state_t *phy, const char *format, ...)
{
char buf[192];
va_list arg;

va_start(arg, format);
vsnprintf(buf, sizeof(buf), format, arg);
va_end(arg);

printf("lwip: ephy%u.%u: %s\n", phy->bus, phy->addr, buf);
}
#else
#define ephy_printf(...)
#endif

#if EPHY_DEBUG
#define ephy_debug_printf(phy, ...) ephy_printf(phy, __VA_ARGS__)
#else
#define ephy_debug_printf(...)
#endif


static uint16_t ephy_reg_read(eth_phy_state_t *phy, uint16_t reg)
{
return mdio_read(phy->bus, phy->addr, reg);
uint16_t ret = mdio_read(phy->bus, phy->addr, reg);
#if MDIO_DEBUG
ephy_printf(phy, "read: val from reg: 0x%04x", phy->bus, phy->addr, ret);
#endif
return ret;
}


static void ephy_reg_write(eth_phy_state_t *phy, uint16_t reg, uint16_t val)
{
mdio_write(phy->bus, phy->addr, reg, val);
ephy_reg_read(phy, reg);
uint16_t ret __attribute__((unused)) = ephy_reg_read(phy, reg);
#if MDIO_DEBUG
ephy_printf(phy, "write: val from reg: 0x%04x", ret);
#endif
}


static void ephy_reset(eth_phy_state_t *phy)
{
if (gpio_valid(&phy->reset)) {
ephy_debug_printf(phy, "ephy_reset: start hardware reset...");
// TODO: prepare bootstrap pins
gpio_set(&phy->reset, 1);
usleep(phy->reset_hold_time_us);
mdio_lock_bus(phy->bus);
gpio_set(&phy->reset, 0);
usleep(phy->reset_release_time_us);
mdio_unlock_bus(phy->bus);
ephy_debug_printf(phy, "ephy_reset: hardware reset complete.");
}
else {
int res = 0, retries = 10;

ephy_debug_printf(phy, "ephy_reset: start software reset...");

ephy_reg_write(phy, EPHY_00_BASIC_CONTROL, 1 << 15);
usleep(phy->reset_release_time_us);

while (retries--) {
do {
res = ephy_reg_read(phy, EPHY_00_BASIC_CONTROL);
if ((res & (1 << 15)) == 0) {
ephy_debug_printf(phy, "ephy_reset: software reset complete.");
break;
}
}
} while (retries--);

if ((res & (1 << 15)) != 0) {
printf("lwip: ephy%u.%u soft-reset timed out\n", phy->bus, phy->addr);
ephy_printf(phy, "software reset timed out");
}
}
}
Expand All @@ -113,14 +146,13 @@ static uint32_t ephy_readPhyId(eth_phy_state_t *phy)
}


static void ephy_show_link_state(eth_phy_state_t *phy)
static void ephy_setLinkState(eth_phy_state_t *phy)
{
uint16_t bctl, bstat, adv, lpa, pc1, pc2;
int speed, full_duplex;

bctl = ephy_reg_read(phy, EPHY_00_BASIC_CONTROL);
bstat = ephy_reg_read(phy, EPHY_01_BASIC_STATUS);
bstat = ephy_reg_read(phy, EPHY_01_BASIC_STATUS);
adv = ephy_reg_read(phy, EPHY_04_AN_ADV);
lpa = ephy_reg_read(phy, EPHY_05_AN_LP_ABILITY);
pc1 = ephy_reg_read(phy, EPHY_1E_PHY_CTRL1);
Expand All @@ -133,10 +165,16 @@ static void ephy_show_link_state(eth_phy_state_t *phy)
phy->link_state_callback(phy->link_state_callback_arg, linkup);
}

printf("lwip: ephy%u.%u link is %s %uMbps/%s (ctl %04x, status %04x, adv %04x, lpa %04x, pctl %04x,%04x)\n",
phy->bus, phy->addr, linkup ? "UP " : "DOWN",
speed, full_duplex ? "Full" : "Half",
bctl, bstat, adv, lpa, pc1, pc2);
if (speed != 0) {
ephy_printf(phy, "link is %s %uMbps/%s (ctl %04x, status %04x, adv %04x, lpa %04x, pctl %04x,%04x)",
linkup ? "UP " : "DOWN",
speed, full_duplex ? "Full" : "Half",
bctl, bstat, adv, lpa, pc1, pc2);
}
else {
ephy_printf(phy, "link is in AN mode (ctl %04x, status %04x, adv %04x, lpa %04x, pctl %04x,%04x)",
bctl, bstat, adv, lpa, pc1, pc2);
}
}


Expand Down Expand Up @@ -170,18 +208,26 @@ static void ephy_link_thread(void *arg)
{
eth_phy_state_t *phy = arg;
uint16_t stat;
int err;

for (;;) {
gpio_wait(&phy->irq_gpio, 1, 0);
err = gpio_wait(&phy->irq_gpio, 1, NULL);
// FIXME: thread exit

stat = ephy_reg_read(phy, EPHY_1B_IRQ_CTRL_STATUS);
if (stat >= 0 && (stat & 0xFF) != 0) {
ephy_show_link_state(phy);
if (err == 0) {
stat = ephy_reg_read(phy, EPHY_1B_IRQ_CTRL_STATUS);
if ((stat & 0xFF) != 0) {
ephy_setLinkState(phy);
}
}
#if EPHY_DEBUG
else {
ephy_printf(phy, "ephy_link_thread: gpio_wait timed out");
}
#endif
}

printf("lwip ephy%u.%u thread finished.\n", phy->bus, phy->addr);
ephy_printf(phy, "ephy link-detect thread finished");
endthread();
}

Expand Down Expand Up @@ -240,6 +286,7 @@ static int ephy_config(eth_phy_state_t *phy, char *cfg)
phy->addr = strtoul(cfg, &p, 0);
}
else {
printf("ephy: WARN: setting default bus 0\n");
phy->bus = 0;
}

Expand Down Expand Up @@ -294,15 +341,17 @@ int ephy_enableLoopback(eth_phy_state_t *phy, bool enable)
ephy_reg_write(phy, EPHY_1F_PHY_CTRL2, phy_ctrl2);

if (ephy_reg_read(phy, EPHY_00_BASIC_CONTROL) != bmcr) {
printf("ephy: failed to set loopback mode\n");
ephy_printf(phy, "failed to set loopback mode");
return -1;
}

if (ephy_reg_read(phy, EPHY_1F_PHY_CTRL2) != phy_ctrl2) {
printf("ephy: failed to force link up\n");
ephy_printf(phy, "failed to force link up");
return -1;
}

ephy_debug_printf(phy, "loopback %s", enable ? "enabled" : "disabled");

return 0;
}

Expand Down Expand Up @@ -340,26 +389,29 @@ static int ephy_setAltConfig(eth_phy_state_t *phy, int cfg_id)

ephy_reg_write(phy, EPHY_1F_PHY_CTRL2, phy_ctrl2);
if (ephy_reg_read(phy, EPHY_1F_PHY_CTRL2) != phy_ctrl2) {
printf("ephy: failed to set alternative clock\n");
ephy_printf(phy, "failed to set alternative clock");
return -1;
}

ephy_debug_printf(phy, "alternative clock set successfully");

return 1;
}


int ephy_init(eth_phy_state_t *phy, char *conf, uint8_t board_rev, link_state_cb_t cb, void *cb_arg)
{
(void)board_rev;
uint32_t phyid;
int err;
int err, cfg_id;

memset(phy, 0, sizeof(*phy));

err = ephy_config(phy, conf);
if (err != 0) {
printf("lwip: ephy: Couldn't configure PHY: %s (%d)", strerror(err), err);
return -EINVAL;
}
ephy_debug_printf(phy, "PHY configured");

/*
* for KSZ8081RNA/D, KSZ8081RNB:
Expand All @@ -373,48 +425,74 @@ int ephy_init(eth_phy_state_t *phy, char *conf, uint8_t board_rev, link_state_cb

err = mdio_setup(phy->bus, 2500 /* kHz */, 10 /* ns */, 0 /* with-preamble */);
if (err != 0) {
ephy_printf(phy, "Couldn't init MDIO: %s (%d)", strerror(err), err);
return err;
}

ephy_reset(phy);

phyid = ephy_readPhyId(phy);
if (phyid == 0u || phyid == ~0u) {
ephy_printf(phy, "Couldn't read PHY ID");
gpio_set(&phy->reset, 1);
return -ENODEV;
}

/* make address 0 not broadcast, disable NAND-tree mode */
ephy_reg_write(phy, EPHY_16_OP_MODE_STRAP_OVERRIDE, (1 << 1) | (1 << 9));

ephy_setAltConfig(phy, 0); /* KSZ8081 RND - default config */
err = ephy_setAltConfig(phy, 0); /* KSZ8081 RND - default config */
if (err <= 0) {
ephy_printf(phy, "Couldn't set default config");
return -ENODEV;
}

#ifdef LWIP_EPHY_INIT_HOOK
LWIP_EPHY_INIT_HOOK(phy, phyid, board_rev);
#else
(void)board_rev;
#endif


#if defined(EPHY_KSZ8081RNA) || defined(EPHY_KSZ8081RNB)
ephy_setAltConfig(phy, 1);
cfg_id = 1;
#elif defined(EPHY_KSZ8081RND)
ephy_setAltConfig(phy, 0);
cfg_id = 0;
#endif
ephy_setAltConfig(phy, cfg_id);
if (err <= 0) {
ephy_printf(phy, "Couldn't set alternative config %d", cfg_id);
return -ENODEV;
}

phy->link_state_callback = cb;
phy->link_state_callback_arg = cb_arg;
ephy_show_link_state(phy);
ephy_setLinkState(phy);

if (gpio_valid(&phy->irq_gpio)) {
err = beginthread(ephy_link_thread, 0, phy->th_stack, sizeof(phy->th_stack), phy);
err = beginthread(ephy_link_thread, 6, phy->th_stack, sizeof(phy->th_stack), phy);
if (err != 0) {
gpio_set(&phy->reset, 1);
return err;
}

/* enable link up/down IRQ signal */
ephy_reg_write(phy, EPHY_1B_IRQ_CTRL_STATUS, (1 << 8) | (1 << 10));

if ((phy->irq_gpio.flags & GPIO_INVERTED) == 0) {
/* set interrupt pin active high */
uint16_t phy_ctrl2 = ephy_reg_read(phy, EPHY_1F_PHY_CTRL2);
ephy_reg_write(phy, EPHY_1F_PHY_CTRL2, phy_ctrl2 | (1 << 9));
}
}
else {
ephy_printf(phy, "WARN: irq_gpio not valid, could not start PHY IRQ thread");
return -ENODEV;
}

ephy_restart_an(phy);

ephy_debug_printf(phy, "Successfully initialized PHY");

return 0;
}
4 changes: 3 additions & 1 deletion drivers/ephy.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#include <stdint.h>
#include <stdbool.h>

typedef void (*link_state_cb_t)(void* arg, int state);
typedef void (*link_state_cb_t)(void *arg, int state);

typedef struct {
unsigned bus;
Expand All @@ -36,7 +36,9 @@ typedef struct {
int ephy_init(eth_phy_state_t *phy, char *conf, uint8_t board_rev, link_state_cb_t cb, void *cb_arg);
int ephy_linkSpeed(eth_phy_state_t *phy, int *full_duplex);

#ifdef ENET_SELFTEST
/* toggle MACPHY internal loopback for test mode */
int ephy_enableLoopback(eth_phy_state_t *phy, bool enable);
#endif

#endif /* NET_EPHY_H_ */
Loading

0 comments on commit 2201bc9

Please sign in to comment.