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