Commit b37bde147890c8fea8369a5a4e230dabdea4ebfb

Authored by Bryan Wu
Committed by David Woodhouse
1 parent c4a9f88daf

[MTD] [NAND] Blackfin on-chip NAND Flash Controller driver

This is the driver for latest Blackfin on-chip nand flash controller

 - use nand_chip and mtd_info common nand driver interface
 - provide both PIO and dma operation
 - compiled with ezkit bf548 configuration
 - use hardware 1-bit ECC
 - tested with YAFFS2 and can mount YAFFS2 filesystem as rootfs

ChangeLog from try#1
 - use hweight32() instead of count_bits()
 - replace bf54x with bf5xx and BF54X with BF5XX
 - compare against plat->page_size in 2 cases when enable hardware ECC

ChangeLog from try#2
 - passed nand_test suites
 - use cpu_relax() instead of busy wait loop
 - some coding style issue pointed out by Andrew

Signed-off-by: Bryan Wu <bryan.wu@analog.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: David Woodhouse <dwmw2@infradead.org>

Showing 5 changed files with 856 additions and 0 deletions Side-by-side Diff

drivers/mtd/nand/Kconfig
... ... @@ -91,6 +91,25 @@
91 91 This enables the driver for the NAND flash controller on the
92 92 AMD/Alchemy 1550 SOC.
93 93  
  94 +config MTD_NAND_BF5XX
  95 + tristate "Blackfin on-chip NAND Flash Controller driver"
  96 + depends on BF54x && MTD_NAND
  97 + help
  98 + This enables the Blackfin on-chip NAND flash controller
  99 +
  100 + No board specific support is done by this driver, each board
  101 + must advertise a platform_device for the driver to attach.
  102 +
  103 + This driver can also be built as a module. If so, the module
  104 + will be called bf5xx-nand.
  105 +
  106 +config MTD_NAND_BF5XX_HWECC
  107 + bool "BF5XX NAND Hardware ECC"
  108 + depends on MTD_NAND_BF5XX
  109 + help
  110 + Enable the use of the BF5XX's internal ECC generator when
  111 + using NAND.
  112 +
94 113 config MTD_NAND_RTC_FROM4
95 114 tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)"
96 115 depends on SH_SOLUTION_ENGINE
drivers/mtd/nand/Makefile
... ... @@ -13,6 +13,7 @@
13 13 obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o
14 14 obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o
15 15 obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
  16 +obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
16 17 obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o
17 18 obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
18 19 obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
drivers/mtd/nand/bf5xx_nand.c
  1 +/* linux/drivers/mtd/nand/bf5xx_nand.c
  2 + *
  3 + * Copyright 2006-2007 Analog Devices Inc.
  4 + * http://blackfin.uclinux.org/
  5 + * Bryan Wu <bryan.wu@analog.com>
  6 + *
  7 + * Blackfin BF5xx on-chip NAND flash controler driver
  8 + *
  9 + * Derived from drivers/mtd/nand/s3c2410.c
  10 + * Copyright (c) 2007 Ben Dooks <ben@simtec.co.uk>
  11 + *
  12 + * Derived from drivers/mtd/nand/cafe.c
  13 + * Copyright © 2006 Red Hat, Inc.
  14 + * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
  15 + *
  16 + * Changelog:
  17 + * 12-Jun-2007 Bryan Wu: Initial version
  18 + * 18-Jul-2007 Bryan Wu:
  19 + * - ECC_HW and ECC_SW supported
  20 + * - DMA supported in ECC_HW
  21 + * - YAFFS tested as rootfs in both ECC_HW and ECC_SW
  22 + *
  23 + * TODO:
  24 + * Enable JFFS2 over NAND as rootfs
  25 + *
  26 + * This program is free software; you can redistribute it and/or modify
  27 + * it under the terms of the GNU General Public License as published by
  28 + * the Free Software Foundation; either version 2 of the License, or
  29 + * (at your option) any later version.
  30 + *
  31 + * This program is distributed in the hope that it will be useful,
  32 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  33 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  34 + * GNU General Public License for more details.
  35 + *
  36 + * You should have received a copy of the GNU General Public License
  37 + * along with this program; if not, write to the Free Software
  38 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  39 +*/
  40 +
  41 +#include <linux/module.h>
  42 +#include <linux/types.h>
  43 +#include <linux/init.h>
  44 +#include <linux/kernel.h>
  45 +#include <linux/string.h>
  46 +#include <linux/ioport.h>
  47 +#include <linux/platform_device.h>
  48 +#include <linux/delay.h>
  49 +#include <linux/dma-mapping.h>
  50 +#include <linux/err.h>
  51 +#include <linux/slab.h>
  52 +#include <linux/io.h>
  53 +#include <linux/bitops.h>
  54 +
  55 +#include <linux/mtd/mtd.h>
  56 +#include <linux/mtd/nand.h>
  57 +#include <linux/mtd/nand_ecc.h>
  58 +#include <linux/mtd/partitions.h>
  59 +
  60 +#include <asm/blackfin.h>
  61 +#include <asm/dma.h>
  62 +#include <asm/cacheflush.h>
  63 +#include <asm/nand.h>
  64 +#include <asm/portmux.h>
  65 +
  66 +#define DRV_NAME "bf5xx-nand"
  67 +#define DRV_VERSION "1.2"
  68 +#define DRV_AUTHOR "Bryan Wu <bryan.wu@analog.com>"
  69 +#define DRV_DESC "BF5xx on-chip NAND FLash Controller Driver"
  70 +
  71 +#ifdef CONFIG_MTD_NAND_BF5XX_HWECC
  72 +static int hardware_ecc = 1;
  73 +#else
  74 +static int hardware_ecc;
  75 +#endif
  76 +
  77 +static unsigned short bfin_nfc_pin_req[] = {P_NAND_CE, P_NAND_RB, 0};
  78 +
  79 +/*
  80 + * Data structures for bf5xx nand flash controller driver
  81 + */
  82 +
  83 +/* bf5xx nand info */
  84 +struct bf5xx_nand_info {
  85 + /* mtd info */
  86 + struct nand_hw_control controller;
  87 + struct mtd_info mtd;
  88 + struct nand_chip chip;
  89 +
  90 + /* platform info */
  91 + struct bf5xx_nand_platform *platform;
  92 +
  93 + /* device info */
  94 + struct device *device;
  95 +
  96 + /* DMA stuff */
  97 + struct completion dma_completion;
  98 +};
  99 +
  100 +/*
  101 + * Conversion functions
  102 + */
  103 +static struct bf5xx_nand_info *mtd_to_nand_info(struct mtd_info *mtd)
  104 +{
  105 + return container_of(mtd, struct bf5xx_nand_info, mtd);
  106 +}
  107 +
  108 +static struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev)
  109 +{
  110 + return platform_get_drvdata(pdev);
  111 +}
  112 +
  113 +static struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev)
  114 +{
  115 + return pdev->dev.platform_data;
  116 +}
  117 +
  118 +/*
  119 + * struct nand_chip interface function pointers
  120 + */
  121 +
  122 +/*
  123 + * bf5xx_nand_hwcontrol
  124 + *
  125 + * Issue command and address cycles to the chip
  126 + */
  127 +static void bf5xx_nand_hwcontrol(struct mtd_info *mtd, int cmd,
  128 + unsigned int ctrl)
  129 +{
  130 + if (cmd == NAND_CMD_NONE)
  131 + return;
  132 +
  133 + while (bfin_read_NFC_STAT() & WB_FULL)
  134 + cpu_relax();
  135 +
  136 + if (ctrl & NAND_CLE)
  137 + bfin_write_NFC_CMD(cmd);
  138 + else
  139 + bfin_write_NFC_ADDR(cmd);
  140 + SSYNC();
  141 +}
  142 +
  143 +/*
  144 + * bf5xx_nand_devready()
  145 + *
  146 + * returns 0 if the nand is busy, 1 if it is ready
  147 + */
  148 +static int bf5xx_nand_devready(struct mtd_info *mtd)
  149 +{
  150 + unsigned short val = bfin_read_NFC_IRQSTAT();
  151 +
  152 + if ((val & NBUSYIRQ) == NBUSYIRQ)
  153 + return 1;
  154 + else
  155 + return 0;
  156 +}
  157 +
  158 +/*
  159 + * ECC functions
  160 + * These allow the bf5xx to use the controller's ECC
  161 + * generator block to ECC the data as it passes through
  162 + */
  163 +
  164 +/*
  165 + * ECC error correction function
  166 + */
  167 +static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
  168 + u_char *read_ecc, u_char *calc_ecc)
  169 +{
  170 + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
  171 + u32 syndrome[5];
  172 + u32 calced, stored;
  173 + int i;
  174 + unsigned short failing_bit, failing_byte;
  175 + u_char data;
  176 +
  177 + calced = calc_ecc[0] | (calc_ecc[1] << 8) | (calc_ecc[2] << 16);
  178 + stored = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16);
  179 +
  180 + syndrome[0] = (calced ^ stored);
  181 +
  182 + /*
  183 + * syndrome 0: all zero
  184 + * No error in data
  185 + * No action
  186 + */
  187 + if (!syndrome[0] || !calced || !stored)
  188 + return 0;
  189 +
  190 + /*
  191 + * sysdrome 0: only one bit is one
  192 + * ECC data was incorrect
  193 + * No action
  194 + */
  195 + if (hweight32(syndrome[0]) == 1) {
  196 + dev_err(info->device, "ECC data was incorrect!\n");
  197 + return 1;
  198 + }
  199 +
  200 + syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF);
  201 + syndrome[2] = (calced & 0x7FF) ^ ((calced >> 11) & 0x7FF);
  202 + syndrome[3] = (stored & 0x7FF) ^ ((stored >> 11) & 0x7FF);
  203 + syndrome[4] = syndrome[2] ^ syndrome[3];
  204 +
  205 + for (i = 0; i < 5; i++)
  206 + dev_info(info->device, "syndrome[%d] 0x%08x\n", i, syndrome[i]);
  207 +
  208 + dev_info(info->device,
  209 + "calced[0x%08x], stored[0x%08x]\n",
  210 + calced, stored);
  211 +
  212 + /*
  213 + * sysdrome 0: exactly 11 bits are one, each parity
  214 + * and parity' pair is 1 & 0 or 0 & 1.
  215 + * 1-bit correctable error
  216 + * Correct the error
  217 + */
  218 + if (hweight32(syndrome[0]) == 11 && syndrome[4] == 0x7FF) {
  219 + dev_info(info->device,
  220 + "1-bit correctable error, correct it.\n");
  221 + dev_info(info->device,
  222 + "syndrome[1] 0x%08x\n", syndrome[1]);
  223 +
  224 + failing_bit = syndrome[1] & 0x7;
  225 + failing_byte = syndrome[1] >> 0x3;
  226 + data = *(dat + failing_byte);
  227 + data = data ^ (0x1 << failing_bit);
  228 + *(dat + failing_byte) = data;
  229 +
  230 + return 0;
  231 + }
  232 +
  233 + /*
  234 + * sysdrome 0: random data
  235 + * More than 1-bit error, non-correctable error
  236 + * Discard data, mark bad block
  237 + */
  238 + dev_err(info->device,
  239 + "More than 1-bit error, non-correctable error.\n");
  240 + dev_err(info->device,
  241 + "Please discard data, mark bad block\n");
  242 +
  243 + return 1;
  244 +}
  245 +
  246 +static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat,
  247 + u_char *read_ecc, u_char *calc_ecc)
  248 +{
  249 + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
  250 + struct bf5xx_nand_platform *plat = info->platform;
  251 + unsigned short page_size = (plat->page_size ? 512 : 256);
  252 + int ret;
  253 +
  254 + ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
  255 +
  256 + /* If page size is 512, correct second 256 bytes */
  257 + if (page_size == 512) {
  258 + dat += 256;
  259 + read_ecc += 8;
  260 + calc_ecc += 8;
  261 + ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
  262 + }
  263 +
  264 + return ret;
  265 +}
  266 +
  267 +static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode)
  268 +{
  269 + return;
  270 +}
  271 +
  272 +static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,
  273 + const u_char *dat, u_char *ecc_code)
  274 +{
  275 + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
  276 + struct bf5xx_nand_platform *plat = info->platform;
  277 + u16 page_size = (plat->page_size ? 512 : 256);
  278 + u16 ecc0, ecc1;
  279 + u32 code[2];
  280 + u8 *p;
  281 + int bytes = 3, i;
  282 +
  283 + /* first 4 bytes ECC code for 256 page size */
  284 + ecc0 = bfin_read_NFC_ECC0();
  285 + ecc1 = bfin_read_NFC_ECC1();
  286 +
  287 + code[0] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11);
  288 +
  289 + dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]);
  290 +
  291 + /* second 4 bytes ECC code for 512 page size */
  292 + if (page_size == 512) {
  293 + ecc0 = bfin_read_NFC_ECC2();
  294 + ecc1 = bfin_read_NFC_ECC3();
  295 + code[1] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11);
  296 + bytes = 6;
  297 + dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]);
  298 + }
  299 +
  300 + p = (u8 *)code;
  301 + for (i = 0; i < bytes; i++)
  302 + ecc_code[i] = p[i];
  303 +
  304 + return 0;
  305 +}
  306 +
  307 +/*
  308 + * PIO mode for buffer writing and reading
  309 + */
  310 +static void bf5xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
  311 +{
  312 + int i;
  313 + unsigned short val;
  314 +
  315 + /*
  316 + * Data reads are requested by first writing to NFC_DATA_RD
  317 + * and then reading back from NFC_READ.
  318 + */
  319 + for (i = 0; i < len; i++) {
  320 + while (bfin_read_NFC_STAT() & WB_FULL)
  321 + cpu_relax();
  322 +
  323 + /* Contents do not matter */
  324 + bfin_write_NFC_DATA_RD(0x0000);
  325 + SSYNC();
  326 +
  327 + while ((bfin_read_NFC_IRQSTAT() & RD_RDY) != RD_RDY)
  328 + cpu_relax();
  329 +
  330 + buf[i] = bfin_read_NFC_READ();
  331 +
  332 + val = bfin_read_NFC_IRQSTAT();
  333 + val |= RD_RDY;
  334 + bfin_write_NFC_IRQSTAT(val);
  335 + SSYNC();
  336 + }
  337 +}
  338 +
  339 +static uint8_t bf5xx_nand_read_byte(struct mtd_info *mtd)
  340 +{
  341 + uint8_t val;
  342 +
  343 + bf5xx_nand_read_buf(mtd, &val, 1);
  344 +
  345 + return val;
  346 +}
  347 +
  348 +static void bf5xx_nand_write_buf(struct mtd_info *mtd,
  349 + const uint8_t *buf, int len)
  350 +{
  351 + int i;
  352 +
  353 + for (i = 0; i < len; i++) {
  354 + while (bfin_read_NFC_STAT() & WB_FULL)
  355 + cpu_relax();
  356 +
  357 + bfin_write_NFC_DATA_WR(buf[i]);
  358 + SSYNC();
  359 + }
  360 +}
  361 +
  362 +static void bf5xx_nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
  363 +{
  364 + int i;
  365 + u16 *p = (u16 *) buf;
  366 + len >>= 1;
  367 +
  368 + /*
  369 + * Data reads are requested by first writing to NFC_DATA_RD
  370 + * and then reading back from NFC_READ.
  371 + */
  372 + bfin_write_NFC_DATA_RD(0x5555);
  373 +
  374 + SSYNC();
  375 +
  376 + for (i = 0; i < len; i++)
  377 + p[i] = bfin_read_NFC_READ();
  378 +}
  379 +
  380 +static void bf5xx_nand_write_buf16(struct mtd_info *mtd,
  381 + const uint8_t *buf, int len)
  382 +{
  383 + int i;
  384 + u16 *p = (u16 *) buf;
  385 + len >>= 1;
  386 +
  387 + for (i = 0; i < len; i++)
  388 + bfin_write_NFC_DATA_WR(p[i]);
  389 +
  390 + SSYNC();
  391 +}
  392 +
  393 +/*
  394 + * DMA functions for buffer writing and reading
  395 + */
  396 +static irqreturn_t bf5xx_nand_dma_irq(int irq, void *dev_id)
  397 +{
  398 + struct bf5xx_nand_info *info = dev_id;
  399 +
  400 + clear_dma_irqstat(CH_NFC);
  401 + disable_dma(CH_NFC);
  402 + complete(&info->dma_completion);
  403 +
  404 + return IRQ_HANDLED;
  405 +}
  406 +
  407 +static int bf5xx_nand_dma_rw(struct mtd_info *mtd,
  408 + uint8_t *buf, int is_read)
  409 +{
  410 + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
  411 + struct bf5xx_nand_platform *plat = info->platform;
  412 + unsigned short page_size = (plat->page_size ? 512 : 256);
  413 + unsigned short val;
  414 +
  415 + dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n",
  416 + mtd, buf, is_read);
  417 +
  418 + /*
  419 + * Before starting a dma transfer, be sure to invalidate/flush
  420 + * the cache over the address range of your DMA buffer to
  421 + * prevent cache coherency problems. Otherwise very subtle bugs
  422 + * can be introduced to your driver.
  423 + */
  424 + if (is_read)
  425 + invalidate_dcache_range((unsigned int)buf,
  426 + (unsigned int)(buf + page_size));
  427 + else
  428 + flush_dcache_range((unsigned int)buf,
  429 + (unsigned int)(buf + page_size));
  430 +
  431 + /*
  432 + * This register must be written before each page is
  433 + * transferred to generate the correct ECC register
  434 + * values.
  435 + */
  436 + bfin_write_NFC_RST(0x1);
  437 + SSYNC();
  438 +
  439 + disable_dma(CH_NFC);
  440 + clear_dma_irqstat(CH_NFC);
  441 +
  442 + /* setup DMA register with Blackfin DMA API */
  443 + set_dma_config(CH_NFC, 0x0);
  444 + set_dma_start_addr(CH_NFC, (unsigned long) buf);
  445 + set_dma_x_count(CH_NFC, (page_size >> 2));
  446 + set_dma_x_modify(CH_NFC, 4);
  447 +
  448 + /* setup write or read operation */
  449 + val = DI_EN | WDSIZE_32;
  450 + if (is_read)
  451 + val |= WNR;
  452 + set_dma_config(CH_NFC, val);
  453 + enable_dma(CH_NFC);
  454 +
  455 + /* Start PAGE read/write operation */
  456 + if (is_read)
  457 + bfin_write_NFC_PGCTL(0x1);
  458 + else
  459 + bfin_write_NFC_PGCTL(0x2);
  460 + wait_for_completion(&info->dma_completion);
  461 +
  462 + return 0;
  463 +}
  464 +
  465 +static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd,
  466 + uint8_t *buf, int len)
  467 +{
  468 + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
  469 + struct bf5xx_nand_platform *plat = info->platform;
  470 + unsigned short page_size = (plat->page_size ? 512 : 256);
  471 +
  472 + dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len);
  473 +
  474 + if (len == page_size)
  475 + bf5xx_nand_dma_rw(mtd, buf, 1);
  476 + else
  477 + bf5xx_nand_read_buf(mtd, buf, len);
  478 +}
  479 +
  480 +static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd,
  481 + const uint8_t *buf, int len)
  482 +{
  483 + struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
  484 + struct bf5xx_nand_platform *plat = info->platform;
  485 + unsigned short page_size = (plat->page_size ? 512 : 256);
  486 +
  487 + dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len);
  488 +
  489 + if (len == page_size)
  490 + bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0);
  491 + else
  492 + bf5xx_nand_write_buf(mtd, buf, len);
  493 +}
  494 +
  495 +/*
  496 + * System initialization functions
  497 + */
  498 +
  499 +static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info)
  500 +{
  501 + int ret;
  502 + unsigned short val;
  503 +
  504 + /* Do not use dma */
  505 + if (!hardware_ecc)
  506 + return 0;
  507 +
  508 + init_completion(&info->dma_completion);
  509 +
  510 + /* Setup DMAC1 channel mux for NFC which shared with SDH */
  511 + val = bfin_read_DMAC1_PERIMUX();
  512 + val &= 0xFFFE;
  513 + bfin_write_DMAC1_PERIMUX(val);
  514 + SSYNC();
  515 +
  516 + /* Request NFC DMA channel */
  517 + ret = request_dma(CH_NFC, "BF5XX NFC driver");
  518 + if (ret < 0) {
  519 + dev_err(info->device, " unable to get DMA channel\n");
  520 + return ret;
  521 + }
  522 +
  523 + set_dma_callback(CH_NFC, (void *) bf5xx_nand_dma_irq, (void *) info);
  524 +
  525 + /* Turn off the DMA channel first */
  526 + disable_dma(CH_NFC);
  527 + return 0;
  528 +}
  529 +
  530 +/*
  531 + * BF5XX NFC hardware initialization
  532 + * - pin mux setup
  533 + * - clear interrupt status
  534 + */
  535 +static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)
  536 +{
  537 + int err = 0;
  538 + unsigned short val;
  539 + struct bf5xx_nand_platform *plat = info->platform;
  540 +
  541 + /* setup NFC_CTL register */
  542 + dev_info(info->device,
  543 + "page_size=%d, data_width=%d, wr_dly=%d, rd_dly=%d\n",
  544 + (plat->page_size ? 512 : 256),
  545 + (plat->data_width ? 16 : 8),
  546 + plat->wr_dly, plat->rd_dly);
  547 +
  548 + val = (plat->page_size << NFC_PG_SIZE_OFFSET) |
  549 + (plat->data_width << NFC_NWIDTH_OFFSET) |
  550 + (plat->rd_dly << NFC_RDDLY_OFFSET) |
  551 + (plat->rd_dly << NFC_WRDLY_OFFSET);
  552 + dev_dbg(info->device, "NFC_CTL is 0x%04x\n", val);
  553 +
  554 + bfin_write_NFC_CTL(val);
  555 + SSYNC();
  556 +
  557 + /* clear interrupt status */
  558 + bfin_write_NFC_IRQMASK(0x0);
  559 + SSYNC();
  560 + val = bfin_read_NFC_IRQSTAT();
  561 + bfin_write_NFC_IRQSTAT(val);
  562 + SSYNC();
  563 +
  564 + if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) {
  565 + printk(KERN_ERR DRV_NAME
  566 + ": Requesting Peripherals failed\n");
  567 + return -EFAULT;
  568 + }
  569 +
  570 + /* DMA initialization */
  571 + if (bf5xx_nand_dma_init(info))
  572 + err = -ENXIO;
  573 +
  574 + return err;
  575 +}
  576 +
  577 +/*
  578 + * Device management interface
  579 + */
  580 +static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
  581 +{
  582 + struct mtd_info *mtd = &info->mtd;
  583 +
  584 +#ifdef CONFIG_MTD_PARTITIONS
  585 + struct mtd_partition *parts = info->platform->partitions;
  586 + int nr = info->platform->nr_partitions;
  587 +
  588 + return add_mtd_partitions(mtd, parts, nr);
  589 +#else
  590 + return add_mtd_device(mtd);
  591 +#endif
  592 +}
  593 +
  594 +static int bf5xx_nand_remove(struct platform_device *pdev)
  595 +{
  596 + struct bf5xx_nand_info *info = to_nand_info(pdev);
  597 + struct mtd_info *mtd = NULL;
  598 +
  599 + platform_set_drvdata(pdev, NULL);
  600 +
  601 + /* first thing we need to do is release all our mtds
  602 + * and their partitions, then go through freeing the
  603 + * resources used
  604 + */
  605 + mtd = &info->mtd;
  606 + if (mtd) {
  607 + nand_release(mtd);
  608 + kfree(mtd);
  609 + }
  610 +
  611 + peripheral_free_list(bfin_nfc_pin_req);
  612 +
  613 + /* free the common resources */
  614 + kfree(info);
  615 +
  616 + return 0;
  617 +}
  618 +
  619 +/*
  620 + * bf5xx_nand_probe
  621 + *
  622 + * called by device layer when it finds a device matching
  623 + * one our driver can handled. This code checks to see if
  624 + * it can allocate all necessary resources then calls the
  625 + * nand layer to look for devices
  626 + */
  627 +static int bf5xx_nand_probe(struct platform_device *pdev)
  628 +{
  629 + struct bf5xx_nand_platform *plat = to_nand_plat(pdev);
  630 + struct bf5xx_nand_info *info = NULL;
  631 + struct nand_chip *chip = NULL;
  632 + struct mtd_info *mtd = NULL;
  633 + int err = 0;
  634 +
  635 + dev_dbg(&pdev->dev, "(%p)\n", pdev);
  636 +
  637 + if (!plat) {
  638 + dev_err(&pdev->dev, "no platform specific information\n");
  639 + goto exit_error;
  640 + }
  641 +
  642 + info = kzalloc(sizeof(*info), GFP_KERNEL);
  643 + if (info == NULL) {
  644 + dev_err(&pdev->dev, "no memory for flash info\n");
  645 + err = -ENOMEM;
  646 + goto exit_error;
  647 + }
  648 +
  649 + platform_set_drvdata(pdev, info);
  650 +
  651 + spin_lock_init(&info->controller.lock);
  652 + init_waitqueue_head(&info->controller.wq);
  653 +
  654 + info->device = &pdev->dev;
  655 + info->platform = plat;
  656 +
  657 + /* initialise chip data struct */
  658 + chip = &info->chip;
  659 +
  660 + if (plat->data_width)
  661 + chip->options |= NAND_BUSWIDTH_16;
  662 +
  663 + chip->options |= NAND_CACHEPRG | NAND_SKIP_BBTSCAN;
  664 +
  665 + chip->read_buf = (plat->data_width) ?
  666 + bf5xx_nand_read_buf16 : bf5xx_nand_read_buf;
  667 + chip->write_buf = (plat->data_width) ?
  668 + bf5xx_nand_write_buf16 : bf5xx_nand_write_buf;
  669 +
  670 + chip->read_byte = bf5xx_nand_read_byte;
  671 +
  672 + chip->cmd_ctrl = bf5xx_nand_hwcontrol;
  673 + chip->dev_ready = bf5xx_nand_devready;
  674 +
  675 + chip->priv = &info->mtd;
  676 + chip->controller = &info->controller;
  677 +
  678 + chip->IO_ADDR_R = (void __iomem *) NFC_READ;
  679 + chip->IO_ADDR_W = (void __iomem *) NFC_DATA_WR;
  680 +
  681 + chip->chip_delay = 0;
  682 +
  683 + /* initialise mtd info data struct */
  684 + mtd = &info->mtd;
  685 + mtd->priv = chip;
  686 + mtd->owner = THIS_MODULE;
  687 +
  688 + /* initialise the hardware */
  689 + err = bf5xx_nand_hw_init(info);
  690 + if (err != 0)
  691 + goto exit_error;
  692 +
  693 + /* setup hardware ECC data struct */
  694 + if (hardware_ecc) {
  695 + if (plat->page_size == NFC_PG_SIZE_256) {
  696 + chip->ecc.bytes = 3;
  697 + chip->ecc.size = 256;
  698 + } else if (plat->page_size == NFC_PG_SIZE_512) {
  699 + chip->ecc.bytes = 6;
  700 + chip->ecc.size = 512;
  701 + }
  702 +
  703 + chip->read_buf = bf5xx_nand_dma_read_buf;
  704 + chip->write_buf = bf5xx_nand_dma_write_buf;
  705 + chip->ecc.calculate = bf5xx_nand_calculate_ecc;
  706 + chip->ecc.correct = bf5xx_nand_correct_data;
  707 + chip->ecc.mode = NAND_ECC_HW;
  708 + chip->ecc.hwctl = bf5xx_nand_enable_hwecc;
  709 + } else {
  710 + chip->ecc.mode = NAND_ECC_SOFT;
  711 + }
  712 +
  713 + /* scan hardware nand chip and setup mtd info data struct */
  714 + if (nand_scan(mtd, 1)) {
  715 + err = -ENXIO;
  716 + goto exit_error;
  717 + }
  718 +
  719 + /* add NAND partition */
  720 + bf5xx_nand_add_partition(info);
  721 +
  722 + dev_dbg(&pdev->dev, "initialised ok\n");
  723 + return 0;
  724 +
  725 +exit_error:
  726 + bf5xx_nand_remove(pdev);
  727 +
  728 + if (err == 0)
  729 + err = -EINVAL;
  730 + return err;
  731 +}
  732 +
  733 +/* PM Support */
  734 +#ifdef CONFIG_PM
  735 +
  736 +static int bf5xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
  737 +{
  738 + struct bf5xx_nand_info *info = platform_get_drvdata(dev);
  739 +
  740 + return 0;
  741 +}
  742 +
  743 +static int bf5xx_nand_resume(struct platform_device *dev)
  744 +{
  745 + struct bf5xx_nand_info *info = platform_get_drvdata(dev);
  746 +
  747 + if (info)
  748 + bf5xx_nand_hw_init(info);
  749 +
  750 + return 0;
  751 +}
  752 +
  753 +#else
  754 +#define bf5xx_nand_suspend NULL
  755 +#define bf5xx_nand_resume NULL
  756 +#endif
  757 +
  758 +/* driver device registration */
  759 +static struct platform_driver bf5xx_nand_driver = {
  760 + .probe = bf5xx_nand_probe,
  761 + .remove = bf5xx_nand_remove,
  762 + .suspend = bf5xx_nand_suspend,
  763 + .resume = bf5xx_nand_resume,
  764 + .driver = {
  765 + .name = DRV_NAME,
  766 + .owner = THIS_MODULE,
  767 + },
  768 +};
  769 +
  770 +static int __init bf5xx_nand_init(void)
  771 +{
  772 + printk(KERN_INFO "%s, Version %s (c) 2007 Analog Devices, Inc.\n",
  773 + DRV_DESC, DRV_VERSION);
  774 +
  775 + return platform_driver_register(&bf5xx_nand_driver);
  776 +}
  777 +
  778 +static void __exit bf5xx_nand_exit(void)
  779 +{
  780 + platform_driver_unregister(&bf5xx_nand_driver);
  781 +}
  782 +
  783 +module_init(bf5xx_nand_init);
  784 +module_exit(bf5xx_nand_exit);
  785 +
  786 +MODULE_LICENSE("GPL");
  787 +MODULE_AUTHOR(DRV_AUTHOR);
  788 +MODULE_DESCRIPTION(DRV_DESC);
include/asm-blackfin/mach-bf548/dma.h
... ... @@ -55,6 +55,7 @@
55 55 #define CH_SPORT3_RX 20
56 56 #define CH_SPORT3_TX 21
57 57 #define CH_SDH 22
  58 +#define CH_NFC 22
58 59 #define CH_SPI2 23
59 60  
60 61 #define CH_MEM_STREAM0_DEST 24
include/asm-blackfin/nand.h
  1 +/* linux/include/asm-blackfin/nand.h
  2 + *
  3 + * Copyright (c) 2007 Analog Devices, Inc.
  4 + * Bryan Wu <bryan.wu@analog.com>
  5 + *
  6 + * BF5XX - NAND flash controller platfrom_device info
  7 + *
  8 + * This program is free software; you can redistribute it and/or modify
  9 + * it under the terms of the GNU General Public License version 2 as
  10 + * published by the Free Software Foundation.
  11 + */
  12 +
  13 +/* struct bf5xx_nand_platform
  14 + *
  15 + * define a interface between platfrom board specific code and
  16 + * bf54x NFC driver.
  17 + *
  18 + * nr_partitions = number of partitions pointed to be partitoons (or zero)
  19 + * partitions = mtd partition list
  20 + */
  21 +
  22 +#define NFC_PG_SIZE_256 0
  23 +#define NFC_PG_SIZE_512 1
  24 +#define NFC_PG_SIZE_OFFSET 9
  25 +
  26 +#define NFC_NWIDTH_8 0
  27 +#define NFC_NWIDTH_16 1
  28 +#define NFC_NWIDTH_OFFSET 8
  29 +
  30 +#define NFC_RDDLY_OFFSET 4
  31 +#define NFC_WRDLY_OFFSET 0
  32 +
  33 +#define NFC_STAT_NBUSY 1
  34 +
  35 +struct bf5xx_nand_platform {
  36 + /* NAND chip information */
  37 + unsigned short page_size;
  38 + unsigned short data_width;
  39 +
  40 + /* RD/WR strobe delay timing information, all times in SCLK cycles */
  41 + unsigned short rd_dly;
  42 + unsigned short wr_dly;
  43 +
  44 + /* NAND MTD partition information */
  45 + int nr_partitions;
  46 + struct mtd_partition *partitions;
  47 +};