RTL8305NB从电口模式切换为光口模式

admin2024-07-03  6

#if 1//下面是参考案例  //RTL8305NB


#define PORT2_PHY_ADDR 0x05  // SFP Port2 PHY地址
#define STATUS_REG_ADDR 0x01 // 状态寄存器地址

#define MDC_PIN GPIO_Pin_13	  //MDC (PC13)	  
#define MDIO_PIN GPIO_Pin_6  //MDIO (PE6)


#define MDIO_DELAY 10      // us
#define MDIO_READ_DELAY 10 // us


void smi_init(void);

u16 smi_reg_read(u16 phy, u16 reg);

void smi_reg_write(u16 phy, u16 reg, u16 val);

static void MDC_OUT(void);
static void MDIO_OUT(void);
static void MDIO_IN(void);
static void MDC_H(void);
static void MDC_L(void);
static uint8_t GET_MDIO(void);
static void SET_MDIO(uint8_t val);
extern void delay_us(u32 nus);

void LOS_UDelay(u32 nus)
{
	delay_us(nus);	
}


/* 设置MDC为输出引脚,在MDC输出时钟之前设置 */
static void MDC_OUT(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; // 推挽输出,因为MDIO是双向的,但在这里我们先配置为输出  
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//GPIO_PuPd (Pull-Up/Pull-Down)设置 GPIO 引脚的内部上拉/下拉电阻
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//GPIO_OType (Output Type)用于设置 GPIO 引脚在输出模式下的类型。 
  
    // MDC (PC13) 配置为输出  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;  
    GPIO_Init(GPIOC, &GPIO_InitStructure); 

}

/* 设置MDIO的gpio引脚为输出引脚 */
static void MDIO_OUT(void)
{

	GPIO_InitTypeDef GPIO_InitStructure;
    // MDIO (PE6) 配置为输出  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; // 推挽输出,因为MDIO是双向的,但在这里我们先配置为输出  
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//GPIO_PuPd (Pull-Up/Pull-Down)设置 GPIO 引脚的内部上拉/下拉电阻
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//GPIO_OType (Output Type)用于设置 GPIO 引脚在输出模式下的类型。
	GPIO_Init(GPIOE, &GPIO_InitStructure);  
  	
}

/* 设置MDIO的gpio引脚为输入引脚 */
static void MDIO_IN(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
    // MDIO (PE6) 配置为输出  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;    
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;   
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//GPIO_PuPd (Pull-Up/Pull-Down)设置 GPIO 引脚的内部上拉/下拉电阻
	GPIO_Init(GPIOE, &GPIO_InitStructure); 
	
}

/* MDC输出高电平,在MDC设置为输出后调用 */
static void MDC_H(void)
{
	GPIO_SetBits(GPIOC, MDC_PIN); 
}



/* MDC输出低电平,在MDC设置为输出后调用 */
static void MDC_L(void)
{
	GPIO_ResetBits(GPIOC, MDC_PIN); 
}

/* 获得MDIO的数据,只获得一个bit */
static uint8_t GET_MDIO(void)
{
    return GPIO_ReadInputDataBit(GPIOE,MDIO_PIN);
}

/* 设置MDIO的数据,一个bit */
static void SET_MDIO(uint8_t val)
{
    if (val != 0) {
        GPIO_SetBits(GPIOE, MDIO_PIN);
    } else {
        GPIO_ResetBits(GPIOE, MDIO_PIN);
    }
}

/* MDIO发送一个bit的数据,MDIO必须已经被配置为输出 */
static void mdio_bb_send_bit(uint8_t val)
{
    MDC_OUT();
    SET_MDIO(val);
    LOS_UDelay(MDIO_DELAY);
    MDC_H();
    LOS_UDelay(MDIO_DELAY);
    MDC_L();
    // LOS_UDelay(MDIO_DELAY);
}

/*  MDIO 获取一个bit的数据,MDIO必须已经被配置为输入. */
static uint8_t mdio_bb_get_bit(void)
{
    uint8_t value;

    MDC_OUT();
    LOS_UDelay(MDIO_DELAY);
    MDC_H();
    LOS_UDelay(MDIO_READ_DELAY);
    value = GET_MDIO();
    //  LOS_UDelay(MDIO_DELAY);
    MDC_L();
    return value;
}

/*
 *  MDIO发送一个数据,MDIO 必须被配置为输出模式.
 *  value:要发送的数据
 *  bits:数据的位数
 *
 *  */
static void mdio_bb_send_num(u16 value, uint8_t bits)
{
    int i;
    MDIO_OUT();
    for (i = bits - 1; i >= 0; i--)
        mdio_bb_send_bit((value >> i) & 1);
}

/*
 *  MDIO获取一个数据,MDIO 必须被配置为输入模式.
 *  bits:获取数据的位数
 *
 *  */
static u16 mdio_bb_get_num(u8 bits)
{
    int i;
    u16 ret = 0;
    for (i = bits - 1; i >= 0; i--) {
        ret <<= 1;
        ret |= mdio_bb_get_bit();
    }

    return ret;
}

/*  Utility to send the preamble, address, and
 *   register (common to read and write).
 */
static void mdio_bb_cmd(uint8_t op, u16 phy, u16 reg)
{
    int i = 0;
    MDIO_OUT(); //设置MDIO引脚为输出引脚

    /*发送32bit的1,这个帧前缀域不是必须的,某些物理层芯片的MDIO操作就没有这个域*/
    for (i = 0; i < 32; i++)
        mdio_bb_send_bit(1);


	mdio_bb_send_bit(0);
    mdio_bb_send_bit(1);

    mdio_bb_send_bit((op >> 1) & 1);
    mdio_bb_send_bit((op >> 0) & 1);

    mdio_bb_send_num(phy, 5);
    mdio_bb_send_num(reg, 5);
}


