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

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_driver\n");
    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%x\n",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%x\n",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%x\n",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%x\n",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%x\n",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

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

![](https://img-blog.csdnimg.cn/20210302131417549.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzc3MTg1Mw==,size_16,color_FFFFFF,t_70)

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CS4334-KSZ 是一款音频数字转换器(ADC/DAC),通常用于音频系统中。下面是该芯片的详细驱动程序。 1. 注册定义 首先,需要定义一些寄存器地址和值,以便在驱动程序中使用。例如: ``` #define CS4334_KSZ_REG_CONTROL 0x00 #define CS4334_KSZ_REG_STATUS 0x01 #define CS4334_KSZ_REG_DAC_L 0x02 #define CS4334_KSZ_REG_DAC_R 0x03 #define CS4334_KSZ_REG_ADC_L 0x04 #define CS4334_KSZ_REG_ADC_R 0x05 #define CS4334_KSZ_CONTROL_PD 0x80 #define CS4334_KSZ_CONTROL_MUTE 0x40 #define CS4334_KSZ_CONTROL_DEEMPH 0x20 #define CS4334_KSZ_CONTROL_FS 0x10 ``` 2. 初始化 在初始化时,需要配置一些寄存器,例如控制寄存器(Control Register),以启用 DAC 和 ADC: ``` void cs4334_ksz_init(void) { // Enable DAC and ADC i2c_write_byte(CS4334_KSZ_ADDRESS, CS4334_KSZ_REG_CONTROL, CS4334_KSZ_CONTROL_PD); } ``` 3. 写入 DAC 数据 要将数字音频数据写入 DAC,需要使用两个寄存器:DAC_L 和 DAC_R。下面是一个简单的例子: ``` void cs4334_ksz_write_dac(uint16_t left, uint16_t right) { i2c_write_byte(CS4334_KSZ_ADDRESS, CS4334_KSZ_REG_DAC_L, left >> 8); i2c_write_byte(CS4334_KSZ_ADDRESS, CS4334_KSZ_REG_DAC_L + 1, left & 0xFF); i2c_write_byte(CS4334_KSZ_ADDRESS, CS4334_KSZ_REG_DAC_R, right >> 8); i2c_write_byte(CS4334_KSZ_ADDRESS, CS4334_KSZ_REG_DAC_R + 1, right & 0xFF); } ``` 4. 读取 ADC 数据 要从 ADC 读取数据,需要使用 ADC_L 和 ADC_R 寄存器。例如: ``` void cs4334_ksz_read_adc(uint16_t* left, uint16_t* right) { uint8_t buf[2]; i2c_read_bytes(CS4334_KSZ_ADDRESS, CS4334_KSZ_REG_ADC_L, buf, 2); *left = (buf[0] << 8) | buf[1]; i2c_read_bytes(CS4334_KSZ_ADDRESS, CS4334_KSZ_REG_ADC_R, buf, 2); *right = (buf[0] << 8) | buf[1]; } ``` 这些就是 CS4334-KSZ 的基本驱动程序。当然,具体的实现可能因平台和应用而异,这里只是提供一个基本的框架。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值