umc8672.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*
  2. * linux/drivers/ide/legacy/umc8672.c Version 0.05 Jul 31, 1996
  3. *
  4. * Copyright (C) 1995-1996 Linus Torvalds & author (see below)
  5. */
  6. /*
  7. * Principal Author/Maintainer: PODIEN@hml2.atlas.de (Wolfram Podien)
  8. *
  9. * This file provides support for the advanced features
  10. * of the UMC 8672 IDE interface.
  11. *
  12. * Version 0.01 Initial version, hacked out of ide.c,
  13. * and #include'd rather than compiled separately.
  14. * This will get cleaned up in a subsequent release.
  15. *
  16. * Version 0.02 now configs/compiles separate from ide.c -ml
  17. * Version 0.03 enhanced auto-tune, fix display bug
  18. * Version 0.05 replace sti() with restore_flags() -ml
  19. * add detection of possible race condition -ml
  20. */
  21. /*
  22. * VLB Controller Support from
  23. * Wolfram Podien
  24. * Rohoefe 3
  25. * D28832 Achim
  26. * Germany
  27. *
  28. * To enable UMC8672 support there must a lilo line like
  29. * append="ide0=umc8672"...
  30. * To set the speed according to the abilities of the hardware there must be a
  31. * line like
  32. * #define UMC_DRIVE0 11
  33. * in the beginning of the driver, which sets the speed of drive 0 to 11 (there
  34. * are some lines present). 0 - 11 are allowed speed values. These values are
  35. * the results from the DOS speed test program supplied from UMC. 11 is the
  36. * highest speed (about PIO mode 3)
  37. */
  38. #define REALLY_SLOW_IO /* some systems can safely undef this */
  39. #include <linux/module.h>
  40. #include <linux/types.h>
  41. #include <linux/kernel.h>
  42. #include <linux/delay.h>
  43. #include <linux/timer.h>
  44. #include <linux/mm.h>
  45. #include <linux/ioport.h>
  46. #include <linux/blkdev.h>
  47. #include <linux/hdreg.h>
  48. #include <linux/ide.h>
  49. #include <linux/init.h>
  50. #include <asm/io.h>
  51. /*
  52. * Default speeds. These can be changed with "auto-tune" and/or hdparm.
  53. */
  54. #define UMC_DRIVE0 1 /* DOS measured drive speeds */
  55. #define UMC_DRIVE1 1 /* 0 to 11 allowed */
  56. #define UMC_DRIVE2 1 /* 11 = Fastest Speed */
  57. #define UMC_DRIVE3 1 /* In case of crash reduce speed */
  58. static u8 current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3};
  59. static const u8 pio_to_umc [5] = {0,3,7,10,11}; /* rough guesses */
  60. /* 0 1 2 3 4 5 6 7 8 9 10 11 */
  61. static const u8 speedtab [3][12] = {
  62. {0xf, 0xb, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
  63. {0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
  64. {0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}};
  65. static void out_umc (char port,char wert)
  66. {
  67. outb_p(port,0x108);
  68. outb_p(wert,0x109);
  69. }
  70. static inline u8 in_umc (char port)
  71. {
  72. outb_p(port,0x108);
  73. return inb_p(0x109);
  74. }
  75. static void umc_set_speeds (u8 speeds[])
  76. {
  77. int i, tmp;
  78. outb_p(0x5A,0x108); /* enable umc */
  79. out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
  80. out_umc (0xd6,(speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
  81. tmp = 0;
  82. for (i = 3; i >= 0; i--) {
  83. tmp = (tmp << 2) | speedtab[1][speeds[i]];
  84. }
  85. out_umc (0xdc,tmp);
  86. for (i = 0;i < 4; i++) {
  87. out_umc (0xd0+i,speedtab[2][speeds[i]]);
  88. out_umc (0xd8+i,speedtab[2][speeds[i]]);
  89. }
  90. outb_p(0xa5,0x108); /* disable umc */
  91. printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
  92. speeds[0], speeds[1], speeds[2], speeds[3]);
  93. }
  94. static void tune_umc (ide_drive_t *drive, u8 pio)
  95. {
  96. unsigned long flags;
  97. ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
  98. pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
  99. printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
  100. drive->name, pio, pio_to_umc[pio]);
  101. spin_lock_irqsave(&ide_lock, flags);
  102. if (hwgroup && hwgroup->handler != NULL) {
  103. printk(KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n");
  104. } else {
  105. current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
  106. umc_set_speeds (current_speeds);
  107. }
  108. spin_unlock_irqrestore(&ide_lock, flags);
  109. }
  110. static int __init umc8672_probe(void)
  111. {
  112. unsigned long flags;
  113. ide_hwif_t *hwif, *mate;
  114. if (!request_region(0x108, 2, "umc8672")) {
  115. printk(KERN_ERR "umc8672: ports 0x108-0x109 already in use.\n");
  116. return 1;
  117. }
  118. local_irq_save(flags);
  119. outb_p(0x5A,0x108); /* enable umc */
  120. if (in_umc (0xd5) != 0xa0) {
  121. local_irq_restore(flags);
  122. printk(KERN_ERR "umc8672: not found\n");
  123. release_region(0x108, 2);
  124. return 1;
  125. }
  126. outb_p(0xa5,0x108); /* disable umc */
  127. umc_set_speeds (current_speeds);
  128. local_irq_restore(flags);
  129. hwif = &ide_hwifs[0];
  130. mate = &ide_hwifs[1];
  131. hwif->chipset = ide_umc8672;
  132. hwif->tuneproc = &tune_umc;
  133. hwif->mate = mate;
  134. mate->chipset = ide_umc8672;
  135. mate->tuneproc = &tune_umc;
  136. mate->mate = hwif;
  137. mate->channel = 1;
  138. probe_hwif_init(hwif);
  139. probe_hwif_init(mate);
  140. create_proc_ide_interfaces();
  141. return 0;
  142. }
  143. /* Can be called directly from ide.c. */
  144. int __init umc8672_init(void)
  145. {
  146. if (umc8672_probe())
  147. return -ENODEV;
  148. return 0;
  149. }
  150. #ifdef MODULE
  151. module_init(umc8672_init);
  152. #endif
  153. MODULE_AUTHOR("Wolfram Podien");
  154. MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
  155. MODULE_LICENSE("GPL");