Template Information

Trang

Chủ đề

BSP (44) Device Drivers (43) WinCE (38) WINDOWS DRIVER (19) Linux Device Drivers (18) ARM (17) Android tools and tips (17) DRIVER FILES (16) Windows Device Driver (16) AUDIO DRIVER (12) 8051 (8) OMAP (7) PRINTER DRIVER FILES (7) C Programming (6) ASUS MOTHERBOARD (5) Interfacing (5) NETWORK ADAPTER (5) VIDEO DRIVER (5) CANON (3) Device Driver Downloads (3) MOBILE PHONE (3) Asus Driver (2) EPSON (2) Epson Printer Driver (2) HP LAPTOP DRIVER (2) LAPTOP DRIVER FILES (2) Logitech Driver (2) NETWORK ADAPTOR (2) OMAP 4430 (2) drivers download (2) ACER (1) ACER TABLET (1) ALL IN ONE DRIVER (1) Acer Aspire 5738 Drivers (1) Analog-to-Digital (1) Asus Drivers (1) Asus Motherboard Drivers (1) Chip Architecture (1) DELL (1) Dell D610 Drivers (1) Dell Drivers (1) Device Drivers Download (1) Device drivers interview questions (1) Display Driver (1) Drivers Download for Windows 7 (1) EEPROMs (1) Free Asus Motherboard Drivers (1) Free Drivers Download for Windows 7 (1) GRAPHIC DRIVER (1) HP Driver (1) Hardware (1) Intel Drivers (1) Intel P35 (1) Intel P35 chipset drivers (1) I²C (1) LAPTOP SERVICE MANUAL (1) LCD (1) Logitech Mouse Driver (1) Logitech webcam driver (1) MODEM DRIVER (1) Motherboard Drivers for Windows 7 (1) PARALLEL PORT (1) Pc Driver (1) RTOS (1) Real Time Clock (1) Sensors (1) USB CABLE DRIVER (1) WEBCAM DRIVER (1) WIRELESS ADAPTOR (1) Windows 7 Drivers (1) Windows Mobile (1) acer driver (1) acer driver downloads (1) acer laptop driver (1) chipset drivers (1) network card driver (1) network driver download (1) sdcc (1)

Bài viết ngẫu nhiên

Xem phim HD Online

Số lượt views

How to write your own U-boot

Thứ Năm, 30 tháng 6, 2011 / 04:55


I. Introduction
Recently got a LIYUTAI of 44B0X board, so I plan to own to be BOOTLOADER, on http://www.sf.net, has been found that
After it was done quite perfected. Do not think so much, and transplanted to say!
Second, download the source code
U-BOOT-1.3.2: ftp://ftp.denx.de/pub/u-boot/u-boot-1.3.2.tar.bz2
ELDK: ftp://ftp.denx.de/pub/eldk/4.1/arm-linux-x86/iso/arm-2007-01-21.iso
(Originally used by 2.95 the arm-elf-gcc to compile, but the problems are too many soft floating point,-MQ option is not supported, and so on, that's all my online
Are met. It seems their luck is good ah)
Third, extract the installation
U-BOOT-1.3.2 can directly extract
tar-jxf u-boot-1.3.2.tar.bz2
ELDK you need through a virtual drive to install. I am using the VM to run LINUX, so direct use of the virtual drive load on it. Into the CD-ROM project
Record, enter
. / Install-d / opt / eldk /
Less than five minutes to complete the installation. I remember in the / etc / profile I added the search path.
Fourth, start migration
1) a copy of the data plate B2.
Analysis found that the B2 plate with ARMSYS 44B0 of the board closest to, it started from it.
[Root @ localhost u-boot-1.3.2] # mkdir board / armsys
[Root @ localhost u-boot-1.3.2] # cp-r board / dave / * board / armsys /
[Root @ localhost u-boot-1.3.2] # mv board/armsys/B2 / board/armsys/44B0 /
[Root @ localhost u-boot-1.3.2] # mv board/armsys/44B0/B2.c board/armsys/44B0/44B0.c
[Root @ localhost u-boot-1.3.2] # cp include/configs/B2.h include/configs/44B0.h
2) modify the main Makefile, add 44B0 options
Open u-boot-1.3.2 directory Makefile, be in B2_config below to add a
44B0_config: unconfig
@ $ (MKCONFIG) $(@:_ config =) arm s3c44b0 44B0 armsys
(Remember to use TAB instead of spaces needed!)
3) modify the configuration of the CPU
Now need to modify the configuration of 44B0. U-BOOT-1.3.2 directory of the CPU has a lot of CPU to manage the classification, just change it
Can be used. We have chosen S344B0 the CPU. According LIYUTAI source code, we only need to modify the corresponding part of it.
A. modify start.s file (see LIYUTAI of BOOTLOADER)
# Include <config.h>
# Include <version.h>
//********** OPTIONS *******************************
/ / _RAM_STARTADDRESS EQU 0xc000000
# Define _ISR_STARTADDRESS 0xc7ff000 / / GCS6: 8MB SDRAM
# Define _IRQ_BASEADDRESS 0xc000000 / / GCS6: 8MB SDRAM
/ / GBLA PLLCLK
Welcome to reprint. Please keep the copyright information 1
Author: Ken Wu E-mail: kenwucn@qq.com
# Define PLLCLK 64000000
/ / The system frequency is calculated as follows:
/ / Fout = (8 + M_DIV) * Fin / [(2 + P_DIV) * 2]
# Define M_DIV 56 / / Fin = 8MHz Fout = ((56 +8) / 8) * 8 = 64MHz
# Define P_DIV 2
# Define S_DIV 1
/ *
* Jump vector table
* /
. Globl _start
_start:
b reset / / Reset
ldr pc, = (_IRQ_BASEADDRESS + 0x04) / / HandlerUndef
ldr pc, = (_IRQ_BASEADDRESS + 0x08) / / HandlerSWI
ldr pc, = (_IRQ_BASEADDRESS + 0x0C) / / HandlerPabort
ldr pc, = (_IRQ_BASEADDRESS + 0x10) / / HandlerDAbort
ldr pc, = (_IRQ_BASEADDRESS + 0x14) / / HandlerReserved
ldr pc, = (_IRQ_BASEADDRESS + 0x18) / / HandlerIRQ
ldr pc, = (_IRQ_BASEADDRESS + 0x1C) / / HandlerFIQ
. Balignl 16,0 xdeadbeef
/ *
************************************************** ***********************
*
* Startup Code (reset vector)
*
* Do important init only if we don't start from memory!
* Relocate u-boot to ram
* Setup stack
* Jump to second stage
*
************************************************** ***********************
* /
_TEXT_BASE:
. Word TEXT_BASE
. Globl _armboot_start
_armboot_start:

. Word _start
/ *
* These are defined in the board-specific linker script.
* /
. Globl _bss_start
_bss_start:
. Word __bss_start
. Globl _bss_end
_bss_end:
. Word _end
# Ifdef CONFIG_USE_IRQ
/ * IRQ stack memory (calculated at run-time) * /
. Globl IRQ_STACK_START
IRQ_STACK_START:
. Word 0x0badc0de
/ * IRQ stack memory (calculated at run-time) * /
. Globl FIQ_STACK_START
FIQ_STACK_START:
. Word 0x0badc0de
# Endif
/ *
* The actual reset code
* /
reset:
/ *
* Set the cpu to SVC32 mode
* /
mrs r0, cpsr
bic r0, r0, # 0x1f
orr r0, r0, # 0x13
msr cpsr, r0
/ *
* We do sys-critical inits only at reboot,
* Not when booting from ram!
* /
# Ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit

/ *
* Before relocating, we have to setup RAM timing
* Because memory timing is board-dependend, you will
* Find a lowlevel_init.S in your board directory.
* /
bl lowlevel_init
# Endif
/ **
* Test the memory befor relocate
* /
# Ifdef CONFIG_MEM_TEST
# Define PDATE 0x1d2002c
ldr r0, = PHYS_SDRAM_1 / / address pointer
ldr r1, = PHYS_SDRAM_1_SIZE / / address of the border
add r1, r0, r1 / / r1 is the bound
ldr r3, = 0xAA55AA44
loop:
str r3, [r0] / / save data to memory
ldr r4, [r0] / / re-read data
cmp r4, r3 / / compare data
bne error
add r0, r0, # 4 / / pointer to point to the next
cmp r0, r1 / / determine whether to reach the border
beq mem_test_ok
bne loop
error:
ldr r0, = PDATE / / PDATE = PDATE &0x1f7;
ldr r1, [r0]
ldr r2, = 0x1f7
and r1, r1, r2
str r1, [r0]
bl delay / / Beep
ldr r1, [r0] / / PDATE = PDATE | 0x8;
mov r2, # 0x8
orr r1, r1, r2
str r1, [r0]
bl delay / / stop Beep
end:
b end / / stop
delay:
ldr r3, = 0xFFFF
e_loop1:
sub r3, r3, # 1

cmp r3, # 0
beq loop_end
ldr r4, = 0xFF
e_loop2:
sub r4, r4, # 1
cmp r4, # 0
bne e_loop2
b e_loop1
loop_end:
mov pc, lr
mem_test_ok:
# Endif
# Ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: / * relocate U-Boot to RAM * /
adr r0, _start / * r0 <- current position of code * /
ldr r1, _TEXT_BASE / * test if we run from flash or RAM * /
cmp r0, r1 / * don't reloc during debug * /
beq stack_setup
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 / * r2 <- size of armboot * /
add r2, r0, r2 / * r2 <- source end address * /
copy_loop:
ldmia r0!, {r3-r10} / * copy from source address [r0] * /
stmia r1!, {r3-r10} / * copy to target address [r1] * /
cmp r0, r2 / * until source end addreee [r2] * /
ble copy_loop
/ *
now copy to sram the interrupt vector
* /
adr r0, real_vectors
add r2, r0, # 1024
ldr r1, = 0x0c000000
add r1, r1, # 0x08
vector_copy_loop:
ldmia r0!, {r3-r10}
stmia r1!, {r3-r10}
cmp r0, r2
ble vector_copy_loop
# Endif / * CONFIG_SKIP_RELOCATE_UBOOT * /
Welcome to reprint. Please keep the copyright information 5
Author: Ken Wu E-mail: kenwucn@qq.com
/ * Set up the stack * /
stack_setup:
ldr r0, _TEXT_BASE / * upper 128 KiB: relocated uboot * /
sub r0, r0, # CFG_MALLOC_LEN / * malloc area * /
sub r0, r0, # CFG_GBL_DATA_SIZE / * bdinfo * /
# Ifdef CONFIG_USE_IRQ
sub r0, r0, # (CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ)
# Endif
sub sp, r0, # 12 / * leave 3 words for abort-stack * /
clear_bss:
/ * BSS segment start address * /
ldr r0, _bss_start
/ * BSS segment end address * /
ldr r1, _bss_end
/ * BSS segment set to 0 * /
mov r2, # 0x00000000
clbss_l:
/ * Clear BSS section loop * /
str r2, [r0]
add r0, r0, # 4
cmp r0, r1
ble clbss_l
ldr pc, _start_armboot
_start_armboot:. word start_armboot
/ *
************************************************** ***********************
*
* CPU_init_critical registers
*
* Setup important registers
* Setup memory timing
*
************************************************** ***********************
* /
# Define INTCON (0x01c00000 +0 x200000)
# Define INTMSK (0x01c00000 +0 x20000c)
# Define LOCKTIME (0x01c00000 +0 x18000c)
# Define PLLCON (0x01c00000 +0 x180000)
# Define CLKCON (0x01c00000 +0 x180004)
# Define WTCON (0x01c00000 +0 x130000)
cpu_init_crit:
/ * Disable watch dog * /
ldr r0, = WTCON

