IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 为Exynos4412移植2022版U-Boot——支持DM9000网卡 -> 正文阅读

[嵌入式]为Exynos4412移植2022版U-Boot——支持DM9000网卡


此篇博文是在 为Exynos4412移植了2022版U-Boot-2022.01-rc4的基础上 1,添加DM9000AEP网卡驱动。

一、DM9000基地址设置原理

电路连接图

DM9000A电路图
从上面可以看出DM9000的地址总线就一根,它不像CS8900那样地址总线和数据总线都齐全。而这里只有一根地址线(CMD),16跟数据线,所以可以确定位宽为16位。而地址线为什么只有一根,这是DM9000决定的,看手册可以知道CPU总线只访问它的两个地址:CMD管脚为0时,数据线送的是DM9000的寄存器地址;CMD管脚为1时,数据线上送的是16位的寄存器数据。因此,对DM9000的操作至少需要两步:先写地址,再写(读)数据。他不像其他内存总线那样直接把数据写到地址传输一次就可以了,而他要传输两次。2

基地址的确定

由于DM9000的引脚电平与Exynos4412的不一致,所以中间需要电平转换电路。这也是tiny4412不用DM9000而使用DM9621的原因。

 dm9000       外围电路         转换电路    soc 
  #CS--------Xm0CSn1_LV--------Xm0CSn1-----Xm0CSn1

由电路图可以看出,把DM9000的#CS接到Exynos4412的nGCS1引脚上,表明DM9000连接到SDRAM的Bank1 memory。由Exynos4412用户手册中的Memory Map可以得到,DM9000的端口基址为0x05000000,3

在这里插入图片描述

寄存器地址的确定

由参考博文42,我们可以得知,DM9000寄存器地址就是基地址。所以,需要宏定义

#define CONFIG_DM9000_BASE     			0x05000000 
#define DM9000_IO      					CONFIG_DM9000_BASE

数据地址的确定

 dm9000       外围电路         转换电路       soc 
  #CMD-------Xm0ADDR2_LV-----Xm0ADDR2-----Xm0ADDR2

由电路图可以看出,DM9000的CMD引脚接到Exynos4412的ADDR2,由CMD引脚的高低电平决定地址口和数据口。那么,ADDR2为0时,访问的就是地址口,所以地址LADDR3-LADDR0 = 0000时,即0x05000000 ;ADDR2为1时,地址LADDR3~LADDR0 = 0100时,访问的就是数据口,所以数据口的地址即 0x05000004。所以,需要宏定义

#define DM9000_DATA    					(CONFIG_DM9000_BASE + 4)

其他引脚

INT---->XEINT7
IOR---->Xm0OEn
IOW---->Xm0WEn

二、修改u-boot-2022.01-rc4源代码支持DM9000AEP

0、添加裸驱动原理分析

要把USB、nandflash、DM9000的裸驱动编译进U-Boot,一是要写入MCU相关寄存器正确的数值以初始化,二是要实现输入和输出等功能。这些都需要调用函数。那么,我们需要做的就是把这些函数找出来,然后对应开发板的硬件型号做修改,然后通过修改Makefile把该函数源文件编译进U-Boot。
对于DM9000A,我发现common/board_r.c中有board_init_r()函数,该函数中定义了数组函数指针init_sequence_r[],该数组保存的是启动U-Boot时需要执行的函数指针。其中有initr_net()函数指针,该函数会调用eth_initialize()。
eth_initialize()函数在/net/eth_legacy.c中实现。eth_legacy.c中定义了弱函数__def_eth_init(struct bd_info *bis)。该弱函数可以有两种实现,分别是cpu_eth_init(struct bd_info *bis)或者board_eth_init(struct bd_info *bis)。eth_initialize()函数会调用这三个函数。

/*
 * CPU and board-specific Ethernet initializations.  Aliased function
 * signals caller to move on
 */
static int __def_eth_init(struct bd_info *bis)
{
	return -1;
}
int cpu_eth_init(struct bd_info *bis) __attribute__((weak, alias("__def_eth_init")));
int board_eth_init(struct bd_info *bis) __attribute__((weak, alias("__def_eth_init")));

而cpu_eth_init和board_eth_init这两种函数都没有具体定义。原因很简单,U-Boot的编写者并不知道开发板使用的是哪种网卡。也就是说,DM9000的裸驱动需要移植者在这里实现。很多Samsung的板子使用board_eth_init()函数实现。

