Commit 65e5cb54d017d60ec9d5de394715e5c95765f836
1 parent
f196044dfd
Exists in
v2017.01-smarct4x
and in
38 other branches
mtd, cfi, ubi: add missing writebufsize initialization
ff94bc40af3481d47546595ba73c136de6af6929 "mtd, ubi, ubifs: resync with Linux-3.14" introduced the writebufsize field in struct mtd_info, which is not initialized in the cfi_flash driver, which leads in not working ubi on cfi flashes. Fix it Signed-off-by: Heiko Schocher <hs@denx.de> Reported-by: Andrew Ruder <andrew.ruder@elecsyscorp.com> Acked-by: Stefan Roese <sr@denx.de> Acked-by: Andrew Ruder <andrew.ruder@elecsyscorp.com>
Showing 1 changed file with 1 additions and 0 deletions Inline Diff
drivers/mtd/cfi_mtd.c
1 | /* | 1 | /* |
2 | * (C) Copyright 2008 Semihalf | 2 | * (C) Copyright 2008 Semihalf |
3 | * | 3 | * |
4 | * Written by: Piotr Ziecik <kosmo@semihalf.com> | 4 | * Written by: Piotr Ziecik <kosmo@semihalf.com> |
5 | * | 5 | * |
6 | * SPDX-License-Identifier: GPL-2.0+ | 6 | * SPDX-License-Identifier: GPL-2.0+ |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <common.h> | 9 | #include <common.h> |
10 | #include <flash.h> | 10 | #include <flash.h> |
11 | #include <malloc.h> | 11 | #include <malloc.h> |
12 | 12 | ||
13 | #include <asm/errno.h> | 13 | #include <asm/errno.h> |
14 | #include <linux/mtd/mtd.h> | 14 | #include <linux/mtd/mtd.h> |
15 | #include <linux/mtd/concat.h> | 15 | #include <linux/mtd/concat.h> |
16 | #include <mtd/cfi_flash.h> | 16 | #include <mtd/cfi_flash.h> |
17 | 17 | ||
18 | static struct mtd_info cfi_mtd_info[CFI_MAX_FLASH_BANKS]; | 18 | static struct mtd_info cfi_mtd_info[CFI_MAX_FLASH_BANKS]; |
19 | static char cfi_mtd_names[CFI_MAX_FLASH_BANKS][16]; | 19 | static char cfi_mtd_names[CFI_MAX_FLASH_BANKS][16]; |
20 | #ifdef CONFIG_MTD_CONCAT | 20 | #ifdef CONFIG_MTD_CONCAT |
21 | static char c_mtd_name[16]; | 21 | static char c_mtd_name[16]; |
22 | #endif | 22 | #endif |
23 | 23 | ||
24 | static int cfi_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) | 24 | static int cfi_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) |
25 | { | 25 | { |
26 | flash_info_t *fi = mtd->priv; | 26 | flash_info_t *fi = mtd->priv; |
27 | size_t a_start = fi->start[0] + instr->addr; | 27 | size_t a_start = fi->start[0] + instr->addr; |
28 | size_t a_end = a_start + instr->len; | 28 | size_t a_end = a_start + instr->len; |
29 | int s_first = -1; | 29 | int s_first = -1; |
30 | int s_last = -1; | 30 | int s_last = -1; |
31 | int error, sect; | 31 | int error, sect; |
32 | 32 | ||
33 | for (sect = 0; sect < fi->sector_count; sect++) { | 33 | for (sect = 0; sect < fi->sector_count; sect++) { |
34 | if (a_start == fi->start[sect]) | 34 | if (a_start == fi->start[sect]) |
35 | s_first = sect; | 35 | s_first = sect; |
36 | 36 | ||
37 | if (sect < fi->sector_count - 1) { | 37 | if (sect < fi->sector_count - 1) { |
38 | if (a_end == fi->start[sect + 1]) { | 38 | if (a_end == fi->start[sect + 1]) { |
39 | s_last = sect; | 39 | s_last = sect; |
40 | break; | 40 | break; |
41 | } | 41 | } |
42 | } else { | 42 | } else { |
43 | s_last = sect; | 43 | s_last = sect; |
44 | break; | 44 | break; |
45 | } | 45 | } |
46 | } | 46 | } |
47 | 47 | ||
48 | if (s_first >= 0 && s_first <= s_last) { | 48 | if (s_first >= 0 && s_first <= s_last) { |
49 | instr->state = MTD_ERASING; | 49 | instr->state = MTD_ERASING; |
50 | 50 | ||
51 | flash_set_verbose(0); | 51 | flash_set_verbose(0); |
52 | error = flash_erase(fi, s_first, s_last); | 52 | error = flash_erase(fi, s_first, s_last); |
53 | flash_set_verbose(1); | 53 | flash_set_verbose(1); |
54 | 54 | ||
55 | if (error) { | 55 | if (error) { |
56 | instr->state = MTD_ERASE_FAILED; | 56 | instr->state = MTD_ERASE_FAILED; |
57 | return -EIO; | 57 | return -EIO; |
58 | } | 58 | } |
59 | 59 | ||
60 | instr->state = MTD_ERASE_DONE; | 60 | instr->state = MTD_ERASE_DONE; |
61 | mtd_erase_callback(instr); | 61 | mtd_erase_callback(instr); |
62 | return 0; | 62 | return 0; |
63 | } | 63 | } |
64 | 64 | ||
65 | return -EINVAL; | 65 | return -EINVAL; |
66 | } | 66 | } |
67 | 67 | ||
68 | static int cfi_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, | 68 | static int cfi_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, |
69 | size_t *retlen, u_char *buf) | 69 | size_t *retlen, u_char *buf) |
70 | { | 70 | { |
71 | flash_info_t *fi = mtd->priv; | 71 | flash_info_t *fi = mtd->priv; |
72 | u_char *f = (u_char*)(fi->start[0]) + from; | 72 | u_char *f = (u_char*)(fi->start[0]) + from; |
73 | 73 | ||
74 | memcpy(buf, f, len); | 74 | memcpy(buf, f, len); |
75 | *retlen = len; | 75 | *retlen = len; |
76 | 76 | ||
77 | return 0; | 77 | return 0; |
78 | } | 78 | } |
79 | 79 | ||
80 | static int cfi_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, | 80 | static int cfi_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, |
81 | size_t *retlen, const u_char *buf) | 81 | size_t *retlen, const u_char *buf) |
82 | { | 82 | { |
83 | flash_info_t *fi = mtd->priv; | 83 | flash_info_t *fi = mtd->priv; |
84 | u_long t = fi->start[0] + to; | 84 | u_long t = fi->start[0] + to; |
85 | int error; | 85 | int error; |
86 | 86 | ||
87 | flash_set_verbose(0); | 87 | flash_set_verbose(0); |
88 | error = write_buff(fi, (u_char*)buf, t, len); | 88 | error = write_buff(fi, (u_char*)buf, t, len); |
89 | flash_set_verbose(1); | 89 | flash_set_verbose(1); |
90 | 90 | ||
91 | if (!error) { | 91 | if (!error) { |
92 | *retlen = len; | 92 | *retlen = len; |
93 | return 0; | 93 | return 0; |
94 | } | 94 | } |
95 | 95 | ||
96 | return -EIO; | 96 | return -EIO; |
97 | } | 97 | } |
98 | 98 | ||
99 | static void cfi_mtd_sync(struct mtd_info *mtd) | 99 | static void cfi_mtd_sync(struct mtd_info *mtd) |
100 | { | 100 | { |
101 | /* | 101 | /* |
102 | * This function should wait until all pending operations | 102 | * This function should wait until all pending operations |
103 | * finish. However this driver is fully synchronous, so | 103 | * finish. However this driver is fully synchronous, so |
104 | * this function returns immediately | 104 | * this function returns immediately |
105 | */ | 105 | */ |
106 | } | 106 | } |
107 | 107 | ||
108 | static int cfi_mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | 108 | static int cfi_mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) |
109 | { | 109 | { |
110 | flash_info_t *fi = mtd->priv; | 110 | flash_info_t *fi = mtd->priv; |
111 | 111 | ||
112 | flash_set_verbose(0); | 112 | flash_set_verbose(0); |
113 | flash_protect(FLAG_PROTECT_SET, fi->start[0] + ofs, | 113 | flash_protect(FLAG_PROTECT_SET, fi->start[0] + ofs, |
114 | fi->start[0] + ofs + len - 1, fi); | 114 | fi->start[0] + ofs + len - 1, fi); |
115 | flash_set_verbose(1); | 115 | flash_set_verbose(1); |
116 | 116 | ||
117 | return 0; | 117 | return 0; |
118 | } | 118 | } |
119 | 119 | ||
120 | static int cfi_mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | 120 | static int cfi_mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) |
121 | { | 121 | { |
122 | flash_info_t *fi = mtd->priv; | 122 | flash_info_t *fi = mtd->priv; |
123 | 123 | ||
124 | flash_set_verbose(0); | 124 | flash_set_verbose(0); |
125 | flash_protect(FLAG_PROTECT_CLEAR, fi->start[0] + ofs, | 125 | flash_protect(FLAG_PROTECT_CLEAR, fi->start[0] + ofs, |
126 | fi->start[0] + ofs + len - 1, fi); | 126 | fi->start[0] + ofs + len - 1, fi); |
127 | flash_set_verbose(1); | 127 | flash_set_verbose(1); |
128 | 128 | ||
129 | return 0; | 129 | return 0; |
130 | } | 130 | } |
131 | 131 | ||
132 | static int cfi_mtd_set_erasesize(struct mtd_info *mtd, flash_info_t *fi) | 132 | static int cfi_mtd_set_erasesize(struct mtd_info *mtd, flash_info_t *fi) |
133 | { | 133 | { |
134 | int sect_size = 0; | 134 | int sect_size = 0; |
135 | int sect_size_old = 0; | 135 | int sect_size_old = 0; |
136 | int sect; | 136 | int sect; |
137 | int regions = 0; | 137 | int regions = 0; |
138 | int numblocks = 0; | 138 | int numblocks = 0; |
139 | ulong offset; | 139 | ulong offset; |
140 | ulong base_addr; | 140 | ulong base_addr; |
141 | 141 | ||
142 | /* | 142 | /* |
143 | * First detect the number of eraseregions so that we can allocate | 143 | * First detect the number of eraseregions so that we can allocate |
144 | * the array of eraseregions correctly | 144 | * the array of eraseregions correctly |
145 | */ | 145 | */ |
146 | for (sect = 0; sect < fi->sector_count; sect++) { | 146 | for (sect = 0; sect < fi->sector_count; sect++) { |
147 | if (sect_size_old != flash_sector_size(fi, sect)) | 147 | if (sect_size_old != flash_sector_size(fi, sect)) |
148 | regions++; | 148 | regions++; |
149 | sect_size_old = flash_sector_size(fi, sect); | 149 | sect_size_old = flash_sector_size(fi, sect); |
150 | } | 150 | } |
151 | 151 | ||
152 | switch (regions) { | 152 | switch (regions) { |
153 | case 0: | 153 | case 0: |
154 | return 1; | 154 | return 1; |
155 | case 1: /* flash has uniform erase size */ | 155 | case 1: /* flash has uniform erase size */ |
156 | mtd->numeraseregions = 0; | 156 | mtd->numeraseregions = 0; |
157 | mtd->erasesize = sect_size_old; | 157 | mtd->erasesize = sect_size_old; |
158 | return 0; | 158 | return 0; |
159 | } | 159 | } |
160 | 160 | ||
161 | mtd->numeraseregions = regions; | 161 | mtd->numeraseregions = regions; |
162 | mtd->eraseregions = malloc(sizeof(struct mtd_erase_region_info) * regions); | 162 | mtd->eraseregions = malloc(sizeof(struct mtd_erase_region_info) * regions); |
163 | 163 | ||
164 | /* | 164 | /* |
165 | * Now detect the largest sector and fill the eraseregions | 165 | * Now detect the largest sector and fill the eraseregions |
166 | */ | 166 | */ |
167 | regions = 0; | 167 | regions = 0; |
168 | base_addr = offset = fi->start[0]; | 168 | base_addr = offset = fi->start[0]; |
169 | sect_size_old = flash_sector_size(fi, 0); | 169 | sect_size_old = flash_sector_size(fi, 0); |
170 | for (sect = 0; sect < fi->sector_count; sect++) { | 170 | for (sect = 0; sect < fi->sector_count; sect++) { |
171 | if (sect_size_old != flash_sector_size(fi, sect)) { | 171 | if (sect_size_old != flash_sector_size(fi, sect)) { |
172 | mtd->eraseregions[regions].offset = offset - base_addr; | 172 | mtd->eraseregions[regions].offset = offset - base_addr; |
173 | mtd->eraseregions[regions].erasesize = sect_size_old; | 173 | mtd->eraseregions[regions].erasesize = sect_size_old; |
174 | mtd->eraseregions[regions].numblocks = numblocks; | 174 | mtd->eraseregions[regions].numblocks = numblocks; |
175 | /* Now start counting the next eraseregions */ | 175 | /* Now start counting the next eraseregions */ |
176 | numblocks = 0; | 176 | numblocks = 0; |
177 | regions++; | 177 | regions++; |
178 | offset = fi->start[sect]; | 178 | offset = fi->start[sect]; |
179 | } | 179 | } |
180 | numblocks++; | 180 | numblocks++; |
181 | 181 | ||
182 | /* | 182 | /* |
183 | * Select the largest sector size as erasesize (e.g. for UBI) | 183 | * Select the largest sector size as erasesize (e.g. for UBI) |
184 | */ | 184 | */ |
185 | if (flash_sector_size(fi, sect) > sect_size) | 185 | if (flash_sector_size(fi, sect) > sect_size) |
186 | sect_size = flash_sector_size(fi, sect); | 186 | sect_size = flash_sector_size(fi, sect); |
187 | 187 | ||
188 | sect_size_old = flash_sector_size(fi, sect); | 188 | sect_size_old = flash_sector_size(fi, sect); |
189 | } | 189 | } |
190 | 190 | ||
191 | /* | 191 | /* |
192 | * Set the last region | 192 | * Set the last region |
193 | */ | 193 | */ |
194 | mtd->eraseregions[regions].offset = offset - base_addr; | 194 | mtd->eraseregions[regions].offset = offset - base_addr; |
195 | mtd->eraseregions[regions].erasesize = sect_size_old; | 195 | mtd->eraseregions[regions].erasesize = sect_size_old; |
196 | mtd->eraseregions[regions].numblocks = numblocks; | 196 | mtd->eraseregions[regions].numblocks = numblocks; |
197 | 197 | ||
198 | mtd->erasesize = sect_size; | 198 | mtd->erasesize = sect_size; |
199 | 199 | ||
200 | return 0; | 200 | return 0; |
201 | } | 201 | } |
202 | 202 | ||
203 | int cfi_mtd_init(void) | 203 | int cfi_mtd_init(void) |
204 | { | 204 | { |
205 | struct mtd_info *mtd; | 205 | struct mtd_info *mtd; |
206 | flash_info_t *fi; | 206 | flash_info_t *fi; |
207 | int error, i; | 207 | int error, i; |
208 | #ifdef CONFIG_MTD_CONCAT | 208 | #ifdef CONFIG_MTD_CONCAT |
209 | int devices_found = 0; | 209 | int devices_found = 0; |
210 | struct mtd_info *mtd_list[CONFIG_SYS_MAX_FLASH_BANKS]; | 210 | struct mtd_info *mtd_list[CONFIG_SYS_MAX_FLASH_BANKS]; |
211 | #endif | 211 | #endif |
212 | 212 | ||
213 | for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { | 213 | for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { |
214 | fi = &flash_info[i]; | 214 | fi = &flash_info[i]; |
215 | mtd = &cfi_mtd_info[i]; | 215 | mtd = &cfi_mtd_info[i]; |
216 | 216 | ||
217 | memset(mtd, 0, sizeof(struct mtd_info)); | 217 | memset(mtd, 0, sizeof(struct mtd_info)); |
218 | 218 | ||
219 | error = cfi_mtd_set_erasesize(mtd, fi); | 219 | error = cfi_mtd_set_erasesize(mtd, fi); |
220 | if (error) | 220 | if (error) |
221 | continue; | 221 | continue; |
222 | 222 | ||
223 | sprintf(cfi_mtd_names[i], "nor%d", i); | 223 | sprintf(cfi_mtd_names[i], "nor%d", i); |
224 | mtd->name = cfi_mtd_names[i]; | 224 | mtd->name = cfi_mtd_names[i]; |
225 | mtd->type = MTD_NORFLASH; | 225 | mtd->type = MTD_NORFLASH; |
226 | mtd->flags = MTD_CAP_NORFLASH; | 226 | mtd->flags = MTD_CAP_NORFLASH; |
227 | mtd->size = fi->size; | 227 | mtd->size = fi->size; |
228 | mtd->writesize = 1; | 228 | mtd->writesize = 1; |
229 | mtd->writebufsize = mtd->writesize; | ||
229 | 230 | ||
230 | mtd->_erase = cfi_mtd_erase; | 231 | mtd->_erase = cfi_mtd_erase; |
231 | mtd->_read = cfi_mtd_read; | 232 | mtd->_read = cfi_mtd_read; |
232 | mtd->_write = cfi_mtd_write; | 233 | mtd->_write = cfi_mtd_write; |
233 | mtd->_sync = cfi_mtd_sync; | 234 | mtd->_sync = cfi_mtd_sync; |
234 | mtd->_lock = cfi_mtd_lock; | 235 | mtd->_lock = cfi_mtd_lock; |
235 | mtd->_unlock = cfi_mtd_unlock; | 236 | mtd->_unlock = cfi_mtd_unlock; |
236 | mtd->priv = fi; | 237 | mtd->priv = fi; |
237 | 238 | ||
238 | if (add_mtd_device(mtd)) | 239 | if (add_mtd_device(mtd)) |
239 | return -ENOMEM; | 240 | return -ENOMEM; |
240 | 241 | ||
241 | #ifdef CONFIG_MTD_CONCAT | 242 | #ifdef CONFIG_MTD_CONCAT |
242 | mtd_list[devices_found++] = mtd; | 243 | mtd_list[devices_found++] = mtd; |
243 | #endif | 244 | #endif |
244 | } | 245 | } |
245 | 246 | ||
246 | #ifdef CONFIG_MTD_CONCAT | 247 | #ifdef CONFIG_MTD_CONCAT |
247 | if (devices_found > 1) { | 248 | if (devices_found > 1) { |
248 | /* | 249 | /* |
249 | * We detected multiple devices. Concatenate them together. | 250 | * We detected multiple devices. Concatenate them together. |
250 | */ | 251 | */ |
251 | sprintf(c_mtd_name, "nor%d", devices_found); | 252 | sprintf(c_mtd_name, "nor%d", devices_found); |
252 | mtd = mtd_concat_create(mtd_list, devices_found, c_mtd_name); | 253 | mtd = mtd_concat_create(mtd_list, devices_found, c_mtd_name); |
253 | 254 | ||
254 | if (mtd == NULL) | 255 | if (mtd == NULL) |
255 | return -ENXIO; | 256 | return -ENXIO; |
256 | 257 | ||
257 | if (add_mtd_device(mtd)) | 258 | if (add_mtd_device(mtd)) |
258 | return -ENOMEM; | 259 | return -ENOMEM; |
259 | } | 260 | } |
260 | #endif /* CONFIG_MTD_CONCAT */ | 261 | #endif /* CONFIG_MTD_CONCAT */ |
261 | 262 | ||
262 | return 0; | 263 | return 0; |
263 | } | 264 | } |
264 | 265 |