--- zzzz-none-000/linux-2.6.39.4/drivers/mmc/host/sdhci.c 2011-08-03 19:43:28.000000000 +0000 +++ puma6-atom-6490-729/linux-2.6.39.4/drivers/mmc/host/sdhci.c 2021-11-10 13:38:15.000000000 +0000 @@ -13,6 +13,12 @@ * - JMicron (hardware and technical support) */ + +/* + * Includes Intel Corporation's changes/modifications dated: 2012. + * Changed/modified portions - Copyright © 2012 - 2014 , Intel Corporation. + */ + #include #include #include @@ -25,7 +31,15 @@ #include #include - +#if defined(CONFIG_HW_MUTEXES) +#if defined(CONFIG_ARCH_GEN3) +#include +#endif +#if defined(CONFIG_ARCH_GEN3_MMC) +#include +#include +#endif +#endif #include "sdhci.h" #define DRIVER_NAME "sdhci" @@ -40,7 +54,11 @@ static unsigned int debug_quirks = 0; +#ifdef CONFIG_ARCH_GEN3 +static void sdhci_prepare_data(struct sdhci_host *, struct mmc_command *); +#else static void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *); +#endif static void sdhci_finish_data(struct sdhci_host *); static void sdhci_send_command(struct sdhci_host *, struct mmc_command *); @@ -148,6 +166,8 @@ unsigned long timeout; u32 uninitialized_var(ier); + // printk("[PowerOn] sdhci_reset\n"); + if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) @@ -157,10 +177,14 @@ if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) ier = sdhci_readl(host, SDHCI_INT_ENABLE); + // printk("[PowerOn] sdhci_reset: sdhci_writeb(host, %d, SDHCI_SOFTWARE_RESET)\n",mask); sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); if (mask & SDHCI_RESET_ALL) + { + // printk("[PowerOn] sdhci_reset(ALL): set host->clock to %d\n",0); host->clock = 0; + } /* Wait max 100 ms */ timeout = 100; @@ -185,10 +209,19 @@ static void sdhci_init(struct sdhci_host *host, int soft) { +#ifdef CONFIG_ARCH_GEN3 + u32 aep_int; +#endif if (soft) + { + // printk("[PowerOn] sdhci_init() call sdhci_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);\n"); sdhci_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); + } else + { + // printk("[PowerOn] sdhci_init() call sdhci_reset(host, SDHCI_RESET_ALL);\n"); sdhci_reset(host, SDHCI_RESET_ALL); + } sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | @@ -196,9 +229,19 @@ SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE); +#ifdef CONFIG_ARCH_GEN3 + if (host->aep_enabled) { + /* Enable AEP to Atom interrupt*/ + aep_int = sdhci_readl(host, PV2ATOM_SW_INT); + aep_int |= EMMC_SW_INT | EMMC_SW_INT_EN | ATOM_DRBL_INT_EN; + sdhci_writel(host, aep_int, PV2ATOM_SW_INT); + } +#endif if (soft) { /* force clock reconfiguration */ + // printk("[PowerOn] sdhci_init: set host->clock to %d\n",0); host->clock = 0; + // printk("[PowerOn] sdhci_init() call sdhci_set_ios\n"); sdhci_set_ios(host->mmc, &host->mmc->ios); } } @@ -405,7 +448,17 @@ cmdlen[0] = cpu_to_le16(cmd); cmdlen[1] = cpu_to_le16(len); - dataddr[0] = cpu_to_le32(addr); +#if defined(CONFIG_ARCH_GEN3_MMC) && (CONFIG_MACH_PUMA6) + /* Puma6 fixup: reduce DDR base offset from 'addr', + as this value write by ARM, and read by ATOM */ + dataddr[0] = cpu_to_le32(addr - CONFIG_ARM_AVALANCHE_SDRAM_PHYS_ADDRESS); +#else + dataddr[0] = cpu_to_le32(addr); +#endif + + // printk("[PowerOn] ADMA desc: desc=0x%X, addr=0x%X, len=0x%X, cmd=0x%X\n",(int*)desc,addr-0x40000000,len,cmd); + // printk("[PowerOn] ADMA desc line: 0x%.2X 0x%.2X 0x%.2X 0x%.2X 0x%.2X 0x%.2X 0x%.2X 0x%.2X\n",desc[7],desc[6],desc[5],desc[4],desc[3],desc[2],desc[1],desc[0]); + } static int sdhci_adma_table_pre(struct sdhci_host *host, @@ -596,6 +649,7 @@ u8 count; unsigned target_timeout, current_timeout; + // printk("[PowerOn] sdhci_calc_timeout()\n"); /* * If the host controller provides us with an incorrect timeout * value, just skip the check and use 0xE. The hardware may take @@ -603,8 +657,14 @@ * timeout value. */ if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) + { + // printk("[PowerOn] sdhci_calc_timeout() SDHCI_QUIRK_BROKEN_TIMEOUT_VAL is set, return 14\n"); return 0xE; - + } +#ifdef CONFIG_ARCH_GEN3 + if (!data) + return 0xE; +#endif /* timeout in us */ target_timeout = data->timeout_ns / 1000 + data->timeout_clks / host->clock; @@ -632,8 +692,10 @@ } if (count >= 0xF) { +#if !defined(CONFIG_ARCH_GEN3) && !defined(CONFIG_ARCH_GEN3_MMC) printk(KERN_WARNING "%s: Too large timeout requested!\n", mmc_hostname(host->mmc)); +#endif count = 0xE; } @@ -650,18 +712,32 @@ else sdhci_clear_set_irqs(host, dma_irqs, pio_irqs); } - +#ifdef CONFIG_ARCH_GEN3 +static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) +#else static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) +#endif { u8 count; u8 ctrl; int ret; +#ifdef CONFIG_ARCH_GEN3 + struct mmc_data *data = cmd->data; + if (data || (cmd->flags & MMC_RSP_BUSY)) { + count = sdhci_calc_timeout(host, data); + if (host->aep_enabled) + count *= 2; + sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL); + } +#endif WARN_ON(host->data); if (data == NULL) return; + // printk("[PowerOn] sdhci_prepare_data()\n"); + /* Sanity checks */ BUG_ON(data->blksz * data->blocks > 524288); BUG_ON(data->blksz > host->mmc->max_blk_size); @@ -670,8 +746,11 @@ host->data = data; host->data_early = 0; +#if defined(CONFIG_MACH_PUMA6) count = sdhci_calc_timeout(host, data); + // printk("[PowerOn] sdhci_prepare_data: set Data timeout counter to %d (max=14)\n",count); sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL); +#endif if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) host->flags |= SDHCI_REQ_USE_DMA; @@ -684,6 +763,8 @@ int broken, i; struct scatterlist *sg; + // printk("[PowerOn] sdhci_prepare_data: host->flags & SDHCI_REQ_USE_DMA.\n"); + broken = 0; if (host->flags & SDHCI_USE_ADMA) { if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) @@ -742,21 +823,29 @@ if (host->flags & SDHCI_REQ_USE_DMA) { if (host->flags & SDHCI_USE_ADMA) { + // printk("[PowerOn] sdhci_prepare_data: sdhci_adma_table_pre ADMA.\n"); ret = sdhci_adma_table_pre(host, data); if (ret) { /* * This only happens when someone fed * us an invalid request. */ + // printk("[PowerOn] sdhci_prepare_data: WARN_ON(1).\n"); WARN_ON(1); host->flags &= ~SDHCI_REQ_USE_DMA; } else { - sdhci_writel(host, host->adma_addr, - SDHCI_ADMA_ADDRESS); +#if defined(CONFIG_ARCH_GEN3_MMC) && (CONFIG_MACH_PUMA6) + /* Puma6 fixup: reduce DDR base offset from 'addr', + as this value write by ARM, and read by ATOM */ + // printk("[PowerOn] sdhci_prepare_data: sdhci_writel(host, host->adma_addr(0x%X),SDHCI_ADMA_ADDRESS.\n",host->adma_addr - CONFIG_ARM_AVALANCHE_SDRAM_PHYS_ADDRESS); + sdhci_writel(host, host->adma_addr - CONFIG_ARM_AVALANCHE_SDRAM_PHYS_ADDRESS, SDHCI_ADMA_ADDRESS); +#else + sdhci_writel(host, host->adma_addr, SDHCI_ADMA_ADDRESS); +#endif } } else { int sg_cnt; - + // printk("[PowerOn] sdhci_prepare_data: dma_map_sg() DMA.\n"); sg_cnt = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, (data->flags & MMC_DATA_READ) ? @@ -767,10 +856,14 @@ * This only happens when someone fed * us an invalid request. */ + // printk("[PowerOn] sdhci_prepare_data: (sg_cnt == 0) WARN_ON(1).\n"); WARN_ON(1); host->flags &= ~SDHCI_REQ_USE_DMA; } else { + // printk("[PowerOn] sdhci_prepare_data: (sg_cnt != 0) WARN_ON(sg_cnt != 1).\n"); WARN_ON(sg_cnt != 1); + + // printk("[PowerOn] sdhci_prepare_data: SDHCI_DMA_ADDRESS = 0x%X.\n",sg_dma_address(data->sg)); sdhci_writel(host, sg_dma_address(data->sg), SDHCI_DMA_ADDRESS); } @@ -783,13 +876,21 @@ * is ADMA. */ if (host->version >= SDHCI_SPEC_200) { + // printk("[PowerOn] sdhci_prepare_data: host->version >= SDHCI_SPEC_200.\n"); + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); ctrl &= ~SDHCI_CTRL_DMA_MASK; if ((host->flags & SDHCI_REQ_USE_DMA) && (host->flags & SDHCI_USE_ADMA)) + { ctrl |= SDHCI_CTRL_ADMA32; + // printk("[PowerOn] sdhci_prepare_data: SDHCI_HOST_CONTROL |= SDHCI_CTRL_ADMA32;.\n"); + } else + { + // printk("[PowerOn] sdhci_prepare_data: SDHCI_HOST_CONTROL |= SDHCI_CTRL_SDMA;.\n"); ctrl |= SDHCI_CTRL_SDMA; + } sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } @@ -805,11 +906,26 @@ host->blocks = data->blocks; } + // printk("[PowerOn] sdhci_prepare_data: sdhci_set_transfer_irqs().\n"); sdhci_set_transfer_irqs(host); +#if !defined(CONFIG_ARCH_GEN3_MMC) /* We do not handle DMA boundaries, so set it to max (512 KiB) */ - sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, data->blksz), SDHCI_BLOCK_SIZE); - sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT); +#ifdef CONFIG_ARCH_GEN3 + if (host->aep_enabled) + sdhci_writel(host, (data->blocks << 16) | + SDHCI_MAKE_BLKSZ(7, data->blksz), SDHCI_BLOCK_SIZE); + else +#endif // CONFIG_ARCH_GEN3 + { + sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, data->blksz), SDHCI_BLOCK_SIZE); + sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT); + } +#else // !defined(CONFIG_ARCH_GEN3_MMC) + /* Note: on Puma6 we must write both BLOCK_SIZE and BLOCK_COUNT registaers at once */ + sdhci_writel(host, (data->blocks<<16)|SDHCI_MAKE_BLKSZ(7, data->blksz), SDHCI_BLOCK_SIZE); +#endif // !defined(CONFIG_ARCH_GEN3_MMC) + } static void sdhci_set_transfer_mode(struct sdhci_host *host, @@ -823,16 +939,29 @@ WARN_ON(!host->data); mode = SDHCI_TRNS_BLK_CNT_EN; + // printk("[PowerOn] sdhci_set_transfer_mode: mode = SDHCI_TRNS_BLK_CNT_EN.\n"); if (data->blocks > 1) { if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) + { + // printk("[PowerOn] sdhci_set_transfer_mode: mode |= SDHCI_TRNS_MULTI | SDHCI_TRNS_ACMD12.\n"); mode |= SDHCI_TRNS_MULTI | SDHCI_TRNS_ACMD12; + } else + { + // printk("[PowerOn] sdhci_set_transfer_mode: mode |= SDHCI_TRNS_MULTI.\n"); mode |= SDHCI_TRNS_MULTI; + } } if (data->flags & MMC_DATA_READ) + { + // printk("[PowerOn] sdhci_set_transfer_mode: mode |= SDHCI_TRNS_READ.\n"); mode |= SDHCI_TRNS_READ; + } if (host->flags & SDHCI_REQ_USE_DMA) + { + // printk("[PowerOn] sdhci_set_transfer_mode: mode |= SDHCI_TRNS_DMA.\n"); mode |= SDHCI_TRNS_DMA; + } sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); } @@ -845,6 +974,7 @@ data = host->data; host->data = NULL; + // printk("[PowerOn] sdhci_finish_data()\n"); if (host->flags & SDHCI_REQ_USE_DMA) { if (host->flags & SDHCI_USE_ADMA) @@ -878,9 +1008,11 @@ sdhci_reset(host, SDHCI_RESET_DATA); } + // printk("[PowerOn] sdhci_finish_data: sdhci_send_command(host, data->stop)\n"); sdhci_send_command(host, data->stop); } else tasklet_schedule(&host->finish_tasklet); + // printk("[PowerOn] sdhci_finish_data: done\n"); } static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) @@ -891,9 +1023,17 @@ WARN_ON(host->cmd); +#ifdef CONFIG_ARCH_GEN3 + if (host->aep_enabled) + /* Wait max 50 ms */ + timeout = 50; + else +#endif /* Wait max 10 ms */ timeout = 10; + // printk("[PowerOn] sdhci_send_command()\n"); + mask = SDHCI_CMD_INHIBIT; if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY)) mask |= SDHCI_DATA_INHIBIT; @@ -916,14 +1056,20 @@ mdelay(1); } + // printk("[PowerOn] sdhci_send_command: mod_timer 10 seconds\n"); mod_timer(&host->timer, jiffies + 10 * HZ); host->cmd = cmd; - + // printk("[PowerOn] sdhci_send_command: sdhci_prepare_data\n"); +#ifdef CONFIG_ARCH_GEN3 + sdhci_prepare_data(host, cmd); +#else sdhci_prepare_data(host, cmd->data); - +#endif + // printk("[PowerOn] sdhci_send_command: SDHCI_ARGUMENT = %X\n",cmd->arg); sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT); + // printk("[PowerOn] sdhci_send_command: sdhci_set_transfer_mode\n"); sdhci_set_transfer_mode(host, cmd->data); if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { @@ -949,8 +1095,17 @@ flags |= SDHCI_CMD_INDEX; if (cmd->data) flags |= SDHCI_CMD_DATA; + // printk("[PowerOn] sdhci_send_command: command flags=0x%.8X. (cmd=%d, crc=%d, data=%d, reponse=%d)\n",flags, ((flags&SDHCI_CMD_INDEX)!=0),((flags&SDHCI_CMD_CRC)!=0),((flags&SDHCI_CMD_DATA)!=0),flags&(SDHCI_CMD_RESP_NONE|SDHCI_CMD_RESP_LONG|SDHCI_CMD_RESP_SHORT_BUSY|SDHCI_CMD_RESP_SHORT)); + + if ((cmd->flags & MMC_RSP_BUSY) && (!(cmd->data))) + { + // printk("[PowerOn] sdhci_send_command: set Data timeout counter to %d (max=14)\n",0xE); + sdhci_writeb(host, 0xE, SDHCI_TIMEOUT_CONTROL); + } + // printk("[PowerOn] sdhci_send_command: SDHCI_COMMAND = %d\n",cmd->opcode); sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); + // printk("[PowerOn] sdhci_send_command: done.\n"); } static void sdhci_finish_command(struct sdhci_host *host) @@ -978,7 +1133,10 @@ host->cmd->error = 0; if (host->data && host->data_early) + { + // printk("[PowerOn] sdhci_finish_command: calling sdhci_finish_data.\n"); sdhci_finish_data(host); + } if (!host->cmd->data) tasklet_schedule(&host->finish_tasklet); @@ -1031,18 +1189,30 @@ clk |= SDHCI_CLOCK_INT_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - /* Wait max 20 ms */ - timeout = 20; - while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) - & SDHCI_CLOCK_INT_STABLE)) { - if (timeout == 0) { - printk(KERN_ERR "%s: Internal clock never " - "stabilised.\n", mmc_hostname(host->mmc)); - sdhci_dumpregs(host); - return; +#ifdef CONFIG_ARCH_GEN3 + if (!host->aep_enabled) +#else + if (!(host->flags & SDHCI_USE_AEP)) +#endif + { + /* Wait max 20 ms */ + timeout = 20; + while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) + & SDHCI_CLOCK_INT_STABLE)) { + if (timeout == 0) { + printk(KERN_ERR "%s: Internal clock never " + "stabilised.\n", mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + return; + } + timeout--; + mdelay(1); } - timeout--; - mdelay(1); + } + else + { + // Do not poll Clock Control in AEP + printk(KERN_WARNING "%s: Do not poll Clock Control in AEP mode - it will never get 'Stable' .\n", mmc_hostname(host->mmc)); } clk |= SDHCI_CLOCK_CARD_EN; @@ -1050,6 +1220,7 @@ out: host->clock = clock; + // printk("[PowerOn] sdhci_set_clock: set host->clock to %d\n",host->clock); } static void sdhci_set_power(struct sdhci_host *host, unsigned short power) @@ -1122,6 +1293,8 @@ bool present; unsigned long flags; + // printk("[PowerOn] sdhci_request called\n"); + host = mmc_priv(mmc); spin_lock_irqsave(&host->lock, flags); @@ -1147,11 +1320,18 @@ present = sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT; - if (!present || host->flags & SDHCI_DEVICE_DEAD) { + // printk("[PowerOn] sdhci_request card present state 0%.8X\n", sdhci_readl(host, SDHCI_PRESENT_STATE)); + if (!present || host->flags & SDHCI_DEVICE_DEAD) + { + // printk("[PowerOn] sdhci_request tasklet_schedule(&host->finish_tasklet)\n"); host->mrq->cmd->error = -ENOMEDIUM; tasklet_schedule(&host->finish_tasklet); - } else + } + else + { + // printk("[PowerOn] sdhci_request -> sdhci_send_command()\n"); sdhci_send_command(host, mrq->cmd); + } mmiowb(); spin_unlock_irqrestore(&host->lock, flags); @@ -1162,7 +1342,11 @@ struct sdhci_host *host; unsigned long flags; u8 ctrl; +#if defined(CONFIG_ARCH_GEN3) || defined(CONFIG_ARCH_GEN3_MMC) + u16 ctrl2; +#endif + // printk("[PowerOn] sdhci_set_ios called\n"); host = mmc_priv(mmc); spin_lock_irqsave(&host->lock, flags); @@ -1200,10 +1384,14 @@ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); if (ios->bus_width == MMC_BUS_WIDTH_8) { ctrl &= ~SDHCI_CTRL_4BITBUS; +#if !defined(CONFIG_ARCH_GEN3) && !defined(CONFIG_ARCH_GEN3_MMC) if (host->version >= SDHCI_SPEC_300) +#endif ctrl |= SDHCI_CTRL_8BITBUS; } else { +#if !defined(CONFIG_ARCH_GEN3) && !defined(CONFIG_ARCH_GEN3_MMC) if (host->version >= SDHCI_SPEC_300) +#endif ctrl &= ~SDHCI_CTRL_8BITBUS; if (ios->bus_width == MMC_BUS_WIDTH_4) ctrl |= SDHCI_CTRL_4BITBUS; @@ -1214,6 +1402,17 @@ } ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); +#if defined(CONFIG_ARCH_GEN3) || defined(CONFIG_ARCH_GEN3_MMC) + if(ios->ddr == MMC_1_8V_DDR_MODE) + { + ctrl2 = SDHCI_CTRL2_DDR; + } + else + { + ctrl2 = SDHCI_CTRL2_SDR; + } + sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); +#endif if ((ios->timing == MMC_TIMING_SD_HS || ios->timing == MMC_TIMING_MMC_HS) @@ -1398,11 +1597,12 @@ if (host->mrq) { printk(KERN_ERR "%s: Timeout waiting for hardware " - "interrupt.\n", mmc_hostname(host->mmc)); + "interrupt. (for CMD%d)\n", mmc_hostname(host->mmc),host->mrq->cmd->opcode); sdhci_dumpregs(host); if (host->data) { host->data->error = -ETIMEDOUT; + // printk("[PowerOn] sdhci_timeout_timer: calling sdhci_finish_data.\n"); sdhci_finish_data(host); } else { if (host->cmd) @@ -1435,11 +1635,22 @@ sdhci_dumpregs(host); return; } - +#ifdef CONFIG_ARCH_GEN3 + /* Manually return timeout to CMD8(SD_SEND_IF_COND) and CMD5(SD_IO_SEND_OP_COND), + * as AEP doesn't support them + */ + if (host->aep_enabled) { + if ((host->cmd->opcode == 8) && (host->cmd->flags == (MMC_RSP_SPI_R7 | + MMC_RSP_R7 | MMC_CMD_BCR))) + host->cmd->error = -ETIMEDOUT; + else if ((host->cmd->opcode == 5) && (host->cmd->flags == (MMC_RSP_SPI_R4 | + MMC_RSP_R4 | MMC_CMD_BCR))) + host->cmd->error = -ETIMEDOUT; + } +#endif if (intmask & SDHCI_INT_TIMEOUT) host->cmd->error = -ETIMEDOUT; - else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT | - SDHCI_INT_INDEX)) + else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) host->cmd->error = -EILSEQ; if (host->cmd->error) { @@ -1512,29 +1723,45 @@ * indicate that a busy state has ended. See comment * above in sdhci_cmd_irq(). */ - if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) { + if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) + { if (intmask & SDHCI_INT_DATA_END) { sdhci_finish_command(host); return; } + else if (intmask & SDHCI_INT_DATA_TIMEOUT) + { + printk(KERN_ERR "%s: Got data interrupt 0x%08x SDHCI_INT_DATA_TIMEOUT " + " while waiting to Command with BUSY flag to finish.\n",mmc_hostname(host->mmc), (unsigned)intmask); + return; + } } printk(KERN_ERR "%s: Got data interrupt 0x%08x even " - "though no data operation was in progress.\n", - mmc_hostname(host->mmc), (unsigned)intmask); + "though no data operation was in progress. (CMD%d)\n", + mmc_hostname(host->mmc), (unsigned)intmask, host->mrq->cmd->opcode); sdhci_dumpregs(host); return; } if (intmask & SDHCI_INT_DATA_TIMEOUT) + { host->data->error = -ETIMEDOUT; + printk(KERN_ERR "%s: Got data interrupt 0x%08x SDHCI_INT_DATA_TIMEOUT.\n",mmc_hostname(host->mmc), (unsigned)intmask); + } else if (intmask & SDHCI_INT_DATA_END_BIT) + { + printk(KERN_ERR "%s: Got data interrupt 0x%08x SDHCI_INT_DATA_END_BIT.\n",mmc_hostname(host->mmc), (unsigned)intmask); host->data->error = -EILSEQ; + } else if ((intmask & SDHCI_INT_DATA_CRC) && SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) != MMC_BUS_TEST_R) - host->data->error = -EILSEQ; + { + printk(KERN_ERR "%s: Got data interrupt 0x%08x SDHCI_INT_DATA_CRC, and SDHCI_COMMAND != MMC_BUS_TEST_R.\n",mmc_hostname(host->mmc), (unsigned)intmask); + host->data->error = -EILSEQ; + } else if (intmask & SDHCI_INT_ADMA_ERROR) { printk(KERN_ERR "%s: ADMA error\n", mmc_hostname(host->mmc)); sdhci_show_adma_error(host); @@ -1542,8 +1769,12 @@ } if (host->data->error) + { + // printk("[PowerOn] sdhci_data_irq: calling sdhci_finish_data(host), due to an error\n"); sdhci_finish_data(host); - else { + } + else + { if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) sdhci_transfer_pio(host); @@ -1565,10 +1796,12 @@ */ host->data_early = 1; } else { + // printk("[PowerOn] sdhci_data_irq: got SDHCI_INT_DATA_END, calling sdhci_finish_data(host)\n"); sdhci_finish_data(host); } } } + // printk("[PowerOn] sdhci_data_irq: done\n"); } static irqreturn_t sdhci_irq(int irq, void *dev_id) @@ -1576,12 +1809,59 @@ irqreturn_t result; struct sdhci_host* host = dev_id; u32 intmask; +#ifdef CONFIG_ARCH_GEN3 + u32 aep_int; +#endif int cardint = 0; +#if (defined(CONFIG_ARCH_GEN3) || defined(CONFIG_ARCH_GEN3_MMC)) && defined(CONFIG_HW_MUTEXES) + /* eMMC card interrupt can be classified to: + * 1, Insert/Remove interrupt + * 2, Data/Command Interrupt + * 3, Unexpected error interrupt + * Interrupt type of 1 & 3 won't happen in Intel CE2600 platform + * It's assumed that interrupt happens only when a task owns + * HW Mutex + */ + if (host->flags & SDHCI_SUPPORT_HW_MUTEX) { + if (!EMMC_HW_MUTEX_IS_LOCKED(host->mmc)) + { + printk(KERN_ERR "%s: Got MMC interrupt, although the IRQ is disabled!\n",mmc_hostname(host->mmc)); + /* Should never get here: + If not holding the HW mutex, then the IRQ is disabled + */ + return IRQ_NONE; + } + } +#endif + spin_lock(&host->lock); +#ifdef CONFIG_ARCH_GEN3 + /* Check if it's an AEP interrupt */ + if (host->aep_enabled) { + aep_int = sdhci_readl(host, PV2ATOM_SW_INT); + if (aep_int & EMMC_SW_INT) { + /* W1C */ + sdhci_writel(host, aep_int, PV2ATOM_SW_INT); + } else { + result = IRQ_NONE; + goto out; + } + } +#endif + intmask = sdhci_readl(host, SDHCI_INT_STATUS); +#if defined(CONFIG_ARCH_GEN3_MMC) + /* Clear AEP interrupt*/ + if (host->flags & SDHCI_USE_AEP) + { + aep_clear_mmc_interrupt(); + } +#endif + + if (!intmask || intmask == 0xffffffff) { result = IRQ_NONE; goto out; @@ -1591,6 +1871,8 @@ mmc_hostname(host->mmc), intmask); if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { + //printk("%s: Got MMC interrupt, SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE\n",mmc_hostname(host->mmc)); + sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS); tasklet_schedule(&host->card_tasklet); @@ -1599,15 +1881,18 @@ intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); if (intmask & SDHCI_INT_CMD_MASK) { + // printk("[PowerOn] %s: Got MMC interrupt, SDHCI_INT_CMD_MASK\n",mmc_hostname(host->mmc)); sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK, SDHCI_INT_STATUS); sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK); } if (intmask & SDHCI_INT_DATA_MASK) { + // printk("[PowerOn] %s: Got MMC interrupt, SDHCI_INT_DATA_MASK\n",mmc_hostname(host->mmc)); sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK, SDHCI_INT_STATUS); sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK); + // printk("[PowerOn] sdhci_irq: sdhci_data_irq return.\n"); } intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK); @@ -1623,7 +1908,10 @@ intmask &= ~SDHCI_INT_BUS_POWER; if (intmask & SDHCI_INT_CARD_INT) + { + // printk("[PowerOn] %s: Got MMC interrupt, SDHCI_INT_CARD_INT\n",mmc_hostname(host->mmc)); cardint = 1; + } intmask &= ~SDHCI_INT_CARD_INT; @@ -1641,11 +1929,25 @@ out: spin_unlock(&host->lock); + // printk("[PowerOn] sdhci_irq: out.\n"); /* * We have to delay this as it calls back into the driver. */ if (cardint) + { + // printk("[PowerOn] sdhci_irq: mmc_signal_sdio_irq.\n"); mmc_signal_sdio_irq(host->mmc); + } + + // printk("[PowerOn] sdhci_irq: ack_irq.\n"); + +#if defined(CONFIG_ARCH_GEN3_MMC) + /* Clear ITNC - In Puma6 for LEVEL interrupts source, the INTC must be clear, + to avoid a second dummy intterrupt */ + ack_irq(host->irq); +#endif + + // printk("[PowerOn] sdhci_irq: done\n"); return result; } @@ -1662,6 +1964,10 @@ { int ret; +#ifdef CONFIG_ARCH_GEN3 + if (host->quirks & SDHCI_QUIRK_NO_SUSPEND) + return 0; +#endif sdhci_disable_card_detection(host); ret = mmc_suspend_host(host->mmc); @@ -1682,7 +1988,11 @@ { int ret; - if (host->vmmc) { +#ifdef CONFIG_ARCH_GEN3 + if (host->quirks & SDHCI_QUIRK_NO_SUSPEND) + return 0; +#endif + if (host->vmmc) { int ret = regulator_enable(host->vmmc); if (ret) return ret; @@ -1736,9 +2046,13 @@ WARN_ON(dev == NULL); + // printk("[PowerOn] sdhci_alloc_host() calling mmc_alloc_host\n"); mmc = mmc_alloc_host(sizeof(struct sdhci_host) + priv_size, dev); if (!mmc) + { + // printk("[PowerOn] mmc_alloc_host() return error\n"); return ERR_PTR(-ENOMEM); + } host = mmc_priv(mmc); host->mmc = mmc; @@ -1763,6 +2077,7 @@ if (debug_quirks) host->quirks = debug_quirks; + // printk("[PowerOn] sdhci_add_host: call sdhci_reset(host, SDHCI_RESET_ALL) \n"); sdhci_reset(host, SDHCI_RESET_ALL); host->version = sdhci_readw(host, SDHCI_HOST_VERSION); @@ -1777,6 +2092,16 @@ caps = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps : sdhci_readl(host, SDHCI_CAPABILITIES); +#ifdef CONFIG_ARCH_GEN3 + if(host->flags & SDHCI_SUPPORT_HW_MUTEX) + caps |= SDHCI_CAN_VDD_330; +#endif + +#if defined(CONFIG_ARCH_GEN3_MMC) && (CONFIG_MACH_PUMA6) + caps |= SDHCI_CAN_VDD_330; +#endif + // printk("[PowerOn] sdhci_add_host: sdhci caps: %p\n",caps); + if (host->quirks & SDHCI_QUIRK_FORCE_DMA) host->flags |= SDHCI_USE_SDMA; else if (!(caps & SDHCI_CAN_DO_SDMA)) @@ -1790,6 +2115,8 @@ host->flags &= ~SDHCI_USE_SDMA; } + // printk("[PowerOn] sdhci_add_host: sdhci flasgs: %s\n",((host->flags & SDHCI_USE_SDMA)?"Set to use use SDMA":"Set to not use SDMA")); + if ((host->version >= SDHCI_SPEC_200) && (caps & SDHCI_CAN_DO_ADMA2)) host->flags |= SDHCI_USE_ADMA; @@ -1799,6 +2126,8 @@ host->flags &= ~SDHCI_USE_ADMA; } + // printk("[PowerOn] sdhci_add_host: sdhci flags: %s\n",((host->flags & SDHCI_USE_ADMA)?"Set to use use ADMA":"Set to not use ADMA")); + if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { if (host->ops->enable_dma) { if (host->ops->enable_dma(host)) { @@ -1817,6 +2146,7 @@ * (128) and potentially one alignment transfer for * each of those entries. */ + // // printk("[PowerOn] Allocate descriptors for ADMA\n"); host->adma_desc = kmalloc((128 * 2 + 1) * 4, GFP_KERNEL); host->align_buffer = kmalloc(128 * 4, GFP_KERNEL); if (!host->adma_desc || !host->align_buffer) { @@ -1846,6 +2176,8 @@ host->max_clk = (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; + // printk("[PowerOn] sdhci_add_host: sdhci caps max_clk %d * 1,000,000\n",host->max_clk); + host->max_clk *= 1000000; if (host->max_clk == 0 || host->quirks & SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) { @@ -1896,14 +2228,33 @@ * won't assume 8-bit width for hosts without that CAP. */ if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA)) +#if !defined(CONFIG_ARCH_GEN3) && !defined(CONFIG_ARCH_GEN3_MMC) mmc->caps |= MMC_CAP_4_BIT_DATA; +#else + mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; +#endif if (caps & SDHCI_CAN_DO_HISPD) mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; +#if defined(CONFIG_ARCH_GEN3) || defined(CONFIG_ARCH_GEN3_MMC) + if(host->flags & SDHCI_SUPPORT_DDR) + mmc->caps |= MMC_CAP_1_8V_DDR; + +#if defined(CONFIG_ARCH_GEN3_MMC) + //printk("[PowerOn] sdhci_add_host() : host->caps = MMC_CAP_NONREMOVABLE \n"); + mmc->caps |= MMC_CAP_NONREMOVABLE; /* This add support of unsafe resume - for eMMC FW upgrade */ +#endif +#endif + if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) && mmc_card_is_removable(mmc)) + { mmc->caps |= MMC_CAP_NEEDS_POLL; + // printk("[PowerOn] sdhci_add_host: sdhci mmc caps quirks: Need card detection polling - %s\n",(mmc->caps & MMC_CAP_NEEDS_POLL?"Yes":"No")); + } + + ocr_avail = 0; if (caps & SDHCI_CAN_VDD_330) @@ -2011,6 +2362,7 @@ regulator_enable(host->vmmc); } + // printk("[PowerOn] sdhci_add_host: sdhci_init calledS\n"); sdhci_init(host, 0); #ifdef CONFIG_MMC_DEBUG @@ -2032,6 +2384,7 @@ mmiowb(); + // printk("[PowerOn] sdhci_add_host: mmc_add_host calledS\n"); mmc_add_host(mmc); printk(KERN_INFO "%s: SDHCI controller on %s [%s] using %s\n",