aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/boards/mpc1211
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/sh/boards/mpc1211
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/sh/boards/mpc1211')
-rw-r--r--arch/sh/boards/mpc1211/Makefile8
-rw-r--r--arch/sh/boards/mpc1211/led.c64
-rw-r--r--arch/sh/boards/mpc1211/pci.c296
-rw-r--r--arch/sh/boards/mpc1211/rtc.c152
-rw-r--r--arch/sh/boards/mpc1211/setup.c360
5 files changed, 880 insertions, 0 deletions
diff --git a/arch/sh/boards/mpc1211/Makefile b/arch/sh/boards/mpc1211/Makefile
new file mode 100644
index 000000000000..1644ebed78cb
--- /dev/null
+++ b/arch/sh/boards/mpc1211/Makefile
@@ -0,0 +1,8 @@
1#
2# Makefile for the Interface (CTP/PCI/MPC-SH02) specific parts of the kernel
3#
4
5obj-y := setup.o rtc.o led.o
6
7obj-$(CONFIG_PCI) += pci.o
8
diff --git a/arch/sh/boards/mpc1211/led.c b/arch/sh/boards/mpc1211/led.c
new file mode 100644
index 000000000000..0a31beec3465
--- /dev/null
+++ b/arch/sh/boards/mpc1211/led.c
@@ -0,0 +1,64 @@
1/*
2 * linux/arch/sh/kernel/led_mpc1211.c
3 *
4 * Copyright (C) 2001 Saito.K & Jeanne
5 *
6 * This file contains Interface MPC-1211 specific LED code.
7 */
8
9#include <linux/config.h>
10
11static void mach_led(int position, int value)
12{
13 volatile unsigned char* p = (volatile unsigned char*)0xa2000000;
14
15 if (value) {
16 *p |= 1;
17 } else {
18 *p &= ~1;
19 }
20}
21
22#ifdef CONFIG_HEARTBEAT
23
24#include <linux/sched.h>
25
26/* Cycle the LED's in the clasic Knightrider/Sun pattern */
27void heartbeat_mpc1211(void)
28{
29 static unsigned int cnt = 0, period = 0;
30 volatile unsigned char* p = (volatile unsigned char*)0xa2000000;
31 static unsigned bit = 0, up = 1;
32
33 cnt += 1;
34 if (cnt < period) {
35 return;
36 }
37
38 cnt = 0;
39
40 /* Go through the points (roughly!):
41 * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
42 */
43 period = 110 - ( (300<<FSHIFT)/
44 ((avenrun[0]/5) + (3<<FSHIFT)) );
45
46 if (up) {
47 if (bit == 7) {
48 bit--;
49 up=0;
50 } else {
51 bit ++;
52 }
53 } else {
54 if (bit == 0) {
55 bit++;
56 up=1;
57 } else {
58 bit--;
59 }
60 }
61 *p = 1<<bit;
62
63}
64#endif /* CONFIG_HEARTBEAT */
diff --git a/arch/sh/boards/mpc1211/pci.c b/arch/sh/boards/mpc1211/pci.c
new file mode 100644
index 000000000000..ba3a65439752
--- /dev/null
+++ b/arch/sh/boards/mpc1211/pci.c
@@ -0,0 +1,296 @@
1/*
2 * Low-Level PCI Support for the MPC-1211(CTP/PCI/MPC-SH02)
3 *
4 * (c) 2002-2003 Saito.K & Jeanne
5 *
6 * Dustin McIntire (dustin@sensoria.com)
7 * Derived from arch/i386/kernel/pci-*.c which bore the message:
8 * (c) 1999--2000 Martin Mares <mj@ucw.cz>
9 *
10 * May be copied or modified under the terms of the GNU General Public
11 * License. See linux/COPYING for more information.
12 *
13 */
14#include <linux/config.h>
15#include <linux/types.h>
16#include <linux/kernel.h>
17#include <linux/init.h>
18#include <linux/delay.h>
19#include <linux/pci.h>
20#include <linux/sched.h>
21#include <linux/ioport.h>
22#include <linux/errno.h>
23#include <linux/irq.h>
24#include <linux/interrupt.h>
25
26#include <asm/machvec.h>
27#include <asm/io.h>
28#include <asm/mpc1211/pci.h>
29
30static struct resource mpcpci_io_resource = {
31 "MPCPCI IO",
32 0x00000000,
33 0xffffffff,
34 IORESOURCE_IO
35};
36
37static struct resource mpcpci_mem_resource = {
38 "MPCPCI mem",
39 0x00000000,
40 0xffffffff,
41 IORESOURCE_MEM
42};
43
44static struct pci_ops pci_direct_conf1;
45struct pci_channel board_pci_channels[] = {
46 {&pci_direct_conf1, &mpcpci_io_resource, &mpcpci_mem_resource, 0, 256},
47 {NULL, NULL, NULL, 0, 0},
48};
49
50/*
51 * Direct access to PCI hardware...
52 */
53
54
55#define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
56
57/*
58 * Functions for accessing PCI configuration space with type 1 accesses
59 */
60static int pci_conf1_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
61{
62 u32 word;
63 unsigned long flags;
64
65 /*
66 * PCIPDR may only be accessed as 32 bit words,
67 * so we must do byte alignment by hand
68 */
69 local_irq_save(flags);
70 writel(CONFIG_CMD(bus,devfn,where), PCIPAR);
71 word = readl(PCIPDR);
72 local_irq_restore(flags);
73
74 switch (size) {
75 case 1:
76 switch (where & 0x3) {
77 case 3:
78 *value = (u8)(word >> 24);
79 break;
80 case 2:
81 *value = (u8)(word >> 16);
82 break;
83 case 1:
84 *value = (u8)(word >> 8);
85 break;
86 default:
87 *value = (u8)word;
88 break;
89 }
90 break;
91 case 2:
92 switch (where & 0x3) {
93 case 3:
94 *value = (u16)(word >> 24);
95 local_irq_save(flags);
96 writel(CONFIG_CMD(bus,devfn,(where+1)), PCIPAR);
97 word = readl(PCIPDR);
98 local_irq_restore(flags);
99 *value |= ((word & 0xff) << 8);
100 break;
101 case 2:
102 *value = (u16)(word >> 16);
103 break;
104 case 1:
105 *value = (u16)(word >> 8);
106 break;
107 default:
108 *value = (u16)word;
109 break;
110 }
111 break;
112 case 4:
113 *value = word;
114 break;
115 }
116 PCIDBG(4,"pci_conf1_read@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),*value);
117 return PCIBIOS_SUCCESSFUL;
118}
119
120/*
121 * Since MPC-1211 only does 32bit access we'll have to do a read,mask,write operation.
122 * We'll allow an odd byte offset, though it should be illegal.
123 */
124static int pci_conf1_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
125{
126 u32 word,mask = 0;
127 unsigned long flags;
128 u32 shift = (where & 3) * 8;
129
130 if(size == 1) {
131 mask = ((1 << 8) - 1) << shift; // create the byte mask
132 } else if(size == 2){
133 if(shift == 24)
134 return PCIBIOS_BAD_REGISTER_NUMBER;
135 mask = ((1 << 16) - 1) << shift; // create the word mask
136 }
137 local_irq_save(flags);
138 writel(CONFIG_CMD(bus,devfn,where), PCIPAR);
139 if(size == 4){
140 writel(value, PCIPDR);
141 local_irq_restore(flags);
142 PCIDBG(4,"pci_conf1_write@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),value);
143 return PCIBIOS_SUCCESSFUL;
144 }
145 word = readl(PCIPDR);
146 word &= ~mask;
147 word |= ((value << shift) & mask);
148 writel(word, PCIPDR);
149 local_irq_restore(flags);
150 PCIDBG(4,"pci_conf1_write@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),word);
151 return PCIBIOS_SUCCESSFUL;
152}
153
154#undef CONFIG_CMD
155
156static struct pci_ops pci_direct_conf1 = {
157 .read = pci_conf1_read,
158 .write = pci_conf1_write,
159};
160
161static void __devinit quirk_ali_ide_ports(struct pci_dev *dev)
162{
163 dev->resource[0].start = 0x1f0;
164 dev->resource[0].end = 0x1f7;
165 dev->resource[0].flags = IORESOURCE_IO;
166 dev->resource[1].start = 0x3f6;
167 dev->resource[1].end = 0x3f6;
168 dev->resource[1].flags = IORESOURCE_IO;
169 dev->resource[2].start = 0x170;
170 dev->resource[2].end = 0x177;
171 dev->resource[2].flags = IORESOURCE_IO;
172 dev->resource[3].start = 0x376;
173 dev->resource[3].end = 0x376;
174 dev->resource[3].flags = IORESOURCE_IO;
175 dev->resource[4].start = 0xf000;
176 dev->resource[4].end = 0xf00f;
177 dev->resource[4].flags = IORESOURCE_IO;
178}
179DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, quirk_ali_ide_ports);
180
181char * __devinit pcibios_setup(char *str)
182{
183 return str;
184}
185
186/*
187 * Called after each bus is probed, but before its children
188 * are examined.
189 */
190
191void __init pcibios_fixup_bus(struct pci_bus *b)
192{
193 pci_read_bridge_bases(b);
194}
195
196/*
197 * IRQ functions
198 */
199static inline u8 bridge_swizzle(u8 pin, u8 slot)
200{
201 return (((pin-1) + slot) % 4) + 1;
202}
203
204static inline u8 bridge_swizzle_pci_1(u8 pin, u8 slot)
205{
206 return (((pin-1) - slot) & 3) + 1;
207}
208
209static u8 __init mpc1211_swizzle(struct pci_dev *dev, u8 *pinp)
210{
211 unsigned long flags;
212 u8 pin = *pinp;
213 u32 word;
214
215 for ( ; dev->bus->self; dev = dev->bus->self) {
216 if (!pin)
217 continue;
218
219 if (dev->bus->number == 1) {
220 local_irq_save(flags);
221 writel(0x80000000 | 0x2c, PCIPAR);
222 word = readl(PCIPDR);
223 local_irq_restore(flags);
224 word >>= 16;
225
226 if (word == 0x0001)
227 pin = bridge_swizzle_pci_1(pin, PCI_SLOT(dev->devfn));
228 else
229 pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
230 } else
231 pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
232 }
233
234 *pinp = pin;
235
236 return PCI_SLOT(dev->devfn);
237}
238
239static int __init map_mpc1211_irq(struct pci_dev *dev, u8 slot, u8 pin)
240{
241 int irq = -1;
242
243 /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */
244 if (dev->bus->number == 0) {
245 switch (slot) {
246 case 13: irq = 9; break; /* USB */
247 case 22: irq = 10; break; /* LAN */
248 default: irq = 0; break;
249 }
250 } else {
251 switch (pin) {
252 case 0: irq = 0; break;
253 case 1: irq = 7; break;
254 case 2: irq = 9; break;
255 case 3: irq = 10; break;
256 case 4: irq = 11; break;
257 }
258 }
259
260 if( irq < 0 ) {
261 PCIDBG(3, "PCI: Error mapping IRQ on device %s\n", pci_name(dev));
262 return irq;
263 }
264
265 PCIDBG(2, "Setting IRQ for slot %s to %d\n", pci_name(dev), irq);
266
267 return irq;
268}
269
270void __init pcibios_fixup_irqs(void)
271{
272 pci_fixup_irqs(mpc1211_swizzle, map_mpc1211_irq);
273}
274
275void pcibios_align_resource(void *data, struct resource *res,
276 unsigned long size, unsigned long align)
277{
278 unsigned long start = res->start;
279
280 if (res->flags & IORESOURCE_IO) {
281 if (start >= 0x10000UL) {
282 if ((start & 0xffffUL) < 0x4000UL) {
283 start = (start & 0xffff0000UL) + 0x4000UL;
284 } else if ((start & 0xffffUL) >= 0xf000UL) {
285 start = (start & 0xffff0000UL) + 0x10000UL;
286 }
287 res->start = start;
288 } else {
289 if (start & 0x300) {
290 start = (start + 0x3ff) & ~0x3ff;
291 res->start = start;
292 }
293 }
294 }
295}
296
diff --git a/arch/sh/boards/mpc1211/rtc.c b/arch/sh/boards/mpc1211/rtc.c
new file mode 100644
index 000000000000..4d100f048072
--- /dev/null
+++ b/arch/sh/boards/mpc1211/rtc.c
@@ -0,0 +1,152 @@
1/*
2 * linux/arch/sh/kernel/rtc-mpc1211.c -- MPC-1211 on-chip RTC support
3 *
4 * Copyright (C) 2002 Saito.K & Jeanne
5 *
6 */
7
8#include <linux/init.h>
9#include <linux/kernel.h>
10#include <linux/sched.h>
11#include <linux/time.h>
12#include <linux/mc146818rtc.h>
13
14#ifndef BCD_TO_BIN
15#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
16#endif
17
18#ifndef BIN_TO_BCD
19#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
20#endif
21
22/* arc/i386/kernel/time.c */
23unsigned long get_cmos_time(void)
24{
25 unsigned int year, mon, day, hour, min, sec;
26 int i;
27
28 spin_lock(&rtc_lock);
29 /* The Linux interpretation of the CMOS clock register contents:
30 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
31 * RTC registers show the second which has precisely just started.
32 * Let's hope other operating systems interpret the RTC the same way.
33 */
34 /* read RTC exactly on falling edge of update flag */
35 for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
36 if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
37 break;
38 for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
39 if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
40 break;
41 do { /* Isn't this overkill ? UIP above should guarantee consistency */
42 sec = CMOS_READ(RTC_SECONDS);
43 min = CMOS_READ(RTC_MINUTES);
44 hour = CMOS_READ(RTC_HOURS);
45 day = CMOS_READ(RTC_DAY_OF_MONTH);
46 mon = CMOS_READ(RTC_MONTH);
47 year = CMOS_READ(RTC_YEAR);
48 } while (sec != CMOS_READ(RTC_SECONDS));
49 if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
50 {
51 BCD_TO_BIN(sec);
52 BCD_TO_BIN(min);
53 BCD_TO_BIN(hour);
54 BCD_TO_BIN(day);
55 BCD_TO_BIN(mon);
56 BCD_TO_BIN(year);
57 }
58 spin_unlock(&rtc_lock);
59 if ((year += 1900) < 1970)
60 year += 100;
61 return mktime(year, mon, day, hour, min, sec);
62}
63
64void mpc1211_rtc_gettimeofday(struct timeval *tv)
65{
66
67 tv->tv_sec = get_cmos_time();
68 tv->tv_usec = 0;
69}
70
71/* arc/i386/kernel/time.c */
72/*
73 * In order to set the CMOS clock precisely, set_rtc_mmss has to be
74 * called 500 ms after the second nowtime has started, because when
75 * nowtime is written into the registers of the CMOS clock, it will
76 * jump to the next second precisely 500 ms later. Check the Motorola
77 * MC146818A or Dallas DS12887 data sheet for details.
78 *
79 * BUG: This routine does not handle hour overflow properly; it just
80 * sets the minutes. Usually you'll only notice that after reboot!
81 */
82static int set_rtc_mmss(unsigned long nowtime)
83{
84 int retval = 0;
85 int real_seconds, real_minutes, cmos_minutes;
86 unsigned char save_control, save_freq_select;
87
88 /* gets recalled with irq locally disabled */
89 spin_lock(&rtc_lock);
90 save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
91 CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
92
93 save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
94 CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
95
96 cmos_minutes = CMOS_READ(RTC_MINUTES);
97 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
98 BCD_TO_BIN(cmos_minutes);
99
100 /*
101 * since we're only adjusting minutes and seconds,
102 * don't interfere with hour overflow. This avoids
103 * messing with unknown time zones but requires your
104 * RTC not to be off by more than 15 minutes
105 */
106 real_seconds = nowtime % 60;
107 real_minutes = nowtime / 60;
108 if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
109 real_minutes += 30; /* correct for half hour time zone */
110 real_minutes %= 60;
111
112 if (abs(real_minutes - cmos_minutes) < 30) {
113 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
114 BIN_TO_BCD(real_seconds);
115 BIN_TO_BCD(real_minutes);
116 }
117 CMOS_WRITE(real_seconds,RTC_SECONDS);
118 CMOS_WRITE(real_minutes,RTC_MINUTES);
119 } else {
120 printk(KERN_WARNING
121 "set_rtc_mmss: can't update from %d to %d\n",
122 cmos_minutes, real_minutes);
123 retval = -1;
124 }
125
126 /* The following flags have to be released exactly in this order,
127 * otherwise the DS12887 (popular MC146818A clone with integrated
128 * battery and quartz) will not reset the oscillator and will not
129 * update precisely 500 ms later. You won't find this mentioned in
130 * the Dallas Semiconductor data sheets, but who believes data
131 * sheets anyway ... -- Markus Kuhn
132 */
133 CMOS_WRITE(save_control, RTC_CONTROL);
134 CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
135 spin_unlock(&rtc_lock);
136
137 return retval;
138}
139
140int mpc1211_rtc_settimeofday(const struct timeval *tv)
141{
142 unsigned long nowtime = tv->tv_sec;
143
144 return set_rtc_mmss(nowtime);
145}
146
147void mpc1211_time_init(void)
148{
149 rtc_get_time = mpc1211_rtc_gettimeofday;
150 rtc_set_time = mpc1211_rtc_settimeofday;
151}
152
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
54const char *get_system_type(void)
55{
56 return "Interface MPC-1211(CTP/PCI/MPC-SH02)";
57}
58
59static 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
78static unsigned char m_irq_mask = 0xfb;
79static unsigned char s_irq_mask = 0xff;
80volatile unsigned long irq_err_count;
81
82static 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
98static 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
114static 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
133static 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
169static void end_mpc1211_irq(unsigned int irq)
170{
171 enable_mpc1211_irq(irq);
172}
173
174static unsigned int startup_mpc1211_irq(unsigned int irq)
175{
176 enable_mpc1211_irq(irq);
177 return 0;
178}
179
180static void shutdown_mpc1211_irq(unsigned int irq)
181{
182 disable_mpc1211_irq(irq);
183}
184
185static 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
195static 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
204int 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
223void __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
264static void delay (void)
265{
266 volatile unsigned short tmp;
267 tmp = *(volatile unsigned short *) 0xa0000000;
268}
269
270static void delay1000 (void)
271{
272 int i;
273
274 for (i=0; i<1000; i++)
275 delay ();
276}
277
278static 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
322struct 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
332ALIAS_MV(mpc1211)
333
334/* arch/sh/boards/mpc1211/rtc.c */
335void mpc1211_time_init(void);
336
337int __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