Commit 8b36ac50 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mmc-fixes-for-3.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc

MMC fixes for 3.3-rc4:
 * The most visible fix here is against a regression introduced in 3.3-rc1
   that ran cards in Ultra High Speed mode even when they failed to initialize
   in that mode, leading to lower-speed cards failing to mount.
 * A lockdep warning introduced in 3.3-rc1 is fixed.
 * Various other small driver fixes, most notably for a NULL dereference
   when using highmem with dw_mmc.

* tag 'mmc-fixes-for-3.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc:
  mmc: dw_mmc: Fix PIO mode with support of highmem
  mmc: atmel-mci: save and restore sdioirq when soft reset is performed
  mmc: block: Init ro_lock sysfs attr to fix lockdep warnings
  mmc: sh_mmcif: fix late delayed work initialisation
  mmc: tmio_mmc: fix card eject during IO with DMA
  mmc: core: Fix comparison issue in mmc_compare_ext_csds
  mmc: core: Fix PowerOff Notify suspend/resume
  mmc: sdhci-pci: set Medfield SDIO as non-removable
  mmc: core: add the capability for broken voltage
  mmc: core: Fix low speed mmc card detection failure
  mmc: esdhc: set the timeout to the max value
  mmc: esdhc: add PIO mode support
  mmc: core: Ensure clocks are always enabled before host interaction
  mmc: of_mmc_spi: fix little endian support
  mmc: core: UHS sdio card that fails should not exceed 50MHz
  mmc: esdhc: fix errors when booting kernel on Freescale eSDHC version 2.3
