sata_sx4.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,500 行 · 第 1/3 页

C
1,500
字号
		(long) (window_size - offset);	memcpy_toio((char *) (dimm_mmio + offset / 4), (char *) psource, dist);	writel(0x01, mmio + PDC_GENERAL_CTLR);	readl(mmio + PDC_GENERAL_CTLR);	psource += dist;    	size -= dist;	for (; (long) size >= (long) window_size ;) {		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);		readl(mmio + PDC_DIMM_WINDOW_CTLR);		memcpy_toio((char *) (dimm_mmio), (char *) psource, 			    window_size / 4);		writel(0x01, mmio + PDC_GENERAL_CTLR);		readl(mmio + PDC_GENERAL_CTLR);		psource += window_size;		size -= window_size;		idx ++;	}    	if (size) {		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);		readl(mmio + PDC_DIMM_WINDOW_CTLR);		memcpy_toio((char *) (dimm_mmio), (char *) psource, size / 4);		writel(0x01, mmio + PDC_GENERAL_CTLR);		readl(mmio + PDC_GENERAL_CTLR);	}}static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, 				      u32 subaddr, u32 *pdata){	void *mmio = pe->mmio_base;	u32 i2creg  = 0;	u32 status;     	u32 count =0;	/* hard-code chip #0 */	mmio += PDC_CHIP0_OFS;	i2creg |= device << 24;	i2creg |= subaddr << 16;	/* Set the device and subaddress */	writel(i2creg, mmio + PDC_I2C_ADDR_DATA_OFFSET);	readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);	/* Write Control to perform read operation, mask int */	writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT, 	       mmio + PDC_I2C_CONTROL_OFFSET);	for (count = 0; count <= 1000; count ++) {		status = readl(mmio + PDC_I2C_CONTROL_OFFSET);		if (status & PDC_I2C_COMPLETE) {			status = readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);			break;		} else if (count == 1000)			return 0;	}	*pdata = (status >> 8) & 0x000000ff;	return 1;           }static int pdc20621_detect_dimm(struct ata_probe_ent *pe){	u32 data=0 ;  	if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 			     PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {   		if (data == 100)			return 100;  	} else		return 0; 	   	if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {		if(data <= 0x75) 			return 133;   	} else		return 0;   	   	return 0;}static int pdc20621_prog_dimm0(struct ata_probe_ent *pe){	u32 spd0[50];	u32 data = 0;   	int size, i;   	u8 bdimmsize;    	void *mmio = pe->mmio_base;	static const struct {		unsigned int reg;		unsigned int ofs;	} pdc_i2c_read_data [] = {		{ PDC_DIMM_SPD_TYPE, 11 },				{ PDC_DIMM_SPD_FRESH_RATE, 12 },		{ PDC_DIMM_SPD_COLUMN_NUM, 4 }, 		{ PDC_DIMM_SPD_ATTRIBUTE, 21 },		{ PDC_DIMM_SPD_ROW_NUM, 3 },		{ PDC_DIMM_SPD_BANK_NUM, 17 },		{ PDC_DIMM_SPD_MODULE_ROW, 5 },		{ PDC_DIMM_SPD_ROW_PRE_CHARGE, 27 },		{ PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 },		{ PDC_DIMM_SPD_RAS_CAS_DELAY, 29 },		{ PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 },		{ PDC_DIMM_SPD_CAS_LATENCY, 18 },       	};	/* hard-code chip #0 */	mmio += PDC_CHIP0_OFS;	for(i=0; i<ARRAY_SIZE(pdc_i2c_read_data); i++)		pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,				  pdc_i2c_read_data[i].reg, 				  &spd0[pdc_i2c_read_data[i].ofs]);     	data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4);   	data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) | 		((((spd0[27] + 9) / 10) - 1) << 8) ;   	data |= (((((spd0[29] > spd0[28]) 		    ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10;    	data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12;      	if (spd0[18] & 0x08) 		data |= ((0x03) << 14);   	else if (spd0[18] & 0x04)		data |= ((0x02) << 14);   	else if (spd0[18] & 0x01)		data |= ((0x01) << 14);   	else		data |= (0 << 14);  	/* 	   Calculate the size of bDIMMSize (power of 2) and	   merge the DIMM size by program start/end address.	*/   	bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3;   	size = (1 << bdimmsize) >> 20;	/* size = xxx(MB) */   	data |= (((size / 16) - 1) << 16);   	data |= (0 << 23);	data |= 8;   	writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET); 	readl(mmio + PDC_DIMM0_CONTROL_OFFSET);   	return size;                          }static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe){	u32 data, spd0;   	int error, i;   	void *mmio = pe->mmio_base;	/* hard-code chip #0 */   	mmio += PDC_CHIP0_OFS;   	/*	  Set To Default : DIMM Module Global Control Register (0x022259F1)	  DIMM Arbitration Disable (bit 20)	  DIMM Data/Control Output Driving Selection (bit12 - bit15)	  Refresh Enable (bit 17)	*/	data = 0x022259F1;   	writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);	readl(mmio + PDC_SDRAM_CONTROL_OFFSET);	/* Turn on for ECC */	pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 			  PDC_DIMM_SPD_TYPE, &spd0);	if (spd0 == 0x02) {		data |= (0x01 << 16);		writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);		readl(mmio + PDC_SDRAM_CONTROL_OFFSET);		printk(KERN_ERR "Local DIMM ECC Enabled\n");   	}   	/* DIMM Initialization Select/Enable (bit 18/19) */   	data &= (~(1<<18));   	data |= (1<<19);   	writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);   	error = 1;                        	for (i = 1; i <= 10; i++) {   /* polling ~5 secs */		data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET);		if (!(data & (1<<19))) {	   		error = 0;	   		break;     		}		set_current_state(TASK_UNINTERRUPTIBLE);		schedule_timeout((i * 100) * HZ / 1000 + 1);   	}   	return error;}	static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe){	int speed, size, length; 	u32 addr,spd0,pci_status;	u32 tmp=0;	u32 time_period=0;	u32 tcount=0;	u32 ticks=0;	u32 clock=0;	u32 fparam=0;   	void *mmio = pe->mmio_base;	/* hard-code chip #0 */   	mmio += PDC_CHIP0_OFS;	/* Initialize PLL based upon PCI Bus Frequency */	/* Initialize Time Period Register */	writel(0xffffffff, mmio + PDC_TIME_PERIOD);	time_period = readl(mmio + PDC_TIME_PERIOD);	VPRINTK("Time Period Register (0x40): 0x%x\n", time_period);	/* Enable timer */	writel(0x00001a0, mmio + PDC_TIME_CONTROL);	readl(mmio + PDC_TIME_CONTROL);	/* Wait 3 seconds */	set_current_state(TASK_UNINTERRUPTIBLE);	schedule_timeout(3 * HZ);	/* 	   When timer is enabled, counter is decreased every internal	   clock cycle.	*/	tcount = readl(mmio + PDC_TIME_COUNTER);	VPRINTK("Time Counter Register (0x44): 0x%x\n", tcount);	/* 	   If SX4 is on PCI-X bus, after 3 seconds, the timer counter	   register should be >= (0xffffffff - 3x10^8).	*/	if(tcount >= PCI_X_TCOUNT) {		ticks = (time_period - tcount);		VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks);			clock = (ticks / 300000);		VPRINTK("10 * Internal clk = 0x%x (%d)\n", clock, clock);				clock = (clock * 33);		VPRINTK("10 * Internal clk * 33 = 0x%x (%d)\n", clock, clock);		/* PLL F Param (bit 22:16) */		fparam = (1400000 / clock) - 2;		VPRINTK("PLL F Param: 0x%x (%d)\n", fparam, fparam);				/* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */		pci_status = (0x8a001824 | (fparam << 16));	} else		pci_status = PCI_PLL_INIT;	/* Initialize PLL. */	VPRINTK("pci_status: 0x%x\n", pci_status);	writel(pci_status, mmio + PDC_CTL_STATUS);	readl(mmio + PDC_CTL_STATUS);	/* 	   Read SPD of DIMM by I2C interface,	   and program the DIMM Module Controller.	*/ 	if (!(speed = pdc20621_detect_dimm(pe))) {		printk(KERN_ERR "Detect Local DIMM Fail\n");  		return 1;	/* DIMM error */   	}   	VPRINTK("Local DIMM Speed = %d\n", speed);   	/* Programming DIMM0 Module Control Register (index_CID0:80h) */    	size = pdc20621_prog_dimm0(pe);   	VPRINTK("Local DIMM Size = %dMB\n",size);   	/* Programming DIMM Module Global Control Register (index_CID0:88h) */    	if (pdc20621_prog_dimm_global(pe)) {		printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");		return 1;   	}#ifdef ATA_VERBOSE_DEBUG	{		u8 test_parttern1[40] = {0x55,0xAA,'P','r','o','m','i','s','e',' ',  				'N','o','t',' ','Y','e','t',' ','D','e','f','i','n','e','d',' ', 				 '1','.','1','0',  				'9','8','0','3','1','6','1','2',0,0};		u8 test_parttern2[40] = {0};		pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x10040, 40);		pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40);		pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40);		pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 		       test_parttern2[1], &(test_parttern2[2]));		pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040, 				       40);		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 		       test_parttern2[1], &(test_parttern2[2]));		pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40);		pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 		       test_parttern2[1], &(test_parttern2[2]));	}#endif	/* ECC initiliazation. */	pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 			  PDC_DIMM_SPD_TYPE, &spd0);	if (spd0 == 0x02) {		VPRINTK("Start ECC initialization\n");		addr = 0;		length = size * 1024 * 1024;		while (addr < length) {			pdc20621_put_to_dimm(pe, (void *) &tmp, addr, 					     sizeof(u32));			addr += sizeof(u32);		}		VPRINTK("Finish ECC initialization\n");	}	return 0;}static void pdc_20621_init(struct ata_probe_ent *pe){	u32 tmp;	void *mmio = pe->mmio_base;	/* hard-code chip #0 */	mmio += PDC_CHIP0_OFS;	/*	 * Select page 0x40 for our 32k DIMM window	 */	tmp = readl(mmio + PDC_20621_DIMM_WINDOW) & 0xffff0000;	tmp |= PDC_PAGE_WINDOW;	/* page 40h; arbitrarily selected */	writel(tmp, mmio + PDC_20621_DIMM_WINDOW);	/*	 * Reset Host DMA	 */	tmp = readl(mmio + PDC_HDMA_CTLSTAT);	tmp |= PDC_RESET;	writel(tmp, mmio + PDC_HDMA_CTLSTAT);	readl(mmio + PDC_HDMA_CTLSTAT);		/* flush */	udelay(10);	tmp = readl(mmio + PDC_HDMA_CTLSTAT);	tmp &= ~PDC_RESET;	writel(tmp, mmio + PDC_HDMA_CTLSTAT);	readl(mmio + PDC_HDMA_CTLSTAT);		/* flush */}static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent){	static int printed_version;	struct ata_probe_ent *probe_ent = NULL;	unsigned long base;	void *mmio_base, *dimm_mmio = NULL;	struct pdc_host_priv *hpriv = NULL;	unsigned int board_idx = (unsigned int) ent->driver_data;	int rc;	if (!printed_version++)		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");	/*	 * If this driver happens to only be useful on Apple's K2, then	 * we should check that here as it has a normal Serverworks ID	 */	rc = pci_enable_device(pdev);	if (rc)		return rc;	rc = pci_request_regions(pdev, DRV_NAME);	if (rc)		goto err_out;	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);	if (rc)		goto err_out_regions;	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);	if (rc)		goto err_out_regions;	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);	if (probe_ent == NULL) {		rc = -ENOMEM;		goto err_out_regions;	}	memset(probe_ent, 0, sizeof(*probe_ent));	probe_ent->pdev = pdev;	INIT_LIST_HEAD(&probe_ent->node);	mmio_base = ioremap(pci_resource_start(pdev, 3),		            pci_resource_len(pdev, 3));	if (mmio_base == NULL) {		rc = -ENOMEM;		goto err_out_free_ent;	}	base = (unsigned long) mmio_base;	hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);	if (!hpriv) {		rc = -ENOMEM;		goto err_out_iounmap;	}	memset(hpriv, 0, sizeof(*hpriv));	dimm_mmio = ioremap(pci_resource_start(pdev, 4),			    pci_resource_len(pdev, 4));	if (!dimm_mmio) {		kfree(hpriv);		rc = -ENOMEM;		goto err_out_iounmap;	}	hpriv->dimm_mmio = dimm_mmio;	probe_ent->sht		= pdc_port_info[board_idx].sht;	probe_ent->host_flags	= pdc_port_info[board_idx].host_flags;	probe_ent->pio_mask	= pdc_port_info[board_idx].pio_mask;	probe_ent->mwdma_mask	= pdc_port_info[board_idx].mwdma_mask;	probe_ent->udma_mask	= pdc_port_info[board_idx].udma_mask;	probe_ent->port_ops	= pdc_port_info[board_idx].port_ops;       	probe_ent->irq = pdev->irq;       	probe_ent->irq_flags = SA_SHIRQ;	probe_ent->mmio_base = mmio_base;	probe_ent->private_data = hpriv;	base += PDC_CHIP0_OFS;	probe_ent->n_ports = 4;	pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);	pdc_sata_setup_port(&probe_ent->port[1], base + 0x280);	pdc_sata_setup_port(&probe_ent->port[2], base + 0x300);	pdc_sata_setup_port(&probe_ent->port[3], base + 0x380);	pci_set_master(pdev);	/* initialize adapter */	/* initialize local dimm */	if (pdc20621_dimm_init(probe_ent)) {		rc = -ENOMEM;		goto err_out_iounmap_dimm;	}	pdc_20621_init(probe_ent);	/* FIXME: check ata_device_add return value */	ata_device_add(probe_ent);	kfree(probe_ent);	return 0;err_out_iounmap_dimm:		/* only get to this label if 20621 */	kfree(hpriv);	iounmap(dimm_mmio);err_out_iounmap:	iounmap(mmio_base);err_out_free_ent:	kfree(probe_ent);err_out_regions:	pci_release_regions(pdev);err_out:	pci_disable_device(pdev);	return rc;}static int __init pdc_sata_init(void){	return pci_module_init(&pdc_sata_pci_driver);}static void __exit pdc_sata_exit(void){	pci_unregister_driver(&pdc_sata_pci_driver);}MODULE_AUTHOR("Jeff Garzik");MODULE_DESCRIPTION("Promise SATA low-level driver");MODULE_LICENSE("GPL");MODULE_DEVICE_TABLE(pci, pdc_sata_pci_tbl);module_init(pdc_sata_init);module_exit(pdc_sata_exit);

⌨️ 快捷键说明

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