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

news2024/11/27 6:16:15

一.硬件原理图

分析:
该交换芯片支持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 RTL8309
	tristate "RTL8309 driver"
	default m
	help
		Enable 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		3

int 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.coloradmin.cn/o/1318727.html

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

相关文章

代码随想录算法训练营Day4 | 24.两两交换链表中的节点、19.删除链表的倒数第 N 个节点、面试题. 链表相交、142.环形链表II

LeetCode 24 两两交换链表中的节点 本题要注意的条件&#xff1a; 遍历终止条件改变引用指向的时候&#xff0c;需要保存一些节点记录 为了更好的操作链表&#xff0c;我定义了一个虚拟的头节点 dummyHead 指向链表。如下图所示 既然要交换链表中的节点&#xff0c;那么肯定…

Ribbon使用

Ribbon &#xff1a;处理客户端负载均衡和容错的解决方案 配置Ribbon的负载均衡 Rule接口&#xff1a; 定义客户端负载均衡的规则 RandomRule :随机选择RoundRobinRuleZoneAvoidanceRule 配置ribbon的负载均衡策略 在配置文件中配置 user-center:ribbon:NFLoadBalancerRul…

网络安全项目实战(六)--报文检测

11. NTP应用协议报文解析 目标 了解NTP协议了解NTP包基本捕获方式了解NTP协议探测&#xff08;解析&#xff09;方法&#xff08;简单方法&#xff09; 11.1. 使用ntpdate同步网络时间 安装 $ sudo apt-get install ntpdate对时服务 查看时间 $ date #date可以查看当前系…

Jupyter Notebook: 交互式数据科学和编程工具

Jupyter Notebook: 功能强大的交互式编程和数据科学工具 简介 Jupyter Notebook是一个开源的Web应用程序&#xff0c;广泛用于数据分析、科学计算、可视化以及机器学习等领域。它允许创建和共享包含实时代码、方程式、可视化和解释性文本的文档。总而言之&#xff0c;我认为它…

PLC、RS485、变频器通讯接线图详解

plc与变频器两者是一种包含与被包含的关系&#xff0c;PLC与变频器都可以完成一些特定的指令&#xff0c;用来控制电机马达&#xff0c;PLC是一种程序输入执行硬件&#xff0c;变频器则是其中之一。 但是PLC的涵盖范围又比变频器大&#xff0c;还可以用来控制更多的东西&#x…

excel可视化看板【动态关联公司、部门、人员、及时间】

昨天网友花钱定制了一个可视化报表&#xff0c;花了一整天时间&#xff0c;做了这份酷炫的可视化报表&#xff0c;右边按钮控件可以动态关联可视化图表 做这种这重要是数据的统计&#xff0c;只要能统计到&#xff0c;剩下的只是如何展示&#xff0c;慢慢的调整&#xff0c;美…

【复杂网络分析与可视化】——通过CSV文件导入Gephi进行社交网络可视化

目录 一、Gephi介绍 二、导入CSV文件构建网络 三、图片输出 一、Gephi介绍 Gephi具有强大的网络分析功能&#xff0c;可以进行各种网络度量&#xff0c;如度中心性、接近中心性、介数中心性等。它还支持社区检测算法&#xff0c;可以帮助用户发现网络中的群组和社区结构。此…

计算机网络 网络层上 | IP数据报,IP地址,ICMP,ARP等

文章目录 1 网络层的两个层面2 网络协议IP2.1 虚拟互联网络2.2 IP地址2.2.1 固定分类编址方式2.2.2 无分类编制CIDR2.2.3 MAC地址和IP地址区别 2.3 地址解析协议ARP2.3.1 解析过程 2.4 IP数据报格式 3 IP层转发分组流程4 国际控制报文协议ICMP4.1 ICMP格式结构4.2 分类4.2.1 差…

快速排序(一)

目录 快速排序&#xff08;hoare版本&#xff09; 初级实现 问题改进 中级实现 时空复杂度 高级实现 三数取中 快速排序&#xff08;hoare版本&#xff09; 历史背景&#xff1a;快速排序是Hoare于1962年提出的一种基于二叉树思想的交换排序方法 基本思想&#xff1a…

