uboot/drivers/pcmcia/ti_pci1410a.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2000-2002
   3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   4 * (C) Copyright 2002
   5 * Daniel Engström, Omicron Ceti AB
   6 *
   7 * See file CREDITS for list of people who contributed to this
   8 * project.
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public License as
  12 * published by the Free Software Foundation; either version 2 of
  13 * the License, or (at your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 * GNU General Public License for more details.
  19 *
  20 * You should have received a copy of the GNU General Public License
  21 * along with this program; if not, write to the Free Software
  22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  23 * MA 02111-1307 USA
  24 *
  25 ********************************************************************
  26 *
  27 * Lots of code copied from:
  28 *
  29 * m8xx_pcmcia.c - Linux PCMCIA socket driver for the mpc8xx series.
  30 * (C) 1999-2000 Magnus Damm <damm@bitsmart.com>
  31 *
  32 * "The ExCA standard specifies that socket controllers should provide
  33 * two IO and five memory windows per socket, which can be independently
  34 * configured and positioned in the host address space and mapped to
  35 * arbitrary segments of card address space. " - David A Hinds. 1999
  36 *
  37 * This controller does _not_ meet the ExCA standard.
  38 *
  39 * m8xx pcmcia controller brief info:
  40 * + 8 windows (attrib, mem, i/o)
  41 * + up to two slots (SLOT_A and SLOT_B)
  42 * + inputpins, outputpins, event and mask registers.
  43 * - no offset register. sigh.
  44 *
  45 * Because of the lacking offset register we must map the whole card.
  46 * We assign each memory window PCMCIA_MEM_WIN_SIZE address space.
  47 * Make sure there is (PCMCIA_MEM_WIN_SIZE * PCMCIA_MEM_WIN_NO
  48 * * PCMCIA_SOCKETS_NO) bytes at PCMCIA_MEM_WIN_BASE.
  49 * The i/o windows are dynamically allocated at PCMCIA_IO_WIN_BASE.
  50 * They are maximum 64KByte each...
  51 */
  52
  53
  54#undef DEBUG            /**/
  55
  56/*
  57 * PCMCIA support
  58 */
  59#include <common.h>
  60#include <command.h>
  61#include <config.h>
  62#include <pci.h>
  63#include <asm/io.h>
  64
  65#include <pcmcia.h>
  66
  67#if defined(CONFIG_CMD_PCMCIA)
  68
  69int pcmcia_on(int ide_base_bus);
  70
  71static int  pcmcia_off(void);
  72static int  hardware_disable(int slot);
  73static int  hardware_enable(int slot);
  74static int  voltage_set(int slot, int vcc, int vpp);
  75static void print_funcid(int func);
  76static void print_fixed(volatile uchar *p);
  77static int  identify(volatile uchar *p);
  78static int  check_ide_device(int slot, int ide_base_bus);
  79
  80
  81/* ------------------------------------------------------------------------- */
  82
  83
  84const char *indent = "\t   ";
  85
  86/* ------------------------------------------------------------------------- */
  87
  88
  89int do_pinit(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
  90{
  91#ifndef CONFIG_SYS_FIRST_PCMCIA_BUS
  92# define CONFIG_SYS_FIRST_PCMCIA_BUS 0
  93#endif
  94
  95        int rcode = 0;
  96
  97        if (argc != 2) {
  98                printf ("Usage: pinit {on | off}\n");
  99                return 1;
 100        }
 101        if (strcmp(argv[1],"on") == 0) {
 102                rcode = pcmcia_on(CONFIG_SYS_FIRST_PCMCIA_BUS);
 103        } else if (strcmp(argv[1],"off") == 0) {
 104                rcode = pcmcia_off();
 105        } else {
 106                printf ("Usage: pinit {on | off}\n");
 107                return 1;
 108        }
 109
 110        return rcode;
 111}
 112
 113/* ------------------------------------------------------------------------- */
 114
 115
 116static struct pci_device_id supported[] = {
 117        { PCI_VENDOR_ID_TI, 0xac50 }, /* Ti PCI1410A */
 118        { PCI_VENDOR_ID_TI, 0xac56 }, /* Ti PCI1510 */
 119        { }
 120};
 121
 122static pci_dev_t devbusfn;
 123static u32 socket_base;
 124static u32 pcmcia_cis_ptr;
 125
 126int pcmcia_on(int ide_base_bus)
 127{
 128        u16 dev_id;
 129        u32 socket_status;
 130        int slot = 0;
 131        int cis_len;
 132        u16 io_base;
 133        u16 io_len;
 134
 135        /*
 136         * Find the CardBus PCI device(s).
 137         */
 138        if ((devbusfn = pci_find_devices(supported, 0)) < 0) {
 139                printf("Ti CardBus: not found\n");
 140                return 1;
 141        }
 142
 143        pci_read_config_word(devbusfn, PCI_DEVICE_ID, &dev_id);
 144
 145        if (dev_id == 0xac56) {
 146                debug("Enable PCMCIA Ti PCI1510\n");
 147        } else {
 148                debug("Enable PCMCIA Ti PCI1410A\n");
 149        }
 150
 151        pcmcia_cis_ptr = CONFIG_SYS_PCMCIA_CIS_WIN;
 152        cis_len = CONFIG_SYS_PCMCIA_CIS_WIN_SIZE;
 153
 154        io_base = CONFIG_SYS_PCMCIA_IO_WIN;
 155        io_len = CONFIG_SYS_PCMCIA_IO_WIN_SIZE;
 156
 157        /*
 158         * Setup the PCI device.
 159         */
 160        pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, &socket_base);
 161        socket_base &= ~0xf;
 162
 163        socket_status = readl(socket_base+8);
 164        if ((socket_status & 6) == 0) {
 165                printf("Card Present: ");
 166
 167                switch (socket_status & 0x3c00) {
 168
 169                case 0x400:
 170                        printf("5V ");
 171                        break;
 172                case 0x800:
 173                        printf("3.3V ");
 174                        break;
 175                case 0xc00:
 176                        printf("3.3/5V ");
 177                        break;
 178                default:
 179                        printf("unsupported Vcc ");
 180                        break;
 181                }
 182                switch (socket_status & 0x30) {
 183                case 0x10:
 184                        printf("16bit PC-Card\n");
 185                        break;
 186                case 0x20:
 187                        printf("32bit CardBus Card\n");
 188                        break;
 189                default:
 190                        printf("8bit PC-Card\n");
 191                        break;
 192                }
 193        }
 194
 195
 196        writeb(0x41, socket_base + 0x806); /* Enable I/O window 0 and memory window 0 */
 197        writeb(0x0e, socket_base + 0x807); /* Reset I/O window options */
 198
 199        /* Careful: the linux yenta driver do not seem to reset the offset
 200         * in the i/o windows, so leaving them non-zero is a problem */
 201
 202        writeb(io_base & 0xff, socket_base + 0x808); /* I/O window 0 base address */
 203        writeb(io_base>>8, socket_base + 0x809);
 204        writeb((io_base + io_len - 1) & 0xff, socket_base + 0x80a); /* I/O window 0 end address */
 205        writeb((io_base + io_len - 1)>>8, socket_base + 0x80b);
 206        writeb(0x00, socket_base + 0x836);      /* I/O window 0 offset address 0x000 */
 207        writeb(0x00, socket_base + 0x837);
 208
 209
 210        writeb((pcmcia_cis_ptr&0x000ff000) >> 12,
 211               socket_base + 0x810); /* Memory window 0 start address bits 19-12 */
 212        writeb((pcmcia_cis_ptr&0x00f00000) >> 20,
 213               socket_base + 0x811);  /* Memory window 0 start address bits 23-20 */
 214        writeb(((pcmcia_cis_ptr+cis_len-1) & 0x000ff000) >> 12,
 215                socket_base + 0x812); /* Memory window 0 end address bits 19-12*/
 216        writeb(((pcmcia_cis_ptr+cis_len-1) & 0x00f00000) >> 20,
 217                socket_base + 0x813); /* Memory window 0 end address bits 23-20*/
 218        writeb(0x00, socket_base + 0x814); /* Memory window 0 offset bits 19-12 */
 219        writeb(0x40, socket_base + 0x815); /* Memory window 0 offset bits 23-20 and
 220                                            * options (read/write, attribute access) */
 221        writeb(0x00, socket_base + 0x816); /* ExCA card-detect and general control  */
 222        writeb(0x00, socket_base + 0x81e); /* ExCA global control (interrupt modes) */
 223
 224        writeb((pcmcia_cis_ptr & 0xff000000) >> 24,
 225               socket_base + 0x840); /* Memory window address bits 31-24 */
 226
 227
 228        /* turn off voltage */
 229        if (voltage_set(slot, 0, 0)) {
 230                return 1;
 231        }
 232
 233        /* Enable external hardware */
 234        if (hardware_enable(slot)) {
 235                return 1;
 236        }
 237
 238        if (check_ide_device(slot, ide_base_bus)) {
 239                return 1;
 240        }
 241
 242        return 0;
 243}
 244
 245/* ------------------------------------------------------------------------- */
 246
 247
 248static int pcmcia_off (void)
 249{
 250        int slot = 0;
 251
 252        writeb(0x00, socket_base + 0x806); /* disable all I/O and memory windows */
 253
 254        writeb(0x00, socket_base + 0x808); /* I/O window 0 base address */
 255        writeb(0x00, socket_base + 0x809);
 256        writeb(0x00, socket_base + 0x80a); /* I/O window 0 end address */
 257        writeb(0x00, socket_base + 0x80b);
 258        writeb(0x00, socket_base + 0x836); /* I/O window 0 offset address  */
 259        writeb(0x00, socket_base + 0x837);
 260
 261        writeb(0x00, socket_base + 0x80c); /* I/O window 1 base address  */
 262        writeb(0x00, socket_base + 0x80d);
 263        writeb(0x00, socket_base + 0x80e); /* I/O window 1 end address  */
 264        writeb(0x00, socket_base + 0x80f);
 265        writeb(0x00, socket_base + 0x838); /* I/O window 1 offset address  */
 266        writeb(0x00, socket_base + 0x839);
 267
 268        writeb(0x00, socket_base + 0x810); /* Memory window 0 start address */
 269        writeb(0x00, socket_base + 0x811);
 270        writeb(0x00, socket_base + 0x812); /* Memory window 0 end address  */
 271        writeb(0x00, socket_base + 0x813);
 272        writeb(0x00, socket_base + 0x814); /* Memory window 0 offset */
 273        writeb(0x00, socket_base + 0x815);
 274
 275        writeb(0xc0, socket_base + 0x840); /* Memory window 0 page address */
 276
 277
 278        /* turn off voltage */
 279        voltage_set(slot, 0, 0);
 280
 281        /* disable external hardware */
 282        printf ("Shutdown and Poweroff Ti PCI1410A\n");
 283        hardware_disable(slot);
 284
 285        return 0;
 286}
 287
 288
 289/* ------------------------------------------------------------------------- */
 290
 291
 292#define MAX_TUPEL_SZ    512
 293#define MAX_FEATURES    4
 294int ide_devices_found;
 295static int check_ide_device(int slot, int ide_base_bus)
 296{
 297        volatile uchar *ident = NULL;
 298        volatile uchar *feature_p[MAX_FEATURES];
 299        volatile uchar *p, *start;
 300        int n_features = 0;
 301        uchar func_id = ~0;
 302        uchar code, len;
 303        ushort config_base = 0;
 304        int found = 0;
 305        int i;
 306        u32 socket_status;
 307
 308        debug ("PCMCIA MEM: %08X\n", pcmcia_cis_ptr);
 309
 310        socket_status = readl(socket_base+8);
 311
 312        if ((socket_status & 6) != 0 || (socket_status & 0x20) != 0) {
 313                printf("no card or CardBus card\n");
 314                return 1;
 315        }
 316
 317        start = p = (volatile uchar *) pcmcia_cis_ptr;
 318
 319        while ((p - start) < MAX_TUPEL_SZ) {
 320
 321                code = *p; p += 2;
 322
 323                if (code == 0xFF) { /* End of chain */
 324                        break;
 325                }
 326
 327                len = *p; p += 2;
 328#if defined(DEBUG) && (DEBUG > 1)
 329                {
 330                        volatile uchar *q = p;
 331                        printf ("\nTuple code %02x  length %d\n\tData:",
 332                                code, len);
 333
 334                        for (i = 0; i < len; ++i) {
 335                                printf (" %02x", *q);
 336                                q+= 2;
 337                        }
 338                }
 339#endif  /* DEBUG */
 340                switch (code) {
 341                case CISTPL_VERS_1:
 342                        ident = p + 4;
 343                        break;
 344                case CISTPL_FUNCID:
 345                        /* Fix for broken SanDisk which may have 0x80 bit set */
 346                        func_id = *p & 0x7F;
 347                        break;
 348                case CISTPL_FUNCE:
 349                        if (n_features < MAX_FEATURES)
 350                                feature_p[n_features++] = p;
 351                        break;
 352                case CISTPL_CONFIG:
 353                        config_base = (*(p+6) << 8) + (*(p+4));
 354                        debug ("\n## Config_base = %04x ###\n", config_base);
 355                default:
 356                        break;
 357                }
 358                p += 2 * len;
 359        }
 360
 361        found = identify(ident);
 362
 363        if (func_id != ((uchar)~0)) {
 364                print_funcid (func_id);
 365
 366                if (func_id == CISTPL_FUNCID_FIXED)
 367                        found = 1;
 368                else
 369                        return 1;       /* no disk drive */
 370        }
 371
 372        for (i=0; i<n_features; ++i) {
 373                print_fixed(feature_p[i]);
 374        }
 375
 376        if (!found) {
 377                printf("unknown card type\n");
 378                return 1;
 379        }
 380
 381        /* select config index 1 */
 382        writeb(1, pcmcia_cis_ptr + config_base);
 383
 384#if 0
 385        printf("Confiuration Option Register: %02x\n", readb(pcmcia_cis_ptr + config_base));
 386        printf("Card Confiuration and Status Register: %02x\n", readb(pcmcia_cis_ptr + config_base + 2));
 387        printf("Pin Replacement Register Register: %02x\n", readb(pcmcia_cis_ptr + config_base + 4));
 388        printf("Socket and Copy Register: %02x\n", readb(pcmcia_cis_ptr + config_base + 6));
 389#endif
 390        ide_devices_found |= (1 << (slot+ide_base_bus));
 391
 392        return 0;
 393}
 394
 395
 396static int voltage_set(int slot, int vcc, int vpp)
 397{
 398        u32 socket_control;
 399        int reg=0;
 400
 401        switch (slot) {
 402        case 0:
 403                reg = socket_base + 0x10;
 404                break;
 405        default:
 406                return 1;
 407        }
 408
 409        socket_control = 0;
 410
 411
 412        switch (vcc) {
 413        case 50:
 414                socket_control |= 0x20;
 415                break;
 416        case 33:
 417                socket_control |= 0x30;
 418                break;
 419        case 0:
 420        default:
 421        }
 422
 423        switch (vpp) {
 424        case 120:
 425                socket_control |= 0x1;
 426                break;
 427        case 50:
 428                socket_control |= 0x2;
 429                break;
 430        case 33:
 431                socket_control |= 0x3;
 432                break;
 433        case 0:
 434        default:
 435        }
 436
 437        writel(socket_control, reg);
 438
 439        debug ("voltage_set: Ti PCI1410A Slot %d, Vcc=%d.%d, Vpp=%d.%d\n",
 440                slot, vcc/10, vcc%10, vpp/10, vpp%10);
 441
 442        udelay(500);
 443        return 0;
 444}
 445
 446
 447static int hardware_enable(int slot)
 448{
 449        u32 socket_status;
 450        u16 brg_ctrl;
 451        int is_82365sl;
 452
 453        socket_status = readl(socket_base+8);
 454
 455        if ((socket_status & 6) == 0) {
 456
 457                switch (socket_status & 0x3c00) {
 458
 459                case 0x400:
 460                        printf("5V ");
 461                        voltage_set(slot, 50, 0);
 462                        break;
 463                case 0x800:
 464                        voltage_set(slot, 33, 0);
 465                        break;
 466                case 0xc00:
 467                        voltage_set(slot, 33, 0);
 468                        break;
 469                default:
 470                        voltage_set(slot, 0, 0);
 471                        break;
 472                }
 473        } else {
 474                voltage_set(slot, 0, 0);
 475        }
 476
 477        pci_read_config_word(devbusfn, PCI_BRIDGE_CONTROL, &brg_ctrl);
 478        brg_ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
 479        pci_write_config_word(devbusfn, PCI_BRIDGE_CONTROL, brg_ctrl);
 480        is_82365sl = ((readb(socket_base+0x800) & 0x0f) == 2);
 481        writeb(is_82365sl?0x90:0x98, socket_base+0x802);
 482        writeb(0x67, socket_base+0x803);
 483        udelay(100000);
 484#if 0
 485        printf("ExCA Id %02x, Card Status %02x, Power config %02x, Interrupt Config %02x, bridge control %04x %d\n",
 486               readb(socket_base+0x800), readb(socket_base+0x801),
 487               readb(socket_base+0x802), readb(socket_base+0x803), brg_ctrl, is_82365sl);
 488#endif
 489
 490        return ((readb(socket_base+0x801)&0x6c)==0x6c)?0:1;
 491}
 492
 493
 494static int hardware_disable(int slot)
 495{
 496        voltage_set(slot, 0, 0);
 497        return 0;
 498}
 499
 500static void print_funcid(int func)
 501{
 502        puts(indent);
 503        switch (func) {
 504        case CISTPL_FUNCID_MULTI:
 505                puts(" Multi-Function");
 506                break;
 507        case CISTPL_FUNCID_MEMORY:
 508                puts(" Memory");
 509                break;
 510        case CISTPL_FUNCID_SERIAL:
 511                puts(" Serial Port");
 512                break;
 513        case CISTPL_FUNCID_PARALLEL:
 514                puts(" Parallel Port");
 515                break;
 516        case CISTPL_FUNCID_FIXED:
 517                puts(" Fixed Disk");
 518                break;
 519        case CISTPL_FUNCID_VIDEO:
 520                puts(" Video Adapter");
 521                break;
 522        case CISTPL_FUNCID_NETWORK:
 523                puts(" Network Adapter");
 524                break;
 525        case CISTPL_FUNCID_AIMS:
 526                puts(" AIMS Card");
 527                break;
 528        case CISTPL_FUNCID_SCSI:
 529                puts(" SCSI Adapter");
 530                break;
 531        default:
 532                puts(" Unknown");
 533                break;
 534        }
 535        puts(" Card\n");
 536}
 537
 538/* ------------------------------------------------------------------------- */
 539
 540static void print_fixed(volatile uchar *p)
 541{
 542        if (p == NULL)
 543                return;
 544
 545        puts(indent);
 546
 547        switch (*p) {
 548        case CISTPL_FUNCE_IDE_IFACE:
 549                {   uchar iface = *(p+2);
 550
 551                        puts ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown");
 552                        puts (" interface ");
 553                        break;
 554                }
 555        case CISTPL_FUNCE_IDE_MASTER:
 556        case CISTPL_FUNCE_IDE_SLAVE:
 557                {
 558                        uchar f1 = *(p+2);
 559                        uchar f2 = *(p+4);
 560
 561                        puts((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]");
 562
 563                        if (f1 & CISTPL_IDE_UNIQUE) {
 564                                puts(" [unique]");
 565                        }
 566
 567                        puts((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]");
 568
 569                        if (f2 & CISTPL_IDE_HAS_SLEEP) {
 570                                puts(" [sleep]");
 571                        }
 572
 573                        if (f2 & CISTPL_IDE_HAS_STANDBY) {
 574                                puts(" [standby]");
 575                        }
 576
 577                        if (f2 & CISTPL_IDE_HAS_IDLE) {
 578                                puts(" [idle]");
 579                        }
 580
 581                        if (f2 & CISTPL_IDE_LOW_POWER) {
 582                                puts(" [low power]");
 583                        }
 584
 585                        if (f2 & CISTPL_IDE_REG_INHIBIT) {
 586                                puts(" [reg inhibit]");
 587                        }
 588
 589                        if (f2 & CISTPL_IDE_HAS_INDEX) {
 590                                puts(" [index]");
 591                        }
 592
 593                        if (f2 & CISTPL_IDE_IOIS16) {
 594                                puts(" [IOis16]");
 595                        }
 596
 597                        break;
 598                }
 599        }
 600        putc('\n');
 601}
 602
 603/* ------------------------------------------------------------------------- */
 604
 605#define MAX_IDENT_CHARS         64
 606#define MAX_IDENT_FIELDS        4
 607
 608static uchar *known_cards[] = {
 609        "ARGOSY PnPIDE D5",
 610        NULL
 611};
 612
 613static int identify(volatile uchar *p)
 614{
 615        uchar id_str[MAX_IDENT_CHARS];
 616        uchar data;
 617        uchar *t;
 618        uchar **card;
 619        int i, done;
 620
 621        if (p == NULL)
 622                return (0);     /* Don't know */
 623
 624        t = id_str;
 625        done =0;
 626
 627        for (i=0; i<=4 && !done; ++i, p+=2) {
 628                while ((data = *p) != '\0') {
 629                        if (data == 0xFF) {
 630                                done = 1;
 631                                break;
 632                        }
 633                        *t++ = data;
 634                        if (t == &id_str[MAX_IDENT_CHARS-1]) {
 635                                done = 1;
 636                                break;
 637                        }
 638                        p += 2;
 639                }
 640                if (!done)
 641                        *t++ = ' ';
 642        }
 643        *t = '\0';
 644        while (--t > id_str) {
 645                if (*t == ' ') {
 646                        *t = '\0';
 647                } else {
 648                        break;
 649                }
 650        }
 651        puts(id_str);
 652        putc('\n');
 653
 654        for (card=known_cards; *card; ++card) {
 655                debug ("## Compare against \"%s\"\n", *card);
 656                if (strcmp(*card, id_str) == 0) {       /* found! */
 657                        debug ("## CARD FOUND ##\n");
 658                        return 1;
 659                }
 660        }
 661
 662        return 0;       /* don't know */
 663}
 664
 665#endif /* CONFIG_CMD_PCMCIA */
 666