Documentation: fix warning "unbalanced square brackets"
[openocd.git] / src / flash / nand / arm_io.c
blob80bd0cf25b02cebede806f63e7df6d118ee276d4
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /*
4 * Copyright (C) 2009 by Marvell Semiconductors, Inc.
5 * Written by Nicolas Pitre <nico at marvell.com>
7 * Copyright (C) 2009 by David Brownell
8 */
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
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>
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.
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
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];
38 int retval;
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 */
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;
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);
62 return retval;
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.
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;
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;
92 /* Inputs:
93 * r0 NAND data address (byte wide)
94 * r1 buffer address
95 * r2 buffer length
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 */
107 /* Inputs:
108 * r0 NAND data address (byte wide)
109 * r1 buffer address
110 * r2 buffer length
112 * see contrib/loaders/flash/armv7m_io.s for src
114 static const uint32_t code_armv7m[] = {
115 0x3b01f811,
116 0x3a017003,
117 0xaffaf47f,
118 0xbf00be00,
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;
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;
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;
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)
153 return retval;
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);
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(&reg_params[0]);
175 destroy_reg_param(&reg_params[1]);
176 destroy_reg_param(&reg_params[2]);
178 return retval;
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;
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;
202 /* Inputs:
203 * r0 buffer address
204 * r1 NAND data address (byte wide)
205 * r2 buffer length
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 */
217 /* Inputs:
218 * r0 buffer address
219 * r1 NAND data address (byte wide)
220 * r2 buffer length
222 * see contrib/loaders/flash/armv7m_io.s for src
224 static const uint32_t code_armv7m[] = {
225 0xf800780b,
226 0x3a013b01,
227 0xaffaf47f,
228 0xbf00be00,
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;
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;
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;
258 nand->op = ARM_NAND_READ;
259 target_buf = nand->copy_area->address + target_code_size;
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);
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(&reg_params[0]);
281 destroy_reg_param(&reg_params[1]);
282 destroy_reg_param(&reg_params[2]);
284 /* read from work area to the host's memory */
285 retval = target_read_buffer(target, target_buf, size, data);
287 return retval;