PageRenderTime 26ms CodeModel.GetById 13ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/ide/legacy/ali14xx.c

https://bitbucket.org/evzijst/gittest
C | 253 lines | 157 code | 33 blank | 63 comment | 12 complexity | b0bb67b91f33435e3f5af70577474858 MD5 | raw file
  1/*
  2 *  linux/drivers/ide/legacy/ali14xx.c		Version 0.03	Feb 09, 1996
  3 *
  4 *  Copyright (C) 1996  Linus Torvalds & author (see below)
  5 */
  6
  7/*
  8 * ALI M14xx chipset EIDE controller
  9 *
 10 * Works for ALI M1439/1443/1445/1487/1489 chipsets.
 11 *
 12 * Adapted from code developed by derekn@vw.ece.cmu.edu.  -ml
 13 * Derek's notes follow:
 14 *
 15 * I think the code should be pretty understandable,
 16 * but I'll be happy to (try to) answer questions.
 17 *
 18 * The critical part is in the setupDrive function.  The initRegisters
 19 * function doesn't seem to be necessary, but the DOS driver does it, so
 20 * I threw it in.
 21 *
 22 * I've only tested this on my system, which only has one disk.  I posted
 23 * it to comp.sys.linux.hardware, so maybe some other people will try it
 24 * out.
 25 *
 26 * Derek Noonburg  (derekn@ece.cmu.edu)
 27 * 95-sep-26
 28 *
 29 * Update 96-jul-13:
 30 *
 31 * I've since upgraded to two disks and a CD-ROM, with no trouble, and
 32 * I've also heard from several others who have used it successfully.
 33 * This driver appears to work with both the 1443/1445 and the 1487/1489
 34 * chipsets.  I've added support for PIO mode 4 for the 1487.  This
 35 * seems to work just fine on the 1443 also, although I'm not sure it's
 36 * advertised as supporting mode 4.  (I've been running a WDC AC21200 in
 37 * mode 4 for a while now with no trouble.)  -Derek
 38 */
 39
 40#undef REALLY_SLOW_IO           /* most systems can safely undef this */
 41
 42#include <linux/module.h>
 43#include <linux/config.h>
 44#include <linux/types.h>
 45#include <linux/kernel.h>
 46#include <linux/delay.h>
 47#include <linux/timer.h>
 48#include <linux/mm.h>
 49#include <linux/ioport.h>
 50#include <linux/blkdev.h>
 51#include <linux/hdreg.h>
 52#include <linux/ide.h>
 53#include <linux/init.h>
 54
 55#include <asm/io.h>
 56
 57/* port addresses for auto-detection */
 58#define ALI_NUM_PORTS 4
 59static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4};
 60
 61/* register initialization data */
 62typedef struct { u8 reg, data; } RegInitializer;
 63
 64static RegInitializer initData[] __initdata = {
 65	{0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
 66	{0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
 67	{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
 68	{0x29, 0x00}, {0x2a, 0x00}, {0x2f, 0x00}, {0x2b, 0x00},
 69	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x30, 0x00},
 70	{0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0xff},
 71	{0x35, 0x03}, {0x00, 0x00}
 72};
 73
 74#define ALI_MAX_PIO 4
 75
 76/* timing parameter registers for each drive */
 77static struct { u8 reg1, reg2, reg3, reg4; } regTab[4] = {
 78	{0x03, 0x26, 0x04, 0x27},     /* drive 0 */
 79	{0x05, 0x28, 0x06, 0x29},     /* drive 1 */
 80	{0x2b, 0x30, 0x2c, 0x31},     /* drive 2 */
 81	{0x2d, 0x32, 0x2e, 0x33},     /* drive 3 */
 82};
 83
 84static int basePort;	/* base port address */
 85static int regPort;	/* port for register number */
 86static int dataPort;	/* port for register data */
 87static u8 regOn;	/* output to base port to access registers */
 88static u8 regOff;	/* output to base port to close registers */
 89
 90/*------------------------------------------------------------------------*/
 91
 92/*
 93 * Read a controller register.
 94 */
 95static inline u8 inReg (u8 reg)
 96{
 97	outb_p(reg, regPort);
 98	return inb(dataPort);
 99}
100
101/*
102 * Write a controller register.
103 */
104static void outReg (u8 data, u8 reg)
105{
106	outb_p(reg, regPort);
107	outb_p(data, dataPort);
108}
109
110/*
111 * Set PIO mode for the specified drive.
112 * This function computes timing parameters
113 * and sets controller registers accordingly.
114 */
115static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio)
116{
117	int driveNum;
118	int time1, time2;
119	u8 param1, param2, param3, param4;
120	unsigned long flags;
121	ide_pio_data_t d;
122	int bus_speed = system_bus_clock();
123
124	pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
125
126	/* calculate timing, according to PIO mode */
127	time1 = d.cycle_time;
128	time2 = ide_pio_timings[pio].active_time;
129	param3 = param1 = (time2 * bus_speed + 999) / 1000;
130	param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
131	if (pio < 3) {
132		param3 += 8;
133		param4 += 8;
134	}
135	printk(KERN_DEBUG "%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
136		drive->name, pio, time1, time2, param1, param2, param3, param4);
137
138	/* stuff timing parameters into controller registers */
139	driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
140	spin_lock_irqsave(&ide_lock, flags);
141	outb_p(regOn, basePort);
142	outReg(param1, regTab[driveNum].reg1);
143	outReg(param2, regTab[driveNum].reg2);
144	outReg(param3, regTab[driveNum].reg3);
145	outReg(param4, regTab[driveNum].reg4);
146	outb_p(regOff, basePort);
147	spin_unlock_irqrestore(&ide_lock, flags);
148}
149
150/*
151 * Auto-detect the IDE controller port.
152 */
153static int __init findPort (void)
154{
155	int i;
156	u8 t;
157	unsigned long flags;
158
159	local_irq_save(flags);
160	for (i = 0; i < ALI_NUM_PORTS; ++i) {
161		basePort = ports[i];
162		regOff = inb(basePort);
163		for (regOn = 0x30; regOn <= 0x33; ++regOn) {
164			outb_p(regOn, basePort);
165			if (inb(basePort) == regOn) {
166				regPort = basePort + 4;
167				dataPort = basePort + 8;
168				t = inReg(0) & 0xf0;
169				outb_p(regOff, basePort);
170				local_irq_restore(flags);
171				if (t != 0x50)
172					return 0;
173				return 1;  /* success */
174			}
175		}
176		outb_p(regOff, basePort);
177	}
178	local_irq_restore(flags);
179	return 0;
180}
181
182/*
183 * Initialize controller registers with default values.
184 */
185static int __init initRegisters (void) {
186	RegInitializer *p;
187	u8 t;
188	unsigned long flags;
189
190	local_irq_save(flags);
191	outb_p(regOn, basePort);
192	for (p = initData; p->reg != 0; ++p)
193		outReg(p->data, p->reg);
194	outb_p(0x01, regPort);
195	t = inb(regPort) & 0x01;
196	outb_p(regOff, basePort);
197	local_irq_restore(flags);
198	return t;
199}
200
201static int __init ali14xx_probe(void)
202{
203	ide_hwif_t *hwif, *mate;
204
205	printk(KERN_DEBUG "ali14xx: base=0x%03x, regOn=0x%02x.\n",
206			  basePort, regOn);
207
208	/* initialize controller registers */
209	if (!initRegisters()) {
210		printk(KERN_ERR "ali14xx: Chip initialization failed.\n");
211		return 1;
212	}
213
214	hwif = &ide_hwifs[0];
215	mate = &ide_hwifs[1];
216
217	hwif->chipset = ide_ali14xx;
218	hwif->tuneproc = &ali14xx_tune_drive;
219	hwif->mate = mate;
220
221	mate->chipset = ide_ali14xx;
222	mate->tuneproc = &ali14xx_tune_drive;
223	mate->mate = hwif;
224	mate->channel = 1;
225
226	probe_hwif_init(hwif);
227	probe_hwif_init(mate);
228
229	create_proc_ide_interfaces();
230
231	return 0;
232}
233
234/* Can be called directly from ide.c. */
235int __init ali14xx_init(void)
236{
237	/* auto-detect IDE controller port */
238	if (findPort()) {
239		if (ali14xx_probe())
240			return -ENODEV;
241		return 0;
242	}
243	printk(KERN_ERR "ali14xx: not found.\n");
244	return -ENODEV;
245}
246
247#ifdef MODULE
248module_init(ali14xx_init);
249#endif
250
251MODULE_AUTHOR("see local file");
252MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
253MODULE_LICENSE("GPL");