uboot/drivers/mtd/nand/ndfc.c
<<
>>
Prefs
   1/*
   2 * Overview:
   3 *   Platform independend driver for NDFC (NanD Flash Controller)
   4 *   integrated into IBM/AMCC PPC4xx cores
   5 *
   6 * (C) Copyright 2006-2009
   7 * Stefan Roese, DENX Software Engineering, sr@denx.de.
   8 *
   9 * Based on original work by
  10 *      Thomas Gleixner
  11 *      Copyright 2006 IBM
  12 *
  13 * SPDX-License-Identifier:     GPL-2.0+
  14 */
  15
  16#include <common.h>
  17#include <nand.h>
  18#include <linux/mtd/ndfc.h>
  19#include <linux/mtd/nand_ecc.h>
  20#include <asm/processor.h>
  21#include <asm/io.h>
  22#include <asm/ppc4xx.h>
  23
  24#ifndef CONFIG_SYS_NAND_BCR
  25#define CONFIG_SYS_NAND_BCR 0x80002222
  26#endif
  27#ifndef CONFIG_SYS_NDFC_EBC0_CFG
  28#define CONFIG_SYS_NDFC_EBC0_CFG 0xb8400000
  29#endif
  30
  31/*
  32 * We need to store the info, which chip-select (CS) is used for the
  33 * chip number. For example on Sequoia NAND chip #0 uses
  34 * CS #3.
  35 */
  36static int ndfc_cs[NDFC_MAX_BANKS];
  37
  38static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
  39{
  40        struct nand_chip *this = mtd->priv;
  41        ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
  42
  43        if (cmd == NAND_CMD_NONE)
  44                return;
  45
  46        if (ctrl & NAND_CLE)
  47                out_8((u8 *)(base + NDFC_CMD), cmd & 0xFF);
  48        else
  49                out_8((u8 *)(base + NDFC_ALE), cmd & 0xFF);
  50}
  51
  52static int ndfc_dev_ready(struct mtd_info *mtdinfo)
  53{
  54        struct nand_chip *this = mtdinfo->priv;
  55        ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
  56
  57        return (in_be32((u32 *)(base + NDFC_STAT)) & NDFC_STAT_IS_READY);
  58}
  59
  60static void ndfc_enable_hwecc(struct mtd_info *mtdinfo, int mode)
  61{
  62        struct nand_chip *this = mtdinfo->priv;
  63        ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
  64        u32 ccr;
  65
  66        ccr = in_be32((u32 *)(base + NDFC_CCR));
  67        ccr |= NDFC_CCR_RESET_ECC;
  68        out_be32((u32 *)(base + NDFC_CCR), ccr);
  69}
  70
  71static int ndfc_calculate_ecc(struct mtd_info *mtdinfo,
  72                              const u_char *dat, u_char *ecc_code)
  73{
  74        struct nand_chip *this = mtdinfo->priv;
  75        ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
  76        u32 ecc;
  77        u8 *p = (u8 *)&ecc;
  78
  79        ecc = in_be32((u32 *)(base + NDFC_ECC));
  80
  81        /* The NDFC uses Smart Media (SMC) bytes order
  82         */
  83        ecc_code[0] = p[1];
  84        ecc_code[1] = p[2];
  85        ecc_code[2] = p[3];
  86
  87        return 0;
  88}
  89
  90/*
  91 * Speedups for buffer read/write/verify
  92 *
  93 * NDFC allows 32bit read/write of data. So we can speed up the buffer
  94 * functions. No further checking, as nand_base will always read/write
  95 * page aligned.
  96 */
  97static void ndfc_read_buf(struct mtd_info *mtdinfo, uint8_t *buf, int len)
  98{
  99        struct nand_chip *this = mtdinfo->priv;
 100        ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
 101        uint32_t *p = (uint32_t *) buf;
 102
 103        for (;len > 0; len -= 4)
 104                *p++ = in_be32((u32 *)(base + NDFC_DATA));
 105}
 106
 107/*
 108 * Don't use these speedup functions in NAND boot image, since the image
 109 * has to fit into 4kByte.
 110 */
 111static void ndfc_write_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len)
 112{
 113        struct nand_chip *this = mtdinfo->priv;
 114        ulong base = (ulong) this->IO_ADDR_W & 0xffffff00;
 115        uint32_t *p = (uint32_t *) buf;
 116
 117        for (; len > 0; len -= 4)
 118                out_be32((u32 *)(base + NDFC_DATA), *p++);
 119}
 120
 121/*
 122 * Read a byte from the NDFC.
 123 */
 124static uint8_t ndfc_read_byte(struct mtd_info *mtd)
 125{
 126
 127        struct nand_chip *chip = mtd->priv;
 128
 129#ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT
 130        return (uint8_t) readw(chip->IO_ADDR_R);
 131#else
 132        return readb(chip->IO_ADDR_R);
 133#endif
 134
 135}
 136
 137void board_nand_select_device(struct nand_chip *nand, int chip)
 138{
 139        /*
 140         * Don't use "chip" to address the NAND device,
 141         * generate the cs from the address where it is encoded.
 142         */
 143        ulong base = (ulong)nand->IO_ADDR_W & 0xffffff00;
 144        int cs = ndfc_cs[chip];
 145
 146        /* Set NandFlash Core Configuration Register */
 147        /* 1 col x 2 rows */
 148        out_be32((u32 *)(base + NDFC_CCR), 0x00000000 | (cs << 24));
 149        out_be32((u32 *)(base + NDFC_BCFG0 + (cs << 2)), CONFIG_SYS_NAND_BCR);
 150}
 151
 152static void ndfc_select_chip(struct mtd_info *mtd, int chip)
 153{
 154        /*
 155         * Nothing to do here!
 156         */
 157}
 158
 159int board_nand_init(struct nand_chip *nand)
 160{
 161        int cs = (ulong)nand->IO_ADDR_W & 0x00000003;
 162        ulong base = (ulong)nand->IO_ADDR_W & 0xffffff00;
 163        static int chip = 0;
 164
 165        /*
 166         * Save chip-select for this chip #
 167         */
 168        ndfc_cs[chip] = cs;
 169
 170        /*
 171         * Select required NAND chip in NDFC
 172         */
 173        board_nand_select_device(nand, chip);
 174
 175        nand->IO_ADDR_R = (void __iomem *)(base + NDFC_DATA);
 176        nand->IO_ADDR_W = (void __iomem *)(base + NDFC_DATA);
 177        nand->cmd_ctrl = ndfc_hwcontrol;
 178        nand->chip_delay = 50;
 179        nand->read_buf = ndfc_read_buf;
 180        nand->dev_ready = ndfc_dev_ready;
 181        nand->ecc.correct = nand_correct_data;
 182        nand->ecc.hwctl = ndfc_enable_hwecc;
 183        nand->ecc.calculate = ndfc_calculate_ecc;
 184        nand->ecc.mode = NAND_ECC_HW;
 185        nand->ecc.size = 256;
 186        nand->ecc.bytes = 3;
 187        nand->ecc.strength = 1;
 188        nand->select_chip = ndfc_select_chip;
 189
 190#ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT
 191        nand->options |= NAND_BUSWIDTH_16;
 192#endif
 193
 194        nand->write_buf  = ndfc_write_buf;
 195        nand->read_byte = ndfc_read_byte;
 196
 197        chip++;
 198
 199        return 0;
 200}
 201