uboot/drivers/mtd/onenand/samsung.c
<<
>>
Prefs
   1/*
   2 * S3C64XX/S5PC100 OneNAND driver at U-Boot
   3 *
   4 * Copyright (C) 2008-2009 Samsung Electronics
   5 * Kyungmin Park <kyungmin.park@samsung.com>
   6 *
   7 * Implementation:
   8 *      Emulate the pseudo BufferRAM
   9 *
  10 * See file CREDITS for list of people who contributed to this
  11 * project.
  12 *
  13 * This program is free software; you can redistribute it and/or
  14 * modify it under the terms of the GNU General Public License as
  15 * published by the Free Software Foundation; either version 2 of
  16 * the License, or (at your option) any later version.
  17 *
  18 * This program is distributed in the hope that it will be useful,
  19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21 * GNU General Public License for more details.
  22 *
  23 * You should have received a copy of the GNU General Public License
  24 * along with this program; if not, write to the Free Software
  25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  26 * MA 02111-1307 USA
  27 */
  28
  29#include <common.h>
  30#include <malloc.h>
  31#include <linux/mtd/compat.h>
  32#include <linux/mtd/mtd.h>
  33#include <linux/mtd/onenand.h>
  34#include <linux/mtd/samsung_onenand.h>
  35
  36#include <asm/io.h>
  37#include <asm/errno.h>
  38
  39#ifdef ONENAND_DEBUG
  40#define DPRINTK(format, args...)                                        \
  41do {                                                                    \
  42        printf("%s[%d]: " format "\n", __func__, __LINE__, ##args);     \
  43} while (0)
  44#else
  45#define DPRINTK(...)                    do { } while (0)
  46#endif
  47
  48#define ONENAND_ERASE_STATUS            0x00
  49#define ONENAND_MULTI_ERASE_SET         0x01
  50#define ONENAND_ERASE_START             0x03
  51#define ONENAND_UNLOCK_START            0x08
  52#define ONENAND_UNLOCK_END              0x09
  53#define ONENAND_LOCK_START              0x0A
  54#define ONENAND_LOCK_END                0x0B
  55#define ONENAND_LOCK_TIGHT_START        0x0C
  56#define ONENAND_LOCK_TIGHT_END          0x0D
  57#define ONENAND_UNLOCK_ALL              0x0E
  58#define ONENAND_OTP_ACCESS              0x12
  59#define ONENAND_SPARE_ACCESS_ONLY       0x13
  60#define ONENAND_MAIN_ACCESS_ONLY        0x14
  61#define ONENAND_ERASE_VERIFY            0x15
  62#define ONENAND_MAIN_SPARE_ACCESS       0x16
  63#define ONENAND_PIPELINE_READ           0x4000
  64
  65#if defined(CONFIG_S3C64XX)
  66#define MAP_00                          (0x0 << 24)
  67#define MAP_01                          (0x1 << 24)
  68#define MAP_10                          (0x2 << 24)
  69#define MAP_11                          (0x3 << 24)
  70#elif defined(CONFIG_S5PC1XX)
  71#define MAP_00                          (0x0 << 26)
  72#define MAP_01                          (0x1 << 26)
  73#define MAP_10                          (0x2 << 26)
  74#define MAP_11                          (0x3 << 26)
  75#endif
  76
  77/* read/write of XIP buffer */
  78#define CMD_MAP_00(mem_addr)            (MAP_00 | ((mem_addr) << 1))
  79/* read/write to the memory device */
  80#define CMD_MAP_01(mem_addr)            (MAP_01 | (mem_addr))
  81/* control special functions of the memory device */
  82#define CMD_MAP_10(mem_addr)            (MAP_10 | (mem_addr))
  83/* direct interface(direct access) with the memory device */
  84#define CMD_MAP_11(mem_addr)            (MAP_11 | ((mem_addr) << 2))
  85
  86struct s3c_onenand {
  87        struct mtd_info *mtd;
  88        void __iomem    *base;
  89        void __iomem    *ahb_addr;
  90        int             bootram_command;
  91        void __iomem    *page_buf;
  92        void __iomem    *oob_buf;
  93        unsigned int    (*mem_addr)(int fba, int fpa, int fsa);
  94        struct samsung_onenand *reg;
  95};
  96
  97static struct s3c_onenand *onenand;
  98
  99static int s3c_read_cmd(unsigned int cmd)
 100{
 101        return readl(onenand->ahb_addr + cmd);
 102}
 103
 104static void s3c_write_cmd(int value, unsigned int cmd)
 105{
 106        writel(value, onenand->ahb_addr + cmd);
 107}
 108
 109/*
 110 * MEM_ADDR
 111 *
 112 * fba: flash block address
 113 * fpa: flash page address
 114 * fsa: flash sector address
 115 *
 116 * return the buffer address on the memory device
 117 * It will be combined with CMD_MAP_XX
 118 */
 119#if defined(CONFIG_S3C64XX)
 120static unsigned int s3c_mem_addr(int fba, int fpa, int fsa)
 121{
 122        return (fba << 12) | (fpa << 6) | (fsa << 4);
 123}
 124#elif defined(CONFIG_S5PC1XX)
 125static unsigned int s3c_mem_addr(int fba, int fpa, int fsa)
 126{
 127        return (fba << 13) | (fpa << 7) | (fsa << 5);
 128}
 129#endif
 130
 131static void s3c_onenand_reset(void)
 132{
 133        unsigned long timeout = 0x10000;
 134        int stat;
 135
 136        writel(ONENAND_MEM_RESET_COLD, &onenand->reg->mem_reset);
 137        while (timeout--) {
 138                stat = readl(&onenand->reg->int_err_stat);
 139                if (stat & RST_CMP)
 140                        break;
 141        }
 142        stat = readl(&onenand->reg->int_err_stat);
 143        writel(stat, &onenand->reg->int_err_ack);
 144
 145        /* Clear interrupt */
 146        writel(0x0, &onenand->reg->int_err_ack);
 147        /* Clear the ECC status */
 148        writel(0x0, &onenand->reg->ecc_err_stat);
 149}
 150
 151static unsigned short s3c_onenand_readw(void __iomem *addr)
 152{
 153        struct onenand_chip *this = onenand->mtd->priv;
 154        int reg = addr - this->base;
 155        int word_addr = reg >> 1;
 156        int value;
 157
 158        /* It's used for probing time */
 159        switch (reg) {
 160        case ONENAND_REG_MANUFACTURER_ID:
 161                return readl(&onenand->reg->manufact_id);
 162        case ONENAND_REG_DEVICE_ID:
 163                return readl(&onenand->reg->device_id);
 164        case ONENAND_REG_VERSION_ID:
 165                return readl(&onenand->reg->flash_ver_id);
 166        case ONENAND_REG_DATA_BUFFER_SIZE:
 167                return readl(&onenand->reg->data_buf_size);
 168        case ONENAND_REG_TECHNOLOGY:
 169                return readl(&onenand->reg->tech);
 170        case ONENAND_REG_SYS_CFG1:
 171                return readl(&onenand->reg->mem_cfg);
 172
 173        /* Used at unlock all status */
 174        case ONENAND_REG_CTRL_STATUS:
 175                return 0;
 176
 177        case ONENAND_REG_WP_STATUS:
 178                return ONENAND_WP_US;
 179
 180        default:
 181                break;
 182        }
 183
 184        /* BootRAM access control */
 185        if (reg < ONENAND_DATARAM && onenand->bootram_command) {
 186                if (word_addr == 0)
 187                        return readl(&onenand->reg->manufact_id);
 188                if (word_addr == 1)
 189                        return readl(&onenand->reg->device_id);
 190                if (word_addr == 2)
 191                        return readl(&onenand->reg->flash_ver_id);
 192        }
 193
 194        value = s3c_read_cmd(CMD_MAP_11(word_addr)) & 0xffff;
 195        printk(KERN_INFO "s3c_onenand_readw:  Illegal access"
 196                " at reg 0x%x, value 0x%x\n", word_addr, value);
 197        return value;
 198}
 199
 200static void s3c_onenand_writew(unsigned short value, void __iomem *addr)
 201{
 202        struct onenand_chip *this = onenand->mtd->priv;
 203        int reg = addr - this->base;
 204        int word_addr = reg >> 1;
 205
 206        /* It's used for probing time */
 207        switch (reg) {
 208        case ONENAND_REG_SYS_CFG1:
 209                writel(value, &onenand->reg->mem_cfg);
 210                return;
 211
 212        case ONENAND_REG_START_ADDRESS1:
 213        case ONENAND_REG_START_ADDRESS2:
 214                return;
 215
 216        /* Lock/lock-tight/unlock/unlock_all */
 217        case ONENAND_REG_START_BLOCK_ADDRESS:
 218                return;
 219
 220        default:
 221                break;
 222        }
 223
 224        /* BootRAM access control */
 225        if (reg < ONENAND_DATARAM) {
 226                if (value == ONENAND_CMD_READID) {
 227                        onenand->bootram_command = 1;
 228                        return;
 229                }
 230                if (value == ONENAND_CMD_RESET) {
 231                        writel(ONENAND_MEM_RESET_COLD,
 232                                        &onenand->reg->mem_reset);
 233                        onenand->bootram_command = 0;
 234                        return;
 235                }
 236        }
 237
 238        printk(KERN_INFO "s3c_onenand_writew: Illegal access"
 239                " at reg 0x%x, value 0x%x\n", word_addr, value);
 240
 241        s3c_write_cmd(value, CMD_MAP_11(word_addr));
 242}
 243
 244static int s3c_onenand_wait(struct mtd_info *mtd, int state)
 245{
 246        unsigned int flags = INT_ACT;
 247        unsigned int stat, ecc;
 248        unsigned long timeout = 0x100000;
 249
 250        switch (state) {
 251        case FL_READING:
 252                flags |= BLK_RW_CMP | LOAD_CMP;
 253                break;
 254        case FL_WRITING:
 255                flags |= BLK_RW_CMP | PGM_CMP;
 256                break;
 257        case FL_ERASING:
 258                flags |= BLK_RW_CMP | ERS_CMP;
 259                break;
 260        case FL_LOCKING:
 261                flags |= BLK_RW_CMP;
 262                break;
 263        default:
 264                break;
 265        }
 266
 267        while (timeout--) {
 268                stat = readl(&onenand->reg->int_err_stat);
 269                if (stat & flags)
 270                        break;
 271        }
 272
 273        /* To get correct interrupt status in timeout case */
 274        stat = readl(&onenand->reg->int_err_stat);
 275        writel(stat, &onenand->reg->int_err_ack);
 276
 277        /*
 278         * In the Spec. it checks the controller status first
 279         * However if you get the correct information in case of
 280         * power off recovery (POR) test, it should read ECC status first
 281         */
 282        if (stat & LOAD_CMP) {
 283                ecc = readl(&onenand->reg->ecc_err_stat);
 284                if (ecc & ONENAND_ECC_4BIT_UNCORRECTABLE) {
 285                        printk(KERN_INFO "%s: ECC error = 0x%04x\n",
 286                                        __func__, ecc);
 287                        mtd->ecc_stats.failed++;
 288                        return -EBADMSG;
 289                }
 290        }
 291
 292        if (stat & (LOCKED_BLK | ERS_FAIL | PGM_FAIL | LD_FAIL_ECC_ERR)) {
 293                printk(KERN_INFO "%s: controller error = 0x%04x\n",
 294                                __func__, stat);
 295                if (stat & LOCKED_BLK)
 296                        printk(KERN_INFO "%s: it's locked error = 0x%04x\n",
 297                                        __func__, stat);
 298
 299                return -EIO;
 300        }
 301
 302        return 0;
 303}
 304
 305static int s3c_onenand_command(struct mtd_info *mtd, int cmd,
 306                loff_t addr, size_t len)
 307{
 308        struct onenand_chip *this = mtd->priv;
 309        unsigned int *m, *s;
 310        int fba, fpa, fsa = 0;
 311        unsigned int mem_addr;
 312        int i, mcount, scount;
 313        int index;
 314
 315        fba = (int) (addr >> this->erase_shift);
 316        fpa = (int) (addr >> this->page_shift);
 317        fpa &= this->page_mask;
 318
 319        mem_addr = onenand->mem_addr(fba, fpa, fsa);
 320
 321        switch (cmd) {
 322        case ONENAND_CMD_READ:
 323        case ONENAND_CMD_READOOB:
 324        case ONENAND_CMD_BUFFERRAM:
 325                ONENAND_SET_NEXT_BUFFERRAM(this);
 326        default:
 327                break;
 328        }
 329
 330        index = ONENAND_CURRENT_BUFFERRAM(this);
 331
 332        /*
 333         * Emulate Two BufferRAMs and access with 4 bytes pointer
 334         */
 335        m = (unsigned int *) onenand->page_buf;
 336        s = (unsigned int *) onenand->oob_buf;
 337
 338        if (index) {
 339                m += (this->writesize >> 2);
 340                s += (mtd->oobsize >> 2);
 341        }
 342
 343        mcount = mtd->writesize >> 2;
 344        scount = mtd->oobsize >> 2;
 345
 346        switch (cmd) {
 347        case ONENAND_CMD_READ:
 348                /* Main */
 349                for (i = 0; i < mcount; i++)
 350                        *m++ = s3c_read_cmd(CMD_MAP_01(mem_addr));
 351                return 0;
 352
 353        case ONENAND_CMD_READOOB:
 354                writel(TSRF, &onenand->reg->trans_spare);
 355                /* Main */
 356                for (i = 0; i < mcount; i++)
 357                        *m++ = s3c_read_cmd(CMD_MAP_01(mem_addr));
 358
 359                /* Spare */
 360                for (i = 0; i < scount; i++)
 361                        *s++ = s3c_read_cmd(CMD_MAP_01(mem_addr));
 362
 363                writel(0, &onenand->reg->trans_spare);
 364                return 0;
 365
 366        case ONENAND_CMD_PROG:
 367                /* Main */
 368                for (i = 0; i < mcount; i++)
 369                        s3c_write_cmd(*m++, CMD_MAP_01(mem_addr));
 370                return 0;
 371
 372        case ONENAND_CMD_PROGOOB:
 373                writel(TSRF, &onenand->reg->trans_spare);
 374
 375                /* Main - dummy write */
 376                for (i = 0; i < mcount; i++)
 377                        s3c_write_cmd(0xffffffff, CMD_MAP_01(mem_addr));
 378
 379                /* Spare */
 380                for (i = 0; i < scount; i++)
 381                        s3c_write_cmd(*s++, CMD_MAP_01(mem_addr));
 382
 383                writel(0, &onenand->reg->trans_spare);
 384                return 0;
 385
 386        case ONENAND_CMD_UNLOCK_ALL:
 387                s3c_write_cmd(ONENAND_UNLOCK_ALL, CMD_MAP_10(mem_addr));
 388                return 0;
 389
 390        case ONENAND_CMD_ERASE:
 391                s3c_write_cmd(ONENAND_ERASE_START, CMD_MAP_10(mem_addr));
 392                return 0;
 393
 394        case ONENAND_CMD_MULTIBLOCK_ERASE:
 395                s3c_write_cmd(ONENAND_MULTI_ERASE_SET, CMD_MAP_10(mem_addr));
 396                return 0;
 397
 398        case ONENAND_CMD_ERASE_VERIFY:
 399                s3c_write_cmd(ONENAND_ERASE_VERIFY, CMD_MAP_10(mem_addr));
 400                return 0;
 401
 402        default:
 403                break;
 404        }
 405
 406        return 0;
 407}
 408
 409static unsigned char *s3c_get_bufferram(struct mtd_info *mtd, int area)
 410{
 411        struct onenand_chip *this = mtd->priv;
 412        int index = ONENAND_CURRENT_BUFFERRAM(this);
 413        unsigned char *p;
 414
 415        if (area == ONENAND_DATARAM) {
 416                p = (unsigned char *) onenand->page_buf;
 417                if (index == 1)
 418                        p += this->writesize;
 419        } else {
 420                p = (unsigned char *) onenand->oob_buf;
 421                if (index == 1)
 422                        p += mtd->oobsize;
 423        }
 424
 425        return p;
 426}
 427
 428static int onenand_read_bufferram(struct mtd_info *mtd, loff_t addr, int area,
 429                                  unsigned char *buffer, int offset,
 430                                  size_t count)
 431{
 432        unsigned char *p;
 433
 434        p = s3c_get_bufferram(mtd, area);
 435        memcpy(buffer, p + offset, count);
 436        return 0;
 437}
 438
 439static int onenand_write_bufferram(struct mtd_info *mtd, loff_t addr, int area,
 440                                   const unsigned char *buffer, int offset,
 441                                   size_t count)
 442{
 443        unsigned char *p;
 444
 445        p = s3c_get_bufferram(mtd, area);
 446        memcpy(p + offset, buffer, count);
 447        return 0;
 448}
 449
 450static int s3c_onenand_bbt_wait(struct mtd_info *mtd, int state)
 451{
 452        struct samsung_onenand *reg = (struct samsung_onenand *)onenand->base;
 453        unsigned int flags = INT_ACT | LOAD_CMP;
 454        unsigned int stat;
 455        unsigned long timeout = 0x10000;
 456
 457        while (timeout--) {
 458                stat = readl(&reg->int_err_stat);
 459                if (stat & flags)
 460                        break;
 461        }
 462        /* To get correct interrupt status in timeout case */
 463        stat = readl(&onenand->reg->int_err_stat);
 464        writel(stat, &onenand->reg->int_err_ack);
 465
 466        if (stat & LD_FAIL_ECC_ERR) {
 467                s3c_onenand_reset();
 468                return ONENAND_BBT_READ_ERROR;
 469        }
 470
 471        if (stat & LOAD_CMP) {
 472                int ecc = readl(&onenand->reg->ecc_err_stat);
 473                if (ecc & ONENAND_ECC_4BIT_UNCORRECTABLE) {
 474                        s3c_onenand_reset();
 475                        return ONENAND_BBT_READ_ERROR;
 476                }
 477        }
 478
 479        return 0;
 480}
 481
 482static void s3c_onenand_check_lock_status(struct mtd_info *mtd)
 483{
 484        struct onenand_chip *this = mtd->priv;
 485        unsigned int block, end;
 486        int tmp;
 487
 488        end = this->chipsize >> this->erase_shift;
 489
 490        for (block = 0; block < end; block++) {
 491                tmp = s3c_read_cmd(CMD_MAP_01(onenand->mem_addr(block, 0, 0)));
 492
 493                if (readl(&onenand->reg->int_err_stat) & LOCKED_BLK) {
 494                        printf("block %d is write-protected!\n", block);
 495                        writel(LOCKED_BLK, &onenand->reg->int_err_ack);
 496                }
 497        }
 498}
 499
 500static void s3c_onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs,
 501                size_t len, int cmd)
 502{
 503        struct onenand_chip *this = mtd->priv;
 504        int start, end, start_mem_addr, end_mem_addr;
 505
 506        start = ofs >> this->erase_shift;
 507        start_mem_addr = onenand->mem_addr(start, 0, 0);
 508        end = start + (len >> this->erase_shift) - 1;
 509        end_mem_addr = onenand->mem_addr(end, 0, 0);
 510
 511        if (cmd == ONENAND_CMD_LOCK) {
 512                s3c_write_cmd(ONENAND_LOCK_START, CMD_MAP_10(start_mem_addr));
 513                s3c_write_cmd(ONENAND_LOCK_END, CMD_MAP_10(end_mem_addr));
 514        } else {
 515                s3c_write_cmd(ONENAND_UNLOCK_START, CMD_MAP_10(start_mem_addr));
 516                s3c_write_cmd(ONENAND_UNLOCK_END, CMD_MAP_10(end_mem_addr));
 517        }
 518
 519        this->wait(mtd, FL_LOCKING);
 520}
 521
 522static void s3c_onenand_unlock_all(struct mtd_info *mtd)
 523{
 524        struct onenand_chip *this = mtd->priv;
 525        loff_t ofs = 0;
 526        size_t len = this->chipsize;
 527
 528        /* FIXME workaround */
 529        this->subpagesize = mtd->writesize;
 530        mtd->subpage_sft = 0;
 531
 532        if (this->options & ONENAND_HAS_UNLOCK_ALL) {
 533                /* Write unlock command */
 534                this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
 535
 536                /* No need to check return value */
 537                this->wait(mtd, FL_LOCKING);
 538
 539                /* Workaround for all block unlock in DDP */
 540                if (!ONENAND_IS_DDP(this)) {
 541                        s3c_onenand_check_lock_status(mtd);
 542                        return;
 543                }
 544
 545                /* All blocks on another chip */
 546                ofs = this->chipsize >> 1;
 547                len = this->chipsize >> 1;
 548        }
 549
 550        s3c_onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
 551        s3c_onenand_check_lock_status(mtd);
 552}
 553
 554#ifdef CONFIG_S3C64XX
 555static void s3c_set_width_regs(struct onenand_chip *this)
 556{
 557        int dev_id, density;
 558        int fba, fpa, fsa;
 559        int dbs_dfs;
 560
 561        dev_id = DEVICE_ID0_REG;
 562
 563        density = (dev_id >> ONENAND_DEVICE_DENSITY_SHIFT) & 0xf;
 564        dbs_dfs = !!(dev_id & ONENAND_DEVICE_IS_DDP);
 565
 566        fba = density + 7;
 567        if (dbs_dfs)
 568                fba--;          /* Decrease the fba */
 569        fpa = 6;
 570        if (density >= ONENAND_DEVICE_DENSITY_512Mb)
 571                fsa = 2;
 572        else
 573                fsa = 1;
 574
 575        DPRINTK("FBA %lu, FPA %lu, FSA %lu, DDP %lu",
 576                FBA_WIDTH0_REG, FPA_WIDTH0_REG, FSA_WIDTH0_REG,
 577                DDP_DEVICE_REG);
 578
 579        DPRINTK("mem_cfg0 0x%lx, sync mode %lu, "
 580                "dev_page_size %lu, BURST LEN %lu",
 581                MEM_CFG0_REG, SYNC_MODE_REG,
 582                DEV_PAGE_SIZE_REG, BURST_LEN0_REG);
 583
 584        DEV_PAGE_SIZE_REG = 0x1;
 585
 586        FBA_WIDTH0_REG = fba;
 587        FPA_WIDTH0_REG = fpa;
 588        FSA_WIDTH0_REG = fsa;
 589        DBS_DFS_WIDTH0_REG = dbs_dfs;
 590}
 591#endif
 592
 593void s3c_onenand_init(struct mtd_info *mtd)
 594{
 595        struct onenand_chip *this = mtd->priv;
 596        u32 size = (4 << 10);   /* 4 KiB */
 597
 598        onenand = malloc(sizeof(struct s3c_onenand));
 599        if (!onenand)
 600                return;
 601
 602        onenand->page_buf = malloc(size * sizeof(char));
 603        if (!onenand->page_buf)
 604                return;
 605        memset(onenand->page_buf, 0xff, size);
 606
 607        onenand->oob_buf = malloc(128 * sizeof(char));
 608        if (!onenand->oob_buf)
 609                return;
 610        memset(onenand->oob_buf, 0xff, 128);
 611
 612        onenand->mtd = mtd;
 613
 614#if defined(CONFIG_S3C64XX)
 615        onenand->base = (void *)0x70100000;
 616        onenand->ahb_addr = (void *)0x20000000;
 617#elif defined(CONFIG_S5PC1XX)
 618        onenand->base = (void *)0xE7100000;
 619        onenand->ahb_addr = (void *)0xB0000000;
 620#endif
 621        onenand->mem_addr = s3c_mem_addr;
 622        onenand->reg = (struct samsung_onenand *)onenand->base;
 623
 624        this->read_word = s3c_onenand_readw;
 625        this->write_word = s3c_onenand_writew;
 626
 627        this->wait = s3c_onenand_wait;
 628        this->bbt_wait = s3c_onenand_bbt_wait;
 629        this->unlock_all = s3c_onenand_unlock_all;
 630        this->command = s3c_onenand_command;
 631
 632        this->read_bufferram = onenand_read_bufferram;
 633        this->write_bufferram = onenand_write_bufferram;
 634
 635        this->options |= ONENAND_RUNTIME_BADBLOCK_CHECK;
 636}
 637