GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* linux/include/linux/mtd/bbm.h
|
||||
*
|
||||
* 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 */
|
||||
#ifndef CONFIG_SYS_NAND_MAX_CHIPS
|
||||
#define CONFIG_SYS_NAND_MAX_CHIPS 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* 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[CONFIG_SYS_NAND_MAX_CHIPS];
|
||||
int offs;
|
||||
int veroffs;
|
||||
uint8_t version[CONFIG_SYS_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
|
||||
/* Search good / bad pattern on the first and the second page */
|
||||
#define NAND_BBT_SCAN2NDPAGE 0x00008000
|
||||
/* Search good / bad pattern on the last page of the eraseblock */
|
||||
#define NAND_BBT_SCANLASTPAGE 0x00010000
|
||||
/*
|
||||
* 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_release(). 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
|
||||
|
||||
/*
|
||||
* Constants for oob configuration
|
||||
*/
|
||||
#define NAND_SMALL_BADBLOCK_POS 5
|
||||
#define NAND_LARGE_BADBLOCK_POS 0
|
||||
#define ONENAND_BADBLOCK_POS 0
|
||||
|
||||
/*
|
||||
* 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
|
||||
* @badblockpos: [INTERN] position of the bad block marker in the oob area
|
||||
* @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 badblockpos;
|
||||
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_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
|
||||
extern int onenand_default_bbt(struct mtd_info *mtd);
|
||||
|
||||
#endif /* __LINUX_MTD_BBM_H */
|
||||
@@ -0,0 +1,32 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org> et al.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MTD_CFI_H__
|
||||
#define __MTD_CFI_H__
|
||||
|
||||
#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
|
||||
|
||||
#endif /* __MTD_CFI_H__ */
|
||||
@@ -0,0 +1,23 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* MTD device concatenation layer definitions
|
||||
*
|
||||
* Copyright © 2002 Robert Kaiser <rkaiser@sysgo.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MTD_CONCAT_H
|
||||
#define MTD_CONCAT_H
|
||||
|
||||
struct mtd_info *mtd_concat_create(
|
||||
struct mtd_info *subdev[], /* subdevices to concatenate */
|
||||
int num_devs, /* number of subdevices */
|
||||
#ifndef __UBOOT__
|
||||
const char *name); /* name for the new device */
|
||||
#else
|
||||
char *name); /* name for the new device */
|
||||
#endif
|
||||
|
||||
void mtd_concat_destroy(struct mtd_info *mtd);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,207 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* 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>
|
||||
#if 0
|
||||
#include <linux/mutex.h>
|
||||
#endif
|
||||
|
||||
#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__)
|
||||
#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2))))
|
||||
#define WriteDOC_(d, adr, reg) do{ *(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0)
|
||||
#define DOC_IOREMAP_LEN 0x8000
|
||||
#elif defined(__ppc__)
|
||||
#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u16 *)(((unsigned long)adr)+((reg)<<1))))
|
||||
#define WriteDOC_(d, adr, reg) do{ *(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0)
|
||||
#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;
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 0
|
||||
struct mutex lock;
|
||||
#endif
|
||||
};
|
||||
|
||||
int doc_decode_ecc(unsigned char sector[512], unsigned char ecc1[6]);
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#if 1
|
||||
/*
|
||||
* NAND Flash Manufacturer ID Codes
|
||||
*/
|
||||
#define NAND_MFR_TOSHIBA 0x98
|
||||
#define NAND_MFR_SAMSUNG 0xec
|
||||
#endif
|
||||
|
||||
#endif /* __MTD_DOC2000_H__ */
|
||||
@@ -0,0 +1,103 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright © 2000 Red Hat UK Limited
|
||||
* Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MTD_FLASHCHIP_H__
|
||||
#define __MTD_FLASHCHIP_H__
|
||||
|
||||
#ifndef __UBOOT__
|
||||
/* 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>
|
||||
#endif
|
||||
|
||||
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_RESETING,
|
||||
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;
|
||||
|
||||
struct mutex mutex;
|
||||
#ifndef __UBOOT__
|
||||
wait_queue_head_t wq; /* Wait on here when we're waiting for the chip
|
||||
to be ready */
|
||||
#endif
|
||||
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,44 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* FSL UPM NAND driver
|
||||
*
|
||||
* Copyright (C) 2007 MontaVista Software, Inc.
|
||||
* Anton Vorontsov <avorontsov@ru.mvista.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MTD_NAND_FSL_UPM
|
||||
#define __LINUX_MTD_NAND_FSL_UPM
|
||||
|
||||
#include <linux/mtd/rawnand.h>
|
||||
|
||||
#define FSL_UPM_WAIT_RUN_PATTERN 0x1
|
||||
#define FSL_UPM_WAIT_WRITE_BYTE 0x2
|
||||
#define FSL_UPM_WAIT_WRITE_BUFFER 0x4
|
||||
|
||||
struct fsl_upm {
|
||||
void __iomem *mdr;
|
||||
void __iomem *mxmr;
|
||||
void __iomem *mar;
|
||||
void __iomem *io_addr;
|
||||
};
|
||||
|
||||
struct fsl_upm_nand {
|
||||
struct fsl_upm upm;
|
||||
|
||||
int width;
|
||||
int upm_cmd_offset;
|
||||
int upm_addr_offset;
|
||||
int upm_mar_chip_offset;
|
||||
int wait_flags;
|
||||
int (*dev_ready)(int chip_nr);
|
||||
int chip_delay;
|
||||
int chip_offset;
|
||||
int chip_nr;
|
||||
|
||||
/* no need to fill */
|
||||
int last_ctrl;
|
||||
};
|
||||
|
||||
extern int fsl_upm_nand_init(struct nand_chip *chip, struct fsl_upm_nand *fun);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,84 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2010
|
||||
* Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
|
||||
*/
|
||||
|
||||
#ifndef __FSMC_NAND_H__
|
||||
#define __FSMC_NAND_H__
|
||||
|
||||
#include <linux/mtd/rawnand.h>
|
||||
|
||||
struct fsmc_regs {
|
||||
u32 ctrl; /* 0x00 */
|
||||
u8 reserved_1[0x40 - 0x04];
|
||||
u32 pc; /* 0x40 */
|
||||
u32 sts; /* 0x44 */
|
||||
u32 comm; /* 0x48 */
|
||||
u32 attrib; /* 0x4c */
|
||||
u32 ioata; /* 0x50 */
|
||||
u32 ecc1; /* 0x54 */
|
||||
u32 ecc2; /* 0x58 */
|
||||
u32 ecc3; /* 0x5c */
|
||||
u8 reserved_2[0xfe0 - 0x60];
|
||||
u32 peripid0; /* 0xfe0 */
|
||||
u32 peripid1; /* 0xfe4 */
|
||||
u32 peripid2; /* 0xfe8 */
|
||||
u32 peripid3; /* 0xfec */
|
||||
u32 pcellid0; /* 0xff0 */
|
||||
u32 pcellid1; /* 0xff4 */
|
||||
u32 pcellid2; /* 0xff8 */
|
||||
u32 pcellid3; /* 0xffc */
|
||||
};
|
||||
|
||||
/* ctrl register definitions */
|
||||
#define FSMC_WP (1 << 7)
|
||||
|
||||
/* pc register definitions */
|
||||
#define FSMC_RESET (1 << 0)
|
||||
#define FSMC_WAITON (1 << 1)
|
||||
#define FSMC_ENABLE (1 << 2)
|
||||
#define FSMC_DEVTYPE_NAND (1 << 3)
|
||||
#define FSMC_DEVWID_8 (0 << 4)
|
||||
#define FSMC_DEVWID_16 (1 << 4)
|
||||
#define FSMC_ECCEN (1 << 6)
|
||||
#define FSMC_ECCPLEN_512 (0 << 7)
|
||||
#define FSMC_ECCPLEN_256 (1 << 7)
|
||||
#define FSMC_TCLR_1 (1 << 9)
|
||||
#define FSMC_TAR_1 (1 << 13)
|
||||
|
||||
/* sts register definitions */
|
||||
#define FSMC_CODE_RDY (1 << 15)
|
||||
|
||||
/* comm register definitions */
|
||||
#define FSMC_TSET_0 (0 << 0)
|
||||
#define FSMC_TWAIT_6 (6 << 8)
|
||||
#define FSMC_THOLD_4 (4 << 16)
|
||||
#define FSMC_THIZ_1 (1 << 24)
|
||||
|
||||
/* peripid2 register definitions */
|
||||
#define FSMC_REVISION_MSK (0xf)
|
||||
#define FSMC_REVISION_SHFT (0x4)
|
||||
|
||||
#define FSMC_VER8 0x8
|
||||
|
||||
/*
|
||||
* There are 13 bytes of ecc for every 512 byte block and it has to be read
|
||||
* consecutively and immediately after the 512 byte data block for hardware to
|
||||
* generate the error bit offsets
|
||||
* Managing the ecc bytes in the following way is easier. This way is similar to
|
||||
* oobfree structure maintained already in u-boot nand driver
|
||||
*/
|
||||
#define FSMC_MAX_ECCPLACE_ENTRIES 32
|
||||
|
||||
struct fsmc_nand_eccplace {
|
||||
u32 offset;
|
||||
u32 length;
|
||||
};
|
||||
|
||||
struct fsmc_eccplace {
|
||||
struct fsmc_nand_eccplace eccplace[FSMC_MAX_ECCPLACE_ENTRIES];
|
||||
};
|
||||
|
||||
extern int fsmc_nand_init(struct nand_chip *nand);
|
||||
#endif
|
||||
+625
@@ -0,0 +1,625 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org> et al.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MTD_MTD_H__
|
||||
#define __MTD_MTD_H__
|
||||
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/types.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <mtd/mtd-abi.h>
|
||||
|
||||
#include <asm/div64.h>
|
||||
#else
|
||||
#include <linux/compat.h>
|
||||
#include <mtd/mtd-abi.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/list.h>
|
||||
#include <div64.h>
|
||||
#if IS_ENABLED(CONFIG_DM)
|
||||
#include <dm/device.h>
|
||||
#endif
|
||||
|
||||
#define MAX_MTD_DEVICES 32
|
||||
#endif
|
||||
|
||||
#define MTD_ERASE_PENDING 0x01
|
||||
#define MTD_ERASING 0x02
|
||||
#define MTD_ERASE_SUSPEND 0x04
|
||||
#define MTD_ERASE_DONE 0x08
|
||||
#define MTD_ERASE_FAILED 0x10
|
||||
|
||||
#define MTD_FAIL_ADDR_UNKNOWN -1LL
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
struct mtd_info *mtd;
|
||||
uint64_t addr;
|
||||
uint64_t len;
|
||||
uint64_t fail_addr;
|
||||
u_long time;
|
||||
u_long retries;
|
||||
unsigned dev;
|
||||
unsigned cell;
|
||||
void (*callback) (struct erase_info *self);
|
||||
u_long priv;
|
||||
u_char state;
|
||||
struct erase_info *next;
|
||||
int scrub;
|
||||
};
|
||||
|
||||
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_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
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SYS_NAND_MAX_OOBFREE
|
||||
#define MTD_MAX_OOBFREE_ENTRIES_LARGE CONFIG_SYS_NAND_MAX_OOBFREE
|
||||
#else
|
||||
#define MTD_MAX_OOBFREE_ENTRIES_LARGE 32
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_NAND_MAX_ECCPOS
|
||||
#define MTD_MAX_ECCPOS_ENTRIES_LARGE CONFIG_SYS_NAND_MAX_ECCPOS
|
||||
#else
|
||||
#define MTD_MAX_ECCPOS_ENTRIES_LARGE 680
|
||||
#endif
|
||||
/**
|
||||
* 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);
|
||||
};
|
||||
|
||||
/*
|
||||
* Internal ECC layout control structure. For historical reasons, there is a
|
||||
* similar, smaller struct nand_ecclayout_user (in mtd-abi.h) that is retained
|
||||
* for export to user-space via the ECCGETLAYOUT ioctl.
|
||||
* nand_ecclayout should be expandable in the future simply by the above macros.
|
||||
*/
|
||||
struct nand_ecclayout {
|
||||
__u32 eccbytes;
|
||||
__u32 eccpos[MTD_MAX_ECCPOS_ENTRIES_LARGE];
|
||||
__u32 oobavail;
|
||||
struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE];
|
||||
};
|
||||
|
||||
struct module; /* only needed for owner field in mtd_info */
|
||||
|
||||
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.
|
||||
#ifndef __UBOOT__
|
||||
const char *name;
|
||||
#else
|
||||
char *name;
|
||||
#endif
|
||||
int index;
|
||||
|
||||
/* OOB layout description */
|
||||
const struct mtd_ooblayout_ops *ooblayout;
|
||||
|
||||
/* ECC layout structure pointer - read only! */
|
||||
struct nand_ecclayout *ecclayout;
|
||||
|
||||
/* 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);
|
||||
#ifndef __UBOOT__
|
||||
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);
|
||||
#endif
|
||||
unsigned long (*_get_unmapped_area) (struct mtd_info *mtd,
|
||||
unsigned long len,
|
||||
unsigned long offset,
|
||||
unsigned long flags);
|
||||
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, u_char *buf);
|
||||
int (*_lock_user_prot_reg) (struct mtd_info *mtd, loff_t from,
|
||||
size_t len);
|
||||
#ifndef __UBOOT__
|
||||
int (*_writev) (struct mtd_info *mtd, const struct kvec *vecs,
|
||||
unsigned long count, loff_t to, size_t *retlen);
|
||||
#endif
|
||||
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);
|
||||
#ifndef __UBOOT__
|
||||
int (*_suspend) (struct mtd_info *mtd);
|
||||
void (*_resume) (struct mtd_info *mtd);
|
||||
void (*_reboot) (struct mtd_info *mtd);
|
||||
#endif
|
||||
/*
|
||||
* 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);
|
||||
|
||||
#ifndef __UBOOT__
|
||||
/* Backing device capabilities for this device
|
||||
* - provides mmap capabilities
|
||||
*/
|
||||
struct backing_dev_info *backing_dev_info;
|
||||
|
||||
struct notifier_block reboot_notifier; /* default mode before reboot */
|
||||
#endif
|
||||
|
||||
/* ECC status information */
|
||||
struct mtd_ecc_stats ecc_stats;
|
||||
/* Subpage shift (NAND) */
|
||||
int subpage_sft;
|
||||
|
||||
void *priv;
|
||||
|
||||
struct module *owner;
|
||||
#ifndef __UBOOT__
|
||||
struct device dev;
|
||||
#else
|
||||
struct udevice *dev;
|
||||
#endif
|
||||
int usecount;
|
||||
|
||||
/* MTD devices do not have any parent. MTD partitions do. */
|
||||
struct mtd_info *parent;
|
||||
|
||||
/*
|
||||
* Offset of the partition relatively to the parent offset.
|
||||
* Is 0 for real MTD devices (ie. not partitions).
|
||||
*/
|
||||
u64 offset;
|
||||
|
||||
/*
|
||||
* List node used to add an MTD partition to the parent
|
||||
* partition list.
|
||||
*/
|
||||
struct list_head node;
|
||||
|
||||
/*
|
||||
* List of partitions attached to this MTD device (the parent
|
||||
* MTD device can itself be a partition).
|
||||
*/
|
||||
struct list_head partitions;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_DM)
|
||||
static inline void mtd_set_of_node(struct mtd_info *mtd,
|
||||
const struct device_node *np)
|
||||
{
|
||||
mtd->dev->node.np = np;
|
||||
}
|
||||
|
||||
static inline const struct device_node *mtd_get_of_node(struct mtd_info *mtd)
|
||||
{
|
||||
return mtd->dev->node.np;
|
||||
}
|
||||
#else
|
||||
struct device_node;
|
||||
|
||||
static inline void mtd_set_of_node(struct mtd_info *mtd,
|
||||
const struct device_node *np)
|
||||
{
|
||||
}
|
||||
|
||||
static inline const struct device_node *mtd_get_of_node(struct mtd_info *mtd)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool mtd_partitions_used(struct mtd_info *master);
|
||||
|
||||
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 u32 mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
|
||||
{
|
||||
return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize;
|
||||
}
|
||||
|
||||
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
|
||||
#ifndef __UBOOT__
|
||||
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);
|
||||
#endif
|
||||
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, u_char *buf);
|
||||
int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len);
|
||||
|
||||
#ifndef __UBOOT__
|
||||
int mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
|
||||
unsigned long count, loff_t to, size_t *retlen);
|
||||
#endif
|
||||
|
||||
static inline void mtd_sync(struct mtd_info *mtd)
|
||||
{
|
||||
if (mtd->_sync)
|
||||
mtd->_sync(mtd);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
* this interface for iTools and application used.
|
||||
*/
|
||||
struct mtd_info_ex
|
||||
{
|
||||
u_char type; /* chip type MTD_NORFLASH / MTD_NANDFLASH */
|
||||
uint64_t chipsize; /* total size of the nand/spi chip */
|
||||
uint32_t erasesize;
|
||||
uint32_t pagesize;
|
||||
uint32_t numchips; /* number of nand chips */
|
||||
|
||||
uint32_t oobsize;
|
||||
uint32_t addrcycle;
|
||||
uint32_t ecctype;
|
||||
|
||||
u_char ids[8];
|
||||
uint32_t id_length;
|
||||
char name[16]; /* chip names */
|
||||
int hostver; /* host controller version */
|
||||
};
|
||||
|
||||
extern struct mtd_info_ex * get_nand_info(void);
|
||||
extern struct mtd_info_ex * get_spiflash_info(void);
|
||||
#ifndef __UBOOT__
|
||||
static inline int mtd_suspend(struct mtd_info *mtd)
|
||||
{
|
||||
return mtd->_suspend ? mtd->_suspend(mtd) : 0;
|
||||
}
|
||||
|
||||
static inline void mtd_resume(struct mtd_info *mtd)
|
||||
{
|
||||
if (mtd->_resume)
|
||||
mtd->_resume(mtd);
|
||||
}
|
||||
#endif
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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_has_oob(const struct mtd_info *mtd)
|
||||
{
|
||||
return mtd->_read_oob && mtd->_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)
|
||||
{
|
||||
return !!mtd->_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 *get_mtd_device_nm(const char *name);
|
||||
extern void put_mtd_device(struct mtd_info *mtd);
|
||||
|
||||
|
||||
#ifndef __UBOOT__
|
||||
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);
|
||||
#endif
|
||||
void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size);
|
||||
|
||||
#ifdef CONFIG_MTD_PARTITIONS
|
||||
void mtd_erase_callback(struct erase_info *instr);
|
||||
#else
|
||||
static inline void mtd_erase_callback(struct erase_info *instr)
|
||||
{
|
||||
if (instr->callback)
|
||||
instr->callback(instr);
|
||||
}
|
||||
#endif
|
||||
|
||||
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 __UBOOT__
|
||||
/* drivers/mtd/mtdcore.h */
|
||||
int add_mtd_device(struct mtd_info *mtd);
|
||||
int del_mtd_device(struct mtd_info *mtd);
|
||||
|
||||
#ifdef CONFIG_MTD_PARTITIONS
|
||||
int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
|
||||
int del_mtd_partitions(struct mtd_info *);
|
||||
#else
|
||||
static inline int add_mtd_partitions(struct mtd_info *mtd,
|
||||
const struct mtd_partition *parts,
|
||||
int nparts)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int del_mtd_partitions(struct mtd_info *mtd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct mtd_info *__mtd_next_device(int i);
|
||||
#define mtd_for_each_device(mtd) \
|
||||
for ((mtd) = __mtd_next_device(0); \
|
||||
(mtd) != NULL; \
|
||||
(mtd) = __mtd_next_device(mtd->index + 1))
|
||||
|
||||
/* drivers/mtd/mtdcore.c */
|
||||
void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
|
||||
const uint64_t length, uint64_t *len_incl_bad,
|
||||
int *truncated);
|
||||
bool mtd_dev_list_updated(void);
|
||||
|
||||
/* drivers/mtd/mtd_uboot.c */
|
||||
int mtd_search_alternate_name(const char *mtdname, char *altname,
|
||||
unsigned int max_len);
|
||||
|
||||
#endif
|
||||
#endif /* __MTD_MTD_H__ */
|
||||
@@ -0,0 +1,734 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright 2017 - Free Electrons
|
||||
*
|
||||
* Authors:
|
||||
* Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
* Peter Pan <peterpandong@micron.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MTD_NAND_H
|
||||
#define __LINUX_MTD_NAND_H
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
|
||||
/**
|
||||
* struct nand_memory_organization - Memory organization structure
|
||||
* @bits_per_cell: number of bits per NAND cell
|
||||
* @pagesize: page size
|
||||
* @oobsize: OOB area size
|
||||
* @pages_per_eraseblock: number of pages per eraseblock
|
||||
* @eraseblocks_per_lun: number of eraseblocks per LUN (Logical Unit Number)
|
||||
* @planes_per_lun: number of planes per LUN
|
||||
* @luns_per_target: number of LUN per target (target is a synonym for die)
|
||||
* @ntargets: total number of targets exposed by the NAND device
|
||||
*/
|
||||
struct nand_memory_organization {
|
||||
unsigned int bits_per_cell;
|
||||
unsigned int pagesize;
|
||||
unsigned int oobsize;
|
||||
unsigned int pages_per_eraseblock;
|
||||
unsigned int eraseblocks_per_lun;
|
||||
unsigned int planes_per_lun;
|
||||
unsigned int luns_per_target;
|
||||
unsigned int ntargets;
|
||||
};
|
||||
|
||||
#define NAND_MEMORG(bpc, ps, os, ppe, epl, ppl, lpt, nt) \
|
||||
{ \
|
||||
.bits_per_cell = (bpc), \
|
||||
.pagesize = (ps), \
|
||||
.oobsize = (os), \
|
||||
.pages_per_eraseblock = (ppe), \
|
||||
.eraseblocks_per_lun = (epl), \
|
||||
.planes_per_lun = (ppl), \
|
||||
.luns_per_target = (lpt), \
|
||||
.ntargets = (nt), \
|
||||
}
|
||||
|
||||
/**
|
||||
* struct nand_row_converter - Information needed to convert an absolute offset
|
||||
* into a row address
|
||||
* @lun_addr_shift: position of the LUN identifier in the row address
|
||||
* @eraseblock_addr_shift: position of the eraseblock identifier in the row
|
||||
* address
|
||||
*/
|
||||
struct nand_row_converter {
|
||||
unsigned int lun_addr_shift;
|
||||
unsigned int eraseblock_addr_shift;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nand_pos - NAND position object
|
||||
* @target: the NAND target/die
|
||||
* @lun: the LUN identifier
|
||||
* @plane: the plane within the LUN
|
||||
* @eraseblock: the eraseblock within the LUN
|
||||
* @page: the page within the LUN
|
||||
*
|
||||
* These information are usually used by specific sub-layers to select the
|
||||
* appropriate target/die and generate a row address to pass to the device.
|
||||
*/
|
||||
struct nand_pos {
|
||||
unsigned int target;
|
||||
unsigned int lun;
|
||||
unsigned int plane;
|
||||
unsigned int eraseblock;
|
||||
unsigned int page;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nand_page_io_req - NAND I/O request object
|
||||
* @pos: the position this I/O request is targeting
|
||||
* @dataoffs: the offset within the page
|
||||
* @datalen: number of data bytes to read from/write to this page
|
||||
* @databuf: buffer to store data in or get data from
|
||||
* @ooboffs: the OOB offset within the page
|
||||
* @ooblen: the number of OOB bytes to read from/write to this page
|
||||
* @oobbuf: buffer to store OOB data in or get OOB data from
|
||||
* @mode: one of the %MTD_OPS_XXX mode
|
||||
*
|
||||
* This object is used to pass per-page I/O requests to NAND sub-layers. This
|
||||
* way all useful information are already formatted in a useful way and
|
||||
* specific NAND layers can focus on translating these information into
|
||||
* specific commands/operations.
|
||||
*/
|
||||
struct nand_page_io_req {
|
||||
struct nand_pos pos;
|
||||
unsigned int dataoffs;
|
||||
unsigned int datalen;
|
||||
union {
|
||||
const void *out;
|
||||
void *in;
|
||||
} databuf;
|
||||
unsigned int ooboffs;
|
||||
unsigned int ooblen;
|
||||
union {
|
||||
const void *out;
|
||||
void *in;
|
||||
} oobbuf;
|
||||
int mode;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nand_ecc_req - NAND ECC requirements
|
||||
* @strength: ECC strength
|
||||
* @step_size: ECC step/block size
|
||||
*/
|
||||
struct nand_ecc_req {
|
||||
unsigned int strength;
|
||||
unsigned int step_size;
|
||||
};
|
||||
|
||||
#define NAND_ECCREQ(str, stp) { .strength = (str), .step_size = (stp) }
|
||||
|
||||
/**
|
||||
* struct nand_bbt - bad block table object
|
||||
* @cache: in memory BBT cache
|
||||
*/
|
||||
struct nand_bbt {
|
||||
unsigned long *cache;
|
||||
};
|
||||
|
||||
struct nand_device;
|
||||
|
||||
/**
|
||||
* struct nand_ops - NAND operations
|
||||
* @erase: erase a specific block. No need to check if the block is bad before
|
||||
* erasing, this has been taken care of by the generic NAND layer
|
||||
* @markbad: mark a specific block bad. No need to check if the block is
|
||||
* already marked bad, this has been taken care of by the generic
|
||||
* NAND layer. This method should just write the BBM (Bad Block
|
||||
* Marker) so that future call to struct_nand_ops->isbad() return
|
||||
* true
|
||||
* @isbad: check whether a block is bad or not. This method should just read
|
||||
* the BBM and return whether the block is bad or not based on what it
|
||||
* reads
|
||||
*
|
||||
* These are all low level operations that should be implemented by specialized
|
||||
* NAND layers (SPI NAND, raw NAND, ...).
|
||||
*/
|
||||
struct nand_ops {
|
||||
int (*erase)(struct nand_device *nand, const struct nand_pos *pos);
|
||||
int (*markbad)(struct nand_device *nand, const struct nand_pos *pos);
|
||||
bool (*isbad)(struct nand_device *nand, const struct nand_pos *pos);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nand_device - NAND device
|
||||
* @mtd: MTD instance attached to the NAND device
|
||||
* @memorg: memory layout
|
||||
* @eccreq: ECC requirements
|
||||
* @rowconv: position to row address converter
|
||||
* @bbt: bad block table info
|
||||
* @ops: NAND operations attached to the NAND device
|
||||
*
|
||||
* Generic NAND object. Specialized NAND layers (raw NAND, SPI NAND, OneNAND)
|
||||
* should declare their own NAND object embedding a nand_device struct (that's
|
||||
* how inheritance is done).
|
||||
* struct_nand_device->memorg and struct_nand_device->eccreq should be filled
|
||||
* at device detection time to reflect the NAND device
|
||||
* capabilities/requirements. Once this is done nanddev_init() can be called.
|
||||
* It will take care of converting NAND information into MTD ones, which means
|
||||
* the specialized NAND layers should never manually tweak
|
||||
* struct_nand_device->mtd except for the ->_read/write() hooks.
|
||||
*/
|
||||
struct nand_device {
|
||||
struct mtd_info *mtd;
|
||||
struct nand_memory_organization memorg;
|
||||
struct nand_ecc_req eccreq;
|
||||
struct nand_row_converter rowconv;
|
||||
struct nand_bbt bbt;
|
||||
const struct nand_ops *ops;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nand_io_iter - NAND I/O iterator
|
||||
* @req: current I/O request
|
||||
* @oobbytes_per_page: maximum number of OOB bytes per page
|
||||
* @dataleft: remaining number of data bytes to read/write
|
||||
* @oobleft: remaining number of OOB bytes to read/write
|
||||
*
|
||||
* Can be used by specialized NAND layers to iterate over all pages covered
|
||||
* by an MTD I/O request, which should greatly simplifies the boiler-plate
|
||||
* code needed to read/write data from/to a NAND device.
|
||||
*/
|
||||
struct nand_io_iter {
|
||||
struct nand_page_io_req req;
|
||||
unsigned int oobbytes_per_page;
|
||||
unsigned int dataleft;
|
||||
unsigned int oobleft;
|
||||
};
|
||||
|
||||
/**
|
||||
* mtd_to_nanddev() - Get the NAND device attached to the MTD instance
|
||||
* @mtd: MTD instance
|
||||
*
|
||||
* Return: the NAND device embedding @mtd.
|
||||
*/
|
||||
static inline struct nand_device *mtd_to_nanddev(struct mtd_info *mtd)
|
||||
{
|
||||
return mtd->priv;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_to_mtd() - Get the MTD device attached to a NAND device
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Return: the MTD device embedded in @nand.
|
||||
*/
|
||||
static inline struct mtd_info *nanddev_to_mtd(struct nand_device *nand)
|
||||
{
|
||||
return nand->mtd;
|
||||
}
|
||||
|
||||
/*
|
||||
* nanddev_bits_per_cell() - Get the number of bits per cell
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Return: the number of bits per cell.
|
||||
*/
|
||||
static inline unsigned int nanddev_bits_per_cell(const struct nand_device *nand)
|
||||
{
|
||||
return nand->memorg.bits_per_cell;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_page_size() - Get NAND page size
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Return: the page size.
|
||||
*/
|
||||
static inline size_t nanddev_page_size(const struct nand_device *nand)
|
||||
{
|
||||
return nand->memorg.pagesize;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_per_page_oobsize() - Get NAND OOB size
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Return: the OOB size.
|
||||
*/
|
||||
static inline unsigned int
|
||||
nanddev_per_page_oobsize(const struct nand_device *nand)
|
||||
{
|
||||
return nand->memorg.oobsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_pages_per_eraseblock() - Get the number of pages per eraseblock
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Return: the number of pages per eraseblock.
|
||||
*/
|
||||
static inline unsigned int
|
||||
nanddev_pages_per_eraseblock(const struct nand_device *nand)
|
||||
{
|
||||
return nand->memorg.pages_per_eraseblock;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_per_page_oobsize() - Get NAND erase block size
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Return: the eraseblock size.
|
||||
*/
|
||||
static inline size_t nanddev_eraseblock_size(const struct nand_device *nand)
|
||||
{
|
||||
return nand->memorg.pagesize * nand->memorg.pages_per_eraseblock;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_eraseblocks_per_lun() - Get the number of eraseblocks per LUN
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Return: the number of eraseblocks per LUN.
|
||||
*/
|
||||
static inline unsigned int
|
||||
nanddev_eraseblocks_per_lun(const struct nand_device *nand)
|
||||
{
|
||||
return nand->memorg.eraseblocks_per_lun;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_target_size() - Get the total size provided by a single target/die
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Return: the total size exposed by a single target/die in bytes.
|
||||
*/
|
||||
static inline u64 nanddev_target_size(const struct nand_device *nand)
|
||||
{
|
||||
return (u64)nand->memorg.luns_per_target *
|
||||
nand->memorg.eraseblocks_per_lun *
|
||||
nand->memorg.pages_per_eraseblock *
|
||||
nand->memorg.pagesize;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_ntarget() - Get the total of targets
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Return: the number of targets/dies exposed by @nand.
|
||||
*/
|
||||
static inline unsigned int nanddev_ntargets(const struct nand_device *nand)
|
||||
{
|
||||
return nand->memorg.ntargets;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_neraseblocks() - Get the total number of erasablocks
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Return: the total number of eraseblocks exposed by @nand.
|
||||
*/
|
||||
static inline unsigned int nanddev_neraseblocks(const struct nand_device *nand)
|
||||
{
|
||||
return (u64)nand->memorg.luns_per_target *
|
||||
nand->memorg.eraseblocks_per_lun *
|
||||
nand->memorg.pages_per_eraseblock;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_size() - Get NAND size
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Return: the total size (in bytes) exposed by @nand.
|
||||
*/
|
||||
static inline u64 nanddev_size(const struct nand_device *nand)
|
||||
{
|
||||
return nanddev_target_size(nand) * nanddev_ntargets(nand);
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_get_memorg() - Extract memory organization info from a NAND device
|
||||
* @nand: NAND device
|
||||
*
|
||||
* This can be used by the upper layer to fill the memorg info before calling
|
||||
* nanddev_init().
|
||||
*
|
||||
* Return: the memorg object embedded in the NAND device.
|
||||
*/
|
||||
static inline struct nand_memory_organization *
|
||||
nanddev_get_memorg(struct nand_device *nand)
|
||||
{
|
||||
return &nand->memorg;
|
||||
}
|
||||
|
||||
int nanddev_init(struct nand_device *nand, const struct nand_ops *ops,
|
||||
struct module *owner);
|
||||
void nanddev_cleanup(struct nand_device *nand);
|
||||
|
||||
/**
|
||||
* nanddev_register() - Register a NAND device
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Register a NAND device.
|
||||
* This function is just a wrapper around mtd_device_register()
|
||||
* registering the MTD device embedded in @nand.
|
||||
*
|
||||
* Return: 0 in case of success, a negative error code otherwise.
|
||||
*/
|
||||
static inline int nanddev_register(struct nand_device *nand)
|
||||
{
|
||||
return mtd_device_register(nand->mtd, NULL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_unregister() - Unregister a NAND device
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Unregister a NAND device.
|
||||
* This function is just a wrapper around mtd_device_unregister()
|
||||
* unregistering the MTD device embedded in @nand.
|
||||
*
|
||||
* Return: 0 in case of success, a negative error code otherwise.
|
||||
*/
|
||||
static inline int nanddev_unregister(struct nand_device *nand)
|
||||
{
|
||||
return mtd_device_unregister(nand->mtd);
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_set_of_node() - Attach a DT node to a NAND device
|
||||
* @nand: NAND device
|
||||
* @np: DT node
|
||||
*
|
||||
* Attach a DT node to a NAND device.
|
||||
*/
|
||||
static inline void nanddev_set_of_node(struct nand_device *nand,
|
||||
const struct device_node *np)
|
||||
{
|
||||
mtd_set_of_node(nand->mtd, np);
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_get_of_node() - Retrieve the DT node attached to a NAND device
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Return: the DT node attached to @nand.
|
||||
*/
|
||||
static inline const struct device_node *nanddev_get_of_node(struct nand_device *nand)
|
||||
{
|
||||
return mtd_get_of_node(nand->mtd);
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_offs_to_pos() - Convert an absolute NAND offset into a NAND position
|
||||
* @nand: NAND device
|
||||
* @offs: absolute NAND offset (usually passed by the MTD layer)
|
||||
* @pos: a NAND position object to fill in
|
||||
*
|
||||
* Converts @offs into a nand_pos representation.
|
||||
*
|
||||
* Return: the offset within the NAND page pointed by @pos.
|
||||
*/
|
||||
static inline unsigned int nanddev_offs_to_pos(struct nand_device *nand,
|
||||
loff_t offs,
|
||||
struct nand_pos *pos)
|
||||
{
|
||||
unsigned int pageoffs;
|
||||
u64 tmp = offs;
|
||||
|
||||
pageoffs = do_div(tmp, nand->memorg.pagesize);
|
||||
pos->page = do_div(tmp, nand->memorg.pages_per_eraseblock);
|
||||
pos->eraseblock = do_div(tmp, nand->memorg.eraseblocks_per_lun);
|
||||
pos->plane = pos->eraseblock % nand->memorg.planes_per_lun;
|
||||
pos->lun = do_div(tmp, nand->memorg.luns_per_target);
|
||||
pos->target = tmp;
|
||||
|
||||
return pageoffs;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_pos_cmp() - Compare two NAND positions
|
||||
* @a: First NAND position
|
||||
* @b: Second NAND position
|
||||
*
|
||||
* Compares two NAND positions.
|
||||
*
|
||||
* Return: -1 if @a < @b, 0 if @a == @b and 1 if @a > @b.
|
||||
*/
|
||||
static inline int nanddev_pos_cmp(const struct nand_pos *a,
|
||||
const struct nand_pos *b)
|
||||
{
|
||||
if (a->target != b->target)
|
||||
return a->target < b->target ? -1 : 1;
|
||||
|
||||
if (a->lun != b->lun)
|
||||
return a->lun < b->lun ? -1 : 1;
|
||||
|
||||
if (a->eraseblock != b->eraseblock)
|
||||
return a->eraseblock < b->eraseblock ? -1 : 1;
|
||||
|
||||
if (a->page != b->page)
|
||||
return a->page < b->page ? -1 : 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_pos_to_offs() - Convert a NAND position into an absolute offset
|
||||
* @nand: NAND device
|
||||
* @pos: the NAND position to convert
|
||||
*
|
||||
* Converts @pos NAND position into an absolute offset.
|
||||
*
|
||||
* Return: the absolute offset. Note that @pos points to the beginning of a
|
||||
* page, if one wants to point to a specific offset within this page
|
||||
* the returned offset has to be adjusted manually.
|
||||
*/
|
||||
static inline loff_t nanddev_pos_to_offs(struct nand_device *nand,
|
||||
const struct nand_pos *pos)
|
||||
{
|
||||
unsigned int npages;
|
||||
|
||||
npages = pos->page +
|
||||
((pos->eraseblock +
|
||||
(pos->lun +
|
||||
(pos->target * nand->memorg.luns_per_target)) *
|
||||
nand->memorg.eraseblocks_per_lun) *
|
||||
nand->memorg.pages_per_eraseblock);
|
||||
|
||||
return (loff_t)npages * nand->memorg.pagesize;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_pos_to_row() - Extract a row address from a NAND position
|
||||
* @nand: NAND device
|
||||
* @pos: the position to convert
|
||||
*
|
||||
* Converts a NAND position into a row address that can then be passed to the
|
||||
* device.
|
||||
*
|
||||
* Return: the row address extracted from @pos.
|
||||
*/
|
||||
static inline unsigned int nanddev_pos_to_row(struct nand_device *nand,
|
||||
const struct nand_pos *pos)
|
||||
{
|
||||
return (pos->lun << nand->rowconv.lun_addr_shift) |
|
||||
(pos->eraseblock << nand->rowconv.eraseblock_addr_shift) |
|
||||
pos->page;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_pos_next_target() - Move a position to the next target/die
|
||||
* @nand: NAND device
|
||||
* @pos: the position to update
|
||||
*
|
||||
* Updates @pos to point to the start of the next target/die. Useful when you
|
||||
* want to iterate over all targets/dies of a NAND device.
|
||||
*/
|
||||
static inline void nanddev_pos_next_target(struct nand_device *nand,
|
||||
struct nand_pos *pos)
|
||||
{
|
||||
pos->page = 0;
|
||||
pos->plane = 0;
|
||||
pos->eraseblock = 0;
|
||||
pos->lun = 0;
|
||||
pos->target++;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_pos_next_lun() - Move a position to the next LUN
|
||||
* @nand: NAND device
|
||||
* @pos: the position to update
|
||||
*
|
||||
* Updates @pos to point to the start of the next LUN. Useful when you want to
|
||||
* iterate over all LUNs of a NAND device.
|
||||
*/
|
||||
static inline void nanddev_pos_next_lun(struct nand_device *nand,
|
||||
struct nand_pos *pos)
|
||||
{
|
||||
if (pos->lun >= nand->memorg.luns_per_target - 1)
|
||||
return nanddev_pos_next_target(nand, pos);
|
||||
|
||||
pos->lun++;
|
||||
pos->page = 0;
|
||||
pos->plane = 0;
|
||||
pos->eraseblock = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_pos_next_eraseblock() - Move a position to the next eraseblock
|
||||
* @nand: NAND device
|
||||
* @pos: the position to update
|
||||
*
|
||||
* Updates @pos to point to the start of the next eraseblock. Useful when you
|
||||
* want to iterate over all eraseblocks of a NAND device.
|
||||
*/
|
||||
static inline void nanddev_pos_next_eraseblock(struct nand_device *nand,
|
||||
struct nand_pos *pos)
|
||||
{
|
||||
if (pos->eraseblock >= nand->memorg.eraseblocks_per_lun - 1)
|
||||
return nanddev_pos_next_lun(nand, pos);
|
||||
|
||||
pos->eraseblock++;
|
||||
pos->page = 0;
|
||||
pos->plane = pos->eraseblock % nand->memorg.planes_per_lun;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_pos_next_eraseblock() - Move a position to the next page
|
||||
* @nand: NAND device
|
||||
* @pos: the position to update
|
||||
*
|
||||
* Updates @pos to point to the start of the next page. Useful when you want to
|
||||
* iterate over all pages of a NAND device.
|
||||
*/
|
||||
static inline void nanddev_pos_next_page(struct nand_device *nand,
|
||||
struct nand_pos *pos)
|
||||
{
|
||||
if (pos->page >= nand->memorg.pages_per_eraseblock - 1)
|
||||
return nanddev_pos_next_eraseblock(nand, pos);
|
||||
|
||||
pos->page++;
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_io_iter_init - Initialize a NAND I/O iterator
|
||||
* @nand: NAND device
|
||||
* @offs: absolute offset
|
||||
* @req: MTD request
|
||||
* @iter: NAND I/O iterator
|
||||
*
|
||||
* Initializes a NAND iterator based on the information passed by the MTD
|
||||
* layer.
|
||||
*/
|
||||
static inline void nanddev_io_iter_init(struct nand_device *nand,
|
||||
loff_t offs, struct mtd_oob_ops *req,
|
||||
struct nand_io_iter *iter)
|
||||
{
|
||||
struct mtd_info *mtd = nanddev_to_mtd(nand);
|
||||
|
||||
iter->req.mode = req->mode;
|
||||
iter->req.dataoffs = nanddev_offs_to_pos(nand, offs, &iter->req.pos);
|
||||
iter->req.ooboffs = req->ooboffs;
|
||||
iter->oobbytes_per_page = mtd_oobavail(mtd, req);
|
||||
iter->dataleft = req->len;
|
||||
iter->oobleft = req->ooblen;
|
||||
iter->req.databuf.in = req->datbuf;
|
||||
iter->req.datalen = min_t(unsigned int,
|
||||
nand->memorg.pagesize - iter->req.dataoffs,
|
||||
iter->dataleft);
|
||||
iter->req.oobbuf.in = req->oobbuf;
|
||||
iter->req.ooblen = min_t(unsigned int,
|
||||
iter->oobbytes_per_page - iter->req.ooboffs,
|
||||
iter->oobleft);
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_io_iter_next_page - Move to the next page
|
||||
* @nand: NAND device
|
||||
* @iter: NAND I/O iterator
|
||||
*
|
||||
* Updates the @iter to point to the next page.
|
||||
*/
|
||||
static inline void nanddev_io_iter_next_page(struct nand_device *nand,
|
||||
struct nand_io_iter *iter)
|
||||
{
|
||||
nanddev_pos_next_page(nand, &iter->req.pos);
|
||||
iter->dataleft -= iter->req.datalen;
|
||||
iter->req.databuf.in += iter->req.datalen;
|
||||
iter->oobleft -= iter->req.ooblen;
|
||||
iter->req.oobbuf.in += iter->req.ooblen;
|
||||
iter->req.dataoffs = 0;
|
||||
iter->req.ooboffs = 0;
|
||||
iter->req.datalen = min_t(unsigned int, nand->memorg.pagesize,
|
||||
iter->dataleft);
|
||||
iter->req.ooblen = min_t(unsigned int, iter->oobbytes_per_page,
|
||||
iter->oobleft);
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_io_iter_end - Should end iteration or not
|
||||
* @nand: NAND device
|
||||
* @iter: NAND I/O iterator
|
||||
*
|
||||
* Check whether @iter has reached the end of the NAND portion it was asked to
|
||||
* iterate on or not.
|
||||
*
|
||||
* Return: true if @iter has reached the end of the iteration request, false
|
||||
* otherwise.
|
||||
*/
|
||||
static inline bool nanddev_io_iter_end(struct nand_device *nand,
|
||||
const struct nand_io_iter *iter)
|
||||
{
|
||||
if (iter->dataleft || iter->oobleft)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_io_for_each_page - Iterate over all NAND pages contained in an MTD I/O
|
||||
* request
|
||||
* @nand: NAND device
|
||||
* @start: start address to read/write from
|
||||
* @req: MTD I/O request
|
||||
* @iter: NAND I/O iterator
|
||||
*
|
||||
* Should be used for iterate over pages that are contained in an MTD request.
|
||||
*/
|
||||
#define nanddev_io_for_each_page(nand, start, req, iter) \
|
||||
for (nanddev_io_iter_init(nand, start, req, iter); \
|
||||
!nanddev_io_iter_end(nand, iter); \
|
||||
nanddev_io_iter_next_page(nand, iter))
|
||||
|
||||
bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos);
|
||||
bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos);
|
||||
int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos);
|
||||
int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos);
|
||||
|
||||
/* BBT related functions */
|
||||
enum nand_bbt_block_status {
|
||||
NAND_BBT_BLOCK_STATUS_UNKNOWN,
|
||||
NAND_BBT_BLOCK_GOOD,
|
||||
NAND_BBT_BLOCK_WORN,
|
||||
NAND_BBT_BLOCK_RESERVED,
|
||||
NAND_BBT_BLOCK_FACTORY_BAD,
|
||||
NAND_BBT_BLOCK_NUM_STATUS,
|
||||
};
|
||||
|
||||
int nanddev_bbt_init(struct nand_device *nand);
|
||||
void nanddev_bbt_cleanup(struct nand_device *nand);
|
||||
int nanddev_bbt_update(struct nand_device *nand);
|
||||
int nanddev_bbt_get_block_status(const struct nand_device *nand,
|
||||
unsigned int entry);
|
||||
int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry,
|
||||
enum nand_bbt_block_status status);
|
||||
int nanddev_bbt_markbad(struct nand_device *nand, unsigned int block);
|
||||
|
||||
/**
|
||||
* nanddev_bbt_pos_to_entry() - Convert a NAND position into a BBT entry
|
||||
* @nand: NAND device
|
||||
* @pos: the NAND position we want to get BBT entry for
|
||||
*
|
||||
* Return the BBT entry used to store information about the eraseblock pointed
|
||||
* by @pos.
|
||||
*
|
||||
* Return: the BBT entry storing information about eraseblock pointed by @pos.
|
||||
*/
|
||||
static inline unsigned int nanddev_bbt_pos_to_entry(struct nand_device *nand,
|
||||
const struct nand_pos *pos)
|
||||
{
|
||||
return pos->eraseblock +
|
||||
((pos->lun + (pos->target * nand->memorg.luns_per_target)) *
|
||||
nand->memorg.eraseblocks_per_lun);
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_bbt_is_initialized() - Check if the BBT has been initialized
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Return: true if the BBT has been initialized, false otherwise.
|
||||
*/
|
||||
static inline bool nanddev_bbt_is_initialized(struct nand_device *nand)
|
||||
{
|
||||
return !!nand->bbt.cache;
|
||||
}
|
||||
|
||||
/* MTD -> NAND helper functions. */
|
||||
int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo);
|
||||
|
||||
#endif /* __LINUX_MTD_NAND_H */
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This file is the header for the NAND BCH ECC implementation.
|
||||
*/
|
||||
|
||||
#ifndef __MTD_NAND_BCH_H__
|
||||
#define __MTD_NAND_BCH_H__
|
||||
|
||||
struct mtd_info;
|
||||
struct nand_bch_control;
|
||||
|
||||
#if defined(CONFIG_NAND_ECC_BCH)
|
||||
|
||||
static inline int mtd_nand_has_bch(void) { return 1; }
|
||||
|
||||
/*
|
||||
* Calculate BCH ecc code
|
||||
*/
|
||||
int nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
|
||||
u_char *ecc_code);
|
||||
|
||||
/*
|
||||
* Detect and correct bit errors
|
||||
*/
|
||||
int nand_bch_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc,
|
||||
u_char *calc_ecc);
|
||||
/*
|
||||
* Initialize BCH encoder/decoder
|
||||
*/
|
||||
struct nand_bch_control *nand_bch_init(struct mtd_info *mtd);
|
||||
/*
|
||||
* Release BCH encoder/decoder resources
|
||||
*/
|
||||
void nand_bch_free(struct nand_bch_control *nbc);
|
||||
|
||||
#else /* !CONFIG_NAND_ECC_BCH */
|
||||
|
||||
static inline int mtd_nand_has_bch(void) { return 0; }
|
||||
|
||||
static inline int
|
||||
nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
|
||||
u_char *ecc_code)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
|
||||
unsigned char *read_ecc, unsigned char *calc_ecc)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void nand_bch_free(struct nand_bch_control *nbc) {}
|
||||
|
||||
#endif /* CONFIG_NAND_ECC_BCH */
|
||||
|
||||
#endif /* __MTD_NAND_BCH_H__ */
|
||||
@@ -0,0 +1,27 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* drivers/mtd/nand_ecc.h
|
||||
*
|
||||
* Copyright (C) 2000-2010 Steven J. Hill <sjhill@realitydiluted.com>
|
||||
* David Woodhouse <dwmw2@infradead.org>
|
||||
* Thomas Gleixner <tglx@linutronix.de>
|
||||
*
|
||||
* This file is the header for the ECC algorithm.
|
||||
*/
|
||||
|
||||
#ifndef __MTD_NAND_ECC_H__
|
||||
#define __MTD_NAND_ECC_H__
|
||||
|
||||
struct mtd_info;
|
||||
|
||||
/*
|
||||
* Calculate 3 byte ECC code for 256 byte block
|
||||
*/
|
||||
int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
|
||||
|
||||
/*
|
||||
* Detect and correct a 1 bit error for 256 byte block
|
||||
*/
|
||||
int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
|
||||
|
||||
#endif /* __MTD_NAND_ECC_H__ */
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* linux/include/linux/mtd/ndfc.h
|
||||
*
|
||||
* Copyright (c) 2006 Thomas Gleixner <tglx@linutronix.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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,79 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2010-2011 Texas Instruments, <www.ti.com>
|
||||
* Mansoor Ahamed <mansoor.ahamed@ti.com>
|
||||
*
|
||||
* Derived from work done by Rohit Choraria <rohitkc@ti.com> for omap3
|
||||
*/
|
||||
#ifndef __ASM_ARCH_ELM_H
|
||||
#define __ASM_ARCH_ELM_H
|
||||
/*
|
||||
* ELM Module Registers
|
||||
*/
|
||||
|
||||
/* ELM registers bit fields */
|
||||
#define ELM_SYSCONFIG_SOFTRESET_MASK (0x2)
|
||||
#define ELM_SYSCONFIG_SOFTRESET (0x2)
|
||||
#define ELM_SYSSTATUS_RESETDONE_MASK (0x1)
|
||||
#define ELM_SYSSTATUS_RESETDONE (0x1)
|
||||
#define ELM_LOCATION_CONFIG_ECC_BCH_LEVEL_MASK (0x3)
|
||||
#define ELM_LOCATION_CONFIG_ECC_SIZE_MASK (0x7FF0000)
|
||||
#define ELM_LOCATION_CONFIG_ECC_SIZE_POS (16)
|
||||
#define ELM_SYNDROME_FRAGMENT_6_SYNDROME_VALID (0x00010000)
|
||||
#define ELM_LOCATION_STATUS_ECC_CORRECTABLE_MASK (0x100)
|
||||
#define ELM_LOCATION_STATUS_ECC_NB_ERRORS_MASK (0x1F)
|
||||
|
||||
#define ELM_MAX_CHANNELS 8
|
||||
#define ELM_MAX_ERROR_COUNT 16
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
enum bch_level {
|
||||
BCH_4_BIT = 0,
|
||||
BCH_8_BIT,
|
||||
BCH_16_BIT
|
||||
};
|
||||
|
||||
|
||||
/* BCH syndrome registers */
|
||||
struct syndrome {
|
||||
u32 syndrome_fragment_x[7]; /* 0x400, 0x404.... 0x418 */
|
||||
u8 res1[36]; /* 0x41c */
|
||||
};
|
||||
|
||||
/* BCH error status & location register */
|
||||
struct location {
|
||||
u32 location_status; /* 0x800 */
|
||||
u8 res1[124]; /* 0x804 */
|
||||
u32 error_location_x[ELM_MAX_ERROR_COUNT]; /* 0x880, 0x980, .. */
|
||||
u8 res2[64]; /* 0x8c0 */
|
||||
};
|
||||
|
||||
/* BCH ELM register map - do not try to allocate memmory for this structure.
|
||||
* We have used plenty of reserved variables to fill the slots in the ELM
|
||||
* register memory map.
|
||||
* Directly initialize the struct pointer to ELM base address.
|
||||
*/
|
||||
struct elm {
|
||||
u32 rev; /* 0x000 */
|
||||
u8 res1[12]; /* 0x004 */
|
||||
u32 sysconfig; /* 0x010 */
|
||||
u32 sysstatus; /* 0x014 */
|
||||
u32 irqstatus; /* 0x018 */
|
||||
u32 irqenable; /* 0x01c */
|
||||
u32 location_config; /* 0x020 */
|
||||
u8 res2[92]; /* 0x024 */
|
||||
u32 page_ctrl; /* 0x080 */
|
||||
u8 res3[892]; /* 0x084 */
|
||||
struct syndrome syndrome_fragments[ELM_MAX_CHANNELS]; /* 0x400,0x420 */
|
||||
u8 res4[512]; /* 0x600 */
|
||||
struct location error_location[ELM_MAX_CHANNELS]; /* 0x800,0x900 ... */
|
||||
};
|
||||
|
||||
int elm_check_error(u8 *syndrome, enum bch_level bch_type, u32 *error_count,
|
||||
u32 *error_locations);
|
||||
int elm_config(enum bch_level level);
|
||||
void elm_reset(void);
|
||||
void elm_init(void);
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __ASM_ARCH_ELM_H */
|
||||
@@ -0,0 +1,97 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2004-2008 Texas Instruments, <www.ti.com>
|
||||
* Rohit Choraria <rohitkc@ti.com>
|
||||
*
|
||||
* (C) Copyright 2013 Andreas Bießmann <andreas@biessmann.org>
|
||||
*/
|
||||
#ifndef __ASM_OMAP_GPMC_H
|
||||
#define __ASM_OMAP_GPMC_H
|
||||
|
||||
#define GPMC_BUF_EMPTY 0
|
||||
#define GPMC_BUF_FULL 1
|
||||
#define GPMC_MAX_SECTORS 8
|
||||
|
||||
enum omap_ecc {
|
||||
/* 1-bit ECC calculation by Software, Error detection by Software */
|
||||
OMAP_ECC_HAM1_CODE_SW = 1, /* avoid un-initialized int can be 0x0 */
|
||||
/* 1-bit ECC calculation by GPMC, Error detection by Software */
|
||||
/* ECC layout compatible to legacy ROMCODE. */
|
||||
OMAP_ECC_HAM1_CODE_HW,
|
||||
/* 4-bit ECC calculation by GPMC, Error detection by Software */
|
||||
OMAP_ECC_BCH4_CODE_HW_DETECTION_SW,
|
||||
/* 4-bit ECC calculation by GPMC, Error detection by ELM */
|
||||
OMAP_ECC_BCH4_CODE_HW,
|
||||
/* 8-bit ECC calculation by GPMC, Error detection by Software */
|
||||
OMAP_ECC_BCH8_CODE_HW_DETECTION_SW,
|
||||
/* 8-bit ECC calculation by GPMC, Error detection by ELM */
|
||||
OMAP_ECC_BCH8_CODE_HW,
|
||||
/* 16-bit ECC calculation by GPMC, Error detection by ELM */
|
||||
OMAP_ECC_BCH16_CODE_HW,
|
||||
};
|
||||
|
||||
struct gpmc_cs {
|
||||
u32 config1; /* 0x00 */
|
||||
u32 config2; /* 0x04 */
|
||||
u32 config3; /* 0x08 */
|
||||
u32 config4; /* 0x0C */
|
||||
u32 config5; /* 0x10 */
|
||||
u32 config6; /* 0x14 */
|
||||
u32 config7; /* 0x18 */
|
||||
u32 nand_cmd; /* 0x1C */
|
||||
u32 nand_adr; /* 0x20 */
|
||||
u32 nand_dat; /* 0x24 */
|
||||
u8 res[8]; /* blow up to 0x30 byte */
|
||||
};
|
||||
|
||||
struct bch_res_0_3 {
|
||||
u32 bch_result_x[4];
|
||||
};
|
||||
|
||||
struct bch_res_4_6 {
|
||||
u32 bch_result_x[3];
|
||||
};
|
||||
|
||||
struct gpmc {
|
||||
u8 res1[0x10];
|
||||
u32 sysconfig; /* 0x10 */
|
||||
u8 res2[0x4];
|
||||
u32 irqstatus; /* 0x18 */
|
||||
u32 irqenable; /* 0x1C */
|
||||
u8 res3[0x20];
|
||||
u32 timeout_control; /* 0x40 */
|
||||
u8 res4[0xC];
|
||||
u32 config; /* 0x50 */
|
||||
u32 status; /* 0x54 */
|
||||
u8 res5[0x8]; /* 0x58 */
|
||||
struct gpmc_cs cs[8]; /* 0x60, 0x90, .. */
|
||||
u32 prefetch_config1; /* 0x1E0 */
|
||||
u32 prefetch_config2; /* 0x1E4 */
|
||||
u32 res6; /* 0x1E8 */
|
||||
u32 prefetch_control; /* 0x1EC */
|
||||
u32 prefetch_status; /* 0x1F0 */
|
||||
u32 ecc_config; /* 0x1F4 */
|
||||
u32 ecc_control; /* 0x1F8 */
|
||||
u32 ecc_size_config; /* 0x1FC */
|
||||
u32 ecc1_result; /* 0x200 */
|
||||
u32 ecc2_result; /* 0x204 */
|
||||
u32 ecc3_result; /* 0x208 */
|
||||
u32 ecc4_result; /* 0x20C */
|
||||
u32 ecc5_result; /* 0x210 */
|
||||
u32 ecc6_result; /* 0x214 */
|
||||
u32 ecc7_result; /* 0x218 */
|
||||
u32 ecc8_result; /* 0x21C */
|
||||
u32 ecc9_result; /* 0x220 */
|
||||
u8 res7[12]; /* 0x224 */
|
||||
u32 testmomde_ctrl; /* 0x230 */
|
||||
u8 res8[12]; /* 0x234 */
|
||||
struct bch_res_0_3 bch_result_0_3[GPMC_MAX_SECTORS]; /* 0x240,0x250, */
|
||||
u8 res9[16 * 4]; /* 0x2C0 - 0x2FF */
|
||||
struct bch_res_4_6 bch_result_4_6[GPMC_MAX_SECTORS]; /* 0x300,0x310, */
|
||||
};
|
||||
|
||||
/* Used for board specific gpmc initialization */
|
||||
extern const struct gpmc *gpmc_cfg;
|
||||
extern char gpmc_cs0_flash;
|
||||
|
||||
#endif /* __ASM_OMAP_GPMC_H */
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* linux/include/linux/mtd/onenand.h
|
||||
*
|
||||
* Copyright (C) 2005-2007 Samsung Electronics
|
||||
* Kyungmin Park <kyungmin.park@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MTD_ONENAND_H
|
||||
#define __LINUX_MTD_ONENAND_H
|
||||
|
||||
#include <linux/mtd/onenand_regs.h>
|
||||
|
||||
/* Note: The header order is impoertant */
|
||||
#include <onenand_uboot.h>
|
||||
|
||||
#include <linux/compat.h>
|
||||
#include <linux/mtd/bbm.h>
|
||||
|
||||
#define MAX_DIES 2
|
||||
#define MAX_BUFFERRAM 2
|
||||
#define MAX_ONENAND_PAGESIZE (4096 + 128)
|
||||
|
||||
/* 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
|
||||
* @param blockpage block & page address in BufferRAM
|
||||
*/
|
||||
struct onenand_bufferram {
|
||||
int blockpage;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct onenand_chip - OneNAND Private Flash Chip Data
|
||||
* @param base [BOARDSPECIFIC] address to access OneNAND
|
||||
* @dies: [INTERN][FLEXONENAND] number of dies on chip
|
||||
* @boundary: [INTERN][FLEXONENAND] Boundary of the dies
|
||||
* @diesize: [INTERN][FLEXONENAND] Size of the dies
|
||||
* @param chipsize [INTERN] the size of one chip for multichip arrays
|
||||
* @param device_id [INTERN] device ID
|
||||
* @param verstion_id [INTERN] version ID
|
||||
* @technology [INTERN] describes the internal NAND array technology such as SLC or MLC.
|
||||
* @density_mask: [INTERN] chip density, used for DDP devices
|
||||
* @param options [BOARDSPECIFIC] various chip options. They can partly be set to inform onenand_scan about
|
||||
* @param erase_shift [INTERN] number of address bits in a block
|
||||
* @param page_shift [INTERN] number of address bits in a page
|
||||
* @param ppb_shift [INTERN] number of address bits in a pages per block
|
||||
* @param page_mask [INTERN] a page per block mask
|
||||
* @param writesize [INTERN] a real page size
|
||||
* @param bufferam_index [INTERN] BufferRAM index
|
||||
* @param bufferam [INTERN] BufferRAM info
|
||||
* @param readw [REPLACEABLE] hardware specific function for read short
|
||||
* @param writew [REPLACEABLE] hardware specific function for write short
|
||||
* @param command [REPLACEABLE] hardware specific function for writing commands to the chip
|
||||
* @param wait [REPLACEABLE] hardware specific function for wait on ready
|
||||
* @param read_bufferram [REPLACEABLE] hardware specific function for BufferRAM Area
|
||||
* @param write_bufferram [REPLACEABLE] hardware specific function for BufferRAM Area
|
||||
* @param chip_lock [INTERN] spinlock used to protect access to this structure and the chip
|
||||
* @param wq [INTERN] wait queue to sleep on if a OneNAND operation is in progress
|
||||
* @param state [INTERN] the current state of the OneNAND device
|
||||
* @param autooob [REPLACEABLE] the default (auto)placement scheme
|
||||
* @param priv [OPTIONAL] pointer to private chip date
|
||||
*/
|
||||
struct onenand_chip {
|
||||
void __iomem *base;
|
||||
unsigned int dies;
|
||||
unsigned int boundary[MAX_DIES];
|
||||
unsigned int 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 erase_shift;
|
||||
unsigned int page_shift;
|
||||
unsigned int ppb_shift; /* Pages per block 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, loff_t addr, int area,
|
||||
unsigned char *buffer, int offset, size_t count);
|
||||
int (*write_bufferram) (struct mtd_info *mtd, loff_t addr, 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);
|
||||
int (*chip_probe)(struct mtd_info *mtd);
|
||||
void (*mmcontrol) (struct mtd_info *mtd, int sync_read);
|
||||
int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
|
||||
int (*scan_bbt)(struct mtd_info *mtd);
|
||||
|
||||
unsigned char *main_buf;
|
||||
unsigned char *spare_buf;
|
||||
#ifdef DONT_USE_UBOOT
|
||||
spinlock_t chip_lock;
|
||||
wait_queue_head_t wq;
|
||||
#endif
|
||||
int state;
|
||||
unsigned char *page_buf;
|
||||
unsigned char *oob_buf;
|
||||
|
||||
struct nand_oobinfo *autooob;
|
||||
int subpagesize;
|
||||
struct nand_ecclayout *ecclayout;
|
||||
|
||||
void *bbm;
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Helper macros
|
||||
*/
|
||||
#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_IS_MLC(this) (this->technology & ONENAND_TECHNOLOGY_IS_MLC)
|
||||
#define ONENAND_IS_DDP(this) \
|
||||
(this->device_id & ONENAND_DEVICE_IS_DDP)
|
||||
|
||||
#define ONENAND_IS_4KB_PAGE(this) \
|
||||
(this->options & ONENAND_HAS_4KB_PAGE)
|
||||
|
||||
#define ONENAND_IS_2PLANE(this) (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_RUNTIME_BADBLOCK_CHECK (0x0200)
|
||||
#define ONENAND_PAGEBUF_ALLOC (0x1000)
|
||||
#define ONENAND_OOBBUF_ALLOC (0x2000)
|
||||
|
||||
/*
|
||||
* OneNAND Flash Manufacturer ID Codes
|
||||
*/
|
||||
#define ONENAND_MFR_NUMONYX 0x20
|
||||
#define ONENAND_MFR_SAMSUNG 0xec
|
||||
|
||||
/**
|
||||
* struct nand_manufacturers - NAND Flash Manufacturer ID Structure
|
||||
* @param name: Manufacturer name
|
||||
* @param 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 int onenand_block(struct onenand_chip *this, loff_t addr);
|
||||
int flexonenand_region(struct mtd_info *mtd, loff_t addr);
|
||||
#endif /* __LINUX_MTD_ONENAND_H */
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* linux/include/linux/mtd/onenand_regs.h
|
||||
*
|
||||
* OneNAND Register header file
|
||||
*
|
||||
* Copyright (C) 2005-2007 Samsung Electronics
|
||||
* Kyungmin Park <kyungmin.park@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#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)
|
||||
|
||||
/*
|
||||
* 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)
|
||||
*/
|
||||
#define ONENAND_DDP_SHIFT (15)
|
||||
#define ONENAND_DDP_CHIP0 (0)
|
||||
#define ONENAND_DDP_CHIP1 (1 << ONENAND_DDP_SHIFT)
|
||||
|
||||
/*
|
||||
* Start Address 8 F107h (R/W)
|
||||
*/
|
||||
#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)
|
||||
#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_READID (0x90)
|
||||
#define FLEXONENAND_CMD_RESET (0xF3)
|
||||
#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)
|
||||
|
||||
/*
|
||||
* 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)
|
||||
|
||||
/*
|
||||
* 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 ONENAND_ECC_4BIT_UNCORRECTABLE (0x1010)
|
||||
#define FLEXONENAND_UNCORRECTABLE_ERROR (0x1010)
|
||||
|
||||
#endif /* __ONENAND_REG_H */
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* 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 */
|
||||
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 */
|
||||
struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only) */
|
||||
};
|
||||
|
||||
#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;
|
||||
|
||||
#ifndef __UBOOT__
|
||||
/**
|
||||
* struct mtd_part_parser_data - used to pass data to MTD partition parsers.
|
||||
* @origin: for RedBoot, start address of MTD device
|
||||
* @of_node: for OF parsers, device node containing partitioning information
|
||||
*/
|
||||
struct mtd_part_parser_data {
|
||||
unsigned long origin;
|
||||
struct device_node *of_node;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Functions dealing with the various ways of partitioning the space
|
||||
*/
|
||||
|
||||
struct mtd_part_parser {
|
||||
struct list_head list;
|
||||
struct module *owner;
|
||||
const char *name;
|
||||
int (*parse_fn)(struct mtd_info *, struct mtd_partition **,
|
||||
struct mtd_part_parser_data *);
|
||||
};
|
||||
|
||||
extern void register_mtd_parser(struct mtd_part_parser *parser);
|
||||
extern void deregister_mtd_parser(struct mtd_part_parser *parser);
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
#if defined(CONFIG_MTD_PARTITIONS)
|
||||
int mtd_parse_partitions(struct mtd_info *parent, const char **_mtdparts,
|
||||
struct mtd_partition **_parts, int *_nparts);
|
||||
void mtd_free_parsed_partitions(struct mtd_partition *parts,
|
||||
unsigned int nparts);
|
||||
#else
|
||||
static inline int
|
||||
mtd_parse_partitions(struct mtd_info *parent, const char **_mtdparts,
|
||||
struct mtd_partition **_parts, int *_nparts)
|
||||
{
|
||||
*_nparts = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
static inline void
|
||||
mtd_free_parsed_partitions(struct mtd_partition *parts, unsigned int nparts)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif /* defined(MTD_PARTITIONS) */
|
||||
|
||||
#endif
|
||||
+1351
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,116 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Samsung Electronics
|
||||
* Minkyu Kang <mk7.kang@samsung.com>
|
||||
* Kyungmin Park <kyungmin.park@samsung.com>
|
||||
*/
|
||||
|
||||
#ifndef __SAMSUNG_ONENAND_H__
|
||||
#define __SAMSUNG_ONENAND_H__
|
||||
|
||||
/*
|
||||
* OneNAND Controller
|
||||
*/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
struct samsung_onenand {
|
||||
unsigned int mem_cfg; /* 0x0000 */
|
||||
unsigned char res1[0xc];
|
||||
unsigned int burst_len; /* 0x0010 */
|
||||
unsigned char res2[0xc];
|
||||
unsigned int mem_reset; /* 0x0020 */
|
||||
unsigned char res3[0xc];
|
||||
unsigned int int_err_stat; /* 0x0030 */
|
||||
unsigned char res4[0xc];
|
||||
unsigned int int_err_mask; /* 0x0040 */
|
||||
unsigned char res5[0xc];
|
||||
unsigned int int_err_ack; /* 0x0050 */
|
||||
unsigned char res6[0xc];
|
||||
unsigned int ecc_err_stat; /* 0x0060 */
|
||||
unsigned char res7[0xc];
|
||||
unsigned int manufact_id; /* 0x0070 */
|
||||
unsigned char res8[0xc];
|
||||
unsigned int device_id; /* 0x0080 */
|
||||
unsigned char res9[0xc];
|
||||
unsigned int data_buf_size; /* 0x0090 */
|
||||
unsigned char res10[0xc];
|
||||
unsigned int boot_buf_size; /* 0x00A0 */
|
||||
unsigned char res11[0xc];
|
||||
unsigned int buf_amount; /* 0x00B0 */
|
||||
unsigned char res12[0xc];
|
||||
unsigned int tech; /* 0x00C0 */
|
||||
unsigned char res13[0xc];
|
||||
unsigned int fba; /* 0x00D0 */
|
||||
unsigned char res14[0xc];
|
||||
unsigned int fpa; /* 0x00E0 */
|
||||
unsigned char res15[0xc];
|
||||
unsigned int fsa; /* 0x00F0 */
|
||||
unsigned char res16[0x3c];
|
||||
unsigned int sync_mode; /* 0x0130 */
|
||||
unsigned char res17[0xc];
|
||||
unsigned int trans_spare; /* 0x0140 */
|
||||
unsigned char res18[0x3c];
|
||||
unsigned int err_page_addr; /* 0x0180 */
|
||||
unsigned char res19[0x1c];
|
||||
unsigned int int_pin_en; /* 0x01A0 */
|
||||
unsigned char res20[0x1c];
|
||||
unsigned int acc_clock; /* 0x01C0 */
|
||||
unsigned char res21[0x1c];
|
||||
unsigned int err_blk_addr; /* 0x01E0 */
|
||||
unsigned char res22[0xc];
|
||||
unsigned int flash_ver_id; /* 0x01F0 */
|
||||
unsigned char res23[0x6c];
|
||||
unsigned int watchdog_cnt_low; /* 0x0260 */
|
||||
unsigned char res24[0xc];
|
||||
unsigned int watchdog_cnt_hi; /* 0x0270 */
|
||||
unsigned char res25[0xc];
|
||||
unsigned int sync_write; /* 0x0280 */
|
||||
unsigned char res26[0x1c];
|
||||
unsigned int cold_reset; /* 0x02A0 */
|
||||
unsigned char res27[0xc];
|
||||
unsigned int ddp_device; /* 0x02B0 */
|
||||
unsigned char res28[0xc];
|
||||
unsigned int multi_plane; /* 0x02C0 */
|
||||
unsigned char res29[0x1c];
|
||||
unsigned int trans_mode; /* 0x02E0 */
|
||||
unsigned char res30[0x1c];
|
||||
unsigned int ecc_err_stat2; /* 0x0300 */
|
||||
unsigned char res31[0xc];
|
||||
unsigned int ecc_err_stat3; /* 0x0310 */
|
||||
unsigned char res32[0xc];
|
||||
unsigned int ecc_err_stat4; /* 0x0320 */
|
||||
unsigned char res33[0x1c];
|
||||
unsigned int dev_page_size; /* 0x0340 */
|
||||
unsigned char res34[0x4c];
|
||||
unsigned int int_mon_status; /* 0x0390 */
|
||||
};
|
||||
#endif
|
||||
|
||||
#define ONENAND_MEM_RESET_HOT 0x3
|
||||
#define ONENAND_MEM_RESET_COLD 0x2
|
||||
#define ONENAND_MEM_RESET_WARM 0x1
|
||||
|
||||
#define INT_ERR_ALL 0x3fff
|
||||
#define CACHE_OP_ERR (1 << 13)
|
||||
#define RST_CMP (1 << 12)
|
||||
#define RDY_ACT (1 << 11)
|
||||
#define INT_ACT (1 << 10)
|
||||
#define UNSUP_CMD (1 << 9)
|
||||
#define LOCKED_BLK (1 << 8)
|
||||
#define BLK_RW_CMP (1 << 7)
|
||||
#define ERS_CMP (1 << 6)
|
||||
#define PGM_CMP (1 << 5)
|
||||
#define LOAD_CMP (1 << 4)
|
||||
#define ERS_FAIL (1 << 3)
|
||||
#define PGM_FAIL (1 << 2)
|
||||
#define INT_TO (1 << 1)
|
||||
#define LD_FAIL_ECC_ERR (1 << 0)
|
||||
|
||||
#define TSRF (1 << 0)
|
||||
|
||||
/* common initialize function */
|
||||
extern void s3c_onenand_init(struct mtd_info *);
|
||||
extern int s5pc110_chip_probe(struct mtd_info *);
|
||||
extern int s5pc210_chip_probe(struct mtd_info *);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,435 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
* Synced from Linux v4.19
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MTD_SPI_NOR_H
|
||||
#define __LINUX_MTD_SPI_NOR_H
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/mtd/cfi.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
|
||||
/*
|
||||
* Manufacturer IDs
|
||||
*
|
||||
* The first byte returned from the flash after sending opcode SPINOR_OP_RDID.
|
||||
* Sometimes these are the same as CFI IDs, but sometimes they aren't.
|
||||
*/
|
||||
#define SNOR_MFR_ATMEL CFI_MFR_ATMEL
|
||||
#define SNOR_MFR_GIGADEVICE 0xc8
|
||||
#define SNOR_MFR_INTEL CFI_MFR_INTEL
|
||||
#define SNOR_MFR_ST CFI_MFR_ST /* ST Micro <--> Micron */
|
||||
#define SNOR_MFR_MICRON CFI_MFR_MICRON /* ST Micro <--> Micron */
|
||||
#define SNOR_MFR_MACRONIX CFI_MFR_MACRONIX
|
||||
#define SNOR_MFR_SPANSION CFI_MFR_AMD
|
||||
#define SNOR_MFR_SST CFI_MFR_SST
|
||||
#define SNOR_MFR_WINBOND 0xef /* Also used by some Spansion */
|
||||
|
||||
/*
|
||||
* 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_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_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_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_RDFSR 0x70 /* Read flag status register */
|
||||
#define SPINOR_OP_CLFSR 0x50 /* Clear flag status register */
|
||||
#define SPINOR_OP_RDEAR 0xc8 /* Read Extended Address Register */
|
||||
#define SPINOR_OP_WREAR 0xc5 /* Write Extended Address Register */
|
||||
|
||||
/* 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_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_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_WRDI 0x04 /* Write disable */
|
||||
#define SPINOR_OP_AAI_WP 0xad /* Auto address increment word program */
|
||||
|
||||
/* Used for SST26* flashes only. */
|
||||
#define SPINOR_OP_READ_BPR 0x72 /* Read block protection register */
|
||||
#define SPINOR_OP_WRITE_BPR 0x42 /* Write block protection register */
|
||||
|
||||
/* Used for S3AN flashes only */
|
||||
#define SPINOR_OP_XSE 0x50 /* Sector erase */
|
||||
#define SPINOR_OP_XPP 0x82 /* Page program */
|
||||
#define SPINOR_OP_XRDSR 0xd7 /* Read status register */
|
||||
|
||||
#define XSR_PAGESIZE BIT(0) /* Page size in Po2 or Linear */
|
||||
#define XSR_RDY BIT(7) /* Ready */
|
||||
|
||||
/* 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 */
|
||||
#define SPINOR_OP_BRRD 0x16 /* Bank register read */
|
||||
#define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */
|
||||
|
||||
/* Used for Micron flashes only. */
|
||||
#define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */
|
||||
#define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */
|
||||
|
||||
/* 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_TB BIT(5) /* 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 SR_QUAD_EN_MX BIT(6) /* Macronix Quad I/O */
|
||||
|
||||
/* Enhanced Volatile Configuration Register bits */
|
||||
#define EVCR_QUAD_EN_MICRON BIT(7) /* Micron Quad I/O */
|
||||
|
||||
/* Flag Status Register bits */
|
||||
#define FSR_READY BIT(7) /* Device status, 0 = Busy, 1 = Ready */
|
||||
#define FSR_E_ERR BIT(5) /* Erase operation status */
|
||||
#define FSR_P_ERR BIT(4) /* Program operation status */
|
||||
#define FSR_PT_ERR BIT(1) /* Protection error bit */
|
||||
|
||||
/* Configuration Register bits. */
|
||||
#define CR_QUAD_EN_SPAN BIT(1) /* Spansion Quad I/O */
|
||||
|
||||
/* Status Register 2 bits. */
|
||||
#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),
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#define SPI_NOR_MAX_CMD_SIZE 8
|
||||
enum spi_nor_ops {
|
||||
SPI_NOR_OPS_READ = 0,
|
||||
SPI_NOR_OPS_WRITE,
|
||||
SPI_NOR_OPS_ERASE,
|
||||
SPI_NOR_OPS_LOCK,
|
||||
SPI_NOR_OPS_UNLOCK,
|
||||
};
|
||||
|
||||
enum spi_nor_option_flags {
|
||||
SNOR_F_USE_FSR = BIT(0),
|
||||
SNOR_F_HAS_SR_TB = BIT(1),
|
||||
SNOR_F_NO_OP_CHIP_ERASE = BIT(2),
|
||||
SNOR_F_S3AN_ADDR_DEFAULT = BIT(3),
|
||||
SNOR_F_READY_XSR_RDY = BIT(4),
|
||||
SNOR_F_USE_CLSR = BIT(5),
|
||||
SNOR_F_BROKEN_RESET = BIT(6),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct flash_info - Forward declaration of a structure used internally by
|
||||
* spi_nor_scan()
|
||||
*/
|
||||
struct flash_info;
|
||||
|
||||
/*
|
||||
* TODO: Remove, once all users of spi_flash interface are moved to MTD
|
||||
*
|
||||
* struct spi_flash {
|
||||
* Defined below (keep this text to enable searching for spi_flash decl)
|
||||
* }
|
||||
*/
|
||||
#define spi_flash spi_nor
|
||||
|
||||
/**
|
||||
* struct spi_nor - Structure for defining a the SPI NOR layer
|
||||
* @mtd: point to a mtd_info structure
|
||||
* @lock: the lock for the read/write/erase/lock/unlock operations
|
||||
* @dev: point to a spi device, or a spi nor controller device.
|
||||
* @info: spi-nor part JDEC MFR id and other info
|
||||
* @page_size: the page size of the SPI NOR
|
||||
* @addr_width: 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
|
||||
* @bank_read_cmd: Bank read cmd
|
||||
* @bank_write_cmd: Bank write cmd
|
||||
* @bank_curr: Current flash bank
|
||||
* @sst_write_second: used by the SST write operation
|
||||
* @flags: flag options for the current SPI-NOR (SNOR_F_*)
|
||||
* @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
|
||||
* @cmd_buf: used by the write_reg
|
||||
* @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: [DRIVER-SPECIFIC] read out the register
|
||||
* @write_reg: [DRIVER-SPECIFIC] write data to the register
|
||||
* @read: [DRIVER-SPECIFIC] read data from the SPI NOR
|
||||
* @write: [DRIVER-SPECIFIC] write data to the SPI NOR
|
||||
* @erase: [DRIVER-SPECIFIC] 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()
|
||||
* @flash_lock: [FLASH-SPECIFIC] lock a region of the SPI NOR
|
||||
* @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR
|
||||
* @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is
|
||||
* @quad_enable: [FLASH-SPECIFIC] enables SPI NOR quad mode
|
||||
* completely locked
|
||||
* @priv: the private data
|
||||
*/
|
||||
struct spi_nor {
|
||||
struct mtd_info mtd;
|
||||
struct udevice *dev;
|
||||
struct spi_slave *spi;
|
||||
const struct flash_info *info;
|
||||
u32 page_size;
|
||||
u8 addr_width;
|
||||
u8 erase_opcode;
|
||||
u8 read_opcode;
|
||||
u8 read_dummy;
|
||||
u8 program_opcode;
|
||||
#ifdef CONFIG_SPI_FLASH_BAR
|
||||
u8 bank_read_cmd;
|
||||
u8 bank_write_cmd;
|
||||
u8 bank_curr;
|
||||
#endif
|
||||
enum spi_nor_protocol read_proto;
|
||||
enum spi_nor_protocol write_proto;
|
||||
enum spi_nor_protocol reg_proto;
|
||||
bool sst_write_second;
|
||||
u32 flags;
|
||||
u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE];
|
||||
|
||||
int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
|
||||
void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
|
||||
int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
|
||||
int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
|
||||
|
||||
ssize_t (*read)(struct spi_nor *nor, loff_t from,
|
||||
size_t len, u_char *read_buf);
|
||||
ssize_t (*write)(struct spi_nor *nor, loff_t to,
|
||||
size_t len, const u_char *write_buf);
|
||||
int (*erase)(struct spi_nor *nor, loff_t offs);
|
||||
|
||||
#ifdef CONFIG_SPI_BLOCK_PROTECT
|
||||
unsigned int bp_level_max;
|
||||
|
||||
void (*lock)(unsigned char cmp, unsigned char level,
|
||||
unsigned char op);
|
||||
#endif
|
||||
int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
|
||||
int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
|
||||
int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
|
||||
int (*quad_enable)(struct spi_nor *nor);
|
||||
|
||||
void *priv;
|
||||
/* Compatibility for spi_flash, remove once sf layer is merged with mtd */
|
||||
const char *name;
|
||||
u32 size;
|
||||
u32 sector_size;
|
||||
u32 erase_size;
|
||||
};
|
||||
|
||||
static inline void spi_nor_set_flash_node(struct spi_nor *nor,
|
||||
const struct device_node *np)
|
||||
{
|
||||
mtd_set_of_node(&nor->mtd, np);
|
||||
}
|
||||
|
||||
static inline const struct
|
||||
device_node *spi_nor_get_flash_node(struct spi_nor *nor)
|
||||
{
|
||||
return mtd_get_of_node(&nor->mtd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 Octo SPI protocols first,
|
||||
* then Quad SPI protocols before Dual SPI protocols, Fast Read and lastly
|
||||
* (Slow) Read.
|
||||
*/
|
||||
#define SNOR_HWCAPS_READ_MASK GENMASK(14, 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_HWCPAS_READ_OCTO GENMASK(14, 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)
|
||||
|
||||
/*
|
||||
* Page Program capabilities.
|
||||
* MUST be ordered by priority: the higher bit position, the higher priority.
|
||||
* Like (Fast) Read capabilities, Octo/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(22, 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_OCTO GENMASK(22, 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)
|
||||
|
||||
/**
|
||||
* spi_nor_scan() - scan the SPI NOR
|
||||
* @nor: the spi_nor structure
|
||||
*
|
||||
* 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{}.
|
||||
*
|
||||
* Return: 0 for success, others for failure.
|
||||
*/
|
||||
int spi_nor_scan(struct spi_nor *nor);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,433 @@
|
||||
/* 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
|
||||
|
||||
#ifndef __UBOOT__
|
||||
#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>
|
||||
#else
|
||||
#include <common.h>
|
||||
#include <spi.h>
|
||||
#include <spi-mem.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Standard SPI NAND flash operations
|
||||
*/
|
||||
|
||||
#define SPINAND_RESET_OP \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xff, 1), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_WR_EN_DIS_OP(enable) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD((enable) ? 0x06 : 0x04, 1), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_READID_OP(ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1))
|
||||
|
||||
#define SPINAND_SET_FEATURE_OP(reg, valptr) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x1f, 1), \
|
||||
SPI_MEM_OP_ADDR(1, reg, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_OUT(1, valptr, 1))
|
||||
|
||||
#define SPINAND_GET_FEATURE_OP(reg, valptr) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x0f, 1), \
|
||||
SPI_MEM_OP_ADDR(1, reg, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_IN(1, valptr, 1))
|
||||
|
||||
#define SPINAND_BLK_ERASE_OP(addr) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xd8, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_PAGE_READ_OP(addr) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x13, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_OP(fast, addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_X2_OP(addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_X4_OP(addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 2), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 2), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 4), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 4), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4))
|
||||
|
||||
#define SPINAND_PROG_EXEC_OP(addr) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x10, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_PROG_LOAD(reset, addr, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x02 : 0x84, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_OUT(len, buf, 1))
|
||||
|
||||
#define SPINAND_PROG_LOAD_X4(reset, addr, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x32 : 0x34, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_OUT(len, buf, 4))
|
||||
|
||||
/**
|
||||
* Standard SPI NAND flash commands
|
||||
*/
|
||||
#define SPINAND_CMD_PROG_LOAD_X4 0x32
|
||||
#define SPINAND_CMD_PROG_LOAD_RDM_DATA_X4 0x34
|
||||
|
||||
/* feature register */
|
||||
#define REG_BLOCK_LOCK 0xa0
|
||||
#define BL_ALL_UNLOCKED 0x00
|
||||
|
||||
/* configuration register */
|
||||
#define REG_CFG 0xb0
|
||||
#define CFG_OTP_ENABLE BIT(6)
|
||||
#define CFG_ECC_ENABLE BIT(4)
|
||||
#define CFG_QUAD_ENABLE BIT(0)
|
||||
|
||||
/* status register */
|
||||
#define REG_STATUS 0xc0
|
||||
#define STATUS_BUSY BIT(0)
|
||||
#define STATUS_ERASE_FAILED BIT(2)
|
||||
#define STATUS_PROG_FAILED BIT(3)
|
||||
#define STATUS_ECC_MASK GENMASK(5, 4)
|
||||
#define STATUS_ECC_NO_BITFLIPS (0 << 4)
|
||||
#define STATUS_ECC_HAS_BITFLIPS (1 << 4)
|
||||
#define STATUS_ECC_UNCOR_ERROR (2 << 4)
|
||||
|
||||
struct spinand_op;
|
||||
struct spinand_device;
|
||||
|
||||
#define SPINAND_MAX_ID_LEN 4
|
||||
|
||||
/**
|
||||
* struct spinand_id - SPI NAND id structure
|
||||
* @data: buffer containing the id bytes. Currently 4 bytes large, but can
|
||||
* be extended if required
|
||||
* @len: ID length
|
||||
*
|
||||
* struct_spinand_id->data contains all bytes returned after a READ_ID command,
|
||||
* including dummy bytes if the chip does not emit ID bytes right after the
|
||||
* READ_ID command. The responsibility to extract real ID bytes is left to
|
||||
* struct_manufacurer_ops->detect().
|
||||
*/
|
||||
struct spinand_id {
|
||||
u8 data[SPINAND_MAX_ID_LEN];
|
||||
int len;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct manufacurer_ops - SPI NAND manufacturer specific operations
|
||||
* @detect: detect a SPI NAND device. Every time a SPI NAND device is probed
|
||||
* the core calls the struct_manufacurer_ops->detect() hook of each
|
||||
* registered manufacturer until one of them return 1. Note that
|
||||
* the first thing to check in this hook is that the manufacturer ID
|
||||
* in struct_spinand_device->id matches the manufacturer whose
|
||||
* ->detect() hook has been called. Should return 1 if there's a
|
||||
* match, 0 if the manufacturer ID does not match and a negative
|
||||
* error code otherwise. When true is returned, the core assumes
|
||||
* that properties of the NAND chip (spinand->base.memorg and
|
||||
* spinand->base.eccreq) have been filled
|
||||
* @init: initialize a SPI NAND device
|
||||
* @cleanup: cleanup a SPI NAND device
|
||||
*
|
||||
* Each SPI NAND manufacturer driver should implement this interface so that
|
||||
* NAND chips coming from this vendor can be detected and initialized properly.
|
||||
*/
|
||||
struct spinand_manufacturer_ops {
|
||||
int (*detect)(struct spinand_device *spinand);
|
||||
int (*init)(struct spinand_device *spinand);
|
||||
void (*cleanup)(struct spinand_device *spinand);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct spinand_manufacturer - SPI NAND manufacturer instance
|
||||
* @id: manufacturer ID
|
||||
* @name: manufacturer name
|
||||
* @ops: manufacturer operations
|
||||
*/
|
||||
struct spinand_manufacturer {
|
||||
u8 id;
|
||||
char *name;
|
||||
const struct spinand_manufacturer_ops *ops;
|
||||
};
|
||||
|
||||
/* SPI NAND manufacturers */
|
||||
extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer macronix_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer micron_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer winbond_spinand_manufacturer;
|
||||
|
||||
/**
|
||||
* struct spinand_op_variants - SPI NAND operation variants
|
||||
* @ops: the list of variants for a given operation
|
||||
* @nops: the number of variants
|
||||
*
|
||||
* Some operations like read-from-cache/write-to-cache have several variants
|
||||
* depending on the number of IO lines you use to transfer data or address
|
||||
* cycles. This structure is a way to describe the different variants supported
|
||||
* by a chip and let the core pick the best one based on the SPI mem controller
|
||||
* capabilities.
|
||||
*/
|
||||
struct spinand_op_variants {
|
||||
const struct spi_mem_op *ops;
|
||||
unsigned int nops;
|
||||
};
|
||||
|
||||
#define SPINAND_OP_VARIANTS(name, ...) \
|
||||
const struct spinand_op_variants name = { \
|
||||
.ops = (struct spi_mem_op[]) { __VA_ARGS__ }, \
|
||||
.nops = sizeof((struct spi_mem_op[]){ __VA_ARGS__ }) / \
|
||||
sizeof(struct spi_mem_op), \
|
||||
}
|
||||
|
||||
/**
|
||||
* spinand_ecc_info - description of the on-die ECC implemented by a SPI NAND
|
||||
* chip
|
||||
* @get_status: get the ECC status. Should return a positive number encoding
|
||||
* the number of corrected bitflips if correction was possible or
|
||||
* -EBADMSG if there are uncorrectable errors. I can also return
|
||||
* other negative error codes if the error is not caused by
|
||||
* uncorrectable bitflips
|
||||
* @ooblayout: the OOB layout used by the on-die ECC implementation
|
||||
*/
|
||||
struct spinand_ecc_info {
|
||||
int (*get_status)(struct spinand_device *spinand, u8 status);
|
||||
const struct mtd_ooblayout_ops *ooblayout;
|
||||
};
|
||||
|
||||
#define SPINAND_HAS_QE_BIT BIT(0)
|
||||
|
||||
/**
|
||||
* struct spinand_info - Structure used to describe SPI NAND chips
|
||||
* @model: model name
|
||||
* @devid: device ID
|
||||
* @flags: OR-ing of the SPINAND_XXX flags
|
||||
* @memorg: memory organization
|
||||
* @eccreq: ECC requirements
|
||||
* @eccinfo: on-die ECC info
|
||||
* @op_variants: operations variants
|
||||
* @op_variants.read_cache: variants of the read-cache operation
|
||||
* @op_variants.write_cache: variants of the write-cache operation
|
||||
* @op_variants.update_cache: variants of the update-cache operation
|
||||
* @select_target: function used to select a target/die. Required only for
|
||||
* multi-die chips
|
||||
*
|
||||
* Each SPI NAND manufacturer driver should have a spinand_info table
|
||||
* describing all the chips supported by the driver.
|
||||
*/
|
||||
struct spinand_info {
|
||||
const char *model;
|
||||
u8 devid;
|
||||
u32 flags;
|
||||
struct nand_memory_organization memorg;
|
||||
struct nand_ecc_req eccreq;
|
||||
struct spinand_ecc_info eccinfo;
|
||||
struct {
|
||||
const struct spinand_op_variants *read_cache;
|
||||
const struct spinand_op_variants *write_cache;
|
||||
const struct spinand_op_variants *update_cache;
|
||||
} op_variants;
|
||||
int (*select_target)(struct spinand_device *spinand,
|
||||
unsigned int target);
|
||||
};
|
||||
|
||||
#define SPINAND_INFO_OP_VARIANTS(__read, __write, __update) \
|
||||
{ \
|
||||
.read_cache = __read, \
|
||||
.write_cache = __write, \
|
||||
.update_cache = __update, \
|
||||
}
|
||||
|
||||
#define SPINAND_ECCINFO(__ooblayout, __get_status) \
|
||||
.eccinfo = { \
|
||||
.ooblayout = __ooblayout, \
|
||||
.get_status = __get_status, \
|
||||
}
|
||||
|
||||
#define SPINAND_SELECT_TARGET(__func) \
|
||||
.select_target = __func,
|
||||
|
||||
#define SPINAND_INFO(__model, __id, __memorg, __eccreq, __op_variants, \
|
||||
__flags, ...) \
|
||||
{ \
|
||||
.model = __model, \
|
||||
.devid = __id, \
|
||||
.memorg = __memorg, \
|
||||
.eccreq = __eccreq, \
|
||||
.op_variants = __op_variants, \
|
||||
.flags = __flags, \
|
||||
__VA_ARGS__ \
|
||||
}
|
||||
|
||||
/**
|
||||
* struct spinand_device - SPI NAND device instance
|
||||
* @base: NAND device instance
|
||||
* @slave: pointer to the SPI slave object
|
||||
* @lock: lock used to serialize accesses to the NAND
|
||||
* @id: NAND ID as returned by READ_ID
|
||||
* @flags: NAND flags
|
||||
* @op_templates: various SPI mem op templates
|
||||
* @op_templates.read_cache: read cache op template
|
||||
* @op_templates.write_cache: write cache op template
|
||||
* @op_templates.update_cache: update cache op template
|
||||
* @select_target: select a specific target/die. Usually called before sending
|
||||
* a command addressing a page or an eraseblock embedded in
|
||||
* this die. Only required if your chip exposes several dies
|
||||
* @cur_target: currently selected target/die
|
||||
* @eccinfo: on-die ECC information
|
||||
* @cfg_cache: config register cache. One entry per die
|
||||
* @databuf: bounce buffer for data
|
||||
* @oobbuf: bounce buffer for OOB data
|
||||
* @scratchbuf: buffer used for everything but page accesses. This is needed
|
||||
* because the spi-mem interface explicitly requests that buffers
|
||||
* passed in spi_mem_op be DMA-able, so we can't based the bufs on
|
||||
* the stack
|
||||
* @manufacturer: SPI NAND manufacturer information
|
||||
* @priv: manufacturer private data
|
||||
*/
|
||||
struct spinand_device {
|
||||
struct nand_device base;
|
||||
#ifndef __UBOOT__
|
||||
struct spi_mem *spimem;
|
||||
struct mutex lock;
|
||||
#else
|
||||
struct spi_slave *slave;
|
||||
#endif
|
||||
struct spinand_id id;
|
||||
u32 flags;
|
||||
|
||||
struct {
|
||||
const struct spi_mem_op *read_cache;
|
||||
const struct spi_mem_op *write_cache;
|
||||
const struct spi_mem_op *update_cache;
|
||||
} op_templates;
|
||||
|
||||
int (*select_target)(struct spinand_device *spinand,
|
||||
unsigned int target);
|
||||
unsigned int cur_target;
|
||||
|
||||
struct spinand_ecc_info eccinfo;
|
||||
|
||||
u8 *cfg_cache;
|
||||
u8 *databuf;
|
||||
u8 *oobbuf;
|
||||
u8 *scratchbuf;
|
||||
const struct spinand_manufacturer *manufacturer;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* mtd_to_spinand() - Get the SPI NAND device attached to an MTD instance
|
||||
* @mtd: MTD instance
|
||||
*
|
||||
* Return: the SPI NAND device attached to @mtd.
|
||||
*/
|
||||
static inline struct spinand_device *mtd_to_spinand(struct mtd_info *mtd)
|
||||
{
|
||||
return container_of(mtd_to_nanddev(mtd), struct spinand_device, base);
|
||||
}
|
||||
|
||||
/**
|
||||
* spinand_to_mtd() - Get the MTD device embedded in a SPI NAND device
|
||||
* @spinand: SPI NAND device
|
||||
*
|
||||
* Return: the MTD device embedded in @spinand.
|
||||
*/
|
||||
static inline struct mtd_info *spinand_to_mtd(struct spinand_device *spinand)
|
||||
{
|
||||
return nanddev_to_mtd(&spinand->base);
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_to_spinand() - Get the SPI NAND device embedding an NAND object
|
||||
* @nand: NAND object
|
||||
*
|
||||
* Return: the SPI NAND device embedding @nand.
|
||||
*/
|
||||
static inline struct spinand_device *nand_to_spinand(struct nand_device *nand)
|
||||
{
|
||||
return container_of(nand, struct spinand_device, base);
|
||||
}
|
||||
|
||||
/**
|
||||
* spinand_to_nand() - Get the NAND device embedded in a SPI NAND object
|
||||
* @spinand: SPI NAND device
|
||||
*
|
||||
* Return: the NAND device embedded in @spinand.
|
||||
*/
|
||||
static inline struct nand_device *
|
||||
spinand_to_nand(struct spinand_device *spinand)
|
||||
{
|
||||
return &spinand->base;
|
||||
}
|
||||
|
||||
/**
|
||||
* spinand_set_of_node - Attach a DT node to a SPI NAND device
|
||||
* @spinand: SPI NAND device
|
||||
* @np: DT node
|
||||
*
|
||||
* Attach a DT node to a SPI NAND device.
|
||||
*/
|
||||
static inline void spinand_set_of_node(struct spinand_device *spinand,
|
||||
const struct device_node *np)
|
||||
{
|
||||
nanddev_set_of_node(&spinand->base, np);
|
||||
}
|
||||
|
||||
int spinand_match_and_init(struct spinand_device *dev,
|
||||
const struct spinand_info *table,
|
||||
unsigned int table_size, u8 devid);
|
||||
|
||||
int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
|
||||
int spinand_select_target(struct spinand_device *spinand, unsigned int target);
|
||||
|
||||
#endif /* __LINUX_MTD_SPINAND_H */
|
||||
@@ -0,0 +1,100 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2009
|
||||
* Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
|
||||
*/
|
||||
|
||||
#ifndef ST_SMI_H
|
||||
#define ST_SMI_H
|
||||
|
||||
/* 0xF800.0000 . 0xFBFF.FFFF 64MB SMI (Serial Flash Mem) */
|
||||
/* 0xFC00.0000 . 0xFC1F.FFFF 2MB SMI (Serial Flash Reg.) */
|
||||
|
||||
#define FLASH_START_ADDRESS CONFIG_SYS_FLASH_BASE
|
||||
#define FLASH_BANK_SIZE CONFIG_SYS_FLASH_BANK_SIZE
|
||||
|
||||
#define SMIBANK0_BASE (FLASH_START_ADDRESS)
|
||||
#define SMIBANK1_BASE (SMIBANK0_BASE + FLASH_BANK_SIZE)
|
||||
#define SMIBANK2_BASE (SMIBANK1_BASE + FLASH_BANK_SIZE)
|
||||
#define SMIBANK3_BASE (SMIBANK2_BASE + FLASH_BANK_SIZE)
|
||||
|
||||
#define BANK0 0
|
||||
#define BANK1 1
|
||||
#define BANK2 2
|
||||
#define BANK3 3
|
||||
|
||||
struct smi_regs {
|
||||
u32 smi_cr1;
|
||||
u32 smi_cr2;
|
||||
u32 smi_sr;
|
||||
u32 smi_tr;
|
||||
u32 smi_rr;
|
||||
};
|
||||
|
||||
/* CONTROL REG 1 */
|
||||
#define BANK_EN 0x0000000F /* enables all banks */
|
||||
#define DSEL_TIME 0x00000060 /* Deselect time */
|
||||
#define PRESCAL5 0x00000500 /* AHB_CK prescaling value */
|
||||
#define PRESCALA 0x00000A00 /* AHB_CK prescaling value */
|
||||
#define PRESCAL3 0x00000300 /* AHB_CK prescaling value */
|
||||
#define PRESCAL4 0x00000400 /* AHB_CK prescaling value */
|
||||
#define SW_MODE 0x10000000 /* enables SW Mode */
|
||||
#define WB_MODE 0x20000000 /* Write Burst Mode */
|
||||
#define FAST_MODE 0x00008000 /* Fast Mode */
|
||||
#define HOLD1 0x00010000
|
||||
|
||||
/* CONTROL REG 2 */
|
||||
#define RD_STATUS_REG 0x00000400 /* reads status reg */
|
||||
#define WE 0x00000800 /* Write Enable */
|
||||
#define BANK0_SEL 0x00000000 /* Select Banck0 */
|
||||
#define BANK1_SEL 0x00001000 /* Select Banck1 */
|
||||
#define BANK2_SEL 0x00002000 /* Select Banck2 */
|
||||
#define BANK3_SEL 0x00003000 /* Select Banck3 */
|
||||
#define BANKSEL_SHIFT 12
|
||||
#define SEND 0x00000080 /* Send data */
|
||||
#define TX_LEN_1 0x00000001 /* data length = 1 byte */
|
||||
#define TX_LEN_2 0x00000002 /* data length = 2 byte */
|
||||
#define TX_LEN_3 0x00000003 /* data length = 3 byte */
|
||||
#define TX_LEN_4 0x00000004 /* data length = 4 byte */
|
||||
#define RX_LEN_1 0x00000010 /* data length = 1 byte */
|
||||
#define RX_LEN_2 0x00000020 /* data length = 2 byte */
|
||||
#define RX_LEN_3 0x00000030 /* data length = 3 byte */
|
||||
#define RX_LEN_4 0x00000040 /* data length = 4 byte */
|
||||
#define TFIE 0x00000100 /* Tx Flag Interrupt Enable */
|
||||
#define WCIE 0x00000200 /* WCF Interrupt Enable */
|
||||
|
||||
/* STATUS_REG */
|
||||
#define INT_WCF_CLR 0xFFFFFDFF /* clear: WCF clear */
|
||||
#define INT_TFF_CLR 0xFFFFFEFF /* clear: TFF clear */
|
||||
#define WIP_BIT 0x00000001 /* WIP Bit of SPI SR */
|
||||
#define WEL_BIT 0x00000002 /* WEL Bit of SPI SR */
|
||||
#define RSR 0x00000005 /* Read Status regiser */
|
||||
#define TFF 0x00000100 /* Transfer Finished FLag */
|
||||
#define WCF 0x00000200 /* Transfer Finished FLag */
|
||||
#define ERF1 0x00000400 /* Error Flag 1 */
|
||||
#define ERF2 0x00000800 /* Error Flag 2 */
|
||||
#define WM0 0x00001000 /* WM Bank 0 */
|
||||
#define WM1 0x00002000 /* WM Bank 1 */
|
||||
#define WM2 0x00004000 /* WM Bank 2 */
|
||||
#define WM3 0x00008000 /* WM Bank 3 */
|
||||
#define WM_SHIFT 12
|
||||
|
||||
/* TR REG */
|
||||
#define READ_ID 0x0000009F /* Read Identification */
|
||||
#define BULK_ERASE 0x000000C7 /* BULK erase */
|
||||
#define SECTOR_ERASE 0x000000D8 /* SECTOR erase */
|
||||
#define WRITE_ENABLE 0x00000006 /* Wenable command to FLASH */
|
||||
|
||||
struct flash_dev {
|
||||
u32 density;
|
||||
ulong size;
|
||||
ushort sector_count;
|
||||
};
|
||||
|
||||
#define SFLASH_PAGE_SIZE 0x100 /* flash page size */
|
||||
#define XFER_FINISH_TOUT 15 /* xfer finish timeout(in ms) */
|
||||
#define WMODE_TOUT 15 /* write enable timeout(in ms) */
|
||||
|
||||
extern void smi_init(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,289 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (c) International Business Machines Corp., 2006
|
||||
*
|
||||
* Author: Artem Bityutskiy (Битюцкий Артём)
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_UBI_H__
|
||||
#define __LINUX_UBI_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <mtd/ubi-user.h>
|
||||
#endif
|
||||
|
||||
/* 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 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;
|
||||
#ifndef __UBOOT__
|
||||
struct scatterlist sg[UBI_MAX_SG_COUNT];
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
#ifndef __UBOOT__
|
||||
dev_t cdev;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* 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_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_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);
|
||||
|
||||
#ifndef __UBOOT__
|
||||
typedef int (*notifier_fn_t)(void *nb,
|
||||
unsigned long action, void *data);
|
||||
|
||||
struct notifier_block {
|
||||
notifier_fn_t notifier_call;
|
||||
struct notifier_block *next;
|
||||
void *next;
|
||||
int priority;
|
||||
};
|
||||
|
||||
int ubi_register_volume_notifier(struct notifier_block *nb,
|
||||
int ignore_existing);
|
||||
int ubi_unregister_volume_notifier(struct notifier_block *nb);
|
||||
#endif
|
||||
|
||||
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);
|
||||
int ubi_flush(int ubi_num, int vol_id, int lnum);
|
||||
|
||||
/*
|
||||
* 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__ */
|
||||
Reference in New Issue
Block a user