Skip to content
Snippets Groups Projects
cmd_pcmcia.c 71.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • Wolfgang Denk's avatar
    Wolfgang Denk committed
    	debug ("Enable PCMCIA buffers and stop RESET\n");
    	reg  =  PCMCIA_PGCRX(_slot_);
    	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
    	PCMCIA_PGCRX(_slot_) = reg;
    
    	udelay(250000);	/* some cards need >150 ms to come up :-( */
    
    	debug ("# hardware_enable done\n");
    
    	return (0);
    }
    
    
    #if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
    static int hardware_disable(int slot)
    {
    	volatile immap_t	*immap;
    	volatile pcmconf8xx_t	*pcmp;
    	u_long reg;
    
    	debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
    
    	immap = (immap_t *)CFG_IMMR;
    	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
    
    	/* remove all power */
    	immap->im_ioport.iop_pcdat |= 0x0400;
    	immap->im_ioport.iop_padat |= 0x0200;
    
    	/* Configure PCMCIA General Control Register */
    	debug ("Disable PCMCIA buffers and assert RESET\n");
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
    	PCMCIA_PGCRX(_slot_) = reg;
    
    	udelay(10000);
    
    	return (0);
    }
    #endif	/* CFG_CMD_PCMCIA */
    
    
    static int voltage_set(int slot, int vcc, int vpp)
    {
    	volatile immap_t	*immap;
    	volatile pcmconf8xx_t	*pcmp;
    	u_long reg;
    
    	debug ("voltage_set: "
    		PCMCIA_BOARD_MSG
    		" Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
    		'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
    
    	immap = (immap_t *)CFG_IMMR;
    	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
    	/*
    	 * Disable PCMCIA buffers (isolate the interface)
    	 * and assert RESET signal
    	 */
    	debug ("Disable PCMCIA buffers and assert RESET\n");
    
    	reg  = PCMCIA_PGCRX(_slot_);
    	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	PCMCIA_PGCRX(_slot_) = reg;
    	udelay(500);
    
    	/*
    	 * Configure Ports A & C pins for
    	 * 5 Volts Enable and 3 Volts enable,
    	 * Turn off all power
    	 */
    	debug ("PCMCIA power OFF\n");
    	immap->im_ioport.iop_pcpar &= ~(0x0400);
    	immap->im_ioport.iop_pcso  &= ~(0x0400);/*
    	immap->im_ioport.iop_pcdir |= 0x0400;*/
    
    	immap->im_ioport.iop_papar &= ~(0x0200);/*
    	immap->im_ioport.iop_padir |= 0x0200;*/
    
    	immap->im_ioport.iop_pcdat |= 0x0400;
    	immap->im_ioport.iop_padat |= 0x0200;
    
    	reg = 0;
    	switch(vcc) {
    	case  0: 		break;
    	case 33: reg |= 0x0200;	break;
    	case 50: reg |= 0x0400;	break;
    	default: 		goto done;
    	}
    
    	/* Checking supported voltages */
    
    	debug ("PIPR: 0x%x --> %s\n",
    		pcmp->pcmc_pipr,
    		(pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
    
    	if (reg & 0x0200)
    		immap->im_ioport.iop_pcdat &= !reg;
    	if (reg & 0x0400)
    		immap->im_ioport.iop_padat &= !reg;
    
    	immap->im_ioport.iop_pcdir |= 0x0200;
    	immap->im_ioport.iop_padir |= 0x0400;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	if (reg) {
    		debug ("PCMCIA powered at %sV\n",
    			(reg&0x0400) ? "5.0" : "3.3");
    	} else {
    		debug ("PCMCIA powered down\n");
    	}
    
    done:
    	debug ("Enable PCMCIA buffers and stop RESET\n");
    	reg  =  PCMCIA_PGCRX(_slot_);
    	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
    	PCMCIA_PGCRX(_slot_) = reg;
    	udelay(500);
    
    	debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
    		slot+'A');
    	return (0);
    }
    
    #endif	/* R360MPI */
    
    
    /* -------------------------------------------------------------------- */
    
    /* KUP4K and KUP4X Boards								*/
    
    /* -------------------------------------------------------------------- */
    
    #if defined(CONFIG_KUP4K) || defined(CONFIG_KUP4X)
    
    #define PCMCIA_BOARD_MSG "KUP"
    
    
    #define KUP4K_PCMCIA_B_3V3 (0x00020000)
    
    static int hardware_enable(int slot)
    {
    	volatile immap_t	*immap;
    	volatile cpm8xx_t	*cp;
    	volatile pcmconf8xx_t	*pcmp;
    	volatile sysconf8xx_t	*sysp;
    	uint reg, mask;
    
    	debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
    
    	udelay(10000);
    
    	immap = (immap_t *)CFG_IMMR;
    	sysp  = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
    	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
    	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
    
    	/*
    	 * Configure SIUMCR to enable PCMCIA port B
    	 * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
    	 */
    	sysp->sc_siumcr &= ~SIUMCR_DBGC11;	/* set DBGC to 00 */
    
    	/* clear interrupt state, and disable interrupts */
    
    	pcmp->pcmc_pscr =  PCMCIA_MASK(slot);
    	pcmp->pcmc_per &= ~PCMCIA_MASK(slot);
    
    	 * Disable interrupts, DMA, and PCMCIA buffers
    	 * (isolate the interface) and assert RESET signal
    
    	 */
    	debug ("Disable PCMCIA buffers and assert RESET\n");
    
    	reg  = 0;
    	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
    
    	PCMCIA_PGCRX(slot) = reg;
    	udelay(2500);
    
    	if (slot) { /* Slot A is built-in */
    		cp->cp_pbdir |=  KUP4K_PCMCIA_B_3V3;
    		cp->cp_pbpar &= ~KUP4K_PCMCIA_B_3V3;
    		/* remove all power */
    		cp->cp_pbdat |=  KUP4K_PCMCIA_B_3V3; /* active low */
    	}
    
    	/*
    	 * Make sure there is a card in the slot, then configure the interface.
    	 */
    	udelay(10000);
    	debug ("[%d] %s: PIPR(%p)=0x%x\n",
    		__LINE__,__FUNCTION__,
    		&(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
    
    	if (pcmp->pcmc_pipr & (0x18000000 >> (slot << 4))) {
    
    	printf("%s  Slot %c:", slot ? "" : "\n", 'A' + slot);
    
    	mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
    	reg  = pcmp->pcmc_pipr;
    	debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
    		reg,
    		(reg&PCMCIA_VS1(slot))?"n":"ff",
    		(reg&PCMCIA_VS2(slot))?"n":"ff");
    	if ((reg & mask) == mask) {
    		puts (" 5.0V card found: NOT SUPPORTED !!!\n");
    	} else {
    
    		if(slot)
    			cp->cp_pbdat &= ~KUP4K_PCMCIA_B_3V3;
    
    		puts (" 3.3V card found: ");
    	}
    #if 0
    	/*  VCC switch error flag, PCMCIA slot INPACK_ pin */
    	cp->cp_pbdir &= ~(0x0020 | 0x0010);
    	cp->cp_pbpar &= ~(0x0020 | 0x0010);
    	udelay(500000);
    #endif
    	debug ("Enable PCMCIA buffers and stop RESET\n");
    
    	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
    
    
    	udelay(250000);	/* some cards need >150 ms to come up :-( */
    
    	debug ("# hardware_enable done\n");
    
    	return (0);
    }
    
    
    #if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
    static int hardware_disable(int slot)
    {
    	volatile immap_t	*immap;
    	volatile cpm8xx_t	*cp;
    	volatile pcmconf8xx_t	*pcmp;
    	u_long reg;
    
    	debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
    
    	immap = (immap_t *)CFG_IMMR;
    	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
    	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
    
    	if (slot)
    		cp->cp_pbdat |= KUP4K_PCMCIA_B_3V3;
    
    
    	/* Configure PCMCIA General Control Register */
    	debug ("Disable PCMCIA buffers and assert RESET\n");
    
    	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
    
    
    	udelay(10000);
    
    	return (0);
    }
    #endif	/* CFG_CMD_PCMCIA */
    
    
    static int voltage_set(int slot, int vcc, int vpp)
    {
    	volatile immap_t	*immap;
    	volatile cpm8xx_t	*cp;
    	volatile pcmconf8xx_t	*pcmp;
    	u_long reg;
    
    	debug ("voltage_set: "	\
    		PCMCIA_BOARD_MSG	\
    		" Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
    		'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
    
    
    	if (!slot) /* Slot A is not configurable */
    		return 0;
    
    
    	immap = (immap_t *)CFG_IMMR;
    	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
    	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
    
    	/*
    	 * Disable PCMCIA buffers (isolate the interface)
    	 * and assert RESET signal
    	 */
    	debug ("Disable PCMCIA buffers and assert RESET\n");
    
    	reg  = PCMCIA_PGCRX(slot);
    	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
    
    	udelay(500);
    
    	debug ("PCMCIA power OFF\n");
    	/*
    	 * Configure Port B pins for
    	 * 3 Volts enable
    	 */
    	cp->cp_pbdir |=  KUP4K_PCMCIA_B_3V3;
    	cp->cp_pbpar &= ~KUP4K_PCMCIA_B_3V3;
    	/* remove all power */
    	cp->cp_pbdat |=  KUP4K_PCMCIA_B_3V3; /* active low */
    
    	switch(vcc) {
    	case  0: 		break;
    	case 33:
    		cp->cp_pbdat &= ~KUP4K_PCMCIA_B_3V3;
    		debug ("PCMCIA powered at 3.3V\n");
    		break;
    	case 50:
    		debug ("PCMCIA: 5Volt vcc not supported\n");
    		break;
    	default:
    		puts("PCMCIA: vcc not supported");
    		break;
    	}
    
    	/* Checking supported voltages */
    
    	debug ("PIPR: 0x%x --> %s\n",
    		pcmp->pcmc_pipr,
    
    		   (pcmp->pcmc_pipr & (0x80000000 >> (slot << 4)))
    
    			? "only 5 V --> NOT SUPPORTED"
    			: "can do 3.3V");
    
    
    	debug ("Enable PCMCIA buffers and stop RESET\n");
    
    	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
    
    	udelay(500);
    
    	debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
    		slot+'A');
    	return (0);
    }
    
    
    #endif	/* KUP4K || KUP4X */
    
    /* -------------------------------------------------------------------- */
    /* End of Board Specific Stuff						*/
    /* -------------------------------------------------------------------- */
    
    /* -------------------------------------------------------------------- */
    /* MPC8xx Specific Stuff - should go to MPC8xx directory		*/
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    /*
     * Search this table to see if the windowsize is
     * supported...
     */
    
    #define M8XX_SIZES_NO 32
    
    static const u_int m8xx_size_to_gray[M8XX_SIZES_NO] =
    { 0x00000001, 0x00000002, 0x00000008, 0x00000004,
      0x00000080, 0x00000040, 0x00000010, 0x00000020,
      0x00008000, 0x00004000, 0x00001000, 0x00002000,
      0x00000100, 0x00000200, 0x00000800, 0x00000400,
    
      0x0fffffff, 0xffffffff, 0xffffffff, 0xffffffff,
      0x01000000, 0x02000000, 0xffffffff, 0x04000000,
      0x00010000, 0x00020000, 0x00080000, 0x00040000,
      0x00800000, 0x00400000, 0x00100000, 0x00200000 };
    
    
    
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    
    #ifndef	CONFIG_I82365
    
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    static u_int m8xx_get_graycode(u_int size)
    {
    	u_int k;
    
    	for (k = 0; k < M8XX_SIZES_NO; k++) {
    		if(m8xx_size_to_gray[k] == size)
    			break;
    	}
    
    	if((k == M8XX_SIZES_NO) || (m8xx_size_to_gray[k] == -1))
    		k = -1;
    
    	return k;
    }
    
    
    #endif	/* CONFIG_I82365 */
    
    
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    #if 0
    static u_int m8xx_get_speed(u_int ns, u_int is_io)
    {
    	u_int reg, clocks, psst, psl, psht;
    
    	if(!ns) {
    
    		/*
    		 * We get called with IO maps setup to 0ns
    		 * if not specified by the user.
    		 * They should be 255ns.
    		 */
    
    		if(is_io)
    			ns = 255;
    		else
    			ns = 100;  /* fast memory if 0 */
    	}
    
    	/*
    	 * In PSST, PSL, PSHT fields we tell the controller
    	 * timing parameters in CLKOUT clock cycles.
    	 * CLKOUT is the same as GCLK2_50.
    	 */
    
    /* how we want to adjust the timing - in percent */
    
    #define ADJ 180 /* 80 % longer accesstime - to be sure */
    
    	clocks = ((M8XX_BUSFREQ / 1000) * ns) / 1000;
    	clocks = (clocks * ADJ) / (100*1000);
    
    	if(clocks >= PCMCIA_BMT_LIMIT) {
    		DEBUG(0, "Max access time limit reached\n");
    		clocks = PCMCIA_BMT_LIMIT-1;
    	}
    
    	psst = clocks / 7;          /* setup time */
    	psht = clocks / 7;          /* hold time */
    	psl  = (clocks * 5) / 7;    /* strobe length */
    
    	psst += clocks - (psst + psht + psl);
    
    	reg =  psst << 12;
    	reg |= psl  << 7;
    	reg |= psht << 16;
    
    	return reg;
    }
    #endif
    
    
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    #ifdef CONFIG_IDE_8xx_PCCARD
    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");
    }
    #endif	/* CONFIG_IDE_8xx_PCCARD */
    
    
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    #ifdef CONFIG_IDE_8xx_PCCARD
    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');
    }
    #endif	/* CONFIG_IDE_8xx_PCCARD */
    
    
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    #ifdef CONFIG_IDE_8xx_PCCARD
    
    #define MAX_IDENT_CHARS		64
    #define	MAX_IDENT_FIELDS	4
    
    static uchar *known_cards[] = {
    	"ARGOSY PnPIDE D5",
    	NULL
    };
    
    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 (id_str);
    	putc ('\n');
    
    	for (card=known_cards; *card; ++card) {
    		debug ("## Compare against \"%s\"\n", *card);
    		if (strcmp(*card, id_str) == 0) {	/* found! */
    			debug ("## CARD FOUND ##\n");
    			return (1);
    		}
    	}
    
    	return (0);	/* don't know */
    }
    #endif	/* CONFIG_IDE_8xx_PCCARD */
    
    
    2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972
    /* -------------------------------------------------------------------- */
    /* NETTA board by Intracom S.A.						*/
    /* -------------------------------------------------------------------- */
    
    #if defined(CONFIG_NETTA)
    
    /* some sane bit macros */
    #define _BD(_b)				(1U << (31-(_b)))
    #define _BDR(_l, _h)			(((((1U << (31-(_l))) - 1) << 1) | 1) & ~((1U << (31-(_h))) - 1))
    
    #define _BW(_b)				(1U << (15-(_b)))
    #define _BWR(_l, _h)			(((((1U << (15-(_l))) - 1) << 1) | 1) & ~((1U << (15-(_h))) - 1))
    
    #define _BB(_b)				(1U << (7-(_b)))
    #define _BBR(_l, _h)			(((((1U << (7-(_l))) - 1) << 1) | 1) & ~((1U << (7-(_h))) - 1))
    
    #define _B(_b)				_BD(_b)
    #define _BR(_l, _h)			_BDR(_l, _h)
    
    #define PCMCIA_BOARD_MSG "NETTA"
    
    static const unsigned short vppd_masks[2] = { _BW(14), _BW(15) };
    
    static void cfg_vppd(int no)
    {
    	volatile immap_t *immap = (immap_t *)CFG_IMMR;
    	unsigned short mask;
    
    	if ((unsigned int)no >= sizeof(vppd_masks)/sizeof(vppd_masks[0]))
    		return;
    
    	mask = vppd_masks[no];
    
    	immap->im_ioport.iop_papar &= ~mask;
    	immap->im_ioport.iop_paodr &= ~mask;
    	immap->im_ioport.iop_padir |=  mask;
    }
    
    static void set_vppd(int no, int what)
    {
    	volatile immap_t *immap = (immap_t *)CFG_IMMR;
    	unsigned short mask;
    
    	if ((unsigned int)no >= sizeof(vppd_masks)/sizeof(vppd_masks[0]))
    		return;
    
    	mask = vppd_masks[no];
    
    	if (what)
    		immap->im_ioport.iop_padat |= mask;
    	else
    		immap->im_ioport.iop_padat &= ~mask;
    }
    
    static const unsigned short vccd_masks[2] = { _BW(10), _BW(6) };
    
    static void cfg_vccd(int no)
    {
    	volatile immap_t *immap = (immap_t *)CFG_IMMR;
    	unsigned short mask;
    
    	if ((unsigned int)no >= sizeof(vccd_masks)/sizeof(vccd_masks[0]))
    		return;
    
    	mask = vccd_masks[no];
    
    	immap->im_ioport.iop_papar &= ~mask;
    	immap->im_ioport.iop_paodr &= ~mask;
    	immap->im_ioport.iop_padir |=  mask;
    }
    
    static void set_vccd(int no, int what)
    {
    	volatile immap_t *immap = (immap_t *)CFG_IMMR;
    	unsigned short mask;
    
    	if ((unsigned int)no >= sizeof(vccd_masks)/sizeof(vccd_masks[0]))
    		return;
    
    	mask = vccd_masks[no];
    
    	if (what)
    		immap->im_ioport.iop_padat |= mask;
    	else
    		immap->im_ioport.iop_padat &= ~mask;
    }
    
    static const unsigned short oc_mask = _BW(8);
    
    static void cfg_oc(void)
    {
    	volatile immap_t *immap = (immap_t *)CFG_IMMR;
    	unsigned short mask = oc_mask;
    
    	immap->im_ioport.iop_pcdir &= ~mask;
    	immap->im_ioport.iop_pcso  &= ~mask;
    	immap->im_ioport.iop_pcint &= ~mask;
    	immap->im_ioport.iop_pcpar &= ~mask;
    }
    
    static int get_oc(void)
    {
    	volatile immap_t *immap = (immap_t *)CFG_IMMR;
    	unsigned short mask = oc_mask;
    	int what;
    
    	what = !!(immap->im_ioport.iop_pcdat & mask);;
    	return what;
    }
    
    static const unsigned short shdn_mask = _BW(12);
    
    static void cfg_shdn(void)
    {
    	volatile immap_t *immap = (immap_t *)CFG_IMMR;
    	unsigned short mask;
    
    	mask = shdn_mask;
    
    	immap->im_ioport.iop_papar &= ~mask;
    	immap->im_ioport.iop_paodr &= ~mask;
    	immap->im_ioport.iop_padir |=  mask;
    }
    
    static void set_shdn(int what)
    {
    	volatile immap_t *immap = (immap_t *)CFG_IMMR;
    	unsigned short mask;
    
    	mask = shdn_mask;
    
    	if (what)
    		immap->im_ioport.iop_padat |= mask;
    	else
    		immap->im_ioport.iop_padat &= ~mask;
    }
    
    static void cfg_ports (void);
    
    static int hardware_enable(int slot)
    {
    	volatile immap_t	*immap;
    	volatile cpm8xx_t	*cp;
    	volatile pcmconf8xx_t	*pcmp;
    	volatile sysconf8xx_t	*sysp;
    	uint reg, pipr, mask;
    	int i;
    
    	debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
    
    	udelay(10000);
    
    	immap = (immap_t *)CFG_IMMR;
    	sysp  = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
    	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
    	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
    
    	/* Configure Ports for TPS2211A PC-Card Power-Interface Switch */
    	cfg_ports ();
    
    	/* clear interrupt state, and disable interrupts */
    	pcmp->pcmc_pscr =  PCMCIA_MASK(_slot_);
    	pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
    
    	/*
    	 * Disable interrupts, DMA, and PCMCIA buffers
    	 * (isolate the interface) and assert RESET signal
    	 */
    	debug ("Disable PCMCIA buffers and assert RESET\n");
    	reg  = 0;
    	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
    	PCMCIA_PGCRX(_slot_) = reg;
    
    	udelay(500);
    
    	/*
    	 * Make sure there is a card in the slot, then configure the interface.
    	 */
    	udelay(10000);
    	debug ("[%d] %s: PIPR(%p)=0x%x\n",
    		__LINE__,__FUNCTION__,
    		&(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
    	if (pcmp->pcmc_pipr & (0x18000000 >> (slot << 4))) {
    		printf ("   No Card found\n");
    		return (1);
    	}
    
    	/*
    	 * Power On: Set VAVCC to 3.3V or 5V, set VAVPP to Hi-Z
    	 */
    	mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
    	pipr = pcmp->pcmc_pipr;
    	debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
    		pipr,
    		(reg&PCMCIA_VS1(slot))?"n":"ff",
    		(reg&PCMCIA_VS2(slot))?"n":"ff");
    
    	if ((pipr & mask) == mask) {
    		set_vppd(0, 1); set_vppd(1, 1); 		/* VAVPP => Hi-Z */
    		set_vccd(0, 0); set_vccd(1, 1); 		/* 5V on, 3V off */
    		puts (" 5.0V card found: ");
    	} else {
    		set_vppd(0, 1); set_vppd(1, 1); 		/* VAVPP => Hi-Z */
    		set_vccd(0, 1); set_vccd(1, 0); 		/* 5V off, 3V on */
    		puts (" 3.3V card found: ");
    	}
    
    	/*  Wait 500 ms; use this to check for over-current */
    	for (i=0; i<5000; ++i) {
    		if (!get_oc()) {
    			printf ("   *** Overcurrent - Safety shutdown ***\n");
    			set_vccd(0, 0); set_vccd(1, 0); 		/* VAVPP => Hi-Z */
    			return (1);
    		}
    		udelay (100);
    	}
    
    	debug ("Enable PCMCIA buffers and stop RESET\n");
    	reg  =  PCMCIA_PGCRX(_slot_);
    	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
    	PCMCIA_PGCRX(_slot_) = reg;
    
    	udelay(250000);	/* some cards need >150 ms to come up :-( */
    
    	debug ("# hardware_enable done\n");
    
    	return (0);
    }
    
    
    #if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
    static int hardware_disable(int slot)
    {
    	volatile immap_t	*immap;
    	volatile pcmconf8xx_t	*pcmp;
    	u_long reg;
    
    	debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
    
    	immap = (immap_t *)CFG_IMMR;
    	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
    
    	/* Configure PCMCIA General Control Register */
    	debug ("Disable PCMCIA buffers and assert RESET\n");
    	reg  = 0;
    	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
    	PCMCIA_PGCRX(_slot_) = reg;
    
    	/* All voltages off / Hi-Z */
    			set_vppd(0, 1); set_vppd(1, 1);
    	set_vccd(0, 1); set_vccd(1, 1);
    
    	udelay(10000);
    
    	return (0);
    }
    #endif	/* CFG_CMD_PCMCIA */
    
    
    static int voltage_set(int slot, int vcc, int vpp)
    {
    	volatile immap_t	*immap;
    	volatile cpm8xx_t	*cp;
    	volatile pcmconf8xx_t	*pcmp;
    	u_long reg;
    	ushort sreg;
    
    	debug ("voltage_set: "
    		PCMCIA_BOARD_MSG
    		" Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
    		'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
    
    	immap = (immap_t *)CFG_IMMR;
    	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
    	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
    	/*
    	 * Disable PCMCIA buffers (isolate the interface)
    	 * and assert RESET signal
    	 */
    	debug ("Disable PCMCIA buffers and assert RESET\n");
    	reg  = PCMCIA_PGCRX(_slot_);
    	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
    	PCMCIA_PGCRX(_slot_) = reg;
    	udelay(500);
    
    	/*
    	 * Configure Port C pins for
    	 * 5 Volts Enable and 3 Volts enable,
    	 * Turn all power pins to Hi-Z
    	 */
    	debug ("PCMCIA power OFF\n");
    	cfg_ports ();	/* Enables switch, but all in Hi-Z */
    
    	sreg  = immap->im_ioport.iop_pcdat;
    	set_vppd(0, 1); set_vppd(1, 1);
    
    	switch(vcc) {
    	case  0:
    		break;	/* Switch off		*/
    
    	case 33:
    		set_vccd(0, 1); set_vccd(1, 0);
    		break;
    
    	case 50:
    		set_vccd(0, 0); set_vccd(1, 1);
    		break;
    
    	default:
    		goto done;
    	}
    
    	/* Checking supported voltages */
    
    	debug ("PIPR: 0x%x --> %s\n",
    		pcmp->pcmc_pipr,
    		(pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
    
    done:
    	debug ("Enable PCMCIA buffers and stop RESET\n");
    	reg  =  PCMCIA_PGCRX(_slot_);
    	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
    	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
    	PCMCIA_PGCRX(_slot_) = reg;
    	udelay(500);
    
    	debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
    		slot+'A');
    	return (0);
    }
    
    static void cfg_ports (void)
    {
    	volatile immap_t	*immap;
    	volatile cpm8xx_t	*cp;
    
    	immap = (immap_t *)CFG_IMMR;
    	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
    
    
    	cfg_vppd(0); cfg_vppd(1);	/* VPPD0,VPPD1 VAVPP => Hi-Z */
    	cfg_vccd(0); cfg_vccd(1);	/* 3V and 5V off */
    	cfg_shdn();
    	cfg_oc();
    
    	/*
    	 * Configure Port A for TPS2211 PC-Card Power-Interface Switch
    	 *
    	 * Switch off all voltages, assert shutdown
    	 */
    	set_vppd(0, 1); set_vppd(1, 1);
    	set_vccd(0, 0); set_vccd(1, 0);
    	set_shdn(1);
    
    	udelay(100000);
    }
    
    #endif	/* NETTA */
    
    
    
    /* -------------------------------------------------------------------- */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    #endif /* CFG_CMD_PCMCIA || (CFG_CMD_IDE && CONFIG_IDE_8xx_PCCARD) */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    /**************************************************/
    
    #if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
    
    U_BOOT_CMD(
    	pinit,	2,	1,	do_pinit,
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	"pinit   - PCMCIA sub-system\n",
    	"on  - power on PCMCIA socket\n"
    	"pinit off - power off PCMCIA socket\n"
    );
    #endif