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

📄 sata_sx4.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		readl(mmio + PDC_DIMM_WINDOW_CTLR);		memcpy_fromio((char *) psource, (char *) (dimm_mmio),			      window_size / 4);		psource += window_size;		size -= window_size;		idx++;	}	if (size) {		writel(0x01, mmio + PDC_GENERAL_CTLR);		readl(mmio + PDC_GENERAL_CTLR);		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);		readl(mmio + PDC_DIMM_WINDOW_CTLR);		memcpy_fromio((char *) psource, (char *) (dimm_mmio),			      size / 4);	}}#endifstatic void pdc20621_put_to_dimm(struct ata_host *host, void *psource,				 u32 offset, u32 size){	u32 window_size;	u16 idx;	u8 page_mask;	long dist;	void __iomem *mmio = host->iomap[PDC_MMIO_BAR];	void __iomem *dimm_mmio = host->iomap[PDC_DIMM_BAR];	/* hard-code chip #0 */	mmio += PDC_CHIP0_OFS;	page_mask = 0x00;	window_size = 0x2000 * 4;       /* 32K byte uchar size */	idx = (u16) (offset / window_size);	writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);	readl(mmio + PDC_DIMM_WINDOW_CTLR);	offset -= (idx * window_size);	idx++;	dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size :		(long) (window_size - offset);	memcpy_toio(dimm_mmio + offset / 4, 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(dimm_mmio, 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(dimm_mmio, psource, size / 4);		writel(0x01, mmio + PDC_GENERAL_CTLR);		readl(mmio + PDC_GENERAL_CTLR);	}}static unsigned int pdc20621_i2c_read(struct ata_host *host, u32 device,				      u32 subaddr, u32 *pdata){	void __iomem *mmio = host->iomap[PDC_MMIO_BAR];	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);	readl(mmio + PDC_I2C_ADDR_DATA);	/* Write Control to perform read operation, mask int */	writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT,	       mmio + PDC_I2C_CONTROL);	for (count = 0; count <= 1000; count ++) {		status = readl(mmio + PDC_I2C_CONTROL);		if (status & PDC_I2C_COMPLETE) {			status = readl(mmio + PDC_I2C_ADDR_DATA);			break;		} else if (count == 1000)			return 0;	}	*pdata = (status >> 8) & 0x000000ff;	return 1;}static int pdc20621_detect_dimm(struct ata_host *host){	u32 data = 0;	if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,			     PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {		if (data == 100)			return 100;	} else		return 0;	if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {		if (data <= 0x75)			return 133;	} else		return 0;	return 0;}static int pdc20621_prog_dimm0(struct ata_host *host){	u32 spd0[50];	u32 data = 0;	int size, i;	u8 bdimmsize;	void __iomem *mmio = host->iomap[PDC_MMIO_BAR];	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(host, 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);	readl(mmio + PDC_DIMM0_CONTROL);	return size;}static unsigned int pdc20621_prog_dimm_global(struct ata_host *host){	u32 data, spd0;	int error, i;	void __iomem *mmio = host->iomap[PDC_MMIO_BAR];	/* 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);	readl(mmio + PDC_SDRAM_CONTROL);	/* Turn on for ECC */	pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,			  PDC_DIMM_SPD_TYPE, &spd0);	if (spd0 == 0x02) {		data |= (0x01 << 16);		writel(data, mmio + PDC_SDRAM_CONTROL);		readl(mmio + PDC_SDRAM_CONTROL);		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);	error = 1;	for (i = 1; i <= 10; i++) {   /* polling ~5 secs */		data = readl(mmio + PDC_SDRAM_CONTROL);		if (!(data & (1<<19))) {			error = 0;			break;		}		msleep(i*100);	}	return error;}static unsigned int pdc20621_dimm_init(struct ata_host *host){	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 __iomem *mmio = host->iomap[PDC_MMIO_BAR];	/* 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(PDC_TIMER_DEFAULT, mmio + PDC_TIME_CONTROL);	readl(mmio + PDC_TIME_CONTROL);	/* Wait 3 seconds */	msleep(3000);	/*	   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(host))) {		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(host);	VPRINTK("Local DIMM Size = %dMB\n", size);	/* Programming DIMM Module Global Control Register (index_CID0:88h) */	if (pdc20621_prog_dimm_global(host)) {		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(host, test_parttern2, 0x10040, 40);		pdc20621_put_to_dimm(host, test_parttern2, 0x40, 40);		pdc20621_put_to_dimm(host, test_parttern1, 0x10040, 40);		pdc20621_get_from_dimm(host, test_parttern2, 0x40, 40);		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],		       test_parttern2[1], &(test_parttern2[2]));		pdc20621_get_from_dimm(host, test_parttern2, 0x10040,				       40);		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],		       test_parttern2[1], &(test_parttern2[2]));		pdc20621_put_to_dimm(host, test_parttern1, 0x40, 40);		pdc20621_get_from_dimm(host, 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(host, 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(host, (void *) &tmp, addr,					     sizeof(u32));			addr += sizeof(u32);		}		VPRINTK("Finish ECC initialization\n");	}	return 0;}static void pdc_20621_init(struct ata_host *host){	u32 tmp;	void __iomem *mmio = host->iomap[PDC_MMIO_BAR];	/* 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;	const struct ata_port_info *ppi[] =		{ &pdc_port_info[ent->driver_data], NULL };	struct ata_host *host;	struct pdc_host_priv *hpriv;	int i, rc;	if (!printed_version++)		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");	/* allocate host */	host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4);	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);	if (!host || !hpriv)		return -ENOMEM;	host->private_data = hpriv;	/* acquire resources and fill host */	rc = pcim_enable_device(pdev);	if (rc)		return rc;	rc = pcim_iomap_regions(pdev, (1 << PDC_MMIO_BAR) | (1 << PDC_DIMM_BAR),				DRV_NAME);	if (rc == -EBUSY)		pcim_pin_device(pdev);	if (rc)		return rc;	host->iomap = pcim_iomap_table(pdev);	for (i = 0; i < 4; i++) {		struct ata_port *ap = host->ports[i];		void __iomem *base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;		unsigned int offset = 0x200 + i * 0x80;		pdc_sata_setup_port(&ap->ioaddr, base + offset);		ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");		ata_port_pbar_desc(ap, PDC_DIMM_BAR, -1, "dimm");		ata_port_pbar_desc(ap, PDC_MMIO_BAR, offset, "port");	}	/* configure and activate */	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;	if (pdc20621_dimm_init(host))		return -ENOMEM;	pdc_20621_init(host);	pci_set_master(pdev);	return ata_host_activate(host, pdev->irq, pdc20621_interrupt,				 IRQF_SHARED, &pdc_sata_sht);}static int __init pdc_sata_init(void){	return pci_register_driver(&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_VERSION(DRV_VERSION);module_init(pdc_sata_init);module_exit(pdc_sata_exit);

⌨️ 快捷键说明

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