RTL9000BRG调试总结

}, {
	.phy_id		= 0x001cc916,
	.name		= "RTL8211F Gigabit Ethernet",
	.phy_id_mask	= 0x001fffff,
	.features	= PHY_GBIT_FEATURES,
	.flags		= PHY_HAS_INTERRUPT,
	.config_aneg	= &genphy_config_aneg,
	.config_init	= &rtl8211f_config_init,
	.read_status	= &genphy_read_status,
	.ack_interrupt	= &rtl8211f_ack_interrupt,
	.config_intr	= &rtl8211f_config_intr,
	.suspend	= genphy_suspend,
	.resume		= genphy_resume,
},

};


所以需要自己适配RTL9000。


## 1.配置设备树



&ethernet {
status = “okay”;
phy-handle = <&phy1>;
phy-mode = “rgmii-id”;
phy-reset-gpios = <112>;
phy-reset-duration = <12>;
phy-reset-post-delay = <10>;
mdio {
#address-cells = <0x1>;
#size-cells = <0x0>;
phy1: phy@1 {
compatible = “RTL8211F Gigabit Ethernet”,“ethernet-phy-ieee802.3-c45”;
reg = <0x1>;
};
};
};


## 2.明确phy id


![](https://img-blog.csdnimg.cn/8940842c14474a2f9c59151cb3179666.png)


 根据寄存器值可以确定phy id是0x001ccb00


## 3.填充驱动



/*

  • drivers/net/phy/realtek.c
  • Driver for Realtek PHYs
  • Author: Johnson Leung r58129@freescale.com
  • Copyright © 2004 Freescale Semiconductor, Inc.
  • This program is free software; you can redistribute it and/or modify it
  • under the terms of the GNU General Public License as published by the
  • Free Software Foundation; either version 2 of the License, or (at your
  • option) any later version.

*/
#include <linux/phy.h>
#include <linux/module.h>
#include <linux/delay.h>

#define RTL821x_PHYSR 0x11
#define RTL821x_PHYSR_DUPLEX 0x2000
#define RTL821x_PHYSR_SPEED 0xc000
#define RTL821x_INER 0x12
#define RTL821x_INER_INIT 0x6400
#define RTL821x_INSR 0x13
#define RTL8211E_INER_LINK_STATUS 0x400

#define RTL8211F_INER_LINK_STATUS 0x0010
#define RTL8211F_INSR 0x1d
#define RTL8211F_PAGE_SELECT 0x1f
#define RTL8211F_TX_DELAY 0x100

#define MIIM_RTL9000_SRAM_ADDR 0x1b
#define MIIM_RTL9000_SRAM_DATA 0x1c
#define MIIM_RTL9000_PAGE_SELECT 0x1f

/*

  • For RTL9000 RGMII Control Registers
  • special register
    */
    #define MIIM_RTL9000_RGRXCR 0xd082
    #define MIIM_RTL9000_TX_DELAY 0x10<<8
    #define MIIM_RTL9000_PHY_STATUS 0x1a
    #define MIIM_RTL9000_PHYSTAT_LINK 0x0004
    #define MIIM_RTL9000_PHYSTAT_DUPLEX 0x0100
    #define MIIM_RTL9000_PHYSTAT_SPEED 0x2040

unsigned int param_check[6*3]={0, 0x8017, 0xFB03, 0, 0x8092, 0x6000,
0, 0x80AF, 0x6000, 0, 0x807D, 0x4443, 0, 0x809A, 0x4443, 0, 0x81A3, 0x0F00};

MODULE_DESCRIPTION(“Realtek PHY driver”);
MODULE_AUTHOR(“Johnson Leung”);
MODULE_LICENSE(“GPL”);

static int rtl821x_ack_interrupt(struct phy_device *phydev)
{
int err;

err = phy_read(phydev, RTL821x_INSR);

return (err < 0) ? err : 0;

}

static int rtl8211f_ack_interrupt(struct phy_device *phydev)
{
int err;

phy_write(phydev, RTL8211F_PAGE_SELECT, 0xa43);
err = phy_read(phydev, RTL8211F_INSR);
/* restore to default page 0 */
phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0);

return (err < 0) ? err : 0;

}

