커널 2.6 기반에서 이지보드에 달려있는 낸드 플래시를 사용하기위한 방법을 소개한다.
Nand 플래시를 사용한다는 것은 파일을 쓰고 지울 수 있어야 한다. 리눅스에서는 이같은 디바이스를 MTD(Memory Technology Device) 라고 부른다.

필요한 것들

PC 의 하드디스크를 사용하기 위해 포맷을 하듯이, MTD 또한 사용하기 위해서는 포맷을 해야 한다. 우리가 흔히 사용하는 ext3, xfs 같은 파일시스템은 실린더가 들어있는 하드디스크 같은 디바이스를 위한 것이고, 플래시메모리라는 FTL 을 가진 디바이스에는 따로 준비된 파일시스템이 있다.
가장 많이 사용되는 것이 JFFS2 와 YAFFS2 이다. 이 문서에서는 낸드 플래시를 각각의 파일시스템으로 사용하는 것을 설명한다.
앞서 설명한 플래시 파일시스템을 사용하기 위해서는 커널에 해당 옵션이 포함되어야 한다.

이더넷 드라이버가 있는 것처럼, Nand 플래시를 사용하기 위해서는 드라이버가 필요하다. 이 드라이버는 파일을 생성하거나 지울 때, Nand 플래시를 컨드롤하는 코드를 담고 있다.
Nand 드라이버가 없거나 잘못된다면, 커널에서 낸드 플래시를 인식하지 못하거나, 파일을 생성하거나 지울 수 없다.

Nand 플래시 드라이버 추가

먼저 드라이버를 작성하자. drivers/mtd/nand 아래에 wj_nand.c 파일을 만들고, 아래와 같이 입력한다.

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/string.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <mach/hardware.h>
#include <mach/pxa-regs.h>
 
 
#define EZ_NAND_BASE_PHY        (PXA_CS1_PHYS+0x000000)
#define EZ_NAND_RANGE           (0x1000)
 
 
#define EZ_NAND_ACCESS_START()  GPCR(81) = GPIO_bit(81)
#define EZ_NAND_DATA            (0x000)
#define EZ_NAND_CMD             (0x100)
#define EZ_NAND_ADDR            (0x200)
//#define EZ_NAND_ACCESS_END()    GPSR(81) = GPIO_bit(81)
 
#define EZ_NAND_ACCESS_END   (0x300)
 
 
#define NAND_BIG_DELAY_US       25
#define NAND_SMALL_DELAY_US     15
 
static struct mtd_info *ez_board_nand_mtd = NULL;
 
//#define SZ_1M     (1024*1024)
 
 
static char *cmdline_par;
 
/*
 * Define partitions for flash device
 */
#ifdef CONFIG_MTD_PARTITIONS
static struct mtd_partition partition_info[] =
{
    {
        .name   = "EZ-X5 Kernel partition",
        .offset = 0x000000,
        .size   = 2*SZ_1M
    },
    {
        .name   = "EZ-X5 Ramdisk partition",
        .offset = 0x200000,
        .size   = 5*SZ_1M
    },
    {
        .name   = "EZ-X5 Data partition 0",
        .offset = 0x700000,
        .size   = 57*SZ_1M
    }
};
#define EZ_X5_NAND_NUM_PARTITIONS   3
#endif
 
// Ä¿³Î Ä¿¸Çµå¶óÀÎÀ» ÆÄ½ÌÇÑ´Ù.
static void fixup_partition_info( void )
{
    char *delim_ = ",";
    int  argc;
    char *argv[256];
    char *tok;
    int  size[3];
 
    argc       = 0;
    argv[argc] = NULL;
    for (tok = strsep( &cmdline_par, delim_); tok; tok = strsep( &cmdline_par, delim_))
    {
        argv[argc++] = tok;
    }
 
    if ( argc == EZ_X5_NAND_NUM_PARTITIONS )
    {
        size[0] = simple_strtoul( argv[0],NULL,0 );
        size[1] = simple_strtoul( argv[1],NULL,0 );
        size[2] = simple_strtoul( argv[2],NULL,0 );
 
        if ( ( size[0] > 0 ) && ( size[1] > 0 ) && ( size[2] > 0 ) )
        {
            partition_info[0].offset = 0;
            partition_info[0].size   = size[0]*SZ_1M;
 
            partition_info[1].offset = size[0]*SZ_1M;
            partition_info[1].size   = size[1]*SZ_1M;
 
            partition_info[2].offset = (size[0]+size[1])*SZ_1M;
            partition_info[2].size   =  size[2]*SZ_1M;
        }
    }
}
 
