--- zzzz-none-000/linux-4.9.279/drivers/mmc/host/sdhci.c 2021-08-08 06:38:54.000000000 +0000 +++ puma7-arm-6591-750/linux-4.9.279/drivers/mmc/host/sdhci.c 2023-02-08 10:58:13.000000000 +0000 @@ -13,6 +13,11 @@ * - JMicron (hardware and technical support) */ +/* + * Includes Intel Corporation's changes/modifications dated: 2014, 2018. + * Changed/modified portions - Copyright © 2012-2018 , Intel Corporation. + */ + #include #include #include @@ -103,6 +108,15 @@ pr_err(DRIVER_NAME ": ===========================================\n"); } + +#ifdef CONFIG_ARCH_GEN3 +void sdhci_dump_status(struct sdhci_host *host) +{ + sdhci_dumpregs(host); +} +EXPORT_SYMBOL_GPL(sdhci_dump_status); +#endif + /*****************************************************************************\ * * * Low level functions * @@ -1252,6 +1266,27 @@ return preset; } +#ifdef CONFIG_ARCH_GEN3 +void sdhci_clock_gating(struct sdhci_host *host, bool enable) +{ + u16 clk; + + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + /* Check if bit 2 already has requested value */ + if ((clk & SDHCI_CLOCK_CARD_EN) != enable) + { + if (enable) { + clk |= SDHCI_CLOCK_CARD_EN; + } + else { + clk &= ~SDHCI_CLOCK_CARD_EN; + } + dev_dbg(mmc_dev(host->mmc), "Clock gating clk=0x%x, enable=%d\n", clk, enable); + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + } +} +#endif + u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock, unsigned int *actual_clock) { @@ -1514,8 +1549,22 @@ } } +#ifdef CONFIG_ARCH_GEN3 + /* Check if clock is set correctly - P7 ATOM might shutdown mmc */ + if (!(sdhci_readw(host, SDHCI_CLOCK_CONTROL) & SDHCI_CLOCK_INT_EN)) + { + pr_err("%s: Internal clock is not enable !!!.\n", mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + present = 0; + } +#endif + if (!present || host->flags & SDHCI_DEVICE_DEAD) { mrq->cmd->error = -ENOMEDIUM; +#ifdef CONFIG_ARCH_GEN3 + pr_err("%s: No device !!!.\n", mmc_hostname(host->mmc)); + sdhci_dumpregs(host); +#endif sdhci_finish_mrq(host, mrq); } else { if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23)) @@ -1735,10 +1784,37 @@ spin_unlock_irqrestore(&host->lock, flags); } +#ifdef CONFIG_ARCH_GEN3 +int sdhci_is_card_stable(struct sdhci_host *host) +{ + return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_IS_STABLE); +} + +void sdhci_wait_for_card_stable(struct sdhci_host *host) +{ + int cnt = 0; + + while(!sdhci_is_card_stable(host) && cnt < 12) + { + mdelay(100); + cnt++; + } + + if(!sdhci_is_card_stable(host)) + { + pr_err("%s: Card Present signal not stable\n", mmc_hostname(host->mmc)); + } +} +#endif + static int sdhci_get_cd(struct mmc_host *mmc) { struct sdhci_host *host = mmc_priv(mmc); - int gpio_cd = mmc_gpio_get_cd(mmc); + int gpio_cd = 0; +#ifdef CONFIG_ARCH_GEN3 + sdhci_wait_for_card_stable(host); +#endif + gpio_cd = mmc_gpio_get_cd(mmc); if (host->flags & SDHCI_DEVICE_DEAD) return 0; @@ -1997,6 +2073,14 @@ goto out_unlock; case MMC_TIMING_MMC_HS200: +#ifdef CONFIG_ARCH_GEN3 + /* Skip tuning if certain quirk is enabled */ + if (host->quirks2 & SDHCI_QUIRK2_DONT_TUNE_HS200) { + pr_info(DRIVER_NAME ": skip hs200 tuning for %s\n", mmc_hostname(host->mmc)); + err = 0; + goto out_unlock; + } +#endif /* * Periodic re-tuning for HS400 is not expected to be needed, so * disable it here. @@ -2663,6 +2747,22 @@ u32 intmask, mask, unexpected = 0; int max_loops = 16; +#if (defined(CONFIG_ARCH_GEN3) && defined(CONFIG_HW_MUTEXES)) + /* eMMC card interrupt can be classified as: + * 1: Insert/Remove interrupt + * 2: Data/Command interrupt + * 3: Unexpected error interrupt + * It is assumed that interrupts happen only when a task owns the + * HW Mutex + */ + + if (MMC_HOST_SUPPORTS_HW_MUTEX(host->mmc)) { + if (!EMMC_HW_MUTEX_IS_LOCKED()) { + return IRQ_NONE; + } + } +#endif + spin_lock(&host->lock); if (host->runtime_suspended && !sdhci_sdio_irq_enabled(host)) { @@ -2759,6 +2859,12 @@ sdhci_dumpregs(host); } +#ifdef CONFIG_ARCH_GEN3 + /* Clear ITNC - In Puma for LEVEL interrupts source, the INTC must be clear, + to avoid a second dummy intterrupt */ + ack_irq(host->irq); +#endif + return result; } @@ -2908,13 +3014,36 @@ if (host->tuning_mode != SDHCI_TUNING_MODE_3) mmc_retune_needed(host->mmc); - spin_lock_irqsave(&host->lock, flags); - host->ier &= SDHCI_INT_CARD_INT; - sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); - sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); - spin_unlock_irqrestore(&host->lock, flags); +#if (defined(CONFIG_ARCH_GEN3) && defined(CONFIG_HW_MUTEXES)) + if (MMC_HOST_SUPPORTS_HW_MUTEX(host->mmc)) + { + /* + * This host controller is shared with another processor. Instead of + * masking interrupts at the host controller level, do it at the OS + * level. Danger: this irq must not be shared, or it will obviously + * affect other devices sharing the irq. + */ + disable_irq(host->irq); + } + else + { + spin_lock_irqsave(&host->lock, flags); + host->ier &= SDHCI_INT_CARD_INT; + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + spin_unlock_irqrestore(&host->lock, flags); + + synchronize_hardirq(host->irq); + } +#else + spin_lock_irqsave(&host->lock, flags); + host->ier &= SDHCI_INT_CARD_INT; + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + spin_unlock_irqrestore(&host->lock, flags); - synchronize_hardirq(host->irq); + synchronize_hardirq(host->irq); +#endif spin_lock_irqsave(&host->lock, flags); host->runtime_suspended = true; @@ -2930,6 +3059,16 @@ unsigned long flags; int host_flags = host->flags; +#if (defined(CONFIG_ARCH_GEN3) && defined(CONFIG_HW_MUTEXES)) + if (MMC_HOST_SUPPORTS_HW_MUTEX(host->mmc)) + { + /* + * Unmask the interrupt at the OS level. Corresponds to disable_irq() + * call in sdhci_runtime_suspend_host(). + */ + enable_irq(host->irq); + } +#endif if (host_flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { if (host->ops->enable_dma) host->ops->enable_dma(host); @@ -2998,6 +3137,10 @@ host->flags = SDHCI_SIGNALING_330; +#if (defined(CONFIG_ARCH_GEN3) && defined(CONFIG_HW_MUTEXES)) + host->irq_enable_count = 0; +#endif + return host; } @@ -3099,6 +3242,18 @@ mmc_hostname(mmc), host->version); } +#ifdef CONFIG_ARCH_GEN3 + pr_warning("%s: Caps0 = 0x%X\n",mmc_hostname(host->mmc),host->caps); + pr_warning("%s: Caps1 = 0x%X\n",mmc_hostname(host->mmc),host->caps1); + + /* Puma7: Disable timer tuning */ + if ((host->caps1 & SDHCI_RETUNING_TIMER_COUNT_MASK) != 0) + { + pr_warning("%s: Disable priodic tuning\n",mmc_hostname(host->mmc)); + host->caps1 &= ~SDHCI_RETUNING_TIMER_COUNT_MASK; + } + +#endif if (host->quirks & SDHCI_QUIRK_FORCE_DMA) host->flags |= SDHCI_USE_SDMA; else if (!(host->caps & SDHCI_CAN_DO_SDMA)) @@ -3133,6 +3288,10 @@ host->flags |= SDHCI_USE_64_BIT_DMA; if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { +#ifdef CONFIG_ARCH_GEN3 +/* For preventing dma return error code */ + mmc_dev(mmc)->dma_mask = &host->dma_mask; +#endif ret = sdhci_set_dma_mask(host); if (!ret && host->ops->enable_dma) @@ -3598,6 +3757,10 @@ goto untasklet; } +#if defined (CONFIG_ARCH_GEN3) && defined (CONFIG_INTEL_IRQ_THREAD_CHANGE_PRIORITY) + host->irq_thread = irq_set_sched(host->irq,SCHED_FIFO,60); +#endif + #ifdef CONFIG_MMC_DEBUG sdhci_dumpregs(host); #endif @@ -3674,6 +3837,9 @@ if (sdhci_has_requests(host)) { pr_err("%s: Controller removed during " " transfer!\n", mmc_hostname(mmc)); +#ifdef CONFIG_ARCH_GEN3 + sdhci_dumpregs(host); +#endif sdhci_error_out_mrqs(host, -ENOMEDIUM); }