From patchwork Thu Sep 9 22:02:44 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Fuzzey X-Patchwork-Id: 178242 Return-path: X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on void.printf.net X-Spam-Level: X-Spam-Status: No, score=-1.0 required=2.9 tests=RCVD_IN_DNSWL_LOW autolearn=disabled version=3.2.5 Envelope-to: chris@printf.net Delivery-date: Thu, 09 Sep 2010 23:03:05 +0100 Received: from lists.laptop.org ([18.85.2.145] helo=mail.laptop.org) by void.printf.net with esmtp (Exim 4.69) (envelope-from ) id 1OtpCw-0005ve-S6 for chris@printf.net; Thu, 09 Sep 2010 23:03:04 +0100 Received: by mail.laptop.org (Postfix) id 7844824A25; Thu, 9 Sep 2010 18:02:42 -0400 (EDT) Delivered-To: cjb@laptop.org Received: from spam.laptop.org (spam.laptop.org [18.85.46.23]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.laptop.org (Postfix) with ESMTPS id 6834924A2B for ; Thu, 9 Sep 2010 18:02:41 -0400 (EDT) X-ASG-Debug-ID: 1284069776-0b74b1a70004-zHW3sV Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by spam.laptop.org with ESMTP id XHLAcqMDcDl73KmV for ; Thu, 09 Sep 2010 18:02:58 -0400 (EDT) X-Barracuda-Envelope-From: linux-mmc-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756277Ab0IIWCu (ORCPT ); Thu, 9 Sep 2010 18:02:50 -0400 Received: from mail-wy0-f174.google.com ([74.125.82.174]:59660 "EHLO mail-wy0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756234Ab0IIWCs (ORCPT ); Thu, 9 Sep 2010 18:02:48 -0400 Received: by wyf22 with SMTP id 22so1933855wyf.19 for ; Thu, 09 Sep 2010 15:02:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:subject:to:cc:date :message-id:user-agent:mime-version:content-type :content-transfer-encoding; bh=GQ/htDxWXf9yCkxSsYmcoQ+hjWlIqwF0XeBwZ0tMv/o=; b=lW3ORd2Ko4RSvn1FjzJF6vs73w68bloXeh7Q3w2SO1Frb0Vk9aaJakd1G0Yp6gW4br MLX/PH3FbcxZUjlkua8hpb1wEWhtQCX/av4/0IC/8sgZw6CUTBQFg1foVNvEcQ9LShBc x1bfMl7dhN1midqmTvBhPFzDeusarbsU1vrzA= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:subject:to:cc:date:message-id:user-agent:mime-version :content-type:content-transfer-encoding; b=BL7QkEFVgeiYpDj672p90uWFjxitVtpPiRtbK+RJzS3RyPjtoosU7G4tROlASbJq2k 0aPlssp6y4fX3CeufYxOEyfLrZCX/UmZsDFo9nEGdbFU2KfZR/hfQM3MK/98k025Gd4t j/PkdEhBIiOAfCTHKwx71ylWRcX76Yx8oK6y4= Received: by 10.216.93.10 with SMTP id k10mr855099wef.38.1284069767159; Thu, 09 Sep 2010 15:02:47 -0700 (PDT) Received: from srv002.fuzzey.net ([93.4.66.10]) by mx.google.com with ESMTPS id k7sm1233450wej.2.2010.09.09.15.02.45 (version=TLSv1/SSLv3 cipher=RC4-MD5); Thu, 09 Sep 2010 15:02:46 -0700 (PDT) From: Martin Fuzzey X-ASG-Orig-Subj: [PATCH V8] mmc : Add i.MX21 support to mxcmmc driver Subject: [PATCH V8] mmc : Add i.MX21 support to mxcmmc driver To: Sascha Hauer , linux-mmc@vger.kernel.org, Pierre Ossman Cc: linux-arm-kernel@lists.infradead.org, cjb@laptop.org Date: Fri, 10 Sep 2010 00:02:44 +0200 Message-ID: <20100909220110.12456.14417.stgit@srv002.fuzzey.net> User-Agent: StGIT/0.14.2 MIME-Version: 1.0 Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Barracuda-Connect: vger.kernel.org[209.132.180.67] X-Barracuda-Start-Time: 1284069778 X-Barracuda-URL: http://18.85.46.23:8000/cgi-mod/mark.cgi X-Virus-Scanned: by bsmtpd at laptop.org X-Barracuda-Spam-Score: 0.00 X-Barracuda-Spam-Status: No, SCORE=0.00 using global scores of TAG_LEVEL=3.5 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=5.5 tests= X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.2.40416 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- diff --git a/arch/arm/mach-imx/clock-imx21.c b/arch/arm/mach-imx/clock-imx21.c index dafc271..076cd43 100644 --- a/arch/arm/mach-imx/clock-imx21.c +++ b/arch/arm/mach-imx/clock-imx21.c @@ -1170,8 +1170,8 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[1]) _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[2]) _REGISTER_CLOCK(NULL, "pwm", pwm_clk[0]) - _REGISTER_CLOCK(NULL, "sdhc1", sdhc_clk[0]) - _REGISTER_CLOCK(NULL, "sdhc2", sdhc_clk[1]) + _REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc_clk[0]) + _REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc_clk[1]) _REGISTER_CLOCK(NULL, "cspi1", cspi_clk[0]) _REGISTER_CLOCK(NULL, "cspi2", cspi_clk[1]) _REGISTER_CLOCK(NULL, "cspi3", cspi_clk[2]) diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 350f78e..88dd31f 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -56,6 +56,8 @@ #define MMC_REG_INT_CNTR 0x24 #define MMC_REG_CMD 0x28 #define MMC_REG_ARG 0x2C +#define MMC_REG_ARGH 0x2C +#define MMC_REG_ARGL 0x30 #define MMC_REG_RES_FIFO 0x34 #define MMC_REG_BUFFER_ACCESS 0x38 @@ -145,6 +147,49 @@ struct mxcmci_host { static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); +static void mxcmci_write_arg(struct mxcmci_host *host, u32 arg) +{ + if (cpu_is_mx21()) { + writel(arg >> 16, host->base + MMC_REG_ARGH); + writel(arg & 0xFFFF, host->base + MMC_REG_ARGL); + } else { + writel(arg, host->base + MMC_REG_ARG); + } +} + +static void mxcmci_ack_int(struct mxcmci_host *host, u32 stat) +{ + if (cpu_is_mx21()) { + u32 intclr = readl(host->base + MMC_REG_INT_CNTR); + + if (stat & STATUS_DATA_TRANS_DONE) + intclr |= INT_READ_OP_EN; + if (stat & STATUS_WRITE_OP_DONE) + intclr |= INT_WRITE_OP_DONE_EN; + if (stat & STATUS_END_CMD_RESP) + intclr |= INT_END_CMD_RES_EN; + + writel(intclr, host->base + MMC_REG_INT_CNTR); + } +} + +static inline void mxcmci_set_int_cntr(struct mxcmci_host *host, u32 enables) +{ + if (cpu_is_mx21()) /* some interrupt enables have reverse polarity */ + enables ^= 0x1F; + writel(enables, host->base + MMC_REG_INT_CNTR); +} + +static inline void mxcmci_start_clock(struct mxcmci_host *host) +{ + writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK); +} + +static inline void mxcmci_stop_clock(struct mxcmci_host *host) +{ + writew(STR_STP_CLK_STOP_CLK, host->base + MMC_REG_STR_STP_CLK); +} + static inline int mxcmci_use_dma(struct mxcmci_host *host) { return host->do_dma; @@ -221,7 +266,10 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) } wmb(); - imx_dma_enable(host->dma); + /* MX21: unreliable writes if dma enabled here - do on command done */ + if (mxcmci_use_dma(host) && + (!cpu_is_mx21() || host->dma_dir == DMA_FROM_DEVICE)) + imx_dma_enable(host->dma); #endif /* HAS_DMA */ return 0; } @@ -263,12 +311,16 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, spin_lock_irqsave(&host->lock, flags); if (host->use_sdio) int_cntr |= INT_SDIO_IRQ_EN; - writel(int_cntr, host->base + MMC_REG_INT_CNTR); + mxcmci_set_int_cntr(host, int_cntr); spin_unlock_irqrestore(&host->lock, flags); writew(cmd->opcode, host->base + MMC_REG_CMD); - writel(cmd->arg, host->base + MMC_REG_ARG); + mxcmci_write_arg(host, cmd->arg); writew(cmdat, host->base + MMC_REG_CMD_DAT_CONT); + if (cpu_is_mx21()) { + /* i.MX21 requires clock start after submitting command */ + mxcmci_start_clock(host); + } return 0; } @@ -282,7 +334,7 @@ static void mxcmci_finish_request(struct mxcmci_host *host, spin_lock_irqsave(&host->lock, flags); if (host->use_sdio) int_cntr |= INT_SDIO_IRQ_EN; - writel(int_cntr, host->base + MMC_REG_INT_CNTR); + mxcmci_set_int_cntr(host, int_cntr); spin_unlock_irqrestore(&host->lock, flags); host->req = NULL; @@ -397,19 +449,29 @@ static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask) static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes) { unsigned int stat; - u32 *buf = _buf; - - while (bytes > 3) { - stat = mxcmci_poll_status(host, + u16 *buf16 = _buf; + u32 *buf32 = _buf; + int count = 0; + int fifo_size = host->cmdat & CMD_DAT_CONT_BUS_WIDTH_4 ? 64 : 16; + int buffer_width = cpu_is_mx21() ? 2 : 4; + + while (bytes >= buffer_width) { + if (count % fifo_size == 0) { + stat = mxcmci_poll_status(host, STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE); - if (stat) - return stat; - *buf++ = readl(host->base + MMC_REG_BUFFER_ACCESS); - bytes -= 4; + if (stat) + return stat; + } + if (buffer_width == 2) + *buf16++ = (u16)readl( + host->base + MMC_REG_BUFFER_ACCESS); + else + *buf32++ = readl(host->base + MMC_REG_BUFFER_ACCESS); + bytes -= buffer_width; + count += buffer_width; } if (bytes) { - u8 *b = (u8 *)buf; u32 tmp; stat = mxcmci_poll_status(host, @@ -417,7 +479,10 @@ static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes) if (stat) return stat; tmp = readl(host->base + MMC_REG_BUFFER_ACCESS); - memcpy(b, &tmp, bytes); + if (buffer_width == 2) + memcpy((u8 *)buf16, &tmp, bytes); + else + memcpy((u8 *)buf32, &tmp, bytes); } return 0; @@ -426,33 +491,41 @@ static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes) static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes) { unsigned int stat; - u32 *buf = _buf; - - while (bytes > 3) { - stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); - if (stat) - return stat; - writel(*buf++, host->base + MMC_REG_BUFFER_ACCESS); - bytes -= 4; + u16 *buf16 = _buf; + u32 *buf32 = _buf; + int count = 0; + int fifo_size = host->cmdat & CMD_DAT_CONT_BUS_WIDTH_4 ? 64 : 16; + int buffer_width = cpu_is_mx21() ? 2 : 4; + + while (bytes >= buffer_width) { + if (count % fifo_size == 0) { + stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); + if (stat) + return stat; + } + if (buffer_width == 2) + writel(*buf16++, host->base + MMC_REG_BUFFER_ACCESS); + else + writel(*buf32++, host->base + MMC_REG_BUFFER_ACCESS); + bytes -= buffer_width; + count += buffer_width; } if (bytes) { - u8 *b = (u8 *)buf; u32 tmp; stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); if (stat) return stat; - memcpy(&tmp, b, bytes); + if (buffer_width == 2) + memcpy(&tmp, (u8 *)buf16, bytes); + else + memcpy(&tmp, (u8 *)buf32, bytes); writel(tmp, host->base + MMC_REG_BUFFER_ACCESS); } - stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); - if (stat) - return stat; - - return 0; + return mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); } static int mxcmci_transfer_data(struct mxcmci_host *host) @@ -540,13 +613,20 @@ static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat) return; } + if (!host->data) + return; + +#ifdef HAS_DMA /* For the DMA case the DMA engine handles the data transfer * automatically. For non DMA we have to do it ourselves. * Don't do it in interrupt context though. */ - if (!mxcmci_use_dma(host) && host->data) + if (mxcmci_use_dma(host)) { + if (cpu_is_mx21() && host->dma_dir == DMA_TO_DEVICE) + imx_dma_enable(host->dma); + } else +#endif schedule_work(&host->datawork); - } static irqreturn_t mxcmci_irq(int irq, void *devid) @@ -559,6 +639,7 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) stat = readl(host->base + MMC_REG_STATUS); writel(stat & ~(STATUS_SDIO_INT_ACTIVE | STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE), host->base + MMC_REG_STATUS); + mxcmci_ack_int(host, stat); dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); @@ -689,9 +770,9 @@ static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (ios->clock) { mxcmci_set_clk_rate(host, ios->clock); - writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK); + mxcmci_start_clock(host); } else { - writew(STR_STP_CLK_STOP_CLK, host->base + MMC_REG_STR_STP_CLK); + mxcmci_stop_clock(host); } host->clock = ios->clock; @@ -845,7 +926,7 @@ static int mxcmci_probe(struct platform_device *pdev) /* recommended in data sheet */ writew(0x2db4, host->base + MMC_REG_READ_TO); - writel(host->default_irq_mask, host->base + MMC_REG_INT_CNTR); + mxcmci_set_int_cntr(host, host->default_irq_mask); #ifdef HAS_DMA host->dma = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_LOW); @@ -862,7 +943,9 @@ static int mxcmci_probe(struct platform_device *pdev) } ret = imx_dma_config_channel(host->dma, - IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO, + (cpu_is_mx21() ? + IMX_DMA_MEMSIZE_16 : IMX_DMA_MEMSIZE_32) + | IMX_DMA_TYPE_FIFO, IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, r->start, 0); if (ret) {