Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/mmc/host/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 130 kB image not shown  

Quelle  sdhci.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *  linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver
 *
 *  Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
 *
 * Thanks to the following companies for their support:
 *
 *     - JMicron (hardware and technical support)
 */


#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/ktime.h>
#include <linux/highmem.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/scatterlist.h>
#include <linux/sizes.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/bug.h>
#include <linux/leds.h>

#include <linux/mmc/mmc.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/slot-gpio.h>

#include "sdhci.h"

#define DRIVER_NAME "sdhci"

#define DBG(f, x...) \
 pr_debug("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)

#define SDHCI_DUMP(f, x...) \
 pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)

#define MAX_TUNING_LOOP 40

static unsigned int debug_quirks = 0;
static unsigned int debug_quirks2;

static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);

void sdhci_dumpregs(struct sdhci_host *host)
{
 SDHCI_DUMP("============ SDHCI REGISTER DUMP ===========\n");

 SDHCI_DUMP("Sys addr: 0x%08x | Version: 0x%08x\n",
     sdhci_readl(host, SDHCI_DMA_ADDRESS),
     sdhci_readw(host, SDHCI_HOST_VERSION));
 SDHCI_DUMP("Blk size: 0x%08x | Blk cnt: 0x%08x\n",
     sdhci_readw(host, SDHCI_BLOCK_SIZE),
     sdhci_readw(host, SDHCI_BLOCK_COUNT));
 SDHCI_DUMP("Argument: 0x%08x | Trn mode: 0x%08x\n",
     sdhci_readl(host, SDHCI_ARGUMENT),
     sdhci_readw(host, SDHCI_TRANSFER_MODE));
 SDHCI_DUMP("Present: 0x%08x | Host ctl: 0x%08x\n",
     sdhci_readl(host, SDHCI_PRESENT_STATE),
     sdhci_readb(host, SDHCI_HOST_CONTROL));
 SDHCI_DUMP("Power: 0x%08x | Blk gap: 0x%08x\n",
     sdhci_readb(host, SDHCI_POWER_CONTROL),
     sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL));
 SDHCI_DUMP("Wake-up: 0x%08x | Clock: 0x%08x\n",
     sdhci_readb(host, SDHCI_WAKE_UP_CONTROL),
     sdhci_readw(host, SDHCI_CLOCK_CONTROL));
 SDHCI_DUMP("Timeout: 0x%08x | Int stat: 0x%08x\n",
     sdhci_readb(host, SDHCI_TIMEOUT_CONTROL),
     sdhci_readl(host, SDHCI_INT_STATUS));
 SDHCI_DUMP("Int enab: 0x%08x | Sig enab: 0x%08x\n",
     sdhci_readl(host, SDHCI_INT_ENABLE),
     sdhci_readl(host, SDHCI_SIGNAL_ENABLE));
 SDHCI_DUMP("ACmd stat: 0x%08x | Slot int: 0x%08x\n",
     sdhci_readw(host, SDHCI_AUTO_CMD_STATUS),
     sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
 SDHCI_DUMP("Caps: 0x%08x | Caps_1: 0x%08x\n",
     sdhci_readl(host, SDHCI_CAPABILITIES),
     sdhci_readl(host, SDHCI_CAPABILITIES_1));
 SDHCI_DUMP("Cmd: 0x%08x | Max curr: 0x%08x\n",
     sdhci_readw(host, SDHCI_COMMAND),
     sdhci_readl(host, SDHCI_MAX_CURRENT));
 SDHCI_DUMP("Resp[0]: 0x%08x | Resp[1]: 0x%08x\n",
     sdhci_readl(host, SDHCI_RESPONSE),
     sdhci_readl(host, SDHCI_RESPONSE + 4));
 SDHCI_DUMP("Resp[2]: 0x%08x | Resp[3]: 0x%08x\n",
     sdhci_readl(host, SDHCI_RESPONSE + 8),
     sdhci_readl(host, SDHCI_RESPONSE + 12));
 SDHCI_DUMP("Host ctl2: 0x%08x\n",
     sdhci_readw(host, SDHCI_HOST_CONTROL2));

 if (host->flags & SDHCI_USE_ADMA) {
  if (host->flags & SDHCI_USE_64_BIT_DMA) {
   SDHCI_DUMP("ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n",
       sdhci_readl(host, SDHCI_ADMA_ERROR),
       sdhci_readl(host, SDHCI_ADMA_ADDRESS_HI),
       sdhci_readl(host, SDHCI_ADMA_ADDRESS));
  } else {
   SDHCI_DUMP("ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
       sdhci_readl(host, SDHCI_ADMA_ERROR),
       sdhci_readl(host, SDHCI_ADMA_ADDRESS));
  }
 }

 if (host->ops->dump_uhs2_regs)
  host->ops->dump_uhs2_regs(host);

 if (host->ops->dump_vendor_regs)
  host->ops->dump_vendor_regs(host);

 SDHCI_DUMP("============================================\n");
}
EXPORT_SYMBOL_GPL(sdhci_dumpregs);

/*****************************************************************************\
 *                                                                           *
 * Low level functions                                                       *
 *                                                                           *
\*****************************************************************************/


static void sdhci_do_enable_v4_mode(struct sdhci_host *host)
{
 u16 ctrl2;

 ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 if (ctrl2 & SDHCI_CTRL_V4_MODE)
  return;

 ctrl2 |= SDHCI_CTRL_V4_MODE;
 sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
}

/*
 * This can be called before sdhci_add_host() by Vendor's host controller
 * driver to enable v4 mode if supported.
 */

void sdhci_enable_v4_mode(struct sdhci_host *host)
{
 host->v4_mode = true;
 sdhci_do_enable_v4_mode(host);
}
EXPORT_SYMBOL_GPL(sdhci_enable_v4_mode);

bool sdhci_data_line_cmd(struct mmc_command *cmd)
{
 return cmd->data || cmd->flags & MMC_RSP_BUSY;
}
EXPORT_SYMBOL_GPL(sdhci_data_line_cmd);

static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
{
 u32 present;

 if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) ||
     !mmc_card_is_removable(host->mmc) || mmc_host_can_gpio_cd(host->mmc))
  return;

 if (enable) {
  present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
          SDHCI_CARD_PRESENT;

  host->ier |= present ? SDHCI_INT_CARD_REMOVE :
           SDHCI_INT_CARD_INSERT;
 } else {
  host->ier &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
 }

 sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
 sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
}

static void sdhci_enable_card_detection(struct sdhci_host *host)
{
 sdhci_set_card_detection(host, true);
}

static void sdhci_disable_card_detection(struct sdhci_host *host)
{
 sdhci_set_card_detection(host, false);
}

static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
{
 if (host->bus_on)
  return;
 host->bus_on = true;
 pm_runtime_get_noresume(mmc_dev(host->mmc));
}

static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
{
 if (!host->bus_on)
  return;
 host->bus_on = false;
 pm_runtime_put_noidle(mmc_dev(host->mmc));
}

void sdhci_reset(struct sdhci_host *host, u8 mask)
{
 ktime_t timeout;

 sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);

 if (mask & SDHCI_RESET_ALL) {
  host->clock = 0;
  /* Reset-all turns off SD Bus Power */
  if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
   sdhci_runtime_pm_bus_off(host);
 }

 /* Wait max 100 ms */
 timeout = ktime_add_ms(ktime_get(), 100);

 /* hw clears the bit when it's done */
 while (1) {
  bool timedout = ktime_after(ktime_get(), timeout);

  if (!(sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask))
   break;
  if (timedout) {
   pr_err("%s: Reset 0x%x never completed.\n",
    mmc_hostname(host->mmc), (int)mask);
   sdhci_err_stats_inc(host, CTRL_TIMEOUT);
   sdhci_dumpregs(host);
   return;
  }
  udelay(10);
 }
}
EXPORT_SYMBOL_GPL(sdhci_reset);

bool sdhci_do_reset(struct sdhci_host *host, u8 mask)
{
 if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
  struct mmc_host *mmc = host->mmc;

  if (!mmc->ops->get_cd(mmc))
   return false;
 }

 host->ops->reset(host, mask);

 return true;
}
EXPORT_SYMBOL_GPL(sdhci_do_reset);

static void sdhci_reset_for_all(struct sdhci_host *host)
{
 if (sdhci_do_reset(host, SDHCI_RESET_ALL)) {
  if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
   if (host->ops->enable_dma)
    host->ops->enable_dma(host);
  }
  /* Resetting the controller clears many */
  host->preset_enabled = false;
 }
}

enum sdhci_reset_reason {
 SDHCI_RESET_FOR_INIT,
 SDHCI_RESET_FOR_REQUEST_ERROR,
 SDHCI_RESET_FOR_REQUEST_ERROR_DATA_ONLY,
 SDHCI_RESET_FOR_TUNING_ABORT,
 SDHCI_RESET_FOR_CARD_REMOVED,
 SDHCI_RESET_FOR_CQE_RECOVERY,
};

static void sdhci_reset_for_reason(struct sdhci_host *host, enum sdhci_reset_reason reason)
{
 if (host->quirks2 & SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER) {
  sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
  return;
 }

 switch (reason) {
 case SDHCI_RESET_FOR_INIT:
  sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
  break;
 case SDHCI_RESET_FOR_REQUEST_ERROR:
 case SDHCI_RESET_FOR_TUNING_ABORT:
 case SDHCI_RESET_FOR_CARD_REMOVED:
 case SDHCI_RESET_FOR_CQE_RECOVERY:
  sdhci_do_reset(host, SDHCI_RESET_CMD);
  sdhci_do_reset(host, SDHCI_RESET_DATA);
  break;
 case SDHCI_RESET_FOR_REQUEST_ERROR_DATA_ONLY:
  sdhci_do_reset(host, SDHCI_RESET_DATA);
  break;
 }
}

#define sdhci_reset_for(h, r) sdhci_reset_for_reason((h), SDHCI_RESET_FOR_##r)

static void sdhci_set_default_irqs(struct sdhci_host *host)
{
 host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
      SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT |
      SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC |
      SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
      SDHCI_INT_RESPONSE;

 if (host->tuning_mode == SDHCI_TUNING_MODE_2 ||
     host->tuning_mode == SDHCI_TUNING_MODE_3)
  host->ier |= SDHCI_INT_RETUNE;

 sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
 sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
}

static void sdhci_config_dma(struct sdhci_host *host)
{
 u8 ctrl;
 u16 ctrl2;

 if (host->version < SDHCI_SPEC_200)
  return;

 ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);

 /*
 * Always adjust the DMA selection as some controllers
 * (e.g. JMicron) can't do PIO properly when the selection
 * is ADMA.
 */

 ctrl &= ~SDHCI_CTRL_DMA_MASK;
 if (!(host->flags & SDHCI_REQ_USE_DMA))
  goto out;

 /* Note if DMA Select is zero then SDMA is selected */
 if (host->flags & SDHCI_USE_ADMA)
  ctrl |= SDHCI_CTRL_ADMA32;

 if (host->flags & SDHCI_USE_64_BIT_DMA) {
  /*
 * If v4 mode, all supported DMA can be 64-bit addressing if
 * controller supports 64-bit system address, otherwise only
 * ADMA can support 64-bit addressing.
 */

  if (host->v4_mode) {
   ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
   ctrl2 |= SDHCI_CTRL_64BIT_ADDR;
   sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
  } else if (host->flags & SDHCI_USE_ADMA) {
   /*
 * Don't need to undo SDHCI_CTRL_ADMA32 in order to
 * set SDHCI_CTRL_ADMA64.
 */

   ctrl |= SDHCI_CTRL_ADMA64;
  }
 }

out:
 sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}

static void sdhci_init(struct sdhci_host *host, int soft)
{
 struct mmc_host *mmc = host->mmc;
 unsigned long flags;

 if (soft)
  sdhci_reset_for(host, INIT);
 else
  sdhci_reset_for_all(host);

 if (host->v4_mode)
  sdhci_do_enable_v4_mode(host);

 spin_lock_irqsave(&host->lock, flags);
 sdhci_set_default_irqs(host);
 spin_unlock_irqrestore(&host->lock, flags);

 host->cqe_on = false;

 if (soft) {
  /* force clock reconfiguration */
  host->clock = 0;
  host->reinit_uhs = true;
  mmc->ops->set_ios(mmc, &mmc->ios);
 }
}

static void sdhci_reinit(struct sdhci_host *host)
{
 u32 cd = host->ier & (SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);

 sdhci_init(host, 0);
 sdhci_enable_card_detection(host);

 /*
 * A change to the card detect bits indicates a change in present state,
 * refer sdhci_set_card_detection(). A card detect interrupt might have
 * been missed while the host controller was being reset, so trigger a
 * rescan to check.
 */

 if (cd != (host->ier & (SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT)))
  mmc_detect_change(host->mmc, msecs_to_jiffies(200));
}

static void __sdhci_led_activate(struct sdhci_host *host)
{
 u8 ctrl;

 if (host->quirks & SDHCI_QUIRK_NO_LED)
  return;

 ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
 ctrl |= SDHCI_CTRL_LED;
 sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}

static void __sdhci_led_deactivate(struct sdhci_host *host)
{
 u8 ctrl;

 if (host->quirks & SDHCI_QUIRK_NO_LED)
  return;

 ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
 ctrl &= ~SDHCI_CTRL_LED;
 sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}

#if IS_REACHABLE(CONFIG_LEDS_CLASS)
static void sdhci_led_control(struct led_classdev *led,
         enum led_brightness brightness)
{
 struct sdhci_host *host = container_of(led, struct sdhci_host, led);
 unsigned long flags;

 spin_lock_irqsave(&host->lock, flags);

 if (host->runtime_suspended)
  goto out;

 if (brightness == LED_OFF)
  __sdhci_led_deactivate(host);
 else
  __sdhci_led_activate(host);
out:
 spin_unlock_irqrestore(&host->lock, flags);
}

static int sdhci_led_register(struct sdhci_host *host)
{
 struct mmc_host *mmc = host->mmc;

 if (host->quirks & SDHCI_QUIRK_NO_LED)
  return 0;

 snprintf(host->led_name, sizeof(host->led_name),
   "%s::", mmc_hostname(mmc));

 host->led.name = host->led_name;
 host->led.brightness = LED_OFF;
 host->led.default_trigger = mmc_hostname(mmc);
 host->led.brightness_set = sdhci_led_control;

 return led_classdev_register(mmc_dev(mmc), &host->led);
}

static void sdhci_led_unregister(struct sdhci_host *host)
{
 if (host->quirks & SDHCI_QUIRK_NO_LED)
  return;

 led_classdev_unregister(&host->led);
}

static inline void sdhci_led_activate(struct sdhci_host *host)
{
}

static inline void sdhci_led_deactivate(struct sdhci_host *host)
{
}

#else

static inline int sdhci_led_register(struct sdhci_host *host)
{
 return 0;
}

static inline void sdhci_led_unregister(struct sdhci_host *host)
{
}

static inline void sdhci_led_activate(struct sdhci_host *host)
{
 __sdhci_led_activate(host);
}

static inline void sdhci_led_deactivate(struct sdhci_host *host)
{
 __sdhci_led_deactivate(host);
}

#endif

void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq,
       unsigned long timeout)
{
 if (sdhci_data_line_cmd(mrq->cmd))
  mod_timer(&host->data_timer, timeout);
 else
  mod_timer(&host->timer, timeout);
}
EXPORT_SYMBOL_GPL(sdhci_mod_timer);

static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq)
{
 if (sdhci_data_line_cmd(mrq->cmd))
  timer_delete(&host->data_timer);
 else
  timer_delete(&host->timer);
}

static inline bool sdhci_has_requests(struct sdhci_host *host)
{
 return host->cmd || host->data_cmd;
}

/*****************************************************************************\
 *                                                                           *
 * Core functions                                                            *
 *                                                                           *
\*****************************************************************************/


static void sdhci_read_block_pio(struct sdhci_host *host)
{
 size_t blksize, len, chunk;
 u32 scratch;
 u8 *buf;

 DBG("PIO reading\n");

 blksize = host->data->blksz;
 chunk = 0;

 while (blksize) {
  BUG_ON(!sg_miter_next(&host->sg_miter));

  len = min(host->sg_miter.length, blksize);

  blksize -= len;
  host->sg_miter.consumed = len;

  buf = host->sg_miter.addr;

  while (len) {
   if (chunk == 0) {
    scratch = sdhci_readl(host, SDHCI_BUFFER);
    chunk = 4;
   }

   *buf = scratch & 0xFF;

   buf++;
   scratch >>= 8;
   chunk--;
   len--;
  }
 }

 sg_miter_stop(&host->sg_miter);
}

static void sdhci_write_block_pio(struct sdhci_host *host)
{
 size_t blksize, len, chunk;
 u32 scratch;
 u8 *buf;

 DBG("PIO writing\n");

 blksize = host->data->blksz;
 chunk = 0;
 scratch = 0;

 while (blksize) {
  BUG_ON(!sg_miter_next(&host->sg_miter));

  len = min(host->sg_miter.length, blksize);

  blksize -= len;
  host->sg_miter.consumed = len;

  buf = host->sg_miter.addr;

  while (len) {
   scratch |= (u32)*buf << (chunk * 8);

   buf++;
   chunk++;
   len--;

   if ((chunk == 4) || ((len == 0) && (blksize == 0))) {
    sdhci_writel(host, scratch, SDHCI_BUFFER);
    chunk = 0;
    scratch = 0;
   }
  }
 }

 sg_miter_stop(&host->sg_miter);
}

static void sdhci_transfer_pio(struct sdhci_host *host)
{
 u32 mask;

 if (host->blocks == 0)
  return;

 if (host->data->flags & MMC_DATA_READ)
  mask = SDHCI_DATA_AVAILABLE;
 else
  mask = SDHCI_SPACE_AVAILABLE;

 /*
 * Some controllers (JMicron JMB38x) mess up the buffer bits
 * for transfers < 4 bytes. As long as it is just one block,
 * we can ignore the bits.
 */

 if ((host->quirks & SDHCI_QUIRK_BROKEN_SMALL_PIO) &&
  (host->data->blocks == 1))
  mask = ~0;

 while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
  if (host->quirks & SDHCI_QUIRK_PIO_NEEDS_DELAY)
   udelay(100);

  if (host->data->flags & MMC_DATA_READ)
   sdhci_read_block_pio(host);
  else
   sdhci_write_block_pio(host);

  host->blocks--;
  if (host->blocks == 0)
   break;
 }

 DBG("PIO transfer complete.\n");
}

