220ea94f92405dc0671b1b84c2f7643397341591
[fw/openocd] / src / target / mips32_dmaacc.c
1 /***************************************************************************
2  *   Copyright (C) 2008 by John McCarthy                                   *
3  *   jgmcc@magma.ca                                                        *
4  *                                                                         *
5  *   Copyright (C) 2008 by Spencer Oliver                                  *
6  *   spen@spen-soft.co.uk                                                  *
7  *                                                                         *
8  *   Copyright (C) 2008 by David T.L. Wong                                 *
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version.                                   *
14  *                                                                         *
15  *   This program is distributed in the hope that it will be useful,       *
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
18  *   GNU General Public License for more details.                          *
19  *                                                                         *
20  *   You should have received a copy of the GNU General Public License     *
21  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
22  ***************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "mips32_dmaacc.h"
29 #include <helper/time_support.h>
30
31 static int mips32_dmaacc_read_mem8(struct mips_ejtag *ejtag_info,
32                 uint32_t addr, int count, uint8_t *buf);
33 static int mips32_dmaacc_read_mem16(struct mips_ejtag *ejtag_info,
34                 uint32_t addr, int count, uint16_t *buf);
35 static int mips32_dmaacc_read_mem32(struct mips_ejtag *ejtag_info,
36                 uint32_t addr, int count, uint32_t *buf);
37
38 static int mips32_dmaacc_write_mem8(struct mips_ejtag *ejtag_info,
39                 uint32_t addr, int count, const uint8_t *buf);
40 static int mips32_dmaacc_write_mem16(struct mips_ejtag *ejtag_info,
41                 uint32_t addr, int count, const uint16_t *buf);
42 static int mips32_dmaacc_write_mem32(struct mips_ejtag *ejtag_info,
43                 uint32_t addr, int count, const uint32_t *buf);
44
45 /*
46  * The following logic shamelessly cloned from HairyDairyMaid's wrt54g_debrick
47  * to support the Broadcom BCM5352 SoC in the Linksys WRT54GL wireless router
48  * (and any others that support EJTAG DMA transfers).
49  * Note: This only supports memory read/write. Since the BCM5352 doesn't
50  * appear to support PRACC accesses, all debug functions except halt
51  * do not work.  Still, this does allow erasing/writing flash as well as
52  * displaying/modifying memory and memory mapped registers.
53  */
54
55 static int ejtag_dma_dstrt_poll(struct mips_ejtag *ejtag_info)
56 {
57         uint32_t ejtag_ctrl;
58         int64_t start = timeval_ms();
59
60         do {
61                 if (timeval_ms() - start > 1000) {
62                         LOG_ERROR("DMA time out");
63                         return -ETIMEDOUT;
64                 }
65                 ejtag_ctrl = EJTAG_CTRL_DMAACC | ejtag_info->ejtag_ctrl;
66                 mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
67         } while (ejtag_ctrl & EJTAG_CTRL_DSTRT);
68         return 0;
69 }
70
71 static int ejtag_dma_read(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *data)
72 {
73         uint32_t v;
74         uint32_t ejtag_ctrl;
75         int retries = RETRY_ATTEMPTS;
76
77 begin_ejtag_dma_read:
78
79         /* Setup Address */
80         v = addr;
81         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
82         mips_ejtag_drscan_32(ejtag_info, &v);
83
84         /* Initiate DMA Read & set DSTRT */
85         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
86         ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DRWN | EJTAG_CTRL_DMA_WORD | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl;
87         mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
88
89         /* Wait for DSTRT to Clear */
90         ejtag_dma_dstrt_poll(ejtag_info);
91
92         /* Read Data */
93         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
94         mips_ejtag_drscan_32(ejtag_info, data);
95
96         /* Clear DMA & Check DERR */
97         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
98         ejtag_ctrl = ejtag_info->ejtag_ctrl;
99         mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
100         if (ejtag_ctrl  & EJTAG_CTRL_DERR) {
101                 if (retries--) {
102                         LOG_ERROR("DMA Read Addr = %08" PRIx32 "  Data = ERROR ON READ (retrying)", addr);
103                         goto begin_ejtag_dma_read;
104                 } else
105                         LOG_ERROR("DMA Read Addr = %08" PRIx32 "  Data = ERROR ON READ", addr);
106                 return ERROR_JTAG_DEVICE_ERROR;
107         }
108
109         return ERROR_OK;
110 }
111
112 static int ejtag_dma_read_h(struct mips_ejtag *ejtag_info, uint32_t addr, uint16_t *data)
113 {
114         uint32_t v;
115         uint32_t ejtag_ctrl;
116         int retries = RETRY_ATTEMPTS;
117
118 begin_ejtag_dma_read_h:
119
120         /* Setup Address */
121         v = addr;
122         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
123         mips_ejtag_drscan_32(ejtag_info, &v);
124
125         /* Initiate DMA Read & set DSTRT */
126         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
127         ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DRWN | EJTAG_CTRL_DMA_HALFWORD |
128                         EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl;
129         mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
130
131         /* Wait for DSTRT to Clear */
132         ejtag_dma_dstrt_poll(ejtag_info);
133
134         /* Read Data */
135         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
136         mips_ejtag_drscan_32(ejtag_info, &v);
137
138         /* Clear DMA & Check DERR */
139         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
140         ejtag_ctrl = ejtag_info->ejtag_ctrl;
141         mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
142         if (ejtag_ctrl  & EJTAG_CTRL_DERR) {
143                 if (retries--) {
144                         LOG_ERROR("DMA Read Addr = %08" PRIx32 "  Data = ERROR ON READ (retrying)", addr);
145                         goto begin_ejtag_dma_read_h;
146                 } else
147                         LOG_ERROR("DMA Read Addr = %08" PRIx32 "  Data = ERROR ON READ", addr);
148                 return ERROR_JTAG_DEVICE_ERROR;
149         }
150
151         /* Handle the bigendian/littleendian */
152         if (addr & 0x2)
153                 *data = (v >> 16) & 0xffff;
154         else
155                 *data = (v & 0x0000ffff);
156
157         return ERROR_OK;
158 }
159
160 static int ejtag_dma_read_b(struct mips_ejtag *ejtag_info, uint32_t addr, uint8_t *data)
161 {
162         uint32_t v;
163         uint32_t ejtag_ctrl;
164         int retries = RETRY_ATTEMPTS;
165
166 begin_ejtag_dma_read_b:
167
168         /* Setup Address */
169         v = addr;
170         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
171         mips_ejtag_drscan_32(ejtag_info, &v);
172
173         /* Initiate DMA Read & set DSTRT */
174         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
175         ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DRWN | EJTAG_CTRL_DMA_BYTE | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl;
176         mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
177
178         /* Wait for DSTRT to Clear */
179         ejtag_dma_dstrt_poll(ejtag_info);
180
181         /* Read Data */
182         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
183         mips_ejtag_drscan_32(ejtag_info, &v);
184
185         /* Clear DMA & Check DERR */
186         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
187         ejtag_ctrl = ejtag_info->ejtag_ctrl;
188         mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
189         if (ejtag_ctrl  & EJTAG_CTRL_DERR) {
190                 if (retries--) {
191                         LOG_ERROR("DMA Read Addr = %08" PRIx32 "  Data = ERROR ON READ (retrying)", addr);
192                         goto begin_ejtag_dma_read_b;
193                 } else
194                         LOG_ERROR("DMA Read Addr = %08" PRIx32 "  Data = ERROR ON READ", addr);
195                 return ERROR_JTAG_DEVICE_ERROR;
196         }
197
198         /* Handle the bigendian/littleendian */
199         switch (addr & 0x3) {
200                 case 0:
201                         *data = v & 0xff;
202                         break;
203                 case 1:
204                         *data = (v >> 8) & 0xff;
205                         break;
206                 case 2:
207                         *data = (v >> 16) & 0xff;
208                         break;
209                 case 3:
210                         *data = (v >> 24) & 0xff;
211                         break;
212         }
213
214         return ERROR_OK;
215 }
216
217 static int ejtag_dma_write(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t data)
218 {
219         uint32_t v;
220         uint32_t ejtag_ctrl;
221         int retries = RETRY_ATTEMPTS;
222
223 begin_ejtag_dma_write:
224
225         /* Setup Address */
226         v = addr;
227         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
228         mips_ejtag_drscan_32(ejtag_info, &v);
229
230         /* Setup Data */
231         v = data;
232         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
233         mips_ejtag_drscan_32(ejtag_info, &v);
234
235         /* Initiate DMA Write & set DSTRT */
236         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
237         ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DMA_WORD | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl;
238         mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
239
240         /* Wait for DSTRT to Clear */
241         ejtag_dma_dstrt_poll(ejtag_info);
242
243         /* Clear DMA & Check DERR */
244         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
245         ejtag_ctrl = ejtag_info->ejtag_ctrl;
246         mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
247         if (ejtag_ctrl  & EJTAG_CTRL_DERR) {
248                 if (retries--) {
249                         LOG_ERROR("DMA Write Addr = %08" PRIx32 "  Data = ERROR ON WRITE (retrying)", addr);
250                         goto begin_ejtag_dma_write;
251                 } else
252                         LOG_ERROR("DMA Write Addr = %08" PRIx32 "  Data = ERROR ON WRITE", addr);
253                 return ERROR_JTAG_DEVICE_ERROR;
254         }
255
256         return ERROR_OK;
257 }
258
259 static int ejtag_dma_write_h(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t data)
260 {
261         uint32_t v;
262         uint32_t ejtag_ctrl;
263         int retries = RETRY_ATTEMPTS;
264
265         /* Handle the bigendian/littleendian */
266         data &= 0xffff;
267         data |= data << 16;
268
269 begin_ejtag_dma_write_h:
270
271         /* Setup Address */
272         v = addr;
273         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
274         mips_ejtag_drscan_32(ejtag_info, &v);
275
276         /* Setup Data */
277         v = data;
278         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
279         mips_ejtag_drscan_32(ejtag_info, &v);
280
281         /* Initiate DMA Write & set DSTRT */
282         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
283         ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DMA_HALFWORD | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl;
284         mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
285
286         /* Wait for DSTRT to Clear */
287         ejtag_dma_dstrt_poll(ejtag_info);
288
289         /* Clear DMA & Check DERR */
290         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
291         ejtag_ctrl = ejtag_info->ejtag_ctrl;
292         mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
293         if (ejtag_ctrl & EJTAG_CTRL_DERR) {
294                 if (retries--) {
295                         LOG_ERROR("DMA Write Addr = %08" PRIx32 "  Data = ERROR ON WRITE (retrying)", addr);
296                         goto begin_ejtag_dma_write_h;
297                 } else
298                         LOG_ERROR("DMA Write Addr = %08" PRIx32 "  Data = ERROR ON WRITE", addr);
299                 return ERROR_JTAG_DEVICE_ERROR;
300         }
301
302         return ERROR_OK;
303 }
304
305 static int ejtag_dma_write_b(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t data)
306 {
307         uint32_t v;
308         uint32_t ejtag_ctrl;
309         int retries = RETRY_ATTEMPTS;
310
311         /* Handle the bigendian/littleendian */
312         data &= 0xff;
313         data |= data << 8;
314         data |= data << 16;
315
316 begin_ejtag_dma_write_b:
317
318         /*  Setup Address*/
319         v = addr;
320         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
321         mips_ejtag_drscan_32(ejtag_info, &v);
322
323         /* Setup Data */
324         v = data;
325         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
326         mips_ejtag_drscan_32(ejtag_info, &v);
327
328         /* Initiate DMA Write & set DSTRT */
329         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
330         ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DMA_BYTE | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl;
331         mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
332
333         /* Wait for DSTRT to Clear */
334         ejtag_dma_dstrt_poll(ejtag_info);
335
336         /* Clear DMA & Check DERR */
337         mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
338         ejtag_ctrl = ejtag_info->ejtag_ctrl;
339         mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
340         if (ejtag_ctrl & EJTAG_CTRL_DERR) {
341                 if (retries--) {
342                         LOG_ERROR("DMA Write Addr = %08" PRIx32 "  Data = ERROR ON WRITE (retrying)", addr);
343                         goto begin_ejtag_dma_write_b;
344                 } else
345                         LOG_ERROR("DMA Write Addr = %08" PRIx32 "  Data = ERROR ON WRITE", addr);
346                 return ERROR_JTAG_DEVICE_ERROR;
347         }
348
349         return ERROR_OK;
350 }
351
352 int mips32_dmaacc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf)
353 {
354         switch (size) {
355                 case 1:
356                         return mips32_dmaacc_read_mem8(ejtag_info, addr, count, (uint8_t *)buf);
357                 case 2:
358                         return mips32_dmaacc_read_mem16(ejtag_info, addr, count, (uint16_t *)buf);
359                 case 4:
360                         return mips32_dmaacc_read_mem32(ejtag_info, addr, count, (uint32_t *)buf);
361         }
362
363         return ERROR_OK;
364 }
365
366 static int mips32_dmaacc_read_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint32_t *buf)
367 {
368         int i;
369         int     retval;
370
371         for (i = 0; i < count; i++) {
372                 retval = ejtag_dma_read(ejtag_info, addr + i * sizeof(*buf), &buf[i]);
373                 if (retval != ERROR_OK)
374                         return retval;
375         }
376
377         return ERROR_OK;
378 }
379
380 static int mips32_dmaacc_read_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint16_t *buf)
381 {
382         int i;
383         int retval;
384
385         for (i = 0; i < count; i++) {
386                 retval = ejtag_dma_read_h(ejtag_info, addr + i * sizeof(*buf), &buf[i]);
387                 if (retval != ERROR_OK)
388                         return retval;
389         }
390
391         return ERROR_OK;
392 }
393
394 static int mips32_dmaacc_read_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint8_t *buf)
395 {
396         int i;
397         int retval;
398
399         for (i = 0; i < count; i++) {
400                 retval = ejtag_dma_read_b(ejtag_info, addr + i * sizeof(*buf), &buf[i]);
401                 if (retval != ERROR_OK)
402                         return retval;
403         }
404
405         return ERROR_OK;
406 }
407
408 int mips32_dmaacc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, const void *buf)
409 {
410         switch (size) {
411                 case 1:
412                         return mips32_dmaacc_write_mem8(ejtag_info, addr, count, buf);
413                 case 2:
414                         return mips32_dmaacc_write_mem16(ejtag_info, addr, count, buf);
415                 case 4:
416                         return mips32_dmaacc_write_mem32(ejtag_info, addr, count, buf);
417         }
418
419         return ERROR_OK;
420 }
421
422 static int mips32_dmaacc_write_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, const uint32_t *buf)
423 {
424         int i;
425         int retval;
426
427         for (i = 0; i < count; i++) {
428                 retval = ejtag_dma_write(ejtag_info, addr + i * sizeof(*buf), buf[i]);
429                 if (retval != ERROR_OK)
430                         return retval;
431         }
432
433         return ERROR_OK;
434 }
435
436 static int mips32_dmaacc_write_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, const uint16_t *buf)
437 {
438         int i;
439         int retval;
440
441         for (i = 0; i < count; i++) {
442                 retval = ejtag_dma_write_h(ejtag_info, addr + i * sizeof(*buf), buf[i]);
443                 if (retval != ERROR_OK)
444                         return retval;
445         }
446
447         return ERROR_OK;
448 }
449
450 static int mips32_dmaacc_write_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, const uint8_t *buf)
451 {
452         int i;
453         int retval;
454
455         for (i = 0; i < count; i++) {
456                 retval = ejtag_dma_write_b(ejtag_info, addr + i * sizeof(*buf), buf[i]);
457                 if (retval != ERROR_OK)
458                         return retval;
459         }
460
461         return ERROR_OK;
462 }