Skip to contentSkip to conversation

Add support for mmc read and writes

PATCH In review mohamed.haneef at lntinfotech.com 3 participants 5 messages Feb 16, 2012 – May 10, 2012

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 4/5 Add support for mmc read and writes

From: Mohamed Haneef <[email protected]>

*Support for msm7x30 mmc read and writes

---
 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
arch/arm/include/asm/arch-msm7630/mmc.h new file +399 -0
new file mode 100644
index 0000000..949e43c
@@ -0,0 +1,399 @@
+/*
+ * (C) Copyright 2012
+ * LARSEN & TOUBRO INFOTECH LTD <www.lntinfotech.com>
+ *
+ * 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 <common.h>
+#include <part.h>
+#include <mmc.h>
+
+/*
+ * 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
+
drivers/mmc/Makefile +1 -0
index 506f1d6..2d926ec 100644
@@ -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)
drivers/mmc/qc_mmc.c new file +584 -0

584 lines not on this page · raw message

--
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"

#1 lore raw

PATCH 4/5 Add support for mmc read and writes

Hi Mohamed,

Le 16/02/2012 03:59, mohamed.haneef at lntinfotech.com a ?crit :

Quoted 3 lines

From: Mohamed Haneef<[email protected]>

*Support for msm7x30 mmc read and writes

The patch title is misleading. MMC reads and writes are already supported in U-Boot; what you add is support for the qc_mc MMC controller.

Amicalement,

Signature · 1 line
Albert.
#2 lore raw

PATCH v2 4/5 Add Support for qc_mmc MMC Controller

In reply to mohamed.haneef at lntinfotech.com

* Support for qc_mmc MMC Controller

---
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
arch/arm/include/asm/arch-msm7630/mmc.h new file +399 -0
new file mode 100644
index 0000000..949e43c
@@ -0,0 +1,399 @@
+/*
+ * (C) Copyright 2012
+ * LARSEN & TOUBRO INFOTECH LTD <www.lntinfotech.com>
+ *
+ * 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 <common.h>
+#include <part.h>
+#include <mmc.h>
+
+/*
+ * 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
+
drivers/mmc/Makefile +1 -0
index 506f1d6..2d926ec 100644
@@ -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)
drivers/mmc/qc_mmc.c new file +584 -0

584 lines not on this page · raw message

--
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"

#3 lore raw

PATCH v2 4/5 Add Support for qc_mmc MMC Controller

NAK, allow me to explain below:

arch/arm/include/asm/arch-msm7630/mmc.h line 26

Quoted 10 lines · Mohamed Haneef

? ? ? ?* Support for qc_mmc MMC Controller

---

arch/arm/include/asm/arch-msm7630/mmc.h new file +6 -0
+#ifndef __MMC_H__
+#define __MMC_H__
+
+#ifndef MMC_SLOT
+#define MMC_SLOT ? ? ? ? ? ?0
+#endif

This sort of thing should probably be passed in by the board code.

Review

Quoted 7 lines
(quoted diff) +7 -0
+
+#if 0
+#define MSM_SDC1_BASE ? ? ? 0x12400000
+#define MSM_SDC2_BASE ? ? ? 0x12140000
+#define MSM_SDC3_BASE ? ? ? 0x12180000
+#define MSM_SDC4_BASE ? ? ? 0x121C0000
+#endif

Why's this still here?

Quoted 6 lines
drivers/mmc/qc_mmc.c new file +0 -0
new file mode 100644
index 0000000..7b7a1ed

drivers/mmc/qc_mmc.c line 33

Quoted 8 lines
drivers/mmc/qc_mmc.c new file +7 -0
@@ -0,0 +1,584 @@
 
+#if MMC_BOOT_ADM
+#include "adm.h"
+#endif
+
+#ifndef NULL
+#define NULL ? ? ? ?0
+#endif

?? Is NULL ever undefined in C?

Quoted 16 lines
drivers/mmc/qc_mmc.c new file +16 -0
+
+#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)

drivers/mmc/qc_mmc.c

Quoted 10 lines
drivers/mmc/qc_mmc.c new file +10 -0
+{
+ ? ? ? 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);

I think it's preferable to do:

struct mmc_priv *priv = mmc->priv;

priv->rd_timeout_ns = 100000000;

Quoted 60 lines
drivers/mmc/qc_mmc.c new file +60 -0
+
+ ? ? ? 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;
+

drivers/mmc/qc_mmc.c

Quoted 10 lines
drivers/mmc/qc_mmc.c new file +10 -0
+ ? ? ? 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)
+{

Why is mmc_ptr an unsigned int *?

Quoted 8 lines

+ ? ? ? 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;

Unnecessary cast

Quoted 25 lines

+ ? ? ? unsigned long reg_status, reg_fifo;

drivers/mmc/qc_mmc.c new file +24 -0
+
+ ? ? ? 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;

drivers/mmc/qc_mmc.c

Quoted 10 lines
drivers/mmc/qc_mmc.c new file +10 -0
+
+ ? ? ? ? ? ? ? ? ? ? ? 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);

I don't remember if readl is explicitly sized, but it seems like there are some implicit and explicit size dependencies, and they aren't currently guaranteed to line up. If you're going to do this, I think mmc_ptr should be u32*. And you should update mmc_count by sizeof(*mmc_ptr) to lock in the connection between the increase in mmc_count and the amount of data read.

Out of curiosity, I notice that you will read from the start of the FIFO each time this function is called. Is there something that resets the FIFO to put the oldest data at the first address? Or is this only called once?

drivers/mmc/qc_mmc.c

Quoted 5 lines
drivers/mmc/qc_mmc.c new file +5 -0
+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;

Unnecessary cast

Quoted 7 lines

+ ? ? ? 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);

You've got priv already, why access it via complicated cast?

Quoted 3 lines

+ ? ? ? /* add some extra clock cycles to be safe */
+ ? ? ? mmc_reg += 1000;
+ ? ? ? mmc_reg = mmc_reg/2;