static int sdhci_pre_dma_transfer(struct sdhci_host *host,
      struct mmc_data *data, int cookie)
{
 int sg_count;

 /*
 * If the data buffers are already mapped, return the previous
 * dma_map_sg() result.
 */

 if (data->host_cookie == COOKIE_PRE_MAPPED)
  return data->sg_count;

 /* Bounce write requests to the bounce buffer */
 if (host->bounce_buffer) {
  unsigned int length = data->blksz * data->blocks;

  if (length > host->bounce_buffer_size) {
   pr_err("%s: asked for transfer of %u bytes exceeds bounce buffer %u bytes\n",
          mmc_hostname(host->mmc), length,
          host->bounce_buffer_size);
   return -EIO;
  }
  if (mmc_get_dma_dir(data) == DMA_TO_DEVICE) {
   /* Copy the data to the bounce buffer */
   if (host->ops->copy_to_bounce_buffer) {
    host->ops->copy_to_bounce_buffer(host,
         data, length);
   } else {
    sg_copy_to_buffer(data->sg, data->sg_len,
        host->bounce_buffer, length);
   }
  }
  /* Switch ownership to the DMA */
  dma_sync_single_for_device(mmc_dev(host->mmc),
        host->bounce_addr,
        host->bounce_buffer_size,
        mmc_get_dma_dir(data));
  /* Just a dummy value */
  sg_count = 1;
 } else {
  /* Just access the data directly from memory */
  sg_count = dma_map_sg(mmc_dev(host->mmc),
          data->sg, data->sg_len,
          mmc_get_dma_dir(data));
 }

 if (sg_count == 0)
  return -ENOSPC;

 data->sg_count = sg_count;
 data->host_cookie = cookie;

 return sg_count;
}

static char *sdhci_kmap_atomic(struct scatterlist *sg)
{
 return kmap_local_page(sg_page(sg)) + sg->offset;
}

static void sdhci_kunmap_atomic(void *buffer)
{
 kunmap_local(buffer);
}

void sdhci_adma_write_desc(struct sdhci_host *host, void **desc,
      dma_addr_t addr, int len, unsigned int cmd)
{
 struct sdhci_adma2_64_desc *dma_desc = *desc;

 /* 32-bit and 64-bit descriptors have these members in same position */
 dma_desc->cmd = cpu_to_le16(cmd);
 dma_desc->len = cpu_to_le16(len);
 dma_desc->addr_lo = cpu_to_le32(lower_32_bits(addr));

 if (host->flags & SDHCI_USE_64_BIT_DMA)
  dma_desc->addr_hi = cpu_to_le32(upper_32_bits(addr));

 *desc += host->desc_sz;
}
EXPORT_SYMBOL_GPL(sdhci_adma_write_desc);

static inline void __sdhci_adma_write_desc(struct sdhci_host *host,
        void **desc, dma_addr_t addr,
        int len, unsigned int cmd)
{
 if (host->ops->adma_write_desc)
  host->ops->adma_write_desc(host, desc, addr, len, cmd);
 else
  sdhci_adma_write_desc(host, desc, addr, len, cmd);
}

static void sdhci_adma_mark_end(void *desc)
{
 struct sdhci_adma2_64_desc *dma_desc = desc;

 /* 32-bit and 64-bit descriptors have 'cmd' in same position */
 dma_desc->cmd |= cpu_to_le16(ADMA2_END);
}

static void sdhci_adma_table_pre(struct sdhci_host *host,
 struct mmc_data *data, int sg_count)
{
 struct scatterlist *sg;
 dma_addr_t addr, align_addr;
 void *desc, *align;
 char *buffer;
 int len, offset, i;

 /*
 * The spec does not specify endianness of descriptor table.
 * We currently guess that it is LE.
 */


 host->sg_count = sg_count;

 desc = host->adma_table;
 align = host->align_buffer;

 align_addr = host->align_addr;

 for_each_sg(data->sg, sg, host->sg_count, i) {
  addr = sg_dma_address(sg);
  len = sg_dma_len(sg);

  /*
 * The SDHCI specification states that ADMA addresses must
 * be 32-bit aligned. If they aren't, then we use a bounce
 * buffer for the (up to three) bytes that screw up the
 * alignment.
 */

  offset = (SDHCI_ADMA2_ALIGN - (addr & SDHCI_ADMA2_MASK)) &
    SDHCI_ADMA2_MASK;
  if (offset) {
   if (data->flags & MMC_DATA_WRITE) {
    buffer = sdhci_kmap_atomic(sg);
    memcpy(align, buffer, offset);
    sdhci_kunmap_atomic(buffer);
   }

   /* tran, valid */
   __sdhci_adma_write_desc(host, &desc, align_addr,
      offset, ADMA2_TRAN_VALID);

   BUG_ON(offset > 65536);

   align += SDHCI_ADMA2_ALIGN;
   align_addr += SDHCI_ADMA2_ALIGN;

   addr += offset;
   len -= offset;
  }

  /*
 * The block layer forces a minimum segment size of PAGE_SIZE,
 * so 'len' can be too big here if PAGE_SIZE >= 64KiB. Write
 * multiple descriptors, noting that the ADMA table is sized
 * for 4KiB chunks anyway, so it will be big enough.
 */

  while (len > host->max_adma) {
   int n = 32 * 1024; /* 32KiB*/

   __sdhci_adma_write_desc(host, &desc, addr, n, ADMA2_TRAN_VALID);
   addr += n;
   len -= n;
  }

  /* tran, valid */
  if (len)
   __sdhci_adma_write_desc(host, &desc, addr, len,
      ADMA2_TRAN_VALID);

  /*
 * If this triggers then we have a calculation bug
 * somewhere. :/
 */

  WARN_ON((desc - host->adma_table) >= host->adma_table_sz);
 }

 if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) {
  /* Mark the last descriptor as the terminating descriptor */
  if (desc != host->adma_table) {
   desc -= host->desc_sz;
   sdhci_adma_mark_end(desc);
  }
 } else {
  /* Add a terminating entry - nop, end, valid */
  __sdhci_adma_write_desc(host, &desc, 0, 0, ADMA2_NOP_END_VALID);
 }
}

static void sdhci_adma_table_post(struct sdhci_host *host,
 struct mmc_data *data)
{
 struct scatterlist *sg;
 int i, size;
 void *align;
 char *buffer;

 if (data->flags & MMC_DATA_READ) {
  bool has_unaligned = false;

  /* Do a quick scan of the SG list for any unaligned mappings */
  for_each_sg(data->sg, sg, host->sg_count, i)
   if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
    has_unaligned = true;
    break;
   }

  if (has_unaligned) {
   dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg,
         data->sg_len, DMA_FROM_DEVICE);

   align = host->align_buffer;

   for_each_sg(data->sg, sg, host->sg_count, i) {
    if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
     size = SDHCI_ADMA2_ALIGN -
            (sg_dma_address(sg) & SDHCI_ADMA2_MASK);

     buffer = sdhci_kmap_atomic(sg);
     memcpy(buffer, align, size);
     sdhci_kunmap_atomic(buffer);

     align += SDHCI_ADMA2_ALIGN;
    }
   }
  }
 }
}

static void sdhci_set_adma_addr(struct sdhci_host *host, dma_addr_t addr)
{
 sdhci_writel(host, lower_32_bits(addr), SDHCI_ADMA_ADDRESS);
 if (host->flags & SDHCI_USE_64_BIT_DMA)
  sdhci_writel(host, upper_32_bits(addr), SDHCI_ADMA_ADDRESS_HI);
}

static dma_addr_t sdhci_sdma_address(struct sdhci_host *host)
{
 if (host->bounce_buffer)
  return host->bounce_addr;
 else
  return sg_dma_address(host->data->sg);
}

static void sdhci_set_sdma_addr(struct sdhci_host *host, dma_addr_t addr)
{
 if (host->v4_mode)
  sdhci_set_adma_addr(host, addr);
 else
  sdhci_writel(host, addr, SDHCI_DMA_ADDRESS);
}

static unsigned int sdhci_target_timeout(struct sdhci_host *host,
      struct mmc_command *cmd,
      struct mmc_data *data)
{
 unsigned int target_timeout;

 /* timeout in us */
 if (!data) {
  target_timeout = cmd->busy_timeout * 1000;
 } else {
  target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
  if (host->clock && data->timeout_clks) {
   unsigned long long val;

   /*
 * data->timeout_clks is in units of clock cycles.
 * host->clock is in Hz.  target_timeout is in us.
 * Hence, us = 1000000 * cycles / Hz.  Round up.
 */

   val = 1000000ULL * data->timeout_clks;
   if (do_div(val, host->clock))
    target_timeout++;
   target_timeout += val;
  }
 }

 return target_timeout;
}

static void sdhci_calc_sw_timeout(struct sdhci_host *host,
      struct mmc_command *cmd)
{
 struct mmc_data *data = cmd->data;
 struct mmc_host *mmc = host->mmc;
 struct mmc_ios *ios = &mmc->ios;
 unsigned char bus_width = 1 << ios->bus_width;
 unsigned int blksz;
 unsigned int freq;
 u64 target_timeout;
 u64 transfer_time;

 target_timeout = sdhci_target_timeout(host, cmd, data);
 target_timeout *= NSEC_PER_USEC;

