2008. 3. 26. 09:11
지친다..
내 시간은 절대적으로 모자르고
몸과 정신은 축날대로 축나고..
살아가는 방향이 점점 상실되는 듯 하다.
살아가는 데 필요한 에너지가 점점 고갈되어 간다.

누군가 내게 위로해주면 좋을텐데...
그 누군가 내게 말을 걸어 나를 바라봐 주면 좋을 텐데..
인생살이가 쉬울수룩 나는 점점 힘들어진다..
2008. 2. 26. 09:47
1. _vimrc

-----------------------------------------------------------------
"My Setting
source $VIMRUNTIME/../ephron_config.vim
source $VIMRUNTIME/../MyMapFunction.vim
source $VIMRUNTIME/../CustomFunction.vim
-----------------------------------------------------------------

2. ephron_config.vim
-----------------------------------------------------------------
set tags=./tags
set nu
set ci
set ai
set si

set sw=4
set ts=4
if has("gui_running")
        set lines=50
        set co=120
endif
"End of My Settings

"Customizing My Color Setting
colorscheme desert

"Customizing Plugin Setting
-----------------------------------------------------------------

3. CustomFunction.vim
-----------------------------------------------------------------
if version >= 500
func! GetTodayDate()
        exe "read !date/t|sed 's/-//g'"
endfunc
endif
-----------------------------------------------------------------

4. myMapFuction.vim
-----------------------------------------------------------------
map <F1> v]#ezf
map <F2> v]}zf
map <F3> zo
map <F9> a// EPHRON_<Esc>:call GetTodayDate()<CR> + kkkJxA
"map <F11> :25vs ./<CR>:set nonumber<CR>^Ww
map <F11> :WMToggle<cr>

"방향키 설정
-----------------------------------------------------------------
2007. 11. 16. 14:23

[ARM] Veneer code

OldPapers/linux 2007. 11. 16. 14:23

                                

Veneer에 대한 정의 입니다.

 

Veneer :  armlinker 생성하는 veneers 대한 세부 정보
            Linker ARM 코드와 Thumb 코드를 link 있고, 필요 자동적으로
            processor state 변경 하기 위한 interworking  veneer 생성하고, 필요한
            에 branch instruction range 확장하기 위해 long branch veneers 생성한다
               Arm linker Arm function Thumb state 호출되거나 Thumb function Arm
            state에서 호출되는 것  detect 있고, 필요 processor state 변경하
            기 위해 call return instruction 변경 하거나 veneers라고 불리는 작은 code
            section 삽입한다.
 
위에 정의된 내용만으로는 뭐하는건지 잘 모르겠죠.. 간단한 예를 들어보겠습니다.
 
다음과 같은 arm모드로 컴파일이된 arm.s 라는 소스가 있고 thumb 모드로 컴파일된 thumb.s 라는 소스가 있다고 하죠
둘다 컴파일 옵션에는 interwork 를 줘야 같이 동작할 수 가 있습니다.
 
 
      ; ******
      ; arm.s
      ; ******
      AREA       Arm,CODE,READONLY
      IMPORT    ThumbProg
      ENTRY
ARMProg
      MOV   r0,#1
      BL      ThumbProg
      MOV   r2,#3
 
      MOV   r0, #0x18
      LDR    r1, =0x20026
      SWI     0x123456
      END
 
 
     ; *******
     ; thumb.s
     ; ********
     AREA  Thumb,CODE,READONLY
 
     CODE16
     EXPORT ThumbProg
ThumbProg
     MOV r1, #2
     BX    lr
     END
 
 
위의 소스를 보면 arm모드로 컴파일되는 arm.s와 thumb모드로 컴파일되는  thumb.s 소스가 있습니다.
일반적으로 arm모드에서 thumb 모드의 코드로 branch하거나 thumb모드에서 arm모드로 branch할때는 BX 명령어가 사용됩니다.
하지만 arm.s 에서 보면 BL  ThumProg 로 Thumb코드인 ThumbProg 함수를 BL 로 호출 했습니다.
이럴 경우 링커는 자동으로 해당 부분에 Veneer 코드를 삽입하여 arm 모드에서 thumb모드로 변환할 수 있는 코드를 넣게 됩니다.
이런 코드를 Veneer 코드라고 하며 위의 소스를 컴파일 한후 disassemble한 코드로 살펴 보면 아래와 같습니다.
 
 
armsd: list 0x8000
ARMProg
            0x00008000: 0xe3a00001  .... : >   mov       r0,#1
            0x00008004: 0xeb000005  .... :      bl          $Ven$AT$$ThumbProg
            0x00008008: 0xe3a02003  . .. :      mov       r2,#3
            0x0000800c: 0xe3a00018  .... :      mov       r0,#0x18
            0x00008010: 0xe59f1000   .... :      ldr         r1,0x00008018 ; =#0x00020026
            0x00008014: 0xef123456   V4.. :    swi        0x123456
            0x00008018: 0x00020026  &... :     dcd        0x00020026   &...
ThumbProg
+0000     0x0000801c: 0x2102       .!    :      mov       r1,#2
+0002     0x0000801e: 0x4770      pG   :      bx         r14
$Ven$AT$$ThumbProg
+0000     0x00008020: 0xe59fc000  .... :      ldr         r12,0x00008028 ; = #0x0000801d
+0004     0x00008024: 0xe12fff1c   ../. :      bx         r12
+0008     0x00008028: 0x0000801d  .... :      dcd       0x0000801d   ....
+000c     0x0000802c: 0xe800e800  .... :     dcd       0xe800e800
+0010     0x00008030: 0xe7ff0010    .... :      dcd       0xe7ff0010   ....
+0014     0x00008034: 0xe800e800  .... :      dcd       0xe800e800  ....
+0018     0x00008038: 0xe7ff0010    .... :      dcd       0xe7ff0010    ....
 
 
disassemble된 코드를 살펴 보면 이전 bl ThumbProg  가 있던 자리에 bl  $Ven$AT$$ThumbProg 로 바뀐것을 볼 수 있습니다.
이 코드가 바로 veneer 코드 이며 arm 모드에서 thumb 모드로 컴파일된 함수를 호출 하기 위해 BX 를 사용하도록 linker가
바꾼 것입니다.
실제 아래쪽에 보면 $Ven$AT$$ThumbProg  로 Lable 이 붙은 코드가 추가가 되었습니다.
BL $Ven$AT$$ThumbProg  에 의해  $Ven$AT$$ThumbProg 로 가보면 이곳에서 하는일은 처음에
r12에다 0x00008028 번지에 있는 값인 0x0000801d 를 넣습니다.
그다음이 bx r12 를 하게 되는데 결국 사용자가 bl ThumbProg로 코드를 작성했지만 thumb모드로 바꾸기위해 링커가
bx 0x0000801d  라는 코드로 바꾼것입니다. (BX를 쓰게되면 해당번지로 branch한 후 state를 바꾸게 됩니다.  번지가 홀 수 번지이면 arm모드에서 thumb 모드로 번지가 짝수 번지이면 thumb모드에서 arm 모드로 state를 바꾸게 됩니다.)
결국 bx 0x0000801d 는 홀수 번지 branch이므로 0x0000801c 번지로 branch하고 arm에서 thumb으로 state를 바꿉니다.
그럼 0x0000801c 번지에는 기존의 ThumbProg 코드가 있습니다. 여기서 해당 코드 수행을 하고 다시 bx r14에 의해 (r14에는 bl 를 한다음 돌아갈 주소가 짝수번지로 들어가 있음  0x00008008) 다시 0x00008008 번지로 branch하고 번지가 짝수 이므로 thumb에서 arm으로 state를 바꾸게 됩니다.
 
이렇게 사용자가 arm/thumb interworking을 고려하지 않고 코드를 짜더라도 링커가 자동으로 해석해서 해당 모드를 바꿀 수 있게 코드를 삽입하게 되는데 이런 코드를 veneer 코드라고 합니다.
 