ldr r1, = 0x0
str r1, [r0]
/ *
* Mask all IRQs by clearing all bits in the INTMRs
* /
ldr r1, = INTMSK
ldr r0, = 0x07fffeff
str r0, [r1]
ldr r1, = INTCON
ldr r0, = 0x05
str r0, [r1]
/ * Set Clock Control Register * /
ldr r0, = LOCKTIME
ldr r1, = 0xfff
str r1, [r0]
ldr r1, = PLLCON
# If CONFIG_S3C44B0_CLOCK_SPEED == 66
ldr r0, = 0x34031 / * 66MHz (Quartz = 11MHz) * /
# Elif CONFIG_S3C44B0_CLOCK_SPEED == 75
ldr r0, = 0x610c1 / * B2: Xtal = 20mhz Fclk = 75MHz * /
# Elif CONFIG_S3C44B0_CLOCK_SPEED == 64
ldr r0, = 0x38021 / / Fin = 8MHz, Fout = 64MHz
# Else
# Error CONFIG_S3C44B0_CLOCK_SPEED undefined
# Endif
str r0, [r1]
ldr r1, = CLKCON
ldr r0, = 0x7ff8
str r0, [r1]
mov pc, lr
/************************************************* /
/ * Interrupt vectors * /
/************************************************* /
real_vectors:
b reset
b undefined_instruction

b software_interrupt
b prefetch_abort
b data_abort
b not_used
b irq
b fiq
/************************************************* /
undefined_instruction:
mov r6, # 3
b reset
software_interrupt:
mov r6, # 4
b reset
prefetch_abort:
mov r6, # 5
b reset
data_abort:
mov r6, # 6
b reset
not_used:
/ * We * should * never reach this * /
mov r6, # 7
b reset
irq:
mov r6, # 8
b reset
fiq:
mov r6, # 9
b reset
B. modify serial.c, modify serial_setbrg. Function as the board's baud rate to use 64MHz, so the need to increase the corresponding baud rate configurations
void serial_setbrg (void)
{
u32 divisor = 0;
/ * Get correct divisor * /
switch (gd-> baudrate) {

case 1200:
# If CONFIG_S3C44B0_CLOCK_SPEED == 66
divisor = 3124;
# Elif CONFIG_S3C44B0_CLOCK_SPEED == 75
divisor = 3905;
# Elif CONFIG_S3C44B0_CLOCK_SPEED == 64
divisor = 3124;
# Else
# Error CONFIG_S3C44B0_CLOCK_SPEED undefined
# Endif
break;
case 9600:
# If CONFIG_S3C44B0_CLOCK_SPEED == 66
divisor = 390;
# Elif CONFIG_S3C44B0_CLOCK_SPEED == 75
divisor = 487;
# Elif CONFIG_S3C44B0_CLOCK_SPEED == 64
divisor = 390;
# Else
# Error CONFIG_S3C44B0_CLOCK_SPEED undefined
# Endif
break;
case 19200:
# If CONFIG_S3C44B0_CLOCK_SPEED == 66
divisor = 194;
# Elif CONFIG_S3C44B0_CLOCK_SPEED == 75
divisor = 243;
# Elif CONFIG_S3C44B0_CLOCK_SPEED == 64
divisor = 194;
# Else
# Error CONFIG_S3C44B0_CLOCK_SPEED undefined
# Endif
break;
case 38400:
# If CONFIG_S3C44B0_CLOCK_SPEED == 66
divisor = 97;
# Elif CONFIG_S3C44B0_CLOCK_SPEED == 75
divisor = 121;
# Elif CONFIG_S3C44B0_CLOCK_SPEED == 64
divisor = 97;
# Else
# Error CONFIG_S3C44B0_CLOCK_SPEED undefined
# Endif / * break; * /

case 57600:
# If CONFIG_S3C44B0_CLOCK_SPEED == 66
divisor = 64;
# Elif CONFIG_S3C44B0_CLOCK_SPEED == 75
divisor = 80;
# Elif CONFIG_S3C44B0_CLOCK_SPEED == 64
divisor = 68;
# Else
# Error CONFIG_S3C44B0_CLOCK_SPEED undefined
# Endif / * break; * /
case 115200:
# If CONFIG_S3C44B0_CLOCK_SPEED == 66
divisor = 32;
# Elif CONFIG_S3C44B0_CLOCK_SPEED == 75
divisor = 40;
# Elif CONFIG_S3C44B0_CLOCK_SPEED == 64
divisor = 34;
# Else
# Error CONFIG_S3C44B0_CLOCK_SPEED undefined
# Endif / * break; * /
}
serial_flush_output ();
serial_flush_input ();
UFCON0 = 0x0;
ULCON0 = 0x03;
UCON0 = 0x245;
UBRDIV0 = divisor;
UFCON1 = 0x0;
ULCON1 = 0x03;
UCON1 = 0x245;
UBRDIV1 = divisor;
for (divisor = 0; divisor <100; divisor + +) {
/ * NOP * /
}
}
At this point, CPU configuration is complete. Next, modify the board configuration.
Into armsys/44B0 folder, start the configuration 44B0 board.
4)
A. modify lowlevel_init.S. lowlevel_init.S is related to external devices to read and write timing, the delay of the configuration file, you can use LIYUTAI of
(LIYUTAI RAM configuration is not very good, but just be able to spend just a little more slowly.)
Configured on it.
. Equ B0_Tacs, 0x0 / * 0clk * /

. Equ B0_Tcos, 0x1 / * 0clk * /
. Equ B0_Tacc, 0x6 / * 10clk * /
. Equ B0_Tcoh, 0x1 / * 0clk * /
. Equ B0_Tah, 0x0 / * 0clk * /
. Equ B0_Tacp, 0x0 / * 0clk * /
. Equ B0_PMC, 0x0 / * normal (1data) * /
/ * Bank 1 parameter * /
. Equ B1_Tacs, 0x3 / * 4clk * /
. Equ B1_Tcos, 0x3 / * 4clk * /
. Equ B1_Tacc, 0x7 / * 14clkv * /
. Equ B1_Tcoh, 0x3 / * 4clk * /
. Equ B1_Tah, 0x3 / * 4clk * /
. Equ B1_Tacp, 0x3 / * 6clk * /
. Equ B1_PMC, 0x0 / * normal (1data) * /
/ * Bank 2 parameter * /
. Equ B2_Tacs, 0x3 / * 4clk * /
. Equ B2_Tcos, 0x3 / * 4clk * /
. Equ B2_Tacc, 0x7 / * 14clk * /
. Equ B2_Tcoh, 0x3 / * 4clk * /
. Equ B2_Tah, 0x3 / * 4clk * /
. Equ B2_Tacp, 0x3 / * 6clk * /
. Equ B2_PMC, 0x0 / * normal (1data) * /
/ * Bank 3 parameter * /
. Equ B3_Tacs, 0x3 / * 4clk * /
. Equ B3_Tcos, 0x3 / * 4clk * /
. Equ B3_Tacc, 0x7 / * 14clk * /
. Equ B3_Tcoh, 0x3 / * 4clk * /
. Equ B3_Tah, 0x3 / * 4clk * /
. Equ B3_Tacp, 0x3 / * 6clk * /
. Equ B3_PMC, 0x0 / * normal (1data) * /
/ * Bank 4 parameter * /
. Equ B4_Tacs, 0x3 / * 4clk * /
. Equ B4_Tcos, 0x3 / * 4clk * /
. Equ B4_Tacc, 0x7 / * 14clk * /
. Equ B4_Tcoh, 0x3 / * 4clk * /
. Equ B4_Tah, 0x3 / * 4clk * /
. Equ B4_Tacp, 0x3 / * 6clk * /
. Equ B4_PMC, 0x0 / * normal (1data) * /
/ * Bank 5 parameter * /
. Equ B5_Tacs, 0x3 / * 4clk * /
. Equ B5_Tcos, 0x3 / * 4clk * /
. Equ B5_Tacc, 0x7 / * 14clk * /

. Equ B5_Tcoh, 0x3 / * 4clk * /
. Equ B5_Tah, 0x3 / * 4clk * /
. Equ B5_Tacp, 0x3 / * 6clk * /
. Equ B5_PMC, 0x0 / * normal (1data) * /
/ * Bank 6 (if SROM) parameter * /
. Equ B6_Tacs, 0x3 / * 4clk * /
. Equ B6_Tcos, 0x3 / * 4clk * /
. Equ B6_Tacc, 0x7 / * 14clk * /
. Equ B6_Tcoh, 0x3 / * 4clk * /
. Equ B6_Tah, 0x3 / * 4clk * /
. Equ B6_Tacp, 0x3 / * 6clk * /
. Equ B6_PMC, 0x0 / * normal (1data) * /
/ * Bank 7 (if SROM) parameter * /
. Equ B7_Tacs, 0x3 / * 4clk * /
. Equ B7_Tcos, 0x3 / * 4clk * /
. Equ B7_Tacc, 0x7 / * 14clk * /
. Equ B7_Tcoh, 0x3 / * 4clk * /
. Equ B7_Tah, 0x3 / * 4clk * /
. Equ B7_Tacp, 0x3 / * 6clk * /
. Equ B7_PMC, 0x0 / * normal (1data) * /
/ * Bank 6 parameter * /
. Equ B6_MT, 0x3 / * SDRAM * /
. Equ B6_Trcd, 0x1 / * 2clk * /
. Equ B6_SCAN, 0x0 / * 10bit * /
. Equ B7_MT, 0x3 / * SDRAM * /
. Equ B7_Trcd, 0x1 / * 2clk * /
. Equ B7_SCAN, 0x0 / * 10bit * /
/ * REFRESH parameter * /
. Equ REFEN, 0x1 / * Refresh enable * /
. Equ TREFMD, 0x0 / * CBR (CAS before RAS) / Auto refresh * /
. Equ Trp, 0x1 / * 2clk * /
. Equ Trc, 0x1 / * 0x1 = 5clk 0x3 = 11clk * /
. Equ Tchr, 0x2 / * 0x2 = 3clk 0x0 = 0clks * /
. Equ REFCNT, 1050 / /; period = 15.6us, MCLK = 64Mhz
MEMORY_CONFIG:
. Long 0x11010101 / * Bank0 = OM [1:0], Bank1-7 16bit, Bank2 = Nowait, UB / LB * /
. Word
((B0_Tacs <<13) + (B0_Tcos <<11) + (B0_Tacc <<8) + (B0_Tcoh <<6) + (B0_Tah <<4) + (B0_Tacp <<2) + (B0_PMC))
/ * GCS0 * /

. Word
((B1_Tacs <<13) + (B1_Tcos <<11) + (B1_Tacc <<8) + (B1_Tcoh <<6) + (B1_Tah <<4) + (B1_Tacp <<2) + (B1_PMC))
/ * GCS1 * /
. Word
((B2_Tacs <<13) + (B2_Tcos <<11) + (B2_Tacc <<8) + (B2_Tcoh <<6) + (B2_Tah <<4) + (B2_Tacp <<2) + (B2_PMC))
/ * GCS2 * /
. Word
((B3_Tacs <<13) + (B3_Tcos <<11) + (B3_Tacc <<8) + (B3_Tcoh <<6) + (B3_Tah <<4) + (B3_Tacp <<2) + (B3_PMC))
/ * GCS3 * /
. Word
((B4_Tacs <<13) + (B4_Tcos <<11) + (B4_Tacc <<8) + (B4_Tcoh <<6) + (B4_Tah <<4) + (B4_Tacp <<2) + (B4_PMC))
/ * GCS4 * /
. Word
((B5_Tacs <<13) + (B5_Tcos <<11) + (B5_Tacc <<8) + (B5_Tcoh <<6) + (B5_Tah <<4) + (B5_Tacp <<2) + (B5_PMC))
/ * GCS5 * /
. Word ((B6_MT <<15) + (B6_Trcd <<2) + (B6_SCAN)) / * GCS6 * /
. Word ((B7_MT <<15) + (B7_Trcd <<2) + (B7_SCAN)) / * GCS7 * /
. Word ((REFEN <<23) + (TREFMD <<22) + (Trp <<20) + (Trc <<18) + (Tchr <<16) + REFCNT) / * REFRESH RFEN = 1,
TREFMD = 0, trp = 3clk, trc = 5clk, tchr = 3clk, count = 1019 * /
. Word 0x17 / * SCLK power down mode, BANKSIZE 16M/16M * /
. Word 0x20 / * MRSR6 CL = 2clk * /
. Word 0x20 / * MRSR7 * /
B. modify the files inside the board_init 44B0.c function, this function is U-BOOT to complete initialization after entering the bottom of the first C function.
int board_init (void)
{
/ / CAUTION: Follow the configuration order for setting the ports.
/ / 1) setting value
/ / 2) setting control register
/ / 3) configure pull-up resistor.
/ / 16bit data bus configuration
/ / PORT A GROUP
/ * BIT 98 7 6 5 4 3 2 1 0 * /
/ * A24 A23 A22 A21 A20 A19 A18 A17 A16 A0 * /
/ * 1111111111 * /
PCONA = 0x3ff;
/ / PORT B ​​GROUP
/ * BIT 10 9 8 7 6 5 4 3 2 1 0
* /
/ * / CS5 / CS4 / CS3 / CS2 / CS1 nWBE3 nWBE2 / SRAS / SCAS SCLK SCKE
* /
/ * EXT NIC USB IDE SMC NC NC Sdram Sdram Sdram
Sdram * /

/ * 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 * /
PDATB = 0x7ff;
PCONB = 0x7cf;
/ / PORT C GROUP
/ / BUSWIDTH = 16 * /
/ * PC15 14 13 12 11 10 9 8 * /
/ * IO RXD1 TXD1 IIII * /
/ * PS2DAT DCLK Uart1 Uart1 NC NC NC NC * /
/ * 0,001,111,100,000,000 * /
/ * PC7 6 5 4 3 2 1 0 * /
/ * IIIIIIII * /
/ * VD4 VD5 VD6 VD7 SMCALE SMCCLE SMCCE SMCRB * /
/ * 0,000,000,001,010,100 * /
PDATC = 0xffff; / / All IO is high
PCONC = 0x1f05ff54;
PUPC = 0x3000; / / PULL UP RESISTOR should be enabled to I / O
/ / PORT D GROUP
/ * PORT D GROUP (I / O OR LCD) * /
/ * BIT 7 6 5 4 3 2 1 0 * /
/ * VF VM VLINE VCLK VD3 VD2 VD1 VD0 * /
/ * 0,000,000,000,000,000 * /
PDATD = 0xff;
PCOND = 0xaaaa;
PUPD = 0x0;
/ / These pins must be set only after CPU's internal LCD controller is enable
/ / PORT E GROUP
/ * Bit 8 7 6 5 4 3 2 1 0 * /
/ * LcdBL LED4 LED5 LED6 LED7 BEEP RXD0 TXD0 LcdDisp * /
/ * 01 0,101,010,101,101,001 * /
PDATE = 0x1ff;
PCONE = 0x25569;
PUPE = 0x6;
/ / PORT F GROUP
/ * Bit8 7 6 5 4 3 2 1 0 * /
/ * IISCLK IISDI IISDO IISLRCK Input Input Input IICSDA IICSCL * /
/ * 100 1,001,001,000,000,001,010 * /
PDATF = 0x0;
PCONF = 0x24900a;
PUPF = 0x1e3;
/ / PORT G GROUP

/ * BIT7 6 5 4 3 2 1 0 * /
/ * INT7 INT6 INT5 INT4 INT3 INT2 INT1
INT0 * /
/ * S3 S4 S5 S6 NIC EXT IDE USB * /
/ * 1,111,111,111,111,111 * /
/ / RPDATG = 0xff;
/ / RPCONG = 0xffff;
PCONG = 0x00ff; / / EXINT0 ~ 3 enabled
PUPG = 0x0; / / pull-up regiseter should be enabled
SPUCR = 0x7; / / D15-D0 pull-up disable
/ * Are low-level trigger, Exint3 set to rising edge ---- modify at 04-12-11 * /
EXTINT = 0x0 | (1 <<14);
return 0;
}
Can be used directly LIYUTAI port initialization function instead on it.
Modify the Makefile to replace 44B0.o ​​B2.o
C.
Modify config.mk file, change the value of the TEXT_BASE 0x0C300000. This is only 2M order to leave space to download the kernel.
D.
U-BOOT boot code will copy TEXT_BASE position, if you do not modify this value, the code will download the larger dead
Machine.
Modify board / armsys / common / flash.c configuration, add flash support.
E.
flash.c:
case (CFG_FLASH_WORD_SIZE) SST_ID_xF160A:
case (CFG_FLASH_WORD_SIZE) SST_ID_xF1601:
And replace all the B2 as 44B0, so as to build into it at compile time
At this point, 44B0 board has been configured. Then you modify configuration files.
Modify include/configs/44B0.h file.
5)
The following is my entire 44B0.h profile
# Ifndef __CONFIG_H
# Define __CONFIG_H
/ *
* High Level Configuration Options
* (Easy to change)
* /
# Define CONFIG_ARM7 1 / * This is a ARM7 CPU * /
# Define CONFIG_44B0 1 / * on an 44B0 Board * /
# Define CONFIG_ARM_THUMB 1 / * this is an ARM7TDMI * /
# Undef CONFIG_ARM7_REVD / * disable ARM720 REV.D Workarounds * /

# Define CONFIG_S3C44B0_CLOCK_SPEED 64 / * we have a 75Mhz S3C44B0 * /
/ / # Define CONFIG_MEM_TEST / / do ram test
# Define CONFIG_SILENT_CONSOLE 1 / / config with silent
# Undef CONFIG_USE_IRQ / * don't need them anymore * /
/ *
* Size of malloc () pool
* /
# Define CFG_MONITOR_LEN (256 * 1024) / * Reserve 256 kB for Monitor * /
# Define CFG_ENV_SIZE 1024 / * 1024 bytes may be used for env vars * /
# Define CFG_MALLOC_LEN (CFG_ENV_SIZE + 128 * 1024)
# Define CFG_GBL_DATA_SIZE 128 / * size in bytes reserved for initial data * /
/ *
* Hardware drivers
* /
/ / # Define CONFIG_DRIVER_LAN91C96
/ / # Define CONFIG_LAN91C96_BASE 0x04000300 / * base address * /
/ / # Define CONFIG_SMC_USE_32_BIT
/ / # Undef CONFIG_SHOW_ACTIVITY
/ / # Define CONFIG_NET_RETRY_COUNT 10 / * # of retries * /
# Define CONFIG_DRIVER_RTL8019
# Define RTL8019_BASE 0x08000000
/ / # Define ET_DEBUG / / DEBUG the ethernet
/ *
* Select serial console configuration
* /
# Define CONFIG_SERIAL1 1 / * we use Serial line 1 * /
/ * Allow to overwrite serial and ethaddr * /
# Define CONFIG_ENV_OVERWRITE
# Define CONFIG_BAUDRATE 115200
/ *
* BOOTP options
* /
# Define CONFIG_BOOTP_SUBNETMASK
# Define CONFIG_BOOTP_GATEWAY
# Define CONFIG_BOOTP_HOSTNAME

# Define CONFIG_BOOTP_BOOTPATH
# Define CONFIG_BOOTP_BOOTFILESIZE
/ *
* Command line configuration.
* /
# Include <config_cmd_default.h>
# Define CONFIG_CMD_DATE
# Define CONFIG_CMD_ELF
/ / # Define CONFIG_CMD_EEPROM
/ / # Define CONFIG_CMD_I2C
# Define CONFIG_CMD_PING / / ping cmd enable
# Define CONFIG_CMD_FLASH / / nor flash support
/ / # Define CONFIG_CMD_NAND / / nand flash support
# Define CONFIG_BOOTDELAY 1
# Define CONFIG_ETHADDR 00:50: c2: 1e: af: fb
# Define CONFIG_BOOTARGS "setenv bootargs root = / dev / ram ip = 192.168.1000.70 ::::: eth0: off \
ether = 25,0,0,0, eth0 ethaddr = 00:50: c2: 1e: af: fb "
# Define CONFIG_NETMASK 255.255.255.0
# Define CONFIG_IPADDR 192.168.100.70
# Define CONFIG_SERVERIP 192.168.100.163
# Define CONFIG_BOOTFILE "image.ram"
/ / # Define CONFIG_BOOTCOMMAND "bootm 20000 f0000"
/ / # Define CONFIG_BOOTCOMMAND "base 0" / / for debuging
# Define CONFIG_BOOTCOMMAND "?" / / For debuging
/ *
* Miscellaneous configurable options
* /
# Define CFG_LONGHELP / * undef to save memory * /
# Define CFG_PROMPT "U-Boot (Ken Wu)>" / * Monitor Command Prompt * /
# Define CFG_CBSIZE 256 / * Console I / O Buffer Size * /
# Define CFG_PBSIZE (CFG_CBSIZE + sizeof (CFG_PROMPT) +16) / * Print Buffer Size * /
# Define CFG_MAXARGS 16 / * max number of command args * /
# Define CFG_BARGSIZE CFG_CBSIZE / * Boot Argument Buffer Size * /
# Define CFG_MEMTEST_START0x0C400000 / * memtest works on * /
# Define CFG_MEMTEST_END 0x0C800000 / * 4 ... 8 MB in DRAM * /
# Undef CFG_CLKS_IN_HZ / * everything, incl board info, in Hz * /
# Define CFG_LOAD_ADDR 0x0c008000 / * default load address * /

# Define CFG_HZ 1000 / * 1 kHz * /
/ * Valid baudrates * /
# Define CFG_BAUDRATE_TABLE {9600, 19200, 38400, 57600, 115200}
/*------------------------------------------------ -----------------------
* Stack sizes
*
* The stack sizes are set up in start.S using the settings below
* /
# Define CONFIG_STACKSIZE (128 * 1024) / * regular stack * /
# Ifdef CONFIG_USE_IRQ
# Define CONFIG_STACKSIZE_IRQ (4 * 1024) / * IRQ stack * /
# Define CONFIG_STACKSIZE_FIQ (4 * 1024) / * FIQ stack * /
# Endif
/*------------------------------------------------ -----------------------
* Physical Memory Map
* /
# Define CONFIG_NR_DRAM_BANKS 1 / * we have 1 banks of DRAM * /
# Define PHYS_SDRAM_1 0x0C000000 / * SDRAM Bank # 1 * /
# Define PHYS_SDRAM_1_SIZE 0x00800000 / * 8 MB * /
/ / # Define CONFIG_HAS_DATAFLASH / / we have flash
# Define PHYS_FLASH_1 0x00000000 / * Flash Bank # 1 * /
# Define PHYS_FLASH_SIZE 0x00200000 / * 2 MB * /
/ / # Define CFG_FLASH_BASE PHYS_FLASH_1
/*------------------------------------------------ -----------------------
* FLASH and environment organization
* /
/*------------------------------------------------ -----------------------
* FLASH organization
* /
# Define CFG_MAX_FLASH_BANKS 1 / * max number of memory banks * /
# Define CFG_MAX_FLASH_SECT 32 / * max number of sectors on one chip * /
# Define FLASH_BLOCK_SIZE 0x00010000 / / flash block size
# Define CFG_FLASH_ERASE_TOUT 120000 / * Timeout for Flash Erase (in ms) * /
# Define CFG_FLASH_WRITE_TOUT 1000 / * Timeout for Flash Write (in ms) * /
# Define CFG_FLASH_WORD_SIZE unsigned short / * flash word size (width) * /
# Define CFG_FLASH_ADDR0 0x5555 / * 1st address for flash config cycles * /
# Define CFG_FLASH_ADDR1 0x2AAA / * 2nd address for flash config cycles * /
/ *

* The following defines are added for buggy IOP480 byte interface.
* All other boards should use the standard values ​​(CPCI405 etc.)
* /
# Define CFG_FLASH_READ0 0x0000 / * 0 is standard * /
# Define CFG_FLASH_READ1 0x0001 / * 1 is standard * /
# Define CFG_FLASH_READ2 0x0002 / * 2 is standard * /
# Define CFG_FLASH_EMPTY_INFO / * print 'E' for empty sector on flinfo * /
/ **
* NAND flash organization & operation
* /
# If defined (CONFIG_CMD_NAND)
# Define NAND_DEBUG 1 / / debug the nand info
# Define CFG_NAND_LEGACY
# Define CFG_NAND_BASE 0x02000000
# Define CFG_MAX_NAND_DEVICE 1 / * Max number of NAND devices * /
# Define SECTORSIZE 512
# Define ADDR_COLUMN 1
# Define ADDR_PAGE 2
# Define ADDR_COLUMN_PAGE 3
# Define NAND_ChipID_UNKNOWN 0x00
# Define NAND_MAX_FLOORS 1
# Define NAND_MAX_CHIPS 1
# Define NAND_WAIT_READY (nand) WAIT_RB ()
# Define NAND_DISABLE_CE (nand) ST_INVALID ()
# Define NAND_ENABLE_CE (nand)
# Define WRITE_NAND_COMMAND (d, adr) NAND_write_cmd (d)
/ / # Define WRITE_NAND_COMMANDW (d, adr) NF_CmdW (d)
# Define WRITE_NAND_ADDRESS (d, adr) NAND_write_addr (d)
# Define WRITE_NAND (d, adr) NAND_write (d)
# Define READ_NAND (adr) NAND_read ()
/ *
* The following functions are NOP's because S3C24X0 handles this in hardware
* But it must define in S344B0 board because the board does not support the interface
* /
# Define NAND_CTL_CLRALE (nandptr)
# Define NAND_CTL_SETALE (nandptr)
# Define NAND_CTL_SETCLE (nandptr)

/ / Do not use write verify and jffs2 ecc at first
/ / # Define CONFIG_MTD_NAND_VERIFY_WRITE 1
/ / # Define CONFIG_MTD_NAND_ECC_JFFS2 1
# Endif
/*------------------------------------------------ -----------------------
* Environment Variable setup
* /
/ / # Define CFG_ENV_IS_IN_EEPROM 1 / * use EEPROM for environment vars * /
/ / # Define CFG_ENV_OFFSET 0x0 / * environment starts at the beginning of the EEPROM * /
# Define CFG_ENV_IS_IN_FLASH 1
# Undef CFG_ENV_IS_NOWHERE
# Define CFG_FLASH_BASE PHYS_FLASH_1
/ / Start from 0x10000 to save the system parameters at
# Define CFG_ENV_OFFSET 0x100000
/ / # Define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x20000) / * environment start address * /
# Define CFG_ENV_SECT_SIZE 0x10000 / * Total Size of Environment Sector * /
/ / # Define CFG_MONITOR_BASE PHYS_SDRAM_1
/*------------------------------------------------ -----------------------
* I2C EEPROM (STM24C02W6) for environment
* /
/ / # Define CONFIG_HARD_I2C / * I2c with hardware support * /
/ / # Define CFG_I2C_SPEED 400000 / * I2C speed and slave address * /
/ / # Define CFG_I2C_SLAVE 0xFE
/ /
/ / # Define CFG_I2C_EEPROM_ADDR 0xA8 / * EEPROM STM24C02W6 * /
/ / # Define CFG_I2C_EEPROM_ADDR_LEN 1 / * Bytes of address * /
/ / / * Mask of address bits that overflow into the "EEPROM chip address" * /
///*# Define CFG_I2C_EEPROM_ADDR_OVERFLOW 0x07 * /
/ / # Define CFG_EEPROM_PAGE_WRITE_BITS 4 / * The Catalyst CAT24WC08 has * /
/ * 16 byte page write mode using * /
/ * Last 4 bits of the address * /
/ / # Define CFG_EEPROM_PAGE_WRITE_DELAY_MS 10 / * and takes up to 10 msec * /
/ / # Define CFG_EEPROM_PAGE_WRITE_ENABLE
/ * Flash banks JFFS2 should use * /
/ *
# Define CFG_JFFS2_FIRST_BANK 0
# Define CFG_JFFS2_FIRST_SECTOR 2
# Define CFG_JFFS2_NUM_BANKS 1
* /
/ *

Linux TAGs (see lib_arm / armlinux.c)
* /
# Define CONFIG_CMDLINE_TAG
# Undef CONFIG_SETUP_MEMORY_TAGS
# Define CONFIG_INITRD_TAG
# Endif / * __CONFIG_H * /
At this point, the configuration has been completed, you can make out the image to the!! ☺
make image
6)
make 44B0_config
make CROSS_COMPILE = arm-linux-
(A lot of compiled information drifting away...)
Finally, you can see the u-boot.bin image files. Burned into the flash which can be directly run! ^ _ ^
Fifth, increased network support
Because linux is there are hundreds of moving image k, if every time you use the serial port to transfer too slow. LIYUTAI board using RTL8019,
U-BOOT have driven directly above, as long as you can change it with a! (Ecstasy!!!)
1) Modify drivers/net/rtl8019.h
# Include <asm/types.h>
# Include <config.h>
# Ifdef CONFIG_DRIVER_RTL8019
# Define ETH_ADDR_SFT (8)
# Define EI_SHIFT (x) ((x) <<ETH_ADDR_SFT)
# Define RTL8019_REG_00 (RTL8019_BASE + EI_SHIFT (0x00))
# Define RTL8019_REG_01 (RTL8019_BASE + EI_SHIFT (0x01))
# Define RTL8019_REG_02 (RTL8019_BASE + EI_SHIFT (0x02))
# Define RTL8019_REG_03 (RTL8019_BASE + EI_SHIFT (0x03))
# Define RTL8019_REG_04 (RTL8019_BASE + EI_SHIFT (0x04))
# Define RTL8019_REG_05 (RTL8019_BASE + EI_SHIFT (0x05))
# Define RTL8019_REG_06 (RTL8019_BASE + EI_SHIFT (0x06))
# Define RTL8019_REG_07 (RTL8019_BASE + EI_SHIFT (0x07))
# Define RTL8019_REG_08 (RTL8019_BASE + EI_SHIFT (0x08))
# Define RTL8019_REG_09 (RTL8019_BASE + EI_SHIFT (0x09))
# Define RTL8019_REG_0a (RTL8019_BASE + EI_SHIFT (0x0a))
# Define RTL8019_REG_0b (RTL8019_BASE + EI_SHIFT (0x0b))
# Define RTL8019_REG_0c (RTL8019_BASE + EI_SHIFT (0x0c))
# Define RTL8019_REG_0d (RTL8019_BASE + EI_SHIFT (0x0d))
# Define RTL8019_REG_0e (RTL8019_BASE + EI_SHIFT (0x0e))
# Define RTL8019_REG_0f (RTL8019_BASE + EI_SHIFT (0x0f))
# Define RTL8019_REG_10 (RTL8019_BASE + EI_SHIFT (0x10))

# Define RTL8019_REG_1f (RTL8019_BASE + EI_SHIFT (0x1f))
# Define RTL8019_COMMAND RTL8019_REG_00
# Define RTL8019_PAGESTART RTL8019_REG_01
# Define RTL8019_PAGESTOP RTL8019_REG_02
# Define RTL8019_BOUNDARY RTL8019_REG_03
# Define RTL8019_TRANSMITSTATUS RTL8019_REG_04
# Define RTL8019_TRANSMITPAGE RTL8019_REG_04
# Define RTL8019_TRANSMITBYTECOUNT0RTL8019_REG_05
# Define RTL8019_NCR RTL8019_REG_05
# Define RTL8019_TRANSMITBYTECOUNT1 RTL8019_REG_06
# Define RTL8019_INTERRUPTSTATUS RTL8019_REG_07
# Define RTL8019_CURRENT RTL8019_REG_07
# Define RTL8019_REMOTESTARTADDRESS0 RTL8019_REG_08
# Define RTL8019_CRDMA0 RTL8019_REG_08
# Define RTL8019_REMOTESTARTADDRESS1 RTL8019_REG_09
# Define RTL8019_CRDMA1 RTL8019_REG_09
# Define RTL8019_REMOTEBYTECOUNT0 RTL8019_REG_0a
# Define RTL8019_REMOTEBYTECOUNT1 RTL8019_REG_0b
# Define RTL8019_RECEIVESTATUS RTL8019_REG_0c
# Define RTL8019_RECEIVECONFIGURATION RTL8019_REG_0c
# Define RTL8019_TRANSMITCONFIGURATION RTL8019_REG_0d
# Define RTL8019_FAE_TALLY RTL8019_REG_0d
# Define RTL8019_DATACONFIGURATION RTL8019_REG_0e
# Define RTL8019_CRC_TALLY RTL8019_REG_0e
# Define RTL8019_INTERRUPTMASK RTL8019_REG_0f
# Define RTL8019_MISS_PKT_TALLY RTL8019_REG_0f
# Define RTL8019_PHYSICALADDRESS0 RTL8019_REG_01
# Define RTL8019_PHYSICALADDRESS1 RTL8019_REG_02
# Define RTL8019_PHYSICALADDRESS2 RTL8019_REG_03
# Define RTL8019_PHYSICALADDRESS3 RTL8019_REG_04
# Define RTL8019_PHYSICALADDRESS4 RTL8019_REG_05
# Define RTL8019_PHYSICALADDRESS5 RTL8019_REG_06
# Define RTL8019_MULTIADDRESS0 RTL8019_REG_08
# Define RTL8019_MULTIADDRESS1 RTL8019_REG_09
# Define RTL8019_MULTIADDRESS2 RTL8019_REG_0a
# Define RTL8019_MULTIADDRESS3 RTL8019_REG_0b
# Define RTL8019_MULTIADDRESS4 RTL8019_REG_0c
# Define RTL8019_MULTIADDRESS5 RTL8019_REG_0d
# Define RTL8019_MULTIADDRESS6 RTL8019_REG_0e
# Define RTL8019_MULTIADDRESS7 RTL8019_REG_0f
# Define RTL8019_DMA_DATA RTL8019_REG_10
# Define RTL8019_RESET RTL8019_REG_1f
# Define RTL8019_PAGE0 0x22

# Define RTL8019_PAGE1 0x62
# Define RTL8019_PAGE0DMAWRITE 0x12
# Define RTL8019_PAGE2DMAWRITE 0x92
# Define RTL8019_REMOTEDMAWR 0x12
# Define RTL8019_REMOTEDMARD 0x0A
# Define RTL8019_ABORTDMAWR 0x32
# Define RTL8019_ABORTDMARD 0x2A
# Define RTL8019_PAGE0STOP 0x21
# Define RTL8019_PAGE1STOP 0x61
# Define RTL8019_TRANSMIT 0x26
# Define RTL8019_TXINPROGRESS 0x04
# Define RTL8019_SEND 0x1A
# Define RTL8019_PSTART 0x4c
# Define RTL8019_PSTOP 0x80
# Define RTL8019_TPSTART 0x40
# Endif / * end of CONFIG_DRIVER_RTL8019 * /
Modify drivers/net/rtl8019.c
2)
When debugging the network has been unreasonable, and later found out after debugging is rtl8019.c a problem. There do not know why put_reg function
volatile and get_reg not, the question arises here. Add to, OK!
static unsigned char get_reg (unsigned int regno)
{
return (* (volatile unsigned char *) regno);
}
VI debugging U-BOOT
In order to debug U-BOOT, I really detail the way, try a good variety of methods can not be source-level debugging. Was found with RVDK
You can debug the window below, as follows: (skyeye later found out that you can use to debug, even on the board can not! Thank you
skyeye of doing such a good platform for us to provide)
Modify arm_config.mk file, add-gdwarf options
# PLATFORM_CPPFLAGS + =-DCONFIG_ARM-D__ARM__
# Debug
PLATFORM_CPPFLAGS + =-DCONFIG_ARM-D__ARM__-gdwarf-2
Then the above can be carried out in RVDK source-level debugging. It was great ~ ~ ~
VII Postscript
In the Portable Document to thank samfei
(Http://www.linuxforum.net/forum/showflat.php?Cat=&Board=embedded&Number=566316&page=&view=&sb=&o
= & Vc = 1), according to basically be able to complete u-boot-1.1.6. I ported it to 1.3.2, hope to help novice.
Thứ Năm, 30 tháng 6, 2011 04:55 Đọc tiếp >>

Control Flow in U-boot

Thứ Tư, 29 tháng 6, 2011 / 22:52

u-boot startup process

system startup entry point. Since we now have to analyze the process of u-boot startup, you must first find the u-boot, which code the first realization, the first completed what tasks. On the other hand an executable image must have an entry point, and only a global entry point, so to inform the compiler where the entrance. From this we can find the entry point is in / board/lpc2210/u-boot.lds specified, which ENTRY (_start) _start start running from that program, and he points to the cpu/arm7tdmi/start.o file. Because we are using the cpu ARM7TDMI architecture, from the address 0x00000000 after reset to take its first instruction, so we will Flash map to this address, so that the system is powered up, cpu will be the first implementation of u-boot process.

u-boot startup process is multi-stage implementation, divided in two stages. Architecture depends on the cpu code (such as device initialization code, etc.) are usually placed in stage1, but also usually implemented in assembly language in order to achieve the purpose of short and pithy. The stage2 is usually implemented with C language, so that complex functions can be achieved, and the code has better readability and portability.

following detailed analysis of our first under the stage1 code shown in Figure 2:





Figure 2 Start.s program flow

code really started in _start, set the exception vector table, so that when an exception occurs in the cpu to jump to / cpu/arm7tdmi / interrupts in the code to execute the appropriate service routine. Most of the document in the interrupts are not implemented exception code specific functions, but only print some exception message, which is the key to reset the interrupt code, skip to the reset entry address.

reset reset before the entrance of some segments of the statement. In the reset, the first is the cpu is set to svc32 mode, and block all irq and fiq. In addition to the u-boot using the timer interrupt, the other is basically no need to use interrupts, such as serial communications and network communications, as long as the u-boot to complete some simple communication can be, so here mask out all interrupts.

initialize the external bus. This part of the first set of I / O port features, including serial, network interface settings, and other I / O port is set to GPIO. Then set BCFG0 ~ BCFG3, the external bus controller. Here bank0 corresponding Flash, set to 16-bit width, the slowest bus speed is set to achieve stable operation; Bank1 corresponding DRAM, the same settings and Flash; Bank2 corresponding RTL8019.

Next is the key to set the cpu, including system re-mapping (to tell the processor when the interrupt occurs in the system to the external memory to read the interrupt vector table) and the system frequency.

lowlevel_init, set the RAM timing, and interrupt controller cleared. The relevant part of the platform-specific, but generally the process is the same.

Here is the code of the move phase. In order to obtain faster execution, usually stage2 is loaded into RAM space to run, it is necessary to load the stage2 ready for Boot Loader section of the scope of available RAM space. Space is best memory page size (usually 4KB) multiple of, in general, 1M of RAM space is enough. stored in flash u-boot executable file, the code segment, data segment, and BSS segments are stored end to end, so when calculating the size of the move is to use the first address with the BSS segment minus the first address code, This is actually calculated using the space. Program uses a loop to move the code 0x81180000, that is the bottom 1M RAM space used to store code. And the program continues to move to RAM interrupt vector table top. Stage2 is usually the C language implementation of the code, therefore I have to build the stack. Even before the stack area allocated to malloc space and the space required for global data space down, and their size is given by the macro definition can be modified in the appropriate location. Basic memory map:




Figure 3, the distribution of moving, memory map

Next is the u-boot start of the second phase, is written in c code, which is of relatively little change in some part of the board that we change it for different number of initialization function call, and by setting Some macro to change the initialization process, so the code in the process of transplantation does not need to modify is the file the error appears relatively small. In the beginning of the file first defines a function pointer array, the array, the program through a loop initialization routine in order, and thereafter through a number of macros to initialize a specific device. In the final program enters a loop, main_loop. This loop receives user input commands to set the parameters or the boot.

of this article will focus on the front of the start.s on, because this part of both the transplant or in the debugging process is the most error-prone places on the need for procedures to solve the problem staff to modify the code, so heres a brief introduction about the basic process start.s, hoping to help.
Thứ Tư, 29 tháng 6, 2011 22:52 Đọc tiếp >>

Bootloader Description

Bootloader for embedded development is bound to touch a concept, it is embedded College two courses in the embedded linux system in the development of important content. This article mainly explains the basic concepts and CY7C1329-100AC datasheet and internal Bootloader principle, this part of the master development will be embedded linux system was extremely helpful!

Bootloader definition: Bootloader is executed before the operating system is running a short program, through this short process, we can initialize the hardware devices, the establishment of a mapping table memory space in order to establish appropriate systems hardware and CY7C1329-100AC price and software environment, called the operating system kernel for the final preparation. Meaning that if we want an operating system up and CY7C1329-100AC suppliers and running on our board, we must first of all on board some of our basic configuration and initialization before it can come in to run the operating system boot. Bootloader specific in what actions to complete the analysis we will be back to where we first recall the architecture of PC: PC, boot loader in the BIOS and the hard disk from MBR in OS Boot Loader (such as LILO and GRUB, etc.) with the composition, BIOS hardware detection and the completion of the allocation of resources, will be hard to read MBR Boot Loader in the system RAM, then transfer control to the OS Boot Loader. Boot Loaders main task is to run the kernel image will be read from the RAM disk, and then jump to kernel entry point to run, which started operating system. In embedded systems, often as not, as the firmware BIOS (Note: some embedded embedded cpu will start a short program), so start the task of loading the whole system is completely done by the Boot Loader. For example, in an embedded ARM7TDMI core-based systems, the system is powered on or reset is usually started from the address at 0x00000000, and in this address is usually arranged at the system Boot Loader program. (First think about, general PC and embedded system why there is such a difference here then?)

Bootloader is based on the specific hardware platform to achieve, therefore virtually impossible for all of the embedded system the establishment of a common Bootloader, different processor architectures have different Bootloader, Bootloader not only dependent on the cpu architecture, but also on board-level embedded system device configuration. For two different board, even if they use the same processor, to get on the board running in a Bootloader program can be run on another piece of board, generally need to modify the source code Bootloader.

Bootloader boot methods

Bootloader boot methods are network boot mode Flash boot disk boot mode and manner.

1, the network boot method





Figure 1 Bootloader Network Starting method diagram

shown in Figure 1, which the host and target board, among them over a network connection, the first target of the DHCP / BIOS Bootloader through the BOOTP service to assign IP addresses, configure the network parameters, in order to support the network transmission function. We use the u-boot can set network parameters, so there would not have a way to use DHCP dynamic allocation of IP was. Bootloader next target board kernel image via TFTP service to download to the target board and then through the network file system to create the host and target communication process between the documents, after the system update usually use this mode of Boot Loader . Work in this mode of Boot Loader to its end users usually provide a simple command line interface.

2, disk boot method

this approach is mainly used in desktop computers and servers, these computers are using the BIOS boot, and use the disk as a storage medium, there is Two important are used to start the linux LILO and GRUB, not specifically described here.

3, flash boot mode

This is the most common way. Flash NOR Flash and NAND Flash has two. NOR Flash can support random access, so the code can run directly in Flash, Bootloader is generally stored in the Flash chip. Flash also has stores on the parameters, the kernel image and file system. This starts with the network boot mode difference between the way is that, in the network boot mode, kernel image and file system on the host first, and then transmitted through the network to download into the target board, which started in the way the kernel image and file system is placed directly in Flash, these two points we use u-boot is used a process.
Thứ Tư, 29 tháng 6, 2011 22:50 Đọc tiếp >>

Control Flow in U-boot (Bootloader)

Bootloader Description
Bootloader for embedded development is bound to touch a concept, it is embedded College two courses in the embedded linux system in the development of important content. This article mainly explains the basic concepts and CY7C1329-100AC datasheet and internal Bootloader principle, this part of the master development will be embedded linux system was extremely helpful!

Bootloader definition: Bootloader is executed before the operating system is running a short program, through this short process, we can initialize the hardware devices, the establishment of a mapping table memory space in order to establish appropriate systems hardware and CY7C1329-100AC price and software environment, called the operating system kernel for the final preparation. Meaning that if we want an operating system up and CY7C1329-100AC suppliers and running on our board, we must first of all on board some of our basic configuration and initialization before it can come in to run the operating system boot. Bootloader specific in what actions to complete the analysis we will be back to where we first recall the architecture of PC: PC, boot loader in the BIOS and the hard disk from MBR in OS Boot Loader (such as LILO and GRUB, etc.) with the composition, BIOS hardware detection and the completion of the allocation of resources, will be hard to read MBR Boot Loader in the system RAM, then transfer control to the OS Boot Loader. Boot Loaders main task is to run the kernel image will be read from the RAM disk, and then jump to kernel entry point to run, which started operating system. In embedded systems, often as not, as the firmware BIOS (Note: some embedded embedded cpu will start a short program), so start the task of loading the whole system is completely done by the Boot Loader. For example, in an embedded ARM7TDMI core-based systems, the system is powered on or reset is usually started from the address at 0x00000000, and in this address is usually arranged at the system Boot Loader program. (First think about, general PC and embedded system why there is such a difference here then?)

Bootloader is based on the specific hardware platform to achieve, therefore virtually impossible for all of the embedded system the establishment of a common Bootloader, different processor architectures have different Bootloader, Bootloader not only dependent on the cpu architecture, but also on board-level embedded system device configuration. For two different board, even if they use the same processor, to get on the board running in a Bootloader program can be run on another piece of board, generally need to modify the source code Bootloader.

Bootloader boot methods

Bootloader boot methods are network boot mode Flash boot disk boot mode and manner.

1, the network boot method





Figure 1 Bootloader Network Starting method diagram

shown in Figure 1, which the host and target board, among them over a network connection, the first target of the DHCP / BIOS Bootloader through the BOOTP service to assign IP addresses, configure the network parameters, in order to support the network transmission function. We use the u-boot can set network parameters, so there would not have a way to use DHCP dynamic allocation of IP was. Bootloader next target board kernel image via TFTP service to download to the target board and then through the network file system to create the host and target communication process between the documents, after the system update usually use this mode of Boot Loader . Work in this mode of Boot Loader to its end users usually provide a simple command line interface.

2, disk boot method

this approach is mainly used in desktop computers and servers, these computers are using the BIOS boot, and use the disk as a storage medium, there is Two important are used to start the linux LILO and GRUB, not specifically described here.

3, flash boot mode

This is the most common way. Flash NOR Flash and NAND Flash has two. NOR Flash can support random access, so the code can run directly in Flash, Bootloader is generally stored in the Flash chip. Flash also has stores on the parameters, the kernel image and file system. This starts with the network boot mode difference between the way is that, in the network boot mode, kernel image and file system on the host first, and then transmitted through the network to download into the target board, which started in the way the kernel image and file system is placed directly in Flash, these two points we use u-boot is used a process.

U-boot definition

U-boot, full name of the Universal Boot Loader, the development team by DENX terms of compliance with GPL open source project, its main function is to complete the hardware device initialization, the operating system code handling, and provide a console and a set of instructions before running the operating system control hardware devices. The reason why such a universal U-boot, because he has a lot of features: open source, support for multiple embedded operating system kernel, supports multiple processors, high stability, a highly flexible feature set, rich devices driver source code and more extensive development and debug documents and a strong network of technical support. Also u-boot operating system and product development provides a rich and flexible support, mainly in: you can boot the kernel compressed or uncompressed, can be flexibly set / pass multiple key parameters to the operating system, for systems in different stages of development commissioning requirements and product releases, support for multiple file system, support for multiple target environment parameters storage medium, the use of CRC32 verification, you can check the kernel and the image file is intact, offers a variety of console interface, so users can not the case of ICE through the serial port / Ethernet / USB interface to download data such as storage devices and burn to go (this feature in the actual product is very useful, especially in the software field upgrades of the time), and provide a rich The device drivers and so on.

u-boot source code directory structure

1, board development board stored in the configuration files related to each development board are in the form of sub-folders.

2, Commom folder implementation to support u-boot command line, each command corresponds to a file.

3, cpu stored in the relevant directory structure of a specific cpu, cpu structure of each section corresponds to a subdirectory.

4, Doc is a document directory, there u-boot is very well documented.

5, Drivers is u-boot support for a variety of device drivers.

6, Fs is a supported file system, the most commonly used is the JFFS2 file system.

7, Include folder is the u-boot using the header files, and various hardware platforms to support the compilation of files, system configuration files and file system support files.

8, Net is the code associated with the network protocol, bootp protocol, TFTP protocol, NFS file system was achieved.

9, Tooles is to generate a U-boot tool.

on the u-boot directory has some understanding, the process of boot code to be much more convenient, the more important directory is / board, / cpu, / drivers, and / include directories, if you want to to achieve u-boot on a platform migration, it is necessary depth of analysis of these directories.

u-boot startup process

system startup entry point. Since we now have to analyze the process of u-boot startup, you must first find the u-boot, which code the first realization, the first completed what tasks. On the other hand an executable image must have an entry point, and only a global entry point, so to inform the compiler where the entrance. From this we can find the entry point is in / board/lpc2210/u-boot.lds specified, which ENTRY (_start) _start start running from that program, and he points to the cpu/arm7tdmi/start.o file. Because we are using the cpu ARM7TDMI architecture, from the address 0x00000000 after reset to take its first instruction, so we will Flash map to this address, so that the system is powered up, cpu will be the first implementation of u-boot process.

u-boot startup process is multi-stage implementation, divided in two stages. Architecture depends on the cpu code (such as device initialization code, etc.) are usually placed in stage1, but also usually implemented in assembly language in order to achieve the purpose of short and pithy. The stage2 is usually implemented with C language, so that complex functions can be achieved, and the code has better readability and portability.

following detailed analysis of our first under the stage1 code shown in Figure 2:





Figure 2 Start.s program flow

code really started in _start, set the exception vector table, so that when an exception occurs in the cpu to jump to / cpu/arm7tdmi / interrupts in the code to execute the appropriate service routine. Most of the document in the interrupts are not implemented exception code specific functions, but only print some exception message, which is the key to reset the interrupt code, skip to the reset entry address.

reset reset before the entrance of some segments of the statement. In the reset, the first is the cpu is set to svc32 mode, and block all irq and fiq. In addition to the u-boot using the timer interrupt, the other is basically no need to use interrupts, such as serial communications and network communications, as long as the u-boot to complete some simple communication can be, so here mask out all interrupts.

initialize the external bus. This part of the first set of I / O port features, including serial, network interface settings, and other I / O port is set to GPIO. Then set BCFG0 ~ BCFG3, the external bus controller. Here bank0 corresponding Flash, set to 16-bit width, the slowest bus speed is set to achieve stable operation; Bank1 corresponding DRAM, the same settings and Flash; Bank2 corresponding RTL8019.

Next is the key to set the cpu, including system re-mapping (to tell the processor when the interrupt occurs in the system to the external memory to read the interrupt vector table) and the system frequency.

lowlevel_init, set the RAM timing, and interrupt controller cleared. The relevant part of the platform-specific, but generally the process is the same.

Here is the code of the move phase. In order to obtain faster execution, usually stage2 is loaded into RAM space to run, it is necessary to load the stage2 ready for Boot Loader section of the scope of available RAM space. Space is best memory page size (usually 4KB) multiple of, in general, 1M of RAM space is enough. stored in flash u-boot executable file, the code segment, data segment, and BSS segments are stored end to end, so when calculating the size of the move is to use the first address with the BSS segment minus the first address code, This is actually calculated using the space. Program uses a loop to move the code 0x81180000, that is the bottom 1M RAM space used to store code. And the program continues to move to RAM interrupt vector table top. Stage2 is usually the C language implementation of the code, therefore I have to build the stack. Even before the stack area allocated to malloc space and the space required for global data space down, and their size is given by the macro definition can be modified in the appropriate location. Basic memory map:




Figure 3, the distribution of moving, memory map

Next is the u-boot start of the second phase, is written in c code, which is of relatively little change in some part of the board that we change it for different number of initialization function call, and by setting Some macro to change the initialization process, so the code in the process of transplantation does not need to modify is the file the error appears relatively small. In the beginning of the file first defines a function pointer array, the array, the program through a loop initialization routine in order, and thereafter through a number of macros to initialize a specific device. In the final program enters a loop, main_loop. This loop receives user input commands to set the parameters or the boot.

of this article will focus on the front of the start.s on, because this part of both the transplant or in the debugging process is the most error-prone places on the need for procedures to solve the problem staff to modify the code, so heres a brief introduction about the basic process start.s, hoping to help.
Thứ Tư, 29 tháng 6, 2011 22:32 Đọc tiếp >>

BeagleBoardRecovery

Thứ Hai, 27 tháng 6, 2011 / 02:17

This page is how to recover ("unbrick") a broken BeagleBoard. It should help you if you messed your boot configuration and BeagleBoard doesn't boot any more the normal way ("bricked").
Symptoms

Normally, if you boot from MMC, you will get something like
...40T...

in terminal program connected to UART (115200 8N1). This is output from OMAP3's bootrom while scanning the UART for boot source before trying to boot from MMC card. If you don't get this, but want to boot from MMC, most probably bootrom doesn't reach the MMC boot stage any more. If you played with NAND before getting this, most probably NAND contains some broken content.
What has happened?

Depending on user button OMAP3 on BeagleBoard uses different boot order. Normal order if user button isn't pressed at power up is boot from

NAND -> USB -> UART -> MMC

in this order. Depending on the boot medium (e.g. MMC) this might fail if something bad is in NAND flash which confuses OMAP3 bootrom thus stopping it to reach MMC boot stage.

This might happen if you e.g. mess your NAND, e.g. something went wrong with NAND boot.
What to do now?

First, we have to press user button at power up to switch boot order to

USB -> UART -> MMC -> NAND

to have option to boot from other sources than broken NAND (which is first if user button is not pressed).

Then, there are three options to boot from:
MMC
USB
UART

Below, MMC and USB recovery will be done in detail. The goal is to get a U-Boot prompt and then to erase the non-booting NAND.
MMC recovery

The procedure to put your board into the "factory fresh state" used on all boards being made now is at http://code.google.com/p/beagleboard/wiki/BeagleboardRevCValidation. The original recovery method is described below.

MMC recovery should be straight forward. Press user button at power up and according to above boot order MMC boot is before NAND. With this, we should be able to boot as we did without pressing the user button before bricking the board. But:

There are some broken MLO (x-loader) out there which fail to boot if something wrong is in NAND. E.g.:
...40T.........

Texas Instruments X-Loader 1.41
Starting on with MMC
Reading boot sector

150832 Bytes Read from MMC
Starting OS Bootloader from MMC...

U-Boot 1.3.3 (Jun 20 2008 - 17:06:22)

OMAP3530-GP rev 2, CPU-OPP2 L3-165MHz
OMAP3 Beagle Board + LPDDR/NAND
RAM Configuration:
Bank #0: 80000000 128 MB
Bank #1: 88000000 0 kB
NAND: NAND device: Manufacturer ID: 0x2c, Chip ID: 0x01 ( AND 128MiB 3,3V 8-bit)
NAND bus width 16 instead 8 bit
0 MiB
<hang, no prompt>

This seems to happen with both MLO's from Beagle source code page (381MHz and 500MHz one) independent of U-Boot version.

Thus, you have to use a special (?) MLO for recovery to get a U-Boot prompt. Replacing MLO used above on MMC/SD card with this recovery MLO we get a U-Boot prompt while pressing the user button at power up:
...40T.........

Texas Instruments X-Loader 1.41
Starting on with MMC
Reading boot sector

150832 Bytes Read from MMC
Starting OS Bootloader from MMC...

U-Boot 1.3.3 (Jun 20 2008 - 17:06:22)

OMAP3530-GP rev 2, CPU-OPP2 L3-165MHz
OMAP3 Beagle Board + LPDDR/NAND
RAM Configuration:
Bank #0: 80000000 128 MB
Bank #1: 88000000 0 kB
NAND: 256 MiB
In: serial
Out: serial
Err: serial
Hit any key to stop autoboot: 0
OMAP3 beagleboard.org #

U-Boot version doesn't seem to matter. Then you can erase NAND start:
OMAP3 beagleboard.org # nand unlock
device 0 whole chip
nand_unlock: start: 00000000, length: 268435456!
NAND flash successfully unlocked
OMAP3 beagleboard.org # nand erase 0 80000

NAND erase: device 0 offset 0x0, size 0x80000
Erasing at 0x60000 -- 100% complete.
OK
OMAP3 beagleboard.org #

If you now re-power your board without pressing the user button it should work as before. Happily unbricked!

Next, you can also restore the NAND flash by preparing an SDCard image that automatically flashes all software components correctly.
MMC recovery Troubleshooting

Some have encountered problems with trying to boot from MMC, but it wasn't booting from MMC because of a bad formating and/or copy of the MLO. This example demonstrates booting from NAND even if the user button (40T) has been pressed.
...40T...

Texas Instruments X-Loader 1.41
Starting OS Bootloader...

Instead, the correct and expected result with user button pressed is booting from MMC and this should be printed:
...40T...

Texas Instruments X-Loader 1.41
Starting on with MMC
Reading boot sector

150832 Bytes Read from MMC
Starting OS Bootloader from MMC...

If MMC is not displayed, this means that the MLO (x-loader for the MMC) has not been properly copied or the partition has not been done properly. Or simply that there is something wrong with what is on the MMC.

The first thing to do is to follow step by step the Linux Boot Disk Format Procedure then after formating the FIRST STEP TO DO AFTER FORMATING IS TO COPY MLO. Which one? MLO_restore from Downloads list the one previously discuss in MCC recovery section.

For u-boot we suggest to use u-boot.bin_autoflash from Downloads list.

Summary:

1- Partition MMC // Last cylinder or +size or +sizeM or +sizeK (1-245, default 245): [+50] ENTER 51 not 50!

2- Format MMC //

3- Copy MLO // Change MLO_restore name for MLO

4- Copy u-boot.bin // Change u-boot.bin_autoflash for u-boot.bin

5- Insert SD into beagleboard hold user button and plug the power you should boot from MMC.

NOTE:The difference between the MLO and x-load.bin.ift is that the first is used for the MMC and the other one for NAND boot.

Reference: Problem discuss
USB recovery

You can use USB boot utility together with U-Boot V2 and then use U-Boot V2's loadb to load U-Boot (V1). Binary: U-boot V2

Note: USB download can only load programs into OMAP3's internal SRAM. This is 64k, so too small for U-Boot (V1). But unfortunately, U-Boot V2 currently lacks NAND support. So we have to use:

USB download -> U-Boot V2 (SRAM) loadb -> U-Boot (V1) (SDRAM) NAND erase

For this, get usbload and U-Boot V2 using above links, start usbload tool at PC and while ... plug in USB OTG (power) cable. At host, this will result in:
> ./omap3_usbload uboot_v2.bin

TI OMAP3 USB boot ROM tool, version 0.1
(c) 2008 Martin Mueller <martinmm@pfump.org>

..........................................

found device!
download ok
>

And at target you will get:
U-Boot 2.0.0-rc5-git (Jun 30 2008 - 20:16:02)

Board: Texas Instrument's SDP343x
Malloc Space: 0x87bfff10 -> 0x87ffff10 (size 4 MB)
running /env/bin/init...
not found
X-load 343x>

Now, you can use this running U-Boot V2 to download U-Boot (V1) using loadb command:
X-load 343x> devinfo
devices:
|----uart3
|----ram0
|----filesystem: /
|----filesystem: /dev

drivers:
serial_ns16550
ramfs
devfs
ram
X-load 343x> help loadb
[OPTIONS]
-d device - which device to download - defaults to /dev/mem
-o offset - what offset to download - defaults to 0
-b baud - baudrate at which to download - defaults to console baudrate

X-load 343x> loadb -d /dev/ram0
## Ready for binary (kermit) download to 0x00000000 offset on /dev/ram0 device at 115200 bps...

Now, send U-Boot (V1) binary (i.e. u-boot.bin) using kermit download of you terminal program. When this is finished:
## Total Size = 0x00023d64 = 146788 Bytes

X-load 343x> help go
addr [arg ...]
- start application at address 'addr'
passing 'arg' as arguments

X-load 343x> go 0x80000000
## Starting application at 0x80000000 ...

U-Boot 1.3.3 (Jul 6 2008 - 10:33:59)

OMAP3530-GP rev 2, CPU-OPP2 L3-165MHz
OMAP3 Beagle Board + LPDDR/NAND
RAM Configuration:
Bank #0: 80000000 128 MB
Bank #1: 88000000 0 kB
NAND: 256 MiB
In: serial
Out: serial
Err: serial
OMAP3 beagleboard.org #

Now, you have your U-Boot (V1) prompt. This can be used now to erase (broken) parts in NAND:
OMAP3 beagleboard.org # nand unlock
device 0 whole chip
nand_unlock: start: 00000000, length: 268435456!
NAND flash successfully unlocked
OMAP3 beagleboard.org # nand erase 0 80000

NAND erase: device 0 offset 0x0, size 0x80000
Erasing at 0x60000 -- 100% complete.
OK
OMAP3 beagleboard.org #

If you now re-power your board without pressing the user board it should work as before. Happily unbricked!
UART recovery

Note: you can download a tarball with all the tools needed here.

1 - Generate an x-loader with serial support
mkdir serial_boot
cd serial_boot
git clone http://git.omapzoom.org/repo/u-boot.git
git clone http://git.omapzoom.org/repo/x-loader.git
cd x-loader
make distclean
make omap3430labradordownload_config
make
cd ..

now you've got an ~13k x-load.bin in the x-loader directory.

2 - Generate Nishant Menon's tools
git clone http://github.com/nmenon/omap-u-boot-utils.git
cd omap-u-boot-utils
make distclean
make

now you've got two tools: pserial and ukermit

3 - Pick up the U-Boot you'd like to put in SDRAM

You can either use the one generated by OE, or you can quickly generate a new one:
cd ..
git clone http://git.denx.de/u-boot.git u-boot-denx
cd u-boot-denx
make distclean
make omap3_beagle_config
make
cd ..

now you've got an ~160k u-boot.bin in the u-boot-denx directory.

4 - Prepare the boot
cd omap-u-boot-utils
cp ../x-loader/x-load.bin .
cp ../u-boot-denx/u-boot.bin .

5 - Boot (use the right tty for your setup of course)

Power off the board.

Run pserial to put the x-loader in the internal SRAM:
./pserial -p /dev/ttyS0 -f x-load.bin

If you already have an x-loader in NAND, you must push the User Button so that the NAND boot is tried after the UART boot, then power-on the board.

If you don't have one, simply power-on the board.

You see:
Waiting For Device ASIC ID: Press Ctrl+C to stop
ASIC ID Detected.
Sending 2ndFile:
Downloading file: 100.000% completed(12700/12700 bytes)
File download completed.

Then run ukermit, to transmit the u-boot to the x-loader and then the x-loader puts it in SDRAM:
./ukermit -p /dev/ttyS0 -f u-boot.bin

You see:
Downloading file: 100.000% completed(162656/162656 bytes)
File Download completed

And then you have an U-Boot prompt like this:
## Start Addr = 0x80008000
Starting OS Bootloader from UART ...

U-Boot 2009.03-rc2-00013-gefb4734 (C3A4r 18 2009 - 10:55:33)

OMAP3530-GP rev 2, CPU-OPP2 L3-165MHz
OMAP3 Beagle board + LPDDR/NAND
DRAM: 128 MB
NAND: 256 MiB
In: serial
Out: serial
Err: serial
Board revision Ax/Bx
Die ID #047a00030000000004013f780601000c
Hit any key to stop autoboot: 0
Thứ Hai, 27 tháng 6, 2011 02:17 Đọc tiếp >>

2010 ICASSP Lab 2 The Boot Sequence


Connecting to the Beagle's serial port

If your Beagle is still running do this to shut it down.
Start HyperTerminal Go to Start:Accessories:Communications:HyperTerminal and create a new connection. Call it Beagle.
Select USB if you are using the USB to serial port adapter, or select COM1 if you are directly connected to the serial port
Select the settings shown

Alternative Serial Program: Putty Newer versions of windows lack HyperTerminal, or if you prefer to use something other then HyperTerminal, putty's serial support works quite well. It can be downloaded here
Upon starting putty select the Serial bubble on the Session tab under Connection type, next set the Speed to 115200. Optionally you can save the session to prevent the need for reconfiguration of future starts of putty.
Simply click open and you should be connected to your beagle.


With either method, you should be able to hit enter and see
.-------.
| | .-.
| | |-----.-----.-----.| | .----..-----.-----.
| | | __ | ---'| '--.| .-'| | |
| | | | | |--- || --'| | | ' | | | |
'---'---'--'--'--. |-----''----''--' '-----'-'-'-'
-' |
'---'

The Angstrom Distribution beagleboard ttyS2

Angstrom 2009.X-stable beagleboard ttyS2

beagleboard login: root
root@beagleboard:~#

Login as root.
Shutting Down and Rebooting on U-Boot
root@beagleboard:~# shutdown -r now

As your Beagle reboots you will see:
Texas Instruments X-Loader 1.4.2 (Feb 19 2009 - 12:01:24)
Reading boot sector
Loading u-boot.bin from mmc

Which is then followed by
U-Boot 2009.11-rc1 (Jan 08 2010 - 21:19:52)

OMAP3530-GP ES3.1, CPU-OPP2 L3-165MHz
OMAP3 Beagle board + LPDDR/NAND
I2C: ready
DRAM: 256 MB
NAND: 256 MiB
In: serial
Out: serial
Err: serial
Board revision C4
Die ID #5444000400000000040365fa1400e007
Hit any key to stop autoboot: 0
OMAP3 beagleboard.org #

Hit a key before it goes on to boot Linux. What has happened so far is:
When power is first applied the Beagle jumps to a boot loader in the OMAPs ROM.
This bootloader finds the SD card run runs a file called MLO.
MLO is X-Loader with a couple things added. The first bit of output above is from X-Loader.
X-Loader looks and finds u-boot.bin and starts running it.

Das U-Boot is universal boot loader that is used on many embedded systems. You can find more information at http://www.denx.de/wiki/U-Boot. You can list the commands it understands: OMAP3 beagleboard.org # help
? - alias for 'help'
base - print or set address offset
bdinfo - print Board Info structure
boot - boot default, i.e., run 'bootcmd'
bootd - boot default, i.e., run 'bootcmd'
bootm - boot application image from memory
chpart - change active partition
cmp - memory compare
coninfo - print console devices and information
cp - memory copy
crc32 - checksum calculation
echo - echo args to console
editenv - edit environment variable
exit - exit script
ext2load- load binary file from a Ext2 filesystem
ext2ls - list files in a directory (default /)
false - do nothing, unsuccessfully
fatinfo - print information about filesystem
fatload - load binary file from a dos filesystem
fatls - list files in a directory (default /)
fsinfo - print information about filesystems
fsload - load binary file from a filesystem image
go - start application at address 'addr'
help - print command description/usage
i2c - I2C sub-system
imxtract- extract a part of a multi-image
itest - return true/false on integer compare loadb - load binary file over serial line (kermit mode)
loads - load S-Record file over serial line
loady - load binary file over serial line (ymodem mode)
loop - infinite loop on address range
ls - list files in a directory (default /)
md - memory display
mm - memory modify (auto-incrementing address)
mmc - MMC sub-system
mtdparts- define flash/nand partitions
mtest - simple RAM read/write test
mw - memory write (fill)
nand - NAND sub-system
nandecc - nandecc - switch OMAP3 NAND ECC calculation algorithm

nboot - boot from NAND device
nm - memory modify (constant address)
printenv- print environment variables
reset - Perform RESET of the CPU
run - run commands in an environment variable
saveenv - save environment variables to persistent storage
setenv - set environment variables
showvar - print local hushshell variables
sleep - delay execution for some time
source - run script from memory
test - minimal test like /bin/sh
true - do nothing, successfully
version - print monitor version


U-Boot source code is available is highly configurable, therefore the command list can be expanded or reduced to fit your application. Try:
OMAP3 beagleboard.org # bdi
arch_number = 0x0000060A
env_t = 0x00000000
boot_params = 0x80000100
DRAM bank = 0x00000000
-> start = 0x80000000
-> size = 0x08000000
DRAM bank = 0x00000001
-> start = 0x88000000
-> size = 0x08000000
baudrate = 115200 bps

This gives you some information about the board. It appears we have some RAM starting at 0x8000 0000.
Booting Linux

Here's what happens when you boot Linux:
OMAP3 beagleboard.org # print bootcmd
bootcmd=mmc init;fatload mmc 0 80300000 uImage;bootm 80300000
OMAP3 beagleboard.org # print bootargs
bootargs=console=ttyS2,115200n8 console=tty0 root=/dev/mmcblk0p2 rw rootfstype=t

Enter boot and Linux will start:
OMAP3 beagleboard.org # boot
mmc1 is available
reading uImage

2996196 bytes read
## Booting kernel from Legacy Image at 80300000 ...
Image Name: Angstrom/2.6.29/beagleboard
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 2996132 Bytes = 2.9 MB
Load Address: 80008000
Entry Point: 80008000
Verifying Checksum ... OK
Loading Kernel Image ... OK
OK

Starting kernel ...

Uncompressing Linux.............................................................
[ 0.000000] Linux version 2.6.29-omap1 (koen@dominion) (gcc version 4.3.3 (G9
[ 0.000000] CPU: ARMv7 Processor [411fc083] revision 3 (ARMv7), cr=10c5387f

...
[94371.964385] eth0: link up, 100Mbps, full-duplex, lpa 0xC5E1
[94372.195861] eth0: link up, 100Mbps, full-duplex, lpa 0xC5E1

.-------.
| | .-.
| | |-----.-----.-----.| | .----..-----.-----.
| | | __ | ---'| '--.| .-'| | |
| | | | | |--- || --'| | | ' | | | |
'---'---'--'--'--. |-----''----''--' '-----'-'-'-'
-' |
'---'

The Angstrom Distribution beagleboard ttyS2

Angstrom 2009.X-stable beagleboard ttyS2

beagleboard login:
Thứ Hai, 27 tháng 6, 2011 02:16 Đọc tiếp >>

Booting Beagle Software


Beagle Board can boot from NAND, MMC, UART, and USB. At present we support only NAND and MMC booting. The compilation steps for software components and pre-built images are described at Beagle Software Compilation Procedure
Booting u-boot on Beagle Board

The u-boot booting on NAND and MMC need another software component called x-loader. The booting procedure for x-loader as such doesn't need any detailed explanation, so this section includes x-loader booting as well.

Booting u-boot on NAND Flash
Assumption: All Beagle "Rev B" Boards come with pre-loaded u-boot on NAND flash
Do the Hardware Setup for booting u-boot over NAND Flash.
On "Powering ON" the board, u-boot 1.3.3 should boot by displaying a splash screen on DVI and playing a tone on audio out, the u-boot console should be shown as below

Texas Instruments X-Loader 1.41
Starting OS Bootloader...


U-Boot 1.3.3 (Jul 8 2008 - 16:29:02)

OMAP3530-GP rev 2, CPU-OPP2 L3-165MHz
OMAP3 Beagle Board + LPDDR/NAND
DRAM: 128 MB
NAND: 256 MiB
*** Warning - bad CRC or NAND, using default environment

In: serial
Out: serial
Err: serial
Audio Tone on Speakers ... complete
Hit any key to stop autoboot: 0
OMAP3 beagleboard.org #

NOTE: If u-boot is not Flashed on the NAND, then refer to Beagle NAND Flash Procedure to do the same

Booting u-boot with MMC/SD Card
Do the Hardware Setup for booting u-boot over MMC/SD Card.
On "Powering ON" the board, u-boot 1.3.3 should boot by displaying a splash screen on DVI and playing a tone on audio out, the u-boot console should be shown as below

Texas Instruments X-Loader 1.41
Starting on with MMC
Reading boot sector

717372 Bytes Read from MMC
Starting OS Bootloader from MMC...


U-Boot 1.3.3 (Jul 8 2008 - 19:29:48)

OMAP3530-GP rev 2, CPU-OPP2 L3-165MHz
OMAP3 Beagle Board + LPDDR/NAND
DRAM: 128 MB
NAND: 256 MiB
In: serial
Out: serial
Err: serial
Audio Tone on Speakers ... complete
Hit any key to stop autoboot: 0
OMAP3 beagleboard.org #

Boot the Linux Image on Beagle Board

Once you have u-boot booted over NAND or MMC, a Linux kernel image can be booted on Beagle Board.

The Linux Kernel Image (uImage) can be downloaded on to Beagle DDR memory using

UART (time consuming), MMC, NAND (if it was stored in it), USB (Not supported yet).

The Below procedure gives MMC based Linux Kernel Booting.
Complile the Linux Kernel Image "uImage".
Copy the uImage file in MMC/SD card pre-formated for FAT32.
Download the uImage
OMAP3 beagleboard.org # mmcinit
OMAP3 beagleboard.org # fatload mmc 0 0x80300000 uImage
Set/Configure the boot arguments

The filesystem to be mounted could be present in MMC, RAM (Ramdisk), NAND (if copied), Ethernet (using Ethernet over USB Dongle on USB HOST machine). The Bootargs for each of these is shown Below
Bootargs for RAMDISK File System

OMAP3 beagleboard.org # setenv bootargs console=ttyS2,115200n8 ramdisk_size=8192 root=/dev/ram0 rw rootfstype=ext2 initrd=0x81600000,8M nohz=off
Bootargs for MMC File System
OMAP3 beagleboard.org # setenv bootargs console=ttyS2,115200n8 noinitrd root=/dev/mmcblk0p1 rootfstype=ext2 rw rootdelay=1 nohz=off
Bootargs for NAND (JFFS2) File System)
TBD
Bootargs for NFS (using Ethernet over USB Dongle)
TBD
Getting File System on Beagle Board
RAMDISK File system
OMAP3 beagleboard.org # fatload mmc 0 0x81600000 rd-ext2.bin

NOTE: rd-ext2.bin should have been copied onto MMC Card.
MMC File system
Copy Filesystem on MMC/SD card.
Format an MMC/SD card for ext2/ext3 file system using Linux Machine
Mount the MMC/SD card on Host Linux Machine
UnTar the Pre-built Filesystem
Un-Mount the MMC/SD card on Host Linux Machine
Remove the MMC/SD card that had uImage, and insert the MMC/SD card that has Filesystem.
Booting the Kernel Image
OMAP3 beagleboard.org # bootm 0x80300000
Thứ Hai, 27 tháng 6, 2011 02:15 Đọc tiếp >>

Beagle Source Code for revisions below REV B


The source uploaded are:
X-loader : http://beagleboard.googlecode.com/files/x-load-beagle-rev2.tar.gz.gz
U-boot (1.1.4) : http://beagleboard.googlecode.com/files/u-boot-beagle-rev2-trial2.tar.gz.gz
Linux Kernel (2.6.22) : http://www.beagleboard.org/uploads/2.6_kernel-beagle-rev2.tar.gz

The Pre-Built Images are available for:
x-load.bin : http://beagleboard.googlecode.com/files/x-load.bin
"Stable slow" MLO + u-boot.bin(381 MHz & L2 cache for kernel disabled):
MLO : http://beagleboard.googlecode.com/files/MLO (md5sum: 6a9f907d630de81f0b8ee8398cf94cf6)
u-boot.bin : http://beagleboard.googlecode.com/files/u-boot.bin (md5sum: 249bb0e452b60dce6560fbb54c4de844)
"Experimental performance" MLO + u-boot.bin (500 MHz & L2 cache for kernel enabled):
MLO : http://www.beagleboard.org/uploads/20080428/MLO (md5sum: fd4bd040dd000158952b67b743a5eb9c)
u-boot.bin : http://beagleboard.googlecode.com/files/u-boot.bin_500 (rename to u-boot.bin) (md5sum: 93fcfe00d952ebcd2c8cea8ce3232946)
Kernel (uImage) 2.6.22 : http://beagleboard.googlecode.com/files/uImage
BusyBox (ramdisk) File System : http://beagleboard.googlecode.com/files/rd-ext2.bin
BusyBox FS with ALSA libraries : http://beagleboard.googlecode.com/files/ALSA-FS.tar.gz

Tools used :

For Compilation

http://www.codesourcery.com/gnu_toolchains/arm/download.html

For Signing

http://beagleboard.googlecode.com/files/signGP

HP USB Disk Storage Format Tool 2.0.6

http://selfdestruct.net/misc/usbboot/SP27213.exe

Compilation Steps

Compiling x-loader
make CROSS_COMPILE=arm-none-linux-gnueabi- distclean
make CROSS_COMPILE=arm-none-linux-gnueabi- omap3530beagle_config
make CROSS_COMPILE=arm-none-linux-gnueabi-

Compiling u-boot
make CROSS_COMPILE=arm-none-linux-gnueabi- distclean
make CROSS_COMPILE=arm-none-linux-gnueabi- omap3530beagle_config
make CROSS_COMPILE=arm-none-linux-gnueabi-

Compiling Kernel
make CROSS_COMPILE=arm-none-linux-gnueabi- distclean
make CROSS_COMPILE=arm-none-linux-gnueabi- omap3_beagle_defconfig
make CROSS_COMPILE=arm-none-linux-gnueabi- uImage

Convert x-load.bin to MLO (required for MMC Boot)
Use the "SignGP" tool to sign the x-loader image. (“x-load.bin.ift” file is generated in the same folder.)
./signGP x-load.bin
Rename x-load.bin.ift to MLO
Copy MLO to MMC/SD card using a card reader/writer.
Thứ Hai, 27 tháng 6, 2011 02:14 Đọc tiếp >>

LinuxBootDiskFormat


Introduction

This guide is meant for those looking to create a dual-partition card, booting from a FAT partition that can be read by the OMAP3 ROM bootloader and Linux/Windows, then utilizing an ext3 partition for the Linux root file system.
Details

Text marked with shows user input.
Determine which device the SD Card Reader is on your system

Plug the SD Card into the SD Card Reader and then plug the SD Card Reader into your system. After doing that, do the following to determine which device it is on your system.
$ [dmesg | tail]
...
[ 6854.215650] sd 7:0:0:0: [sdc] Mode Sense: 0b 00 00 08
[ 6854.215653] sd 7:0:0:0: [sdc] Assuming drive cache: write through
[ 6854.215659] sdc: sdc1
[ 6854.218079] sd 7:0:0:0: [sdc] Attached SCSI removable disk
[ 6854.218135] sd 7:0:0:0: Attached scsi generic sg2 type 0
...

In this case, it shows up as /dev/sdc (note sdc inside the square brackets above).
Check to see if the automounter has mounted the SD Card

Note there may be more than one partition (only one shown in the example below).
$ [df -h]
Filesystem Size Used Avail Use% Mounted on
...
/dev/sdc1 400M 94M 307M 24% /media/disk
...

Note the "Mounted on" field in the above and use that name in the umount commands below.
If so, unmount it
$ [umount /media/disk]
Start fdisk

Be sure to choose the whole device (/dev/sdc), not a single partition (/dev/sdc1).
$ [sudo fdisk /dev/sdc]
Print the partition record

So you know your starting point. Make sure to write down the number of bytes on the card (in this example, 2021654528).
Command (m for help): [p]

Disk /dev/sdc: 2021 MB, 2021654528 bytes
255 heads, 63 sectors/track, 245 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System
/dev/sdc1 * 1 246 1974240+ c W95 FAT32 (LBA)
Partition 1 has different physical/logical endings:
phys=(244, 254, 63) logical=(245, 200, 19)
Delete any partitions that are there already
Command (m for help): [d]
Selected partition 1
Set the Geometry of the SD Card

If the print out above does not show 255 heads, 63 sectors/track, then do the following expert mode steps to redo the SD Card:
Go into expert mode.
Command (m for help): [x]
Set the number of heads to 255.
Expert Command (m for help): [h]
Number of heads (1-256, default xxx): [255]
Set the number of sectors to 63.
Expert Command (m for help): [s]
Number of sectors (1-63, default xxx): [63]
Now Calculate the number of Cylinders for your SD Card.
#cylinders = FLOOR (the number of Bytes on the SD Card (from above) / 255 / 63 / 512 )

So for this example: 2021654528 / 255 / 63 / 512 = 245.79. So we use 245 (i.e. truncate, don't round).
Set the number of cylinders to the number calculated.
Expert Command (m for help): [c]
Number of cylinders (1-256, default xxx): [enter the number you calculated]
Return to Normal mode.
Expert Command (m for help): [r]
Print the partition record to check your work
Command (m for help): [p]

Disk /dev/sdc: 2021 MB, 2021654528 bytes
255 heads, 63 sectors/track, 245 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System
Create the FAT32 partition for booting and transferring files from Windows
Command (m for help): [n]
Command action
e extended
p primary partition (1-4)
[p]
Partition number (1-4): [1]
First cylinder (1-245, default 1): [(press Enter)]
Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-245, default 245): [+50]

Command (m for help): [t]
Selected partition 1
Hex code (type L to list codes): [c]
Changed system type of partition 1 to c (W95 FAT32 (LBA))
Mark it as bootable
Command (m for help): [a]
Partition number (1-4): [1]
Create the Linux partition for the root file system
Command (m for help): [n]
Command action
e extended
p primary partition (1-4)
[p]
Partition number (1-4): [2]
First cylinder (52-245, default 52): [(press Enter)]
Using default value 52
Last cylinder or +size or +sizeM or +sizeK (52-245, default 245): [(press Enter)]
Using default value 245
Print to Check Your Work
Command (m for help): [p]

Disk /dev/sdc: 2021 MB, 2021654528 bytes
255 heads, 63 sectors/track, 245 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System
/dev/sdc1 * 1 51 409626 c W95 FAT32 (LBA)
/dev/sdc2 52 245 1558305 83 Linux
Save the new partition records on the SD Card

This is an important step. All the work up to now has been temporary.
Command (m for help): [w]
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 16: Device or resource busy.
The kernel still uses the old table.
The new table will be used at the next reboot.

WARNING: If you have created or modified any DOS 6.x
partitions, please see the fdisk manual page for additional
information.
Syncing disks.
Format the partitions

The two partitions are given the volume names LABEL1 and LABEL2 by these commands. You can substitute your own volume labels.
$ [sudo mkfs.msdos -F 32 /dev/sdc1 -n LABEL1]
mkfs.msdos 2.11 (12 Mar 2005)

$ [sudo mkfs.ext3 -L LABEL2 /dev/sdc2]
mke2fs 1.40-WIP (14-Nov-2006)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
195072 inodes, 389576 blocks
19478 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=402653184
12 block groups
32768 blocks per group, 32768 fragments per group
16256 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912

Writing inode tables: done
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information:
Bootloader settings

If you use bootloader U-Boot, use following settings to mount root file system at second partition from kernel:
console=ttyS2,115200n8 root=/dev/mmcblk0p2 rw rootdelay=1
Thứ Hai, 27 tháng 6, 2011 02:13 Đọc tiếp >>

How to write a Network Driver in Linux (Realtek 8139)

Linux Network Interface Driver
This article explains how to write a network interface driver in Linux . There are many network
interface cards available in market. I have taken the Realtek chip driver 8139too.c to explain
code snippets. This driver is implemented in linux/drivers/net/8139too.c file. I have chosen
8139too.c
driver because hardware specifications for Realtek chips are available free and you can download
or read them online .
See References section for download links to Realtek Manuals RTL8139D_DataSheet.pdf ,
RTL8139_ProgrammersGuide.pdf. I suggest you, first read device manuals and then read this
article for better understanding. RTL8139_ProgrammersGuide.pdf explains how the reception
and transmission happen in Realtek 8139 chip where as RTL8139D_DataSheet.pdf explains
register’s details. This article explains the driver from linux 2..6.26 kernel.
I assume that reader is familiar with Linux kernel and PCI devices. Though this article explains
8139too.c driver , writing any other network interface driver is similar except for the hardware
specific functionalities, which change.
This article is divided into 5 parts and I wish to present each part every week to facilitate short,
quick and informative reading.
1) Overview
2) Initialization
3) Packet handling ( reception and transmission)
4) Status and Control
5) Uninitialization
Overview
                                   
In Linux, network drivers have different properties than other drivers like char drivers and block
drivers. Char and block drivers have major and minor number concept . VFS identifies these
drivers using their major and minor numbers and these drivers have files created in /dev directory
with their major and minor numbers . But network drivers do not have any major or minor
number concept and no files created in /dev directory. Network drivers are identified in the
kernel with its interface descriptor block ,struct net_device (defined in
linux/include/linux/netdevice.h). net_device objects of all network drivers are put into a global
liked list and accessed by the kernel whenever it needs. An application cannot access the driver
directly and it should go through the system calls like socket .

As you know, any device can be interfaced with CPU using any bus like PCI , USB, Firewire etc.
Network interface card also can be interfaced with CPU using any of the above said buses .
Network interface card can be inbuilt into mother board or inserted into any bus slot. In this
article we assume that network interface card is a PCI device. When a packet arrives, network
interface card sees the destination MAC address of the packet and puts the packet in input data
buffer(RxRing) if the destination MAC address matches with its MAC address , raises an
interrupt and continue receiving the packets. If Driver wants to send a packet it puts the packet in
output buffer(TxBuffer) . Network interface card takes the packet from TxBuffer and puts that in
its controller’s FIFO buffer and try to send the packet. Once the packet is sent network interface
card raises an interrupt and writes status of the interrupt in its status registers. Any Network
interface driver is responsible for activities in the following areas:
Initialization
Packet Reception
Packet Transmission
Status and Control
Uninitialization

Initialization
The initialization part of a network driver has the responsibility of initializing the driver and
hardware. The following are the some of the responsibilities of initialization part of the driver.
Registering with the Linux low level bus interface subsystem
Allocating interface descriptor block (net_device) ,device specific structure and initializing
media specific fields
Getting device specific structure object pointer
Enabling Network interface card
Getting the Device resources (Memory mapped or port mapped I/O register map)
Getting device MAC address
Initialization of device methods in the net_device
Registering net_device object with the kernel
Registering the interrupt handler (ISR)
Allocating Rxring and Txring
Initializing the hardware (network interface card)
Start the network interface’s transmit Queue

2.1) Registering with the Linux low level bus interface subsystem
Linux provides low level interface to access bus. For PCI devices PCI subsystem is provided.
This provides functions for accessing PCI devices. For USB devices USB subsystem is provided.
The PCI subsystem in the kernel provides all the generic functions that are used in common by
various PCI device drivers to access a PCI device. First step in initialization part of the driver
should be registering with PCI subsystem. Once registration is over PCI subsystem will notify the
driver whenever the device is found on the bus by calling probe function of the driver. The
following code snippet shows registration with PCI subsystem. This code would be written in
initialization routine of the driver module.
static struct pci_device_id rtl8139_pci_tbl[] = {
{0×10ec, 0×8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{}, /*Null terminated entry*/
}
static struct pci_driver rtl8139_pci_driver = {
.name = DRV_NAME,
.id_table = rtl8139_pci_tbl,
.probe = rtl8139_init_one,
.remove = __devexit_p(rtl8139_remove_one),
#ifdef CONFIG_PM
.suspend = rtl8139_suspend,
                                    
.resume = rtl8139_resume,
#endif /* CONFIG_PM */
};
static int __init rtl8139_init_module (void)
{
return pci_register_driver(&rtl8139_pci_driver);
}
To register with the PCI subsystem,the driver should create a struct pci_driver object , fill in the
object and call pci_register_driver function. pci_register_driver function takes one parameter ,
pointer to
an object of type struct pci_driver . The following are some of the fields of pci_driver:
‘name’ field is name of this driver,
‘probe’ field is a call back function which is called whenever your network controller is found on
the PCI bus. It’s prototype is:
int (*probe) (struct pci_dev *dev, const struct pci_device_id *id);
‘id_table’ field is struct pci_device_id pointer which contains the device information
that you are writing driver for. struct pci_device_id has the following definition:
struct pci_device_id {
__u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/
__u32 subvendor, subdevice; /* Subsystem ID’s or PCI_ANY_ID */
__u32 class, class_mask; /* (class,subclass,progif) triplet */
kernel_ulong_t driver_data; /* Data private to the driver */
};
‘vendor’ field is vendor of the any PCI device(in this case network interface card ), ‘device ‘ field
is product or device id of the device , subvendor is subvendor of the device , ‘class’ is class of the
device (see PCI specification for different types classes ), driver_data is a private field that can be
used by driver.
‘remove’ is a call back function which is called whenever network interface card is removed or
                                    