/* 
 *  hardware specific access to control-lines
*/
void ez_board_nand0_hwcontrol(struct mtd_info *mtd, int cmd)
{
    int dummy;
    register struct nand_chip *this = mtd->priv;
    register unsigned long NAND_IO_ADDR = this->IO_ADDR_W;
 
#if 0
 
    switch(cmd)
    {
    case NAND_NCE:  EZ_NAND_ACCESS_START();  break; 
    case NAND_CLE:  EZ_NAND_ACCESS_END();    break;
    }
 
#else
 
    switch(cmd)
    {
        case NAND_NCE: dummy = readb(NAND_IO_ADDR + EZ_NAND_DATA)      ; break;
        case NAND_CLE: dummy = readb(NAND_IO_ADDR + EZ_NAND_ACCESS_END); break;
    }
 
#endif
 
 
}
 
/*
 * Send command to NAND device
 */
void ez_board_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 + EZ_NAND_CMD );
    }
    else
    {
        if (mtd->writesize == 256 && column >= 256)
        {
            column -= 256;
            writeb (NAND_CMD_READOOB, NAND_IO_ADDR + EZ_NAND_CMD );
            writeb (NAND_CMD_SEQIN  , NAND_IO_ADDR + EZ_NAND_CMD );
        }
        else if (mtd->writesize == 512 && column >= 256)
        {
            if (column < 512)
            {
                column -= 256;
                writeb (NAND_CMD_READ1, NAND_IO_ADDR + EZ_NAND_CMD);
                writeb (NAND_CMD_SEQIN, NAND_IO_ADDR + EZ_NAND_CMD);
            }
            else
            {
                column -= 512;
                writeb (NAND_CMD_READOOB, NAND_IO_ADDR + EZ_NAND_CMD);
                writeb (NAND_CMD_SEQIN  , NAND_IO_ADDR + EZ_NAND_CMD);
            }
        }
        else
        {
            writeb (NAND_CMD_READ0      , NAND_IO_ADDR + EZ_NAND_CMD);
            writeb (NAND_CMD_SEQIN      , NAND_IO_ADDR + EZ_NAND_CMD);
        }
    }
 
    // Serially input address 
    if (column != -1 || page_addr != -1)
    {
        if (column != -1) writeb (column, NAND_IO_ADDR + EZ_NAND_ADDR);
        if (page_addr != -1)
        {
            writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR + EZ_NAND_ADDR);
            writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR + EZ_NAND_ADDR);
            // One more address cycle for higher density devices 
            if (mtd->size & 0x0c000000)
            {
               writeb ((unsigned char) ((page_addr >> 16) & 0x0f), NAND_IO_ADDR + EZ_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 + EZ_NAND_CMD);
        while ( !(readb (this->IO_ADDR_R) & 0x40));
        return;
 
    default:
        if (!this->dev_ready)
        {
            udelay (this->chip_delay);
            return;
        }
    }
 
    while (!this->dev_ready(mtd));
 
}
 
/*
 * Main initialization routine
 */
