diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/Makefile | 19 | ||||
| -rw-r--r-- | drivers/ali512x.c | 423 | ||||
| -rw-r--r-- | drivers/ds1722.c | 142 | ||||
| -rw-r--r-- | drivers/eepro100.c | 2 | ||||
| -rw-r--r-- | drivers/mw_eeprom.c | 242 | ||||
| -rw-r--r-- | drivers/ti_pci1410a.c | 668 | 
6 files changed, 1489 insertions, 7 deletions
| diff --git a/drivers/Makefile b/drivers/Makefile index c28ed9f00..277d6f68c 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -27,16 +27,23 @@ include $(TOPDIR)/config.mk  LIB	= libdrivers.a -OBJS	= 3c589.o 5701rls.o at91rm9200_ether.o \ -	  bcm570x.o bcm570x_autoneg.o \ -	  cfb_console.o cs8900.o ct69000.o dc2114x.o \ +OBJS	= 3c589.o 5701rls.o ali512x.o at91rm9200_ether.o \ +	  bcm570x.o bcm570x_autoneg.o cfb_console.o \ +	  cs8900.o ct69000.o dc2114x.o          \  	  eepro100.o i8042.o i82365.o inca-ip_sw.o \ -	  lan91c96.o natsemi.o ns16550.o ns8382x.o ns87308.o \ +	  lan91c96.o             natsemi.o \ +	  ns16550.o ns8382x.o ns87308.o \  	  pci.o pci_auto.o pci_indirect.o \  	  pcnet.o plb2800_eth.o \  	  s3c24x0_i2c.o sed13806.o serial.o \ -	  smc91111.o smiLynxEM.o sym53c8xx.o \ -	  tigon3.o w83c553f.o +	  smc91111.o smiLynxEM.o              sym53c8xx.o \ +	  ti_pci1410a.o tigon3.o w83c553f.o + +## Disabled for now: +##	  cs8900.o ct69000.o dc2114x.o ds1722.o \ +##	  lan91c96.o mw_eeprom.o natsemi.o \ +##	  smc91111.o smiLynxEM.o spi_eeprom.o sym53c8xx.o \ +##  all:	$(LIB) diff --git a/drivers/ali512x.c b/drivers/ali512x.c new file mode 100644 index 000000000..e52edd003 --- /dev/null +++ b/drivers/ali512x.c @@ -0,0 +1,423 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB <daniel@omicron.se>. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Based on sc520cdp.c from rolo 1.6: + *---------------------------------------------------------------------- + * (C) Copyright 2000 + * Sysgo Real-Time Solutions GmbH + * Klein-Winternheim, Germany + *---------------------------------------------------------------------- + */ + +#include <config.h> + +#ifdef CONFIG_ALI152X + +#include <common.h> +#include <asm/io.h> +#include <asm/ic/ali512x.h> + + +/* ALI M5123 Logical device numbers: + * 0 FDC + * 1 unused? + * 2 unused? + * 3 lpt + * 4 UART1 + * 5 UART2 + * 6 RTC + * 7 mouse/kbd + * 8 CIO + */ + +/* + ************************************************************ + *  Some access primitives for the ALi chip:                * + ************************************************************ + */ + +static void ali_write(u8 index, u8 value) +{	 +	/* write an arbirary register */ +	outb(index, ALI_INDEX); +	outb(value, ALI_DATA); +} + +#if 0 +static int ali_read(u8 index) +{ +	outb(index, ALI_INDEX); +	return inb(ALI_DATA); +} +#endif + +#define ALI_OPEN() \ +	outb(0x51, ALI_INDEX); \ +	outb(0x23, ALI_INDEX)	 + + +#define ALI_CLOSE() \ +	outb(0xbb, ALI_INDEX) + +/* Select a logical device */ +#define ALI_SELDEV(dev)	\ +	ali_write(0x07, dev)	 + + +void ali512x_init(void) +{ +	ALI_OPEN(); + +	ali_write(0x02, 0x01);	/* soft reset */ +	ali_write(0x03, 0x03);	/* disable access to CIOs */ +	ali_write(0x22, 0x00);	/* disable direct powerdown */ +	ali_write(0x23, 0x00);	/* disable auto powerdown */ +	ali_write(0x24, 0x00);	/* IR 8 is active hi, pin26 is PDIR */ + +	ALI_CLOSE(); +} + +void ali512x_set_fdc(int enabled, u16 io, u8 irq, u8 dma_channel) +{ +	ALI_OPEN(); +	ALI_SELDEV(0); +	 +	ali_write(0x30, enabled?1:0); +	if (enabled) { +		ali_write(0x60, io >> 8); +		ali_write(0x61, io & 0xff); +		ali_write(0x70, irq); +		ali_write(0x74, dma_channel); +		 +		/* AT mode, no drive swap */ +		ali_write(0xf0, 0x08); +		ali_write(0xf1, 0x00); +		ali_write(0xf2, 0xff); +		ali_write(0xf4, 0x00); +	} +	ALI_CLOSE(); +} + + +void ali512x_set_pp(int enabled, u16 io, u8 irq, u8 dma_channel) +{ +	ALI_OPEN(); +	ALI_SELDEV(3); +	 +	ali_write(0x30, enabled?1:0); +	if (enabled) { +		ali_write(0x60, io >> 8); +		ali_write(0x61, io & 0xff); +		ali_write(0x70, irq); +		ali_write(0x74, dma_channel); +		 +		/* mode: EPP 1.9, ECP FIFO threshold = 7, IRQ active low */ +		ali_write(0xf0, 0xbc); +		/* 12 MHz, Burst DMA in ECP */ +		ali_write(0xf1, 0x05); +	} +	ALI_CLOSE(); + +} + +void ali512x_set_uart(int enabled, int index, u16 io, u8 irq) +{ +	ALI_OPEN(); +	ALI_SELDEV(index?5:4); +	 +	ali_write(0x30, enabled?1:0); +	if (enabled) { +		ali_write(0x60, io >> 8); +		ali_write(0x61, io & 0xff); +		ali_write(0x70, irq); +		 +		ali_write(0xf0, 0x00); +		ali_write(0xf1, 0x00); +		 +		/* huh? write 0xf2 twice - a typo in rolo +		 * or some secret ali errata? Who knows?  +		 */ +		if (index) { +			ali_write(0xf2, 0x00); +		} +		ali_write(0xf2, 0x0c); +	} +	ALI_CLOSE(); + +} + +void ali512x_set_uart2_irda(int enabled) +{ +	ALI_OPEN(); +	ALI_SELDEV(5); +	 +	ali_write(0xf1, enabled?0x48:0x00); /* fullduplex IrDa */ +	ALI_CLOSE(); + +} + +void ali512x_set_rtc(int enabled, u16 io, u8 irq) +{ +	ALI_OPEN(); +	ALI_SELDEV(6); +	 +	ali_write(0x30, enabled?1:0); +	if (enabled) { +		ali_write(0x60, io >> 8); +		ali_write(0x61, io & 0xff); +		ali_write(0x70, irq); + +		ali_write(0xf0, 0x00); +	} +	ALI_CLOSE(); +} + +void ali512x_set_kbc(int enabled, u8 kbc_irq, u8 mouse_irq) +{ +	ALI_OPEN(); +	ALI_SELDEV(7); +	 +	ali_write(0x30, enabled?1:0); +	if (enabled) { +		ali_write(0x70, kbc_irq); +		ali_write(0x72, mouse_irq);		 +		 +		ali_write(0xf0, 0x00); +	} +	ALI_CLOSE(); +} + + +/* Common I/O + *  + * (This descripotsion is base on several incompete sources + *  since I have not been able to obtain any datasheet for the device + *  there may be some mis-understandings burried in here.  + *  -- Daniel daniel@omicron.se) + *  + * There are 22 CIO pins numbered + * 10-17 + * 20-25 + * 30-37 + *  + * 20-24 are dedicated CIO pins, the other 17 are muliplexed with + * other functions. + *  + *           Secondary  + * CIO Pin   Function    Decription + * ======================================================= + * CIO10     IRQIN1      Interrupt input 1? + * CIO11     IRQIN2      Interrupt input 2? + * CIO12     IRRX        IrDa Receive + * CIO13     IRTX        IrDa Transmit + * CIO14     P21         KBC P21 fucntion + * CIO15     P20         KBC P21 fucntion + * CIO16     I2C_CLK     I2C Clock + * CIO17     I2C_DAT     I2C Data + *  + * CIO20     - + * CIO21     - + * CIO22     - + * CIO23     - + * CIO24     - + * CIO25     LOCK        Keylock + *  + * CIO30     KBC_CLK     Keybaord Clock + * CIO31     CS0J        General Chip Select decoder CS0J + * CIO32     CS1J        General Chip Select decoder CS1J + * CIO33     ALT_KCLK    Alternative Keyboard Clock + * CIO34     ALT_KDAT    Alternative Keyboard Data + * CIO35     ALT_MCLK    Alternative Mouse Clock + * CIO36     ALT_MDAT    Alternative Mouse Data + * CIO37     ALT_KBC     Alternative KBC select + * + * The CIO use an indirect address scheme.  + *  + * Reigster 3 in the SIO is used to select the index and data + * port addresses where the CIO I/O registers show up. + * The function selection registers are accessible under  + * function SIO 8.  + *  + * SIO reigster 3 (CIO Address Selection) bit definitions: + * bit 7   CIO index and data registers enabled + * bit 1-0 CIO indirect registers port address select + *     	 0  index = 0xE0 data = 0xE1 + *       1  index = 0xE2 data = 0xE3 + *       2  index = 0xE4 data = 0xE5 + *       3  index = 0xEA data = 0xEB + *  + * There are three CIO I/O register accessed via CIO index port and CIO data port + * 0x01     CIO 10-17 data + * 0x02     CIO 20-25 data (bits 7-6 unused) + * 0x03     CIO 30-37 data + *  + *  + * The pin function is accessed through normal  + * SIO registers, each register have the same format: + *  + * Bit   Function                     Value + * 0     Input/output                 1=input  + * 1     Polarity of signal           1=inverted + * 2     Unused                       ?? + * 3     Function (normal or special) 1=special + * 7-4   Unused + *  + * SIO REG + * 0xe0     CIO 10 Config + * 0xe1     CIO 11 Config + * 0xe2     CIO 12 Config + * 0xe3     CIO 13 Config + * 0xe4     CIO 14 Config + * 0xe5     CIO 15 Config + * 0xe6     CIO 16 Config + * 0xe7     CIO 16 Config + * + * 0xe8     CIO 20 Config + * 0xe9     CIO 21 Config + * 0xea     CIO 22 Config + * 0xeb     CIO 23 Config + * 0xec     CIO 24 Config + * 0xed     CIO 25 Config + * + * 0xf5     CIO 30 Config + * 0xf6     CIO 31 Config + * 0xf7     CIO 32 Config + * 0xf8     CIO 33 Config + * 0xf9     CIO 34 Config + * 0xfa     CIO 35 Config + * 0xfb     CIO 36 Config + * 0xfc     CIO 37 Config + *  + */ + +#define ALI_CIO_PORT_SEL 0x83 +#define ALI_CIO_INDEX    0xea +#define ALI_CIO_DATA     0xeb + +void ali512x_set_cio(int enabled) +{ +	int i; +	 +	ALI_OPEN(); +	 +	if (enabled) { +		ali_write(0x3, ALI_CIO_PORT_SEL);    /* Enable CIO data register */ +	} else { +		ali_write(0x3, ALI_CIO_PORT_SEL & ~0x80); +	} +	 +	ALI_SELDEV(8); +	 +	ali_write(0x30, enabled?1:0); +	 +	/* set all pins to input to start with */ +	for (i=0xe0;i<0xee;i++) { +		ali_write(i, 1); +	} +	 +	for (i=0xf5;i<0xfe;i++) { +		ali_write(i, 1); +	} +	 +	ALI_CLOSE(); +} + + +void ali512x_cio_function(int pin, int special, int inv, int input) +{ +	u8 data; +	u8 addr; +	 +	/* valid pins are 10-17, 20-25 and 30-37 */ +	if (pin >= 10 && pin <= 17) {  +		addr = 0xe0+(pin&7); +	} else if (pin >= 20 && pin <= 25) { +		addr = 0xe8+(pin&7); +	} else if (pin >= 30 && pin <= 37) {  +		addr = 0xf5+(pin&7); +	} else { +		return; +	} +	 +	ALI_OPEN(); + +	ALI_SELDEV(8); +	 +	 +	data=0xf4; +	if (special) { +		data |= 0x08; +	} else { +		if (inv) { +			data |= 0x02; +		} +		if (input) { +			data |= 0x01; +		} +	} +	 +	ali_write(addr, data); +	 +	ALI_CLOSE(); +} + +void ali512x_cio_out(int pin, int value)  +{ +	u8 reg; +	u8 data; +	u8 bit; +	 +	reg = pin/10; +	bit = 1 << (pin%10); +	 +		 +	outb(reg, ALI_CIO_INDEX);     /* select I/O register */ +	data = inb(ALI_CIO_DATA); +	if (value) { +		data |= bit; +	} else { +		data &= ~bit; +	} +	outb(data, ALI_CIO_DATA); +} + +int ali512x_cio_in(int pin) +{ +	u8 reg; +	u8 data; +	u8 bit; +			 +	/* valid pins are 10-17, 20-25 and 30-37 */ +	reg = pin/10; +	bit = 1 << (pin%10); +	 +	 +	outb(reg, ALI_CIO_INDEX);     /* select I/O register */ +	data = inb(ALI_CIO_DATA); +	 +	return data & bit;  +} + +  +#endif diff --git a/drivers/ds1722.c b/drivers/ds1722.c new file mode 100644 index 000000000..34eb80ca2 --- /dev/null +++ b/drivers/ds1722.c @@ -0,0 +1,142 @@ + +#include <common.h> + +#include <ssi.h> + +#ifdef CONFIG_DS1722 + +static void ds1722_select(int dev) +{ +	ssi_set_interface(4096, 0, 0, 0); +	ssi_chip_select(0); +	udelay(1); +	ssi_chip_select(dev); +	udelay(1); +} + + +u8 ds1722_read(int dev, int addr) +{ +	u8 res; +	 +	ds1722_select(dev); +	 +	ssi_tx_byte(addr);	 +	res = ssi_rx_byte();   	 +	 +	ssi_chip_select(0); +	 +	return res; +} + +void ds1722_write(int dev, int addr, u8 data) +{ +	ds1722_select(dev); +	 +	ssi_tx_byte(0x80|addr);	 +	ssi_tx_byte(data);   	 +	 +	ssi_chip_select(0); +} + + +u16 ds1722_temp(int dev, int resolution) +{ +	static int useconds[] = { +		75000, 150000, 300000, 600000, 1200000  +	}; +	char temp; +	u16 res; +	 +	 +	/* set up the desired resulotion ... */ +	ds1722_write(dev, 0, 0xe0 | (resolution << 1)); +			 +	/* wait while the chip measures the tremperature */ +	udelay(useconds[resolution]); 	 +	 +	res = (temp = ds1722_read(dev, 2)) << 8; +	 +	if (temp < 0) {  +		temp = (16 - (ds1722_read(dev, 1) >> 4)) & 0x0f; +	} else { +		temp = (ds1722_read(dev, 1) >> 4); +	} +	 +	switch (temp) { +	case 0: +		/* .0000 */ +		break; +	case 1: +		/* .0625 */ +		res |=1; +		break; +	case 2: +		/* .1250 */ +		res |=1; +		break; +	case 3: +		/* .1875 */ +		res |=2; +		break; +	case 4: +		/* .2500 */ +		res |=3; +		break; +	case 5: +		/* .3125 */ +		res |=3; +		break; +	case 6: +		/* .3750 */ +		res |=4; +		break; +	case 7: +		/* .4375 */ +		res |=4; +		break; +	case 8: +		/* .5000 */ +		res |=5; +		break; +	case 9: +		/* .5625 */ +		res |=6; +		break; +	case 10: +		/* .6250 */ +		res |=6; +		break; +	case 11: +		/* .6875 */ +		res |=7; +		break; +	case 12: +		/* .7500 */ +		res |=8; +		break; +	case 13: +		/* .8125 */ +		res |=8; +		break; +	case 14: +		/* .8750 */ +		res |=9; +		break; +	case 15: +		/* .9375 */ +		res |=9; +		break; +	} +	return res; +			 +} + +int ds1722_probe(int dev) +{ +	u16 temp = ds1722_temp(dev, DS1722_RESOLUTION_12BIT); +	printf("%d.%d deg C\n\n", (char)(temp >> 8), temp & 0xff); +	return 0; +} + +#endif diff --git a/drivers/eepro100.c b/drivers/eepro100.c index c8d07de8b..a0bb76da4 100644 --- a/drivers/eepro100.c +++ b/drivers/eepro100.c @@ -331,8 +331,8 @@ int eepro100_initialize (bd_t * bis)  		dev = (struct eth_device *) malloc (sizeof *dev);  		sprintf (dev->name, "i82559#%d", card_number); +		dev->priv = (void *) devno; /* this have to come before bus_to_phys() */  		dev->iobase = bus_to_phys (iobase); -		dev->priv = (void *) devno;  		dev->init = eepro100_init;  		dev->halt = eepro100_halt;  		dev->send = eepro100_send; diff --git a/drivers/mw_eeprom.c b/drivers/mw_eeprom.c new file mode 100644 index 000000000..30a51fa05 --- /dev/null +++ b/drivers/mw_eeprom.c @@ -0,0 +1,242 @@ +/* Three-wire (MicroWire) serial eeprom driver (for 93C46 and compatibles) */ + +#include <common.h> +#include <ssi.h> + + +#ifdef CONFIG_MW_EEPROM + +/* + * Serial EEPROM opcodes, including start bit + */ +#define EEP_OPC_ERASE	0x7  /* 3-bit opcode */ +#define EEP_OPC_WRITE	0x5  /* 3-bit opcode */ +#define EEP_OPC_READ	        0x6  /* 3-bit opcode */ + +#define EEP_OPC_ERASE_ALL	0x12 /* 5-bit opcode */ +#define EEP_OPC_ERASE_EN	0x13 /* 5-bit opcode */ +#define EEP_OPC_WRITE_ALL	0x11 /* 5-bit opcode */ +#define EEP_OPC_ERASE_DIS	0x10 /* 5-bit opcode */ + +static int addrlen; + +static void mw_eeprom_select(int dev) +{ +	ssi_set_interface(2048, 0, 0, 0); +	ssi_chip_select(0); +	udelay(1); +	ssi_chip_select(dev); +	udelay(1); +} + +static int mw_eeprom_size(int dev) +{ +	int x; +	u16 res; +		 +	mw_eeprom_select(dev); +	ssi_tx_byte(EEP_OPC_READ); +	 +	res = ssi_txrx_byte(0) << 8; +	res |= ssi_rx_byte(); +	for (x = 0; x < 16; x++) { +		if (! (res & 0x8000)) { +			break; +		} +		res <<= 1; +	} +	ssi_chip_select(0); +	 +	return x; +} + +int mw_eeprom_erase_enable(int dev) +{ +	mw_eeprom_select(dev); +	ssi_tx_byte(EEP_OPC_ERASE_EN); +	ssi_tx_byte(0); +	udelay(1); +	ssi_chip_select(0); +		 +	return 0; +} + +int mw_eeprom_erase_disable(int dev) +{	 +	mw_eeprom_select(dev); +	ssi_tx_byte(EEP_OPC_ERASE_DIS); +	ssi_tx_byte(0); +	udelay(1); +	ssi_chip_select(0); +		 +	return 0; +} + + +u32 mw_eeprom_read_word(int dev, int addr) +{ +	u16 rcv; +	u16 res; +	int bits; +	 +	mw_eeprom_select(dev); +	ssi_tx_byte((EEP_OPC_READ << 5) | ((addr >> (addrlen - 5)) & 0x1f)); +	rcv = ssi_txrx_byte(addr << (13 - addrlen)); +	res = rcv << (16 - addrlen); +	bits = 4 + addrlen; +	 +	while (bits>0) { +		rcv = ssi_rx_byte(); +		if (bits > 7) { +			res |= rcv << (bits - 8); +		} else { +			res |= rcv >> (8 - bits); +		} +		bits -= 8; +	} +	 +	ssi_chip_select(0); +	 +	return res; +} + +int mw_eeprom_write_word(int dev, int addr, u16 data) +{ +	u8 byte1=0; +	u8 byte2=0; +	 +	mw_eeprom_erase_enable(dev); +	mw_eeprom_select(dev); +	 +	switch (addrlen) { +	 case 6: +		byte1 = EEP_OPC_WRITE >> 2; +		byte2 = (EEP_OPC_WRITE << 6)&0xc0; +		byte2 |= addr; +		break; +	 case 7: +		byte1 = EEP_OPC_WRITE >> 1; +		byte2 = (EEP_OPC_WRITE << 7)&0x80; +		byte2 |= addr; +		break; +	 case 8: +		byte1 = EEP_OPC_WRITE; +		byte2 = addr; +		break; +	 case 9: +		byte1 = EEP_OPC_WRITE << 1; +		byte1 |= addr >> 8; +		byte2 = addr & 0xff; +		break; +	 case 10: +		byte1 = EEP_OPC_WRITE << 2; +		byte1 |= addr >> 8; +		byte2 = addr & 0xff; +		break; +	 default: +		printf("Unsupported number of address bits: %d\n", addrlen); +		return -1; +		 +	} +	 +	ssi_tx_byte(byte1); +	ssi_tx_byte(byte2); +	ssi_tx_byte(data >> 8);	 +	ssi_tx_byte(data & 0xff); +	ssi_chip_select(0);	 +	udelay(10000); /* Worst case */ +	mw_eeprom_erase_disable(dev); + +	return 0; +} + + +int mw_eeprom_write(int dev, int addr, u8 *buffer, int len) +{ +	int done; +	 +	done = 0; +	if (addr & 1) { +		u16 temp = mw_eeprom_read_word(dev, addr >> 1); +		temp &= 0xff00; +		temp |= buffer[0]; +		 +		mw_eeprom_write_word(dev, addr >> 1, temp); +		len--; +		addr++; +		buffer++; +		done++; +	} +	 +	while (len <= 2) { +		mw_eeprom_write_word(dev, addr >> 1, *(u16*)buffer); +		len-=2; +		addr+=2; +		buffer+=2; +		done+=2; +	} + +	if (len) { +		u16 temp = mw_eeprom_read_word(dev, addr >> 1); +		temp &= 0x00ff; +		temp |= buffer[0] << 8; +		 +		mw_eeprom_write_word(dev, addr >> 1, temp); +		len--; +		addr++; +		buffer++; +		done++; +	} + +	return done; +} + + + +int mw_eeprom_read(int dev, int addr, u8 *buffer, int len) +{ +	int done; +	 +	done = 0; +	if (addr & 1) { +		u16 temp = mw_eeprom_read_word(dev, addr >> 1); +		buffer[0]= temp & 0xff; +		 +		len--; +		addr++; +		buffer++; +		done++; +	} +	 +	while (len <= 2) { +		*(u16*)buffer = mw_eeprom_read_word(dev, addr >> 1); +		len-=2; +		addr+=2; +		buffer+=2; +		done+=2; +	} + +	if (len) { +		u16 temp = mw_eeprom_read_word(dev, addr >> 1); +		buffer[0] = temp >> 8; +		 +		len--; +		addr++; +		buffer++; +		done++; +	} + +	return done; +} + +int mw_eeprom_probe(int dev) +{ +	addrlen = mw_eeprom_size(dev); +	 +	if (addrlen < 6 || addrlen > 10) { +		return -1; +	} +	return 0; +} + +#endif diff --git a/drivers/ti_pci1410a.c b/drivers/ti_pci1410a.c new file mode 100644 index 000000000..a2b1a17f2 --- /dev/null +++ b/drivers/ti_pci1410a.c @@ -0,0 +1,668 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ******************************************************************** + * + * Lots of code copied from: + * + * m8xx_pcmcia.c - Linux PCMCIA socket driver for the mpc8xx series. + * (C) 1999-2000 Magnus Damm <damm@bitsmart.com> + * + * "The ExCA standard specifies that socket controllers should provide + * two IO and five memory windows per socket, which can be independently + * configured and positioned in the host address space and mapped to + * arbitrary segments of card address space. " - David A Hinds. 1999 + * + * This controller does _not_ meet the ExCA standard. + * + * m8xx pcmcia controller brief info: + * + 8 windows (attrib, mem, i/o) + * + up to two slots (SLOT_A and SLOT_B) + * + inputpins, outputpins, event and mask registers. + * - no offset register. sigh. + * + * Because of the lacking offset register we must map the whole card. + * We assign each memory window PCMCIA_MEM_WIN_SIZE address space. + * Make sure there is (PCMCIA_MEM_WIN_SIZE * PCMCIA_MEM_WIN_NO + * * PCMCIA_SOCKETS_NO) bytes at PCMCIA_MEM_WIN_BASE. + * The i/o windows are dynamically allocated at PCMCIA_IO_WIN_BASE. + * They are maximum 64KByte each... + */ + + +#undef DEBUG		/**/ + +/* + * PCMCIA support + */ +#include <common.h> +#include <command.h> +#include <config.h> +#include <pci.h> +#include <asm/io.h> + +#include <pcmcia.h> +#include <cmd_pcmcia.h> + +#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA) && defined(CONFIG_IDE_TI_CARDBUS) + +int pcmcia_on(int ide_base_bus); + +static int  pcmcia_off(void); +static int  hardware_disable(int slot); +static int  hardware_enable(int slot); +static int  voltage_set(int slot, int vcc, int vpp); +static void print_funcid(int func); +static void print_fixed(volatile uchar *p); +static int  identify(volatile uchar *p); +static int  check_ide_device(int slot, int ide_base_bus); + + +/* ------------------------------------------------------------------------- */ + + +const char *indent = "\t   "; + +/* ------------------------------------------------------------------------- */ + + +int do_pinit(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +#ifndef CFG_FISRT_PCMCIA_BUS +# define CFG_FISRT_PCMCIA_BUS 0 +#endif + +	int rcode = 0; +	 +	if (argc != 2) { +		printf ("Usage: pinit {on | off}\n"); +		return 1; +	} +	if (strcmp(argv[1],"on") == 0) { +		rcode = pcmcia_on(CFG_FISRT_PCMCIA_BUS); +	} else if (strcmp(argv[1],"off") == 0) { +		rcode = pcmcia_off(); +	} else { +		printf ("Usage: pinit {on | off}\n"); +		return 1; +	} +	 +	return rcode; +} + +/* ------------------------------------------------------------------------- */ + + +static struct pci_device_id supported[] = { +	{ PCI_VENDOR_ID_TI, 0xac50 }, /* Ti PCI1410A */ +	{ PCI_VENDOR_ID_TI, 0xac56 }, /* Ti PCI1510 */ +	{ } +}; + +static pci_dev_t devbusfn; +static u32 socket_base; +static u32 pcmcia_cis_ptr; + +int pcmcia_on(int ide_base_bus) +{	 +	u16 dev_id; +	u32 socket_status; +	int slot = 0; +	int cis_len; +	u16 io_base; +	u16 io_len; +	 +	/* +	 * Find the CardBus PCI device(s). +	 */ +	if ((devbusfn = pci_find_devices(supported, 0)) < 0) { +		printf("Ti CardBus: not found\n"); +		return 1; +	} +	 +	pci_read_config_word(devbusfn, PCI_DEVICE_ID, &dev_id); +	 +	if (dev_id == 0xac56) { +		debug("Enable PCMCIA Ti PCI1510\n"); +	} else { +		debug("Enable PCMCIA Ti PCI1410A\n"); +	} + +	pcmcia_cis_ptr = CFG_PCMCIA_CIS_WIN; +	cis_len = CFG_PCMCIA_CIS_WIN_SIZE; + +	io_base = CFG_PCMCIA_IO_WIN; +	io_len = CFG_PCMCIA_IO_WIN_SIZE;	 + +	/* +	 * Setup the PCI device. +	 */ +	pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, &socket_base); +	socket_base &= ~0xf; + +	socket_status = readl(socket_base+8); +	if ((socket_status & 6) == 0) { +		printf("Card Present: "); +		 +		switch (socket_status & 0x3c00) { +			 +		case 0x400: +			printf("5V "); +			break; +		case 0x800: +			printf("3.3V "); +			break; +		case 0xc00: +			printf("3.3/5V "); +			break; +		default: +			printf("unsupported Vcc "); +			break; +		} +		switch (socket_status & 0x30) { +		case 0x10: +			printf("16bit PC-Card\n"); +			break; +		case 0x20: +			printf("32bit CardBus Card\n"); +			break; +		default: +			printf("8bit PC-Card\n");		 +			break; +		}	 +	} +	 +	 +	writeb(0x41, socket_base + 0x806); /* Enable I/O window 0 and memory window 0 */ +	writeb(0x0e, socket_base + 0x807); /* Reset I/O window options */ + +	/* Careful: the linux yenta driver do not seem to reset the offset +	 * in the i/o windows, so leaving them non-zero is a problem */ +	 +	writeb(io_base & 0xff, socket_base + 0x808); /* I/O window 0 base address */ +	writeb(io_base>>8, socket_base + 0x809); +	writeb((io_base + io_len - 1) & 0xff, socket_base + 0x80a); /* I/O window 0 end address */ +	writeb((io_base + io_len - 1)>>8, socket_base + 0x80b); +	writeb(0x00, socket_base + 0x836);      /* I/O window 0 offset address 0x000 */				      +	writeb(0x00, socket_base + 0x837); + +	 +	writeb((pcmcia_cis_ptr&0x000ff000) >> 12,  +	       socket_base + 0x810); /* Memory window 0 start address bits 19-12 */ +	writeb((pcmcia_cis_ptr&0x00f00000) >> 20,  +	       socket_base + 0x811);  /* Memory window 0 start address bits 23-20 */ +	writeb(((pcmcia_cis_ptr+cis_len-1) & 0x000ff000) >> 12,  +		socket_base + 0x812); /* Memory window 0 end address bits 19-12*/ +	writeb(((pcmcia_cis_ptr+cis_len-1) & 0x00f00000) >> 20,  +		socket_base + 0x813); /* Memory window 0 end address bits 23-20*/ +	writeb(0x00, socket_base + 0x814); /* Memory window 0 offset bits 19-12 */  +	writeb(0x40, socket_base + 0x815); /* Memory window 0 offset bits 23-20 and  +					    * options (read/write, attribute access) */ +	writeb(0x00, socket_base + 0x816); /* ExCA card-detect and general control  */ +	writeb(0x00, socket_base + 0x81e); /* ExCA global control (interrupt modes) */ +	 +	writeb((pcmcia_cis_ptr & 0xff000000) >> 24,  +	       socket_base + 0x840); /* Memory window address bits 31-24 */ + +		 +	/* turn off voltage */ +	if (voltage_set(slot, 0, 0)) { +		return 1; +	} + +	/* Enable external hardware */ +	if (hardware_enable(slot)) { +		return 1; +	} +	 +	if (check_ide_device(slot, ide_base_bus)) { +		return 1; +	} +	 +	return 0; +} + +/* ------------------------------------------------------------------------- */ + + +static int pcmcia_off (void) +{ +	int slot = 0; +	 +	writeb(0x00, socket_base + 0x806); /* disable all I/O and memory windows */ +	 +	writeb(0x00, socket_base + 0x808); /* I/O window 0 base address */ +	writeb(0x00, socket_base + 0x809); +	writeb(0x00, socket_base + 0x80a); /* I/O window 0 end address */ +	writeb(0x00, socket_base + 0x80b); +	writeb(0x00, socket_base + 0x836); /* I/O window 0 offset address  */				      +	writeb(0x00, socket_base + 0x837); +	 +	writeb(0x00, socket_base + 0x80c); /* I/O window 1 base address  */ +	writeb(0x00, socket_base + 0x80d); +	writeb(0x00, socket_base + 0x80e); /* I/O window 1 end address  */ +	writeb(0x00, socket_base + 0x80f); +	writeb(0x00, socket_base + 0x838); /* I/O window 1 offset address  */				      +	writeb(0x00, socket_base + 0x839); +	 +	writeb(0x00, socket_base + 0x810); /* Memory window 0 start address */ +	writeb(0x00, socket_base + 0x811); +	writeb(0x00, socket_base + 0x812); /* Memory window 0 end address  */ +	writeb(0x00, socket_base + 0x813); +	writeb(0x00, socket_base + 0x814); /* Memory window 0 offset */ +	writeb(0x00, socket_base + 0x815); +	 +	writeb(0xc0, socket_base + 0x840); /* Memory window 0 page address */ + + +	/* turn off voltage */ +	voltage_set(slot, 0, 0); + +	/* disable external hardware */ +	printf ("Shutdown and Poweroff Ti PCI1410A\n"); +	hardware_disable(slot); +	 +	return 0; +} + + +/* ------------------------------------------------------------------------- */ + + +#define	MAX_TUPEL_SZ	512 +#define MAX_FEATURES	4 +int ide_devices_found; +static int check_ide_device(int slot, int ide_base_bus) +{ +	volatile uchar *ident = NULL; +	volatile uchar *feature_p[MAX_FEATURES]; +	volatile uchar *p, *start; +	int n_features = 0; +	uchar func_id = ~0; +	uchar code, len; +	ushort config_base = 0; +	int found = 0; +	int i; +	u32 socket_status; + +	debug ("PCMCIA MEM: %08X\n", pcmcia_cis_ptr); +	 +	socket_status = readl(socket_base+8); +	 +	if ((socket_status & 6) != 0 || (socket_status & 0x20) != 0) { +		printf("no card or CardBus card\n"); +		return 1; +	} +	 +	start = p = (volatile uchar *) pcmcia_cis_ptr; + +	while ((p - start) < MAX_TUPEL_SZ) { + +		code = *p; p += 2; + +		if (code == 0xFF) { /* End of chain */ +			break; +		} + +		len = *p; p += 2; +#if defined(DEBUG) && (DEBUG > 1) +		{  +			volatile uchar *q = p; +			printf ("\nTuple code %02x  length %d\n\tData:", +				code, len); + +			for (i = 0; i < len; ++i) { +				printf (" %02x", *q); +				q+= 2; +			} +		} +#endif	/* DEBUG */ +		switch (code) { +		case CISTPL_VERS_1: +			ident = p + 4; +			break; +		case CISTPL_FUNCID: +			/* Fix for broken SanDisk which may have 0x80 bit set */ +			func_id = *p & 0x7F; +			break; +		case CISTPL_FUNCE: +			if (n_features < MAX_FEATURES) +				feature_p[n_features++] = p; +			break; +		case CISTPL_CONFIG: +			config_base = (*(p+6) << 8) + (*(p+4)); +			debug ("\n## Config_base = %04x ###\n", config_base); +		default: +			break; +		} +		p += 2 * len; +	} + +	found = identify(ident); + +	if (func_id != ((uchar)~0)) { +		print_funcid (func_id); + +		if (func_id == CISTPL_FUNCID_FIXED) +			found = 1; +		else +			return 1;	/* no disk drive */ +	} + +	for (i=0; i<n_features; ++i) { +		print_fixed(feature_p[i]); +	} + +	if (!found) { +		printf("unknown card type\n"); +		return 1; +	} +	 +	/* select config index 1 */ +	writeb(1, pcmcia_cis_ptr + config_base);	 + +#if 0 +	printf("Confiuration Option Register: %02x\n", readb(pcmcia_cis_ptr + config_base)); +	printf("Card Confiuration and Status Register: %02x\n", readb(pcmcia_cis_ptr + config_base + 2)); +	printf("Pin Replacement Register Register: %02x\n", readb(pcmcia_cis_ptr + config_base + 4)); +	printf("Socket and Copy Register: %02x\n", readb(pcmcia_cis_ptr + config_base + 6)); +#endif	 +	ide_devices_found |= (1 << (slot+ide_base_bus)); +	 +	return 0; +} + + + +static int voltage_set(int slot, int vcc, int vpp) +{ +	u32 socket_control; +	int reg=0; +	 +	switch (slot) { +	case 0: +		reg = socket_base + 0x10; +		break; +	default: +		return 1; +	} +	 +	socket_control = 0; +	 +	 +	switch (vcc) { +	case 50: +		socket_control |= 0x20; +		break; +	case 33: +		socket_control |= 0x30; +		break; +	case 0: +	default: +	} +	 +	switch (vpp) { +	case 120: +		socket_control |= 0x1; +		break; +	case 50: +		socket_control |= 0x2; +		break; +	case 33: +		socket_control |= 0x3; +		break; +	case 0: +	default: +	} + +	writel(socket_control, reg); +	 +	debug ("voltage_set: Ti PCI1410A Slot %d, Vcc=%d.%d, Vpp=%d.%d\n", +		slot, vcc/10, vcc%10, vpp/10, vpp%10); +	 +	udelay(500); +	return 0; +} + +	 +static int hardware_enable(int slot) +{ +	u32 socket_status; +	u16 brg_ctrl; +	int is_82365sl; +	 +	socket_status = readl(socket_base+8); +	 +	if ((socket_status & 6) == 0) { +		 +		switch (socket_status & 0x3c00) { +			 +		case 0x400: +			printf("5V "); +			voltage_set(slot, 50, 0); +			break; +		case 0x800: +			voltage_set(slot, 33, 0); +			break; +		case 0xc00: +			voltage_set(slot, 33, 0); +			break; +		default: +			voltage_set(slot, 0, 0); +			break; +		} +	} else { +		voltage_set(slot, 0, 0); +	} +	 +	pci_read_config_word(devbusfn, PCI_BRIDGE_CONTROL, &brg_ctrl); +	brg_ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; +	pci_write_config_word(devbusfn, PCI_BRIDGE_CONTROL, brg_ctrl); +	is_82365sl = ((readb(socket_base+0x800) & 0x0f) == 2);  +	writeb(is_82365sl?0x90:0x98, socket_base+0x802); +	writeb(0x67, socket_base+0x803); +	udelay(100000); +#if 0	 +	printf("ExCA Id %02x, Card Status %02x, Power config %02x, Interrupt Config %02x, bridge control %04x %d\n",  +	       readb(socket_base+0x800), readb(socket_base+0x801), +	       readb(socket_base+0x802), readb(socket_base+0x803), brg_ctrl, is_82365sl); +#endif	 +	 +	return ((readb(socket_base+0x801)&0x6c)==0x6c)?0:1; +} + + + +static int hardware_disable(int slot) +{ +	voltage_set(slot, 0, 0); +	return 0; +} + +static void print_funcid(int func) +{ +	puts(indent); +	switch (func) { +	case CISTPL_FUNCID_MULTI: +		puts(" Multi-Function"); +		break; +	case CISTPL_FUNCID_MEMORY: +		puts(" Memory"); +		break; +	case CISTPL_FUNCID_SERIAL: +		puts(" Serial Port"); +		break; +	case CISTPL_FUNCID_PARALLEL: +		puts(" Parallel Port"); +		break; +	case CISTPL_FUNCID_FIXED: +		puts(" Fixed Disk"); +		break; +	case CISTPL_FUNCID_VIDEO: +		puts(" Video Adapter"); +		break; +	case CISTPL_FUNCID_NETWORK: +		puts(" Network Adapter"); +		break; +	case CISTPL_FUNCID_AIMS: +		puts(" AIMS Card"); +		break; +	case CISTPL_FUNCID_SCSI: +		puts(" SCSI Adapter"); +		break; +	default: +		puts(" Unknown"); +		break; +	} +	puts(" Card\n"); +} + +/* ------------------------------------------------------------------------- */ + +static void print_fixed(volatile uchar *p) +{ +	if (p == NULL) +		return; + +	puts(indent); +	 +	switch (*p) { +	case CISTPL_FUNCE_IDE_IFACE: +		{   uchar iface = *(p+2); +			 +			puts ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown"); +			puts (" interface "); +			break; +		} +	case CISTPL_FUNCE_IDE_MASTER: +	case CISTPL_FUNCE_IDE_SLAVE: +		{ +			uchar f1 = *(p+2); +			uchar f2 = *(p+4); +			 +			puts((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]"); +			 +			if (f1 & CISTPL_IDE_UNIQUE) { +				puts(" [unique]"); +			} +			 +			puts((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]"); +			 +			if (f2 & CISTPL_IDE_HAS_SLEEP) { +				puts(" [sleep]"); +			} +			 +			if (f2 & CISTPL_IDE_HAS_STANDBY) { +				puts(" [standby]"); +			} +			 +			if (f2 & CISTPL_IDE_HAS_IDLE) { +				puts(" [idle]"); +			} +			 +			if (f2 & CISTPL_IDE_LOW_POWER) { +				puts(" [low power]"); +			} +			 +			if (f2 & CISTPL_IDE_REG_INHIBIT) { +				puts(" [reg inhibit]"); +			} +			 +			if (f2 & CISTPL_IDE_HAS_INDEX) { +				puts(" [index]"); +			} +			 +			if (f2 & CISTPL_IDE_IOIS16) { +				puts(" [IOis16]"); +			} +			 +			break; +		} +	} +	putc('\n'); +} + +/* ------------------------------------------------------------------------- */ + +#define MAX_IDENT_CHARS		64 +#define	MAX_IDENT_FIELDS	4 + +static uchar *known_cards[] = { +	"ARGOSY PnPIDE D5", +	NULL +}; + +static int identify(volatile uchar *p) +{ +	uchar id_str[MAX_IDENT_CHARS]; +	uchar data; +	uchar *t; +	uchar **card; +	int i, done; + +	if (p == NULL) +		return (0);	/* Don't know */ +	 +	t = id_str; +	done =0; +	 +	for (i=0; i<=4 && !done; ++i, p+=2) { +		while ((data = *p) != '\0') { +			if (data == 0xFF) { +				done = 1; +				break; +			} +			*t++ = data; +			if (t == &id_str[MAX_IDENT_CHARS-1]) { +				done = 1; +				break; +			} +			p += 2; +		} +		if (!done) +			*t++ = ' '; +	} +	*t = '\0'; +	while (--t > id_str) { +		if (*t == ' ') { +			*t = '\0'; +		} else { +			break; +		} +	} +	puts(id_str); +	putc('\n'); + +	for (card=known_cards; *card; ++card) { +		debug ("## Compare against \"%s\"\n", *card); +		if (strcmp(*card, id_str) == 0) {	/* found! */ +			debug ("## CARD FOUND ##\n"); +			return 1; +		} +	} +	 +	return 0;	/* don't know */ +} + +#endif /* CONFIG_IDE_TI_CARDBUS */ |