⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cmd_pcmcia.c

📁 嵌入式ARM的一些源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * (C) Copyright 2000
 * 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...
 */

/*
 * PCMCIA support
 */
#include <mpc8xx_irq.h>
#include <ppcboot.h>
#include <command.h>
#include <cmd_pcmcia.h>
#include <mpc8xx.h>


static int hardware_enable (int slot);
static int hardware_disable(int slot);
static int voltage_set(int slot, int vcc, int vpp);

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

/* ------------------------------------------------------------------------- */
/* Autoconfigure boards if no settings are defined                           */
#if defined(CONFIG_TQM823L) || defined(CONFIG_TQM850L) || defined(CONFIG_TQM860L)
#define	CONFIG_TQM8xxL
#endif

#if !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B)

/* The RPX series use SLOT_B */
#if defined(CONFIG_RPXCLASSIC) || defined(CONFIG_RPXLITE)
# define CONFIG_PCMCIA_SLOT_B
#endif

/* The ADS board use SLOT_A */
#ifdef CONFIG_ADS
# define CONFIG_PCMCIA_SLOT_A
#endif

/* The FADS series are a mess */
#ifdef CONFIG_FADS
# if defined(CONFIG_MPC860T) || defined(CONFIG_MPC860) || defined(CONFIG_MPC821)
#  define CONFIG_PCMCIA_SLOT_A
# else
#  define CONFIG_PCMCIA_SLOT_B
# endif
#endif

/* The TQM8xxL modules use SLOT_A on MPC860, SLOT_B else */
#ifdef	CONFIG_TQM8xxL
# if defined(CONFIG_MPC860T) || defined(CONFIG_MPC860)
#  define	CONFIG_PCMCIA_SLOT_A
# else	/* ! 860, 860T */
#  define	CONFIG_PCMCIA_SLOT_B
# endif	/* 860, 860T */
#endif	/* CONFIG_TQM8xxL */

#endif /* !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) */

/* Make sure exactly one slot is defined - we support only one for now */
#if !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B)
#error Neither CONFIG_PCMCIA_SLOT_A nor CONFIG_PCMCIA_SLOT_B configured
#endif
#if defined(CONFIG_PCMCIA_SLOT_A) && defined(CONFIG_PCMCIA_SLOT_B)
#error Both CONFIG_PCMCIA_SLOT_A and CONFIG_PCMCIA_SLOT_B configured
#endif

#define PCMCIA_SOCKETS_NO	1
#define PCMCIA_MEM_WIN_NO	4
#define PCMCIA_IO_WIN_NO	2

/* define _slot_ to be able to optimize macros */
#ifdef CONFIG_PCMCIA_SLOT_A
# define _slot_			0
# define PCMCIA_SLOT_MSG	"SLOT_A"
#else
# define _slot_			1
# define PCMCIA_SLOT_MSG	"SLOT_B"
#endif

/*
 * The TQM850L hardware has two pins swapped! Grrrrgh!
 */
#ifdef	CONFIG_TQM850L
#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXOE
#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXRESET
#else
#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXRESET
#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXOE
#endif

/* 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])

/*
 * This structure is used to address each window in the PCMCIA controller.
 *
 * Keep in mind that we assume that pcmcia_win_t[n+1] is mapped directly
 * after pcmcia_win_t[n]...
 */

typedef struct {
	uint	br;
	uint	or;
} pcmcia_win_t;



/* ------------------------------------------------------------------------- */

void do_pinit (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
{
	int i;
	u_long reg, base;
	pcmcia_win_t *win;

	if (argc != 2) {
		printf ("Usage: pinit {on | off}\n");
		return;
	}
	if (strcmp(argv[1],"on") == 0) {
		printf ("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;
		}
#if 0
XXX XXX XXX
if(mem->flags & MAP_ATTRIB)
	reg |= 0x00000010;

if(mem->flags & MAP_WRPROT)
	reg |= 0x00000002;

if(mem->flags & MAP_16BIT)
	reg |= 0x00000040;

if(mem->flags & MAP_ACTIVE)
	reg |= 0x00000001;
XXX XXX XXX
#endif

		for (i=0; i<PCMCIA_MEM_WIN_NO; ++i) {
			win->br = base;
			win->or = 0;	/* set to not valid */
printf ("MemWin %d: Base 0x%08lX\n", i, base);
			base += CFG_PCMCIA_MEM_SIZE;
			++win;
		}

		/* turn off voltage */
		voltage_set(_slot_, 0, 0);

		/* Enable external hardware */
		hardware_enable(_slot_);

	} else if (strcmp(argv[1],"off") == 0) {
		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_);
	} else {
		printf ("Usage: pinit {on | off}\n");
		return;
	}

	return;
}

/* ---------------------------------------------------------------------------- */
/* board specific stuff:							*/
/* voltage_set(), hardware_enable() and hardware_disable()			*/
/* ---------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------- */
/* RPX Boards from Embedded Planet						*/
/* ---------------------------------------------------------------------------- */

#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 */
}
static int hardware_disable(int slot)
{
	return 0;	/* No hardware to disable */
}
#endif /* CONFIG_RPXCLASSIC */

/* ---------------------------------------------------------------------------- */
/* (F)ADS Boards from Motorola							*/
/* ---------------------------------------------------------------------------- */

#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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -