diff options
Diffstat (limited to 'arch/sh/boards/mpc1211/setup.c')
-rw-r--r-- | arch/sh/boards/mpc1211/setup.c | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/arch/sh/boards/mpc1211/setup.c b/arch/sh/boards/mpc1211/setup.c new file mode 100644 index 000000000000..2bb581b91683 --- /dev/null +++ b/arch/sh/boards/mpc1211/setup.c | |||
@@ -0,0 +1,360 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/board/mpc1211/setup.c | ||
3 | * | ||
4 | * Copyright (C) 2002 Saito.K & Jeanne, Fujii.Y | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #include <linux/config.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/irq.h> | ||
11 | #include <linux/hdreg.h> | ||
12 | #include <linux/ide.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | |||
15 | #include <asm/io.h> | ||
16 | #include <asm/machvec.h> | ||
17 | #include <asm/mpc1211/mpc1211.h> | ||
18 | #include <asm/mpc1211/pci.h> | ||
19 | #include <asm/mpc1211/m1543c.h> | ||
20 | |||
21 | |||
22 | /* ALI15X3 SMBus address offsets */ | ||
23 | #define SMBHSTSTS (0 + 0x3100) | ||
24 | #define SMBHSTCNT (1 + 0x3100) | ||
25 | #define SMBHSTSTART (2 + 0x3100) | ||
26 | #define SMBHSTCMD (7 + 0x3100) | ||
27 | #define SMBHSTADD (3 + 0x3100) | ||
28 | #define SMBHSTDAT0 (4 + 0x3100) | ||
29 | #define SMBHSTDAT1 (5 + 0x3100) | ||
30 | #define SMBBLKDAT (6 + 0x3100) | ||
31 | |||
32 | /* Other settings */ | ||
33 | #define MAX_TIMEOUT 500 /* times 1/100 sec */ | ||
34 | |||
35 | /* ALI15X3 command constants */ | ||
36 | #define ALI15X3_ABORT 0x04 | ||
37 | #define ALI15X3_T_OUT 0x08 | ||
38 | #define ALI15X3_QUICK 0x00 | ||
39 | #define ALI15X3_BYTE 0x10 | ||
40 | #define ALI15X3_BYTE_DATA 0x20 | ||
41 | #define ALI15X3_WORD_DATA 0x30 | ||
42 | #define ALI15X3_BLOCK_DATA 0x40 | ||
43 | #define ALI15X3_BLOCK_CLR 0x80 | ||
44 | |||
45 | /* ALI15X3 status register bits */ | ||
46 | #define ALI15X3_STS_IDLE 0x04 | ||
47 | #define ALI15X3_STS_BUSY 0x08 | ||
48 | #define ALI15X3_STS_DONE 0x10 | ||
49 | #define ALI15X3_STS_DEV 0x20 /* device error */ | ||
50 | #define ALI15X3_STS_COLL 0x40 /* collision or no response */ | ||
51 | #define ALI15X3_STS_TERM 0x80 /* terminated by abort */ | ||
52 | #define ALI15X3_STS_ERR 0xE0 /* all the bad error bits */ | ||
53 | |||
54 | const char *get_system_type(void) | ||
55 | { | ||
56 | return "Interface MPC-1211(CTP/PCI/MPC-SH02)"; | ||
57 | } | ||
58 | |||
59 | static void __init pci_write_config(unsigned long busNo, | ||
60 | unsigned long devNo, | ||
61 | unsigned long fncNo, | ||
62 | unsigned long cnfAdd, | ||
63 | unsigned long cnfData) | ||
64 | { | ||
65 | ctrl_outl((0x80000000 | ||
66 | + ((busNo & 0xff) << 16) | ||
67 | + ((devNo & 0x1f) << 11) | ||
68 | + ((fncNo & 0x07) << 8) | ||
69 | + (cnfAdd & 0xfc)), PCIPAR); | ||
70 | |||
71 | ctrl_outl(cnfData, PCIPDR); | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | Initialize IRQ setting | ||
76 | */ | ||
77 | |||
78 | static unsigned char m_irq_mask = 0xfb; | ||
79 | static unsigned char s_irq_mask = 0xff; | ||
80 | volatile unsigned long irq_err_count; | ||
81 | |||
82 | static void disable_mpc1211_irq(unsigned int irq) | ||
83 | { | ||
84 | unsigned long flags; | ||
85 | |||
86 | save_and_cli(flags); | ||
87 | if( irq < 8) { | ||
88 | m_irq_mask |= (1 << irq); | ||
89 | outb(m_irq_mask,I8259_M_MR); | ||
90 | } else { | ||
91 | s_irq_mask |= (1 << (irq - 8)); | ||
92 | outb(s_irq_mask,I8259_S_MR); | ||
93 | } | ||
94 | restore_flags(flags); | ||
95 | |||
96 | } | ||
97 | |||
98 | static void enable_mpc1211_irq(unsigned int irq) | ||
99 | { | ||
100 | unsigned long flags; | ||
101 | |||
102 | save_and_cli(flags); | ||
103 | |||
104 | if( irq < 8) { | ||
105 | m_irq_mask &= ~(1 << irq); | ||
106 | outb(m_irq_mask,I8259_M_MR); | ||
107 | } else { | ||
108 | s_irq_mask &= ~(1 << (irq - 8)); | ||
109 | outb(s_irq_mask,I8259_S_MR); | ||
110 | } | ||
111 | restore_flags(flags); | ||
112 | } | ||
113 | |||
114 | static inline int mpc1211_irq_real(unsigned int irq) | ||
115 | { | ||
116 | int value; | ||
117 | int irqmask; | ||
118 | |||
119 | if ( irq < 8) { | ||
120 | irqmask = 1<<irq; | ||
121 | outb(0x0b,I8259_M_CR); /* ISR register */ | ||
122 | value = inb(I8259_M_CR) & irqmask; | ||
123 | outb(0x0a,I8259_M_CR); /* back ro the IPR reg */ | ||
124 | return value; | ||
125 | } | ||
126 | irqmask = 1<<(irq - 8); | ||
127 | outb(0x0b,I8259_S_CR); /* ISR register */ | ||
128 | value = inb(I8259_S_CR) & irqmask; | ||
129 | outb(0x0a,I8259_S_CR); /* back ro the IPR reg */ | ||
130 | return value; | ||
131 | } | ||
132 | |||
133 | static void mask_and_ack_mpc1211(unsigned int irq) | ||
134 | { | ||
135 | unsigned long flags; | ||
136 | |||
137 | save_and_cli(flags); | ||
138 | |||
139 | if(irq < 8) { | ||
140 | if(m_irq_mask & (1<<irq)){ | ||
141 | if(!mpc1211_irq_real(irq)){ | ||
142 | irq_err_count++; | ||
143 | printk("spurious 8259A interrupt: IRQ %x\n",irq); | ||
144 | } | ||
145 | } else { | ||
146 | m_irq_mask |= (1<<irq); | ||
147 | } | ||
148 | inb(I8259_M_MR); /* DUMMY */ | ||
149 | outb(m_irq_mask,I8259_M_MR); /* disable */ | ||
150 | outb(0x60+irq,I8259_M_CR); /* EOI */ | ||
151 | |||
152 | } else { | ||
153 | if(s_irq_mask & (1<<(irq - 8))){ | ||
154 | if(!mpc1211_irq_real(irq)){ | ||
155 | irq_err_count++; | ||
156 | printk("spurious 8259A interrupt: IRQ %x\n",irq); | ||
157 | } | ||
158 | } else { | ||
159 | s_irq_mask |= (1<<(irq - 8)); | ||
160 | } | ||
161 | inb(I8259_S_MR); /* DUMMY */ | ||
162 | outb(s_irq_mask,I8259_S_MR); /* disable */ | ||
163 | outb(0x60+(irq-8),I8259_S_CR); /* EOI */ | ||
164 | outb(0x60+2,I8259_M_CR); | ||
165 | } | ||
166 | restore_flags(flags); | ||
167 | } | ||
168 | |||
169 | static void end_mpc1211_irq(unsigned int irq) | ||
170 | { | ||
171 | enable_mpc1211_irq(irq); | ||
172 | } | ||
173 | |||
174 | static unsigned int startup_mpc1211_irq(unsigned int irq) | ||
175 | { | ||
176 | enable_mpc1211_irq(irq); | ||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static void shutdown_mpc1211_irq(unsigned int irq) | ||
181 | { | ||
182 | disable_mpc1211_irq(irq); | ||
183 | } | ||
184 | |||
185 | static struct hw_interrupt_type mpc1211_irq_type = { | ||
186 | .typename = "MPC1211-IRQ", | ||
187 | .startup = startup_mpc1211_irq, | ||
188 | .shutdown = shutdown_mpc1211_irq, | ||
189 | .enable = enable_mpc1211_irq, | ||
190 | .disable = disable_mpc1211_irq, | ||
191 | .ack = mask_and_ack_mpc1211, | ||
192 | .end = end_mpc1211_irq | ||
193 | }; | ||
194 | |||
195 | static void make_mpc1211_irq(unsigned int irq) | ||
196 | { | ||
197 | irq_desc[irq].handler = &mpc1211_irq_type; | ||
198 | irq_desc[irq].status = IRQ_DISABLED; | ||
199 | irq_desc[irq].action = 0; | ||
200 | irq_desc[irq].depth = 1; | ||
201 | disable_mpc1211_irq(irq); | ||
202 | } | ||
203 | |||
204 | int mpc1211_irq_demux(int irq) | ||
205 | { | ||
206 | unsigned int poll; | ||
207 | |||
208 | if( irq == 2 ) { | ||
209 | outb(0x0c,I8259_M_CR); | ||
210 | poll = inb(I8259_M_CR); | ||
211 | if(poll & 0x80) { | ||
212 | irq = (poll & 0x07); | ||
213 | } | ||
214 | if( irq == 2) { | ||
215 | outb(0x0c,I8259_S_CR); | ||
216 | poll = inb(I8259_S_CR); | ||
217 | irq = (poll & 0x07) + 8; | ||
218 | } | ||
219 | } | ||
220 | return irq; | ||
221 | } | ||
222 | |||
223 | void __init init_mpc1211_IRQ(void) | ||
224 | { | ||
225 | int i; | ||
226 | /* | ||
227 | * Super I/O (Just mimic PC): | ||
228 | * 1: keyboard | ||
229 | * 3: serial 1 | ||
230 | * 4: serial 0 | ||
231 | * 5: printer | ||
232 | * 6: floppy | ||
233 | * 8: rtc | ||
234 | * 10: lan | ||
235 | * 12: mouse | ||
236 | * 14: ide0 | ||
237 | * 15: ide1 | ||
238 | */ | ||
239 | |||
240 | pci_write_config(0,0,0,0x54, 0xb0b0002d); | ||
241 | outb(0x11, I8259_M_CR); /* mater icw1 edge trigger */ | ||
242 | outb(0x11, I8259_S_CR); /* slave icw1 edge trigger */ | ||
243 | outb(0x20, I8259_M_MR); /* m icw2 base vec 0x08 */ | ||
244 | outb(0x28, I8259_S_MR); /* s icw2 base vec 0x70 */ | ||
245 | outb(0x04, I8259_M_MR); /* m icw3 slave irq2 */ | ||
246 | outb(0x02, I8259_S_MR); /* s icw3 slave id */ | ||
247 | outb(0x01, I8259_M_MR); /* m icw4 non buf normal eoi*/ | ||
248 | outb(0x01, I8259_S_MR); /* s icw4 non buf normal eo1*/ | ||
249 | outb(0xfb, I8259_M_MR); /* disable irq0--irq7 */ | ||
250 | outb(0xff, I8259_S_MR); /* disable irq8--irq15 */ | ||
251 | |||
252 | for ( i=0; i < 16; i++) { | ||
253 | if(i != 2) { | ||
254 | make_mpc1211_irq(i); | ||
255 | } | ||
256 | } | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | Initialize the board | ||
261 | */ | ||
262 | |||
263 | |||
264 | static void delay (void) | ||
265 | { | ||
266 | volatile unsigned short tmp; | ||
267 | tmp = *(volatile unsigned short *) 0xa0000000; | ||
268 | } | ||
269 | |||
270 | static void delay1000 (void) | ||
271 | { | ||
272 | int i; | ||
273 | |||
274 | for (i=0; i<1000; i++) | ||
275 | delay (); | ||
276 | } | ||
277 | |||
278 | static int put_smb_blk(unsigned char *p, int address, int command, int no) | ||
279 | { | ||
280 | int temp; | ||
281 | int timeout; | ||
282 | int i; | ||
283 | |||
284 | outb(0xff, SMBHSTSTS); | ||
285 | temp = inb(SMBHSTSTS); | ||
286 | for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE); timeout++) { | ||
287 | delay1000(); | ||
288 | temp = inb(SMBHSTSTS); | ||
289 | } | ||
290 | if (timeout >= MAX_TIMEOUT){ | ||
291 | return -1; | ||
292 | } | ||
293 | |||
294 | outb(((address & 0x7f) << 1), SMBHSTADD); | ||
295 | outb(0xc0, SMBHSTCNT); | ||
296 | outb(command & 0xff, SMBHSTCMD); | ||
297 | outb(no & 0x1f, SMBHSTDAT0); | ||
298 | |||
299 | for(i = 1; i <= no; i++) { | ||
300 | outb(*p++, SMBBLKDAT); | ||
301 | } | ||
302 | outb(0xff, SMBHSTSTART); | ||
303 | |||
304 | temp = inb(SMBHSTSTS); | ||
305 | for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE)); timeout++) { | ||
306 | delay1000(); | ||
307 | temp = inb(SMBHSTSTS); | ||
308 | } | ||
309 | if (timeout >= MAX_TIMEOUT) { | ||
310 | return -2; | ||
311 | } | ||
312 | if ( temp & ALI15X3_STS_ERR ){ | ||
313 | return -3; | ||
314 | } | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * The Machine Vector | ||
320 | */ | ||
321 | |||
322 | struct sh_machine_vector mv_mpc1211 __initmv = { | ||
323 | .mv_nr_irqs = 48, | ||
324 | .mv_irq_demux = mpc1211_irq_demux, | ||
325 | .mv_init_irq = init_mpc1211_IRQ, | ||
326 | |||
327 | #ifdef CONFIG_HEARTBEAT | ||
328 | .mv_heartbeat = heartbeat_mpc1211, | ||
329 | #endif | ||
330 | }; | ||
331 | |||
332 | ALIAS_MV(mpc1211) | ||
333 | |||
334 | /* arch/sh/boards/mpc1211/rtc.c */ | ||
335 | void mpc1211_time_init(void); | ||
336 | |||
337 | int __init platform_setup(void) | ||
338 | { | ||
339 | unsigned char spd_buf[128]; | ||
340 | |||
341 | __set_io_port_base(PA_PCI_IO); | ||
342 | |||
343 | pci_write_config(0,0,0,0x54, 0xb0b00000); | ||
344 | |||
345 | do { | ||
346 | outb(ALI15X3_ABORT, SMBHSTCNT); | ||
347 | spd_buf[0] = 0x0c; | ||
348 | spd_buf[1] = 0x43; | ||
349 | spd_buf[2] = 0x7f; | ||
350 | spd_buf[3] = 0x03; | ||
351 | spd_buf[4] = 0x00; | ||
352 | spd_buf[5] = 0x03; | ||
353 | spd_buf[6] = 0x00; | ||
354 | } while (put_smb_blk(spd_buf, 0x69, 0, 7) < 0); | ||
355 | |||
356 | board_time_init = mpc1211_time_init; | ||
357 | |||
358 | return 0; | ||
359 | } | ||
360 | |||