umc8672.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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/config.h>
  41. #include <linux/types.h>
  42. #include <linux/kernel.h>
  43. #include <linux/delay.h>
  44. #include <linux/timer.h>
  45. #include <linux/mm.h>
  46. #include <linux/ioport.h>
  47. #include <linux/blkdev.h>
  48. #include <linux/hdreg.h>
  49. #include <linux/ide.h>
  50. #include <linux/init.h>
  51. #include <asm/io.h>
  52. /*
  53. * Default speeds. These can be changed with "auto-tune" and/or hdparm.
  54. */
  55. #define UMC_DRIVE0 1 /* DOS measured drive speeds */
  56. #define UMC_DRIVE1 1 /* 0 to 11 allowed */
  57. #define UMC_DRIVE2 1 /* 11 = Fastest Speed */
  58. #define UMC_DRIVE3 1 /* In case of crash reduce speed */
  59. static u8 current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3};
  60. static const u8 pio_to_umc [5] = {0,3,7,10,11}; /* rough guesses */
  61. /* 0 1 2 3 4 5 6 7 8 9 10 11 */
  62. static const u8 speedtab [3][12] = {
  63. {0xf, 0xb, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
  64. {0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
  65. {0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}};
  66. static void out_umc (char port,char wert)
  67. {
  68. outb_p(port,0x108);
  69. outb_p(wert,0x109);
  70. }
  71. static inline u8 in_umc (char port)
  72. {
  73. outb_p(port,0x108);
  74. return inb_p(0x109);
  75. }
  76. static void umc_set_speeds (u8 speeds[])
  77. {
  78. int i, tmp;
  79. outb_p(0x5A,0x108); /* enable umc */
  80. out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
  81. out_umc (0xd6,(speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
  82. tmp = 0;
  83. for (i = 3; i >= 0; i--) {
  84. tmp = (tmp << 2) | speedtab[1][speeds[i]];
  85. }
  86. out_umc (0xdc,tmp);
  87. for (i = 0;i < 4; i++) {
  88. out_umc (0xd0+i,speedtab[2][speeds[i]]);
  89. out_umc (0xd8+i,speedtab[2][speeds[i]]);
  90. }
  91. outb_p(0xa5,0x108); /* disable umc */
  92. printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
  93. speeds[0], speeds[1], speeds[2], speeds[3]);
  94. }
  95. static void tune_umc (ide_drive_t *drive, u8 pio)
  96. {
  97. unsigned long flags;
  98. ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
  99. pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
  100. printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
  101. drive->name, pio, pio_to_umc[pio]);
  102. spin_lock_irqsave(&ide_lock, flags);
  103. if (hwgroup && hwgroup->handler != NULL) {
  104. printk(KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n");
  105. } else {
  106. current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
  107. umc_set_speeds (current_speeds);
  108. }
  109. spin_unlock_irqrestore(&ide_lock, flags);
  110. }
  111. static int __init umc8672_probe(void)
  112. {
  113. unsigned long flags;
  114. ide_hwif_t *hwif, *mate;
  115. if (!request_region(0x108, 2, "umc8672")) {
  116. printk(KERN_ERR "umc8672: ports 0x108-0x109 already in use.\n");
  117. return 1;
  118. }
  119. local_irq_save(flags);
  120. outb_p(0x5A,0x108); /* enable umc */
  121. if (in_umc (0xd5) != 0xa0) {
  122. local_irq_restore(flags);
  123. printk(KERN_ERR "umc8672: not found\n");
  124. release_region(0x108, 2);
  125. return 1;
  126. }
  127. outb_p(0xa5,0x108); /* disable umc */
  128. umc_set_speeds (current_speeds);
  129. local_irq_restore(flags);
  130. hwif = &ide_hwifs[0];
  131. mate = &ide_hwifs[1];
  132. hwif->chipset = ide_umc8672;
  133. hwif->tuneproc = &tune_umc;
  134. hwif->mate = mate;
  135. mate->chipset = ide_umc8672;
  136. mate->tuneproc = &tune_umc;
  137. mate->mate = hwif;
  138. mate->channel = 1;
  139. probe_hwif_init(hwif);
  140. probe_hwif_init(mate);
  141. create_proc_ide_interfaces();
  142. return 0;
  143. }
  144. /* Can be called directly from ide.c. */
  145. int __init umc8672_init(void)
  146. {
  147. if (umc8672_probe())
  148. return -ENODEV;
  149. return 0;
  150. }
  151. #ifdef MODULE
  152. module_init(umc8672_init);
  153. #endif
  154. MODULE_AUTHOR("Wolfram Podien");
  155. MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
  156. MODULE_LICENSE("GPL");