Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
96178769
Commit
96178769
authored
Nov 30, 2009
by
David Woodhouse
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'mxc-nand' of
git://git.pengutronix.de/git/imx/linux-2.6
parents
2e386e4b
1fbff0a6
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
300 additions
and
476 deletions
+300
-476
arch/arm/plat-mxc/include/mach/mxc_nand.h
arch/arm/plat-mxc/include/mach/mxc_nand.h
+2
-1
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/mxc_nand.c
+298
-475
No files found.
arch/arm/plat-mxc/include/mach/mxc_nand.h
View file @
96178769
...
@@ -22,6 +22,7 @@
...
@@ -22,6 +22,7 @@
struct
mxc_nand_platform_data
{
struct
mxc_nand_platform_data
{
int
width
;
/* data bus width in bytes */
int
width
;
/* data bus width in bytes */
int
hw_ecc
;
/* 0 if supress hardware ECC */
int
hw_ecc
:
1
;
/* 0 if supress hardware ECC */
int
flash_bbt
:
1
;
/* set to 1 to use a flash based bbt */
};
};
#endif
/* __ASM_ARCH_NAND_H */
#endif
/* __ASM_ARCH_NAND_H */
drivers/mtd/nand/mxc_nand.c
View file @
96178769
...
@@ -33,9 +33,13 @@
...
@@ -33,9 +33,13 @@
#include <asm/mach/flash.h>
#include <asm/mach/flash.h>
#include <mach/mxc_nand.h>
#include <mach/mxc_nand.h>
#include <mach/hardware.h>
#define DRIVER_NAME "mxc_nand"
#define DRIVER_NAME "mxc_nand"
#define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35())
#define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27())
/* Addresses for NFC registers */
/* Addresses for NFC registers */
#define NFC_BUF_SIZE 0xE00
#define NFC_BUF_SIZE 0xE00
#define NFC_BUF_ADDR 0xE04
#define NFC_BUF_ADDR 0xE04
...
@@ -46,24 +50,14 @@
...
@@ -46,24 +50,14 @@
#define NFC_RSLTMAIN_AREA 0xE0E
#define NFC_RSLTMAIN_AREA 0xE0E
#define NFC_RSLTSPARE_AREA 0xE10
#define NFC_RSLTSPARE_AREA 0xE10
#define NFC_WRPROT 0xE12
#define NFC_WRPROT 0xE12
#define NFC_UNLOCKSTART_BLKADDR 0xE14
#define NFC_V1_UNLOCKSTART_BLKADDR 0xe14
#define NFC_UNLOCKEND_BLKADDR 0xE16
#define NFC_V1_UNLOCKEND_BLKADDR 0xe16
#define NFC_V21_UNLOCKSTART_BLKADDR 0xe20
#define NFC_V21_UNLOCKEND_BLKADDR 0xe22
#define NFC_NF_WRPRST 0xE18
#define NFC_NF_WRPRST 0xE18
#define NFC_CONFIG1 0xE1A
#define NFC_CONFIG1 0xE1A
#define NFC_CONFIG2 0xE1C
#define NFC_CONFIG2 0xE1C
/* Addresses for NFC RAM BUFFER Main area 0 */
#define MAIN_AREA0 0x000
#define MAIN_AREA1 0x200
#define MAIN_AREA2 0x400
#define MAIN_AREA3 0x600
/* Addresses for NFC SPARE BUFFER Spare area 0 */
#define SPARE_AREA0 0x800
#define SPARE_AREA1 0x810
#define SPARE_AREA2 0x820
#define SPARE_AREA3 0x830
/* Set INT to 0, FCMD to 1, rest to 0 in NFC_CONFIG2 Register
/* Set INT to 0, FCMD to 1, rest to 0 in NFC_CONFIG2 Register
* for Command operation */
* for Command operation */
#define NFC_CMD 0x1
#define NFC_CMD 0x1
...
@@ -106,48 +100,66 @@ struct mxc_nand_host {
...
@@ -106,48 +100,66 @@ struct mxc_nand_host {
struct
mtd_partition
*
parts
;
struct
mtd_partition
*
parts
;
struct
device
*
dev
;
struct
device
*
dev
;
void
*
spare0
;
void
*
main_area0
;
void
*
main_area1
;
void
__iomem
*
base
;
void
__iomem
*
regs
;
void
__iomem
*
regs
;
int
spare_only
;
int
status_request
;
int
status_request
;
int
pagesize_2k
;
uint16_t
col_addr
;
struct
clk
*
clk
;
struct
clk
*
clk
;
int
clk_act
;
int
clk_act
;
int
irq
;
int
irq
;
wait_queue_head_t
irq_waitq
;
wait_queue_head_t
irq_waitq
;
};
/* Define delays in microsec for NAND device operations */
#define TROP_US_DELAY 2000
/* Macros to get byte and bit positions of ECC */
#define COLPOS(x) ((x) >> 3)
#define BITPOS(x) ((x) & 0xf)
/* Define single bit Error positions in Main & Spare area */
uint8_t
*
data_buf
;
#define MAIN_SINGLEBIT_ERROR 0x4
unsigned
int
buf_start
;
#define SPARE_SINGLEBIT_ERROR 0x1
int
spare_len
;
/* OOB placement block for use with hardware ecc generation */
static
struct
nand_ecclayout
nand_hw_eccoob_8
=
{
.
eccbytes
=
5
,
.
eccpos
=
{
6
,
7
,
8
,
9
,
10
},
.
oobfree
=
{{
0
,
5
},
{
11
,
5
},
}
};
};
static
struct
nand_ecclayout
nand_hw_eccoob_16
=
{
/* OOB placement block for use with hardware ecc generation */
static
struct
nand_ecclayout
nandv1_hw_eccoob_smallpage
=
{
.
eccbytes
=
5
,
.
eccbytes
=
5
,
.
eccpos
=
{
6
,
7
,
8
,
9
,
10
},
.
eccpos
=
{
6
,
7
,
8
,
9
,
10
},
.
oobfree
=
{{
0
,
5
},
{
1
1
,
5
},
}
.
oobfree
=
{{
0
,
5
},
{
1
2
,
4
},
}
};
};
static
struct
nand_ecclayout
nand
_hw_eccoob_64
=
{
static
struct
nand_ecclayout
nand
v1_hw_eccoob_largepage
=
{
.
eccbytes
=
20
,
.
eccbytes
=
20
,
.
eccpos
=
{
6
,
7
,
8
,
9
,
10
,
22
,
23
,
24
,
25
,
26
,
.
eccpos
=
{
6
,
7
,
8
,
9
,
10
,
22
,
23
,
24
,
25
,
26
,
38
,
39
,
40
,
41
,
42
,
54
,
55
,
56
,
57
,
58
},
38
,
39
,
40
,
41
,
42
,
54
,
55
,
56
,
57
,
58
},
.
oobfree
=
{{
2
,
4
},
{
11
,
10
},
{
27
,
10
},
{
43
,
10
},
{
59
,
5
},
}
.
oobfree
=
{{
2
,
4
},
{
11
,
10
},
{
27
,
10
},
{
43
,
10
},
{
59
,
5
},
}
};
};
/* OOB description for 512 byte pages with 16 byte OOB */
static
struct
nand_ecclayout
nandv2_hw_eccoob_smallpage
=
{
.
eccbytes
=
1
*
9
,
.
eccpos
=
{
7
,
8
,
9
,
10
,
11
,
12
,
13
,
14
,
15
},
.
oobfree
=
{
{.
offset
=
0
,
.
length
=
5
}
}
};
/* OOB description for 2048 byte pages with 64 byte OOB */
static
struct
nand_ecclayout
nandv2_hw_eccoob_largepage
=
{
.
eccbytes
=
4
*
9
,
.
eccpos
=
{
7
,
8
,
9
,
10
,
11
,
12
,
13
,
14
,
15
,
23
,
24
,
25
,
26
,
27
,
28
,
29
,
30
,
31
,
39
,
40
,
41
,
42
,
43
,
44
,
45
,
46
,
47
,
55
,
56
,
57
,
58
,
59
,
60
,
61
,
62
,
63
},
.
oobfree
=
{
{.
offset
=
2
,
.
length
=
4
},
{.
offset
=
16
,
.
length
=
7
},
{.
offset
=
32
,
.
length
=
7
},
{.
offset
=
48
,
.
length
=
7
}
}
};
#ifdef CONFIG_MTD_PARTITIONS
#ifdef CONFIG_MTD_PARTITIONS
static
const
char
*
part_probes
[]
=
{
"RedBoot"
,
"cmdlinepart"
,
NULL
};
static
const
char
*
part_probes
[]
=
{
"RedBoot"
,
"cmdlinepart"
,
NULL
};
#endif
#endif
...
@@ -170,10 +182,10 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
...
@@ -170,10 +182,10 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
/* This function polls the NANDFC to wait for the basic operation to
/* This function polls the NANDFC to wait for the basic operation to
* complete by checking the INT bit of config2 register.
* complete by checking the INT bit of config2 register.
*/
*/
static
void
wait_op_done
(
struct
mxc_nand_host
*
host
,
int
max_retries
,
static
void
wait_op_done
(
struct
mxc_nand_host
*
host
,
int
useirq
)
uint16_t
param
,
int
useirq
)
{
{
uint32_t
tmp
;
uint32_t
tmp
;
int
max_retries
=
2000
;
if
(
useirq
)
{
if
(
useirq
)
{
if
((
readw
(
host
->
regs
+
NFC_CONFIG2
)
&
NFC_INT
)
==
0
)
{
if
((
readw
(
host
->
regs
+
NFC_CONFIG2
)
&
NFC_INT
)
==
0
)
{
...
@@ -200,8 +212,8 @@ static void wait_op_done(struct mxc_nand_host *host, int max_retries,
...
@@ -200,8 +212,8 @@ static void wait_op_done(struct mxc_nand_host *host, int max_retries,
udelay
(
1
);
udelay
(
1
);
}
}
if
(
max_retries
<
0
)
if
(
max_retries
<
0
)
DEBUG
(
MTD_DEBUG_LEVEL0
,
"%s
(%d)
: INT not set
\n
"
,
DEBUG
(
MTD_DEBUG_LEVEL0
,
"%s: INT not set
\n
"
,
__func__
,
param
);
__func__
);
}
}
}
}
...
@@ -215,7 +227,7 @@ static void send_cmd(struct mxc_nand_host *host, uint16_t cmd, int useirq)
...
@@ -215,7 +227,7 @@ static void send_cmd(struct mxc_nand_host *host, uint16_t cmd, int useirq)
writew
(
NFC_CMD
,
host
->
regs
+
NFC_CONFIG2
);
writew
(
NFC_CMD
,
host
->
regs
+
NFC_CONFIG2
);
/* Wait for operation to complete */
/* Wait for operation to complete */
wait_op_done
(
host
,
TROP_US_DELAY
,
cmd
,
useirq
);
wait_op_done
(
host
,
useirq
);
}
}
/* This function sends an address (or partial address) to the
/* This function sends an address (or partial address) to the
...
@@ -229,82 +241,47 @@ static void send_addr(struct mxc_nand_host *host, uint16_t addr, int islast)
...
@@ -229,82 +241,47 @@ static void send_addr(struct mxc_nand_host *host, uint16_t addr, int islast)
writew
(
NFC_ADDR
,
host
->
regs
+
NFC_CONFIG2
);
writew
(
NFC_ADDR
,
host
->
regs
+
NFC_CONFIG2
);
/* Wait for operation to complete */
/* Wait for operation to complete */
wait_op_done
(
host
,
TROP_US_DELAY
,
addr
,
islast
);
wait_op_done
(
host
,
islast
);
}
}
/* This function requests the NANDFC to initate the transfer
static
void
send_page
(
struct
mtd_info
*
mtd
,
unsigned
int
ops
)
* of data currently in the NANDFC RAM buffer to the NAND device. */
static
void
send_prog_page
(
struct
mxc_nand_host
*
host
,
uint8_t
buf_id
,
int
spare_only
)
{
{
DEBUG
(
MTD_DEBUG_LEVEL3
,
"send_prog_page (%d)
\n
"
,
spare_only
);
struct
nand_chip
*
nand_chip
=
mtd
->
priv
;
struct
mxc_nand_host
*
host
=
nand_chip
->
priv
;
/* NANDFC buffer 0 is used for page read/write */
int
bufs
,
i
;
writew
(
buf_id
,
host
->
regs
+
NFC_BUF_ADDR
);
/* Configure spare or page+spare access */
if
(
!
host
->
pagesize_2k
)
{
uint16_t
config1
=
readw
(
host
->
regs
+
NFC_CONFIG1
);
if
(
spare_only
)
config1
|=
NFC_SP_EN
;
else
config1
&=
~
(
NFC_SP_EN
);
writew
(
config1
,
host
->
regs
+
NFC_CONFIG1
);
}
writew
(
NFC_INPUT
,
host
->
regs
+
NFC_CONFIG2
);
if
(
nfc_is_v1
()
&&
mtd
->
writesize
>
512
)
bufs
=
4
;
else
bufs
=
1
;
/* Wait for operation to complete */
for
(
i
=
0
;
i
<
bufs
;
i
++
)
{
wait_op_done
(
host
,
TROP_US_DELAY
,
spare_only
,
true
);
}
/* Requests NANDFC to initated the transfer of data from the
/* NANDFC buffer 0 is used for page read/write */
* NAND device into in the NANDFC ram buffer. */
writew
(
i
,
host
->
regs
+
NFC_BUF_ADDR
);
static
void
send_read_page
(
struct
mxc_nand_host
*
host
,
uint8_t
buf_id
,
int
spare_only
)
{
DEBUG
(
MTD_DEBUG_LEVEL3
,
"send_read_page (%d)
\n
"
,
spare_only
);
/* NANDFC buffer 0 is used for page read/write */
writew
(
ops
,
host
->
regs
+
NFC_CONFIG2
);
writew
(
buf_id
,
host
->
regs
+
NFC_BUF_ADDR
);
/* Configure spare or page+spare access */
/* Wait for operation to complete */
if
(
!
host
->
pagesize_2k
)
{
wait_op_done
(
host
,
true
);
uint32_t
config1
=
readw
(
host
->
regs
+
NFC_CONFIG1
);
if
(
spare_only
)
config1
|=
NFC_SP_EN
;
else
config1
&=
~
NFC_SP_EN
;
writew
(
config1
,
host
->
regs
+
NFC_CONFIG1
);
}
}
writew
(
NFC_OUTPUT
,
host
->
regs
+
NFC_CONFIG2
);
/* Wait for operation to complete */
wait_op_done
(
host
,
TROP_US_DELAY
,
spare_only
,
true
);
}
}
/* Request the NANDFC to perform a read of the NAND device ID. */
/* Request the NANDFC to perform a read of the NAND device ID. */
static
void
send_read_id
(
struct
mxc_nand_host
*
host
)
static
void
send_read_id
(
struct
mxc_nand_host
*
host
)
{
{
struct
nand_chip
*
this
=
&
host
->
nand
;
struct
nand_chip
*
this
=
&
host
->
nand
;
uint16_t
tmp
;
/* NANDFC buffer 0 is used for device ID output */
/* NANDFC buffer 0 is used for device ID output */
writew
(
0x0
,
host
->
regs
+
NFC_BUF_ADDR
);
writew
(
0x0
,
host
->
regs
+
NFC_BUF_ADDR
);
/* Read ID into main buffer */
tmp
=
readw
(
host
->
regs
+
NFC_CONFIG1
);
tmp
&=
~
NFC_SP_EN
;
writew
(
tmp
,
host
->
regs
+
NFC_CONFIG1
);
writew
(
NFC_ID
,
host
->
regs
+
NFC_CONFIG2
);
writew
(
NFC_ID
,
host
->
regs
+
NFC_CONFIG2
);
/* Wait for operation to complete */
/* Wait for operation to complete */
wait_op_done
(
host
,
TROP_US_DELAY
,
0
,
true
);
wait_op_done
(
host
,
true
);
if
(
this
->
options
&
NAND_BUSWIDTH_16
)
{
if
(
this
->
options
&
NAND_BUSWIDTH_16
)
{
void
__iomem
*
main_buf
=
host
->
regs
+
MAIN_AREA
0
;
void
__iomem
*
main_buf
=
host
->
main_area
0
;
/* compress the ID info */
/* compress the ID info */
writeb
(
readb
(
main_buf
+
2
),
main_buf
+
1
);
writeb
(
readb
(
main_buf
+
2
),
main_buf
+
1
);
writeb
(
readb
(
main_buf
+
4
),
main_buf
+
2
);
writeb
(
readb
(
main_buf
+
4
),
main_buf
+
2
);
...
@@ -312,15 +289,16 @@ static void send_read_id(struct mxc_nand_host *host)
...
@@ -312,15 +289,16 @@ static void send_read_id(struct mxc_nand_host *host)
writeb
(
readb
(
main_buf
+
8
),
main_buf
+
4
);
writeb
(
readb
(
main_buf
+
8
),
main_buf
+
4
);
writeb
(
readb
(
main_buf
+
10
),
main_buf
+
5
);
writeb
(
readb
(
main_buf
+
10
),
main_buf
+
5
);
}
}
memcpy
(
host
->
data_buf
,
host
->
main_area0
,
16
);
}
}
/* This function requests the NANDFC to perform a read of the
/* This function requests the NANDFC to perform a read of the
* NAND device status and returns the current status. */
* NAND device status and returns the current status. */
static
uint16_t
get_dev_status
(
struct
mxc_nand_host
*
host
)
static
uint16_t
get_dev_status
(
struct
mxc_nand_host
*
host
)
{
{
void
__iomem
*
main_buf
=
host
->
regs
+
MAIN_AREA
1
;
void
__iomem
*
main_buf
=
host
->
main_area
1
;
uint32_t
store
;
uint32_t
store
;
uint16_t
ret
,
tmp
;
uint16_t
ret
;
/* Issue status request to NAND device */
/* Issue status request to NAND device */
/* store the main area1 first word, later do recovery */
/* store the main area1 first word, later do recovery */
...
@@ -329,15 +307,10 @@ static uint16_t get_dev_status(struct mxc_nand_host *host)
...
@@ -329,15 +307,10 @@ static uint16_t get_dev_status(struct mxc_nand_host *host)
* corruption of read/write buffer on status requests. */
* corruption of read/write buffer on status requests. */
writew
(
1
,
host
->
regs
+
NFC_BUF_ADDR
);
writew
(
1
,
host
->
regs
+
NFC_BUF_ADDR
);
/* Read status into main buffer */
tmp
=
readw
(
host
->
regs
+
NFC_CONFIG1
);
tmp
&=
~
NFC_SP_EN
;
writew
(
tmp
,
host
->
regs
+
NFC_CONFIG1
);
writew
(
NFC_STATUS
,
host
->
regs
+
NFC_CONFIG2
);
writew
(
NFC_STATUS
,
host
->
regs
+
NFC_CONFIG2
);
/* Wait for operation to complete */
/* Wait for operation to complete */
wait_op_done
(
host
,
TROP_US_DELAY
,
0
,
true
);
wait_op_done
(
host
,
true
);
/* Status is placed in first word of main buffer */
/* Status is placed in first word of main buffer */
/* get status, then recovery area 1 data */
/* get status, then recovery area 1 data */
...
@@ -397,32 +370,14 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd)
...
@@ -397,32 +370,14 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd)
{
{
struct
nand_chip
*
nand_chip
=
mtd
->
priv
;
struct
nand_chip
*
nand_chip
=
mtd
->
priv
;
struct
mxc_nand_host
*
host
=
nand_chip
->
priv
;
struct
mxc_nand_host
*
host
=
nand_chip
->
priv
;
uint8_t
ret
=
0
;
uint8_t
ret
;
uint16_t
col
,
rd_word
;
uint16_t
__iomem
*
main_buf
=
host
->
regs
+
MAIN_AREA0
;
uint16_t
__iomem
*
spare_buf
=
host
->
regs
+
SPARE_AREA0
;
/* Check for status request */
/* Check for status request */
if
(
host
->
status_request
)
if
(
host
->
status_request
)
return
get_dev_status
(
host
)
&
0xFF
;
return
get_dev_status
(
host
)
&
0xFF
;
/* Get column for 16-bit access */
ret
=
*
(
uint8_t
*
)(
host
->
data_buf
+
host
->
buf_start
);
col
=
host
->
col_addr
>>
1
;
host
->
buf_start
++
;
/* If we are accessing the spare region */
if
(
host
->
spare_only
)
rd_word
=
readw
(
&
spare_buf
[
col
]);
else
rd_word
=
readw
(
&
main_buf
[
col
]);
/* Pick upper/lower byte of word from RAM buffer */
if
(
host
->
col_addr
&
0x1
)
ret
=
(
rd_word
>>
8
)
&
0xFF
;
else
ret
=
rd_word
&
0xFF
;
/* Update saved column address */
host
->
col_addr
++
;
return
ret
;
return
ret
;
}
}
...
@@ -431,33 +386,10 @@ static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
...
@@ -431,33 +386,10 @@ static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
{
{
struct
nand_chip
*
nand_chip
=
mtd
->
priv
;
struct
nand_chip
*
nand_chip
=
mtd
->
priv
;
struct
mxc_nand_host
*
host
=
nand_chip
->
priv
;
struct
mxc_nand_host
*
host
=
nand_chip
->
priv
;
uint16_t
col
,
rd_word
,
ret
;
uint16_t
ret
;
uint16_t
__iomem
*
p
;
DEBUG
(
MTD_DEBUG_LEVEL3
,
"mxc_nand_read_word(col = %d)
\n
"
,
host
->
col_addr
);
col
=
host
->
col_addr
;
/* Adjust saved column address */
if
(
col
<
mtd
->
writesize
&&
host
->
spare_only
)
col
+=
mtd
->
writesize
;
if
(
col
<
mtd
->
writesize
)
ret
=
*
(
uint16_t
*
)(
host
->
data_buf
+
host
->
buf_start
);
p
=
(
host
->
regs
+
MAIN_AREA0
)
+
(
col
>>
1
);
host
->
buf_start
+=
2
;
else
p
=
(
host
->
regs
+
SPARE_AREA0
)
+
((
col
-
mtd
->
writesize
)
>>
1
);
if
(
col
&
1
)
{
rd_word
=
readw
(
p
);
ret
=
(
rd_word
>>
8
)
&
0xff
;
rd_word
=
readw
(
&
p
[
1
]);
ret
|=
(
rd_word
<<
8
)
&
0xff00
;
}
else
ret
=
readw
(
p
);
/* Update saved column address */
host
->
col_addr
=
col
+
2
;
return
ret
;
return
ret
;
}
}
...
@@ -470,94 +402,14 @@ static void mxc_nand_write_buf(struct mtd_info *mtd,
...
@@ -470,94 +402,14 @@ static void mxc_nand_write_buf(struct mtd_info *mtd,
{
{
struct
nand_chip
*
nand_chip
=
mtd
->
priv
;
struct
nand_chip
*
nand_chip
=
mtd
->
priv
;
struct
mxc_nand_host
*
host
=
nand_chip
->
priv
;
struct
mxc_nand_host
*
host
=
nand_chip
->
priv
;
int
n
,
col
,
i
=
0
;
u16
col
=
host
->
buf_start
;
int
n
=
mtd
->
oobsize
+
mtd
->
writesize
-
col
;
DEBUG
(
MTD_DEBUG_LEVEL3
,
"mxc_nand_write_buf(col = %d, len = %d)
\n
"
,
host
->
col_addr
,
len
);
col
=
host
->
col_addr
;
/* Adjust saved column address */
if
(
col
<
mtd
->
writesize
&&
host
->
spare_only
)
col
+=
mtd
->
writesize
;
n
=
mtd
->
writesize
+
mtd
->
oobsize
-
col
;
n
=
min
(
len
,
n
);
DEBUG
(
MTD_DEBUG_LEVEL3
,
"%s:%d: col = %d, n = %d
\n
"
,
__func__
,
__LINE__
,
col
,
n
);
while
(
n
)
{
void
__iomem
*
p
;
if
(
col
<
mtd
->
writesize
)
p
=
host
->
regs
+
MAIN_AREA0
+
(
col
&
~
3
);
else
p
=
host
->
regs
+
SPARE_AREA0
-
mtd
->
writesize
+
(
col
&
~
3
);
DEBUG
(
MTD_DEBUG_LEVEL3
,
"%s:%d: p = %p
\n
"
,
__func__
,
__LINE__
,
p
);
if
(((
col
|
(
int
)
&
buf
[
i
])
&
3
)
||
n
<
16
)
{
uint32_t
data
=
0
;
if
(
col
&
3
||
n
<
4
)
data
=
readl
(
p
);
switch
(
col
&
3
)
{
case
0
:
if
(
n
)
{
data
=
(
data
&
0xffffff00
)
|
(
buf
[
i
++
]
<<
0
);
n
--
;
col
++
;
}
case
1
:
if
(
n
)
{
data
=
(
data
&
0xffff00ff
)
|
(
buf
[
i
++
]
<<
8
);
n
--
;
col
++
;
}
case
2
:
if
(
n
)
{
data
=
(
data
&
0xff00ffff
)
|
(
buf
[
i
++
]
<<
16
);
n
--
;
col
++
;
}
case
3
:
if
(
n
)
{
data
=
(
data
&
0x00ffffff
)
|
(
buf
[
i
++
]
<<
24
);
n
--
;
col
++
;
}
}
writel
(
data
,
p
);
n
=
min
(
n
,
len
);
}
else
{
int
m
=
mtd
->
writesize
-
col
;
if
(
col
>=
mtd
->
writesize
)
m
+=
mtd
->
oobsize
;
m
=
min
(
n
,
m
)
&
~
3
;
memcpy
(
host
->
data_buf
+
col
,
buf
,
n
)
;
DEBUG
(
MTD_DEBUG_LEVEL3
,
host
->
buf_start
+=
n
;
"%s:%d: n = %d, m = %d, i = %d, col = %d
\n
"
,
__func__
,
__LINE__
,
n
,
m
,
i
,
col
);
memcpy
(
p
,
&
buf
[
i
],
m
);
col
+=
m
;
i
+=
m
;
n
-=
m
;
}
}
/* Update saved column address */
host
->
col_addr
=
col
;
}
}
/* Read the data buffer from the NAND Flash. To read the data from NAND
/* Read the data buffer from the NAND Flash. To read the data from NAND
...
@@ -568,75 +420,14 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
...
@@ -568,75 +420,14 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
{
{
struct
nand_chip
*
nand_chip
=
mtd
->
priv
;
struct
nand_chip
*
nand_chip
=
mtd
->
priv
;
struct
mxc_nand_host
*
host
=
nand_chip
->
priv
;
struct
mxc_nand_host
*
host
=
nand_chip
->
priv
;
int
n
,
col
,
i
=
0
;
u16
col
=
host
->
buf_start
;
int
n
=
mtd
->
oobsize
+
mtd
->
writesize
-
col
;
DEBUG
(
MTD_DEBUG_LEVEL3
,
"mxc_nand_read_buf(col = %d, len = %d)
\n
"
,
host
->
col_addr
,
len
);
col
=
host
->
col_addr
;
/* Adjust saved column address */
n
=
min
(
n
,
len
);
if
(
col
<
mtd
->
writesize
&&
host
->
spare_only
)
col
+=
mtd
->
writesize
;
n
=
mtd
->
writesize
+
mtd
->
oobsize
-
col
;
memcpy
(
buf
,
host
->
data_buf
+
col
,
len
);
n
=
min
(
len
,
n
);
while
(
n
)
{
void
__iomem
*
p
;
if
(
col
<
mtd
->
writesize
)
p
=
host
->
regs
+
MAIN_AREA0
+
(
col
&
~
3
);
else
p
=
host
->
regs
+
SPARE_AREA0
-
mtd
->
writesize
+
(
col
&
~
3
);
if
(((
col
|
(
int
)
&
buf
[
i
])
&
3
)
||
n
<
16
)
{
uint32_t
data
;
data
=
readl
(
p
);
switch
(
col
&
3
)
{
case
0
:
if
(
n
)
{
buf
[
i
++
]
=
(
uint8_t
)
(
data
);
n
--
;
col
++
;
}
case
1
:
if
(
n
)
{
buf
[
i
++
]
=
(
uint8_t
)
(
data
>>
8
);
n
--
;
col
++
;
}
case
2
:
if
(
n
)
{
buf
[
i
++
]
=
(
uint8_t
)
(
data
>>
16
);
n
--
;
col
++
;
}
case
3
:
if
(
n
)
{
buf
[
i
++
]
=
(
uint8_t
)
(
data
>>
24
);
n
--
;
col
++
;
}
}
}
else
{
int
m
=
mtd
->
writesize
-
col
;
if
(
col
>=
mtd
->
writesize
)
m
+=
mtd
->
oobsize
;
m
=
min
(
n
,
m
)
&
~
3
;
memcpy
(
&
buf
[
i
],
p
,
m
);
col
+=
m
;
i
+=
m
;
n
-=
m
;
}
}
/* Update saved column address */
host
->
col_addr
=
col
;
host
->
buf_start
+=
len
;
}
}
/* Used by the upper layer to verify the data in NAND Flash
/* Used by the upper layer to verify the data in NAND Flash
...
@@ -654,23 +445,6 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
...
@@ -654,23 +445,6 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
struct
nand_chip
*
nand_chip
=
mtd
->
priv
;
struct
nand_chip
*
nand_chip
=
mtd
->
priv
;
struct
mxc_nand_host
*
host
=
nand_chip
->
priv
;
struct
mxc_nand_host
*
host
=
nand_chip
->
priv
;
#ifdef CONFIG_MTD_NAND_MXC_FORCE_CE
if
(
chip
>
0
)
{
DEBUG
(
MTD_DEBUG_LEVEL0
,
"ERROR: Illegal chip select (chip = %d)
\n
"
,
chip
);
return
;
}
if
(
chip
==
-
1
)
{
writew
(
readw
(
host
->
regs
+
NFC_CONFIG1
)
&
~
NFC_CE
,
host
->
regs
+
NFC_CONFIG1
);
return
;
}
writew
(
readw
(
host
->
regs
+
NFC_CONFIG1
)
|
NFC_CE
,
host
->
regs
+
NFC_CONFIG1
);
#endif
switch
(
chip
)
{
switch
(
chip
)
{
case
-
1
:
case
-
1
:
/* Disable the NFC clock */
/* Disable the NFC clock */
...
@@ -692,94 +466,40 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
...
@@ -692,94 +466,40 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
}
}
}
}
/*
Used by the upper layer to write command to NAND Flash for
/*
*
different operations to be carried out on NAND Flash */
*
Function to transfer data to/from spare area.
static
void
mxc_nand_command
(
struct
mtd_info
*
mtd
,
unsigned
command
,
*/
int
column
,
int
page_addr
)
static
void
copy_spare
(
struct
mtd_info
*
mtd
,
bool
bfrom
)
{
{
struct
nand_chip
*
nand_chip
=
mtd
->
priv
;
struct
nand_chip
*
this
=
mtd
->
priv
;
struct
mxc_nand_host
*
host
=
nand_chip
->
priv
;
struct
mxc_nand_host
*
host
=
this
->
priv
;
int
useirq
=
true
;
u16
i
,
j
;
u16
n
=
mtd
->
writesize
>>
9
;
DEBUG
(
MTD_DEBUG_LEVEL3
,
u8
*
d
=
host
->
data_buf
+
mtd
->
writesize
;
"mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)
\n
"
,
u8
*
s
=
host
->
spare0
;
command
,
column
,
page_addr
);
u16
t
=
host
->
spare_len
;
/* Reset command state information */
j
=
(
mtd
->
oobsize
/
n
>>
1
)
<<
1
;
host
->
status_request
=
false
;
if
(
bfrom
)
{
/* Command pre-processing step */
for
(
i
=
0
;
i
<
n
-
1
;
i
++
)
switch
(
command
)
{
memcpy
(
d
+
i
*
j
,
s
+
i
*
t
,
j
);
case
NAND_CMD_STATUS
:
/* the last section */
host
->
col_addr
=
0
;
memcpy
(
d
+
i
*
j
,
s
+
i
*
t
,
mtd
->
oobsize
-
i
*
j
);
host
->
status_request
=
true
;
}
else
{
break
;
for
(
i
=
0
;
i
<
n
-
1
;
i
++
)
memcpy
(
&
s
[
i
*
t
],
&
d
[
i
*
j
],
j
);
case
NAND_CMD_READ0
:
host
->
col_addr
=
column
;
host
->
spare_only
=
false
;
useirq
=
false
;
break
;
case
NAND_CMD_READOOB
:
host
->
col_addr
=
column
;
host
->
spare_only
=
true
;
useirq
=
false
;
if
(
host
->
pagesize_2k
)
command
=
NAND_CMD_READ0
;
/* only READ0 is valid */
break
;
case
NAND_CMD_SEQIN
:
if
(
column
>=
mtd
->
writesize
)
{
/*
* FIXME: before send SEQIN command for write OOB,
* We must read one page out.
* For K9F1GXX has no READ1 command to set current HW
* pointer to spare area, we must write the whole page
* including OOB together.
*/
if
(
host
->
pagesize_2k
)
/* call ourself to read a page */
mxc_nand_command
(
mtd
,
NAND_CMD_READ0
,
0
,
page_addr
);
host
->
col_addr
=
column
-
mtd
->
writesize
;
host
->
spare_only
=
true
;
/* Set program pointer to spare region */
if
(
!
host
->
pagesize_2k
)
send_cmd
(
host
,
NAND_CMD_READOOB
,
false
);
}
else
{
host
->
spare_only
=
false
;
host
->
col_addr
=
column
;
/* Set program pointer to page start */
if
(
!
host
->
pagesize_2k
)
send_cmd
(
host
,
NAND_CMD_READ0
,
false
);
}
useirq
=
false
;
break
;
case
NAND_CMD_PAGEPROG
:
send_prog_page
(
host
,
0
,
host
->
spare_only
);
if
(
host
->
pagesize_2k
)
{
/* data in 4 areas datas */
send_prog_page
(
host
,
1
,
host
->
spare_only
);
send_prog_page
(
host
,
2
,
host
->
spare_only
);
send_prog_page
(
host
,
3
,
host
->
spare_only
);
}
break
;
case
NAND_CMD_ERASE1
:
/* the last section */
useirq
=
false
;
memcpy
(
&
s
[
i
*
t
],
&
d
[
i
*
j
],
mtd
->
oobsize
-
i
*
j
);
break
;
}
}
}
/* Write out the command to the device. */
static
void
mxc_do_addr_cycle
(
struct
mtd_info
*
mtd
,
int
column
,
int
page_addr
)
send_cmd
(
host
,
command
,
useirq
);
{
struct
nand_chip
*
nand_chip
=
mtd
->
priv
;
struct
mxc_nand_host
*
host
=
nand_chip
->
priv
;
/* Write out column address, if necessary */
/* Write out column address, if necessary */
if
(
column
!=
-
1
)
{
if
(
column
!=
-
1
)
{
...
@@ -791,7 +511,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
...
@@ -791,7 +511,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
* the full page.
* the full page.
*/
*/
send_addr
(
host
,
0
,
page_addr
==
-
1
);
send_addr
(
host
,
0
,
page_addr
==
-
1
);
if
(
host
->
pagesize_2k
)
if
(
mtd
->
writesize
>
512
)
/* another col addr cycle for 2k page */
/* another col addr cycle for 2k page */
send_addr
(
host
,
0
,
false
);
send_addr
(
host
,
0
,
false
);
}
}
...
@@ -801,7 +521,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
...
@@ -801,7 +521,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
/* paddr_0 - p_addr_7 */
/* paddr_0 - p_addr_7 */
send_addr
(
host
,
(
page_addr
&
0xff
),
false
);
send_addr
(
host
,
(
page_addr
&
0xff
),
false
);
if
(
host
->
pagesize_2k
)
{
if
(
mtd
->
writesize
>
512
)
{
if
(
mtd
->
size
>=
0x10000000
)
{
if
(
mtd
->
size
>=
0x10000000
)
{
/* paddr_8 - paddr_15 */
/* paddr_8 - paddr_15 */
send_addr
(
host
,
(
page_addr
>>
8
)
&
0xff
,
false
);
send_addr
(
host
,
(
page_addr
>>
8
)
&
0xff
,
false
);
...
@@ -820,43 +540,138 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
...
@@ -820,43 +540,138 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
send_addr
(
host
,
(
page_addr
>>
8
)
&
0xff
,
true
);
send_addr
(
host
,
(
page_addr
>>
8
)
&
0xff
,
true
);
}
}
}
}
}
/* Used by the upper layer to write command to NAND Flash for
* different operations to be carried out on NAND Flash */
static
void
mxc_nand_command
(
struct
mtd_info
*
mtd
,
unsigned
command
,
int
column
,
int
page_addr
)
{
struct
nand_chip
*
nand_chip
=
mtd
->
priv
;
struct
mxc_nand_host
*
host
=
nand_chip
->
priv
;
DEBUG
(
MTD_DEBUG_LEVEL3
,
"mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)
\n
"
,
command
,
column
,
page_addr
);
/* Reset command state information */
host
->
status_request
=
false
;
/* Command p
ost
-processing step */
/* Command p
re
-processing step */
switch
(
command
)
{
switch
(
command
)
{
case
NAND_CMD_RESET
:
case
NAND_CMD_STATUS
:
host
->
buf_start
=
0
;
host
->
status_request
=
true
;
send_cmd
(
host
,
command
,
true
);
mxc_do_addr_cycle
(
mtd
,
column
,
page_addr
);
break
;
break
;
case
NAND_CMD_READOOB
:
case
NAND_CMD_READ0
:
case
NAND_CMD_READ0
:
if
(
host
->
pagesize_2k
)
{
case
NAND_CMD_READOOB
:
/* send read confirm command */
if
(
command
==
NAND_CMD_READ0
)
host
->
buf_start
=
column
;
else
host
->
buf_start
=
column
+
mtd
->
writesize
;
if
(
mtd
->
writesize
>
512
)
command
=
NAND_CMD_READ0
;
/* only READ0 is valid */
send_cmd
(
host
,
command
,
false
);
mxc_do_addr_cycle
(
mtd
,
column
,
page_addr
);
if
(
mtd
->
writesize
>
512
)
send_cmd
(
host
,
NAND_CMD_READSTART
,
true
);
send_cmd
(
host
,
NAND_CMD_READSTART
,
true
);
/* read for each AREA */
send_read_page
(
host
,
0
,
host
->
spare_only
);
send_page
(
mtd
,
NFC_OUTPUT
);
send_read_page
(
host
,
1
,
host
->
spare_only
);
send_read_page
(
host
,
2
,
host
->
spare_only
);
memcpy
(
host
->
data_buf
,
host
->
main_area0
,
mtd
->
writesize
);
send_read_page
(
host
,
3
,
host
->
spare_only
);
copy_spare
(
mtd
,
true
);
}
else
send_read_page
(
host
,
0
,
host
->
spare_only
);
break
;
break
;
case
NAND_CMD_READID
:
case
NAND_CMD_SEQIN
:
host
->
col_addr
=
0
;
if
(
column
>=
mtd
->
writesize
)
{
send_read_id
(
host
);
/*
* FIXME: before send SEQIN command for write OOB,
* We must read one page out.
* For K9F1GXX has no READ1 command to set current HW
* pointer to spare area, we must write the whole page
* including OOB together.
*/
if
(
mtd
->
writesize
>
512
)
/* call ourself to read a page */
mxc_nand_command
(
mtd
,
NAND_CMD_READ0
,
0
,
page_addr
);
host
->
buf_start
=
column
;
/* Set program pointer to spare region */
if
(
mtd
->
writesize
==
512
)
send_cmd
(
host
,
NAND_CMD_READOOB
,
false
);
}
else
{
host
->
buf_start
=
column
;
/* Set program pointer to page start */
if
(
mtd
->
writesize
==
512
)
send_cmd
(
host
,
NAND_CMD_READ0
,
false
);
}
send_cmd
(
host
,
command
,
false
);
mxc_do_addr_cycle
(
mtd
,
column
,
page_addr
);
break
;
break
;
case
NAND_CMD_PAGEPROG
:
case
NAND_CMD_PAGEPROG
:
memcpy
(
host
->
main_area0
,
host
->
data_buf
,
mtd
->
writesize
);
copy_spare
(
mtd
,
false
);
send_page
(
mtd
,
NFC_INPUT
);
send_cmd
(
host
,
command
,
true
);
mxc_do_addr_cycle
(
mtd
,
column
,
page_addr
);
break
;
break
;
case
NAND_CMD_STATUS
:
case
NAND_CMD_READID
:
send_cmd
(
host
,
command
,
true
);
mxc_do_addr_cycle
(
mtd
,
column
,
page_addr
);
send_read_id
(
host
);
host
->
buf_start
=
column
;
break
;
break
;
case
NAND_CMD_ERASE1
:
case
NAND_CMD_ERASE2
:
case
NAND_CMD_ERASE2
:
send_cmd
(
host
,
command
,
false
);
mxc_do_addr_cycle
(
mtd
,
column
,
page_addr
);
break
;
break
;
}
}
}
}
/*
* The generic flash bbt decriptors overlap with our ecc
* hardware, so define some i.MX specific ones.
*/
static
uint8_t
bbt_pattern
[]
=
{
'B'
,
'b'
,
't'
,
'0'
};
static
uint8_t
mirror_pattern
[]
=
{
'1'
,
't'
,
'b'
,
'B'
};
static
struct
nand_bbt_descr
bbt_main_descr
=
{
.
options
=
NAND_BBT_LASTBLOCK
|
NAND_BBT_CREATE
|
NAND_BBT_WRITE
|
NAND_BBT_2BIT
|
NAND_BBT_VERSION
|
NAND_BBT_PERCHIP
,
.
offs
=
0
,
.
len
=
4
,
.
veroffs
=
4
,
.
maxblocks
=
4
,
.
pattern
=
bbt_pattern
,
};
static
struct
nand_bbt_descr
bbt_mirror_descr
=
{
.
options
=
NAND_BBT_LASTBLOCK
|
NAND_BBT_CREATE
|
NAND_BBT_WRITE
|
NAND_BBT_2BIT
|
NAND_BBT_VERSION
|
NAND_BBT_PERCHIP
,
.
offs
=
0
,
.
len
=
4
,
.
veroffs
=
4
,
.
maxblocks
=
4
,
.
pattern
=
mirror_pattern
,
};
static
int
__init
mxcnd_probe
(
struct
platform_device
*
pdev
)
static
int
__init
mxcnd_probe
(
struct
platform_device
*
pdev
)
{
{
struct
nand_chip
*
this
;
struct
nand_chip
*
this
;
...
@@ -866,12 +681,16 @@ static int __init mxcnd_probe(struct platform_device *pdev)
...
@@ -866,12 +681,16 @@ static int __init mxcnd_probe(struct platform_device *pdev)
struct
resource
*
res
;
struct
resource
*
res
;
uint16_t
tmp
;
uint16_t
tmp
;
int
err
=
0
,
nr_parts
=
0
;
int
err
=
0
,
nr_parts
=
0
;
struct
nand_ecclayout
*
oob_smallpage
,
*
oob_largepage
;
/* Allocate memory for MTD device structure and private data */
/* Allocate memory for MTD device structure and private data */
host
=
kzalloc
(
sizeof
(
struct
mxc_nand_host
),
GFP_KERNEL
);
host
=
kzalloc
(
sizeof
(
struct
mxc_nand_host
)
+
NAND_MAX_PAGESIZE
+
NAND_MAX_OOBSIZE
,
GFP_KERNEL
);
if
(
!
host
)
if
(
!
host
)
return
-
ENOMEM
;
return
-
ENOMEM
;
host
->
data_buf
=
(
uint8_t
*
)(
host
+
1
);
host
->
dev
=
&
pdev
->
dev
;
host
->
dev
=
&
pdev
->
dev
;
/* structures must be linked */
/* structures must be linked */
this
=
&
host
->
nand
;
this
=
&
host
->
nand
;
...
@@ -879,7 +698,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
...
@@ -879,7 +698,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
mtd
->
priv
=
this
;
mtd
->
priv
=
this
;
mtd
->
owner
=
THIS_MODULE
;
mtd
->
owner
=
THIS_MODULE
;
mtd
->
dev
.
parent
=
&
pdev
->
dev
;
mtd
->
dev
.
parent
=
&
pdev
->
dev
;
mtd
->
name
=
"mxc_nand"
;
mtd
->
name
=
DRIVER_NAME
;
/* 50 us command delay time */
/* 50 us command delay time */
this
->
chip_delay
=
5
;
this
->
chip_delay
=
5
;
...
@@ -909,62 +728,93 @@ static int __init mxcnd_probe(struct platform_device *pdev)
...
@@ -909,62 +728,93 @@ static int __init mxcnd_probe(struct platform_device *pdev)
goto
eres
;
goto
eres
;
}
}
host
->
regs
=
ioremap
(
res
->
start
,
res
->
end
-
res
->
start
+
1
);
host
->
base
=
ioremap
(
res
->
start
,
resource_size
(
res
)
);
if
(
!
host
->
regs
)
{
if
(
!
host
->
base
)
{
err
=
-
ENOMEM
;
err
=
-
ENOMEM
;
goto
eres
;
goto
eres
;
}
}
host
->
main_area0
=
host
->
base
;
host
->
main_area1
=
host
->
base
+
0x200
;
if
(
nfc_is_v21
())
{
host
->
regs
=
host
->
base
+
0x1000
;
host
->
spare0
=
host
->
base
+
0x1000
;
host
->
spare_len
=
64
;
oob_smallpage
=
&
nandv2_hw_eccoob_smallpage
;
oob_largepage
=
&
nandv2_hw_eccoob_largepage
;
}
else
if
(
nfc_is_v1
())
{
host
->
regs
=
host
->
base
;
host
->
spare0
=
host
->
base
+
0x800
;
host
->
spare_len
=
16
;
oob_smallpage
=
&
nandv1_hw_eccoob_smallpage
;
oob_largepage
=
&
nandv1_hw_eccoob_largepage
;
}
else
BUG
();
/* disable interrupt and spare enable */
tmp
=
readw
(
host
->
regs
+
NFC_CONFIG1
);
tmp
=
readw
(
host
->
regs
+
NFC_CONFIG1
);
tmp
|=
NFC_INT_MSK
;
tmp
|=
NFC_INT_MSK
;
tmp
&=
~
NFC_SP_EN
;
writew
(
tmp
,
host
->
regs
+
NFC_CONFIG1
);
writew
(
tmp
,
host
->
regs
+
NFC_CONFIG1
);
init_waitqueue_head
(
&
host
->
irq_waitq
);
init_waitqueue_head
(
&
host
->
irq_waitq
);
host
->
irq
=
platform_get_irq
(
pdev
,
0
);
host
->
irq
=
platform_get_irq
(
pdev
,
0
);
err
=
request_irq
(
host
->
irq
,
mxc_nfc_irq
,
0
,
"mxc_nd"
,
host
);
err
=
request_irq
(
host
->
irq
,
mxc_nfc_irq
,
0
,
DRIVER_NAME
,
host
);
if
(
err
)
if
(
err
)
goto
eirq
;
goto
eirq
;
/* Reset NAND */
this
->
cmdfunc
(
mtd
,
NAND_CMD_RESET
,
-
1
,
-
1
);
/* preset operation */
/* Unlock the internal RAM Buffer */
writew
(
0x2
,
host
->
regs
+
NFC_CONFIG
);
/* Blocks to be unlocked */
if
(
nfc_is_v21
())
{
writew
(
0x0
,
host
->
regs
+
NFC_V21_UNLOCKSTART_BLKADDR
);
writew
(
0xffff
,
host
->
regs
+
NFC_V21_UNLOCKEND_BLKADDR
);
this
->
ecc
.
bytes
=
9
;
}
else
if
(
nfc_is_v1
())
{
writew
(
0x0
,
host
->
regs
+
NFC_V1_UNLOCKSTART_BLKADDR
);
writew
(
0x4000
,
host
->
regs
+
NFC_V1_UNLOCKEND_BLKADDR
);
this
->
ecc
.
bytes
=
3
;
}
else
BUG
();
/* Unlock Block Command for given address range */
writew
(
0x4
,
host
->
regs
+
NFC_WRPROT
);
this
->
ecc
.
size
=
512
;
this
->
ecc
.
layout
=
oob_smallpage
;
if
(
pdata
->
hw_ecc
)
{
if
(
pdata
->
hw_ecc
)
{
this
->
ecc
.
calculate
=
mxc_nand_calculate_ecc
;
this
->
ecc
.
calculate
=
mxc_nand_calculate_ecc
;
this
->
ecc
.
hwctl
=
mxc_nand_enable_hwecc
;
this
->
ecc
.
hwctl
=
mxc_nand_enable_hwecc
;
this
->
ecc
.
correct
=
mxc_nand_correct_data
;
this
->
ecc
.
correct
=
mxc_nand_correct_data
;
this
->
ecc
.
mode
=
NAND_ECC_HW
;
this
->
ecc
.
mode
=
NAND_ECC_HW
;
this
->
ecc
.
size
=
512
;
this
->
ecc
.
bytes
=
3
;
tmp
=
readw
(
host
->
regs
+
NFC_CONFIG1
);
tmp
=
readw
(
host
->
regs
+
NFC_CONFIG1
);
tmp
|=
NFC_ECC_EN
;
tmp
|=
NFC_ECC_EN
;
writew
(
tmp
,
host
->
regs
+
NFC_CONFIG1
);
writew
(
tmp
,
host
->
regs
+
NFC_CONFIG1
);
}
else
{
}
else
{
this
->
ecc
.
size
=
512
;
this
->
ecc
.
bytes
=
3
;
this
->
ecc
.
layout
=
&
nand_hw_eccoob_8
;
this
->
ecc
.
mode
=
NAND_ECC_SOFT
;
this
->
ecc
.
mode
=
NAND_ECC_SOFT
;
tmp
=
readw
(
host
->
regs
+
NFC_CONFIG1
);
tmp
=
readw
(
host
->
regs
+
NFC_CONFIG1
);
tmp
&=
~
NFC_ECC_EN
;
tmp
&=
~
NFC_ECC_EN
;
writew
(
tmp
,
host
->
regs
+
NFC_CONFIG1
);
writew
(
tmp
,
host
->
regs
+
NFC_CONFIG1
);
}
}
/* Reset NAND */
this
->
cmdfunc
(
mtd
,
NAND_CMD_RESET
,
-
1
,
-
1
);
/* preset operation */
/* Unlock the internal RAM Buffer */
writew
(
0x2
,
host
->
regs
+
NFC_CONFIG
);
/* Blocks to be unlocked */
writew
(
0x0
,
host
->
regs
+
NFC_UNLOCKSTART_BLKADDR
);
writew
(
0x4000
,
host
->
regs
+
NFC_UNLOCKEND_BLKADDR
);
/* Unlock Block Command for given address range */
writew
(
0x4
,
host
->
regs
+
NFC_WRPROT
);
/* NAND bus width determines access funtions used by upper layer */
/* NAND bus width determines access funtions used by upper layer */
if
(
pdata
->
width
==
2
)
{
if
(
pdata
->
width
==
2
)
this
->
options
|=
NAND_BUSWIDTH_16
;
this
->
options
|=
NAND_BUSWIDTH_16
;
this
->
ecc
.
layout
=
&
nand_hw_eccoob_16
;
if
(
pdata
->
flash_bbt
)
{
this
->
bbt_td
=
&
bbt_main_descr
;
this
->
bbt_md
=
&
bbt_mirror_descr
;
/* update flash based bbt */
this
->
options
|=
NAND_USE_FLASH_BBT
;
}
}
/* first scan to find the device and get the page size */
/* first scan to find the device and get the page size */
...
@@ -973,35 +823,8 @@ static int __init mxcnd_probe(struct platform_device *pdev)
...
@@ -973,35 +823,8 @@ static int __init mxcnd_probe(struct platform_device *pdev)
goto
escan
;
goto
escan
;
}
}
host
->
pagesize_2k
=
(
mtd
->
writesize
==
2048
)
?
1
:
0
;
if
(
mtd
->
writesize
==
2048
)
this
->
ecc
.
layout
=
oob_largepage
;
if
(
this
->
ecc
.
mode
==
NAND_ECC_HW
)
{
switch
(
mtd
->
oobsize
)
{
case
8
:
this
->
ecc
.
layout
=
&
nand_hw_eccoob_8
;
break
;
case
16
:
this
->
ecc
.
layout
=
&
nand_hw_eccoob_16
;
break
;
case
64
:
this
->
ecc
.
layout
=
&
nand_hw_eccoob_64
;
break
;
default:
/* page size not handled by HW ECC */
/* switching back to soft ECC */
this
->
ecc
.
size
=
512
;
this
->
ecc
.
bytes
=
3
;
this
->
ecc
.
layout
=
&
nand_hw_eccoob_8
;
this
->
ecc
.
mode
=
NAND_ECC_SOFT
;
this
->
ecc
.
calculate
=
NULL
;
this
->
ecc
.
correct
=
NULL
;
this
->
ecc
.
hwctl
=
NULL
;
tmp
=
readw
(
host
->
regs
+
NFC_CONFIG1
);
tmp
&=
~
NFC_ECC_EN
;
writew
(
tmp
,
host
->
regs
+
NFC_CONFIG1
);
break
;
}
}
/* second phase scan */
/* second phase scan */
if
(
nand_scan_tail
(
mtd
))
{
if
(
nand_scan_tail
(
mtd
))
{
...
@@ -1029,7 +852,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
...
@@ -1029,7 +852,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
escan:
escan:
free_irq
(
host
->
irq
,
host
);
free_irq
(
host
->
irq
,
host
);
eirq:
eirq:
iounmap
(
host
->
regs
);
iounmap
(
host
->
base
);
eres:
eres:
clk_put
(
host
->
clk
);
clk_put
(
host
->
clk
);
eclk:
eclk:
...
@@ -1048,7 +871,7 @@ static int __exit mxcnd_remove(struct platform_device *pdev)
...
@@ -1048,7 +871,7 @@ static int __exit mxcnd_remove(struct platform_device *pdev)
nand_release
(
&
host
->
mtd
);
nand_release
(
&
host
->
mtd
);
free_irq
(
host
->
irq
,
host
);
free_irq
(
host
->
irq
,
host
);
iounmap
(
host
->
regs
);
iounmap
(
host
->
base
);
kfree
(
host
);
kfree
(
host
);
return
0
;
return
0
;
...
...
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