xref: /OK3568_Linux_fs/u-boot/cmd/pcmcia.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2000-2006
3*4882a593Smuzhiyun  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  ********************************************************************
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Lots of code copied from:
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * m8xx_pcmcia.c - Linux PCMCIA socket driver for the mpc8xx series.
12*4882a593Smuzhiyun  * (C) 1999-2000 Magnus Damm <damm@bitsmart.com>
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * "The ExCA standard specifies that socket controllers should provide
15*4882a593Smuzhiyun  * two IO and five memory windows per socket, which can be independently
16*4882a593Smuzhiyun  * configured and positioned in the host address space and mapped to
17*4882a593Smuzhiyun  * arbitrary segments of card address space. " - David A Hinds. 1999
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  * This controller does _not_ meet the ExCA standard.
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * m8xx pcmcia controller brief info:
22*4882a593Smuzhiyun  * + 8 windows (attrib, mem, i/o)
23*4882a593Smuzhiyun  * + up to two slots (SLOT_A and SLOT_B)
24*4882a593Smuzhiyun  * + inputpins, outputpins, event and mask registers.
25*4882a593Smuzhiyun  * - no offset register. sigh.
26*4882a593Smuzhiyun  *
27*4882a593Smuzhiyun  * Because of the lacking offset register we must map the whole card.
28*4882a593Smuzhiyun  * We assign each memory window PCMCIA_MEM_WIN_SIZE address space.
29*4882a593Smuzhiyun  * Make sure there is (PCMCIA_MEM_WIN_SIZE * PCMCIA_MEM_WIN_NO
30*4882a593Smuzhiyun  * * PCMCIA_SOCKETS_NO) bytes at PCMCIA_MEM_WIN_BASE.
31*4882a593Smuzhiyun  * The i/o windows are dynamically allocated at PCMCIA_IO_WIN_BASE.
32*4882a593Smuzhiyun  * They are maximum 64KByte each...
33*4882a593Smuzhiyun  */
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun /* #define DEBUG	1	*/
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun /*
38*4882a593Smuzhiyun  * PCMCIA support
39*4882a593Smuzhiyun  */
40*4882a593Smuzhiyun #include <common.h>
41*4882a593Smuzhiyun #include <command.h>
42*4882a593Smuzhiyun #include <config.h>
43*4882a593Smuzhiyun #include <pcmcia.h>
44*4882a593Smuzhiyun #include <asm/io.h>
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun /* -------------------------------------------------------------------- */
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun #if defined(CONFIG_CMD_PCMCIA)
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun extern int pcmcia_on (void);
51*4882a593Smuzhiyun extern int pcmcia_off (void);
52*4882a593Smuzhiyun 
do_pinit(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])53*4882a593Smuzhiyun int do_pinit (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	int rcode = 0;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	if (argc != 2) {
58*4882a593Smuzhiyun 		printf ("Usage: pinit {on | off}\n");
59*4882a593Smuzhiyun 		return 1;
60*4882a593Smuzhiyun 	}
61*4882a593Smuzhiyun 	if (strcmp(argv[1],"on") == 0) {
62*4882a593Smuzhiyun 		rcode = pcmcia_on ();
63*4882a593Smuzhiyun 	} else if (strcmp(argv[1],"off") == 0) {
64*4882a593Smuzhiyun 		rcode = pcmcia_off ();
65*4882a593Smuzhiyun 	} else {
66*4882a593Smuzhiyun 		printf ("Usage: pinit {on | off}\n");
67*4882a593Smuzhiyun 		return 1;
68*4882a593Smuzhiyun 	}
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	return rcode;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun U_BOOT_CMD(
74*4882a593Smuzhiyun 	pinit,	2,	0,	do_pinit,
75*4882a593Smuzhiyun 	"PCMCIA sub-system",
76*4882a593Smuzhiyun 	"on  - power on PCMCIA socket\n"
77*4882a593Smuzhiyun 	"pinit off - power off PCMCIA socket"
78*4882a593Smuzhiyun );
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun #endif
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun /* -------------------------------------------------------------------- */
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun #undef	CHECK_IDE_DEVICE
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun #if	defined(CONFIG_PXA_PCMCIA)
87*4882a593Smuzhiyun #define	CHECK_IDE_DEVICE
88*4882a593Smuzhiyun #endif
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun #ifdef	CHECK_IDE_DEVICE
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun int		ide_devices_found;
93*4882a593Smuzhiyun static uchar	*known_cards[] = {
94*4882a593Smuzhiyun 	(uchar *)"ARGOSY PnPIDE D5",
95*4882a593Smuzhiyun 	NULL
96*4882a593Smuzhiyun };
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun #define	MAX_TUPEL_SZ	512
99*4882a593Smuzhiyun #define MAX_FEATURES	4
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun #define MAX_IDENT_CHARS		64
102*4882a593Smuzhiyun #define	MAX_IDENT_FIELDS	4
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun #define	indent	"\t   "
105*4882a593Smuzhiyun 
print_funcid(int func)106*4882a593Smuzhiyun static void print_funcid (int func)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	puts (indent);
109*4882a593Smuzhiyun 	switch (func) {
110*4882a593Smuzhiyun 		case CISTPL_FUNCID_MULTI:
111*4882a593Smuzhiyun 			puts (" Multi-Function");
112*4882a593Smuzhiyun 			break;
113*4882a593Smuzhiyun 		case CISTPL_FUNCID_MEMORY:
114*4882a593Smuzhiyun 			puts (" Memory");
115*4882a593Smuzhiyun 			break;
116*4882a593Smuzhiyun 		case CISTPL_FUNCID_SERIAL:
117*4882a593Smuzhiyun 			puts (" Serial Port");
118*4882a593Smuzhiyun 			break;
119*4882a593Smuzhiyun 		case CISTPL_FUNCID_PARALLEL:
120*4882a593Smuzhiyun 			puts (" Parallel Port");
121*4882a593Smuzhiyun 			break;
122*4882a593Smuzhiyun 		case CISTPL_FUNCID_FIXED:
123*4882a593Smuzhiyun 			puts (" Fixed Disk");
124*4882a593Smuzhiyun 			break;
125*4882a593Smuzhiyun 		case CISTPL_FUNCID_VIDEO:
126*4882a593Smuzhiyun 			puts (" Video Adapter");
127*4882a593Smuzhiyun 			break;
128*4882a593Smuzhiyun 		case CISTPL_FUNCID_NETWORK:
129*4882a593Smuzhiyun 			puts (" Network Adapter");
130*4882a593Smuzhiyun 			break;
131*4882a593Smuzhiyun 		case CISTPL_FUNCID_AIMS:
132*4882a593Smuzhiyun 			puts (" AIMS Card");
133*4882a593Smuzhiyun 			break;
134*4882a593Smuzhiyun 		case CISTPL_FUNCID_SCSI:
135*4882a593Smuzhiyun 			puts (" SCSI Adapter");
136*4882a593Smuzhiyun 			break;
137*4882a593Smuzhiyun 		default:
138*4882a593Smuzhiyun 			puts (" Unknown");
139*4882a593Smuzhiyun 			break;
140*4882a593Smuzhiyun 	}
141*4882a593Smuzhiyun 	puts (" Card\n");
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
print_fixed(volatile uchar * p)144*4882a593Smuzhiyun static void print_fixed (volatile uchar *p)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	if (p == NULL)
147*4882a593Smuzhiyun 		return;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	puts(indent);
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	switch (*p) {
152*4882a593Smuzhiyun 		case CISTPL_FUNCE_IDE_IFACE:
153*4882a593Smuzhiyun 		{   uchar iface = *(p+2);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 		puts ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown");
156*4882a593Smuzhiyun 		puts (" interface ");
157*4882a593Smuzhiyun 		break;
158*4882a593Smuzhiyun 		}
159*4882a593Smuzhiyun 		case CISTPL_FUNCE_IDE_MASTER:
160*4882a593Smuzhiyun 		case CISTPL_FUNCE_IDE_SLAVE:
161*4882a593Smuzhiyun 		{   uchar f1 = *(p+2);
162*4882a593Smuzhiyun 		uchar f2 = *(p+4);
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 		puts ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]");
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 		if (f1 & CISTPL_IDE_UNIQUE)
167*4882a593Smuzhiyun 			puts (" [unique]");
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 		puts ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]");
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 		if (f2 & CISTPL_IDE_HAS_SLEEP)
172*4882a593Smuzhiyun 			puts (" [sleep]");
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 		if (f2 & CISTPL_IDE_HAS_STANDBY)
175*4882a593Smuzhiyun 			puts (" [standby]");
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 		if (f2 & CISTPL_IDE_HAS_IDLE)
178*4882a593Smuzhiyun 			puts (" [idle]");
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 		if (f2 & CISTPL_IDE_LOW_POWER)
181*4882a593Smuzhiyun 			puts (" [low power]");
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 		if (f2 & CISTPL_IDE_REG_INHIBIT)
184*4882a593Smuzhiyun 			puts (" [reg inhibit]");
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 		if (f2 & CISTPL_IDE_HAS_INDEX)
187*4882a593Smuzhiyun 			puts (" [index]");
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 		if (f2 & CISTPL_IDE_IOIS16)
190*4882a593Smuzhiyun 			puts (" [IOis16]");
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 		break;
193*4882a593Smuzhiyun 		}
194*4882a593Smuzhiyun 	}
195*4882a593Smuzhiyun 	putc ('\n');
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun 
identify(volatile uchar * p)198*4882a593Smuzhiyun static int identify  (volatile uchar *p)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun 	uchar id_str[MAX_IDENT_CHARS];
201*4882a593Smuzhiyun 	uchar data;
202*4882a593Smuzhiyun 	uchar *t;
203*4882a593Smuzhiyun 	uchar **card;
204*4882a593Smuzhiyun 	int i, done;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	if (p == NULL)
207*4882a593Smuzhiyun 		return (0);	/* Don't know */
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	t = id_str;
210*4882a593Smuzhiyun 	done =0;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	for (i=0; i<=4 && !done; ++i, p+=2) {
213*4882a593Smuzhiyun 		while ((data = *p) != '\0') {
214*4882a593Smuzhiyun 			if (data == 0xFF) {
215*4882a593Smuzhiyun 				done = 1;
216*4882a593Smuzhiyun 				break;
217*4882a593Smuzhiyun 			}
218*4882a593Smuzhiyun 			*t++ = data;
219*4882a593Smuzhiyun 			if (t == &id_str[MAX_IDENT_CHARS-1]) {
220*4882a593Smuzhiyun 				done = 1;
221*4882a593Smuzhiyun 				break;
222*4882a593Smuzhiyun 			}
223*4882a593Smuzhiyun 			p += 2;
224*4882a593Smuzhiyun 		}
225*4882a593Smuzhiyun 		if (!done)
226*4882a593Smuzhiyun 			*t++ = ' ';
227*4882a593Smuzhiyun 	}
228*4882a593Smuzhiyun 	*t = '\0';
229*4882a593Smuzhiyun 	while (--t > id_str) {
230*4882a593Smuzhiyun 		if (*t == ' ')
231*4882a593Smuzhiyun 			*t = '\0';
232*4882a593Smuzhiyun 		else
233*4882a593Smuzhiyun 			break;
234*4882a593Smuzhiyun 	}
235*4882a593Smuzhiyun 	puts ((char *)id_str);
236*4882a593Smuzhiyun 	putc ('\n');
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	for (card=known_cards; *card; ++card) {
239*4882a593Smuzhiyun 		debug ("## Compare against \"%s\"\n", *card);
240*4882a593Smuzhiyun 		if (strcmp((char *)*card, (char *)id_str) == 0) {	/* found! */
241*4882a593Smuzhiyun 			debug ("## CARD FOUND ##\n");
242*4882a593Smuzhiyun 			return (1);
243*4882a593Smuzhiyun 		}
244*4882a593Smuzhiyun 	}
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	return (0);	/* don't know */
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun 
check_ide_device(int slot)249*4882a593Smuzhiyun int check_ide_device (int slot)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun 	volatile uchar *ident = NULL;
252*4882a593Smuzhiyun 	volatile uchar *feature_p[MAX_FEATURES];
253*4882a593Smuzhiyun 	volatile uchar *p, *start, *addr;
254*4882a593Smuzhiyun 	int n_features = 0;
255*4882a593Smuzhiyun 	uchar func_id = ~0;
256*4882a593Smuzhiyun 	uchar code, len;
257*4882a593Smuzhiyun 	ushort config_base = 0;
258*4882a593Smuzhiyun 	int found = 0;
259*4882a593Smuzhiyun 	int i;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	addr = (volatile uchar *)(CONFIG_SYS_PCMCIA_MEM_ADDR +
262*4882a593Smuzhiyun 				  CONFIG_SYS_PCMCIA_MEM_SIZE * (slot * 4));
263*4882a593Smuzhiyun 	debug ("PCMCIA MEM: %08lX\n", (ulong)addr);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	start = p = (volatile uchar *) addr;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	while ((p - start) < MAX_TUPEL_SZ) {
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 		code = *p; p += 2;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 		if (code == 0xFF) { /* End of chain */
272*4882a593Smuzhiyun 			break;
273*4882a593Smuzhiyun 		}
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 		len = *p; p += 2;
276*4882a593Smuzhiyun #if defined(DEBUG) && (DEBUG > 1)
277*4882a593Smuzhiyun 		{ volatile uchar *q = p;
278*4882a593Smuzhiyun 			printf ("\nTuple code %02x  length %d\n\tData:",
279*4882a593Smuzhiyun 				code, len);
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 			for (i = 0; i < len; ++i) {
282*4882a593Smuzhiyun 				printf (" %02x", *q);
283*4882a593Smuzhiyun 				q+= 2;
284*4882a593Smuzhiyun 			}
285*4882a593Smuzhiyun 		}
286*4882a593Smuzhiyun #endif	/* DEBUG */
287*4882a593Smuzhiyun 		switch (code) {
288*4882a593Smuzhiyun 		case CISTPL_VERS_1:
289*4882a593Smuzhiyun 			ident = p + 4;
290*4882a593Smuzhiyun 			break;
291*4882a593Smuzhiyun 		case CISTPL_FUNCID:
292*4882a593Smuzhiyun 			/* Fix for broken SanDisk which may have 0x80 bit set */
293*4882a593Smuzhiyun 			func_id = *p & 0x7F;
294*4882a593Smuzhiyun 			break;
295*4882a593Smuzhiyun 		case CISTPL_FUNCE:
296*4882a593Smuzhiyun 			if (n_features < MAX_FEATURES)
297*4882a593Smuzhiyun 				feature_p[n_features++] = p;
298*4882a593Smuzhiyun 			break;
299*4882a593Smuzhiyun 		case CISTPL_CONFIG:
300*4882a593Smuzhiyun 			config_base = (*(p+6) << 8) + (*(p+4));
301*4882a593Smuzhiyun 			debug ("\n## Config_base = %04x ###\n", config_base);
302*4882a593Smuzhiyun 		default:
303*4882a593Smuzhiyun 			break;
304*4882a593Smuzhiyun 		}
305*4882a593Smuzhiyun 		p += 2 * len;
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	found = identify (ident);
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	if (func_id != ((uchar)~0)) {
311*4882a593Smuzhiyun 		print_funcid (func_id);
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 		if (func_id == CISTPL_FUNCID_FIXED)
314*4882a593Smuzhiyun 			found = 1;
315*4882a593Smuzhiyun 		else
316*4882a593Smuzhiyun 			return (1);	/* no disk drive */
317*4882a593Smuzhiyun 	}
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	for (i=0; i<n_features; ++i) {
320*4882a593Smuzhiyun 		print_fixed (feature_p[i]);
321*4882a593Smuzhiyun 	}
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	if (!found) {
324*4882a593Smuzhiyun 		printf ("unknown card type\n");
325*4882a593Smuzhiyun 		return (1);
326*4882a593Smuzhiyun 	}
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	ide_devices_found |= (1 << slot);
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	/* set I/O area in config reg -> only valid for ARGOSY D5!!! */
331*4882a593Smuzhiyun 	*((uchar *)(addr + config_base)) = 1;
332*4882a593Smuzhiyun #if 0
333*4882a593Smuzhiyun 	printf("\n## Config_base = %04x ###\n", config_base);
334*4882a593Smuzhiyun 	printf("Configuration Option Register: %02x @ %x\n", readb(addr + config_base), addr + config_base);
335*4882a593Smuzhiyun 	printf("Card Configuration and Status Register: %02x\n", readb(addr + config_base + 2));
336*4882a593Smuzhiyun 	printf("Pin Replacement Register Register: %02x\n", readb(addr + config_base + 4));
337*4882a593Smuzhiyun 	printf("Socket and Copy Register: %02x\n", readb(addr + config_base + 6));
338*4882a593Smuzhiyun #endif
339*4882a593Smuzhiyun 	return (0);
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun #endif	/* CHECK_IDE_DEVICE */
343