Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
8fa7a41f
Commit
8fa7a41f
authored
Jan 11, 2007
by
David Woodhouse
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
git://git.infradead.org/~kmpark/onenand-mtd-2.6
parents
abb536e7
0fc2ccea
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
124 additions
and
74 deletions
+124
-74
drivers/mtd/onenand/onenand_base.c
drivers/mtd/onenand/onenand_base.c
+119
-73
drivers/mtd/onenand/onenand_bbt.c
drivers/mtd/onenand/onenand_bbt.c
+2
-1
include/linux/mtd/onenand.h
include/linux/mtd/onenand.h
+3
-0
No files found.
drivers/mtd/onenand/onenand_base.c
View file @
8fa7a41f
...
...
@@ -192,8 +192,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
struct
onenand_chip
*
this
=
mtd
->
priv
;
int
value
,
readcmd
=
0
,
block_cmd
=
0
;
int
block
,
page
;
/* Now we use page size operation */
int
sectors
=
4
,
count
=
4
;
/* Address translation */
switch
(
cmd
)
{
...
...
@@ -245,6 +243,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
}
if
(
page
!=
-
1
)
{
/* Now we use page size operation */
int
sectors
=
4
,
count
=
4
;
int
dataram
;
switch
(
cmd
)
{
...
...
@@ -298,7 +298,7 @@ static int onenand_wait(struct mtd_info *mtd, int state)
unsigned
long
timeout
;
unsigned
int
flags
=
ONENAND_INT_MASTER
;
unsigned
int
interrupt
=
0
;
unsigned
int
ctrl
,
ecc
;
unsigned
int
ctrl
;
/* The 20 msec is enough */
timeout
=
jiffies
+
msecs_to_jiffies
(
20
);
...
...
@@ -310,7 +310,6 @@ static int onenand_wait(struct mtd_info *mtd, int state)
if
(
state
!=
FL_READING
)
cond_resched
();
touch_softlockup_watchdog
();
}
/* To get correct interrupt status in timeout case */
interrupt
=
this
->
read_word
(
this
->
base
+
ONENAND_REG_INTERRUPT
);
...
...
@@ -318,24 +317,20 @@ static int onenand_wait(struct mtd_info *mtd, int state)
ctrl
=
this
->
read_word
(
this
->
base
+
ONENAND_REG_CTRL_STATUS
);
if
(
ctrl
&
ONENAND_CTRL_ERROR
)
{
/* It maybe occur at initial bad block */
DEBUG
(
MTD_DEBUG_LEVEL0
,
"onenand_wait: controller error = 0x%04x
\n
"
,
ctrl
);
/* Clear other interrupt bits for preventing ECC error */
interrupt
&=
ONENAND_INT_MASTER
;
}
if
(
ctrl
&
ONENAND_CTRL_LOCK
)
{
DEBUG
(
MTD_DEBUG_LEVEL0
,
"onenand_wait: it's locked error = 0x%04x
\n
"
,
ctrl
);
return
-
EACCES
;
if
(
ctrl
&
ONENAND_CTRL_LOCK
)
DEBUG
(
MTD_DEBUG_LEVEL0
,
"onenand_wait: it's locked error.
\n
"
);
return
ctrl
;
}
if
(
interrupt
&
ONENAND_INT_READ
)
{
ecc
=
this
->
read_word
(
this
->
base
+
ONENAND_REG_ECC_STATUS
);
int
ecc
=
this
->
read_word
(
this
->
base
+
ONENAND_REG_ECC_STATUS
);
if
(
ecc
)
{
DEBUG
(
MTD_DEBUG_LEVEL0
,
"onenand_wait: ECC error = 0x%04x
\n
"
,
ecc
);
if
(
ecc
&
ONENAND_ECC_2BIT_ALL
)
if
(
ecc
&
ONENAND_ECC_2BIT_ALL
)
{
mtd
->
ecc_stats
.
failed
++
;
else
if
(
ecc
&
ONENAND_ECC_1BIT_ALL
)
return
ecc
;
}
else
if
(
ecc
&
ONENAND_ECC_1BIT_ALL
)
mtd
->
ecc_stats
.
corrected
++
;
}
}
...
...
@@ -372,9 +367,6 @@ static int onenand_interrupt_wait(struct mtd_info *mtd, int state)
{
struct
onenand_chip
*
this
=
mtd
->
priv
;
/* To prevent soft lockup */
touch_softlockup_watchdog
();
wait_for_completion
(
&
this
->
complete
);
return
onenand_wait
(
mtd
,
state
);
...
...
@@ -395,9 +387,6 @@ static int onenand_try_interrupt_wait(struct mtd_info *mtd, int state)
/* We use interrupt wait first */
this
->
wait
=
onenand_interrupt_wait
;
/* To prevent soft lockup */
touch_softlockup_watchdog
();
timeout
=
msecs_to_jiffies
(
100
);
remain
=
wait_for_completion_timeout
(
&
this
->
complete
,
timeout
);
if
(
!
remain
)
{
...
...
@@ -721,7 +710,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
struct
mtd_ecc_stats
stats
;
int
read
=
0
,
column
;
int
thislen
;
int
ret
=
0
;
int
ret
=
0
,
boundary
=
0
;
DEBUG
(
MTD_DEBUG_LEVEL3
,
"onenand_read: from = 0x%08x, len = %i
\n
"
,
(
unsigned
int
)
from
,
(
int
)
len
);
...
...
@@ -738,38 +727,60 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
/* TODO handling oob */
stats
=
mtd
->
ecc_stats
;
while
(
read
<
len
)
{
thislen
=
min_t
(
int
,
mtd
->
writesize
,
len
-
read
);
column
=
from
&
(
mtd
->
writesize
-
1
);
if
(
column
+
thislen
>
mtd
->
writesize
)
thislen
=
mtd
->
writesize
-
column
;
if
(
!
onenand_check_bufferram
(
mtd
,
from
))
{
this
->
command
(
mtd
,
ONENAND_CMD_READ
,
from
,
mtd
->
writesize
);
ret
=
this
->
wait
(
mtd
,
FL_READING
);
/* First copy data and check return value for ECC handling */
onenand_update_bufferram
(
mtd
,
from
,
1
);
}
this
->
read_bufferram
(
mtd
,
ONENAND_DATARAM
,
buf
,
column
,
thislen
);
read
+=
thislen
;
if
(
read
==
len
)
break
;
/* Read-while-load method */
/* Do first load to bufferRAM */
if
(
read
<
len
)
{
if
(
!
onenand_check_bufferram
(
mtd
,
from
))
{
this
->
command
(
mtd
,
ONENAND_CMD_READ
,
from
,
mtd
->
writesize
);
ret
=
this
->
wait
(
mtd
,
FL_READING
);
onenand_update_bufferram
(
mtd
,
from
,
!
ret
);
}
}
thislen
=
min_t
(
int
,
mtd
->
writesize
,
len
-
read
);
column
=
from
&
(
mtd
->
writesize
-
1
);
if
(
column
+
thislen
>
mtd
->
writesize
)
thislen
=
mtd
->
writesize
-
column
;
while
(
!
ret
)
{
/* If there is more to load then start next load */
from
+=
thislen
;
if
(
read
+
thislen
<
len
)
{
this
->
command
(
mtd
,
ONENAND_CMD_READ
,
from
,
mtd
->
writesize
);
/*
* Chip boundary handling in DDP
* Now we issued chip 1 read and pointed chip 1
* bufferam so we have to point chip 0 bufferam.
*/
if
(
this
->
device_id
&
ONENAND_DEVICE_IS_DDP
&&
unlikely
(
from
==
(
this
->
chipsize
>>
1
)))
{
this
->
write_word
(
0
,
this
->
base
+
ONENAND_REG_START_ADDRESS2
);
boundary
=
1
;
}
else
boundary
=
0
;
ONENAND_SET_PREV_BUFFERRAM
(
this
);
}
/* While load is going, read from last bufferRAM */
this
->
read_bufferram
(
mtd
,
ONENAND_DATARAM
,
buf
,
column
,
thislen
);
/* See if we are done */
read
+=
thislen
;
if
(
read
==
len
)
break
;
/* Set up for next read from bufferRAM */
if
(
unlikely
(
boundary
))
this
->
write_word
(
0x8000
,
this
->
base
+
ONENAND_REG_START_ADDRESS2
);
ONENAND_SET_NEXT_BUFFERRAM
(
this
);
buf
+=
thislen
;
thislen
=
min_t
(
int
,
mtd
->
writesize
,
len
-
read
);
column
=
0
;
cond_resched
();
/* Now wait for load */
ret
=
this
->
wait
(
mtd
,
FL_READING
);
onenand_update_bufferram
(
mtd
,
from
,
!
ret
);
}
if
(
ret
)
{
DEBUG
(
MTD_DEBUG_LEVEL0
,
"onenand_read: read failed = %d
\n
"
,
ret
);
goto
out
;
}
from
+=
thislen
;
buf
+=
thislen
;
}
out:
/* Deselect and wake up anyone waiting on the device */
onenand_release_device
(
mtd
);
...
...
@@ -783,6 +794,9 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
if
(
mtd
->
ecc_stats
.
failed
-
stats
.
failed
)
return
-
EBADMSG
;
if
(
ret
)
return
ret
;
return
mtd
->
ecc_stats
.
corrected
-
stats
.
corrected
?
-
EUCLEAN
:
0
;
}
...
...
@@ -820,6 +834,8 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
column
=
from
&
(
mtd
->
oobsize
-
1
);
while
(
read
<
len
)
{
cond_resched
();
thislen
=
mtd
->
oobsize
-
column
;
thislen
=
min_t
(
int
,
thislen
,
len
);
...
...
@@ -832,16 +848,16 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
this
->
read_bufferram
(
mtd
,
ONENAND_SPARERAM
,
buf
,
column
,
thislen
);
if
(
ret
)
{
DEBUG
(
MTD_DEBUG_LEVEL0
,
"onenand_read_oob: read failed = 0x%x
\n
"
,
ret
);
goto
out
;
}
read
+=
thislen
;
if
(
read
==
len
)
break
;
if
(
ret
)
{
DEBUG
(
MTD_DEBUG_LEVEL0
,
"onenand_read_oob: read failed = %d
\n
"
,
ret
);
goto
out
;
}
buf
+=
thislen
;
/* Read more? */
...
...
@@ -919,6 +935,10 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr)
void
__iomem
*
dataram0
,
*
dataram1
;
int
ret
=
0
;
/* In partial page write, just skip it */
if
((
addr
&
(
mtd
->
writesize
-
1
))
!=
0
)
return
0
;
this
->
command
(
mtd
,
ONENAND_CMD_READ
,
addr
,
mtd
->
writesize
);
ret
=
this
->
wait
(
mtd
,
FL_READING
);
...
...
@@ -941,7 +961,7 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr)
#define onenand_verify_oob(...) (0)
#endif
#define NOTALIGNED(x) ((x & (
mtd->writ
esize - 1)) != 0)
#define NOTALIGNED(x) ((x & (
this->subpag
esize - 1)) != 0)
/**
* onenand_write - [MTD Interface] write buffer to FLASH
...
...
@@ -959,6 +979,7 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
struct
onenand_chip
*
this
=
mtd
->
priv
;
int
written
=
0
;
int
ret
=
0
;
int
column
,
subpage
;
DEBUG
(
MTD_DEBUG_LEVEL3
,
"onenand_write: to = 0x%08x, len = %i
\n
"
,
(
unsigned
int
)
to
,
(
int
)
len
);
...
...
@@ -977,45 +998,63 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
return
-
EINVAL
;
}
column
=
to
&
(
mtd
->
writesize
-
1
);
subpage
=
column
||
(
len
&
(
mtd
->
writesize
-
1
));
/* Grab the lock and see if the device is available */
onenand_get_device
(
mtd
,
FL_WRITING
);
/* Loop until all data write */
while
(
written
<
len
)
{
int
thislen
=
min_t
(
int
,
mtd
->
writesize
,
len
-
written
);
this
->
command
(
mtd
,
ONENAND_CMD_BUFFERRAM
,
to
,
mtd
->
writesize
);
int
bytes
=
mtd
->
writesize
;
int
thislen
=
min_t
(
int
,
bytes
,
len
-
written
);
u_char
*
wbuf
=
(
u_char
*
)
buf
;
cond_resched
();
this
->
command
(
mtd
,
ONENAND_CMD_BUFFERRAM
,
to
,
bytes
);
/* Partial page write */
if
(
subpage
)
{
bytes
=
min_t
(
int
,
bytes
-
column
,
(
int
)
len
);
memset
(
this
->
page_buf
,
0xff
,
mtd
->
writesize
);
memcpy
(
this
->
page_buf
+
column
,
buf
,
bytes
);
wbuf
=
this
->
page_buf
;
/* Even though partial write, we need page size */
thislen
=
mtd
->
writesize
;
}
this
->
write_bufferram
(
mtd
,
ONENAND_DATARAM
,
buf
,
0
,
thislen
);
this
->
write_bufferram
(
mtd
,
ONENAND_DATARAM
,
w
buf
,
0
,
thislen
);
this
->
write_bufferram
(
mtd
,
ONENAND_SPARERAM
,
ffchars
,
0
,
mtd
->
oobsize
);
this
->
command
(
mtd
,
ONENAND_CMD_PROG
,
to
,
mtd
->
writesize
);
onenand_update_bufferram
(
mtd
,
to
,
1
);
/* In partial page write we don't update bufferram */
onenand_update_bufferram
(
mtd
,
to
,
!
subpage
);
ret
=
this
->
wait
(
mtd
,
FL_WRITING
);
if
(
ret
)
{
DEBUG
(
MTD_DEBUG_LEVEL0
,
"onenand_write: write filaed %d
\n
"
,
ret
);
goto
out
;
break
;
}
written
+=
thislen
;
/* Only check verify write turn on */
ret
=
onenand_verify_page
(
mtd
,
(
u_char
*
)
buf
,
to
);
ret
=
onenand_verify_page
(
mtd
,
(
u_char
*
)
w
buf
,
to
);
if
(
ret
)
{
DEBUG
(
MTD_DEBUG_LEVEL0
,
"onenand_write: verify failed %d
\n
"
,
ret
);
goto
out
;
break
;
}
written
+=
thislen
;
if
(
written
==
len
)
break
;
column
=
0
;
to
+=
thislen
;
buf
+=
thislen
;
}
out:
/* Deselect and wake up anyone waiting on the device */
onenand_release_device
(
mtd
);
...
...
@@ -1059,6 +1098,8 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
while
(
written
<
len
)
{
int
thislen
=
min_t
(
int
,
mtd
->
oobsize
,
len
-
written
);
cond_resched
();
column
=
to
&
(
mtd
->
oobsize
-
1
);
this
->
command
(
mtd
,
ONENAND_CMD_BUFFERRAM
,
to
,
mtd
->
oobsize
);
...
...
@@ -1186,6 +1227,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
instr
->
state
=
MTD_ERASING
;
while
(
len
)
{
cond_resched
();
/* Check if we have a bad block, we do not erase bad blocks */
if
(
onenand_block_checkbad
(
mtd
,
addr
,
0
,
0
))
{
...
...
@@ -1199,10 +1241,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
ret
=
this
->
wait
(
mtd
,
FL_ERASING
);
/* Check, if it is write protected */
if
(
ret
)
{
if
(
ret
==
-
EPERM
)
DEBUG
(
MTD_DEBUG_LEVEL0
,
"onenand_erase: Device is write protected!!!
\n
"
);
else
DEBUG
(
MTD_DEBUG_LEVEL0
,
"onenand_erase: Failed erase, block %d
\n
"
,
(
unsigned
)
(
addr
>>
this
->
erase_shift
));
DEBUG
(
MTD_DEBUG_LEVEL0
,
"onenand_erase: Failed erase, block %d
\n
"
,
(
unsigned
)
(
addr
>>
this
->
erase_shift
));
instr
->
state
=
MTD_ERASE_FAILED
;
instr
->
fail_addr
=
addr
;
goto
erase_exit
;
...
...
@@ -2029,23 +2068,30 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
init_waitqueue_head
(
&
this
->
wq
);
spin_lock_init
(
&
this
->
chip_lock
);
/*
* Allow subpage writes up to oobsize.
*/
switch
(
mtd
->
oobsize
)
{
case
64
:
this
->
ecclayout
=
&
onenand_oob_64
;
mtd
->
subpage_sft
=
2
;
break
;
case
32
:
this
->
ecclayout
=
&
onenand_oob_32
;
mtd
->
subpage_sft
=
1
;
break
;
default:
printk
(
KERN_WARNING
"No OOB scheme defined for oobsize %d
\n
"
,
mtd
->
oobsize
);
mtd
->
subpage_sft
=
0
;
/* To prevent kernel oops */
this
->
ecclayout
=
&
onenand_oob_32
;
break
;
}
this
->
subpagesize
=
mtd
->
writesize
>>
mtd
->
subpage_sft
;
mtd
->
ecclayout
=
this
->
ecclayout
;
/* Fill in remaining MTD driver data */
...
...
drivers/mtd/onenand/onenand_bbt.c
View file @
8fa7a41f
...
...
@@ -93,7 +93,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
ret
=
onenand_do_read_oob
(
mtd
,
from
+
j
*
mtd
->
writesize
+
bd
->
offs
,
readlen
,
&
retlen
,
&
buf
[
0
]);
if
(
ret
)
/* If it is a initial bad block, just ignore it */
if
(
ret
&&
!
(
ret
&
ONENAND_CTRL_LOAD
))
return
ret
;
if
(
check_short_pattern
(
&
buf
[
j
*
scanlen
],
scanlen
,
mtd
->
writesize
,
bd
))
{
...
...
include/linux/mtd/onenand.h
View file @
8fa7a41f
...
...
@@ -88,6 +88,7 @@ struct onenand_bufferram {
* operation is in progress
* @state: [INTERN] the current state of the OneNAND device
* @page_buf: data buffer
* @subpagesize: [INTERN] holds the subpagesize
* @ecclayout: [REPLACEABLE] the default ecc placement scheme
* @bbm: [REPLACEABLE] pointer to Bad Block Management
* @priv: [OPTIONAL] pointer to private chip date
...
...
@@ -128,6 +129,7 @@ struct onenand_chip {
onenand_state_t
state
;
unsigned
char
*
page_buf
;
int
subpagesize
;
struct
nand_ecclayout
*
ecclayout
;
void
*
bbm
;
...
...
@@ -141,6 +143,7 @@ struct onenand_chip {
#define ONENAND_CURRENT_BUFFERRAM(this) (this->bufferram_index)
#define ONENAND_NEXT_BUFFERRAM(this) (this->bufferram_index ^ 1)
#define ONENAND_SET_NEXT_BUFFERRAM(this) (this->bufferram_index ^= 1)
#define ONENAND_SET_PREV_BUFFERRAM(this) (this->bufferram_index ^= 1)
#define ONENAND_GET_SYS_CFG1(this) \
(this->read_word(this->base + ONENAND_REG_SYS_CFG1))
...
...
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