parents 694ce18e f9c2a0dc
...@@ -1694,6 +1694,7 @@ static int mmc_add_disk(struct mmc_blk_data *md) ...@@ -1694,6 +1694,7 @@ static int mmc_add_disk(struct mmc_blk_data *md)
md->power_ro_lock.show = power_ro_lock_show; md->power_ro_lock.show = power_ro_lock_show;
md->power_ro_lock.store = power_ro_lock_store; md->power_ro_lock.store = power_ro_lock_store;
sysfs_attr_init(&md->power_ro_lock.attr);
md->power_ro_lock.attr.mode = mode; md->power_ro_lock.attr.mode = mode;
md->power_ro_lock.attr.name = md->power_ro_lock.attr.name =
"ro_lock_until_next_power_on"; "ro_lock_until_next_power_on";
......
...@@ -290,8 +290,11 @@ static void mmc_wait_for_req_done(struct mmc_host *host, ...@@ -290,8 +290,11 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq, static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
bool is_first_req) bool is_first_req)
{ {
if (host->ops->pre_req) if (host->ops->pre_req) {
mmc_host_clk_hold(host);
host->ops->pre_req(host, mrq, is_first_req); host->ops->pre_req(host, mrq, is_first_req);
mmc_host_clk_release(host);
}
} }
/** /**
...@@ -306,8 +309,11 @@ static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq, ...@@ -306,8 +309,11 @@ static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq, static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
int err) int err)
{ {
if (host->ops->post_req) if (host->ops->post_req) {
mmc_host_clk_hold(host);
host->ops->post_req(host, mrq, err); host->ops->post_req(host, mrq, err);
mmc_host_clk_release(host);
}
} }
/** /**
...@@ -620,7 +626,9 @@ int mmc_host_enable(struct mmc_host *host) ...@@ -620,7 +626,9 @@ int mmc_host_enable(struct mmc_host *host)
int err; int err;
host->en_dis_recurs = 1; host->en_dis_recurs = 1;
mmc_host_clk_hold(host);
err = host->ops->enable(host); err = host->ops->enable(host);
mmc_host_clk_release(host);
host->en_dis_recurs = 0; host->en_dis_recurs = 0;
if (err) { if (err) {
...@@ -640,7 +648,9 @@ static int mmc_host_do_disable(struct mmc_host *host, int lazy) ...@@ -640,7 +648,9 @@ static int mmc_host_do_disable(struct mmc_host *host, int lazy)
int err; int err;
host->en_dis_recurs = 1; host->en_dis_recurs = 1;
mmc_host_clk_hold(host);
err = host->ops->disable(host, lazy); err = host->ops->disable(host, lazy);
mmc_host_clk_release(host);
host->en_dis_recurs = 0; host->en_dis_recurs = 0;
if (err < 0) { if (err < 0) {
...@@ -1121,6 +1131,10 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc, ...@@ -1121,6 +1131,10 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
* might not allow this operation * might not allow this operation
*/ */
voltage = regulator_get_voltage(supply); voltage = regulator_get_voltage(supply);
if (mmc->caps2 & MMC_CAP2_BROKEN_VOLTAGE)
min_uV = max_uV = voltage;
if (voltage < 0) if (voltage < 0)
result = voltage; result = voltage;
else if (voltage < min_uV || voltage > max_uV) else if (voltage < min_uV || voltage > max_uV)
...@@ -1203,8 +1217,11 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11 ...@@ -1203,8 +1217,11 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11
host->ios.signal_voltage = signal_voltage; host->ios.signal_voltage = signal_voltage;
if (host->ops->start_signal_voltage_switch) if (host->ops->start_signal_voltage_switch) {
mmc_host_clk_hold(host);
err = host->ops->start_signal_voltage_switch(host, &host->ios); err = host->ops->start_signal_voltage_switch(host, &host->ios);
mmc_host_clk_release(host);
}
return err; return err;
} }
...@@ -1239,6 +1256,7 @@ static void mmc_poweroff_notify(struct mmc_host *host) ...@@ -1239,6 +1256,7 @@ static void mmc_poweroff_notify(struct mmc_host *host)
int err = 0; int err = 0;
card = host->card; card = host->card;
mmc_claim_host(host);
/* /*
* Send power notify command only if card * Send power notify command only if card
...@@ -1269,6 +1287,7 @@ static void mmc_poweroff_notify(struct mmc_host *host) ...@@ -1269,6 +1287,7 @@ static void mmc_poweroff_notify(struct mmc_host *host)
/* Set the card state to no notification after the poweroff */ /* Set the card state to no notification after the poweroff */
card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION; card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION;
} }
mmc_release_host(host);
} }
/* /*
...@@ -1327,12 +1346,28 @@ static void mmc_power_up(struct mmc_host *host) ...@@ -1327,12 +1346,28 @@ static void mmc_power_up(struct mmc_host *host)
void mmc_power_off(struct mmc_host *host) void mmc_power_off(struct mmc_host *host)
{ {
int err = 0;
mmc_host_clk_hold(host); mmc_host_clk_hold(host);
host->ios.clock = 0; host->ios.clock = 0;
host->ios.vdd = 0; host->ios.vdd = 0;
/*
* For eMMC 4.5 device send AWAKE command before
* POWER_OFF_NOTIFY command, because in sleep state
* eMMC 4.5 devices respond to only RESET and AWAKE cmd
*/
if (host->card && mmc_card_is_sleep(host->card) &&
host->bus_ops->resume) {
err = host->bus_ops->resume(host);
if (!err)
mmc_poweroff_notify(host); mmc_poweroff_notify(host);
else
pr_warning("%s: error %d during resume "
"(continue with poweroff sequence)\n",
mmc_hostname(host), err);
}
/* /*
* Reset ocr mask to be the highest possible voltage supported for * Reset ocr mask to be the highest possible voltage supported for
...@@ -2386,12 +2421,6 @@ int mmc_suspend_host(struct mmc_host *host) ...@@ -2386,12 +2421,6 @@ int mmc_suspend_host(struct mmc_host *host)
*/ */
if (mmc_try_claim_host(host)) { if (mmc_try_claim_host(host)) {
if (host->bus_ops->suspend) { if (host->bus_ops->suspend) {
/*
* For eMMC 4.5 device send notify command
* before sleep, because in sleep state eMMC 4.5
* devices respond to only RESET and AWAKE cmd
*/
mmc_poweroff_notify(host);
err = host->bus_ops->suspend(host); err = host->bus_ops->suspend(host);
} }
mmc_do_release_host(host); mmc_do_release_host(host);
......
...@@ -14,27 +14,6 @@ ...@@ -14,27 +14,6 @@
int mmc_register_host_class(void); int mmc_register_host_class(void);
void mmc_unregister_host_class(void); void mmc_unregister_host_class(void);
#ifdef CONFIG_MMC_CLKGATE
void mmc_host_clk_hold(struct mmc_host *host);
void mmc_host_clk_release(struct mmc_host *host);
unsigned int mmc_host_clk_rate(struct mmc_host *host);
#else
static inline void mmc_host_clk_hold(struct mmc_host *host)
{
}
static inline void mmc_host_clk_release(struct mmc_host *host)
{
}
static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
{
return host->ios.clock;
}
#endif
void mmc_host_deeper_disable(struct work_struct *work); void mmc_host_deeper_disable(struct work_struct *work);
#endif #endif
......
...@@ -376,7 +376,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) ...@@ -376,7 +376,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
} }
card->ext_csd.raw_hc_erase_gap_size = card->ext_csd.raw_hc_erase_gap_size =
ext_csd[EXT_CSD_PARTITION_ATTRIBUTE]; ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
card->ext_csd.raw_sec_trim_mult = card->ext_csd.raw_sec_trim_mult =
ext_csd[EXT_CSD_SEC_TRIM_MULT]; ext_csd[EXT_CSD_SEC_TRIM_MULT];
card->ext_csd.raw_sec_erase_mult = card->ext_csd.raw_sec_erase_mult =
...@@ -551,7 +551,7 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) ...@@ -551,7 +551,7 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
goto out; goto out;
/* only compare read only fields */ /* only compare read only fields */
err = (!(card->ext_csd.raw_partition_support == err = !((card->ext_csd.raw_partition_support ==
bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) && bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
(card->ext_csd.raw_erased_mem_count == (card->ext_csd.raw_erased_mem_count ==
bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) && bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
...@@ -1006,7 +1006,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, ...@@ -1006,7 +1006,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
err = mmc_select_hs200(card); err = mmc_select_hs200(card);
else if (host->caps & MMC_CAP_MMC_HIGHSPEED) else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, 1, 0); EXT_CSD_HS_TIMING, 1,
card->ext_csd.generic_cmd6_time);
if (err && err != -EBADMSG) if (err && err != -EBADMSG)
goto free_card; goto free_card;
...@@ -1116,7 +1117,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, ...@@ -1116,7 +1117,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
* Activate wide bus and DDR (if supported). * Activate wide bus and DDR (if supported).
*/ */
if (!mmc_card_hs200(card) && if (!mmc_card_hs200(card) &&
(card->csd.mmca_vsn >= CSD_SPEC_VER_3) && (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) { (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
static unsigned ext_csd_bits[][2] = { static unsigned ext_csd_bits[][2] = {
{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 }, { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
...@@ -1315,11 +1316,13 @@ static int mmc_suspend(struct mmc_host *host) ...@@ -1315,11 +1316,13 @@ static int mmc_suspend(struct mmc_host *host)
BUG_ON(!host->card); BUG_ON(!host->card);
mmc_claim_host(host); mmc_claim_host(host);
if (mmc_card_can_sleep(host)) if (mmc_card_can_sleep(host)) {
err = mmc_card_sleep(host); err = mmc_card_sleep(host);
else if (!mmc_host_is_spi(host)) if (!err)
mmc_card_set_sleep(host->card);
} else if (!mmc_host_is_spi(host))
mmc_deselect_cards(host); mmc_deselect_cards(host);
host->card->state &= ~MMC_STATE_HIGHSPEED; host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
mmc_release_host(host); mmc_release_host(host);
return err; return err;
...@@ -1339,6 +1342,10 @@ static int mmc_resume(struct mmc_host *host) ...@@ -1339,6 +1342,10 @@ static int mmc_resume(struct mmc_host *host)
BUG_ON(!host->card); BUG_ON(!host->card);
mmc_claim_host(host); mmc_claim_host(host);
if (mmc_card_is_sleep(host->card)) {
err = mmc_card_awake(host);
mmc_card_clr_sleep(host->card);
} else
err = mmc_init_card(host, host->ocr, host->card); err = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host); mmc_release_host(host);
...@@ -1349,7 +1356,8 @@ static int mmc_power_restore(struct mmc_host *host) ...@@ -1349,7 +1356,8 @@ static int mmc_power_restore(struct mmc_host *host)
{ {
int ret; int ret;
host->card->state &= ~MMC_STATE_HIGHSPEED; host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
mmc_card_clr_sleep(host->card);
mmc_claim_host(host); mmc_claim_host(host);
ret = mmc_init_card(host, host->ocr, host->card); ret = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host); mmc_release_host(host);
......
...@@ -451,9 +451,11 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status) ...@@ -451,9 +451,11 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status)
* information and let the hardware specific code * information and let the hardware specific code
* return what is possible given the options * return what is possible given the options
*/ */
mmc_host_clk_hold(card->host);
drive_strength = card->host->ops->select_drive_strength( drive_strength = card->host->ops->select_drive_strength(
card->sw_caps.uhs_max_dtr, card->sw_caps.uhs_max_dtr,
host_drv_type, card_drv_type); host_drv_type, card_drv_type);
mmc_host_clk_release(card->host);
err = mmc_sd_switch(card, 1, 2, drive_strength, status); err = mmc_sd_switch(card, 1, 2, drive_strength, status);
if (err) if (err)
...@@ -660,9 +662,12 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) ...@@ -660,9 +662,12 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
goto out; goto out;
/* SPI mode doesn't define CMD19 */ /* SPI mode doesn't define CMD19 */
if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) {
mmc_host_clk_hold(card->host);
err = card->host->ops->execute_tuning(card->host, err = card->host->ops->execute_tuning(card->host,
MMC_SEND_TUNING_BLOCK); MMC_SEND_TUNING_BLOCK);
mmc_host_clk_release(card->host);
}
out: out:
kfree(status); kfree(status);
...@@ -850,8 +855,11 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, ...@@ -850,8 +855,11 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
if (!reinit) { if (!reinit) {
int ro = -1; int ro = -1;
if (host->ops->get_ro) if (host->ops->get_ro) {
mmc_host_clk_hold(card->host);
ro = host->ops->get_ro(host); ro = host->ops->get_ro(host);
mmc_host_clk_release(card->host);
}
if (ro < 0) { if (ro < 0) {
pr_warning("%s: host does not " pr_warning("%s: host does not "
...@@ -967,8 +975,11 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, ...@@ -967,8 +975,11 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
* Since initialization is now complete, enable preset * Since initialization is now complete, enable preset
* value registers for UHS-I cards. * value registers for UHS-I cards.
*/ */
if (host->ops->enable_preset_value) if (host->ops->enable_preset_value) {
mmc_host_clk_hold(card->host);
host->ops->enable_preset_value(host, true); host->ops->enable_preset_value(host, true);
mmc_host_clk_release(card->host);
}
} else { } else {
/* /*
* Attempt to change to high-speed (if supported) * Attempt to change to high-speed (if supported)
...@@ -1151,8 +1162,11 @@ int mmc_attach_sd(struct mmc_host *host) ...@@ -1151,8 +1162,11 @@ int mmc_attach_sd(struct mmc_host *host)
return err; return err;
/* Disable preset value enable if already set since last time */ /* Disable preset value enable if already set since last time */
if (host->ops->enable_preset_value) if (host->ops->enable_preset_value) {
mmc_host_clk_hold(host);
host->ops->enable_preset_value(host, false); host->ops->enable_preset_value(host, false);
mmc_host_clk_release(host);
}
err = mmc_send_app_op_cond(host, 0, &ocr); err = mmc_send_app_op_cond(host, 0, &ocr);
if (err) if (err)
......
...@@ -98,10 +98,11 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn) ...@@ -98,10 +98,11 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn)
return ret; return ret;
} }
static int sdio_read_cccr(struct mmc_card *card) static int sdio_read_cccr(struct mmc_card *card, u32 ocr)
{ {
int ret; int ret;
int cccr_vsn; int cccr_vsn;
int uhs = ocr & R4_18V_PRESENT;
unsigned char data; unsigned char data;
unsigned char speed; unsigned char speed;
...@@ -149,7 +150,7 @@ static int sdio_read_cccr(struct mmc_card *card) ...@@ -149,7 +150,7 @@ static int sdio_read_cccr(struct mmc_card *card)
card->scr.sda_spec3 = 0; card->scr.sda_spec3 = 0;
card->sw_caps.sd3_bus_mode = 0; card->sw_caps.sd3_bus_mode = 0;
card->sw_caps.sd3_drv_type = 0; card->sw_caps.sd3_drv_type = 0;
if (cccr_vsn >= SDIO_CCCR_REV_3_00) { if (cccr_vsn >= SDIO_CCCR_REV_3_00 && uhs) {
card->scr.sda_spec3 = 1; card->scr.sda_spec3 = 1;
ret = mmc_io_rw_direct(card, 0, 0, ret = mmc_io_rw_direct(card, 0, 0,
SDIO_CCCR_UHS, 0, &data); SDIO_CCCR_UHS, 0, &data);
...@@ -712,7 +713,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, ...@@ -712,7 +713,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
/* /*
* Read the common registers. * Read the common registers.
*/ */
err = sdio_read_cccr(card); err = sdio_read_cccr(card, ocr);
if (err) if (err)
goto remove; goto remove;
......
...@@ -146,15 +146,21 @@ static int sdio_irq_thread(void *_host) ...@@ -146,15 +146,21 @@ static int sdio_irq_thread(void *_host)
} }
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (host->caps & MMC_CAP_SDIO_IRQ) if (host->caps & MMC_CAP_SDIO_IRQ) {
mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 1); host->ops->enable_sdio_irq(host, 1);
mmc_host_clk_release(host);
}
if (!kthread_should_stop()) if (!kthread_should_stop())
schedule_timeout(period); schedule_timeout(period);
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
} while (!kthread_should_stop()); } while (!kthread_should_stop());
if (host->caps & MMC_CAP_SDIO_IRQ) if (host->caps & MMC_CAP_SDIO_IRQ) {
mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 0); host->ops->enable_sdio_irq(host, 0);
mmc_host_clk_release(host);
}
pr_debug("%s: IRQ thread exiting with code %d\n", pr_debug("%s: IRQ thread exiting with code %d\n",
mmc_hostname(host), ret); mmc_hostname(host), ret);
......
...@@ -969,11 +969,14 @@ static void atmci_start_request(struct atmel_mci *host, ...@@ -969,11 +969,14 @@ static void atmci_start_request(struct atmel_mci *host,
host->data_status = 0; host->data_status = 0;
if (host->need_reset) { if (host->need_reset) {
iflags = atmci_readl(host, ATMCI_IMR);
iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB);
atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN);
atmci_writel(host, ATMCI_MR, host->mode_reg); atmci_writel(host, ATMCI_MR, host->mode_reg);
if (host->caps.has_cfg_reg) if (host->caps.has_cfg_reg)
atmci_writel(host, ATMCI_CFG, host->cfg_reg); atmci_writel(host, ATMCI_CFG, host->cfg_reg);
atmci_writel(host, ATMCI_IER, iflags);
host->need_reset = false; host->need_reset = false;
} }
atmci_writel(host, ATMCI_SDCR, slot->sdc_reg); atmci_writel(host, ATMCI_SDCR, slot->sdc_reg);
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/scatterlist.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/stat.h> #include <linux/stat.h>
...@@ -502,8 +501,14 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) ...@@ -502,8 +501,14 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
host->dir_status = DW_MCI_SEND_STATUS; host->dir_status = DW_MCI_SEND_STATUS;
if (dw_mci_submit_data_dma(host, data)) { if (dw_mci_submit_data_dma(host, data)) {
int 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->sg = data->sg; host->sg = data->sg;
host->pio_offset = 0;
host->part_buf_start = 0; host->part_buf_start = 0;
host->part_buf_count = 0; host->part_buf_count = 0;
...@@ -972,6 +977,7 @@ static void dw_mci_tasklet_func(unsigned long priv) ...@@ -972,6 +977,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
* generates a block interrupt, hence setting * generates a block interrupt, hence setting
* the scatter-gather pointer to NULL. * the scatter-gather pointer to NULL.
*/ */
sg_miter_stop(&host->sg_miter);
host->sg = NULL; host->sg = NULL;
ctrl = mci_readl(host, CTRL); ctrl = mci_readl(host, CTRL);
ctrl |= SDMMC_CTRL_FIFO_RESET; ctrl |= SDMMC_CTRL_FIFO_RESET;
...@@ -1311,54 +1317,44 @@ static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt) ...@@ -1311,54 +1317,44 @@ static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)
static void dw_mci_read_data_pio(struct dw_mci *host) static void dw_mci_read_data_pio(struct dw_mci *host)
{ {
struct scatterlist *sg = host->sg; struct sg_mapping_iter *sg_miter = &host->sg_miter;
void *buf = sg_virt(sg); void *buf;
unsigned int offset = host->pio_offset; unsigned int offset;
struct mmc_data *data = host->data; struct mmc_data *data = host->data;
int shift = host->data_shift; int shift = host->data_shift;
u32 status; u32 status;
unsigned int nbytes = 0, len; unsigned int nbytes = 0, len;
unsigned int remain, fcnt;
do { do {
len = host->part_buf_count + if (!sg_miter_next(sg_miter))
(SDMMC_GET_FCNT(mci_readl(host, STATUS)) << shift);
if (offset + len <= sg->length) {
dw_mci_pull_data(host, (void *)(buf + offset), len);
offset += len;
nbytes += len;
if (offset == sg->length) {
flush_dcache_page(sg_page(sg));
host->sg = sg = sg_next(sg);
if (!sg)
goto done; goto done;
host->sg = sg_miter->__sg;
buf = sg_miter->addr;
remain = sg_miter->length;
offset = 0; offset = 0;
buf = sg_virt(sg);
}
} else {
unsigned int remaining = sg->length - offset;
dw_mci_pull_data(host, (void *)(buf + offset),
remaining);
nbytes += remaining;
flush_dcache_page(sg_page(sg));
host->sg = sg = sg_next(sg);
if (!sg)
goto done;
offset = len - remaining; do {
buf = sg_virt(sg); fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS))
dw_mci_pull_data(host, buf, offset); << shift) + host->part_buf_count;
nbytes += offset; len = min(remain, fcnt);
} if (!len)
break;
dw_mci_pull_data(host, (void *)(buf + offset), len);
offset += len;
nbytes += len;
remain -= len;
} while (remain);
sg_miter->consumed = offset;
status = mci_readl(host, MINTSTS); status = mci_readl(host, MINTSTS);
mci_writel(host, RINTSTS, SDMMC_INT_RXDR); mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
if (status & DW_MCI_DATA_ERROR_FLAGS) { if (status & DW_MCI_DATA_ERROR_FLAGS) {
host->data_status = status; host->data_status = status;
data->bytes_xfered += nbytes; data->bytes_xfered += nbytes;
sg_miter_stop(sg_miter);
host->sg = NULL;
smp_wmb(); smp_wmb();
set_bit(EVENT_DATA_ERROR, &host->pending_events); set_bit(EVENT_DATA_ERROR, &host->pending_events);
...@@ -1367,65 +1363,66 @@ static void dw_mci_read_data_pio(struct dw_mci *host) ...@@ -1367,65 +1363,66 @@ static void dw_mci_read_data_pio(struct dw_mci *host)
return; return;
} }
} while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/ } while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/
host->pio_offset = offset;
data->bytes_xfered += nbytes; data->bytes_xfered += nbytes;
if (!remain) {
if (!sg_miter_next(sg_miter))
goto done;
sg_miter->consumed = 0;
}
sg_miter_stop(sg_miter);
return; return;
done: done:
data->bytes_xfered += nbytes; data->bytes_xfered += nbytes;
sg_miter_stop(sg_miter);
host->sg = NULL;
smp_wmb(); smp_wmb();
set_bit(EVENT_XFER_COMPLETE, &host->pending_events); set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
} }
static void dw_mci_write_data_pio(struct dw_mci *host) static void dw_mci_write_data_pio(struct dw_mci *host)
{ {
struct scatterlist *sg = host->sg; struct sg_mapping_iter *sg_miter = &host->sg_miter;
void *buf = sg_virt(sg); void *buf;
unsigned int offset = host->pio_offset; unsigned int offset;
struct mmc_data *data = host->data; struct mmc_data *data = host->data;
int shift = host->data_shift; int shift = host->data_shift;
u32 status; u32 status;
unsigned int nbytes = 0, len; unsigned int nbytes = 0, len;
unsigned int fifo_depth = host->fifo_depth;
unsigned int remain, fcnt;
do { do {
len = ((host->fifo_depth - if (!sg_miter_next(sg_miter))
SDMMC_GET_FCNT(mci_readl(host, STATUS))) << shift)
- host->part_buf_count;
if (offset + len <= sg->length) {
host->push_data(host, (void *)(buf + offset), len);
offset += len;
nbytes += len;
if (offset == sg->length) {
host->sg = sg = sg_next(sg);
if (!sg)
goto done; goto done;
host->sg = sg_miter->__sg;
buf = sg_miter->addr;
remain = sg_miter->length;
offset = 0; offset = 0;
buf = sg_virt(sg);
}
} else {
unsigned int remaining = sg->length - offset;
host->push_data(host, (void *)(buf + offset),
remaining);
nbytes += remaining;
host->sg = sg = sg_next(sg); do {
if (!sg) fcnt = ((fifo_depth -
goto done; SDMMC_GET_FCNT(mci_readl(host, STATUS)))
<< shift) - host->part_buf_count;
offset = len - remaining; len = min(remain, fcnt);
buf = sg_virt(sg); if (!len)
host->push_data(host, (void *)buf, offset); break;
nbytes += offset; host->push_data(host, (void *)(buf + offset), len);
} offset += len;
nbytes += len;
remain -= len;
} while (remain);
sg_miter->consumed = offset;
status = mci_readl(host, MINTSTS); status = mci_readl(host, MINTSTS);
mci_writel(host, RINTSTS, SDMMC_INT_TXDR); mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
if (status & DW_MCI_DATA_ERROR_FLAGS) { if (status & DW_MCI_DATA_ERROR_FLAGS) {
host->data_status = status; host->data_status = status;
data->bytes_xfered += nbytes; data->bytes_xfered += nbytes;
sg_miter_stop(sg_miter);
host->sg = NULL;
smp_wmb(); smp_wmb();
...@@ -1435,12 +1432,20 @@ static void dw_mci_write_data_pio(struct dw_mci *host) ...@@ -1435,12 +1432,20 @@ static void dw_mci_write_data_pio(struct dw_mci *host)
return; return;
} }
} while (status & SDMMC_INT_TXDR); /* if TXDR write again */ } while (status & SDMMC_INT_TXDR); /* if TXDR write again */
host->pio_offset = offset;
data->bytes_xfered += nbytes; data->bytes_xfered += nbytes;
if (!remain) {
if (!sg_miter_next(sg_miter))
goto done;
sg_miter->consumed = 0;
}
sg_miter_stop(sg_miter);
return; return;
done: done:
data->bytes_xfered += nbytes; data->bytes_xfered += nbytes;
sg_miter_stop(sg_miter);
host->sg = NULL;
smp_wmb(); smp_wmb();
set_bit(EVENT_XFER_COMPLETE, &host->pending_events); set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
} }
...@@ -1643,6 +1648,7 @@ static void dw_mci_work_routine_card(struct work_struct *work) ...@@ -1643,6 +1648,7 @@ static void dw_mci_work_routine_card(struct work_struct *work)
* block interrupt, hence setting the * block interrupt, hence setting the
* scatter-gather pointer to NULL. * scatter-gather pointer to NULL.
*/ */
sg_miter_stop(&host->sg_miter);
host->sg = NULL; host->sg = NULL;
ctrl = mci_readl(host, CTRL); ctrl = mci_readl(host, CTRL);
......
...@@ -113,8 +113,8 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi) ...@@ -113,8 +113,8 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi)
const int j = i * 2; const int j = i * 2;
u32 mask; u32 mask;
mask = mmc_vddrange_to_ocrmask(voltage_ranges[j], mask = mmc_vddrange_to_ocrmask(be32_to_cpu(voltage_ranges[j]),
voltage_ranges[j + 1]); be32_to_cpu(voltage_ranges[j + 1]));
if (!mask) { if (!mask) {
ret = -EINVAL; ret = -EINVAL;
dev_err(dev, "OF: voltage-range #%d is invalid\n", i); dev_err(dev, "OF: voltage-range #%d is invalid\n", i);
......
...@@ -38,6 +38,23 @@ static u8 esdhc_readb(struct sdhci_host *host, int reg) ...@@ -38,6 +38,23 @@ static u8 esdhc_readb(struct sdhci_host *host, int reg)
int base = reg & ~0x3; int base = reg & ~0x3;
int shift = (reg & 0x3) * 8; int shift = (reg & 0x3) * 8;
u8 ret = (in_be32(host->ioaddr + base) >> shift) & 0xff; u8 ret = (in_be32(host->ioaddr + base) >> shift) & 0xff;
/*
* "DMA select" locates at offset 0x28 in SD specification, but on
* P5020 or P3041, it locates at 0x29.
*/
if (reg == SDHCI_HOST_CONTROL) {
u32 dma_bits;
dma_bits = in_be32(host->ioaddr + reg);
/* DMA select is 22,23 bits in Protocol Control Register */
dma_bits = (dma_bits >> 5) & SDHCI_CTRL_DMA_MASK;
/* fixup the result */
ret &= ~SDHCI_CTRL_DMA_MASK;
ret |= dma_bits;
}
return ret; return ret;
} }
...@@ -56,6 +73,21 @@ static void esdhc_writew(struct sdhci_host *host, u16 val, int reg) ...@@ -56,6 +73,21 @@ static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg) static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
{ {
/*
* "DMA select" location is offset 0x28 in SD specification, but on
* P5020 or P3041, it's located at 0x29.
*/
if (reg == SDHCI_HOST_CONTROL) {
u32 dma_bits;
/* DMA select is 22,23 bits in Protocol Control Register */
dma_bits = (val & SDHCI_CTRL_DMA_MASK) << 5;
clrsetbits_be32(host->ioaddr + reg , SDHCI_CTRL_DMA_MASK << 5,
dma_bits);
val &= ~SDHCI_CTRL_DMA_MASK;
val |= in_be32(host->ioaddr + reg) & SDHCI_CTRL_DMA_MASK;
}
/* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */ /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
if (reg == SDHCI_HOST_CONTROL) if (reg == SDHCI_HOST_CONTROL)
val &= ~ESDHC_HOST_CONTROL_RES; val &= ~ESDHC_HOST_CONTROL_RES;
......
...@@ -250,7 +250,7 @@ static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) ...@@ -250,7 +250,7 @@ static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot)
static int mfd_sdio_probe_slot(struct sdhci_pci_slot *slot) static int mfd_sdio_probe_slot(struct sdhci_pci_slot *slot)
{ {
slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD; slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE;
return 0; return 0;
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* sdhci-pltfm.c Support for SDHCI platform devices * sdhci-pltfm.c Support for SDHCI platform devices
* Copyright (c) 2009 Intel Corporation * Copyright (c) 2009 Intel Corporation
* *
* Copyright (c) 2007 Freescale Semiconductor, Inc. * Copyright (c) 2007, 2011 Freescale Semiconductor, Inc.
* Copyright (c) 2009 MontaVista Software, Inc. * Copyright (c) 2009 MontaVista Software, Inc.
* *
* Authors: Xiaobo Xie <X.Xie@freescale.com> * Authors: Xiaobo Xie <X.Xie@freescale.com>
...@@ -71,6 +71,14 @@ void sdhci_get_of_property(struct platform_device *pdev) ...@@ -71,6 +71,14 @@ void sdhci_get_of_property(struct platform_device *pdev)
if (sdhci_of_wp_inverted(np)) if (sdhci_of_wp_inverted(np))
host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT; host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
if (of_device_is_compatible(np, "fsl,p2020-esdhc") ||
of_device_is_compatible(np, "fsl,p1010-esdhc") ||
of_device_is_compatible(np, "fsl,mpc8536-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
clk = of_get_property(np, "clock-frequency", &size); clk = of_get_property(np, "clock-frequency", &size);
if (clk && size == sizeof(*clk) && *clk) if (clk && size == sizeof(*clk) && *clk)
pltfm_host->clock = be32_to_cpup(clk); pltfm_host->clock = be32_to_cpup(clk);
......
...@@ -1327,7 +1327,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) ...@@ -1327,7 +1327,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
if (ret < 0) if (ret < 0)
goto clean_up2; goto clean_up2;
mmc_add_host(mmc); INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work);
sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
...@@ -1338,22 +1338,24 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) ...@@ -1338,22 +1338,24 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
} }
ret = request_threaded_irq(irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host); ret = request_threaded_irq(irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host);
if (ret) { if (ret) {
free_irq(irq[0], host);
dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n"); dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n");
goto clean_up3; goto clean_up4;
} }
INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work); ret = mmc_add_host(mmc);
if (ret < 0)
mmc_detect_change(host->mmc, 0); goto clean_up5;
dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION); dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION);
dev_dbg(&pdev->dev, "chip ver H'%04x\n", dev_dbg(&pdev->dev, "chip ver H'%04x\n",
sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff); sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff);
return ret; return ret;
clean_up5:
free_irq(irq[1], host);
clean_up4:
free_irq(irq[0], host);
clean_up3: clean_up3:
mmc_remove_host(mmc);
pm_runtime_suspend(&pdev->dev); pm_runtime_suspend(&pdev->dev);
clean_up2: clean_up2:
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
......
...@@ -20,8 +20,8 @@ ...@@ -20,8 +20,8 @@
#include <linux/mmc/tmio.h> #include <linux/mmc/tmio.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/spinlock.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/spinlock.h>
/* Definitions for values the CTRL_SDIO_STATUS register can take. */ /* Definitions for values the CTRL_SDIO_STATUS register can take. */
#define TMIO_SDIO_STAT_IOIRQ 0x0001 #define TMIO_SDIO_STAT_IOIRQ 0x0001
...@@ -120,6 +120,7 @@ void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data); ...@@ -120,6 +120,7 @@ void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data);
void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable); void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable);
void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata); void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata);
void tmio_mmc_release_dma(struct tmio_mmc_host *host); void tmio_mmc_release_dma(struct tmio_mmc_host *host);
void tmio_mmc_abort_dma(struct tmio_mmc_host *host);
#else #else
static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host, static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host,
struct mmc_data *data) struct mmc_data *data)
...@@ -140,6 +141,10 @@ static inline void tmio_mmc_request_dma(struct tmio_mmc_host *host, ...@@ -140,6 +141,10 @@ static inline void tmio_mmc_request_dma(struct tmio_mmc_host *host,
static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host) static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host)
{ {
} }
static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
{
}
#endif #endif
#ifdef CONFIG_PM #ifdef CONFIG_PM
......
...@@ -34,6 +34,18 @@ void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) ...@@ -34,6 +34,18 @@ void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
#endif #endif
} }
void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
{
tmio_mmc_enable_dma(host, false);
if (host->chan_rx)
dmaengine_terminate_all(host->chan_rx);
if (host->chan_tx)
dmaengine_terminate_all(host->chan_tx);
tmio_mmc_enable_dma(host, true);
}
static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
{ {
struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct scatterlist *sg = host->sg_ptr, *sg_tmp;
......
...@@ -41,8 +41,8 @@ ...@@ -41,8 +41,8 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/workqueue.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/workqueue.h>
#include "tmio_mmc.h" #include "tmio_mmc.h"
...@@ -246,6 +246,7 @@ static void tmio_mmc_reset_work(struct work_struct *work) ...@@ -246,6 +246,7 @@ static void tmio_mmc_reset_work(struct work_struct *work)
/* Ready for new calls */ /* Ready for new calls */
host->mrq = NULL; host->mrq = NULL;
tmio_mmc_abort_dma(host);
mmc_request_done(host->mmc, mrq); mmc_request_done(host->mmc, mrq);
} }
...@@ -272,6 +273,9 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host) ...@@ -272,6 +273,9 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
host->mrq = NULL; host->mrq = NULL;
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
if (mrq->cmd->error || (mrq->data && mrq->data->error))
tmio_mmc_abort_dma(host);
mmc_request_done(host->mmc, mrq); mmc_request_done(host->mmc, mrq);
} }
......
...@@ -217,6 +217,7 @@ struct mmc_card { ...@@ -217,6 +217,7 @@ struct mmc_card {
#define MMC_CARD_SDXC (1<<6) /* card is SDXC */ #define MMC_CARD_SDXC (1<<6) /* card is SDXC */
#define MMC_CARD_REMOVED (1<<7) /* card has been removed */ #define MMC_CARD_REMOVED (1<<7) /* card has been removed */
#define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */ #define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */
#define MMC_STATE_SLEEP (1<<9) /* card is in sleep state */
unsigned int quirks; /* card quirks */ unsigned int quirks; /* card quirks */
#define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */ #define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */
#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */ #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */
...@@ -382,6 +383,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) ...@@ -382,6 +383,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
#define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED) #define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC) #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED)) #define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
#define mmc_card_is_sleep(c) ((c)->state & MMC_STATE_SLEEP)
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
...@@ -393,7 +395,9 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) ...@@ -393,7 +395,9 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
#define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED) #define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC) #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED) #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
#define mmc_card_set_sleep(c) ((c)->state |= MMC_STATE_SLEEP)
#define mmc_card_clr_sleep(c) ((c)->state &= ~MMC_STATE_SLEEP)
/* /*
* Quirk add/remove for MMC products. * Quirk add/remove for MMC products.
*/ */
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#ifndef LINUX_MMC_DW_MMC_H #ifndef LINUX_MMC_DW_MMC_H
#define LINUX_MMC_DW_MMC_H #define LINUX_MMC_DW_MMC_H
#include <linux/scatterlist.h>
#define MAX_MCI_SLOTS 2 #define MAX_MCI_SLOTS 2
enum dw_mci_state { enum dw_mci_state {
...@@ -40,7 +42,7 @@ struct mmc_data; ...@@ -40,7 +42,7 @@ struct mmc_data;
* @lock: Spinlock protecting the queue and associated data. * @lock: Spinlock protecting the queue and associated data.
* @regs: Pointer to MMIO registers. * @regs: Pointer to MMIO registers.
* @sg: Scatterlist entry currently being processed by PIO code, if any. * @sg: Scatterlist entry currently being processed by PIO code, if any.
* @pio_offset: Offset into the current scatterlist entry. * @sg_miter: PIO mapping scatterlist iterator.
* @cur_slot: The slot which is currently using the controller. * @cur_slot: The slot which is currently using the controller.
* @mrq: The request currently being processed on @cur_slot, * @mrq: The request currently being processed on @cur_slot,
* or NULL if the controller is idle. * or NULL if the controller is idle.
...@@ -115,7 +117,7 @@ struct dw_mci { ...@@ -115,7 +117,7 @@ struct dw_mci {
void __iomem *regs; void __iomem *regs;
struct scatterlist *sg; struct scatterlist *sg;
unsigned int pio_offset; struct sg_mapping_iter sg_miter;
struct dw_mci_slot *cur_slot; struct dw_mci_slot *cur_slot;
struct mmc_request *mrq; struct mmc_request *mrq;
......
...@@ -257,6 +257,7 @@ struct mmc_host { ...@@ -257,6 +257,7 @@ struct mmc_host {
#define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */ #define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */
#define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \ #define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \
MMC_CAP2_HS200_1_2V_SDR) MMC_CAP2_HS200_1_2V_SDR)
#define MMC_CAP2_BROKEN_VOLTAGE (1 << 7) /* Use the broken voltage */
mmc_pm_flag_t pm_caps; /* supported pm features */ mmc_pm_flag_t pm_caps; /* supported pm features */
unsigned int power_notify_type; unsigned int power_notify_type;
...@@ -444,4 +445,23 @@ static inline int mmc_boot_partition_access(struct mmc_host *host) ...@@ -444,4 +445,23 @@ static inline int mmc_boot_partition_access(struct mmc_host *host)
return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC); return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC);
} }
#ifdef CONFIG_MMC_CLKGATE
void mmc_host_clk_hold(struct mmc_host *host);
void mmc_host_clk_release(struct mmc_host *host);
unsigned int mmc_host_clk_rate(struct mmc_host *host);
#else
static inline void mmc_host_clk_hold(struct mmc_host *host)
{
}
static inline void mmc_host_clk_release(struct mmc_host *host)
{
}
static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
{
return host->ios.clock;
}
#endif
#endif /* LINUX_MMC_HOST_H */ #endif /* LINUX_MMC_HOST_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment