Beispiel #1
0
int omap_reset( SIM_HBA *hba, uint32_t rst )
{
	SIM_MMC_EXT		*ext;
	omap_ext_t		*oext;
	uintptr_t		base;
	int				stat;
	uint32_t		sctl;

	ext		= (SIM_MMC_EXT *)hba->ext;
	oext	= (omap_ext_t *)ext->handle;
	base	= oext->mmc_base;

#ifdef OMAP_DEBUG
	mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 1, "%s:  rst %x", __FUNCTION__, rst );
#endif

	sctl	= in32( base + OMAP_MMCHS_SYSCTL );

		// wait up to 100 ms for reset to complete
	out32( base + OMAP_MMCHS_SYSCTL, sctl | rst );
	stat = omap_waitmask( hba, OMAP_MMCHS_SYSCTL, rst, rst, 10000 );
	stat = omap_waitmask( hba, OMAP_MMCHS_SYSCTL, rst, 0, 100000 );

	if( stat ) {
		mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 1, "%s:  timeout", __FUNCTION__ );
	}

	return( stat );
}
Beispiel #2
0
int esdhc_interrupt( SIM_HBA *hba, int irq, int rtype, uint32_t *resp )
{
    SIM_MMC_EXT		*ext;
    esdhc_ext_t		*esdhc;
    uintptr_t		base;
    uint32_t		imsk;
    uint32_t		istat;
    uint32_t		acstat;
    int				intr;

    ext		= (SIM_MMC_EXT *)hba->ext;
    esdhc	= (esdhc_ext_t *)ext->handle;
    base	= esdhc->base;
    istat	= in32( base + ESDHC_IRQSTAT );
    imsk	= in32( base + ESDHC_IRQSTATEN );
    acstat	= in32( base + ESDHC_AUTOC12ERR );
    intr	= 0;

#ifdef ESDHC_DEBUG
    mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 1, "%s: IRQSTAT %x, IRQSTATEN %x, IRQSIGEN %x, AUTOC12ERR %x, PRSSTAT %x", __FUNCTION__, istat, imsk, in32( base + ESDHC_IRQSIGEN ), acstat, in32( base + ESDHC_PRSSTAT ) );
#endif

    if( imsk & ESDHC_IRQ_CC ) {			// command complete interrupt enabled
        if( istat & ESDHC_IRQ_CTOE ) {	// command timeout
            intr |= MMC_ERR_CMD_TO | MMC_INTR_ERROR | MMC_INTR_COMMAND;

            mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 1, "%s: CTOE blks remaining %d", __FUNCTION__, ( esdhc->xmode & ESDHC_XFERTYP_BCEN ) ? ( in32( base + ESDHC_BLKATTR ) >> ESDHC_BLKATTR_BLKCNT_SHIFT ) : 0 );

            if( esdhc_reset( hba, ESDHC_SYSCTL_RSTD | ESDHC_SYSCTL_RSTC, CAM_TRUE ) ) {
                mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 1, "%s: ESDHC_SYSCTL_RSTD/ESDHC_SYSCTL_RSTC timeout", __FUNCTION__ );
            }
        }
        else if( istat & ESDHC_IRQ_CC ) {
Beispiel #3
0
int esdhc_clock( SIM_HBA *hba, int *clock, int hs )
{
    SIM_MMC_EXT		*ext;
    esdhc_ext_t		*esdhc;
    uintptr_t		base;
    uint32_t		sysctl;
    uint32_t		max_clk;
    int				dvs;
    int				sdclkfs;

    ext			= (SIM_MMC_EXT *)hba->ext;
    esdhc		= (esdhc_ext_t *)ext->handle;
    base		= esdhc->base;
    max_clk		= esdhc->clock;
    hs			= hs;
    sdclkfs		= 2;

#ifdef ESDHC_DEBUG
    mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 1, "%s: requested clock %d, %s speed", __FUNCTION__, *clock, hs ? "high" : "low" );
#endif
    if(*clock>max_clk) {
        *clock = max_clk;
    }

    if(*clock < (max_clk / 256)) {
        *clock = max_clk / 256;
    }

    // calc sdclkfs (min is div 2)
    if( max_clk / 16 > *clock ) {
        for( sdclkfs = 2; sdclkfs < 256; sdclkfs *= 2 ) {
            if( ( max_clk / sdclkfs ) < ( *clock * 16 ) ) {
                break;
            }
        }
    }

    // calc dvs using above sdclkfs
    for( dvs = 1; dvs <= 16; dvs++ ) {
        if( ( max_clk / ( dvs * sdclkfs ) ) <= *clock ) {
            break;
        }
    }

    sdclkfs >>= 1;
    dvs -= 1;

    sysctl = in32( base + ESDHC_SYSCTL ) & ~( ESDHC_SYSCTL_SDCLKFS_MASK | ESDHC_SYSCTL_DVS_MASK );
    sysctl |= ( dvs << ESDHC_SYSCTL_DVS_SHIFT ) | ( sdclkfs << ESDHC_SYSCTL_SDCLKFS_SHIFT );
    out32( base + ESDHC_SYSCTL, sysctl | ESDHC_SYSCTL_DTOCV_MAX );
    out32( base + ESDHC_SYSCTL, sysctl | ESDHC_SYSCTL_PEREN | ESDHC_SYSCTL_DTOCV_MAX );

#ifdef ESDHC_DEBUG
    mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 1, "%s: SYSCTL %x, dvs %x, sdclkfs %x", __FUNCTION__, in32( base + ESDHC_SYSCTL ), dvs, sdclkfs );
#endif

    return( MMC_SUCCESS );
}
Beispiel #4
0
int omap_dump( SIM_HBA *hba )
{
	SIM_MMC_EXT		*ext;
	omap_ext_t		*oext;
	uintptr_t		base;

	ext		= (SIM_MMC_EXT *)hba->ext;
	oext	= (omap_ext_t *)ext->handle;
	base	= oext->mmc_base;

#ifdef OMAP_DEBUG
	mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 3, "%s: HL_REV %x, HL_HWINFO %x, HL_SYSCONFIG %x, SYSSTATUS %x, REV %x, CAPA %x, CUR_CAPA %x, SYSTEST %x, FE %x",
	__FUNCTION__, 
	in32( base + OMAP_MMCHS_HL_REV ),
	in32( base + OMAP_MMCHS_HL_HWINFO ),
	in32( base + OMAP_MMCHS_HL_SYSCONFIG ),
	in32( base + OMAP_MMCHS_SYSSTATUS ),
	in32( base + OMAP_MMCHS_REV ),
	in32( base + OMAP_MMCHS_CAPA ),
	in32( base + OMAP_MMCHS_CUR_CAPA ),
	in32( base + OMAP_MMCHS_SYSTEST ),
	in32( base + OMAP_MMCHS_FE ) );
	
	mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 3, "%s: CSRE %x, CON %x, PWCNT %x, BLK %x, ARG %x, CMD %x, RSP10 %x, RSP32 %x, RSP54 %x,  RSP76 %x",
	__FUNCTION__,
	in32( base + OMAP_MMCHS_CSRE ),
	in32( base + OMAP_MMCHS_CON ),
	in32( base + OMAP_MMCHS_PWCNT ),
	in32( base + OMAP_MMCHS_BLK ),
	in32( base + OMAP_MMCHS_ARG ),
	in32( base + OMAP_MMCHS_CMD ),
	in32( base + OMAP_MMCHS_RSP10 ),
	in32( base + OMAP_MMCHS_RSP32 ),
	in32( base + OMAP_MMCHS_RSP54 ),
	in32( base + OMAP_MMCHS_RSP76 ) );

	mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 3, "%s: PSTATE %x, HCTL %x, SYSCTL %x, STAT %x, IE %x, ISE %x, AC12 %x, ADMAES %x ADMASAL %x",
	__FUNCTION__,
	in32( base + OMAP_MMCHS_PSTATE ),
	in32( base + OMAP_MMCHS_HCTL ),
	in32( base + OMAP_MMCHS_SYSCTL ),
	in32( base + OMAP_MMCHS_STAT ), 
	in32( base + OMAP_MMCHS_IE ),
	in32( base + OMAP_MMCHS_ISE ),
	in32( base + OMAP_MMCHS_AC12 ),
	in32( base + OMAP_MMCHS_ADMAES ),
	in32( base + OMAP_MMCHS_ADMASAL ) );
