diff options
Diffstat (limited to 'arch/sh/boards/mpc1211/setup.c')
-rw-r--r-- | arch/sh/boards/mpc1211/setup.c | 360 |
1 files changed, 360 insertions, 0 deletions
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; +} + |