Author: marcel
Date: Tue Jul  3 01:00:29 2012
New Revision: 238046
URL: http://svn.freebsd.org/changeset/base/238046

Log:
  Add a driver for the Freescale FCM module in the localbus controller.
  This driver does not yet handle multiple chip selects properly.
  
  Note that the NAND infrastructure does not perform full page
  reads or writes, which means that this driver cannot make use
  of the hardware ECC that is otherwise present.

Added:
  head/sys/dev/nand/nfc_fsl.c   (contents, props changed)
  head/sys/dev/nand/nfc_fsl.h   (contents, props changed)
Modified:
  head/sys/conf/files.powerpc

Modified: head/sys/conf/files.powerpc
==============================================================================
--- head/sys/conf/files.powerpc Tue Jul  3 00:06:14 2012        (r238045)
+++ head/sys/conf/files.powerpc Tue Jul  3 01:00:29 2012        (r238046)
@@ -35,6 +35,7 @@ dev/iicbus/ad7417.c           optional        ad7417 pow
 dev/iicbus/ds1775.c            optional        ds1775 powermac
 dev/iicbus/max6690.c           optional        max6690 powermac
 dev/kbd/kbd.c                  optional        sc
+dev/nand/nfc_fsl.c             optional        nand mpc85xx
 dev/ofw/openfirm.c             optional        aim | fdt
 dev/ofw/openfirmio.c           optional        aim | fdt
 dev/ofw/ofw_bus_if.m           optional        aim | fdt