when the driver module is unloaded. Prototype of this function is:
void (*remove) (struct pci_dev *dev)
’suspend ‘ is a call back function which is called whenever device is to be suspended and should
not process any more packets. Prototype of this function is:
int (*suspend) (struct pci_dev *dev, pm_message_t state);
‘resume’ is a call back function which is called by the PCI layer whenever suspended device
wants to be woken up. Prototype of this function is:
int (*resume) (struct pci_dev *dev);
Once the driver creates pci_driver object it is registered with the PCI subsystem using
pci_register_driver function. Whenever our device (network interface card) is found on the bus,
PCI subsystem calls driver’s ‘probe’ function. probe function receives two parameters. One is
pointer to
struct pci_dev object and second is pointer to struct pci_device_id object . Each PCI device is an
object of type struct pci_dev . The following is the 8139too.c probe function.
static int __devinit rtl8139_init_one (struct pci_dev *pdev, onst struct pci_device_id *ent)
c
{
struct net_device *dev = NULL;
struct rtl8139_private *tp;
}
2.2) Allocating interface descriptor block (net_device) ,device specific structure and
initializing media specific fields
Each interface is an object of type struct net_device , called interface descriptor block. Interface
can represent a specific media like Ethernet,Token ring and fddi etc. Interface descriptor block is
a
combination of device specific fields and media specific fields . the following function allocates
interface descriptor block struct net_device.
dev = alloc_netdev(sizeof(*tp),”eth%d”,ether_setup);
This function creates struct net_device object ,allocates space for device specific structure
                                      
