[U-Boot] [U-boot] [Patch v2 0/5] keystone2: serdes: add seredes driver

This patch series adds serdes driver, taking out it from keystone_net driver.
v2..v1: - just rebase.
Based on "[U-boot] [Patch v2 0/5] keystone2: generalize keystone_net driver usage" https://www.mail-archive.com/u-boot@lists.denx.de/msg148657.html
Ivan Khoronzhuk (5): net: phy: print a number of phy that is not found net: keystone_net: use mdio_reset function net: keystone_net: register MDIO bus net: keystone_net: register eth PHYs on MDIO bus net: keystone_net: use general get link function
arch/arm/include/asm/ti-common/keystone_net.h | 1 + drivers/net/keystone_net.c | 143 ++++++++++++++------------ drivers/net/phy/phy.c | 2 +- include/configs/ks2_evm.h | 2 + 4 files changed, 83 insertions(+), 65 deletions(-)

In case when several Ethernet ports are supported it's convenient to see the number of phy that is not found.
Signed-off-by: Ivan Khoronzhuk ivan.khoronzhuk@ti.com --- drivers/net/phy/phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 1d6c14f..99b0b83 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -648,7 +648,7 @@ static struct phy_device *get_phy_device_by_mask(struct mii_dev *bus, if (phydev) return phydev; } - printf("Phy not found\n"); + printf("Phy %d not found\n", ffs(phy_mask) - 1); return phy_device_create(bus, ffs(phy_mask) - 1, 0xffffffff, interface); }

