完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
网口驱动相关结构体
// 不同平台的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 = 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延时的代码解析以及自动获取延时的文章。 |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
基于米尔瑞芯微RK3576核心板/开发板的人脸疲劳检测应用方案
533 浏览 0 评论
803 浏览 1 评论
700 浏览 1 评论
1926 浏览 1 评论
3171 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 22:28 , Processed in 0.498307 second(s), Total 40, Slave 34 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号