Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 1 | /* |
| 2 | * Freescale GPMI NAND Flash Driver |
| 3 | * |
| 4 | * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. |
| 5 | * Copyright (C) 2008 Embedded Alley Solutions, Inc. |
| 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License as published by |
| 9 | * the Free Software Foundation; either version 2 of the License, or |
| 10 | * (at your option) any later version. |
| 11 | * |
| 12 | * This program is distributed in the hope that it will be useful, |
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | * GNU General Public License for more details. |
| 16 | */ |
| 17 | #ifndef __DRIVERS_MTD_NAND_GPMI_NAND_H |
| 18 | #define __DRIVERS_MTD_NAND_GPMI_NAND_H |
| 19 | |
| 20 | #include <linux/mtd/nand.h> |
| 21 | #include <linux/platform_device.h> |
| 22 | #include <linux/dma-mapping.h> |
Shawn Guo | 5fac0e1 | 2013-02-26 11:44:28 +0800 | [diff] [blame^] | 23 | #include <linux/dmaengine.h> |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 24 | |
Huang Shijie | ff50617 | 2012-07-02 21:39:32 -0400 | [diff] [blame] | 25 | #define GPMI_CLK_MAX 5 /* MX6Q needs five clocks */ |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 26 | struct resources { |
Huang Shijie | 513d57e | 2012-07-17 14:14:02 +0800 | [diff] [blame] | 27 | void __iomem *gpmi_regs; |
| 28 | void __iomem *bch_regs; |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 29 | unsigned int bch_low_interrupt; |
| 30 | unsigned int bch_high_interrupt; |
| 31 | unsigned int dma_low_channel; |
| 32 | unsigned int dma_high_channel; |
Huang Shijie | ff50617 | 2012-07-02 21:39:32 -0400 | [diff] [blame] | 33 | struct clk *clock[GPMI_CLK_MAX]; |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 34 | }; |
| 35 | |
| 36 | /** |
| 37 | * struct bch_geometry - BCH geometry description. |
| 38 | * @gf_len: The length of Galois Field. (e.g., 13 or 14) |
| 39 | * @ecc_strength: A number that describes the strength of the ECC |
| 40 | * algorithm. |
| 41 | * @page_size: The size, in bytes, of a physical page, including |
| 42 | * both data and OOB. |
| 43 | * @metadata_size: The size, in bytes, of the metadata. |
| 44 | * @ecc_chunk_size: The size, in bytes, of a single ECC chunk. Note |
| 45 | * the first chunk in the page includes both data and |
| 46 | * metadata, so it's a bit larger than this value. |
| 47 | * @ecc_chunk_count: The number of ECC chunks in the page, |
| 48 | * @payload_size: The size, in bytes, of the payload buffer. |
| 49 | * @auxiliary_size: The size, in bytes, of the auxiliary buffer. |
| 50 | * @auxiliary_status_offset: The offset into the auxiliary buffer at which |
| 51 | * the ECC status appears. |
| 52 | * @block_mark_byte_offset: The byte offset in the ECC-based page view at |
| 53 | * which the underlying physical block mark appears. |
| 54 | * @block_mark_bit_offset: The bit offset into the ECC-based page view at |
| 55 | * which the underlying physical block mark appears. |
| 56 | */ |
| 57 | struct bch_geometry { |
| 58 | unsigned int gf_len; |
| 59 | unsigned int ecc_strength; |
| 60 | unsigned int page_size; |
| 61 | unsigned int metadata_size; |
| 62 | unsigned int ecc_chunk_size; |
| 63 | unsigned int ecc_chunk_count; |
| 64 | unsigned int payload_size; |
| 65 | unsigned int auxiliary_size; |
| 66 | unsigned int auxiliary_status_offset; |
| 67 | unsigned int block_mark_byte_offset; |
| 68 | unsigned int block_mark_bit_offset; |
| 69 | }; |
| 70 | |
| 71 | /** |
| 72 | * struct boot_rom_geometry - Boot ROM geometry description. |
| 73 | * @stride_size_in_pages: The size of a boot block stride, in pages. |
| 74 | * @search_area_stride_exponent: The logarithm to base 2 of the size of a |
| 75 | * search area in boot block strides. |
| 76 | */ |
| 77 | struct boot_rom_geometry { |
| 78 | unsigned int stride_size_in_pages; |
| 79 | unsigned int search_area_stride_exponent; |
| 80 | }; |
| 81 | |
| 82 | /* DMA operations types */ |
| 83 | enum dma_ops_type { |
| 84 | DMA_FOR_COMMAND = 1, |
| 85 | DMA_FOR_READ_DATA, |
| 86 | DMA_FOR_WRITE_DATA, |
| 87 | DMA_FOR_READ_ECC_PAGE, |
| 88 | DMA_FOR_WRITE_ECC_PAGE |
| 89 | }; |
| 90 | |
| 91 | /** |
| 92 | * struct nand_timing - Fundamental timing attributes for NAND. |
| 93 | * @data_setup_in_ns: The data setup time, in nanoseconds. Usually the |
| 94 | * maximum of tDS and tWP. A negative value |
| 95 | * indicates this characteristic isn't known. |
| 96 | * @data_hold_in_ns: The data hold time, in nanoseconds. Usually the |
| 97 | * maximum of tDH, tWH and tREH. A negative value |
| 98 | * indicates this characteristic isn't known. |
| 99 | * @address_setup_in_ns: The address setup time, in nanoseconds. Usually |
| 100 | * the maximum of tCLS, tCS and tALS. A negative |
| 101 | * value indicates this characteristic isn't known. |
| 102 | * @gpmi_sample_delay_in_ns: A GPMI-specific timing parameter. A negative value |
| 103 | * indicates this characteristic isn't known. |
| 104 | * @tREA_in_ns: tREA, in nanoseconds, from the data sheet. A |
| 105 | * negative value indicates this characteristic isn't |
| 106 | * known. |
| 107 | * @tRLOH_in_ns: tRLOH, in nanoseconds, from the data sheet. A |
| 108 | * negative value indicates this characteristic isn't |
| 109 | * known. |
| 110 | * @tRHOH_in_ns: tRHOH, in nanoseconds, from the data sheet. A |
| 111 | * negative value indicates this characteristic isn't |
| 112 | * known. |
| 113 | */ |
| 114 | struct nand_timing { |
| 115 | int8_t data_setup_in_ns; |
| 116 | int8_t data_hold_in_ns; |
| 117 | int8_t address_setup_in_ns; |
| 118 | int8_t gpmi_sample_delay_in_ns; |
| 119 | int8_t tREA_in_ns; |
| 120 | int8_t tRLOH_in_ns; |
| 121 | int8_t tRHOH_in_ns; |
| 122 | }; |
| 123 | |
| 124 | struct gpmi_nand_data { |
Huang Shijie | 995fbbf | 2012-09-13 14:57:59 +0800 | [diff] [blame] | 125 | /* flags */ |
| 126 | #define GPMI_ASYNC_EDO_ENABLED (1 << 0) |
Huang Shijie | 9c95f11 | 2012-09-13 14:58:00 +0800 | [diff] [blame] | 127 | #define GPMI_TIMING_INIT_OK (1 << 1) |
Huang Shijie | 995fbbf | 2012-09-13 14:57:59 +0800 | [diff] [blame] | 128 | int flags; |
| 129 | |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 130 | /* System Interface */ |
| 131 | struct device *dev; |
| 132 | struct platform_device *pdev; |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 133 | |
| 134 | /* Resources */ |
| 135 | struct resources resources; |
| 136 | |
| 137 | /* Flash Hardware */ |
| 138 | struct nand_timing timing; |
Huang Shijie | 995fbbf | 2012-09-13 14:57:59 +0800 | [diff] [blame] | 139 | int timing_mode; |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 140 | |
| 141 | /* BCH */ |
| 142 | struct bch_geometry bch_geometry; |
| 143 | struct completion bch_done; |
| 144 | |
| 145 | /* NAND Boot issue */ |
| 146 | bool swap_block_mark; |
| 147 | struct boot_rom_geometry rom_geometry; |
| 148 | |
| 149 | /* MTD / NAND */ |
| 150 | struct nand_chip nand; |
| 151 | struct mtd_info mtd; |
| 152 | |
| 153 | /* General-use Variables */ |
| 154 | int current_chip; |
| 155 | unsigned int command_length; |
| 156 | |
| 157 | /* passed from upper layer */ |
| 158 | uint8_t *upper_buf; |
| 159 | int upper_len; |
| 160 | |
| 161 | /* for DMA operations */ |
| 162 | bool direct_dma_map_ok; |
| 163 | |
| 164 | struct scatterlist cmd_sgl; |
| 165 | char *cmd_buffer; |
| 166 | |
| 167 | struct scatterlist data_sgl; |
| 168 | char *data_buffer_dma; |
| 169 | |
| 170 | void *page_buffer_virt; |
| 171 | dma_addr_t page_buffer_phys; |
| 172 | unsigned int page_buffer_size; |
| 173 | |
| 174 | void *payload_virt; |
| 175 | dma_addr_t payload_phys; |
| 176 | |
| 177 | void *auxiliary_virt; |
| 178 | dma_addr_t auxiliary_phys; |
| 179 | |
| 180 | /* DMA channels */ |
| 181 | #define DMA_CHANS 8 |
| 182 | struct dma_chan *dma_chans[DMA_CHANS]; |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 183 | enum dma_ops_type last_dma_type; |
| 184 | enum dma_ops_type dma_type; |
| 185 | struct completion dma_done; |
| 186 | |
| 187 | /* private */ |
| 188 | void *private; |
| 189 | }; |
| 190 | |
| 191 | /** |
| 192 | * struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters. |
| 193 | * @data_setup_in_cycles: The data setup time, in cycles. |
| 194 | * @data_hold_in_cycles: The data hold time, in cycles. |
| 195 | * @address_setup_in_cycles: The address setup time, in cycles. |
Huang Shijie | ddab383 | 2012-09-13 14:57:54 +0800 | [diff] [blame] | 196 | * @device_busy_timeout: The timeout waiting for NAND Ready/Busy, |
| 197 | * this value is the number of cycles multiplied |
| 198 | * by 4096. |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 199 | * @use_half_periods: Indicates the clock is running slowly, so the |
| 200 | * NFC DLL should use half-periods. |
| 201 | * @sample_delay_factor: The sample delay factor. |
Huang Shijie | d37e02d | 2012-09-13 14:57:56 +0800 | [diff] [blame] | 202 | * @wrn_dly_sel: The delay on the GPMI write strobe. |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 203 | */ |
| 204 | struct gpmi_nfc_hardware_timing { |
Huang Shijie | ddab383 | 2012-09-13 14:57:54 +0800 | [diff] [blame] | 205 | /* for HW_GPMI_TIMING0 */ |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 206 | uint8_t data_setup_in_cycles; |
| 207 | uint8_t data_hold_in_cycles; |
| 208 | uint8_t address_setup_in_cycles; |
Huang Shijie | ddab383 | 2012-09-13 14:57:54 +0800 | [diff] [blame] | 209 | |
| 210 | /* for HW_GPMI_TIMING1 */ |
| 211 | uint16_t device_busy_timeout; |
| 212 | #define GPMI_DEFAULT_BUSY_TIMEOUT 0x500 /* default busy timeout value.*/ |
| 213 | |
| 214 | /* for HW_GPMI_CTRL1 */ |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 215 | bool use_half_periods; |
| 216 | uint8_t sample_delay_factor; |
Huang Shijie | d37e02d | 2012-09-13 14:57:56 +0800 | [diff] [blame] | 217 | uint8_t wrn_dly_sel; |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 218 | }; |
| 219 | |
| 220 | /** |
| 221 | * struct timing_threshod - Timing threshold |
| 222 | * @max_data_setup_cycles: The maximum number of data setup cycles that |
| 223 | * can be expressed in the hardware. |
| 224 | * @internal_data_setup_in_ns: The time, in ns, that the NFC hardware requires |
| 225 | * for data read internal setup. In the Reference |
| 226 | * Manual, see the chapter "High-Speed NAND |
| 227 | * Timing" for more details. |
| 228 | * @max_sample_delay_factor: The maximum sample delay factor that can be |
| 229 | * expressed in the hardware. |
| 230 | * @max_dll_clock_period_in_ns: The maximum period of the GPMI clock that the |
| 231 | * sample delay DLL hardware can possibly work |
| 232 | * with (the DLL is unusable with longer periods). |
| 233 | * If the full-cycle period is greater than HALF |
| 234 | * this value, the DLL must be configured to use |
| 235 | * half-periods. |
| 236 | * @max_dll_delay_in_ns: The maximum amount of delay, in ns, that the |
| 237 | * DLL can implement. |
| 238 | * @clock_frequency_in_hz: The clock frequency, in Hz, during the current |
| 239 | * I/O transaction. If no I/O transaction is in |
| 240 | * progress, this is the clock frequency during |
| 241 | * the most recent I/O transaction. |
| 242 | */ |
| 243 | struct timing_threshod { |
| 244 | const unsigned int max_chip_count; |
| 245 | const unsigned int max_data_setup_cycles; |
| 246 | const unsigned int internal_data_setup_in_ns; |
| 247 | const unsigned int max_sample_delay_factor; |
| 248 | const unsigned int max_dll_clock_period_in_ns; |
| 249 | const unsigned int max_dll_delay_in_ns; |
| 250 | unsigned long clock_frequency_in_hz; |
| 251 | |
| 252 | }; |
| 253 | |
| 254 | /* Common Services */ |
| 255 | extern int common_nfc_set_geometry(struct gpmi_nand_data *); |
| 256 | extern struct dma_chan *get_dma_chan(struct gpmi_nand_data *); |
| 257 | extern void prepare_data_dma(struct gpmi_nand_data *, |
| 258 | enum dma_data_direction dr); |
| 259 | extern int start_dma_without_bch_irq(struct gpmi_nand_data *, |
| 260 | struct dma_async_tx_descriptor *); |
| 261 | extern int start_dma_with_bch_irq(struct gpmi_nand_data *, |
| 262 | struct dma_async_tx_descriptor *); |
| 263 | |
| 264 | /* GPMI-NAND helper function library */ |
| 265 | extern int gpmi_init(struct gpmi_nand_data *); |
Huang Shijie | 995fbbf | 2012-09-13 14:57:59 +0800 | [diff] [blame] | 266 | extern int gpmi_extra_init(struct gpmi_nand_data *); |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 267 | extern void gpmi_clear_bch(struct gpmi_nand_data *); |
| 268 | extern void gpmi_dump_info(struct gpmi_nand_data *); |
| 269 | extern int bch_set_geometry(struct gpmi_nand_data *); |
| 270 | extern int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip); |
| 271 | extern int gpmi_send_command(struct gpmi_nand_data *); |
| 272 | extern void gpmi_begin(struct gpmi_nand_data *); |
| 273 | extern void gpmi_end(struct gpmi_nand_data *); |
| 274 | extern int gpmi_read_data(struct gpmi_nand_data *); |
| 275 | extern int gpmi_send_data(struct gpmi_nand_data *); |
| 276 | extern int gpmi_send_page(struct gpmi_nand_data *, |
| 277 | dma_addr_t payload, dma_addr_t auxiliary); |
| 278 | extern int gpmi_read_page(struct gpmi_nand_data *, |
| 279 | dma_addr_t payload, dma_addr_t auxiliary); |
| 280 | |
| 281 | /* BCH : Status Block Completion Codes */ |
| 282 | #define STATUS_GOOD 0x00 |
| 283 | #define STATUS_ERASED 0xff |
| 284 | #define STATUS_UNCORRECTABLE 0xfe |
| 285 | |
Huang Shijie | 92d0e09 | 2013-01-29 09:23:38 +0800 | [diff] [blame] | 286 | /* BCH's bit correction capability. */ |
| 287 | #define MXS_ECC_STRENGTH_MAX 20 /* mx23 and mx28 */ |
| 288 | #define MX6_ECC_STRENGTH_MAX 40 |
| 289 | |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 290 | /* Use the platform_id to distinguish different Archs. */ |
Huang Shijie | e10db1f | 2012-05-04 21:42:05 -0400 | [diff] [blame] | 291 | #define IS_MX23 0x0 |
| 292 | #define IS_MX28 0x1 |
Huang Shijie | 9013bb4 | 2012-05-04 21:42:06 -0400 | [diff] [blame] | 293 | #define IS_MX6Q 0x2 |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 294 | #define GPMI_IS_MX23(x) ((x)->pdev->id_entry->driver_data == IS_MX23) |
| 295 | #define GPMI_IS_MX28(x) ((x)->pdev->id_entry->driver_data == IS_MX28) |
Huang Shijie | 9013bb4 | 2012-05-04 21:42:06 -0400 | [diff] [blame] | 296 | #define GPMI_IS_MX6Q(x) ((x)->pdev->id_entry->driver_data == IS_MX6Q) |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 297 | #endif |