Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
mtd
nand
ndfc.c
Go to the documentation of this file.
1
/*
2
* drivers/mtd/ndfc.c
3
*
4
* Overview:
5
* Platform independent driver for NDFC (NanD Flash Controller)
6
* integrated into EP440 cores
7
*
8
* Ported to an OF platform driver by Sean MacLennan
9
*
10
* The NDFC supports multiple chips, but this driver only supports a
11
* single chip since I do not have access to any boards with
12
* multiple chips.
13
*
14
* Author: Thomas Gleixner
15
*
16
* Copyright 2006 IBM
17
* Copyright 2008 PIKA Technologies
18
* Sean MacLennan <
[email protected]
>
19
*
20
* This program is free software; you can redistribute it and/or modify it
21
* under the terms of the GNU General Public License as published by the
22
* Free Software Foundation; either version 2 of the License, or (at your
23
* option) any later version.
24
*
25
*/
26
#include <linux/module.h>
27
#include <
linux/mtd/nand.h
>
28
#include <
linux/mtd/nand_ecc.h
>
29
#include <
linux/mtd/partitions.h
>
30
#include <
linux/mtd/ndfc.h
>
31
#include <linux/slab.h>
32
#include <
linux/mtd/mtd.h
>
33
#include <
linux/of_platform.h
>
34
#include <asm/io.h>
35
36
#define NDFC_MAX_CS 4
37
38
struct
ndfc_controller
{
39
struct
platform_device
*
ofdev
;
40
void
__iomem
*
ndfcbase
;
41
struct
mtd_info
mtd
;
42
struct
nand_chip
chip
;
43
int
chip_select
;
44
struct
nand_hw_control
ndfc_control
;
45
};
46
47
static
struct
ndfc_controller
ndfc_ctrl[
NDFC_MAX_CS
];
48
49
static
void
ndfc_select_chip(
struct
mtd_info
*
mtd
,
int
chip
)
50
{
51
uint32_t
ccr
;
52
struct
nand_chip
*nchip = mtd->
priv
;
53
struct
ndfc_controller
*ndfc = nchip->
priv
;
54
55
ccr =
in_be32
(ndfc->
ndfcbase
+
NDFC_CCR
);
56
if
(chip >= 0) {
57
ccr &= ~
NDFC_CCR_BS_MASK
;
58
ccr |=
NDFC_CCR_BS
(chip + ndfc->
chip_select
);
59
}
else
60
ccr |=
NDFC_CCR_RESET_CE
;
61
out_be32
(ndfc->
ndfcbase
+
NDFC_CCR
, ccr);
62
}
63
64
static
void
ndfc_hwcontrol(
struct
mtd_info
*mtd,
int
cmd
,
unsigned
int
ctrl
)
65
{
66
struct
nand_chip
*chip = mtd->
priv
;
67
struct
ndfc_controller
*ndfc = chip->
priv
;
68
69
if
(cmd ==
NAND_CMD_NONE
)
70
return
;
71
72
if
(ctrl &
NAND_CLE
)
73
writel
(cmd & 0xFF, ndfc->
ndfcbase
+
NDFC_CMD
);
74
else
75
writel
(cmd & 0xFF, ndfc->
ndfcbase
+
NDFC_ALE
);
76
}
77
78
static
int
ndfc_ready(
struct
mtd_info
*mtd)
79
{
80
struct
nand_chip
*chip = mtd->
priv
;
81
struct
ndfc_controller
*ndfc = chip->
priv
;
82
83
return
in_be32
(ndfc->
ndfcbase
+
NDFC_STAT
) &
NDFC_STAT_IS_READY
;
84
}
85
86
static
void
ndfc_enable_hwecc(
struct
mtd_info
*mtd,
int
mode
)
87
{
88
uint32_t
ccr
;
89
struct
nand_chip
*chip = mtd->
priv
;
90
struct
ndfc_controller
*ndfc = chip->
priv
;
91
92
ccr =
in_be32
(ndfc->
ndfcbase
+
NDFC_CCR
);
93
ccr |=
NDFC_CCR_RESET_ECC
;
94
out_be32
(ndfc->
ndfcbase
+
NDFC_CCR
, ccr);
95
wmb
();
96
}
97
98
static
int
ndfc_calculate_ecc(
struct
mtd_info
*mtd,
99
const
u_char
*
dat
,
u_char
*ecc_code)
100
{
101
struct
nand_chip
*chip = mtd->
priv
;
102
struct
ndfc_controller
*ndfc = chip->
priv
;
103
uint32_t
ecc
;
104
uint8_t
*
p
= (
uint8_t
*)&ecc;
105
106
wmb
();
107
ecc =
in_be32
(ndfc->
ndfcbase
+
NDFC_ECC
);
108
/* The NDFC uses Smart Media (SMC) bytes order */
109
ecc_code[0] = p[1];
110
ecc_code[1] = p[2];
111
ecc_code[2] = p[3];
112
113
return
0;
114
}
115
116
/*
117
* Speedups for buffer read/write/verify
118
*
119
* NDFC allows 32bit read/write of data. So we can speed up the buffer
120
* functions. No further checking, as nand_base will always read/write
121
* page aligned.
122
*/
123
static
void
ndfc_read_buf(
struct
mtd_info
*mtd,
uint8_t
*
buf
,
int
len)
124
{
125
struct
nand_chip
*chip = mtd->
priv
;
126
struct
ndfc_controller
*ndfc = chip->
priv
;
127
uint32_t
*
p
= (
uint32_t
*) buf;
128
129
for
(;len > 0; len -= 4)
130
*p++ =
in_be32
(ndfc->
ndfcbase
+
NDFC_DATA
);
131
}
132
133
static
void
ndfc_write_buf(
struct
mtd_info
*mtd,
const
uint8_t
*buf,
int
len)
134
{
135
struct
nand_chip
*chip = mtd->
priv
;
136
struct
ndfc_controller
*ndfc = chip->
priv
;
137
uint32_t
*p = (
uint32_t
*) buf;
138
139
for
(;len > 0; len -= 4)
140
out_be32
(ndfc->
ndfcbase
+
NDFC_DATA
, *p++);
141
}
142
143
/*
144
* Initialize chip structure
145
*/
146
static
int
ndfc_chip_init(
struct
ndfc_controller
*ndfc,
147
struct
device_node
*
node
)
148
{
149
struct
device_node
*flash_np;
150
struct
nand_chip
*chip = &ndfc->
chip
;
151
struct
mtd_part_parser_data
ppdata
;
152
int
ret
;
153
154
chip->
IO_ADDR_R
= ndfc->
ndfcbase
+
NDFC_DATA
;
155
chip->
IO_ADDR_W
= ndfc->
ndfcbase
+
NDFC_DATA
;
156
chip->
cmd_ctrl
= ndfc_hwcontrol;
157
chip->
dev_ready
= ndfc_ready;
158
chip->
select_chip
= ndfc_select_chip;
159
chip->
chip_delay
= 50;
160
chip->
controller
= &ndfc->
ndfc_control
;
161
chip->
read_buf
= ndfc_read_buf;
162
chip->
write_buf
= ndfc_write_buf;
163
chip->
ecc
.correct =
nand_correct_data
;
164
chip->
ecc
.hwctl = ndfc_enable_hwecc;
165
chip->
ecc
.calculate = ndfc_calculate_ecc;
166
chip->
ecc
.mode =
NAND_ECC_HW
;
167
chip->
ecc
.size = 256;
168
chip->
ecc
.bytes = 3;
169
chip->
ecc
.strength = 1;
170
chip->
priv
= ndfc;
171
172
ndfc->
mtd
.priv =
chip
;
173
ndfc->
mtd
.owner =
THIS_MODULE
;
174
175
flash_np =
of_get_next_child
(node,
NULL
);
176
if
(!flash_np)
177
return
-
ENODEV
;
178
179
ppdata
.of_node = flash_np;
180
ndfc->
mtd
.name =
kasprintf
(
GFP_KERNEL
,
"%s.%s"
,
181
dev_name(&ndfc->
ofdev
->dev), flash_np->
name
);
182
if
(!ndfc->
mtd
.name) {
183
ret = -
ENOMEM
;
184
goto
err
;
185
}
186
187
ret =
nand_scan
(&ndfc->
mtd
, 1);
188
if
(ret)
189
goto
err
;
190
191
ret =
mtd_device_parse_register
(&ndfc->
mtd
,
NULL
, &
ppdata
,
NULL
, 0);
192
193
err
:
194
of_node_put(flash_np);
195
if
(ret)
196
kfree
(ndfc->
mtd
.name);
197
return
ret
;
198
}
199
200
static
int
__devinit
ndfc_probe(
struct
platform_device
*ofdev)
201
{
202
struct
ndfc_controller
*ndfc;
203
const
__be32
*
reg
;
204
u32
ccr
;
205
int
err
, len,
cs
;
206
207
/* Read the reg property to get the chip select */
208
reg =
of_get_property
(ofdev->
dev
.of_node,
"reg"
, &len);
209
if
(reg ==
NULL
|| len != 12) {
210
dev_err
(&ofdev->
dev
,
"unable read reg property (%d)\n"
, len);
211
return
-
ENOENT
;
212
}
213
214
cs =
be32_to_cpu
(reg[0]);
215
if
(cs >=
NDFC_MAX_CS
) {
216
dev_err
(&ofdev->
dev
,
"invalid CS number (%d)\n"
, cs);
217
return
-
EINVAL
;
218
}
219
220
ndfc = &ndfc_ctrl[
cs
];
221
ndfc->
chip_select
=
cs
;
222
223
spin_lock_init
(&ndfc->
ndfc_control
.lock);
224
init_waitqueue_head
(&ndfc->
ndfc_control
.wq);
225
ndfc->
ofdev
=
ofdev
;
226
dev_set_drvdata
(&ofdev->
dev
, ndfc);
227
228
ndfc->
ndfcbase
=
of_iomap
(ofdev->
dev
.of_node, 0);
229
if
(!ndfc->
ndfcbase
) {
230
dev_err
(&ofdev->
dev
,
"failed to get memory\n"
);
231
return
-
EIO
;
232
}
233
234
ccr =
NDFC_CCR_BS
(ndfc->
chip_select
);
235
236
/* It is ok if ccr does not exist - just default to 0 */
237
reg =
of_get_property
(ofdev->
dev
.of_node,
"ccr"
,
NULL
);
238
if
(reg)
239
ccr |=
be32_to_cpup
(reg);
240
241
out_be32
(ndfc->
ndfcbase
+
NDFC_CCR
, ccr);
242
243
/* Set the bank settings if given */
244
reg =
of_get_property
(ofdev->
dev
.of_node,
"bank-settings"
,
NULL
);
245
if
(reg) {
246
int
offset
=
NDFC_BCFG0
+ (ndfc->
chip_select
<< 2);
247
out_be32
(ndfc->
ndfcbase
+ offset,
be32_to_cpup
(reg));
248
}
249
250
err = ndfc_chip_init(ndfc, ofdev->
dev
.of_node);
251
if
(err) {
252
iounmap
(ndfc->
ndfcbase
);
253
return
err
;
254
}
255
256
return
0;
257
}
258
259
static
int
__devexit
ndfc_remove(
struct
platform_device
*ofdev)
260
{
261
struct
ndfc_controller
*ndfc =
dev_get_drvdata
(&ofdev->
dev
);
262
263
nand_release
(&ndfc->
mtd
);
264
kfree
(ndfc->
mtd
.name);
265
266
return
0;
267
}
268
269
static
const
struct
of_device_id
ndfc_match[] = {
270
{ .compatible =
"ibm,ndfc"
, },
271
{}
272
};
273
MODULE_DEVICE_TABLE
(of, ndfc_match);
274
275
static
struct
platform_driver
ndfc_driver = {
276
.driver = {
277
.name =
"ndfc"
,
278
.owner =
THIS_MODULE
,
279
.of_match_table = ndfc_match,
280
},
281
.probe = ndfc_probe,
282
.remove =
__devexit_p
(ndfc_remove),
283
};
284
285
module_platform_driver
(ndfc_driver);
286
287
MODULE_LICENSE
(
"GPL"
);
288
MODULE_AUTHOR
(
"Thomas Gleixner <
[email protected]
>"
);
289
MODULE_DESCRIPTION
(
"OF Platform driver for NDFC"
);
Generated on Thu Jan 10 2013 13:57:01 for Linux Kernel by
1.8.2