| /****************************************************************************** |
| * |
| * (C)Copyright 2005 - 2011 Marvell. All Rights Reserved. |
| * |
| * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MARVELL. |
| * The copyright notice above does not evidence any actual or intended |
| * publication of such source code. |
| * This Module contains Proprietary Information of Marvell and should be |
| * treated as Confidential. |
| * The information in this file is provided for the exclusive use of the |
| * licensees of Marvell. |
| * Such users have the right to use, modify, and incorporate this code into |
| * products for purposes authorized by the license agreement provided they |
| * include this notice and the associated copyright notice with any such |
| * product. |
| * The information in this file is provided "AS IS" without warranty. |
| * |
| ******************************************************************************/ |
| |
| /****************************************************************************** |
| ** |
| ** FILENAME: sdhc_controller.c |
| ** |
| ** PURPOSE: MMC and SD specific low level controller routines for the MM4 controller |
| ** |
| ** |
| ** |
| ** |
| ******************************************************************************/ |
| #include "sdhc2_controller.h" |
| #include "misc.h" |
| #include "Errors.h" |
| #include "timer.h" |
| |
| void MMC4Gen74Clocks(P_MM4_SDMMC_CONTEXT_T pContext) |
| { |
| P_MM4_SD_LEGACY_CTRL_REG pMM4_SD_LEGACY_CTRL_REG; |
| P_MM4_CTRL_REG pP_MM4_CTRL_REG; |
| UINT_T startTime, endTime; |
| UINT_T retval = NoError; |
| |
| pMM4_SD_LEGACY_CTRL_REG = (P_MM4_SD_LEGACY_CTRL_REG)&pContext->pMMC4Reg->mm4_legacy_ctrl_reg; |
| pP_MM4_CTRL_REG = (P_MM4_CTRL_REG)&pContext->pMMC4Reg->mm4_mmc_ctrl_reg; |
| |
| // Enable capturing status for sending out 74 clock cycles. |
| pP_MM4_CTRL_REG->misc_int_en = 1; |
| pP_MM4_CTRL_REG->misc_int = 1; |
| |
| // Enable and start 74 clock cycles |
| pMM4_SD_LEGACY_CTRL_REG->gen_pad_clk_cnt = 74; // 74 clock cycles. |
| pMM4_SD_LEGACY_CTRL_REG->gen_pad_clk_on = 1; // Start generating the clocks. |
| |
| // Wait for the 74 clock cycles to be generated. |
| startTime = GetOSCR0(); |
| startTime = GetOSCR0(); |
| do |
| { |
| if (pP_MM4_CTRL_REG->misc_int) |
| break; // 74 clock cycles have been generated. |
| |
| endTime = GetOSCR0(); |
| |
| if (OSCR0IntervalInMilli(startTime, endTime) >= 10) |
| return SDMMCInitializationError; |
| }while(1); |
| |
| return retval; |
| } |
| |
| /****************************************************************************** |
| Description: |
| Start MMC/SD Internal bus clock. MUST be done to start MM4CLK! |
| Only after starting bus clock, communication between |
| controller and card is possible |
| Input Parameters: |
| pContext--Pointer to MMC context structure |
| Output Parameters: |
| None |
| Returns: |
| None |
| *******************************************************************************/ |
| void MMC4StartInternalBusClock(P_MM4_SDMMC_CONTEXT_T pContext) |
| { |
| P_MM4_CNTL2 pMM4_CNTL2; |
| MM4_CNTL2_UNION MM4_cntl2; |
| |
| pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2); |
| MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2; |
| MM4_cntl2.mm4_cntl2_bits.inter_clk_en = 1; |
| *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value; |
| |
| // Wait for clock to become stable. * TBD * Add timeout |
| do |
| { |
| MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2; |
| } while (!(MM4_cntl2.mm4_cntl2_bits.inter_clk_stable)); |
| |
| return; |
| } |
| |
| /****************************************************************************** |
| Description: |
| Stops the MMC/SD Internal bus clock. |
| Input Parameters: |
| pContext--Pointer to MMC context structure |
| Output Parameters: |
| None |
| Returns: |
| None |
| *******************************************************************************/ |
| void MMC4StopInternalBusClock(P_MM4_SDMMC_CONTEXT_T pContext) |
| { |
| P_MM4_CNTL2 pMM4_CNTL2; |
| MM4_CNTL2_UNION MM4_cntl2; |
| |
| pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2); |
| MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2; |
| MM4_cntl2.mm4_cntl2_bits.inter_clk_en = 0; |
| *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value; |
| |
| // Wait for clock to become stable. * TBD * Add timeout |
| do |
| { |
| MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2; |
| } while (MM4_cntl2.mm4_cntl2_bits.inter_clk_stable); |
| |
| return; |
| } |
| |
| |
| /****************************************************************************** |
| Description: |
| Start MMC bus clock. Only after starting bus clock, communication between |
| controller and card is possible |
| Input Parameters: |
| pContext--Pointer to MMC context structure |
| Output Parameters: |
| None |
| Returns: |
| None |
| *******************************************************************************/ |
| void MMC4StartBusClock(P_MM4_SDMMC_CONTEXT_T pContext) |
| { |
| P_MM4_CNTL2 pMM4_CNTL2; |
| MM4_CNTL2_UNION MM4_cntl2; |
| |
| pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2); |
| MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2; |
| MM4_cntl2.mm4_cntl2_bits.mm4clken = 1; |
| |
| *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value; |
| return; |
| } |
| |
| /****************************************************************************** |
| Description: |
| Stops MMC bus clock. |
| Input Parameters: |
| pContext--Pointer to MMC context structure |
| Output Parameters: |
| None |
| Returns: |
| None |
| *******************************************************************************/ |
| void MMC4StopBusClock (P_MM4_SDMMC_CONTEXT_T pContext) |
| { |
| P_MM4_CNTL2 pMM4_CNTL2; |
| MM4_CNTL2_UNION MM4_cntl2; |
| |
| // Request bus clock stop |
| pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2); |
| MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2; |
| MM4_cntl2.mm4_cntl2_bits.mm4clken = 0; |
| *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value; |
| |
| return; |
| } |
| |
| /****************************************************************************** |
| Description: |
| Set a new MMC bus clock rate. This function stops and resumes bus clock. |
| Input Parameters: |
| pContext |
| Pointer to MMC context structure |
| rate |
| bus clock speed |
| Output Parameters: |
| None |
| Returns: |
| None |
| *******************************************************************************/ |
| void MMC4SetBusRate(P_MM4_SDMMC_CONTEXT_T pContext, UINT_T rate) |
| { |
| P_MM4_CNTL2 pMM4_CNTL2; |
| MM4_CNTL2_UNION MM4_cntl2; |
| |
| // Request bus clock stop, set rate, start clock. |
| MMC4StopBusClock (pContext); |
| pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2); |
| MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2; |
| |
| // Update the rate and start the clock. |
| MM4_cntl2.mm4_cntl2_bits.sd_freq_sel_lo = (rate & 0xFF); |
| MM4_cntl2.mm4_cntl2_bits.sd_freq_sel_hi = ((rate >> 8) & 3); |
| MM4_cntl2.mm4_cntl2_bits.mm4clken = 1; |
| *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value; |
| |
| // Make sure internal bus clock also enabled. |
| MMC4StartInternalBusClock(pContext); |
| |
| return; |
| } |
| |
| void MMC4SelectUHSMode(P_MM4_SDMMC_CONTEXT_T pContext, UINT8_T mode) |
| { |
| UINT8_T ctrl = 0; |
| P_MM4_HOST_CNTL2_UNION pMM4_host_CNTL2; |
| MM4_HOST_CNTL2_UNION MM4_host_cntl2; |
| |
| MMC4StopBusClock (pContext); |
| |
| pMM4_host_CNTL2 = (P_MM4_HOST_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_acmd12_er); |
| MM4_host_cntl2.mm4_host_cntl2_value = *(VUINT_T *)pMM4_host_CNTL2; |
| |
| if (mode & SDH_BUS_SPEED_SDR_CLK_208M) { |
| ctrl |= 0x03; |
| } else if (mode & SDH_BUS_SPEED_SDR_CLK_100M) { |
| ctrl |= 0x02; |
| } else if (mode & SDH_BUS_SPEED_DDR_CLK_50M) { |
| ctrl |= 0x04; |
| } else if (mode & SDH_BUS_SPEED_SDR_CLK_50M) { |
| ctrl |= 0x01; |
| } else if (mode & SDH_BUS_SPEED_DEFAULT) { |
| ctrl |= 0x00; |
| } |
| |
| MM4_host_cntl2.mm4_host_cntl2_bits.uhs_mode_sel = ctrl; |
| *(VUINT_T *)pMM4_host_CNTL2 = MM4_host_cntl2.mm4_host_cntl2_value; |
| |
| MMC4StartBusClock(pContext); |
| |
| return; |
| } |
| |
| void MMC4SetTXIntCLKSet(P_MM4_SDMMC_CONTEXT_T pContext, UINT_T mode1, UINT_T mode2) |
| { |
| P_MM4_TX_CFG pMM4_TX_CFG; |
| |
| pMM4_TX_CFG = (P_MM4_TX_CFG)&pContext->pMMC4Reg->mm4_sd_tx_cfg_reg; |
| |
| //set the tx_int_clk_sel that makes the Tih dependant on bus clock rather than base clock |
| pMM4_TX_CFG->tx_int_clk = mode1; |
| pMM4_TX_CFG->tx_mux_sel = mode2; |
| } |
| |
| void MMC4SetRXConfig(P_MM4_SDMMC_CONTEXT_T pContext) |
| { |
| UINT_T value = 0; |
| P_MM4_RX_CFG_UNION pMM4_RX_CFG_UNION; |
| P_MM4_SD_DLINE_CTRL p_MM4_SD_DLINE_CTRL; |
| P_MM4_SD_DLINE_CFG p_MM4_SD_DLINE_CFG; |
| |
| pMM4_RX_CFG_UNION = (P_MM4_RX_CFG)&pContext->pMMC4Reg->mm4_sd_rx_cfg_reg; |
| p_MM4_SD_DLINE_CTRL = (P_MM4_SD_DLINE_CTRL)&pContext->pMMC4Reg->mm4_sd_dline_ctrl_reg; |
| p_MM4_SD_DLINE_CFG = (P_MM4_SD_DLINE_CFG)&pContext->pMMC4Reg->mm4_sd_dline_cfg_reg; |
| |
| value = pMM4_RX_CFG_UNION->MM4_RX_CFG_value; |
| value &= ~(RX_SDCLK_SEL1_MASK << RX_SDCLK_SEL1_SHIFT); |
| /* clock by SDCLK_SEL0, so it is default setting */ |
| value |= 0x1 << RX_SDCLK_SEL1_SHIFT; |
| *(VUINT_T *)pMM4_RX_CFG_UNION = value; |
| |
| p_MM4_SD_DLINE_CFG->rx_dline_reg = 0x0; |
| p_MM4_SD_DLINE_CTRL->rx_dline_code = DDR_RX_DELAY; |
| p_MM4_SD_DLINE_CTRL->dline_pu = 1; |
| } |
| |
| void MMC4SetTXConfig(P_MM4_SDMMC_CONTEXT_T pContext) |
| { |
| UINT_T value = 0; |
| UINT_T tx_delay = DDR_TX_DELAY; |
| P_MM4_TX_CFG_UNION pMM4_TX_CFG_UNION; |
| P_MM4_SD_DLINE_CTRL p_MM4_SD_DLINE_CTRL; |
| P_MM4_SD_DLINE_CFG p_MM4_SD_DLINE_CFG; |
| |
| pMM4_TX_CFG_UNION = (P_MM4_TX_CFG)&pContext->pMMC4Reg->mm4_sd_tx_cfg_reg; |
| p_MM4_SD_DLINE_CTRL = (P_MM4_SD_DLINE_CTRL)&pContext->pMMC4Reg->mm4_sd_dline_ctrl_reg; |
| p_MM4_SD_DLINE_CFG = (P_MM4_SD_DLINE_CFG)&pContext->pMMC4Reg->mm4_sd_dline_cfg_reg; |
| |
| value = pMM4_TX_CFG_UNION->MM4_TX_CFG_value; |
| if (tx_delay) |
| { |
| value &= ~TX_SEL_BUS_CLK; //clr bit 30 |
| value |= TX_MUX_SEL; //set bit 31 select DDLL |
| } |
| |
| *(VUINT_T *)pMM4_TX_CFG_UNION = value; |
| p_MM4_SD_DLINE_CFG->tx_dline_reg = 0x0; |
| p_MM4_SD_DLINE_CTRL->tx_dline_code = tx_delay & TX_DELAY_MASK; |
| p_MM4_SD_DLINE_CTRL->dline_pu = 1; |
| } |
| |
| /****************************************************************************** |
| Description: |
| This routine unmasks and enables or masks and disables required interrupts |
| needed by the driver |
| Input Parameters: |
| pContext |
| Pointer to MMC context structure |
| Desire - Enable or Disable the interrupts |
| Output Parameters: |
| None |
| Returns: |
| None |
| *******************************************************************************/ |
| void MMC4EnableDisableIntSources(P_MM4_SDMMC_CONTEXT_T pContext, UINT8_T Desire) |
| { |
| P_MM4_I_STAT pMM4_I_STAT; |
| MM4_I_STAT_UNION MM4_i_stat; |
| |
| // Capture existing Value |
| pMM4_I_STAT = (P_MM4_I_STAT)((VUINT32_T) &pContext->pMMC4Reg->mm4_i_sig_en); |
| |
| MM4_i_stat.mm4_i_stat_value = *(VUINT_T*)pMM4_I_STAT; |
| // Route the interrupt signal enable register |
| MM4_i_stat.mm4_i_stat_bits.cmdcomp = Desire; |
| MM4_i_stat.mm4_i_stat_bits.xfrcomp = Desire; |
| MM4_i_stat.mm4_i_stat_bits.dmaint = Desire; |
| MM4_i_stat.mm4_i_stat_bits.bufwrrdy = Desire; |
| MM4_i_stat.mm4_i_stat_bits.bufrdrdy = Desire; |
| MM4_i_stat.mm4_i_stat_bits.errint = Desire; |
| MM4_i_stat.mm4_i_stat_bits.ctoerr = Desire; |
| MM4_i_stat.mm4_i_stat_bits.cenderr = Desire; |
| MM4_i_stat.mm4_i_stat_bits.dtoerr = Desire; |
| MM4_i_stat.mm4_i_stat_bits.dcrcerr = Desire; |
| MM4_i_stat.mm4_i_stat_bits.denderr = Desire; |
| MM4_i_stat.mm4_i_stat_bits.admaerr = Desire; |
| MM4_i_stat.mm4_i_stat_bits.crc_stat_err = Desire; |
| |
| // Write it out |
| *(VUINT_T*)pMM4_I_STAT = MM4_i_stat.mm4_i_stat_value; |
| |
| // Now remove the masks |
| pMM4_I_STAT = (P_MM4_I_STAT)((VUINT32_T) &pContext->pMMC4Reg->mm4_i_stat_en); |
| MM4_i_stat.mm4_i_stat_value = *(VUINT_T*)pMM4_I_STAT; |
| MM4_i_stat.mm4_i_stat_bits.cmdcomp = Desire; |
| MM4_i_stat.mm4_i_stat_bits.xfrcomp = Desire; |
| MM4_i_stat.mm4_i_stat_bits.dmaint = Desire; |
| MM4_i_stat.mm4_i_stat_bits.bufwrrdy = Desire; |
| MM4_i_stat.mm4_i_stat_bits.bufrdrdy = Desire; |
| MM4_i_stat.mm4_i_stat_bits.errint = Desire; |
| MM4_i_stat.mm4_i_stat_bits.ctoerr = Desire; |
| MM4_i_stat.mm4_i_stat_bits.cenderr = Desire; |
| MM4_i_stat.mm4_i_stat_bits.dtoerr = Desire; |
| MM4_i_stat.mm4_i_stat_bits.dcrcerr = Desire; |
| MM4_i_stat.mm4_i_stat_bits.denderr = Desire; |
| MM4_i_stat.mm4_i_stat_bits.admaerr = Desire; |
| MM4_i_stat.mm4_i_stat_bits.crc_stat_err = Desire; |
| |
| // Write it out |
| *(VUINT_T*)pMM4_I_STAT = MM4_i_stat.mm4_i_stat_value; |
| |
| return; |
| } |
| |
| /****************************************************************************** |
| Description: |
| Set the data response timeout value. |
| Input Parameters: |
| pContext |
| Pointer to MMC context structure |
| CounterValue |
| the value which will be written into DTOCNTR |
| Output Parameters: |
| None |
| Returns: |
| None |
| *******************************************************************************/ |
| void MMC4SetDataTimeout(P_MM4_SDMMC_CONTEXT_T pContext, UINT8_T CounterValue) |
| { |
| P_MM4_CNTL2 pMM4_CNTL2; |
| MM4_CNTL2_UNION MM4_cntl2; |
| |
| // Set the register |
| pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2); |
| MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2; |
| MM4_cntl2.mm4_cntl2_bits.dtocntr = CounterValue; |
| |
| // Write Back |
| *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value; |
| return; |
| } |
| |
| /****************************************************************************** |
| Description: |
| This function will induce a software reset of all MMC4 data lines |
| Input Parameters: |
| pContext |
| Pointer to MMC context structure |
| Output Parameters: |
| None |
| Returns: |
| None |
| *******************************************************************************/ |
| void MMC4CMDSWReset(P_MM4_SDMMC_CONTEXT_T pContext) |
| { |
| P_MM4_CNTL2 pMM4_CNTL2; |
| MM4_CNTL2_UNION MM4_cntl2; |
| |
| // Set the register |
| pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2); |
| MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2; |
| MM4_cntl2.mm4_cntl2_bits.cmdswrst = 1; |
| |
| // Write Back |
| *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value; |
| return; |
| } |
| |
| /****************************************************************************** |
| Description: |
| This function will induce a software reset of all MMC4 data lines |
| Input Parameters: |
| pContext |
| Pointer to MMC context structure |
| Output Parameters: |
| None |
| Returns: |
| None |
| *******************************************************************************/ |
| void MMC4DataSWReset(P_MM4_SDMMC_CONTEXT_T pContext) |
| { |
| P_MM4_CNTL2 pMM4_CNTL2; |
| MM4_CNTL2_UNION MM4_cntl2; |
| |
| // Set the register |
| pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2); |
| MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2; |
| MM4_cntl2.mm4_cntl2_bits.datswrst = 1; |
| |
| // Write Back |
| *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value; |
| return; |
| } |
| |
| /****************************************************************************** |
| Description: |
| This function will induce a full software reset of all MMC4 components except |
| MM4_CAPX |
| Input Parameters: |
| pContext |
| Pointer to MMC context structure |
| Output Parameters: |
| None |
| Returns: |
| None |
| *******************************************************************************/ |
| void MMC4FullSWReset(P_MM4_SDMMC_CONTEXT_T pContext) |
| { |
| P_MM4_CNTL2 pMM4_CNTL2; |
| MM4_CNTL2_UNION MM4_cntl2; |
| |
| // Set the register |
| pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2); |
| MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2; |
| MM4_cntl2.mm4_cntl2_bits.mswrst = 1; |
| |
| // Write Back |
| *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value; |
| return; |
| } |
| |
| /****************************************************************************** |
| Description: |
| Set up the registers of the controller to start the transaction to |
| communicate to the card for data related command. The commands are clearly defined in the MMC |
| specification. |
| Input Parameters: |
| pContext |
| Pointer to MMC context structure |
| Cmd |
| Command Index - See MMC or SD specification |
| argument |
| the argument of the command. MSW is for ARGH and LSW is for ARGL |
| BlockType |
| Multiple or Single Block Type |
| ResType |
| Expected response type |
| Output Parameters: |
| None |
| Returns: |
| None |
| *******************************************************************************/ |
| void MMC4SendDataCommand(P_MM4_SDMMC_CONTEXT_T pContext, |
| UINT_T Cmd, |
| UINT_T Argument, |
| UINT_T BlockType, |
| UINT_T DataDirection, |
| UINT_T ResType, |
| UINT_T DMAMode, |
| UINT_T AutoCmd23En) |
| { |
| MM4_CMD_XFRMD_UNION xfrmd; |
| P_MM4_STATE pMM4_STATE; |
| MM4_STATE_UNION MM4_state; |
| |
| // Make sure the controller is ready to accept the next command |
| pMM4_STATE = (P_MM4_STATE) &pContext->pMMC4Reg->mm4_state; |
| MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE; |
| |
| do |
| { |
| MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE; |
| } while (MM4_state.mm4_state_bits.dcmdinhbt); |
| |
| // Set the Argument Field |
| pContext->pMMC4Reg->mm4_arg = Argument; |
| |
| // Set the Data Transfer Command fields. |
| xfrmd.mm4_cmd_xfrmd_value = 0; |
| xfrmd.mm4_cmd_xfrmd_bits.cmd_idx = Cmd; |
| xfrmd.mm4_cmd_xfrmd_bits.cmd_type = MM4_CMD_TYPE_NORMAL; |
| xfrmd.mm4_cmd_xfrmd_bits.dpsel = MM4_CMD_DATA; |
| // xfrmd.mm4_cmd_xfrmd_bits.idxchken = TRUE; |
| // xfrmd.mm4_cmd_xfrmd_bits.crcchken = TRUE; |
| xfrmd.mm4_cmd_xfrmd_bits.res_type = ResType; |
| xfrmd.mm4_cmd_xfrmd_bits.ms_blksel = BlockType; |
| xfrmd.mm4_cmd_xfrmd_bits.dxfrdir = DataDirection; |
| |
| //if SDMA/ADMA2 |
| if (DMAMode) |
| xfrmd.mm4_cmd_xfrmd_bits.dma_en = TRUE; |
| //CMD23 -> Lets the card know about number of blocks to transfer for the upcoming read/write transaction |
| //AutoCMD23 should be sent prior to CMD18 or CMD25 if ADMA2 is used and BLK_CNT is disabled for ADMA2 |
| //Since AutoCMD23 is sent, AutoCMD12 is not required |
| if(AutoCmd23En) |
| { |
| xfrmd.mm4_cmd_xfrmd_bits.autocmd23 = TRUE; |
| xfrmd.mm4_cmd_xfrmd_bits.blkcnten = TRUE; // block counter is a better choice than send stop command |
| } |
| else |
| { |
| //For PIO and SDMA mode |
| xfrmd.mm4_cmd_xfrmd_bits.autocmd12 = TRUE; |
| xfrmd.mm4_cmd_xfrmd_bits.blkcnten = TRUE; |
| } |
| |
| // Kick off the command |
| pContext->pMMC4Reg->mm4_cmd_xfrmd = xfrmd.mm4_cmd_xfrmd_value; |
| |
| return; |
| } |
| |
| |
| /****************************************************************************** |
| Description: |
| Set up the registers of the controller to start the transaction to |
| communicate to the card for data related command. The commands are clearly defined in the MMC |
| specification. |
| Input Parameters: |
| pContext |
| Pointer to MMC context structure |
| Cmd |
| Command Index - See MMC or SD specification |
| argument |
| the argument of the command. MSW is for ARGH and LSW is for ARGL |
| BlockType |
| Multiple or Single Block Type |
| ResType |
| Expected response type |
| Output Parameters: |
| None |
| Returns: |
| None |
| *******************************************************************************/ |
| void MMC4SendDataCommandNoAuto12(P_MM4_SDMMC_CONTEXT_T pContext, |
| UINT_T Cmd, |
| UINT_T Argument, |
| UINT_T BlockType, |
| UINT_T DataDirection, |
| UINT_T ResType, |
| UINT_T DMAMode, |
| UINT_T Blk_Cnt_Enable) |
| { |
| MM4_CMD_XFRMD_UNION xfrmd; |
| P_MM4_STATE pMM4_STATE; |
| MM4_STATE_UNION MM4_state; |
| |
| // Make sure the controller is ready to accept the next command |
| pMM4_STATE = (P_MM4_STATE) &pContext->pMMC4Reg->mm4_state; |
| MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE; |
| |
| do |
| { |
| MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE; |
| } while (MM4_state.mm4_state_bits.dcmdinhbt); |
| // Set the Argument Field |
| pContext->pMMC4Reg->mm4_arg = Argument; |
| |
| // Set the Data Transfer Command fields. |
| xfrmd.mm4_cmd_xfrmd_value = 0; |
| xfrmd.mm4_cmd_xfrmd_bits.cmd_idx = Cmd; |
| xfrmd.mm4_cmd_xfrmd_bits.cmd_type = MM4_CMD_TYPE_NORMAL; |
| xfrmd.mm4_cmd_xfrmd_bits.dpsel = MM4_CMD_DATA; |
| // xfrmd.mm4_cmd_xfrmd_bits.idxchken = TRUE; |
| // xfrmd.mm4_cmd_xfrmd_bits.crcchken = TRUE; |
| xfrmd.mm4_cmd_xfrmd_bits.res_type = ResType; |
| xfrmd.mm4_cmd_xfrmd_bits.ms_blksel = BlockType; |
| xfrmd.mm4_cmd_xfrmd_bits.dxfrdir = DataDirection; |
| xfrmd.mm4_cmd_xfrmd_bits.autocmd12 = FALSE; |
| |
| if (DMAMode) |
| xfrmd.mm4_cmd_xfrmd_bits.dma_en = TRUE; |
| |
| if(Blk_Cnt_Enable) //Blk_Cnt is not enabled for ADMA2 |
| xfrmd.mm4_cmd_xfrmd_bits.blkcnten = TRUE; |
| |
| // Kick off the command |
| pContext->pMMC4Reg->mm4_cmd_xfrmd = xfrmd.mm4_cmd_xfrmd_value; |
| return; |
| } |
| |
| /****************************************************************************** |
| Description: |
| Set up the registers of the controller to start the transaction to |
| communicate to the card for setup related commands. |
| The commands are clearly defined in the MMC specification. |
| Input Parameters: |
| pContext |
| Pointer to MMC context structure |
| Cmd |
| Command Index - See MMC or SD specification |
| argument |
| the argument of the command. MSW is for ARGH and LSW is for ARGL |
| ResType |
| Expected response type |
| Output Parameters: |
| None |
| Returns: |
| None |
| *******************************************************************************/ |
| void MMC4SendSetupCommand(P_MM4_SDMMC_CONTEXT_T pContext, |
| UINT_T Cmd, |
| UINT_T CmdType, |
| UINT_T Argument, |
| UINT_T ResType) |
| { |
| MM4_CMD_XFRMD_UNION xfrmd; |
| P_MM4_STATE pMM4_STATE; |
| MM4_STATE_UNION MM4_state; |
| UINT_T startTime, endTime; |
| |
| startTime = GetOSCR0(); // get the start time |
| startTime = GetOSCR0(); // get the start time |
| endTime = startTime; |
| |
| // Make sure the controller is ready to accept the next command |
| pMM4_STATE = (P_MM4_STATE) &pContext->pMMC4Reg->mm4_state; |
| MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE; |
| |
| do |
| { |
| endTime = GetOSCR0(); |
| |
| if (OSCR0IntervalInMilli(startTime, endTime) > 200) |
| return; // Let the getresponse routine catch the error |
| |
| MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE; |
| } while (MM4_state.mm4_state_bits.ccmdinhbt); |
| |
| // Set the Argument Field |
| pContext->pMMC4Reg->mm4_arg = Argument; |
| |
| // Set the Data Transfer Command fields. |
| xfrmd.mm4_cmd_xfrmd_value = 0; |
| xfrmd.mm4_cmd_xfrmd_bits.cmd_idx = Cmd; |
| xfrmd.mm4_cmd_xfrmd_bits.cmd_type = CmdType; |
| // xfrmd.mm4_cmd_xfrmd_bits.idxchken = TRUE; |
| xfrmd.mm4_cmd_xfrmd_bits.crcchken = TRUE; |
| xfrmd.mm4_cmd_xfrmd_bits.res_type = ResType; |
| |
| // Kick off the command |
| pContext->pMMC4Reg->mm4_cmd_xfrmd = xfrmd.mm4_cmd_xfrmd_value; |
| return; |
| } |