From patchwork Wed Jan 25 19:54:01 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heiner Kallweit X-Patchwork-Id: 719889 X-Patchwork-Delegate: jh80.chung@samsung.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 3v7ypL3LK2z9srY for ; Thu, 26 Jan 2017 08:28:26 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="P0qo/nYO"; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 642F0B3892; Wed, 25 Jan 2017 22:28:19 +0100 (CET) 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 wLJXttU4ANGK; Wed, 25 Jan 2017 22:28:19 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 4EDADB387E; Wed, 25 Jan 2017 22:28:09 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 4EBF94ACF9 for ; Wed, 25 Jan 2017 20:54:35 +0100 (CET) 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 IgFZcKLq7yEH for ; Wed, 25 Jan 2017 20:54:35 +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 mail-wm0-f65.google.com (mail-wm0-f65.google.com [74.125.82.65]) by theia.denx.de (Postfix) with ESMTPS id 14FA54ACA6 for ; Wed, 25 Jan 2017 20:54:30 +0100 (CET) Received: by mail-wm0-f65.google.com with SMTP id c85so44780656wmi.1 for ; Wed, 25 Jan 2017 11:54:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:subject:to:references:cc:message-id:date:user-agent :mime-version:in-reply-to:content-transfer-encoding; bh=FPcAyejLQjsv6T672QV3z+QChKKepBCqWPw2l4dUb/g=; b=P0qo/nYO5Yw3BU4ahqZe/Nl89+wXhTxx1CQVuek9r+vVa/C4RdwjbhjYUpMARdDQH7 c0nF69PrxkJxvM0EM6ARcQXC63CliaJQJWdrsRXOp2aa23fcr98rCENG0u8NPREuE81Q AxznAMz82LIwwqi/kD8eW2XZ81rkMqW+0NLUc9lEfILVMW7IzADbijBgFCHtHzvhmQkL dQ0HdwMb2Q9skkWE2WoUt6r6tmRBj+0eF8d3XVYbC4ruzF0rT3w88s9nBkjH2JzrF2iw CvAPvvZdAsoprU+hBl1I6KaOlC5zjX3dp+++r+FSg17abogZv2NrE4FR8EqqoSLR0ZLx zYIw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:subject:to:references:cc:message-id:date :user-agent:mime-version:in-reply-to:content-transfer-encoding; bh=FPcAyejLQjsv6T672QV3z+QChKKepBCqWPw2l4dUb/g=; b=bgc6gCjd2m/Fi2K++VLoqbhBxtanYnXakWCAGdtr8r454r0aeg87WRtGDBUOg6qZrd H4DhBQAHZasj7YmqnfHUhimtgwe92XYE4aAmoKnFccsN4ceqVnZUx1qwJsEs8Jwq/uPY N2Zl7VWn8aSrPXSFN0W8zyKO5Yi8avpKTOpXKxsaGeuoQTlkA+Iv0jejZ0tdMiL9aITf 1yzNRqbC0eiWqV16x/Hln9jZfMILblmJRlVjqdEp3Jxevh1WHLmYTqOXligl6SpdvZeQ qEiY8QF8hJcZ8OBi/HcX3/ttseY/XLwKE/tHxJYGvrrNpunPLC8zyNpa47E57JwiBrOd 8XIg== X-Gm-Message-State: AIkVDXKij1HZJlLYI1c711T7S6Adpeef7RPQf8D9FMQkia0MgTsj80lSbybfNqx5wDA3Eg== X-Received: by 10.223.161.222 with SMTP id v30mr39891722wrv.114.1485374070117; Wed, 25 Jan 2017 11:54:30 -0800 (PST) Received: from ?IPv6:2003:c6:ebc5:6c00:55a4:2048:123e:5e11? (p200300C6EBC56C0055A42048123E5E11.dip0.t-ipconnect.de. [2003:c6:ebc5:6c00:55a4:2048:123e:5e11]) by smtp.googlemail.com with ESMTPSA id c133sm116959wmd.13.2017.01.25.11.54.29 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 25 Jan 2017 11:54:29 -0800 (PST) From: Heiner Kallweit To: Jaehoon Chung References: Message-ID: <4bfc9711-9076-9c46-0826-a06d8c94ccf1@gmail.com> Date: Wed, 25 Jan 2017 20:54:01 +0100 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Thunderbird/45.6.0 MIME-Version: 1.0 In-Reply-To: X-Mailman-Approved-At: Wed, 25 Jan 2017 22:27:52 +0100 Cc: carlo@caione.org, u-boot@lists.denx.de, carlo@endlessm.com Subject: [U-Boot] [PATCH v2 3/4] mmc: meson: add MMC driver for Meson GX (S905) X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" This driver implements MMC support on Meson GX (S905) based systems. It's based on Carlo Caione's work, changes: - BLK support added - general refactoring Original author: Carlo Caione Signed-off-by: Heiner Kallweit --- v2: - addressed review comments - general refactoring --- arch/arm/include/asm/arch-meson/sd_emmc.h | 89 +++++++++ drivers/mmc/Kconfig | 11 ++ drivers/mmc/Makefile | 1 + drivers/mmc/meson_gx_mmc.c | 291 ++++++++++++++++++++++++++++++ include/configs/meson-gxbb-common.h | 4 + 5 files changed, 396 insertions(+) create mode 100644 arch/arm/include/asm/arch-meson/sd_emmc.h create mode 100644 drivers/mmc/meson_gx_mmc.c diff --git a/arch/arm/include/asm/arch-meson/sd_emmc.h b/arch/arm/include/asm/arch-meson/sd_emmc.h new file mode 100644 index 0000000..25dbf60 --- /dev/null +++ b/arch/arm/include/asm/arch-meson/sd_emmc.h @@ -0,0 +1,89 @@ +/* + * (C) Copyright 2017 Carlo Caione + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __SD_EMMC_H__ +#define __SD_EMMC_H__ + +#include + +#define SDIO_PORT_A 0 +#define SDIO_PORT_B 1 +#define SDIO_PORT_C 2 + +#define SD_EMMC_CLKSRC_24M 24000000 /* 24 MHz */ +#define SD_EMMC_CLKSRC_DIV2 1000000000 /* 1 GHz */ + +#define MESON_SD_EMMC_CLOCK 0x00 +#define CLK_MAX_DIV 63 +#define CLK_SRC_24M (0 << 6) +#define CLK_SRC_DIV2 (1 << 6) +#define CLK_CO_PHASE_000 (0 << 8) +#define CLK_CO_PHASE_090 (1 << 8) +#define CLK_CO_PHASE_180 (2 << 8) +#define CLK_CO_PHASE_270 (3 << 8) +#define CLK_TX_PHASE_000 (0 << 10) +#define CLK_TX_PHASE_090 (1 << 10) +#define CLK_TX_PHASE_180 (2 << 10) +#define CLK_TX_PHASE_270 (3 << 10) +#define CLK_ALWAYS_ON BIT(24) + +#define MESON_SD_EMMC_CFG 0x44 +#define CFG_BUS_WIDTH_MASK GENMASK(1, 0) +#define CFG_BUS_WIDTH_1 0 +#define CFG_BUS_WIDTH_4 1 +#define CFG_BUS_WIDTH_8 2 +#define CFG_BL_LEN_MASK GENMASK(7, 4) +#define CFG_BL_LEN_SHIFT 4 +#define CFG_BL_LEN_512 (9 << 4) +#define CFG_RESP_TIMEOUT_MASK GENMASK(11, 8) +#define CFG_RESP_TIMEOUT_256 (8 << 8) +#define CFG_RC_CC_MASK GENMASK(15, 12) +#define CFG_RC_CC_16 (4 << 12) +#define CFG_SDCLK_ALWAYS_ON BIT(18) +#define CFG_AUTO_CLK BIT(23) + +#define MESON_SD_EMMC_STATUS 0x48 +#define STATUS_MASK GENMASK(15, 0) +#define STATUS_ERR_MASK GENMASK(12, 0) +#define STATUS_RXD_ERR_MASK GENMASK(7, 0) +#define STATUS_TXD_ERR BIT(8) +#define STATUS_DESC_ERR BIT(9) +#define STATUS_RESP_ERR BIT(10) +#define STATUS_RESP_TIMEOUT BIT(11) +#define STATUS_DESC_TIMEOUT BIT(12) +#define STATUS_END_OF_CHAIN BIT(13) + +#define MESON_SD_EMMC_IRQ_EN 0x4c + +#define MESON_SD_EMMC_CMD_CFG 0x50 +#define CMD_CFG_LENGTH_MASK GENMASK(8, 0) +#define CMD_CFG_BLOCK_MODE BIT(9) +#define CMD_CFG_R1B BIT(10) +#define CMD_CFG_END_OF_CHAIN BIT(11) +#define CMD_CFG_TIMEOUT_4S (12 << 12) +#define CMD_CFG_NO_RESP BIT(16) +#define CMD_CFG_DATA_IO BIT(18) +#define CMD_CFG_DATA_WR BIT(19) +#define CMD_CFG_RESP_NOCRC BIT(20) +#define CMD_CFG_RESP_128 BIT(21) +#define CMD_CFG_CMD_INDEX_SHIFT 24 +#define CMD_CFG_OWNER BIT(31) + +#define MESON_SD_EMMC_CMD_ARG 0x54 +#define MESON_SD_EMMC_CMD_DAT 0x58 +#define MESON_SD_EMMC_CMD_RSP 0x5c +#define MESON_SD_EMMC_CMD_RSP1 0x60 +#define MESON_SD_EMMC_CMD_RSP2 0x64 +#define MESON_SD_EMMC_CMD_RSP3 0x68 + +struct meson_mmc_platdata { + struct mmc_config cfg; + struct mmc mmc; + void *regbase; + void *w_buf; +}; + +#endif diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 9ed8da3..03416ff 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -168,6 +168,17 @@ config ZYNQ_SDHCI help Support for Arasan SDHCI host controller on Zynq/ZynqMP ARM SoCs platform +config MMC_MESON_GX + bool "Meson GX EMMC controller support" + depends on DM_MMC && BLK && DM_MMC_OPS && ARCH_MESON + help + Support for EMMC host controller on Meson GX ARM SoCs platform (S905) + +config MMC_MESON_GX_SD_PORT + int "Meson SD port selection" + range 0 2 + depends on MMC_MESON_GX + config ROCKCHIP_SDHCI bool "Arasan SDHCI controller for Rockchip support" depends on DM_MMC && BLK && DM_MMC_OPS diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 4dca09c..6e951a0 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -31,6 +31,7 @@ ifdef CONFIG_SUPPORT_EMMC_BOOT obj-$(CONFIG_GENERIC_MMC) += mmc_boot.o endif obj-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o +obj-$(CONFIG_MMC_MESON_GX) += meson_gx_mmc.o obj-$(CONFIG_MMC_SPI) += mmc_spi.o obj-$(CONFIG_MVEBU_MMC) += mvebu_mmc.o obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o diff --git a/drivers/mmc/meson_gx_mmc.c b/drivers/mmc/meson_gx_mmc.c new file mode 100644 index 0000000..d4c6e04 --- /dev/null +++ b/drivers/mmc/meson_gx_mmc.c @@ -0,0 +1,291 @@ +/* + * (C) Copyright 2017 Carlo Caione + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static inline void *get_regbase(const struct mmc *mmc) +{ + struct meson_mmc_platdata *pdata = mmc->priv; + + return pdata->regbase; +} + +static inline uint32_t meson_read(struct mmc *mmc, int offset) +{ + return readl(get_regbase(mmc) + offset); +} + +static inline void meson_write(struct mmc *mmc, uint32_t val, int offset) +{ + writel(val, get_regbase(mmc) + offset); +} + +static void meson_mmc_config_clock(struct mmc *mmc) +{ + uint32_t meson_mmc_clk = 0; + unsigned int clk, clk_src, clk_div; + + /* 1GHz / CLK_MAX_DIV = 15,9 MHz */ + if (mmc->clock > 16000000) { + clk = SD_EMMC_CLKSRC_DIV2; + clk_src = CLK_SRC_DIV2; + } else { + clk = SD_EMMC_CLKSRC_24M; + clk_src = CLK_SRC_24M; + } + clk_div = DIV_ROUND_UP(clk, mmc->clock); + + /* 180 phase core clock */ + meson_mmc_clk |= CLK_CO_PHASE_180; + + /* 180 phase tx clock */ + meson_mmc_clk |= CLK_TX_PHASE_180; + + /* clock settings */ + meson_mmc_clk |= clk_src; + meson_mmc_clk |= clk_div; + + meson_write(mmc, meson_mmc_clk, MESON_SD_EMMC_CLOCK); +} + +static int meson_dm_mmc_set_ios(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + uint32_t meson_mmc_cfg; + + meson_mmc_config_clock(mmc); + + meson_mmc_cfg = meson_read(mmc, MESON_SD_EMMC_CFG); + + meson_mmc_cfg &= ~CFG_BUS_WIDTH_MASK; + if (mmc->bus_width == 1) + meson_mmc_cfg |= CFG_BUS_WIDTH_1; + else if (mmc->bus_width == 4) + meson_mmc_cfg |= CFG_BUS_WIDTH_4; + else if (mmc->bus_width == 8) + meson_mmc_cfg |= CFG_BUS_WIDTH_8; + else + return -EINVAL; + + /* 512 bytes block length */ + meson_mmc_cfg &= ~CFG_BL_LEN_MASK; + meson_mmc_cfg |= CFG_BL_LEN_512; + + /* Response timeout 256 clk */ + meson_mmc_cfg &= ~CFG_RESP_TIMEOUT_MASK; + meson_mmc_cfg |= CFG_RESP_TIMEOUT_256; + + /* Command-command gap 16 clk */ + meson_mmc_cfg &= ~CFG_RC_CC_MASK; + meson_mmc_cfg |= CFG_RC_CC_16; + + meson_write(mmc, meson_mmc_cfg, MESON_SD_EMMC_CFG); + + return 0; +} + +static void meson_mmc_setup_cmd(struct mmc *mmc, struct mmc_data *data, + struct mmc_cmd *cmd) +{ + uint32_t meson_mmc_cmd = 0, cfg; + + meson_mmc_cmd |= cmd->cmdidx << CMD_CFG_CMD_INDEX_SHIFT; + + if (cmd->resp_type & MMC_RSP_PRESENT) { + if (cmd->resp_type & MMC_RSP_136) + meson_mmc_cmd |= CMD_CFG_RESP_128; + + if (cmd->resp_type & MMC_RSP_BUSY) + meson_mmc_cmd |= CMD_CFG_R1B; + + if (!(cmd->resp_type & MMC_RSP_CRC)) + meson_mmc_cmd |= CMD_CFG_RESP_NOCRC; + } else { + meson_mmc_cmd |= CMD_CFG_NO_RESP; + } + + if (data) { + cfg = meson_read(mmc, MESON_SD_EMMC_CFG); + cfg &= ~CFG_BL_LEN_MASK; + cfg |= ilog2(data->blocksize) << CFG_BL_LEN_SHIFT; + meson_write(mmc, cfg, MESON_SD_EMMC_CFG); + + if (data->flags == MMC_DATA_WRITE) + meson_mmc_cmd |= CMD_CFG_DATA_WR; + + cfg = CMD_CFG_DATA_IO | CMD_CFG_BLOCK_MODE | data->blocks; + meson_mmc_cmd |= cfg; + } + + cfg = CMD_CFG_TIMEOUT_4S | CMD_CFG_OWNER | CMD_CFG_END_OF_CHAIN; + meson_mmc_cmd |= cfg; + + meson_write(mmc, meson_mmc_cmd, MESON_SD_EMMC_CMD_CFG); +} + +static void meson_mmc_setup_addr(struct mmc *mmc, struct mmc_data *data) +{ + struct meson_mmc_platdata *pdata = mmc->priv; + unsigned int data_size; + uint32_t data_addr = 0; + + if (data) { + data_size = data->blocks * data->blocksize; + + if (data->flags == MMC_DATA_READ) { + data_addr = (ulong) data->dest; + invalidate_dcache_range(data_addr, + data_addr + data_size); + } else if (data->flags == MMC_DATA_WRITE) { + pdata->w_buf = calloc(data_size, sizeof(char)); + data_addr = (ulong) pdata->w_buf; + memcpy(pdata->w_buf, data->src, data_size); + flush_dcache_range(data_addr, data_addr + data_size); + } + } + + meson_write(mmc, data_addr, MESON_SD_EMMC_CMD_DAT); +} + +static void meson_mmc_read_response(struct mmc *mmc, struct mmc_cmd *cmd) +{ + if (cmd->resp_type & MMC_RSP_136) { + cmd->response[0] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP3); + cmd->response[1] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP2); + cmd->response[2] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP1); + cmd->response[3] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP); + } else { + cmd->response[0] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP); + } +} + +static int meson_dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + struct meson_mmc_platdata *pdata = mmc->priv; + uint32_t status; + ulong start; + int ret = 0; + + /* max block size supported by chip is 512 byte */ + if (data && data->blocksize > 512) + return -EINVAL; + + meson_mmc_setup_cmd(mmc, data, cmd); + meson_mmc_setup_addr(mmc, data); + + meson_write(mmc, cmd->cmdarg, MESON_SD_EMMC_CMD_ARG); + + /* use 10s timeout */ + start = get_timer(0); + do { + status = meson_read(mmc, MESON_SD_EMMC_STATUS); + } while(!(status & STATUS_END_OF_CHAIN) && get_timer(start) < 10000); + + if (!(status & STATUS_END_OF_CHAIN)) + ret = -ETIMEDOUT; + else if (status & STATUS_RESP_TIMEOUT) + ret = -ETIMEDOUT; + else if (status & STATUS_ERR_MASK) + ret = -EIO; + + meson_mmc_read_response(mmc, cmd); + + if (data && data->flags == MMC_DATA_WRITE) + free(pdata->w_buf); + + /* reset status bits */ + meson_write(mmc, STATUS_MASK, MESON_SD_EMMC_STATUS); + + return ret; +} + +static const struct dm_mmc_ops meson_dm_mmc_ops = { + .send_cmd = meson_dm_mmc_send_cmd, + .set_ios = meson_dm_mmc_set_ios, +}; + +static int meson_mmc_ofdata_to_platdata(struct udevice *dev) +{ + struct meson_mmc_platdata *pdata = dev_get_platdata(dev); + fdt_addr_t addr; + + addr = dev_get_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + pdata->regbase = (void *)addr; + + return 0; +} + +static int meson_mmc_probe(struct udevice *dev) +{ + struct meson_mmc_platdata *pdata = dev_get_platdata(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct mmc *mmc = &pdata->mmc; + struct mmc_config *cfg = &pdata->cfg; + uint32_t val; + + cfg->voltages = MMC_VDD_33_34 | MMC_VDD_32_33 | + MMC_VDD_31_32 | MMC_VDD_165_195; + cfg->host_caps = MMC_MODE_8BIT | MMC_MODE_4BIT | + MMC_MODE_HS_52MHz | MMC_MODE_HS; + cfg->f_min = DIV_ROUND_UP(SD_EMMC_CLKSRC_24M, CLK_MAX_DIV); + cfg->f_max = 100000000; /* 100 MHz */ + cfg->b_max = 256; /* max 256 blocks */ + cfg->name = dev->name; + + mmc->priv = pdata; + upriv->mmc = mmc; + + mmc_set_clock(mmc, cfg->f_min); + + /* reset all status bits */ + meson_write(mmc, STATUS_MASK, MESON_SD_EMMC_STATUS); + + /* disable interrupts */ + meson_write(mmc, 0, MESON_SD_EMMC_IRQ_EN); + + /* enable auto clock mode */ + val = meson_read(mmc, MESON_SD_EMMC_CFG); + val &= ~CFG_SDCLK_ALWAYS_ON; + val |= CFG_AUTO_CLK; + meson_write(mmc, val, MESON_SD_EMMC_CFG); + + return 0; +} + +int meson_mmc_bind(struct udevice *dev) +{ + struct meson_mmc_platdata *pdata = dev_get_platdata(dev); + + return mmc_bind(dev, &pdata->mmc, &pdata->cfg); +} + +static const struct udevice_id meson_mmc_match[] = { + { .compatible = "amlogic,meson-gx-mmc" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(meson_mmc) = { + .name = "meson_gx_mmc", + .id = UCLASS_MMC, + .of_match = meson_mmc_match, + .ops = &meson_dm_mmc_ops, + .probe = meson_mmc_probe, + .bind = meson_mmc_bind, + .ofdata_to_platdata = meson_mmc_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct meson_mmc_platdata), +}; diff --git a/include/configs/meson-gxbb-common.h b/include/configs/meson-gxbb-common.h index 3bba2e6..53c04a9 100644 --- a/include/configs/meson-gxbb-common.h +++ b/include/configs/meson-gxbb-common.h @@ -24,6 +24,10 @@ #define CONFIG_SYS_INIT_SP_ADDR 0x20000000 #define CONFIG_SYS_LOAD_ADDR CONFIG_SYS_TEXT_BASE +#ifdef CONFIG_MMC +#define CONFIG_GENERIC_MMC +#endif + /* Generic Interrupt Controller Definitions */ #define GICD_BASE 0xc4301000 #define GICC_BASE 0xc4302000