Linux内核(五) [ RK3568 ] PHY驱动框架解析 —— MDIO总线

本文介绍RK3568平台网口驱动的结构体定义、设备树配置及驱动流程。涵盖mac操作函数集、mac资源数据等关键结构体,并详细解析设备树配置与驱动初始化过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

平台:RK3568 内核版本4.19.194

网口驱动相关结构体

// 不同平台的mac操作函数集结构体
struct rk_gmac_ops {
    void (*set_to_rgmii)(struct rk_priv_data *bsp_priv,
                 int tx_delay, int rx_delay);
    void (*set_to_rmii)(struct rk_priv_data *bsp_priv);
    void (*set_to_sgmii)(struct rk_priv_data *bsp_priv);
    void (*set_to_qsgmii)(struct rk_priv_data *bsp_priv);
    void (*set_rgmii_speed)(struct rk_priv_data *bsp_priv, int speed);
    void (*set_rmii_speed)(struct rk_priv_data *bsp_priv, int speed);
    void (*integrated_phy_powerup)(struct rk_priv_data *bsp_priv);
};

// mac资源数据
struct stmmac_resources {
    void __iomem *addr;
    const char *mac;
    int wol_irq;
    int lpi_irq;
    int irq;
};

struct plat_stmmacenet_data {
    int bus_id;
    int phy_addr;
    int interface;
    struct stmmac_mdio_bus_data *mdio_bus_data;
    struct device_node *phy_node;
    struct device_node *mdio_node;
    struct stmmac_dma_cfg *dma_cfg;
    int clk_csr;
    int has_gmac;
    int enh_desc;
    int tx_coe;
    int rx_coe;
    int bugged_jumbo;
    int pmt;
    int force_sf_dma_mode;
    int force_thresh_dma_mode;
    int riwt_off;
    int max_speed;
    int maxmtu;
    int multicast_filter_bins;
    int unicast_filter_entries;
    int tx_fifo_size;
    int rx_fifo_size;
    u32 rx_queues_to_use;
    u32 tx_queues_to_use;
    u8 rx_sched_algorithm;
    u8 tx_sched_algorithm;
    struct stmmac_rxq_cfg rx_queues_cfg[MTL_MAX_RX_QUEUES];
    struct stmmac_txq_cfg tx_queues_cfg[MTL_MAX_TX_QUEUES];
    void (*fix_mac_speed)(void *priv, unsigned int speed);
    int (*init)(struct platform_device *pdev, void *priv);
    void (*exit)(struct platform_device *pdev, void *priv);
    void (*get_eth_addr)(void *priv, unsigned char *addr);
    struct mac_device_info *(*setup)(void *priv);
    void *bsp_priv;
    struct clk *stmmac_clk;
    struct clk *pclk;
    struct clk *clk_ptp_ref;
    unsigned int clk_ptp_rate;
    unsigned int clk_ref_rate;
    struct reset_control *stmmac_rst;
    struct stmmac_axi *axi;
    int has_gmac4;
    bool has_sun8i;
    bool tso_en;
    int mac_port_sel_speed;
    bool en_tx_lpi_clockgating;
    int has_xgmac;
};

设备树配置与解析

// RK3568设备树配置
gmac0: ethernet@fe2a0000 {
    compatible = "rockchip,rk3568-gmac", "snps,dwmac-4.20a";
    reg = <0x0 0xfe2a0000 0x0 0x10000>;
    interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>,
             <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
    interrupt-names = "macirq", "eth_wake_irq";
    rockchip,grf = <&grf>;
    clocks = <&cru SCLK_GMAC0>, <&cru SCLK_GMAC0_RX_TX>,
         <&cru SCLK_GMAC0_RX_TX>, <&cru CLK_MAC0_REFOUT>,
         <&cru ACLK_GMAC0>, <&cru PCLK_GMAC0>,
         <&cru SCLK_GMAC0_RX_TX>, <&cru CLK_GMAC0_PTP_REF>,
         <&cru PCLK_XPCS>;
    clock-names = "stmmaceth", "mac_clk_rx",
              "mac_clk_tx", "clk_mac_refout",
              "aclk_mac", "pclk_mac",
              "clk_mac_speed", "ptp_ref",
              "pclk_xpcs";
    resets = <&cru SRST_A_GMAC0>;
    reset-names = "stmmaceth";

    snps,mixed-burst;
    snps,tso;

    snps,axi-config = <&gmac0_stmmac_axi_setup>;
    snps,mtl-rx-config = <&gmac0_mtl_rx_setup>;
    snps,mtl-tx-config = <&gmac0_mtl_tx_setup>;
    status = "disabled";

    mdio0: mdio {
        compatible = "snps,dwmac-mdio";
        #address-cells = <0x1>;
        #size-cells = <0x0>;
    };

    gmac0_stmmac_axi_setup: stmmac-axi-config {
        snps,wr_osr_lmt = <4>;
        snps,rd_osr_lmt = <8>;
        snps,blen = <0 0 0 0 16 8 4>;
    };

    gmac0_mtl_rx_setup: rx-queues-config {
        snps,rx-queues-to-use = <1>;
        queue0 {};
    };

    gmac0_mtl_tx_setup: tx-queues-config {
        snps,tx-queues-to-use = <1>;
        queue0 {};
    };
};

