MMC core:

- A couple of changes to improve the support for erase/discard/trim cmds
  - Add eMMC HS400 enhanced strobe support
  - Show OCR and DSR registers in SYSFS for MMC/SD cards
  - Correct and improve busy detection logic for MMC switch (CMD6) cmds
  - Disable HPI cmds for certain broken Hynix eMMC cards
  - Allow MMC hosts to specify non-support for SD and MMC cmds
  - Some minor additional fixes
 
 MMC host:
  - sdhci: Re-works, fixes and clean-ups
  - sdhci: Add HW auto re-tuning support
  - sdhci: Re-factor code to prepare for adding support for eMMC CMDQ
  - sdhci-esdhc-imx: Fixes and clean-ups
  - sdhci-esdhc-imx: Update system PM support
  - sdhci-esdhc-imx: Enable HW auto re-tuning
  - sdhci-bcm2835: Remove driver as sdhci-iproc is used instead
  - sdhci-brcmstb: Add new driver for Broadcom BRCMSTB SoCs
  - sdhci-msm: Add support for UHS cards
  - sdhci-tegra: Improve support for UHS cards
  - sdhci-of-arasan: Update phy support for Rockchip SoCs
  - sdhci-of-arasan: Deploy enhanced strobe support
  - dw_mmc: Some fixes and clean-ups
  - dw_mmc: Enable support for erase/discard/trim cmds
  - dw_mmc: Enable CMD23 support
  - mediatek: Some fixes related to the eMMC HS400 support
  - sh_mmcif: Improve support for HW busy detection
  - rtsx_pci: Enable support for erase/discard/trim cmds
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJXnibNAAoJEP4mhCVzWIwpKIQQAM2iTx5ROuOe3/CmWEAv5phg
 XpgmuWz/R/KQH1wyDor4zEJUE5mUYpvSg9vSCByYnVwHpoNKg4R0t0OJZJSN05Z0
 njdKCtkVXlRaQitX3tiFQazkMLaQER0tRrqrHjYZYkBgr8DnSEf00aueSGshrr/p
 g/JE7Z+eGVJx6d3Lvd24NMVZYSGbVq5lY/JTbURkKR5C9OhEe5GMfUsw1M+aVhUo
 pvxeGVYuIr4WsP+c+roa6czTO8VMrsd71syLDCweWMk+GOHvaSjpzvdC7iFGAl4B
 CoN6f3LTpJGpDCBWnqp/yQMvrMsR1SKlrwOUph4XEAXZCaz5WtF8+vhQaK7gwYGO
 RiyIIh04Bup+gzY6w0Mwgsw0jAkw5ahXl6xknD58q/sPEdlKe0ATyxl0oUwDntc0
 957BtmOvChYG13Q5pW6VNef0jKW6LOU+brJKEGxtr8x9OPeCiQOBO/GCUTg3IwA5
 ohylmjS+/6G3G4bgGvfXyGvObOsdAh3RQ8g7/1pVb0hQobDhxO5PjtTqVtelfFJk
 PRdKKIWhROiNMrpVLZnL7+OLkusEQ4s0Lmq08T1dVXvV+hLITwyTyWYmBr6Kb51B
 2x3DO7PcfEyytSn3TjPjdp7Wax+19YL+tMmu2QAlXv3iHSKFAH17nLk0bPO6VOWZ
 FHzKKutm4TwZJ/fyyiqP
 =wzSC
 -----END PGP SIGNATURE-----

Merge tag 'mmc-v4.8' of git://git.linaro.org/people/ulf.hansson/mmc

Pull MMC updates from Ulf Hansson:
 "MMC core:
   - A couple of changes to improve the support for erase/discard/trim cmds
   - Add eMMC HS400 enhanced strobe support
   - Show OCR and DSR registers in SYSFS for MMC/SD cards
   - Correct and improve busy detection logic for MMC switch (CMD6) cmds
   - Disable HPI cmds for certain broken Hynix eMMC cards
   - Allow MMC hosts to specify non-support for SD and MMC cmds
   - Some minor additional fixes

  MMC host:
   - sdhci: Re-works, fixes and clean-ups
   - sdhci: Add HW auto re-tuning support
   - sdhci: Re-factor code to prepare for adding support for eMMC CMDQ
   - sdhci-esdhc-imx: Fixes and clean-ups
   - sdhci-esdhc-imx: Update system PM support
   - sdhci-esdhc-imx: Enable HW auto re-tuning
   - sdhci-bcm2835: Remove driver as sdhci-iproc is used instead
   - sdhci-brcmstb: Add new driver for Broadcom BRCMSTB SoCs
   - sdhci-msm: Add support for UHS cards
   - sdhci-tegra: Improve support for UHS cards
   - sdhci-of-arasan: Update phy support for Rockchip SoCs
   - sdhci-of-arasan: Deploy enhanced strobe support
   - dw_mmc: Some fixes and clean-ups
   - dw_mmc: Enable support for erase/discard/trim cmds
   - dw_mmc: Enable CMD23 support
   - mediatek: Some fixes related to the eMMC HS400 support
   - sh_mmcif: Improve support for HW busy detection
   - rtsx_pci: Enable support for erase/discard/trim cmds"

* tag 'mmc-v4.8' of git://git.linaro.org/people/ulf.hansson/mmc: (135 commits)
  mmc: rtsx_pci: Remove deprecated create_singlethread_workqueue
  mmc: rtsx_pci: Enable MMC_CAP_ERASE to allow erase/discard/trim requests
  mmc: rtsx_pci: Use the provided busy timeout from the mmc core
  mmc: sdhci-pltfm: Drop define for SDHCI_PLTFM_PMOPS
  mmc: sdhci-pltfm: Convert to use the SET_SYSTEM_SLEEP_PM_OPS
  mmc: sdhci-pltfm: Make sdhci_pltfm_suspend|resume() static
  mmc: sdhci-esdhc-imx: Use common sdhci_suspend|resume_host()
  mmc: sdhci-esdhc-imx: Assign system PM ops within #ifdef CONFIG_PM_SLEEP
  mmc: sdhci-sirf: Remove non needed #ifdef CONFIG_PM* for dev_pm_ops
  mmc: sdhci-s3c: Remove non needed #ifdef CONFIG_PM for dev_pm_ops
  mmc: sdhci-pxav3: Remove non needed #ifdef CONFIG_PM for dev_pm_ops
  mmc: sdhci-of-esdhc: Simplify code by using SIMPLE_DEV_PM_OPS
  mmc: sdhci-acpi: Simplify code by using SET_SYSTEM_SLEEP_PM_OPS
  mmc: sdhci-pci-core: Simplify code by using SET_SYSTEM_SLEEP_PM_OPS
  mmc: Change the max discard sectors and erase response when HW busy detect
  phy: rockchip-emmc: Wait even longer for the DLL to lock
  phy: rockchip-emmc: Be tolerant to card clock of 0 in power on
  mmc: sdhci-of-arasan: Revert: Always power the PHY off/on when clock changes
  mmc: sdhci-msm: Add support for UHS cards
  mmc: sdhci-msm: Add set_uhs_signaling() implementation
  ...
This commit is contained in:
Linus Torvalds 2016-07-31 21:36:58 -04:00
commit 07f00f06ba
65 changed files with 2127 additions and 1020 deletions

View file