#endif
	return( MMC_SUCCESS );
}
Beispiel #5
0
int omap_waitmask( SIM_HBA *hba, uint32_t reg, uint32_t mask, uint32_t val, uint32_t usec )
{
	SIM_MMC_EXT		*ext;
	omap_ext_t		*oext;
	uintptr_t		base;
	uint32_t		cnt;
	int				stat;
	int				rval;
	uint32_t		iter;

	ext		= (SIM_MMC_EXT *)hba->ext;
	oext	= (omap_ext_t *)ext->handle;
	base	= oext->mmc_base;
	stat	= MMC_FAILURE;
	rval	= MMC_SUCCESS;

		// fast poll for 1ms - 1us intervals
	for( cnt = min( usec, 1000 ); cnt; cnt-- ) {
		if( ( ( rval = in32( base + reg ) ) & mask ) == val ) {
			stat = MMC_SUCCESS;
			break;
		}
		nanospin_ns( 1000L );
	}

	if( usec > 1000 && stat ) {
		iter	= usec / 1000L;
		for( cnt = iter; cnt; cnt-- ) {
			if( ( ( rval = in32( base + reg ) ) & mask ) == val ) {
				stat = MMC_SUCCESS;
				break;
			}
			delay( 1 );
		}
	}

#ifdef OMAP_DEBUG
	if( !cnt ) {
		mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 3, "%s: reg %x, mask %x, val %x, rval %x", __FUNCTION__, reg, mask, val, in32( base + reg ) ); 
	}
#endif

	return( stat );
}
Beispiel #6
0
int esdhc_dump_regs( SIM_HBA *hba )
{
    SIM_MMC_EXT		*ext;
    esdhc_ext_t		*esdhc;
    uintptr_t		base;

    ext		= (SIM_MMC_EXT *)hba->ext;
    esdhc	= (esdhc_ext_t *)ext->handle;
    base	= esdhc->base;

    mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 1, "%s: DSADDR %x, BLKATTR %x, CMDARG %x, XFERTYP %x, CMDRSP0 %x, CMDRSP1 %x, CMDRSP2 %x, CMDRSP3 %x, PRSSTAT %x, PROTCTL %x, SYSCTL %x, IRQSTAT %x, IRQSTATEN %x, IRQSIGEN %x, AUTOC12ERR %x, HOSTCAPBLT %x, WML %x, FEVT %x, HOSTVER %x, SCR %x", __FUNCTION__,
               in32( base + ESDHC_DSADDR ), in32( base + ESDHC_BLKATTR ),
               in32( base + ESDHC_CMDARG ), in32( base + ESDHC_XFERTYP ),
               in32( base + ESDHC_CMDRSP0 ), in32( base + ESDHC_CMDRSP1 ),
               in32( base + ESDHC_CMDRSP2 ), in32( base + ESDHC_CMDRSP3 ),
               in32( base + ESDHC_PRSSTAT ), in32( base + ESDHC_PROCTL ),
               in32( base + ESDHC_SYSCTL ), in32( base + ESDHC_IRQSTAT ),
               in32( base + ESDHC_IRQSTATEN ), in32( base + ESDHC_IRQSIGEN ),
               in32( base + ESDHC_AUTOC12ERR ), in32( base + ESDHC_HOSTCAPBLT ),
               in32( base + ESDHC_WML ), in32( base + ESDHC_FEVT ),
               in32( base + ESDHC_HOSTVER ), in32( base + ESDHC_SCR ) );
    return( MMC_SUCCESS );
}
Beispiel #7
0
int _mmc_sendcmd(SIM_HBA *hba, uint32_t cmdflg, uint32_t argument)
{
	SIM_MMC_EXT		*ext;
	mmc_cmd_t		cmd;

	ext = (SIM_MMC_EXT *)hba->ext;

	/* Put the card in idle state */
	cmd.argument = argument;
	cmd.opcode   = cmdflg & 0xFF;
	cmd.resp     = (cmdflg >> 8) & 0xFF;
	cmd.eflags   = (cmdflg >> 16) & 0xFFFF;
	if (ext->eflags & MMC_EFLAG_PPL)
		cmd.eflags  |= MMC_CMD_PPL;

	ext->mmc_resp[0] = ext->mmc_resp[1] = ext->mmc_resp[2] = ext->mmc_resp[3] = 0;
	ext->resp_type = cmd.resp;

#ifdef MMCSD_DEBUG
	mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 1, "%s: %s (%d), arg 0x%x, resp 0x%x, eflags 0x%x", __FUNCTION__, mmc_cmds[cmd.opcode], cmd.opcode, cmd.argument, cmd.resp, cmd.eflags );