static int __init ez_board_nand_init (void)
{
    struct nand_chip *this;
        unsigned long nand_base_virt;
 
    //  Allocate memory for MTD device structure and private data 
    ez_board_nand_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL);
    if (!ez_board_nand_mtd)
    {
        printk ("Unable to allocate EZ-X5-NAND MTD device structure.\n");
        return -ENOMEM;
    }
 
    // Get pointer to private data 
    this = (struct nand_chip *) (&ez_board_nand_mtd[1]);
 
    // Initialize structures 
    memset((char *) ez_board_nand_mtd, 0, sizeof(struct mtd_info));
    memset((char *) this, 0, sizeof(struct nand_chip));
 
    // Link the private data with the MTD structure 
    ez_board_nand_mtd->priv = this;
 
    // Set address of NAND IO lines 
        nand_base_virt = (unsigned long )  ioremap( EZ_NAND_BASE_PHY, EZ_NAND_RANGE );
    this->IO_ADDR_R = nand_base_virt + EZ_NAND_DATA;
    this->IO_ADDR_W = nand_base_virt + EZ_NAND_DATA;
    // Set address of hardware control function 
    this->cmd_ctrl = ez_board_nand0_hwcontrol;
    // Set commamd function 
    this->cmdfunc = ez_board_nand_command ;
    // 15 us command delay time 
    this->chip_delay = NAND_SMALL_DELAY_US;
    this->ecc.mode = NAND_ECC_SOFT;
 
    // Scan to find existence of the device 
    if (nand_scan (ez_board_nand_mtd,1))
    {
        kfree (ez_board_nand_mtd);
        return -ENXIO;
    }
 
    // Allocate memory for internal data buffer 
    this->buffers = kmalloc (sizeof(u_char) * (ez_board_nand_mtd->writesize + ez_board_nand_mtd->oobsize), GFP_KERNEL);
    if (!this->buffers)
    {
        printk ("Unable to allocate NAND data buffer for EZ_IXP42X-NAND.\n");
        kfree (ez_board_nand_mtd);
        return -ENOMEM;
    }
 
    // Ä¿³ÎÄ¿¸Çµå¿¡¼­ Á¤º¸¸¦ ¾ò´Â´Ù 
    fixup_partition_info();
 
    // Register the partitions 
    add_mtd_partitions(ez_board_nand_mtd, partition_info, EZ_X5_NAND_NUM_PARTITIONS);
 
    // Return happy 
    return 0;
}
 
module_init(ez_board_nand_init);
 
 
/*
 * Clean up routine
 */
#ifdef MODULE
static void __exit ez_board_nand_cleanup (void)
{
    struct nand_chip *this = (struct nand_chip *) &ez_board_nand_mtd[0];
 
    // Unregister the device 
    del_mtd_device (ez_board_nand_mtd);
 
    // Free internal data buffer 
    kfree (this->data_buf);
 
    // Free the MTD device structure 
    kfree (ez_board_nand_mtd);
}
module_exit(ez_board_nand_cleanup);
#endif
 
static int __init nandpart_setup(char *s)
{
    cmdline_par = s;
    return 1;
}
 
__setup("nandparts=", nandpart_setup);
 
 
MODULE_AUTHOR("You Youngchang,jang hyung-gi <frog@falinux.com");
MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on EZ-X5-NAND board");
MODULE_LICENSE("GPL");

이제 커널 빌드에 추가하기 위해 옵션을 추가한다. drivers/mtd/nand/Kconfig 파일에 다음을 추가한다.

...
config MTD_NAND_WJ_X5
    tristate "NAND Flash device on WJ-X5 board"
    depends on MACH_WJ_X5 && MTD_NAND
    help
      This enables the NAND flash driver on the WJ-X5 Board.
...
config MTD_NAND_S3C2410

마지막으로 drivers/mtd/nand/Makefile 파일을 추가한다.

...
obj-$(CONFIG_MTD_NAND_WJ_X5)    += wj_nand.o
...

이제 앞서 추가한 커널 옵션을 추가해보자!

Device Drivers  --->  
 
                 <*> Memory Technology Device (MTD) support  ---> 
 
                  [*]   MTD partitioning support
                  < >     RedBoot partition table parsing
                  [ ]     Command line partition table parsing
                 < >     ARM Firmware Suite partition parsing
                 < >     TI AR7 partitioning support
                   *** User Modules And Translation Layers ***
                  <*>   Direct char device access to MTD devices
                   -*-   Common interface to block layer for MTD 'translation layers
                   <*>   Caching block device access to MTD devices
 
                  <*>   NAND Device Support  --->
                          <*>   NAND Flash device on WJ-X5 board

