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