Porting 2022 U-Boot for Exynos4412 -- supporting DM9000 network card


This blog post is in The 2022 version of U-Boot-2022.01-rc4 was ported for Exynos4412 Based on 1 , add DM9000AEP network card driver.

1, DM9000 base address setting principle

Circuit connection diagram


As can be seen from the above, DM9000 has only one address bus. Unlike CS8900, it has complete address bus and data bus. There is only one address line (CMD) and 16 data lines, so the positioning width can be 16 bits. Why there is only one address line is determined by DM9000. You can see from the manual that the CPU bus only accesses its two addresses: when the CMD pin is 0, the data line sends the register address of DM9000; When CMD pin is 1, 16 bit register data is sent on the data line. Therefore, the operation of DM9000 requires at least two steps: write the address first, and then write (read) the data. Unlike other memory buses, he writes data directly to the address and transmits it once, but he transmits it twice. 2

Determination of base address

Because the pin level of DM9000 is inconsistent with that of Exynos4412, a level conversion circuit is required in the middle. This is why tiny4412 uses DM9621 instead of DM9000.

 dm9000       peripheral circuit         Conversion circuit    soc 
  #CS--------Xm0CSn1_LV--------Xm0CSn1-----Xm0CSn1

As can be seen from the circuit diagram, connecting the #CS of DM9000 to the nGCS1 pin of Exynos4412 indicates that DM9000 is connected to Bank1 memory of SDRAM. From the Memory Map in the Exynos4412 user manual, the base address of the DM9000 port is 0x05000000, 3

Determination of register address

By reference blog 4 and 2 , we can know that the DM9000 register address is the base address. Therefore, a macro definition is required

#define CONFIG_DM9000_BASE     			0x05000000 
#define DM9000_IO      					CONFIG_DM9000_BASE

Determination of data address

 dm9000       peripheral circuit         Conversion circuit       soc 
  #CMD-------Xm0ADDR2_LV-----Xm0ADDR2-----Xm0ADDR2

As can be seen from the circuit diagram, the CMD pin of DM9000 is connected to ADDR2 of Exynos4412, and the address port and data port are determined by the high and low level of CMD pin. Then, when ADDR2 is 0, the address port is accessed, so when the address LADDR3-LADDR0 = 0000, that is 0x05000000; When ADDR2 is 1 and the addresses LADDR3~LADDR0 = 0100, the data port is accessed, so the address of the data port is 0x05000004. Therefore, a macro definition is required

#define DM9000_DATA    					(CONFIG_DM9000_BASE + 4)

Other pins

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

2, Modify u-boot-2022.01-rc4 source code to support DM9000AEP

0. Add bare drive principle analysis

To compile the raw drivers of USB, nandflash and DM9000 into U-Boot, one is to write the correct value of MCU related registers for initialization, and the other is to realize the functions of input and output. These all need to call functions. Then, what we need to do is find out these functions, modify the hardware model of the corresponding development board, and then compile the function source file into U-Boot by modifying Makefile.
For DM9000A, I found common / board_ r. Board in C_ init_ R() function, which calls the start sequence array function pointer init_sequence_r [], Initr in array_ Net() function pointer, which calls eth_initialize().
eth_initialize() function in / net/eth_legacy.c. eth_ legacy. Weak function is defined in C__ def_eth_init(struct bd_info *bis). The weak function can be implemented in two ways: cpu_eth_init(struct bd_info *bis) or board_eth_init(struct bd_info *bis). eth_ The initialize () function calls these three functions.

