⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cmd640.c

📁 ep9315平台下硬盘驱动的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
 */static void set_prefetch_mode (unsigned int index, int mode){	ide_drive_t *drive = cmd_drives[index];	int reg = prefetch_regs[index];	u8 b;	unsigned long flags;	spin_lock_irqsave(&ide_lock, flags);	b = __get_cmd640_reg(reg);	if (mode) {	/* want prefetch on? */#if CMD640_PREFETCH_MASKS		drive->no_unmask = 1;		drive->unmask = 0;#endif		drive->no_io_32bit = 0;		b &= ~prefetch_masks[index];	/* enable prefetch */	} else {		drive->no_unmask = 0;		drive->no_io_32bit = 1;		drive->io_32bit = 0;		b |= prefetch_masks[index];	/* disable prefetch */	}	__put_cmd640_reg(reg, b);	spin_unlock_irqrestore(&ide_lock, flags);}/* * Dump out current drive clocks settings */static void display_clocks (unsigned int index){	u8 active_count, recovery_count;	active_count = active_counts[index];	if (active_count == 1)		++active_count;	recovery_count = recovery_counts[index];	if (active_count > 3 && recovery_count == 1)		++recovery_count;	if (cmd640_chip_version > 1)		recovery_count += 1;  /* cmd640b uses (count + 1)*/	printk(", clocks=%d/%d/%d\n", setup_counts[index], active_count, recovery_count);}/* * Pack active and recovery counts into single byte representation * used by controller */inline static u8 pack_nibbles (u8 upper, u8 lower){	return ((upper & 0x0f) << 4) | (lower & 0x0f);}/* * This routine retrieves the initial drive timings from the chipset. */static void __init retrieve_drive_counts (unsigned int index){	u8 b;	/*	 * Get the internal setup timing, and convert to clock count	 */	b = get_cmd640_reg(arttim_regs[index]) & ~0x3f;	switch (b) {		case 0x00: b = 4; break;		case 0x80: b = 3; break;		case 0x40: b = 2; break;		default:   b = 5; break;	}	setup_counts[index] = b;	/*	 * Get the active/recovery counts	 */	b = get_cmd640_reg(drwtim_regs[index]);	active_counts[index]   = (b >> 4)   ? (b >> 4)   : 0x10;	recovery_counts[index] = (b & 0x0f) ? (b & 0x0f) : 0x10;}/* * This routine writes the prepared setup/active/recovery counts * for a drive into the cmd640 chipset registers to active them. */static void program_drive_counts (unsigned int index){	unsigned long flags;	u8 setup_count    = setup_counts[index];	u8 active_count   = active_counts[index];	u8 recovery_count = recovery_counts[index];	/*	 * Set up address setup count and drive read/write timing registers.	 * Primary interface has individual count/timing registers for	 * each drive.  Secondary interface has one common set of registers,	 * so we merge the timings, using the slowest value for each timing.	 */	if (index > 1) {		unsigned int mate;		if (cmd_drives[mate = index ^ 1]->present) {			if (setup_count < setup_counts[mate])				setup_count = setup_counts[mate];			if (active_count < active_counts[mate])				active_count = active_counts[mate];			if (recovery_count < recovery_counts[mate])				recovery_count = recovery_counts[mate];		}	}	/*	 * Convert setup_count to internal chipset representation	 */	switch (setup_count) {		case 4:	 setup_count = 0x00; break;		case 3:	 setup_count = 0x80; break;		case 1:		case 2:	 setup_count = 0x40; break;		default: setup_count = 0xc0; /* case 5 */	}	/*	 * Now that everything is ready, program the new timings	 */	spin_lock_irqsave(&ide_lock, flags);	/*	 * Program the address_setup clocks into ARTTIM reg,	 * and then the active/recovery counts into the DRWTIM reg	 * (this converts counts of 16 into counts of zero -- okay).	 */	setup_count |= __get_cmd640_reg(arttim_regs[index]) & 0x3f;	__put_cmd640_reg(arttim_regs[index], setup_count);	__put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));	spin_unlock_irqrestore(&ide_lock, flags);}/* * Set a specific pio_mode for a drive */static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle_time){	int setup_time, active_time, recovery_time, clock_time;	u8 setup_count, active_count, recovery_count, recovery_count2, cycle_count;	int bus_speed = system_bus_clock();	if (pio_mode > 5)		pio_mode = 5;	setup_time  = ide_pio_timings[pio_mode].setup_time;	active_time = ide_pio_timings[pio_mode].active_time;	recovery_time = cycle_time - (setup_time + active_time);	clock_time = 1000 / bus_speed;	cycle_count = (cycle_time + clock_time - 1) / clock_time;	setup_count = (setup_time + clock_time - 1) / clock_time;	active_count = (active_time + clock_time - 1) / clock_time;	if (active_count < 2)		active_count = 2; /* minimum allowed by cmd640 */	recovery_count = (recovery_time + clock_time - 1) / clock_time;	recovery_count2 = cycle_count - (setup_count + active_count);	if (recovery_count2 > recovery_count)		recovery_count = recovery_count2;	if (recovery_count < 2)		recovery_count = 2; /* minimum allowed by cmd640 */	if (recovery_count > 17) {		active_count += recovery_count - 17;		recovery_count = 17;	}	if (active_count > 16)		active_count = 16; /* maximum allowed by cmd640 */	if (cmd640_chip_version > 1)		recovery_count -= 1;  /* cmd640b uses (count + 1)*/	if (recovery_count > 16)		recovery_count = 16; /* maximum allowed by cmd640 */	setup_counts[index]    = setup_count;	active_counts[index]   = active_count;	recovery_counts[index] = recovery_count;	/*	 * In a perfect world, we might set the drive pio mode here	 * (using WIN_SETFEATURE) before continuing.	 *	 * But we do not, because:	 *	1) this is the wrong place to do it (proper is do_special() in ide.c)	 * 	2) in practice this is rarely, if ever, necessary	 */	program_drive_counts (index);}/* * Drive PIO mode selection: */static void cmd640_tune_drive (ide_drive_t *drive, u8 mode_wanted){	u8 b;	ide_pio_data_t  d;	unsigned int index = 0;	while (drive != cmd_drives[index]) {		if (++index > 3) {			printk("%s: bad news in cmd640_tune_drive\n", drive->name);			return;		}	}	switch (mode_wanted) {		case 6: /* set fast-devsel off */		case 7: /* set fast-devsel on */			mode_wanted &= 1;			b = get_cmd640_reg(CNTRL) & ~0x27;			if (mode_wanted)				b |= 0x27;			put_cmd640_reg(CNTRL, b);			printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis");			return;		case 8: /* set prefetch off */		case 9: /* set prefetch on */			mode_wanted &= 1;			set_prefetch_mode(index, mode_wanted);			printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");			return;	}	(void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);	cmd640_set_mode (index, d.pio_mode, d.cycle_time);	printk ("%s: selected cmd640 PIO mode%d (%dns)%s",		drive->name,		d.pio_mode,		d.cycle_time,		d.overridden ? " (overriding vendor mode)" : "");	display_clocks(index);	return;}#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */static int pci_conf1(void){	u32 tmp;	unsigned long flags;	spin_lock_irqsave(&ide_lock, flags);	outb(0x01, 0xCFB);	tmp = inl(0xCF8);	outl(0x80000000, 0xCF8);	if (inl(0xCF8) == 0x80000000) {		outl(tmp, 0xCF8);		spin_unlock_irqrestore(&ide_lock, flags);		return 1;	}	outl(tmp, 0xCF8);	spin_unlock_irqrestore(&ide_lock, flags);	return 0;}static int pci_conf2(void){	unsigned long flags;	spin_lock_irqsave(&ide_lock, flags);	outb(0x00, 0xCFB);	outb(0x00, 0xCF8);	outb(0x00, 0xCFA);	if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) {		spin_unlock_irqrestore(&ide_lock, flags);		return 1;	}	spin_unlock_irqrestore(&ide_lock, flags);	return 0;}/* * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c */int __init ide_probe_for_cmd640x (void){#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED	int second_port_toggled = 0;#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */	int second_port_cmd640 = 0;	const char *bus_type, *port2;	unsigned int index;	u8 b, cfr;	if (cmd640_vlb && probe_for_cmd640_vlb()) {		bus_type = "VLB";	} else {		cmd640_vlb = 0;		/* Find out what kind of PCI probing is supported otherwise		   Justin Gibbs will sulk.. */		if (pci_conf1() && probe_for_cmd640_pci1())			bus_type = "PCI (type1)";		else if (pci_conf2() && probe_for_cmd640_pci2())			bus_type = "PCI (type2)";		else			return 0;	}	/*	 * Undocumented magic (there is no 0x5b reg in specs)	 */	put_cmd640_reg(0x5b, 0xbd);	if (get_cmd640_reg(0x5b) != 0xbd) {		printk(KERN_ERR "ide: cmd640 init failed: wrong value in reg 0x5b\n");		return 0;	}	put_cmd640_reg(0x5b, 0);#ifdef CMD640_DUMP_REGS	CMD640_DUMP_REGS;#endif	/*	 * Documented magic begins here	 */	cfr = get_cmd640_reg(CFR);	cmd640_chip_version = cfr & CFR_DEVREV;	if (cmd640_chip_version == 0) {		printk ("ide: bad cmd640 revision: %d\n", cmd640_chip_version);		return 0;	}	/*	 * Initialize data for primary port	 */	setup_device_ptrs ();	printk("%s: buggy cmd640%c interface on %s, config=0x%02x\n",	       cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);	cmd_hwif0->chipset = ide_cmd640;#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED	cmd_hwif0->tuneproc = &cmd640_tune_drive;#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */	/*	 * Ensure compatibility by always using the slowest timings	 * for access to the drive's command register block,	 * and reset the prefetch burstsize to default (512 bytes).	 *	 * Maybe we need a way to NOT do these on *some* systems?	 */	put_cmd640_reg(CMDTIM, 0);	put_cmd640_reg(BRST, 0x40);	/*	 * Try to enable the secondary interface, if not already enabled	 */	if (cmd_hwif1->noprobe) {		port2 = "not probed";	} else {		b = get_cmd640_reg(CNTRL);		if (secondary_port_responding()) {			if ((b & CNTRL_ENA_2ND)) {				second_port_cmd640 = 1;				port2 = "okay";			} else if (cmd640_vlb) {				second_port_cmd640 = 1;				port2 = "alive";			} else				port2 = "not cmd640";		} else {			put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */			if (secondary_port_responding()) {				second_port_cmd640 = 1;#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED				second_port_toggled = 1;#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */				port2 = "enabled";			} else {				put_cmd640_reg(CNTRL, b); /* restore original setting */				port2 = "not responding";			}		}	}	/*	 * Initialize data for secondary cmd640 port, if enabled	 */	if (second_port_cmd640) {		cmd_hwif0->serialized = 1;		cmd_hwif1->serialized = 1;		cmd_hwif1->chipset = ide_cmd640;		cmd_hwif0->mate = cmd_hwif1;		cmd_hwif1->mate = cmd_hwif0;		cmd_hwif1->channel = 1;#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED		cmd_hwif1->tuneproc = &cmd640_tune_drive;#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */	}	printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,		cmd_hwif0->serialized ? "" : "not ", port2);	/*	 * Establish initial timings/prefetch for all drives.	 * Do not unnecessarily disturb any prior BIOS setup of these.	 */	for (index = 0; index < (2 + (second_port_cmd640 << 1)); index++) {		ide_drive_t *drive = cmd_drives[index];#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED		if (drive->autotune || ((index > 1) && second_port_toggled)) {	 		/*	 		 * Reset timing to the slowest speed and turn off prefetch.			 * This way, the drive identify code has a better chance.			 */			setup_counts    [index] = 4;	/* max possible */			active_counts   [index] = 16;	/* max possible */			recovery_counts [index] = 16;	/* max possible */			program_drive_counts (index);			set_prefetch_mode (index, 0);			printk("cmd640: drive%d timings/prefetch cleared\n", index);		} else {			/*			 * Record timings/prefetch without changing them.			 * This preserves any prior BIOS setup.			 */			retrieve_drive_counts (index);			check_prefetch (index);			printk("cmd640: drive%d timings/prefetch(%s) preserved",				index, drive->no_io_32bit ? "off" : "on");			display_clocks(index);		}#else		/*		 * Set the drive unmask flags to match the prefetch setting		 */		check_prefetch (index);		printk("cmd640: drive%d timings/prefetch(%s) preserved\n",			index, drive->no_io_32bit ? "off" : "on");#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */	}#ifdef CMD640_DUMP_REGS	CMD640_DUMP_REGS;#endif	return 1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -