Merge tag 'mtd/for-4.19' of git://git.infradead.org/linux-mtd
Pull mtd updates from Boris Brezillon: "JFFS2 changes: - Support 64-bit timestamps MTD core changes: - Support sub-partitions - Clarify mtd_oob_ops documentation - Make Kconfig formatting consistent - Fix potential overflows in mtdchar_{write,read}() - Fallback to ->_{read,write}() when ->_{read,write}_oob() is missing and no OOB data were requested - Remove VLA usage in the bch lib MTD driver changes: - Use mtd_device_register() instead of mtd_device_parse_register() where applicable - Use proper printk format to print physical addresses in the solutionengine driver - Add missing mtd_set_of_node() call in the powernv driver - Remove unneeded variables in a few drivers - Plug the TRX part parser to the DT partition parsers logic - Check ioremap_cache() return code in the gpio-addr-flash driver - Stop using VMLINUX_SYMBOL_STR() in gen_probe.c SPI NOR core changes: - Apply reset hacks only when reset is explicitly marked as broken in the DT SPI NOR driver changes: - Minor cleanup/fixes in the m25p80 driver - Release flash_np in the nxp-spifi driver - Add suspend/resume hooks to the atmel-quadspi driver - Include gpio/consumer.h instead of gpio.h in the atmel-quadspi driver - Use %pK instead of %p in the stm32-quadspi driver - Improve timeout handling in the cadence-quadspi driver - Use mtd_device_register() instead of mtd_device_parse_register() in the intel-spi driver NAND core changes: - Add the SPI-NAND framework. - Create a helper to find the best ECC configuration. - Create NAND controller operations. - Allocate dynamically ONFI parameters structure. - Add defines for ONFI version bits. - Add manufacturer fixup for ONFI parameter page. - Add an option to specify NAND chip as a boot device. - Add Reed-Solomon error correction algorithm. - Better name for the controller structure. - Remove unused caller_is_module() definition. - Make subop helpers return unsigned values. - Expose _notsupp() helpers for raw page accessors. - Add default values for dynamic timings. - Kill the chip->scan_bbt() hook. - Rename nand_default_bbt() into nand_create_bbt(). - Start to clean the nand_chip structure. - Remove stale prototype from rawnand.h. Raw NAND controllers drivers changes: - Qcom: structuring cleanup. - Denali: use core helper to find the best ECC configuration. - Possible build of almost all drivers by adding a dependency on COMPILE_TEST for almost all of them in Kconfig, implies various fixes, Kconfig cleanup, GPIO headers inclusion cleanup, and even changes in sparc64 and ia64 architectures. - Clean the ->probe() functions error path of a lot of drivers. - Migrate all drivers to use nand_scan() instead of nand_scan_ident()/nand_scan_tail() pair. - Use mtd_device_register() where applicable to simplify the code. - Marvell: * Handle on-die ECC. * Better clocks handling. * Remove bogus comment. * Add suspend and resume support. - Tegra: add NAND controller driver. - Atmel: * Add module param to avoid using dma. * Drop Wenyou Yang from MAINTAINERS. - Denali: optimize timings handling. - FSMC: Stop using chip->read_buf(). - FSL: * Switch to SPDX license tag identifiers. * Fix qualifiers in MXC init functions. Raw NAND chip drivers changes: - Micron: * Add fixup for ONFI revision. * Update ecc_stats.corrected. * Make ECC activation stateful. * Avoid enabling/disabling ECC when it can't be disabled. * Get the actual number of bitflips. * Allow forced on-die ECC. * Support 8/512 on-die ECC. * Fix on-die ECC detection logic. - Hynix: * Fix decoding the OOB size on H27UCG8T2BTR. * Use ->exec_op() in hynix_nand_reg_write_op()" * tag 'mtd/for-4.19' of git://git.infradead.org/linux-mtd: (188 commits) mtd: rawnand: atmel: Select GENERIC_ALLOCATOR MAINTAINERS: drop Wenyou Yang from Atmel NAND driver support mtd: rawnand: allocate dynamically ONFI parameters during detection mtd: spi-nor: only apply reset hacks to broken hardware mtd: spi-nor: cadence-quadspi: fix timeout handling mtd: spi-nor: atmel-quadspi: Include gpio/consumer.h instead of gpio.h mtd: spi-nor: intel-spi: use mtd_device_register() mtd: spi-nor: stm32-quadspi: replace "%p" with "%pK" mtd: spi-nor: atmel-quadspi: add suspend/resume hooks mtd: rawnand: allocate model parameter dynamically mtd: rawnand: do not export nand_scan_[ident|tail]() anymore mtd: rawnand: txx9ndfmc: convert driver to nand_scan() mtd: rawnand: txx9ndfmc: clarify ECC parameters assignation mtd: rawnand: tegra: convert driver to nand_scan() mtd: rawnand: jz4740: convert driver to nand_scan() mtd: rawnand: jz4740: group nand_scan_{ident, tail} calls mtd: rawnand: jz4740: fix probe function error path mtd: rawnand: docg4: convert driver to nand_scan() mtd: rawnand: do not execute nand_scan_ident() if maxchips is zero mtd: rawnand: atmel: convert driver to nand_scan() ...
This commit is contained in:
@@ -67,9 +67,11 @@ struct mtd_erase_region_info {
|
||||
* @datbuf: data buffer - if NULL only oob data are read/written
|
||||
* @oobbuf: oob data buffer
|
||||
*
|
||||
* Note, it is allowed to read more than one OOB area at one go, but not write.
|
||||
* The interface assumes that the OOB write requests program only one page's
|
||||
* OOB area.
|
||||
* Note, some MTD drivers do not allow you to write more than one OOB area at
|
||||
* one go. If you try to do that on such an MTD device, -EINVAL will be
|
||||
* returned. If you want to make your implementation portable on all kind of MTD
|
||||
* devices you should split the write request into several sub-requests when the
|
||||
* request crosses a page boundary.
|
||||
*/
|
||||
struct mtd_oob_ops {
|
||||
unsigned int mode;
|
||||
|
@@ -21,11 +21,10 @@
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/flashchip.h>
|
||||
#include <linux/mtd/bbm.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct mtd_info;
|
||||
struct nand_flash_dev;
|
||||
struct device_node;
|
||||
|
||||
/* Scan and identify a NAND device */
|
||||
int nand_scan_with_ids(struct mtd_info *mtd, int max_chips,
|
||||
@@ -36,17 +35,6 @@ static inline int nand_scan(struct mtd_info *mtd, int max_chips)
|
||||
return nand_scan_with_ids(mtd, max_chips, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Separate phases of nand_scan(), allowing board driver to intervene
|
||||
* and override command or ECC setup according to flash type.
|
||||
*/
|
||||
int nand_scan_ident(struct mtd_info *mtd, int max_chips,
|
||||
struct nand_flash_dev *table);
|
||||
int nand_scan_tail(struct mtd_info *mtd);
|
||||
|
||||
/* Unregister the MTD device and free resources held by the NAND device */
|
||||
void nand_release(struct mtd_info *mtd);
|
||||
|
||||
/* Internal helper for board drivers which need to override command function */
|
||||
void nand_wait_ready(struct mtd_info *mtd);
|
||||
|
||||
@@ -121,6 +109,7 @@ enum nand_ecc_algo {
|
||||
NAND_ECC_UNKNOWN,
|
||||
NAND_ECC_HAMMING,
|
||||
NAND_ECC_BCH,
|
||||
NAND_ECC_RS,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -218,6 +207,12 @@ enum nand_ecc_algo {
|
||||
*/
|
||||
#define NAND_WAIT_TCCS 0x00200000
|
||||
|
||||
/*
|
||||
* Whether the NAND chip is a boot medium. Drivers might use this information
|
||||
* to select ECC algorithms supported by the boot ROM or similar restrictions.
|
||||
*/
|
||||
#define NAND_IS_BOOT_MEDIUM 0x00400000
|
||||
|
||||
/* Options set by nand scan */
|
||||
/* Nand scan has allocated controller struct */
|
||||
#define NAND_CONTROLLER_ALLOC 0x80000000
|
||||
@@ -230,6 +225,17 @@ enum nand_ecc_algo {
|
||||
/* Keep gcc happy */
|
||||
struct nand_chip;
|
||||
|
||||
/* ONFI version bits */
|
||||
#define ONFI_VERSION_1_0 BIT(1)
|
||||
#define ONFI_VERSION_2_0 BIT(2)
|
||||
#define ONFI_VERSION_2_1 BIT(3)
|
||||
#define ONFI_VERSION_2_2 BIT(4)
|
||||
#define ONFI_VERSION_2_3 BIT(5)
|
||||
#define ONFI_VERSION_3_0 BIT(6)
|
||||
#define ONFI_VERSION_3_1 BIT(7)
|
||||
#define ONFI_VERSION_3_2 BIT(8)
|
||||
#define ONFI_VERSION_4_0 BIT(9)
|
||||
|
||||
/* ONFI features */
|
||||
#define ONFI_FEATURE_16_BIT_BUS (1 << 0)
|
||||
#define ONFI_FEATURE_EXT_PARAM_PAGE (1 << 7)
|
||||
@@ -470,13 +476,13 @@ struct onfi_params {
|
||||
*/
|
||||
struct nand_parameters {
|
||||
/* Generic parameters */
|
||||
char model[100];
|
||||
const char *model;
|
||||
bool supports_set_get_features;
|
||||
DECLARE_BITMAP(set_feature_list, ONFI_FEATURE_NUMBER);
|
||||
DECLARE_BITMAP(get_feature_list, ONFI_FEATURE_NUMBER);
|
||||
|
||||
/* ONFI parameters */
|
||||
struct onfi_params onfi;
|
||||
struct onfi_params *onfi;
|
||||
};
|
||||
|
||||
/* The maximum expected count of bytes in the NAND ID sequence */
|
||||
@@ -493,20 +499,42 @@ struct nand_id {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices
|
||||
* struct nand_controller_ops - Controller operations
|
||||
*
|
||||
* @attach_chip: this method is called after the NAND detection phase after
|
||||
* flash ID and MTD fields such as erase size, page size and OOB
|
||||
* size have been set up. ECC requirements are available if
|
||||
* provided by the NAND chip or device tree. Typically used to
|
||||
* choose the appropriate ECC configuration and allocate
|
||||
* associated resources.
|
||||
* This hook is optional.
|
||||
* @detach_chip: free all resources allocated/claimed in
|
||||
* nand_controller_ops->attach_chip().
|
||||
* This hook is optional.
|
||||
*/
|
||||
struct nand_controller_ops {
|
||||
int (*attach_chip)(struct nand_chip *chip);
|
||||
void (*detach_chip)(struct nand_chip *chip);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nand_controller - Structure used to describe a NAND controller
|
||||
*
|
||||
* @lock: protection lock
|
||||
* @active: the mtd device which holds the controller currently
|
||||
* @wq: wait queue to sleep on if a NAND operation is in
|
||||
* progress used instead of the per chip wait queue
|
||||
* when a hw controller is available.
|
||||
* @ops: NAND controller operations.
|
||||
*/
|
||||
struct nand_hw_control {
|
||||
struct nand_controller {
|
||||
spinlock_t lock;
|
||||
struct nand_chip *active;
|
||||
wait_queue_head_t wq;
|
||||
const struct nand_controller_ops *ops;
|
||||
};
|
||||
|
||||
static inline void nand_hw_control_init(struct nand_hw_control *nfc)
|
||||
static inline void nand_controller_init(struct nand_controller *nfc)
|
||||
{
|
||||
nfc->active = NULL;
|
||||
spin_lock_init(&nfc->lock);
|
||||
@@ -778,11 +806,15 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
|
||||
* implementation) if any.
|
||||
* @cleanup: the ->init() function may have allocated resources, ->cleanup()
|
||||
* is here to let vendor specific code release those resources.
|
||||
* @fixup_onfi_param_page: apply vendor specific fixups to the ONFI parameter
|
||||
* page. This is called after the checksum is verified.
|
||||
*/
|
||||
struct nand_manufacturer_ops {
|
||||
void (*detect)(struct nand_chip *chip);
|
||||
int (*init)(struct nand_chip *chip);
|
||||
void (*cleanup)(struct nand_chip *chip);
|
||||
void (*fixup_onfi_param_page)(struct nand_chip *chip,
|
||||
struct nand_onfi_params *p);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -986,14 +1018,14 @@ struct nand_subop {
|
||||
unsigned int last_instr_end_off;
|
||||
};
|
||||
|
||||
int nand_subop_get_addr_start_off(const struct nand_subop *subop,
|
||||
unsigned int op_id);
|
||||
int nand_subop_get_num_addr_cyc(const struct nand_subop *subop,
|
||||
unsigned int op_id);
|
||||
int nand_subop_get_data_start_off(const struct nand_subop *subop,
|
||||
unsigned int op_id);
|
||||
int nand_subop_get_data_len(const struct nand_subop *subop,
|
||||
unsigned int op_id);
|
||||
unsigned int nand_subop_get_addr_start_off(const struct nand_subop *subop,
|
||||
unsigned int op_id);
|
||||
unsigned int nand_subop_get_num_addr_cyc(const struct nand_subop *subop,
|
||||
unsigned int op_id);
|
||||
unsigned int nand_subop_get_data_start_off(const struct nand_subop *subop,
|
||||
unsigned int op_id);
|
||||
unsigned int nand_subop_get_data_len(const struct nand_subop *subop,
|
||||
unsigned int op_id);
|
||||
|
||||
/**
|
||||
* struct nand_op_parser_addr_constraints - Constraints for address instructions
|
||||
@@ -1176,9 +1208,9 @@ int nand_op_parser_exec_op(struct nand_chip *chip,
|
||||
* setting the read-retry mode. Mostly needed for MLC NAND.
|
||||
* @ecc: [BOARDSPECIFIC] ECC control structure
|
||||
* @buf_align: minimum buffer alignment required by a platform
|
||||
* @hwcontrol: platform-specific hardware control structure
|
||||
* @dummy_controller: dummy controller implementation for drivers that can
|
||||
* only control a single chip
|
||||
* @erase: [REPLACEABLE] erase function
|
||||
* @scan_bbt: [REPLACEABLE] function to scan bad block table
|
||||
* @chip_delay: [BOARDSPECIFIC] chip dependent delay for transferring
|
||||
* data from array to read regs (tR).
|
||||
* @state: [INTERN] the current state of the NAND device
|
||||
@@ -1271,7 +1303,6 @@ struct nand_chip {
|
||||
const struct nand_operation *op,
|
||||
bool check_only);
|
||||
int (*erase)(struct mtd_info *mtd, int page);
|
||||
int (*scan_bbt)(struct mtd_info *mtd);
|
||||
int (*set_features)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int feature_addr, uint8_t *subfeature_para);
|
||||
int (*get_features)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
@@ -1314,11 +1345,11 @@ struct nand_chip {
|
||||
flstate_t state;
|
||||
|
||||
uint8_t *oob_poi;
|
||||
struct nand_hw_control *controller;
|
||||
struct nand_controller *controller;
|
||||
|
||||
struct nand_ecc_ctrl ecc;
|
||||
unsigned long buf_align;
|
||||
struct nand_hw_control hwcontrol;
|
||||
struct nand_controller dummy_controller;
|
||||
|
||||
uint8_t *bbt;
|
||||
struct nand_bbt_descr *bbt_td;
|
||||
@@ -1517,14 +1548,12 @@ extern const struct nand_manufacturer_ops micron_nand_manuf_ops;
|
||||
extern const struct nand_manufacturer_ops amd_nand_manuf_ops;
|
||||
extern const struct nand_manufacturer_ops macronix_nand_manuf_ops;
|
||||
|
||||
int nand_default_bbt(struct mtd_info *mtd);
|
||||
int nand_create_bbt(struct nand_chip *chip);
|
||||
int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
|
||||
int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);
|
||||
int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
|
||||
int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
|
||||
int allowbbt);
|
||||
int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, uint8_t *buf);
|
||||
|
||||
/**
|
||||
* struct platform_nand_chip - chip level device structure
|
||||
@@ -1555,14 +1584,12 @@ struct platform_device;
|
||||
* struct platform_nand_ctrl - controller level device structure
|
||||
* @probe: platform specific function to probe/setup hardware
|
||||
* @remove: platform specific function to remove/teardown hardware
|
||||
* @hwcontrol: platform specific hardware control structure
|
||||
* @dev_ready: platform specific function to read ready/busy pin
|
||||
* @select_chip: platform specific chip select function
|
||||
* @cmd_ctrl: platform specific function for controlling
|
||||
* ALE/CLE/nCE. Also used to write command and address
|
||||
* @write_buf: platform specific function for write buffer
|
||||
* @read_buf: platform specific function for read buffer
|
||||
* @read_byte: platform specific function to read one byte from chip
|
||||
* @priv: private data to transport driver specific settings
|
||||
*
|
||||
* All fields are optional and depend on the hardware driver requirements
|
||||
@@ -1570,13 +1597,11 @@ struct platform_device;
|
||||
struct platform_nand_ctrl {
|
||||
int (*probe)(struct platform_device *pdev);
|
||||
void (*remove)(struct platform_device *pdev);
|
||||
void (*hwcontrol)(struct mtd_info *mtd, int cmd);
|
||||
int (*dev_ready)(struct mtd_info *mtd);
|
||||
void (*select_chip)(struct mtd_info *mtd, int chip);
|
||||
void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
|
||||
void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
|
||||
void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
|
||||
unsigned char (*read_byte)(struct mtd_info *mtd);
|
||||
void *priv;
|
||||
};
|
||||
|
||||
@@ -1593,10 +1618,10 @@ struct platform_nand_data {
|
||||
/* return the supported asynchronous timing mode. */
|
||||
static inline int onfi_get_async_timing_mode(struct nand_chip *chip)
|
||||
{
|
||||
if (!chip->parameters.onfi.version)
|
||||
if (!chip->parameters.onfi)
|
||||
return ONFI_TIMING_MODE_UNKNOWN;
|
||||
|
||||
return chip->parameters.onfi.async_timing_mode;
|
||||
return chip->parameters.onfi->async_timing_mode;
|
||||
}
|
||||
|
||||
int onfi_fill_data_interface(struct nand_chip *chip,
|
||||
@@ -1641,14 +1666,8 @@ int nand_check_erased_ecc_chunk(void *data, int datalen,
|
||||
void *extraoob, int extraooblen,
|
||||
int threshold);
|
||||
|
||||
int nand_check_ecc_caps(struct nand_chip *chip,
|
||||
const struct nand_ecc_caps *caps, int oobavail);
|
||||
|
||||
int nand_match_ecc_req(struct nand_chip *chip,
|
||||
const struct nand_ecc_caps *caps, int oobavail);
|
||||
|
||||
int nand_maximize_ecc(struct nand_chip *chip,
|
||||
const struct nand_ecc_caps *caps, int oobavail);
|
||||
int nand_ecc_choose_conf(struct nand_chip *chip,
|
||||
const struct nand_ecc_caps *caps, int oobavail);
|
||||
|
||||
/* Default write_oob implementation */
|
||||
int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page);
|
||||
@@ -1674,10 +1693,14 @@ int nand_get_set_features_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
/* Default read_page_raw implementation */
|
||||
int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page);
|
||||
int nand_read_page_raw_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
u8 *buf, int oob_required, int page);
|
||||
|
||||
/* Default write_page_raw implementation */
|
||||
int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required, int page);
|
||||
int nand_write_page_raw_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const u8 *buf, int oob_required, int page);
|
||||
|
||||
/* Reset and initialize a NAND device */
|
||||
int nand_reset(struct nand_chip *chip, int chipnr);
|
||||
@@ -1711,8 +1734,13 @@ int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
|
||||
int nand_write_data_op(struct nand_chip *chip, const void *buf,
|
||||
unsigned int len, bool force_8bit);
|
||||
|
||||
/* Free resources held by the NAND device */
|
||||
/*
|
||||
* Free resources held by the NAND device, must be called on error after a
|
||||
* sucessful nand_scan().
|
||||
*/
|
||||
void nand_cleanup(struct nand_chip *chip);
|
||||
/* Unregister the MTD device and calls nand_cleanup() */
|
||||
void nand_release(struct mtd_info *mtd);
|
||||
|
||||
/* Default extended ID decoding function */
|
||||
void nand_decode_ext_id(struct nand_chip *chip);
|
||||
|
@@ -235,6 +235,7 @@ enum spi_nor_option_flags {
|
||||
SNOR_F_S3AN_ADDR_DEFAULT = BIT(3),
|
||||
SNOR_F_READY_XSR_RDY = BIT(4),
|
||||
SNOR_F_USE_CLSR = BIT(5),
|
||||
SNOR_F_BROKEN_RESET = BIT(6),
|
||||
};
|
||||
|
||||
/**
|
||||
|
421
include/linux/mtd/spinand.h
Normal file
421
include/linux/mtd/spinand.h
Normal file
@@ -0,0 +1,421 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Micron Technology, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Peter Pan <peterpandong@micron.com>
|
||||
*/
|
||||
#ifndef __LINUX_MTD_SPINAND_H
|
||||
#define __LINUX_MTD_SPINAND_H
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spi-mem.h>
|
||||
|
||||
/**
|
||||
* Standard SPI NAND flash operations
|
||||
*/
|
||||
|
||||
#define SPINAND_RESET_OP \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xff, 1), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_WR_EN_DIS_OP(enable) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD((enable) ? 0x06 : 0x04, 1), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_READID_OP(ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1))
|
||||
|
||||
#define SPINAND_SET_FEATURE_OP(reg, valptr) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x1f, 1), \
|
||||
SPI_MEM_OP_ADDR(1, reg, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_OUT(1, valptr, 1))
|
||||
|
||||
#define SPINAND_GET_FEATURE_OP(reg, valptr) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x0f, 1), \
|
||||
SPI_MEM_OP_ADDR(1, reg, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_IN(1, valptr, 1))
|
||||
|
||||
#define SPINAND_BLK_ERASE_OP(addr) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xd8, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_PAGE_READ_OP(addr) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x13, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_OP(fast, addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_X2_OP(addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_X4_OP(addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 2), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 2), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 4), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 4), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4))
|
||||
|
||||
#define SPINAND_PROG_EXEC_OP(addr) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x10, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_PROG_LOAD(reset, addr, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x02 : 0x84, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_OUT(len, buf, 1))
|
||||
|
||||
#define SPINAND_PROG_LOAD_X4(reset, addr, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x32 : 0x34, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_OUT(len, buf, 4))
|
||||
|
||||
/**
|
||||
* Standard SPI NAND flash commands
|
||||
*/
|
||||
#define SPINAND_CMD_PROG_LOAD_X4 0x32
|
||||
#define SPINAND_CMD_PROG_LOAD_RDM_DATA_X4 0x34
|
||||
|
||||
/* feature register */
|
||||
#define REG_BLOCK_LOCK 0xa0
|
||||
#define BL_ALL_UNLOCKED 0x00
|
||||
|
||||
/* configuration register */
|
||||
#define REG_CFG 0xb0
|
||||
#define CFG_OTP_ENABLE BIT(6)
|
||||
#define CFG_ECC_ENABLE BIT(4)
|
||||
#define CFG_QUAD_ENABLE BIT(0)
|
||||
|
||||
/* status register */
|
||||
#define REG_STATUS 0xc0
|
||||
#define STATUS_BUSY BIT(0)
|
||||
#define STATUS_ERASE_FAILED BIT(2)
|
||||
#define STATUS_PROG_FAILED BIT(3)
|
||||
#define STATUS_ECC_MASK GENMASK(5, 4)
|
||||
#define STATUS_ECC_NO_BITFLIPS (0 << 4)
|
||||
#define STATUS_ECC_HAS_BITFLIPS (1 << 4)
|
||||
#define STATUS_ECC_UNCOR_ERROR (2 << 4)
|
||||
|
||||
struct spinand_op;
|
||||
struct spinand_device;
|
||||
|
||||
#define SPINAND_MAX_ID_LEN 4
|
||||
|
||||
/**
|
||||
* struct spinand_id - SPI NAND id structure
|
||||
* @data: buffer containing the id bytes. Currently 4 bytes large, but can
|
||||
* be extended if required
|
||||
* @len: ID length
|
||||
*
|
||||
* struct_spinand_id->data contains all bytes returned after a READ_ID command,
|
||||
* including dummy bytes if the chip does not emit ID bytes right after the
|
||||
* READ_ID command. The responsibility to extract real ID bytes is left to
|
||||
* struct_manufacurer_ops->detect().
|
||||
*/
|
||||
struct spinand_id {
|
||||
u8 data[SPINAND_MAX_ID_LEN];
|
||||
int len;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct manufacurer_ops - SPI NAND manufacturer specific operations
|
||||
* @detect: detect a SPI NAND device. Every time a SPI NAND device is probed
|
||||
* the core calls the struct_manufacurer_ops->detect() hook of each
|
||||
* registered manufacturer until one of them return 1. Note that
|
||||
* the first thing to check in this hook is that the manufacturer ID
|
||||
* in struct_spinand_device->id matches the manufacturer whose
|
||||
* ->detect() hook has been called. Should return 1 if there's a
|
||||
* match, 0 if the manufacturer ID does not match and a negative
|
||||
* error code otherwise. When true is returned, the core assumes
|
||||
* that properties of the NAND chip (spinand->base.memorg and
|
||||
* spinand->base.eccreq) have been filled
|
||||
* @init: initialize a SPI NAND device
|
||||
* @cleanup: cleanup a SPI NAND device
|
||||
*
|
||||
* Each SPI NAND manufacturer driver should implement this interface so that
|
||||
* NAND chips coming from this vendor can be detected and initialized properly.
|
||||
*/
|
||||
struct spinand_manufacturer_ops {
|
||||
int (*detect)(struct spinand_device *spinand);
|
||||
int (*init)(struct spinand_device *spinand);
|
||||
void (*cleanup)(struct spinand_device *spinand);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct spinand_manufacturer - SPI NAND manufacturer instance
|
||||
* @id: manufacturer ID
|
||||
* @name: manufacturer name
|
||||
* @ops: manufacturer operations
|
||||
*/
|
||||
struct spinand_manufacturer {
|
||||
u8 id;
|
||||
char *name;
|
||||
const struct spinand_manufacturer_ops *ops;
|
||||
};
|
||||
|
||||
/* SPI NAND manufacturers */
|
||||
extern const struct spinand_manufacturer macronix_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer micron_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer winbond_spinand_manufacturer;
|
||||
|
||||
/**
|
||||
* struct spinand_op_variants - SPI NAND operation variants
|
||||
* @ops: the list of variants for a given operation
|
||||
* @nops: the number of variants
|
||||
*
|
||||
* Some operations like read-from-cache/write-to-cache have several variants
|
||||
* depending on the number of IO lines you use to transfer data or address
|
||||
* cycles. This structure is a way to describe the different variants supported
|
||||
* by a chip and let the core pick the best one based on the SPI mem controller
|
||||
* capabilities.
|
||||
*/
|
||||
struct spinand_op_variants {
|
||||
const struct spi_mem_op *ops;
|
||||
unsigned int nops;
|
||||
};
|
||||
|
||||
#define SPINAND_OP_VARIANTS(name, ...) \
|
||||
const struct spinand_op_variants name = { \
|
||||
.ops = (struct spi_mem_op[]) { __VA_ARGS__ }, \
|
||||
.nops = sizeof((struct spi_mem_op[]){ __VA_ARGS__ }) / \
|
||||
sizeof(struct spi_mem_op), \
|
||||
}
|
||||
|
||||
/**
|
||||
* spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
|
||||
* chip
|
||||
* @get_status: get the ECC status. Should return a positive number encoding
|
||||
* the number of corrected bitflips if correction was possible or
|
||||
* -EBADMSG if there are uncorrectable errors. I can also return
|
||||
* other negative error codes if the error is not caused by
|
||||
* uncorrectable bitflips
|
||||
* @ooblayout: the OOB layout used by the on-die ECC implementation
|
||||
*/
|
||||
struct spinand_ecc_info {
|
||||
int (*get_status)(struct spinand_device *spinand, u8 status);
|
||||
const struct mtd_ooblayout_ops *ooblayout;
|
||||
};
|
||||
|
||||
#define SPINAND_HAS_QE_BIT BIT(0)
|
||||
|
||||
/**
|
||||
* struct spinand_info - Structure used to describe SPI NAND chips
|
||||
* @model: model name
|
||||
* @devid: device ID
|
||||
* @flags: OR-ing of the SPINAND_XXX flags
|
||||
* @memorg: memory organization
|
||||
* @eccreq: ECC requirements
|
||||
* @eccinfo: on-die ECC info
|
||||
* @op_variants: operations variants
|
||||
* @op_variants.read_cache: variants of the read-cache operation
|
||||
* @op_variants.write_cache: variants of the write-cache operation
|
||||
* @op_variants.update_cache: variants of the update-cache operation
|
||||
* @select_target: function used to select a target/die. Required only for
|
||||
* multi-die chips
|
||||
*
|
||||
* Each SPI NAND manufacturer driver should have a spinand_info table
|
||||
* describing all the chips supported by the driver.
|
||||
*/
|
||||
struct spinand_info {
|
||||
const char *model;
|
||||
u8 devid;
|
||||
u32 flags;
|
||||
struct nand_memory_organization memorg;
|
||||
struct nand_ecc_req eccreq;
|
||||
struct spinand_ecc_info eccinfo;
|
||||
struct {
|
||||
const struct spinand_op_variants *read_cache;
|
||||
const struct spinand_op_variants *write_cache;
|
||||
const struct spinand_op_variants *update_cache;
|
||||
} op_variants;
|
||||
int (*select_target)(struct spinand_device *spinand,
|
||||
unsigned int target);
|
||||
};
|
||||
|
||||
#define SPINAND_INFO_OP_VARIANTS(__read, __write, __update) \
|
||||
{ \
|
||||
.read_cache = __read, \
|
||||
.write_cache = __write, \
|
||||
.update_cache = __update, \
|
||||
}
|
||||
|
||||
#define SPINAND_ECCINFO(__ooblayout, __get_status) \
|
||||
.eccinfo = { \
|
||||
.ooblayout = __ooblayout, \
|
||||
.get_status = __get_status, \
|
||||
}
|
||||
|
||||
#define SPINAND_SELECT_TARGET(__func) \
|
||||
.select_target = __func,
|
||||
|
||||
#define SPINAND_INFO(__model, __id, __memorg, __eccreq, __op_variants, \
|
||||
__flags, ...) \
|
||||
{ \
|
||||
.model = __model, \
|
||||
.devid = __id, \
|
||||
.memorg = __memorg, \
|
||||
.eccreq = __eccreq, \
|
||||
.op_variants = __op_variants, \
|
||||
.flags = __flags, \
|
||||
__VA_ARGS__ \
|
||||
}
|
||||
|
||||
/**
|
||||
* struct spinand_device - SPI NAND device instance
|
||||
* @base: NAND device instance
|
||||
* @spimem: pointer to the SPI mem object
|
||||
* @lock: lock used to serialize accesses to the NAND
|
||||
* @id: NAND ID as returned by READ_ID
|
||||
* @flags: NAND flags
|
||||
* @op_templates: various SPI mem op templates
|
||||
* @op_templates.read_cache: read cache op template
|
||||
* @op_templates.write_cache: write cache op template
|
||||
* @op_templates.update_cache: update cache op template
|
||||
* @select_target: select a specific target/die. Usually called before sending
|
||||
* a command addressing a page or an eraseblock embedded in
|
||||
* this die. Only required if your chip exposes several dies
|
||||
* @cur_target: currently selected target/die
|
||||
* @eccinfo: on-die ECC information
|
||||
* @cfg_cache: config register cache. One entry per die
|
||||
* @databuf: bounce buffer for data
|
||||
* @oobbuf: bounce buffer for OOB data
|
||||
* @scratchbuf: buffer used for everything but page accesses. This is needed
|
||||
* because the spi-mem interface explicitly requests that buffers
|
||||
* passed in spi_mem_op be DMA-able, so we can't based the bufs on
|
||||
* the stack
|
||||
* @manufacturer: SPI NAND manufacturer information
|
||||
* @priv: manufacturer private data
|
||||
*/
|
||||
struct spinand_device {
|
||||
struct nand_device base;
|
||||
struct spi_mem *spimem;
|
||||
struct mutex lock;
|
||||
struct spinand_id id;
|
||||
u32 flags;
|
||||
|
||||
struct {
|
||||
const struct spi_mem_op *read_cache;
|
||||
const struct spi_mem_op *write_cache;
|
||||
const struct spi_mem_op *update_cache;
|
||||
} op_templates;
|
||||
|
||||
int (*select_target)(struct spinand_device *spinand,
|
||||
unsigned int target);
|
||||
unsigned int cur_target;
|
||||
|
||||
struct spinand_ecc_info eccinfo;
|
||||
|
||||
u8 *cfg_cache;
|
||||
u8 *databuf;
|
||||
u8 *oobbuf;
|
||||
u8 *scratchbuf;
|
||||
const struct spinand_manufacturer *manufacturer;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* mtd_to_spinand() - Get the SPI NAND device attached to an MTD instance
|
||||
* @mtd: MTD instance
|
||||
*
|
||||
* Return: the SPI NAND device attached to @mtd.
|
||||
*/
|
||||
static inline struct spinand_device *mtd_to_spinand(struct mtd_info *mtd)
|
||||
{
|
||||
return container_of(mtd_to_nanddev(mtd), struct spinand_device, base);
|
||||
}
|
||||
|
||||
/**
|
||||
* spinand_to_mtd() - Get the MTD device embedded in a SPI NAND device
|
||||
* @spinand: SPI NAND device
|
||||
*
|
||||
* Return: the MTD device embedded in @spinand.
|
||||
*/
|
||||
static inline struct mtd_info *spinand_to_mtd(struct spinand_device *spinand)
|
||||
{
|
||||
return nanddev_to_mtd(&spinand->base);
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_to_spinand() - Get the SPI NAND device embedding an NAND object
|
||||
* @nand: NAND object
|
||||
*
|
||||
* Return: the SPI NAND device embedding @nand.
|
||||
*/
|
||||
static inline struct spinand_device *nand_to_spinand(struct nand_device *nand)
|
||||
{
|
||||
return container_of(nand, struct spinand_device, base);
|
||||
}
|
||||
|
||||
/**
|
||||
* spinand_to_nand() - Get the NAND device embedded in a SPI NAND object
|
||||
* @spinand: SPI NAND device
|
||||
*
|
||||
* Return: the NAND device embedded in @spinand.
|
||||
*/
|
||||
static inline struct nand_device *
|
||||
spinand_to_nand(struct spinand_device *spinand)
|
||||
{
|
||||
return &spinand->base;
|
||||
}
|
||||
|
||||
/**
|
||||
* spinand_set_of_node - Attach a DT node to a SPI NAND device
|
||||
* @spinand: SPI NAND device
|
||||
* @np: DT node
|
||||
*
|
||||
* Attach a DT node to a SPI NAND device.
|
||||
*/
|
||||
static inline void spinand_set_of_node(struct spinand_device *spinand,
|
||||
struct device_node *np)
|
||||
{
|
||||
nanddev_set_of_node(&spinand->base, np);
|
||||
}
|
||||
|
||||
int spinand_match_and_init(struct spinand_device *dev,
|
||||
const struct spinand_info *table,
|
||||
unsigned int table_size, u8 devid);
|
||||
|
||||
int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
|
||||
int spinand_select_target(struct spinand_device *spinand, unsigned int target);
|
||||
|
||||
#endif /* __LINUX_MTD_SPINAND_H */
|
34
include/linux/platform_data/jz4740/jz4740_nand.h
Normal file
34
include/linux/platform_data/jz4740/jz4740_nand.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
|
||||
* JZ4740 SoC NAND controller driver
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __JZ4740_NAND_H__
|
||||
#define __JZ4740_NAND_H__
|
||||
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
||||
#define JZ_NAND_NUM_BANKS 4
|
||||
|
||||
struct jz_nand_platform_data {
|
||||
int num_partitions;
|
||||
struct mtd_partition *partitions;
|
||||
|
||||
unsigned char banks[JZ_NAND_NUM_BANKS];
|
||||
|
||||
void (*ident_callback)(struct platform_device *, struct mtd_info *,
|
||||
struct mtd_partition **, int *num_partitions);
|
||||
};
|
||||
|
||||
#endif
|
@@ -12,7 +12,6 @@
|
||||
*/
|
||||
struct orion_nand_data {
|
||||
struct mtd_partition *parts;
|
||||
int (*dev_ready)(struct mtd_info *mtd);
|
||||
u32 nr_parts;
|
||||
u8 ale; /* address line number connected to ALE */
|
||||
u8 cle; /* address line number connected to CLE */
|
||||
|
30
include/linux/platform_data/txx9/ndfmc.h
Normal file
30
include/linux/platform_data/txx9/ndfmc.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* (C) Copyright TOSHIBA CORPORATION 2007
|
||||
*/
|
||||
#ifndef __TXX9_NDFMC_H
|
||||
#define __TXX9_NDFMC_H
|
||||
|
||||
#define NDFMC_PLAT_FLAG_USE_BSPRT 0x01
|
||||
#define NDFMC_PLAT_FLAG_NO_RSTR 0x02
|
||||
#define NDFMC_PLAT_FLAG_HOLDADD 0x04
|
||||
#define NDFMC_PLAT_FLAG_DUMMYWRITE 0x08
|
||||
|
||||
struct txx9ndfmc_platform_data {
|
||||
unsigned int shift;
|
||||
unsigned int gbus_clock;
|
||||
unsigned int hold; /* hold time in nanosecond */
|
||||
unsigned int spw; /* strobe pulse width in nanosecond */
|
||||
unsigned int flags;
|
||||
unsigned char ch_mask; /* available channel bitmask */
|
||||
unsigned char wp_mask; /* write-protect bitmask */
|
||||
unsigned char wide_mask; /* 16bit-nand bitmask */
|
||||
};
|
||||
|
||||
void txx9_ndfmc_init(unsigned long baseaddr,
|
||||
const struct txx9ndfmc_platform_data *plat_data);
|
||||
|
||||
#endif /* __TXX9_NDFMC_H */
|
@@ -3,7 +3,9 @@
|
||||
* Copyright (C) 2018 Exceet Electronics GmbH
|
||||
* Copyright (C) 2018 Bootlin
|
||||
*
|
||||
* Author: Boris Brezillon <boris.brezillon@bootlin.com>
|
||||
* Author:
|
||||
* Peter Pan <peterpandong@micron.com>
|
||||
* Boris Brezillon <boris.brezillon@bootlin.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_SPI_MEM_H
|
||||
|
Reference in New Issue
Block a user