EDA365电子论坛网

标题: S3C2440 Linux驱动移植——NAND驱动 [打印本页]

作者: mutougeda    时间: 2020-6-3 11:01
标题: S3C2440 Linux驱动移植——NAND驱动
开发板:TQ2440
+ J  u1 S  Y! f3 e; d: G$ o
: k1 y' ]. h( @; ~' {( `# S内核:Linux 2.6.32
4 v& n" p% ^0 n+ O
6 E- ?( ?( W; H9 OPC OS:Ubuntu 11.046 l" k# [' b1 Q% ~( y6 }
& n* z0 ~$ R. B) V! W
2 K$ r9 O% c0 b+ K# I  M: p  R
% w* F  |% J. p1 F- l( x
   本文将对NAND驱动的移植进行简单介绍。其中,将对NAND控制器所需要的参数进行详细说明。$ R/ {9 T- @6 _& H  t' P; U

; s5 p/ [" Z' f2 Y& U+ @/ _1 s1.  修改分区表
5 ^! X& J3 w8 _5 h. c0 H1 ^, q5 Z7 p0 l
打开文件arch/arm/plat-s3c24xx/common-smdk.c,修改mtd_partition结构体数组。
* _5 Q5 T& ^1 C
, D' E0 H$ T# A2 i  P修改后如下:
+ [" e$ t* S$ D2 f- t. e! |, W' ?  s% {7 c0 |5 ]
static struct mtd_partition smdk_default_nand_part[] = {
' Q2 p$ n9 W! K4 }        [0] = {
, f' E/ ]0 r! z/ D9 ^                .name        = "Uboot",+ l, ]# S2 g' }+ E" G% m; f6 T
                .size        = 0x00040000,: p( T4 C" ]# T: s
                .offset        = 0x00000000,, y2 G& t! c( k7 j( u
        },
5 G. \9 N% J( l" L2 D6 g% K        [1] = {
# U$ w5 W3 N& p) O, F" _1 A                .name        = "Kernel",* E5 j7 W2 S+ M! r  k- R8 x# [  m
                .offset = 0x00200000,' r5 f+ H) `  K6 ?* F; H
                .size        = 0x00300000,
$ F8 M* I! [7 {- d0 y        },
$ N1 s$ }9 p. G  |  W) w5 G        [2] = {
+ P& h2 @0 D3 I                .name        = "filesystem",
- ^0 [3 E% ]* e- e* O% a                .offset = 0x00500000,
4 |* ^, B# Z4 p: h                .size        = MTDPART_SIZ_FULL,2 ?( C5 S+ h  ^- }4 D+ X
        }
4 Q" ]( t4 _; I; c% ?, c) y, O};
* J! t8 c* ~# C+ m8 Z$ r
0 P  ?2 L$ k8 N! m* D7 N$ p1 N0 n) J" w) m8 Z! q3 S7 \, T
TQ2440板上的NAND为256M,请根据你的NAND实际大小分配空间。! z" k( a! B8 b) j

6 }6 g3 B6 `! a) a$ o6 z% _0 `3 Z7 h! |; J' e$ F' G/ @

, i, ?' Q7 _# K4 C4 k2. 修改NAND控制器参数$ }% b5 d: F; ~! ^4 j

