cmd_pcmcia.c 7.16 KB
Newer Older
wdenk's avatar
wdenk committed
1
/*
2
 * (C) Copyright 2000-2006
wdenk's avatar
wdenk committed
3 4
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *
5
 * SPDX-License-Identifier:	GPL-2.0+
wdenk's avatar
wdenk committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
 *
 ********************************************************************
 *
 * 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...
 */

/* #define DEBUG	1	*/

/*
 * PCMCIA support
 */
#include <common.h>
#include <command.h>
#include <config.h>
#include <pcmcia.h>
44 45
#include <asm/io.h>

46
/* -------------------------------------------------------------------- */
wdenk's avatar
wdenk committed
47

48
#if defined(CONFIG_CMD_PCMCIA)
49

50 51
extern int pcmcia_on (void);
extern int pcmcia_off (void);
wdenk's avatar
wdenk committed
52

53
int do_pinit (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenk's avatar
wdenk committed
54 55 56 57 58 59 60 61
{
	int rcode = 0;

	if (argc != 2) {
		printf ("Usage: pinit {on | off}\n");
		return 1;
	}
	if (strcmp(argv[1],"on") == 0) {
62
		rcode = pcmcia_on ();
wdenk's avatar
wdenk committed
63 64 65 66 67 68 69 70 71
	} else if (strcmp(argv[1],"off") == 0) {
		rcode = pcmcia_off ();
	} else {
		printf ("Usage: pinit {on | off}\n");
		return 1;
	}

	return rcode;
}
72

73
U_BOOT_CMD(
74
	pinit,	2,	0,	do_pinit,
Peter Tyser's avatar
Peter Tyser committed
75
	"PCMCIA sub-system",
76
	"on  - power on PCMCIA socket\n"
77 78
	"pinit off - power off PCMCIA socket"
);
79

80
#endif
81

82
/* -------------------------------------------------------------------- */
83

84
#undef	CHECK_IDE_DEVICE
85

86
#if defined(CONFIG_CMD_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
87
#define	CHECK_IDE_DEVICE
88
#endif
89 90 91

#if	defined(CONFIG_PXA_PCMCIA)
#define	CHECK_IDE_DEVICE
wdenk's avatar
wdenk committed
92 93
#endif

94
#ifdef	CHECK_IDE_DEVICE
wdenk's avatar
wdenk committed
95

96 97 98 99 100
int		ide_devices_found;
static uchar	*known_cards[] = {
	(uchar *)"ARGOSY PnPIDE D5",
	NULL
};
wdenk's avatar
wdenk committed
101

102 103
#define	MAX_TUPEL_SZ	512
#define MAX_FEATURES	4
wdenk's avatar
wdenk committed
104

105 106
#define MAX_IDENT_CHARS		64
#define	MAX_IDENT_FIELDS	4
wdenk's avatar
wdenk committed
107

108
#define	indent	"\t   "
wdenk's avatar
wdenk committed
109

110 111 112 113 114 115
static void print_funcid (int func)
{
	puts (indent);
	switch (func) {
		case CISTPL_FUNCID_MULTI:
			puts (" Multi-Function");
116
			break;
117 118
		case CISTPL_FUNCID_MEMORY:
			puts (" Memory");
wdenk's avatar
wdenk committed
119
			break;
120 121
		case CISTPL_FUNCID_SERIAL:
			puts (" Serial Port");
wdenk's avatar
wdenk committed
122
			break;
123 124
		case CISTPL_FUNCID_PARALLEL:
			puts (" Parallel Port");
wdenk's avatar
wdenk committed
125
			break;
126 127
		case CISTPL_FUNCID_FIXED:
			puts (" Fixed Disk");
128
			break;
129 130 131 132 133 134 135 136 137 138 139 140 141 142
		case CISTPL_FUNCID_VIDEO:
			puts (" Video Adapter");
			break;
		case CISTPL_FUNCID_NETWORK:
			puts (" Network Adapter");
			break;
		case CISTPL_FUNCID_AIMS:
			puts (" AIMS Card");
			break;
		case CISTPL_FUNCID_SCSI:
			puts (" SCSI Adapter");
			break;
		default:
			puts (" Unknown");
wdenk's avatar
wdenk committed
143
			break;
144
	}
145
	puts (" Card\n");
146 147
}

148
static void print_fixed (volatile uchar *p)
149
{
150 151
	if (p == NULL)
		return;
152

153
	puts(indent);
154

155 156 157
	switch (*p) {
		case CISTPL_FUNCE_IDE_IFACE:
		{   uchar iface = *(p+2);
158

159 160 161 162 163 164 165 166
		puts ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown");
		puts (" interface ");
		break;
		}
		case CISTPL_FUNCE_IDE_MASTER:
		case CISTPL_FUNCE_IDE_SLAVE:
		{   uchar f1 = *(p+2);
		uchar f2 = *(p+4);
167

168
		puts ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]");
169

170 171
		if (f1 & CISTPL_IDE_UNIQUE)
			puts (" [unique]");
172

173
		puts ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]");
174

175 176
		if (f2 & CISTPL_IDE_HAS_SLEEP)
			puts (" [sleep]");
177

178 179
		if (f2 & CISTPL_IDE_HAS_STANDBY)
			puts (" [standby]");
180

181 182
		if (f2 & CISTPL_IDE_HAS_IDLE)
			puts (" [idle]");
183

184 185
		if (f2 & CISTPL_IDE_LOW_POWER)
			puts (" [low power]");
wdenk's avatar
wdenk committed
186

187 188
		if (f2 & CISTPL_IDE_REG_INHIBIT)
			puts (" [reg inhibit]");
wdenk's avatar
wdenk committed
189

190 191
		if (f2 & CISTPL_IDE_HAS_INDEX)
			puts (" [index]");
192

193 194
		if (f2 & CISTPL_IDE_IOIS16)
			puts (" [IOis16]");
195

196 197 198 199
		break;
		}
	}
	putc ('\n');
