diff options
author | Patrick Turley <patrick.turley@freescale.com> | 2010-02-24 11:56:27 -0600 |
---|---|---|
committer | Frank Li <Frank.Li@freescale.com> | 2010-03-16 12:37:46 +0800 |
commit | a178d9bf9235c56fa960f2f90de8453ec17756d1 (patch) | |
tree | 464d6c7ed5a452ef01257eb54ee7e3ea1a83df0d /drivers/mtd/nand/gpmi1/gpmi.h | |
parent | 77e3d6e4430166ee5cdcb1352aa7b13fd32ac095 (diff) |
ENGR00117735-2 MX28: SLC/MLC NAND
Port the i.MX23 NAND Flash driver to i.MX28.
Signed-off-by: Patrick Turley <patrick.turley@freescale.com>
Diffstat (limited to 'drivers/mtd/nand/gpmi1/gpmi.h')
-rw-r--r-- | drivers/mtd/nand/gpmi1/gpmi.h | 456 |
1 files changed, 456 insertions, 0 deletions
diff --git a/drivers/mtd/nand/gpmi1/gpmi.h b/drivers/mtd/nand/gpmi1/gpmi.h new file mode 100644 index 00000000000..c49268ce944 --- /dev/null +++ b/drivers/mtd/nand/gpmi1/gpmi.h @@ -0,0 +1,456 @@ +/* + * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface) + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2010 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __DRIVERS_GPMI_H +#define __DRIVERS_GPMI_H + +#include <linux/mtd/partitions.h> +#include <linux/timer.h> +#include <mach/dmaengine.h> +#include "regs-gpmi.h" +#include "regs-bch.h" + +#include "../nand_device_info.h" + +/* The number of DMA descriptors we need to allocate. */ + +#define DMA_DESCRIPTOR_COUNT (4) + +#define NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES (512) +#define NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES \ + ((((NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES*8)/16)*6)/8) +#define NAND_HC_ECC_OFFSET_FIRST_DATA_COPY (0) +#define NAND_HC_ECC_OFFSET_SECOND_DATA_COPY \ + (NAND_HC_ECC_OFFSET_FIRST_DATA_COPY + \ + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES) +#define NAND_HC_ECC_OFFSET_THIRD_DATA_COPY \ + (NAND_HC_ECC_OFFSET_SECOND_DATA_COPY + \ + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES) +#define NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY \ + (NAND_HC_ECC_OFFSET_THIRD_DATA_COPY + \ + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES) +#define NAND_HC_ECC_OFFSET_SECOND_PARITY_COPY \ + (NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY + \ + NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES) +#define NAND_HC_ECC_OFFSET_THIRD_PARITY_COPY \ + (NAND_HC_ECC_OFFSET_SECOND_PARITY_COPY + \ + NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES) + +/** + * struct gpmi_nand_timing - NAND Flash timing parameters. + * + * This structure contains the fundamental timing attributes for the NAND Flash + * bus. + * + * @data_setup_in_ns: The data setup time, in nanoseconds. Usually the + * maximum of tDS and tWP. A negative value + * indicates this characteristic isn't known. + * @data_hold_in_ns: The data hold time, in nanoseconds. Usually the + * maximum of tDH, tWH and tREH. A negative value + * indicates this characteristic isn't known. + * @address_setup_in_ns: The address setup time, in nanoseconds. Usually + * the maximum of tCLS, tCS and tALS. A negative + * value indicates this characteristic isn't known. + * @gpmi_sample_time_in_ns: A GPMI-specific timing parameter. A negative + * value indicates this characteristic isn't known. + * @tREA_in_ns: tREA, in nanoseconds, from the data sheet. A + * negative value indicates this characteristic + * isn't known. + * @tRLOH_in_ns: tRLOH, in nanoseconds, from the data sheet. A + * negative value indicates this characteristic + * isn't known. + * @tRHOH_in_ns: tRHOH, in nanoseconds, from the data sheet. A + * negative value indicates this characteristic + * isn't known. + */ + +struct gpmi_nand_timing { + int8_t data_setup_in_ns; + int8_t data_hold_in_ns; + int8_t address_setup_in_ns; + int8_t gpmi_sample_delay_in_ns; + int8_t tREA_in_ns; + int8_t tRLOH_in_ns; + int8_t tRHOH_in_ns; +}; + +/** + * struct gpmi_bcb_info - Information obtained from Boot Control Blocks. + * + * @timing: Timing values extracted from an NCB. + * @ncbblock: The offset within the MTD at which the NCB was found. + * @pre_ncb: + * @pre_ncb_size: + */ + +struct gpmi_bcb_info { + struct gpmi_nand_timing timing; + loff_t ncbblock; + const void *pre_ncb; + size_t pre_ncb_size; +}; + +struct gpmi_ncb; + +int gpmi_erase(struct mtd_info *mtd, struct erase_info *instr); +int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs); +int gpmi_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip); +int gpmi_scan_bbt(struct mtd_info *mtd); +int gpmi_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip); +#ifdef CONFIG_MTD_NAND_GPMI_SYSFS_ENTRIES +int gpmi_sysfs(struct platform_device *p, int create); +#endif +int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page, int sndcmd); +int gpmi_write_ncb(struct mtd_info *mtd, struct gpmi_bcb_info *b); + +unsigned gpmi_hamming_ecc_size_22_16(int block_size); +void gpmi_encode_hamming_ncb_22_16(void *source_block, size_t source_size, + void *target_block, size_t target_size); +void gpmi_encode_hamming_22_16(void *source_block, size_t src_size, + void *source_ecc, size_t ecc_size); +int gpmi_verify_hamming_22_16(void *data, u8 *parity, size_t size); + +unsigned gpmi_hamming_ecc_size_13_8(int block_size); +void gpmi_encode_hamming_ncb_13_8(void *source_block, size_t source_size, + void *target_block, size_t target_size); +void gpmi_encode_hamming_13_8(void *source_block, size_t src_size, + void *source_ecc, size_t ecc_size); +int gpmi_verify_hamming_13_8(void *data, u8 *parity, size_t size); + +#define GPMI_DMA_MAX_CHAIN 20 /* max DMA commands in chain */ + +/* + * Sizes of data buffers to exchange commands/data with NAND chip. + * Default values cover 4K NAND page (4096 data bytes + 218 bytes OOB) + */ +#define GPMI_CMD_BUF_SZ 10 +#define GPMI_DATA_BUF_SZ NAND_MAX_PAGESIZE +#define GPMI_WRITE_BUF_SZ NAND_MAX_PAGESIZE +#define GPMI_OOB_BUF_SZ NAND_MAX_OOBSIZE + +#define GPMI_MAX_CHIPS 10 + +/** + * struct gpmi_ecc_descriptor - Abstract description of ECC. + * + * @name: The name of the ECC represented by this structure. + * @list: Infrastructure for the list to which this structure belongs. + * @setup: A pointer to a function that prepares the ECC to function. + * @reset: A pointer to a function that resets the ECC to a known state. This + * pointer is currently never used, and probably should be removed. + * @read: A pointer to a function that fills in a given DMA chain such that + * a page read will pass through the owning ECC. + * @write: A pointer to a function that fills in a given DMA chain such that + * a page write will pass through the owning ECC. + * @stat: A pointer to a function that reports on ECC statistics for + * the preceding read operation. + */ + +struct gpmi_ecc_descriptor { + char name[40]; + struct list_head list; + int (*setup)(void *ctx, int index, int writesize, int oobsize); + int (*reset)(void *ctx, int index); + int (*read)(void *ctx, int index, + struct mxs_dma_desc *chain[], unsigned channel, + dma_addr_t page, dma_addr_t oob); + int (*write)(void *ctx, int index, + struct mxs_dma_desc *chain[], unsigned channel, + dma_addr_t page, dma_addr_t oob); + int (*stat)(void *ctx, int index, struct mtd_ecc_stats *r); +}; + +/* ECC descriptor management. */ + +struct gpmi_ecc_descriptor *gpmi_ecc_find(char *name); +void gpmi_ecc_add(struct gpmi_ecc_descriptor *chip); +void gpmi_ecc_remove(struct gpmi_ecc_descriptor *chip); + +/* Housecleaning functions for the ECC hardware blocks. */ + +int bch_init(void); +int ecc8_init(void); +void bch_exit(void); +void ecc8_exit(void); + +/** + * struct gpmi_nand_data - GPMI driver per-device data structure. + * + * @dev: A pointer to the owning struct device. + * @gpd: GPMI-specific platform data. + * @io_base: The base I/O address of of the GPMI registers. + * @clk: A pointer to the structure that represents the GPMI + * clock. + * @irq: The GPMI interrupt request number. + * @inactivity_timer: A pointer to a timer the driver uses to shut itself + * down after periods of inactivity. + * @self_suspended: Indicates the driver suspended itself, rather than + * being suspended by higher layers of software. This is + * important because it effects how the driver wakes + * itself back up. + * @use_count: Used within the driver to hold off suspension until + * all operations are complete. + * @regulator: A pointer to the structure that represents the + * power regulator supplying power to the GPMI. + * @reg_uA: The GPMI current limit, in uA. + * @ignorebad: Forces the driver to report that all blocks are good. + * @bbt: Used to save a pointer to the in-memory NAND Flash MTD + * Bad Block Table if the "ignorebad" flag is turned on + * through the corresponding sysfs node. + * @mtd: The data structure that represents this NAND Flash + * medium to MTD. + * @nand: The data structure that represents this NAND Flash + * medium to the MTD NAND Flash system. + * @device_info Detailed information about the NAND Flash device. + * @partitions: A pointer to an array of partition descriptions + * collected from the platform. If this member is NULL, + * then no such partitions were given. + * @partition_count: The number of elements in the partitions array. + * @done: A struct completion used to manage GPMI interrupts. + * @cmd_buffer: + * @cmd_buffer_handle: + * @cmd_buffer_size: + * @cmd_buffer_sz: The number of command and address bytes queued up, + * waiting for transmission to the NAND Flash. + * @write_buffer: + * @write_buffer_handle: + * @write_buffer_size: + * @read_buffer: + * @read_buffer_handle: + * @data_buffer: + * @data_buffer_handle: + * @data_buffer_size: + * @oob_buffer: + * @oob_buffer_handle: + * @oob_buffer_size: + * @verify_buffer: + * @dma_descriptors: An array of DMA descriptors used in I/O operations. + * @chips: An array of data structures, one for each physical + * chip. + * @cchip: A pointer to the element within the chips array that + * represents the currently selected chip. + * @selected_chip: The currently selectd chip number, or -1 if no chip + * is selected. + * @hwecc_type_read: + * @hwecc_type_write: + * @hwecc: Never used. + * @ecc_oob_bytes: The number of ECC bytes covering the OOB bytes alone. + * @oob_free: The total number of OOB bytes. + * @transcribe_bbmark: Used by the bad block management code to indicate + * that the medium is in common format and the bad block + * marks must be transcribed. + * @timing: The current timings installed in the hardware. + * @saved_command: Used to "hook" the NAND Flash MTD default + * implementation for the cmdfunc fuction pointer. + * @raw_oob_mode: + * @saved_read_oob: Used to "hook" the NAND Flash MTD interface function + * for the MTD read_oob fuction pointer. + * @saved_write_oob: Used to "hook" the NAND Flash MTD interface function + * for the MTD write_oob fuction pointer. + * @hc: A pointer to a structure that represents the ECC + * in use. + */ + +struct gpmi_nand_data { + + struct platform_device *dev; + struct gpmi_platform_data *gpd; + + void __iomem *io_base; + struct clk *clk; + int irq; + struct timer_list timer; + int self_suspended; + int use_count; + struct regulator *regulator; + int reg_uA; + + int ignorebad; + void *bbt; + + struct mtd_info mtd; + struct nand_chip nand; + + struct nand_device_info device_info; + +#if defined(CONFIG_MTD_PARTITIONS) && defined(CONFIG_MTD_CONCAT) + struct mtd_info *general_use_mtd; + struct mtd_partition *partitions; + unsigned partition_count; +#endif + + struct completion done; + + u8 *cmd_buffer; + dma_addr_t cmd_buffer_handle; + int cmd_buffer_size, cmd_buffer_sz; + + u8 *write_buffer; + dma_addr_t write_buffer_handle; + int write_buffer_size; + u8 *read_buffer; /* point in write_buffer */ + dma_addr_t read_buffer_handle; + + u8 *data_buffer; + dma_addr_t data_buffer_handle; + int data_buffer_size; + + u8 *oob_buffer; + dma_addr_t oob_buffer_handle; + int oob_buffer_size; + + void *verify_buffer; + + struct mxs_dma_desc *dma_descriptors[DMA_DESCRIPTOR_COUNT]; + + struct nchip { + int cs; + unsigned dma_ch; + struct mxs_dma_desc *d[GPMI_DMA_MAX_CHAIN]; + } chips[GPMI_MAX_CHIPS]; + struct nchip *cchip; + int selected_chip; + + int hwecc; + + int ecc_oob_bytes, oob_free; + + struct gpmi_nand_timing timing; + + void (*saved_command)(struct mtd_info *mtd, unsigned int command, + int column, int page_addr); + + int raw_oob_mode; + int (*saved_read_oob)(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops); + int (*saved_write_oob)(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops); + + struct gpmi_ecc_descriptor *hc; + +}; + +extern struct gpmi_nand_timing gpmi_safe_timing; + +/** + * struct gpmi_ncb - + * + * @fingerprint1: + * @timing: + * @pagesize: + * @page_plus_oob_size: + * @sectors_per_block: + * @sector_in_page_mask: + * @sector_to_page_shift: + * @num_nands: + * @fingerprint2: + */ + +struct gpmi_fcb { + u32 fingerprint1; + struct gpmi_nand_timing timing; + u32 pagesize; + u32 page_plus_oob_size; + u32 sectors_per_block; + u32 sector_in_page_mask; + u32 sector_to_page_shift; + u32 num_nands; + u32 reserved[3]; + u32 fingerprint2; /* offset 0x2C */ +}; + +/** + * struct gpmi_ldlb - + * + * @fingerprint1: + * @major: + * @minor: + * @sub: + * @nand_bitmap: + * @fingerprint2: + * @fw: + * @fw_starting_nand: + * @fw_starting_sector: + * @fw_sector_stride: + * @fw_sectors_total: + * @fw_major: + * @fw_minor: + * @fw_sub: + * @fw_reserved: + * @bbt_blk: + * @bbt_blk_backup: + */ + +struct gpmi_ldlb { + u32 fingerprint1; + u16 major, minor, sub, reserved; + u32 nand_bitmap; + u32 reserved1[7]; + u32 fingerprint2; + struct { + u32 fw_starting_nand; + u32 fw_starting_sector; + u32 fw_sector_stride; + u32 fw_sectors_total; + } fw[2]; + u16 fw_major, fw_minor, fw_sub, fw_reserved; + u32 bbt_blk; + u32 bbt_blk_backup; +}; + +static inline void gpmi_block_mark_as(struct nand_chip *chip, + int block, int mark) +{ + u32 o; + int shift = (block & 0x03) << 1, + index = block >> 2; + + if (chip->bbt) { + mark &= 0x03; + + o = chip->bbt[index]; + o &= ~(0x03 << shift); + o |= (mark << shift); + chip->bbt[index] = o; + } +} + +static inline int gpmi_block_badness(struct nand_chip *chip, int block) +{ + u32 o; + int shift = (block & 0x03) << 1, + index = block >> 2; + + if (chip->bbt) { + o = (chip->bbt[index] >> shift) & 0x03; + pr_debug("%s: block = %d, o = %d\n", __func__, block, o); + return o; + } + return -1; +} + +#ifdef CONFIG_STMP3XXX_UNIQUE_ID +int __init gpmi_uid_init(const char *name, struct mtd_info *mtd, + u_int32_t start, u_int32_t size); +void gpmi_uid_remove(const char *name); +#else +#define gpmi_uid_init(name, mtd, start, size) +#define gpmi_uid_remove(name) +#endif + +#endif |