 if (data) {
  blksz = data->blksz;
  freq = mmc->actual_clock ? : host->clock;
  transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width);
  do_div(transfer_time, freq);
  /* multiply by '2' to account for any unknowns */
  transfer_time = transfer_time * 2;
  /* calculate timeout for the entire data */
  host->data_timeout = data->blocks * target_timeout +
         transfer_time;
 } else {
  host->data_timeout = target_timeout;
 }

 if (host->data_timeout)
  host->data_timeout += MMC_CMD_TRANSFER_TIME;
}

static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd,
        bool *too_big)
{
 u8 count;
 struct mmc_data *data;
 unsigned target_timeout, current_timeout;

 *too_big = false;

 /*
 * If the host controller provides us with an incorrect timeout
 * value, just skip the check and use the maximum. The hardware may take
 * longer to time out, but that's much better than having a too-short
 * timeout value.
 */

 if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
  return host->max_timeout_count;

 /* Unspecified command, assume max */
 if (cmd == NULL)
  return host->max_timeout_count;

 data = cmd->data;
 /* Unspecified timeout, assume max */
 if (!data && !cmd->busy_timeout)
  return host->max_timeout_count;

 /* timeout in us */
 target_timeout = sdhci_target_timeout(host, cmd, data);

 /*
 * Figure out needed cycles.
 * We do this in steps in order to fit inside a 32 bit int.
 * The first step is the minimum timeout, which will have a
 * minimum resolution of 6 bits:
 * (1) 2^13*1000 > 2^22,
 * (2) host->timeout_clk < 2^16
 *     =>
 *     (1) / (2) > 2^6
 */

 count = 0;
 current_timeout = (1 << 13) * 1000 / host->timeout_clk;
 while (current_timeout < target_timeout) {
  count++;
  current_timeout <<= 1;
  if (count > host->max_timeout_count) {
   if (!(host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT))
    DBG("Too large timeout 0x%x requested for CMD%d!\n",
        count, cmd->opcode);
   count = host->max_timeout_count;
   *too_big = true;
   break;
  }
 }

 return count;
}

static void sdhci_set_transfer_irqs(struct sdhci_host *host)
{
 u32 pio_irqs = SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL;
 u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;

 if (host->flags & SDHCI_REQ_USE_DMA)
  host->ier = (host->ier & ~pio_irqs) | dma_irqs;
 else
  host->ier = (host->ier & ~dma_irqs) | pio_irqs;

 if (host->flags & (SDHCI_AUTO_CMD23 | SDHCI_AUTO_CMD12))
  host->ier |= SDHCI_INT_AUTO_CMD_ERR;
 else
  host->ier &= ~SDHCI_INT_AUTO_CMD_ERR;

 sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
 sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
}

void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable)
{
 if (enable)
  host->ier |= SDHCI_INT_DATA_TIMEOUT;
 else
  host->ier &= ~SDHCI_INT_DATA_TIMEOUT;
 sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
 sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
}
EXPORT_SYMBOL_GPL(sdhci_set_data_timeout_irq);

void __sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
{
 bool too_big = false;
 u8 count = sdhci_calc_timeout(host, cmd, &too_big);

 if (too_big &&
     host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT) {
  sdhci_calc_sw_timeout(host, cmd);
  sdhci_set_data_timeout_irq(host, false);
 } else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT)) {
  sdhci_set_data_timeout_irq(host, true);
 }

 sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
}
EXPORT_SYMBOL_GPL(__sdhci_set_timeout);

static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
{
 if (host->ops->set_timeout)
  host->ops->set_timeout(host, cmd);
 else
  __sdhci_set_timeout(host, cmd);
}

void sdhci_initialize_data(struct sdhci_host *host, struct mmc_data *data)
{
 WARN_ON(host->data);

 /* Sanity checks */
 BUG_ON(data->blksz * data->blocks > 524288);
 BUG_ON(data->blksz > host->mmc->max_blk_size);
 BUG_ON(data->blocks > 65535);

 host->data = data;
 host->data_early = 0;
 host->data->bytes_xfered = 0;
}
EXPORT_SYMBOL_GPL(sdhci_initialize_data);

static inline void sdhci_set_block_info(struct sdhci_host *host,
     struct mmc_data *data)
{
 /* Set the DMA boundary value and block size */
 sdhci_writew(host,
       SDHCI_MAKE_BLKSZ(host->sdma_boundary, data->blksz),
       SDHCI_BLOCK_SIZE);
 /*
 * For Version 4.10 onwards, if v4 mode is enabled, 32-bit Block Count
 * can be supported, in that case 16-bit block count register must be 0.
 */

 if (host->version >= SDHCI_SPEC_410 && host->v4_mode &&
     (host->quirks2 & SDHCI_QUIRK2_USE_32BIT_BLK_CNT)) {
  if (sdhci_readw(host, SDHCI_BLOCK_COUNT))
   sdhci_writew(host, 0, SDHCI_BLOCK_COUNT);
  sdhci_writew(host, data->blocks, SDHCI_32BIT_BLK_CNT);
 } else {
  sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
 }
}

void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data)
{
 if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
  struct scatterlist *sg;
  unsigned int length_mask, offset_mask;
  int i;

  host->flags |= SDHCI_REQ_USE_DMA;

  /*
 * FIXME: This doesn't account for merging when mapping the
 * scatterlist.
 *
 * The assumption here being that alignment and lengths are
 * the same after DMA mapping to device address space.
 */

  length_mask = 0;
  offset_mask = 0;
  if (host->flags & SDHCI_USE_ADMA) {
   if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) {
    length_mask = 3;
    /*
 * As we use up to 3 byte chunks to work
 * around alignment problems, we need to
 * check the offset as well.
 */

    offset_mask = 3;
   }
  } else {
   if (host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE)
    length_mask = 3;
   if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR)
    offset_mask = 3;
  }

  if (unlikely(length_mask | offset_mask)) {
   for_each_sg(data->sg, sg, data->sg_len, i) {
    if (sg->length & length_mask) {
     DBG("Reverting to PIO because of transfer size (%d)\n",
         sg->length);
     host->flags &= ~SDHCI_REQ_USE_DMA;
     break;
    }
    if (sg->offset & offset_mask) {
     DBG("Reverting to PIO because of bad alignment\n");
     host->flags &= ~SDHCI_REQ_USE_DMA;
     break;
    }
   }
  }
 }

 sdhci_config_dma(host);

 if (host->flags & SDHCI_REQ_USE_DMA) {
  int sg_cnt = sdhci_pre_dma_transfer(host, data, COOKIE_MAPPED);

  if (sg_cnt <= 0) {
   /*
 * This only happens when someone fed
 * us an invalid request.
 */

   WARN_ON(1);
   host->flags &= ~SDHCI_REQ_USE_DMA;
  } else if (host->flags & SDHCI_USE_ADMA) {
   sdhci_adma_table_pre(host, data, sg_cnt);
   sdhci_set_adma_addr(host, host->adma_addr);
  } else {
   WARN_ON(sg_cnt != 1);
   sdhci_set_sdma_addr(host, sdhci_sdma_address(host));
  }
 }

 if (!(host->flags & SDHCI_REQ_USE_DMA)) {
  int flags;

  flags = SG_MITER_ATOMIC;
  if (host->data->flags & MMC_DATA_READ)
   flags |= SG_MITER_TO_SG;
  else
   flags |= SG_MITER_FROM_SG;
  sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
  host->blocks = data->blocks;
 }

 sdhci_set_transfer_irqs(host);
}
EXPORT_SYMBOL_GPL(sdhci_prepare_dma);

static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
{
 struct mmc_data *data = cmd->data;

 sdhci_initialize_data(host, data);

 sdhci_prepare_dma(host, data);

 sdhci_set_block_info(host, data);
}

#if IS_ENABLED(CONFIG_MMC_SDHCI_EXTERNAL_DMA)

static int sdhci_external_dma_init(struct sdhci_host *host)
{
 int ret = 0;
 struct mmc_host *mmc = host->mmc;

 host->tx_chan = dma_request_chan(mmc_dev(mmc), "tx");
 if (IS_ERR(host->tx_chan)) {
  ret = PTR_ERR(host->tx_chan);
  if (ret != -EPROBE_DEFER)
   pr_warn("Failed to request TX DMA channel.\n");
  host->tx_chan = NULL;
  return ret;
 }

 host->rx_chan = dma_request_chan(mmc_dev(mmc), "rx");
 if (IS_ERR(host->rx_chan)) {
  if (host->tx_chan) {
   dma_release_channel(host->tx_chan);
   host->tx_chan = NULL;
  }

  ret = PTR_ERR(host->rx_chan);
  if (ret != -EPROBE_DEFER)
   pr_warn("Failed to request RX DMA channel.\n");
  host->rx_chan = NULL;
 }

 return ret;
}

static struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
         struct mmc_data *data)
{
 return data->flags & MMC_DATA_WRITE ? host->tx_chan : host->rx_chan;
}

static int sdhci_external_dma_setup(struct sdhci_host *host,
        struct mmc_command *cmd)
{
 int ret, i;
 enum dma_transfer_direction dir;
 struct dma_async_tx_descriptor *desc;
 struct mmc_data *data = cmd->data;
 struct dma_chan *chan;
 struct dma_slave_config cfg;
 dma_cookie_t cookie;
 int sg_cnt;

 if (!host->mapbase)
  return -EINVAL;