커널 빌드 후에 부팅시켜보자. 아래와 같이 낸드 플래시에 대한 로그가 보인다면 제대로 인식한 것이다.

NAND device: Manufacturer ID:0xec, Chip ID:0x76 (Samsung NAND 64MiB 3,3V 8-bit)
Scanning device for bad blocks
Creating 3 MTD partitions on "NAND 64MiB 3,3V 8-bit":
0x00000000-0x00100000 : "falinux boot/config/logo partition"
0x00100000-0x00900000 : "falinux kernel/ramdisk partition"
0x00900000-0x04000000 : "falinux yaffs partition"

JFFS2 사용하기

이제는 인식한 낸드 플래시를 사용하기 위해 파일시스템을 커널에 추가해보자. 우선 JFFS2 부터 하겠다.
JFFS2 는 YAFFS2 와는 달리 커널에 포함되어 있기 때문에 별도의 패치 없이 바로 커널 옵션에서 추가할 수 있다.

File systems  --->      
Miscellaneous filesystems  ---> 
 
     <*> Journalling Flash File System v2 (JFFS2) support
                      (0)   JFFS2 debugging verbosity (0 = quiet, 2 = noisy) (NEW)
                      [*]   JFFS2 write-buffering support (NEW)
                      [ ]     Verify JFFS2 write-buffer reads (NEW)
                      [ ]   JFFS2 summary support (EXPERIMENTAL) (NEW)
                      [ ]   JFFS2 XATTR support (EXPERIMENTAL) (NEW)
                      [ ]   Advanced compression options for JFFS2 (NEW)

커널을 빌드하자.
이제 마지막으로 낸드 플래시를 JFFS2 로 포맷할 프로그램이 필요하다. MTD Utilities 이라는 소스코드를 따로 빌드해도 되지만, 여기서는 busybox 에도 동일한 코드가 들어있기 때문에 이를 사용한다. 우리가 필요한 것은 flash_eraseall 이라는 실행파일이다.

빌드한 busybox(빌드시 flash_eraseall 를 선택했다)를 타겟보드에 올리고, 다음과 같이 실행한다.

[root@falinux ~]$ cat /proc/mtd 
dev:    size   erasesize  name
mtd0: 00100000 00004000 "EZ-X5 Kernel partition"
mtd1: 00800000 00004000 "EZ-X5 Ramdisk partition"
mtd2: 03700000 00004000 "EZ-X5 Data partition 0"

현재 낸드 플래시의 파티션이 보인다. 여기서는 가장 큰 사이즈를 차지하는 mtd2 파티션을 포맷한다. -j 옵션은 JFFS2 를 위한 포맷이다.

#./busybox flash_eraseall -j /dev/mtd2
Erasing 64 Kibyte @ 10000 --  100 % complete

이제 마운트를 해보자.

#mount -t jffs2 /dev/mtdblock2 /app

에러없이 수행되었다면, 해당 디렉토리에서 파일을 생성하고 지워보자. 그리고 보드 전원을 끄고, 남아있는지 확인하자.

YAFFS2 사용하기

YAFFS2 는 커널에 기본적으로 포함되지 않기 때문에 패치를 해줘야 한다. 먼저 코드를 다운받기 위해서 http://www.yaffs.net/ 에 접속하자.
패치하는 방법은 다음과 같다.

#cd yaffs2
#./patch-ker.sh c m /opt/linux-2.6.28                // c 는 copy, m 은 멀티버전, 그리고 커널 소스 경로를 적어준다.

이제 menuconfig 를 통해 커널 옵션을 지정해보자.