/*
 * 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")));

And cpu_eth_init and board_ eth_ Neither init function is specifically defined. The reason is very simple. The writer of U-Boot does not know what kind of network card the development board uses. In other words, the naked driver of DM9000 needs to be implemented by the transplant here. Many Samsung boards use board_eth_init() function implementation.

1. Modify board / sampling / cbt4412 / cbt4412 h

configs/cbt4412_defconfig
View the file drivers/net/Makefile:

obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o

According to Makefile, to compile DM9000A driver into u-boot, you need to define CONFIG_DRIVER_DM9000 macro.
In addition, we also need to add some u-boot commands, such as ping command to check whether the network is unobstructed and tftp to download files.

There are two ways to define macros. One is in configs/cbt4412_defconfig defines macros in board / sampling / cbt4412 / cbt4412 h. Unfortunately, I'm in configs / cbt4412_ Add config in defconfig_ DRIVER_ Dm9000 = y, but it doesn't work. Use obj - $(CONFIG_DRIVER_DM9000) + = dm9000x in drivers/net/Makefile O cannot generate dm9000x O object file. But I only have board / sampling / cbt4412 / cbt4412 H define macro config_ DRIVER_ Dm9000 and environment parameters are defined as follows:

/* 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

The base address, register address and data address of DM9000 have been analyzed above.
#define EXYNOS4412_SROMC_BASE 0X12570000 defines the SFR register address of sromc. You can find it in the Exynos4412 user manual.

2. New arch / arm / Mach exynos / cbt4412_ init. c

Assuming that the current path is arch / arm / Mach exynos /, I don't know why I can't call dm9000x in the drivers/net / directory C, prompt error: undefined reference to `dm9000_initialize’. (if any visitors know how to modify Makefile or Makefile.build or scripts/kconfig or scripts/Makefile.spl or other methods, please leave a message and don't hesitate to comment. Thank you!) In desperation, I had to put dm9000x C and dm9000x H copy to arch / arm / Mach exynos / path, and write initialization and raw driver functions to cbt4412_init.c. The code in this section is written in this source file.

(1) Header files and function declarations

// 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 controller read timing and DM9000A read timing parameters

The read timing of SROM controller and DM9000A are mainly through SROM_BCn control register setting. The specific analysis process can refer to this document 3. SROM_ Part 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 macros are defined in arch/arm/include/asm/global_data.h medium.

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

gd_t is defined in include / ASM generic / global_data. h. It's called global_data structure.

typedef struct global_data gd_t;

(3) Initialize SROM

Controlling SROM is essentially a register for configuring SROM. The specific analysis process can refer to this document 3. SROM_ Part BC1.
The key here is to define int board_eth_init(struct bd_info *bis) function. So, board_r function will be called during execution, which realizes the initialization of 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;
}

3. Modify arch / arm / Mach exynos / Lowell_ init. c

In arch / arm / Mach exynos / low level_ init. Calling cbt4412_ in C init().

@@ -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 

The basic initialization code is complete, but some code related to compilation needs to be modified.

4. Modification/ Makefile

In order to make the cross compilation tool chain version, modify the Makefile in the top-level directory. Add ARCH=arm and cross in appropriate places_ 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. Modify arch / arm / Mach exynos / makefile

Add the target file cbt4412 in arch / arm / Mach exynos / makefile_ init. O and dm9000x o. s5p_gpio.c is also from drivers/gpio/s5p_gpio.c is copied to 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. Modify arch/arm/Kconfig

DM_ETH and dm9000x C drivers are incompatible, so remove this configuration option in arch/arm/Kconfig.

@@ -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

3, Compile, burn and run

Insert the SD card.
Because the top-level Makefile file is modified, run the following commands directly in the terminal to burn the new U-Boot to the SD card.
The principles and steps of burning can be referred to in the blog Part VIII. 1

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

The results of U-Boot startup are as follows:

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 #

Tips

Net: dm9000
Error: dm9000 address not set.

It indicates that the above modification is successful. Subsequently, continue to modify the initialization code to realize the network card function.

  1. Steps and principle analysis of porting 2022 U-Boot for Exynos4412 ↩︎ ↩︎

  2. DM9000 network card principle and base address setting ↩︎ ↩︎

  3. Learn ARM network card DM9000 and uboot protocol stack from 0 ↩︎

  4. Relationship between DM9000 and processor address ↩︎

Keywords: Ubuntu U-boot

Added by badgoat on Wed, 12 Jan 2022 22:09:44 +0200