单片机
返回首页

[Linux 底层]U-boot ksz8081网络驱动调试

2022-07-14 来源:csdn

micrel公司一款优秀的PHY芯片,关于芯片的介绍参考:


[Datasheet PHY] ksz8081数据手册解读


系统版本:Ubuntu18.04-64


编译器版本:gcc version 7.4.0 (Ubuntu/Linaro 7.4.0-1ubuntu1~18.04.1)


uboot版本:2018.07 -linux4sam_6.0


板子型号:at91sama5d3x-xplained


MCU型号:sama5d36


与ksz9031很相似,公众部分可参考:


1、如何找到uboot官网开发板默认配置文件路径


2、如何进行公共信息配置


3、如何核对开发板硬件的参数


4、如何对uboot功能进行裁剪


5、设备树文件存放位置,及IO配置


6、网卡初始化流程,程序入口如何调用驱动文件接口;


[Linux 底层]U-boot ksz9031网络驱动调试


关注微信公众号,回复“ksz8081驱动”,免费下载ksz8081的驱动源代码。


硬件参考图如下:


1、设备树更改


phy-mode = “rmii”; PHY的接口方式为RMII 外部需要提供50MHZ时钟,或者通过内部倍频;


gpios,因为硬件设计上,把芯片的电源和RST单独控制,可给芯片复位,或者进行上下电操作;可在应用层进行调用;


            macb1: ethernet@f802c000 {

                phy-mode = 'rmii';

                #address-cells = <1>;

                #size-cells = <0>;

                pinctrl-0 = <&pinctrl_mcb1_rst >;

                status = 'okay';

                gpios = <

                    &pioC   18 GPIO_ACTIVE_HIGH ///poweren

                    &pioC   31 GPIO_ACTIVE_HIGH ///rst

                    >;

                ethernet-phy@1 {

                    reg = <0x1>;

                };

            };


2、驱动初始化函数入口


#ifdef CONFIG_PHY_MICREL_KSZ8XXX

    phy_micrel_ksz8xxx_init();

#endif



int phy_micrel_ksz8xxx_init(void)

{

    printf('phy_micrel_ksz8xxx_init KSZ8081_drivern');

    phy_register(&KSZ804_driver);

    phy_register(&KSZ8031_driver);

    phy_register(&KSZ8051_driver);

    phy_register(&KSZ8081_driver);

    phy_register(&KS8721_driver);

    phy_register(&ksz8895_driver);

    phy_register(&ksz886x_driver);

    return 0;

}


50MHz晶振


static struct phy_driver KSZ8081_driver = {

    .name = 'Micrel KSZ8081',

    .uid = 0x221560,

    .mask = 0xfffff0,

    .features = PHY_BASIC_FEATURES,

    .config = &ksz_8081_config,  //配置函数进行了重构,因为外部使用50M晶振,官网使用25M晶振

    .startup = &genphy_startup,

    .shutdown = &genphy_shutdown,

};


static int ksz_8081_config(struct phy_device *phydev)

{

    int ret;


    int regval;


    //50M晶振配置

    regval = phy_read(phydev, MDIO_DEVAD_NONE,MII_KSZPHY_CTRL);

    regval |= KSZ8051_RMII_50MHZ_CLK;

    phy_write(phydev, MDIO_DEVAD_NONE,MII_KSZPHY_CTRL, regval);

    printf(' ksz_8081_config MII_KSZPHY_CTRL(0x1f) =0x%xn',regval);


    ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO);

    if (ret < 0)

        return ret;


    ret |= KSZPHY_OMSO_B_CAST_OFF;

    //ret &= ~KSZPHY_OMSO_B_CAST_OFF;

    printf(' ksz_8081_config MII_KSZPHY_OMSO(0x16) =0x%xn',ret);

    ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO,

            ret);

    if (ret < 0)

        return ret;



    return genphy_config(phydev);

}


int genphy_config(struct phy_device *phydev)

