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