Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * arch/m68k/mvme16x/config.c | |
3 | * | |
4 | * Copyright (C) 1995 Richard Hirst [richard@sleepie.demon.co.uk] | |
5 | * | |
6 | * Based on: | |
7 | * | |
8 | * linux/amiga/config.c | |
9 | * | |
10 | * Copyright (C) 1993 Hamish Macdonald | |
11 | * | |
12 | * This file is subject to the terms and conditions of the GNU General Public | |
13 | * License. See the file README.legal in the main directory of this archive | |
14 | * for more details. | |
15 | */ | |
16 | ||
17 | #include <linux/types.h> | |
18 | #include <linux/kernel.h> | |
19 | #include <linux/mm.h> | |
813dcf7a | 20 | #include <linux/seq_file.h> |
1da177e4 LT |
21 | #include <linux/tty.h> |
22 | #include <linux/console.h> | |
23 | #include <linux/linkage.h> | |
24 | #include <linux/init.h> | |
25 | #include <linux/major.h> | |
26 | #include <linux/genhd.h> | |
27 | #include <linux/rtc.h> | |
28 | #include <linux/interrupt.h> | |
612e484f | 29 | #include <linux/module.h> |
1da177e4 LT |
30 | |
31 | #include <asm/bootinfo.h> | |
4c3c522b | 32 | #include <asm/bootinfo-vme.h> |
abe48101 | 33 | #include <asm/byteorder.h> |
1da177e4 LT |
34 | #include <asm/pgtable.h> |
35 | #include <asm/setup.h> | |
36 | #include <asm/irq.h> | |
37 | #include <asm/traps.h> | |
38 | #include <asm/rtc.h> | |
39 | #include <asm/machdep.h> | |
40 | #include <asm/mvme16xhw.h> | |
41 | ||
42 | extern t_bdid mvme_bdid; | |
43 | ||
44 | static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE; | |
45 | ||
1da177e4 | 46 | static void mvme16x_get_model(char *model); |
40220c1a | 47 | extern void mvme16x_sched_init(irq_handler_t handler); |
c8d5ba18 | 48 | extern u32 mvme16x_gettimeoffset(void); |
1da177e4 LT |
49 | extern int mvme16x_hwclk (int, struct rtc_time *); |
50 | extern int mvme16x_set_clock_mmss (unsigned long); | |
51 | extern void mvme16x_reset (void); | |
1da177e4 LT |
52 | |
53 | int bcd2int (unsigned char b); | |
54 | ||
e53f276b TH |
55 | /* Save tick handler routine pointer, will point to xtime_update() in |
56 | * kernel/time/timekeeping.c, called via mvme16x_process_int() */ | |
1da177e4 | 57 | |
40220c1a | 58 | static irq_handler_t tick_handler; |
1da177e4 LT |
59 | |
60 | ||
61 | unsigned short mvme16x_config; | |
612e484f | 62 | EXPORT_SYMBOL(mvme16x_config); |
1da177e4 LT |
63 | |
64 | ||
a4df02a2 | 65 | int __init mvme16x_parse_bootinfo(const struct bi_record *bi) |
1da177e4 | 66 | { |
abe48101 GU |
67 | uint16_t tag = be16_to_cpu(bi->tag); |
68 | if (tag == BI_VME_TYPE || tag == BI_VME_BRDINFO) | |
1da177e4 LT |
69 | return 0; |
70 | else | |
71 | return 1; | |
72 | } | |
73 | ||
74 | void mvme16x_reset(void) | |
75 | { | |
76 | printk ("\r\n\nCalled mvme16x_reset\r\n" | |
77 | "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r"); | |
78 | /* The string of returns is to delay the reset until the whole | |
79 | * message is output. Assert reset bit in GCSR */ | |
80 | *(volatile char *)0xfff40107 = 0x80; | |
81 | } | |
82 | ||
83 | static void mvme16x_get_model(char *model) | |
84 | { | |
85 | p_bdid p = &mvme_bdid; | |
86 | char suf[4]; | |
87 | ||
88 | suf[1] = p->brdsuffix[0]; | |
89 | suf[2] = p->brdsuffix[1]; | |
90 | suf[3] = '\0'; | |
91 | suf[0] = suf[1] ? '-' : '\0'; | |
92 | ||
abe48101 | 93 | sprintf(model, "Motorola MVME%x%s", be16_to_cpu(p->brdno), suf); |
1da177e4 LT |
94 | } |
95 | ||
96 | ||
813dcf7a | 97 | static void mvme16x_get_hardware_list(struct seq_file *m) |
1da177e4 | 98 | { |
abe48101 | 99 | uint16_t brdno = be16_to_cpu(mvme_bdid.brdno); |
1da177e4 | 100 | |
abe48101 | 101 | if (brdno == 0x0162 || brdno == 0x0172) |
1da177e4 LT |
102 | { |
103 | unsigned char rev = *(unsigned char *)MVME162_VERSION_REG; | |
104 | ||
813dcf7a | 105 | seq_printf (m, "VMEchip2 %spresent\n", |
1da177e4 | 106 | rev & MVME16x_CONFIG_NO_VMECHIP2 ? "NOT " : ""); |
813dcf7a | 107 | seq_printf (m, "SCSI interface %spresent\n", |
1da177e4 | 108 | rev & MVME16x_CONFIG_NO_SCSICHIP ? "NOT " : ""); |
813dcf7a | 109 | seq_printf (m, "Ethernet i/f %spresent\n", |
1da177e4 LT |
110 | rev & MVME16x_CONFIG_NO_ETHERNET ? "NOT " : ""); |
111 | } | |
1da177e4 LT |
112 | } |
113 | ||
200a3d35 RZ |
114 | /* |
115 | * This function is called during kernel startup to initialize | |
116 | * the mvme16x IRQ handling routines. Should probably ensure | |
117 | * that the base vectors for the VMEChip2 and PCCChip2 are valid. | |
118 | */ | |
119 | ||
66a3f820 | 120 | static void __init mvme16x_init_IRQ (void) |
200a3d35 | 121 | { |
f30a6484 | 122 | m68k_setup_user_interrupt(VEC_USER, 192); |
200a3d35 | 123 | } |
1da177e4 LT |
124 | |
125 | #define pcc2chip ((volatile u_char *)0xfff42000) | |
126 | #define PccSCCMICR 0x1d | |
127 | #define PccSCCTICR 0x1e | |
128 | #define PccSCCRICR 0x1f | |
f9994894 KJ |
129 | #define PccTPIACKR 0x25 |
130 | ||
131 | #ifdef CONFIG_EARLY_PRINTK | |
132 | ||
133 | /**** cd2401 registers ****/ | |
134 | #define CD2401_ADDR (0xfff45000) | |
135 | ||
136 | #define CyGFRCR (0x81) | |
137 | #define CyCCR (0x13) | |
138 | #define CyCLR_CHAN (0x40) | |
139 | #define CyINIT_CHAN (0x20) | |
140 | #define CyCHIP_RESET (0x10) | |
141 | #define CyENB_XMTR (0x08) | |
142 | #define CyDIS_XMTR (0x04) | |
143 | #define CyENB_RCVR (0x02) | |
144 | #define CyDIS_RCVR (0x01) | |
145 | #define CyCAR (0xee) | |
146 | #define CyIER (0x11) | |
147 | #define CyMdmCh (0x80) | |
148 | #define CyRxExc (0x20) | |
149 | #define CyRxData (0x08) | |
150 | #define CyTxMpty (0x02) | |
151 | #define CyTxRdy (0x01) | |
152 | #define CyLICR (0x26) | |
153 | #define CyRISR (0x89) | |
154 | #define CyTIMEOUT (0x80) | |
155 | #define CySPECHAR (0x70) | |
156 | #define CyOVERRUN (0x08) | |
157 | #define CyPARITY (0x04) | |
158 | #define CyFRAME (0x02) | |
159 | #define CyBREAK (0x01) | |
160 | #define CyREOIR (0x84) | |
161 | #define CyTEOIR (0x85) | |
162 | #define CyMEOIR (0x86) | |
163 | #define CyNOTRANS (0x08) | |
164 | #define CyRFOC (0x30) | |
165 | #define CyRDR (0xf8) | |
166 | #define CyTDR (0xf8) | |
167 | #define CyMISR (0x8b) | |
168 | #define CyRISR (0x89) | |
169 | #define CyTISR (0x8a) | |
170 | #define CyMSVR1 (0xde) | |
171 | #define CyMSVR2 (0xdf) | |
172 | #define CyDSR (0x80) | |
173 | #define CyDCD (0x40) | |
174 | #define CyCTS (0x20) | |
175 | #define CyDTR (0x02) | |
176 | #define CyRTS (0x01) | |
177 | #define CyRTPRL (0x25) | |
178 | #define CyRTPRH (0x24) | |
179 | #define CyCOR1 (0x10) | |
180 | #define CyPARITY_NONE (0x00) | |
181 | #define CyPARITY_E (0x40) | |
182 | #define CyPARITY_O (0xC0) | |
183 | #define Cy_5_BITS (0x04) | |
184 | #define Cy_6_BITS (0x05) | |
185 | #define Cy_7_BITS (0x06) | |
186 | #define Cy_8_BITS (0x07) | |
187 | #define CyCOR2 (0x17) | |
188 | #define CyETC (0x20) | |
189 | #define CyCtsAE (0x02) | |
190 | #define CyCOR3 (0x16) | |
191 | #define Cy_1_STOP (0x02) | |
192 | #define Cy_2_STOP (0x04) | |
193 | #define CyCOR4 (0x15) | |
194 | #define CyREC_FIFO (0x0F) /* Receive FIFO threshold */ | |
195 | #define CyCOR5 (0x14) | |
196 | #define CyCOR6 (0x18) | |
197 | #define CyCOR7 (0x07) | |
198 | #define CyRBPR (0xcb) | |
199 | #define CyRCOR (0xc8) | |
200 | #define CyTBPR (0xc3) | |
201 | #define CyTCOR (0xc0) | |
202 | #define CySCHR1 (0x1f) | |
203 | #define CySCHR2 (0x1e) | |
204 | #define CyTPR (0xda) | |
205 | #define CyPILR1 (0xe3) | |
206 | #define CyPILR2 (0xe0) | |
207 | #define CyPILR3 (0xe1) | |
208 | #define CyCMR (0x1b) | |
209 | #define CyASYNC (0x02) | |
210 | #define CyLICR (0x26) | |
211 | #define CyLIVR (0x09) | |
212 | #define CySCRL (0x23) | |
213 | #define CySCRH (0x22) | |
214 | #define CyTFTC (0x80) | |
215 | ||
c46f46d0 | 216 | void mvme16x_cons_write(struct console *co, const char *str, unsigned count) |
f9994894 KJ |
217 | { |
218 | volatile unsigned char *base_addr = (u_char *)CD2401_ADDR; | |
219 | volatile u_char sink; | |
220 | u_char ier; | |
221 | int port; | |
222 | u_char do_lf = 0; | |
223 | int i = 0; | |
224 | ||
225 | /* Ensure transmitter is enabled! */ | |
226 | ||
227 | port = 0; | |
228 | base_addr[CyCAR] = (u_char)port; | |
229 | while (base_addr[CyCCR]) | |
230 | ; | |
231 | base_addr[CyCCR] = CyENB_XMTR; | |
232 | ||
233 | ier = base_addr[CyIER]; | |
234 | base_addr[CyIER] = CyTxMpty; | |
235 | ||
236 | while (1) { | |
237 | if (pcc2chip[PccSCCTICR] & 0x20) | |
238 | { | |
239 | /* We have a Tx int. Acknowledge it */ | |
240 | sink = pcc2chip[PccTPIACKR]; | |
241 | if ((base_addr[CyLICR] >> 2) == port) { | |
242 | if (i == count) { | |
243 | /* Last char of string is now output */ | |
244 | base_addr[CyTEOIR] = CyNOTRANS; | |
245 | break; | |
246 | } | |
247 | if (do_lf) { | |
248 | base_addr[CyTDR] = '\n'; | |
249 | str++; | |
250 | i++; | |
251 | do_lf = 0; | |
252 | } | |
253 | else if (*str == '\n') { | |
254 | base_addr[CyTDR] = '\r'; | |
255 | do_lf = 1; | |
256 | } | |
257 | else { | |
258 | base_addr[CyTDR] = *str++; | |
259 | i++; | |
260 | } | |
261 | base_addr[CyTEOIR] = 0; | |
262 | } | |
263 | else | |
264 | base_addr[CyTEOIR] = CyNOTRANS; | |
265 | } | |
266 | } | |
267 | ||
268 | base_addr[CyIER] = ier; | |
269 | } | |
270 | ||
f9994894 | 271 | #endif |
1da177e4 LT |
272 | |
273 | void __init config_mvme16x(void) | |
274 | { | |
275 | p_bdid p = &mvme_bdid; | |
276 | char id[40]; | |
abe48101 | 277 | uint16_t brdno = be16_to_cpu(p->brdno); |
1da177e4 LT |
278 | |
279 | mach_max_dma_address = 0xffffffff; | |
280 | mach_sched_init = mvme16x_sched_init; | |
281 | mach_init_IRQ = mvme16x_init_IRQ; | |
c8d5ba18 | 282 | arch_gettimeoffset = mvme16x_gettimeoffset; |
1da177e4 LT |
283 | mach_hwclk = mvme16x_hwclk; |
284 | mach_set_clock_mmss = mvme16x_set_clock_mmss; | |
285 | mach_reset = mvme16x_reset; | |
1da177e4 LT |
286 | mach_get_model = mvme16x_get_model; |
287 | mach_get_hardware_list = mvme16x_get_hardware_list; | |
288 | ||
289 | /* Report board revision */ | |
290 | ||
291 | if (strncmp("BDID", p->bdid, 4)) | |
292 | { | |
293 | printk ("\n\nBug call .BRD_ID returned garbage - giving up\n\n"); | |
294 | while (1) | |
295 | ; | |
296 | } | |
297 | /* Board type is only set by newer versions of vmelilo/tftplilo */ | |
298 | if (vme_brdtype == 0) | |
abe48101 | 299 | vme_brdtype = brdno; |
1da177e4 LT |
300 | |
301 | mvme16x_get_model(id); | |
302 | printk ("\nBRD_ID: %s BUG %x.%x %02x/%02x/%02x\n", id, p->rev>>4, | |
303 | p->rev&0xf, p->yr, p->mth, p->day); | |
abe48101 | 304 | if (brdno == 0x0162 || brdno == 0x172) |
1da177e4 LT |
305 | { |
306 | unsigned char rev = *(unsigned char *)MVME162_VERSION_REG; | |
307 | ||
308 | mvme16x_config = rev | MVME16x_CONFIG_GOT_SCCA; | |
309 | ||
abe48101 | 310 | printk ("MVME%x Hardware status:\n", brdno); |
1da177e4 LT |
311 | printk (" CPU Type 68%s040\n", |
312 | rev & MVME16x_CONFIG_GOT_FPU ? "" : "LC"); | |
313 | printk (" CPU clock %dMHz\n", | |
314 | rev & MVME16x_CONFIG_SPEED_32 ? 32 : 25); | |
315 | printk (" VMEchip2 %spresent\n", | |
316 | rev & MVME16x_CONFIG_NO_VMECHIP2 ? "NOT " : ""); | |
317 | printk (" SCSI interface %spresent\n", | |
318 | rev & MVME16x_CONFIG_NO_SCSICHIP ? "NOT " : ""); | |
319 | printk (" Ethernet interface %spresent\n", | |
320 | rev & MVME16x_CONFIG_NO_ETHERNET ? "NOT " : ""); | |
321 | } | |
322 | else | |
323 | { | |
324 | mvme16x_config = MVME16x_CONFIG_GOT_LP | MVME16x_CONFIG_GOT_CD2401; | |
1da177e4 LT |
325 | } |
326 | } | |
327 | ||
2850bc27 | 328 | static irqreturn_t mvme16x_abort_int (int irq, void *dev_id) |
1da177e4 | 329 | { |
1da177e4 LT |
330 | unsigned long *new = (unsigned long *)vectors; |
331 | unsigned long *old = (unsigned long *)0xffe00000; | |
332 | volatile unsigned char uc, *ucp; | |
abe48101 | 333 | uint16_t brdno = be16_to_cpu(mvme_bdid.brdno); |
1da177e4 | 334 | |
abe48101 | 335 | if (brdno == 0x0162 || brdno == 0x172) |
1da177e4 LT |
336 | { |
337 | ucp = (volatile unsigned char *)0xfff42043; | |
338 | uc = *ucp | 8; | |
339 | *ucp = uc; | |
340 | } | |
341 | else | |
342 | { | |
343 | *(volatile unsigned long *)0xfff40074 = 0x40000000; | |
344 | } | |
345 | *(new+4) = *(old+4); /* Illegal instruction */ | |
346 | *(new+9) = *(old+9); /* Trace */ | |
347 | *(new+47) = *(old+47); /* Trap #15 */ | |
348 | ||
abe48101 | 349 | if (brdno == 0x0162 || brdno == 0x172) |
1da177e4 LT |
350 | *(new+0x5e) = *(old+0x5e); /* ABORT switch */ |
351 | else | |
352 | *(new+0x6e) = *(old+0x6e); /* ABORT switch */ | |
353 | return IRQ_HANDLED; | |
354 | } | |
355 | ||
2850bc27 | 356 | static irqreturn_t mvme16x_timer_int (int irq, void *dev_id) |
1da177e4 LT |
357 | { |
358 | *(volatile unsigned char *)0xfff4201b |= 8; | |
2850bc27 | 359 | return tick_handler(irq, dev_id); |
1da177e4 LT |
360 | } |
361 | ||
40220c1a | 362 | void mvme16x_sched_init (irq_handler_t timer_routine) |
1da177e4 | 363 | { |
abe48101 | 364 | uint16_t brdno = be16_to_cpu(mvme_bdid.brdno); |
1da177e4 LT |
365 | int irq; |
366 | ||
367 | tick_handler = timer_routine; | |
368 | /* Using PCCchip2 or MC2 chip tick timer 1 */ | |
369 | *(volatile unsigned long *)0xfff42008 = 0; | |
370 | *(volatile unsigned long *)0xfff42004 = 10000; /* 10ms */ | |
371 | *(volatile unsigned char *)0xfff42017 |= 3; | |
372 | *(volatile unsigned char *)0xfff4201b = 0x16; | |
373 | if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, 0, | |
374 | "timer", mvme16x_timer_int)) | |
375 | panic ("Couldn't register timer int"); | |
376 | ||
abe48101 | 377 | if (brdno == 0x0162 || brdno == 0x172) |
1da177e4 LT |
378 | irq = MVME162_IRQ_ABORT; |
379 | else | |
380 | irq = MVME167_IRQ_ABORT; | |
381 | if (request_irq(irq, mvme16x_abort_int, 0, | |
382 | "abort", mvme16x_abort_int)) | |
383 | panic ("Couldn't register abort int"); | |
384 | } | |
385 | ||
386 | ||
387 | /* This is always executed with interrupts disabled. */ | |
c8d5ba18 | 388 | u32 mvme16x_gettimeoffset(void) |
1da177e4 | 389 | { |
c8d5ba18 | 390 | return (*(volatile u32 *)0xfff42008) * 1000; |
1da177e4 LT |
391 | } |
392 | ||
393 | int bcd2int (unsigned char b) | |
394 | { | |
395 | return ((b>>4)*10 + (b&15)); | |
396 | } | |
397 | ||
398 | int mvme16x_hwclk(int op, struct rtc_time *t) | |
399 | { | |
400 | #warning check me! | |
401 | if (!op) { | |
402 | rtc->ctrl = RTC_READ; | |
403 | t->tm_year = bcd2int (rtc->bcd_year); | |
404 | t->tm_mon = bcd2int (rtc->bcd_mth); | |
405 | t->tm_mday = bcd2int (rtc->bcd_dom); | |
406 | t->tm_hour = bcd2int (rtc->bcd_hr); | |
407 | t->tm_min = bcd2int (rtc->bcd_min); | |
408 | t->tm_sec = bcd2int (rtc->bcd_sec); | |
409 | rtc->ctrl = 0; | |
410 | } | |
411 | return 0; | |
412 | } | |
413 | ||
414 | int mvme16x_set_clock_mmss (unsigned long nowtime) | |
415 | { | |
416 | return 0; | |
417 | } | |
418 |