1、修改board/samsung/cbt4412/cbt4412.h

查看文件drivers/net/Makefile:

obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o

从 Makefile 得知,如果要把 DM9000A 的驱动编译进 u-boot中,就需要定义 CONFIG_DRIVER_DM9000 这个宏。
除此以外我们还需要添加一些 u-boot 的命令,比如 ping 命令用来检查网络是否通畅,tftp用来下载文件。

定义宏有2种方式,一是在configs/cbt4412_defconfig中定义宏,二是在board/samsung/cbt4412/cbt4412.h中定义宏。很悲剧的是,我在configs/cbt4412_defconfig中添加CONFIG_DRIVER_DM9000=y,但是不起作用。虽然drivers/net/Makefile中存在obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o,但是不能生成dm9000x.o目标文件。无奈,我只有在board/samsung/cbt4412/cbt4412.h定义宏CONFIG_DRIVER_DM9000,以及环境参数等宏定义,如下:

/* DM9000 Config */
#ifdef CONFIG_CMD_NET
#define CONFIG_DRIVER_DM9000 y

#define CONFIG_DM9000_BASE	0x05000000 		
#define DM9000_IO		CONFIG_DM9000_BASE	/* #undef CONFIG_DM_ETH */
#define DM9000_DATA		(CONFIG_DM9000_BASE + 4)/*  */
#define CONFIG_DM9000_USE_16BIT				/*  */
#define CONFIG_DM9000_NO_SROM	1			/*  */
#define CONFIG_ETHADDR		11:22:33:44:55:66
#define CONFIG_IPADDR		192.168.1.8
#define CONFIG_SERVERIP		192.168.1.7
#define CONFIG_GATEWAYIP	192.168.1.1
#define CONFIG_NETMASK		255.255.255.0

#define EXYNOS4412_SROMC_BASE 	0X12570000
#endif

DM9000的基地址、寄存器地址、数据地址在上文中以及分析过了。
#define EXYNOS4412_SROMC_BASE 0X12570000定义的是SROMC的SFR寄存器地址。可以在Exynos4412用户手册中查到。
SROMC的SFR寄存器地址

2、新建arch/arm/mach-exynos/cbt4412_init.c