void mdio_set_turnaround(void)
{
    int i = 0;
    MDIO_IN();
    MDC_OUT();
    for (i = 0; i < 1; i++) {
        LOS_UDelay(MDIO_DELAY);
        MDC_H();
        LOS_UDelay(MDIO_DELAY);
        MDC_L();
    }
}

u16 smi_reg_read(u16 phy, u16 reg)
{
    u16 ret, i;

	mdio_bb_cmd(MDIO_READ, phy, reg);

    MDIO_IN();
    // mdio_set_turnaround();
#if 1
    /*  check the turnaround bit: the PHY should be driving it to zero */
    if (mdio_bb_get_bit() != 0) {
        /* PHY didn\'t driver TA low -- flush any bits it may be trying to send*/
        for (i = 0; i < 32; i++)
            mdio_bb_get_bit();
        // bios_log("PHY didn\'t driver TA low! \r\n");
        return 0xFFFF;
    }
#endif
    ret = mdio_bb_get_num(16);
    mdio_bb_get_bit();
    return ret;
}

void smi_reg_write(u16 phy, u16 reg, u16 val)
{

	mdio_bb_cmd(MDIO_WRITE, phy, reg);

    /*  send the turnaround (10) */
    mdio_bb_send_bit(1);
    mdio_bb_send_bit(0);

    mdio_bb_send_num(val, 16);

    MDIO_IN();
    // mdio_bb_get_bit();
}

void smi_init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;  
	// 使能GPIOE和GPIOC的时钟  
    RCC_APB2PeriphClockCmd(RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOC, ENABLE); 
	
	// MDIO (PE6) 配置为输出  
    GPIO_InitStructure.GPIO_Pin = MDIO_PIN;  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; // 推挽输出,因为MDIO是双向的,但在这里我们先配置为输出  
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//GPIO_PuPd (Pull-Up/Pull-Down)设置 GPIO 引脚的内部上拉/下拉电阻
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//GPIO_OType (Output Type)用于设置 GPIO 引脚在输出模式下的类型。
	GPIO_Init(GPIOE, &GPIO_InitStructure);  
  
    // MDC (PC13) 配置为输出  
    GPIO_InitStructure.GPIO_Pin = MDC_PIN;  
    GPIO_Init(GPIOC, &GPIO_InitStructure); 

}
  

void switch_fiber_port_init(void)
{
    u16 data = 0;
    smi_reg_write(0x08, 0x1F, 0x8000);         // 切换Page至PHY page

    smi_reg_write(PORT2_PHY_ADDR, 0x1F, 0x00); // 设置Port2为光口
    data = smi_reg_read(PORT2_PHY_ADDR, 0x1C); // 读出寄存器28原始状态
    data |= (0x01 << 5);// 将bit5置高
    smi_reg_write(PORT2_PHY_ADDR, 0x1C, data); // 将修改后的值写入寄存器
    smi_reg_write(0x08, 0x1F, 0x0); // 切回MAC Page
}






#endif

对于RTL8305NB,要从电口模式切换为光口模式,主要操作涉及到PHY page的切换和特定寄存器的配置。以下是详细的操作步骤:

  1. PHY Page切换
    • 首先,需要访问PHY地址8的寄存器31。这个寄存器用于Page的切换。
    • 向PHY地址8的寄存器31写入值0x8000,这将使芯片切换到PHY page。
  2. 光口模式配置
    • 在切换到PHY page后,需要配置特定的寄存器以将端口设置为光口模式。
    • 根据参考文章提供的信息,通常需要修改PHY page下的某个寄存器的某个位来配置光口模式。具体而言,是将寄存器28的bit5置高(设置为1)。
// 假设有一个函数用于向PHY寄存器写入值  
void write_phy_register(uint8_t phy_address, uint8_t register_address, uint16_t value) {  
    // 实现向PHY寄存器写入的逻辑  
    // ...  
}  
  
// 切换到PHY Page  
write_phy_register(8, 31, 0x8000); // 切换到PHY Page

// 假设有一个函数用于读取PHY寄存器的值  
uint16_t read_phy_register(uint8_t phy_address, uint8_t register_address) {  
    // 实现从PHY寄存器读取值的逻辑  
    // ...  
    return value;  
}  
  
// 配置光口模式  
uint16_t register28_value = read_phy_register(8, 28); // 读取寄存器28的当前值  
register28_value |= (1 << 5); // 将bit5设置为1(光口模式)  
write_phy_register(8, 28, register28_value); // 将修改后的值写回寄存器28


void switch_fiber_port_init(void)
{
    unsigned short data = 0;
    write_phy_register(0x08, 0x1F, 0x8000);         // 切换Page至PHY page
    write_phy_register(PORT2_PHY_ADDR, 0x1F, 0x00); // 设置Port2为光口
    data = read_phy_register(PORT2_PHY_ADDR, 0x1C); // 读出寄存器28原始状态
    data |= (0x01 << 5);// 将bit5置高
    write_phy_register(PORT2_PHY_ADDR, 0x1C, data); // 将修改后的值写入寄存器
    write_phy_register(0x08, 0x1F, 0x0); // 切回MAC Page
}

总结

  • 访问PHY地址8的寄存器31,并写入0x8000以切换到PHY page。
  • 在PHY page下,将寄存器28的bit5置高,从而配置端口为光口模式。

RTL8305NB从电口模式切换为光口模式,第1张

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明原文出处。如若内容造成侵权/违法违规/事实不符,请联系SD编程学习网:675289112@qq.com进行投诉反馈,一经查实,立即删除!