static int rtl8211b_config_intr(struct phy_device *phydev)
{
int err;

if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
	err = phy_write(phydev, RTL821x_INER,
			RTL821x_INER_INIT);
else
	err = phy_write(phydev, RTL821x_INER, 0);

return err;

}

static int rtl8211e_config_intr(struct phy_device *phydev)
{
int err;

if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
	err = phy_write(phydev, RTL821x_INER,
			RTL8211E_INER_LINK_STATUS);
else
	err = phy_write(phydev, RTL821x_INER, 0);

return err;

}

static int rtl8211f_config_intr(struct phy_device *phydev)
{
int err;

if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
	err = phy_write(phydev, RTL821x_INER,
			RTL8211F_INER_LINK_STATUS);
else
	err = phy_write(phydev, RTL821x_INER, 0);

return err;

}

static int rtl8211f_config_init(struct phy_device *phydev)
{
int ret;
u16 reg;

ret = genphy_config_init(phydev);
if (ret < 0)
	return ret;

phy_write(phydev, RTL8211F_PAGE_SELECT, 0xd08);
reg = phy_read(phydev, 0x11);

/* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
	reg |= RTL8211F_TX_DELAY;
else
	reg &= ~RTL8211F_TX_DELAY;

phy_write(phydev, 0x11, reg);
/* restore to default page 0 */
phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0);

return 0;

}

static void RTL9000Bxx_Initial_Config_Erratum1(struct phy_device *phydev)
{
int io_data = 0;
int timer = 2000;
//sample_code 04
//phy_write(phydev, 0x1F, 0x0A43);
phy_write(phydev, 0x1B, 0x8017);
phy_write(phydev, 0x1C, 0xFB03); // PHY patch request
phy_write(phydev, 0x1B, 0x8092);
phy_write(phydev, 0x1C, 0x6000);
phy_write(phydev, 0x1B, 0x80AF);
phy_write(phydev, 0x1C, 0x6000);
phy_write(phydev, 0x1B, 0x807D);
phy_write(phydev, 0x1C, 0x4443);
phy_write(phydev, 0x1B, 0x809A);
phy_write(phydev, 0x1C, 0x4443);
phy_write(phydev, 0x1B, 0x81A3);
phy_write(phydev, 0x1C, 0x0F00);
phy_write(phydev, 0x1F, 0x0A81);
phy_write(phydev, 0x12, 0x0004);
phy_write(phydev, 0x1B, 0x83C8);
phy_write(phydev, 0x1C, 0x0005);
phy_write(phydev, 0x1F, 0x0A5C);
phy_write(phydev, 0x12, 0x0003);
phy_write(phydev, 0x1B, 0xB820);
phy_write(phydev, 0x1C, 0x0010);
phy_write(phydev, 0x1B, 0xB830);
phy_write(phydev, 0x1C, 0x8000);
//phy_write(phydev, 0x1B, 0xB800);
do {
phy_write(phydev, 0x1B, 0xB800);
io_data = (phy_read(phydev, 0x1C)) & 0x40;
timer–;
if (timer == 0) {
timer = 2000;
break;
}
} while (io_data == 0);

phy_write(phydev, 0x1B, 0x8020);
phy_write(phydev, 0x1C, 0x3300);
phy_write(phydev, 0x1B, 0xB82E);
phy_write(phydev, 0x1C, 0x0001);
phy_write(phydev, 0x1B, 0xB820);
phy_write(phydev, 0x1C, 0x0290);
phy_write(phydev, 0x1B, 0xA012);
phy_write(phydev, 0x1C, 0x0000);
phy_write(phydev, 0x1B, 0xA014);
phy_write(phydev, 0x1C, 0x401C);
phy_write(phydev, 0x1C, 0xA610);
phy_write(phydev, 0x1C, 0x8520);
phy_write(phydev, 0x1C, 0xA510);
phy_write(phydev, 0x1C, 0x21F4);
phy_write(phydev, 0x1B, 0xA01A);
phy_write(phydev, 0x1C, 0x0000);
phy_write(phydev, 0x1B, 0xA000);
phy_write(phydev, 0x1C, 0x11EF);
phy_write(phydev, 0x1B, 0xB820);
phy_write(phydev, 0x1C, 0x0210);
phy_write(phydev, 0x1B, 0xB82E);
phy_write(phydev, 0x1C, 0x0000);
phy_write(phydev, 0x1B, 0x8020);
phy_write(phydev, 0x1C, 0x0000);
phy_write(phydev, 0x1B, 0xB820);
phy_write(phydev, 0x1C, 0x0000);
//phy_write(phydev, 0x1B, 0xB800);
do {
	phy_write(phydev, 0x1B, 0xB800);
	io_data = (phy_read(phydev, 0x1C)) & 0x40;
	timer--;
	if (timer == 0) {
		break;
	}
} while (io_data != 0);

}

