Transferred from: http://blog.sina.com.cn/s/blog_664c545f0100v9zl.html
Reprint: http://www.mculee.cn/post/48.html
"1" LCD Driver basics
The Linux-2.6.32.2 core already supports the s3c2440 LCD controller driver, but here we introduce some basic knowledge about the 2440 LCD controller and the driver-related LCD.
Note: Here we only discuss TFT LCD , which is the true color screen.
The most critical element of the LCD driver is the clock frequency setting, the clock frequency setting is not correct, the LCD display will flash, or not show at all. General LCD datasheet will be written on a recommended frequency, such as mini2440 used by the 3.5 "LCD, in its data manual on page 13th, there is a table:
As you can see, the recommended clock frequency here is 6.39MHz, approximately 6.4MHz, range, is 5m-6.85mhz. S3C2440 's LCD controller with this associated setting is Clkval, by setting it, you can generate the LCD interface on the VCLK pin to produce the clock frequency required by the LCD, then Clkval and vclk What is the relationship? In the 2440 Handbook (411 pages), there is a description:
The rate of VCLK signal depends on the Clkvalfield in the LCDCON1 register. Table 15-3 defines the
Relationship of VCLK and Clkval. The minimum value of Clkval IS0
Next, their mathematical relationship formula is provided in the manual:
VCLK (Hz) = hclk/[(clkval+1) x2]
Therefore, it can be concluded that:
VCLK = HCLK/((clkval+1) * *)
So how much is HCLK? Our Development Board runs at 400Mhz, which can be seen in the following code near the U-boot/cpu/arm920t/start.s 172 line:
# ifdefined (config_s3c2440)//thes3c2440 ' clock
#define MPLLCON 0x4c000004//the address Ofregister base to the main frequency
Ldr R0,=clkdivn//FCLK:HCLK:PCLK = 1:4:8
mov r1, #5
STR R1, [R0]
Ldr r0, =mpllcon//the mainfrequency is 405MHz
LDR R1, =0x7f021//refer to themanual PLL VALUE SELECTION TABLE of the S3c2440chip
STR R1, [R0]
Visible, FCLK:HCLK:PCLK = 1:4:8, so the Hclk=100mhz, and then according to the above formula to derive clkval should be:
clkval=hclk/(vclk*2)-1
Clkval = 100000000/(6400000 * 2)-1 =6.8
Select the nearest integer value 7 and write it to lcdcon1:17-8 (note: We actually use a value of 8), the resulting VCLK frequency is measured at about 5.63Mhz, it is also the value between 5-6.85mhz,
Pixclock parameters in the new kernel "2"
Hint: the Pixclock parameter we actually provide is not deduced in the following way, but the value of the Clkval is determined first, and then repeated attempts and guesses are obtained. The
has such a function in the Framebuffer driver (LINUX-2.6.32.2/DRIVERS/VIDEO/S3C2410FB.C):
clkdiv =div_round_up (S3C2410FB _CALC_PIXCLK (Fbi,var->pixclock), 2);
The clkdiv here is the clkval we mentioned above, and DIV_ROUND_UP is a macro definition, which is located in the include/linux/kernel.h file:
#define Div_ Round_up (N,d) (((n) + (d)-1)/(d))
This is actually a mathematical concept: rounding up. Here is a description of "rounding up":
1> problems
A, b are integers and a>1,b>1 The
┌a/b┐ is the rounding up of A/b.
When a/b is evenly divisible, the top rounding return value is a/b.
when not evenly divisible, the return value is an application of an int (A/b) + 1
Algorithm: If you have a dynamically growing buffer, the growth step is B,
one time the size of the buffer request is a, this time, you can use this algorithm to calculate the buffer of a close
fit size , just can hold A, and not too much, the redundant part is no more than B.
2>. method
Int ((a+b-1)/b)
3>. The proof of the Hunton
up is
because a>1, b>1, and A and B are integers, so you can set A=nb+m
where N is a nonnegative integer and M is 0 to B-1 number, then
A/b = N + m/b
(a+b-1) /b = N + 1 + (M-1)/b;
When M is 0 o'clock,
up (A/b) = n,
Int ((a+b-1)/b) = n + int (1-1/b) = n
When M is 1 to B-1 number, 0 <= M-1 <=b-2
Up (A/b) = n + 1,
Int (a+b-1)/b) = n + 1 + int ((M-1)/b) = n +1
So the integers a and B for A>1, b>1 are:
Up (A/b) = Int ((a+b-1)/b)
For the divisor of "2" for this algorithm, we can simply understand the "(N/2) +0.5" corresponding to the integer value, so there is no way to avoid the error, that is, the value of n is a certain range, where n is "S3C2410FB_CALC_PIXCLK ( Fbi,var->pixclock)", so the above formula can be rewritten as:
clkdiv= S3C2410FB_CALC_PIXCLK (Fbi,var->pixclock)/2 +0.5
The function of S3C2410FB_CALC_PIXCLK (fbi,var->pixclock) is defined in LINUX-2.6.32.2/DRIVERS/VIDEO/S3C2410FB.C:
static unsigned int s3c2410fb_calc_pixclk (struct S3C2410FB_INFO*FBI,
unsigned long PIXCLK)
{
unsigned long CLK = fbi->clk_rate;
unsigned long long div;
The result of this function is calculated here.
div = (unsigned long long) CLK * PIXCLK;
Div >>= 12;
Do_div (Div, 625 * 625UL * 625);
DPRINTK ("Pixclk%ld, Divisor is%ld\n", PIXCLK, (long) div);
return div;
}
It is therefore concluded that:
clkdiv=clk*pixclk/(10^12)/2 + 0.5
According to the actual printing results, the CLK here is actually hclk.
And according to the description in the static void S3c2410fb_activate_var (struct fb_info*info) function, a relationship is drawn:
Clkval=clkdiv-1
Combined with the formula obtained from the 2440-chip manual clkval=hclk/(vclk*2)-1, it is possible to obtain a general result ("roughly" can be understood as a certain error range):
pixclk= (HCLK-VLCK) X10^12/HCLK*VCLK
Take the Baoti we use as an example:
hclk=100mhz=100,000,000hz
vlck=6.4mhz=6400,000hz
Therefore, the calculated: PIXCLK = 146250, the unit is PS (picoseconds), and we actually set the value of 170000 is a certain error.
In addition, in the Linux kernel document, there is another way to calculate the Pixclock, see Linux/documentation/fb/framebuffer.txt, here we are no longer detailed introduction, interested can see for themselves, or to check the relevant information on the Internet.
If you compare these parameters to the "Halo", we recommend that you follow the friendly official has been transplanted validated parameters to set, the following are the specific reference steps.
"3" adds support for various LCD types in the kernel
To open arch/arm/mach-s3c2440/mach-smdk2440.c, navigate between lines 114 to 157, first remove the previous LCD device platform code, as follows:
static struct S3c2410fb_display Mini2440_lcd_cfg__initdata = {
. lcdcon5 =s3c2410_lcdcon5_frm565 |
S3c2410_lcdcon5_invvline |
S3c2410_lcdcon5_invvframe |
S3c2410_lcdcon5_pwren |
S3C2410_LCDCON5_HWSWP,
. Type =s3c2410_lcdcon1_tft,
. width = 240,
. Height = 320,
. Pixclock = 166667,
. xres = 240,
. Yres = 320,
. BPP = 16,
. Left_margin = 20,
. Right_margin = 8,
. Hsync_len = 4,
. Upper_margin = 8,
. Lower_margin = 7,
. Vsync_len = 4,
};
static struct S3c2410fb_mach_info Mini2440_fb_info__initdata = {
. Displays =&mini2440_lcd_cfg,
. num_displays = 1,
. Default_display = 0,
#if 0
. Gpccon =0xaa940659,
. Gpccon_mask = 0xFFFFFFFF,
. Gpcup =0x0000ffff,
. Gpcup_mask = 0xFFFFFFFF,
. Gpdcon =0xaa84aaa0,
. Gpdcon_mask = 0xFFFFFFFF,
. Gpdup =0x0000faff,
. Gpdup_mask = 0xFFFFFFFF,
#endif
. Lpcsel = ((0xce6) & ~) |1<<4,
};
Then join the friendly arm with the transplanted code as follows:
//; NEC 3.5 "LCD Configuration and parameter settings
#if defined (config_fb_s3c2410_n240320)
#define LCD_WIDTH 240
#define LCD_HEIGHT 320
#define Lcd_pixclock 100000
#define Lcd_right_margin 36
#define Lcd_left_margin 19
#define Lcd_hsync_len 5
#define Lcd_upper_margin 1
#define Lcd_lower_margin 5
#define Lcd_vsync_len 1
; Sharp 8 "LCD Configuration and parameter settings
#elif defined (config_fb_s3c2410_tft640480)
#define LCD_WIDTH 640
#define LCD_HEIGHT 480
#define Lcd_pixclock 80000
#define Lcd_right_margin 67
#define LCD_LEFT_MARGIN 40
#define Lcd_hsync_len 31
#define Lcd_upper_margin 25
#define Lcd_lower_margin 5
#define Lcd_vsync_len 1
, 3.5 "LCD configuration and parameter settings
#elif defined (config_fb_s3c2410_t240320)
#define LCD_WIDTH 240
#define LCD_HEIGHT 320
#define Lcd_pixclock 146250//170000
#define Lcd_right_margin 25
#define LCD_LEFT_MARGIN 0
#define Lcd_hsync_len 4
#define Lcd_upper_margin 1
#define Lcd_lower_margin 4
#define Lcd_vsync_len 1
, group Gen 7 "LCD configuration and parameter settings
#elif defined (config_fb_s3c2410_tft800480)
#define LCD_WIDTH 800
#define LCD_HEIGHT 480
#define Lcd_pixclock 11463//40000
#define Lcd_right_margin 67
#define LCD_LEFT_MARGIN 40
#define Lcd_hsync_len 31
#define Lcd_upper_margin 25
#define Lcd_lower_margin 5
#define Lcd_vsync_len 1
//; Configuration and parameter settings for the LCD2VGA (1024x768 resolution) module
#elif defined (config_fb_s3c2410_vga1024768)
#define LCD_WIDTH 1024
#define Lcd_height 768
#define Lcd_pixclock 80000
#define Lcd_right_margin 15
#define Lcd_left_margin 199
#define Lcd_hsync_len 15
#define Lcd_upper_margin 1
#define Lcd_lower_margin 1
#define Lcd_vsync_len 1
#define LCD_CON5 (s3c2410_lcdcon5_frm565 | S3C2410_LCDCON5_HWSWP)
#endif
#if defined (lcd_width)
static struct S3c2410fb_display mini2440_lcd_cfg __initdata ={
#if!defined (LCD_CON5)
. lcdcon5 = s3c2410_lcdcon5_frm565 |
S3c2410_lcdcon5_invvline |
S3c2410_lcdcon5_invvframe |
S3c2410_lcdcon5_pwren |
S3C2410_LCDCON5_HWSWP,
#else
. lcdcon5 = Lcd_con5,
#endif
. Type = S3c2410_lcdcon1_tft,
. width = lcd_width,
. Height = lcd_height,
. Pixclock = Lcd_pixclock,
. xres = Lcd_width,
. Yres = Lcd_height,
. BPP = 16,
. Left_margin = Lcd_left_margin + 1,
. Right_margin = Lcd_right_margin + 1,
. Hsync_len = Lcd_hsync_len + 1,
. Upper_margin = Lcd_upper_margin + 1,
. Lower_margin = Lcd_lower_margin + 1,
. Vsync_len = Lcd_vsync_len + 1,
};
static struct S3c2410fb_mach_info mini2440_fb_info __initdata ={
. Displays = &mini2440_lcd_cfg,
. num_displays = 1,
. Default_display = 0,
. Gpccon = 0xaa955699,
. Gpccon_mask = 0xffc003cc,
. Gpcup = 0x0000FFFF,
. Gpcup_mask = 0xFFFFFFFF,
. Gpdcon = 0xaa95aaa1,
. Gpdcon_mask = 0xffc0fff0,
. Gpdup = 0x0000faff,
. Gpdup_mask = 0xFFFFFFFF,
. Lpcsel = 0xf82,
};
#endif
Then open drivers/video/kconfig:
Config Fb_s3c2410_debug
BOOL "s3c2410 LCD Debug Messages"
Depends on fb_s3c2410
Help
Turn on debugging messages. Note that the can set/unset at run time
Through SYSFS
Choice
Prompt "LCD Select"
Depends on fb_s3c2410
Help
S3c24x0 LCD Sizeselect
Config fb_s3c2410_t240320
Boolean "3.5 inch 240X320 Toppoly LCD"
Depends on fb_s3c2410
Help
3.5 inch 240X320 TOPPOLYLCD
Config fb_s3c2410_n240320
Boolean "3.5 inch 240X320 NEC LCD"
Depends on fb_s3c2410
Help
3.5 inch 240x320 NECLCD
Config fb_s3c2410_tft640480
Boolean "8 inch 640x480 L80 LCD"
Depends on fb_s3c2410
Help
8 inch 640X480LCD
Config fb_s3c2410_tft800480
Boolean "7 inch 800x480 TFT LCD"
Depends on fb_s3c2410
Help
7 inch 800x480 TFTLCD
Config fb_s3c2410_vga1024768
Boolean "VGA 1024x768"
Depends on fb_s3c2410
Help
VGA 1024x768
Endchoice
Config fb_sm501
TriState "Silicon Motion SM501 Framebuffersupport"
Depends on FB &&mfd_sm501
Select Fb_cfb_fillrect
Select Fb_cfb_copyarea
In arch/arm/mach-mini2440/mach-smdk2440.c, add the following code in the initialization section ( Check for presence ):
static void __init mini2440_map_io (void)
{
S3c24xx_init_io (Mini2440_iodesc,array_size (MINI2440_IODESC));
S3c24xx_init_clocks (12000000);
S3c24xx_init_uarts (Mini2440_uartcfgs,array_size (MINI2440_UARTCFGS));
}
static void __initmini2440_machine_init (void)
{
#if defined (lcd_width)
S3c24xx_fb_set_platdata (&mini2440_fb_info);
#endif
S3c_i2c0_set_platdata (NULL);
S3c_device_nand.dev.platform_data =&mini2440_nand_info;
Platform_add_devices (Mini2440_devices,array_size (mini2440_devices));
Smdk_machine_init ();
}
In this way, we have completed the LCD driver transplant, if you need to add other models of LCD driver, you can also refer to the above method of copying, general small size of the Pixclock parameters can refer to the 3.5 ", more than 640x480 resolution parameters can refer to 8" LCD, Pay special attention to the length and width of the LCD you are using.
"4" Configuration kernel and download to dev Board test
Now, let's enter in the command line: Make menuconfig into the kernel configuration, and then click on the following submenu item to select:
Device Drivers--->
Graphicssupport--->
<*> support for frame buffer devices--->
LCD Select (3.5 inch 240X320 toppoly LCD)--->
(X) 3.5 inch 240X320 TOPPOLYLCD//select 3.5 inch LCD
Console Display Driver Support--->
<*> Framebuffer Consolesupport//Support Framebuffer Console
[*] Select Compiled-in Fonts//Choose font, Default VGA 8x8, VGA 8x16
[*] VGA 8x8font
[*] VGA 8x16font
[*] BOOTUP Logo--->
[*] Standard 224-color Linuxlogo
Press space or ENTER to select the LCD model we need, then exit to save the kernel configuration.
Execute at the command line:
#make Uimage
Will generate a arch/arm/boot/uimage, burn it to the Development Board, you can see a little penguin appears on the screen,
And there is a cursor prompt flashing at the bottom left of the logo.
(mknod/dev/fb0 C 29 0
Create a framebuffer device node, run cat/dev/fb0, if you find a bunch of garbled output on the screen, it means to find/dev/fb0 this device. If not, your video card may not be supported)
"6" displays kernel boot information via LCD
Before the kernel through the serial port to print kernel information, kernel command line parameter is CONSOLE=TTYSAC0, can now add one, namely "console=ttysac0, Console=tty1".
Note that Tty1 represents the first virtual terminal, Tty2 represents a second virtual terminal, ... tty0 represents the current virtual terminal.
However, to log in through it, you need to modify the Inittab file to add the following 6 lines:
#/etc/inittab
:: Sysinit:/etc/init.d/rcs
Console::askfirst:-/bin/sh
Tty1::askfirst:-/bin/sh
Tty2::askfirst:-/bin/sh
Tty3::askfirst:-/bin/sh
Tty4::askfirst:-/bin/sh
Tty5::askfirst:-/bin/sh
Tty6::askfirst:-/bin/sh
:: Ctrlaltdel:/sbin/reboot
:: Shutdown:/bin/umount-a–r
This will start the shell program on the virtual terminal. Press ALT+FN (N=1~6) on the LCD USB keyboard to switch between the 1th to 6th console.
In the serial terminal
[[email protected]/] #ls-L/DEV/TTY0
crw-rw----1root root 4, 0 Jan 1 00:00/dev/tty0
[[email protected]/] #ls-L/dev/tty1
crw-rw----1root root 4, 1 Jan 1 00:00/dev/tty1
[Email protected]/]#
You can see the virtual Terminal Tty0,tty1 's main device number bit 4, which is 0 and 1,c is a character device.
In the serial terminal
[[email protected]/] #echo hello>/dev/tty0
[Email protected]/]#
You can display the Hello character on the current LCD.
2410 running Linux console on the LCD, and then use the USB keyboard as input to form a small terminal. On the Internet to find some information, most just said can be kernel the startup parameters of the "console" set to "Tty0" can be, try it, after the modification can indeed be the kernel boot information to print to the LCD, but could not enter any information, no use.
Simply to study the Linux configuration, and finally can fully follow their own wishes to implement the LCD+USB keyboard console:
First step, enter "Character devices":
Console "height=" 660 "border=" 0 "width=" 832 ">
Tick "[*] support for console onvirtual terminal":
Console "height=" 660 "border=" 0 "width=" 832 ">
Step two, go to "Console drivers"--"frame-buffersupport":
Console "height=" 660 "border=" 0 "width=" 832 ">
Console "height=" 660 "border=" 0 "width=" 832 ">
Deselect support for only 8 pixels wide fonts, and select a font under Select Compiled-infonts for reference. This step is to improve the display font on the LCD, the default font is too small, not good looking.
Console "height=" 660 "border=" 0 "width=" 832 ">
Step three, go to "General Setup":
Console "height=" 660 "border=" 0 "width=" 832 ">
Select "Supportconsole_pm". This step is to open the cursor, otherwise when using the LCD as the console, there is no cursor, very bad. This point on the internet for a long time have not found, very sorry. Later simply to read kernel code, only to find the cursor display or not, unexpectedly is with "console_pm" option related, has not wanted to understand why ~ (PM is powermanagement write it? )
Console "height=" 660 "border=" 0 "width=" 832 ">
In the final step, modify the startup parameters of the kernel. Taking Vivi as an example of bootloader, we usually use the following startup parameters:
Vivi>param set Linux_cmd_line "Noinitrdroot=/dev/mtdblock/1 init=/linuxrc console=ttys0"
Here, Console=ttys0 says to make
Embedded Linux supports LCD console "turn"