 memset(&cfg, 0, sizeof(cfg));
 cfg.src_addr = host->mapbase + SDHCI_BUFFER;
 cfg.dst_addr = host->mapbase + SDHCI_BUFFER;
 cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 cfg.src_maxburst = data->blksz / 4;
 cfg.dst_maxburst = data->blksz / 4;

 /* Sanity check: all the SG entries must be aligned by block size. */
 for (i = 0; i < data->sg_len; i++) {
  if ((data->sg + i)->length % data->blksz)
   return -EINVAL;
 }

 chan = sdhci_external_dma_channel(host, data);

 ret = dmaengine_slave_config(chan, &cfg);
 if (ret)
  return ret;

 sg_cnt = sdhci_pre_dma_transfer(host, data, COOKIE_MAPPED);
 if (sg_cnt <= 0)
  return -EINVAL;

 dir = data->flags & MMC_DATA_WRITE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
 desc = dmaengine_prep_slave_sg(chan, data->sg, data->sg_len, dir,
           DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 if (!desc)
  return -EINVAL;

 desc->callback = NULL;
 desc->callback_param = NULL;

 cookie = dmaengine_submit(desc);
 if (dma_submit_error(cookie))
  ret = cookie;

 return ret;
}

static void sdhci_external_dma_release(struct sdhci_host *host)
{
 if (host->tx_chan) {
  dma_release_channel(host->tx_chan);
  host->tx_chan = NULL;
 }

 if (host->rx_chan) {
  dma_release_channel(host->rx_chan);
  host->rx_chan = NULL;
 }

 sdhci_switch_external_dma(host, false);
}

static void __sdhci_external_dma_prepare_data(struct sdhci_host *host,
           struct mmc_command *cmd)
{
 struct mmc_data *data = cmd->data;

 sdhci_initialize_data(host, data);

 host->flags |= SDHCI_REQ_USE_DMA;
 sdhci_set_transfer_irqs(host);

 sdhci_set_block_info(host, data);
}

static void sdhci_external_dma_prepare_data(struct sdhci_host *host,
         struct mmc_command *cmd)
{
 if (!sdhci_external_dma_setup(host, cmd)) {
  __sdhci_external_dma_prepare_data(host, cmd);
 } else {
  sdhci_external_dma_release(host);
  pr_err("%s: Cannot use external DMA, switch to the DMA/PIO which standard SDHCI provides.\n",
         mmc_hostname(host->mmc));
  sdhci_prepare_data(host, cmd);
 }
}

static void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
         struct mmc_command *cmd)
{
 struct dma_chan *chan;

 if (!cmd->data)
  return;

 chan = sdhci_external_dma_channel(host, cmd->data);
 if (chan)
  dma_async_issue_pending(chan);
}

#else

static inline int sdhci_external_dma_init(struct sdhci_host *host)
{
 return -EOPNOTSUPP;
}

static inline void sdhci_external_dma_release(struct sdhci_host *host)
{
}

static inline void sdhci_external_dma_prepare_data(struct sdhci_host *host,
         struct mmc_command *cmd)
{
 /* This should never happen */
 WARN_ON_ONCE(1);
}

static inline void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
         struct mmc_command *cmd)
{
}

static inline struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
         struct mmc_data *data)
{
 return NULL;
}

#endif

void sdhci_switch_external_dma(struct sdhci_host *host, bool en)
{
 host->use_external_dma = en;
}
EXPORT_SYMBOL_GPL(sdhci_switch_external_dma);

static inline bool sdhci_auto_cmd12(struct sdhci_host *host,
        struct mmc_request *mrq)
{
 return !mrq->sbc && (host->flags & SDHCI_AUTO_CMD12) &&
        !mrq->cap_cmd_during_tfr;
}

static inline bool sdhci_auto_cmd23(struct sdhci_host *host,
        struct mmc_request *mrq)
{
 return mrq->sbc && (host->flags & SDHCI_AUTO_CMD23);
}

static inline bool sdhci_manual_cmd23(struct sdhci_host *host,
          struct mmc_request *mrq)
{
 return mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23);
}

static inline void sdhci_auto_cmd_select(struct sdhci_host *host,
      struct mmc_command *cmd,
      u16 *mode)
{
 bool use_cmd12 = sdhci_auto_cmd12(host, cmd->mrq) &&
    (cmd->opcode != SD_IO_RW_EXTENDED);
 bool use_cmd23 = sdhci_auto_cmd23(host, cmd->mrq);
 u16 ctrl2;

 /*
 * In case of Version 4.10 or later, use of 'Auto CMD Auto
 * Select' is recommended rather than use of 'Auto CMD12
 * Enable' or 'Auto CMD23 Enable'. We require Version 4 Mode
 * here because some controllers (e.g sdhci-of-dwmshc) expect it.
 */

 if (host->version >= SDHCI_SPEC_410 && host->v4_mode &&
     (use_cmd12 || use_cmd23)) {
  *mode |= SDHCI_TRNS_AUTO_SEL;

  ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
  if (use_cmd23)
   ctrl2 |= SDHCI_CMD23_ENABLE;
  else
   ctrl2 &= ~SDHCI_CMD23_ENABLE;
  sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);

  return;
 }

 /*
 * If we are sending CMD23, CMD12 never gets sent
 * on successful completion (so no Auto-CMD12).
 */

 if (use_cmd12)
  *mode |= SDHCI_TRNS_AUTO_CMD12;
 else if (use_cmd23)
  *mode |= SDHCI_TRNS_AUTO_CMD23;
}

static void sdhci_set_transfer_mode(struct sdhci_host *host,
 struct mmc_command *cmd)
{
 u16 mode = 0;
 struct mmc_data *data = cmd->data;

 if (data == NULL) {
  if (host->quirks2 &
   SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD) {
   /* must not clear SDHCI_TRANSFER_MODE when tuning */
   if (!mmc_op_tuning(cmd->opcode))
    sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE);
  } else {
  /* clear Auto CMD settings for no data CMDs */
   mode = sdhci_readw(host, SDHCI_TRANSFER_MODE);
   sdhci_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 |
    SDHCI_TRNS_AUTO_CMD23), SDHCI_TRANSFER_MODE);
  }
  return;
 }

 WARN_ON(!host->data);

 if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE))
  mode = SDHCI_TRNS_BLK_CNT_EN;

 if (mmc_op_multi(cmd->opcode) || data->blocks > 1) {
  mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI;
  sdhci_auto_cmd_select(host, cmd, &mode);
  if (sdhci_auto_cmd23(host, cmd->mrq))
   sdhci_writel(host, cmd->mrq->sbc->arg, SDHCI_ARGUMENT2);
 }

 if (data->flags & MMC_DATA_READ)
  mode |= SDHCI_TRNS_READ;
 if (host->flags & SDHCI_REQ_USE_DMA)
  mode |= SDHCI_TRNS_DMA;

 sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
}

bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq)
{
 return (!(host->flags & SDHCI_DEVICE_DEAD) &&
  ((mrq->cmd && mrq->cmd->error) ||
   (mrq->sbc && mrq->sbc->error) ||
   (mrq->data && mrq->data->stop && mrq->data->stop->error) ||
   (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)));
}
EXPORT_SYMBOL_GPL(sdhci_needs_reset);

static void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq)
{
 int i;

 for (i = 0; i < SDHCI_MAX_MRQS; i++) {
  if (host->mrqs_done[i] == mrq) {
   WARN_ON(1);
   return;
  }
 }

 for (i = 0; i < SDHCI_MAX_MRQS; i++) {
  if (!host->mrqs_done[i]) {
   host->mrqs_done[i] = mrq;
   break;
  }
 }

 WARN_ON(i >= SDHCI_MAX_MRQS);
}

void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
{
 if (host->cmd && host->cmd->mrq == mrq)
  host->cmd = NULL;

 if (host->data_cmd && host->data_cmd->mrq == mrq)
  host->data_cmd = NULL;

 if (host->deferred_cmd && host->deferred_cmd->mrq == mrq)
  host->deferred_cmd = NULL;

 if (host->data && host->data->mrq == mrq)
  host->data = NULL;

 if (sdhci_needs_reset(host, mrq))
  host->pending_reset = true;

 sdhci_set_mrq_done(host, mrq);

 sdhci_del_timer(host, mrq);

 if (!sdhci_has_requests(host))
  sdhci_led_deactivate(host);
}
EXPORT_SYMBOL_GPL(__sdhci_finish_mrq);

void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
{
 __sdhci_finish_mrq(host, mrq);

 queue_work(host->complete_wq, &host->complete_work);
}
EXPORT_SYMBOL_GPL(sdhci_finish_mrq);

