blob: 7c3d1d304157f48d70555fa4dc71bdc199aeb00d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Uwe Zeisbergerf30c2262006-10-03 23:01:26 +02002 * linux/arch/sh/boards/mpc1211/setup.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Copyright (C) 2002 Saito.K & Jeanne, Fujii.Y
5 *
6 */
7
Linus Torvalds1da177e2005-04-16 15:20:36 -07008#include <linux/init.h>
9#include <linux/irq.h>
10#include <linux/hdreg.h>
11#include <linux/ide.h>
12#include <linux/interrupt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <asm/io.h>
14#include <asm/machvec.h>
15#include <asm/mpc1211/mpc1211.h>
16#include <asm/mpc1211/pci.h>
17#include <asm/mpc1211/m1543c.h>
18
Linus Torvalds1da177e2005-04-16 15:20:36 -070019/* ALI15X3 SMBus address offsets */
20#define SMBHSTSTS (0 + 0x3100)
21#define SMBHSTCNT (1 + 0x3100)
22#define SMBHSTSTART (2 + 0x3100)
23#define SMBHSTCMD (7 + 0x3100)
24#define SMBHSTADD (3 + 0x3100)
25#define SMBHSTDAT0 (4 + 0x3100)
26#define SMBHSTDAT1 (5 + 0x3100)
27#define SMBBLKDAT (6 + 0x3100)
28
29/* Other settings */
30#define MAX_TIMEOUT 500 /* times 1/100 sec */
31
32/* ALI15X3 command constants */
33#define ALI15X3_ABORT 0x04
34#define ALI15X3_T_OUT 0x08
35#define ALI15X3_QUICK 0x00
36#define ALI15X3_BYTE 0x10
37#define ALI15X3_BYTE_DATA 0x20
38#define ALI15X3_WORD_DATA 0x30
39#define ALI15X3_BLOCK_DATA 0x40
40#define ALI15X3_BLOCK_CLR 0x80
41
42/* ALI15X3 status register bits */
43#define ALI15X3_STS_IDLE 0x04
44#define ALI15X3_STS_BUSY 0x08
45#define ALI15X3_STS_DONE 0x10
46#define ALI15X3_STS_DEV 0x20 /* device error */
47#define ALI15X3_STS_COLL 0x40 /* collision or no response */
48#define ALI15X3_STS_TERM 0x80 /* terminated by abort */
49#define ALI15X3_STS_ERR 0xE0 /* all the bad error bits */
50
Linus Torvalds1da177e2005-04-16 15:20:36 -070051static void __init pci_write_config(unsigned long busNo,
52 unsigned long devNo,
53 unsigned long fncNo,
54 unsigned long cnfAdd,
55 unsigned long cnfData)
56{
57 ctrl_outl((0x80000000
58 + ((busNo & 0xff) << 16)
59 + ((devNo & 0x1f) << 11)
60 + ((fncNo & 0x07) << 8)
61 + (cnfAdd & 0xfc)), PCIPAR);
62
63 ctrl_outl(cnfData, PCIPDR);
64}
65
66/*
67 Initialize IRQ setting
68*/
69
70static unsigned char m_irq_mask = 0xfb;
71static unsigned char s_irq_mask = 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
73static void disable_mpc1211_irq(unsigned int irq)
74{
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 if( irq < 8) {
76 m_irq_mask |= (1 << irq);
77 outb(m_irq_mask,I8259_M_MR);
78 } else {
79 s_irq_mask |= (1 << (irq - 8));
80 outb(s_irq_mask,I8259_S_MR);
81 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
83}
84
85static void enable_mpc1211_irq(unsigned int irq)
86{
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070094}
95
96static inline int mpc1211_irq_real(unsigned int irq)
97{
98 int value;
99 int irqmask;
100
101 if ( irq < 8) {
102 irqmask = 1<<irq;
103 outb(0x0b,I8259_M_CR); /* ISR register */
104 value = inb(I8259_M_CR) & irqmask;
105 outb(0x0a,I8259_M_CR); /* back ro the IPR reg */
106 return value;
107 }
108 irqmask = 1<<(irq - 8);
109 outb(0x0b,I8259_S_CR); /* ISR register */
110 value = inb(I8259_S_CR) & irqmask;
111 outb(0x0a,I8259_S_CR); /* back ro the IPR reg */
112 return value;
113}
114
115static void mask_and_ack_mpc1211(unsigned int irq)
116{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 if(irq < 8) {
118 if(m_irq_mask & (1<<irq)){
119 if(!mpc1211_irq_real(irq)){
Paul Mundt35f3c512006-10-06 15:31:16 +0900120 atomic_inc(&irq_err_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 printk("spurious 8259A interrupt: IRQ %x\n",irq);
122 }
123 } else {
124 m_irq_mask |= (1<<irq);
125 }
126 inb(I8259_M_MR); /* DUMMY */
127 outb(m_irq_mask,I8259_M_MR); /* disable */
128 outb(0x60+irq,I8259_M_CR); /* EOI */
129
130 } else {
131 if(s_irq_mask & (1<<(irq - 8))){
132 if(!mpc1211_irq_real(irq)){
Paul Mundt35f3c512006-10-06 15:31:16 +0900133 atomic_inc(&irq_err_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 printk("spurious 8259A interrupt: IRQ %x\n",irq);
135 }
136 } else {
137 s_irq_mask |= (1<<(irq - 8));
138 }
139 inb(I8259_S_MR); /* DUMMY */
140 outb(s_irq_mask,I8259_S_MR); /* disable */
141 outb(0x60+(irq-8),I8259_S_CR); /* EOI */
142 outb(0x60+2,I8259_M_CR);
143 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144}
145
146static void end_mpc1211_irq(unsigned int irq)
147{
148 enable_mpc1211_irq(irq);
149}
150
151static unsigned int startup_mpc1211_irq(unsigned int irq)
152{
153 enable_mpc1211_irq(irq);
154 return 0;
155}
156
157static void shutdown_mpc1211_irq(unsigned int irq)
158{
159 disable_mpc1211_irq(irq);
160}
161
162static struct hw_interrupt_type mpc1211_irq_type = {
163 .typename = "MPC1211-IRQ",
164 .startup = startup_mpc1211_irq,
165 .shutdown = shutdown_mpc1211_irq,
166 .enable = enable_mpc1211_irq,
167 .disable = disable_mpc1211_irq,
168 .ack = mask_and_ack_mpc1211,
169 .end = end_mpc1211_irq
170};
171
172static void make_mpc1211_irq(unsigned int irq)
173{
Ingo Molnard1bef4e2006-06-29 02:24:36 -0700174 irq_desc[irq].chip = &mpc1211_irq_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 irq_desc[irq].status = IRQ_DISABLED;
176 irq_desc[irq].action = 0;
177 irq_desc[irq].depth = 1;
178 disable_mpc1211_irq(irq);
179}
180
181int mpc1211_irq_demux(int irq)
182{
183 unsigned int poll;
184
185 if( irq == 2 ) {
186 outb(0x0c,I8259_M_CR);
187 poll = inb(I8259_M_CR);
188 if(poll & 0x80) {
189 irq = (poll & 0x07);
190 }
191 if( irq == 2) {
192 outb(0x0c,I8259_S_CR);
193 poll = inb(I8259_S_CR);
194 irq = (poll & 0x07) + 8;
195 }
196 }
197 return irq;
198}
199
Paul Mundt2c7834a2006-09-27 18:17:31 +0900200static void __init init_mpc1211_IRQ(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201{
202 int i;
203 /*
204 * Super I/O (Just mimic PC):
205 * 1: keyboard
206 * 3: serial 1
207 * 4: serial 0
208 * 5: printer
209 * 6: floppy
210 * 8: rtc
211 * 10: lan
212 * 12: mouse
213 * 14: ide0
214 * 15: ide1
215 */
216
217 pci_write_config(0,0,0,0x54, 0xb0b0002d);
218 outb(0x11, I8259_M_CR); /* mater icw1 edge trigger */
219 outb(0x11, I8259_S_CR); /* slave icw1 edge trigger */
220 outb(0x20, I8259_M_MR); /* m icw2 base vec 0x08 */
221 outb(0x28, I8259_S_MR); /* s icw2 base vec 0x70 */
222 outb(0x04, I8259_M_MR); /* m icw3 slave irq2 */
223 outb(0x02, I8259_S_MR); /* s icw3 slave id */
224 outb(0x01, I8259_M_MR); /* m icw4 non buf normal eoi*/
225 outb(0x01, I8259_S_MR); /* s icw4 non buf normal eo1*/
226 outb(0xfb, I8259_M_MR); /* disable irq0--irq7 */
227 outb(0xff, I8259_S_MR); /* disable irq8--irq15 */
228
229 for ( i=0; i < 16; i++) {
230 if(i != 2) {
231 make_mpc1211_irq(i);
232 }
233 }
234}
235
Paul Mundt959f85f2006-09-27 16:43:28 +0900236static void delay1000(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237{
238 int i;
239
240 for (i=0; i<1000; i++)
Paul Mundt959f85f2006-09-27 16:43:28 +0900241 ctrl_delay();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242}
243
244static int put_smb_blk(unsigned char *p, int address, int command, int no)
245{
246 int temp;
247 int timeout;
248 int i;
249
250 outb(0xff, SMBHSTSTS);
251 temp = inb(SMBHSTSTS);
252 for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE); timeout++) {
253 delay1000();
254 temp = inb(SMBHSTSTS);
255 }
256 if (timeout >= MAX_TIMEOUT){
257 return -1;
258 }
259
260 outb(((address & 0x7f) << 1), SMBHSTADD);
261 outb(0xc0, SMBHSTCNT);
262 outb(command & 0xff, SMBHSTCMD);
263 outb(no & 0x1f, SMBHSTDAT0);
264
265 for(i = 1; i <= no; i++) {
266 outb(*p++, SMBBLKDAT);
267 }
268 outb(0xff, SMBHSTSTART);
269
270 temp = inb(SMBHSTSTS);
271 for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE)); timeout++) {
272 delay1000();
273 temp = inb(SMBHSTSTS);
274 }
275 if (timeout >= MAX_TIMEOUT) {
276 return -2;
277 }
278 if ( temp & ALI15X3_STS_ERR ){
279 return -3;
280 }
281 return 0;
282}
283
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284/* arch/sh/boards/mpc1211/rtc.c */
285void mpc1211_time_init(void);
286
Paul Mundt2c7834a2006-09-27 18:17:31 +0900287static void __init mpc1211_setup(char **cmdline_p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
289 unsigned char spd_buf[128];
290
291 __set_io_port_base(PA_PCI_IO);
292
293 pci_write_config(0,0,0,0x54, 0xb0b00000);
294
295 do {
296 outb(ALI15X3_ABORT, SMBHSTCNT);
297 spd_buf[0] = 0x0c;
298 spd_buf[1] = 0x43;
299 spd_buf[2] = 0x7f;
300 spd_buf[3] = 0x03;
301 spd_buf[4] = 0x00;
302 spd_buf[5] = 0x03;
303 spd_buf[6] = 0x00;
304 } while (put_smb_blk(spd_buf, 0x69, 0, 7) < 0);
305
306 board_time_init = mpc1211_time_init;
307
308 return 0;
309}
310
Paul Mundt2c7834a2006-09-27 18:17:31 +0900311/*
312 * The Machine Vector
313 */
314struct sh_machine_vector mv_mpc1211 __initmv = {
315 .mv_name = "Interface MPC-1211(CTP/PCI/MPC-SH02)",
316 .mv_setup = mpc1211_setup,
317 .mv_nr_irqs = 48,
318 .mv_irq_demux = mpc1211_irq_demux,
319 .mv_init_irq = init_mpc1211_IRQ,
320
321#ifdef CONFIG_HEARTBEAT
322 .mv_heartbeat = heartbeat_mpc1211,
323#endif
324};
325ALIAS_MV(mpc1211)