1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2009 by Marvell Semiconductors, Inc.
5 * Written by Nicolas Pitre <nico at marvell.com>
7 * Copyright (C) 2009 by David Brownell
16 #include <helper/binarybuffer.h>
17 #include <target/arm.h>
18 #include <target/armv7m.h>
19 #include <target/algorithm.h>
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.
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
30 * @param area Pointer to a pointer to a working area to copy code to
31 * @return Success or failure of the operation
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
)
37 uint8_t code_buf
[code_size
];
39 unsigned size
= code_size
+ additional
;
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...
46 /* make sure we have a working 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
;
55 /* buffer code in target endianness */
56 target_buffer_set_u32_array(target
, code_buf
, code_size
/ 4, code
);
58 /* copy code to work area */
59 retval
= target_write_memory(target
, (*area
)->address
,
60 4, code_size
/ 4, code_buf
);
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.
69 * Enhancements to target_run_algorithm() could enable:
70 * - ARMv6 and ARMv7 cores in ARM mode
72 * Different code fragments could handle:
73 * - 16-bit wide data (needs different setup)
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
80 int arm_nandwrite(struct arm_nand_data
*nand
, uint8_t *data
, int size
)
82 struct target
*target
= nand
->target
;
83 struct arm_algorithm armv4_5_algo
;
84 struct armv7m_algorithm armv7m_algo
;
86 struct arm
*arm
= target
->arch_info
;
87 struct reg_param reg_params
[3];
89 uint32_t exit_var
= 0;
93 * r0 NAND data address (byte wide)
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 */
103 /* exit: ARMv4 needs hardware breakpoint */
104 0xe1200070, /* e: bkpt #0 */
108 * r0 NAND data address (byte wide)
112 * see contrib/loaders/flash/armv7m_io.s for src
114 static const uint32_t code_armv7m
[] = {
121 int target_code_size
= 0;
122 const uint32_t *target_code_src
= NULL
;
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
;
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
;
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
)
147 nand
->op
= ARM_NAND_WRITE
;
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
)
155 /* set up parameters */
156 init_reg_param(®_params
[0], "r0", 32, PARAM_IN
);
157 init_reg_param(®_params
[1], "r1", 32, PARAM_IN
);
158 init_reg_param(®_params
[2], "r2", 32, PARAM_IN
);
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
);
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;
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");
174 destroy_reg_param(®_params
[0]);
175 destroy_reg_param(®_params
[1]);
176 destroy_reg_param(®_params
[2]);
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.
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
190 int arm_nandread(struct arm_nand_data
*nand
, uint8_t *data
, uint32_t size
)
192 struct target
*target
= nand
->target
;
193 struct arm_algorithm armv4_5_algo
;
194 struct armv7m_algorithm armv7m_algo
;
196 struct arm
*arm
= target
->arch_info
;
197 struct reg_param reg_params
[3];
199 uint32_t exit_var
= 0;
204 * r1 NAND data address (byte wide)
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 */
213 /* exit: ARMv4 needs hardware breakpoint */
214 0xe1200070, /* e: bkpt #0 */
219 * r1 NAND data address (byte wide)
222 * see contrib/loaders/flash/armv7m_io.s for src
224 static const uint32_t code_armv7m
[] = {
231 int target_code_size
= 0;
232 const uint32_t *target_code_src
= NULL
;
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
;
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
;
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
)
258 nand
->op
= ARM_NAND_READ
;
259 target_buf
= nand
->copy_area
->address
+ target_code_size
;
261 /* set up parameters */
262 init_reg_param(®_params
[0], "r0", 32, PARAM_IN
);
263 init_reg_param(®_params
[1], "r1", 32, PARAM_IN
);
264 init_reg_param(®_params
[2], "r2", 32, PARAM_IN
);
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
);
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;
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");
280 destroy_reg_param(®_params
[0]);
281 destroy_reg_param(®_params
[1]);
282 destroy_reg_param(®_params
[2]);
284 /* read from work area to the host's memory */
285 retval
= target_read_buffer(target
, target_buf
, size
, data
);
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)