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 + -
显示快捷键?