}, {
.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.配置设备树
ðernet {
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年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!
15597589889)]
[外链图片转存中…(img-BmphH2bv-1715597589890)]
[外链图片转存中…(img-1URE7RbT-1715597589891)]
[外链图片转存中…(img-l3YXRn6s-1715597589891)]
[外链图片转存中…(img-FzuSOWFA-1715597589892)]
[外链图片转存中…(img-hdr1dtKc-1715597589892)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!