jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / flash / nand / arm_io.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /*
4 * Copyright (C) 2009 by Marvell Semiconductors, Inc.
5 * Written by Nicolas Pitre <nico at marvell.com>
6 *
7 * Copyright (C) 2009 by David Brownell
8 */
9
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13
14 #include "core.h"
15 #include "arm_io.h"
16 #include <helper/binarybuffer.h>
17 #include <target/arm.h>
18 #include <target/armv7m.h>
19 #include <target/algorithm.h>
20
21 /**
22 * Copies code to a working area. This will allocate room for the code plus the
23 * additional amount requested if the working area pointer is null.
24 *
25 * @param target Pointer to the target to copy code to
26 * @param code Pointer to the code area to be copied
27 * @param code_size Size of the code being copied
28 * @param additional Size of the additional area to be allocated in addition to
29 * code
30 * @param area Pointer to a pointer to a working area to copy code to
31 * @return Success or failure of the operation
32 */
33 static int arm_code_to_working_area(struct target *target,
34 const uint32_t *code, unsigned code_size,
35 unsigned additional, struct working_area **area)
36 {
37 uint8_t code_buf[code_size];
38 int retval;
39 unsigned size = code_size + additional;
40
41 /* REVISIT this assumes size doesn't ever change.
42 * That's usually correct; but there are boards with
43 * both large and small page chips, where it won't be...
44 */
45
46 /* make sure we have a working area */
47 if (!*area) {
48 retval = target_alloc_working_area(target, size, area);
49 if (retval != ERROR_OK) {
50 LOG_DEBUG("%s: no %d byte buffer", __func__, (int) size);
51 return ERROR_NAND_NO_BUFFER;
52 }
53 }
54
55 /* buffer code in target endianness */
56 target_buffer_set_u32_array(target, code_buf, code_size / 4, code);
57
58 /* copy code to work area */
59 retval = target_write_memory(target, (*area)->address,
60 4, code_size / 4, code_buf);
61
62 return retval;
63 }
64
65 /**
66 * ARM-specific bulk write from buffer to address of 8-bit wide NAND.
67 * For now this supports ARMv4,ARMv5 and ARMv7-M cores.
68 *
69 * Enhancements to target_run_algorithm() could enable:
70 * - ARMv6 and ARMv7 cores in ARM mode
71 *
72 * Different code fragments could handle:
73 * - 16-bit wide data (needs different setup)
74 *
75 * @param nand Pointer to the arm_nand_data struct that defines the I/O
76 * @param data Pointer to the data to be copied to flash
77 * @param size Size of the data being copied
78 * @return Success or failure of the operation
79 */
80 int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
81 {
82 struct target *target = nand->target;
83 struct arm_algorithm armv4_5_algo;
84 struct armv7m_algorithm armv7m_algo;
85 void *arm_algo;
86 struct arm *arm = target->arch_info;
87 struct reg_param reg_params[3];
88 uint32_t target_buf;
89 uint32_t exit_var = 0;
90 int retval;
91
92 /* Inputs:
93 * r0 NAND data address (byte wide)
94 * r1 buffer address
95 * r2 buffer length
96 */
97 static const uint32_t code_armv4_5[] = {
98 0xe4d13001, /* s: ldrb r3, [r1], #1 */
99 0xe5c03000, /* strb r3, [r0] */
100 0xe2522001, /* subs r2, r2, #1 */
101 0x1afffffb, /* bne s */
102
103 /* exit: ARMv4 needs hardware breakpoint */
104 0xe1200070, /* e: bkpt #0 */
105 };
106
107 /* Inputs:
108 * r0 NAND data address (byte wide)
109 * r1 buffer address
110 * r2 buffer length
111 *
112 * see contrib/loaders/flash/armv7m_io.s for src
113 */
114 static const uint32_t code_armv7m[] = {
115 0x3b01f811,
116 0x3a017003,
117 0xaffaf47f,
118 0xbf00be00,
119 };
120
121 int target_code_size = 0;
122 const uint32_t *target_code_src = NULL;
123
124 /* set up algorithm */
125 if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */
126 armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
127 armv7m_algo.core_mode = ARM_MODE_THREAD;
128 arm_algo = &armv7m_algo;
129 target_code_size = sizeof(code_armv7m);
130 target_code_src = code_armv7m;
131 } else {
132 armv4_5_algo.common_magic = ARM_COMMON_MAGIC;
133 armv4_5_algo.core_mode = ARM_MODE_SVC;
134 armv4_5_algo.core_state = ARM_STATE_ARM;
135 arm_algo = &armv4_5_algo;
136 target_code_size = sizeof(code_armv4_5);
137 target_code_src = code_armv4_5;
138 }
139
140 if (nand->op != ARM_NAND_WRITE || !nand->copy_area) {
141 retval = arm_code_to_working_area(target, target_code_src, target_code_size,
142 nand->chunk_size, &nand->copy_area);
143 if (retval != ERROR_OK)
144 return retval;
145 }
146
147 nand->op = ARM_NAND_WRITE;
148
149 /* copy data to work area */
150 target_buf = nand->copy_area->address + target_code_size;
151 retval = target_write_buffer(target, target_buf, size, data);
152 if (retval != ERROR_OK)
153 return retval;
154
155 /* set up parameters */
156 init_reg_param(&reg_params[0], "r0", 32, PARAM_IN);
157 init_reg_param(&reg_params[1], "r1", 32, PARAM_IN);
158 init_reg_param(&reg_params[2], "r2", 32, PARAM_IN);
159
160 buf_set_u32(reg_params[0].value, 0, 32, nand->data);
161 buf_set_u32(reg_params[1].value, 0, 32, target_buf);
162 buf_set_u32(reg_params[2].value, 0, 32, size);
163
164 /* armv4 must exit using a hardware breakpoint */
165 if (arm->arch == ARM_ARCH_V4)
166 exit_var = nand->copy_area->address + target_code_size - 4;
167
168 /* use alg to write data from work area to NAND chip */
169 retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
170 nand->copy_area->address, exit_var, 1000, arm_algo);
171 if (retval != ERROR_OK)
172 LOG_ERROR("error executing hosted NAND write");
173
174 destroy_reg_param(&reg_params[0]);
175 destroy_reg_param(&reg_params[1]);
176 destroy_reg_param(&reg_params[2]);
177
178 return retval;
179 }
180
181 /**
182 * Uses an on-chip algorithm for an ARM device to read from a NAND device and
183 * store the data into the host machine's memory.
184 *
185 * @param nand Pointer to the arm_nand_data struct that defines the I/O
186 * @param data Pointer to the data buffer to store the read data
187 * @param size Amount of data to be stored to the buffer.
188 * @return Success or failure of the operation
189 */
190 int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
191 {
192 struct target *target = nand->target;
193 struct arm_algorithm armv4_5_algo;
194 struct armv7m_algorithm armv7m_algo;
195 void *arm_algo;
196 struct arm *arm = target->arch_info;
197 struct reg_param reg_params[3];
198 uint32_t target_buf;
199 uint32_t exit_var = 0;
200 int retval;
201
202 /* Inputs:
203 * r0 buffer address
204 * r1 NAND data address (byte wide)
205 * r2 buffer length
206 */
207 static const uint32_t code_armv4_5[] = {
208 0xe5d13000, /* s: ldrb r3, [r1] */
209 0xe4c03001, /* strb r3, [r0], #1 */
210 0xe2522001, /* subs r2, r2, #1 */
211 0x1afffffb, /* bne s */
212
213 /* exit: ARMv4 needs hardware breakpoint */
214 0xe1200070, /* e: bkpt #0 */
215 };
216
217 /* Inputs:
218 * r0 buffer address
219 * r1 NAND data address (byte wide)
220 * r2 buffer length
221 *
222 * see contrib/loaders/flash/armv7m_io.s for src
223 */
224 static const uint32_t code_armv7m[] = {
225 0xf800780b,
226 0x3a013b01,
227 0xaffaf47f,
228 0xbf00be00,
229 };
230
231 int target_code_size = 0;
232 const uint32_t *target_code_src = NULL;
233
234 /* set up algorithm */
235 if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */
236 armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
237 armv7m_algo.core_mode = ARM_MODE_THREAD;
238 arm_algo = &armv7m_algo;
239 target_code_size = sizeof(code_armv7m);
240 target_code_src = code_armv7m;
241 } else {
242 armv4_5_algo.common_magic = ARM_COMMON_MAGIC;
243 armv4_5_algo.core_mode = ARM_MODE_SVC;
244 armv4_5_algo.core_state = ARM_STATE_ARM;
245 arm_algo = &armv4_5_algo;
246 target_code_size = sizeof(code_armv4_5);
247 target_code_src = code_armv4_5;
248 }
249
250 /* create the copy area if not yet available */
251 if (nand->op != ARM_NAND_READ || !nand->copy_area) {
252 retval = arm_code_to_working_area(target, target_code_src, target_code_size,
253 nand->chunk_size, &nand->copy_area);
254 if (retval != ERROR_OK)
255 return retval;
256 }
257
258 nand->op = ARM_NAND_READ;
259 target_buf = nand->copy_area->address + target_code_size;
260
261 /* set up parameters */
262 init_reg_param(&reg_params[0], "r0", 32, PARAM_IN);
263 init_reg_param(&reg_params[1], "r1", 32, PARAM_IN);
264 init_reg_param(&reg_params[2], "r2", 32, PARAM_IN);
265
266 buf_set_u32(reg_params[0].value, 0, 32, target_buf);
267 buf_set_u32(reg_params[1].value, 0, 32, nand->data);
268 buf_set_u32(reg_params[2].value, 0, 32, size);
269
270 /* armv4 must exit using a hardware breakpoint */
271 if (arm->arch == ARM_ARCH_V4)
272 exit_var = nand->copy_area->address + target_code_size - 4;
273
274 /* use alg to write data from NAND chip to work area */
275 retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
276 nand->copy_area->address, exit_var, 1000, arm_algo);
277 if (retval != ERROR_OK)
278 LOG_ERROR("error executing hosted NAND read");
279
280 destroy_reg_param(&reg_params[0]);
281 destroy_reg_param(&reg_params[1]);
282 destroy_reg_param(&reg_params[2]);
283
284 /* read from work area to the host's memory */
285 retval = target_read_buffer(target, target_buf, size, data);
286
287 return retval;
288 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)