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> | |
20 | #include <linux/tty.h> | |
21 | #include <linux/console.h> | |
22 | #include <linux/linkage.h> | |
23 | #include <linux/init.h> | |
24 | #include <linux/major.h> | |
25 | #include <linux/genhd.h> | |
26 | #include <linux/rtc.h> | |
27 | #include <linux/interrupt.h> | |
28 | ||
29 | #include <asm/bootinfo.h> | |
30 | #include <asm/system.h> | |
31 | #include <asm/pgtable.h> | |
32 | #include <asm/setup.h> | |
33 | #include <asm/irq.h> | |
34 | #include <asm/traps.h> | |
35 | #include <asm/rtc.h> | |
36 | #include <asm/machdep.h> | |
37 | #include <asm/mvme16xhw.h> | |
38 | ||
39 | extern t_bdid mvme_bdid; | |
40 | ||
41 | static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE; | |
42 | ||
43 | extern irqreturn_t mvme16x_process_int (int level, struct pt_regs *regs); | |
44 | extern void mvme16x_init_IRQ (void); | |
45 | extern void mvme16x_free_irq (unsigned int, void *); | |
46 | extern int show_mvme16x_interrupts (struct seq_file *, void *); | |
47 | extern void mvme16x_enable_irq (unsigned int); | |
48 | extern void mvme16x_disable_irq (unsigned int); | |
49 | static void mvme16x_get_model(char *model); | |
50 | static int mvme16x_get_hardware_list(char *buffer); | |
51 | extern int mvme16x_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id); | |
52 | extern void mvme16x_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); | |
53 | extern unsigned long mvme16x_gettimeoffset (void); | |
54 | extern int mvme16x_hwclk (int, struct rtc_time *); | |
55 | extern int mvme16x_set_clock_mmss (unsigned long); | |
56 | extern void mvme16x_reset (void); | |
57 | extern void mvme16x_waitbut(void); | |
58 | ||
59 | int bcd2int (unsigned char b); | |
60 | ||
61 | /* Save tick handler routine pointer, will point to do_timer() in | |
62 | * kernel/sched.c, called via mvme16x_process_int() */ | |
63 | ||
64 | static irqreturn_t (*tick_handler)(int, void *, struct pt_regs *); | |
65 | ||
66 | ||
67 | unsigned short mvme16x_config; | |
68 | ||
69 | ||
70 | int mvme16x_parse_bootinfo(const struct bi_record *bi) | |
71 | { | |
72 | if (bi->tag == BI_VME_TYPE || bi->tag == BI_VME_BRDINFO) | |
73 | return 0; | |
74 | else | |
75 | return 1; | |
76 | } | |
77 | ||
78 | void mvme16x_reset(void) | |
79 | { | |
80 | printk ("\r\n\nCalled mvme16x_reset\r\n" | |
81 | "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r"); | |
82 | /* The string of returns is to delay the reset until the whole | |
83 | * message is output. Assert reset bit in GCSR */ | |
84 | *(volatile char *)0xfff40107 = 0x80; | |
85 | } | |
86 | ||
87 | static void mvme16x_get_model(char *model) | |
88 | { | |
89 | p_bdid p = &mvme_bdid; | |
90 | char suf[4]; | |
91 | ||
92 | suf[1] = p->brdsuffix[0]; | |
93 | suf[2] = p->brdsuffix[1]; | |
94 | suf[3] = '\0'; | |
95 | suf[0] = suf[1] ? '-' : '\0'; | |
96 | ||
97 | sprintf(model, "Motorola MVME%x%s", p->brdno, suf); | |
98 | } | |
99 | ||
100 | ||
101 | static int mvme16x_get_hardware_list(char *buffer) | |
102 | { | |
103 | p_bdid p = &mvme_bdid; | |
104 | int len = 0; | |
105 | ||
106 | if (p->brdno == 0x0162 || p->brdno == 0x0172) | |
107 | { | |
108 | unsigned char rev = *(unsigned char *)MVME162_VERSION_REG; | |
109 | ||
110 | len += sprintf (buffer+len, "VMEchip2 %spresent\n", | |
111 | rev & MVME16x_CONFIG_NO_VMECHIP2 ? "NOT " : ""); | |
112 | len += sprintf (buffer+len, "SCSI interface %spresent\n", | |
113 | rev & MVME16x_CONFIG_NO_SCSICHIP ? "NOT " : ""); | |
114 | len += sprintf (buffer+len, "Ethernet i/f %spresent\n", | |
115 | rev & MVME16x_CONFIG_NO_ETHERNET ? "NOT " : ""); | |
116 | } | |
117 | else | |
118 | *buffer = '\0'; | |
119 | ||
120 | return (len); | |
121 | } | |
122 | ||
123 | ||
124 | #define pcc2chip ((volatile u_char *)0xfff42000) | |
125 | #define PccSCCMICR 0x1d | |
126 | #define PccSCCTICR 0x1e | |
127 | #define PccSCCRICR 0x1f | |
128 | ||
129 | void __init config_mvme16x(void) | |
130 | { | |
131 | p_bdid p = &mvme_bdid; | |
132 | char id[40]; | |
133 | ||
134 | mach_max_dma_address = 0xffffffff; | |
135 | mach_sched_init = mvme16x_sched_init; | |
136 | mach_init_IRQ = mvme16x_init_IRQ; | |
137 | mach_gettimeoffset = mvme16x_gettimeoffset; | |
138 | mach_hwclk = mvme16x_hwclk; | |
139 | mach_set_clock_mmss = mvme16x_set_clock_mmss; | |
140 | mach_reset = mvme16x_reset; | |
141 | mach_free_irq = mvme16x_free_irq; | |
142 | mach_process_int = mvme16x_process_int; | |
143 | mach_get_irq_list = show_mvme16x_interrupts; | |
144 | mach_request_irq = mvme16x_request_irq; | |
145 | enable_irq = mvme16x_enable_irq; | |
146 | disable_irq = mvme16x_disable_irq; | |
147 | mach_get_model = mvme16x_get_model; | |
148 | mach_get_hardware_list = mvme16x_get_hardware_list; | |
149 | ||
150 | /* Report board revision */ | |
151 | ||
152 | if (strncmp("BDID", p->bdid, 4)) | |
153 | { | |
154 | printk ("\n\nBug call .BRD_ID returned garbage - giving up\n\n"); | |
155 | while (1) | |
156 | ; | |
157 | } | |
158 | /* Board type is only set by newer versions of vmelilo/tftplilo */ | |
159 | if (vme_brdtype == 0) | |
160 | vme_brdtype = p->brdno; | |
161 | ||
162 | mvme16x_get_model(id); | |
163 | printk ("\nBRD_ID: %s BUG %x.%x %02x/%02x/%02x\n", id, p->rev>>4, | |
164 | p->rev&0xf, p->yr, p->mth, p->day); | |
165 | if (p->brdno == 0x0162 || p->brdno == 0x172) | |
166 | { | |
167 | unsigned char rev = *(unsigned char *)MVME162_VERSION_REG; | |
168 | ||
169 | mvme16x_config = rev | MVME16x_CONFIG_GOT_SCCA; | |
170 | ||
171 | printk ("MVME%x Hardware status:\n", p->brdno); | |
172 | printk (" CPU Type 68%s040\n", | |
173 | rev & MVME16x_CONFIG_GOT_FPU ? "" : "LC"); | |
174 | printk (" CPU clock %dMHz\n", | |
175 | rev & MVME16x_CONFIG_SPEED_32 ? 32 : 25); | |
176 | printk (" VMEchip2 %spresent\n", | |
177 | rev & MVME16x_CONFIG_NO_VMECHIP2 ? "NOT " : ""); | |
178 | printk (" SCSI interface %spresent\n", | |
179 | rev & MVME16x_CONFIG_NO_SCSICHIP ? "NOT " : ""); | |
180 | printk (" Ethernet interface %spresent\n", | |
181 | rev & MVME16x_CONFIG_NO_ETHERNET ? "NOT " : ""); | |
182 | } | |
183 | else | |
184 | { | |
185 | mvme16x_config = MVME16x_CONFIG_GOT_LP | MVME16x_CONFIG_GOT_CD2401; | |
186 | ||
187 | /* Dont allow any interrupts from the CD2401 until the interrupt */ | |
188 | /* handlers are installed */ | |
189 | ||
190 | pcc2chip[PccSCCMICR] = 0x10; | |
191 | pcc2chip[PccSCCTICR] = 0x10; | |
192 | pcc2chip[PccSCCRICR] = 0x10; | |
193 | } | |
194 | } | |
195 | ||
196 | static irqreturn_t mvme16x_abort_int (int irq, void *dev_id, struct pt_regs *fp) | |
197 | { | |
198 | p_bdid p = &mvme_bdid; | |
199 | unsigned long *new = (unsigned long *)vectors; | |
200 | unsigned long *old = (unsigned long *)0xffe00000; | |
201 | volatile unsigned char uc, *ucp; | |
202 | ||
203 | if (p->brdno == 0x0162 || p->brdno == 0x172) | |
204 | { | |
205 | ucp = (volatile unsigned char *)0xfff42043; | |
206 | uc = *ucp | 8; | |
207 | *ucp = uc; | |
208 | } | |
209 | else | |
210 | { | |
211 | *(volatile unsigned long *)0xfff40074 = 0x40000000; | |
212 | } | |
213 | *(new+4) = *(old+4); /* Illegal instruction */ | |
214 | *(new+9) = *(old+9); /* Trace */ | |
215 | *(new+47) = *(old+47); /* Trap #15 */ | |
216 | ||
217 | if (p->brdno == 0x0162 || p->brdno == 0x172) | |
218 | *(new+0x5e) = *(old+0x5e); /* ABORT switch */ | |
219 | else | |
220 | *(new+0x6e) = *(old+0x6e); /* ABORT switch */ | |
221 | return IRQ_HANDLED; | |
222 | } | |
223 | ||
224 | static irqreturn_t mvme16x_timer_int (int irq, void *dev_id, struct pt_regs *fp) | |
225 | { | |
226 | *(volatile unsigned char *)0xfff4201b |= 8; | |
227 | return tick_handler(irq, dev_id, fp); | |
228 | } | |
229 | ||
230 | void mvme16x_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *)) | |
231 | { | |
232 | p_bdid p = &mvme_bdid; | |
233 | int irq; | |
234 | ||
235 | tick_handler = timer_routine; | |
236 | /* Using PCCchip2 or MC2 chip tick timer 1 */ | |
237 | *(volatile unsigned long *)0xfff42008 = 0; | |
238 | *(volatile unsigned long *)0xfff42004 = 10000; /* 10ms */ | |
239 | *(volatile unsigned char *)0xfff42017 |= 3; | |
240 | *(volatile unsigned char *)0xfff4201b = 0x16; | |
241 | if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, 0, | |
242 | "timer", mvme16x_timer_int)) | |
243 | panic ("Couldn't register timer int"); | |
244 | ||
245 | if (p->brdno == 0x0162 || p->brdno == 0x172) | |
246 | irq = MVME162_IRQ_ABORT; | |
247 | else | |
248 | irq = MVME167_IRQ_ABORT; | |
249 | if (request_irq(irq, mvme16x_abort_int, 0, | |
250 | "abort", mvme16x_abort_int)) | |
251 | panic ("Couldn't register abort int"); | |
252 | } | |
253 | ||
254 | ||
255 | /* This is always executed with interrupts disabled. */ | |
256 | unsigned long mvme16x_gettimeoffset (void) | |
257 | { | |
258 | return (*(volatile unsigned long *)0xfff42008); | |
259 | } | |
260 | ||
261 | int bcd2int (unsigned char b) | |
262 | { | |
263 | return ((b>>4)*10 + (b&15)); | |
264 | } | |
265 | ||
266 | int mvme16x_hwclk(int op, struct rtc_time *t) | |
267 | { | |
268 | #warning check me! | |
269 | if (!op) { | |
270 | rtc->ctrl = RTC_READ; | |
271 | t->tm_year = bcd2int (rtc->bcd_year); | |
272 | t->tm_mon = bcd2int (rtc->bcd_mth); | |
273 | t->tm_mday = bcd2int (rtc->bcd_dom); | |
274 | t->tm_hour = bcd2int (rtc->bcd_hr); | |
275 | t->tm_min = bcd2int (rtc->bcd_min); | |
276 | t->tm_sec = bcd2int (rtc->bcd_sec); | |
277 | rtc->ctrl = 0; | |
278 | } | |
279 | return 0; | |
280 | } | |
281 | ||
282 | int mvme16x_set_clock_mmss (unsigned long nowtime) | |
283 | { | |
284 | return 0; | |
285 | } | |
286 |