#endif

	return (ext->command(hba, &cmd));
}
Beispiel #8
0
static int omap_setup_sgdma( SIM_HBA *hba, int dir )
{
	SIM_MMC_EXT		*ext;
	omap_ext_t		*oext;
	CCB_SCSIIO		*ccb;
	uintptr_t		base;
	uint32_t		xlen;
	uint32_t		blkcnt;
	sdhci_adma32_t	*adma;
	SG_ELEM			sge;
	SG_ELEM			*sgp;
	int				sgc;
	int				sgi;
	int				acnt;
	int				alen;
	int				sg_count;
	paddr_t			paddr;

	ext		= (SIM_MMC_EXT *)hba->ext;
	oext	= (omap_ext_t *)ext->handle;
	adma	= (sdhci_adma32_t *)oext->adma;
	ccb		= ext->nexus;
	base	= oext->mmc_base;
	xlen	= ccb->cam_dxfer_len;

#ifdef OMAP_DEBUG
	mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 1, "%s: ", __FUNCTION__ );
#endif

	if( ccb->cam_ch.cam_flags & CAM_SCATTER_VALID ) {
		sgc = ccb->cam_sglist_cnt;
		sgp = ccb->cam_data.cam_sg_ptr;
	}
	else {
		sgp = &sge;
		sgc = 1;
		sgp->cam_sg_count	= ccb->cam_dxfer_len;
		sgp->cam_sg_address	= ccb->cam_data.cam_data_ptr;
	}

