Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
2301_76519099
rt-thread
提交
bc5a5f89
R
rt-thread
项目概览
2301_76519099
/
rt-thread
与 Fork 源项目一致
Fork自
RT-Thread / rt-thread
通知
3
Star
1
Fork
1
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rt-thread
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
bc5a5f89
编写于
9月 18, 2018
作者:
H
heyuanjie87
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
添加新的mtd接口
上级
1abe8353
变更
9
显示空白变更内容
内联
并排
Showing
9 changed file
with
1264 addition
and
1 deletion
+1264
-1
components/drivers/Kconfig
components/drivers/Kconfig
+14
-1
components/drivers/include/drivers/mtd.h
components/drivers/include/drivers/mtd.h
+118
-0
components/drivers/include/drivers/mtdnand.h
components/drivers/include/drivers/mtdnand.h
+118
-0
components/drivers/include/drivers/mtdnor.h
components/drivers/include/drivers/mtdnor.h
+48
-0
components/drivers/include/rtdevice.h
components/drivers/include/rtdevice.h
+7
-0
components/drivers/mtd/SConscript
components/drivers/mtd/SConscript
+11
-0
components/drivers/mtd/mtd.c
components/drivers/mtd/mtd.c
+225
-0
components/drivers/mtd/mtdnand.c
components/drivers/mtd/mtdnand.c
+636
-0
components/drivers/mtd/mtdnor.c
components/drivers/mtd/mtdnor.c
+87
-0
未找到文件。
components/drivers/Kconfig
浏览文件 @
bc5a5f89
...
...
@@ -90,6 +90,20 @@ config RT_USING_MTD_NAND
default n
endif
config RT_USING_MTD
bool "Using Memory Technology Device (MTD)"
default n
if RT_USING_MTD
config MTD_USING_NOR
bool "Using MTD Nor Flash device"
default n
config MTD_USING_NAND
bool "Using MTD Nand Flash device"
default n
endif
config RT_USING_RTC
bool "Using RTC device drivers"
default n
...
...
@@ -138,7 +152,6 @@ config RT_USING_SDIO
config RT_MMCSD_MAX_PARTITION
int "mmcsd max partition"
default 16
config RT_SDIO_DEBUG
bool "Enable SDIO debug log output"
default n
...
...
components/drivers/include/drivers/mtd.h
0 → 100644
浏览文件 @
bc5a5f89
/*
* File : mtd.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2012, Shanghai Real-Thread Technology Co., Ltd
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-7-5 heyuanjie the first version
*/
#ifndef __MTD_H__
#define __MTD_H__
#include <rtthread.h>
#include <stddef.h>
#include <stdint.h>
#define MTD_TYPE_NOR 1
#define MTD_TYPE_NAND 2
/**
* MTD operation modes
*
* @MTD_OPM_PLACE_OOB: OOB data are placed at the given offset (default)
* @MTD_OPM_AUTO_OOB: OOB data are automatically placed at the free areas
* @MTD_OPM_RAW: data are transferred as-is, with no error correction;
*/
enum
mtd_opm
{
MTD_OPM_PLACE_OOB
=
0
,
MTD_OPM_AUTO_OOB
=
1
,
MTD_OPM_RAW
=
2
,
};
#ifndef loff_t
typedef
long
loff_t
;
#endif
struct
mtd_oob_region
{
uint8_t
offset
;
uint8_t
length
;
};
typedef
struct
mtd_info
{
struct
rt_device
parent
;
const
struct
mtd_ops
*
ops
;
uint16_t
oob_size
;
uint16_t
sector_size
;
/* Minimal writable flash unit size */
uint32_t
block_size
:
28
;
/* Erase size for the device */
uint32_t
type
:
4
;
size_t
size
;
/* Total size of the MTD */
loff_t
offset
;
/* At which this MTD starts, from the beginning of the MEMORY */
struct
mtd_info
*
master
;
void
*
priv
;
}
rt_mtd_t
;
struct
mtd_io_desc
{
uint8_t
mode
;
/* operation mode(enum mtd_opm) */
uint8_t
ooblen
;
/* number of oob bytes to write/read */
uint8_t
oobretlen
;
/* number of oob bytes written/read */
uint8_t
ooboffs
;
/* offset in the oob area */
uint8_t
*
oobbuf
;
size_t
datlen
;
/* number of data bytes to write/read */
size_t
datretlen
;
/* number of data bytes written/read */
uint8_t
*
datbuf
;
/* if NULL only oob are read/written */
};
struct
mtd_ops
{
int
(
*
erase
)(
rt_mtd_t
*
mtd
,
loff_t
addr
,
size_t
len
);
/* return 0 if success */
int
(
*
read
)
(
rt_mtd_t
*
mtd
,
loff_t
from
,
struct
mtd_io_desc
*
ops
);
/* return 0 if success */
int
(
*
write
)
(
rt_mtd_t
*
mtd
,
loff_t
to
,
struct
mtd_io_desc
*
ops
);
/* return 0 if success */
int
(
*
isbad
)
(
rt_mtd_t
*
mtd
,
uint32_t
block
);
/* return 1 if bad, 0 not bad */
int
(
*
markbad
)
(
rt_mtd_t
*
mtd
,
uint32_t
block
);
/* return 0 if success */
};
struct
mtd_part
{
const
char
*
name
;
/* name of the MTD partion */
loff_t
offset
;
/* start addr of partion */
size_t
size
;
/* size of partion */
};
int
rt_mtd_erase
(
rt_mtd_t
*
mtd
,
loff_t
addr
,
size_t
size
);
int
rt_mtd_block_erase
(
rt_mtd_t
*
mtd
,
uint32_t
block
);
int
rt_mtd_read_oob
(
rt_mtd_t
*
mtd
,
loff_t
from
,
struct
mtd_io_desc
*
desc
);
int
rt_mtd_write_oob
(
rt_mtd_t
*
mtd
,
loff_t
to
,
struct
mtd_io_desc
*
desc
);
int
rt_mtd_read
(
rt_mtd_t
*
mtd
,
loff_t
from
,
uint8_t
*
buf
,
size_t
len
);
int
rt_mtd_write
(
rt_mtd_t
*
mtd
,
loff_t
to
,
const
uint8_t
*
buf
,
size_t
len
);
int
rt_mtd_block_markbad
(
rt_mtd_t
*
mtd
,
uint32_t
block
);
int
rt_mtd_block_isbad
(
rt_mtd_t
*
mtd
,
uint32_t
block
);
rt_mtd_t
*
rt_mtd_get
(
const
char
*
name
);
int
rt_mtd_register
(
rt_mtd_t
*
master
,
const
struct
mtd_part
*
parts
,
int
np
);
#endif
components/drivers/include/drivers/mtdnand.h
0 → 100644
浏览文件 @
bc5a5f89
/*
* File : nand.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-7-8 heyuanjie the first version
*/
/*
* COPYRIGHT (C) 2012, Shanghai Real Thread
*/
#ifndef _MTDNAND_H_
#define _MTDNAND_H_
#include "mtd.h"
/* Status bits */
#define NAND_STATUS_FAIL 0x01
#define NAND_STATUS_FAIL_N1 0x02
#define NAND_STATUS_WP 0x80
typedef
enum
{
NAND_CMD_PAGE_RD
,
/* read data to chip's page buffer,do WaitBusy after this cmd in low driver */
NAND_CMD_PAGE_WR0
,
/* write data to chip's page buffer */
NAND_CMD_PAGE_WR1
,
/* do flash programe */
NAND_CMD_BLK_ERASE
,
/* erase block */
NAND_CMD_ECC_EN
,
/* enable gen HWECC */
NAND_CMD_ECC_DIS
/* disable gen HWECC */
}
nand_cmd_t
;
typedef
enum
{
NAND_ECCM_NONE
,
NAND_ECCM_HW
,
}
nand_eccmode_t
;
struct
nand_chip
;
struct
nand_ops
;
/**
* struct nand_buffers - buffer structure for read/write
* @ecccalc: buffer pointer for calculated ECC, size is oobsize.
* @ecccode: buffer pointer for ECC read from flash, size is oobsize.
*
*/
struct
nand_buffers
{
uint8_t
*
ecccalc
;
uint8_t
*
ecccode
;
};
struct
nand_ecc
{
uint8_t
mode
;
/* nand_eccmode_t */
uint8_t
bytes
;
/* gen ecc bytes per ecc step(usually 3) */
uint16_t
stepsize
:
12
;
/* min 256 */
uint16_t
_step
:
4
;
/* */
/* driver must set the two interface if HWECC */
void
(
*
calculate
)(
struct
nand_chip
*
chip
,
const
uint8_t
*
dat
,
uint8_t
*
ecc_code
);
/* return max bit flips if can't correct,return -1 ECC is error(0 success) */
int
(
*
correct
)(
struct
nand_chip
*
chip
,
uint8_t
*
dat
,
uint8_t
*
read_ecc
,
uint8_t
*
calc_ecc
);
/* ignore if NONECC */
const
struct
mtd_oob_region
*
layout
;
};
typedef
struct
nand_chip
{
rt_mtd_t
parent
;
/* driver must init these */
const
struct
nand_ops
*
ops
;
struct
nand_ecc
ecc
;
const
struct
mtd_oob_region
*
freelayout
;
/* driver do not touch */
struct
nand_buffers
buffers
;
uint8_t
*
oob_poi
;
uint8_t
*
pagebuf
;
uint32_t
size
;
uint16_t
oobsize
;
uint8_t
pages_pb
;
uint16_t
page_size
;
int
(
*
read_page
)(
struct
nand_chip
*
chip
,
uint8_t
*
buf
,
int
oob_required
,
int
page
);
int
(
*
write_page
)(
struct
nand_chip
*
chip
,
const
uint8_t
*
buf
,
int
oob_required
,
int
page
);
}
rt_nand_t
;
struct
nand_ops
{
int
(
*
cmdfunc
)(
rt_nand_t
*
nand
,
int
cmd
,
int
page
,
int
offset
);
/* send nand operation cmd, return Status bits(0 success),
if nand is busy please wait in low driver */
int
(
*
read_buf
)(
rt_nand_t
*
nand
,
uint8_t
*
buf
,
int
len
);
/* read data from nand chip's page buffer */
int
(
*
write_buf
)(
rt_nand_t
*
nand
,
const
uint8_t
*
buf
,
int
len
);
/* write data to nand chip's page buffer */
int
(
*
isbad
)(
rt_nand_t
*
nand
,
uint32_t
blk
);
/* if NULL OOB[0] used as bad mark(not 0xff is bad) */
int
(
*
markbad
)(
rt_nand_t
*
nand
,
uint32_t
blk
);
/* if NULL OOB[0] used as bad mark(set to 0x00) */
};
int
rt_mtd_nand_init
(
rt_nand_t
*
nand
,
int
blk_size
,
int
page_size
,
int
blks_pc
,
int
oob_size
);
#endif
/* MTD_NAND_H_ */
components/drivers/include/drivers/mtdnor.h
0 → 100644
浏览文件 @
bc5a5f89
/*
* File : mtdnor.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2012, Shanghai Real-Thread Technology Co., Ltd
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-8-30 heyuanjie the first version
*/
#ifndef __MTDNOR_H__
#define __MTDNOR_H__
#include <drivers/mtd.h>
struct
nor_ops
;
typedef
struct
{
rt_mtd_t
parent
;
const
struct
nor_ops
*
ops
;
/* operations interface */
}
rt_nor_t
;
struct
nor_ops
{
int
(
*
erase
)(
rt_nor_t
*
nor
,
loff_t
addr
,
size_t
len
);
/* return success erased len or error code */
int
(
*
read
)(
rt_nor_t
*
nor
,
loff_t
addr
,
uint8_t
*
buf
,
size_t
len
);
/* return success data size or error code */
int
(
*
write
)(
rt_nor_t
*
nor
,
loff_t
addr
,
const
uint8_t
*
buf
,
size_t
len
);
/* return success data size or error code */
};
int
rt_mtd_nor_init
(
rt_nor_t
*
nor
,
int
blksize
);
#endif
components/drivers/include/rtdevice.h
浏览文件 @
bc5a5f89
...
...
@@ -117,6 +117,13 @@ extern "C" {
#include "drivers/rt_drv_pwm.h"
#endif
#ifdef MTD_USING_NOR
#include "drivers/mtdnor.h"
#endif
#ifdef MTD_USING_NAND
#include "drivers/mtdnand.h"
#endif
#ifdef __cplusplus
}
#endif
...
...
components/drivers/mtd/SConscript
浏览文件 @
bc5a5f89
...
...
@@ -9,6 +9,17 @@ depend = []
CPPPATH
=
[
cwd
+
'/../include'
]
group
=
[]
if
GetDepend
([
'RT_USING_MTD'
]):
src
+=
[
'mtd.c'
]
depend
+=
[
'RT_USING_MTD'
]
if
GetDepend
([
'MTD_USING_NOR'
]):
src
+=
[
'mtdnor.c'
]
depend
+=
[
'MTD_USING_NOR'
]
if
GetDepend
([
'MTD_USING_NAND'
]):
src
+=
[
'mtdnand.c'
]
depend
+=
[
'MTD_USING_NAND'
]
if
GetDepend
([
'RT_USING_MTD_NOR'
]):
src
+=
[
'mtd_nor.c'
]
depend
+=
[
'RT_USING_MTD_NOR'
]
...
...
components/drivers/mtd/mtd.c
0 → 100644
浏览文件 @
bc5a5f89
#include <drivers/mtd.h>
static
rt_mtd_t
*
mtd_part_alloc
(
rt_mtd_t
*
master
,
const
struct
mtd_part
*
part
)
{
rt_mtd_t
*
slave
;
slave
=
rt_malloc
(
sizeof
(
rt_mtd_t
));
if
(
slave
==
RT_NULL
)
goto
out
;
slave
->
master
=
master
;
*
slave
=
*
master
;
slave
->
size
=
part
->
size
;
slave
->
offset
=
part
->
offset
;
out:
return
slave
;
}
rt_mtd_t
*
rt_mtd_get
(
const
char
*
name
)
{
rt_mtd_t
*
mtd
;
mtd
=
(
rt_mtd_t
*
)
rt_device_find
(
name
);
if
(
mtd
==
RT_NULL
)
return
RT_NULL
;
if
(
mtd
->
parent
.
type
!=
RT_Device_Class_MTD
)
return
RT_NULL
;
return
mtd
;
}
/*
* Register MTD driver
*
* @parts partion description
* @np number of partitions
* @return number of unregistered partitions
*
*/
int
rt_mtd_register
(
rt_mtd_t
*
master
,
const
struct
mtd_part
*
parts
,
int
np
)
{
int
ret
;
rt_mtd_t
*
slave
;
master
->
master
=
master
;
master
->
parent
.
type
=
RT_Device_Class_MTD
;
if
(
np
>
0
)
{
master
->
offset
=
parts
->
offset
;
master
->
size
=
parts
->
size
;
ret
=
rt_device_register
((
rt_device_t
)
master
,
parts
->
name
,
0
);
if
(
ret
!=
0
)
goto
_out
;
np
--
;
parts
++
;
}
while
(
np
>
0
)
{
slave
=
mtd_part_alloc
(
master
,
parts
);
if
(
!
slave
)
break
;
ret
=
rt_device_register
((
rt_device_t
)
slave
,
parts
->
name
,
0
);
if
(
ret
)
break
;
parts
++
;
np
--
;
}
_out:
return
np
;
}
int
rt_mtd_block_erase
(
rt_mtd_t
*
mtd
,
uint32_t
block
)
{
uint32_t
total_blks
;
loff_t
addr
;
total_blks
=
mtd
->
size
/
mtd
->
block_size
;
if
(
block
>=
total_blks
)
return
-
EINVAL
;
addr
=
mtd
->
offset
+
mtd
->
block_size
*
block
;
return
mtd
->
ops
->
erase
(
mtd
->
master
,
addr
,
mtd
->
block_size
);
}
int
rt_mtd_block_isbad
(
rt_mtd_t
*
mtd
,
uint32_t
block
)
{
uint32_t
total_blks
,
offset_blk
;
if
(
!
mtd
->
ops
->
isbad
)
return
0
;
total_blks
=
mtd
->
size
/
mtd
->
block_size
;
if
(
block
>=
total_blks
)
return
-
EINVAL
;
offset_blk
=
mtd
->
offset
/
mtd
->
block_size
;
return
mtd
->
ops
->
isbad
(
mtd
->
master
,
block
+
offset_blk
);
}
int
rt_mtd_block_markbad
(
rt_mtd_t
*
mtd
,
uint32_t
block
)
{
uint32_t
total_blks
,
offset_blk
;
if
(
!
mtd
->
ops
->
markbad
)
return
-
EOPNOTSUPP
;
total_blks
=
mtd
->
size
/
mtd
->
block_size
;
if
(
block
>=
total_blks
)
return
-
EINVAL
;
offset_blk
=
mtd
->
offset
/
mtd
->
block_size
;
return
mtd
->
ops
->
markbad
(
mtd
->
master
,
block
+
offset_blk
);
}
int
rt_mtd_erase
(
rt_mtd_t
*
mtd
,
loff_t
addr
,
size_t
size
)
{
if
(
addr
>
mtd
->
size
||
(
addr
+
size
)
>
mtd
->
size
)
return
-
EINVAL
;
addr
+=
mtd
->
offset
;
return
mtd
->
ops
->
erase
(
mtd
->
master
,
addr
,
size
);
}
/*
* Read data only
*
* @from offset to read from
* @return success size or error code
*/
int
rt_mtd_read
(
rt_mtd_t
*
mtd
,
loff_t
from
,
uint8_t
*
buf
,
size_t
len
)
{
int
ret
;
struct
mtd_io_desc
desc
=
{
0
};
if
(
from
<
0
||
from
>=
(
loff_t
)
mtd
->
size
||
len
>
mtd
->
size
-
from
)
return
-
EINVAL
;
if
(
!
len
)
return
0
;
desc
.
datbuf
=
buf
;
desc
.
datlen
=
len
;
ret
=
mtd
->
ops
->
read
(
mtd
->
master
,
from
+
mtd
->
offset
,
&
desc
);
if
(
ret
)
return
ret
;
return
desc
.
datretlen
;
}
/**
* Write data only
*
* @to offset to write from
* @return success size or error code
*/
int
rt_mtd_write
(
rt_mtd_t
*
mtd
,
loff_t
to
,
const
uint8_t
*
buf
,
size_t
len
)
{
int
ret
;
struct
mtd_io_desc
desc
=
{
0
};
if
(
to
<
0
||
to
>=
(
loff_t
)
mtd
->
size
||
len
>
mtd
->
size
-
to
)
return
-
EINVAL
;
if
(
!
mtd
->
ops
->
write
)
return
-
EROFS
;
if
(
!
len
)
return
0
;
desc
.
datbuf
=
(
uint8_t
*
)
buf
;
desc
.
datlen
=
len
;
ret
=
mtd
->
ops
->
write
(
mtd
->
master
,
to
+
mtd
->
offset
,
&
desc
);
if
(
ret
)
return
ret
;
return
desc
.
datretlen
;
}
/**
* Read data and/or out-of-band
*
* @from offset to read from
* @desc sector operation description structure
* @return error code, 0 success
*/
int
rt_mtd_read_oob
(
rt_mtd_t
*
mtd
,
loff_t
from
,
struct
mtd_io_desc
*
desc
)
{
desc
->
datretlen
=
0
;
desc
->
oobretlen
=
0
;
if
(
from
<
0
||
from
>=
(
loff_t
)
mtd
->
size
)
return
-
EINVAL
;
if
(
desc
->
datbuf
&&
(
desc
->
datlen
>
(
mtd
->
size
-
from
)))
return
-
EINVAL
;
return
mtd
->
ops
->
read
(
mtd
->
master
,
from
+
mtd
->
offset
,
desc
);
}
/**
* Write data and/or out-of-band
*
* @to offset to read from
* @desc sector operation description structure
* @return error code, 0 success
*/
int
rt_mtd_write_oob
(
rt_mtd_t
*
mtd
,
loff_t
to
,
struct
mtd_io_desc
*
desc
)
{
desc
->
datretlen
=
0
;
desc
->
oobretlen
=
0
;
if
(
to
<
0
||
to
>=
(
loff_t
)
mtd
->
size
)
return
-
EINVAL
;
if
(
desc
->
datbuf
&&
(
desc
->
datlen
>
(
mtd
->
size
-
to
)))
return
-
EINVAL
;
return
mtd
->
ops
->
write
(
mtd
->
master
,
to
+
mtd
->
offset
,
desc
);
}
components/drivers/mtd/mtdnand.c
0 → 100644
浏览文件 @
bc5a5f89
#include <rtdevice.h>
#define MTDTONAND(x) ((rt_nand_t*)(x))
#define NOTALIGNED(x) ((x & (chip->page_size - 1)) != 0)
#ifndef min
#define min(a,b) (a>b? b:a)
#endif
static
uint8_t
*
nand_fill_oob
(
rt_nand_t
*
chip
,
uint8_t
*
oob
,
size_t
len
,
struct
mtd_io_desc
*
desc
)
{
rt_memset
(
chip
->
oob_poi
,
0xff
,
chip
->
oobsize
);
switch
(
desc
->
mode
)
{
case
MTD_OPM_PLACE_OOB
:
case
MTD_OPM_RAW
:
rt_memcpy
(
chip
->
oob_poi
+
desc
->
ooboffs
,
oob
,
len
);
return
oob
+
len
;
case
MTD_OPM_AUTO_OOB
:
{
const
struct
mtd_oob_region
*
free
=
chip
->
freelayout
;
uint32_t
boffs
;
size_t
bytes
;
bytes
=
min
(
len
,
free
->
length
);
boffs
=
free
->
offset
;
rt_memcpy
(
chip
->
oob_poi
+
boffs
,
oob
,
bytes
);
oob
+=
bytes
;
return
oob
;
}
}
return
NULL
;
}
static
uint8_t
*
nand_transfer_oob
(
rt_nand_t
*
chip
,
uint8_t
*
oob
,
struct
mtd_io_desc
*
desc
,
size_t
len
)
{
switch
(
desc
->
mode
)
{
case
MTD_OPM_PLACE_OOB
:
case
MTD_OPM_RAW
:
rt_memcpy
(
oob
,
chip
->
oob_poi
+
desc
->
ooboffs
,
len
);
return
oob
+
len
;
case
MTD_OPM_AUTO_OOB
:
{
struct
mtd_oob_region
*
free
=
(
struct
mtd_oob_region
*
)
chip
->
freelayout
;
uint32_t
boffs
=
0
,
roffs
=
desc
->
ooboffs
;
size_t
bytes
=
0
;
for
(;
free
->
length
&&
len
;
free
++
,
len
-=
bytes
)
{
/* Read request not from offset 0? */
if
(
roffs
)
{
if
(
roffs
>=
free
->
length
)
{
roffs
-=
free
->
length
;
continue
;
}
boffs
=
free
->
offset
+
roffs
;
bytes
=
min
(
len
,
(
free
->
length
-
roffs
));
roffs
=
0
;
}
else
{
bytes
=
min
(
len
,
free
->
length
);
boffs
=
free
->
offset
;
}
rt_memcpy
(
oob
,
chip
->
oob_poi
+
boffs
,
bytes
);
oob
+=
bytes
;
}
return
oob
;
}
}
return
NULL
;
}
static
int
nand_read_page_raw
(
rt_nand_t
*
chip
,
uint8_t
*
buf
,
int
oob_required
,
int
page
)
{
chip
->
ops
->
read_buf
(
chip
,
buf
,
chip
->
page_size
);
if
(
oob_required
)
chip
->
ops
->
read_buf
(
chip
,
chip
->
oob_poi
,
chip
->
oobsize
);
return
0
;
}
static
int
nand_write_page_raw
(
rt_nand_t
*
chip
,
const
uint8_t
*
buf
,
int
oob_required
,
int
page
)
{
chip
->
ops
->
write_buf
(
chip
,
buf
,
chip
->
page_size
);
if
(
oob_required
)
chip
->
ops
->
write_buf
(
chip
,
chip
->
oob_poi
,
chip
->
oobsize
);
return
0
;
}
static
int
nand_write_page_hwecc
(
rt_nand_t
*
chip
,
const
uint8_t
*
buf
,
int
oob_required
,
int
page
)
{
uint16_t
i
;
uint16_t
stepsize
=
chip
->
ecc
.
stepsize
;
uint16_t
eccbytes
=
chip
->
ecc
.
bytes
;
uint16_t
eccsteps
=
chip
->
ecc
.
_step
;
uint16_t
eccpos
=
chip
->
ecc
.
layout
->
offset
;
uint8_t
*
ecc_calc
=
chip
->
buffers
.
ecccalc
;
const
uint8_t
*
p
=
buf
;
for
(
i
=
0
;
eccsteps
;
eccsteps
--
,
i
+=
eccbytes
,
p
+=
stepsize
)
{
chip
->
ops
->
cmdfunc
(
chip
,
NAND_CMD_ECC_EN
,
0
,
0
);
chip
->
ops
->
write_buf
(
chip
,
p
,
stepsize
);
chip
->
ecc
.
calculate
(
chip
,
p
,
&
ecc_calc
[
i
]);
chip
->
ops
->
cmdfunc
(
chip
,
NAND_CMD_ECC_DIS
,
0
,
0
);
}
rt_memcpy
(
&
chip
->
oob_poi
[
eccpos
],
ecc_calc
,
chip
->
ecc
.
layout
->
length
);
chip
->
ops
->
write_buf
(
chip
,
chip
->
oob_poi
,
chip
->
oobsize
);
return
0
;
}
static
int
nand_read_page_hwecc
(
rt_nand_t
*
chip
,
uint8_t
*
buf
,
int
oob_required
,
int
page
)
{
uint16_t
i
;
uint16_t
eccsize
=
chip
->
ecc
.
stepsize
;
uint16_t
eccbytes
=
chip
->
ecc
.
bytes
;
uint16_t
eccsteps
=
chip
->
ecc
.
_step
;
uint16_t
eccpos
=
chip
->
ecc
.
layout
->
offset
;
uint8_t
*
p
=
buf
;
uint8_t
*
ecc_calc
=
chip
->
buffers
.
ecccalc
;
uint8_t
*
ecc_code
=
chip
->
buffers
.
ecccode
;
int
ret
=
0
;
for
(
i
=
0
;
eccsteps
;
eccsteps
--
,
i
+=
eccbytes
,
p
+=
eccsize
)
{
chip
->
ops
->
cmdfunc
(
chip
,
NAND_CMD_ECC_EN
,
0
,
0
);
chip
->
ops
->
read_buf
(
chip
,
p
,
eccsize
);
chip
->
ecc
.
calculate
(
chip
,
p
,
&
ecc_calc
[
i
]);
chip
->
ops
->
cmdfunc
(
chip
,
NAND_CMD_ECC_DIS
,
0
,
0
);
}
chip
->
ops
->
read_buf
(
chip
,
chip
->
oob_poi
,
chip
->
oobsize
);
rt_memcpy
(
ecc_code
,
&
chip
->
oob_poi
[
eccpos
],
chip
->
ecc
.
layout
->
length
);
eccsteps
=
chip
->
ecc
.
_step
;
p
=
buf
;
for
(
i
=
0
;
eccsteps
;
eccsteps
--
,
i
+=
eccbytes
,
p
+=
eccsize
)
{
int
stat
;
stat
=
chip
->
ecc
.
correct
(
chip
,
p
,
&
ecc_code
[
i
],
&
ecc_calc
[
i
]);
if
(
stat
!=
0
)
ret
=
-
1
;
}
return
ret
;
}
static
int
nand_write_page
(
rt_nand_t
*
chip
,
const
uint8_t
*
buf
,
int
oob_required
,
int
page
,
int
raw
)
{
int
status
;
chip
->
ops
->
cmdfunc
(
chip
,
NAND_CMD_PAGE_WR0
,
page
,
0x00
);
if
(
raw
)
{
nand_write_page_raw
(
chip
,
buf
,
oob_required
,
page
);
}
else
{
chip
->
write_page
(
chip
,
buf
,
oob_required
,
page
);
}
status
=
chip
->
ops
->
cmdfunc
(
chip
,
NAND_CMD_PAGE_WR1
,
-
1
,
-
1
);
return
status
;
}
static
int
nand_do_read_desc
(
rt_nand_t
*
chip
,
loff_t
from
,
struct
mtd_io_desc
*
desc
)
{
int
page
,
bytes
;
char
oob_required
;
char
ecc_fail
=
0
;
int
ret
=
0
;
uint32_t
readlen
=
desc
->
datlen
;
uint16_t
oobreadlen
=
desc
->
ooblen
;
uint16_t
max_oobsize
=
desc
->
mode
==
MTD_OPM_AUTO_OOB
?
chip
->
freelayout
->
length
:
chip
->
oobsize
;
uint8_t
*
oob
,
*
buf
,
*
notalign
=
0
;
/* Reject reads, which are not page aligned */
if
(
NOTALIGNED
(
from
))
{
return
-
EINVAL
;
}
buf
=
desc
->
datbuf
;
if
(
NOTALIGNED
(
desc
->
datlen
)
&&
!
chip
->
pagebuf
)
{
chip
->
pagebuf
=
rt_malloc
(
chip
->
page_size
);
if
(
!
chip
->
pagebuf
)
return
-
ENOMEM
;
}
page
=
(
int
)(
from
/
chip
->
page_size
);
oob
=
desc
->
oobbuf
;
oob_required
=
oob
?
1
:
0
;
while
(
1
)
{
bytes
=
min
(
chip
->
page_size
,
readlen
);
chip
->
ops
->
cmdfunc
(
chip
,
NAND_CMD_PAGE_RD
,
page
,
0x00
);
if
(
NOTALIGNED
(
bytes
))
{
notalign
=
buf
;
buf
=
chip
->
pagebuf
;
}
/*
* Now read the page into the buffer. Absent an error,
* the read methods return max bitflips per ecc step.
*/
if
(
desc
->
mode
==
MTD_OPM_RAW
)
{
ret
=
nand_read_page_raw
(
chip
,
buf
,
oob_required
,
page
);
}
else
{
ret
=
chip
->
read_page
(
chip
,
buf
,
oob_required
,
page
);
}
if
(
ret
!=
0
)
{
ret
=
-
EBADMSG
;
break
;
}
if
(
oob
)
{
int
toread
=
min
(
oobreadlen
,
max_oobsize
);
if
(
toread
)
{
oob
=
nand_transfer_oob
(
chip
,
oob
,
desc
,
toread
);
oobreadlen
-=
toread
;
}
}
if
(
notalign
)
{
rt_memcpy
(
notalign
,
buf
,
bytes
);
}
buf
+=
bytes
;
readlen
-=
bytes
;
if
(
!
readlen
)
break
;
page
++
;
}
desc
->
datretlen
=
desc
->
datlen
-
(
size_t
)
readlen
;
if
(
oob
)
desc
->
oobretlen
=
desc
->
ooblen
-
oobreadlen
;
return
ret
;
}
/*
* write with ECC
*
*/
static
int
nand_do_write_desc
(
rt_nand_t
*
chip
,
loff_t
to
,
struct
mtd_io_desc
*
desc
)
{
int
page
;
uint16_t
writelen
=
desc
->
datlen
;
uint16_t
oob_required
=
desc
->
oobbuf
?
1
:
0
;
uint16_t
oobwritelen
=
desc
->
ooblen
;
uint16_t
oobmaxlen
=
desc
->
mode
==
MTD_OPM_AUTO_OOB
?
chip
->
freelayout
->
length
:
chip
->
oobsize
;
uint8_t
*
oob
=
desc
->
oobbuf
;
uint8_t
*
buf
=
desc
->
datbuf
;
int
ret
;
if
(
!
writelen
)
return
0
;
/* Reject writes, which are not page aligned */
if
(
NOTALIGNED
(
to
))
{
return
-
EINVAL
;
}
page
=
(
int
)(
to
/
chip
->
page_size
);
/* Don't allow multipage oob writes with offset */
if
(
oob
&&
desc
->
ooboffs
&&
(
desc
->
ooboffs
+
desc
->
ooblen
>
oobmaxlen
))
{
ret
=
-
EINVAL
;
goto
err_out
;
}
if
(
NOTALIGNED
(
desc
->
datlen
)
&&
!
chip
->
pagebuf
)
{
chip
->
pagebuf
=
rt_malloc
(
chip
->
page_size
);
if
(
!
chip
->
pagebuf
)
return
-
ENOMEM
;
}
while
(
1
)
{
uint16_t
bytes
=
min
(
chip
->
page_size
,
writelen
);
if
(
oob
)
{
size_t
len
=
min
(
oobwritelen
,
oobmaxlen
);
oob
=
nand_fill_oob
(
chip
,
oob
,
len
,
desc
);
oobwritelen
-=
len
;
}
else
{
/* We still need to erase leftover OOB data */
rt_memset
(
chip
->
oob_poi
,
0xff
,
chip
->
oobsize
);
}
if
(
NOTALIGNED
(
bytes
))
{
uint8_t
*
dbtmp
=
buf
;
buf
=
chip
->
pagebuf
;
rt_memset
(
&
buf
[
bytes
],
0xff
,
chip
->
page_size
-
bytes
);
rt_memcpy
(
buf
,
dbtmp
,
bytes
);
}
ret
=
nand_write_page
(
chip
,
buf
,
oob_required
,
page
,
(
desc
->
mode
==
MTD_OPM_RAW
));
if
(
ret
)
break
;
writelen
-=
bytes
;
if
(
!
writelen
)
break
;
buf
+=
bytes
;
page
++
;
}
desc
->
datretlen
=
desc
->
datlen
-
writelen
;
if
(
oob
)
desc
->
oobretlen
=
desc
->
ooblen
;
err_out:
return
ret
;
}
static
int
nand_read_oob_std
(
rt_nand_t
*
chip
,
int
page
)
{
chip
->
ops
->
cmdfunc
(
chip
,
NAND_CMD_PAGE_RD
,
page
,
chip
->
page_size
);
chip
->
ops
->
read_buf
(
chip
,
chip
->
oob_poi
,
chip
->
oobsize
);
return
0
;
}
/*
* read one page of OOB
*/
static
int
nand_only_read_oob
(
rt_nand_t
*
chip
,
loff_t
from
,
struct
mtd_io_desc
*
desc
)
{
int
page
;
int
readlen
=
desc
->
ooblen
;
int
len
;
uint8_t
*
buf
=
desc
->
oobbuf
;
int
ret
=
0
;
if
(
desc
->
mode
==
MTD_OPM_AUTO_OOB
)
len
=
chip
->
freelayout
->
length
;
else
len
=
chip
->
oobsize
;
if
(
desc
->
ooboffs
>=
len
)
//attempt to start read outside oob
{
return
-
EINVAL
;
}
page
=
(
int
)(
from
/
chip
->
page_size
);
ret
=
nand_read_oob_std
(
chip
,
page
);
if
(
ret
==
0
)
{
len
=
min
(
len
,
readlen
);
buf
=
nand_transfer_oob
(
chip
,
buf
,
desc
,
len
);
desc
->
oobretlen
=
len
;
}
return
ret
;
}
static
int
nand_write_oob_std
(
rt_nand_t
*
chip
,
int
page
)
{
int
status
;
chip
->
ops
->
cmdfunc
(
chip
,
NAND_CMD_PAGE_WR0
,
page
,
chip
->
page_size
);
chip
->
ops
->
write_buf
(
chip
,
chip
->
oob_poi
,
chip
->
oobsize
);
/* Send command to program the OOB data */
status
=
chip
->
ops
->
cmdfunc
(
chip
,
NAND_CMD_PAGE_WR1
,
-
1
,
-
1
);
return
status
&
NAND_STATUS_FAIL
?
-
EIO
:
0
;
}
static
int
nand_only_write_oob
(
rt_nand_t
*
chip
,
loff_t
to
,
struct
mtd_io_desc
*
desc
)
{
int
page
,
ret
,
len
;
if
(
desc
->
mode
==
MTD_OPM_AUTO_OOB
)
len
=
chip
->
freelayout
->
length
;
else
len
=
chip
->
oobsize
;
/* Do not allow write past end of page */
if
((
desc
->
ooboffs
+
desc
->
ooblen
)
>
len
)
{
return
-
EINVAL
;
}
if
(
desc
->
ooblen
==
0
)
{
return
-
EINVAL
;
}
/* get page */
page
=
(
int
)(
to
/
chip
->
page_size
);
nand_fill_oob
(
chip
,
desc
->
oobbuf
,
desc
->
ooblen
,
desc
);
ret
=
nand_write_oob_std
(
chip
,
page
);
if
(
ret
==
0
)
desc
->
oobretlen
=
len
;
return
ret
;
}
static
int
nand_erase
(
rt_mtd_t
*
mtd
,
loff_t
addr
,
size_t
size
)
{
rt_nand_t
*
chip
;
int
status
;
int
page
;
uint32_t
blksize
;
chip
=
MTDTONAND
(
mtd
);
blksize
=
mtd
->
block_size
;
page
=
addr
/
chip
->
page_size
;
while
(
size
>=
blksize
)
{
status
=
chip
->
ops
->
cmdfunc
(
chip
,
NAND_CMD_BLK_ERASE
,
page
,
0
);
if
(
status
&
NAND_STATUS_FAIL
)
{
break
;
}
size
-=
blksize
;
page
+=
chip
->
pages_pb
;
}
return
size
;
}
static
int
nand_read
(
rt_mtd_t
*
mtd
,
loff_t
from
,
struct
mtd_io_desc
*
desc
)
{
int
ret
=
-
ENOTSUP
;
rt_nand_t
*
chip
;
chip
=
MTDTONAND
(
mtd
);
switch
(
desc
->
mode
)
{
case
MTD_OPM_PLACE_OOB
:
case
MTD_OPM_AUTO_OOB
:
case
MTD_OPM_RAW
:
break
;
default:
goto
out
;
}
if
(
!
desc
->
datbuf
||
!
desc
->
datlen
)
ret
=
nand_only_read_oob
(
chip
,
from
,
desc
);
else
ret
=
nand_do_read_desc
(
chip
,
from
,
desc
);
out:
return
ret
;
}
static
int
nand_write
(
rt_mtd_t
*
mtd
,
loff_t
to
,
struct
mtd_io_desc
*
desc
)
{
int
ret
=
-
ENOTSUP
;
rt_nand_t
*
chip
;
chip
=
MTDTONAND
(
mtd
);
switch
(
desc
->
mode
)
{
case
MTD_OPM_PLACE_OOB
:
case
MTD_OPM_AUTO_OOB
:
case
MTD_OPM_RAW
:
break
;
default:
goto
out
;
}
if
(
!
desc
->
datbuf
||
!
desc
->
datlen
)
ret
=
nand_only_write_oob
(
chip
,
to
,
desc
);
else
ret
=
nand_do_write_desc
(
chip
,
to
,
desc
);
out:
return
ret
;
}
static
int
nand_block_isbad
(
rt_mtd_t
*
mtd
,
uint32_t
blk
)
{
int
ret
;
rt_nand_t
*
chip
=
MTDTONAND
(
mtd
);
if
(
chip
->
ops
->
isbad
)
{
ret
=
chip
->
ops
->
isbad
(
chip
,
blk
);
}
else
{
int
page
;
page
=
blk
*
chip
->
pages_pb
;
nand_read_oob_std
(
chip
,
page
);
ret
=
chip
->
oob_poi
[
0
]
!=
0xFF
;
}
return
ret
;
}
static
int
nand_block_markbad
(
rt_mtd_t
*
mtd
,
uint32_t
blk
)
{
int
ret
;
rt_nand_t
*
chip
;
chip
=
MTDTONAND
(
mtd
);
if
(
chip
->
ops
->
markbad
)
{
ret
=
chip
->
ops
->
markbad
(
chip
,
blk
);
}
else
{
int
page
;
page
=
blk
*
chip
->
pages_pb
;
rt_memset
(
chip
->
oob_poi
,
0xff
,
chip
->
oobsize
);
chip
->
oob_poi
[
0
]
=
0
;
ret
=
nand_write_oob_std
(
chip
,
page
);
}
return
ret
;
}
static
const
struct
mtd_ops
_ops
=
{
nand_erase
,
nand_read
,
nand_write
,
nand_block_isbad
,
nand_block_markbad
,
};
int
rt_mtd_nand_init
(
rt_nand_t
*
nand
,
int
blk_size
,
int
page_size
,
int
blks_pc
,
int
oob_size
)
{
uint8_t
*
buf
;
buf
=
rt_malloc
(
oob_size
*
3
);
if
(
buf
==
RT_NULL
)
return
-
ENOMEM
;
nand
->
oob_poi
=
buf
;
buf
+=
oob_size
;
nand
->
buffers
.
ecccalc
=
buf
;
buf
+=
oob_size
;
nand
->
buffers
.
ecccode
=
buf
;
nand
->
pagebuf
=
0
;
/* alloc when unaligen access */
nand
->
size
=
blk_size
*
blks_pc
;
nand
->
pages_pb
=
blk_size
/
page_size
;
nand
->
ecc
.
_step
=
page_size
/
nand
->
ecc
.
stepsize
;
nand
->
page_size
=
page_size
;
nand
->
oobsize
=
oob_size
;
nand
->
parent
.
type
=
MTD_TYPE_NAND
;
nand
->
parent
.
ops
=
&
_ops
;
nand
->
parent
.
sector_size
=
page_size
;
nand
->
parent
.
block_size
=
blk_size
;
nand
->
parent
.
oob_size
=
oob_size
;
switch
(
nand
->
ecc
.
mode
)
{
case
NAND_ECCM_NONE
:
{
nand
->
read_page
=
nand_read_page_raw
;
nand
->
write_page
=
nand_write_page_raw
;
}
break
;
case
NAND_ECCM_HW
:
{
nand
->
read_page
=
nand_read_page_hwecc
;
nand
->
write_page
=
nand_write_page_hwecc
;
}
break
;
default:
{
rt_free
(
buf
);
return
-
1
;
}
}
return
0
;
}
components/drivers/mtd/mtdnor.c
0 → 100644
浏览文件 @
bc5a5f89
/*
* File : mtdnor.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2012, Shanghai Real-Thread Technology Co., Ltd
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-8-30 heyuanjie the first version
*/
#include <drivers/mtdnor.h>
#ifdef MTD_USING_NOR
static
int
_nor_erase
(
rt_mtd_t
*
mtd
,
loff_t
addr
,
size_t
len
)
{
rt_nor_t
*
nor
;
nor
=
(
rt_nor_t
*
)
mtd
;
return
nor
->
ops
->
erase
(
nor
,
addr
,
len
);
}
static
int
_nor_read
(
rt_mtd_t
*
mtd
,
loff_t
from
,
struct
mtd_io_desc
*
desc
)
{
rt_nor_t
*
nor
;
int
ret
;
nor
=
(
rt_nor_t
*
)
mtd
;
ret
=
nor
->
ops
->
read
(
nor
,
from
,
desc
->
datbuf
,
desc
->
datlen
);
if
(
ret
>
0
)
{
desc
->
datretlen
=
ret
;
ret
=
0
;
}
return
ret
;
}
static
int
_nor_write
(
rt_mtd_t
*
mtd
,
loff_t
to
,
struct
mtd_io_desc
*
desc
)
{
rt_nor_t
*
nor
;
int
ret
;
nor
=
(
rt_nor_t
*
)
mtd
;
ret
=
nor
->
ops
->
write
(
nor
,
to
,
desc
->
datbuf
,
desc
->
datlen
);
if
(
ret
>
0
)
{
desc
->
datretlen
=
ret
;
ret
=
0
;
}
return
ret
;
}
static
const
struct
mtd_ops
_ops
=
{
_nor_erase
,
_nor_read
,
_nor_write
,
0
,
0
};
int
rt_mtd_nor_init
(
rt_nor_t
*
nor
,
int
blksize
)
{
nor
->
parent
.
sector_size
=
1
;
nor
->
parent
.
block_size
=
blksize
;
nor
->
parent
.
ops
=
&
_ops
;
nor
->
parent
.
type
=
MTD_TYPE_NOR
;
nor
->
parent
.
oob_size
=
0
;
return
0
;
}
#endif
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录