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