TA的每日心情 | 怒 2019-11-20 15:22 |
|---|
签到天数: 2 天 [LV.1]初来乍到
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
s3c2440 lcd驱动源码文件是:drivers/video/s3c2410fb.c" Q- I; O0 p1 J+ m. X1 f4 v Z
# V& s4 {( X6 [
看驱动源码首先当然是先看入口函数,这里是s3c2410fb_init函数 O8 S3 z3 Z8 P) w1 I5 s# a% I
/ s/ T2 E" L4 p
% Q- `/ z4 J5 f1 @6 @int __init s3c2410fb_init(void)$ F& v6 @% I6 I$ ]) i- b
{
# l" n6 f9 p2 b6 i: i /* 注册一个s3c2410fb_driver平台驱动 */
8 w7 y0 z6 L/ I int ret = platform_driver_register(&s3c2410fb_driver);
* \+ r4 S4 v4 y4 n9 q& V# q1 j& V4 r
if (ret == 0)
R3 @- _1 s: A5 a% M ret = platform_driver_register(&s3c2412fb_driver);;1 L# K; Q$ T2 v3 n4 N) P! M0 t% b8 U
" `9 S' S: ~+ o5 g1 A return ret;
: q8 A$ z$ R5 `0 o}
g" @2 Q$ Q: G) x出口函数,自然是注销s3c2410fb_driver平台驱动) a3 j# m8 ]$ `) h8 Y3 g
2 ?3 w9 r8 e# F7 F0 v; n3 Ystatic void __exit s3c2410fb_cleanup(void)
) j, l$ Q" U6 I; i1 Z- U{- R) N* e- |6 V) Z
platform_driver_unregister(&s3c2410fb_driver);1 k! ^' g7 [8 X% I4 l
platform_driver_unregister(&s3c2412fb_driver);# \# k! ?5 P! }, @) h3 }& a
}# h; K6 {$ b- ^/ d7 d
我们研究的是s3c2440,只关心s3c2410fb_driver,s3c2412fb_driver不用理会。
/ q9 R5 M+ a9 H* S
+ l& S& P! x7 K" @static struct platform_driver s3c2410fb_driver = {
7 ^/ i) S4 }$ U& M% r5 {' m .probe = s3c2410fb_probe,
" q/ o2 ?) P j .remove = s3c2410fb_remove,' V# q7 i8 H) s# M
.suspend = s3c2410fb_suspend,
& E2 U+ A/ n$ q& q .resume = s3c2410fb_resume,
+ u* }- ^! A2 C/ P! I .driver = {) a. i$ ]' ^4 \
.name = "s3c2410-lcd"," k' u' e) I; b
.owner = THIS_MODULE,4 t9 i9 _/ N3 T# Z/ F
},; j1 {# K. {, p2 z* m7 U" e: v
};; ~7 _; e H% c7 s% H. c* F
这里看到s3c2410fb_driver的name字段为s3c2410-lcd。回顾这钱前面章节说过的知识,如果linux系统中存在同名的平台设备时,就会调用平台驱动的probe函数。这里,如果存在有同名"s3c2410-lcd"的平台设备,就会调用s3c2410fb_driver的s3c2410fb_probe函数。
5 O8 H0 j% P, U) G: F# m在source insight搜索s3c2410-lcd,很快就能搜索到arch/ARM/plat-s3c24xx/devs.c中有那么一段4 ~$ B5 x Q; j- {0 N
' m" k2 A# J& [8 l% a
/ [2 J k7 t. ]+ f- }/ f; {3 r2 S; u
struct platform_device s3c_device_lcd = {4 y+ H0 V1 b% _ y' h* s
.name = "s3c2410-lcd",
) U0 ^% H+ u! T4 M8 ]4 y .id = -1,4 a7 f/ Y- v. ~9 B
.num_resources = ARRAY_SIZE(s3c_lcd_resource),% K- w- _! V8 s$ T k! ?
.resource = s3c_lcd_resource,
3 m- p( ]0 g) l' f .dev = {: E, V. R( K- B; a' f
.dma_mask = &s3c_device_lcd_dmamask,4 b/ {5 C0 Z \9 ~+ |6 x; _8 t
.coherent_dma_mask = 0xffffffffUL: I& X7 E4 }$ T+ B& m o1 e
}
' w; a/ L% e0 b. M};
$ N7 f$ `/ B! a% q# d# _
: d2 k1 U4 U# T; ]8 BEXPORT_SYMBOL(s3c_device_lcd);
! ~7 d6 b1 Z% c" D9 w: N. M7 x1 F其中平台设备中比较重要的是成员是resource,这里是s3c_lcd_resource
5 a8 G% S5 \5 A
+ d5 J# M) M+ Y; c1 k% pstatic struct resource s3c_lcd_resource[] = {
5 z2 i! b) L" m7 I: S [0] = {
! h" L- x" \0 f7 D. a .start = S3C24XX_PA_LCD, /* 0x4D000000 */
% F( J7 Z; N: @% F7 V; _ .end = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,
* |, q& u8 w8 m2 @ y7 ~% H" } .flags = IORESOURCE_MEM,4 t7 i r {, w
}, f5 H- z% C6 \+ t& w
[1] = {4 Q) x( j' q R
.start = IRQ_LCD, /* IRQ = 32 */
l1 p7 w- f7 k* e5 q .end = IRQ_LCD,
: u$ k5 c% c# K0 J$ H .flags = IORESOURCE_IRQ,
* T! N$ P, {9 {' N, P }
; a k, E' E$ G$ W* |
0 q6 Z7 `6 X* j! v7 g/ z. D. o};9 ?, n( I( E4 I6 F
9 D- w: s4 z' D7 R2 H
static u64 s3c_device_lcd_dmamask = 0xffffffffUL;
( m+ G( @2 U/ d& h! B那么接下来当然是要分析probe函数了! _+ F6 f- F X9 l
& D8 k! O! E* C) ]
static int __init s3c2410fb_probe(struct platform_device *pdev)' |/ P& ]/ _7 K' L* E- B
{
0 g, T7 p3 d& T i, P9 a7 n return s3c24xxfb_probe(pdev, DRV_S3C2410);, E0 T& _! M; ?' [* @
}
! G0 M8 C* D. g& Z* x& h' J$ ls3c2410fb_probe函数调用s3c24xxfb_probe函数,这是lcd驱动的关键函数之一,留到"linux lcd设备驱动剖析二"再分析,但是在分析这个函数前,需要来熟悉一下几个结构体。% a7 Z' D- s+ E: f, C1 O
linux lcd驱动中有个关键词叫帧缓冲,它是linux为显示设备提供的一个接口,它允许应用程序在图形模式下直接对显示缓冲区进行读写操作,用户不必关心物理显示缓冲区的具体位置及存放方式,这些都由帧缓冲设备驱动本身来完成。
1 \0 ~% q B$ z! v- u+ N1 B: Q5 n9 ]7 r; Z
帧缓冲设备为标准字符设备,主设备号为29,对应/dev/fbn 设备文件,帧缓冲设备最关键的一个数据结构是fb_info结构体,它包括了关于帧缓冲设备属性和操作的完整描述。. v5 T* ]6 S/ ^. c
2 r7 n: E' O* S2 J
struct fb_info {% y; j0 _7 Q: B3 y; ?+ i9 F* u
int node; //用作次设备号索引/ k; D8 j$ o- R) a8 i
int flags;5 q1 ~# T. O9 X" i7 U# V
struct mutex lock; //用于open/release/ioctl函数的锁5 s+ n* w8 W: a/ Y' }+ d
struct fb_var_screeninfo var; //可变参数,重点
p" U5 |) @" E# S# j, ] struct fb_fix_screeninfo fix; //固定参数,重点
# x6 I% [# d; D6 H0 `4 {. k struct fb_monspecs monspecs; //显示器标准
* F" v. z9 {7 P c struct work_struct queue; //帧缓冲区队列( Y6 k' X, `0 u* y0 P4 N$ m
struct fb_pixmap pixmap; //图像硬件映射
9 _( l. q; q, Y; U( g struct fb_pixmap sprite; //光标硬件映射) g. |0 q% S. a: d
struct fb_cmap cmap; //当前颜色表8 K* R2 d `; @6 f! f$ j" r
struct list_head modelist; //模式链表9 T) ?. t, R d
struct fb_videomode *mode; //当前video模式9 v$ X/ w3 v9 Y6 x% F: w% o# `* K( {
: N! a2 S6 _& |5 E1 g) f8 [ char __iomem *screen_base; //显存基地址* [. N$ n6 }' W: V: l' K" {7 d
unsigned long screen_size; //显存大小- t5 [8 r }* t+ z+ c n: _
void *pseudo_palette; //伪16色颜色表$ X. e6 @1 @' ~' [/ \. _3 U
#define FBINFO_STATE_RUNNING 0+ R( L) m. ]. m5 b
#define FBINFO_STATE_SUSPENDED 1
$ h. X1 ^* j0 N" A u32 state; //硬件状态,如挂起
, g/ g# o9 ?& v0 F; F# B4 ~ void *fbcon_par; //用作私有数据区
7 U+ y9 y3 L. F! ]* d void *par; //info->par指向了额外多申请内存空间的首地址9 X5 @8 O9 S2 ^4 Q
};
( C5 V ^( m7 x; ~s3c2410fb_info结构体,这是s3c2410抽像出来的特有信息
& ]# _" ]7 I9 p' {" z" k5 y5 {% |$ ~1 b8 B9 G: N
struct s3c2410fb_info {" r& v' u' ~) w. q% \; N& Y* P
struct device *dev; //设备$ {. Z1 S' s! X
struct clk *clk; //时钟
5 P5 u7 e( O) K) V3 g+ Q3 w3 X, R
struct resource *mem; //资源+ {! l: W0 g' l, X1 _$ P7 w$ x
void __iomem *io; //IO地址
2 g, u! A" h8 ^6 f6 T5 {; i8 d- Z void __iomem *irq_base; //IRQ基数
: m; o7 u, h W; j+ W+ A3 R( `- q. ~+ J0 |
enum s3c_drv_type drv_type; //驱动类型,S3C2410或S3C24125 `# ?& V8 Z, p& c( C+ u
struct s3c2410fb_hw regs; //s3c2410 lcd硬件寄存器* U9 k9 ^5 T) y% z
6 `7 w2 S& k: n$ a' _* c! s+ o unsigned int palette_ready; //调色板是否就绪标志位. o( K( H% ?0 I/ p" \3 [" ^* w
5 ^& |) ^7 W( z$ x3 z. ~) B( f
/* keep these registers in case we need to re-write palette */
+ m) ?# s6 T. b0 G u32 palette_buffer[256]; //调色板缓冲区) b2 G$ A" ~$ I( g
u32 pseudo_pal[16]; //伪颜色表# W5 U. V9 ]: k. J
};) O% v) e# h3 E6 n0 @" |
s3c2410fb_display结构体,关于LCD参数的描述,如分辨率,LCD类型,BPP等等$ G5 U6 z% z) i) e# S- k% R
6 o7 V2 i h6 {$ l9 Z# N
/* LCD description */3 P4 n. N' f# Y7 K4 {, E+ k
struct s3c2410fb_display {* ?0 `/ C' g6 \% B' r
/* LCD type */
% \2 p2 ?7 O( X: Q3 e9 \ unsigned type;
/ O( n- d9 B" `' K. b0 z9 K' [0 F# ]/ n$ @3 L' P4 p) t. t1 I
/* Screen size */4 z" @: h# _; D s; W
unsigned short width;# j* T, b+ t: I, u7 _+ ] N
unsigned short height;
0 ?( D) h2 Y( P3 ?! G5 m8 z; W: D2 p7 |5 }; _$ W& B
/* Screen info */, B! A& n- m9 e9 R" w' r
unsigned short xres;
4 f9 c1 G1 N F* P5 v1 d unsigned short yres;
4 p7 f& n5 g) A unsigned short bpp;& }+ N) a6 K$ E& g! L
+ @( }' q; O! _ unsigned pixclock; /* pixclock in picoseconds */
& G( h1 V3 i q& R unsigned setclkval; /* clkval */
6 T5 N% w0 Q% c1 M7 R unsigned short left_margin; /* value in pixels (TFT) or HCLKs (STN) */
2 s- ?" ?- R3 L8 l unsigned short right_margin; /* value in pixels (TFT) or HCLKs (STN) */
+ Y) }: A2 l' I8 P" a$ B unsigned short hsync_len; /* value in pixels (TFT) or HCLKs (STN) */
: p9 T: a: u5 `7 E) R unsigned short upper_margin; /* value in lines (TFT) or 0 (STN) */
2 W! X4 `9 A' c+ s unsigned short lower_margin; /* value in lines (TFT) or 0 (STN) */9 Y" n! ?6 E3 |& R% C8 B: J- s" H
unsigned short vsync_len; /* value in lines (TFT) or 0 (STN) */
; o2 C& @% _2 S" q5 v: R$ o# D; u
/* lcd configuration registers */0 u7 v+ z) C! R" o1 l
unsigned long lcdcon5;
\0 B. Y7 P' y" h& W};
1 C6 X- r7 r7 q* F" f) s* C! C* H1 }对于TQ2440的液晶屏实例为tq2440_lcd_cfg,为方便查阅这里省略了其他分辨率的参数设置1 i* z1 y \4 n3 K
3 I4 i; e0 v( n* y/* LCD driver info */# V+ `7 x8 s8 E6 d
static struct s3c2410fb_display tq2440_lcd_cfg __initdata = {
{% v. E4 Y. Q0 _# X+ T .lcdcon5 = S3C2410_LCDCON5_FRM565 |! \2 R: X5 W' q6 w) m
S3C2410_LCDCON5_INVVLINE |
' z7 _% }2 T+ @# h/ k S3C2410_LCDCON5_INVVFRAME |! T: p# j; @1 u- p t
S3C2410_LCDCON5_PWREN |
( f+ x& `! n# W6 h& v S3C2410_LCDCON5_HWSWP,
. l# V6 W9 N# W& |8 C$ L2 J .type = S3C2410_LCDCON1_TFT,* w- w4 u: p! Z: f6 r
/* TQ2440的液晶是4.3寸的,分辨率是480*272 */
, ~6 C1 u# F2 M$ Y5 r& c% v" t+ R#elif defined(CONFIG_FB_S3C24X0_TFT480272) /* config_EmbedSky_W43:CONFIG_FB_S3C24X0_TFT480272=y */5 N4 J" g0 U! l/ U7 A& W7 m
.width = 480,
9 K0 p) Q+ U& D8 m, \, C5 j+ l .height = 272, J ]! [2 F& ]: S, S$ p' E
3 k2 E2 p# |, q- P
.pixclock = 40000, /* HCLK 100 MHz, divisor 1 */
& x. P6 k3 o+ @8 z: q .setclkval = 0x4,) A) g A3 l/ I+ q. ~2 s
.xres = 480,
1 n2 \$ P9 Z9 _# N0 ` .yres = 272,; u2 j# T# U8 c, O) I, v9 Z
.bpp = 16,' ?' l4 O% \( U$ b) q) e. W, K) S. O
.left_margin = 19, /* for HFPD*/
8 Q4 Q, H; @7 N5 k6 Y' P .right_margin = 10, /* for HBPD*/% m2 h. z" P9 w7 a) @+ f, j, I
.hsync_len = 30, /* for HSPW*/3 g. ^; f2 J: v5 h9 C1 G; Z
.upper_margin = 4, /* for VFPD*/
5 h& I2 \1 S3 W7 V$ d& O' s3 U( ` .lower_margin = 2, /* for VBPD*/
2 e" U. b( I+ z' N4 } .vsync_len = 8, /* for VSPW*/
% j) Z' f _1 x- S7 X};
6 A( H3 y# j$ E$ g1 C# N1 V+ is3c2410fb_mach_info结构体,它包括了s3c2410fb_display结构体
( E. H' V M: q% b" ~
$ t9 u" @0 C! m* jstruct s3c2410fb_mach_info {
; c" J( H4 A0 J5 C- ^' ?. o struct s3c2410fb_display *displays; //s3c2410fb_display结构体6 o. ]/ y: F- q/ J3 L, y8 Z4 J4 Q
unsigned num_displays; //displays的个数
6 c K0 r8 j! n# ^9 G# X: i5 | unsigned default_display; //默认的default_display个数
) y* l$ q8 s7 F; M" F& S! L; K8 o2 f/ J5 e* b
/* GPIOs */% D7 U2 }' s/ F; o5 y6 l9 i
unsigned long gpcup; //GPC
- y) v p' X2 T) z unsigned long gpcup_mask;) Q e" ^* P* M: l! }. o! h7 O$ [
unsigned long gpccon;3 j+ |3 g# A4 u. m
unsigned long gpccon_mask;. b( m* I5 X- m/ Y9 a! j" J
unsigned long gpdup; //GPD
* d$ ~6 y0 U) E3 t; y7 {$ Q; x unsigned long gpdup_mask;
% D1 F5 _; F4 _+ K( m unsigned long gpdcon;
8 `4 I; ~+ y; m unsigned long gpdcon_mask;# Y0 q/ K. k- O7 n. W
2 {6 s$ n/ A1 z' Z- o9 k1 V
/* lpc3600 control register */* ]9 @; X7 x0 E# z) ~
unsigned long lpcsel;
& a3 g! T" |/ V5 w};6 U7 _. @- |6 I! T# W3 j
1 g6 R6 t( w3 p' X R
" d. W A; y' v* {5 b( X |
|