#define OMAP_ADMA_MAX_XFER	(1024 *60)

	for( sgi = 0, acnt = 0; sgi < sgc; sgi++, sgp++ ) {
		paddr		= mmc_mphys( ccb, sgp->cam_sg_address, sgi );
		sg_count	= sgp->cam_sg_count;
		while( sg_count ) {
			alen		= min( sg_count, OMAP_ADMA_MAX_XFER );
			adma->attr	= SDHCI_ADMA2_VALID | SDHCI_ADMA2_TRAN;
			adma->addr	= paddr;
			adma->len	= alen;
			sg_count	-= alen; 
			paddr		+= alen;
			adma++;
			if( ++acnt > SDHCI_ADMA_DESC_MAX ) {
				return( 0 );
			}
		}
	}

	adma--;
	adma->attr |= SDHCI_ADMA2_END;

	blkcnt = ccb->cam_dxfer_len / oext->blksz;
	xlen   = oext->blksz * blkcnt;

	if( blkcnt == 0 ) {
		return( 0 );
	}

	oext->dmask	= INTR_TC;
	oext->dcmd	= CMD_DP | CMD_DE;
	if( ccb->cam_ch.cam_flags & CAM_DIR_IN ) {
		oext->dcmd |= CMD_DDIR;
	}

	if( blkcnt > 1 ) {
		oext->dcmd |= CMD_MBS | CMD_BCE;
		if( ext->hccap & MMC_HCCAP_ACMD12 ) {
			oext->dcmd |= CMD_ACEN;
		}
	}

	out32( oext->mmc_base + OMAP_MMCHS_BLK, ( blkcnt << 16 ) | oext->blksz );
	out32( base + OMAP_MMCHS_ADMASAL, oext->admap );

	return( xlen );
}
Beispiel #9
0
static int omap_interrupt( SIM_HBA *hba, int irq, int resp_type, uint32_t *resp )
{
	SIM_MMC_EXT		*ext;
	omap_ext_t		*oext;
	uint32_t		sts;
	int				intr;
	uintptr_t		base;

	ext		= (SIM_MMC_EXT *)hba->ext;
	oext	= (omap_ext_t *)ext->handle;
	base	= oext->mmc_base;
	intr	= 0;

	sts = in32( base + OMAP_MMCHS_STAT );
	sts &= in32( base + OMAP_MMCHS_IE ) | INTR_ERRI;
	out32( base + OMAP_MMCHS_STAT, sts );

	if( sts & INTR_ERRI ) {	// Any errors ?
//		mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 1, "%s:  status %x", __FUNCTION__, sts );
		omap_dump( hba );
		intr |= MMC_INTR_ERROR | MMC_INTR_COMMAND;
		if( sts & INTR_ADMAE ) {	// ADMA error
			mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 1, "%s:  ADMAES %x", __FUNCTION__, in32( base + OMAP_MMCHS_ADMAES ) );
		}

		if( sts & INTR_DTO ) {
			intr |= MMC_ERR_DATA_TO;
			omap_reset( hba, SYSCTL_SRD );
			omap_reset( hba, SYSCTL_SRC );
		}
		if( sts & INTR_DCRC ) {
			intr |= MMC_ERR_DATA_CRC;
		}
		if( sts & INTR_DEB ) {
			intr |= MMC_ERR_DATA_END;
		}
		if( sts & INTR_CTO ) {
			intr |= MMC_ERR_CMD_TO;
			omap_reset( hba, SYSCTL_SRC );
		}
		if( sts & INTR_CCRC ) {
			intr |= MMC_ERR_CMD_CRC;
		}
		if( sts & INTR_CEB ) {
			intr |= MMC_ERR_CMD_END;
		}
		if( sts & INTR_CIE ) {
			intr |= MMC_ERR_CMD_IDX;
		}
		if( sts & INTR_ACE ) {
			mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 1, "%s: AC12 Error %x", __FUNCTION__, in32( base + OMAP_MMCHS_AC12 ) );
			intr |= MMC_ERR_DATA_TO | MMC_INTR_ERROR;
			omap_reset( hba, SYSCTL_SRD );
			omap_reset( hba, SYSCTL_SRC );
		}
	}
	else {
		if( sts & INTR_CC ) {
			intr |= MMC_INTR_COMMAND;
			if( resp ) {
				if( resp_type & MMC_RSP_136 ) {
					resp[3] = in32( base + OMAP_MMCHS_RSP76 );
					resp[2] = in32( base + OMAP_MMCHS_RSP54 );
					resp[1] = in32( base + OMAP_MMCHS_RSP32 );
					resp[0] = in32( base + OMAP_MMCHS_RSP10 );
				}
				else if( resp_type & MMC_RSP_PRESENT ) {
					resp[0] = in32( base + OMAP_MMCHS_RSP10 );
				}
			}

				// Busy check?
			if( resp_type & MMC_RSP_BUSY ) {
				if( omap_waitmask( hba, OMAP_MMCHS_PSTATE, PSTATE_DLA, 0, 500000 ) ) {
					intr |= MMC_ERR_CMD_TO | MMC_INTR_ERROR;
					mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 1, "%s:  busy check time out", __FUNCTION__ );
				}
			}
		}

		if( sts & ( INTR_TC | INTR_BWR | INTR_BRR ) ) {
			if( sts & INTR_TC ) {
				intr |= MMC_INTR_DATA;
			}
			if( sts & INTR_BRR ) {
				intr |= MMC_INTR_RBRDY;
			}
			if( sts & INTR_BWR ) {
				intr |= MMC_INTR_WBRDY;
			}
		}
	}

	if( intr ) {
		out32( base + OMAP_MMCHS_IE, 0 );
	}

	return( intr );
}