void __sdhci_finish_data_common(struct sdhci_host *host, bool defer_reset)
{
 struct mmc_command *data_cmd = host->data_cmd;
 struct mmc_data *data = host->data;

 host->data = NULL;
 host->data_cmd = NULL;

 /*
 * The controller needs a reset of internal state machines upon error
 * conditions.
 */

 if (data->error) {
  if (defer_reset)
   host->pending_reset = true;
  else if (!host->cmd || host->cmd == data_cmd)
   sdhci_reset_for(host, REQUEST_ERROR);
  else
   sdhci_reset_for(host, REQUEST_ERROR_DATA_ONLY);
 }

 if ((host->flags & (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) ==
     (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA))
  sdhci_adma_table_post(host, data);

 /*
 * The specification states that the block count register must
 * be updated, but it does not specify at what point in the
 * data flow. That makes the register entirely useless to read
 * back so we have to assume that nothing made it to the card
 * in the event of an error.
 */

 if (data->error)
  data->bytes_xfered = 0;
 else
  data->bytes_xfered = data->blksz * data->blocks;
}
EXPORT_SYMBOL_GPL(__sdhci_finish_data_common);

static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
{
 struct mmc_data *data = host->data;

 __sdhci_finish_data_common(host, false);

 /*
 * Need to send CMD12 if -
 * a) open-ended multiblock transfer not using auto CMD12 (no CMD23)
 * b) error in multiblock transfer
 */

 if (data->stop &&
     ((!data->mrq->sbc && !sdhci_auto_cmd12(host, data->mrq)) ||
      data->error)) {
  /*
 * 'cap_cmd_during_tfr' request must not use the command line
 * after mmc_command_done() has been called. It is upper layer's
 * responsibility to send the stop command if required.
 */

  if (data->mrq->cap_cmd_during_tfr) {
   __sdhci_finish_mrq(host, data->mrq);
  } else {
   /* Avoid triggering warning in sdhci_send_command() */
   host->cmd = NULL;
   if (!sdhci_send_command(host, data->stop)) {
    if (sw_data_timeout) {
     /*
 * This is anyway a sw data timeout, so
 * give up now.
 */

     data->stop->error = -EIO;
     __sdhci_finish_mrq(host, data->mrq);
    } else {
     WARN_ON(host->deferred_cmd);
     host->deferred_cmd = data->stop;
    }
   }
  }
 } else {
  __sdhci_finish_mrq(host, data->mrq);
 }
}

static void sdhci_finish_data(struct sdhci_host *host)
{
 __sdhci_finish_data(host, false);
}

static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
{
 int flags;
 u32 mask;
 unsigned long timeout;

 WARN_ON(host->cmd);

 /* Initially, a command has no error */
 cmd->error = 0;

 if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) &&
     cmd->opcode == MMC_STOP_TRANSMISSION)
  cmd->flags |= MMC_RSP_BUSY;

 mask = SDHCI_CMD_INHIBIT;
 if (sdhci_data_line_cmd(cmd))
  mask |= SDHCI_DATA_INHIBIT;

 /* We shouldn't wait for data inihibit for stop commands, even
   though they might use busy signaling */

 if (cmd->mrq->data && (cmd == cmd->mrq->data->stop))
  mask &= ~SDHCI_DATA_INHIBIT;

 if (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask)
  return false;

 host->cmd = cmd;
 host->data_timeout = 0;
 if (sdhci_data_line_cmd(cmd)) {
  WARN_ON(host->data_cmd);
  host->data_cmd = cmd;
  sdhci_set_timeout(host, cmd);
 }

 if (cmd->data) {
  if (host->use_external_dma)
   sdhci_external_dma_prepare_data(host, cmd);
  else
   sdhci_prepare_data(host, cmd);
 }

 sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);

 sdhci_set_transfer_mode(host, cmd);

 if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
  WARN_ONCE(1, "Unsupported response type!\n");
  /*
 * This does not happen in practice because 136-bit response
 * commands never have busy waiting, so rather than complicate
 * the error path, just remove busy waiting and continue.
 */

  cmd->flags &= ~MMC_RSP_BUSY;
 }

 if (!(cmd->flags & MMC_RSP_PRESENT))
  flags = SDHCI_CMD_RESP_NONE;
 else if (cmd->flags & MMC_RSP_136)
  flags = SDHCI_CMD_RESP_LONG;
 else if (cmd->flags & MMC_RSP_BUSY)
  flags = SDHCI_CMD_RESP_SHORT_BUSY;
 else
  flags = SDHCI_CMD_RESP_SHORT;

 if (cmd->flags & MMC_RSP_CRC)
  flags |= SDHCI_CMD_CRC;
 if (cmd->flags & MMC_RSP_OPCODE)
  flags |= SDHCI_CMD_INDEX;

 /* CMD19 is special in that the Data Present Select should be set */
 if (cmd->data || mmc_op_tuning(cmd->opcode))
  flags |= SDHCI_CMD_DATA;

 timeout = jiffies;
 if (host->data_timeout)
  timeout += nsecs_to_jiffies(host->data_timeout);
 else if (!cmd->data && cmd->busy_timeout > 9000)
  timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
 else
  timeout += 10 * HZ;
 sdhci_mod_timer(host, cmd->mrq, timeout);

 if (host->use_external_dma)
  sdhci_external_dma_pre_transfer(host, cmd);

 sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);

 return true;
}

bool sdhci_present_error(struct sdhci_host *host,
    struct mmc_command *cmd, bool present)
{
 if (!present || host->flags & SDHCI_DEVICE_DEAD) {
  cmd->error = -ENOMEDIUM;
  return true;
 }

 return false;
}
EXPORT_SYMBOL_GPL(sdhci_present_error);

static bool sdhci_send_command_retry(struct sdhci_host *host,
         struct mmc_command *cmd,
         unsigned long flags)
 __releases(host->lock)
 __acquires(host->lock)
{
 struct mmc_command *deferred_cmd = host->deferred_cmd;
 int timeout = 10; /* Approx. 10 ms */
 bool present;

 while (!sdhci_send_command(host, cmd)) {
  if (!timeout--) {
   pr_err("%s: Controller never released inhibit bit(s).\n",
          mmc_hostname(host->mmc));
   sdhci_err_stats_inc(host, CTRL_TIMEOUT);
   sdhci_dumpregs(host);
   cmd->error = -EIO;
   return false;
  }

  spin_unlock_irqrestore(&host->lock, flags);

  usleep_range(1000, 1250);

  present = host->mmc->ops->get_cd(host->mmc);

  spin_lock_irqsave(&host->lock, flags);

  /* A deferred command might disappear, handle that */
  if (cmd == deferred_cmd && cmd != host->deferred_cmd)
   return true;

  if (sdhci_present_error(host, cmd, present))
   return false;
 }

 if (cmd == host->deferred_cmd)
  host->deferred_cmd = NULL;

 return true;
}

static void sdhci_read_rsp_136(struct sdhci_host *host, struct mmc_command *cmd)
{
 int i, reg;

 for (i = 0; i < 4; i++) {
  reg = SDHCI_RESPONSE + (3 - i) * 4;
  cmd->resp[i] = sdhci_readl(host, reg);
 }

 if (host->quirks2 & SDHCI_QUIRK2_RSP_136_HAS_CRC)
  return;

 /* CRC is stripped so we need to do some shifting */
 for (i = 0; i < 4; i++) {
  cmd->resp[i] <<= 8;
  if (i != 3)
   cmd->resp[i] |= cmd->resp[i + 1] >> 24;
 }
}

static void sdhci_finish_command(struct sdhci_host *host)
{
 struct mmc_command *cmd = host->cmd;

 host->cmd = NULL;

 if (cmd->flags & MMC_RSP_PRESENT) {
  if (cmd->flags & MMC_RSP_136) {
   sdhci_read_rsp_136(host, cmd);
  } else {
   cmd->resp[0] = sdhci_readl(host, SDHCI_RESPONSE);
  }
 }

 if (cmd->mrq->cap_cmd_during_tfr && cmd == cmd->mrq->cmd)
  mmc_command_done(host->mmc, cmd->mrq);

 /*
 * The host can send and interrupt when the busy state has
 * ended, allowing us to wait without wasting CPU cycles.
 * The busy signal uses DAT0 so this is similar to waiting
 * for data to complete.
 *
 * Note: The 1.0 specification is a bit ambiguous about this
 *       feature so there might be some problems with older
 *       controllers.
 */

 if (cmd->flags & MMC_RSP_BUSY) {
  if (cmd->data) {
   DBG("Cannot wait for busy signal when also doing a data transfer");
  } else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) &&
      cmd == host->data_cmd) {
   /* Command complete before busy is ended */
   return;
  }
 }

 /* Finished CMD23, now send actual command. */
 if (cmd == cmd->mrq->sbc) {
  if (!sdhci_send_command(host, cmd->mrq->cmd)) {
   WARN_ON(host->deferred_cmd);
   host->deferred_cmd = cmd->mrq->cmd;
  }
 } else {

  /* Processed actual command. */
  if (host->data && host->data_early)
   sdhci_finish_data(host);

  if (!cmd->data)
   __sdhci_finish_mrq(host, cmd->mrq);
 }
}

static u16 sdhci_get_preset_value(struct sdhci_host *host)
{
 u16 preset = 0;

 switch (host->timing) {
 case MMC_TIMING_MMC_HS:
 case MMC_TIMING_SD_HS:
  preset = sdhci_readw(host, SDHCI_PRESET_FOR_HIGH_SPEED);
  break;
 case MMC_TIMING_UHS_SDR12:
  preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12);
  break;
 case MMC_TIMING_UHS_SDR25:
  preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR25);
  break;
 case MMC_TIMING_UHS_SDR50:
  preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR50);
  break;
 case MMC_TIMING_UHS_SDR104:
 case MMC_TIMING_MMC_HS200:
  preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104);
  break;
 case MMC_TIMING_UHS_DDR50:
 case MMC_TIMING_MMC_DDR52:
  preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50);
  break;
 case MMC_TIMING_MMC_HS400:
  preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400);
  break;
 case MMC_TIMING_UHS2_SPEED_A:
 case MMC_TIMING_UHS2_SPEED_A_HD:
 case MMC_TIMING_UHS2_SPEED_B:
 case MMC_TIMING_UHS2_SPEED_B_HD:
  preset = sdhci_readw(host, SDHCI_PRESET_FOR_UHS2);
  break;
 default:
  pr_warn("%s: Invalid UHS-I mode selected\n",
   mmc_hostname(host->mmc));
  preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12);
  break;
 }
 return preset;
}

