aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/nand/nand.h
blob: 0e9ea41bc60bb0ee500733fb92154213f2f2dd0c (plain) (blame)
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
/*-
 * Copyright (C) 2009-2012 Semihalf
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD$
 */

#ifndef _DEV_NAND_H_
#define _DEV_NAND_H_

#include <sys/bus.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/lock.h>
#include <sys/sx.h>
#include <sys/taskqueue.h>
#include <sys/queue.h>
#include <sys/bio.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/malloc.h>

#include <dev/nand/nand_dev.h>

MALLOC_DECLARE(M_NAND);

/* Read commands */
#define NAND_CMD_READ		0x00
#define NAND_CMD_CHNG_READ_COL	0x05
#define NAND_CMD_READ_END	0x30
#define NAND_CMD_READ_CACHE	0x31
#define NAND_CMD_READ_CPBK	0x35
#define NAND_CMD_READ_CACHE_END	0x3F
#define	NAND_CMD_CHNG_READ_COL_END	0xE0

/* Erase commands */
#define NAND_CMD_ERASE		0x60
#define NAND_CMD_ERASE_END	0xD0
#define NAND_CMD_ERASE_INTLV	0xD1

/* Program commands */
#define NAND_CMD_PROG		0x80
#define NAND_CMD_CHNG_WRITE_COL	0x85
#define NAND_CMD_PROG_END	0x10
#define NAND_CMD_PROG_INTLV	0x11
#define NAND_CMD_PROG_CACHE	0x15

/* Misc commands */
#define NAND_CMD_STATUS		0x70
#define NAND_CMD_STATUS_ENH	0x78
#define NAND_CMD_READ_ID	0x90
#define NAND_CMD_READ_PARAMETER	0xec
#define NAND_CMD_READ_UNIQUE_ID	0xed
#define NAND_CMD_GET_FEATURE	0xee
#define NAND_CMD_SET_FEATURE	0xef

/* Reset commands */
#define NAND_CMD_SYNCH_RESET	0xfc
#define NAND_CMD_RESET		0xff

/* Small page flash commands */
#define NAND_CMD_SMALLA		0x00
#define NAND_CMD_SMALLB		0x01
#define NAND_CMD_SMALLOOB	0x50

#define NAND_STATUS_FAIL	0x1
#define NAND_STATUS_FAILC	0x2
#define NAND_STATUS_ARDY	0x20
#define NAND_STATUS_RDY		0x40
#define NAND_STATUS_WP		0x80

#define NAND_LP_OOB_COLUMN_START	0x800
#define NAND_LP_OOBSZ			0x40
#define NAND_SP_OOB_COLUMN_START	0x200
#define NAND_SP_OOBSZ			0x10

#define PAGE_PARAM_LENGTH		0x100
#define PAGE_PARAMETER_DEF		0x0
#define PAGE_PARAMETER_RED_1		0x100
#define PAGE_PARAMETER_RED_2		0x200

#define ONFI_SIG_ADDR	0x20

#define NAND_MAX_CHIPS	0x4
#define NAND_MAX_OOBSZ	512
#define NAND_MAX_PAGESZ	16384

#define NAND_SMALL_PAGE_SIZE	0x200

#define NAND_16_BIT		0x00000001

#define NAND_ECC_NONE			0x0
#define NAND_ECC_SOFT			0x1
#define	NAND_ECC_FULLHW			0x2
#define	NAND_ECC_PARTHW			0x4
#define NAND_ECC_MODE_MASK		0x7

#define ECC_OK			0
#define ECC_CORRECTABLE		1
#define ECC_ERROR_ECC		(-1)
#define ECC_UNCORRECTABLE	(-2)

#define NAND_MAN_SAMSUNG		0xec
#define NAND_MAN_HYNIX			0xad
#define NAND_MAN_STMICRO		0x20
#define NAND_MAN_MICRON			0x2c

struct nand_id {
	uint8_t man_id;
	uint8_t dev_id;
};

struct nand_params {
	struct nand_id	id;
	char		*name;
	uint32_t	chip_size;
	uint32_t	page_size;
	uint32_t	oob_size;
	uint32_t	pages_per_block;
	uint32_t	flags;
};

/* nand debug levels */
#define NDBG_NAND	0x01
#define NDBG_CDEV	0x02
#define NDBG_GEN	0x04
#define NDBG_GEOM	0x08
#define NDBG_BUS	0x10
#define NDBG_SIM	0x20
#define NDBG_CTRL	0x40
#define NDBG_DRV	0x80
#define NDBG_ECC	0x100

/* nand_debug_function */
void nand_debug(int level, const char *fmt, ...);
extern int nand_debug_flag;

/* ONFI features bit*/
#define ONFI_FEAT_16BIT		0x01
#define ONFI_FEAT_MULT_LUN	0x02
#define ONFI_FEAT_INTLV_OPS	0x04
#define ONFI_FEAT_CPBK_RESTRICT	0x08
#define ONFI_FEAT_SRC_SYNCH	0x10

