Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de> Signed-off-by: Adrian Bunk <bunk@stusta.de>
		
			
				
	
	
		
			359 lines
		
	
	
	
		
			7.4 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			359 lines
		
	
	
	
		
			7.4 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * linux/arch/sh/board/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 <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].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;
 | 
						|
}
 | 
						|
 | 
						|
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;
 | 
						|
}
 | 
						|
 |