Added: head/sys/dev/nand/nfc_fsl.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/nand/nfc_fsl.c Tue Jul  3 01:00:29 2012        (r238046)
@@ -0,0 +1,716 @@
+/*-
+ * Copyright (C) 2012 Juniper Networks, Inc.
+ * 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.
+ */
+/*
+ * TODO :
+ *
+ *  -- test support for small pages
+ *  -- support for reading ONFI parameters
+ *  -- support for cached and interleaving commands
+ *  -- proper setting of AL bits in FMR
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/kdb.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <powerpc/mpc85xx/lbc.h>
+
+#include <dev/nand/nand.h>
+#include <dev/nand/nandbus.h>
+
+#include "nfc_fsl.h"
+
+#include "nfc_if.h"
+
+#define LBC_READ(regname)      lbc_read_reg(dev, (LBC85XX_ ## regname))
+#define LBC_WRITE(regname, val)        lbc_write_reg(dev, (LBC85XX_ ## 
regname), val)
+
+enum addr_type {
+       ADDR_NONE,
+       ADDR_ID,
+       ADDR_ROW,
+       ADDR_ROWCOL
+};
+
+struct fsl_nfc_fcm {
+       /* Read-only after initialization */
+       uint32_t        reg_fmr;
+
+       /* To be preserved across "start_command" */
+       u_int           buf_ofs;
+       u_int           read_ptr;
+       u_int           status:1;
+
+       /* Command state -- cleared by "start_command" */
+       uint32_t        fcm_startzero;
+       uint32_t        reg_fcr;
+       uint32_t        reg_fir;
+       uint32_t        reg_mdr;
+       uint32_t        reg_fbcr;
+       uint32_t        reg_fbar;
+       uint32_t        reg_fpar;
+       u_int           cmdnr;
+       u_int           opnr;
+       u_int           pg_ofs;
+       enum addr_type  addr_type;
+       u_int           addr_bytes;
+       u_int           row_addr;
+       u_int           column_addr;
+       u_int           data_fir:8;
+       uint32_t        fcm_endzero;
+};
+
+struct fsl_nand_softc {
+       struct nand_softc               nand_dev;
+       device_t                        dev;
+       struct resource                 *res;
+       int                             rid;            /* Resourceid */
+       struct lbc_devinfo              *dinfo;
+       struct fsl_nfc_fcm              fcm;
+       uint8_t                         col_cycles;
+       uint8_t                         row_cycles;
+       uint16_t                        pgsz;           /* Page size */
+};
+
+static int     fsl_nand_attach(device_t dev);
+static int     fsl_nand_probe(device_t dev);
+static int     fsl_nand_detach(device_t dev);
+
+static int     fsl_nfc_select_cs(device_t dev, uint8_t cs);
+static int     fsl_nfc_read_rnb(device_t dev);
+static int     fsl_nfc_send_command(device_t dev, uint8_t command);
+static int     fsl_nfc_send_address(device_t dev, uint8_t address);
+static uint8_t fsl_nfc_read_byte(device_t dev);
+static int     fsl_nfc_start_command(device_t dev);
+static void    fsl_nfc_read_buf(device_t dev, void *buf, uint32_t len);
+static void    fsl_nfc_write_buf(device_t dev, void *buf, uint32_t len);
+
+static device_method_t fsl_nand_methods[] = {
+       DEVMETHOD(device_probe,         fsl_nand_probe),
+       DEVMETHOD(device_attach,        fsl_nand_attach),
+       DEVMETHOD(device_detach,        fsl_nand_detach),
+
+       DEVMETHOD(nfc_select_cs,        fsl_nfc_select_cs),
+       DEVMETHOD(nfc_read_rnb,         fsl_nfc_read_rnb),
+       DEVMETHOD(nfc_start_command,    fsl_nfc_start_command),
+       DEVMETHOD(nfc_send_command,     fsl_nfc_send_command),
+       DEVMETHOD(nfc_send_address,     fsl_nfc_send_address),
+       DEVMETHOD(nfc_read_byte,        fsl_nfc_read_byte),
+       DEVMETHOD(nfc_read_buf,         fsl_nfc_read_buf),
+       DEVMETHOD(nfc_write_buf,        fsl_nfc_write_buf),
+       { 0, 0 },
+};
+
+static driver_t fsl_nand_driver = {
+       "nand",
+       fsl_nand_methods,
+       sizeof(struct fsl_nand_softc),
+};
+
+static devclass_t fsl_nand_devclass;
+
+DRIVER_MODULE(fsl_nand, lbc, fsl_nand_driver, fsl_nand_devclass,
+    0, 0);
+
+static int fsl_nand_build_address(device_t dev, uint32_t page, uint32_t 
column);
+static int fsl_nand_chip_preprobe(device_t dev, struct nand_id *id);
+
+#ifdef NAND_DEBUG_TIMING
+static device_t fcm_devs[8];
+#endif
+
+#define CMD_SHIFT(cmd_num)     (24 - ((cmd_num) * 8))
+#define OP_SHIFT(op_num)       (28 - ((op_num) * 4))
+
+#define FSL_LARGE_PAGE_SIZE    (2112)
+#define FSL_SMALL_PAGE_SIZE    (528)
+
+static void
+fsl_nand_init_regs(struct fsl_nand_softc *sc)
+{
+       uint32_t or_v, br_v;
+       device_t dev;
+
+       dev = sc->dev;
+
+       sc->fcm.reg_fmr = (15 << FMR_CWTO_SHIFT);
+
+       /*
+        * Setup 4 row cycles and hope that chip ignores superfluous address
+        * bytes.
+        */
+       sc->fcm.reg_fmr |= (2 << FMR_AL_SHIFT);
+
+       /* Reprogram BR(x) */
+       br_v = lbc_read_reg(dev, LBC85XX_BR(sc->dinfo->di_bank));
+       br_v &= 0xffff8000;
+       br_v |= 1 << 11;        /* 8-bit port size */
+       br_v |= 0 << 9;         /* No ECC checking and generation */
+       br_v |= 1 << 5;         /* FCM machine */
+       br_v |= 1;              /* Valid */
+       lbc_write_reg(dev, LBC85XX_BR(sc->dinfo->di_bank), br_v);
+
+       /* Reprogram OR(x) */
+       or_v = lbc_read_reg(dev, LBC85XX_OR(sc->dinfo->di_bank));
+       or_v &= 0xfffffc00;
+       or_v |= 0x03AE;         /* Default POR timing */
+       lbc_write_reg(dev, LBC85XX_OR(sc->dinfo->di_bank), or_v);
+
+       if (or_v & OR_FCM_PAGESIZE) {
+               sc->pgsz = FSL_LARGE_PAGE_SIZE;
+               sc->col_cycles = 2;
+               nand_debug(NDBG_DRV, "%s: large page NAND device at #%d",
+                   device_get_nameunit(dev), sc->dinfo->di_bank);
+       } else {
+               sc->pgsz = FSL_SMALL_PAGE_SIZE;
+               sc->col_cycles = 1;
+               nand_debug(NDBG_DRV, "%s: small page NAND device at #%d",
+                   device_get_nameunit(dev), sc->dinfo->di_bank);
+       }
+}
+
+static int
+fsl_nand_probe(device_t dev)
+{
+
+       if (!ofw_bus_is_compatible(dev, "fsl,elbc-fcm-nand"))
+               return (ENXIO);
+
+       device_set_desc(dev, "Freescale localbus FCM Controller");
+       return (BUS_PROBE_DEFAULT);
+}
+
+static int
+fsl_nand_attach(device_t dev)
+{
+       struct fsl_nand_softc *sc;
+       struct nand_id id;
+       struct nand_params *param;
+       uint32_t num_pages;
+
+       sc = device_get_softc(dev);
+       sc->dev = dev;
+       sc->dinfo = device_get_ivars(dev);
+
+       sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid,
+           RF_ACTIVE);
+       if (sc->res == NULL) {
+               device_printf(dev, "could not allocate resources!\n");
+               return (ENXIO);
+       }
+
+       bzero(&sc->fcm, sizeof(sc->fcm));
+
+       /* Init register and check if HW ECC turned on */
+       fsl_nand_init_regs(sc);
+
+       /* Chip is probed, so determine number of row address cycles */
+       fsl_nand_chip_preprobe(dev, &id);
+       param = nand_get_params(&id);
+       if (param != NULL) {
+               num_pages = (param->chip_size << 20) / param->page_size;
+               while(num_pages) {
+                       sc->row_cycles++;
+                       num_pages >>= 8;
+               }
+
+               sc->fcm.reg_fmr &= ~(FMR_AL);
+               sc->fcm.reg_fmr |= (sc->row_cycles - 2) << FMR_AL_SHIFT;
+       }
+
+       nand_init(&sc->nand_dev, dev, NAND_ECC_SOFT, 0, 0, NULL, NULL);
+
+#ifdef NAND_DEBUG_TIMING
+       fcm_devs[sc->dinfo->di_bank] = dev;
+#endif
+
+       return (nandbus_create(dev));
+}
+
+static int
+fsl_nand_detach(device_t dev)
+{
+       struct fsl_nand_softc *sc;
+
+       sc = device_get_softc(dev);
+
+       if (sc->res != NULL)
+               bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res);
+
+       return (0);
+}
+
+static int
+fsl_nfc_select_cs(device_t dev, uint8_t cs)
+{
+
+       // device_printf(dev, "%s(cs=%u)\n", __func__, cs);
+       return ((cs > 0) ? EINVAL : 0);
+}
+
+static int
+fsl_nfc_read_rnb(device_t dev)
+{
+
+       // device_printf(dev, "%s()\n", __func__);
+       return (0);
+}
+
+static int
+fsl_nfc_send_command(device_t dev, uint8_t command)
+{
+       struct fsl_nand_softc *sc;
+       struct fsl_nfc_fcm *fcm;
+       uint8_t fir_op;
+
+       // device_printf(dev, "%s(command=%u)\n", __func__, command);
+
+       sc = device_get_softc(dev);
+       fcm = &sc->fcm;
+
+       if (command == NAND_CMD_PROG_END) {
+               fcm->reg_fir |= (FIR_OP_WB << OP_SHIFT(fcm->opnr));
+               fcm->opnr++;
+       }
+       fcm->reg_fcr |= command << CMD_SHIFT(fcm->cmdnr);
+       fir_op = (fcm->cmdnr == 0) ? FIR_OP_CW0 : FIR_OP_CM(fcm->cmdnr);
+       fcm->cmdnr++;
+
+       fcm->reg_fir |= (fir_op << OP_SHIFT(fcm->opnr));
+       fcm->opnr++;
+
+       switch (command) {
+       case NAND_CMD_READ_ID:
+               fcm->data_fir = FIR_OP_RBW;
+               fcm->addr_type = ADDR_ID;
+               break;
+       case NAND_CMD_SMALLOOB:
+               fcm->pg_ofs += 256;
+               /*FALLTHROUGH*/
+       case NAND_CMD_SMALLB:
+               fcm->pg_ofs += 256;
+               /*FALLTHROUGH*/
+       case NAND_CMD_READ: /* NAND_CMD_SMALLA */
+               fcm->data_fir = FIR_OP_RBW;
+               fcm->addr_type = ADDR_ROWCOL;
+               break;
+       case NAND_CMD_STATUS:
+               fcm->data_fir = FIR_OP_RS;
+               fcm->status = 1;
+               break;
+       case NAND_CMD_ERASE:
+               fcm->addr_type = ADDR_ROW;
+               break;
+       case NAND_CMD_PROG:
+               fcm->addr_type = ADDR_ROWCOL;
+               break;
+       }
+       return (0);
+}
+
+static int
+fsl_nfc_send_address(device_t dev, uint8_t addr)
+{
+       struct fsl_nand_softc *sc;
+       struct fsl_nfc_fcm *fcm;
+       uint32_t addr_bits;
+
+       // device_printf(dev, "%s(address=%u)\n", __func__, addr);
+
+       sc = device_get_softc(dev);
+       fcm = &sc->fcm;
+
+       KASSERT(fcm->addr_type != ADDR_NONE,
+           ("controller doesn't expect address cycle"));
+
+       addr_bits = addr;
+
+       if (fcm->addr_type == ADDR_ID) {
+               fcm->reg_fir |= (FIR_OP_UA << OP_SHIFT(fcm->opnr));
+               fcm->opnr++;
+
+               fcm->reg_fbcr = 5;
+               fcm->reg_fbar = 0;
+               fcm->reg_fpar = 0;
+               fcm->reg_mdr = addr_bits;
+               fcm->buf_ofs = 0;
+               fcm->read_ptr = 0;
+               return (0);
+       }
+
+       if (fcm->addr_type == ADDR_ROW) {
+               addr_bits <<= fcm->addr_bytes * 8;
+               fcm->row_addr |= addr_bits;
+               fcm->addr_bytes++;
+               if (fcm->addr_bytes < sc->row_cycles)
+                       return (0);
+       } else {
+               if (fcm->addr_bytes < sc->col_cycles) {
+                       addr_bits <<= fcm->addr_bytes * 8;
+                       fcm->column_addr |= addr_bits;
+               } else {
+                       addr_bits <<= (fcm->addr_bytes - sc->col_cycles) * 8;
+                       fcm->row_addr |= addr_bits;
+               }
+               fcm->addr_bytes++;
+               if (fcm->addr_bytes < (sc->row_cycles + sc->col_cycles))
+                       return (0);
+       }
+
+       return (fsl_nand_build_address(dev, fcm->row_addr, fcm->column_addr));
+}
+
+static int
+fsl_nand_build_address(device_t dev, uint32_t row, uint32_t column)
+{
+       struct fsl_nand_softc *sc;
+       struct fsl_nfc_fcm *fcm;
+       uint32_t byte_count = 0;
+       uint32_t block_address = 0;
+       uint32_t page_address = 0;
+
+       sc = device_get_softc(dev);
+       fcm = &sc->fcm;
+
+       fcm->read_ptr = 0;
+       fcm->buf_ofs = 0;
+
+       if (fcm->addr_type == ADDR_ROWCOL) {
+               fcm->reg_fir |= (FIR_OP_CA << OP_SHIFT(fcm->opnr));
+               fcm->opnr++;
+
+               column += fcm->pg_ofs;
+               fcm->pg_ofs = 0;
+
+               page_address |= column;
+
+               if (column != 0) {
+                       byte_count = sc->pgsz - column;
+                       fcm->read_ptr = column;
+               }
+       }
+
+       fcm->reg_fir |= (FIR_OP_PA << OP_SHIFT(fcm->opnr));
+       fcm->opnr++;
+
+       if (sc->pgsz == FSL_LARGE_PAGE_SIZE) {
+               block_address = row >> 6;
+               page_address |= ((row << FPAR_LP_PI_SHIFT) & FPAR_LP_PI);
+               fcm->buf_ofs = (row & 1) * 4096;
+       } else {
+               block_address = row >> 5;
+               page_address |= ((row << FPAR_SP_PI_SHIFT) & FPAR_SP_PI);
+               fcm->buf_ofs = (row & 7) * 1024;
+       }
+
+       fcm->reg_fbcr = byte_count;
+       fcm->reg_fbar = block_address;
+       fcm->reg_fpar = page_address;
+       return (0);
+}
+
+static int
+fsl_nfc_start_command(device_t dev)
+{
+       struct fsl_nand_softc *sc;
+       struct fsl_nfc_fcm *fcm;
+       uint32_t fmr, ltesr_v;
+       int error, timeout;
+
+       // device_printf(dev, "%s()\n", __func__);
+
+       sc = device_get_softc(dev);
+       fcm = &sc->fcm;
+
+       fmr = fcm->reg_fmr | FMR_OP;
+
+       if (fcm->data_fir)
+               fcm->reg_fir |= (fcm->data_fir << OP_SHIFT(fcm->opnr));
+
+       LBC_WRITE(FIR, fcm->reg_fir);
+       LBC_WRITE(FCR, fcm->reg_fcr);
+
+       LBC_WRITE(FMR, fmr);
+
+       LBC_WRITE(FBCR, fcm->reg_fbcr);
+       LBC_WRITE(FBAR, fcm->reg_fbar);
+       LBC_WRITE(FPAR, fcm->reg_fpar);
+
+       if (fcm->addr_type == ADDR_ID)
+               LBC_WRITE(MDR, fcm->reg_mdr);
+
+       nand_debug(NDBG_DRV, "BEFORE:\nFMR=%#x, FIR=%#x, FCR=%#x", fmr,
+           fcm->reg_fir, fcm->reg_fcr);
+       nand_debug(NDBG_DRV, "MDR=%#x, FBAR=%#x, FPAR=%#x, FBCR=%#x",
+           LBC_READ(MDR), fcm->reg_fbar, fcm->reg_fpar, fcm->reg_fbcr);
+
+       LBC_WRITE(LSOR, sc->dinfo->di_bank);
+
+       timeout = (cold) ? FSL_FCM_WAIT_TIMEOUT : ~0;
+       error = 0;
+       ltesr_v = LBC_READ(LTESR);
+       while (!error && (ltesr_v & LTESR_CC) == 0) {
+               if (cold) {
+                       DELAY(1000);
+                       timeout--;
+                       if (timeout < 0)
+                               error = EWOULDBLOCK;
+               } else
+                       error = tsleep(device_get_parent(sc->dev), PRIBIO,
+                           "nfcfsl", hz);
+               ltesr_v = LBC_READ(LTESR);
+       }
+       if (error)
+               nand_debug(NDBG_DRV, "Command complete wait timeout\n");
+
+       nand_debug(NDBG_DRV, "AFTER:\nLTESR=%#x, LTEDR=%#x, LTEIR=%#x,"
+           " LTEATR=%#x, LTEAR=%#x, LTECCR=%#x", ltesr_v,
+           LBC_READ(LTEDR), LBC_READ(LTEIR), LBC_READ(LTEATR),
+           LBC_READ(LTEAR), LBC_READ(LTECCR));
+
+       bzero(&fcm->fcm_startzero,
+           __rangeof(struct fsl_nfc_fcm, fcm_startzero, fcm_endzero));
+
+       if (fcm->status)
+               sc->fcm.reg_mdr = LBC_READ(MDR);
+
+       /* Even if timeout occured, we should perform steps below */
+       LBC_WRITE(LTESR, ltesr_v);
+       LBC_WRITE(LTEATR, 0);
+
+       return (error);
+}
+
+static uint8_t
+fsl_nfc_read_byte(device_t dev)
+{
+       struct fsl_nand_softc *sc = device_get_softc(dev);
+       uint32_t offset;
+
+       // device_printf(dev, "%s()\n", __func__);
+
+       /*
+        * LBC controller allows us to read status into a MDR instead of FCM
+        * buffer. If last operation requested before read_byte() was STATUS,
+        * then return MDR instead of reading a single byte from a buffer.
+        */
+       if (sc->fcm.status) {
+               sc->fcm.status = 0;
+               return (sc->fcm.reg_mdr);
+       }
+
+       KASSERT(sc->fcm.read_ptr < sc->pgsz,
+           ("Attempt to read beyond buffer %x %x", sc->fcm.read_ptr,
+           sc->pgsz));
+
+       offset = sc->fcm.buf_ofs + sc->fcm.read_ptr;
+       sc->fcm.read_ptr++;
+       return (bus_read_1(sc->res, offset));
+}
+
+static void
+fsl_nfc_read_buf(device_t dev, void *buf, uint32_t len)
+{
+       struct fsl_nand_softc *sc = device_get_softc(dev);
+       uint32_t offset;
+       int bytesleft = 0;
+
+       // device_printf(dev, "%s(buf=%p, len=%u)\n", __func__, buf, len);
+
+       nand_debug(NDBG_DRV, "REQUEST OF 0x%0x B (BIB=0x%0x, NTR=0x%0x)",
+           len, sc->pgsz, sc->fcm.read_ptr);
+
+       bytesleft = MIN((unsigned int)len, sc->pgsz - sc->fcm.read_ptr);
+
+       offset = sc->fcm.buf_ofs + sc->fcm.read_ptr;
+       bus_read_region_1(sc->res, offset, buf, bytesleft);
+       sc->fcm.read_ptr += bytesleft;
+}
+
+static void
+fsl_nfc_write_buf(device_t dev, void *buf, uint32_t len)
+{
+       struct fsl_nand_softc *sc = device_get_softc(dev);
+       uint32_t offset;
+       int bytesleft = 0;
+
+       // device_printf(dev, "%s(buf=%p, len=%u)\n", __func__, buf, len);
+
+       KASSERT(len <= sc->pgsz - sc->fcm.read_ptr,
+           ("Attempt to write beyond buffer"));
+
+       bytesleft = MIN((unsigned int)len, sc->pgsz - sc->fcm.read_ptr);
+
+       nand_debug(NDBG_DRV, "REQUEST TO WRITE 0x%0x (BIB=0x%0x, NTR=0x%0x)",
+           bytesleft, sc->pgsz, sc->fcm.read_ptr);
+
+       offset = sc->fcm.buf_ofs + sc->fcm.read_ptr;
+       bus_write_region_1(sc->res, offset, buf, bytesleft);
+       sc->fcm.read_ptr += bytesleft;
+}
+
+static int
+fsl_nand_chip_preprobe(device_t dev, struct nand_id *id)
+{
+
+       if (fsl_nfc_send_command(dev, NAND_CMD_RESET) != 0)
+               return (ENXIO);
+
+       if (fsl_nfc_start_command(dev) != 0)
+               return (ENXIO);
+
+       DELAY(1000);
+
+       if (fsl_nfc_send_command(dev, NAND_CMD_READ_ID))
+               return (ENXIO);
+
+       if (fsl_nfc_send_address(dev, 0))
+               return (ENXIO);
+
+       if (fsl_nfc_start_command(dev) != 0)
+               return (ENXIO);
+
+       DELAY(25);
+
+       id->man_id = fsl_nfc_read_byte(dev);
+       id->dev_id = fsl_nfc_read_byte(dev);
+
+       nand_debug(NDBG_DRV, "manufacturer id: %x chip id: %x",
+           id->man_id, id->dev_id);
+
+       return (0);
+}
+
+#ifdef NAND_DEBUG_TIMING
+
+static SYSCTL_NODE(_debug, OID_AUTO, fcm, CTLFLAG_RD, 0, "FCM timing");
+
+static u_int csct = 1; /* 22:    Chip select to command time (trlx). */
+SYSCTL_UINT(_debug_fcm, OID_AUTO, csct, CTLFLAG_RW, &csct, 1,
+    "Chip select to command time: determines how far in advance -LCSn is "
+    "asserted prior to any bus activity during a NAND Flash access handled "
+    "by the FCM. This helps meet chip-select setup times for slow memories.");
+
+static u_int cst = 1;  /* 23:    Command setup time (trlx). */
+SYSCTL_UINT(_debug_fcm, OID_AUTO, cst, CTLFLAG_RW, &cst, 1,
+    "Command setup time: determines the delay of -LFWE assertion relative to "
+    "the command, address, or data change when the external memory access "
+    "is handled by the FCM.");
+
+static u_int cht = 1;  /* 24:    Command hold time (trlx). */
+SYSCTL_UINT(_debug_fcm, OID_AUTO, cht, CTLFLAG_RW, &cht, 1,
+    "Command hold time: determines the -LFWE negation prior to the command, "
+    "address, or data change when the external memory access is handled by "
+    "the FCM.");
+
+static u_int scy = 2;  /* 25-27: Cycle length in bus clocks */
+SYSCTL_UINT(_debug_fcm, OID_AUTO, scy, CTLFLAG_RW, &scy, 2,
+    "Cycle length in bus clocks: see RM");
+
+static u_int rst = 1;  /* 28:    Read setup time (trlx). */
+SYSCTL_UINT(_debug_fcm, OID_AUTO, rst, CTLFLAG_RW, &rst, 1,
+    "Read setup time: determines the delay of -LFRE assertion relative to "
+    "sampling of read data when the external memory access is handled by "
+    "the FCM.");
+
+static u_int trlx = 1; /* 29:    Timing relaxed. */
+SYSCTL_UINT(_debug_fcm, OID_AUTO, trlx, CTLFLAG_RW, &trlx, 1,
+    "Timing relaxed: modifies the settings of timing parameters for slow "
+    "memories. See RM");
+
+static u_int ehtr = 1; /* 30:    Extended hold time on read accesses. */
+SYSCTL_UINT(_debug_fcm, OID_AUTO, ehtr, CTLFLAG_RW, &ehtr, 1,
+    "Extended hold time on read accesses: indicates with TRLX how many "
+    "cycles are inserted between a read access from the current bank and "
+    "the next access.");
+
+static u_int
+fsl_nand_get_timing(void)
+{
+       u_int timing;
+
+       timing = ((csct & 1) << 9) | ((cst & 1) << 8) | ((cht & 1) << 7) |
+           ((scy & 7) << 4) | ((rst & 1) << 3) | ((trlx & 1) << 2) |
+           ((ehtr & 1) << 1);
+
+       printf("nfc_fsl: timing = %u\n", timing);
+       return (timing);
+}
+
+static int
+fsl_sysctl_program(SYSCTL_HANDLER_ARGS)
+{
+       struct fsl_nand_softc *sc;
+       int error, i;
+       device_t dev;
+       uint32_t or_v;
+
+       error = sysctl_wire_old_buffer(req, sizeof(int));
+       if (error == 0) {
+               i = 0;
+               error = sysctl_handle_int(oidp, &i, 0, req);
+       }
+       if (error != 0 || req->newptr == NULL)
+               return (error);
+
+       for (i = 0; i < 8; i++) {
+               dev = fcm_devs[i];
+               if (dev == NULL)
+                       continue;
+               sc = device_get_softc(dev);
+
+               /* Reprogram OR(x) */
+               or_v = lbc_read_reg(dev, LBC85XX_OR(sc->dinfo->di_bank));
+               or_v &= 0xfffffc00;
+               or_v |= fsl_nand_get_timing();
+               lbc_write_reg(dev, LBC85XX_OR(sc->dinfo->di_bank), or_v);
+       }
+       return (0);
+}
+
+SYSCTL_PROC(_debug_fcm, OID_AUTO, program, CTLTYPE_INT | CTLFLAG_RW, NULL, 0,
+    fsl_sysctl_program, "I", "write to program FCM with current values");
+
+#endif /* NAND_DEBUG_TIMING */