File systems  --->      
Miscellaneous filesystems  ---> 
                              <*> yaffs2 file system support
                                     -*-   512 byte / page devices
                                     [*]     Use older-style on-NAND data format with pageStatus byte
                                     -*-   2048 byte (or larger) / page devices
                                     [ ]     Autoselect yaffs2 format
                                     [*]     Disable yaffs from doing ECC on tags by default
                                     [*]   Force chunk erase check
                                     [*]   Empty lost and found on boot
                                     [*]   Disable yaffs2 block refreshing
                                     [*]   Disable yaffs2 background processing
                                     [*]   Enable yaffs2 xattr support
                                     <*> Journalling Flash File System v2 (JFFS2) support
                                     (0)   JFFS2 debugging verbosity (0 = quiet, 2 = noisy)
                                     [*]   JFFS2 write-buffering support
                                     [ ]     Verify JFFS2 write-buffer reads
                                     [ ]   JFFS2 summary support (EXPERIMENTAL)
                                     [ ]   JFFS2 XATTR support (EXPERIMENTAL)
                                     [ ]   Advanced compression options for JFFS2

이제 빌드하고 부팅해서, 앞서와 마찬가지로 파티션을 포맷하자.

#./busybox flash_eraseall /dev/mtd2
Erasing 64 Kibyte @ 10000 --  100 % complete

그리고 마운트를 해보자.

#mount -t yaffs2 /dev/mtdblock2 /app

파일을 삭제하고 생성해보자. 그리고 보드 전원을 끄고, 남아있는지 확인하자.

FAQ

[root@falinux app]$ cat /proc/mtd 
dev:    size   erasesize  name
mtd0: 00200000 00004000 "EZ-X5 Kernel partition"
mtd1: 00500000 00004000 "EZ-X5 Ramdisk partition"
mtd2: 03900000 00004000 "EZ-X5 Data partition 0"
 
YAFFS built:Jan 13 2013 23:57:58
$Id:    yaffs_fs.c,v 1.32 2003/10/29 20:42:34 charles
$Id: yaffs_guts.c,v 1.33 2003/11/16 07:40:42 charles
 
 
 
Device yaffs
startBlock......... 1
endBlock........... 3647
chunkGroupBits..... 1
chunkGroupSize..... 2
nErasedBlocks...... 3646
nTnodesCreated..... 100
nFreeTnodes........ 67
nObjectsCreated.... 100
nFreeObjects....... 92
nFreeChunks........ 116699
nPageWrites........ 4
nPageReads......... 22
nBlockErasures..... 0
nGCCopies.......... 0
garbageCollections. 0
passiveGCs......... 0
nRetriedWrites..... 0
nRetireBlocks...... 0
eccFixed........... 0
eccUnfixed......... 0
tagsEccFixed....... 0
tagsEccUnfixed..... 3652
cacheHits.......... 0
nDeletedFiles...... 0
nUnlinkedFiles..... 0
nBackgroudDeletions 0
useNANDECC......... 0
[root@falinux app]$

성공 화면

