From patchwork Tue Jul 3 04:57:47 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jaehoon Chung X-Patchwork-Id: 168681 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 02D512C00B2 for ; Tue, 3 Jul 2012 14:58:16 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id C69D32808B; Tue, 3 Jul 2012 06:58:11 +0200 (CEST) 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 n0Ti2vUUSsCK; Tue, 3 Jul 2012 06:58:11 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 393DC28086; Tue, 3 Jul 2012 06:58:07 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id A1D5428087 for ; Tue, 3 Jul 2012 06:57:58 +0200 (CEST) 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 m3ULCW-kFxgM for ; Tue, 3 Jul 2012 06:57:53 +0200 (CEST) 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 mailout3.samsung.com (mailout3.samsung.com [203.254.224.33]) by theia.denx.de (Postfix) with ESMTP id 05AE728084 for ; Tue, 3 Jul 2012 06:57:51 +0200 (CEST) Received: from epcpsbgm1.samsung.com (mailout3.samsung.com [203.254.224.33]) by mailout3.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0M6K00GS3J40DCF0@mailout3.samsung.com> for u-boot@lists.denx.de; Tue, 03 Jul 2012 13:57:48 +0900 (KST) X-AuditID: cbfee61a-b7f086d000000e64-48-4ff27bcca691 Received: from epmmp1.local.host ( [203.254.227.16]) by epcpsbgm1.samsung.com (EPCPMTA) with SMTP id 35.1B.03684.CCB72FF4; Tue, 03 Jul 2012 13:57:48 +0900 (KST) Received: from [10.90.51.55] by mmp1.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0M6K00H20J4BL290@mmp1.samsung.com> for u-boot@lists.denx.de; Tue, 03 Jul 2012 13:57:48 +0900 (KST) Message-id: <4FF27BCB.2000105@samsung.com> Date: Tue, 03 Jul 2012 13:57:47 +0900 From: Jaehoon Chung User-Agent: Mozilla/5.0 (X11; Linux i686; rv:12.0) Gecko/20120430 Thunderbird/12.0.1 MIME-version: 1.0 To: "u-boot@lists.denx.de" X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprMLMWRmVeSWpSXmKPExsVy+t9jAd0z1Z/8DeY/0bJ4u7eT3YHR4+yd HYwBjFFcNimpOZllqUX6dglcGa9OPWErOFpbsfHmQsYGxi2pXYycHBICJhLXmw4xQthiEhfu rWfrYuTiEBJYxCjx6OYuVginiUli75GjrCBVvAJaEtc/zwezWQRUJZqOfAGz2QR0JLZ/O84E YosKhEm8nnKIBaJeUOLH5HtgtoiAocTf3btZQIYyC2xmlDh8YiZQAweHsIC9xOYPfiA1zEBz 9rdOY4Ow5SU2r3nLPIGRbxaSUbOQlM1CUraAkXkVo2hqQXJBcVJ6rqFecWJucWleul5yfu4m RnBQPZPawbiyweIQowAHoxIPr0fpJ38h1sSy4srcQ4wSHMxKIrxxRz76C/GmJFZWpRblxxeV 5qQWH2KU5mBREudtsr7gLySQnliSmp2aWpBaBJNl4uCUamC07fFvWGKzKT1VZk9lTNCxa48V K6fb2646a3k646BwyCSb94sMJrnXe546VtO9o+9izxyd0/IstgHfeZiFlLLnevXfrTqseFVj d+Rt1XcK/O2X+k3nnGWyVDl6ZhVruhmfyYqq03Mj50+3MNnAnTvVzmPVEt9QUZNJeU8YGS1u xaVwt/srf1ZiKc5INNRiLipOBACFZxJ6JgIAAA== X-TM-AS-MML: No Cc: Andy Fleming , Kyungmin Park , Rajeshwari Shinde Subject: [U-Boot] [PATCH] mmc: dw-mmc: support DesignWare 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 This patch is supported DesginWare MMC Controller. Signed-off-by: Jaehoon Chung Signed-off-by: Kyungmin Park Signed-off-by: Rajeshawari Shinde --- drivers/mmc/dw_mmc.c | 388 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/dwmmc.h | 186 ++++++++++++++++++++++++ 2 files changed, 574 insertions(+), 0 deletions(-) create mode 100644 drivers/mmc/dw_mmc.c create mode 100644 include/dwmmc.h diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c new file mode 100644 index 0000000..8159234 --- /dev/null +++ b/drivers/mmc/dw_mmc.c @@ -0,0 +1,388 @@ +/* + * (C) Copyright 2012 SAMSUNG Electronics + * Jaehoon Chung + * Rajeshawari Shinde + * + * 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 +#include + +#define PAGE_SIZE 4096 + +static int dwmci_wait_reset(struct dwmci_host *host, u32 value) +{ + unsigned long timeout = 1000; + u32 ctrl; + + dwmci_writel(host, DWMCI_CTRL, value); + + while (timeout--) { + ctrl = dwmci_readl(host, DWMCI_CTRL); + if (!(ctrl & DWMCI_RESET_ALL)) + return 1; + if (timeout == 0) + break; + } + return 0; +} + +static void dwmci_set_idma_desc(u8 *idmac, unsigned int des0, + unsigned int des1, unsigned int des2) +{ + struct dwmci_idmac *desc = (struct dwmci_idmac *)idmac; + + desc->des0 = des0; + desc->des1 = des1; + desc->des2 = des2; + desc->des3 = (unsigned int)desc + sizeof(struct dwmci_idmac); +} + +static void dwmci_prepare_data(struct dwmci_host *host, + struct mmc_data *data) +{ + unsigned long ctrl; + unsigned int i = 0, flag, cnt, blk_cnt; + struct dwmci_idmac *p; + ulong data_start, data_end, start_addr; + ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, idmac, 65565); + + + p = idmac; + blk_cnt = data->blocks; + + dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET); + + if (data->flags == MMC_DATA_READ) + start_addr = (unsigned int)data->dest; + else + start_addr = (unsigned int)data->src; + + do { + flag = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH ; + flag |= (i == 0) ? DWMCI_IDMAC_FS : 0; + if (blk_cnt <= 8) { + flag |= DWMCI_IDMAC_LD; + cnt = data->blocksize * blk_cnt; + } else { + flag &= ~DWMCI_IDMAC_LD; + cnt = data->blocksize * 8; + } + + dwmci_set_idma_desc((u8 *)p, flag, cnt, + start_addr + (i * PAGE_SIZE)); + + if (blk_cnt <= 8) + break; + blk_cnt -= 8; + p++; + i++; + } while(1); + + data_start = (ulong)idmac; + data_end = (ulong)p; + flush_dcache_range(data_start, data_end + ARCH_DMA_MINALIGN); + + dwmci_writel(host, DWMCI_DBADDR, (unsigned int)(idmac)); + + ctrl = dwmci_readl(host, DWMCI_CTRL); + ctrl |= DWMCI_IDMAC_EN | DWMCI_DMA_EN; + dwmci_writel(host, DWMCI_CTRL, ctrl); + + ctrl = dwmci_readl(host, DWMCI_BMOD); + ctrl |= DWMCI_BMOD_IDMAC_FB | DWMCI_BMOD_IDMAC_EN; + dwmci_writel(host, DWMCI_BMOD, ctrl); + + dwmci_writel(host, DWMCI_BLKSIZ, data->blocksize); + dwmci_writel(host, DWMCI_BYTCNT, data->blocksize * data->blocks); +} + +static int dwmci_set_transfer_mode(struct dwmci_host *host, + struct mmc_data *data) +{ + unsigned long mode; + + mode = DWMCI_CMD_DATA_EXP; + if (data->flags & MMC_DATA_WRITE) + mode |= DWMCI_CMD_RW; + + return mode; +} + +static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + struct dwmci_host *host = (struct dwmci_host *)mmc->priv; + int flags = 0, i; + unsigned int timeout = 100000; + u32 retry = 10000; + u32 mask, ctrl; + + while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { + if (timeout == 0) { + printf("Timeout on data busy\n"); + return TIMEOUT; + } + timeout--; + } + + dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL); + + if (data) + dwmci_prepare_data(host, data); + + + dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg); + + if (data) { + flags = dwmci_set_transfer_mode(host, data); + } + + if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY)) + return -1; + + if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) + flags |= DWMCI_CMD_ABORT_STOP; + else + flags |= DWMCI_CMD_PRV_DAT_WAIT; + + if (cmd->resp_type & MMC_RSP_PRESENT) { + flags |= DWMCI_CMD_RESP_EXP; + if (cmd->resp_type & MMC_RSP_136) + flags |= DWMCI_CMD_RESP_LENGTH; + } + + if (cmd->resp_type & MMC_RSP_CRC) + flags |= DWMCI_CMD_CHECK_CRC; + + flags |= (cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG); + + debug("Sending CMD%d\n",cmd->cmdidx); + + dwmci_writel(host, DWMCI_CMD, flags); + + for (i = 0; i < retry; i++) { + mask = dwmci_readl(host, DWMCI_RINTSTS); + if (mask & DWMCI_INTMSK_CDONE) { + if (!data) + dwmci_writel(host, DWMCI_RINTSTS, mask); + break; + } + } + + if (i == retry) + return TIMEOUT; + + if (mask & DWMCI_INTMSK_RTO) { + debug("Response Timeout..\n"); + return TIMEOUT; + } else if (mask & DWMCI_INTMSK_RE) { + debug("Response Error..\n"); + return -1; + } + + + if (cmd->resp_type & MMC_RSP_PRESENT) { + if (cmd->resp_type & MMC_RSP_136) { + cmd->response[0] = dwmci_readl(host, DWMCI_RESP3); + cmd->response[1] = dwmci_readl(host, DWMCI_RESP2); + cmd->response[2] = dwmci_readl(host, DWMCI_RESP1); + cmd->response[3] = dwmci_readl(host, DWMCI_RESP0); + } else { + cmd->response[0] = dwmci_readl(host, DWMCI_RESP0); + } + } + + if (data) { + while (1) { + mask = dwmci_readl(host, DWMCI_RINTSTS); + if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { + debug("DATA ERROR!\n"); + return -1; + } else if (mask & DWMCI_INTMSK_DTO) + break; + } + + dwmci_writel(host, DWMCI_RINTSTS, mask); + + ctrl = dwmci_readl(host, DWMCI_CTRL); + ctrl &= ~(DWMCI_DMA_EN); + dwmci_writel(host, DWMCI_CTRL, ctrl); + } + + udelay(100); + + return 0; +} + +static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) +{ + u32 div, status; + int timeout = 10000; + unsigned long sclk; + + if (freq == host->clock) + return 0; + + /* + * If get_mmc_clk didn't define, + * then assume that host->bus_hz is source clock value. + * host->bus_hz should be set from user. + */ + if (host->get_mmc_clk) + sclk = host->get_mmc_clk(host->dev_index); + else if (host->bus_hz) + sclk = host->bus_hz; + else { + printf("Didn't get source clock value..\n"); + return -EINVAL; + } + + for (div = 1; div < 255; div++) { + if ((sclk / (2 * div)) <= freq) { + break; + } + } + + dwmci_writel(host, DWMCI_CLKENA, 0); + dwmci_writel(host, DWMCI_CLKSRC, 0); + + dwmci_writel(host, DWMCI_CLKDIV, div); + dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | + DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); + + do { + status = dwmci_readl(host, DWMCI_CMD); + if (timeout == 0) { + printf("TIMEOUT error!!\n"); + return -ETIMEDOUT; + } + } while ((status & DWMCI_CMD_START) && timeout--); + + dwmci_writel(host, DWMCI_CLKENA, DWMCI_CLKEN_ENABLE | + DWMCI_CLKEN_LOW_PWR); + + dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | + DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); + + timeout = 10000; + do { + status = dwmci_readl(host, DWMCI_CMD); + if (timeout == 0) { + printf("TIMEOUT error!!\n"); + return -ETIMEDOUT; + } + } while ((status & DWMCI_CMD_START) && timeout--); + + host->clock = freq; + + return 0; +} + +static void dwmci_set_ios(struct mmc *mmc) +{ + struct dwmci_host *host = (struct dwmci_host *)mmc->priv; + u32 ctype; + + debug("Buswidth = %d, clock: %d\n",mmc->bus_width, mmc->clock); + + dwmci_setup_bus(host, mmc->clock); + switch (mmc->bus_width) { + case 8: + ctype = DWMCI_CTYPE_8BIT; + break; + case 4: + ctype = DWMCI_CTYPE_4BIT; + break; + default: + ctype = DWMCI_CTYPE_1BIT; + break; + } + + dwmci_writel(host, DWMCI_CTYPE, ctype); + + if (host->clksel) + host->clksel(host); +} + +static int dwmci_init(struct mmc *mmc) +{ + struct dwmci_host *host = (struct dwmci_host *)mmc->priv; + u32 fifo_size, fifoth_val; + + dwmci_writel(host, DWMCI_PWREN, 1); + + if (!dwmci_wait_reset(host, DWMCI_RESET_ALL)) { + debug("%s[%d] Fail-reset!!\n",__func__,__LINE__); + return -1; + } + + dwmci_writel(host, DWMCI_RINTSTS, 0xFFFFFFFF); + dwmci_writel(host, DWMCI_INTMASK, 0); + + dwmci_writel(host, DWMCI_TMOUT, 0xFFFFFFFF); + + dwmci_writel(host, DWMCI_IDINTEN, 0); + dwmci_writel(host, DWMCI_BMOD, 1); + + fifo_size = dwmci_readl(host, DWMCI_FIFOTH); + if (host->fifoth_val) + fifoth_val = host->fifoth_val; + else + fifoth_val = (0x2 << 28) | ((fifo_size/2 -1) << 16) | + ((fifo_size/2) << 0); + dwmci_writel(host, DWMCI_FIFOTH, fifoth_val); + + dwmci_writel(host, DWMCI_CLKENA, 0); + dwmci_writel(host, DWMCI_CLKSRC, 0); + + return 0; +} + +int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk, int index) +{ + struct mmc *mmc; + int err = 0; + + mmc = malloc(sizeof(struct mmc)); + if (!mmc) { + printf("mmc malloc fail!\n"); + return -1; + } + + mmc->priv = host; + host->mmc = mmc; + + sprintf(mmc->name, "%s", host->name); + mmc->send_cmd = dwmci_send_cmd; + mmc->set_ios = dwmci_set_ios; + mmc->init = dwmci_init; + mmc->f_min = min_clk; + mmc->f_max = max_clk; + + mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; + mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_8BIT | + MMC_MODE_HC; + + err = mmc_register(mmc); + + return err; +} diff --git a/include/dwmmc.h b/include/dwmmc.h new file mode 100644 index 0000000..8699804 --- /dev/null +++ b/include/dwmmc.h @@ -0,0 +1,186 @@ +/* + * (C) Copyright 2012 SAMSUNG Electronics + * Jaehoon Chung + * + * 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 __DWMMC_HW_H +#define __DWMMC_HW_H + +#include +#include + +#define DWMCI_CTRL 0x000 +#define DWMCI_PWREN 0x004 +#define DWMCI_CLKDIV 0x008 +#define DWMCI_CLKSRC 0x00C +#define DWMCI_CLKENA 0x010 +#define DWMCI_TMOUT 0x014 +#define DWMCI_CTYPE 0x018 +#define DWMCI_BLKSIZ 0x01C +#define DWMCI_BYTCNT 0x020 +#define DWMCI_INTMASK 0x024 +#define DWMCI_CMDARG 0x028 +#define DWMCI_CMD 0x02C +#define DWMCI_RESP0 0x030 +#define DWMCI_RESP1 0x034 +#define DWMCI_RESP2 0x038 +#define DWMCI_RESP3 0x03C +#define DWMCI_MINTSTS 0x040 +#define DWMCI_RINTSTS 0x044 +#define DWMCI_STATUS 0x048 +#define DWMCI_FIFOTH 0x04C +#define DWMCI_CDETECT 0x050 +#define DWMCI_WRTPRT 0x054 +#define DWMCI_GPIO 0x058 +#define DWMCI_TCMCNT 0x05C +#define DWMCI_TBBCNT 0x060 +#define DWMCI_DEBNCE 0x064 +#define DWMCI_USRID 0x068 +#define DWMCI_VERID 0x06C +#define DWMCI_HCON 0x070 +#define DWMCI_UHS_REG 0x074 +#define DWMCI_BMOD 0x080 +#define DWMCI_PLDMND 0x084 +#define DWMCI_DBADDR 0x088 +#define DWMCI_IDSTS 0x08C +#define DWMCI_IDINTEN 0x090 +#define DWMCI_DSCADDR 0x094 +#define DWMCI_BUFADDR 0x098 +#define DWMCI_DATA 0x200 + +/* Interrupt Mask register */ +#define DWMCI_INTMSK_ALL 0xffffffff +#define DWMCI_INTMSK_RE (1 << 1) +#define DWMCI_INTMSK_CDONE (1 << 2) +#define DWMCI_INTMSK_DTO (1 << 3) +#define DWMCI_INTMSK_TXDR (1 << 4) +#define DWMCI_INTMSK_RXDR (1 << 5) +#define DWMCI_INTMSK_DCRC (1 << 7) +#define DWMCI_INTMSK_RTO (1 << 8) +#define DWMCI_INTMSK_DRTO (1 << 9) +#define DWMCI_INTMSK_HTO (1 << 10) +#define DWMCI_INTMSK_FRUN (1 << 11) +#define DWMCI_INTMSK_HLE (1 << 12) +#define DWMCI_INTMSK_SBE (1 << 13) +#define DWMCI_INTMSK_ACD (1 << 14) +#define DWMCI_INTMSK_EBE (1 << 15) + +/* Raw interrupt Regsiter */ +#define DWMCI_DATA_ERR (DWMCI_INTMSK_EBE | DWMCI_INTMSK_SBE | DWMCI_INTMSK_HLE |\ + DWMCI_INTMSK_FRUN | DWMCI_INTMSK_EBE | DWMCI_INTMSK_DCRC) +#define DWMCI_DATA_TOUT (DWMCI_INTMSK_HTO | DWMCI_INTMSK_DRTO) +/* CTRL register */ +#define DWMCI_CTRL_RESET (1 << 0) +#define DWMCI_CTRL_FIFO_RESET (1 << 1) +#define DWMCI_CTRL_DMA_RESET (1 << 2) +#define DWMCI_DMA_EN (1 << 5) +#define DWMCI_CTRL_SEND_AS_CCSD (1 << 10) +#define DWMCI_IDMAC_EN (1 << 25) +#define DWMCI_RESET_ALL (DWMCI_CTRL_RESET | DWMCI_CTRL_FIFO_RESET |\ + DWMCI_CTRL_DMA_RESET) + +/* CMD register */ +#define DWMCI_CMD_RESP_EXP (1 << 6) +#define DWMCI_CMD_RESP_LENGTH (1 << 7) +#define DWMCI_CMD_CHECK_CRC (1 << 8) +#define DWMCI_CMD_DATA_EXP (1 << 9) +#define DWMCI_CMD_RW (1 << 10) +#define DWMCI_CMD_SEND_STOP (1 << 12) +#define DWMCI_CMD_ABORT_STOP (1 << 14) +#define DWMCI_CMD_PRV_DAT_WAIT (1 << 13) +#define DWMCI_CMD_UPD_CLK (1 << 21) +#define DWMCI_CMD_USE_HOLD_REG (1 << 29) +#define DWMCI_CMD_START (1 << 31) + +/* CLKENA register */ +#define DWMCI_CLKEN_ENABLE (1 << 0) +#define DWMCI_CLKEN_LOW_PWR (1 << 16) + +/* Card-type registe */ +#define DWMCI_CTYPE_1BIT 0 +#define DWMCI_CTYPE_4BIT (1 << 0) +#define DWMCI_CTYPE_8BIT (1 << 16) + +/* Status Register */ +#define DWMCI_BUSY (1 << 9) + +#define DWMCI_IDMAC_OWN (1 << 31) +#define DWMCI_IDMAC_CH (1 << 4) +#define DWMCI_IDMAC_FS (1 << 3) +#define DWMCI_IDMAC_LD (1 << 2) + +/* Bus Mode Register */ +#define DWMCI_BMOD_IDMAC_RESET (1 << 0) +#define DWMCI_BMOD_IDMAC_FB (1 << 1) +#define DWMCI_BMOD_IDMAC_EN (1 << 7) + +struct dwmci_host { + char *name; + void *ioaddr; + unsigned int quirks; + unsigned int caps; + unsigned int version; + unsigned int clock; + unsigned int bus_hz; + int dev_index; + int buswidth; + u32 fifoth_val; + struct mmc *mmc; + + void (*clksel)(struct dwmci_host *host); + unsigned int (*get_mmc_clk)(int dev_index); +}; + +struct dwmci_idmac { + u32 des0; + u32 des1; + u32 des2; + u32 des3; +}; + +static inline void dwmci_writel(struct dwmci_host *host, int reg, u32 val) +{ + writel(val, host->ioaddr + reg); +} + +static inline void dwmci_writew(struct dwmci_host *host, int reg, u16 val) +{ + writew(val, host->ioaddr + reg); +} + +static inline void dwmci_writeb(struct dwmci_host *host, int reg, u8 val) +{ + writeb(val, host->ioaddr + reg); +} +static inline u32 dwmci_readl(struct dwmci_host *host, int reg) +{ + return readl(host->ioaddr + reg); +} + +static inline u16 dwmci_readw(struct dwmci_host *host, int reg) +{ + return readw(host->ioaddr + reg); +} + +static inline u8 dwmci_readb(struct dwmci_host *host, int reg) +{ + return readb(host->ioaddr + reg); +} + +int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk, int index); +#endif /* __DWMMC_HW_H */