The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm/freescale/vybrid/vf_nfc.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 /*
   30  * Vybrid Family NAND Flash Controller (NFC)
   31  * Chapter 31, Vybrid Reference Manual, Rev. 5, 07/2013
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD: head/sys/arm/freescale/vybrid/vf_nfc.c 326258 2017-11-27 15:04:10Z pfg $");
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/proc.h>
   40 #include <sys/bus.h>
   41 #include <sys/conf.h>
   42 #include <sys/kernel.h>
   43 #include <sys/module.h>
   44 #include <sys/malloc.h>
   45 #include <sys/rman.h>
   46 #include <sys/lock.h>
   47 #include <sys/mutex.h>
   48 #include <sys/time.h>
   49 
   50 #include <dev/ofw/ofw_bus.h>
   51 #include <dev/ofw/ofw_bus_subr.h>
   52 #include <dev/nand/nand.h>
   53 #include <dev/nand/nandbus.h>
   54 
   55 #include <machine/bus.h>
   56 
   57 #include "nfc_if.h"
   58 
   59 #include <arm/freescale/vybrid/vf_common.h>
   60 
   61 enum addr_type {
   62         ADDR_NONE,
   63         ADDR_ID,
   64         ADDR_ROW,
   65         ADDR_ROWCOL
   66 };
   67 
   68 struct fsl_nfc_fcm {
   69         uint32_t        addr_bits;
   70         enum addr_type  addr_type;
   71         uint32_t        col_addr_bits;
   72         uint32_t        row_addr_bits;
   73         u_int           read_ptr;
   74         u_int           addr_ptr;
   75         u_int           command;
   76         u_int           code;
   77 };
   78 
   79 struct vf_nand_softc {
   80         struct nand_softc       nand_dev;
   81         bus_space_handle_t      bsh;
   82         bus_space_tag_t         bst;
   83         struct resource         *res[2];
   84         struct fsl_nfc_fcm      fcm;
   85 };
   86 
   87 static struct resource_spec nfc_spec[] = {
   88         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
   89         { SYS_RES_IRQ,          0,      RF_ACTIVE },
   90         { -1, 0 }
   91 };
   92 
   93 static int      vf_nand_attach(device_t);
   94 static int      vf_nand_probe(device_t);
   95 static int      vf_nand_send_command(device_t, uint8_t);
   96 static int      vf_nand_send_address(device_t, uint8_t);
   97 static int      vf_nand_start_command(device_t);
   98 static uint8_t  vf_nand_read_byte(device_t);
   99 static void     vf_nand_read_buf(device_t, void *, uint32_t);
  100 static void     vf_nand_write_buf(device_t, void *, uint32_t);
  101 static int      vf_nand_select_cs(device_t, uint8_t);
  102 static int      vf_nand_read_rnb(device_t);
  103 
  104 #define CMD_READ_PAGE           0x7EE0
  105 #define CMD_PROG_PAGE           0x7FC0
  106 #define CMD_PROG_PAGE_DMA       0xFFC8
  107 #define CMD_ERASE               0x4EC0
  108 #define CMD_READ_ID             0x4804
  109 #define CMD_READ_STATUS         0x4068
  110 #define CMD_RESET               0x4040
  111 #define CMD_RANDOM_IN           0x7140
  112 #define CMD_RANDOM_OUT          0x70E0
  113 
  114 #define CMD_BYTE2_PROG_PAGE     0x10
  115 #define CMD_BYTE2_PAGE_READ     0x30
  116 #define CMD_BYTE2_ERASE         0xD0
  117 
  118 #define NFC_CMD1        0x3F00  /* Flash command 1 */
  119 #define NFC_CMD2        0x3F04  /* Flash command 2 */
  120 #define NFC_CAR         0x3F08  /* Column address */
  121 #define NFC_RAR         0x3F0C  /* Row address */
  122 #define NFC_RPT         0x3F10  /* Flash command repeat */
  123 #define NFC_RAI         0x3F14  /* Row address increment */
  124 #define NFC_SR1         0x3F18  /* Flash status 1 */
  125 #define NFC_SR2         0x3F1C  /* Flash status 2 */
  126 #define NFC_DMA_CH1     0x3F20  /* DMA channel 1 address */
  127 #define NFC_DMACFG      0x3F24  /* DMA configuration */
  128 #define NFC_SWAP        0x3F28  /* Cach swap */
  129 #define NFC_SECSZ       0x3F2C  /* Sector size */
  130 #define NFC_CFG         0x3F30  /* Flash configuration */
  131 #define NFC_DMA_CH2     0x3F34  /* DMA channel 2 address */
  132 #define NFC_ISR         0x3F38  /* Interrupt status */
  133 
  134 #define ECCMODE_SHIFT           17
  135 #define AIAD_SHIFT              5
  136 #define AIBN_SHIFT              4
  137 #define PAGECOUNT_SHIFT         0
  138 #define BITWIDTH_SHIFT          7
  139 #define BITWIDTH8               0
  140 #define BITWIDTH16              1
  141 #define PAGECOUNT_MASK          0xf
  142 
  143 #define CMD2_BYTE1_SHIFT        24
  144 #define CMD2_CODE_SHIFT         8
  145 #define CMD2_BUFNO_SHIFT        1
  146 #define CMD2_START_SHIFT        0
  147 
  148 static device_method_t vf_nand_methods[] = {
  149         DEVMETHOD(device_probe,         vf_nand_probe),
  150         DEVMETHOD(device_attach,        vf_nand_attach),
  151         DEVMETHOD(nfc_start_command,    vf_nand_start_command),
  152         DEVMETHOD(nfc_send_command,     vf_nand_send_command),
  153         DEVMETHOD(nfc_send_address,     vf_nand_send_address),
  154         DEVMETHOD(nfc_read_byte,        vf_nand_read_byte),
  155         DEVMETHOD(nfc_read_buf,         vf_nand_read_buf),
  156         DEVMETHOD(nfc_write_buf,        vf_nand_write_buf),
  157         DEVMETHOD(nfc_select_cs,        vf_nand_select_cs),
  158         DEVMETHOD(nfc_read_rnb,         vf_nand_read_rnb),
  159         { 0, 0 },
  160 };
  161 
  162 static driver_t vf_nand_driver = {
  163         "nand",
  164         vf_nand_methods,
  165         sizeof(struct vf_nand_softc),
  166 };
  167 
  168 static devclass_t vf_nand_devclass;
  169 DRIVER_MODULE(vf_nand, simplebus, vf_nand_driver, vf_nand_devclass, 0, 0);
  170 
  171 static int
  172 vf_nand_probe(device_t dev)
  173 {
  174 
  175         if (!ofw_bus_status_okay(dev))
  176                 return (ENXIO);
  177 
  178         if (!ofw_bus_is_compatible(dev, "fsl,mvf600-nand"))
  179                 return (ENXIO);
  180 
  181         device_set_desc(dev, "Vybrid Family NAND controller");
  182         return (BUS_PROBE_DEFAULT);
  183 }
  184 
  185 static int
  186 vf_nand_attach(device_t dev)
  187 {
  188         struct vf_nand_softc *sc;
  189         int err;
  190         int reg;
  191 
  192         sc = device_get_softc(dev);
  193         if (bus_alloc_resources(dev, nfc_spec, sc->res)) {
  194                 device_printf(dev, "could not allocate resources!\n");
  195                 return (ENXIO);
  196         }
  197 
  198         sc->bst = rman_get_bustag(sc->res[0]);
  199         sc->bsh = rman_get_bushandle(sc->res[0]);
  200 
  201         /* Size in bytes of one elementary transfer unit */
  202         WRITE4(sc, NFC_SECSZ, 2048);
  203 
  204         /* Flash mode width */
  205         reg = READ4(sc, NFC_CFG);
  206         reg |= (BITWIDTH16 << BITWIDTH_SHIFT);
  207 
  208         /* No correction, ECC bypass */
  209         reg &= ~(0x7 << ECCMODE_SHIFT);
  210 
  211         /* Disable Auto-incrementing of flash row address */
  212         reg &= ~(0x1 << AIAD_SHIFT);
  213 
  214         /* Disable Auto-incrementing of buffer numbers */
  215         reg &= ~(0x1 << AIBN_SHIFT);
  216 
  217         /*
  218          * Number of virtual pages (in one physical flash page)
  219          * to be programmed or read, etc.
  220          */
  221         reg &= ~(PAGECOUNT_MASK);
  222         reg |= (1 << PAGECOUNT_SHIFT);
  223         WRITE4(sc, NFC_CFG, reg);
  224 
  225         nand_init(&sc->nand_dev, dev, NAND_ECC_NONE, 0, 0, NULL, NULL);
  226         err = nandbus_create(dev);
  227         return (err);
  228 }
  229 
  230 static int
  231 vf_nand_start_command(device_t dev)
  232 {
  233         struct vf_nand_softc *sc;
  234         struct fsl_nfc_fcm *fcm;
  235         int reg;
  236 
  237         sc = device_get_softc(dev);
  238         fcm = &sc->fcm;
  239 
  240         nand_debug(NDBG_DRV,"vf_nand: start command %x", fcm->command);
  241 
  242         /* CMD2 */
  243         reg = READ4(sc, NFC_CMD2);
  244         reg &= ~(0xff << CMD2_BYTE1_SHIFT);
  245         reg |= (fcm->command << CMD2_BYTE1_SHIFT);
  246         WRITE4(sc, NFC_CMD2, reg);
  247 
  248         /* CMD1 */
  249         if ((fcm->command == NAND_CMD_READ) ||
  250             (fcm->command == NAND_CMD_PROG) ||
  251             (fcm->command == NAND_CMD_ERASE)) {
  252                 reg = READ4(sc, NFC_CMD1);
  253                 reg &= ~(0xff << 24);
  254 
  255                 if (fcm->command == NAND_CMD_READ)
  256                         reg |= (CMD_BYTE2_PAGE_READ << 24);
  257                 else if (fcm->command == NAND_CMD_PROG)
  258                         reg |= (CMD_BYTE2_PROG_PAGE << 24);
  259                 else if (fcm->command == NAND_CMD_ERASE)
  260                         reg |= (CMD_BYTE2_ERASE << 24);
  261 
  262                 WRITE4(sc, NFC_CMD1, reg);
  263         }
  264 
  265         /* We work with 1st buffer */
  266         reg = READ4(sc, NFC_CMD2);
  267         reg &= ~(0xf << CMD2_BUFNO_SHIFT);
  268         reg |= (0 << CMD2_BUFNO_SHIFT);
  269         WRITE4(sc, NFC_CMD2, reg);
  270 
  271         /* Cmd CODE */
  272         reg = READ4(sc, NFC_CMD2);
  273         reg &= ~(0xffff << CMD2_CODE_SHIFT);
  274         reg |= (fcm->code << CMD2_CODE_SHIFT);
  275         WRITE4(sc, NFC_CMD2, reg);
  276 
  277         /* Col */
  278         if (fcm->addr_type == ADDR_ROWCOL) {
  279                 reg = READ4(sc, NFC_CAR);
  280                 reg &= ~(0xffff);
  281                 reg |= fcm->col_addr_bits;
  282                 nand_debug(NDBG_DRV,"setting CAR to 0x%08x\n", reg);
  283                 WRITE4(sc, NFC_CAR, reg);
  284         }
  285 
  286         /* Row */
  287         reg = READ4(sc, NFC_RAR);
  288         reg &= ~(0xffffff);
  289         if (fcm->addr_type == ADDR_ID)
  290                 reg |= fcm->addr_bits;
  291         else
  292                 reg |= fcm->row_addr_bits;
  293         WRITE4(sc, NFC_RAR, reg);
  294 
  295         /* Start */
  296         reg = READ4(sc, NFC_CMD2);
  297         reg |= (1 << CMD2_START_SHIFT);
  298         WRITE4(sc, NFC_CMD2, reg);
  299 
  300         /* Wait command completion */
  301         while (READ4(sc, NFC_CMD2) & (1 << CMD2_START_SHIFT))
  302                 ;
  303 
  304         return (0);
  305 }
  306 
  307 static int
  308 vf_nand_send_command(device_t dev, uint8_t command)
  309 {
  310         struct vf_nand_softc *sc;
  311         struct fsl_nfc_fcm *fcm;
  312 
  313         nand_debug(NDBG_DRV,"vf_nand: send command %x", command);
  314 
  315         sc = device_get_softc(dev);
  316         fcm = &sc->fcm;
  317 
  318         if ((command == NAND_CMD_READ_END) ||
  319             (command == NAND_CMD_PROG_END) ||
  320             (command == NAND_CMD_ERASE_END)) {
  321                 return (0);
  322         }
  323 
  324         fcm->command = command;
  325 
  326         fcm->code = 0;
  327         fcm->read_ptr = 0;
  328         fcm->addr_type = 0;
  329         fcm->addr_bits = 0;
  330 
  331         fcm->addr_ptr = 0;
  332         fcm->col_addr_bits = 0;
  333         fcm->row_addr_bits = 0;
  334 
  335         switch (command) {
  336         case NAND_CMD_READ:
  337                 fcm->code = CMD_READ_PAGE;
  338                 fcm->addr_type = ADDR_ROWCOL;
  339                 break;
  340         case NAND_CMD_PROG:
  341                 fcm->code = CMD_PROG_PAGE;
  342                 fcm->addr_type = ADDR_ROWCOL;
  343                 break;
  344         case NAND_CMD_PROG_END:
  345                 break;
  346         case NAND_CMD_ERASE_END:
  347                 break;
  348         case NAND_CMD_RESET:
  349                 fcm->code = CMD_RESET;
  350                 break;
  351         case NAND_CMD_READ_ID:
  352                 fcm->code = CMD_READ_ID;
  353                 fcm->addr_type = ADDR_ID;
  354                 break;
  355         case NAND_CMD_READ_PARAMETER:
  356                 fcm->code = CMD_READ_PAGE;
  357                 fcm->addr_type = ADDR_ID;
  358                 break;
  359         case NAND_CMD_STATUS:
  360                 fcm->code = CMD_READ_STATUS;
  361                 break;
  362         case NAND_CMD_ERASE:
  363                 fcm->code = CMD_ERASE;
  364                 fcm->addr_type = ADDR_ROW;
  365                 break;
  366         default:
  367                 nand_debug(NDBG_DRV, "unknown command %d\n", command);
  368                 return (1);
  369         }
  370 
  371         return (0);
  372 }
  373 
  374 static int
  375 vf_nand_send_address(device_t dev, uint8_t addr)
  376 {
  377         struct vf_nand_softc *sc;
  378         struct fsl_nfc_fcm *fcm;
  379 
  380         nand_debug(NDBG_DRV,"vf_nand: send address %x", addr);
  381         sc = device_get_softc(dev);
  382         fcm = &sc->fcm;
  383 
  384         nand_debug(NDBG_DRV, "setting addr #%d to 0x%02x\n", fcm->addr_ptr, addr);
  385 
  386         if (fcm->addr_type == ADDR_ID) {
  387                 fcm->addr_bits = addr;
  388         } else if (fcm->addr_type == ADDR_ROWCOL) {
  389 
  390                 if (fcm->addr_ptr < 2)
  391                         fcm->col_addr_bits |= (addr << (fcm->addr_ptr * 8));
  392                 else
  393                         fcm->row_addr_bits |= (addr << ((fcm->addr_ptr - 2) * 8));
  394 
  395         } else if (fcm->addr_type == ADDR_ROW)
  396                 fcm->row_addr_bits |= (addr << (fcm->addr_ptr * 8));
  397 
  398         fcm->addr_ptr += 1;
  399 
  400         return (0);
  401 }
  402 
  403 static uint8_t
  404 vf_nand_read_byte(device_t dev)
  405 {
  406         struct vf_nand_softc *sc;
  407         struct fsl_nfc_fcm *fcm;
  408         uint8_t data;
  409         int sr1, sr2;
  410         int b;
  411 
  412         sc = device_get_softc(dev);
  413         fcm = &sc->fcm;
  414 
  415         sr1 = READ4(sc, NFC_SR1);
  416         sr2 = READ4(sc, NFC_SR2);
  417 
  418         data = 0;
  419         if (fcm->addr_type == ADDR_ID) {
  420                 b = 32 - ((fcm->read_ptr + 1) * 8);
  421                 data = (sr1 >> b) & 0xff;
  422                 fcm->read_ptr++;
  423         } else if (fcm->command == NAND_CMD_STATUS) {
  424                 data = sr2 & 0xff;
  425         }
  426 
  427         nand_debug(NDBG_DRV,"vf_nand: read %x", data);
  428         return (data);
  429 }
  430 
  431 static void
  432 vf_nand_read_buf(device_t dev, void* buf, uint32_t len)
  433 {
  434         struct vf_nand_softc *sc;
  435         struct fsl_nfc_fcm *fcm;
  436         uint16_t *tmp;
  437         uint8_t *b;
  438         int i;
  439 
  440         b = (uint8_t*)buf;
  441         sc = device_get_softc(dev);
  442         fcm = &sc->fcm;
  443 
  444         nand_debug(NDBG_DRV, "vf_nand: read_buf len %d", len);
  445 
  446         if (fcm->command == NAND_CMD_READ_PARAMETER) {
  447                 tmp = malloc(len, M_DEVBUF, M_NOWAIT);
  448                 bus_read_region_2(sc->res[0], 0x0, tmp, len);
  449 
  450                 for (i = 0; i < len; i += 2) {
  451                         b[i] = tmp[i+1];
  452                         b[i+1] = tmp[i];
  453                 }
  454 
  455                 free(tmp, M_DEVBUF);
  456 
  457 #ifdef NAND_DEBUG
  458                 for (i = 0; i < len; i++) {
  459                         if (!(i % 16))
  460                                 printf("%s", i == 0 ? "vf_nand:\n" : "\n");
  461                         printf(" %x", b[i]);
  462                         if (i == len - 1)
  463                                 printf("\n");
  464                 }
  465 #endif
  466 
  467         } else {
  468 
  469                 for (i = 0; i < len; i++) {
  470                         b[i] = READ1(sc, i);
  471 
  472 #ifdef NAND_DEBUG
  473                         if (!(i % 16))
  474                                 printf("%s", i == 0 ? "vf_nand:\n" : "\n");
  475                         printf(" %x", b[i]);
  476                         if (i == len - 1)
  477                                 printf("\n");
  478 #endif
  479                 }
  480 
  481         }
  482 }
  483 
  484 static void
  485 vf_nand_write_buf(device_t dev, void* buf, uint32_t len)
  486 {
  487         struct vf_nand_softc *sc;
  488         struct fsl_nfc_fcm *fcm;
  489         uint8_t *b;
  490         int i;
  491 
  492         b = (uint8_t*)buf;
  493         sc = device_get_softc(dev);
  494         fcm = &sc->fcm;
  495 
  496         nand_debug(NDBG_DRV,"vf_nand: write_buf len %d", len);
  497 
  498         for (i = 0; i < len; i++) {
  499                 WRITE1(sc, i, b[i]);
  500 
  501 #ifdef NAND_DEBUG
  502                 if (!(i % 16))
  503                         printf("%s", i == 0 ? "vf_nand:\n" : "\n");
  504                 printf(" %x", b[i]);
  505                 if (i == len - 1)
  506                         printf("\n");
  507 #endif
  508 
  509         }
  510 }
  511 
  512 static int
  513 vf_nand_select_cs(device_t dev, uint8_t cs)
  514 {
  515 
  516         if (cs > 0)
  517                 return (ENODEV);
  518 
  519         return (0);
  520 }
  521 
  522 static int
  523 vf_nand_read_rnb(device_t dev)
  524 {
  525 
  526         /* no-op */
  527         return (0); /* ready */
  528 }

Cache object: 068f3f81153a95af7cf92de31edaa214


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.