m8xx_pcmcia.c

来自「linux 内核源代码」· C语言 代码 · 共 1,339 行 · 第 1/3 页

C
1,339
字号
/* * m8xx_pcmcia.c - Linux PCMCIA socket driver for the mpc8xx series. * * (C) 1999-2000 Magnus Damm <damm@bitsmart.com> * (C) 2001-2002 Montavista Software, Inc. *     <mlocke@mvista.com> * * Support for two slots by Cyclades Corporation *     <oliver.kurth@cyclades.de> * Further fixes, v2.6 kernel port *     <marcelo.tosatti@cyclades.com> *  * Some fixes, additions (C) 2005-2007 Montavista Software, Inc. *     <vbordug@ru.mvista.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... */#include <linux/module.h>#include <linux/init.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/timer.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/fsl_devices.h>#include <linux/bitops.h>#include <asm/io.h>#include <asm/system.h>#include <asm/time.h>#include <asm/mpc8xx.h>#include <asm/8xx_immap.h>#include <asm/irq.h>#include <asm/fs_pd.h>#include <asm/of_device.h>#include <asm/of_platform.h>#include <pcmcia/version.h>#include <pcmcia/cs_types.h>#include <pcmcia/cs.h>#include <pcmcia/ss.h>#ifdef PCMCIA_DEBUGstatic int pc_debug = PCMCIA_DEBUG;module_param(pc_debug, int, 0);#define dprintk(args...) printk(KERN_DEBUG "m8xx_pcmcia: " args);#else#define dprintk(args...)#endif#define pcmcia_info(args...) printk(KERN_INFO "m8xx_pcmcia: "args)#define pcmcia_error(args...) printk(KERN_ERR "m8xx_pcmcia: "args)static const char *version = "Version 0.06, Aug 2005";MODULE_LICENSE("Dual MPL/GPL");#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#define CONFIG_BD_IS_MHZ#endif/* The ADS board use SLOT_A */#ifdef CONFIG_ADS#define CONFIG_PCMCIA_SLOT_A#define CONFIG_BD_IS_MHZ#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#if defined(CONFIG_MPC885ADS)#define CONFIG_PCMCIA_SLOT_A#define PCMCIA_GLITCHY_CD#endif/* Cyclades ACS uses both slots */#ifdef CONFIG_PRxK#define CONFIG_PCMCIA_SLOT_A#define CONFIG_PCMCIA_SLOT_B#endif#endif				/* !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) */#if defined(CONFIG_PCMCIA_SLOT_A) && defined(CONFIG_PCMCIA_SLOT_B)#define PCMCIA_SOCKETS_NO 2/* We have only 8 windows, dualsocket support will be limited. */#define PCMCIA_MEM_WIN_NO 2#define PCMCIA_IO_WIN_NO  2#define PCMCIA_SLOT_MSG "SLOT_A and SLOT_B"#elif defined(CONFIG_PCMCIA_SLOT_A) || defined(CONFIG_PCMCIA_SLOT_B)#define PCMCIA_SOCKETS_NO 1/* full support for one slot */#define PCMCIA_MEM_WIN_NO 5#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#else#error m8xx_pcmcia: Bad configuration!#endif/* ------------------------------------------------------------------------- */#define PCMCIA_MEM_WIN_BASE 0xe0000000	/* base address for memory window 0   */#define PCMCIA_MEM_WIN_SIZE 0x04000000	/* each memory window is 64 MByte     */#define PCMCIA_IO_WIN_BASE  _IO_BASE	/* base address for io window 0       *//* ------------------------------------------------------------------------- */static int pcmcia_schlvl;static DEFINE_SPINLOCK(events_lock);#define PCMCIA_SOCKET_KEY_5V 1#define PCMCIA_SOCKET_KEY_LV 2/* look up table for pgcrx registers */static u32 *m8xx_pgcrx[2];/* * This structure is used to address each window in the PCMCIA controller. * * Keep in mind that we assume that pcmcia_win[n+1] is mapped directly * after pcmcia_win[n]... */struct pcmcia_win {	u32 br;	u32 or;};/* * For some reason the hardware guys decided to make both slots share * some registers. * * Could someone invent object oriented hardware ? * * The macros are used to get the right bit from the registers. * SLOT_A : slot = 0 * SLOT_B : slot = 1 */#define M8XX_PCMCIA_VS1(slot)      (0x80000000 >> (slot << 4))#define M8XX_PCMCIA_VS2(slot)      (0x40000000 >> (slot << 4))#define M8XX_PCMCIA_VS_MASK(slot)  (0xc0000000 >> (slot << 4))#define M8XX_PCMCIA_VS_SHIFT(slot) (30 - (slot << 4))#define M8XX_PCMCIA_WP(slot)       (0x20000000 >> (slot << 4))#define M8XX_PCMCIA_CD2(slot)      (0x10000000 >> (slot << 4))#define M8XX_PCMCIA_CD1(slot)      (0x08000000 >> (slot << 4))#define M8XX_PCMCIA_BVD2(slot)     (0x04000000 >> (slot << 4))#define M8XX_PCMCIA_BVD1(slot)     (0x02000000 >> (slot << 4))#define M8XX_PCMCIA_RDY(slot)      (0x01000000 >> (slot << 4))#define M8XX_PCMCIA_RDY_L(slot)    (0x00800000 >> (slot << 4))#define M8XX_PCMCIA_RDY_H(slot)    (0x00400000 >> (slot << 4))#define M8XX_PCMCIA_RDY_R(slot)    (0x00200000 >> (slot << 4))#define M8XX_PCMCIA_RDY_F(slot)    (0x00100000 >> (slot << 4))#define M8XX_PCMCIA_MASK(slot)     (0xFFFF0000 >> (slot << 4))#define M8XX_PCMCIA_POR_VALID    0x00000001#define M8XX_PCMCIA_POR_WRPROT   0x00000002#define M8XX_PCMCIA_POR_ATTRMEM  0x00000010#define M8XX_PCMCIA_POR_IO       0x00000018#define M8XX_PCMCIA_POR_16BIT    0x00000040#define M8XX_PGCRX(slot)  m8xx_pgcrx[slot]#define M8XX_PGCRX_CXOE    0x00000080#define M8XX_PGCRX_CXRESET 0x00000040/* we keep one lookup table per socket to check flags */#define PCMCIA_EVENTS_MAX 5	/* 4 max at a time + termination */struct event_table {	u32 regbit;	u32 eventbit;};static const char driver_name[] = "m8xx-pcmcia";struct socket_info {	void (*handler) (void *info, u32 events);	void *info;	u32 slot;	pcmconf8xx_t *pcmcia;	u32 bus_freq;	int hwirq;	socket_state_t state;	struct pccard_mem_map mem_win[PCMCIA_MEM_WIN_NO];	struct pccard_io_map io_win[PCMCIA_IO_WIN_NO];	struct event_table events[PCMCIA_EVENTS_MAX];	struct pcmcia_socket socket;};static struct socket_info socket[PCMCIA_SOCKETS_NO];/* * Search this table to see if the windowsize is * supported... */#define M8XX_SIZES_NO 32static const u32 m8xx_size_to_gray[M8XX_SIZES_NO] = {	0x00000001, 0x00000002, 0x00000008, 0x00000004,	0x00000080, 0x00000040, 0x00000010, 0x00000020,	0x00008000, 0x00004000, 0x00001000, 0x00002000,	0x00000100, 0x00000200, 0x00000800, 0x00000400,	0x0fffffff, 0xffffffff, 0xffffffff, 0xffffffff,	0x01000000, 0x02000000, 0xffffffff, 0x04000000,	0x00010000, 0x00020000, 0x00080000, 0x00040000,	0x00800000, 0x00400000, 0x00100000, 0x00200000};/* ------------------------------------------------------------------------- */static irqreturn_t m8xx_interrupt(int irq, void *dev);#define PCMCIA_BMT_LIMIT (15*4)	/* Bus Monitor Timeout value *//* ------------------------------------------------------------------------- *//* 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){	u32 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 == 50) || (vcc == 0)))		return 1;	/* first, turn off all power */	out_be32(((u32 *) RPX_CSR_ADDR),		 in_be32(((u32 *) RPX_CSR_ADDR)) & ~(BCSR1_PCVCTL4 |						     BCSR1_PCVCTL5 |						     BCSR1_PCVCTL6 |						     BCSR1_PCVCTL7));	/* enable new powersettings */	out_be32(((u32 *) RPX_CSR_ADDR), in_be32(((u32 *) RPX_CSR_ADDR)) | reg);	return 0;}#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V#define hardware_enable(_slot_)	/* No hardware to enable */#define hardware_disable(_slot_)	/* No hardware to disable */#endif				/* CONFIG_RPXCLASSIC *//* FADS Boards from Motorola                                               */#if defined(CONFIG_FADS)#define PCMCIA_BOARD_MSG "FADS"static int voltage_set(int slot, int vcc, int vpp){	u32 reg = 0;	switch (vcc) {	case 0:		break;	case 33:		reg |= BCSR1_PCCVCC0;		break;	case 50:		reg |= BCSR1_PCCVCC1;		break;	default:		return 1;	}	switch (vpp) {	case 0:		break;	case 33:	case 50:		if (vcc == vpp)			reg |= BCSR1_PCCVPP1;		else			return 1;		break;	case 120:		if ((vcc == 33) || (vcc == 50))			reg |= BCSR1_PCCVPP0;		else			return 1;	default:		return 1;	}	/* first, turn off all power */	out_be32((u32 *) BCSR1,		 in_be32((u32 *) BCSR1) & ~(BCSR1_PCCVCC_MASK |					    BCSR1_PCCVPP_MASK));	/* enable new powersettings */	out_be32((u32 *) BCSR1, in_be32((u32 *) BCSR1) | reg);	return 0;}#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5Vstatic void hardware_enable(int slot){	out_be32((u32 *) BCSR1, in_be32((u32 *) BCSR1) & ~BCSR1_PCCEN);}static void hardware_disable(int slot){	out_be32((u32 *) BCSR1, in_be32((u32 *) BCSR1) | BCSR1_PCCEN);}#endif/* MPC885ADS Boards */#if defined(CONFIG_MPC885ADS)#define PCMCIA_BOARD_MSG "MPC885ADS"#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5Vstatic inline void hardware_enable(int slot){	m8xx_pcmcia_ops.hw_ctrl(slot, 1);}static inline void hardware_disable(int slot){	m8xx_pcmcia_ops.hw_ctrl(slot, 0);}static inline int voltage_set(int slot, int vcc, int vpp){	return m8xx_pcmcia_ops.voltage_set(slot, vcc, vpp);}#endif/* ------------------------------------------------------------------------- *//* Motorola MBX860                                                           */#if defined(CONFIG_MBX)#define PCMCIA_BOARD_MSG "MBX"static int voltage_set(int slot, int vcc, int vpp){	u8 reg = 0;	switch (vcc) {	case 0:

⌨️ 快捷键说明

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