&gmac0 {
    phy-mode = "rgmii";              // rgmii或rmii pinctrl-0必须与之相匹配
    clock_in_out = "output";         // output 时钟由MAC输入给PHY  input与之相反

    snps,reset-gpio = <&gpio2 RK_PC5 GPIO_ACTIVE_LOW>;     // 用于复位PHY的GPIO
    snps,reset-active-low;           // 复位PHY的GPIO低电平有效
    snps,reset-delays-us = <0 30000 150000>;   // 复位PHY之前延时0ms  拉低维持的时间为30ms 拉高后延时150ms

    assigned-clocks = <&cru SCLK_GMAC0_RX_TX>, <&cru SCLK_GMAC0>;   // MAC时钟源
    assigned-clock-parents = <&cru SCLK_GMAC0_RGMII_SPEED>, <&cru CLK_MAC0_2TOP>;    // MAC父时钟源
    assigned-clock-rates = <0>, <125000000>;   // MAC时钟频率

    pinctrl-names = "default";
    pinctrl-0 = <&gmac0_miim              // 设置PHY的各个引脚
             &gmac0_tx_bus2
             &gmac0_rx_bus2
             &gmac0_rgmii_clk
             &gmac0_rgmii_bus>;

    tx_delay = <0x25>;           // 收发延时 只有在rgmii模式下才需要配置该属性
    rx_delay = <0x15>;

    phy-handle = <&rgmii_phy0>;     // 与mdio总线相连
    status = "disabled";
};

&mdio0 {
    rgmii_phy0: phy@2 {      // 连接某个phy 以及phy硬件地址
        compatible = "ethernet-phy-ieee802.3-c22";      // mdio和PHY之间的通信协议为22
        reg = <0x2>;       // phy硬件地址与与硬件上的phy地址相对应
    };
};

// 电压域配置  查看原理图phy是从哪个io接出来的  vccio6 其电压为3.3V
&pmu_io_domains {
    status = "okay";
        pmuio1-supply = <&vcc3v3_pmu>;
    pmuio2-supply = <&vcc3v3_pmu>;
    vccio1-supply = <&vccio_acodec>;
    vccio3-supply = <&vccio_sd>;
    vccio4-supply = <&vcc_3v3>;
    vccio5-supply = <&vcc_3v3>;
    vccio6-supply = <&vcc_3v3>;
    vccio7-supply = <&vcc_3v3>;
};

驱动流程详解

通过上面的设备树匹配了平台设备。路径:kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c

static const struct of_device_id rk_gmac_dwmac_match[] = {
    { .compatible = "rockchip,px30-gmac",   .data = &px30_ops   },
    { .compatible = "rockchip,rk1808-gmac", .data = &rk1808_ops },
    { .compatible = "rockchip,rk3128-gmac", .data = &rk3128_ops },
    { .compatible = "rockchip,rk3228-gmac", .data = &rk3228_ops },
    { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_ops },
    { .compatible = "rockchip,rk3308-mac",  .data = &rk3308_ops },
    { .compatible = "rockchip,rk3328-gmac", .data = &rk3328_ops },
    { .compatible = "rockchip,rk3366-gmac", .data = &rk3366_ops },
    { .compatible = "rockchip,rk3368-gmac", .data = &rk3368_ops },
    { .compatible = "rockchip,rk3399-gmac", .data = &rk3399_ops },
    { .compatible = "rockchip,rk3568-gmac", .data = &rk3568_ops },
    { .compatible = "rockchip,rv1108-gmac", .data = &rv1108_ops },
    { .compatible = "rockchip,rv1126-gmac", .data = &rv1126_ops },
    { }
};
MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_match);

static struct platform_driver rk_gmac_dwmac_driver = {
    .probe  = rk_gmac_probe,
    .remove = rk_gmac_remove,
    .driver = {
        .name           = "rk_gmac-dwmac",
        .pm     = &rk_gmac_pm_ops,
        .of_match_table = rk_gmac_dwmac_match,
    },
};
module_platform_driver(rk_gmac_dwmac_driver);

// RK3568 date操作函数集
rk_gmac_probe
    -> of_device_get_match_data      // 返回的是匹配的of_device_id的 rk_gmac_ops *data
    -> stmmac_get_platform_resources(pdev, &stmmac_res);  // 利用设备树中资源给stmmac_res赋值
        -> stmmac_res->irq = platform_get_irq_byname(pdev, "macirq");        // 名字和设备树上的对应
        -> stmmac_res->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
        -> stmmac_res->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
        -> platform_get_resource(pdev, IORESOURCE_MEM, 0);                   // 得到IORESOURCE_MEM资源
        -> stmmac_res->addr = devm_ioremap_resource(&pdev->dev, res);        // 映射后填充stmmac_res
    -> plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);             // 填充plat_stmmacenet_data *plat_dat
        -> *mac = of_get_mac_address(np);                                    // mac地址
        -> plat->interface = of_get_phy_mode(np);                            // phy接口
        -> of_property_read_u32(np, "max-speed", &plat->max_speed)           // 最大速度
        ......
    -> plat_dat->fix_mac_speed = rk_fix_speed;
    -> plat_dat->get_eth_addr = rk_get_eth_addr;
    -> plat_dat->bsp_priv = rk_gmac_setup(pdev, plat_dat, data);              // 分配填充bsp_priv然后放到plat_dat->bsp_priv
        -> bsp_priv = devm_kzalloc(dev, sizeof(*bsp_priv), GFP_KERNEL);       // 分配结构体
        -> bsp_priv->phy_iface = of_get_phy_mode(dev->of_node);               // 接口类型
        -> of_property_read_string(dev->of_node, "clock_in_out", &strings);
        -> of_property_read_u32(dev->of_node, "tx_delay", &value);
        -> of_property_read_u32(dev->of_node, "rx_delay", &value);
     -> rk_gmac_clk_init(plat_dat);                                           // 时钟配置,填充到plat_dat中
     -> rk_gmac_powerup(plat_dat->bsp_priv);
     -> stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
         -> ndev = alloc_etherdev_mqs(sizeof(struct stmmac_priv),MTL_MAX_TX_QUEUES,MTL_MAX_RX_QUEUES);    // 分配一个net_device *ndev
         -> stmmac_set_ethtool_ops(ndev);         // 分配钩子函数
         -> dev_set_drvdata(device, priv->dev);    // 把 priv->dev == device->driver_data
         -> stmmac_verify_args();                   // 一些驱动参数
         -> stmmac_hw_init(priv);                  // 初始化mac并得到能力
         -> stmmac_mdio_register(ndev);            // 注册mdio_bus
             -> mdiobus_alloc                      // 申请一个mii_bus
             -> new_bus->read = &stmmac_mdio_read;      // 读写复位函数
             -> new_bus->write = &stmmac_mdio_write;
             -> new_bus->reset = &stmmac_mdio_reset;
             -> of_mdiobus_register(new_bus, mdio_node);   // 注册mdio_bus
                 -> mdiobus_register(mdio);
                     -> __mdiobus_register
                         -> device_register(&bus->dev);     // 注册设备文件
                         -> bus->reset(bus);                // 总线复位
                         -> mdiobus_scan(bus, i);           // 循环扫描phy
                             -> phydev = get_phy_device(bus, addr, false);      // 创建phy设备
                                 -> get_phy_id
                             -> phy_device_register(phydev);  // 注册phy设备
                         -> bus->state = MDIOBUS_REGISTERED;   // 标志已经注册
           -> register_netdev(ndev);                           // 注册ndev
     -> dwmac_rk_create_loopback_sysfs(&pdev->dev);                             // 相关系统文件

小结
1、RK平台PHY驱动与NXP的整体框架对比大部分一致,具体驱动流程可以参考NXP-phy驱动详解
2、驱动最后调用dwmac_rk_create_loopback_sysfs构建检测MAC端TX/RX延时的相关系统文件,后续会更有关TX/RX延时的代码解析以及自动获取延时的文章

