uboot/drivers/mtd/nand/sunxi_nand_spl.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2014-2015, Antmicro Ltd <www.antmicro.com>
   3 * Copyright (c) 2015, AW-SOM Technologies <www.aw-som.com>
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8#include <asm/arch/clock.h>
   9#include <asm/io.h>
  10#include <common.h>
  11#include <config.h>
  12#include <nand.h>
  13
  14/* registers */
  15#define NFC_CTL                    0x00000000
  16#define NFC_ST                     0x00000004
  17#define NFC_INT                    0x00000008
  18#define NFC_TIMING_CTL             0x0000000C
  19#define NFC_TIMING_CFG             0x00000010
  20#define NFC_ADDR_LOW               0x00000014
  21#define NFC_ADDR_HIGH              0x00000018
  22#define NFC_SECTOR_NUM             0x0000001C
  23#define NFC_CNT                    0x00000020
  24#define NFC_CMD                    0x00000024
  25#define NFC_RCMD_SET               0x00000028
  26#define NFC_WCMD_SET               0x0000002C
  27#define NFC_IO_DATA                0x00000030
  28#define NFC_ECC_CTL                0x00000034
  29#define NFC_ECC_ST                 0x00000038
  30#define NFC_DEBUG                  0x0000003C
  31#define NFC_ECC_CNT0               0x00000040
  32#define NFC_ECC_CNT1               0x00000044
  33#define NFC_ECC_CNT2               0x00000048
  34#define NFC_ECC_CNT3               0x0000004C
  35#define NFC_USER_DATA_BASE         0x00000050
  36#define NFC_EFNAND_STATUS          0x00000090
  37#define NFC_SPARE_AREA             0x000000A0
  38#define NFC_PATTERN_ID             0x000000A4
  39#define NFC_RAM0_BASE              0x00000400
  40#define NFC_RAM1_BASE              0x00000800
  41
  42#define NFC_CTL_EN                 (1 << 0)
  43#define NFC_CTL_RESET              (1 << 1)
  44#define NFC_CTL_RAM_METHOD         (1 << 14)
  45#define NFC_CTL_PAGE_SIZE_MASK     (0xf << 8)
  46#define NFC_CTL_PAGE_SIZE(a)       ((fls(a) - 11) << 8)
  47
  48
  49#define NFC_ECC_EN                 (1 << 0)
  50#define NFC_ECC_PIPELINE           (1 << 3)
  51#define NFC_ECC_EXCEPTION          (1 << 4)
  52#define NFC_ECC_BLOCK_SIZE         (1 << 5)
  53#define NFC_ECC_RANDOM_EN          (1 << 9)
  54#define NFC_ECC_RANDOM_DIRECTION   (1 << 10)
  55
  56
  57#define NFC_ADDR_NUM_OFFSET        16
  58#define NFC_SEND_ADR               (1 << 19)
  59#define NFC_ACCESS_DIR             (1 << 20)
  60#define NFC_DATA_TRANS             (1 << 21)
  61#define NFC_SEND_CMD1              (1 << 22)
  62#define NFC_WAIT_FLAG              (1 << 23)
  63#define NFC_SEND_CMD2              (1 << 24)
  64#define NFC_SEQ                    (1 << 25)
  65#define NFC_DATA_SWAP_METHOD       (1 << 26)
  66#define NFC_ROW_AUTO_INC           (1 << 27)
  67#define NFC_SEND_CMD3              (1 << 28)
  68#define NFC_SEND_CMD4              (1 << 29)
  69#define NFC_RAW_CMD                (0 << 30)
  70#define NFC_PAGE_CMD               (2 << 30)
  71
  72#define NFC_ST_CMD_INT_FLAG        (1 << 1)
  73#define NFC_ST_DMA_INT_FLAG        (1 << 2)
  74
  75#define NFC_READ_CMD_OFFSET         0
  76#define NFC_RANDOM_READ_CMD0_OFFSET 8
  77#define NFC_RANDOM_READ_CMD1_OFFSET 16
  78
  79#define NFC_CMD_RNDOUTSTART        0xE0
  80#define NFC_CMD_RNDOUT             0x05
  81#define NFC_CMD_READSTART          0x30
  82
  83#define SUNXI_DMA_CFG_REG0              0x300
  84#define SUNXI_DMA_SRC_START_ADDR_REG0   0x304
  85#define SUNXI_DMA_DEST_START_ADDRR_REG0 0x308
  86#define SUNXI_DMA_DDMA_BC_REG0          0x30C
  87#define SUNXI_DMA_DDMA_PARA_REG0        0x318
  88
  89#define SUNXI_DMA_DDMA_CFG_REG_LOADING  (1 << 31)
  90#define SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32 (2 << 25)
  91#define SUNXI_DMA_DDMA_CFG_REG_DDMA_DST_DRQ_TYPE_DRAM (1 << 16)
  92#define SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32 (2 << 9)
  93#define SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO (1 << 5)
  94#define SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC (3 << 0)
  95
  96#define SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC (0x0F << 0)
  97#define SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE (0x7F << 8)
  98
  99struct nfc_config {
 100        int page_size;
 101        int ecc_strength;
 102        int ecc_size;
 103        int addr_cycles;
 104        int nseeds;
 105        bool randomize;
 106        bool valid;
 107};
 108
 109/* minimal "boot0" style NAND support for Allwinner A20 */
 110
 111/* random seed used by linux */
 112const uint16_t random_seed[128] = {
 113        0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
 114        0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
 115        0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
 116        0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
 117        0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
 118        0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
 119        0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
 120        0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
 121        0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
 122        0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
 123        0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
 124        0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
 125        0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
 126        0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
 127        0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
 128        0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
 129};
 130
 131#define DEFAULT_TIMEOUT_US      100000
 132
 133static int check_value_inner(int offset, int expected_bits,
 134                             int timeout_us, int negation)
 135{
 136        do {
 137                int val = readl(offset) & expected_bits;
 138                if (negation ? !val : val)
 139                        return 1;
 140                udelay(1);
 141        } while (--timeout_us);
 142
 143        return 0;
 144}
 145
 146static inline int check_value(int offset, int expected_bits,
 147                              int timeout_us)
 148{
 149        return check_value_inner(offset, expected_bits, timeout_us, 0);
 150}
 151
 152static inline int check_value_negated(int offset, int unexpected_bits,
 153                                      int timeout_us)
 154{
 155        return check_value_inner(offset, unexpected_bits, timeout_us, 1);
 156}
 157
 158void nand_init(void)
 159{
 160        uint32_t val;
 161
 162        board_nand_init();
 163
 164        val = readl(SUNXI_NFC_BASE + NFC_CTL);
 165        /* enable and reset CTL */
 166        writel(val | NFC_CTL_EN | NFC_CTL_RESET,
 167               SUNXI_NFC_BASE + NFC_CTL);
 168
 169        if (!check_value_negated(SUNXI_NFC_BASE + NFC_CTL,
 170                                 NFC_CTL_RESET, DEFAULT_TIMEOUT_US)) {
 171                printf("Couldn't initialize nand\n");
 172        }
 173
 174        /* reset NAND */
 175        writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
 176        writel(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET,
 177               SUNXI_NFC_BASE + NFC_CMD);
 178
 179        if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG,
 180                         DEFAULT_TIMEOUT_US)) {
 181                printf("Error timeout waiting for nand reset\n");
 182                return;
 183        }
 184        writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
 185}
 186
 187static void nand_apply_config(const struct nfc_config *conf)
 188{
 189        u32 val;
 190
 191        val = readl(SUNXI_NFC_BASE + NFC_CTL);
 192        val &= ~NFC_CTL_PAGE_SIZE_MASK;
 193        writel(val | NFC_CTL_RAM_METHOD | NFC_CTL_PAGE_SIZE(conf->page_size),
 194               SUNXI_NFC_BASE + NFC_CTL);
 195        writel(conf->ecc_size, SUNXI_NFC_BASE + NFC_CNT);
 196        writel(conf->page_size, SUNXI_NFC_BASE + NFC_SPARE_AREA);
 197}
 198
 199static int nand_load_page(const struct nfc_config *conf, u32 offs)
 200{
 201        int page = offs / conf->page_size;
 202
 203        writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) |
 204               (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) |
 205               (NFC_CMD_READSTART << NFC_READ_CMD_OFFSET),
 206               SUNXI_NFC_BASE + NFC_RCMD_SET);
 207        writel(((page & 0xFFFF) << 16), SUNXI_NFC_BASE + NFC_ADDR_LOW);
 208        writel((page >> 16) & 0xFF, SUNXI_NFC_BASE + NFC_ADDR_HIGH);
 209        writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
 210        writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | NFC_WAIT_FLAG |
 211               ((conf->addr_cycles - 1) << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADR,
 212               SUNXI_NFC_BASE + NFC_CMD);
 213
 214        if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG,
 215                         DEFAULT_TIMEOUT_US)) {
 216                printf("Error while initializing dma interrupt\n");
 217                return -EIO;
 218        }
 219
 220        return 0;
 221}
 222
 223static int nand_reset_column(void)
 224{
 225        writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) |
 226               (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) |
 227               (NFC_CMD_RNDOUTSTART << NFC_READ_CMD_OFFSET),
 228               SUNXI_NFC_BASE + NFC_RCMD_SET);
 229        writel(0, SUNXI_NFC_BASE + NFC_ADDR_LOW);
 230        writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD |
 231               (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADR | NFC_CMD_RNDOUT,
 232               SUNXI_NFC_BASE + NFC_CMD);
 233
 234        if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG,
 235                         DEFAULT_TIMEOUT_US)) {
 236                printf("Error while initializing dma interrupt\n");
 237                return -1;
 238        }
 239
 240        return 0;
 241}
 242
 243static int nand_read_page(const struct nfc_config *conf, u32 offs,
 244                          void *dest, int len)
 245{
 246        dma_addr_t dst = (dma_addr_t)dest;
 247        int nsectors = len / conf->ecc_size;
 248        u16 rand_seed = 0;
 249        u32 val;
 250        int page;
 251
 252        page = offs / conf->page_size;
 253
 254        if (offs % conf->page_size || len % conf->ecc_size ||
 255            len > conf->page_size || len < 0)
 256                return -EINVAL;
 257
 258        /* clear ecc status */
 259        writel(0, SUNXI_NFC_BASE + NFC_ECC_ST);
 260
 261        /* Choose correct seed if randomized */
 262        if (conf->randomize)
 263                rand_seed = random_seed[page % conf->nseeds];
 264
 265        writel((rand_seed << 16) | (conf->ecc_strength << 12) |
 266                (conf->randomize ? NFC_ECC_RANDOM_EN : 0) |
 267                (conf->ecc_size == 512 ? NFC_ECC_BLOCK_SIZE : 0) |
 268                NFC_ECC_EN | NFC_ECC_PIPELINE | NFC_ECC_EXCEPTION,
 269                SUNXI_NFC_BASE + NFC_ECC_CTL);
 270
 271        flush_dcache_range(dst, ALIGN(dst + conf->ecc_size, ARCH_DMA_MINALIGN));
 272
 273        /* SUNXI_DMA */
 274        writel(0x0, SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0); /* clr dma cmd */
 275        /* read from REG_IO_DATA */
 276        writel(SUNXI_NFC_BASE + NFC_IO_DATA,
 277               SUNXI_DMA_BASE + SUNXI_DMA_SRC_START_ADDR_REG0);
 278        /* read to RAM */
 279        writel(dst, SUNXI_DMA_BASE + SUNXI_DMA_DEST_START_ADDRR_REG0);
 280        writel(SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC |
 281               SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE,
 282               SUNXI_DMA_BASE + SUNXI_DMA_DDMA_PARA_REG0);
 283        writel(len, SUNXI_DMA_BASE + SUNXI_DMA_DDMA_BC_REG0);
 284        writel(SUNXI_DMA_DDMA_CFG_REG_LOADING |
 285               SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32 |
 286               SUNXI_DMA_DDMA_CFG_REG_DDMA_DST_DRQ_TYPE_DRAM |
 287               SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32 |
 288               SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO |
 289               SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC,
 290               SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0);
 291
 292        writel(nsectors, SUNXI_NFC_BASE + NFC_SECTOR_NUM);
 293        writel(NFC_ST_DMA_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
 294        writel(NFC_DATA_TRANS | NFC_PAGE_CMD | NFC_DATA_SWAP_METHOD,
 295               SUNXI_NFC_BASE + NFC_CMD);
 296
 297        if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_DMA_INT_FLAG,
 298                         DEFAULT_TIMEOUT_US)) {
 299                printf("Error while initializing dma interrupt\n");
 300                return -EIO;
 301        }
 302        writel(NFC_ST_DMA_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
 303
 304        if (!check_value_negated(SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0,
 305                                 SUNXI_DMA_DDMA_CFG_REG_LOADING,
 306                                 DEFAULT_TIMEOUT_US)) {
 307                printf("Error while waiting for dma transfer to finish\n");
 308                return -EIO;
 309        }
 310
 311        invalidate_dcache_range(dst,
 312                                ALIGN(dst + conf->ecc_size, ARCH_DMA_MINALIGN));
 313
 314        val = readl(SUNXI_NFC_BASE + NFC_ECC_ST);
 315
 316        /* ECC error detected. */
 317        if (val & 0xffff)
 318                return -EIO;
 319
 320        /*
 321         * Return 1 if the page is empty.
 322         * We consider the page as empty if the first ECC block is marked
 323         * empty.
 324         */
 325        return (val & 0x10000) ? 1 : 0;
 326}
 327
 328static int nand_max_ecc_strength(struct nfc_config *conf)
 329{
 330        static const int ecc_bytes[] = { 32, 46, 54, 60, 74, 88, 102, 110, 116 };
 331        int max_oobsize, max_ecc_bytes;
 332        int nsectors = conf->page_size / conf->ecc_size;
 333        int i;
 334
 335        /*
 336         * ECC strength is limited by the size of the OOB area which is
 337         * correlated with the page size.
 338         */
 339        switch (conf->page_size) {
 340        case 2048:
 341                max_oobsize = 64;
 342                break;
 343        case 4096:
 344                max_oobsize = 256;
 345                break;
 346        case 8192:
 347                max_oobsize = 640;
 348                break;
 349        case 16384:
 350                max_oobsize = 1664;
 351                break;
 352        default:
 353                return -EINVAL;
 354        }
 355
 356        max_ecc_bytes = max_oobsize / nsectors;
 357
 358        for (i = 0; i < ARRAY_SIZE(ecc_bytes); i++) {
 359                if (ecc_bytes[i] > max_ecc_bytes)
 360                        break;
 361        }
 362
 363        if (!i)
 364                return -EINVAL;
 365
 366        return i - 1;
 367}
 368
 369static int nand_detect_ecc_config(struct nfc_config *conf, u32 offs,
 370                                  void *dest)
 371{
 372        /* NAND with pages > 4k will likely require 1k sector size. */
 373        int min_ecc_size = conf->page_size > 4096 ? 1024 : 512;
 374        int page = offs / conf->page_size;
 375        int ret;
 376
 377        /*
 378         * In most cases, 1k sectors are preferred over 512b ones, start
 379         * testing this config first.
 380         */
 381        for (conf->ecc_size = 1024; conf->ecc_size >= min_ecc_size;
 382             conf->ecc_size >>= 1) {
 383                int max_ecc_strength = nand_max_ecc_strength(conf);
 384
 385                nand_apply_config(conf);
 386
 387                /*
 388                 * We are starting from the maximum ECC strength because
 389                 * most of the time NAND vendors provide an OOB area that
 390                 * barely meets the ECC requirements.
 391                 */
 392                for (conf->ecc_strength = max_ecc_strength;
 393                     conf->ecc_strength >= 0;
 394                     conf->ecc_strength--) {
 395                        conf->randomize = false;
 396                        if (nand_reset_column())
 397                                return -EIO;
 398
 399                        /*
 400                         * Only read the first sector to speedup detection.
 401                         */
 402                        ret = nand_read_page(conf, offs, dest, conf->ecc_size);
 403                        if (!ret) {
 404                                return 0;
 405                        } else if (ret > 0) {
 406                                /*
 407                                 * If page is empty we can't deduce anything
 408                                 * about the ECC config => stop the detection.
 409                                 */
 410                                return -EINVAL;
 411                        }
 412
 413                        conf->randomize = true;
 414                        conf->nseeds = ARRAY_SIZE(random_seed);
 415                        do {
 416                                if (nand_reset_column())
 417                                        return -EIO;
 418
 419                                if (!nand_read_page(conf, offs, dest,
 420                                                    conf->ecc_size))
 421                                        return 0;
 422
 423                                /*
 424                                 * Find the next ->nseeds value that would
 425                                 * change the randomizer seed for the page
 426                                 * we're trying to read.
 427                                 */
 428                                while (conf->nseeds >= 16) {
 429                                        int seed = page % conf->nseeds;
 430
 431                                        conf->nseeds >>= 1;
 432                                        if (seed != page % conf->nseeds)
 433                                                break;
 434                                }
 435                        } while (conf->nseeds >= 16);
 436                }
 437        }
 438
 439        return -EINVAL;
 440}
 441
 442static int nand_detect_config(struct nfc_config *conf, u32 offs, void *dest)
 443{
 444        if (conf->valid)
 445                return 0;
 446
 447        /*
 448         * Modern NANDs are more likely than legacy ones, so we start testing
 449         * with 5 address cycles.
 450         */
 451        for (conf->addr_cycles = 5;
 452             conf->addr_cycles >= 4;
 453             conf->addr_cycles--) {
 454                int max_page_size = conf->addr_cycles == 4 ? 2048 : 16384;
 455
 456                /*
 457                 * Ignoring 1k pages cause I'm not even sure this case exist
 458                 * in the real world.
 459                 */
 460                for (conf->page_size = 2048; conf->page_size <= max_page_size;
 461                     conf->page_size <<= 1) {
 462                        if (nand_load_page(conf, offs))
 463                                return -1;
 464
 465                        if (!nand_detect_ecc_config(conf, offs, dest)) {
 466                                conf->valid = true;
 467                                return 0;
 468                        }
 469                }
 470        }
 471
 472        return -EINVAL;
 473}
 474
 475static int nand_read_buffer(struct nfc_config *conf, uint32_t offs,
 476                            unsigned int size, void *dest)
 477{
 478        int first_seed, page, ret;
 479
 480        size = ALIGN(size, conf->page_size);
 481        page = offs / conf->page_size;
 482        first_seed = page % conf->nseeds;
 483
 484        for (; size; size -= conf->page_size) {
 485                if (nand_load_page(conf, offs))
 486                        return -1;
 487
 488                ret = nand_read_page(conf, offs, dest, conf->page_size);
 489                /*
 490                 * The ->nseeds value should be equal to the number of pages
 491                 * in an eraseblock. Since we don't know this information in
 492                 * advance we might have picked a wrong value.
 493                 */
 494                if (ret < 0 && conf->randomize) {
 495                        int cur_seed = page % conf->nseeds;
 496
 497                        /*
 498                         * We already tried all the seed values => we are
 499                         * facing a real corruption.
 500                         */
 501                        if (cur_seed < first_seed)
 502                                return -EIO;
 503
 504                        /* Try to adjust ->nseeds and read the page again... */
 505                        conf->nseeds = cur_seed;
 506
 507                        if (nand_reset_column())
 508                                return -EIO;
 509
 510                        /* ... it still fails => it's a real corruption. */
 511                        if (nand_read_page(conf, offs, dest, conf->page_size))
 512                                return -EIO;
 513                } else if (ret && conf->randomize) {
 514                        memset(dest, 0xff, conf->page_size);
 515                }
 516
 517                page++;
 518                offs += conf->page_size;
 519                dest += conf->page_size;
 520        }
 521
 522        return 0;
 523}
 524
 525int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest)
 526{
 527        static struct nfc_config conf = { };
 528        int ret;
 529
 530        ret = nand_detect_config(&conf, offs, dest);
 531        if (ret)
 532                return ret;
 533
 534        return nand_read_buffer(&conf, offs, size, dest);
 535}
 536
 537void nand_deselect(void)
 538{
 539        struct sunxi_ccm_reg *const ccm =
 540                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 541
 542        clrbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0));
 543#ifdef CONFIG_MACH_SUN9I
 544        clrbits_le32(&ccm->ahb_gate1, (1 << AHB_GATE_OFFSET_DMA));
 545#else
 546        clrbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_DMA));
 547#endif
 548        clrbits_le32(&ccm->nand0_clk_cfg, CCM_NAND_CTRL_ENABLE | AHB_DIV_1);
 549}
 550