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
Kirill Smelkov
linux
Commits
103e40f6
Commit
103e40f6
authored
Nov 29, 2006
by
David Woodhouse
Browse files
Options
Browse Files
Download
Plain Diff
Merge
git://git.infradead.org/~kmpark/onenand-mtd-2.6
parents
95b93a0c
f4f91ac3
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
174 additions
and
22 deletions
+174
-22
drivers/mtd/onenand/generic.c
drivers/mtd/onenand/generic.c
+1
-0
drivers/mtd/onenand/onenand_base.c
drivers/mtd/onenand/onenand_base.c
+167
-21
drivers/mtd/onenand/onenand_bbt.c
drivers/mtd/onenand/onenand_bbt.c
+1
-0
include/linux/mtd/onenand.h
include/linux/mtd/onenand.h
+4
-1
include/linux/mtd/onenand_regs.h
include/linux/mtd/onenand_regs.h
+1
-0
No files found.
drivers/mtd/onenand/generic.c
View file @
103e40f6
...
...
@@ -61,6 +61,7 @@ static int __devinit generic_onenand_probe(struct device *dev)
}
info
->
onenand
.
mmcontrol
=
pdata
->
mmcontrol
;
info
->
onenand
.
irq
=
platform_get_irq
(
pdev
,
0
);
info
->
mtd
.
name
=
pdev
->
dev
.
bus_id
;
info
->
mtd
.
priv
=
&
info
->
onenand
;
...
...
drivers/mtd/onenand/onenand_base.c
View file @
103e40f6
...
...
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/onenand.h>
...
...
@@ -330,15 +331,123 @@ static int onenand_wait(struct mtd_info *mtd, int state)
if
(
interrupt
&
ONENAND_INT_READ
)
{
ecc
=
this
->
read_word
(
this
->
base
+
ONENAND_REG_ECC_STATUS
);
if
(
ecc
&
ONENAND_ECC_2BIT_ALL
)
{
if
(
ecc
)
{
DEBUG
(
MTD_DEBUG_LEVEL0
,
"onenand_wait: ECC error = 0x%04x
\n
"
,
ecc
);
return
-
EBADMSG
;
if
(
ecc
&
ONENAND_ECC_2BIT_ALL
)
mtd
->
ecc_stats
.
failed
++
;
else
if
(
ecc
&
ONENAND_ECC_1BIT_ALL
)
mtd
->
ecc_stats
.
corrected
++
;
}
}
return
0
;
}
/*
* onenand_interrupt - [DEFAULT] onenand interrupt handler
* @param irq onenand interrupt number
* @param dev_id interrupt data
*
* complete the work
*/
static
irqreturn_t
onenand_interrupt
(
int
irq
,
void
*
data
)
{
struct
onenand_chip
*
this
=
(
struct
onenand_chip
*
)
data
;
/* To handle shared interrupt */
if
(
!
this
->
complete
.
done
)
complete
(
&
this
->
complete
);
return
IRQ_HANDLED
;
}
/*
* onenand_interrupt_wait - [DEFAULT] wait until the command is done
* @param mtd MTD device structure
* @param state state to select the max. timeout value
*
* Wait for command done.
*/
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
);
}
/*
* onenand_try_interrupt_wait - [DEFAULT] try interrupt wait
* @param mtd MTD device structure
* @param state state to select the max. timeout value
*
* Try interrupt based wait (It is used one-time)
*/
static
int
onenand_try_interrupt_wait
(
struct
mtd_info
*
mtd
,
int
state
)
{
struct
onenand_chip
*
this
=
mtd
->
priv
;
unsigned
long
remain
,
timeout
;
/* 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
)
{
printk
(
KERN_INFO
"OneNAND: There's no interrupt. "
"We use the normal wait
\n
"
);
/* Release the irq */
free_irq
(
this
->
irq
,
this
);
this
->
wait
=
onenand_wait
;
}
return
onenand_wait
(
mtd
,
state
);
}
/*
* onenand_setup_wait - [OneNAND Interface] setup onenand wait method
* @param mtd MTD device structure
*
* There's two method to wait onenand work
* 1. polling - read interrupt status register
* 2. interrupt - use the kernel interrupt method
*/
static
void
onenand_setup_wait
(
struct
mtd_info
*
mtd
)
{
struct
onenand_chip
*
this
=
mtd
->
priv
;
int
syscfg
;
init_completion
(
&
this
->
complete
);
if
(
this
->
irq
<=
0
)
{
this
->
wait
=
onenand_wait
;
return
;
}
if
(
request_irq
(
this
->
irq
,
&
onenand_interrupt
,
IRQF_SHARED
,
"onenand"
,
this
))
{
/* If we can't get irq, use the normal wait */
this
->
wait
=
onenand_wait
;
return
;
}
/* Enable interrupt */
syscfg
=
this
->
read_word
(
this
->
base
+
ONENAND_REG_SYS_CFG1
);
syscfg
|=
ONENAND_SYS_CFG1_IOBE
;
this
->
write_word
(
syscfg
,
this
->
base
+
ONENAND_REG_SYS_CFG1
);
this
->
wait
=
onenand_try_interrupt_wait
;
}
/**
* onenand_bufferram_offset - [DEFAULT] BufferRAM offset
* @param mtd MTD data structure
...
...
@@ -609,6 +718,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t
*
retlen
,
u_char
*
buf
)
{
struct
onenand_chip
*
this
=
mtd
->
priv
;
struct
mtd_ecc_stats
stats
;
int
read
=
0
,
column
;
int
thislen
;
int
ret
=
0
;
...
...
@@ -627,6 +737,7 @@ 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
);
...
...
@@ -668,7 +779,11 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
* retlen == desired len and result == -EBADMSG
*/
*
retlen
=
read
;
return
ret
;
if
(
mtd
->
ecc_stats
.
failed
-
stats
.
failed
)
return
-
EBADMSG
;
return
mtd
->
ecc_stats
.
corrected
-
stats
.
corrected
?
-
EUCLEAN
:
0
;
}
/**
...
...
@@ -1129,7 +1244,6 @@ static void onenand_sync(struct mtd_info *mtd)
onenand_release_device
(
mtd
);
}
/**
* onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
* @param mtd MTD device structure
...
...
@@ -1196,32 +1310,38 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
}
/**
* onenand_
unlock - [MTD Interface] U
nlock block(s)
* onenand_
do_lock_cmd - [OneNAND Interface] Lock or u
nlock block(s)
* @param mtd MTD device structure
* @param ofs offset relative to mtd start
* @param len number of bytes to unlock
* @param len number of bytes to
lock or
unlock
*
*
U
nlock one or more blocks
*
Lock or u
nlock one or more blocks
*/
static
int
onenand_
unlock
(
struct
mtd_info
*
mtd
,
loff_t
ofs
,
size_t
len
)
static
int
onenand_
do_lock_cmd
(
struct
mtd_info
*
mtd
,
loff_t
ofs
,
size_t
len
,
int
cmd
)
{
struct
onenand_chip
*
this
=
mtd
->
priv
;
int
start
,
end
,
block
,
value
,
status
;
int
wp_status_mask
;
start
=
ofs
>>
this
->
erase_shift
;
end
=
len
>>
this
->
erase_shift
;
if
(
cmd
==
ONENAND_CMD_LOCK
)
wp_status_mask
=
ONENAND_WP_LS
;
else
wp_status_mask
=
ONENAND_WP_US
;
/* Continuous lock scheme */
if
(
this
->
options
&
ONENAND_HAS_CONT_LOCK
)
{
/* Set start block address */
this
->
write_word
(
start
,
this
->
base
+
ONENAND_REG_START_BLOCK_ADDRESS
);
/* Set end block address */
this
->
write_word
(
start
+
end
-
1
,
this
->
base
+
ONENAND_REG_END_BLOCK_ADDRESS
);
/* Write
un
lock command */
this
->
command
(
mtd
,
ONENAND_CMD_UNLOCK
,
0
,
0
);
/* Write lock command */
this
->
command
(
mtd
,
cmd
,
0
,
0
);
/* There's no return value */
this
->
wait
(
mtd
,
FL_
UN
LOCKING
);
this
->
wait
(
mtd
,
FL_LOCKING
);
/* Sanity check */
while
(
this
->
read_word
(
this
->
base
+
ONENAND_REG_CTRL_STATUS
)
...
...
@@ -1230,7 +1350,7 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
/* Check lock status */
status
=
this
->
read_word
(
this
->
base
+
ONENAND_REG_WP_STATUS
);
if
(
!
(
status
&
ONENAND_WP_US
))
if
(
!
(
status
&
wp_status_mask
))
printk
(
KERN_ERR
"wp status = 0x%x
\n
"
,
status
);
return
0
;
...
...
@@ -1246,11 +1366,11 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
this
->
write_word
(
value
,
this
->
base
+
ONENAND_REG_START_ADDRESS2
);
/* Set start block address */
this
->
write_word
(
block
,
this
->
base
+
ONENAND_REG_START_BLOCK_ADDRESS
);
/* Write
un
lock command */
this
->
command
(
mtd
,
ONENAND_CMD_UNLOCK
,
0
,
0
);
/* Write lock command */
this
->
command
(
mtd
,
cmd
,
0
,
0
);
/* There's no return value */
this
->
wait
(
mtd
,
FL_
UN
LOCKING
);
this
->
wait
(
mtd
,
FL_LOCKING
);
/* Sanity check */
while
(
this
->
read_word
(
this
->
base
+
ONENAND_REG_CTRL_STATUS
)
...
...
@@ -1259,13 +1379,39 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
/* Check lock status */
status
=
this
->
read_word
(
this
->
base
+
ONENAND_REG_WP_STATUS
);
if
(
!
(
status
&
ONENAND_WP_US
))
if
(
!
(
status
&
wp_status_mask
))
printk
(
KERN_ERR
"block = %d, wp status = 0x%x
\n
"
,
block
,
status
);
}
return
0
;
}
/**
* onenand_lock - [MTD Interface] Lock block(s)
* @param mtd MTD device structure
* @param ofs offset relative to mtd start
* @param len number of bytes to unlock
*
* Lock one or more blocks
*/
static
int
onenand_lock
(
struct
mtd_info
*
mtd
,
loff_t
ofs
,
size_t
len
)
{
return
onenand_do_lock_cmd
(
mtd
,
ofs
,
len
,
ONENAND_CMD_LOCK
);
}
/**
* onenand_unlock - [MTD Interface] Unlock block(s)
* @param mtd MTD device structure
* @param ofs offset relative to mtd start
* @param len number of bytes to unlock
*
* Unlock one or more blocks
*/
static
int
onenand_unlock
(
struct
mtd_info
*
mtd
,
loff_t
ofs
,
size_t
len
)
{
return
onenand_do_lock_cmd
(
mtd
,
ofs
,
len
,
ONENAND_CMD_UNLOCK
);
}
/**
* onenand_check_lock_status - [OneNAND Interface] Check lock status
* @param this onenand chip data structure
...
...
@@ -1310,7 +1456,7 @@ static int onenand_unlock_all(struct mtd_info *mtd)
this
->
command
(
mtd
,
ONENAND_CMD_UNLOCK_ALL
,
0
,
0
);
/* There's no return value */
this
->
wait
(
mtd
,
FL_
UN
LOCKING
);
this
->
wait
(
mtd
,
FL_LOCKING
);
/* Sanity check */
while
(
this
->
read_word
(
this
->
base
+
ONENAND_REG_CTRL_STATUS
)
...
...
@@ -1334,7 +1480,7 @@ static int onenand_unlock_all(struct mtd_info *mtd)
return
0
;
}
mtd
->
unlock
(
mtd
,
0x0
,
this
->
chipsize
);
onenand_
unlock
(
mtd
,
0x0
,
this
->
chipsize
);
return
0
;
}
...
...
@@ -1762,7 +1908,7 @@ static int onenand_probe(struct mtd_info *mtd)
/* Read manufacturer and device IDs from Register */
maf_id
=
this
->
read_word
(
this
->
base
+
ONENAND_REG_MANUFACTURER_ID
);
dev_id
=
this
->
read_word
(
this
->
base
+
ONENAND_REG_DEVICE_ID
);
ver_id
=
this
->
read_word
(
this
->
base
+
ONENAND_REG_VERSION_ID
);
ver_id
=
this
->
read_word
(
this
->
base
+
ONENAND_REG_VERSION_ID
);
/* Check OneNAND device */
if
(
maf_id
!=
bram_maf_id
||
dev_id
!=
bram_dev_id
)
...
...
@@ -1846,7 +1992,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
if
(
!
this
->
command
)
this
->
command
=
onenand_command
;
if
(
!
this
->
wait
)
this
->
wait
=
onenand_wait
;
onenand_setup_wait
(
mtd
)
;
if
(
!
this
->
read_bufferram
)
this
->
read_bufferram
=
onenand_read_bufferram
;
...
...
@@ -1922,7 +2068,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
mtd
->
lock_user_prot_reg
=
onenand_lock_user_prot_reg
;
#endif
mtd
->
sync
=
onenand_sync
;
mtd
->
lock
=
NULL
;
mtd
->
lock
=
onenand_lock
;
mtd
->
unlock
=
onenand_unlock
;
mtd
->
suspend
=
onenand_suspend
;
mtd
->
resume
=
onenand_resume
;
...
...
drivers/mtd/onenand/onenand_bbt.c
View file @
103e40f6
...
...
@@ -100,6 +100,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
bbm
->
bbt
[
i
>>
3
]
|=
0x03
<<
(
i
&
0x6
);
printk
(
KERN_WARNING
"Bad eraseblock %d at 0x%08x
\n
"
,
i
>>
1
,
(
unsigned
int
)
from
);
mtd
->
ecc_stats
.
badblocks
++
;
break
;
}
}
...
...
include/linux/mtd/onenand.h
View file @
103e40f6
...
...
@@ -13,6 +13,7 @@
#define __LINUX_MTD_ONENAND_H
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/mtd/onenand_regs.h>
#include <linux/mtd/bbm.h>
...
...
@@ -33,7 +34,6 @@ typedef enum {
FL_WRITING
,
FL_ERASING
,
FL_SYNCING
,
FL_UNLOCKING
,
FL_LOCKING
,
FL_RESETING
,
FL_OTPING
,
...
...
@@ -120,6 +120,9 @@ struct onenand_chip {
int
(
*
block_markbad
)(
struct
mtd_info
*
mtd
,
loff_t
ofs
);
int
(
*
scan_bbt
)(
struct
mtd_info
*
mtd
);
struct
completion
complete
;
int
irq
;
spinlock_t
chip_lock
;
wait_queue_head_t
wq
;
onenand_state_t
state
;
...
...
include/linux/mtd/onenand_regs.h
View file @
103e40f6
...
...
@@ -179,6 +179,7 @@
* ECC Status Reigser FF00h (R)
*/
#define ONENAND_ECC_1BIT (1 << 0)
#define ONENAND_ECC_1BIT_ALL (0x5555)
#define ONENAND_ECC_2BIT (1 << 1)
#define ONENAND_ECC_2BIT_ALL (0xAAAA)
...
...
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