diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/sh/boards/mpc1211 |
Linux-2.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 00000000000..1644ebed78c --- /dev/null +++ b/arch/sh/boards/mpc1211/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the Interface (CTP/PCI/MPC-SH02) specific parts of the kernel +# + +obj-y := setup.o rtc.o led.o + +obj-$(CONFIG_PCI) += pci.o + diff --git a/arch/sh/boards/mpc1211/led.c b/arch/sh/boards/mpc1211/led.c new file mode 100644 index 00000000000..0a31beec346 --- /dev/null +++ b/arch/sh/boards/mpc1211/led.c @@ -0,0 +1,64 @@ +/* + * linux/arch/sh/kernel/led_mpc1211.c + * + * Copyright (C) 2001 Saito.K & Jeanne + * + * This file contains Interface MPC-1211 specific LED code. + */ + +#include <linux/config.h> + +static void mach_led(int position, int value) +{ + volatile unsigned char* p = (volatile unsigned char*)0xa2000000; + + if (value) { + *p |= 1; + } else { + *p &= ~1; + } +} + +#ifdef CONFIG_HEARTBEAT + +#include <linux/sched.h> + +/* Cycle the LED's in the clasic Knightrider/Sun pattern */ +void heartbeat_mpc1211(void) +{ + static unsigned int cnt = 0, period = 0; + volatile unsigned char* p = (volatile unsigned char*)0xa2000000; + static unsigned bit = 0, up = 1; + + cnt += 1; + if (cnt < period) { + return; + } + + cnt = 0; + + /* Go through the points (roughly!): + * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110 + */ + period = 110 - ( (300<<FSHIFT)/ + ((avenrun[0]/5) + (3<<FSHIFT)) ); + + if (up) { + if (bit == 7) { + bit--; + up=0; + } else { + bit ++; + } + } else { + if (bit == 0) { + bit++; + up=1; + } else { + bit--; + } + } + *p = 1<<bit; + +} +#endif /* CONFIG_HEARTBEAT */ diff --git a/arch/sh/boards/mpc1211/pci.c b/arch/sh/boards/mpc1211/pci.c new file mode 100644 index 00000000000..ba3a6543975 --- /dev/null +++ b/arch/sh/boards/mpc1211/pci.c @@ -0,0 +1,296 @@ +/* + * Low-Level PCI Support for the MPC-1211(CTP/PCI/MPC-SH02) + * + * (c) 2002-2003 Saito.K & Jeanne + * + * Dustin McIntire (dustin@sensoria.com) + * Derived from arch/i386/kernel/pci-*.c which bore the message: + * (c) 1999--2000 Martin Mares <mj@ucw.cz> + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + */ +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/sched.h> +#include <linux/ioport.h> +#include <linux/errno.h> +#include <linux/irq.h> +#include <linux/interrupt.h> + +#include <asm/machvec.h> +#include <asm/io.h> +#include <asm/mpc1211/pci.h> + +static struct resource mpcpci_io_resource = { + "MPCPCI IO", + 0x00000000, + 0xffffffff, + IORESOURCE_IO +}; + +static struct resource mpcpci_mem_resource = { + "MPCPCI mem", + 0x00000000, + 0xffffffff, + IORESOURCE_MEM +}; + +static struct pci_ops pci_direct_conf1; +struct pci_channel board_pci_channels[] = { + {&pci_direct_conf1, &mpcpci_io_resource, &mpcpci_mem_resource, 0, 256}, + {NULL, NULL, NULL, 0, 0}, +}; + +/* + * Direct access to PCI hardware... + */ + + +#define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3)) + +/* + * Functions for accessing PCI configuration space with type 1 accesses + */ +static int pci_conf1_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) +{ + u32 word; + unsigned long flags; + + /* + * PCIPDR may only be accessed as 32 bit words, + * so we must do byte alignment by hand + */ + local_irq_save(flags); + writel(CONFIG_CMD(bus,devfn,where), PCIPAR); + word = readl(PCIPDR); + local_irq_restore(flags); + + switch (size) { + case 1: + switch (where & 0x3) { + case 3: + *value = (u8)(word >> 24); + break; + case 2: + *value = (u8)(word >> 16); + break; + case 1: + *value = (u8)(word >> 8); + break; + default: + *value = (u8)word; + break; + } + break; + case 2: + switch (where & 0x3) { + case 3: + *value = (u16)(word >> 24); + local_irq_save(flags); + writel(CONFIG_CMD(bus,devfn,(where+1)), PCIPAR); + word = readl(PCIPDR); + local_irq_restore(flags); + *value |= ((word & 0xff) << 8); + break; + case 2: + *value = (u16)(word >> 16); + break; + case 1: + *value = (u16)(word >> 8); + break; + default: + *value = (u16)word; + break; + } + break; + case 4: + *value = word; + break; + } + PCIDBG(4,"pci_conf1_read@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),*value); + return PCIBIOS_SUCCESSFUL; +} + +/* + * Since MPC-1211 only does 32bit access we'll have to do a read,mask,write operation. + * We'll allow an odd byte offset, though it should be illegal. + */ +static int pci_conf1_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) +{ + u32 word,mask = 0; + unsigned long flags; + u32 shift = (where & 3) * 8; + + if(size == 1) { + mask = ((1 << 8) - 1) << shift; // create the byte mask + } else if(size == 2){ + if(shift == 24) + return PCIBIOS_BAD_REGISTER_NUMBER; + mask = ((1 << 16) - 1) << shift; // create the word mask + } + local_irq_save(flags); + writel(CONFIG_CMD(bus,devfn,where), PCIPAR); + if(size == 4){ + writel(value, PCIPDR); + local_irq_restore(flags); + PCIDBG(4,"pci_conf1_write@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),value); + return PCIBIOS_SUCCESSFUL; + } + word = readl(PCIPDR); + word &= ~mask; + word |= ((value << shift) & mask); + writel(word, PCIPDR); + local_irq_restore(flags); + PCIDBG(4,"pci_conf1_write@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),word); + return PCIBIOS_SUCCESSFUL; +} + +#undef CONFIG_CMD + +static struct pci_ops pci_direct_conf1 = { + .read = pci_conf1_read, + .write = pci_conf1_write, +}; + +static void __devinit quirk_ali_ide_ports(struct pci_dev *dev) +{ + dev->resource[0].start = 0x1f0; + dev->resource[0].end = 0x1f7; + dev->resource[0].flags = IORESOURCE_IO; + dev->resource[1].start = 0x3f6; + dev->resource[1].end = 0x3f6; + dev->resource[1].flags = IORESOURCE_IO; + dev->resource[2].start = 0x170; + dev->resource[2].end = 0x177; + dev->resource[2].flags = IORESOURCE_IO; + dev->resource[3].start = 0x376; + dev->resource[3].end = 0x376; + dev->resource[3].flags = IORESOURCE_IO; + dev->resource[4].start = 0xf000; + dev->resource[4].end = 0xf00f; + dev->resource[4].flags = IORESOURCE_IO; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, quirk_ali_ide_ports); + +char * __devinit pcibios_setup(char *str) +{ + return str; +} + +/* + * Called after each bus is probed, but before its children + * are examined. + */ + +void __init pcibios_fixup_bus(struct pci_bus *b) +{ + pci_read_bridge_bases(b); +} + +/* + * IRQ functions + */ +static inline u8 bridge_swizzle(u8 pin, u8 slot) +{ + return (((pin-1) + slot) % 4) + 1; +} + +static inline u8 bridge_swizzle_pci_1(u8 pin, u8 slot) +{ + return (((pin-1) - slot) & 3) + 1; +} + +static u8 __init mpc1211_swizzle(struct pci_dev *dev, u8 *pinp) +{ + unsigned long flags; + u8 pin = *pinp; + u32 word; + + for ( ; dev->bus->self; dev = dev->bus->self) { + if (!pin) + continue; + + if (dev->bus->number == 1) { + local_irq_save(flags); + writel(0x80000000 | 0x2c, PCIPAR); + word = readl(PCIPDR); + local_irq_restore(flags); + word >>= 16; + + if (word == 0x0001) + pin = bridge_swizzle_pci_1(pin, PCI_SLOT(dev->devfn)); + else + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + } else + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + } + + *pinp = pin; + + return PCI_SLOT(dev->devfn); +} + +static int __init map_mpc1211_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + int irq = -1; + + /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */ + if (dev->bus->number == 0) { + switch (slot) { + case 13: irq = 9; break; /* USB */ + case 22: irq = 10; break; /* LAN */ + default: irq = 0; break; + } + } else { + switch (pin) { + case 0: irq = 0; break; + case 1: irq = 7; break; + case 2: irq = 9; break; + case 3: irq = 10; break; + case 4: irq = 11; break; + } + } + + if( irq < 0 ) { + PCIDBG(3, "PCI: Error mapping IRQ on device %s\n", pci_name(dev)); + return irq; + } + + PCIDBG(2, "Setting IRQ for slot %s to %d\n", pci_name(dev), irq); + + return irq; +} + +void __init pcibios_fixup_irqs(void) +{ + pci_fixup_irqs(mpc1211_swizzle, map_mpc1211_irq); +} + +void pcibios_align_resource(void *data, struct resource *res, + unsigned long size, unsigned long align) +{ + unsigned long start = res->start; + + if (res->flags & IORESOURCE_IO) { + if (start >= 0x10000UL) { + if ((start & 0xffffUL) < 0x4000UL) { + start = (start & 0xffff0000UL) + 0x4000UL; + } else if ((start & 0xffffUL) >= 0xf000UL) { + start = (start & 0xffff0000UL) + 0x10000UL; + } + res->start = start; + } else { + if (start & 0x300) { + start = (start + 0x3ff) & ~0x3ff; + res->start = start; + } + } + } +} + diff --git a/arch/sh/boards/mpc1211/rtc.c b/arch/sh/boards/mpc1211/rtc.c new file mode 100644 index 00000000000..4d100f04807 --- /dev/null +++ b/arch/sh/boards/mpc1211/rtc.c @@ -0,0 +1,152 @@ +/* + * linux/arch/sh/kernel/rtc-mpc1211.c -- MPC-1211 on-chip RTC support + * + * Copyright (C) 2002 Saito.K & Jeanne + * + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/mc146818rtc.h> + +#ifndef BCD_TO_BIN +#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) +#endif + +#ifndef BIN_TO_BCD +#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) +#endif + +/* arc/i386/kernel/time.c */ +unsigned long get_cmos_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + int i; + + spin_lock(&rtc_lock); + /* The Linux interpretation of the CMOS clock register contents: + * When the Update-In-Progress (UIP) flag goes from 1 to 0, the + * RTC registers show the second which has precisely just started. + * Let's hope other operating systems interpret the RTC the same way. + */ + /* read RTC exactly on falling edge of update flag */ + for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ + if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) + break; + for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ + if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) + break; + do { /* Isn't this overkill ? UIP above should guarantee consistency */ + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + } while (sec != CMOS_READ(RTC_SECONDS)); + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + } + spin_unlock(&rtc_lock); + if ((year += 1900) < 1970) + year += 100; + return mktime(year, mon, day, hour, min, sec); +} + +void mpc1211_rtc_gettimeofday(struct timeval *tv) +{ + + tv->tv_sec = get_cmos_time(); + tv->tv_usec = 0; +} + +/* arc/i386/kernel/time.c */ +/* + * In order to set the CMOS clock precisely, set_rtc_mmss has to be + * called 500 ms after the second nowtime has started, because when + * nowtime is written into the registers of the CMOS clock, it will + * jump to the next second precisely 500 ms later. Check the Motorola + * MC146818A or Dallas DS12887 data sheet for details. + * + * BUG: This routine does not handle hour overflow properly; it just + * sets the minutes. Usually you'll only notice that after reboot! + */ +static int set_rtc_mmss(unsigned long nowtime) +{ + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + unsigned char save_control, save_freq_select; + + /* gets recalled with irq locally disabled */ + spin_lock(&rtc_lock); + save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + cmos_minutes = CMOS_READ(RTC_MINUTES); + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + BCD_TO_BIN(cmos_minutes); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + } + CMOS_WRITE(real_seconds,RTC_SECONDS); + CMOS_WRITE(real_minutes,RTC_MINUTES); + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } + + /* The following flags have to be released exactly in this order, + * otherwise the DS12887 (popular MC146818A clone with integrated + * battery and quartz) will not reset the oscillator and will not + * update precisely 500 ms later. You won't find this mentioned in + * the Dallas Semiconductor data sheets, but who believes data + * sheets anyway ... -- Markus Kuhn + */ + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock(&rtc_lock); + + return retval; +} + +int mpc1211_rtc_settimeofday(const struct timeval *tv) +{ + unsigned long nowtime = tv->tv_sec; + + return set_rtc_mmss(nowtime); +} + +void mpc1211_time_init(void) +{ + rtc_get_time = mpc1211_rtc_gettimeofday; + rtc_set_time = mpc1211_rtc_settimeofday; +} + diff --git a/arch/sh/boards/mpc1211/setup.c b/arch/sh/boards/mpc1211/setup.c new file mode 100644 index 00000000000..2bb581b9168 --- /dev/null +++ b/arch/sh/boards/mpc1211/setup.c @@ -0,0 +1,360 @@ +/* + * linux/arch/sh/board/mpc1211/setup.c + * + * Copyright (C) 2002 Saito.K & Jeanne, Fujii.Y + * + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/hdreg.h> +#include <linux/ide.h> +#include <linux/interrupt.h> + +#include <asm/io.h> +#include <asm/machvec.h> +#include <asm/mpc1211/mpc1211.h> +#include <asm/mpc1211/pci.h> +#include <asm/mpc1211/m1543c.h> + + +/* ALI15X3 SMBus address offsets */ +#define SMBHSTSTS (0 + 0x3100) +#define SMBHSTCNT (1 + 0x3100) +#define SMBHSTSTART (2 + 0x3100) +#define SMBHSTCMD (7 + 0x3100) +#define SMBHSTADD (3 + 0x3100) +#define SMBHSTDAT0 (4 + 0x3100) +#define SMBHSTDAT1 (5 + 0x3100) +#define SMBBLKDAT (6 + 0x3100) + +/* Other settings */ +#define MAX_TIMEOUT 500 /* times 1/100 sec */ + +/* ALI15X3 command constants */ +#define ALI15X3_ABORT 0x04 +#define ALI15X3_T_OUT 0x08 +#define ALI15X3_QUICK 0x00 +#define ALI15X3_BYTE 0x10 +#define ALI15X3_BYTE_DATA 0x20 +#define ALI15X3_WORD_DATA 0x30 +#define ALI15X3_BLOCK_DATA 0x40 +#define ALI15X3_BLOCK_CLR 0x80 + +/* ALI15X3 status register bits */ +#define ALI15X3_STS_IDLE 0x04 +#define ALI15X3_STS_BUSY 0x08 +#define ALI15X3_STS_DONE 0x10 +#define ALI15X3_STS_DEV 0x20 /* device error */ +#define ALI15X3_STS_COLL 0x40 /* collision or no response */ +#define ALI15X3_STS_TERM 0x80 /* terminated by abort */ +#define ALI15X3_STS_ERR 0xE0 /* all the bad error bits */ + +const char *get_system_type(void) +{ + return "Interface MPC-1211(CTP/PCI/MPC-SH02)"; +} + +static void __init pci_write_config(unsigned long busNo, + unsigned long devNo, + unsigned long fncNo, + unsigned long cnfAdd, + unsigned long cnfData) +{ + ctrl_outl((0x80000000 + + ((busNo & 0xff) << 16) + + ((devNo & 0x1f) << 11) + + ((fncNo & 0x07) << 8) + + (cnfAdd & 0xfc)), PCIPAR); + + ctrl_outl(cnfData, PCIPDR); +} + +/* + Initialize IRQ setting +*/ + +static unsigned char m_irq_mask = 0xfb; +static unsigned char s_irq_mask = 0xff; +volatile unsigned long irq_err_count; + +static void disable_mpc1211_irq(unsigned int irq) +{ + unsigned long flags; + + save_and_cli(flags); + if( irq < 8) { + m_irq_mask |= (1 << irq); + outb(m_irq_mask,I8259_M_MR); + } else { + s_irq_mask |= (1 << (irq - 8)); + outb(s_irq_mask,I8259_S_MR); + } + restore_flags(flags); + +} + +static void enable_mpc1211_irq(unsigned int irq) +{ + unsigned long flags; + + save_and_cli(flags); + + if( irq < 8) { + m_irq_mask &= ~(1 << irq); + outb(m_irq_mask,I8259_M_MR); + } else { + s_irq_mask &= ~(1 << (irq - 8)); + outb(s_irq_mask,I8259_S_MR); + } + restore_flags(flags); +} + +static inline int mpc1211_irq_real(unsigned int irq) +{ + int value; + int irqmask; + + if ( irq < 8) { + irqmask = 1<<irq; + outb(0x0b,I8259_M_CR); /* ISR register */ + value = inb(I8259_M_CR) & irqmask; + outb(0x0a,I8259_M_CR); /* back ro the IPR reg */ + return value; + } + irqmask = 1<<(irq - 8); + outb(0x0b,I8259_S_CR); /* ISR register */ + value = inb(I8259_S_CR) & irqmask; + outb(0x0a,I8259_S_CR); /* back ro the IPR reg */ + return value; +} + +static void mask_and_ack_mpc1211(unsigned int irq) +{ + unsigned long flags; + + save_and_cli(flags); + + if(irq < 8) { + if(m_irq_mask & (1<<irq)){ + if(!mpc1211_irq_real(irq)){ + irq_err_count++; + printk("spurious 8259A interrupt: IRQ %x\n",irq); + } + } else { + m_irq_mask |= (1<<irq); + } + inb(I8259_M_MR); /* DUMMY */ + outb(m_irq_mask,I8259_M_MR); /* disable */ + outb(0x60+irq,I8259_M_CR); /* EOI */ + + } else { + if(s_irq_mask & (1<<(irq - 8))){ + if(!mpc1211_irq_real(irq)){ + irq_err_count++; + printk("spurious 8259A interrupt: IRQ %x\n",irq); + } + } else { + s_irq_mask |= (1<<(irq - 8)); + } + inb(I8259_S_MR); /* DUMMY */ + outb(s_irq_mask,I8259_S_MR); /* disable */ + outb(0x60+(irq-8),I8259_S_CR); /* EOI */ + outb(0x60+2,I8259_M_CR); + } + restore_flags(flags); +} + +static void end_mpc1211_irq(unsigned int irq) +{ + enable_mpc1211_irq(irq); +} + +static unsigned int startup_mpc1211_irq(unsigned int irq) +{ + enable_mpc1211_irq(irq); + return 0; +} + +static void shutdown_mpc1211_irq(unsigned int irq) +{ + disable_mpc1211_irq(irq); +} + +static struct hw_interrupt_type mpc1211_irq_type = { + .typename = "MPC1211-IRQ", + .startup = startup_mpc1211_irq, + .shutdown = shutdown_mpc1211_irq, + .enable = enable_mpc1211_irq, + .disable = disable_mpc1211_irq, + .ack = mask_and_ack_mpc1211, + .end = end_mpc1211_irq +}; + +static void make_mpc1211_irq(unsigned int irq) +{ + irq_desc[irq].handler = &mpc1211_irq_type; + irq_desc[irq].status = IRQ_DISABLED; + irq_desc[irq].action = 0; + irq_desc[irq].depth = 1; + disable_mpc1211_irq(irq); +} + +int mpc1211_irq_demux(int irq) +{ + unsigned int poll; + + if( irq == 2 ) { + outb(0x0c,I8259_M_CR); + poll = inb(I8259_M_CR); + if(poll & 0x80) { + irq = (poll & 0x07); + } + if( irq == 2) { + outb(0x0c,I8259_S_CR); + poll = inb(I8259_S_CR); + irq = (poll & 0x07) + 8; + } + } + return irq; +} + +void __init init_mpc1211_IRQ(void) +{ + int i; + /* + * Super I/O (Just mimic PC): + * 1: keyboard + * 3: serial 1 + * 4: serial 0 + * 5: printer + * 6: floppy + * 8: rtc + * 10: lan + * 12: mouse + * 14: ide0 + * 15: ide1 + */ + + pci_write_config(0,0,0,0x54, 0xb0b0002d); + outb(0x11, I8259_M_CR); /* mater icw1 edge trigger */ + outb(0x11, I8259_S_CR); /* slave icw1 edge trigger */ + outb(0x20, I8259_M_MR); /* m icw2 base vec 0x08 */ + outb(0x28, I8259_S_MR); /* s icw2 base vec 0x70 */ + outb(0x04, I8259_M_MR); /* m icw3 slave irq2 */ + outb(0x02, I8259_S_MR); /* s icw3 slave id */ + outb(0x01, I8259_M_MR); /* m icw4 non buf normal eoi*/ + outb(0x01, I8259_S_MR); /* s icw4 non buf normal eo1*/ + outb(0xfb, I8259_M_MR); /* disable irq0--irq7 */ + outb(0xff, I8259_S_MR); /* disable irq8--irq15 */ + + for ( i=0; i < 16; i++) { + if(i != 2) { + make_mpc1211_irq(i); + } + } +} + +/* + Initialize the board +*/ + + +static void delay (void) +{ + volatile unsigned short tmp; + tmp = *(volatile unsigned short *) 0xa0000000; +} + +static void delay1000 (void) +{ + int i; + + for (i=0; i<1000; i++) + delay (); +} + +static int put_smb_blk(unsigned char *p, int address, int command, int no) +{ + int temp; + int timeout; + int i; + + outb(0xff, SMBHSTSTS); + temp = inb(SMBHSTSTS); + for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE); timeout++) { + delay1000(); + temp = inb(SMBHSTSTS); + } + if (timeout >= MAX_TIMEOUT){ + return -1; + } + + outb(((address & 0x7f) << 1), SMBHSTADD); + outb(0xc0, SMBHSTCNT); + outb(command & 0xff, SMBHSTCMD); + outb(no & 0x1f, SMBHSTDAT0); + + for(i = 1; i <= no; i++) { + outb(*p++, SMBBLKDAT); + } + outb(0xff, SMBHSTSTART); + + temp = inb(SMBHSTSTS); + for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE)); timeout++) { + delay1000(); + temp = inb(SMBHSTSTS); + } + if (timeout >= MAX_TIMEOUT) { + return -2; + } + if ( temp & ALI15X3_STS_ERR ){ + return -3; + } + return 0; +} + +/* + * The Machine Vector + */ + +struct sh_machine_vector mv_mpc1211 __initmv = { + .mv_nr_irqs = 48, + .mv_irq_demux = mpc1211_irq_demux, + .mv_init_irq = init_mpc1211_IRQ, + +#ifdef CONFIG_HEARTBEAT + .mv_heartbeat = heartbeat_mpc1211, +#endif +}; + +ALIAS_MV(mpc1211) + +/* arch/sh/boards/mpc1211/rtc.c */ +void mpc1211_time_init(void); + +int __init platform_setup(void) +{ + unsigned char spd_buf[128]; + + __set_io_port_base(PA_PCI_IO); + + pci_write_config(0,0,0,0x54, 0xb0b00000); + + do { + outb(ALI15X3_ABORT, SMBHSTCNT); + spd_buf[0] = 0x0c; + spd_buf[1] = 0x43; + spd_buf[2] = 0x7f; + spd_buf[3] = 0x03; + spd_buf[4] = 0x00; + spd_buf[5] = 0x03; + spd_buf[6] = 0x00; + } while (put_smb_blk(spd_buf, 0x69, 0, 7) < 0); + + board_time_init = mpc1211_time_init; + + return 0; +} + |