uboot/drivers/mtd/nand/raw/denali_spl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2014       Panasonic Corporation
   4 * Copyright (C) 2014-2015  Masahiro Yamada <yamada.masahiro@socionext.com>
   5 */
   6
   7#include <common.h>
   8#include <log.h>
   9#include <asm/io.h>
  10#include <asm/unaligned.h>
  11#include <linux/delay.h>
  12#include <linux/mtd/rawnand.h>
  13#include "denali.h"
  14
  15#define DENALI_MAP01            (1 << 26)       /* read/write pages in PIO */
  16#define DENALI_MAP10            (2 << 26)       /* high-level control plane */
  17
  18#define INDEX_CTRL_REG          0x0
  19#define INDEX_DATA_REG          0x10
  20
  21#define SPARE_ACCESS            0x41
  22#define MAIN_ACCESS             0x42
  23#define PIPELINE_ACCESS         0x2000
  24
  25#define BANK(x) ((x) << 24)
  26
  27static void __iomem *denali_flash_mem =
  28                        (void __iomem *)CONFIG_SYS_NAND_DATA_BASE;
  29static void __iomem *denali_flash_reg =
  30                        (void __iomem *)CONFIG_SYS_NAND_REGS_BASE;
  31
  32static const int flash_bank;
  33static int page_size, oob_size, pages_per_block;
  34
  35static void index_addr(uint32_t address, uint32_t data)
  36{
  37        writel(address, denali_flash_mem + INDEX_CTRL_REG);
  38        writel(data, denali_flash_mem + INDEX_DATA_REG);
  39}
  40
  41static int wait_for_irq(uint32_t irq_mask)
  42{
  43        unsigned long timeout = 1000000;
  44        uint32_t intr_status;
  45
  46        do {
  47                intr_status = readl(denali_flash_reg + INTR_STATUS(flash_bank));
  48
  49                if (intr_status & INTR__ECC_UNCOR_ERR) {
  50                        debug("Uncorrected ECC detected\n");
  51                        return -EBADMSG;
  52                }
  53
  54                if (intr_status & irq_mask)
  55                        break;
  56
  57                udelay(1);
  58                timeout--;
  59        } while (timeout);
  60
  61        if (!timeout) {
  62                debug("Timeout with interrupt status %08x\n", intr_status);
  63                return -EIO;
  64        }
  65
  66        return 0;
  67}
  68
  69static void read_data_from_flash_mem(uint8_t *buf, int len)
  70{
  71        int i;
  72        uint32_t *buf32;
  73
  74        /* transfer the data from the flash */
  75        buf32 = (uint32_t *)buf;
  76
  77        /*
  78         * Let's take care of unaligned access although it rarely happens.
  79         * Avoid put_unaligned() for the normal use cases since it leads to
  80         * a bit performance regression.
  81         */
  82        if ((unsigned long)buf32 % 4) {
  83                for (i = 0; i < len / 4; i++)
  84                        put_unaligned(readl(denali_flash_mem + INDEX_DATA_REG),
  85                                      buf32++);
  86        } else {
  87                for (i = 0; i < len / 4; i++)
  88                        *buf32++ = readl(denali_flash_mem + INDEX_DATA_REG);
  89        }
  90
  91        if (len % 4) {
  92                u32 tmp;
  93
  94                tmp = cpu_to_le32(readl(denali_flash_mem + INDEX_DATA_REG));
  95                buf = (uint8_t *)buf32;
  96                for (i = 0; i < len % 4; i++) {
  97                        *buf++ = tmp;
  98                        tmp >>= 8;
  99                }
 100        }
 101}
 102
 103int denali_send_pipeline_cmd(int page, int ecc_en, int access_type)
 104{
 105        uint32_t addr, cmd;
 106        static uint32_t page_count = 1;
 107
 108        writel(ecc_en, denali_flash_reg + ECC_ENABLE);
 109
 110        /* clear all bits of intr_status. */
 111        writel(0xffff, denali_flash_reg + INTR_STATUS(flash_bank));
 112
 113        addr = BANK(flash_bank) | page;
 114
 115        /* setup the acccess type */
 116        cmd = DENALI_MAP10 | addr;
 117        index_addr(cmd, access_type);
 118
 119        /* setup the pipeline command */
 120        index_addr(cmd, PIPELINE_ACCESS | page_count);
 121
 122        cmd = DENALI_MAP01 | addr;
 123        writel(cmd, denali_flash_mem + INDEX_CTRL_REG);
 124
 125        return wait_for_irq(INTR__LOAD_COMP);
 126}
 127
 128static int nand_read_oob(void *buf, int page)
 129{
 130        int ret;
 131
 132        ret = denali_send_pipeline_cmd(page, 0, SPARE_ACCESS);
 133        if (ret < 0)
 134                return ret;
 135
 136        read_data_from_flash_mem(buf, oob_size);
 137
 138        return 0;
 139}
 140
 141static int nand_read_page(void *buf, int page)
 142{
 143        int ret;
 144
 145        ret = denali_send_pipeline_cmd(page, 1, MAIN_ACCESS);
 146        if (ret < 0)
 147                return ret;
 148
 149        read_data_from_flash_mem(buf, page_size);
 150
 151        return 0;
 152}
 153
 154static int nand_block_isbad(void *buf, int block)
 155{
 156        int ret;
 157
 158        ret = nand_read_oob(buf, block * pages_per_block);
 159        if (ret < 0)
 160                return ret;
 161
 162        return *((uint8_t *)buf + CONFIG_SYS_NAND_BAD_BLOCK_POS) != 0xff;
 163}
 164
 165/* nand_init() - initialize data to make nand usable by SPL */
 166void nand_init(void)
 167{
 168        /* access to main area */
 169        writel(0, denali_flash_reg + TRANSFER_SPARE_REG);
 170
 171        /*
 172         * These registers are expected to be already set by the hardware
 173         * or earlier boot code.  So we read these values out.
 174         */
 175        page_size = readl(denali_flash_reg + DEVICE_MAIN_AREA_SIZE);
 176        oob_size = readl(denali_flash_reg + DEVICE_SPARE_AREA_SIZE);
 177        pages_per_block = readl(denali_flash_reg + PAGES_PER_BLOCK);
 178
 179        /* Do as denali_hw_init() does. */
 180        writel(CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES,
 181               denali_flash_reg + SPARE_AREA_SKIP_BYTES);
 182        writel(0x0F, denali_flash_reg + RB_PIN_ENABLED);
 183        writel(CHIP_EN_DONT_CARE__FLAG, denali_flash_reg + CHIP_ENABLE_DONT_CARE);
 184        writel(0xffff, denali_flash_reg + SPARE_AREA_MARKER);
 185}
 186
 187int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
 188{
 189        int block, page, column, readlen;
 190        int ret;
 191        int force_bad_block_check = 1;
 192
 193        page = offs / page_size;
 194        column = offs % page_size;
 195
 196        block = page / pages_per_block;
 197        page = page % pages_per_block;
 198
 199        while (size) {
 200                if (force_bad_block_check || page == 0) {
 201                        ret = nand_block_isbad(dst, block);
 202                        if (ret < 0)
 203                                return ret;
 204
 205                        if (ret) {
 206                                block++;
 207                                continue;
 208                        }
 209                }
 210
 211                force_bad_block_check = 0;
 212
 213                ret = nand_read_page(dst, block * pages_per_block + page);
 214                if (ret < 0)
 215                        return ret;
 216
 217                readlen = min(page_size - column, (int)size);
 218
 219                if (unlikely(column)) {
 220                        /* Partial page read */
 221                        memmove(dst, dst + column, readlen);
 222                        column = 0;
 223                }
 224
 225                size -= readlen;
 226                dst += readlen;
 227                page++;
 228                if (page == pages_per_block) {
 229                        block++;
 230                        page = 0;
 231                }
 232        }
 233
 234        return 0;
 235}
 236
 237void nand_deselect(void) {}
 238