s name to this interface as ‘eth%d’ (%d
struct rtl8139_private (first argument) and assign
specifies eth0 for first interface ,eth1 for second interface etc)(second argument).
struct rtl8139_private is a device specific structure .There will be an object of this structure
for each interface found on the network interface card. Each driver will define its own device
specific
structure. struct rtl8139_private definition can be found in 8139too.c file.
Realtek 8139 driver is a Ethernet driver. So we need to initialize Ethernet media specific fields of
n to
struct net_device object . alloc_netdev function calls ether_setup (third argument) functio
initialize the Ethernet media specific fields.
ether_setup is a kernel function which initialize some of the ethernet specific fields . tr_setup
function
can be used to initialize token ring device fields. fddi_setup function can be used for fddi
devices.
These all three tasks , allocating net_device , allocating space for device specific structure and
initializing
media specific fields can also be performed by calling alloc_etherdev media specific function.
The
following code shows that.
dev = alloc_etherdev(sizeof(*tp));
This allocates net_device object ,gives its name as eth%d and initialize ethernet media specific
fields.
For token ring devices you have alloc_trdev and for fddi devices you have alloc_fddidev
functions .
If you want more about struct net_device you can refer Understanding Linux network internals
book.
2.3 Getting device specific structure object pointer
                                    
