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

📄 sata_sil3114.c

📁 uboot详细解读可用启动引导LINUX2.6内核
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) Excito Elektronik i Sk錸e AB, All rights reserved. * Author: Tor Krill <tor@excito.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * This is a driver for Silicon Image sil3114 sata chip modelled on * the ata_piix driver */#include <common.h>#include <pci.h>#include <command.h>#include <config.h>#include <asm/byteorder.h>#include <asm/io.h>#include <ide.h>#include <libata.h>#include "sata_sil3114.h"/* Convert sectorsize to wordsize */#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2)/* Forwards */u8 sil3114_spin_up (int num);u8 sil3114_spin_down (int num);static int sata_bus_softreset (int num);static void sata_identify (int num, int dev);static u8 check_power_mode (int num);static void sata_port (struct sata_ioports *ioport);static void set_Feature_cmd (int num, int dev);static u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits,			  unsigned int max, u8 usealtstatus);static u8 sata_chk_status (struct sata_ioports *ioaddr, u8 usealtstatus);static void msleep (int count);static u32 iobase[6] = { 0, 0, 0, 0, 0, 0};	/* PCI BAR registers for device */extern block_dev_desc_t sata_dev_desc[CFG_SATA_MAX_DEVICE];static struct sata_port port[CFG_SATA_MAX_DEVICE];static void output_data (struct sata_ioports *ioaddr, u16 * sect_buf, int words){	while (words--) {		__raw_writew (*sect_buf++, (void *)ioaddr->data_addr);	}}static int input_data (struct sata_ioports *ioaddr, u16 * sect_buf, int words){	while (words--) {		*sect_buf++ = __raw_readw ((void *)ioaddr->data_addr);	}	return 0;}static int sata_bus_softreset (int num){	u8 status = 0;	port[num].dev_mask = 1;	port[num].ctl_reg = 0x08;	/*Default value of control reg */	writeb (port[num].ctl_reg, port[num].ioaddr.ctl_addr);	udelay (10);	writeb (port[num].ctl_reg | ATA_SRST, port[num].ioaddr.ctl_addr);	udelay (10);	writeb (port[num].ctl_reg, port[num].ioaddr.ctl_addr);	/* spec mandates ">= 2ms" before checking status.	 * We wait 150ms, because that was the magic delay used for	 * ATAPI devices in Hale Landis's ATADRVR, for the period of time	 * between when the ATA command register is written, and then	 * status is checked.  Because waiting for "a while" before	 * checking status is fine, post SRST, we perform this magic	 * delay here as well.	 */	msleep (150);	status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 300, 0);	while ((status & ATA_BUSY)) {		msleep (100);		status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 3, 0);	}	if (status & ATA_BUSY) {		printf ("ata%u is slow to respond,plz be patient\n", port);	}	while ((status & ATA_BUSY)) {		msleep (100);		status = sata_chk_status (&port[num].ioaddr, 0);	}	if (status & ATA_BUSY) {		printf ("ata%u failed to respond : ", port);		printf ("bus reset failed\n");		port[num].dev_mask = 0;		return 1;	}	return 0;}static void sata_identify (int num, int dev){	u8 cmd = 0, status = 0, devno = num;	u16 iobuf[ATA_SECTOR_WORDS];	u64 n_sectors = 0;	memset (iobuf, 0, sizeof (iobuf));	if (!(port[num].dev_mask & 0x01)) {		printf ("dev%d is not present on port#%d\n", dev, num);		return;	}	debug ("port=%d dev=%d\n", num, dev);	status = 0;	cmd = ATA_CMD_ID_ATA;	/*Device Identify Command */	writeb (cmd, port[num].ioaddr.command_addr);	readb (port[num].ioaddr.altstatus_addr);	udelay (10);	status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 1000, 0);	if (status & ATA_ERR) {		printf ("\ndevice not responding\n");		port[num].dev_mask &= ~0x01;		return;	}	input_data (&port[num].ioaddr, iobuf, ATA_SECTOR_WORDS);	ata_swap_buf_le16 (iobuf, ATA_SECTOR_WORDS);	debug ("Specific config: %x\n", iobuf[2]);	/* we require LBA and DMA support (bits 8 & 9 of word 49) */	if (!ata_id_has_dma (iobuf) || !ata_id_has_lba (iobuf)) {		debug ("ata%u: no dma/lba\n", num);	}#ifdef DEBUG	ata_dump_id (iobuf);#endif	n_sectors = ata_id_n_sectors (iobuf);	if (n_sectors == 0) {		port[num].dev_mask &= ~0x01;		return;	}	ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].revision,			 ATA_ID_FW_REV, sizeof (sata_dev_desc[devno].revision));	ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].vendor,			 ATA_ID_PROD, sizeof (sata_dev_desc[devno].vendor));	ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].product,			 ATA_ID_SERNO, sizeof (sata_dev_desc[devno].product));	/* TODO - atm we asume harddisk ie not removable */	sata_dev_desc[devno].removable = 0;	sata_dev_desc[devno].lba = (u32) n_sectors;	debug ("lba=0x%x\n", sata_dev_desc[devno].lba);#ifdef CONFIG_LBA48	if (iobuf[83] & (1 << 10)) {		sata_dev_desc[devno].lba48 = 1;	} else {		sata_dev_desc[devno].lba48 = 0;	}#endif	/* assuming HD */	sata_dev_desc[devno].type = DEV_TYPE_HARDDISK;	sata_dev_desc[devno].blksz = ATA_SECT_SIZE;	sata_dev_desc[devno].lun = 0;	/* just to fill something in... */}static void set_Feature_cmd (int num, int dev){	u8 status = 0;	if (!(port[num].dev_mask & 0x01)) {		debug ("dev%d is not present on port#%d\n", dev, num);		return;	}	writeb (SETFEATURES_XFER, port[num].ioaddr.feature_addr);	writeb (XFER_PIO_4, port[num].ioaddr.nsect_addr);	writeb (0, port[num].ioaddr.lbal_addr);	writeb (0, port[num].ioaddr.lbam_addr);	writeb (0, port[num].ioaddr.lbah_addr);	writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr);	writeb (ATA_CMD_SET_FEATURES, port[num].ioaddr.command_addr);	udelay (50);	msleep (150);	status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000, 0);	if ((status & (ATA_BUSY | ATA_ERR))) {		printf ("Error  : status 0x%02x\n", status);		port[num].dev_mask &= ~0x01;	}}u8 sil3114_spin_down (int num){	u8 status = 0;	debug ("Spin down disk\n");	if (!(port[num].dev_mask & 0x01)) {		debug ("Device ata%d is not present\n", num);		return 1;	}	if ((status = check_power_mode (num)) == 0x00) {		debug ("Already in standby\n");		return 0;	}	if (status == 0x01) {		printf ("Failed to check power mode on ata%d\n", num);		return 1;	}	if (!((status = sata_chk_status (&port[num].ioaddr, 0)) & ATA_DRDY)) {		printf ("Device ata%d not ready\n", num);		return 1;	}	writeb (0x00, port[num].ioaddr.feature_addr);	writeb (0x00, port[num].ioaddr.nsect_addr);	writeb (0x00, port[num].ioaddr.lbal_addr);	writeb (0x00, port[num].ioaddr.lbam_addr);	writeb (0x00, port[num].ioaddr.lbah_addr);	writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr);	writeb (ATA_CMD_STANDBY, port[num].ioaddr.command_addr);	status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 30000, 0);	if ((status & (ATA_BUSY | ATA_ERR))) {		printf ("Error waiting for disk spin down: status 0x%02x\n",			status);		port[num].dev_mask &= ~0x01;		return 1;	}	return 0;}u8 sil3114_spin_up (int num){	u8 status = 0;	debug ("Spin up disk\n");	if (!(port[num].dev_mask & 0x01)) {		debug ("Device ata%d is not present\n", num);		return 1;	}	if ((status = check_power_mode (num)) != 0x00) {		if (status == 0x01) {			printf ("Failed to check power mode on ata%d\n", num);			return 1;		} else {			/* should be up and running already */			return 0;		}	}	if (!((status = sata_chk_status (&port[num].ioaddr, 0)) & ATA_DRDY)) {		printf ("Device ata%d not ready\n", num);		return 1;	}	debug ("Stautus of device check: %d\n", status);	writeb (0x00, port[num].ioaddr.feature_addr);	writeb (0x00, port[num].ioaddr.nsect_addr);	writeb (0x00, port[num].ioaddr.lbal_addr);	writeb (0x00, port[num].ioaddr.lbam_addr);	writeb (0x00, port[num].ioaddr.lbah_addr);	writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr);	writeb (ATA_CMD_IDLE, port[num].ioaddr.command_addr);	status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 30000, 0);	if ((status & (ATA_BUSY | ATA_ERR))) {		printf ("Error waiting for disk spin up: status 0x%02x\n",			status);		port[num].dev_mask &= ~0x01;		return 1;	}	/* Wait for disk to enter Active state */	do {		msleep (10);		status = check_power_mode (num);	} while ((status == 0x00) || (status == 0x80));	if (status == 0x01) {		printf ("Falied waiting for disk to spin up\n");		return 1;	}	return 0;}/* Return value is not the usual here * 0x00 - Device stand by * 0x01 - Operation failed * 0x80 - Device idle * 0xff - Device active*/static u8 check_power_mode (int num){	u8 status = 0;	u8 res = 0;	if (!(port[num].dev_mask & 0x01)) {		debug ("Device ata%d is not present\n", num);		return 1;	}	if (!(sata_chk_status (&port[num].ioaddr, 0) & ATA_DRDY)) {		printf ("Device ata%d not ready\n", num);		return 1;	}	writeb (0, port[num].ioaddr.feature_addr);	writeb (0, port[num].ioaddr.nsect_addr);	writeb (0, port[num].ioaddr.lbal_addr);	writeb (0, port[num].ioaddr.lbam_addr);	writeb (0, port[num].ioaddr.lbah_addr);	writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr);	writeb (ATA_CMD_CHK_POWER, port[num].ioaddr.command_addr);	status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000, 0);	if ((status & (ATA_BUSY | ATA_ERR))) {		printf		    ("Error waiting for check power mode complete  : status 0x%02x\n",		     status);		port[num].dev_mask &= ~0x01;		return 1;	}	res = readb (port[num].ioaddr.nsect_addr);	debug ("Check powermode: %d\n", res);	return res;}static void sata_port (struct sata_ioports *ioport){	ioport->data_addr = ioport->cmd_addr + ATA_REG_DATA;	ioport->error_addr = ioport->cmd_addr + ATA_REG_ERR;	ioport->feature_addr = ioport->cmd_addr + ATA_REG_FEATURE;	ioport->nsect_addr = ioport->cmd_addr + ATA_REG_NSECT;	ioport->lbal_addr = ioport->cmd_addr + ATA_REG_LBAL;	ioport->lbam_addr = ioport->cmd_addr + ATA_REG_LBAM;	ioport->lbah_addr = ioport->cmd_addr + ATA_REG_LBAH;	ioport->device_addr = ioport->cmd_addr + ATA_REG_DEVICE;	ioport->status_addr = ioport->cmd_addr + ATA_REG_STATUS;	ioport->command_addr = ioport->cmd_addr + ATA_REG_CMD;}static u8 wait_for_irq (int num, unsigned int max){	u32 port = iobase[5];	switch (num) {	case 0:		port += VND_TF_CNST_CH0;		break;	case 1:		port += VND_TF_CNST_CH1;		break;	case 2:		port += VND_TF_CNST_CH2;		break;	case 3:		port += VND_TF_CNST_CH3;		break;	default:		return 1;	}	do {		if (readl (port) & VND_TF_CNST_INTST) {			break;		}		udelay (1000);		max--;	} while ((max > 0));	return (max == 0);}static u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits,			  unsigned int max, u8 usealtstatus){	u8 status;	do {		if (!((status = sata_chk_status (ioaddr, usealtstatus)) & bits)) {			break;

⌨️ 快捷键说明

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