Merge tag 'mtd/for-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux
[platform/kernel/linux-rpi.git] / drivers / mtd / nand / raw / nand_macronix.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2017 Free Electrons
4  * Copyright (C) 2017 NextThing Co
5  *
6  * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
7  */
8
9 #include "internals.h"
10
11 #define MACRONIX_READ_RETRY_BIT BIT(0)
12 #define MACRONIX_NUM_READ_RETRY_MODES 6
13
14 struct nand_onfi_vendor_macronix {
15         u8 reserved;
16         u8 reliability_func;
17 } __packed;
18
19 static int macronix_nand_setup_read_retry(struct nand_chip *chip, int mode)
20 {
21         u8 feature[ONFI_SUBFEATURE_PARAM_LEN];
22
23         if (!chip->parameters.supports_set_get_features ||
24             !test_bit(ONFI_FEATURE_ADDR_READ_RETRY,
25                       chip->parameters.set_feature_list))
26                 return -ENOTSUPP;
27
28         feature[0] = mode;
29         return nand_set_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, feature);
30 }
31
32 static void macronix_nand_onfi_init(struct nand_chip *chip)
33 {
34         struct nand_parameters *p = &chip->parameters;
35         struct nand_onfi_vendor_macronix *mxic;
36
37         if (!p->onfi)
38                 return;
39
40         mxic = (struct nand_onfi_vendor_macronix *)p->onfi->vendor;
41         if ((mxic->reliability_func & MACRONIX_READ_RETRY_BIT) == 0)
42                 return;
43
44         chip->read_retries = MACRONIX_NUM_READ_RETRY_MODES;
45         chip->setup_read_retry = macronix_nand_setup_read_retry;
46
47         if (p->supports_set_get_features) {
48                 bitmap_set(p->set_feature_list,
49                            ONFI_FEATURE_ADDR_READ_RETRY, 1);
50                 bitmap_set(p->get_feature_list,
51                            ONFI_FEATURE_ADDR_READ_RETRY, 1);
52         }
53 }
54
55 /*
56  * Macronix AC series does not support using SET/GET_FEATURES to change
57  * the timings unlike what is declared in the parameter page. Unflag
58  * this feature to avoid unnecessary downturns.
59  */
60 static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
61 {
62         unsigned int i;
63         static const char * const broken_get_timings[] = {
64                 "MX30LF1G18AC",
65                 "MX30LF1G28AC",
66                 "MX30LF2G18AC",
67                 "MX30LF2G28AC",
68                 "MX30LF4G18AC",
69                 "MX30LF4G28AC",
70                 "MX60LF8G18AC",
71                 "MX30UF1G18AC",
72                 "MX30UF1G16AC",
73                 "MX30UF2G18AC",
74                 "MX30UF2G16AC",
75                 "MX30UF4G18AC",
76                 "MX30UF4G16AC",
77                 "MX30UF4G28AC",
78         };
79
80         if (!chip->parameters.supports_set_get_features)
81                 return;
82
83         for (i = 0; i < ARRAY_SIZE(broken_get_timings); i++) {
84                 if (!strcmp(broken_get_timings[i], chip->parameters.model))
85                         break;
86         }
87
88         if (i == ARRAY_SIZE(broken_get_timings))
89                 return;
90
91         bitmap_clear(chip->parameters.get_feature_list,
92                      ONFI_FEATURE_ADDR_TIMING_MODE, 1);
93         bitmap_clear(chip->parameters.set_feature_list,
94                      ONFI_FEATURE_ADDR_TIMING_MODE, 1);
95 }
96
97 static int macronix_nand_init(struct nand_chip *chip)
98 {
99         if (nand_is_slc(chip))
100                 chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
101
102         macronix_nand_fix_broken_get_timings(chip);
103         macronix_nand_onfi_init(chip);
104
105         return 0;
106 }
107
108 const struct nand_manufacturer_ops macronix_nand_manuf_ops = {
109         .init = macronix_nand_init,
110 };