]> Git Repo - linux.git/blob - drivers/mtd/nand/raw/nand_toshiba.c
Merge tag 'microblaze-v5.0-rc1' of git://git.monstr.eu/linux-2.6-microblaze
[linux.git] / drivers / mtd / nand / raw / nand_toshiba.c
1 /*
2  * Copyright (C) 2017 Free Electrons
3  * Copyright (C) 2017 NextThing Co
4  *
5  * Author: Boris Brezillon <[email protected]>
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 "internals.h"
19
20 /* Bit for detecting BENAND */
21 #define TOSHIBA_NAND_ID4_IS_BENAND              BIT(7)
22
23 /* Recommended to rewrite for BENAND */
24 #define TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED BIT(3)
25
26 static int toshiba_nand_benand_eccstatus(struct nand_chip *chip)
27 {
28         struct mtd_info *mtd = nand_to_mtd(chip);
29         int ret;
30         unsigned int max_bitflips = 0;
31         u8 status;
32
33         /* Check Status */
34         ret = nand_status_op(chip, &status);
35         if (ret)
36                 return ret;
37
38         if (status & NAND_STATUS_FAIL) {
39                 /* uncorrected */
40                 mtd->ecc_stats.failed++;
41         } else if (status & TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED) {
42                 /* corrected */
43                 max_bitflips = mtd->bitflip_threshold;
44                 mtd->ecc_stats.corrected += max_bitflips;
45         }
46
47         return max_bitflips;
48 }
49
50 static int
51 toshiba_nand_read_page_benand(struct nand_chip *chip, uint8_t *buf,
52                               int oob_required, int page)
53 {
54         int ret;
55
56         ret = nand_read_page_raw(chip, buf, oob_required, page);
57         if (ret)
58                 return ret;
59
60         return toshiba_nand_benand_eccstatus(chip);
61 }
62
63 static int
64 toshiba_nand_read_subpage_benand(struct nand_chip *chip, uint32_t data_offs,
65                                  uint32_t readlen, uint8_t *bufpoi, int page)
66 {
67         int ret;
68
69         ret = nand_read_page_op(chip, page, data_offs,
70                                 bufpoi + data_offs, readlen);
71         if (ret)
72                 return ret;
73
74         return toshiba_nand_benand_eccstatus(chip);
75 }
76
77 static void toshiba_nand_benand_init(struct nand_chip *chip)
78 {
79         struct mtd_info *mtd = nand_to_mtd(chip);
80
81         /*
82          * On BENAND, the entire OOB region can be used by the MTD user.
83          * The calculated ECC bytes are stored into other isolated
84          * area which is not accessible to users.
85          * This is why chip->ecc.bytes = 0.
86          */
87         chip->ecc.bytes = 0;
88         chip->ecc.size = 512;
89         chip->ecc.strength = 8;
90         chip->ecc.read_page = toshiba_nand_read_page_benand;
91         chip->ecc.read_subpage = toshiba_nand_read_subpage_benand;
92         chip->ecc.write_page = nand_write_page_raw;
93         chip->ecc.read_page_raw = nand_read_page_raw_notsupp;
94         chip->ecc.write_page_raw = nand_write_page_raw_notsupp;
95
96         chip->options |= NAND_SUBPAGE_READ;
97
98         mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
99 }
100
101 static void toshiba_nand_decode_id(struct nand_chip *chip)
102 {
103         struct mtd_info *mtd = nand_to_mtd(chip);
104
105         nand_decode_ext_id(chip);
106
107         /*
108          * Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
109          * 512B page. For Toshiba SLC, we decode the 5th/6th byte as
110          * follows:
111          * - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
112          *                         110b -> 24nm
113          * - ID byte 5, bit[7]:    1 -> BENAND, 0 -> raw SLC
114          */
115         if (chip->id.len >= 6 && nand_is_slc(chip) &&
116             (chip->id.data[5] & 0x7) == 0x6 /* 24nm */ &&
117             !(chip->id.data[4] & 0x80) /* !BENAND */)
118                 mtd->oobsize = 32 * mtd->writesize >> 9;
119
120         /*
121          * Extract ECC requirements from 6th id byte.
122          * For Toshiba SLC, ecc requrements are as follows:
123          *  - 43nm: 1 bit ECC for each 512Byte is required.
124          *  - 32nm: 4 bit ECC for each 512Byte is required.
125          *  - 24nm: 8 bit ECC for each 512Byte is required.
126          */
127         if (chip->id.len >= 6 && nand_is_slc(chip)) {
128                 chip->ecc_step_ds = 512;
129                 switch (chip->id.data[5] & 0x7) {
130                 case 0x4:
131                         chip->ecc_strength_ds = 1;
132                         break;
133                 case 0x5:
134                         chip->ecc_strength_ds = 4;
135                         break;
136                 case 0x6:
137                         chip->ecc_strength_ds = 8;
138                         break;
139                 default:
140                         WARN(1, "Could not get ECC info");
141                         chip->ecc_step_ds = 0;
142                         break;
143                 }
144         }
145 }
146
147 static int toshiba_nand_init(struct nand_chip *chip)
148 {
149         if (nand_is_slc(chip))
150                 chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
151
152         /* Check that chip is BENAND and ECC mode is on-die */
153         if (nand_is_slc(chip) && chip->ecc.mode == NAND_ECC_ON_DIE &&
154             chip->id.data[4] & TOSHIBA_NAND_ID4_IS_BENAND)
155                 toshiba_nand_benand_init(chip);
156
157         return 0;
158 }
159
160 const struct nand_manufacturer_ops toshiba_nand_manuf_ops = {
161         .detect = toshiba_nand_decode_id,
162         .init = toshiba_nand_init,
163 };
This page took 0.044125 seconds and 4 git commands to generate.