Skip to content
Snippets Groups Projects
cmd_pcmcia.c 59 KiB
Newer Older
  • Learn to ignore specific revisions
  • Wolfgang Denk's avatar
    Wolfgang Denk committed
    /*
     * (C) Copyright 2000-2002
     * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
     *
     * 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...
     */
    
    /* #define DEBUG	1	*/
    
    /*
     * PCMCIA support
     */
    #include <common.h>
    #include <command.h>
    #include <config.h>
    #include <pcmcia.h>
    #include <cmd_pcmcia.h>
    #if defined(CONFIG_IDE_8xx_PCCARD) && defined(CONFIG_8xx)
    #include <mpc8xx.h>
    #endif
    #if defined(CONFIG_LWMON)
    #include <i2c.h>
    #endif
    
    #if (CONFIG_COMMANDS & CFG_CMD_PCMCIA) || \
        ((CONFIG_COMMANDS & CFG_CMD_IDE) && defined(CONFIG_IDE_8xx_PCCARD))
    
    int pcmcia_on (void);
    
    #if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
    static int  pcmcia_off (void);
    static int  hardware_disable(int slot);
    #endif
    static int  hardware_enable (int slot);
    static int  voltage_set(int slot, int vcc, int vpp);
    #ifdef CONFIG_IDE_8xx_PCCARD
    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);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    #endif	/* CONFIG_IDE_8xx_PCCARD */
    
    static u_int m8xx_get_graycode(u_int size);
    #if 0
    static u_int m8xx_get_speed(u_int ns, u_int is_io);
    #endif
    
    
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    /* look up table for pgcrx registers */
    
    static u_int *pcmcia_pgcrx[2] = {
    	&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pgcra,
    	&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pgcrb,
    };
    
    #define PCMCIA_PGCRX(slot)	(*pcmcia_pgcrx[slot])
    
    const char *indent = "\t   ";
    
    
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    #if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
    
    int do_pinit (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
    {
    	int rcode = 0;
    
    	if (argc != 2) {
    		printf ("Usage: pinit {on | off}\n");
    		return 1;
    	}
    	if (strcmp(argv[1],"on") == 0) {
    	     	rcode = pcmcia_on ();
    	} else if (strcmp(argv[1],"off") == 0) {
    		rcode = pcmcia_off ();
    	} else {
    		printf ("Usage: pinit {on | off}\n");
    		return 1;
    	}
    
    	return rcode;
    }
    #endif	/* CFG_CMD_PCMCIA */
    
    
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    #if defined(CONFIG_LWMON)
    # define  CFG_PCMCIA_TIMING	(PCMCIA_SHT(9) | PCMCIA_SST(3) | PCMCIA_SL(12))
    #else
    # define  CFG_PCMCIA_TIMING	(PCMCIA_SHT(2) | PCMCIA_SST(4) | PCMCIA_SL(9))
    #endif
    
    int pcmcia_on (void)
    {
    	int i;
    	u_long reg, base;
    	pcmcia_win_t *win;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    	debug ("Enable PCMCIA " PCMCIA_SLOT_MSG "\n");
    
    	/* intialize the fixed memory windows */
    	win = (pcmcia_win_t *)(&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pbr0);
    	base = CFG_PCMCIA_MEM_ADDR;
    
    	if((reg = m8xx_get_graycode(CFG_PCMCIA_MEM_SIZE)) == -1) {
    		printf ("Cannot set window size to 0x%08x\n",
    			CFG_PCMCIA_MEM_SIZE);
    		return (1);
    	}
    
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	for (i=0; i<PCMCIA_MEM_WIN_NO; ++i) {
    		win->br = base;
    
    
    #if (PCMCIA_SOCKETS_NO == 2)
    		if (i == 4) /* Another slot starting from win 4 */
    			slotbit = (slotbit ? PCMCIA_PSLOT_A : PCMCIA_PSLOT_B);
    #endif
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		switch (i) {
    #ifdef CONFIG_IDE_8xx_PCCARD
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		case 0:	{	/* map attribute memory */
    			win->or = (	PCMCIA_BSIZE_64M
    				|	PCMCIA_PPS_8
    				|	PCMCIA_PRS_ATTR
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    				|	PCMCIA_PV
    				|	CFG_PCMCIA_TIMING );
    			break;
    		    }
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		case 1: {	/* map I/O window for data reg */
    			win->or = (	PCMCIA_BSIZE_1K
    				|	PCMCIA_PPS_16
    				|	PCMCIA_PRS_IO
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    				|	PCMCIA_PV
    				|	CFG_PCMCIA_TIMING );
    			break;
    		    }
    
    		case 2: {	/* map I/O window for cmd/ctrl reg block */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    			win->or = (	PCMCIA_BSIZE_1K
    				|	PCMCIA_PPS_8
    				|	PCMCIA_PRS_IO
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    				|	PCMCIA_PV
    				|	CFG_PCMCIA_TIMING );
    			break;
    		    }
    #endif	/* CONFIG_IDE_8xx_PCCARD */
    		default:	/* set to not valid */
    			win->or = 0;
    			break;
    		}
    
    		debug ("MemWin %d: PBR 0x%08lX  POR %08lX\n",
    			i, win->br, win->or);
    		base += CFG_PCMCIA_MEM_SIZE;
    		++win;
    	}
    
    
    	for (i=0, rc=0, slot=_slot_; i<PCMCIA_SOCKETS_NO; i++, slot = !slot) {
    
    		/* turn off voltage */
    		if ((rc = voltage_set(slot, 0, 0)))
    			continue;
    
    		/* Enable external hardware */
    		if ((rc = hardware_enable(slot)))
    			continue;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    #ifdef CONFIG_IDE_8xx_PCCARD
    
    		if ((rc = check_ide_device(i)))
    			continue;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    #endif
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    }
    
    
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    #if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
    
    static int pcmcia_off (void)
    {
    	int i;
    	pcmcia_win_t *win;
    
    	printf ("Disable PCMCIA " PCMCIA_SLOT_MSG "\n");
    
    	/* clear interrupt state, and disable interrupts */
    	((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pscr =  PCMCIA_MASK(_slot_);
    	((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_per &= ~PCMCIA_MASK(_slot_);
    
    	/* turn off interrupt and disable CxOE */
    	PCMCIA_PGCRX(_slot_) = __MY_PCMCIA_GCRX_CXOE;
    
    	/* turn off memory windows */
    	win = (pcmcia_win_t *)(&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pbr0);
    
    	for (i=0; i<PCMCIA_MEM_WIN_NO; ++i) {
    		/* disable memory window */
    		win->or = 0;
    		++win;
    	}
    
    	/* turn off voltage */
    	voltage_set(_slot_, 0, 0);
    
    	/* disable external hardware */
    	printf ("Shutdown and Poweroff " PCMCIA_SLOT_MSG "\n");
    	hardware_disable(_slot_);
    	return 0;
    }
    
    #endif	/* CFG_CMD_PCMCIA */
    
    
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    #ifdef CONFIG_IDE_8xx_PCCARD
    
    #define	MAX_TUPEL_SZ	512
    #define MAX_FEATURES	4
    
    
    static int check_ide_device (int slot)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    {
    	volatile uchar *ident = NULL;
    	volatile uchar *feature_p[MAX_FEATURES];
    
    	volatile uchar *p, *start, *addr;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	int n_features = 0;
    	uchar func_id = ~0;
    	uchar code, len;
    	ushort config_base = 0;
    	int found = 0;
    	int i;
    
    
    	addr = (volatile uchar *)(CFG_PCMCIA_MEM_ADDR +
    				  CFG_PCMCIA_MEM_SIZE * (slot * 4));
    
    	debug ("PCMCIA MEM: %08X\n", addr);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    	start = p = (volatile uchar *) addr;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    	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);
    	}
    
    	/* set I/O area in config reg -> only valid for ARGOSY D5!!! */
    
    	*((uchar *)(addr + config_base)) = 1;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    	return (0);
    }
    #endif	/* CONFIG_IDE_8xx_PCCARD */
    
    
    /* -------------------------------------------------------------------- */
    
    /* -------------------------------------------------------------------- */
    /* board specific stuff:						*/
    /* voltage_set(), hardware_enable() and hardware_disable()		*/
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    /* -------------------------------------------------------------------- */
    /* RPX Boards from Embedded Planet					*/
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    #if defined(CONFIG_RPXCLASSIC) || defined(CONFIG_RPXLITE)
    
    /* The RPX boards seems to have it's bus monitor timeout set to 6*8 clocks.
     * SYPCR is write once only, therefore must the slowest memory be faster
     * than the bus monitor or we will get a machine check due to the bus timeout.
     */
    
    #define PCMCIA_BOARD_MSG "RPX CLASSIC or RPX LITE"
    
    #undef PCMCIA_BMT_LIMIT
    #define PCMCIA_BMT_LIMIT (6*8)
    
    static int voltage_set(int slot, int vcc, int vpp)
    {
    	u_long reg = 0;
    
    	switch(vcc) {
    	case 0: break;
    	case 33: reg |= BCSR1_PCVCTL4; break;
    	case 50: reg |= BCSR1_PCVCTL5; break;
    	default: return 1;
    	}
    
    	switch(vpp) {
    	case 0: break;
    	case 33:
    	case 50:
    		if(vcc == vpp)
    			reg |= BCSR1_PCVCTL6;
    		else
    			return 1;
    		break;
    	case 120:
    		reg |= BCSR1_PCVCTL7;
    	default: return 1;
    	}
    
    	if(vcc == 120)
    	   return 1;
    
    	/* first, turn off all power */
    
    	*((uint *)RPX_CSR_ADDR) &= ~(BCSR1_PCVCTL4 | BCSR1_PCVCTL5
    				     | BCSR1_PCVCTL6 | BCSR1_PCVCTL7);
    
    	/* enable new powersettings */
    
    	*((uint *)RPX_CSR_ADDR) |= reg;
    
    	return 0;
    }
    
    #define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
    static int hardware_enable (int slot)
    {
    	return 0;	/* No hardware to enable */
    }
    #if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
    static int hardware_disable(int slot)
    {
    	return 0;	/* No hardware to disable */
    }
    #endif	/* CFG_CMD_PCMCIA */
    #endif	/* CONFIG_RPXCLASSIC */
    
    
    /* -------------------------------------------------------------------- */
    /* (F)ADS Boards from Motorola						*/
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    #if defined(CONFIG_ADS) || defined(CONFIG_FADS)
    
    #ifdef CONFIG_ADS
    #define PCMCIA_BOARD_MSG "ADS"
    #define PCMCIA_GLITCHY_CD  /* My ADS board needs this */
    #else
    #define PCMCIA_BOARD_MSG "FADS"
    #endif
    
    static int voltage_set(int slot, int vcc, int vpp)
    {
    	u_long reg = 0;
    
    	switch(vpp) {
    	case 0: reg = 0; break;
    	case 50: reg = 1; break;
    	case 120: reg = 2; break;
    	default: return 1;
    	}
    
    	switch(vcc) {
    	case 0: reg = 0; break;
    #ifdef CONFIG_ADS
    	case 50: reg = BCSR1_PCCVCCON; break;
    #endif
    #ifdef CONFIG_FADS
    	case 33: reg = BCSR1_PCCVCC0 | BCSR1_PCCVCC1; break;
    	case 50: reg = BCSR1_PCCVCC1; break;
    #endif
    	default: return 1;
    	}
    
    	/* first, turn off all power */
    
    #ifdef CONFIG_ADS
    	*((uint *)BCSR1) |= BCSR1_PCCVCCON;
    #endif
    #ifdef CONFIG_FADS
    	*((uint *)BCSR1) &= ~(BCSR1_PCCVCC0 | BCSR1_PCCVCC1);
    #endif
    	*((uint *)BCSR1) &= ~BCSR1_PCCVPP_MASK;
    
    	/* enable new powersettings */
    
    #ifdef CONFIG_ADS
    	*((uint *)BCSR1) &= ~reg;
    #endif
    #ifdef CONFIG_FADS
    	*((uint *)BCSR1) |= reg;
    #endif
    
     	*((uint *)BCSR1) |= reg << 20;
    
    	return 0;
    }
    
    #define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
    
    static int hardware_enable(int slot)
    {
    	*((uint *)BCSR1) &= ~BCSR1_PCCEN;
    	return 0;
    }
    
    #if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
    static int hardware_disable(int slot)
    {
    	*((uint *)BCSR1) &= ~BCSR1_PCCEN;
    	return 0;
    }
    #endif	/* CFG_CMD_PCMCIA */
    
    #endif	/* (F)ADS */
    
    
    /* -------------------------------------------------------------------- */
    /* TQM8xxL Boards by TQ Components					*/
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    #if defined(CONFIG_TQM8xxL)
    
    #define PCMCIA_BOARD_MSG "TQM8xxL"
    
    
    static int hardware_enable(int slot)
    {
    	volatile immap_t	*immap;
    	volatile cpm8xx_t	*cp;
    	volatile pcmconf8xx_t	*pcmp;
    	volatile sysconf8xx_t	*sysp;
    	uint reg, mask;
    
    	debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
    
    	udelay(10000);
    
    	immap = (immap_t *)CFG_IMMR;
    	sysp  = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
    	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
    	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
    
    	/*
    	 * Configure SIUMCR to enable PCMCIA port B
    	 * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
    	 */
    	sysp->sc_siumcr &= ~SIUMCR_DBGC11;	/* set DBGC to 00 */
    
    	/* clear interrupt state, and disable interrupts */
    	pcmp->pcmc_pscr =  PCMCIA_MASK(_slot_);
    	pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
    
    	/*
    
    	 * Disable interrupts, DMA, and PCMCIA buffers
    	 * (isolate the interface) and assert RESET signal
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	 */
    	debug ("Disable PCMCIA buffers and assert RESET\n");
    
    	reg  = 0;
    	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	PCMCIA_PGCRX(_slot_) = reg;
    	udelay(500);
    
    	/*
    	 * Configure Port C pins for
    	 * 5 Volts Enable and 3 Volts enable
    	 */
    	immap->im_ioport.iop_pcpar &= ~(0x0002 | 0x0004);
    	immap->im_ioport.iop_pcso  &= ~(0x0002 | 0x0004);
    	/* remove all power */
    
    	immap->im_ioport.iop_pcdat &= ~(0x0002 | 0x0004);
    
    	/*
    	 * Make sure there is a card in the slot, then configure the interface.
    	 */
    	udelay(10000);
    	debug ("[%d] %s: PIPR(%p)=0x%x\n",
    		__LINE__,__FUNCTION__,
    		&(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
    
    	if (pcmp->pcmc_pipr & (0x18000000 >> (slot << 4))) {
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		printf ("   No Card found\n");
    		return (1);
    	}
    
    	/*
    	 * Power On.
    	 */
    	mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
    	reg  = pcmp->pcmc_pipr;
    	debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
    		reg,
    		(reg&PCMCIA_VS1(slot))?"n":"ff",
    		(reg&PCMCIA_VS2(slot))?"n":"ff");
    	if ((reg & mask) == mask) {
    		immap->im_ioport.iop_pcdat |= 0x0004;
    		puts (" 5.0V card found: ");
    	} else {
    		immap->im_ioport.iop_pcdat |= 0x0002;
    		puts (" 3.3V card found: ");
    	}
    
    	immap->im_ioport.iop_pcdir |= (0x0002 | 0x0004);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    #if 0
    	/*  VCC switch error flag, PCMCIA slot INPACK_ pin */
    	cp->cp_pbdir &= ~(0x0020 | 0x0010);
    	cp->cp_pbpar &= ~(0x0020 | 0x0010);
    	udelay(500000);
    #endif
    	udelay(1000);
    	debug ("Enable PCMCIA buffers and stop RESET\n");
    	reg  =  PCMCIA_PGCRX(_slot_);
    	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
    	PCMCIA_PGCRX(_slot_) = reg;
    
    	udelay(250000);	/* some cards need >150 ms to come up :-( */
    
    	debug ("# hardware_enable done\n");
    
    	return (0);
    }
    
    
    
    #if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
    static int hardware_disable(int slot)
    {
    	volatile immap_t	*immap;
    	volatile pcmconf8xx_t	*pcmp;
    	u_long reg;
    
    	debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
    
    	immap = (immap_t *)CFG_IMMR;
    	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
    
    	/* remove all power */
    	immap->im_ioport.iop_pcdat &= ~(0x0002 | 0x0004);
    
    	debug ("Disable PCMCIA buffers and assert RESET\n");
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
    	PCMCIA_PGCRX(_slot_) = reg;
    
    	udelay(10000);
    
    	return (0);
    }
    #endif	/* CFG_CMD_PCMCIA */
    
    
    
    static int voltage_set(int slot, int vcc, int vpp)
    {
    	volatile immap_t	*immap;
    	volatile pcmconf8xx_t	*pcmp;
    	u_long reg;
    
    	debug ("voltage_set: "
    		PCMCIA_BOARD_MSG
    		" Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
    		'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
    
    	immap = (immap_t *)CFG_IMMR;
    	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
    	/*
    	 * Disable PCMCIA buffers (isolate the interface)
    	 * and assert RESET signal
    	 */
    	debug ("Disable PCMCIA buffers and assert RESET\n");
    
    	reg  = PCMCIA_PGCRX(_slot_);
    	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	PCMCIA_PGCRX(_slot_) = reg;
    	udelay(500);
    
    	/*
    	 * Configure Port C pins for
    	 * 5 Volts Enable and 3 Volts enable,
    	 * Turn off all power
    	 */
    	debug ("PCMCIA power OFF\n");
    	immap->im_ioport.iop_pcpar &= ~(0x0002 | 0x0004);
    	immap->im_ioport.iop_pcso  &= ~(0x0002 | 0x0004);
    	immap->im_ioport.iop_pcdat &= ~(0x0002 | 0x0004);
    
    	reg = 0;
    	switch(vcc) {
    	case  0: 		break;
    	case 33: reg |= 0x0002;	break;
    	case 50: reg |= 0x0004;	break;
    	default: 		goto done;
    	}
    
    	/* Checking supported voltages */
    
    	debug ("PIPR: 0x%x --> %s\n",
    		pcmp->pcmc_pipr,
    		(pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
    
    	immap->im_ioport.iop_pcdat |= reg;
    
    	immap->im_ioport.iop_pcdir |= (0x0002 | 0x0004);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	if (reg) {
    		debug ("PCMCIA powered at %sV\n",
    			(reg&0x0004) ? "5.0" : "3.3");
    	} else {
    		debug ("PCMCIA powered down\n");
    	}
    
    done:
    	debug ("Enable PCMCIA buffers and stop RESET\n");
    	reg  =  PCMCIA_PGCRX(_slot_);
    	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
    	PCMCIA_PGCRX(_slot_) = reg;
    	udelay(500);
    
    	debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
    		slot+'A');
    	return (0);
    }
    
    #endif	/* TQM8xxL */
    
    
    
    /* -------------------------------------------------------------------- */
    /* LWMON Board								*/
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    #if defined(CONFIG_LWMON)
    
    #define PCMCIA_BOARD_MSG "LWMON"
    
    /* #define's for MAX1604 Power Switch */
    #define MAX1604_OP_SUS		0x80
    #define MAX1604_VCCBON		0x40
    #define MAX1604_VCC_35		0x20
    #define MAX1604_VCCBHIZ		0x10
    #define MAX1604_VPPBON		0x08
    #define MAX1604_VPPBPBPGM	0x04
    #define MAX1604_VPPBHIZ		0x02
    /* reserved			0x01	*/
    
    static int hardware_enable(int slot)
    {
    	volatile immap_t	*immap;
    	volatile cpm8xx_t	*cp;
    	volatile pcmconf8xx_t	*pcmp;
    	volatile sysconf8xx_t	*sysp;
    	uint reg, mask;
    	uchar val;
    
    
    	debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
    
    	/* Switch on PCMCIA port in PIC register 0x60 */
    	reg = pic_read  (0x60);
    	debug ("[%d] PIC read: reg_60 = 0x%02x\n", __LINE__, reg);
    	reg &= ~0x10;
    
    	/* reg |= 0x08; Vpp not needed */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	pic_write (0x60, reg);
    #ifdef DEBUG
    	reg = pic_read  (0x60);
    	printf ("[%d] PIC read: reg_60 = 0x%02x\n", __LINE__, reg);
    #endif
    	udelay(10000);
    
    	immap = (immap_t *)CFG_IMMR;
    	sysp  = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
    	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
    	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
    
    	/*
    	 * Configure SIUMCR to enable PCMCIA port B
    	 * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
    	 */
    	sysp->sc_siumcr &= ~SIUMCR_DBGC11;	/* set DBGC to 00 */
    
    	/* clear interrupt state, and disable interrupts */
    	pcmp->pcmc_pscr =  PCMCIA_MASK(_slot_);
    	pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
    
    	/*
    
    	 * Disable interrupts, DMA, and PCMCIA buffers
    	 * (isolate the interface) and assert RESET signal
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	 */
    	debug ("Disable PCMCIA buffers and assert RESET\n");
    
    	reg  = 0;
    	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	PCMCIA_PGCRX(_slot_) = reg;
    	udelay(500);
    
    	/*
    	 * Make sure there is a card in the slot, then configure the interface.
    	 */
    	udelay(10000);
    	debug ("[%d] %s: PIPR(%p)=0x%x\n",
    		__LINE__,__FUNCTION__,
    		&(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
    
    	if (pcmp->pcmc_pipr & (0x18000000 >> (slot << 4))) {
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		printf ("   No Card found\n");
    		return (1);
    	}
    
    	/*
    	 * Power On.
    	 */
    	mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
    	reg  = pcmp->pcmc_pipr;
    	debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
    		reg,
    		(reg&PCMCIA_VS1(slot))?"n":"ff",
    		(reg&PCMCIA_VS2(slot))?"n":"ff");
    	if ((reg & mask) == mask) {
    		val = 0;		/* VCCB3/5 = 0 ==> use Vx = 5.0 V */
    		puts (" 5.0V card found: ");
    	} else {
    		val = MAX1604_VCC_35;	/* VCCB3/5 = 1 ==> use Vy = 3.3 V */
    		puts (" 3.3V card found: ");
    	}
    
    	/*  switch VCC on */
    
    	val |= MAX1604_OP_SUS | MAX1604_VCCBON;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	i2c_init  (CFG_I2C_SPEED, CFG_I2C_SLAVE);
    	i2c_write (CFG_I2C_POWER_A_ADDR, 0, 0, &val, 1);
    
    	udelay(500000);
    
    	debug ("Enable PCMCIA buffers and stop RESET\n");
    	reg  =  PCMCIA_PGCRX(_slot_);
    	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
    	PCMCIA_PGCRX(_slot_) = reg;
    
    	udelay(250000);	/* some cards need >150 ms to come up :-( */
    
    	debug ("# hardware_enable done\n");
    
    	return (0);
    }
    
    
    
    #if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
    static int hardware_disable(int slot)
    {
    	volatile immap_t	*immap;
    	volatile pcmconf8xx_t	*pcmp;
    	u_long reg;
    	uchar val;
    
    	debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
    
    	immap = (immap_t *)CFG_IMMR;
    	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
    
    	/* remove all power, put output in high impedance state */
    	val  = MAX1604_VCCBHIZ | MAX1604_VPPBHIZ;
    	i2c_init  (CFG_I2C_SPEED, CFG_I2C_SLAVE);
    	i2c_write (CFG_I2C_POWER_A_ADDR, 0, 0, &val, 1);
    
    	/* Configure PCMCIA General Control Register */
    	debug ("Disable PCMCIA buffers and assert RESET\n");
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
    	PCMCIA_PGCRX(_slot_) = reg;
    
    	/* Switch off PCMCIA port in PIC register 0x60 */
    	reg = pic_read  (0x60);
    	debug ("[%d] PIC read: reg_60 = 0x%02x\n", __LINE__, reg);
    	reg |=  0x10;
    	reg &= ~0x08;
    	pic_write (0x60, reg);
    #ifdef DEBUG
    	reg = pic_read  (0x60);
    	printf ("[%d] PIC read: reg_60 = 0x%02x\n", __LINE__, reg);
    #endif
    	udelay(10000);
    
    	return (0);
    }
    #endif	/* CFG_CMD_PCMCIA */
    
    
    
    static int voltage_set(int slot, int vcc, int vpp)
    {
    	volatile immap_t	*immap;
    	volatile pcmconf8xx_t	*pcmp;
    	u_long reg;
    	uchar val;
    
    	debug ("voltage_set: "
    		PCMCIA_BOARD_MSG
    		" Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
    		'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
    
    	immap = (immap_t *)CFG_IMMR;
    	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
    	/*
    	 * Disable PCMCIA buffers (isolate the interface)
    	 * and assert RESET signal
    	 */
    	debug ("Disable PCMCIA buffers and assert RESET\n");
    
    	reg  = PCMCIA_PGCRX(_slot_);
    	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	PCMCIA_PGCRX(_slot_) = reg;
    	udelay(500);
    
    	/*
    	 * Turn off all power (switch to high impedance)
    	 */
    	debug ("PCMCIA power OFF\n");
    	val  = MAX1604_VCCBHIZ | MAX1604_VPPBHIZ;
    	i2c_init  (CFG_I2C_SPEED, CFG_I2C_SLAVE);
    	i2c_write (CFG_I2C_POWER_A_ADDR, 0, 0, &val, 1);
    
    	val = 0;
    	switch(vcc) {
    	case  0: 			break;
    	case 33: val = MAX1604_VCC_35;	break;
    	case 50: 			break;
    	default: 			goto done;
    	}
    
    	/* Checking supported voltages */
    
    	debug ("PIPR: 0x%x --> %s\n",
    		pcmp->pcmc_pipr,
    		(pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
    
    	i2c_write (CFG_I2C_POWER_A_ADDR, 0, 0, &val, 1);
    	if (val) {
    		debug ("PCMCIA powered at %sV\n",
    			(val & MAX1604_VCC_35) ? "3.3" : "5.0");
    	} else {
    		debug ("PCMCIA powered down\n");
    	}
    
    done:
    	debug ("Enable PCMCIA buffers and stop RESET\n");
    	reg  =  PCMCIA_PGCRX(_slot_);
    	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
    	PCMCIA_PGCRX(_slot_) = reg;
    	udelay(500);
    
    	debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
    		slot+'A');
    	return (0);
    }
    
    #endif	/* LWMON */
    
    
    /* -------------------------------------------------------------------- */
    /* GTH board by Corelatus AB						*/
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    #if defined(CONFIG_GTH)
    
    #define PCMCIA_BOARD_MSG "GTH COMPACT FLASH"
    
    
    static int voltage_set (int slot, int vcc, int vpp)
    {	/* Do nothing */
    	return 0;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    }
    
    static int hardware_enable (int slot)
    {
    
    	volatile immap_t *immap;
    	volatile cpm8xx_t *cp;
    	volatile pcmconf8xx_t *pcmp;
    	volatile sysconf8xx_t *sysp;
    	uint reg, mask;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    	debug ("hardware_enable: GTH Slot %c\n", 'A' + slot);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    	immap = (immap_t *) CFG_IMMR;
    	sysp = (sysconf8xx_t *) (&(((immap_t *) CFG_IMMR)->im_siu_conf));
    	pcmp = (pcmconf8xx_t *) (&(((immap_t *) CFG_IMMR)->im_pcmcia));
    	cp = (cpm8xx_t *) (&(((immap_t *) CFG_IMMR)->im_cpm));
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    	/* clear interrupt state, and disable interrupts */
    	pcmp->pcmc_pscr = PCMCIA_MASK (_slot_);
    	pcmp->pcmc_per &= ~PCMCIA_MASK (_slot_);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    	/*
    	 * Disable interrupts, DMA, and PCMCIA buffers
    	 * (isolate the interface) and assert RESET signal
    	 */
    	debug ("Disable PCMCIA buffers and assert RESET\n");
    	reg = 0;
    	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg |= __MY_PCMCIA_GCRX_CXOE;	/* active low  */
    	PCMCIA_PGCRX (_slot_) = reg;
    	udelay (500);
    
    	/*
    	 * Make sure there is a card in the slot,
    	 * then configure the interface.
    	 */
    	udelay (10000);