| /* |
| * linux/arch/sh/boards/mpc1211/setup.c |
| * |
| * Copyright (C) 2002 Saito.K & Jeanne, Fujii.Y |
| * |
| */ |
| |
| #include <linux/init.h> |
| #include <linux/irq.h> |
| #include <linux/hdreg.h> |
| #include <linux/ide.h> |
| #include <linux/interrupt.h> |
| #include <linux/platform_device.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 */ |
| |
| 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; |
| |
| static void disable_mpc1211_irq(unsigned int irq) |
| { |
| 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); |
| } |
| |
| } |
| |
| static void enable_mpc1211_irq(unsigned int irq) |
| { |
| 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); |
| } |
| } |
| |
| 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) |
| { |
| if(irq < 8) { |
| if(m_irq_mask & (1<<irq)){ |
| if(!mpc1211_irq_real(irq)){ |
| atomic_inc(&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)){ |
| atomic_inc(&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); |
| } |
| } |
| |
| 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].chip = &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; |
| } |
| |
| static 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); |
| } |
| } |
| } |
| |
| static void delay1000(void) |
| { |
| int i; |
| |
| for (i=0; i<1000; i++) |
| ctrl_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; |
| } |
| |
| static struct resource heartbeat_resources[] = { |
| [0] = { |
| .start = 0xa2000000, |
| .end = 0xa2000000 + 8 - 1, |
| .flags = IORESOURCE_MEM, |
| }, |
| }; |
| |
| static struct platform_device heartbeat_device = { |
| .name = "heartbeat", |
| .id = -1, |
| .num_resources = ARRAY_SIZE(heartbeat_resources), |
| .resource = heartbeat_resources, |
| }; |
| |
| static struct platform_device *mpc1211_devices[] __initdata = { |
| &heartbeat_device, |
| }; |
| |
| static int __init mpc1211_devices_setup(void) |
| { |
| return platform_add_devices(mpc1211_devices, |
| ARRAY_SIZE(mpc1211_devices)); |
| } |
| __initcall(mpc1211_devices_setup); |
| |
| /* arch/sh/boards/mpc1211/rtc.c */ |
| void mpc1211_time_init(void); |
| |
| static void __init mpc1211_setup(char **cmdline_p) |
| { |
| 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; |
| } |
| |
| /* |
| * The Machine Vector |
| */ |
| struct sh_machine_vector mv_mpc1211 __initmv = { |
| .mv_name = "Interface MPC-1211(CTP/PCI/MPC-SH02)", |
| .mv_setup = mpc1211_setup, |
| .mv_nr_irqs = 48, |
| .mv_irq_demux = mpc1211_irq_demux, |
| .mv_init_irq = init_mpc1211_IRQ, |
| }; |
| ALIAS_MV(mpc1211) |