static int RTL9000Bxx_init(struct phy_device *phydev)
{
int mdio_data = 0;
int ret;
int set_master = 0;
int power_section = 5;

unsigned int mdio_data_chk = 0;
unsigned int page;
unsigned int reg, i;

/*  check PHY accessible  */
while (mdio_data != 0x0003) {
	phy_write(phydev, 0x1F, 0x0A42);
	mdio_data = phy_read(phydev, 0x10);
	mdio_data = mdio_data & 0x0007;
}

/*  hardware reset  */
// phy_write(phydev, 0x1B, 0xDD00);
// mdio_data = phy_read(phydev, 0x1C);
// phy_write(phydev, 0x1C, (mdio_data | 0x0020));

phy_write(phydev, 0x1F, 0x0A42);//change page to default value
//check PHY accessible

mdio_data = 0;
while (mdio_data != 0x0003) {
	mdio_data = phy_read(phydev, 0x10);
	mdio_data = mdio_data & 0x0007;
}

/*  init parameter  */
RTL9000Bxx_Initial_Config_Erratum1(phydev);

/*  check init success  */
for(i = 0; i < 6*3; i = i+3) {
	page = param_check[i];
	mdio_data_chk = param_check[i+2];
	reg = param_check[i+1];
	if(page == 0) {
		phy_write(phydev, 0x1B, reg);
		mdio_data = phy_read(phydev, 0x1C);
	} else {
		phy_write(phydev, 0x1F, reg);
		mdio_data = phy_read(phydev, reg);
	}
	if(mdio_data_chk!= mdio_data) {
		printk(("%dth param error page=0x%04X reg=0x%04X data=0x%04X\n",
			i/3, page, reg, mdio_data));
		printk("phyInit error\n");
	}
}
printk("phy Init success\n");

/*  I/O Power Sllection  */
phy_write(phydev, 0x1F, 0x0A4C);//change page to default value
mdio_data = phy_read(phydev, 0x12);
mdio_data &= 0xC7FF;
mdio_data |= 4 << 11;
phy_write(phydev, 0x12, mdio_data);



/***************************here is optional **********************/
/*  role setting  */
if (set_master == 1) {
	// Master or Slave mode depends on customer's application.
	mdio_data = phy_read(phydev, 9);
	phy_write(phydev, 9, (mdio_data | 0x0800));	// Set as Master
} else {
	mdio_data = phy_read(phydev, 9);
	phy_write(phydev, 9, (mdio_data & 0xF7FF));	// Set as Slave
}
//.....other applications
/*****************************************************************/


/*  power supply selection */
switch (power_section) {
case 0://external 3.3V
	phy_write(phydev, 0x1F, 0x0A43); //change page to 0xa43
	phy_write(phydev, 0x1B, 0xDC06);
	phy_write(phydev, 0x1C, 0x0DF8);
	break;
case 1://internal LDO 2.5V
	phy_write(phydev, 0x1F, 0x0A43);
	phy_write(phydev, 0x1B, 0xDC06);
	phy_write(phydev, 0x1C, 0x5DF9);
	break;
case 2://external 2.5V
	phy_write(phydev, 0x1F, 0x0A43);
	phy_write(phydev, 0x1B, 0xDC06);
	phy_write(phydev, 0x1C, 0xDDF9);
	break;
case 3://internal LDO 1.8v
	phy_write(phydev, 0x1F, 0x0A43);
	phy_write(phydev, 0x1B, 0xDC06);
	phy_write(phydev, 0x1C, 0xADFA);
	break;
case 4://external 1.8v
	phy_write(phydev, 0x1F, 0x0A43);
	phy_write(phydev, 0x1B, 0xDC06);
	phy_write(phydev, 0x1C, 0xEDFA);
	break;
case 5://RTL9000BRG
	//phy_write(phydev, 0x1F, 0x0A43);
	phy_write(phydev, 0x1B, 0xD414);
	ret = (phy_read(phydev, 0x1C)) | 0x1010;
	phy_write(phydev, 0x1C, ret);

	phy_write(phydev, 0x1B, 0xD416);
	ret = (phy_read(phydev, 0x1C)) | 0x1010;
	phy_write(phydev, 0x1C, ret);

	phy_write(phydev, 0x1B, 0xD418);
	ret = (phy_read(phydev, 0x1C)) | 0x1000;
	phy_write(phydev, 0x1C, ret);

	phy_write(phydev, 0x1B, 0xD41A);
	ret = (phy_read(phydev, 0x1C)) | 0x1000;
	phy_write(phydev, 0x1C, ret);
	phy_write(phydev, 0x1B, 0xD42E);
	phy_write(phydev, 0x1C, 0x7E7E);
}

/* Settting delay */
phy_write(phydev, 0x1F, 0x0a43);
phy_write(phydev, 0x1B, 0xD082);
reg = phy_read(phydev, 0x1C);

/* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
	reg &= 0xFCF8;
	reg |= 7;      //RX delay
	//reg |= 1 << 8;   //TX delay
} else {
	reg &= ~(0x10 << 8);
}
phy_write(phydev, 0x1B, 0xD082);
phy_write(phydev, 0x1C, reg);
phy_write(phydev, 0x1F, 0xa42);



//software reset
phy_write(phydev, 0, 0x8000);	// PHY soft-reset
mdelay(30);

/*  Check soft-reset complete  */
mdio_data = 0;
mdio_data = phy_read(phydev, 0);
int num = 0;
while (mdio_data != 0x2100) {
	mdio_data = phy_read(phydev, 0);
	if(num == 9)
		break;
	++num;
}

return 0;

}

static int rtl9000_config_init(struct phy_device *phydev)
{
unsigned int reg;
phy_write(phydev, 0, 0x8000); // PHY soft-reset
mdelay(30);

RTL9000Bxx_init(phydev);

/* Set green LED for Link, yellow LED for Active */
// phy_write(phydev, MDIO_DEVAD_NONE,
// 	  MIIM_RTL9000_PAGE_SELECT, 0xd04);

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

15597589889)]

[外链图片转存中…(img-BmphH2bv-1715597589890)]

[外链图片转存中…(img-1URE7RbT-1715597589891)]

[外链图片转存中…(img-l3YXRn6s-1715597589891)]

[外链图片转存中…(img-FzuSOWFA-1715597589892)]

[外链图片转存中…(img-hdr1dtKc-1715597589892)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

  • 26
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值