From patchwork Mon Mar 5 14:40:41 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: mohamed.haneef@lntinfotech.com X-Patchwork-Id: 144692 X-Patchwork-Delegate: afleming@freescale.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 5D85BB6F62 for ; Tue, 6 Mar 2012 01:39:53 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id F2DA4280A6; Mon, 5 Mar 2012 15:39:48 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 46NOkORAO1wY; Mon, 5 Mar 2012 15:39:48 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id E0B46280A9; Mon, 5 Mar 2012 15:39:46 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 449D5280A9 for ; Mon, 5 Mar 2012 15:39:44 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id s+bOKqIYX8vL for ; Mon, 5 Mar 2012 15:39:42 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail1.bemta12.messagelabs.com (mail1.bemta12.messagelabs.com [216.82.250.242]) by theia.denx.de (Postfix) with ESMTPS id 70D84280A6 for ; Mon, 5 Mar 2012 15:39:39 +0100 (CET) Received: from [216.82.249.99:40722] by server-4.bemta-12.messagelabs.com id 90/BB-12849-A20D45F4; Mon, 05 Mar 2012 14:39:38 +0000 X-Env-Sender: Mohamed.Haneef@lntinfotech.com X-Msg-Ref: server-12.tower-142.messagelabs.com!1330958372!125378947!2 X-Originating-IP: [203.101.96.7] X-StarScan-Version: 6.5.5; banners=-,-,- X-VirusChecked: Checked Received: (qmail 8230 invoked from network); 5 Mar 2012 14:39:37 -0000 Received: from unknown (HELO BLRINMSHTCAS01.bglrodc.lntinfotech.com) (203.101.96.7) by server-12.tower-142.messagelabs.com with AES128-SHA encrypted SMTP; 5 Mar 2012 14:39:37 -0000 Received: from INFBA02474.BGLRODC.lntinfotech.com (172.28.9.86) by BLRINMSHTCAS01.bglrodc.lntinfotech.com (172.28.0.81) with Microsoft SMTP Server id 8.2.176.0; Mon, 5 Mar 2012 20:09:28 +0530 From: Mohamed Haneef To: u-boot@lists.denx.de, albert.u.boot@aribaud.net Date: Mon, 5 Mar 2012 20:10:41 +0530 Message-ID: <1330958441-24679-1-git-send-email-mohamed.haneef@lntinfotech.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1329361163-11228-5-git-send-email-mohamed.haneef@lntinfotech.com> References: <1329361163-11228-5-git-send-email-mohamed.haneef@lntinfotech.com> MIME-Version: 1.0 Cc: Mohamed Haneef , srikanth.reddy@lntinfotech.com Subject: [U-Boot] [PATCH v2 4/5] Add Support for qc_mmc MMC Controller X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de * Support for qc_mmc MMC Controller Signed-off-by: Mohamed Haneef --- change for v2: - changed the patch title to "support for qc_mmc MMC Controller" arch/arm/include/asm/arch-msm7630/mmc.h | 399 +++++++++++++++++++++ drivers/mmc/Makefile | 1 + drivers/mmc/qc_mmc.c | 584 +++++++++++++++++++++++++++++++ 3 files changed, 984 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/arch-msm7630/mmc.h create mode 100644 drivers/mmc/qc_mmc.c -- 1.7.1 The contents of this e-mail and any attachment(s) may contain confidential or privileged information for the intended recipient(s). Unintended recipients are prohibited from taking action on the basis of information in this e-mail and using or disseminating the information, and must notify the sender and delete it from their system. L&T Infotech will not accept responsibility or liability for the accuracy or completeness of, or the presence of any virus or disabling code in this e-mail" diff --git a/arch/arm/include/asm/arch-msm7630/mmc.h b/arch/arm/include/asm/arch-msm7630/mmc.h new file mode 100644 index 0000000..949e43c --- /dev/null +++ b/arch/arm/include/asm/arch-msm7630/mmc.h @@ -0,0 +1,399 @@ +/* + * (C) Copyright 2012 + * LARSEN & TOUBRO INFOTECH LTD + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __MMC_H__ +#define __MMC_H__ + +#ifndef MMC_SLOT +#define MMC_SLOT 0 +#endif + +#include +#include +#include + +/* + * Define Macros for SDCC Registers + */ +/* 8 bit */ +#define MMC_BOOT_MCI_POWER 0x000 + +/* MCICMD output control - 6th bit */ +#ifdef PLATFORM_MSM7X30 +#define MMC_BOOT_MCI_OPEN_DRAIN (1 << 6) +#define MMC_BOOT_MCI_PWR_OFF 0x00 +#define MMC_BOOT_MCI_PWR_UP 0x01 +#define MMC_BOOT_MCI_PWR_ON 0x01 +#else +#define MMC_BOOT_MCI_OPEN_DRAIN (1 << 6) +#define MMC_BOOT_MCI_PWR_OFF 0x00 +#define MMC_BOOT_MCI_PWR_UP 0x02 +#define MMC_BOOT_MCI_PWR_ON 0x03 +#endif + +/* 16 bits */ +#define MMC_BOOT_MCI_CLK 0x004 +/* Enable MCI bus clock - 0: clock disabled 1: enabled */ +#define MMC_BOOT_MCI_CLK_ENABLE (1 << 8) +/* Disable clk o/p when bus idle- 0:always enabled 1:enabled when bus active */ +#define MMC_BOOT_MCI_CLK_PWRSAVE (1 << 9) +/* Enable Widebus mode - 00: 1 bit mode 10:4 bit mode 01/11: 8 bit mode */ +#define MMC_BOOT_MCI_CLK_WIDEBUS_MODE (3 << 10) +#define MMC_BOOT_MCI_CLK_WIDEBUS_1_BIT 0 +#define MMC_BOOT_MCI_CLK_WIDEBUS_4_BIT (2 << 10) +#define MMC_BOOT_MCI_CLK_WIDEBUS_8_BIT (1 << 10) +/* Enable flow control- 0: disable 1: enable */ +#define MMC_BOOT_MCI_CLK_ENA_FLOW (1 << 12) +/* Set/clear to select rising/falling edge for data/cmd output */ +#define MMC_BOOT_MCI_CLK_INVERT_OUT (1 << 13) +/* Select to lach data/cmd coming in falling/rising/feedbk/loopbk of MCIclk */ +#define MMC_BOOT_MCI_CLK_IN_FALLING 0x0 +#define MMC_BOOT_MCI_CLK_IN_RISING (1 << 14) +#define MMC_BOOT_MCI_CLK_IN_FEEDBACK (2 << 14) +#define MMC_BOOT_MCI_CLK_IN_LOOPBACK (3 << 14) + +/* Bus Width */ +#define MMC_BOOT_BUS_WIDTH_1_BIT 0 +#define MMC_BOOT_BUS_WIDTH_4_BIT 2 +#define MMC_BOOT_BUS_WIDTH_8_BIT 3 + +/* 32 bits */ +#define MMC_BOOT_MCI_ARGUMENT 0x008 + +/* 16 bits */ +#define MMC_BOOT_MCI_CMD 0x00C +/* Command Index: 0 -5 */ +/* Waits for response if set */ +#define MMC_BOOT_MCI_CMD_RESPONSE (1 << 6) +/* Receives a 136-bit long response if set */ +#define MMC_BOOT_MCI_CMD_LONGRSP (1 << 7) +/* If set, CPSM disables command timer and waits for interrupt */ +#define MMC_BOOT_MCI_CMD_INTERRUPT (1 << 8) +/* If set waits for CmdPend before starting to send a command */ +#define MMC_BOOT_MCI_CMD_PENDING (1 << 9) +/* CPSM is enabled if set */ +#define MMC_BOOT_MCI_CMD_ENABLE (1 << 10) +/* If set PROG_DONE status bit asserted when busy is de-asserted */ +#define MMC_BOOT_MCI_CMD_PROG_ENA (1 << 11) +/* To indicate that this is a Command with Data (for SDIO interrupts) */ +#define MMC_BOOT_MCI_CMD_DAT_CMD (1 << 12) +/* Signals the next command to be an abort (stop) command. Always read 0 */ +#define MMC_BOOT_MCI_CMD_MCIABORT (1 << 13) +/* Waits for Command Completion Signal if set */ +#define MMC_BOOT_MCI_CMD_CCS_ENABLE (1 << 14) +/* If set sends CCS disable sequence */ +#define MMC_BOOT_MCI_CMD_CCS_DISABLE (1 << 15) + +#define MMC_BOOT_MCI_RESP_CMD 0x010 + +#define MMC_BOOT_MCI_RESP_0 0x014 +#define MMC_BOOT_MCI_RESP_1 0x018 +#define MMC_BOOT_MCI_RESP_2 0x01C +#define MMC_BOOT_MCI_RESP_3 0x020 + +#define MMC_BOOT_MCI_DATA_TIMER 0x024 +#define MMC_BOOT_MCI_DATA_LENGTH 0x028 +/* 16 bits */ +#define MMC_BOOT_MCI_DATA_CTL 0x02C +/* Data transfer enabled */ +#define MMC_BOOT_MCI_DATA_ENABLE (1 << 0) +/* Data transfer direction - 0: controller to card 1:card to controller */ +#define MMC_BOOT_MCI_DATA_DIR (1 << 1) +/* Data transfer mode - 0: block data transfer 1: stream data transfer */ +#define MMC_BOOT_MCI_DATA_MODE (1 << 2) +/* Enable DM interface - 0: DM disabled 1: DM enabled */ +#define MMC_BOOT_MCI_DATA_DM_ENABLE (1 << 3) +/* Data block length in bytes (1-4096) */ +#define MMC_BOOT_MCI_BLKSIZE_POS 4 +#define MMC_BOOT_MCI_DATA_COUNT 0x030 +#define MMC_BOOT_MCI_STATUS 0x034 +/* Command response received - CRC check failed */ +#define MMC_BOOT_MCI_STAT_CMD_CRC_FAIL (1 << 0) +/* Data block sent/received - CRC check failed */ +#define MMC_BOOT_MCI_STAT_DATA_CRC_FAIL (1 << 1) +/* Command resonse timeout */ +#define MMC_BOOT_MCI_STAT_CMD_TIMEOUT (1 << 2) +/* Data timeout */ +#define MMC_BOOT_MCI_STAT_DATA_TIMEOUT (1 << 3) +/* Transmit FIFO underrun error */ +#define MMC_BOOT_MCI_STAT_TX_UNDRUN (1 << 4) +/* Receive FIFO overrun error */ +#define MMC_BOOT_MCI_STAT_RX_OVRRUN (1 << 5) +/* Command response received - CRC check passed */ +#define MMC_BOOT_MCI_STAT_CMD_RESP_END (1 << 6) +/* Command sent - no response required */ +#define MMC_BOOT_MCI_STAT_CMD_SENT (1 << 7) +/* Data end - data counter zero */ +#define MMC_BOOT_MCI_STAT_DATA_END (1 << 8) +/* Start bit not detected on all data signals in wide bus mode */ +#define MMC_BOOT_MCI_STAT_START_BIT_ERR (1 << 9) +/* Data block sent/received - CRC check passed */ +#define MMC_BOOT_MCI_STAT_DATA_BLK_END (1 << 10) +/* Command transfer in progress */ +#define MMC_BOOT_MCI_STAT_CMD_ACTIVE (1 << 11) +/* Data transmit in progress */ +#define MMC_BOOT_MCI_STAT_TX_ACTIVE (1 << 12) +/* Data receive in progress */ +#define MMC_BOOT_MCI_STAT_RX_ACTIVE (1 << 13) +/* Transmit FIFO half full */ +#define MMC_BOOT_MCI_STAT_TX_FIFO_HFULL (1 << 14) +/* Receive FIFO half full */ +#define MMC_BOOT_MCI_STAT_RX_FIFO_HFULL (1 << 15) +/* Transmit FIFO full */ +#define MMC_BOOT_MCI_STAT_TX_FIFO_FULL (1 << 16) +/* Receive FIFO full */ +#define MMC_BOOT_MCI_STAT_RX_FIFO_FULL (1 << 17) +/* Transmit FIFO empty */ +#define MMC_BOOT_MCI_STAT_TX_FIFO_EMPTY (1 << 18) +/* Receive FIFO empty */ +#define MMC_BOOT_MCI_STAT_RX_FIFO_EMPTY (1 << 19) +/* Data available in transmit FIFO */ +#define MMC_BOOT_MCI_STAT_TX_DATA_AVLBL (1 << 20) +/* Data available in receive FIFO */ +#define MMC_BOOT_MCI_STAT_RX_DATA_AVLBL (1 << 21) +/* SDIO interrupt indicator for wake-up */ +#define MMC_BOOT_MCI_STAT_SDIO_INTR (1 << 22) +/* Programming done */ +#define MMC_BOOT_MCI_STAT_PROG_DONE (1 << 23) +/* CE-ATA command completion signal detected */ +#define MMC_BOOT_MCI_STAT_ATA_CMD_CMPL (1 << 24) +/* SDIO interrupt indicator for normal operation */ +#define MMC_BOOT_MCI_STAT_SDIO_INTR_OP (1 << 25) +/* Commpand completion signal timeout */ +#define MMC_BOOT_MCI_STAT_CCS_TIMEOUT (1 << 26) + +#define MMC_BOOT_MCI_STATIC_STATUS (MMC_BOOT_MCI_STAT_CMD_CRC_FAIL| \ + MMC_BOOT_MCI_STAT_DATA_CRC_FAIL| \ + MMC_BOOT_MCI_STAT_CMD_TIMEOUT| \ + MMC_BOOT_MCI_STAT_DATA_TIMEOUT| \ + MMC_BOOT_MCI_STAT_TX_UNDRUN| \ + MMC_BOOT_MCI_STAT_RX_OVRRUN| \ + MMC_BOOT_MCI_STAT_CMD_RESP_END| \ + MMC_BOOT_MCI_STAT_CMD_SENT| \ + MMC_BOOT_MCI_STAT_DATA_END| \ + MMC_BOOT_MCI_STAT_START_BIT_ERR| \ + MMC_BOOT_MCI_STAT_DATA_BLK_END| \ + MMC_BOOT_MCI_SDIO_INTR_CLR| \ + MMC_BOOT_MCI_STAT_PROG_DONE| \ + MMC_BOOT_MCI_STAT_ATA_CMD_CMPL |\ + MMC_BOOT_MCI_STAT_CCS_TIMEOUT) + +#define MMC_BOOT_MCI_CLEAR 0x038 +#define MMC_BOOT_MCI_CMD_CRC_FAIL_CLR (1 << 0) +#define MMC_BOOT_MCI_DATA_CRC_FAIL_CLR (1 << 1) +#define MMC_BOOT_MCI_CMD_TIMEOUT_CLR (1 << 2) +#define MMC_BOOT_MCI_DATA_TIMEOUT_CLR (1 << 3) +#define MMC_BOOT_MCI_TX_UNDERRUN_CLR (1 << 4) +#define MMC_BOOT_MCI_RX_OVERRUN_CLR (1 << 5) +#define MMC_BOOT_MCI_CMD_RESP_END_CLR (1 << 6) +#define MMC_BOOT_MCI_CMD_SENT_CLR (1 << 7) +#define MMC_BOOT_MCI_DATA_END_CLR (1 << 8) +#define MMC_BOOT_MCI_START_BIT_ERR_CLR (1 << 9) +#define MMC_BOOT_MCI_DATA_BLK_END_CLR (1 << 10) +#define MMC_BOOT_MCI_SDIO_INTR_CLR (1 << 22) +#define MMC_BOOT_MCI_PROG_DONE_CLR (1 << 23) +#define MMC_BOOT_MCI_ATA_CMD_COMPLR_CLR (1 << 24) +#define MMC_BOOT_MCI_CCS_TIMEOUT_CLR (1 << 25) + +#define MMC_BOOT_MCI_INT_MASK0 0x03C +#define MMC_BOOT_MCI_CMD_CRC_FAIL_MASK (1 << 0) +#define MMC_BOOT_MCI_DATA_CRC_FAIL_MASK (1 << 1) +#define MMC_BOOT_MCI_CMD_TIMEOUT_MASK (1 << 2) +#define MMC_BOOT_MCI_DATA_TIMEOUT_MASK (1 << 3) +#define MMC_BOOT_MCI_TX_OVERRUN_MASK (1 << 4) +#define MMC_BOOT_MCI_RX_OVERRUN_MASK (1 << 5) +#define MMC_BOOT_MCI_CMD_RESP_END_MASK (1 << 6) +#define MMC_BOOT_MCI_CMD_SENT_MASK (1 << 7) +#define MMC_BOOT_MCI_DATA_END_MASK (1 << 8) +#define MMC_BOOT_MCI_START_BIT_ERR_MASK (1 << 9) +#define MMC_BOOT_MCI_DATA_BLK_END_MASK (1 << 10) +#define MMC_BOOT_MCI_CMD_ACTIVE_MASK (1 << 11) +#define MMC_BOOT_MCI_TX_ACTIVE_MASK (1 << 12) +#define MMC_BOOT_MCI_RX_ACTIVE_MASK (1 << 13) +#define MMC_BOOT_MCI_TX_FIFO_HFULL_MASK (1 << 14) +#define MMC_BOOT_MCI_RX_FIFO_HFULL_MASK (1 << 15) +#define MMC_BOOT_MCI_TX_FIFO_FULL_MASK (1 << 16) +#define MMC_BOOT_MCI_RX_FIFO_FULL_MASK (1 << 17) +#define MMC_BOOT_MCI_TX_FIFO_EMPTY_MASK (1 << 18) +#define MMC_BOOT_MCI_RX_FIFO_EMPTY_MASK (1 << 19) +#define MMC_BOOT_MCI_TX_DATA_AVLBL_MASK (1 << 20) +#define MMC_BOOT_MCI_RX_DATA_AVLBL_MASK (1 << 21) +#define MMC_BOOT_MCI_SDIO_INT_MASK (1 << 22) +#define MMC_BOOT_MCI_PROG_DONE_MASK (1 << 23) +#define MMC_BOOT_MCI_ATA_CMD_COMPL_MASK (1 << 24) +#define MMC_BOOT_MCI_SDIO_INT_OPER_MASK (1 << 25) +#define MMC_BOOT_MCI_CCS_TIME_OUT_MASK (1 << 26) + +#define MMC_BOOT_MCI_INT_MASK1 0x040 + +#define MMC_BOOT_MCI_FIFO_COUNT 0x044 + +#define MMC_BOOT_MCI_CCS_TIMER 0x0058 + +#define MMC_BOOT_MCI_FIFO 0x080 + +/* OCR Register */ +#define MMC_BOOT_OCR_17_19 (1 << 7) +#define MMC_BOOT_OCR_27_36 (0x1FF << 15) +#define MMC_BOOT_OCR_SEC_MODE (2 << 29) +#define MMC_BOOT_OCR_BUSY (1 << 31) + +/* Commands type */ +#define MMC_BOOT_CMD_BCAST (1 << 0) +#define MMC_BOOT_CMD_BCAST_W_RESP (1 << 1) +#define MMC_BOOT_CMD_ADDRESS (1 << 2) +#define MMC_BOOT_CMD_ADDR_DATA_XFER (1 << 3) + +/* Card Status bits (R1 register) */ +#define MMC_BOOT_R1_AKE_SEQ_ERROR (1 << 3) +#define MMC_BOOT_R1_APP_CMD (1 << 5) +#define MMC_BOOT_R1_RDY_FOR_DATA (1 << 6) +#define MMC_BOOT_R1_CURR_STATE_IDLE (0 << 9) +#define MMC_BOOT_R1_CURR_STATE_RDY (1 << 9) +#define MMC_BOOT_R1_CURR_STATE_IDENT (2 << 9) +#define MMC_BOOT_R1_CURR_STATE_STBY (3 << 9) +#define MMC_BOOT_R1_CURR_STATE_TRAN (4 << 9) +#define MMC_BOOT_R1_CURR_STATE_DATA (5 << 9) +#define MMC_BOOT_R1_CURR_STATE_RCV (6 << 9) +#define MMC_BOOT_R1_CURR_STATE_PRG (7 << 9) +#define MMC_BOOT_R1_CURR_STATE_DIS (8 << 9) +#define MMC_BOOT_R1_ERASE_RESET (1 << 13) +#define MMC_BOOT_R1_CARD_ECC_DISABLED (1 << 14) +#define MMC_BOOT_R1_WP_ERASE_SKIP (1 << 15) +#define MMC_BOOT_R1_ERROR (1 << 19) +#define MMC_BOOT_R1_CC_ERROR (1 << 20) +#define MMC_BOOT_R1_CARD_ECC_FAILED (1 << 21) +#define MMC_BOOT_R1_ILLEGAL_CMD (1 << 22) +#define MMC_BOOT_R1_COM_CRC_ERR (1 << 23) +#define MMC_BOOT_R1_LOCK_UNLOCK_FAIL (1 << 24) +#define MMC_BOOT_R1_CARD_IS_LOCKED (1 << 25) +#define MMC_BOOT_R1_WP_VIOLATION (1 << 26) +#define MMC_BOOT_R1_ERASE_PARAM (1 << 27) +#define MMC_BOOT_R1_ERASE_SEQ_ERR (1 << 28) +#define MMC_BOOT_R1_BLOCK_LEN_ERR (1 << 29) +#define MMC_BOOT_R1_ADDR_ERR (1 << 30) +#define MMC_BOOT_R1_OUT_OF_RANGE (1 << 31) + +/* Macros for Common Errors */ +#define MMC_BOOT_E_SUCCESS 0 +#define MMC_BOOT_E_FAILURE 1 +/* Not used..use instead TIMEOUT in include/mmc.h */ +#define MMC_BOOT_E_TIMEOUT 2 +#define MMC_BOOT_E_INVAL 3 +#define MMC_BOOT_E_CRC_FAIL 4 +#define MMC_BOOT_E_INIT_FAIL 5 +#define MMC_BOOT_E_CMD_INDX_MISMATCH 6 +#define MMC_BOOT_E_RESP_VERIFY_FAIL 7 +#define MMC_BOOT_E_NOT_SUPPORTED 8 +#define MMC_BOOT_E_CARD_BUSY 9 +#define MMC_BOOT_E_MEM_ALLOC_FAIL 10 +#define MMC_BOOT_E_CLK_ENABLE_FAIL 11 +#define MMC_BOOT_E_CMMC_DECODE_FAIL 12 +#define MMC_BOOT_E_CID_DECODE_FAIL 13 +#define MMC_BOOT_E_BLOCKLEN_ERR 14 +#define MMC_BOOT_E_ADDRESS_ERR 15 +#define MMC_BOOT_E_DATA_CRC_FAIL 16 +#define MMC_BOOT_E_DATA_TIMEOUT 17 +#define MMC_BOOT_E_RX_OVRRUN 18 +#define MMC_BOOT_E_VREG_SET_FAILED 19 +#define MMC_BOOT_E_GPIO_CFG_FAIL 20 +#define MMC_BOOT_E_DATA_ADM_ERR 21 + +/* EXT_CSD */ +#define MMC_BOOT_ACCESS_WRITE 0x3 +#define MMC_BOOT_EXT_CMMC_HS_TIMING 185 +#define MMC_BOOT_EXT_CMMC_BUS_WIDTH 183 + +#define MMC_BOOT_EXT_USER_WP 171 +#define MMC_BOOT_EXT_ERASE_GROUP_DEF 175 +#define MMC_BOOT_EXT_HC_WP_GRP_SIZE 221 +#define MMC_BOOT_EXT_HC_ERASE_GRP_SIZE 224 + +#define MMC_BOOT_US_PERM_WP_EN 2 +#define MMC_BOOT_US_PWR_WP_DIS 3 + +#define MMC_BOOT_US_PERM_WP_DIS (1<<4) +#define MMC_BOOT_US_PWR_WP_EN 1 + +/* For SD */ +#define MMC_BOOT_SD_HC_VOLT_SUPPLIED 0x000001AA +#define MMC_BOOT_SD_NEG_OCR 0x00FF8000 +#define MMC_BOOT_SD_HC_HCS 0x40000000 +#define MMC_BOOT_SD_DEV_READY 0x80000000 +#define MMC_BOOT_SD_SWITCH_HS 0x80FFFFF1 + +/* Data structure definitions */ + +#define MMC_BOOT_XFER_MODE_BLOCK 0 +#define MMC_BOOT_XFER_MODE_STREAM 1 +#define MMC_BOOT_PROGRAM_ENABLED 2 + + +#define MMC_RCA 2 + +#define MMC_BOOT_MAX_COMMAND_RETRY 1000 +#define MMC_BOOT_RD_BLOCK_LEN 512 +#define MMC_BOOT_WR_BLOCK_LEN 512 + +/* We have 16 32-bits FIFO registers */ +#define MMC_BOOT_MCI_FIFO_DEPTH 16 +#define MMC_BOOT_MCI_HFIFO_COUNT (MMC_BOOT_MCI_FIFO_DEPTH / 2) +#define MMC_BOOT_MCI_FIFO_SIZE (MMC_BOOT_MCI_FIFO_DEPTH * 4) + +#define MAX_PARTITIONS 64 + +#define MMC_BOOT_CHECK_PATTERN 0xAA /* 10101010b */ + +#define MMC_CLK_400KHZ 400000 +#define MMC_CLK_144KHZ 144000 +#define MMC_CLK_20MHZ 20000000 +#define MMC_CLK_24MHZ 24000000 +#define MMC_CLK_25MHZ 25000000 +#define MMC_CLK_26MHZ 26000000 +#define MMC_CLK_48MHZ 48000000 +#define MMC_CLK_50MHZ 49152000 +#define MMC_CLK_52MHZ 52000000 + +#define MMC_CLK_ENABLE 1 +#define MMC_CLK_DISABLE 0 + +#if 0 +#define MSM_SDC1_BASE 0x12400000 +#define MSM_SDC2_BASE 0x12140000 +#define MSM_SDC3_BASE 0x12180000 +#define MSM_SDC4_BASE 0x121C0000 +#endif +struct mmc_priv { + unsigned int instance; + unsigned int base; + unsigned int rd_timeout_ns; /* for read timeout */ +}; + +void mmc_boot_set_ios(struct mmc *mmc); +int mmc_boot_send_command_map(struct mmc *mmc, + struct mmc_cmd *cmd, + struct mmc_data *data); +unsigned long int mmc_boot_mci_reg(unsigned long base, unsigned long offset); +unsigned int mmc_boot_main(struct mmc *mmc); + +extern void clock_config_mmc(uint32_t interface, uint32_t freq); +extern void clock_init_mmc(uint32_t interface); +#endif + diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 506f1d6..2d926ec 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -44,6 +44,7 @@ COBJS-$(CONFIG_S5P_MMC) += s5p_mmc.o COBJS-$(CONFIG_SDHCI) += sdhci.o COBJS-$(CONFIG_SH_MMCIF) += sh_mmcif.o COBJS-$(CONFIG_TEGRA2_MMC) += tegra2_mmc.o +COBJS-$(CONFIG_QC_MMC) += qc_mmc.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/mmc/qc_mmc.c b/drivers/mmc/qc_mmc.c new file mode 100644 index 0000000..7b7a1ed --- /dev/null +++ b/drivers/mmc/qc_mmc.c @@ -0,0 +1,584 @@ +/* + * (C) Copyright 2012 + * LARSEN & TOUBRO INFOTECH LTD + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include + +#if MMC_BOOT_ADM +#include "adm.h" +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#define MMC_BOOT_DATA_READ 0 +#define MMC_BOOT_DATA_WRITE 1 +/* + * Calculates the address of registers according to the base address + */ +unsigned long int mmc_boot_mci_reg(unsigned long base, unsigned long offset) +{ + return base + offset; +} + + +/* + * Sets a timeout for read operation. + */ +static unsigned int mmc_boot_set_read_timeout(struct mmc *mmc) +{ + if (mmc == NULL) + return MMC_BOOT_E_INVAL; + + /* todo: Add a check for HC, only if HC do this. + * If not, taac and nsac must be taken into account + */ + ((struct mmc_priv *)(mmc->priv))->rd_timeout_ns = 100000000; + debug(" Read timeout set: %d ns\n", + ((struct mmc_priv *)(mmc->priv))->rd_timeout_ns); + + return MMC_BOOT_E_SUCCESS; +} + +/* + * Check to ensure that there is no alignment or data length errors + */ +static unsigned int mmc_boot_check_read_data(struct mmc_cmd *cmd) +{ + + if (cmd->response[0] & MMC_BOOT_R1_BLOCK_LEN_ERR) + return MMC_BOOT_E_BLOCKLEN_ERR; + + /* Misaligned address not matching block length */ + if (cmd->response[0] & MMC_BOOT_R1_ADDR_ERR) + return MMC_BOOT_E_ADDRESS_ERR; + + return MMC_BOOT_E_SUCCESS; +} + +/* + * Decode type of error caused during read and write + */ +static unsigned int mmc_boot_status_error(unsigned mmc_status) +{ + unsigned int mmc_ret = MMC_BOOT_E_SUCCESS; + + /* If DATA_CRC_FAIL bit is set to 1 then CRC error + * was detected by card/device during the data transfer + */ + if (mmc_status & MMC_BOOT_MCI_STAT_DATA_CRC_FAIL) + mmc_ret = MMC_BOOT_E_DATA_CRC_FAIL; + /* If DATA_TIMEOUT bit is set to 1 then the data transfer time + * exceeded the data timeout period without completing the + * transfer + */ + else if (mmc_status & MMC_BOOT_MCI_STAT_DATA_TIMEOUT) + mmc_ret = MMC_BOOT_E_DATA_TIMEOUT; + /* If RX_OVERRUN bit is set to 1 then SDCC2 tried to + * receive data from the card before empty storage for new + * received data was available. + * Verify that bit FLOW_ENA in MCI_CLK is set to 1 during + * the data xfer. + */ + else if (mmc_status & MMC_BOOT_MCI_STAT_RX_OVRRUN) + /* Note: We've set FLOW_ENA bit in MCI_CLK to 1. + * so no need to verify for now + */ + mmc_ret = MMC_BOOT_E_RX_OVRRUN; + /* If TX_UNDERRUN bit is set to 1 then SDCC2 tried to send + * data to the card before new data for sending was available. + * Verify that bit FLOW_ENA in MCI_CLK + * is set to 1 during the data xfer. + */ + else if (mmc_status & MMC_BOOT_MCI_STAT_TX_UNDRUN) + /* Note: We've set FLOW_ENA bit in MCI_CLK to 1. + * so skipping it now + */ + mmc_ret = MMC_BOOT_E_RX_OVRRUN; + + return mmc_ret; +} + +/* + * Read data to SDC FIFO. + */ +static unsigned int mmc_boot_fifo_read(unsigned int *mmc_ptr, + unsigned int data_len, + struct mmc *mmc) +{ + unsigned int mmc_ret = MMC_BOOT_E_SUCCESS; + unsigned int mmc_status = 0; + unsigned int mmc_count = 0; + unsigned int read_error = MMC_BOOT_MCI_STAT_DATA_CRC_FAIL | \ + MMC_BOOT_MCI_STAT_DATA_TIMEOUT | \ + MMC_BOOT_MCI_STAT_RX_OVRRUN; + unsigned int i; + struct mmc_priv *priv = (struct mmc_priv *)mmc->priv; + unsigned long reg_status, reg_fifo; + + reg_status = mmc_boot_mci_reg(priv->base, MMC_BOOT_MCI_STATUS); + reg_fifo = mmc_boot_mci_reg(priv->base, MMC_BOOT_MCI_FIFO); + + /* Read the data from the MCI_FIFO register as long as + * RXDATA_AVLBL bit of MCI_STATUS register is set to 1 and bits + * DATA_CRC_FAIL, DATA_TIMEOUT, RX_OVERRUN of MCI_STATUS + * register are cleared to 0. + * Continue the reads until the whole transfer data is received + */ + + do { + mmc_ret = MMC_BOOT_E_SUCCESS; + mmc_status = readl(reg_status); + + if (mmc_status & read_error) { + mmc_ret = mmc_boot_status_error(mmc_status); + break; + } + + if (mmc_status & MMC_BOOT_MCI_STAT_RX_DATA_AVLBL) { + unsigned read_count = 1; + if (mmc_status & MMC_BOOT_MCI_STAT_RX_FIFO_HFULL) + read_count = MMC_BOOT_MCI_HFIFO_COUNT; + + for (i = 0; i < read_count; i++) { + /* FIFO contains 16 32-bit data buffer + * on 16 sequential addresses + */ + *mmc_ptr = readl(reg_fifo + + (mmc_count % MMC_BOOT_MCI_FIFO_SIZE)); + mmc_ptr++; + /* increase mmc_count by word size */ + mmc_count += sizeof(unsigned int); + } + /* quit if we have read enough of data */ + if (mmc_count == data_len) + break; + } else if (mmc_status & MMC_BOOT_MCI_STAT_DATA_END) + break; + } while (1); + return mmc_ret; +} + +static unsigned int mmc_boot_fifo_data_transfer(unsigned int *data_ptr, + unsigned int data_len, + unsigned char direction, + struct mmc *mmc) +{ + unsigned int mmc_ret = MMC_BOOT_E_SUCCESS; + + if (direction == MMC_BOOT_DATA_READ) + mmc_ret = mmc_boot_fifo_read(data_ptr, data_len, mmc); + + return mmc_ret; +} + +/* + * Sends specified command to a card and waits for a response. + */ +static unsigned int mmc_boot_send_command(struct mmc_cmd *cmd, + struct mmc *mmc) +{ + unsigned int mmc_cmd = 0; + unsigned int mmc_status = 0; + unsigned int mmc_resp = 0; + unsigned int mmc_return = MMC_BOOT_E_SUCCESS; + unsigned int cmd_index = 0; + int i = 0; + unsigned long reg, reg_status, reg_resp_cmd, reg_resp_0; + struct mmc_priv *priv = (struct mmc_priv *)mmc->priv; + + /* basic check */ + if (cmd == NULL) + return MMC_BOOT_E_INVAL; + + /* 1. Write command argument to MMC_BOOT_MCI_ARGUMENT register */ + reg = mmc_boot_mci_reg(priv->base, MMC_BOOT_MCI_ARGUMENT); + writel(cmd->cmdarg, reg); + + /* Writes to MCI port are not effective for 3 ticks of PCLK. + * ticks calculated using 400KHz clock speed + */ + udelay(8); + + /* 2. Set appropriate fields and write MMC_BOOT_MCI_CMD */ + /* 2a. Write command index in CMD_INDEX field */ + cmd_index = cmd->cmdidx; + mmc_cmd |= cmd->cmdidx; + /* 2b. Set RESPONSE bit to 1 for all cmds except CMD0 */ + if (cmd_index != MMC_CMD_GO_IDLE_STATE) + mmc_cmd |= MMC_BOOT_MCI_CMD_RESPONSE; + + /* 2c. Set LONGRESP bit to 1 for CMD2, CMD9 and CMD10 */ + if (cmd->resp_type & MMC_RSP_136) + mmc_cmd |= MMC_BOOT_MCI_CMD_LONGRSP; + + /* 2d. Set INTERRUPT bit to 1 to disable command timeout */ + + /* 2e. Set PENDING bit to 1 for CMD12 in the beginning of stream + * mode data transfer + */ + if (cmd->flags & MMC_BOOT_XFER_MODE_STREAM) + mmc_cmd |= MMC_BOOT_MCI_CMD_PENDING; + + /* 2f. Set ENABLE bit to 1 */ + mmc_cmd |= MMC_BOOT_MCI_CMD_ENABLE; + + /* 2g. Set PROG_ENA bit to 1 for CMD12, CMD13 issued at the end of + * write data transfer + */ + if ((cmd_index == MMC_CMD_STOP_TRANSMISSION || + cmd_index == MMC_CMD_SEND_STATUS) && + (cmd->flags & MMC_BOOT_PROGRAM_ENABLED)) + mmc_cmd |= MMC_BOOT_MCI_CMD_PROG_ENA; + + + /* 2h. Set MCIABORT bit to 1 for CMD12 when working with SDIO card */ + /* 2i. Set CCS_ENABLE bit to 1 for CMD61 when Command Completion Signal + * of CE-ATA device is enabled + */ + + /* 2j. clear all static status bits */ + reg = mmc_boot_mci_reg(priv->base, MMC_BOOT_MCI_CLEAR); + writel(MMC_BOOT_MCI_STATIC_STATUS, reg); + + /* 2k. Write to MMC_BOOT_MCI_CMD register */ + reg = mmc_boot_mci_reg(priv->base, MMC_BOOT_MCI_CMD); + writel(mmc_cmd, reg); + + /* Writes to MCI port are not effective for 3 ticks of PCLK. + * ticks calculated using 400KHz clock speed + */ + udelay(8); + + reg_status = mmc_boot_mci_reg(priv->base, MMC_BOOT_MCI_STATUS); + reg_resp_cmd = mmc_boot_mci_reg(priv->base, MMC_BOOT_MCI_RESP_CMD); + reg_resp_0 = mmc_boot_mci_reg(priv->base, MMC_BOOT_MCI_RESP_0); + + /* 3. Wait for interrupt or poll on the following bits of MCI_STATUS + * register + */ + do { + /* 3a. Read MCI_STATUS register */ + mmc_status = readl(reg_status); + while (mmc_status & MMC_BOOT_MCI_STAT_CMD_ACTIVE) + mmc_status = readl(reg_status); + + /* 3b. CMD_SENT bit supposed to be set to 1 only + * after CMD0 is sent -no response required. + */ + if ((cmd->resp_type == MMC_RSP_NONE) && + (mmc_status & MMC_BOOT_MCI_STAT_CMD_SENT)) + break; + + /* 3c. If CMD_TIMEOUT bit is set then no response + * was received */ + else if (mmc_status & MMC_BOOT_MCI_STAT_CMD_TIMEOUT) { + mmc_return = TIMEOUT; + break; + } + /* 3d. If CMD_RESPONSE_END bit is set to 1 then command's + * response was received and CRC check passed + * Spcial case for ACMD41: it seems to always fail CRC even if + * the response is valid + */ + else if ((mmc_status & MMC_BOOT_MCI_STAT_CMD_RESP_END) || + (cmd_index == MMC_CMD_SEND_OP_COND) + || (cmd_index == SD_CMD_SEND_IF_COND)) { + /* 3i. Read MCI_RESP_CMD register to verify that + * response index is equal to command index + */ + mmc_resp = readl(reg_resp_cmd) & 0x3F; + + /* However, long response does not contain the + * command index field. + * In that case, response index field must be set to + * 111111b (0x3F) + */ + if ((mmc_resp == cmd_index) || + (cmd->resp_type == MMC_RSP_R2 || + cmd->resp_type == MMC_RSP_R3 || + cmd->resp_type == MMC_RSP_R6 || + cmd->resp_type == MMC_RSP_R7)){ + /* 3j. If resp index is equal to cmd index, + * read command resp from MCI_RESPn registers + * - MCI_RESP0/1/2/3 for CMD2/9/10 + * - MCI_RESP0 for all other registers + */ + if (cmd->resp_type & MMC_RSP_136) { + for (i = 0; i < 4; i++) + cmd->response[3-i] = + readl(reg_resp_0 + \ + (i * 4)); + } else + cmd->response[0] = readl(reg_resp_0); + } else + /* command index mis-match */ + mmc_return = MMC_BOOT_E_CMD_INDX_MISMATCH; + + break; + } + + /* 3e. If CMD_CRC_FAIL bit is set to 1 then cmd's response + * was recvd, but CRC check failed. + */ + else if ((mmc_status & MMC_BOOT_MCI_STAT_CMD_CRC_FAIL)) { + if (cmd_index == SD_CMD_APP_SEND_OP_COND) + cmd->response[0] = readl(reg_resp_0); + else + mmc_return = MMC_BOOT_E_CRC_FAIL; + break; + } + + } while (1); + + return mmc_return; +} + +static void mmc_boot_init_data(struct mmc *mmc, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + uint32_t data_ctrl, mmc_reg, data_len; + struct mmc_priv *priv = (struct mmc_priv *)mmc->priv; + unsigned long reg; + + /* Write data timeout period to MCI_DATA_TIMER register. */ + /* Data timeout period should be in card bus clock periods */ + mmc_reg = (unsigned long)(((struct mmc_priv *) + (mmc->priv))->rd_timeout_ns / + 1000000) * (mmc->clock / 1000); + /* add some extra clock cycles to be safe */ + mmc_reg += 1000; + mmc_reg = mmc_reg/2; + + reg = mmc_boot_mci_reg(priv->base, MMC_BOOT_MCI_DATA_TIMER); + writel(mmc_reg, reg); + + /* Write the total size of the transfer data to MCI_DATA_LENGTH + * register. For block xfer it must be multiple of the block + * size. + */ + + data_len = data->blocks*data->blocksize; + reg = mmc_boot_mci_reg(priv->base, MMC_BOOT_MCI_DATA_LENGTH); + writel(data_len, reg); + + /* Writes to MCI port are not effective for 3 ticks of PCLK. + * ticks calculated using 400KHz clock speed + */ + udelay(8); + + data_ctrl = MMC_BOOT_MCI_DATA_ENABLE | + (data->blocksize << MMC_BOOT_MCI_BLKSIZE_POS); + + + if (data->flags == MMC_DATA_READ) + data_ctrl |= MMC_BOOT_MCI_DATA_DIR; + + reg = mmc_boot_mci_reg(priv->base, MMC_BOOT_MCI_DATA_CTL); + writel(data_ctrl, reg); + + /* Writes to MCI port are not effective for 3 ticks of PCLK. + * ticks calculated using 400KHz clock speed + */ + udelay(8); + +} + +/* + * Function to map mmc send command to board send command + */ +int mmc_boot_send_command_map(struct mmc *mmc, + struct mmc_cmd *cmd, + struct mmc_data *data) +{ + unsigned int mmc_ret = MMC_BOOT_E_SUCCESS; + + /* todo: do we need to fill in command type ?? */ + + if (cmd->cmdidx == MMC_CMD_SEND_STATUS) { + /* u-boot doesn't fill in the correct argument value */ + cmd->cmdarg = mmc->rca << 16; + /* this is to explicitly disable the prg enabled flag */ + cmd->flags &= ~MMC_BOOT_PROGRAM_ENABLED; + + } else if (cmd->cmdidx == MMC_CMD_READ_SINGLE_BLOCK) { + if (mmc->read_bl_len != MMC_BOOT_RD_BLOCK_LEN && + mmc->version & SD_VERSION_SD) { + mmc->read_bl_len = MMC_BOOT_RD_BLOCK_LEN; + data->blocksize = MMC_BOOT_RD_BLOCK_LEN; + } + } else if (cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) { + if (mmc->read_bl_len != MMC_BOOT_RD_BLOCK_LEN && + mmc->version & SD_VERSION_SD) { + mmc->read_bl_len = MMC_BOOT_RD_BLOCK_LEN; + data->blocksize = MMC_BOOT_RD_BLOCK_LEN; + } + } else if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) { + /* explicitly disable the prg enabled flag */ + cmd->flags &= ~MMC_BOOT_PROGRAM_ENABLED; + /* set the XFER mode */ + cmd->flags |= MMC_BOOT_XFER_MODE_BLOCK; + } + + + /* For Data cmd's */ + if (data != NULL) + mmc_boot_init_data(mmc, cmd, data); + + /* send command */ + mmc_ret = mmc_boot_send_command(cmd, mmc); + + if (mmc_ret != MMC_BOOT_E_SUCCESS) { + debug("Return Error = %d\n", mmc_ret); + return mmc_ret; + } + + if (data != NULL) { + mmc_ret = mmc_boot_check_read_data(cmd); + if (mmc_ret) + return mmc_ret; + mmc_boot_fifo_data_transfer((unsigned int *) data->dest, + data->blocks * data->blocksize, + MMC_BOOT_DATA_READ, + mmc); + } + + if (cmd->cmdidx == MMC_CMD_SEND_CSD) { + /* Set read timeout once csd is received */ + mmc_ret = mmc_boot_set_read_timeout(mmc); + if (mmc_ret != MMC_BOOT_E_SUCCESS) { + printf("Error No.%d: Failure setting \ + write Timeout value!\n", + mmc_ret); + return mmc_ret; + } + } else if ((cmd->cmdidx == SD_CMD_SWITCH_FUNC) && (data != NULL)) { + /* cmd6 needs at least 8 clocks after the + * End Data of Status. + * ticks calculated using 400KHz clock speed + */ + udelay(20); + } + + return mmc_ret; +} + +/* + * Initialize host structure, set and enable clock-rate and power mode. + */ +unsigned int mmc_boot_init(struct mmc *mmc) +{ + unsigned int mmc_pwr = 0; + struct mmc_priv *priv = (struct mmc_priv *) mmc->priv; + int mmc_slot = priv->instance; + unsigned long reg; + + /* Initialize any clocks needed for SDC controller */ + clock_init_mmc(mmc_slot); + + /* Setup initial freq to 400KHz */ + clock_config_mmc(mmc_slot, MMC_CLK_400KHZ); + + /* set power mode*/ + mmc_pwr &= ~MMC_BOOT_MCI_PWR_UP; + mmc_pwr |= MMC_BOOT_MCI_PWR_ON; + mmc_pwr |= MMC_BOOT_MCI_PWR_UP; + reg = mmc_boot_mci_reg(priv->base, MMC_BOOT_MCI_POWER); + writel(mmc_pwr, reg); + + /* Writes to MCI port are not effective for 3 ticks of PCLK. + * ticks calculated using 400KHz clock speed + */ + udelay(8); + + return MMC_BOOT_E_SUCCESS; +} + +static unsigned int mmc_boot_set_bus_width(unsigned int width, + struct mmc *mmc) +{ + unsigned int mmc_reg; + struct mmc_priv *priv = (struct mmc_priv *)mmc->priv; + unsigned long reg; + + /* set MCI_CLK accordingly */ + reg = mmc_boot_mci_reg(priv->base, MMC_BOOT_MCI_CLK); + mmc_reg = readl(reg); + mmc_reg &= ~MMC_BOOT_MCI_CLK_WIDEBUS_MODE; + if (width == 1) + mmc_reg |= MMC_BOOT_MCI_CLK_WIDEBUS_1_BIT; + else if (width == 4) + mmc_reg |= MMC_BOOT_MCI_CLK_WIDEBUS_4_BIT; + else if (width == 8) + mmc_reg |= MMC_BOOT_MCI_CLK_WIDEBUS_8_BIT; + else + return MMC_BOOT_E_INVAL; + + writel(mmc_reg, reg); + + /* Writes to MCI port are not effective for 3 ticks of PCLK. + * ticks calculated using 400KHz clock speed + */ + udelay(8); + + debug("Setting bus width to %d\n", width); + return MMC_BOOT_E_SUCCESS; +} + +void mmc_boot_set_ios(struct mmc *mmc) +{ + unsigned int mmc_ret = MMC_BOOT_E_SUCCESS; + struct mmc_priv *priv = (struct mmc_priv *)mmc->priv; + int mmc_slot = priv->instance; + + /* clock frequency should be less than 400KHz in identification mode */ + clock_config_mmc(mmc_slot, mmc->clock); + /* + * give atleast 2 MCLK cycles delay for clocks + * and SDCC core to stabilize. + * ticks calculated using 400KHz clock speed + */ + udelay(5); + mmc_ret = mmc_boot_set_bus_width(mmc->bus_width, mmc); + if (mmc_ret != MMC_BOOT_E_SUCCESS) + printf("Set bus width error %d\n", mmc_ret); +} + +/* + * Board specific initializations + */ +unsigned int mmc_boot_main(struct mmc *mmc) +{ + unsigned int mmc_ret = MMC_BOOT_E_SUCCESS; + + /* Initialize necessary data structure and enable/set clock and power */ + debug(" Initializing MMC host data structure and clock!\n"); + mmc_ret = mmc_boot_init(mmc); + if (mmc_ret != MMC_BOOT_E_SUCCESS) { + printf("MMC Boot: Error Initializing MMC Card!!!\n"); + return MMC_BOOT_E_FAILURE; + } + + return MMC_BOOT_E_SUCCESS; +}