Mirror only - Please move to https://github.com/immortalwrt/immortalwrt
Revision | 28481a26eae988b3949083fd1e4c582b9ec4fe2b (tree) |
---|---|
Time | 2022-10-12 20:29:59 |
Author | Ansuel Smith <ansuelsmth@gmai...> |
Commiter | Tianling Shen |
ipq806x: introduce nandc boot layout mode
ipq806x have different ecc configuration for boot partition and rootfs partition. Add support for this to fix IO error on mtd block scan.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
(cherry picked from commit 62cc66fa6737de50d6aa57042f9508fccd476ed7)
@@ -0,0 +1,239 @@ | ||
1 | +From 6949d651e3be3ebbfedb6bbd5b541cfda6ee58a9 Mon Sep 17 00:00:00 2001 | |
2 | +From: Ansuel Smith <ansuelsmth@gmail.com> | |
3 | +Date: Wed, 10 Feb 2021 10:40:17 +0100 | |
4 | +Subject: [PATCH 1/2] mtd: nand: raw: qcom_nandc: add boot_layout_mode support | |
5 | + | |
6 | +ipq806x nand have a special ecc configuration for the boot pages. The | |
7 | +use of the non-boot pages configuration on boot pages cause I/O error | |
8 | +and can cause broken data written to the nand. Add support for this | |
9 | +special configuration if the page to be read/write is in the size of the | |
10 | +boot pages set by the dts. | |
11 | + | |
12 | +Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> | |
13 | +--- | |
14 | + drivers/mtd/nand/raw/qcom_nandc.c | 82 +++++++++++++++++++++++++++++-- | |
15 | + 1 file changed, 77 insertions(+), 5 deletions(-) | |
16 | + | |
17 | +--- a/drivers/mtd/nand/raw/qcom_nandc.c | |
18 | ++++ b/drivers/mtd/nand/raw/qcom_nandc.c | |
19 | +@@ -159,6 +159,11 @@ | |
20 | + /* NAND_CTRL bits */ | |
21 | + #define BAM_MODE_EN BIT(0) | |
22 | + | |
23 | ++ | |
24 | ++#define UD_SIZE_BYTES_MASK (0x3ff << UD_SIZE_BYTES) | |
25 | ++#define SPARE_SIZE_BYTES_MASK (0xf << SPARE_SIZE_BYTES) | |
26 | ++#define ECC_NUM_DATA_BYTES_MASK (0x3ff << ECC_NUM_DATA_BYTES) | |
27 | ++ | |
28 | + /* | |
29 | + * the NAND controller performs reads/writes with ECC in 516 byte chunks. | |
30 | + * the driver calls the chunks 'step' or 'codeword' interchangeably | |
31 | +@@ -430,6 +435,13 @@ struct qcom_nand_controller { | |
32 | + * @cfg0, cfg1, cfg0_raw..: NANDc register configurations needed for | |
33 | + * ecc/non-ecc mode for the current nand flash | |
34 | + * device | |
35 | ++ * | |
36 | ++ * @boot_pages_conf: keep track of the current ecc configuration used by | |
37 | ++ * the driver for read/write operation. (boot pages | |
38 | ++ * have different configuration than normal page) | |
39 | ++ * @boot_pages: number of pages starting from 0 used as boot pages | |
40 | ++ * where the driver will use the boot pages ecc | |
41 | ++ * configuration for read/write operation | |
42 | + */ | |
43 | + struct qcom_nand_host { | |
44 | + struct nand_chip chip; | |
45 | +@@ -452,6 +464,9 @@ struct qcom_nand_host { | |
46 | + u32 ecc_bch_cfg; | |
47 | + u32 clrflashstatus; | |
48 | + u32 clrreadstatus; | |
49 | ++ | |
50 | ++ bool boot_pages_conf; | |
51 | ++ u32 boot_pages; | |
52 | + }; | |
53 | + | |
54 | + /* | |
55 | +@@ -460,12 +475,14 @@ struct qcom_nand_host { | |
56 | + * @ecc_modes - ecc mode for NAND | |
57 | + * @is_bam - whether NAND controller is using BAM | |
58 | + * @is_qpic - whether NAND CTRL is part of qpic IP | |
59 | ++ * @has_boot_pages - whether NAND has different ecc settings for boot pages | |
60 | + * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset | |
61 | + */ | |
62 | + struct qcom_nandc_props { | |
63 | + u32 ecc_modes; | |
64 | + bool is_bam; | |
65 | + bool is_qpic; | |
66 | ++ bool has_boot_pages; | |
67 | + u32 dev_cmd_reg_start; | |
68 | + }; | |
69 | + | |
70 | +@@ -1604,7 +1621,7 @@ qcom_nandc_read_cw_raw(struct mtd_info * | |
71 | + data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); | |
72 | + oob_size1 = host->bbm_size; | |
73 | + | |
74 | +- if (cw == (ecc->steps - 1)) { | |
75 | ++ if (cw == (ecc->steps - 1) && !host->boot_pages_conf) { | |
76 | + data_size2 = ecc->size - data_size1 - | |
77 | + ((ecc->steps - 1) * 4); | |
78 | + oob_size2 = (ecc->steps * 4) + host->ecc_bytes_hw + | |
79 | +@@ -1685,7 +1702,7 @@ check_for_erased_page(struct qcom_nand_h | |
80 | + } | |
81 | + | |
82 | + for_each_set_bit(cw, &uncorrectable_cws, ecc->steps) { | |
83 | +- if (cw == (ecc->steps - 1)) { | |
84 | ++ if (cw == (ecc->steps - 1) && !host->boot_pages_conf) { | |
85 | + data_size = ecc->size - ((ecc->steps - 1) * 4); | |
86 | + oob_size = (ecc->steps * 4) + host->ecc_bytes_hw; | |
87 | + } else { | |
88 | +@@ -1844,7 +1861,7 @@ static int read_page_ecc(struct qcom_nan | |
89 | + for (i = 0; i < ecc->steps; i++) { | |
90 | + int data_size, oob_size; | |
91 | + | |
92 | +- if (i == (ecc->steps - 1)) { | |
93 | ++ if (i == (ecc->steps - 1) && !host->boot_pages_conf) { | |
94 | + data_size = ecc->size - ((ecc->steps - 1) << 2); | |
95 | + oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + | |
96 | + host->spare_bytes; | |
97 | +@@ -1941,6 +1958,30 @@ static int copy_last_cw(struct qcom_nand | |
98 | + return ret; | |
99 | + } | |
100 | + | |
101 | ++static void | |
102 | ++check_boot_pages_conf(struct qcom_nand_host *host, int page) | |
103 | ++{ | |
104 | ++ bool boot_pages_conf = page < host->boot_pages; | |
105 | ++ | |
106 | ++ /* Skip conf write if we are already in the correct mode */ | |
107 | ++ if (boot_pages_conf != host->boot_pages_conf) { | |
108 | ++ host->boot_pages_conf = boot_pages_conf; | |
109 | ++ | |
110 | ++ host->cw_data = boot_pages_conf ? 512 : 516; | |
111 | ++ host->spare_bytes = host->cw_size - host->ecc_bytes_hw - | |
112 | ++ host->bbm_size - host->cw_data; | |
113 | ++ | |
114 | ++ host->cfg0 &= ~(SPARE_SIZE_BYTES_MASK | UD_SIZE_BYTES_MASK); | |
115 | ++ host->cfg0 |= host->spare_bytes << SPARE_SIZE_BYTES | | |
116 | ++ host->cw_data << UD_SIZE_BYTES; | |
117 | ++ | |
118 | ++ host->ecc_bch_cfg &= ~ECC_NUM_DATA_BYTES_MASK; | |
119 | ++ host->ecc_bch_cfg |= host->cw_data << ECC_NUM_DATA_BYTES; | |
120 | ++ host->ecc_buf_cfg = (boot_pages_conf ? 0x1ff : 0x203) << | |
121 | ++ NUM_STEPS; | |
122 | ++ } | |
123 | ++} | |
124 | ++ | |
125 | + /* implements ecc->read_page() */ | |
126 | + static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf, | |
127 | + int oob_required, int page) | |
128 | +@@ -1949,6 +1990,9 @@ static int qcom_nandc_read_page(struct n | |
129 | + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); | |
130 | + u8 *data_buf, *oob_buf = NULL; | |
131 | + | |
132 | ++ if (host->boot_pages) | |
133 | ++ check_boot_pages_conf(host, page); | |
134 | ++ | |
135 | + nand_read_page_op(chip, page, 0, NULL, 0); | |
136 | + data_buf = buf; | |
137 | + oob_buf = oob_required ? chip->oob_poi : NULL; | |
138 | +@@ -1968,6 +2012,9 @@ static int qcom_nandc_read_page_raw(stru | |
139 | + int cw, ret; | |
140 | + u8 *data_buf = buf, *oob_buf = chip->oob_poi; | |
141 | + | |
142 | ++ if (host->boot_pages) | |
143 | ++ check_boot_pages_conf(host, page); | |
144 | ++ | |
145 | + for (cw = 0; cw < ecc->steps; cw++) { | |
146 | + ret = qcom_nandc_read_cw_raw(mtd, chip, data_buf, oob_buf, | |
147 | + page, cw); | |
148 | +@@ -1988,6 +2035,9 @@ static int qcom_nandc_read_oob(struct na | |
149 | + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); | |
150 | + struct nand_ecc_ctrl *ecc = &chip->ecc; | |
151 | + | |
152 | ++ if (host->boot_pages) | |
153 | ++ check_boot_pages_conf(host, page); | |
154 | ++ | |
155 | + clear_read_regs(nandc); | |
156 | + clear_bam_transaction(nandc); | |
157 | + | |
158 | +@@ -2008,6 +2058,9 @@ static int qcom_nandc_write_page(struct | |
159 | + u8 *data_buf, *oob_buf; | |
160 | + int i, ret; | |
161 | + | |
162 | ++ if (host->boot_pages) | |
163 | ++ check_boot_pages_conf(host, page); | |
164 | ++ | |
165 | + nand_prog_page_begin_op(chip, page, 0, NULL, 0); | |
166 | + | |
167 | + clear_read_regs(nandc); | |
168 | +@@ -2023,7 +2076,7 @@ static int qcom_nandc_write_page(struct | |
169 | + for (i = 0; i < ecc->steps; i++) { | |
170 | + int data_size, oob_size; | |
171 | + | |
172 | +- if (i == (ecc->steps - 1)) { | |
173 | ++ if (i == (ecc->steps - 1) && !host->boot_pages_conf) { | |
174 | + data_size = ecc->size - ((ecc->steps - 1) << 2); | |
175 | + oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + | |
176 | + host->spare_bytes; | |
177 | +@@ -2080,6 +2133,9 @@ static int qcom_nandc_write_page_raw(str | |
178 | + u8 *data_buf, *oob_buf; | |
179 | + int i, ret; | |
180 | + | |
181 | ++ if (host->boot_pages) | |
182 | ++ check_boot_pages_conf(host, page); | |
183 | ++ | |
184 | + nand_prog_page_begin_op(chip, page, 0, NULL, 0); | |
185 | + clear_read_regs(nandc); | |
186 | + clear_bam_transaction(nandc); | |
187 | +@@ -2098,7 +2154,7 @@ static int qcom_nandc_write_page_raw(str | |
188 | + data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); | |
189 | + oob_size1 = host->bbm_size; | |
190 | + | |
191 | +- if (i == (ecc->steps - 1)) { | |
192 | ++ if (i == (ecc->steps - 1) && !host->boot_pages_conf) { | |
193 | + data_size2 = ecc->size - data_size1 - | |
194 | + ((ecc->steps - 1) << 2); | |
195 | + oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw + | |
196 | +@@ -2158,6 +2214,9 @@ static int qcom_nandc_write_oob(struct n | |
197 | + int data_size, oob_size; | |
198 | + int ret; | |
199 | + | |
200 | ++ if (host->boot_pages) | |
201 | ++ check_boot_pages_conf(host, page); | |
202 | ++ | |
203 | + host->use_ecc = true; | |
204 | + clear_bam_transaction(nandc); | |
205 | + | |
206 | +@@ -2806,6 +2865,7 @@ static int qcom_nand_host_init_and_regis | |
207 | + struct nand_chip *chip = &host->chip; | |
208 | + struct mtd_info *mtd = nand_to_mtd(chip); | |
209 | + struct device *dev = nandc->dev; | |
210 | ++ u32 boot_pages_size; | |
211 | + int ret; | |
212 | + | |
213 | + ret = of_property_read_u32(dn, "reg", &host->cs); | |
214 | +@@ -2866,6 +2926,17 @@ static int qcom_nand_host_init_and_regis | |
215 | + if (ret) | |
216 | + nand_cleanup(chip); | |
217 | + | |
218 | ++ if (nandc->props->has_boot_pages && | |
219 | ++ of_property_read_bool(dn, "nand-is-boot-medium")) { | |
220 | ++ ret = of_property_read_u32(dn, "qcom,boot_pages_size", | |
221 | ++ &boot_pages_size); | |
222 | ++ if (ret) | |
223 | ++ dev_warn(dev, "can't get boot pages size"); | |
224 | ++ else | |
225 | ++ /* Convert size to nand pages */ | |
226 | ++ host->boot_pages = boot_pages_size / mtd->writesize; | |
227 | ++ } | |
228 | ++ | |
229 | + return ret; | |
230 | + } | |
231 | + | |
232 | +@@ -3032,6 +3103,7 @@ static int qcom_nandc_remove(struct plat | |
233 | + static const struct qcom_nandc_props ipq806x_nandc_props = { | |
234 | + .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT), | |
235 | + .is_bam = false, | |
236 | ++ .has_boot_pages = true, | |
237 | + .dev_cmd_reg_start = 0x0, | |
238 | + }; | |
239 | + |
@@ -0,0 +1,42 @@ | ||
1 | +From 6fb003a7a117f97a35b078ba726c84adeae29c4c Mon Sep 17 00:00:00 2001 | |
2 | +From: Ansuel Smith <ansuelsmth@gmail.com> | |
3 | +Date: Wed, 10 Feb 2021 10:54:19 +0100 | |
4 | +Subject: [PATCH 2/2] Documentation: devicetree: mtd: qcom_nandc: document | |
5 | + qcom,boot_layout_size binding | |
6 | + | |
7 | +Document new qcom,boot_layout_size binding used to apply special | |
8 | +read/write confituation to boots partitions. | |
9 | + | |
10 | +Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> | |
11 | +--- | |
12 | + Documentation/devicetree/bindings/mtd/qcom_nandc.txt | 11 +++++++++++ | |
13 | + 1 file changed, 11 insertions(+) | |
14 | + | |
15 | +--- a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt | |
16 | ++++ b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt | |
17 | +@@ -52,6 +52,15 @@ Optional properties: | |
18 | + be used according to chip requirement and available | |
19 | + OOB size. | |
20 | + | |
21 | ++EBI2 specific properties: | |
22 | ++- nand-is-boot-medium: nand contains boot partitions and different ecc configuration | |
23 | ++ should be used for these partitions. | |
24 | ++- qcom,boot_pages_size: should contain the size of the total boot partitions | |
25 | ++ where the boot layout read/write specific configuration | |
26 | ++ should be used. The boot layout is considered from the | |
27 | ++ start of the nand to the value set in this binding. | |
28 | ++ Only used in combination with 'nand-is-boot-medium'. | |
29 | ++ | |
30 | + Each nandcs device node may optionally contain a 'partitions' sub-node, which | |
31 | + further contains sub-nodes describing the flash partition mapping. See | |
32 | + partition.txt for more detail. | |
33 | +@@ -80,6 +89,9 @@ nand-controller@1ac00000 { | |
34 | + nand-ecc-strength = <4>; | |
35 | + nand-bus-width = <8>; | |
36 | + | |
37 | ++ nand-is-boot-medium; | |
38 | ++ qcom,boot_pages_size: <0x58a0000>; | |
39 | ++ | |
40 | + partitions { | |
41 | + compatible = "fixed-partitions"; | |
42 | + #address-cells = <1>; |