arm/thumb interworking 뿐아니라 long jump를 할경우도 이런 veneer 코드가 생기는 arm 모드에서 최대 32M 영역까지 branch를 할 수 있고 thumb 모드에서는 최대 4M 영역까지 branch를 할 수 있습니다.  마찬가지로 thumb모드에서 4M를 넘어가는곳의 함수를 호출 하는경우 링커는 알아서 veneer 코드를 만들어 arm 모드로 state를 바꾸고 해당 영역으로 branch한 후 다시 thumb 모드로 바꿔주는 코드를 삽입하게 됩니다.
 
 $Ven$AT$$ThumbProg   여기서 $Ven 은 veneer 코드라는 의미이고  $AT 는 Arm 모드에서 Thumb 모드로 변경한다는 의미입니다.
 
 
 
 
 
 
 
 
 

                                
2007. 8. 28. 16:19
Structure alignment
  - The alignment of a nonpacked structure is the maximum alignment required by any of its fields. - ARM
  - 구조체에서의 alignment 는 가장 큰 alignment에 맞추어진다.
    이는 자동 padding 과 연계되어 실수를 하기 쉬운 부분이 된다.

struct
{
    int a;
    double b;
    int c;
} TT;

TT의 sizeof 결과는 얼마일까? 답은 24이다.
왜냐하면 가장 큰 alignment 인 8 에 맞춰 남는 부분들이 padding 되기 때문이다.


padding
보통 우리가 아는 한에서는 4byte alignment 이다. 그리고 이보다 작을 경우에는 compiler 에서 자동 padding을 넣어준다. 이렇게 하는 이유는 performance 상의 이유이다. 메모리 접근시 유리하다.

packing 하기(packed 의 사용)
그러나 이러한 자동 padding 은 코드 호환성은 상당히 떨어진다.
왜냐하면 compiler 에 따라 자동 padding 하는 방식이 다를 수도 있기 때문이다. 그래서 performance를 떨어트리더라도 코드 호환성을 높이기 위해 자동 padding 을 하지 않게 된다.
즉, alignment 에 맞춰 padding을 넣지 않고 순수한 data가 차지하는 byte만을 메모리에 잡는다.

이렇게 하는 것을 packing 이라고 한다.


packing 하게 되면 기본적으로 alignment 를 1로 잡는다.

arm 계열
__packed 명령을 이용하여 packing 한다.
__align(n) 명령을 통해 특정 n byte 로 align이 가능하다.

gcc
__attribute__((packed))
__attribute__((align(n))) 과 같이 한다.

VC (MS 계열)
#pragma pack(push)
#pragma pack(4)
~~~~~~~~~
#pragma pack(pop)

VC 에서는 align 이 없고 pack 명령어를 통해 다 처리한다.
2007. 3. 7. 16:53
출처 : http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/index.jsp?topic=/com.ibm.vacpp6m.doc/compiler/ref/ruoptaln.htm


align
  


Purpose
Specifies what aggregate alignment rules the compiler uses for file compilation. Use this option to specify the maximum alignment to be used when mapping a class-type object, either for the whole source program or for specific parts.


Syntax



where available alignment options are:


power  The compiler uses a set of alignment rules to that provide binary compatibility with objects created by gcc V3.3 using the -malign option. This is the default.  
natural  The compiler uses a set of alignment rules to that provide binary compatibility with objects created by gcc V3.3 using the -malign option.  
mac68k  The compiler uses the Macintosh** alignment rules.  
bit_packed  The compiler uses the bit_packed alignment rules. Data, including bitfields, is packed as tightly as possible.  

See also #pragma align and #pragma options.


Notes
If you use the -qalign option more than once on the command line, the last alignment rule specified applies to the file.

You can control the alignment of a subset of your code by using #pragma align=alignment_rule. Use #pragma align=reset to revert to a previous alignment rule. The compiler stacks alignment directives, so you can go back to using the previous alignment directive, without knowing what it is, by specifying the #pragma align=reset directive. For example, you can use this option if you have a class declaration within an include file and you do not want the alignment rule specified for the class to apply to the file in which the class is included.

You can code #pragma align=reset in a source file to change the alignment option to what it was before the last alignment option was specified. If no previous alignment rule appears in the file, the alignment rule specified in the invocation command is used.


Examples
Example 1 - Affecting Only Aggregate Definition

Using the compiler invocation:

xlc++ file2.C /* <-- default alignment rule for file is                 */
            /*     power since no alignment rule specified */

Where file2.C has:

extern struct A A1;
typedef struct A A2;

#pragma options align=bit_packed /* <-- use bit_packed alignment rules*/
struct A {
  int a;
  char c;
};
#pragma options align=reset /* <-- Go back to default alignment rules */

struct A A1;  /* <-- aligned using bit_packed alignment rules since   */
A2 A3;        /*     this rule applied when struct A was defined      */

Example 2 - Imbedded #pragmas

Using the compiler invocation:

xlc -qalign=mac68k file.c  /* <-- default alignment rule for file is */
                           /*    Macintosh                           */

xlc -qalign=power file.c  /* <-- default alignment rule for file */
                           /*    is power                        */

Where file.c has:

struct A {
  int a;
  struct B {
    char c;
    double d;
#pragma options align=bit_packed /* <-- B will be unaffected by this  */
                            /*     #pragma, unlike previous behavior; */
                            /*     power alignment rules still    */
                            /*     in effect                          */
  } BB;
#pragma options align=reset /* <-- A is unaffected by this #pragma;   */
} AA;                       /*     power alignment rules still    */
                            /*     in effect                          */


Using the __align specifier
You can use the __align specifier to explicitly specify data alignment when declaring or defining a data item.


__align Specifier

Purpose
Use the __align specifier to explicitly specify alignment and padding when declaring or defining data items.


Syntax
declarator __align (int_const) identifier;

__align (int_const) struct_or_union_specifier [identifier] {struct_decln_list}

where:


int_const  Specifies a byte-alignment boundary. int_const must be an integer greater than 0 and equal to a power of 2.  


Notes
The __align specifier can only be used with declarations of first-level variables and aggregate definitions. It ignores parameters and automatics.

The __align specifier cannot be used on individual elements within an aggregate definition, but it can be used on an aggregate definition nested within another aggregate definition.

The __align specifier cannot be used in the following situations:

Individual elements within an aggregate definition.
Variables declared with incomplete type.
Aggregates declared without definition.
Individual elements of an array.
Other types of declarations or definitions, such as typedef, function, and enum.
Where the size of variable alignment is smaller than the size of type alignment.
Not all alignments may be representable in an object file.


Examples
Applying __align to first-level variables:

int __align(1024) varA;        /* varA is aligned on a 1024-byte boundary
                                   and padded with 1020 bytes              */

static int __align(512) varB;  /* varB is aligned on a 512-byte boundary
                                   and padded with 508 bytes               */

int __align(128) functionB( ); /* An error                                 */

typedef int __align(128) T;    /* An error                                 */

__align enum C {a, b, c};      /* An error                                 */

  

Applying __align to align and pad aggregate tags without affecting aggregate members:

__align(1024) struct structA {int i; int j;}; /* struct structA is aligned
                                                 on a 1024-byte boundary
                                                 with size including padding
                                                 of 1024 bytes             */

__align(1024) union unionA {int i; int j;}; /* union unionA is aligned
                                                 on a 1024-byte boundary
                                                 with size including padding
                                                 of 1024 bytes            */

  

Applying __align to a structure or union, where the size and alignment of the aggregate using the structure or union is affected:

__align(128) struct S {int i;};     /* sizeof(struct S) == 128             */

struct S sarray[10];                /* sarray is aligned on 128-byte boundary
                                       with sizeof(sarray) == 1280         */

struct S __align(64) svar;          /* error - alignment of variable is
                                         smaller than alignment of type    */

struct S2 {struct S s1; int a;} s2; /* s2 is aligned on 128-byte boundary
                                         with sizeof(s2) == 256 bytes      */

  

Applying __align to an array:

AnyType __align(64) arrayA[10]; /* Only arrayA is aligned on a 64-byte
                                  boundary, and elements within that array
                                  are aligned according to the alignment
                                  of AnyType.  Padding is applied after the
                                  back of the array and does not affect
                                  the size of the array member itself.    */

  

Applying __align where size of variable alignment differs from size of type alignment:

__align(64) struct S {int i;};

struct S __align(32) s1;          /* error, alignment of variable is smaller
                                     than alignment of type                 */

