Stefan Agner | 7152f34 | 2018-06-22 17:19:46 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0+ */ |
| 2 | /* |
| 3 | * NXP GPMI NAND flash driver |
| 4 | * |
| 5 | * Copyright (C) 2018 Toradex |
| 6 | * Authors: |
| 7 | * Stefan Agner <stefan.agner@toradex.com> |
| 8 | */ |
| 9 | |
Stefan Agner | 19f9051 | 2018-06-22 18:06:16 +0200 | [diff] [blame] | 10 | #include <linux/mtd/mtd.h> |
Tom Rini | 3bde7e2 | 2021-09-22 14:50:35 -0400 | [diff] [blame] | 11 | #include <linux/mtd/rawnand.h> |
Stefan Agner | 19f9051 | 2018-06-22 18:06:16 +0200 | [diff] [blame] | 12 | #include <asm/cache.h> |
| 13 | #include <nand.h> |
| 14 | #include <asm/mach-imx/dma.h> |
| 15 | |
| 16 | /** |
| 17 | * @gf_len: The length of Galois Field. (e.g., 13 or 14) |
| 18 | * @ecc_strength: A number that describes the strength of the ECC |
| 19 | * algorithm. |
Ye Li | 9454744 | 2020-05-04 22:08:50 +0800 | [diff] [blame] | 20 | * @ecc_chunk0_size: The size, in bytes, of a first ECC chunk. |
| 21 | * @ecc_chunkn_size: The size, in bytes, of a single ECC chunk after |
| 22 | * the first chunk in the page. |
Stefan Agner | 19f9051 | 2018-06-22 18:06:16 +0200 | [diff] [blame] | 23 | * @ecc_chunk_count: The number of ECC chunks in the page, |
| 24 | * @block_mark_byte_offset: The byte offset in the ECC-based page view at |
| 25 | * which the underlying physical block mark appears. |
| 26 | * @block_mark_bit_offset: The bit offset into the ECC-based page view at |
| 27 | * which the underlying physical block mark appears. |
Ye Li | 9454744 | 2020-05-04 22:08:50 +0800 | [diff] [blame] | 28 | * @ecc_for_meta: The flag to indicate if there is a dedicate ecc |
| 29 | * for meta. |
Stefan Agner | 19f9051 | 2018-06-22 18:06:16 +0200 | [diff] [blame] | 30 | */ |
| 31 | struct bch_geometry { |
| 32 | unsigned int gf_len; |
| 33 | unsigned int ecc_strength; |
Ye Li | 9454744 | 2020-05-04 22:08:50 +0800 | [diff] [blame] | 34 | unsigned int ecc_chunk0_size; |
| 35 | unsigned int ecc_chunkn_size; |
Stefan Agner | 19f9051 | 2018-06-22 18:06:16 +0200 | [diff] [blame] | 36 | unsigned int ecc_chunk_count; |
| 37 | unsigned int block_mark_byte_offset; |
| 38 | unsigned int block_mark_bit_offset; |
Ye Li | 9454744 | 2020-05-04 22:08:50 +0800 | [diff] [blame] | 39 | unsigned int ecc_for_meta; /* ECC for meta data */ |
Stefan Agner | 19f9051 | 2018-06-22 18:06:16 +0200 | [diff] [blame] | 40 | }; |
| 41 | |
| 42 | struct mxs_nand_info { |
| 43 | struct nand_chip chip; |
| 44 | struct udevice *dev; |
| 45 | unsigned int max_ecc_strength_supported; |
| 46 | bool use_minimum_ecc; |
Ye Li | c673613 | 2020-05-04 22:08:51 +0800 | [diff] [blame] | 47 | /* legacy bch geometry flag */ |
| 48 | bool legacy_bch_geometry; |
Stefan Agner | 19f9051 | 2018-06-22 18:06:16 +0200 | [diff] [blame] | 49 | int cur_chip; |
| 50 | |
| 51 | uint32_t cmd_queue_len; |
| 52 | uint32_t data_buf_size; |
| 53 | struct bch_geometry bch_geometry; |
| 54 | |
| 55 | uint8_t *cmd_buf; |
| 56 | uint8_t *data_buf; |
| 57 | uint8_t *oob_buf; |
| 58 | |
| 59 | uint8_t marking_block_bad; |
| 60 | uint8_t raw_oob_mode; |
| 61 | |
| 62 | struct mxs_gpmi_regs *gpmi_regs; |
| 63 | struct mxs_bch_regs *bch_regs; |
| 64 | |
| 65 | /* Functions with altered behaviour */ |
| 66 | int (*hooked_read_oob)(struct mtd_info *mtd, |
| 67 | loff_t from, struct mtd_oob_ops *ops); |
| 68 | int (*hooked_write_oob)(struct mtd_info *mtd, |
| 69 | loff_t to, struct mtd_oob_ops *ops); |
| 70 | int (*hooked_block_markbad)(struct mtd_info *mtd, |
| 71 | loff_t ofs); |
| 72 | |
| 73 | /* DMA descriptors */ |
| 74 | struct mxs_dma_desc **desc; |
| 75 | uint32_t desc_index; |
Igor Opaniuk | c5540137 | 2019-11-03 16:49:43 +0100 | [diff] [blame] | 76 | |
| 77 | /* Hardware BCH interface and randomizer */ |
| 78 | u32 en_randomizer; |
| 79 | u32 writesize; |
| 80 | u32 oobsize; |
| 81 | u32 bch_flash0layout0; |
| 82 | u32 bch_flash0layout1; |
| 83 | }; |
| 84 | |
| 85 | struct mxs_nand_layout { |
| 86 | u32 nblocks; |
| 87 | u32 meta_size; |
| 88 | u32 data0_size; |
| 89 | u32 ecc0; |
| 90 | u32 datan_size; |
| 91 | u32 eccn; |
Han Xu | 33543b5 | 2020-05-04 22:08:58 +0800 | [diff] [blame] | 92 | u32 gf_len; |
Stefan Agner | 19f9051 | 2018-06-22 18:06:16 +0200 | [diff] [blame] | 93 | }; |
| 94 | |
| 95 | int mxs_nand_init_ctrl(struct mxs_nand_info *nand_info); |
Stefan Agner | 7152f34 | 2018-06-22 17:19:46 +0200 | [diff] [blame] | 96 | int mxs_nand_init_spl(struct nand_chip *nand); |
Stefan Agner | 5883e55 | 2018-06-22 17:19:47 +0200 | [diff] [blame] | 97 | int mxs_nand_setup_ecc(struct mtd_info *mtd); |
Igor Opaniuk | c5540137 | 2019-11-03 16:49:43 +0100 | [diff] [blame] | 98 | |
Han Xu | afed2a1 | 2020-05-06 20:59:19 +0800 | [diff] [blame] | 99 | void mxs_nand_mode_fcb_62bit(struct mtd_info *mtd); |
| 100 | void mxs_nand_mode_fcb_40bit(struct mtd_info *mtd); |
Igor Opaniuk | c5540137 | 2019-11-03 16:49:43 +0100 | [diff] [blame] | 101 | void mxs_nand_mode_normal(struct mtd_info *mtd); |
| 102 | u32 mxs_nand_mark_byte_offset(struct mtd_info *mtd); |
| 103 | u32 mxs_nand_mark_bit_offset(struct mtd_info *mtd); |
| 104 | void mxs_nand_get_layout(struct mtd_info *mtd, struct mxs_nand_layout *l); |