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