RK3568平台(网络篇)添加网络交换芯片RTL8306M

一.硬件原理图

分析:
该交换芯片支持I2C、SPI、mdio通信,但是看ast1520的uboot代码采用的是mdio去通信phy芯片的,所以暂时也先采用mdio的方式,需要配置相应的引脚才可以配置成mdio通信模式,具体的配置硬件工程师解决。

背景:

RTL8306M芯片上可能没有提供MDC/MDIO接口,可以通过GPIO(General Purpose Input/Output)来模拟,GPIO可实现串行输入输出,且一般CPU上会提供很多GPIO接口供用户自定义使用。每组SMI需要两个GPIO口分别来模拟MDC和MDIO,首先需要保证这两个GPIO口不作其他用途,且相应的复用模式设置为GPIO模式。

二.SMI[MDC/MDIO]协议

SMI:串行管理接口(Serial Management Interface),通常直接被称为MDIO接口(Management Data Input/Output Interface)。MDIO最早在IEEE 802.3的第22卷定义,后来在第45卷又定义了增强版本的MDIO,其主要被应用于以太网的MAC和PHY层之间,用于MAC层器件通过读写寄存器来实现对PHY层器件的操作与管理。

MDIO接口包括两条线,MDIO和MDC,其中MDIO是双向数据线,而MDC是由STA驱动的时钟线。MDC时钟的最高速率一般为2.5MHz,MDC也可以是非固定频率,甚至可以是非周期的。MDIO接口只是会在MDC时钟的上升沿进行采样,而并不在意MDC时钟的频率(类似于I2C接口)。MDIO是一个PHY的管理接口,用来读/写PHY的寄存器,以控制PHY的行为或获取PHY的状态,MDC为MDIO提供时钟。

MAC读取PHY的寄存器:

MAC向PHY的寄存器写入数据:

三.代码实现

原厂提供了芯片RTL8306M的读写逻辑,需要自己实现gpio模拟MDC/MDIO和驱动入口。

Kconfig:

config RTL8309tristate "RTL8309 driver"default mhelpEnable this driver will support network switch control

Makefile:

# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the Realtek network device drivers.
#obj-$(CONFIG_RTL8309)	+= rtl8309.o
rtl8309-objs := rtl8309_main.o mdcmdio.o rtk_api.o rtl8309n_asicdrv.

DTS配置:

rtl_8309: rtl-8309{status ="okay";compatible = "rtl8309";pinctrl-names = "default";pinctrl-0 = <&rtl8309_mdio_pin&rtl8309_mdc_pin>;rtl8309-mdio-gpios = <&gpio3 RK_PC3 GPIO_ACTIVE_HIGH>;rtl8309-mdc-gpios = <&gpio3 RK_PC2 GPIO_ACTIVE_HIGH>;};rtl-8309 {rtl8309_mdio_pin:rtl8309-mdio-gpios{rockchip,pins = <3 RK_PC3 RK_FUNC_GPIO &pcfg_pull_up>;};rtl8309_mdc_pin:rtl8309-mdc-gpios{rockchip,pins = <3 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>;};};

 实现一个杂散类设备RTL8306M:

#include <linux/miscdevice.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/compat.h>
#include <linux/printk.h>
#include <linux/kobject.h>
#include <linux/version.h>
#include <linux/kthread.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>#include "rtk_api.h"
#include "rtl8309_main.h"#include <linux/delay.h>#define DRIVER_NAME "RTL8309"#define RTL8309_DEBUG	1
#if RTL8309_DEBUG
#define DBG(format, args...)					\printk(KERN_DEBUG "%s: " format, DRIVER_NAME, ##args)
#define ERR(format, args...)					\printk(KERN_ERR "%s: " format, DRIVER_NAME, ##args)
#define WARNING(format, args...)				\printk(KERN_WARN "%s: " format, DRIVER_NAME, ##args)
#define INFO(format, args...)					\printk(KERN_INFO "%s: " format, DRIVER_NAME, ##args)
#else
#define DBG(format, args...)
#define ERR(format, args...)
#define WARNING(format, args...)
#define INFO(format, args...)
#endif#define LINK_UP			1		
#define LINK_DOWN		2
#define LINK_UNKNOW		3int PRE_PORT_STATUS[5]={0,0,0,0,0};struct rtl8309_dev {struct device *dev;struct device sys_dev;struct gpio_desc *rtl8309_mdio;struct gpio_desc *rtl8309_mdc;struct delayed_work check_status_work;struct mutex status_lock;u32 link_status;
};struct rtl8309_dev *g_rtl8309;
struct rtl8309_dev *rtl8309;void setGpioDirection(int gpio, uint32_t  dir)
{if(gpio == IST_GPIO_RTL8309_MDIO){if(dir){gpiod_direction_output(g_rtl8309->rtl8309_mdio,1);}else{gpiod_direction_input(g_rtl8309->rtl8309_mdio);}}else if(gpio == IST_GPIO_RTL8309_MDC){if(dir){gpiod_direction_output(g_rtl8309->rtl8309_mdc,1);}else{gpiod_direction_input(g_rtl8309->rtl8309_mdc);}}
}void setGpioOutput(int gpio, uint32_t out )
{if(gpio == IST_GPIO_RTL8309_MDIO){gpiod_set_value(g_rtl8309->rtl8309_mdio, out);}else if(gpio == IST_GPIO_RTL8309_MDC){gpiod_set_value(g_rtl8309->rtl8309_mdc, out);}
}void getGpioInput(int gpio,uint32_t *in)
{if(gpio == IST_GPIO_RTL8309_MDIO){*in = gpiod_get_value(g_rtl8309->rtl8309_mdio);}else if(gpio == IST_GPIO_RTL8309_MDC){*in = gpiod_get_value(g_rtl8309->rtl8309_mdc);}
}static long rtl8309_ioctl(struct file *file, uint32_t cmd, unsigned long arg)
{return 0;
}static ssize_t rtl8309_write(struct file *file, const char __user *buf,size_t size, loff_t *ppos)
{return 1;
}static ssize_t rtl8309_read(struct file *file, char __user *buf, size_t size,loff_t *ppos)
{return 1;
}static void check_link_status(struct work_struct *work)
{struct delayed_work *dwork = to_delayed_work(work);struct rtl8309_dev *rtl8309 =container_of(dwork, struct rtl8309_dev, check_status_work);int PORT_ENABLE[5]={0,1,0,1,0};int PORT_STATUS[5]={0,0,0,0,0};int status = 0;int i = 0;rtk_port_linkStatus_t pLinkStatus = PORT_LINKDOWN;rtk_port_speed_t pSpeed = PORT_SPEED_10M;rtk_port_duplex_t pDuplex = PORT_HALF_DUPLEX;mutex_lock(&rtl8309->status_lock);for(i=0;i<5;i++){if(PORT_ENABLE[i] == 1){if(rtk_port_phyStatus_get((rtk_port_t)i, &pLinkStatus, &pSpeed, &pDuplex) !=0 ){printk("rtk_port_phyStatus_get error:%d",i);break;}printk("GetEthStatus, port= %d, pLinkStatus= %d, pSpeed= %d, pDuplex= %d \n",i, pLinkStatus, pSpeed, pDuplex);if(pLinkStatus == PORT_LINKUP){PORT_STATUS[i] = 1;printk("port_status\n");if(PRE_PORT_STATUS[i] != PORT_STATUS[i]){printk("port[%d] status changed, set led mode\n",i);if(pSpeed == PORT_SPEED_100M){printk("port_speed\n");}else{printk("port_speed error\n");}}}else{PORT_STATUS[i] = 0;printk("port_status\n");}PRE_PORT_STATUS[i] = PORT_STATUS[i];msleep(10);}}mutex_unlock(&rtl8309->status_lock);for(i=0;i<5;i++){status = status | PORT_STATUS[i];}if(status == 0)rtl8309->link_status =  LINK_DOWN;else if(status == 1)rtl8309->link_status =  LINK_UP;else rtl8309->link_status =  LINK_UNKNOW;schedule_delayed_work(&rtl8309->check_status_work, msecs_to_jiffies(5000));
}static ssize_t rtl8309_status_read(struct device *dev,struct device_attribute *attr, char *buf)
{struct rtl8309_dev *rtl8309 = g_rtl8309;printk("rtl8309_status_read rtl8309_status_read:%d\n",rtl8309->link_status);return sprintf(buf, "%d\n", rtl8309->link_status);
}static ssize_t rtl8309_status_write(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
{printk("rtl8309_status_write rtl8309_status_write");return count;
}static DEVICE_ATTR(linkstatus, 0644,rtl8309_status_read, rtl8309_status_write);static const struct file_operations rtl8309_fops = {.owner = THIS_MODULE,.read = rtl8309_read,.write = rtl8309_write,.unlocked_ioctl = rtl8309_ioctl,
};struct miscdevice rtl8309_miscdev = {.minor = MISC_DYNAMIC_MINOR,.name = "rtl8309_dev",.fops = &rtl8309_fops,
};static int rtl8309_probe(struct platform_device *pdev)
{printk("rtl8309_probe");struct rtl8309_dev *rtl8309;int ret = 0;rtl8309 = devm_kzalloc(&pdev->dev, sizeof(*rtl8309), GFP_KERNEL);if (!rtl8309)return -ENOMEM;rtl8309->dev = &pdev->dev;rtl8309->rtl8309_mdio = devm_gpiod_get_optional(rtl8309->dev,"rtl8309-mdio", GPIOD_OUT_HIGH);if (IS_ERR(rtl8309->rtl8309_mdio)) {printk("Could not get rtl8367-mdio");rtl8309->rtl8309_mdio = NULL;}rtl8309->rtl8309_mdc = devm_gpiod_get_optional(rtl8309->dev,"rtl8309-mdc", GPIOD_OUT_HIGH);if (IS_ERR(rtl8309->rtl8309_mdc)) {printk("Could not get rtl8367-mdc ");rtl8309->rtl8309_mdc = NULL;}g_rtl8309 = rtl8309;ret = misc_register(&rtl8309_miscdev);if (ret) {ERR("rtl8309_miscdev ERROR: could not register rtl8309_miscdev device\n");return ret;}ret = device_create_file(rtl8309_miscdev.this_device,&dev_attr_linkstatus);if (ret) {printk("failed to create attr linkstatus");return ret;}mutex_init(&rtl8309->status_lock);INIT_DELAYED_WORK(&rtl8309->check_status_work, check_link_status);schedule_delayed_work(&rtl8309->check_status_work, msecs_to_jiffies(5000));return 0;
}static int rtl8309_remove(struct platform_device *client)
{return 0;
}static const struct of_device_id rtl8309_of_match[] = {{ .compatible = "rtl8309" },{}
};
MODULE_DEVICE_TABLE(of, rtl8309_of_match);static struct platform_driver rtl8309_driver = {.probe = rtl8309_probe,.remove = rtl8309_remove,.driver = {.owner = THIS_MODULE,.name = DRIVER_NAME,.of_match_table = of_match_ptr(rtl8309_of_match),},
};static int __init rtl8309_init(void)
{int ret = platform_driver_register(&rtl8309_driver);if (ret != 0) {pr_err("Failed to register example driver: %d\n", ret);return ret;}pr_info("Example driver initialized\n");return 0;
}static void __exit rtl8309_exit(void)
{platform_driver_unregister(&rtl8309_driver);pr_info("Example driver exited\n");
}module_init(rtl8309_init);
module_exit(rtl8309_exit);MODULE_DESCRIPTION("rtl8309 GPIO Switch");
MODULE_AUTHOR("Zewei Ye <yezw@ist.com.hk>");
MODULE_LICENSE("GPL v2");

函数说明:rtk_port_phyStatus_get为原厂提供的读取RTL8306M芯片状态的接口,根据返回的状态判断是否有百兆网。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/227081.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用netcore编写对比excel差异

一、新建项目Vlook项目 using MiniExcelLibs; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Data; using System.IO;namespace Vlook {internal class Program{static void Main(string[] args){var dir App…

L1-046:整除光棍

题目描述 这里所谓的“光棍”&#xff0c;并不是指单身汪啦~ 说的是全部由1组成的数字&#xff0c;比如1、11、111、1111等。传说任何一个光棍都能被一个不以5结尾的奇数整除。比如&#xff0c;111111就可以被13整除。 现在&#xff0c;你的程序要读入一个整数x&#xff0c;这个…

通义千问关于网络模块的专业知识能力正确率测试

闲着无聊&#xff0c;就用问答区的一个问题&#xff0c;去考验了通义千问&#xff0c;结果优点出乎意料。 我们来看一下具体的问题&#xff0c;这里&#xff0c;我准备了三个问题&#xff1a; 第一个问题&#xff1a;11.192.0.x 注意&#xff0c;这里我并没有增加任何的辅助提…

关于文件操作---C语言

引言 关于文件&#xff0c;想必大家或多或少都会有些了解&#xff0c;文件可以帮我们储存数据&#xff0c;不同格式的文件可以储存不同类型的数据&#xff0c;也可以将文件中的数据用不同的方式打开。电脑中的文件&#xff0c;是放在硬盘上的。在我们编写代码并运行的时候&…

金蝶云星空表单插件获取复选框的值

文章目录 金蝶云星空表单插件获取复选框的值 金蝶云星空表单插件获取复选框的值 object getPur this.View.Model.GetValue("F_XHWT_IsPur", rowIndexV);bool isSerial !Convert.ToBoolean(itemClose["F_XHWT_IsPur"] "");取得值可以直接转换成…

Datawhale聪明办法学Python(task3变量与函数)

一、课程基本结构 课程开源地址&#xff1a;课程简介 - 聪明办法学 Python 第二版 章节结构&#xff1a; Chapter 0 安装 Installation Chapter 1 启航 Getting Started Chapter 2 数据类型和操作 Data Types and Operators Chapter 3 变量与函数 Variables and Functions Ch…

Cortex-M4内核结构

Cortex-M4内核结构 1. 内核Core 2. 三阶流水线 3. 内核工作模式 4. 总结 Cortex-M4内核结构 Cortex-M4处理器是ARMv7-M架构的一种实现&#xff0c;它是一种32位精简指令集(Reduced Instruction Set Computing, RISC)的处理器&#xff0c;有一个三阶的指令流水线&#xff0c;依…

飞天使-docker知识点4-harbor

文章目录 Harbor安装完成harbor 官方建议方式之后查看 images配置docker 使用harbor 仓库上传下载镜像docker 镜像结合harbor 运行 Harbor Harbor 是一个用于存储和分发 Docker 镜像的企业级 Registry 服务器&#xff0c;由 vmware 开源&#xff0c;其通过添加一些企业必需的功…

C++初阶-list类的模拟实现

list类的模拟实现 一、基本框架1.1 节点类1.2 迭代器类1.3 list类 二、构造函数和析构函数2.1 构造函数2.2 析构函数 三、operator的重载和拷贝构造3.1 operator的重载3.2 拷贝构造 四、迭代器的实现4.1 迭代器类中的各种操作4.1 list类中的迭代器 五、list的增容和删除5.1 尾插…

Visual Studio 2022封装C代码为x64和x86平台动态库

1.引言 本文介绍如何使用Visual Studio 2022将C语言函数封装成x64和x86平台上使用的动态链接库(dll文件)并生成对应的静态链接库(lib文件)&#xff0c;以及如何在C程序中调用生成的dll。 程序下载&#xff1a; 2.示例C语言程序 假设需要开发一个动态链接库&#xff0c;实现复…

for-each循环优先于传统的for循环

在大多数情况下&#xff0c;使用 for-each 循环&#xff08;也称为增强型 for 循环&#xff09;比传统的 for 循环更加简洁和方便。它提供了一种更直观的方式来遍历集合或数组中的元素。以下是一个例子&#xff0c;展示了 for-each 循环优于传统 for 循环的情况&#xff1a; i…

AI智能配音助手微信小程序前后端源码支持多种声音场景选择

大家好今天给大家带来一款配音小程序 &#xff0c;这款小程序支持多种不同声音和场景的选择更人性化&#xff0c; 比如说支持各地区的方言,英文,童声呀等等、 另外也支持男声女声的选择,反正就是模板那些非常的多 当然啦音量,语调,语速那些都是可以DIY跳转的哟,所以说这一款小程…

python每日学11:xpath的使用与调试

背景&#xff1a;最近在使用selenium 模拟浏览器作一些常规操作&#xff0c;在使用selenium的过程中接触到的一种定位方法&#xff0c;叫xpath, 这里说一下使用心得。 首先&#xff0c;我觉得如果只是简单使用的话是不用详细了解具体的语法规则的。 一、xpath怎么用&#xff1…

树莓派(Raspberry Pi)4B密码忘记了,怎么办?

树莓派长时间不用&#xff0c;导致密码忘记了&#xff0c;这可咋整&#xff1f; 第1步&#xff1a;取出SD卡 将树莓派关机&#xff0c;移除sd卡&#xff0c;使用读卡器&#xff0c;插入到你的电脑。 第2步&#xff1a;编辑 cmdline.txt 在PC上打开SD卡根目录&#xff0c;启动…

【星环云课堂大数据实验】kafka消息发布与订阅

文章目录 一、Kafka概述二、实验环境三、实验准备四、实验目的五、实验步骤5.1、创建Kafka Topic5.2、Kafka消息发布5.3、Kafka消息订阅 六、实验感悟 一、Kafka概述 Kafka是由Apache软件基金会开发的一个开源流处理平台&#xff0c;由Scala和Java编写。该项目的目标是为处理实…

内存的管理、扩充、存储保护、地址转换、分配和回收

一、 内存的存储保护 1.1 上、下限寄存器方式&#xff1a; 上、下限寄存器&#xff08;Limit Registers&#xff09;&#xff1a;这是一种硬件级别的内存保护机制。每个进程都有一对上、下限寄存器&#xff0c;用于定义该进程能够访问的内存范围。上限寄存器存储进程能够访问的…

【Android12】WindowManagerService架构分析

Android WindowManagerService架构分析 WindowManagerService(以下简称WMS) 是Android的核心服务。WMS管理所有应用程序窗口(Window)的Create、Display、Update、Destory。 因为Android系统中只有一个WMS&#xff08;运行在SystemServer进程&#xff09;&#xff0c;可以称其为…

快宝技术:连接无代码开发,API集成提升电商营销和用户运营效率

无代码开发&#xff1a;创新的启航 快宝技术自2012年成立至今&#xff0c;一直是无代码开发领域的佼佼者。通过无代码开发平台&#xff0c;快宝技术旨在降低技术门槛&#xff0c;并使非技术人员能够轻松创建和部署应用程序。这不仅使得快递末端软件开发变得高效和便捷&#xf…

vue3.0项目搭建

一、安装vue3脚手架 卸载vue2脚手架 npm uninstall -g vue-cli清除缓存 npm cache clen --force安装最新脚手架 npm install -g vue/cli查看脚手架版本 vue -V 二、构建项目 创建项目 vue create 项目名选择配置 自定义配置&#xff0c;回车 上下键选择Linter / Formatter&a…