Don't use mdio_enable twice while eth open. Also rename it to keystone2_mdio_reset as more appropriate name.
Signed-off-by: Ivan Khoronzhuk ivan.khoronzhuk@ti.com --- drivers/net/keystone_net.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-)
diff --git a/drivers/net/keystone_net.c b/drivers/net/keystone_net.c index 8a45fbd..ed5c61e 100644 --- a/drivers/net/keystone_net.c +++ b/drivers/net/keystone_net.c @@ -38,7 +38,6 @@ struct rx_buff_desc net_rx_buffs = { .rx_flow = 22, };
-static void keystone2_eth_mdio_enable(void); static void keystone2_net_serdes_setup(void);
static int gen_get_link_speed(int phy_addr); @@ -71,7 +70,7 @@ int keystone2_eth_read_mac_addr(struct eth_device *dev) return 0; }
-static void keystone2_eth_mdio_enable(void) +static void keystone2_mdio_reset(void) { u_int32_t clkdiv;
@@ -397,7 +396,6 @@ int32_t cpmac_drv_send(u32 *buffer, int num_bytes, int slave_port_num) /* Eth device open */ static int keystone2_eth_open(struct eth_device *dev, bd_t *bis) { - u_int32_t clkdiv; int link; struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv;
@@ -410,9 +408,6 @@ static int keystone2_eth_open(struct eth_device *dev, bd_t *bis)
keystone2_net_serdes_setup();
- if (sys_has_mdio) - keystone2_eth_mdio_enable(); - keystone_sgmii_config(eth_priv->slave_port - 1, eth_priv->sgmii_link_type);
@@ -440,13 +435,7 @@ static int keystone2_eth_open(struct eth_device *dev, bd_t *bis) hw_config_streaming_switch();
if (sys_has_mdio) { - /* Init MDIO & get link state */ - clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; - writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | - MDIO_CONTROL_FAULT, &adap_mdio->control) - ; - - /* We need to wait for MDIO to start */ + keystone2_mdio_reset(); udelay(1000);
link = keystone_get_link_status(dev);

Currently MDIO framework is not used to configure Ethernet PHY. As result some of already implemented functions are duplicated. So register MDIO bus in order to use it. On that stage it's just registered, it'll be used as we start to use PHY framework.
Use mdio bus read/write/reset functions in the driver.
Signed-off-by: Ivan Khoronzhuk ivan.khoronzhuk@ti.com --- drivers/net/keystone_net.c | 89 ++++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 34 deletions(-)
diff --git a/drivers/net/keystone_net.c b/drivers/net/keystone_net.c index ed5c61e..6f7cc17 100644 --- a/drivers/net/keystone_net.c +++ b/drivers/net/keystone_net.c @@ -17,6 +17,7 @@ #include <asm/ti-common/keystone_serdes.h>
unsigned int emac_open; +static struct mii_dev *mdio_bus; static unsigned int sys_has_mdio = 1;
#ifdef KEYSTONE2_EMAC_GIG_ENABLE @@ -70,64 +71,67 @@ int keystone2_eth_read_mac_addr(struct eth_device *dev) return 0; }
-static void keystone2_mdio_reset(void) +/* MDIO */ + +static int keystone2_mdio_reset(struct mii_dev *bus) { - u_int32_t clkdiv; + u_int32_t clkdiv; + struct mdio_regs *adap_mdio = bus->priv;
clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
- writel((clkdiv & 0xffff) | - MDIO_CONTROL_ENABLE | - MDIO_CONTROL_FAULT | - MDIO_CONTROL_FAULT_ENABLE, + writel((clkdiv & 0xffff) | MDIO_CONTROL_ENABLE | + MDIO_CONTROL_FAULT | MDIO_CONTROL_FAULT_ENABLE, &adap_mdio->control);
while (readl(&adap_mdio->control) & MDIO_CONTROL_IDLE) ; + + return 0; }
-/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */ -int keystone2_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data) +/** + * keystone2_mdio_read - read a PHY register via MDIO interface. + * Blocks until operation is complete. + */ +static int keystone2_mdio_read(struct mii_dev *bus, + int addr, int devad, int reg) { - int tmp; + int tmp; + struct mdio_regs *adap_mdio = bus->priv;
while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO) ;
- writel(MDIO_USERACCESS0_GO | - MDIO_USERACCESS0_WRITE_READ | - ((reg_num & 0x1f) << 21) | - ((phy_addr & 0x1f) << 16), + writel(MDIO_USERACCESS0_GO | MDIO_USERACCESS0_WRITE_READ | + ((reg & 0x1f) << 21) | ((addr & 0x1f) << 16), &adap_mdio->useraccess0);
/* Wait for command to complete */ while ((tmp = readl(&adap_mdio->useraccess0)) & MDIO_USERACCESS0_GO) ;
- if (tmp & MDIO_USERACCESS0_ACK) { - *data = tmp & 0xffff; - return 0; - } + if (tmp & MDIO_USERACCESS0_ACK) + return tmp & 0xffff;
- *data = -1; return -1; }
-/* - * Write to a PHY register via MDIO inteface. +/** + * keystone2_mdio_write - write to a PHY register via MDIO interface. * Blocks until operation is complete. */ -int keystone2_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data) +static int keystone2_mdio_write(struct mii_dev *bus, + int addr, int devad, int reg, u16 val) { + struct mdio_regs *adap_mdio = bus->priv; + while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO) ;
- writel(MDIO_USERACCESS0_GO | - MDIO_USERACCESS0_WRITE_WRITE | - ((reg_num & 0x1f) << 21) | - ((phy_addr & 0x1f) << 16) | - (data & 0xffff), - &adap_mdio->useraccess0); + writel(MDIO_USERACCESS0_GO | MDIO_USERACCESS0_WRITE_WRITE | + ((reg & 0x1f) << 21) | ((addr & 0x1f) << 16) | + (val & 0xffff), &adap_mdio->useraccess0);
/* Wait for command to complete */ while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO) @@ -139,12 +143,12 @@ int keystone2_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data) /* PHY functions for a generic PHY */ static int gen_get_link_speed(int phy_addr) { - u_int16_t tmp; + u_int16_t tmp;
- if ((!keystone2_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp)) && - (tmp & 0x04)) { + tmp = mdio_bus->read(mdio_bus, phy_addr, + MDIO_DEVAD_NONE, MII_STATUS_REG); + if (tmp & 0x04) return 0; - }
return -1; } @@ -156,8 +160,10 @@ static void __attribute__((unused)) struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv;
if (sys_has_mdio) { - if (keystone2_eth_phy_read(eth_priv->phy_addr, 0, &data) || - !(data & (1 << 6))) /* speed selection MSB */ + data = keystone2_mdio_read(mdio_bus, eth_priv->phy_addr, + MDIO_DEVAD_NONE, 0); + /* speed selection MSB */ + if (!(data & (1 << 6))) return; }
@@ -435,7 +441,7 @@ static int keystone2_eth_open(struct eth_device *dev, bd_t *bis) hw_config_streaming_switch();
if (sys_has_mdio) { - keystone2_mdio_reset(); + keystone2_mdio_reset(mdio_bus); udelay(1000);
link = keystone_get_link_status(dev); @@ -519,6 +525,7 @@ static int keystone2_eth_rcv_packet(struct eth_device *dev) */ int keystone2_emac_initialize(struct eth_priv_t *eth_priv) { + int res; struct eth_device *dev;
dev = malloc(sizeof(struct eth_device)); @@ -540,6 +547,20 @@ int keystone2_emac_initialize(struct eth_priv_t *eth_priv)
eth_register(dev);
+ /* Register MDIO bus if it's not registered yet */ + if (!mdio_bus) { + mdio_bus = mdio_alloc(); + mdio_bus->read = keystone2_mdio_read; + mdio_bus->write = keystone2_mdio_write; + mdio_bus->reset = keystone2_mdio_reset; + mdio_bus->priv = (void *)EMAC_MDIO_BASE_ADDR; + sprintf(mdio_bus->name, "ethernet-mdio"); + + res = mdio_register(mdio_bus); + if (res) + return res; + } + return 0; }

As MDIO bus has been added we can register PHYs on it. Register only for SGMII ports connected with appropriate PHY. After registration, the PHY driver will be probed according to the hardware on board.
Signed-off-by: Ivan Khoronzhuk ivan.khoronzhuk@ti.com --- drivers/net/keystone_net.c | 14 ++++++++++++++ include/configs/ks2_evm.h | 2 ++ 2 files changed, 16 insertions(+)
diff --git a/drivers/net/keystone_net.c b/drivers/net/keystone_net.c index 6f7cc17..5789045 100644 --- a/drivers/net/keystone_net.c +++ b/drivers/net/keystone_net.c @@ -10,6 +10,7 @@ #include <command.h>
#include <net.h> +#include <phy.h> #include <miiphy.h> #include <malloc.h> #include <asm/ti-common/keystone_nav.h> @@ -527,6 +528,7 @@ int keystone2_emac_initialize(struct eth_priv_t *eth_priv) { int res; struct eth_device *dev; + struct phy_device *phy_dev;
dev = malloc(sizeof(struct eth_device)); if (dev == NULL) @@ -561,6 +563,18 @@ int keystone2_emac_initialize(struct eth_priv_t *eth_priv) return res; }
+ /* Don't add ports that hasn't PHY */ + if (eth_priv->sgmii_link_type != SGMII_LINK_MAC_MAC_FORCED) { + /* Find a phy by address and register it */ + phy_dev = phy_connect(mdio_bus, eth_priv->phy_addr, + dev, PHY_INTERFACE_MODE_SGMII); + + if (phy_dev) + phy_config(phy_dev); + else + return -1; + } + return 0; }
diff --git a/include/configs/ks2_evm.h b/include/configs/ks2_evm.h index 2e781b9..af84abc 100644 --- a/include/configs/ks2_evm.h +++ b/include/configs/ks2_evm.h @@ -94,6 +94,8 @@ #define CONFIG_SYS_SPI2_NUM_CS 4
/* Network Configuration */ +#define CONFIG_PHYLIB +#define CONFIG_PHY_MARVELL #define CONFIG_MII #define CONFIG_BOOTP_DEFAULT #define CONFIG_BOOTP_DNS

