diff options
Diffstat (limited to 'drivers/mtd/nand/gpmi-nfc/gpmi-nfc.h')
-rw-r--r-- | drivers/mtd/nand/gpmi-nfc/gpmi-nfc.h | 643 |
1 files changed, 643 insertions, 0 deletions
diff --git a/drivers/mtd/nand/gpmi-nfc/gpmi-nfc.h b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc.h new file mode 100644 index 000000000000..6f14b73dd93d --- /dev/null +++ b/drivers/mtd/nand/gpmi-nfc/gpmi-nfc.h @@ -0,0 +1,643 @@ +/* + * Freescale GPMI NFC NAND Flash Driver + * + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * Copyright (C) 2008 Embedded Alley Solutions, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __DRIVERS_MTD_NAND_GPMI_NFC_H +#define __DRIVERS_MTD_NAND_GPMI_NFC_H + +/* Linux header files. */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/concat.h> +#include <linux/gpmi-nfc.h> +#include <asm/sizes.h> + +/* Platform header files. */ + +#include <mach/system.h> +#include <mach/dmaengine.h> +#include <mach/device.h> +#include <mach/clock.h> + +/* Driver header files. */ + +#include "../nand_device_info.h" + +/* + *------------------------------------------------------------------------------ + * Fundamental Macros + *------------------------------------------------------------------------------ + */ + +/* Define this macro to enable detailed information messages. */ + +#define DETAILED_INFO + +/* Define this macro to enable event reporting. */ + +/*#define EVENT_REPORTING*/ + +/* + *------------------------------------------------------------------------------ + * Fundamental Data Structures + *------------------------------------------------------------------------------ + */ + +/** + * struct resources - The collection of resources the driver needs. + * + * @gpmi_regs: A pointer to the GPMI registers. + * @bch_regs: A pointer to the BCH registers. + * @bch_interrupt: The BCH interrupt number. + * @dma_low_channel: The low DMA channel. + * @dma_high_channel: The high DMA channel. + * @dma_interrupt: The DMA interrupt number. + * @clock: A pointer to the struct clk for the NFC's clock. + */ + +struct resources { + void *gpmi_regs; + void *bch_regs; + unsigned int bch_interrupt; + unsigned int dma_low_channel; + unsigned int dma_high_channel; + unsigned int dma_interrupt; + struct clk *clock; +}; + +/** + * struct mil - State for the MTD Interface Layer. + * + * @nand: The NAND Flash MTD data structure that represents + * the NAND Flash medium. + * @mtd: The MTD data structure that represents the NAND + * Flash medium. + * @oob_layout: A structure that describes how bytes are laid out + * in the OOB. + * @general_use_mtd: A pointer to an MTD we export for general use. + * This *may* simply be a pointer to the mtd field, if + * we've been instructed NOT to protect the boot + * areas. + * @partitions: A pointer to a set of partitions applied to the + * general use MTD. + * @partition_count: The number of partitions. + * @ubi_partition_memory: If not NULL, a block of memory used to create a set + * of partitions that help with the problem that UBI + * can't handle an MTD larger than 2GiB. + * @current_chip: The chip currently selected by the NAND Fash MTD + * code. A negative value indicates that no chip is + * selected. + * @command_length: The length of the command that appears in the + * command buffer (see cmd_virt, below). + * @inject_ecc_error: Indicates the driver should inject a "fake" ECC + * error into the next read operation that uses ECC. + * User space programs can set this value through the + * sysfs node of the same name. If this value is less + * than zero, the driver will inject an uncorrectable + * ECC error. If this value is greater than zero, the + * driver will inject that number of correctable + * errors, capped by the maximum possible number of + * errors that could appear in a single read. + * @ignore_bad_block_marks: Indicates we are ignoring bad block marks. + * @saved_bbt: A saved pointer to the in-memory NAND Flash MTD bad + * block table. See show_device_ignorebad() for more + * details. + * @raw_oob_mode: Indicates the OOB is to be read/written in "raw" + * mode. See mil_ecc_read_oob() for details. + * @hooked_read_oob: A pointer to the ecc.read_oob() function we + * "hooked." See mil_ecc_read_oob() for details. + * @hooked_write_oob: A pointer to the ecc.write_oob() function pointer + * we "hooked." See mil_ecc_read_oob() for details. + * @marking_a_bad_block: Indicates the caller is marking a bad block. See + * mil_ecc_write_oob() for details. + * @hooked_block_markbad: A pointer to the block_markbad() function we + * we "hooked." See mil_ecc_write_oob() for details. + * @cmd_virt: A pointer to a DMA-coherent buffer in which we + * accumulate command bytes before we give them to the + * NFC layer. See mil_cmd_ctrl() for more details. + * @cmd_phys: The physical address for the cmd_virt buffer. + * @page_buffer_virt: A pointer to a DMA-coherent buffer we use for + * reading and writing pages. This buffer includes + * space for both the payload data and the auxiliary + * data (including status bytes, but not syndrome + * bytes). + * @page_buffer_phys: The physical address for the page_buffer_virt + * buffer. + * @page_buffer_size: The size of the page buffer. + * @payload_virt: A pointer to a location in the page buffer used + * for payload bytes. The size of this buffer is + * determined by struct nfc_geometry. + * @payload_phys: The physical address for payload_virt. + * @payload_size: The size of the payload area in the page buffer. + * @auxiliary_virt: A pointer to a location in the page buffer used + * for auxiliary bytes. The size of this buffer is + * determined by struct nfc_geometry. + * @auxiliary_phys: The physical address for auxiliary_virt. + * @auxiliary_size: The size of the auxiliary area in the page buffer. + */ + +#define MIL_COMMAND_BUFFER_SIZE (10) + +struct mil { + + /* MTD Data Structures */ + + struct nand_chip nand; + struct mtd_info mtd; + struct nand_ecclayout oob_layout; + + /* Partitioning and Boot Area Protection */ + + struct mtd_info *general_use_mtd; + struct mtd_partition *partitions; + unsigned int partition_count; + void *ubi_partition_memory; + + /* General-use Variables */ + + int current_chip; + unsigned int command_length; + int inject_ecc_error; + int ignore_bad_block_marks; + void *saved_bbt; + + /* MTD Function Pointer Hooks */ + + int raw_oob_mode; + int (*hooked_read_oob)(struct mtd_info *mtd, + loff_t from, struct mtd_oob_ops *ops); + int (*hooked_write_oob)(struct mtd_info *mtd, + loff_t to, struct mtd_oob_ops *ops); + + int marking_a_bad_block; + int (*hooked_block_markbad)(struct mtd_info *mtd, + loff_t ofs); + + /* DMA Buffers */ + + char *cmd_virt; + dma_addr_t cmd_phys; + + void *page_buffer_virt; + dma_addr_t page_buffer_phys; + unsigned int page_buffer_size; + + void *payload_virt; + dma_addr_t payload_phys; + + void *auxiliary_virt; + dma_addr_t auxiliary_phys; + +}; + +/** + * struct physical_geometry - Physical geometry description. + * + * This structure describes the physical geometry of the medium. + * + * @chip_count: The number of chips in the medium. + * @chip_size_in_bytes: The size, in bytes, of a single chip + * (excluding the out-of-band bytes). + * @block_size_in_bytes: The size, in bytes, of a single block + * (excluding the out-of-band bytes). + * @page_data_size_in_bytes: The size, in bytes, of the data area in a + * page (excluding the out-of-band bytes). + * @page_oob_size_in_bytes: The size, in bytes, of the out-of-band area + * in a page. + */ + +struct physical_geometry { + unsigned int chip_count; + uint64_t chip_size_in_bytes; + unsigned int block_size_in_bytes; + unsigned int page_data_size_in_bytes; + unsigned int page_oob_size_in_bytes; +}; + +/** + * struct nfc_geometry - NFC geometry description. + * + * This structure describes the NFC's view of the medium geometry. + * + * @ecc_algorithm: The human-readable name of the ECC algorithm + * (e.g., "Reed-Solomon" or "BCH"). + * @ecc_strength: A number that describes the strength of the ECC + * algorithm. + * @page_size_in_bytes: The size, in bytes, of a physical page, including + * both data and OOB. + * @metadata_size_in_bytes: The size, in bytes, of the metadata. + * @ecc_chunk_size_in_bytes: The size, in bytes, of a single ECC chunk. Note + * the first chunk in the page includes both data and + * metadata, so it's a bit larger than this value. + * @ecc_chunk_count: The number of ECC chunks in the page, + * @payload_size_in_bytes: The size, in bytes, of the payload buffer. + * @auxiliary_size_in_bytes: The size, in bytes, of the auxiliary buffer. + * @auxiliary_status_offset: The offset into the auxiliary buffer at which + * the ECC status appears. + * @block_mark_byte_offset: The byte offset in the ECC-based page view at + * which the underlying physical block mark appears. + * @block_mark_bit_offset: The bit offset into the ECC-based page view at + * which the underlying physical block mark appears. + */ + +struct nfc_geometry { + char *ecc_algorithm; + unsigned int ecc_strength; + unsigned int page_size_in_bytes; + unsigned int metadata_size_in_bytes; + unsigned int ecc_chunk_size_in_bytes; + unsigned int ecc_chunk_count; + unsigned int payload_size_in_bytes; + unsigned int auxiliary_size_in_bytes; + unsigned int auxiliary_status_offset; + unsigned int block_mark_byte_offset; + unsigned int block_mark_bit_offset; +}; + +/** + * struct boot_rom_geometry - Boot ROM geometry description. + * + * This structure encapsulates decisions made by the Boot ROM Helper. + * + * @boot_area_count: The number of boot areas. The first boot area + * appears at the beginning of chip 0, the next + * at the beginning of chip 1, etc. + * @boot_area_size_in_bytes: The size, in bytes, of each boot area. + * @stride_size_in_pages: The size of a boot block stride, in pages. + * @search_area_stride_exponent: The logarithm to base 2 of the size of a + * search area in boot block strides. + */ + +struct boot_rom_geometry { + unsigned int boot_area_count; + unsigned int boot_area_size_in_bytes; + unsigned int stride_size_in_pages; + unsigned int search_area_stride_exponent; +}; + +/** + * struct gpmi_nfc_data - i.MX NFC per-device data. + * + * Note that the "device" managed by this driver represents the NAND Flash + * controller *and* the NAND Flash medium behind it. Thus, the per-device data + * structure has information about the controller, the chips to which it is + * connected, and properties of the medium as a whole. + * + * @dev: A pointer to the owning struct device. + * @pdev: A pointer to the owning struct platform_device. + * @pdata: A pointer to the device's platform data. + * @resources: Information about system resources used by this driver. + * @device_info: A structure that contains detailed information about + * the NAND Flash device. + * @physical_geometry: A description of the medium's physical geometry. + * @nfc: A pointer to a structure that represents the underlying + * NFC hardware. + * @nfc_geometry: A description of the medium geometry as viewed by the + * NFC. + * @rom: A pointer to a structure that represents the underlying + * Boot ROM. + * @rom_geometry: A description of the medium geometry as viewed by the + * Boot ROM. + * @mil: A collection of information used by the MTD Interface + * Layer. + */ + +struct gpmi_nfc_data { + + /* System Interface */ + struct device *dev; + struct platform_device *pdev; + struct gpmi_nfc_platform_data *pdata; + + /* Resources */ + struct resources resources; + + /* Flash Hardware */ + struct nand_device_info device_info; + struct physical_geometry physical_geometry; + + /* NFC HAL */ + struct nfc_hal *nfc; + struct nfc_geometry nfc_geometry; + + /* Boot ROM Helper */ + struct boot_rom_helper *rom; + struct boot_rom_geometry rom_geometry; + + /* MTD Interface Layer */ + struct mil mil; + +}; + +/** + * struct gpmi_nfc_timing - GPMI NFC timing parameters. + * + * This structure contains the fundamental timing attributes for the NAND Flash + * bus and the GPMI NFC hardware. + * + * @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_delay_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_nfc_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_nfc_hardware_timing - GPMI NFC hardware timing parameters. + * + * This structure contains timing information expressed in a form directly + * usable by the GPMI NFC hardware. + * + * @data_setup_in_cycles: The data setup time, in cycles. + * @data_hold_in_cycles: The data hold time, in cycles. + * @address_setup_in_cycles: The address setup time, in cycles. + * @use_half_periods: Indicates the clock is running slowly, so the + * NFC DLL should use half-periods. + * @sample_delay_factor: The sample delay factor. + */ + +struct gpmi_nfc_hardware_timing { + uint8_t data_setup_in_cycles; + uint8_t data_hold_in_cycles; + uint8_t address_setup_in_cycles; + bool use_half_periods; + uint8_t sample_delay_factor; +}; + +/** + * struct nfc_hal - GPMI NFC HAL + * + * This structure embodies an abstract interface to the underlying NFC hardware. + * + * @version: The NFC hardware version. + * @description: A pointer to a human-readable description of + * the NFC hardware. + * @max_chip_count: The maximum number of chips the NFC can + * possibly support (this value is a constant for + * each NFC version). This may *not* be the actual + * number of chips connected. + * @max_data_setup_cycles: The maximum number of data setup cycles that + * can be expressed in the hardware. + * @internal_data_setup_in_ns: The time, in ns, that the NFC hardware requires + * for data read internal setup. In the Reference + * Manual, see the chapter "High-Speed NAND + * Timing" for more details. + * @max_sample_delay_factor: The maximum sample delay factor that can be + * expressed in the hardware. + * @max_dll_clock_period_in_ns: The maximum period of the GPMI clock that the + * sample delay DLL hardware can possibly work + * with (the DLL is unusable with longer periods). + * If the full-cycle period is greater than HALF + * this value, the DLL must be configured to use + * half-periods. + * @max_dll_delay_in_ns: The maximum amount of delay, in ns, that the + * DLL can implement. + * @dma_descriptors: A pool of DMA descriptors. + * @isr_dma_channel: The DMA channel with which the NFC HAL is + * working. We record this here so the ISR knows + * which DMA channel to acknowledge. + * @dma_done: The completion structure used for DMA + * interrupts. + * @bch_done: The completion structure used for BCH + * interrupts. + * @timing: The current timing configuration. + * @clock_frequency_in_hz: The clock frequency, in Hz, during the current + * I/O transaction. If no I/O transaction is in + * progress, this is the clock frequency during + * the most recent I/O transaction. + * @hardware_timing: The hardware timing configuration in effect + * during the current I/O transaction. If no I/O + * transaction is in progress, this is the + * hardware timing configuration during the most + * recent I/O transaction. + * @init: Initializes the NFC hardware and data + * structures. This function will be called after + * everything has been set up for communication + * with the NFC itself, but before the platform + * has set up off-chip communication. Thus, this + * function must not attempt to communicate with + * the NAND Flash hardware. + * @set_geometry: Configures the NFC hardware and data structures + * to match the physical NAND Flash geometry. + * @set_geometry: Configures the NFC hardware and data structures + * to match the physical NAND Flash geometry. + * @set_timing: Configures the NFC hardware and data structures + * to match the given NAND Flash bus timing. + * @get_timing: Returns the the clock frequency, in Hz, and + * the hardware timing configuration during the + * current I/O transaction. If no I/O transaction + * is in progress, this is the timing state during + * the most recent I/O transaction. + * @exit: Shuts down the NFC hardware and data + * structures. This function will be called after + * the platform has shut down off-chip + * communication but while communication with the + * NFC itself still works. + * @clear_bch: Clears a BCH interrupt (intended to be called + * by a more general interrupt handler to do + * device-specific clearing). + * @is_ready: Returns true if the given chip is ready. + * @begin: Begins an interaction with the NFC. This + * function must be called before *any* of the + * following functions so the NFC can prepare + * itself. + * @end: Ends interaction with the NFC. This function + * should be called to give the NFC a chance to, + * among other things, enter a lower-power state. + * @send_command: Sends the given buffer of command bytes. + * @send_data: Sends the given buffer of data bytes. + * @read_data: Reads data bytes into the given buffer. + * @send_page: Sends the given given data and OOB bytes, + * using the ECC engine. + * @read_page: Reads a page through the ECC engine and + * delivers the data and OOB bytes to the given + * buffers. + */ + +#define NFC_DMA_DESCRIPTOR_COUNT (4) + +struct nfc_hal { + + /* Hardware attributes. */ + + const unsigned int version; + const char *description; + const unsigned int max_chip_count; + const unsigned int max_data_setup_cycles; + const unsigned int internal_data_setup_in_ns; + const unsigned int max_sample_delay_factor; + const unsigned int max_dll_clock_period_in_ns; + const unsigned int max_dll_delay_in_ns; + + /* Working variables. */ + + struct mxs_dma_desc *dma_descriptors[NFC_DMA_DESCRIPTOR_COUNT]; + int isr_dma_channel; + struct completion dma_done; + struct completion bch_done; + struct gpmi_nfc_timing timing; + unsigned long clock_frequency_in_hz; + + /* Configuration functions. */ + + int (*init) (struct gpmi_nfc_data *); + int (*set_geometry)(struct gpmi_nfc_data *); + int (*set_timing) (struct gpmi_nfc_data *, + const struct gpmi_nfc_timing *); + void (*get_timing) (struct gpmi_nfc_data *, + unsigned long *clock_frequency_in_hz, + struct gpmi_nfc_hardware_timing *); + void (*exit) (struct gpmi_nfc_data *); + + /* Call these functions to begin and end I/O. */ + + void (*begin) (struct gpmi_nfc_data *); + void (*end) (struct gpmi_nfc_data *); + + /* Call these I/O functions only between begin() and end(). */ + + void (*clear_bch) (struct gpmi_nfc_data *); + int (*is_ready) (struct gpmi_nfc_data *, unsigned chip); + int (*send_command)(struct gpmi_nfc_data *, unsigned chip, + dma_addr_t buffer, unsigned length); + int (*send_data) (struct gpmi_nfc_data *, unsigned chip, + dma_addr_t buffer, unsigned length); + int (*read_data) (struct gpmi_nfc_data *, unsigned chip, + dma_addr_t buffer, unsigned length); + int (*send_page) (struct gpmi_nfc_data *, unsigned chip, + dma_addr_t payload, dma_addr_t auxiliary); + int (*read_page) (struct gpmi_nfc_data *, unsigned chip, + dma_addr_t payload, dma_addr_t auxiliary); +}; + +/** + * struct boot_rom_helper - Boot ROM Helper + * + * This structure embodies the interface to an object that assists the driver + * in making decisions that relate to the Boot ROM. + * + * @version: The Boot ROM version. + * @description: A pointer to a human-readable description of the + * Boot ROM. + * @swap_block_mark: Indicates that the Boot ROM will swap the block + * mark with the first byte of the OOB. + * @set_geometry: Configures the Boot ROM geometry. + * @check_transcription_stamp: Checks for a transcription stamp. This pointer + * is ignored if swap_block_mark is set. + * @write_transcription_stamp: Writes a transcription stamp. This pointer + * is ignored if swap_block_mark is set. + */ + +struct boot_rom_helper { + const unsigned int version; + const char *description; + const int swap_block_mark; + int (*set_geometry) (struct gpmi_nfc_data *); + int (*check_transcription_stamp)(struct gpmi_nfc_data *); + int (*write_transcription_stamp)(struct gpmi_nfc_data *); +}; + +/* + *------------------------------------------------------------------------------ + * External Symbols + *------------------------------------------------------------------------------ + */ + +/* Event Reporting */ + +#if defined(EVENT_REPORTING) + extern void gpmi_nfc_start_event_trace(char *description); + extern void gpmi_nfc_add_event(char *description, int delta); + extern void gpmi_nfc_stop_event_trace(char *description); + extern void gpmi_nfc_dump_event_trace(void); +#else + #define gpmi_nfc_start_event_trace(description) do {} while (0) + #define gpmi_nfc_add_event(description, delta) do {} while (0) + #define gpmi_nfc_stop_event_trace(description) do {} while (0) + #define gpmi_nfc_dump_event_trace() do {} while (0) +#endif + +/* NFC HAL Common Services */ + +extern irqreturn_t gpmi_nfc_bch_isr(int irq, void *cookie); +extern irqreturn_t gpmi_nfc_dma_isr(int irq, void *cookie); +extern int gpmi_nfc_dma_init(struct gpmi_nfc_data *this); +extern void gpmi_nfc_dma_exit(struct gpmi_nfc_data *this); +extern int gpmi_nfc_set_geometry(struct gpmi_nfc_data *this); +extern int gpmi_nfc_dma_go(struct gpmi_nfc_data *this, int dma_channel); +extern int gpmi_nfc_compute_hardware_timing(struct gpmi_nfc_data *this, + struct gpmi_nfc_hardware_timing *hw); + +/* NFC HAL Structures */ + +extern struct nfc_hal gpmi_nfc_hal_v0; +extern struct nfc_hal gpmi_nfc_hal_v1; + +/* Boot ROM Helper Common Services */ + +extern int gpmi_nfc_rom_helper_set_geometry(struct gpmi_nfc_data *this); + +/* Boot ROM Helper Structures */ + +extern struct boot_rom_helper gpmi_nfc_boot_rom_helper_v0; +extern struct boot_rom_helper gpmi_nfc_boot_rom_helper_v1; + +/* MTD Interface Layer */ + +extern int gpmi_nfc_mil_init(struct gpmi_nfc_data *this); +extern void gpmi_nfc_mil_exit(struct gpmi_nfc_data *this); + +#endif |