| /* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ |
| /* |
| * drivers/nand/logic/aml_nftl.h |
| * |
| * Copyright (C) 2020 Amlogic, Inc. All rights reserved. |
| * |
| */ |
| |
| #ifndef __AML_NFTL_H |
| #define __AML_NFTL_H |
| |
| #include "../include/amlnf_dev.h" |
| #include "../include/aml_nftl_cfg.h" /*for config settings.*/ |
| #include "aml_nftl_type.h" |
| |
| #define DRV_FTL_VERSION "1.01.002" |
| |
| typedef enum { |
| AML_NFTL_SUCCESS =0, |
| AML_NFTL_FAILURE =1, |
| AML_NFTL_INVALID_PARTITION =2, |
| AML_NFTL_INVALID_ADDRESS =3, |
| AML_NFTL_DELETED_SECTOR =4, |
| AML_NFTL_FLUSH_ERROR =5, |
| AML_NFTL_UNFORMATTED =6, |
| AML_NFTL_UNWRITTEN_SECTOR =7, |
| AML_NFTL_PAGENOTFOUND =0x08, |
| AML_NFTL_NO_FREE_BLOCKS =0x10, |
| AML_NFTL_STRUCTURE_FULL =0x11, |
| AML_NFTL_NO_INVALID_BLOCKS =0x12, |
| AML_NFTL_SECTORDELETED =0x50, |
| AML_NFTL_ABT_FAILURE =0x51, |
| AML_NFTL_MOUNTED_PARTITION =0, |
| AML_NFTL_UNMOUNTED_PARTITION =1, |
| AML_NFTL_SPAREAREA_ERROR =0x13, |
| AML_NFTL_STATIC_WL_FINISH =0x14, |
| AML_NFTL_BLKNOTFOUND =0x15, |
| AML_NFTL_WRITE_ERROR =5 |
| }t_AML_NFTL_error; |
| |
| /* debug line for nftl... */ |
| #define NPRINT printf |
| //#define NFTL_LINE do {aml_nand_msg("%s() %d", __FUNCTION__, __LINE__);} while(0); |
| #define NFTL_LINE do {aml_nand_msg("%s() %d", __FUNCTION__, __LINE__);} while(0); |
| //#define NCACHE_LINE do {aml_nand_msg("%s() %d", __FUNCTION__, __LINE__);} while(0); |
| #define NCACHE_LINE |
| //#define NFTL_CREAT_LINE do {aml_nand_msg("%s() %d", __FUNCTION__, __LINE__);} while(0); |
| #define NFTL_CREAT_LINE |
| //#define NFTL_CREAT_LINE2 do {aml_nand_msg("%s() %d", __FUNCTION__, __LINE__);} while(0); |
| #define NFTL_CREAT_LINE2 do {;} while(0); |
| //#define NFTL_CREAT_LINE3 do {aml_nand_msg("%s() %d", __FUNCTION__, __LINE__);} while(0); |
| #define NFTL_CREAT_LINE3 do {;} while(0); |
| |
| //#define NFTL_LINE |
| |
| #define MAX_PAGE_PER_BLOCK 1024 |
| #define MAX_CACHE_NUM 32 |
| #define MAX_PRIO_GC_NUM 10 |
| |
| #define BLOCK_FOR_BAD_TABLE 0xee |
| |
| |
| |
| #define SPARE_OFFSET_LOGIC_PAGE 0 |
| |
| |
| |
| //#define SPARE_OFFSET_NO 10 |
| //#define SPARE_OFFSET_TYPE 11 |
| //#define SPARE_OFFSET_MAGIC 12 |
| |
| |
| #define BLOCK_NO_USED 1 |
| #define BLOCK_HAVE_USED 0 |
| #define BLOCK_IS_BAD 0xff |
| |
| #define RET_YES 1 |
| #define RET_NO 0 |
| |
| #define FTL_NORMAL 0 |
| #define FTL_UNUSUAL 1 |
| |
| //nand block |
| typedef struct{ |
| uint16 blkNO_in_chip; |
| }_nand_block; |
| |
| |
| typedef struct __phy_block _phy_block_info; |
| |
| typedef struct{ |
| uint16 pages_per_blk; |
| uint16 page_offset_in_nextblk; |
| uint16 *phy_conversion_table; |
| uchar (*nand_erase_superblk)(_physic_op_par *p); |
| uchar (*nand_read_page)(_physic_op_par *p); |
| uchar (*nand_write_page)(_physic_op_par *p); |
| uchar (*nand_copy_page)(_physic_op_par* a, _physic_op_par* b,uchar *buf); |
| }_nand_safe_property; |
| |
| struct nand_chip_t{ |
| uchar nand_id[8]; |
| uchar sector_per_page; |
| uchar frequence_par; |
| uchar bytes_user_date; |
| uchar bytes_ecc_date; |
| uchar ecc_bits; //8,24,32 |
| uchar ecc_for_bytes; //512 or 1024 |
| uchar two_plane_support; |
| uint16 max_erase_times; |
| uint16 two_plane_offset; |
| uint16 pages_per_blk; |
| uint16 page_offset_in_nextblk; |
| uint16 blk_per_chip; |
| uint32 bytes_per_page; |
| uint16 bitmap_per_page; |
| _nand_safe_property nand_safe; |
| _phy_block_info* nand_block_info; |
| }; |
| |
| typedef struct __phy_block{ |
| _nand_block phy_block; |
| uint16 info; |
| uint16 invalid_page_count; //[0,pages_per_blk-1] |
| uint16 erase_count; //[0,10000] |
| sint32 block_used_count; |
| _phy_block_info* invalid_page_next; |
| _phy_block_info* invalid_page_prev; |
| _phy_block_info* free_next; |
| _phy_block_info* block_used_next; |
| _phy_block_info* block_used_prev; |
| |
| }_phy_block_t; |
| |
| #define GC_ON 0 |
| #define GC_STOP 1 |
| //Schmidt oscillator |
| typedef struct{ |
| uint16 start_gc_free_blocks; |
| uint16 stop_gc_free_blocks; |
| uint16 process; |
| uint16 flag_gc_block; |
| uint16 gc_page; |
| }_gc_strategy; |
| |
| |
| #define PRIO_NONE 0 |
| #define GC_READ_RECLAIM 1 |
| #define GC_WEAR_LEVELING 2 |
| |
| typedef struct __prio_gc_node _prio_gc_node; |
| typedef struct __prio_gc_node |
| { |
| uint16 gc_no; |
| uint16 prio_type; |
| _phy_block_info* phy_block_info; |
| _prio_gc_node* prio_gc_next; |
| _prio_gc_node* prio_gc_prev; |
| }_prio_gc_node_t; |
| |
| typedef struct |
| { |
| uint16 gc_num; |
| uint16 prio_type_now; |
| _prio_gc_node prio_gc_node[MAX_PRIO_GC_NUM]; |
| _prio_gc_node prio_gc_head; |
| }_prio_gc; |
| |
| |
| |
| #define CACHE_WRITE 1 |
| #define CACHE_READ 0 |
| #define CACHE_EMPTY 0xff |
| |
| typedef struct __cache_node _cache_node; |
| typedef struct __cache_node |
| { |
| uint16 cache_no; |
| uint16 cache_info; //[CACHE_EMPTY,CACHE_READ,CACHE_WRITE] |
| uint32 page_no; |
| uchar* buf; |
| _cache_node* cache_read_next; |
| _cache_node* cache_read_prev; |
| _cache_node* cache_write_next; |
| _cache_node* cache_write_prev; |
| }_cache_node_t; |
| |
| typedef struct |
| { |
| uint16 cache_totals; |
| uint16 cache_read_nums; |
| uint16 cache_write_nums; |
| uchar* cache_buf; |
| _cache_node cache_node[MAX_CACHE_NUM]; |
| _cache_node cache_read_head; |
| _cache_node cache_write_head; |
| }_cache; |
| |
| |
| #define WL_ON 1 |
| #define WL_STOP 0 |
| |
| typedef struct |
| { |
| uint16 erase_threshold; |
| uint16 erase_span; |
| uint16 s_wl_status; |
| }_s_wl; |
| |
| typedef struct |
| { |
| unsigned char unusual; |
| }_ftl_status; |
| #define MAX_MALLOC_BYTES 0x100000 |
| #define MAX_LOGIC_MAP_NUM 12 |
| #define MALLOC_FLAG 1 |
| |
| struct aml_nftl_part_t; |
| |
| struct aml_nftl_part_t{ |
| // struct mtd_info * mtd; |
| void* priv; |
| // struct mutex aml_nftl_lock; |
| struct nand_chip_t* nand_chip; |
| char version[16]; |
| uchar part_no; |
| uchar part_attr; |
| uint16 blocks; |
| uint16 bad_block; |
| uint16 free_block_num; |
| uint32 logic_cap_in_sects; |
| uint32 backup_cap_in_sects; |
| _nand_block part_start_blk_NO; |
| _phy_block_info* part_start_phy_block; |
| _phy_block_info* part_end_phy_block; |
| #if MALLOC_FLAG |
| _nand_page* part_logic_page_map[MAX_LOGIC_MAP_NUM]; |
| #else |
| _nand_page* part_logic_page_map; |
| #endif |
| |
| _phy_block_info free_head; |
| _phy_block_info invalid_page_head; |
| _phy_block_info block_used_head; |
| _phy_block_info * part_current_used_block; |
| uint16 current_block_used_page; |
| uint32 current_block_used_count; |
| uchar* temp_page_buf; |
| |
| uint32 total_reads; |
| uint32 total_write; |
| |
| uint32 test; |
| _ftl_status ftl_status; |
| |
| _gc_strategy gc_strategy; |
| _prio_gc prio_gc; |
| _s_wl s_wl; |
| _cache cache; |
| struct _nftl_cfg* cfg; |
| |
| // struct class debug; |
| int (*nand_erase_superblk)(struct aml_nftl_part_t* part,_physic_op_par *p); |
| int (*nand_read_page)(struct aml_nftl_part_t* part,_physic_op_par *p); |
| int (*nand_write_page)(struct aml_nftl_part_t* part,_physic_op_par *p); |
| int (*nand_copy_page)(struct aml_nftl_part_t *part,_physic_op_par* a, _physic_op_par* b, |
| uchar *buf,uint32 block_used_count,uint16 erase_times,uint32 logic_no); |
| int (*nand_is_blk_good)(struct aml_nftl_part_t* part,_physic_op_par *p); |
| int (*nand_mark_bad_blk)(struct aml_nftl_part_t* part,_physic_op_par *p); |
| uint32 (*nand_write_logic_page)(struct aml_nftl_part_t* part,uint32 page_no,uchar *buf); |
| uint32 (*nand_read_logic_page)(struct aml_nftl_part_t* part,uint32 page_no,uchar *buf); |
| |
| }; |
| |
| //extern void *aml_nftl_malloc(uint32 size); |
| //extern void aml_nftl_free(const void *ptr); |
| //extern int aml_nand_msg(const char * fmt,...); |
| extern uint32 nftl_nand_read(void *priv,uint32 start_sector,uint32 len,unsigned char *buf); |
| extern uint32 nftl_nand_write(void *priv,uint32 start_sector,uint32 len,unsigned char *buf); |
| |
| extern uint32 do_static_wear_leveling(struct aml_nftl_part_t* part); |
| extern uint32 garbage_collect(struct aml_nftl_part_t* part); |
| extern uint32 do_prio_gc(struct aml_nftl_part_t* part); |
| |
| extern void* aml_nftl_get_part_priv(void * _part); |
| extern void aml_nftl_add_part_total_read(void * _part); |
| extern void aml_nftl_add_part_total_write(void * _part); |
| extern uint32 aml_nftl_get_part_cap(void * _part); |
| extern int aml_nftl_start(void* priv,void* cfg,void ** ppart,uint64_t size,unsigned erasesize,\ |
| unsigned writesize,unsigned oobavail,char* name,int no,char type); |
| |
| int adjust_invalid_list(struct aml_nftl_part_t *part); |
| int put_phy_block_to_invalid_page_list(struct aml_nftl_part_t *part, |
| _phy_block_info *phy_block_ptr); |
| _phy_block_info *out_phy_block_from_invalid_page_list_by_block(struct aml_nftl_part_t *part, |
| _phy_block_info *phy_block_ptr); |
| _phy_block_info *out_phy_block_from_free_list(struct aml_nftl_part_t *part); |
| int phy_block_from_invalid_page_incr(struct aml_nftl_part_t *part, _phy_block_info *block); |
| _phy_block_info *out_phy_block_from_invalid_page_list(struct aml_nftl_part_t *part); |
| int put_phy_block_to_free_list(struct aml_nftl_part_t *part, _phy_block_info *phy_block_ptr); |
| void print_block_invalid_list(struct aml_nftl_part_t *part); |
| _phy_block_info *del_block_invalid_list(struct aml_nftl_part_t *part); |
| _phy_block_info *del_block_invalid_list_by_block(struct aml_nftl_part_t *part, |
| _phy_block_info *phy_block_ptr); |
| void print_block_count_list(struct aml_nftl_part_t *part); |
| int add_block_count_list(struct aml_nftl_part_t *part, _phy_block_info *phy_block_ptr); |
| void print_free_list(struct aml_nftl_part_t *part); |
| _phy_block_info *del_block_count_list(struct aml_nftl_part_t *part); |
| int set_new_current_block(struct aml_nftl_part_t *part); |
| uint32 nand_write_logic_page(struct aml_nftl_part_t *part, uint32 page_no, uchar *buf); |
| uint32 nand_read_logic_page(struct aml_nftl_part_t *part, uint32 page_no, uchar *buf); |
| |
| int nand_copy_page(struct aml_nftl_part_t *part, _physic_op_par *a, _physic_op_par *b, |
| uchar *buf, uint32 block_used_count, uint16 erase_times, uint32 logic_no); |
| void set_oob_special_page(struct aml_nftl_part_t *part, uchar *buf, |
| uint32 special_data, uint32 block_used_count, uint16 erase_times, uchar type); |
| uint32 get_logic_page_from_oob(uchar *buf); |
| uint16 get_erase_count_from_oob(uchar *buf); |
| void set_oob_logic_page(struct aml_nftl_part_t *part, uchar *buf, |
| uint32 logic_page, uint32 block_used_count, uint16 erase_times); |
| uint32 get_special_data_from_oob(uchar *buf); |
| _nand_page *get_logic_page_map(struct aml_nftl_part_t *part, uint32 logic_page); |
| int init_logic_page_map(struct aml_nftl_part_t *part, uint32 total_pages); |
| int check_logic_page_map(struct aml_nftl_part_t *part); |
| uint32 get_block_used_count_from_oob(uchar *buf); |
| void set_spare_data(uchar *buf, uint32 data, uchar offset, uchar num); |
| uint32 get_spare_data(uchar *buf, uchar offset, uchar num); |
| |
| _phy_block_info *get_phy_block_addr(struct aml_nftl_part_t *part, uint16 block); |
| uint32 is_phy_block_valid(_phy_block_info *p_phy_block_info, struct aml_nftl_part_t *part); |
| uint32 is_last_phy_block(_phy_block_info *p_phy_block_info, struct aml_nftl_part_t *part); |
| uint32 recover_current_block_mapping(struct aml_nftl_part_t *part, _phy_block_info *phy_block_ptr); |
| void recover_block_log2pyh_mapping(struct aml_nftl_part_t *part, _phy_block_info *phy_block_ptr); |
| uint32 do_write_error_in_create_list(struct aml_nftl_part_t *part, _phy_block_info *block1, |
| _phy_block_info *block2, uint16 page_num); |
| uint32 get_used_page_num(struct aml_nftl_part_t *part, _phy_block_info *phy_block_ptr); |
| uint32 get_used_block_count(struct aml_nftl_part_t *part, _phy_block_info *phy_block_ptr); |
| void print_nftl_part(struct aml_nftl_part_t *part); |
| int part_param_exit(struct aml_nftl_part_t *part); |
| uint32 get_valid_blocks(struct aml_nftl_part_t *part, uint32 start_block, uint32 blocks); |
| uint32 do_write_error_in_create_list_for_discard(struct aml_nftl_part_t *part, |
| _phy_block_info *block1, _phy_block_info *block2, uint16 page_num); |
| uint32 garbage_collect_first(struct aml_nftl_part_t *part, _phy_block_info *block, uint16 page_num); |
| void add_prio_gc(struct aml_nftl_part_t *part, _phy_block_info *block, uint16 type); |
| uint32 prio_gc_all(struct aml_nftl_part_t *part); |
| uint32 do_prio_gc(struct aml_nftl_part_t *part); |
| uint32 gc_all(struct aml_nftl_part_t *part); |
| uint32 gc_one(struct aml_nftl_part_t *part); |
| uint32 garbage_collect(struct aml_nftl_part_t *part); |
| uint32 do_static_wear_leveling(struct aml_nftl_part_t *part); |
| |
| int nand_write_logic_page_no_gc(struct aml_nftl_part_t *part, uint32 page_no, uchar *buf); |
| int write_phy_page_map(struct aml_nftl_part_t *part); |
| int set_new_current_block(struct aml_nftl_part_t *part); |
| |
| int nand_read_page(struct aml_nftl_part_t *part, _physic_op_par *p); |
| int nand_erase_superblk(struct aml_nftl_part_t *part, _physic_op_par *p); |
| int nand_write_page(struct aml_nftl_part_t *part, _physic_op_par *p); |
| int nand_mark_bad_blk(struct aml_nftl_part_t *part, _physic_op_par *p); |
| int nand_is_blk_good(struct aml_nftl_part_t *part, _physic_op_par *p); |
| |
| void aml_nftl_ops_init(struct aml_nftl_part_t *part); |
| uint32 create_part_list(struct aml_nftl_part_t *part); |
| uint32 create_part_list_first(struct aml_nftl_part_t *part, uint32 size); |
| uint32 is_no_use_device(struct aml_nftl_part_t *part, uint32 size); |
| int part_param_init(struct aml_nftl_part_t *part, uint16 start_block, |
| uint32 logic_sects, uint32 backup_cap_in_sects); |
| int nftl_cache_init(struct aml_nftl_part_t *part); |
| int nftl_cache_exit(struct aml_nftl_part_t *part); |
| #endif |
| |
| |