1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
4 | * 2002-2006 Thomas Gleixner (tglx@linutronix.de) |
5 | * |
6 | * Credits: |
7 | * David Woodhouse for adding multichip support |
8 | * |
9 | * Aleph One Ltd. and Toby Churchill Ltd. for supporting the |
10 | * rework for 2K page size chips |
11 | * |
12 | * This file contains all ONFI helpers. |
13 | */ |
14 | |
15 | #include <linux/slab.h> |
16 | |
17 | #include "internals.h" |
18 | |
19 | #define JEDEC_PARAM_PAGES 3 |
20 | |
21 | /* |
22 | * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise. |
23 | */ |
24 | int nand_jedec_detect(struct nand_chip *chip) |
25 | { |
26 | struct nand_device *base = &chip->base; |
27 | struct mtd_info *mtd = nand_to_mtd(chip); |
28 | struct nand_memory_organization *memorg; |
29 | struct nand_jedec_params *p; |
30 | struct jedec_ecc_info *ecc; |
31 | bool use_datain = false; |
32 | int jedec_version = 0; |
33 | char id[5]; |
34 | int i, val, ret; |
35 | u16 crc; |
36 | |
37 | memorg = nanddev_get_memorg(nand: &chip->base); |
38 | |
39 | /* Try JEDEC for unknown chip or LP */ |
40 | ret = nand_readid_op(chip, addr: 0x40, buf: id, len: sizeof(id)); |
41 | if (ret || strncmp(id, "JEDEC" , sizeof(id))) |
42 | return 0; |
43 | |
44 | /* JEDEC chip: allocate a buffer to hold its parameter page */ |
45 | p = kzalloc(size: sizeof(*p), GFP_KERNEL); |
46 | if (!p) |
47 | return -ENOMEM; |
48 | |
49 | if (!nand_has_exec_op(chip) || chip->controller->supported_op.data_only_read) |
50 | use_datain = true; |
51 | |
52 | for (i = 0; i < JEDEC_PARAM_PAGES; i++) { |
53 | if (!i) |
54 | ret = nand_read_param_page_op(chip, page: 0x40, buf: p, |
55 | len: sizeof(*p)); |
56 | else if (use_datain) |
57 | ret = nand_read_data_op(chip, buf: p, len: sizeof(*p), force_8bit: true, |
58 | check_only: false); |
59 | else |
60 | ret = nand_change_read_column_op(chip, offset_in_page: sizeof(*p) * i, |
61 | buf: p, len: sizeof(*p), force_8bit: true); |
62 | if (ret) { |
63 | ret = 0; |
64 | goto free_jedec_param_page; |
65 | } |
66 | |
67 | crc = onfi_crc16(ONFI_CRC_BASE, p: (u8 *)p, len: 510); |
68 | if (crc == le16_to_cpu(p->crc)) |
69 | break; |
70 | } |
71 | |
72 | if (i == JEDEC_PARAM_PAGES) { |
73 | pr_err("Could not find valid JEDEC parameter page; aborting\n" ); |
74 | goto free_jedec_param_page; |
75 | } |
76 | |
77 | /* Check version */ |
78 | val = le16_to_cpu(p->revision); |
79 | if (val & (1 << 2)) |
80 | jedec_version = 10; |
81 | else if (val & (1 << 1)) |
82 | jedec_version = 1; /* vendor specific version */ |
83 | |
84 | if (!jedec_version) { |
85 | pr_info("unsupported JEDEC version: %d\n" , val); |
86 | goto free_jedec_param_page; |
87 | } |
88 | |
89 | sanitize_string(s: p->manufacturer, len: sizeof(p->manufacturer)); |
90 | sanitize_string(s: p->model, len: sizeof(p->model)); |
91 | chip->parameters.model = kstrdup(s: p->model, GFP_KERNEL); |
92 | if (!chip->parameters.model) { |
93 | ret = -ENOMEM; |
94 | goto free_jedec_param_page; |
95 | } |
96 | |
97 | if (p->opt_cmd[0] & JEDEC_OPT_CMD_READ_CACHE) |
98 | chip->parameters.supports_read_cache = true; |
99 | |
100 | memorg->pagesize = le32_to_cpu(p->byte_per_page); |
101 | mtd->writesize = memorg->pagesize; |
102 | |
103 | /* Please reference to the comment for nand_flash_detect_onfi. */ |
104 | memorg->pages_per_eraseblock = |
105 | 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1); |
106 | mtd->erasesize = memorg->pages_per_eraseblock * memorg->pagesize; |
107 | |
108 | memorg->oobsize = le16_to_cpu(p->spare_bytes_per_page); |
109 | mtd->oobsize = memorg->oobsize; |
110 | |
111 | memorg->luns_per_target = p->lun_count; |
112 | memorg->planes_per_lun = 1 << p->multi_plane_addr; |
113 | |
114 | /* Please reference to the comment for nand_flash_detect_onfi. */ |
115 | memorg->eraseblocks_per_lun = |
116 | 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1); |
117 | memorg->bits_per_cell = p->bits_per_cell; |
118 | |
119 | if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS) |
120 | chip->options |= NAND_BUSWIDTH_16; |
121 | |
122 | /* ECC info */ |
123 | ecc = &p->ecc_info[0]; |
124 | |
125 | if (ecc->codeword_size >= 9) { |
126 | struct nand_ecc_props requirements = { |
127 | .strength = ecc->ecc_bits, |
128 | .step_size = 1 << ecc->codeword_size, |
129 | }; |
130 | |
131 | nanddev_set_ecc_requirements(nand: base, reqs: &requirements); |
132 | } else { |
133 | pr_warn("Invalid codeword size\n" ); |
134 | } |
135 | |
136 | ret = 1; |
137 | |
138 | free_jedec_param_page: |
139 | kfree(objp: p); |
140 | return ret; |
141 | } |
142 | |