OpenOCD
arm_io.c
Go to the documentation of this file.
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 
34  const uint32_t *code, unsigned int code_size,
35  unsigned int additional, struct working_area **area)
36 {
37  uint8_t code_buf[code_size];
38  int retval;
39  unsigned int 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  return target_write_memory(target, (*area)->address,
60  4, code_size / 4, code_buf);
61 }
62 
78 int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
79 {
80  struct target *target = nand->target;
81  struct arm_algorithm armv4_5_algo;
82  struct armv7m_algorithm armv7m_algo;
83  void *arm_algo;
84  struct arm *arm = target->arch_info;
85  struct reg_param reg_params[3];
86  uint32_t target_buf;
87  uint32_t exit_var = 0;
88  int retval;
89 
90  /* Inputs:
91  * r0 NAND data address (byte wide)
92  * r1 buffer address
93  * r2 buffer length
94  */
95  static const uint32_t code_armv4_5[] = {
96  0xe4d13001, /* s: ldrb r3, [r1], #1 */
97  0xe5c03000, /* strb r3, [r0] */
98  0xe2522001, /* subs r2, r2, #1 */
99  0x1afffffb, /* bne s */
100 
101  /* exit: ARMv4 needs hardware breakpoint */
102  0xe1200070, /* e: bkpt #0 */
103  };
104 
105  /* Inputs:
106  * r0 NAND data address (byte wide)
107  * r1 buffer address
108  * r2 buffer length
109  *
110  * see contrib/loaders/flash/armv7m_io.s for src
111  */
112  static const uint32_t code_armv7m[] = {
113  0x3b01f811,
114  0x3a017003,
115  0xaffaf47f,
116  0xbf00be00,
117  };
118 
119  int target_code_size = 0;
120  const uint32_t *target_code_src = NULL;
121 
122  /* set up algorithm */
123  if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */
124  armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
125  armv7m_algo.core_mode = ARM_MODE_THREAD;
126  arm_algo = &armv7m_algo;
127  target_code_size = sizeof(code_armv7m);
128  target_code_src = code_armv7m;
129  } else {
130  armv4_5_algo.common_magic = ARM_COMMON_MAGIC;
131  armv4_5_algo.core_mode = ARM_MODE_SVC;
132  armv4_5_algo.core_state = ARM_STATE_ARM;
133  arm_algo = &armv4_5_algo;
134  target_code_size = sizeof(code_armv4_5);
135  target_code_src = code_armv4_5;
136  }
137 
138  if (nand->op != ARM_NAND_WRITE || !nand->copy_area) {
139  retval = arm_code_to_working_area(target, target_code_src, target_code_size,
140  nand->chunk_size, &nand->copy_area);
141  if (retval != ERROR_OK)
142  return retval;
143  }
144 
145  nand->op = ARM_NAND_WRITE;
146 
147  /* copy data to work area */
148  target_buf = nand->copy_area->address + target_code_size;
149  retval = target_write_buffer(target, target_buf, size, data);
150  if (retval != ERROR_OK)
151  return retval;
152 
153  /* set up parameters */
154  init_reg_param(&reg_params[0], "r0", 32, PARAM_IN);
155  init_reg_param(&reg_params[1], "r1", 32, PARAM_IN);
156  init_reg_param(&reg_params[2], "r2", 32, PARAM_IN);
157 
158  buf_set_u32(reg_params[0].value, 0, 32, nand->data);
159  buf_set_u32(reg_params[1].value, 0, 32, target_buf);
160  buf_set_u32(reg_params[2].value, 0, 32, size);
161 
162  /* armv4 must exit using a hardware breakpoint */
163  if (arm->arch == ARM_ARCH_V4)
164  exit_var = nand->copy_area->address + target_code_size - 4;
165 
166  /* use alg to write data from work area to NAND chip */
167  retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
168  nand->copy_area->address, exit_var, 1000, arm_algo);
169  if (retval != ERROR_OK)
170  LOG_ERROR("error executing hosted NAND write");
171 
172  destroy_reg_param(&reg_params[0]);
173  destroy_reg_param(&reg_params[1]);
174  destroy_reg_param(&reg_params[2]);
175 
176  return retval;
177 }
178 
188 int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
189 {
190  struct target *target = nand->target;
191  struct arm_algorithm armv4_5_algo;
192  struct armv7m_algorithm armv7m_algo;
193  void *arm_algo;
194  struct arm *arm = target->arch_info;
195  struct reg_param reg_params[3];
196  uint32_t target_buf;
197  uint32_t exit_var = 0;
198  int retval;
199 
200  /* Inputs:
201  * r0 buffer address
202  * r1 NAND data address (byte wide)
203  * r2 buffer length
204  */
205  static const uint32_t code_armv4_5[] = {
206  0xe5d13000, /* s: ldrb r3, [r1] */
207  0xe4c03001, /* strb r3, [r0], #1 */
208  0xe2522001, /* subs r2, r2, #1 */
209  0x1afffffb, /* bne s */
210 
211  /* exit: ARMv4 needs hardware breakpoint */
212  0xe1200070, /* e: bkpt #0 */
213  };
214 
215  /* Inputs:
216  * r0 buffer address
217  * r1 NAND data address (byte wide)
218  * r2 buffer length
219  *
220  * see contrib/loaders/flash/armv7m_io.s for src
221  */
222  static const uint32_t code_armv7m[] = {
223  0xf800780b,
224  0x3a013b01,
225  0xaffaf47f,
226  0xbf00be00,
227  };
228 
229  int target_code_size = 0;
230  const uint32_t *target_code_src = NULL;
231 
232  /* set up algorithm */
233  if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */
234  armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
235  armv7m_algo.core_mode = ARM_MODE_THREAD;
236  arm_algo = &armv7m_algo;
237  target_code_size = sizeof(code_armv7m);
238  target_code_src = code_armv7m;
239  } else {
240  armv4_5_algo.common_magic = ARM_COMMON_MAGIC;
241  armv4_5_algo.core_mode = ARM_MODE_SVC;
242  armv4_5_algo.core_state = ARM_STATE_ARM;
243  arm_algo = &armv4_5_algo;
244  target_code_size = sizeof(code_armv4_5);
245  target_code_src = code_armv4_5;
246  }
247 
248  /* create the copy area if not yet available */
249  if (nand->op != ARM_NAND_READ || !nand->copy_area) {
250  retval = arm_code_to_working_area(target, target_code_src, target_code_size,
251  nand->chunk_size, &nand->copy_area);
252  if (retval != ERROR_OK)
253  return retval;
254  }
255 
256  nand->op = ARM_NAND_READ;
257  target_buf = nand->copy_area->address + target_code_size;
258 
259  /* set up parameters */
260  init_reg_param(&reg_params[0], "r0", 32, PARAM_IN);
261  init_reg_param(&reg_params[1], "r1", 32, PARAM_IN);
262  init_reg_param(&reg_params[2], "r2", 32, PARAM_IN);
263 
264  buf_set_u32(reg_params[0].value, 0, 32, target_buf);
265  buf_set_u32(reg_params[1].value, 0, 32, nand->data);
266  buf_set_u32(reg_params[2].value, 0, 32, size);
267 
268  /* armv4 must exit using a hardware breakpoint */
269  if (arm->arch == ARM_ARCH_V4)
270  exit_var = nand->copy_area->address + target_code_size - 4;
271 
272  /* use alg to write data from NAND chip to work area */
273  retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
274  nand->copy_area->address, exit_var, 1000, arm_algo);
275  if (retval != ERROR_OK)
276  LOG_ERROR("error executing hosted NAND read");
277 
278  destroy_reg_param(&reg_params[0]);
279  destroy_reg_param(&reg_params[1]);
280  destroy_reg_param(&reg_params[2]);
281 
282  /* read from work area to the host's memory */
283  return target_read_buffer(target, target_buf, size, data);
284 }
void init_reg_param(struct reg_param *param, const char *reg_name, uint32_t size, enum param_direction direction)
Definition: algorithm.c:29
void destroy_reg_param(struct reg_param *param)
Definition: algorithm.c:38
@ PARAM_IN
Definition: algorithm.h:15
Holds the interface to ARM cores.
#define ARM_COMMON_MAGIC
Definition: arm.h:167
@ ARM_ARCH_V4
Definition: arm.h:55
@ ARM_MODE_SVC
Definition: arm.h:86
@ ARM_MODE_THREAD
Definition: arm.h:94
@ ARM_STATE_ARM
Definition: arm.h:152
int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
ARM-specific bulk write from buffer to address of 8-bit wide NAND.
Definition: arm_io.c:78
static int arm_code_to_working_area(struct target *target, const uint32_t *code, unsigned int code_size, unsigned int additional, struct working_area **area)
Copies code to a working area.
Definition: arm_io.c:33
int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
Uses an on-chip algorithm for an ARM device to read from a NAND device and store the data into the ho...
Definition: arm_io.c:188
@ ARM_NAND_READ
Read operation performed.
Definition: arm_io.h:14
@ ARM_NAND_WRITE
Write operation performed.
Definition: arm_io.h:15
static struct armv7m_common * target_to_armv7m(struct target *target)
Definition: armv7m.h:273
#define ARMV7M_COMMON_MAGIC
Definition: armv7m.h:229
static bool is_armv7m(const struct armv7m_common *armv7m)
Definition: armv7m.h:261
Support functions to access arbitrary bits in a byte array.
static void buf_set_u32(uint8_t *_buffer, unsigned int first, unsigned int num, uint32_t value)
Sets num bits in _buffer, starting at the first bit, using the bits in value.
Definition: binarybuffer.h:34
uint32_t size
Size of dw_spi_transaction::buffer.
Definition: dw-spi-helper.h:4
#define LOG_ERROR(expr ...)
Definition: log.h:147
#define LOG_DEBUG(expr ...)
Definition: log.h:124
#define ERROR_OK
Definition: log.h:182
#define ERROR_NAND_NO_BUFFER
Definition: nand/core.h:222
Upper level NOR flash interfaces.
unsigned int common_magic
Definition: arm.h:275
enum arm_mode core_mode
Definition: arm.h:277
enum arm_state core_state
Definition: arm.h:278
The arm_nand_data struct is used for defining NAND I/O operations on an ARM core.
Definition: arm_io.h:22
struct target * target
Target is proxy for some ARM core.
Definition: arm_io.h:24
struct working_area * copy_area
The copy area holds code loop and data for I/O operations.
Definition: arm_io.h:27
unsigned int chunk_size
The chunk size is the page size or ECC chunk.
Definition: arm_io.h:30
enum arm_nand_op op
Last operation executed using this struct.
Definition: arm_io.h:36
uint32_t data
Where data is read from or written to.
Definition: arm_io.h:33
Represents a generic ARM core, with standard application registers.
Definition: arm.h:176
enum arm_arch arch
ARM architecture version.
Definition: arm.h:203
unsigned int common_magic
Definition: armv7m.h:306
enum arm_mode core_mode
Definition: armv7m.h:308
uint8_t * value
Definition: algorithm.h:30
Definition: target.h:119
void * arch_info
Definition: target.h:174
target_addr_t address
Definition: target.h:89
int target_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer)
Definition: target.c:2369
int target_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer)
Definition: target.c:2434
int target_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, target_addr_t entry_point, target_addr_t exit_point, unsigned int timeout_ms, void *arch_info)
Downloads a target-specific native code algorithm to the target, and executes it.
Definition: target.c:786
int target_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer)
Write count items of size bytes to the memory of target at the address given.
Definition: target.c:1288
int target_alloc_working_area(struct target *target, uint32_t size, struct working_area **area)
Definition: target.c:2090
void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_t count, const uint32_t *srcbuf)
Definition: target.c:427
#define NULL
Definition: usb.h:16