core_i2c.c

来自「6440linuxDriver的源代码」· C语言 代码 · 共 723 行 · 第 1/2 页

C
723 行
字号
#include "core_header.h"#ifdef SUPPORT_I2C#include "core_exp.h"#include "core_i2c.h"#ifdef SUPPORT_ERROR_HANDLINGextern void Core_ReqTimeout (MV_PVOID This, MV_PVOID temp);#endifMV_U8 Read_I2C_Register(PCore_Driver_Extension pCore, MV_U8 regIndex){	MV_U32	reg;	reg=0;	((PREG_I2C_SOFTWARE_CONTROL)&reg)->ADRS_PORT = regIndex;	((PREG_I2C_SOFTWARE_CONTROL)&reg)->READ_EN = 1;	MV_IO_WRITE_DWORD(pCore->Base_Address[MV_PCI_BAR2],I2C_SOFTWARE_CONTROL,reg);	reg=MV_IO_READ_DWORD(pCore->Base_Address[MV_PCI_BAR2],I2C_SOFTWARE_CONTROL);	return((MV_U8)((PREG_I2C_SOFTWARE_CONTROL)&reg)->DATA_PORT);}voidWrite_I2C_Register(PCore_Driver_Extension pCore, MV_U8 regIndex, MV_U8 regVal){	MV_U32	reg;	reg=0;	((PREG_I2C_SOFTWARE_CONTROL)&reg)->ADRS_PORT = regIndex;	((PREG_I2C_SOFTWARE_CONTROL)&reg)->DATA_PORT = regVal;	((PREG_I2C_SOFTWARE_CONTROL)&reg)->WRITE_EN = 1;	MV_IO_WRITE_DWORD(pCore->Base_Address[MV_PCI_BAR2],I2C_SOFTWARE_CONTROL,reg);	((PREG_I2C_SOFTWARE_CONTROL)&reg)->WRITE_EN = 0;	MV_IO_WRITE_DWORD(pCore->Base_Address[MV_PCI_BAR2],I2C_SOFTWARE_CONTROL,reg);	return;}MV_U8 I2C_FindCCR(MV_U32 LinkRate){	MV_U8 n, m, bestN = 0, bestM = 0;	MV_U32 expPortion, currentFreq, minDiff, currentDiff;	minDiff = 0xFFFFFFFF;/* f=sys_clock/((M+1)*2^(N+1)), sys_clock=OscFreq/10 */	for(n=0; n<8; n++)	{		expPortion = 1<<(n+1); /*2^(N+1)*/		for(m=0; m<16; m++)		{			currentFreq=I2C_SYS_CLOCK/((m+1)*expPortion);			currentDiff=(currentFreq<=LinkRate)?(LinkRate-currentFreq):0xFFFFFFFF; 			if(currentDiff<minDiff)			{				minDiff   = currentDiff;				bestN=n;				bestM=m;			}         }	}	return((bestM<<3) | bestN );}MV_BOOLEAN I2C_InterruptServiceRoutine(MV_PVOID This){	PCore_Driver_Extension pCore=(PCore_Driver_Extension)This;	void (*pCallBack)(MV_PVOID pExtension,MV_PVOID pContext);	MV_U8 I2cCtlReg,I2cStatusReg;	PDomain_I2cLink pI2cLink=&pCore->I2cLink;	MV_U8 *pBuffer;	MV_BOOLEAN bDoReset=MV_FALSE, bCompleted=MV_FALSE;	PMV_Request pReq;	MV_U32 reg;    if( pI2cLink->pI2cRequest==NULL ){		return MV_FALSE;			}	pReq=(PMV_Request)pI2cLink->pI2cRequest;	pBuffer=pReq->Data_Buffer;	pCallBack=(void (*)(MV_PVOID pExtension,MV_PVOID pContext))pReq->Completion;	if(pCallBack==NULL)		return MV_FALSE;	I2cCtlReg = Read_I2C_Register(pCore, MI2C_CONTROL);	if( (!((PREG_MI2C_CONTROL)&I2cCtlReg)->IEN) || (!((PREG_MI2C_CONTROL)&I2cCtlReg)->IFLG) )		return MV_FALSE;	I2cStatusReg = Read_I2C_Register(pCore, MI2C_STATUS);	//MV_PRINT("*   \n" );	//MV_PRINT("*   I2C I2cCtlReg = 0x%x \n", I2cCtlReg);	//MV_PRINT("*   I2C pI2cLink->I2C_State = 0x%x \n", pI2cLink->I2C_State );    //MV_PRINT("*   I2C I2cStatusReg = 0x%x \n", I2cStatusReg);	switch(pI2cLink->I2C_State)	{	case I2C_STATE_CMD:		switch(I2cStatusReg)		{		case MI2C_STATUS_START_TX:		case MI2C_STATUS_ADDR_W_TX_ACK:		case MI2C_STATUS_MDATA_TX_ACK:			if(pI2cLink->I2cXferCount < pI2cLink->I2cCmdFrameLen)			{				if(pI2cLink->I2cCmdHeader[1]==I2C_CT_H2D_SES)				{/* I2cCmdHeader = [6 bytes of cmd header]+[checksum] I2cCmdFrameLen = length of SES request page + 7*//*I2C_CT_H2D_SES: [6 bytes of cmd header]+[SES request page]+[checksum] */					if(pI2cLink->I2cXferCount<6)						Write_I2C_Register(pCore,MI2C_DATA,pI2cLink->I2cCmdHeader[pI2cLink->I2cXferCount]);					else if(pI2cLink->I2cXferCount==(pI2cLink->I2cCmdFrameLen-1))						Write_I2C_Register(pCore,MI2C_DATA,pI2cLink->I2cCmdHeader[6]); 					else						Write_I2C_Register(pCore,MI2C_DATA,pBuffer[pI2cLink->I2cXferCount-6]);				}				else					Write_I2C_Register(pCore,MI2C_DATA,pI2cLink->I2cCmdHeader[pI2cLink->I2cXferCount]);/*I2C_CT_D2H_SES: [6 bytes of cmd header]+[checksum] */				pI2cLink->I2cXferCount++;			}			else			{/* last byte transfered, generate a STOP signal */				((PREG_MI2C_CONTROL)&I2cCtlReg)->STP=1;/* move to next command phase, and reset the count for receiving */				pI2cLink->I2C_State=I2C_STATE_RESPONSE;				pI2cLink->I2cXferCount=0;			}			break;		default:/* error occurred */			if(pI2cLink->I2cXferCount)				((PREG_MI2C_CONTROL)&I2cCtlReg)->STP=1;			else				bDoReset=MV_TRUE;			/* done, post command */			//MV_PRINT("Command terminated.\n");			pI2cLink->I2C_State=I2C_STATE_ERROR;			pReq->Scsi_Status=REQ_STATUS_ERROR;			bCompleted=MV_TRUE;			break;		}		break;	case I2C_STATE_RESPONSE:		switch(I2cStatusReg)		{		case MI2C_STATUS_ADDR_W_TX_ACK:		case MI2C_STATUS_MDATA_TX_ACK:/* STOP sent */			break;		case MI2C_STATUS_SADDR_W_RX_ACK:		case MI2C_STATUS_SADDR_DATA_RX_ACK:			if(pI2cLink->I2cXferCount < pI2cLink->I2cRspFrameLen)			{/* for response, I2cCmdHeader = [6 bytes of cmd header]+[status]+[checksum] I2cRspFrameLen = length of SES request page + 8*//*I2C_CT_H2D_SES: [6 bytes of cmd header]+[status]+[checksum]*/				if(pI2cLink->I2cCmdHeader[1]==I2C_CT_H2D_SES)						pI2cLink->I2cCmdHeader[pI2cLink->I2cXferCount]=Read_I2C_Register(pCore, MI2C_DATA);				else				{/*I2C_CT_D2H_SES: [6 bytes of cmd header]+[status]+[SES response page]+[checksum] */					if(pI2cLink->I2cXferCount<7)						pI2cLink->I2cCmdHeader[pI2cLink->I2cXferCount]=Read_I2C_Register(pCore, MI2C_DATA);					else if(pI2cLink->I2cXferCount==(pI2cLink->I2cCmdFrameLen-1))						pI2cLink->I2cCmdHeader[7]=Read_I2C_Register(pCore, MI2C_DATA);					else						pBuffer[pI2cLink->I2cXferCount-7]=Read_I2C_Register(pCore, MI2C_DATA);				}				pI2cLink->I2cXferCount++;			}			else{				MV_PRINT("I2c Receiver buffer overflow, 0x%x\n",pI2cLink->I2cXferCount++);			}			break;		case MI2C_STATUS_STOP_RX:			/* done, post command */			//MV_PRINT("Command completed (MI2C_STATUS_STOP_RX).\n");			((PREG_MI2C_CONTROL)&I2cCtlReg)->STP=1;			pI2cLink->I2C_State=I2C_STATE_IDLE;			pReq->Scsi_Status=REQ_STATUS_SUCCESS;			bCompleted=MV_TRUE;			break;		default:/* error occurred */			bDoReset=MV_TRUE;			/* done, post command */			//MV_PRINT("Command terminated.\n");			pReq->Scsi_Status=REQ_STATUS_ERROR;			pI2cLink->I2C_State=I2C_STATE_ERROR;			bCompleted=MV_TRUE;			break;		}		break;	case I2C_STATE_IDLE:	case I2C_STATE_ERROR:	default:		bDoReset=MV_TRUE;		break;	}/* re-enable I2C : Write to MI2C_CONTROL Register */	((PREG_MI2C_CONTROL)&I2cCtlReg)->IFLG=0;	//MV_PRINT("*  I2cCtlReg Int serivce 0x%x\n", I2cCtlReg);	Write_I2C_Register(pCore, MI2C_CONTROL, I2cCtlReg);	if(bDoReset)	{		Write_I2C_Register(pCore,MI2C_SOFT_RESET,0);		Write_I2C_Register(pCore,MI2C_CLOCK_CONTROL,pI2cLink->I2C_Clock);	}	if(bCompleted)	{			//MV_PRINT("*   I2C interrupt completed\n" );			reg = MV_REG_READ_DWORD(pCore->Mmio_Base, COMMON_IRQ_MASK);			//MV_PRINT("*   IRQ status = 0x%x\n", reg );			reg &= ~INT_SLAVE_I2C;			//MV_PRINT("*   IRQ status (after) = 0x%x\n", reg );			MV_REG_WRITE_DWORD(pCore->Mmio_Base, COMMON_IRQ_MASK, reg);			pI2cLink->pI2cRequest=NULL;#if defined(SUPPORT_ERROR_HANDLING) && defined(_OS_WINDOWS)	        if ( pI2cLink->pI2cDevice->Outstanding_Req > 0 )	        {				pI2cLink->pI2cDevice->Outstanding_Req--;	        }			/* request for this device came back, so we cancel the timer */	        if( pI2cLink->pI2cDevice->Timer_ID != NO_CURRENT_TIMER )	        {		        Timer_CancelRequest( pCore, pI2cLink->pI2cDevice->Timer_ID );		        pI2cLink->pI2cDevice->Timer_ID = NO_CURRENT_TIMER;	        }		/* if there are more outstanding requests, we send a new timer */	        if ( pI2cLink->pI2cDevice->Outstanding_Req > 0 )	        {		        pI2cLink->pI2cDevice->Timer_ID = Timer_AddRequest( pCore, REQUEST_TIME_OUT, Core_ReqTimeout, pI2cLink->pI2cDevice, NULL );	        }#endif /* defined(SUPPORT_ERROR_HANDLING) && defined(_OS_WINDOWS) */			pCallBack(pCore, pReq);	}	return MV_TRUE;}voidI2C_SendI2cFrame(MV_PVOID This, PMV_Request pReq){	PCore_Driver_Extension pCore=(PCore_Driver_Extension)This;	PDomain_I2cLink pI2cLink=&pCore->I2cLink;	MV_U8 I2cCtlReg;	Write_I2C_Register(pCore,MI2C_DATA,pI2cLink->I2cCmdHeader[0]);	pI2cLink->I2cXferCount=0;	pI2cLink->I2C_State=I2C_STATE_CMD;	pI2cLink->pI2cRequest=pReq;	I2cCtlReg = Read_I2C_Register(pCore, MI2C_CONTROL);	((PREG_MI2C_CONTROL)&I2cCtlReg)->STA=1;	Write_I2C_Register(pCore, MI2C_CONTROL, I2cCtlReg);}MV_U8 I2C_SataChecksum(MV_U8* buffer, MV_U32 length, MV_U8 sumseed){	MV_U8	checksum;	MV_U32	index;    checksum=-sumseed;	/* Calculate the IPMB based checksum and return */	for(index = 0; index < length; index ++)	{		checksum += buffer[index];	}	/* Return type is a byte, a negative value is automatically adjusted */	return -checksum;}#define I2C_STD_INQUIRY_SIZE	36#ifndef _OS_BIOS	MV_U8 BASEATTR I2C_INQUIRY_DEVICE_DATA[I2C_STD_INQUIRY_SIZE] = {	0x0D, 0x00, 0x05, 0x02, I2C_STD_INQUIRY_SIZE-5, 0x00, 0x40, 0x00,	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,	0x20, 0x20, 0x20, 0x20 };#define I2C_VPD_PAGE0_SIZE		7MV_U8 BASEATTR I2C_INQUIRY_VPD_PAGE0_DATA[I2C_VPD_PAGE0_SIZE] = {	0x0D, 0x00, 0x00, 0x03, 0x00, 0x80, 0x83};/* VP PG80 Unit Serial Number, Header only */#define I2C_VPD_PAGE80_SIZE		4MV_U8 BASEATTR I2C_INQUIRY_VPD_PAGE80_DATA[I2C_VPD_PAGE80_SIZE] = {	0x0D, 0x80, 0x00, 0x00};/* VP PG83 Device Identification, Emulated whole page */#define I2C_VPD_PAGE83_SIZE		0x18MV_U8 BASEATTR I2C_INQUIRY_VPD_PAGE83_DATA[I2C_VPD_PAGE83_SIZE] = {	0x0D, 0x83, 0x00, 0x14, 0x61, 0x93, 0x00, 0x08,	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	0x61, 0x94, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00};#endif	/* #ifndef _OS_BIOS */MV_U32I2C_MakeSerialNumber( MV_PU8 pString, PIDENTIFY_SEP_DATA pSepIdentify, MV_U32 BufferLen ){	MV_U32 i;	MV_CopyMemory(pString, pSepIdentify->vendorID, MV_MIN(BufferLen, 8)); 	for(i=0;(((i*2)+8)<BufferLen)&&(i<8);i++)		sprintf((pString+8+(i*2)),"%02x",pSepIdentify->logicalID[7-i]);	return MV_MIN(BufferLen, (i*2)+8);}MV_QUEUE_COMMAND_RESULTI2C_InquiryCmd(	PDomain_I2cLink pI2cLink, PMV_Request pMvReq ){	PIDENTIFY_SEP_DATA pSepIdentify=(PIDENTIFY_SEP_DATA)(pI2cLink->I2cIdentify);	MV_U8 statusCode = REQ_STATUS_SUCCESS;	MV_U8 senseKey = 0, adSenseCode = 0;	MV_U32 tmpLen = 0;	if ( (pMvReq->Cdb[1] & CDB_INQUIRY_EVPD)==0) {		/* Shall return standard INQUIRY data */		if (pMvReq->Cdb[2]!=0) {			/* PAGE CODE field must be zero when EVPD is zero for a valid request */			/* sense key as ILLEGAL REQUEST and additional sense code as INVALID FIELD IN CDB */			statusCode = REQ_STATUS_HAS_SENSE;			senseKey = SCSI_SK_ILLEGAL_REQUEST;			adSenseCode = SCSI_ASC_INVALID_FEILD_IN_CDB;		}		else {			tmpLen = MV_MIN(pMvReq->Data_Transfer_Length, I2C_STD_INQUIRY_SIZE);			MV_CopyMemory(pMvReq->Data_Buffer, I2C_INQUIRY_DEVICE_DATA, tmpLen);			if (pMvReq->Data_Transfer_Length > 8) {				MV_CopyMemory((MV_PU8)(pMvReq->Data_Buffer)+8,					pSepIdentify->vendorID, MV_MIN((pMvReq->Data_Transfer_Length - 8), 8));				if(pMvReq->Data_Transfer_Length > 16)				{					MV_CopyMemory((MV_PU8)(pMvReq->Data_Buffer)+16,						pSepIdentify->productID, MV_MIN((pMvReq->Data_Transfer_Length - 16), 16));					if(pMvReq->Data_Transfer_Length > 32)						MV_CopyMemory((MV_PU8)(pMvReq->Data_Buffer)+32,							pSepIdentify->revisionLevel, MV_MIN((pMvReq->Data_Transfer_Length - 32), 4));				}			}		}	}

⌨️ 快捷键说明

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