The phy framework has function to get link, so use it instead of own implementation.
There is no reason to check SGMII link while sending each packet, phy link is enough. Check SGMII link only while ethernet open.
Signed-off-by: Ivan Khoronzhuk ivan.khoronzhuk@ti.com --- arch/arm/include/asm/ti-common/keystone_net.h | 1 + drivers/net/keystone_net.c | 41 +++++++++++---------------- 2 files changed, 17 insertions(+), 25 deletions(-)
diff --git a/arch/arm/include/asm/ti-common/keystone_net.h b/arch/arm/include/asm/ti-common/keystone_net.h index e56759d..011c03c 100644 --- a/arch/arm/include/asm/ti-common/keystone_net.h +++ b/arch/arm/include/asm/ti-common/keystone_net.h @@ -239,6 +239,7 @@ struct eth_priv_t { int phy_addr; int slave_port; int sgmii_link_type; + struct phy_device *phy_dev; };
int keystone2_emac_initialize(struct eth_priv_t *eth_priv); diff --git a/drivers/net/keystone_net.c b/drivers/net/keystone_net.c index 5789045..e3268da 100644 --- a/drivers/net/keystone_net.c +++ b/drivers/net/keystone_net.c @@ -42,12 +42,6 @@ struct rx_buff_desc net_rx_buffs = {
static void keystone2_net_serdes_setup(void);
-static int gen_get_link_speed(int phy_addr); - -/* EMAC Addresses */ -static volatile struct mdio_regs *adap_mdio = - (struct mdio_regs *)EMAC_MDIO_BASE_ADDR; - int keystone2_eth_read_mac_addr(struct eth_device *dev) { struct eth_priv_t *eth_priv; @@ -141,19 +135,6 @@ static int keystone2_mdio_write(struct mii_dev *bus, return 0; }
-/* PHY functions for a generic PHY */ -static int gen_get_link_speed(int phy_addr) -{ - u_int16_t tmp; - - tmp = mdio_bus->read(mdio_bus, phy_addr, - MDIO_DEVAD_NONE, MII_STATUS_REG); - if (tmp & 0x04) - return 0; - - return -1; -} - static void __attribute__((unused)) keystone2_eth_gigabit_enable(struct eth_device *dev) { @@ -184,13 +165,15 @@ int keystone_sgmii_link_status(int port)
status = __raw_readl(SGMII_STATUS_REG(port));
- return status & SGMII_REG_STATUS_LINK; + return (status & SGMII_REG_STATUS_LOCK) && + (status & SGMII_REG_STATUS_LINK); }
int keystone_get_link_status(struct eth_device *dev) { struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv; + struct phy_device *phy_dev = eth_priv->phy_dev; int sgmii_link; int link_state = 0; #if CONFIG_GET_LINK_STATUS_ATTEMPTS > 1 @@ -206,8 +189,8 @@ int keystone_get_link_status(struct eth_device *dev) link_state = 1;
if (eth_priv->sgmii_link_type == SGMII_LINK_MAC_PHY) - if (gen_get_link_speed(eth_priv->phy_addr)) - link_state = 0; + if (!genphy_update_link(phy_dev)) + link_state = phy_dev->link; } #if CONFIG_GET_LINK_STATUS_ATTEMPTS > 1 } @@ -491,9 +474,15 @@ static int keystone2_eth_send_packet(struct eth_device *dev, { int ret_status = -1; struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv; + struct phy_device *phy_dev = eth_priv->phy_dev;
- if (keystone_get_link_status(dev) == 0) + if (phy_dev) { + genphy_update_link(phy_dev); + if (phy_dev->link == 0) + return -1; + } else { return -1; + }
if (cpmac_drv_send((u32 *)packet, length, eth_priv->slave_port) != 0) return ret_status; @@ -569,10 +558,12 @@ int keystone2_emac_initialize(struct eth_priv_t *eth_priv) phy_dev = phy_connect(mdio_bus, eth_priv->phy_addr, dev, PHY_INTERFACE_MODE_SGMII);
- if (phy_dev) + if (phy_dev) { + eth_priv->phy_dev = phy_dev; phy_config(phy_dev); - else + } else { return -1; + } }
return 0;
participants (1)
-
Ivan Khoronzhuk