1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
|
/*
* Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface)
*
* Author: dmitry pervushin <dimka@embeddedalley.com>
*
* Copyright 2008-2010 Freescale Semiconductor, Inc.
* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#ifndef __DRIVERS_GPMI_H
#define __DRIVERS_GPMI_H
#include <linux/mtd/partitions.h>
#include <linux/timer.h>
#include <mach/dmaengine.h>
#include "regs-gpmi.h"
#include "regs-bch.h"
#include "../nand_device_info.h"
/* The number of DMA descriptors we need to allocate. */
#define DMA_DESCRIPTOR_COUNT (4)
#define NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES (512)
#define NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES \
((((NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES*8)/16)*6)/8)
#define NAND_HC_ECC_OFFSET_FIRST_DATA_COPY (0)
#define NAND_HC_ECC_OFFSET_SECOND_DATA_COPY \
(NAND_HC_ECC_OFFSET_FIRST_DATA_COPY + \
NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES)
#define NAND_HC_ECC_OFFSET_THIRD_DATA_COPY \
(NAND_HC_ECC_OFFSET_SECOND_DATA_COPY + \
NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES)
#define NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY \
(NAND_HC_ECC_OFFSET_THIRD_DATA_COPY + \
NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES)
#define NAND_HC_ECC_OFFSET_SECOND_PARITY_COPY \
(NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY + \
NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES)
#define NAND_HC_ECC_OFFSET_THIRD_PARITY_COPY \
(NAND_HC_ECC_OFFSET_SECOND_PARITY_COPY + \
NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES)
/**
* struct gpmi_nand_timing - NAND Flash timing parameters.
*
* This structure contains the fundamental timing attributes for the NAND Flash
* bus.
*
* @data_setup_in_ns: The data setup time, in nanoseconds. Usually the
* maximum of tDS and tWP. A negative value
* indicates this characteristic isn't known.
* @data_hold_in_ns: The data hold time, in nanoseconds. Usually the
* maximum of tDH, tWH and tREH. A negative value
* indicates this characteristic isn't known.
* @address_setup_in_ns: The address setup time, in nanoseconds. Usually
* the maximum of tCLS, tCS and tALS. A negative
* value indicates this characteristic isn't known.
* @gpmi_sample_time_in_ns: A GPMI-specific timing parameter. A negative
* value indicates this characteristic isn't known.
* @tREA_in_ns: tREA, in nanoseconds, from the data sheet. A
* negative value indicates this characteristic
* isn't known.
* @tRLOH_in_ns: tRLOH, in nanoseconds, from the data sheet. A
* negative value indicates this characteristic
* isn't known.
* @tRHOH_in_ns: tRHOH, in nanoseconds, from the data sheet. A
* negative value indicates this characteristic
* isn't known.
*/
struct gpmi_nand_timing {
int8_t data_setup_in_ns;
int8_t data_hold_in_ns;
int8_t address_setup_in_ns;
int8_t gpmi_sample_delay_in_ns;
int8_t tREA_in_ns;
int8_t tRLOH_in_ns;
int8_t tRHOH_in_ns;
};
/**
* struct gpmi_bcb_info - Information obtained from Boot Control Blocks.
*
* @timing: Timing values extracted from an NCB.
* @ncbblock: The offset within the MTD at which the NCB was found.
* @pre_ncb:
* @pre_ncb_size:
*/
struct gpmi_bcb_info {
struct gpmi_nand_timing timing;
loff_t ncbblock;
const void *pre_ncb;
size_t pre_ncb_size;
};
struct gpmi_ncb;
int gpmi_erase(struct mtd_info *mtd, struct erase_info *instr);
int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs);
int gpmi_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip);
int gpmi_scan_bbt(struct mtd_info *mtd);
int gpmi_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip);
#ifdef CONFIG_MTD_NAND_GPMI_SYSFS_ENTRIES
int gpmi_sysfs(struct platform_device *p, int create);
#endif
int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page, int sndcmd);
int gpmi_write_ncb(struct mtd_info *mtd, struct gpmi_bcb_info *b);
unsigned gpmi_hamming_ecc_size_22_16(int block_size);
void gpmi_encode_hamming_ncb_22_16(void *source_block, size_t source_size,
void *target_block, size_t target_size);
void gpmi_encode_hamming_22_16(void *source_block, size_t src_size,
void *source_ecc, size_t ecc_size);
int gpmi_verify_hamming_22_16(void *data, u8 *parity, size_t size);
unsigned gpmi_hamming_ecc_size_13_8(int block_size);
void gpmi_encode_hamming_ncb_13_8(void *source_block, size_t source_size,
void *target_block, size_t target_size);
void gpmi_encode_hamming_13_8(void *source_block, size_t src_size,
void *source_ecc, size_t ecc_size);
int gpmi_verify_hamming_13_8(void *data, u8 *parity, size_t size);
#define GPMI_DMA_MAX_CHAIN 20 /* max DMA commands in chain */
/*
* Sizes of data buffers to exchange commands/data with NAND chip.
* Default values cover 4K NAND page (4096 data bytes + 218 bytes OOB)
*/
#define GPMI_CMD_BUF_SZ 10
#define GPMI_DATA_BUF_SZ NAND_MAX_PAGESIZE
#define GPMI_WRITE_BUF_SZ NAND_MAX_PAGESIZE
#define GPMI_OOB_BUF_SZ NAND_MAX_OOBSIZE
#define GPMI_MAX_CHIPS 10
/**
* struct gpmi_ecc_descriptor - Abstract description of ECC.
*
* @name: The name of the ECC represented by this structure.
* @list: Infrastructure for the list to which this structure belongs.
* @setup: A pointer to a function that prepares the ECC to function.
* @reset: A pointer to a function that resets the ECC to a known state. This
* pointer is currently never used, and probably should be removed.
* @read: A pointer to a function that fills in a given DMA chain such that
* a page read will pass through the owning ECC.
* @write: A pointer to a function that fills in a given DMA chain such that
* a page write will pass through the owning ECC.
* @stat: A pointer to a function that reports on ECC statistics for
* the preceding read operation.
*/
struct gpmi_ecc_descriptor {
char name[40];
struct list_head list;
int (*setup)(void *ctx, int index, int writesize, int oobsize);
int (*reset)(void *ctx, int index);
int (*read)(void *ctx, int index,
struct mxs_dma_desc *chain[], unsigned channel,
dma_addr_t page, dma_addr_t oob);
int (*write)(void *ctx, int index,
struct mxs_dma_desc *chain[], unsigned channel,
dma_addr_t page, dma_addr_t oob);
int (*stat)(void *ctx, int index, struct mtd_ecc_stats *r);
};
/* ECC descriptor management. */
struct gpmi_ecc_descriptor *gpmi_ecc_find(char *name);
void gpmi_ecc_add(struct gpmi_ecc_descriptor *chip);
void gpmi_ecc_remove(struct gpmi_ecc_descriptor *chip);
/* Housecleaning functions for the ECC hardware blocks. */
int bch_init(void);
int ecc8_init(void);
void bch_exit(void);
void ecc8_exit(void);
/**
* struct gpmi_nand_data - GPMI driver per-device data structure.
*
* @dev: A pointer to the owning struct device.
* @gpd: GPMI-specific platform data.
* @io_base: The base I/O address of of the GPMI registers.
* @clk: A pointer to the structure that represents the GPMI
* clock.
* @irq: The GPMI interrupt request number.
* @inactivity_timer: A pointer to a timer the driver uses to shut itself
* down after periods of inactivity.
* @self_suspended: Indicates the driver suspended itself, rather than
* being suspended by higher layers of software. This is
* important because it effects how the driver wakes
* itself back up.
* @use_count: Used within the driver to hold off suspension until
* all operations are complete.
* @regulator: A pointer to the structure that represents the
* power regulator supplying power to the GPMI.
* @reg_uA: The GPMI current limit, in uA.
* @ignorebad: Forces the driver to report that all blocks are good.
* @bbt: Used to save a pointer to the in-memory NAND Flash MTD
* Bad Block Table if the "ignorebad" flag is turned on
* through the corresponding sysfs node.
* @mtd: The data structure that represents this NAND Flash
* medium to MTD.
* @nand: The data structure that represents this NAND Flash
* medium to the MTD NAND Flash system.
* @device_info Detailed information about the NAND Flash device.
* @partitions: A pointer to an array of partition descriptions
* collected from the platform. If this member is NULL,
* then no such partitions were given.
* @partition_count: The number of elements in the partitions array.
* @done: A struct completion used to manage GPMI interrupts.
* @cmd_buffer:
* @cmd_buffer_handle:
* @cmd_buffer_size:
* @cmd_buffer_sz: The number of command and address bytes queued up,
* waiting for transmission to the NAND Flash.
* @write_buffer:
* @write_buffer_handle:
* @write_buffer_size:
* @read_buffer:
* @read_buffer_handle:
* @data_buffer:
* @data_buffer_handle:
* @data_buffer_size:
* @oob_buffer:
* @oob_buffer_handle:
* @oob_buffer_size:
* @verify_buffer:
* @dma_descriptors: An array of DMA descriptors used in I/O operations.
* @chips: An array of data structures, one for each physical
* chip.
* @cchip: A pointer to the element within the chips array that
* represents the currently selected chip.
* @selected_chip: The currently selectd chip number, or -1 if no chip
* is selected.
* @hwecc_type_read:
* @hwecc_type_write:
* @hwecc: Never used.
* @ecc_oob_bytes: The number of ECC bytes covering the OOB bytes alone.
* @oob_free: The total number of OOB bytes.
* @transcribe_bbmark: Used by the bad block management code to indicate
* that the medium is in common format and the bad block
* marks must be transcribed.
* @timing: The current timings installed in the hardware.
* @saved_command: Used to "hook" the NAND Flash MTD default
* implementation for the cmdfunc fuction pointer.
* @raw_oob_mode:
* @saved_read_oob: Used to "hook" the NAND Flash MTD interface function
* for the MTD read_oob fuction pointer.
* @saved_write_oob: Used to "hook" the NAND Flash MTD interface function
* for the MTD write_oob fuction pointer.
* @hc: A pointer to a structure that represents the ECC
* in use.
*/
struct gpmi_nand_data {
struct platform_device *dev;
struct gpmi_platform_data *gpd;
void __iomem *io_base;
struct clk *clk;
int irq;
struct timer_list timer;
int self_suspended;
int use_count;
struct regulator *regulator;
int reg_uA;
int ignorebad;
void *bbt;
struct mtd_info mtd;
struct nand_chip nand;
struct nand_device_info device_info;
unsigned last_write_page_address;
#if defined(CONFIG_MTD_PARTITIONS)
struct mtd_info *general_use_mtd;
struct mtd_partition *partitions;
unsigned partition_count;
#endif
struct completion done;
u8 *cmd_buffer;
dma_addr_t cmd_buffer_handle;
int cmd_buffer_size, cmd_buffer_sz;
u8 *write_buffer;
dma_addr_t write_buffer_handle;
int write_buffer_size;
u8 *read_buffer; /* point in write_buffer */
dma_addr_t read_buffer_handle;
u8 *data_buffer;
dma_addr_t data_buffer_handle;
int data_buffer_size;
u8 *oob_buffer;
dma_addr_t oob_buffer_handle;
int oob_buffer_size;
void *verify_buffer;
struct mxs_dma_desc *dma_descriptors[DMA_DESCRIPTOR_COUNT];
struct nchip {
int cs;
unsigned dma_ch;
struct mxs_dma_desc *d[GPMI_DMA_MAX_CHAIN];
} chips[GPMI_MAX_CHIPS];
struct nchip *cchip;
int selected_chip;
int hwecc;
int ecc_oob_bytes, oob_free;
struct gpmi_nand_timing timing;
void (*saved_command)(struct mtd_info *mtd, unsigned int command,
int column, int page_addr);
int raw_oob_mode;
int (*saved_read_oob)(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops);
int (*saved_write_oob)(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops);
struct gpmi_ecc_descriptor *hc;
};
extern struct gpmi_nand_timing gpmi_safe_timing;
/**
* struct gpmi_ncb -
*
* @fingerprint1:
* @timing:
* @pagesize:
* @page_plus_oob_size:
* @sectors_per_block:
* @sector_in_page_mask:
* @sector_to_page_shift:
* @num_nands:
* @fingerprint2:
*/
struct gpmi_fcb {
u32 fingerprint1;
struct gpmi_nand_timing timing;
u32 pagesize;
u32 page_plus_oob_size;
u32 sectors_per_block;
u32 sector_in_page_mask;
u32 sector_to_page_shift;
u32 num_nands;
u32 reserved[3];
u32 fingerprint2; /* offset 0x2C */
};
/**
* struct gpmi_ldlb -
*
* @fingerprint1:
* @major:
* @minor:
* @sub:
* @nand_bitmap:
* @fingerprint2:
* @fw:
* @fw_starting_nand:
* @fw_starting_sector:
* @fw_sector_stride:
* @fw_sectors_total:
* @fw_major:
* @fw_minor:
* @fw_sub:
* @fw_reserved:
* @bbt_blk:
* @bbt_blk_backup:
*/
struct gpmi_ldlb {
u32 fingerprint1;
u16 major, minor, sub, reserved;
u32 nand_bitmap;
u32 reserved1[7];
u32 fingerprint2;
struct {
u32 fw_starting_nand;
u32 fw_starting_sector;
u32 fw_sector_stride;
u32 fw_sectors_total;
} fw[2];
u16 fw_major, fw_minor, fw_sub, fw_reserved;
u32 bbt_blk;
u32 bbt_blk_backup;
};
static inline void gpmi_block_mark_as(struct nand_chip *chip,
int block, int mark)
{
u32 o;
int shift = (block & 0x03) << 1,
index = block >> 2;
if (chip->bbt) {
mark &= 0x03;
o = chip->bbt[index];
o &= ~(0x03 << shift);
o |= (mark << shift);
chip->bbt[index] = o;
}
}
static inline int gpmi_block_badness(struct nand_chip *chip, int block)
{
u32 o;
int shift = (block & 0x03) << 1,
index = block >> 2;
if (chip->bbt) {
o = (chip->bbt[index] >> shift) & 0x03;
pr_debug("%s: block = %d, o = %d\n", __func__, block, o);
return o;
}
return -1;
}
#ifdef CONFIG_STMP3XXX_UNIQUE_ID
int __init gpmi_uid_init(const char *name, struct mtd_info *mtd,
u_int32_t start, u_int32_t size);
void gpmi_uid_remove(const char *name);
#else
#define gpmi_uid_init(name, mtd, start, size)
#define gpmi_uid_remove(name)
#endif
#endif
|