restore lost packages from 0.2.3 + fix overwritten 0.2.4 files
- Restore 29 recipe symlinks (libdrm, qtbase, dbus, sddm, pipewire, etc.) - Restore 33 patches (KDE, libdrm, mesa, pipewire, sddm, wireplumber) - Restore 20+ local/scripts (audit, lint, test, build helpers) - Restore src/cook/scheduler.rs, status.rs, gnu-config/ - Restore scripts/patch-inclusion-gate.sh, run_mini1.sh, validate-collision-log.sh - Recover TLC source from HEAD (was overwritten by 0.2.3 checkout) - Recover 11 local/docs plans from HEAD (were overwritten) - Recover qt6-wayland-smoke symlink from HEAD - Fix MOTD: remove garbled ASCII art, use clean text - Update version: 0.2.0 -> 0.2.4 in os-release, motd, config - Reduce filesystem_size: 1536 -> 512 MiB - Add ABSOLUTE RULE to AGENTS.md: never delete/ignore packages - Reduce pcid scheme log verbosity: info -> debug
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* NAND family Bad Block Management (BBM) header file
|
||||
* - Bad Block Table (BBT) implementation
|
||||
*
|
||||
* Copyright © 2005 Samsung Electronics
|
||||
* Kyungmin Park <kyungmin.park@samsung.com>
|
||||
*
|
||||
* Copyright © 2000-2005
|
||||
* Thomas Gleixner <tglx@linuxtronix.de>
|
||||
*/
|
||||
#ifndef __LINUX_MTD_BBM_H
|
||||
#define __LINUX_MTD_BBM_H
|
||||
|
||||
/* The maximum number of NAND chips in an array */
|
||||
#define NAND_MAX_CHIPS 8
|
||||
|
||||
/**
|
||||
* struct nand_bbt_descr - bad block table descriptor
|
||||
* @options: options for this descriptor
|
||||
* @pages: the page(s) where we find the bbt, used with option BBT_ABSPAGE
|
||||
* when bbt is searched, then we store the found bbts pages here.
|
||||
* Its an array and supports up to 8 chips now
|
||||
* @offs: offset of the pattern in the oob area of the page
|
||||
* @veroffs: offset of the bbt version counter in the oob are of the page
|
||||
* @version: version read from the bbt page during scan
|
||||
* @len: length of the pattern, if 0 no pattern check is performed
|
||||
* @maxblocks: maximum number of blocks to search for a bbt. This number of
|
||||
* blocks is reserved at the end of the device where the tables are
|
||||
* written.
|
||||
* @reserved_block_code: if non-0, this pattern denotes a reserved (rather than
|
||||
* bad) block in the stored bbt
|
||||
* @pattern: pattern to identify bad block table or factory marked good /
|
||||
* bad blocks, can be NULL, if len = 0
|
||||
*
|
||||
* Descriptor for the bad block table marker and the descriptor for the
|
||||
* pattern which identifies good and bad blocks. The assumption is made
|
||||
* that the pattern and the version count are always located in the oob area
|
||||
* of the first block.
|
||||
*/
|
||||
struct nand_bbt_descr {
|
||||
int options;
|
||||
int pages[NAND_MAX_CHIPS];
|
||||
int offs;
|
||||
int veroffs;
|
||||
uint8_t version[NAND_MAX_CHIPS];
|
||||
int len;
|
||||
int maxblocks;
|
||||
int reserved_block_code;
|
||||
uint8_t *pattern;
|
||||
};
|
||||
|
||||
/* Options for the bad block table descriptors */
|
||||
|
||||
/* The number of bits used per block in the bbt on the device */
|
||||
#define NAND_BBT_NRBITS_MSK 0x0000000F
|
||||
#define NAND_BBT_1BIT 0x00000001
|
||||
#define NAND_BBT_2BIT 0x00000002
|
||||
#define NAND_BBT_4BIT 0x00000004
|
||||
#define NAND_BBT_8BIT 0x00000008
|
||||
/* The bad block table is in the last good block of the device */
|
||||
#define NAND_BBT_LASTBLOCK 0x00000010
|
||||
/* The bbt is at the given page, else we must scan for the bbt */
|
||||
#define NAND_BBT_ABSPAGE 0x00000020
|
||||
/* bbt is stored per chip on multichip devices */
|
||||
#define NAND_BBT_PERCHIP 0x00000080
|
||||
/* bbt has a version counter at offset veroffs */
|
||||
#define NAND_BBT_VERSION 0x00000100
|
||||
/* Create a bbt if none exists */
|
||||
#define NAND_BBT_CREATE 0x00000200
|
||||
/*
|
||||
* Create an empty BBT with no vendor information. Vendor's information may be
|
||||
* unavailable, for example, if the NAND controller has a different data and OOB
|
||||
* layout or if this information is already purged. Must be used in conjunction
|
||||
* with NAND_BBT_CREATE.
|
||||
*/
|
||||
#define NAND_BBT_CREATE_EMPTY 0x00000400
|
||||
/* Write bbt if neccecary */
|
||||
#define NAND_BBT_WRITE 0x00002000
|
||||
/* Read and write back block contents when writing bbt */
|
||||
#define NAND_BBT_SAVECONTENT 0x00004000
|
||||
|
||||
/*
|
||||
* Use a flash based bad block table. By default, OOB identifier is saved in
|
||||
* OOB area. This option is passed to the default bad block table function.
|
||||
*/
|
||||
#define NAND_BBT_USE_FLASH 0x00020000
|
||||
/*
|
||||
* Do not store flash based bad block table marker in the OOB area; store it
|
||||
* in-band.
|
||||
*/
|
||||
#define NAND_BBT_NO_OOB 0x00040000
|
||||
/*
|
||||
* Do not write new bad block markers to OOB; useful, e.g., when ECC covers
|
||||
* entire spare area. Must be used with NAND_BBT_USE_FLASH.
|
||||
*/
|
||||
#define NAND_BBT_NO_OOB_BBM 0x00080000
|
||||
|
||||
/*
|
||||
* Flag set by nand_create_default_bbt_descr(), marking that the nand_bbt_descr
|
||||
* was allocated dynamicaly and must be freed in nand_cleanup(). Has no meaning
|
||||
* in nand_chip.bbt_options.
|
||||
*/
|
||||
#define NAND_BBT_DYNAMICSTRUCT 0x80000000
|
||||
|
||||
/* The maximum number of blocks to scan for a bbt */
|
||||
#define NAND_BBT_SCAN_MAXBLOCKS 4
|
||||
|
||||
/*
|
||||
* Bad block scanning errors
|
||||
*/
|
||||
#define ONENAND_BBT_READ_ERROR 1
|
||||
#define ONENAND_BBT_READ_ECC_ERROR 2
|
||||
#define ONENAND_BBT_READ_FATAL_ERROR 4
|
||||
|
||||
/**
|
||||
* struct bbm_info - [GENERIC] Bad Block Table data structure
|
||||
* @bbt_erase_shift: [INTERN] number of address bits in a bbt entry
|
||||
* @options: options for this descriptor
|
||||
* @bbt: [INTERN] bad block table pointer
|
||||
* @isbad_bbt: function to determine if a block is bad
|
||||
* @badblock_pattern: [REPLACEABLE] bad block scan pattern used for
|
||||
* initial bad block scan
|
||||
* @priv: [OPTIONAL] pointer to private bbm date
|
||||
*/
|
||||
struct bbm_info {
|
||||
int bbt_erase_shift;
|
||||
int options;
|
||||
|
||||
uint8_t *bbt;
|
||||
|
||||
int (*isbad_bbt)(struct mtd_info *mtd, loff_t ofs, int allowbbt);
|
||||
|
||||
/* TODO Add more NAND specific fileds */
|
||||
struct nand_bbt_descr *badblock_pattern;
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/* OneNAND BBT interface */
|
||||
extern int onenand_default_bbt(struct mtd_info *mtd);
|
||||
|
||||
#endif /* __LINUX_MTD_BBM_H */
|
||||
@@ -0,0 +1,92 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright © 2003-2010 David Woodhouse <dwmw2@infradead.org>
|
||||
*/
|
||||
|
||||
#ifndef __MTD_TRANS_H__
|
||||
#define __MTD_TRANS_H__
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
struct hd_geometry;
|
||||
struct mtd_info;
|
||||
struct mtd_blktrans_ops;
|
||||
struct file;
|
||||
struct inode;
|
||||
|
||||
struct mtd_blktrans_dev {
|
||||
struct mtd_blktrans_ops *tr;
|
||||
struct list_head list;
|
||||
struct mtd_info *mtd;
|
||||
struct mutex lock;
|
||||
int devnum;
|
||||
bool bg_stop;
|
||||
unsigned long size;
|
||||
int readonly;
|
||||
int open;
|
||||
struct kref ref;
|
||||
struct gendisk *disk;
|
||||
struct attribute_group *disk_attributes;
|
||||
struct request_queue *rq;
|
||||
struct list_head rq_list;
|
||||
struct blk_mq_tag_set *tag_set;
|
||||
spinlock_t queue_lock;
|
||||
void *priv;
|
||||
bool writable;
|
||||
};
|
||||
|
||||
struct mtd_blktrans_ops {
|
||||
char *name;
|
||||
int major;
|
||||
int part_bits;
|
||||
int blksize;
|
||||
int blkshift;
|
||||
|
||||
/* Access functions */
|
||||
int (*readsect)(struct mtd_blktrans_dev *dev,
|
||||
unsigned long block, char *buffer);
|
||||
int (*writesect)(struct mtd_blktrans_dev *dev,
|
||||
unsigned long block, char *buffer);
|
||||
int (*discard)(struct mtd_blktrans_dev *dev,
|
||||
unsigned long block, unsigned nr_blocks);
|
||||
void (*background)(struct mtd_blktrans_dev *dev);
|
||||
|
||||
/* Block layer ioctls */
|
||||
int (*getgeo)(struct mtd_blktrans_dev *dev, struct hd_geometry *geo);
|
||||
int (*flush)(struct mtd_blktrans_dev *dev);
|
||||
|
||||
/* Called with mtd_table_mutex held; no race with add/remove */
|
||||
int (*open)(struct mtd_blktrans_dev *dev);
|
||||
void (*release)(struct mtd_blktrans_dev *dev);
|
||||
|
||||
/* Called on {de,}registration and on subsequent addition/removal
|
||||
of devices, with mtd_table_mutex held. */
|
||||
void (*add_mtd)(struct mtd_blktrans_ops *tr, struct mtd_info *mtd);
|
||||
void (*remove_dev)(struct mtd_blktrans_dev *dev);
|
||||
|
||||
struct list_head devs;
|
||||
struct list_head list;
|
||||
struct module *owner;
|
||||
};
|
||||
|
||||
extern int register_mtd_blktrans(struct mtd_blktrans_ops *tr);
|
||||
extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr);
|
||||
extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
|
||||
extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
|
||||
extern int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev);
|
||||
|
||||
/**
|
||||
* module_mtd_blktrans() - Helper macro for registering a mtd blktrans driver
|
||||
* @__mtd_blktrans: mtd_blktrans_ops struct
|
||||
*
|
||||
* Helper macro for mtd blktrans drivers which do not do anything special in
|
||||
* module init/exit. This eliminates a lot of boilerplate. Each module may only
|
||||
* use this macro once, and calling it replaces module_init() and module_exit()
|
||||
*/
|
||||
#define module_mtd_blktrans(__mtd_blktrans) \
|
||||
module_driver(__mtd_blktrans, register_mtd_blktrans, \
|
||||
deregister_mtd_blktrans)
|
||||
|
||||
#endif /* __MTD_TRANS_H__ */
|
||||
@@ -0,0 +1,387 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org> et al.
|
||||
*/
|
||||
|
||||
#ifndef __MTD_CFI_H__
|
||||
#define __MTD_CFI_H__
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mtd/flashchip.h>
|
||||
#include <linux/mtd/map.h>
|
||||
#include <linux/mtd/cfi_endian.h>
|
||||
#include <linux/mtd/xip.h>
|
||||
|
||||
#ifdef CONFIG_MTD_CFI_I1
|
||||
#define cfi_interleave(cfi) 1
|
||||
#define cfi_interleave_is_1(cfi) (cfi_interleave(cfi) == 1)
|
||||
#else
|
||||
#define cfi_interleave_is_1(cfi) (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_CFI_I2
|
||||
# ifdef cfi_interleave
|
||||
# undef cfi_interleave
|
||||
# define cfi_interleave(cfi) ((cfi)->interleave)
|
||||
# else
|
||||
# define cfi_interleave(cfi) 2
|
||||
# endif
|
||||
#define cfi_interleave_is_2(cfi) (cfi_interleave(cfi) == 2)
|
||||
#else
|
||||
#define cfi_interleave_is_2(cfi) (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_CFI_I4
|
||||
# ifdef cfi_interleave
|
||||
# undef cfi_interleave
|
||||
# define cfi_interleave(cfi) ((cfi)->interleave)
|
||||
# else
|
||||
# define cfi_interleave(cfi) 4
|
||||
# endif
|
||||
#define cfi_interleave_is_4(cfi) (cfi_interleave(cfi) == 4)
|
||||
#else
|
||||
#define cfi_interleave_is_4(cfi) (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_CFI_I8
|
||||
# ifdef cfi_interleave
|
||||
# undef cfi_interleave
|
||||
# define cfi_interleave(cfi) ((cfi)->interleave)
|
||||
# else
|
||||
# define cfi_interleave(cfi) 8
|
||||
# endif
|
||||
#define cfi_interleave_is_8(cfi) (cfi_interleave(cfi) == 8)
|
||||
#else
|
||||
#define cfi_interleave_is_8(cfi) (0)
|
||||
#endif
|
||||
|
||||
#ifndef cfi_interleave
|
||||
#warning No CONFIG_MTD_CFI_Ix selected. No NOR chip support can work.
|
||||
static inline int cfi_interleave(void *cfi)
|
||||
{
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int cfi_interleave_supported(int i)
|
||||
{
|
||||
switch (i) {
|
||||
#ifdef CONFIG_MTD_CFI_I1
|
||||
case 1:
|
||||
#endif
|
||||
#ifdef CONFIG_MTD_CFI_I2
|
||||
case 2:
|
||||
#endif
|
||||
#ifdef CONFIG_MTD_CFI_I4
|
||||
case 4:
|
||||
#endif
|
||||
#ifdef CONFIG_MTD_CFI_I8
|
||||
case 8:
|
||||
#endif
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* NB: these values must represents the number of bytes needed to meet the
|
||||
* device type (x8, x16, x32). Eg. a 32 bit device is 4 x 8 bytes.
|
||||
* These numbers are used in calculations.
|
||||
*/
|
||||
#define CFI_DEVICETYPE_X8 (8 / 8)
|
||||
#define CFI_DEVICETYPE_X16 (16 / 8)
|
||||
#define CFI_DEVICETYPE_X32 (32 / 8)
|
||||
#define CFI_DEVICETYPE_X64 (64 / 8)
|
||||
|
||||
|
||||
/* Device Interface Code Assignments from the "Common Flash Memory Interface
|
||||
* Publication 100" dated December 1, 2001.
|
||||
*/
|
||||
#define CFI_INTERFACE_X8_ASYNC 0x0000
|
||||
#define CFI_INTERFACE_X16_ASYNC 0x0001
|
||||
#define CFI_INTERFACE_X8_BY_X16_ASYNC 0x0002
|
||||
#define CFI_INTERFACE_X32_ASYNC 0x0003
|
||||
#define CFI_INTERFACE_X16_BY_X32_ASYNC 0x0005
|
||||
#define CFI_INTERFACE_NOT_ALLOWED 0xffff
|
||||
|
||||
|
||||
/* NB: We keep these structures in memory in HOST byteorder, except
|
||||
* where individually noted.
|
||||
*/
|
||||
|
||||
/* Basic Query Structure */
|
||||
struct cfi_ident {
|
||||
uint8_t qry[3];
|
||||
uint16_t P_ID;
|
||||
uint16_t P_ADR;
|
||||
uint16_t A_ID;
|
||||
uint16_t A_ADR;
|
||||
uint8_t VccMin;
|
||||
uint8_t VccMax;
|
||||
uint8_t VppMin;
|
||||
uint8_t VppMax;
|
||||
uint8_t WordWriteTimeoutTyp;
|
||||
uint8_t BufWriteTimeoutTyp;
|
||||
uint8_t BlockEraseTimeoutTyp;
|
||||
uint8_t ChipEraseTimeoutTyp;
|
||||
uint8_t WordWriteTimeoutMax;
|
||||
uint8_t BufWriteTimeoutMax;
|
||||
uint8_t BlockEraseTimeoutMax;
|
||||
uint8_t ChipEraseTimeoutMax;
|
||||
uint8_t DevSize;
|
||||
uint16_t InterfaceDesc;
|
||||
uint16_t MaxBufWriteSize;
|
||||
uint8_t NumEraseRegions;
|
||||
uint32_t EraseRegionInfo[]; /* Not host ordered */
|
||||
} __packed;
|
||||
|
||||
/* Extended Query Structure for both PRI and ALT */
|
||||
|
||||
struct cfi_extquery {
|
||||
uint8_t pri[3];
|
||||
uint8_t MajorVersion;
|
||||
uint8_t MinorVersion;
|
||||
} __packed;
|
||||
|
||||
/* Vendor-Specific PRI for Intel/Sharp Extended Command Set (0x0001) */
|
||||
|
||||
struct cfi_pri_intelext {
|
||||
uint8_t pri[3];
|
||||
uint8_t MajorVersion;
|
||||
uint8_t MinorVersion;
|
||||
uint32_t FeatureSupport; /* if bit 31 is set then an additional uint32_t feature
|
||||
block follows - FIXME - not currently supported */
|
||||
uint8_t SuspendCmdSupport;
|
||||
uint16_t BlkStatusRegMask;
|
||||
uint8_t VccOptimal;
|
||||
uint8_t VppOptimal;
|
||||
uint8_t NumProtectionFields;
|
||||
uint16_t ProtRegAddr;
|
||||
uint8_t FactProtRegSize;
|
||||
uint8_t UserProtRegSize;
|
||||
uint8_t extra[];
|
||||
} __packed;
|
||||
|
||||
struct cfi_intelext_otpinfo {
|
||||
uint32_t ProtRegAddr;
|
||||
uint16_t FactGroups;
|
||||
uint8_t FactProtRegSize;
|
||||
uint16_t UserGroups;
|
||||
uint8_t UserProtRegSize;
|
||||
} __packed;
|
||||
|
||||
struct cfi_intelext_blockinfo {
|
||||
uint16_t NumIdentBlocks;
|
||||
uint16_t BlockSize;
|
||||
uint16_t MinBlockEraseCycles;
|
||||
uint8_t BitsPerCell;
|
||||
uint8_t BlockCap;
|
||||
} __packed;
|
||||
|
||||
struct cfi_intelext_regioninfo {
|
||||
uint16_t NumIdentPartitions;
|
||||
uint8_t NumOpAllowed;
|
||||
uint8_t NumOpAllowedSimProgMode;
|
||||
uint8_t NumOpAllowedSimEraMode;
|
||||
uint8_t NumBlockTypes;
|
||||
struct cfi_intelext_blockinfo BlockTypes[1];
|
||||
} __packed;
|
||||
|
||||
struct cfi_intelext_programming_regioninfo {
|
||||
uint8_t ProgRegShift;
|
||||
uint8_t Reserved1;
|
||||
uint8_t ControlValid;
|
||||
uint8_t Reserved2;
|
||||
uint8_t ControlInvalid;
|
||||
uint8_t Reserved3;
|
||||
} __packed;
|
||||
|
||||
/* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */
|
||||
|
||||
struct cfi_pri_amdstd {
|
||||
uint8_t pri[3];
|
||||
uint8_t MajorVersion;
|
||||
uint8_t MinorVersion;
|
||||
uint8_t SiliconRevision; /* bits 1-0: Address Sensitive Unlock */
|
||||
uint8_t EraseSuspend;
|
||||
uint8_t BlkProt;
|
||||
uint8_t TmpBlkUnprotect;
|
||||
uint8_t BlkProtUnprot;
|
||||
uint8_t SimultaneousOps;
|
||||
uint8_t BurstMode;
|
||||
uint8_t PageMode;
|
||||
uint8_t VppMin;
|
||||
uint8_t VppMax;
|
||||
uint8_t TopBottom;
|
||||
/* Below field are added from version 1.5 */
|
||||
uint8_t ProgramSuspend;
|
||||
uint8_t UnlockBypass;
|
||||
uint8_t SecureSiliconSector;
|
||||
uint8_t SoftwareFeatures;
|
||||
#define CFI_POLL_STATUS_REG BIT(0)
|
||||
#define CFI_POLL_DQ BIT(1)
|
||||
} __packed;
|
||||
|
||||
/* Vendor-Specific PRI for Atmel chips (command set 0x0002) */
|
||||
|
||||
struct cfi_pri_atmel {
|
||||
uint8_t pri[3];
|
||||
uint8_t MajorVersion;
|
||||
uint8_t MinorVersion;
|
||||
uint8_t Features;
|
||||
uint8_t BottomBoot;
|
||||
uint8_t BurstMode;
|
||||
uint8_t PageMode;
|
||||
} __packed;
|
||||
|
||||
struct cfi_pri_query {
|
||||
uint8_t NumFields;
|
||||
uint32_t ProtField[1]; /* Not host ordered */
|
||||
} __packed;
|
||||
|
||||
struct cfi_bri_query {
|
||||
uint8_t PageModeReadCap;
|
||||
uint8_t NumFields;
|
||||
uint32_t ConfField[1]; /* Not host ordered */
|
||||
} __packed;
|
||||
|
||||
#define P_ID_NONE 0x0000
|
||||
#define P_ID_INTEL_EXT 0x0001
|
||||
#define P_ID_AMD_STD 0x0002
|
||||
#define P_ID_INTEL_STD 0x0003
|
||||
#define P_ID_AMD_EXT 0x0004
|
||||
#define P_ID_WINBOND 0x0006
|
||||
#define P_ID_ST_ADV 0x0020
|
||||
#define P_ID_MITSUBISHI_STD 0x0100
|
||||
#define P_ID_MITSUBISHI_EXT 0x0101
|
||||
#define P_ID_SST_PAGE 0x0102
|
||||
#define P_ID_SST_OLD 0x0701
|
||||
#define P_ID_INTEL_PERFORMANCE 0x0200
|
||||
#define P_ID_INTEL_DATA 0x0210
|
||||
#define P_ID_RESERVED 0xffff
|
||||
|
||||
|
||||
#define CFI_MODE_CFI 1
|
||||
#define CFI_MODE_JEDEC 0
|
||||
|
||||
struct cfi_private {
|
||||
uint16_t cmdset;
|
||||
void *cmdset_priv;
|
||||
int interleave;
|
||||
int device_type;
|
||||
int cfi_mode; /* Are we a JEDEC device pretending to be CFI? */
|
||||
int addr_unlock1;
|
||||
int addr_unlock2;
|
||||
struct mtd_info *(*cmdset_setup)(struct map_info *);
|
||||
struct cfi_ident *cfiq; /* For now only one. We insist that all devs
|
||||
must be of the same type. */
|
||||
int mfr, id;
|
||||
int numchips;
|
||||
map_word sector_erase_cmd;
|
||||
unsigned long chipshift; /* Because they're of the same type */
|
||||
const char *im_name; /* inter_module name for cmdset_setup */
|
||||
unsigned long quirks;
|
||||
struct flchip chips[] __counted_by(numchips); /* per-chip data structure for each chip */
|
||||
};
|
||||
|
||||
uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs,
|
||||
struct map_info *map, struct cfi_private *cfi);
|
||||
|
||||
map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi);
|
||||
#define CMD(x) cfi_build_cmd((x), map, cfi)
|
||||
|
||||
unsigned long cfi_merge_status(map_word val, struct map_info *map,
|
||||
struct cfi_private *cfi);
|
||||
#define MERGESTATUS(x) cfi_merge_status((x), map, cfi)
|
||||
|
||||
uint32_t cfi_send_gen_cmd(u_char cmd, uint32_t cmd_addr, uint32_t base,
|
||||
struct map_info *map, struct cfi_private *cfi,
|
||||
int type, map_word *prev_val);
|
||||
|
||||
static inline uint8_t cfi_read_query(struct map_info *map, uint32_t addr)
|
||||
{
|
||||
map_word val = map_read(map, addr);
|
||||
|
||||
if (map_bankwidth_is_1(map))
|
||||
return val.x[0];
|
||||
if (map_bankwidth_is_2(map))
|
||||
return cfi16_to_cpu(map, val.x[0]);
|
||||
/*
|
||||
* No point in a 64-bit byteswap since that would just be
|
||||
* swapping the responses from different chips, and we are
|
||||
* only interested in one chip (a representative sample)
|
||||
*/
|
||||
return cfi32_to_cpu(map, val.x[0]);
|
||||
}
|
||||
|
||||
static inline uint16_t cfi_read_query16(struct map_info *map, uint32_t addr)
|
||||
{
|
||||
map_word val = map_read(map, addr);
|
||||
|
||||
if (map_bankwidth_is_1(map))
|
||||
return val.x[0] & 0xff;
|
||||
if (map_bankwidth_is_2(map))
|
||||
return cfi16_to_cpu(map, val.x[0]);
|
||||
/*
|
||||
* No point in a 64-bit byteswap since that would just be
|
||||
* swapping the responses from different chips, and we are
|
||||
* only interested in one chip (a representative sample)
|
||||
*/
|
||||
return cfi32_to_cpu(map, val.x[0]);
|
||||
}
|
||||
|
||||
void cfi_udelay(int us);
|
||||
|
||||
int __xipram cfi_qry_present(struct map_info *map, __u32 base,
|
||||
struct cfi_private *cfi);
|
||||
int __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map,
|
||||
struct cfi_private *cfi);
|
||||
void __xipram cfi_qry_mode_off(uint32_t base, struct map_info *map,
|
||||
struct cfi_private *cfi);
|
||||
|
||||
struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size,
|
||||
const char* name);
|
||||
struct cfi_fixup {
|
||||
uint16_t mfr;
|
||||
uint16_t id;
|
||||
void (*fixup)(struct mtd_info *mtd);
|
||||
};
|
||||
|
||||
#define CFI_MFR_ANY 0xFFFF
|
||||
#define CFI_ID_ANY 0xFFFF
|
||||
#define CFI_MFR_CONTINUATION 0x007F
|
||||
|
||||
#define CFI_MFR_AMD 0x0001
|
||||
#define CFI_MFR_AMIC 0x0037
|
||||
#define CFI_MFR_ATMEL 0x001F
|
||||
#define CFI_MFR_EON 0x001C
|
||||
#define CFI_MFR_FUJITSU 0x0004
|
||||
#define CFI_MFR_HYUNDAI 0x00AD
|
||||
#define CFI_MFR_INTEL 0x0089
|
||||
#define CFI_MFR_MACRONIX 0x00C2
|
||||
#define CFI_MFR_NEC 0x0010
|
||||
#define CFI_MFR_PMC 0x009D
|
||||
#define CFI_MFR_SAMSUNG 0x00EC
|
||||
#define CFI_MFR_SHARP 0x00B0
|
||||
#define CFI_MFR_SST 0x00BF
|
||||
#define CFI_MFR_ST 0x0020 /* STMicroelectronics */
|
||||
#define CFI_MFR_MICRON 0x002C /* Micron */
|
||||
#define CFI_MFR_TOSHIBA 0x0098
|
||||
#define CFI_MFR_WINBOND 0x00DA
|
||||
|
||||
void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup* fixups);
|
||||
|
||||
typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip,
|
||||
unsigned long adr, int len, void *thunk);
|
||||
|
||||
int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
|
||||
loff_t ofs, size_t len, void *thunk);
|
||||
|
||||
|
||||
#endif /* __MTD_CFI_H__ */
|
||||
@@ -0,0 +1,39 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright © 2001-2010 David Woodhouse <dwmw2@infradead.org>
|
||||
*/
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#define CFI_HOST_ENDIAN 1
|
||||
#define CFI_LITTLE_ENDIAN 2
|
||||
#define CFI_BIG_ENDIAN 3
|
||||
|
||||
#if !defined(CONFIG_MTD_CFI_ADV_OPTIONS) || defined(CONFIG_MTD_CFI_NOSWAP)
|
||||
#define CFI_DEFAULT_ENDIAN CFI_HOST_ENDIAN
|
||||
#elif defined(CONFIG_MTD_CFI_LE_BYTE_SWAP)
|
||||
#define CFI_DEFAULT_ENDIAN CFI_LITTLE_ENDIAN
|
||||
#elif defined(CONFIG_MTD_CFI_BE_BYTE_SWAP)
|
||||
#define CFI_DEFAULT_ENDIAN CFI_BIG_ENDIAN
|
||||
#else
|
||||
#error No CFI endianness defined
|
||||
#endif
|
||||
|
||||
#define cfi_default(s) ((s)?:CFI_DEFAULT_ENDIAN)
|
||||
#define cfi_be(s) (cfi_default(s) == CFI_BIG_ENDIAN)
|
||||
#define cfi_le(s) (cfi_default(s) == CFI_LITTLE_ENDIAN)
|
||||
#define cfi_host(s) (cfi_default(s) == CFI_HOST_ENDIAN)
|
||||
|
||||
#define cpu_to_cfi8(map, x) (x)
|
||||
#define cfi8_to_cpu(map, x) (x)
|
||||
#define cpu_to_cfi16(map, x) _cpu_to_cfi(16, (map)->swap, (x))
|
||||
#define cpu_to_cfi32(map, x) _cpu_to_cfi(32, (map)->swap, (x))
|
||||
#define cpu_to_cfi64(map, x) _cpu_to_cfi(64, (map)->swap, (x))
|
||||
#define cfi16_to_cpu(map, x) _cfi_to_cpu(16, (map)->swap, (x))
|
||||
#define cfi32_to_cpu(map, x) _cfi_to_cpu(32, (map)->swap, (x))
|
||||
#define cfi64_to_cpu(map, x) _cfi_to_cpu(64, (map)->swap, (x))
|
||||
|
||||
#define _cpu_to_cfi(w, s, x) (cfi_host(s)?(x):_swap_to_cfi(w, s, x))
|
||||
#define _cfi_to_cpu(w, s, x) (cfi_host(s)?(x):_swap_to_cpu(w, s, x))
|
||||
#define _swap_to_cfi(w, s, x) (cfi_be(s)?cpu_to_be##w(x):cpu_to_le##w(x))
|
||||
#define _swap_to_cpu(w, s, x) (cfi_be(s)?be##w##_to_cpu(x):le##w##_to_cpu(x))
|
||||
@@ -0,0 +1,81 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* MTD device concatenation layer definitions
|
||||
*
|
||||
* Copyright © 2002 Robert Kaiser <rkaiser@sysgo.de>
|
||||
*/
|
||||
|
||||
#ifndef MTD_CONCAT_H
|
||||
#define MTD_CONCAT_H
|
||||
|
||||
|
||||
/*
|
||||
* Our storage structure:
|
||||
* Subdev points to an array of pointers to struct mtd_info objects
|
||||
* which is allocated along with this structure
|
||||
*
|
||||
*/
|
||||
struct mtd_concat {
|
||||
struct mtd_info mtd;
|
||||
int num_subdev;
|
||||
struct mtd_info *subdev[];
|
||||
};
|
||||
|
||||
struct mtd_info *mtd_concat_create(
|
||||
struct mtd_info *subdev[], /* subdevices to concatenate */
|
||||
int num_devs, /* number of subdevices */
|
||||
const char *name); /* name for the new device */
|
||||
|
||||
void mtd_concat_destroy(struct mtd_info *mtd);
|
||||
|
||||
/**
|
||||
* mtd_virt_concat_node_create - Create a component for concatenation
|
||||
*
|
||||
* Returns a positive number representing the no. of devices found for
|
||||
* concatenation, or a negative error code.
|
||||
*
|
||||
* List all the devices for concatenations found in DT and create a
|
||||
* component for concatenation.
|
||||
*/
|
||||
int mtd_virt_concat_node_create(void);
|
||||
|
||||
/**
|
||||
* mtd_virt_concat_add - add mtd_info object to the list of subdevices for concatenation
|
||||
* @mtd: pointer to new MTD device info structure
|
||||
*
|
||||
* Returns true if the mtd_info object is added successfully else returns false.
|
||||
*
|
||||
* The mtd_info object is added to the list of subdevices for concatenation.
|
||||
* It returns true if a match is found, and false if all subdevices have
|
||||
* already been added or if the mtd_info object does not match any of the
|
||||
* intended MTD devices.
|
||||
*/
|
||||
bool mtd_virt_concat_add(struct mtd_info *mtd);
|
||||
|
||||
/**
|
||||
* mtd_virt_concat_create_join - Create and register the concatenated MTD device
|
||||
*
|
||||
* Returns 0 on succes, or a negative error code.
|
||||
*
|
||||
* Creates and registers the concatenated MTD device
|
||||
*/
|
||||
int mtd_virt_concat_create_join(void);
|
||||
|
||||
/**
|
||||
* mtd_virt_concat_destroy - Remove the concat that includes a specific mtd device
|
||||
* as one of its components.
|
||||
* @mtd: pointer to MTD device info structure.
|
||||
*
|
||||
* Returns 0 on succes, or a negative error code.
|
||||
*
|
||||
* If the mtd_info object is part of a concatenated device, all other MTD devices
|
||||
* within that concat are registered individually. The concatenated device is then
|
||||
* removed, along with its concatenation component.
|
||||
*
|
||||
*/
|
||||
int mtd_virt_concat_destroy(struct mtd_info *mtd);
|
||||
|
||||
void mtd_virt_concat_destroy_joins(void);
|
||||
void mtd_virt_concat_destroy_items(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,206 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Linux driver for Disk-On-Chip devices
|
||||
*
|
||||
* Copyright © 1999 Machine Vision Holdings, Inc.
|
||||
* Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org>
|
||||
* Copyright © 2002-2003 Greg Ungerer <gerg@snapgear.com>
|
||||
* Copyright © 2002-2003 SnapGear Inc
|
||||
*/
|
||||
|
||||
#ifndef __MTD_DOC2000_H__
|
||||
#define __MTD_DOC2000_H__
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#define DoC_Sig1 0
|
||||
#define DoC_Sig2 1
|
||||
|
||||
#define DoC_ChipID 0x1000
|
||||
#define DoC_DOCStatus 0x1001
|
||||
#define DoC_DOCControl 0x1002
|
||||
#define DoC_FloorSelect 0x1003
|
||||
#define DoC_CDSNControl 0x1004
|
||||
#define DoC_CDSNDeviceSelect 0x1005
|
||||
#define DoC_ECCConf 0x1006
|
||||
#define DoC_2k_ECCStatus 0x1007
|
||||
|
||||
#define DoC_CDSNSlowIO 0x100d
|
||||
#define DoC_ECCSyndrome0 0x1010
|
||||
#define DoC_ECCSyndrome1 0x1011
|
||||
#define DoC_ECCSyndrome2 0x1012
|
||||
#define DoC_ECCSyndrome3 0x1013
|
||||
#define DoC_ECCSyndrome4 0x1014
|
||||
#define DoC_ECCSyndrome5 0x1015
|
||||
#define DoC_AliasResolution 0x101b
|
||||
#define DoC_ConfigInput 0x101c
|
||||
#define DoC_ReadPipeInit 0x101d
|
||||
#define DoC_WritePipeTerm 0x101e
|
||||
#define DoC_LastDataRead 0x101f
|
||||
#define DoC_NOP 0x1020
|
||||
|
||||
#define DoC_Mil_CDSN_IO 0x0800
|
||||
#define DoC_2k_CDSN_IO 0x1800
|
||||
|
||||
#define DoC_Mplus_NOP 0x1002
|
||||
#define DoC_Mplus_AliasResolution 0x1004
|
||||
#define DoC_Mplus_DOCControl 0x1006
|
||||
#define DoC_Mplus_AccessStatus 0x1008
|
||||
#define DoC_Mplus_DeviceSelect 0x1008
|
||||
#define DoC_Mplus_Configuration 0x100a
|
||||
#define DoC_Mplus_OutputControl 0x100c
|
||||
#define DoC_Mplus_FlashControl 0x1020
|
||||
#define DoC_Mplus_FlashSelect 0x1022
|
||||
#define DoC_Mplus_FlashCmd 0x1024
|
||||
#define DoC_Mplus_FlashAddress 0x1026
|
||||
#define DoC_Mplus_FlashData0 0x1028
|
||||
#define DoC_Mplus_FlashData1 0x1029
|
||||
#define DoC_Mplus_ReadPipeInit 0x102a
|
||||
#define DoC_Mplus_LastDataRead 0x102c
|
||||
#define DoC_Mplus_LastDataRead1 0x102d
|
||||
#define DoC_Mplus_WritePipeTerm 0x102e
|
||||
#define DoC_Mplus_ECCSyndrome0 0x1040
|
||||
#define DoC_Mplus_ECCSyndrome1 0x1041
|
||||
#define DoC_Mplus_ECCSyndrome2 0x1042
|
||||
#define DoC_Mplus_ECCSyndrome3 0x1043
|
||||
#define DoC_Mplus_ECCSyndrome4 0x1044
|
||||
#define DoC_Mplus_ECCSyndrome5 0x1045
|
||||
#define DoC_Mplus_ECCConf 0x1046
|
||||
#define DoC_Mplus_Toggle 0x1046
|
||||
#define DoC_Mplus_DownloadStatus 0x1074
|
||||
#define DoC_Mplus_CtrlConfirm 0x1076
|
||||
#define DoC_Mplus_Power 0x1fff
|
||||
|
||||
/* How to access the device?
|
||||
* On ARM, it'll be mmap'd directly with 32-bit wide accesses.
|
||||
* On PPC, it's mmap'd and 16-bit wide.
|
||||
* Others use readb/writeb
|
||||
*/
|
||||
#if defined(__arm__)
|
||||
static inline u8 ReadDOC_(u32 __iomem *addr, unsigned long reg)
|
||||
{
|
||||
return __raw_readl(addr + reg);
|
||||
}
|
||||
static inline void WriteDOC_(u8 data, u32 __iomem *addr, unsigned long reg)
|
||||
{
|
||||
__raw_writel(data, addr + reg);
|
||||
wmb();
|
||||
}
|
||||
#define DOC_IOREMAP_LEN 0x8000
|
||||
#elif defined(__ppc__)
|
||||
static inline u8 ReadDOC_(u16 __iomem *addr, unsigned long reg)
|
||||
{
|
||||
return __raw_readw(addr + reg);
|
||||
}
|
||||
static inline void WriteDOC_(u8 data, u16 __iomem *addr, unsigned long reg)
|
||||
{
|
||||
__raw_writew(data, addr + reg);
|
||||
wmb();
|
||||
}
|
||||
#define DOC_IOREMAP_LEN 0x4000
|
||||
#else
|
||||
#define ReadDOC_(adr, reg) readb((void __iomem *)(adr) + (reg))
|
||||
#define WriteDOC_(d, adr, reg) writeb(d, (void __iomem *)(adr) + (reg))
|
||||
#define DOC_IOREMAP_LEN 0x2000
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#define USE_MEMCPY
|
||||
#endif
|
||||
|
||||
/* These are provided to directly use the DoC_xxx defines */
|
||||
#define ReadDOC(adr, reg) ReadDOC_(adr,DoC_##reg)
|
||||
#define WriteDOC(d, adr, reg) WriteDOC_(d,adr,DoC_##reg)
|
||||
|
||||
#define DOC_MODE_RESET 0
|
||||
#define DOC_MODE_NORMAL 1
|
||||
#define DOC_MODE_RESERVED1 2
|
||||
#define DOC_MODE_RESERVED2 3
|
||||
|
||||
#define DOC_MODE_CLR_ERR 0x80
|
||||
#define DOC_MODE_RST_LAT 0x10
|
||||
#define DOC_MODE_BDECT 0x08
|
||||
#define DOC_MODE_MDWREN 0x04
|
||||
|
||||
#define DOC_ChipID_Doc2k 0x20
|
||||
#define DOC_ChipID_Doc2kTSOP 0x21 /* internal number for MTD */
|
||||
#define DOC_ChipID_DocMil 0x30
|
||||
#define DOC_ChipID_DocMilPlus32 0x40
|
||||
#define DOC_ChipID_DocMilPlus16 0x41
|
||||
|
||||
#define CDSN_CTRL_FR_B 0x80
|
||||
#define CDSN_CTRL_FR_B0 0x40
|
||||
#define CDSN_CTRL_FR_B1 0x80
|
||||
|
||||
#define CDSN_CTRL_ECC_IO 0x20
|
||||
#define CDSN_CTRL_FLASH_IO 0x10
|
||||
#define CDSN_CTRL_WP 0x08
|
||||
#define CDSN_CTRL_ALE 0x04
|
||||
#define CDSN_CTRL_CLE 0x02
|
||||
#define CDSN_CTRL_CE 0x01
|
||||
|
||||
#define DOC_ECC_RESET 0
|
||||
#define DOC_ECC_ERROR 0x80
|
||||
#define DOC_ECC_RW 0x20
|
||||
#define DOC_ECC__EN 0x08
|
||||
#define DOC_TOGGLE_BIT 0x04
|
||||
#define DOC_ECC_RESV 0x02
|
||||
#define DOC_ECC_IGNORE 0x01
|
||||
|
||||
#define DOC_FLASH_CE 0x80
|
||||
#define DOC_FLASH_WP 0x40
|
||||
#define DOC_FLASH_BANK 0x02
|
||||
|
||||
/* We have to also set the reserved bit 1 for enable */
|
||||
#define DOC_ECC_EN (DOC_ECC__EN | DOC_ECC_RESV)
|
||||
#define DOC_ECC_DIS (DOC_ECC_RESV)
|
||||
|
||||
struct Nand {
|
||||
char floor, chip;
|
||||
unsigned long curadr;
|
||||
unsigned char curmode;
|
||||
/* Also some erase/write/pipeline info when we get that far */
|
||||
};
|
||||
|
||||
#define MAX_FLOORS 4
|
||||
#define MAX_CHIPS 4
|
||||
|
||||
#define MAX_FLOORS_MIL 1
|
||||
#define MAX_CHIPS_MIL 1
|
||||
|
||||
#define MAX_FLOORS_MPLUS 2
|
||||
#define MAX_CHIPS_MPLUS 1
|
||||
|
||||
#define ADDR_COLUMN 1
|
||||
#define ADDR_PAGE 2
|
||||
#define ADDR_COLUMN_PAGE 3
|
||||
|
||||
struct DiskOnChip {
|
||||
unsigned long physadr;
|
||||
void __iomem *virtadr;
|
||||
unsigned long totlen;
|
||||
unsigned char ChipID; /* Type of DiskOnChip */
|
||||
int ioreg;
|
||||
|
||||
unsigned long mfr; /* Flash IDs - only one type of flash per device */
|
||||
unsigned long id;
|
||||
int chipshift;
|
||||
char page256;
|
||||
char pageadrlen;
|
||||
char interleave; /* Internal interleaving - Millennium Plus style */
|
||||
unsigned long erasesize;
|
||||
|
||||
int curfloor;
|
||||
int curchip;
|
||||
|
||||
int numchips;
|
||||
struct Nand *chips;
|
||||
struct mtd_info *nextdoc;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
int doc_decode_ecc(unsigned char sector[512], unsigned char ecc1[6]);
|
||||
|
||||
#endif /* __MTD_DOC2000_H__ */
|
||||
@@ -0,0 +1,100 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright © 2000 Red Hat UK Limited
|
||||
* Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org>
|
||||
*/
|
||||
|
||||
#ifndef __MTD_FLASHCHIP_H__
|
||||
#define __MTD_FLASHCHIP_H__
|
||||
|
||||
/* For spinlocks. sched.h includes spinlock.h from whichever directory it
|
||||
* happens to be in - so we don't have to care whether we're on 2.2, which
|
||||
* has asm/spinlock.h, or 2.4, which has linux/spinlock.h
|
||||
*/
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
typedef enum {
|
||||
FL_READY,
|
||||
FL_STATUS,
|
||||
FL_CFI_QUERY,
|
||||
FL_JEDEC_QUERY,
|
||||
FL_ERASING,
|
||||
FL_ERASE_SUSPENDING,
|
||||
FL_ERASE_SUSPENDED,
|
||||
FL_WRITING,
|
||||
FL_WRITING_TO_BUFFER,
|
||||
FL_OTP_WRITE,
|
||||
FL_WRITE_SUSPENDING,
|
||||
FL_WRITE_SUSPENDED,
|
||||
FL_PM_SUSPENDED,
|
||||
FL_SYNCING,
|
||||
FL_UNLOADING,
|
||||
FL_LOCKING,
|
||||
FL_UNLOCKING,
|
||||
FL_POINT,
|
||||
FL_XIP_WHILE_ERASING,
|
||||
FL_XIP_WHILE_WRITING,
|
||||
FL_SHUTDOWN,
|
||||
/* These 2 come from nand_state_t, which has been unified here */
|
||||
FL_READING,
|
||||
FL_CACHEDPRG,
|
||||
/* These 4 come from onenand_state_t, which has been unified here */
|
||||
FL_RESETTING,
|
||||
FL_OTPING,
|
||||
FL_PREPARING_ERASE,
|
||||
FL_VERIFYING_ERASE,
|
||||
|
||||
FL_UNKNOWN
|
||||
} flstate_t;
|
||||
|
||||
|
||||
|
||||
/* NOTE: confusingly, this can be used to refer to more than one chip at a time,
|
||||
if they're interleaved. This can even refer to individual partitions on
|
||||
the same physical chip when present. */
|
||||
|
||||
struct flchip {
|
||||
unsigned long start; /* Offset within the map */
|
||||
// unsigned long len;
|
||||
/* We omit len for now, because when we group them together
|
||||
we insist that they're all of the same size, and the chip size
|
||||
is held in the next level up. If we get more versatile later,
|
||||
it'll make it a damn sight harder to find which chip we want from
|
||||
a given offset, and we'll want to add the per-chip length field
|
||||
back in.
|
||||
*/
|
||||
int ref_point_counter;
|
||||
flstate_t state;
|
||||
flstate_t oldstate;
|
||||
|
||||
unsigned int write_suspended:1;
|
||||
unsigned int erase_suspended:1;
|
||||
unsigned long in_progress_block_addr;
|
||||
unsigned long in_progress_block_mask;
|
||||
|
||||
struct mutex mutex;
|
||||
wait_queue_head_t wq; /* Wait on here when we're waiting for the chip
|
||||
to be ready */
|
||||
int word_write_time;
|
||||
int buffer_write_time;
|
||||
int erase_time;
|
||||
|
||||
int word_write_time_max;
|
||||
int buffer_write_time_max;
|
||||
int erase_time_max;
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/* This is used to handle contention on write/erase operations
|
||||
between partitions of the same physical chip. */
|
||||
struct flchip_shared {
|
||||
struct mutex lock;
|
||||
struct flchip *writing;
|
||||
struct flchip *erasing;
|
||||
};
|
||||
|
||||
|
||||
#endif /* __MTD_FLASHCHIP_H__ */
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Derived from (and probably identical to):
|
||||
* ftl.h 1.7 1999/10/25 20:23:17
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License
|
||||
* at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* The initial developer of the original code is David A. Hinds
|
||||
* <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
|
||||
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License version 2 (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of the
|
||||
* above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use
|
||||
* your version of this file under the MPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the MPL or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FTL_H
|
||||
#define _LINUX_FTL_H
|
||||
|
||||
typedef struct erase_unit_header_t {
|
||||
uint8_t LinkTargetTuple[5];
|
||||
uint8_t DataOrgTuple[10];
|
||||
uint8_t NumTransferUnits;
|
||||
uint32_t EraseCount;
|
||||
uint16_t LogicalEUN;
|
||||
uint8_t BlockSize;
|
||||
uint8_t EraseUnitSize;
|
||||
uint16_t FirstPhysicalEUN;
|
||||
uint16_t NumEraseUnits;
|
||||
uint32_t FormattedSize;
|
||||
uint32_t FirstVMAddress;
|
||||
uint16_t NumVMPages;
|
||||
uint8_t Flags;
|
||||
uint8_t Code;
|
||||
uint32_t SerialNumber;
|
||||
uint32_t AltEUHOffset;
|
||||
uint32_t BAMOffset;
|
||||
uint8_t Reserved[12];
|
||||
uint8_t EndTuple[2];
|
||||
} erase_unit_header_t;
|
||||
|
||||
/* Flags in erase_unit_header_t */
|
||||
#define HIDDEN_AREA 0x01
|
||||
#define REVERSE_POLARITY 0x02
|
||||
#define DOUBLE_BAI 0x04
|
||||
|
||||
/* Definitions for block allocation information */
|
||||
|
||||
#define BLOCK_FREE(b) ((b) == 0xffffffff)
|
||||
#define BLOCK_DELETED(b) (((b) == 0) || ((b) == 0xfffffffe))
|
||||
|
||||
#define BLOCK_TYPE(b) ((b) & 0x7f)
|
||||
#define BLOCK_ADDRESS(b) ((b) & ~0x7f)
|
||||
#define BLOCK_NUMBER(b) ((b) >> 9)
|
||||
#define BLOCK_CONTROL 0x30
|
||||
#define BLOCK_DATA 0x40
|
||||
#define BLOCK_REPLACEMENT 0x60
|
||||
#define BLOCK_BAD 0x70
|
||||
|
||||
#endif /* _LINUX_FTL_H */
|
||||
@@ -0,0 +1,23 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright © 2001 Red Hat UK Limited
|
||||
* Copyright © 2001-2010 David Woodhouse <dwmw2@infradead.org>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MTD_GEN_PROBE_H__
|
||||
#define __LINUX_MTD_GEN_PROBE_H__
|
||||
|
||||
#include <linux/mtd/flashchip.h>
|
||||
#include <linux/mtd/map.h>
|
||||
#include <linux/mtd/cfi.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
struct chip_probe {
|
||||
char *name;
|
||||
int (*probe_chip)(struct map_info *map, __u32 base,
|
||||
unsigned long *chip_map, struct cfi_private *cfi);
|
||||
};
|
||||
|
||||
struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp);
|
||||
|
||||
#endif /* __LINUX_MTD_GEN_PROBE_H__ */
|
||||
@@ -0,0 +1,95 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MTD_HYPERBUS_H__
|
||||
#define __LINUX_MTD_HYPERBUS_H__
|
||||
|
||||
#include <linux/mtd/map.h>
|
||||
|
||||
/* HyperBus command bits */
|
||||
#define HYPERBUS_RW 0x80 /* R/W# */
|
||||
#define HYPERBUS_RW_WRITE 0
|
||||
#define HYPERBUS_RW_READ 0x80
|
||||
#define HYPERBUS_AS 0x40 /* Address Space */
|
||||
#define HYPERBUS_AS_MEM 0
|
||||
#define HYPERBUS_AS_REG 0x40
|
||||
#define HYPERBUS_BT 0x20 /* Burst Type */
|
||||
#define HYPERBUS_BT_WRAPPED 0
|
||||
#define HYPERBUS_BT_LINEAR 0x20
|
||||
|
||||
enum hyperbus_memtype {
|
||||
HYPERFLASH,
|
||||
HYPERRAM,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hyperbus_device - struct representing HyperBus slave device
|
||||
* @map: map_info struct for accessing MMIO HyperBus flash memory
|
||||
* @np: pointer to HyperBus slave device node
|
||||
* @mtd: pointer to MTD struct
|
||||
* @ctlr: pointer to HyperBus controller struct
|
||||
* @memtype: type of memory device: HyperFlash or HyperRAM
|
||||
* @priv: pointer to controller specific per device private data
|
||||
*/
|
||||
|
||||
struct hyperbus_device {
|
||||
struct map_info map;
|
||||
struct device_node *np;
|
||||
struct mtd_info *mtd;
|
||||
struct hyperbus_ctlr *ctlr;
|
||||
enum hyperbus_memtype memtype;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hyperbus_ops - struct representing custom HyperBus operations
|
||||
* @read16: read 16 bit of data from flash in a single burst. Used to read
|
||||
* from non default address space, such as ID/CFI space
|
||||
* @write16: write 16 bit of data to flash in a single burst. Used to
|
||||
* send cmd to flash or write single 16 bit word at a time.
|
||||
* @copy_from: copy data from flash memory
|
||||
* @copy_to: copy data to flash memory
|
||||
* @calibrate: calibrate HyperBus controller
|
||||
*/
|
||||
|
||||
struct hyperbus_ops {
|
||||
u16 (*read16)(struct hyperbus_device *hbdev, unsigned long addr);
|
||||
void (*write16)(struct hyperbus_device *hbdev,
|
||||
unsigned long addr, u16 val);
|
||||
void (*copy_from)(struct hyperbus_device *hbdev, void *to,
|
||||
unsigned long from, ssize_t len);
|
||||
void (*copy_to)(struct hyperbus_device *dev, unsigned long to,
|
||||
const void *from, ssize_t len);
|
||||
int (*calibrate)(struct hyperbus_device *dev);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hyperbus_ctlr - struct representing HyperBus controller
|
||||
* @dev: pointer to HyperBus controller device
|
||||
* @calibrated: flag to indicate ctlr calibration sequence is complete
|
||||
* @ops: HyperBus controller ops
|
||||
*/
|
||||
struct hyperbus_ctlr {
|
||||
struct device *dev;
|
||||
bool calibrated;
|
||||
|
||||
const struct hyperbus_ops *ops;
|
||||
};
|
||||
|
||||
/**
|
||||
* hyperbus_register_device - probe and register a HyperBus slave memory device
|
||||
* @hbdev: hyperbus_device struct with dev, np and ctlr field populated
|
||||
*
|
||||
* Return: 0 for success, others for failure.
|
||||
*/
|
||||
int hyperbus_register_device(struct hyperbus_device *hbdev);
|
||||
|
||||
/**
|
||||
* hyperbus_unregister_device - deregister HyperBus slave memory device
|
||||
* @hbdev: hyperbus_device to be unregistered
|
||||
*/
|
||||
void hyperbus_unregister_device(struct hyperbus_device *hbdev);
|
||||
|
||||
#endif /* __LINUX_MTD_HYPERBUS_H__ */
|
||||
@@ -0,0 +1,63 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* inftl.h -- defines to support the Inverse NAND Flash Translation Layer
|
||||
*
|
||||
* (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
|
||||
*/
|
||||
|
||||
#ifndef __MTD_INFTL_H__
|
||||
#define __MTD_INFTL_H__
|
||||
|
||||
#ifndef __KERNEL__
|
||||
#error This is a kernel header. Perhaps include nftl-user.h instead?
|
||||
#endif
|
||||
|
||||
#include <linux/mtd/blktrans.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/nftl.h>
|
||||
|
||||
#include <mtd/inftl-user.h>
|
||||
|
||||
#ifndef INFTL_MAJOR
|
||||
#define INFTL_MAJOR 96
|
||||
#endif
|
||||
#define INFTL_PARTN_BITS 4
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
struct INFTLrecord {
|
||||
struct mtd_blktrans_dev mbd;
|
||||
__u16 MediaUnit;
|
||||
__u32 EraseSize;
|
||||
struct INFTLMediaHeader MediaHdr;
|
||||
int usecount;
|
||||
unsigned char heads;
|
||||
unsigned char sectors;
|
||||
unsigned short cylinders;
|
||||
__u16 numvunits;
|
||||
__u16 firstEUN;
|
||||
__u16 lastEUN;
|
||||
__u16 numfreeEUNs;
|
||||
__u16 LastFreeEUN; /* To speed up finding a free EUN */
|
||||
int head,sect,cyl;
|
||||
__u16 *PUtable; /* Physical Unit Table */
|
||||
__u16 *VUtable; /* Virtual Unit Table */
|
||||
unsigned int nb_blocks; /* number of physical blocks */
|
||||
unsigned int nb_boot_blocks; /* number of blocks used by the bios */
|
||||
struct erase_info instr;
|
||||
};
|
||||
|
||||
int INFTL_mount(struct INFTLrecord *s);
|
||||
int INFTL_formatblock(struct INFTLrecord *s, int block);
|
||||
|
||||
void INFTL_dumptables(struct INFTLrecord *s);
|
||||
void INFTL_dumpVUchains(struct INFTLrecord *s);
|
||||
|
||||
int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
|
||||
size_t *retlen, uint8_t *buf);
|
||||
int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
|
||||
size_t *retlen, uint8_t *buf);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __MTD_INFTL_H__ */
|
||||
@@ -0,0 +1,94 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org>
|
||||
* Steven J. Hill <sjhill@realitydiluted.com>
|
||||
* Thomas Gleixner <tglx@kernel.org>
|
||||
*
|
||||
* Contains all JEDEC related definitions
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MTD_JEDEC_H
|
||||
#define __LINUX_MTD_JEDEC_H
|
||||
|
||||
struct jedec_ecc_info {
|
||||
u8 ecc_bits;
|
||||
u8 codeword_size;
|
||||
__le16 bb_per_lun;
|
||||
__le16 block_endurance;
|
||||
u8 reserved[2];
|
||||
} __packed;
|
||||
|
||||
/* JEDEC features */
|
||||
#define JEDEC_FEATURE_16_BIT_BUS (1 << 0)
|
||||
|
||||
/* JEDEC Optional Commands */
|
||||
#define JEDEC_OPT_CMD_READ_CACHE BIT(1)
|
||||
|
||||
struct nand_jedec_params {
|
||||
/* rev info and features block */
|
||||
/* 'J' 'E' 'S' 'D' */
|
||||
u8 sig[4];
|
||||
__le16 revision;
|
||||
__le16 features;
|
||||
u8 opt_cmd[3];
|
||||
__le16 sec_cmd;
|
||||
u8 num_of_param_pages;
|
||||
u8 reserved0[18];
|
||||
|
||||
/* manufacturer information block */
|
||||
char manufacturer[12];
|
||||
char model[20];
|
||||
u8 jedec_id[6];
|
||||
u8 reserved1[10];
|
||||
|
||||
/* memory organization block */
|
||||
__le32 byte_per_page;
|
||||
__le16 spare_bytes_per_page;
|
||||
u8 reserved2[6];
|
||||
__le32 pages_per_block;
|
||||
__le32 blocks_per_lun;
|
||||
u8 lun_count;
|
||||
u8 addr_cycles;
|
||||
u8 bits_per_cell;
|
||||
u8 programs_per_page;
|
||||
u8 multi_plane_addr;
|
||||
u8 multi_plane_op_attr;
|
||||
u8 reserved3[38];
|
||||
|
||||
/* electrical parameter block */
|
||||
__le16 async_sdr_speed_grade;
|
||||
__le16 toggle_ddr_speed_grade;
|
||||
__le16 sync_ddr_speed_grade;
|
||||
u8 async_sdr_features;
|
||||
u8 toggle_ddr_features;
|
||||
u8 sync_ddr_features;
|
||||
__le16 t_prog;
|
||||
__le16 t_bers;
|
||||
__le16 t_r;
|
||||
__le16 t_r_multi_plane;
|
||||
__le16 t_ccs;
|
||||
__le16 io_pin_capacitance_typ;
|
||||
__le16 input_pin_capacitance_typ;
|
||||
__le16 clk_pin_capacitance_typ;
|
||||
u8 driver_strength_support;
|
||||
__le16 t_adl;
|
||||
u8 reserved4[36];
|
||||
|
||||
/* ECC and endurance block */
|
||||
u8 guaranteed_good_blocks;
|
||||
__le16 guaranteed_block_endurance;
|
||||
struct jedec_ecc_info ecc_info[4];
|
||||
u8 reserved5[29];
|
||||
|
||||
/* reserved */
|
||||
u8 reserved6[148];
|
||||
|
||||
/* vendor */
|
||||
__le16 vendor_rev_num;
|
||||
u8 reserved7[88];
|
||||
|
||||
/* CRC for Parameter Page */
|
||||
__le16 crc;
|
||||
} __packed;
|
||||
|
||||
#endif /* __LINUX_MTD_JEDEC_H */
|
||||
@@ -0,0 +1,17 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Platform data for LPC32xx SoC MLC NAND controller
|
||||
*
|
||||
* Copyright © 2012 Roland Stigge
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MTD_LPC32XX_MLC_H
|
||||
#define __LINUX_MTD_LPC32XX_MLC_H
|
||||
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
struct lpc32xx_mlc_platform_data {
|
||||
dma_filter_fn dma_filter;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_MTD_LPC32XX_MLC_H */
|
||||
@@ -0,0 +1,17 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Platform data for LPC32xx SoC SLC NAND controller
|
||||
*
|
||||
* Copyright © 2012 Roland Stigge
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MTD_LPC32XX_SLC_H
|
||||
#define __LINUX_MTD_LPC32XX_SLC_H
|
||||
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
struct lpc32xx_slc_platform_data {
|
||||
dma_filter_fn dma_filter;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_MTD_LPC32XX_SLC_H */
|
||||
@@ -0,0 +1,466 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org> et al.
|
||||
*/
|
||||
|
||||
/* Overhauled routines for dealing with different mmap regions of flash */
|
||||
|
||||
#ifndef __LINUX_MTD_MAP_H__
|
||||
#define __LINUX_MTD_MAP_H__
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <asm/barrier.h>
|
||||
|
||||
struct device_node;
|
||||
struct module;
|
||||
|
||||
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_1
|
||||
#define map_bankwidth(map) 1
|
||||
#define map_bankwidth_is_1(map) (map_bankwidth(map) == 1)
|
||||
#define map_bankwidth_is_large(map) (0)
|
||||
#define map_words(map) (1)
|
||||
#define MAX_MAP_BANKWIDTH 1
|
||||
#else
|
||||
#define map_bankwidth_is_1(map) (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_2
|
||||
# ifdef map_bankwidth
|
||||
# undef map_bankwidth
|
||||
# define map_bankwidth(map) ((map)->bankwidth)
|
||||
# else
|
||||
# define map_bankwidth(map) 2
|
||||
# define map_bankwidth_is_large(map) (0)
|
||||
# define map_words(map) (1)
|
||||
# endif
|
||||
#define map_bankwidth_is_2(map) (map_bankwidth(map) == 2)
|
||||
#undef MAX_MAP_BANKWIDTH
|
||||
#define MAX_MAP_BANKWIDTH 2
|
||||
#else
|
||||
#define map_bankwidth_is_2(map) (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_4
|
||||
# ifdef map_bankwidth
|
||||
# undef map_bankwidth
|
||||
# define map_bankwidth(map) ((map)->bankwidth)
|
||||
# else
|
||||
# define map_bankwidth(map) 4
|
||||
# define map_bankwidth_is_large(map) (0)
|
||||
# define map_words(map) (1)
|
||||
# endif
|
||||
#define map_bankwidth_is_4(map) (map_bankwidth(map) == 4)
|
||||
#undef MAX_MAP_BANKWIDTH
|
||||
#define MAX_MAP_BANKWIDTH 4
|
||||
#else
|
||||
#define map_bankwidth_is_4(map) (0)
|
||||
#endif
|
||||
|
||||
/* ensure we never evaluate anything shorted than an unsigned long
|
||||
* to zero, and ensure we'll never miss the end of an comparison (bjd) */
|
||||
|
||||
#define map_calc_words(map) ((map_bankwidth(map) + (sizeof(unsigned long)-1)) / sizeof(unsigned long))
|
||||
|
||||
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_8
|
||||
# ifdef map_bankwidth
|
||||
# undef map_bankwidth
|
||||
# define map_bankwidth(map) ((map)->bankwidth)
|
||||
# if BITS_PER_LONG < 64
|
||||
# undef map_bankwidth_is_large
|
||||
# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
|
||||
# undef map_words
|
||||
# define map_words(map) map_calc_words(map)
|
||||
# endif
|
||||
# else
|
||||
# define map_bankwidth(map) 8
|
||||
# define map_bankwidth_is_large(map) (BITS_PER_LONG < 64)
|
||||
# define map_words(map) map_calc_words(map)
|
||||
# endif
|
||||
#define map_bankwidth_is_8(map) (map_bankwidth(map) == 8)
|
||||
#undef MAX_MAP_BANKWIDTH
|
||||
#define MAX_MAP_BANKWIDTH 8
|
||||
#else
|
||||
#define map_bankwidth_is_8(map) (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_16
|
||||
# ifdef map_bankwidth
|
||||
# undef map_bankwidth
|
||||
# define map_bankwidth(map) ((map)->bankwidth)
|
||||
# undef map_bankwidth_is_large
|
||||
# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
|
||||
# undef map_words
|
||||
# define map_words(map) map_calc_words(map)
|
||||
# else
|
||||
# define map_bankwidth(map) 16
|
||||
# define map_bankwidth_is_large(map) (1)
|
||||
# define map_words(map) map_calc_words(map)
|
||||
# endif
|
||||
#define map_bankwidth_is_16(map) (map_bankwidth(map) == 16)
|
||||
#undef MAX_MAP_BANKWIDTH
|
||||
#define MAX_MAP_BANKWIDTH 16
|
||||
#else
|
||||
#define map_bankwidth_is_16(map) (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_32
|
||||
/* always use indirect access for 256-bit to preserve kernel stack */
|
||||
# undef map_bankwidth
|
||||
# define map_bankwidth(map) ((map)->bankwidth)
|
||||
# undef map_bankwidth_is_large
|
||||
# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
|
||||
# undef map_words
|
||||
# define map_words(map) map_calc_words(map)
|
||||
#define map_bankwidth_is_32(map) (map_bankwidth(map) == 32)
|
||||
#undef MAX_MAP_BANKWIDTH
|
||||
#define MAX_MAP_BANKWIDTH 32
|
||||
#else
|
||||
#define map_bankwidth_is_32(map) (0)
|
||||
#endif
|
||||
|
||||
#ifndef map_bankwidth
|
||||
#ifdef CONFIG_MTD
|
||||
#warning "No CONFIG_MTD_MAP_BANK_WIDTH_xx selected. No NOR chip support can work"
|
||||
#endif
|
||||
static inline int map_bankwidth(void *map)
|
||||
{
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
#define map_bankwidth_is_large(map) (0)
|
||||
#define map_words(map) (0)
|
||||
#define MAX_MAP_BANKWIDTH 1
|
||||
#endif
|
||||
|
||||
static inline int map_bankwidth_supported(int w)
|
||||
{
|
||||
switch (w) {
|
||||
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_1
|
||||
case 1:
|
||||
#endif
|
||||
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_2
|
||||
case 2:
|
||||
#endif
|
||||
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_4
|
||||
case 4:
|
||||
#endif
|
||||
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_8
|
||||
case 8:
|
||||
#endif
|
||||
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_16
|
||||
case 16:
|
||||
#endif
|
||||
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_32
|
||||
case 32:
|
||||
#endif
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_MAP_LONGS (((MAX_MAP_BANKWIDTH * 8) + BITS_PER_LONG - 1) / BITS_PER_LONG)
|
||||
|
||||
typedef union {
|
||||
unsigned long x[MAX_MAP_LONGS];
|
||||
} map_word;
|
||||
|
||||
/* The map stuff is very simple. You fill in your struct map_info with
|
||||
a handful of routines for accessing the device, making sure they handle
|
||||
paging etc. correctly if your device needs it. Then you pass it off
|
||||
to a chip probe routine -- either JEDEC or CFI probe or both -- via
|
||||
do_map_probe(). If a chip is recognised, the probe code will invoke the
|
||||
appropriate chip driver (if present) and return a struct mtd_info.
|
||||
At which point, you fill in the mtd->module with your own module
|
||||
address, and register it with the MTD core code. Or you could partition
|
||||
it and register the partitions instead, or keep it for your own private
|
||||
use; whatever.
|
||||
|
||||
The mtd->priv field will point to the struct map_info, and any further
|
||||
private data required by the chip driver is linked from the
|
||||
mtd->priv->fldrv_priv field. This allows the map driver to get at
|
||||
the destructor function map->fldrv_destroy() when it's tired
|
||||
of living.
|
||||
*/
|
||||
|
||||
struct mtd_chip_driver;
|
||||
struct map_info {
|
||||
const char *name;
|
||||
unsigned long size;
|
||||
resource_size_t phys;
|
||||
#define NO_XIP (-1UL)
|
||||
|
||||
void __iomem *virt;
|
||||
void *cached;
|
||||
|
||||
int swap; /* this mapping's byte-swapping requirement */
|
||||
int bankwidth; /* in octets. This isn't necessarily the width
|
||||
of actual bus cycles -- it's the repeat interval
|
||||
in bytes, before you are talking to the first chip again.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
|
||||
map_word (*read)(struct map_info *, unsigned long);
|
||||
void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t);
|
||||
|
||||
void (*write)(struct map_info *, const map_word, unsigned long);
|
||||
void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t);
|
||||
|
||||
/* We can perhaps put in 'point' and 'unpoint' methods, if we really
|
||||
want to enable XIP for non-linear mappings. Not yet though. */
|
||||
#endif
|
||||
/* It's possible for the map driver to use cached memory in its
|
||||
copy_from implementation (and _only_ with copy_from). However,
|
||||
when the chip driver knows some flash area has changed contents,
|
||||
it will signal it to the map driver through this routine to let
|
||||
the map driver invalidate the corresponding cache as needed.
|
||||
If there is no cache to care about this can be set to NULL. */
|
||||
void (*inval_cache)(struct map_info *, unsigned long, ssize_t);
|
||||
|
||||
/* This will be called with 1 as parameter when the first map user
|
||||
* needs VPP, and called with 0 when the last user exits. The map
|
||||
* core maintains a reference counter, and assumes that VPP is a
|
||||
* global resource applying to all mapped flash chips on the system.
|
||||
*/
|
||||
void (*set_vpp)(struct map_info *, int);
|
||||
|
||||
unsigned long pfow_base;
|
||||
unsigned long map_priv_1;
|
||||
unsigned long map_priv_2;
|
||||
struct device_node *device_node;
|
||||
void *fldrv_priv;
|
||||
struct mtd_chip_driver *fldrv;
|
||||
};
|
||||
|
||||
struct mtd_chip_driver {
|
||||
struct mtd_info *(*probe)(struct map_info *map);
|
||||
void (*destroy)(struct mtd_info *);
|
||||
struct module *module;
|
||||
char *name;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
void register_mtd_chip_driver(struct mtd_chip_driver *);
|
||||
void unregister_mtd_chip_driver(struct mtd_chip_driver *);
|
||||
|
||||
struct mtd_info *do_map_probe(const char *name, struct map_info *map);
|
||||
void map_destroy(struct mtd_info *mtd);
|
||||
|
||||
#define ENABLE_VPP(map) do { if (map->set_vpp) map->set_vpp(map, 1); } while (0)
|
||||
#define DISABLE_VPP(map) do { if (map->set_vpp) map->set_vpp(map, 0); } while (0)
|
||||
|
||||
#define INVALIDATE_CACHED_RANGE(map, from, size) \
|
||||
do { if (map->inval_cache) map->inval_cache(map, from, size); } while (0)
|
||||
|
||||
#define map_word_equal(map, val1, val2) \
|
||||
({ \
|
||||
int i, ret = 1; \
|
||||
for (i = 0; i < map_words(map); i++) \
|
||||
if ((val1).x[i] != (val2).x[i]) { \
|
||||
ret = 0; \
|
||||
break; \
|
||||
} \
|
||||
ret; \
|
||||
})
|
||||
|
||||
#define map_word_and(map, val1, val2) \
|
||||
({ \
|
||||
map_word r; \
|
||||
int i; \
|
||||
for (i = 0; i < map_words(map); i++) \
|
||||
r.x[i] = (val1).x[i] & (val2).x[i]; \
|
||||
r; \
|
||||
})
|
||||
|
||||
#define map_word_clr(map, val1, val2) \
|
||||
({ \
|
||||
map_word r; \
|
||||
int i; \
|
||||
for (i = 0; i < map_words(map); i++) \
|
||||
r.x[i] = (val1).x[i] & ~(val2).x[i]; \
|
||||
r; \
|
||||
})
|
||||
|
||||
#define map_word_or(map, val1, val2) \
|
||||
({ \
|
||||
map_word r; \
|
||||
int i; \
|
||||
for (i = 0; i < map_words(map); i++) \
|
||||
r.x[i] = (val1).x[i] | (val2).x[i]; \
|
||||
r; \
|
||||
})
|
||||
|
||||
#define map_word_andequal(map, val1, val2, val3) \
|
||||
({ \
|
||||
int i, ret = 1; \
|
||||
for (i = 0; i < map_words(map); i++) { \
|
||||
if (((val1).x[i] & (val2).x[i]) != (val3).x[i]) { \
|
||||
ret = 0; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
ret; \
|
||||
})
|
||||
|
||||
#define map_word_bitsset(map, val1, val2) \
|
||||
({ \
|
||||
int i, ret = 0; \
|
||||
for (i = 0; i < map_words(map); i++) { \
|
||||
if ((val1).x[i] & (val2).x[i]) { \
|
||||
ret = 1; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
ret; \
|
||||
})
|
||||
|
||||
static inline map_word map_word_load(struct map_info *map, const void *ptr)
|
||||
{
|
||||
map_word r;
|
||||
|
||||
if (map_bankwidth_is_1(map))
|
||||
r.x[0] = *(unsigned char *)ptr;
|
||||
else if (map_bankwidth_is_2(map))
|
||||
r.x[0] = get_unaligned((uint16_t *)ptr);
|
||||
else if (map_bankwidth_is_4(map))
|
||||
r.x[0] = get_unaligned((uint32_t *)ptr);
|
||||
#if BITS_PER_LONG >= 64
|
||||
else if (map_bankwidth_is_8(map))
|
||||
r.x[0] = get_unaligned((uint64_t *)ptr);
|
||||
#endif
|
||||
else if (map_bankwidth_is_large(map))
|
||||
memcpy(r.x, ptr, map->bankwidth);
|
||||
else
|
||||
BUG();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline map_word map_word_load_partial(struct map_info *map, map_word orig, const unsigned char *buf, int start, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (map_bankwidth_is_large(map)) {
|
||||
char *dest = (char *)&orig;
|
||||
|
||||
memcpy(dest+start, buf, len);
|
||||
} else {
|
||||
for (i = start; i < start+len; i++) {
|
||||
int bitpos;
|
||||
|
||||
#ifdef __LITTLE_ENDIAN
|
||||
bitpos = i * 8;
|
||||
#else /* __BIG_ENDIAN */
|
||||
bitpos = (map_bankwidth(map) - 1 - i) * 8;
|
||||
#endif
|
||||
orig.x[0] &= ~(0xff << bitpos);
|
||||
orig.x[0] |= (unsigned long)buf[i-start] << bitpos;
|
||||
}
|
||||
}
|
||||
return orig;
|
||||
}
|
||||
|
||||
#if BITS_PER_LONG < 64
|
||||
#define MAP_FF_LIMIT 4
|
||||
#else
|
||||
#define MAP_FF_LIMIT 8
|
||||
#endif
|
||||
|
||||
static inline map_word map_word_ff(struct map_info *map)
|
||||
{
|
||||
map_word r;
|
||||
int i;
|
||||
|
||||
if (map_bankwidth(map) < MAP_FF_LIMIT) {
|
||||
int bw = 8 * map_bankwidth(map);
|
||||
|
||||
r.x[0] = (1UL << bw) - 1;
|
||||
} else {
|
||||
for (i = 0; i < map_words(map); i++)
|
||||
r.x[i] = ~0UL;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline map_word inline_map_read(struct map_info *map, unsigned long ofs)
|
||||
{
|
||||
map_word r;
|
||||
|
||||
if (map_bankwidth_is_1(map))
|
||||
r.x[0] = __raw_readb(map->virt + ofs);
|
||||
else if (map_bankwidth_is_2(map))
|
||||
r.x[0] = __raw_readw(map->virt + ofs);
|
||||
else if (map_bankwidth_is_4(map))
|
||||
r.x[0] = __raw_readl(map->virt + ofs);
|
||||
#if BITS_PER_LONG >= 64
|
||||
else if (map_bankwidth_is_8(map))
|
||||
r.x[0] = __raw_readq(map->virt + ofs);
|
||||
#endif
|
||||
else if (map_bankwidth_is_large(map))
|
||||
memcpy_fromio(r.x, map->virt + ofs, map->bankwidth);
|
||||
else
|
||||
BUG();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline void inline_map_write(struct map_info *map, const map_word datum, unsigned long ofs)
|
||||
{
|
||||
if (map_bankwidth_is_1(map))
|
||||
__raw_writeb(datum.x[0], map->virt + ofs);
|
||||
else if (map_bankwidth_is_2(map))
|
||||
__raw_writew(datum.x[0], map->virt + ofs);
|
||||
else if (map_bankwidth_is_4(map))
|
||||
__raw_writel(datum.x[0], map->virt + ofs);
|
||||
#if BITS_PER_LONG >= 64
|
||||
else if (map_bankwidth_is_8(map))
|
||||
__raw_writeq(datum.x[0], map->virt + ofs);
|
||||
#endif
|
||||
else if (map_bankwidth_is_large(map))
|
||||
memcpy_toio(map->virt+ofs, datum.x, map->bankwidth);
|
||||
else
|
||||
BUG();
|
||||
mb();
|
||||
}
|
||||
|
||||
static inline void inline_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
|
||||
{
|
||||
if (map->cached)
|
||||
memcpy(to, (char *)map->cached + from, len);
|
||||
else
|
||||
memcpy_fromio(to, map->virt + from, len);
|
||||
}
|
||||
|
||||
static inline void inline_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
|
||||
{
|
||||
memcpy_toio(map->virt + to, from, len);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
|
||||
#define map_read(map, ofs) (map)->read(map, ofs)
|
||||
#define map_copy_from(map, to, from, len) (map)->copy_from(map, to, from, len)
|
||||
#define map_write(map, datum, ofs) (map)->write(map, datum, ofs)
|
||||
#define map_copy_to(map, to, from, len) (map)->copy_to(map, to, from, len)
|
||||
|
||||
extern void simple_map_init(struct map_info *);
|
||||
#define map_is_linear(map) (map->phys != NO_XIP)
|
||||
|
||||
#else
|
||||
#define map_read(map, ofs) inline_map_read(map, ofs)
|
||||
#define map_copy_from(map, to, from, len) inline_map_copy_from(map, to, from, len)
|
||||
#define map_write(map, datum, ofs) inline_map_write(map, datum, ofs)
|
||||
#define map_copy_to(map, to, from, len) inline_map_copy_to(map, to, from, len)
|
||||
|
||||
|
||||
#define simple_map_init(map) BUG_ON(!map_bankwidth_supported((map)->bankwidth))
|
||||
#define map_is_linear(map) ({ (void)(map); 1; })
|
||||
|
||||
#endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */
|
||||
|
||||
#endif /* __LINUX_MTD_MAP_H__ */
|
||||
@@ -0,0 +1,724 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org> et al.
|
||||
*/
|
||||
|
||||
#ifndef __MTD_MTD_H__
|
||||
#define __MTD_MTD_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/nvmem-provider.h>
|
||||
|
||||
#include <mtd/mtd-abi.h>
|
||||
|
||||
#include <asm/div64.h>
|
||||
|
||||
#define MTD_FAIL_ADDR_UNKNOWN -1LL
|
||||
|
||||
struct mtd_info;
|
||||
|
||||
/*
|
||||
* If the erase fails, fail_addr might indicate exactly which block failed. If
|
||||
* fail_addr = MTD_FAIL_ADDR_UNKNOWN, the failure was not at the device level
|
||||
* or was not specific to any particular block.
|
||||
*/
|
||||
struct erase_info {
|
||||
uint64_t addr;
|
||||
uint64_t len;
|
||||
uint64_t fail_addr;
|
||||
};
|
||||
|
||||
struct mtd_erase_region_info {
|
||||
uint64_t offset; /* At which this region starts, from the beginning of the MTD */
|
||||
uint32_t erasesize; /* For this region */
|
||||
uint32_t numblocks; /* Number of blocks of erasesize in this region */
|
||||
unsigned long *lockmap; /* If keeping bitmap of locks */
|
||||
};
|
||||
|
||||
struct mtd_req_stats {
|
||||
unsigned int uncorrectable_errors;
|
||||
unsigned int corrected_bitflips;
|
||||
unsigned int max_bitflips;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mtd_oob_ops - oob operation operands
|
||||
* @mode: operation mode
|
||||
*
|
||||
* @len: number of data bytes to write/read
|
||||
*
|
||||
* @retlen: number of data bytes written/read
|
||||
*
|
||||
* @ooblen: number of oob bytes to write/read
|
||||
* @oobretlen: number of oob bytes written/read
|
||||
* @ooboffs: offset of oob data in the oob area (only relevant when
|
||||
* mode = MTD_OPS_PLACE_OOB or MTD_OPS_RAW)
|
||||
* @datbuf: data buffer - if NULL only oob data are read/written
|
||||
* @oobbuf: oob data buffer
|
||||
*
|
||||
* 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;
|
||||
size_t len;
|
||||
size_t retlen;
|
||||
size_t ooblen;
|
||||
size_t oobretlen;
|
||||
uint32_t ooboffs;
|
||||
uint8_t *datbuf;
|
||||
uint8_t *oobbuf;
|
||||
struct mtd_req_stats *stats;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mtd_oob_region - oob region definition
|
||||
* @offset: region offset
|
||||
* @length: region length
|
||||
*
|
||||
* This structure describes a region of the OOB area, and is used
|
||||
* to retrieve ECC or free bytes sections.
|
||||
* Each section is defined by an offset within the OOB area and a
|
||||
* length.
|
||||
*/
|
||||
struct mtd_oob_region {
|
||||
u32 offset;
|
||||
u32 length;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct mtd_ooblayout_ops - NAND OOB layout operations
|
||||
* @ecc: function returning an ECC region in the OOB area.
|
||||
* Should return -ERANGE if %section exceeds the total number of
|
||||
* ECC sections.
|
||||
* @free: function returning a free region in the OOB area.
|
||||
* Should return -ERANGE if %section exceeds the total number of
|
||||
* free sections.
|
||||
*/
|
||||
struct mtd_ooblayout_ops {
|
||||
int (*ecc)(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *oobecc);
|
||||
int (*free)(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *oobfree);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mtd_pairing_info - page pairing information
|
||||
*
|
||||
* @pair: pair id
|
||||
* @group: group id
|
||||
*
|
||||
* The term "pair" is used here, even though TLC NANDs might group pages by 3
|
||||
* (3 bits in a single cell). A pair should regroup all pages that are sharing
|
||||
* the same cell. Pairs are then indexed in ascending order.
|
||||
*
|
||||
* @group is defining the position of a page in a given pair. It can also be
|
||||
* seen as the bit position in the cell: page attached to bit 0 belongs to
|
||||
* group 0, page attached to bit 1 belongs to group 1, etc.
|
||||
*
|
||||
* Example:
|
||||
* The H27UCG8T2BTR-BC datasheet describes the following pairing scheme:
|
||||
*
|
||||
* group-0 group-1
|
||||
*
|
||||
* pair-0 page-0 page-4
|
||||
* pair-1 page-1 page-5
|
||||
* pair-2 page-2 page-8
|
||||
* ...
|
||||
* pair-127 page-251 page-255
|
||||
*
|
||||
*
|
||||
* Note that the "group" and "pair" terms were extracted from Samsung and
|
||||
* Hynix datasheets, and might be referenced under other names in other
|
||||
* datasheets (Micron is describing this concept as "shared pages").
|
||||
*/
|
||||
struct mtd_pairing_info {
|
||||
int pair;
|
||||
int group;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mtd_pairing_scheme - page pairing scheme description
|
||||
*
|
||||
* @ngroups: number of groups. Should be related to the number of bits
|
||||
* per cell.
|
||||
* @get_info: converts a write-unit (page number within an erase block) into
|
||||
* mtd_pairing information (pair + group). This function should
|
||||
* fill the info parameter based on the wunit index or return
|
||||
* -EINVAL if the wunit parameter is invalid.
|
||||
* @get_wunit: converts pairing information into a write-unit (page) number.
|
||||
* This function should return the wunit index pointed by the
|
||||
* pairing information described in the info argument. It should
|
||||
* return -EINVAL, if there's no wunit corresponding to the
|
||||
* passed pairing information.
|
||||
*
|
||||
* See mtd_pairing_info documentation for a detailed explanation of the
|
||||
* pair and group concepts.
|
||||
*
|
||||
* The mtd_pairing_scheme structure provides a generic solution to represent
|
||||
* NAND page pairing scheme. Instead of exposing two big tables to do the
|
||||
* write-unit <-> (pair + group) conversions, we ask the MTD drivers to
|
||||
* implement the ->get_info() and ->get_wunit() functions.
|
||||
*
|
||||
* MTD users will then be able to query these information by using the
|
||||
* mtd_pairing_info_to_wunit() and mtd_wunit_to_pairing_info() helpers.
|
||||
*
|
||||
* @ngroups is here to help MTD users iterating over all the pages in a
|
||||
* given pair. This value can be retrieved by MTD users using the
|
||||
* mtd_pairing_groups() helper.
|
||||
*
|
||||
* Examples are given in the mtd_pairing_info_to_wunit() and
|
||||
* mtd_wunit_to_pairing_info() documentation.
|
||||
*/
|
||||
struct mtd_pairing_scheme {
|
||||
int ngroups;
|
||||
int (*get_info)(struct mtd_info *mtd, int wunit,
|
||||
struct mtd_pairing_info *info);
|
||||
int (*get_wunit)(struct mtd_info *mtd,
|
||||
const struct mtd_pairing_info *info);
|
||||
};
|
||||
|
||||
struct module; /* only needed for owner field in mtd_info */
|
||||
|
||||
/**
|
||||
* struct mtd_debug_info - debugging information for an MTD device.
|
||||
*
|
||||
* @dfs_dir: direntry object of the MTD device debugfs directory
|
||||
*/
|
||||
struct mtd_debug_info {
|
||||
struct dentry *dfs_dir;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mtd_part - MTD partition specific fields
|
||||
*
|
||||
* @node: list node used to add an MTD partition to the parent partition list
|
||||
* @offset: offset of the partition relatively to the parent offset
|
||||
* @size: partition size. Should be equal to mtd->size unless
|
||||
* MTD_SLC_ON_MLC_EMULATION is set
|
||||
* @flags: original flags (before the mtdpart logic decided to tweak them based
|
||||
* on flash constraints, like eraseblock/pagesize alignment)
|
||||
*
|
||||
* This struct is embedded in mtd_info and contains partition-specific
|
||||
* properties/fields.
|
||||
*/
|
||||
struct mtd_part {
|
||||
struct list_head node;
|
||||
u64 offset;
|
||||
u64 size;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mtd_master - MTD master specific fields
|
||||
*
|
||||
* @partitions_lock: lock protecting accesses to the partition list. Protects
|
||||
* not only the master partition list, but also all
|
||||
* sub-partitions.
|
||||
* @suspended: set to 1 when the device is suspended, 0 otherwise
|
||||
*
|
||||
* This struct is embedded in mtd_info and contains master-specific
|
||||
* properties/fields. The master is the root MTD device from the MTD partition
|
||||
* point of view.
|
||||
*/
|
||||
struct mtd_master {
|
||||
struct mutex partitions_lock;
|
||||
struct mutex chrdev_lock;
|
||||
unsigned int suspended : 1;
|
||||
};
|
||||
|
||||
struct mtd_info {
|
||||
u_char type;
|
||||
uint32_t flags;
|
||||
uint64_t size; // Total size of the MTD
|
||||
|
||||
/* "Major" erase size for the device. Naïve users may take this
|
||||
* to be the only erase size available, or may use the more detailed
|
||||
* information below if they desire
|
||||
*/
|
||||
uint32_t erasesize;
|
||||
/* Minimal writable flash unit size. In case of NOR flash it is 1 (even
|
||||
* though individual bits can be cleared), in case of NAND flash it is
|
||||
* one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR
|
||||
* it is of ECC block size, etc. It is illegal to have writesize = 0.
|
||||
* Any driver registering a struct mtd_info must ensure a writesize of
|
||||
* 1 or larger.
|
||||
*/
|
||||
uint32_t writesize;
|
||||
|
||||
/*
|
||||
* Size of the write buffer used by the MTD. MTD devices having a write
|
||||
* buffer can write multiple writesize chunks at a time. E.g. while
|
||||
* writing 4 * writesize bytes to a device with 2 * writesize bytes
|
||||
* buffer the MTD driver can (but doesn't have to) do 2 writesize
|
||||
* operations, but not 4. Currently, all NANDs have writebufsize
|
||||
* equivalent to writesize (NAND page size). Some NOR flashes do have
|
||||
* writebufsize greater than writesize.
|
||||
*/
|
||||
uint32_t writebufsize;
|
||||
|
||||
uint32_t oobsize; // Amount of OOB data per block (e.g. 16)
|
||||
uint32_t oobavail; // Available OOB bytes per block
|
||||
|
||||
/*
|
||||
* If erasesize is a power of 2 then the shift is stored in
|
||||
* erasesize_shift otherwise erasesize_shift is zero. Ditto writesize.
|
||||
*/
|
||||
unsigned int erasesize_shift;
|
||||
unsigned int writesize_shift;
|
||||
/* Masks based on erasesize_shift and writesize_shift */
|
||||
unsigned int erasesize_mask;
|
||||
unsigned int writesize_mask;
|
||||
|
||||
/*
|
||||
* read ops return -EUCLEAN if max number of bitflips corrected on any
|
||||
* one region comprising an ecc step equals or exceeds this value.
|
||||
* Settable by driver, else defaults to ecc_strength. User can override
|
||||
* in sysfs. N.B. The meaning of the -EUCLEAN return code has changed;
|
||||
* see Documentation/ABI/testing/sysfs-class-mtd for more detail.
|
||||
*/
|
||||
unsigned int bitflip_threshold;
|
||||
|
||||
/* Kernel-only stuff starts here. */
|
||||
const char *name;
|
||||
int index;
|
||||
|
||||
/* OOB layout description */
|
||||
const struct mtd_ooblayout_ops *ooblayout;
|
||||
|
||||
/* NAND pairing scheme, only provided for MLC/TLC NANDs */
|
||||
const struct mtd_pairing_scheme *pairing;
|
||||
|
||||
/* the ecc step size. */
|
||||
unsigned int ecc_step_size;
|
||||
|
||||
/* max number of correctible bit errors per ecc step */
|
||||
unsigned int ecc_strength;
|
||||
|
||||
/* Data for variable erase regions. If numeraseregions is zero,
|
||||
* it means that the whole device has erasesize as given above.
|
||||
*/
|
||||
int numeraseregions;
|
||||
struct mtd_erase_region_info *eraseregions;
|
||||
|
||||
/*
|
||||
* Do not call via these pointers, use corresponding mtd_*()
|
||||
* wrappers instead.
|
||||
*/
|
||||
int (*_erase) (struct mtd_info *mtd, struct erase_info *instr);
|
||||
int (*_point) (struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, void **virt, resource_size_t *phys);
|
||||
int (*_unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
|
||||
int (*_read) (struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf);
|
||||
int (*_write) (struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf);
|
||||
int (*_panic_write) (struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf);
|
||||
int (*_read_oob) (struct mtd_info *mtd, loff_t from,
|
||||
struct mtd_oob_ops *ops);
|
||||
int (*_write_oob) (struct mtd_info *mtd, loff_t to,
|
||||
struct mtd_oob_ops *ops);
|
||||
int (*_get_fact_prot_info) (struct mtd_info *mtd, size_t len,
|
||||
size_t *retlen, struct otp_info *buf);
|
||||
int (*_read_fact_prot_reg) (struct mtd_info *mtd, loff_t from,
|
||||
size_t len, size_t *retlen, u_char *buf);
|
||||
int (*_get_user_prot_info) (struct mtd_info *mtd, size_t len,
|
||||
size_t *retlen, struct otp_info *buf);
|
||||
int (*_read_user_prot_reg) (struct mtd_info *mtd, loff_t from,
|
||||
size_t len, size_t *retlen, u_char *buf);
|
||||
int (*_write_user_prot_reg) (struct mtd_info *mtd, loff_t to,
|
||||
size_t len, size_t *retlen,
|
||||
const u_char *buf);
|
||||
int (*_lock_user_prot_reg) (struct mtd_info *mtd, loff_t from,
|
||||
size_t len);
|
||||
int (*_erase_user_prot_reg) (struct mtd_info *mtd, loff_t from,
|
||||
size_t len);
|
||||
int (*_writev) (struct mtd_info *mtd, const struct kvec *vecs,
|
||||
unsigned long count, loff_t to, size_t *retlen);
|
||||
void (*_sync) (struct mtd_info *mtd);
|
||||
int (*_lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int (*_unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int (*_is_locked) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int (*_block_isreserved) (struct mtd_info *mtd, loff_t ofs);
|
||||
int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);
|
||||
int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
|
||||
int (*_max_bad_blocks) (struct mtd_info *mtd, loff_t ofs, size_t len);
|
||||
int (*_suspend) (struct mtd_info *mtd);
|
||||
void (*_resume) (struct mtd_info *mtd);
|
||||
void (*_reboot) (struct mtd_info *mtd);
|
||||
/*
|
||||
* If the driver is something smart, like UBI, it may need to maintain
|
||||
* its own reference counting. The below functions are only for driver.
|
||||
*/
|
||||
int (*_get_device) (struct mtd_info *mtd);
|
||||
void (*_put_device) (struct mtd_info *mtd);
|
||||
|
||||
/*
|
||||
* flag indicates a panic write, low level drivers can take appropriate
|
||||
* action if required to ensure writes go through
|
||||
*/
|
||||
bool oops_panic_write;
|
||||
|
||||
struct notifier_block reboot_notifier; /* default mode before reboot */
|
||||
|
||||
/* ECC status information */
|
||||
struct mtd_ecc_stats ecc_stats;
|
||||
/* Subpage shift (NAND) */
|
||||
int subpage_sft;
|
||||
|
||||
void *priv;
|
||||
|
||||
struct module *owner;
|
||||
struct device dev;
|
||||
struct kref refcnt;
|
||||
struct mtd_debug_info dbg;
|
||||
struct nvmem_device *nvmem;
|
||||
struct nvmem_device *otp_user_nvmem;
|
||||
struct nvmem_device *otp_factory_nvmem;
|
||||
|
||||
/*
|
||||
* Parent device from the MTD partition point of view.
|
||||
*
|
||||
* MTD masters do not have any parent, MTD partitions do. The parent
|
||||
* MTD device can itself be a partition.
|
||||
*/
|
||||
struct mtd_info *parent;
|
||||
|
||||
/* List of partitions attached to this MTD device */
|
||||
struct list_head partitions;
|
||||
|
||||
struct mtd_part part;
|
||||
struct mtd_master master;
|
||||
};
|
||||
|
||||
static inline struct mtd_info *mtd_get_master(struct mtd_info *mtd)
|
||||
{
|
||||
while (mtd->parent)
|
||||
mtd = mtd->parent;
|
||||
|
||||
return mtd;
|
||||
}
|
||||
|
||||
static inline u64 mtd_get_master_ofs(struct mtd_info *mtd, u64 ofs)
|
||||
{
|
||||
while (mtd->parent) {
|
||||
ofs += mtd->part.offset;
|
||||
mtd = mtd->parent;
|
||||
}
|
||||
|
||||
return ofs;
|
||||
}
|
||||
|
||||
static inline bool mtd_is_partition(const struct mtd_info *mtd)
|
||||
{
|
||||
return mtd->parent;
|
||||
}
|
||||
|
||||
static inline bool mtd_has_partitions(const struct mtd_info *mtd)
|
||||
{
|
||||
return !list_empty(&mtd->partitions);
|
||||
}
|
||||
|
||||
int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *oobecc);
|
||||
int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte,
|
||||
int *section,
|
||||
struct mtd_oob_region *oobregion);
|
||||
int mtd_ooblayout_get_eccbytes(struct mtd_info *mtd, u8 *eccbuf,
|
||||
const u8 *oobbuf, int start, int nbytes);
|
||||
int mtd_ooblayout_set_eccbytes(struct mtd_info *mtd, const u8 *eccbuf,
|
||||
u8 *oobbuf, int start, int nbytes);
|
||||
int mtd_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *oobfree);
|
||||
int mtd_ooblayout_get_databytes(struct mtd_info *mtd, u8 *databuf,
|
||||
const u8 *oobbuf, int start, int nbytes);
|
||||
int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf,
|
||||
u8 *oobbuf, int start, int nbytes);
|
||||
int mtd_ooblayout_count_freebytes(struct mtd_info *mtd);
|
||||
int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd);
|
||||
|
||||
static inline void mtd_set_ooblayout(struct mtd_info *mtd,
|
||||
const struct mtd_ooblayout_ops *ooblayout)
|
||||
{
|
||||
mtd->ooblayout = ooblayout;
|
||||
}
|
||||
|
||||
static inline void mtd_set_pairing_scheme(struct mtd_info *mtd,
|
||||
const struct mtd_pairing_scheme *pairing)
|
||||
{
|
||||
mtd->pairing = pairing;
|
||||
}
|
||||
|
||||
static inline void mtd_set_of_node(struct mtd_info *mtd,
|
||||
struct device_node *np)
|
||||
{
|
||||
mtd->dev.of_node = np;
|
||||
if (!mtd->name)
|
||||
of_property_read_string(np, "label", &mtd->name);
|
||||
}
|
||||
|
||||
static inline struct device_node *mtd_get_of_node(struct mtd_info *mtd)
|
||||
{
|
||||
return dev_of_node(&mtd->dev);
|
||||
}
|
||||
|
||||
static inline u32 mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
|
||||
{
|
||||
return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize;
|
||||
}
|
||||
|
||||
static inline int mtd_max_bad_blocks(struct mtd_info *mtd,
|
||||
loff_t ofs, size_t len)
|
||||
{
|
||||
struct mtd_info *master = mtd_get_master(mtd);
|
||||
|
||||
if (!master->_max_bad_blocks)
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (mtd->size < (len + ofs) || ofs < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return master->_max_bad_blocks(master, mtd_get_master_ofs(mtd, ofs),
|
||||
len);
|
||||
}
|
||||
|
||||
int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit,
|
||||
struct mtd_pairing_info *info);
|
||||
int mtd_pairing_info_to_wunit(struct mtd_info *mtd,
|
||||
const struct mtd_pairing_info *info);
|
||||
int mtd_pairing_groups(struct mtd_info *mtd);
|
||||
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
|
||||
int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
||||
void **virt, resource_size_t *phys);
|
||||
int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len);
|
||||
unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, unsigned long len,
|
||||
unsigned long offset, unsigned long flags);
|
||||
int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
||||
u_char *buf);
|
||||
int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||
const u_char *buf);
|
||||
int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||
const u_char *buf);
|
||||
|
||||
int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops);
|
||||
int mtd_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops);
|
||||
|
||||
int mtd_get_fact_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen,
|
||||
struct otp_info *buf);
|
||||
int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf);
|
||||
int mtd_get_user_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen,
|
||||
struct otp_info *buf);
|
||||
int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf);
|
||||
int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf);
|
||||
int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len);
|
||||
int mtd_erase_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len);
|
||||
|
||||
int mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
|
||||
unsigned long count, loff_t to, size_t *retlen);
|
||||
|
||||
static inline void mtd_sync(struct mtd_info *mtd)
|
||||
{
|
||||
struct mtd_info *master = mtd_get_master(mtd);
|
||||
|
||||
if (master->_sync)
|
||||
master->_sync(master);
|
||||
}
|
||||
|
||||
int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int mtd_block_isreserved(struct mtd_info *mtd, loff_t ofs);
|
||||
int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs);
|
||||
int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs);
|
||||
|
||||
static inline int mtd_suspend(struct mtd_info *mtd)
|
||||
{
|
||||
struct mtd_info *master = mtd_get_master(mtd);
|
||||
int ret;
|
||||
|
||||
if (master->master.suspended)
|
||||
return 0;
|
||||
|
||||
ret = master->_suspend ? master->_suspend(master) : 0;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
master->master.suspended = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mtd_resume(struct mtd_info *mtd)
|
||||
{
|
||||
struct mtd_info *master = mtd_get_master(mtd);
|
||||
|
||||
if (!master->master.suspended)
|
||||
return;
|
||||
|
||||
if (master->_resume)
|
||||
master->_resume(master);
|
||||
|
||||
master->master.suspended = 0;
|
||||
}
|
||||
|
||||
static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd)
|
||||
{
|
||||
if (mtd->erasesize_shift)
|
||||
return sz >> mtd->erasesize_shift;
|
||||
do_div(sz, mtd->erasesize);
|
||||
return sz;
|
||||
}
|
||||
|
||||
static inline uint32_t mtd_mod_by_eb(uint64_t sz, struct mtd_info *mtd)
|
||||
{
|
||||
if (mtd->erasesize_shift)
|
||||
return sz & mtd->erasesize_mask;
|
||||
return do_div(sz, mtd->erasesize);
|
||||
}
|
||||
|
||||
/**
|
||||
* mtd_align_erase_req - Adjust an erase request to align things on eraseblock
|
||||
* boundaries.
|
||||
* @mtd: the MTD device this erase request applies on
|
||||
* @req: the erase request to adjust
|
||||
*
|
||||
* This function will adjust @req->addr and @req->len to align them on
|
||||
* @mtd->erasesize. Of course we expect @mtd->erasesize to be != 0.
|
||||
*/
|
||||
static inline void mtd_align_erase_req(struct mtd_info *mtd,
|
||||
struct erase_info *req)
|
||||
{
|
||||
u32 mod;
|
||||
|
||||
if (WARN_ON(!mtd->erasesize))
|
||||
return;
|
||||
|
||||
mod = mtd_mod_by_eb(req->addr, mtd);
|
||||
if (mod) {
|
||||
req->addr -= mod;
|
||||
req->len += mod;
|
||||
}
|
||||
|
||||
mod = mtd_mod_by_eb(req->addr + req->len, mtd);
|
||||
if (mod)
|
||||
req->len += mtd->erasesize - mod;
|
||||
}
|
||||
|
||||
static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd)
|
||||
{
|
||||
if (mtd->writesize_shift)
|
||||
return sz >> mtd->writesize_shift;
|
||||
do_div(sz, mtd->writesize);
|
||||
return sz;
|
||||
}
|
||||
|
||||
static inline uint32_t mtd_mod_by_ws(uint64_t sz, struct mtd_info *mtd)
|
||||
{
|
||||
if (mtd->writesize_shift)
|
||||
return sz & mtd->writesize_mask;
|
||||
return do_div(sz, mtd->writesize);
|
||||
}
|
||||
|
||||
static inline int mtd_wunit_per_eb(struct mtd_info *mtd)
|
||||
{
|
||||
struct mtd_info *master = mtd_get_master(mtd);
|
||||
|
||||
return master->erasesize / mtd->writesize;
|
||||
}
|
||||
|
||||
static inline int mtd_offset_to_wunit(struct mtd_info *mtd, loff_t offs)
|
||||
{
|
||||
return mtd_div_by_ws(mtd_mod_by_eb(offs, mtd), mtd);
|
||||
}
|
||||
|
||||
static inline loff_t mtd_wunit_to_offset(struct mtd_info *mtd, loff_t base,
|
||||
int wunit)
|
||||
{
|
||||
return base + (wunit * mtd->writesize);
|
||||
}
|
||||
|
||||
|
||||
static inline int mtd_has_oob(const struct mtd_info *mtd)
|
||||
{
|
||||
struct mtd_info *master = mtd_get_master((struct mtd_info *)mtd);
|
||||
|
||||
return master->_read_oob && master->_write_oob;
|
||||
}
|
||||
|
||||
static inline int mtd_type_is_nand(const struct mtd_info *mtd)
|
||||
{
|
||||
return mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH;
|
||||
}
|
||||
|
||||
static inline int mtd_can_have_bb(const struct mtd_info *mtd)
|
||||
{
|
||||
struct mtd_info *master = mtd_get_master((struct mtd_info *)mtd);
|
||||
|
||||
return !!master->_block_isbad;
|
||||
}
|
||||
|
||||
/* Kernel-side ioctl definitions */
|
||||
|
||||
struct mtd_partition;
|
||||
struct mtd_part_parser_data;
|
||||
|
||||
extern int mtd_device_parse_register(struct mtd_info *mtd,
|
||||
const char * const *part_probe_types,
|
||||
struct mtd_part_parser_data *parser_data,
|
||||
const struct mtd_partition *defparts,
|
||||
int defnr_parts);
|
||||
#define mtd_device_register(master, parts, nr_parts) \
|
||||
mtd_device_parse_register(master, NULL, NULL, parts, nr_parts)
|
||||
extern int mtd_device_unregister(struct mtd_info *master);
|
||||
extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num);
|
||||
extern int __get_mtd_device(struct mtd_info *mtd);
|
||||
extern void __put_mtd_device(struct mtd_info *mtd);
|
||||
extern struct mtd_info *of_get_mtd_device_by_node(struct device_node *np);
|
||||
extern struct mtd_info *get_mtd_device_nm(const char *name);
|
||||
extern void put_mtd_device(struct mtd_info *mtd);
|
||||
|
||||
|
||||
struct mtd_notifier {
|
||||
void (*add)(struct mtd_info *mtd);
|
||||
void (*remove)(struct mtd_info *mtd);
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
|
||||
extern void register_mtd_user (struct mtd_notifier *new);
|
||||
extern int unregister_mtd_user (struct mtd_notifier *old);
|
||||
void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size);
|
||||
|
||||
static inline int mtd_is_bitflip(int err) {
|
||||
return err == -EUCLEAN;
|
||||
}
|
||||
|
||||
static inline int mtd_is_eccerr(int err) {
|
||||
return err == -EBADMSG;
|
||||
}
|
||||
|
||||
static inline int mtd_is_bitflip_or_eccerr(int err) {
|
||||
return mtd_is_bitflip(err) || mtd_is_eccerr(err);
|
||||
}
|
||||
|
||||
unsigned mtd_mmap_capabilities(struct mtd_info *mtd);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
bool mtd_check_expert_analysis_mode(void);
|
||||
#else
|
||||
static inline bool mtd_check_expert_analysis_mode(void) { return false; }
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __MTD_MTD_H__ */
|
||||
@@ -0,0 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __MTD_MTDRAM_H__
|
||||
#define __MTD_MTDRAM_H__
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
|
||||
unsigned long size, const char *name);
|
||||
|
||||
#endif /* __MTD_MTDRAM_H__ */
|
||||
@@ -0,0 +1,47 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
|
||||
/*
|
||||
* MTK SDG1 ECC controller
|
||||
*
|
||||
* Copyright (c) 2016 Mediatek
|
||||
* Authors: Xiaolei Li <xiaolei.li@mediatek.com>
|
||||
* Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
|
||||
*/
|
||||
|
||||
#ifndef __DRIVERS_MTD_NAND_MTK_ECC_H__
|
||||
#define __DRIVERS_MTD_NAND_MTK_ECC_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1};
|
||||
enum mtk_ecc_operation {ECC_ENCODE, ECC_DECODE};
|
||||
|
||||
struct device_node;
|
||||
struct mtk_ecc;
|
||||
|
||||
struct mtk_ecc_stats {
|
||||
u32 corrected;
|
||||
u32 bitflips;
|
||||
u32 failed;
|
||||
};
|
||||
|
||||
struct mtk_ecc_config {
|
||||
enum mtk_ecc_operation op;
|
||||
enum mtk_ecc_mode mode;
|
||||
dma_addr_t addr;
|
||||
u32 strength;
|
||||
u32 sectors;
|
||||
u32 len;
|
||||
};
|
||||
|
||||
int mtk_ecc_encode(struct mtk_ecc *, struct mtk_ecc_config *, u8 *, u32);
|
||||
void mtk_ecc_get_stats(struct mtk_ecc *, struct mtk_ecc_stats *, int);
|
||||
int mtk_ecc_wait_done(struct mtk_ecc *, enum mtk_ecc_operation);
|
||||
int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *);
|
||||
void mtk_ecc_disable(struct mtk_ecc *);
|
||||
void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p);
|
||||
unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc);
|
||||
|
||||
struct mtk_ecc *of_mtk_ecc_get(struct device_node *);
|
||||
void mtk_ecc_release(struct mtk_ecc *);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright © 2019 Macronix
|
||||
* Author: Miquèl Raynal <miquel.raynal@bootlin.com>
|
||||
*
|
||||
* Header for the Macronix external ECC engine.
|
||||
*/
|
||||
|
||||
#ifndef __MTD_NAND_ECC_MXIC_H__
|
||||
#define __MTD_NAND_ECC_MXIC_H__
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
struct mxic_ecc_engine;
|
||||
|
||||
#if IS_ENABLED(CONFIG_MTD_NAND_ECC_MXIC) && IS_REACHABLE(CONFIG_MTD_NAND_CORE)
|
||||
|
||||
const struct nand_ecc_engine_ops *mxic_ecc_get_pipelined_ops(void);
|
||||
struct nand_ecc_engine *mxic_ecc_get_pipelined_engine(struct platform_device *spi_pdev);
|
||||
void mxic_ecc_put_pipelined_engine(struct nand_ecc_engine *eng);
|
||||
int mxic_ecc_process_data_pipelined(struct nand_ecc_engine *eng,
|
||||
unsigned int direction, dma_addr_t dirmap);
|
||||
|
||||
#else /* !CONFIG_MTD_NAND_ECC_MXIC */
|
||||
|
||||
static inline const struct nand_ecc_engine_ops *mxic_ecc_get_pipelined_ops(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct nand_ecc_engine *
|
||||
mxic_ecc_get_pipelined_engine(struct platform_device *spi_pdev)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline void mxic_ecc_put_pipelined_engine(struct nand_ecc_engine *eng) {}
|
||||
|
||||
static inline int mxic_ecc_process_data_pipelined(struct nand_ecc_engine *eng,
|
||||
unsigned int direction,
|
||||
dma_addr_t dirmap)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MTD_NAND_ECC_MXIC */
|
||||
|
||||
#endif /* __MTD_NAND_ECC_MXIC_H__ */
|
||||
@@ -0,0 +1,71 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com>
|
||||
*
|
||||
* This file is the header for the NAND BCH ECC implementation.
|
||||
*/
|
||||
|
||||
#ifndef __MTD_NAND_ECC_SW_BCH_H__
|
||||
#define __MTD_NAND_ECC_SW_BCH_H__
|
||||
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/bch.h>
|
||||
|
||||
/**
|
||||
* struct nand_ecc_sw_bch_conf - private software BCH ECC engine structure
|
||||
* @req_ctx: Save request context and tweak the original request to fit the
|
||||
* engine needs
|
||||
* @code_size: Number of bytes needed to store a code (one code per step)
|
||||
* @calc_buf: Buffer to use when calculating ECC bytes
|
||||
* @code_buf: Buffer to use when reading (raw) ECC bytes from the chip
|
||||
* @bch: BCH control structure
|
||||
* @errloc: error location array
|
||||
* @eccmask: XOR ecc mask, allows erased pages to be decoded as valid
|
||||
*/
|
||||
struct nand_ecc_sw_bch_conf {
|
||||
struct nand_ecc_req_tweak_ctx req_ctx;
|
||||
unsigned int code_size;
|
||||
u8 *calc_buf;
|
||||
u8 *code_buf;
|
||||
struct bch_control *bch;
|
||||
unsigned int *errloc;
|
||||
unsigned char *eccmask;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_BCH)
|
||||
|
||||
int nand_ecc_sw_bch_calculate(struct nand_device *nand,
|
||||
const unsigned char *buf, unsigned char *code);
|
||||
int nand_ecc_sw_bch_correct(struct nand_device *nand, unsigned char *buf,
|
||||
unsigned char *read_ecc, unsigned char *calc_ecc);
|
||||
int nand_ecc_sw_bch_init_ctx(struct nand_device *nand);
|
||||
void nand_ecc_sw_bch_cleanup_ctx(struct nand_device *nand);
|
||||
struct nand_ecc_engine *nand_ecc_sw_bch_get_engine(void);
|
||||
|
||||
#else /* !CONFIG_MTD_NAND_ECC_SW_BCH */
|
||||
|
||||
static inline int nand_ecc_sw_bch_calculate(struct nand_device *nand,
|
||||
const unsigned char *buf,
|
||||
unsigned char *code)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline int nand_ecc_sw_bch_correct(struct nand_device *nand,
|
||||
unsigned char *buf,
|
||||
unsigned char *read_ecc,
|
||||
unsigned char *calc_ecc)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline int nand_ecc_sw_bch_init_ctx(struct nand_device *nand)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline void nand_ecc_sw_bch_cleanup_ctx(struct nand_device *nand) {}
|
||||
|
||||
#endif /* CONFIG_MTD_NAND_ECC_SW_BCH */
|
||||
|
||||
#endif /* __MTD_NAND_ECC_SW_BCH_H__ */
|
||||
@@ -0,0 +1,89 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2000-2010 Steven J. Hill <sjhill@realitydiluted.com>
|
||||
* David Woodhouse <dwmw2@infradead.org>
|
||||
* Thomas Gleixner <tglx@kernel.org>
|
||||
*
|
||||
* This file is the header for the NAND Hamming ECC implementation.
|
||||
*/
|
||||
|
||||
#ifndef __MTD_NAND_ECC_SW_HAMMING_H__
|
||||
#define __MTD_NAND_ECC_SW_HAMMING_H__
|
||||
|
||||
#include <linux/mtd/nand.h>
|
||||
|
||||
/**
|
||||
* struct nand_ecc_sw_hamming_conf - private software Hamming ECC engine structure
|
||||
* @req_ctx: Save request context and tweak the original request to fit the
|
||||
* engine needs
|
||||
* @code_size: Number of bytes needed to store a code (one code per step)
|
||||
* @calc_buf: Buffer to use when calculating ECC bytes
|
||||
* @code_buf: Buffer to use when reading (raw) ECC bytes from the chip
|
||||
* @sm_order: Smart Media special ordering
|
||||
*/
|
||||
struct nand_ecc_sw_hamming_conf {
|
||||
struct nand_ecc_req_tweak_ctx req_ctx;
|
||||
unsigned int code_size;
|
||||
u8 *calc_buf;
|
||||
u8 *code_buf;
|
||||
unsigned int sm_order;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING)
|
||||
|
||||
int nand_ecc_sw_hamming_init_ctx(struct nand_device *nand);
|
||||
void nand_ecc_sw_hamming_cleanup_ctx(struct nand_device *nand);
|
||||
int ecc_sw_hamming_calculate(const unsigned char *buf, unsigned int step_size,
|
||||
unsigned char *code, bool sm_order);
|
||||
int nand_ecc_sw_hamming_calculate(struct nand_device *nand,
|
||||
const unsigned char *buf,
|
||||
unsigned char *code);
|
||||
int ecc_sw_hamming_correct(unsigned char *buf, unsigned char *read_ecc,
|
||||
unsigned char *calc_ecc, unsigned int step_size,
|
||||
bool sm_order);
|
||||
int nand_ecc_sw_hamming_correct(struct nand_device *nand, unsigned char *buf,
|
||||
unsigned char *read_ecc,
|
||||
unsigned char *calc_ecc);
|
||||
|
||||
#else /* !CONFIG_MTD_NAND_ECC_SW_HAMMING */
|
||||
|
||||
static inline int nand_ecc_sw_hamming_init_ctx(struct nand_device *nand)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline void nand_ecc_sw_hamming_cleanup_ctx(struct nand_device *nand) {}
|
||||
|
||||
static inline int ecc_sw_hamming_calculate(const unsigned char *buf,
|
||||
unsigned int step_size,
|
||||
unsigned char *code, bool sm_order)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline int nand_ecc_sw_hamming_calculate(struct nand_device *nand,
|
||||
const unsigned char *buf,
|
||||
unsigned char *code)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline int ecc_sw_hamming_correct(unsigned char *buf,
|
||||
unsigned char *read_ecc,
|
||||
unsigned char *calc_ecc,
|
||||
unsigned int step_size, bool sm_order)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline int nand_ecc_sw_hamming_correct(struct nand_device *nand,
|
||||
unsigned char *buf,
|
||||
unsigned char *read_ecc,
|
||||
unsigned char *calc_ecc)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MTD_NAND_ECC_SW_HAMMING */
|
||||
|
||||
#endif /* __MTD_NAND_ECC_SW_HAMMING_H__ */
|
||||
@@ -0,0 +1,15 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __LINUX_MTD_NAND_GPIO_H
|
||||
#define __LINUX_MTD_NAND_GPIO_H
|
||||
|
||||
#include <linux/mtd/rawnand.h>
|
||||
|
||||
struct gpio_nand_platdata {
|
||||
void (*adjust_parts)(struct gpio_nand_platdata *, size_t);
|
||||
struct mtd_partition *parts;
|
||||
unsigned int num_parts;
|
||||
unsigned int options;
|
||||
int chip_delay;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,483 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* QCOM QPIC common APIs header file
|
||||
*
|
||||
* Copyright (c) 2023 Qualcomm Inc.
|
||||
* Authors: Md sadre Alam <quic_mdalam@quicinc.com>
|
||||
*
|
||||
*/
|
||||
#ifndef __MTD_NAND_QPIC_COMMON_H__
|
||||
#define __MTD_NAND_QPIC_COMMON_H__
|
||||
|
||||
/* NANDc reg offsets */
|
||||
#define NAND_FLASH_CMD 0x00
|
||||
#define NAND_ADDR0 0x04
|
||||
#define NAND_ADDR1 0x08
|
||||
#define NAND_FLASH_CHIP_SELECT 0x0c
|
||||
#define NAND_EXEC_CMD 0x10
|
||||
#define NAND_FLASH_STATUS 0x14
|
||||
#define NAND_BUFFER_STATUS 0x18
|
||||
#define NAND_DEV0_CFG0 0x20
|
||||
#define NAND_DEV0_CFG1 0x24
|
||||
#define NAND_DEV0_ECC_CFG 0x28
|
||||
#define NAND_AUTO_STATUS_EN 0x2c
|
||||
#define NAND_DEV1_CFG0 0x30
|
||||
#define NAND_DEV1_CFG1 0x34
|
||||
#define NAND_READ_ID 0x40
|
||||
#define NAND_READ_STATUS 0x44
|
||||
#define NAND_DEV_CMD0 0xa0
|
||||
#define NAND_DEV_CMD1 0xa4
|
||||
#define NAND_DEV_CMD2 0xa8
|
||||
#define NAND_DEV_CMD_VLD 0xac
|
||||
#define SFLASHC_BURST_CFG 0xe0
|
||||
#define NAND_ERASED_CW_DETECT_CFG 0xe8
|
||||
#define NAND_ERASED_CW_DETECT_STATUS 0xec
|
||||
#define NAND_EBI2_ECC_BUF_CFG 0xf0
|
||||
#define FLASH_BUF_ACC 0x100
|
||||
|
||||
#define NAND_CTRL 0xf00
|
||||
#define NAND_VERSION 0xf08
|
||||
#define NAND_READ_LOCATION_0 0xf20
|
||||
#define NAND_READ_LOCATION_1 0xf24
|
||||
#define NAND_READ_LOCATION_2 0xf28
|
||||
#define NAND_READ_LOCATION_3 0xf2c
|
||||
#define NAND_READ_LOCATION_LAST_CW_0 0xf40
|
||||
#define NAND_READ_LOCATION_LAST_CW_1 0xf44
|
||||
#define NAND_READ_LOCATION_LAST_CW_2 0xf48
|
||||
#define NAND_READ_LOCATION_LAST_CW_3 0xf4c
|
||||
|
||||
/* dummy register offsets, used by qcom_write_reg_dma */
|
||||
#define NAND_DEV_CMD1_RESTORE 0xdead
|
||||
#define NAND_DEV_CMD_VLD_RESTORE 0xbeef
|
||||
|
||||
/* NAND_FLASH_CMD bits */
|
||||
#define PAGE_ACC BIT(4)
|
||||
#define LAST_PAGE BIT(5)
|
||||
|
||||
/* NAND_FLASH_CHIP_SELECT bits */
|
||||
#define NAND_DEV_SEL 0
|
||||
#define DM_EN BIT(2)
|
||||
|
||||
/* NAND_FLASH_STATUS bits */
|
||||
#define FS_OP_ERR BIT(4)
|
||||
#define FS_READY_BSY_N BIT(5)
|
||||
#define FS_MPU_ERR BIT(8)
|
||||
#define FS_DEVICE_STS_ERR BIT(16)
|
||||
#define FS_DEVICE_WP BIT(23)
|
||||
|
||||
/* NAND_BUFFER_STATUS bits */
|
||||
#define BS_UNCORRECTABLE_BIT BIT(8)
|
||||
#define BS_CORRECTABLE_ERR_MSK 0x1f
|
||||
|
||||
/* NAND_DEVn_CFG0 bits */
|
||||
#define DISABLE_STATUS_AFTER_WRITE BIT(4)
|
||||
#define CW_PER_PAGE_MASK GENMASK(8, 6)
|
||||
#define UD_SIZE_BYTES_MASK GENMASK(18, 9)
|
||||
#define ECC_PARITY_SIZE_BYTES_RS GENMASK(22, 19)
|
||||
#define SPARE_SIZE_BYTES_MASK GENMASK(26, 23)
|
||||
#define NUM_ADDR_CYCLES_MASK GENMASK(29, 27)
|
||||
#define STATUS_BFR_READ BIT(30)
|
||||
#define SET_RD_MODE_AFTER_STATUS BIT(31)
|
||||
|
||||
/* NAND_DEVn_CFG0 bits */
|
||||
#define DEV0_CFG1_ECC_DISABLE BIT(0)
|
||||
#define WIDE_FLASH BIT(1)
|
||||
#define NAND_RECOVERY_CYCLES_MASK GENMASK(4, 2)
|
||||
#define CS_ACTIVE_BSY BIT(5)
|
||||
#define BAD_BLOCK_BYTE_NUM_MASK GENMASK(15, 6)
|
||||
#define BAD_BLOCK_IN_SPARE_AREA BIT(16)
|
||||
#define WR_RD_BSY_GAP_MASK GENMASK(22, 17)
|
||||
#define ENABLE_BCH_ECC BIT(27)
|
||||
|
||||
/* NAND_DEV0_ECC_CFG bits */
|
||||
#define ECC_CFG_ECC_DISABLE BIT(0)
|
||||
#define ECC_SW_RESET BIT(1)
|
||||
#define ECC_MODE_MASK GENMASK(5, 4)
|
||||
#define ECC_MODE_4BIT 0
|
||||
#define ECC_MODE_8BIT 1
|
||||
#define ECC_PARITY_SIZE_BYTES_BCH_MASK GENMASK(12, 8)
|
||||
#define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16)
|
||||
#define ECC_FORCE_CLK_OPEN BIT(30)
|
||||
|
||||
/* NAND_DEV_CMD1 bits */
|
||||
#define READ_ADDR_MASK GENMASK(7, 0)
|
||||
|
||||
/* NAND_DEV_CMD_VLD bits */
|
||||
#define READ_START_VLD BIT(0)
|
||||
#define READ_STOP_VLD BIT(1)
|
||||
#define WRITE_START_VLD BIT(2)
|
||||
#define ERASE_START_VLD BIT(3)
|
||||
#define SEQ_READ_START_VLD BIT(4)
|
||||
|
||||
/* NAND_EBI2_ECC_BUF_CFG bits */
|
||||
#define NUM_STEPS_MASK GENMASK(9, 0)
|
||||
|
||||
/* NAND_ERASED_CW_DETECT_CFG bits */
|
||||
#define ERASED_CW_ECC_MASK 1
|
||||
#define AUTO_DETECT_RES 0
|
||||
#define MASK_ECC BIT(ERASED_CW_ECC_MASK)
|
||||
#define RESET_ERASED_DET BIT(AUTO_DETECT_RES)
|
||||
#define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES)
|
||||
#define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC)
|
||||
#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC)
|
||||
|
||||
/* NAND_ERASED_CW_DETECT_STATUS bits */
|
||||
#define PAGE_ALL_ERASED BIT(7)
|
||||
#define CODEWORD_ALL_ERASED BIT(6)
|
||||
#define PAGE_ERASED BIT(5)
|
||||
#define CODEWORD_ERASED BIT(4)
|
||||
#define ERASED_PAGE (PAGE_ALL_ERASED | PAGE_ERASED)
|
||||
#define ERASED_CW (CODEWORD_ALL_ERASED | CODEWORD_ERASED)
|
||||
|
||||
/* NAND_READ_LOCATION_n bits */
|
||||
#define READ_LOCATION_OFFSET_MASK GENMASK(9, 0)
|
||||
#define READ_LOCATION_SIZE_MASK GENMASK(25, 16)
|
||||
#define READ_LOCATION_LAST_MASK BIT(31)
|
||||
|
||||
/* Version Mask */
|
||||
#define NAND_VERSION_MAJOR_MASK 0xf0000000
|
||||
#define NAND_VERSION_MAJOR_SHIFT 28
|
||||
#define NAND_VERSION_MINOR_MASK 0x0fff0000
|
||||
#define NAND_VERSION_MINOR_SHIFT 16
|
||||
|
||||
/* NAND OP_CMDs */
|
||||
#define OP_PAGE_READ 0x2
|
||||
#define OP_PAGE_READ_WITH_ECC 0x3
|
||||
#define OP_PAGE_READ_WITH_ECC_SPARE 0x4
|
||||
#define OP_PAGE_READ_ONFI_READ 0x5
|
||||
#define OP_PROGRAM_PAGE 0x6
|
||||
#define OP_PAGE_PROGRAM_WITH_ECC 0x7
|
||||
#define OP_PROGRAM_PAGE_SPARE 0x9
|
||||
#define OP_BLOCK_ERASE 0xa
|
||||
#define OP_CHECK_STATUS 0xc
|
||||
#define OP_FETCH_ID 0xb
|
||||
#define OP_RESET_DEVICE 0xd
|
||||
|
||||
/* Default Value for NAND_DEV_CMD_VLD */
|
||||
#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \
|
||||
ERASE_START_VLD | SEQ_READ_START_VLD)
|
||||
|
||||
/* NAND_CTRL bits */
|
||||
#define BAM_MODE_EN BIT(0)
|
||||
|
||||
/*
|
||||
* the NAND controller performs reads/writes with ECC in 516 byte chunks.
|
||||
* the driver calls the chunks 'step' or 'codeword' interchangeably
|
||||
*/
|
||||
#define NANDC_STEP_SIZE 512
|
||||
|
||||
/*
|
||||
* the largest page size we support is 8K, this will have 16 steps/codewords
|
||||
* of 512 bytes each
|
||||
*/
|
||||
#define MAX_NUM_STEPS (SZ_8K / NANDC_STEP_SIZE)
|
||||
|
||||
/* we read at most 3 registers per codeword scan */
|
||||
#define MAX_REG_RD (3 * MAX_NUM_STEPS)
|
||||
|
||||
/* ECC modes supported by the controller */
|
||||
#define ECC_NONE BIT(0)
|
||||
#define ECC_RS_4BIT BIT(1)
|
||||
#define ECC_BCH_4BIT BIT(2)
|
||||
#define ECC_BCH_8BIT BIT(3)
|
||||
|
||||
/*
|
||||
* Returns the actual register address for all NAND_DEV_ registers
|
||||
* (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
|
||||
*/
|
||||
#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
|
||||
|
||||
/* Returns the dma address for reg read buffer */
|
||||
#define reg_buf_dma_addr(chip, vaddr) \
|
||||
((chip)->reg_read_dma + \
|
||||
((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf))
|
||||
|
||||
#define QPIC_PER_CW_CMD_ELEMENTS 32
|
||||
#define QPIC_PER_CW_CMD_SGL 32
|
||||
#define QPIC_PER_CW_DATA_SGL 8
|
||||
|
||||
#define QPIC_NAND_COMPLETION_TIMEOUT msecs_to_jiffies(2000)
|
||||
|
||||
/*
|
||||
* Flags used in DMA descriptor preparation helper functions
|
||||
* (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma)
|
||||
*/
|
||||
/* Don't set the EOT in current tx BAM sgl */
|
||||
#define NAND_BAM_NO_EOT BIT(0)
|
||||
/* Set the NWD flag in current BAM sgl */
|
||||
#define NAND_BAM_NWD BIT(1)
|
||||
/* Finish writing in the current BAM sgl and start writing in another BAM sgl */
|
||||
#define NAND_BAM_NEXT_SGL BIT(2)
|
||||
/*
|
||||
* Erased codeword status is being used two times in single transfer so this
|
||||
* flag will determine the current value of erased codeword status register
|
||||
*/
|
||||
#define NAND_ERASED_CW_SET BIT(4)
|
||||
|
||||
#define MAX_ADDRESS_CYCLE 5
|
||||
|
||||
/*
|
||||
* This data type corresponds to the BAM transaction which will be used for all
|
||||
* NAND transfers.
|
||||
* @bam_ce - the array of BAM command elements
|
||||
* @cmd_sgl - sgl for NAND BAM command pipe
|
||||
* @data_sgl - sgl for NAND BAM consumer/producer pipe
|
||||
* @last_data_desc - last DMA desc in data channel (tx/rx).
|
||||
* @last_cmd_desc - last DMA desc in command channel.
|
||||
* @txn_done - completion for NAND transfer.
|
||||
* @bam_ce_nitems - the number of elements in the @bam_ce array
|
||||
* @cmd_sgl_nitems - the number of elements in the @cmd_sgl array
|
||||
* @data_sgl_nitems - the number of elements in the @data_sgl array
|
||||
* @bam_ce_pos - the index in bam_ce which is available for next sgl
|
||||
* @bam_ce_start - the index in bam_ce which marks the start position ce
|
||||
* for current sgl. It will be used for size calculation
|
||||
* for current sgl
|
||||
* @cmd_sgl_pos - current index in command sgl.
|
||||
* @cmd_sgl_start - start index in command sgl.
|
||||
* @tx_sgl_pos - current index in data sgl for tx.
|
||||
* @tx_sgl_start - start index in data sgl for tx.
|
||||
* @rx_sgl_pos - current index in data sgl for rx.
|
||||
* @rx_sgl_start - start index in data sgl for rx.
|
||||
*/
|
||||
struct bam_transaction {
|
||||
struct bam_cmd_element *bam_ce;
|
||||
struct scatterlist *cmd_sgl;
|
||||
struct scatterlist *data_sgl;
|
||||
struct dma_async_tx_descriptor *last_data_desc;
|
||||
struct dma_async_tx_descriptor *last_cmd_desc;
|
||||
struct completion txn_done;
|
||||
|
||||
unsigned int bam_ce_nitems;
|
||||
unsigned int cmd_sgl_nitems;
|
||||
unsigned int data_sgl_nitems;
|
||||
|
||||
struct_group(bam_positions,
|
||||
u32 bam_ce_pos;
|
||||
u32 bam_ce_start;
|
||||
u32 cmd_sgl_pos;
|
||||
u32 cmd_sgl_start;
|
||||
u32 tx_sgl_pos;
|
||||
u32 tx_sgl_start;
|
||||
u32 rx_sgl_pos;
|
||||
u32 rx_sgl_start;
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
/*
|
||||
* This data type corresponds to the nand dma descriptor
|
||||
* @dma_desc - low level DMA engine descriptor
|
||||
* @list - list for desc_info
|
||||
*
|
||||
* @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by
|
||||
* ADM
|
||||
* @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM
|
||||
* @sgl_cnt - number of SGL in bam_sgl. Only used by BAM
|
||||
* @dir - DMA transfer direction
|
||||
*/
|
||||
struct desc_info {
|
||||
struct dma_async_tx_descriptor *dma_desc;
|
||||
struct list_head node;
|
||||
|
||||
union {
|
||||
struct scatterlist adm_sgl;
|
||||
struct {
|
||||
struct scatterlist *bam_sgl;
|
||||
int sgl_cnt;
|
||||
};
|
||||
};
|
||||
enum dma_data_direction dir;
|
||||
};
|
||||
|
||||
/*
|
||||
* holds the current register values that we want to write. acts as a contiguous
|
||||
* chunk of memory which we use to write the controller registers through DMA.
|
||||
*/
|
||||
struct nandc_regs {
|
||||
__le32 cmd;
|
||||
__le32 addr0;
|
||||
__le32 addr1;
|
||||
__le32 chip_sel;
|
||||
__le32 exec;
|
||||
|
||||
__le32 cfg0;
|
||||
__le32 cfg1;
|
||||
__le32 ecc_bch_cfg;
|
||||
|
||||
__le32 clrflashstatus;
|
||||
__le32 clrreadstatus;
|
||||
|
||||
__le32 cmd1;
|
||||
__le32 vld;
|
||||
|
||||
__le32 orig_cmd1;
|
||||
__le32 orig_vld;
|
||||
|
||||
__le32 ecc_buf_cfg;
|
||||
__le32 read_location0;
|
||||
__le32 read_location1;
|
||||
__le32 read_location2;
|
||||
__le32 read_location3;
|
||||
__le32 read_location_last0;
|
||||
__le32 read_location_last1;
|
||||
__le32 read_location_last2;
|
||||
__le32 read_location_last3;
|
||||
__le32 spi_cfg;
|
||||
__le32 num_addr_cycle;
|
||||
__le32 busy_wait_cnt;
|
||||
__le32 flash_feature;
|
||||
|
||||
__le32 erased_cw_detect_cfg_clr;
|
||||
__le32 erased_cw_detect_cfg_set;
|
||||
};
|
||||
|
||||
/*
|
||||
* NAND controller data struct
|
||||
*
|
||||
* @dev: parent device
|
||||
*
|
||||
* @base: MMIO base
|
||||
*
|
||||
* @core_clk: controller clock
|
||||
* @aon_clk: another controller clock
|
||||
* @iomacro_clk: io macro clock
|
||||
*
|
||||
* @regs: a contiguous chunk of memory for DMA register
|
||||
* writes. contains the register values to be
|
||||
* written to controller
|
||||
*
|
||||
* @props: properties of current NAND controller,
|
||||
* initialized via DT match data
|
||||
*
|
||||
* @controller: base controller structure
|
||||
* @qspi: qpic spi structure
|
||||
* @host_list: list containing all the chips attached to the
|
||||
* controller
|
||||
*
|
||||
* @chan: dma channel
|
||||
* @cmd_crci: ADM DMA CRCI for command flow control
|
||||
* @data_crci: ADM DMA CRCI for data flow control
|
||||
*
|
||||
* @desc_list: DMA descriptor list (list of desc_infos)
|
||||
*
|
||||
* @data_buffer: our local DMA buffer for page read/writes,
|
||||
* used when we can't use the buffer provided
|
||||
* by upper layers directly
|
||||
* @reg_read_buf: local buffer for reading back registers via DMA
|
||||
*
|
||||
* @base_phys: physical base address of controller registers
|
||||
* @base_dma: dma base address of controller registers
|
||||
* @reg_read_dma: contains dma address for register read buffer
|
||||
*
|
||||
* @buf_size/count/start: markers for chip->legacy.read_buf/write_buf
|
||||
* functions
|
||||
* @max_cwperpage: maximum QPIC codewords required. calculated
|
||||
* from all connected NAND devices pagesize
|
||||
*
|
||||
* @reg_read_pos: marker for data read in reg_read_buf
|
||||
*
|
||||
* @cmd1/vld: some fixed controller register values
|
||||
*
|
||||
* @exec_opwrite: flag to select correct number of code word
|
||||
* while reading status
|
||||
*/
|
||||
struct qcom_nand_controller {
|
||||
struct device *dev;
|
||||
|
||||
void __iomem *base;
|
||||
|
||||
struct clk *core_clk;
|
||||
struct clk *aon_clk;
|
||||
|
||||
struct nandc_regs *regs;
|
||||
struct bam_transaction *bam_txn;
|
||||
|
||||
const struct qcom_nandc_props *props;
|
||||
|
||||
struct nand_controller *controller;
|
||||
struct qpic_spi_nand *qspi;
|
||||
struct list_head host_list;
|
||||
|
||||
union {
|
||||
/* will be used only by QPIC for BAM DMA */
|
||||
struct {
|
||||
struct dma_chan *tx_chan;
|
||||
struct dma_chan *rx_chan;
|
||||
struct dma_chan *cmd_chan;
|
||||
};
|
||||
|
||||
/* will be used only by EBI2 for ADM DMA */
|
||||
struct {
|
||||
struct dma_chan *chan;
|
||||
unsigned int cmd_crci;
|
||||
unsigned int data_crci;
|
||||
};
|
||||
};
|
||||
|
||||
struct list_head desc_list;
|
||||
|
||||
u8 *data_buffer;
|
||||
__le32 *reg_read_buf;
|
||||
|
||||
phys_addr_t base_phys;
|
||||
dma_addr_t base_dma;
|
||||
dma_addr_t reg_read_dma;
|
||||
|
||||
int buf_size;
|
||||
int buf_count;
|
||||
int buf_start;
|
||||
unsigned int max_cwperpage;
|
||||
|
||||
int reg_read_pos;
|
||||
|
||||
u32 cmd1, vld;
|
||||
bool exec_opwrite;
|
||||
};
|
||||
|
||||
/*
|
||||
* This data type corresponds to the NAND controller properties which varies
|
||||
* among different NAND controllers.
|
||||
* @ecc_modes - ecc mode for NAND
|
||||
* @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
|
||||
* @supports_bam - whether NAND controller is using BAM
|
||||
* @nandc_part_of_qpic - whether NAND controller is part of qpic IP
|
||||
* @qpic_version2 - flag to indicate QPIC IP version 2
|
||||
* @use_codeword_fixup - whether NAND has different layout for boot partitions
|
||||
*/
|
||||
struct qcom_nandc_props {
|
||||
u32 ecc_modes;
|
||||
u32 dev_cmd_reg_start;
|
||||
u32 bam_offset;
|
||||
bool supports_bam;
|
||||
bool nandc_part_of_qpic;
|
||||
bool qpic_version2;
|
||||
bool use_codeword_fixup;
|
||||
};
|
||||
|
||||
void qcom_free_bam_transaction(struct qcom_nand_controller *nandc);
|
||||
struct bam_transaction *qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc);
|
||||
void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc);
|
||||
void qcom_qpic_bam_dma_done(void *data);
|
||||
void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu);
|
||||
int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc,
|
||||
struct dma_chan *chan, unsigned long flags);
|
||||
int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
|
||||
int reg_off, const void *vaddr, int size, unsigned int flags);
|
||||
int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read,
|
||||
const void *vaddr, int size, unsigned int flags);
|
||||
int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, int reg_off,
|
||||
const void *vaddr, int size, bool flow_control);
|
||||
int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first, int num_regs,
|
||||
unsigned int flags);
|
||||
int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, int first,
|
||||
int num_regs, unsigned int flags);
|
||||
int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr,
|
||||
int size, unsigned int flags);
|
||||
int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr,
|
||||
int size, unsigned int flags);
|
||||
int qcom_submit_descs(struct qcom_nand_controller *nandc);
|
||||
void qcom_clear_read_regs(struct qcom_nand_controller *nandc);
|
||||
void qcom_nandc_unalloc(struct qcom_nand_controller *nandc);
|
||||
int qcom_nandc_alloc(struct qcom_nand_controller *nandc);
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,61 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2006 Linutronix GmbH, Thomas Gleixner <tglx@kernel.org>
|
||||
*
|
||||
* Info:
|
||||
* Contains defines, datastructures for ndfc nand controller
|
||||
*/
|
||||
#ifndef __LINUX_MTD_NDFC_H
|
||||
#define __LINUX_MTD_NDFC_H
|
||||
|
||||
/* NDFC Register definitions */
|
||||
#define NDFC_CMD 0x00
|
||||
#define NDFC_ALE 0x04
|
||||
#define NDFC_DATA 0x08
|
||||
#define NDFC_ECC 0x10
|
||||
#define NDFC_BCFG0 0x30
|
||||
#define NDFC_BCFG1 0x34
|
||||
#define NDFC_BCFG2 0x38
|
||||
#define NDFC_BCFG3 0x3c
|
||||
#define NDFC_CCR 0x40
|
||||
#define NDFC_STAT 0x44
|
||||
#define NDFC_HWCTL 0x48
|
||||
#define NDFC_REVID 0x50
|
||||
|
||||
#define NDFC_STAT_IS_READY 0x01000000
|
||||
|
||||
#define NDFC_CCR_RESET_CE 0x80000000 /* CE Reset */
|
||||
#define NDFC_CCR_RESET_ECC 0x40000000 /* ECC Reset */
|
||||
#define NDFC_CCR_RIE 0x20000000 /* Interrupt Enable on Device Rdy */
|
||||
#define NDFC_CCR_REN 0x10000000 /* Enable wait for Rdy in LinearR */
|
||||
#define NDFC_CCR_ROMEN 0x08000000 /* Enable ROM In LinearR */
|
||||
#define NDFC_CCR_ARE 0x04000000 /* Auto-Read Enable */
|
||||
#define NDFC_CCR_BS(x) (((x) & 0x3) << 24) /* Select Bank on CE[x] */
|
||||
#define NDFC_CCR_BS_MASK 0x03000000 /* Select Bank */
|
||||
#define NDFC_CCR_ARAC0 0x00000000 /* 3 Addr, 1 Col 2 Row 512b page */
|
||||
#define NDFC_CCR_ARAC1 0x00001000 /* 4 Addr, 1 Col 3 Row 512b page */
|
||||
#define NDFC_CCR_ARAC2 0x00002000 /* 4 Addr, 2 Col 2 Row 2K page */
|
||||
#define NDFC_CCR_ARAC3 0x00003000 /* 5 Addr, 2 Col 3 Row 2K page */
|
||||
#define NDFC_CCR_ARAC_MASK 0x00003000 /* Auto-Read mode Addr Cycles */
|
||||
#define NDFC_CCR_RPG 0x0000C000 /* Auto-Read Page */
|
||||
#define NDFC_CCR_EBCC 0x00000004 /* EBC Configuration Completed */
|
||||
#define NDFC_CCR_DHC 0x00000002 /* Direct Hardware Control Enable */
|
||||
|
||||
#define NDFC_BxCFG_EN 0x80000000 /* Bank Enable */
|
||||
#define NDFC_BxCFG_CED 0x40000000 /* nCE Style */
|
||||
#define NDFC_BxCFG_SZ_MASK 0x08000000 /* Bank Size */
|
||||
#define NDFC_BxCFG_SZ_8BIT 0x00000000 /* 8bit */
|
||||
#define NDFC_BxCFG_SZ_16BIT 0x08000000 /* 16bit */
|
||||
|
||||
#define NDFC_MAX_BANKS 4
|
||||
|
||||
struct ndfc_controller_settings {
|
||||
uint32_t ccr_settings;
|
||||
uint64_t ndfc_erpn;
|
||||
};
|
||||
|
||||
struct ndfc_chip_settings {
|
||||
uint32_t bank_settings;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org>
|
||||
*/
|
||||
|
||||
#ifndef __MTD_NFTL_H__
|
||||
#define __MTD_NFTL_H__
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/blktrans.h>
|
||||
|
||||
#include <mtd/nftl-user.h>
|
||||
|
||||
/* these info are used in ReplUnitTable */
|
||||
#define BLOCK_NIL 0xffff /* last block of a chain */
|
||||
#define BLOCK_FREE 0xfffe /* free block */
|
||||
#define BLOCK_NOTEXPLORED 0xfffd /* non explored block, only used during mounting */
|
||||
#define BLOCK_RESERVED 0xfffc /* bios block or bad block */
|
||||
|
||||
struct NFTLrecord {
|
||||
struct mtd_blktrans_dev mbd;
|
||||
__u16 MediaUnit, SpareMediaUnit;
|
||||
__u32 EraseSize;
|
||||
struct NFTLMediaHeader MediaHdr;
|
||||
int usecount;
|
||||
unsigned char heads;
|
||||
unsigned char sectors;
|
||||
unsigned short cylinders;
|
||||
__u16 numvunits;
|
||||
__u16 lastEUN; /* should be suppressed */
|
||||
__u16 numfreeEUNs;
|
||||
__u16 LastFreeEUN; /* To speed up finding a free EUN */
|
||||
int head,sect,cyl;
|
||||
__u16 *EUNtable; /* [numvunits]: First EUN for each virtual unit */
|
||||
__u16 *ReplUnitTable; /* [numEUNs]: ReplUnitNumber for each */
|
||||
unsigned int nb_blocks; /* number of physical blocks */
|
||||
unsigned int nb_boot_blocks; /* number of blocks used by the bios */
|
||||
struct erase_info instr;
|
||||
};
|
||||
|
||||
int NFTL_mount(struct NFTLrecord *s);
|
||||
int NFTL_formatblock(struct NFTLrecord *s, int block);
|
||||
|
||||
int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
|
||||
size_t *retlen, uint8_t *buf);
|
||||
int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
|
||||
size_t *retlen, uint8_t *buf);
|
||||
|
||||
#ifndef NFTL_MAJOR
|
||||
#define NFTL_MAJOR 93
|
||||
#endif
|
||||
|
||||
#define MAX_NFTLS 16
|
||||
#define MAX_SECTORS_PER_UNIT 64
|
||||
#define NFTL_PARTN_BITS 4
|
||||
|
||||
#endif /* __MTD_NFTL_H__ */
|
||||
@@ -0,0 +1,240 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* linux/include/linux/mtd/onenand.h
|
||||
*
|
||||
* Copyright © 2005-2009 Samsung Electronics
|
||||
* Kyungmin Park <kyungmin.park@samsung.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MTD_ONENAND_H
|
||||
#define __LINUX_MTD_ONENAND_H
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/mtd/flashchip.h>
|
||||
#include <linux/mtd/onenand_regs.h>
|
||||
#include <linux/mtd/bbm.h>
|
||||
|
||||
#define MAX_DIES 2
|
||||
#define MAX_BUFFERRAM 2
|
||||
|
||||
/* Scan and identify a OneNAND device */
|
||||
extern int onenand_scan(struct mtd_info *mtd, int max_chips);
|
||||
/* Free resources held by the OneNAND device */
|
||||
extern void onenand_release(struct mtd_info *mtd);
|
||||
|
||||
/**
|
||||
* struct onenand_bufferram - OneNAND BufferRAM Data
|
||||
* @blockpage: block & page address in BufferRAM
|
||||
*/
|
||||
struct onenand_bufferram {
|
||||
int blockpage;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct onenand_chip - OneNAND Private Flash Chip Data
|
||||
* @base: [BOARDSPECIFIC] address to access OneNAND
|
||||
* @dies: [INTERN][FLEX-ONENAND] number of dies on chip
|
||||
* @boundary: [INTERN][FLEX-ONENAND] Boundary of the dies
|
||||
* @diesize: [INTERN][FLEX-ONENAND] Size of the dies
|
||||
* @chipsize: [INTERN] the size of one chip for multichip arrays
|
||||
* FIXME For Flex-OneNAND, chipsize holds maximum possible
|
||||
* device size ie when all blocks are considered MLC
|
||||
* @device_id: [INTERN] device ID
|
||||
* @density_mask: chip density, used for DDP devices
|
||||
* @verstion_id: [INTERN] version ID
|
||||
* @options: [BOARDSPECIFIC] various chip options. They can
|
||||
* partly be set to inform onenand_scan about
|
||||
* @erase_shift: [INTERN] number of address bits in a block
|
||||
* @page_shift: [INTERN] number of address bits in a page
|
||||
* @page_mask: [INTERN] a page per block mask
|
||||
* @writesize: [INTERN] a real page size
|
||||
* @bufferram_index: [INTERN] BufferRAM index
|
||||
* @bufferram: [INTERN] BufferRAM info
|
||||
* @readw: [REPLACEABLE] hardware specific function for read short
|
||||
* @writew: [REPLACEABLE] hardware specific function for write short
|
||||
* @command: [REPLACEABLE] hardware specific function for writing
|
||||
* commands to the chip
|
||||
* @wait: [REPLACEABLE] hardware specific function for wait on ready
|
||||
* @bbt_wait: [REPLACEABLE] hardware specific function for bbt wait on ready
|
||||
* @unlock_all: [REPLACEABLE] hardware specific function for unlock all
|
||||
* @read_bufferram: [REPLACEABLE] hardware specific function for BufferRAM Area
|
||||
* @write_bufferram: [REPLACEABLE] hardware specific function for BufferRAM Area
|
||||
* @read_word: [REPLACEABLE] hardware specific function for read
|
||||
* register of OneNAND
|
||||
* @write_word: [REPLACEABLE] hardware specific function for write
|
||||
* register of OneNAND
|
||||
* @mmcontrol: sync burst read function
|
||||
* @chip_probe: [REPLACEABLE] hardware specific function for chip probe
|
||||
* @block_markbad: function to mark a block as bad
|
||||
* @scan_bbt: [REPLACEALBE] hardware specific function for scanning
|
||||
* Bad block Table
|
||||
* @chip_lock: [INTERN] spinlock used to protect access to this
|
||||
* structure and the chip
|
||||
* @wq: [INTERN] wait queue to sleep on if a OneNAND
|
||||
* operation is in progress
|
||||
* @state: [INTERN] the current state of the OneNAND device
|
||||
* @page_buf: [INTERN] page main data buffer
|
||||
* @oob_buf: [INTERN] page oob data buffer
|
||||
* @subpagesize: [INTERN] holds the subpagesize
|
||||
* @bbm: [REPLACEABLE] pointer to Bad Block Management
|
||||
* @priv: [OPTIONAL] pointer to private chip date
|
||||
*/
|
||||
struct onenand_chip {
|
||||
void __iomem *base;
|
||||
unsigned dies;
|
||||
unsigned boundary[MAX_DIES];
|
||||
loff_t diesize[MAX_DIES];
|
||||
unsigned int chipsize;
|
||||
unsigned int device_id;
|
||||
unsigned int version_id;
|
||||
unsigned int technology;
|
||||
unsigned int density_mask;
|
||||
unsigned int options;
|
||||
unsigned int badblockpos;
|
||||
|
||||
unsigned int erase_shift;
|
||||
unsigned int page_shift;
|
||||
unsigned int page_mask;
|
||||
unsigned int writesize;
|
||||
|
||||
unsigned int bufferram_index;
|
||||
struct onenand_bufferram bufferram[MAX_BUFFERRAM];
|
||||
|
||||
int (*command)(struct mtd_info *mtd, int cmd, loff_t address, size_t len);
|
||||
int (*wait)(struct mtd_info *mtd, int state);
|
||||
int (*bbt_wait)(struct mtd_info *mtd, int state);
|
||||
void (*unlock_all)(struct mtd_info *mtd);
|
||||
int (*read_bufferram)(struct mtd_info *mtd, int area,
|
||||
unsigned char *buffer, int offset, size_t count);
|
||||
int (*write_bufferram)(struct mtd_info *mtd, int area,
|
||||
const unsigned char *buffer, int offset, size_t count);
|
||||
unsigned short (*read_word)(void __iomem *addr);
|
||||
void (*write_word)(unsigned short value, void __iomem *addr);
|
||||
void (*mmcontrol)(struct mtd_info *mtd, int sync_read);
|
||||
int (*chip_probe)(struct mtd_info *mtd);
|
||||
int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
|
||||
int (*scan_bbt)(struct mtd_info *mtd);
|
||||
int (*enable)(struct mtd_info *mtd);
|
||||
int (*disable)(struct mtd_info *mtd);
|
||||
|
||||
struct completion complete;
|
||||
int irq;
|
||||
|
||||
spinlock_t chip_lock;
|
||||
wait_queue_head_t wq;
|
||||
flstate_t state;
|
||||
unsigned char *page_buf;
|
||||
unsigned char *oob_buf;
|
||||
#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
|
||||
unsigned char *verify_buf;
|
||||
#endif
|
||||
|
||||
int subpagesize;
|
||||
|
||||
void *bbm;
|
||||
|
||||
void *priv;
|
||||
|
||||
/*
|
||||
* Shows that the current operation is composed
|
||||
* of sequence of commands. For example, cache program.
|
||||
* Such command status OnGo bit is checked at the end of
|
||||
* sequence.
|
||||
*/
|
||||
unsigned int ongoing;
|
||||
};
|
||||
|
||||
/*
|
||||
* Helper macros
|
||||
*/
|
||||
#define ONENAND_PAGES_PER_BLOCK (1<<6)
|
||||
|
||||
#define ONENAND_CURRENT_BUFFERRAM(this) (this->bufferram_index)
|
||||
#define ONENAND_NEXT_BUFFERRAM(this) (this->bufferram_index ^ 1)
|
||||
#define ONENAND_SET_NEXT_BUFFERRAM(this) (this->bufferram_index ^= 1)
|
||||
#define ONENAND_SET_PREV_BUFFERRAM(this) (this->bufferram_index ^= 1)
|
||||
#define ONENAND_SET_BUFFERRAM0(this) (this->bufferram_index = 0)
|
||||
#define ONENAND_SET_BUFFERRAM1(this) (this->bufferram_index = 1)
|
||||
|
||||
#define FLEXONENAND(this) \
|
||||
(this->device_id & DEVICE_IS_FLEXONENAND)
|
||||
#define ONENAND_GET_SYS_CFG1(this) \
|
||||
(this->read_word(this->base + ONENAND_REG_SYS_CFG1))
|
||||
#define ONENAND_SET_SYS_CFG1(v, this) \
|
||||
(this->write_word(v, this->base + ONENAND_REG_SYS_CFG1))
|
||||
|
||||
#define ONENAND_IS_DDP(this) \
|
||||
(this->device_id & ONENAND_DEVICE_IS_DDP)
|
||||
|
||||
#define ONENAND_IS_MLC(this) \
|
||||
(this->technology & ONENAND_TECHNOLOGY_IS_MLC)
|
||||
|
||||
#ifdef CONFIG_MTD_ONENAND_2X_PROGRAM
|
||||
#define ONENAND_IS_2PLANE(this) \
|
||||
(this->options & ONENAND_HAS_2PLANE)
|
||||
#else
|
||||
#define ONENAND_IS_2PLANE(this) (0)
|
||||
#endif
|
||||
|
||||
#define ONENAND_IS_CACHE_PROGRAM(this) \
|
||||
(this->options & ONENAND_HAS_CACHE_PROGRAM)
|
||||
|
||||
#define ONENAND_IS_NOP_1(this) \
|
||||
(this->options & ONENAND_HAS_NOP_1)
|
||||
|
||||
/* Check byte access in OneNAND */
|
||||
#define ONENAND_CHECK_BYTE_ACCESS(addr) (addr & 0x1)
|
||||
|
||||
#define ONENAND_BADBLOCK_POS 0
|
||||
|
||||
/*
|
||||
* Options bits
|
||||
*/
|
||||
#define ONENAND_HAS_CONT_LOCK (0x0001)
|
||||
#define ONENAND_HAS_UNLOCK_ALL (0x0002)
|
||||
#define ONENAND_HAS_2PLANE (0x0004)
|
||||
#define ONENAND_HAS_4KB_PAGE (0x0008)
|
||||
#define ONENAND_HAS_CACHE_PROGRAM (0x0010)
|
||||
#define ONENAND_HAS_NOP_1 (0x0020)
|
||||
#define ONENAND_SKIP_UNLOCK_CHECK (0x0100)
|
||||
#define ONENAND_PAGEBUF_ALLOC (0x1000)
|
||||
#define ONENAND_OOBBUF_ALLOC (0x2000)
|
||||
#define ONENAND_SKIP_INITIAL_UNLOCKING (0x4000)
|
||||
|
||||
#define ONENAND_IS_4KB_PAGE(this) \
|
||||
(this->options & ONENAND_HAS_4KB_PAGE)
|
||||
|
||||
/*
|
||||
* OneNAND Flash Manufacturer ID Codes
|
||||
*/
|
||||
#define ONENAND_MFR_SAMSUNG 0xec
|
||||
#define ONENAND_MFR_NUMONYX 0x20
|
||||
|
||||
/**
|
||||
* struct onenand_manufacturers - NAND Flash Manufacturer ID Structure
|
||||
* @name: Manufacturer name
|
||||
* @id: manufacturer ID code of device.
|
||||
*/
|
||||
struct onenand_manufacturers {
|
||||
int id;
|
||||
char *name;
|
||||
};
|
||||
|
||||
int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
|
||||
struct mtd_oob_ops *ops);
|
||||
unsigned onenand_block(struct onenand_chip *this, loff_t addr);
|
||||
loff_t onenand_addr(struct onenand_chip *this, int block);
|
||||
int flexonenand_region(struct mtd_info *mtd, loff_t addr);
|
||||
|
||||
struct mtd_partition;
|
||||
|
||||
struct onenand_platform_data {
|
||||
void (*mmcontrol)(struct mtd_info *mtd, int sync_read);
|
||||
int (*read_bufferram)(struct mtd_info *mtd, int area,
|
||||
unsigned char *buffer, int offset, size_t count);
|
||||
struct mtd_partition *parts;
|
||||
unsigned int nr_parts;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_MTD_ONENAND_H */
|
||||
@@ -0,0 +1,221 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* linux/include/linux/mtd/onenand_regs.h
|
||||
*
|
||||
* OneNAND Register header file
|
||||
*
|
||||
* Copyright (C) 2005-2007 Samsung Electronics
|
||||
* Kyungmin Park <kyungmin.park@samsung.com>
|
||||
*/
|
||||
|
||||
#ifndef __ONENAND_REG_H
|
||||
#define __ONENAND_REG_H
|
||||
|
||||
/* Memory Address Map Translation (Word order) */
|
||||
#define ONENAND_MEMORY_MAP(x) ((x) << 1)
|
||||
|
||||
/*
|
||||
* External BufferRAM area
|
||||
*/
|
||||
#define ONENAND_BOOTRAM ONENAND_MEMORY_MAP(0x0000)
|
||||
#define ONENAND_DATARAM ONENAND_MEMORY_MAP(0x0200)
|
||||
#define ONENAND_SPARERAM ONENAND_MEMORY_MAP(0x8010)
|
||||
|
||||
/*
|
||||
* OneNAND Registers
|
||||
*/
|
||||
#define ONENAND_REG_MANUFACTURER_ID ONENAND_MEMORY_MAP(0xF000)
|
||||
#define ONENAND_REG_DEVICE_ID ONENAND_MEMORY_MAP(0xF001)
|
||||
#define ONENAND_REG_VERSION_ID ONENAND_MEMORY_MAP(0xF002)
|
||||
#define ONENAND_REG_DATA_BUFFER_SIZE ONENAND_MEMORY_MAP(0xF003)
|
||||
#define ONENAND_REG_BOOT_BUFFER_SIZE ONENAND_MEMORY_MAP(0xF004)
|
||||
#define ONENAND_REG_NUM_BUFFERS ONENAND_MEMORY_MAP(0xF005)
|
||||
#define ONENAND_REG_TECHNOLOGY ONENAND_MEMORY_MAP(0xF006)
|
||||
|
||||
#define ONENAND_REG_START_ADDRESS1 ONENAND_MEMORY_MAP(0xF100)
|
||||
#define ONENAND_REG_START_ADDRESS2 ONENAND_MEMORY_MAP(0xF101)
|
||||
#define ONENAND_REG_START_ADDRESS3 ONENAND_MEMORY_MAP(0xF102)
|
||||
#define ONENAND_REG_START_ADDRESS4 ONENAND_MEMORY_MAP(0xF103)
|
||||
#define ONENAND_REG_START_ADDRESS5 ONENAND_MEMORY_MAP(0xF104)
|
||||
#define ONENAND_REG_START_ADDRESS6 ONENAND_MEMORY_MAP(0xF105)
|
||||
#define ONENAND_REG_START_ADDRESS7 ONENAND_MEMORY_MAP(0xF106)
|
||||
#define ONENAND_REG_START_ADDRESS8 ONENAND_MEMORY_MAP(0xF107)
|
||||
|
||||
#define ONENAND_REG_START_BUFFER ONENAND_MEMORY_MAP(0xF200)
|
||||
#define ONENAND_REG_COMMAND ONENAND_MEMORY_MAP(0xF220)
|
||||
#define ONENAND_REG_SYS_CFG1 ONENAND_MEMORY_MAP(0xF221)
|
||||
#define ONENAND_REG_SYS_CFG2 ONENAND_MEMORY_MAP(0xF222)
|
||||
#define ONENAND_REG_CTRL_STATUS ONENAND_MEMORY_MAP(0xF240)
|
||||
#define ONENAND_REG_INTERRUPT ONENAND_MEMORY_MAP(0xF241)
|
||||
#define ONENAND_REG_START_BLOCK_ADDRESS ONENAND_MEMORY_MAP(0xF24C)
|
||||
#define ONENAND_REG_END_BLOCK_ADDRESS ONENAND_MEMORY_MAP(0xF24D)
|
||||
#define ONENAND_REG_WP_STATUS ONENAND_MEMORY_MAP(0xF24E)
|
||||
|
||||
#define ONENAND_REG_ECC_STATUS ONENAND_MEMORY_MAP(0xFF00)
|
||||
#define ONENAND_REG_ECC_M0 ONENAND_MEMORY_MAP(0xFF01)
|
||||
#define ONENAND_REG_ECC_S0 ONENAND_MEMORY_MAP(0xFF02)
|
||||
#define ONENAND_REG_ECC_M1 ONENAND_MEMORY_MAP(0xFF03)
|
||||
#define ONENAND_REG_ECC_S1 ONENAND_MEMORY_MAP(0xFF04)
|
||||
#define ONENAND_REG_ECC_M2 ONENAND_MEMORY_MAP(0xFF05)
|
||||
#define ONENAND_REG_ECC_S2 ONENAND_MEMORY_MAP(0xFF06)
|
||||
#define ONENAND_REG_ECC_M3 ONENAND_MEMORY_MAP(0xFF07)
|
||||
#define ONENAND_REG_ECC_S3 ONENAND_MEMORY_MAP(0xFF08)
|
||||
|
||||
/*
|
||||
* Device ID Register F001h (R)
|
||||
*/
|
||||
#define DEVICE_IS_FLEXONENAND (1 << 9)
|
||||
#define FLEXONENAND_PI_MASK (0x3ff)
|
||||
#define FLEXONENAND_PI_UNLOCK_SHIFT (14)
|
||||
#define ONENAND_DEVICE_DENSITY_MASK (0xf)
|
||||
#define ONENAND_DEVICE_DENSITY_SHIFT (4)
|
||||
#define ONENAND_DEVICE_IS_DDP (1 << 3)
|
||||
#define ONENAND_DEVICE_IS_DEMUX (1 << 2)
|
||||
#define ONENAND_DEVICE_VCC_MASK (0x3)
|
||||
|
||||
#define ONENAND_DEVICE_DENSITY_512Mb (0x002)
|
||||
#define ONENAND_DEVICE_DENSITY_1Gb (0x003)
|
||||
#define ONENAND_DEVICE_DENSITY_2Gb (0x004)
|
||||
#define ONENAND_DEVICE_DENSITY_4Gb (0x005)
|
||||
#define ONENAND_DEVICE_DENSITY_8Gb (0x006)
|
||||
|
||||
/*
|
||||
* Version ID Register F002h (R)
|
||||
*/
|
||||
#define ONENAND_VERSION_PROCESS_SHIFT (8)
|
||||
|
||||
/*
|
||||
* Technology Register F006h (R)
|
||||
*/
|
||||
#define ONENAND_TECHNOLOGY_IS_MLC (1 << 0)
|
||||
|
||||
/*
|
||||
* Start Address 1 F100h (R/W) & Start Address 2 F101h (R/W)
|
||||
*/
|
||||
#define ONENAND_DDP_SHIFT (15)
|
||||
#define ONENAND_DDP_CHIP0 (0)
|
||||
#define ONENAND_DDP_CHIP1 (1 << ONENAND_DDP_SHIFT)
|
||||
|
||||
/*
|
||||
* Start Address 8 F107h (R/W)
|
||||
*/
|
||||
/* Note: It's actually 0x3f in case of SLC */
|
||||
#define ONENAND_FPA_MASK (0x7f)
|
||||
#define ONENAND_FPA_SHIFT (2)
|
||||
#define ONENAND_FSA_MASK (0x03)
|
||||
|
||||
/*
|
||||
* Start Buffer Register F200h (R/W)
|
||||
*/
|
||||
#define ONENAND_BSA_MASK (0x03)
|
||||
#define ONENAND_BSA_SHIFT (8)
|
||||
#define ONENAND_BSA_BOOTRAM (0 << 2)
|
||||
#define ONENAND_BSA_DATARAM0 (2 << 2)
|
||||
#define ONENAND_BSA_DATARAM1 (3 << 2)
|
||||
/* Note: It's actually 0x03 in case of SLC */
|
||||
#define ONENAND_BSC_MASK (0x07)
|
||||
|
||||
/*
|
||||
* Command Register F220h (R/W)
|
||||
*/
|
||||
#define ONENAND_CMD_READ (0x00)
|
||||
#define ONENAND_CMD_READOOB (0x13)
|
||||
#define ONENAND_CMD_PROG (0x80)
|
||||
#define ONENAND_CMD_PROGOOB (0x1A)
|
||||
#define ONENAND_CMD_2X_PROG (0x7D)
|
||||
#define ONENAND_CMD_2X_CACHE_PROG (0x7F)
|
||||
#define ONENAND_CMD_UNLOCK (0x23)
|
||||
#define ONENAND_CMD_LOCK (0x2A)
|
||||
#define ONENAND_CMD_LOCK_TIGHT (0x2C)
|
||||
#define ONENAND_CMD_UNLOCK_ALL (0x27)
|
||||
#define ONENAND_CMD_ERASE (0x94)
|
||||
#define ONENAND_CMD_MULTIBLOCK_ERASE (0x95)
|
||||
#define ONENAND_CMD_ERASE_VERIFY (0x71)
|
||||
#define ONENAND_CMD_RESET (0xF0)
|
||||
#define ONENAND_CMD_OTP_ACCESS (0x65)
|
||||
#define ONENAND_CMD_READID (0x90)
|
||||
#define FLEXONENAND_CMD_PI_UPDATE (0x05)
|
||||
#define FLEXONENAND_CMD_PI_ACCESS (0x66)
|
||||
#define FLEXONENAND_CMD_RECOVER_LSB (0x05)
|
||||
|
||||
/* NOTE: Those are not *REAL* commands */
|
||||
#define ONENAND_CMD_BUFFERRAM (0x1978)
|
||||
#define FLEXONENAND_CMD_READ_PI (0x1985)
|
||||
|
||||
/*
|
||||
* System Configuration 1 Register F221h (R, R/W)
|
||||
*/
|
||||
#define ONENAND_SYS_CFG1_SYNC_READ (1 << 15)
|
||||
#define ONENAND_SYS_CFG1_BRL_7 (7 << 12)
|
||||
#define ONENAND_SYS_CFG1_BRL_6 (6 << 12)
|
||||
#define ONENAND_SYS_CFG1_BRL_5 (5 << 12)
|
||||
#define ONENAND_SYS_CFG1_BRL_4 (4 << 12)
|
||||
#define ONENAND_SYS_CFG1_BRL_3 (3 << 12)
|
||||
#define ONENAND_SYS_CFG1_BRL_10 (2 << 12)
|
||||
#define ONENAND_SYS_CFG1_BRL_9 (1 << 12)
|
||||
#define ONENAND_SYS_CFG1_BRL_8 (0 << 12)
|
||||
#define ONENAND_SYS_CFG1_BRL_SHIFT (12)
|
||||
#define ONENAND_SYS_CFG1_BL_32 (4 << 9)
|
||||
#define ONENAND_SYS_CFG1_BL_16 (3 << 9)
|
||||
#define ONENAND_SYS_CFG1_BL_8 (2 << 9)
|
||||
#define ONENAND_SYS_CFG1_BL_4 (1 << 9)
|
||||
#define ONENAND_SYS_CFG1_BL_CONT (0 << 9)
|
||||
#define ONENAND_SYS_CFG1_BL_SHIFT (9)
|
||||
#define ONENAND_SYS_CFG1_NO_ECC (1 << 8)
|
||||
#define ONENAND_SYS_CFG1_RDY (1 << 7)
|
||||
#define ONENAND_SYS_CFG1_INT (1 << 6)
|
||||
#define ONENAND_SYS_CFG1_IOBE (1 << 5)
|
||||
#define ONENAND_SYS_CFG1_RDY_CONF (1 << 4)
|
||||
#define ONENAND_SYS_CFG1_VHF (1 << 3)
|
||||
#define ONENAND_SYS_CFG1_HF (1 << 2)
|
||||
#define ONENAND_SYS_CFG1_SYNC_WRITE (1 << 1)
|
||||
|
||||
/*
|
||||
* Controller Status Register F240h (R)
|
||||
*/
|
||||
#define ONENAND_CTRL_ONGO (1 << 15)
|
||||
#define ONENAND_CTRL_LOCK (1 << 14)
|
||||
#define ONENAND_CTRL_LOAD (1 << 13)
|
||||
#define ONENAND_CTRL_PROGRAM (1 << 12)
|
||||
#define ONENAND_CTRL_ERASE (1 << 11)
|
||||
#define ONENAND_CTRL_ERROR (1 << 10)
|
||||
#define ONENAND_CTRL_RSTB (1 << 7)
|
||||
#define ONENAND_CTRL_OTP_L (1 << 6)
|
||||
#define ONENAND_CTRL_OTP_BL (1 << 5)
|
||||
|
||||
/*
|
||||
* Interrupt Status Register F241h (R)
|
||||
*/
|
||||
#define ONENAND_INT_MASTER (1 << 15)
|
||||
#define ONENAND_INT_READ (1 << 7)
|
||||
#define ONENAND_INT_WRITE (1 << 6)
|
||||
#define ONENAND_INT_ERASE (1 << 5)
|
||||
#define ONENAND_INT_RESET (1 << 4)
|
||||
#define ONENAND_INT_CLEAR (0 << 0)
|
||||
|
||||
/*
|
||||
* NAND Flash Write Protection Status Register F24Eh (R)
|
||||
*/
|
||||
#define ONENAND_WP_US (1 << 2)
|
||||
#define ONENAND_WP_LS (1 << 1)
|
||||
#define ONENAND_WP_LTS (1 << 0)
|
||||
|
||||
/*
|
||||
* ECC Status Reigser FF00h (R)
|
||||
*/
|
||||
#define ONENAND_ECC_1BIT (1 << 0)
|
||||
#define ONENAND_ECC_1BIT_ALL (0x5555)
|
||||
#define ONENAND_ECC_2BIT (1 << 1)
|
||||
#define ONENAND_ECC_2BIT_ALL (0xAAAA)
|
||||
#define FLEXONENAND_UNCORRECTABLE_ERROR (0x1010)
|
||||
#define ONENAND_ECC_3BIT (1 << 2)
|
||||
#define ONENAND_ECC_4BIT (1 << 3)
|
||||
#define ONENAND_ECC_4BIT_UNCORRECTABLE (0x1010)
|
||||
|
||||
/*
|
||||
* One-Time Programmable (OTP)
|
||||
*/
|
||||
#define FLEXONENAND_OTP_LOCK_OFFSET (2048)
|
||||
#define ONENAND_OTP_LOCK_OFFSET (14)
|
||||
|
||||
#endif /* __ONENAND_REG_H */
|
||||
@@ -0,0 +1,190 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org>
|
||||
* Steven J. Hill <sjhill@realitydiluted.com>
|
||||
* Thomas Gleixner <tglx@kernel.org>
|
||||
*
|
||||
* Contains all ONFI related definitions
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MTD_ONFI_H
|
||||
#define __LINUX_MTD_ONFI_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/bitfield.h>
|
||||
|
||||
/* 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 BIT(0)
|
||||
#define ONFI_FEATURE_NV_DDR BIT(5)
|
||||
#define ONFI_FEATURE_EXT_PARAM_PAGE BIT(7)
|
||||
|
||||
/* ONFI timing mode, used in both asynchronous and synchronous mode */
|
||||
#define ONFI_DATA_INTERFACE_SDR 0
|
||||
#define ONFI_DATA_INTERFACE_NVDDR BIT(4)
|
||||
#define ONFI_DATA_INTERFACE_NVDDR2 BIT(5)
|
||||
#define ONFI_TIMING_MODE_0 BIT(0)
|
||||
#define ONFI_TIMING_MODE_1 BIT(1)
|
||||
#define ONFI_TIMING_MODE_2 BIT(2)
|
||||
#define ONFI_TIMING_MODE_3 BIT(3)
|
||||
#define ONFI_TIMING_MODE_4 BIT(4)
|
||||
#define ONFI_TIMING_MODE_5 BIT(5)
|
||||
#define ONFI_TIMING_MODE_UNKNOWN BIT(6)
|
||||
#define ONFI_TIMING_MODE_PARAM(x) FIELD_GET(GENMASK(3, 0), (x))
|
||||
|
||||
/* ONFI feature number/address */
|
||||
#define ONFI_FEATURE_NUMBER 256
|
||||
#define ONFI_FEATURE_ADDR_TIMING_MODE 0x1
|
||||
|
||||
/* Vendor-specific feature address (Micron) */
|
||||
#define ONFI_FEATURE_ADDR_READ_RETRY 0x89
|
||||
#define ONFI_FEATURE_ON_DIE_ECC 0x90
|
||||
#define ONFI_FEATURE_ON_DIE_ECC_EN BIT(3)
|
||||
|
||||
/* ONFI subfeature parameters length */
|
||||
#define ONFI_SUBFEATURE_PARAM_LEN 4
|
||||
|
||||
/* ONFI optional commands SET/GET FEATURES supported? */
|
||||
#define ONFI_OPT_CMD_READ_CACHE BIT(1)
|
||||
#define ONFI_OPT_CMD_SET_GET_FEATURES BIT(2)
|
||||
|
||||
struct nand_onfi_params {
|
||||
/* rev info and features block */
|
||||
/* 'O' 'N' 'F' 'I' */
|
||||
u8 sig[4];
|
||||
__le16 revision;
|
||||
__le16 features;
|
||||
__le16 opt_cmd;
|
||||
u8 reserved0[2];
|
||||
__le16 ext_param_page_length; /* since ONFI 2.1 */
|
||||
u8 num_of_param_pages; /* since ONFI 2.1 */
|
||||
u8 reserved1[17];
|
||||
|
||||
/* manufacturer information block */
|
||||
char manufacturer[12];
|
||||
char model[20];
|
||||
u8 jedec_id;
|
||||
__le16 date_code;
|
||||
u8 reserved2[13];
|
||||
|
||||
/* memory organization block */
|
||||
__le32 byte_per_page;
|
||||
__le16 spare_bytes_per_page;
|
||||
__le32 data_bytes_per_ppage;
|
||||
__le16 spare_bytes_per_ppage;
|
||||
__le32 pages_per_block;
|
||||
__le32 blocks_per_lun;
|
||||
u8 lun_count;
|
||||
u8 addr_cycles;
|
||||
u8 bits_per_cell;
|
||||
__le16 bb_per_lun;
|
||||
__le16 block_endurance;
|
||||
u8 guaranteed_good_blocks;
|
||||
__le16 guaranteed_block_endurance;
|
||||
u8 programs_per_page;
|
||||
u8 ppage_attr;
|
||||
u8 ecc_bits;
|
||||
u8 interleaved_bits;
|
||||
u8 interleaved_ops;
|
||||
u8 reserved3[13];
|
||||
|
||||
/* electrical parameter block */
|
||||
u8 io_pin_capacitance_max;
|
||||
__le16 sdr_timing_modes;
|
||||
__le16 program_cache_timing_mode;
|
||||
__le16 t_prog;
|
||||
__le16 t_bers;
|
||||
__le16 t_r;
|
||||
__le16 t_ccs;
|
||||
u8 nvddr_timing_modes;
|
||||
u8 nvddr2_timing_modes;
|
||||
u8 nvddr_nvddr2_features;
|
||||
__le16 clk_pin_capacitance_typ;
|
||||
__le16 io_pin_capacitance_typ;
|
||||
__le16 input_pin_capacitance_typ;
|
||||
u8 input_pin_capacitance_max;
|
||||
u8 driver_strength_support;
|
||||
__le16 t_int_r;
|
||||
__le16 t_adl;
|
||||
u8 reserved4[8];
|
||||
|
||||
/* vendor */
|
||||
__le16 vendor_revision;
|
||||
u8 vendor[88];
|
||||
|
||||
__le16 crc;
|
||||
} __packed;
|
||||
|
||||
#define ONFI_CRC_BASE 0x4F4E
|
||||
|
||||
/* Extended ECC information Block Definition (since ONFI 2.1) */
|
||||
struct onfi_ext_ecc_info {
|
||||
u8 ecc_bits;
|
||||
u8 codeword_size;
|
||||
__le16 bb_per_lun;
|
||||
__le16 block_endurance;
|
||||
u8 reserved[2];
|
||||
} __packed;
|
||||
|
||||
#define ONFI_SECTION_TYPE_0 0 /* Unused section. */
|
||||
#define ONFI_SECTION_TYPE_1 1 /* for additional sections. */
|
||||
#define ONFI_SECTION_TYPE_2 2 /* for ECC information. */
|
||||
struct onfi_ext_section {
|
||||
u8 type;
|
||||
u8 length;
|
||||
} __packed;
|
||||
|
||||
#define ONFI_EXT_SECTION_MAX 8
|
||||
|
||||
/* Extended Parameter Page Definition (since ONFI 2.1) */
|
||||
struct onfi_ext_param_page {
|
||||
__le16 crc;
|
||||
u8 sig[4]; /* 'E' 'P' 'P' 'S' */
|
||||
u8 reserved0[10];
|
||||
struct onfi_ext_section sections[ONFI_EXT_SECTION_MAX];
|
||||
|
||||
/*
|
||||
* The actual size of the Extended Parameter Page is in
|
||||
* @ext_param_page_length of nand_onfi_params{}.
|
||||
* The following are the variable length sections.
|
||||
* So we do not add any fields below. Please see the ONFI spec.
|
||||
*/
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct onfi_params - ONFI specific parameters that will be reused
|
||||
* @version: ONFI version (BCD encoded), 0 if ONFI is not supported
|
||||
* @tPROG: Page program time
|
||||
* @tBERS: Block erase time
|
||||
* @tR: Page read time
|
||||
* @tCCS: Change column setup time
|
||||
* @fast_tCAD: Command/Address/Data slow or fast delay (NV-DDR only)
|
||||
* @sdr_timing_modes: Supported asynchronous/SDR timing modes
|
||||
* @nvddr_timing_modes: Supported source synchronous/NV-DDR timing modes
|
||||
* @vendor_revision: Vendor specific revision number
|
||||
* @vendor: Vendor specific data
|
||||
*/
|
||||
struct onfi_params {
|
||||
int version;
|
||||
u16 tPROG;
|
||||
u16 tBERS;
|
||||
u16 tR;
|
||||
u16 tCCS;
|
||||
bool fast_tCAD;
|
||||
u16 sdr_timing_modes;
|
||||
u16 nvddr_timing_modes;
|
||||
u16 vendor_revision;
|
||||
u8 vendor[88];
|
||||
};
|
||||
|
||||
#endif /* __LINUX_MTD_ONFI_H */
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* MTD partitioning layer definitions
|
||||
*
|
||||
* (C) 2000 Nicolas Pitre <nico@fluxnic.net>
|
||||
*
|
||||
* This code is GPL
|
||||
*/
|
||||
|
||||
#ifndef MTD_PARTITIONS_H
|
||||
#define MTD_PARTITIONS_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
|
||||
/*
|
||||
* Partition definition structure:
|
||||
*
|
||||
* An array of struct partition is passed along with a MTD object to
|
||||
* mtd_device_register() to create them.
|
||||
*
|
||||
* For each partition, these fields are available:
|
||||
* name: string that will be used to label the partition's MTD device.
|
||||
* types: some partitions can be containers using specific format to describe
|
||||
* embedded subpartitions / volumes. E.g. many home routers use "firmware"
|
||||
* partition that contains at least kernel and rootfs. In such case an
|
||||
* extra parser is needed that will detect these dynamic partitions and
|
||||
* report them to the MTD subsystem. If set this property stores an array
|
||||
* of parser names to use when looking for subpartitions.
|
||||
* size: the partition size; if defined as MTDPART_SIZ_FULL, the partition
|
||||
* will extend to the end of the master MTD device.
|
||||
* offset: absolute starting position within the master MTD device; if
|
||||
* defined as MTDPART_OFS_APPEND, the partition will start where the
|
||||
* previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block;
|
||||
* if MTDPART_OFS_RETAIN, consume as much as possible, leaving size
|
||||
* after the end of partition.
|
||||
* mask_flags: contains flags that have to be masked (removed) from the
|
||||
* master MTD flag set for the corresponding MTD partition.
|
||||
* For example, to force a read-only partition, simply adding
|
||||
* MTD_WRITEABLE to the mask_flags will do the trick.
|
||||
* add_flags: contains flags to add to the parent flags
|
||||
*
|
||||
* Note: writeable partitions require their size and offset be
|
||||
* erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
|
||||
*/
|
||||
|
||||
struct mtd_partition {
|
||||
const char *name; /* identifier string */
|
||||
const char *const *types; /* names of parsers to use if any */
|
||||
uint64_t size; /* partition size */
|
||||
uint64_t offset; /* offset within the master MTD space */
|
||||
uint32_t mask_flags; /* master MTD flags to mask out for this partition */
|
||||
uint32_t add_flags; /* flags to add to the partition */
|
||||
struct device_node *of_node;
|
||||
};
|
||||
|
||||
#define MTDPART_OFS_RETAIN (-3)
|
||||
#define MTDPART_OFS_NXTBLK (-2)
|
||||
#define MTDPART_OFS_APPEND (-1)
|
||||
#define MTDPART_SIZ_FULL (0)
|
||||
|
||||
|
||||
struct mtd_info;
|
||||
struct device_node;
|
||||
|
||||
/**
|
||||
* struct mtd_part_parser_data - used to pass data to MTD partition parsers.
|
||||
* @origin: for RedBoot, start address of MTD device
|
||||
*/
|
||||
struct mtd_part_parser_data {
|
||||
unsigned long origin;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Functions dealing with the various ways of partitioning the space
|
||||
*/
|
||||
|
||||
struct mtd_part_parser {
|
||||
struct list_head list;
|
||||
struct module *owner;
|
||||
const char *name;
|
||||
const struct of_device_id *of_match_table;
|
||||
int (*parse_fn)(struct mtd_info *, const struct mtd_partition **,
|
||||
struct mtd_part_parser_data *);
|
||||
void (*cleanup)(const struct mtd_partition *pparts, int nr_parts);
|
||||
};
|
||||
|
||||
/* Container for passing around a set of parsed partitions */
|
||||
struct mtd_partitions {
|
||||
const struct mtd_partition *parts;
|
||||
int nr_parts;
|
||||
const struct mtd_part_parser *parser;
|
||||
};
|
||||
|
||||
extern int __register_mtd_parser(struct mtd_part_parser *parser,
|
||||
struct module *owner);
|
||||
#define register_mtd_parser(parser) __register_mtd_parser(parser, THIS_MODULE)
|
||||
|
||||
extern void deregister_mtd_parser(struct mtd_part_parser *parser);
|
||||
|
||||
/*
|
||||
* module_mtd_part_parser() - Helper macro for MTD partition parsers that don't
|
||||
* do anything special in module init/exit. Each driver may only use this macro
|
||||
* once, and calling it replaces module_init() and module_exit().
|
||||
*/
|
||||
#define module_mtd_part_parser(__mtd_part_parser) \
|
||||
module_driver(__mtd_part_parser, register_mtd_parser, \
|
||||
deregister_mtd_parser)
|
||||
|
||||
int mtd_add_partition(struct mtd_info *master, const char *name,
|
||||
long long offset, long long length);
|
||||
int mtd_del_partition(struct mtd_info *master, int partno);
|
||||
uint64_t mtd_get_device_size(const struct mtd_info *mtd);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,124 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Primary function overlay window definitions
|
||||
* and service functions used by LPDDR chips
|
||||
*/
|
||||
#ifndef __LINUX_MTD_PFOW_H
|
||||
#define __LINUX_MTD_PFOW_H
|
||||
|
||||
#include <linux/mtd/qinfo.h>
|
||||
|
||||
/* PFOW registers addressing */
|
||||
/* Address of symbol "P" */
|
||||
#define PFOW_QUERY_STRING_P 0x0000
|
||||
/* Address of symbol "F" */
|
||||
#define PFOW_QUERY_STRING_F 0x0002
|
||||
/* Address of symbol "O" */
|
||||
#define PFOW_QUERY_STRING_O 0x0004
|
||||
/* Address of symbol "W" */
|
||||
#define PFOW_QUERY_STRING_W 0x0006
|
||||
/* Identification info for LPDDR chip */
|
||||
#define PFOW_MANUFACTURER_ID 0x0020
|
||||
#define PFOW_DEVICE_ID 0x0022
|
||||
/* Address in PFOW where prog buffer can be found */
|
||||
#define PFOW_PROGRAM_BUFFER_OFFSET 0x0040
|
||||
/* Size of program buffer in words */
|
||||
#define PFOW_PROGRAM_BUFFER_SIZE 0x0042
|
||||
/* Address command code register */
|
||||
#define PFOW_COMMAND_CODE 0x0080
|
||||
/* command data register */
|
||||
#define PFOW_COMMAND_DATA 0x0084
|
||||
/* command address register lower address bits */
|
||||
#define PFOW_COMMAND_ADDRESS_L 0x0088
|
||||
/* command address register upper address bits */
|
||||
#define PFOW_COMMAND_ADDRESS_H 0x008a
|
||||
/* number of bytes to be proggrammed lower address bits */
|
||||
#define PFOW_DATA_COUNT_L 0x0090
|
||||
/* number of bytes to be proggrammed higher address bits */
|
||||
#define PFOW_DATA_COUNT_H 0x0092
|
||||
/* command execution register, the only possible value is 0x01 */
|
||||
#define PFOW_COMMAND_EXECUTE 0x00c0
|
||||
/* 0x01 should be written at this address to clear buffer */
|
||||
#define PFOW_CLEAR_PROGRAM_BUFFER 0x00c4
|
||||
/* device program/erase suspend register */
|
||||
#define PFOW_PROGRAM_ERASE_SUSPEND 0x00c8
|
||||
/* device status register */
|
||||
#define PFOW_DSR 0x00cc
|
||||
|
||||
/* LPDDR memory device command codes */
|
||||
/* They are possible values of PFOW command code register */
|
||||
#define LPDDR_WORD_PROGRAM 0x0041
|
||||
#define LPDDR_BUFF_PROGRAM 0x00E9
|
||||
#define LPDDR_BLOCK_ERASE 0x0020
|
||||
#define LPDDR_LOCK_BLOCK 0x0061
|
||||
#define LPDDR_UNLOCK_BLOCK 0x0062
|
||||
#define LPDDR_READ_BLOCK_LOCK_STATUS 0x0065
|
||||
#define LPDDR_INFO_QUERY 0x0098
|
||||
#define LPDDR_READ_OTP 0x0097
|
||||
#define LPDDR_PROG_OTP 0x00C0
|
||||
#define LPDDR_RESUME 0x00D0
|
||||
|
||||
/* Defines possible value of PFOW command execution register */
|
||||
#define LPDDR_START_EXECUTION 0x0001
|
||||
|
||||
/* Defines possible value of PFOW program/erase suspend register */
|
||||
#define LPDDR_SUSPEND 0x0001
|
||||
|
||||
/* Possible values of PFOW device status register */
|
||||
/* access R - read; RC read & clearable */
|
||||
#define DSR_DPS (1<<1) /* RC; device protect status
|
||||
* 0 - not protected 1 - locked */
|
||||
#define DSR_PSS (1<<2) /* R; program suspend status;
|
||||
* 0-prog in progress/completed,
|
||||
* 1- prog suspended */
|
||||
#define DSR_VPPS (1<<3) /* RC; 0-Vpp OK, * 1-Vpp low */
|
||||
#define DSR_PROGRAM_STATUS (1<<4) /* RC; 0-successful, 1-error */
|
||||
#define DSR_ERASE_STATUS (1<<5) /* RC; erase or blank check status;
|
||||
* 0-success erase/blank check,
|
||||
* 1 blank check error */
|
||||
#define DSR_ESS (1<<6) /* R; erase suspend status;
|
||||
* 0-erase in progress/complete,
|
||||
* 1 erase suspended */
|
||||
#define DSR_READY_STATUS (1<<7) /* R; Device status
|
||||
* 0-busy,
|
||||
* 1-ready */
|
||||
#define DSR_RPS (0x3<<8) /* RC; region program status
|
||||
* 00 - Success,
|
||||
* 01-re-program attempt in region with
|
||||
* object mode data,
|
||||
* 10-object mode program w attempt in
|
||||
* region with control mode data
|
||||
* 11-attempt to program invalid half
|
||||
* with 0x41 command */
|
||||
#define DSR_AOS (1<<12) /* RC; 1- AO related failure */
|
||||
#define DSR_AVAILABLE (1<<15) /* R; Device availbility
|
||||
* 1 - Device available
|
||||
* 0 - not available */
|
||||
|
||||
/* The superset of all possible error bits in DSR */
|
||||
#define DSR_ERR 0x133A
|
||||
|
||||
static inline void send_pfow_command(struct map_info *map,
|
||||
unsigned long cmd_code, unsigned long adr,
|
||||
unsigned long len, map_word *datum)
|
||||
{
|
||||
int bits_per_chip = map_bankwidth(map) * 8;
|
||||
|
||||
map_write(map, CMD(cmd_code), map->pfow_base + PFOW_COMMAND_CODE);
|
||||
map_write(map, CMD(adr & ((1<<bits_per_chip) - 1)),
|
||||
map->pfow_base + PFOW_COMMAND_ADDRESS_L);
|
||||
map_write(map, CMD(adr>>bits_per_chip),
|
||||
map->pfow_base + PFOW_COMMAND_ADDRESS_H);
|
||||
if (len) {
|
||||
map_write(map, CMD(len & ((1<<bits_per_chip) - 1)),
|
||||
map->pfow_base + PFOW_DATA_COUNT_L);
|
||||
map_write(map, CMD(len>>bits_per_chip),
|
||||
map->pfow_base + PFOW_DATA_COUNT_H);
|
||||
}
|
||||
if (datum)
|
||||
map_write(map, *datum, map->pfow_base + PFOW_COMMAND_DATA);
|
||||
|
||||
/* Command execution start */
|
||||
map_write(map, CMD(LPDDR_START_EXECUTION),
|
||||
map->pfow_base + PFOW_COMMAND_EXECUTE);
|
||||
}
|
||||
#endif /* __LINUX_MTD_PFOW_H */
|
||||
@@ -0,0 +1,31 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* For boards with physically mapped flash and using
|
||||
* drivers/mtd/maps/physmap.c mapping driver.
|
||||
*
|
||||
* Copyright (C) 2003 MontaVista Software Inc.
|
||||
* Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MTD_PHYSMAP__
|
||||
#define __LINUX_MTD_PHYSMAP__
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
||||
struct map_info;
|
||||
struct platform_device;
|
||||
|
||||
struct physmap_flash_data {
|
||||
unsigned int width;
|
||||
int (*init)(struct platform_device *);
|
||||
void (*exit)(struct platform_device *);
|
||||
void (*set_vpp)(struct platform_device *, int);
|
||||
unsigned int nr_parts;
|
||||
unsigned int pfow_base;
|
||||
char *probe_type;
|
||||
struct mtd_partition *parts;
|
||||
const char * const *part_probe_types;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_MTD_PHYSMAP__ */
|
||||
@@ -0,0 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* PISMO memory driver - http://www.pismoworld.org/
|
||||
*/
|
||||
#ifndef __LINUX_MTD_PISMO_H
|
||||
#define __LINUX_MTD_PISMO_H
|
||||
|
||||
struct pismo_pdata {
|
||||
void (*set_vpp)(void *, int);
|
||||
void *vpp_data;
|
||||
phys_addr_t cs_addrs[5];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* linux/include/linux/mtd/plat-ram.h
|
||||
*
|
||||
* (c) 2004 Simtec Electronics
|
||||
* http://www.simtec.co.uk/products/SWLINUX/
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
*
|
||||
* Generic platform device based RAM map
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MTD_PLATRAM_H
|
||||
#define __LINUX_MTD_PLATRAM_H __FILE__
|
||||
|
||||
#define PLATRAM_RO (0)
|
||||
#define PLATRAM_RW (1)
|
||||
|
||||
struct platdata_mtd_ram {
|
||||
const char *mapname;
|
||||
const char * const *map_probes;
|
||||
const char * const *probes;
|
||||
struct mtd_partition *partitions;
|
||||
int nr_partitions;
|
||||
int bankwidth;
|
||||
|
||||
/* control callbacks */
|
||||
|
||||
void (*set_rw)(struct device *dev, int to);
|
||||
};
|
||||
|
||||
#endif /* __LINUX_MTD_PLATRAM_H */
|
||||
@@ -0,0 +1,74 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org>
|
||||
* Steven J. Hill <sjhill@realitydiluted.com>
|
||||
* Thomas Gleixner <tglx@kernel.org>
|
||||
*
|
||||
* Contains all platform NAND related definitions.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MTD_PLATNAND_H
|
||||
#define __LINUX_MTD_PLATNAND_H
|
||||
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/**
|
||||
* struct platform_nand_chip - chip level device structure
|
||||
* @nr_chips: max. number of chips to scan for
|
||||
* @chip_offset: chip number offset
|
||||
* @nr_partitions: number of partitions pointed to by partitions (or zero)
|
||||
* @partitions: mtd partition list
|
||||
* @chip_delay: R/B delay value in us
|
||||
* @options: Option flags, e.g. 16bit buswidth
|
||||
* @bbt_options: BBT option flags, e.g. NAND_BBT_USE_FLASH
|
||||
* @part_probe_types: NULL-terminated array of probe types
|
||||
*/
|
||||
struct platform_nand_chip {
|
||||
int nr_chips;
|
||||
int chip_offset;
|
||||
int nr_partitions;
|
||||
struct mtd_partition *partitions;
|
||||
int chip_delay;
|
||||
unsigned int options;
|
||||
unsigned int bbt_options;
|
||||
const char **part_probe_types;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct platform_nand_ctrl - controller level device structure
|
||||
* @probe: platform specific function to probe/setup hardware
|
||||
* @remove: platform specific function to remove/teardown hardware
|
||||
* @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
|
||||
* @priv: private data to transport driver specific settings
|
||||
*
|
||||
* All fields are optional and depend on the hardware driver requirements
|
||||
*/
|
||||
struct platform_nand_ctrl {
|
||||
int (*probe)(struct platform_device *pdev);
|
||||
void (*remove)(struct platform_device *pdev);
|
||||
int (*dev_ready)(struct nand_chip *chip);
|
||||
void (*select_chip)(struct nand_chip *chip, int cs);
|
||||
void (*cmd_ctrl)(struct nand_chip *chip, int dat, unsigned int ctrl);
|
||||
void (*write_buf)(struct nand_chip *chip, const uint8_t *buf, int len);
|
||||
void (*read_buf)(struct nand_chip *chip, uint8_t *buf, int len);
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct platform_nand_data - container structure for platform-specific data
|
||||
* @chip: chip level chip structure
|
||||
* @ctrl: controller level device structure
|
||||
*/
|
||||
struct platform_nand_data {
|
||||
struct platform_nand_chip chip;
|
||||
struct platform_nand_ctrl ctrl;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_MTD_PLATNAND_H */
|
||||
@@ -0,0 +1,92 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __LINUX_MTD_QINFO_H
|
||||
#define __LINUX_MTD_QINFO_H
|
||||
|
||||
#include <linux/mtd/map.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/flashchip.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
||||
/* lpddr_private describes lpddr flash chip in memory map
|
||||
* @ManufactId - Chip Manufacture ID
|
||||
* @DevId - Chip Device ID
|
||||
* @qinfo - pointer to qinfo records describing the chip
|
||||
* @numchips - number of chips including virual RWW partitions
|
||||
* @chipshift - Chip/partition size 2^chipshift
|
||||
* @chips - per-chip data structure
|
||||
*/
|
||||
struct lpddr_private {
|
||||
uint16_t ManufactId;
|
||||
uint16_t DevId;
|
||||
struct qinfo_chip *qinfo;
|
||||
int numchips;
|
||||
unsigned long chipshift;
|
||||
struct flchip chips[] __counted_by(numchips);
|
||||
};
|
||||
|
||||
/* qinfo_query_info structure contains request information for
|
||||
* each qinfo record
|
||||
* @major - major number of qinfo record
|
||||
* @major - minor number of qinfo record
|
||||
* @id_str - descriptive string to access the record
|
||||
* @desc - detailed description for the qinfo record
|
||||
*/
|
||||
struct qinfo_query_info {
|
||||
uint8_t major;
|
||||
uint8_t minor;
|
||||
char *id_str;
|
||||
char *desc;
|
||||
};
|
||||
|
||||
/*
|
||||
* qinfo_chip structure contains necessary qinfo records data
|
||||
* @DevSizeShift - Device size 2^n bytes
|
||||
* @BufSizeShift - Program buffer size 2^n bytes
|
||||
* @TotalBlocksNum - Total number of blocks
|
||||
* @UniformBlockSizeShift - Uniform block size 2^UniformBlockSizeShift bytes
|
||||
* @HWPartsNum - Number of hardware partitions
|
||||
* @SuspEraseSupp - Suspend erase supported
|
||||
* @SingleWordProgTime - Single word program 2^SingleWordProgTime u-sec
|
||||
* @ProgBufferTime - Program buffer write 2^ProgBufferTime u-sec
|
||||
* @BlockEraseTime - Block erase 2^BlockEraseTime m-sec
|
||||
*/
|
||||
struct qinfo_chip {
|
||||
/* General device info */
|
||||
uint16_t DevSizeShift;
|
||||
uint16_t BufSizeShift;
|
||||
/* Erase block information */
|
||||
uint16_t TotalBlocksNum;
|
||||
uint16_t UniformBlockSizeShift;
|
||||
/* Partition information */
|
||||
uint16_t HWPartsNum;
|
||||
/* Optional features */
|
||||
uint16_t SuspEraseSupp;
|
||||
/* Operation typical time */
|
||||
uint16_t SingleWordProgTime;
|
||||
uint16_t ProgBufferTime;
|
||||
uint16_t BlockEraseTime;
|
||||
};
|
||||
|
||||
/* defines for fixup usage */
|
||||
#define LPDDR_MFR_ANY 0xffff
|
||||
#define LPDDR_ID_ANY 0xffff
|
||||
#define NUMONYX_MFGR_ID 0x0089
|
||||
#define R18_DEVICE_ID_1G 0x893c
|
||||
|
||||
static inline map_word lpddr_build_cmd(u_long cmd, struct map_info *map)
|
||||
{
|
||||
map_word val = { {0} };
|
||||
val.x[0] = cmd;
|
||||
return val;
|
||||
}
|
||||
|
||||
#define CMD(x) lpddr_build_cmd(x, map)
|
||||
#define CMDVAL(cmd) cmd.x[0]
|
||||
|
||||
struct mtd_info *lpddr_cmdset(struct map_info *);
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,180 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* SuperH FLCTL nand controller
|
||||
*
|
||||
* Copyright © 2008 Renesas Solutions Corp.
|
||||
*/
|
||||
|
||||
#ifndef __SH_FLCTL_H__
|
||||
#define __SH_FLCTL_H__
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/pm_qos.h>
|
||||
|
||||
/* FLCTL registers */
|
||||
#define FLCMNCR(f) (f->reg + 0x0)
|
||||
#define FLCMDCR(f) (f->reg + 0x4)
|
||||
#define FLCMCDR(f) (f->reg + 0x8)
|
||||
#define FLADR(f) (f->reg + 0xC)
|
||||
#define FLADR2(f) (f->reg + 0x3C)
|
||||
#define FLDATAR(f) (f->reg + 0x10)
|
||||
#define FLDTCNTR(f) (f->reg + 0x14)
|
||||
#define FLINTDMACR(f) (f->reg + 0x18)
|
||||
#define FLBSYTMR(f) (f->reg + 0x1C)
|
||||
#define FLBSYCNT(f) (f->reg + 0x20)
|
||||
#define FLDTFIFO(f) (f->reg + 0x24)
|
||||
#define FLECFIFO(f) (f->reg + 0x28)
|
||||
#define FLTRCR(f) (f->reg + 0x2C)
|
||||
#define FLHOLDCR(f) (f->reg + 0x38)
|
||||
#define FL4ECCRESULT0(f) (f->reg + 0x80)
|
||||
#define FL4ECCRESULT1(f) (f->reg + 0x84)
|
||||
#define FL4ECCRESULT2(f) (f->reg + 0x88)
|
||||
#define FL4ECCRESULT3(f) (f->reg + 0x8C)
|
||||
#define FL4ECCCR(f) (f->reg + 0x90)
|
||||
#define FL4ECCCNT(f) (f->reg + 0x94)
|
||||
#define FLERRADR(f) (f->reg + 0x98)
|
||||
|
||||
/* FLCMNCR control bits */
|
||||
#define _4ECCCNTEN (0x1 << 24)
|
||||
#define _4ECCEN (0x1 << 23)
|
||||
#define _4ECCCORRECT (0x1 << 22)
|
||||
#define SHBUSSEL (0x1 << 20)
|
||||
#define SEL_16BIT (0x1 << 19)
|
||||
#define SNAND_E (0x1 << 18) /* SNAND (0=512 1=2048)*/
|
||||
#define QTSEL_E (0x1 << 17)
|
||||
#define ENDIAN (0x1 << 16) /* 1 = little endian */
|
||||
#define FCKSEL_E (0x1 << 15)
|
||||
#define ACM_SACCES_MODE (0x01 << 10)
|
||||
#define NANWF_E (0x1 << 9)
|
||||
#define SE_D (0x1 << 8) /* Spare area disable */
|
||||
#define CE1_ENABLE (0x1 << 4) /* Chip Enable 1 */
|
||||
#define CE0_ENABLE (0x1 << 3) /* Chip Enable 0 */
|
||||
#define TYPESEL_SET (0x1 << 0)
|
||||
|
||||
/*
|
||||
* Clock settings using the PULSEx registers from FLCMNCR
|
||||
*
|
||||
* Some hardware uses bits called PULSEx instead of FCKSEL_E and QTSEL_E
|
||||
* to control the clock divider used between the High-Speed Peripheral Clock
|
||||
* and the FLCTL internal clock. If so, use CLK_8_BIT_xxx for connecting 8 bit
|
||||
* and CLK_16_BIT_xxx for connecting 16 bit bus bandwith NAND chips. For the 16
|
||||
* bit version the divider is seperate for the pulse width of high and low
|
||||
* signals.
|
||||
*/
|
||||
#define PULSE3 (0x1 << 27)
|
||||
#define PULSE2 (0x1 << 17)
|
||||
#define PULSE1 (0x1 << 15)
|
||||
#define PULSE0 (0x1 << 9)
|
||||
#define CLK_8B_0_5 PULSE1
|
||||
#define CLK_8B_1 0x0
|
||||
#define CLK_8B_1_5 (PULSE1 | PULSE2)
|
||||
#define CLK_8B_2 PULSE0
|
||||
#define CLK_8B_3 (PULSE0 | PULSE1 | PULSE2)
|
||||
#define CLK_8B_4 (PULSE0 | PULSE2)
|
||||
#define CLK_16B_6L_2H PULSE0
|
||||
#define CLK_16B_9L_3H (PULSE0 | PULSE1 | PULSE2)
|
||||
#define CLK_16B_12L_4H (PULSE0 | PULSE2)
|
||||
|
||||
/* FLCMDCR control bits */
|
||||
#define ADRCNT2_E (0x1 << 31) /* 5byte address enable */
|
||||
#define ADRMD_E (0x1 << 26) /* Sector address access */
|
||||
#define CDSRC_E (0x1 << 25) /* Data buffer selection */
|
||||
#define DOSR_E (0x1 << 24) /* Status read check */
|
||||
#define SELRW (0x1 << 21) /* 0:read 1:write */
|
||||
#define DOADR_E (0x1 << 20) /* Address stage execute */
|
||||
#define ADRCNT_1 (0x00 << 18) /* Address data bytes: 1byte */
|
||||
#define ADRCNT_2 (0x01 << 18) /* Address data bytes: 2byte */
|
||||
#define ADRCNT_3 (0x02 << 18) /* Address data bytes: 3byte */
|
||||
#define ADRCNT_4 (0x03 << 18) /* Address data bytes: 4byte */
|
||||
#define DOCMD2_E (0x1 << 17) /* 2nd cmd stage execute */
|
||||
#define DOCMD1_E (0x1 << 16) /* 1st cmd stage execute */
|
||||
|
||||
/* FLINTDMACR control bits */
|
||||
#define ESTERINTE (0x1 << 24) /* ECC error interrupt enable */
|
||||
#define AC1CLR (0x1 << 19) /* ECC FIFO clear */
|
||||
#define AC0CLR (0x1 << 18) /* Data FIFO clear */
|
||||
#define DREQ0EN (0x1 << 16) /* FLDTFIFODMA Request Enable */
|
||||
#define ECERB (0x1 << 9) /* ECC error */
|
||||
#define STERB (0x1 << 8) /* Status error */
|
||||
#define STERINTE (0x1 << 4) /* Status error enable */
|
||||
|
||||
/* FLTRCR control bits */
|
||||
#define TRSTRT (0x1 << 0) /* translation start */
|
||||
#define TREND (0x1 << 1) /* translation end */
|
||||
|
||||
/*
|
||||
* FLHOLDCR control bits
|
||||
*
|
||||
* HOLDEN: Bus Occupancy Enable (inverted)
|
||||
* Enable this bit when the external bus might be used in between transfers.
|
||||
* If not set and the bus gets used by other modules, a deadlock occurs.
|
||||
*/
|
||||
#define HOLDEN (0x1 << 0)
|
||||
|
||||
/* FL4ECCCR control bits */
|
||||
#define _4ECCFA (0x1 << 2) /* 4 symbols correct fault */
|
||||
#define _4ECCEND (0x1 << 1) /* 4 symbols end */
|
||||
#define _4ECCEXST (0x1 << 0) /* 4 symbols exist */
|
||||
|
||||
#define LOOP_TIMEOUT_MAX 0x00010000
|
||||
|
||||
enum flctl_ecc_res_t {
|
||||
FL_SUCCESS,
|
||||
FL_REPAIRABLE,
|
||||
FL_ERROR,
|
||||
FL_TIMEOUT
|
||||
};
|
||||
|
||||
struct dma_chan;
|
||||
|
||||
struct sh_flctl {
|
||||
struct nand_chip chip;
|
||||
struct platform_device *pdev;
|
||||
struct dev_pm_qos_request pm_qos;
|
||||
void __iomem *reg;
|
||||
resource_size_t fifo;
|
||||
|
||||
uint8_t done_buff[2048 + 64]; /* max size 2048 + 64 */
|
||||
int read_bytes;
|
||||
unsigned int index;
|
||||
int seqin_column; /* column in SEQIN cmd */
|
||||
int seqin_page_addr; /* page_addr in SEQIN cmd */
|
||||
uint32_t seqin_read_cmd; /* read cmd in SEQIN cmd */
|
||||
int erase1_page_addr; /* page_addr in ERASE1 cmd */
|
||||
uint32_t erase_ADRCNT; /* bits of FLCMDCR in ERASE1 cmd */
|
||||
uint32_t rw_ADRCNT; /* bits of FLCMDCR in READ WRITE cmd */
|
||||
uint32_t flcmncr_base; /* base value of FLCMNCR */
|
||||
uint32_t flintdmacr_base; /* irq enable bits */
|
||||
|
||||
unsigned page_size:1; /* NAND page size (0 = 512, 1 = 2048) */
|
||||
unsigned hwecc:1; /* Hardware ECC (0 = disabled, 1 = enabled) */
|
||||
unsigned holden:1; /* Hardware has FLHOLDCR and HOLDEN is set */
|
||||
unsigned qos_request:1; /* QoS request to prevent deep power shutdown */
|
||||
|
||||
/* DMA related objects */
|
||||
struct dma_chan *chan_fifo0_rx;
|
||||
struct dma_chan *chan_fifo0_tx;
|
||||
struct completion dma_complete;
|
||||
};
|
||||
|
||||
struct sh_flctl_platform_data {
|
||||
struct mtd_partition *parts;
|
||||
int nr_parts;
|
||||
unsigned long flcmncr_val;
|
||||
|
||||
unsigned has_hwecc:1;
|
||||
unsigned use_holden:1;
|
||||
|
||||
unsigned int slave_id_fifo0_tx;
|
||||
unsigned int slave_id_fifo0_rx;
|
||||
};
|
||||
|
||||
static inline struct sh_flctl *mtd_to_flctl(struct mtd_info *mtdinfo)
|
||||
{
|
||||
return container_of(mtd_to_nand(mtdinfo), struct sh_flctl, chip);
|
||||
}
|
||||
|
||||
#endif /* __SH_FLCTL_H__ */
|
||||
@@ -0,0 +1,22 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* SharpSL NAND support
|
||||
*
|
||||
* Copyright (C) 2008 Dmitry Baryshkov
|
||||
*/
|
||||
|
||||
#ifndef _MTD_SHARPSL_H
|
||||
#define _MTD_SHARPSL_H
|
||||
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
||||
struct sharpsl_nand_platform_data {
|
||||
struct nand_bbt_descr *badblock_pattern;
|
||||
const struct mtd_ooblayout_ops *ecc_layout;
|
||||
struct mtd_partition *partitions;
|
||||
unsigned int nr_partitions;
|
||||
const char *const *part_parsers;
|
||||
};
|
||||
|
||||
#endif /* _MTD_SHARPSL_H */
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright © 2010 ST Microelectronics
|
||||
* Shiraz Hashim <shiraz.linux.kernel@gmail.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#ifndef __MTD_SPEAR_SMI_H
|
||||
#define __MTD_SPEAR_SMI_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
/* max possible slots for serial-nor flash chip in the SMI controller */
|
||||
#define MAX_NUM_FLASH_CHIP 4
|
||||
|
||||
/* macro to define partitions for flash devices */
|
||||
#define DEFINE_PARTS(n, of, s) \
|
||||
{ \
|
||||
.name = n, \
|
||||
.offset = of, \
|
||||
.size = s, \
|
||||
}
|
||||
|
||||
/**
|
||||
* struct spear_smi_flash_info - platform structure for passing flash
|
||||
* information
|
||||
*
|
||||
* @name: name of the serial nor flash for identification
|
||||
* @mem_base: the memory base on which the flash is mapped
|
||||
* @size: size of the flash in bytes
|
||||
* @partitions: parition details
|
||||
* @nr_partitions: number of partitions
|
||||
* @fast_mode: whether flash supports fast mode
|
||||
*/
|
||||
|
||||
struct spear_smi_flash_info {
|
||||
char *name;
|
||||
unsigned long mem_base;
|
||||
unsigned long size;
|
||||
struct mtd_partition *partitions;
|
||||
int nr_partitions;
|
||||
u8 fast_mode;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct spear_smi_plat_data - platform structure for configuring smi
|
||||
*
|
||||
* @clk_rate: clk rate at which SMI must operate
|
||||
* @num_flashes: number of flashes present on board
|
||||
* @board_flash_info: specific details of each flash present on board
|
||||
* @np: array of DT node pointers for all possible flash chip devices
|
||||
*/
|
||||
struct spear_smi_plat_data {
|
||||
unsigned long clk_rate;
|
||||
int num_flashes;
|
||||
struct spear_smi_flash_info *board_flash_info;
|
||||
struct device_node *np[MAX_NUM_FLASH_CHIP];
|
||||
};
|
||||
|
||||
#endif /* __MTD_SPEAR_SMI_H */
|
||||
@@ -0,0 +1,453 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MTD_SPI_NOR_H
|
||||
#define __LINUX_MTD_SPI_NOR_H
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/spi/spi-mem.h>
|
||||
|
||||
/*
|
||||
* Note on opcode nomenclature: some opcodes have a format like
|
||||
* SPINOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number
|
||||
* of I/O lines used for the opcode, address, and data (respectively). The
|
||||
* FUNCTION has an optional suffix of '4', to represent an opcode which
|
||||
* requires a 4-byte (32-bit) address.
|
||||
*/
|
||||
|
||||
/* Flash opcodes. */
|
||||
#define SPINOR_OP_WRDI 0x04 /* Write disable */
|
||||
#define SPINOR_OP_WREN 0x06 /* Write enable */
|
||||
#define SPINOR_OP_RDSR 0x05 /* Read status register */
|
||||
#define SPINOR_OP_WRSR 0x01 /* Write status register 1 byte */
|
||||
#define SPINOR_OP_RDSR2 0x3f /* Read status register 2 */
|
||||
#define SPINOR_OP_WRSR2 0x3e /* Write status register 2 */
|
||||
#define SPINOR_OP_READ 0x03 /* Read data bytes (low frequency) */
|
||||
#define SPINOR_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */
|
||||
#define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual Output SPI) */
|
||||
#define SPINOR_OP_READ_1_2_2 0xbb /* Read data bytes (Dual I/O SPI) */
|
||||
#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad Output SPI) */
|
||||
#define SPINOR_OP_READ_1_4_4 0xeb /* Read data bytes (Quad I/O SPI) */
|
||||
#define SPINOR_OP_READ_1_1_8 0x8b /* Read data bytes (Octal Output SPI) */
|
||||
#define SPINOR_OP_READ_1_8_8 0xcb /* Read data bytes (Octal I/O SPI) */
|
||||
#define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */
|
||||
#define SPINOR_OP_PP_1_1_4 0x32 /* Quad page program */
|
||||
#define SPINOR_OP_PP_1_4_4 0x38 /* Quad page program */
|
||||
#define SPINOR_OP_PP_1_1_8 0x82 /* Octal page program */
|
||||
#define SPINOR_OP_PP_1_8_8 0xc2 /* Octal page program */
|
||||
#define SPINOR_OP_BE_4K 0x20 /* Erase 4KiB block */
|
||||
#define SPINOR_OP_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */
|
||||
#define SPINOR_OP_BE_32K 0x52 /* Erase 32KiB block */
|
||||
#define SPINOR_OP_CHIP_ERASE 0xc7 /* Erase whole flash chip */
|
||||
#define SPINOR_OP_SE 0xd8 /* Sector erase (usually 64KiB) */
|
||||
#define SPINOR_OP_RDID 0x9f /* Read JEDEC ID */
|
||||
#define SPINOR_OP_RDSFDP 0x5a /* Read SFDP */
|
||||
#define SPINOR_OP_RDCR 0x35 /* Read configuration register */
|
||||
#define SPINOR_OP_SRSTEN 0x66 /* Software Reset Enable */
|
||||
#define SPINOR_OP_SRST 0x99 /* Software Reset */
|
||||
#define SPINOR_OP_GBULK 0x98 /* Global Block Unlock */
|
||||
|
||||
/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
|
||||
#define SPINOR_OP_READ_4B 0x13 /* Read data bytes (low frequency) */
|
||||
#define SPINOR_OP_READ_FAST_4B 0x0c /* Read data bytes (high frequency) */
|
||||
#define SPINOR_OP_READ_1_1_2_4B 0x3c /* Read data bytes (Dual Output SPI) */
|
||||
#define SPINOR_OP_READ_1_2_2_4B 0xbc /* Read data bytes (Dual I/O SPI) */
|
||||
#define SPINOR_OP_READ_1_1_4_4B 0x6c /* Read data bytes (Quad Output SPI) */
|
||||
#define SPINOR_OP_READ_1_4_4_4B 0xec /* Read data bytes (Quad I/O SPI) */
|
||||
#define SPINOR_OP_READ_1_1_8_4B 0x7c /* Read data bytes (Octal Output SPI) */
|
||||
#define SPINOR_OP_READ_1_8_8_4B 0xcc /* Read data bytes (Octal I/O SPI) */
|
||||
#define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */
|
||||
#define SPINOR_OP_PP_1_1_4_4B 0x34 /* Quad page program */
|
||||
#define SPINOR_OP_PP_1_4_4_4B 0x3e /* Quad page program */
|
||||
#define SPINOR_OP_PP_1_1_8_4B 0x84 /* Octal page program */
|
||||
#define SPINOR_OP_PP_1_8_8_4B 0x8e /* Octal page program */
|
||||
#define SPINOR_OP_BE_4K_4B 0x21 /* Erase 4KiB block */
|
||||
#define SPINOR_OP_BE_32K_4B 0x5c /* Erase 32KiB block */
|
||||
#define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */
|
||||
|
||||
/* Double Transfer Rate opcodes - defined in JEDEC JESD216B. */
|
||||
#define SPINOR_OP_READ_1_1_1_DTR 0x0d
|
||||
#define SPINOR_OP_READ_1_2_2_DTR 0xbd
|
||||
#define SPINOR_OP_READ_1_4_4_DTR 0xed
|
||||
|
||||
#define SPINOR_OP_READ_1_1_1_DTR_4B 0x0e
|
||||
#define SPINOR_OP_READ_1_2_2_DTR_4B 0xbe
|
||||
#define SPINOR_OP_READ_1_4_4_DTR_4B 0xee
|
||||
|
||||
/* Used for SST flashes only. */
|
||||
#define SPINOR_OP_BP 0x02 /* Byte program */
|
||||
#define SPINOR_OP_AAI_WP 0xad /* Auto address increment word program */
|
||||
|
||||
/* Used for Macronix and Winbond flashes. */
|
||||
#define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */
|
||||
#define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */
|
||||
|
||||
/* Used for Spansion flashes only. */
|
||||
#define SPINOR_OP_BRWR 0x17 /* Bank register write */
|
||||
|
||||
/* Used for Micron flashes only. */
|
||||
#define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */
|
||||
#define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */
|
||||
|
||||
/* Used for GigaDevices and Winbond flashes. */
|
||||
#define SPINOR_OP_ESECR 0x44 /* Erase Security registers */
|
||||
#define SPINOR_OP_PSECR 0x42 /* Program Security registers */
|
||||
#define SPINOR_OP_RSECR 0x48 /* Read Security registers */
|
||||
|
||||
/* Status Register bits. */
|
||||
#define SR_WIP BIT(0) /* Write in progress */
|
||||
#define SR_WEL BIT(1) /* Write enable latch */
|
||||
/* meaning of other SR_* bits may differ between vendors */
|
||||
#define SR_BP0 BIT(2) /* Block protect 0 */
|
||||
#define SR_BP1 BIT(3) /* Block protect 1 */
|
||||
#define SR_BP2 BIT(4) /* Block protect 2 */
|
||||
#define SR_BP3 BIT(5) /* Block protect 3 */
|
||||
#define SR_TB_BIT5 BIT(5) /* Top/Bottom protect */
|
||||
#define SR_BP3_BIT6 BIT(6) /* Block protect 3 */
|
||||
#define SR_TB_BIT6 BIT(6) /* Top/Bottom protect */
|
||||
#define SR_SRWD BIT(7) /* SR write protect */
|
||||
/* Spansion/Cypress specific status bits */
|
||||
#define SR_E_ERR BIT(5)
|
||||
#define SR_P_ERR BIT(6)
|
||||
|
||||
#define SR1_QUAD_EN_BIT6 BIT(6)
|
||||
|
||||
#define SR_BP_SHIFT 2
|
||||
|
||||
/* Enhanced Volatile Configuration Register bits */
|
||||
#define EVCR_QUAD_EN_MICRON BIT(7) /* Micron Quad I/O */
|
||||
|
||||
/* Status Register 2 bits. */
|
||||
#define SR2_QUAD_EN_BIT1 BIT(1)
|
||||
#define SR2_LB1 BIT(3) /* Security Register Lock Bit 1 */
|
||||
#define SR2_LB2 BIT(4) /* Security Register Lock Bit 2 */
|
||||
#define SR2_LB3 BIT(5) /* Security Register Lock Bit 3 */
|
||||
#define SR2_QUAD_EN_BIT7 BIT(7)
|
||||
|
||||
/* Supported SPI protocols */
|
||||
#define SNOR_PROTO_INST_MASK GENMASK(23, 16)
|
||||
#define SNOR_PROTO_INST_SHIFT 16
|
||||
#define SNOR_PROTO_INST(_nbits) \
|
||||
((((unsigned long)(_nbits)) << SNOR_PROTO_INST_SHIFT) & \
|
||||
SNOR_PROTO_INST_MASK)
|
||||
|
||||
#define SNOR_PROTO_ADDR_MASK GENMASK(15, 8)
|
||||
#define SNOR_PROTO_ADDR_SHIFT 8
|
||||
#define SNOR_PROTO_ADDR(_nbits) \
|
||||
((((unsigned long)(_nbits)) << SNOR_PROTO_ADDR_SHIFT) & \
|
||||
SNOR_PROTO_ADDR_MASK)
|
||||
|
||||
#define SNOR_PROTO_DATA_MASK GENMASK(7, 0)
|
||||
#define SNOR_PROTO_DATA_SHIFT 0
|
||||
#define SNOR_PROTO_DATA(_nbits) \
|
||||
((((unsigned long)(_nbits)) << SNOR_PROTO_DATA_SHIFT) & \
|
||||
SNOR_PROTO_DATA_MASK)
|
||||
|
||||
#define SNOR_PROTO_IS_DTR BIT(24) /* Double Transfer Rate */
|
||||
|
||||
#define SNOR_PROTO_STR(_inst_nbits, _addr_nbits, _data_nbits) \
|
||||
(SNOR_PROTO_INST(_inst_nbits) | \
|
||||
SNOR_PROTO_ADDR(_addr_nbits) | \
|
||||
SNOR_PROTO_DATA(_data_nbits))
|
||||
#define SNOR_PROTO_DTR(_inst_nbits, _addr_nbits, _data_nbits) \
|
||||
(SNOR_PROTO_IS_DTR | \
|
||||
SNOR_PROTO_STR(_inst_nbits, _addr_nbits, _data_nbits))
|
||||
|
||||
enum spi_nor_protocol {
|
||||
SNOR_PROTO_1_1_1 = SNOR_PROTO_STR(1, 1, 1),
|
||||
SNOR_PROTO_1_1_2 = SNOR_PROTO_STR(1, 1, 2),
|
||||
SNOR_PROTO_1_1_4 = SNOR_PROTO_STR(1, 1, 4),
|
||||
SNOR_PROTO_1_1_8 = SNOR_PROTO_STR(1, 1, 8),
|
||||
SNOR_PROTO_1_2_2 = SNOR_PROTO_STR(1, 2, 2),
|
||||
SNOR_PROTO_1_4_4 = SNOR_PROTO_STR(1, 4, 4),
|
||||
SNOR_PROTO_1_8_8 = SNOR_PROTO_STR(1, 8, 8),
|
||||
SNOR_PROTO_2_2_2 = SNOR_PROTO_STR(2, 2, 2),
|
||||
SNOR_PROTO_4_4_4 = SNOR_PROTO_STR(4, 4, 4),
|
||||
SNOR_PROTO_8_8_8 = SNOR_PROTO_STR(8, 8, 8),
|
||||
|
||||
SNOR_PROTO_1_1_1_DTR = SNOR_PROTO_DTR(1, 1, 1),
|
||||
SNOR_PROTO_1_2_2_DTR = SNOR_PROTO_DTR(1, 2, 2),
|
||||
SNOR_PROTO_1_4_4_DTR = SNOR_PROTO_DTR(1, 4, 4),
|
||||
SNOR_PROTO_1_8_8_DTR = SNOR_PROTO_DTR(1, 8, 8),
|
||||
SNOR_PROTO_8_8_8_DTR = SNOR_PROTO_DTR(8, 8, 8),
|
||||
};
|
||||
|
||||
static inline bool spi_nor_protocol_is_dtr(enum spi_nor_protocol proto)
|
||||
{
|
||||
return !!(proto & SNOR_PROTO_IS_DTR);
|
||||
}
|
||||
|
||||
static inline u8 spi_nor_get_protocol_inst_nbits(enum spi_nor_protocol proto)
|
||||
{
|
||||
return ((unsigned long)(proto & SNOR_PROTO_INST_MASK)) >>
|
||||
SNOR_PROTO_INST_SHIFT;
|
||||
}
|
||||
|
||||
static inline u8 spi_nor_get_protocol_addr_nbits(enum spi_nor_protocol proto)
|
||||
{
|
||||
return ((unsigned long)(proto & SNOR_PROTO_ADDR_MASK)) >>
|
||||
SNOR_PROTO_ADDR_SHIFT;
|
||||
}
|
||||
|
||||
static inline u8 spi_nor_get_protocol_data_nbits(enum spi_nor_protocol proto)
|
||||
{
|
||||
return ((unsigned long)(proto & SNOR_PROTO_DATA_MASK)) >>
|
||||
SNOR_PROTO_DATA_SHIFT;
|
||||
}
|
||||
|
||||
static inline u8 spi_nor_get_protocol_width(enum spi_nor_protocol proto)
|
||||
{
|
||||
return spi_nor_get_protocol_data_nbits(proto);
|
||||
}
|
||||
|
||||
/**
|
||||
* struct spi_nor_hwcaps - Structure for describing the hardware capabilies
|
||||
* supported by the SPI controller (bus master).
|
||||
* @mask: the bitmask listing all the supported hw capabilies
|
||||
*/
|
||||
struct spi_nor_hwcaps {
|
||||
u32 mask;
|
||||
};
|
||||
|
||||
/*
|
||||
*(Fast) Read capabilities.
|
||||
* MUST be ordered by priority: the higher bit position, the higher priority.
|
||||
* As a matter of performances, it is relevant to use Octal SPI protocols first,
|
||||
* then Quad SPI protocols before Dual SPI protocols, Fast Read and lastly
|
||||
* (Slow) Read.
|
||||
*/
|
||||
#define SNOR_HWCAPS_READ_MASK GENMASK(15, 0)
|
||||
#define SNOR_HWCAPS_READ BIT(0)
|
||||
#define SNOR_HWCAPS_READ_FAST BIT(1)
|
||||
#define SNOR_HWCAPS_READ_1_1_1_DTR BIT(2)
|
||||
|
||||
#define SNOR_HWCAPS_READ_DUAL GENMASK(6, 3)
|
||||
#define SNOR_HWCAPS_READ_1_1_2 BIT(3)
|
||||
#define SNOR_HWCAPS_READ_1_2_2 BIT(4)
|
||||
#define SNOR_HWCAPS_READ_2_2_2 BIT(5)
|
||||
#define SNOR_HWCAPS_READ_1_2_2_DTR BIT(6)
|
||||
|
||||
#define SNOR_HWCAPS_READ_QUAD GENMASK(10, 7)
|
||||
#define SNOR_HWCAPS_READ_1_1_4 BIT(7)
|
||||
#define SNOR_HWCAPS_READ_1_4_4 BIT(8)
|
||||
#define SNOR_HWCAPS_READ_4_4_4 BIT(9)
|
||||
#define SNOR_HWCAPS_READ_1_4_4_DTR BIT(10)
|
||||
|
||||
#define SNOR_HWCAPS_READ_OCTAL GENMASK(15, 11)
|
||||
#define SNOR_HWCAPS_READ_1_1_8 BIT(11)
|
||||
#define SNOR_HWCAPS_READ_1_8_8 BIT(12)
|
||||
#define SNOR_HWCAPS_READ_8_8_8 BIT(13)
|
||||
#define SNOR_HWCAPS_READ_1_8_8_DTR BIT(14)
|
||||
#define SNOR_HWCAPS_READ_8_8_8_DTR BIT(15)
|
||||
|
||||
/*
|
||||
* Page Program capabilities.
|
||||
* MUST be ordered by priority: the higher bit position, the higher priority.
|
||||
* Like (Fast) Read capabilities, Octal/Quad SPI protocols are preferred to the
|
||||
* legacy SPI 1-1-1 protocol.
|
||||
* Note that Dual Page Programs are not supported because there is no existing
|
||||
* JEDEC/SFDP standard to define them. Also at this moment no SPI flash memory
|
||||
* implements such commands.
|
||||
*/
|
||||
#define SNOR_HWCAPS_PP_MASK GENMASK(23, 16)
|
||||
#define SNOR_HWCAPS_PP BIT(16)
|
||||
|
||||
#define SNOR_HWCAPS_PP_QUAD GENMASK(19, 17)
|
||||
#define SNOR_HWCAPS_PP_1_1_4 BIT(17)
|
||||
#define SNOR_HWCAPS_PP_1_4_4 BIT(18)
|
||||
#define SNOR_HWCAPS_PP_4_4_4 BIT(19)
|
||||
|
||||
#define SNOR_HWCAPS_PP_OCTAL GENMASK(23, 20)
|
||||
#define SNOR_HWCAPS_PP_1_1_8 BIT(20)
|
||||
#define SNOR_HWCAPS_PP_1_8_8 BIT(21)
|
||||
#define SNOR_HWCAPS_PP_8_8_8 BIT(22)
|
||||
#define SNOR_HWCAPS_PP_8_8_8_DTR BIT(23)
|
||||
|
||||
#define SNOR_HWCAPS_X_X_X (SNOR_HWCAPS_READ_2_2_2 | \
|
||||
SNOR_HWCAPS_READ_4_4_4 | \
|
||||
SNOR_HWCAPS_READ_8_8_8 | \
|
||||
SNOR_HWCAPS_PP_4_4_4 | \
|
||||
SNOR_HWCAPS_PP_8_8_8)
|
||||
|
||||
#define SNOR_HWCAPS_X_X_X_DTR (SNOR_HWCAPS_READ_8_8_8_DTR | \
|
||||
SNOR_HWCAPS_PP_8_8_8_DTR)
|
||||
|
||||
#define SNOR_HWCAPS_DTR (SNOR_HWCAPS_READ_1_1_1_DTR | \
|
||||
SNOR_HWCAPS_READ_1_2_2_DTR | \
|
||||
SNOR_HWCAPS_READ_1_4_4_DTR | \
|
||||
SNOR_HWCAPS_READ_1_8_8_DTR | \
|
||||
SNOR_HWCAPS_READ_8_8_8_DTR)
|
||||
|
||||
#define SNOR_HWCAPS_ALL (SNOR_HWCAPS_READ_MASK | \
|
||||
SNOR_HWCAPS_PP_MASK)
|
||||
|
||||
/* Forward declaration that is used in 'struct spi_nor_controller_ops' */
|
||||
struct spi_nor;
|
||||
|
||||
/**
|
||||
* struct spi_nor_controller_ops - SPI NOR controller driver specific
|
||||
* operations.
|
||||
* @prepare: [OPTIONAL] do some preparations for the
|
||||
* read/write/erase/lock/unlock operations.
|
||||
* @unprepare: [OPTIONAL] do some post work after the
|
||||
* read/write/erase/lock/unlock operations.
|
||||
* @read_reg: read out the register.
|
||||
* @write_reg: write data to the register.
|
||||
* @read: read data from the SPI NOR.
|
||||
* @write: write data to the SPI NOR.
|
||||
* @erase: erase a sector of the SPI NOR at the offset @offs; if
|
||||
* not provided by the driver, SPI NOR will send the erase
|
||||
* opcode via write_reg().
|
||||
*/
|
||||
struct spi_nor_controller_ops {
|
||||
int (*prepare)(struct spi_nor *nor);
|
||||
void (*unprepare)(struct spi_nor *nor);
|
||||
int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, size_t len);
|
||||
int (*write_reg)(struct spi_nor *nor, u8 opcode, const u8 *buf,
|
||||
size_t len);
|
||||
|
||||
ssize_t (*read)(struct spi_nor *nor, loff_t from, size_t len, u8 *buf);
|
||||
ssize_t (*write)(struct spi_nor *nor, loff_t to, size_t len,
|
||||
const u8 *buf);
|
||||
int (*erase)(struct spi_nor *nor, loff_t offs);
|
||||
};
|
||||
|
||||
/**
|
||||
* enum spi_nor_cmd_ext - describes the command opcode extension in DTR mode
|
||||
* @SPI_NOR_EXT_NONE: no extension. This is the default, and is used in Legacy
|
||||
* SPI mode
|
||||
* @SPI_NOR_EXT_REPEAT: the extension is same as the opcode
|
||||
* @SPI_NOR_EXT_INVERT: the extension is the bitwise inverse of the opcode
|
||||
* @SPI_NOR_EXT_HEX: the extension is any hex value. The command and opcode
|
||||
* combine to form a 16-bit opcode.
|
||||
*/
|
||||
enum spi_nor_cmd_ext {
|
||||
SPI_NOR_EXT_NONE = 0,
|
||||
SPI_NOR_EXT_REPEAT,
|
||||
SPI_NOR_EXT_INVERT,
|
||||
SPI_NOR_EXT_HEX,
|
||||
};
|
||||
|
||||
/*
|
||||
* Forward declarations that are used internally by the core and manufacturer
|
||||
* drivers.
|
||||
*/
|
||||
struct flash_info;
|
||||
struct spi_nor_manufacturer;
|
||||
struct spi_nor_flash_parameter;
|
||||
|
||||
/**
|
||||
* struct spi_nor - Structure for defining the SPI NOR layer
|
||||
* @mtd: an mtd_info structure
|
||||
* @lock: the lock for the read/write/erase/lock/unlock operations
|
||||
* @rww: Read-While-Write (RWW) sync lock
|
||||
* @rww.wait: wait queue for the RWW sync
|
||||
* @rww.ongoing_io: the bus is busy
|
||||
* @rww.ongoing_rd: a read is ongoing on the chip
|
||||
* @rww.ongoing_pe: a program/erase is ongoing on the chip
|
||||
* @rww.used_banks: bitmap of the banks in use
|
||||
* @dev: pointer to an SPI device or an SPI NOR controller device
|
||||
* @spimem: pointer to the SPI memory device
|
||||
* @bouncebuf: bounce buffer used when the buffer passed by the MTD
|
||||
* layer is not DMA-able
|
||||
* @bouncebuf_size: size of the bounce buffer
|
||||
* @id: The flash's ID bytes. Always contains
|
||||
* SPI_NOR_MAX_ID_LEN bytes.
|
||||
* @info: SPI NOR part JEDEC MFR ID and other info
|
||||
* @manufacturer: SPI NOR manufacturer
|
||||
* @addr_nbytes: number of address bytes
|
||||
* @erase_opcode: the opcode for erasing a sector
|
||||
* @read_opcode: the read opcode
|
||||
* @read_dummy: the dummy needed by the read operation
|
||||
* @program_opcode: the program opcode
|
||||
* @sst_write_second: used by the SST write operation
|
||||
* @flags: flag options for the current SPI NOR (SNOR_F_*)
|
||||
* @cmd_ext_type: the command opcode extension type for DTR mode.
|
||||
* @read_proto: the SPI protocol for read operations
|
||||
* @write_proto: the SPI protocol for write operations
|
||||
* @reg_proto: the SPI protocol for read_reg/write_reg/erase operations
|
||||
* @sfdp: the SFDP data of the flash
|
||||
* @debugfs_root: pointer to the debugfs directory
|
||||
* @controller_ops: SPI NOR controller driver specific operations.
|
||||
* @params: [FLASH-SPECIFIC] SPI NOR flash parameters and settings.
|
||||
* The structure includes legacy flash parameters and
|
||||
* settings that can be overwritten by the spi_nor_fixups
|
||||
* hooks, or dynamically when parsing the SFDP tables.
|
||||
* @dirmap: pointers to struct spi_mem_dirmap_desc for reads/writes.
|
||||
* @priv: pointer to the private data
|
||||
*/
|
||||
struct spi_nor {
|
||||
struct mtd_info mtd;
|
||||
struct mutex lock;
|
||||
struct spi_nor_rww {
|
||||
wait_queue_head_t wait;
|
||||
bool ongoing_io;
|
||||
bool ongoing_rd;
|
||||
bool ongoing_pe;
|
||||
unsigned int used_banks;
|
||||
} rww;
|
||||
struct device *dev;
|
||||
struct spi_mem *spimem;
|
||||
u8 *bouncebuf;
|
||||
size_t bouncebuf_size;
|
||||
u8 *id;
|
||||
const struct flash_info *info;
|
||||
const struct spi_nor_manufacturer *manufacturer;
|
||||
u8 addr_nbytes;
|
||||
u8 erase_opcode;
|
||||
u8 read_opcode;
|
||||
u8 read_dummy;
|
||||
u8 program_opcode;
|
||||
enum spi_nor_protocol read_proto;
|
||||
enum spi_nor_protocol write_proto;
|
||||
enum spi_nor_protocol reg_proto;
|
||||
bool sst_write_second;
|
||||
u32 flags;
|
||||
enum spi_nor_cmd_ext cmd_ext_type;
|
||||
struct sfdp *sfdp;
|
||||
struct dentry *debugfs_root;
|
||||
|
||||
const struct spi_nor_controller_ops *controller_ops;
|
||||
|
||||
struct spi_nor_flash_parameter *params;
|
||||
|
||||
struct {
|
||||
struct spi_mem_dirmap_desc *rdesc;
|
||||
struct spi_mem_dirmap_desc *wdesc;
|
||||
} dirmap;
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
static inline void spi_nor_set_flash_node(struct spi_nor *nor,
|
||||
struct device_node *np)
|
||||
{
|
||||
mtd_set_of_node(&nor->mtd, np);
|
||||
}
|
||||
|
||||
static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
|
||||
{
|
||||
return mtd_get_of_node(&nor->mtd);
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_nor_scan() - scan the SPI NOR
|
||||
* @nor: the spi_nor structure
|
||||
* @name: the chip type name
|
||||
* @hwcaps: the hardware capabilities supported by the controller driver
|
||||
*
|
||||
* The drivers can use this function to scan the SPI NOR.
|
||||
* In the scanning, it will try to get all the necessary information to
|
||||
* fill the mtd_info{} and the spi_nor{}.
|
||||
*
|
||||
* The chip type name can be provided through the @name parameter.
|
||||
*
|
||||
* Return: 0 for success, others for failure.
|
||||
*/
|
||||
int spi_nor_scan(struct spi_nor *nor, const char *name,
|
||||
const struct spi_nor_hwcaps *hwcaps);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,905 @@
|
||||
/* 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_1S_0_0_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_1S_0_0_OP \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x06, 1), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_WR_DIS_1S_0_0_OP \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x04, 1), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_READID_1S_1S_1S_OP(naddr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1), \
|
||||
SPI_MEM_OP_ADDR(naddr, 0, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1))
|
||||
|
||||
#define SPINAND_SET_FEATURE_1S_1S_1S_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_1S_1S_1S_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_1S_1S_0_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_1S_1S_0_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_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x03, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x0b, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x03, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_FAST_3A_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x0b, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_1D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x0d, 1), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 1), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(addr, ndummy, buf, len, freq) \
|
||||
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), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_2S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_2D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x3d, 1), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 2), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(addr, ndummy, buf, len, freq) \
|
||||
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), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_2S_2S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 2), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 2), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_2D_2D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xbd, 1), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 2), \
|
||||
SPI_MEM_DTR_OP_DUMMY(ndummy, 2), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 2), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(addr, ndummy, buf, len, freq) \
|
||||
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), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_4S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_4D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x6d, 1), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 4), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(addr, ndummy, buf, len, freq) \
|
||||
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), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_4S_4S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 4), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 4), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_4D_4D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xed, 1), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 4), \
|
||||
SPI_MEM_DTR_OP_DUMMY(ndummy, 4), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 4), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_8S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x8b, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 8), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xcb, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 8), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 8), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 8), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_8D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x9d, 1), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 8), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PROG_EXEC_1S_1S_0_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_1S_1S_1S_OP(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_1S_1S_4S_OP(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))
|
||||
|
||||
#define SPINAND_PROG_LOAD_1S_1S_8S_OP(addr, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x82, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_OUT(len, buf, 8))
|
||||
|
||||
#define SPINAND_PROG_LOAD_1S_8S_8S_OP(reset, addr, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0xc2 : 0xc4, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 8), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_OUT(len, buf, 8))
|
||||
|
||||
/**
|
||||
* Octal DDR SPI NAND flash operations
|
||||
*/
|
||||
|
||||
#define SPINAND_RESET_8D_0_0_OP \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0xff, 8), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_READID_8D_8D_8D_OP(naddr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9f, 8), \
|
||||
SPI_MEM_DTR_OP_ADDR(naddr, 0, 8), \
|
||||
SPI_MEM_DTR_OP_DUMMY(ndummy, 8), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 8))
|
||||
|
||||
#define SPINAND_WR_EN_8D_0_0_OP \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x06, 8), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_WR_DIS_8D_0_0_OP \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x04, 8), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_SET_FEATURE_8D_8D_8D_OP(reg, valptr) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x1f, 8), \
|
||||
SPI_MEM_DTR_OP_RPT_ADDR(reg, 8), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_DTR_OP_DATA_OUT(2, valptr, 8))
|
||||
|
||||
#define SPINAND_GET_FEATURE_8D_8D_8D_OP(reg, valptr) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x0f, 8), \
|
||||
SPI_MEM_DTR_OP_RPT_ADDR(reg, 8), \
|
||||
SPI_MEM_DTR_OP_DUMMY(14, 8), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(2, valptr, 8))
|
||||
|
||||
#define SPINAND_BLK_ERASE_8D_8D_0_OP(addr) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0xd8, 8), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 8), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_PAGE_READ_8D_8D_0_OP(addr) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x13, 8), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 8), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_PAGE_READ_PACKED_8D_8D_0_OP(addr) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_PACKED_CMD(0x13, addr >> 16, 8), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr & 0xffff, 8), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9d, 8), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 8), \
|
||||
SPI_MEM_DTR_OP_DUMMY(ndummy, 8), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 8), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PROG_EXEC_8D_8D_0_OP(addr) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x10, 8), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 8), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_PROG_LOAD_8D_8D_8D_OP(reset, addr, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD((reset ? 0xc2 : 0xc4), 8), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 8), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_DTR_OP_DATA_OUT(len, buf, 8))
|
||||
|
||||
/* 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 6
|
||||
/*
|
||||
* For erase, write and read operation, we got the following timings :
|
||||
* tBERS (erase) 1ms to 4ms
|
||||
* tPROG 300us to 400us
|
||||
* tREAD 25us to 100us
|
||||
* In order to minimize latency, the min value is divided by 4 for the
|
||||
* initial delay, and dividing by 20 for the poll delay.
|
||||
* For reset, 5us/10us/500us if the device is respectively
|
||||
* reading/programming/erasing when the RESET occurs. Since we always
|
||||
* issue a RESET when the device is IDLE, 5us is selected for both initial
|
||||
* and poll delay.
|
||||
*/
|
||||
#define SPINAND_READ_INITIAL_DELAY_US 6
|
||||
#define SPINAND_READ_POLL_DELAY_US 5
|
||||
#define SPINAND_RESET_INITIAL_DELAY_US 5
|
||||
#define SPINAND_RESET_POLL_DELAY_US 5
|
||||
#define SPINAND_WRITE_INITIAL_DELAY_US 75
|
||||
#define SPINAND_WRITE_POLL_DELAY_US 15
|
||||
#define SPINAND_ERASE_INITIAL_DELAY_US 250
|
||||
#define SPINAND_ERASE_POLL_DELAY_US 50
|
||||
|
||||
#define SPINAND_WAITRDY_TIMEOUT_MS 400
|
||||
|
||||
/**
|
||||
* struct spinand_id - SPI NAND id structure
|
||||
* @data: buffer containing the id bytes. Currently 6 bytes large, but can
|
||||
* be extended if required
|
||||
* @len: ID length
|
||||
*/
|
||||
struct spinand_id {
|
||||
u8 data[SPINAND_MAX_ID_LEN];
|
||||
int len;
|
||||
};
|
||||
|
||||
enum spinand_readid_method {
|
||||
SPINAND_READID_METHOD_OPCODE,
|
||||
SPINAND_READID_METHOD_OPCODE_ADDR,
|
||||
SPINAND_READID_METHOD_OPCODE_DUMMY,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct spinand_devid - SPI NAND device id structure
|
||||
* @id: device id of current chip
|
||||
* @len: number of bytes in device id
|
||||
* @method: method to read chip id
|
||||
* There are 3 possible variants:
|
||||
* SPINAND_READID_METHOD_OPCODE: chip id is returned immediately
|
||||
* after read_id opcode.
|
||||
* SPINAND_READID_METHOD_OPCODE_ADDR: chip id is returned after
|
||||
* read_id opcode + 1-byte address.
|
||||
* SPINAND_READID_METHOD_OPCODE_DUMMY: chip id is returned after
|
||||
* read_id opcode + 1 dummy byte.
|
||||
*/
|
||||
struct spinand_devid {
|
||||
const u8 *id;
|
||||
const u8 len;
|
||||
const enum spinand_readid_method method;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct manufacurer_ops - SPI NAND manufacturer specific operations
|
||||
* @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 initialized properly.
|
||||
*/
|
||||
struct spinand_manufacturer_ops {
|
||||
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
|
||||
* @devid_len: number of bytes in device ID
|
||||
* @chips: supported SPI NANDs under current manufacturer
|
||||
* @nchips: number of SPI NANDs available in chips array
|
||||
* @ops: manufacturer operations
|
||||
*/
|
||||
struct spinand_manufacturer {
|
||||
u8 id;
|
||||
char *name;
|
||||
const struct spinand_info *chips;
|
||||
const size_t nchips;
|
||||
const struct spinand_manufacturer_ops *ops;
|
||||
};
|
||||
|
||||
/* SPI NAND manufacturers */
|
||||
extern const struct spinand_manufacturer alliancememory_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer ato_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer dosilicon_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer esmt_8c_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer fmsh_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer foresee_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer macronix_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer micron_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer paragon_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer skyhigh_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer winbond_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer xtx_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;
|
||||
};
|
||||
|
||||
/* SPI NAND flags */
|
||||
#define SPINAND_HAS_QE_BIT BIT(0)
|
||||
#define SPINAND_HAS_CR_FEAT_BIT BIT(1)
|
||||
#define SPINAND_HAS_PROG_PLANE_SELECT_BIT BIT(2)
|
||||
#define SPINAND_HAS_READ_PLANE_SELECT_BIT BIT(3)
|
||||
#define SPINAND_NO_RAW_ACCESS BIT(4)
|
||||
#define SPINAND_ODTR_PACKED_PAGE_READ BIT(5)
|
||||
|
||||
/**
|
||||
* struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure
|
||||
* @status: status of the last wait operation that will be used in case
|
||||
* ->get_status() is not populated by the spinand device.
|
||||
*/
|
||||
struct spinand_ondie_ecc_conf {
|
||||
u8 status;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct spinand_otp_layout - structure to describe the SPI NAND OTP area
|
||||
* @npages: number of pages in the OTP
|
||||
* @start_page: start page of the user/factory OTP area.
|
||||
*/
|
||||
struct spinand_otp_layout {
|
||||
unsigned int npages;
|
||||
unsigned int start_page;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct spinand_fact_otp_ops - SPI NAND OTP methods for factory area
|
||||
* @info: get the OTP area information
|
||||
* @read: read from the SPI NAND OTP area
|
||||
*/
|
||||
struct spinand_fact_otp_ops {
|
||||
int (*info)(struct spinand_device *spinand, size_t len,
|
||||
struct otp_info *buf, size_t *retlen);
|
||||
int (*read)(struct spinand_device *spinand, loff_t from, size_t len,
|
||||
size_t *retlen, u8 *buf);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct spinand_user_otp_ops - SPI NAND OTP methods for user area
|
||||
* @info: get the OTP area information
|
||||
* @lock: lock an OTP region
|
||||
* @erase: erase an OTP region
|
||||
* @read: read from the SPI NAND OTP area
|
||||
* @write: write to the SPI NAND OTP area
|
||||
*/
|
||||
struct spinand_user_otp_ops {
|
||||
int (*info)(struct spinand_device *spinand, size_t len,
|
||||
struct otp_info *buf, size_t *retlen);
|
||||
int (*lock)(struct spinand_device *spinand, loff_t from, size_t len);
|
||||
int (*erase)(struct spinand_device *spinand, loff_t from, size_t len);
|
||||
int (*read)(struct spinand_device *spinand, loff_t from, size_t len,
|
||||
size_t *retlen, u8 *buf);
|
||||
int (*write)(struct spinand_device *spinand, loff_t from, size_t len,
|
||||
size_t *retlen, const u8 *buf);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct spinand_fact_otp - SPI NAND OTP grouping structure for factory area
|
||||
* @layout: OTP region layout
|
||||
* @ops: OTP access ops
|
||||
*/
|
||||
struct spinand_fact_otp {
|
||||
const struct spinand_otp_layout layout;
|
||||
const struct spinand_fact_otp_ops *ops;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct spinand_user_otp - SPI NAND OTP grouping structure for user area
|
||||
* @layout: OTP region layout
|
||||
* @ops: OTP access ops
|
||||
*/
|
||||
struct spinand_user_otp {
|
||||
const struct spinand_otp_layout layout;
|
||||
const struct spinand_user_otp_ops *ops;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum spinand_bus_interface - SPI NAND bus interface types
|
||||
* @SSDR: Bus configuration supporting all 1S-XX-XX operations, including dual and quad
|
||||
* @ODTR: Bus configuration supporting only 8D-8D-8D operations
|
||||
*/
|
||||
enum spinand_bus_interface {
|
||||
SSDR,
|
||||
ODTR,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @vendor_ops: vendor specific operations
|
||||
* @select_target: function used to select a target/die. Required only for
|
||||
* multi-die chips
|
||||
* @configure_chip: Align the chip configuration with the core settings
|
||||
* @set_cont_read: enable/disable continuous cached reads
|
||||
* @fact_otp: SPI NAND factory OTP info.
|
||||
* @user_otp: SPI NAND user OTP info.
|
||||
* @read_retries: the number of read retry modes supported
|
||||
* @set_read_retry: enable/disable read retry for data recovery
|
||||
*
|
||||
* 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;
|
||||
struct spinand_devid devid;
|
||||
u32 flags;
|
||||
struct nand_memory_organization memorg;
|
||||
struct nand_ecc_props 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;
|
||||
const struct spinand_op_variants *vendor_ops;
|
||||
int (*select_target)(struct spinand_device *spinand,
|
||||
unsigned int target);
|
||||
int (*configure_chip)(struct spinand_device *spinand,
|
||||
enum spinand_bus_interface iface);
|
||||
int (*set_cont_read)(struct spinand_device *spinand,
|
||||
bool enable);
|
||||
struct spinand_fact_otp fact_otp;
|
||||
struct spinand_user_otp user_otp;
|
||||
unsigned int read_retries;
|
||||
int (*set_read_retry)(struct spinand_device *spinand,
|
||||
unsigned int read_retry);
|
||||
};
|
||||
|
||||
#define SPINAND_ID(__method, ...) \
|
||||
{ \
|
||||
.id = (const u8[]){ __VA_ARGS__ }, \
|
||||
.len = sizeof((u8[]){ __VA_ARGS__ }), \
|
||||
.method = __method, \
|
||||
}
|
||||
|
||||
#define SPINAND_INFO_OP_VARIANTS(__read, __write, __update) \
|
||||
{ \
|
||||
.read_cache = __read, \
|
||||
.write_cache = __write, \
|
||||
.update_cache = __update, \
|
||||
}
|
||||
|
||||
#define SPINAND_INFO_VENDOR_OPS(__ops) \
|
||||
.vendor_ops = __ops
|
||||
|
||||
#define SPINAND_ECCINFO(__ooblayout, __get_status) \
|
||||
.eccinfo = { \
|
||||
.ooblayout = __ooblayout, \
|
||||
.get_status = __get_status, \
|
||||
}
|
||||
|
||||
#define SPINAND_SELECT_TARGET(__func) \
|
||||
.select_target = __func
|
||||
|
||||
#define SPINAND_CONFIGURE_CHIP(__configure_chip) \
|
||||
.configure_chip = __configure_chip
|
||||
|
||||
#define SPINAND_CONT_READ(__set_cont_read) \
|
||||
.set_cont_read = __set_cont_read
|
||||
|
||||
#define SPINAND_FACT_OTP_INFO(__npages, __start_page, __ops) \
|
||||
.fact_otp = { \
|
||||
.layout = { \
|
||||
.npages = __npages, \
|
||||
.start_page = __start_page, \
|
||||
}, \
|
||||
.ops = __ops, \
|
||||
}
|
||||
|
||||
#define SPINAND_USER_OTP_INFO(__npages, __start_page, __ops) \
|
||||
.user_otp = { \
|
||||
.layout = { \
|
||||
.npages = __npages, \
|
||||
.start_page = __start_page, \
|
||||
}, \
|
||||
.ops = __ops, \
|
||||
}
|
||||
|
||||
#define SPINAND_READ_RETRY(__read_retries, __set_read_retry) \
|
||||
.read_retries = __read_retries, \
|
||||
.set_read_retry = __set_read_retry
|
||||
|
||||
#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_dirmap {
|
||||
struct spi_mem_dirmap_desc *wdesc;
|
||||
struct spi_mem_dirmap_desc *rdesc;
|
||||
struct spi_mem_dirmap_desc *wdesc_ecc;
|
||||
struct spi_mem_dirmap_desc *rdesc_ecc;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct spinand_mem_ops - SPI NAND memory operations
|
||||
* @reset: reset op template
|
||||
* @readid: read ID op template
|
||||
* @wr_en: write enable op template
|
||||
* @wr_dis: write disable op template
|
||||
* @set_feature: set feature op template
|
||||
* @get_feature: get feature op template
|
||||
* @blk_erase: blk erase op template
|
||||
* @page_read: page read op template
|
||||
* @prog_exec: prog exec op template
|
||||
* @read_cache: read cache op template
|
||||
* @write_cache: write cache op template
|
||||
* @update_cache: update cache op template
|
||||
*/
|
||||
struct spinand_mem_ops {
|
||||
struct spi_mem_op reset;
|
||||
struct spi_mem_op readid;
|
||||
struct spi_mem_op wr_en;
|
||||
struct spi_mem_op wr_dis;
|
||||
struct spi_mem_op set_feature;
|
||||
struct spi_mem_op get_feature;
|
||||
struct spi_mem_op blk_erase;
|
||||
struct spi_mem_op page_read;
|
||||
struct spi_mem_op prog_exec;
|
||||
const struct spi_mem_op *read_cache;
|
||||
const struct spi_mem_op *write_cache;
|
||||
const struct spi_mem_op *update_cache;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @ssdr_op_templates: Templates for all single SDR SPI mem operations
|
||||
* @odtr_op_templates: Templates for all octal DTR SPI mem operations
|
||||
* @op_templates: Templates for all SPI mem operations
|
||||
* @bus_iface: Current bus interface
|
||||
* @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
|
||||
* @configure_chip: Align the chip configuration with the core settings
|
||||
* @cont_read_possible: Field filled by the core once the whole system
|
||||
* configuration is known to tell whether continuous reads are
|
||||
* suitable to use or not in general with this chip/configuration.
|
||||
* A per-transfer check must of course be done to ensure it is
|
||||
* actually relevant to enable this feature.
|
||||
* @set_cont_read: Enable/disable the continuous read feature
|
||||
* @priv: manufacturer private data
|
||||
* @fact_otp: SPI NAND factory OTP info.
|
||||
* @user_otp: SPI NAND user OTP info.
|
||||
* @read_retries: the number of read retry modes supported
|
||||
* @set_read_retry: Enable/disable the read retry feature
|
||||
*/
|
||||
struct spinand_device {
|
||||
struct nand_device base;
|
||||
struct spi_mem *spimem;
|
||||
struct mutex lock;
|
||||
struct spinand_id id;
|
||||
u32 flags;
|
||||
|
||||
struct spinand_mem_ops ssdr_op_templates;
|
||||
struct spinand_mem_ops odtr_op_templates;
|
||||
struct spinand_mem_ops *op_templates;
|
||||
enum spinand_bus_interface bus_iface;
|
||||
|
||||
struct spinand_dirmap *dirmaps;
|
||||
|
||||
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;
|
||||
|
||||
int (*configure_chip)(struct spinand_device *spinand,
|
||||
enum spinand_bus_interface iface);
|
||||
bool cont_read_possible;
|
||||
int (*set_cont_read)(struct spinand_device *spinand,
|
||||
bool enable);
|
||||
|
||||
const struct spinand_fact_otp *fact_otp;
|
||||
const struct spinand_user_otp *user_otp;
|
||||
|
||||
unsigned int read_retries;
|
||||
int (*set_read_retry)(struct spinand_device *spinand,
|
||||
unsigned int retry_mode);
|
||||
};
|
||||
|
||||
struct spi_mem_op spinand_fill_wr_en_op(struct spinand_device *spinand);
|
||||
struct spi_mem_op spinand_fill_set_feature_op(struct spinand_device *spinand, u64 reg, const void *valptr);
|
||||
struct spi_mem_op spinand_fill_get_feature_op(struct spinand_device *spinand, u64 reg, void *valptr);
|
||||
struct spi_mem_op spinand_fill_prog_exec_op(struct spinand_device *spinand, u64 addr);
|
||||
|
||||
#define SPINAND_OP(spinand, op_name, ...) \
|
||||
spinand_fill_ ## op_name ## _op(spinand, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* 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 *spinand,
|
||||
const struct spinand_info *table,
|
||||
unsigned int table_size,
|
||||
enum spinand_readid_method rdid_method);
|
||||
|
||||
int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
|
||||
int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val);
|
||||
int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val);
|
||||
int spinand_write_enable_op(struct spinand_device *spinand);
|
||||
int spinand_select_target(struct spinand_device *spinand, unsigned int target);
|
||||
|
||||
int spinand_wait(struct spinand_device *spinand, unsigned long initial_delay_us,
|
||||
unsigned long poll_delay_us, u8 *s);
|
||||
|
||||
int spinand_read_page(struct spinand_device *spinand,
|
||||
const struct nand_page_io_req *req);
|
||||
|
||||
int spinand_write_page(struct spinand_device *spinand,
|
||||
const struct nand_page_io_req *req);
|
||||
|
||||
size_t spinand_otp_page_size(struct spinand_device *spinand);
|
||||
size_t spinand_fact_otp_size(struct spinand_device *spinand);
|
||||
size_t spinand_user_otp_size(struct spinand_device *spinand);
|
||||
|
||||
int spinand_fact_otp_read(struct spinand_device *spinand, loff_t ofs,
|
||||
size_t len, size_t *retlen, u8 *buf);
|
||||
int spinand_user_otp_read(struct spinand_device *spinand, loff_t ofs,
|
||||
size_t len, size_t *retlen, u8 *buf);
|
||||
int spinand_user_otp_write(struct spinand_device *spinand, loff_t ofs,
|
||||
size_t len, size_t *retlen, const u8 *buf);
|
||||
|
||||
int spinand_set_mtd_otp_ops(struct spinand_device *spinand);
|
||||
|
||||
#endif /* __LINUX_MTD_SPINAND_H */
|
||||
@@ -0,0 +1,25 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* MTD-based superblock handling
|
||||
*
|
||||
* Copyright © 2006 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#ifndef __MTD_SUPER_H__
|
||||
#define __MTD_SUPER_H__
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mount.h>
|
||||
|
||||
extern int get_tree_mtd(struct fs_context *fc,
|
||||
int (*fill_super)(struct super_block *sb,
|
||||
struct fs_context *fc));
|
||||
extern void kill_mtd_super(struct super_block *sb);
|
||||
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __MTD_SUPER_H__ */
|
||||
@@ -0,0 +1,273 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) International Business Machines Corp., 2006
|
||||
*
|
||||
* Author: Artem Bityutskiy (Битюцкий Артём)
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_UBI_H__
|
||||
#define __LINUX_UBI_H__
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <mtd/ubi-user.h>
|
||||
|
||||
/* All voumes/LEBs */
|
||||
#define UBI_ALL -1
|
||||
|
||||
/*
|
||||
* Maximum number of scatter gather list entries,
|
||||
* we use only 64 to have a lower memory foot print.
|
||||
*/
|
||||
#define UBI_MAX_SG_COUNT 64
|
||||
|
||||
/*
|
||||
* enum ubi_open_mode - UBI volume open mode constants.
|
||||
*
|
||||
* UBI_READONLY: read-only mode
|
||||
* UBI_READWRITE: read-write mode
|
||||
* UBI_EXCLUSIVE: exclusive mode
|
||||
* UBI_METAONLY: modify only the volume meta-data,
|
||||
* i.e. the data stored in the volume table, but not in any of volume LEBs.
|
||||
*/
|
||||
enum {
|
||||
UBI_READONLY = 1,
|
||||
UBI_READWRITE,
|
||||
UBI_EXCLUSIVE,
|
||||
UBI_METAONLY
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ubi_volume_info - UBI volume description data structure.
|
||||
* @vol_id: volume ID
|
||||
* @ubi_num: UBI device number this volume belongs to
|
||||
* @size: how many physical eraseblocks are reserved for this volume
|
||||
* @used_bytes: how many bytes of data this volume contains
|
||||
* @used_ebs: how many physical eraseblocks of this volume actually contain any
|
||||
* data
|
||||
* @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
|
||||
* @corrupted: non-zero if the volume is corrupted (static volumes only)
|
||||
* @upd_marker: non-zero if the volume has update marker set
|
||||
* @alignment: volume alignment
|
||||
* @usable_leb_size: how many bytes are available in logical eraseblocks of
|
||||
* this volume
|
||||
* @name_len: volume name length
|
||||
* @name: volume name
|
||||
* @cdev: UBI volume character device major and minor numbers
|
||||
*
|
||||
* The @corrupted flag is only relevant to static volumes and is always zero
|
||||
* for dynamic ones. This is because UBI does not care about dynamic volume
|
||||
* data protection and only cares about protecting static volume data.
|
||||
*
|
||||
* The @upd_marker flag is set if the volume update operation was interrupted.
|
||||
* Before touching the volume data during the update operation, UBI first sets
|
||||
* the update marker flag for this volume. If the volume update operation was
|
||||
* further interrupted, the update marker indicates this. If the update marker
|
||||
* is set, the contents of the volume is certainly damaged and a new volume
|
||||
* update operation has to be started.
|
||||
*
|
||||
* To put it differently, @corrupted and @upd_marker fields have different
|
||||
* semantics:
|
||||
* o the @corrupted flag means that this static volume is corrupted for some
|
||||
* reasons, but not because an interrupted volume update
|
||||
* o the @upd_marker field means that the volume is damaged because of an
|
||||
* interrupted update operation.
|
||||
*
|
||||
* I.e., the @corrupted flag is never set if the @upd_marker flag is set.
|
||||
*
|
||||
* The @used_bytes and @used_ebs fields are only really needed for static
|
||||
* volumes and contain the number of bytes stored in this static volume and how
|
||||
* many eraseblock this data occupies. In case of dynamic volumes, the
|
||||
* @used_bytes field is equivalent to @size*@usable_leb_size, and the @used_ebs
|
||||
* field is equivalent to @size.
|
||||
*
|
||||
* In general, logical eraseblock size is a property of the UBI device, not
|
||||
* of the UBI volume. Indeed, the logical eraseblock size depends on the
|
||||
* physical eraseblock size and on how much bytes UBI headers consume. But
|
||||
* because of the volume alignment (@alignment), the usable size of logical
|
||||
* eraseblocks if a volume may be less. The following equation is true:
|
||||
* @usable_leb_size = LEB size - (LEB size mod @alignment),
|
||||
* where LEB size is the logical eraseblock size defined by the UBI device.
|
||||
*
|
||||
* The alignment is multiple to the minimal flash input/output unit size or %1
|
||||
* if all the available space is used.
|
||||
*
|
||||
* To put this differently, alignment may be considered is a way to change
|
||||
* volume logical eraseblock sizes.
|
||||
*/
|
||||
struct ubi_volume_info {
|
||||
int ubi_num;
|
||||
int vol_id;
|
||||
int size;
|
||||
long long used_bytes;
|
||||
int used_ebs;
|
||||
int vol_type;
|
||||
int corrupted;
|
||||
int upd_marker;
|
||||
int alignment;
|
||||
int usable_leb_size;
|
||||
int name_len;
|
||||
const char *name;
|
||||
dev_t cdev;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ubi_sgl - UBI scatter gather list data structure.
|
||||
* @list_pos: current position in @sg[]
|
||||
* @page_pos: current position in @sg[@list_pos]
|
||||
* @sg: the scatter gather list itself
|
||||
*
|
||||
* ubi_sgl is a wrapper around a scatter list which keeps track of the
|
||||
* current position in the list and the current list item such that
|
||||
* it can be used across multiple ubi_leb_read_sg() calls.
|
||||
*/
|
||||
struct ubi_sgl {
|
||||
int list_pos;
|
||||
int page_pos;
|
||||
struct scatterlist sg[UBI_MAX_SG_COUNT];
|
||||
};
|
||||
|
||||
/**
|
||||
* ubi_sgl_init - initialize an UBI scatter gather list data structure.
|
||||
* @usgl: the UBI scatter gather struct itself
|
||||
*
|
||||
* Please note that you still have to use sg_init_table() or any adequate
|
||||
* function to initialize the unterlaying struct scatterlist.
|
||||
*/
|
||||
static inline void ubi_sgl_init(struct ubi_sgl *usgl)
|
||||
{
|
||||
usgl->list_pos = 0;
|
||||
usgl->page_pos = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct ubi_device_info - UBI device description data structure.
|
||||
* @ubi_num: ubi device number
|
||||
* @leb_size: logical eraseblock size on this UBI device
|
||||
* @leb_start: starting offset of logical eraseblocks within physical
|
||||
* eraseblocks
|
||||
* @min_io_size: minimal I/O unit size
|
||||
* @max_write_size: maximum amount of bytes the underlying flash can write at a
|
||||
* time (MTD write buffer size)
|
||||
* @ro_mode: if this device is in read-only mode
|
||||
* @cdev: UBI character device major and minor numbers
|
||||
*
|
||||
* Note, @leb_size is the logical eraseblock size offered by the UBI device.
|
||||
* Volumes of this UBI device may have smaller logical eraseblock size if their
|
||||
* alignment is not equivalent to %1.
|
||||
*
|
||||
* The @max_write_size field describes flash write maximum write unit. For
|
||||
* example, NOR flash allows for changing individual bytes, so @min_io_size is
|
||||
* %1. However, it does not mean than NOR flash has to write data byte-by-byte.
|
||||
* Instead, CFI NOR flashes have a write-buffer of, e.g., 64 bytes, and when
|
||||
* writing large chunks of data, they write 64-bytes at a time. Obviously, this
|
||||
* improves write throughput.
|
||||
*
|
||||
* Also, the MTD device may have N interleaved (striped) flash chips
|
||||
* underneath, in which case @min_io_size can be physical min. I/O size of
|
||||
* single flash chip, while @max_write_size can be N * @min_io_size.
|
||||
*
|
||||
* The @max_write_size field is always greater or equivalent to @min_io_size.
|
||||
* E.g., some NOR flashes may have (@min_io_size = 1, @max_write_size = 64). In
|
||||
* contrast, NAND flashes usually have @min_io_size = @max_write_size = NAND
|
||||
* page size.
|
||||
*/
|
||||
struct ubi_device_info {
|
||||
int ubi_num;
|
||||
int leb_size;
|
||||
int leb_start;
|
||||
int min_io_size;
|
||||
int max_write_size;
|
||||
int ro_mode;
|
||||
dev_t cdev;
|
||||
};
|
||||
|
||||
/*
|
||||
* Volume notification types.
|
||||
* @UBI_VOLUME_ADDED: a volume has been added (an UBI device was attached or a
|
||||
* volume was created)
|
||||
* @UBI_VOLUME_REMOVED: a volume has been removed (an UBI device was detached
|
||||
* or a volume was removed)
|
||||
* @UBI_VOLUME_RESIZED: a volume has been re-sized
|
||||
* @UBI_VOLUME_RENAMED: a volume has been re-named
|
||||
* @UBI_VOLUME_SHUTDOWN: a volume is going to removed, shutdown users
|
||||
* @UBI_VOLUME_UPDATED: data has been written to a volume
|
||||
*
|
||||
* These constants define which type of event has happened when a volume
|
||||
* notification function is invoked.
|
||||
*/
|
||||
enum {
|
||||
UBI_VOLUME_ADDED,
|
||||
UBI_VOLUME_REMOVED,
|
||||
UBI_VOLUME_RESIZED,
|
||||
UBI_VOLUME_RENAMED,
|
||||
UBI_VOLUME_SHUTDOWN,
|
||||
UBI_VOLUME_UPDATED,
|
||||
};
|
||||
|
||||
/*
|
||||
* struct ubi_notification - UBI notification description structure.
|
||||
* @di: UBI device description object
|
||||
* @vi: UBI volume description object
|
||||
*
|
||||
* UBI notifiers are called with a pointer to an object of this type. The
|
||||
* object describes the notification. Namely, it provides a description of the
|
||||
* UBI device and UBI volume the notification informs about.
|
||||
*/
|
||||
struct ubi_notification {
|
||||
struct ubi_device_info di;
|
||||
struct ubi_volume_info vi;
|
||||
};
|
||||
|
||||
/* UBI descriptor given to users when they open UBI volumes */
|
||||
struct ubi_volume_desc;
|
||||
|
||||
int ubi_get_device_info(int ubi_num, struct ubi_device_info *di);
|
||||
void ubi_get_volume_info(struct ubi_volume_desc *desc,
|
||||
struct ubi_volume_info *vi);
|
||||
struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode);
|
||||
struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
|
||||
int mode);
|
||||
struct ubi_volume_desc *ubi_open_volume_path(const char *pathname, int mode);
|
||||
|
||||
int ubi_register_volume_notifier(struct notifier_block *nb,
|
||||
int ignore_existing);
|
||||
int ubi_unregister_volume_notifier(struct notifier_block *nb);
|
||||
|
||||
void ubi_close_volume(struct ubi_volume_desc *desc);
|
||||
int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
|
||||
int len, int check);
|
||||
int ubi_leb_read_sg(struct ubi_volume_desc *desc, int lnum, struct ubi_sgl *sgl,
|
||||
int offset, int len, int check);
|
||||
int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
|
||||
int offset, int len);
|
||||
int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
|
||||
int len);
|
||||
int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum);
|
||||
int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum);
|
||||
int ubi_leb_map(struct ubi_volume_desc *desc, int lnum);
|
||||
int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum);
|
||||
int ubi_sync(int ubi_num);
|
||||
|
||||
/*
|
||||
* This function is the same as the 'ubi_leb_read()' function, but it does not
|
||||
* provide the checking capability.
|
||||
*/
|
||||
static inline int ubi_read(struct ubi_volume_desc *desc, int lnum, char *buf,
|
||||
int offset, int len)
|
||||
{
|
||||
return ubi_leb_read(desc, lnum, buf, offset, len, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is the same as the 'ubi_leb_read_sg()' function, but it does
|
||||
* not provide the checking capability.
|
||||
*/
|
||||
static inline int ubi_read_sg(struct ubi_volume_desc *desc, int lnum,
|
||||
struct ubi_sgl *sgl, int offset, int len)
|
||||
{
|
||||
return ubi_leb_read_sg(desc, lnum, sgl, offset, len, 0);
|
||||
}
|
||||
#endif /* !__LINUX_UBI_H__ */
|
||||
@@ -0,0 +1,98 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* MTD primitives for XIP support
|
||||
*
|
||||
* Author: Nicolas Pitre
|
||||
* Created: Nov 2, 2004
|
||||
* Copyright: (C) 2004 MontaVista Software, Inc.
|
||||
*
|
||||
* This XIP support for MTD has been loosely inspired
|
||||
* by an earlier patch authored by David Woodhouse.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MTD_XIP_H__
|
||||
#define __LINUX_MTD_XIP_H__
|
||||
|
||||
|
||||
#ifdef CONFIG_MTD_XIP
|
||||
|
||||
/*
|
||||
* We really don't want gcc to guess anything.
|
||||
* We absolutely _need_ proper inlining.
|
||||
*/
|
||||
#include <linux/compiler.h>
|
||||
|
||||
/*
|
||||
* Function that are modifying the flash state away from array mode must
|
||||
* obviously not be running from flash. The __xipram is therefore marking
|
||||
* those functions so they get relocated to ram.
|
||||
*/
|
||||
#ifdef CONFIG_XIP_KERNEL
|
||||
#define __xipram noinline __section(".xiptext")
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Each architecture has to provide the following macros. They must access
|
||||
* the hardware directly and not rely on any other (XIP) functions since they
|
||||
* won't be available when used (flash not in array mode).
|
||||
*
|
||||
* xip_irqpending()
|
||||
*
|
||||
* return non zero when any hardware interrupt is pending.
|
||||
*
|
||||
* xip_currtime()
|
||||
*
|
||||
* return a platform specific time reference to be used with
|
||||
* xip_elapsed_since().
|
||||
*
|
||||
* xip_elapsed_since(x)
|
||||
*
|
||||
* return in usecs the elapsed timebetween now and the reference x as
|
||||
* returned by xip_currtime().
|
||||
*
|
||||
* note 1: conversion to usec can be approximated, as long as the
|
||||
* returned value is <= the real elapsed time.
|
||||
* note 2: this should be able to cope with a few seconds without
|
||||
* overflowing.
|
||||
*
|
||||
* xip_iprefetch()
|
||||
*
|
||||
* Macro to fill instruction prefetch
|
||||
* e.g. a series of nops: asm volatile (".rep 8; nop; .endr");
|
||||
*/
|
||||
|
||||
#include <asm/mtd-xip.h>
|
||||
|
||||
#ifndef xip_irqpending
|
||||
|
||||
#warning "missing IRQ and timer primitives for XIP MTD support"
|
||||
#warning "some of the XIP MTD support code will be disabled"
|
||||
#warning "your system will therefore be unresponsive when writing or erasing flash"
|
||||
|
||||
#define xip_irqpending() (0)
|
||||
#define xip_currtime() (0)
|
||||
#define xip_elapsed_since(x) (0)
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef xip_iprefetch
|
||||
#define xip_iprefetch() do { } while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* xip_cpu_idle() is used when waiting for a delay equal or larger than
|
||||
* the system timer tick period. This should put the CPU into idle mode
|
||||
* to save power and to be woken up only when some interrupts are pending.
|
||||
* This should not rely upon standard kernel code.
|
||||
*/
|
||||
#ifndef xip_cpu_idle
|
||||
#define xip_cpu_idle() do { } while (0)
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_MTD_XIP */
|
||||
|
||||
#ifndef __xipram
|
||||
#define __xipram
|
||||
#endif
|
||||
|
||||
#endif /* __LINUX_MTD_XIP_H__ */
|
||||
Reference in New Issue
Block a user