|  | /* | 
|  | * (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 *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, | 
|  | "pinit   - PCMCIA sub-system\n", | 
|  | "on  - power on PCMCIA socket\n" | 
|  | "pinit off - power off PCMCIA socket\n" | 
|  | ); | 
|  |  | 
|  | #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 */ |