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