/* ONFI optional commands bits */
#define ONFI_OPTCOM_PROG_CACHE	0x01
#define ONFI_OPTCOM_READ_CACHE	0x02
#define ONFI_OPTCOM_GETSET_FEAT	0x04
#define ONFI_OPTCOM_STATUS_ENH	0x08
#define ONFI_OPTCOM_COPYBACK	0x10
#define ONFI_OPTCOM_UNIQUE_ID	0x20


/* Layout of parameter page is defined in ONFI */
struct onfi_params {
	char		signature[4];
	uint16_t	rev;
	uint16_t	features;
	uint16_t	optional_commands;
	uint8_t		primary_advanced_command;
	uint8_t		res1;
	uint16_t	extended_parameter_page_length;
	uint8_t		parameter_page_count;
	uint8_t		res2[17];
	char		manufacturer_name[12];
	char		device_model[20];
	uint8_t		manufacturer_id;
	uint8_t		manufacture_date_yy;
	uint8_t		manufacture_date_ww;
	uint8_t		res3[13];
	uint32_t	bytes_per_page;
	uint16_t	spare_bytes_per_page;
	uint32_t	bytes_per_partial_page;
	uint16_t	spare_bytes_per_partial_page;
	uint32_t	pages_per_block;
	uint32_t	blocks_per_lun;
	uint8_t		luns;
	uint8_t		address_cycles;
	uint8_t		bits_per_cell;
	uint16_t	max_bad_block_per_lun;
	uint16_t	block_endurance;
	uint8_t		guaranteed_valid_blocks;
	uint16_t	valid_block_endurance;
	uint8_t		programs_per_page;
	uint8_t		partial_prog_attr;
	uint8_t		bits_of_ecc;
	uint8_t		interleaved_addr_bits;
	uint8_t		interleaved_oper_attr;
	uint8_t		eznand_support;
	uint8_t		res4[12];
	uint8_t		pin_capacitance;
	uint16_t	asynch_timing_mode_support;
	uint16_t	asynch_prog_cache_timing_mode_support;
	uint16_t	t_prog;	/* us, max page program time */
	uint16_t	t_bers;	/* us, max block erase time */
	uint16_t	t_r;	/* us, max page read time */
	uint16_t	t_ccs;	/* ns, min change column setup time */
	uint16_t	source_synch_timing_mode_support;
	uint8_t		source_synch_feat;
	uint16_t	clk_input_capacitance;
	uint16_t	io_capacitance;
	uint16_t	input_capacitance;
	uint8_t		input_capacitance_max;
	uint8_t		driver_strength_support;
	uint16_t	t_r_interleaved;
	uint16_t	t_adl;
	uint16_t	t_r_eznand;
	uint8_t		nv_ddr2_features;
	uint8_t		nv_ddr2_warmup_cycles;
	uint8_t		res5[4];
	uint16_t	vendor_rev;
	uint8_t		vendor_spec[88];
	uint16_t	crc;
}__attribute__((packed));
CTASSERT(sizeof(struct onfi_params) == 256);

struct onfi_chip_params {
	uint32_t blocks_per_lun;
	uint32_t pages_per_block;
	uint32_t bytes_per_page;
	uint32_t spare_bytes_per_page;
	uint16_t t_bers;
	uint16_t t_prog;
	uint16_t t_r;
	uint16_t t_ccs;
	uint16_t features;
	uint8_t address_cycles;
	uint8_t luns;
};

struct nand_ecc_data {
	int	eccsize;		/* Number of data bytes per ECC step */
	int	eccmode;
	int	eccbytes;		/* Number of ECC bytes per step */

	uint16_t	*eccpositions;		/* Positions of ecc bytes */
	uint8_t	ecccalculated[NAND_MAX_OOBSZ];
	uint8_t	eccread[NAND_MAX_OOBSZ];
};

struct ecc_stat {
	uint32_t ecc_succeded;
	uint32_t ecc_corrected;
	uint32_t ecc_failed;
};

struct page_stat {
	struct ecc_stat	ecc_stat;
	uint32_t	page_read;
	uint32_t	page_raw_read;
	uint32_t	page_written;
	uint32_t	page_raw_written;
};

struct block_stat {
	uint32_t block_erased;
};

struct chip_geom {
	uint32_t	chip_size;
	uint32_t	block_size;
	uint32_t	page_size;
	uint32_t	oob_size;

	uint32_t	luns;
	uint32_t	blks_per_lun;
	uint32_t	blks_per_chip;
	uint32_t	pgs_per_blk;

	uint32_t	pg_mask;
	uint32_t	blk_mask;
	uint32_t	lun_mask;
	uint8_t		blk_shift;
	uint8_t		lun_shift;
};

struct nand_chip {
	device_t		dev;
	struct nand_id		id;
	struct chip_geom	chip_geom;

	uint16_t		t_prog;	/* us, max page program time */
	uint16_t		t_bers;	/* us, max block erase time */
	uint16_t		t_r;	/* us, max page read time */
	uint16_t		t_ccs;	/* ns, min change column setup time */
	uint8_t			num;
	uint8_t			flags;

