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 ); }
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 ) {
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 ); }
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 ); }
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 ); }
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 ); }
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)); }
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 ); }
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 ); }