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

📄 pata_pdc2027x.c

📁 This file was based on: drivers/ata/pata_ixp4xx_cf.c
💻 C
📖 第 1 页 / 共 2 页
字号:
 *	@r_failed: Returned device for failure * *	The pdc2027x hardware will look at "SET FEATURES" and change the timing registers *	automatically. The values set by the hardware might be incorrect, under 133Mhz PLL. *	This function overwrites the possibly incorrect values set by the hardware to be correct. */static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed){	struct ata_port *ap = link->ap;	struct ata_device *dev;	int rc;	rc = ata_do_set_mode(link, r_failed);	if (rc < 0)		return rc;	ata_link_for_each_dev(dev, link) {		if (ata_dev_enabled(dev)) {			pdc2027x_set_piomode(ap, dev);			/*			 * Enable prefetch if the device support PIO only.			 */			if (dev->xfer_shift == ATA_SHIFT_PIO) {				u32 ctcr1 = ioread32(dev_mmio(ap, dev, PDC_CTCR1));				ctcr1 |= (1 << 25);				iowrite32(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));				PDPRINTK("Turn on prefetch\n");			} else {				pdc2027x_set_dmamode(ap, dev);			}		}	}	return 0;}/** *	pdc2027x_check_atapi_dma - Check whether ATAPI DMA can be supported for this command *	@qc: Metadata associated with taskfile to check * *	LOCKING: *	None (inherited from caller). * *	RETURNS: 0 when ATAPI DMA can be used *		 1 otherwise */static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc){	struct scsi_cmnd *cmd = qc->scsicmd;	u8 *scsicmd = cmd->cmnd;	int rc = 1; /* atapi dma off by default */	/*	 * This workaround is from Promise's GPL driver.	 * If ATAPI DMA is used for commands not in the	 * following white list, say MODE_SENSE and REQUEST_SENSE,	 * pdc2027x might hit the irq lost problem.	 */	switch (scsicmd[0]) {	case READ_10:	case WRITE_10:	case READ_12:	case WRITE_12:	case READ_6:	case WRITE_6:	case 0xad: /* READ_DVD_STRUCTURE */	case 0xbe: /* READ_CD */		/* ATAPI DMA is ok */		rc = 0;		break;	default:		;	}	return rc;}/** * pdc_read_counter - Read the ctr counter * @host: target ATA host */static long pdc_read_counter(struct ata_host *host){	void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR];	long counter;	int retry = 1;	u32 bccrl, bccrh, bccrlv, bccrhv;retry:	bccrl = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff;	bccrh = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;	/* Read the counter values again for verification */	bccrlv = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff;	bccrhv = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;	counter = (bccrh << 15) | bccrl;	PDPRINTK("bccrh [%X] bccrl [%X]\n", bccrh,  bccrl);	PDPRINTK("bccrhv[%X] bccrlv[%X]\n", bccrhv, bccrlv);	/*	 * The 30-bit decreasing counter are read by 2 pieces.	 * Incorrect value may be read when both bccrh and bccrl are changing.	 * Ex. When 7900 decrease to 78FF, wrong value 7800 might be read.	 */	if (retry && !(bccrh == bccrhv && bccrl >= bccrlv)) {		retry--;		PDPRINTK("rereading counter\n");		goto retry;	}	return counter;}/** * adjust_pll - Adjust the PLL input clock in Hz. * * @pdc_controller: controller specific information * @host: target ATA host * @pll_clock: The input of PLL in HZ */static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int board_idx){	void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR];	u16 pll_ctl;	long pll_clock_khz = pll_clock / 1000;	long pout_required = board_idx? PDC_133_MHZ:PDC_100_MHZ;	long ratio = pout_required / pll_clock_khz;	int F, R;	/* Sanity check */	if (unlikely(pll_clock_khz < 5000L || pll_clock_khz > 70000L)) {		printk(KERN_ERR DRV_NAME ": Invalid PLL input clock %ldkHz, give up!\n", pll_clock_khz);		return;	}#ifdef PDC_DEBUG	PDPRINTK("pout_required is %ld\n", pout_required);	/* Show the current clock value of PLL control register	 * (maybe already configured by the firmware)	 */	pll_ctl = ioread16(mmio_base + PDC_PLL_CTL);	PDPRINTK("pll_ctl[%X]\n", pll_ctl);#endif	/*	 * Calculate the ratio of F, R and OD	 * POUT = (F + 2) / (( R + 2) * NO)	 */	if (ratio < 8600L) { /* 8.6x */		/* Using NO = 0x01, R = 0x0D */		R = 0x0d;	} else if (ratio < 12900L) { /* 12.9x */		/* Using NO = 0x01, R = 0x08 */		R = 0x08;	} else if (ratio < 16100L) { /* 16.1x */		/* Using NO = 0x01, R = 0x06 */		R = 0x06;	} else if (ratio < 64000L) { /* 64x */		R = 0x00;	} else {		/* Invalid ratio */		printk(KERN_ERR DRV_NAME ": Invalid ratio %ld, give up!\n", ratio);		return;	}	F = (ratio * (R+2)) / 1000 - 2;	if (unlikely(F < 0 || F > 127)) {		/* Invalid F */		printk(KERN_ERR DRV_NAME ": F[%d] invalid!\n", F);		return;	}	PDPRINTK("F[%d] R[%d] ratio*1000[%ld]\n", F, R, ratio);	pll_ctl = (R << 8) | F;	PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl);	iowrite16(pll_ctl, mmio_base + PDC_PLL_CTL);	ioread16(mmio_base + PDC_PLL_CTL); /* flush */	/* Wait the PLL circuit to be stable */	mdelay(30);#ifdef PDC_DEBUG	/*	 *  Show the current clock value of PLL control register	 * (maybe configured by the firmware)	 */	pll_ctl = ioread16(mmio_base + PDC_PLL_CTL);	PDPRINTK("pll_ctl[%X]\n", pll_ctl);#endif	return;}/** * detect_pll_input_clock - Detect the PLL input clock in Hz. * @host: target ATA host * Ex. 16949000 on 33MHz PCI bus for pdc20275. *     Half of the PCI clock. */static long pdc_detect_pll_input_clock(struct ata_host *host){	void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR];	u32 scr;	long start_count, end_count;	struct timeval start_time, end_time;	long pll_clock, usec_elapsed;	/* Start the test mode */	scr = ioread32(mmio_base + PDC_SYS_CTL);	PDPRINTK("scr[%X]\n", scr);	iowrite32(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL);	ioread32(mmio_base + PDC_SYS_CTL); /* flush */	/* Read current counter value */	start_count = pdc_read_counter(host);	do_gettimeofday(&start_time);	/* Let the counter run for 100 ms. */	mdelay(100);	/* Read the counter values again */	end_count = pdc_read_counter(host);	do_gettimeofday(&end_time);	/* Stop the test mode */	scr = ioread32(mmio_base + PDC_SYS_CTL);	PDPRINTK("scr[%X]\n", scr);	iowrite32(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL);	ioread32(mmio_base + PDC_SYS_CTL); /* flush */	/* calculate the input clock in Hz */	usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 +		(end_time.tv_usec - start_time.tv_usec);	pll_clock = ((start_count - end_count) & 0x3fffffff) / 100 *		(100000000 / usec_elapsed);	PDPRINTK("start[%ld] end[%ld] \n", start_count, end_count);	PDPRINTK("PLL input clock[%ld]Hz\n", pll_clock);	return pll_clock;}/** * pdc_hardware_init - Initialize the hardware. * @host: target ATA host * @board_idx: board identifier */static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx){	long pll_clock;	/*	 * Detect PLL input clock rate.	 * On some system, where PCI bus is running at non-standard clock rate.	 * Ex. 25MHz or 40MHz, we have to adjust the cycle_time.	 * The pdc20275 controller employs PLL circuit to help correct timing registers setting.	 */	pll_clock = pdc_detect_pll_input_clock(host);	dev_printk(KERN_INFO, host->dev, "PLL input clock %ld kHz\n", pll_clock/1000);	/* Adjust PLL control register */	pdc_adjust_pll(host, pll_clock, board_idx);	return 0;}/** * pdc_ata_setup_port - setup the mmio address * @port: ata ioports to setup * @base: base address */static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base){	port->cmd_addr		=	port->data_addr		= base;	port->feature_addr	=	port->error_addr	= base + 0x05;	port->nsect_addr	= base + 0x0a;	port->lbal_addr		= base + 0x0f;	port->lbam_addr		= base + 0x10;	port->lbah_addr		= base + 0x15;	port->device_addr	= base + 0x1a;	port->command_addr	=	port->status_addr	= base + 0x1f;	port->altstatus_addr	=	port->ctl_addr		= base + 0x81a;}/** * pdc2027x_init_one - PCI probe function * Called when an instance of PCI adapter is inserted. * This function checks whether the hardware is supported, * initialize hardware and register an instance of ata_host to * libata.  (implements struct pci_driver.probe() ) * * @pdev: instance of pci_dev found * @ent:  matching entry in the id_tbl[] */static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){	static int printed_version;	static const unsigned long cmd_offset[] = { 0x17c0, 0x15c0 };	static const unsigned long bmdma_offset[] = { 0x1000, 0x1008 };	unsigned int board_idx = (unsigned int) ent->driver_data;	const struct ata_port_info *ppi[] =		{ &pdc2027x_port_info[board_idx], NULL };	struct ata_host *host;	void __iomem *mmio_base;	int i, rc;	if (!printed_version++)		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");	/* alloc host */	host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);	if (!host)		return -ENOMEM;	/* acquire resources and fill host */	rc = pcim_enable_device(pdev);	if (rc)		return rc;	rc = pcim_iomap_regions(pdev, 1 << PDC_MMIO_BAR, DRV_NAME);	if (rc)		return rc;	host->iomap = pcim_iomap_table(pdev);	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);	if (rc)		return rc;	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);	if (rc)		return rc;	mmio_base = host->iomap[PDC_MMIO_BAR];	for (i = 0; i < 2; i++) {		struct ata_port *ap = host->ports[i];		pdc_ata_setup_port(&ap->ioaddr, mmio_base + cmd_offset[i]);		ap->ioaddr.bmdma_addr = mmio_base + bmdma_offset[i];		ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");		ata_port_pbar_desc(ap, PDC_MMIO_BAR, cmd_offset[i], "cmd");	}	//pci_enable_intx(pdev);	/* initialize adapter */	if (pdc_hardware_init(host, board_idx) != 0)		return -EIO;	pci_set_master(pdev);	return ata_host_activate(host, pdev->irq, ata_sff_interrupt,				 IRQF_SHARED, &pdc2027x_sht);}/** * pdc2027x_init - Called after this module is loaded into the kernel. */static int __init pdc2027x_init(void){	return pci_register_driver(&pdc2027x_pci_driver);}/** * pdc2027x_exit - Called before this module unloaded from the kernel */static void __exit pdc2027x_exit(void){	pci_unregister_driver(&pdc2027x_pci_driver);}module_init(pdc2027x_init);module_exit(pdc2027x_exit);

⌨️ 快捷键说明

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