	struct page_stat	*pg_stat;
	struct block_stat	*blk_stat;
	struct nand_softc	*nand;
	struct nand_bbt		*bbt;
	struct nand_ops		*ops;
	struct cdev		*cdev;

	struct disk		*ndisk;
	struct disk		*rdisk;
	struct bio_queue_head	bioq;	/* bio queue */
	struct mtx		qlock;	/* bioq lock */
	struct taskqueue	*tq;	/* private task queue for i/o request */
	struct task		iotask;	/* i/o processing */

};

struct nand_softc {
	uint8_t			flags;

	char			*chip_cdev_name;
	struct nand_ecc_data	ecc;
};

/* NAND ops */
int nand_erase_blocks(struct nand_chip *chip, off_t offset, size_t len);
int nand_prog_pages(struct nand_chip *chip, uint32_t offset, uint8_t *buf,
    uint32_t len);
int nand_read_pages(struct nand_chip *chip, uint32_t offset, void *buf,
    uint32_t len);
int nand_read_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf,
    uint32_t len);
int nand_prog_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf,
    uint32_t len);
int nand_read_oob(struct nand_chip *chip, uint32_t page, void *buf,
    uint32_t len);
int nand_prog_oob(struct nand_chip *chip, uint32_t page, void *buf,
    uint32_t len);

int nand_select_cs(device_t dev, uint8_t cs);

int nand_read_parameter(struct nand_softc *nand, struct onfi_params *param);
int nand_synch_reset(struct nand_softc *nand);
int nand_chng_read_col(device_t dev, uint32_t col, void *buf, size_t len);
int nand_chng_write_col(device_t dev, uint32_t col, void *buf, size_t len);
int nand_get_feature(device_t dev, uint8_t feat, void* buf);
int nand_set_feature(device_t dev, uint8_t feat, void* buf);


int nand_erase_block_intlv(device_t dev, uint32_t block);
int nand_copyback_read(device_t dev, uint32_t page, uint32_t col,
    void *buf, size_t len);
int nand_copyback_prog(device_t dev, uint32_t page, uint32_t col,
    void *buf, size_t len);
int nand_copyback_prog_intlv(device_t dev, uint32_t page);
int nand_prog_cache(device_t dev, uint32_t page, uint32_t col,
    void *buf, size_t len, uint8_t end);
int nand_prog_intlv(device_t dev, uint32_t page, uint32_t col,
    void *buf, size_t len);
int nand_read_cache(device_t dev, uint32_t page, uint32_t col,
    void *buf, size_t len, uint8_t end);

int nand_write_ecc(struct nand_softc *nand, uint32_t page, uint8_t *data);
int nand_read_ecc(struct nand_softc *nand, uint32_t page, uint8_t *data);

int nand_softecc_get(device_t dev, uint8_t *buf, int pagesize, uint8_t *ecc);
int nand_softecc_correct(device_t dev, uint8_t *buf, int pagesize,
    uint8_t *readecc, uint8_t *calcecc);

/* Chip initialization */
void nand_init(struct nand_softc *nand, device_t dev, int ecc_mode,
    int ecc_bytes, int ecc_size, uint16_t* eccposition, char* cdev_name);
void nand_detach(struct nand_softc *nand);
struct nand_params *nand_get_params(struct nand_id *id);

void nand_onfi_set_params(struct nand_chip *chip, struct onfi_chip_params *params);
void nand_set_params(struct nand_chip *chip, struct nand_params *params);
int  nand_init_stat(struct nand_chip *chip);
void nand_destroy_stat(struct nand_chip *chip);

/* BBT */
int nand_init_bbt(struct nand_chip *chip);
void nand_destroy_bbt(struct nand_chip *chip);
int nand_update_bbt(struct nand_chip *chip);
int nand_mark_bad_block(struct nand_chip* chip, uint32_t block_num);
int nand_check_bad_block(struct nand_chip* chip, uint32_t block_num);

/* cdev creation/removal */
int  nand_make_dev(struct nand_chip* chip);
void nand_destroy_dev(struct nand_chip *chip);

int  create_geom_disk(struct nand_chip* chip);
int  create_geom_raw_disk(struct nand_chip *chip);
void destroy_geom_disk(struct nand_chip *chip);
void destroy_geom_raw_disk(struct nand_chip *chip);

int init_chip_geom(struct chip_geom* cg, uint32_t luns, uint32_t blks_per_lun,
    uint32_t pgs_per_blk, uint32_t pg_size, uint32_t oob_size);
int nand_row_to_blkpg(struct chip_geom *cg, uint32_t row, uint32_t *lun,
    uint32_t *blk, uint32_t *pg);
int page_to_row(struct chip_geom *cg, uint32_t page, uint32_t *row);
int nand_check_page_boundary(struct nand_chip *chip, uint32_t page);
void nand_get_chip_param(struct nand_chip *chip, struct chip_param_io *param);

#endif /* _DEV_NAND_H_ */