200
}
201

202
static int identify  (volatile uchar *p)
wdenk's avatar
wdenk committed
203
{
204 205 206 207 208
	uchar id_str[MAX_IDENT_CHARS];
	uchar data;
	uchar *t;
	uchar **card;
	int i, done;
wdenk's avatar
wdenk committed
209

210 211
	if (p == NULL)
		return (0);	/* Don't know */
wdenk's avatar
wdenk committed
212

213 214
	t = id_str;
	done =0;
wdenk's avatar
wdenk committed
215

216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
	for (i=0; i<=4 && !done; ++i, p+=2) {
		while ((data = *p) != '\0') {
			if (data == 0xFF) {
				done = 1;
				break;
			}
			*t++ = data;
			if (t == &id_str[MAX_IDENT_CHARS-1]) {
				done = 1;
				break;
			}
			p += 2;
		}
		if (!done)
			*t++ = ' ';
wdenk's avatar
wdenk committed
231
	}
232 233 234 235 236 237 238 239 240
	*t = '\0';
	while (--t > id_str) {
		if (*t == ' ')
			*t = '\0';
		else
			break;
	}
	puts ((char *)id_str);
	putc ('\n');
wdenk's avatar
wdenk committed
241

242 243 244 245 246 247 248
	for (card=known_cards; *card; ++card) {
		debug ("## Compare against \"%s\"\n", *card);
		if (strcmp((char *)*card, (char *)id_str) == 0) {	/* found! */
			debug ("## CARD FOUND ##\n");
			return (1);
		}
	}
wdenk's avatar
wdenk committed
249

250
	return (0);	/* don't know */
251
}
wdenk's avatar
wdenk committed
252

253
int check_ide_device (int slot)
wdenk's avatar
wdenk committed
254 255 256
{
	volatile uchar *ident = NULL;
	volatile uchar *feature_p[MAX_FEATURES];
257
	volatile uchar *p, *start, *addr;
wdenk's avatar
wdenk committed
258 259 260 261 262 263 264
	int n_features = 0;
	uchar func_id = ~0;
	uchar code, len;
	ushort config_base = 0;
	int found = 0;
	int i;

265 266
	addr = (volatile uchar *)(CONFIG_SYS_PCMCIA_MEM_ADDR +
				  CONFIG_SYS_PCMCIA_MEM_SIZE * (slot * 4));
267
	debug ("PCMCIA MEM: %08lX\n", (ulong)addr);
wdenk's avatar
wdenk committed
268

269
	start = p = (volatile uchar *) addr;
wdenk's avatar
wdenk committed
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331

	while ((p - start) < MAX_TUPEL_SZ) {

		code = *p; p += 2;

		if (code == 0xFF) { /* End of chain */
			break;
		}

		len = *p; p += 2;
#if defined(DEBUG) && (DEBUG > 1)
		{ volatile uchar *q = p;
			printf ("\nTuple code %02x  length %d\n\tData:",
				code, len);

			for (i = 0; i < len; ++i) {
				printf (" %02x", *q);
				q+= 2;
			}
		}
#endif	/* DEBUG */
		switch (code) {
		case CISTPL_VERS_1:
			ident = p + 4;
			break;
		case CISTPL_FUNCID:
			/* Fix for broken SanDisk which may have 0x80 bit set */
			func_id = *p & 0x7F;
			break;
		case CISTPL_FUNCE:
			if (n_features < MAX_FEATURES)
				feature_p[n_features++] = p;
			break;
		case CISTPL_CONFIG:
			config_base = (*(p+6) << 8) + (*(p+4));
			debug ("\n## Config_base = %04x ###\n", config_base);
		default:
			break;
		}
		p += 2 * len;
	}

	found = identify (ident);

	if (func_id != ((uchar)~0)) {
		print_funcid (func_id);

		if (func_id == CISTPL_FUNCID_FIXED)
			found = 1;
		else
			return (1);	/* no disk drive */
	}

	for (i=0; i<n_features; ++i) {
		print_fixed (feature_p[i]);
	}

	if (!found) {
		printf ("unknown card type\n");
		return (1);
	}

332 333
	ide_devices_found |= (1 << slot);

wdenk's avatar
wdenk committed
334
	/* set I/O area in config reg -> only valid for ARGOSY D5!!! */
335
	*((uchar *)(addr + config_base)) = 1;
336 337 338 339 340 341 342
#if 0
	printf("\n## Config_base = %04x ###\n", config_base);
	printf("Configuration Option Register: %02x @ %x\n", readb(addr + config_base), addr + config_base);
	printf("Card Configuration and Status Register: %02x\n", readb(addr + config_base + 2));
	printf("Pin Replacement Register Register: %02x\n", readb(addr + config_base + 4));
	printf("Socket and Copy Register: %02x\n", readb(addr + config_base + 6));
#endif
wdenk's avatar
wdenk committed
343 344 345
	return (0);
}

346
#endif	/* CHECK_IDE_DEVICE */