Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-elphel
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
linux-elphel
Commits
ced80966
Commit
ced80966
authored
Jul 23, 2019
by
Oleg Dzhimiev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
updated to current version
parent
fd4f2e1d
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
753 additions
and
570 deletions
+753
-570
nand_base.c
src/drivers/mtd/nand/nand_base.c
+753
-570
No files found.
src/drivers/mtd/nand/nand_base.c
View file @
ced80966
...
@@ -36,9 +36,10 @@
...
@@ -36,9 +36,10 @@
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/nmi.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/
raw
nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/nand_bch.h>
#include <linux/mtd/nand_bch.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
...
@@ -69,8 +70,14 @@ static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
...
@@ -69,8 +70,14 @@ static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
if
(
!
section
)
{
if
(
!
section
)
{
oobregion
->
offset
=
0
;
oobregion
->
offset
=
0
;
if
(
mtd
->
oobsize
==
16
)
oobregion
->
length
=
4
;
oobregion
->
length
=
4
;
else
oobregion
->
length
=
3
;
}
else
{
}
else
{
if
(
mtd
->
oobsize
==
8
)
return
-
ERANGE
;
oobregion
->
offset
=
6
;
oobregion
->
offset
=
6
;
oobregion
->
length
=
ecc
->
total
-
4
;
oobregion
->
length
=
ecc
->
total
-
4
;
}
}
...
@@ -143,6 +150,74 @@ const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
...
@@ -143,6 +150,74 @@ const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
};
};
EXPORT_SYMBOL_GPL
(
nand_ooblayout_lp_ops
);
EXPORT_SYMBOL_GPL
(
nand_ooblayout_lp_ops
);
/*
* Support the old "large page" layout used for 1-bit Hamming ECC where ECC
* are placed at a fixed offset.
*/
static
int
nand_ooblayout_ecc_lp_hamming
(
struct
mtd_info
*
mtd
,
int
section
,
struct
mtd_oob_region
*
oobregion
)
{
struct
nand_chip
*
chip
=
mtd_to_nand
(
mtd
);
struct
nand_ecc_ctrl
*
ecc
=
&
chip
->
ecc
;
if
(
section
)
return
-
ERANGE
;
switch
(
mtd
->
oobsize
)
{
case
64
:
oobregion
->
offset
=
40
;
break
;
case
128
:
oobregion
->
offset
=
80
;
break
;
default:
return
-
EINVAL
;
}
oobregion
->
length
=
ecc
->
total
;
if
(
oobregion
->
offset
+
oobregion
->
length
>
mtd
->
oobsize
)
return
-
ERANGE
;
return
0
;
}
static
int
nand_ooblayout_free_lp_hamming
(
struct
mtd_info
*
mtd
,
int
section
,
struct
mtd_oob_region
*
oobregion
)
{
struct
nand_chip
*
chip
=
mtd_to_nand
(
mtd
);
struct
nand_ecc_ctrl
*
ecc
=
&
chip
->
ecc
;
int
ecc_offset
=
0
;
if
(
section
<
0
||
section
>
1
)
return
-
ERANGE
;
switch
(
mtd
->
oobsize
)
{
case
64
:
ecc_offset
=
40
;
break
;
case
128
:
ecc_offset
=
80
;
break
;
default:
return
-
EINVAL
;
}
if
(
section
==
0
)
{
oobregion
->
offset
=
2
;
oobregion
->
length
=
ecc_offset
-
2
;
}
else
{
oobregion
->
offset
=
ecc_offset
+
ecc
->
total
;
oobregion
->
length
=
mtd
->
oobsize
-
oobregion
->
offset
;
}
return
0
;
}
static
const
struct
mtd_ooblayout_ops
nand_ooblayout_lp_hamming_ops
=
{
.
ecc
=
nand_ooblayout_ecc_lp_hamming
,
.
free
=
nand_ooblayout_free_lp_hamming
,
};
static
int
check_offs_len
(
struct
mtd_info
*
mtd
,
static
int
check_offs_len
(
struct
mtd_info
*
mtd
,
loff_t
ofs
,
uint64_t
len
)
loff_t
ofs
,
uint64_t
len
)
{
{
...
@@ -360,40 +435,32 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
...
@@ -360,40 +435,32 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
*/
*/
static
int
nand_block_bad
(
struct
mtd_info
*
mtd
,
loff_t
ofs
)
static
int
nand_block_bad
(
struct
mtd_info
*
mtd
,
loff_t
ofs
)
{
{
int
page
,
res
=
0
,
i
=
0
;
int
page
,
page_end
,
res
;
struct
nand_chip
*
chip
=
mtd_to_nand
(
mtd
);
struct
nand_chip
*
chip
=
mtd_to_nand
(
mtd
);
u
16
bad
;
u
8
bad
;
if
(
chip
->
bbt_options
&
NAND_BBT_SCANLASTPAGE
)
if
(
chip
->
bbt_options
&
NAND_BBT_SCANLASTPAGE
)
ofs
+=
mtd
->
erasesize
-
mtd
->
writesize
;
ofs
+=
mtd
->
erasesize
-
mtd
->
writesize
;
page
=
(
int
)(
ofs
>>
chip
->
page_shift
)
&
chip
->
pagemask
;
page
=
(
int
)(
ofs
>>
chip
->
page_shift
)
&
chip
->
pagemask
;
page_end
=
page
+
(
chip
->
bbt_options
&
NAND_BBT_SCAN2NDPAGE
?
2
:
1
);
do
{
for
(;
page
<
page_end
;
page
++
)
{
if
(
chip
->
options
&
NAND_BUSWIDTH_16
)
{
res
=
chip
->
ecc
.
read_oob
(
mtd
,
chip
,
page
);
chip
->
cmdfunc
(
mtd
,
NAND_CMD_READOOB
,
if
(
res
)
chip
->
badblockpos
&
0xFE
,
page
);
return
res
;
bad
=
cpu_to_le16
(
chip
->
read_word
(
mtd
));
if
(
chip
->
badblockpos
&
0x1
)
bad
=
chip
->
oob_poi
[
chip
->
badblockpos
];
bad
>>=
8
;
else
bad
&=
0xFF
;
}
else
{
chip
->
cmdfunc
(
mtd
,
NAND_CMD_READOOB
,
chip
->
badblockpos
,
page
);
bad
=
chip
->
read_byte
(
mtd
);
}
if
(
likely
(
chip
->
badblockbits
==
8
))
if
(
likely
(
chip
->
badblockbits
==
8
))
res
=
bad
!=
0xFF
;
res
=
bad
!=
0xFF
;
else
else
res
=
hweight8
(
bad
)
<
chip
->
badblockbits
;
res
=
hweight8
(
bad
)
<
chip
->
badblockbits
;
ofs
+=
mtd
->
writesize
;
if
(
res
)
page
=
(
int
)(
ofs
>>
chip
->
page_shift
)
&
chip
->
pagemask
;
i
++
;
}
while
(
!
res
&&
i
<
2
&&
(
chip
->
bbt_options
&
NAND_BBT_SCAN2NDPAGE
));
return
res
;
return
res
;
}
return
0
;
}
}
/**
/**
...
@@ -448,10 +515,12 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
...
@@ -448,10 +515,12 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
* specify how to write bad block markers to OOB (chip->block_markbad).
* specify how to write bad block markers to OOB (chip->block_markbad).
*
*
* We try operations in the following order:
* We try operations in the following order:
*
* (1) erase the affected block, to allow OOB marker to be written cleanly
* (1) erase the affected block, to allow OOB marker to be written cleanly
* (2) write bad block marker to OOB area of affected block (unless flag
* (2) write bad block marker to OOB area of affected block (unless flag
* NAND_BBT_NO_OOB_BBM is present)
* NAND_BBT_NO_OOB_BBM is present)
* (3) update the BBT
* (3) update the BBT
*
* Note that we retain the first error encountered in (2) or (3), finish the
* Note that we retain the first error encountered in (2) or (3), finish the
* procedures, and dump the error in the end.
* procedures, and dump the error in the end.
*/
*/
...
@@ -682,6 +751,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
...
@@ -682,6 +751,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
case
NAND_CMD_ERASE2
:
case
NAND_CMD_ERASE2
:
case
NAND_CMD_SEQIN
:
case
NAND_CMD_SEQIN
:
case
NAND_CMD_STATUS
:
case
NAND_CMD_STATUS
:
case
NAND_CMD_READID
:
case
NAND_CMD_SET_FEATURES
:
return
;
return
;
case
NAND_CMD_RESET
:
case
NAND_CMD_RESET
:
...
@@ -697,6 +768,16 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
...
@@ -697,6 +768,16 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
return
;
return
;
/* This applies to read commands */
/* This applies to read commands */
case
NAND_CMD_READ0
:
/*
* READ0 is sometimes used to exit GET STATUS mode. When this
* is the case no address cycles are requested, and we can use
* this information to detect that we should not wait for the
* device to be ready.
*/
if
(
column
==
-
1
&&
page_addr
==
-
1
)
return
;
default:
default:
/*
/*
* If we don't have access to the busy pin, we apply the given
* If we don't have access to the busy pin, we apply the given
...
@@ -716,6 +797,25 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
...
@@ -716,6 +797,25 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
nand_wait_ready
(
mtd
);
nand_wait_ready
(
mtd
);
}
}
static
void
nand_ccs_delay
(
struct
nand_chip
*
chip
)
{
/*
* The controller already takes care of waiting for tCCS when the RNDIN
* or RNDOUT command is sent, return directly.
*/
if
(
!
(
chip
->
options
&
NAND_WAIT_TCCS
))
return
;
/*
* Wait tCCS_min if it is correctly defined, otherwise wait 500ns
* (which should be safe for all NANDs).
*/
if
(
chip
->
data_interface
&&
chip
->
data_interface
->
timings
.
sdr
.
tCCS_min
)
ndelay
(
chip
->
data_interface
->
timings
.
sdr
.
tCCS_min
/
1000
);
else
ndelay
(
500
);
}
/**
/**
* nand_command_lp - [DEFAULT] Send command to NAND large page device
* nand_command_lp - [DEFAULT] Send command to NAND large page device
* @mtd: MTD device structure
* @mtd: MTD device structure
...
@@ -780,8 +880,13 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
...
@@ -780,8 +880,13 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
case
NAND_CMD_ERASE1
:
case
NAND_CMD_ERASE1
:
case
NAND_CMD_ERASE2
:
case
NAND_CMD_ERASE2
:
case
NAND_CMD_SEQIN
:
case
NAND_CMD_SEQIN
:
case
NAND_CMD_RNDIN
:
case
NAND_CMD_STATUS
:
case
NAND_CMD_STATUS
:
case
NAND_CMD_READID
:
case
NAND_CMD_SET_FEATURES
:
return
;
case
NAND_CMD_RNDIN
:
nand_ccs_delay
(
chip
);
return
;
return
;
case
NAND_CMD_RESET
:
case
NAND_CMD_RESET
:
...
@@ -802,9 +907,20 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
...
@@ -802,9 +907,20 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
NAND_NCE
|
NAND_CLE
|
NAND_CTRL_CHANGE
);
NAND_NCE
|
NAND_CLE
|
NAND_CTRL_CHANGE
);
chip
->
cmd_ctrl
(
mtd
,
NAND_CMD_NONE
,
chip
->
cmd_ctrl
(
mtd
,
NAND_CMD_NONE
,
NAND_NCE
|
NAND_CTRL_CHANGE
);
NAND_NCE
|
NAND_CTRL_CHANGE
);
nand_ccs_delay
(
chip
);
return
;
return
;
case
NAND_CMD_READ0
:
case
NAND_CMD_READ0
:
/*
* READ0 is sometimes used to exit GET STATUS mode. When this
* is the case no address cycles are requested, and we can use
* this information to detect that READSTART should not be
* issued.
*/
if
(
column
==
-
1
&&
page_addr
==
-
1
)
return
;
chip
->
cmd_ctrl
(
mtd
,
NAND_CMD_READSTART
,
chip
->
cmd_ctrl
(
mtd
,
NAND_CMD_READSTART
,
NAND_NCE
|
NAND_CLE
|
NAND_CTRL_CHANGE
);
NAND_NCE
|
NAND_CLE
|
NAND_CTRL_CHANGE
);
chip
->
cmd_ctrl
(
mtd
,
NAND_CMD_NONE
,
chip
->
cmd_ctrl
(
mtd
,
NAND_CMD_NONE
,
...
@@ -962,12 +1078,13 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
...
@@ -962,12 +1078,13 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
/**
/**
* nand_reset_data_interface - Reset data interface and timings
* nand_reset_data_interface - Reset data interface and timings
* @chip: The NAND chip
* @chip: The NAND chip
* @chipnr: Internal die id
*
*
* Reset the Data interface and timings to ONFI mode 0.
* Reset the Data interface and timings to ONFI mode 0.
*
*
* Returns 0 for success or negative error code otherwise.
* Returns 0 for success or negative error code otherwise.
*/
*/
static
int
nand_reset_data_interface
(
struct
nand_chip
*
chip
)
static
int
nand_reset_data_interface
(
struct
nand_chip
*
chip
,
int
chipnr
)
{
{
struct
mtd_info
*
mtd
=
nand_to_mtd
(
chip
);
struct
mtd_info
*
mtd
=
nand_to_mtd
(
chip
);
const
struct
nand_data_interface
*
conf
;
const
struct
nand_data_interface
*
conf
;
...
@@ -991,7 +1108,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
...
@@ -991,7 +1108,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
*/
*/
conf
=
nand_get_default_data_interface
();
conf
=
nand_get_default_data_interface
();
ret
=
chip
->
setup_data_interface
(
mtd
,
c
onf
,
false
);
ret
=
chip
->
setup_data_interface
(
mtd
,
c
hipnr
,
conf
);
if
(
ret
)
if
(
ret
)
pr_err
(
"Failed to configure data interface to SDR timing mode 0
\n
"
);
pr_err
(
"Failed to configure data interface to SDR timing mode 0
\n
"
);
...
@@ -1001,6 +1118,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
...
@@ -1001,6 +1118,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
/**
/**
* nand_setup_data_interface - Setup the best data interface and timings
* nand_setup_data_interface - Setup the best data interface and timings
* @chip: The NAND chip
* @chip: The NAND chip
* @chipnr: Internal die id
*
*
* Find and configure the best data interface and NAND timings supported by
* Find and configure the best data interface and NAND timings supported by
* the chip and the driver.
* the chip and the driver.
...
@@ -1010,7 +1128,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
...
@@ -1010,7 +1128,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
*
*
* Returns 0 for success or negative error code otherwise.
* Returns 0 for success or negative error code otherwise.
*/
*/
static
int
nand_setup_data_interface
(
struct
nand_chip
*
chip
)
static
int
nand_setup_data_interface
(
struct
nand_chip
*
chip
,
int
chipnr
)
{
{
struct
mtd_info
*
mtd
=
nand_to_mtd
(
chip
);
struct
mtd_info
*
mtd
=
nand_to_mtd
(
chip
);
int
ret
;
int
ret
;
...
@@ -1022,7 +1140,9 @@ static int nand_setup_data_interface(struct nand_chip *chip)
...
@@ -1022,7 +1140,9 @@ static int nand_setup_data_interface(struct nand_chip *chip)
* Ensure the timing mode has been changed on the chip side
* Ensure the timing mode has been changed on the chip side
* before changing timings on the controller side.
* before changing timings on the controller side.
*/
*/
if
(
chip
->
onfi_version
)
{
if
(
chip
->
onfi_version
&&
(
le16_to_cpu
(
chip
->
onfi_params
.
opt_cmd
)
&
ONFI_OPT_CMD_SET_GET_FEATURES
))
{
u8
tmode_param
[
ONFI_SUBFEATURE_PARAM_LEN
]
=
{
u8
tmode_param
[
ONFI_SUBFEATURE_PARAM_LEN
]
=
{
chip
->
onfi_timing_mode_default
,
chip
->
onfi_timing_mode_default
,
};
};
...
@@ -1034,7 +1154,7 @@ static int nand_setup_data_interface(struct nand_chip *chip)
...
@@ -1034,7 +1154,7 @@ static int nand_setup_data_interface(struct nand_chip *chip)
goto
err
;
goto
err
;
}
}
ret
=
chip
->
setup_data_interface
(
mtd
,
chip
->
data_interface
,
fals
e
);
ret
=
chip
->
setup_data_interface
(
mtd
,
chip
nr
,
chip
->
data_interfac
e
);
err:
err:
return
ret
;
return
ret
;
}
}
...
@@ -1085,8 +1205,10 @@ static int nand_init_data_interface(struct nand_chip *chip)
...
@@ -1085,8 +1205,10 @@ static int nand_init_data_interface(struct nand_chip *chip)
if
(
ret
)
if
(
ret
)
continue
;
continue
;
ret
=
chip
->
setup_data_interface
(
mtd
,
chip
->
data_interface
,
/* Pass -1 to only */
true
);
ret
=
chip
->
setup_data_interface
(
mtd
,
NAND_DATA_IFACE_CHECK_ONLY
,
chip
->
data_interface
);
if
(
!
ret
)
{
if
(
!
ret
)
{
chip
->
onfi_timing_mode_default
=
mode
;
chip
->
onfi_timing_mode_default
=
mode
;
break
;
break
;
...
@@ -1113,7 +1235,7 @@ int nand_reset(struct nand_chip *chip, int chipnr)
...
@@ -1113,7 +1235,7 @@ int nand_reset(struct nand_chip *chip, int chipnr)
struct
mtd_info
*
mtd
=
nand_to_mtd
(
chip
);
struct
mtd_info
*
mtd
=
nand_to_mtd
(
chip
);
int
ret
;
int
ret
;
ret
=
nand_reset_data_interface
(
chip
);
ret
=
nand_reset_data_interface
(
chip
,
chipnr
);
if
(
ret
)
if
(
ret
)
return
ret
;
return
ret
;
...
@@ -1126,7 +1248,7 @@ int nand_reset(struct nand_chip *chip, int chipnr)
...
@@ -1126,7 +1248,7 @@ int nand_reset(struct nand_chip *chip, int chipnr)
chip
->
select_chip
(
mtd
,
-
1
);
chip
->
select_chip
(
mtd
,
-
1
);
chip
->
select_chip
(
mtd
,
chipnr
);
chip
->
select_chip
(
mtd
,
chipnr
);
ret
=
nand_setup_data_interface
(
chip
);
ret
=
nand_setup_data_interface
(
chip
,
chipnr
);
chip
->
select_chip
(
mtd
,
-
1
);
chip
->
select_chip
(
mtd
,
-
1
);
if
(
ret
)
if
(
ret
)
return
ret
;
return
ret
;
...
@@ -1134,178 +1256,6 @@ int nand_reset(struct nand_chip *chip, int chipnr)
...
@@ -1134,178 +1256,6 @@ int nand_reset(struct nand_chip *chip, int chipnr)
return
0
;
return
0
;
}
}
/**
* __nand_unlock - [REPLACEABLE] unlocks specified locked blocks
* @mtd: mtd info
* @ofs: offset to start unlock from
* @len: length to unlock
* @invert: when = 0, unlock the range of blocks within the lower and
* upper boundary address
* when = 1, unlock the range of blocks outside the boundaries
* of the lower and upper boundary address
*
* Returs unlock status.
*/
static
int
__nand_unlock
(
struct
mtd_info
*
mtd
,
loff_t
ofs
,
uint64_t
len
,
int
invert
)
{
int
ret
=
0
;
int
status
,
page
;
struct
nand_chip
*
chip
=
mtd_to_nand
(
mtd
);
/* Submit address of first page to unlock */
page
=
ofs
>>
chip
->
page_shift
;
chip
->
cmdfunc
(
mtd
,
NAND_CMD_UNLOCK1
,
-
1
,
page
&
chip
->
pagemask
);
/* Submit address of last page to unlock */
page
=
(
ofs
+
len
)
>>
chip
->
page_shift
;
chip
->
cmdfunc
(
mtd
,
NAND_CMD_UNLOCK2
,
-
1
,
(
page
|
invert
)
&
chip
->
pagemask
);
/* Call wait ready function */
status
=
chip
->
waitfunc
(
mtd
,
chip
);
/* See if device thinks it succeeded */
if
(
status
&
NAND_STATUS_FAIL
)
{
pr_debug
(
"%s: error status = 0x%08x
\n
"
,
__func__
,
status
);
ret
=
-
EIO
;
}
return
ret
;
}
/**
* nand_unlock - [REPLACEABLE] unlocks specified locked blocks
* @mtd: mtd info
* @ofs: offset to start unlock from
* @len: length to unlock
*
* Returns unlock status.
*/
int
nand_unlock
(
struct
mtd_info
*
mtd
,
loff_t
ofs
,
uint64_t
len
)
{
int
ret
=
0
;
int
chipnr
;
struct
nand_chip
*
chip
=
mtd_to_nand
(
mtd
);
pr_debug
(
"%s: start = 0x%012llx, len = %llu
\n
"
,
__func__
,
(
unsigned
long
long
)
ofs
,
len
);
if
(
check_offs_len
(
mtd
,
ofs
,
len
))
return
-
EINVAL
;
/* Align to last block address if size addresses end of the device */
if
(
ofs
+
len
==
mtd
->
size
)
len
-=
mtd
->
erasesize
;
nand_get_device
(
mtd
,
FL_UNLOCKING
);
/* Shift to get chip number */
chipnr
=
ofs
>>
chip
->
chip_shift
;
/*
* Reset the chip.
* If we want to check the WP through READ STATUS and check the bit 7
* we must reset the chip
* some operation can also clear the bit 7 of status register
* eg. erase/program a locked block
*/
nand_reset
(
chip
,
chipnr
);
chip
->
select_chip
(
mtd
,
chipnr
);
/* Check, if it is write protected */
if
(
nand_check_wp
(
mtd
))
{
pr_debug
(
"%s: device is write protected!
\n
"
,
__func__
);
ret
=
-
EIO
;
goto
out
;
}
ret
=
__nand_unlock
(
mtd
,
ofs
,
len
,
0
);
out:
chip
->
select_chip
(
mtd
,
-
1
);
nand_release_device
(
mtd
);
return
ret
;
}
EXPORT_SYMBOL
(
nand_unlock
);
/**
* nand_lock - [REPLACEABLE] locks all blocks present in the device
* @mtd: mtd info
* @ofs: offset to start unlock from
* @len: length to unlock
*
* This feature is not supported in many NAND parts. 'Micron' NAND parts do
* have this feature, but it allows only to lock all blocks, not for specified
* range for block. Implementing 'lock' feature by making use of 'unlock', for
* now.
*
* Returns lock status.
*/
int
nand_lock
(
struct
mtd_info
*
mtd
,
loff_t
ofs
,
uint64_t
len
)
{
int
ret
=
0
;
int
chipnr
,
status
,
page
;
struct
nand_chip
*
chip
=
mtd_to_nand
(
mtd
);
pr_debug
(
"%s: start = 0x%012llx, len = %llu
\n
"
,
__func__
,
(
unsigned
long
long
)
ofs
,
len
);
if
(
check_offs_len
(
mtd
,
ofs
,
len
))
return
-
EINVAL
;
nand_get_device
(
mtd
,
FL_LOCKING
);
/* Shift to get chip number */
chipnr
=
ofs
>>
chip
->
chip_shift
;
/*
* Reset the chip.
* If we want to check the WP through READ STATUS and check the bit 7
* we must reset the chip
* some operation can also clear the bit 7 of status register
* eg. erase/program a locked block
*/
nand_reset
(
chip
,
chipnr
);
chip
->
select_chip
(
mtd
,
chipnr
);
/* Check, if it is write protected */
if
(
nand_check_wp
(
mtd
))
{
pr_debug
(
"%s: device is write protected!
\n
"
,
__func__
);
status
=
MTD_ERASE_FAILED
;
ret
=
-
EIO
;
goto
out
;
}
/* Submit address of first page to lock */
page
=
ofs
>>
chip
->
page_shift
;
chip
->
cmdfunc
(
mtd
,
NAND_CMD_LOCK
,
-
1
,
page
&
chip
->
pagemask
);
/* Call wait ready function */
status
=
chip
->
waitfunc
(
mtd
,
chip
);
/* See if device thinks it succeeded */
if
(
status
&
NAND_STATUS_FAIL
)
{
pr_debug
(
"%s: error status = 0x%08x
\n
"
,
__func__
,
status
);
ret
=
-
EIO
;
goto
out
;
}
ret
=
__nand_unlock
(
mtd
,
ofs
,
len
,
0x1
);
out:
chip
->
select_chip
(
mtd
,
-
1
);
nand_release_device
(
mtd
);
return
ret
;
}
EXPORT_SYMBOL
(
nand_lock
);
/**
/**
* nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
* nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
* @buf: buffer to test
* @buf: buffer to test
...
@@ -1341,7 +1291,10 @@ static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)
...
@@ -1341,7 +1291,10 @@ static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)
for
(;
len
>=
sizeof
(
long
);
for
(;
len
>=
sizeof
(
long
);
len
-=
sizeof
(
long
),
bitmap
+=
sizeof
(
long
))
{
len
-=
sizeof
(
long
),
bitmap
+=
sizeof
(
long
))
{
weight
=
hweight_long
(
*
((
unsigned
long
*
)
bitmap
));
unsigned
long
d
=
*
((
unsigned
long
*
)
bitmap
);
if
(
d
==
~
0UL
)
continue
;
weight
=
hweight_long
(
d
);
bitflips
+=
BITS_PER_LONG
-
weight
;
bitflips
+=
BITS_PER_LONG
-
weight
;
if
(
unlikely
(
bitflips
>
bitflips_threshold
))
if
(
unlikely
(
bitflips
>
bitflips_threshold
))
return
-
EBADMSG
;
return
-
EBADMSG
;
...
@@ -1444,7 +1397,7 @@ EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
...
@@ -1444,7 +1397,7 @@ EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
*
*
* Not for syndrome calculating ECC controllers, which use a special oob layout.
* Not for syndrome calculating ECC controllers, which use a special oob layout.
*/
*/
static
int
nand_read_page_raw
(
struct
mtd_info
*
mtd
,
struct
nand_chip
*
chip
,
int
nand_read_page_raw
(
struct
mtd_info
*
mtd
,
struct
nand_chip
*
chip
,
uint8_t
*
buf
,
int
oob_required
,
int
page
)
uint8_t
*
buf
,
int
oob_required
,
int
page
)
{
{
chip
->
read_buf
(
mtd
,
buf
,
mtd
->
writesize
);
chip
->
read_buf
(
mtd
,
buf
,
mtd
->
writesize
);
...
@@ -1452,6 +1405,7 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
...
@@ -1452,6 +1405,7 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
chip
->
read_buf
(
mtd
,
chip
->
oob_poi
,
mtd
->
oobsize
);
chip
->
read_buf
(
mtd
,
chip
->
oob_poi
,
mtd
->
oobsize
);
return
0
;
return
0
;
}
}
EXPORT_SYMBOL
(
nand_read_page_raw
);
/**
/**
* nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc
* nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc
...
@@ -1944,7 +1898,9 @@ int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
...
@@ -1944,7 +1898,9 @@ int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
if
(
!
aligned
)
if
(
!
aligned
)
use_bufpoi
=
1
;
use_bufpoi
=
1
;
else
if
(
chip
->
options
&
NAND_USE_BOUNCE_BUFFER
)
else
if
(
chip
->
options
&
NAND_USE_BOUNCE_BUFFER
)
use_bufpoi
=
!
virt_addr_valid
(
buf
);
use_bufpoi
=
!
virt_addr_valid
(
buf
)
||
!
IS_ALIGNED
((
unsigned
long
)
buf
,
chip
->
buf_align
);
else
else
use_bufpoi
=
0
;
use_bufpoi
=
0
;
...
@@ -1957,6 +1913,7 @@ int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
...
@@ -1957,6 +1913,7 @@ int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
__func__
,
buf
);
__func__
,
buf
);
read_retry:
read_retry:
if
(
nand_standard_page_accessors
(
&
chip
->
ecc
))
chip
->
cmdfunc
(
mtd
,
NAND_CMD_READ0
,
0x00
,
page
);
chip
->
cmdfunc
(
mtd
,
NAND_CMD_READ0
,
0x00
,
page
);
/*
/*
...
@@ -1982,8 +1939,6 @@ read_retry:
...
@@ -1982,8 +1939,6 @@ read_retry:
break
;
break
;
}
}
max_bitflips
=
max_t
(
unsigned
int
,
max_bitflips
,
ret
);
/* Transfer not aligned data */
/* Transfer not aligned data */
if
(
use_bufpoi
)
{
if
(
use_bufpoi
)
{
if
(
!
NAND_HAS_SUBPAGE_READ
(
chip
)
&&
!
oob
&&
if
(
!
NAND_HAS_SUBPAGE_READ
(
chip
)
&&
!
oob
&&
...
@@ -2034,6 +1989,7 @@ read_retry:
...
@@ -2034,6 +1989,7 @@ read_retry:
}
}
buf
+=
bytes
;
buf
+=
bytes
;
max_bitflips
=
max_t
(
unsigned
int
,
max_bitflips
,
ret
);
}
else
{
}
else
{
memcpy
(
buf
,
chip
->
buffers
->
databuf
+
col
,
bytes
);
memcpy
(
buf
,
chip
->
buffers
->
databuf
+
col
,
bytes
);
buf
+=
bytes
;
buf
+=
bytes
;
...
@@ -2389,7 +2345,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
...
@@ -2389,7 +2345,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
*
*
* Not for syndrome calculating ECC controllers, which use a special oob layout.
* Not for syndrome calculating ECC controllers, which use a special oob layout.
*/
*/
static
int
nand_write_page_raw
(
struct
mtd_info
*
mtd
,
struct
nand_chip
*
chip
,
int
nand_write_page_raw
(
struct
mtd_info
*
mtd
,
struct
nand_chip
*
chip
,
const
uint8_t
*
buf
,
int
oob_required
,
int
page
)
const
uint8_t
*
buf
,
int
oob_required
,
int
page
)
{
{
chip
->
write_buf
(
mtd
,
buf
,
mtd
->
writesize
);
chip
->
write_buf
(
mtd
,
buf
,
mtd
->
writesize
);
...
@@ -2398,6 +2354,7 @@ static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
...
@@ -2398,6 +2354,7 @@ static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
return
0
;
return
0
;
}
}
EXPORT_SYMBOL
(
nand_write_page_raw
);
/**
/**
* nand_write_page_raw_syndrome - [INTERN] raw page write function
* nand_write_page_raw_syndrome - [INTERN] raw page write function
...
@@ -2622,7 +2579,7 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
...
@@ -2622,7 +2579,7 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
}
}
/**
/**
* nand_write_page -
[REPLACEABLE]
write one page
* nand_write_page - write one page
* @mtd: MTD device structure
* @mtd: MTD device structure
* @chip: NAND chip descriptor
* @chip: NAND chip descriptor
* @offset: address offset within the page
* @offset: address offset within the page
...
@@ -2630,12 +2587,11 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
...
@@ -2630,12 +2587,11 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
* @buf: the data to write
* @buf: the data to write
* @oob_required: must write chip->oob_poi to OOB
* @oob_required: must write chip->oob_poi to OOB
* @page: page number to write
* @page: page number to write
* @cached: cached programming
* @raw: use _raw version of write_page
* @raw: use _raw version of write_page
*/
*/
static
int
nand_write_page
(
struct
mtd_info
*
mtd
,
struct
nand_chip
*
chip
,
static
int
nand_write_page
(
struct
mtd_info
*
mtd
,
struct
nand_chip
*
chip
,
uint32_t
offset
,
int
data_len
,
const
uint8_t
*
buf
,
uint32_t
offset
,
int
data_len
,
const
uint8_t
*
buf
,
int
oob_required
,
int
page
,
int
cached
,
int
raw
)
int
oob_required
,
int
page
,
int
raw
)
{
{
int
status
,
subpage
;
int
status
,
subpage
;
...
@@ -2645,6 +2601,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
...
@@ -2645,6 +2601,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
else
else
subpage
=
0
;
subpage
=
0
;
if
(
nand_standard_page_accessors
(
&
chip
->
ecc
))
chip
->
cmdfunc
(
mtd
,
NAND_CMD_SEQIN
,
0x00
,
page
);
chip
->
cmdfunc
(
mtd
,
NAND_CMD_SEQIN
,
0x00
,
page
);
if
(
unlikely
(
raw
))
if
(
unlikely
(
raw
))
...
@@ -2660,29 +2617,12 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
...
@@ -2660,29 +2617,12 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
if
(
status
<
0
)
if
(
status
<
0
)
return
status
;
return
status
;
/*
if
(
nand_standard_page_accessors
(
&
chip
->
ecc
))
{
* Cached progamming disabled for now. Not sure if it's worth the
* trouble. The speed gain is not very impressive. (2.3->2.6Mib/s).
*/
cached
=
0
;
if
(
!
cached
||
!
NAND_HAS_CACHEPROG
(
chip
))
{
chip
->
cmdfunc
(
mtd
,
NAND_CMD_PAGEPROG
,
-
1
,
-
1
);
chip
->
cmdfunc
(
mtd
,
NAND_CMD_PAGEPROG
,
-
1
,
-
1
);
status
=
chip
->
waitfunc
(
mtd
,
chip
);
/*
* See if operation failed and additional status checks are
* available.
*/
if
((
status
&
NAND_STATUS_FAIL
)
&&
(
chip
->
errstat
))
status
=
chip
->
errstat
(
mtd
,
chip
,
FL_WRITING
,
status
,
page
);
status
=
chip
->
waitfunc
(
mtd
,
chip
);
if
(
status
&
NAND_STATUS_FAIL
)
if
(
status
&
NAND_STATUS_FAIL
)
return
-
EIO
;
return
-
EIO
;
}
else
{
chip
->
cmdfunc
(
mtd
,
NAND_CMD_CACHEDPROG
,
-
1
,
-
1
);
status
=
chip
->
waitfunc
(
mtd
,
chip
);
}
}
return
0
;
return
0
;
...
@@ -2742,7 +2682,7 @@ static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
...
@@ -2742,7 +2682,7 @@ static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
int
nand_do_write_ops
(
struct
mtd_info
*
mtd
,
loff_t
to
,
int
nand_do_write_ops
(
struct
mtd_info
*
mtd
,
loff_t
to
,
struct
mtd_oob_ops
*
ops
)
struct
mtd_oob_ops
*
ops
)
{
{
int
chipnr
,
realpage
,
page
,
blockmask
,
column
;
int
chipnr
,
realpage
,
page
,
column
;
struct
nand_chip
*
chip
=
mtd_to_nand
(
mtd
);
struct
nand_chip
*
chip
=
mtd_to_nand
(
mtd
);
uint32_t
writelen
=
ops
->
len
;
uint32_t
writelen
=
ops
->
len
;
...
@@ -2778,7 +2718,6 @@ int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
...
@@ -2778,7 +2718,6 @@ int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
realpage
=
(
int
)(
to
>>
chip
->
page_shift
);
realpage
=
(
int
)(
to
>>
chip
->
page_shift
);
page
=
realpage
&
chip
->
pagemask
;
page
=
realpage
&
chip
->
pagemask
;
blockmask
=
(
1
<<
(
chip
->
phys_erase_shift
-
chip
->
page_shift
))
-
1
;
/* Invalidate the page cache, when we write to the cached page */
/* Invalidate the page cache, when we write to the cached page */
if
(
to
<=
((
loff_t
)
chip
->
pagebuf
<<
chip
->
page_shift
)
&&
if
(
to
<=
((
loff_t
)
chip
->
pagebuf
<<
chip
->
page_shift
)
&&
...
@@ -2793,7 +2732,6 @@ int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
...
@@ -2793,7 +2732,6 @@ int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
while
(
1
)
{
while
(
1
)
{
int
bytes
=
mtd
->
writesize
;
int
bytes
=
mtd
->
writesize
;
int
cached
=
writelen
>
bytes
&&
page
!=
blockmask
;
uint8_t
*
wbuf
=
buf
;
uint8_t
*
wbuf
=
buf
;
int
use_bufpoi
;
int
use_bufpoi
;
int
part_pagewr
=
(
column
||
writelen
<
mtd
->
writesize
);
int
part_pagewr
=
(
column
||
writelen
<
mtd
->
writesize
);
...
@@ -2801,7 +2739,9 @@ int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
...
@@ -2801,7 +2739,9 @@ int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
if
(
part_pagewr
)
if
(
part_pagewr
)
use_bufpoi
=
1
;
use_bufpoi
=
1
;
else
if
(
chip
->
options
&
NAND_USE_BOUNCE_BUFFER
)
else
if
(
chip
->
options
&
NAND_USE_BOUNCE_BUFFER
)
use_bufpoi
=
!
virt_addr_valid
(
buf
);
use_bufpoi
=
!
virt_addr_valid
(
buf
)
||
!
IS_ALIGNED
((
unsigned
long
)
buf
,
chip
->
buf_align
);
else
else
use_bufpoi
=
0
;
use_bufpoi
=
0
;
...
@@ -2809,7 +2749,6 @@ int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
...
@@ -2809,7 +2749,6 @@ int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
if
(
use_bufpoi
)
{
if
(
use_bufpoi
)
{
pr_debug
(
"%s: using write bounce buffer for buf@%p
\n
"
,
pr_debug
(
"%s: using write bounce buffer for buf@%p
\n
"
,
__func__
,
buf
);
__func__
,
buf
);
cached
=
0
;
if
(
part_pagewr
)
if
(
part_pagewr
)
bytes
=
min_t
(
int
,
bytes
-
column
,
writelen
);
bytes
=
min_t
(
int
,
bytes
-
column
,
writelen
);
chip
->
pagebuf
=
-
1
;
chip
->
pagebuf
=
-
1
;
...
@@ -2826,8 +2765,9 @@ int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
...
@@ -2826,8 +2765,9 @@ int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
/* We still need to erase leftover OOB data */
/* We still need to erase leftover OOB data */
memset
(
chip
->
oob_poi
,
0xff
,
mtd
->
oobsize
);
memset
(
chip
->
oob_poi
,
0xff
,
mtd
->
oobsize
);
}
}
ret
=
chip
->
write_page
(
mtd
,
chip
,
column
,
bytes
,
wbuf
,
oob_required
,
page
,
cached
,
ret
=
nand_write_page
(
mtd
,
chip
,
column
,
bytes
,
wbuf
,
oob_required
,
page
,
(
ops
->
mode
==
MTD_OPS_RAW
));
(
ops
->
mode
==
MTD_OPS_RAW
));
if
(
ret
)
if
(
ret
)
break
;
break
;
...
@@ -3153,14 +3093,6 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
...
@@ -3153,14 +3093,6 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
status
=
chip
->
erase
(
mtd
,
page
&
chip
->
pagemask
);
status
=
chip
->
erase
(
mtd
,
page
&
chip
->
pagemask
);
/*
* See if operation failed and additional status checks are
* available
*/
if
((
status
&
NAND_STATUS_FAIL
)
&&
(
chip
->
errstat
))
status
=
chip
->
errstat
(
mtd
,
chip
,
FL_ERASING
,
status
,
page
);
/* See if block erase succeeded */
/* See if block erase succeeded */
if
(
status
&
NAND_STATUS_FAIL
)
{
if
(
status
&
NAND_STATUS_FAIL
)
{
pr_debug
(
"%s: failed erase, page 0x%08x
\n
"
,
pr_debug
(
"%s: failed erase, page 0x%08x
\n
"
,
...
@@ -3259,6 +3191,42 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
...
@@ -3259,6 +3191,42 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
return
nand_block_markbad_lowlevel
(
mtd
,
ofs
);
return
nand_block_markbad_lowlevel
(
mtd
,
ofs
);
}
}
/**
* nand_max_bad_blocks - [MTD Interface] Max number of bad blocks for an mtd
* @mtd: MTD device structure
* @ofs: offset relative to mtd start
* @len: length of mtd
*/
static
int
nand_max_bad_blocks
(
struct
mtd_info
*
mtd
,
loff_t
ofs
,
size_t
len
)
{
struct
nand_chip
*
chip
=
mtd_to_nand
(
mtd
);
u32
part_start_block
;
u32
part_end_block
;
u32
part_start_die
;
u32
part_end_die
;
/*
* max_bb_per_die and blocks_per_die used to determine
* the maximum bad block count.
*/
if
(
!
chip
->
max_bb_per_die
||
!
chip
->
blocks_per_die
)
return
-
ENOTSUPP
;
/* Get the start and end of the partition in erase blocks. */
part_start_block
=
mtd_div_by_eb
(
ofs
,
mtd
);
part_end_block
=
mtd_div_by_eb
(
len
,
mtd
)
+
part_start_block
-
1
;
/* Get the start and end LUNs of the partition. */
part_start_die
=
part_start_block
/
chip
->
blocks_per_die
;
part_end_die
=
part_end_block
/
chip
->
blocks_per_die
;
/*
* Look up the bad blocks per unit and multiply by the number of units
* that the partition spans.
*/
return
chip
->
max_bb_per_die
*
(
part_end_die
-
part_start_die
+
1
);
}
/**
/**
* nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
* nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
* @mtd: MTD device structure
* @mtd: MTD device structure
...
@@ -3310,6 +3278,25 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
...
@@ -3310,6 +3278,25 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
return
0
;
return
0
;
}
}
/**
* nand_onfi_get_set_features_notsupp - set/get features stub returning
* -ENOTSUPP
* @mtd: MTD device structure
* @chip: nand chip info structure
* @addr: feature address.
* @subfeature_param: the subfeature parameters, a four bytes array.
*
* Should be used by NAND controller drivers that do not support the SET/GET
* FEATURES operations.
*/
int
nand_onfi_get_set_features_notsupp
(
struct
mtd_info
*
mtd
,
struct
nand_chip
*
chip
,
int
addr
,
u8
*
subfeature_param
)
{
return
-
ENOTSUPP
;
}
EXPORT_SYMBOL
(
nand_onfi_get_set_features_notsupp
);
/**
/**
* nand_suspend - [MTD Interface] Suspend the NAND flash
* nand_suspend - [MTD Interface] Suspend the NAND flash
* @mtd: MTD device structure
* @mtd: MTD device structure
...
@@ -3345,8 +3332,10 @@ static void nand_shutdown(struct mtd_info *mtd)
...
@@ -3345,8 +3332,10 @@ static void nand_shutdown(struct mtd_info *mtd)
}
}
/* Set default functions */
/* Set default functions */
static
void
nand_set_defaults
(
struct
nand_chip
*
chip
,
int
busw
)
static
void
nand_set_defaults
(
struct
nand_chip
*
chip
)
{
{
unsigned
int
busw
=
chip
->
options
&
NAND_BUSWIDTH_16
;
/* check for proper chip_delay setup, set 20us if not */
/* check for proper chip_delay setup, set 20us if not */
if
(
!
chip
->
chip_delay
)
if
(
!
chip
->
chip_delay
)
chip
->
chip_delay
=
20
;
chip
->
chip_delay
=
20
;
...
@@ -3391,6 +3380,8 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
...
@@ -3391,6 +3380,8 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
nand_hw_control_init
(
chip
->
controller
);
nand_hw_control_init
(
chip
->
controller
);
}
}
if
(
!
chip
->
buf_align
)
chip
->
buf_align
=
1
;
}
}
/* Sanitize ONFI strings so we can safely print them */
/* Sanitize ONFI strings so we can safely print them */
...
@@ -3424,9 +3415,10 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
...
@@ -3424,9 +3415,10 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
}
}
/* Parse the Extended Parameter Page. */
/* Parse the Extended Parameter Page. */
static
int
nand_flash_detect_ext_param_page
(
struct
mtd_info
*
mtd
,
static
int
nand_flash_detect_ext_param_page
(
struct
nand_chip
*
chip
,
struct
nand_chip
*
chip
,
struct
nand_onfi_params
*
p
)
struct
nand_onfi_params
*
p
)
{
{
struct
mtd_info
*
mtd
=
nand_to_mtd
(
chip
);
struct
onfi_ext_param_page
*
ep
;
struct
onfi_ext_param_page
*
ep
;
struct
onfi_ext_section
*
s
;
struct
onfi_ext_section
*
s
;
struct
onfi_ext_ecc_info
*
ecc
;
struct
onfi_ext_ecc_info
*
ecc
;
...
@@ -3494,39 +3486,15 @@ ext_out:
...
@@ -3494,39 +3486,15 @@ ext_out:
return
ret
;
return
ret
;
}
}
static
int
nand_setup_read_retry_micron
(
struct
mtd_info
*
mtd
,
int
retry_mode
)
{
struct
nand_chip
*
chip
=
mtd_to_nand
(
mtd
);
uint8_t
feature
[
ONFI_SUBFEATURE_PARAM_LEN
]
=
{
retry_mode
};
return
chip
->
onfi_set_features
(
mtd
,
chip
,
ONFI_FEATURE_ADDR_READ_RETRY
,
feature
);
}
/*
/*
* C
onfigure chip properties from Micron vendor-specific ONFI table
* C
heck if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
*/
*/
static
void
nand_onfi_detect_micron
(
struct
nand_chip
*
chip
,
static
int
nand_flash_detect_onfi
(
struct
nand_chip
*
chip
)
struct
nand_onfi_params
*
p
)
{
{
struct
nand_onfi_vendor_micron
*
micron
=
(
void
*
)
p
->
vendor
;
struct
mtd_info
*
mtd
=
nand_to_mtd
(
chip
);
struct
nand_onfi_params
*
p
=
&
chip
->
onfi_params
;
if
(
le16_to_cpu
(
p
->
vendor_revision
)
<
1
)
int
i
,
j
;
return
;
int
val
;
chip
->
read_retries
=
micron
->
read_retry_options
;
chip
->
setup_read_retry
=
nand_setup_read_retry_micron
;
}
/*
* Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
*/
static
int
nand_flash_detect_onfi
(
struct
mtd_info
*
mtd
,
struct
nand_chip
*
chip
,
int
*
busw
)
{
struct
nand_onfi_params
*
p
=
&
chip
->
onfi_params
;
int
i
,
j
;
int
val
;
/* ONFI need to be probed in 8 bits mode, and 16 bits should be selected with NAND_BUSWIDTH_AUTO */
/* ONFI need to be probed in 8 bits mode, and 16 bits should be selected with NAND_BUSWIDTH_AUTO */
if
(
chip
->
options
&
NAND_BUSWIDTH_16
)
{
if
(
chip
->
options
&
NAND_BUSWIDTH_16
)
{
...
@@ -3595,10 +3563,11 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
...
@@ -3595,10 +3563,11 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
chip
->
chipsize
*=
(
uint64_t
)
mtd
->
erasesize
*
p
->
lun_count
;
chip
->
chipsize
*=
(
uint64_t
)
mtd
->
erasesize
*
p
->
lun_count
;
chip
->
bits_per_cell
=
p
->
bits_per_cell
;
chip
->
bits_per_cell
=
p
->
bits_per_cell
;
chip
->
max_bb_per_die
=
le16_to_cpu
(
p
->
bb_per_lun
);
chip
->
blocks_per_die
=
le32_to_cpu
(
p
->
blocks_per_lun
);
if
(
onfi_feature
(
chip
)
&
ONFI_FEATURE_16_BIT_BUS
)
if
(
onfi_feature
(
chip
)
&
ONFI_FEATURE_16_BIT_BUS
)
*
busw
=
NAND_BUSWIDTH_16
;
chip
->
options
|=
NAND_BUSWIDTH_16
;
else
*
busw
=
0
;
if
(
p
->
ecc_bits
!=
0xff
)
{
if
(
p
->
ecc_bits
!=
0xff
)
{
chip
->
ecc_strength_ds
=
p
->
ecc_bits
;
chip
->
ecc_strength_ds
=
p
->
ecc_bits
;
...
@@ -3616,24 +3585,21 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
...
@@ -3616,24 +3585,21 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
chip
->
cmdfunc
=
nand_command_lp
;
chip
->
cmdfunc
=
nand_command_lp
;
/* The Extended Parameter Page is supported since ONFI 2.1. */
/* The Extended Parameter Page is supported since ONFI 2.1. */
if
(
nand_flash_detect_ext_param_page
(
mtd
,
chip
,
p
))
if
(
nand_flash_detect_ext_param_page
(
chip
,
p
))
pr_warn
(
"Failed to detect ONFI extended param page
\n
"
);
pr_warn
(
"Failed to detect ONFI extended param page
\n
"
);
}
else
{
}
else
{
pr_warn
(
"Could not retrieve ONFI ECC requirements
\n
"
);
pr_warn
(
"Could not retrieve ONFI ECC requirements
\n
"
);
}
}
if
(
p
->
jedec_id
==
NAND_MFR_MICRON
)
nand_onfi_detect_micron
(
chip
,
p
);
return
1
;
return
1
;
}
}
/*
/*
* Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
* Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
*/
*/
static
int
nand_flash_detect_jedec
(
struct
mtd_info
*
mtd
,
struct
nand_chip
*
chip
,
static
int
nand_flash_detect_jedec
(
struct
nand_chip
*
chip
)
int
*
busw
)
{
{
struct
mtd_info
*
mtd
=
nand_to_mtd
(
chip
);
struct
nand_jedec_params
*
p
=
&
chip
->
jedec_params
;
struct
nand_jedec_params
*
p
=
&
chip
->
jedec_params
;
struct
jedec_ecc_info
*
ecc
;
struct
jedec_ecc_info
*
ecc
;
int
val
;
int
val
;
...
@@ -3692,9 +3658,7 @@ static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip,
...
@@ -3692,9 +3658,7 @@ static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip,
chip
->
bits_per_cell
=
p
->
bits_per_cell
;
chip
->
bits_per_cell
=
p
->
bits_per_cell
;
if
(
jedec_feature
(
chip
)
&
JEDEC_FEATURE_16_BIT_BUS
)
if
(
jedec_feature
(
chip
)
&
JEDEC_FEATURE_16_BIT_BUS
)
*
busw
=
NAND_BUSWIDTH_16
;
chip
->
options
|=
NAND_BUSWIDTH_16
;
else
*
busw
=
0
;
/* ECC info */
/* ECC info */
ecc
=
&
p
->
ecc_info
[
0
];
ecc
=
&
p
->
ecc_info
[
0
];
...
@@ -3783,165 +3747,46 @@ static int nand_get_bits_per_cell(u8 cellinfo)
...
@@ -3783,165 +3747,46 @@ static int nand_get_bits_per_cell(u8 cellinfo)
* chip. The rest of the parameters must be decoded according to generic or
* chip. The rest of the parameters must be decoded according to generic or
* manufacturer-specific "extended ID" decoding patterns.
* manufacturer-specific "extended ID" decoding patterns.
*/
*/
static
void
nand_decode_ext_id
(
struct
mtd_info
*
mtd
,
struct
nand_chip
*
chip
,
void
nand_decode_ext_id
(
struct
nand_chip
*
chip
)
u8
id_data
[
8
],
int
*
busw
)
{
{
int
extid
,
id_len
;
struct
mtd_info
*
mtd
=
nand_to_mtd
(
chip
);
int
extid
;
u8
*
id_data
=
chip
->
id
.
data
;
/* The 3rd id byte holds MLC / multichip data */
/* The 3rd id byte holds MLC / multichip data */
chip
->
bits_per_cell
=
nand_get_bits_per_cell
(
id_data
[
2
]);
chip
->
bits_per_cell
=
nand_get_bits_per_cell
(
id_data
[
2
]);
/* The 4th id byte is the important one */
/* The 4th id byte is the important one */
extid
=
id_data
[
3
];
extid
=
id_data
[
3
];
id_len
=
nand_id_len
(
id_data
,
8
);
/*
* Field definitions are in the following datasheets:
* Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44)
* Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22)
*
* Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung
* ID to decide what to do.
*/
if
(
id_len
==
6
&&
id_data
[
0
]
==
NAND_MFR_SAMSUNG
&&
!
nand_is_slc
(
chip
)
&&
id_data
[
5
]
!=
0x00
)
{
/* Calc pagesize */
mtd
->
writesize
=
2048
<<
(
extid
&
0x03
);
extid
>>=
2
;
/* Calc oobsize */
switch
(((
extid
>>
2
)
&
0x04
)
|
(
extid
&
0x03
))
{
case
1
:
mtd
->
oobsize
=
128
;
break
;
case
2
:
mtd
->
oobsize
=
218
;
break
;
case
3
:
mtd
->
oobsize
=
400
;
break
;
case
4
:
mtd
->
oobsize
=
436
;
break
;
case
5
:
mtd
->
oobsize
=
512
;
break
;
case
6
:
mtd
->
oobsize
=
640
;
break
;
case
7
:
default:
/* Other cases are "reserved" (unknown) */
mtd
->
oobsize
=
1024
;
break
;
}
extid
>>=
2
;
/* Calc blocksize */
mtd
->
erasesize
=
(
128
*
1024
)
<<
(((
extid
>>
1
)
&
0x04
)
|
(
extid
&
0x03
));
*
busw
=
0
;
}
else
if
(
id_len
==
6
&&
id_data
[
0
]
==
NAND_MFR_HYNIX
&&
!
nand_is_slc
(
chip
))
{
unsigned
int
tmp
;
/* Calc pagesize */
mtd
->
writesize
=
2048
<<
(
extid
&
0x03
);
extid
>>=
2
;
/* Calc oobsize */
switch
(((
extid
>>
2
)
&
0x04
)
|
(
extid
&
0x03
))
{
case
0
:
mtd
->
oobsize
=
128
;
break
;
case
1
:
mtd
->
oobsize
=
224
;
break
;
case
2
:
mtd
->
oobsize
=
448
;
break
;
case
3
:
mtd
->
oobsize
=
64
;
break
;
case
4
:
mtd
->
oobsize
=
32
;
break
;
case
5
:
mtd
->
oobsize
=
16
;
break
;
default:
mtd
->
oobsize
=
640
;
break
;
}
extid
>>=
2
;
/* Calc blocksize */
tmp
=
((
extid
>>
1
)
&
0x04
)
|
(
extid
&
0x03
);
if
(
tmp
<
0x03
)
mtd
->
erasesize
=
(
128
*
1024
)
<<
tmp
;
else
if
(
tmp
==
0x03
)
mtd
->
erasesize
=
768
*
1024
;
else
mtd
->
erasesize
=
(
64
*
1024
)
<<
tmp
;
*
busw
=
0
;
}
else
{
/* Calc pagesize */
/* Calc pagesize */
mtd
->
writesize
=
1024
<<
(
extid
&
0x03
);
mtd
->
writesize
=
1024
<<
(
extid
&
0x03
);
extid
>>=
2
;
extid
>>=
2
;
/* Calc oobsize */
/* Calc oobsize */
mtd
->
oobsize
=
(
8
<<
(
extid
&
0x01
))
*
mtd
->
oobsize
=
(
8
<<
(
extid
&
0x01
))
*
(
mtd
->
writesize
>>
9
);
(
mtd
->
writesize
>>
9
);
extid
>>=
2
;
extid
>>=
2
;
/* Calc blocksize. Blocksize is multiples of 64KiB */
/* Calc blocksize. Blocksize is multiples of 64KiB */
mtd
->
erasesize
=
(
64
*
1024
)
<<
(
extid
&
0x03
);
mtd
->
erasesize
=
(
64
*
1024
)
<<
(
extid
&
0x03
);
extid
>>=
2
;
extid
>>=
2
;
/* Get buswidth information */
/* Get buswidth information */
*
busw
=
(
extid
&
0x01
)
?
NAND_BUSWIDTH_16
:
0
;
if
(
extid
&
0x1
)
chip
->
options
|=
NAND_BUSWIDTH_16
;
/*
* Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
* 512B page. For Toshiba SLC, we decode the 5th/6th byte as
* follows:
* - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
* 110b -> 24nm
* - ID byte 5, bit[7]: 1 -> BENAND, 0 -> raw SLC
*/
if
(
id_len
>=
6
&&
id_data
[
0
]
==
NAND_MFR_TOSHIBA
&&
nand_is_slc
(
chip
)
&&
(
id_data
[
5
]
&
0x7
)
==
0x6
/* 24nm */
&&
!
(
id_data
[
4
]
&
0x80
)
/* !BENAND */
)
{
mtd
->
oobsize
=
32
*
mtd
->
writesize
>>
9
;
}
}
}
}
EXPORT_SYMBOL_GPL
(
nand_decode_ext_id
);
/*
/*
* Old devices have chip data hardcoded in the device ID table. nand_decode_id
* Old devices have chip data hardcoded in the device ID table. nand_decode_id
* decodes a matching ID table entry and assigns the MTD size parameters for
* decodes a matching ID table entry and assigns the MTD size parameters for
* the chip.
* the chip.
*/
*/
static
void
nand_decode_id
(
struct
mtd_info
*
mtd
,
struct
nand_chip
*
chip
,
static
void
nand_decode_id
(
struct
nand_chip
*
chip
,
struct
nand_flash_dev
*
type
)
struct
nand_flash_dev
*
type
,
u8
id_data
[
8
],
int
*
busw
)
{
{
int
maf_id
=
id_data
[
0
]
;
struct
mtd_info
*
mtd
=
nand_to_mtd
(
chip
)
;
mtd
->
erasesize
=
type
->
erasesize
;
mtd
->
erasesize
=
type
->
erasesize
;
mtd
->
writesize
=
type
->
pagesize
;
mtd
->
writesize
=
type
->
pagesize
;
mtd
->
oobsize
=
mtd
->
writesize
/
32
;
mtd
->
oobsize
=
mtd
->
writesize
/
32
;
*
busw
=
type
->
options
&
NAND_BUSWIDTH_16
;
/* All legacy ID NAND are small-page, SLC */
/* All legacy ID NAND are small-page, SLC */
chip
->
bits_per_cell
=
1
;
chip
->
bits_per_cell
=
1
;
/*
* Check for Spansion/AMD ID + repeating 5th, 6th byte since
* some Spansion chips have erasesize that conflicts with size
* listed in nand_ids table.
* Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
*/
if
(
maf_id
==
NAND_MFR_AMD
&&
id_data
[
4
]
!=
0x00
&&
id_data
[
5
]
==
0x00
&&
id_data
[
6
]
==
0x00
&&
id_data
[
7
]
==
0x00
&&
mtd
->
writesize
==
512
)
{
mtd
->
erasesize
=
128
*
1024
;
mtd
->
erasesize
<<=
((
id_data
[
3
]
&
0x03
)
<<
1
);
}
}
}
/*
/*
...
@@ -3949,36 +3794,15 @@ static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
...
@@ -3949,36 +3794,15 @@ static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
* heuristic patterns using various detected parameters (e.g., manufacturer,
* heuristic patterns using various detected parameters (e.g., manufacturer,
* page size, cell-type information).
* page size, cell-type information).
*/
*/
static
void
nand_decode_bbm_options
(
struct
mtd_info
*
mtd
,
static
void
nand_decode_bbm_options
(
struct
nand_chip
*
chip
)
struct
nand_chip
*
chip
,
u8
id_data
[
8
])
{
{
int
maf_id
=
id_data
[
0
]
;
struct
mtd_info
*
mtd
=
nand_to_mtd
(
chip
)
;
/* Set the bad block position */
/* Set the bad block position */
if
(
mtd
->
writesize
>
512
||
(
chip
->
options
&
NAND_BUSWIDTH_16
))
if
(
mtd
->
writesize
>
512
||
(
chip
->
options
&
NAND_BUSWIDTH_16
))
chip
->
badblockpos
=
NAND_LARGE_BADBLOCK_POS
;
chip
->
badblockpos
=
NAND_LARGE_BADBLOCK_POS
;
else
else
chip
->
badblockpos
=
NAND_SMALL_BADBLOCK_POS
;
chip
->
badblockpos
=
NAND_SMALL_BADBLOCK_POS
;
/*
* Bad block marker is stored in the last page of each block on Samsung
* and Hynix MLC devices; stored in first two pages of each block on
* Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba,
* AMD/Spansion, and Macronix. All others scan only the first page.
*/
if
(
!
nand_is_slc
(
chip
)
&&
(
maf_id
==
NAND_MFR_SAMSUNG
||
maf_id
==
NAND_MFR_HYNIX
))
chip
->
bbt_options
|=
NAND_BBT_SCANLASTPAGE
;
else
if
((
nand_is_slc
(
chip
)
&&
(
maf_id
==
NAND_MFR_SAMSUNG
||
maf_id
==
NAND_MFR_HYNIX
||
maf_id
==
NAND_MFR_TOSHIBA
||
maf_id
==
NAND_MFR_AMD
||
maf_id
==
NAND_MFR_MACRONIX
))
||
(
mtd
->
writesize
==
2048
&&
maf_id
==
NAND_MFR_MICRON
))
chip
->
bbt_options
|=
NAND_BBT_SCAN2NDPAGE
;
}
}
static
inline
bool
is_full_id_nand
(
struct
nand_flash_dev
*
type
)
static
inline
bool
is_full_id_nand
(
struct
nand_flash_dev
*
type
)
...
@@ -3986,9 +3810,12 @@ static inline bool is_full_id_nand(struct nand_flash_dev *type)
...
@@ -3986,9 +3810,12 @@ static inline bool is_full_id_nand(struct nand_flash_dev *type)
return
type
->
id_len
;
return
type
->
id_len
;
}
}
static
bool
find_full_id_nand
(
struct
mtd_info
*
mtd
,
struct
nand_chip
*
chip
,
static
bool
find_full_id_nand
(
struct
nand_chip
*
chip
,
struct
nand_flash_dev
*
type
,
u8
*
id_data
,
int
*
busw
)
struct
nand_flash_dev
*
type
)
{
{
struct
mtd_info
*
mtd
=
nand_to_mtd
(
chip
);
u8
*
id_data
=
chip
->
id
.
data
;
if
(
!
strncmp
(
type
->
id
,
id_data
,
type
->
id_len
))
{
if
(
!
strncmp
(
type
->
id
,
id_data
,
type
->
id_len
))
{
mtd
->
writesize
=
type
->
pagesize
;
mtd
->
writesize
=
type
->
pagesize
;
mtd
->
erasesize
=
type
->
erasesize
;
mtd
->
erasesize
=
type
->
erasesize
;
...
@@ -4002,8 +3829,6 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
...
@@ -4002,8 +3829,6 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
chip
->
onfi_timing_mode_default
=
chip
->
onfi_timing_mode_default
=
type
->
onfi_timing_mode_default
;
type
->
onfi_timing_mode_default
;
*
busw
=
type
->
options
&
NAND_BUSWIDTH_16
;
if
(
!
mtd
->
name
)
if
(
!
mtd
->
name
)
mtd
->
name
=
type
->
name
;
mtd
->
name
=
type
->
name
;
...
@@ -4012,17 +3837,67 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
...
@@ -4012,17 +3837,67 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
return
false
;
return
false
;
}
}
/*
* Manufacturer detection. Only used when the NAND is not ONFI or JEDEC
* compliant and does not have a full-id or legacy-id entry in the nand_ids
* table.
*/
static
void
nand_manufacturer_detect
(
struct
nand_chip
*
chip
)
{
/*
* Try manufacturer detection if available and use
* nand_decode_ext_id() otherwise.
*/
if
(
chip
->
manufacturer
.
desc
&&
chip
->
manufacturer
.
desc
->
ops
&&
chip
->
manufacturer
.
desc
->
ops
->
detect
)
{
/* The 3rd id byte holds MLC / multichip data */
chip
->
bits_per_cell
=
nand_get_bits_per_cell
(
chip
->
id
.
data
[
2
]);
chip
->
manufacturer
.
desc
->
ops
->
detect
(
chip
);
}
else
{
nand_decode_ext_id
(
chip
);
}
}
/*
* Manufacturer initialization. This function is called for all NANDs including
* ONFI and JEDEC compliant ones.
* Manufacturer drivers should put all their specific initialization code in
* their ->init() hook.
*/
static
int
nand_manufacturer_init
(
struct
nand_chip
*
chip
)
{
if
(
!
chip
->
manufacturer
.
desc
||
!
chip
->
manufacturer
.
desc
->
ops
||
!
chip
->
manufacturer
.
desc
->
ops
->
init
)
return
0
;
return
chip
->
manufacturer
.
desc
->
ops
->
init
(
chip
);
}
/*
* Manufacturer cleanup. This function is called for all NANDs including
* ONFI and JEDEC compliant ones.
* Manufacturer drivers should put all their specific cleanup code in their
* ->cleanup() hook.
*/
static
void
nand_manufacturer_cleanup
(
struct
nand_chip
*
chip
)
{
/* Release manufacturer private data */
if
(
chip
->
manufacturer
.
desc
&&
chip
->
manufacturer
.
desc
->
ops
&&
chip
->
manufacturer
.
desc
->
ops
->
cleanup
)
chip
->
manufacturer
.
desc
->
ops
->
cleanup
(
chip
);
}
/*
/*
* Get the flash and manufacturer id and lookup if the type is supported.
* Get the flash and manufacturer id and lookup if the type is supported.
*/
*/
static
struct
nand_flash_dev
*
nand_get_flash_type
(
struct
mtd_info
*
mtd
,
static
int
nand_detect
(
struct
nand_chip
*
chip
,
struct
nand_flash_dev
*
type
)
struct
nand_chip
*
chip
,
int
*
maf_id
,
int
*
dev_id
,
struct
nand_flash_dev
*
type
)
{
{
const
struct
nand_manufacturer
*
manufacturer
;
struct
mtd_info
*
mtd
=
nand_to_mtd
(
chip
);
int
busw
;
int
busw
;
int
i
,
maf_idx
;
int
i
;
u8
id_data
[
8
];
u8
*
id_data
=
chip
->
id
.
data
;
u8
maf_id
,
dev_id
;
/*
/*
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
...
@@ -4037,8 +3912,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
...
@@ -4037,8 +3912,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
chip
->
cmdfunc
(
mtd
,
NAND_CMD_READID
,
0x00
,
-
1
);
chip
->
cmdfunc
(
mtd
,
NAND_CMD_READID
,
0x00
,
-
1
);
/* Read manufacturer and device IDs */
/* Read manufacturer and device IDs */
*
maf_id
=
chip
->
read_byte
(
mtd
);
maf_id
=
chip
->
read_byte
(
mtd
);
*
dev_id
=
chip
->
read_byte
(
mtd
);
dev_id
=
chip
->
read_byte
(
mtd
);
/*
/*
* Try again to make sure, as some systems the bus-hold or other
* Try again to make sure, as some systems the bus-hold or other
...
@@ -4050,23 +3925,44 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
...
@@ -4050,23 +3925,44 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
chip
->
cmdfunc
(
mtd
,
NAND_CMD_READID
,
0x00
,
-
1
);
chip
->
cmdfunc
(
mtd
,
NAND_CMD_READID
,
0x00
,
-
1
);
/* Read entire ID string */
/* Read entire ID string */
for
(
i
=
0
;
i
<
8
;
i
++
)
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
chip
->
id
.
data
)
;
i
++
)
id_data
[
i
]
=
chip
->
read_byte
(
mtd
);
id_data
[
i
]
=
chip
->
read_byte
(
mtd
);
if
(
id_data
[
0
]
!=
*
maf_id
||
id_data
[
1
]
!=
*
dev_id
)
{
if
(
id_data
[
0
]
!=
maf_id
||
id_data
[
1
]
!=
dev_id
)
{
pr_info
(
"second ID read did not match %02x,%02x against %02x,%02x
\n
"
,
pr_info
(
"second ID read did not match %02x,%02x against %02x,%02x
\n
"
,
*
maf_id
,
*
dev_id
,
id_data
[
0
],
id_data
[
1
]);
maf_id
,
dev_id
,
id_data
[
0
],
id_data
[
1
]);
return
ERR_PTR
(
-
ENODEV
)
;
return
-
ENODEV
;
}
}
chip
->
id
.
len
=
nand_id_len
(
id_data
,
ARRAY_SIZE
(
chip
->
id
.
data
));
/* Try to identify manufacturer */
manufacturer
=
nand_get_manufacturer
(
maf_id
);
chip
->
manufacturer
.
desc
=
manufacturer
;
if
(
!
type
)
if
(
!
type
)
type
=
nand_flash_ids
;
type
=
nand_flash_ids
;
/*
* Save the NAND_BUSWIDTH_16 flag before letting auto-detection logic
* override it.
* This is required to make sure initial NAND bus width set by the
* NAND controller driver is coherent with the real NAND bus width
* (extracted by auto-detection code).
*/
busw
=
chip
->
options
&
NAND_BUSWIDTH_16
;
/*
* The flag is only set (never cleared), reset it to its default value
* before starting auto-detection.
*/
chip
->
options
&=
~
NAND_BUSWIDTH_16
;
for
(;
type
->
name
!=
NULL
;
type
++
)
{
for
(;
type
->
name
!=
NULL
;
type
++
)
{
if
(
is_full_id_nand
(
type
))
{
if
(
is_full_id_nand
(
type
))
{
if
(
find_full_id_nand
(
mtd
,
chip
,
type
,
id_data
,
&
busw
))
if
(
find_full_id_nand
(
chip
,
type
))
goto
ident_done
;
goto
ident_done
;
}
else
if
(
*
dev_id
==
type
->
dev_id
)
{
}
else
if
(
dev_id
==
type
->
dev_id
)
{
break
;
break
;
}
}
}
}
...
@@ -4074,64 +3970,50 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
...
@@ -4074,64 +3970,50 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
chip
->
onfi_version
=
0
;
chip
->
onfi_version
=
0
;
if
(
!
type
->
name
||
!
type
->
pagesize
)
{
if
(
!
type
->
name
||
!
type
->
pagesize
)
{
/* Check if the chip is ONFI compliant */
/* Check if the chip is ONFI compliant */
if
(
nand_flash_detect_onfi
(
mtd
,
chip
,
&
busw
))
if
(
nand_flash_detect_onfi
(
chip
))
goto
ident_done
;
goto
ident_done
;
/* Check if the chip is JEDEC compliant */
/* Check if the chip is JEDEC compliant */
if
(
nand_flash_detect_jedec
(
mtd
,
chip
,
&
busw
))
if
(
nand_flash_detect_jedec
(
chip
))
goto
ident_done
;
goto
ident_done
;
}
}
if
(
!
type
->
name
)
if
(
!
type
->
name
)
return
ERR_PTR
(
-
ENODEV
)
;
return
-
ENODEV
;
if
(
!
mtd
->
name
)
if
(
!
mtd
->
name
)
mtd
->
name
=
type
->
name
;
mtd
->
name
=
type
->
name
;
chip
->
chipsize
=
(
uint64_t
)
type
->
chipsize
<<
20
;
chip
->
chipsize
=
(
uint64_t
)
type
->
chipsize
<<
20
;
if
(
!
type
->
pagesize
)
{
if
(
!
type
->
pagesize
)
/* Decode parameters from extended ID */
nand_manufacturer_detect
(
chip
);
nand_decode_ext_id
(
mtd
,
chip
,
id_data
,
&
busw
);
else
}
else
{
nand_decode_id
(
chip
,
type
);
nand_decode_id
(
mtd
,
chip
,
type
,
id_data
,
&
busw
);
}
/* Get chip options */
/* Get chip options */
chip
->
options
|=
type
->
options
;
chip
->
options
|=
type
->
options
;
/*
* Check if chip is not a Samsung device. Do not clear the
* options for chips which do not have an extended id.
*/
if
(
*
maf_id
!=
NAND_MFR_SAMSUNG
&&
!
type
->
pagesize
)
chip
->
options
&=
~
NAND_SAMSUNG_LP_OPTIONS
;
ident_done:
ident_done:
/* Try to identify manufacturer */
for
(
maf_idx
=
0
;
nand_manuf_ids
[
maf_idx
].
id
!=
0x0
;
maf_idx
++
)
{
if
(
nand_manuf_ids
[
maf_idx
].
id
==
*
maf_id
)
break
;
}
if
(
chip
->
options
&
NAND_BUSWIDTH_AUTO
)
{
if
(
chip
->
options
&
NAND_BUSWIDTH_AUTO
)
{
WARN_ON
(
chip
->
options
&
NAND_BUSWIDTH_16
);
WARN_ON
(
busw
&
NAND_BUSWIDTH_16
);
chip
->
options
|=
busw
;
nand_set_defaults
(
chip
);
nand_set_defaults
(
chip
,
busw
);
}
else
if
(
busw
!=
(
chip
->
options
&
NAND_BUSWIDTH_16
))
{
}
else
if
(
busw
!=
(
chip
->
options
&
NAND_BUSWIDTH_16
))
{
/*
/*
* Check, if buswidth is correct. Hardware drivers should set
* Check, if buswidth is correct. Hardware drivers should set
* chip correct!
* chip correct!
*/
*/
pr_info
(
"device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x
\n
"
,
pr_info
(
"device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x
\n
"
,
*
maf_id
,
*
dev_id
);
maf_id
,
dev_id
);
pr_info
(
"%s %s
\n
"
,
nand_manuf
_ids
[
maf_idx
].
name
,
mtd
->
name
);
pr_info
(
"%s %s
\n
"
,
nand_manuf
acturer_name
(
manufacturer
),
pr_warn
(
"bus width %d instead %d bit
\n
"
,
mtd
->
name
);
(
chip
->
options
&
NAND_BUSWIDTH_16
)
?
16
:
8
,
pr_warn
(
"bus width %d instead of %d bits
\n
"
,
busw
?
16
:
8
,
busw
?
16
:
8
);
(
chip
->
options
&
NAND_BUSWIDTH_16
)
?
16
:
8
);
return
ERR_PTR
(
-
EINVAL
)
;
return
-
EINVAL
;
}
}
nand_decode_bbm_options
(
mtd
,
chip
,
id_data
);
nand_decode_bbm_options
(
chip
);
/* Calculate the address shift from the page size */
/* Calculate the address shift from the page size */
chip
->
page_shift
=
ffs
(
mtd
->
writesize
)
-
1
;
chip
->
page_shift
=
ffs
(
mtd
->
writesize
)
-
1
;
...
@@ -4154,25 +4036,23 @@ ident_done:
...
@@ -4154,25 +4036,23 @@ ident_done:
if
(
mtd
->
writesize
>
512
&&
chip
->
cmdfunc
==
nand_command
)
if
(
mtd
->
writesize
>
512
&&
chip
->
cmdfunc
==
nand_command
)
chip
->
cmdfunc
=
nand_command_lp
;
chip
->
cmdfunc
=
nand_command_lp
;
if
(
*
maf_id
==
NAND_MFR_MICRON
)
nandchip_micron_init
(
mtd
,
*
dev_id
);
pr_info
(
"device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x
\n
"
,
pr_info
(
"device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x
\n
"
,
*
maf_id
,
*
dev_id
);
maf_id
,
dev_id
);
if
(
chip
->
onfi_version
)
if
(
chip
->
onfi_version
)
pr_info
(
"%s %s
\n
"
,
nand_manuf
_ids
[
maf_idx
].
name
,
pr_info
(
"%s %s
\n
"
,
nand_manuf
acturer_name
(
manufacturer
)
,
chip
->
onfi_params
.
model
);
chip
->
onfi_params
.
model
);
else
if
(
chip
->
jedec_version
)
else
if
(
chip
->
jedec_version
)
pr_info
(
"%s %s
\n
"
,
nand_manuf
_ids
[
maf_idx
].
name
,
pr_info
(
"%s %s
\n
"
,
nand_manuf
acturer_name
(
manufacturer
)
,
chip
->
jedec_params
.
model
);
chip
->
jedec_params
.
model
);
else
else
pr_info
(
"%s %s
\n
"
,
nand_manuf
_ids
[
maf_idx
].
name
,
pr_info
(
"%s %s
\n
"
,
nand_manuf
acturer_name
(
manufacturer
)
,
type
->
name
);
type
->
name
);
pr_info
(
"%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d
\n
"
,
pr_info
(
"%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d
\n
"
,
(
int
)(
chip
->
chipsize
>>
20
),
nand_is_slc
(
chip
)
?
"SLC"
:
"MLC"
,
(
int
)(
chip
->
chipsize
>>
20
),
nand_is_slc
(
chip
)
?
"SLC"
:
"MLC"
,
mtd
->
erasesize
>>
10
,
mtd
->
writesize
,
mtd
->
oobsize
);
mtd
->
erasesize
>>
10
,
mtd
->
writesize
,
mtd
->
oobsize
);
return
type
;
return
0
;
}
}
static
const
char
*
const
nand_ecc_modes
[]
=
{
static
const
char
*
const
nand_ecc_modes
[]
=
{
...
@@ -4181,6 +4061,7 @@ static const char * const nand_ecc_modes[] = {
...
@@ -4181,6 +4061,7 @@ static const char * const nand_ecc_modes[] = {
[
NAND_ECC_HW
]
=
"hw"
,
[
NAND_ECC_HW
]
=
"hw"
,
[
NAND_ECC_HW_SYNDROME
]
=
"hw_syndrome"
,
[
NAND_ECC_HW_SYNDROME
]
=
"hw_syndrome"
,
[
NAND_ECC_HW_OOB_FIRST
]
=
"hw_oob_first"
,
[
NAND_ECC_HW_OOB_FIRST
]
=
"hw_oob_first"
,
[
NAND_ECC_ON_DIE
]
=
"on-die"
,
};
};
static
int
of_get_nand_ecc_mode
(
struct
device_node
*
np
)
static
int
of_get_nand_ecc_mode
(
struct
device_node
*
np
)
...
@@ -4299,12 +4180,6 @@ static int nand_dt_init(struct nand_chip *chip)
...
@@ -4299,12 +4180,6 @@ static int nand_dt_init(struct nand_chip *chip)
ecc_strength
=
of_get_nand_ecc_strength
(
dn
);
ecc_strength
=
of_get_nand_ecc_strength
(
dn
);
ecc_step
=
of_get_nand_ecc_step_size
(
dn
);
ecc_step
=
of_get_nand_ecc_step_size
(
dn
);
if
((
ecc_step
>=
0
&&
!
(
ecc_strength
>=
0
))
||
(
!
(
ecc_step
>=
0
)
&&
ecc_strength
>=
0
))
{
pr_err
(
"must set both strength and step size in DT
\n
"
);
return
-
EINVAL
;
}
if
(
ecc_mode
>=
0
)
if
(
ecc_mode
>=
0
)
chip
->
ecc
.
mode
=
ecc_mode
;
chip
->
ecc
.
mode
=
ecc_mode
;
...
@@ -4338,7 +4213,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
...
@@ -4338,7 +4213,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
{
{
int
i
,
nand_maf_id
,
nand_dev_id
;
int
i
,
nand_maf_id
,
nand_dev_id
;
struct
nand_chip
*
chip
=
mtd_to_nand
(
mtd
);
struct
nand_chip
*
chip
=
mtd_to_nand
(
mtd
);
struct
nand_flash_dev
*
type
;
int
ret
;
int
ret
;
ret
=
nand_dt_init
(
chip
);
ret
=
nand_dt_init
(
chip
);
...
@@ -4358,35 +4232,19 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
...
@@ -4358,35 +4232,19 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
return
-
EINVAL
;
return
-
EINVAL
;
}
}
/* Set the default functions */
/* Set the default functions */
nand_set_defaults
(
chip
,
chip
->
options
&
NAND_BUSWIDTH_16
);
nand_set_defaults
(
chip
);
/* Read the flash type */
/* Read the flash type */
type
=
nand_get_flash_type
(
mtd
,
chip
,
&
nand_maf_id
,
ret
=
nand_detect
(
chip
,
table
);
&
nand_dev_id
,
table
);
if
(
ret
)
{
if
(
IS_ERR
(
type
))
{
if
(
!
(
chip
->
options
&
NAND_SCAN_SILENT_NODEV
))
if
(
!
(
chip
->
options
&
NAND_SCAN_SILENT_NODEV
))
pr_warn
(
"No NAND device found
\n
"
);
pr_warn
(
"No NAND device found
\n
"
);
chip
->
select_chip
(
mtd
,
-
1
);
chip
->
select_chip
(
mtd
,
-
1
);
return
PTR_ERR
(
type
);
}
/* Initialize the ->data_interface field. */
ret
=
nand_init_data_interface
(
chip
);
if
(
ret
)
return
ret
;
return
ret
;
}
/*
nand_maf_id
=
chip
->
id
.
data
[
0
];
* Setup the data interface correctly on the chip and controller side.
nand_dev_id
=
chip
->
id
.
data
[
1
];
* This explicit call to nand_setup_data_interface() is only required
* for the first die, because nand_reset() has been called before
* ->data_interface and ->default_onfi_timing_mode were set.
* For the other dies, nand_reset() will automatically switch to the
* best mode for us.
*/
ret
=
nand_setup_data_interface
(
chip
);
if
(
ret
)
return
ret
;
chip
->
select_chip
(
mtd
,
-
1
);
chip
->
select_chip
(
mtd
,
-
1
);
...
@@ -4513,6 +4371,226 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
...
@@ -4513,6 +4371,226 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
}
}
}
}
/**
* nand_check_ecc_caps - check the sanity of preset ECC settings
* @chip: nand chip info structure
* @caps: ECC caps info structure
* @oobavail: OOB size that the ECC engine can use
*
* When ECC step size and strength are already set, check if they are supported
* by the controller and the calculated ECC bytes fit within the chip's OOB.
* On success, the calculated ECC bytes is set.
*/
int
nand_check_ecc_caps
(
struct
nand_chip
*
chip
,
const
struct
nand_ecc_caps
*
caps
,
int
oobavail
)
{
struct
mtd_info
*
mtd
=
nand_to_mtd
(
chip
);
const
struct
nand_ecc_step_info
*
stepinfo
;
int
preset_step
=
chip
->
ecc
.
size
;
int
preset_strength
=
chip
->
ecc
.
strength
;
int
nsteps
,
ecc_bytes
;
int
i
,
j
;
if
(
WARN_ON
(
oobavail
<
0
))
return
-
EINVAL
;
if
(
!
preset_step
||
!
preset_strength
)
return
-
ENODATA
;
nsteps
=
mtd
->
writesize
/
preset_step
;
for
(
i
=
0
;
i
<
caps
->
nstepinfos
;
i
++
)
{
stepinfo
=
&
caps
->
stepinfos
[
i
];
if
(
stepinfo
->
stepsize
!=
preset_step
)
continue
;
for
(
j
=
0
;
j
<
stepinfo
->
nstrengths
;
j
++
)
{
if
(
stepinfo
->
strengths
[
j
]
!=
preset_strength
)
continue
;
ecc_bytes
=
caps
->
calc_ecc_bytes
(
preset_step
,
preset_strength
);
if
(
WARN_ON_ONCE
(
ecc_bytes
<
0
))
return
ecc_bytes
;
if
(
ecc_bytes
*
nsteps
>
oobavail
)
{
pr_err
(
"ECC (step, strength) = (%d, %d) does not fit in OOB"
,
preset_step
,
preset_strength
);
return
-
ENOSPC
;
}
chip
->
ecc
.
bytes
=
ecc_bytes
;
return
0
;
}
}
pr_err
(
"ECC (step, strength) = (%d, %d) not supported on this controller"
,
preset_step
,
preset_strength
);
return
-
ENOTSUPP
;
}
EXPORT_SYMBOL_GPL
(
nand_check_ecc_caps
);
/**
* nand_match_ecc_req - meet the chip's requirement with least ECC bytes
* @chip: nand chip info structure
* @caps: ECC engine caps info structure
* @oobavail: OOB size that the ECC engine can use
*
* If a chip's ECC requirement is provided, try to meet it with the least
* number of ECC bytes (i.e. with the largest number of OOB-free bytes).
* On success, the chosen ECC settings are set.
*/
int
nand_match_ecc_req
(
struct
nand_chip
*
chip
,
const
struct
nand_ecc_caps
*
caps
,
int
oobavail
)
{
struct
mtd_info
*
mtd
=
nand_to_mtd
(
chip
);
const
struct
nand_ecc_step_info
*
stepinfo
;
int
req_step
=
chip
->
ecc_step_ds
;
int
req_strength
=
chip
->
ecc_strength_ds
;
int
req_corr
,
step_size
,
strength
,
nsteps
,
ecc_bytes
,
ecc_bytes_total
;
int
best_step
,
best_strength
,
best_ecc_bytes
;
int
best_ecc_bytes_total
=
INT_MAX
;
int
i
,
j
;
if
(
WARN_ON
(
oobavail
<
0
))
return
-
EINVAL
;
/* No information provided by the NAND chip */
if
(
!
req_step
||
!
req_strength
)
return
-
ENOTSUPP
;
/* number of correctable bits the chip requires in a page */
req_corr
=
mtd
->
writesize
/
req_step
*
req_strength
;
for
(
i
=
0
;
i
<
caps
->
nstepinfos
;
i
++
)
{
stepinfo
=
&
caps
->
stepinfos
[
i
];
step_size
=
stepinfo
->
stepsize
;
for
(
j
=
0
;
j
<
stepinfo
->
nstrengths
;
j
++
)
{
strength
=
stepinfo
->
strengths
[
j
];
/*
* If both step size and strength are smaller than the
* chip's requirement, it is not easy to compare the
* resulted reliability.
*/
if
(
step_size
<
req_step
&&
strength
<
req_strength
)
continue
;
if
(
mtd
->
writesize
%
step_size
)
continue
;
nsteps
=
mtd
->
writesize
/
step_size
;
ecc_bytes
=
caps
->
calc_ecc_bytes
(
step_size
,
strength
);
if
(
WARN_ON_ONCE
(
ecc_bytes
<
0
))
continue
;
ecc_bytes_total
=
ecc_bytes
*
nsteps
;
if
(
ecc_bytes_total
>
oobavail
||
strength
*
nsteps
<
req_corr
)
continue
;
/*
* We assume the best is to meet the chip's requrement
* with the least number of ECC bytes.
*/
if
(
ecc_bytes_total
<
best_ecc_bytes_total
)
{
best_ecc_bytes_total
=
ecc_bytes_total
;
best_step
=
step_size
;
best_strength
=
strength
;
best_ecc_bytes
=
ecc_bytes
;
}
}
}
if
(
best_ecc_bytes_total
==
INT_MAX
)
return
-
ENOTSUPP
;
chip
->
ecc
.
size
=
best_step
;
chip
->
ecc
.
strength
=
best_strength
;
chip
->
ecc
.
bytes
=
best_ecc_bytes
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
nand_match_ecc_req
);
/**
* nand_maximize_ecc - choose the max ECC strength available
* @chip: nand chip info structure
* @caps: ECC engine caps info structure
* @oobavail: OOB size that the ECC engine can use
*
* Choose the max ECC strength that is supported on the controller, and can fit
* within the chip's OOB. On success, the chosen ECC settings are set.
*/
int
nand_maximize_ecc
(
struct
nand_chip
*
chip
,
const
struct
nand_ecc_caps
*
caps
,
int
oobavail
)
{
struct
mtd_info
*
mtd
=
nand_to_mtd
(
chip
);
const
struct
nand_ecc_step_info
*
stepinfo
;
int
step_size
,
strength
,
nsteps
,
ecc_bytes
,
corr
;
int
best_corr
=
0
;
int
best_step
=
0
;
int
best_strength
,
best_ecc_bytes
;
int
i
,
j
;
if
(
WARN_ON
(
oobavail
<
0
))
return
-
EINVAL
;
for
(
i
=
0
;
i
<
caps
->
nstepinfos
;
i
++
)
{
stepinfo
=
&
caps
->
stepinfos
[
i
];
step_size
=
stepinfo
->
stepsize
;
/* If chip->ecc.size is already set, respect it */
if
(
chip
->
ecc
.
size
&&
step_size
!=
chip
->
ecc
.
size
)
continue
;
for
(
j
=
0
;
j
<
stepinfo
->
nstrengths
;
j
++
)
{
strength
=
stepinfo
->
strengths
[
j
];
if
(
mtd
->
writesize
%
step_size
)
continue
;
nsteps
=
mtd
->
writesize
/
step_size
;
ecc_bytes
=
caps
->
calc_ecc_bytes
(
step_size
,
strength
);
if
(
WARN_ON_ONCE
(
ecc_bytes
<
0
))
continue
;
if
(
ecc_bytes
*
nsteps
>
oobavail
)
continue
;
corr
=
strength
*
nsteps
;
/*
* If the number of correctable bits is the same,
* bigger step_size has more reliability.
*/
if
(
corr
>
best_corr
||
(
corr
==
best_corr
&&
step_size
>
best_step
))
{
best_corr
=
corr
;
best_step
=
step_size
;
best_strength
=
strength
;
best_ecc_bytes
=
ecc_bytes
;
}
}
}
if
(
!
best_corr
)
return
-
ENOTSUPP
;
chip
->
ecc
.
size
=
best_step
;
chip
->
ecc
.
strength
=
best_strength
;
chip
->
ecc
.
bytes
=
best_ecc_bytes
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
nand_maximize_ecc
);
/*
/*
* Check if the chip configuration meet the datasheet requirements.
* Check if the chip configuration meet the datasheet requirements.
...
@@ -4547,6 +4625,26 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
...
@@ -4547,6 +4625,26 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
return
corr
>=
ds_corr
&&
ecc
->
strength
>=
chip
->
ecc_strength_ds
;
return
corr
>=
ds_corr
&&
ecc
->
strength
>=
chip
->
ecc_strength_ds
;
}
}
static
bool
invalid_ecc_page_accessors
(
struct
nand_chip
*
chip
)
{
struct
nand_ecc_ctrl
*
ecc
=
&
chip
->
ecc
;
if
(
nand_standard_page_accessors
(
ecc
))
return
false
;
/*
* NAND_ECC_CUSTOM_PAGE_ACCESS flag is set, make sure the NAND
* controller driver implements all the page accessors because
* default helpers are not suitable when the core does not
* send the READ0/PAGEPROG commands.
*/
return
(
!
ecc
->
read_page
||
!
ecc
->
write_page
||
!
ecc
->
read_page_raw
||
!
ecc
->
write_page_raw
||
(
NAND_HAS_SUBPAGE_READ
(
chip
)
&&
!
ecc
->
read_subpage
)
||
(
NAND_HAS_SUBPAGE_WRITE
(
chip
)
&&
!
ecc
->
write_subpage
&&
ecc
->
hwctl
&&
ecc
->
calculate
));
}
/**
/**
* nand_scan_tail - [NAND Interface] Scan for the NAND device
* nand_scan_tail - [NAND Interface] Scan for the NAND device
* @mtd: MTD device structure
* @mtd: MTD device structure
...
@@ -4559,29 +4657,61 @@ int nand_scan_tail(struct mtd_info *mtd)
...
@@ -4559,29 +4657,61 @@ int nand_scan_tail(struct mtd_info *mtd)
{
{
struct
nand_chip
*
chip
=
mtd_to_nand
(
mtd
);
struct
nand_chip
*
chip
=
mtd_to_nand
(
mtd
);
struct
nand_ecc_ctrl
*
ecc
=
&
chip
->
ecc
;
struct
nand_ecc_ctrl
*
ecc
=
&
chip
->
ecc
;
struct
nand_buffers
*
nbuf
;
struct
nand_buffers
*
nbuf
=
NULL
;
int
ret
;
int
ret
,
i
;
/* New bad blocks should be marked in OOB, flash-based BBT, or both */
/* New bad blocks should be marked in OOB, flash-based BBT, or both */
if
(
WARN_ON
((
chip
->
bbt_options
&
NAND_BBT_NO_OOB_BBM
)
&&
if
(
WARN_ON
((
chip
->
bbt_options
&
NAND_BBT_NO_OOB_BBM
)
&&
!
(
chip
->
bbt_options
&
NAND_BBT_USE_FLASH
)))
!
(
chip
->
bbt_options
&
NAND_BBT_USE_FLASH
)))
{
return
-
EINVAL
;
}
if
(
invalid_ecc_page_accessors
(
chip
))
{
pr_err
(
"Invalid ECC page accessors setup
\n
"
);
return
-
EINVAL
;
return
-
EINVAL
;
}
if
(
!
(
chip
->
options
&
NAND_OWN_BUFFERS
))
{
if
(
!
(
chip
->
options
&
NAND_OWN_BUFFERS
))
{
nbuf
=
kzalloc
(
sizeof
(
*
nbuf
)
+
mtd
->
writesize
nbuf
=
kzalloc
(
sizeof
(
*
nbuf
),
GFP_KERNEL
);
+
mtd
->
oobsize
*
3
,
GFP_KERNEL
);
if
(
!
nbuf
)
if
(
!
nbuf
)
return
-
ENOMEM
;
return
-
ENOMEM
;
nbuf
->
ecccalc
=
(
uint8_t
*
)(
nbuf
+
1
);
nbuf
->
ecccode
=
nbuf
->
ecccalc
+
mtd
->
oobsize
;
nbuf
->
ecccalc
=
kmalloc
(
mtd
->
oobsize
,
GFP_KERNEL
);
nbuf
->
databuf
=
nbuf
->
ecccode
+
mtd
->
oobsize
;
if
(
!
nbuf
->
ecccalc
)
{
ret
=
-
ENOMEM
;
goto
err_free_nbuf
;
}
nbuf
->
ecccode
=
kmalloc
(
mtd
->
oobsize
,
GFP_KERNEL
);
if
(
!
nbuf
->
ecccode
)
{
ret
=
-
ENOMEM
;
goto
err_free_nbuf
;
}
nbuf
->
databuf
=
kmalloc
(
mtd
->
writesize
+
mtd
->
oobsize
,
GFP_KERNEL
);
if
(
!
nbuf
->
databuf
)
{
ret
=
-
ENOMEM
;
goto
err_free_nbuf
;
}
chip
->
buffers
=
nbuf
;
chip
->
buffers
=
nbuf
;
}
else
{
}
else
if
(
!
chip
->
buffers
)
{
if
(
!
chip
->
buffers
)
return
-
ENOMEM
;
return
-
ENOMEM
;
}
}
/*
* FIXME: some NAND manufacturer drivers expect the first die to be
* selected when manufacturer->init() is called. They should be fixed
* to explictly select the relevant die when interacting with the NAND
* chip.
*/
chip
->
select_chip
(
mtd
,
0
);
ret
=
nand_manufacturer_init
(
chip
);
chip
->
select_chip
(
mtd
,
-
1
);
if
(
ret
)
goto
err_free_nbuf
;
/* Set the internal oob buffer location, just after the page data */
/* Set the internal oob buffer location, just after the page data */
chip
->
oob_poi
=
chip
->
buffers
->
databuf
+
mtd
->
writesize
;
chip
->
oob_poi
=
chip
->
buffers
->
databuf
+
mtd
->
writesize
;
...
@@ -4597,19 +4727,16 @@ int nand_scan_tail(struct mtd_info *mtd)
...
@@ -4597,19 +4727,16 @@ int nand_scan_tail(struct mtd_info *mtd)
break
;
break
;
case
64
:
case
64
:
case
128
:
case
128
:
mtd_set_ooblayout
(
mtd
,
&
nand_ooblayout_lp_ops
);
mtd_set_ooblayout
(
mtd
,
&
nand_ooblayout_lp_
hamming_
ops
);
break
;
break
;
default:
default:
WARN
(
1
,
"No oob scheme defined for oobsize %d
\n
"
,
WARN
(
1
,
"No oob scheme defined for oobsize %d
\n
"
,
mtd
->
oobsize
);
mtd
->
oobsize
);
ret
=
-
EINVAL
;
ret
=
-
EINVAL
;
goto
err_
free
;
goto
err_
nand_manuf_cleanup
;
}
}
}
}
if
(
!
chip
->
write_page
)
chip
->
write_page
=
nand_write_page
;
/*
/*
* Check ECC mode, default to software if 3byte/512byte hardware ECC is
* Check ECC mode, default to software if 3byte/512byte hardware ECC is
* selected and we have 256 byte pagesize fallback to software ECC
* selected and we have 256 byte pagesize fallback to software ECC
...
@@ -4621,7 +4748,7 @@ int nand_scan_tail(struct mtd_info *mtd)
...
@@ -4621,7 +4748,7 @@ int nand_scan_tail(struct mtd_info *mtd)
if
(
!
ecc
->
calculate
||
!
ecc
->
correct
||
!
ecc
->
hwctl
)
{
if
(
!
ecc
->
calculate
||
!
ecc
->
correct
||
!
ecc
->
hwctl
)
{
WARN
(
1
,
"No ECC functions supplied; hardware ECC not possible
\n
"
);
WARN
(
1
,
"No ECC functions supplied; hardware ECC not possible
\n
"
);
ret
=
-
EINVAL
;
ret
=
-
EINVAL
;
goto
err_
free
;
goto
err_
nand_manuf_cleanup
;
}
}
if
(
!
ecc
->
read_page
)
if
(
!
ecc
->
read_page
)
ecc
->
read_page
=
nand_read_page_hwecc_oob_first
;
ecc
->
read_page
=
nand_read_page_hwecc_oob_first
;
...
@@ -4653,7 +4780,7 @@ int nand_scan_tail(struct mtd_info *mtd)
...
@@ -4653,7 +4780,7 @@ int nand_scan_tail(struct mtd_info *mtd)
ecc
->
write_page
==
nand_write_page_hwecc
))
{
ecc
->
write_page
==
nand_write_page_hwecc
))
{
WARN
(
1
,
"No ECC functions supplied; hardware ECC not possible
\n
"
);
WARN
(
1
,
"No ECC functions supplied; hardware ECC not possible
\n
"
);
ret
=
-
EINVAL
;
ret
=
-
EINVAL
;
goto
err_
free
;
goto
err_
nand_manuf_cleanup
;
}
}
/* Use standard syndrome read/write page function? */
/* Use standard syndrome read/write page function? */
if
(
!
ecc
->
read_page
)
if
(
!
ecc
->
read_page
)
...
@@ -4673,7 +4800,7 @@ int nand_scan_tail(struct mtd_info *mtd)
...
@@ -4673,7 +4800,7 @@ int nand_scan_tail(struct mtd_info *mtd)
if
(
!
ecc
->
strength
)
{
if
(
!
ecc
->
strength
)
{
WARN
(
1
,
"Driver must set ecc.strength when using hardware ECC
\n
"
);
WARN
(
1
,
"Driver must set ecc.strength when using hardware ECC
\n
"
);
ret
=
-
EINVAL
;
ret
=
-
EINVAL
;
goto
err_
free
;
goto
err_
nand_manuf_cleanup
;
}
}
break
;
break
;
}
}
...
@@ -4686,10 +4813,22 @@ int nand_scan_tail(struct mtd_info *mtd)
...
@@ -4686,10 +4813,22 @@ int nand_scan_tail(struct mtd_info *mtd)
ret
=
nand_set_ecc_soft_ops
(
mtd
);
ret
=
nand_set_ecc_soft_ops
(
mtd
);
if
(
ret
)
{
if
(
ret
)
{
ret
=
-
EINVAL
;
ret
=
-
EINVAL
;
goto
err_
free
;
goto
err_
nand_manuf_cleanup
;
}
}
break
;
break
;
case
NAND_ECC_ON_DIE
:
if
(
!
ecc
->
read_page
||
!
ecc
->
write_page
)
{
WARN
(
1
,
"No ECC functions supplied; on-die ECC not possible
\n
"
);
ret
=
-
EINVAL
;
goto
err_nand_manuf_cleanup
;
}
if
(
!
ecc
->
read_oob
)
ecc
->
read_oob
=
nand_read_oob_std
;
if
(
!
ecc
->
write_oob
)
ecc
->
write_oob
=
nand_write_oob_std
;
break
;
case
NAND_ECC_NONE
:
case
NAND_ECC_NONE
:
pr_warn
(
"NAND_ECC_NONE selected by board driver. This is not recommended!
\n
"
);
pr_warn
(
"NAND_ECC_NONE selected by board driver. This is not recommended!
\n
"
);
ecc
->
read_page
=
nand_read_page_raw
;
ecc
->
read_page
=
nand_read_page_raw
;
...
@@ -4706,7 +4845,7 @@ int nand_scan_tail(struct mtd_info *mtd)
...
@@ -4706,7 +4845,7 @@ int nand_scan_tail(struct mtd_info *mtd)
default:
default:
WARN
(
1
,
"Invalid NAND_ECC_MODE %d
\n
"
,
ecc
->
mode
);
WARN
(
1
,
"Invalid NAND_ECC_MODE %d
\n
"
,
ecc
->
mode
);
ret
=
-
EINVAL
;
ret
=
-
EINVAL
;
goto
err_
free
;
goto
err_
nand_manuf_cleanup
;
}
}
/* For many systems, the standard OOB write also works for raw */
/* For many systems, the standard OOB write also works for raw */
...
@@ -4727,9 +4866,14 @@ int nand_scan_tail(struct mtd_info *mtd)
...
@@ -4727,9 +4866,14 @@ int nand_scan_tail(struct mtd_info *mtd)
if
(
ecc
->
steps
*
ecc
->
size
!=
mtd
->
writesize
)
{
if
(
ecc
->
steps
*
ecc
->
size
!=
mtd
->
writesize
)
{
WARN
(
1
,
"Invalid ECC parameters
\n
"
);
WARN
(
1
,
"Invalid ECC parameters
\n
"
);
ret
=
-
EINVAL
;
ret
=
-
EINVAL
;
goto
err_
free
;
goto
err_
nand_manuf_cleanup
;
}
}
ecc
->
total
=
ecc
->
steps
*
ecc
->
bytes
;
ecc
->
total
=
ecc
->
steps
*
ecc
->
bytes
;
if
(
ecc
->
total
>
mtd
->
oobsize
)
{
WARN
(
1
,
"Total number of ECC bytes exceeded oobsize
\n
"
);
ret
=
-
EINVAL
;
goto
err_nand_manuf_cleanup
;
}
/*
/*
* The number of bytes available for a client to place data into
* The number of bytes available for a client to place data into
...
@@ -4799,6 +4943,7 @@ int nand_scan_tail(struct mtd_info *mtd)
...
@@ -4799,6 +4943,7 @@ int nand_scan_tail(struct mtd_info *mtd)
mtd
->
_block_isreserved
=
nand_block_isreserved
;
mtd
->
_block_isreserved
=
nand_block_isreserved
;
mtd
->
_block_isbad
=
nand_block_isbad
;
mtd
->
_block_isbad
=
nand_block_isbad
;
mtd
->
_block_markbad
=
nand_block_markbad
;
mtd
->
_block_markbad
=
nand_block_markbad
;
mtd
->
_max_bad_blocks
=
nand_max_bad_blocks
;
mtd
->
writebufsize
=
mtd
->
writesize
;
mtd
->
writebufsize
=
mtd
->
writesize
;
/*
/*
...
@@ -4809,15 +4954,46 @@ int nand_scan_tail(struct mtd_info *mtd)
...
@@ -4809,15 +4954,46 @@ int nand_scan_tail(struct mtd_info *mtd)
if
(
!
mtd
->
bitflip_threshold
)
if
(
!
mtd
->
bitflip_threshold
)
mtd
->
bitflip_threshold
=
DIV_ROUND_UP
(
mtd
->
ecc_strength
*
3
,
4
);
mtd
->
bitflip_threshold
=
DIV_ROUND_UP
(
mtd
->
ecc_strength
*
3
,
4
);
/* Initialize the ->data_interface field. */
ret
=
nand_init_data_interface
(
chip
);
if
(
ret
)
goto
err_nand_manuf_cleanup
;
/* Enter fastest possible mode on all dies. */
for
(
i
=
0
;
i
<
chip
->
numchips
;
i
++
)
{
chip
->
select_chip
(
mtd
,
i
);
ret
=
nand_setup_data_interface
(
chip
,
i
);
chip
->
select_chip
(
mtd
,
-
1
);
if
(
ret
)
goto
err_nand_data_iface_cleanup
;
}
/* Check, if we should skip the bad block table scan */
/* Check, if we should skip the bad block table scan */
if
(
chip
->
options
&
NAND_SKIP_BBTSCAN
)
if
(
chip
->
options
&
NAND_SKIP_BBTSCAN
)
return
0
;
return
0
;
/* Build bad block table */
/* Build bad block table */
return
chip
->
scan_bbt
(
mtd
);
ret
=
chip
->
scan_bbt
(
mtd
);
err_free:
if
(
ret
)
if
(
!
(
chip
->
options
&
NAND_OWN_BUFFERS
))
goto
err_nand_data_iface_cleanup
;
kfree
(
chip
->
buffers
);
return
0
;
err_nand_data_iface_cleanup:
nand_release_data_interface
(
chip
);
err_nand_manuf_cleanup:
nand_manufacturer_cleanup
(
chip
);
err_free_nbuf:
if
(
nbuf
)
{
kfree
(
nbuf
->
databuf
);
kfree
(
nbuf
->
ecccode
);
kfree
(
nbuf
->
ecccalc
);
kfree
(
nbuf
);
}
return
ret
;
return
ret
;
}
}
EXPORT_SYMBOL
(
nand_scan_tail
);
EXPORT_SYMBOL
(
nand_scan_tail
);
...
@@ -4868,13 +5044,20 @@ void nand_cleanup(struct nand_chip *chip)
...
@@ -4868,13 +5044,20 @@ void nand_cleanup(struct nand_chip *chip)
/* Free bad block table memory */
/* Free bad block table memory */
kfree
(
chip
->
bbt
);
kfree
(
chip
->
bbt
);
if
(
!
(
chip
->
options
&
NAND_OWN_BUFFERS
))
if
(
!
(
chip
->
options
&
NAND_OWN_BUFFERS
)
&&
chip
->
buffers
)
{
kfree
(
chip
->
buffers
->
databuf
);
kfree
(
chip
->
buffers
->
ecccode
);
kfree
(
chip
->
buffers
->
ecccalc
);
kfree
(
chip
->
buffers
);
kfree
(
chip
->
buffers
);
}
/* Free bad block descriptor memory */
/* Free bad block descriptor memory */
if
(
chip
->
badblock_pattern
&&
chip
->
badblock_pattern
->
options
if
(
chip
->
badblock_pattern
&&
chip
->
badblock_pattern
->
options
&
NAND_BBT_DYNAMICSTRUCT
)
&
NAND_BBT_DYNAMICSTRUCT
)
kfree
(
chip
->
badblock_pattern
);
kfree
(
chip
->
badblock_pattern
);
/* Free manufacturer priv data. */
nand_manufacturer_cleanup
(
chip
);
}
}
EXPORT_SYMBOL_GPL
(
nand_cleanup
);
EXPORT_SYMBOL_GPL
(
nand_cleanup
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment