blob: aa5c09e6065a8c7b12a2fbf0c9d1ebf22cd89bc3 [file] [log] [blame]
David Hendricksd1c55d72010-08-24 15:14:19 -07001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2010 Google Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
David Hendricksd1c55d72010-08-24 15:14:19 -070016 */
17
David Hendricksf7924d12010-06-10 21:26:44 -070018#include <stdlib.h>
19#include <string.h>
Edward O'Callaghanb4300ca2019-09-03 16:15:21 +100020#include <strings.h>
David Hendricksf7924d12010-06-10 21:26:44 -070021
22#include "flash.h"
23#include "flashchips.h"
24#include "chipdrivers.h"
Louis Yung-Chieh Lo52aa9302010-09-06 10:45:02 +080025#include "spi.h"
David Hendricks23cd7782010-08-25 12:42:38 -070026#include "writeprotect.h"
David Hendricksf7924d12010-06-10 21:26:44 -070027
David Hendricks1c09f802012-10-03 11:03:48 -070028/*
David Hendricksf7924d12010-06-10 21:26:44 -070029 * The following procedures rely on look-up tables to match the user-specified
30 * range with the chip's supported ranges. This turned out to be the most
31 * elegant approach since diferent flash chips use different levels of
32 * granularity and methods to determine protected ranges. In other words,
David Hendrickse0512a72014-07-15 20:30:47 -070033 * be stupid and simple since clever arithmetic will not work for many chips.
David Hendricksf7924d12010-06-10 21:26:44 -070034 */
35
36struct wp_range {
37 unsigned int start; /* starting address */
38 unsigned int len; /* len */
39};
40
41enum bit_state {
42 OFF = 0,
43 ON = 1,
Louis Yung-Chieh Loedd39302011-11-10 15:43:06 +080044 X = -1 /* don't care. Must be bigger than max # of bp. */
David Hendricksf7924d12010-06-10 21:26:44 -070045};
46
David Hendrickse0512a72014-07-15 20:30:47 -070047/*
48 * Generic write-protection schema for 25-series SPI flash chips. This assumes
49 * there is a status register that contains one or more consecutive bits which
50 * determine which address range is protected.
51 */
52
53struct status_register_layout {
54 int bp0_pos; /* position of BP0 */
55 int bp_bits; /* number of block protect bits */
56 int srp_pos; /* position of status register protect enable bit */
57};
58
Edward O'Callaghan91b38272019-12-04 17:12:43 +110059/*
60 * The following ranges and functions are useful for representing the
61 * writeprotect schema in which there are typically 5 bits of
62 * relevant information stored in status register 1:
63 * m.sec: This bit indicates the units (sectors vs. blocks)
64 * m.tb: The top-bottom bit indicates if the affected range is at the top of
65 * the flash memory's address space or at the bottom.
66 * bp: Bitmask representing the number of affected sectors/blocks.
67 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +110068struct wp_range_descriptor {
Edward O'Callaghan9c4c9a52019-12-04 18:18:01 +110069 struct modifier_bits m;
David Hendrickse0512a72014-07-15 20:30:47 -070070 unsigned int bp; /* block protect bitfield */
71 struct wp_range range;
72};
73
74struct generic_wp {
75 struct status_register_layout sr1; /* status register 1 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +110076 struct wp_range_descriptor *descrs;
David Hendricks148a4bf2015-03-13 21:02:42 -070077
78 /*
79 * Some chips store modifier bits in one or more special control
80 * registers instead of the status register like many older SPI NOR
81 * flash chips did. get_modifier_bits() and set_modifier_bits() will do
82 * any chip-specific operations necessary to get/set these bit values.
83 */
Souvik Ghoshd75cd672016-06-17 14:21:39 -070084 int (*get_modifier_bits)(const struct flashctx *flash,
Edward O'Callaghan9c4c9a52019-12-04 18:18:01 +110085 struct modifier_bits *m);
Souvik Ghoshd75cd672016-06-17 14:21:39 -070086 int (*set_modifier_bits)(const struct flashctx *flash,
Edward O'Callaghan9c4c9a52019-12-04 18:18:01 +110087 struct modifier_bits *m);
David Hendrickse0512a72014-07-15 20:30:47 -070088};
89
90/*
David Hendrickse0512a72014-07-15 20:30:47 -070091 * Mask to extract write-protect enable and range bits
92 * Status register 1:
93 * SRP0: bit 7
94 * range(BP2-BP0): bit 4-2
Duncan Laurie1801f7c2019-01-09 18:02:51 -080095 * range(BP3-BP0): bit 5-2 (large chips)
David Hendrickse0512a72014-07-15 20:30:47 -070096 * Status register 2:
97 * SRP1: bit 1
98 */
99#define MASK_WP_AREA (0x9C)
Duncan Laurie1801f7c2019-01-09 18:02:51 -0800100#define MASK_WP_AREA_LARGE (0x9C)
David Hendrickse0512a72014-07-15 20:30:47 -0700101#define MASK_WP2_AREA (0x01)
102
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100103struct wp_range_descriptor en25f40_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100104 { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
105 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 504 * 1024} },
106 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 496 * 1024} },
107 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 480 * 1024} },
108 { .m = { .sec = 0, .tb = 0 }, 0x4, {0x000000, 448 * 1024} },
109 { .m = { .sec = 0, .tb = 0 }, 0x5, {0x000000, 384 * 1024} },
110 { .m = { .sec = 0, .tb = 0 }, 0x6, {0x000000, 256 * 1024} },
111 { .m = { .sec = 0, .tb = 0 }, 0x7, {0x000000, 512 * 1024} },
David Hendricks57566ed2010-08-16 18:24:45 -0700112};
113
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100114struct wp_range_descriptor en25q40_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100115 { .m = { .sec = 0, .tb = 0 }, 0, {0, 0} }, /* none */
116 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 504 * 1024} },
117 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 496 * 1024} },
118 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 480 * 1024} },
David Hendrickse185bf22011-05-24 15:34:18 -0700119
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100120 { .m = { .sec = 0, .tb = 1 }, 0x0, {0x000000, 448 * 1024} },
121 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 384 * 1024} },
122 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 256 * 1024} },
123 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 512 * 1024} },
David Hendrickse185bf22011-05-24 15:34:18 -0700124};
125
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100126struct wp_range_descriptor en25q80_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100127 { .m = { .sec = 0, .tb = 0 }, 0, {0, 0} }, /* none */
128 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 1016 * 1024} },
129 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 1008 * 1024} },
130 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 992 * 1024} },
131 { .m = { .sec = 0, .tb = 0 }, 0x4, {0x000000, 960 * 1024} },
132 { .m = { .sec = 0, .tb = 0 }, 0x5, {0x000000, 896 * 1024} },
133 { .m = { .sec = 0, .tb = 0 }, 0x6, {0x000000, 768 * 1024} },
134 { .m = { .sec = 0, .tb = 0 }, 0x7, {0x000000, 1024 * 1024} },
David Hendrickse185bf22011-05-24 15:34:18 -0700135};
136
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100137struct wp_range_descriptor en25q32_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100138 { .m = { .sec = 0, .tb = 0 }, 0, {0, 0} }, /* none */
139 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 4032 * 1024} },
140 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 3968 * 1024} },
141 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 3840 * 1024} },
142 { .m = { .sec = 0, .tb = 0 }, 0x4, {0x000000, 3584 * 1024} },
143 { .m = { .sec = 0, .tb = 0 }, 0x5, {0x000000, 3072 * 1024} },
144 { .m = { .sec = 0, .tb = 0 }, 0x6, {0x000000, 2048 * 1024} },
145 { .m = { .sec = 0, .tb = 0 }, 0x7, {0x000000, 4096 * 1024} },
David Hendrickse185bf22011-05-24 15:34:18 -0700146
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100147 { .m = { .sec = 0, .tb = 1 }, 0, {0, 0} }, /* none */
148 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x010000, 4032 * 1024} },
149 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x020000, 3968 * 1024} },
150 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x040000, 3840 * 1024} },
151 { .m = { .sec = 0, .tb = 1 }, 0x4, {0x080000, 3584 * 1024} },
152 { .m = { .sec = 0, .tb = 1 }, 0x5, {0x100000, 3072 * 1024} },
153 { .m = { .sec = 0, .tb = 1 }, 0x6, {0x200000, 2048 * 1024} },
154 { .m = { .sec = 0, .tb = 1 }, 0x7, {0x000000, 4096 * 1024} },
David Hendrickse185bf22011-05-24 15:34:18 -0700155};
156
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100157struct wp_range_descriptor en25q64_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100158 { .m = { .sec = 0, .tb = 0 }, 0, {0, 0} }, /* none */
159 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 8128 * 1024} },
160 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 8064 * 1024} },
161 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 7936 * 1024} },
162 { .m = { .sec = 0, .tb = 0 }, 0x4, {0x000000, 7680 * 1024} },
163 { .m = { .sec = 0, .tb = 0 }, 0x5, {0x000000, 7168 * 1024} },
164 { .m = { .sec = 0, .tb = 0 }, 0x6, {0x000000, 6144 * 1024} },
165 { .m = { .sec = 0, .tb = 0 }, 0x7, {0x000000, 8192 * 1024} },
David Hendrickse185bf22011-05-24 15:34:18 -0700166
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100167 { .m = { .sec = 0, .tb = 1 }, 0, {0, 0} }, /* none */
168 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x010000, 8128 * 1024} },
169 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x020000, 8064 * 1024} },
170 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x040000, 7936 * 1024} },
171 { .m = { .sec = 0, .tb = 1 }, 0x4, {0x080000, 7680 * 1024} },
172 { .m = { .sec = 0, .tb = 1 }, 0x5, {0x100000, 7168 * 1024} },
173 { .m = { .sec = 0, .tb = 1 }, 0x6, {0x200000, 6144 * 1024} },
174 { .m = { .sec = 0, .tb = 1 }, 0x7, {0x000000, 8192 * 1024} },
David Hendrickse185bf22011-05-24 15:34:18 -0700175};
176
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100177struct wp_range_descriptor en25q128_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100178 { .m = { .sec = 0, .tb = 0 }, 0, {0, 0} }, /* none */
179 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 16320 * 1024} },
180 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 16256 * 1024} },
181 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 16128 * 1024} },
182 { .m = { .sec = 0, .tb = 0 }, 0x4, {0x000000, 15872 * 1024} },
183 { .m = { .sec = 0, .tb = 0 }, 0x5, {0x000000, 15360 * 1024} },
184 { .m = { .sec = 0, .tb = 0 }, 0x6, {0x000000, 14336 * 1024} },
185 { .m = { .sec = 0, .tb = 0 }, 0x7, {0x000000, 16384 * 1024} },
David Hendrickse185bf22011-05-24 15:34:18 -0700186
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100187 { .m = { .sec = 0, .tb = 1 }, 0, {0, 0} }, /* none */
188 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x010000, 16320 * 1024} },
189 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x020000, 16256 * 1024} },
190 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x040000, 16128 * 1024} },
191 { .m = { .sec = 0, .tb = 1 }, 0x4, {0x080000, 15872 * 1024} },
192 { .m = { .sec = 0, .tb = 1 }, 0x5, {0x100000, 15360 * 1024} },
193 { .m = { .sec = 0, .tb = 1 }, 0x6, {0x200000, 14336 * 1024} },
194 { .m = { .sec = 0, .tb = 1 }, 0x7, {0x000000, 16384 * 1024} },
David Hendrickse185bf22011-05-24 15:34:18 -0700195};
196
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100197struct wp_range_descriptor en25s64_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100198 { .m = { .sec = 0, .tb = 0 }, 0, {0, 0} }, /* none */
199 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 8064 * 1024} },
200 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 7936 * 1024} },
201 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 7680 * 1024} },
202 { .m = { .sec = 0, .tb = 0 }, 0x4, {0x000000, 7168 * 1024} },
203 { .m = { .sec = 0, .tb = 0 }, 0x5, {0x000000, 6144 * 1024} },
204 { .m = { .sec = 0, .tb = 0 }, 0x6, {0x000000, 4096 * 1024} },
205 { .m = { .sec = 0, .tb = 0 }, 0x7, {0x000000, 8192 * 1024} },
Marc Jonesb2f90022014-04-29 17:37:23 -0600206
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100207 { .m = { .sec = 0, .tb = 1 }, 0, {0, 0} }, /* none */
208 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x7e0000, 128 * 1024} },
209 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x7c0000, 256 * 1024} },
210 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x780000, 512 * 1024} },
211 { .m = { .sec = 0, .tb = 1 }, 0x4, {0x700000, 1024 * 1024} },
212 { .m = { .sec = 0, .tb = 1 }, 0x5, {0x600000, 2048 * 1024} },
213 { .m = { .sec = 0, .tb = 1 }, 0x6, {0x400000, 4096 * 1024} },
214 { .m = { .sec = 0, .tb = 1 }, 0x7, {0x000000, 8192 * 1024} },
Marc Jonesb2f90022014-04-29 17:37:23 -0600215};
216
David Hendricksf8f00c72011-02-01 12:39:46 -0800217/* mx25l1005 ranges also work for the mx25l1005c */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100218static struct wp_range_descriptor mx25l1005_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100219 { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
220 { .m = { .sec = X, .tb = X }, 0x1, {0x010000, 64 * 1024} },
221 { .m = { .sec = X, .tb = X }, 0x2, {0x000000, 128 * 1024} },
222 { .m = { .sec = X, .tb = X }, 0x3, {0x000000, 128 * 1024} },
David Hendricksf8f00c72011-02-01 12:39:46 -0800223};
224
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100225static struct wp_range_descriptor mx25l2005_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100226 { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
227 { .m = { .sec = X, .tb = X }, 0x1, {0x030000, 64 * 1024} },
228 { .m = { .sec = X, .tb = X }, 0x2, {0x020000, 128 * 1024} },
229 { .m = { .sec = X, .tb = X }, 0x3, {0x000000, 256 * 1024} },
David Hendricksf8f00c72011-02-01 12:39:46 -0800230};
231
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100232static struct wp_range_descriptor mx25l4005_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100233 { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
234 { .m = { .sec = X, .tb = X }, 0x1, {0x070000, 64 * 1 * 1024} }, /* block 7 */
235 { .m = { .sec = X, .tb = X }, 0x2, {0x060000, 64 * 2 * 1024} }, /* blocks 6-7 */
236 { .m = { .sec = X, .tb = X }, 0x3, {0x040000, 64 * 4 * 1024} }, /* blocks 4-7 */
237 { .m = { .sec = X, .tb = X }, 0x4, {0x000000, 512 * 1024} },
238 { .m = { .sec = X, .tb = X }, 0x5, {0x000000, 512 * 1024} },
239 { .m = { .sec = X, .tb = X }, 0x6, {0x000000, 512 * 1024} },
240 { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 512 * 1024} },
David Hendricksf8f00c72011-02-01 12:39:46 -0800241};
242
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100243static struct wp_range_descriptor mx25l8005_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100244 { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
245 { .m = { .sec = X, .tb = X }, 0x1, {0x0f0000, 64 * 1 * 1024} }, /* block 15 */
246 { .m = { .sec = X, .tb = X }, 0x2, {0x0e0000, 64 * 2 * 1024} }, /* blocks 14-15 */
247 { .m = { .sec = X, .tb = X }, 0x3, {0x0c0000, 64 * 4 * 1024} }, /* blocks 12-15 */
248 { .m = { .sec = X, .tb = X }, 0x4, {0x080000, 64 * 8 * 1024} }, /* blocks 8-15 */
249 { .m = { .sec = X, .tb = X }, 0x5, {0x000000, 1024 * 1024} },
250 { .m = { .sec = X, .tb = X }, 0x6, {0x000000, 1024 * 1024} },
251 { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 1024 * 1024} },
David Hendricksf8f00c72011-02-01 12:39:46 -0800252};
253
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100254static struct wp_range_descriptor mx25l1605d_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100255 { .m = { .sec = X, .tb = 0 }, 0, {0, 0} }, /* none */
256 { .m = { .sec = X, .tb = 0 }, 0x1, {0x1f0000, 64 * 1 * 1024} }, /* block 31 */
257 { .m = { .sec = X, .tb = 0 }, 0x2, {0x1e0000, 64 * 2 * 1024} }, /* blocks 30-31 */
258 { .m = { .sec = X, .tb = 0 }, 0x3, {0x1c0000, 64 * 4 * 1024} }, /* blocks 28-31 */
259 { .m = { .sec = X, .tb = 0 }, 0x4, {0x180000, 64 * 8 * 1024} }, /* blocks 24-31 */
260 { .m = { .sec = X, .tb = 0 }, 0x5, {0x100000, 64 * 16 * 1024} }, /* blocks 16-31 */
261 { .m = { .sec = X, .tb = 0 }, 0x6, {0x000000, 64 * 32 * 1024} }, /* blocks 0-31 */
262 { .m = { .sec = X, .tb = 0 }, 0x7, {0x000000, 64 * 32 * 1024} }, /* blocks 0-31 */
David Hendricksf8f00c72011-02-01 12:39:46 -0800263
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100264 { .m = { .sec = X, .tb = 1 }, 0x0, {0x000000, 2048 * 1024} },
265 { .m = { .sec = X, .tb = 1 }, 0x1, {0x000000, 2048 * 1024} },
266 { .m = { .sec = X, .tb = 1 }, 0x2, {0x000000, 64 * 16 * 1024} }, /* blocks 0-15 */
267 { .m = { .sec = X, .tb = 1 }, 0x3, {0x000000, 64 * 24 * 1024} }, /* blocks 0-23 */
268 { .m = { .sec = X, .tb = 1 }, 0x4, {0x000000, 64 * 28 * 1024} }, /* blocks 0-27 */
269 { .m = { .sec = X, .tb = 1 }, 0x5, {0x000000, 64 * 30 * 1024} }, /* blocks 0-29 */
270 { .m = { .sec = X, .tb = 1 }, 0x6, {0x000000, 64 * 31 * 1024} }, /* blocks 0-30 */
271 { .m = { .sec = X, .tb = 1 }, 0x7, {0x000000, 64 * 32 * 1024} }, /* blocks 0-31 */
David Hendricksf8f00c72011-02-01 12:39:46 -0800272};
273
274/* FIXME: Is there an mx25l3205 (without a trailing letter)? */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100275static struct wp_range_descriptor mx25l3205d_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100276 { .m = { .sec = X, .tb = 0 }, 0, {0, 0} }, /* none */
277 { .m = { .sec = X, .tb = 0 }, 0x1, {0x3f0000, 64 * 1024} },
278 { .m = { .sec = X, .tb = 0 }, 0x2, {0x3e0000, 128 * 1024} },
279 { .m = { .sec = X, .tb = 0 }, 0x3, {0x3c0000, 256 * 1024} },
280 { .m = { .sec = X, .tb = 0 }, 0x4, {0x380000, 512 * 1024} },
281 { .m = { .sec = X, .tb = 0 }, 0x5, {0x300000, 1024 * 1024} },
282 { .m = { .sec = X, .tb = 0 }, 0x6, {0x200000, 2048 * 1024} },
283 { .m = { .sec = X, .tb = 0 }, 0x7, {0x000000, 4096 * 1024} },
David Hendricksac72e362010-08-16 18:20:03 -0700284
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100285 { .m = { .sec = X, .tb = 1 }, 0x0, {0x000000, 4096 * 1024} },
286 { .m = { .sec = X, .tb = 1 }, 0x1, {0x000000, 2048 * 1024} },
287 { .m = { .sec = X, .tb = 1 }, 0x2, {0x000000, 3072 * 1024} },
288 { .m = { .sec = X, .tb = 1 }, 0x3, {0x000000, 3584 * 1024} },
289 { .m = { .sec = X, .tb = 1 }, 0x4, {0x000000, 3840 * 1024} },
290 { .m = { .sec = X, .tb = 1 }, 0x5, {0x000000, 3968 * 1024} },
291 { .m = { .sec = X, .tb = 1 }, 0x6, {0x000000, 4032 * 1024} },
292 { .m = { .sec = X, .tb = 1 }, 0x7, {0x000000, 4096 * 1024} },
David Hendricksac72e362010-08-16 18:20:03 -0700293};
294
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100295static struct wp_range_descriptor mx25u3235e_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100296 { .m = { .sec = X, .tb = 0 }, 0, {0, 0} }, /* none */
297 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x3f0000, 64 * 1024} },
298 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x3e0000, 128 * 1024} },
299 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x3c0000, 256 * 1024} },
300 { .m = { .sec = 0, .tb = 0 }, 0x4, {0x380000, 512 * 1024} },
301 { .m = { .sec = 0, .tb = 0 }, 0x5, {0x300000, 1024 * 1024} },
302 { .m = { .sec = 0, .tb = 0 }, 0x6, {0x200000, 2048 * 1024} },
303 { .m = { .sec = 0, .tb = 0 }, 0x7, {0x000000, 4096 * 1024} },
Vincent Palatin87e092a2013-02-28 15:46:14 -0800304
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100305 { .m = { .sec = 0, .tb = 1 }, 0x0, {0x000000, 4096 * 1024} },
306 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 2048 * 1024} },
307 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 3072 * 1024} },
308 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 3584 * 1024} },
309 { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 3840 * 1024} },
310 { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 3968 * 1024} },
311 { .m = { .sec = 0, .tb = 1 }, 0x6, {0x000000, 4032 * 1024} },
312 { .m = { .sec = 0, .tb = 1 }, 0x7, {0x000000, 4096 * 1024} },
Vincent Palatin87e092a2013-02-28 15:46:14 -0800313};
314
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100315static struct wp_range_descriptor mx25u6435e_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100316 { .m = { .sec = X, .tb = 0 }, 0, {0, 0} }, /* none */
317 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x7f0000, 1 * 64 * 1024} }, /* block 127 */
318 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x7e0000, 2 * 64 * 1024} }, /* blocks 126-127 */
319 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x7c0000, 4 * 64 * 1024} }, /* blocks 124-127 */
320 { .m = { .sec = 0, .tb = 0 }, 0x4, {0x780000, 8 * 64 * 1024} }, /* blocks 120-127 */
321 { .m = { .sec = 0, .tb = 0 }, 0x5, {0x700000, 16 * 64 * 1024} }, /* blocks 112-127 */
322 { .m = { .sec = 0, .tb = 0 }, 0x6, {0x600000, 32 * 64 * 1024} }, /* blocks 96-127 */
323 { .m = { .sec = 0, .tb = 0 }, 0x7, {0x400000, 64 * 64 * 1024} }, /* blocks 64-127 */
Jongpil66a96492014-08-14 17:59:06 +0900324
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100325 { .m = { .sec = 0, .tb = 1 }, 0x0, {0x000000, 64 * 64 * 1024} }, /* blocks 0-63 */
326 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 96 * 64 * 1024} }, /* blocks 0-95 */
327 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 112 * 64 * 1024} }, /* blocks 0-111 */
328 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 120 * 64 * 1024} }, /* blocks 0-119 */
329 { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 124 * 64 * 1024} }, /* blocks 0-123 */
330 { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 126 * 64 * 1024} }, /* blocks 0-125 */
331 { .m = { .sec = 0, .tb = 1 }, 0x6, {0x000000, 127 * 64 * 1024} }, /* blocks 0-126 */
332 { .m = { .sec = 0, .tb = 1 }, 0x7, {0x000000, 128 * 64 * 1024} }, /* blocks 0-127 */
Jongpil66a96492014-08-14 17:59:06 +0900333};
334
Karthikeyan Ramasubramanianfb166b72019-06-24 12:38:55 -0600335#define MX25U12835E_TB (1 << 3)
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100336static struct wp_range_descriptor mx25u12835e_tb0_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100337 { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
338 { .m = { .sec = 0, .tb = 0 }, 0x1, {0xff0000, 1 * 64 * 1024} }, /* block 255 */
339 { .m = { .sec = 0, .tb = 0 }, 0x2, {0xfe0000, 2 * 64 * 1024} }, /* blocks 254-255 */
340 { .m = { .sec = 0, .tb = 0 }, 0x3, {0xfc0000, 4 * 64 * 1024} }, /* blocks 252-255 */
341 { .m = { .sec = 0, .tb = 0 }, 0x4, {0xf80000, 8 * 64 * 1024} }, /* blocks 248-255 */
342 { .m = { .sec = 0, .tb = 0 }, 0x5, {0xf00000, 16 * 64 * 1024} }, /* blocks 240-255 */
343 { .m = { .sec = 0, .tb = 0 }, 0x6, {0xe00000, 32 * 64 * 1024} }, /* blocks 224-255 */
344 { .m = { .sec = 0, .tb = 0 }, 0x7, {0xc00000, 64 * 64 * 1024} }, /* blocks 192-255 */
345 { .m = { .sec = 0, .tb = 0 }, 0x8, {0x800000, 128 * 64 * 1024} }, /* blocks 128-255 */
346 { .m = { .sec = 0, .tb = 0 }, 0x9, {0x000000, 256 * 64 * 1024} }, /* blocks all */
347 { .m = { .sec = 0, .tb = 0 }, 0xa, {0x000000, 256 * 64 * 1024} }, /* blocks all */
348 { .m = { .sec = 0, .tb = 0 }, 0xb, {0x000000, 256 * 64 * 1024} }, /* blocks all */
349 { .m = { .sec = 0, .tb = 0 }, 0xc, {0x000000, 256 * 64 * 1024} }, /* blocks all */
350 { .m = { .sec = 0, .tb = 0 }, 0xd, {0x000000, 256 * 64 * 1024} }, /* blocks all */
351 { .m = { .sec = 0, .tb = 0 }, 0xe, {0x000000, 256 * 64 * 1024} }, /* blocks all */
352 { .m = { .sec = 0, .tb = 0 }, 0xf, {0x000000, 256 * 64 * 1024} }, /* blocks all */
Karthikeyan Ramasubramanianfb166b72019-06-24 12:38:55 -0600353};
Alex Lu831c6092017-11-02 23:19:34 -0700354
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100355static struct wp_range_descriptor mx25u12835e_tb1_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100356 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 1 * 64 * 1024} }, /* block 0 */
357 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 2 * 64 * 1024} }, /* blocks 0-1 */
358 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 4 * 64 * 1024} }, /* blocks 0-3 */
359 { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 8 * 64 * 1024} }, /* blocks 0-7 */
360 { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 16 * 64 * 1024} }, /* blocks 0-15 */
361 { .m = { .sec = 0, .tb = 1 }, 0x6, {0x000000, 32 * 64 * 1024} }, /* blocks 0-31 */
362 { .m = { .sec = 0, .tb = 1 }, 0x7, {0x000000, 64 * 64 * 1024} }, /* blocks 0-63 */
363 { .m = { .sec = 0, .tb = 1 }, 0x8, {0x000000, 128 * 64 * 1024} }, /* blocks 0-127 */
364 { .m = { .sec = 0, .tb = 1 }, 0x9, {0x000000, 256 * 64 * 1024} }, /* blocks all */
365 { .m = { .sec = 0, .tb = 1 }, 0xa, {0x000000, 256 * 64 * 1024} }, /* blocks all */
366 { .m = { .sec = 0, .tb = 1 }, 0xb, {0x000000, 256 * 64 * 1024} }, /* blocks all */
367 { .m = { .sec = 0, .tb = 1 }, 0xc, {0x000000, 256 * 64 * 1024} }, /* blocks all */
368 { .m = { .sec = 0, .tb = 1 }, 0xd, {0x000000, 256 * 64 * 1024} }, /* blocks all */
369 { .m = { .sec = 0, .tb = 1 }, 0xe, {0x000000, 256 * 64 * 1024} }, /* blocks all */
370 { .m = { .sec = 0, .tb = 1 }, 0xf, {0x000000, 256 * 64 * 1024} }, /* blocks all */
Alex Lu831c6092017-11-02 23:19:34 -0700371};
372
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100373static struct wp_range_descriptor n25q064_ranges[] = {
David Hendricksfe9123b2015-04-21 13:18:31 -0700374 /*
375 * Note: For N25Q064, sec (usually in bit position 6) is called BP3
376 * (block protect bit 3). It is only useful when all blocks are to
377 * be write-protected.
378 */
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100379 { .m = { .sec = 0, .tb = 0 }, 0, {0, 0} }, /* none */
David Hendricksbfa624b2012-07-24 12:47:59 -0700380
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100381 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x7f0000, 64 * 1024} }, /* block 127 */
382 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x7e0000, 2 * 64 * 1024} }, /* blocks 126-127 */
383 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x7c0000, 4 * 64 * 1024} }, /* blocks 124-127 */
384 { .m = { .sec = 0, .tb = 0 }, 0x4, {0x780000, 8 * 64 * 1024} }, /* blocks 120-127 */
385 { .m = { .sec = 0, .tb = 0 }, 0x5, {0x700000, 16 * 64 * 1024} }, /* blocks 112-127 */
386 { .m = { .sec = 0, .tb = 0 }, 0x6, {0x600000, 32 * 64 * 1024} }, /* blocks 96-127 */
387 { .m = { .sec = 0, .tb = 0 }, 0x7, {0x400000, 64 * 64 * 1024} }, /* blocks 64-127 */
David Hendricksbfa624b2012-07-24 12:47:59 -0700388
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100389 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} }, /* block 0 */
390 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 2 * 64 * 1024} }, /* blocks 0-1 */
391 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 4 * 64 * 1024} }, /* blocks 0-3 */
392 { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 8 * 64 * 1024} }, /* blocks 0-7 */
393 { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 16 * 64 * 1024} }, /* blocks 0-15 */
394 { .m = { .sec = 0, .tb = 1 }, 0x6, {0x000000, 32 * 64 * 1024} }, /* blocks 0-31 */
395 { .m = { .sec = 0, .tb = 1 }, 0x7, {0x000000, 64 * 64 * 1024} }, /* blocks 0-63 */
David Hendricksbfa624b2012-07-24 12:47:59 -0700396
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100397 { .m = { .sec = X, .tb = 1 }, 0x0, {0x000000, 128 * 64 * 1024} }, /* all */
398 { .m = { .sec = X, .tb = 1 }, 0x1, {0x000000, 128 * 64 * 1024} }, /* all */
399 { .m = { .sec = X, .tb = 1 }, 0x2, {0x000000, 128 * 64 * 1024} }, /* all */
400 { .m = { .sec = X, .tb = 1 }, 0x3, {0x000000, 128 * 64 * 1024} }, /* all */
401 { .m = { .sec = X, .tb = 1 }, 0x4, {0x000000, 128 * 64 * 1024} }, /* all */
402 { .m = { .sec = X, .tb = 1 }, 0x5, {0x000000, 128 * 64 * 1024} }, /* all */
403 { .m = { .sec = X, .tb = 1 }, 0x6, {0x000000, 128 * 64 * 1024} }, /* all */
404 { .m = { .sec = X, .tb = 1 }, 0x7, {0x000000, 128 * 64 * 1024} }, /* all */
David Hendricksbfa624b2012-07-24 12:47:59 -0700405};
406
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100407static struct wp_range_descriptor w25q16_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100408 { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
409 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x1f0000, 64 * 1024} },
410 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x1e0000, 128 * 1024} },
411 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x1c0000, 256 * 1024} },
412 { .m = { .sec = 0, .tb = 0 }, 0x4, {0x180000, 512 * 1024} },
413 { .m = { .sec = 0, .tb = 0 }, 0x5, {0x100000, 1024 * 1024} },
David Hendricksf7924d12010-06-10 21:26:44 -0700414
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100415 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} },
416 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 128 * 1024} },
417 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 256 * 1024} },
418 { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 512 * 1024} },
419 { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 1024 * 1024} },
420 { .m = { .sec = X, .tb = X }, 0x6, {0x000000, 2048 * 1024} },
421 { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 2048 * 1024} },
David Hendricksf7924d12010-06-10 21:26:44 -0700422
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100423 { .m = { .sec = 1, .tb = 0 }, 0x1, {0x1ff000, 4 * 1024} },
424 { .m = { .sec = 1, .tb = 0 }, 0x2, {0x1fe000, 8 * 1024} },
425 { .m = { .sec = 1, .tb = 0 }, 0x3, {0x1fc000, 16 * 1024} },
426 { .m = { .sec = 1, .tb = 0 }, 0x4, {0x1f8000, 32 * 1024} },
427 { .m = { .sec = 1, .tb = 0 }, 0x5, {0x1f8000, 32 * 1024} },
David Hendricksf7924d12010-06-10 21:26:44 -0700428
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100429 { .m = { .sec = 1, .tb = 1 }, 0x1, {0x000000, 4 * 1024} },
430 { .m = { .sec = 1, .tb = 1 }, 0x2, {0x000000, 8 * 1024} },
431 { .m = { .sec = 1, .tb = 1 }, 0x3, {0x000000, 16 * 1024} },
432 { .m = { .sec = 1, .tb = 1 }, 0x4, {0x000000, 32 * 1024} },
433 { .m = { .sec = 1, .tb = 1 }, 0x5, {0x000000, 32 * 1024} },
David Hendricksf7924d12010-06-10 21:26:44 -0700434};
435
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100436static struct wp_range_descriptor w25q32_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100437 { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
438 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x3f0000, 64 * 1024} },
439 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x3e0000, 128 * 1024} },
440 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x3c0000, 256 * 1024} },
441 { .m = { .sec = 0, .tb = 0 }, 0x4, {0x380000, 512 * 1024} },
442 { .m = { .sec = 0, .tb = 0 }, 0x5, {0x300000, 1024 * 1024} },
443 { .m = { .sec = 0, .tb = 0 }, 0x6, {0x200000, 2048 * 1024} },
David Hendricksf7924d12010-06-10 21:26:44 -0700444
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100445 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} },
446 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 128 * 1024} },
447 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 256 * 1024} },
448 { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 512 * 1024} },
449 { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 1024 * 1024} },
450 { .m = { .sec = 0, .tb = 1 }, 0x6, {0x000000, 2048 * 1024} },
451 { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 4096 * 1024} },
David Hendricksf7924d12010-06-10 21:26:44 -0700452
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100453 { .m = { .sec = 1, .tb = 0 }, 0x1, {0x3ff000, 4 * 1024} },
454 { .m = { .sec = 1, .tb = 0 }, 0x2, {0x3fe000, 8 * 1024} },
455 { .m = { .sec = 1, .tb = 0 }, 0x3, {0x3fc000, 16 * 1024} },
456 { .m = { .sec = 1, .tb = 0 }, 0x4, {0x3f8000, 32 * 1024} },
457 { .m = { .sec = 1, .tb = 0 }, 0x5, {0x3f8000, 32 * 1024} },
David Hendricksf7924d12010-06-10 21:26:44 -0700458
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100459 { .m = { .sec = 1, .tb = 1 }, 0x1, {0x000000, 4 * 1024} },
460 { .m = { .sec = 1, .tb = 1 }, 0x2, {0x000000, 8 * 1024} },
461 { .m = { .sec = 1, .tb = 1 }, 0x3, {0x000000, 16 * 1024} },
462 { .m = { .sec = 1, .tb = 1 }, 0x4, {0x000000, 32 * 1024} },
463 { .m = { .sec = 1, .tb = 1 }, 0x5, {0x000000, 32 * 1024} },
David Hendricksf7924d12010-06-10 21:26:44 -0700464};
465
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100466static struct wp_range_descriptor w25q80_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100467 { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
468 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x0f0000, 64 * 1024} },
469 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x0e0000, 128 * 1024} },
470 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x0c0000, 256 * 1024} },
471 { .m = { .sec = 0, .tb = 0 }, 0x4, {0x080000, 512 * 1024} },
David Hendricksf7924d12010-06-10 21:26:44 -0700472
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100473 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} },
474 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 128 * 1024} },
475 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 256 * 1024} },
476 { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 512 * 1024} },
477 { .m = { .sec = X, .tb = X }, 0x6, {0x000000, 1024 * 1024} },
478 { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 1024 * 1024} },
David Hendricksf7924d12010-06-10 21:26:44 -0700479
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100480 { .m = { .sec = 1, .tb = 0 }, 0x1, {0x1ff000, 4 * 1024} },
481 { .m = { .sec = 1, .tb = 0 }, 0x2, {0x1fe000, 8 * 1024} },
482 { .m = { .sec = 1, .tb = 0 }, 0x3, {0x1fc000, 16 * 1024} },
483 { .m = { .sec = 1, .tb = 0 }, 0x4, {0x1f8000, 32 * 1024} },
484 { .m = { .sec = 1, .tb = 0 }, 0x5, {0x1f8000, 32 * 1024} },
David Hendricksf7924d12010-06-10 21:26:44 -0700485
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100486 { .m = { .sec = 1, .tb = 1 }, 0x1, {0x000000, 4 * 1024} },
487 { .m = { .sec = 1, .tb = 1 }, 0x2, {0x000000, 8 * 1024} },
488 { .m = { .sec = 1, .tb = 1 }, 0x3, {0x000000, 16 * 1024} },
489 { .m = { .sec = 1, .tb = 1 }, 0x4, {0x000000, 32 * 1024} },
490 { .m = { .sec = 1, .tb = 1 }, 0x5, {0x000000, 32 * 1024} },
David Hendricksf7924d12010-06-10 21:26:44 -0700491};
492
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100493static struct wp_range_descriptor w25q64_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100494 { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
David Hendricks2c4a76c2010-06-28 14:00:43 -0700495
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100496 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x7e0000, 128 * 1024} },
497 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x7c0000, 256 * 1024} },
498 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x780000, 512 * 1024} },
499 { .m = { .sec = 0, .tb = 0 }, 0x4, {0x700000, 1024 * 1024} },
500 { .m = { .sec = 0, .tb = 0 }, 0x5, {0x600000, 2048 * 1024} },
501 { .m = { .sec = 0, .tb = 0 }, 0x6, {0x400000, 4096 * 1024} },
David Hendricks2c4a76c2010-06-28 14:00:43 -0700502
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100503 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 128 * 1024} },
504 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 256 * 1024} },
505 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 512 * 1024} },
506 { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 1024 * 1024} },
507 { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 2048 * 1024} },
508 { .m = { .sec = 0, .tb = 1 }, 0x6, {0x000000, 4096 * 1024} },
509 { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 8192 * 1024} },
David Hendricks2c4a76c2010-06-28 14:00:43 -0700510
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100511 { .m = { .sec = 1, .tb = 0 }, 0x1, {0x7ff000, 4 * 1024} },
512 { .m = { .sec = 1, .tb = 0 }, 0x2, {0x7fe000, 8 * 1024} },
513 { .m = { .sec = 1, .tb = 0 }, 0x3, {0x7fc000, 16 * 1024} },
514 { .m = { .sec = 1, .tb = 0 }, 0x4, {0x7f8000, 32 * 1024} },
515 { .m = { .sec = 1, .tb = 0 }, 0x5, {0x7f8000, 32 * 1024} },
David Hendricks2c4a76c2010-06-28 14:00:43 -0700516
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100517 { .m = { .sec = 1, .tb = 1 }, 0x1, {0x000000, 4 * 1024} },
518 { .m = { .sec = 1, .tb = 1 }, 0x2, {0x000000, 8 * 1024} },
519 { .m = { .sec = 1, .tb = 1 }, 0x3, {0x000000, 16 * 1024} },
520 { .m = { .sec = 1, .tb = 1 }, 0x4, {0x000000, 32 * 1024} },
521 { .m = { .sec = 1, .tb = 1 }, 0x5, {0x000000, 32 * 1024} },
David Hendricks2c4a76c2010-06-28 14:00:43 -0700522};
523
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100524static struct wp_range_descriptor w25rq128_cmp0_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100525 { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* NONE */
Ramya Vijaykumare6a7ca82015-05-12 14:27:29 +0530526
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100527 { .m = { .sec = 0, .tb = 0 }, 0x1, {0xfc0000, 256 * 1024} }, /* Upper 1/64 */
528 { .m = { .sec = 0, .tb = 0 }, 0x2, {0xf80000, 512 * 1024} }, /* Upper 1/32 */
529 { .m = { .sec = 0, .tb = 0 }, 0x3, {0xf00000, 1024 * 1024} }, /* Upper 1/16 */
530 { .m = { .sec = 0, .tb = 0 }, 0x4, {0xe00000, 2048 * 1024} }, /* Upper 1/8 */
531 { .m = { .sec = 0, .tb = 0 }, 0x5, {0xc00000, 4096 * 1024} }, /* Upper 1/4 */
532 { .m = { .sec = 0, .tb = 0 }, 0x6, {0x800000, 8192 * 1024} }, /* Upper 1/2 */
Ramya Vijaykumare6a7ca82015-05-12 14:27:29 +0530533
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100534 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 256 * 1024} }, /* Lower 1/64 */
535 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 512 * 1024} }, /* Lower 1/32 */
536 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 1024 * 1024} }, /* Lower 1/16 */
537 { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 2048 * 1024} }, /* Lower 1/8 */
538 { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 4096 * 1024} }, /* Lower 1/4 */
539 { .m = { .sec = 0, .tb = 1 }, 0x6, {0x000000, 8192 * 1024} }, /* Lower 1/2 */
Ramya Vijaykumare6a7ca82015-05-12 14:27:29 +0530540
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100541 { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 16384 * 1024} }, /* ALL */
Ramya Vijaykumare6a7ca82015-05-12 14:27:29 +0530542
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100543 { .m = { .sec = 1, .tb = 0 }, 0x1, {0xfff000, 4 * 1024} }, /* Upper 1/4096 */
544 { .m = { .sec = 1, .tb = 0 }, 0x2, {0xffe000, 8 * 1024} }, /* Upper 1/2048 */
545 { .m = { .sec = 1, .tb = 0 }, 0x3, {0xffc000, 16 * 1024} }, /* Upper 1/1024 */
546 { .m = { .sec = 1, .tb = 0 }, 0x4, {0xff8000, 32 * 1024} }, /* Upper 1/512 */
547 { .m = { .sec = 1, .tb = 0 }, 0x5, {0xff8000, 32 * 1024} }, /* Upper 1/512 */
Duncan Laurieed32d7b2015-05-27 11:28:18 -0700548
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100549 { .m = { .sec = 1, .tb = 1 }, 0x1, {0x000000, 4 * 1024} }, /* Lower 1/4096 */
550 { .m = { .sec = 1, .tb = 1 }, 0x2, {0x000000, 8 * 1024} }, /* Lower 1/2048 */
551 { .m = { .sec = 1, .tb = 1 }, 0x3, {0x000000, 16 * 1024} }, /* Lower 1/1024 */
552 { .m = { .sec = 1, .tb = 1 }, 0x4, {0x000000, 32 * 1024} }, /* Lower 1/512 */
553 { .m = { .sec = 1, .tb = 1 }, 0x5, {0x000000, 32 * 1024} }, /* Lower 1/512 */
Duncan Laurieed32d7b2015-05-27 11:28:18 -0700554};
555
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100556static struct wp_range_descriptor w25rq128_cmp1_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100557 { .m = { .sec = X, .tb = X }, 0x0, {0x000000, 16 * 1024 * 1024} }, /* ALL */
Duncan Laurieed32d7b2015-05-27 11:28:18 -0700558
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100559 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 16128 * 1024} }, /* Lower 63/64 */
560 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 15872 * 1024} }, /* Lower 31/32 */
561 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 15 * 1024 * 1024} }, /* Lower 15/16 */
562 { .m = { .sec = 0, .tb = 0 }, 0x4, {0x000000, 14 * 1024 * 1024} }, /* Lower 7/8 */
563 { .m = { .sec = 0, .tb = 0 }, 0x5, {0x000000, 12 * 1024 * 1024} }, /* Lower 3/4 */
564 { .m = { .sec = 0, .tb = 0 }, 0x6, {0x000000, 8 * 1024 * 1024} }, /* Lower 1/2 */
Duncan Laurieed32d7b2015-05-27 11:28:18 -0700565
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100566 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x040000, 16128 * 1024} }, /* Upper 63/64 */
567 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x080000, 15872 * 1024} }, /* Upper 31/32 */
568 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x100000, 15 * 1024 * 1024} }, /* Upper 15/16 */
569 { .m = { .sec = 0, .tb = 1 }, 0x4, {0x200000, 14 * 1024 * 1024} }, /* Upper 7/8 */
570 { .m = { .sec = 0, .tb = 1 }, 0x5, {0x400000, 12 * 1024 * 1024} }, /* Upper 3/4 */
571 { .m = { .sec = 0, .tb = 1 }, 0x6, {0x800000, 8 * 1024 * 1024} }, /* Upper 1/2 */
Duncan Laurieed32d7b2015-05-27 11:28:18 -0700572
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100573 { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 0} }, /* NONE */
Duncan Laurieed32d7b2015-05-27 11:28:18 -0700574
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100575 { .m = { .sec = 1, .tb = 0 }, 0x1, {0x000000, 16380 * 1024} }, /* Lower 4095/4096 */
576 { .m = { .sec = 1, .tb = 0 }, 0x2, {0x000000, 16376 * 1024} }, /* Lower 2048/2048 */
577 { .m = { .sec = 1, .tb = 0 }, 0x3, {0x000000, 16368 * 1024} }, /* Lower 1023/1024 */
578 { .m = { .sec = 1, .tb = 0 }, 0x4, {0x000000, 16352 * 1024} }, /* Lower 511/512 */
579 { .m = { .sec = 1, .tb = 0 }, 0x5, {0x000000, 16352 * 1024} }, /* Lower 511/512 */
Duncan Laurieed32d7b2015-05-27 11:28:18 -0700580
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100581 { .m = { .sec = 1, .tb = 1 }, 0x1, {0x001000, 16380 * 1024} }, /* Upper 4095/4096 */
582 { .m = { .sec = 1, .tb = 1 }, 0x2, {0x002000, 16376 * 1024} }, /* Upper 2047/2048 */
583 { .m = { .sec = 1, .tb = 1 }, 0x3, {0x004000, 16368 * 1024} }, /* Upper 1023/1024 */
584 { .m = { .sec = 1, .tb = 1 }, 0x4, {0x008000, 16352 * 1024} }, /* Upper 511/512 */
585 { .m = { .sec = 1, .tb = 1 }, 0x5, {0x008000, 16352 * 1024} }, /* Upper 511/512 */
Ramya Vijaykumare6a7ca82015-05-12 14:27:29 +0530586};
587
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100588static struct wp_range_descriptor w25rq256_cmp0_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100589 { .m = { .sec = X, .tb = X }, 0x0, {0x0000000, 0x0000000} }, /* NONE */
Duncan Laurie1801f7c2019-01-09 18:02:51 -0800590
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100591 { .m = { .sec = X, .tb = 0 }, 0x1, {0x1ff0000, 64 * 1 * 1024} }, /* Upper 1/512 */
592 { .m = { .sec = X, .tb = 0 }, 0x2, {0x1fe0000, 64 * 2 * 1024} }, /* Upper 1/256 */
593 { .m = { .sec = X, .tb = 0 }, 0x3, {0x1fc0000, 64 * 4 * 1024} }, /* Upper 1/128 */
594 { .m = { .sec = X, .tb = 0 }, 0x4, {0x1f80000, 64 * 8 * 1024} }, /* Upper 1/64 */
595 { .m = { .sec = X, .tb = 0 }, 0x5, {0x1f00000, 64 * 16 * 1024} }, /* Upper 1/32 */
596 { .m = { .sec = X, .tb = 0 }, 0x6, {0x1e00000, 64 * 32 * 1024} }, /* Upper 1/16 */
597 { .m = { .sec = X, .tb = 0 }, 0x7, {0x1c00000, 64 * 64 * 1024} }, /* Upper 1/8 */
598 { .m = { .sec = X, .tb = 0 }, 0x8, {0x1800000, 64 * 128 * 1024} }, /* Upper 1/4 */
599 { .m = { .sec = X, .tb = 0 }, 0x9, {0x1000000, 64 * 256 * 1024} }, /* Upper 1/2 */
Duncan Laurie1801f7c2019-01-09 18:02:51 -0800600
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100601 { .m = { .sec = X, .tb = 1 }, 0x1, {0x0000000, 64 * 1 * 1024} }, /* Lower 1/512 */
602 { .m = { .sec = X, .tb = 1 }, 0x2, {0x0000000, 64 * 2 * 1024} }, /* Lower 1/256 */
603 { .m = { .sec = X, .tb = 1 }, 0x3, {0x0000000, 64 * 4 * 1024} }, /* Lower 1/128 */
604 { .m = { .sec = X, .tb = 1 }, 0x4, {0x0000000, 64 * 8 * 1024} }, /* Lower 1/64 */
605 { .m = { .sec = X, .tb = 1 }, 0x5, {0x0000000, 64 * 16 * 1024} }, /* Lower 1/32 */
606 { .m = { .sec = X, .tb = 1 }, 0x6, {0x0000000, 64 * 32 * 1024} }, /* Lower 1/16 */
607 { .m = { .sec = X, .tb = 1 }, 0x7, {0x0000000, 64 * 64 * 1024} }, /* Lower 1/8 */
608 { .m = { .sec = X, .tb = 1 }, 0x8, {0x0000000, 64 * 128 * 1024} }, /* Lower 1/4 */
609 { .m = { .sec = X, .tb = 1 }, 0x9, {0x0000000, 64 * 256 * 1024} }, /* Lower 1/2 */
Duncan Laurie1801f7c2019-01-09 18:02:51 -0800610
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100611 { .m = { .sec = X, .tb = X }, 0xa, {0x0000000, 64 * 512 * 1024} }, /* ALL */
612 { .m = { .sec = X, .tb = X }, 0xb, {0x0000000, 64 * 512 * 1024} }, /* ALL */
613 { .m = { .sec = X, .tb = X }, 0xc, {0x0000000, 64 * 512 * 1024} }, /* ALL */
614 { .m = { .sec = X, .tb = X }, 0xd, {0x0000000, 64 * 512 * 1024} }, /* ALL */
615 { .m = { .sec = X, .tb = X }, 0xe, {0x0000000, 64 * 512 * 1024} }, /* ALL */
616 { .m = { .sec = X, .tb = X }, 0xf, {0x0000000, 64 * 512 * 1024} }, /* ALL */
Duncan Laurie1801f7c2019-01-09 18:02:51 -0800617};
618
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100619static struct wp_range_descriptor w25rq256_cmp1_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100620 { .m = { .sec = X, .tb = X }, 0x0, {0x0000000, 64 * 512 * 1024} }, /* ALL */
Duncan Laurie1801f7c2019-01-09 18:02:51 -0800621
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100622 { .m = { .sec = X, .tb = 0 }, 0x1, {0x0000000, 64 * 511 * 1024} }, /* Lower 511/512 */
623 { .m = { .sec = X, .tb = 0 }, 0x2, {0x0000000, 64 * 510 * 1024} }, /* Lower 255/256 */
624 { .m = { .sec = X, .tb = 0 }, 0x3, {0x0000000, 64 * 508 * 1024} }, /* Lower 127/128 */
625 { .m = { .sec = X, .tb = 0 }, 0x4, {0x0000000, 64 * 504 * 1024} }, /* Lower 63/64 */
626 { .m = { .sec = X, .tb = 0 }, 0x5, {0x0000000, 64 * 496 * 1024} }, /* Lower 31/32 */
627 { .m = { .sec = X, .tb = 0 }, 0x6, {0x0000000, 64 * 480 * 1024} }, /* Lower 15/16 */
628 { .m = { .sec = X, .tb = 0 }, 0x7, {0x0000000, 64 * 448 * 1024} }, /* Lower 7/8 */
629 { .m = { .sec = X, .tb = 0 }, 0x8, {0x0000000, 64 * 384 * 1024} }, /* Lower 3/4 */
630 { .m = { .sec = X, .tb = 0 }, 0x9, {0x0000000, 64 * 256 * 1024} }, /* Lower 1/2 */
Duncan Laurie1801f7c2019-01-09 18:02:51 -0800631
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100632 { .m = { .sec = X, .tb = 1 }, 0x1, {0x0010000, 64 * 511 * 1024} }, /* Upper 511/512 */
633 { .m = { .sec = X, .tb = 1 }, 0x2, {0x0020000, 64 * 510 * 1024} }, /* Upper 255/256 */
634 { .m = { .sec = X, .tb = 1 }, 0x3, {0x0040000, 64 * 508 * 1024} }, /* Upper 127/128 */
635 { .m = { .sec = X, .tb = 1 }, 0x4, {0x0080000, 64 * 504 * 1024} }, /* Upper 63/64 */
636 { .m = { .sec = X, .tb = 1 }, 0x5, {0x0100000, 64 * 496 * 1024} }, /* Upper 31/32 */
637 { .m = { .sec = X, .tb = 1 }, 0x6, {0x0200000, 64 * 480 * 1024} }, /* Upper 15/16 */
638 { .m = { .sec = X, .tb = 1 }, 0x7, {0x0400000, 64 * 448 * 1024} }, /* Upper 7/8 */
639 { .m = { .sec = X, .tb = 1 }, 0x8, {0x0800000, 64 * 384 * 1024} }, /* Upper 3/4 */
640 { .m = { .sec = X, .tb = 1 }, 0x9, {0x1000000, 64 * 256 * 1024} }, /* Upper 1/2 */
Duncan Laurie1801f7c2019-01-09 18:02:51 -0800641
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100642 { .m = { .sec = X, .tb = X }, 0xa, {0x0000000, 0x0000000} }, /* NONE */
643 { .m = { .sec = X, .tb = X }, 0xb, {0x0000000, 0x0000000} }, /* NONE */
644 { .m = { .sec = X, .tb = X }, 0xc, {0x0000000, 0x0000000} }, /* NONE */
645 { .m = { .sec = X, .tb = X }, 0xd, {0x0000000, 0x0000000} }, /* NONE */
646 { .m = { .sec = X, .tb = X }, 0xe, {0x0000000, 0x0000000} }, /* NONE */
647 { .m = { .sec = X, .tb = X }, 0xf, {0x0000000, 0x0000000} }, /* NONE */
Duncan Laurie1801f7c2019-01-09 18:02:51 -0800648};
649
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100650struct wp_range_descriptor w25x10_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100651 { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
652 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x010000, 64 * 1024} },
653 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} },
654 { .m = { .sec = X, .tb = X }, 0x2, {0x000000, 128 * 1024} },
655 { .m = { .sec = X, .tb = X }, 0x3, {0x000000, 128 * 1024} },
Louis Yung-Chieh Lo232951f2010-09-16 11:30:00 +0800656};
657
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100658struct wp_range_descriptor w25x20_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100659 { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
660 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x030000, 64 * 1024} },
661 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x020000, 128 * 1024} },
662 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} },
663 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 128 * 1024} },
664 { .m = { .sec = 0, .tb = X }, 0x3, {0x000000, 256 * 1024} },
Louis Yung-Chieh Lo232951f2010-09-16 11:30:00 +0800665};
666
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100667struct wp_range_descriptor w25x40_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100668 { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
669 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x070000, 64 * 1024} },
670 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x060000, 128 * 1024} },
671 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x040000, 256 * 1024} },
672 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} },
673 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 128 * 1024} },
674 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 256 * 1024} },
675 { .m = { .sec = 0, .tb = X }, 0x4, {0x000000, 512 * 1024} },
676 { .m = { .sec = 0, .tb = X }, 0x5, {0x000000, 512 * 1024} },
677 { .m = { .sec = 0, .tb = X }, 0x6, {0x000000, 512 * 1024} },
678 { .m = { .sec = 0, .tb = X }, 0x7, {0x000000, 512 * 1024} },
David Hendricks470ca952010-08-13 14:01:53 -0700679};
680
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100681struct wp_range_descriptor w25x80_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100682 { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
683 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x0F0000, 64 * 1024} },
684 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x0E0000, 128 * 1024} },
685 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x0C0000, 256 * 1024} },
686 { .m = { .sec = 0, .tb = 0 }, 0x4, {0x080000, 512 * 1024} },
687 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} },
688 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 128 * 1024} },
689 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 256 * 1024} },
690 { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 512 * 1024} },
691 { .m = { .sec = 0, .tb = X }, 0x5, {0x000000, 1024 * 1024} },
692 { .m = { .sec = 0, .tb = X }, 0x6, {0x000000, 1024 * 1024} },
693 { .m = { .sec = 0, .tb = X }, 0x7, {0x000000, 1024 * 1024} },
Louis Yung-Chieh Lo232951f2010-09-16 11:30:00 +0800694};
695
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100696static struct wp_range_descriptor gd25q40_cmp0_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100697 { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* None */
698 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x070000, 64 * 1024} },
699 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x060000, 128 * 1024} },
700 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x040000, 256 * 1024} },
701 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} },
702 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 128 * 1024} },
703 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 256 * 1024} },
704 { .m = { .sec = 0, .tb = X }, 0x4, {0x000000, 512 * 1024} }, /* All */
705 { .m = { .sec = 0, .tb = X }, 0x5, {0x000000, 512 * 1024} }, /* All */
706 { .m = { .sec = 0, .tb = X }, 0x6, {0x000000, 512 * 1024} }, /* All */
707 { .m = { .sec = 0, .tb = X }, 0x7, {0x000000, 512 * 1024} }, /* All */
708 { .m = { .sec = 1, .tb = 0 }, 0x1, {0x07F000, 4 * 1024} },
709 { .m = { .sec = 1, .tb = 0 }, 0x2, {0x07E000, 8 * 1024} },
710 { .m = { .sec = 1, .tb = 0 }, 0x3, {0x07C000, 16 * 1024} },
711 { .m = { .sec = 1, .tb = 0 }, 0x4, {0x078000, 32 * 1024} },
712 { .m = { .sec = 1, .tb = 0 }, 0x5, {0x078000, 32 * 1024} },
713 { .m = { .sec = 1, .tb = 0 }, 0x6, {0x078000, 32 * 1024} },
714 { .m = { .sec = 1, .tb = 1 }, 0x1, {0x000000, 4 * 1024} },
715 { .m = { .sec = 1, .tb = 1 }, 0x2, {0x000000, 8 * 1024} },
716 { .m = { .sec = 1, .tb = 1 }, 0x3, {0x000000, 16 * 1024} },
717 { .m = { .sec = 1, .tb = 1 }, 0x4, {0x000000, 32 * 1024} },
718 { .m = { .sec = 1, .tb = 1 }, 0x5, {0x000000, 32 * 1024} },
719 { .m = { .sec = 1, .tb = 1 }, 0x6, {0x000000, 32 * 1024} },
720 { .m = { .sec = 1, .tb = X }, 0x7, {0x000000, 512 * 1024} }, /* All */
Martin Rothf3c3d5f2017-04-28 14:56:41 -0600721};
722
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100723static struct wp_range_descriptor gd25q40_cmp1_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100724 { .m = { .sec = X, .tb = X }, 0x0, {0x000000, 512 * 1024} }, /* ALL */
725 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 448 * 1024} },
726 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 384 * 1024} },
727 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 256 * 1024} },
Martin Rothf3c3d5f2017-04-28 14:56:41 -0600728
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100729 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x010000, 448 * 1024} },
730 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x020000, 384 * 1024} },
731 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x040000, 256 * 1024} },
Martin Rothf3c3d5f2017-04-28 14:56:41 -0600732
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100733 { .m = { .sec = 0, .tb = X }, 0x4, {0x000000, 0} }, /* None */
734 { .m = { .sec = 0, .tb = X }, 0x5, {0x000000, 0} }, /* None */
735 { .m = { .sec = 0, .tb = X }, 0x6, {0x000000, 0} }, /* None */
736 { .m = { .sec = 0, .tb = X }, 0x7, {0x000000, 0} }, /* None */
Martin Rothf3c3d5f2017-04-28 14:56:41 -0600737
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100738 { .m = { .sec = 1, .tb = 0 }, 0x1, {0x000000, 508 * 1024} },
739 { .m = { .sec = 1, .tb = 0 }, 0x2, {0x000000, 504 * 1024} },
740 { .m = { .sec = 1, .tb = 0 }, 0x3, {0x000000, 496 * 1024} },
741 { .m = { .sec = 1, .tb = 0 }, 0x4, {0x000000, 480 * 1024} },
742 { .m = { .sec = 1, .tb = 0 }, 0x5, {0x000000, 480 * 1024} },
743 { .m = { .sec = 1, .tb = 0 }, 0x6, {0x000000, 480 * 1024} },
Martin Rothf3c3d5f2017-04-28 14:56:41 -0600744
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100745 { .m = { .sec = 1, .tb = 1 }, 0x1, {0x001000, 508 * 1024} },
746 { .m = { .sec = 1, .tb = 1 }, 0x2, {0x002000, 504 * 1024} },
747 { .m = { .sec = 1, .tb = 1 }, 0x3, {0x004000, 496 * 1024} },
748 { .m = { .sec = 1, .tb = 1 }, 0x4, {0x008000, 480 * 1024} },
749 { .m = { .sec = 1, .tb = 1 }, 0x5, {0x008000, 480 * 1024} },
750 { .m = { .sec = 1, .tb = 1 }, 0x6, {0x008000, 480 * 1024} },
Martin Rothf3c3d5f2017-04-28 14:56:41 -0600751
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100752 { .m = { .sec = 1, .tb = X }, 0x7, {0x000000, 0} }, /* None */
Martin Rothf3c3d5f2017-04-28 14:56:41 -0600753};
754
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100755static struct wp_range_descriptor gd25q64_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100756 { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
757 { .m = { .sec = 0, .tb = 0 }, 0x1, {0x7e0000, 128 * 1024} },
758 { .m = { .sec = 0, .tb = 0 }, 0x2, {0x7c0000, 256 * 1024} },
759 { .m = { .sec = 0, .tb = 0 }, 0x3, {0x780000, 512 * 1024} },
760 { .m = { .sec = 0, .tb = 0 }, 0x4, {0x700000, 1024 * 1024} },
761 { .m = { .sec = 0, .tb = 0 }, 0x5, {0x600000, 2048 * 1024} },
762 { .m = { .sec = 0, .tb = 0 }, 0x6, {0x400000, 4096 * 1024} },
Shawn Nematbakhsh9e8ef492012-09-01 21:58:03 -0700763
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100764 { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 128 * 1024} },
765 { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 256 * 1024} },
766 { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 512 * 1024} },
767 { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 1024 * 1024} },
768 { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 2048 * 1024} },
769 { .m = { .sec = 0, .tb = 1 }, 0x6, {0x000000, 4096 * 1024} },
770 { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 8192 * 1024} },
Shawn Nematbakhsh9e8ef492012-09-01 21:58:03 -0700771
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100772 { .m = { .sec = 1, .tb = 0 }, 0x1, {0x7ff000, 4 * 1024} },
773 { .m = { .sec = 1, .tb = 0 }, 0x2, {0x7fe000, 8 * 1024} },
774 { .m = { .sec = 1, .tb = 0 }, 0x3, {0x7fc000, 16 * 1024} },
775 { .m = { .sec = 1, .tb = 0 }, 0x4, {0x7f8000, 32 * 1024} },
776 { .m = { .sec = 1, .tb = 0 }, 0x5, {0x7f8000, 32 * 1024} },
777 { .m = { .sec = 1, .tb = 0 }, 0x6, {0x7f8000, 32 * 1024} },
Shawn Nematbakhsh9e8ef492012-09-01 21:58:03 -0700778
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100779 { .m = { .sec = 1, .tb = 1 }, 0x1, {0x000000, 4 * 1024} },
780 { .m = { .sec = 1, .tb = 1 }, 0x2, {0x000000, 8 * 1024} },
781 { .m = { .sec = 1, .tb = 1 }, 0x3, {0x000000, 16 * 1024} },
782 { .m = { .sec = 1, .tb = 1 }, 0x4, {0x000000, 32 * 1024} },
783 { .m = { .sec = 1, .tb = 1 }, 0x5, {0x000000, 32 * 1024} },
784 { .m = { .sec = 1, .tb = 1 }, 0x6, {0x000000, 32 * 1024} },
Shawn Nematbakhsh9e8ef492012-09-01 21:58:03 -0700785};
786
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100787static struct wp_range_descriptor a25l040_ranges[] = {
Edward O'Callaghan91b38272019-12-04 17:12:43 +1100788 { .m = { .sec = X, .tb = X }, 0x0, {0, 0} }, /* none */
789 { .m = { .sec = X, .tb = X }, 0x1, {0x70000, 64 * 1024} },
790 { .m = { .sec = X, .tb = X }, 0x2, {0x60000, 128 * 1024} },
791 { .m = { .sec = X, .tb = X }, 0x3, {0x40000, 256 * 1024} },
792 { .m = { .sec = X, .tb = X }, 0x4, {0x00000, 512 * 1024} },
793 { .m = { .sec = X, .tb = X }, 0x5, {0x00000, 512 * 1024} },
794 { .m = { .sec = X, .tb = X }, 0x6, {0x00000, 512 * 1024} },
795 { .m = { .sec = X, .tb = X }, 0x7, {0x00000, 512 * 1024} },
Louis Yung-Chieh Loc8ec7152012-09-17 17:38:35 +0800796};
797
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700798static uint8_t do_read_status(const struct flashctx *flash)
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +0530799{
Patrick Georgif3fa2992017-02-02 16:24:44 +0100800 if (flash->chip->read_status)
801 return flash->chip->read_status(flash);
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +0530802 else
803 return spi_read_status_register(flash);
804}
805
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700806static int do_write_status(const struct flashctx *flash, int status)
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +0530807{
Patrick Georgif3fa2992017-02-02 16:24:44 +0100808 if (flash->chip->write_status)
809 return flash->chip->write_status(flash, status);
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +0530810 else
811 return spi_write_status_register(flash, status);
812}
813
Duncan Laurieed32d7b2015-05-27 11:28:18 -0700814/* FIXME: Move to spi25.c if it's a JEDEC standard opcode */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700815static uint8_t w25q_read_status_register_2(const struct flashctx *flash)
Duncan Laurieed32d7b2015-05-27 11:28:18 -0700816{
817 static const unsigned char cmd[JEDEC_RDSR_OUTSIZE] = { 0x35 };
818 unsigned char readarr[2];
819 int ret;
820
821 /* Read Status Register */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700822 ret = spi_send_command(flash, sizeof(cmd), sizeof(readarr), cmd, readarr);
Duncan Laurieed32d7b2015-05-27 11:28:18 -0700823 if (ret) {
824 /*
825 * FIXME: make this a benign failure for now in case we are
826 * unable to execute the opcode
827 */
828 msg_cdbg("RDSR2 failed!\n");
829 readarr[0] = 0x00;
830 }
831
832 return readarr[0];
833}
834
Karthikeyan Ramasubramanianfb166b72019-06-24 12:38:55 -0600835/* FIXME: Move to spi25.c if it's a JEDEC standard opcode */
836uint8_t mx25l_read_config_register(const struct flashctx *flash)
837{
838 static const unsigned char cmd[JEDEC_RDSR_OUTSIZE] = { 0x15 };
839 unsigned char readarr[2]; /* leave room for dummy byte */
840 int ret;
841
842 ret = spi_send_command(flash, sizeof(cmd), sizeof(readarr), cmd, readarr);
843 if (ret) {
844 msg_cdbg("RDCR failed!\n");
845 readarr[0] = 0x00;
846 }
847
848 return readarr[0];
849}
850
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +0800851/* Given a flash chip, this function returns its range table. */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700852static int w25_range_table(const struct flashctx *flash,
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100853 struct wp_range_descriptor **descrs,
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +0800854 int *num_entries)
David Hendricksf7924d12010-06-10 21:26:44 -0700855{
Karthikeyan Ramasubramanianfb166b72019-06-24 12:38:55 -0600856 uint8_t cr;
857
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100858 *descrs = 0;
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +0800859 *num_entries = 0;
David Hendricksf7924d12010-06-10 21:26:44 -0700860
Patrick Georgif3fa2992017-02-02 16:24:44 +0100861 switch (flash->chip->manufacture_id) {
David Hendricksd494b0a2010-08-16 16:28:50 -0700862 case WINBOND_NEX_ID:
Patrick Georgif3fa2992017-02-02 16:24:44 +0100863 switch(flash->chip->model_id) {
David Hendricksc801adb2010-12-09 16:58:56 -0800864 case WINBOND_NEX_W25X10:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100865 *descrs = w25x10_ranges;
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +0800866 *num_entries = ARRAY_SIZE(w25x10_ranges);
Louis Yung-Chieh Lo232951f2010-09-16 11:30:00 +0800867 break;
David Hendricksc801adb2010-12-09 16:58:56 -0800868 case WINBOND_NEX_W25X20:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100869 *descrs = w25x20_ranges;
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +0800870 *num_entries = ARRAY_SIZE(w25x20_ranges);
Louis Yung-Chieh Lo232951f2010-09-16 11:30:00 +0800871 break;
David Hendricksc801adb2010-12-09 16:58:56 -0800872 case WINBOND_NEX_W25X40:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100873 *descrs = w25x40_ranges;
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +0800874 *num_entries = ARRAY_SIZE(w25x40_ranges);
David Hendricksd494b0a2010-08-16 16:28:50 -0700875 break;
David Hendricksc801adb2010-12-09 16:58:56 -0800876 case WINBOND_NEX_W25X80:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100877 *descrs = w25x80_ranges;
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +0800878 *num_entries = ARRAY_SIZE(w25x80_ranges);
Louis Yung-Chieh Lo232951f2010-09-16 11:30:00 +0800879 break;
Patrick Georgicc04a452017-02-06 12:14:43 +0100880 case WINBOND_NEX_W25Q80_V:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100881 *descrs = w25q80_ranges;
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +0800882 *num_entries = ARRAY_SIZE(w25q80_ranges);
David Hendricksd494b0a2010-08-16 16:28:50 -0700883 break;
Patrick Georgicc04a452017-02-06 12:14:43 +0100884 case WINBOND_NEX_W25Q16_V:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100885 *descrs = w25q16_ranges;
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +0800886 *num_entries = ARRAY_SIZE(w25q16_ranges);
David Hendricksd494b0a2010-08-16 16:28:50 -0700887 break;
Patrick Georgicc04a452017-02-06 12:14:43 +0100888 case WINBOND_NEX_W25Q32_V:
889 case WINBOND_NEX_W25Q32_W:
Edward O'Callaghand80cf712019-05-24 22:06:36 +1000890 case WINBOND_NEX_W25Q32JW:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100891 *descrs = w25q32_ranges;
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +0800892 *num_entries = ARRAY_SIZE(w25q32_ranges);
David Hendricksd494b0a2010-08-16 16:28:50 -0700893 break;
Patrick Georgicc04a452017-02-06 12:14:43 +0100894 case WINBOND_NEX_W25Q64_V:
895 case WINBOND_NEX_W25Q64_W:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100896 *descrs = w25q64_ranges;
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +0800897 *num_entries = ARRAY_SIZE(w25q64_ranges);
David Hendricksd494b0a2010-08-16 16:28:50 -0700898 break;
Edward O'Callaghan517cb822019-11-21 14:08:32 +1100899 case WINBOND_NEX_W25Q128_DTR:
Alan Green77a95de2019-07-01 16:40:39 +1000900 case WINBOND_NEX_W25Q128_V_M:
Patrick Georgicc04a452017-02-06 12:14:43 +0100901 case WINBOND_NEX_W25Q128_V:
902 case WINBOND_NEX_W25Q128_W:
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700903 if (w25q_read_status_register_2(flash) & (1 << 6)) {
Duncan Laurieed32d7b2015-05-27 11:28:18 -0700904 /* CMP == 1 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100905 *descrs = w25rq128_cmp1_ranges;
Duncan Laurieed32d7b2015-05-27 11:28:18 -0700906 *num_entries = ARRAY_SIZE(w25rq128_cmp1_ranges);
907 } else {
908 /* CMP == 0 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100909 *descrs = w25rq128_cmp0_ranges;
Duncan Laurieed32d7b2015-05-27 11:28:18 -0700910 *num_entries = ARRAY_SIZE(w25rq128_cmp0_ranges);
911 }
Ramya Vijaykumare6a7ca82015-05-12 14:27:29 +0530912 break;
Alan Green77a95de2019-07-01 16:40:39 +1000913 case WINBOND_NEX_W25Q256JV_M:
Duncan Laurie1801f7c2019-01-09 18:02:51 -0800914 if (w25q_read_status_register_2(flash) & (1 << 6)) {
915 /* CMP == 1 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100916 *descrs = w25rq256_cmp1_ranges;
Duncan Laurie1801f7c2019-01-09 18:02:51 -0800917 *num_entries = ARRAY_SIZE(w25rq256_cmp1_ranges);
918 } else {
919 /* CMP == 0 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100920 *descrs = w25rq256_cmp0_ranges;
Duncan Laurie1801f7c2019-01-09 18:02:51 -0800921 *num_entries = ARRAY_SIZE(w25rq256_cmp0_ranges);
922 }
923 break;
David Hendricksd494b0a2010-08-16 16:28:50 -0700924 default:
925 msg_cerr("%s() %d: WINBOND flash chip mismatch (0x%04x)"
926 ", aborting\n", __func__, __LINE__,
Patrick Georgif3fa2992017-02-02 16:24:44 +0100927 flash->chip->model_id);
David Hendricksd494b0a2010-08-16 16:28:50 -0700928 return -1;
929 }
David Hendricks2c4a76c2010-06-28 14:00:43 -0700930 break;
David Hendricks57566ed2010-08-16 18:24:45 -0700931 case EON_ID_NOPREFIX:
Patrick Georgif3fa2992017-02-02 16:24:44 +0100932 switch (flash->chip->model_id) {
David Hendricksc801adb2010-12-09 16:58:56 -0800933 case EON_EN25F40:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100934 *descrs = en25f40_ranges;
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +0800935 *num_entries = ARRAY_SIZE(en25f40_ranges);
David Hendricks57566ed2010-08-16 18:24:45 -0700936 break;
David Hendrickse185bf22011-05-24 15:34:18 -0700937 case EON_EN25Q40:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100938 *descrs = en25q40_ranges;
David Hendrickse185bf22011-05-24 15:34:18 -0700939 *num_entries = ARRAY_SIZE(en25q40_ranges);
940 break;
941 case EON_EN25Q80:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100942 *descrs = en25q80_ranges;
David Hendrickse185bf22011-05-24 15:34:18 -0700943 *num_entries = ARRAY_SIZE(en25q80_ranges);
944 break;
945 case EON_EN25Q32:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100946 *descrs = en25q32_ranges;
David Hendrickse185bf22011-05-24 15:34:18 -0700947 *num_entries = ARRAY_SIZE(en25q32_ranges);
948 break;
949 case EON_EN25Q64:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100950 *descrs = en25q64_ranges;
David Hendrickse185bf22011-05-24 15:34:18 -0700951 *num_entries = ARRAY_SIZE(en25q64_ranges);
952 break;
953 case EON_EN25Q128:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100954 *descrs = en25q128_ranges;
David Hendrickse185bf22011-05-24 15:34:18 -0700955 *num_entries = ARRAY_SIZE(en25q128_ranges);
956 break;
Marc Jonesb2f90022014-04-29 17:37:23 -0600957 case EON_EN25S64:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100958 *descrs = en25s64_ranges;
Marc Jonesb2f90022014-04-29 17:37:23 -0600959 *num_entries = ARRAY_SIZE(en25s64_ranges);
960 break;
David Hendricks57566ed2010-08-16 18:24:45 -0700961 default:
962 msg_cerr("%s():%d: EON flash chip mismatch (0x%04x)"
963 ", aborting\n", __func__, __LINE__,
Patrick Georgif3fa2992017-02-02 16:24:44 +0100964 flash->chip->model_id);
David Hendricks57566ed2010-08-16 18:24:45 -0700965 return -1;
966 }
967 break;
David Hendricksc801adb2010-12-09 16:58:56 -0800968 case MACRONIX_ID:
Patrick Georgif3fa2992017-02-02 16:24:44 +0100969 switch (flash->chip->model_id) {
David Hendricksf8f00c72011-02-01 12:39:46 -0800970 case MACRONIX_MX25L1005:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100971 *descrs = mx25l1005_ranges;
David Hendricksf8f00c72011-02-01 12:39:46 -0800972 *num_entries = ARRAY_SIZE(mx25l1005_ranges);
973 break;
974 case MACRONIX_MX25L2005:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100975 *descrs = mx25l2005_ranges;
David Hendricksf8f00c72011-02-01 12:39:46 -0800976 *num_entries = ARRAY_SIZE(mx25l2005_ranges);
977 break;
978 case MACRONIX_MX25L4005:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100979 *descrs = mx25l4005_ranges;
David Hendricksf8f00c72011-02-01 12:39:46 -0800980 *num_entries = ARRAY_SIZE(mx25l4005_ranges);
981 break;
982 case MACRONIX_MX25L8005:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100983 *descrs = mx25l8005_ranges;
David Hendricksf8f00c72011-02-01 12:39:46 -0800984 *num_entries = ARRAY_SIZE(mx25l8005_ranges);
985 break;
986 case MACRONIX_MX25L1605:
987 /* FIXME: MX25L1605 and MX25L1605D have different write
988 * protection capabilities, but share IDs */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100989 *descrs = mx25l1605d_ranges;
David Hendricksf8f00c72011-02-01 12:39:46 -0800990 *num_entries = ARRAY_SIZE(mx25l1605d_ranges);
991 break;
David Hendricksc801adb2010-12-09 16:58:56 -0800992 case MACRONIX_MX25L3205:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100993 *descrs = mx25l3205d_ranges;
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +0800994 *num_entries = ARRAY_SIZE(mx25l3205d_ranges);
David Hendricksac72e362010-08-16 18:20:03 -0700995 break;
Vincent Palatin87e092a2013-02-28 15:46:14 -0800996 case MACRONIX_MX25U3235E:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +1100997 *descrs = mx25u3235e_ranges;
Vincent Palatin87e092a2013-02-28 15:46:14 -0800998 *num_entries = ARRAY_SIZE(mx25u3235e_ranges);
999 break;
Jongpil66a96492014-08-14 17:59:06 +09001000 case MACRONIX_MX25U6435E:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001001 *descrs = mx25u6435e_ranges;
Jongpil66a96492014-08-14 17:59:06 +09001002 *num_entries = ARRAY_SIZE(mx25u6435e_ranges);
1003 break;
Alan Greendc0792e2019-07-01 15:01:34 +10001004 case MACRONIX_MX25U12835E:
Karthikeyan Ramasubramanianfb166b72019-06-24 12:38:55 -06001005 cr = mx25l_read_config_register(flash);
1006 if (cr & MX25U12835E_TB) { /* T/B == 1 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001007 *descrs = mx25u12835e_tb1_ranges;
Karthikeyan Ramasubramanianfb166b72019-06-24 12:38:55 -06001008 *num_entries = ARRAY_SIZE(mx25u12835e_tb1_ranges);
1009 } else { /* T/B == 0 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001010 *descrs = mx25u12835e_tb0_ranges;
Karthikeyan Ramasubramanianfb166b72019-06-24 12:38:55 -06001011 *num_entries = ARRAY_SIZE(mx25u12835e_tb0_ranges);
1012 }
Alex Lu831c6092017-11-02 23:19:34 -07001013 break;
David Hendricksac72e362010-08-16 18:20:03 -07001014 default:
1015 msg_cerr("%s():%d: MXIC flash chip mismatch (0x%04x)"
1016 ", aborting\n", __func__, __LINE__,
Patrick Georgif3fa2992017-02-02 16:24:44 +01001017 flash->chip->model_id);
David Hendricksac72e362010-08-16 18:20:03 -07001018 return -1;
1019 }
1020 break;
David Hendricksbfa624b2012-07-24 12:47:59 -07001021 case ST_ID:
Patrick Georgif3fa2992017-02-02 16:24:44 +01001022 switch(flash->chip->model_id) {
David Hendricksbfa624b2012-07-24 12:47:59 -07001023 case ST_N25Q064__1E:
1024 case ST_N25Q064__3E:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001025 *descrs = n25q064_ranges;
David Hendricksbfa624b2012-07-24 12:47:59 -07001026 *num_entries = ARRAY_SIZE(n25q064_ranges);
1027 break;
1028 default:
1029 msg_cerr("%s() %d: Micron flash chip mismatch"
1030 " (0x%04x), aborting\n", __func__, __LINE__,
Patrick Georgif3fa2992017-02-02 16:24:44 +01001031 flash->chip->model_id);
David Hendricksbfa624b2012-07-24 12:47:59 -07001032 return -1;
1033 }
1034 break;
Bryan Freed9a0051f2012-05-22 16:06:09 -07001035 case GIGADEVICE_ID:
Patrick Georgif3fa2992017-02-02 16:24:44 +01001036 switch(flash->chip->model_id) {
Bryan Freed9a0051f2012-05-22 16:06:09 -07001037 case GIGADEVICE_GD25LQ32:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001038 *descrs = w25q32_ranges;
Bryan Freed9a0051f2012-05-22 16:06:09 -07001039 *num_entries = ARRAY_SIZE(w25q32_ranges);
1040 break;
Martin Rothf3c3d5f2017-04-28 14:56:41 -06001041 case GIGADEVICE_GD25Q40:
1042 if (w25q_read_status_register_2(flash) & (1 << 6)) {
1043 /* CMP == 1 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001044 *descrs = gd25q40_cmp1_ranges;
Martin Rothf3c3d5f2017-04-28 14:56:41 -06001045 *num_entries = ARRAY_SIZE(gd25q40_cmp1_ranges);
1046 } else {
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001047 *descrs = gd25q40_cmp0_ranges;
Martin Rothf3c3d5f2017-04-28 14:56:41 -06001048 *num_entries = ARRAY_SIZE(gd25q40_cmp0_ranges);
1049 }
1050 break;
Shawn Nematbakhsh9e8ef492012-09-01 21:58:03 -07001051 case GIGADEVICE_GD25Q64:
Marc Jonesb18734f2014-04-03 16:19:47 -06001052 case GIGADEVICE_GD25LQ64:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001053 *descrs = gd25q64_ranges;
Shawn Nematbakhsh9e8ef492012-09-01 21:58:03 -07001054 *num_entries = ARRAY_SIZE(gd25q64_ranges);
1055 break;
Martin Roth1fd87ed2017-02-27 20:50:50 -07001056 case GIGADEVICE_GD25Q128:
Aaron Durbin6c957d72018-08-20 09:31:01 -06001057 case GIGADEVICE_GD25LQ128CD:
Martin Roth1fd87ed2017-02-27 20:50:50 -07001058 if (w25q_read_status_register_2(flash) & (1 << 6)) {
1059 /* CMP == 1 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001060 *descrs = w25rq128_cmp1_ranges;
Martin Roth1fd87ed2017-02-27 20:50:50 -07001061 *num_entries = ARRAY_SIZE(w25rq128_cmp1_ranges);
1062 } else {
1063 /* CMP == 0 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001064 *descrs = w25rq128_cmp0_ranges;
Martin Roth1fd87ed2017-02-27 20:50:50 -07001065 *num_entries = ARRAY_SIZE(w25rq128_cmp0_ranges);
1066 }
1067 break;
Duncan Laurie0c383552019-03-16 12:35:16 -07001068 case GIGADEVICE_GD25Q256D:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001069 *descrs = w25rq256_cmp0_ranges;
Duncan Laurie0c383552019-03-16 12:35:16 -07001070 *num_entries = ARRAY_SIZE(w25rq256_cmp0_ranges);
1071 break;
Bryan Freed9a0051f2012-05-22 16:06:09 -07001072 default:
1073 msg_cerr("%s() %d: GigaDevice flash chip mismatch"
1074 " (0x%04x), aborting\n", __func__, __LINE__,
Patrick Georgif3fa2992017-02-02 16:24:44 +01001075 flash->chip->model_id);
Bryan Freed9a0051f2012-05-22 16:06:09 -07001076 return -1;
1077 }
1078 break;
Louis Yung-Chieh Loc8ec7152012-09-17 17:38:35 +08001079 case AMIC_ID_NOPREFIX:
Patrick Georgif3fa2992017-02-02 16:24:44 +01001080 switch(flash->chip->model_id) {
Louis Yung-Chieh Loc8ec7152012-09-17 17:38:35 +08001081 case AMIC_A25L040:
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001082 *descrs = a25l040_ranges;
Louis Yung-Chieh Loc8ec7152012-09-17 17:38:35 +08001083 *num_entries = ARRAY_SIZE(a25l040_ranges);
1084 break;
1085 default:
1086 msg_cerr("%s() %d: AMIC flash chip mismatch"
1087 " (0x%04x), aborting\n", __func__, __LINE__,
Patrick Georgif3fa2992017-02-02 16:24:44 +01001088 flash->chip->model_id);
Louis Yung-Chieh Loc8ec7152012-09-17 17:38:35 +08001089 return -1;
1090 }
1091 break;
Furquan Shaikhb4df8ef2017-01-05 15:05:35 -08001092 case ATMEL_ID:
Patrick Georgif3fa2992017-02-02 16:24:44 +01001093 switch(flash->chip->model_id) {
Edward O'Callaghan1fa87e02019-05-03 02:27:24 -04001094 case ATMEL_AT25SF128A:
Furquan Shaikhb4df8ef2017-01-05 15:05:35 -08001095 case ATMEL_AT25SL128A:
1096 if (w25q_read_status_register_2(flash) & (1 << 6)) {
1097 /* CMP == 1 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001098 *descrs = w25rq128_cmp1_ranges;
Furquan Shaikhb4df8ef2017-01-05 15:05:35 -08001099 *num_entries = ARRAY_SIZE(w25rq128_cmp1_ranges);
1100 } else {
1101 /* CMP == 0 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001102 *descrs = w25rq128_cmp0_ranges;
Furquan Shaikhb4df8ef2017-01-05 15:05:35 -08001103 *num_entries = ARRAY_SIZE(w25rq128_cmp0_ranges);
1104 }
1105 break;
1106 default:
1107 msg_cerr("%s() %d: Atmel flash chip mismatch"
1108 " (0x%04x), aborting\n", __func__, __LINE__,
Patrick Georgif3fa2992017-02-02 16:24:44 +01001109 flash->chip->model_id);
Furquan Shaikhb4df8ef2017-01-05 15:05:35 -08001110 return -1;
1111 }
1112 break;
David Hendricksf7924d12010-06-10 21:26:44 -07001113 default:
David Hendricksd494b0a2010-08-16 16:28:50 -07001114 msg_cerr("%s: flash vendor (0x%x) not found, aborting\n",
Patrick Georgif3fa2992017-02-02 16:24:44 +01001115 __func__, flash->chip->manufacture_id);
David Hendricksf7924d12010-06-10 21:26:44 -07001116 return -1;
1117 }
1118
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +08001119 return 0;
1120}
1121
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001122int w25_range_to_status(const struct flashctx *flash,
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +08001123 unsigned int start, unsigned int len,
1124 struct w25q_status *status)
1125{
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001126 struct wp_range_descriptor *descrs;
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +08001127 int i, range_found = 0;
1128 int num_entries;
1129
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001130 if (w25_range_table(flash, &descrs, &num_entries))
Edward O'Callaghanbea239e2019-12-04 14:42:54 +11001131 return -1;
1132
David Hendricksf7924d12010-06-10 21:26:44 -07001133 for (i = 0; i < num_entries; i++) {
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001134 struct wp_range *r = &descrs[i].range;
David Hendricksf7924d12010-06-10 21:26:44 -07001135
1136 msg_cspew("comparing range 0x%x 0x%x / 0x%x 0x%x\n",
1137 start, len, r->start, r->len);
1138 if ((start == r->start) && (len == r->len)) {
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001139 status->bp0 = descrs[i].bp & 1;
1140 status->bp1 = descrs[i].bp >> 1;
1141 status->bp2 = descrs[i].bp >> 2;
1142 status->tb = descrs[i].m.tb;
1143 status->sec = descrs[i].m.sec;
David Hendricksf7924d12010-06-10 21:26:44 -07001144
1145 range_found = 1;
1146 break;
1147 }
1148 }
1149
1150 if (!range_found) {
1151 msg_cerr("matching range not found\n");
1152 return -1;
1153 }
Edward O'Callaghanbea239e2019-12-04 14:42:54 +11001154
David Hendricksd494b0a2010-08-16 16:28:50 -07001155 return 0;
1156}
1157
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001158int w25_status_to_range(const struct flashctx *flash,
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +08001159 const struct w25q_status *status,
1160 unsigned int *start, unsigned int *len)
1161{
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001162 struct wp_range_descriptor *descrs;
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +08001163 int i, status_found = 0;
1164 int num_entries;
1165
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001166 if (w25_range_table(flash, &descrs, &num_entries))
Edward O'Callaghanbea239e2019-12-04 14:42:54 +11001167 return -1;
1168
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +08001169 for (i = 0; i < num_entries; i++) {
1170 int bp;
Louis Yung-Chieh Loedd39302011-11-10 15:43:06 +08001171 int table_bp, table_tb, table_sec;
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +08001172
1173 bp = status->bp0 | (status->bp1 << 1) | (status->bp2 << 2);
1174 msg_cspew("comparing 0x%x 0x%x / 0x%x 0x%x / 0x%x 0x%x\n",
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001175 bp, descrs[i].bp,
1176 status->tb, descrs[i].m.tb,
1177 status->sec, descrs[i].m.sec);
1178 table_bp = descrs[i].bp;
1179 table_tb = descrs[i].m.tb;
1180 table_sec = descrs[i].m.sec;
Louis Yung-Chieh Loedd39302011-11-10 15:43:06 +08001181 if ((bp == table_bp || table_bp == X) &&
1182 (status->tb == table_tb || table_tb == X) &&
1183 (status->sec == table_sec || table_sec == X)) {
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001184 *start = descrs[i].range.start;
1185 *len = descrs[i].range.len;
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +08001186
1187 status_found = 1;
1188 break;
1189 }
1190 }
1191
1192 if (!status_found) {
1193 msg_cerr("matching status not found\n");
1194 return -1;
1195 }
Edward O'Callaghanbea239e2019-12-04 14:42:54 +11001196
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +08001197 return 0;
1198}
1199
Louis Yung-Chieh Lo165b4642010-11-26 16:35:26 +08001200/* Given a [start, len], this function calls w25_range_to_status() to convert
1201 * it to flash-chip-specific range bits, then sets into status register.
1202 */
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001203static int w25_set_range(const struct flashctx *flash,
David Hendricksd494b0a2010-08-16 16:28:50 -07001204 unsigned int start, unsigned int len)
1205{
1206 struct w25q_status status;
Louis Yung-Chieh Lo165b4642010-11-26 16:35:26 +08001207 int tmp = 0;
1208 int expected = 0;
David Hendricksd494b0a2010-08-16 16:28:50 -07001209
1210 memset(&status, 0, sizeof(status));
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05301211 tmp = do_read_status(flash);
David Hendricksd494b0a2010-08-16 16:28:50 -07001212 memcpy(&status, &tmp, 1);
1213 msg_cdbg("%s: old status: 0x%02x\n", __func__, tmp);
1214
Edward O'Callaghanbea239e2019-12-04 14:42:54 +11001215 if (w25_range_to_status(flash, start, len, &status))
1216 return -1;
David Hendricksf7924d12010-06-10 21:26:44 -07001217
1218 msg_cdbg("status.busy: %x\n", status.busy);
1219 msg_cdbg("status.wel: %x\n", status.wel);
1220 msg_cdbg("status.bp0: %x\n", status.bp0);
1221 msg_cdbg("status.bp1: %x\n", status.bp1);
1222 msg_cdbg("status.bp2: %x\n", status.bp2);
1223 msg_cdbg("status.tb: %x\n", status.tb);
1224 msg_cdbg("status.sec: %x\n", status.sec);
1225 msg_cdbg("status.srp0: %x\n", status.srp0);
1226
Louis Yung-Chieh Lo165b4642010-11-26 16:35:26 +08001227 memcpy(&expected, &status, sizeof(status));
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05301228 do_write_status(flash, expected);
David Hendricksf7924d12010-06-10 21:26:44 -07001229
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05301230 tmp = do_read_status(flash);
Louis Yung-Chieh Lo165b4642010-11-26 16:35:26 +08001231 msg_cdbg("%s: new status: 0x%02x\n", __func__, tmp);
Edward O'Callaghan2672fb92019-12-04 14:47:58 +11001232 if ((tmp & MASK_WP_AREA) != (expected & MASK_WP_AREA)) {
David Hendricksc801adb2010-12-09 16:58:56 -08001233 msg_cerr("expected=0x%02x, but actual=0x%02x.\n",
Louis Yung-Chieh Lo165b4642010-11-26 16:35:26 +08001234 expected, tmp);
1235 return 1;
1236 }
Edward O'Callaghan2672fb92019-12-04 14:47:58 +11001237
1238 return 0;
David Hendricksf7924d12010-06-10 21:26:44 -07001239}
1240
Louis Yung-Chieh Lo165b4642010-11-26 16:35:26 +08001241/* Print out the current status register value with human-readable text. */
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001242static int w25_wp_status(const struct flashctx *flash)
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +08001243{
1244 struct w25q_status status;
1245 int tmp;
David Hendricksce8ded32010-10-08 11:23:38 -07001246 unsigned int start, len;
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +08001247 int ret = 0;
1248
Louis Yung-Chieh Lo165b4642010-11-26 16:35:26 +08001249 memset(&status, 0, sizeof(status));
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05301250 tmp = do_read_status(flash);
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +08001251 memcpy(&status, &tmp, 1);
1252 msg_cinfo("WP: status: 0x%02x\n", tmp);
1253 msg_cinfo("WP: status.srp0: %x\n", status.srp0);
1254 msg_cinfo("WP: write protect is %s.\n",
1255 status.srp0 ? "enabled" : "disabled");
1256
1257 msg_cinfo("WP: write protect range: ");
1258 if (w25_status_to_range(flash, &status, &start, &len)) {
1259 msg_cinfo("(cannot resolve the range)\n");
1260 ret = -1;
1261 } else {
1262 msg_cinfo("start=0x%08x, len=0x%08x\n", start, len);
1263 }
1264
1265 return ret;
1266}
1267
Duncan Laurie1801f7c2019-01-09 18:02:51 -08001268static int w25q_large_range_to_status(const struct flashctx *flash,
1269 unsigned int start, unsigned int len,
1270 struct w25q_status_large *status)
1271{
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001272 struct wp_range_descriptor *descrs;
Duncan Laurie1801f7c2019-01-09 18:02:51 -08001273 int i, range_found = 0;
1274 int num_entries;
1275
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001276 if (w25_range_table(flash, &descrs, &num_entries))
Duncan Laurie1801f7c2019-01-09 18:02:51 -08001277 return -1;
Edward O'Callaghanbea239e2019-12-04 14:42:54 +11001278
Duncan Laurie1801f7c2019-01-09 18:02:51 -08001279 for (i = 0; i < num_entries; i++) {
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001280 struct wp_range *r = &descrs[i].range;
Duncan Laurie1801f7c2019-01-09 18:02:51 -08001281
1282 msg_cspew("comparing range 0x%x 0x%x / 0x%x 0x%x\n",
1283 start, len, r->start, r->len);
1284 if ((start == r->start) && (len == r->len)) {
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001285 status->bp0 = descrs[i].bp & 1;
1286 status->bp1 = descrs[i].bp >> 1;
1287 status->bp2 = descrs[i].bp >> 2;
1288 status->bp3 = descrs[i].bp >> 3;
Karthikeyan Ramasubramanianfb166b72019-06-24 12:38:55 -06001289 /*
1290 * For MX25U12835E chip, Top/Bottom (T/B) bit is not
1291 * part of status register and in that bit position is
1292 * Quad Enable (QE)
1293 */
1294 if (flash->chip->manufacture_id != MACRONIX_ID ||
1295 flash->chip->model_id != MACRONIX_MX25U12835E)
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001296 status->tb = descrs[i].m.tb;
Duncan Laurie1801f7c2019-01-09 18:02:51 -08001297
1298 range_found = 1;
1299 break;
1300 }
1301 }
1302
1303 if (!range_found) {
1304 msg_cerr("matching range not found\n");
1305 return -1;
1306 }
Edward O'Callaghanbea239e2019-12-04 14:42:54 +11001307
Duncan Laurie1801f7c2019-01-09 18:02:51 -08001308 return 0;
1309}
1310
1311static int w25_large_status_to_range(const struct flashctx *flash,
1312 const struct w25q_status_large *status,
1313 unsigned int *start, unsigned int *len)
1314{
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001315 struct wp_range_descriptor *descrs;
Duncan Laurie1801f7c2019-01-09 18:02:51 -08001316 int i, status_found = 0;
1317 int num_entries;
1318
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001319 if (w25_range_table(flash, &descrs, &num_entries))
Duncan Laurie1801f7c2019-01-09 18:02:51 -08001320 return -1;
Edward O'Callaghanbea239e2019-12-04 14:42:54 +11001321
Duncan Laurie1801f7c2019-01-09 18:02:51 -08001322 for (i = 0; i < num_entries; i++) {
1323 int bp;
1324 int table_bp, table_tb;
1325
1326 bp = status->bp0 | (status->bp1 << 1) | (status->bp2 << 2) |
1327 (status->bp3 << 3);
1328 msg_cspew("comparing 0x%x 0x%x / 0x%x 0x%x\n",
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001329 bp, descrs[i].bp,
1330 status->tb, descrs[i].m.tb);
1331 table_bp = descrs[i].bp;
1332 table_tb = descrs[i].m.tb;
Duncan Laurie1801f7c2019-01-09 18:02:51 -08001333 if ((bp == table_bp || table_bp == X) &&
1334 (status->tb == table_tb || table_tb == X)) {
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001335 *start = descrs[i].range.start;
1336 *len = descrs[i].range.len;
Duncan Laurie1801f7c2019-01-09 18:02:51 -08001337
1338 status_found = 1;
1339 break;
1340 }
1341 }
1342
1343 if (!status_found) {
1344 msg_cerr("matching status not found\n");
1345 return -1;
1346 }
Edward O'Callaghanbea239e2019-12-04 14:42:54 +11001347
Duncan Laurie1801f7c2019-01-09 18:02:51 -08001348 return 0;
1349}
1350
1351/* Given a [start, len], this function calls w25_range_to_status() to convert
1352 * it to flash-chip-specific range bits, then sets into status register.
1353 * Returns 0 if successful, -1 on error, and 1 if reading back was different.
1354 */
1355static int w25q_large_set_range(const struct flashctx *flash,
1356 unsigned int start, unsigned int len)
1357{
1358 struct w25q_status_large status;
1359 int tmp;
1360 int expected = 0;
1361
1362 memset(&status, 0, sizeof(status));
1363 tmp = do_read_status(flash);
1364 memcpy(&status, &tmp, 1);
1365 msg_cdbg("%s: old status: 0x%02x\n", __func__, tmp);
1366
1367 if (w25q_large_range_to_status(flash, start, len, &status))
1368 return -1;
1369
1370 msg_cdbg("status.busy: %x\n", status.busy);
1371 msg_cdbg("status.wel: %x\n", status.wel);
1372 msg_cdbg("status.bp0: %x\n", status.bp0);
1373 msg_cdbg("status.bp1: %x\n", status.bp1);
1374 msg_cdbg("status.bp2: %x\n", status.bp2);
1375 msg_cdbg("status.bp3: %x\n", status.bp3);
1376 msg_cdbg("status.tb: %x\n", status.tb);
1377 msg_cdbg("status.srp0: %x\n", status.srp0);
1378
1379 memcpy(&expected, &status, sizeof(status));
1380 do_write_status(flash, expected);
1381
1382 tmp = do_read_status(flash);
1383 msg_cdbg("%s: new status: 0x%02x\n", __func__, tmp);
Edward O'Callaghan2672fb92019-12-04 14:47:58 +11001384 if ((tmp & MASK_WP_AREA_LARGE) != (expected & MASK_WP_AREA_LARGE)) {
Duncan Laurie1801f7c2019-01-09 18:02:51 -08001385 msg_cerr("expected=0x%02x, but actual=0x%02x.\n",
1386 expected, tmp);
1387 return 1;
1388 }
Edward O'Callaghan2672fb92019-12-04 14:47:58 +11001389
1390 return 0;
Duncan Laurie1801f7c2019-01-09 18:02:51 -08001391}
1392
1393static int w25q_large_wp_status(const struct flashctx *flash)
1394{
1395 struct w25q_status_large sr1;
1396 struct w25q_status_2 sr2;
1397 uint8_t tmp[2];
1398 unsigned int start, len;
1399 int ret = 0;
1400
1401 memset(&sr1, 0, sizeof(sr1));
1402 tmp[0] = do_read_status(flash);
1403 memcpy(&sr1, &tmp[0], 1);
1404
1405 memset(&sr2, 0, sizeof(sr2));
1406 tmp[1] = w25q_read_status_register_2(flash);
1407 memcpy(&sr2, &tmp[1], 1);
1408
1409 msg_cinfo("WP: status: 0x%02x%02x\n", tmp[1], tmp[0]);
1410 msg_cinfo("WP: status.srp0: %x\n", sr1.srp0);
1411 msg_cinfo("WP: status.srp1: %x\n", sr2.srp1);
1412 msg_cinfo("WP: write protect is %s.\n",
1413 (sr1.srp0 || sr2.srp1) ? "enabled" : "disabled");
1414
1415 msg_cinfo("WP: write protect range: ");
1416 if (w25_large_status_to_range(flash, &sr1, &start, &len)) {
1417 msg_cinfo("(cannot resolve the range)\n");
1418 ret = -1;
1419 } else {
1420 msg_cinfo("start=0x%08x, len=0x%08x\n", start, len);
1421 }
1422
1423 return ret;
1424}
1425
Louis Yung-Chieh Lo165b4642010-11-26 16:35:26 +08001426/* Set/clear the SRP0 bit in the status register. */
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001427static int w25_set_srp0(const struct flashctx *flash, int enable)
David Hendricksf7924d12010-06-10 21:26:44 -07001428{
1429 struct w25q_status status;
1430 int tmp = 0;
Louis Yung-Chieh Lo165b4642010-11-26 16:35:26 +08001431 int expected = 0;
David Hendricksf7924d12010-06-10 21:26:44 -07001432
1433 memset(&status, 0, sizeof(status));
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05301434 tmp = do_read_status(flash);
Louis Yung-Chieh Lo165b4642010-11-26 16:35:26 +08001435 /* FIXME: this is NOT endian-free copy. */
David Hendricksf7924d12010-06-10 21:26:44 -07001436 memcpy(&status, &tmp, 1);
1437 msg_cdbg("%s: old status: 0x%02x\n", __func__, tmp);
1438
Louis Yung-Chieh Loc19d3c52010-10-08 11:59:16 +08001439 status.srp0 = enable ? 1 : 0;
Louis Yung-Chieh Lo165b4642010-11-26 16:35:26 +08001440 memcpy(&expected, &status, sizeof(status));
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05301441 do_write_status(flash, expected);
Louis Yung-Chieh Lo165b4642010-11-26 16:35:26 +08001442
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05301443 tmp = do_read_status(flash);
Louis Yung-Chieh Lo165b4642010-11-26 16:35:26 +08001444 msg_cdbg("%s: new status: 0x%02x\n", __func__, tmp);
1445 if ((tmp & MASK_WP_AREA) != (expected & MASK_WP_AREA))
1446 return 1;
David Hendricksf7924d12010-06-10 21:26:44 -07001447
1448 return 0;
1449}
1450
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001451static int w25_enable_writeprotect(const struct flashctx *flash,
David Hendricks1c09f802012-10-03 11:03:48 -07001452 enum wp_mode wp_mode)
Louis Yung-Chieh Loc19d3c52010-10-08 11:59:16 +08001453{
1454 int ret;
1455
Edward O'Callaghanca44e5c2019-12-04 14:23:54 +11001456 if (wp_mode != WP_MODE_HARDWARE) {
David Hendricks1c09f802012-10-03 11:03:48 -07001457 msg_cerr("%s(): unsupported write-protect mode\n", __func__);
1458 return 1;
1459 }
1460
Edward O'Callaghanca44e5c2019-12-04 14:23:54 +11001461 ret = w25_set_srp0(flash, 1);
David Hendricksc801adb2010-12-09 16:58:56 -08001462 if (ret)
1463 msg_cerr("%s(): error=%d.\n", __func__, ret);
Louis Yung-Chieh Loc19d3c52010-10-08 11:59:16 +08001464 return ret;
1465}
1466
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001467static int w25_disable_writeprotect(const struct flashctx *flash)
Louis Yung-Chieh Loc19d3c52010-10-08 11:59:16 +08001468{
1469 int ret;
1470
1471 ret = w25_set_srp0(flash, 0);
David Hendricksc801adb2010-12-09 16:58:56 -08001472 if (ret)
1473 msg_cerr("%s(): error=%d.\n", __func__, ret);
Edward O'Callaghanbea239e2019-12-04 14:42:54 +11001474
Louis Yung-Chieh Loc19d3c52010-10-08 11:59:16 +08001475 return ret;
1476}
1477
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001478static int w25_list_ranges(const struct flashctx *flash)
David Hendricks0f7f5382011-02-11 18:12:31 -08001479{
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001480 struct wp_range_descriptor *descrs;
David Hendricks0f7f5382011-02-11 18:12:31 -08001481 int i, num_entries;
1482
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001483 if (w25_range_table(flash, &descrs, &num_entries))
Edward O'Callaghanbea239e2019-12-04 14:42:54 +11001484 return -1;
1485
David Hendricks0f7f5382011-02-11 18:12:31 -08001486 for (i = 0; i < num_entries; i++) {
1487 msg_cinfo("start: 0x%06x, length: 0x%06x\n",
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001488 descrs[i].range.start,
1489 descrs[i].range.len);
David Hendricks0f7f5382011-02-11 18:12:31 -08001490 }
1491
1492 return 0;
1493}
1494
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001495static int w25q_wp_status(const struct flashctx *flash)
David Hendricks1c09f802012-10-03 11:03:48 -07001496{
1497 struct w25q_status sr1;
1498 struct w25q_status_2 sr2;
David Hendricksf1bd8802012-10-30 11:37:57 -07001499 uint8_t tmp[2];
David Hendricks1c09f802012-10-03 11:03:48 -07001500 unsigned int start, len;
1501 int ret = 0;
1502
1503 memset(&sr1, 0, sizeof(sr1));
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05301504 tmp[0] = do_read_status(flash);
David Hendricksf1bd8802012-10-30 11:37:57 -07001505 memcpy(&sr1, &tmp[0], 1);
David Hendricks1c09f802012-10-03 11:03:48 -07001506
David Hendricksf1bd8802012-10-30 11:37:57 -07001507 memset(&sr2, 0, sizeof(sr2));
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001508 tmp[1] = w25q_read_status_register_2(flash);
David Hendricksf1bd8802012-10-30 11:37:57 -07001509 memcpy(&sr2, &tmp[1], 1);
1510
1511 msg_cinfo("WP: status: 0x%02x%02x\n", tmp[1], tmp[0]);
David Hendricks1c09f802012-10-03 11:03:48 -07001512 msg_cinfo("WP: status.srp0: %x\n", sr1.srp0);
1513 msg_cinfo("WP: status.srp1: %x\n", sr2.srp1);
1514 msg_cinfo("WP: write protect is %s.\n",
1515 (sr1.srp0 || sr2.srp1) ? "enabled" : "disabled");
1516
1517 msg_cinfo("WP: write protect range: ");
1518 if (w25_status_to_range(flash, &sr1, &start, &len)) {
1519 msg_cinfo("(cannot resolve the range)\n");
1520 ret = -1;
1521 } else {
1522 msg_cinfo("start=0x%08x, len=0x%08x\n", start, len);
1523 }
1524
1525 return ret;
1526}
1527
1528/*
1529 * W25Q adds an optional byte to the standard WRSR opcode. If /CS is
1530 * de-asserted after the first byte, then it acts like a JEDEC-standard
1531 * WRSR command. if /CS is asserted, then the next data byte is written
1532 * into status register 2.
1533 */
1534#define W25Q_WRSR_OUTSIZE 0x03
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001535static int w25q_write_status_register_WREN(const struct flashctx *flash, uint8_t s1, uint8_t s2)
David Hendricks1c09f802012-10-03 11:03:48 -07001536{
1537 int result;
1538 struct spi_command cmds[] = {
1539 {
1540 /* FIXME: WRSR requires either EWSR or WREN depending on chip type. */
1541 .writecnt = JEDEC_WREN_OUTSIZE,
1542 .writearr = (const unsigned char[]){ JEDEC_WREN },
1543 .readcnt = 0,
1544 .readarr = NULL,
1545 }, {
1546 .writecnt = W25Q_WRSR_OUTSIZE,
1547 .writearr = (const unsigned char[]){ JEDEC_WRSR, s1, s2 },
1548 .readcnt = 0,
1549 .readarr = NULL,
1550 }, {
1551 .writecnt = 0,
1552 .writearr = NULL,
1553 .readcnt = 0,
1554 .readarr = NULL,
1555 }};
1556
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001557 result = spi_send_multicommand(flash, cmds);
David Hendricks1c09f802012-10-03 11:03:48 -07001558 if (result) {
1559 msg_cerr("%s failed during command execution\n",
1560 __func__);
1561 }
1562
1563 /* WRSR performs a self-timed erase before the changes take effect. */
David Hendricks60824042014-12-11 17:22:06 -08001564 programmer_delay(100 * 1000);
David Hendricks1c09f802012-10-03 11:03:48 -07001565
1566 return result;
1567}
1568
1569/*
1570 * Set/clear the SRP1 bit in status register 2.
1571 * FIXME: make this more generic if other chips use the same SR2 layout
1572 */
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001573static int w25q_set_srp1(const struct flashctx *flash, int enable)
David Hendricks1c09f802012-10-03 11:03:48 -07001574{
1575 struct w25q_status sr1;
1576 struct w25q_status_2 sr2;
1577 uint8_t tmp, expected;
1578
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05301579 tmp = do_read_status(flash);
David Hendricks1c09f802012-10-03 11:03:48 -07001580 memcpy(&sr1, &tmp, 1);
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001581 tmp = w25q_read_status_register_2(flash);
David Hendricks1c09f802012-10-03 11:03:48 -07001582 memcpy(&sr2, &tmp, 1);
1583
1584 msg_cdbg("%s: old status 2: 0x%02x\n", __func__, tmp);
1585
1586 sr2.srp1 = enable ? 1 : 0;
1587
1588 memcpy(&expected, &sr2, 1);
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001589 w25q_write_status_register_WREN(flash, *((uint8_t *)&sr1), *((uint8_t *)&sr2));
David Hendricks1c09f802012-10-03 11:03:48 -07001590
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001591 tmp = w25q_read_status_register_2(flash);
David Hendricks1c09f802012-10-03 11:03:48 -07001592 msg_cdbg("%s: new status 2: 0x%02x\n", __func__, tmp);
1593 if ((tmp & MASK_WP2_AREA) != (expected & MASK_WP2_AREA))
1594 return 1;
1595
1596 return 0;
1597}
1598
1599enum wp_mode get_wp_mode(const char *mode_str)
1600{
1601 enum wp_mode wp_mode = WP_MODE_UNKNOWN;
1602
1603 if (!strcasecmp(mode_str, "hardware"))
1604 wp_mode = WP_MODE_HARDWARE;
1605 else if (!strcasecmp(mode_str, "power_cycle"))
1606 wp_mode = WP_MODE_POWER_CYCLE;
1607 else if (!strcasecmp(mode_str, "permanent"))
1608 wp_mode = WP_MODE_PERMANENT;
1609
1610 return wp_mode;
1611}
1612
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001613static int w25q_disable_writeprotect(const struct flashctx *flash,
David Hendricks1c09f802012-10-03 11:03:48 -07001614 enum wp_mode wp_mode)
1615{
1616 int ret = 1;
David Hendricks1c09f802012-10-03 11:03:48 -07001617 struct w25q_status_2 sr2;
1618 uint8_t tmp;
1619
1620 switch (wp_mode) {
1621 case WP_MODE_HARDWARE:
1622 ret = w25_set_srp0(flash, 0);
1623 break;
1624 case WP_MODE_POWER_CYCLE:
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001625 tmp = w25q_read_status_register_2(flash);
David Hendricks1c09f802012-10-03 11:03:48 -07001626 memcpy(&sr2, &tmp, 1);
1627 if (sr2.srp1) {
1628 msg_cerr("%s(): must disconnect power to disable "
1629 "write-protection\n", __func__);
1630 } else {
1631 ret = 0;
1632 }
1633 break;
1634 case WP_MODE_PERMANENT:
1635 msg_cerr("%s(): cannot disable permanent write-protection\n",
1636 __func__);
1637 break;
1638 default:
1639 msg_cerr("%s(): invalid mode specified\n", __func__);
1640 break;
1641 }
1642
1643 if (ret)
1644 msg_cerr("%s(): error=%d.\n", __func__, ret);
Edward O'Callaghanbea239e2019-12-04 14:42:54 +11001645
David Hendricks1c09f802012-10-03 11:03:48 -07001646 return ret;
1647}
1648
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001649static int w25q_disable_writeprotect_default(const struct flashctx *flash)
David Hendricks1c09f802012-10-03 11:03:48 -07001650{
1651 return w25q_disable_writeprotect(flash, WP_MODE_HARDWARE);
1652}
1653
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001654static int w25q_enable_writeprotect(const struct flashctx *flash,
David Hendricks1c09f802012-10-03 11:03:48 -07001655 enum wp_mode wp_mode)
1656{
1657 int ret = 1;
1658 struct w25q_status sr1;
1659 struct w25q_status_2 sr2;
1660 uint8_t tmp;
1661
1662 switch (wp_mode) {
1663 case WP_MODE_HARDWARE:
1664 if (w25q_disable_writeprotect(flash, WP_MODE_POWER_CYCLE)) {
1665 msg_cerr("%s(): cannot disable power cycle WP mode\n",
1666 __func__);
1667 break;
1668 }
1669
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05301670 tmp = do_read_status(flash);
David Hendricks1c09f802012-10-03 11:03:48 -07001671 memcpy(&sr1, &tmp, 1);
1672 if (sr1.srp0)
1673 ret = 0;
1674 else
1675 ret = w25_set_srp0(flash, 1);
1676
1677 break;
1678 case WP_MODE_POWER_CYCLE:
1679 if (w25q_disable_writeprotect(flash, WP_MODE_HARDWARE)) {
1680 msg_cerr("%s(): cannot disable hardware WP mode\n",
1681 __func__);
1682 break;
1683 }
1684
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001685 tmp = w25q_read_status_register_2(flash);
David Hendricks1c09f802012-10-03 11:03:48 -07001686 memcpy(&sr2, &tmp, 1);
1687 if (sr2.srp1)
1688 ret = 0;
1689 else
1690 ret = w25q_set_srp1(flash, 1);
1691
1692 break;
1693 case WP_MODE_PERMANENT:
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05301694 tmp = do_read_status(flash);
David Hendricks1c09f802012-10-03 11:03:48 -07001695 memcpy(&sr1, &tmp, 1);
1696 if (sr1.srp0 == 0) {
1697 ret = w25_set_srp0(flash, 1);
1698 if (ret) {
David Hendricksf1bd8802012-10-30 11:37:57 -07001699 msg_perr("%s(): cannot enable SRP0 for "
David Hendricks1c09f802012-10-03 11:03:48 -07001700 "permanent WP\n", __func__);
1701 break;
1702 }
1703 }
1704
Souvik Ghoshd75cd672016-06-17 14:21:39 -07001705 tmp = w25q_read_status_register_2(flash);
David Hendricks1c09f802012-10-03 11:03:48 -07001706 memcpy(&sr2, &tmp, 1);
1707 if (sr2.srp1 == 0) {
1708 ret = w25q_set_srp1(flash, 1);
1709 if (ret) {
David Hendricksf1bd8802012-10-30 11:37:57 -07001710 msg_perr("%s(): cannot enable SRP1 for "
David Hendricks1c09f802012-10-03 11:03:48 -07001711 "permanent WP\n", __func__);
1712 break;
1713 }
1714 }
1715
1716 break;
David Hendricksf1bd8802012-10-30 11:37:57 -07001717 default:
1718 msg_perr("%s(): invalid mode %d\n", __func__, wp_mode);
1719 break;
David Hendricks1c09f802012-10-03 11:03:48 -07001720 }
1721
1722 if (ret)
1723 msg_cerr("%s(): error=%d.\n", __func__, ret);
1724 return ret;
1725}
1726
1727/* W25P, W25X, and many flash chips from various vendors */
David Hendricksf7924d12010-06-10 21:26:44 -07001728struct wp wp_w25 = {
David Hendricks0f7f5382011-02-11 18:12:31 -08001729 .list_ranges = w25_list_ranges,
David Hendricksf7924d12010-06-10 21:26:44 -07001730 .set_range = w25_set_range,
1731 .enable = w25_enable_writeprotect,
Louis Yung-Chieh Loc19d3c52010-10-08 11:59:16 +08001732 .disable = w25_disable_writeprotect,
Louis Yung-Chieh Loa92e8b22010-10-08 13:31:27 +08001733 .wp_status = w25_wp_status,
David Hendricks1c09f802012-10-03 11:03:48 -07001734
1735};
1736
1737/* W25Q series has features such as a second status register and SFDP */
1738struct wp wp_w25q = {
1739 .list_ranges = w25_list_ranges,
1740 .set_range = w25_set_range,
1741 .enable = w25q_enable_writeprotect,
1742 /*
1743 * By default, disable hardware write-protection. We may change
1744 * this later if we want to add fine-grained write-protect disable
1745 * as a command-line option.
1746 */
1747 .disable = w25q_disable_writeprotect_default,
1748 .wp_status = w25q_wp_status,
David Hendricksf7924d12010-06-10 21:26:44 -07001749};
David Hendrickse0512a72014-07-15 20:30:47 -07001750
Duncan Laurie1801f7c2019-01-09 18:02:51 -08001751/* W25Q large series has 4 block-protect bits */
1752struct wp wp_w25q_large = {
1753 .list_ranges = w25_list_ranges,
1754 .set_range = w25q_large_set_range,
1755 .enable = w25q_enable_writeprotect,
1756 /*
1757 * By default, disable hardware write-protection. We may change
1758 * this later if we want to add fine-grained write-protect disable
1759 * as a command-line option.
1760 */
1761 .disable = w25q_disable_writeprotect_default,
1762 .wp_status = w25q_large_wp_status,
1763};
1764
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001765struct wp_range_descriptor gd25q32_cmp0_ranges[] = {
David Hendricksaf3944a2014-07-28 18:37:40 -07001766 /* none, bp4 and bp3 => don't care */
David Hendricks148a4bf2015-03-13 21:02:42 -07001767 { { }, 0x00, {0, 0} },
1768 { { }, 0x08, {0, 0} },
1769 { { }, 0x10, {0, 0} },
1770 { { }, 0x18, {0, 0} },
David Hendricksaf3944a2014-07-28 18:37:40 -07001771
David Hendricks148a4bf2015-03-13 21:02:42 -07001772 { { }, 0x01, {0x3f0000, 64 * 1024} },
1773 { { }, 0x02, {0x3e0000, 128 * 1024} },
1774 { { }, 0x03, {0x3c0000, 256 * 1024} },
1775 { { }, 0x04, {0x380000, 512 * 1024} },
1776 { { }, 0x05, {0x300000, 1024 * 1024} },
1777 { { }, 0x06, {0x200000, 2048 * 1024} },
David Hendricksaf3944a2014-07-28 18:37:40 -07001778
David Hendricks148a4bf2015-03-13 21:02:42 -07001779 { { }, 0x09, {0x000000, 64 * 1024} },
1780 { { }, 0x0a, {0x000000, 128 * 1024} },
1781 { { }, 0x0b, {0x000000, 256 * 1024} },
1782 { { }, 0x0c, {0x000000, 512 * 1024} },
1783 { { }, 0x0d, {0x000000, 1024 * 1024} },
1784 { { }, 0x0e, {0x000000, 2048 * 1024} },
David Hendricksaf3944a2014-07-28 18:37:40 -07001785
1786 /* all, bp4 and bp3 => don't care */
David Hendricks148a4bf2015-03-13 21:02:42 -07001787 { { }, 0x07, {0x000000, 4096 * 1024} },
1788 { { }, 0x0f, {0x000000, 4096 * 1024} },
1789 { { }, 0x17, {0x000000, 4096 * 1024} },
1790 { { }, 0x1f, {0x000000, 4096 * 1024} },
David Hendricksaf3944a2014-07-28 18:37:40 -07001791
David Hendricks148a4bf2015-03-13 21:02:42 -07001792 { { }, 0x11, {0x3ff000, 4 * 1024} },
1793 { { }, 0x12, {0x3fe000, 8 * 1024} },
1794 { { }, 0x13, {0x3fc000, 16 * 1024} },
1795 { { }, 0x14, {0x3f8000, 32 * 1024} }, /* bp0 => don't care */
1796 { { }, 0x15, {0x3f8000, 32 * 1024} }, /* bp0 => don't care */
1797 { { }, 0x16, {0x3f8000, 32 * 1024} },
David Hendricksaf3944a2014-07-28 18:37:40 -07001798
David Hendricks148a4bf2015-03-13 21:02:42 -07001799 { { }, 0x19, {0x000000, 4 * 1024} },
1800 { { }, 0x1a, {0x000000, 8 * 1024} },
1801 { { }, 0x1b, {0x000000, 16 * 1024} },
1802 { { }, 0x1c, {0x000000, 32 * 1024} }, /* bp0 => don't care */
1803 { { }, 0x1d, {0x000000, 32 * 1024} }, /* bp0 => don't care */
1804 { { }, 0x1e, {0x000000, 32 * 1024} },
David Hendricksaf3944a2014-07-28 18:37:40 -07001805};
1806
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001807struct wp_range_descriptor gd25q32_cmp1_ranges[] = {
Martin Roth563a1fe2017-04-18 14:26:27 -06001808 /* All, bp4 and bp3 => don't care */
1809 { { }, 0x00, {0x000000, 4096 * 1024} }, /* All */
1810 { { }, 0x08, {0x000000, 4096 * 1024} },
1811 { { }, 0x10, {0x000000, 4096 * 1024} },
1812 { { }, 0x18, {0x000000, 4096 * 1024} },
David Hendricksaf3944a2014-07-28 18:37:40 -07001813
David Hendricks148a4bf2015-03-13 21:02:42 -07001814 { { }, 0x01, {0x000000, 4032 * 1024} },
1815 { { }, 0x02, {0x000000, 3968 * 1024} },
1816 { { }, 0x03, {0x000000, 3840 * 1024} },
1817 { { }, 0x04, {0x000000, 3584 * 1024} },
1818 { { }, 0x05, {0x000000, 3 * 1024 * 1024} },
1819 { { }, 0x06, {0x000000, 2 * 1024 * 1024} },
David Hendricksaf3944a2014-07-28 18:37:40 -07001820
David Hendricks148a4bf2015-03-13 21:02:42 -07001821 { { }, 0x09, {0x010000, 4032 * 1024} },
1822 { { }, 0x0a, {0x020000, 3968 * 1024} },
1823 { { }, 0x0b, {0x040000, 3840 * 1024} },
1824 { { }, 0x0c, {0x080000, 3584 * 1024} },
1825 { { }, 0x0d, {0x100000, 3 * 1024 * 1024} },
1826 { { }, 0x0e, {0x200000, 2 * 1024 * 1024} },
David Hendricksaf3944a2014-07-28 18:37:40 -07001827
Martin Roth563a1fe2017-04-18 14:26:27 -06001828 /* None, bp4 and bp3 => don't care */
1829 { { }, 0x07, {0, 0} }, /* None */
1830 { { }, 0x0f, {0, 0} },
1831 { { }, 0x17, {0, 0} },
1832 { { }, 0x1f, {0, 0} },
David Hendricksaf3944a2014-07-28 18:37:40 -07001833
David Hendricks148a4bf2015-03-13 21:02:42 -07001834 { { }, 0x11, {0x000000, 4092 * 1024} },
1835 { { }, 0x12, {0x000000, 4088 * 1024} },
1836 { { }, 0x13, {0x000000, 4080 * 1024} },
1837 { { }, 0x14, {0x000000, 4064 * 1024} }, /* bp0 => don't care */
1838 { { }, 0x15, {0x000000, 4064 * 1024} }, /* bp0 => don't care */
1839 { { }, 0x16, {0x000000, 4064 * 1024} },
David Hendricksaf3944a2014-07-28 18:37:40 -07001840
David Hendricks148a4bf2015-03-13 21:02:42 -07001841 { { }, 0x19, {0x001000, 4092 * 1024} },
1842 { { }, 0x1a, {0x002000, 4088 * 1024} },
1843 { { }, 0x1b, {0x040000, 4080 * 1024} },
1844 { { }, 0x1c, {0x080000, 4064 * 1024} }, /* bp0 => don't care */
1845 { { }, 0x1d, {0x080000, 4064 * 1024} }, /* bp0 => don't care */
1846 { { }, 0x1e, {0x080000, 4064 * 1024} },
David Hendricksaf3944a2014-07-28 18:37:40 -07001847};
1848
1849static struct generic_wp gd25q32_wp = {
1850 /* TODO: map second status register */
1851 .sr1 = { .bp0_pos = 2, .bp_bits = 5, .srp_pos = 7 },
1852};
1853
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001854struct wp_range_descriptor gd25q128_cmp0_ranges[] = {
David Hendricks1e9d7ca2016-03-14 15:50:34 -07001855 /* none, bp4 and bp3 => don't care, others = 0 */
1856 { { .tb = 0 }, 0x00, {0, 0} },
1857 { { .tb = 0 }, 0x08, {0, 0} },
1858 { { .tb = 0 }, 0x10, {0, 0} },
1859 { { .tb = 0 }, 0x18, {0, 0} },
1860
1861 { { .tb = 0 }, 0x01, {0xfc0000, 256 * 1024} },
1862 { { .tb = 0 }, 0x02, {0xf80000, 512 * 1024} },
1863 { { .tb = 0 }, 0x03, {0xf00000, 1024 * 1024} },
1864 { { .tb = 0 }, 0x04, {0xe00000, 2048 * 1024} },
1865 { { .tb = 0 }, 0x05, {0xc00000, 4096 * 1024} },
1866 { { .tb = 0 }, 0x06, {0x800000, 8192 * 1024} },
1867
1868 { { .tb = 0 }, 0x09, {0x000000, 256 * 1024} },
1869 { { .tb = 0 }, 0x0a, {0x000000, 512 * 1024} },
1870 { { .tb = 0 }, 0x0b, {0x000000, 1024 * 1024} },
1871 { { .tb = 0 }, 0x0c, {0x000000, 2048 * 1024} },
1872 { { .tb = 0 }, 0x0d, {0x000000, 4096 * 1024} },
1873 { { .tb = 0 }, 0x0e, {0x000000, 8192 * 1024} },
1874
1875 /* all, bp4 and bp3 => don't care, others = 1 */
1876 { { .tb = 0 }, 0x07, {0x000000, 16384 * 1024} },
1877 { { .tb = 0 }, 0x0f, {0x000000, 16384 * 1024} },
1878 { { .tb = 0 }, 0x17, {0x000000, 16384 * 1024} },
1879 { { .tb = 0 }, 0x1f, {0x000000, 16384 * 1024} },
1880
1881 { { .tb = 0 }, 0x11, {0xfff000, 4 * 1024} },
1882 { { .tb = 0 }, 0x12, {0xffe000, 8 * 1024} },
1883 { { .tb = 0 }, 0x13, {0xffc000, 16 * 1024} },
1884 { { .tb = 0 }, 0x14, {0xff8000, 32 * 1024} }, /* bp0 => don't care */
1885 { { .tb = 0 }, 0x15, {0xff8000, 32 * 1024} }, /* bp0 => don't care */
1886
1887 { { .tb = 0 }, 0x19, {0x000000, 4 * 1024} },
1888 { { .tb = 0 }, 0x1a, {0x000000, 8 * 1024} },
1889 { { .tb = 0 }, 0x1b, {0x000000, 16 * 1024} },
1890 { { .tb = 0 }, 0x1c, {0x000000, 32 * 1024} }, /* bp0 => don't care */
1891 { { .tb = 0 }, 0x1d, {0x000000, 32 * 1024} }, /* bp0 => don't care */
1892 { { .tb = 0 }, 0x1e, {0x000000, 32 * 1024} },
1893};
1894
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001895struct wp_range_descriptor gd25q128_cmp1_ranges[] = {
David Hendricks1e9d7ca2016-03-14 15:50:34 -07001896 /* none, bp4 and bp3 => don't care, others = 0 */
1897 { { .tb = 1 }, 0x00, {0x000000, 16384 * 1024} },
1898 { { .tb = 1 }, 0x08, {0x000000, 16384 * 1024} },
1899 { { .tb = 1 }, 0x10, {0x000000, 16384 * 1024} },
1900 { { .tb = 1 }, 0x18, {0x000000, 16384 * 1024} },
1901
1902 { { .tb = 1 }, 0x01, {0x000000, 16128 * 1024} },
1903 { { .tb = 1 }, 0x02, {0x000000, 15872 * 1024} },
1904 { { .tb = 1 }, 0x03, {0x000000, 15360 * 1024} },
1905 { { .tb = 1 }, 0x04, {0x000000, 14336 * 1024} },
1906 { { .tb = 1 }, 0x05, {0x000000, 12288 * 1024} },
1907 { { .tb = 1 }, 0x06, {0x000000, 8192 * 1024} },
1908
1909 { { .tb = 1 }, 0x09, {0x000000, 16128 * 1024} },
1910 { { .tb = 1 }, 0x0a, {0x000000, 15872 * 1024} },
1911 { { .tb = 1 }, 0x0b, {0x000000, 15360 * 1024} },
1912 { { .tb = 1 }, 0x0c, {0x000000, 14336 * 1024} },
1913 { { .tb = 1 }, 0x0d, {0x000000, 12288 * 1024} },
1914 { { .tb = 1 }, 0x0e, {0x000000, 8192 * 1024} },
1915
1916 /* none, bp4 and bp3 => don't care, others = 1 */
1917 { { .tb = 1 }, 0x07, {0x000000, 16384 * 1024} },
1918 { { .tb = 1 }, 0x08, {0x000000, 16384 * 1024} },
1919 { { .tb = 1 }, 0x0f, {0x000000, 16384 * 1024} },
1920 { { .tb = 1 }, 0x17, {0x000000, 16384 * 1024} },
1921 { { .tb = 1 }, 0x1f, {0x000000, 16384 * 1024} },
1922
1923 { { .tb = 1 }, 0x11, {0x000000, 16380 * 1024} },
1924 { { .tb = 1 }, 0x12, {0x000000, 16376 * 1024} },
1925 { { .tb = 1 }, 0x13, {0x000000, 16368 * 1024} },
1926 { { .tb = 1 }, 0x14, {0x000000, 16352 * 1024} }, /* bp0 => don't care */
1927 { { .tb = 1 }, 0x15, {0x000000, 16352 * 1024} }, /* bp0 => don't care */
1928
1929 { { .tb = 1 }, 0x19, {0x001000, 16380 * 1024} },
1930 { { .tb = 1 }, 0x1a, {0x002000, 16376 * 1024} },
1931 { { .tb = 1 }, 0x1b, {0x004000, 16368 * 1024} },
1932 { { .tb = 1 }, 0x1c, {0x008000, 16352 * 1024} }, /* bp0 => don't care */
1933 { { .tb = 1 }, 0x1d, {0x008000, 16352 * 1024} }, /* bp0 => don't care */
1934 { { .tb = 1 }, 0x1e, {0x008000, 16352 * 1024} },
1935};
1936
1937static struct generic_wp gd25q128_wp = {
1938 /* TODO: map second and third status registers */
1939 .sr1 = { .bp0_pos = 2, .bp_bits = 5, .srp_pos = 7 },
1940};
1941
David Hendricks83541d32014-07-15 20:58:21 -07001942/* FIXME: MX25L6406 has same ID as MX25L6405D */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001943struct wp_range_descriptor mx25l6406e_ranges[] = {
David Hendricks148a4bf2015-03-13 21:02:42 -07001944 { { }, 0, {0, 0} }, /* none */
1945 { { }, 0x1, {0x7e0000, 64 * 2 * 1024} }, /* blocks 126-127 */
1946 { { }, 0x2, {0x7c0000, 64 * 4 * 1024} }, /* blocks 124-127 */
1947 { { }, 0x3, {0x7a0000, 64 * 8 * 1024} }, /* blocks 120-127 */
1948 { { }, 0x4, {0x700000, 64 * 16 * 1024} }, /* blocks 112-127 */
1949 { { }, 0x5, {0x600000, 64 * 32 * 1024} }, /* blocks 96-127 */
1950 { { }, 0x6, {0x400000, 64 * 64 * 1024} }, /* blocks 64-127 */
David Hendricks83541d32014-07-15 20:58:21 -07001951
David Hendricks148a4bf2015-03-13 21:02:42 -07001952 { { }, 0x7, {0x000000, 64 * 128 * 1024} }, /* all */
1953 { { }, 0x8, {0x000000, 64 * 128 * 1024} }, /* all */
1954 { { }, 0x9, {0x000000, 64 * 64 * 1024} }, /* blocks 0-63 */
1955 { { }, 0xa, {0x000000, 64 * 96 * 1024} }, /* blocks 0-95 */
1956 { { }, 0xb, {0x000000, 64 * 112 * 1024} }, /* blocks 0-111 */
1957 { { }, 0xc, {0x000000, 64 * 120 * 1024} }, /* blocks 0-119 */
1958 { { }, 0xd, {0x000000, 64 * 124 * 1024} }, /* blocks 0-123 */
1959 { { }, 0xe, {0x000000, 64 * 126 * 1024} }, /* blocks 0-125 */
1960 { { }, 0xf, {0x000000, 64 * 128 * 1024} }, /* all */
David Hendricks83541d32014-07-15 20:58:21 -07001961};
1962
1963static struct generic_wp mx25l6406e_wp = {
1964 .sr1 = { .bp0_pos = 2, .bp_bits = 4, .srp_pos = 7 },
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001965 .descrs = &mx25l6406e_ranges[0],
David Hendricks83541d32014-07-15 20:58:21 -07001966};
David Hendrickse0512a72014-07-15 20:30:47 -07001967
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001968struct wp_range_descriptor mx25l6495f_tb0_ranges[] = {
David Hendricks148a4bf2015-03-13 21:02:42 -07001969 { { }, 0, {0, 0} }, /* none */
1970 { { }, 0x1, {0x7f0000, 64 * 1 * 1024} }, /* block 127 */
1971 { { }, 0x2, {0x7e0000, 64 * 2 * 1024} }, /* blocks 126-127 */
1972 { { }, 0x3, {0x7c0000, 64 * 4 * 1024} }, /* blocks 124-127 */
David Hendricksc3496092014-11-13 17:20:55 -08001973
David Hendricks148a4bf2015-03-13 21:02:42 -07001974 { { }, 0x4, {0x780000, 64 * 8 * 1024} }, /* blocks 120-127 */
1975 { { }, 0x5, {0x700000, 64 * 16 * 1024} }, /* blocks 112-127 */
1976 { { }, 0x6, {0x600000, 64 * 32 * 1024} }, /* blocks 96-127 */
1977 { { }, 0x7, {0x400000, 64 * 64 * 1024} }, /* blocks 64-127 */
1978 { { }, 0x8, {0x000000, 64 * 128 * 1024} }, /* all */
1979 { { }, 0x9, {0x000000, 64 * 128 * 1024} }, /* all */
1980 { { }, 0xa, {0x000000, 64 * 128 * 1024} }, /* all */
1981 { { }, 0xb, {0x000000, 64 * 128 * 1024} }, /* all */
1982 { { }, 0xc, {0x000000, 64 * 128 * 1024} }, /* all */
1983 { { }, 0xd, {0x000000, 64 * 128 * 1024} }, /* all */
1984 { { }, 0xe, {0x000000, 64 * 128 * 1024} }, /* all */
1985 { { }, 0xf, {0x000000, 64 * 128 * 1024} }, /* all */
David Hendricksc3496092014-11-13 17:20:55 -08001986};
1987
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11001988struct wp_range_descriptor mx25l6495f_tb1_ranges[] = {
David Hendricks148a4bf2015-03-13 21:02:42 -07001989 { { }, 0, {0, 0} }, /* none */
1990 { { }, 0x1, {0x000000, 64 * 1 * 1024} }, /* block 0 */
1991 { { }, 0x2, {0x000000, 64 * 2 * 1024} }, /* blocks 0-1 */
1992 { { }, 0x3, {0x000000, 64 * 4 * 1024} }, /* blocks 0-3 */
1993 { { }, 0x4, {0x000000, 64 * 8 * 1024} }, /* blocks 0-7 */
1994 { { }, 0x5, {0x000000, 64 * 16 * 1024} }, /* blocks 0-15 */
1995 { { }, 0x6, {0x000000, 64 * 32 * 1024} }, /* blocks 0-31 */
1996 { { }, 0x7, {0x000000, 64 * 64 * 1024} }, /* blocks 0-63 */
1997 { { }, 0x8, {0x000000, 64 * 128 * 1024} }, /* all */
1998 { { }, 0x9, {0x000000, 64 * 128 * 1024} }, /* all */
1999 { { }, 0xa, {0x000000, 64 * 128 * 1024} }, /* all */
2000 { { }, 0xb, {0x000000, 64 * 128 * 1024} }, /* all */
2001 { { }, 0xc, {0x000000, 64 * 128 * 1024} }, /* all */
2002 { { }, 0xd, {0x000000, 64 * 128 * 1024} }, /* all */
2003 { { }, 0xe, {0x000000, 64 * 128 * 1024} }, /* all */
2004 { { }, 0xf, {0x000000, 64 * 128 * 1024} }, /* all */
David Hendricksc3496092014-11-13 17:20:55 -08002005};
2006
2007static struct generic_wp mx25l6495f_wp = {
2008 .sr1 = { .bp0_pos = 2, .bp_bits = 4, .srp_pos = 7 },
2009};
2010
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002011struct wp_range_descriptor mx25l25635f_tb0_ranges[] = {
Vic Yang848bfd12018-03-23 10:24:07 -07002012 { { }, 0, {0, 0} }, /* none */
2013 { { }, 0x1, {0x1ff0000, 64 * 1 * 1024} }, /* block 511 */
2014 { { }, 0x2, {0x1fe0000, 64 * 2 * 1024} }, /* blocks 510-511 */
2015 { { }, 0x3, {0x1fc0000, 64 * 4 * 1024} }, /* blocks 508-511 */
2016 { { }, 0x4, {0x1f80000, 64 * 8 * 1024} }, /* blocks 504-511 */
2017 { { }, 0x5, {0x1f00000, 64 * 16 * 1024} }, /* blocks 496-511 */
2018 { { }, 0x6, {0x1e00000, 64 * 32 * 1024} }, /* blocks 480-511 */
2019 { { }, 0x7, {0x1c00000, 64 * 64 * 1024} }, /* blocks 448-511 */
2020 { { }, 0x8, {0x1800000, 64 * 128 * 1024} }, /* blocks 384-511 */
2021 { { }, 0x9, {0x1000000, 64 * 256 * 1024} }, /* blocks 256-511 */
2022 { { }, 0xa, {0x0000000, 64 * 512 * 1024} }, /* all */
2023 { { }, 0xb, {0x0000000, 64 * 512 * 1024} }, /* all */
2024 { { }, 0xc, {0x0000000, 64 * 512 * 1024} }, /* all */
2025 { { }, 0xd, {0x0000000, 64 * 512 * 1024} }, /* all */
2026 { { }, 0xe, {0x0000000, 64 * 512 * 1024} }, /* all */
2027 { { }, 0xf, {0x0000000, 64 * 512 * 1024} }, /* all */
2028};
2029
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002030struct wp_range_descriptor mx25l25635f_tb1_ranges[] = {
Vic Yang848bfd12018-03-23 10:24:07 -07002031 { { }, 0, {0, 0} }, /* none */
2032 { { }, 0x1, {0x000000, 64 * 1 * 1024} }, /* block 0 */
2033 { { }, 0x2, {0x000000, 64 * 2 * 1024} }, /* blocks 0-1 */
2034 { { }, 0x3, {0x000000, 64 * 4 * 1024} }, /* blocks 0-3 */
2035 { { }, 0x4, {0x000000, 64 * 8 * 1024} }, /* blocks 0-7 */
2036 { { }, 0x5, {0x000000, 64 * 16 * 1024} }, /* blocks 0-15 */
2037 { { }, 0x6, {0x000000, 64 * 32 * 1024} }, /* blocks 0-31 */
2038 { { }, 0x7, {0x000000, 64 * 64 * 1024} }, /* blocks 0-63 */
2039 { { }, 0x8, {0x000000, 64 * 128 * 1024} }, /* blocks 0-127 */
2040 { { }, 0x9, {0x000000, 64 * 256 * 1024} }, /* blocks 0-255 */
2041 { { }, 0xa, {0x000000, 64 * 512 * 1024} }, /* all */
2042 { { }, 0xb, {0x000000, 64 * 512 * 1024} }, /* all */
2043 { { }, 0xc, {0x000000, 64 * 512 * 1024} }, /* all */
2044 { { }, 0xd, {0x000000, 64 * 512 * 1024} }, /* all */
2045 { { }, 0xe, {0x000000, 64 * 512 * 1024} }, /* all */
2046 { { }, 0xf, {0x000000, 64 * 512 * 1024} }, /* all */
2047};
2048
2049static struct generic_wp mx25l25635f_wp = {
2050 .sr1 = { .bp0_pos = 2, .bp_bits = 4, .srp_pos = 7 },
2051};
2052
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002053struct wp_range_descriptor s25fs128s_ranges[] = {
David Hendricks148a4bf2015-03-13 21:02:42 -07002054 { { .tb = 1 }, 0, {0, 0} }, /* none */
2055 { { .tb = 1 }, 0x1, {0x000000, 256 * 1024} }, /* lower 64th */
2056 { { .tb = 1 }, 0x2, {0x000000, 512 * 1024} }, /* lower 32nd */
2057 { { .tb = 1 }, 0x3, {0x000000, 1024 * 1024} }, /* lower 16th */
2058 { { .tb = 1 }, 0x4, {0x000000, 2048 * 1024} }, /* lower 8th */
2059 { { .tb = 1 }, 0x5, {0x000000, 4096 * 1024} }, /* lower 4th */
2060 { { .tb = 1 }, 0x6, {0x000000, 8192 * 1024} }, /* lower half */
2061 { { .tb = 1 }, 0x7, {0x000000, 16384 * 1024} }, /* all */
David Hendricksa9884852014-12-11 15:31:12 -08002062
David Hendricks148a4bf2015-03-13 21:02:42 -07002063 { { .tb = 0 }, 0, {0, 0} }, /* none */
2064 { { .tb = 0 }, 0x1, {0xfc0000, 256 * 1024} }, /* upper 64th */
2065 { { .tb = 0 }, 0x2, {0xf80000, 512 * 1024} }, /* upper 32nd */
2066 { { .tb = 0 }, 0x3, {0xf00000, 1024 * 1024} }, /* upper 16th */
2067 { { .tb = 0 }, 0x4, {0xe00000, 2048 * 1024} }, /* upper 8th */
2068 { { .tb = 0 }, 0x5, {0xc00000, 4096 * 1024} }, /* upper 4th */
2069 { { .tb = 0 }, 0x6, {0x800000, 8192 * 1024} }, /* upper half */
2070 { { .tb = 0 }, 0x7, {0x000000, 16384 * 1024} }, /* all */
David Hendricksa9884852014-12-11 15:31:12 -08002071};
2072
2073static struct generic_wp s25fs128s_wp = {
2074 .sr1 = { .bp0_pos = 2, .bp_bits = 3, .srp_pos = 7 },
David Hendricks148a4bf2015-03-13 21:02:42 -07002075 .get_modifier_bits = s25f_get_modifier_bits,
2076 .set_modifier_bits = s25f_set_modifier_bits,
David Hendricksa9884852014-12-11 15:31:12 -08002077};
2078
David Hendricksc694bb82015-02-25 14:52:17 -08002079
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002080struct wp_range_descriptor s25fl256s_ranges[] = {
David Hendricks148a4bf2015-03-13 21:02:42 -07002081 { { .tb = 1 }, 0, {0, 0} }, /* none */
2082 { { .tb = 1 }, 0x1, {0x000000, 512 * 1024} }, /* lower 64th */
2083 { { .tb = 1 }, 0x2, {0x000000, 1024 * 1024} }, /* lower 32nd */
2084 { { .tb = 1 }, 0x3, {0x000000, 2048 * 1024} }, /* lower 16th */
2085 { { .tb = 1 }, 0x4, {0x000000, 4096 * 1024} }, /* lower 8th */
2086 { { .tb = 1 }, 0x5, {0x000000, 8192 * 1024} }, /* lower 4th */
2087 { { .tb = 1 }, 0x6, {0x000000, 16384 * 1024} }, /* lower half */
2088 { { .tb = 1 }, 0x7, {0x000000, 32768 * 1024} }, /* all */
2089
2090 { { .tb = 0 }, 0, {0, 0} }, /* none */
2091 { { .tb = 0 }, 0x1, {0x1f80000, 512 * 1024} }, /* upper 64th */
2092 { { .tb = 0 }, 0x2, {0x1f00000, 1024 * 1024} }, /* upper 32nd */
2093 { { .tb = 0 }, 0x3, {0x1e00000, 2048 * 1024} }, /* upper 16th */
2094 { { .tb = 0 }, 0x4, {0x1c00000, 4096 * 1024} }, /* upper 8th */
2095 { { .tb = 0 }, 0x5, {0x1800000, 8192 * 1024} }, /* upper 4th */
2096 { { .tb = 0 }, 0x6, {0x1000000, 16384 * 1024} }, /* upper half */
2097 { { .tb = 0 }, 0x7, {0x000000, 32768 * 1024} }, /* all */
David Hendricksc694bb82015-02-25 14:52:17 -08002098};
2099
2100static struct generic_wp s25fl256s_wp = {
2101 .sr1 = { .bp0_pos = 2, .bp_bits = 3, .srp_pos = 7 },
David Hendricks148a4bf2015-03-13 21:02:42 -07002102 .get_modifier_bits = s25f_get_modifier_bits,
2103 .set_modifier_bits = s25f_set_modifier_bits,
David Hendricksc694bb82015-02-25 14:52:17 -08002104};
2105
David Hendrickse0512a72014-07-15 20:30:47 -07002106/* Given a flash chip, this function returns its writeprotect info. */
Souvik Ghoshd75cd672016-06-17 14:21:39 -07002107static int generic_range_table(const struct flashctx *flash,
David Hendrickse0512a72014-07-15 20:30:47 -07002108 struct generic_wp **wp,
2109 int *num_entries)
2110{
2111 *wp = NULL;
2112 *num_entries = 0;
2113
Patrick Georgif3fa2992017-02-02 16:24:44 +01002114 switch (flash->chip->manufacture_id) {
David Hendricksaf3944a2014-07-28 18:37:40 -07002115 case GIGADEVICE_ID:
Patrick Georgif3fa2992017-02-02 16:24:44 +01002116 switch(flash->chip->model_id) {
David Hendricks1e9d7ca2016-03-14 15:50:34 -07002117
Martin Roth563a1fe2017-04-18 14:26:27 -06002118 case GIGADEVICE_GD25LQ32:
David Hendricksaf3944a2014-07-28 18:37:40 -07002119 case GIGADEVICE_GD25Q32: {
Souvik Ghoshd75cd672016-06-17 14:21:39 -07002120 uint8_t sr1 = w25q_read_status_register_2(flash);
David Hendricksaf3944a2014-07-28 18:37:40 -07002121 *wp = &gd25q32_wp;
David Hendricks1e9d7ca2016-03-14 15:50:34 -07002122
David Hendricksaf3944a2014-07-28 18:37:40 -07002123 if (!(sr1 & (1 << 6))) { /* CMP == 0 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002124 (*wp)->descrs = &gd25q32_cmp0_ranges[0];
David Hendricksaf3944a2014-07-28 18:37:40 -07002125 *num_entries = ARRAY_SIZE(gd25q32_cmp0_ranges);
2126 } else { /* CMP == 1 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002127 (*wp)->descrs = &gd25q32_cmp1_ranges[0];
David Hendricksaf3944a2014-07-28 18:37:40 -07002128 *num_entries = ARRAY_SIZE(gd25q32_cmp1_ranges);
2129 }
2130
2131 break;
David Hendricks1e9d7ca2016-03-14 15:50:34 -07002132 }
Furquan Shaikh62cd8102016-07-17 23:04:06 -07002133 case GIGADEVICE_GD25Q128:
Aaron Durbin6c957d72018-08-20 09:31:01 -06002134 case GIGADEVICE_GD25LQ128CD: {
Souvik Ghoshd75cd672016-06-17 14:21:39 -07002135 uint8_t sr1 = w25q_read_status_register_2(flash);
David Hendricks1e9d7ca2016-03-14 15:50:34 -07002136 *wp = &gd25q128_wp;
2137
2138 if (!(sr1 & (1 << 6))) { /* CMP == 0 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002139 (*wp)->descrs = &gd25q128_cmp0_ranges[0];
David Hendricks1e9d7ca2016-03-14 15:50:34 -07002140 *num_entries = ARRAY_SIZE(gd25q128_cmp0_ranges);
2141 } else { /* CMP == 1 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002142 (*wp)->descrs = &gd25q128_cmp1_ranges[0];
David Hendricks1e9d7ca2016-03-14 15:50:34 -07002143 *num_entries = ARRAY_SIZE(gd25q128_cmp1_ranges);
2144 }
2145
2146 break;
David Hendricksaf3944a2014-07-28 18:37:40 -07002147 }
2148 default:
2149 msg_cerr("%s() %d: GigaDevice flash chip mismatch"
2150 " (0x%04x), aborting\n", __func__, __LINE__,
Patrick Georgif3fa2992017-02-02 16:24:44 +01002151 flash->chip->model_id);
David Hendricksaf3944a2014-07-28 18:37:40 -07002152 return -1;
2153 }
2154 break;
David Hendricks83541d32014-07-15 20:58:21 -07002155 case MACRONIX_ID:
Patrick Georgif3fa2992017-02-02 16:24:44 +01002156 switch (flash->chip->model_id) {
David Hendricks83541d32014-07-15 20:58:21 -07002157 case MACRONIX_MX25L6405:
2158 /* FIXME: MX25L64* chips have mixed capabilities and
2159 share IDs */
2160 *wp = &mx25l6406e_wp;
2161 *num_entries = ARRAY_SIZE(mx25l6406e_ranges);
2162 break;
David Hendricksc3496092014-11-13 17:20:55 -08002163 case MACRONIX_MX25L6495F: {
Souvik Ghoshd75cd672016-06-17 14:21:39 -07002164 uint8_t cr = mx25l_read_config_register(flash);
David Hendricksc3496092014-11-13 17:20:55 -08002165
2166 *wp = &mx25l6495f_wp;
2167 if (!(cr & (1 << 3))) { /* T/B == 0 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002168 (*wp)->descrs = &mx25l6495f_tb0_ranges[0];
David Hendricksc3496092014-11-13 17:20:55 -08002169 *num_entries = ARRAY_SIZE(mx25l6495f_tb0_ranges);
2170 } else { /* T/B == 1 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002171 (*wp)->descrs = &mx25l6495f_tb1_ranges[0];
David Hendricksc3496092014-11-13 17:20:55 -08002172 *num_entries = ARRAY_SIZE(mx25l6495f_tb1_ranges);
2173 }
2174 break;
2175 }
Vic Yang848bfd12018-03-23 10:24:07 -07002176 case MACRONIX_MX25L25635F: {
2177 uint8_t cr = mx25l_read_config_register(flash);
2178
2179 *wp = &mx25l25635f_wp;
2180 if (!(cr & (1 << 3))) { /* T/B == 0 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002181 (*wp)->descrs = &mx25l25635f_tb0_ranges[0];
Vic Yang848bfd12018-03-23 10:24:07 -07002182 *num_entries = ARRAY_SIZE(mx25l25635f_tb0_ranges);
2183 } else { /* T/B == 1 */
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002184 (*wp)->descrs = &mx25l25635f_tb1_ranges[0];
Vic Yang848bfd12018-03-23 10:24:07 -07002185 *num_entries = ARRAY_SIZE(mx25l25635f_tb1_ranges);
2186 }
2187 break;
2188 }
David Hendricks83541d32014-07-15 20:58:21 -07002189 default:
2190 msg_cerr("%s():%d: MXIC flash chip mismatch (0x%04x)"
2191 ", aborting\n", __func__, __LINE__,
Patrick Georgif3fa2992017-02-02 16:24:44 +01002192 flash->chip->model_id);
David Hendricks83541d32014-07-15 20:58:21 -07002193 return -1;
2194 }
2195 break;
David Hendricksa9884852014-12-11 15:31:12 -08002196 case SPANSION_ID:
Patrick Georgif3fa2992017-02-02 16:24:44 +01002197 switch (flash->chip->model_id) {
David Hendricksa9884852014-12-11 15:31:12 -08002198 case SPANSION_S25FS128S_L:
2199 case SPANSION_S25FS128S_S: {
David Hendricksa9884852014-12-11 15:31:12 -08002200 *wp = &s25fs128s_wp;
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002201 (*wp)->descrs = s25fs128s_ranges;
David Hendricks148a4bf2015-03-13 21:02:42 -07002202 *num_entries = ARRAY_SIZE(s25fs128s_ranges);
David Hendricksa9884852014-12-11 15:31:12 -08002203 break;
2204 }
David Hendricksc694bb82015-02-25 14:52:17 -08002205 case SPANSION_S25FL256S_UL:
2206 case SPANSION_S25FL256S_US: {
David Hendricksc694bb82015-02-25 14:52:17 -08002207 *wp = &s25fl256s_wp;
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002208 (*wp)->descrs = s25fl256s_ranges;
David Hendricks148a4bf2015-03-13 21:02:42 -07002209 *num_entries = ARRAY_SIZE(s25fl256s_ranges);
David Hendricksc694bb82015-02-25 14:52:17 -08002210 break;
2211 }
David Hendricksa9884852014-12-11 15:31:12 -08002212 default:
2213 msg_cerr("%s():%d Spansion flash chip mismatch (0x%04x)"
Patrick Georgif3fa2992017-02-02 16:24:44 +01002214 ", aborting\n", __func__, __LINE__,
2215 flash->chip->model_id);
David Hendricksa9884852014-12-11 15:31:12 -08002216 return -1;
2217 }
2218 break;
David Hendrickse0512a72014-07-15 20:30:47 -07002219 default:
2220 msg_cerr("%s: flash vendor (0x%x) not found, aborting\n",
Patrick Georgif3fa2992017-02-02 16:24:44 +01002221 __func__, flash->chip->manufacture_id);
David Hendrickse0512a72014-07-15 20:30:47 -07002222 return -1;
2223 }
2224
2225 return 0;
2226}
2227
Marco Chen9d5bddb2020-02-11 17:12:56 +08002228static uint8_t generic_get_bp_mask(struct generic_wp *wp)
2229{
2230 return ((1 << (wp->sr1.bp0_pos + wp->sr1.bp_bits)) - 1) ^ \
2231 ((1 << wp->sr1.bp0_pos) - 1);
2232}
2233
2234static uint8_t generic_get_status_check_mask(struct generic_wp *wp)
2235{
2236 return generic_get_bp_mask(wp) | 1 << wp->sr1.srp_pos;
2237}
2238
David Hendrickse0512a72014-07-15 20:30:47 -07002239/* Given a [start, len], this function finds a block protect bit combination
2240 * (if possible) and sets the corresponding bits in "status". Remaining bits
2241 * are preserved. */
Souvik Ghoshd75cd672016-06-17 14:21:39 -07002242static int generic_range_to_status(const struct flashctx *flash,
David Hendrickse0512a72014-07-15 20:30:47 -07002243 unsigned int start, unsigned int len,
Marco Chen9d5bddb2020-02-11 17:12:56 +08002244 uint8_t *status, uint8_t *check_mask)
David Hendrickse0512a72014-07-15 20:30:47 -07002245{
2246 struct generic_wp *wp;
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002247 struct wp_range_descriptor *r;
David Hendrickse0512a72014-07-15 20:30:47 -07002248 int i, range_found = 0, num_entries;
2249 uint8_t bp_mask;
2250
2251 if (generic_range_table(flash, &wp, &num_entries))
2252 return -1;
2253
Marco Chen9d5bddb2020-02-11 17:12:56 +08002254 bp_mask = generic_get_bp_mask(wp);
David Hendrickse0512a72014-07-15 20:30:47 -07002255
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002256 for (i = 0, r = &wp->descrs[0]; i < num_entries; i++, r++) {
David Hendrickse0512a72014-07-15 20:30:47 -07002257 msg_cspew("comparing range 0x%x 0x%x / 0x%x 0x%x\n",
2258 start, len, r->range.start, r->range.len);
2259 if ((start == r->range.start) && (len == r->range.len)) {
2260 *status &= ~(bp_mask);
2261 *status |= r->bp << (wp->sr1.bp0_pos);
David Hendricks148a4bf2015-03-13 21:02:42 -07002262
2263 if (wp->set_modifier_bits) {
2264 if (wp->set_modifier_bits(flash, &r->m) < 0) {
2265 msg_cerr("error setting modifier "
2266 "bits for range.\n");
2267 return -1;
2268 }
2269 }
2270
David Hendrickse0512a72014-07-15 20:30:47 -07002271 range_found = 1;
2272 break;
2273 }
2274 }
2275
2276 if (!range_found) {
2277 msg_cerr("matching range not found\n");
2278 return -1;
2279 }
Edward O'Callaghanbea239e2019-12-04 14:42:54 +11002280
Marco Chen9d5bddb2020-02-11 17:12:56 +08002281 *check_mask = generic_get_status_check_mask(wp);
David Hendrickse0512a72014-07-15 20:30:47 -07002282 return 0;
2283}
2284
Souvik Ghoshd75cd672016-06-17 14:21:39 -07002285static int generic_status_to_range(const struct flashctx *flash,
David Hendrickse0512a72014-07-15 20:30:47 -07002286 const uint8_t sr1, unsigned int *start, unsigned int *len)
2287{
2288 struct generic_wp *wp;
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002289 struct wp_range_descriptor *r;
Duncan Laurie04ca1172015-03-12 09:25:34 -07002290 int num_entries, i, status_found = 0;
David Hendrickse0512a72014-07-15 20:30:47 -07002291 uint8_t sr1_bp;
Edward O'Callaghan9c4c9a52019-12-04 18:18:01 +11002292 struct modifier_bits m;
David Hendrickse0512a72014-07-15 20:30:47 -07002293
2294 if (generic_range_table(flash, &wp, &num_entries))
2295 return -1;
2296
David Hendricks148a4bf2015-03-13 21:02:42 -07002297 /* modifier bits may be compared more than once, so get them here */
Edward O'Callaghanadcc7782019-12-04 14:50:14 +11002298 if (wp->get_modifier_bits && wp->get_modifier_bits(flash, &m) < 0)
David Hendricks148a4bf2015-03-13 21:02:42 -07002299 return -1;
David Hendricks148a4bf2015-03-13 21:02:42 -07002300
David Hendrickse0512a72014-07-15 20:30:47 -07002301 sr1_bp = (sr1 >> wp->sr1.bp0_pos) & ((1 << wp->sr1.bp_bits) - 1);
2302
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002303 for (i = 0, r = &wp->descrs[0]; i < num_entries; i++, r++) {
David Hendricks148a4bf2015-03-13 21:02:42 -07002304 if (wp->get_modifier_bits) {
2305 if (memcmp(&m, &r->m, sizeof(m)))
2306 continue;
2307 }
David Hendrickse0512a72014-07-15 20:30:47 -07002308 msg_cspew("comparing 0x%02x 0x%02x\n", sr1_bp, r->bp);
2309 if (sr1_bp == r->bp) {
2310 *start = r->range.start;
2311 *len = r->range.len;
2312 status_found = 1;
2313 break;
2314 }
2315 }
2316
2317 if (!status_found) {
2318 msg_cerr("matching status not found\n");
2319 return -1;
2320 }
Edward O'Callaghanbea239e2019-12-04 14:42:54 +11002321
David Hendrickse0512a72014-07-15 20:30:47 -07002322 return 0;
2323}
2324
2325/* Given a [start, len], this function calls generic_range_to_status() to
2326 * convert it to flash-chip-specific range bits, then sets into status register.
2327 */
Souvik Ghoshd75cd672016-06-17 14:21:39 -07002328static int generic_set_range(const struct flashctx *flash,
David Hendrickse0512a72014-07-15 20:30:47 -07002329 unsigned int start, unsigned int len)
2330{
Marco Chen9d5bddb2020-02-11 17:12:56 +08002331 uint8_t status, expected, check_mask;
David Hendrickse0512a72014-07-15 20:30:47 -07002332
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05302333 status = do_read_status(flash);
David Hendrickse0512a72014-07-15 20:30:47 -07002334 msg_cdbg("%s: old status: 0x%02x\n", __func__, status);
2335
2336 expected = status; /* preserve non-bp bits */
Marco Chen9d5bddb2020-02-11 17:12:56 +08002337 if (generic_range_to_status(flash, start, len, &expected, &check_mask))
David Hendrickse0512a72014-07-15 20:30:47 -07002338 return -1;
2339
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05302340 do_write_status(flash, expected);
David Hendrickse0512a72014-07-15 20:30:47 -07002341
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05302342 status = do_read_status(flash);
David Hendrickse0512a72014-07-15 20:30:47 -07002343 msg_cdbg("%s: new status: 0x%02x\n", __func__, status);
Marco Chen9d5bddb2020-02-11 17:12:56 +08002344 if ((status & check_mask) != (expected & check_mask)) {
2345 msg_cerr("expected=0x%02x, but actual=0x%02x. check mask=0x%02x\n",
2346 expected, status, check_mask);
David Hendrickse0512a72014-07-15 20:30:47 -07002347 return 1;
2348 }
David Hendrickse0512a72014-07-15 20:30:47 -07002349 return 0;
2350}
2351
2352/* Set/clear the status regsiter write protect bit in SR1. */
Souvik Ghoshd75cd672016-06-17 14:21:39 -07002353static int generic_set_srp0(const struct flashctx *flash, int enable)
David Hendrickse0512a72014-07-15 20:30:47 -07002354{
Marco Chen9d5bddb2020-02-11 17:12:56 +08002355 uint8_t status, expected, check_mask;
David Hendrickse0512a72014-07-15 20:30:47 -07002356 struct generic_wp *wp;
2357 int num_entries;
2358
2359 if (generic_range_table(flash, &wp, &num_entries))
2360 return -1;
2361
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05302362 expected = do_read_status(flash);
David Hendrickse0512a72014-07-15 20:30:47 -07002363 msg_cdbg("%s: old status: 0x%02x\n", __func__, expected);
2364
2365 if (enable)
2366 expected |= 1 << wp->sr1.srp_pos;
2367 else
2368 expected &= ~(1 << wp->sr1.srp_pos);
2369
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05302370 do_write_status(flash, expected);
David Hendrickse0512a72014-07-15 20:30:47 -07002371
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05302372 status = do_read_status(flash);
David Hendrickse0512a72014-07-15 20:30:47 -07002373 msg_cdbg("%s: new status: 0x%02x\n", __func__, status);
Marco Chen9d5bddb2020-02-11 17:12:56 +08002374
2375 check_mask = generic_get_status_check_mask(wp);
2376 msg_cdbg("%s: check mask: 0x%02x\n", __func__, check_mask);
2377 if ((status & check_mask) != (expected & check_mask)) {
2378 msg_cerr("expected=0x%02x, but actual=0x%02x. check mask=0x%02x\n",
2379 expected, status, check_mask);
David Hendrickse0512a72014-07-15 20:30:47 -07002380 return -1;
Marco Chen9d5bddb2020-02-11 17:12:56 +08002381 }
David Hendrickse0512a72014-07-15 20:30:47 -07002382
2383 return 0;
2384}
2385
Souvik Ghoshd75cd672016-06-17 14:21:39 -07002386static int generic_enable_writeprotect(const struct flashctx *flash,
David Hendrickse0512a72014-07-15 20:30:47 -07002387 enum wp_mode wp_mode)
2388{
2389 int ret;
2390
Edward O'Callaghanca44e5c2019-12-04 14:23:54 +11002391 if (wp_mode != WP_MODE_HARDWARE) {
David Hendrickse0512a72014-07-15 20:30:47 -07002392 msg_cerr("%s(): unsupported write-protect mode\n", __func__);
2393 return 1;
2394 }
2395
Edward O'Callaghanca44e5c2019-12-04 14:23:54 +11002396 ret = generic_set_srp0(flash, 1);
David Hendrickse0512a72014-07-15 20:30:47 -07002397 if (ret)
2398 msg_cerr("%s(): error=%d.\n", __func__, ret);
Edward O'Callaghanca44e5c2019-12-04 14:23:54 +11002399
David Hendrickse0512a72014-07-15 20:30:47 -07002400 return ret;
2401}
2402
Souvik Ghoshd75cd672016-06-17 14:21:39 -07002403static int generic_disable_writeprotect(const struct flashctx *flash)
David Hendrickse0512a72014-07-15 20:30:47 -07002404{
2405 int ret;
2406
2407 ret = generic_set_srp0(flash, 0);
2408 if (ret)
2409 msg_cerr("%s(): error=%d.\n", __func__, ret);
Edward O'Callaghanbea239e2019-12-04 14:42:54 +11002410
David Hendrickse0512a72014-07-15 20:30:47 -07002411 return ret;
2412}
2413
Souvik Ghoshd75cd672016-06-17 14:21:39 -07002414static int generic_list_ranges(const struct flashctx *flash)
David Hendrickse0512a72014-07-15 20:30:47 -07002415{
2416 struct generic_wp *wp;
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002417 struct wp_range_descriptor *r;
David Hendrickse0512a72014-07-15 20:30:47 -07002418 int i, num_entries;
2419
2420 if (generic_range_table(flash, &wp, &num_entries))
2421 return -1;
2422
Edward O'Callaghane146f9a2019-12-05 14:27:24 +11002423 r = &wp->descrs[0];
David Hendrickse0512a72014-07-15 20:30:47 -07002424 for (i = 0; i < num_entries; i++) {
2425 msg_cinfo("start: 0x%06x, length: 0x%06x\n",
2426 r->range.start, r->range.len);
2427 r++;
2428 }
2429
2430 return 0;
2431}
2432
Souvik Ghoshd75cd672016-06-17 14:21:39 -07002433static int generic_wp_status(const struct flashctx *flash)
David Hendrickse0512a72014-07-15 20:30:47 -07002434{
2435 uint8_t sr1;
2436 unsigned int start, len;
2437 int ret = 0;
2438 struct generic_wp *wp;
David Hendrickse0512a72014-07-15 20:30:47 -07002439 int num_entries, wp_en;
2440
2441 if (generic_range_table(flash, &wp, &num_entries))
2442 return -1;
2443
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +05302444 sr1 = do_read_status(flash);
David Hendrickse0512a72014-07-15 20:30:47 -07002445 wp_en = (sr1 >> wp->sr1.srp_pos) & 1;
2446
2447 msg_cinfo("WP: status: 0x%04x\n", sr1);
2448 msg_cinfo("WP: status.srp0: %x\n", wp_en);
2449 /* FIXME: SRP1 is not really generic, but we probably should print
2450 * it anyway to have consistent output. #legacycruft */
2451 msg_cinfo("WP: status.srp1: %x\n", 0);
2452 msg_cinfo("WP: write protect is %s.\n",
2453 wp_en ? "enabled" : "disabled");
2454
2455 msg_cinfo("WP: write protect range: ");
2456 if (generic_status_to_range(flash, sr1, &start, &len)) {
2457 msg_cinfo("(cannot resolve the range)\n");
2458 ret = -1;
2459 } else {
2460 msg_cinfo("start=0x%08x, len=0x%08x\n", start, len);
2461 }
2462
2463 return ret;
2464}
2465
2466struct wp wp_generic = {
2467 .list_ranges = generic_list_ranges,
2468 .set_range = generic_set_range,
2469 .enable = generic_enable_writeprotect,
2470 .disable = generic_disable_writeprotect,
2471 .wp_status = generic_wp_status,
2472};