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.01  Nov 16, 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 
  18 /* Interface to access cmd640x registers */
  19 static void (*put_cmd640_reg)(int key, int reg_no, int val);
  20 static byte (*get_cmd640_reg)(int key, int reg_no);
  21 
  22 enum { none, vlb, pci1, pci2 };
  23 static int      bus_type = none;
  24 static int      cmd640_chip_version;
  25 static int      cmd640_key;
  26 static byte     is_cmd640[MAX_HWIFS];
  27 
  28 /*
  29  * For some unknown reasons pcibios functions which read and write registers
  30  * do not work with cmd640. We use direct io instead.
  31  */
  32 
  33 /* PCI method 1 access */
  34 
  35 static void put_cmd640_reg_pci1(int key, int reg_no, int val)
     /* [previous][next][first][last][top][bottom][index][help] */
  36 {
  37         unsigned long flags;
  38 
  39         save_flags(flags);
  40         cli();
  41         outl_p((reg_no & 0xfc) | key, 0xcf8);
  42         outb_p(val, (reg_no & 3) + 0xcfc);
  43         restore_flags(flags);
  44 }
  45 
  46 static byte get_cmd640_reg_pci1(int key, int reg_no)
     /* [previous][next][first][last][top][bottom][index][help] */
  47 {
  48         byte b;
  49         unsigned long flags;
  50 
  51         save_flags(flags);
  52         cli();
  53         outl_p((reg_no & 0xfc) | key, 0xcf8);
  54         b = inb(0xcfc + (reg_no & 3));
  55         restore_flags(flags);
  56         return b;
  57 }
  58 
  59 /* PCI method 2 access (from CMD datasheet) */
  60 
  61 static void put_cmd640_reg_pci2(int key, int reg_no, int val)
     /* [previous][next][first][last][top][bottom][index][help] */
  62 {
  63         unsigned long flags;
  64 
  65         save_flags(flags);
  66         cli();
  67         outb_p(0x10, 0xcf8);
  68         outb_p(val, key + reg_no);
  69         outb_p(0, 0xcf8);
  70         restore_flags(flags);
  71 }
  72 
  73 static byte get_cmd640_reg_pci2(int key, int reg_no)
     /* [previous][next][first][last][top][bottom][index][help] */
  74 {
  75         byte b;
  76         unsigned long flags;
  77 
  78         save_flags(flags);
  79         cli();
  80         outb_p(0x10, 0xcf8);
  81         b = inb(key + reg_no);
  82         outb_p(0, 0xcf8);
  83         restore_flags(flags);
  84         return b;
  85 }
  86 
  87 /* VLB access */
  88 
  89 static void put_cmd640_reg_vlb(int key, int reg_no, int val)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91         unsigned long flags;
  92 
  93         save_flags(flags);
  94         cli();
  95         outb(reg_no, key + 8);
  96         outb(val, key + 0xc);
  97         restore_flags(flags);
  98 }
  99 
 100 static byte get_cmd640_reg_vlb(int key, int reg_no)
     /* [previous][next][first][last][top][bottom][index][help] */
 101 {
 102         byte b;
 103         unsigned long flags;
 104 
 105         save_flags(flags);
 106         cli();
 107         outb(reg_no, key + 8);
 108         b = inb(key + 0xc);
 109         restore_flags(flags);
 110         return b;
 111 }
 112 
 113 /*
 114  * Probe for CMD640x -- pci method 1
 115  */
 116 
 117 static int probe_for_cmd640_pci1(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 118 {
 119         long id;
 120         int     k;
 121 
 122         for (k = 0x80000000; k <= 0x8000f800; k += 0x800) {
 123                 outl(k, 0xcf8);
 124                 id = inl(0xcfc);
 125                 if (id != 0x06401095)
 126                         continue;
 127                 put_cmd640_reg = put_cmd640_reg_pci1;
 128                 get_cmd640_reg = get_cmd640_reg_pci1;
 129                 cmd640_key = k;
 130                 return 1;
 131         }
 132         return 0;
 133 }
 134 
 135 /*
 136  * Probe for CMD640x -- pci method 2
 137  */
 138 
 139 static int probe_for_cmd640_pci2(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 140 {
 141         int i;
 142         int v_id;
 143         int d_id;
 144 
 145         for (i = 0xc000; i <= 0xcf00; i += 0x100) {
 146                 outb(0x10, 0xcf8);
 147                 v_id = inw(i);
 148                 d_id = inw(i + 2);
 149                 outb(0, 0xcf8);
 150                 if (v_id != 0x1095 || d_id != 0x640)
 151                         continue;
 152                 put_cmd640_reg = put_cmd640_reg_pci2;
 153                 get_cmd640_reg = get_cmd640_reg_pci2;
 154                 cmd640_key = i;
 155                 return 1;
 156         }
 157         return 0;
 158 }
 159 
 160 /*
 161  * Probe for CMD640x -- vlb
 162  */
 163 
 164 static int probe_for_cmd640_vlb(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 165         byte b;
 166 
 167         outb(0x50, 0x178);
 168         b = inb(0x17c);
 169         if (b == 0xff || b == 0 || (b & 0x20)) {
 170                 outb(0x50, 0xc78);
 171                 b = inb(0x7c);
 172                 if (b == 0xff || b == 0 || !(b & 0x20))
 173                         return 0;
 174                 cmd640_key = 0x70;
 175         } else {
 176                 cmd640_key = 0x170;
 177         }
 178         put_cmd640_reg = put_cmd640_reg_vlb;
 179         get_cmd640_reg = get_cmd640_reg_vlb;
 180         return 1;
 181 }
 182 
 183 /*
 184  * Probe for Cmd640x and initialize it if found
 185  */
 186 
 187 int ide_probe_for_cmd640x(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 188 {
 189         int i;
 190 
 191         for (i = 0; i < MAX_HWIFS; i++)
 192                 is_cmd640[i] = 0;
 193 
 194         if (probe_for_cmd640_pci1()) {
 195                 bus_type = pci1;
 196         } else if (probe_for_cmd640_pci2()) {
 197                 bus_type = pci2;
 198         } else if (cmd640_vlb && probe_for_cmd640_vlb()) {
 199                 /* May be remove cmd640_vlb at all, and probe in any case */
 200                 bus_type = vlb;
 201         } else {
 202                 return 0;
 203         }
 204 
 205         /*
 206          * Undocumented magic. (There is no 0x5b port in specs)
 207          */
 208 
 209         put_cmd640_reg(cmd640_key, 0x5b, 0xbd);
 210         if (get_cmd640_reg(cmd640_key, 0x5b) != 0xbd) {
 211                 printk("ide: can't initialize cmd640 -- wrong value in 0x5b\n");
 212                 return 0;
 213         }
 214         put_cmd640_reg(cmd640_key, 0x5b, 0);
 215 
 216         /*
 217          * Documented magic.
 218          */
 219 
 220         cmd640_chip_version = get_cmd640_reg(cmd640_key, 0x50) & 3;
 221         if (cmd640_chip_version == 0) {
 222                 printk ("ide: wrong CMD640 version -- 0\n");
 223                 return 0;
 224         }
 225 
 226         put_cmd640_reg(cmd640_key, 0x51, get_cmd640_reg(cmd640_key, 0x51) | 0xc8);
 227         put_cmd640_reg(cmd640_key, 0x57, 0);
 228         put_cmd640_reg(cmd640_key, 0x57, get_cmd640_reg(cmd640_key, 0x57) | 0x0c);
 229 
 230         serialized = 1;
 231 
 232         printk("ide: buggy CMD640 interface at ");
 233         switch (bus_type) {
 234                 case vlb :
 235                         printk("local bus, port 0x%x", cmd640_key);
 236                         break;
 237                 case pci1:
 238                         printk("pci, (0x%x)", cmd640_key);
 239                         break;
 240                 case pci2:
 241                         printk("pci,(access method 2) (0x%x)", cmd640_key);
 242                         break;
 243         }
 244 
 245         is_cmd640[0] = is_cmd640[1] = 1;
 246 
 247         /*
 248          * Reset interface timings
 249          */
 250 
 251         put_cmd640_reg(cmd640_key, 0x58, 0);
 252         put_cmd640_reg(cmd640_key, 0x52, 0);
 253 
 254         printk("\n ... serialized, disabled read-ahead, secondary interface enabled\n");
 255 
 256         return 1;
 257 }
 258 
 259 static int as_clocks(int a) {
     /* [previous][next][first][last][top][bottom][index][help] */
 260         switch (a & 0xf0) {
 261                 case 0 :        return 4;
 262                 case 0x40 :     return 2;
 263                 case 0x80 :     return 3;
 264                 case 0xc0 :     return 5;
 265                 default :       return -1;
 266         }
 267 }
 268 
 269 /*
 270  * Tuning of drive parameters
 271  */
 272 
 273 static void cmd640_set_timing(int if_num, int dr_num, int r1, int r2) {
     /* [previous][next][first][last][top][bottom][index][help] */
 274         int  b_reg;
 275         byte b;
 276         int  r52;
 277 
 278         b_reg = if_num ? 0x57 : dr_num ? 0x55 : 0x53;
 279 
 280         if (if_num == 0) {
 281                 put_cmd640_reg(cmd640_key, b_reg, r1);
 282                 put_cmd640_reg(cmd640_key, b_reg + 1, r2);
 283         } else {
 284                 b = get_cmd640_reg(cmd640_key, b_reg);
 285                 if ((b&1) == 0) {
 286                         put_cmd640_reg(cmd640_key, b_reg, r1);
 287                 } else {
 288                         if (as_clocks(b) < as_clocks(r1))
 289                                 put_cmd640_reg(cmd640_key, b_reg, r1);
 290                 }
 291                 b = get_cmd640_reg(cmd640_key, b_reg + 1);
 292                 if (b == 0) {
 293                         put_cmd640_reg(cmd640_key, b_reg + 1, r2);
 294                 } else {
 295                         r52 = (b&0xf) < (r2&0xf) ? (r2&0xf) : (b&0xf);
 296                         r52 |= (b&0xf0) < (r2&0xf0) ? (r2&0xf0) : (b&0xf0);
 297                         put_cmd640_reg(cmd640_key, b_reg+1, r52);
 298                 }
 299         }
 300 
 301         b = get_cmd640_reg(cmd640_key, 0x52);
 302         if (b == 0) {
 303                 put_cmd640_reg(cmd640_key, 0x52, r2);
 304         } else {
 305                 r52 = (b&0xf) < (r2&0xf) ? (r2&0xf) : (b&0xf);
 306                 r52 |= (b&0xf0) < (r2&0xf0) ? (r2&0xf0) : (b&0xf0);
 307                 put_cmd640_reg(cmd640_key, 0x52, r52);
 308         }
 309 }
 310 
 311 static int bus_speed = 33; /* MHz */
 312 
 313 struct pio_timing {
 314         int     mc_time;        /* Minimal cycle time (ns) */
 315         int     av_time;        /* Address valid to DIOR-/DIOW- setup (ns) */
 316         int     ds_time;        /* DIOR data setup      (ns) */
 317 } pio_timings[6] = {
 318         { 70,   165,    600 },  /* PIO Mode 0 */
 319         { 50,   125,    383 },  /* PIO Mode 1 */
 320         { 30,   100,    240 },  /* PIO Mode 2 */
 321         { 30,   80,     180 },  /* PIO Mode 3 */
 322         { 25,   70,     125 },  /* PIO Mode 4 */
 323         { 20,   50,     100 }   /* PIO Mode ? */
 324 };
 325 
 326 struct drive_pio_info {
 327         const char      *name;
 328         int             pio;
 329 } drive_pios[] = {
 330         { "Maxtor 7131 AT", 1 },
 331         { "Maxtor 7171 AT", 1 },
 332         { "Maxtor 7213 AT", 1 },
 333         { "Maxtor 7245 AT", 1 },
 334         { "SAMSUNG SHD-3122A", 1 },
 335         { "QUANTUM ELS127A", 0 },
 336         { "QUANTUM LPS240A", 0 },
 337         { "QUANTUM LPS270A", 3 },
 338         { "QUANTUM LPS540A", 3 },
 339         { NULL, 0 }
 340 };
 341 
 342 static int known_drive_pio(char* name) {
     /* [previous][next][first][last][top][bottom][index][help] */
 343         struct drive_pio_info* pi;
 344 
 345         for (pi = drive_pios; pi->name != NULL; pi++) {
 346                 if (strcmp(pi->name, name) == 0)
 347                         return pi->pio;
 348         }
 349         return -1;
 350 }
 351 
 352 static void cmd640_timings_to_regvals(int mc_time, int av_time, int ds_time,
     /* [previous][next][first][last][top][bottom][index][help] */
 353                                 int clock_time,
 354                                 int* r1, int* r2)
 355 {
 356         int a, b;
 357 
 358         a = (mc_time + clock_time - 1)/clock_time;
 359         if (a <= 2) *r1 = 0x40;
 360         else if (a == 3) *r1 = 0x80;
 361         else if (a == 4) *r1 = 0;
 362         else *r1 = 0xc0;
 363 
 364         a = (av_time + clock_time - 1)/clock_time;
 365         if (a < 2)
 366                 a = 2;
 367         b = (ds_time + clock_time - 1)/clock_time - a;
 368         if (b < 2)
 369                 b = 2;
 370         if (b > 0x11) {
 371                 a += b - 0x11;
 372                 b = 0x11;
 373         }
 374         if (a > 0xf)
 375                 a = 0;
 376         if (cmd640_chip_version > 1)
 377                 b -= 1;
 378         if (b > 0xf)
 379                 b = 0;
 380         *r2 = (a << 4) | b;
 381 }
 382 
 383 static void set_pio_mode(int if_num, int drv_num, int mode_num) {
     /* [previous][next][first][last][top][bottom][index][help] */
 384         int p_base;
 385         int i;
 386 
 387         p_base = if_num ? 0x170 : 0x1f0;
 388         outb(3, p_base + 1);
 389         outb(mode_num | 8, p_base + 2);
 390         outb((drv_num | 0xa) << 4, p_base + 6);
 391         outb(0xef, p_base + 7);
 392         for (i = 0; (i < 100) && (inb (p_base + 7) & 0x80); i++)
 393                 delay_10ms();
 394 }
 395 
 396 void cmd640_tune_drive(ide_drive_t* drive) {
     /* [previous][next][first][last][top][bottom][index][help] */
 397         int interface_number;
 398         int drive_number;
 399         int clock_time; /* ns */
 400         int max_pio;
 401         int mc_time, av_time, ds_time;
 402         struct hd_driveid* id;
 403         int r1, r2;
 404 
 405         /*
 406          * Determine if drive is under cmd640 control
 407          */
 408         interface_number = HWIF(drive) - ide_hwifs;
 409         if (!is_cmd640[interface_number])
 410                 return;
 411 
 412         drive_number = drive - HWIF(drive)->drives;
 413         clock_time = 1000/bus_speed;
 414         id = drive->id;
 415         if ((max_pio = known_drive_pio(id->model)) != -1) {
 416                 mc_time = pio_timings[max_pio].mc_time;
 417                 av_time = pio_timings[max_pio].av_time;
 418                 ds_time = pio_timings[max_pio].ds_time;
 419         } else {
 420                 max_pio = id->tPIO;
 421                 mc_time = pio_timings[max_pio].mc_time;
 422                 av_time = pio_timings[max_pio].av_time;
 423                 ds_time = pio_timings[max_pio].ds_time;
 424                 if (id->field_valid & 2) {
 425                         if ((id->capability & 8) && (id->eide_pio_modes & 7)) {
 426                                 if (id->eide_pio_modes & 4) max_pio = 5;
 427                                 else if (id->eide_pio_modes & 2) max_pio = 4;
 428                                 else max_pio = 3;
 429                                 ds_time = id->eide_pio_iordy;
 430                                 mc_time = pio_timings[max_pio].mc_time;
 431                                 av_time = pio_timings[max_pio].av_time;
 432                         } else {
 433                                 ds_time = id->eide_pio;
 434                         }
 435                         if (ds_time == 0)
 436                                 ds_time = pio_timings[max_pio].ds_time;
 437                 }
 438         }
 439         cmd640_timings_to_regvals(mc_time, av_time, ds_time, clock_time,
 440                                 &r1, &r2);
 441         set_pio_mode(interface_number, drive_number, max_pio);
 442         cmd640_set_timing(interface_number, drive_number, r1, r2);
 443         printk ("Mode and Timing set to PIO%d (0x%x 0x%x)\n", max_pio, r1, r2);
 444 }

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