From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1760393AbZFWPQZ (ORCPT ); Tue, 23 Jun 2009 11:16:25 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1755309AbZFWPQR (ORCPT ); Tue, 23 Jun 2009 11:16:17 -0400 Received: from rv-out-0506.google.com ([209.85.198.237]:7252 "EHLO rv-out-0506.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755936AbZFWPQO (ORCPT ); Tue, 23 Jun 2009 11:16:14 -0400 DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:user-agent:mime-version:to:cc:subject :references:in-reply-to:content-type:content-transfer-encoding; b=uBMGO3lIt4s3fBM6CA+u/t7beEXqcDQngMqf8hZHXf6O/S1XldpVwbkvABvuDF0W5a GPbWlbGO5jN9hhjmY14FuD2Kzn6coa+umjg9zWbKoUGpqVlcqKTmZVmTLKSoVXXn9oHa 1et3y+cLgdY40CAHGkptcNICsRDjygXsfRKcM= Message-ID: <4A40F0C5.9030308@qq.com> Date: Tue, 23 Jun 2009 23:12:05 +0800 From: taco User-Agent: Thunderbird 2.0.0.14 (X11/20080526) MIME-Version: 1.0 To: Vipin CC: linux-kernel@vger.kernel.org, davinci-linux-open-source@linux.davincidsp.com, drzeus-mmc@drzeus.cx Subject: Re: [PATCH] DaVinci: MMC: V5: MMC/SD controller driver for DaVinci family. References: <1245747324-28206-1-git-send-email-vipin.bhandari@ti.com> <00dd01c9f3f8$47f1aeb0$d7d50c10$@bhandari@ti.com> In-Reply-To: <00dd01c9f3f8$47f1aeb0$d7d50c10$@bhandari@ti.com> Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Vipin wrote: > The description of this patch needs to be updated. I'll repost the patch > soon. > > Thanks and regards, > ~Vipin > > > >> -----Original Message----- >> From: Vipin Bhandari [mailto:vipin.bhandari@ti.com] >> Sent: Tuesday, June 23, 2009 2:25 PM >> To: linux-kernel@vger.kernel.org >> Cc: davinci-linux-open-source@linux.davincidsp.com; drzeus- >> mmc@drzeus.cx; Vipin Bhandari; Purshotam Kumar >> Subject: [PATCH] DaVinci: MMC: V5: MMC/SD controller driver for DaVinci >> family. >> >> This patch adds support for MMC/SD controller driver for DaVinci family >> SoC. >> This patch will work for SoC like DM6446 and DM355. SoC like DM365 and >> DA830 also has same controller with small variations and could >> supported/added >> easily by using this version of patch. It means that this version of >> patch >> could be used for all SoC which has been derived from DaVinci family. >> >> This patch has been generated against latest 2.6.30 mainline kernel. >> This patch >> will not compile currently because it depends notably on the EDMA >> utilities and >> chip/board setup, that will come at some point through the ARM tree. >> Please use >> currently DaVinci GIT tree for EDMA utilities and chip/board setup etc. >> >> The scatterlist traversal is made proper. The also has some minor >> comments >> modification and also sets the value written to the DAVINCI_MMCTOR >> register >> properly. The timeout calculation is made proper by deriving it from >> the clock >> values. >> >> Many thanks to David Brownell (david-b@pacbell.net) for all his >> support. >> >> This updated patch incorporates most of review comments given by Pierre >> Ossman. >> Many thanks for Pierre Ossman for reviewing. >> >> Signed-off-by: Vipin Bhandari >> Signed-off-by: Purshotam Kumar >> Acked-by: David Brownell >> --- >> drivers/mmc/host/Kconfig | 8 + >> drivers/mmc/host/Makefile | 1 + >> drivers/mmc/host/davinci_mmc.c | 1281 >> ++++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 1290 insertions(+), 0 deletions(-) >> create mode 100644 drivers/mmc/host/davinci_mmc.c >> >> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig >> index 891ef18..b5adcba 100644 >> --- a/drivers/mmc/host/Kconfig >> +++ b/drivers/mmc/host/Kconfig >> @@ -236,6 +236,14 @@ config MMC_MVSDIO >> To compile this driver as a module, choose M here: the >> module will be called mvsdio. >> >> +config MMC_DAVINCI >> + tristate "TI DAVINCI Multimedia Card Interface support" >> + depends on ARCH_DAVINCI >> + help >> + This selects the TI DAVINCI Multimedia card Interface. >> + If you have an DAVINCI board with a Multimedia Card slot, >> + say Y or M here. If unsure, say N. >> + >> config MMC_SPI >> tristate "MMC/SD/SDIO over SPI" >> depends on SPI_MASTER && !HIGHMEM && HAS_DMA >> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile >> index cf153f6..784bde1 100644 >> --- a/drivers/mmc/host/Makefile >> +++ b/drivers/mmc/host/Makefile >> @@ -24,6 +24,7 @@ obj-$(CONFIG_MMC_AT91) += at91_mci.o >> obj-$(CONFIG_MMC_ATMELMCI) += atmel-mci.o >> obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o >> obj-$(CONFIG_MMC_MVSDIO) += mvsdio.o >> +obj-$(CONFIG_MMC_DAVINCI) += davinci_mmc.o >> obj-$(CONFIG_MMC_SPI) += mmc_spi.o >> ifeq ($(CONFIG_OF),y) >> obj-$(CONFIG_MMC_SPI) += of_mmc_spi.o >> diff --git a/drivers/mmc/host/davinci_mmc.c >> b/drivers/mmc/host/davinci_mmc.c >> new file mode 100644 >> index 0000000..5caa542 >> --- /dev/null >> +++ b/drivers/mmc/host/davinci_mmc.c >> @@ -0,0 +1,1281 @@ >> +/* >> + * davinci_mmc.c - TI DaVinci MMC/SD/SDIO driver >> + * >> + * Copyright (C) 2006 Texas Instruments. >> + * Original author: Purushotam Kumar >> + * Copyright (C) 2009 David Brownell >> + * >> + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include >> +#include >> + >> +/* >> + * Register Definitions >> + */ >> +#define DAVINCI_MMCCTL 0x00 /* Control Register >> */ >> +#define DAVINCI_MMCCLK 0x04 /* Memory Clock Control Register >> */ >> +#define DAVINCI_MMCST0 0x08 /* Status Register 0 >> */ >> +#define DAVINCI_MMCST1 0x0C /* Status Register 1 >> */ >> +#define DAVINCI_MMCIM 0x10 /* Interrupt Mask Register >> */ >> +#define DAVINCI_MMCTOR 0x14 /* Response Time-Out Register >> */ >> +#define DAVINCI_MMCTOD 0x18 /* Data Read Time-Out Register >> */ >> +#define DAVINCI_MMCBLEN 0x1C /* Block Length Register >> */ >> +#define DAVINCI_MMCNBLK 0x20 /* Number of Blocks Register >> */ >> +#define DAVINCI_MMCNBLC 0x24 /* Number of Blocks Counter Register >> */ >> +#define DAVINCI_MMCDRR 0x28 /* Data Receive Register >> */ >> +#define DAVINCI_MMCDXR 0x2C /* Data Transmit Register >> */ >> +#define DAVINCI_MMCCMD 0x30 /* Command Register >> */ >> +#define DAVINCI_MMCARGHL 0x34 /* Argument Register >> */ >> +#define DAVINCI_MMCRSP01 0x38 /* Response Register 0 and 1 >> */ >> +#define DAVINCI_MMCRSP23 0x3C /* Response Register 0 and 1 >> */ >> +#define DAVINCI_MMCRSP45 0x40 /* Response Register 0 and 1 >> */ >> +#define DAVINCI_MMCRSP67 0x44 /* Response Register 0 and 1 >> */ >> +#define DAVINCI_MMCDRSP 0x48 /* Data Response Register >> */ >> +#define DAVINCI_MMCETOK 0x4C >> +#define DAVINCI_MMCCIDX 0x50 /* Command Index Register >> */ >> +#define DAVINCI_MMCCKC 0x54 >> +#define DAVINCI_MMCTORC 0x58 >> +#define DAVINCI_MMCTODC 0x5C >> +#define DAVINCI_MMCBLNC 0x60 >> +#define DAVINCI_SDIOCTL 0x64 >> +#define DAVINCI_SDIOST0 0x68 >> +#define DAVINCI_SDIOEN 0x6C >> +#define DAVINCI_SDIOST 0x70 >> +#define DAVINCI_MMCFIFOCTL 0x74 /* FIFO Control Register >> */ >> + >> +/* DAVINCI_MMCCTL definitions */ >> +#define MMCCTL_DATRST (1 << 0) >> +#define MMCCTL_CMDRST (1 << 1) >> +#define MMCCTL_WIDTH_4_BIT (1 << 2) >> +#define MMCCTL_DATEG_DISABLED (0 << 6) >> +#define MMCCTL_DATEG_RISING (1 << 6) >> +#define MMCCTL_DATEG_FALLING (2 << 6) >> +#define MMCCTL_DATEG_BOTH (3 << 6) >> +#define MMCCTL_PERMDR_LE (0 << 9) >> +#define MMCCTL_PERMDR_BE (1 << 9) >> +#define MMCCTL_PERMDX_LE (0 << 10) >> +#define MMCCTL_PERMDX_BE (1 << 10) >> + >> +/* DAVINCI_MMCCLK definitions */ >> +#define MMCCLK_CLKEN (1 << 8) >> +#define MMCCLK_CLKRT_MASK (0xFF << 0) >> + >> +/* IRQ bit definitions, for DAVINCI_MMCST0 and DAVINCI_MMCIM */ >> +#define MMCST0_DATDNE BIT(0) /* data done */ >> +#define MMCST0_BSYDNE BIT(1) /* busy done */ >> +#define MMCST0_RSPDNE BIT(2) /* command done */ >> +#define MMCST0_TOUTRD BIT(3) /* data read timeout */ >> +#define MMCST0_TOUTRS BIT(4) /* command response timeout >> */ >> +#define MMCST0_CRCWR BIT(5) /* data write CRC error */ >> +#define MMCST0_CRCRD BIT(6) /* data read CRC error */ >> +#define MMCST0_CRCRS BIT(7) /* command response CRC error >> */ >> +#define MMCST0_DXRDY BIT(9) /* data transmit ready (fifo >> empty) */ >> +#define MMCST0_DRRDY BIT(10) /* data receive ready (data >> in fifo)*/ >> +#define MMCST0_DATED BIT(11) /* DAT3 edge detect */ >> +#define MMCST0_TRNDNE BIT(12) /* transfer done */ >> + >> +/* DAVINCI_MMCST1 definitions */ >> +#define MMCST1_BUSY (1 << 0) >> + >> +/* DAVINCI_MMCCMD definitions */ >> +#define MMCCMD_CMD_MASK (0x3F << 0) >> +#define MMCCMD_PPLEN (1 << 7) >> +#define MMCCMD_BSYEXP (1 << 8) >> +#define MMCCMD_RSPFMT_MASK (3 << 9) >> +#define MMCCMD_RSPFMT_NONE (0 << 9) >> +#define MMCCMD_RSPFMT_R1456 (1 << 9) >> +#define MMCCMD_RSPFMT_R2 (2 << 9) >> +#define MMCCMD_RSPFMT_R3 (3 << 9) >> +#define MMCCMD_DTRW (1 << 11) >> +#define MMCCMD_STRMTP (1 << 12) >> +#define MMCCMD_WDATX (1 << 13) >> +#define MMCCMD_INITCK (1 << 14) >> +#define MMCCMD_DCLR (1 << 15) >> +#define MMCCMD_DMATRIG (1 << 16) >> + >> +/* DAVINCI_MMCFIFOCTL definitions */ >> +#define MMCFIFOCTL_FIFORST (1 << 0) >> +#define MMCFIFOCTL_FIFODIR_WR (1 << 1) >> +#define MMCFIFOCTL_FIFODIR_RD (0 << 1) >> +#define MMCFIFOCTL_FIFOLEV (1 << 2) /* 0 = 128 bits, 1 = 256 bits >> */ >> +#define MMCFIFOCTL_ACCWD_4 (0 << 3) /* access width of 4 bytes >> */ >> +#define MMCFIFOCTL_ACCWD_3 (1 << 3) /* access width of 3 bytes >> */ >> +#define MMCFIFOCTL_ACCWD_2 (2 << 3) /* access width of 2 bytes >> */ >> +#define MMCFIFOCTL_ACCWD_1 (3 << 3) /* access width of 1 byte >> */ >> + >> + >> +/* MMCSD Init clock in Hz in opendrain mode */ >> +#define MMCSD_INIT_CLOCK 200000 >> + >> +/* >> + * One scatterlist dma "segment" is at most MAX_CCNT rw_threshold >> units, >> + * and we handle up to NR_SG segments. MMC_BLOCK_BOUNCE kicks in only >> + * for drivers with max_hw_segs == 1, making the segments bigger >> (64KB) >> + * than the page or two that's otherwise typical. NR_SG == 16 gives >> at >> + * least the same throughput boost, using EDMA transfer linkage >> instead >> + * of spending CPU time copying pages. >> + */ >> +#define MAX_CCNT ((1 << 16) - 1) >> + >> +#define NR_SG 16 >> + >> +static unsigned rw_threshold = 32; >> +module_param(rw_threshold, uint, S_IRUGO); >> +MODULE_PARM_DESC(rw_threshold, >> + "Read/Write threshold. Default = 32"); >> + >> +static unsigned __initdata use_dma = 1; >> +module_param(use_dma, uint, 0); >> +MODULE_PARM_DESC(use_dma, "Whether to use DMA or not. Default = 1"); >> + >> +struct mmc_davinci_host { >> + struct mmc_command *cmd; >> + struct mmc_data *data; >> + struct mmc_host *mmc; >> + struct clk *clk; >> + unsigned int mmc_input_clk; >> + void __iomem *base; >> + struct resource *mem_res; >> + int irq; >> + unsigned char bus_mode; >> + >> +#define DAVINCI_MMC_DATADIR_NONE 0 >> +#define DAVINCI_MMC_DATADIR_READ 1 >> +#define DAVINCI_MMC_DATADIR_WRITE 2 >> + unsigned char data_dir; >> + >> + /* buffer is used during PIO of one scatterlist segment, and >> + * is updated along with buffer_bytes_left. bytes_left applies >> + * to all N blocks of the PIO transfer. >> + */ >> + u8 *buffer; >> + u32 buffer_bytes_left; >> + u32 bytes_left; >> + >> + u8 rxdma, txdma; >> + bool use_dma; >> + bool do_dma; >> + >> + /* Scatterlist DMA uses one or more parameter RAM entries: >> + * the main one (associated with rxdma or txdma) plus zero or >> + * more links. The entries for a given transfer differ only >> + * by memory buffer (address, length) and link field. >> + */ >> + struct edmacc_param tx_template; >> + struct edmacc_param rx_template; >> + unsigned n_link; >> + u8 links[NR_SG - 1]; >> + >> + /* For PIO we walk scatterlists one segment at a time. */ >> + unsigned int sg_len; >> + struct scatterlist *sg; >> + >> + /* Version of the MMC/SD controller */ >> + u8 version; >> + /* for ns in one cycle calculation */ >> + unsigned ns_in_one_cycle; >> +}; >> + >> + >> +/* PIO only */ >> +static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host) >> +{ >> + host->buffer_bytes_left = sg_dma_len(host->sg); >> + host->buffer = sg_virt(host->sg); >> + if (host->buffer_bytes_left > host->bytes_left) >> + host->buffer_bytes_left = host->bytes_left; >> +} >> + >> +static void davinci_fifo_data_trans(struct mmc_davinci_host *host, >> + unsigned int n) >> +{ >> + u8 *p; >> + unsigned int i; >> + >> + if (host->buffer_bytes_left == 0) { >> + host->sg = sg_next(host->data->sg); >> + mmc_davinci_sg_to_buf(host); >> + } >> + >> + p = host->buffer; >> + if (n > host->buffer_bytes_left) >> + n = host->buffer_bytes_left; >> + host->buffer_bytes_left -= n; >> + host->bytes_left -= n; >> + >> + /* NOTE: we never transfer more than rw_threshold bytes >> + * to/from the fifo here; there's no I/O overlap. >> + * This also assumes that access width( i.e. ACCWD) is 4 bytes >> + */ >> + if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) { >> + for (i = 0; i < (n >> 2); i++) { >> + writel(*((u32 *)p), host->base + DAVINCI_MMCDXR); >> + p = p + 4; >> + } >> + if (n & 3) { >> + iowrite8_rep(host->base + DAVINCI_MMCDXR, p, (n & >> 3)); >> + p = p + (n & 3); >> + } >> + } else { >> + for (i = 0; i < (n >> 2); i++) { >> + *((u32 *)p) = readl(host->base + DAVINCI_MMCDRR); >> + p = p + 4; >> + } >> + if (n & 3) { >> + ioread8_rep(host->base + DAVINCI_MMCDRR, p, (n & >> > 3)); > >> + p = p + (n & 3); >> + } >> + } >> + host->buffer = p; >> +} >> + >> +static void mmc_davinci_start_command(struct mmc_davinci_host *host, >> + struct mmc_command *cmd) >> +{ >> + u32 cmd_reg = 0; >> + u32 im_val; >> + >> + dev_dbg(mmc_dev(host->mmc), "CMD%d, arg 0x%08x%s\n", >> + cmd->opcode, cmd->arg, >> + ({ char *s; >> + switch (mmc_resp_type(cmd)) { >> + case MMC_RSP_R1: >> + s = ", R1/R5/R6/R7 response"; >> + break; >> + case MMC_RSP_R1B: >> + s = ", R1b response"; >> + break; >> + case MMC_RSP_R2: >> + s = ", R2 response"; >> + break; >> + case MMC_RSP_R3: >> + s = ", R3/R4 response"; >> + break; >> + default: >> + s = ", (R? response)"; >> + break; >> + }; s; })); >> + host->cmd = cmd; >> + >> + switch (mmc_resp_type(cmd)) { >> + case MMC_RSP_R1B: >> + /* There's some spec confusion about when R1B is >> + * allowed, but if the card doesn't issue a BUSY >> + * then it's harmless for us to allow it. >> + */ >> + cmd_reg |= MMCCMD_BSYEXP; >> + /* FALLTHROUGH */ >> + case MMC_RSP_R1: /* 48 bits, CRC */ >> + cmd_reg |= MMCCMD_RSPFMT_R1456; >> + break; >> + case MMC_RSP_R2: /* 136 bits, CRC */ >> + cmd_reg |= MMCCMD_RSPFMT_R2; >> + break; >> + case MMC_RSP_R3: /* 48 bits, no CRC */ >> + cmd_reg |= MMCCMD_RSPFMT_R3; >> + break; >> + default: >> + cmd_reg |= MMCCMD_RSPFMT_NONE; >> + dev_dbg(mmc_dev(host->mmc), "unknown resp_type %04x\n", >> + mmc_resp_type(cmd)); >> + break; >> + } >> + >> + /* Set command index */ >> + cmd_reg |= cmd->opcode; >> + >> + /* Enable EDMA transfer triggers */ >> + if (host->do_dma) >> + cmd_reg |= MMCCMD_DMATRIG; >> + >> + if (host->version == MMC_CTLR_VERSION_2 && host->data != NULL && >> + host->data_dir == DAVINCI_MMC_DATADIR_READ) >> + cmd_reg |= MMCCMD_DMATRIG; >> + >> + /* Setting whether command involves data transfer or not */ >> + if (cmd->data) >> + cmd_reg |= MMCCMD_WDATX; >> + >> + /* Setting whether stream or block transfer */ >> + if (cmd->flags & MMC_DATA_STREAM) >> + cmd_reg |= MMCCMD_STRMTP; >> + >> + /* Setting whether data read or write */ >> + if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) >> + cmd_reg |= MMCCMD_DTRW; >> + >> + if (host->bus_mode == MMC_BUSMODE_PUSHPULL) >> + cmd_reg |= MMCCMD_PPLEN; >> + >> + /* set Command timeout */ >> + writel(0x1FFF, host->base + DAVINCI_MMCTOR); >> + >> + /* Enable interrupt (calculate here, defer until FIFO is >> stuffed). */ >> + im_val = MMCST0_RSPDNE | MMCST0_CRCRS | MMCST0_TOUTRS; >> + if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) { >> + im_val |= MMCST0_DATDNE | MMCST0_CRCWR; >> + >> + if (!host->do_dma) >> + im_val |= MMCST0_DXRDY; >> + } else if (host->data_dir == DAVINCI_MMC_DATADIR_READ) { >> + im_val |= MMCST0_DATDNE | MMCST0_CRCRD | MMCST0_TOUTRD; >> + >> + if (!host->do_dma) >> + im_val |= MMCST0_DRRDY; >> + } >> + >> + /* >> + * Before non-DMA WRITE commands the controller needs priming: >> + * FIFO should be populated with 32 bytes i.e. whatever is the >> FIFO size >> + */ >> + if (!host->do_dma && (host->data_dir == >> DAVINCI_MMC_DATADIR_WRITE)) >> + davinci_fifo_data_trans(host, rw_threshold); >> + >> + writel(cmd->arg, host->base + DAVINCI_MMCARGHL); >> + writel(cmd_reg, host->base + DAVINCI_MMCCMD); >> + writel(im_val, host->base + DAVINCI_MMCIM); >> +} >> + >> +/*-------------------------------------------------------------------- >> --*/ >> + >> +/* DMA infrastructure */ >> + >> +static void davinci_abort_dma(struct mmc_davinci_host *host) >> +{ >> + int sync_dev; >> + >> + if (host->data_dir == DAVINCI_MMC_DATADIR_READ) >> + sync_dev = host->rxdma; >> + else >> + sync_dev = host->txdma; >> + >> + edma_stop(sync_dev); >> + edma_clean_channel(sync_dev); >> +} >> + >> +static void >> +mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data >> *data); >> + >> +static void mmc_davinci_dma_cb(unsigned channel, u16 ch_status, void >> *data) >> +{ >> + if (DMA_COMPLETE != ch_status) { >> + struct mmc_davinci_host *host = data; >> + >> + /* Currently means: DMA Event Missed, or "null" transfer >> + * request was seen. In the future, TC errors (like bad >> + * addresses) might be presented too. >> + */ >> + dev_warn(mmc_dev(host->mmc), "DMA %s error\n", >> + (host->data->flags & MMC_DATA_WRITE) >> + ? "write" : "read"); >> + host->data->error = -EIO; >> + mmc_davinci_xfer_done(host, host->data); >> + } >> +} >> + >> +/* Set up tx or rx template, to be modified and updated later */ >> +static void __init mmc_davinci_dma_setup(struct mmc_davinci_host >> *host, >> + bool tx, struct edmacc_param *template) >> +{ >> + unsigned sync_dev; >> + const u16 acnt = 4; >> + const u16 bcnt = rw_threshold >> 2; >> + const u16 ccnt = 0; >> + u32 src_port = 0; >> + u32 dst_port = 0; >> + s16 src_bidx, dst_bidx; >> + s16 src_cidx, dst_cidx; >> + >> + /* >> + * A-B Sync transfer: each DMA request is for one "frame" of >> + * rw_threshold bytes, broken into "acnt"-size chunks repeated >> + * "bcnt" times. Each segment needs "ccnt" such frames; since >> + * we tell the block layer our mmc->max_seg_size limit, we can >> + * trust (later) that it's within bounds. >> + * >> + * The FIFOs are read/written in 4-byte chunks (acnt == 4) and >> + * EDMA will optimize memory operations to use larger bursts. >> + */ >> + if (tx) { >> + sync_dev = host->txdma; >> + >> + /* src_prt, ccnt, and link to be set up later */ >> + src_bidx = acnt; >> + src_cidx = acnt * bcnt; >> + >> + dst_port = host->mem_res->start + DAVINCI_MMCDXR; >> + dst_bidx = 0; >> + dst_cidx = 0; >> + } else { >> + sync_dev = host->rxdma; >> + >> + src_port = host->mem_res->start + DAVINCI_MMCDRR; >> + src_bidx = 0; >> + src_cidx = 0; >> + >> + /* dst_prt, ccnt, and link to be set up later */ >> + dst_bidx = acnt; >> + dst_cidx = acnt * bcnt; >> + } >> + >> + /* >> + * We can't use FIFO mode for the FIFOs because MMC FIFO >> addresses >> + * are not 256-bit (32-byte) aligned. So we use INCR, and the >> W8BIT >> + * parameter is ignored. >> + */ >> + edma_set_src(sync_dev, src_port, INCR, W8BIT); >> + edma_set_dest(sync_dev, dst_port, INCR, W8BIT); >> + >> + edma_set_src_index(sync_dev, src_bidx, src_cidx); >> + edma_set_dest_index(sync_dev, dst_bidx, dst_cidx); >> + >> + edma_set_transfer_params(sync_dev, acnt, bcnt, ccnt, 8, ABSYNC); >> + >> + edma_read_slot(sync_dev, template); >> + >> + /* don't bother with irqs or chaining */ >> + template->opt |= sync_dev << 12; >> +} >> + >> +static void mmc_davinci_send_dma_request(struct mmc_davinci_host >> *host, >> + struct mmc_data *data) >> +{ >> + struct edmacc_param *template; >> + int channel, slot; >> + unsigned link; >> + struct scatterlist *sg; >> + unsigned sg_len; >> + unsigned bytes_left = host->bytes_left; >> + const unsigned shift = ffs(rw_threshold) - 1;; >> + >> + if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) { >> + template = &host->tx_template; >> + channel = host->txdma; >> + } else { >> + template = &host->rx_template; >> + channel = host->rxdma; >> + } >> + >> + /* We know sg_len and ccnt will never be out of range because >> + * we told the mmc layer which in turn tells the block layer >> + * to ensure that it only hands us one scatterlist segment >> + * per EDMA PARAM entry. Update the PARAM >> + * entries needed for each segment of this scatterlist. >> + */ >> + for (slot = channel, link = 0, sg = data->sg, sg_len = host- >> >>> sg_len; >>> >> + sg_len-- != 0 && bytes_left; >> + sg = sg_next(sg), slot = host->links[link++]) { >> + u32 buf = sg_dma_address(sg); >> + unsigned count = sg_dma_len(sg); >> + >> + template->link_bcntrld = sg_len >> + ? (host->links[link] << 5) >> + : 0xffff; >> + >> + if (count > bytes_left) >> + count = bytes_left; >> + bytes_left -= count; >> + >> + if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) >> + template->src = buf; >> + else >> + template->dst = buf; >> + template->ccnt = count >> shift; >> + >> + edma_write_slot(slot, template); >> + } >> + >> + if (host->version == MMC_CTLR_VERSION_2) >> + edma_clear_event(channel); >> + >> + edma_start(channel); >> +} >> + >> +static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host >> *host, >> + struct mmc_data *data) >> +{ >> + int i; >> + int mask = rw_threshold - 1; >> + >> + host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data- >> >>> sg_len, >>> >> + ((data->flags & MMC_DATA_WRITE) >> + ? DMA_TO_DEVICE >> + : DMA_FROM_DEVICE)); >> + >> + /* no individual DMA segment should need a partial FIFO */ >> + for (i = 0; i < host->sg_len; i++) { >> + if (sg_dma_len(data->sg + i) & mask) { >> + dma_unmap_sg(mmc_dev(host->mmc), >> + data->sg, data->sg_len, >> + (data->flags & MMC_DATA_WRITE) >> + ? DMA_TO_DEVICE >> + : DMA_FROM_DEVICE); >> + return -1; >> + } >> + } >> + >> + host->do_dma = 1; >> + mmc_davinci_send_dma_request(host, data); >> + >> + return 0; >> +} >> + >> +static void __init_or_module >> +davinci_release_dma_channels(struct mmc_davinci_host *host) >> +{ >> + unsigned i; >> + >> + if (!host->use_dma) >> + return; >> + >> + for (i = 0; i < host->n_link; i++) >> + edma_free_slot(host->links[i]); >> + >> + edma_free_channel(host->txdma); >> + edma_free_channel(host->rxdma); >> +} >> + >> +static int __init davinci_acquire_dma_channels(struct mmc_davinci_host >> *host) >> +{ >> + int r, i; >> + >> + /* Acquire master DMA write channel */ >> + r = edma_alloc_channel(host->txdma, mmc_davinci_dma_cb, host, >> + EVENTQ_DEFAULT); >> + if (r < 0) { >> + dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n", >> + "tx", r); >> + return r; >> + } >> + mmc_davinci_dma_setup(host, true, &host->tx_template); >> + >> + /* Acquire master DMA read channel */ >> + r = edma_alloc_channel(host->rxdma, mmc_davinci_dma_cb, host, >> + EVENTQ_DEFAULT); >> + if (r < 0) { >> + dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n", >> + "rx", r); >> + goto free_master_write; >> + } >> + mmc_davinci_dma_setup(host, false, &host->rx_template); >> + >> + /* Allocate parameter RAM slots, which will later be bound to a >> + * channel as needed to handle a scatterlist. >> + */ >> + for (i = 0; i < ARRAY_SIZE(host->links); i++) { >> + r = edma_alloc_slot(EDMA_SLOT_ANY); >> + if (r < 0) { >> + dev_dbg(mmc_dev(host->mmc), "dma PaRAM alloc --> >> %d\n", >> + r); >> + break; >> + } >> + host->links[i] = r; >> + } >> + host->n_link = i; >> + >> + return 0; >> + >> +free_master_write: >> + edma_free_channel(host->txdma); >> + >> + return r; >> +} >> + >> +/*-------------------------------------------------------------------- >> --*/ >> + >> +static void >> +mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct >> mmc_request *req) >> +{ >> + int fifo_lev = (rw_threshold == 32) ? MMCFIFOCTL_FIFOLEV : 0; >> + int timeout; >> + struct mmc_data *data = req->data; >> + >> + if (host->version == MMC_CTLR_VERSION_2) >> + fifo_lev = (rw_threshold == 64) ? MMCFIFOCTL_FIFOLEV : 0; >> + >> + host->data = data; >> + if (data == NULL) { >> + host->data_dir = DAVINCI_MMC_DATADIR_NONE; >> + writel(0, host->base + DAVINCI_MMCBLEN); >> + writel(0, host->base + DAVINCI_MMCNBLK); >> + return; >> + } >> + >> + dev_dbg(mmc_dev(host->mmc), "%s %s, %d blocks of %d bytes\n", >> + (data->flags & MMC_DATA_STREAM) ? "stream" : "block", >> + (data->flags & MMC_DATA_WRITE) ? "write" : "read", >> + data->blocks, data->blksz); >> + dev_dbg(mmc_dev(host->mmc), " DTO %d cycles + %d ns\n", >> + data->timeout_clks, data->timeout_ns); >> + timeout = data->timeout_clks + >> + (data->timeout_ns / host->ns_in_one_cycle); >> + if (timeout > 0xffff) >> + timeout = 0xffff; >> + >> + writel(timeout, host->base + DAVINCI_MMCTOD); >> + writel(data->blocks, host->base + DAVINCI_MMCNBLK); >> + writel(data->blksz, host->base + DAVINCI_MMCBLEN); >> + >> + /* Configure the FIFO */ >> + switch (data->flags & MMC_DATA_WRITE) { >> + case MMC_DATA_WRITE: >> + host->data_dir = DAVINCI_MMC_DATADIR_WRITE; >> + writel(fifo_lev | MMCFIFOCTL_FIFODIR_WR | >> MMCFIFOCTL_FIFORST, >> + host->base + DAVINCI_MMCFIFOCTL); >> + writel(fifo_lev | MMCFIFOCTL_FIFODIR_WR, >> + host->base + DAVINCI_MMCFIFOCTL); >> + break; >> + >> + default: >> + host->data_dir = DAVINCI_MMC_DATADIR_READ; >> + writel(fifo_lev | MMCFIFOCTL_FIFODIR_RD | >> MMCFIFOCTL_FIFORST, >> + host->base + DAVINCI_MMCFIFOCTL); >> + writel(fifo_lev | MMCFIFOCTL_FIFODIR_RD, >> + host->base + DAVINCI_MMCFIFOCTL); >> + break; >> + } >> + >> + host->buffer = NULL; >> + host->bytes_left = data->blocks * data->blksz; >> + >> + /* For now we try to use DMA whenever we won't need partial FIFO >> + * reads or writes, either for the whole transfer (as tested >> here) >> + * or for any individual scatterlist segment (tested when we call >> + * start_dma_transfer). >> + * >> + * While we *could* change that, unusual block sizes are rarely >> + * used. The occasional fallback to PIO should't hurt. >> + */ >> + if (host->use_dma && (host->bytes_left & (rw_threshold - 1)) == 0 >> + && mmc_davinci_start_dma_transfer(host, data) == 0) >> > { > >> + /* zero this to ensure we take no PIO paths */ >> + host->bytes_left = 0; >> + } else { >> + /* Revert to CPU Copy */ >> + host->sg_len = data->sg_len; >> + host->sg = host->data->sg; >> + mmc_davinci_sg_to_buf(host); >> + } >> +} >> + >> +static void mmc_davinci_request(struct mmc_host *mmc, struct >> mmc_request *req) >> +{ >> + struct mmc_davinci_host *host = mmc_priv(mmc); >> + unsigned long timeout = jiffies + msecs_to_jiffies(900); >> + u32 mmcst1 = 0; >> + >> + /* Card may still be sending BUSY after a previous operation, >> + * typically some kind of write. If so, we can't proceed yet. >> + */ >> + while (time_before(jiffies, timeout)) { >> + mmcst1 = readl(host->base + DAVINCI_MMCST1); >> + if (!(mmcst1 & MMCST1_BUSY)) >> + break; >> + cpu_relax(); >> + } >> + if (mmcst1 & MMCST1_BUSY) { >> + dev_err(mmc_dev(host->mmc), "still BUSY? bad ... \n"); >> + req->cmd->error = -ETIMEDOUT; >> + mmc_request_done(mmc, req); >> + return; >> + } >> + >> + host->do_dma = 0; >> + mmc_davinci_prepare_data(host, req); >> + mmc_davinci_start_command(host, req->cmd); >> +} >> + >> +static unsigned int calculate_freq_for_card(struct mmc_davinci_host >> *host, >> + unsigned int mmc_req_freq) >> +{ >> + unsigned int mmc_freq = 0, mmc_pclk = 0, mmc_push_pull_divisor = >> 0; >> + >> + mmc_pclk = host->mmc_input_clk; >> + if (mmc_req_freq && mmc_pclk > (2 * mmc_req_freq)) >> + mmc_push_pull_divisor = ((unsigned int)mmc_pclk >> + / (2 * mmc_req_freq)) - 1; >> + else >> + mmc_push_pull_divisor = 0; >> + >> + mmc_freq = (unsigned int)mmc_pclk >> + / (2 * (mmc_push_pull_divisor + 1)); >> + >> + if (mmc_freq > mmc_req_freq) >> + mmc_push_pull_divisor = mmc_push_pull_divisor + 1; >> + /* Convert ns to clock cycles */ >> + if (mmc_req_freq <= 400000) >> + host->ns_in_one_cycle = (1000000) / (((mmc_pclk >> + / (2 * (mmc_push_pull_divisor + 1)))/1000)); >> + else >> + host->ns_in_one_cycle = (1000000) / (((mmc_pclk >> + / (2 * (mmc_push_pull_divisor + >> > 1)))/1000000)); > >> + >> + return mmc_push_pull_divisor; >> +} >> + >> +static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios >> *ios) >> +{ >> + unsigned int open_drain_freq = 0, mmc_pclk = 0; >> + unsigned int mmc_push_pull_freq = 0; >> + struct mmc_davinci_host *host = mmc_priv(mmc); >> + >> + mmc_pclk = host->mmc_input_clk; >> + dev_dbg(mmc_dev(host->mmc), >> + "clock %dHz busmode %d powermode %d Vdd %04x\n", >> + ios->clock, ios->bus_mode, ios->power_mode, >> + ios->vdd); >> + if (ios->bus_width == MMC_BUS_WIDTH_4) { >> + dev_dbg(mmc_dev(host->mmc), "Enabling 4 bit mode\n"); >> + writel(readl(host->base + DAVINCI_MMCCTL) | >> MMCCTL_WIDTH_4_BIT, >> + host->base + DAVINCI_MMCCTL); >> + } else { >> + dev_dbg(mmc_dev(host->mmc), "Disabling 4 bit mode\n"); >> + writel(readl(host->base + DAVINCI_MMCCTL) & >> ~MMCCTL_WIDTH_4_BIT, >> + host->base + DAVINCI_MMCCTL); >> + } >> + >> + if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) { >> + u32 temp; >> + >> + /* Ignoring the init clock value passed for fixing the >> inter >> + * operability with different cards. >> + */ >> + open_drain_freq = ((unsigned int)mmc_pclk >> + / (2 * MMCSD_INIT_CLOCK)) - 1; >> + >> + if (open_drain_freq > 0xFF) >> + open_drain_freq = 0xFF; >> + >> + temp = readl(host->base + DAVINCI_MMCCLK) & >> ~MMCCLK_CLKRT_MASK; >> + temp |= open_drain_freq; >> + writel(temp, host->base + DAVINCI_MMCCLK); >> + >> + /* Convert ns to clock cycles */ >> + host->ns_in_one_cycle = (1000000) / >> (MMCSD_INIT_CLOCK/1000); >> + } else { >> + u32 temp; >> + mmc_push_pull_freq = calculate_freq_for_card(host, ios- >> >>> clock); >>> >> + >> + if (mmc_push_pull_freq > 0xFF) >> + mmc_push_pull_freq = 0xFF; >> + >> + temp = readl(host->base + DAVINCI_MMCCLK) & ~MMCCLK_CLKEN; >> + writel(temp, host->base + DAVINCI_MMCCLK); >> + >> + udelay(10); >> + >> + temp = readl(host->base + DAVINCI_MMCCLK) & >> ~MMCCLK_CLKRT_MASK; >> + temp |= mmc_push_pull_freq; >> + writel(temp, host->base + DAVINCI_MMCCLK); >> + >> + writel(temp | MMCCLK_CLKEN, host->base + DAVINCI_MMCCLK); >> + >> + udelay(10); >> + } >> + >> + host->bus_mode = ios->bus_mode; >> + if (ios->power_mode == MMC_POWER_UP) { >> + unsigned long timeout = jiffies + msecs_to_jiffies(50); >> + bool lose = true; >> + >> + /* Send clock cycles, poll completion */ >> + writel(0, host->base + DAVINCI_MMCARGHL); >> + writel(MMCCMD_INITCK, host->base + DAVINCI_MMCCMD); >> + while (time_before(jiffies, timeout)) { >> + u32 tmp = readl(host->base + DAVINCI_MMCST0); >> + >> + if (tmp & MMCST0_RSPDNE) { >> + lose = false; >> + break; >> + } >> + cpu_relax(); >> + } >> + if (lose) >> + dev_warn(mmc_dev(host->mmc), "powerup timeout\n"); >> + } >> + >> + /* FIXME on power OFF, reset things ... */ >> +} >> + >> +static void >> +mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data >> *data) >> +{ >> + host->data = NULL; >> + host->data_dir = DAVINCI_MMC_DATADIR_NONE; >> + >> + if (host->do_dma) { >> + davinci_abort_dma(host); >> + >> + dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, >> + (data->flags & MMC_DATA_WRITE) >> + ? DMA_TO_DEVICE >> + : DMA_FROM_DEVICE); >> + host->do_dma = false; >> + } >> + >> + if (!data->stop || (host->cmd && host->cmd->error)) { >> + mmc_request_done(host->mmc, data->mrq); >> + writel(0, host->base + DAVINCI_MMCIM); >> + } else >> + mmc_davinci_start_command(host, data->stop); >> +} >> + >> +static void mmc_davinci_cmd_done(struct mmc_davinci_host *host, >> + struct mmc_command *cmd) >> +{ >> + host->cmd = NULL; >> + >> + if (cmd->flags & MMC_RSP_PRESENT) { >> + if (cmd->flags & MMC_RSP_136) { >> + /* response type 2 */ >> + cmd->resp[3] = readl(host->base + DAVINCI_MMCRSP01); >> + cmd->resp[2] = readl(host->base + DAVINCI_MMCRSP23); >> + cmd->resp[1] = readl(host->base + DAVINCI_MMCRSP45); >> + cmd->resp[0] = readl(host->base + DAVINCI_MMCRSP67); >> + } else { >> + /* response types 1, 1b, 3, 4, 5, 6 */ >> + cmd->resp[0] = readl(host->base + DAVINCI_MMCRSP67); >> + } >> + } >> + >> + if (host->data == NULL || cmd->error) { >> + if (cmd->error == -ETIMEDOUT) >> + cmd->mrq->cmd->retries = 0; >> + mmc_request_done(host->mmc, cmd->mrq); >> + writel(0, host->base + DAVINCI_MMCIM); >> + } >> +} >> + >> +static void >> +davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data >> *data) >> +{ >> + u32 temp; >> + >> + /* reset command and data state machines */ >> + temp = readl(host->base + DAVINCI_MMCCTL); >> + writel(temp | MMCCTL_CMDRST | MMCCTL_DATRST, >> + host->base + DAVINCI_MMCCTL); >> + >> + temp &= ~(MMCCTL_CMDRST | MMCCTL_DATRST); >> + udelay(10); >> + writel(temp, host->base + DAVINCI_MMCCTL); >> +} >> + >> +static irqreturn_t mmc_davinci_irq(int irq, void *dev_id) >> +{ >> + struct mmc_davinci_host *host = (struct mmc_davinci_host >> *)dev_id; >> + unsigned int status, qstatus; >> + int end_command = 0; >> + int end_transfer = 0; >> + struct mmc_data *data = host->data; >> + >> + if (host->cmd == NULL && host->data == NULL) { >> + status = readl(host->base + DAVINCI_MMCST0); >> + dev_dbg(mmc_dev(host->mmc), >> + "Spurious interrupt 0x%04x\n", status); >> + /* Disable the interrupt from mmcsd */ >> + writel(0, host->base + DAVINCI_MMCIM); >> + return IRQ_NONE; >> + } >> + >> + status = readl(host->base + DAVINCI_MMCST0); >> + qstatus = status; >> + >> + /* handle FIFO first when using PIO for data. >> + * bytes_left will decrease to zero as I/O progress and status >> will >> + * read zero over iteration because this controller status >> + * register(MMCST0) reports any status only once and it is >> cleared >> + * by read. So, it is not unbouned loop even in the case of >> + * non-dma. >> + */ >> + while (host->bytes_left && (status & (MMCST0_DXRDY | >> MMCST0_DRRDY))) { >> + davinci_fifo_data_trans(host, rw_threshold); >> + status = readl(host->base + DAVINCI_MMCST0); >> + if (!status) >> + break; >> + qstatus |= status; >> + } >> + >> + if (qstatus & MMCST0_DATDNE) { >> + /* All blocks sent/received, and CRC checks passed */ >> + if (data != NULL) { >> + if ((host->do_dma == 0) && (host->bytes_left > 0)) { >> + /* if datasize < rw_threshold >> + * no RX ints are generated >> + */ >> + davinci_fifo_data_trans(host, host- >> >>> bytes_left); >>> >> + } >> + end_transfer = 1; >> + data->bytes_xfered = data->blocks * data->blksz; >> + } else { >> + dev_err(mmc_dev(host->mmc), >> + "DATDNE with no host->data\n"); >> + } >> + } >> + >> + if (qstatus & MMCST0_TOUTRD) { >> + /* Read data timeout */ >> + data->error = -ETIMEDOUT; >> + end_transfer = 1; >> + >> + dev_dbg(mmc_dev(host->mmc), >> + "read data timeout, status %x\n", >> + qstatus); >> + >> + davinci_abort_data(host, data); >> + } >> + >> + if (qstatus & (MMCST0_CRCWR | MMCST0_CRCRD)) { >> + /* Data CRC error */ >> + data->error = -EILSEQ; >> + end_transfer = 1; >> + >> + /* NOTE: this controller uses CRCWR to report both CRC >> + * errors and timeouts (on writes). MMCDRSP values are >> + * only weakly documented, but 0x9f was clearly a timeout >> + * case and the two three-bit patterns in various SD specs >> + * (101, 010) aren't part of it ... >> + */ >> + if (qstatus & MMCST0_CRCWR) { >> + u32 temp = readb(host->base + DAVINCI_MMCDRSP); >> + >> + if (temp == 0x9f) >> + data->error = -ETIMEDOUT; >> + } >> + dev_dbg(mmc_dev(host->mmc), "data %s %s error\n", >> + (qstatus & MMCST0_CRCWR) ? "write" : "read", >> + (data->error == -ETIMEDOUT) ? "timeout" : "CRC"); >> + >> + davinci_abort_data(host, data); >> + } >> + >> + if (qstatus & MMCST0_TOUTRS) { >> + /* Command timeout */ >> + if (host->cmd) { >> + dev_dbg(mmc_dev(host->mmc), >> + "CMD%d timeout, status %x\n", >> + host->cmd->opcode, qstatus); >> + host->cmd->error = -ETIMEDOUT; >> + if (data) { >> + end_transfer = 1; >> + davinci_abort_data(host, data); >> + } else >> + end_command = 1; >> + } >> + } >> + >> + if (qstatus & MMCST0_CRCRS) { >> + /* Command CRC error */ >> + dev_dbg(mmc_dev(host->mmc), "Command CRC error\n"); >> + if (host->cmd) { >> + host->cmd->error = -EILSEQ; >> + end_command = 1; >> + } >> + } >> + >> + if (qstatus & MMCST0_RSPDNE) { >> + /* End of command phase */ >> + end_command = (int) host->cmd; >> + } >> + >> + if (end_command) >> + mmc_davinci_cmd_done(host, host->cmd); >> + if (end_transfer) >> + mmc_davinci_xfer_done(host, data); >> + return IRQ_HANDLED; >> +} >> + >> +static int mmc_davinci_get_cd(struct mmc_host *mmc) >> +{ >> + struct platform_device *pdev = to_platform_device(mmc->parent); >> + struct davinci_mmc_config *config = pdev->dev.platform_data; >> + >> + if (!config || !config->get_cd) >> + return -ENOSYS; >> + return config->get_cd(pdev->id); >> +} >> + >> +static int mmc_davinci_get_ro(struct mmc_host *mmc) >> +{ >> + struct platform_device *pdev = to_platform_device(mmc->parent); >> + struct davinci_mmc_config *config = pdev->dev.platform_data; >> + >> + if (!config || !config->get_ro) >> + return -ENOSYS; >> + return config->get_ro(pdev->id); >> +} >> + >> +static struct mmc_host_ops mmc_davinci_ops = { >> + .request = mmc_davinci_request, >> + .set_ios = mmc_davinci_set_ios, >> + .get_cd = mmc_davinci_get_cd, >> + .get_ro = mmc_davinci_get_ro, >> +}; >> + >> +/*-------------------------------------------------------------------- >> --*/ >> + >> +static void __init init_mmcsd_host(struct mmc_davinci_host *host) >> +{ >> + /* DAT line portion is diabled and in reset state */ >> + writel(readl(host->base + DAVINCI_MMCCTL) | MMCCTL_DATRST, >> + host->base + DAVINCI_MMCCTL); >> + >> + /* CMD line portion is diabled and in reset state */ >> + writel(readl(host->base + DAVINCI_MMCCTL) | MMCCTL_CMDRST, >> + host->base + DAVINCI_MMCCTL); >> + >> + udelay(10); >> + >> + writel(0, host->base + DAVINCI_MMCCLK); >> + writel(MMCCLK_CLKEN, host->base + DAVINCI_MMCCLK); >> + >> + writel(0x1FFF, host->base + DAVINCI_MMCTOR); >> + writel(0xFFFF, host->base + DAVINCI_MMCTOD); >> + >> + writel(readl(host->base + DAVINCI_MMCCTL) & ~MMCCTL_DATRST, >> + host->base + DAVINCI_MMCCTL); >> + writel(readl(host->base + DAVINCI_MMCCTL) & ~MMCCTL_CMDRST, >> + host->base + DAVINCI_MMCCTL); >> + >> + udelay(10); >> +} >> + >> +static int __init davinci_mmcsd_probe(struct platform_device *pdev) >> +{ >> + struct davinci_mmc_config *pdata = pdev->dev.platform_data; >> + struct mmc_davinci_host *host = NULL; >> + struct mmc_host *mmc = NULL; >> + struct resource *r, *mem = NULL; >> + int ret = 0, irq = 0; >> + size_t mem_size; >> + >> + /* REVISIT: when we're fully converted, fail if pdata is NULL */ >> + >> + ret = -ENODEV; >> + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> + irq = platform_get_irq(pdev, 0); >> + if (!r || irq == NO_IRQ) >> + goto out; >> + >> + ret = -EBUSY; >> + mem_size = resource_size(r); >> + mem = request_mem_region(r->start, mem_size, pdev->name); >> + if (!mem) >> + goto out; >> + >> + ret = -ENOMEM; >> + mmc = mmc_alloc_host(sizeof(struct mmc_davinci_host), &pdev- >> >>> dev); >>> >> + if (!mmc) >> + goto out; >> + >> + host = mmc_priv(mmc); >> + host->mmc = mmc; /* Important */ >> + >> + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); >> + if (!r) >> + goto out; >> + host->rxdma = r->start; >> + >> + r = platform_get_resource(pdev, IORESOURCE_DMA, 1); >> + if (!r) >> + goto out; >> + host->txdma = r->start; >> + >> + host->mem_res = mem; >> + host->base = ioremap(mem->start, mem_size); >> + if (!host->base) >> + goto out; >> + >> + ret = -ENXIO; >> + host->clk = clk_get(&pdev->dev, "MMCSDCLK"); >> + if (IS_ERR(host->clk)) { >> + ret = PTR_ERR(host->clk); >> + goto out; >> + } >> + clk_enable(host->clk); >> + host->mmc_input_clk = clk_get_rate(host->clk); >> + >> + init_mmcsd_host(host); >> + >> + host->use_dma = use_dma; >> + host->irq = irq; >> + >> + if (host->use_dma && davinci_acquire_dma_channels(host) != 0) >> + host->use_dma = 0; >> + >> + /* REVISIT: someday, support IRQ-driven card detection. */ >> + mmc->caps |= MMC_CAP_NEEDS_POLL; >> + >> + if (!pdata || pdata->wires == 4 || pdata->wires == 0) >> + mmc->caps |= MMC_CAP_4_BIT_DATA; >> + >> + host->version = pdata->version; >> + >> + mmc->ops = &mmc_davinci_ops; >> + mmc->f_min = 312500; >> + mmc->f_max = 25000000; >> + if (pdata && pdata->max_freq) >> + mmc->f_max = pdata->max_freq; >> + if (pdata && pdata->caps) >> + mmc->caps |= pdata->caps; >> + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; >> + >> + /* With no iommu coalescing pages, each phys_seg is a hw_seg. >> + * Each hw_seg uses one EDMA parameter RAM slot, always one >> + * channel and then usually some linked slots. >> + */ >> + mmc->max_hw_segs = 1 + host->n_link; >> + mmc->max_phys_segs = mmc->max_hw_segs; >> + >> + /* EDMA limit per hw segment (one or two MBytes) */ >> + mmc->max_seg_size = MAX_CCNT * rw_threshold; >> + >> + /* MMC/SD controller limits for multiblock requests */ >> + mmc->max_blk_size = 4095; /* BLEN is 12 bits */ >> + mmc->max_blk_count = 65535; /* NBLK is 16 bits */ >> + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; >> + >> + dev_dbg(mmc_dev(host->mmc), "max_phys_segs=%d\n", mmc- >> >>> max_phys_segs); >>> >> + dev_dbg(mmc_dev(host->mmc), "max_hw_segs=%d\n", mmc- >> >>> max_hw_segs); >>> >> + dev_dbg(mmc_dev(host->mmc), "max_blk_size=%d\n", mmc- >> >>> max_blk_size); >>> >> + dev_dbg(mmc_dev(host->mmc), "max_req_size=%d\n", mmc- >> >>> max_req_size); >>> >> + dev_dbg(mmc_dev(host->mmc), "max_seg_size=%d\n", mmc- >> >>> max_seg_size); >>> >> + >> + platform_set_drvdata(pdev, host); >> + >> + ret = mmc_add_host(mmc); >> + if (ret < 0) >> + goto out; >> + >> + ret = request_irq(irq, mmc_davinci_irq, 0, mmc_hostname(mmc), >> host); >> + if (ret) >> + goto out; >> + >> + rename_region(mem, mmc_hostname(mmc)); >> + >> + dev_info(mmc_dev(host->mmc), "Using %s, %d-bit mode\n", >> + host->use_dma ? "DMA" : "PIO", >> + (mmc->caps & MMC_CAP_4_BIT_DATA) ? 4 : 1); >> + >> + return 0; >> + >> +out: >> + if (host) { >> + davinci_release_dma_channels(host); >> + >> + if (host->clk) { >> + clk_disable(host->clk); >> + clk_put(host->clk); >> + } >> + >> + if (host->base) >> + iounmap(host->base); >> + } >> + >> + if (mmc) >> + mmc_free_host(mmc); >> + >> + if (mem) >> + release_resource(mem); >> + >> + dev_dbg(&pdev->dev, "probe err %d\n", ret); >> + >> + return ret; >> +} >> + >> +static int __exit davinci_mmcsd_remove(struct platform_device *pdev) >> +{ >> + struct mmc_davinci_host *host = platform_get_drvdata(pdev); >> + >> + platform_set_drvdata(pdev, NULL); >> + if (host) { >> + mmc_remove_host(host->mmc); >> + free_irq(host->irq, host); >> + >> + davinci_release_dma_channels(host); >> + >> + clk_disable(host->clk); >> + clk_put(host->clk); >> + >> + iounmap(host->base); >> + >> + release_resource(host->mem_res); >> + >> + mmc_free_host(host->mmc); >> + } >> + >> + return 0; >> +} >> + >> +#ifdef CONFIG_PM >> +static int davinci_mmcsd_suspend(struct platform_device *pdev, >> pm_message_t msg) >> +{ >> + struct mmc_davinci_host *host = platform_get_drvdata(pdev); >> + >> + return mmc_suspend_host(host->mmc, msg); >> +} >> + >> +static int davinci_mmcsd_resume(struct platform_device *pdev) >> +{ >> + struct mmc_davinci_host *host = platform_get_drvdata(pdev); >> + >> + return mmc_resume_host(host->mmc); >> +} >> +#else >> +#define davinci_mmcsd_suspend NULL >> +#define davinci_mmcsd_resume NULL >> +#endif >> + >> +static struct platform_driver davinci_mmcsd_driver = { >> + .driver = { >> + .name = "davinci_mmc", >> + .owner = THIS_MODULE, >> + }, >> + .remove = __exit_p(davinci_mmcsd_remove), >> + .suspend = davinci_mmcsd_suspend, >> + .resume = davinci_mmcsd_resume, >> +}; >> + >> +static int __init davinci_mmcsd_init(void) >> +{ >> + return platform_driver_probe(&davinci_mmcsd_driver, >> + davinci_mmcsd_probe); >> +} >> +module_init(davinci_mmcsd_init); >> + >> +static void __exit davinci_mmcsd_exit(void) >> +{ >> + platform_driver_unregister(&davinci_mmcsd_driver); >> +} >> +module_exit(davinci_mmcsd_exit); >> + >> +MODULE_AUTHOR("Texas Instruments India"); >> +MODULE_LICENSE("GPL"); >> +MODULE_DESCRIPTION("MMC/SD driver for Davinci MMC controller"); >> + >> -- >> 1.5.6 >> > > > _______________________________________________ > Davinci-linux-open-source mailing list > Davinci-linux-open-source@linux.davincidsp.com > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source > > > hi, Vipin Whether it supports SDHC card on DM355 EVM? I am using the dvsdk based on linux-2.6.10 , I found out SDHC cards can't work. I don't know how to solve this problem. please give me some tips will welcome. best regards.