nfc_fsl.c revision 331722
1/*-
2 * Copyright (C) 2012 Juniper Networks, Inc.
3 * Copyright (C) 2009-2012 Semihalf
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27/*
28 * TODO :
29 *
30 *  -- test support for small pages
31 *  -- support for reading ONFI parameters
32 *  -- support for cached and interleaving commands
33 *  -- proper setting of AL bits in FMR
34 */
35
36#include <sys/cdefs.h>
37__FBSDID("$FreeBSD: stable/11/sys/dev/nand/nfc_fsl.c 331722 2018-03-29 02:50:57Z eadler $");
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/proc.h>
42#include <sys/bus.h>
43#include <sys/conf.h>
44#include <sys/kernel.h>
45#include <sys/module.h>
46#include <sys/malloc.h>
47#include <sys/rman.h>
48#include <sys/sysctl.h>
49#include <sys/time.h>
50#include <sys/kdb.h>
51
52#include <machine/bus.h>
53
54#include <dev/ofw/ofw_bus.h>
55#include <dev/ofw/ofw_bus_subr.h>
56
57#include <powerpc/mpc85xx/lbc.h>
58
59#include <dev/nand/nand.h>
60#include <dev/nand/nandbus.h>
61
62#include "nfc_fsl.h"
63
64#include "nfc_if.h"
65
66#define LBC_READ(regname)	lbc_read_reg(dev, (LBC85XX_ ## regname))
67#define LBC_WRITE(regname, val)	lbc_write_reg(dev, (LBC85XX_ ## regname), val)
68
69enum addr_type {
70	ADDR_NONE,
71	ADDR_ID,
72	ADDR_ROW,
73	ADDR_ROWCOL
74};
75
76struct fsl_nfc_fcm {
77	/* Read-only after initialization */
78	uint32_t	reg_fmr;
79
80	/* To be preserved across "start_command" */
81	u_int		buf_ofs;
82	u_int		read_ptr;
83	u_int		status:1;
84
85	/* Command state -- cleared by "start_command" */
86	uint32_t	fcm_startzero;
87	uint32_t	reg_fcr;
88	uint32_t	reg_fir;
89	uint32_t	reg_mdr;
90	uint32_t	reg_fbcr;
91	uint32_t	reg_fbar;
92	uint32_t	reg_fpar;
93	u_int		cmdnr;
94	u_int		opnr;
95	u_int		pg_ofs;
96	enum addr_type	addr_type;
97	u_int		addr_bytes;
98	u_int		row_addr;
99	u_int		column_addr;
100	u_int		data_fir:8;
101	uint32_t	fcm_endzero;
102};
103
104struct fsl_nand_softc {
105	struct nand_softc		nand_dev;
106	device_t			dev;
107	struct resource			*res;
108	int				rid;		/* Resourceid */
109	struct lbc_devinfo		*dinfo;
110	struct fsl_nfc_fcm		fcm;
111	uint8_t				col_cycles;
112	uint8_t				row_cycles;
113	uint16_t			pgsz;		/* Page size */
114};
115
116static int	fsl_nand_attach(device_t dev);
117static int	fsl_nand_probe(device_t dev);
118static int	fsl_nand_detach(device_t dev);
119
120static int	fsl_nfc_select_cs(device_t dev, uint8_t cs);
121static int	fsl_nfc_read_rnb(device_t dev);
122static int	fsl_nfc_send_command(device_t dev, uint8_t command);
123static int	fsl_nfc_send_address(device_t dev, uint8_t address);
124static uint8_t	fsl_nfc_read_byte(device_t dev);
125static int	fsl_nfc_start_command(device_t dev);
126static void	fsl_nfc_read_buf(device_t dev, void *buf, uint32_t len);
127static void	fsl_nfc_write_buf(device_t dev, void *buf, uint32_t len);
128
129static device_method_t fsl_nand_methods[] = {
130	DEVMETHOD(device_probe,		fsl_nand_probe),
131	DEVMETHOD(device_attach,	fsl_nand_attach),
132	DEVMETHOD(device_detach,	fsl_nand_detach),
133
134	DEVMETHOD(nfc_select_cs,	fsl_nfc_select_cs),
135	DEVMETHOD(nfc_read_rnb,		fsl_nfc_read_rnb),
136	DEVMETHOD(nfc_start_command,	fsl_nfc_start_command),
137	DEVMETHOD(nfc_send_command,	fsl_nfc_send_command),
138	DEVMETHOD(nfc_send_address,	fsl_nfc_send_address),
139	DEVMETHOD(nfc_read_byte,	fsl_nfc_read_byte),
140	DEVMETHOD(nfc_read_buf,		fsl_nfc_read_buf),
141	DEVMETHOD(nfc_write_buf,	fsl_nfc_write_buf),
142	{ 0, 0 },
143};
144
145static driver_t fsl_nand_driver = {
146	"nand",
147	fsl_nand_methods,
148	sizeof(struct fsl_nand_softc),
149};
150
151static devclass_t fsl_nand_devclass;
152
153DRIVER_MODULE(fsl_nand, lbc, fsl_nand_driver, fsl_nand_devclass,
154    0, 0);
155
156static int fsl_nand_build_address(device_t dev, uint32_t page, uint32_t column);
157static int fsl_nand_chip_preprobe(device_t dev, struct nand_id *id);
158
159#ifdef NAND_DEBUG_TIMING
160static device_t fcm_devs[8];
161#endif
162
163#define CMD_SHIFT(cmd_num)	(24 - ((cmd_num) * 8))
164#define OP_SHIFT(op_num)	(28 - ((op_num) * 4))
165
166#define FSL_LARGE_PAGE_SIZE	(2112)
167#define FSL_SMALL_PAGE_SIZE	(528)
168
169static void
170fsl_nand_init_regs(struct fsl_nand_softc *sc)
171{
172	uint32_t or_v, br_v;
173	device_t dev;
174
175	dev = sc->dev;
176
177	sc->fcm.reg_fmr = (15 << FMR_CWTO_SHIFT);
178
179	/*
180	 * Setup 4 row cycles and hope that chip ignores superfluous address
181	 * bytes.
182	 */
183	sc->fcm.reg_fmr |= (2 << FMR_AL_SHIFT);
184
185	/* Reprogram BR(x) */
186	br_v = lbc_read_reg(dev, LBC85XX_BR(sc->dinfo->di_bank));
187	br_v &= 0xffff8000;
188	br_v |= 1 << 11;	/* 8-bit port size */
189	br_v |= 0 << 9;		/* No ECC checking and generation */
190	br_v |= 1 << 5;		/* FCM machine */
191	br_v |= 1;		/* Valid */
192	lbc_write_reg(dev, LBC85XX_BR(sc->dinfo->di_bank), br_v);
193
194	/* Reprogram OR(x) */
195	or_v = lbc_read_reg(dev, LBC85XX_OR(sc->dinfo->di_bank));
196	or_v &= 0xfffffc00;
197	or_v |= 0x03AE;		/* Default POR timing */
198	lbc_write_reg(dev, LBC85XX_OR(sc->dinfo->di_bank), or_v);
199
200	if (or_v & OR_FCM_PAGESIZE) {
201		sc->pgsz = FSL_LARGE_PAGE_SIZE;
202		sc->col_cycles = 2;
203		nand_debug(NDBG_DRV, "%s: large page NAND device at #%d",
204		    device_get_nameunit(dev), sc->dinfo->di_bank);
205	} else {
206		sc->pgsz = FSL_SMALL_PAGE_SIZE;
207		sc->col_cycles = 1;
208		nand_debug(NDBG_DRV, "%s: small page NAND device at #%d",
209		    device_get_nameunit(dev), sc->dinfo->di_bank);
210	}
211}
212
213static int
214fsl_nand_probe(device_t dev)
215{
216
217	if (!ofw_bus_is_compatible(dev, "fsl,elbc-fcm-nand"))
218		return (ENXIO);
219
220	device_set_desc(dev, "Freescale localbus FCM Controller");
221	return (BUS_PROBE_DEFAULT);
222}
223
224static int
225fsl_nand_attach(device_t dev)
226{
227	struct fsl_nand_softc *sc;
228	struct nand_id id;
229	struct nand_params *param;
230	uint32_t num_pages;
231
232	sc = device_get_softc(dev);
233	sc->dev = dev;
234	sc->dinfo = device_get_ivars(dev);
235
236	sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid,
237	    RF_ACTIVE);
238	if (sc->res == NULL) {
239		device_printf(dev, "could not allocate resources!\n");
240		return (ENXIO);
241	}
242
243	bzero(&sc->fcm, sizeof(sc->fcm));
244
245	/* Init register and check if HW ECC turned on */
246	fsl_nand_init_regs(sc);
247
248	/* Chip is probed, so determine number of row address cycles */
249	fsl_nand_chip_preprobe(dev, &id);
250	param = nand_get_params(&id);
251	if (param != NULL) {
252		num_pages = (param->chip_size << 20) / param->page_size;
253		while(num_pages) {
254			sc->row_cycles++;
255			num_pages >>= 8;
256		}
257
258		sc->fcm.reg_fmr &= ~(FMR_AL);
259		sc->fcm.reg_fmr |= (sc->row_cycles - 2) << FMR_AL_SHIFT;
260	}
261
262	nand_init(&sc->nand_dev, dev, NAND_ECC_SOFT, 0, 0, NULL, NULL);
263
264#ifdef NAND_DEBUG_TIMING
265	fcm_devs[sc->dinfo->di_bank] = dev;
266#endif
267
268	return (nandbus_create(dev));
269}
270
271static int
272fsl_nand_detach(device_t dev)
273{
274	struct fsl_nand_softc *sc;
275
276	sc = device_get_softc(dev);
277
278	if (sc->res != NULL)
279		bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res);
280
281	return (0);
282}
283
284static int
285fsl_nfc_select_cs(device_t dev, uint8_t cs)
286{
287
288	// device_printf(dev, "%s(cs=%u)\n", __func__, cs);
289	return ((cs > 0) ? EINVAL : 0);
290}
291
292static int
293fsl_nfc_read_rnb(device_t dev)
294{
295
296	// device_printf(dev, "%s()\n", __func__);
297	return (0);
298}
299
300static int
301fsl_nfc_send_command(device_t dev, uint8_t command)
302{
303	struct fsl_nand_softc *sc;
304	struct fsl_nfc_fcm *fcm;
305	uint8_t	fir_op;
306
307	// device_printf(dev, "%s(command=%u)\n", __func__, command);
308
309	sc = device_get_softc(dev);
310	fcm = &sc->fcm;
311
312	if (command == NAND_CMD_PROG_END) {
313		fcm->reg_fir |= (FIR_OP_WB << OP_SHIFT(fcm->opnr));
314		fcm->opnr++;
315	}
316	fcm->reg_fcr |= command << CMD_SHIFT(fcm->cmdnr);
317	fir_op = (fcm->cmdnr == 0) ? FIR_OP_CW0 : FIR_OP_CM(fcm->cmdnr);
318	fcm->cmdnr++;
319
320	fcm->reg_fir |= (fir_op << OP_SHIFT(fcm->opnr));
321	fcm->opnr++;
322
323	switch (command) {
324	case NAND_CMD_READ_ID:
325		fcm->data_fir = FIR_OP_RBW;
326		fcm->addr_type = ADDR_ID;
327		break;
328	case NAND_CMD_SMALLOOB:
329		fcm->pg_ofs += 256;
330		/*FALLTHROUGH*/
331	case NAND_CMD_SMALLB:
332		fcm->pg_ofs += 256;
333		/*FALLTHROUGH*/
334	case NAND_CMD_READ: /* NAND_CMD_SMALLA */
335		fcm->data_fir = FIR_OP_RBW;
336		fcm->addr_type = ADDR_ROWCOL;
337		break;
338	case NAND_CMD_STATUS:
339		fcm->data_fir = FIR_OP_RS;
340		fcm->status = 1;
341		break;
342	case NAND_CMD_ERASE:
343		fcm->addr_type = ADDR_ROW;
344		break;
345	case NAND_CMD_PROG:
346		fcm->addr_type = ADDR_ROWCOL;
347		break;
348	}
349	return (0);
350}
351
352static int
353fsl_nfc_send_address(device_t dev, uint8_t addr)
354{
355	struct fsl_nand_softc *sc;
356	struct fsl_nfc_fcm *fcm;
357	uint32_t addr_bits;
358
359	// device_printf(dev, "%s(address=%u)\n", __func__, addr);
360
361	sc = device_get_softc(dev);
362	fcm = &sc->fcm;
363
364	KASSERT(fcm->addr_type != ADDR_NONE,
365	    ("controller doesn't expect address cycle"));
366
367	addr_bits = addr;
368
369	if (fcm->addr_type == ADDR_ID) {
370		fcm->reg_fir |= (FIR_OP_UA << OP_SHIFT(fcm->opnr));
371		fcm->opnr++;
372
373		fcm->reg_fbcr = 5;
374		fcm->reg_fbar = 0;
375		fcm->reg_fpar = 0;
376		fcm->reg_mdr = addr_bits;
377		fcm->buf_ofs = 0;
378		fcm->read_ptr = 0;
379		return (0);
380	}
381
382	if (fcm->addr_type == ADDR_ROW) {
383		addr_bits <<= fcm->addr_bytes * 8;
384		fcm->row_addr |= addr_bits;
385		fcm->addr_bytes++;
386		if (fcm->addr_bytes < sc->row_cycles)
387			return (0);
388	} else {
389		if (fcm->addr_bytes < sc->col_cycles) {
390			addr_bits <<= fcm->addr_bytes * 8;
391			fcm->column_addr |= addr_bits;
392		} else {
393			addr_bits <<= (fcm->addr_bytes - sc->col_cycles) * 8;
394			fcm->row_addr |= addr_bits;
395		}
396		fcm->addr_bytes++;
397		if (fcm->addr_bytes < (sc->row_cycles + sc->col_cycles))
398			return (0);
399	}
400
401	return (fsl_nand_build_address(dev, fcm->row_addr, fcm->column_addr));
402}
403
404static int
405fsl_nand_build_address(device_t dev, uint32_t row, uint32_t column)
406{
407	struct fsl_nand_softc *sc;
408	struct fsl_nfc_fcm *fcm;
409	uint32_t byte_count = 0;
410	uint32_t block_address = 0;
411	uint32_t page_address = 0;
412
413	sc = device_get_softc(dev);
414	fcm = &sc->fcm;
415
416	fcm->read_ptr = 0;
417	fcm->buf_ofs = 0;
418
419	if (fcm->addr_type == ADDR_ROWCOL) {
420		fcm->reg_fir |= (FIR_OP_CA << OP_SHIFT(fcm->opnr));
421		fcm->opnr++;
422
423		column += fcm->pg_ofs;
424		fcm->pg_ofs = 0;
425
426		page_address |= column;
427
428		if (column != 0) {
429			byte_count = sc->pgsz - column;
430			fcm->read_ptr = column;
431		}
432	}
433
434	fcm->reg_fir |= (FIR_OP_PA << OP_SHIFT(fcm->opnr));
435	fcm->opnr++;
436
437	if (sc->pgsz == FSL_LARGE_PAGE_SIZE) {
438		block_address = row >> 6;
439		page_address |= ((row << FPAR_LP_PI_SHIFT) & FPAR_LP_PI);
440		fcm->buf_ofs = (row & 1) * 4096;
441	} else {
442		block_address = row >> 5;
443		page_address |= ((row << FPAR_SP_PI_SHIFT) & FPAR_SP_PI);
444		fcm->buf_ofs = (row & 7) * 1024;
445	}
446
447	fcm->reg_fbcr = byte_count;
448	fcm->reg_fbar = block_address;
449	fcm->reg_fpar = page_address;
450	return (0);
451}
452
453static int
454fsl_nfc_start_command(device_t dev)
455{
456	struct fsl_nand_softc *sc;
457	struct fsl_nfc_fcm *fcm;
458	uint32_t fmr, ltesr_v;
459	int error, timeout;
460
461	// device_printf(dev, "%s()\n", __func__);
462
463	sc = device_get_softc(dev);
464	fcm = &sc->fcm;
465
466	fmr = fcm->reg_fmr | FMR_OP;
467
468	if (fcm->data_fir)
469		fcm->reg_fir |= (fcm->data_fir << OP_SHIFT(fcm->opnr));
470
471	LBC_WRITE(FIR, fcm->reg_fir);
472	LBC_WRITE(FCR, fcm->reg_fcr);
473
474	LBC_WRITE(FMR, fmr);
475
476	LBC_WRITE(FBCR, fcm->reg_fbcr);
477	LBC_WRITE(FBAR, fcm->reg_fbar);
478	LBC_WRITE(FPAR, fcm->reg_fpar);
479
480	if (fcm->addr_type == ADDR_ID)
481		LBC_WRITE(MDR, fcm->reg_mdr);
482
483	nand_debug(NDBG_DRV, "BEFORE:\nFMR=%#x, FIR=%#x, FCR=%#x", fmr,
484	    fcm->reg_fir, fcm->reg_fcr);
485	nand_debug(NDBG_DRV, "MDR=%#x, FBAR=%#x, FPAR=%#x, FBCR=%#x",
486	    LBC_READ(MDR), fcm->reg_fbar, fcm->reg_fpar, fcm->reg_fbcr);
487
488	LBC_WRITE(LSOR, sc->dinfo->di_bank);
489
490	timeout = (cold) ? FSL_FCM_WAIT_TIMEOUT : ~0;
491	error = 0;
492	ltesr_v = LBC_READ(LTESR);
493	while (!error && (ltesr_v & LTESR_CC) == 0) {
494		if (cold) {
495			DELAY(1000);
496			timeout--;
497			if (timeout < 0)
498				error = EWOULDBLOCK;
499		} else
500			error = tsleep(device_get_parent(sc->dev), PRIBIO,
501			    "nfcfsl", hz);
502		ltesr_v = LBC_READ(LTESR);
503	}
504	if (error)
505		nand_debug(NDBG_DRV, "Command complete wait timeout\n");
506
507	nand_debug(NDBG_DRV, "AFTER:\nLTESR=%#x, LTEDR=%#x, LTEIR=%#x,"
508	    " LTEATR=%#x, LTEAR=%#x, LTECCR=%#x", ltesr_v,
509	    LBC_READ(LTEDR), LBC_READ(LTEIR), LBC_READ(LTEATR),
510	    LBC_READ(LTEAR), LBC_READ(LTECCR));
511
512	bzero(&fcm->fcm_startzero,
513	    __rangeof(struct fsl_nfc_fcm, fcm_startzero, fcm_endzero));
514
515	if (fcm->status)
516		sc->fcm.reg_mdr = LBC_READ(MDR);
517
518	/* Even if timeout occurred, we should perform steps below */
519	LBC_WRITE(LTESR, ltesr_v);
520	LBC_WRITE(LTEATR, 0);
521
522	return (error);
523}
524
525static uint8_t
526fsl_nfc_read_byte(device_t dev)
527{
528	struct fsl_nand_softc *sc = device_get_softc(dev);
529	uint32_t offset;
530
531	// device_printf(dev, "%s()\n", __func__);
532
533	/*
534	 * LBC controller allows us to read status into a MDR instead of FCM
535	 * buffer. If last operation requested before read_byte() was STATUS,
536	 * then return MDR instead of reading a single byte from a buffer.
537	 */
538	if (sc->fcm.status) {
539		sc->fcm.status = 0;
540		return (sc->fcm.reg_mdr);
541	}
542
543	KASSERT(sc->fcm.read_ptr < sc->pgsz,
544	    ("Attempt to read beyond buffer %x %x", sc->fcm.read_ptr,
545	    sc->pgsz));
546
547	offset = sc->fcm.buf_ofs + sc->fcm.read_ptr;
548	sc->fcm.read_ptr++;
549	return (bus_read_1(sc->res, offset));
550}
551
552static void
553fsl_nfc_read_buf(device_t dev, void *buf, uint32_t len)
554{
555	struct fsl_nand_softc *sc = device_get_softc(dev);
556	uint32_t offset;
557	int bytesleft = 0;
558
559	// device_printf(dev, "%s(buf=%p, len=%u)\n", __func__, buf, len);
560
561	nand_debug(NDBG_DRV, "REQUEST OF 0x%0x B (BIB=0x%0x, NTR=0x%0x)",
562	    len, sc->pgsz, sc->fcm.read_ptr);
563
564	bytesleft = MIN((unsigned int)len, sc->pgsz - sc->fcm.read_ptr);
565
566	offset = sc->fcm.buf_ofs + sc->fcm.read_ptr;
567	bus_read_region_1(sc->res, offset, buf, bytesleft);
568	sc->fcm.read_ptr += bytesleft;
569}
570
571static void
572fsl_nfc_write_buf(device_t dev, void *buf, uint32_t len)
573{
574	struct fsl_nand_softc *sc = device_get_softc(dev);
575	uint32_t offset;
576	int bytesleft = 0;
577
578	// device_printf(dev, "%s(buf=%p, len=%u)\n", __func__, buf, len);
579
580	KASSERT(len <= sc->pgsz - sc->fcm.read_ptr,
581	    ("Attempt to write beyond buffer"));
582
583	bytesleft = MIN((unsigned int)len, sc->pgsz - sc->fcm.read_ptr);
584
585	nand_debug(NDBG_DRV, "REQUEST TO WRITE 0x%0x (BIB=0x%0x, NTR=0x%0x)",
586	    bytesleft, sc->pgsz, sc->fcm.read_ptr);
587
588	offset = sc->fcm.buf_ofs + sc->fcm.read_ptr;
589	bus_write_region_1(sc->res, offset, buf, bytesleft);
590	sc->fcm.read_ptr += bytesleft;
591}
592
593static int
594fsl_nand_chip_preprobe(device_t dev, struct nand_id *id)
595{
596
597	if (fsl_nfc_send_command(dev, NAND_CMD_RESET) != 0)
598		return (ENXIO);
599
600	if (fsl_nfc_start_command(dev) != 0)
601		return (ENXIO);
602
603	DELAY(1000);
604
605	if (fsl_nfc_send_command(dev, NAND_CMD_READ_ID))
606		return (ENXIO);
607
608	if (fsl_nfc_send_address(dev, 0))
609		return (ENXIO);
610
611	if (fsl_nfc_start_command(dev) != 0)
612		return (ENXIO);
613
614	DELAY(25);
615
616	id->man_id = fsl_nfc_read_byte(dev);
617	id->dev_id = fsl_nfc_read_byte(dev);
618
619	nand_debug(NDBG_DRV, "manufacturer id: %x chip id: %x",
620	    id->man_id, id->dev_id);
621
622	return (0);
623}
624
625#ifdef NAND_DEBUG_TIMING
626
627static SYSCTL_NODE(_debug, OID_AUTO, fcm, CTLFLAG_RD, 0, "FCM timing");
628
629static u_int csct = 1;	/* 22:    Chip select to command time (trlx). */
630SYSCTL_UINT(_debug_fcm, OID_AUTO, csct, CTLFLAG_RW, &csct, 1,
631    "Chip select to command time: determines how far in advance -LCSn is "
632    "asserted prior to any bus activity during a NAND Flash access handled "
633    "by the FCM. This helps meet chip-select setup times for slow memories.");
634
635static u_int cst = 1;	/* 23:    Command setup time (trlx). */
636SYSCTL_UINT(_debug_fcm, OID_AUTO, cst, CTLFLAG_RW, &cst, 1,
637    "Command setup time: determines the delay of -LFWE assertion relative to "
638    "the command, address, or data change when the external memory access "
639    "is handled by the FCM.");
640
641static u_int cht = 1;	/* 24:    Command hold time (trlx). */
642SYSCTL_UINT(_debug_fcm, OID_AUTO, cht, CTLFLAG_RW, &cht, 1,
643    "Command hold time: determines the -LFWE negation prior to the command, "
644    "address, or data change when the external memory access is handled by "
645    "the FCM.");
646
647static u_int scy = 2;	/* 25-27: Cycle length in bus clocks */
648SYSCTL_UINT(_debug_fcm, OID_AUTO, scy, CTLFLAG_RW, &scy, 2,
649    "Cycle length in bus clocks: see RM");
650
651static u_int rst = 1;	/* 28:    Read setup time (trlx). */
652SYSCTL_UINT(_debug_fcm, OID_AUTO, rst, CTLFLAG_RW, &rst, 1,
653    "Read setup time: determines the delay of -LFRE assertion relative to "
654    "sampling of read data when the external memory access is handled by "
655    "the FCM.");
656
657static u_int trlx = 1;	/* 29:    Timing relaxed. */
658SYSCTL_UINT(_debug_fcm, OID_AUTO, trlx, CTLFLAG_RW, &trlx, 1,
659    "Timing relaxed: modifies the settings of timing parameters for slow "
660    "memories. See RM");
661
662static u_int ehtr = 1;	/* 30:    Extended hold time on read accesses. */
663SYSCTL_UINT(_debug_fcm, OID_AUTO, ehtr, CTLFLAG_RW, &ehtr, 1,
664    "Extended hold time on read accesses: indicates with TRLX how many "
665    "cycles are inserted between a read access from the current bank and "
666    "the next access.");
667
668static u_int
669fsl_nand_get_timing(void)
670{
671	u_int timing;
672
673	timing = ((csct & 1) << 9) | ((cst & 1) << 8) | ((cht & 1) << 7) |
674	    ((scy & 7) << 4) | ((rst & 1) << 3) | ((trlx & 1) << 2) |
675	    ((ehtr & 1) << 1);
676
677	printf("nfc_fsl: timing = %u\n", timing);
678	return (timing);
679}
680
681static int
682fsl_sysctl_program(SYSCTL_HANDLER_ARGS)
683{
684	struct fsl_nand_softc *sc;
685	int error, i;
686	device_t dev;
687	uint32_t or_v;
688
689	error = sysctl_wire_old_buffer(req, sizeof(int));
690	if (error == 0) {
691		i = 0;
692		error = sysctl_handle_int(oidp, &i, 0, req);
693	}
694	if (error != 0 || req->newptr == NULL)
695		return (error);
696
697	for (i = 0; i < 8; i++) {
698		dev = fcm_devs[i];
699		if (dev == NULL)
700			continue;
701		sc = device_get_softc(dev);
702
703		/* Reprogram OR(x) */
704		or_v = lbc_read_reg(dev, LBC85XX_OR(sc->dinfo->di_bank));
705		or_v &= 0xfffffc00;
706		or_v |= fsl_nand_get_timing();
707		lbc_write_reg(dev, LBC85XX_OR(sc->dinfo->di_bank), or_v);
708	}
709	return (0);
710}
711
712SYSCTL_PROC(_debug_fcm, OID_AUTO, program, CTLTYPE_INT | CTLFLAG_RW, NULL, 0,
713    fsl_sysctl_program, "I", "write to program FCM with current values");
714
715#endif /* NAND_DEBUG_TIMING */
716