Commit 4a9cbbe832e1c377d04cfb53e9679844595bc3cf
1 parent
e887afc9da
Exists in
master
and in
54 other branches
Initial revision
Showing 17 changed files with 4551 additions and 0 deletions Side-by-side Diff
- common/cmd_fpga.c
- common/kgdb.c
- cpu/74xx_7xx/cpu_init.c
- cpu/74xx_7xx/speed.c
- cpu/mpc824x/cpu.c
- cpu/mpc824x/interrupts.c
- cpu/mpc8260/cpu.c
- cpu/mpc8260/interrupts.c
- cpu/mpc8260/serial_scc.c
- cpu/mpc8260/serial_smc.c
- cpu/mpc8260/speed.c
- cpu/mpc8xx/cpu_init.c
- cpu/mpc8xx/serial.c
- cpu/mpc8xx/speed.c
- cpu/mpc8xx/wlkbd.c
- cpu/ppc4xx/cpu_init.c
- cpu/sa1100/cpu.c
common/cmd_fpga.c
1 | +/* | |
2 | + * (C) Copyright 2000, 2001 | |
3 | + * Rich Ireland, Enterasys Networks, rireland@enterasys.com. | |
4 | + * | |
5 | + * See file CREDITS for list of people who contributed to this | |
6 | + * project. | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU General Public License as | |
10 | + * published by the Free Software Foundation; either version 2 of | |
11 | + * the License, or (at your option) any later version. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, write to the Free Software | |
20 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | + * MA 02111-1307 USA | |
22 | + * | |
23 | + */ | |
24 | + | |
25 | +/* | |
26 | + * FPGA support | |
27 | + */ | |
28 | +#include <common.h> | |
29 | +#include <command.h> | |
30 | +#include <cmd_fpga.h> | |
31 | +#include <fpga.h> | |
32 | +#if (CONFIG_COMMANDS & CFG_CMD_NET) | |
33 | +#include <net.h> | |
34 | +#endif | |
35 | + | |
36 | +#if 0 | |
37 | +#define FPGA_DEBUG | |
38 | +#endif | |
39 | + | |
40 | +#ifdef FPGA_DEBUG | |
41 | +#define PRINTF(fmt,args...) printf (fmt ,##args) | |
42 | +#else | |
43 | +#define PRINTF(fmt,args...) | |
44 | +#endif | |
45 | + | |
46 | +#if defined (CONFIG_FPGA) && ( CONFIG_COMMANDS & CFG_CMD_FPGA ) | |
47 | + | |
48 | +/* Local functions */ | |
49 | +static void fpga_usage ( cmd_tbl_t *cmdtp ); | |
50 | +static int fpga_get_op( char *opstr ); | |
51 | + | |
52 | +/* Local defines */ | |
53 | +#define FPGA_NONE -1 | |
54 | +#define FPGA_INFO 0 | |
55 | +#define FPGA_LOAD 1 | |
56 | +#define FPGA_DUMP 3 | |
57 | + | |
58 | +/* ------------------------------------------------------------------------- */ | |
59 | +/* command form: | |
60 | + * fpga <op> <device number> <data addr> <datasize> | |
61 | + * where op is 'load', 'dump', or 'info' | |
62 | + * If there is no device number field, the fpga environment variable is used. | |
63 | + * If there is no data addr field, the fpgadata environment variable is used. | |
64 | + * The info command requires no data address field. | |
65 | + */ | |
66 | +int | |
67 | +do_fpga (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) | |
68 | +{ | |
69 | + int op, dev = FPGA_INVALID_DEVICE; | |
70 | + size_t data_size = 0; | |
71 | + void *fpga_data = NULL; | |
72 | + char *devstr = getenv("fpga"); | |
73 | + char *datastr = getenv("fpgadata"); | |
74 | + | |
75 | + if ( devstr ) dev = (int)simple_strtoul( devstr, NULL, 16 ); | |
76 | + if ( datastr ) fpga_data = (void *)simple_strtoul( datastr, NULL, 16 ); | |
77 | + | |
78 | + switch ( argc ) | |
79 | + { | |
80 | + case 5: /* fpga <op> <dev> <data> <datasize> */ | |
81 | + data_size = simple_strtoul( argv[4], NULL, 16 ); | |
82 | + case 4: /* fpga <op> <dev> <data> */ | |
83 | + fpga_data = (void *)simple_strtoul( argv[3], NULL, 16 ); | |
84 | + PRINTF(__FUNCTION__": fpga_data = 0x%x\n", (uint)fpga_data ); | |
85 | + case 3: /* fpga <op> <dev | data addr> */ | |
86 | + dev = (int)simple_strtoul( argv[2], NULL, 16 ); | |
87 | + PRINTF(__FUNCTION__": device = %d\n", dev ); | |
88 | + /* FIXME - this is a really weak test */ | |
89 | + if (( argc == 3 ) && ( dev > fpga_count() )) { /* must be buffer ptr */ | |
90 | + PRINTF(__FUNCTION__": Assuming buffer pointer in arg 3\n"); | |
91 | + fpga_data = (void *)dev; | |
92 | + PRINTF(__FUNCTION__": fpga_data = 0x%x\n", (uint)fpga_data ); | |
93 | + dev = FPGA_INVALID_DEVICE; /* reset device num */ | |
94 | + } | |
95 | + case 2: /* fpga <op> */ | |
96 | + op = (int)fpga_get_op( argv[1] ); | |
97 | + break; | |
98 | + default: | |
99 | + PRINTF(__FUNCTION__": Too many or too few args (%d)\n", argc ); | |
100 | + op = FPGA_NONE; /* force usage display */ | |
101 | + break; | |
102 | + } | |
103 | + | |
104 | + switch ( op ) { | |
105 | + case FPGA_NONE: | |
106 | + fpga_usage( cmdtp ); | |
107 | + break; | |
108 | + | |
109 | + case FPGA_INFO: | |
110 | + fpga_info( dev ); | |
111 | + break; | |
112 | + | |
113 | + case FPGA_LOAD: | |
114 | + fpga_load( dev, fpga_data, data_size ); | |
115 | + break; | |
116 | + | |
117 | + case FPGA_DUMP: | |
118 | + fpga_dump( dev, fpga_data, data_size ); | |
119 | + break; | |
120 | + | |
121 | + default: | |
122 | + printf( "Unknown operation.\n" ); | |
123 | + fpga_usage( cmdtp ); | |
124 | + break; | |
125 | + } | |
126 | + return 0; | |
127 | +} | |
128 | + | |
129 | +static void fpga_usage ( cmd_tbl_t *cmdtp ) | |
130 | +{ | |
131 | + printf( "Usage:\n%s\n", cmdtp->usage ); | |
132 | +} | |
133 | + | |
134 | +/* | |
135 | + * Map op to supported operations. We don't use a table since we | |
136 | + * would just have to relocate it from flash anyway. | |
137 | + */ | |
138 | +static int fpga_get_op( char *opstr ) | |
139 | +{ | |
140 | + int op = FPGA_NONE; | |
141 | + | |
142 | + if (!strcmp ("info", opstr)) { | |
143 | + op = FPGA_INFO; | |
144 | + } | |
145 | + else if (!strcmp ("load", opstr)) { | |
146 | + op = FPGA_LOAD; | |
147 | + } | |
148 | + else if (!strcmp ("dump", opstr)) { | |
149 | + op = FPGA_DUMP; | |
150 | + } | |
151 | + | |
152 | + if ( op == FPGA_NONE ) { | |
153 | + printf ("Unknown fpga operation \"%s\"\n", opstr); | |
154 | + } | |
155 | + return op; | |
156 | +} | |
157 | + | |
158 | +#endif /* CONFIG_FPGA && CONFIG_COMMANDS & CFG_CMD_FPGA */ |
common/kgdb.c
1 | +/* taken from arch/ppc/kernel/ppc-stub.c */ | |
2 | + | |
3 | +/**************************************************************************** | |
4 | + | |
5 | + THIS SOFTWARE IS NOT COPYRIGHTED | |
6 | + | |
7 | + HP offers the following for use in the public domain. HP makes no | |
8 | + warranty with regard to the software or its performance and the | |
9 | + user accepts the software "AS IS" with all faults. | |
10 | + | |
11 | + HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD | |
12 | + TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
13 | + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
14 | + | |
15 | +****************************************************************************/ | |
16 | + | |
17 | +/**************************************************************************** | |
18 | + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ | |
19 | + * | |
20 | + * Module name: remcom.c $ | |
21 | + * Revision: 1.34 $ | |
22 | + * Date: 91/03/09 12:29:49 $ | |
23 | + * Contributor: Lake Stevens Instrument Division$ | |
24 | + * | |
25 | + * Description: low level support for gdb debugger. $ | |
26 | + * | |
27 | + * Considerations: only works on target hardware $ | |
28 | + * | |
29 | + * Written by: Glenn Engel $ | |
30 | + * ModuleState: Experimental $ | |
31 | + * | |
32 | + * NOTES: See Below $ | |
33 | + * | |
34 | + * Modified for SPARC by Stu Grossman, Cygnus Support. | |
35 | + * | |
36 | + * This code has been extensively tested on the Fujitsu SPARClite demo board. | |
37 | + * | |
38 | + * To enable debugger support, two things need to happen. One, a | |
39 | + * call to set_debug_traps() is necessary in order to allow any breakpoints | |
40 | + * or error conditions to be properly intercepted and reported to gdb. | |
41 | + * Two, a breakpoint needs to be generated to begin communication. This | |
42 | + * is most easily accomplished by a call to breakpoint(). Breakpoint() | |
43 | + * simulates a breakpoint by executing a trap #1. | |
44 | + * | |
45 | + ************* | |
46 | + * | |
47 | + * The following gdb commands are supported: | |
48 | + * | |
49 | + * command function Return value | |
50 | + * | |
51 | + * g return the value of the CPU registers hex data or ENN | |
52 | + * G set the value of the CPU registers OK or ENN | |
53 | + * qOffsets Get section offsets. Reply is Text=xxx;Data=yyy;Bss=zzz | |
54 | + * | |
55 | + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN | |
56 | + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN | |
57 | + * | |
58 | + * c Resume at current address SNN ( signal NN) | |
59 | + * cAA..AA Continue at address AA..AA SNN | |
60 | + * | |
61 | + * s Step one instruction SNN | |
62 | + * sAA..AA Step one instruction from AA..AA SNN | |
63 | + * | |
64 | + * k kill | |
65 | + * | |
66 | + * ? What was the last sigval ? SNN (signal NN) | |
67 | + * | |
68 | + * bBB..BB Set baud rate to BB..BB OK or BNN, then sets | |
69 | + * baud rate | |
70 | + * | |
71 | + * All commands and responses are sent with a packet which includes a | |
72 | + * checksum. A packet consists of | |
73 | + * | |
74 | + * $<packet info>#<checksum>. | |
75 | + * | |
76 | + * where | |
77 | + * <packet info> :: <characters representing the command or response> | |
78 | + * <checksum> :: <two hex digits computed as modulo 256 sum of <packetinfo>> | |
79 | + * | |
80 | + * When a packet is received, it is first acknowledged with either '+' or '-'. | |
81 | + * '+' indicates a successful transfer. '-' indicates a failed transfer. | |
82 | + * | |
83 | + * Example: | |
84 | + * | |
85 | + * Host: Reply: | |
86 | + * $m0,10#2a +$00010203040506070809101112131415#42 | |
87 | + * | |
88 | + ****************************************************************************/ | |
89 | + | |
90 | +#include <common.h> | |
91 | + | |
92 | +#include <kgdb.h> | |
93 | +#include <command.h> | |
94 | + | |
95 | +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) | |
96 | + | |
97 | +#undef KGDB_DEBUG | |
98 | + | |
99 | +/* | |
100 | + * BUFMAX defines the maximum number of characters in inbound/outbound buffers | |
101 | + */ | |
102 | +#define BUFMAX 1024 | |
103 | +static char remcomInBuffer[BUFMAX]; | |
104 | +static char remcomOutBuffer[BUFMAX]; | |
105 | +static char remcomRegBuffer[BUFMAX]; | |
106 | + | |
107 | +static int initialized = 0; | |
108 | +static int kgdb_active = 0, first_entry = 1; | |
109 | +static struct pt_regs entry_regs; | |
110 | +static u_int error_jmp_buf[BUFMAX/2]; | |
111 | +static int longjmp_on_fault = 0; | |
112 | +#ifdef KGDB_DEBUG | |
113 | +static int kdebug = 1; | |
114 | +#endif | |
115 | + | |
116 | +static const char hexchars[]="0123456789abcdef"; | |
117 | + | |
118 | +/* Convert ch from a hex digit to an int */ | |
119 | +static int | |
120 | +hex(unsigned char ch) | |
121 | +{ | |
122 | + if (ch >= 'a' && ch <= 'f') | |
123 | + return ch-'a'+10; | |
124 | + if (ch >= '0' && ch <= '9') | |
125 | + return ch-'0'; | |
126 | + if (ch >= 'A' && ch <= 'F') | |
127 | + return ch-'A'+10; | |
128 | + return -1; | |
129 | +} | |
130 | + | |
131 | +/* Convert the memory pointed to by mem into hex, placing result in buf. | |
132 | + * Return a pointer to the last char put in buf (null). | |
133 | + */ | |
134 | +static unsigned char * | |
135 | +mem2hex(char *mem, char *buf, int count) | |
136 | +{ | |
137 | + unsigned char ch; | |
138 | + | |
139 | + longjmp_on_fault = 1; | |
140 | + while (count-- > 0) { | |
141 | + ch = *mem++; | |
142 | + *buf++ = hexchars[ch >> 4]; | |
143 | + *buf++ = hexchars[ch & 0xf]; | |
144 | + } | |
145 | + *buf = 0; | |
146 | + longjmp_on_fault = 0; | |
147 | + return buf; | |
148 | +} | |
149 | + | |
150 | +/* convert the hex array pointed to by buf into binary to be placed in mem | |
151 | + * return a pointer to the character AFTER the last byte fetched from buf. | |
152 | +*/ | |
153 | +static char * | |
154 | +hex2mem(char *buf, char *mem, int count) | |
155 | +{ | |
156 | + int i, hexValue; | |
157 | + unsigned char ch; | |
158 | + char *mem_start = mem; | |
159 | + | |
160 | + longjmp_on_fault = 1; | |
161 | + for (i=0; i<count; i++) { | |
162 | + if ((hexValue = hex(*buf++)) < 0) | |
163 | + kgdb_error(KGDBERR_NOTHEXDIG); | |
164 | + ch = hexValue << 4; | |
165 | + if ((hexValue = hex(*buf++)) < 0) | |
166 | + kgdb_error(KGDBERR_NOTHEXDIG); | |
167 | + ch |= hexValue; | |
168 | + *mem++ = ch; | |
169 | + } | |
170 | + kgdb_flush_cache_range((void *)mem_start, (void *)(mem - 1)); | |
171 | + longjmp_on_fault = 0; | |
172 | + | |
173 | + return buf; | |
174 | +} | |
175 | + | |
176 | +/* | |
177 | + * While we find nice hex chars, build an int. | |
178 | + * Return number of chars processed. | |
179 | + */ | |
180 | +static int | |
181 | +hexToInt(char **ptr, int *intValue) | |
182 | +{ | |
183 | + int numChars = 0; | |
184 | + int hexValue; | |
185 | + | |
186 | + *intValue = 0; | |
187 | + | |
188 | + longjmp_on_fault = 1; | |
189 | + while (**ptr) { | |
190 | + hexValue = hex(**ptr); | |
191 | + if (hexValue < 0) | |
192 | + break; | |
193 | + | |
194 | + *intValue = (*intValue << 4) | hexValue; | |
195 | + numChars ++; | |
196 | + | |
197 | + (*ptr)++; | |
198 | + } | |
199 | + longjmp_on_fault = 0; | |
200 | + | |
201 | + return (numChars); | |
202 | +} | |
203 | + | |
204 | +/* scan for the sequence $<data>#<checksum> */ | |
205 | +static void | |
206 | +getpacket(char *buffer) | |
207 | +{ | |
208 | + unsigned char checksum; | |
209 | + unsigned char xmitcsum; | |
210 | + int i; | |
211 | + int count; | |
212 | + unsigned char ch; | |
213 | + | |
214 | + do { | |
215 | + /* wait around for the start character, ignore all other | |
216 | + * characters */ | |
217 | + while ((ch = (getDebugChar() & 0x7f)) != '$') { | |
218 | +#ifdef KGDB_DEBUG | |
219 | + if (kdebug) | |
220 | + putc(ch); | |
221 | +#endif | |
222 | + ; | |
223 | + } | |
224 | + | |
225 | + checksum = 0; | |
226 | + xmitcsum = -1; | |
227 | + | |
228 | + count = 0; | |
229 | + | |
230 | + /* now, read until a # or end of buffer is found */ | |
231 | + while (count < BUFMAX) { | |
232 | + ch = getDebugChar() & 0x7f; | |
233 | + if (ch == '#') | |
234 | + break; | |
235 | + checksum = checksum + ch; | |
236 | + buffer[count] = ch; | |
237 | + count = count + 1; | |
238 | + } | |
239 | + | |
240 | + if (count >= BUFMAX) | |
241 | + continue; | |
242 | + | |
243 | + buffer[count] = 0; | |
244 | + | |
245 | + if (ch == '#') { | |
246 | + xmitcsum = hex(getDebugChar() & 0x7f) << 4; | |
247 | + xmitcsum |= hex(getDebugChar() & 0x7f); | |
248 | + if (checksum != xmitcsum) | |
249 | + putDebugChar('-'); /* failed checksum */ | |
250 | + else { | |
251 | + putDebugChar('+'); /* successful transfer */ | |
252 | + /* if a sequence char is present, reply the ID */ | |
253 | + if (buffer[2] == ':') { | |
254 | + putDebugChar(buffer[0]); | |
255 | + putDebugChar(buffer[1]); | |
256 | + /* remove sequence chars from buffer */ | |
257 | + count = strlen(buffer); | |
258 | + for (i=3; i <= count; i++) | |
259 | + buffer[i-3] = buffer[i]; | |
260 | + } | |
261 | + } | |
262 | + } | |
263 | + } while (checksum != xmitcsum); | |
264 | +} | |
265 | + | |
266 | +/* send the packet in buffer. */ | |
267 | +static void | |
268 | +putpacket(unsigned char *buffer) | |
269 | +{ | |
270 | + unsigned char checksum; | |
271 | + int count; | |
272 | + unsigned char ch, recv; | |
273 | + | |
274 | + /* $<packet info>#<checksum>. */ | |
275 | + do { | |
276 | + putDebugChar('$'); | |
277 | + checksum = 0; | |
278 | + count = 0; | |
279 | + | |
280 | + while ((ch = buffer[count])) { | |
281 | + putDebugChar(ch); | |
282 | + checksum += ch; | |
283 | + count += 1; | |
284 | + } | |
285 | + | |
286 | + putDebugChar('#'); | |
287 | + putDebugChar(hexchars[checksum >> 4]); | |
288 | + putDebugChar(hexchars[checksum & 0xf]); | |
289 | + recv = getDebugChar(); | |
290 | + } while ((recv & 0x7f) != '+'); | |
291 | +} | |
292 | + | |
293 | +/* | |
294 | + * This function does all command processing for interfacing to gdb. | |
295 | + */ | |
296 | +static int | |
297 | +handle_exception (struct pt_regs *regs) | |
298 | +{ | |
299 | + int addr; | |
300 | + int length; | |
301 | + char *ptr; | |
302 | + kgdb_data kd; | |
303 | + int i; | |
304 | + | |
305 | + if (!initialized) { | |
306 | + printf("kgdb: exception before kgdb is initialized! huh?\n"); | |
307 | + return (0); | |
308 | + } | |
309 | + | |
310 | + /* probably should check which exception occured as well */ | |
311 | + if (longjmp_on_fault) { | |
312 | + longjmp_on_fault = 0; | |
313 | + kgdb_longjmp((long*)error_jmp_buf, KGDBERR_MEMFAULT); | |
314 | + panic("kgdb longjump failed!\n"); | |
315 | + } | |
316 | + | |
317 | + if (kgdb_active) { | |
318 | + printf("kgdb: unexpected exception from within kgdb\n"); | |
319 | + return (0); | |
320 | + } | |
321 | + kgdb_active = 1; | |
322 | + | |
323 | + kgdb_interruptible(0); | |
324 | + | |
325 | + printf("kgdb: handle_exception; trap [0x%x]\n", kgdb_trap(regs)); | |
326 | + | |
327 | + if (kgdb_setjmp((long*)error_jmp_buf) != 0) | |
328 | + panic("kgdb: error or fault in entry init!\n"); | |
329 | + | |
330 | + kgdb_enter(regs, &kd); | |
331 | + | |
332 | + if (first_entry) { | |
333 | + /* | |
334 | + * the first time we enter kgdb, we save the processor | |
335 | + * state so that we can return to the monitor if the | |
336 | + * remote end quits gdb (or at least, tells us to quit | |
337 | + * with the 'k' packet) | |
338 | + */ | |
339 | + entry_regs = *regs; | |
340 | + first_entry = 0; | |
341 | + } | |
342 | + | |
343 | + ptr = remcomOutBuffer; | |
344 | + | |
345 | + *ptr++ = 'T'; | |
346 | + | |
347 | + *ptr++ = hexchars[kd.sigval >> 4]; | |
348 | + *ptr++ = hexchars[kd.sigval & 0xf]; | |
349 | + | |
350 | + for (i = 0; i < kd.nregs; i++) { | |
351 | + kgdb_reg *rp = &kd.regs[i]; | |
352 | + | |
353 | + *ptr++ = hexchars[rp->num >> 4]; | |
354 | + *ptr++ = hexchars[rp->num & 0xf]; | |
355 | + *ptr++ = ':'; | |
356 | + ptr = mem2hex((char *)&rp->val, ptr, 4); | |
357 | + *ptr++ = ';'; | |
358 | + } | |
359 | + | |
360 | + *ptr = 0; | |
361 | + | |
362 | +#ifdef KGDB_DEBUG | |
363 | + if (kdebug) | |
364 | + printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer); | |
365 | +#endif | |
366 | + | |
367 | + putpacket(remcomOutBuffer); | |
368 | + | |
369 | + while (1) { | |
370 | + volatile int errnum; | |
371 | + | |
372 | + remcomOutBuffer[0] = 0; | |
373 | + | |
374 | + getpacket(remcomInBuffer); | |
375 | + ptr = &remcomInBuffer[1]; | |
376 | + | |
377 | +#ifdef KGDB_DEBUG | |
378 | + if (kdebug) | |
379 | + printf("kgdb: remcomInBuffer: %s\n", remcomInBuffer); | |
380 | +#endif | |
381 | + | |
382 | + errnum = kgdb_setjmp((long*)error_jmp_buf); | |
383 | + | |
384 | + if (errnum == 0) switch (remcomInBuffer[0]) { | |
385 | + | |
386 | + case '?': /* report most recent signal */ | |
387 | + remcomOutBuffer[0] = 'S'; | |
388 | + remcomOutBuffer[1] = hexchars[kd.sigval >> 4]; | |
389 | + remcomOutBuffer[2] = hexchars[kd.sigval & 0xf]; | |
390 | + remcomOutBuffer[3] = 0; | |
391 | + break; | |
392 | + | |
393 | +#ifdef KGDB_DEBUG | |
394 | + case 'd': | |
395 | + /* toggle debug flag */ | |
396 | + kdebug ^= 1; | |
397 | + break; | |
398 | +#endif | |
399 | + | |
400 | + case 'g': /* return the value of the CPU registers. */ | |
401 | + length = kgdb_getregs(regs, remcomRegBuffer, BUFMAX); | |
402 | + mem2hex(remcomRegBuffer, remcomOutBuffer, length); | |
403 | + break; | |
404 | + | |
405 | + case 'G': /* set the value of the CPU registers */ | |
406 | + length = strlen(ptr); | |
407 | + if ((length & 1) != 0) kgdb_error(KGDBERR_BADPARAMS); | |
408 | + hex2mem(ptr, remcomRegBuffer, length/2); | |
409 | + kgdb_putregs(regs, remcomRegBuffer, length/2); | |
410 | + strcpy(remcomOutBuffer,"OK"); | |
411 | + break; | |
412 | + | |
413 | + case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ | |
414 | + /* Try to read %x,%x. */ | |
415 | + | |
416 | + if (hexToInt(&ptr, &addr) | |
417 | + && *ptr++ == ',' | |
418 | + && hexToInt(&ptr, &length)) { | |
419 | + mem2hex((char *)addr, remcomOutBuffer, length); | |
420 | + } else { | |
421 | + kgdb_error(KGDBERR_BADPARAMS); | |
422 | + } | |
423 | + break; | |
424 | + | |
425 | + case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ | |
426 | + /* Try to read '%x,%x:'. */ | |
427 | + | |
428 | + if (hexToInt(&ptr, &addr) | |
429 | + && *ptr++ == ',' | |
430 | + && hexToInt(&ptr, &length) | |
431 | + && *ptr++ == ':') { | |
432 | + hex2mem(ptr, (char *)addr, length); | |
433 | + strcpy(remcomOutBuffer, "OK"); | |
434 | + } else { | |
435 | + kgdb_error(KGDBERR_BADPARAMS); | |
436 | + } | |
437 | + break; | |
438 | + | |
439 | + | |
440 | + case 'k': /* kill the program, actually return to monitor */ | |
441 | + kd.extype = KGDBEXIT_KILL; | |
442 | + *regs = entry_regs; | |
443 | + first_entry = 1; | |
444 | + goto doexit; | |
445 | + | |
446 | + case 'C': /* CSS continue with signal SS */ | |
447 | + *ptr = '\0'; /* ignore the signal number for now */ | |
448 | + /* fall through */ | |
449 | + | |
450 | + case 'c': /* cAA..AA Continue; address AA..AA optional */ | |
451 | + /* try to read optional parameter, pc unchanged if no parm */ | |
452 | + kd.extype = KGDBEXIT_CONTINUE; | |
453 | + | |
454 | + if (hexToInt(&ptr, &addr)) { | |
455 | + kd.exaddr = addr; | |
456 | + kd.extype |= KGDBEXIT_WITHADDR; | |
457 | + } | |
458 | + | |
459 | + goto doexit; | |
460 | + | |
461 | + case 'S': /* SSS single step with signal SS */ | |
462 | + *ptr = '\0'; /* ignore the signal number for now */ | |
463 | + /* fall through */ | |
464 | + | |
465 | + case 's': | |
466 | + kd.extype = KGDBEXIT_SINGLE; | |
467 | + | |
468 | + if (hexToInt(&ptr, &addr)) { | |
469 | + kd.exaddr = addr; | |
470 | + kd.extype |= KGDBEXIT_WITHADDR; | |
471 | + } | |
472 | + | |
473 | + doexit: | |
474 | +/* Need to flush the instruction cache here, as we may have deposited a | |
475 | + * breakpoint, and the icache probably has no way of knowing that a data ref to | |
476 | + * some location may have changed something that is in the instruction cache. | |
477 | + */ | |
478 | + kgdb_flush_cache_all(); | |
479 | + kgdb_exit(regs, &kd); | |
480 | + kgdb_active = 0; | |
481 | + kgdb_interruptible(1); | |
482 | + return (1); | |
483 | + | |
484 | + case 'r': /* Reset (if user process..exit ???)*/ | |
485 | + panic("kgdb reset."); | |
486 | + break; | |
487 | + | |
488 | + case 'P': /* Pr=v set reg r to value v (r and v are hex) */ | |
489 | + if (hexToInt(&ptr, &addr) | |
490 | + && *ptr++ == '=' | |
491 | + && ((length = strlen(ptr)) & 1) == 0) { | |
492 | + hex2mem(ptr, remcomRegBuffer, length/2); | |
493 | + kgdb_putreg(regs, addr, | |
494 | + remcomRegBuffer, length/2); | |
495 | + strcpy(remcomOutBuffer,"OK"); | |
496 | + } else { | |
497 | + kgdb_error(KGDBERR_BADPARAMS); | |
498 | + } | |
499 | + break; | |
500 | + } /* switch */ | |
501 | + | |
502 | + if (errnum != 0) | |
503 | + sprintf(remcomOutBuffer, "E%02d", errnum); | |
504 | + | |
505 | +#ifdef KGDB_DEBUG | |
506 | + if (kdebug) | |
507 | + printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer); | |
508 | +#endif | |
509 | + | |
510 | + /* reply to the request */ | |
511 | + putpacket(remcomOutBuffer); | |
512 | + | |
513 | + } /* while(1) */ | |
514 | +} | |
515 | + | |
516 | +/* | |
517 | + * kgdb_init must be called *after* the | |
518 | + * monitor is relocated into ram | |
519 | + */ | |
520 | +void | |
521 | +kgdb_init(void) | |
522 | +{ | |
523 | + kgdb_serial_init(); | |
524 | + debugger_exception_handler = handle_exception; | |
525 | + initialized = 1; | |
526 | + | |
527 | + putDebugStr("kgdb ready\n"); | |
528 | + puts("ready\n"); | |
529 | +} | |
530 | + | |
531 | +void | |
532 | +kgdb_error(int errnum) | |
533 | +{ | |
534 | + longjmp_on_fault = 0; | |
535 | + kgdb_longjmp((long*)error_jmp_buf, errnum); | |
536 | + panic("kgdb_error: longjmp failed!\n"); | |
537 | +} | |
538 | + | |
539 | +/* Output string in GDB O-packet format if GDB has connected. If nothing | |
540 | + output, returns 0 (caller must then handle output). */ | |
541 | +int | |
542 | +kgdb_output_string (const char* s, unsigned int count) | |
543 | +{ | |
544 | + char buffer[512]; | |
545 | + | |
546 | + count = (count <= (sizeof(buffer) / 2 - 2)) | |
547 | + ? count : (sizeof(buffer) / 2 - 2); | |
548 | + | |
549 | + buffer[0] = 'O'; | |
550 | + mem2hex ((char *)s, &buffer[1], count); | |
551 | + putpacket(buffer); | |
552 | + | |
553 | + return 1; | |
554 | +} | |
555 | + | |
556 | +void | |
557 | +breakpoint(void) | |
558 | +{ | |
559 | + if (!initialized) { | |
560 | + printf("breakpoint() called b4 kgdb init\n"); | |
561 | + return; | |
562 | + } | |
563 | + | |
564 | + kgdb_breakpoint(0, 0); | |
565 | +} | |
566 | + | |
567 | +int | |
568 | +do_kgdb(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) | |
569 | +{ | |
570 | + printf("Entering KGDB mode via exception handler...\n\n"); | |
571 | + kgdb_breakpoint(argc - 1, argv + 1); | |
572 | + printf("\nReturned from KGDB mode\n"); | |
573 | + return 0; | |
574 | +} | |
575 | + | |
576 | +#else | |
577 | + | |
578 | +int kgdb_not_configured = 1; | |
579 | + | |
580 | +#endif /* CFG_CMD_KGDB */ |
cpu/74xx_7xx/cpu_init.c
1 | +/* | |
2 | + * (C) Copyright 2001 | |
3 | + * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc. | |
4 | + * | |
5 | + * See file CREDITS for list of people who contributed to this | |
6 | + * project. | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU General Public License as | |
10 | + * published by the Free Software Foundation; either version 2 of | |
11 | + * the License, or (at your option) any later version. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, write to the Free Software | |
20 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | + * MA 02111-1307 USA | |
22 | + */ | |
23 | + | |
24 | +/* | |
25 | + * cpu_init.c - low level cpu init | |
26 | + * | |
27 | + * there's really nothing going on here yet. future work area? | |
28 | + */ | |
29 | + | |
30 | +#include <common.h> | |
31 | +#include <74xx_7xx.h> | |
32 | + | |
33 | +/* | |
34 | + * Breath some life into the CPU... | |
35 | + * | |
36 | + * there's basically nothing to do here since the memory controller | |
37 | + * isn't on the CPU in this case. | |
38 | + */ | |
39 | +void | |
40 | +cpu_init_f (void) | |
41 | +{ | |
42 | + if (get_cpu_type() == CPU_7450) { | |
43 | + /* enable the timebase bit in HID0 */ | |
44 | + set_hid0(get_hid0() | 0x4000000); | |
45 | + } | |
46 | +} | |
47 | + | |
48 | +/* | |
49 | + * initialize higher level parts of CPU like timers | |
50 | + */ | |
51 | +int cpu_init_r (void) | |
52 | +{ | |
53 | + return (0); | |
54 | +} |
cpu/74xx_7xx/speed.c
1 | +/* | |
2 | + * (C) Copyright 2000-2002 | |
3 | + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | + * | |
5 | + * See file CREDITS for list of people who contributed to this | |
6 | + * project. | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU General Public License as | |
10 | + * published by the Free Software Foundation; either version 2 of | |
11 | + * the License, or (at your option) any later version. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, write to the Free Software | |
20 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | + * MA 02111-1307 USA | |
22 | + */ | |
23 | + | |
24 | +#include <common.h> | |
25 | +#include <74xx_7xx.h> | |
26 | +#include <asm/processor.h> | |
27 | + | |
28 | +static const int hid1_multipliers_x_10[] = { | |
29 | + 25, /* 0000 - 2.5x */ | |
30 | + 75, /* 0001 - 7.5x */ | |
31 | + 70, /* 0010 - 7x */ | |
32 | + 10, /* 0011 - bypass */ | |
33 | + 20, /* 0100 - 2x */ | |
34 | + 65, /* 0101 - 6.5x */ | |
35 | + 100, /* 0110 - 10x */ | |
36 | + 45, /* 0111 - 4.5x */ | |
37 | + 30, /* 1000 - 3x */ | |
38 | + 55, /* 1001 - 5.5x */ | |
39 | + 40, /* 1010 - 4x */ | |
40 | + 50, /* 1011 - 5x */ | |
41 | + 80, /* 1100 - 8x */ | |
42 | + 60, /* 1101 - 6x */ | |
43 | + 35, /* 1110 - 3.5x */ | |
44 | + 0 /* 1111 - off */ | |
45 | +}; | |
46 | + | |
47 | +/* ------------------------------------------------------------------------- */ | |
48 | + | |
49 | +/* | |
50 | + * Measure CPU clock speed (core clock GCLK1, GCLK2) | |
51 | + * | |
52 | + * (Approx. GCLK frequency in Hz) | |
53 | + */ | |
54 | + | |
55 | +int get_clocks (void) | |
56 | +{ | |
57 | + DECLARE_GLOBAL_DATA_PTR; | |
58 | + | |
59 | + ulong clock = CFG_BUS_CLK * \ | |
60 | + hid1_multipliers_x_10[get_hid1 () >> 28] / 10; | |
61 | + gd->cpu_clk = clock; | |
62 | + gd->bus_clk = CFG_BUS_CLK; | |
63 | + | |
64 | + return (0); | |
65 | +} | |
66 | + | |
67 | +/* ------------------------------------------------------------------------- */ | |
68 | + | |
69 | +#if 0 /* disabled XXX - use global data instead */ | |
70 | +ulong get_bus_freq (ulong gclk_freq) | |
71 | +{ | |
72 | + return CFG_BUS_CLK; | |
73 | +} | |
74 | +#endif /* 0 */ | |
75 | + | |
76 | +/* ------------------------------------------------------------------------- */ |
cpu/mpc824x/cpu.c
1 | +/* | |
2 | + * (C) Copyright 2000 - 2002 | |
3 | + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | + * | |
5 | + * See file CREDITS for list of people who contributed to this | |
6 | + * project. | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU General Public License as | |
10 | + * published by the Free Software Foundation; either version 2 of | |
11 | + * the License, or (at your option) any later version. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, write to the Free Software | |
20 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | + * MA 02111-1307 USA | |
22 | + */ | |
23 | + | |
24 | +#include <config.h> | |
25 | +#include <mpc824x.h> | |
26 | +#include <common.h> | |
27 | +#include <command.h> | |
28 | + | |
29 | +int checkcpu (void) | |
30 | +{ | |
31 | + DECLARE_GLOBAL_DATA_PTR; | |
32 | + | |
33 | + unsigned int pvr = get_pvr (); | |
34 | + unsigned int version = pvr >> 16; | |
35 | + unsigned char revision; | |
36 | + ulong clock = gd->cpu_clk; | |
37 | + char buf[32]; | |
38 | + | |
39 | + puts ("CPU: "); | |
40 | + | |
41 | + switch (version) { | |
42 | + case CPU_TYPE_8240: | |
43 | + puts ("MPC8240"); | |
44 | + break; | |
45 | + | |
46 | + case CPU_TYPE_8245: | |
47 | + puts ("MPC8245"); | |
48 | + break; | |
49 | + | |
50 | + default: | |
51 | + return -1; /*not valid for this source */ | |
52 | + } | |
53 | + | |
54 | + CONFIG_READ_BYTE (REVID, revision); | |
55 | + | |
56 | + if (revision) { | |
57 | + printf (" Revision %d.%d", | |
58 | + (revision & 0xf0) >> 4, | |
59 | + (revision & 0x0f)); | |
60 | + } else { | |
61 | + return -1; /* no valid CPU revision info */ | |
62 | + } | |
63 | + | |
64 | + printf (" at %s MHz:", strmhz (buf, clock)); | |
65 | + | |
66 | + printf (" %u kB I-Cache", checkicache () >> 10); | |
67 | + printf (" %u kB D-Cache", checkdcache () >> 10); | |
68 | + | |
69 | + puts ("\n"); | |
70 | + | |
71 | + return 0; | |
72 | +} | |
73 | + | |
74 | +/* ------------------------------------------------------------------------- */ | |
75 | +/* L1 i-cache */ | |
76 | + | |
77 | +int checkicache (void) | |
78 | +{ | |
79 | + /*TODO*/ | |
80 | + return 128 * 4 * 32; | |
81 | +}; | |
82 | + | |
83 | +/* ------------------------------------------------------------------------- */ | |
84 | +/* L1 d-cache */ | |
85 | + | |
86 | +int checkdcache (void) | |
87 | +{ | |
88 | + /*TODO*/ | |
89 | + return 128 * 4 * 32; | |
90 | + | |
91 | +}; | |
92 | + | |
93 | +/*------------------------------------------------------------------- */ | |
94 | + | |
95 | +int do_reset (cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, | |
96 | + char *argv[]) | |
97 | +{ | |
98 | + ulong msr, addr; | |
99 | + | |
100 | + /* Interrupts and MMU off */ | |
101 | + __asm__ ("mtspr 81, 0"); | |
102 | + | |
103 | + /* Interrupts and MMU off */ | |
104 | + __asm__ __volatile__ ("mfmsr %0":"=r" (msr):); | |
105 | + | |
106 | + msr &= ~0x1030; | |
107 | + __asm__ __volatile__ ("mtmsr %0"::"r" (msr)); | |
108 | + | |
109 | + /* | |
110 | + * Trying to execute the next instruction at a non-existing address | |
111 | + * should cause a machine check, resulting in reset | |
112 | + */ | |
113 | +#ifdef CFG_RESET_ADDRESS | |
114 | + addr = CFG_RESET_ADDRESS; | |
115 | +#else | |
116 | + /* | |
117 | + * note: when CFG_MONITOR_BASE points to a RAM address, | |
118 | + * CFG_MONITOR_BASE - sizeof (ulong) is usually a valid | |
119 | + * address. Better pick an address known to be invalid on | |
120 | + * your system and assign it to CFG_RESET_ADDRESS. | |
121 | + * "(ulong)-1" used to be a good choice for many systems... | |
122 | + */ | |
123 | + addr = CFG_MONITOR_BASE - sizeof (ulong); | |
124 | +#endif | |
125 | + ((void (*)(void)) addr) (); | |
126 | + return 1; | |
127 | + | |
128 | +} | |
129 | + | |
130 | +/* ------------------------------------------------------------------------- */ | |
131 | + | |
132 | +/* | |
133 | + * Get timebase clock frequency (like cpu_clk in Hz) | |
134 | + * This is the sys_logic_clk (memory bus) divided by 4 | |
135 | + */ | |
136 | +unsigned long get_tbclk (void) | |
137 | +{ | |
138 | + return ((get_bus_freq (0) + 2L) / 4L); | |
139 | +} | |
140 | + | |
141 | +/* ------------------------------------------------------------------------- */ | |
142 | + | |
143 | +/* | |
144 | + * The MPC824x has an integrated PCI controller known as the MPC107. | |
145 | + * The following are MPC107 Bridge Controller and PCI Support functions | |
146 | + * | |
147 | + */ | |
148 | + | |
149 | +/* | |
150 | + * This procedure reads a 32-bit address MPC107 register, and returns | |
151 | + * a 32 bit value. It swaps the address to little endian before | |
152 | + * writing it to config address, and swaps the value to big endian | |
153 | + * before returning to the caller. | |
154 | + */ | |
155 | +unsigned int mpc824x_mpc107_getreg (unsigned int regNum) | |
156 | +{ | |
157 | + unsigned int temp; | |
158 | + | |
159 | + /* swap the addr. to little endian */ | |
160 | + *(volatile unsigned int *) CHRP_REG_ADDR = PCISWAP (regNum); | |
161 | + temp = *(volatile unsigned int *) CHRP_REG_DATA; | |
162 | + return PCISWAP (temp); /* swap the data upon return */ | |
163 | +} | |
164 | + | |
165 | +/* | |
166 | + * This procedure writes a 32-bit address MPC107 register. It swaps | |
167 | + * the address to little endian before writing it to config address. | |
168 | + */ | |
169 | + | |
170 | +void mpc824x_mpc107_setreg (unsigned int regNum, unsigned int regVal) | |
171 | +{ | |
172 | + /* swap the addr. to little endian */ | |
173 | + *(volatile unsigned int *) CHRP_REG_ADDR = PCISWAP (regNum); | |
174 | + *(volatile unsigned int *) CHRP_REG_DATA = PCISWAP (regVal); | |
175 | + return; | |
176 | +} | |
177 | + | |
178 | + | |
179 | +/* | |
180 | + * Write a byte (8 bits) to a memory location. | |
181 | + */ | |
182 | +void mpc824x_mpc107_write8 (unsigned int addr, unsigned char data) | |
183 | +{ | |
184 | + *(unsigned char *) addr = data; | |
185 | + __asm__ ("sync"); | |
186 | +} | |
187 | + | |
188 | +/* | |
189 | + * Write a word (16 bits) to a memory location after the value | |
190 | + * has been byte swapped (big to little endian or vice versa) | |
191 | + */ | |
192 | + | |
193 | +void mpc824x_mpc107_write16 (unsigned int address, unsigned short data) | |
194 | +{ | |
195 | + *(volatile unsigned short *) address = BYTE_SWAP_16_BIT (data); | |
196 | + __asm__ ("sync"); | |
197 | +} | |
198 | + | |
199 | +/* | |
200 | + * Write a long word (32 bits) to a memory location after the value | |
201 | + * has been byte swapped (big to little endian or vice versa) | |
202 | + */ | |
203 | + | |
204 | +void mpc824x_mpc107_write32 (unsigned int address, unsigned int data) | |
205 | +{ | |
206 | + *(volatile unsigned int *) address = LONGSWAP (data); | |
207 | + __asm__ ("sync"); | |
208 | +} | |
209 | + | |
210 | +/* | |
211 | + * Read a byte (8 bits) from a memory location. | |
212 | + */ | |
213 | +unsigned char mpc824x_mpc107_read8 (unsigned int addr) | |
214 | +{ | |
215 | + return *(volatile unsigned char *) addr; | |
216 | +} | |
217 | + | |
218 | + | |
219 | +/* | |
220 | + * Read a word (16 bits) from a memory location, and byte swap the | |
221 | + * value before returning to the caller. | |
222 | + */ | |
223 | +unsigned short mpc824x_mpc107_read16 (unsigned int address) | |
224 | +{ | |
225 | + unsigned short retVal; | |
226 | + | |
227 | + retVal = BYTE_SWAP_16_BIT (*(unsigned short *) address); | |
228 | + return retVal; | |
229 | +} | |
230 | + | |
231 | + | |
232 | +/* | |
233 | + * Read a long word (32 bits) from a memory location, and byte | |
234 | + * swap the value before returning to the caller. | |
235 | + */ | |
236 | +unsigned int mpc824x_mpc107_read32 (unsigned int address) | |
237 | +{ | |
238 | + unsigned int retVal; | |
239 | + | |
240 | + retVal = LONGSWAP (*(unsigned int *) address); | |
241 | + return (retVal); | |
242 | +} | |
243 | + | |
244 | + | |
245 | +/* | |
246 | + * Read a register in the Embedded Utilities Memory Block address | |
247 | + * space. | |
248 | + * Input: regNum - register number + utility base address. Example, | |
249 | + * the base address of EPIC is 0x40000, the register number | |
250 | + * being passed is 0x40000+the address of the target register. | |
251 | + * (See epic.h for register addresses). | |
252 | + * Output: The 32 bit little endian value of the register. | |
253 | + */ | |
254 | + | |
255 | +unsigned int mpc824x_eummbar_read (unsigned int regNum) | |
256 | +{ | |
257 | + unsigned int temp; | |
258 | + | |
259 | + temp = *(volatile unsigned int *) (EUMBBAR_VAL + regNum); | |
260 | + temp = PCISWAP (temp); | |
261 | + return temp; | |
262 | +} | |
263 | + | |
264 | + | |
265 | +/* | |
266 | + * Write a value to a register in the Embedded Utilities Memory | |
267 | + * Block address space. | |
268 | + * Input: regNum - register number + utility base address. Example, | |
269 | + * the base address of EPIC is 0x40000, the register | |
270 | + * number is 0x40000+the address of the target register. | |
271 | + * (See epic.h for register addresses). | |
272 | + * regVal - value to be written to the register. | |
273 | + */ | |
274 | + | |
275 | +void mpc824x_eummbar_write (unsigned int regNum, unsigned int regVal) | |
276 | +{ | |
277 | + *(volatile unsigned int *) (EUMBBAR_VAL + regNum) = PCISWAP (regVal); | |
278 | + return; | |
279 | +} | |
280 | + | |
281 | +/* ------------------------------------------------------------------------- */ |
cpu/mpc824x/interrupts.c
1 | +/* | |
2 | + * (C) Copyright 2000-2002 | |
3 | + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | + * Rob Taylor, Flying Pig Systems. robt@flyingpig.com | |
5 | + * | |
6 | + * See file CREDITS for list of people who contributed to this | |
7 | + * project. | |
8 | + * | |
9 | + * This program is free software; you can redistribute it and/or | |
10 | + * modify it under the terms of the GNU General Public License as | |
11 | + * published by the Free Software Foundation; either version 2 of | |
12 | + * the License, or (at your option) any later version. | |
13 | + * | |
14 | + * This program is distributed in the hope that it will be useful, | |
15 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | + * GNU General Public License for more details. | |
18 | + * | |
19 | + * You should have received a copy of the GNU General Public License | |
20 | + * along with this program; if not, write to the Free Software | |
21 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
22 | + * MA 02111-1307 USA | |
23 | + */ | |
24 | + | |
25 | +#include <common.h> | |
26 | +#include <mpc824x.h> | |
27 | +#include <asm/processor.h> | |
28 | +#include <asm/pci_io.h> | |
29 | +#include <commproc.h> | |
30 | +#include "drivers/epic.h" | |
31 | + | |
32 | +/****************************************************************************/ | |
33 | + | |
34 | +unsigned decrementer_count; /* count val for 1e6/HZ microseconds */ | |
35 | + | |
36 | +static __inline__ unsigned long get_msr (void) | |
37 | +{ | |
38 | + unsigned long msr; | |
39 | + | |
40 | + asm volatile ("mfmsr %0":"=r" (msr):); | |
41 | + | |
42 | + return msr; | |
43 | +} | |
44 | + | |
45 | +static __inline__ void set_msr (unsigned long msr) | |
46 | +{ | |
47 | + asm volatile ("mtmsr %0"::"r" (msr)); | |
48 | +} | |
49 | + | |
50 | +static __inline__ unsigned long get_dec (void) | |
51 | +{ | |
52 | + unsigned long val; | |
53 | + | |
54 | + asm volatile ("mfdec %0":"=r" (val):); | |
55 | + | |
56 | + return val; | |
57 | +} | |
58 | + | |
59 | + | |
60 | +static __inline__ void set_dec (unsigned long val) | |
61 | +{ | |
62 | + asm volatile ("mtdec %0"::"r" (val)); | |
63 | +} | |
64 | + | |
65 | + | |
66 | +void enable_interrupts (void) | |
67 | +{ | |
68 | + set_msr (get_msr () | MSR_EE); | |
69 | +} | |
70 | + | |
71 | +/* returns flag if MSR_EE was set before */ | |
72 | +int disable_interrupts (void) | |
73 | +{ | |
74 | + ulong msr = get_msr (); | |
75 | + | |
76 | + set_msr (msr & ~MSR_EE); | |
77 | + return ((msr & MSR_EE) != 0); | |
78 | +} | |
79 | + | |
80 | +/****************************************************************************/ | |
81 | + | |
82 | +int interrupt_init (void) | |
83 | +{ | |
84 | + decrementer_count = (get_bus_freq (0) / 4) / CFG_HZ; | |
85 | + | |
86 | + /* | |
87 | + * It's all broken at the moment and I currently don't need | |
88 | + * interrupts. If you want to fix it, have a look at the epic | |
89 | + * drivers in dink32 v12. They do everthing and Motorola said | |
90 | + * I could use the dink source in this project as long as | |
91 | + * copyright notices remain intact. | |
92 | + */ | |
93 | + | |
94 | + epicInit (EPIC_DIRECT_IRQ, 0); | |
95 | + | |
96 | + set_dec (decrementer_count); | |
97 | + | |
98 | + set_msr (get_msr () | MSR_EE); | |
99 | + | |
100 | + return (0); | |
101 | +} | |
102 | + | |
103 | +/****************************************************************************/ | |
104 | + | |
105 | +/* | |
106 | + * Handle external interrupts | |
107 | + */ | |
108 | +void external_interrupt (struct pt_regs *regs) | |
109 | +{ | |
110 | + register unsigned long temp; | |
111 | + | |
112 | + pci_readl (CFG_EUMB_ADDR + EPIC_PROC_INT_ACK_REG, temp); | |
113 | + sync (); /* i'm not convinced this is needed, but dink source has it */ | |
114 | + temp &= 0xff; /*get vector */ | |
115 | + | |
116 | + /*TODO: handle them -... */ | |
117 | + epicEOI (); | |
118 | +} | |
119 | + | |
120 | +/****************************************************************************/ | |
121 | + | |
122 | +/* | |
123 | + * blank int handlers. | |
124 | + */ | |
125 | + | |
126 | +void | |
127 | +irq_install_handler (int vec, interrupt_handler_t * handler, void *arg) | |
128 | +{ | |
129 | +} | |
130 | + | |
131 | +void irq_free_handler (int vec) | |
132 | +{ | |
133 | + | |
134 | +} | |
135 | + | |
136 | +/*TODO: some handlers for winbond and 87308 interrupts | |
137 | + and what about generic pci inteerupts? | |
138 | + vga? | |
139 | + */ | |
140 | + | |
141 | +volatile ulong timestamp = 0; | |
142 | + | |
143 | +void timer_interrupt (struct pt_regs *regs) | |
144 | +{ | |
145 | + /* Restore Decrementer Count */ | |
146 | + set_dec (decrementer_count); | |
147 | + | |
148 | + timestamp++; | |
149 | + | |
150 | +#if defined(CONFIG_WATCHDOG) | |
151 | + if ((timestamp % (CFG_HZ / 2)) == 0) { | |
152 | +#if defined(CONFIG_OXC) | |
153 | + { | |
154 | + extern void oxc_wdt_reset (void); | |
155 | + | |
156 | + oxc_wdt_reset (); | |
157 | + } | |
158 | +#endif | |
159 | + } | |
160 | +#endif /* CONFIG_WATCHDOG */ | |
161 | +#if defined(CONFIG_SHOW_ACTIVITY) && defined(CONFIG_OXC) | |
162 | + if ((timestamp % (CFG_HZ / 10)) == 0) { | |
163 | + { | |
164 | + extern void oxc_toggle_activeled (void); | |
165 | + | |
166 | + oxc_toggle_activeled (); | |
167 | + } | |
168 | + } | |
169 | +#endif | |
170 | +} | |
171 | + | |
172 | +void reset_timer (void) | |
173 | +{ | |
174 | + timestamp = 0; | |
175 | +} | |
176 | + | |
177 | +ulong get_timer (ulong base) | |
178 | +{ | |
179 | + return (timestamp - base); | |
180 | +} | |
181 | + | |
182 | +void set_timer (ulong t) | |
183 | +{ | |
184 | + timestamp = t; | |
185 | +} |
cpu/mpc8260/cpu.c
1 | +/* | |
2 | + * (C) Copyright 2000 | |
3 | + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | + * | |
5 | + * See file CREDITS for list of people who contributed to this | |
6 | + * project. | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU General Public License as | |
10 | + * published by the Free Software Foundation; either version 2 of | |
11 | + * the License, or (at your option) any later version. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, write to the Free Software | |
20 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | + * MA 02111-1307 USA | |
22 | + */ | |
23 | + | |
24 | +/* | |
25 | + * CPU specific code for the MPC8260 | |
26 | + * | |
27 | + * written or collected and sometimes rewritten by | |
28 | + * Magnus Damm <damm@bitsmart.com> | |
29 | + * | |
30 | + * minor modifications by | |
31 | + * Wolfgang Denk <wd@denx.de> | |
32 | + * | |
33 | + * modified for 8260 by | |
34 | + * Murray Jensen <Murray.Jensen@cmst.csiro.au> | |
35 | + * | |
36 | + * added 8260 masks by | |
37 | + * Marius Groeger <mag@sysgo.de> | |
38 | + */ | |
39 | + | |
40 | +#include <common.h> | |
41 | +#include <watchdog.h> | |
42 | +#include <command.h> | |
43 | +#include <mpc8260.h> | |
44 | +#include <asm/processor.h> | |
45 | +#include <asm/cpm_8260.h> | |
46 | + | |
47 | +int checkcpu (void) | |
48 | +{ | |
49 | + DECLARE_GLOBAL_DATA_PTR; | |
50 | + | |
51 | + volatile immap_t *immap = (immap_t *) CFG_IMMR; | |
52 | + ulong clock = gd->cpu_clk; | |
53 | + uint pvr = get_pvr (); | |
54 | + uint immr, rev, m, k; | |
55 | + char buf[32]; | |
56 | + | |
57 | + puts ("CPU: "); | |
58 | + | |
59 | + if (((pvr >> 16) & 0xff) != 0x81) | |
60 | + return -1; /* whoops! not an MPC8260 */ | |
61 | + rev = pvr & 0xff; | |
62 | + | |
63 | + immr = immap->im_memctl.memc_immr; | |
64 | + if ((immr & IMMR_ISB_MSK) != CFG_IMMR) | |
65 | + return -1; /* whoops! someone moved the IMMR */ | |
66 | + | |
67 | + printf ("MPC8260 (Rev %02x, Mask ", rev); | |
68 | + | |
69 | + /* | |
70 | + * the bottom 16 bits of the immr are the Part Number and Mask Number | |
71 | + * (4-34); the 16 bits at PROFF_REVNUM (0x8af0) in dual port ram is the | |
72 | + * RISC Microcode Revision Number (13-10). | |
73 | + * For the 8260, Motorola doesn't include the Microcode Revision | |
74 | + * in the mask. | |
75 | + */ | |
76 | + m = immr & (IMMR_PARTNUM_MSK | IMMR_MASKNUM_MSK); | |
77 | + k = *((ushort *) & immap->im_dprambase[PROFF_REVNUM]); | |
78 | + | |
79 | + switch (m) { | |
80 | + case 0x0000: | |
81 | + printf ("0.2 2J24M"); | |
82 | + break; | |
83 | + case 0x0010: | |
84 | + printf ("A.0 K22A"); | |
85 | + break; | |
86 | + case 0x0011: | |
87 | + printf ("A.1 1K22A-XC"); | |
88 | + break; | |
89 | + case 0x0001: | |
90 | + printf ("B.1 1K23A"); | |
91 | + break; | |
92 | + case 0x0021: | |
93 | + printf ("B.2 2K23A-XC"); | |
94 | + break; | |
95 | + case 0x0023: | |
96 | + printf ("B.3 3K23A"); | |
97 | + break; | |
98 | + case 0x0024: | |
99 | + printf ("C.2 6K23A"); | |
100 | + break; | |
101 | + case 0x0060: | |
102 | + printf ("A.0(A) 2K25A"); | |
103 | + break; | |
104 | + default: | |
105 | + printf ("unknown [immr=0x%04x,k=0x%04x]", m, k); | |
106 | + break; | |
107 | + } | |
108 | + | |
109 | + printf (") at %s MHz\n", strmhz (buf, clock)); | |
110 | + | |
111 | + return 0; | |
112 | +} | |
113 | + | |
114 | +/* ------------------------------------------------------------------------- */ | |
115 | +/* configures a UPM by writing into the UPM RAM array */ | |
116 | +/* uses bank 11 and a dummy physical address (=BRx_BA_MSK) */ | |
117 | +/* NOTE: the physical address chosen must not overlap into any other area */ | |
118 | +/* mapped by the memory controller because bank 11 has the lowest priority */ | |
119 | + | |
120 | +void upmconfig (uint upm, uint * table, uint size) | |
121 | +{ | |
122 | + volatile immap_t *immap = (immap_t *) CFG_IMMR; | |
123 | + volatile memctl8260_t *memctl = &immap->im_memctl; | |
124 | + volatile uchar *dummy = (uchar *) BRx_BA_MSK; /* set all BA bits */ | |
125 | + uint i; | |
126 | + | |
127 | + /* first set up bank 11 to reference the correct UPM at a dummy address */ | |
128 | + | |
129 | + memctl->memc_or11 = ORxU_AM_MSK; /* set all AM bits */ | |
130 | + | |
131 | + switch (upm) { | |
132 | + | |
133 | + case UPMA: | |
134 | + memctl->memc_br11 = | |
135 | + ((uint)dummy & BRx_BA_MSK) | BRx_PS_32 | BRx_MS_UPMA | | |
136 | + BRx_V; | |
137 | + memctl->memc_mamr = MxMR_OP_WARR; | |
138 | + break; | |
139 | + | |
140 | + case UPMB: | |
141 | + memctl->memc_br11 = | |
142 | + ((uint)dummy & BRx_BA_MSK) | BRx_PS_32 | BRx_MS_UPMB | | |
143 | + BRx_V; | |
144 | + memctl->memc_mbmr = MxMR_OP_WARR; | |
145 | + break; | |
146 | + | |
147 | + case UPMC: | |
148 | + memctl->memc_br11 = | |
149 | + ((uint)dummy & BRx_BA_MSK) | BRx_PS_32 | BRx_MS_UPMC | | |
150 | + BRx_V; | |
151 | + memctl->memc_mcmr = MxMR_OP_WARR; | |
152 | + break; | |
153 | + | |
154 | + default: | |
155 | + panic ("upmconfig passed invalid UPM number (%u)\n", upm); | |
156 | + break; | |
157 | + | |
158 | + } | |
159 | + | |
160 | + /* | |
161 | + * at this point, the dummy address is set up to access the selected UPM, | |
162 | + * the MAD pointer is zero, and the MxMR OP is set for writing to RAM | |
163 | + * | |
164 | + * now we simply load the mdr with each word and poke the dummy address. | |
165 | + * the MAD is incremented on each access. | |
166 | + */ | |
167 | + | |
168 | + for (i = 0; i < size; i++) { | |
169 | + memctl->memc_mdr = table[i]; | |
170 | + *dummy = 0; | |
171 | + } | |
172 | + | |
173 | + /* now kill bank 11 */ | |
174 | + memctl->memc_br11 = 0; | |
175 | +} | |
176 | + | |
177 | +/* ------------------------------------------------------------------------- */ | |
178 | + | |
179 | +int | |
180 | +do_reset (cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char *argv[]) | |
181 | +{ | |
182 | + ulong msr, addr; | |
183 | + | |
184 | + volatile immap_t *immap = (immap_t *) CFG_IMMR; | |
185 | + | |
186 | + immap->im_clkrst.car_rmr = RMR_CSRE; /* Checkstop Reset enable */ | |
187 | + | |
188 | + /* Interrupts and MMU off */ | |
189 | + __asm__ __volatile__ ("mfmsr %0":"=r" (msr):); | |
190 | + | |
191 | + msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR); | |
192 | + __asm__ __volatile__ ("mtmsr %0"::"r" (msr)); | |
193 | + | |
194 | + /* | |
195 | + * Trying to execute the next instruction at a non-existing address | |
196 | + * should cause a machine check, resulting in reset | |
197 | + */ | |
198 | +#ifdef CFG_RESET_ADDRESS | |
199 | + addr = CFG_RESET_ADDRESS; | |
200 | +#else | |
201 | + /* | |
202 | + * note: when CFG_MONITOR_BASE points to a RAM address, CFG_MONITOR_BASE | |
203 | + * - sizeof (ulong) is usually a valid address. Better pick an address | |
204 | + * known to be invalid on your system and assign it to CFG_RESET_ADDRESS. | |
205 | + */ | |
206 | + addr = CFG_MONITOR_BASE - sizeof (ulong); | |
207 | +#endif | |
208 | + ((void (*)(void)) addr) (); | |
209 | + return 1; | |
210 | + | |
211 | +} | |
212 | + | |
213 | +/* ------------------------------------------------------------------------- */ | |
214 | + | |
215 | +/* | |
216 | + * Get timebase clock frequency (like cpu_clk in Hz) | |
217 | + * | |
218 | + */ | |
219 | +unsigned long get_tbclk (void) | |
220 | +{ | |
221 | + DECLARE_GLOBAL_DATA_PTR; | |
222 | + | |
223 | + ulong tbclk; | |
224 | + | |
225 | + tbclk = (gd->bus_clk + 3L) / 4L; | |
226 | + | |
227 | + return (tbclk); | |
228 | +} | |
229 | + | |
230 | +/* ------------------------------------------------------------------------- */ | |
231 | + | |
232 | +#if defined(CONFIG_WATCHDOG) | |
233 | +void watchdog_reset (void) | |
234 | +{ | |
235 | + int re_enable = disable_interrupts (); | |
236 | + | |
237 | + reset_8260_watchdog ((immap_t *) CFG_IMMR); | |
238 | + if (re_enable) | |
239 | + enable_interrupts (); | |
240 | +} | |
241 | +#endif /* CONFIG_WATCHDOG */ | |
242 | + | |
243 | +/* ------------------------------------------------------------------------- */ |
cpu/mpc8260/interrupts.c
1 | +/* | |
2 | + * (C) Copyright 2000-2002 | |
3 | + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | + * | |
5 | + * See file CREDITS for list of people who contributed to this | |
6 | + * project. | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU General Public License as | |
10 | + * published by the Free Software Foundation; either version 2 of | |
11 | + * the License, or (at your option) any later version. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, write to the Free Software | |
20 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | + * MA 02111-1307 USA | |
22 | + * | |
23 | + * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 22-Oct-00 | |
24 | + */ | |
25 | + | |
26 | +#include <common.h> | |
27 | +#include <watchdog.h> | |
28 | +#include <command.h> | |
29 | +#include <mpc8260.h> | |
30 | +#include <mpc8260_irq.h> | |
31 | +#include <asm/processor.h> | |
32 | + | |
33 | +/****************************************************************************/ | |
34 | + | |
35 | +unsigned decrementer_count; /* count val for 1e6/HZ microseconds */ | |
36 | + | |
37 | +struct irq_action { | |
38 | + interrupt_handler_t *handler; | |
39 | + void *arg; | |
40 | + ulong count; | |
41 | +}; | |
42 | + | |
43 | +static struct irq_action irq_handlers[NR_IRQS]; | |
44 | + | |
45 | +static ulong ppc_cached_irq_mask[NR_MASK_WORDS]; | |
46 | + | |
47 | +/****************************************************************************/ | |
48 | +/* this section was ripped out of arch/ppc/kernel/ppc8260_pic.c in the */ | |
49 | +/* Linux/PPC 2.4.x source. There was no copyright notice in that file. */ | |
50 | + | |
51 | +/* The 8260 internal interrupt controller. It is usually | |
52 | + * the only interrupt controller. | |
53 | + * There are two 32-bit registers (high/low) for up to 64 | |
54 | + * possible interrupts. | |
55 | + * | |
56 | + * Now, the fun starts.....Interrupt Numbers DO NOT MAP | |
57 | + * in a simple arithmetic fashion to mask or pending registers. | |
58 | + * That is, interrupt 4 does not map to bit position 4. | |
59 | + * We create two tables, indexed by vector number, to indicate | |
60 | + * which register to use and which bit in the register to use. | |
61 | + */ | |
62 | +static u_char irq_to_siureg[] = { | |
63 | + 1, 1, 1, 1, 1, 1, 1, 1, | |
64 | + 1, 1, 1, 1, 1, 1, 1, 1, | |
65 | + 0, 0, 0, 0, 0, 0, 0, 0, | |
66 | + 0, 0, 0, 0, 0, 0, 0, 0, | |
67 | + 1, 1, 1, 1, 1, 1, 1, 1, | |
68 | + 1, 1, 1, 1, 1, 1, 1, 1, | |
69 | + 0, 0, 0, 0, 0, 0, 0, 0, | |
70 | + 0, 0, 0, 0, 0, 0, 0, 0 | |
71 | +}; | |
72 | + | |
73 | +static u_char irq_to_siubit[] = { | |
74 | + 31, 16, 17, 18, 19, 20, 21, 22, | |
75 | + 23, 24, 25, 26, 27, 28, 29, 30, | |
76 | + 29, 30, 16, 17, 18, 19, 20, 21, | |
77 | + 22, 23, 24, 25, 26, 27, 28, 31, | |
78 | + 0, 1, 2, 3, 4, 5, 6, 7, | |
79 | + 8, 9, 10, 11, 12, 13, 14, 15, | |
80 | + 15, 14, 13, 12, 11, 10, 9, 8, | |
81 | + 7, 6, 5, 4, 3, 2, 1, 0 | |
82 | +}; | |
83 | + | |
84 | +static void m8260_mask_irq (unsigned int irq_nr) | |
85 | +{ | |
86 | + volatile immap_t *immr = (immap_t *) CFG_IMMR; | |
87 | + int bit, word; | |
88 | + volatile uint *simr; | |
89 | + | |
90 | + bit = irq_to_siubit[irq_nr]; | |
91 | + word = irq_to_siureg[irq_nr]; | |
92 | + | |
93 | + simr = &(immr->im_intctl.ic_simrh); | |
94 | + ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); | |
95 | + simr[word] = ppc_cached_irq_mask[word]; | |
96 | +} | |
97 | + | |
98 | +static void m8260_unmask_irq (unsigned int irq_nr) | |
99 | +{ | |
100 | + volatile immap_t *immr = (immap_t *) CFG_IMMR; | |
101 | + int bit, word; | |
102 | + volatile uint *simr; | |
103 | + | |
104 | + bit = irq_to_siubit[irq_nr]; | |
105 | + word = irq_to_siureg[irq_nr]; | |
106 | + | |
107 | + simr = &(immr->im_intctl.ic_simrh); | |
108 | + ppc_cached_irq_mask[word] |= (1 << (31 - bit)); | |
109 | + simr[word] = ppc_cached_irq_mask[word]; | |
110 | +} | |
111 | + | |
112 | +static void m8260_mask_and_ack (unsigned int irq_nr) | |
113 | +{ | |
114 | + volatile immap_t *immr = (immap_t *) CFG_IMMR; | |
115 | + int bit, word; | |
116 | + volatile uint *simr, *sipnr; | |
117 | + | |
118 | + bit = irq_to_siubit[irq_nr]; | |
119 | + word = irq_to_siureg[irq_nr]; | |
120 | + | |
121 | + simr = &(immr->im_intctl.ic_simrh); | |
122 | + sipnr = &(immr->im_intctl.ic_sipnrh); | |
123 | + ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); | |
124 | + simr[word] = ppc_cached_irq_mask[word]; | |
125 | + sipnr[word] = 1 << (31 - bit); | |
126 | +} | |
127 | + | |
128 | +static int m8260_get_irq (struct pt_regs *regs) | |
129 | +{ | |
130 | + volatile immap_t *immr = (immap_t *) CFG_IMMR; | |
131 | + int irq; | |
132 | + unsigned long bits; | |
133 | + | |
134 | + /* For MPC8260, read the SIVEC register and shift the bits down | |
135 | + * to get the irq number. */ | |
136 | + bits = immr->im_intctl.ic_sivec; | |
137 | + irq = bits >> 26; | |
138 | + return irq; | |
139 | +} | |
140 | + | |
141 | +/* end of code ripped out of arch/ppc/kernel/ppc8260_pic.c */ | |
142 | +/****************************************************************************/ | |
143 | + | |
144 | +static __inline__ unsigned long get_msr (void) | |
145 | +{ | |
146 | + unsigned long msr; | |
147 | + | |
148 | + __asm__ __volatile__ ("mfmsr %0":"=r" (msr):); | |
149 | + | |
150 | + return msr; | |
151 | +} | |
152 | + | |
153 | +static __inline__ void set_msr (unsigned long msr) | |
154 | +{ | |
155 | + __asm__ __volatile__ ("mtmsr %0"::"r" (msr)); | |
156 | +} | |
157 | + | |
158 | +static __inline__ unsigned long get_dec (void) | |
159 | +{ | |
160 | + unsigned long val; | |
161 | + | |
162 | + __asm__ __volatile__ ("mfdec %0":"=r" (val):); | |
163 | + | |
164 | + return val; | |
165 | +} | |
166 | + | |
167 | +static __inline__ void set_dec (unsigned long val) | |
168 | +{ | |
169 | + __asm__ __volatile__ ("mtdec %0"::"r" (val)); | |
170 | +} | |
171 | + | |
172 | +void enable_interrupts (void) | |
173 | +{ | |
174 | + set_msr (get_msr () | MSR_EE); | |
175 | +} | |
176 | + | |
177 | +/* returns flag if MSR_EE was set before */ | |
178 | +int disable_interrupts (void) | |
179 | +{ | |
180 | + ulong msr = get_msr (); | |
181 | + | |
182 | + set_msr (msr & ~MSR_EE); | |
183 | + return ((msr & MSR_EE) != 0); | |
184 | +} | |
185 | + | |
186 | +/****************************************************************************/ | |
187 | + | |
188 | +int interrupt_init (void) | |
189 | +{ | |
190 | + DECLARE_GLOBAL_DATA_PTR; | |
191 | + | |
192 | + volatile immap_t *immr = (immap_t *) CFG_IMMR; | |
193 | + | |
194 | + decrementer_count = (gd->bus_clk / 4) / CFG_HZ; | |
195 | + | |
196 | + /* Initialize the default interrupt mapping priorities */ | |
197 | + immr->im_intctl.ic_sicr = 0; | |
198 | + immr->im_intctl.ic_siprr = 0x05309770; | |
199 | + immr->im_intctl.ic_scprrh = 0x05309770; | |
200 | + immr->im_intctl.ic_scprrl = 0x05309770; | |
201 | + | |
202 | + /* disable all interrupts and clear all pending bits */ | |
203 | + immr->im_intctl.ic_simrh = ppc_cached_irq_mask[0] = 0; | |
204 | + immr->im_intctl.ic_simrl = ppc_cached_irq_mask[1] = 0; | |
205 | + immr->im_intctl.ic_sipnrh = 0xffffffff; | |
206 | + immr->im_intctl.ic_sipnrl = 0xffffffff; | |
207 | + | |
208 | + set_dec (decrementer_count); | |
209 | + | |
210 | + set_msr (get_msr () | MSR_EE); | |
211 | + | |
212 | + return (0); | |
213 | +} | |
214 | + | |
215 | +/****************************************************************************/ | |
216 | + | |
217 | +/* | |
218 | + * Handle external interrupts | |
219 | + */ | |
220 | +void external_interrupt (struct pt_regs *regs) | |
221 | +{ | |
222 | + int irq, unmask = 1; | |
223 | + | |
224 | + irq = m8260_get_irq (regs); | |
225 | + | |
226 | + m8260_mask_and_ack (irq); | |
227 | + | |
228 | + set_msr (get_msr () | MSR_EE); | |
229 | + | |
230 | + if (irq_handlers[irq].handler != NULL) | |
231 | + (*irq_handlers[irq].handler) (irq_handlers[irq].arg); | |
232 | + else { | |
233 | + printf ("\nBogus External Interrupt IRQ %d\n", irq); | |
234 | + /* | |
235 | + * turn off the bogus interrupt, otherwise it | |
236 | + * might repeat forever | |
237 | + */ | |
238 | + unmask = 0; | |
239 | + } | |
240 | + | |
241 | + if (unmask) | |
242 | + m8260_unmask_irq (irq); | |
243 | +} | |
244 | + | |
245 | +/****************************************************************************/ | |
246 | + | |
247 | +/* | |
248 | + * Install and free an interrupt handler. | |
249 | + */ | |
250 | + | |
251 | +void | |
252 | +irq_install_handler (int irq, interrupt_handler_t * handler, void *arg) | |
253 | +{ | |
254 | + if (irq < 0 || irq >= NR_IRQS) { | |
255 | + printf ("irq_install_handler: bad irq number %d\n", irq); | |
256 | + return; | |
257 | + } | |
258 | + | |
259 | + if (irq_handlers[irq].handler != NULL) | |
260 | + printf ("irq_install_handler: 0x%08lx replacing 0x%08lx\n", | |
261 | + (ulong) handler, (ulong) irq_handlers[irq].handler); | |
262 | + | |
263 | + irq_handlers[irq].handler = handler; | |
264 | + irq_handlers[irq].arg = arg; | |
265 | + | |
266 | + m8260_unmask_irq (irq); | |
267 | +} | |
268 | + | |
269 | +void irq_free_handler (int irq) | |
270 | +{ | |
271 | + if (irq < 0 || irq >= NR_IRQS) { | |
272 | + printf ("irq_free_handler: bad irq number %d\n", irq); | |
273 | + return; | |
274 | + } | |
275 | + | |
276 | + m8260_mask_irq (irq); | |
277 | + | |
278 | + irq_handlers[irq].handler = NULL; | |
279 | + irq_handlers[irq].arg = NULL; | |
280 | +} | |
281 | + | |
282 | +/****************************************************************************/ | |
283 | + | |
284 | +volatile ulong timestamp = 0; | |
285 | + | |
286 | +/* | |
287 | + * timer_interrupt - gets called when the decrementer overflows, | |
288 | + * with interrupts disabled. | |
289 | + * Trivial implementation - no need to be really accurate. | |
290 | + */ | |
291 | +void timer_interrupt (struct pt_regs *regs) | |
292 | +{ | |
293 | +#if defined(CONFIG_WATCHDOG) || defined(CFG_HYMOD_DBLEDS) | |
294 | + volatile immap_t *immr = (immap_t *) CFG_IMMR; | |
295 | +#endif /* CONFIG_WATCHDOG */ | |
296 | + | |
297 | + /* Restore Decrementer Count */ | |
298 | + set_dec (decrementer_count); | |
299 | + | |
300 | + timestamp++; | |
301 | + | |
302 | +#if defined(CONFIG_WATCHDOG) || \ | |
303 | + defined(CFG_CMA_LCD_HEARTBEAT) || \ | |
304 | + defined(CFG_HYMOD_DBLEDS) | |
305 | + | |
306 | + if ((timestamp % CFG_HZ) == 0) { | |
307 | +#if defined(CFG_CMA_LCD_HEARTBEAT) | |
308 | + extern void lcd_heartbeat (void); | |
309 | +#endif /* CFG_CMA_LCD_HEARTBEAT */ | |
310 | +#if defined(CFG_HYMOD_DBLEDS) | |
311 | + volatile iop8260_t *iop = &immr->im_ioport; | |
312 | + static int shift = 0; | |
313 | +#endif /* CFG_HYMOD_DBLEDS */ | |
314 | + | |
315 | +#if defined(CFG_CMA_LCD_HEARTBEAT) | |
316 | + lcd_heartbeat (); | |
317 | +#endif /* CFG_CMA_LCD_HEARTBEAT */ | |
318 | + | |
319 | +#if defined(CONFIG_WATCHDOG) | |
320 | + reset_8260_watchdog (immr); | |
321 | +#endif /* CONFIG_WATCHDOG */ | |
322 | + | |
323 | +#if defined(CFG_HYMOD_DBLEDS) | |
324 | + /* hymod daughter board LEDs */ | |
325 | + if (++shift > 3) | |
326 | + shift = 0; | |
327 | + iop->iop_pdatd = | |
328 | + (iop->iop_pdatd & ~0x0f000000) | (1 << (24 + shift)); | |
329 | +#endif /* CFG_HYMOD_DBLEDS */ | |
330 | + } | |
331 | +#endif /* CONFIG_WATCHDOG || CFG_CMA_LCD_HEARTBEAT */ | |
332 | +} | |
333 | + | |
334 | +/****************************************************************************/ | |
335 | + | |
336 | +void reset_timer (void) | |
337 | +{ | |
338 | + timestamp = 0; | |
339 | +} | |
340 | + | |
341 | +ulong get_timer (ulong base) | |
342 | +{ | |
343 | + return (timestamp - base); | |
344 | +} | |
345 | + | |
346 | +void set_timer (ulong t) | |
347 | +{ | |
348 | + timestamp = t; | |
349 | +} | |
350 | + | |
351 | +/****************************************************************************/ | |
352 | + | |
353 | +#if (CONFIG_COMMANDS & CFG_CMD_IRQ) | |
354 | + | |
355 | +/* ripped this out of ppc4xx/interrupts.c */ | |
356 | + | |
357 | +/******************************************************************************* | |
358 | +* | |
359 | +* irqinfo - print information about PCI devices | |
360 | +* | |
361 | +*/ | |
362 | +void | |
363 | +do_irqinfo (cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char *argv[]) | |
364 | +{ | |
365 | + int irq, re_enable; | |
366 | + | |
367 | + re_enable = disable_interrupts (); | |
368 | + | |
369 | + printf ("\nInterrupt-Information:\n"); | |
370 | + printf ("Nr Routine Arg Count\n"); | |
371 | + | |
372 | + for (irq = 0; irq < 32; irq++) | |
373 | + if (irq_handlers[irq].handler != NULL) | |
374 | + printf ("%02d %08lx %08lx %ld\n", irq, | |
375 | + (ulong) irq_handlers[irq].handler, | |
376 | + (ulong) irq_handlers[irq].arg, | |
377 | + irq_handlers[irq].count); | |
378 | + | |
379 | + if (re_enable) | |
380 | + enable_interrupts (); | |
381 | +} | |
382 | + | |
383 | +#endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */ |
cpu/mpc8260/serial_scc.c
1 | +/* | |
2 | + * (C) Copyright 2000 | |
3 | + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | + * | |
5 | + * See file CREDITS for list of people who contributed to this | |
6 | + * project. | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU General Public License as | |
10 | + * published by the Free Software Foundation; either version 2 of | |
11 | + * the License, or (at your option) any later version. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, write to the Free Software | |
20 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | + * MA 02111-1307 USA | |
22 | + * | |
23 | + * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00. | |
24 | + */ | |
25 | + | |
26 | +/* | |
27 | + * Minimal serial functions needed to use one of the SCC ports | |
28 | + * as serial console interface. | |
29 | + */ | |
30 | + | |
31 | +#include <common.h> | |
32 | +#include <mpc8260.h> | |
33 | +#include <asm/cpm_8260.h> | |
34 | + | |
35 | +#if defined(CONFIG_CONS_ON_SCC) | |
36 | + | |
37 | +#if CONFIG_CONS_INDEX == 1 /* Console on SCC1 */ | |
38 | + | |
39 | +#define SCC_INDEX 0 | |
40 | +#define PROFF_SCC PROFF_SCC1 | |
41 | +#define CMXSCR_MASK (CMXSCR_GR1|CMXSCR_SC1|\ | |
42 | + CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK) | |
43 | +#define CMXSCR_VALUE (CMXSCR_RS1CS_BRG1|CMXSCR_TS1CS_BRG1) | |
44 | +#define CPM_CR_SCC_PAGE CPM_CR_SCC1_PAGE | |
45 | +#define CPM_CR_SCC_SBLOCK CPM_CR_SCC1_SBLOCK | |
46 | + | |
47 | +#elif CONFIG_CONS_INDEX == 2 /* Console on SCC2 */ | |
48 | + | |
49 | +#define SCC_INDEX 1 | |
50 | +#define PROFF_SCC PROFF_SCC2 | |
51 | +#define CMXSCR_MASK (CMXSCR_GR2|CMXSCR_SC2|\ | |
52 | + CMXSCR_RS2CS_MSK|CMXSCR_TS2CS_MSK) | |
53 | +#define CMXSCR_VALUE (CMXSCR_RS2CS_BRG2|CMXSCR_TS2CS_BRG2) | |
54 | +#define CPM_CR_SCC_PAGE CPM_CR_SCC2_PAGE | |
55 | +#define CPM_CR_SCC_SBLOCK CPM_CR_SCC2_SBLOCK | |
56 | + | |
57 | +#elif CONFIG_CONS_INDEX == 3 /* Console on SCC3 */ | |
58 | + | |
59 | +#define SCC_INDEX 2 | |
60 | +#define PROFF_SCC PROFF_SCC3 | |
61 | +#define CMXSCR_MASK (CMXSCR_GR3|CMXSCR_SC3|\ | |
62 | + CMXSCR_RS3CS_MSK|CMXSCR_TS3CS_MSK) | |
63 | +#define CMXSCR_VALUE (CMXSCR_RS3CS_BRG3|CMXSCR_TS3CS_BRG3) | |
64 | +#define CPM_CR_SCC_PAGE CPM_CR_SCC3_PAGE | |
65 | +#define CPM_CR_SCC_SBLOCK CPM_CR_SCC3_SBLOCK | |
66 | + | |
67 | +#elif CONFIG_CONS_INDEX == 4 /* Console on SCC4 */ | |
68 | + | |
69 | +#define SCC_INDEX 3 | |
70 | +#define PROFF_SCC PROFF_SCC4 | |
71 | +#define CMXSCR_MASK (CMXSCR_GR4|CMXSCR_SC4|\ | |
72 | + CMXSCR_RS4CS_MSK|CMXSCR_TS4CS_MSK) | |
73 | +#define CMXSCR_VALUE (CMXSCR_RS4CS_BRG4|CMXSCR_TS4CS_BRG4) | |
74 | +#define CPM_CR_SCC_PAGE CPM_CR_SCC4_PAGE | |
75 | +#define CPM_CR_SCC_SBLOCK CPM_CR_SCC4_SBLOCK | |
76 | + | |
77 | +#else | |
78 | + | |
79 | +#error "console not correctly defined" | |
80 | + | |
81 | +#endif | |
82 | + | |
83 | +int serial_init (void) | |
84 | +{ | |
85 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
86 | + volatile scc_t *sp; | |
87 | + volatile scc_uart_t *up; | |
88 | + volatile cbd_t *tbdf, *rbdf; | |
89 | + volatile cpm8260_t *cp = &(im->im_cpm); | |
90 | + uint dpaddr; | |
91 | + | |
92 | + /* initialize pointers to SCC */ | |
93 | + | |
94 | + sp = (scc_t *) &(im->im_scc[SCC_INDEX]); | |
95 | + up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC]; | |
96 | + | |
97 | + /* Disable transmitter/receiver. | |
98 | + */ | |
99 | + sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); | |
100 | + | |
101 | + /* put the SCC channel into NMSI (non multiplexd serial interface) | |
102 | + * mode and wire the selected SCC Tx and Rx clocks to BRGx (15-15). | |
103 | + */ | |
104 | + im->im_cpmux.cmx_scr = (im->im_cpmux.cmx_scr&~CMXSCR_MASK)|CMXSCR_VALUE; | |
105 | + | |
106 | + /* Set up the baud rate generator. | |
107 | + */ | |
108 | + serial_setbrg (); | |
109 | + | |
110 | + /* Allocate space for two buffer descriptors in the DP ram. | |
111 | + * damm: allocating space after the two buffers for rx/tx data | |
112 | + */ | |
113 | + | |
114 | + dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16); | |
115 | + | |
116 | + /* Set the physical address of the host memory buffers in | |
117 | + * the buffer descriptors. | |
118 | + */ | |
119 | + rbdf = (cbd_t *)&im->im_dprambase[dpaddr]; | |
120 | + rbdf->cbd_bufaddr = (uint) (rbdf+2); | |
121 | + rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; | |
122 | + tbdf = rbdf + 1; | |
123 | + tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1; | |
124 | + tbdf->cbd_sc = BD_SC_WRAP; | |
125 | + | |
126 | + /* Set up the uart parameters in the parameter ram. | |
127 | + */ | |
128 | + up->scc_genscc.scc_rbase = dpaddr; | |
129 | + up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t); | |
130 | + up->scc_genscc.scc_rfcr = CPMFCR_EB; | |
131 | + up->scc_genscc.scc_tfcr = CPMFCR_EB; | |
132 | + up->scc_genscc.scc_mrblr = 1; | |
133 | + up->scc_maxidl = 0; | |
134 | + up->scc_brkcr = 1; | |
135 | + up->scc_parec = 0; | |
136 | + up->scc_frmec = 0; | |
137 | + up->scc_nosec = 0; | |
138 | + up->scc_brkec = 0; | |
139 | + up->scc_uaddr1 = 0; | |
140 | + up->scc_uaddr2 = 0; | |
141 | + up->scc_toseq = 0; | |
142 | + up->scc_char1 = up->scc_char2 = up->scc_char3 = up->scc_char4 = 0x8000; | |
143 | + up->scc_char5 = up->scc_char6 = up->scc_char7 = up->scc_char8 = 0x8000; | |
144 | + up->scc_rccm = 0xc0ff; | |
145 | + | |
146 | + /* Mask all interrupts and remove anything pending. | |
147 | + */ | |
148 | + sp->scc_sccm = 0; | |
149 | + sp->scc_scce = 0xffff; | |
150 | + | |
151 | + /* Set 8 bit FIFO, 16 bit oversampling and UART mode. | |
152 | + */ | |
153 | + sp->scc_gsmrh = SCC_GSMRH_RFW; /* 8 bit FIFO */ | |
154 | + sp->scc_gsmrl = \ | |
155 | + SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16 | SCC_GSMRL_MODE_UART; | |
156 | + | |
157 | + /* Set CTS flow control, 1 stop bit, 8 bit character length, | |
158 | + * normal async UART mode, no parity | |
159 | + */ | |
160 | + sp->scc_psmr = SCU_PSMR_FLC | SCU_PSMR_CL; | |
161 | + | |
162 | + /* execute the "Init Rx and Tx params" CP command. | |
163 | + */ | |
164 | + | |
165 | + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ | |
166 | + ; | |
167 | + | |
168 | + cp->cp_cpcr = mk_cr_cmd(CPM_CR_SCC_PAGE, CPM_CR_SCC_SBLOCK, | |
169 | + 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; | |
170 | + | |
171 | + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ | |
172 | + ; | |
173 | + | |
174 | + /* Enable transmitter/receiver. | |
175 | + */ | |
176 | + sp->scc_gsmrl |= SCC_GSMRL_ENR | SCC_GSMRL_ENT; | |
177 | + | |
178 | + return (0); | |
179 | +} | |
180 | + | |
181 | +void | |
182 | +serial_setbrg (void) | |
183 | +{ | |
184 | + DECLARE_GLOBAL_DATA_PTR; | |
185 | + | |
186 | +#if defined(CONFIG_CONS_USE_EXTC) | |
187 | + m8260_cpm_extcbrg(SCC_INDEX, gd->baudrate, | |
188 | + CONFIG_CONS_EXTC_RATE, CONFIG_CONS_EXTC_PINSEL); | |
189 | +#else | |
190 | + m8260_cpm_setbrg(SCC_INDEX, gd->baudrate); | |
191 | +#endif | |
192 | +} | |
193 | + | |
194 | +void | |
195 | +serial_putc(const char c) | |
196 | +{ | |
197 | + volatile scc_uart_t *up; | |
198 | + volatile cbd_t *tbdf; | |
199 | + volatile immap_t *im; | |
200 | + | |
201 | + if (c == '\n') | |
202 | + serial_putc ('\r'); | |
203 | + | |
204 | + im = (immap_t *)CFG_IMMR; | |
205 | + up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC]; | |
206 | + tbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_tbase]; | |
207 | + | |
208 | + /* Wait for last character to go. | |
209 | + */ | |
210 | + while (tbdf->cbd_sc & BD_SC_READY) | |
211 | + ; | |
212 | + | |
213 | + /* Load the character into the transmit buffer. | |
214 | + */ | |
215 | + *(volatile char *)tbdf->cbd_bufaddr = c; | |
216 | + tbdf->cbd_datlen = 1; | |
217 | + tbdf->cbd_sc |= BD_SC_READY; | |
218 | +} | |
219 | + | |
220 | +void | |
221 | +serial_puts (const char *s) | |
222 | +{ | |
223 | + while (*s) { | |
224 | + serial_putc (*s++); | |
225 | + } | |
226 | +} | |
227 | + | |
228 | +int | |
229 | +serial_getc(void) | |
230 | +{ | |
231 | + volatile cbd_t *rbdf; | |
232 | + volatile scc_uart_t *up; | |
233 | + volatile immap_t *im; | |
234 | + unsigned char c; | |
235 | + | |
236 | + im = (immap_t *)CFG_IMMR; | |
237 | + up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC]; | |
238 | + rbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_rbase]; | |
239 | + | |
240 | + /* Wait for character to show up. | |
241 | + */ | |
242 | + while (rbdf->cbd_sc & BD_SC_EMPTY) | |
243 | + ; | |
244 | + | |
245 | + /* Grab the char and clear the buffer again. | |
246 | + */ | |
247 | + c = *(volatile unsigned char *)rbdf->cbd_bufaddr; | |
248 | + rbdf->cbd_sc |= BD_SC_EMPTY; | |
249 | + | |
250 | + return (c); | |
251 | +} | |
252 | + | |
253 | +int | |
254 | +serial_tstc() | |
255 | +{ | |
256 | + volatile cbd_t *rbdf; | |
257 | + volatile scc_uart_t *up; | |
258 | + volatile immap_t *im; | |
259 | + | |
260 | + im = (immap_t *)CFG_IMMR; | |
261 | + up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC]; | |
262 | + rbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_rbase]; | |
263 | + | |
264 | + return ((rbdf->cbd_sc & BD_SC_EMPTY) == 0); | |
265 | +} | |
266 | + | |
267 | +#endif /* CONFIG_CONS_ON_SCC */ | |
268 | + | |
269 | +#if defined(CONFIG_KGDB_ON_SCC) | |
270 | + | |
271 | +#if defined(CONFIG_CONS_ON_SCC) && CONFIG_KGDB_INDEX == CONFIG_CONS_INDEX | |
272 | +#error Whoops! serial console and kgdb are on the same scc serial port | |
273 | +#endif | |
274 | + | |
275 | +#if CONFIG_KGDB_INDEX == 1 /* KGDB Port on SCC1 */ | |
276 | + | |
277 | +#define KGDB_SCC_INDEX 0 | |
278 | +#define KGDB_PROFF_SCC PROFF_SCC1 | |
279 | +#define KGDB_CMXSCR_MASK (CMXSCR_GR1|CMXSCR_SC1|\ | |
280 | + CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK) | |
281 | +#define KGDB_CMXSCR_VALUE (CMXSCR_RS1CS_BRG1|CMXSCR_TS1CS_BRG1) | |
282 | +#define KGDB_CPM_CR_SCC_PAGE CPM_CR_SCC1_PAGE | |
283 | +#define KGDB_CPM_CR_SCC_SBLOCK CPM_CR_SCC1_SBLOCK | |
284 | + | |
285 | +#elif CONFIG_KGDB_INDEX == 2 /* KGDB Port on SCC2 */ | |
286 | + | |
287 | +#define KGDB_SCC_INDEX 1 | |
288 | +#define KGDB_PROFF_SCC PROFF_SCC2 | |
289 | +#define KGDB_CMXSCR_MASK (CMXSCR_GR2|CMXSCR_SC2|\ | |
290 | + CMXSCR_RS2CS_MSK|CMXSCR_TS2CS_MSK) | |
291 | +#define KGDB_CMXSCR_VALUE (CMXSCR_RS2CS_BRG2|CMXSCR_TS2CS_BRG2) | |
292 | +#define KGDB_CPM_CR_SCC_PAGE CPM_CR_SCC2_PAGE | |
293 | +#define KGDB_CPM_CR_SCC_SBLOCK CPM_CR_SCC2_SBLOCK | |
294 | + | |
295 | +#elif CONFIG_KGDB_INDEX == 3 /* KGDB Port on SCC3 */ | |
296 | + | |
297 | +#define KGDB_SCC_INDEX 2 | |
298 | +#define KGDB_PROFF_SCC PROFF_SCC3 | |
299 | +#define KGDB_CMXSCR_MASK (CMXSCR_GR3|CMXSCR_SC3|\ | |
300 | + CMXSCR_RS3CS_MSK|CMXSCR_TS3CS_MSK) | |
301 | +#define KGDB_CMXSCR_VALUE (CMXSCR_RS3CS_BRG3|CMXSCR_TS3CS_BRG3) | |
302 | +#define KGDB_CPM_CR_SCC_PAGE CPM_CR_SCC3_PAGE | |
303 | +#define KGDB_CPM_CR_SCC_SBLOCK CPM_CR_SCC3_SBLOCK | |
304 | + | |
305 | +#elif CONFIG_KGDB_INDEX == 4 /* KGDB Port on SCC4 */ | |
306 | + | |
307 | +#define KGDB_SCC_INDEX 3 | |
308 | +#define KGDB_PROFF_SCC PROFF_SCC4 | |
309 | +#define KGDB_CMXSCR_MASK (CMXSCR_GR4|CMXSCR_SC4|\ | |
310 | + CMXSCR_RS4CS_MSK|CMXSCR_TS4CS_MSK) | |
311 | +#define KGDB_CMXSCR_VALUE (CMXSCR_RS4CS_BRG4|CMXSCR_TS4CS_BRG4) | |
312 | +#define KGDB_CPM_CR_SCC_PAGE CPM_CR_SCC4_PAGE | |
313 | +#define KGDB_CPM_CR_SCC_SBLOCK CPM_CR_SCC4_SBLOCK | |
314 | + | |
315 | +#else | |
316 | + | |
317 | +#error "kgdb serial port not correctly defined" | |
318 | + | |
319 | +#endif | |
320 | + | |
321 | +void | |
322 | +kgdb_serial_init (void) | |
323 | +{ | |
324 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
325 | + volatile scc_t *sp; | |
326 | + volatile scc_uart_t *up; | |
327 | + volatile cbd_t *tbdf, *rbdf; | |
328 | + volatile cpm8260_t *cp = &(im->im_cpm); | |
329 | + uint dpaddr, speed = CONFIG_KGDB_BAUDRATE; | |
330 | + char *s, *e; | |
331 | + | |
332 | + if ((s = getenv("kgdbrate")) != NULL && *s != '\0') { | |
333 | + ulong rate = simple_strtoul(s, &e, 10); | |
334 | + if (e > s && *e == '\0') | |
335 | + speed = rate; | |
336 | + } | |
337 | + | |
338 | + /* initialize pointers to SCC */ | |
339 | + | |
340 | + sp = (scc_t *) &(im->im_scc[KGDB_SCC_INDEX]); | |
341 | + up = (scc_uart_t *)&im->im_dprambase[KGDB_PROFF_SCC]; | |
342 | + | |
343 | + /* Disable transmitter/receiver. | |
344 | + */ | |
345 | + sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); | |
346 | + | |
347 | + /* put the SCC channel into NMSI (non multiplexd serial interface) | |
348 | + * mode and wire the selected SCC Tx and Rx clocks to BRGx (15-15). | |
349 | + */ | |
350 | + im->im_cpmux.cmx_scr = \ | |
351 | + (im->im_cpmux.cmx_scr & ~KGDB_CMXSCR_MASK) | KGDB_CMXSCR_VALUE; | |
352 | + | |
353 | + /* Set up the baud rate generator. | |
354 | + */ | |
355 | +#if defined(CONFIG_KGDB_USE_EXTC) | |
356 | + m8260_cpm_extcbrg(KGDB_SCC_INDEX, speed, | |
357 | + CONFIG_KGDB_EXTC_RATE, CONFIG_KGDB_EXTC_PINSEL); | |
358 | +#else | |
359 | + m8260_cpm_setbrg(KGDB_SCC_INDEX, speed); | |
360 | +#endif | |
361 | + | |
362 | + /* Allocate space for two buffer descriptors in the DP ram. | |
363 | + * damm: allocating space after the two buffers for rx/tx data | |
364 | + */ | |
365 | + | |
366 | + dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16); | |
367 | + | |
368 | + /* Set the physical address of the host memory buffers in | |
369 | + * the buffer descriptors. | |
370 | + */ | |
371 | + rbdf = (cbd_t *)&im->im_dprambase[dpaddr]; | |
372 | + rbdf->cbd_bufaddr = (uint) (rbdf+2); | |
373 | + rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; | |
374 | + tbdf = rbdf + 1; | |
375 | + tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1; | |
376 | + tbdf->cbd_sc = BD_SC_WRAP; | |
377 | + | |
378 | + /* Set up the uart parameters in the parameter ram. | |
379 | + */ | |
380 | + up->scc_genscc.scc_rbase = dpaddr; | |
381 | + up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t); | |
382 | + up->scc_genscc.scc_rfcr = CPMFCR_EB; | |
383 | + up->scc_genscc.scc_tfcr = CPMFCR_EB; | |
384 | + up->scc_genscc.scc_mrblr = 1; | |
385 | + up->scc_maxidl = 0; | |
386 | + up->scc_brkcr = 1; | |
387 | + up->scc_parec = 0; | |
388 | + up->scc_frmec = 0; | |
389 | + up->scc_nosec = 0; | |
390 | + up->scc_brkec = 0; | |
391 | + up->scc_uaddr1 = 0; | |
392 | + up->scc_uaddr2 = 0; | |
393 | + up->scc_toseq = 0; | |
394 | + up->scc_char1 = up->scc_char2 = up->scc_char3 = up->scc_char4 = 0x8000; | |
395 | + up->scc_char5 = up->scc_char6 = up->scc_char7 = up->scc_char8 = 0x8000; | |
396 | + up->scc_rccm = 0xc0ff; | |
397 | + | |
398 | + /* Mask all interrupts and remove anything pending. | |
399 | + */ | |
400 | + sp->scc_sccm = 0; | |
401 | + sp->scc_scce = 0xffff; | |
402 | + | |
403 | + /* Set 8 bit FIFO, 16 bit oversampling and UART mode. | |
404 | + */ | |
405 | + sp->scc_gsmrh = SCC_GSMRH_RFW; /* 8 bit FIFO */ | |
406 | + sp->scc_gsmrl = \ | |
407 | + SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16 | SCC_GSMRL_MODE_UART; | |
408 | + | |
409 | + /* Set CTS flow control, 1 stop bit, 8 bit character length, | |
410 | + * normal async UART mode, no parity | |
411 | + */ | |
412 | + sp->scc_psmr = SCU_PSMR_FLC | SCU_PSMR_CL; | |
413 | + | |
414 | + /* execute the "Init Rx and Tx params" CP command. | |
415 | + */ | |
416 | + | |
417 | + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ | |
418 | + ; | |
419 | + | |
420 | + cp->cp_cpcr = mk_cr_cmd(KGDB_CPM_CR_SCC_PAGE, KGDB_CPM_CR_SCC_SBLOCK, | |
421 | + 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; | |
422 | + | |
423 | + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ | |
424 | + ; | |
425 | + | |
426 | + /* Enable transmitter/receiver. | |
427 | + */ | |
428 | + sp->scc_gsmrl |= SCC_GSMRL_ENR | SCC_GSMRL_ENT; | |
429 | + | |
430 | + printf("SCC%d at %dbps ", CONFIG_KGDB_INDEX, speed); | |
431 | +} | |
432 | + | |
433 | +void | |
434 | +putDebugChar(const char c) | |
435 | +{ | |
436 | + volatile scc_uart_t *up; | |
437 | + volatile cbd_t *tbdf; | |
438 | + volatile immap_t *im; | |
439 | + | |
440 | + if (c == '\n') | |
441 | + putDebugChar ('\r'); | |
442 | + | |
443 | + im = (immap_t *)CFG_IMMR; | |
444 | + up = (scc_uart_t *)&im->im_dprambase[KGDB_PROFF_SCC]; | |
445 | + tbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_tbase]; | |
446 | + | |
447 | + /* Wait for last character to go. | |
448 | + */ | |
449 | + while (tbdf->cbd_sc & BD_SC_READY) | |
450 | + ; | |
451 | + | |
452 | + /* Load the character into the transmit buffer. | |
453 | + */ | |
454 | + *(volatile char *)tbdf->cbd_bufaddr = c; | |
455 | + tbdf->cbd_datlen = 1; | |
456 | + tbdf->cbd_sc |= BD_SC_READY; | |
457 | +} | |
458 | + | |
459 | +void | |
460 | +putDebugStr (const char *s) | |
461 | +{ | |
462 | + while (*s) { | |
463 | + putDebugChar (*s++); | |
464 | + } | |
465 | +} | |
466 | + | |
467 | +int | |
468 | +getDebugChar(void) | |
469 | +{ | |
470 | + volatile cbd_t *rbdf; | |
471 | + volatile scc_uart_t *up; | |
472 | + volatile immap_t *im; | |
473 | + unsigned char c; | |
474 | + | |
475 | + im = (immap_t *)CFG_IMMR; | |
476 | + up = (scc_uart_t *)&im->im_dprambase[KGDB_PROFF_SCC]; | |
477 | + rbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_rbase]; | |
478 | + | |
479 | + /* Wait for character to show up. | |
480 | + */ | |
481 | + while (rbdf->cbd_sc & BD_SC_EMPTY) | |
482 | + ; | |
483 | + | |
484 | + /* Grab the char and clear the buffer again. | |
485 | + */ | |
486 | + c = *(volatile unsigned char *)rbdf->cbd_bufaddr; | |
487 | + rbdf->cbd_sc |= BD_SC_EMPTY; | |
488 | + | |
489 | + return (c); | |
490 | +} | |
491 | + | |
492 | +void | |
493 | +kgdb_interruptible(int yes) | |
494 | +{ | |
495 | + return; | |
496 | +} | |
497 | + | |
498 | +#endif /* CONFIG_KGDB_ON_SCC */ |
cpu/mpc8260/serial_smc.c
1 | +/* | |
2 | + * (C) Copyright 2000, 2001, 2002 | |
3 | + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | + * | |
5 | + * See file CREDITS for list of people who contributed to this | |
6 | + * project. | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU General Public License as | |
10 | + * published by the Free Software Foundation; either version 2 of | |
11 | + * the License, or (at your option) any later version. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, write to the Free Software | |
20 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | + * MA 02111-1307 USA | |
22 | + * | |
23 | + * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00, with | |
24 | + * changes based on the file arch/ppc/mbxboot/m8260_tty.c from the | |
25 | + * Linux/PPC sources (m8260_tty.c had no copyright info in it). | |
26 | + */ | |
27 | + | |
28 | +/* | |
29 | + * Minimal serial functions needed to use one of the SMC ports | |
30 | + * as serial console interface. | |
31 | + */ | |
32 | + | |
33 | +#include <common.h> | |
34 | +#include <mpc8260.h> | |
35 | +#include <asm/cpm_8260.h> | |
36 | + | |
37 | +#if defined(CONFIG_CONS_ON_SMC) | |
38 | + | |
39 | +#if CONFIG_CONS_INDEX == 1 /* Console on SMC1 */ | |
40 | + | |
41 | +#define SMC_INDEX 0 | |
42 | +#define PROFF_SMC_BASE PROFF_SMC1_BASE | |
43 | +#define PROFF_SMC PROFF_SMC1 | |
44 | +#define CPM_CR_SMC_PAGE CPM_CR_SMC1_PAGE | |
45 | +#define CPM_CR_SMC_SBLOCK CPM_CR_SMC1_SBLOCK | |
46 | +#define CMXSMR_MASK (CMXSMR_SMC1|CMXSMR_SMC1CS_MSK) | |
47 | +#define CMXSMR_VALUE CMXSMR_SMC1CS_BRG7 | |
48 | + | |
49 | +#elif CONFIG_CONS_INDEX == 2 /* Console on SMC2 */ | |
50 | + | |
51 | +#define SMC_INDEX 1 | |
52 | +#define PROFF_SMC_BASE PROFF_SMC2_BASE | |
53 | +#define PROFF_SMC PROFF_SMC2 | |
54 | +#define CPM_CR_SMC_PAGE CPM_CR_SMC2_PAGE | |
55 | +#define CPM_CR_SMC_SBLOCK CPM_CR_SMC2_SBLOCK | |
56 | +#define CMXSMR_MASK (CMXSMR_SMC2|CMXSMR_SMC2CS_MSK) | |
57 | +#define CMXSMR_VALUE CMXSMR_SMC2CS_BRG8 | |
58 | + | |
59 | +#else | |
60 | + | |
61 | +#error "console not correctly defined" | |
62 | + | |
63 | +#endif | |
64 | + | |
65 | +/* map rs_table index to baud rate generator index */ | |
66 | +static unsigned char brg_map[] = { | |
67 | + 6, /* BRG7 for SMC1 */ | |
68 | + 7, /* BRG8 for SMC2 */ | |
69 | + 0, /* BRG1 for SCC1 */ | |
70 | + 1, /* BRG1 for SCC2 */ | |
71 | + 2, /* BRG1 for SCC3 */ | |
72 | + 3, /* BRG1 for SCC4 */ | |
73 | +}; | |
74 | + | |
75 | +int serial_init (void) | |
76 | +{ | |
77 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
78 | + volatile smc_t *sp; | |
79 | + volatile smc_uart_t *up; | |
80 | + volatile cbd_t *tbdf, *rbdf; | |
81 | + volatile cpm8260_t *cp = &(im->im_cpm); | |
82 | + uint dpaddr; | |
83 | + | |
84 | + /* initialize pointers to SMC */ | |
85 | + | |
86 | + sp = (smc_t *) &(im->im_smc[SMC_INDEX]); | |
87 | + *(ushort *)(&im->im_dprambase[PROFF_SMC_BASE]) = PROFF_SMC; | |
88 | + up = (smc_uart_t *)&im->im_dprambase[PROFF_SMC]; | |
89 | + | |
90 | + /* Disable transmitter/receiver. | |
91 | + */ | |
92 | + sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); | |
93 | + | |
94 | + /* NOTE: I/O port pins are set up via the iop_conf_tab[] table */ | |
95 | + | |
96 | + /* Allocate space for two buffer descriptors in the DP ram. | |
97 | + * damm: allocating space after the two buffers for rx/tx data | |
98 | + */ | |
99 | + | |
100 | + dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16); | |
101 | + | |
102 | + /* Set the physical address of the host memory buffers in | |
103 | + * the buffer descriptors. | |
104 | + */ | |
105 | + rbdf = (cbd_t *)&im->im_dprambase[dpaddr]; | |
106 | + rbdf->cbd_bufaddr = (uint) (rbdf+2); | |
107 | + rbdf->cbd_sc = 0; | |
108 | + tbdf = rbdf + 1; | |
109 | + tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1; | |
110 | + tbdf->cbd_sc = 0; | |
111 | + | |
112 | + /* Set up the uart parameters in the parameter ram. | |
113 | + */ | |
114 | + up->smc_rbase = dpaddr; | |
115 | + up->smc_tbase = dpaddr+sizeof(cbd_t); | |
116 | + up->smc_rfcr = CPMFCR_EB; | |
117 | + up->smc_tfcr = CPMFCR_EB; | |
118 | + up->smc_brklen = 0; | |
119 | + up->smc_brkec = 0; | |
120 | + up->smc_brkcr = 0; | |
121 | + | |
122 | + /* Set UART mode, 8 bit, no parity, one stop. | |
123 | + * Enable receive and transmit. | |
124 | + */ | |
125 | + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; | |
126 | + | |
127 | + /* Mask all interrupts and remove anything pending. | |
128 | + */ | |
129 | + sp->smc_smcm = 0; | |
130 | + sp->smc_smce = 0xff; | |
131 | + | |
132 | + /* put the SMC channel into NMSI (non multiplexd serial interface) | |
133 | + * mode and wire either BRG7 to SMC1 or BRG8 to SMC2 (15-17). | |
134 | + */ | |
135 | + im->im_cpmux.cmx_smr = (im->im_cpmux.cmx_smr&~CMXSMR_MASK)|CMXSMR_VALUE; | |
136 | + | |
137 | + /* Set up the baud rate generator. | |
138 | + */ | |
139 | + serial_setbrg (); | |
140 | + | |
141 | + /* Make the first buffer the only buffer. | |
142 | + */ | |
143 | + tbdf->cbd_sc |= BD_SC_WRAP; | |
144 | + rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; | |
145 | + | |
146 | + /* Single character receive. | |
147 | + */ | |
148 | + up->smc_mrblr = 1; | |
149 | + up->smc_maxidl = 0; | |
150 | + | |
151 | + /* Initialize Tx/Rx parameters. | |
152 | + */ | |
153 | + | |
154 | + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ | |
155 | + ; | |
156 | + | |
157 | + cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC_PAGE, CPM_CR_SMC_SBLOCK, | |
158 | + 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; | |
159 | + | |
160 | + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ | |
161 | + ; | |
162 | + | |
163 | + /* Enable transmitter/receiver. | |
164 | + */ | |
165 | + sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; | |
166 | + | |
167 | + return (0); | |
168 | +} | |
169 | + | |
170 | +void | |
171 | +serial_setbrg (void) | |
172 | +{ | |
173 | + DECLARE_GLOBAL_DATA_PTR; | |
174 | + | |
175 | +#if defined(CONFIG_CONS_USE_EXTC) | |
176 | + m8260_cpm_extcbrg(brg_map[SMC_INDEX], gd->baudrate, | |
177 | + CONFIG_CONS_EXTC_RATE, CONFIG_CONS_EXTC_PINSEL); | |
178 | +#else | |
179 | + m8260_cpm_setbrg(brg_map[SMC_INDEX], gd->baudrate); | |
180 | +#endif | |
181 | +} | |
182 | + | |
183 | +void | |
184 | +serial_putc(const char c) | |
185 | +{ | |
186 | + volatile cbd_t *tbdf; | |
187 | + volatile char *buf; | |
188 | + volatile smc_uart_t *up; | |
189 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
190 | + | |
191 | + if (c == '\n') | |
192 | + serial_putc ('\r'); | |
193 | + | |
194 | + up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]); | |
195 | + | |
196 | + tbdf = (cbd_t *)&im->im_dprambase[up->smc_tbase]; | |
197 | + | |
198 | + /* Wait for last character to go. | |
199 | + */ | |
200 | + buf = (char *)tbdf->cbd_bufaddr; | |
201 | + while (tbdf->cbd_sc & BD_SC_READY) | |
202 | + ; | |
203 | + | |
204 | + *buf = c; | |
205 | + tbdf->cbd_datlen = 1; | |
206 | + tbdf->cbd_sc |= BD_SC_READY; | |
207 | +} | |
208 | + | |
209 | +void | |
210 | +serial_puts (const char *s) | |
211 | +{ | |
212 | + while (*s) { | |
213 | + serial_putc (*s++); | |
214 | + } | |
215 | +} | |
216 | + | |
217 | +int | |
218 | +serial_getc(void) | |
219 | +{ | |
220 | + volatile cbd_t *rbdf; | |
221 | + volatile unsigned char *buf; | |
222 | + volatile smc_uart_t *up; | |
223 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
224 | + unsigned char c; | |
225 | + | |
226 | + up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]); | |
227 | + | |
228 | + rbdf = (cbd_t *)&im->im_dprambase[up->smc_rbase]; | |
229 | + | |
230 | + /* Wait for character to show up. | |
231 | + */ | |
232 | + buf = (unsigned char *)rbdf->cbd_bufaddr; | |
233 | + while (rbdf->cbd_sc & BD_SC_EMPTY) | |
234 | + ; | |
235 | + c = *buf; | |
236 | + rbdf->cbd_sc |= BD_SC_EMPTY; | |
237 | + | |
238 | + return(c); | |
239 | +} | |
240 | + | |
241 | +int | |
242 | +serial_tstc() | |
243 | +{ | |
244 | + volatile cbd_t *rbdf; | |
245 | + volatile smc_uart_t *up; | |
246 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
247 | + | |
248 | + up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]); | |
249 | + | |
250 | + rbdf = (cbd_t *)&im->im_dprambase[up->smc_rbase]; | |
251 | + | |
252 | + return(!(rbdf->cbd_sc & BD_SC_EMPTY)); | |
253 | +} | |
254 | + | |
255 | +#endif /* CONFIG_CONS_ON_SMC */ | |
256 | + | |
257 | +#if defined(CONFIG_KGDB_ON_SMC) | |
258 | + | |
259 | +#if defined(CONFIG_CONS_ON_SMC) && CONFIG_KGDB_INDEX == CONFIG_CONS_INDEX | |
260 | +#error Whoops! serial console and kgdb are on the same smc serial port | |
261 | +#endif | |
262 | + | |
263 | +#if CONFIG_KGDB_INDEX == 1 /* KGDB Port on SMC1 */ | |
264 | + | |
265 | +#define KGDB_SMC_INDEX 0 | |
266 | +#define KGDB_PROFF_SMC_BASE PROFF_SMC1_BASE | |
267 | +#define KGDB_PROFF_SMC PROFF_SMC1 | |
268 | +#define KGDB_CPM_CR_SMC_PAGE CPM_CR_SMC1_PAGE | |
269 | +#define KGDB_CPM_CR_SMC_SBLOCK CPM_CR_SMC1_SBLOCK | |
270 | +#define KGDB_CMXSMR_MASK (CMXSMR_SMC1|CMXSMR_SMC1CS_MSK) | |
271 | +#define KGDB_CMXSMR_VALUE CMXSMR_SMC1CS_BRG7 | |
272 | + | |
273 | +#elif CONFIG_KGDB_INDEX == 2 /* KGDB Port on SMC2 */ | |
274 | + | |
275 | +#define KGDB_SMC_INDEX 1 | |
276 | +#define KGDB_PROFF_SMC_BASE PROFF_SMC2_BASE | |
277 | +#define KGDB_PROFF_SMC PROFF_SMC2 | |
278 | +#define KGDB_CPM_CR_SMC_PAGE CPM_CR_SMC2_PAGE | |
279 | +#define KGDB_CPM_CR_SMC_SBLOCK CPM_CR_SMC2_SBLOCK | |
280 | +#define KGDB_CMXSMR_MASK (CMXSMR_SMC2|CMXSMR_SMC2CS_MSK) | |
281 | +#define KGDB_CMXSMR_VALUE CMXSMR_SMC2CS_BRG8 | |
282 | + | |
283 | +#else | |
284 | + | |
285 | +#error "console not correctly defined" | |
286 | + | |
287 | +#endif | |
288 | + | |
289 | +void | |
290 | +kgdb_serial_init (void) | |
291 | +{ | |
292 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
293 | + volatile smc_t *sp; | |
294 | + volatile smc_uart_t *up; | |
295 | + volatile cbd_t *tbdf, *rbdf; | |
296 | + volatile cpm8260_t *cp = &(im->im_cpm); | |
297 | + uint dpaddr, speed = CONFIG_KGDB_BAUDRATE; | |
298 | + char *s, *e; | |
299 | + | |
300 | + if ((s = getenv("kgdbrate")) != NULL && *s != '\0') { | |
301 | + ulong rate = simple_strtoul(s, &e, 10); | |
302 | + if (e > s && *e == '\0') | |
303 | + speed = rate; | |
304 | + } | |
305 | + | |
306 | + /* initialize pointers to SMC */ | |
307 | + | |
308 | + sp = (smc_t *) &(im->im_smc[KGDB_SMC_INDEX]); | |
309 | + *(ushort *)(&im->im_dprambase[KGDB_PROFF_SMC_BASE]) = KGDB_PROFF_SMC; | |
310 | + up = (smc_uart_t *)&im->im_dprambase[KGDB_PROFF_SMC]; | |
311 | + | |
312 | + /* Disable transmitter/receiver. | |
313 | + */ | |
314 | + sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); | |
315 | + | |
316 | + /* NOTE: I/O port pins are set up via the iop_conf_tab[] table */ | |
317 | + | |
318 | + /* Allocate space for two buffer descriptors in the DP ram. | |
319 | + * damm: allocating space after the two buffers for rx/tx data | |
320 | + */ | |
321 | + | |
322 | + dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16); | |
323 | + | |
324 | + /* Set the physical address of the host memory buffers in | |
325 | + * the buffer descriptors. | |
326 | + */ | |
327 | + rbdf = (cbd_t *)&im->im_dprambase[dpaddr]; | |
328 | + rbdf->cbd_bufaddr = (uint) (rbdf+2); | |
329 | + rbdf->cbd_sc = 0; | |
330 | + tbdf = rbdf + 1; | |
331 | + tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1; | |
332 | + tbdf->cbd_sc = 0; | |
333 | + | |
334 | + /* Set up the uart parameters in the parameter ram. | |
335 | + */ | |
336 | + up->smc_rbase = dpaddr; | |
337 | + up->smc_tbase = dpaddr+sizeof(cbd_t); | |
338 | + up->smc_rfcr = CPMFCR_EB; | |
339 | + up->smc_tfcr = CPMFCR_EB; | |
340 | + up->smc_brklen = 0; | |
341 | + up->smc_brkec = 0; | |
342 | + up->smc_brkcr = 0; | |
343 | + | |
344 | + /* Set UART mode, 8 bit, no parity, one stop. | |
345 | + * Enable receive and transmit. | |
346 | + */ | |
347 | + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; | |
348 | + | |
349 | + /* Mask all interrupts and remove anything pending. | |
350 | + */ | |
351 | + sp->smc_smcm = 0; | |
352 | + sp->smc_smce = 0xff; | |
353 | + | |
354 | + /* put the SMC channel into NMSI (non multiplexd serial interface) | |
355 | + * mode and wire either BRG7 to SMC1 or BRG8 to SMC2 (15-17). | |
356 | + */ | |
357 | + im->im_cpmux.cmx_smr = | |
358 | + (im->im_cpmux.cmx_smr & ~KGDB_CMXSMR_MASK) | KGDB_CMXSMR_VALUE; | |
359 | + | |
360 | + /* Set up the baud rate generator. | |
361 | + */ | |
362 | +#if defined(CONFIG_KGDB_USE_EXTC) | |
363 | + m8260_cpm_extcbrg(KGDB_SMC_INDEX, speed, | |
364 | + CONFIG_KGDB_EXTC_RATE, CONFIG_KGDB_EXTC_PINSEL); | |
365 | +#else | |
366 | + m8260_cpm_setbrg(KGDB_SMC_INDEX, speed); | |
367 | +#endif | |
368 | + | |
369 | + /* Make the first buffer the only buffer. | |
370 | + */ | |
371 | + tbdf->cbd_sc |= BD_SC_WRAP; | |
372 | + rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; | |
373 | + | |
374 | + /* Single character receive. | |
375 | + */ | |
376 | + up->smc_mrblr = 1; | |
377 | + up->smc_maxidl = 0; | |
378 | + | |
379 | + /* Initialize Tx/Rx parameters. | |
380 | + */ | |
381 | + | |
382 | + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ | |
383 | + ; | |
384 | + | |
385 | + cp->cp_cpcr = mk_cr_cmd(KGDB_CPM_CR_SMC_PAGE, KGDB_CPM_CR_SMC_SBLOCK, | |
386 | + 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; | |
387 | + | |
388 | + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ | |
389 | + ; | |
390 | + | |
391 | + /* Enable transmitter/receiver. | |
392 | + */ | |
393 | + sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; | |
394 | + | |
395 | + printf("SMC%d at %dbps ", CONFIG_KGDB_INDEX, speed); | |
396 | +} | |
397 | + | |
398 | +void | |
399 | +putDebugChar(const char c) | |
400 | +{ | |
401 | + volatile cbd_t *tbdf; | |
402 | + volatile char *buf; | |
403 | + volatile smc_uart_t *up; | |
404 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
405 | + | |
406 | + if (c == '\n') | |
407 | + putDebugChar ('\r'); | |
408 | + | |
409 | + up = (smc_uart_t *)&(im->im_dprambase[KGDB_PROFF_SMC]); | |
410 | + | |
411 | + tbdf = (cbd_t *)&im->im_dprambase[up->smc_tbase]; | |
412 | + | |
413 | + /* Wait for last character to go. | |
414 | + */ | |
415 | + buf = (char *)tbdf->cbd_bufaddr; | |
416 | + while (tbdf->cbd_sc & BD_SC_READY) | |
417 | + ; | |
418 | + | |
419 | + *buf = c; | |
420 | + tbdf->cbd_datlen = 1; | |
421 | + tbdf->cbd_sc |= BD_SC_READY; | |
422 | +} | |
423 | + | |
424 | +void | |
425 | +putDebugStr (const char *s) | |
426 | +{ | |
427 | + while (*s) { | |
428 | + putDebugChar (*s++); | |
429 | + } | |
430 | +} | |
431 | + | |
432 | +int | |
433 | +getDebugChar(void) | |
434 | +{ | |
435 | + volatile cbd_t *rbdf; | |
436 | + volatile unsigned char *buf; | |
437 | + volatile smc_uart_t *up; | |
438 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
439 | + unsigned char c; | |
440 | + | |
441 | + up = (smc_uart_t *)&(im->im_dprambase[KGDB_PROFF_SMC]); | |
442 | + | |
443 | + rbdf = (cbd_t *)&im->im_dprambase[up->smc_rbase]; | |
444 | + | |
445 | + /* Wait for character to show up. | |
446 | + */ | |
447 | + buf = (unsigned char *)rbdf->cbd_bufaddr; | |
448 | + while (rbdf->cbd_sc & BD_SC_EMPTY) | |
449 | + ; | |
450 | + c = *buf; | |
451 | + rbdf->cbd_sc |= BD_SC_EMPTY; | |
452 | + | |
453 | + return(c); | |
454 | +} | |
455 | + | |
456 | +void | |
457 | +kgdb_interruptible(int yes) | |
458 | +{ | |
459 | + return; | |
460 | +} | |
461 | + | |
462 | +#endif /* CONFIG_KGDB_ON_SMC */ |
cpu/mpc8260/speed.c
1 | +/* | |
2 | + * (C) Copyright 2000-2002 | |
3 | + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | + * | |
5 | + * See file CREDITS for list of people who contributed to this | |
6 | + * project. | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU General Public License as | |
10 | + * published by the Free Software Foundation; either version 2 of | |
11 | + * the License, or (at your option) any later version. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, write to the Free Software | |
20 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | + * MA 02111-1307 USA | |
22 | + */ | |
23 | + | |
24 | +#include <common.h> | |
25 | +#include <mpc8260.h> | |
26 | +#include <asm/processor.h> | |
27 | + | |
28 | +/* ------------------------------------------------------------------------- */ | |
29 | + | |
30 | +/* Bus-to-Core Multiplier */ | |
31 | +#define _1x 2 | |
32 | +#define _1_5x 3 | |
33 | +#define _2x 4 | |
34 | +#define _2_5x 5 | |
35 | +#define _3x 6 | |
36 | +#define _3_5x 7 | |
37 | +#define _4x 8 | |
38 | +#define _4_5x 9 | |
39 | +#define _5x 10 | |
40 | +#define _5_5x 11 | |
41 | +#define _6x 12 | |
42 | +#define _6_5x 13 | |
43 | +#define _7x 14 | |
44 | +#define _7_5x 15 | |
45 | +#define _8x 16 | |
46 | +#define _byp -1 | |
47 | +#define _off -2 | |
48 | +#define _unk -3 | |
49 | + | |
50 | +typedef struct { | |
51 | + int b2c_mult; | |
52 | + int vco_div; | |
53 | + char *freq_60x; | |
54 | + char *freq_core; | |
55 | +} corecnf_t; | |
56 | + | |
57 | +/* | |
58 | + * this table based on "Errata to MPC8260 PowerQUICC II User's Manual", | |
59 | + * Rev. 1, 8/2000, page 10. | |
60 | + */ | |
61 | +corecnf_t corecnf_tab[] = { | |
62 | + { _1_5x, 4, " 33-100", " 33-100" }, /* 0x00 */ | |
63 | + { _1x, 4, " 50-150", " 50-150" }, /* 0x01 */ | |
64 | + { _1x, 8, " 25-75 ", " 25-75 " }, /* 0x02 */ | |
65 | + { _byp, -1, " ?-? ", " ?-? " }, /* 0x03 */ | |
66 | + { _2x, 2, " 50-150", "100-300" }, /* 0x04 */ | |
67 | + { _2x, 4, " 25-75 ", " 50-150" }, /* 0x05 */ | |
68 | + { _2_5x, 2, " 40-120", "100-240" }, /* 0x06 */ | |
69 | + { _4_5x, 2, " 22-65 ", "100-300" }, /* 0x07 */ | |
70 | + { _3x, 2, " 33-100", "100-300" }, /* 0x08 */ | |
71 | + { _5_5x, 2, " 18-55 ", "100-300" }, /* 0x09 */ | |
72 | + { _4x, 2, " 25-75 ", "100-300" }, /* 0x0A */ | |
73 | + { _5x, 2, " 20-60 ", "100-300" }, /* 0x0B */ | |
74 | + { _1_5x, 8, " 16-50 ", " 16-50 " }, /* 0x0C */ | |
75 | + { _6x, 2, " 16-50 ", "100-300" }, /* 0x0D */ | |
76 | + { _3_5x, 2, " 30-85 ", "100-300" }, /* 0x0E */ | |
77 | + { _off, -1, " ?-? ", " ?-? " }, /* 0x0F */ | |
78 | + { _3x, 4, " 16-50 ", " 50-150" }, /* 0x10 */ | |
79 | + { _2_5x, 4, " 20-60 ", " 50-120" }, /* 0x11 */ | |
80 | + { _6_5x, 2, " 15-46 ", "100-300" }, /* 0x12 */ | |
81 | + { _byp, -1, " ?-? ", " ?-? " }, /* 0x13 */ | |
82 | + { _7x, 2, " 14-43 ", "100-300" }, /* 0x14 */ | |
83 | + { _2x, 4, " 25-75 ", " 50-150" }, /* 0x15 */ | |
84 | + { _7_5x, 2, " 13-40 ", "100-300" }, /* 0x16 */ | |
85 | + { _4_5x, 2, " 22-65 ", "100-300" }, /* 0x17 */ | |
86 | + { _unk, -1, " ?-? ", " ?-? " }, /* 0x18 */ | |
87 | + { _5_5x, 2, " 18-55 ", "100-300" }, /* 0x19 */ | |
88 | + { _4x, 2, " 25-75 ", "100-300" }, /* 0x1A */ | |
89 | + { _5x, 2, " 20-60 ", "100-300" }, /* 0x1B */ | |
90 | + { _8x, 2, " 12-38 ", "100-300" }, /* 0x1C */ | |
91 | + { _6x, 2, " 16-50 ", "100-300" }, /* 0x1D */ | |
92 | + { _3_5x, 2, " 30-85 ", "100-300" }, /* 0x1E */ | |
93 | + { _off, -1, " ?-? ", " ?-? " }, /* 0x1F */ | |
94 | +}; | |
95 | + | |
96 | +/* ------------------------------------------------------------------------- */ | |
97 | + | |
98 | +/* | |
99 | + * | |
100 | + */ | |
101 | + | |
102 | +int get_clocks (void) | |
103 | +{ | |
104 | + DECLARE_GLOBAL_DATA_PTR; | |
105 | + | |
106 | + volatile immap_t *immap = (immap_t *) CFG_IMMR; | |
107 | + ulong clkin; | |
108 | + ulong sccr, dfbrg; | |
109 | + ulong scmr, corecnf, busdf, cpmdf, plldf, pllmf; | |
110 | + corecnf_t *cp; | |
111 | + | |
112 | +#if !defined(CONFIG_8260_CLKIN) | |
113 | +#error clock measuring not implemented yet - define CONFIG_8260_CLKIN | |
114 | +#else | |
115 | + clkin = CONFIG_8260_CLKIN; | |
116 | +#endif | |
117 | + | |
118 | + sccr = immap->im_clkrst.car_sccr; | |
119 | + dfbrg = (sccr & SCCR_DFBRG_MSK) >> SCCR_DFBRG_SHIFT; | |
120 | + | |
121 | + scmr = immap->im_clkrst.car_scmr; | |
122 | + corecnf = (scmr & SCMR_CORECNF_MSK) >> SCMR_CORECNF_SHIFT; | |
123 | + busdf = (scmr & SCMR_BUSDF_MSK) >> SCMR_BUSDF_SHIFT; | |
124 | + cpmdf = (scmr & SCMR_CPMDF_MSK) >> SCMR_CPMDF_SHIFT; | |
125 | + plldf = (scmr & SCMR_PLLDF) ? 1 : 0; | |
126 | + pllmf = (scmr & SCMR_PLLMF_MSK) >> SCMR_PLLMF_SHIFT; | |
127 | + | |
128 | + cp = &corecnf_tab[corecnf]; | |
129 | + | |
130 | + gd->vco_out = (clkin * 2 * (pllmf + 1)) / (plldf + 1); | |
131 | + | |
132 | +#if 0 | |
133 | + if (gd->vco_out / (busdf + 1) != clkin) { | |
134 | + /* aaarrrggghhh!!! */ | |
135 | + return (1); | |
136 | + } | |
137 | +#endif | |
138 | + | |
139 | + gd->cpm_clk = gd->vco_out / 2; | |
140 | + gd->bus_clk = clkin; | |
141 | + gd->scc_clk = gd->vco_out / 4; | |
142 | + gd->brg_clk = gd->vco_out / (1 << (2 * (dfbrg + 1))); | |
143 | + | |
144 | + if (cp->b2c_mult > 0) { | |
145 | + gd->cpu_clk = (clkin * cp->b2c_mult) / 2; | |
146 | + } else { | |
147 | + gd->cpu_clk = clkin; | |
148 | + } | |
149 | + | |
150 | + return (0); | |
151 | +} | |
152 | + | |
153 | +int prt_8260_clks (void) | |
154 | +{ | |
155 | + DECLARE_GLOBAL_DATA_PTR; | |
156 | + | |
157 | + volatile immap_t *immap = (immap_t *) CFG_IMMR; | |
158 | + ulong sccr, dfbrg; | |
159 | + ulong scmr, corecnf, busdf, cpmdf, plldf, pllmf; | |
160 | + corecnf_t *cp; | |
161 | + | |
162 | + sccr = immap->im_clkrst.car_sccr; | |
163 | + dfbrg = (sccr & SCCR_DFBRG_MSK) >> SCCR_DFBRG_SHIFT; | |
164 | + | |
165 | + scmr = immap->im_clkrst.car_scmr; | |
166 | + corecnf = (scmr & SCMR_CORECNF_MSK) >> SCMR_CORECNF_SHIFT; | |
167 | + busdf = (scmr & SCMR_BUSDF_MSK) >> SCMR_BUSDF_SHIFT; | |
168 | + cpmdf = (scmr & SCMR_CPMDF_MSK) >> SCMR_CPMDF_SHIFT; | |
169 | + plldf = (scmr & SCMR_PLLDF) ? 1 : 0; | |
170 | + pllmf = (scmr & SCMR_PLLMF_MSK) >> SCMR_PLLMF_SHIFT; | |
171 | + | |
172 | + cp = &corecnf_tab[corecnf]; | |
173 | + | |
174 | + printf ("MPC8260 Clock Configuration\n - Bus-to-Core Mult "); | |
175 | + | |
176 | + switch (cp->b2c_mult) { | |
177 | + case _byp: | |
178 | + printf ("BYPASS"); | |
179 | + break; | |
180 | + | |
181 | + case _off: | |
182 | + printf ("OFF"); | |
183 | + break; | |
184 | + | |
185 | + case _unk: | |
186 | + printf ("UNKNOWN"); | |
187 | + break; | |
188 | + | |
189 | + default: | |
190 | + printf ("%d%sx", | |
191 | + cp->b2c_mult / 2, | |
192 | + (cp->b2c_mult % 2) ? ".5" : ""); | |
193 | + break; | |
194 | + } | |
195 | + | |
196 | + printf (", VCO Div %d, 60x Bus Freq %s, Core Freq %s\n", | |
197 | + cp->vco_div, cp->freq_60x, cp->freq_core); | |
198 | + | |
199 | + printf (" - dfbrg %ld, corecnf 0x%02lx, busdf %ld, cpmdf %ld, " | |
200 | + "plldf %ld, pllmf %ld\n", dfbrg, corecnf, busdf, cpmdf, plldf, | |
201 | + pllmf); | |
202 | + | |
203 | + printf (" - vco_out %10ld, scc_clk %10ld, brg_clk %10ld\n", | |
204 | + gd->vco_out, gd->scc_clk, gd->brg_clk); | |
205 | + | |
206 | + printf (" - cpu_clk %10ld, cpm_clk %10ld, bus_clk %10ld\n\n", | |
207 | + gd->cpu_clk, gd->cpm_clk, gd->bus_clk); | |
208 | + return (0); | |
209 | +} | |
210 | + | |
211 | +/* ------------------------------------------------------------------------- */ |
cpu/mpc8xx/cpu_init.c
1 | +/* | |
2 | + * (C) Copyright 2000-2002 | |
3 | + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | + * | |
5 | + * See file CREDITS for list of people who contributed to this | |
6 | + * project. | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU General Public License as | |
10 | + * published by the Free Software Foundation; either version 2 of | |
11 | + * the License, or (at your option) any later version. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, write to the Free Software | |
20 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | + * MA 02111-1307 USA | |
22 | + */ | |
23 | + | |
24 | +#include <common.h> | |
25 | +#include <watchdog.h> | |
26 | + | |
27 | +#include <mpc8xx.h> | |
28 | +#include <commproc.h> | |
29 | + | |
30 | +#if defined(CFG_I2C_UCODE_PATCH) || defined(CFG_SPI_UCODE_PATCH) | |
31 | +void cpm_load_patch (volatile immap_t * immr); | |
32 | +#endif | |
33 | + | |
34 | +/* | |
35 | + * Breath some life into the CPU... | |
36 | + * | |
37 | + * Set up the memory map, | |
38 | + * initialize a bunch of registers, | |
39 | + * initialize the UPM's | |
40 | + */ | |
41 | +void cpu_init_f (volatile immap_t * immr) | |
42 | +{ | |
43 | +#ifndef CONFIG_MBX | |
44 | + volatile memctl8xx_t *memctl = &immr->im_memctl; | |
45 | + ulong reg; | |
46 | +#endif | |
47 | + | |
48 | + /* SYPCR - contains watchdog control (11-9) */ | |
49 | + | |
50 | + immr->im_siu_conf.sc_sypcr = CFG_SYPCR; | |
51 | + | |
52 | +#if defined(CONFIG_WATCHDOG) | |
53 | + reset_8xx_watchdog (immr); | |
54 | +#endif /* CONFIG_WATCHDOG */ | |
55 | + | |
56 | + /* SIUMCR - contains debug pin configuration (11-6) */ | |
57 | + | |
58 | + immr->im_siu_conf.sc_siumcr |= CFG_SIUMCR; | |
59 | + | |
60 | + /* initialize timebase status and control register (11-26) */ | |
61 | + /* unlock TBSCRK */ | |
62 | + | |
63 | + immr->im_sitk.sitk_tbscrk = KAPWR_KEY; | |
64 | + immr->im_sit.sit_tbscr = CFG_TBSCR; | |
65 | + | |
66 | + /* initialize the PIT (11-31) */ | |
67 | + | |
68 | + immr->im_sitk.sitk_piscrk = KAPWR_KEY; | |
69 | + immr->im_sit.sit_piscr = CFG_PISCR; | |
70 | + | |
71 | + /* PLL (CPU clock) settings (15-30) */ | |
72 | + | |
73 | + immr->im_clkrstk.cark_plprcrk = KAPWR_KEY; | |
74 | + | |
75 | +#ifndef CONFIG_MBX /* MBX board does things different */ | |
76 | + | |
77 | + /* If CFG_PLPRCR (set in the various *_config.h files) tries to | |
78 | + * set the MF field, then just copy CFG_PLPRCR over car_plprcr, | |
79 | + * otherwise OR in CFG_PLPRCR so we do not change the currentMF | |
80 | + * field value. | |
81 | + */ | |
82 | +#if ((CFG_PLPRCR & PLPRCR_MF_MSK) != 0) | |
83 | + reg = CFG_PLPRCR; /* reset control bits */ | |
84 | +#else | |
85 | + reg = immr->im_clkrst.car_plprcr; | |
86 | + reg &= PLPRCR_MF_MSK; /* isolate MF field */ | |
87 | + reg |= CFG_PLPRCR; /* reset control bits */ | |
88 | +#endif | |
89 | + immr->im_clkrst.car_plprcr = reg; | |
90 | + | |
91 | + /* System integration timers. Don't change EBDF! (15-27) */ | |
92 | + | |
93 | + immr->im_clkrstk.cark_sccrk = KAPWR_KEY; | |
94 | + reg = immr->im_clkrst.car_sccr; | |
95 | + reg &= SCCR_MASK; | |
96 | + reg |= CFG_SCCR; | |
97 | + immr->im_clkrst.car_sccr = reg; | |
98 | + | |
99 | + /* | |
100 | + * Memory Controller: | |
101 | + */ | |
102 | + | |
103 | + /* perform BR0 reset that MPC850 Rev. A can't guarantee */ | |
104 | + reg = memctl->memc_br0; | |
105 | + reg &= BR_PS_MSK; /* Clear everything except Port Size bits */ | |
106 | + reg |= BR_V; /* then add just the "Bank Valid" bit */ | |
107 | + memctl->memc_br0 = reg; | |
108 | + | |
109 | + /* Map banks 0 (and maybe 1) to the FLASH banks 0 (and 1) at | |
110 | + * preliminary addresses - these have to be modified later | |
111 | + * when FLASH size has been determined | |
112 | + * | |
113 | + * Depending on the size of the memory region defined by | |
114 | + * CFG_OR0_REMAP some boards (wide address mask) allow to map the | |
115 | + * CFG_MONITOR_BASE, while others (narrower address mask) can't | |
116 | + * map CFG_MONITOR_BASE. | |
117 | + * | |
118 | + * For example, for CONFIG_IVMS8, the CFG_MONITOR_BASE is | |
119 | + * 0xff000000, but CFG_OR0_REMAP's address mask is 0xfff80000. | |
120 | + * | |
121 | + * If BR0 wasn't loaded with address base 0xff000000, then BR0's | |
122 | + * base address remains as 0x00000000. However, the address mask | |
123 | + * have been narrowed to 512Kb, so CFG_MONITOR_BASE wasn't mapped | |
124 | + * into the Bank0. | |
125 | + * | |
126 | + * This is why CONFIG_IVMS8 and similar boards must load BR0 with | |
127 | + * CFG_BR0_PRELIM in advance. | |
128 | + * | |
129 | + * [Thanks to Michael Liao for this explanation. | |
130 | + * I owe him a free beer. - wd] | |
131 | + */ | |
132 | + | |
133 | +#if defined(CONFIG_GTH) || \ | |
134 | + defined(CONFIG_HERMES) || \ | |
135 | + defined(CONFIG_ICU862) || \ | |
136 | + defined(CONFIG_IP860) || \ | |
137 | + defined(CONFIG_IVML24) || \ | |
138 | + defined(CONFIG_IVMS8) || \ | |
139 | + defined(CONFIG_LWMON) || \ | |
140 | + defined(CONFIG_MHPC) || \ | |
141 | + defined(CONFIG_PCU_E) || \ | |
142 | + defined(CONFIG_R360MPI) || \ | |
143 | + defined(CONFIG_RPXCLASSIC) || \ | |
144 | + defined(CONFIG_RPXLITE) || \ | |
145 | + defined(CONFIG_SPD823TS) || \ | |
146 | + (defined(CONFIG_MPC860T) && defined(CONFIG_FADS)) | |
147 | + | |
148 | + memctl->memc_br0 = CFG_BR0_PRELIM; | |
149 | +#endif | |
150 | + | |
151 | +#if defined(CFG_OR0_REMAP) | |
152 | + memctl->memc_or0 = CFG_OR0_REMAP; | |
153 | +#endif | |
154 | +#if defined(CFG_OR1_REMAP) | |
155 | + memctl->memc_or1 = CFG_OR1_REMAP; | |
156 | +#endif | |
157 | +#if defined(CFG_OR5_REMAP) | |
158 | + memctl->memc_or5 = CFG_OR5_REMAP; | |
159 | +#endif | |
160 | + | |
161 | + /* now restrict to preliminary range */ | |
162 | + memctl->memc_br0 = CFG_BR0_PRELIM; | |
163 | + memctl->memc_or0 = CFG_OR0_PRELIM; | |
164 | + | |
165 | +#if (defined(CFG_OR1_PRELIM) && defined(CFG_BR1_PRELIM)) | |
166 | + memctl->memc_or1 = CFG_OR1_PRELIM; | |
167 | + memctl->memc_br1 = CFG_BR1_PRELIM; | |
168 | +#endif | |
169 | + | |
170 | +#if defined(CONFIG_IP860) /* disable CS0 now that Flash is mapped on CS1 */ | |
171 | + memctl->memc_br0 = 0; | |
172 | +#endif | |
173 | + | |
174 | +#if defined(CFG_OR2_PRELIM) && defined(CFG_BR2_PRELIM) | |
175 | + memctl->memc_or2 = CFG_OR2_PRELIM; | |
176 | + memctl->memc_br2 = CFG_BR2_PRELIM; | |
177 | +#endif | |
178 | + | |
179 | +#if defined(CFG_OR3_PRELIM) && defined(CFG_BR3_PRELIM) | |
180 | + memctl->memc_or3 = CFG_OR3_PRELIM; | |
181 | + memctl->memc_br3 = CFG_BR3_PRELIM; | |
182 | +#endif | |
183 | + | |
184 | +#if defined(CFG_OR4_PRELIM) && defined(CFG_BR4_PRELIM) | |
185 | + memctl->memc_or4 = CFG_OR4_PRELIM; | |
186 | + memctl->memc_br4 = CFG_BR4_PRELIM; | |
187 | +#endif | |
188 | + | |
189 | +#if defined(CFG_OR5_PRELIM) && defined(CFG_BR5_PRELIM) | |
190 | + memctl->memc_or5 = CFG_OR5_PRELIM; | |
191 | + memctl->memc_br5 = CFG_BR5_PRELIM; | |
192 | +#endif | |
193 | + | |
194 | +#if defined(CFG_OR6_PRELIM) && defined(CFG_BR6_PRELIM) | |
195 | + memctl->memc_or6 = CFG_OR6_PRELIM; | |
196 | + memctl->memc_br6 = CFG_BR6_PRELIM; | |
197 | +#endif | |
198 | + | |
199 | +#if defined(CFG_OR7_PRELIM) && defined(CFG_BR7_PRELIM) | |
200 | + memctl->memc_or7 = CFG_OR7_PRELIM; | |
201 | + memctl->memc_br7 = CFG_BR7_PRELIM; | |
202 | +#endif | |
203 | + | |
204 | +#endif /* ! CONFIG_MBX */ | |
205 | + | |
206 | + /* | |
207 | + * Reset CPM | |
208 | + */ | |
209 | + immr->im_cpm.cp_cpcr = CPM_CR_RST | CPM_CR_FLG; | |
210 | + do { /* Spin until command processed */ | |
211 | + __asm__ ("eieio"); | |
212 | + } while (immr->im_cpm.cp_cpcr & CPM_CR_FLG); | |
213 | + | |
214 | +#ifdef CONFIG_MBX | |
215 | + /* | |
216 | + * on the MBX, things are a little bit different: | |
217 | + * - we need to read the VPD to get board information | |
218 | + * - the plprcr is set up dynamically | |
219 | + * - the memory controller is set up dynamically | |
220 | + */ | |
221 | + mbx_init (); | |
222 | +#endif /* CONFIG_MBX */ | |
223 | + | |
224 | +#ifdef CONFIG_RPXCLASSIC | |
225 | + rpxclassic_init (); | |
226 | +#endif | |
227 | + | |
228 | +#ifdef CFG_RCCR /* must be done before cpm_load_patch() */ | |
229 | + /* write config value */ | |
230 | + immr->im_cpm.cp_rccr = CFG_RCCR; | |
231 | +#endif | |
232 | + | |
233 | +#if defined(CFG_I2C_UCODE_PATCH) || defined(CFG_SPI_UCODE_PATCH) | |
234 | + cpm_load_patch (immr); /* load mpc8xx microcode patch */ | |
235 | +#endif | |
236 | +} | |
237 | + | |
238 | +/* | |
239 | + * initialize higher level parts of CPU like timers | |
240 | + */ | |
241 | +int cpu_init_r (void) | |
242 | +{ | |
243 | +#if defined(CFG_RTCSC) || defined(CFG_RMDS) | |
244 | + DECLARE_GLOBAL_DATA_PTR; | |
245 | + | |
246 | + bd_t *bd = gd->bd; | |
247 | + volatile immap_t *immr = (volatile immap_t *) (bd->bi_immr_base); | |
248 | +#endif | |
249 | + | |
250 | +#ifdef CFG_RTCSC | |
251 | + /* Unlock RTSC register */ | |
252 | + immr->im_sitk.sitk_rtcsck = KAPWR_KEY; | |
253 | + /* write config value */ | |
254 | + immr->im_sit.sit_rtcsc = CFG_RTCSC; | |
255 | +#endif | |
256 | + | |
257 | +#ifdef CFG_RMDS | |
258 | + /* write config value */ | |
259 | + immr->im_cpm.cp_rmds = CFG_RMDS; | |
260 | +#endif | |
261 | + return (0); | |
262 | +} |
cpu/mpc8xx/serial.c
1 | +/* | |
2 | + * (C) Copyright 2000 | |
3 | + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | + * | |
5 | + * See file CREDITS for list of people who contributed to this | |
6 | + * project. | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU General Public License as | |
10 | + * published by the Free Software Foundation; either version 2 of | |
11 | + * the License, or (at your option) any later version. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, write to the Free Software | |
20 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | + * MA 02111-1307 USA | |
22 | + */ | |
23 | + | |
24 | +#include <common.h> | |
25 | +#include <commproc.h> | |
26 | +#include <command.h> | |
27 | + | |
28 | +#if !defined(CONFIG_8xx_CONS_NONE) /* No Console at all */ | |
29 | + | |
30 | +#if defined(CONFIG_8xx_CONS_SMC1) /* Console on SMC1 */ | |
31 | +#define SMC_INDEX 0 | |
32 | +#undef SCC_INDEX | |
33 | +#define PROFF_SMC PROFF_SMC1 | |
34 | +#define CPM_CR_CH_SMC CPM_CR_CH_SMC1 | |
35 | + | |
36 | +#elif defined(CONFIG_8xx_CONS_SMC2) /* Console on SMC2 */ | |
37 | +#define SMC_INDEX 1 | |
38 | +#undef SCC_INDEX | |
39 | +#define PROFF_SMC PROFF_SMC2 | |
40 | +#define CPM_CR_CH_SMC CPM_CR_CH_SMC2 | |
41 | + | |
42 | +#elif defined(CONFIG_8xx_CONS_SCC1) /* Console on SCC1 */ | |
43 | +#undef SMC_INDEX | |
44 | +#define SCC_INDEX 0 | |
45 | +#define PROFF_SCC PROFF_SCC1 | |
46 | +#define CPM_CR_CH_SCC CPM_CR_CH_SCC1 | |
47 | + | |
48 | +#elif defined(CONFIG_8xx_CONS_SCC2) /* Console on SCC2 */ | |
49 | +#undef SMC_INDEX | |
50 | +#define SCC_INDEX 1 | |
51 | +#define PROFF_SCC PROFF_SCC2 | |
52 | +#define CPM_CR_CH_SCC CPM_CR_CH_SCC2 | |
53 | + | |
54 | +#elif defined(CONFIG_8xx_CONS_SCC3) /* Console on SCC3 */ | |
55 | +#undef SMC_INDEX | |
56 | +#define SCC_INDEX 2 | |
57 | +#define PROFF_SCC PROFF_SCC3 | |
58 | +#define CPM_CR_CH_SCC CPM_CR_CH_SCC3 | |
59 | + | |
60 | +#elif defined(CONFIG_8xx_CONS_SCC4) /* Console on SCC4 */ | |
61 | +#undef SMC_INDEX | |
62 | +#define SCC_INDEX 3 | |
63 | +#define PROFF_SCC PROFF_SCC4 | |
64 | +#define CPM_CR_CH_SCC CPM_CR_CH_SCC4 | |
65 | + | |
66 | +#else /* CONFIG_8xx_CONS_? */ | |
67 | +#error "console not correctly defined" | |
68 | +#endif | |
69 | + | |
70 | +#if (defined (CONFIG_8xx_CONS_SMC1) || defined (CONFIG_8xx_CONS_SMC2)) | |
71 | + | |
72 | +/* | |
73 | + * Minimal serial functions needed to use one of the SMC ports | |
74 | + * as serial console interface. | |
75 | + */ | |
76 | + | |
77 | +int serial_init (void) | |
78 | +{ | |
79 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
80 | + volatile smc_t *sp; | |
81 | + volatile smc_uart_t *up; | |
82 | + volatile cbd_t *tbdf, *rbdf; | |
83 | + volatile cpm8xx_t *cp = &(im->im_cpm); | |
84 | +#if (!defined(CONFIG_8xx_CONS_SMC1)) && (defined(CONFIG_MPC823) || defined(CONFIG_MPC850)) | |
85 | + volatile iop8xx_t *ip = (iop8xx_t *)&(im->im_ioport); | |
86 | +#endif | |
87 | + uint dpaddr; | |
88 | + | |
89 | + /* initialize pointers to SMC */ | |
90 | + | |
91 | + sp = (smc_t *) &(cp->cp_smc[SMC_INDEX]); | |
92 | + up = (smc_uart_t *) &cp->cp_dparam[PROFF_SMC]; | |
93 | + | |
94 | + /* Disable transmitter/receiver. | |
95 | + */ | |
96 | + sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); | |
97 | + | |
98 | + /* Enable SDMA. | |
99 | + */ | |
100 | + im->im_siu_conf.sc_sdcr = 1; | |
101 | + | |
102 | + /* clear error conditions */ | |
103 | +#ifdef CFG_SDSR | |
104 | + im->im_sdma.sdma_sdsr = CFG_SDSR; | |
105 | +#else | |
106 | + im->im_sdma.sdma_sdsr = 0x83; | |
107 | +#endif | |
108 | + | |
109 | + /* clear SDMA interrupt mask */ | |
110 | +#ifdef CFG_SDMR | |
111 | + im->im_sdma.sdma_sdmr = CFG_SDMR; | |
112 | +#else | |
113 | + im->im_sdma.sdma_sdmr = 0x00; | |
114 | +#endif | |
115 | + | |
116 | +#if defined(CONFIG_8xx_CONS_SMC1) | |
117 | + /* Use Port B for SMC1 instead of other functions. | |
118 | + */ | |
119 | + cp->cp_pbpar |= 0x000000c0; | |
120 | + cp->cp_pbdir &= ~0x000000c0; | |
121 | + cp->cp_pbodr &= ~0x000000c0; | |
122 | +#else /* CONFIG_8xx_CONS_SMC2 */ | |
123 | +# if defined(CONFIG_MPC823) || defined(CONFIG_MPC850) | |
124 | + /* Use Port A for SMC2 instead of other functions. | |
125 | + */ | |
126 | + ip->iop_papar |= 0x00c0; | |
127 | + ip->iop_padir &= ~0x00c0; | |
128 | + ip->iop_paodr &= ~0x00c0; | |
129 | +# else /* must be a 860 then */ | |
130 | + /* Use Port B for SMC2 instead of other functions. | |
131 | + */ | |
132 | + cp->cp_pbpar |= 0x00000c00; | |
133 | + cp->cp_pbdir &= ~0x00000c00; | |
134 | + cp->cp_pbodr &= ~0x00000c00; | |
135 | +# endif | |
136 | +#endif | |
137 | + | |
138 | +#if defined(CONFIG_FADS) | |
139 | + /* Enable RS232 */ | |
140 | +#if defined(CONFIG_8xx_CONS_SMC1) | |
141 | + *((uint *) BCSR1) &= ~BCSR1_RS232EN_1; | |
142 | +#else | |
143 | + *((uint *) BCSR1) &= ~BCSR1_RS232EN_2; | |
144 | +#endif | |
145 | +#endif /* CONFIG_FADS */ | |
146 | + | |
147 | +#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) | |
148 | + /* Enable Monitor Port Transceiver */ | |
149 | + *((uchar *) BCSR0) |= BCSR0_ENMONXCVR ; | |
150 | +#endif /* CONFIG_RPXLITE */ | |
151 | + | |
152 | + /* Set the physical address of the host memory buffers in | |
153 | + * the buffer descriptors. | |
154 | + */ | |
155 | + | |
156 | +#ifdef CFG_ALLOC_DPRAM | |
157 | + dpaddr = dpram_alloc_align (sizeof(cbd_t)*2 + 2, 8) ; | |
158 | +#else | |
159 | + dpaddr = CPM_SERIAL_BASE ; | |
160 | +#endif | |
161 | + | |
162 | + /* Allocate space for two buffer descriptors in the DP ram. | |
163 | + * For now, this address seems OK, but it may have to | |
164 | + * change with newer versions of the firmware. | |
165 | + * damm: allocating space after the two buffers for rx/tx data | |
166 | + */ | |
167 | + | |
168 | + rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; | |
169 | + rbdf->cbd_bufaddr = (uint) (rbdf+2); | |
170 | + rbdf->cbd_sc = 0; | |
171 | + tbdf = rbdf + 1; | |
172 | + tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1; | |
173 | + tbdf->cbd_sc = 0; | |
174 | + | |
175 | + /* Set up the uart parameters in the parameter ram. | |
176 | + */ | |
177 | + up->smc_rbase = dpaddr; | |
178 | + up->smc_tbase = dpaddr+sizeof(cbd_t); | |
179 | + up->smc_rfcr = SMC_EB; | |
180 | + up->smc_tfcr = SMC_EB; | |
181 | + | |
182 | +#if defined(CONFIG_MBX) | |
183 | + board_serial_init(); | |
184 | +#endif /* CONFIG_MBX */ | |
185 | + | |
186 | + /* Set UART mode, 8 bit, no parity, one stop. | |
187 | + * Enable receive and transmit. | |
188 | + */ | |
189 | + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; | |
190 | + | |
191 | + /* Mask all interrupts and remove anything pending. | |
192 | + */ | |
193 | + sp->smc_smcm = 0; | |
194 | + sp->smc_smce = 0xff; | |
195 | + | |
196 | + /* Set up the baud rate generator. | |
197 | + */ | |
198 | + serial_setbrg (); | |
199 | + | |
200 | + /* Make the first buffer the only buffer. | |
201 | + */ | |
202 | + tbdf->cbd_sc |= BD_SC_WRAP; | |
203 | + rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; | |
204 | + | |
205 | + /* Single character receive. | |
206 | + */ | |
207 | + up->smc_mrblr = 1; | |
208 | + up->smc_maxidl = 0; | |
209 | + | |
210 | + /* Initialize Tx/Rx parameters. | |
211 | + */ | |
212 | + | |
213 | + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ | |
214 | + ; | |
215 | + | |
216 | + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC, CPM_CR_INIT_TRX) | CPM_CR_FLG; | |
217 | + | |
218 | + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ | |
219 | + ; | |
220 | + | |
221 | + /* Enable transmitter/receiver. | |
222 | + */ | |
223 | + sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; | |
224 | + | |
225 | + return (0); | |
226 | +} | |
227 | + | |
228 | +void | |
229 | +serial_setbrg (void) | |
230 | +{ | |
231 | + DECLARE_GLOBAL_DATA_PTR; | |
232 | + | |
233 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
234 | + volatile cpm8xx_t *cp = &(im->im_cpm); | |
235 | + | |
236 | + /* Set up the baud rate generator. | |
237 | + * See 8xx_io/commproc.c for details. | |
238 | + * | |
239 | + * Wire BRG1 to SMCx | |
240 | + */ | |
241 | + | |
242 | + cp->cp_simode = 0x00000000; | |
243 | + | |
244 | + cp->cp_brgc1 = | |
245 | + (((gd->cpu_clk / 16 / gd->baudrate)-1) << 1) | CPM_BRG_EN; | |
246 | +} | |
247 | + | |
248 | +void | |
249 | +serial_putc(const char c) | |
250 | +{ | |
251 | + volatile cbd_t *tbdf; | |
252 | + volatile char *buf; | |
253 | + volatile smc_uart_t *up; | |
254 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
255 | + volatile cpm8xx_t *cpmp = &(im->im_cpm); | |
256 | + | |
257 | + if (c == '\n') | |
258 | + serial_putc ('\r'); | |
259 | + | |
260 | + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC]; | |
261 | + | |
262 | + tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase]; | |
263 | + | |
264 | + /* Wait for last character to go. | |
265 | + */ | |
266 | + | |
267 | + buf = (char *)tbdf->cbd_bufaddr; | |
268 | +#if 0 | |
269 | + __asm__("eieio"); | |
270 | + while (tbdf->cbd_sc & BD_SC_READY) | |
271 | + __asm__("eieio"); | |
272 | +#endif | |
273 | + | |
274 | + *buf = c; | |
275 | + tbdf->cbd_datlen = 1; | |
276 | + tbdf->cbd_sc |= BD_SC_READY; | |
277 | + __asm__("eieio"); | |
278 | +#if 1 | |
279 | + while (tbdf->cbd_sc & BD_SC_READY) | |
280 | + __asm__("eieio"); | |
281 | +#endif | |
282 | +} | |
283 | + | |
284 | +int | |
285 | +serial_getc(void) | |
286 | +{ | |
287 | + volatile cbd_t *rbdf; | |
288 | + volatile unsigned char *buf; | |
289 | + volatile smc_uart_t *up; | |
290 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
291 | + volatile cpm8xx_t *cpmp = &(im->im_cpm); | |
292 | + unsigned char c; | |
293 | + | |
294 | + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC]; | |
295 | + | |
296 | + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; | |
297 | + | |
298 | + /* Wait for character to show up. | |
299 | + */ | |
300 | + buf = (unsigned char *)rbdf->cbd_bufaddr; | |
301 | + while (rbdf->cbd_sc & BD_SC_EMPTY) | |
302 | + ; | |
303 | + c = *buf; | |
304 | + rbdf->cbd_sc |= BD_SC_EMPTY; | |
305 | + | |
306 | + return(c); | |
307 | +} | |
308 | + | |
309 | +int | |
310 | +serial_tstc() | |
311 | +{ | |
312 | + volatile cbd_t *rbdf; | |
313 | + volatile smc_uart_t *up; | |
314 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
315 | + volatile cpm8xx_t *cpmp = &(im->im_cpm); | |
316 | + | |
317 | + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC]; | |
318 | + | |
319 | + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; | |
320 | + | |
321 | + return(!(rbdf->cbd_sc & BD_SC_EMPTY)); | |
322 | +} | |
323 | + | |
324 | +#else /* ! CONFIG_8xx_CONS_SMC1, CONFIG_8xx_CONS_SMC2 */ | |
325 | + | |
326 | +int serial_init (void) | |
327 | +{ | |
328 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
329 | + volatile scc_t *sp; | |
330 | + volatile scc_uart_t *up; | |
331 | + volatile cbd_t *tbdf, *rbdf; | |
332 | + volatile cpm8xx_t *cp = &(im->im_cpm); | |
333 | + uint dpaddr; | |
334 | +#if (SCC_INDEX != 2) || !defined(CONFIG_MPC850) | |
335 | + volatile iop8xx_t *ip = (iop8xx_t *)&(im->im_ioport); | |
336 | +#endif | |
337 | + | |
338 | + /* initialize pointers to SCC */ | |
339 | + | |
340 | + sp = (scc_t *) &(cp->cp_scc[SCC_INDEX]); | |
341 | + up = (scc_uart_t *) &cp->cp_dparam[PROFF_SCC]; | |
342 | + | |
343 | +#if defined(CONFIG_LWMON) && defined(CONFIG_8xx_CONS_SCC2) | |
344 | + { /* Disable Ethernet, enable Serial */ | |
345 | + uchar c; | |
346 | + | |
347 | + c = pic_read (0x61); | |
348 | + c &= ~0x40; /* enable COM3 */ | |
349 | + c |= 0x80; /* disable Ethernet */ | |
350 | + pic_write (0x61, c); | |
351 | + | |
352 | + /* enable RTS2 */ | |
353 | + cp->cp_pbpar |= 0x2000; | |
354 | + cp->cp_pbdat |= 0x2000; | |
355 | + cp->cp_pbdir |= 0x2000; | |
356 | + } | |
357 | +#endif /* CONFIG_LWMON */ | |
358 | + | |
359 | + /* Disable transmitter/receiver. | |
360 | + */ | |
361 | + sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); | |
362 | + | |
363 | +#if (SCC_INDEX == 2) && defined(CONFIG_MPC850) | |
364 | + /* | |
365 | + * The MPC850 has SCC3 on Port B | |
366 | + */ | |
367 | + cp->cp_pbpar |= 0x06; | |
368 | + cp->cp_pbdir &= ~0x06; | |
369 | + cp->cp_pbodr &= ~0x06; | |
370 | + | |
371 | +#elif (SCC_INDEX < 2) || !defined(CONFIG_IP860) | |
372 | + /* | |
373 | + * Standard configuration for SCC's is on Part A | |
374 | + */ | |
375 | + ip->iop_papar |= ((3 << (2 * SCC_INDEX))); | |
376 | + ip->iop_padir &= ~((3 << (2 * SCC_INDEX))); | |
377 | + ip->iop_paodr &= ~((3 << (2 * SCC_INDEX))); | |
378 | +#else | |
379 | + /* | |
380 | + * The IP860 has SCC3 and SCC4 on Port D | |
381 | + */ | |
382 | + ip->iop_pdpar |= ((3 << (2 * SCC_INDEX))); | |
383 | +#endif | |
384 | + | |
385 | + /* Allocate space for two buffer descriptors in the DP ram. | |
386 | + */ | |
387 | + | |
388 | +#ifdef CFG_ALLOC_DPRAM | |
389 | + dpaddr = dpram_alloc_align (sizeof(cbd_t)*2 + 2, 8) ; | |
390 | +#else | |
391 | + dpaddr = CPM_SERIAL_BASE ; | |
392 | +#endif | |
393 | + | |
394 | + /* Enable SDMA. | |
395 | + */ | |
396 | + im->im_siu_conf.sc_sdcr = 0x0001; | |
397 | + | |
398 | + /* Set the physical address of the host memory buffers in | |
399 | + * the buffer descriptors. | |
400 | + */ | |
401 | + | |
402 | + rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; | |
403 | + rbdf->cbd_bufaddr = (uint) (rbdf+2); | |
404 | + rbdf->cbd_sc = 0; | |
405 | + tbdf = rbdf + 1; | |
406 | + tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1; | |
407 | + tbdf->cbd_sc = 0; | |
408 | + | |
409 | + /* Set up the baud rate generator. | |
410 | + */ | |
411 | + serial_setbrg (); | |
412 | + | |
413 | + /* Set up the uart parameters in the parameter ram. | |
414 | + */ | |
415 | + up->scc_genscc.scc_rbase = dpaddr; | |
416 | + up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t); | |
417 | + | |
418 | + /* Initialize Tx/Rx parameters. | |
419 | + */ | |
420 | + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ | |
421 | + ; | |
422 | + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC, CPM_CR_INIT_TRX) | CPM_CR_FLG; | |
423 | + | |
424 | + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ | |
425 | + ; | |
426 | + | |
427 | + up->scc_genscc.scc_rfcr = SCC_EB | 0x05; | |
428 | + up->scc_genscc.scc_tfcr = SCC_EB | 0x05; | |
429 | + | |
430 | + up->scc_genscc.scc_mrblr = 1; /* Single character receive */ | |
431 | + up->scc_maxidl = 0; /* disable max idle */ | |
432 | + up->scc_brkcr = 1; /* send one break character on stop TX */ | |
433 | + up->scc_parec = 0; | |
434 | + up->scc_frmec = 0; | |
435 | + up->scc_nosec = 0; | |
436 | + up->scc_brkec = 0; | |
437 | + up->scc_uaddr1 = 0; | |
438 | + up->scc_uaddr2 = 0; | |
439 | + up->scc_toseq = 0; | |
440 | + up->scc_char1 = 0x8000; | |
441 | + up->scc_char2 = 0x8000; | |
442 | + up->scc_char3 = 0x8000; | |
443 | + up->scc_char4 = 0x8000; | |
444 | + up->scc_char5 = 0x8000; | |
445 | + up->scc_char6 = 0x8000; | |
446 | + up->scc_char7 = 0x8000; | |
447 | + up->scc_char8 = 0x8000; | |
448 | + up->scc_rccm = 0xc0ff; | |
449 | + | |
450 | + /* Set low latency / small fifo. | |
451 | + */ | |
452 | + sp->scc_gsmrh = SCC_GSMRH_RFW; | |
453 | + | |
454 | + /* Set SCC(x) clock mode to 16x | |
455 | + * See 8xx_io/commproc.c for details. | |
456 | + * | |
457 | + * Wire BRG1 to SCCn | |
458 | + */ | |
459 | + | |
460 | + /* Set UART mode, clock divider 16 on Tx and Rx | |
461 | + */ | |
462 | + sp->scc_gsmrl |= | |
463 | + (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); | |
464 | + | |
465 | + sp->scc_psmr |= SCU_PSMR_CL; | |
466 | + | |
467 | + /* Mask all interrupts and remove anything pending. | |
468 | + */ | |
469 | + sp->scc_sccm = 0; | |
470 | + sp->scc_scce = 0xffff; | |
471 | + sp->scc_dsr = 0x7e7e; | |
472 | + sp->scc_psmr = 0x3000; | |
473 | + | |
474 | + /* Make the first buffer the only buffer. | |
475 | + */ | |
476 | + tbdf->cbd_sc |= BD_SC_WRAP; | |
477 | + rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; | |
478 | + | |
479 | + /* Enable transmitter/receiver. | |
480 | + */ | |
481 | + sp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); | |
482 | + | |
483 | + return (0); | |
484 | +} | |
485 | + | |
486 | +void | |
487 | +serial_setbrg (void) | |
488 | +{ | |
489 | + DECLARE_GLOBAL_DATA_PTR; | |
490 | + | |
491 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
492 | + volatile cpm8xx_t *cp = &(im->im_cpm); | |
493 | + | |
494 | + /* Set up the baud rate generator. | |
495 | + * See 8xx_io/commproc.c for details. | |
496 | + * | |
497 | + * Wire BRG1 to SCCx | |
498 | + */ | |
499 | + | |
500 | + cp->cp_sicr &= ~(0x000000FF << (8 * SCC_INDEX)); | |
501 | + /* no |= needed, since BRG1 is 000 */ | |
502 | + | |
503 | + cp->cp_brgc1 = | |
504 | + (((gd->cpu_clk / 16 / gd->baudrate)-1) << 1) | CPM_BRG_EN; | |
505 | +} | |
506 | + | |
507 | +void | |
508 | +serial_putc(const char c) | |
509 | +{ | |
510 | + volatile cbd_t *tbdf; | |
511 | + volatile char *buf; | |
512 | + volatile scc_uart_t *up; | |
513 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
514 | + volatile cpm8xx_t *cpmp = &(im->im_cpm); | |
515 | + | |
516 | + if (c == '\n') | |
517 | + serial_putc ('\r'); | |
518 | + | |
519 | + up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC]; | |
520 | + | |
521 | + tbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_tbase]; | |
522 | + | |
523 | + /* Wait for last character to go. | |
524 | + */ | |
525 | + | |
526 | + buf = (char *)tbdf->cbd_bufaddr; | |
527 | +#if 0 | |
528 | + __asm__("eieio"); | |
529 | + while (tbdf->cbd_sc & BD_SC_READY) | |
530 | + __asm__("eieio"); | |
531 | +#endif | |
532 | + | |
533 | + *buf = c; | |
534 | + tbdf->cbd_datlen = 1; | |
535 | + tbdf->cbd_sc |= BD_SC_READY; | |
536 | + __asm__("eieio"); | |
537 | +#if 1 | |
538 | + while (tbdf->cbd_sc & BD_SC_READY) | |
539 | + __asm__("eieio"); | |
540 | +#endif | |
541 | +} | |
542 | + | |
543 | +int | |
544 | +serial_getc(void) | |
545 | +{ | |
546 | + volatile cbd_t *rbdf; | |
547 | + volatile unsigned char *buf; | |
548 | + volatile scc_uart_t *up; | |
549 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
550 | + volatile cpm8xx_t *cpmp = &(im->im_cpm); | |
551 | + unsigned char c; | |
552 | + | |
553 | + up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC]; | |
554 | + | |
555 | + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_rbase]; | |
556 | + | |
557 | + /* Wait for character to show up. | |
558 | + */ | |
559 | + buf = (unsigned char *)rbdf->cbd_bufaddr; | |
560 | + while (rbdf->cbd_sc & BD_SC_EMPTY) | |
561 | + ; | |
562 | + c = *buf; | |
563 | + rbdf->cbd_sc |= BD_SC_EMPTY; | |
564 | + | |
565 | + return(c); | |
566 | +} | |
567 | + | |
568 | +int | |
569 | +serial_tstc() | |
570 | +{ | |
571 | + volatile cbd_t *rbdf; | |
572 | + volatile scc_uart_t *up; | |
573 | + volatile immap_t *im = (immap_t *)CFG_IMMR; | |
574 | + volatile cpm8xx_t *cpmp = &(im->im_cpm); | |
575 | + | |
576 | + up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC]; | |
577 | + | |
578 | + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_rbase]; | |
579 | + | |
580 | + return(!(rbdf->cbd_sc & BD_SC_EMPTY)); | |
581 | +} | |
582 | + | |
583 | +#endif /* CONFIG_8xx_CONS_SMC1, CONFIG_8xx_CONS_SMC2 */ | |
584 | + | |
585 | + | |
586 | +void | |
587 | +serial_puts (const char *s) | |
588 | +{ | |
589 | + while (*s) { | |
590 | + serial_putc (*s++); | |
591 | + } | |
592 | +} | |
593 | + | |
594 | + | |
595 | +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) | |
596 | + | |
597 | +void | |
598 | +kgdb_serial_init(void) | |
599 | +{ | |
600 | +#if defined(CONFIG_8xx_CONS_SMC1) | |
601 | + serial_printf("[on SMC1] "); | |
602 | +#elif defined(CONFIG_8xx_CONS_SMC2) | |
603 | + serial_printf("[on SMC2] "); | |
604 | +#elif defined(CONFIG_8xx_CONS_SCC1) | |
605 | + serial_printf("[on SCC1] "); | |
606 | +#elif defined(CONFIG_8xx_CONS_SCC2) | |
607 | + serial_printf("[on SCC2] "); | |
608 | +#elif defined(CONFIG_8xx_CONS_SCC3) | |
609 | + serial_printf("[on SCC3] "); | |
610 | +#elif defined(CONFIG_8xx_CONS_SCC4) | |
611 | + serial_printf("[on SCC4] "); | |
612 | +#endif | |
613 | +} | |
614 | + | |
615 | +void | |
616 | +putDebugChar (int c) | |
617 | +{ | |
618 | + serial_putc (c); | |
619 | +} | |
620 | + | |
621 | +void | |
622 | +putDebugStr (const char *str) | |
623 | +{ | |
624 | + serial_puts (str); | |
625 | +} | |
626 | + | |
627 | +int | |
628 | +getDebugChar (void) | |
629 | +{ | |
630 | + return serial_getc(); | |
631 | +} | |
632 | + | |
633 | +void | |
634 | +kgdb_interruptible (int yes) | |
635 | +{ | |
636 | + return; | |
637 | +} | |
638 | +#endif /* CFG_CMD_KGDB */ | |
639 | + | |
640 | +#endif /* CONFIG_8xx_CONS_NONE */ |
cpu/mpc8xx/speed.c
1 | +/* | |
2 | + * (C) Copyright 2000-2002 | |
3 | + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | + * | |
5 | + * See file CREDITS for list of people who contributed to this | |
6 | + * project. | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU General Public License as | |
10 | + * published by the Free Software Foundation; either version 2 of | |
11 | + * the License, or (at your option) any later version. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, write to the Free Software | |
20 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | + * MA 02111-1307 USA | |
22 | + */ | |
23 | + | |
24 | +#include <common.h> | |
25 | +#include <mpc8xx.h> | |
26 | +#include <asm/processor.h> | |
27 | + | |
28 | +#define PITC_SHIFT 16 | |
29 | +#define PITR_SHIFT 16 | |
30 | +/* pitc values to time for 58/8192 seconds (about 70.8 milliseconds) */ | |
31 | +#define SPEED_PIT_COUNTS 58 | |
32 | +#define SPEED_PITC ((SPEED_PIT_COUNTS - 1) << PITC_SHIFT) | |
33 | +#define SPEED_PITC_INIT ((SPEED_PIT_COUNTS + 1) << PITC_SHIFT) | |
34 | + | |
35 | +#if !defined(CONFIG_8xx_GCLK_FREQ) | |
36 | +/* Access functions for the Machine State Register */ | |
37 | +static __inline__ unsigned long get_msr(void) | |
38 | +{ | |
39 | + unsigned long msr; | |
40 | + | |
41 | + asm volatile("mfmsr %0" : "=r" (msr) :); | |
42 | + return msr; | |
43 | +} | |
44 | + | |
45 | +static __inline__ void set_msr(unsigned long msr) | |
46 | +{ | |
47 | + asm volatile("mtmsr %0" : : "r" (msr)); | |
48 | +} | |
49 | +#endif | |
50 | + | |
51 | +/* ------------------------------------------------------------------------- */ | |
52 | + | |
53 | +/* | |
54 | + * Measure CPU clock speed (core clock GCLK1, GCLK2), | |
55 | + * also determine bus clock speed (checking bus divider factor) | |
56 | + * | |
57 | + * (Approx. GCLK frequency in Hz) | |
58 | + * | |
59 | + * Initializes timer 2 and PIT, but disables them before return. | |
60 | + * [Use timer 2, because MPC823 CPUs mask 0.x do not have timers 3 and 4] | |
61 | + * | |
62 | + * When measuring the CPU clock against the PIT, we count cpu clocks | |
63 | + * for 58/8192 seconds with a prescale divide by 177 for the cpu clock. | |
64 | + * These strange values for the timing interval and prescaling are used | |
65 | + * because the formula for the CPU clock is: | |
66 | + * | |
67 | + * CPU clock = count * (177 * (8192 / 58)) | |
68 | + * | |
69 | + * = count * 24999.7241 | |
70 | + * | |
71 | + * which is very close to | |
72 | + * | |
73 | + * = count * 25000 | |
74 | + * | |
75 | + * Since the count gives the CPU clock divided by 25000, we can get | |
76 | + * the CPU clock rounded to the nearest 0.1 MHz by | |
77 | + * | |
78 | + * CPU clock = ((count + 2) / 4) * 100000; | |
79 | + * | |
80 | + * The rounding is important since the measurement is sometimes going | |
81 | + * to be high or low by 0.025 MHz, depending on exactly how the clocks | |
82 | + * and counters interact. By rounding we get the exact answer for any | |
83 | + * CPU clock that is an even multiple of 0.1 MHz. | |
84 | + */ | |
85 | + | |
86 | +int get_clocks (void) | |
87 | +{ | |
88 | + DECLARE_GLOBAL_DATA_PTR; | |
89 | + | |
90 | + volatile immap_t *immr = (immap_t *) CFG_IMMR; | |
91 | +#ifndef CONFIG_8xx_GCLK_FREQ | |
92 | + volatile cpmtimer8xx_t *timerp = &immr->im_cpmtimer; | |
93 | + ulong timer2_val; | |
94 | + ulong msr_val; | |
95 | + | |
96 | + /* Reset + Stop Timer 2, no cascading | |
97 | + */ | |
98 | + timerp->cpmt_tgcr &= ~(TGCR_CAS2 | TGCR_RST2); | |
99 | + | |
100 | + /* Keep stopped, halt in debug mode | |
101 | + */ | |
102 | + timerp->cpmt_tgcr |= (TGCR_FRZ2 | TGCR_STP2); | |
103 | + | |
104 | + /* Timer 2 setup: | |
105 | + * Output ref. interrupt disable, int. clock | |
106 | + * Prescale by 177. Note that prescaler divides by value + 1 | |
107 | + * so we must subtract 1 here. | |
108 | + */ | |
109 | + timerp->cpmt_tmr2 = ((177 - 1) << TMR_PS_SHIFT) | TMR_ICLK_IN_GEN; | |
110 | + | |
111 | + timerp->cpmt_tcn2 = 0; /* reset state */ | |
112 | + timerp->cpmt_tgcr |= TGCR_RST2; /* enable timer 2 */ | |
113 | + | |
114 | + /* | |
115 | + * PIT setup: | |
116 | + * | |
117 | + * We want to time for SPEED_PITC_COUNTS counts (of 8192 Hz), | |
118 | + * so the count value would be SPEED_PITC_COUNTS - 1. | |
119 | + * But there would be an uncertainty in the start time of 1/4 | |
120 | + * count since when we enable the PIT the count is not | |
121 | + * synchronized to the 32768 Hz oscillator. The trick here is | |
122 | + * to start the count higher and wait until the PIT count | |
123 | + * changes to the required value before starting timer 2. | |
124 | + * | |
125 | + * One count high should be enough, but occasionally the start | |
126 | + * is off by 1 or 2 counts of 32768 Hz. With the start value | |
127 | + * set two counts high it seems very reliable. | |
128 | + */ | |
129 | + | |
130 | + immr->im_sitk.sitk_pitck = KAPWR_KEY; /* PIT initialization */ | |
131 | + immr->im_sit.sit_pitc = SPEED_PITC_INIT; | |
132 | + | |
133 | + immr->im_sitk.sitk_piscrk = KAPWR_KEY; | |
134 | + immr->im_sit.sit_piscr = CFG_PISCR; | |
135 | + | |
136 | + /* | |
137 | + * Start measurement - disable interrupts, just in case | |
138 | + */ | |
139 | + msr_val = get_msr (); | |
140 | + set_msr (msr_val & ~MSR_EE); | |
141 | + | |
142 | + immr->im_sit.sit_piscr |= PISCR_PTE; | |
143 | + | |
144 | + /* spin until get exact count when we want to start */ | |
145 | + while (immr->im_sit.sit_pitr > SPEED_PITC); | |
146 | + | |
147 | + timerp->cpmt_tgcr &= ~TGCR_STP2; /* Start Timer 2 */ | |
148 | + while ((immr->im_sit.sit_piscr & PISCR_PS) == 0); | |
149 | + timerp->cpmt_tgcr |= TGCR_STP2; /* Stop Timer 2 */ | |
150 | + | |
151 | + /* re-enable external interrupts if they were on */ | |
152 | + set_msr (msr_val); | |
153 | + | |
154 | + /* Disable timer and PIT | |
155 | + */ | |
156 | + timer2_val = timerp->cpmt_tcn2; /* save before reset timer */ | |
157 | + | |
158 | + timerp->cpmt_tgcr &= ~(TGCR_RST2 | TGCR_FRZ2 | TGCR_STP2); | |
159 | + immr->im_sit.sit_piscr &= ~PISCR_PTE; | |
160 | + | |
161 | + gd->cpu_clk = ((timer2_val + 2) / 4) * 100000L; /* convert to Hz */ | |
162 | + | |
163 | +#else /* CONFIG_8xx_GCLK_FREQ */ | |
164 | + | |
165 | + /* | |
166 | + * If for some reason measuring the gclk frequency won't | |
167 | + * work, we return the hardwired value. | |
168 | + * (For example, the cogent CMA286-60 CPU module has no | |
169 | + * separate oscillator for PITRTCLK) | |
170 | + */ | |
171 | + | |
172 | + gd->cpu_clk = CONFIG_8xx_GCLK_FREQ; | |
173 | + | |
174 | +#endif /* CONFIG_8xx_GCLK_FREQ */ | |
175 | + | |
176 | + if ((immr->im_clkrst.car_sccr & SCCR_EBDF11) == 0) { | |
177 | + /* No Bus Divider active */ | |
178 | + gd->bus_clk = gd->cpu_clk; | |
179 | + } else { | |
180 | + /* The MPC8xx has only one BDF: half clock speed */ | |
181 | + gd->bus_clk = gd->cpu_clk / 2; | |
182 | + } | |
183 | + | |
184 | + return (0); | |
185 | +} | |
186 | + | |
187 | +/* ------------------------------------------------------------------------- */ |
cpu/mpc8xx/wlkbd.c
1 | +/* | |
2 | + * (C) Copyright 2000 | |
3 | + * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it | |
4 | + * | |
5 | + * See file CREDITS for list of people who contributed to this | |
6 | + * project. | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU General Public License as | |
10 | + * published by the Free Software Foundation; either version 2 of | |
11 | + * the License, or (at your option) any later version. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, write to the Free Software | |
20 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | + * MA 02111-1307 USA | |
22 | + */ | |
23 | + | |
24 | +#include <common.h> | |
25 | +#include <config.h> | |
26 | + | |
27 | +#ifdef CONFIG_WL_4PPM_KEYBOARD | |
28 | + | |
29 | +/* WIP: Wireless keyboard on SMC | |
30 | + */ | |
31 | +int drv_wlkbd_init (void) | |
32 | +{ | |
33 | + return 0 ; | |
34 | +} | |
35 | + | |
36 | +#endif /* CONFIG_WL_4PPM_KEYBOARD */ |
cpu/ppc4xx/cpu_init.c
1 | +/* | |
2 | + * (C) Copyright 2000 | |
3 | + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | + * | |
5 | + * See file CREDITS for list of people who contributed to this | |
6 | + * project. | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU General Public License as | |
10 | + * published by the Free Software Foundation; either version 2 of | |
11 | + * the License, or (at your option) any later version. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, write to the Free Software | |
20 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | + * MA 02111-1307 USA | |
22 | + */ | |
23 | + | |
24 | +#include <common.h> | |
25 | +#include <watchdog.h> | |
26 | +#include <405gp_enet.h> | |
27 | +#include <asm/processor.h> | |
28 | +#include <ppc4xx.h> | |
29 | + | |
30 | + | |
31 | +#define mtebc(reg, data) mtdcr(ebccfga,reg);mtdcr(ebccfgd,data) | |
32 | + | |
33 | + | |
34 | +/* | |
35 | + * Breath some life into the CPU... | |
36 | + * | |
37 | + * Set up the memory map, | |
38 | + * initialize a bunch of registers | |
39 | + */ | |
40 | +void | |
41 | +cpu_init_f (void) | |
42 | +{ | |
43 | + /* | |
44 | + * External Bus Controller (EBC) Setup | |
45 | + */ | |
46 | +#if (defined(CFG_EBC_PB0AP) && defined(CFG_EBC_PB0CR)) | |
47 | + /* | |
48 | + * Move the next instructions into icache, since these modify the flash | |
49 | + * we are running from! | |
50 | + */ | |
51 | + asm volatile(" bl 0f" ::: "lr"); | |
52 | + asm volatile("0: mflr 3" ::: "r3"); | |
53 | + asm volatile(" addi 4, 0, 14" ::: "r4"); | |
54 | + asm volatile(" mtctr 4" ::: "ctr"); | |
55 | + asm volatile("1: icbt 0, 3"); | |
56 | + asm volatile(" addi 3, 3, 32" ::: "r3"); | |
57 | + asm volatile(" bdnz 1b" ::: "ctr", "cr0"); | |
58 | + asm volatile(" addis 3, 0, 0x0" ::: "r3"); | |
59 | + asm volatile(" ori 3, 3, 0xA000" ::: "r3"); | |
60 | + asm volatile(" mtctr 3" ::: "ctr"); | |
61 | + asm volatile("2: bdnz 2b" ::: "ctr", "cr0"); | |
62 | + | |
63 | + mtebc(pb0ap, CFG_EBC_PB0AP); | |
64 | + mtebc(pb0cr, CFG_EBC_PB0CR); | |
65 | +#endif | |
66 | + | |
67 | +#if (defined(CFG_EBC_PB1AP) && defined(CFG_EBC_PB1CR)) | |
68 | + mtebc(pb1ap, CFG_EBC_PB1AP); | |
69 | + mtebc(pb1cr, CFG_EBC_PB1CR); | |
70 | +#endif | |
71 | + | |
72 | +#if (defined(CFG_EBC_PB2AP) && defined(CFG_EBC_PB2CR)) | |
73 | + mtebc(pb2ap, CFG_EBC_PB2AP); | |
74 | + mtebc(pb2cr, CFG_EBC_PB2CR); | |
75 | +#endif | |
76 | + | |
77 | +#if (defined(CFG_EBC_PB3AP) && defined(CFG_EBC_PB3CR)) | |
78 | + mtebc(pb3ap, CFG_EBC_PB3AP); | |
79 | + mtebc(pb3cr, CFG_EBC_PB3CR); | |
80 | +#endif | |
81 | + | |
82 | +#if (defined(CFG_EBC_PB4AP) && defined(CFG_EBC_PB4CR)) | |
83 | + mtebc(pb4ap, CFG_EBC_PB4AP); | |
84 | + mtebc(pb4cr, CFG_EBC_PB4CR); | |
85 | +#endif | |
86 | + | |
87 | +#if (defined(CFG_EBC_PB5AP) && defined(CFG_EBC_PB5CR)) | |
88 | + mtebc(pb5ap, CFG_EBC_PB5AP); | |
89 | + mtebc(pb5cr, CFG_EBC_PB5CR); | |
90 | +#endif | |
91 | + | |
92 | +#if (defined(CFG_EBC_PB6AP) && defined(CFG_EBC_PB6CR)) | |
93 | + mtebc(pb6ap, CFG_EBC_PB6AP); | |
94 | + mtebc(pb6cr, CFG_EBC_PB6CR); | |
95 | +#endif | |
96 | + | |
97 | +#if (defined(CFG_EBC_PB7AP) && defined(CFG_EBC_PB7CR)) | |
98 | + mtebc(pb7ap, CFG_EBC_PB7AP); | |
99 | + mtebc(pb7cr, CFG_EBC_PB7CR); | |
100 | +#endif | |
101 | + | |
102 | +#if defined(CONFIG_WATCHDOG) | |
103 | + unsigned long val; | |
104 | + | |
105 | + val = mfspr(tcr); | |
106 | + val |= 0xf0000000; /* generate system reset after 2.684 seconds */ | |
107 | + mtspr(tcr, val); | |
108 | + | |
109 | + val = mfspr(tsr); | |
110 | + val |= 0x80000000; /* enable watchdog timer */ | |
111 | + mtspr(tsr, val); | |
112 | + | |
113 | + reset_4xx_watchdog(); | |
114 | +#endif /* CONFIG_WATCHDOG */ | |
115 | +} | |
116 | + | |
117 | +/* | |
118 | + * initialize higher level parts of CPU like time base and timers | |
119 | + */ | |
120 | +int cpu_init_r (void) | |
121 | +{ | |
122 | +#ifdef CONFIG_405GP | |
123 | + DECLARE_GLOBAL_DATA_PTR; | |
124 | + | |
125 | + bd_t *bd = gd->bd; | |
126 | + unsigned long reg; | |
127 | + | |
128 | + /* | |
129 | + * Write Ethernetaddress into on-chip register | |
130 | + */ | |
131 | + reg = 0x00000000; | |
132 | + reg |= bd->bi_enetaddr[0]; /* set high address */ | |
133 | + reg = reg << 8; | |
134 | + reg |= bd->bi_enetaddr[1]; | |
135 | + out32 (EMAC_IAH, reg); | |
136 | + | |
137 | + reg = 0x00000000; | |
138 | + reg |= bd->bi_enetaddr[2]; /* set low address */ | |
139 | + reg = reg << 8; | |
140 | + reg |= bd->bi_enetaddr[3]; | |
141 | + reg = reg << 8; | |
142 | + reg |= bd->bi_enetaddr[4]; | |
143 | + reg = reg << 8; | |
144 | + reg |= bd->bi_enetaddr[5]; | |
145 | + out32 (EMAC_IAL, reg); | |
146 | +#endif /* CONFIG_405GP */ | |
147 | + return (0); | |
148 | +} |
cpu/sa1100/cpu.c
1 | +/* | |
2 | + * (C) Copyright 2002 | |
3 | + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
4 | + * Marius Groeger <mgroeger@sysgo.de> | |
5 | + * | |
6 | + * (C) Copyright 2002 | |
7 | + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
8 | + * Alex Zuepke <azu@sysgo.de> | |
9 | + * | |
10 | + * See file CREDITS for list of people who contributed to this | |
11 | + * project. | |
12 | + * | |
13 | + * This program is free software; you can redistribute it and/or | |
14 | + * modify it under the terms of the GNU General Public License as | |
15 | + * published by the Free Software Foundation; either version 2 of | |
16 | + * the License, or (at your option) any later version. | |
17 | + * | |
18 | + * This program is distributed in the hope that it will be useful, | |
19 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | + * GNU General Public License for more details. | |
22 | + * | |
23 | + * You should have received a copy of the GNU General Public License | |
24 | + * along with this program; if not, write to the Free Software | |
25 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
26 | + * MA 02111-1307 USA | |
27 | + */ | |
28 | + | |
29 | +/* | |
30 | + * CPU specific code | |
31 | + */ | |
32 | + | |
33 | +#include <common.h> | |
34 | +#include <command.h> | |
35 | + | |
36 | +int cpu_init (void) | |
37 | +{ | |
38 | + /* | |
39 | + * setup up stack if necessary | |
40 | + */ | |
41 | +#ifdef CONFIG_USE_IRQ | |
42 | + IRQ_STACK_START = _armboot_end + | |
43 | + CONFIG_STACKSIZE + CONFIG_STACKSIZE_IRQ - 4; | |
44 | + FIQ_STACK_START = IRQ_STACK_START + CONFIG_STACKSIZE_FIQ; | |
45 | + _armboot_real_end = FIQ_STACK_START + 4; | |
46 | +#else | |
47 | + _armboot_real_end = _armboot_end + CONFIG_STACKSIZE; | |
48 | +#endif | |
49 | + return (0); | |
50 | +} | |
51 | + | |
52 | +int cleanup_before_linux (void) | |
53 | +{ | |
54 | + /* | |
55 | + * this function is called just before we call linux | |
56 | + * it prepares the processor for linux | |
57 | + * | |
58 | + * just disable everything that can disturb booting linux | |
59 | + */ | |
60 | + | |
61 | + unsigned long i; | |
62 | + | |
63 | + disable_interrupts (); | |
64 | + | |
65 | + /* turn off I-cache */ | |
66 | + asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); | |
67 | + i &= ~0x1000; | |
68 | + asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); | |
69 | + | |
70 | + /* flush I-cache */ | |
71 | + asm ("mcr p15, 0, %0, c7, c5, 0": :"r" (i)); | |
72 | + | |
73 | + return (0); | |
74 | +} | |
75 | + | |
76 | +int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) | |
77 | +{ | |
78 | + extern void reset_cpu (ulong addr); | |
79 | + | |
80 | + printf ("resetting ...\n"); | |
81 | + | |
82 | + udelay (50000); /* wait 50 ms */ | |
83 | + disable_interrupts (); | |
84 | + reset_cpu (0); | |
85 | + | |
86 | + /*NOTREACHED*/ | |
87 | + return (0); | |
88 | +} | |
89 | + | |
90 | +/* taken from blob */ | |
91 | +void icache_enable (void) | |
92 | +{ | |
93 | + register u32 i; | |
94 | + | |
95 | + /* read control register */ | |
96 | + asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); | |
97 | + | |
98 | + /* set i-cache */ | |
99 | + i |= 0x1000; | |
100 | + | |
101 | + /* write back to control register */ | |
102 | + asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); | |
103 | +} | |
104 | + | |
105 | +void icache_disable (void) | |
106 | +{ | |
107 | + register u32 i; | |
108 | + | |
109 | + /* read control register */ | |
110 | + asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); | |
111 | + | |
112 | + /* clear i-cache */ | |
113 | + i &= ~0x1000; | |
114 | + | |
115 | + /* write back to control register */ | |
116 | + asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); | |
117 | + | |
118 | + /* flush i-cache */ | |
119 | + asm ("mcr p15, 0, %0, c7, c5, 0": :"r" (i)); | |
120 | +} | |
121 | + | |
122 | +int icache_status (void) | |
123 | +{ | |
124 | + register u32 i; | |
125 | + | |
126 | + /* read control register */ | |
127 | + asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); | |
128 | + | |
129 | + /* return bit */ | |
130 | + return (i & 0x1000); | |
131 | +} | |
132 | + | |
133 | +/* we will never enable dcache, because we have to setup MMU first */ | |
134 | +void dcache_enable (void) | |
135 | +{ | |
136 | + return; | |
137 | +} | |
138 | + | |
139 | +void dcache_disable (void) | |
140 | +{ | |
141 | + return; | |
142 | +} | |
143 | + | |
144 | +int dcache_status (void) | |
145 | +{ | |
146 | + return 0; /* always off */ | |
147 | +} |