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

📄 fsl_sata.c

📁 uboot详细解读可用启动引导LINUX2.6内核
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 2008 Freescale Semiconductor, Inc. *		Dave Liu <daveliu@freescale.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 */#include <common.h>#include <command.h>#include <asm/io.h>#include <malloc.h>#include <libata.h>#include <fis.h>#include "fsl_sata.h"extern block_dev_desc_t sata_dev_desc[CFG_SATA_MAX_DEVICE];#ifndef CFG_SATA1_FLAGS	#define CFG_SATA1_FLAGS	FLAGS_DMA#endif#ifndef CFG_SATA2_FLAGS	#define CFG_SATA2_FLAGS	FLAGS_DMA#endifstatic struct fsl_sata_info fsl_sata_info[] = {#ifdef CONFIG_SATA1	{CFG_SATA1, CFG_SATA1_FLAGS},#else	{0, 0},#endif#ifdef CONFIG_SATA2	{CFG_SATA2, CFG_SATA2_FLAGS},#else	{0, 0},#endif};static inline void mdelay(unsigned long msec){	unsigned long i;	for (i = 0; i < msec; i++)		udelay(1000);}static inline void sdelay(unsigned long sec){	unsigned long i;	for (i = 0; i < sec; i++)		mdelay(1000);}void dprint_buffer(unsigned char *buf, int len){	int i, j;	i = 0;	j = 0;	printf("\n\r");	for (i = 0; i < len; i++) {		printf("%02x ", *buf++);		j++;		if (j == 16) {			printf("\n\r");			j = 0;		}	}	printf("\n\r");}static void fsl_sata_dump_sfis(struct sfis *s){	printf("Status FIS dump:\n\r");	printf("fis_type:		%02x\n\r", s->fis_type);	printf("pm_port_i:		%02x\n\r", s->pm_port_i);	printf("status:			%02x\n\r", s->status);	printf("error:			%02x\n\r", s->error);	printf("lba_low:		%02x\n\r", s->lba_low);	printf("lba_mid:		%02x\n\r", s->lba_mid);	printf("lba_high:		%02x\n\r", s->lba_high);	printf("device:			%02x\n\r", s->device);	printf("lba_low_exp:		%02x\n\r", s->lba_low_exp);	printf("lba_mid_exp:		%02x\n\r", s->lba_mid_exp);	printf("lba_high_exp:		%02x\n\r", s->lba_high_exp);	printf("res1:			%02x\n\r", s->res1);	printf("sector_count:		%02x\n\r", s->sector_count);	printf("sector_count_exp:	%02x\n\r", s->sector_count_exp);}static int ata_wait_register(volatile unsigned *addr, u32 mask,			 u32 val, u32 timeout_msec){	int i;	u32 temp;	for (i = 0; (((temp = in_le32(addr)) & mask) != val)			 && i < timeout_msec; i++)		mdelay(1);	return (i < timeout_msec) ? 0 : -1;}int init_sata(int dev){	u32 length, align;	cmd_hdr_tbl_t *cmd_hdr;	u32 cda;	u32 val32;	fsl_sata_reg_t *reg;	u32 sig;	int i;	fsl_sata_t *sata;	if (dev < 0 || dev > (CFG_SATA_MAX_DEVICE - 1)) {		printf("the sata index %d is out of ranges\n\r", dev);		return -1;	}	/* Allocate SATA device driver struct */	sata = (fsl_sata_t *)malloc(sizeof(fsl_sata_t));	if (!sata) {		printf("alloc the sata device struct failed\n\r");		return -1;	}	/* Zero all of the device driver struct */	memset((void *)sata, 0, sizeof(fsl_sata_t));	/* Save the private struct to block device struct */	sata_dev_desc[dev].priv = (void *)sata;	sprintf(sata->name, "SATA%d", dev);	/* Set the controller register base address to device struct */	reg = (fsl_sata_reg_t *)(fsl_sata_info[dev].sata_reg_base);	sata->reg_base = reg;	/* Allocate the command header table, 4 bytes aligned */	length = sizeof(struct cmd_hdr_tbl);	align = SATA_HC_CMD_HDR_TBL_ALIGN;	sata->cmd_hdr_tbl_offset = (void *)malloc(length + align);	if (!sata) {		printf("alloc the command header failed\n\r");		return -1;	}	cmd_hdr = (cmd_hdr_tbl_t *)(((u32)sata->cmd_hdr_tbl_offset + align)						& ~(align - 1));	sata->cmd_hdr = cmd_hdr;	/* Zero all of the command header table */	memset((void *)sata->cmd_hdr_tbl_offset, 0, length + align);	/* Allocate command descriptor for all command */	length = sizeof(struct cmd_desc) * SATA_HC_MAX_CMD;	align = SATA_HC_CMD_DESC_ALIGN;	sata->cmd_desc_offset = (void *)malloc(length + align);	if (!sata->cmd_desc_offset) {		printf("alloc the command descriptor failed\n\r");		return -1;	}	sata->cmd_desc = (cmd_desc_t *)(((u32)sata->cmd_desc_offset + align)						& ~(align - 1));	/* Zero all of command descriptor */	memset((void *)sata->cmd_desc_offset, 0, length + align);	/* Link the command descriptor to command header */	for (i = 0; i < SATA_HC_MAX_CMD; i++) {		cda = ((u32)sata->cmd_desc + SATA_HC_CMD_DESC_SIZE * i)					 & ~(CMD_HDR_CDA_ALIGN - 1);		cmd_hdr->cmd_slot[i].cda = cpu_to_le32(cda);	}	/* To have safe state, force the controller offline */	val32 = in_le32(&reg->hcontrol);	val32 &= ~HCONTROL_ONOFF;	val32 |= HCONTROL_FORCE_OFFLINE;	out_le32(&reg->hcontrol, val32);	/* Wait the controller offline */	ata_wait_register(&reg->hstatus, HSTATUS_ONOFF, 0, 1000);	/* Set the command header base address to CHBA register to tell DMA */	out_le32(&reg->chba, (u32)cmd_hdr & ~0x3);	/* Snoop for the command header */	val32 = in_le32(&reg->hcontrol);	val32 |= HCONTROL_HDR_SNOOP;	out_le32(&reg->hcontrol, val32);	/* Disable all of interrupts */	val32 = in_le32(&reg->hcontrol);	val32 &= ~HCONTROL_INT_EN_ALL;	out_le32(&reg->hcontrol, val32);	/* Clear all of interrupts */	val32 = in_le32(&reg->hstatus);	out_le32(&reg->hstatus, val32);	/* Set the ICC, no interrupt coalescing */	out_le32(&reg->icc, 0x01000000);	/* No PM attatched, the SATA device direct connect */	out_le32(&reg->cqpmp, 0);	/* Clear SError register */	val32 = in_le32(&reg->serror);	out_le32(&reg->serror, val32);	/* Clear CER register */	val32 = in_le32(&reg->cer);	out_le32(&reg->cer, val32);	/* Clear DER register */	val32 = in_le32(&reg->der);	out_le32(&reg->der, val32);	/* No device detection or initialization action requested */	out_le32(&reg->scontrol, 0x00000300);	/* Configure the transport layer, default value */	out_le32(&reg->transcfg, 0x08000016);	/* Configure the link layer, default value */	out_le32(&reg->linkcfg, 0x0000ff34);	/* Bring the controller online */	val32 = in_le32(&reg->hcontrol);	val32 |= HCONTROL_ONOFF;	out_le32(&reg->hcontrol, val32);	mdelay(100);	/* print sata device name */	if (!dev)		printf("%s ", sata->name);	else		printf("       %s ", sata->name);	/* Wait PHY RDY signal changed for 500ms */	ata_wait_register(&reg->hstatus, HSTATUS_PHY_RDY,			  HSTATUS_PHY_RDY, 500);	/* Check PHYRDY */	val32 = in_le32(&reg->hstatus);	if (val32 & HSTATUS_PHY_RDY) {		sata->link = 1;	} else {		sata->link = 0;		printf("(No RDY)\n\r");		return -1;	}	/* Wait for signature updated, which is 1st D2H */	ata_wait_register(&reg->hstatus, HSTATUS_SIGNATURE,			  HSTATUS_SIGNATURE, 10000);	if (val32 & HSTATUS_SIGNATURE) {		sig = in_le32(&reg->sig);		debug("Signature updated, the sig =%08x\n\r", sig);		sata->ata_device_type = ata_dev_classify(sig);	}	/* Check the speed */	val32 = in_le32(&reg->sstatus);	if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN1)		printf("(1.5 Gbps)\n\r");	else if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN2)		printf("(3 Gbps)\n\r");	return 0;}/* Hardware reset, like Power-on and COMRESET */void fsl_sata_hardware_reset(u32 reg_base){	fsl_sata_reg_t *reg = (fsl_sata_reg_t *)reg_base;	u32 scontrol;	/* Disable the SATA interface and put PHY offline */	scontrol = in_le32(&reg->scontrol);	scontrol = (scontrol & 0x0f0) | 0x304;	out_le32(&reg->scontrol, scontrol);	/* No speed strict */	scontrol = in_le32(&reg->scontrol);	scontrol = scontrol & ~0x0f0;	out_le32(&reg->scontrol, scontrol);	/* Issue PHY wake/reset, Hardware_reset_asserted */	scontrol = in_le32(&reg->scontrol);	scontrol = (scontrol & 0x0f0) | 0x301;	out_le32(&reg->scontrol, scontrol);	mdelay(100);	/* Resume PHY, COMRESET negated, the device initialize hardware	 * and execute diagnostics, send good status-signature to host,	 * which is D2H register FIS, and then the device enter idle state.	 */	scontrol = in_le32(&reg->scontrol);	scontrol = (scontrol & 0x0f0) | 0x300;	out_le32(&reg->scontrol, scontrol);	mdelay(100);	return;}static void fsl_sata_dump_regs(fsl_sata_reg_t *reg){	printf("\n\rSATA:           %08x\n\r", (u32)reg);	printf("CQR:            %08x\n\r", in_le32(&reg->cqr));	printf("CAR:            %08x\n\r", in_le32(&reg->car));	printf("CCR:            %08x\n\r", in_le32(&reg->ccr));	printf("CER:            %08x\n\r", in_le32(&reg->cer));	printf("CQR:            %08x\n\r", in_le32(&reg->cqr));	printf("DER:            %08x\n\r", in_le32(&reg->der));	printf("CHBA:           %08x\n\r", in_le32(&reg->chba));	printf("HStatus:        %08x\n\r", in_le32(&reg->hstatus));	printf("HControl:       %08x\n\r", in_le32(&reg->hcontrol));	printf("CQPMP:          %08x\n\r", in_le32(&reg->cqpmp));	printf("SIG:            %08x\n\r", in_le32(&reg->sig));	printf("ICC:            %08x\n\r", in_le32(&reg->icc));	printf("SStatus:        %08x\n\r", in_le32(&reg->sstatus));	printf("SError:         %08x\n\r", in_le32(&reg->serror));	printf("SControl:       %08x\n\r", in_le32(&reg->scontrol));	printf("SNotification:  %08x\n\r", in_le32(&reg->snotification));	printf("TransCfg:       %08x\n\r", in_le32(&reg->transcfg));	printf("TransStatus:    %08x\n\r", in_le32(&reg->transstatus));	printf("LinkCfg:        %08x\n\r", in_le32(&reg->linkcfg));	printf("LinkCfg1:       %08x\n\r", in_le32(&reg->linkcfg1));	printf("LinkCfg2:       %08x\n\r", in_le32(&reg->linkcfg2));	printf("LinkStatus:     %08x\n\r", in_le32(&reg->linkstatus));	printf("LinkStatus1:    %08x\n\r", in_le32(&reg->linkstatus1));	printf("PhyCtrlCfg:     %08x\n\r", in_le32(&reg->phyctrlcfg));	printf("SYSPR:          %08x\n\r", in_be32(&reg->syspr));}static int fsl_ata_exec_ata_cmd(struct fsl_sata *sata, struct cfis *cfis,				int is_ncq, int tag, u8 *buffer, u32 len){	cmd_hdr_entry_t *cmd_hdr;	cmd_desc_t *cmd_desc;	sata_fis_h2d_t *h2d;	prd_entry_t *prde;	u32 ext_c_ddc;	u32 prde_count;	u32 val32;	u32 ttl;	fsl_sata_reg_t *reg = sata->reg_base;	int i;	/* Check xfer length */	if (len > SATA_HC_MAX_XFER_LEN) {		printf("max transfer length is 64MB\n\r");		return 0;	}	/* Setup the command descriptor */	cmd_desc = sata->cmd_desc + tag;	/* Get the pointer cfis of command descriptor */	h2d = (sata_fis_h2d_t *)cmd_desc->cfis;	/* Zero the cfis of command descriptor */	memset((void *)h2d, 0, SATA_HC_CMD_DESC_CFIS_SIZE);	/* Copy the cfis from user to command descriptor */	h2d->fis_type = cfis->fis_type;	h2d->pm_port_c = cfis->pm_port_c;	h2d->command = cfis->command;	h2d->features = cfis->features;	h2d->features_exp = cfis->features_exp;	h2d->lba_low = cfis->lba_low;	h2d->lba_mid = cfis->lba_mid;	h2d->lba_high = cfis->lba_high;	h2d->lba_low_exp = cfis->lba_low_exp;	h2d->lba_mid_exp = cfis->lba_mid_exp;	h2d->lba_high_exp = cfis->lba_high_exp;	if (!is_ncq) {		h2d->sector_count = cfis->sector_count;		h2d->sector_count_exp = cfis->sector_count_exp;	} else { /* NCQ */		h2d->sector_count = (u8)(tag << 3);	}	h2d->device = cfis->device;	h2d->control = cfis->control;	/* Setup the PRD table */	prde = (prd_entry_t *)cmd_desc->prdt;	memset((void *)prde, 0, sizeof(struct prdt));	prde_count = 0;	ttl = len;	for (i = 0; i < SATA_HC_MAX_PRD_DIRECT; i++) {		if (!len)			break;		prde->dba = cpu_to_le32((u32)buffer & ~0x3);		debug("dba = %08x\n\r", (u32)buffer);		if (len < PRD_ENTRY_MAX_XFER_SZ) {			ext_c_ddc = PRD_ENTRY_DATA_SNOOP | len;			debug("ext_c_ddc1 = %08x, len = %08x\n\r", ext_c_ddc, len);			prde->ext_c_ddc = cpu_to_le32(ext_c_ddc);			prde_count++;			prde++;			break;		} else {			ext_c_ddc = PRD_ENTRY_DATA_SNOOP; /* 4M bytes */			debug("ext_c_ddc2 = %08x, len = %08x\n\r", ext_c_ddc, len);			prde->ext_c_ddc = cpu_to_le32(ext_c_ddc);			buffer += PRD_ENTRY_MAX_XFER_SZ;			len -= PRD_ENTRY_MAX_XFER_SZ;			prde_count++;			prde++;		}	}	/* Setup the command slot of cmd hdr */	cmd_hdr = (cmd_hdr_entry_t *)&sata->cmd_hdr->cmd_slot[tag];	cmd_hdr->cda = cpu_to_le32((u32)cmd_desc & ~0x3);	val32 = prde_count << CMD_HDR_PRD_ENTRY_SHIFT;	val32 |= sizeof(sata_fis_h2d_t);	cmd_hdr->prde_fis_len = cpu_to_le32(val32);	cmd_hdr->ttl = cpu_to_le32(ttl);	if (!is_ncq) {		val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP;	} else {		val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP | CMD_HDR_ATTR_FPDMA;	}	tag &= CMD_HDR_ATTR_TAG;	val32 |= tag;	debug("attribute = %08x\n\r", val32);	cmd_hdr->attribute = cpu_to_le32(val32);	/* Make sure cmd desc and cmd slot valid before commmand issue */	sync();	/* PMP*/	val32 = (u32)(h2d->pm_port_c & 0x0f);	out_le32(&reg->cqpmp, val32);

⌨️ 快捷键说明

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