Copy Kernel Image .....
Copy Ramdisk Image .....
Starting kernel [MARCH 3002]...
kernel command [EZBOOT mem=64M initrd=0xA0800000,5M root=/dev/ram ramdisk=16384 console=ttyPXA2,115200    ip0=1.1.1.2 mac=00:FA:07:78:65:05 netmask=255.255.255.0 gw=192.]
Uncompressing Linux............................................................................................................. done, booting the kernel.
Linux version 2.6.21-falinux (gemini@hw27) (gcc version 3.4.3) #1 Mon Jun 30 20:37:01 KST 2008
CPU: XScale-PXA255 [69052d06] revision 6 (ARMv5TE), cr=0000397f
Machine: FALinux EZ-X5 Development Platform
Memory policy: ECC disabled, Data cache writeback
Memory clock: 99.53MHz (*27)
Run Mode clock: 398.13MHz (*4)
Turbo Mode clock: 398.13MHz (*1.0, inactive)
CPU0: D VIVT undefined 5 cache
CPU0: I cache: 32768 bytes, associativity 32, 32 byte lines, 32 sets
CPU0: D cache: 32768 bytes, associativity 32, 32 byte lines, 32 sets
Built 1 zonelists.  Total pages: 16256
Kernel command line: EZBOOT mem=64M initrd=0xA0800000,5M root=/dev/ram ramdisk=16384 console=ttyPXA2,115200    ip0=1.1.1.2 mac=00:FA:07:78:65:05 netmask=255.255.255.0 gw 
PID hash table entries: 256 (order: 8, 1024 bytes)
Console: colour dummy device 80x30
Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
Memory: 64MB = 64MB total
Memory: 56320KB available (3012K code, 361K data, 108K init)
Security Framework v1.0.0 initialized
SELinux:  Initializing.
selinux_register_security:  Registering secondary module capability
Capability LSM initialized as secondary
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
NET: Registered protocol family 16
SCSI subsystem initialized
NET: Registered protocol family 2
Time: pxa_timer clocksource has been installed.
IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
TCP established hash table entries: 2048 (order: 2, 16384 bytes)
TCP bind hash table entries: 2048 (order: 1, 8192 bytes)
TCP: Hash tables configured (established 2048 bind 2048)
TCP reno registered
checking if image is initramfs...it isn't (no cpio magic); looks like an initrd
Freeing initrd memory: 5120K
NetWinder Floating Point Emulator V0.97 (double precision)
audit: initializing netlink socket (disabled)
audit(8.699:1): initialized
yaffs Jun 30 2008 20:35:14 Installing. 
io scheduler noop registered
io scheduler anticipatory registered
io scheduler deadline registered
io scheduler cfq registered (default)
pxa2xx-uart.0: ttyPXA0 at MMIO 0x40100000 (irq = 15) is a FFUART
pxa2xx-uart.1: ttyPXA1 at MMIO 0x40200000 (irq = 14) is a BTUART
pxa2xx-uart.2: ttyPXA2 at MMIO 0x40700000 (irq = 13) is a STUART
pxa2xx-uart.3: ttyPXA3 at MMIO 0x41600000 (irq = 0) is a HWUART
RAMDISK driver initialized: 16 RAM disks of 16384K size 1024 blocksize
loop: loaded (max 8 devices)
eth0: cs8900 rev J found at 0xf1000300 [Cirrus EEPROM] 
cs89x0 media RJ-45, IRQ 44, programmed I/O, MAC 00:fa:07:78:65:05
NAND device: Manufacturer ID:0xec, Chip ID:0x76 (Samsung NAND 64MiB 3,3V 8-bit)
Scanning device for bad blocks
Creating 3 MTD partitions on "NAND 64MiB 3,3V 8-bit":
0x00000000-0x00100000 : "falinux boot/config/logo partition"
0x00100000-0x00900000 : "falinux kernel/ramdisk partition"
0x00900000-0x04000000 : "falinux yaffs partition"
mice: PS/2 mouse device common for all mice
i2c /dev entries driver
I2C: i2c-0: PXA I2C adapter
TCP cubic registered
NET: Registered protocol family 1
NET: Registered protocol family 10
lo: Disabled Privacy Extensions
Mobile IPv6
IPv6 over IPv4 tunneling driver
sit0: Disabled Privacy Extensions
NET: Registered protocol family 17
XScale DSP coprocessor detected.
RAMDISK: Compressed image found at block 0
VFS: Mounted root (ext2 filesystem) readonly.
Freeing init memory: 108K
INIT: version 2.86 booting
INIT: Entering runlevel: 3
eth0: using full-duplex 10Base-T (RJ-45)
route: SIOC[ADD|DEL]RT: Network is unreachable
yaffs: dev is 32505858 name is "mtdblock2"
yaffs: passed flags ""
yaffs: Attempting MTD mount on 31.2, "mtdblock2"
yaffs: auto selecting yaffs1
/usr/local/apache/bin/apachectl start: httpd started
Starting system logger: [  OK  ]
Starting INET services: [  OK  ]
 
 
Welcome to FALinux (www.falinux.com)
Linux Kernel 2.6.21-falinux
falinux login: root
[root@falinux ~]$ df
Filesystem           1k-blocks      Used Available Use% Mounted on
/dev/ram                 15863     11945      3099  79% /
/dev/mtdblock2           56320       100     56220   0% /app
[root@falinux ~]$ 
  • computer/embedded/이지보드-x5_에_디바이스_드라이버_포팅하기_-_nand_flash.txt
  • Last modified: 4 years ago
  • by likewind