sdk-hwV1.3/lichee/brandy-2.0/u-boot-2018/include/linux/mtd/aw-spinand.h

312 lines
9.8 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __SUNXI_SPINAND_H
#define __SUNXI_SPINAND_H
#include <linux/kernel.h>
#include <linux/compat.h>
#include <linux/mtd/mtd.h>
#include <hexdump.h>
/* to print more log for uboot */
#undef CONFIG_LOGLEVEL
#define CONFIG_LOGLEVEL 7
/*
* spinand do not support multiplane. In order to adapt to aw nand
* we simulate 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)
#define AW_OOB_SIZE_PER_PHY_PAGE (16)
#define AW_SPINAND_RESERVED_PHY_BLK_FOR_SECURE_STORAGE 8
#define AW_SPINAND_RESERVED_FOR_PSTORE_KB 512
/**
* In order to fix for nftl nand, make they has the same address
* for saving crc16
*/
#define AW_CRC16_OOB_OFFSET (12)
/* ecc status */
#define ECC_GOOD (0 << 4)
#define ECC_LIMIT (1 << 4)
#define ECC_ERR (2 << 4)
#define SPI_NBITS_SINGLE 1
#define SPI_NBITS_DUAL 2
#define SPI_NBITS_QUAD 4
#define SPI_SELECT_ODDNUM_BLACK 0x10
#define SPINAND_MSG_EN (1U)
#define SPINAND_MSG(d, fmt, args...) \
do {if ((d)->msglevel & SPINAND_MSG_EN) \
pr_err("[SPINAND]: "fmt, ##args); } while (0)
struct aw_spinand_ecc;
struct aw_spinand_info;
struct aw_spinand_phy_info;
struct aw_spinand_chip_ops;
struct aw_spinand_chip {
struct aw_spinand_chip_ops *ops;
struct aw_spinand_ecc *ecc;
struct aw_spinand_cache *cache;
struct aw_spinand_info *info;
struct aw_spinand_bbt *bbt;
struct spi_slave *slave;
unsigned int rx_bit;
unsigned int tx_bit;
unsigned int freq;
void *priv;
};
struct aw_spinand_chip_request {
unsigned int block;
unsigned int page;
unsigned int pageoff;
unsigned int ooblen;
unsigned int datalen;
void *databuf;
void *oobbuf;
unsigned int oobleft;
unsigned int dataleft;
#define AW_SPINAND_MTD_OPS_RAW (2)
int mode;
};
struct aw_spinand_chip_ops {
int (*get_block_lock)(struct aw_spinand_chip *chip,
unsigned char *reg_val);
int (*set_block_lock)(struct aw_spinand_chip *chip,
unsigned char reg_val);
int (*get_otp)(struct aw_spinand_chip *chip, unsigned char *reg_val);
int (*set_otp)(struct aw_spinand_chip *chip, unsigned char reg_val);
int (*get_bft)(struct aw_spinand_chip *chip, unsigned char *reg_val);
int (*get_driver_level)(struct aw_spinand_chip *chip,
unsigned char *reg_val);
int (*set_driver_level)(struct aw_spinand_chip *chip,
unsigned char reg_val);
int (*reset)(struct aw_spinand_chip *chip);
int (*read_status)(struct aw_spinand_chip *chip, unsigned char *status);
int (*read_id)(struct aw_spinand_chip *chip, void *id, int len,
int dummy);
int (*read_reg)(struct aw_spinand_chip *chip, unsigned char cmd,
unsigned char reg, unsigned char *val);
int (*write_reg)(struct aw_spinand_chip *chip, unsigned char cmd,
unsigned char reg, unsigned char val);
int (*is_bad)(struct aw_spinand_chip *chip,
struct aw_spinand_chip_request *req);
int (*mark_bad)(struct aw_spinand_chip *chip,
struct aw_spinand_chip_request *req);
int (*erase_block)(struct aw_spinand_chip *chip,
struct aw_spinand_chip_request *req);
int (*write_page)(struct aw_spinand_chip *chip,
struct aw_spinand_chip_request *req);
int (*read_page)(struct aw_spinand_chip *chip,
struct aw_spinand_chip_request *req);
int (*phy_is_bad)(struct aw_spinand_chip *chip,
struct aw_spinand_chip_request *req);
int (*phy_mark_bad)(struct aw_spinand_chip *chip,
struct aw_spinand_chip_request *req);
int (*phy_erase_block)(struct aw_spinand_chip *chip,
struct aw_spinand_chip_request *req);
int (*phy_write_page)(struct aw_spinand_chip *chip,
struct aw_spinand_chip_request *req);
int (*phy_read_page)(struct aw_spinand_chip *chip,
struct aw_spinand_chip_request *req);
int (*phy_copy_block)(struct aw_spinand_chip *chip,
unsigned int from_blk, unsigned int to_blk);
};
/*different manufacture spinand's ecc status location maybe not the same*/
enum ecc_status_shift {
ECC_STATUS_SHIFT_0 = 0,
ECC_STATUS_SHIFT_1,
ECC_STATUS_SHIFT_2,
ECC_STATUS_SHIFT_3,
ECC_STATUS_SHIFT_4,
ECC_STATUS_SHIFT_5,
ECC_STATUS_SHIFT_6,
ECC_STATUS_SHIFT_7,
};
enum ecc_limit_err {
ECC_TYPE_ERR = 0,
BIT3_LIMIT2_TO_6_ERR7,
BIT2_LIMIT1_ERR2,
BIT2_LIMIT1_ERR2_TO_ERR3,
BIT2_LIMIT2_ERR3,
BIT2_LIMIT1_ERR2_LIMIT3,
BIT2_ERR2_LIMIT3,
BIT4_LIMIT3_TO_4_ERR15,
BIT3_LIMIT3_TO_4_ERR7,
BIT3_LIMIT5_ERR2,
BIT4_LIMIT5_TO_7_ERR8_LIMIT_12,
BIT4_LIMIT5_TO_8_ERR9_TO_15,
};
enum ecc_oob_protected {
ECC_PROTECTED_TYPE = 0,
/* all spare data are under ecc protection */
SIZE16_OFF0_LEN16,
SIZE16_OFF4_LEN12,
SIZE16_OFF4_LEN4_OFF8,
/*compatible with GD5F1GQ4UBYIG@R6*/
SIZE16_OFF4_LEN8_OFF4,
SIZE16_OFF32_LEN16,
/*compatible with XTX*/
SIZE16_OFF8_LEN16,
};
struct aw_spinand_phy_info {
const char *Model;
#define MAX_ID_LEN 8
unsigned char NandID[MAX_ID_LEN];
unsigned int DieCntPerChip;
unsigned int BlkCntPerDie;
unsigned int PageCntPerBlk;
unsigned int SectCntPerPage;
unsigned int OobSizePerPage;
#define BAD_BLK_FLAG_MARK 0x03
#define BAD_BLK_FLAG_FRIST_1_PAGE 0x00
#define BAD_BLK_FLAG_FIRST_2_PAGE 0x01
#define BAD_BLK_FLAG_LAST_1_PAGE 0x02
#define BAD_BLK_FLAG_LAST_2_PAGE 0x03
int BadBlockFlag;
#define SPINAND_DUAL_READ BIT(0)
#define SPINAND_QUAD_READ BIT(1)
#define SPINAND_QUAD_PROGRAM BIT(2)
#define SPINAND_QUAD_NO_NEED_ENABLE BIT(3)
#define SPINAND_TWO_PLANE_SELECT BIT(7)
#define SPINAND_ONEDUMMY_AFTER_RANDOMREAD BIT(8)
int OperationOpt;
int MaxEraseTimes;
#define HAS_EXT_ECC_SE01 BIT(0)
#define HAS_EXT_ECC_STATUS BIT(1)
int EccFlag;
enum ecc_status_shift ecc_status_shift;
enum ecc_limit_err EccType;
enum ecc_oob_protected EccProtectedType;
};
struct aw_spinand_info {
const char *(*model)(struct aw_spinand_chip *chip);
const char *(*manufacture)(struct aw_spinand_chip *chip);
void (*nandid)(struct aw_spinand_chip *chip, unsigned char *id, int cnt);
unsigned int (*die_cnt)(struct aw_spinand_chip *chip);
unsigned int (*oob_size)(struct aw_spinand_chip *chip);
unsigned int (*sector_size)(struct aw_spinand_chip *chip);
unsigned int (*page_size)(struct aw_spinand_chip *chip);
unsigned int (*block_size)(struct aw_spinand_chip *chip);
unsigned int (*phy_oob_size)(struct aw_spinand_chip *chip);
unsigned int (*phy_page_size)(struct aw_spinand_chip *chip);
unsigned int (*phy_block_size)(struct aw_spinand_chip *chip);
unsigned int (*total_size)(struct aw_spinand_chip *chip);
int (*operation_opt)(struct aw_spinand_chip *chip);
int (*max_erase_times)(struct aw_spinand_chip *chip);
/* private data */
struct aw_spinand_phy_info *phy_info;
};
int addr_to_req(struct aw_spinand_chip *chip, struct aw_spinand_chip_request *req,
unsigned int addr);
int aw_spinand_chip_init(struct spi_slave *salve, struct aw_spinand_chip *chip);
void aw_spinand_chip_exit(struct aw_spinand_chip *chip);
#define aw_spinand_hexdump(level, prefix, buf, len) \
print_hex_dump(prefix, DUMP_PREFIX_OFFSET, 16, 1, \
buf, len, true)
#define aw_spinand_reqdump(func, note, req) \
do { \
func("%s(%d): %s\n", __func__, __LINE__, note); \
func("\tblock: %u\n", (req)->block); \
func("\tpage: %u\n", (req)->page); \
func("\tpageoff: %u\n", (req)->pageoff); \
if ((req)->databuf) \
func("\tdatabuf: 0x%p\n", (req)->databuf); \
else \
func("\tdatabuf: NULL\n"); \
func("\tdatalen: %u\n", (req)->datalen); \
func("\tdataleft: %u\n", (req)->dataleft); \
if ((req)->oobbuf) \
func("\toobbuf: 0x%p\n", (req)->oobbuf); \
else \
func("\toobbuf: NULL\n"); \
func("\tooblen: %u\n", (req)->ooblen); \
func("\toobleft: %u\n", (req)->oobleft); \
func("\n"); \
} while (0)
struct aw_spinand_sec_sto {
/* the follow three must be initialized by the caller before read/write */
unsigned int startblk;
unsigned int endblk;
struct aw_spinand_chip *chip;
unsigned int blk[2];
int init_end;
};
int aw_spinand_secure_storage_read(struct aw_spinand_sec_sto *sec_sto,
int item, char *buf, unsigned int len);
int aw_spinand_secure_storage_write(struct aw_spinand_sec_sto *sec_sto,
int item, char *buf, unsigned int len);
struct aw_spinand {
struct aw_spinand_chip chip;
struct mtd_info mtd;
int sector_shift;
int page_shift;
int block_shift;
int phy_page_shift;
int phy_block_shift;
struct aw_spinand_sec_sto sec_sto;
int msglevel;
unsigned int right_sample_delay;
unsigned int right_sample_mode;
};
extern int aw_spinand_probe(struct udevice *dev);
extern void aw_spinand_exit(struct aw_spinand *spinand);
extern int spinand_mtd_init(void);
extern int spinand_mtd_attach_mtd(void);
extern int spinand_mtd_exit(void);
extern unsigned spinand_mtd_size(void);
extern bool support_spinand(void);
extern struct aw_spinand *get_spinand(void);
extern int spinand_mtd_download_boot0(unsigned int len, void *buf);
extern int spinand_mtd_download_uboot(unsigned int len, void *buf);
extern int spinand_mtd_upload_uboot(void *buf, unsigned int len);
extern int spinand_mtd_flush(void);
extern int spinand_mtd_write_end(void);
extern int spinand_mtd_get_flash_info(void *info, unsigned int len);
extern unsigned int spinand_mtd_blksize(void);
extern unsigned int spinand_mtd_pagesize(void);
extern int aw_spinand_mtd_read(unsigned int start, unsigned int sects, void *buf);
extern int aw_spinand_mtd_write(unsigned int start, unsigned int sects, void *buf);
extern int spinand_mtd_erase(int force);
extern int spinand_mtd_force_erase(void);
extern int spinand_mtd_update_ubi_env(void);
extern int spinand_mtd_set_last_vol_sects(unsigned int sects);
extern int spinand_mtd_secure_storage_read(int item, char *buf,
unsigned int len);
extern int spinand_mtd_secure_storage_write(int item, char *buf,
unsigned int len);
extern uint64_t spinand_sys_part_offset(void);
extern void disable_spinand(void);
#endif