Memory allocated for the device specific object will be pointed by the ‘priv’ field of the
net_device
object. This can be stored into a local variable using netdev_priv function. Direct accessing of
‘priv’
field is discouraged.
tp = netdev_priv(dev);
This will store the pointer to device specific structure into ‘tp’ local pointer variable.
2.4 Enabling Network Interface Card
At the initialization time , network interface card will be in idle state . we need to enable the
network
interface card by setting enable bit in the command register of the device configuration space.
This can
be done by calling pci_enable_device function.
rc = pci_enable_device(pdev);
if(rc)
goto err_out;
2.5 Getting the Device resources (Memory mapped or Port mapped register map )
To talk to the network interface card , network controller provides some registers. Driver has to
map
these registers into processor address space so that read/write operations by the driverwill be
made on
system memory addresses directly. PCI devices can provide two types of memory mapping, one
is
memory mapped I/O and second is port mapped I/ . O
Details of each register will be explained in the device specification. At the time of device
enumeration,
base address of the registers, some flags and total size of these registers are stored in ‘resources’
field of
the struct pci_dev object. Network interface driver needs to get these details and store them in
device specific structure to be used later. The following code snippet shows this:
                                    
pio_start = pci_resource_start (pdev, 0);
pio_end = pci_resource_end (pdev, 0);
pio_flags = pci_resource_flags (pdev, 0);
pio_len = pci_resource_len (pdev, 0);
mmio_start = pci_resource_start (pdev, 1);
mmio_end = pci_resource_end (pdev, 1);
mmio_flags = pci_resource_flags (pdev, 1);
mmio_len = pci_resource_len (pdev, 1);
Each PCI device can support upto six base addresses like base address 0,base address 1 etc . One
for
memory mapped ,one for port mapped and etc .For each base address an object of type struct
resource is created and filled with base address ,size and flags . Driver has to read each struct
resource object and get the base address and size and flags..
To get the base address of a device you can use pci_resource_start macro. This macro takes two
parameters , one is pci_dev object of the device that you want base address and another is base
address
register number. Base address register number can be one of 05 numbers.
To get the end of base address you can use pci_resource_end macro,to get size of the registers
you can
use pci_resource_len macro.
To get flags of the device you can use pci_resource_flags macro. Flags can be any of the
following.
IORESOURCE_IO /* Resource type */
IORESOURCE_MEM
IORESOURCE_IRQ
IORESOURCE_DMA
IORESOURCE_PREFETCH
IORESOURCE_READONLY
                                    
