mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-22 23:12:32 +00:00
050621aa01
This patch adds a new spi-nand driver which implements the SNFI of mt7622 and mt7629. Unlike the existing snfi driver which makes use of the spi-mem framework and the spi-nand framework with modified ecc support, this driver is implemented directly on the mtd framework with other components untouched, and provides better performance, and behaves exactly the same as the nand framework. Signed-off-by: Weijie Gao <hackpascal@gmail.com>
269 lines
6.5 KiB
C
269 lines
6.5 KiB
C
/* 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;
|
|
};
|
|
|
|
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_ */
|