root/drivers/block/cmd640.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. put_cmd640_reg_pci1
  2. get_cmd640_reg_pci1
  3. put_cmd640_reg_pci2
  4. get_cmd640_reg_pci2
  5. put_cmd640_reg_vlb
  6. get_cmd640_reg_vlb
  7. probe_for_cmd640_pci1
  8. probe_for_cmd640_pci2
  9. probe_for_cmd640_vlb
  10. ide_probe_for_cmd640x
  11. as_clocks
  12. cmd640_set_timing
  13. known_drive_pio
  14. cmd640_timings_to_regvals
  15. set_pio_mode
  16. cmd640_tune_drive

   1 /*
   2  *  linux/drivers/block/cmd640.c        Version 0.02  Nov 30, 1995
   3  *
   4  *  Copyright (C) 1995  Linus Torvalds & author (see below)
   5  */
   6 
   7 /*
   8  *  Principal Author/Maintainer:  abramov@cecmow.enet.dec.com (Igor)
   9  *
  10  *  This file provides support for the advanced features and bugs
  11  *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
  12  *
  13  *  Version 0.01        Initial version, hacked out of ide.c,
  14  *                      and #include'd rather than compiled separately.
  15  *                      This will get cleaned up in a subsequent release.
  16  *
  17  *  Version 0.02        Fixes for vlb initialization code, enable
  18  *                      read-ahead for versions 'B' and 'C' of chip by
  19  *                      default, some code cleanup.
  20  *
  21  */
  22 
  23 /*
  24  * CMD640 specific registers definition.
  25  */
  26 
  27 #define VID             0x00
  28 #define DID             0x02
  29 #define PCMD            0x04
  30 #define PSTTS           0x06
  31 #define REVID           0x08
  32 #define PROGIF          0x09
  33 #define SUBCL           0x0a
  34 #define BASCL           0x0b
  35 #define BaseA0          0x10
  36 #define BaseA1          0x14
  37 #define BaseA2          0x18
  38 #define BaseA3          0x1c
  39 #define INTLINE         0x3c
  40 #define INPINE          0x3d
  41 
  42 #define CFR             0x50
  43 #define   CFR_DEVREV            0x03
  44 #define   CFR_IDE01INTR         0x04
  45 #define   CFR_DEVID             0x18
  46 #define   CFR_AT_VESA_078h      0x20
  47 #define   CFR_DSA1              0x40
  48 #define   CFR_DSA0              0x80
  49 
  50 #define CNTRL           0x51
  51 #define   CNTRL_DIS_RA0         0x40
  52 #define   CNTRL_DIS_RA1         0x80
  53 #define   CNTRL_ENA_2ND         0x08
  54 
  55 #define CMDTIM          0x52
  56 #define ARTTIM0         0x53
  57 #define DRWTIM0         0x54
  58 #define ARTTIM1         0x55
  59 #define DRWTIM1         0x56
  60 #define ARTTIM23        0x57
  61 #define   DIS_RA2               0x04
  62 #define   DIS_RA3               0x08
  63 #define DRWTIM23        0x58
  64 #define BRST            0x59
  65 
  66 /* Interface to access cmd640x registers */
  67 static void (*put_cmd640_reg)(int key, int reg_no, int val);
  68 static byte (*get_cmd640_reg)(int key, int reg_no);
  69 
  70 enum { none, vlb, pci1, pci2 };
  71 static int      bus_type = none;
  72 static int      cmd640_chip_version;
  73 static int      cmd640_key;
  74 static byte     is_cmd640[MAX_HWIFS];
  75 static int      bus_speed; /* MHz */
  76 
  77 /*
  78  * For some unknown reasons pcibios functions which read and write registers
  79  * do not work with cmd640. We use direct io instead.
  80  */
  81 
  82 /* PCI method 1 access */
  83 
  84 static void put_cmd640_reg_pci1(int key, int reg_no, int val)
     /* [previous][next][first][last][top][bottom][index][help] */
  85 {
  86         unsigned long flags;
  87 
  88         save_flags(flags);
  89         cli();
  90         outl_p((reg_no & 0xfc) | key, 0xcf8);
  91         outb_p(val, (reg_no & 3) + 0xcfc);
  92         restore_flags(flags);
  93 }
  94 
  95 static byte get_cmd640_reg_pci1(int key, int reg_no)
     /* [previous][next][first][last][top][bottom][index][help] */
  96 {
  97         byte b;
  98         unsigned long flags;
  99 
 100         save_flags(flags);
 101         cli();
 102         outl_p((reg_no & 0xfc) | key, 0xcf8);
 103         b = inb_p(0xcfc + (reg_no & 3));
 104         restore_flags(flags);
 105         return b;
 106 }
 107 
 108 /* PCI method 2 access (from CMD datasheet) */
 109 
 110 static void put_cmd640_reg_pci2(int key, int reg_no, int val)
     /* [previous][next][first][last][top][bottom][index][help] */
 111 {
 112         unsigned long flags;
 113 
 114         save_flags(flags);
 115         cli();
 116         outb_p(0x10, 0xcf8);
 117         outb_p(val, key + reg_no);
 118         outb_p(0, 0xcf8);
 119         restore_flags(flags);
 120 }
 121 
 122 static byte get_cmd640_reg_pci2(int key, int reg_no)
     /* [previous][next][first][last][top][bottom][index][help] */
 123 {
 124         byte b;
 125         unsigned long flags;
 126 
 127         save_flags(flags);
 128         cli();
 129         outb_p(0x10, 0xcf8);
 130         b = inb_p(key + reg_no);
 131         outb_p(0, 0xcf8);
 132         restore_flags(flags);
 133         return b;
 134 }
 135 
 136 /* VLB access */
 137 
 138 static void put_cmd640_reg_vlb(int key, int reg_no, int val)
     /* [previous][next][first][last][top][bottom][index][help] */
 139 {
 140         unsigned long flags;
 141 
 142         save_flags(flags);
 143         cli();
 144         outb_p(reg_no, key + 8);
 145         outb_p(val, key + 0xc);
 146         restore_flags(flags);
 147 }
 148 
 149 static byte get_cmd640_reg_vlb(int key, int reg_no)
     /* [previous][next][first][last][top][bottom][index][help] */
 150 {
 151         byte b;
 152         unsigned long flags;
 153 
 154         save_flags(flags);
 155         cli();
 156         outb_p(reg_no, key + 8);
 157         b = inb_p(key + 0xc);
 158         restore_flags(flags);
 159         return b;
 160 }
 161 
 162 /*
 163  * Probe for CMD640x -- pci method 1
 164  */
 165 
 166 static int probe_for_cmd640_pci1(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 167 {
 168         long id;
 169         int     k;
 170 
 171         for (k = 0x80000000; k <= 0x8000f800; k += 0x800) {
 172                 outl(k, 0xcf8);
 173                 id = inl(0xcfc);
 174                 if (id != 0x06401095)
 175                         continue;
 176                 put_cmd640_reg = put_cmd640_reg_pci1;
 177                 get_cmd640_reg = get_cmd640_reg_pci1;
 178                 cmd640_key = k;
 179                 return 1;
 180         }
 181         return 0;
 182 }
 183 
 184 /*
 185  * Probe for CMD640x -- pci method 2
 186  */
 187 
 188 static int probe_for_cmd640_pci2(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 189 {
 190         int i;
 191         int v_id;
 192         int d_id;
 193 
 194         for (i = 0xc000; i <= 0xcf00; i += 0x100) {
 195                 outb(0x10, 0xcf8);
 196                 v_id = inw(i);
 197                 d_id = inw(i + 2);
 198                 outb(0, 0xcf8);
 199                 if (v_id != 0x1095 || d_id != 0x640)
 200                         continue;
 201                 put_cmd640_reg = put_cmd640_reg_pci2;
 202                 get_cmd640_reg = get_cmd640_reg_pci2;
 203                 cmd640_key = i;
 204                 return 1;
 205         }
 206         return 0;
 207 }
 208 
 209 /*
 210  * Probe for CMD640x -- vlb
 211  */
 212 
 213 static int probe_for_cmd640_vlb(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 214         byte b;
 215 
 216         outb(CFR, 0x178);
 217         b = inb(0x17c);
 218         if (b == 0xff || b == 0 || (b & CFR_AT_VESA_078h)) {
 219                 outb(CFR, 0x78);
 220                 b = inb(0x7c);
 221                 if (b == 0xff || b == 0 || !(b & CFR_AT_VESA_078h))
 222                         return 0;
 223                 cmd640_key = 0x70;
 224         } else {
 225                 cmd640_key = 0x170;
 226         }
 227         put_cmd640_reg = put_cmd640_reg_vlb;
 228         get_cmd640_reg = get_cmd640_reg_vlb;
 229         return 1;
 230 }
 231 
 232 /*
 233  * Probe for Cmd640x and initialize it if found
 234  */
 235 
 236 int ide_probe_for_cmd640x(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 237 {
 238         int  i;
 239         int  second_port;
 240         int  cmd_read_ahead;
 241         byte b;
 242 
 243         for (i = 0; i < MAX_HWIFS; i++)
 244                 is_cmd640[i] = 0;
 245 
 246         if (probe_for_cmd640_pci1()) {
 247                 bus_type = pci1;
 248         } else if (probe_for_cmd640_pci2()) {
 249                 bus_type = pci2;
 250         } else if (cmd640_vlb && probe_for_cmd640_vlb()) {
 251                 /* May be remove cmd640_vlb at all, and probe in any case */
 252                 bus_type = vlb;
 253         } else {
 254                 return 0;
 255         }
 256 
 257         /*
 258          * Undocumented magic. (There is no 0x5b port in specs)
 259          */
 260 
 261         put_cmd640_reg(cmd640_key, 0x5b, 0xbd);
 262         if (get_cmd640_reg(cmd640_key, 0x5b) != 0xbd) {
 263                 printk("ide: can't initialize cmd640 -- wrong value in 0x5b\n");
 264                 return 0;
 265         }
 266         put_cmd640_reg(cmd640_key, 0x5b, 0);
 267 
 268         /*
 269          * Documented magic.
 270          */
 271 
 272         cmd640_chip_version = get_cmd640_reg(cmd640_key, CFR) & CFR_DEVREV;
 273         if (cmd640_chip_version == 0) {
 274                 printk ("ide: wrong CMD640 version -- 0\n");
 275                 return 0;
 276         }
 277 
 278         /*
 279          * Do not initialize secondary controller for vlbus
 280          */
 281         second_port = (bus_type != vlb);
 282 
 283         /*
 284          * Set the maximum allowed bus speed (it is safest until we
 285          *                                    find how detect bus speed)
 286          * Normally PCI bus runs at 33MHz, but often works overclocked to 40
 287          */
 288         bus_speed = (bus_type == vlb) ? 50 : 40; 
 289 
 290 #if 1   /* don't know if this is reliable yet */
 291         /*
 292          * Enable readahead for versions above 'A'
 293          */
 294         cmd_read_ahead = (cmd640_chip_version > 1);
 295 #else
 296         cmd_read_ahead = 0;
 297 #endif
 298         /*
 299          * Setup Control Register
 300          */
 301         b = get_cmd640_reg(cmd640_key, CNTRL);  
 302         if (second_port)
 303                 b |= CNTRL_ENA_2ND;
 304         else
 305                 b &= ~CNTRL_ENA_2ND;
 306         if (cmd_read_ahead)
 307                 b &= ~(CNTRL_DIS_RA0 | CNTRL_DIS_RA1);
 308         else
 309                 b |= (CNTRL_DIS_RA0 | CNTRL_DIS_RA1);
 310         put_cmd640_reg(cmd640_key, CNTRL, b);
 311 
 312         /*
 313          * Initialize 2nd IDE port, if required
 314          */
 315         if (second_port) {
 316                 /* We reset timings, and setup read-ahead */
 317                 b = cmd_read_ahead ? 0 : (DIS_RA2 | DIS_RA3);
 318                 put_cmd640_reg(cmd640_key, ARTTIM23, b);
 319                 put_cmd640_reg(cmd640_key, DRWTIM23, 0);
 320         }
 321 
 322         serialized = 1;
 323 
 324         printk("ide: buggy CMD640%c interface at ", 
 325                'A' - 1 + cmd640_chip_version);
 326         switch (bus_type) {
 327                 case vlb :
 328                         printk("local bus, port 0x%x", cmd640_key);
 329                         break;
 330                 case pci1:
 331                         printk("pci, (0x%x)", cmd640_key);
 332                         break;
 333                 case pci2:
 334                         printk("pci,(access method 2) (0x%x)", cmd640_key);
 335                         break;
 336         }
 337 
 338         is_cmd640[0] = is_cmd640[1] = 1;
 339 
 340         /*
 341          * Reset interface timings
 342          */
 343         put_cmd640_reg(cmd640_key, CMDTIM, 0);
 344 
 345         printk("\n ... serialized, %s read-ahead, secondary interface %s\n",
 346                cmd_read_ahead ? "enabled" : "disabled",
 347                second_port ? "enabled" : "disabled");
 348 
 349         return 1;
 350 }
 351 
 352 static int as_clocks(int a) {
     /* [previous][next][first][last][top][bottom][index][help] */
 353         switch (a & 0xc0) {
 354                 case 0 :        return 4;
 355                 case 0x40 :     return 2;
 356                 case 0x80 :     return 3;
 357                 case 0xc0 :     return 5;
 358                 default :       return -1;
 359         }
 360 }
 361 
 362 /*
 363  * Tuning of drive parameters
 364  */
 365 
 366 static void cmd640_set_timing(int if_num, int dr_num, int r1, int r2) {
     /* [previous][next][first][last][top][bottom][index][help] */
 367         int  b_reg;
 368         byte b;
 369         int  r52;
 370         static int a = 0;
 371 
 372         b_reg = if_num ? ARTTIM23 : dr_num ? ARTTIM1 : ARTTIM0;
 373 
 374         if (if_num == 0) {
 375                 put_cmd640_reg(cmd640_key, b_reg, r1);
 376                 put_cmd640_reg(cmd640_key, b_reg + 1, r2);
 377         } else {
 378                 b = get_cmd640_reg(cmd640_key, b_reg);
 379                 if (a == 0 || as_clocks(b) < as_clocks(r1))
 380                         put_cmd640_reg(cmd640_key, b_reg, (b & 0xc0) | r1);
 381                 
 382                 if (a == 0) {
 383                         put_cmd640_reg(cmd640_key, b_reg + 1, r2);
 384                 } else {
 385                         b = get_cmd640_reg(cmd640_key, b_reg + 1);
 386                         r52 =  (b&0x0f) < (r2&0x0f) ? (r2&0x0f) : (b&0x0f);
 387                         r52 |= (b&0xf0) < (r2&0xf0) ? (r2&0xf0) : (b&0xf0);
 388                         put_cmd640_reg(cmd640_key, b_reg+1, r52);
 389                 }
 390                 a = 1;
 391         }
 392 
 393         b = get_cmd640_reg(cmd640_key, CMDTIM);
 394         if (b == 0) {
 395                 put_cmd640_reg(cmd640_key, CMDTIM, r2);
 396         } else {
 397                 r52  = (b&0x0f) < (r2&0x0f) ? (r2&0x0f) : (b&0x0f);
 398                 r52 |= (b&0xf0) < (r2&0xf0) ? (r2&0xf0) : (b&0xf0);
 399                 put_cmd640_reg(cmd640_key, CMDTIM, r52);
 400         }
 401 }
 402 
 403 struct pio_timing {
 404         int     mc_time;        /* Minimal cycle time (ns) */
 405         int     av_time;        /* Address valid to DIOR-/DIOW- setup (ns) */
 406         int     ds_time;        /* DIOR data setup      (ns) */
 407 } pio_timings[6] = {
 408         { 70,   165,    600 },  /* PIO Mode 0 */
 409         { 50,   125,    383 },  /* PIO Mode 1 */
 410         { 30,   100,    240 },  /* PIO Mode 2 */
 411         { 30,   80,     180 },  /* PIO Mode 3 */
 412         { 25,   70,     125 },  /* PIO Mode 4 */
 413         { 20,   50,     100 }   /* PIO Mode ? */
 414 };
 415 
 416 struct drive_pio_info {
 417         const char      *name;
 418         int             pio;
 419 } drive_pios[] = {
 420         { "Maxtor 7131 AT", 1 },
 421         { "Maxtor 7171 AT", 1 },
 422         { "Maxtor 7213 AT", 1 },
 423         { "Maxtor 7245 AT", 1 },
 424         { "SAMSUNG SHD-3122A", 1 },
 425         { "QUANTUM ELS127A", 0 },
 426         { "QUANTUM LPS240A", 0 },
 427         { "QUANTUM LPS270A", 3 },
 428         { "QUANTUM LPS540A", 3 },
 429         { NULL, 0 }
 430 };
 431 
 432 static int known_drive_pio(char* name) {
     /* [previous][next][first][last][top][bottom][index][help] */
 433         struct drive_pio_info* pi;
 434 
 435         for (pi = drive_pios; pi->name != NULL; pi++) {
 436                 if (strcmp(pi->name, name) == 0)
 437                         return pi->pio;
 438         }
 439         return -1;
 440 }
 441 
 442 static void cmd640_timings_to_regvals(int mc_time, int av_time, int ds_time,
     /* [previous][next][first][last][top][bottom][index][help] */
 443                                 int clock_time,
 444                                 int* r1, int* r2)
 445 {
 446         int a, b;
 447 
 448         a = (mc_time + clock_time - 1)/clock_time;
 449         if (a <= 2) *r1 = 0x40;
 450         else if (a == 3) *r1 = 0x80;
 451         else if (a == 4) *r1 = 0;
 452         else *r1 = 0xc0;
 453 
 454         a = (av_time + clock_time - 1)/clock_time;
 455         if (a < 2)
 456                 a = 2;
 457         b = (ds_time + clock_time - 1)/clock_time - a;
 458         if (b < 2)
 459                 b = 2;
 460         if (b > 0x11) {
 461                 a += b - 0x11;
 462                 b = 0x11;
 463         }
 464         if (a > 0xf)
 465                 a = 0;
 466         if (cmd640_chip_version > 1)
 467                 b -= 1;
 468         if (b > 0xf)
 469                 b = 0;
 470         *r2 = (a << 4) | b;
 471 }
 472 
 473 static void set_pio_mode(int if_num, int drv_num, int mode_num) {
     /* [previous][next][first][last][top][bottom][index][help] */
 474         int p_base;
 475         int i;
 476 
 477         p_base = if_num ? 0x170 : 0x1f0;
 478         outb_p(3, p_base + 1);
 479         outb_p(mode_num | 8, p_base + 2);
 480         outb_p((drv_num | 0xa) << 4, p_base + 6);
 481         outb_p(0xef, p_base + 7);
 482         for (i = 0; (i < 100) && (inb (p_base + 7) & 0x80); i++)
 483                 delay_10ms();
 484 }
 485 
 486 void cmd640_tune_drive(ide_drive_t* drive) {
     /* [previous][next][first][last][top][bottom][index][help] */
 487         int interface_number;
 488         int drive_number;
 489         int clock_time; /* ns */
 490         int max_pio;
 491         int mc_time, av_time, ds_time;
 492         struct hd_driveid* id;
 493         int r1, r2;
 494 
 495         /*
 496          * Determine if drive is under cmd640 control
 497          */
 498         interface_number = HWIF(drive) - ide_hwifs;
 499         if (!is_cmd640[interface_number])
 500                 return;
 501 
 502         drive_number = drive - HWIF(drive)->drives;
 503         clock_time = 1000/bus_speed;
 504         id = drive->id;
 505         if ((max_pio = known_drive_pio(id->model)) != -1) {
 506                 mc_time = pio_timings[max_pio].mc_time;
 507                 av_time = pio_timings[max_pio].av_time;
 508                 ds_time = pio_timings[max_pio].ds_time;
 509         } else {
 510                 max_pio = id->tPIO;
 511                 mc_time = pio_timings[max_pio].mc_time;
 512                 av_time = pio_timings[max_pio].av_time;
 513                 ds_time = pio_timings[max_pio].ds_time;
 514                 if (id->field_valid & 2) {
 515                         if ((id->capability & 8) && (id->eide_pio_modes & 7)) {
 516                                 if (id->eide_pio_modes & 4) max_pio = 5;
 517                                 else if (id->eide_pio_modes & 2) max_pio = 4;
 518                                 else max_pio = 3;
 519                                 ds_time = id->eide_pio_iordy;
 520                                 mc_time = pio_timings[max_pio].mc_time;
 521                                 av_time = pio_timings[max_pio].av_time;
 522                         } else {
 523                                 ds_time = id->eide_pio;
 524                         }
 525                         if (ds_time == 0)
 526                                 ds_time = pio_timings[max_pio].ds_time;
 527                 }
 528         }
 529         cmd640_timings_to_regvals(mc_time, av_time, ds_time, clock_time,
 530                                 &r1, &r2);
 531         set_pio_mode(interface_number, drive_number, max_pio);
 532         cmd640_set_timing(interface_number, drive_number, r1, r2);
 533         printk ("Mode and Timing set to PIO%d (0x%x 0x%x)\n", max_pio, r1, r2);
 534 }
 535 

/* [previous][next][first][last][top][bottom][index][help] */