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

📄 sata_sil3114.c

📁 uboot详细解读可用启动引导LINUX2.6内核
💻 C
📖 第 1 页 / 共 2 页
字号:
		}		udelay (1000);		max--;	} while ((status & bits) && (max > 0));	return status;}static u8 sata_chk_status (struct sata_ioports *ioaddr, u8 usealtstatus){	if (!usealtstatus) {		return readb (ioaddr->status_addr);	} else {		return readb (ioaddr->altstatus_addr);	}}static void msleep (int count){	int i;	for (i = 0; i < count; i++)		udelay (1000);}/* Read up to 255 sectors * * Returns sectors read*/static u8 do_one_read (int device, ulong block, u8 blkcnt, u16 * buff,		       uchar lba48){	u8 sr = 0;	u8 status;	u64 blknr = (u64) block;	if (!(sata_chk_status (&port[device].ioaddr, 0) & ATA_DRDY)) {		printf ("Device ata%d not ready\n", device);		return 0;	}	/* Set up transfer */#ifdef CONFIG_LBA48	if (lba48) {		/* write high bits */		writeb (0, port[device].ioaddr.nsect_addr);		writeb ((blknr >> 24) & 0xFF, port[device].ioaddr.lbal_addr);		writeb ((blknr >> 32) & 0xFF, port[device].ioaddr.lbam_addr);		writeb ((blknr >> 40) & 0xFF, port[device].ioaddr.lbah_addr);	}#endif	writeb (blkcnt, port[device].ioaddr.nsect_addr);	writeb (((blknr) >> 0) & 0xFF, port[device].ioaddr.lbal_addr);	writeb ((blknr >> 8) & 0xFF, port[device].ioaddr.lbam_addr);	writeb ((blknr >> 16) & 0xFF, port[device].ioaddr.lbah_addr);#ifdef CONFIG_LBA48	if (lba48) {		writeb (ATA_LBA, port[device].ioaddr.device_addr);		writeb (ATA_CMD_PIO_READ_EXT, port[device].ioaddr.command_addr);	} else#endif	{		writeb (ATA_LBA | ((blknr >> 24) & 0xF),			port[device].ioaddr.device_addr);		writeb (ATA_CMD_PIO_READ, port[device].ioaddr.command_addr);	}	status = sata_busy_wait (&port[device].ioaddr, ATA_BUSY, 10000, 1);	if (status & ATA_BUSY) {		u8 err = 0;		printf ("Device %d not responding status %d\n", device, status);		err = readb (port[device].ioaddr.error_addr);		printf ("Error reg = 0x%x\n", err);		return (sr);	}	while (blkcnt--) {		if (wait_for_irq (device, 500)) {			printf ("ata%u irq failed\n", device);			return sr;		}		status = sata_chk_status (&port[device].ioaddr, 0);		if (status & ATA_ERR) {			printf ("ata%u error %d\n", device,				readb (port[device].ioaddr.error_addr));			return sr;		}		/* Read one sector */		input_data (&port[device].ioaddr, buff, ATA_SECTOR_WORDS);		buff += ATA_SECTOR_WORDS;		sr++;	}	return sr;}ulong sata_read (int device, ulong block, lbaint_t blkcnt, void *buff){	ulong n = 0, sread;	u16 *buffer = (u16 *) buff;	u8 status = 0;	u64 blknr = (u64) block;	unsigned char lba48 = 0;#ifdef CONFIG_LBA48	if (blknr > 0xfffffff) {		if (!sata_dev_desc[device].lba48) {			printf ("Drive doesn't support 48-bit addressing\n");			return 0;		}		/* more than 28 bits used, use 48bit mode */		lba48 = 1;	}#endif	while (blkcnt > 0) {		if (blkcnt > 255) {			sread = 255;		} else {			sread = blkcnt;		}		status = do_one_read (device, blknr, sread, buffer, lba48);		if (status != sread) {			printf ("Read failed\n");			return n;		}		blkcnt -= sread;		blknr += sread;		n += sread;		buffer += sread * ATA_SECTOR_WORDS;	}	return n;}ulong sata_write (int device, ulong block, lbaint_t blkcnt, const void *buff){	ulong n = 0;	u16 *buffer = (u16 *) buff;	unsigned char status = 0, num = 0;	u64 blknr = (u64) block;#ifdef CONFIG_LBA48	unsigned char lba48 = 0;	if (blknr > 0xfffffff) {		if (!sata_dev_desc[device].lba48) {			printf ("Drive doesn't support 48-bit addressing\n");			return 0;		}		/* more than 28 bits used, use 48bit mode */		lba48 = 1;	}#endif	/*Port Number */	num = device;	while (blkcnt-- > 0) {		status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500, 0);		if (status & ATA_BUSY) {			printf ("ata%u failed to respond\n", port[num].port_no);			return n;		}#ifdef CONFIG_LBA48		if (lba48) {			/* write high bits */			writeb (0, port[num].ioaddr.nsect_addr);			writeb ((blknr >> 24) & 0xFF,				port[num].ioaddr.lbal_addr);			writeb ((blknr >> 32) & 0xFF,				port[num].ioaddr.lbam_addr);			writeb ((blknr >> 40) & 0xFF,				port[num].ioaddr.lbah_addr);		}#endif		writeb (1, port[num].ioaddr.nsect_addr);		writeb ((blknr >> 0) & 0xFF, port[num].ioaddr.lbal_addr);		writeb ((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr);		writeb ((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr);#ifdef CONFIG_LBA48		if (lba48) {			writeb (ATA_LBA, port[num].ioaddr.device_addr);			writeb (ATA_CMD_PIO_WRITE_EXT, port[num].ioaddr.command_addr);		} else#endif		{			writeb (ATA_LBA | ((blknr >> 24) & 0xF),				port[num].ioaddr.device_addr);			writeb (ATA_CMD_PIO_WRITE, port[num].ioaddr.command_addr);		}		msleep (50);		/*may take up to 4 sec */		status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 4000, 0);		if ((status & (ATA_DRQ | ATA_BUSY | ATA_ERR)) != ATA_DRQ) {			printf ("Error no DRQ dev %d blk %ld: sts 0x%02x\n",				device, (ulong) blknr, status);			return (n);		}		output_data (&port[num].ioaddr, buffer, ATA_SECTOR_WORDS);		readb (port[num].ioaddr.altstatus_addr);		udelay (50);		++n;		++blknr;		buffer += ATA_SECTOR_WORDS;	}	return n;}/* Driver implementation */static u8 sil_get_device_cache_line (pci_dev_t pdev){	u8 cache_line = 0;	pci_read_config_byte (pdev, PCI_CACHE_LINE_SIZE, &cache_line);	return cache_line;}int init_sata (int dev){	static u8 init_done = 0;	static int res = 1;	pci_dev_t devno;	u8 cls = 0;	u16 cmd = 0;	u32 sconf = 0;	if (init_done) {		return res;	}	init_done = 1;	if ((devno = pci_find_device (SIL_VEND_ID, SIL3114_DEVICE_ID, 0)) == -1) {		res = 1;		return res;	}	/* Read out all BARs, even though we only use MMIO from BAR5 */	pci_read_config_dword (devno, PCI_BASE_ADDRESS_0, &iobase[0]);	pci_read_config_dword (devno, PCI_BASE_ADDRESS_1, &iobase[1]);	pci_read_config_dword (devno, PCI_BASE_ADDRESS_2, &iobase[2]);	pci_read_config_dword (devno, PCI_BASE_ADDRESS_3, &iobase[3]);	pci_read_config_dword (devno, PCI_BASE_ADDRESS_4, &iobase[4]);	pci_read_config_dword (devno, PCI_BASE_ADDRESS_5, &iobase[5]);	if ((iobase[0] == 0xFFFFFFFF) || (iobase[1] == 0xFFFFFFFF) ||	    (iobase[2] == 0xFFFFFFFF) || (iobase[3] == 0xFFFFFFFF) ||	    (iobase[4] == 0xFFFFFFFF) || (iobase[5] == 0xFFFFFFFF)) {		printf ("Error no base addr for SATA controller\n");		res = 1;		return res;	}	/* mask off unused bits */	iobase[0] &= 0xfffffffc;	iobase[1] &= 0xfffffff8;	iobase[2] &= 0xfffffffc;	iobase[3] &= 0xfffffff8;	iobase[4] &= 0xfffffff0;	iobase[5] &= 0xfffffc00;	/* from sata_sil in Linux kernel */	cls = sil_get_device_cache_line (devno);	if (cls) {		cls >>= 3;		cls++;		/* cls = (line_size/8)+1 */		writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH0);		writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH1);		writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH2);		writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH3);	} else {		printf ("Cache line not set. Driver may not function\n");	}	/* Enable operation */	pci_read_config_word (devno, PCI_COMMAND, &cmd);	cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;	pci_write_config_word (devno, PCI_COMMAND, cmd);	/* Disable interrupt usage */	pci_read_config_dword (devno, VND_SYSCONFSTAT, &sconf);	sconf |= (VND_SYSCONFSTAT_CHN_0_INTBLOCK | VND_SYSCONFSTAT_CHN_1_INTBLOCK);	pci_write_config_dword (devno, VND_SYSCONFSTAT, sconf);	res = 0;	return res;}/* Check if device is connected to port */int sata_bus_probe (int portno){	u32 port = iobase[5];	u32 val;	switch (portno) {	case 0:		port += VND_SSTATUS_CH0;		break;	case 1:		port += VND_SSTATUS_CH1;		break;	case 2:		port += VND_SSTATUS_CH2;		break;	case 3:		port += VND_SSTATUS_CH3;		break;	default:		return 0;	}	val = readl (port);	if ((val & SATA_DET_PRES) == SATA_DET_PRES) {		return 1;	} else {		return 0;	}}int sata_phy_reset (int portno){	u32 port = iobase[5];	u32 val;	switch (portno) {	case 0:		port += VND_SCONTROL_CH0;		break;	case 1:		port += VND_SCONTROL_CH1;		break;	case 2:		port += VND_SCONTROL_CH2;		break;	case 3:		port += VND_SCONTROL_CH3;		break;	default:		return 0;	}	val = readl (port);	writel (val | SATA_SC_DET_RST, port);	msleep (150);	writel (val & ~SATA_SC_DET_RST, port);	return 0;}int scan_sata (int dev){	/* A bit brain dead, but the code has a legacy */	switch (dev) {	case 0:		port[0].port_no = 0;		port[0].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH0;		port[0].ioaddr.altstatus_addr = port[0].ioaddr.ctl_addr =		    (iobase[5] + VND_TF2_CH0) | ATA_PCI_CTL_OFS;		port[0].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH0;		break;	case 1:		port[1].port_no = 0;		port[1].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH1;		port[1].ioaddr.altstatus_addr = port[1].ioaddr.ctl_addr =		    (iobase[5] + VND_TF2_CH1) | ATA_PCI_CTL_OFS;		port[1].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH1;		break;	case 2:		port[2].port_no = 0;		port[2].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH2;		port[2].ioaddr.altstatus_addr = port[2].ioaddr.ctl_addr =		    (iobase[5] + VND_TF2_CH2) | ATA_PCI_CTL_OFS;		port[2].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH2;		break;	case 3:		port[3].port_no = 0;		port[3].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH3;		port[3].ioaddr.altstatus_addr = port[3].ioaddr.ctl_addr =		    (iobase[5] + VND_TF2_CH3) | ATA_PCI_CTL_OFS;		port[3].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH3;		break;	default:		printf ("Tried to scan unknown port: ata%d\n", dev);		return 1;	}	/* Initialize other registers */	sata_port (&port[dev].ioaddr);	/* Check for attached device */	if (!sata_bus_probe (dev)) {		port[dev].port_state = 0;		debug ("SATA#%d port is not present\n", dev);	} else {		debug ("SATA#%d port is present\n", dev);		if (sata_bus_softreset (dev)) {			/* soft reset failed, try a hard one */			sata_phy_reset (dev);			if (sata_bus_softreset (dev)) {				port[dev].port_state = 0;			} else {				port[dev].port_state = 1;			}		} else {			port[dev].port_state = 1;		}	}	if (port[dev].port_state == 1) {		/* Probe device and set xfer mode */		sata_identify (dev, 0);		set_Feature_cmd (dev, 0);	}	return 0;}

⌨️ 快捷键说明

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