ar8031网卡中的光口和电口相互切换

经过一段时间的奋斗,实现了ar8031网卡的光口和电口相互切换。其中的几个关键概念需要厘清。光口如果是SFP的1000M模块需要注意,一定只能是1000M模式。因为这个问题卡了一段时间。不过因为这些问题,把网卡的驱动流程dump了一遍,其中关键的文件为phy_device.c,关键的驱动接口结构体为:

static struct phy_driver genphy_driver = {
	.phy_id		= 0xffffffff,
	.phy_id_mask	= 0xffffffff,
	.name		= "Generic PHY",
	.config_init	= genphy_config_init,
	.features	= 0,
	.config_aneg	= genphy_config_aneg,
	.read_status	= genphy_read_status,
	.suspend	= genphy_suspend,
	.resume		= genphy_resume,
	.driver		= {.owner= THIS_MODULE, },
};
然后这个结构体被在另外一个文件中也实现了,具体文件为at803x.c文件:

static struct phy_driver at8030_driver = {
	.phy_id		= 0x004dd076,
	.name		= "Atheros 8030 ethernet",
	.phy_id_mask	= 0xffffffef,
	.config_init	= at803x_config_init,
	.features	= PHY_GBIT_FEATURES,
	.flags		= PHY_HAS_INTERRUPT,
	.config_aneg	= &genphy_config_aneg,
	.read_status	= &genphy_read_status,
	.driver		= {
		.owner = THIS_MODULE,
	},
};
从这个两个结构体中可以看出,是相互关联实现的。对此可以看出来PHY的基本初始化流程和配置流程。基于此思路我修改了config_aneg的实现。根据PHY的模式修改了对应的配置寄存器实现了光口和电口的互相切换。


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
下面是一个使用Verilog编写的dp83848i的RMII程序示例: module dp83848i_rmii ( input wire clk, input wire reset, input wire [1:0] rx_data, output wire [1:0] tx_data, output wire tx_en, output wire tx_er, input wire col, input wire crs_dv, input wire [1:0] mdio, input wire mdc ); // 定义寄存器地址 parameter ID1 = 32'h20005c01; parameter ID2 = 32'h20005c02; parameter BMCR = 32'h20005c00; parameter BMSR = 32'h20005c01; parameter ANAR = 32'h20005c04; parameter ANLPAR = 32'h20005c05; parameter ANER = 32'h20005c06; parameter PHY_CTRL = 32'h20005c10; parameter TX_CTRL = 32'h20005c12; parameter RX_CTRL = 32'h20005c14; // 定义常量 parameter RMII_CLK_DIV = 2; // RMII 时钟分频器 parameter RX_EN = 2'b10; // 接收使能 parameter TX_EN = 2'b10; // 发送使能 parameter TX_ER = 1'b1; // 发送错误 parameter AN_ENABLE = 1'b1; // 使能自协商 parameter AN_RESTART = 1'b10000; // 自协商重启 // 定义寄存器变量 reg [15:0] reg_data; reg [4:0] reg_addr; reg reg_rd; reg reg_wr; // 定义内部信号 wire [15:0] phy_id; // PHY ID wire [15:0] aneg_ability; // 自协商能力 wire [15:0] aneg_lp_ability; // 对侧自协商能力 wire [15:0] aneg_err; // 自协商错误 wire [15:0] phy_ctrl; // PHY 控制寄存器 wire [15:0] tx_ctrl; // 发送控制寄存器 wire [15:0] rx_ctrl; // 接收控制寄存器 // 定义发送数据寄存器 reg [7:0] tx_data_reg; reg tx_en_reg; reg tx_er_reg; // 定义状态机变量 parameter IDLE = 2'd0; parameter READ = 2'd1; parameter WRITE = 2'd2; reg [1:0] state; // 时钟分频 reg [RMII_CLK_DIV-1:0] clk_div; always @(posedge clk) begin if (reset) begin clk_div <= 0; end else begin clk_div <= clk_div + 1; end end // 读取PHY ID assign mdio = (state == READ || state == WRITE) ? 1'b0 : 1'b1; assign mdio[0] = (state == READ && !reg_rd) ? 1'b1 : 1'b0; assign mdio[1] = (state == WRITE && reg_wr) ? 1'b1 : 1'b0; assign tx_data = (state == WRITE) ? reg_data[7:0] : 2'b00; assign col = 1'b0; assign crs_dv = (state == READ && !reg_rd) ? 1'b1 : 1'b0; always @(posedge clk) begin if (reset) begin state <= IDLE; reg_addr <= 0; reg_rd <= 0; reg_wr <= 0; reg_data <= 0; tx_data_reg <= 0; tx_en_reg <= 0; tx_er_reg <= 0; end else begin case (state) IDLE: if (clk_div == RMII_CLK_DIV) begin state <= READ; reg_addr <= ID1[15:0]; reg_rd <= 1; end READ: if (clk_div == RMII_CLK_DIV) begin reg_rd <= 0; state <= WRITE; reg_addr <= BMCR[15:0]; reg_data <= AN_ENABLE; reg_wr <= 1; end WRITE: if (clk_div == RMII_CLK_DIV) begin reg_wr <= 0; state <= READ; reg_addr <= BMSR[15:0]; reg_rd <= 1; end default: state <= IDLE; endcase end end // 读取寄存器值 always @(posedge clk) begin if (reset) begin phy_id <= 0; aneg_ability <= 0; aneg_lp_ability <= 0; aneg_err <= 0; phy_ctrl <= 0; tx_ctrl <= 0; rx_ctrl <= 0; end else begin case (reg_addr) ID1: phy_id <= reg_data; ID2: phy_id <= {reg_data[7:0], phy_id[7:0]}; BMCR: phy_ctrl <= {reg_data[15:0]}; BMSR: aneg_err <= {reg_data[15:0]}; ANAR: aneg_ability <= {reg_data[15:0]}; ANLPAR: aneg_lp_ability <= {reg_data[15:0]}; ANER: aneg_err <= {reg_data[15:0]}; PHY_CTRL: phy_ctrl <= {reg_data[15:0]}; TX_CTRL: tx_ctrl <= {reg_data[15:0]}; RX_CTRL: rx_ctrl <= {reg_data[15:0]}; endcase end end // 发送数据 always @(posedge clk) begin if (reset) begin tx_data_reg <= 0; tx_en_reg <= 0; tx_er_reg <= 0; end else begin if (tx_en_reg && !tx_er_reg) begin // 发送完成 tx_data_reg <= 0; tx_en_reg <= 0; tx_er_reg <= 0; end else if (tx_en_reg && tx_er_reg) begin // 发送错误 tx_er_reg <= 0; end else if (tx_en && !tx_en_reg) begin // 开始发送 tx_data_reg <= tx_data; tx_en_reg <= 1; tx_er_reg <= 0; end else if (tx_en_reg) begin // 继续发送 tx_data_reg <= {tx_data_reg[6:0], col, tx_data_reg[0]}; tx_er_reg <= (tx_er_reg || tx_data_reg[7] != tx_data[7]); // 发送错误检测 end end end // 输出接口 assign tx_data = tx_data_reg; assign tx_en = tx_en_reg; assign tx_er = tx_er_reg; assign phy_ctrl[0] = 1'b1; // 使能 PHY assign tx_ctrl[1:0] = TX_EN; // 发送使能 assign rx_ctrl[1:0] = RX_EN; // 接收使能 endmodule

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值