强制性产品认证车辆一致性证书二维码解析

目录 说明 界面 下载 强制性产品认证车辆一致性证书二维码解析 说明 二维码扫描出的信息为&#xff1a; qW0qS6aFjU50pMOqis0WupBnM21DnMxy0dGFN/2Mc9gENXhKh0qEBxFgfXSLoR qW0qS6aFjU50pMOqis0WupBnM21DnMxy0dGFN/2Mc9gENXhKh0qEBxFgfXSLoR 解析后的信息为&#xff1a…

20来岁,大专毕业,学软件测试可行吗?

转行软件测试找不到工作&#xff01; 转行软件测试找不到工作&#xff01; 转行软件测试找不到工作&#xff01; 重要的事情说三遍&#xff01;千万别听培训班咨询老师给你画饼 &#xff1b;我就是某某软件测试培训班出来的&#xff0c;大专&#xff0c;其他专业毕业&#x…

初级数据结构(六)——堆

文中代码源文件已上传&#xff1a;数据结构源码 <-上一篇 初级数据结构&#xff08;五&#xff09;——树和二叉树的概念 | NULL 下一篇-> 1、堆的特性 1.1、定义 堆结构属于完全二叉树的范畴&#xff0c;除了满足完全二叉树的限制之外&#xff0c;还满…

小程序商城活动页面怎么生成二维码

背景 小程序商城某些页面需要做成活动推广页&#xff0c;或需要某一个页面做成二维码进行推广。比如某些非公开的商品做成一个活动&#xff0c;发送指定部分用户&#xff0c;这个活动页面可以做成二维码。 前提 小程序已经上线 步骤 登录微信小程序官网&#xff0c;选择工具…

数据库交付运维高级工程师-腾讯云TDSQL

数据库交付运维高级工程师-腾讯云TDSQL上机指导&#xff0c;付费指导&#xff0c;暂定99

Element 介绍

Element 介绍 Vue 快速入门 Vue 常见组件 表格 分页组件 其他自己去看吧 链接: 其他组件

【idea】解决sprintboot项目创建遇到的问题

目录 一、报错Plugin ‘org.springframework.boot:spring-boot-maven-plugin:‘ not found 二、报错java: 错误: 无效的源发行版&#xff1a;17 三、java: 无法访问org.springframework.web.bind.annotation.CrossOrigin 四、整合mybatis的时候&#xff0c;报java.lang.Ill…

文件函数的简单介绍

1. 向文件中写入一个字符 fputc int_Ch指的是输入文件中的字符 &#xff08;int&#xff09;的原因是以ascll码值的型式输入 #include <stdio.h> #include <errno.h> #include <string.h> int main() { FILE* pf fopen("test.txt","…

再怎么“顽固”的应用程序,也很难经得住以下的卸载方法

卸载程序是我们经常尝试的事情。这可能是因为我们不再需要程序,该程序可能会导致问题等。有时,如果你试图卸载某个程序,你会收到一个错误,但卸载没有发生。在这种情况下,你可以选择强制卸载。在本教程中,我将向你展示如何在Windows 10/11计算机上强制卸载程序。 ​控制面…

西南科技大学数字电子技术实验五(用计数器设计简单秒表)FPGA部分

一、实验目的 1.进一步理解用中规模集成计数器构成任意进制计数器的原理。 2.了解计数器的简单应用。 3.进一步学习与非门和译码显示器的使用方法。 4.学会用FPGA实现本实验内容。 二、实验原理 简单秒表 可暂停、复位秒表 三、程序清单(每条语句必须包括注释或在开发…

运维开发实践 - 服务网关 - apisix部署

1. Apache Apisix Apache Apisix 是一个动态&#xff0c;实时&#xff0c;高性能的云原生API网关&#xff0c;提供负载均衡&#xff0c;动态上游&#xff0c;灰度发布&#xff0c;服务熔断&#xff0c;身份认证&#xff0c;可观测性等丰富的流量管理功能&#xff1b; 2. 如…