@ -1801,8 +1801,7 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
do_data_tag = (card->ext_csd.data_tag_unit_size) &&
(prq->cmd_flags & REQ_META) &&
(rq_data_dir(prq) == WRITE) &&
((brq->data.blocks * brq->data.blksz) >=
card->ext_csd.data_tag_unit_size);
blk_rq_bytes(prq) >= card->ext_csd.data_tag_unit_size;
/* Argument of CMD23 */
packed_cmd_hdr[(i * 2)] = cpu_to_le32(
(do_rel_wr ? MMC_CMD23_ARG_REL_WR : 0) |
@ -1977,8 +1976,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
* When 4KB native sector is enabled, only 8 blocks
* multiple read or write is allowed
*/
if ((brq->data.blocks & 0x07) &&
(card->ext_csd.data_sector_size == 4096)) {
if (mmc_large_sector(card) &&
!IS_ALIGNED(blk_rq_sectors(rqc), 8)) {
pr_err("%s: Transfer size is not 4KB sector size aligned\n",
req->rq_disk->disk_name);
mq_rq = mq->mqrq_cur;
@ -2501,12 +2500,6 @@ force_ro_fail:
return ret;
}
#define CID_MANFID_SANDISK 0x2
#define CID_MANFID_TOSHIBA 0x11
#define CID_MANFID_MICRON 0x13
#define CID_MANFID_SAMSUNG 0x15
#define CID_MANFID_KINGSTON 0x70
static const struct mmc_fixup blk_fixups[] =
{
MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk,

View file

@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
mmc_card_ddr52(card) ? "DDR " : "",
type);
} else {
pr_info("%s: new %s%s%s%s%s card at address %04x\n",
pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
mmc_hostname(card->host),
mmc_card_uhs(card) ? "ultra high speed " :
(mmc_card_hs(card) ? "high speed " : ""),
mmc_card_hs400(card) ? "HS400 " :
(mmc_card_hs200(card) ? "HS200 " : ""),
mmc_card_hs400es(card) ? "Enhanced strobe " : "",
mmc_card_ddr52(card) ? "DDR " : "",
uhs_bus_speed_mode, type, card->rca);
}

View file

@ -1127,6 +1127,15 @@ void mmc_set_initial_state(struct mmc_host *host)
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
host->ios.drv_type = 0;
host->ios.enhanced_strobe = false;
/*
* Make sure we are in non-enhanced strobe mode before we
* actually enable it in ext_csd.
*/
if ((host->caps2 & MMC_CAP2_HS400_ES) &&
host->ops->hs400_enhanced_strobe)
host->ops->hs400_enhanced_strobe(host, &host->ios);
mmc_set_ios(host);
}
@ -1925,17 +1934,15 @@ void mmc_init_erase(struct mmc_card *card)
* to that size and alignment.
*
* For SD cards that define Allocation Unit size, limit erases to one
* Allocation Unit at a time. For MMC cards that define High Capacity
* Erase Size, whether it is switched on or not, limit to that size.
* Otherwise just have a stab at a good value. For modern cards it
* will end up being 4MiB. Note that if the value is too small, it
* can end up taking longer to erase.
* Allocation Unit at a time.
* For MMC, have a stab at ai good value and for modern cards it will
* end up being 4MiB. Note that if the value is too small, it can end
* up taking longer to erase. Also note, erase_size is already set to
* High Capacity Erase Size if available when this function is called.
*/
if (mmc_card_sd(card) && card->ssr.au) {
card->pref_erase = card->ssr.au;
card->erase_shift = ffs(card->ssr.au) - 1;
} else if (card->ext_csd.hc_erase_size) {
card->pref_erase = card->ext_csd.hc_erase_size;
} else if (card->erase_size) {
sz = (card->csd.capacity << (card->csd.read_blkbits - 9)) >> 11;
if (sz < 128)
@ -2060,7 +2067,8 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
unsigned int to, unsigned int arg)
{
struct mmc_command cmd = {0};
unsigned int qty = 0;
unsigned int qty = 0, busy_timeout = 0;
bool use_r1b_resp = false;
unsigned long timeout;
int err;
@ -2128,8 +2136,22 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_ERASE;
cmd.arg = arg;
cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
cmd.busy_timeout = mmc_erase_timeout(card, arg, qty);
busy_timeout = mmc_erase_timeout(card, arg, qty);
/*
* If the host controller supports busy signalling and the timeout for
* the erase operation does not exceed the max_busy_timeout, we should
* use R1B response. Or we need to prevent the host from doing hw busy
* detection, which is done by converting to a R1 response instead.
*/
if (card->host->max_busy_timeout &&
busy_timeout > card->host->max_busy_timeout) {
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
} else {
cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
cmd.busy_timeout = busy_timeout;
use_r1b_resp = true;
}
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err) {
pr_err("mmc_erase: erase error %d, status %#x\n",
@ -2141,7 +2163,14 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
if (mmc_host_is_spi(card->host))
goto out;
timeout = jiffies + msecs_to_jiffies(MMC_CORE_TIMEOUT_MS);
/*
* In case of when R1B + MMC_CAP_WAIT_WHILE_BUSY is used, the polling
* shall be avoided.
*/
if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
goto out;
timeout = jiffies + msecs_to_jiffies(busy_timeout);
do {
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SEND_STATUS;
@ -2321,23 +2350,41 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
unsigned int arg)
{
struct mmc_host *host = card->host;
unsigned int max_discard, x, y, qty = 0, max_qty, timeout;
unsigned int max_discard, x, y, qty = 0, max_qty, min_qty, timeout;
unsigned int last_timeout = 0;
if (card->erase_shift)
if (card->erase_shift) {
max_qty = UINT_MAX >> card->erase_shift;
else if (mmc_card_sd(card))
min_qty = card->pref_erase >> card->erase_shift;
} else if (mmc_card_sd(card)) {
max_qty = UINT_MAX;
else
min_qty = card->pref_erase;
} else {
max_qty = UINT_MAX / card->erase_size;
min_qty = card->pref_erase / card->erase_size;
}
/* Find the largest qty with an OK timeout */
/*
* We should not only use 'host->max_busy_timeout' as the limitation
* when deciding the max discard sectors. We should set a balance value
* to improve the erase speed, and it can not get too long timeout at
* the same time.
*
* Here we set 'card->pref_erase' as the minimal discard sectors no
* matter what size of 'host->max_busy_timeout', but if the
* 'host->max_busy_timeout' is large enough for more discard sectors,
* then we can continue to increase the max discard sectors until we
* get a balance value.
*/
do {
y = 0;
for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {
timeout = mmc_erase_timeout(card, arg, qty + x);
if (timeout > host->max_busy_timeout)
if (qty + x > min_qty &&
timeout > host->max_busy_timeout)
break;
if (timeout < last_timeout)
break;
last_timeout = timeout;
@ -2491,17 +2538,21 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
mmc_go_idle(host);
mmc_send_if_cond(host, host->ocr_avail);
if (!(host->caps2 & MMC_CAP2_NO_SD))
mmc_send_if_cond(host, host->ocr_avail);
/* Order's important: probe SDIO, then SD, then MMC */
if (!(host->caps2 & MMC_CAP2_NO_SDIO))
if (!mmc_attach_sdio(host))
return 0;
if (!mmc_attach_sd(host))
return 0;
if (!mmc_attach_mmc(host))
return 0;
if (!(host->caps2 & MMC_CAP2_NO_SD))
if (!mmc_attach_sd(host))
return 0;
if (!(host->caps2 & MMC_CAP2_NO_MMC))
if (!mmc_attach_mmc(host))
return 0;
mmc_power_off(host);
return -EIO;

View file

@ -148,7 +148,8 @@ static int mmc_ios_show(struct seq_file *s, void *data)
str = "mmc HS200";
break;
case MMC_TIMING_MMC_HS400:
str = "mmc HS400";
str = mmc_card_hs400es(host->card) ?
"mmc HS400 enhanced strobe" : "mmc HS400";
break;
default:
str = "invalid";

View file

@ -313,6 +313,14 @@ int mmc_of_parse(struct mmc_host *host)
host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
if (of_property_read_bool(np, "mmc-hs400-1_2v"))
host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
if (of_property_read_bool(np, "mmc-hs400-enhanced-strobe"))
host->caps2 |= MMC_CAP2_HS400_ES;
if (of_property_read_bool(np, "no-sdio"))
host->caps2 |= MMC_CAP2_NO_SDIO;
if (of_property_read_bool(np, "no-sd"))
host->caps2 |= MMC_CAP2_NO_SD;
if (of_property_read_bool(np, "no-mmc"))
host->caps2 |= MMC_CAP2_NO_MMC;
host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
if (host->dsr_req && (host->dsr & ~0xffff)) {

View file

@ -45,6 +45,17 @@ static const unsigned int tacc_mant[] = {
35, 40, 45, 50, 55, 60, 70, 80,
};
static const struct mmc_fixup mmc_ext_csd_fixups[] = {
/*
* Certain Hynix eMMC 4.41 cards might get broken when HPI feature
* is used so disable the HPI feature for such buggy cards.
*/
MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX,
0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5),
END_FIXUP
};
#define UNSTUFF_BITS(resp,start,size) \
({ \
const int __size = size; \
@ -235,6 +246,11 @@ static void mmc_select_card_type(struct mmc_card *card)
avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
}
if ((caps2 & MMC_CAP2_HS400_ES) &&
card->ext_csd.strobe_support &&
(avail_type & EXT_CSD_CARD_TYPE_HS400))
avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
card->ext_csd.hs_max_dtr = hs_max_dtr;
card->ext_csd.hs200_max_dtr = hs200_max_dtr;
card->mmc_avail_type = avail_type;
@ -370,6 +386,9 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
*/
card->ext_csd.rev = ext_csd[EXT_CSD_REV];
/* fixup device after ext_csd revision field is updated */
mmc_fixup_device(card, mmc_ext_csd_fixups);
card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0];
card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1];
card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2];
@ -386,6 +405,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
mmc_card_set_blockaddr(card);
}
card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
mmc_select_card_type(card);
@ -500,7 +520,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
card->cid.year += 16;
/* check whether the eMMC card supports BKOPS */
if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
if (!mmc_card_broken_hpi(card) &&
ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
card->ext_csd.bkops = 1;
card->ext_csd.man_bkops_en =
(ext_csd[EXT_CSD_BKOPS_EN] &
@ -513,7 +534,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
}
/* check whether the eMMC card supports HPI */
if (!broken_hpi && (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1)) {
if (!mmc_card_broken_hpi(card) &&
!broken_hpi && (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1)) {
card->ext_csd.hpi = 1;
if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION;
@ -727,6 +749,7 @@ MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
MMC_DEV_ATTR(ocr, "%08x\n", card->ocr);
static ssize_t mmc_fwrev_show(struct device *dev,
struct device_attribute *attr,
@ -744,6 +767,22 @@ static ssize_t mmc_fwrev_show(struct device *dev,
static DEVICE_ATTR(fwrev, S_IRUGO, mmc_fwrev_show, NULL);
static ssize_t mmc_dsr_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct mmc_card *card = mmc_dev_to_card(dev);
struct mmc_host *host = card->host;
if (card->csd.dsr_imp && host->dsr_req)
return sprintf(buf, "0x%x\n", host->dsr);
else
/* return default DSR value */
return sprintf(buf, "0x%x\n", 0x404);
}
static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL);
static struct attribute *mmc_std_attrs[] = {
&dev_attr_cid.attr,
&dev_attr_csd.attr,
@ -762,6 +801,8 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_enhanced_area_size.attr,
&dev_attr_raw_rpmb_size_mult.attr,
&dev_attr_rel_sectors.attr,
&dev_attr_ocr.attr,
&dev_attr_dsr.attr,
NULL,
};
ATTRIBUTE_GROUPS(mmc_std);
@ -959,6 +1000,19 @@ static int mmc_select_bus_width(struct mmc_card *card)
return err;
}
/* Caller must hold re-tuning */
static int mmc_switch_status(struct mmc_card *card)
{
u32 status;
int err;
err = mmc_send_status(card, &status);
if (err)
return err;
return mmc_switch_status_error(card->host, status);
}
/*
* Switch to the high-speed mode
*/
@ -969,9 +1023,11 @@ static int mmc_select_hs(struct mmc_card *card)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
card->ext_csd.generic_cmd6_time,
true, true, true);
if (!err)
true, false, true);
if (!err) {
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
err = mmc_switch_status(card);
}
return err;
}
@ -1047,23 +1103,9 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
return err;
}
/* Caller must hold re-tuning */
static int mmc_switch_status(struct mmc_card *card)
{
u32 status;
int err;
err = mmc_send_status(card, &status);
if (err)
return err;
return mmc_switch_status_error(card->host, status);
}
static int mmc_select_hs400(struct mmc_card *card)
{
struct mmc_host *host = card->host;
bool send_status = true;
unsigned int max_dtr;
int err = 0;
u8 val;
@ -1075,19 +1117,12 @@ static int mmc_select_hs400(struct mmc_card *card)
host->ios.bus_width == MMC_BUS_WIDTH_8))
return 0;
if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
send_status = false;
/* Reduce frequency to HS frequency */
max_dtr = card->ext_csd.hs_max_dtr;
mmc_set_clock(host, max_dtr);
/* Switch card to HS mode */
val = EXT_CSD_TIMING_HS;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time,
true, send_status, true);
true, false, true);
if (err) {
pr_err("%s: switch to high-speed from hs200 failed, err:%d\n",
mmc_hostname(host), err);
@ -1097,11 +1132,13 @@ static int mmc_select_hs400(struct mmc_card *card)
/* Set host controller to HS timing */
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
if (!send_status) {
err = mmc_switch_status(card);
if (err)
goto out_err;
}
/* Reduce frequency to HS frequency */
max_dtr = card->ext_csd.hs_max_dtr;
mmc_set_clock(host, max_dtr);
err = mmc_switch_status(card);
if (err)
goto out_err;
/* Switch card to DDR */
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
@ -1120,7 +1157,7 @@ static int mmc_select_hs400(struct mmc_card *card)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time,
true, send_status, true);
true, false, true);
if (err) {
pr_err("%s: switch to hs400 failed, err:%d\n",
mmc_hostname(host), err);
@ -1131,11 +1168,9 @@ static int mmc_select_hs400(struct mmc_card *card)
mmc_set_timing(host, MMC_TIMING_MMC_HS400);
mmc_set_bus_speed(card);
if (!send_status) {
err = mmc_switch_status(card);
if (err)
goto out_err;
}
err = mmc_switch_status(card);
if (err)
goto out_err;
return 0;
@ -1153,14 +1188,10 @@ int mmc_hs200_to_hs400(struct mmc_card *card)
int mmc_hs400_to_hs200(struct mmc_card *card)
{
struct mmc_host *host = card->host;
bool send_status = true;
unsigned int max_dtr;
int err;
u8 val;
if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
send_status = false;
/* Reduce frequency to HS */
max_dtr = card->ext_csd.hs_max_dtr;
mmc_set_clock(host, max_dtr);
@ -1169,49 +1200,43 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
val = EXT_CSD_TIMING_HS;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
val, card->ext_csd.generic_cmd6_time,
true, send_status, true);
true, false, true);
if (err)
goto out_err;
mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
if (!send_status) {
err = mmc_switch_status(card);
if (err)
goto out_err;
}
err = mmc_switch_status(card);
if (err)
goto out_err;
/* Switch HS DDR to HS */
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
EXT_CSD_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time,
true, send_status, true);
true, false, true);
if (err)
goto out_err;
mmc_set_timing(host, MMC_TIMING_MMC_HS);
if (!send_status) {
err = mmc_switch_status(card);
if (err)
goto out_err;
}
err = mmc_switch_status(card);
if (err)
goto out_err;
/* Switch HS to HS200 */
val = EXT_CSD_TIMING_HS200 |
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
val, card->ext_csd.generic_cmd6_time, true,
send_status, true);
val, card->ext_csd.generic_cmd6_time,
true, false, true);
if (err)
goto out_err;
mmc_set_timing(host, MMC_TIMING_MMC_HS200);
if (!send_status) {
err = mmc_switch_status(card);
if (err)
goto out_err;
}
err = mmc_switch_status(card);
if (err)
goto out_err;
mmc_set_bus_speed(card);
@ -1223,6 +1248,78 @@ out_err:
return err;
}
static int mmc_select_hs400es(struct mmc_card *card)
{
struct mmc_host *host = card->host;
int err = 0;
u8 val;
if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
err = -ENOTSUPP;
goto out_err;
}
err = mmc_select_bus_width(card);
if (err < 0)
goto out_err;
/* Switch card to HS mode */
err = mmc_select_hs(card);
if (err) {
pr_err("%s: switch to high-speed failed, err:%d\n",
mmc_hostname(host), err);
goto out_err;
}
err = mmc_switch_status(card);
if (err)
goto out_err;
/* Switch card to DDR with strobe bit */
val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
val,
card->ext_csd.generic_cmd6_time);
if (err) {
pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
mmc_hostname(host), err);
goto out_err;
}
/* Switch card to HS400 */
val = EXT_CSD_TIMING_HS400 |
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time,
true, false, true);
if (err) {
pr_err("%s: switch to hs400es failed, err:%d\n",
mmc_hostname(host), err);
goto out_err;
}
/* Set host controller to HS400 timing and frequency */
mmc_set_timing(host, MMC_TIMING_MMC_HS400);
/* Controller enable enhanced strobe function */
host->ios.enhanced_strobe = true;
if (host->ops->hs400_enhanced_strobe)
host->ops->hs400_enhanced_strobe(host, &host->ios);
err = mmc_switch_status(card);
if (err)
goto out_err;
return 0;
out_err:
pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
__func__, err);
return err;
}
static void mmc_select_driver_type(struct mmc_card *card)
{
int card_drv_type, drive_strength, drv_type;
@ -1250,7 +1347,6 @@ static void mmc_select_driver_type(struct mmc_card *card)
static int mmc_select_hs200(struct mmc_card *card)
{
struct mmc_host *host = card->host;
bool send_status = true;
unsigned int old_timing, old_signal_voltage;
int err = -EINVAL;
u8 val;
@ -1268,34 +1364,30 @@ static int mmc_select_hs200(struct mmc_card *card)
mmc_select_driver_type(card);
if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
send_status = false;
/*
* Set the bus width(4 or 8) with host's support and
* switch to HS200 mode if bus width is set successfully.
*/
err = mmc_select_bus_width(card);
if (err >= 0) {
if (err > 0) {
val = EXT_CSD_TIMING_HS200 |
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time,
true, send_status, true);
true, false, true);
if (err)
goto err;
old_timing = host->ios.timing;
mmc_set_timing(host, MMC_TIMING_MMC_HS200);
if (!send_status) {
err = mmc_switch_status(card);
/*
* mmc_select_timing() assumes timing has not changed if
* it is a switch error.
*/
if (err == -EBADMSG)
mmc_set_timing(host, old_timing);
}
err = mmc_switch_status(card);
/*
* mmc_select_timing() assumes timing has not changed if
* it is a switch error.
*/
if (err == -EBADMSG)
mmc_set_timing(host, old_timing);
}
err:
if (err) {
@ -1310,7 +1402,7 @@ err:
}
/*
* Activate High Speed or HS200 mode if supported.
* Activate High Speed, HS200 or HS400ES mode if supported.
*/
static int mmc_select_timing(struct mmc_card *card)
{
@ -1319,7 +1411,9 @@ static int mmc_select_timing(struct mmc_card *card)
if (!mmc_can_ext_csd(card))
goto bus_speed;
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
err = mmc_select_hs400es(card);
else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
err = mmc_select_hs200(card);
else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
err = mmc_select_hs(card);
@ -1583,7 +1677,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
} else if (mmc_card_hs(card)) {
/* Select the desired bus width optionally */
err = mmc_select_bus_width(card);
if (err >= 0) {
if (err > 0) {
err = mmc_select_hs_ddr(card);
if (err)
goto free_card;
@ -1616,7 +1710,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
* If cache size is higher than 0, this indicates
* the existence of cache and it can be turned on.
*/
if (card->ext_csd.cache_size > 0) {
if (!mmc_card_broken_hpi(card) &&
card->ext_csd.cache_size > 0) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_CACHE_CTRL, 1,
card->ext_csd.generic_cmd6_time);

View file

@ -480,6 +480,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
u32 status = 0;
bool use_r1b_resp = use_busy_signal;
bool expired = false;
bool busy = false;
mmc_retune_hold(host);
@ -533,21 +534,26 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
timeout_ms = MMC_OPS_TIMEOUT_MS;
/* Must check status to be sure of no errors. */
timeout = jiffies + msecs_to_jiffies(timeout_ms);
timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1;
do {
/*
* Due to the possibility of being preempted after
* sending the status command, check the expiration
* time first.
*/
expired = time_after(jiffies, timeout);
if (send_status) {
/*
* Due to the possibility of being preempted after
* sending the status command, check the expiration
* time first.
*/
expired = time_after(jiffies, timeout);
err = __mmc_send_status(card, &status, ignore_crc);
if (err)
goto out;
}
if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
break;
if (host->ops->card_busy) {
if (!host->ops->card_busy(host))
break;
busy = true;
}
if (mmc_host_is_spi(host))
break;
@ -556,19 +562,20 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
* does'nt support MMC_CAP_WAIT_WHILE_BUSY, then we can only
* rely on waiting for the stated timeout to be sufficient.
*/
if (!send_status) {
if (!send_status && !host->ops->card_busy) {
mmc_delay(timeout_ms);
goto out;
}
/* Timeout if the device never leaves the program state. */
if (expired && R1_CURRENT_STATE(status) == R1_STATE_PRG) {
if (expired &&
(R1_CURRENT_STATE(status) == R1_STATE_PRG || busy)) {
pr_err("%s: Card stuck in programming state! %s\n",
mmc_hostname(host), __func__);
err = -ETIMEDOUT;
goto out;
}
} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
} while (R1_CURRENT_STATE(status) == R1_STATE_PRG || busy);
err = mmc_switch_status_error(host, status);
out:

View file

@ -72,6 +72,8 @@ void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
f->cis_vendor == (u16) SDIO_ANY_ID) &&
(f->cis_device == card->cis.device ||
f->cis_device == (u16) SDIO_ANY_ID) &&
(f->ext_csd_rev == EXT_CSD_REV_ANY ||
f->ext_csd_rev == card->ext_csd.rev) &&
rev >= f->rev_start && rev <= f->rev_end) {
dev_dbg(&card->dev, "calling %pf\n", f->vendor_fixup);
f->vendor_fixup(card, f->data);

View file

@ -675,8 +675,25 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
MMC_DEV_ATTR(ocr, "%08x\n", card->ocr);
static ssize_t mmc_dsr_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct mmc_card *card = mmc_dev_to_card(dev);
struct mmc_host *host = card->host;
if (card->csd.dsr_imp && host->dsr_req)
return sprintf(buf, "0x%x\n", host->dsr);
else
/* return default DSR value */
return sprintf(buf, "0x%x\n", 0x404);
}
static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL);
static struct attribute *sd_std_attrs[] = {
&dev_attr_cid.attr,
&dev_attr_csd.attr,
@ -690,6 +707,8 @@ static struct attribute *sd_std_attrs[] = {
&dev_attr_name.attr,
&dev_attr_oemid.attr,
&dev_attr_serial.attr,
&dev_attr_ocr.attr,
&dev_attr_dsr.attr,
NULL,
};
ATTRIBUTE_GROUPS(sd_std);

View file

@ -122,6 +122,7 @@ config MMC_SDHCI_OF_ARASAN
tristate "SDHCI OF support for the Arasan SDHCI controllers"
depends on MMC_SDHCI_PLTFM
depends on OF
depends on COMMON_CLK
help
This selects the Arasan Secure Digital Host Controller Interface
(SDHCI). This hardware is found e.g. in Xilinx' Zynq SoC.
@ -296,17 +297,6 @@ config MMC_SDHCI_BCM_KONA
If you have a controller with this interface, say Y or M here.
config MMC_SDHCI_BCM2835
tristate "SDHCI platform support for the BCM2835 SD/MMC Controller"
depends on ARCH_BCM2835
depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS
help
This selects the BCM2835 SD/MMC controller. If you have a BCM2835
platform with SD or MMC devices, say Y or M here.
If unsure, say N.
config MMC_SDHCI_F_SDH30
tristate "SDHCI support for Fujitsu Semiconductor F_SDH30"
depends on MMC_SDHCI_PLTFM
@ -798,3 +788,13 @@ config MMC_SDHCI_MICROCHIP_PIC32
If you have a controller with this interface, say Y or M here.
If unsure, say N.
config MMC_SDHCI_BRCMSTB
tristate "Broadcom SDIO/SD/MMC support"
depends on ARCH_BRCMSTB || BMIPS_GENERIC
depends on MMC_SDHCI_PLTFM
default y
help
This selects support for the SDIO/SD/MMC Host Controller on
Broadcom STB SoCs.
If unsure, say Y.

View file

@ -71,11 +71,11 @@ obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o
obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o
obj-$(CONFIG_MMC_SDHCI_BCM2835) += sdhci-bcm2835.o
obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o
obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o
obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o
obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o
obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o
ifeq ($(CONFIG_CB710_DEBUG),y)
CFLAGS-cb710-mmc += -DDEBUG

View file

@ -157,7 +157,7 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
* HOLD register should be bypassed in case there is no phase shift
* applied on CMD/DATA that is sent to the card.
*/
if (!SDMMC_CLKSEL_GET_DRV_WD3(clksel))
if (!SDMMC_CLKSEL_GET_DRV_WD3(clksel) && host->cur_slot)
set_bit(DW_MMC_CARD_NO_USE_HOLD, &host->cur_slot->flags);
}

View file

@ -32,6 +32,12 @@ struct k3_priv {
struct regmap *reg;
};
static unsigned long dw_mci_hi6220_caps[] = {
MMC_CAP_CMD23,
MMC_CAP_CMD23,
0
};
static void dw_mci_k3_set_ios(struct dw_mci *host, struct mmc_ios *ios)
{
int ret;
@ -126,6 +132,7 @@ static void dw_mci_hi6220_set_ios(struct dw_mci *host, struct mmc_ios *ios)
}
static const struct dw_mci_drv_data hi6220_data = {
.caps = dw_mci_hi6220_caps,
.switch_voltage = dw_mci_hi6220_switch_voltage,
.set_ios = dw_mci_hi6220_set_ios,
.parse_dt = dw_mci_hi6220_parse_dt,

View file

@ -285,9 +285,6 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
/* It is slot 8 on Rockchip SoCs */
host->sdio_id0 = 8;
/* It needs this quirk on all Rockchip SoCs */
host->pdata->quirks |= DW_MCI_QUIRK_BROKEN_DTO;
if (of_device_is_compatible(host->dev->of_node,
"rockchip,rk3288-dw-mshc"))
host->bus_hz /= RK3288_CLKGEN_DIV;
@ -297,10 +294,10 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
/* Common capabilities of RK3288 SoC */
static unsigned long dw_mci_rk3288_dwmmc_caps[4] = {
MMC_CAP_ERASE | MMC_CAP_CMD23,
MMC_CAP_ERASE | MMC_CAP_CMD23,
MMC_CAP_ERASE | MMC_CAP_CMD23,
MMC_CAP_ERASE | MMC_CAP_CMD23,
MMC_CAP_CMD23,
MMC_CAP_CMD23,
MMC_CAP_CMD23,
MMC_CAP_CMD23,
};
static const struct dw_mci_drv_data rk2928_drv_data = {

View file

@ -44,11 +44,11 @@
/* Common flag combinations */
#define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DRTO | SDMMC_INT_DCRC | \
SDMMC_INT_HTO | SDMMC_INT_SBE | \
SDMMC_INT_EBE)
SDMMC_INT_EBE | SDMMC_INT_HLE)
#define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \
SDMMC_INT_RESP_ERR)
SDMMC_INT_RESP_ERR | SDMMC_INT_HLE)
#define DW_MCI_ERROR_FLAGS (DW_MCI_DATA_ERROR_FLAGS | \
DW_MCI_CMD_ERROR_FLAGS | SDMMC_INT_HLE)
DW_MCI_CMD_ERROR_FLAGS)
#define DW_MCI_SEND_STATUS 1
#define DW_MCI_RECV_STATUS 2
#define DW_MCI_DMA_THRESHOLD 16
@ -92,7 +92,7 @@ struct idmac_desc {
__le32 des1; /* Buffer sizes */
#define IDMAC_SET_BUFFER1_SIZE(d, s) \
((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff))
((d)->des1 = ((d)->des1 & cpu_to_le32(0x03ffe000)) | (cpu_to_le32((s) & 0x1fff)))
__le32 des2; /* buffer 1 physical address */
@ -105,6 +105,7 @@ struct idmac_desc {
static bool dw_mci_reset(struct dw_mci *host);
static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
static int dw_mci_card_busy(struct mmc_host *mmc);
static int dw_mci_get_cd(struct mmc_host *mmc);
#if defined(CONFIG_DEBUG_FS)
static int dw_mci_req_show(struct seq_file *s, void *v)
@ -898,23 +899,35 @@ done:
mci_writel(host, FIFOTH, fifoth_val);
}
static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data)
static void dw_mci_ctrl_thld(struct dw_mci *host, struct mmc_data *data)
{
unsigned int blksz = data->blksz;
u32 blksz_depth, fifo_depth;
u16 thld_size;
WARN_ON(!(data->flags & MMC_DATA_READ));
u8 enable;
/*
* CDTHRCTL doesn't exist prior to 240A (in fact that register offset is
* in the FIFO region, so we really shouldn't access it).
*/
if (host->verid < DW_MMC_240A)
if (host->verid < DW_MMC_240A ||
(host->verid < DW_MMC_280A && data->flags & MMC_DATA_WRITE))
return;
/*
* Card write Threshold is introduced since 2.80a
* It's used when HS400 mode is enabled.
*/
if (data->flags & MMC_DATA_WRITE &&
!(host->timing != MMC_TIMING_MMC_HS400))
return;
if (data->flags & MMC_DATA_WRITE)
enable = SDMMC_CARD_WR_THR_EN;
else
enable = SDMMC_CARD_RD_THR_EN;
if (host->timing != MMC_TIMING_MMC_HS200 &&
host->timing != MMC_TIMING_MMC_HS400 &&
host->timing != MMC_TIMING_UHS_SDR104)
goto disable;
@ -930,11 +943,11 @@ static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data)
* Currently just choose blksz.
*/
thld_size = blksz;
mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(thld_size, 1));
mci_writel(host, CDTHRCTL, SDMMC_SET_THLD(thld_size, enable));
return;
disable:
mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(0, 0));
mci_writel(host, CDTHRCTL, 0);
}
static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
@ -1005,12 +1018,12 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
host->sg = NULL;
host->data = data;
if (data->flags & MMC_DATA_READ) {
if (data->flags & MMC_DATA_READ)
host->dir_status = DW_MCI_RECV_STATUS;
dw_mci_ctrl_rd_thld(host, data);
} else {
else
host->dir_status = DW_MCI_SEND_STATUS;
}
dw_mci_ctrl_thld(host, data);
if (dw_mci_submit_data_dma(host, data)) {
if (host->data->flags & MMC_DATA_READ)
@ -1099,12 +1112,11 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0;
if ((clock << div) != slot->__clk_old || force_clkinit)
dev_info(&slot->mmc->class_dev,
"Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n",
slot->id, host->bus_hz, clock,
div ? ((host->bus_hz / div) >> 1) :
host->bus_hz, div);
dev_info(&slot->mmc->class_dev,
"Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n",
slot->id, host->bus_hz, clock,
div ? ((host->bus_hz / div) >> 1) :
host->bus_hz, div);
/* disable clock */
mci_writel(host, CLKENA, 0);
@ -1127,9 +1139,6 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
/* inform CIU */
mci_send_cmd(slot, sdmmc_cmd_bits, 0);
/* keep the clock with reflecting clock dividor */
slot->__clk_old = clock << div;
}
host->current_speed = clock;
@ -1253,15 +1262,15 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
* atomic, otherwise the card could be removed in between and the
* request wouldn't fail until another card was inserted.
*/
spin_lock_bh(&host->lock);
if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
spin_unlock_bh(&host->lock);
if (!dw_mci_get_cd(mmc)) {
mrq->cmd->error = -ENOMEDIUM;
mmc_request_done(mmc, mrq);
return;
}
spin_lock_bh(&host->lock);
dw_mci_queue_request(host, slot, mrq);
spin_unlock_bh(&host->lock);
@ -1451,8 +1460,7 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
int gpio_cd = mmc_gpio_get_cd(mmc);
/* Use platform get_cd function, else try onboard card detect */
if ((mmc->caps & MMC_CAP_NEEDS_POLL) ||
(mmc->caps & MMC_CAP_NONREMOVABLE))
if ((mmc->caps & MMC_CAP_NEEDS_POLL) || !mmc_card_is_removable(mmc))
present = 1;
else if (gpio_cd >= 0)
present = gpio_cd;
@ -1761,6 +1769,33 @@ static void dw_mci_tasklet_func(unsigned long priv)
}
if (cmd->data && err) {
/*
* During UHS tuning sequence, sending the stop
* command after the response CRC error would
* throw the system into a confused state
* causing all future tuning phases to report
* failure.
*
* In such case controller will move into a data
* transfer state after a response error or
* response CRC error. Let's let that finish
* before trying to send a stop, so we'll go to
* STATE_SENDING_DATA.
*
* Although letting the data transfer take place
* will waste a bit of time (we already know
* the command was bad), it can't cause any
* errors since it's possible it would have
* taken place anyway if this tasklet got
* delayed. Allowing the transfer to take place
* avoids races and keeps things simple.
*/
if ((err != -ETIMEDOUT) &&
(cmd->opcode == MMC_SEND_TUNING_BLOCK)) {
state = STATE_SENDING_DATA;
continue;
}
dw_mci_stop_dma(host);
send_stop_abort(host, data);
state = STATE_SENDING_STOP;
@ -1801,8 +1836,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
* If all data-related interrupts don't come
* within the given time in reading data state.
*/
if ((host->quirks & DW_MCI_QUIRK_BROKEN_DTO) &&
(host->dir_status == DW_MCI_RECV_STATUS))
if (host->dir_status == DW_MCI_RECV_STATUS)
dw_mci_set_drto(host);
break;
}
@ -1844,8 +1878,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
* interrupt doesn't come within the given time.
* in reading data state.
*/
if ((host->quirks & DW_MCI_QUIRK_BROKEN_DTO) &&
(host->dir_status == DW_MCI_RECV_STATUS))
if (host->dir_status == DW_MCI_RECV_STATUS)
dw_mci_set_drto(host);
break;
}
@ -2411,8 +2444,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
}
if (pending & SDMMC_INT_DATA_OVER) {
if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO)
del_timer(&host->dto_timer);
del_timer(&host->dto_timer);
mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
if (!host->data_status)
@ -2474,7 +2506,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI |
SDMMC_IDMAC_INT_RI);
mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI);
host->dma_ops->complete((void *)host);
if (!test_bit(EVENT_DATA_ERROR, &host->pending_events))
host->dma_ops->complete((void *)host);
}
} else {
pending = mci_readl(host, IDSTS);
@ -2482,7 +2515,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI |
SDMMC_IDMAC_INT_RI);
mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
host->dma_ops->complete((void *)host);
if (!test_bit(EVENT_DATA_ERROR, &host->pending_events))
host->dma_ops->complete((void *)host);
}
}
@ -2570,6 +2604,12 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
if (host->pdata->caps)
mmc->caps = host->pdata->caps;
/*
* Support MMC_CAP_ERASE by default.
* It needs to use trim/discard/erase commands.
*/
mmc->caps |= MMC_CAP_ERASE;
if (host->pdata->pm_caps)
mmc->pm_caps = host->pdata->pm_caps;
@ -2616,10 +2656,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
mmc->max_seg_size = mmc->max_req_size;
}
if (dw_mci_get_cd(mmc))
set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
else
clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
dw_mci_get_cd(mmc);
ret = mmc_add_host(mmc);
if (ret)
@ -3006,11 +3043,8 @@ int dw_mci_probe(struct dw_mci *host)
setup_timer(&host->cmd11_timer,
dw_mci_cmd11_timer, (unsigned long)host);
host->quirks = host->pdata->quirks;
if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO)
setup_timer(&host->dto_timer,
dw_mci_dto_timer, (unsigned long)host);
setup_timer(&host->dto_timer,
dw_mci_dto_timer, (unsigned long)host);
spin_lock_init(&host->lock);
spin_lock_init(&host->irq_lock);

View file

@ -15,6 +15,7 @@
#define _DW_MMC_H_
#define DW_MMC_240A 0x240a
#define DW_MMC_280A 0x280a
#define SDMMC_CTRL 0x000
#define SDMMC_PWREN 0x004
@ -175,7 +176,10 @@
/* Version ID register define */
#define SDMMC_GET_VERID(x) ((x) & 0xFFFF)
/* Card read threshold */
#define SDMMC_SET_RD_THLD(v, x) (((v) & 0xFFF) << 16 | (x))
#define SDMMC_SET_THLD(v, x) (((v) & 0xFFF) << 16 | (x))
#define SDMMC_CARD_WR_THR_EN BIT(2)
#define SDMMC_CARD_RD_THR_EN BIT(0)
/* UHS-1 register defines */
#define SDMMC_UHS_18V BIT(0)
/* All ctrl reset bits */
#define SDMMC_CTRL_ALL_RESET_FLAGS \
@ -245,9 +249,6 @@ extern int dw_mci_resume(struct dw_mci *host);
* @queue_node: List node for placing this node in the @queue list of
* &struct dw_mci.
* @clock: Clock rate configured by set_ios(). Protected by host->lock.
* @__clk_old: The last updated clock with reflecting clock divider.
* Keeping track of this helps us to avoid spamming the console
* with CONFIG_MMC_CLKGATE.
* @flags: Random state bits associated with the slot.
* @id: Number of this slot.
* @sdio_id: Number of this slot in the SDIO interrupt registers.
@ -262,7 +263,6 @@ struct dw_mci_slot {
struct list_head queue_node;
unsigned int clock;
unsigned int __clk_old;
unsigned long flags;
#define DW_MMC_CARD_PRESENT 0

View file

@ -287,6 +287,11 @@ struct msdc_save_para {
u32 emmc50_cfg0;
};
struct msdc_tune_para {
u32 iocon;
u32 pad_tune;
};
struct msdc_delay_phase {
u8 maxlen;
u8 start;
@ -326,7 +331,10 @@ struct msdc_host {
unsigned char timing;
bool vqmmc_enabled;
u32 hs400_ds_delay;
bool hs400_mode; /* current eMMC will run at hs400 mode */
struct msdc_save_para save_para; /* used when gate HCLK */
struct msdc_tune_para def_tune_para; /* default tune setting */
struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */
};
static void sdr_set_bits(void __iomem *reg, u32 bs)
@ -582,6 +590,18 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
msdc_set_timeout(host, host->timeout_ns, host->timeout_clks);
sdr_set_bits(host->base + MSDC_INTEN, flags);
/*
* mmc_select_hs400() will drop to 50Mhz and High speed mode,
* tune result of hs200/200Mhz is not suitable for 50Mhz
*/
if (host->sclk <= 52000000) {
writel(host->def_tune_para.iocon, host->base + MSDC_IOCON);
writel(host->def_tune_para.pad_tune, host->base + MSDC_PAD_TUNE);
} else {
writel(host->saved_tune_para.iocon, host->base + MSDC_IOCON);
writel(host->saved_tune_para.pad_tune, host->base + MSDC_PAD_TUNE);
}
dev_dbg(host->dev, "sclk: %d, timing: %d\n", host->sclk, timing);
}
@ -781,7 +801,13 @@ static bool msdc_cmd_done(struct msdc_host *host, int events,
}
if (!sbc_error && !(events & MSDC_INT_CMDRDY)) {
msdc_reset_hw(host);
if (cmd->opcode != MMC_SEND_TUNING_BLOCK &&
cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200)
/*
* should not clear fifo/interrupt as the tune data
* may have alreay come.
*/
msdc_reset_hw(host);
if (events & MSDC_INT_RSPCRCERR) {
cmd->error = -EILSEQ;
host->error |= REQ_CMD_EIO;
@ -865,7 +891,11 @@ static void msdc_start_command(struct msdc_host *host,
static void msdc_cmd_next(struct msdc_host *host,
struct mmc_request *mrq, struct mmc_command *cmd)
{
if (cmd->error || (mrq->sbc && mrq->sbc->error))
if ((cmd->error &&
!(cmd->error == -EILSEQ &&
(cmd->opcode == MMC_SEND_TUNING_BLOCK ||
cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200))) ||
(mrq->sbc && mrq->sbc->error))
msdc_request_done(host, mrq);
else if (cmd == mrq->sbc)
msdc_start_command(host, mrq, mrq->cmd);
@ -1158,6 +1188,8 @@ static void msdc_init_hw(struct msdc_host *host)
/* Configure to default data timeout */
sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3);
host->def_tune_para.iocon = readl(host->base + MSDC_IOCON);
host->def_tune_para.pad_tune = readl(host->base + MSDC_PAD_TUNE);
dev_dbg(host->dev, "init hardware done!");
}
@ -1296,7 +1328,7 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
{
struct msdc_host *host = mmc_priv(mmc);
u32 rise_delay = 0, fall_delay = 0;
struct msdc_delay_phase final_rise_delay, final_fall_delay;
struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,};
u8 final_delay, final_maxlen;
int cmd_err;
int i;
@ -1309,6 +1341,11 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
if (!cmd_err)
rise_delay |= (1 << i);
}
final_rise_delay = get_best_delay(host, rise_delay);
/* if rising edge has enough margin, then do not scan falling edge */
if (final_rise_delay.maxlen >= 10 ||
(final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
goto skip_fall;
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
for (i = 0; i < PAD_DELAY_MAX; i++) {
@ -1318,10 +1355,9 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
if (!cmd_err)
fall_delay |= (1 << i);
}
final_rise_delay = get_best_delay(host, rise_delay);
final_fall_delay = get_best_delay(host, fall_delay);
skip_fall:
final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
if (final_maxlen == final_rise_delay.maxlen) {
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
@ -1342,7 +1378,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
{
struct msdc_host *host = mmc_priv(mmc);
u32 rise_delay = 0, fall_delay = 0;
struct msdc_delay_phase final_rise_delay, final_fall_delay;
struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,};
u8 final_delay, final_maxlen;
int i, ret;
@ -1355,6 +1391,11 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
if (!ret)
rise_delay |= (1 << i);
}
final_rise_delay = get_best_delay(host, rise_delay);
/* if rising edge has enough margin, then do not scan falling edge */
if (final_rise_delay.maxlen >= 10 ||
(final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
goto skip_fall;
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
@ -1365,14 +1406,10 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
if (!ret)
fall_delay |= (1 << i);
}
final_rise_delay = get_best_delay(host, rise_delay);
final_fall_delay = get_best_delay(host, fall_delay);
skip_fall:
final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
/* Rising edge is more stable, prefer to use it */
if (final_rise_delay.maxlen >= 10)
final_maxlen = final_rise_delay.maxlen;
if (final_maxlen == final_rise_delay.maxlen) {
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
@ -1402,16 +1439,21 @@ static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode)
dev_err(host->dev, "Tune response fail!\n");
return ret;
}
ret = msdc_tune_data(mmc, opcode);
if (ret == -EIO)
dev_err(host->dev, "Tune data fail!\n");
if (host->hs400_mode == false) {
ret = msdc_tune_data(mmc, opcode);
if (ret == -EIO)
dev_err(host->dev, "Tune data fail!\n");
}
host->saved_tune_para.iocon = readl(host->base + MSDC_IOCON);
host->saved_tune_para.pad_tune = readl(host->base + MSDC_PAD_TUNE);
return ret;
}
static int msdc_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct msdc_host *host = mmc_priv(mmc);
host->hs400_mode = true;
writel(host->hs400_ds_delay, host->base + PAD_DS_TUNE);
return 0;

View file

@ -1065,7 +1065,7 @@ static int mxcmci_probe(struct platform_device *pdev)
if (pdata)
dat3_card_detect = pdata->dat3_card_detect;
else if (!(mmc->caps & MMC_CAP_NONREMOVABLE)
else if (mmc_card_is_removable(mmc)
&& !of_property_read_bool(pdev->dev.of_node, "cd-gpios"))
dat3_card_detect = true;

View file

@ -38,7 +38,6 @@ struct realtek_pci_sdmmc {
struct rtsx_pcr *pcr;
struct mmc_host *mmc;
struct mmc_request *mrq;
struct workqueue_struct *workq;
#define SDMMC_WORKQ_NAME "rtsx_pci_sdmmc_workq"
struct work_struct work;
@ -244,7 +243,7 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
stat_idx = sd_status_index(rsp_type);
if (rsp_type == SD_RSP_TYPE_R1b)
timeout = 3000;
timeout = cmd->busy_timeout ? cmd->busy_timeout : 3000;
if (cmd->opcode == SD_SWITCH_VOLTAGE) {
err = rtsx_pci_write_register(pcr, SD_BUS_STAT,
@ -885,7 +884,7 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
if (sd_rw_cmd(mrq->cmd) || sdio_extblock_cmd(mrq->cmd, data))
host->using_cookie = sd_pre_dma_transfer(host, data, false);
queue_work(host->workq, &host->work);
schedule_work(&host->work);
}
static int sd_set_bus_width(struct realtek_pci_sdmmc *host,
@ -1360,7 +1359,7 @@ static void realtek_init_host(struct realtek_pci_sdmmc *host)
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED |
MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST |
MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_ERASE;
mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE;
mmc->max_current_330 = 400;
mmc->max_current_180 = 800;
@ -1404,11 +1403,6 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
return -ENOMEM;
host = mmc_priv(mmc);
host->workq = create_singlethread_workqueue(SDMMC_WORKQ_NAME);
if (!host->workq) {
mmc_free_host(mmc);
return -ENOMEM;
}
host->pcr = pcr;
host->mmc = mmc;
host->pdev = pdev;
@ -1462,9 +1456,7 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
mmc_remove_host(mmc);
host->eject = true;
flush_workqueue(host->workq);
destroy_workqueue(host->workq);
host->workq = NULL;
flush_work(&host->work);
mmc_free_host(mmc);

View file

@ -1365,7 +1365,7 @@ static struct s3c24xx_mci_pdata s3cmci_def_pdata = {
.no_detect = 1,
};
#ifdef CONFIG_CPU_FREQ
#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
static int s3cmci_cpufreq_transition(struct notifier_block *nb,
unsigned long val, void *data)

View file

@ -74,7 +74,7 @@ struct s3cmci_host {
struct dentry *debug_regs;
#endif
#ifdef CONFIG_CPU_FREQ
#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
struct notifier_block freq_transition;
#endif
};

View file

@ -532,11 +532,6 @@ static int sdhci_acpi_resume(struct device *dev)
return sdhci_resume_host(c->host);
}
#else
#define sdhci_acpi_suspend NULL
#define sdhci_acpi_resume NULL
#endif
#ifdef CONFIG_PM
@ -560,8 +555,7 @@ static int sdhci_acpi_runtime_resume(struct device *dev)
#endif
static const struct dev_pm_ops sdhci_acpi_pm_ops = {
.suspend = sdhci_acpi_suspend,
.resume = sdhci_acpi_resume,
SET_SYSTEM_SLEEP_PM_OPS(sdhci_acpi_suspend, sdhci_acpi_resume)
SET_RUNTIME_PM_OPS(sdhci_acpi_runtime_suspend,
sdhci_acpi_runtime_resume, NULL)
};

View file

@ -264,12 +264,12 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
}
dev_dbg(dev, "non-removable=%c\n",
(host->mmc->caps & MMC_CAP_NONREMOVABLE) ? 'Y' : 'N');
mmc_card_is_removable(host->mmc) ? 'N' : 'Y');
dev_dbg(dev, "cd_gpio %c, wp_gpio %c\n",
(mmc_gpio_get_cd(host->mmc) != -ENOSYS) ? 'Y' : 'N',
(mmc_gpio_get_ro(host->mmc) != -ENOSYS) ? 'Y' : 'N');
if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
if (!mmc_card_is_removable(host->mmc))
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
dev_dbg(dev, "is_8bit=%c\n",
@ -288,7 +288,7 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
}
/* if device is eMMC, emulate card insert right here */
if (host->mmc->caps & MMC_CAP_NONREMOVABLE) {
if (!mmc_card_is_removable(host->mmc)) {
ret = sdhci_bcm_kona_sd_card_emulate(host, 1);
if (ret) {
dev_err(dev,
@ -326,7 +326,7 @@ err_pltfm_free:
static struct platform_driver sdhci_bcm_kona_driver = {
.driver = {
.name = "sdhci-kona",
.pm = SDHCI_PLTFM_PMOPS,
.pm = &sdhci_pltfm_pmops,
.of_match_table = sdhci_bcm_kona_of_match,
},
.probe = sdhci_bcm_kona_probe,

View file

@ -1,204 +0,0 @@
/*
* BCM2835 SDHCI
* Copyright (C) 2012 Stephen Warren
* Based on U-Boot's MMC driver for the BCM2835 by Oleksandr Tymoshenko & me
* Portions of the code there were obviously based on the Linux kernel at:
* git://github.com/raspberrypi/linux.git rpi-3.6.y
* commit f5b930b "Main bcm2708 linux port" signed-off-by Dom Cobley.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/mmc/host.h>
#include "sdhci-pltfm.h"
/*
* 400KHz is max freq for card ID etc. Use that as min card clock. We need to
* know the min to enable static calculation of max BCM2835_SDHCI_WRITE_DELAY.
*/
#define MIN_FREQ 400000
/*
* The Arasan has a bugette whereby it may lose the content of successive
* writes to registers that are within two SD-card clock cycles of each other
* (a clock domain crossing problem). It seems, however, that the data
* register does not have this problem, which is just as well - otherwise we'd
* have to nobble the DMA engine too.
*
* This should probably be dynamically calculated based on the actual card
* frequency. However, this is the longest we'll have to wait, and doesn't
* seem to slow access down too much, so the added complexity doesn't seem
* worth it for now.
*
* 1/MIN_FREQ is (max) time per tick of eMMC clock.
* 2/MIN_FREQ is time for two ticks.
* Multiply by 1000000 to get uS per two ticks.
* *1000000 for uSecs.
* +1 for hack rounding.
*/
#define BCM2835_SDHCI_WRITE_DELAY (((2 * 1000000) / MIN_FREQ) + 1)
struct bcm2835_sdhci {
u32 shadow;
};
static void bcm2835_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
{
writel(val, host->ioaddr + reg);
udelay(BCM2835_SDHCI_WRITE_DELAY);
}
static inline u32 bcm2835_sdhci_readl(struct sdhci_host *host, int reg)
{
u32 val = readl(host->ioaddr + reg);
if (reg == SDHCI_CAPABILITIES)
val |= SDHCI_CAN_VDD_330;
return val;
}
static void bcm2835_sdhci_writew(struct sdhci_host *host, u16 val, int reg)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct bcm2835_sdhci *bcm2835_host = sdhci_pltfm_priv(pltfm_host);
u32 oldval = (reg == SDHCI_COMMAND) ? bcm2835_host->shadow :
bcm2835_sdhci_readl(host, reg & ~3);
u32 word_num = (reg >> 1) & 1;
u32 word_shift = word_num * 16;
u32 mask = 0xffff << word_shift;
u32 newval = (oldval & ~mask) | (val << word_shift);
if (reg == SDHCI_TRANSFER_MODE)
bcm2835_host->shadow = newval;
else
bcm2835_sdhci_writel(host, newval, reg & ~3);
}
static u16 bcm2835_sdhci_readw(struct sdhci_host *host, int reg)
{
u32 val = bcm2835_sdhci_readl(host, (reg & ~3));
u32 word_num = (reg >> 1) & 1;
u32 word_shift = word_num * 16;
u32 word = (val >> word_shift) & 0xffff;
return word;
}
static void bcm2835_sdhci_writeb(struct sdhci_host *host, u8 val, int reg)
{
u32 oldval = bcm2835_sdhci_readl(host, reg & ~3);
u32 byte_num = reg & 3;
u32 byte_shift = byte_num * 8;
u32 mask = 0xff << byte_shift;
u32 newval = (oldval & ~mask) | (val << byte_shift);
bcm2835_sdhci_writel(host, newval, reg & ~3);
}
static u8 bcm2835_sdhci_readb(struct sdhci_host *host, int reg)
{
u32 val = bcm2835_sdhci_readl(host, (reg & ~3));
u32 byte_num = reg & 3;
u32 byte_shift = byte_num * 8;
u32 byte = (val >> byte_shift) & 0xff;
return byte;
}
static unsigned int bcm2835_sdhci_get_min_clock(struct sdhci_host *host)
{
return MIN_FREQ;
}
static const struct sdhci_ops bcm2835_sdhci_ops = {
.write_l = bcm2835_sdhci_writel,
.write_w = bcm2835_sdhci_writew,
.write_b = bcm2835_sdhci_writeb,
.read_l = bcm2835_sdhci_readl,
.read_w = bcm2835_sdhci_readw,
.read_b = bcm2835_sdhci_readb,
.set_clock = sdhci_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_min_clock = bcm2835_sdhci_get_min_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
static const struct sdhci_pltfm_data bcm2835_sdhci_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
.ops = &bcm2835_sdhci_ops,
};
static int bcm2835_sdhci_probe(struct platform_device *pdev)
{
struct sdhci_host *host;
struct bcm2835_sdhci *bcm2835_host;
struct sdhci_pltfm_host *pltfm_host;
int ret;
host = sdhci_pltfm_init(pdev, &bcm2835_sdhci_pdata,
sizeof(*bcm2835_host));
if (IS_ERR(host))
return PTR_ERR(host);
pltfm_host = sdhci_priv(host);
pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(pltfm_host->clk)) {
ret = PTR_ERR(pltfm_host->clk);
goto err;
}
ret = clk_prepare_enable(pltfm_host->clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable host clk\n");
goto err;
}
ret = sdhci_add_host(host);
if (ret)
goto err_clk;
return 0;
err_clk:
clk_disable_unprepare(pltfm_host->clk);
err:
sdhci_pltfm_free(pdev);
return ret;
}
static const struct of_device_id bcm2835_sdhci_of_match[] = {
{ .compatible = "brcm,bcm2835-sdhci" },
{ }
};
MODULE_DEVICE_TABLE(of, bcm2835_sdhci_of_match);
static struct platform_driver bcm2835_sdhci_driver = {
.driver = {
.name = "sdhci-bcm2835",
.of_match_table = bcm2835_sdhci_of_match,
.pm = SDHCI_PLTFM_PMOPS,
},
.probe = bcm2835_sdhci_probe,
.remove = sdhci_pltfm_unregister,
};
module_platform_driver(bcm2835_sdhci_driver);
MODULE_DESCRIPTION("BCM2835 SDHCI driver");
MODULE_AUTHOR("Stephen Warren");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,143 @@
/*
* sdhci-brcmstb.c Support for SDHCI on Broadcom BRCMSTB SoC's
*
* Copyright (C) 2015 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/io.h>
#include <linux/mmc/host.h>
#include <linux/module.h>
#include <linux/of.h>
#include "sdhci-pltfm.h"
#ifdef CONFIG_PM_SLEEP
static int sdhci_brcmstb_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
int res;
res = sdhci_suspend_host(host);
if (res)
return res;
clk_disable_unprepare(pltfm_host->clk);
return res;
}
static int sdhci_brcmstb_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
int err;
err = clk_prepare_enable(pltfm_host->clk);
if (err)
return err;
return sdhci_resume_host(host);
}
#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(sdhci_brcmstb_pmops, sdhci_brcmstb_suspend,
sdhci_brcmstb_resume);
static const struct sdhci_ops sdhci_brcmstb_ops = {
.set_clock = sdhci_set_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
static struct sdhci_pltfm_data sdhci_brcmstb_pdata = {
.ops = &sdhci_brcmstb_ops,
};
static int sdhci_brcmstb_probe(struct platform_device *pdev)
{
struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host;
struct clk *clk;
int res;
clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "Clock not found in Device Tree\n");
clk = NULL;
}
res = clk_prepare_enable(clk);
if (res)
return res;
host = sdhci_pltfm_init(pdev, &sdhci_brcmstb_pdata, 0);
if (IS_ERR(host)) {
res = PTR_ERR(host);
goto err_clk;
}
/* Enable MMC_CAP2_HC_ERASE_SZ for better max discard calculations */
host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
sdhci_get_of_property(pdev);
mmc_of_parse(host->mmc);
/*
* Supply the existing CAPS, but clear the UHS modes. This
* will allow these modes to be specified by device tree
* properties through mmc_of_parse().
*/
host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
SDHCI_SUPPORT_DDR50);
host->quirks |= SDHCI_QUIRK_MISSING_CAPS |
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
res = sdhci_add_host(host);
if (res)
goto err;
pltfm_host = sdhci_priv(host);
pltfm_host->clk = clk;
return res;
err:
sdhci_pltfm_free(pdev);
err_clk:
clk_disable_unprepare(clk);
return res;
}
static const struct of_device_id sdhci_brcm_of_match[] = {
{ .compatible = "brcm,bcm7425-sdhci" },
{},
};
MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match);
static struct platform_driver sdhci_brcmstb_driver = {
.driver = {
.name = "sdhci-brcmstb",
.owner = THIS_MODULE,
.pm = &sdhci_brcmstb_pmops,
.of_match_table = of_match_ptr(sdhci_brcm_of_match),
},
.probe = sdhci_brcmstb_probe,
.remove = sdhci_pltfm_unregister,
};
module_platform_driver(sdhci_brcmstb_driver);
MODULE_DESCRIPTION("SDHCI driver for Broadcom BRCMSTB SoCs");
MODULE_AUTHOR("Broadcom");
MODULE_LICENSE("GPL v2");

View file

@ -101,7 +101,7 @@ static int sdhci_cns3xxx_probe(struct platform_device *pdev)
static struct platform_driver sdhci_cns3xxx_driver = {
.driver = {
.name = "sdhci-cns3xxx",
.pm = SDHCI_PLTFM_PMOPS,
.pm = &sdhci_pltfm_pmops,
},
.probe = sdhci_cns3xxx_probe,
.remove = sdhci_pltfm_unregister,

View file

@ -117,7 +117,7 @@ MODULE_DEVICE_TABLE(of, sdhci_dove_of_match_table);
static struct platform_driver sdhci_dove_driver = {
.driver = {
.name = "sdhci-dove",
.pm = SDHCI_PLTFM_PMOPS,
.pm = &sdhci_pltfm_pmops,
.of_match_table = sdhci_dove_of_match_table,
},
.probe = sdhci_dove_probe,

View file

@ -39,11 +39,13 @@
#define ESDHC_VENDOR_SPEC_VSELECT (1 << 1)
#define ESDHC_VENDOR_SPEC_FRC_SDCLK_ON (1 << 8)
#define ESDHC_WTMK_LVL 0x44
#define ESDHC_WTMK_DEFAULT_VAL 0x10401040
#define ESDHC_MIX_CTRL 0x48
#define ESDHC_MIX_CTRL_DDREN (1 << 3)
#define ESDHC_MIX_CTRL_AC23EN (1 << 7)
#define ESDHC_MIX_CTRL_EXE_TUNE (1 << 22)
#define ESDHC_MIX_CTRL_SMPCLK_SEL (1 << 23)
#define ESDHC_MIX_CTRL_AUTO_TUNE_EN (1 << 24)
#define ESDHC_MIX_CTRL_FBCLK_SEL (1 << 25)
#define ESDHC_MIX_CTRL_HS400_EN (1 << 26)
/* Bits 3 and 6 are not SDHCI standard definitions */
@ -75,7 +77,8 @@
#define ESDHC_TUNING_CTRL 0xcc
#define ESDHC_STD_TUNING_EN (1 << 24)
/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
#define ESDHC_TUNING_START_TAP 0x1
#define ESDHC_TUNING_START_TAP_DEFAULT 0x1
#define ESDHC_TUNING_START_TAP_MASK 0xff
#define ESDHC_TUNING_STEP_MASK 0x00070000
#define ESDHC_TUNING_STEP_SHIFT 16
@ -299,7 +302,8 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
/* imx6q/dl does not have cap_1 register, fake one */
val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
| SDHCI_SUPPORT_SDR50
| SDHCI_USE_SDR50_TUNING;
| SDHCI_USE_SDR50_TUNING
| (SDHCI_TUNING_MODE_3 << SDHCI_RETUNING_MODE_SHIFT);
if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
val |= SDHCI_SUPPORT_HS400;
@ -469,32 +473,29 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
new_val = readl(host->ioaddr + ESDHC_MIX_CTRL);
if (val & SDHCI_CTRL_TUNED_CLK)
if (val & SDHCI_CTRL_TUNED_CLK) {
new_val |= ESDHC_MIX_CTRL_SMPCLK_SEL;
else
new_val |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
} else {
new_val &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
new_val &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN;
}
writel(new_val , host->ioaddr + ESDHC_MIX_CTRL);
} else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR);
u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
u32 tuning_ctrl;
if (val & SDHCI_CTRL_TUNED_CLK) {
v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
} else {
v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
m &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN;
}
if (val & SDHCI_CTRL_EXEC_TUNING) {
v |= ESDHC_MIX_CTRL_EXE_TUNE;
m |= ESDHC_MIX_CTRL_FBCLK_SEL;
tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL);
tuning_ctrl |= ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP;
if (imx_data->boarddata.tuning_step) {
tuning_ctrl &= ~ESDHC_TUNING_STEP_MASK;
tuning_ctrl |= imx_data->boarddata.tuning_step << ESDHC_TUNING_STEP_SHIFT;
}
writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL);
m |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
} else {
v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
}
@ -751,6 +752,7 @@ static void esdhc_post_tuning(struct sdhci_host *host)
reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
reg &= ~ESDHC_MIX_CTRL_EXE_TUNE;
reg |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
}
@ -838,6 +840,11 @@ static void esdhc_set_strobe_dll(struct sdhci_host *host)
u32 v;
if (host->mmc->actual_clock > ESDHC_STROBE_DLL_CLK_FREQ) {
/* disable clock before enabling strobe dll */
writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) &
~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
host->ioaddr + ESDHC_VENDOR_SPEC);
/* force a reset on strobe dll */
writel(ESDHC_STROBE_DLL_CTRL_RESET,
host->ioaddr + ESDHC_STROBE_DLL_CTRL);
@ -899,6 +906,8 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN;
writel(m, host->ioaddr + ESDHC_MIX_CTRL);
imx_data->is_ddr = 1;
/* update clock after enable DDR for strobe DLL lock */
host->ops->set_clock(host, host->clock);
esdhc_set_strobe_dll(host);
break;
}
@ -957,6 +966,62 @@ static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
.ops = &sdhci_esdhc_ops,
};
static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
int tmp;
if (esdhc_is_usdhc(imx_data)) {
/*
* The imx6q ROM code will change the default watermark
* level setting to something insane. Change it back here.
*/
writel(ESDHC_WTMK_DEFAULT_VAL, host->ioaddr + ESDHC_WTMK_LVL);
/*
* ROM code will change the bit burst_length_enable setting
* to zero if this usdhc is choosed to boot system. Change
* it back here, otherwise it will impact the performance a
* lot. This bit is used to enable/disable the burst length
* for the external AHB2AXI bridge, it's usefully especially
* for INCR transfer because without burst length indicator,
* the AHB2AXI bridge does not know the burst length in
* advance. And without burst length indicator, AHB INCR
* transfer can only be converted to singles on the AXI side.
*/
writel(readl(host->ioaddr + SDHCI_HOST_CONTROL)
| ESDHC_BURST_LEN_EN_INCR,
host->ioaddr + SDHCI_HOST_CONTROL);
/*
* errata ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL
* TO1.1, it's harmless for MX6SL
*/
writel(readl(host->ioaddr + 0x6c) | BIT(7),
host->ioaddr + 0x6c);
/* disable DLL_CTRL delay line settings */
writel(0x0, host->ioaddr + ESDHC_DLL_CTRL);
if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL);
tmp |= ESDHC_STD_TUNING_EN |
ESDHC_TUNING_START_TAP_DEFAULT;
if (imx_data->boarddata.tuning_start_tap) {
tmp &= ~ESDHC_TUNING_START_TAP_MASK;
tmp |= imx_data->boarddata.tuning_start_tap;
}
if (imx_data->boarddata.tuning_step) {
tmp &= ~ESDHC_TUNING_STEP_MASK;
tmp |= imx_data->boarddata.tuning_step
<< ESDHC_TUNING_STEP_SHIFT;
}
writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL);
}
}
}
#ifdef CONFIG_OF
static int
sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
@ -975,6 +1040,8 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
boarddata->wp_type = ESDHC_WP_GPIO;
of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step);
of_property_read_u32(np, "fsl,tuning-start-tap",
&boarddata->tuning_start_tap);
if (of_find_property(np, "no-1-8-v", NULL))
boarddata->support_vsel = false;
@ -1147,58 +1214,27 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
if (IS_ERR(imx_data->pins_default))
dev_warn(mmc_dev(host->mmc), "could not get default state\n");
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
if (imx_data->socdata->flags & ESDHC_FLAG_ENGCM07207)
/* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK
| SDHCI_QUIRK_BROKEN_ADMA;
/*
* The imx6q ROM code will change the default watermark level setting
* to something insane. Change it back here.
*/
if (esdhc_is_usdhc(imx_data)) {
writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL);
host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
host->mmc->caps |= MMC_CAP_1_8V_DDR;
/*
* ROM code will change the bit burst_length_enable setting
* to zero if this usdhc is choosed to boot system. Change
* it back here, otherwise it will impact the performance a
* lot. This bit is used to enable/disable the burst length
* for the external AHB2AXI bridge, it's usefully especially
* for INCR transfer because without burst length indicator,
* the AHB2AXI bridge does not know the burst length in
* advance. And without burst length indicator, AHB INCR
* transfer can only be converted to singles on the AXI side.
*/
writel(readl(host->ioaddr + SDHCI_HOST_CONTROL)
| ESDHC_BURST_LEN_EN_INCR,
host->ioaddr + SDHCI_HOST_CONTROL);
if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200))
host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
/*
* errata ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL
* TO1.1, it's harmless for MX6SL
*/
writel(readl(host->ioaddr + 0x6c) | BIT(7),
host->ioaddr + 0x6c);
/* clear tuning bits in case ROM has set it already */
writel(0x0, host->ioaddr + ESDHC_MIX_CTRL);
writel(0x0, host->ioaddr + SDHCI_ACMD12_ERR);
writel(0x0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
}
if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING)
sdhci_esdhc_ops.platform_execute_tuning =
esdhc_executing_tuning;
if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING)
writel(readl(host->ioaddr + ESDHC_TUNING_CTRL) |
ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP,
host->ioaddr + ESDHC_TUNING_CTRL);
if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536)
host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
@ -1212,6 +1248,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
if (err)
goto disable_clk;
sdhci_esdhc_imx_hwinit(host);
err = sdhci_add_host(host);
if (err)
goto disable_clk;
@ -1255,6 +1293,25 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int sdhci_esdhc_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
return sdhci_suspend_host(host);
}
static int sdhci_esdhc_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
/* re-initialize hw state in case it's lost in low power mode */
sdhci_esdhc_imx_hwinit(host);
return sdhci_resume_host(host);
}
#endif
#ifdef CONFIG_PM
static int sdhci_esdhc_runtime_suspend(struct device *dev)
{
@ -1291,7 +1348,7 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
#endif
static const struct dev_pm_ops sdhci_esdhc_pmops = {
SET_SYSTEM_SLEEP_PM_OPS(sdhci_pltfm_suspend, sdhci_pltfm_resume)
SET_SYSTEM_SLEEP_PM_OPS(sdhci_esdhc_suspend, sdhci_esdhc_resume)
SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
sdhci_esdhc_runtime_resume, NULL)
};

