summaryrefslogtreecommitdiff
path: root/drivers/mtd/nand/gpmi/gpmi.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/gpmi/gpmi.h')
-rw-r--r--drivers/mtd/nand/gpmi/gpmi.h291
1 files changed, 291 insertions, 0 deletions
diff --git a/drivers/mtd/nand/gpmi/gpmi.h b/drivers/mtd/nand/gpmi/gpmi.h
new file mode 100644
index 000000000000..99c26988f370
--- /dev/null
+++ b/drivers/mtd/nand/gpmi/gpmi.h
@@ -0,0 +1,291 @@
+/*
+ * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface)
+ *
+ * Author: dmitry pervushin <dimka@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * 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 <mach/gpmi.h>
+#include <mach/regs-gpmi.h>
+#include <mach/regs-apbh.h>
+#ifdef CONFIG_MTD_NAND_GPMI_BCH
+#include <mach/regs-bch.h>
+#endif
+#include <mach/regs-ecc8.h>
+
+#include "gpmi-hamming-22-16.h"
+
+#define GPMI_ECC4_WR \
+ (BM_GPMI_ECCCTRL_ENABLE_ECC | \
+ BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_4_BIT))
+#define GPMI_ECC4_RD \
+ (BM_GPMI_ECCCTRL_ENABLE_ECC | \
+ BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__DECODE_4_BIT))
+#define GPMI_ECC8_WR \
+ (BM_GPMI_ECCCTRL_ENABLE_ECC | \
+ BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_8_BIT))
+#define GPMI_ECC8_RD \
+ (BM_GPMI_ECCCTRL_ENABLE_ECC | \
+ BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__DECODE_8_BIT))
+
+/* fingerprints of BCB that can be found on STMP-formatted flash */
+#define SIG1 "STMP"
+#define SIG_NCB "NCB "
+#define SIG_LDLB "LDLB"
+#define SIG_DBBT "DBBT"
+#define SIG_SIZE 4
+
+struct gpmi_nand_timing {
+ u8 data_setup;
+ u8 data_hold;
+ u8 address_setup;
+ u8 dsample_time;
+};
+
+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);
+void gpmi_set_timings(struct platform_device *pdev,
+ struct gpmi_nand_timing *tm);
+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_hwecc_chip {
+ 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 stmp3xxx_dma_descriptor *chain,
+ dma_addr_t error,
+ dma_addr_t page, dma_addr_t oob);
+ int (*write)(void *ctx, int index,
+ struct stmp3xxx_dma_descriptor *chain,
+ dma_addr_t error,
+ dma_addr_t page, dma_addr_t oob);
+ int (*stat)(void *ctx, int index, struct mtd_ecc_stats *r);
+};
+
+/* HWECC chips */
+struct gpmi_hwecc_chip *gpmi_hwecc_chip_find(char *name);
+void gpmi_hwecc_chip_add(struct gpmi_hwecc_chip *chip);
+void gpmi_hwecc_chip_remove(struct gpmi_hwecc_chip *chip);
+int bch_init(void);
+int ecc8_init(void);
+void bch_exit(void);
+void ecc8_exit(void);
+
+
+struct gpmi_nand_data {
+ 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 nand_chip chip;
+ struct mtd_info mtd;
+ struct platform_device *dev;
+
+#ifdef CONFIG_MTD_PARTITIONS
+ int nr_parts;
+ struct mtd_partition
+ *parts;
+#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 nchip {
+ unsigned dma_ch;
+ struct stmp37xx_circ_dma_chain chain;
+ struct stmp3xxx_dma_descriptor d[GPMI_DMA_MAX_CHAIN];
+ struct stmp3xxx_dma_descriptor error;
+ int cs;
+ } chips[GPMI_MAX_CHIPS];
+ struct nchip *cchip;
+ int selected_chip;
+
+ unsigned hwecc_type_read, hwecc_type_write;
+ int hwecc;
+
+ int ecc_oob_bytes, oob_free;
+
+ int transcribe_bbmark;
+ 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_hwecc_chip *hc;
+
+ int numchips;
+ int custom_partitions;
+ struct mtd_info *masters[GPMI_MAX_CHIPS];
+ struct mtd_partition chip_partitions[GPMI_MAX_CHIPS];
+ int n_concat;
+ struct mtd_info *concat[GPMI_MAX_CHIPS];
+ struct mtd_info *concat_mtd;
+};
+
+extern struct gpmi_nand_timing gpmi_safe_timing;
+
+struct gpmi_ncb {
+ 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 {
+ 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