| /* | |
| * (C) Copyright 2000-2006 | |
| * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
| * | |
| * See file CREDITS for list of people who contributed to this | |
| * project. | |
| * | |
| * This program is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU General Public License as | |
| * published by the Free Software Foundation; either version 2 of | |
| * the License, or (at your option) any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU General Public License | |
| * along with this program; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
| * MA 02111-1307 USA | |
| * | |
| ******************************************************************** | |
| * | |
| * 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> | |
| #include <asm/io.h> | |
| /* -------------------------------------------------------------------- */ | |
| #if defined(CONFIG_CMD_PCMCIA) | |
| extern int pcmcia_on (void); | |
| extern int pcmcia_off (void); | |
| int do_pinit (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
| { | |
| int rcode = 0; | |
| if (argc != 2) { | |
| printf ("Usage: pinit {on | off}\n"); | |
| return 1; | |
| } | |
| if (strcmp(argv[1],"on") == 0) { | |
| rcode = pcmcia_on (); | |
| } else if (strcmp(argv[1],"off") == 0) { | |
| rcode = pcmcia_off (); | |
| } else { | |
| printf ("Usage: pinit {on | off}\n"); | |
| return 1; | |
| } | |
| return rcode; | |
| } | |
| U_BOOT_CMD( | |
| pinit, 2, 0, do_pinit, | |
| "PCMCIA sub-system", | |
| "on - power on PCMCIA socket\n" | |
| "pinit off - power off PCMCIA socket" | |
| ); | |
| #endif | |
| /* -------------------------------------------------------------------- */ | |
| #undef CHECK_IDE_DEVICE | |
| #if defined(CONFIG_CMD_IDE) && defined(CONFIG_IDE_8xx_PCCARD) | |
| #define CHECK_IDE_DEVICE | |
| #endif | |
| #if defined(CONFIG_PXA_PCMCIA) | |
| #define CHECK_IDE_DEVICE | |
| #endif | |
| #ifdef CHECK_IDE_DEVICE | |
| int ide_devices_found; | |
| static uchar *known_cards[] = { | |
| (uchar *)"ARGOSY PnPIDE D5", | |
| NULL | |
| }; | |
| #define MAX_TUPEL_SZ 512 | |
| #define MAX_FEATURES 4 | |
| #define MAX_IDENT_CHARS 64 | |
| #define MAX_IDENT_FIELDS 4 | |
| #define indent "\t " | |
| static void print_funcid (int func) | |
| { | |
| puts (indent); | |
| switch (func) { | |
| case CISTPL_FUNCID_MULTI: | |
| puts (" Multi-Function"); | |
| break; | |
| case CISTPL_FUNCID_MEMORY: | |
| puts (" Memory"); | |
| break; | |
| case CISTPL_FUNCID_SERIAL: | |
| puts (" Serial Port"); | |
| break; | |
| case CISTPL_FUNCID_PARALLEL: | |
| puts (" Parallel Port"); | |
| break; | |
| case CISTPL_FUNCID_FIXED: | |
| puts (" Fixed Disk"); | |
| break; | |
| 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"); | |
| break; | |
| } | |
| puts (" Card\n"); | |
| } | |
| static void print_fixed (volatile uchar *p) | |
| { | |
| if (p == NULL) | |
| return; | |
| puts(indent); | |
| switch (*p) { | |
| case CISTPL_FUNCE_IDE_IFACE: | |
| { uchar iface = *(p+2); | |
| 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); | |
| puts ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]"); | |
| if (f1 & CISTPL_IDE_UNIQUE) | |
| puts (" [unique]"); | |
| puts ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]"); | |
| if (f2 & CISTPL_IDE_HAS_SLEEP) | |
| puts (" [sleep]"); | |
| if (f2 & CISTPL_IDE_HAS_STANDBY) | |
| puts (" [standby]"); | |
| if (f2 & CISTPL_IDE_HAS_IDLE) | |
| puts (" [idle]"); | |
| if (f2 & CISTPL_IDE_LOW_POWER) | |
| puts (" [low power]"); | |
| if (f2 & CISTPL_IDE_REG_INHIBIT) | |
| puts (" [reg inhibit]"); | |
| if (f2 & CISTPL_IDE_HAS_INDEX) | |
| puts (" [index]"); | |
| if (f2 & CISTPL_IDE_IOIS16) | |
| puts (" [IOis16]"); | |
| break; | |
| } | |
| } | |
| putc ('\n'); | |
| } | |
| static int identify (volatile uchar *p) | |
| { | |
| uchar id_str[MAX_IDENT_CHARS]; | |
| uchar data; | |
| uchar *t; | |
| uchar **card; | |
| int i, done; | |
| if (p == NULL) | |
| return (0); /* Don't know */ | |
| t = id_str; | |
| done =0; | |
| 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++ = ' '; | |
| } | |
| *t = '\0'; | |
| while (--t > id_str) { | |
| if (*t == ' ') | |
| *t = '\0'; | |
| else | |
| break; | |
| } | |
| puts ((char *)id_str); | |
| putc ('\n'); | |
| 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); | |
| } | |
| } | |
| return (0); /* don't know */ | |
| } | |
| int check_ide_device (int slot) | |
| { | |
| volatile uchar *ident = NULL; | |
| volatile uchar *feature_p[MAX_FEATURES]; | |
| volatile uchar *p, *start, *addr; | |
| int n_features = 0; | |
| uchar func_id = ~0; | |
| uchar code, len; | |
| ushort config_base = 0; | |
| int found = 0; | |
| int i; | |
| addr = (volatile uchar *)(CONFIG_SYS_PCMCIA_MEM_ADDR + | |
| CONFIG_SYS_PCMCIA_MEM_SIZE * (slot * 4)); | |
| debug ("PCMCIA MEM: %08lX\n", (ulong)addr); | |
| start = p = (volatile uchar *) addr; | |
| 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); | |
| } | |
| ide_devices_found |= (1 << slot); | |
| #if CONFIG_CPC45 | |
| #else | |
| /* set I/O area in config reg -> only valid for ARGOSY D5!!! */ | |
| *((uchar *)(addr + config_base)) = 1; | |
| #endif | |
| #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 | |
| return (0); | |
| } | |
| #endif /* CHECK_IDE_DEVICE */ |