View file

@ -164,8 +164,17 @@ static const struct sdhci_pltfm_data sdhci_iproc_pltfm_data = {
static const struct sdhci_iproc_data iproc_data = {
.pdata = &sdhci_iproc_pltfm_data,
.caps = 0x05E90000,
.caps1 = 0x00000064,
.caps = ((0x1 << SDHCI_MAX_BLOCK_SHIFT)
& SDHCI_MAX_BLOCK_MASK) |
SDHCI_CAN_VDD_330 |
SDHCI_CAN_VDD_180 |
SDHCI_CAN_DO_SUSPEND |
SDHCI_CAN_DO_HISPD |
SDHCI_CAN_DO_ADMA2 |
SDHCI_CAN_DO_SDMA,
.caps1 = SDHCI_DRIVER_TYPE_C |
SDHCI_DRIVER_TYPE_D |
SDHCI_SUPPORT_DDR50,
.mmc_caps = MMC_CAP_1_8V_DDR,
};
@ -251,7 +260,7 @@ static struct platform_driver sdhci_iproc_driver = {
.driver = {
.name = "sdhci-iproc",
.of_match_table = sdhci_iproc_of_match,
.pm = SDHCI_PLTFM_PMOPS,
.pm = &sdhci_pltfm_pmops,
},
.probe = sdhci_iproc_probe,
.remove = sdhci_pltfm_unregister,

View file

@ -32,6 +32,21 @@
#define CORE_POWER 0x0
#define CORE_SW_RST BIT(7)
#define CORE_PWRCTL_STATUS 0xdc
#define CORE_PWRCTL_MASK 0xe0
#define CORE_PWRCTL_CLEAR 0xe4
#define CORE_PWRCTL_CTL 0xe8
#define CORE_PWRCTL_BUS_OFF BIT(0)
#define CORE_PWRCTL_BUS_ON BIT(1)
#define CORE_PWRCTL_IO_LOW BIT(2)
#define CORE_PWRCTL_IO_HIGH BIT(3)
#define CORE_PWRCTL_BUS_SUCCESS BIT(0)
#define CORE_PWRCTL_IO_SUCCESS BIT(2)
#define REQ_BUS_OFF BIT(0)
#define REQ_BUS_ON BIT(1)
#define REQ_IO_LOW BIT(2)
#define REQ_IO_HIGH BIT(3)
#define INT_MASK 0xf
#define MAX_PHASES 16
#define CORE_DLL_LOCK BIT(7)
#define CORE_DLL_EN BIT(16)
@ -56,6 +71,7 @@
struct sdhci_msm_host {
struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
int pwr_irq; /* power irq */
struct clk *clk; /* main SD/MMC bus clock */
struct clk *pclk; /* SDHC peripheral bus clock */
struct clk *bus_clk; /* SDHC bus voter clock */
@ -410,6 +426,85 @@ retry:
return rc;
}
static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
unsigned int uhs)
{
struct mmc_host *mmc = host->mmc;
u16 ctrl_2;
ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
/* Select Bus Speed Mode for host */
ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
switch (uhs) {
case MMC_TIMING_UHS_SDR12:
ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
break;
case MMC_TIMING_UHS_SDR25:
ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
break;
case MMC_TIMING_UHS_SDR50:
ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
break;
case MMC_TIMING_MMC_HS200:
case MMC_TIMING_UHS_SDR104:
ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
break;
case MMC_TIMING_UHS_DDR50:
case MMC_TIMING_MMC_DDR52:
ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
break;
}
/*
* When clock frequency is less than 100MHz, the feedback clock must be
* provided and DLL must not be used so that tuning can be skipped. To
* provide feedback clock, the mode selection can be any value less
* than 3'b011 in bits [2:0] of HOST CONTROL2 register.
*/
if (host->clock <= 100000000 &&
(uhs == MMC_TIMING_MMC_HS400 ||
uhs == MMC_TIMING_MMC_HS200 ||
uhs == MMC_TIMING_UHS_SDR104))
ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n",
mmc_hostname(host->mmc), host->clock, uhs, ctrl_2);
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
}
static void sdhci_msm_voltage_switch(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
u32 irq_status, irq_ack = 0;
irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
irq_status &= INT_MASK;
writel_relaxed(irq_status, msm_host->core_mem + CORE_PWRCTL_CLEAR);
if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF))
irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
if (irq_status & (CORE_PWRCTL_IO_LOW | CORE_PWRCTL_IO_HIGH))
irq_ack |= CORE_PWRCTL_IO_SUCCESS;
/*
* The driver has to acknowledge the interrupt, switch voltages and
* report back if it succeded or not to this register. The voltage
* switches are handled by the sdhci core, so just report success.
*/
writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL);
}
static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
{
struct sdhci_host *host = (struct sdhci_host *)data;
sdhci_msm_voltage_switch(host);
return IRQ_HANDLED;
}
static const struct of_device_id sdhci_msm_dt_match[] = {
{ .compatible = "qcom,sdhci-msm-v4" },
{},
@ -422,11 +517,13 @@ static const struct sdhci_ops sdhci_msm_ops = {
.reset = sdhci_reset,
.set_clock = sdhci_set_clock,
.set_bus_width = sdhci_set_bus_width,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
.voltage_switch = sdhci_msm_voltage_switch,
};
static const struct sdhci_pltfm_data sdhci_msm_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
SDHCI_QUIRK_NO_CARD_NO_RESET |
SDHCI_QUIRK_SINGLE_POWER_WRITE,
.ops = &sdhci_msm_ops,
};
@ -473,7 +570,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
msm_host->pclk = devm_clk_get(&pdev->dev, "iface");
if (IS_ERR(msm_host->pclk)) {
ret = PTR_ERR(msm_host->pclk);
dev_err(&pdev->dev, "Perpheral clk setup failed (%d)\n", ret);
dev_err(&pdev->dev, "Peripheral clk setup failed (%d)\n", ret);
goto bus_clk_disable;
}
@ -545,6 +642,22 @@ static int sdhci_msm_probe(struct platform_device *pdev)
CORE_VENDOR_SPEC_CAPABILITIES0);
}
/* Setup IRQ for handling power/voltage tasks with PMIC */
msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
if (msm_host->pwr_irq < 0) {
dev_err(&pdev->dev, "Get pwr_irq failed (%d)\n",
msm_host->pwr_irq);
goto clk_disable;
}
ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
sdhci_msm_pwr_irq, IRQF_ONESHOT,
dev_name(&pdev->dev), host);
if (ret) {
dev_err(&pdev->dev, "Request IRQ failed (%d)\n", ret);
goto clk_disable;
}
ret = sdhci_add_host(host);
if (ret)
goto clk_disable;