I'd prefer that the variables have names that indicate their purpose (e.g. - mmc_timeout). It took me a few times looking at this to realize you were updating a variable that will be written to a reg, rather than a pointer to your mmc register space.

Also, I'm assuming that the register defines the timeout field so that you need ns/2, but you might want to document that as why you divide by 2.

Quoted 3 lines

+
+ ? ? ? reg = mmc_boot_mci_reg(priv->base, MMC_BOOT_MCI_DATA_TIMER);
+ ? ? ? writel(mmc_reg, reg);

If you're going to repeat a sequence like this, frequently, it might be better to create a qc_mmc_write() function which takes priv, reg, and value as arguments:

qc_mmc_write(priv, MMC_BOOT_MCI_DATA_TIMER, mmc_reg);

BTW, are all of these prefixed with MMC_BOOT because this is only used at boot time? Seems limiting. And it makes the constant names very long.

Quoted 25 lines
drivers/mmc/qc_mmc.c new file +25 -0
+
+ ? ? ? /* 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);
+

drivers/mmc/qc_mmc.c

Quoted 10 lines
drivers/mmc/qc_mmc.c new file +10 -0
+ ? ? ? /* 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
+ */

This sounds...odd.

drivers/mmc/qc_mmc.c

Quoted 11 lines
drivers/mmc/qc_mmc.c new file +11 -0
+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;

I'm not sure what this means. But if you think U-Boot should be filling in a different value, we should change it in mmc.c, not one-at-a-time in each driver...

Quoted 2 lines

+ ? ? ? ? ? ? ? /* this is to explicitly disable the prg enabled flag */
+ ? ? ? ? ? ? ? cmd->flags &= ~MMC_BOOT_PROGRAM_ENABLED;

1) I'm not sure this field is ever used for anything
2) You shouldn't define your own constants for inspecting/setting data in fields that haven't been explicitly set aside for driver-specific implementation. While it doesn't look like any of the mmc code ever sets this field, it could one day, and break your driver.

Quoted 12 lines
drivers/mmc/qc_mmc.c new file +12 -0
+
+ ? ? ? } 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;

drivers/mmc/qc_mmc.c

Quoted 10 lines
drivers/mmc/qc_mmc.c new file +10 -0
+ ? ? ? ? ? ? ? ? ? ? ? }
+ ? ? ? } 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 */

nit: no apostrophe needed

drivers/mmc/qc_mmc.c

Quoted 7 lines
drivers/mmc/qc_mmc.c new file +7 -0
+/*
+ * 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;

No cast

Quoted 1 line

+ ? ? ? int mmc_slot = priv->instance;

Whenever a driver has to be told which instance it is, a kitten dies.... Ok, after reading through I see that it's only used to set clocking. That's probably fine. More on this later.

Quoted 7 lines
drivers/mmc/qc_mmc.c new file +7 -0
+/*
+ * Board specific initializations
+ */
+unsigned int mmc_boot_main(struct mmc *mmc)
+{
+ ? ? ? unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+

drivers/mmc/qc_mmc.c

Quoted 10 lines
drivers/mmc/qc_mmc.c new file +10 -0
+ ? ? ? /* 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;
+}

Why not put the actual initialization function here? We usually want to contain the driver information, here. It looks like you have two different initialization paths, but there should be some way to codify that so that future readers/writers can understand which parts of the driver are being used under a given set of conditions. As it currently stands, they will have to investigate the board file to figure it out. Use the board init function to pass in parameters the driver can use to make those choices. For instance, the

Quoted 2 lines

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"

These sorts of disclaimers really serve to irritate open source developers. Also, it puts me in the legal void, as you neglected to CC me, which means I might be an unintended recipient. In defiance of your disclaimer, I decided to take action, anyway. Feel free to sue me. :P

Andy

author NAK
#4 lore raw

PATCH v2 4/5 Add Support for qc_mmc MMC Controller

Hi,

NAK, allow me to explain below:

arch/arm/include/asm/arch-msm7630/mmc.h line 26

Quoted 10 lines · Mohamed Haneef

* Support for qc_mmc MMC Controller

---

arch/arm/include/asm/arch-msm7630/mmc.h new file +6 -0
+#ifndef __MMC_H__
+#define __MMC_H__
+
+#ifndef MMC_SLOT
+#define MMC_SLOT            0
+#endif

This sort of thing should probably be passed in by the board code.

it is removed.

arch/arm/include/asm/arch-msm7630/mmc.h line 382

Quoted 7 lines
arch/arm/include/asm/arch-msm7630/mmc.h new file +7 -0
+
+#if 0
+#define MSM_SDC1_BASE       0x12400000
+#define MSM_SDC2_BASE       0x12140000
+#define MSM_SDC3_BASE       0x12180000
+#define MSM_SDC4_BASE       0x121C0000
+#endif

Why's this still here?

this got removed as well

Quoted 6 lines
drivers/mmc/qc_mmc.c new file +0 -0
new file mode 100644
index 0000000..7b7a1ed

drivers/mmc/qc_mmc.c line 33

Quoted 8 lines
drivers/mmc/qc_mmc.c new file +7 -0
@@ -0,0 +1,584 @@
 
+#if MMC_BOOT_ADM
+#include "adm.h"
+#endif
+
+#ifndef NULL
+#define NULL        0
+#endif

?? Is NULL ever undefined in C?

Quoted 16 lines
drivers/mmc/qc_mmc.c new file +16 -0
+
+#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)

drivers/mmc/qc_mmc.c line 59

Quoted 10 lines
drivers/mmc/qc_mmc.c new file +10 -0
+{
+       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);

I think it's preferable to do:

struct mmc_priv *priv = mmc->priv;

priv->rd_timeout_ns = 100000000;

Quoted 60 lines
drivers/mmc/qc_mmc.c new file +60 -0
+
+       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;
+

drivers/mmc/qc_mmc.c line 129

Quoted 10 lines
drivers/mmc/qc_mmc.c new file +10 -0
+       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)
+{

Why is mmc_ptr an unsigned int *?

drivers/mmc/qc_mmc.c line 137

Quoted 8 lines
drivers/mmc/qc_mmc.c new file +8 -0
+       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;

Unnecessary cast

Quoted 25 lines
drivers/mmc/qc_mmc.c new file +25 -0
+       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;

drivers/mmc/qc_mmc.c line 172

Quoted 10 lines
drivers/mmc/qc_mmc.c new file +10 -0
+
+                       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);

I don't remember if readl is explicitly sized, but it seems like there are some implicit and explicit size dependencies, and they aren't currently guaranteed to line up. If you're going to do this, I think mmc_ptr should be u32*. And you should update mmc_count by sizeof(*mmc_ptr) to lock in the connection between the increase in mmc_count and the amount of data read.

Out of curiosity, I notice that you will read from the start of the FIFO each time this function is called. Is there something that resets the FIFO to put the oldest data at the first address? Or is this only called once?

drivers/mmc/qc_mmc.c line 362

Quoted 5 lines
drivers/mmc/qc_mmc.c new file +5 -0
+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;

Unnecessary cast

drivers/mmc/qc_mmc.c line 369

Quoted 7 lines
drivers/mmc/qc_mmc.c new file +7 -0
+       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);

You've got priv already, why access it via complicated cast?

drivers/mmc/qc_mmc.c line 372

Quoted 3 lines
drivers/mmc/qc_mmc.c new file +3 -0
+       /* add some extra clock cycles to be safe */
+       mmc_reg += 1000;
+       mmc_reg = mmc_reg/2;

I'd prefer that the variables have names that indicate their purpose (e.g. - mmc_timeout). It took me a few times looking at this to realize you were updating a variable that will be written to a reg, rather than a pointer to your mmc register space.

Also, I'm assuming that the register defines the timeout field so that you need ns/2, but you might want to document that as why you divide by 2.

drivers/mmc/qc_mmc.c line 375

Quoted 3 lines
drivers/mmc/qc_mmc.c new file +3 -0
+
+       reg = mmc_boot_mci_reg(priv->base, MMC_BOOT_MCI_DATA_TIMER);
+       writel(mmc_reg, reg);

If you're going to repeat a sequence like this, frequently, it might be better to create a qc_mmc_write() function which takes priv, reg, and value as arguments:

qc_mmc_write(priv, MMC_BOOT_MCI_DATA_TIMER, mmc_reg);

BTW, are all of these prefixed with MMC_BOOT because this is only used at boot time? Seems limiting. And it makes the constant names very long.

Quoted 25 lines
drivers/mmc/qc_mmc.c new file +25 -0
+
+       /* 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);
+

drivers/mmc/qc_mmc.c line 410

Quoted 10 lines
drivers/mmc/qc_mmc.c new file +10 -0
+       /* 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
+ */

This sounds...odd.

drivers/mmc/qc_mmc.c line 421

Quoted 11 lines
drivers/mmc/qc_mmc.c new file +11 -0
+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;

I'm not sure what this means. But if you think U-Boot should be filling in a different value, we should change it in mmc.c, not one-at-a-time in each driver...

drivers/mmc/qc_mmc.c

Quoted 2 lines
drivers/mmc/qc_mmc.c new file +2 -0
+               /* this is to explicitly disable the prg enabled flag */
+               cmd->flags &= ~MMC_BOOT_PROGRAM_ENABLED;

1) I'm not sure this field is ever used for anything
2) You shouldn't define your own constants for inspecting/setting data in fields that haven't been explicitly set aside for driver-specific implementation. While it doesn't look like any of the mmc code ever sets this field, it could one day, and break your driver.

Quoted 12 lines
drivers/mmc/qc_mmc.c new file +12 -0
+
+       } 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;

drivers/mmc/qc_mmc.c line 445

Quoted 10 lines
drivers/mmc/qc_mmc.c new file +10 -0
+                       }
+       } 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 */

nit: no apostrophe needed

drivers/mmc/qc_mmc.c line 493

Quoted 7 lines
drivers/mmc/qc_mmc.c new file +7 -0
+/*
+ * 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;

No cast

Quoted 1 line

+ int mmc_slot = priv->instance;

Whenever a driver has to be told which instance it is, a kitten dies.... Ok, after reading through I see that it's only used to set clocking. That's probably fine. More on this later.

Quoted 7 lines
drivers/mmc/qc_mmc.c new file +7 -0
+/*
+ * Board specific initializations
+ */
+unsigned int mmc_boot_main(struct mmc *mmc)
+{
+       unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+

drivers/mmc/qc_mmc.c line 584

Quoted 10 lines
drivers/mmc/qc_mmc.c new file +10 -0
+       /* 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;
+}

Why not put the actual initialization function here? We usually want to contain the driver information, here. It looks like you have two different initialization paths, but there should be some way to codify that so that future readers/writers can understand which parts of the driver are being used under a given set of conditions. As it currently stands, they will have to investigate the board file to figure it out. Use the board init function to pass in parameters the driver can use to make those choices. For instance, the

Quoted 2 lines

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"

These sorts of disclaimers really serve to irritate open source developers. Also, it puts me in the legal void, as you neglected to CC me, which means I might be an unintended recipient. In defiance of your disclaimer, I decided to take action, anyway. Feel free to sue me. :P