uboot/board/netta/pcmcia.c
<<
>>
Prefs
   1#include <common.h>
   2#include <mpc8xx.h>
   3#include <pcmcia.h>
   4
   5#undef  CONFIG_PCMCIA
   6
   7#if defined(CONFIG_CMD_PCMCIA)
   8#define CONFIG_PCMCIA
   9#endif
  10
  11#if defined(CONFIG_CMD_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
  12#define CONFIG_PCMCIA
  13#endif
  14
  15#ifdef  CONFIG_PCMCIA
  16
  17/* some sane bit macros */
  18#define _BD(_b)                         (1U << (31-(_b)))
  19#define _BDR(_l, _h)                    (((((1U << (31-(_l))) - 1) << 1) | 1) & ~((1U << (31-(_h))) - 1))
  20
  21#define _BW(_b)                         (1U << (15-(_b)))
  22#define _BWR(_l, _h)                    (((((1U << (15-(_l))) - 1) << 1) | 1) & ~((1U << (15-(_h))) - 1))
  23
  24#define _BB(_b)                         (1U << (7-(_b)))
  25#define _BBR(_l, _h)                    (((((1U << (7-(_l))) - 1) << 1) | 1) & ~((1U << (7-(_h))) - 1))
  26
  27#define _B(_b)                          _BD(_b)
  28#define _BR(_l, _h)                     _BDR(_l, _h)
  29
  30#define PCMCIA_BOARD_MSG "NETTA"
  31
  32static const unsigned short vppd_masks[2] = { _BW(14), _BW(15) };
  33
  34static void cfg_vppd(int no)
  35{
  36        volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
  37        unsigned short mask;
  38
  39        if ((unsigned int)no >= sizeof(vppd_masks)/sizeof(vppd_masks[0]))
  40                return;
  41
  42        mask = vppd_masks[no];
  43
  44        immap->im_ioport.iop_papar &= ~mask;
  45        immap->im_ioport.iop_paodr &= ~mask;
  46        immap->im_ioport.iop_padir |=  mask;
  47}
  48
  49static void set_vppd(int no, int what)
  50{
  51        volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
  52        unsigned short mask;
  53
  54        if ((unsigned int)no >= sizeof(vppd_masks)/sizeof(vppd_masks[0]))
  55                return;
  56
  57        mask = vppd_masks[no];
  58
  59        if (what)
  60                immap->im_ioport.iop_padat |= mask;
  61        else
  62                immap->im_ioport.iop_padat &= ~mask;
  63}
  64
  65static const unsigned short vccd_masks[2] = { _BW(10), _BW(6) };
  66
  67static void cfg_vccd(int no)
  68{
  69        volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
  70        unsigned short mask;
  71
  72        if ((unsigned int)no >= sizeof(vccd_masks)/sizeof(vccd_masks[0]))
  73                return;
  74
  75        mask = vccd_masks[no];
  76
  77        immap->im_ioport.iop_papar &= ~mask;
  78        immap->im_ioport.iop_paodr &= ~mask;
  79        immap->im_ioport.iop_padir |=  mask;
  80}
  81
  82static void set_vccd(int no, int what)
  83{
  84        volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
  85        unsigned short mask;
  86
  87        if ((unsigned int)no >= sizeof(vccd_masks)/sizeof(vccd_masks[0]))
  88                return;
  89
  90        mask = vccd_masks[no];
  91
  92        if (what)
  93                immap->im_ioport.iop_padat |= mask;
  94        else
  95                immap->im_ioport.iop_padat &= ~mask;
  96}
  97
  98static const unsigned short oc_mask = _BW(8);
  99
 100static void cfg_oc(void)
 101{
 102        volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
 103        unsigned short mask = oc_mask;
 104
 105        immap->im_ioport.iop_pcdir &= ~mask;
 106        immap->im_ioport.iop_pcso  &= ~mask;
 107        immap->im_ioport.iop_pcint &= ~mask;
 108        immap->im_ioport.iop_pcpar &= ~mask;
 109}
 110
 111static int get_oc(void)
 112{
 113        volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
 114        unsigned short mask = oc_mask;
 115        int what;
 116
 117        what = !!(immap->im_ioport.iop_pcdat & mask);;
 118        return what;
 119}
 120
 121static const unsigned short shdn_mask = _BW(12);
 122
 123static void cfg_shdn(void)
 124{
 125        volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
 126        unsigned short mask;
 127
 128        mask = shdn_mask;
 129
 130        immap->im_ioport.iop_papar &= ~mask;
 131        immap->im_ioport.iop_paodr &= ~mask;
 132        immap->im_ioport.iop_padir |=  mask;
 133}
 134
 135static void set_shdn(int what)
 136{
 137        volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
 138        unsigned short mask;
 139
 140        mask = shdn_mask;
 141
 142        if (what)
 143                immap->im_ioport.iop_padat |= mask;
 144        else
 145                immap->im_ioport.iop_padat &= ~mask;
 146}
 147
 148static void cfg_ports (void)
 149{
 150        cfg_vppd(0); cfg_vppd(1);       /* VPPD0,VPPD1 VAVPP => Hi-Z */
 151        cfg_vccd(0); cfg_vccd(1);       /* 3V and 5V off */
 152        cfg_shdn();
 153        cfg_oc();
 154
 155        /*
 156         * Configure Port A for TPS2211 PC-Card Power-Interface Switch
 157         *
 158         * Switch off all voltages, assert shutdown
 159         */
 160        set_vppd(0, 1); set_vppd(1, 1);
 161        set_vccd(0, 0); set_vccd(1, 0);
 162        set_shdn(1);
 163
 164        udelay(100000);
 165}
 166
 167int pcmcia_hardware_enable(int slot)
 168{
 169        volatile pcmconf8xx_t   *pcmp;
 170        uint reg, pipr, mask;
 171        int i;
 172
 173        debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
 174
 175        udelay(10000);
 176
 177        pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CONFIG_SYS_IMMR)->im_pcmcia));
 178
 179        /* Configure Ports for TPS2211A PC-Card Power-Interface Switch */
 180        cfg_ports ();
 181
 182        /* clear interrupt state, and disable interrupts */
 183        pcmp->pcmc_pscr =  PCMCIA_MASK(_slot_);
 184        pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
 185
 186        /*
 187         * Disable interrupts, DMA, and PCMCIA buffers
 188         * (isolate the interface) and assert RESET signal
 189         */
 190        debug ("Disable PCMCIA buffers and assert RESET\n");
 191        reg  = 0;
 192        reg |= __MY_PCMCIA_GCRX_CXRESET;        /* active high */
 193        reg |= __MY_PCMCIA_GCRX_CXOE;           /* active low  */
 194        PCMCIA_PGCRX(_slot_) = reg;
 195
 196        udelay(500);
 197
 198        /*
 199        * Make sure there is a card in the slot, then configure the interface.
 200        */
 201        udelay(10000);
 202        debug ("[%d] %s: PIPR(%p)=0x%x\n",
 203               __LINE__,__FUNCTION__,
 204               &(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
 205        if (pcmp->pcmc_pipr & (0x18000000 >> (slot << 4))) {
 206                printf ("   No Card found\n");
 207                return (1);
 208        }
 209
 210        /*
 211         * Power On: Set VAVCC to 3.3V or 5V, set VAVPP to Hi-Z
 212         */
 213        mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
 214        pipr = pcmp->pcmc_pipr;
 215        debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
 216               pipr,
 217               (reg&PCMCIA_VS1(slot))?"n":"ff",
 218               (reg&PCMCIA_VS2(slot))?"n":"ff");
 219
 220        if ((pipr & mask) == mask) {
 221                set_vppd(0, 1); set_vppd(1, 1);         /* VAVPP => Hi-Z */
 222                set_vccd(0, 0); set_vccd(1, 1);         /* 5V on, 3V off */
 223                puts (" 5.0V card found: ");
 224        } else {
 225                set_vppd(0, 1); set_vppd(1, 1);         /* VAVPP => Hi-Z */
 226                set_vccd(0, 1); set_vccd(1, 0);         /* 5V off, 3V on */
 227                puts (" 3.3V card found: ");
 228        }
 229
 230        /*  Wait 500 ms; use this to check for over-current */
 231        for (i=0; i<5000; ++i) {
 232                if (!get_oc()) {
 233                        printf ("   *** Overcurrent - Safety shutdown ***\n");
 234                        set_vccd(0, 0); set_vccd(1, 0);         /* VAVPP => Hi-Z */
 235                        return (1);
 236                }
 237                udelay (100);
 238        }
 239
 240        debug ("Enable PCMCIA buffers and stop RESET\n");
 241        reg  =  PCMCIA_PGCRX(_slot_);
 242        reg &= ~__MY_PCMCIA_GCRX_CXRESET;       /* active high */
 243        reg &= ~__MY_PCMCIA_GCRX_CXOE;          /* active low  */
 244        PCMCIA_PGCRX(_slot_) = reg;
 245
 246        udelay(250000); /* some cards need >150 ms to come up :-( */
 247
 248        debug ("# hardware_enable done\n");
 249
 250        return (0);
 251}
 252
 253
 254#if defined(CONFIG_CMD_PCMCIA)
 255int pcmcia_hardware_disable(int slot)
 256{
 257        u_long reg;
 258
 259        debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
 260
 261        /* Configure PCMCIA General Control Register */
 262        debug ("Disable PCMCIA buffers and assert RESET\n");
 263        reg  = 0;
 264        reg |= __MY_PCMCIA_GCRX_CXRESET;        /* active high */
 265        reg |= __MY_PCMCIA_GCRX_CXOE;           /* active low  */
 266        PCMCIA_PGCRX(_slot_) = reg;
 267
 268        /* All voltages off / Hi-Z */
 269        set_vppd(0, 1); set_vppd(1, 1);
 270        set_vccd(0, 1); set_vccd(1, 1);
 271
 272        udelay(10000);
 273
 274        return (0);
 275}
 276#endif
 277
 278
 279int pcmcia_voltage_set(int slot, int vcc, int vpp)
 280{
 281        volatile pcmconf8xx_t   *pcmp;
 282        u_long reg;
 283
 284        debug ("voltage_set: "
 285                        PCMCIA_BOARD_MSG
 286                        " Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
 287        'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
 288
 289        pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CONFIG_SYS_IMMR)->im_pcmcia));
 290        /*
 291         * Disable PCMCIA buffers (isolate the interface)
 292         * and assert RESET signal
 293         */
 294        debug ("Disable PCMCIA buffers and assert RESET\n");
 295        reg  = PCMCIA_PGCRX(_slot_);
 296        reg |= __MY_PCMCIA_GCRX_CXRESET;        /* active high */
 297        reg |= __MY_PCMCIA_GCRX_CXOE;           /* active low  */
 298        PCMCIA_PGCRX(_slot_) = reg;
 299        udelay(500);
 300
 301        /*
 302         * Configure Port C pins for
 303         * 5 Volts Enable and 3 Volts enable,
 304         * Turn all power pins to Hi-Z
 305         */
 306        debug ("PCMCIA power OFF\n");
 307        cfg_ports ();   /* Enables switch, but all in Hi-Z */
 308
 309        set_vppd(0, 1); set_vppd(1, 1);
 310
 311        switch(vcc) {
 312        case  0:
 313                break;  /* Switch off           */
 314
 315        case 33:
 316                set_vccd(0, 1); set_vccd(1, 0);
 317                break;
 318
 319        case 50:
 320                set_vccd(0, 0); set_vccd(1, 1);
 321                break;
 322
 323        default:
 324                goto done;
 325        }
 326
 327        /* Checking supported voltages */
 328
 329        debug ("PIPR: 0x%x --> %s\n",
 330               pcmp->pcmc_pipr,
 331               (pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
 332
 333done:
 334                        debug ("Enable PCMCIA buffers and stop RESET\n");
 335        reg  =  PCMCIA_PGCRX(_slot_);
 336        reg &= ~__MY_PCMCIA_GCRX_CXRESET;       /* active high */
 337        reg &= ~__MY_PCMCIA_GCRX_CXOE;          /* active low  */
 338        PCMCIA_PGCRX(_slot_) = reg;
 339        udelay(500);
 340
 341        debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
 342               slot+'A');
 343        return (0);
 344}
 345
 346#endif  /* CONFIG_PCMCIA */
 347