| /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ |
| /* |
| * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. |
| * |
| * Author: Weijie Gao <weijie.gao@mediatek.com> |
| */ |
| |
| #ifndef _MTK_SNAND_DEF_H_ |
| #define _MTK_SNAND_DEF_H_ |
| |
| #include "mtk-snand-os.h" |
| |
| #ifdef PRIVATE_MTK_SNAND_HEADER |
| #include "mtk-snand.h" |
| #else |
| #include <mtk-snand.h> |
| #endif |
| |
| struct mtk_snand_plat_dev; |
| |
| enum snand_flash_io { |
| SNAND_IO_1_1_1, |
| SNAND_IO_1_1_2, |
| SNAND_IO_1_2_2, |
| SNAND_IO_1_1_4, |
| SNAND_IO_1_4_4, |
| |
| __SNAND_IO_MAX |
| }; |
| |
| #define SPI_IO_1_1_1 BIT(SNAND_IO_1_1_1) |
| #define SPI_IO_1_1_2 BIT(SNAND_IO_1_1_2) |
| #define SPI_IO_1_2_2 BIT(SNAND_IO_1_2_2) |
| #define SPI_IO_1_1_4 BIT(SNAND_IO_1_1_4) |
| #define SPI_IO_1_4_4 BIT(SNAND_IO_1_4_4) |
| |
| struct snand_opcode { |
| uint8_t opcode; |
| uint8_t dummy; |
| }; |
| |
| struct snand_io_cap { |
| uint8_t caps; |
| struct snand_opcode opcodes[__SNAND_IO_MAX]; |
| }; |
| |
| #define SNAND_OP(_io, _opcode, _dummy) [_io] = { .opcode = (_opcode), \ |
| .dummy = (_dummy) } |
| |
| #define SNAND_IO_CAP(_name, _caps, ...) \ |
| struct snand_io_cap _name = { .caps = (_caps), \ |
| .opcodes = { __VA_ARGS__ } } |
| |
| #define SNAND_MAX_ID_LEN 4 |
| |
| enum snand_id_type { |
| SNAND_ID_DYMMY, |
| SNAND_ID_ADDR = SNAND_ID_DYMMY, |
| SNAND_ID_DIRECT, |
| |
| __SNAND_ID_TYPE_MAX |
| }; |
| |
| struct snand_id { |
| uint8_t type; /* enum snand_id_type */ |
| uint8_t len; |
| uint8_t id[SNAND_MAX_ID_LEN]; |
| }; |
| |
| #define SNAND_ID(_type, ...) \ |
| { .type = (_type), .id = { __VA_ARGS__ }, \ |
| .len = sizeof((uint8_t[]) { __VA_ARGS__ }) } |
| |
| struct snand_mem_org { |
| uint16_t pagesize; |
| uint16_t sparesize; |
| uint16_t pages_per_block; |
| uint16_t blocks_per_die; |
| uint16_t planes_per_die; |
| uint16_t ndies; |
| }; |
| |
| #define SNAND_MEMORG(_ps, _ss, _ppb, _bpd, _ppd, _nd) \ |
| { .pagesize = (_ps), .sparesize = (_ss), .pages_per_block = (_ppb), \ |
| .blocks_per_die = (_bpd), .planes_per_die = (_ppd), .ndies = (_nd) } |
| |
| typedef int (*snand_select_die_t)(struct mtk_snand *snf, uint32_t dieidx); |
| |
| struct snand_flash_info { |
| const char *model; |
| struct snand_id id; |
| const struct snand_mem_org memorg; |
| const struct snand_io_cap *cap_rd; |
| const struct snand_io_cap *cap_pl; |
| snand_select_die_t select_die; |
| }; |
| |
| #define SNAND_INFO(_model, _id, _memorg, _cap_rd, _cap_pl, ...) \ |
| { .model = (_model), .id = _id, .memorg = _memorg, \ |
| .cap_rd = (_cap_rd), .cap_pl = (_cap_pl), __VA_ARGS__ } |
| |
| const struct snand_flash_info *snand_flash_id_lookup(enum snand_id_type type, |
| const uint8_t *id); |
| |
| struct mtk_snand_soc_data { |
| uint16_t sector_size; |
| uint16_t max_sectors; |
| uint16_t fdm_size; |
| uint16_t fdm_ecc_size; |
| uint16_t fifo_size; |
| |
| bool bbm_swap; |
| bool empty_page_check; |
| uint32_t mastersta_mask; |
| |
| const uint8_t *spare_sizes; |
| uint32_t num_spare_size; |
| |
| uint16_t latch_lat; |
| uint16_t sample_delay; |
| }; |
| |
| enum mtk_ecc_regs { |
| ECC_DECDONE, |
| }; |
| |
| struct mtk_ecc_soc_data { |
| const uint8_t *ecc_caps; |
| uint32_t num_ecc_cap; |
| const uint32_t *regs; |
| uint16_t mode_shift; |
| uint8_t errnum_bits; |
| uint8_t errnum_shift; |
| }; |
| |
| struct mtk_snand { |
| struct mtk_snand_plat_dev *pdev; |
| |
| void __iomem *nfi_base; |
| void __iomem *ecc_base; |
| |
| enum mtk_snand_soc soc; |
| const struct mtk_snand_soc_data *nfi_soc; |
| const struct mtk_ecc_soc_data *ecc_soc; |
| bool snfi_quad_spi; |
| bool quad_spi_op; |
| |
| const char *model; |
| uint64_t size; |
| uint64_t die_size; |
| uint32_t erasesize; |
| uint32_t writesize; |
| uint32_t oobsize; |
| |
| uint32_t num_dies; |
| snand_select_die_t select_die; |
| |
| uint8_t opcode_rfc; |
| uint8_t opcode_pl; |
| uint8_t dummy_rfc; |
| uint8_t mode_rfc; |
| uint8_t mode_pl; |
| |
| uint32_t writesize_mask; |
| uint32_t writesize_shift; |
| uint32_t erasesize_mask; |
| uint32_t erasesize_shift; |
| uint64_t die_mask; |
| uint32_t die_shift; |
| |
| uint32_t spare_per_sector; |
| uint32_t raw_sector_size; |
| uint32_t ecc_strength; |
| uint32_t ecc_steps; |
| uint32_t ecc_bytes; |
| uint32_t ecc_parity_bits; |
| |
| uint8_t *page_cache; /* Used by read/write page */ |
| uint8_t *buf_cache; /* Used by block bad/markbad & auto_oob */ |
| int *sect_bf; /* Used by ECC correction */ |
| }; |
| |
| enum mtk_snand_log_category { |
| SNAND_LOG_NFI, |
| SNAND_LOG_SNFI, |
| SNAND_LOG_ECC, |
| SNAND_LOG_CHIP, |
| |
| __SNAND_LOG_CAT_MAX |
| }; |
| |
| int mtk_ecc_setup(struct mtk_snand *snf, void *fmdaddr, uint32_t max_ecc_bytes, |
| uint32_t msg_size); |
| int mtk_snand_ecc_encoder_start(struct mtk_snand *snf); |
| void mtk_snand_ecc_encoder_stop(struct mtk_snand *snf); |
| int mtk_snand_ecc_decoder_start(struct mtk_snand *snf); |
| void mtk_snand_ecc_decoder_stop(struct mtk_snand *snf); |
| int mtk_ecc_wait_decoder_done(struct mtk_snand *snf); |
| int mtk_ecc_check_decode_error(struct mtk_snand *snf); |
| int mtk_ecc_fixup_empty_sector(struct mtk_snand *snf, uint32_t sect); |
| |
| int mtk_snand_mac_io(struct mtk_snand *snf, const uint8_t *out, uint32_t outlen, |
| uint8_t *in, uint32_t inlen); |
| int mtk_snand_set_feature(struct mtk_snand *snf, uint32_t addr, uint32_t val); |
| |
| int mtk_snand_log(struct mtk_snand_plat_dev *pdev, |
| enum mtk_snand_log_category cat, const char *fmt, ...); |
| |
| #define snand_log_nfi(pdev, fmt, ...) \ |
| mtk_snand_log(pdev, SNAND_LOG_NFI, fmt, ##__VA_ARGS__) |
| |
| #define snand_log_snfi(pdev, fmt, ...) \ |
| mtk_snand_log(pdev, SNAND_LOG_SNFI, fmt, ##__VA_ARGS__) |
| |
| #define snand_log_ecc(pdev, fmt, ...) \ |
| mtk_snand_log(pdev, SNAND_LOG_ECC, fmt, ##__VA_ARGS__) |
| |
| #define snand_log_chip(pdev, fmt, ...) \ |
| mtk_snand_log(pdev, SNAND_LOG_CHIP, fmt, ##__VA_ARGS__) |
| |
| /* ffs64 */ |
| static inline int mtk_snand_ffs64(uint64_t x) |
| { |
| if (!x) |
| return 0; |
| |
| if (!(x & 0xffffffff)) |
| return ffs((uint32_t)(x >> 32)) + 32; |
| |
| return ffs((uint32_t)(x & 0xffffffff)); |
| } |
| |
| /* NFI dummy commands */ |
| #define NFI_CMD_DUMMY_READ 0x00 |
| #define NFI_CMD_DUMMY_WRITE 0x80 |
| |
| /* SPI-NAND opcodes */ |
| #define SNAND_CMD_RESET 0xff |
| #define SNAND_CMD_BLOCK_ERASE 0xd8 |
| #define SNAND_CMD_READ_FROM_CACHE_QUAD 0xeb |
| #define SNAND_CMD_WINBOND_SELECT_DIE 0xc2 |
| #define SNAND_CMD_READ_FROM_CACHE_DUAL 0xbb |
| #define SNAND_CMD_READID 0x9f |
| #define SNAND_CMD_READ_FROM_CACHE_X4 0x6b |
| #define SNAND_CMD_READ_FROM_CACHE_X2 0x3b |
| #define SNAND_CMD_PROGRAM_LOAD_X4 0x32 |
| #define SNAND_CMD_SET_FEATURE 0x1f |
| #define SNAND_CMD_READ_TO_CACHE 0x13 |
| #define SNAND_CMD_PROGRAM_EXECUTE 0x10 |
| #define SNAND_CMD_GET_FEATURE 0x0f |
| #define SNAND_CMD_READ_FROM_CACHE 0x0b |
| #define SNAND_CMD_WRITE_ENABLE 0x06 |
| #define SNAND_CMD_PROGRAM_LOAD 0x02 |
| |
| /* SPI-NAND feature addresses */ |
| #define SNAND_FEATURE_MICRON_DIE_ADDR 0xd0 |
| #define SNAND_MICRON_DIE_SEL_1 BIT(6) |
| |
| #define SNAND_FEATURE_STATUS_ADDR 0xc0 |
| #define SNAND_STATUS_OIP BIT(0) |
| #define SNAND_STATUS_WEL BIT(1) |
| #define SNAND_STATUS_ERASE_FAIL BIT(2) |
| #define SNAND_STATUS_PROGRAM_FAIL BIT(3) |
| |
| #define SNAND_FEATURE_CONFIG_ADDR 0xb0 |
| #define SNAND_FEATURE_QUAD_ENABLE BIT(0) |
| #define SNAND_FEATURE_ECC_EN BIT(4) |
| |
| #define SNAND_FEATURE_PROTECT_ADDR 0xa0 |
| |
| #endif /* _MTK_SNAND_DEF_H_ */ |