summaryrefslogtreecommitdiff
path: root/drivers/mtd/nand/gpmi/gpmi.h
blob: 99c26988f370f3bc87911bd5fd683892b7a0123d (plain)
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
/*
 * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface)
 *
 * Author: dmitry pervushin <dimka@embeddedalley.com>
 *
 * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
 * 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 <mach/gpmi.h>
#include <mach/regs-gpmi.h>
#include <mach/regs-apbh.h>
#ifdef CONFIG_MTD_NAND_GPMI_BCH
#include <mach/regs-bch.h>
#endif
#include <mach/regs-ecc8.h>

#include "gpmi-hamming-22-16.h"

#define GPMI_ECC4_WR \
	(BM_GPMI_ECCCTRL_ENABLE_ECC | \
	BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_4_BIT))
#define GPMI_ECC4_RD \
	(BM_GPMI_ECCCTRL_ENABLE_ECC | \
	BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__DECODE_4_BIT))
#define GPMI_ECC8_WR \
	(BM_GPMI_ECCCTRL_ENABLE_ECC | \
	BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_8_BIT))
#define GPMI_ECC8_RD \
	(BM_GPMI_ECCCTRL_ENABLE_ECC | \
	BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__DECODE_8_BIT))

/* fingerprints of BCB that can be found on STMP-formatted flash */
#define SIG1		"STMP"
#define SIG_NCB		"NCB "
#define SIG_LDLB	"LDLB"
#define SIG_DBBT	"DBBT"
#define SIG_SIZE	4

struct gpmi_nand_timing {
	u8 data_setup;
	u8 data_hold;
	u8 address_setup;
	u8 dsample_time;
};

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);
void gpmi_set_timings(struct platform_device *pdev,
			struct gpmi_nand_timing *tm);
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_hwecc_chip {
	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 stmp3xxx_dma_descriptor *chain,
			dma_addr_t error,
			dma_addr_t page, dma_addr_t oob);
	int (*write)(void *ctx, int index,
			struct stmp3xxx_dma_descriptor *chain,
			dma_addr_t error,
			dma_addr_t page, dma_addr_t oob);
	int (*stat)(void *ctx, int index, struct mtd_ecc_stats *r);
};

/* HWECC chips */
struct gpmi_hwecc_chip *gpmi_hwecc_chip_find(char *name);
void gpmi_hwecc_chip_add(struct gpmi_hwecc_chip *chip);
void gpmi_hwecc_chip_remove(struct gpmi_hwecc_chip *chip);
int bch_init(void);
int ecc8_init(void);
void bch_exit(void);
void ecc8_exit(void);


struct gpmi_nand_data {
	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 nand_chip	chip;
	struct mtd_info		mtd;
	struct platform_device  *dev;

#ifdef CONFIG_MTD_PARTITIONS
	int			nr_parts;
	struct mtd_partition
				*parts;
#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 nchip {
		unsigned dma_ch;
		struct stmp37xx_circ_dma_chain chain;
		struct stmp3xxx_dma_descriptor d[GPMI_DMA_MAX_CHAIN];
		struct stmp3xxx_dma_descriptor error;
		int cs;
	} chips[GPMI_MAX_CHIPS];
	struct nchip *cchip;
	int selected_chip;

	unsigned		hwecc_type_read, hwecc_type_write;
	int			hwecc;

	int			ecc_oob_bytes, oob_free;

	int			transcribe_bbmark;
	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_hwecc_chip *hc;

	int numchips;
	int custom_partitions;
	struct mtd_info *masters[GPMI_MAX_CHIPS];
	struct mtd_partition chip_partitions[GPMI_MAX_CHIPS];
	int n_concat;
	struct mtd_info *concat[GPMI_MAX_CHIPS];
	struct mtd_info *concat_mtd;
};

extern struct gpmi_nand_timing gpmi_safe_timing;

struct gpmi_ncb {
	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 {
	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