]>
Commit | Line | Data |
---|---|---|
c942fddf | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
c51d0ac5 BB |
2 | /* |
3 | * Copyright (C) 2017 Free Electrons | |
4 | * Copyright (C) 2017 NextThing Co | |
5 | * | |
6 | * Author: Boris Brezillon <boris.brezillon@free-electrons.com> | |
c51d0ac5 BB |
7 | */ |
8 | ||
348d56a8 | 9 | #include "internals.h" |
c51d0ac5 BB |
10 | |
11 | static void samsung_nand_decode_id(struct nand_chip *chip) | |
12 | { | |
13 | struct mtd_info *mtd = nand_to_mtd(chip); | |
629a442c BB |
14 | struct nand_memory_organization *memorg; |
15 | ||
16 | memorg = nanddev_get_memorg(&chip->base); | |
c51d0ac5 BB |
17 | |
18 | /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */ | |
19 | if (chip->id.len == 6 && !nand_is_slc(chip) && | |
20 | chip->id.data[5] != 0x00) { | |
21 | u8 extid = chip->id.data[3]; | |
22 | ||
23 | /* Get pagesize */ | |
629a442c BB |
24 | memorg->pagesize = 2048 << (extid & 0x03); |
25 | mtd->writesize = memorg->pagesize; | |
c51d0ac5 BB |
26 | |
27 | extid >>= 2; | |
28 | ||
29 | /* Get oobsize */ | |
30 | switch (((extid >> 2) & 0x4) | (extid & 0x3)) { | |
31 | case 1: | |
629a442c | 32 | memorg->oobsize = 128; |
c51d0ac5 BB |
33 | break; |
34 | case 2: | |
629a442c | 35 | memorg->oobsize = 218; |
c51d0ac5 BB |
36 | break; |
37 | case 3: | |
629a442c | 38 | memorg->oobsize = 400; |
c51d0ac5 BB |
39 | break; |
40 | case 4: | |
629a442c | 41 | memorg->oobsize = 436; |
c51d0ac5 BB |
42 | break; |
43 | case 5: | |
629a442c | 44 | memorg->oobsize = 512; |
c51d0ac5 BB |
45 | break; |
46 | case 6: | |
629a442c | 47 | memorg->oobsize = 640; |
c51d0ac5 BB |
48 | break; |
49 | default: | |
50 | /* | |
51 | * We should never reach this case, but if that | |
52 | * happens, this probably means Samsung decided to use | |
53 | * a different extended ID format, and we should find | |
54 | * a way to support it. | |
55 | */ | |
56 | WARN(1, "Invalid OOB size value"); | |
57 | break; | |
58 | } | |
59 | ||
629a442c BB |
60 | mtd->oobsize = memorg->oobsize; |
61 | ||
c51d0ac5 BB |
62 | /* Get blocksize */ |
63 | extid >>= 2; | |
629a442c BB |
64 | memorg->pages_per_eraseblock = (128 * 1024) << |
65 | (((extid >> 1) & 0x04) | | |
66 | (extid & 0x03)) / | |
67 | memorg->pagesize; | |
c51d0ac5 BB |
68 | mtd->erasesize = (128 * 1024) << |
69 | (((extid >> 1) & 0x04) | (extid & 0x03)); | |
8fc82d45 HG |
70 | |
71 | /* Extract ECC requirements from 5th id byte*/ | |
72 | extid = (chip->id.data[4] >> 4) & 0x07; | |
73 | if (extid < 5) { | |
6a1b66d6 BB |
74 | chip->base.eccreq.step_size = 512; |
75 | chip->base.eccreq.strength = 1 << extid; | |
8fc82d45 | 76 | } else { |
6a1b66d6 | 77 | chip->base.eccreq.step_size = 1024; |
8fc82d45 HG |
78 | switch (extid) { |
79 | case 5: | |
6a1b66d6 | 80 | chip->base.eccreq.strength = 24; |
8fc82d45 HG |
81 | break; |
82 | case 6: | |
6a1b66d6 | 83 | chip->base.eccreq.strength = 40; |
8fc82d45 HG |
84 | break; |
85 | case 7: | |
6a1b66d6 | 86 | chip->base.eccreq.strength = 60; |
8fc82d45 | 87 | break; |
d2419790 BN |
88 | default: |
89 | WARN(1, "Could not decode ECC info"); | |
6a1b66d6 | 90 | chip->base.eccreq.step_size = 0; |
8fc82d45 HG |
91 | } |
92 | } | |
c51d0ac5 BB |
93 | } else { |
94 | nand_decode_ext_id(chip); | |
707d8154 | 95 | |
09ec417b LM |
96 | if (nand_is_slc(chip)) { |
97 | switch (chip->id.data[1]) { | |
98 | /* K9F4G08U0D-S[I|C]B0(T00) */ | |
99 | case 0xDC: | |
6a1b66d6 BB |
100 | chip->base.eccreq.step_size = 512; |
101 | chip->base.eccreq.strength = 1; | |
09ec417b LM |
102 | break; |
103 | ||
104 | /* K9F1G08U0E 21nm chips do not support subpage write */ | |
105 | case 0xF1: | |
106 | if (chip->id.len > 4 && | |
107 | (chip->id.data[4] & GENMASK(1, 0)) == 0x1) | |
108 | chip->options |= NAND_NO_SUBPAGE_WRITE; | |
109 | break; | |
110 | default: | |
111 | break; | |
112 | } | |
707d8154 | 113 | } |
c51d0ac5 BB |
114 | } |
115 | } | |
116 | ||
117 | static int samsung_nand_init(struct nand_chip *chip) | |
118 | { | |
119 | struct mtd_info *mtd = nand_to_mtd(chip); | |
120 | ||
121 | if (mtd->writesize > 512) | |
122 | chip->options |= NAND_SAMSUNG_LP_OPTIONS; | |
123 | ||
124 | if (!nand_is_slc(chip)) | |
04649ec1 | 125 | chip->options |= NAND_BBM_LASTPAGE; |
c51d0ac5 | 126 | else |
bb592548 | 127 | chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; |
c51d0ac5 BB |
128 | |
129 | return 0; | |
130 | } | |
131 | ||
132 | const struct nand_manufacturer_ops samsung_nand_manuf_ops = { | |
133 | .detect = samsung_nand_decode_id, | |
134 | .init = samsung_nand_init, | |
135 | }; |