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