struct S __align(128) s2;         /* s2 is aligned on 128-byte boundary     */

struct S __align(16) s3[10];      /* error                                  */

int __align(1) s4;                /* error                                  */

__align(1) struct S {int i;};     /* error                                  */


Related References
Compiler Command Line Options
#pragma align
#pragma pack

See also:

The Data Mapping and Storage section of the VisualAge C++ Programming Tasks manual.
__attribute__((aligned)).
__attribute__((packed)).
2006. 9. 15. 11:22
세상에서 가장 행복한 모습으로



시장통 작은 분식점에서
찐빵과 만두를 만들어 파는 어머니가 있었습니다.

어느 일요일 오후,
아침부터 꾸물꾸물하던 하늘에서
후두둑 비가 떨어지기 시작했습니다.
소나기였습니다.

그런데 한 시간이 지나도 두 시간이 지나도
그치기는 커녕 빗발이 점점 더 굵어지자,
어머니는 서둘러 가게를 정리한 뒤
큰길로 나와 우산 두 개를 샀습니다.

그 길로 딸이 다니는 미술학원 앞으로
달려간 어머니는 학원 문을 열려다 말고
깜짝 놀라며 자신의 옷차림을 살폈습니다.

작업복에 낡은 슬리퍼, 앞치마엔
밀가루 반죽이 덕지덕지 묻어 있었습니다.
안그래도 감수성 예민한 여고생 딸이
상처를 입을까 걱정된 어머니는 건물 아래층에서
학원이 파하기를 기다리기로 했습니다.

한참을 서성대던 어머니가 문득
3층 학원 창가를 올려다봤을 때,
마침 아래쪽의 어머니를 내려다보고 있던
딸과 눈이 마주쳤습니다.

어머니는 반갑게 손짓을 했지만
딸은 못본 척 얼른 몸을 숨겼다가
다시 삐죽 고개를 내밀고,
숨겼다가 얼굴을 내밀곤 할 뿐
초라한 엄마가 기다리는 걸
원하지 않는 것 같았습니다.

슬픔에 잠긴 어머니는 고개를 숙인 채
그냥 돌아섰습니다.
그로부터 한 달 뒤 어머니는
딸의 미술학원에서 학생들의 작품을
전시한다는 초대장을 받았습니다.

딸이 부끄러워할 것만 같아 한나절을
망설이던 어머니는 다늦은 저녁에야
이웃집에 잠시 가게를 맡긴 뒤
부랴부랴 딸의 미술학원으로 갔습니다.

“끝나 버렸으면 어쩌지………….”

다행히 전시장 문은 열려 있었습니다.
벽에 가득 걸린 그림들을 하나하나
훑어보던 어머니는 한 그림 앞에서
그만 가슴이 덜컹 내려앉았습니다.

"세상에서 가장 아름다운 모습"

비, 우산, 밀가루 반죽이 허옇게
묻은 앞치마, 그리고 낡은 신발...
그림 속엔 어머니가 학원 앞에서...
딸을 기다리던 날의 초라한 모습이
고스란히 들어 있었습니다.

그날 딸은 창문 뒤에 숨어서
우산을 들고 서 있는 어머니의 모습을....
화폭에 담고 가슴에 담았던 것입니다.

어느새 어머니 곁으로 다가온 딸이
곁에서 환하게 웃고 있었습니다.
모녀는 그 그림을 오래 오래 바라보았습니다.

세상에서 가장 행복한 모습으로...
2006. 6. 30. 11:37
http://www.arm.com/support/faqdev/1453.html

ARM/Thumb Interworking and 'Unsupported call'



Description
When building an ARM/Thumb Interworking Image, the linker may give messages like:

For SDT 2.50/2.51:

Error: Unsupported call from Thumb code to ARM symbol arm_sub in thumb.o(C$$code). For SDT 2.11a:

Warning: Unsupported call from Thumb code to ARM symbol arm_sub in thumb.o(C$$code). For SDT 2.11:


1 Thumb to ARM interworking calls generated, use '-info interwork' to listInterworking call from Thumb to ARM code symbol arm_sub in thumb.o(C$$code). Solution
These messages indicate that ARM-to-Thumb or Thumb-to-ARM interworking calls have been detected by the linker, but the called routines have not been compiled for interworking. The example above shows a call from the (Thumb) object module thumb.o to the routine arm_sub() in another module.

Even if the link appears to be successful, you should interpret such messages as being errors, because the image may not execute correctly.

