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