假设当前路径是arch/arm/mach-exynos/,不知道为什么我不能调用drivers/net/目录下dm9000x.c中的函数,提示错误:undefined reference to `dm9000_initialize’。(如果有看客知道如何修改Makefile或者Makefile.build或者scripts/kconfig或者scripts/Makefile.spl或者其他方法,请留言不吝赐教,谢谢!在cbt4412_init.c中声明extern int dm9000_initialize(struct bd_info *bis)或许可以。)无奈之下,我只好把dm9000x.c和dm9000x.h拷贝到arch/arm/mach-exynos/路径下,并把初始化和裸驱动函数写入cbt4412_init.c。本小节的代码都写在此源文件中。

(1)头文件和函数声明

// SPDX-License-Identifier: GPL-2.0+

#include <asm/system.h>
#include <init.h>
#include "configs/cbt4412.h"
#include "dm9000x.h"

void dm9000aep_pre_init(void);
void exynos_config_sromc(u32 srom_bank, u32 srom_bw_conf, u32 srom_bc_conf);
int board_eth_init(struct bd_info *bis);
extern int dm9000_initialize(struct bd_info *bis);

(2)SROM 控制器读时序和 DM9000A 的读时序参数

SROM 控制器读时序和 DM9000A 的读时序主要通过SROM_BCn控制寄存器设置。具体分析过程可以参考这个文献的3. SROM_BC1部分。

/* DM9000 Config */
#ifdef CONFIG_CMD_NET

#define DM9000_Tacs     (0x1)   // address set-up
#define DM9000_Tcos     (0x1)   // chip selection set-up
#define DM9000_Tacc     (0x5)   // access cycle
#define DM9000_Tcoh     (0x1)   // chip selection hold
#define DM9000_Tah      (0xC)   // address holding time
#define DM9000_Tacp     (0x9)   // page mode access cycle
#define DM9000_PMC      (0x1)   // normal(1data)page mode configuration

#endif

DECLARE_GLOBAL_DATA_PTR;

#ifdef CONFIG_TARGET_CBT4412
struct exynos_sromc {
	unsigned int bw;
	unsigned int bc[6];
};

DECLARE_GLOBAL_DATA_PTR的宏定义在arch/arm/include/asm/global_data.h中。

#define DECLARE_GLOBAL_DATA_PTR		register volatile gd_t *gd asm ("r9")

gd_t的定义在include/asm-generic/global_data.h,是名为global_data的结构体。

typedef struct global_data gd_t;

(3)初始化SROM

控制SROM本质上是配置SROM的寄存器。具体分析过程可以参考这个文献的3. SROM_BC1部分。
这里的关键是定义了int board_eth_init(struct bd_info *bis)函数。那么,board_r函数在执行的过程中会调用该函数,也就实现了DM9000的初始化。

#ifdef CONFIG_CMD_NET 
int board_eth_init(struct bd_info *bis)
{	
	int rc = 0; 
#ifdef CONFIG_DRIVER_DM9000
	dm9000aep_pre_init();
	rc = dm9000_initialize(bis);
	printascii("dm9000_initialize(bis) was runned\r\n");
#endif

#if defined(CONFIG_RESET_PHY_R)
	printascii("Reset Ethernet PHY\r\n");
	reset_phy();
#endif
	return rc;                                                               
}   
#endif 

static void dm9000aep_pre_init(void)
{
	unsigned char smc_bank_num = 1;
	unsigned int     smc_bw_conf=0;
	unsigned int     smc_bc_conf=0;

	/* gpio configuration */
	writel(0x00220020, 0x11000000 + 0x120);//GPY0CON
	writel(0x00002222, 0x11000000 + 0x140);//GPY1CON
	/* 16 Bit bus width */
	writel(0x22222222, 0x11000000 + 0x180);//GPY3CON
	writel(0x0000FFFF, 0x11000000 + 0x188);//GPY3PUD
	writel(0x22222222, 0x11000000 + 0x1C0);//GPY5CON
	writel(0x0000FFFF, 0x11000000 + 0x1C8);//GPY5PUD
	writel(0x22222222, 0x11000000 + 0x1E0);//GPY6CON
	writel(0x0000FFFF, 0x11000000 + 0x1E8);//GPY6PUD
	              
	smc_bw_conf &= ~(0xf<<4);
	smc_bw_conf |= (1<<7) | (1<<6) | (1<<5) | (1<<4);
	smc_bc_conf = ((DM9000_Tacs << 28)
			| (DM9000_Tcos << 24)
			| (DM9000_Tacc << 16)
			| (DM9000_Tcoh << 12)
			| (DM9000_Tah << 8)
			| (DM9000_Tacp << 4)
			| (DM9000_PMC));
	exynos_config_sromc(smc_bank_num,smc_bw_conf,smc_bc_conf);
}
/*
 *  exynos_config_sromc() - select the proper SROMC Bank and configure the
 *  band width control and bank control registers
 *  srom_bank    - SROM
 *  srom_bw_conf  - SMC Band witdh reg configuration value
 *  srom_bc_conf  - SMC Bank Control reg configuration value
 */

static void exynos_config_sromc(u32 srom_bank, u32 srom_bw_conf, u32 srom_bc_conf)
{
	unsigned int tmp;
	struct exynos_sromc *srom = (struct exynos_sromc *)(EXYNOS4412_SROMC_BASE);

	/* Configure SMC_BW register to handle proper SROMC
	 * bank */
	tmp = srom->bw;
	tmp &= ~(0xF << (srom_bank * 4));
	tmp |= srom_bw_conf;
	srom->bw = tmp;

	/* Configure SMC_BC
	 * register */
	srom->bc[srom_bank] = srom_bc_conf;
}

也有博文把裸驱动写入board/samsung/cbt4412/cbt4412.c,同样存在不能调用其他路径下函数的问题。如有解决者,请留言告知不吝赐教!谢谢!

3、修改arch/arm/mach-exynos/lowlevel_init.c

在arch/arm/mach-exynos/lowlevel_init.c中调用dm9000aep_pre_init()。此处也可以不修改。这样做只是为了提醒看官,此处修改并不能把网卡的驱动编译进U-Boot,因为此时还只是为U-Boot做准备而没有跳转到U-Boot。

@@ -223,6 +224,7 @@ int do_lowlevel_init(void)
 
 #ifdef CONFIG_TARGET_CBT4412
                exynos_pinmux_config(PERIPH_ID_UART0, PINMUX_FLAG_NONE);
+               dm9000aep_pre_init();
 #else
                exynos_pinmux_config(PERIPH_ID_UART3, PINMUX_FLAG_NONE);
 #endif 

基本的初始化代码完成了,但是还要修改和编译相关的部分代码。

4、修改./Makefile

为了制定交叉编译工具链版本,修改顶层目录下的Makefile。在适当位置添加 ARCH ?=arm 以及CROSS_COMPILE ?= arm-none-linux-gnueabihf-

@@ -6,6 +6,7 @@ SUBLEVEL =
 EXTRAVERSION = -rc4
 NAME =
 
+ARCH ?= arm
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
@@ -274,6 +275,13 @@ ifeq ($(HOSTARCH),$(ARCH))
 CROSS_COMPILE ?=
 endif
 
+ifeq (arm,$(ARCH))
+CROSS_COMPILE ?= arm-none-linux-gnueabihf-
+endif
+
+export ARCH CROSS_COMPILE
+
 KCONFIG_CONFIG ?= .config
 export KCONFIG_CONFIG

5、修改arch/arm/mach-exynos/Makefile

在arch/arm/mach-exynos/Makefile添加目标文件cbt4412_init.o和dm9000x.o。s5p_gpio.c也是从drivers/gpio/s5p_gpio.c复制到arch/arm/mach-exynos/的。

@@ -8,7 +8,10 @@ obj-$(CONFIG_CPU_V7A) += clock.o pinmux.o power.o system.o
 obj-$(CONFIG_ARM64)    += mmu-arm64.o
 
 obj-$(CONFIG_EXYNOS5420)       += sec_boot.o
+ifdef CONFIG_TARGET_CBT4412
 obj-$(CONFIG_S5P)      += s5p_gpio.o
+obj-y  += cbt4412_init.o
+obj-y	+= dm9000x.o
+endif
 
 ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_EXYNOS5)  += clock_init_exynos5.o

6、修改arch/arm/Kconfig

DM_ETH与DM9000x.c驱动是不兼容的,所以在arch/arm/Kconfig中删除此配置选项。如果select DM_ETH,那么编译的就是/net/eth-uclass.c,而不是/net/eth-legacy.c。

@@ -679,7 +679,6 @@ config ARCH_EXYNOS
        select DM
        select DM_GPIO
        select DM_I2C
-       select DM_ETH
        select DM_KEYBOARD
        select DM_SERIAL
        select DM_SPI

三、编译、烧写、运行

插入SD卡。
由于修改了顶层Makefile文件,所以在终端中直接运行下列命令,就可以将新的U-Boot烧写到SD卡中。
烧写的原理和步骤可参考博文的第八部分1

make distclean && make cbt4412_defconfig && make
cd sd_fuse/tiny4412/
sudo ./sd_fusing.sh /dev/sdb

U-Boot启动结果如下:

U-Boot 2022.01-rc4 (Jan 11 2022 - 09:45:22 +0800) for CBT4412

CPU:   Exynos4412 @ 1.4 GHz
Model: CBt4412 board based on Exynos4412
DRAM:  1 GiB
WARNING: Caches not enabled
MMC:   
Loading Environment from MMC... MMC Device 2 not found
*** Warning - No MMC card found, using default environment

Net:   dm9000
Error: dm9000 address not set.

Hit any key to stop autoboot:  0 
No MMC device available
Couldn't find partition mmc 0
Can't set block device
Wrong Image Format for bootm command
ERROR: can't get kernel image!
CBT4412 #

提示

Net: dm9000
Error: dm9000 address not set.

表明以上修改是成功的。后续继续修改初始化代码实现网卡功能。


  1. 为Exynos4412移植2022版U-Boot的步骤及其原理分析 ?? ??

  2. DM9000网卡原理与基地址设置 ?? ??

  3. 从0学ARM-网卡DM9000及uboot协议栈详解 ??

  4. DM9000 和处理器地址的关系 ??

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-01-14 02:08:40  更:2022-01-14 02:09:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/9 1:15:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码