View file

@ -19,27 +19,136 @@
* your option) any later version.
*/
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/regmap.h>
#include "sdhci-pltfm.h"
#define SDHCI_ARASAN_CLK_CTRL_OFFSET 0x2c
#define SDHCI_ARASAN_VENDOR_REGISTER 0x78
#define VENDOR_ENHANCED_STROBE BIT(0)
#define CLK_CTRL_TIMEOUT_SHIFT 16
#define CLK_CTRL_TIMEOUT_MASK (0xf << CLK_CTRL_TIMEOUT_SHIFT)
#define CLK_CTRL_TIMEOUT_MIN_EXP 13
/*
* On some SoCs the syscon area has a feature where the upper 16-bits of
* each 32-bit register act as a write mask for the lower 16-bits. This allows
* atomic updates of the register without locking. This macro is used on SoCs
* that have that feature.
*/
#define HIWORD_UPDATE(val, mask, shift) \
((val) << (shift) | (mask) << ((shift) + 16))
/**
* struct sdhci_arasan_soc_ctl_field - Field used in sdhci_arasan_soc_ctl_map
*
* @reg: Offset within the syscon of the register containing this field
* @width: Number of bits for this field
* @shift: Bit offset within @reg of this field (or -1 if not avail)
*/
struct sdhci_arasan_soc_ctl_field {
u32 reg;
u16 width;
s16 shift;
};
/**
* struct sdhci_arasan_soc_ctl_map - Map in syscon to corecfg registers
*
* It's up to the licensee of the Arsan IP block to make these available
* somewhere if needed. Presumably these will be scattered somewhere that's
* accessible via the syscon API.
*
* @baseclkfreq: Where to find corecfg_baseclkfreq
* @hiword_update: If true, use HIWORD_UPDATE to access the syscon
*/
struct sdhci_arasan_soc_ctl_map {
struct sdhci_arasan_soc_ctl_field baseclkfreq;
bool hiword_update;
};
/**
* struct sdhci_arasan_data
* @clk_ahb: Pointer to the AHB clock
* @phy: Pointer to the generic phy
* @host: Pointer to the main SDHCI host structure.
* @clk_ahb: Pointer to the AHB clock
* @phy: Pointer to the generic phy
* @sdcardclk_hw: Struct for the clock we might provide to a PHY.
* @sdcardclk: Pointer to normal 'struct clock' for sdcardclk_hw.
* @soc_ctl_base: Pointer to regmap for syscon for soc_ctl registers.
* @soc_ctl_map: Map to get offsets into soc_ctl registers.
*/
struct sdhci_arasan_data {
struct sdhci_host *host;
struct clk *clk_ahb;
struct phy *phy;
struct clk_hw sdcardclk_hw;
struct clk *sdcardclk;
struct regmap *soc_ctl_base;
const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
};
static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = {
.baseclkfreq = { .reg = 0xf000, .width = 8, .shift = 8 },
.hiword_update = true,
};
/**
* sdhci_arasan_syscon_write - Write to a field in soc_ctl registers
*
* This function allows writing to fields in sdhci_arasan_soc_ctl_map.
* Note that if a field is specified as not available (shift < 0) then
* this function will silently return an error code. It will be noisy
* and print errors for any other (unexpected) errors.
*
* @host: The sdhci_host
* @fld: The field to write to
* @val: The value to write
*/
static int sdhci_arasan_syscon_write(struct sdhci_host *host,
const struct sdhci_arasan_soc_ctl_field *fld,
u32 val)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
struct regmap *soc_ctl_base = sdhci_arasan->soc_ctl_base;
u32 reg = fld->reg;
u16 width = fld->width;
s16 shift = fld->shift;
int ret;
/*
* Silently return errors for shift < 0 so caller doesn't have
* to check for fields which are optional. For fields that
* are required then caller needs to do something special
* anyway.
*/
if (shift < 0)
return -EINVAL;
if (sdhci_arasan->soc_ctl_map->hiword_update)
ret = regmap_write(soc_ctl_base, reg,
HIWORD_UPDATE(val, GENMASK(width, 0),
shift));
else
ret = regmap_update_bits(soc_ctl_base, reg,
GENMASK(shift + width, shift),
val << shift);
/* Yell about (unexpected) regmap errors */
if (ret)
pr_warn("%s: Regmap write fail: %d\n",
mmc_hostname(host->mmc), ret);
return ret;
}
static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)
{
u32 div;
@ -79,6 +188,21 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
}
}
static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
struct mmc_ios *ios)
{
u32 vendor;
struct sdhci_host *host = mmc_priv(mmc);
vendor = readl(host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
if (ios->enhanced_strobe)
vendor |= VENDOR_ENHANCED_STROBE;
else
vendor &= ~VENDOR_ENHANCED_STROBE;
writel(vendor, host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
}
static struct sdhci_ops sdhci_arasan_ops = {
.set_clock = sdhci_arasan_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
@ -172,9 +296,168 @@ static int sdhci_arasan_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend,
sdhci_arasan_resume);
static const struct of_device_id sdhci_arasan_of_match[] = {
/* SoC-specific compatible strings w/ soc_ctl_map */
{
.compatible = "rockchip,rk3399-sdhci-5.1",
.data = &rk3399_soc_ctl_map,
},
/* Generic compatible below here */
{ .compatible = "arasan,sdhci-8.9a" },
{ .compatible = "arasan,sdhci-5.1" },
{ .compatible = "arasan,sdhci-4.9a" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match);
/**
* sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate
*
* Return the current actual rate of the SD card clock. This can be used
* to communicate with out PHY.
*
* @hw: Pointer to the hardware clock structure.
* @parent_rate The parent rate (should be rate of clk_xin).
* Returns the card clock rate.
*/
static unsigned long sdhci_arasan_sdcardclk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct sdhci_arasan_data *sdhci_arasan =
container_of(hw, struct sdhci_arasan_data, sdcardclk_hw);
struct sdhci_host *host = sdhci_arasan->host;
return host->mmc->actual_clock;
}
static const struct clk_ops arasan_sdcardclk_ops = {
.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
};
/**
* sdhci_arasan_update_baseclkfreq - Set corecfg_baseclkfreq
*
* The corecfg_baseclkfreq is supposed to contain the MHz of clk_xin. This
* function can be used to make that happen.
*
* NOTES:
* - Many existing devices don't seem to do this and work fine. To keep
* compatibility for old hardware where the device tree doesn't provide a
* register map, this function is a noop if a soc_ctl_map hasn't been provided
* for this platform.
* - It's assumed that clk_xin is not dynamic and that we use the SDHCI divider
* to achieve lower clock rates. That means that this function is called once
* at probe time and never called again.
*
* @host: The sdhci_host
*/
static void sdhci_arasan_update_baseclkfreq(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
const struct sdhci_arasan_soc_ctl_map *soc_ctl_map =
sdhci_arasan->soc_ctl_map;
u32 mhz = DIV_ROUND_CLOSEST(clk_get_rate(pltfm_host->clk), 1000000);
/* Having a map is optional */
if (!soc_ctl_map)
return;
/* If we have a map, we expect to have a syscon */
if (!sdhci_arasan->soc_ctl_base) {
pr_warn("%s: Have regmap, but no soc-ctl-syscon\n",
mmc_hostname(host->mmc));
return;
}
sdhci_arasan_syscon_write(host, &soc_ctl_map->baseclkfreq, mhz);
}
/**
* sdhci_arasan_register_sdclk - Register the sdclk for a PHY to use
*
* Some PHY devices need to know what the actual card clock is. In order for
* them to find out, we'll provide a clock through the common clock framework
* for them to query.
*
* Note: without seriously re-architecting SDHCI's clock code and testing on
* all platforms, there's no way to create a totally beautiful clock here
* with all clock ops implemented. Instead, we'll just create a clock that can
* be queried and set the CLK_GET_RATE_NOCACHE attribute to tell common clock
* framework that we're doing things behind its back. This should be sufficient
* to create nice clean device tree bindings and later (if needed) we can try
* re-architecting SDHCI if we see some benefit to it.
*
* @sdhci_arasan: Our private data structure.
* @clk_xin: Pointer to the functional clock
* @dev: Pointer to our struct device.
* Returns 0 on success and error value on error
*/
static int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan,
struct clk *clk_xin,
struct device *dev)
{
struct device_node *np = dev->of_node;
struct clk_init_data sdcardclk_init;
const char *parent_clk_name;
int ret;
/* Providing a clock to the PHY is optional; no error if missing */
if (!of_find_property(np, "#clock-cells", NULL))
return 0;
ret = of_property_read_string_index(np, "clock-output-names", 0,
&sdcardclk_init.name);
if (ret) {
dev_err(dev, "DT has #clock-cells but no clock-output-names\n");
return ret;
}
parent_clk_name = __clk_get_name(clk_xin);
sdcardclk_init.parent_names = &parent_clk_name;
sdcardclk_init.num_parents = 1;
sdcardclk_init.flags = CLK_GET_RATE_NOCACHE;
sdcardclk_init.ops = &arasan_sdcardclk_ops;
sdhci_arasan->sdcardclk_hw.init = &sdcardclk_init;
sdhci_arasan->sdcardclk =
devm_clk_register(dev, &sdhci_arasan->sdcardclk_hw);
sdhci_arasan->sdcardclk_hw.init = NULL;
ret = of_clk_add_provider(np, of_clk_src_simple_get,
sdhci_arasan->sdcardclk);
if (ret)
dev_err(dev, "Failed to add clock provider\n");
return ret;
}
/**
* sdhci_arasan_unregister_sdclk - Undoes sdhci_arasan_register_sdclk()
*
* Should be called any time we're exiting and sdhci_arasan_register_sdclk()
* returned success.
*
* @dev: Pointer to our struct device.
*/
static void sdhci_arasan_unregister_sdclk(struct device *dev)
{
struct device_node *np = dev->of_node;
if (!of_find_property(np, "#clock-cells", NULL))
return;
of_clk_del_provider(dev->of_node);
}
static int sdhci_arasan_probe(struct platform_device *pdev)
{
int ret;
const struct of_device_id *match;
struct device_node *node;
struct clk *clk_xin;
struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host;
@ -187,6 +470,24 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
pltfm_host = sdhci_priv(host);
sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
sdhci_arasan->host = host;
match = of_match_node(sdhci_arasan_of_match, pdev->dev.of_node);
sdhci_arasan->soc_ctl_map = match->data;
node = of_parse_phandle(pdev->dev.of_node, "arasan,soc-ctl-syscon", 0);
if (node) {
sdhci_arasan->soc_ctl_base = syscon_node_to_regmap(node);
of_node_put(node);
if (IS_ERR(sdhci_arasan->soc_ctl_base)) {
ret = PTR_ERR(sdhci_arasan->soc_ctl_base);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "Can't get syscon: %d\n",
ret);
goto err_pltfm_free;
}
}
sdhci_arasan->clk_ahb = devm_clk_get(&pdev->dev, "clk_ahb");
if (IS_ERR(sdhci_arasan->clk_ahb)) {
@ -217,10 +518,16 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
sdhci_get_of_property(pdev);
pltfm_host->clk = clk_xin;
sdhci_arasan_update_baseclkfreq(host);
ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, &pdev->dev);
if (ret)
goto clk_disable_all;
ret = mmc_of_parse(host->mmc);
if (ret) {
dev_err(&pdev->dev, "parsing dt failed (%u)\n", ret);
goto clk_disable_all;
goto unreg_clk;
}
sdhci_arasan->phy = ERR_PTR(-ENODEV);
@ -231,13 +538,13 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
if (IS_ERR(sdhci_arasan->phy)) {
ret = PTR_ERR(sdhci_arasan->phy);
dev_err(&pdev->dev, "No phy for arasan,sdhci-5.1.\n");
goto clk_disable_all;
goto unreg_clk;
}
ret = phy_init(sdhci_arasan->phy);
if (ret < 0) {
dev_err(&pdev->dev, "phy_init err.\n");
goto clk_disable_all;
goto unreg_clk;
}
ret = phy_power_on(sdhci_arasan->phy);
@ -245,6 +552,9 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "phy_power_on err.\n");
goto err_phy_power;
}
host->mmc_host_ops.hs400_enhanced_strobe =
sdhci_arasan_hs400_enhanced_strobe;
}
ret = sdhci_add_host(host);
@ -259,6 +569,8 @@ err_add_host:
err_phy_power:
if (!IS_ERR(sdhci_arasan->phy))
phy_exit(sdhci_arasan->phy);
unreg_clk:
sdhci_arasan_unregister_sdclk(&pdev->dev);
clk_disable_all:
clk_disable_unprepare(clk_xin);
clk_dis_ahb:
@ -281,6 +593,8 @@ static int sdhci_arasan_remove(struct platform_device *pdev)
phy_exit(sdhci_arasan->phy);
}
sdhci_arasan_unregister_sdclk(&pdev->dev);
ret = sdhci_pltfm_unregister(pdev);
clk_disable_unprepare(clk_ahb);
@ -288,14 +602,6 @@ static int sdhci_arasan_remove(struct platform_device *pdev)
return ret;
}
static const struct of_device_id sdhci_arasan_of_match[] = {
{ .compatible = "arasan,sdhci-8.9a" },
{ .compatible = "arasan,sdhci-5.1" },
{ .compatible = "arasan,sdhci-4.9a" },
{ }
};
MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match);
static struct platform_driver sdhci_arasan_driver = {
.driver = {
.name = "sdhci-arasan",

View file

@ -288,7 +288,7 @@ static int sdhci_at91_probe(struct platform_device *pdev)
* Disable SDHCI_QUIRK_BROKEN_CARD_DETECTION to be sure nobody tries
* to enable polling via device tree with broken-cd property.
*/
if (!(host->mmc->caps & MMC_CAP_NONREMOVABLE) &&
if (mmc_card_is_removable(host->mmc) &&
mmc_gpio_get_cd(host->mmc) < 0) {
host->mmc->caps |= MMC_CAP_NEEDS_POLL;
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;

View file

@ -481,7 +481,7 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask)
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static u32 esdhc_proctl;
static int esdhc_of_suspend(struct device *dev)
{
@ -504,16 +504,12 @@ static int esdhc_of_resume(struct device *dev)
}
return ret;
}
static const struct dev_pm_ops esdhc_pmops = {
.suspend = esdhc_of_suspend,
.resume = esdhc_of_resume,
};
#define ESDHC_PMOPS (&esdhc_pmops)
#else
#define ESDHC_PMOPS NULL
#endif
static SIMPLE_DEV_PM_OPS(esdhc_of_dev_pm_ops,
esdhc_of_suspend,
esdhc_of_resume);
static const struct sdhci_ops sdhci_esdhc_be_ops = {
.read_l = esdhc_be_readl,
.read_w = esdhc_be_readw,
@ -657,7 +653,7 @@ static struct platform_driver sdhci_esdhc_driver = {
.driver = {
.name = "sdhci-esdhc",
.of_match_table = sdhci_esdhc_of_match,
.pm = ESDHC_PMOPS,
.pm = &esdhc_of_dev_pm_ops,
},
.probe = sdhci_esdhc_probe,
.remove = sdhci_pltfm_unregister,

View file

@ -85,7 +85,7 @@ static struct platform_driver sdhci_hlwd_driver = {
.driver = {
.name = "sdhci-hlwd",
.of_match_table = sdhci_hlwd_of_match,
.pm = SDHCI_PLTFM_PMOPS,
.pm = &sdhci_pltfm_pmops,
},
.probe = sdhci_hlwd_probe,
.remove = sdhci_pltfm_unregister,

View file

@ -419,13 +419,13 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
};
/* Define Host controllers for Intel Merrifield platform */
#define INTEL_MRFL_EMMC_0 0
#define INTEL_MRFL_EMMC_1 1
#define INTEL_MRFLD_EMMC_0 0
#define INTEL_MRFLD_EMMC_1 1
static int intel_mrfl_mmc_probe_slot(struct sdhci_pci_slot *slot)
static int intel_mrfld_mmc_probe_slot(struct sdhci_pci_slot *slot)
{
if ((PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFL_EMMC_0) &&
(PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFL_EMMC_1))
if ((PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFLD_EMMC_0) &&
(PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFLD_EMMC_1))
/* SD support is not ready yet */
return -ENODEV;
@ -435,12 +435,12 @@ static int intel_mrfl_mmc_probe_slot(struct sdhci_pci_slot *slot)
return 0;
}
static const struct sdhci_pci_fixes sdhci_intel_mrfl_mmc = {
static const struct sdhci_pci_fixes sdhci_intel_mrfld_mmc = {
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_BROKEN_HS200 |
SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
.allow_runtime_pm = true,
.probe_slot = intel_mrfl_mmc_probe_slot,
.probe_slot = intel_mrfld_mmc_probe_slot,
};
/* O2Micro extra registers */
@ -1104,10 +1104,10 @@ static const struct pci_device_id pci_ids[] = {
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_MRFL_MMC,
.device = PCI_DEVICE_ID_INTEL_MRFLD_MMC,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_mrfl_mmc,
.driver_data = (kernel_ulong_t)&sdhci_intel_mrfld_mmc,
},
{
@ -1413,8 +1413,7 @@ static const struct sdhci_ops sdhci_pci_ops = {
* *
\*****************************************************************************/
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int sdhci_pci_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
@ -1496,7 +1495,9 @@ static int sdhci_pci_resume(struct device *dev)
return 0;
}
#endif
#ifdef CONFIG_PM
static int sdhci_pci_runtime_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
@ -1562,17 +1563,10 @@ static int sdhci_pci_runtime_resume(struct device *dev)
return 0;
}
#else /* CONFIG_PM */
#define sdhci_pci_suspend NULL
#define sdhci_pci_resume NULL
#endif /* CONFIG_PM */
#endif
static const struct dev_pm_ops sdhci_pci_pm_ops = {
.suspend = sdhci_pci_suspend,
.resume = sdhci_pci_resume,
SET_SYSTEM_SLEEP_PM_OPS(sdhci_pci_suspend, sdhci_pci_resume)
SET_RUNTIME_PM_OPS(sdhci_pci_runtime_suspend,
sdhci_pci_runtime_resume, NULL)
};
@ -1760,11 +1754,12 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
static void sdhci_pci_runtime_pm_allow(struct device *dev)
{
pm_runtime_put_noidle(dev);
pm_runtime_allow(dev);
pm_suspend_ignore_children(dev, 1);
pm_runtime_set_autosuspend_delay(dev, 50);
pm_runtime_use_autosuspend(dev);
pm_suspend_ignore_children(dev, 1);
pm_runtime_allow(dev);
/* Stay active until mmc core scans for a card */
pm_runtime_put_noidle(dev);
}
static void sdhci_pci_runtime_pm_forbid(struct device *dev)
@ -1810,15 +1805,13 @@ static int sdhci_pci_probe(struct pci_dev *pdev,
return -ENODEV;
}
ret = pci_enable_device(pdev);
ret = pcim_enable_device(pdev);
if (ret)
return ret;
chip = kzalloc(sizeof(struct sdhci_pci_chip), GFP_KERNEL);
if (!chip) {
ret = -ENOMEM;
goto err;
}
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->pdev = pdev;
chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data;
@ -1834,7 +1827,7 @@ static int sdhci_pci_probe(struct pci_dev *pdev,
if (chip->fixes && chip->fixes->probe) {
ret = chip->fixes->probe(chip);
if (ret)
goto free;
return ret;
}
slots = chip->num_slots; /* Quirk may have changed this */
@ -1844,8 +1837,7 @@ static int sdhci_pci_probe(struct pci_dev *pdev,
if (IS_ERR(slot)) {
for (i--; i >= 0; i--)
sdhci_pci_remove_slot(chip->slots[i]);
ret = PTR_ERR(slot);
goto free;
return PTR_ERR(slot);
}
chip->slots[i] = slot;
@ -1855,35 +1847,18 @@ static int sdhci_pci_probe(struct pci_dev *pdev,
sdhci_pci_runtime_pm_allow(&pdev->dev);
return 0;
free:
pci_set_drvdata(pdev, NULL);
kfree(chip);
err:
pci_disable_device(pdev);
return ret;
}
static void sdhci_pci_remove(struct pci_dev *pdev)
{
int i;
struct sdhci_pci_chip *chip;
struct sdhci_pci_chip *chip = pci_get_drvdata(pdev);
chip = pci_get_drvdata(pdev);
if (chip->allow_runtime_pm)
sdhci_pci_runtime_pm_forbid(&pdev->dev);
if (chip) {
if (chip->allow_runtime_pm)
sdhci_pci_runtime_pm_forbid(&pdev->dev);
for (i = 0; i < chip->num_slots; i++)
sdhci_pci_remove_slot(chip->slots[i]);
pci_set_drvdata(pdev, NULL);
kfree(chip);
}
pci_disable_device(pdev);
for (i = 0; i < chip->num_slots; i++)
sdhci_pci_remove_slot(chip->slots[i]);
}
static struct pci_driver sdhci_driver = {

View file

@ -14,7 +14,7 @@
#define PCI_DEVICE_ID_INTEL_BSW_EMMC 0x2294
#define PCI_DEVICE_ID_INTEL_BSW_SDIO 0x2295
#define PCI_DEVICE_ID_INTEL_BSW_SD 0x2296
#define PCI_DEVICE_ID_INTEL_MRFL_MMC 0x1190
#define PCI_DEVICE_ID_INTEL_MRFLD_MMC 0x1190
#define PCI_DEVICE_ID_INTEL_CLV_SDIO0 0x08f9
#define PCI_DEVICE_ID_INTEL_CLV_SDIO1 0x08fa
#define PCI_DEVICE_ID_INTEL_CLV_SDIO2 0x08fb

View file

@ -215,29 +215,26 @@ int sdhci_pltfm_unregister(struct platform_device *pdev)
}
EXPORT_SYMBOL_GPL(sdhci_pltfm_unregister);
#ifdef CONFIG_PM
int sdhci_pltfm_suspend(struct device *dev)
#ifdef CONFIG_PM_SLEEP
static int sdhci_pltfm_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
return sdhci_suspend_host(host);
}
EXPORT_SYMBOL_GPL(sdhci_pltfm_suspend);
int sdhci_pltfm_resume(struct device *dev)
static int sdhci_pltfm_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
return sdhci_resume_host(host);
}
EXPORT_SYMBOL_GPL(sdhci_pltfm_resume);
#endif
const struct dev_pm_ops sdhci_pltfm_pmops = {
.suspend = sdhci_pltfm_suspend,
.resume = sdhci_pltfm_resume,
SET_SYSTEM_SLEEP_PM_OPS(sdhci_pltfm_suspend, sdhci_pltfm_resume)
};
EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops);
#endif /* CONFIG_PM */
static int __init sdhci_pltfm_drv_init(void)
{

View file

@ -109,13 +109,6 @@ static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
return (void *)host->private;
}
#ifdef CONFIG_PM
extern int sdhci_pltfm_suspend(struct device *dev);
extern int sdhci_pltfm_resume(struct device *dev);
extern const struct dev_pm_ops sdhci_pltfm_pmops;
#define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
#else
#define SDHCI_PLTFM_PMOPS NULL
#endif
#endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */

View file

@ -252,7 +252,7 @@ static struct platform_driver sdhci_pxav2_driver = {
.driver = {
.name = "sdhci-pxav2",
.of_match_table = of_match_ptr(sdhci_pxav2_of_match),
.pm = SDHCI_PLTFM_PMOPS,
.pm = &sdhci_pltfm_pmops,
},
.probe = sdhci_pxav2_probe,
.remove = sdhci_pxav2_remove,

View file

@ -583,24 +583,17 @@ static int sdhci_pxav3_runtime_resume(struct device *dev)
}
#endif
#ifdef CONFIG_PM
static const struct dev_pm_ops sdhci_pxav3_pmops = {
SET_SYSTEM_SLEEP_PM_OPS(sdhci_pxav3_suspend, sdhci_pxav3_resume)
SET_RUNTIME_PM_OPS(sdhci_pxav3_runtime_suspend,
sdhci_pxav3_runtime_resume, NULL)
};
#define SDHCI_PXAV3_PMOPS (&sdhci_pxav3_pmops)
#else
#define SDHCI_PXAV3_PMOPS NULL
#endif
static struct platform_driver sdhci_pxav3_driver = {
.driver = {
.name = "sdhci-pxav3",
.of_match_table = of_match_ptr(sdhci_pxav3_of_match),
.pm = SDHCI_PXAV3_PMOPS,
.pm = &sdhci_pxav3_pmops,
},
.probe = sdhci_pxav3_probe,
.remove = sdhci_pxav3_remove,

View file

@ -714,19 +714,12 @@ static int sdhci_s3c_runtime_resume(struct device *dev)
}
#endif
#ifdef CONFIG_PM
static const struct dev_pm_ops sdhci_s3c_pmops = {
SET_SYSTEM_SLEEP_PM_OPS(sdhci_s3c_suspend, sdhci_s3c_resume)
SET_RUNTIME_PM_OPS(sdhci_s3c_runtime_suspend, sdhci_s3c_runtime_resume,
NULL)
};
#define SDHCI_S3C_PMOPS (&sdhci_s3c_pmops)
#else
#define SDHCI_S3C_PMOPS NULL
#endif
#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212)
static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = {
.no_divider = true,
@ -765,7 +758,7 @@ static struct platform_driver sdhci_s3c_driver = {
.driver = {
.name = "s3c-sdhci",
.of_match_table = of_match_ptr(sdhci_s3c_dt_match),
.pm = SDHCI_S3C_PMOPS,
.pm = &sdhci_s3c_pmops,
},
};

View file

@ -260,9 +260,9 @@ static int sdhci_sirf_resume(struct device *dev)
return sdhci_resume_host(host);
}
#endif
static SIMPLE_DEV_PM_OPS(sdhci_sirf_pm_ops, sdhci_sirf_suspend, sdhci_sirf_resume);
#endif
static const struct of_device_id sdhci_sirf_of_match[] = {
{ .compatible = "sirf,prima2-sdhc" },
@ -274,9 +274,7 @@ static struct platform_driver sdhci_sirf_driver = {
.driver = {
.name = "sdhci-sirf",
.of_match_table = sdhci_sirf_of_match,
#ifdef CONFIG_PM_SLEEP
.pm = &sdhci_sirf_pm_ops,
#endif
},
.probe = sdhci_sirf_probe,
.remove = sdhci_pltfm_unregister,

View file

@ -183,7 +183,7 @@ static void st_mmcss_cconfig(struct device_node *np, struct sdhci_host *host)
writel_relaxed(cconf2, host->ioaddr + ST_MMC_CCONFIG_REG_2);
if (mhost->caps & MMC_CAP_NONREMOVABLE)
if (!mmc_card_is_removable(mhost))
cconf3 |= ST_MMC_CCONFIG_EMMC_SLOT_TYPE;
else
/* CARD _D ET_CTRL */

View file

@ -148,28 +148,37 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
return;
misc_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL);
/* Erratum: Enable SDHCI spec v3.00 support */
if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300)
misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300;
/* Advertise UHS modes as supported by host */
if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50)
misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50;
else
misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR50;
if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50)
misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50;
else
misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_DDR50;
if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104)
misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104;
else
misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR104;
sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL);
clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
misc_ctrl &= ~(SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 |
SDHCI_MISC_CTRL_ENABLE_SDR50 |
SDHCI_MISC_CTRL_ENABLE_DDR50 |
SDHCI_MISC_CTRL_ENABLE_SDR104);
clk_ctrl &= ~SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE;
if (soc_data->nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50)
clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE;
/*
* If the board does not define a regulator for the SDHCI
* IO voltage, then don't advertise support for UHS modes
* even if the device supports it because the IO voltage
* cannot be configured.
*/
if (!IS_ERR(host->mmc->supply.vqmmc)) {
/* Erratum: Enable SDHCI spec v3.00 support */
if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300)
misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300;
/* Advertise UHS modes as supported by host */
if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50)
misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50;
if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50)
misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50;
if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104)
misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104;
if (soc_data->nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50)
clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE;
}
sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL);
sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB)
@ -474,7 +483,7 @@ static struct platform_driver sdhci_tegra_driver = {
.driver = {
.name = "sdhci-tegra",
.of_match_table = sdhci_tegra_dt_match,
.pm = SDHCI_PLTFM_PMOPS,
.pm = &sdhci_pltfm_pmops,
},
.probe = sdhci_tegra_probe,
.remove = sdhci_pltfm_unregister,

File diff suppressed because it is too large Load diff

View file

@ -128,6 +128,7 @@
#define SDHCI_INT_CARD_INSERT 0x00000040
#define SDHCI_INT_CARD_REMOVE 0x00000080
#define SDHCI_INT_CARD_INT 0x00000100
#define SDHCI_INT_RETUNE 0x00001000
#define SDHCI_INT_ERROR 0x00008000
#define SDHCI_INT_TIMEOUT 0x00010000
#define SDHCI_INT_CRC 0x00020000
@ -186,6 +187,7 @@
#define SDHCI_CAN_DO_ADMA1 0x00100000
#define SDHCI_CAN_DO_HISPD 0x00200000
#define SDHCI_CAN_DO_SDMA 0x00400000
#define SDHCI_CAN_DO_SUSPEND 0x00800000
#define SDHCI_CAN_VDD_330 0x01000000
#define SDHCI_CAN_VDD_300 0x02000000
#define SDHCI_CAN_VDD_180 0x04000000
@ -314,6 +316,9 @@ struct sdhci_adma2_64_desc {
*/
#define SDHCI_MAX_SEGS 128
/* Allow for a a command request and a data request at the same time */
#define SDHCI_MAX_MRQS 2
enum sdhci_cookie {
COOKIE_UNMAPPED,
COOKIE_PRE_MAPPED, /* mapped by sdhci_pre_req() */
@ -447,6 +452,9 @@ struct sdhci_host {
#define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */
#define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */
#define SDHCI_HS400_TUNING (1<<13) /* Tuning for HS400 */
#define SDHCI_SIGNALING_330 (1<<14) /* Host is capable of 3.3V signaling */
#define SDHCI_SIGNALING_180 (1<<15) /* Host is capable of 1.8V signaling */
#define SDHCI_SIGNALING_120 (1<<16) /* Host is capable of 1.2V signaling */
unsigned int version; /* SDHCI spec. version */
@ -460,12 +468,13 @@ struct sdhci_host {
bool runtime_suspended; /* Host is runtime suspended */
bool bus_on; /* Bus power prevents runtime suspend */
bool preset_enabled; /* Preset is enabled */
bool pending_reset; /* Cmd/data reset is pending */
struct mmc_request *mrq; /* Current request */
struct mmc_request *mrqs_done[SDHCI_MAX_MRQS]; /* Requests done */
struct mmc_command *cmd; /* Current command */
struct mmc_command *data_cmd; /* Current data command */
struct mmc_data *data; /* Current data request */
unsigned int data_early:1; /* Data finished before cmd */
unsigned int busy_handle:1; /* Handling the order of Busy-end */
struct sg_mapping_iter sg_miter; /* SG state for PIO */
unsigned int blocks; /* remaining PIO blocks */
@ -486,9 +495,11 @@ struct sdhci_host {
struct tasklet_struct finish_tasklet; /* Tasklet structures */
struct timer_list timer; /* Timer for timeouts */
struct timer_list data_timer; /* Timer for data timeouts */
u32 caps; /* Alternative CAPABILITY_0 */
u32 caps1; /* Alternative CAPABILITY_1 */
u32 caps; /* CAPABILITY_0 */
u32 caps1; /* CAPABILITY_1 */
bool read_caps; /* Capability flags have been read */
unsigned int ocr_avail_sdio; /* OCR bit masks */
unsigned int ocr_avail_sd;
@ -508,6 +519,8 @@ struct sdhci_host {
unsigned int tuning_count; /* Timer count for re-tuning */
unsigned int tuning_mode; /* Re-tuning mode supported by host */
#define SDHCI_TUNING_MODE_1 0
#define SDHCI_TUNING_MODE_2 1
#define SDHCI_TUNING_MODE_3 2
unsigned long private[0] ____cacheline_aligned;
};
@ -645,11 +658,20 @@ static inline void *sdhci_priv(struct sdhci_host *host)
}
extern void sdhci_card_detect(struct sdhci_host *host);
extern void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps,
u32 *caps1);
extern int sdhci_setup_host(struct sdhci_host *host);
extern int __sdhci_add_host(struct sdhci_host *host);
extern int sdhci_add_host(struct sdhci_host *host);
extern void sdhci_remove_host(struct sdhci_host *host, int dead);
extern void sdhci_send_command(struct sdhci_host *host,
struct mmc_command *cmd);
static inline void sdhci_read_caps(struct sdhci_host *host)
{
__sdhci_read_caps(host, NULL, NULL, NULL);
}
static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host)
{
return !!(host->flags & SDHCI_SDIO_IRQ_ENABLED);

View file

@ -222,7 +222,7 @@ static struct platform_driver sdhci_f_sdh30_driver = {
.driver = {
.name = "f_sdh30",
.of_match_table = f_sdh30_dt_ids,
.pm = SDHCI_PLTFM_PMOPS,
.pm = &sdhci_pltfm_pmops,
},
.probe = sdhci_f_sdh30_probe,
.remove = sdhci_f_sdh30_remove,

View file

@ -574,7 +574,7 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
if (state1 & STS1_CMDSEQ) {
sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK);
sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK);
for (timeout = 10000000; timeout; timeout--) {
for (timeout = 10000; timeout; timeout--) {
if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1)
& STS1_CMDSEQ))
break;
@ -819,10 +819,12 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
tmp |= CMD_SET_RTYP_NO;
break;
case MMC_RSP_R1:
case MMC_RSP_R1B:
case MMC_RSP_R3:
tmp |= CMD_SET_RTYP_6B;
break;
case MMC_RSP_R1B:
tmp |= CMD_SET_RBSY | CMD_SET_RTYP_6B;
break;
case MMC_RSP_R2:
tmp |= CMD_SET_RTYP_17B;
break;
@ -830,17 +832,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
dev_err(dev, "Unsupported response type.\n");
break;
}
switch (opc) {
/* RBSY */
case MMC_SLEEP_AWAKE:
case MMC_SWITCH:
case MMC_STOP_TRANSMISSION:
case MMC_SET_WRITE_PROT:
case MMC_CLR_WRITE_PROT:
case MMC_ERASE:
tmp |= CMD_SET_RBSY;
break;
}
/* WDAT / DATW */
if (data) {
tmp |= CMD_SET_WDAT;
@ -925,23 +917,13 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
{
struct mmc_command *cmd = mrq->cmd;
u32 opc = cmd->opcode;
u32 mask;
u32 mask = 0;
unsigned long flags;
switch (opc) {
/* response busy check */
case MMC_SLEEP_AWAKE:
case MMC_SWITCH:
case MMC_STOP_TRANSMISSION:
case MMC_SET_WRITE_PROT:
case MMC_CLR_WRITE_PROT:
case MMC_ERASE:
if (cmd->flags & MMC_RSP_BUSY)
mask = MASK_START_CMD | MASK_MRBSYE;
break;
default:
else
mask = MASK_START_CMD | MASK_MCRSPE;
break;
}
if (host->ccs_enable)
mask |= MASK_MCCSTO;
@ -1009,22 +991,6 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
host->state = STATE_REQUEST;
spin_unlock_irqrestore(&host->lock, flags);
switch (mrq->cmd->opcode) {
/* MMCIF does not support SD/SDIO command */
case MMC_SLEEP_AWAKE: /* = SD_IO_SEND_OP_COND (5) */
case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
if ((mrq->cmd->flags & MMC_CMD_MASK) != MMC_CMD_BCR)
break;
case MMC_APP_CMD:
case SD_IO_RW_DIRECT:
host->state = STATE_IDLE;
mrq->cmd->error = -ETIMEDOUT;
mmc_request_done(mmc, mrq);
return;
default:
break;
}
host->mrq = mrq;
sh_mmcif_start_cmd(host, mrq);
@ -1488,6 +1454,9 @@ static int sh_mmcif_probe(struct platform_device *pdev)
sh_mmcif_init_ocr(host);
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_WAIT_WHILE_BUSY;
mmc->caps2 |= MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO;
mmc->max_busy_timeout = 10000;
if (pd && pd->caps)
mmc->caps |= pd->caps;
mmc->max_segs = 32;

View file

@ -39,6 +39,12 @@
#define EXT_ACC 0xe4
#define SDHI_VER_GEN2_SDR50 0x490c
/* very old datasheets said 0x490c for SDR104, too. They are wrong! */
#define SDHI_VER_GEN2_SDR104 0xcb0d
#define SDHI_VER_GEN3_SD 0xcc10
#define SDHI_VER_GEN3_SDMMC 0xcd10
#define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data)
struct sh_mobile_sdhi_of_data {
@ -109,14 +115,14 @@ static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
* sh_mobile_sdhi_of_data :: dma_buswidth
*/
switch (sd_ctrl_read16(host, CTL_VERSION)) {
case 0x490C:
case SDHI_VER_GEN2_SDR50:
val = (width == 32) ? 0x0001 : 0x0000;
break;
case 0xCB0D:
case SDHI_VER_GEN2_SDR104:
val = (width == 32) ? 0x0000 : 0x0001;
break;
case 0xCC10: /* Gen3, SD only */
case 0xCD10: /* Gen3, SD + MMC */
case SDHI_VER_GEN3_SD:
case SDHI_VER_GEN3_SDMMC:
if (width == 64)
val = 0x0000;
else if (width == 32)

View file

@ -259,7 +259,7 @@ static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr,
static inline void sd_ctrl_write32_as_16_and_16(struct tmio_mmc_host *host, int addr, u32 val)
{
writew(val, host->ctl + (addr << host->bus_shift));
writew(val & 0xffff, host->ctl + (addr << host->bus_shift));
writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
}

View file

@ -1086,7 +1086,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
_host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD ||
mmc->caps & MMC_CAP_NEEDS_POLL ||
mmc->caps & MMC_CAP_NONREMOVABLE ||
!mmc_card_is_removable(mmc) ||
mmc->slot.cd_irq >= 0);
if (tmio_mmc_clk_enable(_host) < 0) {