📄 m8xx_pcmcia.c
字号:
/* * m8xx_pcmcia.c - Linux PCMCIA socket driver for the mpc8xx series. * * (C) 1999-2000 Magnus Damm <damm@opensource.se> * * "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 <asm/io.h>#include <asm/bitops.h>#include <asm/system.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/timer.h>#include <linux/ioport.h>#include <linux/delay.h>#include <asm/mpc8xx.h>#include <asm/8xx_immap.h>#include <asm/irq.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_PARM(pc_debug, "i");#define DEBUG(n, args...) printk(KERN_DEBUG "m8xx_pcmcia: " args);#else#define DEBUG(n, 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.03, 14-Feb-2000, Magnus Damm";/* ------------------------------------------------------------------------- *//* Autoconfigure boards if no settings are defined */ #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#endif /* !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) *//* ------------------------------------------------------------------------- */#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 */#define PCMCIA_SCHLVL PCMCIA_INTERRUPT /* Status Change Interrupt Level *//* ------------------------------------------------------------------------- */#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#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#if (LINUX_VERSION_CODE >= VERSION(2,4,0))/* 2.4.x has this always in HZ */#define M8XX_BUSFREQ ((((bd_t *)&(__res))->bi_busfreq))#else /* 2.2.x */#ifdef CONFIG_BD_IS_MHZ#define M8XX_BUSFREQ ((mpc8xx_bdinfo->bi_busfreq) * 1000000)#else#define M8XX_BUSFREQ (mpc8xx_bdinfo->bi_busfreq)#endif#endifstatic int pcmcia_schlvl = PCMCIA_SCHLVL;/* ------------------------------------------------------------------------- */#define PCMCIA_SOCKET_KEY_5V 1#define PCMCIA_SOCKET_KEY_LV 2/* look up table for pgcrx registers */static u_int *m8xx_pgcrx[2] = { &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcra, &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcrb}; /* * 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;/* * 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_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 */typedef struct { u_int regbit; u_int eventbit;} event_table_t;typedef struct socket_info_t { void (*handler)(void *info, u_int events); void *info; u_int slot; socket_state_t state; struct pccard_mem_map mem_win[PCMCIA_MEM_WIN_NO]; struct pccard_io_map io_win[PCMCIA_IO_WIN_NO]; event_table_t events[PCMCIA_EVENTS_MAX]; } socket_info_t;static socket_info_t socket[PCMCIA_SOCKETS_NO];static socket_cap_t capabilities = { /* only 16-bit cards, memory windows must be size-aligned */ SS_CAP_PCCARD | SS_CAP_MEM_ALIGN | SS_CAP_STATIC_MAP, 0x000, /* SIU_LEVEL 7 -> 0 */ 0x1000, /* 4K minimum window size */ 9, 0 /* No PCI or CardBus support */};/* * Search this table to see if the windowsize is * supported... */#define M8XX_SIZES_NO 32static const u_int 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 void m8xx_interrupt(int irq, void *dev, struct pt_regs *regs);static int m8xx_service(u_int sock, u_int cmd, void *arg);#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){ u_int 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 */ *((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#define hardware_enable(_slot_) /* No hardware to enable */#define hardware_disable(_slot_) /* 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"#endifstatic int voltage_set(int slot, int vcc, int vpp){ u_int 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_5Vstatic void hardware_enable(int slot){ *((uint *)BCSR1) &= ~BCSR1_PCCEN;}static void hardware_disable(int slot){ *((uint *)BCSR1) &= ~BCSR1_PCCEN;}#endif/* ------------------------------------------------------------------------- */static void m8xx_shutdown(void){ u_int k, m; pcmcia_win_t *w;#if (PCMCIA_SOCKETS_NO == 2) u_int _slot_;#endif w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; for(k = 0; k < PCMCIA_SOCKETS_NO; k++) {#if (PCMCIA_SOCKETS_NO == 2) _slot_ = socket[k].slot;#endif ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -