Fabio Estevam | b04a3fe | 2018-07-07 14:25:20 -0300 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0+ */ |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 2 | /* |
| 3 | * Freescale GPMI NAND Flash Driver |
| 4 | * |
| 5 | * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. |
| 6 | * Copyright (C) 2008 Embedded Alley Solutions, Inc. |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 7 | */ |
| 8 | #ifndef __DRIVERS_MTD_NAND_GPMI_NAND_H |
| 9 | #define __DRIVERS_MTD_NAND_GPMI_NAND_H |
| 10 | |
Boris Brezillon | d4092d7 | 2017-08-04 17:29:10 +0200 | [diff] [blame] | 11 | #include <linux/mtd/rawnand.h> |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 12 | #include <linux/platform_device.h> |
| 13 | #include <linux/dma-mapping.h> |
Shawn Guo | 5fac0e1 | 2013-02-26 11:44:28 +0800 | [diff] [blame] | 14 | #include <linux/dmaengine.h> |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 15 | |
Huang Shijie | ff50617 | 2012-07-02 21:39:32 -0400 | [diff] [blame] | 16 | #define GPMI_CLK_MAX 5 /* MX6Q needs five clocks */ |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 17 | struct resources { |
Huang Shijie | 513d57e | 2012-07-17 14:14:02 +0800 | [diff] [blame] | 18 | void __iomem *gpmi_regs; |
| 19 | void __iomem *bch_regs; |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 20 | unsigned int dma_low_channel; |
| 21 | unsigned int dma_high_channel; |
Huang Shijie | ff50617 | 2012-07-02 21:39:32 -0400 | [diff] [blame] | 22 | struct clk *clock[GPMI_CLK_MAX]; |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 23 | }; |
| 24 | |
| 25 | /** |
| 26 | * struct bch_geometry - BCH geometry description. |
| 27 | * @gf_len: The length of Galois Field. (e.g., 13 or 14) |
| 28 | * @ecc_strength: A number that describes the strength of the ECC |
| 29 | * algorithm. |
| 30 | * @page_size: The size, in bytes, of a physical page, including |
| 31 | * both data and OOB. |
| 32 | * @metadata_size: The size, in bytes, of the metadata. |
| 33 | * @ecc_chunk_size: The size, in bytes, of a single ECC chunk. Note |
| 34 | * the first chunk in the page includes both data and |
| 35 | * metadata, so it's a bit larger than this value. |
| 36 | * @ecc_chunk_count: The number of ECC chunks in the page, |
| 37 | * @payload_size: The size, in bytes, of the payload buffer. |
| 38 | * @auxiliary_size: The size, in bytes, of the auxiliary buffer. |
| 39 | * @auxiliary_status_offset: The offset into the auxiliary buffer at which |
| 40 | * the ECC status appears. |
| 41 | * @block_mark_byte_offset: The byte offset in the ECC-based page view at |
| 42 | * which the underlying physical block mark appears. |
| 43 | * @block_mark_bit_offset: The bit offset into the ECC-based page view at |
| 44 | * which the underlying physical block mark appears. |
| 45 | */ |
| 46 | struct bch_geometry { |
| 47 | unsigned int gf_len; |
| 48 | unsigned int ecc_strength; |
| 49 | unsigned int page_size; |
| 50 | unsigned int metadata_size; |
| 51 | unsigned int ecc_chunk_size; |
| 52 | unsigned int ecc_chunk_count; |
| 53 | unsigned int payload_size; |
| 54 | unsigned int auxiliary_size; |
| 55 | unsigned int auxiliary_status_offset; |
| 56 | unsigned int block_mark_byte_offset; |
| 57 | unsigned int block_mark_bit_offset; |
| 58 | }; |
| 59 | |
| 60 | /** |
| 61 | * struct boot_rom_geometry - Boot ROM geometry description. |
| 62 | * @stride_size_in_pages: The size of a boot block stride, in pages. |
| 63 | * @search_area_stride_exponent: The logarithm to base 2 of the size of a |
| 64 | * search area in boot block strides. |
| 65 | */ |
| 66 | struct boot_rom_geometry { |
| 67 | unsigned int stride_size_in_pages; |
| 68 | unsigned int search_area_stride_exponent; |
| 69 | }; |
| 70 | |
Huang Shijie | 6189ccc | 2014-03-21 18:19:39 +0800 | [diff] [blame] | 71 | enum gpmi_type { |
| 72 | IS_MX23, |
| 73 | IS_MX28, |
Huang Shijie | 91f5498 | 2014-03-27 10:43:22 +0800 | [diff] [blame] | 74 | IS_MX6Q, |
Stefan Agner | b4af694 | 2017-04-21 18:23:35 -0700 | [diff] [blame] | 75 | IS_MX6SX, |
| 76 | IS_MX7D, |
Huang Shijie | 6189ccc | 2014-03-21 18:19:39 +0800 | [diff] [blame] | 77 | }; |
| 78 | |
| 79 | struct gpmi_devdata { |
| 80 | enum gpmi_type type; |
| 81 | int bch_max_ecc_strength; |
| 82 | int max_chain_delay; /* See the async EDO mode */ |
Stefan Agner | 6b7ee72 | 2017-04-21 18:23:34 -0700 | [diff] [blame] | 83 | const char * const *clks; |
| 84 | const int clks_count; |
Huang Shijie | 6189ccc | 2014-03-21 18:19:39 +0800 | [diff] [blame] | 85 | }; |
| 86 | |
Miquel Raynal | 76e1a00 | 2018-03-02 15:38:39 +0100 | [diff] [blame] | 87 | /** |
| 88 | * struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters. |
Miquel Raynal | 76e1a00 | 2018-03-02 15:38:39 +0100 | [diff] [blame] | 89 | * @must_apply_timings: Whether controller timings have already been |
| 90 | * applied or not (useful only while there is |
| 91 | * support for only one chip select) |
| 92 | * @clk_rate: The clock rate that must be used to derive the |
Miquel Raynal | b120612 | 2018-03-02 15:38:40 +0100 | [diff] [blame] | 93 | * following parameters |
| 94 | * @timing0: HW_GPMI_TIMING0 register |
| 95 | * @timing1: HW_GPMI_TIMING1 register |
| 96 | * @ctrl1n: HW_GPMI_CTRL1n register |
Miquel Raynal | 76e1a00 | 2018-03-02 15:38:39 +0100 | [diff] [blame] | 97 | */ |
| 98 | struct gpmi_nfc_hardware_timing { |
Miquel Raynal | 76e1a00 | 2018-03-02 15:38:39 +0100 | [diff] [blame] | 99 | bool must_apply_timings; |
| 100 | unsigned long int clk_rate; |
Miquel Raynal | b120612 | 2018-03-02 15:38:40 +0100 | [diff] [blame] | 101 | u32 timing0; |
| 102 | u32 timing1; |
| 103 | u32 ctrl1n; |
Miquel Raynal | 76e1a00 | 2018-03-02 15:38:39 +0100 | [diff] [blame] | 104 | }; |
| 105 | |
Sascha Hauer | ef347c0 | 2019-05-21 09:06:43 +0200 | [diff] [blame^] | 106 | #define GPMI_MAX_TRANSFERS 8 |
| 107 | |
| 108 | struct gpmi_transfer { |
| 109 | u8 cmdbuf[8]; |
| 110 | struct scatterlist sgl; |
| 111 | enum dma_data_direction direction; |
| 112 | }; |
| 113 | |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 114 | struct gpmi_nand_data { |
Miquel Raynal | 76e1a00 | 2018-03-02 15:38:39 +0100 | [diff] [blame] | 115 | /* Devdata */ |
Huang Shijie | 6189ccc | 2014-03-21 18:19:39 +0800 | [diff] [blame] | 116 | const struct gpmi_devdata *devdata; |
Huang Shijie | 995fbbf | 2012-09-13 14:57:59 +0800 | [diff] [blame] | 117 | |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 118 | /* System Interface */ |
| 119 | struct device *dev; |
| 120 | struct platform_device *pdev; |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 121 | |
| 122 | /* Resources */ |
| 123 | struct resources resources; |
| 124 | |
| 125 | /* Flash Hardware */ |
Miquel Raynal | 76e1a00 | 2018-03-02 15:38:39 +0100 | [diff] [blame] | 126 | struct gpmi_nfc_hardware_timing hw; |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 127 | |
| 128 | /* BCH */ |
| 129 | struct bch_geometry bch_geometry; |
| 130 | struct completion bch_done; |
| 131 | |
| 132 | /* NAND Boot issue */ |
| 133 | bool swap_block_mark; |
| 134 | struct boot_rom_geometry rom_geometry; |
| 135 | |
| 136 | /* MTD / NAND */ |
Sascha Hauer | ef347c0 | 2019-05-21 09:06:43 +0200 | [diff] [blame^] | 137 | struct nand_controller base; |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 138 | struct nand_chip nand; |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 139 | |
Sascha Hauer | ef347c0 | 2019-05-21 09:06:43 +0200 | [diff] [blame^] | 140 | struct gpmi_transfer transfers[GPMI_MAX_TRANSFERS]; |
| 141 | int ntransfers; |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 142 | |
Sascha Hauer | ef347c0 | 2019-05-21 09:06:43 +0200 | [diff] [blame^] | 143 | bool bch; |
| 144 | uint32_t bch_flashlayout0; |
| 145 | uint32_t bch_flashlayout1; |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 146 | |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 147 | char *data_buffer_dma; |
| 148 | |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 149 | void *auxiliary_virt; |
| 150 | dma_addr_t auxiliary_phys; |
| 151 | |
Boris BREZILLON | da3bc42c | 2014-11-30 19:10:29 +0100 | [diff] [blame] | 152 | void *raw_buffer; |
| 153 | |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 154 | /* DMA channels */ |
| 155 | #define DMA_CHANS 8 |
| 156 | struct dma_chan *dma_chans[DMA_CHANS]; |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 157 | struct completion dma_done; |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 158 | }; |
| 159 | |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 160 | /* BCH : Status Block Completion Codes */ |
| 161 | #define STATUS_GOOD 0x00 |
| 162 | #define STATUS_ERASED 0xff |
| 163 | #define STATUS_UNCORRECTABLE 0xfe |
| 164 | |
Huang Shijie | 6189ccc | 2014-03-21 18:19:39 +0800 | [diff] [blame] | 165 | /* Use the devdata to distinguish different Archs. */ |
| 166 | #define GPMI_IS_MX23(x) ((x)->devdata->type == IS_MX23) |
| 167 | #define GPMI_IS_MX28(x) ((x)->devdata->type == IS_MX28) |
| 168 | #define GPMI_IS_MX6Q(x) ((x)->devdata->type == IS_MX6Q) |
Huang Shijie | 91f5498 | 2014-03-27 10:43:22 +0800 | [diff] [blame] | 169 | #define GPMI_IS_MX6SX(x) ((x)->devdata->type == IS_MX6SX) |
Stefan Agner | b4af694 | 2017-04-21 18:23:35 -0700 | [diff] [blame] | 170 | #define GPMI_IS_MX7D(x) ((x)->devdata->type == IS_MX7D) |
Huang Shijie | 91f5498 | 2014-03-27 10:43:22 +0800 | [diff] [blame] | 171 | |
Stefan Agner | b4af694 | 2017-04-21 18:23:35 -0700 | [diff] [blame] | 172 | #define GPMI_IS_MX6(x) (GPMI_IS_MX6Q(x) || GPMI_IS_MX6SX(x) || \ |
| 173 | GPMI_IS_MX7D(x)) |
Fabio Estevam | f67ed14 | 2019-02-07 08:50:54 -0200 | [diff] [blame] | 174 | #define GPMI_IS_MXS(x) (GPMI_IS_MX23(x) || GPMI_IS_MX28(x)) |
Huang Shijie | 10a2bca | 2011-09-08 10:47:09 +0800 | [diff] [blame] | 175 | #endif |