xref: /linux/drivers/mtd/nand/raw/nand_macronix.c (revision 2f4c53349961c8ca480193e47da4d44fdb8335a8)
1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
23b5206f4SBoris Brezillon /*
33b5206f4SBoris Brezillon  * Copyright (C) 2017 Free Electrons
43b5206f4SBoris Brezillon  * Copyright (C) 2017 NextThing Co
53b5206f4SBoris Brezillon  *
63b5206f4SBoris Brezillon  * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
73b5206f4SBoris Brezillon  */
83b5206f4SBoris Brezillon 
9348d56a8SBoris Brezillon #include "internals.h"
103b5206f4SBoris Brezillon 
1134c5c01eSMiquel Raynal /*
12fe3dd97dSMason Yang  * Macronix AC series does not support using SET/GET_FEATURES to change
1334c5c01eSMiquel Raynal  * the timings unlike what is declared in the parameter page. Unflag
1434c5c01eSMiquel Raynal  * this feature to avoid unnecessary downturns.
1534c5c01eSMiquel Raynal  */
16fe3dd97dSMason Yang static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip)
17fe3dd97dSMason Yang {
18fe3dd97dSMason Yang 	unsigned int i;
19fe3dd97dSMason Yang 	static const char * const broken_get_timings[] = {
20fe3dd97dSMason Yang 		"MX30LF1G18AC",
21fe3dd97dSMason Yang 		"MX30LF1G28AC",
22fe3dd97dSMason Yang 		"MX30LF2G18AC",
23fe3dd97dSMason Yang 		"MX30LF2G28AC",
24fe3dd97dSMason Yang 		"MX30LF4G18AC",
25fe3dd97dSMason Yang 		"MX30LF4G28AC",
26fe3dd97dSMason Yang 		"MX60LF8G18AC",
27acc9d62bSMason Yang 		"MX30UF1G18AC",
28acc9d62bSMason Yang 		"MX30UF1G16AC",
29acc9d62bSMason Yang 		"MX30UF2G18AC",
30acc9d62bSMason Yang 		"MX30UF2G16AC",
31acc9d62bSMason Yang 		"MX30UF4G18AC",
32acc9d62bSMason Yang 		"MX30UF4G16AC",
33acc9d62bSMason Yang 		"MX30UF4G28AC",
34fe3dd97dSMason Yang 	};
35fe3dd97dSMason Yang 
36fe3dd97dSMason Yang 	if (!chip->parameters.supports_set_get_features)
37fe3dd97dSMason Yang 		return;
38fe3dd97dSMason Yang 
39fe3dd97dSMason Yang 	for (i = 0; i < ARRAY_SIZE(broken_get_timings); i++) {
40fe3dd97dSMason Yang 		if (!strcmp(broken_get_timings[i], chip->parameters.model))
41fe3dd97dSMason Yang 			break;
42fe3dd97dSMason Yang 	}
43fe3dd97dSMason Yang 
44fe3dd97dSMason Yang 	if (i == ARRAY_SIZE(broken_get_timings))
45fe3dd97dSMason Yang 		return;
46fe3dd97dSMason Yang 
4734c5c01eSMiquel Raynal 	bitmap_clear(chip->parameters.get_feature_list,
4834c5c01eSMiquel Raynal 		     ONFI_FEATURE_ADDR_TIMING_MODE, 1);
4934c5c01eSMiquel Raynal 	bitmap_clear(chip->parameters.set_feature_list,
5034c5c01eSMiquel Raynal 		     ONFI_FEATURE_ADDR_TIMING_MODE, 1);
5134c5c01eSMiquel Raynal }
5234c5c01eSMiquel Raynal 
53fe3dd97dSMason Yang static int macronix_nand_init(struct nand_chip *chip)
54fe3dd97dSMason Yang {
55fe3dd97dSMason Yang 	if (nand_is_slc(chip))
56bb592548SFrieder Schrempf 		chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
57fe3dd97dSMason Yang 
58fe3dd97dSMason Yang 	macronix_nand_fix_broken_get_timings(chip);
59fe3dd97dSMason Yang 
603b5206f4SBoris Brezillon 	return 0;
613b5206f4SBoris Brezillon }
623b5206f4SBoris Brezillon 
633b5206f4SBoris Brezillon const struct nand_manufacturer_ops macronix_nand_manuf_ops = {
643b5206f4SBoris Brezillon 	.init = macronix_nand_init,
653b5206f4SBoris Brezillon };
66