]>
Commit | Line | Data |
---|---|---|
c51d0ac5 BB |
1 | /* |
2 | * Copyright (C) 2017 Free Electrons | |
3 | * Copyright (C) 2017 NextThing Co | |
4 | * | |
5 | * Author: Boris Brezillon <boris.brezillon@free-electrons.com> | |
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 | ||
18 | #include <linux/mtd/nand.h> | |
19 | ||
20 | static void samsung_nand_decode_id(struct nand_chip *chip) | |
21 | { | |
22 | struct mtd_info *mtd = nand_to_mtd(chip); | |
23 | ||
24 | /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */ | |
25 | if (chip->id.len == 6 && !nand_is_slc(chip) && | |
26 | chip->id.data[5] != 0x00) { | |
27 | u8 extid = chip->id.data[3]; | |
28 | ||
29 | /* Get pagesize */ | |
30 | mtd->writesize = 2048 << (extid & 0x03); | |
31 | ||
32 | extid >>= 2; | |
33 | ||
34 | /* Get oobsize */ | |
35 | switch (((extid >> 2) & 0x4) | (extid & 0x3)) { | |
36 | case 1: | |
37 | mtd->oobsize = 128; | |
38 | break; | |
39 | case 2: | |
40 | mtd->oobsize = 218; | |
41 | break; | |
42 | case 3: | |
43 | mtd->oobsize = 400; | |
44 | break; | |
45 | case 4: | |
46 | mtd->oobsize = 436; | |
47 | break; | |
48 | case 5: | |
49 | mtd->oobsize = 512; | |
50 | break; | |
51 | case 6: | |
52 | mtd->oobsize = 640; | |
53 | break; | |
54 | default: | |
55 | /* | |
56 | * We should never reach this case, but if that | |
57 | * happens, this probably means Samsung decided to use | |
58 | * a different extended ID format, and we should find | |
59 | * a way to support it. | |
60 | */ | |
61 | WARN(1, "Invalid OOB size value"); | |
62 | break; | |
63 | } | |
64 | ||
65 | /* Get blocksize */ | |
66 | extid >>= 2; | |
67 | mtd->erasesize = (128 * 1024) << | |
68 | (((extid >> 1) & 0x04) | (extid & 0x03)); | |
8fc82d45 HG |
69 | |
70 | /* Extract ECC requirements from 5th id byte*/ | |
71 | extid = (chip->id.data[4] >> 4) & 0x07; | |
72 | if (extid < 5) { | |
73 | chip->ecc_step_ds = 512; | |
74 | chip->ecc_strength_ds = 1 << extid; | |
75 | } else { | |
76 | chip->ecc_step_ds = 1024; | |
77 | switch (extid) { | |
78 | case 5: | |
79 | chip->ecc_strength_ds = 24; | |
80 | break; | |
81 | case 6: | |
82 | chip->ecc_strength_ds = 40; | |
83 | break; | |
84 | case 7: | |
85 | chip->ecc_strength_ds = 60; | |
86 | break; | |
d2419790 BN |
87 | default: |
88 | WARN(1, "Could not decode ECC info"); | |
89 | chip->ecc_step_ds = 0; | |
8fc82d45 HG |
90 | } |
91 | } | |
c51d0ac5 BB |
92 | } else { |
93 | nand_decode_ext_id(chip); | |
94 | } | |
95 | } | |
96 | ||
97 | static int samsung_nand_init(struct nand_chip *chip) | |
98 | { | |
99 | struct mtd_info *mtd = nand_to_mtd(chip); | |
100 | ||
101 | if (mtd->writesize > 512) | |
102 | chip->options |= NAND_SAMSUNG_LP_OPTIONS; | |
103 | ||
104 | if (!nand_is_slc(chip)) | |
105 | chip->bbt_options |= NAND_BBT_SCANLASTPAGE; | |
106 | else | |
107 | chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; | |
108 | ||
109 | return 0; | |
110 | } | |
111 | ||
112 | const struct nand_manufacturer_ops samsung_nand_manuf_ops = { | |
113 | .detect = samsung_nand_decode_id, | |
114 | .init = samsung_nand_init, | |
115 | }; |