{

    int val;

    u32 features;


    features = (SUPPORTED_TP | SUPPORTED_MII

            | SUPPORTED_AUI | SUPPORTED_FIBRE |

            SUPPORTED_BNC);


    /* Do we support autonegotiation? */

    val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);


    printf('genphy_config phyaddr=%d,MII_BMSR(%d)=0x%xn',phydev->addr,MII_BMSR,val);

    if (val < 0)

        return val;


    if (val & BMSR_ANEGCAPABLE)

        features |= SUPPORTED_Autoneg;


    if (val & BMSR_100FULL)

        features |= SUPPORTED_100baseT_Full;

    if (val & BMSR_100HALF)

        features |= SUPPORTED_100baseT_Half;

    if (val & BMSR_10FULL)

        features |= SUPPORTED_10baseT_Full;

    if (val & BMSR_10HALF)

        features |= SUPPORTED_10baseT_Half;


    if (val & BMSR_ESTATEN) {

        val = phy_read(phydev, MDIO_DEVAD_NONE, MII_ESTATUS);

        printf('genphy_config phyaddr=%d,MII_ESTATUS(%d)=0x%xn',phydev->addr,MII_ESTATUS,val);

        if (val < 0)

            return val;


        if (val & ESTATUS_1000_TFULL)

            features |= SUPPORTED_1000baseT_Full;

        if (val & ESTATUS_1000_THALF)

            features |= SUPPORTED_1000baseT_Half;

        if (val & ESTATUS_1000_XFULL)

            features |= SUPPORTED_1000baseX_Full;

        if (val & ESTATUS_1000_XHALF)

            features |= SUPPORTED_1000baseX_Half;

    }


    phydev->supported &= features;

    phydev->advertising &= features;


    genphy_config_aneg(phydev);


    return 0;

}


/**

 * genphy_config_aneg - restart auto-negotiation or write BMCR

 * @phydev: target phy_device struct

 *

 * Description: If auto-negotiation is enabled, we configure the

 *   advertising, and then restart auto-negotiation.  If it is not

 *   enabled, then we write the BMCR.

 */

int genphy_config_aneg(struct phy_device *phydev)

{

    int result;

    int ival = 0;


    if (phydev->autoneg != AUTONEG_ENABLE)

        return genphy_setup_forced(phydev);

#if 0

    //set loopback

    //Reg 0

    ival |= (1 << 14 );

    ival |= (1 << 6 );

    ival &= ~(1 << 13 );

    ival &= ~(1 << 12 );

    ival |= (1 << 8 );

    phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_ANENABLE & (~(1<<6)));

#endif

    printf('genphy_config_aneg ival = 0x%x,test1111.n',ival);

    result = genphy_config_advert(phydev);


    if (result < 0) /* error */

    {

        return result;

    }


    printf('genphy_config_aneg result=%d test2222.n',result);

    if (result == 0) {

        /*

         * Advertisment hasn't changed, but maybe aneg was never on to

         * begin with?  Or maybe phy was isolated?

         */

        int ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);

        printf('genphy_config_aneg MII_BMCR, ctl=0x%xn',ctl);

        if (ctl < 0)

            return ctl;


        if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))

            result = 1; /* do restart aneg */

    }


    /*

     * Only restart aneg if we are advertising something different

     * than we were before.

     */

    if (result > 0)

    {

        printf('genphy_config_aneg test3333.n');

        result = genphy_restart_aneg(phydev);

    }


    return result;

}


3、编译之后,把u-boot.bin文件下载到板子,运行打印信息如下:


U-Boot 2018.07-linux4sam_6.0 (Oct 11 2020 - 23:57:20 -0700)


CPU: SAMA5D36

Crystal frequency:       12 MHz

CPU clock        :      528 MHz

Master clock     :      132 MHz

DRAM:  256 MiB

NAND:  256 MiB

MMC:   Atmel mci: 0, Atmel mci: 1

Loading Environment from NAND... OK

In:    serial@ffffee00

Out:   serial@ffffee00

Err:   serial@ffffee00

Netjack:   macb_eth_probe phy-mode=mii,devname=ethernet@f0028000

eth0: ethernet@f0028000 [PRIME]macb_eth_probe phy-mode=rmii,devname=ethernet@f802c000

, eth1: ethernet@f802c000

Hit any key to stop autoboot:  0 

=> pri

打印出phy-mode=rmii是从设备树里面读取的信息;


使用ping命令进行验证,是否能够正常通讯;


=> ping 192.168.2.108

CONFIG_DM_ETH _macb_init MACB_BIT(RMII) | MACB_BIT(CLKEN)

ethernet@f802c000: PHY present at 1,phy_id=0x22,macb->phy_addr=1

macb_phy_init name=ethernet@f802c000,phy_addr=1,ret=0

 ksz_8081_config MII_KSZPHY_CTRL(0x1f) =0x8180

 ksz_8081_config MII_KSZPHY_OMSO(0x16) =0x202

ethernet@f802c000: Starting autonegotiation...

ethernet@f802c000: Autonegotiation complete

ethernet@f802c000: link up, 100Mbps full-duplex (lpa: 0xcde1)

macb_phy_init udelay(3000)

Using ethernet@f802c000 device

gmacb send

