aboutsummaryrefslogtreecommitdiff
path: root/drivers/mtd/nand/gpmi1/gpmi.h
diff options
context:
space:
mode:
authorPatrick Turley <patrick.turley@freescale.com>2010-02-24 11:56:27 -0600
committerFrank Li <Frank.Li@freescale.com>2010-03-16 12:37:46 +0800
commita178d9bf9235c56fa960f2f90de8453ec17756d1 (patch)
tree464d6c7ed5a452ef01257eb54ee7e3ea1a83df0d /drivers/mtd/nand/gpmi1/gpmi.h
parent77e3d6e4430166ee5cdcb1352aa7b13fd32ac095 (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.h456
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