/* * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface) * * Author: dmitry pervushin * * 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 #include #include #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; unsigned last_write_page_address; #if defined(CONFIG_MTD_PARTITIONS) 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