For the case above, you should recompile/reassemble for interworking the (C/asm) module(s) containing arm_sub (let's call it FUNC).

If FUNC is a C file, you should recompile it using the option '-apcs /interwork'.
If FUNC is an assembler file, you should:

use the 'INTERWORK' area assembler attribute for these routines e.g. AREA func, CODE, READONLY, INTERWORK  
check the called routine (arm_sub) use a BX LR instruction to return.
check the calling routine uses a BL instruction to call the routine arm_sub.
If the use of '-apcs /interwork' (for armcc & tcc) and 'INTERWORK' (for armasm & tasm) is applied consistently in your project, then the linker will generate the correct interworking veneers, and you will no longer see the message(s) above.

If the object file causing the error is supplied by a 3rd party vendor (e.g. an RTOS) which you do not have the source code for, then you may have to ask your supplier to provide suitably recompiled/reassembled object files.

For more details, see the SDT 2.11 User Guide, chapter 12, 'Interworking ARM and Thumb' or the SDT 2.50 User Guide, chapter 7, 'Interworking ARM and Thumb'.

2006. 6. 21. 07:35

Nand 자료

OldPapers/linux 2006. 6. 21. 07:35
nand 자료

nand에서 boot시 참고자료
2006. 6. 20. 23:38
U-Boot>nand write.yaffs : NAND Flash Filesystem : YAFFS HOW-TO (2nd)  

글쓴이 : jazz0719  조회 : 3216   날짜 : 2004/06/30 16:40:51

% style % -->
오랫만에 글올리는군요. 다들 잘 지내셨어요?



저번엔 U-Boot에 NAND fusing 관련하여, MTD기반으로 연동하는 방법을 올렸었죠 ?

(공구보드 U-Boot소스. 2410-09-bluesky-u-boot-1.0.0.tar.gz도 살짝 보니까

이런방식이더군요.)



이번에 고도리님 등등과 자체프로젝트(^^?)를 추진하고 있는데, YAFFS작업이 있어서

이 기회에 cmd_nand.c의 JFFS지원 루틴을 분석하여, U-Boot에서 YAFFS 이미지 fusing도

지원하도록 수정해보았습니다.



질문올라온거 보면 yaffs image를 U-Boot의 nand write[.jffs2] 명령을 이용하여

fusing 시도하는 분이 계시던데, 절대 안될겁니다.(^---^).

YAFFS 이미지포맷이 JFFS2등 다른 이미지파일과 다르고, Spare Area(OOB)의 처리가

되어야 하기 때문입니다.



아래 찬찬히 읽어보시면 이해되실거예요.

(보드 specific 코드 - 형욱보드..로 표기)



- 장형욱 씀.


NAND Flash Filesystem : YAFFS
yaffs를 지원하도록 리눅스커널 설정

mtd driver 패치 설치
MTD(Memory Technology Devices)는 임베디드 디바이스에서 고형체 파일시스템(solid state filesystem)을구성하는데 사용하는 플래시 메모리, RAM, 그리고 그 비슷한 다른 칩셋 등 메모리 장치로 yaffs도 mtd를 통해 연결됨
mtd관련모듈을 yaffs를 지원하도록 최신 버전으로 패치(안할경우 fs/yaffs 컴파일시 에러 발생)
http://www.linux-mtd.infradead.org/에서 mtd-snapshot...tar.gz2 최신버전 다운로드
[mtd]/patch> sh patchin.sh -c -j [linux] : kernel mtd모듈 패치
-c : symbolic link를 만들지 않고 직접 커널소스로 mtd copy
-j : jffs2 지원

변경내용 : [linux]/drivers/mtd/, [linux]/include/linux/mtd/

NAND 관련 driver 코드 작성(형욱보드_nand.c)
falinux사이트에서 관련소스를 다운로드(http://www.falinux.com/download/data/kernel.zip)
[linux]/drivers/mtd/nand/ez_x5.c를 pwpro_nand.c로 바꾸고 아래와 같이 수정
: 하드웨어 관련 컨트롤 함수, IO 주소공간 지정, NAND 파티션 테이블 작성 등.
NAND 플래시 상 MTD 파티션 구분
Creating 3 MTD partitions on "NAND 16MiB 3,3V":
mtd0,mtdblock0 : 0x00004000-0x00190000 (1584K) : "Linux Kernel Partition"
mtd1,mtdblock1 : 0x00190000-0x00640000 (4800K) : "Root Filesystem(YAFFS) Partition"
mtd2,mtdblock2 : 0x00640000-0x00fa0000 (9600K) : "Configuration Partition"


소스

/*
*  drivers/mtd/nand/형욱보드_nand.c
*
*  Copyright (C) 2003 JANG, Hyung-Wook (jazz0719@dreamwiz.com)
*
*  Support board : 형욱보드
*/

#include <linux/slab.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
/* modified by hwjang. */
#include <asm-ppc/delay.h>
#include <asm-ppc/processor.h>

#define PWPRO_NAND_BASE                0xf0000000
#define PWPRO_NAND_BASE_D0            PWPRO_NAND_BASE
#define PWPRO_NAND_ACCESS_START            (0x000)    // not use
#define PWPRO_NAND_DATA                    (0x00000)
#define PWPRO_NAND_CMD                     (0x00001)
#define PWPRO_NAND_ADDR                    (0x00002)
#define PWPRO_NAND_ACCESS_END              (0x300) // not use
#define NAND_MAXCHIP                (1)
static struct mtd_info *pwpro_nand_mtd = NULL;    

#define SZ_1K                           (1024)
#define SZ_1M                 (1024*1024)
#define __PWPRO_GPIO

/* modified by hwjang. add NAND Flash IO address mapping. */

#define FLASH_BASE_ADDR     0xF0000000
/*
#define FLASH_DATA_REG      *(volatile unsigned char*)(FLASH_BASE_ADDR + 0x00000)
#define FLASH_CMD_REG       *(volatile unsigned char*)(FLASH_BASE_ADDR + 0x00001)
#define FLASH_ADDR_REG      *(volatile unsigned char*)(FLASH_BASE_ADDR + 0x00002)
#define FLASH_CS0_SET       *(volatile unsigned char*)(FLASH_BASE_ADDR + 0x80000)
#define FLASH_CS0_CLR       *(volatile unsigned char*)(FLASH_BASE_ADDR + 0xA0000)
*/
#define FLASH_DATA_REG      (FLASH_BASE_ADDR + 0x00000)
#define FLASH_CMD_REG       (FLASH_BASE_ADDR + 0x00001)
#define FLASH_ADDR_REG      (FLASH_BASE_ADDR + 0x00002)
#define FLASH_CS0_SET       (FLASH_BASE_ADDR + 0x80000)
#define FLASH_CS0_CLR       (FLASH_BASE_ADDR + 0xA0000)

#if defined(__PWPRO_GPIO)               /* Clocking and Chip Control */
#define DCRN_CPC0_CGCR0     0x0b1       /* Clock Generation Control Register 0 */

#define GPIO0_OR        0xEF600700
#define GPIO0_TCR       0xEF600704
#define GPIO0_ODR       0xEF600714
#define GPIO0_IR        0xEF60071C

#define GPIO_MASK_NAND_FLASH_MEM (1<<(31-15))

#define gpio_init()     (*(volatile unsigned int*)GPIO0_TCR = 0x10000000)
#define gpio_read()     (*(volatile unsigned int*)GPIO0_IR)
#define gpio_write(n)   (*(volatile unsigned int*)GPIO0_OR = (n))

static void _flash_gpio_init(void)
{
        unsigned long temp;
        unsigned int  val;
                                                                                                
        temp = mfdcr(DCRN_CPC0_CGCR0);
        temp |= 0x00200000;
        mtdcr(DCRN_CPC0_CGCR0, temp);
                                                                                                
        val = (*(volatile unsigned int*) GPIO0_TCR);
        val &= ~(GPIO_MASK_NAND_FLASH_MEM);
        (*(volatile unsigned int*) GPIO0_TCR) = val;
                                                                                                
        val = (*(volatile unsigned int*) GPIO0_ODR);
        val &= ~(GPIO_MASK_NAND_FLASH_MEM);
        (*(volatile unsigned int*) GPIO0_ODR) = val;
                                                                                                
        val  = gpio_read();
        val &= ~GPIO_MASK_NAND_FLASH_MEM;
        gpio_write(val);
}
#endif /* __PWPRO_GPIO */

/*
* Define partitions for flash device
*/
const static struct mtd_partition partition_info[] =
{
    {
        name  : "형욱보드 Linux Kernel Partition",
        offset: 0x00004000,
        size  : 1584*SZ_1K
    },
    {
        name  : "형욱보드 Root Filesystem(YAFFS) Partition",
        offset: 0x00190000,
        size  : 4800*SZ_1K
    },
    {
        name  : "형욱보드 Configuration Partition",
        offset: 0x00640000,
        size  : 9600*SZ_1K
    }
};
#define PWPRO_NAND_NUM_PARTITIONS     3


/*
*    hardware specific access to control-lines
*/
/* void pwpro_nand0_hwcontrol(int cmd) */
void pwpro_nand0_hwcontrol(struct mtd_info *mtd, int cmd)
{
/*    int dummy; */

    switch(cmd)
    {
/*
    case NAND_CTL_SETNCE: dummy = readb(EZ_NAND_BASE_D0 + EZ_NAND_DATA)      ; break;
    case NAND_CTL_CLRNCE: dummy = readb(EZ_NAND_BASE_D0 + EZ_NAND_ACCESS_END); break;
*/  
    case NAND_CTL_SETNCE:
        writeb(0, FLASH_CS0_SET);         /* chip enable */
        writeb(NAND_CMD_RESET, FLASH_CMD_REG);     /* reset */
        udelay(20);                 /* delay */
        break;
    case NAND_CTL_CLRNCE:
        break;
    default:
        break;
    }
}

/*
* Send command to NAND device
*/
void pwpro_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
{
    register struct nand_chip *this = mtd->priv;
    register unsigned long NAND_IO_ADDR = this->IO_ADDR_W;

    // Write out the command to the device.
    if (command != NAND_CMD_SEQIN)
    {
        writeb (command, NAND_IO_ADDR + PWPRO_NAND_CMD );
    }  
    else
    {
        if (mtd->oobblock == 256 && column >= 256)
        {
            column -= 256;
            writeb (NAND_CMD_READOOB, NAND_IO_ADDR + PWPRO_NAND_CMD );
            writeb (NAND_CMD_SEQIN  , NAND_IO_ADDR + PWPRO_NAND_CMD );
        }
        else if (mtd->oobblock == 512 && column >= 256)
        {
            if (column < 512)
            {
                column -= 256;
                writeb (NAND_CMD_READ1, NAND_IO_ADDR + PWPRO_NAND_CMD);
                writeb (NAND_CMD_SEQIN, NAND_IO_ADDR + PWPRO_NAND_CMD);
            }
            else
            {
                column -= 512;
                writeb (NAND_CMD_READOOB, NAND_IO_ADDR + PWPRO_NAND_CMD);
                writeb (NAND_CMD_SEQIN  , NAND_IO_ADDR + PWPRO_NAND_CMD);
            }
        }
        else
        {
            writeb (NAND_CMD_READ0      , NAND_IO_ADDR + PWPRO_NAND_CMD);
            writeb (NAND_CMD_SEQIN      , NAND_IO_ADDR + PWPRO_NAND_CMD);
        }
    }

    // Serially input address
    if (column != -1 || page_addr != -1)
    {
        if (column != -1) writeb (column, NAND_IO_ADDR + PWPRO_NAND_ADDR);
        if (page_addr != -1)
        {
            writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR + PWPRO_NAND_ADDR);
            writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR + PWPRO_NAND_ADDR);
            // One more address cycle for higher density devices
            if (mtd->size & 0x0c000000)
            {
               writeb ((unsigned char) ((page_addr >> 16) & 0x0f), NAND_IO_ADDR + PWPRO_NAND_ADDR);
            }
        }  
    }
  
    switch (command)
    {
          
    case NAND_CMD_PAGEPROG:
    case NAND_CMD_ERASE1:
    case NAND_CMD_ERASE2:
    case NAND_CMD_SEQIN:
    case NAND_CMD_STATUS:
        return;

    case NAND_CMD_RESET:
        if( this->dev_ready )    break;
        writeb (NAND_CMD_STATUS, NAND_IO_ADDR + PWPRO_NAND_CMD);
        while ( !(readb (this->IO_ADDR_R) & 0x40));
        return;

    default:
        if (!this->dev_ready)
        {
            udelay (this->chip_delay);
            return;
        }  
    }
  
/*    while (!this->dev_ready()); */
    while (!this->dev_ready);
  
}