IORESOURCE_CACHEABLE
IORESOURCE_RANGELENGTH
IORESOURCE_SHADOWABLE
IORESOURCE_SIZEALIGN /* size indicates alignment */
IORESOURCE_STARTAL IGN /* start field is alignment */
IORESOURCE_DISABLED
IORESOURCE_UNSET
IORESOURCE_AUTO
IORESOURCE_BUSY /* Driver has marked this resource busy */
As a driver developer you need to know only IORESOURCE_IO, IORESOURCE_MEM and
IORESOURCE_BUSY flags. IORESOURCE_IO flags tel s that this base address is port mapped
,
l
IORESOURCE_MEM tells that this base address is memory mapped and
IORESOURCE_BUSY tells
that this resource is reserved by this driver. If resources are reserved, another driver cannot use
these
resources.
Once you got the device resources you need to check them for what type of mapping they are.
The
following code shows that :
/* make sure PCI base addr 0 is PIO */
if (!(pio_flags & IORESOURCE_IO)) {
dev_err(&pdev>dev, “region #0 not a PIO resource, aborting\n”);
rc = ENODEV;
goto err_out;
}
/* make sure PCI base addr 1 is MMIO */
                                   
if (!(mmio_flags & IORESOURCE_MEM)) {
dev_err(&pdev>dev, “region #1 not an MMIO resource, aborting\n”);
rc = ENODEV;
goto err_out;
}
After checking the resources you have to reserve the resources by calling pci_request_regions
function.
This function reserves the resources and returns error if they are already reserved by another
driver.
rc = pci_request_regions (pdev, DRV_NAME);
if (rc)
goto err_out;
Some PCI devices have the capability of bus mastering . We need to enable it by calling
pci_set_master
function. This function sets the bus mastering bit of the command register in the device
configuration
space.
/* enable PCI busmastering */
pci_set_master(pdev);
Device resources have to be remapped into the kernel address space so that page tables will be
created
for the registers. For the Port mapped I/O this is done using ioport_map and for memory mapped
I/O
this is done using pci_iomap function. After remapping you need to store base address in the
‘base_addr’ field of net_device object and also store base address and resource length in the
device
specific object to be used later.
#ifdef USE_IO_OPS
ioaddr = ioport_map(pio_start, pio_len);
                                   
if (!ioaddr) {
dev_err(&pdev>dev, “cannot map PIO, aborting\n”);
rc = EIO;
goto err_out;
}
dev>base_addr = pio_start;
tp>mmio_addr = ioaddr;
tp>regs_len = pio_len;
#else
/* ioremap MMIO region */
ioaddr = pci_iomap(pdev, 1, 0);
if (ioaddr == NULL) {
dev_err(&pdev>dev, “cannot remap MMIO, aborting\n”);
rc = EIO;
goto err_out;
}
dev>base_addr = (long) ioaddr;
tp>mmio_addr = ioaddr;
tp>regs_len = mmio_len;
#endif /* USE_IO_OPS */
Once you got resources you need to reset the controller chip. This can be done by setting reset bit
of the
command register of the controller.(see the device specification)
/* Soft reset the chip. */
RTL_W8 (ChipCmd, CmdReset);
/* Check that the chip has finished the reset. */
for (i = 1000; i > 0; i) {
                                   
barrier();
if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
break;
udelay (10);
}
RTL_W8 macro definition is:
#define RTL_W8(reg, val8) iowrite8 ((val8), ioaddr + (reg));
2.6 Getting device MAC address
Driver has to read the MAC address stored in the ROM of the network interface card . To access
ROM
of the network interface card , some of the registers of the memory mapped or port mapped I/O
registers
are used. This details can be found in the device specification.8139too driver calls read_eeprom
local
function to read the MAC address from the ROM of the controller. This MAC address is stored
in the
‘dev_addr’ and ‘perm_addr’ fields of net_device object.
addr_len = read_eeprom (ioaddr, 0,      == 0×8129 ? 8 : 6;
for (i = 0; i <>
((__le16 *) (dev>dev_addr))[i] = cpu_to_le16(read_eeprom (ioaddr, i + 7, addr_len));
memcpy(dev>perm_addr, dev>dev_addr, dev>addr_len);
2.7 Filling device methods in the net_device
Driver has to provide it’s functionalities to the kernel through the device methods of struct
net_device . These are the operations that can be performed on the network interface. Some of
the
function pointers of net_device structure are left blank and some are filled by ‘ether_setup’
function
called at the time of net_device object allocation.
                                      
Driver should fill some basic fundamenta l operations and can leave optional operations.
Fundamental
methods are those that are needed to be able to use the interface; optional methods implement
more
advanced functionalities that are not strictly required.
/* The Rtl8139specific entries in the device structure. */
dev>open = rtl8139_open;
dev>hard_start_xmit = rtl8139_start_xmit;
netif_napi_add(dev, &tp>napi, rtl8139_poll, 64);
dev>stop = rtl8139_close;
dev>get_stats = rtl8139_get_stats;
dev>set_multicast_list = rtl8139_set_rx_mode;
dev>do_ioctl = netdev_ioctl;
dev>ethtool_ops = &rtl8139_ethtool_ops;
dev>tx_timeout = rtl8139_tx_timeout;
dev>watchdog_timeo = TX_TIMEOUT;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev>poll_controller = rtl8139_poll_controller;
#endif
‘open ‘ function opens the interface and is called whenever user configures the interface using
any
utilities like ifconfig or ip . This function explained later in detail.
‘hard_start_xmit’ function is called whenever kernel wants to send a packet . This function is
explained later in detail.
‘rtl8139_poll ‘ is called whenever there is an incoming packet to be processed. This function is
explained later in detail.
’stop’ function stops the interface and is called whenever interface is brought down. This
function
                                     
is explained later in detail.
‘get_stats’ is called whenever an application needs to know statistics of the interface . This
function is explained later in detail.
’set_multicast_list’ is an optional method and is called when the multicast list for the device
changes and when the flags change . We are not going to explain this function.
‘do_ioctl’ is interface specific function . This is an optional routine and we are not going to
explain.
‘ethtool_ops’ is a pointer to a structure of type struct ethtool_ops. This structure contains some
function pointers that are used by the ethtool tool. This we are not going to explain.
‘poll_controller’ is called whenever kernel wants to poll for the device status. This function
simply calls drivers interrupt routine to check if the device has anything to say.
After this some of the net_device and device specific object fields are filled .
dev>features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
dev>irq = pdev>irq;
/* tp zeroed and aligned in alloc_etherdev */
tp>mmio_addr = ioaddr;
‘features’ field of net_device object tells the capabilities of the driver like it support scatter gather
I/O ,check sum can be calculated in hardware and can DMA to high memory etc.’irq’ field of
net_device
object contains irq number of this controller.
2.8 Registering net_device object with kernel
Driver has to register with the kernel by giving net_device object . All net_device objects of all
interfaces are put into linked lists and accessed by the kernel whenever it needs. Network driver
can
register with the kernel using register_netdev function.
i = register_netdev(dev);
register_netdev function takes a completed net_device object and adds it to the kernel interfaces.
                                     
0 is returned on success and a negative error no code is returned on a failure to set up the device,
or if
the name is a duplicate.
struct net_device object is stored in struct pci_dev object so that it can be accessed later.
This is done with pci_set_drvdata function.
pci_set_drvdata(pdev , dev);
} /*end of rtl8139_init_one function */
/*start of open function */
static int rtl8139_open (struct net_device *dev)
{
open function is called by the kernel whenever this network interface is configured by admin
using any
user space utilities like ifconfig or ip .When ifconfig is used to assign an address to the interface,
it
performs two tasks. First, it assigns the address by means of ioctl(SIOCSIFADDR) (Socket I/O
Control
Set Interface Address). Then it sets the IFF_UP bit in dev>flag by means of
ioctl(SIOCSIFFLAGS) (Socket I/O Control Set Interface Flags) to turn the interface on.
open function receives net_device object as its parameter. Driver should get the device specific
object which is stored in the ‘priv’ field of net_device object at the time of net_device object
allocation. This can be done by calling netdev_priv inline function.
struct rtl8139_private *tp = netdev_priv(dev);
/* get registers base address in a local variable */
void __iomem *ioaddr = tp>mmio_addr;
2.9 Registering Interrupt handler (ISR)
Whenever a packet is received or a packet is sent an interrupt is raised by the network controller.
Driver
needs to register an interrupt handler(ISR ) and this handler is called whenever controller raises
an
                                    
interrupt. Driver can register the interrupt handler either in driver’s init routine or in the open
function .
Driver registers with interrupt handler using request_irq routine.
retval = request_irq (dev>irq, rtl8139_interrupt, IRQF_SHARED, dev>name, dev);
if (retval)
return retval;
request_irq routine takes five parameters. First parameter is irq number of the device , second
parameter
is interrupt handler (ISR) ,Third parameter is irqflags,fourth parameter is device name and last
parameter
is dev_id. ‘dev_id’ feild can be of any object pointer ,is necessary if irqflags is IRQF_SHARED
and
used at the time of freeing the ISR using free_irq routine. Generally this field will be a pointer to
net_device instance and is used at the time of interrupt handler execution. Interrupt handler has
the
following prototype:
irqreturn_t (*irq_handler_t)(in t, void *)
and irqflags can be any of the following.
* IRQF_DISABLED keep irqs disabled when calling the action handler
* IRQF_SAMPLE_RANDOM irq is used to feed the random generator
* IRQF_SHARED allow sharing the irq among several devices
* IRQF_PROBE_SHARED set by callers when they expect sharing mismatches to
occur
* IRQF_TIMER Flag to mark this interrupt as timer interrupt
* IRQF_PERCPU Interrupt is per cpu
* IRQF_NOBALANCING lag to exclude this interrupt from irq balancing
F
* IRQF_IRQPOLL Interrupt is used for polling (only the interrupt that is registered first
                                     
in an shared interrupt is considered for performance reasons)
request_irq routine allocates interrupt resources and enables the interrupt line and IRQ handling.
From
the point this call is made driver handler function may be invoked. Since driver handler function
must
clear any interrupt the board raises, driver must take care both to initialize the hardware and to set
up
the interrupt handler in the right order.
We will describe functionalities of interrupt handler(ISR) later in this article.
2.10 Allocating Rxring and Txbuffer
Whenever network controller receives a packet it puts that in a receive buffer called RxRing and
raises an
interrupt and continue to receive next packet. Driver puts outgoing packets in Txbuffer and
network
controller takes the packets from the Txbuffer , sends them out of the wire and raises interrupt.
We will
describe this process later in detail. Driver allocates Rxring and Txbuffer using
dma_alloc_coherent
routine. If Memory allocated for the buffers ,the by dma_free_coherent routine returns virtual
address
of the buffers .
tp>tx_bufs = dma_alloc_coherent(&tp>pci_dev>dev,TX_BUF_TOT_LEN,
&tp>tx_bufs_dma, GFP_KERNEL);
tp>rx_ring = dma_alloc_coherent(&tp>pci_dev>dev, X_BUF_TOT_LEN, R
&tp>rx_ring_dma, GFP_KERNEL);
if (tp>tx_bufs == NULL || tp>rx_ring == NULL) {
free_irq(dev>irq, dev);
if (tp>tx_bufs)
dma_free_coherent(&tp>pci_dev>dev,TX_BUF_TOT_LEN,
tp>tx_bufs, tp>tx_bufs_dma);
                                     
if (tp>rx_ring)
dma_free_coherent(&tp>pci_dev>dev,RX_BUF_TOT_LEN,
tp>rx_ring, tp>rx_ring_dma);
return ENOMEM;
}
dma_alloc_coherent routine takes four parameters. First is generic device struct device object ,
second is length of the buffer ,third is an output param of type dma_addr_t which is filled with
physical
address (bus address) of the allocated memory and fifth is GFP flag which tells how the memory
should
be allocated..This function returns virtual address of the memory allocated.
2.11 Initialize the hardware (network interface card)
Network driver has to initialize network controller at the time of open function is called.
Controller
initialization includes, resetting the chip , restoring MAC address in the chip register enabling ,
reception(rx) and transmission by setting rxenable and txenable bits in command register of the
controller,setting transfer thresholds , initializing transmission descriptors and reception
descriptor of the
controller with the physical addresses of the Txbuffer and RxRing,setting what type of packets to
be
received by setting in RxConfig and TxConfig registers, and enabling interrupts by setting
Interrupt
Mask Register(IMR) .
1 Soft reset the chip
RTL_W8 (ChipCmd, CmdReset);
/* Check that the chip has finished the reset. */
for (i = 1000; i > 0; i) {
barrier();
if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
                                    
break;
udelay (10);
}
2 Restore the MAC address
RTL_W32_F (MAC0 + 0, le32_to_cpu (*(__le32 *) (dev>dev_addr + 0)));
RTL_W32_F (MAC0 + 4, le16_to_cpu (*(__le16 *) (dev>dev_addr + 4)));
3 Enable transmission and reception
RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
4 Set type of packets to be received
RTL_W32 (RxConfig, tp>rx_config);
RTL_W32 (TxConfig, rtl8139_tx_config);
5 initialize reception buffer descriptor(RxBuf) with RxRing DMA address(bus address).This s
i
where physical address used.
RTL_W32_F (RxBuf, tp>rx_ring_dma);
6 Initialize transmission descriptors with Txbuffer DMA address (bus address)
for (i = 0; i <>
RTL_W32_F (TxAddr0 + (i * 4), tp>tx_bufs_dma + (tp>tx_buf[i] tp>tx_bufs));
7 Enable all known interrupts by setting the interrupt mask register
RTL_W16 (IntrMask, rtl8139_intr_mask);
2.12 Start the network interface’s transmit Queue
The open function should also start the interface’s transmit queue (allowing it to accept packets
for
transmission) once it is ready to start sending data. Driver should call kernel function
netif_start_queue
to start queue.
netif_start_queue (dev);
                                      
netif_start_queue takes net_device object as its parameter and returns nothing. This function
simply
sets a bit in ’state’ field of net_device object that allows upper layers to call the device
hard_start_xmit function .
}/ * end of open function */
3 Packet handling
Packet handling is a task of performing transmission and reception of packets. Packet handling is
most
important task of any network interface driver. in kernel discussions, transmission refers only to
sending
frames outward, whereas reception refers to frames coming in.
Before going to see how transmission and reception happen we will see the role of interrupts in
network
drivers. Kernel can use two main techniques for exchanging data: pol ing and interrupts. There is
also an
l
option of combination of these two techniques.
Polling is a technique where the kernel constantly keeps checking whether the device has
anything to
say. It can do that by continually reading a memory register on the device, for instance, or
returning to
check it when a timer expires.
Interrupts is another technique technique of exchanging data. Here the device driver, on behalf of
the
kernel, instructs the device to generate a hardware interrupt when specific events occur. The
kernel,
interrupted from its other activities, will then invoke a handler registered by the driver to take
care of the
device’s needs. Interrupts can be raised by the device when frame is received and when a frame is
transmitted .. If this is the reception of a frame, the handler queues the frame somewhere and
notifies the
                                     
kernel about it and if it is transmission the handler updates its status.
The code that takes care of an input frame is split into two parts: first the driver
copies the frame into an
input queue accessible by the kernel, and then the kernel processes it (usually passing it to a
handler
dedicated to the associated protocol such as IP). The first part is executed in interrupt context and
second
part is executed in the bottom half ..Second part may interrupted by the first because interrupt
context
has the higher priority than bottom half . More about bottom halves can be read in Understanding
Linux
Kernel and Understanding Linux network internals books.
Multiple Frames also can be processed During an Interrupt. This approach is used by quite a few
Linux
device drivers. When an interrupt is notified and the driver handler is executed, the latter keeps
downloading frames and queuing them to the kernel input queue, up to a maximum number of
frames
TimerDriven Interrupts technique is an enhancement to the previous ones. Instead of having the
device
asynchronously notify the driver about frame receptions, the driver instructs the device to
generate an
interrupt at regular intervals. The handler will then check if any frames have arrived since the
previous
interrupt, and handles all of them in one shot.
Combination of all above said techniques is also possible . A good combination would use the
interrupt
technique under low load and switch to the timerdriven interrupt under high load.
Pros and cons of all above said and more detail description of above said techniques can be
found in
Understanding Linux Network Internals book by Christian Benvenuti.
3.1 Packet Reception
                                    
When a packet arrives into the network interface card , network controller checks the destination
MAC
address of the packet. if it matches with its MAC address or if it is broadcast address network
interface
card copies the packet into receive buffer(Rxring) and raises an interrupt.
Receive buffer(Rxrinf) is a block of I/O memory allocated by the river . Network interface card
will
d
have a receive buffer descriptor register and a receive buffer status register. Driver has to write
Physical
address of the receive buffer allocated into the receive buffer descriptor register. This process is
specific
to hardware and is provided in the device manual. Some devices provide some receive block
descriptors,a structure,that contains status of the each packet , buffer pointer and size of packets
etc.
Driver has to allocate a buffer and physical address of this is put in the buffer pointer .
When a packet is received by the network interface card, it adds a packet header before the
packet , puts
the packet in receive buffer(Rxring) and raises interrupt. This is specific to Realtek 8139 chips
and see
device specification.
When the interrupt is raised , driver interrupt handler(ISR) gets called. Driver interrupt handler
has to
check the interrupt status register(ISR) of the device what the interrupt is raised for and has to
take
appropriate action. In the case of reception ,reception bit of interrupt status register is set. Now
we will
see step by step what interrupt handler does:
3.1.1 Interrupt handler of the driver:
Interrupt handler is called when a packet is received or transmitted. Kernel will send two
arguments to
                                    
this function . One is irq number and other is dev_id which is sent as last parameter of
request_irq
function at the time of interrupt handler registration. Generally this is a pointer to net_device
object.
As i said, driver has to check status register of the network interface card and should take action
accordingly. In the case of packet reception , driver should schedule a bottom half and return
from
interrupt handler. The next step of processing of packet is done by the kernel in the bottom half.
In the
bottom half, kernel calls driver’s poll function to do the later processing of packet.
static irqreturn_t rtl8139_interrupt (int irq, void *dev_id)
{
1 Get net_device object from the dev_id
struct net_device *dev = (struct net_device *) dev_id;
2 Get device specific structure object from the net_device. This is stored in the ‘priv’ field of
net_device. Use netdev_priv inline function to get pointer to that and store registers base
address into a local variable ‘ioaddr’ .
struct rtl8139_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp>mmio_addr;
3 Get interrupt status register (ISR) of the controller into a local variable
status = RTL_R16 (IntrStatus);
4 Irq numbers in PCI devices can be shared by many devices. So many devices might have been
registered interrupt handler on the same irq number . Driver has to confirm that interrupt has
been raised by its interface card . This can be done by checking interrupt status register for
any pending interrupts by the interface card.
/* shared irq? */
if (unlikely((status & rtl8139_intr_mask) == 0))
goto out;
                                     
5 Check if the device is present or not (hot pluggable) or if there is major problem.
if (unlikely(status == 0xFFFF))
goto out;
6 Driver has to acknowledge the interrupts by clearing appropriate bits in the interrupt status
register (ISR)
ackstat = status & ~(RxAckBits | TxErr);
if (ackstat)
RTL_W16 (IntrStatus, ackstat);
7 As i said , receive packets are processed by poll function vector in the bottom handler.
Network uses softirq NET_ RX_SOFTIRQ bottom half for input packets. Driver should
schedule the bottom half and finish the interrupt handler. netif_rx_schedule is used to enable
NET_RX_SOFTIRQ bottom half. This functions takes two parameters, one is net_device
object and other is an object of type struct napi_struct . This structure has the
following definition.
struct napi_struct {
/* The poll_list must only be managed by the entity which
* changes the state of the NAPI_STATE_SCHED bit. This means
* whoever atomically sets that bit can add this napi_struct
* to the percpu poll_list, and whoever clears that bit
* can remove from the list right before clearing the bit.
*/
struct list_head poll_list;
unsigned long state;
int weight;
int (*poll)(struct napi_struct *, int);
#ifdef CONFIG_NETPOLL
                                     
spinlock_t poll_lock;
int poll_owner;
struct net_device *dev;
struct list_head dev_list;
#endif
};
This object is filled at the time of function pointers assignment, using netif_napi_add
function.
The following code checks status of the interrupt and calls netif_rx_schedule to
enable the bottom half. netif_rx_schdule function first tests if poll needs to be scheduled
using netif_rx_schedule_prep, is scheduled only if network interface up and next calls
__netif_rx_schedule to schedule poll .
if (status & RxAckBits)
netif_rx_schedule(dev, &tp>napi);
8 return from the interrupt handler. (we will see transmission part of interrupt handler later in
Packet transmission section )
return IRQ_RETVAL(handled);
} /* end of interrupt handler routine */
3.1.2 NET_RX_SOFTIRQ softirq calls driver’s poll method
Kernel calls poll method of the driver in the NET_RX_SOFTIRQ softirq bottom half to process
the
input packet . This softirq was scheduled in interrupt handler routine.
poll method receives two parameters, one is pointer to struct napi_struct object and second is
‘budget’. napi_struct object is the object which was created at the time of initialization of
methods in
the net_device object .’budget’ field is the maximum number of packets the kernel can accept at
this
                                    
time or we can say that the ‘budget’ value is a maximum number of packets that the current CPU
can
receive from all interfaces.
The following is the 8139too.c driver poll method. It checks for the interrupt status register and
calls
rtl8139_rx local function to do the rest of the process.
static int rtl8139_poll(struct napi_struct *napi, int budget)
{
1 Get device specific structure object. ‘napi’ is a field of type stuct napi_struct in device
specific structure struct rtl8139_private. If we know the address of ‘napi’ field of
struct rtl8139_private we can find the starting address of the struct
rtl8139_private object using container_of function.
struct rtl8139_private *tp = container_of(napi, struct rtl8139_private, napi);
2 Get net_device object from the struct rtl8139_private object and store register
base address into a local variable.
struct net_device *dev = tp>dev;
void __iomem *ioaddr = tp>mmio_addr;
3 Check if it was the receive interrupt and call rtl8139_rx local function. rtl8139_rx returns
number of packets received. This function is explained below.
if (likely(RTL_R16(IntrStatus) & RxAckB its))
work_done += rtl8139_rx(dev, tp, budget);
4 If number of packets received is less than budget , reenable receive interrupts by setting the
interrupts mask regsiter(IMR) and all __netif_rx_complete function to turn of polling.
c
RTL_W16_F(IntrMask, rtl8139 _intr_mask);
__netif_rx_complete(dev, napi);
__netif_rx_complete function removes this interface from the polling list.
                                    
5 Return number of packets received
return work_done;
} /*end of rtl8139_poll method*/
A received packet is put into a structure struct sk_buff called socket buffer. This structure is the
main encapsulation of a packet and contains pointers to point different layer headers in the packet
and
pointers to input ,output interfaces . More about this structure can be read in Understanding
Linux
network internals book.
Driver has to take the packet from the RxRing , copy that into sk_buff object and give it to the
kernel.
rtl8139_rx local function will do that. This function receives three parameters , one is pointer to
net_device object ,second is pointer to device specific object struct rtl8139_private and last is
‘budget’.
static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp, int budget)
{
void __iomem *ioaddr = tp>mmio_addr;
int received = 0;
1 Get pointer to RxRing
unsigned char *rx_ring = tp>rx_ring;
2 Get current packet offeset (see device specification)
unsigned int cur_rx = tp>cur_rx;
3 Now the driver should run in a loop and take the each packet from the RxRing . The loop
should run until three conditions are satisfied . Three conditions are network interface should be
up, received packets should be less than the ‘budget’ and the RxRing is not empty.
while (netif_running(dev) && received <>
&& (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
struct sk_buf *skb;
                                    
4 Get the packet offset into the RxRing
u32 ring_offset = cur_rx % RX_BUF_LEN;
5 Get the packet header ( See device Manual) and find packet size. Note that packet size is
receive packet size minus 4( 4 is CRC)
/* read size+status of next frame from DMA ring buffer */
rx_status = le32_to_cpu (*(__le32 *) (rx_ring + ring_offset));
rx_size = rx_status >> 16; /*receive packet size from packet header*/
pkt_size = rx_size – 4; /* packet size */
6 Allocate struct sk_buff object.
skb = dev_alloc_skb (pkt_size + 2);
7 Copy packet into sk_buff . This will copy packet into ‘data’ field of sk_buff
skb_copy_to_linear_data (skb, &rx_ring[ring_offset + 4], pkt_size);
8 Set ‘protocol’ field of sk_buff to appropriate packet type. This is ‘type’ of ethernet
frame. Call eth_type_trans to get the packet type. For token ting devices you can use
tr_type_trans function.
skb>protocol = eth_type_trans ( skb, dev);
9 Update statistics
tp>stats.rx_bytes += pkt_size;
tp>stats.rx_packets++;
10 Give the skb to kernel
netif_receive_skb (skb);
received ++;
} /* end of while*/
tp>cu_rx = cur_rx;
return received;
}
                                   
netif_running inline function tests if the interface is up and running. It checks if
__LINK_STATE_START bit of ’status’ field of et_device object is set. dev_alloc_skb function
n
allocates memory for sk_buff from the cache and fills some the fields. netif_receive_skb is
main receive data processing function.
3.2 Packet Transmission
When the kernel has packets to send out of the interface ,it calls driver’s hard_start_xmit method.
hard_start_xmit function receives two parameters ,one is sk_buff of the packet to be transmitted
and
another is net_device object .
sk_buff of the trasmitted packet is filled by the upper layers. ‘data’ field of sk_buff contains
packet to be sent. Driver should extract packet from the sk_buff and put that into TxBuffers.
Then
driver should write length of packet and threshold in the Transmission descriptor status register
of the
device . Then the device takes the packet from the Txbuffers and sends it.
Now we will describe rtl8139_start_xmit(hard_start_xmit) function of 8139too driver.
static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
{
struct rtl8139_private *tp = netdev_priv(dev);
void __iomem ioaddr = tp>mmio_addr; /*register base address */
unsigned int len = skb>len; /* length of the packet */
1 Calculate the next Tx descriptor entry
entry = tp>cur_tx % NUM_TX_DESC;
2 Copy the packet into TxBuffer
skb_copy_and_csum_dev(skb, tp>tx_buf[entry]);
3 Free the socket buffer sk_buff
dev_kfree_skb(skb);
                                   
4 Writer length of packet and threshold in Transmission descripor status register
RTL_W32_F (TxStatus0 + entry * sizeof (u32)),
(
tp>tx_flag | max(len, (unsigned int)ETH_ZLEN));
} /* end of tl8139_start_xmit */
Network interface card will take the packet from the TxBuffer and puts that in it’s FIFO. Once
the FIFO
reached threshold value set by the driver it sends the packet. After sending the packet network
interface
card will raise an interrupt. Driver’s interrupt handler will be called.
Driver’s interrupt handler should check why the interrupt has occurred and if it is transmission
interrupt it
updates its statistics. The following code shows how rtl8139too driver will handle the
transmission
interrupt.
static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance)
{
struct net_device *dev = (struct net_device *) dev_instance;
struct rtl8139_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp>mmio_addr;
status = status = RTL_R16 (IntrStatus);
1 Check if the interrupt is transmission interrupt and call rtl8139_tx_interrupt local
function.
if (status & (TxOK | TxErr)) {
rtl8139_tx_interrupt (dev, tp, ioaddr);
if (status & TxErr)
RTL_W16 (IntrStatus, TxErr);
} /* end of rtl8139_interrupt */
                                    
static void rtl8139_tx_interrupt (struct net_device *dev, struct rtl8139_private *tp,
void __iomem *ioaddr)
{
1 Read transmission descriptor status register and see what the status of the packet.
txstatus = RTL_R32 (TxStatus0 + (entry * sizeof (u32)));
2 Increment error statistics if there are any problems in the transmission
if (txstatus & (TxOutOfWindow | TxAborted)) {
tp>stats.tx_errors++;
if (txstatus & TxAborted) {
tp>stats.tx_aborted_errors++;
RTL_W32 (TxConfig, TxClearAbt);
RTL_W16 (IntrStatus, TxErr);
}
if (txstatus & TxCarrierLost)
tp>stats.tx_carrier_errors++;
if (txstatus & TxOutOfWindow)
tp>stats.tx_window_errors++;
}
3 Increment statistics of successful transmitted packets
else {
tp>stats.collisions += (txstatus >> 24) & 15;
tp>stats.tx_bytes += txstatus & 0×7ff;
tp>stats.tx_packets++;
}
4 start the transmission queue allowing kernel to call driver’s hard_start_xmit method
again.
                                    
netif_wake_queue (dev);
}/* End of rtl8139_tx_interrupt */
4 Status and Control
4.1 When kernel wants to stop interface it calls stop method of driver
When kernel wants to stop interface it calls stop function of driver. This is called ,for example,
when the
interface is brought down by using any utilities like ifconfig. Responsibility of this function is
would be
exactly opposite to what we have done in open method. Some of the responsibilities include
freeing
receive and transmission buffers , freeing irq and stopping transmission queue etc.
stop takes struct net_device object as its parameter. The following code shows how 8139too.c
implements stop method.
static int rtl8139_close (struct net_device *dev)
{
struct rtl8139_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp>mmio_addr;
unsigned long flags;
1 stop transmission queue. Once transmission queue is stopped kernel cannot send any more
packets to the driver
netif_stop_queue(dev);
2 Prevent poll function to be scheduled .
napi_disable(&tp>napi);
3 Stop the chip’s Transmission and reception DMA processes . This can be done by writing 0
into
command register of device.
RTL_W8 (ChipCmd, 0);
4 Disable interrupts by clearing the interrupt mask register(IMR).
                                     
RTL_W16 (IntrMask, 0);
5 wait for pending IRQ handlers (on other CPUs) to be completed. This can be done using
synchronize_irq function.
synchronize_irq (dev>irq);
6 Unregister the interrupt handler (ISR)
free_irq(dev>irq,dev);
free_irq function removes an interrupt handler. The handler is removed and if the interrupt line
is no longer in use by any driver it is disabled. On a shared IRQ the driver must ensure the
interrupts are disabled by clearing interrupt mask register on the card it drives before calling
this function. This function does not return until any executing interrupts for this IRQ have
completed. This function must not be called from interrupt context. This function takes two
parameters one is irq line that is to be freed and second is ‘dev_id’ which is sent as last argument
to request_irq function.
7 Free receive(RxRing) and transmission(TxBuffer) buffers .
dma_free_coherent(&tp>pci_dev>dev,RX_BUF_TOT_LEN,
tp>rx_ring, tp>rx_ring_dma);
dma_free_coherent(&tp>pci_dev>dev,TX_BUF_TOT_LEN,
tp>tx_bufs, tp>tx_bufs_dma);
tp>rx_ring = NULL;
tp>tx_bufs = NULL;
return 0;
}
When Application wants statistics of the interface, drivers’s get_stats
4.
method is called
Whenever an application needs to get statistics for the interface, get_stats method of driver is
called. This
                                       
happens, for example, when ifconfig or netstat i is used by the user.
This function receives struct net_device object as its parameter and returns struct
net_device_stats object. Driver has to fill in the struct net_device_stats object with
interface statistics stored in device specific structure rtl8139_private and return it. The
following is the get_stats implementation of 8139too.c driver.
static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
{
struct rtl8139_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp>mmio_addr;
/*return statistics stored in ’stats’ field of device specific object*/
return &tp>stats;
}
5 Uninitialization
5.1 remove function of pci_driver (pci remove function)
pci_driver ’s remove method is called whenever network interface card is removed or when the
driver module is unloaded. Functionalities of this driver includes unregistering the net_device
with
the kernel and disabling the network interface card,freeing resources etc . remove function takes
pci_dev object as its parameter and returns nothing.
static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
{
1 Get net_device object from pci_dev object. We have stored net_device object in
pci_dev object by calling pci_set_drvdata in probe method of the driver.
struct net_device *dev = pci_get_drvdata (pdev);
2 flush if there are any packets to be transmitted yet. This can be done using
flush_scheduled_work function. flush_scheduled_work function starts the work queue
rtl8139_thread ,that is created at the time of probe function.
                                  
flush_scheduled_work();
3 Unregister the net_device object with kernel
unregister_netdev (dev);
4 Free IO Resources and net_device object
__rtl8139_cleanup_dev (dev);
5 Disable the network interface card .
pci_disable_device (pdev);
}
static void __rtl8139_cleanup_dev (struct net_device *dev)
{
struct rtl8139_private *tp = netdev_priv(dev);
struct pci_dev *pdev;
pdev = tp>pci_dev;
1 Remove kernel page tables for IO resources
#ifdef USE_IO_OPS
if (tp>mmio_addr)
ioport_unmap (tp>mmio_addr);
#else
if (tp>mmio_addr)
pci_iounmap (pdev, tp>mmio_addr);
#endif /* USE_IO_OPS */
2 Release reserved PCI I/O and memory resources. These resources were previously reserved by
pci_request_regions function. This function takes pci_dev object as its parameter.
pci_release_regions (pdev);
3 Free net_device object using free_netdev function. free_netdev function does the last stage of
destroying an allocated device interface. The reference to the device object is released.
                                   
free_netdev(dev);
}
5.2 Unregistering driver with the low level bus interface (PCI Subsystem)
Last step in the network driver development will be unregistering with low level bus interface ,in
this
case PCI subsystem. Driver can unregister with PCI subsystem using pci_unregister_driver
function.
This function takes pci_driver object as its parameter.
Unregistering will be done in driver module’s cleanup routine.
static void __exit rtl8139_cleanup_module (void)
{
pci_unregister_driver (&rtl8139_pci_driver);
}
References:
1) PCI Local Bus specification
2) Device specifications (RTL8139D_DataSheet.pdf , RTL8139_ProgrammersGuide.pdf)
3) Understanding Linux Network Internals by By Christian Benvenu ti
4) Linux source code
Thứ Hai, 27 tháng 6, 2011 02:04 Đọc tiếp >>