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