6 b( z/ L$ ^* S# k打开文件arch/arm/plat-s3c24xx/common-smdk.c,修改smdk_nand_info结构体。
1 W" c. _: ]4 W& g; C) r% v* k* v* t
; [" C- h+ I% ~* [4 s修改后如下:
% q3 [+ V& Q% W9 p0 f+ k
9 S& }4 B( P5 Z; B0 Estatic struct s3c2410_platform_nand smdk_nand_info = {8 a6 H4 p( ~+ v; @3 M
        .tacls                = 0, //10,//20,
4 V0 H* Z0 I/ t# s* E        .twrph0                = 21, //25,//60,
$ I# \9 O, s/ X3 K% v8 e        .twrph1                = 5, //10,//20,. y- B: I4 V: Z3 J- [* K9 h2 }
        .nr_sets        = ARRAY_SIZE(smdk_nand_sets),
2 o/ [. T, _3 E& _+ i6 a# R0 G        .sets                = smdk_nand_sets,4 H, z. d( ^; |- i
};7 o/ B9 O" x2 z1 ?. ~" I
% d2 m( [' r& b  C7 R
这里的三个参数tacls,twrph0,和twrph1是如何给出的? 我们来分析下。; W- U5 n/ u/ B! |! x

+ r* J- m+ h/ P/ n0 x先看下这个结构体的定义,位于arch/arm/mach-s3c2410/include/mach/nand.h:" o: y. K4 I8 h  e3 x

7 ^% F7 Y- T' b+ `+ ?struct s3c2410_platform_nand {
  L; B( o1 e) e: C5 S        /* timing information for controller, all times in nanoseconds */
) {. E% B1 [5 k" I
( R4 J' ]/ y# [& d, }        int        tacls;        /* time for active CLE/ALE to nWE/nOE */4 r& R/ v0 i+ g* V
        int        twrph0;        /* active time for nWE/nOE */
2 N6 t* r/ s- u' ]2 M        int        twrph1;        /* time for release CLE/ALE from nWE/nOE inactive */
$ v' D4 M1 I$ i* k) {, D
* n3 K( C8 H5 e7 r- S        unsigned int        ignore_unset_ecc:1;' v+ @! R4 G' e- R7 u1 M9 O; v' ]
* s% K3 c, k$ s8 q* {5 p8 |
        int                        nr_sets;9 I& W# y% @7 F" u
        struct s3c2410_nand_set *sets;
+ \8 `0 t) L0 l0 T) a  ]
9 K: y" f6 E1 N; W+ e        void                        (*select_chip)(struct s3c2410_nand_set *,
8 ?. N- Q# G3 X, H                                               int chip);
3 ?* ]& a% g6 J  X' h) n: b};
8 }" x) _) w6 B1 }0 p4 k
8 [7 e6 _* X$ l* [! ?4 h7 [/ M* i看到了对这三个参数的说明,这里提到了这三个参数的单位为纳秒,请注意。
* t% @# Y6 Y' T0 S4 J6 Q% d
. M. j; e4 ?2 C4 N" @& A/ P0 v那么这三个参数到底从哪来的呢? 它来自于S3C2440 nand 控制器的NFCONF控制器,如下:8 I/ P& q: l0 a+ q* F4 o
  x9 G. \. g- G7 \3 V( L

$ W; j# I, y9 v5 f
% X# `5 p$ b7 i' Z! W7 ~( I- s
4 ~& ?! x. T& k' @; b6 A( u$ ]2 ^  G, m5 N
既然找到这三个参数的出处了,那么它们究竟是何含义呢?我们里看下:+ F/ @9 Q5 H5 ^$ n+ d" X4 |' d9 `& I

6 Q: E+ Y& l" _# g* m6 Z& R6 b ) t7 ^- r; v  @4 _

+ x/ _" z$ V" w/ t$ @, [5 }& h9 ^' V8 g2 ?. `7 r7 \
/ u5 _- X) u+ J. ?1 ~5 V
这幅时序图同样来自S3C2440的datasheet。. X8 `8 m% }5 s+ h2 D3 O

3 p8 m" o5 J. V通过这幅图和struct s3c2410_platform_nand中的注释,我们可以对这3个参数做出如下定义。
3 Y' E: j# f# r' b- e' b5 B9 z' L& r% p( f9 `
TACLS:表示在CLE/ALE拉高后,多少时间以后才允许将nWE拉低。
$ g7 c' b3 g+ a& {( X/ u1 B3 s2 \
TWRPH0:表示nWE低电平持续的时间。0 {* ^  H& P% P( e. P
" _2 [1 A3 [) J7 a6 `! X' ^. ?
TWRPH1:表示nWE变为高电平后,多少时间后允许CLE/ALE拉低。2 e  r- o5 y9 ]! g  U" c+ }

7 ^& ]% G; F0 A* l知道参数的意义后,我们来看下NAND芯片K9F1208U0C的datasheet来确定这3个参数的值。
4 n  [' O+ Q) V" |3 L# X0 O; F# M1 U. d/ }; y# t6 h8 f

) V( ^7 r1 }+ W; z' c0 m( w4 C7 q; e  l' h" s

& c- `& `( `6 ]# ~9 j
: O- W. {* U+ O: l- o从这个时序图,我们可以直观地看到twp对应着参数twrph0,而tclh对于着参数twrph1。
% [: d2 U5 n" E+ y  o8 [, c9 v( f" i+ n/ A+ @- S
但是tacls如何得出呢?从图中并不能直接得出该参数的值,需要转个弯,那就是将tcls减去twp,就可以得到tacls了。
7 H, M' a+ I' Y& q, h0 W$ X, B+ a6 B4 C# W9 R
综上所述,为了得到nand控制器所需的3个参数,我们需要获得该nand芯片的3个时序参数:twp,tcls和tclh。
6 Q+ ]* u/ \5 A. P8 j0 |4 k5 {+ h7 D0 a1 `: I
通过查找该nand的datasheet,3个时序参数的值如下:
. p3 n, E* P. b3 X' q0 `
2 J1 t8 O, a; B/ p/ c; b" x2 dtwp=21, tcls=21, tclh=5。
& j% [0 Q3 d) w' X/ _, K* H1 b" X7 ^9 C* i0 u1 F
将这3个时序参数转为我们需要的3个参数,单位为纳秒(ns):
$ S% K" e3 D2 ], r
/ A9 i  ~8 ^9 N8 ~* S# etacls = tcls-twp = 21 - 21 = 0 ns
$ r. I: J$ B  b4 r8 y/ R* G5 i7 p+ Q; d$ Z6 D' T0 J3 J
twrph0= twp = 21 ns& e7 C8 V3 F. S
0 y6 [9 |$ X; _
twrph1 = tclh = 5 ns0 I9 a/ q* ^8 y; i: N& I: e; N* o$ j4 Y

% t! F8 _. B6 t  _3 z, c; Z5 \至此,就成功计算出三个参数的值了 。+ p! [% F) @6 U* V+ c
1 T- T: `7 b$ _+ C2 a6 e- ?1 E
3. 配置内核
, m! Z# f/ A1 X8 O4 }! K% H. Q5 r: q' R

+ o, Z2 w& \' k8 }; V) s8 B$ J) @# Q* m8 A! Z% G  T2 x
. G. H( g$ ^2 b. B8 }3 ~5 b+ v. d
* }1 E5 i3 n3 {' \2 j+ H( C
4. 验证
% |7 w9 r% i4 H1 d0 x
! K& o/ n! }) b  在经过上述步骤后,编译内核并将内核少入nand,启动系统。在Linux的启动信息中,会有如下输出:
0 O4 n7 K+ R; I
+ {8 ?- A2 |7 F......) k5 h) x" R% V# A1 K4 V( e
" O( X2 _1 a  ^/ A, L" S+ I
S3C24XX NAND Driver, (c) 2004 Simtec Electronics
! W& E1 [( `- q5 o8 Ms3c24xx-nand s3c2440-nand: Tacls=1, 10ns Twrph0=3 30ns, Twrph1=1 10ns
  ^6 h8 @) Y4 z! U) Ts3c24xx-nand s3c2440-nand: NAND hardware ECC
4 A8 P" J, L+ e) Q( i- m4 j6 fNAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)
; P6 {* j6 p9 L- nScanning device for bad blocks6 e( O  i# b3 z, T1 E+ h9 E
Bad eraseblock 781 at 0x0000061a0000
& K0 X  U: a$ f1 rBad eraseblock 1113 at 0x000008b20000$ d  `- N7 w) W5 E  N
Bad eraseblock 1117 at 0x000008ba0000
, J, G: l. }$ J/ vBad eraseblock 1481 at 0x00000b920000
" z+ g5 j( m7 g' q/ F; S3 T8 `! M  mBad eraseblock 1566 at 0x00000c3c0000
* F! ^& U" I/ r: vBad eraseblock 1885 at 0x00000eba0000
( R: P$ E2 m" N+ kCreating 3 MTD partitions on "NAND 256MiB 3,3V 8-bit":
: h! u+ v! O! \/ i: ?; x/ b0x000000000000-0x000000040000 : "Uboot"6 ?4 d' ^( t# b- G; x1 Q+ v
0x000000200000-0x000000500000 : "Kernel"9 m6 k6 U9 v+ ]
0x000000500000-0x000010000000 : "filesystem". D9 t2 X; E0 h. R+ V3 l/ v
6 Q/ w8 ?8 W& r1 r- d8 s
......# d, F0 N9 z$ q) M% s6 U- ]

& |4 m; g8 {/ v* \. T6 y  M上述信息表明以成功访问了NAND FLASH。0 p; f3 j6 j( x2 O* f
) e( @! \* D6 j) j/ w
这里,对第二行的输出进行个说明。2 [) f4 ~: P/ @# e5 Y$ u

, e& H5 C4 m" o6 |7 bUBOOT启动将S3C2440的工作频率 FCLK:HCLK: PCLK = 8:4 :1,
* ~3 ?2 o- G5 t5 L' T2 Z6 ^
7 Q( T3 }! W0 e  Y而FCLK为400Mhz,那么HCLK为100Mhz,根据NFCONF寄存器的说明,寄存器中的这3个参数都跟HCLK有关,必须为1/HCLK的倍数,, u$ G) Q, r! [" D- i

2 c& y) k. G: v! M6 c/ ^4 c也就是1/100MHz=10ns的倍数。. [3 {$ d% S, r; i

0 w4 Z7 d4 x( j5 w; a通过上面第二行的输出信息,Twrph0为 30ns而Twrph1为10ns,这是显而意见的。
7 Q, b% l: E' S! O
1 k! B; G; ^' }; O/ w# U& t3 {由于参数必须为10ns的倍数,而且必须大于datasheet给出的值,因此向上取到10的倍数,也即5ns取到10ns,21ns取到30ns。
8 T2 Y, [, O8 p3 Y; u; V( ~' q$ o8 t( A- R2 O
那么为什么Tacls是10ns呢?明明给出的是0ns,是不是驱动不允许参数为0ns?4 O* z$ u9 x8 L, }

7 e9 r5 r& B- h0 M1 d在S3C2440的nand驱动中,参数的值是通过如下函数确定的:
5 o8 A$ ]4 ^8 f. o5 A) p4 n7 E8 B1 [/ z
static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)
/ h5 C/ }2 }. n, q, R6 B9 M, p{
: l6 N& f  a( B3 b        int result;
* g4 A5 N5 v$ f  B8 M) c2 j
; C1 b7 }: |0 V: _        result = DIV_ROUND_UP((wanted * clk), NS_IN_KHZ);
3 i% I# ]8 W1 Y( e- n6 e* v( f0 Y; h8 W5 c: q0 K. D2 Z, c7 R
        pr_debug("result %d from %ld, %d\n", result, clk, wanted);4 I7 c! q, B( u! L( ^

% T% [6 Z9 P& _/ N        if (result > max) {
+ L6 R2 X' {/ b' r# o# b- ]                printk("%d ns is too big for current clock rate %ld\n", wanted, clk);
/ |9 _3 N6 j% c                return -1;; u; s( y1 t  J* U7 A: C
        }
1 g( M9 t8 u  ]8 T" S# n( T3 f0 _' y, A# Z" V+ l
        if (result < 1)' s& n2 C( R; w( D
                result = 1;
0 M$ r# K- {5 `; |2 K' }! T( n+ q6 @7 s' N5 E0 k- h8 w) e
        return result;
) @( d1 J) V" j6 _* S( {}  S- e8 ]. q/ {8 B) a( d

, ?, a6 ^3 n- b" Y# z参数wanted就是0(ns),而clk即为HCLK/1000。! x: ~2 X+ }+ s, g" l, y2 _7 X  Z
, P4 a8 Z: X! o6 V. b
DIV_ROUND_UP宏将返回0,但是if对result进行了限制,也就是不允许小于0,因此将参数值设置为1,并返回给调用函数。# ^& y% d, Y& z

4 F3 K. E7 K- L; `5 o' b  T* k  `( t' I7 }3 {% g* s/ h; X# o8 }4 l

1 s' E7 w/ Y* s$ v7 q$ S& d$ J8 t, z& w
+ o! N6 B: d( c

- E7 j! I  H1 c5 ~$ X9 u! O/ N( x% n' ^3 t- G" H
6 x2 f) Q$ \5 V3 r$ u1 i- ^7 F
/ A  D6 G2 X, d) `. z3 p, [9 j0 u

作者: ExxNEN    时间: 2020-6-3 13:12
NAND驱动




欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/) Powered by Discuz! X3.2