Added: head/sys/dev/nand/nfc_fsl.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/nand/nfc_fsl.h Tue Jul  3 01:00:29 2012        (r238046)
@@ -0,0 +1,97 @@
+/*-
+ * Copyright (C) 2012 Juniper Networks, Inc.
+ * 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 _NAND_NFC_FSL_H_
+#define        _NAND_NFC_FSL_H_
+
+/* LBC BR/OR Registers layout definitions */
+#define BR_V           0x00000001
+#define BR_V_SHIFT     0
+#define BR_MSEL                0x000000E0
+#define BR_MSEL_SHIFT  5
+#define BR_DECC_CHECK_MODE     0x00000600
+#define BR_DECC_CHECK_GEN      0x00000400
+
+#define OR_FCM_PAGESIZE                0x00000400
+
+/* Options definitions */
+#define NAND_OPT_ECC_MODE_HW   1
+#define NAND_OPT_ECC_MODE_SOFT (1 << 1)
+
+/* FMR - Flash Mode Register */
+#define FMR_CWTO       0xF000
+#define FMR_CWTO_SHIFT 12
+#define FMR_BOOT       0x0800
+#define FMR_ECCM       0x0100
+#define FMR_AL         0x0030
+#define FMR_AL_SHIFT   4
+#define FMR_OP         0x0003
+#define FMR_OP_SHIFT   0
+
+#define FIR_OP_NOP     0x0 /* No operation and end of sequence */
+#define FIR_OP_CA      0x1 /* Issue current column address */
+#define FIR_OP_PA      0x2 /* Issue current block+page address */
+#define FIR_OP_UA      0x3 /* Issue user defined address */
+#define        FIR_OP_CM(x)    (4 + (x))       /* Issue command from 
FCR[CMD(x)] */
+#define FIR_OP_WB      0x8 /* Write FBCR bytes from FCM buffer */
+#define FIR_OP_WS      0x9 /* Write 1 or 2 bytes from MDR[AS] */
+#define FIR_OP_RB      0xA /* Read FBCR bytes to FCM buffer */
+#define FIR_OP_RS      0xB /* Read 1 or 2 bytes to MDR[AS] */
+#define FIR_OP_CW0     0xC /* Wait then issue FCR[CMD0] */
+#define FIR_OP_CW1     0xD /* Wait then issue FCR[CMD1] */
+#define FIR_OP_RBW     0xE /* Wait then read FBCR bytes */
+#define FIR_OP_RSW     0xF /* Wait then read 1 or 2 bytes */
+
+/* LTESR - Transfer Error Status Register */
+#define LTESR_BM       0x80000000
+#define LTESR_FCT      0x40000000
+#define LTESR_PAR      0x20000000
+#define LTESR_WP       0x04000000
+#define LTESR_ATMW     0x00800000
+#define LTESR_ATMR     0x00400000
+#define LTESR_CS       0x00080000
+#define LTESR_CC       0x00000001
+
+#define LTESR_NAND_MASK        (LTESR_FCT | LTESR_CC | LTESR_CS)
+
+/* FPAR - Flash Page Address Register */
+#define FPAR_SP_PI             0x00007C00
+#define FPAR_SP_PI_SHIFT       10
+#define FPAR_SP_MS             0x00000200
+#define FPAR_SP_CI             0x000001FF
+#define FPAR_SP_CI_SHIFT       0
+#define FPAR_LP_PI             0x0003F000
+#define FPAR_LP_PI_SHIFT       12
+#define FPAR_LP_MS             0x00000800
+#define FPAR_LP_CI             0x000007FF
+#define FPAR_LP_CI_SHIFT       0
+
+#define FSL_FCM_WAIT_TIMEOUT   10
+
+#endif /* _NAND_NFC_FSL_H_ */
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to