u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
     unsigned int *actual_clock)
{
 int div = 0; /* Initialized for compiler warning */
 int real_div = div, clk_mul = 1;
 u16 clk = 0;
 bool switch_base_clk = false;

 if (host->version >= SDHCI_SPEC_300) {
  if (host->preset_enabled) {
   u16 pre_val;

   clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
   pre_val = sdhci_get_preset_value(host);
   div = FIELD_GET(SDHCI_PRESET_SDCLK_FREQ_MASK, pre_val);
   if (host->clk_mul &&
    (pre_val & SDHCI_PRESET_CLKGEN_SEL)) {
    clk = SDHCI_PROG_CLOCK_MODE;
    real_div = div + 1;
    clk_mul = host->clk_mul;
   } else {
    real_div = max_t(int, 1, div << 1);
   }
   goto clock_set;
  }

  /*
 * Check if the Host Controller supports Programmable Clock
 * Mode.
 */

  if (host->clk_mul) {
   for (div = 1; div <= 1024; div++) {
    if ((host->max_clk * host->clk_mul / div)
     <= clock)
     break;
   }
   if ((host->max_clk * host->clk_mul / div) <= clock) {
    /*
 * Set Programmable Clock Mode in the Clock
 * Control register.
 */

    clk = SDHCI_PROG_CLOCK_MODE;
    real_div = div;
    clk_mul = host->clk_mul;
    div--;
   } else {
    /*
 * Divisor can be too small to reach clock
 * speed requirement. Then use the base clock.
 */

    switch_base_clk = true;
   }
  }

  if (!host->clk_mul || switch_base_clk) {
   /* Version 3.00 divisors must be a multiple of 2. */
   if (host->max_clk <= clock)
    div = 1;
   else {
    for (div = 2; div < SDHCI_MAX_DIV_SPEC_300;
         div += 2) {
     if ((host->max_clk / div) <= clock)
      break;
    }
   }
   real_div = div;
   div >>= 1;
   if ((host->quirks2 & SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN)
    && !div && host->max_clk <= 25000000)
    div = 1;
  }
 } else {
  /* Version 2.00 divisors must be a power of 2. */
  for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) {
   if ((host->max_clk / div) <= clock)
    break;
  }
  real_div = div;
  div >>= 1;
 }

clock_set:
 if (real_div)
  *actual_clock = (host->max_clk * clk_mul) / real_div;
 clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
 clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
  << SDHCI_DIVIDER_HI_SHIFT;

 return clk;
}
EXPORT_SYMBOL_GPL(sdhci_calc_clk);

void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
{
 ktime_t timeout;

 clk |= SDHCI_CLOCK_INT_EN;
 sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);

 /* Wait max 150 ms */
 timeout = ktime_add_ms(ktime_get(), 150);
 while (1) {
  bool timedout = ktime_after(ktime_get(), timeout);

  clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
  if (clk & SDHCI_CLOCK_INT_STABLE)
   break;
  if (timedout) {
   pr_err("%s: Internal clock never stabilised.\n",
          mmc_hostname(host->mmc));
   sdhci_err_stats_inc(host, CTRL_TIMEOUT);
   sdhci_dumpregs(host);
   return;
  }
  udelay(10);
 }

 if (host->version >= SDHCI_SPEC_410 && host->v4_mode) {
  clk |= SDHCI_CLOCK_PLL_EN;
  clk &= ~SDHCI_CLOCK_INT_STABLE;
  sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);

  /* Wait max 150 ms */
  timeout = ktime_add_ms(ktime_get(), 150);
  while (1) {
   bool timedout = ktime_after(ktime_get(), timeout);

   clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
   if (clk & SDHCI_CLOCK_INT_STABLE)
    break;
   if (timedout) {
    pr_err("%s: PLL clock never stabilised.\n",
           mmc_hostname(host->mmc));
    sdhci_err_stats_inc(host, CTRL_TIMEOUT);
    sdhci_dumpregs(host);
    return;
   }
   udelay(10);
  }
 }

 clk |= SDHCI_CLOCK_CARD_EN;
 sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
}
EXPORT_SYMBOL_GPL(sdhci_enable_clk);

void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
{
 u16 clk;

 host->mmc->actual_clock = 0;

 sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);

 if (clock == 0)
  return;

 clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
 sdhci_enable_clk(host, clk);
}
EXPORT_SYMBOL_GPL(sdhci_set_clock);

static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
    unsigned short vdd)
{
 struct mmc_host *mmc = host->mmc;

 mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);

 if (mode != MMC_POWER_OFF)
  sdhci_writeb(host, SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
 else
  sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
}

unsigned short sdhci_get_vdd_value(unsigned short vdd)
{
 switch (1 << vdd) {
 case MMC_VDD_165_195:
 /*
 * Without a regulator, SDHCI does not support 2.0v
 * so we only get here if the driver deliberately
 * added the 2.0v range to ocr_avail. Map it to 1.8v
 * for the purpose of turning on the power.
 */

 case MMC_VDD_20_21:
  return SDHCI_POWER_180;
 case MMC_VDD_29_30:
 case MMC_VDD_30_31:
  return SDHCI_POWER_300;
 case MMC_VDD_32_33:
 case MMC_VDD_33_34:
 /*
 * 3.4V ~ 3.6V are valid only for those platforms where it's
 * known that the voltage range is supported by hardware.
 */

 case MMC_VDD_34_35:
 case MMC_VDD_35_36:
  return SDHCI_POWER_330;
 default:
  return 0;
 }
}
EXPORT_SYMBOL_GPL(sdhci_get_vdd_value);

void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
      unsigned short vdd)
{
 u8 pwr = 0;

 if (mode != MMC_POWER_OFF) {
  pwr = sdhci_get_vdd_value(vdd);
  if (!pwr) {
   WARN(1, "%s: Invalid vdd %#x\n",
        mmc_hostname(host->mmc), vdd);
  }
 }

 if (host->pwr == pwr)
  return;

 host->pwr = pwr;

 if (pwr == 0) {
  sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
  if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
   sdhci_runtime_pm_bus_off(host);
 } else {
  /*
 * Spec says that we should clear the power reg before setting
 * a new value. Some controllers don't seem to like this though.
 */

  if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
   sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);

  /*
 * At least the Marvell CaFe chip gets confused if we set the
 * voltage and set turn on power at the same time, so set the
 * voltage first.
 */

  if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
   sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);

  pwr |= SDHCI_POWER_ON;

  sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);

  if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
   sdhci_runtime_pm_bus_on(host);

  /*
 * Some controllers need an extra 10ms delay of 10ms before
 * they can apply clock after applying power
 */

  if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
   mdelay(10);
 }
}
EXPORT_SYMBOL_GPL(sdhci_set_power_noreg);

void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
       unsigned short vdd)
{
 if (IS_ERR(host->mmc->supply.vmmc))
  sdhci_set_power_noreg(host, mode, vdd);
 else
  sdhci_set_power_reg(host, mode, vdd);
}
EXPORT_SYMBOL_GPL(sdhci_set_power);

/*
 * Some controllers need to configure a valid bus voltage on their power
 * register regardless of whether an external regulator is taking care of power
 * supply. This helper function takes care of it if set as the controller's
 * sdhci_ops.set_power callback.
 */

void sdhci_set_power_and_bus_voltage(struct sdhci_host *host,
         unsigned char mode,
         unsigned short vdd)
{
 if (!IS_ERR(host->mmc->supply.vmmc)) {
  struct mmc_host *mmc = host->mmc;

  mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
 }
 sdhci_set_power_noreg(host, mode, vdd);
}
EXPORT_SYMBOL_GPL(sdhci_set_power_and_bus_voltage);

/*****************************************************************************\
 *                                                                           *
 * MMC callbacks                                                             *
 *                                                                           *
\*****************************************************************************/


void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
 struct sdhci_host *host = mmc_priv(mmc);
 struct mmc_command *cmd;
 unsigned long flags;
 bool present;

 /* Firstly check card presence */
 present = mmc->ops->get_cd(mmc);

 spin_lock_irqsave(&host->lock, flags);

 sdhci_led_activate(host);

 if (sdhci_present_error(host, mrq->cmd, present))
  goto out_finish;

 cmd = sdhci_manual_cmd23(host, mrq) ? mrq->sbc : mrq->cmd;

 if (!sdhci_send_command_retry(host, cmd, flags))
  goto out_finish;

 spin_unlock_irqrestore(&host->lock, flags);

 return;

out_finish:
 sdhci_finish_mrq(host, mrq);
 spin_unlock_irqrestore(&host->lock, flags);
}
EXPORT_SYMBOL_GPL(sdhci_request);

