TA的每日心情 | 怒 2019-11-20 15:22 |
|---|
签到天数: 2 天 [LV.1]初来乍到
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
s3c2440 lcd驱动源码文件是:drivers/video/s3c2410fb.c! [5 G! l# x( V
3 o( P1 r A# A4 c! F/ y' i
看驱动源码首先当然是先看入口函数,这里是s3c2410fb_init函数3 F9 `$ @3 Y& ]" Y
' |0 H( w8 V% B0 Q; i7 E9 C7 w7 F
+ e( @; W" L) o/ e- `5 s j6 oint __init s3c2410fb_init(void)
, ^' |1 t( @* u- z{8 Z& H. Z: @; L1 q' m
/* 注册一个s3c2410fb_driver平台驱动 */8 u: C2 i/ ^5 T8 d @
int ret = platform_driver_register(&s3c2410fb_driver);
; G- C7 H5 U* l) u- ^2 o. { y3 g8 i
if (ret == 0)
% @, p8 D4 O: W/ h2 Q5 j ret = platform_driver_register(&s3c2412fb_driver);;" W& T# {; e, F$ Z) q' i4 h
8 _- S4 V/ }" P3 N: S; \* U4 [
return ret;4 }2 l8 g# _ T* _6 c# ~& k
}
* W1 e; }; ^! q出口函数,自然是注销s3c2410fb_driver平台驱动9 Y( v9 O$ S5 Y2 [. N8 C' J+ w7 G
6 _4 G; R; q6 W4 ^static void __exit s3c2410fb_cleanup(void)
5 O+ u" \% g# e9 Z1 H) T{
) T0 t$ Q& u5 I# J' Q. i platform_driver_unregister(&s3c2410fb_driver);
; |' h& ~% h2 D& O platform_driver_unregister(&s3c2412fb_driver); t3 g+ p) |4 U! ~% n: n
}5 a& a6 l" I0 ^
我们研究的是s3c2440,只关心s3c2410fb_driver,s3c2412fb_driver不用理会。
: ]2 L- k3 w( l+ d' r, q( f; R! s; O* l* O) c' E
static struct platform_driver s3c2410fb_driver = {8 }' @. N, d8 C" M5 j- j& \' k
.probe = s3c2410fb_probe,
- g& x5 l. _: B7 |; P i$ a .remove = s3c2410fb_remove,
1 u( @. Y8 }3 Y .suspend = s3c2410fb_suspend,, q0 v$ o8 [, s: {# ?
.resume = s3c2410fb_resume,$ Y: n9 t! s" J2 R- ~
.driver = {
# P$ W6 c# ], a2 v9 G! W .name = "s3c2410-lcd",
' v; G4 _3 t4 |$ Q9 S2 v# _ .owner = THIS_MODULE,0 z! _+ I7 P2 Z, C
},% f0 _! d$ f; b
};
1 l3 ^% g+ u5 j0 ~$ a9 V这里看到s3c2410fb_driver的name字段为s3c2410-lcd。回顾这钱前面章节说过的知识,如果linux系统中存在同名的平台设备时,就会调用平台驱动的probe函数。这里,如果存在有同名"s3c2410-lcd"的平台设备,就会调用s3c2410fb_driver的s3c2410fb_probe函数。
7 o' Q. t5 D+ U" C) I% Z2 z0 T在source insight搜索s3c2410-lcd,很快就能搜索到arch/ARM/plat-s3c24xx/devs.c中有那么一段) {: w7 T3 W$ |) a7 ~8 s% b& D: C
- x) h% _( t1 h: d1 J$ }9 I
) l' u3 B# }$ q$ B# @& Dstruct platform_device s3c_device_lcd = {
x9 @! R! u( t5 E4 X q .name = "s3c2410-lcd",( L" t @# b- u- v8 d$ f+ {
.id = -1,) o* E. R1 M( ^" g. v
.num_resources = ARRAY_SIZE(s3c_lcd_resource),3 \5 e0 v, \1 C( Q, \! x" K
.resource = s3c_lcd_resource,7 a( `) N1 I- v: g
.dev = {3 O# [8 g2 m, ]2 b" [4 a- D
.dma_mask = &s3c_device_lcd_dmamask,
# i; J9 d `+ ?. }, t .coherent_dma_mask = 0xffffffffUL
$ X1 c# R" r: Y; c" x }
0 E, o: g8 O' S5 ~' R};
2 t9 Q8 a2 j# l6 m
( J2 G" q; q0 m3 k9 eEXPORT_SYMBOL(s3c_device_lcd);
- I' a1 \( F+ v" u0 m* i4 ?9 {; \其中平台设备中比较重要的是成员是resource,这里是s3c_lcd_resource
7 y8 K8 Z/ L! M: d' w9 ]- [; f4 l. W$ S5 e9 B. A$ J) U& i
static struct resource s3c_lcd_resource[] = {2 A( g( u9 w; z: e
[0] = {
' h* \9 b: x+ X$ t& S .start = S3C24XX_PA_LCD, /* 0x4D000000 */
- r' d+ C0 e! i: n% @1 e# } .end = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,+ i8 {. |. Q, J* J! s
.flags = IORESOURCE_MEM," |" C- m( i9 Y& F4 x; ]
},3 P! Z# W8 u& z. p
[1] = { |2 l# q! r# @7 D. T
.start = IRQ_LCD, /* IRQ = 32 */5 C3 @& z4 }* @
.end = IRQ_LCD," E/ c, w4 i: p) {
.flags = IORESOURCE_IRQ,2 `# B" O+ H' w
}) g( {: r0 T% V5 t7 q- g8 S
' Z$ U: q- M) ~6 U% K5 a
};0 u6 Z& s4 [, Y' ^8 n4 l
# ~& M/ V, M& R5 o
static u64 s3c_device_lcd_dmamask = 0xffffffffUL;
7 ~( f5 `: w; p0 K8 a$ m. j那么接下来当然是要分析probe函数了 ^ o* j! j- }% J( {
( N. f4 R& ~$ F
static int __init s3c2410fb_probe(struct platform_device *pdev)- }; }, I* J3 P, D
{8 B, a, {2 `& t+ v! y0 G6 ]% [, u1 D
return s3c24xxfb_probe(pdev, DRV_S3C2410);1 C( | r6 {# L
}
% w0 z, n5 c2 m7 k# T* t4 t9 h7 os3c2410fb_probe函数调用s3c24xxfb_probe函数,这是lcd驱动的关键函数之一,留到"linux lcd设备驱动剖析二"再分析,但是在分析这个函数前,需要来熟悉一下几个结构体。, a6 l# l' D3 ^- A- t% a( o
linux lcd驱动中有个关键词叫帧缓冲,它是linux为显示设备提供的一个接口,它允许应用程序在图形模式下直接对显示缓冲区进行读写操作,用户不必关心物理显示缓冲区的具体位置及存放方式,这些都由帧缓冲设备驱动本身来完成。: O: e# d9 f/ c( i
+ F8 B" \- K* c0 m8 C
帧缓冲设备为标准字符设备,主设备号为29,对应/dev/fbn 设备文件,帧缓冲设备最关键的一个数据结构是fb_info结构体,它包括了关于帧缓冲设备属性和操作的完整描述。
1 W( I) o9 {5 J' D! E8 o! Z" p& ^
1 L9 G2 j7 Q: _! _7 u4 F+ Gstruct fb_info {
8 A/ [5 v2 L% z k& @ int node; //用作次设备号索引" y# X: N8 V$ S0 X6 Z; o h
int flags;# u, J. e& m7 _* M, I$ K% G
struct mutex lock; //用于open/release/ioctl函数的锁* c( P+ F: f7 _! ?: K( s7 S8 o
struct fb_var_screeninfo var; //可变参数,重点
6 u+ n1 z% S" N6 {' q/ E' M struct fb_fix_screeninfo fix; //固定参数,重点, \8 Q% r2 f! J
struct fb_monspecs monspecs; //显示器标准8 a. H5 c/ z9 k( ` ?! ^# D: ]9 m
struct work_struct queue; //帧缓冲区队列
- O! w+ s j) M& X( H struct fb_pixmap pixmap; //图像硬件映射: R. i G8 x) A; q& c
struct fb_pixmap sprite; //光标硬件映射
% A3 T4 ]0 l# d) A) X7 Y struct fb_cmap cmap; //当前颜色表
( r8 }: [$ ?1 l) i/ @7 i0 N struct list_head modelist; //模式链表: h/ J+ ?2 E4 k3 X+ g
struct fb_videomode *mode; //当前video模式
3 }" f( p# Y) c3 u/ k, |
1 K# d3 P/ [9 u4 [ char __iomem *screen_base; //显存基地址1 I& }, ^" N7 N: I
unsigned long screen_size; //显存大小; _6 s3 R5 [' B9 v" q
void *pseudo_palette; //伪16色颜色表
9 E) e, C' y5 |# Z7 i j Y( F#define FBINFO_STATE_RUNNING 0
( \1 a$ P6 r* J8 W#define FBINFO_STATE_SUSPENDED 1
U2 Y$ C1 N# d u32 state; //硬件状态,如挂起
, q m) t6 p9 |1 f0 i8 q void *fbcon_par; //用作私有数据区4 V9 i& e0 ?/ C
void *par; //info->par指向了额外多申请内存空间的首地址
; ]/ R1 ?- O0 c9 X" N- K};
; J; ^1 H( w% c; b0 Ps3c2410fb_info结构体,这是s3c2410抽像出来的特有信息5 Z4 r) s" w8 `+ U% j3 U( I# \2 P+ v
) a1 m1 Z1 Q; {
struct s3c2410fb_info {
: ?6 e) z2 D1 s$ d% x p struct device *dev; //设备! u; O- Z h: \
struct clk *clk; //时钟
5 ~- M$ z2 i0 X
" U( F# \! ?6 I" U struct resource *mem; //资源; Q2 P' Q7 R4 M9 d) d: L% I
void __iomem *io; //IO地址8 X9 g- T3 G, O
void __iomem *irq_base; //IRQ基数
3 I& d; K+ W2 b' @0 H
; T+ M' m1 A* T. z! e k5 E9 O6 J enum s3c_drv_type drv_type; //驱动类型,S3C2410或S3C24123 i0 K3 g3 t" P6 M
struct s3c2410fb_hw regs; //s3c2410 lcd硬件寄存器
. q/ b* r$ D( t- C+ G; H9 o: a) U, G3 q1 H. Y; U
unsigned int palette_ready; //调色板是否就绪标志位
7 E+ M+ F# B. x: K6 ]. A$ E. Q* C" m+ ^" ^. r7 Q$ \
/* keep these registers in case we need to re-write palette */
! e4 e0 l: F$ X V) Z u32 palette_buffer[256]; //调色板缓冲区# o/ w t4 Y* `4 @. g1 r
u32 pseudo_pal[16]; //伪颜色表
6 n) W4 s" K: r t};# h' D& V/ e$ j, D. V
s3c2410fb_display结构体,关于LCD参数的描述,如分辨率,LCD类型,BPP等等2 n5 ?, ^+ }% {( \; X& H
7 _( E! Q' p1 Z( h/* LCD description */
9 x6 Y( }3 D2 L( Tstruct s3c2410fb_display {% E+ ?. y6 k! A6 X% E7 K
/* LCD type */
2 o3 q8 P. P( y& T% @$ p- [- A% ~5 c unsigned type;
- T6 y/ P' p" z0 ~* P( L6 F7 P& S* w$ r6 L" [
/* Screen size */7 S4 }, Y1 d9 f& f" u5 m
unsigned short width;; }* f3 @2 S6 e/ Z) S
unsigned short height;
6 \) ~& ~- ~2 F1 W4 C7 O' Q- l7 k% \) U( v. z8 W+ e! `
/* Screen info */
! p6 _) t4 l R k1 R unsigned short xres;
, {6 s; _* \- T! U2 G: c unsigned short yres;
) ~& Z0 ?, n" T! e7 @9 g unsigned short bpp;, y/ Z0 Z$ W# S( \
1 }( w5 [5 b% ` e0 b8 G2 I unsigned pixclock; /* pixclock in picoseconds */
+ o. [5 ?2 x8 H( J9 X unsigned setclkval; /* clkval */# c- z/ l1 Q* @1 p" b
unsigned short left_margin; /* value in pixels (TFT) or HCLKs (STN) */& }3 T4 p3 m2 U1 W/ {
unsigned short right_margin; /* value in pixels (TFT) or HCLKs (STN) */2 F8 v7 X3 U: A8 M
unsigned short hsync_len; /* value in pixels (TFT) or HCLKs (STN) */8 w- O9 o# }1 u+ G
unsigned short upper_margin; /* value in lines (TFT) or 0 (STN) */
! h/ ^) j6 E T5 h; [5 m unsigned short lower_margin; /* value in lines (TFT) or 0 (STN) */
: r Q4 h7 k- q8 y unsigned short vsync_len; /* value in lines (TFT) or 0 (STN) */
: d! }3 T1 J1 T1 V0 F2 ]. D1 i3 l4 c6 l0 v& u) w
/* lcd configuration registers */
2 m4 i! w( t( t7 Y/ ~: h0 t unsigned long lcdcon5;
* x9 ^, F/ R# E* S};
# G) n* ]% S1 ?% Y s B4 a9 w对于TQ2440的液晶屏实例为tq2440_lcd_cfg,为方便查阅这里省略了其他分辨率的参数设置
. }! K8 z! l4 ]. T! M5 d+ `1 Q& ]) t% [( j* `& q- O
/* LCD driver info */; u7 K s: |6 Y) {" E; o% {
static struct s3c2410fb_display tq2440_lcd_cfg __initdata = {0 Q* `( R: h% g( t! n/ q
.lcdcon5 = S3C2410_LCDCON5_FRM565 |+ p+ i# g* o+ g- n9 {
S3C2410_LCDCON5_INVVLINE |$ U" ]6 j/ U* x+ D' e- A" O- L+ H
S3C2410_LCDCON5_INVVFRAME |
( E" F6 X5 N! v. R0 K S3C2410_LCDCON5_PWREN |
) q: z n& X# Q% u S3C2410_LCDCON5_HWSWP,
6 t( ~2 B3 G E7 U7 W# n .type = S3C2410_LCDCON1_TFT,
. h/ I6 ~. W: `& {4 y /* TQ2440的液晶是4.3寸的,分辨率是480*272 */# l. ^3 V7 i( e, q; g
#elif defined(CONFIG_FB_S3C24X0_TFT480272) /* config_EmbedSky_W43:CONFIG_FB_S3C24X0_TFT480272=y */
! F# B3 w: X8 @$ M .width = 480,
* v& h- U& q3 y) L" U1 D, c0 Y .height = 272,
1 l! x8 p6 b! f3 } v7 _. z0 K
: U4 L `9 G+ y* R4 y$ c .pixclock = 40000, /* HCLK 100 MHz, divisor 1 */
`1 x: O4 F/ e .setclkval = 0x4,
/ b1 b c$ R) t .xres = 480,8 [( ^ M' R* m
.yres = 272,
% T7 d# Q# R* i" o, i .bpp = 16,
2 ], z& N( t* ^# e .left_margin = 19, /* for HFPD*/5 L8 k0 a8 y9 j2 M, o" e
.right_margin = 10, /* for HBPD*/
- Z4 X3 u# B p8 s ?* b) ] { .hsync_len = 30, /* for HSPW*/! H1 _& f s% a* i! Q( Z9 T
.upper_margin = 4, /* for VFPD*/
/ ^+ K- B- Y$ L3 Z2 X# a: q .lower_margin = 2, /* for VBPD*/
4 J2 I. U# f' Z: U .vsync_len = 8, /* for VSPW*/! e' G* N6 T( u. I4 d; Y
};
2 u! n: M+ ?6 _5 ~4 B' b) Ks3c2410fb_mach_info结构体,它包括了s3c2410fb_display结构体. X* t1 S/ M/ i! t# C5 u: n% r
o3 U0 t6 U, {# astruct s3c2410fb_mach_info {& ~ R8 p0 U; Y
struct s3c2410fb_display *displays; //s3c2410fb_display结构体2 ^& z6 {. ~0 c0 C) ]# K, p
unsigned num_displays; //displays的个数
9 A% }# v, }: p& M( d6 q- K1 b* g unsigned default_display; //默认的default_display个数& W& O& z5 }- Q" E
4 Z$ m) c- Q2 J: s
/* GPIOs */) l% ^5 l4 [; P k: e
unsigned long gpcup; //GPC
- ]$ x# g m7 s* b Q1 g+ G unsigned long gpcup_mask;
& S# |; S5 @! H1 J' v- T unsigned long gpccon;3 ~8 ~2 @0 C8 J
unsigned long gpccon_mask;
+ l8 ^2 y, T5 Z: L unsigned long gpdup; //GPD C0 @7 u2 H7 e/ u
unsigned long gpdup_mask;
' L" K' O4 ]' w) M8 _, M# F& ]+ O unsigned long gpdcon;
' t% d& f6 s; b unsigned long gpdcon_mask;
4 {4 }, m. r3 V* }5 J1 i1 k, _) d5 }* s6 e9 p% u; ]# U
/* lpc3600 control register */
# t1 V4 p5 a1 a; H" N0 ? `* F) h unsigned long lpcsel;( s4 N( Q. ^1 E: m( o8 E3 v% ~) B/ p
};
- I N0 b3 q; D Q( b+ @8 W8 i5 Y4 q6 P2 {5 u# S$ m' u
2 }& W' E$ m( v) R! D6 K. e |
|