Merge branch 'master' of ../work into next
[platform/kernel/u-boot.git] / cpu / ppc4xx / bedbug_405.c
1 /*
2  * Bedbug Functions specific to the PPC405 chip
3  */
4
5 #include <common.h>
6 #include <command.h>
7 #include <linux/ctype.h>
8 #include <bedbug/type.h>
9 #include <bedbug/bedbug.h>
10 #include <bedbug/regs.h>
11 #include <bedbug/ppc.h>
12
13 #if defined(CONFIG_CMD_BEDBUG) && defined(CONFIG_4xx)
14
15 #define MAX_BREAK_POINTS 4
16
17 extern CPU_DEBUG_CTX bug_ctx;
18
19 void bedbug405_init __P ((void));
20 void bedbug405_do_break __P ((cmd_tbl_t *, int, int, char *[]));
21 void bedbug405_break_isr __P ((struct pt_regs *));
22 int bedbug405_find_empty __P ((void));
23 int bedbug405_set __P ((int, unsigned long));
24 int bedbug405_clear __P ((int));
25 \f
26
27 /* ======================================================================
28  * Initialize the global bug_ctx structure for the AMCC PPC405. Clear all
29  * of the breakpoints.
30  * ====================================================================== */
31
32 void bedbug405_init (void)
33 {
34         int i;
35
36         /* -------------------------------------------------- */
37
38         bug_ctx.hw_debug_enabled = 0;
39         bug_ctx.stopped = 0;
40         bug_ctx.current_bp = 0;
41         bug_ctx.regs = NULL;
42
43         bug_ctx.do_break = bedbug405_do_break;
44         bug_ctx.break_isr = bedbug405_break_isr;
45         bug_ctx.find_empty = bedbug405_find_empty;
46         bug_ctx.set = bedbug405_set;
47         bug_ctx.clear = bedbug405_clear;
48
49         for (i = 1; i <= MAX_BREAK_POINTS; ++i)
50                 (*bug_ctx.clear) (i);
51
52         puts ("BEDBUG:ready\n");
53         return;
54 }       /* bedbug_init_breakpoints */
55 \f
56
57
58 /* ======================================================================
59  * Set/clear/show one of the hardware breakpoints for the 405.  The "off"
60  * string will disable a specific breakpoint.  The "show" string will
61  * display the current breakpoints.  Otherwise an address will set a
62  * breakpoint at that address.  Setting a breakpoint uses the CPU-specific
63  * set routine which will assign a breakpoint number.
64  * ====================================================================== */
65
66 void bedbug405_do_break (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
67 {
68         long addr = 0;          /* Address to break at  */
69         int which_bp;           /* Breakpoint number    */
70
71         /* -------------------------------------------------- */
72
73         if (argc < 2) {
74                 cmd_usage(cmdtp);
75                 return;
76         }
77
78         /* Turn off a breakpoint */
79
80         if (strcmp (argv[1], "off") == 0) {
81                 if (bug_ctx.hw_debug_enabled == 0) {
82                         printf ("No breakpoints enabled\n");
83                         return;
84                 }
85
86                 which_bp = simple_strtoul (argv[2], NULL, 10);
87
88                 if (bug_ctx.clear)
89                         (*bug_ctx.clear) (which_bp);
90
91                 printf ("Breakpoint %d removed\n", which_bp);
92                 return;
93         }
94
95         /* Show a list of breakpoints */
96
97         if (strcmp (argv[1], "show") == 0) {
98                 for (which_bp = 1; which_bp <= MAX_BREAK_POINTS; ++which_bp) {
99
100                         switch (which_bp) {
101                         case 1:
102                                 addr = GET_IAC1 ();
103                                 break;
104                         case 2:
105                                 addr = GET_IAC2 ();
106                                 break;
107                         case 3:
108                                 addr = GET_IAC3 ();
109                                 break;
110                         case 4:
111                                 addr = GET_IAC4 ();
112                                 break;
113                         }
114
115                         printf ("Breakpoint [%d]: ", which_bp);
116                         if (addr == 0)
117                                 printf ("NOT SET\n");
118                         else
119                                 disppc ((unsigned char *) addr, 0, 1, bedbug_puts,
120                                                 F_RADHEX);
121                 }
122                 return;
123         }
124
125         /* Set a breakpoint at the address */
126
127         if (!isdigit (argv[1][0])) {
128                 cmd_usage(cmdtp);
129                 return;
130         }
131
132         addr = simple_strtoul (argv[1], NULL, 16) & 0xfffffffc;
133
134         if ((bug_ctx.set) && (which_bp = (*bug_ctx.set) (0, addr)) > 0) {
135                 printf ("Breakpoint [%d]: ", which_bp);
136                 disppc ((unsigned char *) addr, 0, 1, bedbug_puts, F_RADHEX);
137         }
138
139         return;
140 }       /* bedbug405_do_break */
141 \f
142
143
144 /* ======================================================================
145  * Handle a breakpoint.  First determine which breakpoint was hit by
146  * looking at the DeBug Status Register (DBSR), clear the breakpoint
147  * and enter a mini main loop.  Stay in the loop until the stopped flag
148  * in the debug context is cleared.
149  * ====================================================================== */
150
151 void bedbug405_break_isr (struct pt_regs *regs)
152 {
153         unsigned long dbsr_val;         /* Value of the DBSR    */
154         unsigned long addr = 0;         /* Address stopped at   */
155
156         /* -------------------------------------------------- */
157
158         dbsr_val = GET_DBSR ();
159
160         if (dbsr_val & DBSR_IA1) {
161                 bug_ctx.current_bp = 1;
162                 addr = GET_IAC1 ();
163                 SET_DBSR (DBSR_IA1);    /* Write a 1 to clear */
164         } else if (dbsr_val & DBSR_IA2) {
165                 bug_ctx.current_bp = 2;
166                 addr = GET_IAC2 ();
167                 SET_DBSR (DBSR_IA2);    /* Write a 1 to clear */
168         } else if (dbsr_val & DBSR_IA3) {
169                 bug_ctx.current_bp = 3;
170                 addr = GET_IAC3 ();
171                 SET_DBSR (DBSR_IA3);    /* Write a 1 to clear */
172         } else if (dbsr_val & DBSR_IA4) {
173                 bug_ctx.current_bp = 4;
174                 addr = GET_IAC4 ();
175                 SET_DBSR (DBSR_IA4);    /* Write a 1 to clear */
176         }
177
178         bedbug_main_loop (addr, regs);
179         return;
180 }       /* bedbug405_break_isr */
181 \f
182
183
184 /* ======================================================================
185  * Look through all of the hardware breakpoints available to see if one
186  * is unused.
187  * ====================================================================== */
188
189 int bedbug405_find_empty (void)
190 {
191         /* -------------------------------------------------- */
192
193         if (GET_IAC1 () == 0)
194                 return 1;
195
196         if (GET_IAC2 () == 0)
197                 return 2;
198
199         if (GET_IAC3 () == 0)
200                 return 3;
201
202         if (GET_IAC4 () == 0)
203                 return 4;
204
205         return 0;
206 }       /* bedbug405_find_empty */
207 \f
208
209
210 /* ======================================================================
211  * Set a breakpoint.  If 'which_bp' is zero then find an unused breakpoint
212  * number, otherwise reassign the given breakpoint.  If hardware debugging
213  * is not enabled, then turn it on via the MSR and DBCR0.  Set the break
214  * address in the appropriate IACx register and enable proper address
215  * beakpoint in DBCR0.
216  * ====================================================================== */
217
218 int bedbug405_set (int which_bp, unsigned long addr)
219 {
220         /* -------------------------------------------------- */
221
222         /* Only look if which_bp == 0, else use which_bp */
223         if ((bug_ctx.find_empty) && (!which_bp) &&
224                 (which_bp = (*bug_ctx.find_empty) ()) == 0) {
225                 printf ("All breakpoints in use\n");
226                 return 0;
227         }
228
229         if (which_bp < 1 || which_bp > MAX_BREAK_POINTS) {
230                 printf ("Invalid break point # %d\n", which_bp);
231                 return 0;
232         }
233
234         if (!bug_ctx.hw_debug_enabled) {
235                 SET_MSR (GET_MSR () | 0x200);   /* set MSR[ DE ] */
236                 SET_DBCR0 (GET_DBCR0 () | DBCR0_IDM);
237                 bug_ctx.hw_debug_enabled = 1;
238         }
239
240         switch (which_bp) {
241         case 1:
242                 SET_IAC1 (addr);
243                 SET_DBCR0 (GET_DBCR0 () | DBCR0_IA1);
244                 break;
245
246         case 2:
247                 SET_IAC2 (addr);
248                 SET_DBCR0 (GET_DBCR0 () | DBCR0_IA2);
249                 break;
250
251         case 3:
252                 SET_IAC3 (addr);
253                 SET_DBCR0 (GET_DBCR0 () | DBCR0_IA3);
254                 break;
255
256         case 4:
257                 SET_IAC4 (addr);
258                 SET_DBCR0 (GET_DBCR0 () | DBCR0_IA4);
259                 break;
260         }
261
262         return which_bp;
263 }       /* bedbug405_set */
264 \f
265
266
267 /* ======================================================================
268  * Disable a specific breakoint by setting the appropriate IACx register
269  * to zero and claring the instruction address breakpoint in DBCR0.
270  * ====================================================================== */
271
272 int bedbug405_clear (int which_bp)
273 {
274         /* -------------------------------------------------- */
275
276         if (which_bp < 1 || which_bp > MAX_BREAK_POINTS) {
277                 printf ("Invalid break point # (%d)\n", which_bp);
278                 return -1;
279         }
280
281         switch (which_bp) {
282         case 1:
283                 SET_IAC1 (0);
284                 SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA1);
285                 break;
286
287         case 2:
288                 SET_IAC2 (0);
289                 SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA2);
290                 break;
291
292         case 3:
293                 SET_IAC3 (0);
294                 SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA3);
295                 break;
296
297         case 4:
298                 SET_IAC4 (0);
299                 SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA4);
300                 break;
301         }
302
303         return 0;
304 }       /* bedbug405_clear */
305
306
307 /* ====================================================================== */
308 #endif