/*
* Main initialization routine
*/
int __init pwpro_nand_init (void)
{
    struct nand_chip *this;
  
    //  Allocate memory for MTD device structure and private data
    pwpro_nand_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL);
    if (!pwpro_nand_mtd)
    {
        printk ("Unable to allocate 형욱보드 MTD device structure.\n");
        return -ENOMEM;
    }
    // Get pointer to private data
    this = (struct nand_chip *) (&pwpro_nand_mtd[1]);

    // Initialize structures
    memset((char *) pwpro_nand_mtd, 0, sizeof(struct mtd_info));
    memset((char *) this, 0, sizeof(struct nand_chip));

    // Link the private data with the MTD structure
    pwpro_nand_mtd->priv = this;

    // Set address of NAND IO lines
    this->IO_ADDR_R = PWPRO_NAND_BASE_D0 + PWPRO_NAND_DATA;
    this->IO_ADDR_W = PWPRO_NAND_BASE_D0 + PWPRO_NAND_DATA;
    // Set address of hardware control function
    this->hwcontrol = pwpro_nand0_hwcontrol;
    // Set commamd function
    this->cmdfunc = pwpro_nand_command ;
    // 15 us command delay time */
    this->chip_delay = 15;      

//    this->eccmode = NAND_ECC_SOFT;
//    pwpro_nand_mtd->oobinfo.useecc = -1;

#if defined(__PWPRO_GPIO)
    _flash_gpio_init();
#endif /* __POWATCH_GPIO */
  
    // Scan to find existence of the device
/*    if (nand_scan (pwpro_nand_mtd)) */
    if (nand_scan (pwpro_nand_mtd, NAND_MAXCHIP))
    {
        kfree (pwpro_nand_mtd);
        return -ENXIO;
    }
    // Allocate memory for internal data buffer
    this->data_buf = kmalloc (sizeof(u_char) * (pwpro_nand_mtd->oobblock + pwpro_nand_mtd->oobsize), GFP_KERNEL);
    if (!this->data_buf)
    {
        printk ("Unable to allocate NAND data buffer for 형욱보드-NAND.\n");
        kfree (pwpro_nand_mtd);
        return -ENOMEM;
    }
    // Register the partitions
    add_mtd_partitions(pwpro_nand_mtd, partition_info, PWPRO_NAND_NUM_PARTITIONS);
    // Return happy
    return 0;
}
module_init(pwpro_nand_init);

/*
* Clean up routine
*/
#ifdef MODULE
static void __exit pwpro_nand_cleanup (void)
{
    struct nand_chip *this = (struct nand_chip *) &pwpro_nand_mtd[0];

    // Unregister the device
    del_mtd_device (pwpro_nand_mtd);

    // Free internal data buffer
    kfree (this->data_buf);

    // Free the MTD device structure
    kfree (pwpro_nand_mtd);
}
module_exit(pwpro_nand_cleanup);
#endif

MODULE_LICENSE("GPL");
MODULE_AUTHOR("JANG, Hyung-Wook <jazz0719@dreamwiz.com");
MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on 형욱보드");



pwpro_nand.c를 커널컴파일 때 추가할 수 있도록 설정
[linux]/drivers/mtd/nand/Config.in 에 추가
dep_tristate '  NAND Device Support' CONFIG_MTD_NAND $CONFIG_MTD
if [ "$CONFIG_MTD_NAND" = "y" -o "$CONFIG_MTD_NAND" = "m" ]; then
   bool '    NAND Flash Device on 형욱보드' CONFIG_MTD_NAND_PWPRO
fi
[linux]/drivers/mtd/nand/Makefile 에 추가
obj-$(CONFIG_MTD_NAND_PWPRO)    += pwpro_nand.o


NAND Flash에 접근할 수 있도록 IO 주소공간을 커널에 등록
[linux]/arch/ppc/platforms/walnut.c 에 다음내용을 추가 (위에서 이미 등록됨. 확인)
void __init
board_io_mapping(void)
{
/* modified by hwjang */
        ...
        /* CS1 - NAND FLASH */
        io_block_mapping( 0xF0000000, 0xF0000000, 0x00100000, _PAGE_IO );
        ...
}
NAND ECC 경고메세지 관련
YAFFS는 MTD/NAND driver의 ECC기능을 쓰지않고, YAFFS에서 제공하는 것을 쓰므로 이로인한 아래의 경고메세지를 주석처리한다

[linux]/drivers/mtd/nand/nand.c 수정
case NAND_ECC_NONE:
  // printk(KERNEL_WARNING ...)


yaffs를 kernel fs에 포함

http://www.aleph1.co.uk/armlinux/projects/yaffs/index.html(yaffs소스),
http://www.toby-churchill.org/(ballon_yaffs소스) 다운로드


[linux]/fs/yaffs 생성.

yaffs소스에서 [linux]/fs/yaffs아래에 devextras.h yaffs_fs.c yaffs_guts.c yaffs_guts.h
yaffs_mtdif.cyaffs_mtdif.h yaffsinterface.h, yportenv.h, yaffs_ecc.h, yaffs_ecc.c 를 copy


