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