From 7422f27a8ad7f6a7474e324a61e5a7f8be166c25 Mon Sep 17 00:00:00 2001 From: Ivo Clarysse Date: Thu, 8 Apr 2010 16:14:44 +0200 Subject: MXC: mxc_nand: set NFC registers after reset This patch allows the mxc_nand driver to reset the NAND flash controller. NFC registers are (re-)set after completion of the reset, as a reset will have reverted the NFC registers to their default values. Signed-off-by: Ivo Clarysse Signed-off-by: Sascha Hauer --- drivers/mtd/nand/mxc_nand.c | 90 ++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index b2900d8406d3..ed27d38de27a 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -542,6 +542,41 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) } } +static void preset(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct mxc_nand_host *host = nand_chip->priv; + uint16_t tmp; + + /* disable interrupt, disable spare enable */ + tmp = readw(host->regs + NFC_CONFIG1); + tmp |= NFC_INT_MSK; + tmp &= ~NFC_SP_EN; + if (nand_chip->ecc.mode == NAND_ECC_HW) { + tmp |= NFC_ECC_EN; + } else { + tmp &= ~NFC_ECC_EN; + } + writew(tmp, host->regs + NFC_CONFIG1); + /* preset operation */ + + /* Unlock the internal RAM Buffer */ + writew(0x2, host->regs + NFC_CONFIG); + + /* Blocks to be unlocked */ + if (nfc_is_v21()) { + writew(0x0, host->regs + NFC_V21_UNLOCKSTART_BLKADDR); + writew(0xffff, host->regs + NFC_V21_UNLOCKEND_BLKADDR); + } else if (nfc_is_v1()) { + writew(0x0, host->regs + NFC_V1_UNLOCKSTART_BLKADDR); + writew(0x4000, host->regs + NFC_V1_UNLOCKEND_BLKADDR); + } else + BUG(); + + /* Unlock Block Command for given address range */ + writew(0x4, host->regs + NFC_WRPROT); +} + /* Used by the upper layer to write command to NAND Flash for * different operations to be carried out on NAND Flash */ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, @@ -559,6 +594,10 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, /* Command pre-processing step */ switch (command) { + case NAND_CMD_RESET: + send_cmd(host, command, false); + preset(mtd); + break; case NAND_CMD_STATUS: host->buf_start = 0; @@ -679,7 +718,6 @@ static int __init mxcnd_probe(struct platform_device *pdev) struct mxc_nand_platform_data *pdata = pdev->dev.platform_data; struct mxc_nand_host *host; struct resource *res; - uint16_t tmp; int err = 0, nr_parts = 0; struct nand_ecclayout *oob_smallpage, *oob_largepage; @@ -743,51 +781,17 @@ static int __init mxcnd_probe(struct platform_device *pdev) host->spare_len = 64; oob_smallpage = &nandv2_hw_eccoob_smallpage; oob_largepage = &nandv2_hw_eccoob_largepage; + this->ecc.bytes = 9; } else if (nfc_is_v1()) { host->regs = host->base; host->spare0 = host->base + 0x800; host->spare_len = 16; oob_smallpage = &nandv1_hw_eccoob_smallpage; oob_largepage = &nandv1_hw_eccoob_largepage; - } else - BUG(); - - /* disable interrupt and spare enable */ - tmp = readw(host->regs + NFC_CONFIG1); - tmp |= NFC_INT_MSK; - tmp &= ~NFC_SP_EN; - writew(tmp, host->regs + NFC_CONFIG1); - - init_waitqueue_head(&host->irq_waitq); - - host->irq = platform_get_irq(pdev, 0); - - err = request_irq(host->irq, mxc_nfc_irq, 0, DRIVER_NAME, host); - if (err) - goto eirq; - - /* Reset NAND */ - this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); - - /* preset operation */ - /* Unlock the internal RAM Buffer */ - writew(0x2, host->regs + NFC_CONFIG); - - /* Blocks to be unlocked */ - if (nfc_is_v21()) { - writew(0x0, host->regs + NFC_V21_UNLOCKSTART_BLKADDR); - writew(0xffff, host->regs + NFC_V21_UNLOCKEND_BLKADDR); - this->ecc.bytes = 9; - } else if (nfc_is_v1()) { - writew(0x0, host->regs + NFC_V1_UNLOCKSTART_BLKADDR); - writew(0x4000, host->regs + NFC_V1_UNLOCKEND_BLKADDR); this->ecc.bytes = 3; } else BUG(); - /* Unlock Block Command for given address range */ - writew(0x4, host->regs + NFC_WRPROT); - this->ecc.size = 512; this->ecc.layout = oob_smallpage; @@ -796,14 +800,8 @@ static int __init mxcnd_probe(struct platform_device *pdev) this->ecc.hwctl = mxc_nand_enable_hwecc; this->ecc.correct = mxc_nand_correct_data; this->ecc.mode = NAND_ECC_HW; - tmp = readw(host->regs + NFC_CONFIG1); - tmp |= NFC_ECC_EN; - writew(tmp, host->regs + NFC_CONFIG1); } else { this->ecc.mode = NAND_ECC_SOFT; - tmp = readw(host->regs + NFC_CONFIG1); - tmp &= ~NFC_ECC_EN; - writew(tmp, host->regs + NFC_CONFIG1); } /* NAND bus width determines access funtions used by upper layer */ @@ -817,6 +815,14 @@ static int __init mxcnd_probe(struct platform_device *pdev) this->options |= NAND_USE_FLASH_BBT; } + init_waitqueue_head(&host->irq_waitq); + + host->irq = platform_get_irq(pdev, 0); + + err = request_irq(host->irq, mxc_nfc_irq, 0, DRIVER_NAME, host); + if (err) + goto eirq; + /* first scan to find the device and get the page size */ if (nand_scan_ident(mtd, 1)) { err = -ENXIO; -- cgit v1.2.1 From 63f4079b6a90e2a8ee64c5900a6d4d0bcb79bc65 Mon Sep 17 00:00:00 2001 From: Ivo Clarysse Date: Thu, 8 Apr 2010 16:16:51 +0200 Subject: MXC: mxc_nand: support i.MX21 On i.MX21 SoCs, if the NFC_CONFIG1:NFC_INT_MASK bit is set, NFC_CONFIG2:NFC_INT always reads out zero, even if an operation is completed. This patch uses enable_irq and disable_irq_nosync instead of NFC_CONFIG1:NFC_INT_MASK to mask NFC interrupts. This allows NFC_CONFIG2:NFC_INT to also be used to detect operation completion on i.MX21. The i.MX21 NFC does not signal reset completion using NFC_CONFIG1:NFC_INT_MASK, so instead reset completion is tested by checking if NFC_CONFIG2 becomes 0. Signed-off-by: Ivo Clarysse Signed-off-by: Sascha Hauer --- drivers/mtd/nand/mxc_nand.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index ed27d38de27a..fb03aff8e83a 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -38,7 +38,7 @@ #define DRIVER_NAME "mxc_nand" #define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) -#define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27()) +#define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21()) /* Addresses for NFC registers */ #define NFC_BUF_SIZE 0xE00 @@ -168,11 +168,7 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) { struct mxc_nand_host *host = dev_id; - uint16_t tmp; - - tmp = readw(host->regs + NFC_CONFIG1); - tmp |= NFC_INT_MSK; /* Disable interrupt */ - writew(tmp, host->regs + NFC_CONFIG1); + disable_irq_nosync(irq); wake_up(&host->irq_waitq); @@ -184,15 +180,13 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) */ static void wait_op_done(struct mxc_nand_host *host, int useirq) { - uint32_t tmp; - int max_retries = 2000; + uint16_t tmp; + int max_retries = 8000; if (useirq) { if ((readw(host->regs + NFC_CONFIG2) & NFC_INT) == 0) { - tmp = readw(host->regs + NFC_CONFIG1); - tmp &= ~NFC_INT_MSK; /* Enable interrupt */ - writew(tmp, host->regs + NFC_CONFIG1); + enable_irq(host->irq); wait_event(host->irq_waitq, readw(host->regs + NFC_CONFIG2) & NFC_INT); @@ -226,8 +220,23 @@ static void send_cmd(struct mxc_nand_host *host, uint16_t cmd, int useirq) writew(cmd, host->regs + NFC_FLASH_CMD); writew(NFC_CMD, host->regs + NFC_CONFIG2); - /* Wait for operation to complete */ - wait_op_done(host, useirq); + if (cpu_is_mx21() && (cmd == NAND_CMD_RESET)) { + int max_retries = 100; + /* Reset completion is indicated by NFC_CONFIG2 */ + /* being set to 0 */ + while (max_retries-- > 0) { + if (readw(host->regs + NFC_CONFIG2) == 0) { + break; + } + udelay(1); + } + if (max_retries < 0) + DEBUG(MTD_DEBUG_LEVEL0, "%s: RESET failed\n", + __func__); + } else { + /* Wait for operation to complete */ + wait_op_done(host, useirq); + } } /* This function sends an address (or partial address) to the @@ -548,9 +557,9 @@ static void preset(struct mtd_info *mtd) struct mxc_nand_host *host = nand_chip->priv; uint16_t tmp; - /* disable interrupt, disable spare enable */ + /* enable interrupt, disable spare enable */ tmp = readw(host->regs + NFC_CONFIG1); - tmp |= NFC_INT_MSK; + tmp &= ~NFC_INT_MSK; tmp &= ~NFC_SP_EN; if (nand_chip->ecc.mode == NAND_ECC_HW) { tmp |= NFC_ECC_EN; @@ -819,7 +828,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) host->irq = platform_get_irq(pdev, 0); - err = request_irq(host->irq, mxc_nfc_irq, 0, DRIVER_NAME, host); + err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host); if (err) goto eirq; -- cgit v1.2.1 From 4725f6f17691f4602e3e31d785da5a461a16ccfe Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 1 Apr 2010 10:03:23 +0200 Subject: ARM: MXC: mxcmmc: misc cleanups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Be more verbose on error messages and add one debug message. Signed-off-by: Daniel Mack Cc: Sascha Hauer Cc: Dan Williams Cc: Volker Ernst Cc: Jiri Kosina Cc: Michał Mirosław Signed-off-by: Sascha Hauer --- drivers/mmc/host/mxcmmc.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 2df90412abb5..44a53ee5e212 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -151,6 +151,8 @@ static void mxcmci_softreset(struct mxcmci_host *host) { int i; + dev_dbg(mmc_dev(host->mmc), "mxcmci_softreset\n"); + /* reset sequence */ writew(STR_STP_CLK_RESET, host->base + MMC_REG_STR_STP_CLK); writew(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK, @@ -290,16 +292,25 @@ static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat) dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n", stat); if (stat & STATUS_CRC_READ_ERR) { + dev_err(mmc_dev(host->mmc), "%s: -EILSEQ\n", __func__); data->error = -EILSEQ; } else if (stat & STATUS_CRC_WRITE_ERR) { u32 err_code = (stat >> 9) & 0x3; - if (err_code == 2) /* No CRC response */ + if (err_code == 2) { /* No CRC response */ + dev_err(mmc_dev(host->mmc), + "%s: No CRC -ETIMEDOUT\n", __func__); data->error = -ETIMEDOUT; - else + } else { + dev_err(mmc_dev(host->mmc), + "%s: -EILSEQ\n", __func__); data->error = -EILSEQ; + } } else if (stat & STATUS_TIME_OUT_READ) { + dev_err(mmc_dev(host->mmc), + "%s: read -ETIMEDOUT\n", __func__); data->error = -ETIMEDOUT; } else { + dev_err(mmc_dev(host->mmc), "%s: -EIO\n", __func__); data->error = -EIO; } } else { @@ -433,8 +444,6 @@ static int mxcmci_transfer_data(struct mxcmci_host *host) struct scatterlist *sg; int stat, i; - host->datasize = 0; - host->data = data; host->datasize = 0; -- cgit v1.2.1 From f441b993101d4ee95222ccbaad1e0dd53ea90b64 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 1 Apr 2010 10:03:24 +0200 Subject: ARM: MXC: mxcmmc: Teach the driver SDIO operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Successfully tested on MX31 hardware using libertas SDIO peripherals. Signed-off-by: Daniel Mack Cc: Sascha Hauer Cc: Dan Williams Cc: Volker Ernst Cc: Jiri Kosina Cc: Michał Mirosław Signed-off-by: Sascha Hauer --- drivers/mmc/host/mxcmmc.c | 70 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 44a53ee5e212..51e880c8f193 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -119,6 +119,7 @@ struct mxcmci_host { int detect_irq; int dma; int do_dma; + int use_sdio; unsigned int power_mode; struct imxmmc_platform_data *pdata; @@ -138,6 +139,7 @@ struct mxcmci_host { int clock; struct work_struct datawork; + spinlock_t lock; }; static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); @@ -226,6 +228,9 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, unsigned int cmdat) { + u32 int_cntr; + unsigned long flags; + WARN_ON(host->cmd != NULL); host->cmd = cmd; @@ -249,12 +254,16 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, return -EINVAL; } + int_cntr = INT_END_CMD_RES_EN; + if (mxcmci_use_dma(host)) - writel(INT_READ_OP_EN | INT_WRITE_OP_DONE_EN | - INT_END_CMD_RES_EN, - host->base + MMC_REG_INT_CNTR); - else - writel(INT_END_CMD_RES_EN, host->base + MMC_REG_INT_CNTR); + int_cntr |= INT_READ_OP_EN | INT_WRITE_OP_DONE_EN; + + 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); + spin_unlock_irqrestore(&host->lock, flags); writew(cmd->opcode, host->base + MMC_REG_CMD); writel(cmd->arg, host->base + MMC_REG_ARG); @@ -266,7 +275,14 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, static void mxcmci_finish_request(struct mxcmci_host *host, struct mmc_request *req) { - writel(0, host->base + MMC_REG_INT_CNTR); + u32 int_cntr = 0; + unsigned long flags; + + 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); + spin_unlock_irqrestore(&host->lock, flags); host->req = NULL; host->cmd = NULL; @@ -532,15 +548,27 @@ static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat) static irqreturn_t mxcmci_irq(int irq, void *devid) { struct mxcmci_host *host = devid; + unsigned long flags; + bool sdio_irq; u32 stat; stat = readl(host->base + MMC_REG_STATUS); - writel(stat, host->base + MMC_REG_STATUS); + writel(stat & ~STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS); dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); + spin_lock_irqsave(&host->lock, flags); + sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio; + spin_unlock_irqrestore(&host->lock, flags); + + if (sdio_irq) { + writel(STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS); + mmc_signal_sdio_irq(host->mmc); + } + if (stat & STATUS_END_CMD_RESP) mxcmci_cmd_done(host, stat); + #ifdef HAS_DMA if (mxcmci_use_dma(host) && (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) @@ -677,11 +705,30 @@ static int mxcmci_get_ro(struct mmc_host *mmc) return -ENOSYS; } +static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct mxcmci_host *host = mmc_priv(mmc); + unsigned long flags; + u32 int_cntr; + + spin_lock_irqsave(&host->lock, flags); + host->use_sdio = enable; + int_cntr = readl(host->base + MMC_REG_INT_CNTR); + + if (enable) + int_cntr |= INT_SDIO_IRQ_EN; + else + int_cntr &= ~INT_SDIO_IRQ_EN; + + writel(int_cntr, host->base + MMC_REG_INT_CNTR); + spin_unlock_irqrestore(&host->lock, flags); +} static const struct mmc_host_ops mxcmci_ops = { - .request = mxcmci_request, - .set_ios = mxcmci_set_ios, - .get_ro = mxcmci_get_ro, + .request = mxcmci_request, + .set_ios = mxcmci_set_ios, + .get_ro = mxcmci_get_ro, + .enable_sdio_irq = mxcmci_enable_sdio_irq, }; static int mxcmci_probe(struct platform_device *pdev) @@ -709,7 +756,7 @@ static int mxcmci_probe(struct platform_device *pdev) } mmc->ops = &mxcmci_ops; - mmc->caps = MMC_CAP_4_BIT_DATA; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; /* MMC core transfer sizes tunable parameters */ mmc->max_hw_segs = 64; @@ -728,6 +775,7 @@ static int mxcmci_probe(struct platform_device *pdev) host->mmc = mmc; host->pdata = pdev->dev.platform_data; + spin_lock_init(&host->lock); if (host->pdata && host->pdata->ocr_avail) mmc->ocr_avail = host->pdata->ocr_avail; -- cgit v1.2.1 From 3fcb027d7fd749569665d34a79ce2a8e00bc2ed6 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 1 Apr 2010 10:03:25 +0200 Subject: ARM: MXC: mxcmmc: work around a bug in the SDHC busy line handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MX3 SoCs have a silicon bug which corrupts CRC calculation of multi-block transfers when connected SDIO peripheral doesn't drive the BUSY line as required by the specs. One way to prevent this is to only allow 1-bit transfers. Another way is playing tricks with the DMA engine, but this isn't mainline yet. So for now, we live with the performance drawback of 1-bit transfers until a nicer solution is found. This patch introduces a new host controller callback 'init_card' which is for now only called from mmc_sdio_init_card(). Signed-off-by: Daniel Mack Cc: Sascha Hauer Cc: Dan Williams Cc: Volker Ernst Cc: Jiri Kosina Cc: Michał Mirosław Signed-off-by: Sascha Hauer --- drivers/mmc/core/sdio.c | 6 ++++++ drivers/mmc/host/mxcmmc.c | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 2dd4cfe7ca17..b9dee28ee7d0 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -295,6 +295,12 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, card->type = MMC_TYPE_SDIO; + /* + * Call the optional HC's init_card function to handle quirks. + */ + if (host->ops->init_card) + host->ops->init_card(host, card); + /* * For native busses: set card RCA and quit open drain mode. */ diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 51e880c8f193..2c53024ee439 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -724,11 +724,27 @@ static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable) spin_unlock_irqrestore(&host->lock, flags); } +static void mxcmci_init_card(struct mmc_host *host, struct mmc_card *card) +{ + /* + * MX3 SoCs have a silicon bug which corrupts CRC calculation of + * multi-block transfers when connected SDIO peripheral doesn't + * drive the BUSY line as required by the specs. + * One way to prevent this is to only allow 1-bit transfers. + */ + + if (cpu_is_mx3() && card->type == MMC_TYPE_SDIO) + host->caps &= ~MMC_CAP_4_BIT_DATA; + else + host->caps |= MMC_CAP_4_BIT_DATA; +} + static const struct mmc_host_ops mxcmci_ops = { .request = mxcmci_request, .set_ios = mxcmci_set_ios, .get_ro = mxcmci_get_ro, .enable_sdio_irq = mxcmci_enable_sdio_irq, + .init_card = mxcmci_init_card, }; static int mxcmci_probe(struct platform_device *pdev) -- cgit v1.2.1 From 5a25ad84e01173bb225285eb50f9af48ed1a7598 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Fri, 30 Apr 2010 15:48:26 -0500 Subject: mxc: Add generic USB HW initialization for MX51 This patch adds USB HW initializiation code to /plat-mxc/ehci.c. -Sets some specific PHY settings Renames mxc_set_usbcontrol to mxc_initialize_usb_hw. Adds new register bit defines for the USB HW on Freescale SoCs. This patch applies to 2.6.34-rc6. Signed-off-by: Dinh Nguyen Reviewed-by: Daniel Mack Signed-off-by: Sascha Hauer --- drivers/usb/host/ehci-mxc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index ead59f42e69b..544ccfd7056e 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -199,8 +199,8 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) writel(pdata->portsc, hcd->regs + PORTSC_OFFSET); mdelay(10); - /* setup USBCONTROL. */ - ret = mxc_set_usbcontrol(pdev->id, pdata->flags); + /* setup specific usb hw */ + ret = mxc_initialize_usb_hw(pdev->id, pdata->flags); if (ret < 0) goto err_init; -- cgit v1.2.1 From 4a31f2eff3b8fcf009db35f89eb222ed7835b6b9 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 27 Apr 2010 12:24:42 +0200 Subject: ARM: mx3: Fix a race condition in mxcmmc From cefcdab08d1c9636c4a7290bc2bbe937d051bce4 Mon Sep 17 00:00:00 2001 From: Volker Ernst Date: Mon, 26 Apr 2010 22:51:07 +0200 Subject: [PATCH] ARM: mx3: Fix a race condition in mxcmmc This fixes a race condition regarding interrupt bits in the SDHC controller driver code. In case of PIO-transfer it does not clear SDHC-status bit#11/12 in the INT-handler anymore. INT-handler might be called during an ongoing PIO-data-transfer (with some other INT-flag set) and PIO-transfer depends on these bits being set to detect the end of the data-transfer. This also means that at the end of PIO- transfer that PIO-software has to clear these bits itself. However in case of DMA-transfer these bits have to be cleared in the INT-handler, because they are used to generate INTs then. Works solid, no more problems here, can transfer big files. Signed-off-by: Volker Ernst Acked-by: Daniel Mack Cc: Andy Green Signed-off-by: Sascha Hauer --- drivers/mmc/host/mxcmmc.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 2c53024ee439..ec18e3b60342 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -489,6 +489,9 @@ static void mxcmci_datawork(struct work_struct *work) struct mxcmci_host *host = container_of(work, struct mxcmci_host, datawork); int datastat = mxcmci_transfer_data(host); + + writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, + host->base + MMC_REG_STATUS); mxcmci_finish_data(host, datastat); if (host->req->stop) { @@ -553,7 +556,8 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) u32 stat; stat = readl(host->base + MMC_REG_STATUS); - writel(stat & ~STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS); + writel(stat & ~(STATUS_SDIO_INT_ACTIVE | STATUS_DATA_TRANS_DONE | + STATUS_WRITE_OP_DONE), host->base + MMC_REG_STATUS); dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); @@ -561,6 +565,13 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio; spin_unlock_irqrestore(&host->lock, flags); +#ifdef HAS_DMA + if (mxcmci_use_dma(host) && + (stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE))) + writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, + host->base + MMC_REG_STATUS); +#endif + if (sdio_irq) { writel(STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS); mmc_signal_sdio_irq(host->mmc); -- cgit v1.2.1