#include "proto.h" #include #include /******************************************************************************************* Protocol analyzer for MMC Interface (embedded MMC) 25. Feb. 2011, JIM (c) Lauterbach GmbH *******************************************************************************************/ typedef struct { int viewDAT; } param; typedef struct { int clk; // CLK int cmd; // CMD int dat; // DAT } signals; typedef struct { protoTime timestamp; char isCommand; // 1:command , 0: response char commandIndex; int argument; int CommandToken[4]; int DataPkt[1]; int count; } data; static protoSizeT PROTOAPI process1(protoContext context, protoPtr arrayOut, protoSizeT arrayOutSize, protoPtr arrayIn, protoSizeT arrayInSize, protoPtr localdata) { protoTime time; // incoming timestamp protoTime time_preclk; // incoming timestamp signals traceBits; // incoming signal lines signals traceBitsOld; // previous icoming signla lines (for edge detection) data *dataOut; // outgoing data structure which is generated by this function (process1) param *parameters; // global parameters int sample = 0; // number of received data samples protoSizeT index = 0; // number of detected data bytes int countClk = 0; int countClkDAT=0; int *bitsCommandToken; int *bitsDataPkt; char startedCMD = 0; char startedDAT=0; char datBusEnabled=0; int argument = 0x0; char command=0; int byteCnt=0; int i; time_preclk=0x0; dataOut = (data*) arrayOut; parameters= (param*) localdata; bitsCommandToken = dataOut[index].CommandToken; for(i=0;i<4;i++){ bitsCommandToken[i]=0; } bitsDataPkt = dataOut[index].DataPkt; bitsDataPkt[0]=0; dataOut[index].commandIndex = 0; if( arrayInSize == 0 ) return 0; if( arrayOutSize == 0 ) return PROTO_PROCESS_OUTOFMEMORY; PROTO_ReadTrace( context, sample, &time, (int*) &traceBits ); sample++; while( sample < arrayInSize ) { if( (sample & 0xfff) == 0 ) // give GUI a chance to stop us if (PROTO_Cancel(context)) return PROTO_PROCESS_CANCEL; traceBitsOld = traceBits; PROTO_ReadTrace( context, sample, &time, (int*) &traceBits ); sample++; if (traceBitsOld.clk == 1 && traceBits.clk == 0) { time_preclk = time; } if (traceBitsOld.clk == 0 && traceBits.clk == 1 && ((time-time_preclk)>0x100) ) { /* avoid glitch signal, it regards as a glitch signal when it is faster than 50Mhz (0.02us) */ bitsCommandToken[3] = bitsCommandToken[3]<<1 | !!(bitsCommandToken[2]&0x80000000) ; bitsCommandToken[2] = bitsCommandToken[2]<<1 | !!(bitsCommandToken[1]&0x80000000) ; bitsCommandToken[1] = bitsCommandToken[1]<<1 | !!(bitsCommandToken[0]&0x80000000) ; bitsCommandToken[0] = bitsCommandToken[0]<<1 | traceBits.cmd; bitsDataPkt[0] = bitsDataPkt[0]<<1 | traceBits.dat; if(parameters->viewDAT){ if ( traceBitsOld.cmd==0 && traceBits.cmd==0 && startedCMD==0 ){ //Start CMD Line startedCMD=1; countClk=0; dataOut[index].timestamp = time; bitsCommandToken = dataOut[index].CommandToken; } if ( startedCMD==1) { if(countClk==1) { // first of CMD line signal dataOut[index].isCommand=traceBits.cmd ; //CMD or Response } countClk++; if(dataOut[index].isCommand==1) { //Command if (countClk>=48) { startedCMD=0; command=(dataOut[index].CommandToken[1]>>8)&0x3F; argument=((bitsCommandToken[1]&0xFF)<<24)|((bitsCommandToken[0]>>8)&0xFFFFFF); if(command==18 || command==25 || command==17 || command==24) { datBusEnabled=1; countClkDAT=0; } } } else if (dataOut[index].isCommand==0) { //Response if(command==2 || command==9 || command==10){ if(countClk>=136) startedCMD=0; }else{ if(countClk>=48)startedCMD=0; } } /* When the command or response message is finished */ /*if (startedCMD==0){ dataOut[index].commandIndex=command; index++ ; if( index >= arrayOutSize ) // Check if we have space for a new data byte return PROTO_PROCESS_OUTOFMEMORY; bitsCommandToken = dataOut[index].CommandToken; for(i=0;i<4;i++)bitsCommandToken[i]=0; }*/ } if ( datBusEnabled==1 ) { if (traceBitsOld.dat==0 && traceBits.dat==0 && startedDAT==0 ){ //Start DAT Line startedDAT=1; countClkDAT=0; } else if(startedDAT==1){ countClkDAT++; if(countClkDAT%8==0){ bitsDataPkt = dataOut[index].DataPkt; dataOut[index].timestamp = time; dataOut[index].count=byteCnt; dataOut[index].argument=argument; dataOut[index].commandIndex=command; //For response byteCnt++; index++ ; if( index >= arrayOutSize ) // Check if we have space for a new data byte return PROTO_PROCESS_OUTOFMEMORY; bitsDataPkt = dataOut[index].DataPkt; bitsDataPkt[0]=0; } if(countClkDAT%(512*8)==0){ datBusEnabled=0x0; //finished byteCnt=0x0; startedDAT=0; } } } } else{ //When parameters->viewDAT is OFF if ( traceBitsOld.cmd==0 && traceBits.cmd==0 && startedCMD==0 ){ //Start CMD Line startedCMD=1; countClk=0; dataOut[index].timestamp = time; bitsCommandToken = dataOut[index].CommandToken; } if ( startedCMD==1) { if(countClk==1) { // first of CMD line signal dataOut[index].isCommand=traceBits.cmd ; //CMD or Response } countClk++; if(dataOut[index].isCommand==1) { //Command if (countClk>=48) { startedCMD=0; command=(dataOut[index].CommandToken[1]>>8)&0x3F; } } else if (dataOut[index].isCommand==0) { //Response if(command==2 || command==9 || command==10){ if(countClk>=136) startedCMD=0; }else{ if(countClk>=48)startedCMD=0; } } /* When the command or response message is finished */ if (startedCMD==0){ dataOut[index].commandIndex=command; index++ ; if( index >= arrayOutSize ) // Check if we have space for a new data byte return PROTO_PROCESS_OUTOFMEMORY; bitsCommandToken = dataOut[index].CommandToken; for(i=0;i<4;i++)bitsCommandToken[i]=0; } } } } } return index; } #define MMC_CID(buf, bitfield, bits) ( (buf[bitfield/8]>>(bitfield%8)) & ((1 << (bits)) - 1) ) #define MMC_CID_MID(buf) MMC_CID(buf, 120, 8) /* Manufacturer ID */ #define MMC_CID_BGA(buf) MMC_CID(buf, 112, 2) /* Card/BGA(eMMC) */ #define MMC_CID_CBX(buf) MMC_CID(buf, 112, 2) /* Card/BGA(eMMC) */ #define MMC_CID_OID_BYTE_0(buf) MMC_CID(buf, 104, 8) /* OEM/Application ID byte 0 */ #define MMC_CID_PNM_BYTE_5(buf) MMC_CID(buf, 96, 8) /* Product name byte 5 for MMC */ #define MMC_CID_PNM_BYTE_4(buf) MMC_CID(buf, 88, 8) /* Product name byte 4 for MMC */ #define MMC_CID_PNM_BYTE_3(buf) MMC_CID(buf, 80, 8) /* Product name byte 3 for MMC */ #define MMC_CID_PNM_BYTE_2(buf) MMC_CID(buf, 72, 8) /* Product name byte 2 for MMC */ #define MMC_CID_PNM_BYTE_1(buf) MMC_CID(buf, 64, 8) /* Product name byte 1 for MMC */ #define MMC_CID_PNM_BYTE_0(buf) MMC_CID(buf, 56, 8) /* Product name byte 0 for MMC */ #define MMC_CID_PRV_2(buf) MMC_CID(buf, 52, 4) /* Product revision 1 for MMC */ #define MMC_CID_PRV_1(buf) MMC_CID(buf, 48, 4) /* Product revision 2 for MMC */ #define MMC_CID_PSN_3(buf) MMC_CID(buf, 40, 8) /* Product serial number for MMC */ #define MMC_CID_PSN_2(buf) MMC_CID(buf, 32, 8) /* Product serial number for MMC */ #define MMC_CID_PSN_1(buf) MMC_CID(buf, 24, 8) /* Product serial number for MMC */ #define MMC_CID_PSN_0(buf) MMC_CID(buf, 16, 8) /* Product serial number for MMC */ #define MMC_CID_MDT_YEAR(buf) (MMC_CID(buf, 12, 4))+2000 /* Manufacturing date year */ #define MMC_CID_MDT_MONTH(buf) MMC_CID(buf, 8, 4) /* Manufacturing date month */ #define MMC_CID_CRC(buf) MMC_CID(buf, 1, 7) /* CRC7 checksum */ static void PROTOAPI display1(protoContext context, protoPtr pdata, protoPtr localdata) { data *mmcdata = (data*) pdata; param *parameters = (param*)localdata; char command; char *buf; char *currentState=""; buf=(char *)mmcdata->CommandToken; command=mmcdata->commandIndex; if(parameters->viewDAT) { PROTO_Control( context, PROTO_ATTRIBUTE_NORM ); PROTO_Printf ( context, "CMD%-2d ", command); PROTO_Printf ( context, "ARG(0x%08X), ", mmcdata->argument); PROTO_Printf ( context, "DAT0: 0x%02X #:0x%X", (mmcdata->DataPkt[0])&0xFF , mmcdata->count); } else{ if(mmcdata->isCommand==0x0) { //Response PROTO_Control( context, PROTO_ATTRIBUTE_LIGHT ); PROTO_Printf ( context, "resp, "); if(command==1){ PROTO_Printf ( context, "OCR: 0x%08X",((mmcdata->CommandToken[1]&0xFF)<<24)|((mmcdata->CommandToken[0]>>8)&0xFFFFFF)); } else if(command==2 || command==10){ PROTO_Printf( context, "CID: ",mmcdata->CommandToken[3],mmcdata->CommandToken[2], mmcdata->CommandToken[1], mmcdata->CommandToken[0] ); //PROTO_Printf( context, "CID:"); PROTO_Control(context, PROTO_CONTROL_LINEFEED); PROTO_Printf(context, "Manufacturer ID: 0x%X", MMC_CID_MID(buf) ); PROTO_Control(context, PROTO_CONTROL_LINEFEED); PROTO_Printf(context,"OEM/Application ID: 0x%X", MMC_CID_OID_BYTE_0(buf)); PROTO_Control(context, PROTO_CONTROL_LINEFEED); PROTO_Printf(context,"Product name: %c%c%c%c%c%c", MMC_CID_PNM_BYTE_5(buf), MMC_CID_PNM_BYTE_4(buf), MMC_CID_PNM_BYTE_3(buf), MMC_CID_PNM_BYTE_2(buf),MMC_CID_PNM_BYTE_1(buf), MMC_CID_PNM_BYTE_0(buf)); PROTO_Control(context, PROTO_CONTROL_LINEFEED); PROTO_Printf(context,"Product revision: %d.%d", MMC_CID_PRV_2(buf), MMC_CID_PRV_1(buf) ); PROTO_Control(context, PROTO_CONTROL_LINEFEED); PROTO_Printf(context,"Serial number: %X%X%X%X", MMC_CID_PSN_3(buf),MMC_CID_PSN_2(buf), MMC_CID_PSN_1(buf),MMC_CID_PSN_0(buf) ); PROTO_Control(context, PROTO_CONTROL_LINEFEED); PROTO_Printf(context,"Manufacture date: %3d %d", MMC_CID_MDT_MONTH(buf), MMC_CID_MDT_YEAR(buf) ); } else if(command==9){ PROTO_Printf( context, "CSD: 0x%08X %08X %08X %08X ",mmcdata->CommandToken[3],mmcdata->CommandToken[2], mmcdata->CommandToken[1], mmcdata->CommandToken[0] ); } else{ PROTO_Printf ( context, "STA: 0x%08X",((mmcdata->CommandToken[1]&0xFF)<<24)|((mmcdata->CommandToken[0]>>8)&0xFFFFFF)); switch((((mmcdata->CommandToken[1]&0xFF)<<24)|((mmcdata->CommandToken[0]>>8)&0xFFFFFF)>>9)&0xF) { case 0: currentState = "idle" ; break; case 1: currentState = "ready" ; break; case 2: currentState = "ident" ; break; case 3: currentState = "stby" ; break; case 4: currentState = "tran" ; break; case 5: currentState = "data" ; break; case 6: currentState = "rcv" ; break; case 7: currentState = "prg" ; break; case 8: currentState = "dis" ; break; default : currentState = "reserv"; break; } PROTO_Control( context, PROTO_ATTRIBUTE_LIGHT ); PROTO_Printf ( context, " (%-s)-> " ,currentState ); } } else if(mmcdata->isCommand==0x1) { //Command PROTO_Control( context, PROTO_ATTRIBUTE_NORM ); PROTO_Printf ( context, "CMD%-2d ", command); //PROTO_Control( context, PROTO_ATTRIBUTE_LIGHT ); PROTO_Printf ( context, "ARG(0x%08X) ",((mmcdata->CommandToken[1]&0xFF)<<24)|((mmcdata->CommandToken[0]>>8)&0xFFFFFF)); PROTO_Printf ( context, "CRC7(0x%02X) ",(mmcdata->CommandToken[0]>>1)&0x7F); PROTO_Printf ( context, ", [47:0]: 0x%04X%08X ", mmcdata->CommandToken[1]&0xFFFF, mmcdata->CommandToken[0] ); } } } static void PROTOAPI export(protoContext context, protoPtr pdata, protoPtr localdata) { } int PROTOAPI PROTO_Init(protoContext context, int command) { param *parameters; parameters = (param*) PROTO_Alloc(context, sizeof(param) ); parameters->viewDAT = 0; PROTO_Parse(context, (protoPtr) 0, "", PROTO_PARSE_CHANNEL); PROTO_Parse(context, (protoPtr) 0, "", PROTO_PARSE_CHANNEL); PROTO_Parse(context, (protoPtr) 0, "", PROTO_PARSE_CHANNEL); PROTO_Parse(context, (protoPtr)(¶meters->viewDAT), "", PROTO_PARSE_INTEGER |PROTO_PARSE_OPTIONAL); if( parameters->viewDAT != 0 ) parameters->viewDAT = 1; PROTO_RegisterProcessCallback(context, process1, (protoPtr) parameters, sizeof(data), 1); PROTO_RegisterDisplayCallback(context, display1, (protoPtr) parameters, 1); PROTO_RegisterExportCallback (context, export, (protoPtr) parameters, 1); PROTO_SetDefaultLevel(context, 1); return PROTO_OK; }