1*fd51b0e0SSergei Poselenov /* 2*fd51b0e0SSergei Poselenov * (C) Copyright 2008 3*fd51b0e0SSergei Poselenov * Sergei Poselenov, Emcraft Systems, sposelenov@emcraft.com. 4*fd51b0e0SSergei Poselenov * 5*fd51b0e0SSergei Poselenov * See file CREDITS for list of people who contributed to this 6*fd51b0e0SSergei Poselenov * project. 7*fd51b0e0SSergei Poselenov * 8*fd51b0e0SSergei Poselenov * This program is free software; you can redistribute it and/or 9*fd51b0e0SSergei Poselenov * modify it under the terms of the GNU General Public License as 10*fd51b0e0SSergei Poselenov * published by the Free Software Foundation; either version 2 of 11*fd51b0e0SSergei Poselenov * the License, or (at your option) any later version. 12*fd51b0e0SSergei Poselenov * 13*fd51b0e0SSergei Poselenov * This program is distributed in the hope that it will be useful, 14*fd51b0e0SSergei Poselenov * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*fd51b0e0SSergei Poselenov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*fd51b0e0SSergei Poselenov * GNU General Public License for more details. 17*fd51b0e0SSergei Poselenov * 18*fd51b0e0SSergei Poselenov * You should have received a copy of the GNU General Public License 19*fd51b0e0SSergei Poselenov * along with this program; if not, write to the Free Software 20*fd51b0e0SSergei Poselenov * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21*fd51b0e0SSergei Poselenov * MA 02111-1307 USA 22*fd51b0e0SSergei Poselenov */ 23*fd51b0e0SSergei Poselenov 24*fd51b0e0SSergei Poselenov #include <common.h> 25*fd51b0e0SSergei Poselenov 26*fd51b0e0SSergei Poselenov #if defined(CFG_NAND_BASE) 27*fd51b0e0SSergei Poselenov #include <nand.h> 28*fd51b0e0SSergei Poselenov #include <asm/errno.h> 29*fd51b0e0SSergei Poselenov #include <asm/io.h> 30*fd51b0e0SSergei Poselenov 31*fd51b0e0SSergei Poselenov static int state; 32*fd51b0e0SSergei Poselenov static void nand_write_byte(struct mtd_info *mtd, u_char byte); 33*fd51b0e0SSergei Poselenov static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len); 34*fd51b0e0SSergei Poselenov static void nand_write_word(struct mtd_info *mtd, u16 word); 35*fd51b0e0SSergei Poselenov static u_char nand_read_byte(struct mtd_info *mtd); 36*fd51b0e0SSergei Poselenov static u16 nand_read_word(struct mtd_info *mtd); 37*fd51b0e0SSergei Poselenov static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len); 38*fd51b0e0SSergei Poselenov static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len); 39*fd51b0e0SSergei Poselenov static int nand_device_ready(struct mtd_info *mtdinfo); 40*fd51b0e0SSergei Poselenov static void nand_hwcontrol(struct mtd_info *mtdinfo, int cmd); 41*fd51b0e0SSergei Poselenov 42*fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_MASK (0x7 << 28) 43*fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_COMMAND (0x0 << 28) 44*fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_ADDR (0x1 << 28) 45*fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_READ (0x2 << 28) 46*fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_WRITE (0x3 << 28) 47*fd51b0e0SSergei Poselenov #define FPGA_NAND_BUSY (0x1 << 15) 48*fd51b0e0SSergei Poselenov #define FPGA_NAND_ENABLE (0x1 << 31) 49*fd51b0e0SSergei Poselenov #define FPGA_NAND_DATA_SHIFT 16 50*fd51b0e0SSergei Poselenov 51*fd51b0e0SSergei Poselenov /** 52*fd51b0e0SSergei Poselenov * nand_write_byte - write one byte to the chip 53*fd51b0e0SSergei Poselenov * @mtd: MTD device structure 54*fd51b0e0SSergei Poselenov * @byte: pointer to data byte to write 55*fd51b0e0SSergei Poselenov */ 56*fd51b0e0SSergei Poselenov static void nand_write_byte(struct mtd_info *mtd, u_char byte) 57*fd51b0e0SSergei Poselenov { 58*fd51b0e0SSergei Poselenov nand_write_buf(mtd, (const uchar *)&byte, sizeof(byte)); 59*fd51b0e0SSergei Poselenov } 60*fd51b0e0SSergei Poselenov 61*fd51b0e0SSergei Poselenov /** 62*fd51b0e0SSergei Poselenov * nand_write_word - write one word to the chip 63*fd51b0e0SSergei Poselenov * @mtd: MTD device structure 64*fd51b0e0SSergei Poselenov * @word: data word to write 65*fd51b0e0SSergei Poselenov */ 66*fd51b0e0SSergei Poselenov static void nand_write_word(struct mtd_info *mtd, u16 word) 67*fd51b0e0SSergei Poselenov { 68*fd51b0e0SSergei Poselenov nand_write_buf(mtd, (const uchar *)&word, sizeof(word)); 69*fd51b0e0SSergei Poselenov } 70*fd51b0e0SSergei Poselenov 71*fd51b0e0SSergei Poselenov /** 72*fd51b0e0SSergei Poselenov * nand_write_buf - write buffer to chip 73*fd51b0e0SSergei Poselenov * @mtd: MTD device structure 74*fd51b0e0SSergei Poselenov * @buf: data buffer 75*fd51b0e0SSergei Poselenov * @len: number of bytes to write 76*fd51b0e0SSergei Poselenov */ 77*fd51b0e0SSergei Poselenov static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) 78*fd51b0e0SSergei Poselenov { 79*fd51b0e0SSergei Poselenov int i; 80*fd51b0e0SSergei Poselenov struct nand_chip *this = mtd->priv; 81*fd51b0e0SSergei Poselenov long val; 82*fd51b0e0SSergei Poselenov 83*fd51b0e0SSergei Poselenov if ((state & FPGA_NAND_CMD_MASK) == FPGA_NAND_CMD_MASK) { 84*fd51b0e0SSergei Poselenov /* Write data */ 85*fd51b0e0SSergei Poselenov val = (state & FPGA_NAND_ENABLE) | FPGA_NAND_CMD_WRITE; 86*fd51b0e0SSergei Poselenov } else { 87*fd51b0e0SSergei Poselenov /* Write address or command */ 88*fd51b0e0SSergei Poselenov val = state; 89*fd51b0e0SSergei Poselenov } 90*fd51b0e0SSergei Poselenov 91*fd51b0e0SSergei Poselenov for (i = 0; i < len; i++) { 92*fd51b0e0SSergei Poselenov out_be32(this->IO_ADDR_W, val | (buf[i] << FPGA_NAND_DATA_SHIFT)); 93*fd51b0e0SSergei Poselenov } 94*fd51b0e0SSergei Poselenov } 95*fd51b0e0SSergei Poselenov 96*fd51b0e0SSergei Poselenov 97*fd51b0e0SSergei Poselenov /** 98*fd51b0e0SSergei Poselenov * nand_read_byte - read one byte from the chip 99*fd51b0e0SSergei Poselenov * @mtd: MTD device structure 100*fd51b0e0SSergei Poselenov */ 101*fd51b0e0SSergei Poselenov static u_char nand_read_byte(struct mtd_info *mtd) 102*fd51b0e0SSergei Poselenov { 103*fd51b0e0SSergei Poselenov u8 byte; 104*fd51b0e0SSergei Poselenov nand_read_buf(mtd, (uchar *)&byte, sizeof(byte)); 105*fd51b0e0SSergei Poselenov return byte; 106*fd51b0e0SSergei Poselenov } 107*fd51b0e0SSergei Poselenov 108*fd51b0e0SSergei Poselenov /** 109*fd51b0e0SSergei Poselenov * nand_read_word - read one word from the chip 110*fd51b0e0SSergei Poselenov * @mtd: MTD device structure 111*fd51b0e0SSergei Poselenov */ 112*fd51b0e0SSergei Poselenov static u16 nand_read_word(struct mtd_info *mtd) 113*fd51b0e0SSergei Poselenov { 114*fd51b0e0SSergei Poselenov u16 word; 115*fd51b0e0SSergei Poselenov nand_read_buf(mtd, (uchar *)&word, sizeof(word)); 116*fd51b0e0SSergei Poselenov return word; 117*fd51b0e0SSergei Poselenov } 118*fd51b0e0SSergei Poselenov 119*fd51b0e0SSergei Poselenov /** 120*fd51b0e0SSergei Poselenov * nand_read_buf - read chip data into buffer 121*fd51b0e0SSergei Poselenov * @mtd: MTD device structure 122*fd51b0e0SSergei Poselenov * @buf: buffer to store date 123*fd51b0e0SSergei Poselenov * @len: number of bytes to read 124*fd51b0e0SSergei Poselenov */ 125*fd51b0e0SSergei Poselenov static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) 126*fd51b0e0SSergei Poselenov { 127*fd51b0e0SSergei Poselenov int i; 128*fd51b0e0SSergei Poselenov struct nand_chip *this = mtd->priv; 129*fd51b0e0SSergei Poselenov int val; 130*fd51b0e0SSergei Poselenov 131*fd51b0e0SSergei Poselenov val = (state & FPGA_NAND_ENABLE) | FPGA_NAND_CMD_READ; 132*fd51b0e0SSergei Poselenov 133*fd51b0e0SSergei Poselenov out_be32(this->IO_ADDR_W, val); 134*fd51b0e0SSergei Poselenov for (i = 0; i < len; i++) { 135*fd51b0e0SSergei Poselenov buf[i] = (in_be32(this->IO_ADDR_R) >> FPGA_NAND_DATA_SHIFT) & 0xff; 136*fd51b0e0SSergei Poselenov } 137*fd51b0e0SSergei Poselenov } 138*fd51b0e0SSergei Poselenov 139*fd51b0e0SSergei Poselenov /** 140*fd51b0e0SSergei Poselenov * nand_verify_buf - Verify chip data against buffer 141*fd51b0e0SSergei Poselenov * @mtd: MTD device structure 142*fd51b0e0SSergei Poselenov * @buf: buffer containing the data to compare 143*fd51b0e0SSergei Poselenov * @len: number of bytes to compare 144*fd51b0e0SSergei Poselenov */ 145*fd51b0e0SSergei Poselenov static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) 146*fd51b0e0SSergei Poselenov { 147*fd51b0e0SSergei Poselenov int i; 148*fd51b0e0SSergei Poselenov 149*fd51b0e0SSergei Poselenov for (i = 0; i < len; i++) { 150*fd51b0e0SSergei Poselenov if (buf[i] != nand_read_byte(mtd)); 151*fd51b0e0SSergei Poselenov return -EFAULT; 152*fd51b0e0SSergei Poselenov } 153*fd51b0e0SSergei Poselenov return 0; 154*fd51b0e0SSergei Poselenov } 155*fd51b0e0SSergei Poselenov 156*fd51b0e0SSergei Poselenov /** 157*fd51b0e0SSergei Poselenov * nand_device_ready - Check the NAND device is ready for next command. 158*fd51b0e0SSergei Poselenov * @mtd: MTD device structure 159*fd51b0e0SSergei Poselenov */ 160*fd51b0e0SSergei Poselenov static int nand_device_ready(struct mtd_info *mtdinfo) 161*fd51b0e0SSergei Poselenov { 162*fd51b0e0SSergei Poselenov struct nand_chip *this = mtdinfo->priv; 163*fd51b0e0SSergei Poselenov 164*fd51b0e0SSergei Poselenov if (in_be32(this->IO_ADDR_W) & FPGA_NAND_BUSY) 165*fd51b0e0SSergei Poselenov return 0; /* busy */ 166*fd51b0e0SSergei Poselenov return 1; 167*fd51b0e0SSergei Poselenov } 168*fd51b0e0SSergei Poselenov 169*fd51b0e0SSergei Poselenov /** 170*fd51b0e0SSergei Poselenov * nand_hwcontrol - NAND control functions wrapper. 171*fd51b0e0SSergei Poselenov * @mtd: MTD device structure 172*fd51b0e0SSergei Poselenov * @cmd: Command 173*fd51b0e0SSergei Poselenov */ 174*fd51b0e0SSergei Poselenov static void nand_hwcontrol(struct mtd_info *mtdinfo, int cmd) 175*fd51b0e0SSergei Poselenov { 176*fd51b0e0SSergei Poselenov 177*fd51b0e0SSergei Poselenov switch(cmd) { 178*fd51b0e0SSergei Poselenov case NAND_CTL_CLRALE: 179*fd51b0e0SSergei Poselenov state |= FPGA_NAND_CMD_MASK; /* use all 1s to mark */ 180*fd51b0e0SSergei Poselenov break; 181*fd51b0e0SSergei Poselenov case NAND_CTL_CLRCLE: 182*fd51b0e0SSergei Poselenov state |= FPGA_NAND_CMD_MASK; /* use all 1s to mark */ 183*fd51b0e0SSergei Poselenov break; 184*fd51b0e0SSergei Poselenov case NAND_CTL_SETCLE: 185*fd51b0e0SSergei Poselenov state = (state & ~FPGA_NAND_CMD_MASK) | FPGA_NAND_CMD_COMMAND; 186*fd51b0e0SSergei Poselenov break; 187*fd51b0e0SSergei Poselenov case NAND_CTL_SETALE: 188*fd51b0e0SSergei Poselenov state = (state & ~FPGA_NAND_CMD_MASK) | FPGA_NAND_CMD_ADDR; 189*fd51b0e0SSergei Poselenov break; 190*fd51b0e0SSergei Poselenov case NAND_CTL_SETNCE: 191*fd51b0e0SSergei Poselenov state |= FPGA_NAND_ENABLE; 192*fd51b0e0SSergei Poselenov break; 193*fd51b0e0SSergei Poselenov case NAND_CTL_CLRNCE: 194*fd51b0e0SSergei Poselenov state &= ~FPGA_NAND_ENABLE; 195*fd51b0e0SSergei Poselenov break; 196*fd51b0e0SSergei Poselenov default: 197*fd51b0e0SSergei Poselenov printf("%s: unknown cmd %#x\n", __FUNCTION__, cmd); 198*fd51b0e0SSergei Poselenov break; 199*fd51b0e0SSergei Poselenov } 200*fd51b0e0SSergei Poselenov } 201*fd51b0e0SSergei Poselenov 202*fd51b0e0SSergei Poselenov int board_nand_init(struct nand_chip *nand) 203*fd51b0e0SSergei Poselenov { 204*fd51b0e0SSergei Poselenov nand->hwcontrol = nand_hwcontrol; 205*fd51b0e0SSergei Poselenov nand->eccmode = NAND_ECC_SOFT; 206*fd51b0e0SSergei Poselenov nand->dev_ready = nand_device_ready; 207*fd51b0e0SSergei Poselenov nand->write_byte = nand_write_byte; 208*fd51b0e0SSergei Poselenov nand->read_byte = nand_read_byte; 209*fd51b0e0SSergei Poselenov nand->write_word = nand_write_word; 210*fd51b0e0SSergei Poselenov nand->read_word = nand_read_word; 211*fd51b0e0SSergei Poselenov nand->write_buf = nand_write_buf; 212*fd51b0e0SSergei Poselenov nand->read_buf = nand_read_buf; 213*fd51b0e0SSergei Poselenov nand->verify_buf = nand_verify_buf; 214*fd51b0e0SSergei Poselenov 215*fd51b0e0SSergei Poselenov return 0; 216*fd51b0e0SSergei Poselenov } 217*fd51b0e0SSergei Poselenov 218*fd51b0e0SSergei Poselenov #endif 219