sdk-hwV1.3/lichee/linux-4.9/include/linux/mtd/aw-rawnand.h

1375 lines
37 KiB
C

/**
* SPDX-License-Identifier: GPL-2.0+
*
* (C) Copyright 2020 - 2021
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* cuizhikui <cuizhikui@allwinnertech.com>
*
*/
#ifndef __AW_RAWNAND_H__
#define __AW_RAWNAND_H__
#include <linux/mtd/mtd.h>
#include <linux/mutex.h>
/* aw rawnand warning messages */
#define awrawnand_warn(fmt, ...) pr_warn("awrawnand(mtd):warning: %s: " fmt, \
__func__, ##__VA_ARGS__)
/* aw rawnand error messages */
#define awrawnand_err(fmt, ...) pr_err("awrawnand(mtd):error: %s: " fmt, \
__func__, ##__VA_ARGS__)
/* aw rawnand info messages */
#define awrawnand_info(fmt, ...) pr_info("awrawnand(mtd):info:" fmt, \
##__VA_ARGS__)
/* aw rawnand debug messages */
#define awrawnand_dbg(fmt, ...) pr_debug("awrawnand(mtd): dbg:" fmt, \
##__VA_ARGS__)
/* aw rawnand messages */
#define awrawnand_print(fmt, ...) pr_err("awrawnand(mtd):" fmt, ##__VA_ARGS__)
//#define DBG
#ifdef DBG
#define AWRAWNAND_TRACE(fmt, ...) pr_err("awrawnand(mtd):" fmt, ##__VA_ARGS__)
#else
#define AWRAWNAND_TRACE(fmt, ...)
#endif
//#define DBG_NFC
#ifdef DBG_NFC
#define AWRAWNAND_TRACE_NFC(fmt, ...) pr_err("awrawnand(mtd):" fmt, ##__VA_ARGS__)
#else
#define AWRAWNAND_TRACE_NFC(fmt, ...)
#endif
//#define DBG_CHIP
#ifdef DBG_CHIP
#define awrawnand_chip_trace(fmt, ...) pr_err(fmt, ##__VA_ARGS__)
#else
#define awrawnand_chip_trace(fmt, ...)
#endif
//#define TRACE_UBI_MTD
#ifdef TRACE_UBI_MTD
#define awrawnand_ubi_trace(fmt, ...) pr_err("aw-mtd:" fmt, ##__VA_ARGS__)
#else
#define awrawnand_ubi_trace(fmt, ...)
#endif
//#define TRACE_MTD
#ifdef TRACE_MTD
#define awrawnand_mtd_trace(fmt, ...) pr_err(fmt, ##__VA_ARGS__)
#else
#define awrawnand_mtd_trace(fmt, ...)
#endif
/*
* rawnand multiplane.
*
* Merge pages in two adjacent blocks with the same page num to super page.
* Merge adjacent blocs to super block.
*
* phy-block0 phy-block1 = super block 0
* |------------|------------|
* | phy-page 0 | phy-page 0 | = super page 0 on super block 0
* | phy-page 1 | phy-page 1 | = super page 1 on super block 0
* | ... | ... |
* |------------|------------|
*
*/
#define SIMULATE_MULTIPLANE (1)
/* ecc status */
#define ECC_GOOD (0 << 4)
#define ECC_LIMIT (1 << 4)
#define ECC_ERR (2 << 4)
#define ECC_BLANK_PAGE (3 << 4)
#define MAX_CYCLE (5)
#define RAWNAND_MAX_ID_LEN (8U)
#define UBOOT_START_BLOCK_SMALLNAND 8
#define UBOOT_START_BLOCK_BIGNAND 4
#define AW_RAWNAND_RESERVED_PHY_BLK_FOR_SECURE_STORAGE 8
#define PHY_BLKS_FOR_SECURE_STORAGE AW_RAWNAND_RESERVED_PHY_BLK_FOR_SECURE_STORAGE
#define PSTORE_SIZE_KB 512
/*
* Standard NAND flash commands
*/
#define RAWNAND_CMD_READ0 0
#define RAWNAND_CMD_READ1 1
#define RAWNAND_CMD_RNDOUT 5
#define RAWNAND_CMD_PAGEPROG 0x10
#define RAWNAND_CMD_READOOB 0x50
#define RAWNAND_CMD_ERASE1 0x60
#define RAWNAND_CMD_STATUS 0x70
#define RAWNAND_CMD_SEQIN 0x80
#define RAWNAND_CMD_JEDEC_SEQIN 0x81
#define RAWNAND_CMD_RNDIN 0x85
#define RAWNAND_CMD_READID 0x90
#define RAWNAND_CMD_ERASE2 0xd0
#define RAWNAND_CMD_PARAM 0xec
#define RAWNAND_CMD_GET_FEATURES 0xee
#define RAWNAND_CMD_SET_FEATURES 0xef
#define RAWNAND_CMD_RESET 0xff
/* Extended commands for large page devices */
#define RAWNAND_CMD_READSTART 0x30
#define RAWNAND_CMD_RNDOUTSTART 0xE0
#define RAWNAND_CMD_CACHEDPROG 0x15
#define RAWNAND_CMD_MULTIPROG 0x11
#define RAWNAND_CMD_MULTIPREADSTART 0x32
#define RAWNAND_CMD_MULTIERASE 0xd1
#define TOGGLE_INTERFACE_CHANGE_ADDR (0x80)
/* Status bits */
#define RAWNAND_STATUS_FAIL 0x01
#define RAWNAND_STATUS_FAIL_N1 0x02
#define RAWNAND_STATUS_TRUE_READY 0x20
#define RAWNAND_STATUS_READY 0x40
#define RAWNAND_STATUS_WP 0x80
#define DEV_IO_READY (0x1)
#define DEV_ARRAY_READY (0x2)
#define DEV_READY (0x3)
#define FEATURES_PARA_LEN (4)
/*idtab options bitmap*/
/* Device interface*/
#define RAWNAND_ITF_SDR BIT(0)
#define RAWNAND_ITF_ONFI_DDR BIT(1)
#define RAWNAND_ITF_ONFI_DDR2 BIT(2)
#define RAWNAND_ITF_TOGGLE_DDR BIT(3)
#define RAWNAND_ITF_TOGGLE_DDR2 BIT(4)
/* TOGGLE only support*/
#define RAWNAND_TOGGLE_SUPPORT_ONLY BIT(5)
/* ONFI timing mode, used in both asynchronous and synchronous mode */
#define RAWNAND_ONFI_TIMING_MODE BIT(6)
/* ONFI features */
#define RAWNAND_ONFI_FEATURE_EXT_PARAM_PAGE BIT(7)
/* Chip has cache program function */
#define RAWNAND_CACHEPRG BIT(8)
/* Chip has copy back function */
#define RAWNAND_COPYBACK BIT(9)
/* Chip allow multi writes */
/* 80h -- 11h ~ 80h -- 10h*/
#define RAWNAND_MULTI_WRITE BIT(10)
/* Chip allow multi reads */
#define RAWNAND_MULTI_READ BIT(11)
/* Chip allow multi erase 60h-60h-d0h*/
#define RAWNAND_MULTI_ERASE BIT(12)
/* Chip allow onfi multi erase 60h-d1h -- 60h- d0h*/
#define RAWNAND_MULTI_ONFI_ERASE BIT(13)
/* Chip allow multi writes */
/* 80h -- 11h ~ 81h -- 10h*/
#define RAWNAND_JEDEC_MULTI_WRITE BIT(14)
/* Device needs 2rd row address cycle */
#define RAWNAND_ROW_ADDR_2 BIT(16)
/* Default Toggle DDR1.0 , SDR need to set*/
#define RAWNAND_TOGGLE_DDR_TO_SDR BIT(29)
/* Open nfc randomizer */
#define RAWNAND_NFC_RANDOM BIT(30)
/* Macros to identify the above */
#define RAWNAND_HAS_ONLY_TWO_ADDR(chip) ((chip->options & RAWNAND_ROW_ADDR_2))
#define RAWNAND_HAS_ITF_SDR(chip) ((chip->options & RAWNAND_ITF_SDR))
#define RAWNAND_HAS_ITF_ONFI_DDR(chip) ((chip->options & RAWNAND_ITF_ONFI_DDR))
#define RAWNAND_HAS_ITF_ONFI_DDR2(chip) ((chip->options & RAWNAND_ITF_ONFI_DDR2))
#define RAWNAND_HAS_ITF_TOGGLE_DDR(chip) ((chip->options & RAWNAND_ITF_TOGGLE_DDR))
#define RAWNAND_HAS_ITF_TOGGLE_DDR2(chip) ((chip->options & RAWNAND_ITF_TOGGLE_DDR2))
#define RAWNAND_HAS_CACHEPROG(chip) ((chip->options & RAWNAND_CACHEPRG))
#define RAWNAND_HAS_MULTI_WRITE(chip) ((chip)->options & RAWNAND_MULTI_WRITE)
#define RAWNAND_HAS_JEDEC_MULTI_WRITE(chip) ((chip)->options & RAWNAND_JEDEC_MULTI_WRITE)
#define RAWNAND_HAS_MULTI_READ(chip) ((chip->options & RAWNAND_MULTI_READ))
#define RAWNAND_HAS_MULTI_ERASE(chip) ((chip->options & RAWNAND_MULTI_ERASE))
#define RAWNAND_HAS_MULTI_ONFI_ERASE(chip) ((chip->options & RAWNAND_MULTI_ONFI_ERASE))
#define RAWNAND_HAS_ONLY_TOGGLE(chip) ((chip->options & RAWNAND_TOGGLE_SUPPORT_ONLY))
#define RAWNAND_NEED_CHANGE_TO_SDR(chip) ((chip->options & RAWNAND_TOGGLE_DDR_TO_SDR))
#define RAWNAND_NFC_NEED_RANDOM(chip) ((chip->options & RAWNAND_NFC_RANDOM))
/*
* RAW NAND Flash Manufacturer ID Codes
*/
#define RAWNAND_MFR_TOSHIBA 0x98
#define RAWNAND_MFR_SAMSUNG 0xec
#define RAWNAND_MFR_FUJITSU 0x04
#define RAWNAND_MFR_NATIONAL 0x8f
#define RAWNAND_MFR_RENESAS 0x07
#define RAWNAND_MFR_STMICRO 0x20
#define RAWNAND_MFR_HYNIX 0xad
#define RAWNAND_MFR_MICRON 0x2c
#define RAWNAND_MFR_AMD 0x01
#define RAWNAND_MFR_MACRONIX 0xc2
#define RAWNAND_MFR_EON 0x92
#define RAWNAND_MFR_SANDISK 0x45
#define RAWNAND_MFR_INTEL 0x89
#define RAWNAND_MFR_ATO 0x9b
#define RAWNAND_MFR_SPANSION 0x01
#define RAWNAND_MFR_ESMT 0xc8
#define RAWNAND_MFR_GIGA 0xc8
#define RAWNAND_MFR_MXIC 0xc2
#define RAWNAND_MFR_FORESEE 0xec
#define RAWNAND_MFR_WINBOND 0xef
#define RAWNAND_MFR_FIDELIX 0xad
#define RAWNAND_MFR_UNILC 0xc8
#define RAWNAND_MFR_JSC 0xad
#define RAWNAND_MFR_DOSILICON 0xf8
#define RAWNAND_MFR_FORESEE_1 0xcd
#define RAWNAND_MFR_DOSILICON_1 0xe5
/*
* RAWNAND Flash Manufacture name
* */
#define SPANSION_NAME "spansion"
#define ATO_NAME "ato"
#define EON_NAME "eon"
#define ESMT_NAME "esmt"
#define FUJITSU_NAME "fujitsu"
#define HYNIX_NAME "hynix"
#define INTEL_NAME "intel"
#define MACRONIX_NAME "macronix"
#define GIGA_NAME "giga"
#define MXIC_NAME "mxic"
#define MICRON_NAME "micron"
#define NATIONAL_NAME "national"
#define RENESAS_NAME "renesas"
#define SAMSUNG_NAME "samsung"
#define SANDISK_NAME "sandisk"
#define STMICRO_NAME "stmicro"
#define TOSHIBA_NAME "toshiba"
#define WINBOND_NAME "winbond"
#define FORESEE_NAME "foresee"
#define FIDELIX_NAME "fidelix"
#define UNILC_NAME "unilc"
#define JSC_NAME "jsc"
#define DOSILICON_NAME "dosilicon"
#define PE_CYCLES_1K (1000)
#define PE_CYCLES_2K (2000)
#define PE_CYCLES_3K (3000)
#define PE_CYCLES_4K (4000)
#define PE_CYCLES_5K (5000)
#define PE_CYCLES_6K (6000)
#define PE_CYCLES_7K (7000)
#define PE_CYCLES_8K (8000)
#define PE_CYCLES_9K (9000)
#define PE_CYCLES_10K (10000)
#define PE_CYCLES_20K (20000)
#define PE_CYCLES_30K (30000)
#define PE_CYCLES_40K (40000)
#define PE_CYCLES_50K (50000)
#define PE_CYCLES_60K (60000)
#define PE_CYCLES_70K (70000)
#define PE_CYCLES_80K (80000)
#define PE_CYCLES_90K (90000)
#define PE_CYCLES_100K (100000)
#define PE_CYCLES_200K (200000)
#define PE_CYCLES_300K (300000)
#define PE_CYCLES_500K (500000)
#define PE_CYCLES_600K (600000)
#define PE_CYCLES_700K (700000)
#define PE_CYCLES_800K (800000)
#define PE_CYCLES_900K (900000)
#define PE_CYCLES_1000K (1000000)
#define BCH_NO (-1)
#define BCH_16 (0)
#define BCH_24 (1)
#define BCH_28 (2)
#define BCH_32 (3)
#define BCH_40 (4)
#define BCH_44 (5)
#define BCH_48 (6)
#define BCH_52 (7)
#define BCH_56 (8)
#define BCH_60 (9)
#define BCH_64 (10)
#define BCH_68 (11)
#define BCH_72 (12)
#define BCH_76 (13)
#define BCH_80 (14)
#define B_TO_KB(x) ((x) >> 10)
#define MOD(x, y) ((x) % (y))
#define MAX_CHIPS (4U)
enum error_management {
/*first spare area location on first page of each block*/
PST_FIRST_PAGE = 0x1,
/*first spare area location on first page and second page of each block*/
PST_FIRST_TWO_PAGES = 0x11,
/*first spare area location on last page of each block*/
PST_LAST_PAGE = 0x2,
/*first spare area location on last two page of each block*/
PST_LAST_TWO_PAGES = 0x22,
/*first spare area location on first and last page of each block*/
PST_FIRST_AND_LAST_PAGES = 0x4,
/*first spare area location on first two and last page of each block*/
PST_FIRST_TWO_AND_LAST_PAGES = 0x8,
};
struct aw_nand_flash_dev {
char *name;
union {
struct {
uint8_t mfr_id;
uint8_t dev_id;
};
uint8_t id[RAWNAND_MAX_ID_LEN];
};
int id_len;
unsigned int dies_per_chip;
/*main data size, eg. Page Size:(2K+64)byte ==> pagesize=2K byte,
* sparesize=64byte*/
unsigned int pagesize;
unsigned int sparesize;
unsigned int pages_per_blk;
unsigned int blks_per_die;
unsigned int access_freq;
enum error_management badblock_flag_pos;
unsigned int pe_cycles;
unsigned int options;
};
struct rawnand_manufacture {
u8 id;
char *name;
struct aw_nand_flash_dev *dev;
int ndev;
};
#define RAWNAND_MANUFACTURE(_id, _name, _mfr) \
{ \
.id = _id, \
.name = _name, \
.dev = _mfr, \
.ndev = (sizeof(_mfr) / sizeof(_mfr[0])), \
}
struct aw_nand_manufactures {
struct rawnand_manufacture *manuf;
int nm;
};
#define AW_NAND_MANUFACTURE(_aw_nand, _manufs) \
struct aw_nand_manufactures _aw_nand = { \
.manuf = _manufs, \
.nm = (sizeof(_manufs) / sizeof(_manufs[0])), \
}
struct aw_nand_chip;
struct mtd_info;
extern struct aw_nand_chip awnand_chip;
extern struct aw_nand_manufactures aw_nand_manufs;
extern struct aw_nand_sec_sto rawnand_sec_sto;
struct nfc_reg {
volatile unsigned int *ctl; /*0x0000 NDFC Control Register*/
volatile unsigned int *sta; /*0x0004 NDFC Status Register*/
volatile unsigned int *int_ctl; /*0x0008 NDFC Interrupt and DMA Enable Register*/
volatile unsigned int *timing_ctl; /*0x000C NDFC Timing Control Register*/
volatile unsigned int *timing_cfg; /*0x0010 NDFC Timing Configure Register*/
volatile unsigned int *addr_low; /*0x0014 NDFC Address Low Word Register*/
volatile unsigned int *addr_high; /*0x0018 NDFC Address High Word Register*/
volatile unsigned int *data_block_mask; /*0x001C NDFC Data Block Mask Register*/
volatile unsigned int *cnt; /*0x0020 NDFC Data Block Mask Register*/
volatile unsigned int *cmd; /*0x0024 NDFC Command IO Register*/
volatile unsigned int *read_cmd_set; /*0x0028 NDFC Command Set Register 0*/
volatile unsigned int *write_cmd_set; /*0x002C NDFC Command Set Register 1*/
volatile unsigned int *ecc_ctl; /*0x0034 NDFC ECC Control Register*/
volatile unsigned int *ecc_sta; /*0x0038 NDFC ECC Status Register*/
volatile unsigned int *data_pattern_sta; /*0x003C NDFC Data Pattern Status Register*/
volatile unsigned int *efr; /*0x0040 NDFC Enhanced Featur Register*/
volatile unsigned int *rdata_sta_ctl; /*0x0044 NDFC Read Data Status Control Register*/
volatile unsigned int *rdata_sta_0; /*0x0048 NDFC Read Data Status Register 0*/
volatile unsigned int *rdata_sta_1; /*0x004C NDFC Read Data Status Register 1*/
#define MAX_ERR_CNT (8U)
volatile unsigned int *err_cnt[MAX_ERR_CNT]; /*0x0050 NDFC Error Counter Register 0*/
#define MAX_USER_DATA_LEN (4U)
volatile unsigned int *user_data_len_base; /*0x0070 NDFC User Data Length Register X*/
#define MAX_USER_DATA (32U)
volatile unsigned int *user_data_base; /*0x0080 NDFC User Data Register X*/
volatile unsigned int *efnand_sta; /*0x0110 NDFC EFNAND STATUS Register*/
volatile unsigned int *spare_area; /*0x0114 NDFC Spare Aera Register*/
volatile unsigned int *pat_id; /*0x0118 NDFC Pattern ID Register*/
volatile unsigned int *ddr2_spec_ctl; /*0x011C NDFC DDR2 Specific Control Register*/
volatile unsigned int *ndma_mode_ctl; /*0x0120 NDFC Normal DMA Mode Control Register*/
volatile unsigned int *mbus_dma_dlba; /*0x0200 NDFC MBUS DMA Descriptor List Base Address Register in no.1 version*/
volatile unsigned int *mbus_dma_sta; /*0x0204 NDFC MBUS DMA Interrupt Status Register in no.1 version*/
volatile unsigned int *mdma_int_mask; /*0x0208 NDFC MBUS DMA Interrupt Enable Register in no.1 version*/
volatile unsigned int *mdma_cur_desc_addr; /*0x020C NDFC MBUS DMA Current Descriptor Address Register in no.1 version*/
volatile unsigned int *mdma_cur_buf_addr; /*0x0210 NDFC MBUS DMA Current Buffer Address Register in no.1 version*/
volatile unsigned int *dma_cnt; /*0x0214 NDFC Normal DMA Byte Counter Register*/
volatile unsigned int *ver; /*0x02F0 NDFC Version Number Register*/
volatile unsigned int *ram0_base; /*0x0400 NDFC Control Register*/
volatile unsigned int *ram1_base; /*0x0800 NDFC Control Register*/
};
enum op_type {
FLASH_READ = 0,
FLASH_WRITE,
FLASH_CACHE_READ,
FLASH_CACHE_WRITE,
FLASH_MULTI_READ,
FLASH_MULTI_WRITE,
FLASH_ULTI_CACHE_READ,
FLASH_MULTI_CACHE_WRITE,
};
enum normal_req_type {
CMD = 0,
/*e.g. erase block*/
CMD_WITH_ADDR,
/*e.g. set/get feature/read page parameter/read id/read status (addr_cycles is 0)*/
CMD_WITH_ADDR_DATA,
};
enum ecc_layout {
INTERLEAVE = 0,
SEQUENCE,
};
enum data_type {
MAINSPARE = 0,
ONLY_SPARE,
};
enum plane_ab {
PLANE_A = 0,
PLANE_B,
};
struct aw_nfc_normal_req {
enum normal_req_type type;
bool wait_rb;
union {
struct {
uint8_t code;
} cmd;
struct {
uint8_t code;
uint8_t addr[MAX_CYCLE];
/*valid address number*/
uint8_t addr_cycles;
} cmd_with_addr;
struct {
/*read status*/
uint8_t code;
int len;
uint8_t *in;
} cmd_with_data;
struct {
uint8_t code;
uint8_t addr[MAX_CYCLE];
/*valid address number*/
uint8_t addr_cycles;
uint8_t direct;
int len;
uint8_t *in;
uint8_t *out;
} cmd_with_addr_data;
} op;
};
#define NORMAL_REQ_CMD_WITH_ADDR1_DATA_OUT(_req, _cmd, _addr, _data, _len) \
struct aw_nfc_normal_req _req = { \
.type = CMD_WITH_ADDR_DATA, \
.op = { \
.cmd_with_addr_data = { \
.code = _cmd, \
.addr[0] = _addr, \
.addr_cycles = 1, \
.direct = FLASH_WRITE, \
.len = _len, \
.out = _data, \
} \
} \
}
#define NORMAL_REQ_CMD_WITH_ADDR0_DATA_IN(_req, _cmd, _data, _len) \
struct aw_nfc_normal_req _req = { \
.type = CMD_WITH_ADDR_DATA, \
.op = { \
.cmd_with_addr_data = { \
.code = _cmd, \
.addr_cycles = 0, \
.direct = FLASH_READ, \
.len = _len, \
.in = _data, \
} \
} \
}
#define NORMAL_REQ_CMD_WITH_ADDR1_DATA_IN(_req, _cmd, _addr, _data, _len) \
struct aw_nfc_normal_req _req = { \
.type = CMD_WITH_ADDR_DATA, \
.op = { \
.cmd_with_addr_data = { \
.code = _cmd, \
.addr[0] = _addr, \
.addr_cycles = 1, \
.direct = FLASH_READ, \
.len = _len, \
.in = _data, \
} \
} \
}
#define NORMAL_REQ_CMD(_req, _cmd_code) \
struct aw_nfc_normal_req _req = { \
.type = CMD, \
.wait_rb = 0, \
.op = { \
.cmd = { \
.code = _cmd_code, \
} \
} \
}
#define NORMAL_REQ_CMD_WAIT_RB(_req, _cmd_code) \
struct aw_nfc_normal_req _req = { \
.type = CMD, \
.wait_rb = 1, \
.op = { \
.cmd = { \
.code = _cmd_code, \
} \
} \
}
#define NORMAL_REQ_CMD_WITH_ADDR_N1(_req, _cmd_code, _addr) \
struct aw_nfc_normal_req _req = { \
.type = CMD_WITH_ADDR, \
.wait_rb = 0, \
.op = { \
.cmd_with_addr = { \
.code = _cmd_code, \
.addr[0] = _addr, \
.addr_cycles = 1, \
} \
} \
}
#define NORMAL_REQ_CMD_WITH_ADDR_N2(_req, _cmd_code, _addr1, _addr2) \
struct aw_nfc_normal_req _req = { \
.type = CMD_WITH_ADDR, \
.op = { \
.cmd_with_addr = { \
.code = _cmd_code, \
.addr[0] = _addr1, \
.addr[1] = _addr2, \
.addr_cycles = 2, \
} \
} \
}
#define NORMAL_REQ_CMD_WITH_ADDR_N3(_req, _cmd_code, _addr1, _addr2, _addr3) \
struct aw_nfc_normal_req _req = { \
.type = CMD_WITH_ADDR, \
.op = { \
.cmd_with_addr = { \
.code = _cmd_code, \
.addr[0] = _addr1, \
.addr[1] = _addr2, \
.addr[2] = _addr3, \
.addr_cycles = 3, \
} \
} \
}
#define NORMAL_REQ_CMD_WITH_ADDR_N4(_req, _cmd_code, _addr1, _addr2, _addr3, _addr4) \
struct aw_nfc_normal_req _req = { \
.type = CMD_WITH_ADDR, \
.op = { \
.cmd_with_addr = { \
.code = _cmd_code, \
.addr[0] = _addr1, \
.addr[1] = _addr2, \
.addr[2] = _addr3, \
.addr[3] = _addr4, \
.addr_cycles = 4, \
} \
} \
}
#define NORMAL_REQ_CMD_WITH_ADDR_N5(_req, _cmd_code, _addr1, _addr2, _addr3, _addr4, _addr5) \
struct aw_nfc_normal_req _req = { \
.type = CMD_WITH_ADDR, \
.op = { \
.cmd_with_addr = { \
.code = _cmd_code, \
.addr[0] = _addr1, \
.addr[1] = _addr2, \
.addr[2] = _addr3, \
.addr[3] = _addr4, \
.addr[4] = _addr5, \
.addr[5] = _addr5, \
.addr_cycles = 5, \
} \
} \
}
#define NORMAL_REQ_GET_ADDR(__p_req, __p_addr_low, __p_addr_high) \
int i = 0; \
\
for (i = 0; i < __p_req->addr_cycles; i++) { \
if (i < 4) \
(*__p_addr_low) |= req->addr[i] << (i * 8); \
else \
(*__p_addr_high) |= req->addr[i] << ((i - 4) * 8); \
} \
struct aw_nfc_batch_req {
enum op_type type;
enum ecc_layout layout;
enum plane_ab plane;
union {
struct {
uint8_t first;
uint8_t snd;
uint8_t rnd1;
uint8_t rnd2;
} val;
struct {
/*page read*/
uint8_t READ0;
uint8_t READSTART;
uint8_t RNOUT;
uint8_t RNOUTSTART;
} r;
struct {
/*page program/write*/
uint8_t SEQIN;
uint8_t PAGEPROG;
uint8_t RNDIN;
} w;
struct {
/*page cache write*/
uint8_t SEQIN;
uint8_t CACHEDPROG;
uint8_t RNDIN;
} cw;
struct {
/*multi-plane page write*/
uint8_t SEQIN;
uint8_t MULTIPROG;
uint8_t RNDIN;
} mw;
struct {
/*page read*/
uint8_t READ0;
uint8_t MULTIREADSTART;
uint8_t RNOUT;
uint8_t RNOUTSTART;
} mr;
} cmd;
struct {
uint32_t page;
uint8_t row_cycles;
} addr;
struct {
enum data_type type;
/*main_len align with ecc_block(1KB)*/
/*spare_len == chip->avalid_sparesize*/
int main_len;
int spare_len;
uint8_t *main;
uint8_t *spare;
} data;
};
#define BATCH_REQ_READ(_req, _page, _row_cycles, _mdata, _mlen, _sdata, _slen) \
struct aw_nfc_batch_req _req = { \
.type = FLASH_READ, \
.layout = INTERLEAVE, \
.cmd.r = { \
.READ0 = RAWNAND_CMD_READ0, \
.READSTART = RAWNAND_CMD_READSTART, \
.RNOUT = RAWNAND_CMD_RNDOUT, \
.RNOUTSTART = RAWNAND_CMD_RNDOUTSTART, \
}, \
.addr = { \
.page = _page, \
.row_cycles = _row_cycles, \
}, \
.data = { \
.type = MAINSPARE, \
.main_len = _mlen, \
.spare_len = _slen, \
.main = _mdata, \
.spare = _sdata, \
}, \
}
#define BATCH_REQ_MULTI_READ(_req, _page, _row_cycles, _mdata, _mlen, _sdata, _slen) \
struct aw_nfc_batch_req _req = { \
.type = FLASH_MULTI_READ, \
.layout = INTERLEAVE, \
.cmd.mr = { \
.READ0 = RAWNAND_CMD_READ0, \
.MULTIREADSTART = RAWNAND_CMD_MULTIPREADSTART, \
.RNOUT = RAWNAND_CMD_RNDOUT, \
.RNOUTSTART = RAWNAND_CMD_RNDOUTSTART, \
}, \
.addr = { \
.page = _page, \
.row_cycles = _row_cycles, \
}, \
.data = { \
.type = MAINSPARE, \
.main_len = _mlen, \
.spare_len = _slen, \
.main = _mdata, \
.spare = _sdata, \
}, \
}
#define BATCH_REQ_READ_SEQ(_req, _page, _row_cycles, _mdata, _mlen, _sdata, _slen) \
struct aw_nfc_batch_req _req = { \
.type = FLASH_READ, \
.layout = SEQUENCE, \
.cmd.r = { \
.READ0 = RAWNAND_CMD_READ0, \
.READSTART = RAWNAND_CMD_READSTART, \
.RNOUT = RAWNAND_CMD_RNDOUT, \
.RNOUTSTART = RAWNAND_CMD_RNDOUTSTART, \
}, \
.addr = { \
.page = _page, \
.row_cycles = _row_cycles, \
}, \
.data = { \
.type = MAINSPARE, \
.main_len = _mlen, \
.spare_len = _slen, \
.main = _mdata, \
.spare = _sdata, \
}, \
}
#define BATCH_REQ_READ_ONLY_SPARE(_req, _page, _row_cycles, _sdata, _slen) \
struct aw_nfc_batch_req _req = { \
.type = FLASH_READ, \
.layout = INTERLEAVE, \
.cmd.r = { \
.READ0 = RAWNAND_CMD_READ0, \
.READSTART = RAWNAND_CMD_READSTART, \
.RNOUT = RAWNAND_CMD_RNDOUT, \
.RNOUTSTART = RAWNAND_CMD_RNDOUTSTART, \
}, \
.addr = { \
.page = _page, \
.row_cycles = _row_cycles, \
}, \
.data = { \
.type = ONLY_SPARE, \
.main_len = 0, \
.spare_len = _slen, \
.main = NULL, \
.spare = _sdata, \
}, \
}
#define BATCH_REQ_WRITE(_req, _page, _row_cycles, _mdata, _mlen, _sdata, _slen) \
struct aw_nfc_batch_req _req = { \
.type = FLASH_WRITE, \
.layout = INTERLEAVE, \
.cmd.w = { \
.SEQIN = RAWNAND_CMD_SEQIN, \
.PAGEPROG = RAWNAND_CMD_PAGEPROG, \
.RNDIN = RAWNAND_CMD_RNDIN, \
}, \
.addr = { \
.page = _page, \
.row_cycles = _row_cycles, \
}, \
.data = { \
.type = MAINSPARE, \
.main_len = _mlen, \
.spare_len = _slen, \
.main = _mdata, \
.spare = _sdata, \
}, \
}
#define BATCH_REQ_JEDEC_WRITE(_req, _page, _row_cycles, _mdata, _mlen, _sdata, _slen) \
struct aw_nfc_batch_req _req = { \
.type = FLASH_WRITE, \
.layout = INTERLEAVE, \
.cmd.w = { \
.SEQIN = RAWNAND_CMD_JEDEC_SEQIN, \
.PAGEPROG = RAWNAND_CMD_PAGEPROG, \
.RNDIN = RAWNAND_CMD_RNDIN, \
}, \
.addr = { \
.page = _page, \
.row_cycles = _row_cycles, \
}, \
.data = { \
.type = MAINSPARE, \
.main_len = _mlen, \
.spare_len = _slen, \
.main = _mdata, \
.spare = _sdata, \
}, \
}
#define BATCH_REQ_MULTI_WRITE(_req, _page, _row_cycles, _mdata, _mlen, _sdata, _slen, _plane) \
struct aw_nfc_batch_req _req = { \
.type = FLASH_MULTI_WRITE, \
.layout = INTERLEAVE, \
.plane = _plane, \
.cmd.mw = { \
.SEQIN = RAWNAND_CMD_SEQIN, \
.MULTIPROG = RAWNAND_CMD_MULTIPROG, \
.RNDIN = RAWNAND_CMD_RNDIN, \
}, \
.addr = { \
.page = _page, \
.row_cycles = _row_cycles, \
}, \
.data = { \
.type = MAINSPARE, \
.main_len = _mlen, \
.spare_len = _slen, \
.main = _mdata, \
.spare = _sdata, \
}, \
}
#define BATCH_REQ_CACHE_WRITE(_req, _page, _row_cycles, _mdata, _mlen, _sdata, _slen) \
struct aw_nfc_batch_req _req = { \
.type = FLASH_CACHE_WRITE, \
.layout = INTERLEAVE, \
.cmd.cw = { \
.SEQIN = RAWNAND_CMD_SEQIN, \
.CACHEDPROG = RAWNAND_CMD_CACHEDPROG, \
.RNDIN = RAWNAND_CMD_RNDIN, \
}, \
.addr = { \
.page = _page, \
.row_cycles = _row_cycles, \
}, \
.data = { \
.type = MAINSPARE, \
.main_len = _mlen, \
.spare_len = _slen, \
.main = _mdata, \
.spare = _sdata, \
}, \
}
#define BATCH_REQ_WRITE_SEQ(_req, _page, _row_cycles, _mdata, _mlen, _sdata, _slen) \
struct aw_nfc_batch_req _req = { \
.type = FLASH_WRITE, \
.layout = SEQUENCE, \
.cmd.w = { \
.SEQIN = RAWNAND_CMD_SEQIN, \
.PAGEPROG = RAWNAND_CMD_PAGEPROG, \
.RNDIN = RAWNAND_CMD_RNDIN, \
}, \
.addr = { \
.page = _page, \
.row_cycles = _row_cycles, \
}, \
.data = { \
.type = MAINSPARE, \
.main_len = _mlen, \
.spare_len = _slen, \
.main = _mdata, \
.spare = _sdata, \
}, \
}
/**
* enum nand_data_interface_type - NAND interface timing type
* @NAND_SDR_IFACE: Single Data Rate interface
*/
enum rawnand_data_interface_type {
RAWNAND_SDR_IFACE = 0,
RAWNAND_ONFI_DDR = 0x2,
RAWNAND_ONFI_DDR2 = 0x12,
RAWNAND_TOGGLE_DDR = 0x3,
RAWNAND_TOGGLE_DDR2 = 0x13,
};
enum dma_type {
GENERIC_DMA = 0,
MBUS_DMA,
};
#define NFC_DESC_FIRST_FLAG (0x1 << 3)
#define NFC_DESC_LAST_FLAG (0x1 << 2)
#define NFC_DMA_DESC_MAX_NUM (32)
#define NFC_DESC_BSIZE(bsize) ((bsize)&0xFFFF) /*in order to ndfc spec BUFF_SIZE 16bits valid*/
struct aw_nfc_dma_desc {
unsigned int cfg;
unsigned int bcnt;
unsigned int buff;
struct aw_nfc_dma_desc *next;
};
struct aw_nand_host {
struct device *dev;
struct pinctrl *pinctrl;
void __iomem *base;
struct nfc_reg nfc_reg;
struct clk *pclk; /*pll clock*/
struct clk *mdclk; /*nand module clock*/
struct clk *mcclk; /*nand ecc engine clock*/
#ifndef __UBOOT__
struct regulator *vcc_nand;
struct regulator *vcc_io;
#endif
unsigned int mdclk_val;
unsigned int mcclk_val;
bool init;
unsigned long clk_rate;
unsigned int timing_ctl;
unsigned int timing_cfg;
enum rawnand_data_interface_type nf_type;
u8 cs[4];
u8 rb[4];
/*1: use b2r int when rb signal from busy to ready; 0: don't use b2r int*/
uint8_t use_rb_int;
uint8_t rb_ready_flag;
uint8_t use_dma;
enum dma_type dma_type;
dma_addr_t dma_addr;
dma_addr_t desc_addr; /*descripte dma addr*/
/*1: use dma int when dma is completed; 0: don't use dma int*/
uint8_t use_dma_int;
uint8_t dma_ready_flag;
uint8_t bitflips;
#define MAX_SPARE_SIZE (64)
uint8_t *spare_default;
struct aw_nfc_dma_desc *nfc_dma_desc; /*physic addr*/
struct aw_nfc_dma_desc *nfc_dma_desc_cpu; /*virtual addr*/
int (*normal_op)(struct aw_nand_chip *chip, struct aw_nfc_normal_req *req);
int (*batch_op)(struct aw_nand_chip *chip, struct aw_nfc_batch_req *req);
bool (*rb_ready)(struct aw_nand_chip *chip, struct aw_nand_host *host);
void *priv;
};
#define NAND_DATA_ITF_TYPE_TOGGLE_DDR1_2(chip) \
((chip->data_interface.type == RAWNAND_TOGGLE_DDR) || \
(chip->data_interface.type == RAWNAND_TOGGLE_DDR2))
/**
* struct nand_data_interface - NAND interface timing
* @type: type of the timing
* @timings: The timing, type according to @type
*/
struct rawnand_data_interface {
enum rawnand_data_interface_type type;
int (*set_feature)(struct aw_nand_chip *chip,
int feature_addr, uint8_t *feature_para);
int (*get_feature)(struct aw_nand_chip *chip,
int feature_addr, uint8_t *feature_para);
};
struct ce_info {
int ce_no;
int relate_rb_no;
};
struct select_chip {
int chip_no;
struct ce_info ceinfo[MAX_CHIPS];
};
/*aw_nand_chip_cache design in simu chip layer*/
struct aw_nand_chip_cache {
#define INVALID_CACHE (-1)
uint32_t simu_pageno;
uint32_t simu_oobno;
int simu_page_len;
/*valid data size in simup pagebuf start*/
int valid_col;
/*valid data size in simu pagebuf len from valid col*/
int valid_len;
uint8_t *simu_pagebuf;
/*valid data size in simu oob start*/
int valid_oob_col;
/*valid data size in simu oob len from valid oob col*/
int valid_oob_len;
int simu_oob_len;
uint8_t *simu_oobbuf;
uint8_t bitflips;
int sub_page_len;
int chipno;
};
struct aw_nand_chip {
struct mutex lock;
/**************************
* mtd layer
*------------------------
* simu chip
*------------------------
* chip
*| --blkn----|--blkn+1--|
*| (planeA) | (planeB)|
* ************************/
struct mtd_info mtd;
#define SLC_NAND (0)
#define MLC_NAND (1)
int type;
uint8_t id[RAWNAND_MAX_ID_LEN];
unsigned int dies;
#define MAX_DIES (2U)
uint64_t diesize[MAX_DIES];
int chips;
uint64_t chipsize;
uint64_t simu_chipsize;
int chip_shift;
int simu_chip_shift;
int chip_pages;
/*simulation is for multi, see line@48 rawnand multiplane layout.*/
int simu_chip_pages;
int chip_pages_mask;
int simu_chip_pages_mask;
/*main data size*/
int pagesize;
int simu_pagesize;
/*main data size shift*/
unsigned int pagesize_shift;
unsigned int simu_pagesize_shift;
int pagesize_mask;
int simu_pagesize_mask;
/*main data size + spare data size*/
int real_pagesize;
unsigned int erasesize;
unsigned int simu_erasesize;
unsigned int erase_shift;
unsigned int simu_erase_shift;
unsigned int erasesize_mask;
unsigned int simu_erasesize_mask;
unsigned int pages_per_blk_shift;
unsigned int simu_pages_per_blk_shift;
unsigned int pages_per_blk_mask;
unsigned int simu_pages_per_blk_mask;
int avalid_sparesize;
int ecc_mode;
int random;
int row_cycles;
enum error_management badblock_mark_pos;
unsigned int pe_cycles;
unsigned int options;
int clk_rate;
int operate_boot0;
int boot0_ecc_mode;
int uboot_end;
struct select_chip selected_chip;
struct ce_info ceinfo[MAX_CHIPS];
struct aw_nand_chip_cache simu_chip_buffer;
struct rawnand_data_interface data_interface;
#define BBT_B_INVALID (2)
#define BBT_B_BAD (1)
#define BBT_B_GOOD (0)
uint8_t *bbt;
/*mark whether the corresponding bbt bit is updated*/
uint8_t *bbtd;
uint8_t bitflips;
void (*select_chip)(struct mtd_info *mtd, int chip);
bool (*dev_ready_wait)(struct mtd_info *mtd);
int (*dev_status)(struct mtd_info *mtd);
int (*block_bad)(struct mtd_info *mtd, int block);
int (*simu_block_bad)(struct mtd_info *mtd, int block);
int (*block_markbad)(struct mtd_info *mtd, int block);
int (*simu_block_markbad)(struct mtd_info *mtd, int block);
/*scan device to update bbt*/
int (*scan_bbt)(struct mtd_info *mtd);
int (*erase)(struct mtd_info *mtd, int page);
int (*multi_erase)(struct mtd_info *mtd, int page);
int (*write_page)(struct mtd_info *mtd, struct aw_nand_chip *chip,
uint8_t *mdata, int mlen, uint8_t *sdata, int slen, int page);
int (*multi_write_page)(struct mtd_info *mtd, struct aw_nand_chip *chip,
uint8_t *mdata, int mlen, uint8_t *sdata, int slen, int page);
int (*cache_write_page)(struct mtd_info *mtd, struct aw_nand_chip *chip,
uint8_t *mdata, int mlen, uint8_t *sdata, int slen, int page);
int (*read_page)(struct mtd_info *mtd, struct aw_nand_chip *chip,
uint8_t *mdata, int mlen, uint8_t *sdata, int slen, int page);
int (*multi_read_page)(struct mtd_info *mtd, struct aw_nand_chip *chip,
uint8_t *mdata, int mlen, uint8_t *sdata, int slen, int page);
int (*read_page_spare)(struct mtd_info *mtd, struct aw_nand_chip *chip,
uint8_t *sdata, int slen, int page);
int (*write_boot0_page)(struct mtd_info *mtd, struct aw_nand_chip *chip,
uint8_t *mdata, int mlen, uint8_t *sdata, int slen, int page);
int (*read_boot0_page)(struct mtd_info *mtd, struct aw_nand_chip *chip,
uint8_t *mdata, int mlen, uint8_t *sdata, int slen, int page);
int (*setup_read_retry)(struct mtd_info *mtd, struct aw_nand_chip *chip);
int (*setup_data_interface)(struct mtd_info *mtd, struct aw_nand_chip *chip,
int chipnr, const struct rawnand_data_interface *conf);
struct aw_nand_flash_dev *dev;
void *priv;
struct list_head node;
};
struct aw_nand_sec_sto {
struct aw_nand_chip *chip;
/*initialized before read/write*/
unsigned int startblk;
unsigned int endblk;
unsigned int blk[2];
int init_end;
};
static inline struct aw_nand_host *awnand_chip_to_host(struct aw_nand_chip *chip)
{
return (struct aw_nand_host *)chip->priv;
}
static inline struct aw_nand_chip *awnand_host_to_chip(struct aw_nand_host *host)
{
return (struct aw_nand_chip *)host->priv;
}
static inline struct mtd_info *awnand_chip_to_mtd(struct aw_nand_chip *chip)
{
return (struct mtd_info *)&chip->mtd;
}
static inline struct aw_nand_chip *awnand_mtd_to_chip(struct mtd_info *mtd)
{
return container_of(mtd, struct aw_nand_chip, mtd);
//return (struct aw_nand_chip *)container_of(mtd, struct aw_nand_chip, mtd);
}
static inline struct aw_nand_host *awnand_nfc_to_host(struct nfc_reg *nfc)
{
return container_of(nfc, struct aw_nand_host, nfc_reg);
}
static inline struct aw_nand_chip *get_rawnand(void)
{
return &awnand_chip;
}
static inline struct aw_nand_sec_sto *get_rawnand_sec_sto(void)
{
return &rawnand_sec_sto;
}
/**
* check_offs_len - check mtd->_erase requset legality
* */
static inline int check_offs_len(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct aw_nand_chip *chip = awnand_mtd_to_chip(mtd);
int ret = 0;
/*check align to block and exceed the mtd size*/
if ((ofs & chip->erasesize_mask) ||
(len & chip->erasesize_mask) ||
((ofs + len) > mtd->size)) {
awrawnand_err("unaligned address@%llu len@%llu\n", ofs, len);
ret = -EINVAL;
}
return ret;
}
/**
* check_ofs_mtd_oob_ops - use to check _read/write_oob requeset legality
* @rw: 0: read , 1: write
* */
static inline int check_ofs_mtd_oob_ops(struct mtd_info *mtd, loff_t ofs, struct mtd_oob_ops *ops,
int rw)
{
struct aw_nand_chip *chip = awnand_mtd_to_chip(mtd);
/*check boundary*/
if (ops->datbuf && (ofs + ops->len) > mtd->size) {
awrawnand_err("attemp to %s to@%llu len@%u beyond end of device@%llu\n",
rw ? "write" : "read", ofs, ops->len, mtd->size);
return -EINVAL;
}
/*chec spare boundary*/
if (ops->oobbuf && ((ops->ooboffs + ops->ooblen) > mtd->oobsize)) {
awrawnand_err("attemp to %s ooblen@%u beyond end of avalid_sparesize@%d\n",
rw ? "write" : "read", ops->ooblen, chip->avalid_sparesize);
return -EINVAL;
}
/*check align*/
if ((ofs & chip->pagesize_mask) || (ops->len & chip->pagesize_mask)) {
awrawnand_print("attemp to %s to@%llu len@%u non pagesize@%d aligned data\n",
rw ? "write" : "read", ofs, ops->len, chip->pagesize);
return 0;
}
return 0;
}
/**
* check_from_len - check mtd->_read request legality
* */
static inline int check_from_len(struct mtd_info *mtd, loff_t from, size_t len)
{
struct aw_nand_chip *chip = awnand_mtd_to_chip(mtd);
/*check boundary*/
if ((from + len) > mtd->size) {
awrawnand_err("attemp to read from@0x%llx len@0x%x beyond end of device@0x%llx\n",
from, len, mtd->size);
return -EINVAL;
}
if (from & chip->pagesize_mask) {
awrawnand_err("attemp to read from@%llu not align to pagesize@%u\n",
from, chip->pagesize);
return -EINVAL;
}
return 0;
}
/**
* check_to_len - check mtd->_write request legality
* */
static inline int check_to_len(struct mtd_info *mtd, loff_t to, size_t len)
{
struct aw_nand_chip *chip = awnand_mtd_to_chip(mtd);
/*check boundary*/
if ((to + len) > mtd->size) {
awrawnand_err("attemp to write to@0x%llx len@0x%x beyond end of device@0x%llx\n",
to, len, mtd->size);
return -EINVAL;
}
if ((to & chip->pagesize_mask) || (len & chip->pagesize_mask)) {
awrawnand_err("attemp to write to@%llu not align to phy-pagesize@%u\n",
to, chip->pagesize);
return -EINVAL;
}
return 0;
}
extern bool support_rawnand(void);
extern int aw_rawnand_secure_storage_read(struct aw_nand_sec_sto *sec_sto,
int item, char *buf, unsigned int len);
extern int aw_rawnand_secure_storage_write(struct aw_nand_sec_sto *sec_sto,
int item, char *buf, unsigned int len);
extern void rawnand_uboot_blknum(unsigned int *start, unsigned int *end);
extern int rawnand_mtd_download_uboot(unsigned int len, void *buf);
extern int rawnand_mtd_download_boot0(unsigned int len, void *buf);
extern int rawnand_mtd_secure_storage_write(int item, char *buf, unsigned int len);
extern int rawnand_mtd_secure_storage_read(int item, char *buf, unsigned int len);
extern int aw_rawnand_chip_block_bad(struct mtd_info *mtd, int block);
extern int aw_rawnand_chip_simu_block_bad(struct mtd_info *mtd, int block);
extern int aw_rawnand_chip_block_markbad(struct mtd_info *mtd, int block);
extern int aw_rawnand_chip_simu_block_markbad(struct mtd_info *mtd, int block);
extern int aw_rawnand_chip_scan_bbt(struct mtd_info *mtd);
extern int aw_host_init(struct device *dev);
extern void aw_host_exit(struct aw_nand_host *host);
extern int aw_host_init_tail(struct aw_nand_host *host);
extern int rawnand_mtd_init(void);
extern void rawnand_mtd_exit(void);
extern int rawnand_mtd_flush(void);
extern int rawnand_mtd_attach_mtd(void);
extern unsigned rawnand_mtd_size(void);
extern int rawnand_mtd_erase(int flag);
extern int rawnand_mtd_force_erase(void);
extern int rawnand_mtd_read(unsigned int start, unsigned int sects, void *buf);
extern int rawnand_mtd_write(unsigned int start, unsigned int sects, void *buf);
extern int rawnand_mtd_write_end(void);
extern int rawnand_mtd_get_flash_info(void *data, unsigned int len);
extern int rawnand_mtd_update_ubi_env(void);
extern int rawnand_mtd_set_last_vol_sects(unsigned int sects);
extern int rawslcnand_write_boot0_page(struct mtd_info *mtd, struct aw_nand_chip *chip,
uint8_t *mdata, int mlen, uint8_t *sdata, int slen, int page);
extern int rawslcnand_read_boot0_page(struct mtd_info *mtd, struct aw_nand_chip *chip,
uint8_t *mdata, int mlen, uint8_t *sdata, int slen, int page);
extern void rawnand_uboot_blknum(unsigned int *start, unsigned int *end);
extern int aw_rawnand_mtd_download_boot0(unsigned int len, void *buf);
extern int aw_rawnand_mtd_download_uboot(unsigned int len, void *buf);
#endif /*AW_RAWNAND_H*/