[linux]/fs/yaffs에 [ballon_yaffs]/Makefile을 copy하고 아래와 같이 수정
obj-y := yaffs_fs.o yaffs_guts.o yaffs_mtdif.o yaffs_ecc.o
[linux]/fs/Config.in의 앞부분에 아래 추가하여 커널 컴파일 configuration시 yaffs 선택할 수 있도록 함
tristate "Yaffs filesystem on NAND" CONFIG_YAFFS_FS
(document에서는 CONFIG_MTD_NAND가 정의되어있을때면 설정가능하도록 되어있으나,
실제 nand flash에 접근할때는 mtd가아닌 yaffs의 ecc, verify write기능을 쓰기 때문에 이렇게 설정해야함


[linxux]fs/Makefile에 추가
subdir-$(CONFIG_YAFFS_FS)       += yaffs


컴파일 에러 발생시 추가 수정내용 (옵션)
[linux]/include/linux/serialP.h 수정 : async_icount 구조체 정의 관련
/* modified by hwjang. for yaffs filesystem support */
/* #if (LINUX_VERSION_CODE < 0x020300) */
#if (LINUX_VERSION_CODE >= 0x020300)
/* Unfortunate, but Linux 2.2 needs async_icount defined here and
* it got moved in 2.3 */
#include <linux/serial.h>
#endif


[linux]/include/linux/mtd/mtd.h 추가 : 2.5버전이하에서 사용하는 BUG_ON함수가 previewkit 소스에는 제공하지 않으므로 2.5이상 버전의 커널 소스트리의 bug.h파일을 [linux]/include/asm-ppc/bug.h 로 copy
#include <asm-ppc/bug.h>




kernel에 mtd, yaffs가 적용되도록 환경설정

Load configuration : arc/ppc/deconfig 한후 아래 내용 추가

Loadable module support
  [*] Kernel module loader : /sbin/insmod yaff.o하지 않아도 커널이 자동적으로 yaff module을 등록시키도록 하기 위함.

General setup
  [*] Default bootloader kernel arguments
    Initial kernel command string: "console=ttyS0,9600 console=tty0 root=/dev/mtdblock0"
    : 루트파일시스템을 플래시에 구성된 yaffs파일시스템으로 mtd를 통해 연결. 아래 참고.

Memory Technolygy Devices(MTD)
  <*> Memory Technology Device (MTD) support
  [*] Debugging(verbocity=0)
  <*> MTD partitioning support
  <*> Direct char Device access to MTD device
  <*> Caching block device access to MTD devices
  NAND Flash Device Drivers
    <*> NAND Device Support
    [*] NAND Flash Device on 형욱보드
    [*] Verify NAND page writes

Fliesystem
  <*> Yaffs filesystem on NAND

Save as poswatch_pro.menuconfig


[linux]>make clea
[linux]>make dep
[linux]>make uImage
-> yaffs 플래시파일시스템 지원 u-boot용 커널 생성
   : [linux]/arch/ppc/boot/images/vmlinux.UBoot
[linux]>make zImage
-> Poswatch openbios용 압축커널이미지(arch/ppc/boot/images/zImage.treeboot) 생성(http://www.geocrawler.com/archives/3/8358/2002/1/50/7622546/)


U-Boot를 yaffs를 지원하여 Stand-alone으로 동작하도록 수정
include/configs/형욱보드.h
mtd partition 0으로부터 리눅스 커널 이미지를 램으로 로드하여, 부팅.
/* autoboot command */
#define CONFIG_BOOTCOMMAND      "nand read 200000 4000 (vmlinux.UBoot사이즈);bootm 200000"

mtd partition 1의 yaffs.image를 root filesystem으로 인식.
#define CONFIG_BOOTARGS           "root=/dev/mtdblock1 rw"


yaffs rootfs 구성


directory 구성
yaffs : working dir
- rootfs_yaffs : 위에서 구성한 rootfs를 copy ( cp -dprR 이용)


$ cd rootfs_yaffs


mknod dev/mtd0 c 90 0
mknod dev/mtd1 c 90 1
mknod dev/mtdblock0 b 31 0
mknod dev/mtdblock1 b 31 1


$ vi etc/fstab
/dev/mtdblock1    / yaffs default 0 0


아래의 설정은 http://doc.kldp.org/KoreanDoc/html/Boot_Process-KLDP/inittabfile.html 참조.


vi etc/inittab
::sysinit:/etc/init.d/rcS 추가 (이상하게 앞의 si 키워드 없애야 동작함. 향후 검토)


vi etc/init.d/rcS 수정(맨앞)
/sbin/insmod yaffs.o : menuconfig에서 Loadable support>kernel module loader선택했다면 제외할것.
mount -t yaffs /dev/mtdblock1 / -> flash의 yaffs파일시스템이 /로 마운트


yaffs 이미지 작성.


yaffs/utils에서 yaffs 이미지 작성용 툴을 제공
mkyaffsimage : root filesystem 디렉토리로부터 NAND flash용 yaffs 이미지 작성
mkyaffs : flash erase


yaffs compile
yaffs/Makefile, yaffs/utils/Makefile을 아래와 같이 수정
KERNELDIR = [linux]
MAKETOOLS =
...
# USE_RAM_FOR_TEST = -DCONFIG_YAFFS_RAM_ENABLED


yaffs$ make
yaffs/utils$ make
http://62.49.201.250/balloon/releases/utils/mkyaffsimage 다운로드  
$ mv mkyaffsimage mkyaffsimage.ballon
Ihttp://www.intrinsyc.com/support/I-Linux/405-cube/cerfcube405ep.htm#misc/cd.htm으로부터 mkyaffsimage 다운로드
$ mv mkyaffsimage mkyaffsimage.cerf


$ mkyaffsimage.cerf rootfs_yaffs yaffs.image convert: NAND flash용 yaffs 이미지(yaffs.image)생성


U-Boot에 YAFFS 이미지 지원 NAND flash 처리루틴 추가 (cmd_nand.c 기반)
NAND flash 관련 명령어는 common/cmd_nand.c에서 정의됨
common/cmd_nand.c
U_BOOT_CMD(
        nand,   5,      1,      do_nand,
        "nand    - NAND sub-system\n",
        "info  - show available NAND devices\n"
        "nand device [dev] - show or set current device\n"
        "nand read[.jffs2[s]]  addr off size\n"
        "nand write[.jffs2] addr off size - read/write `size' bytes starting\n"
        "    at offset `off' to/from memory address `addr'\n"
        "nand erase [clean] [off size] - erase `size' bytes from\n"
        "    offset `off' (entire device if not specified)\n"
        "nand bad - show bad blocks\n"
        "nand read.oob addr off size - read out-of-band data\n"
        "nand write.oob addr off size - write out-of-band data\n"
);
nand 관련 명령어 셋 컴파일되도록 설정

$ vi common/Makefile
COBJS = cmd_nand.o 추가
$ vi include/configs/WALNUT405.h : CFG_CMD_NAND 추가

#define CONFIG_COMMANDS        (CONFIG_CMD_DFL  | \
                                CFG_CMD_PCI     | \
                                CFG_CMD_IRQ     | \
                                CFG_CMD_NAND )
board/.../형욱보드.c
/* modified by hwjang : NAND initialization */
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
extern ulong
nand_probe(ulong physadr);

void
nand_init(void)
{
#define FLASH_BASE_ADDR     0xF0000000
        ulong totlen = 0;

        printf ("Probing at 0x%.8x\n", FLASH_BASE_ADDR);
        totlen = nand_probe (FLASH_BASE_ADDR);

        printf ("%4lu MB\n", totlen >>20);
}
#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */




$ vi include/configs/형욱보드.h : 각시스템의 설정에 맞게 각 매크로를 define해주세요.
/* modified by hwjang */
/*-----------------------------------------------------------------------
* NAND-FLASH stuff
*-----------------------------------------------------------------------
*/
#define CONFIG_NAND
#define CONFIG_YAFFS                    /* use yaffs filesystem on nand flash */

#define CFG_NAND_BASE                   0xF0000000
#define DCRN_CPC0_CGCR0                 0x0b1
#define GPIO0_TCR_ADDR                  0xEF600704
#define GPIO0_ODR_ADDR                  0xEF600718
#define GPIO0_IR_ADDR                   0xEF60071C

#define GPIO_MASK_NAND_FLASH_MEM        (1<<(31-15))

#define gpio_read()                     (*(volatile unsigned int*)GPIO0_IR)
#define gpio_write(n)                   (*(volatile unsigned int*)GPIO0_ODR_ADDR = (n))

#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 CFG_NAND_CE_SET         (CFG_NAND_BASE + 0x00080000)
#define CFG_NAND_CE_CLR         (CFG_NAND_BASE + 0x000A0000)
#define CFG_NAND_CMD_REG        (CFG_NAND_BASE + 0x00000001)
#define CFG_NAND_ADDR_REG       (CFG_NAND_BASE + 0x00000002)

#define NAND_DISABLE_CE(nand)    do { *(volatile __u8 *)(CFG_NAND_CE_CLR) = 0;} while(0)
#define NAND_ENABLE_CE(nand)     do { *(volatile __u8 *)(CFG_NAND_CE_SET) = 0;} while(0)
#define NAND_CTL_CLRALE(nandptr) do { ; } while(0)
#define NAND_CTL_SETALE(nandptr) do { ; } while(0)
#define NAND_CTL_CLRCLE(nandptr) do { ; } while(0)
#define NAND_CTL_SETCLE(nandptr) do { ; } while(0)
#define NAND_WAIT_READY(nand)    while ((gpio_read() & GPIO_MASK_NAND_FLASH_MEM) ? 0:1)

#define WRITE_NAND_COMMAND(d, adr) do{ *(volatile __u8 *)(CFG_NAND_CMD_REG) = (__u8)(d); } while(0)
#define WRITE_NAND_ADDRESS(d, adr) do{ *(volatile __u8 *)(CFG_NAND_ADDR_REG) = (__u8)(d); } while(0)
#define WRITE_NAND(d, adr) ( writeb(d, adr) )
#define READ_NAND(adr) ( readb(adr) )


$ vi lib_ppc/board.c : flash 초기화 안해줌(수정 가능)
/* modified by hwjang : no flash initialization */
#if 0
/* #if !defined(CFG_NO_FLASH) */
        puts ("FLASH: ");

        if ((flash_size = flash_init ()) > 0) {


YAFFS 이미지  Fusing 루틴 추가 (cmd_nand.c)
#  nand write.yaffs (yaffs.image가 로딩된 ram addr) (NAND flash offset) (yaffs.image 사이즈)
가 동작하도록 명령어 셋과 처리루틴 추가
YAFFS의 경우 U-Boot에서 지원하는 JFFS2와 동작하는 상황이 다르며, 아래사항을 처리해야 함
Page Write 시 OOB영역 처리 : yaffs.image는 data(1st/2nd half array, 512bytes) + oob(spare array, 16bytes)의 연속으로 구성되며, JFFS2와 다르게  spare area(OOB영역)에 yaffs.image의 값을 쓸 수 있도록 수정

ECC disable : YAFFS는 NAND_ECC_NONE모드
size 문제 : (yaffs.image 사이즈)는 oob영역까지 포함된 사이즈, U-Boot에서는 data영역만의 사이즈 기반(즉 FLASH address기반)으로 처리하므로, yaffs의 경우 이를 적당히 조절해야 함. 처리하지 않을 경우 의도보다 FLASH 영역을 넘어서 잘못된 값을 Fusing. bad block 발생.
nand write.yaffs 명령어셋 추가
#define NANDRW_YAFFS    0x08
nand write.yaffs 명령을 인식하고, nand_write_yaffs()를 호출하도록 설정.
int do_nand (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
...
                else if (cmdtail && !strncmp(cmdtail, ".yaffs", 2))
                        cmd |= NANDRW_YAFFS;
...
}
/* cmd: 0: NANDRW_WRITE                 write, fail on bad block
*      1: NANDRW_READ                  read, fail on bad block
*      2: NANDRW_WRITE | NANDRW_JFFS2  write, skip bad blocks
*      3: NANDRW_READ | NANDRW_JFFS2   read, data all 0xff for bad blocks
*      7: NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP read, skip bad blocks
*      8: NANDRW_WRITE | NANDRW_YAFFS  write, yaffs // hwjang
*/
static int nand_rw (struct nand_chip* nand, int cmd,
            size_t start, size_t len,
            size_t * retlen, u_char * buf)
{
/* size관련처리 */
int pages_per_block = (nand->erasesize) / (nand->oobblock);
if (cmd & NANDRW_YAFFS) {
// len passed is yaffs image size (including oob_data).
// modified to size except oob_data to work properly in u-boot
        int num_pages_yaffs = len / (nand->oobblock + nand->oobsize);
        len = num_pages_yaffs << nand->page_shift;
}
..
             else if ((cmd == (NANDRW_WRITE | NANDRW_JFFS2)) || (cmd == (NANDRW_WRITE | NANDRW_YAFFS))) {
             //else if (cmd == (NANDRW_WRITE | NANDRW_JFFS2)) {
                                        /* skip bad block */
                                        start += erasesize;
                                        continue;
                                }
...
    else if (cmd & NANDRW_YAFFS) {
        ret = nand_write_yaffs (nand, start,
                   min(len, eblk + erasesize - start),
                   &n, (u_char*)buf, NULL);

        // hwjang :     yaffs image contains oob_data ( size : 16 Bytes in each page )
        //              so buf pointer should be increased to point at data_buf of the next block.
        buf += (pages_per_block << 4);

    }

}
nand->data_buf[]에 OOB영역까지 포함한 yaffs.image의 값을 할당하고, OOB영역까지 page programming되도록 설정
static int nand_write_yaffs (struct nand_chip* nand, size_t to, size_t len,
                           size_t * retlen, const u_char * buf, u_char * ecc_code)
{
        int i, page, col, cnt, ret = 0;
//hwjang
int pages_per_block = (nand->erasesize) / (nand->oobblock);

        /* Do not allow write past end of device */
        if ((to + len) > nand->totlen) {
                printf ("%s: Attempt to write past end of page\n", __FUNCTION__);
                return -1;
        }

        /* Shift to get page */
        page = ((int) to) >> nand->page_shift;

        /* Get the starting column */
        col = to & (nand->oobblock - 1);

        /* Initialize return length value */
        *retlen = 0;

        /* Select the NAND device */
#ifdef CONFIG_OMAP1510
        archflashwp(0,0);
#endif
        NAND_ENABLE_CE(nand);  /* set pin low */

        /* Check the WP bit */
        NanD_Command(nand, NAND_CMD_STATUS);
        if (!(READ_NAND(nand->IO_ADDR) & 0x80)) {
                printf ("%s: Device is write protected!!!\n", __FUNCTION__);
                ret = -1;
                goto out;
        }

        /* Loop until all data is written */
// hwjang :     yaffs image contains oob_data ( size : 16 Bytes in each page )
//              so additional length should be checked.
        while (*retlen < len + (pages_per_block << 4)) {

                /* Invalidate cache, if we write to this page */
                if (nand->cache_page == page)
                        nand->cache_page = -1;

                /* Write data into buffer */
                if ((col + len) >= nand->oobblock)
// hwjang :     write including oob_data in yaffs image
                        for (i = col, cnt = 0; i < nand->oobblock + nand->oobsize; i++, cnt++)
                                nand->data_buf[i] = buf[(*retlen + cnt)];
                else
                        for (i = col, cnt = 0; cnt < (len - *retlen); i++, cnt++)
                                nand->data_buf[i] = buf[(*retlen + cnt)];

                /* We use the same function for write and writev !) */
                ret = nand_write_page_yaffs (nand, page, col, i, NULL);

                if (ret)
                        goto out;

                /* Next data start at page boundary */
                col = 0;

                /* Update written bytes count */
                *retlen += cnt;

                /* Increment page address */
                page++;
        }

        /* Return happy */
        *retlen = len;

out:
        /* De-select the NAND device */
        NAND_DISABLE_CE(nand);  /* set pin high */
#ifdef CONFIG_OMAP1510
        archflashwp(0,1);
#endif
        return ret;
}


OOB영역에 접근하는 ECC관련코드를 제거(nand_write_page()와 비교해볼것).
timing 설정(아래참조)
static int nand_write_page_yaffs (struct nand_chip *nand,
                            int page, int col, int last, u_char * ecc_code)
{
        int i;
        unsigned long nandptr = nand->IO_ADDR;

        /* Prepad for partial page programming !!! */
        for (i = 0; i < col; i++)
                nand->data_buf[i] = 0xff;

        /* Postpad for partial page programming !!! oob is already padded */
        for (i = last; i < nand->oobblock; i++)
                nand->data_buf[i] = 0xff;

        /* Send command to begin auto page programming */
        NanD_Command(nand, NAND_CMD_READ0);
        NanD_Command(nand, NAND_CMD_SEQIN);
        NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);

        /* Write out complete page of data */
        for (i = 0; i < (nand->oobblock + nand->oobsize); i++)
                WRITE_NAND(nand->data_buf[i], nand->IO_ADDR);

        /* Send command to actually program the data */
        NanD_Command(nand, NAND_CMD_PAGEPROG);

udelay(300); // hwjang

        NanD_Command(nand, NAND_CMD_STATUS);
#ifdef NAND_NO_RB
        { u_char ret_val;

          do{
                ret_val = READ_NAND(nandptr);   /* wait till ready */
          } while((ret_val & 0x40) != 0x40);
        }
#endif
        /* See if device thinks it succeeded */
        if (READ_NAND(nand->IO_ADDR) & 0x01) {
                printf ("%s: Failed write, page 0x%08x, ", __FUNCTION__, page);
                return -1;
        }

#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
        /*
         * The NAND device assumes that it is always writing to
         * a cleanly erased page. Hence, it performs its internal
         * write verification only on bits that transitioned from
         * 1 to 0. The device does NOT verify the whole page on a
         * byte by byte basis. It is possible that the page was
         * not completely erased or the page is becoming unusable
         * due to wear. The read with ECC would catch the error
         * later when the ECC page check fails, but we would rather
         * catch it early in the page write stage. Better to write
         * no data than invalid data.
         */

        /* Send command to read back the page */
        if (col < nand->eccsize)
                NanD_Command(nand, NAND_CMD_READ0);
        else
                NanD_Command(nand, NAND_CMD_READ1);
        NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);

udelay(9); // hwjang

        /* Loop through and verify the data */
        for (i = col; i < last; i++) {
               if (nand->data_buf[i] != readb (nand->IO_ADDR)) {
                        printf ("%s: Failed write verify, page 0x%08x ", __FUNCTION__, page);
                        return -1;
                }
        }
#endif
        return 0;
}


