/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Platform header files. */ #include #include #include #include /* 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