ff ff ff ff ff ff aa ab c1 d2 e6 c6 08 06 00 01 08 00 06 04 00 01 aa ab c1 d2 e6 c6 c0 a8 01 64 00 00 00 00 00 00 c0 a8 02 6c 

 _macb_recv paddr=0x2fb6bec0, length=64,phy_addr=1

 _macb_recv paddr=0x2fb6bf40, length=64,phy_addr=1

 _macb_recv paddr=0x2fb6bfc0, length=64,phy_addr=1

 _macb_recv paddr=0x2fb6c040, length=64,phy_addr=1

 _macb_recv paddr=0x2fb6c0c0, length=64,phy_addr=1

 _macb_recv paddr=0x2fb6c140, length=64,phy_addr=1

 _macb_recv paddr=0x2fb6c1c0, length=114,phy_addr=1

 _macb_recv paddr=0x2fb6c240, length=64,phy_addr=1

 _macb_recv paddr=0x2fb6c2c0, length=64,phy_addr=1

gmacb send

ff ff ff ff ff ff aa ab c1 d2 e6 c6 08 06 00 01 08 00 06 04 00 01 aa ab c1 d2 e6 c6 c0 a8 01 64 00 00 00 00 00 00 c0 a8 02 6c 

 _macb_recv paddr=0x2fb6c340, length=96,phy_addr=1

 _macb_recv paddr=0x2fb6c3c0, length=64,phy_addr=1

 _macb_recv paddr=0x2fb6c4c0, length=64,phy_addr=1

 _macb_recv paddr=0x2fb6c5c0, length=64,phy_addr=1

 _macb_recv paddr=0x2fb6c640, length=96,phy_addr=1

gmacb send

ff ff ff ff ff ff aa ab c1 d2 e6 c6 08 06 00 01 08 00 06 04 00 01 aa ab c1 d2 e6 c6 c0 a8 01 64 00 00 00 00 00 00 c0 a8 02 6c 

 _macb_recv paddr=0x2fb6c740, length=96,phy_addr=1

 _macb_recv paddr=0x2fb6c7c0, length=96,phy_addr=1

 _macb_recv paddr=0x2fb6c840, length=96,phy_addr=1

 _macb_recv paddr=0x2fb6c8c0, length=96,phy_addr=1

 _macb_recv paddr=0x2fb6c940, length=96,phy_addr=1

 _macb_recv paddr=0x2fb6c9c0, length=96,phy_addr=1

 _macb_recv paddr=0x2fb6cac0, length=64,phy_addr=1

gmacb send

ff ff ff ff ff ff aa ab c1 d2 e6 c6 08 06 00 01 08 00 06 04 00 01 aa ab c1 d2 e6 c6 c0 a8 01 64 00 00 00 00 00 00 c0 a8 02 6c 

 _macb_recv paddr=0x2fb6cb40, length=96,phy_addr=1

 _macb_recv paddr=0x2fb6cbc0, length=96,phy_addr=1

 _macb_recv paddr=0x2fb6cc40, length=96,phy_addr=1

 _macb_recv paddr=0x2fb6ccc0, length=64,phy_addr=1

 _macb_recv paddr=0x2fb6cd41, length=64,phy_addr=1

 _macb_recv paddr=0x2fb6cdc3, length=64,phy_addr=1

 _macb_recv paddr=0x2fb6be41, length=64,phy_addr=1

 _macb_recv paddr=0x2fb6bec0, length=64,phy_addr=1

 _macb_recv paddr=0x2fb6bf40, length=96,phy_addr=1

 _macb_recv paddr=0x2fb6bfc0, length=96,phy_addr=1

 _macb_recv paddr=0x2fb6c040, length=96,phy_addr=1


ARP Retry count exceeded; starting again

ping failed; host 192.168.2.108 is not alive

=> 


根据以上信息可以看出,网络不通;驱动还是有问题;


=> ping 192.168.2.108

CONFIG_DM_ETH _macb_init MACB_BIT(RMII) | MACB_BIT(CLKEN)

//phy_id核对是正确的,地址是OK

ethernet@f802c000: PHY present at 1,phy_id=0x22,macb->phy_addr=1

//控制寄存器值正常;

macb_phy_init name=ethernet@f802c000,phy_addr=1,ret=0

 ksz_8081_config MII_KSZPHY_CTRL(0x1f) =0x8180

 ksz_8081_config MII_KSZPHY_OMSO(0x16) =0x202

ethernet@f802c000: Starting autonegotiation...

ethernet@f802c000: Autonegotiation complete

ethernet@f802c000: link up, 100Mbps full-duplex (lpa: 0xcde1)

//自适应到网络连接,100M全双工

