/** * SPDX-License-Identifier: GPL-2.0+ * * (C) Copyright 2020 - 2021 * Allwinner Technology Co., Ltd. * cuizhikui * */ #ifndef __AW_RAWNAND_H__ #define __AW_RAWNAND_H__ #include #include /* 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*/