형욱보드 설정에 맞춘 wait timing 세팅  
하드웨어 측정 결과
구분
하드웨어 R/B pin Busy timing
소스 설정값(udelay 적용값)

write
t_PROG = 180 us
300 us

erase
t_BER = 2000 us
2500 us

read
t_R = 7.20 us
9 us


$ vi common/cmd_nand.c
static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len,
                 size_t * retlen, u_char *buf, u_char *ecc_code)
{
...
                /* Send the read command */
                NanD_Command(nand, NAND_CMD_READ0);
                NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);

udelay(9); // hwjang

                /* Read in a page + oob data */
                NanD_ReadBuf(nand, nand->data_buf, nand->oobblock + nand->oobsize);
...
}

static int nand_write_page (struct nand_chip *nand,
                            int page, int col, int last, u_char * ecc_code)
{
...
        /* Write out complete page of data */
        for (i = 0; i < (nand->oobblock + nand->oobsize); i++)
                WRITE_NAND(nand->data_buf[i], nand->IO_ADDR);

        /* Send command to actually program the data */
        NanD_Command(nand, NAND_CMD_PAGEPROG);

udelay(300); // hwjang

        NanD_Command(nand, NAND_CMD_STATUS);
...
}

static int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len,
                         size_t * retlen, u_char * buf)
{
...
        if (nand->page256 && ofs + len > (ofs | 0x7) + 1) {
                len256 = (ofs | 0x7) + 1 - ofs;
                NanD_ReadBuf(nand, buf, len256);

                NanD_Command(nand, NAND_CMD_READOOB);
                NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff));
        }