<think>好的,我需要解决用户关于RK3588设备始终出现在通用串口总线位置的问题。首先,用户提到了引用中的总线匹配函数mdio_bus_match和通用PHY驱动,这可能与设备驱动匹配有关。另外,用户还提到了RK3568开发板的I2C总线内容,虽然RK3588和RK3568不同,但总线管理可能有相似之处。 首先,我应该了解RK3588的硬件架构,特别是其串口总线管理。通用串口总线通常指UART,但设备出现在总线位置异常可能与驱动匹配或设备树配置有关。可能的原因包括: 1. **驱动未正确绑定**:设备可能没有正确的驱动绑定,导致系统无法识别,从而出现在通用总线位置。检查设备树中的节点是否指定了正确的驱动,或者驱动是否加载正确。 2. **设备树配置错误**:设备树中的串口节点可能配置不正确,比如兼容性字符串(compatible)错误,导致内核无法匹配正确的驱动,回退到通用驱动。 3. **内核驱动冲突**:可能存在多个驱动匹配同一设备,导致冲突,系统选择错误的驱动。 接下来,根据引用中的mdio_bus_match函数,这属于总线匹配机制。对于串口总线,可能涉及类似的匹配函数,如of_device_match。需要检查设备树中的节点是否与驱动中的of_match_table匹配。 解决方案可能包括: - **检查设备树配置**:确保串口节点的compatible属性与内核驱动中的定义一致。例如,RK3588的串口驱动可能使用"rockchip,rk3588-uart"之类的字符串。 - **确认驱动加载**:使用lsmod查看相关驱动是否加载,或者检查dmesg日志,确认驱动是否正确探测设备。 - **调试设备探测过程**:通过内核日志查看设备匹配过程,确定是否因为匹配失败而使用通用驱动。 用户可能还需要更新内核驱动到最新版本,确保支持RK3588的特定硬件。此外,硬件设计问题,如引脚复用配置错误,也可能导致设备无法正确识别,需要检查硬件配置是否正确。 最后,生成相关问题需要考虑用户可能的后续疑问,如设备树配置方法、驱动调试技巧,以及如何更新内核驱动等。</think>### RK3588设备出现在通用串口总线位置的原因及解决方案 #### 原因分析 1. **设备驱动未正确绑定** RK3588的串口控制器可能未绑定到专用驱动,导致系统将其识别为通用设备。这通常由以下原因引起: - 设备树(Device Tree)中串口节点的`compatible`属性未正确指定RK3588专用驱动标识符[^1]。 - 内核未包含RK3588串口驱动,或驱动未正确加载。 2. **设备树配置错误** 设备树中串口控制器的配置(如时钟、寄存器地址、引脚复用)与实际硬件不匹配,导致驱动初始化失败,系统回退到通用总线驱动[^2]。 3. **内核版本兼容性问题** 旧版本内核可能未完全支持RK3588的硬件特性,导致驱动匹配失败。 #### 解决方案 1. **检查设备树配置** - 确认串口节点的`compatible`属性包含RK3588专用标识符,例如: ```dts uart2: serial@fe720000 { compatible = "rockchip,rk3588-uart"; // 确保与驱动匹配 reg = <0x0 0xfe720000 0x0 0x100>; clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>; interrupts = <GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH>; status = "okay"; }; ``` - 验证引脚复用配置(如`pinctrl`)是否正确,避免与其他功能冲突。 2. **确认驱动加载状态** - 执行`dmesg | grep serial`查看内核日志,确认驱动是否成功探测设备: ```bash [ 2.540000] fe720000.serial: ttyS2 at MMIO 0xfe720000 (irq = 334) is a rk3588-uart ``` - 若未显示专用驱动名称,检查内核配置中是否启用`CONFIG_SERIAL_ROCKCHIP`选项。 3. **更新内核驱动** - 使用最新版内核(≥5.10),确保包含RK3588的完整支持。 - 从Rockchip官方GitHub仓库获取最新驱动补丁: ```bash git clone https://github.com/rockchip-linux/kernel ``` 4. **调试设备匹配过程** 在驱动代码中添加调试输出,观察总线匹配函数的执行逻辑: ```c static const struct of_device_id rockchip_uart_dt_match[] = { { .compatible = "rockchip,rk3588-uart" }, // 检查是否与设备树一致 {} }; ``` 5. **硬件验证** 使用示波器或逻辑分析仪检查串口引脚信号,确认物理层无异常(如时钟未使能、引脚电平错误)。 ####
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bazinga bingo

您的鼓励就是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值