diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /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/Makefile | 8 | ||||
-rw-r--r-- | arch/sh/boards/mpc1211/led.c | 64 | ||||
-rw-r--r-- | arch/sh/boards/mpc1211/pci.c | 296 | ||||
-rw-r--r-- | arch/sh/boards/mpc1211/rtc.c | 152 | ||||
-rw-r--r-- | arch/sh/boards/mpc1211/setup.c | 360 |
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 | |||
5 | obj-y := setup.o rtc.o led.o | ||
6 | |||
7 | obj-$(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 | |||
11 | static 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 */ | ||
27 | void 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 | |||
30 | static struct resource mpcpci_io_resource = { | ||
31 | "MPCPCI IO", | ||
32 | 0x00000000, | ||
33 | 0xffffffff, | ||
34 | IORESOURCE_IO | ||
35 | }; | ||
36 | |||
37 | static struct resource mpcpci_mem_resource = { | ||
38 | "MPCPCI mem", | ||
39 | 0x00000000, | ||
40 | 0xffffffff, | ||
41 | IORESOURCE_MEM | ||
42 | }; | ||
43 | |||
44 | static struct pci_ops pci_direct_conf1; | ||
45 | struct 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 | */ | ||
60 | static 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 | */ | ||
124 | static 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 | |||
156 | static struct pci_ops pci_direct_conf1 = { | ||
157 | .read = pci_conf1_read, | ||
158 | .write = pci_conf1_write, | ||
159 | }; | ||
160 | |||
161 | static 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 | } | ||
179 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, quirk_ali_ide_ports); | ||
180 | |||
181 | char * __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 | |||
191 | void __init pcibios_fixup_bus(struct pci_bus *b) | ||
192 | { | ||
193 | pci_read_bridge_bases(b); | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * IRQ functions | ||
198 | */ | ||
199 | static inline u8 bridge_swizzle(u8 pin, u8 slot) | ||
200 | { | ||
201 | return (((pin-1) + slot) % 4) + 1; | ||
202 | } | ||
203 | |||
204 | static inline u8 bridge_swizzle_pci_1(u8 pin, u8 slot) | ||
205 | { | ||
206 | return (((pin-1) - slot) & 3) + 1; | ||
207 | } | ||
208 | |||
209 | static 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 | |||
239 | static 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 | |||
270 | void __init pcibios_fixup_irqs(void) | ||
271 | { | ||
272 | pci_fixup_irqs(mpc1211_swizzle, map_mpc1211_irq); | ||
273 | } | ||
274 | |||
275 | void 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 */ | ||
23 | unsigned 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 | |||
64 | void 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 | */ | ||
82 | static 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 | |||
140 | int mpc1211_rtc_settimeofday(const struct timeval *tv) | ||
141 | { | ||
142 | unsigned long nowtime = tv->tv_sec; | ||
143 | |||
144 | return set_rtc_mmss(nowtime); | ||
145 | } | ||
146 | |||
147 | void 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 | |||
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 | |||