macb_phy_init udelay(3000)

//怀疑是MCU初始化的时序不同步,加了3000ms的延时,还是无效

Using ethernet@f802c000 device


4、后面想应该是初始化程序运行时,PHY芯片还没自检完成导致,因为芯片上电需要IO控制,需要加载起dts中的gpios的电源脚初始化芯片才能有电;


进行电源提前上电和RST提前拉成高电平尝试;


在初始化中添加GPIO的控制;


//PHY 9031的RESET脚使用CPU控制,PHY 8081的电源和RESET使用CPU控制

board/atmel/sama5d3_xplained/sama5d3_xplained.c

添加代码


static void sama5d3_xplained_phy_hw_init(void)

{

    at91_set_pio_periph(AT91_PIO_PORTE, 9, 1);      /* GPIO output up*/

    at91_set_pio_periph(AT91_PIO_PORTC, 18, 1);         /* GPIO output up*/

    at91_set_pio_periph(AT91_PIO_PORTC, 31, 1);         /* GPIO output up*/

    at91_set_pio_periph(AT91_PIO_PORTB, 12, 1);         /* LED GPIO output up*/


    at91_set_pio_output(AT91_PIO_PORTE, 9, 1);      //micrel ksz9031 reset gpio

    at91_set_pio_output(AT91_PIO_PORTC, 18, 0);     //micrel ksz8081 power gpio

    at91_set_pio_output(AT91_PIO_PORTC, 31, 1);     //micrel ksz8081 reset gpio


    at91_set_pio_output(AT91_PIO_PORTB, 12, 0);     //Board led on

}


int board_init(void)

{

    /* adress of boot parameters */

    gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;


#ifdef CONFIG_NAND_ATMEL

    sama5d3_xplained_nand_hw_init();

#endif

#ifdef CONFIG_CMD_USB

    sama5d3_xplained_usb_hw_init();

#endif

#ifdef CONFIG_GENERIC_ATMEL_MCI

    sama5d3_xplained_mci0_hw_init();

#endif


    // add by for xkk phy init gpio

    sama5d3_xplained_phy_hw_init();


    return 0;

}


编译之后烧录,验证网卡调通,使用ksz8081下载ftp程序如下:


U-Boot 2018.07-linux4sam_6.0 (Sep 29 2020 - 20:40:44 -0700)


CPU: SAMA5D36

Crystal frequency:       12 MHz

CPU clock        :      528 MHz

Master clock     :      132 MHz

DRAM:  256 MiB

NAND:  256 MiB

MMC:   Atmel mci: 0, Atmel mci: 1

Loading Environment from NAND... OK

In:    serial@ffffee00

Out:   serial@ffffee00

Err:   serial@ffffee00

Netjack:   macb_eth_probe phy-mode=mii,devname=ethernet@f0028000

eth0: ethernet@f0028000macb_eth_probe phy-mode=rmii,devname=ethernet@f802c000


Error: ethernet@f802c000 address not set.

, eth-1: ethernet@f802c000

Hit any key to stop autoboot:  0 

ethernet@f0028000: PHY present at 0

ethernet@f0028000: Starting autonegotiation...

ethernet@f0028000: Autonegotiation complete

ethernet@f0028000: link up, 100Mbps full-duplex (lpa: 0xcde1)

Using ethernet@f0028000 device

TFTP from server 192.168.1.108; our IP address is 192.168.1.100

Filename 'at91-sama5d3_xplained.dtb'.

Load address: 0x21000000

Loading: ####

         375 KiB/s

done

Bytes transferred = 49969 (c331 hex)

ethernet@f0028000: PHY present at 0

ethernet@f0028000: Starting autonegotiation...

ethernet@f0028000: Autonegotiation complete

ethernet@f0028000: link up, 100Mbps full-duplex (lpa: 0xcde1)

Using ethernet@f0028000 device

TFTP from server 192.168.1.108; our IP address is 192.168.1.100

Filename 'zImage'.

Load address: 0x22000000

Loading: #################################################################

         #################################################################

         #################################################################

         #################################################################

         #######################

         753.9 KiB/s

done

Bytes transferred = 4149536 (3f5120 hex)

## Flattened Device Tree blob at 21000000

   Booting using the fdt blob at 0x21000000

   Loading Device Tree to 2fb06000, end 2fb15330 ... OK

进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • PIC单片机控制的遥控防盗报警器电路

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • 用NE555制作定时器

  • 如何构建一个触摸传感器电路

  • 基于ICL296的大电流开关稳压器电源电路

  • 基于TDA2003的简单低功耗汽车立体声放大器电路

    相关电子头条文章