int sdhci_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq)
{
 struct sdhci_host *host = mmc_priv(mmc);
 struct mmc_command *cmd;
 unsigned long flags;
 int ret = 0;

 spin_lock_irqsave(&host->lock, flags);

 if (sdhci_present_error(host, mrq->cmd, true)) {
  sdhci_finish_mrq(host, mrq);
  goto out_finish;
 }

 cmd = sdhci_manual_cmd23(host, mrq) ? mrq->sbc : mrq->cmd;

 /*
 * The HSQ may send a command in interrupt context without polling
 * the busy signaling, which means we should return BUSY if controller
 * has not released inhibit bits to allow HSQ trying to send request
 * again in non-atomic context. So we should not finish this request
 * here.
 */

 if (!sdhci_send_command(host, cmd))
  ret = -EBUSY;
 else
  sdhci_led_activate(host);

out_finish:
 spin_unlock_irqrestore(&host->lock, flags);
 return ret;
}
EXPORT_SYMBOL_GPL(sdhci_request_atomic);

void sdhci_set_bus_width(struct sdhci_host *host, int width)
{
 u8 ctrl;

 ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
 if (width == MMC_BUS_WIDTH_8) {
  ctrl &= ~SDHCI_CTRL_4BITBUS;
  ctrl |= SDHCI_CTRL_8BITBUS;
 } else {
  if (host->mmc->caps & MMC_CAP_8_BIT_DATA)
   ctrl &= ~SDHCI_CTRL_8BITBUS;
  if (width == MMC_BUS_WIDTH_4)
   ctrl |= SDHCI_CTRL_4BITBUS;
  else
   ctrl &= ~SDHCI_CTRL_4BITBUS;
 }
 sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
EXPORT_SYMBOL_GPL(sdhci_set_bus_width);

void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
{
 u16 ctrl_2;

 ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 /* Select Bus Speed Mode for host */
 ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
 if ((timing == MMC_TIMING_MMC_HS200) ||
     (timing == MMC_TIMING_UHS_SDR104))
  ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
 else if (timing == MMC_TIMING_UHS_SDR12)
  ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
 else if (timing == MMC_TIMING_UHS_SDR25)
  ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
 else if (timing == MMC_TIMING_UHS_SDR50)
  ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
 else if ((timing == MMC_TIMING_UHS_DDR50) ||
   (timing == MMC_TIMING_MMC_DDR52))
  ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
 else if (timing == MMC_TIMING_MMC_HS400)
  ctrl_2 |= SDHCI_CTRL_HS400; /* Non-standard */
 sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
}
EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);

static bool sdhci_timing_has_preset(unsigned char timing)
{
 switch (timing) {
 case MMC_TIMING_UHS_SDR12:
 case MMC_TIMING_UHS_SDR25:
 case MMC_TIMING_UHS_SDR50:
 case MMC_TIMING_UHS_SDR104:
 case MMC_TIMING_UHS_DDR50:
 case MMC_TIMING_MMC_DDR52:
  return true;
 }
 return false;
}

static bool sdhci_preset_needed(struct sdhci_host *host, unsigned char timing)
{
 return !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
        sdhci_timing_has_preset(timing);
}

static bool sdhci_presetable_values_change(struct sdhci_host *host, struct mmc_ios *ios)
{
 /*
 * Preset Values are: Driver Strength, Clock Generator and SDCLK/RCLK
 * Frequency. Check if preset values need to be enabled, or the Driver
 * Strength needs updating. Note, clock changes are handled separately.
 */

 return !host->preset_enabled &&
        (sdhci_preset_needed(host, ios->timing) || host->drv_type != ios->drv_type);
}

void sdhci_set_ios_common(struct mmc_host *mmc, struct mmc_ios *ios)
{
 struct sdhci_host *host = mmc_priv(mmc);

 /*
 * Reset the chip on each power off.
 * Should clear out any weird states.
 */

 if (ios->power_mode == MMC_POWER_OFF) {
  sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
  sdhci_reinit(host);
 }

 if (host->version >= SDHCI_SPEC_300 &&
  (ios->power_mode == MMC_POWER_UP) &&
  !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
  sdhci_enable_preset_value(host, false);
}
EXPORT_SYMBOL_GPL(sdhci_set_ios_common);

void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
 struct sdhci_host *host = mmc_priv(mmc);
 bool reinit_uhs = host->reinit_uhs;
 bool turning_on_clk;
 u8 ctrl;

 host->reinit_uhs = false;

 if (ios->power_mode == MMC_POWER_UNDEFINED)
  return;

 if (host->flags & SDHCI_DEVICE_DEAD) {
  if (!IS_ERR(mmc->supply.vmmc) &&
      ios->power_mode == MMC_POWER_OFF)
   mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
  return;
 }

 turning_on_clk = ios->clock != host->clock && ios->clock && !host->clock;

 sdhci_set_ios_common(mmc, ios);

 if (!ios->clock || ios->clock != host->clock) {
  host->ops->set_clock(host, ios->clock);
  host->clock = ios->clock;

  if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK &&
      host->clock) {
   host->timeout_clk = mmc->actual_clock ?
      mmc->actual_clock / 1000 :
      host->clock / 1000;
   mmc->max_busy_timeout =
    host->ops->get_max_timeout_count ?
    host->ops->get_max_timeout_count(host) :
    1 << 27;
   mmc->max_busy_timeout /= host->timeout_clk;
  }
 }

 if (host->ops->set_power)
  host->ops->set_power(host, ios->power_mode, ios->vdd);
 else
  sdhci_set_power(host, ios->power_mode, ios->vdd);

 if (host->ops->platform_send_init_74_clocks)
  host->ops->platform_send_init_74_clocks(host, ios->power_mode);

 host->ops->set_bus_width(host, ios->bus_width);

 /*
 * Special case to avoid multiple clock changes during voltage
 * switching.
 */

 if (!reinit_uhs &&
     turning_on_clk &&
     host->timing == ios->timing &&
     host->version >= SDHCI_SPEC_300 &&
     !sdhci_presetable_values_change(host, ios))
  return;

 ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);

 if (!(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) {
  if (ios->timing == MMC_TIMING_SD_HS ||
       ios->timing == MMC_TIMING_MMC_HS ||
       ios->timing == MMC_TIMING_MMC_HS400 ||
       ios->timing == MMC_TIMING_MMC_HS200 ||
       ios->timing == MMC_TIMING_MMC_DDR52 ||
       ios->timing == MMC_TIMING_UHS_SDR50 ||
       ios->timing == MMC_TIMING_UHS_SDR104 ||
       ios->timing == MMC_TIMING_UHS_DDR50 ||
       ios->timing == MMC_TIMING_UHS_SDR25)
   ctrl |= SDHCI_CTRL_HISPD;
  else
   ctrl &= ~SDHCI_CTRL_HISPD;
 }

 if (host->version >= SDHCI_SPEC_300) {
  u16 clk, ctrl_2;

  /*
 * According to SDHCI Spec v3.00, if the Preset Value
 * Enable in the Host Control 2 register is set, we
 * need to reset SD Clock Enable before changing High
 * Speed Enable to avoid generating clock glitches.
 */

  clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
  if (clk & SDHCI_CLOCK_CARD_EN) {
   clk &= ~SDHCI_CLOCK_CARD_EN;
   sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
  }

  sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);

  if (!host->preset_enabled) {
   /*
 * We only need to set Driver Strength if the
 * preset value enable is not set.
 */

   ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
   ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK;
   if (ios->drv_type == MMC_SET_DRIVER_TYPE_A)
    ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A;
   else if (ios->drv_type == MMC_SET_DRIVER_TYPE_B)
    ctrl_2 |= SDHCI_CTRL_DRV_TYPE_B;
   else if (ios->drv_type == MMC_SET_DRIVER_TYPE_C)
    ctrl_2 |= SDHCI_CTRL_DRV_TYPE_C;
   else if (ios->drv_type == MMC_SET_DRIVER_TYPE_D)
    ctrl_2 |= SDHCI_CTRL_DRV_TYPE_D;
   else {
    pr_warn("%s: invalid driver type, default to driver type B\n",
     mmc_hostname(mmc));
    ctrl_2 |= SDHCI_CTRL_DRV_TYPE_B;
   }

   sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
   host->drv_type = ios->drv_type;
  }

  host->ops->set_uhs_signaling(host, ios->timing);
  host->timing = ios->timing;

  if (sdhci_preset_needed(host, ios->timing)) {
   u16 preset;

   sdhci_enable_preset_value(host, true);
   preset = sdhci_get_preset_value(host);
   ios->drv_type = FIELD_GET(SDHCI_PRESET_DRV_MASK,
        preset);
   host->drv_type = ios->drv_type;
  }

  /* Re-enable SD Clock */
  host->ops->set_clock(host, host->clock);
 } else
  sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
EXPORT_SYMBOL_GPL(sdhci_set_ios);

static int sdhci_get_cd(struct mmc_host *mmc)
{
 struct sdhci_host *host = mmc_priv(mmc);
 int gpio_cd = mmc_gpio_get_cd(mmc);

 if (host->flags & SDHCI_DEVICE_DEAD)
  return 0;

 /* If nonremovable, assume that the card is always present. */
 if (!mmc_card_is_removable(mmc))
  return 1;

 /*
 * Try slot gpio detect, if defined it take precedence
 * over build in controller functionality
 */

 if (gpio_cd >= 0)
  return !!gpio_cd;

 /* If polling, assume that the card is always present. */
 if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
  return 1;

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=97 H=96 G=96

¤ Dauer der Verarbeitung: 0.20 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.