udelay(9); // hwjang

        NanD_ReadBuf(nand, &buf[len256], len - len256);
...
}

static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len,
                  size_t * retlen, const u_char * buf)
{
...
        /* treat crossing 8-byte OOB data for 2M x 8bit devices */
        /* Note: datasheet says it should automaticaly wrap to the */
        /*       next OOB block, but it didn't work here. mf.      */
        if (nand->page256 && ofs + len > (ofs | 0x7) + 1) {
                len256 = (ofs | 0x7) + 1 - ofs;
                for (i = 0; i < len256; i++)
                        WRITE_NAND(buf[i], nandptr);

                NanD_Command(nand, NAND_CMD_PAGEPROG);

udelay(300);

                NanD_Command(nand, NAND_CMD_STATUS);
...
        for (i = len256; i < len; i++)
                WRITE_NAND(buf[i], nandptr);

        NanD_Command(nand, NAND_CMD_PAGEPROG);

udelay(300); // hwjang

        NanD_Command(nand, NAND_CMD_STATUS);
...
}

static int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean)
{
...
        while(len) {
                /*mychip = &nand->chips[shr(ofs, nand->chipshift)];*/
                mychip = &nand->chips[ofs >> nand->chipshift];

                /* always check for bad block first, genuine bad blocks
                 * should _never_  be erased.
                 */
                if (ALLOW_ERASE_BAD_DEBUG || !check_block(nand, ofs)) {
                        /* Select the NAND device */
                        NAND_ENABLE_CE(nand);  /* set pin low */

                        NanD_Command(nand, NAND_CMD_ERASE1);
                        NanD_Address(nand, ADDR_PAGE, ofs);
                        NanD_Command(nand, NAND_CMD_ERASE2);
udelay(2500); // hwjang
                        NanD_Command(nand, NAND_CMD_STATUS);
...
}
NAND FLASH로부터 STAND-ALONE으로 동작
# tftpboot 200000 /tftpboot/vmlinux.UBoot
# tftpboot 400000 /tftpboot/yaffs.image
# nand erase (nand시작번지) (nand 사이즈)
# nand write 200000 4000 (vmlinux.UBoot 사이즈)
# nand write.yaffs 400000 190000 (yaffs.image 사이즈)
# reset
(재부팅)
# nand read 200000 4000 (vmlinux.UBoot사이즈);bootm 200000 실행되고

(콘솔메시지)
U-Boot 1.1.1 (Jun 30 2004 - 15:21:21)

CPU:   IBM PowerPC 405GPr Rev. B at 266.500 MHz (PLB=133, OPB=66, EBC=66 MHz)
       PCI sync clock at 33 MHz, internal PCI arbiter enabled
       16 kB I-Cache 16 kB D-Cache
Board: ### No HW ID - assuming WALNUT405
I2C:   ready
DRAM:  32 MB
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
NAND:Probing at 0xf0000000
  16 MB
Hit any key to stop autoboot:  0
=> tftpboot 200000 /tftpboot/uImage
ENET Speed is 10 Mbps - HALF duplex connection
TFTP from server 192.168.1.210; our IP address is 192.168.1.200
Filename '/tftpboot/uImage'.
Load address: 0x200000
Loading: #################################################################
         #################################################################
         ############
done
Bytes transferred = 722310 (b0586 hex)
=> tftpboot 400000 /tftpboot/yaffs.image
ENET Speed is 10 Mbps - HALF duplex connection
TFTP from server 192.168.1.210; our IP address is 192.168.1.200
Filename '/tftpboot/yaffs.image'.
Load address: 0x400000
Loading: #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         ############################################################
done
Bytes transferred = 3631056 (3767d0 hex)
=> nand write 200000 4000 b0586

NAND write: device 0 offset 16384, size 722310 ...  722310 bytes written: OK
=> nand write.yaffs 400000 190000 3767d0

NAND write: device 0 offset 1638400, size 3631056 ...  3521024 bytes written: OK
=> nand bad

Device 0 bad blocks:
0x00000000

=> reset

U-Boot 1.1.1 (Jun 30 2004 - 15:21:21)

CPU:   IBM PowerPC 405GPr Rev. B at 266.500 MHz (PLB=133, OPB=66, EBC=66 MHz)
       PCI sync clock at 33 MHz, internal PCI arbiter enabled
       16 kB I-Cache 16 kB D-Cache
Board: ### No HW ID - assuming WALNUT405
I2C:   ready
DRAM:  32 MB
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
NAND:Probing at 0xf0000000
  16 MB
Hit any key to stop autoboot:  0

NAND read: device 0 offset 16384, size 2097152 ...  2097152 bytes read: OK
## Booting image at 00200000 ...
   Image Name:   Linux-2.4.24-pre2
   Image Type:   PowerPC Linux Kernel Image (gzip compressed)
   Data Size:    722246 Bytes = 705.3 kB
   Load Address: 00000000
   Entry Point:  00000000
   Verifying Checksum ... OK
   Uncompressing Kernel Image ... OK

...(중간생략)

NAND device: Manufacturer ID: 0xec, Chip ID: 0x73 (Samsung NAND 16MiB 3,3V)
Creating 3 MTD partitions on "NAND 16MiB 3,3V":
0x00004000-0x00190000 : "형욱보드 Linux Kernel Partition"
mtd: Giving out device 0 to 형욱보드 Linux Kernel Partition
0x00190000-0x00640000 : "형욱보드 Root Filesystem(YAFFS) Partition"
mtd: Giving out device 1 to 형욱보드 Root Filesystem(YAFFS) Partition
0x00640000-0x00fa0000 : "형욱보드 Configuration Partition"
mtd: Giving out device 2 to 형욱보드 Configuration Partition

...(중간생략)

yaffs: dev is 7937 name is "1f:01"
VFS: Mounted root (yaffs filesystem).
Freeing unused kernel memory: 100k init
serial console detected.  Disabling virtual terminals.
init started:  BusyBox v0.60.2 (2002.12.19-10:50+0000) multi-call binary

(none) login: root

$ ls
$ cd /tmp
$ ls
$ cat abcd > test.txt
cat: abcd: No such file or directory
$ echo abcd > test.txt
$ ls
test.tx
2006. 5. 1. 23:21

chicaloca

OldPapers/free_stuff 2006. 5. 1. 23:21
http://www.chicaloca.co.kr/