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