📄 cmd_pcmcia.c
字号:
/*
* (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 + -