mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 17:30:02 +00:00
MMC core:
- Improve reliability when selecting HS200 mode - Improve reliability when selecting HS400 mode - mmc: remove bondage between REQ_META and reliable write MMC host: - pxamci: Fix read-only gpio detection polarity - mtk-sd: Preinitialize delay_phase to fix the case when delay is zero - android-goldfish: Fix build dependency by adding HAS_DMA - dw_mmc: Remove Seungwon Jeon from MAINTAINERS -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWTZxbAAoJEP4mhCVzWIwpN0MP/3Op47ik1L9CqZphjT5D2PJV FHb5lZVWGwLpLugpILnesIWl1YeZ47touOi4Krs1I8V8Qh7IWMWWdPuiCrYsx329 J39OSisTHC8NVNXG/+JhSKUwaKe/yYvqJOjK8bVMG/9U0uzHyFo/OU8MZnZz8rDU bKB3KWolSdREACt9Mz5R4r4HXB384/FQ4YdNzZtDtu16zki5E8r5R7nj0d2FURXq vZyGG5cMnTpMtRjoXOVG+fCw2tYCZcFG+focWrg1E+GtU952hpe114F1QG6mvkqc 9aJvBqDDLEroM8BLhnOgxdE8dE3wjOsDIMDUi3gtatNzpJ5b/5cN2rY8dvThGO1k kjx+u/MtGSTy6imB80GFpqN8XMm/m1+15N2T3p+UjiZiR9kUhS/cjYtA3AeelWLq x0oAUtJDAtAs8RccGJqh9rBw/PeYYWU4/cQ8Zs+7BrrPrk+OTu6NyD8lKMDY4kKl ikWj60UrzmIr9D52Sy1YgxV+Y0RwWIPUBtZDBZzC5g+61e60Ay6sS91EVuiXcpdS FowP+Dw+lxbD0j4urq55Q4CLVTcZGY2kfrzoBYy8NCqu3DWAf6hWmlY8+0WrfYXh Gm0bk5JWI+H2YlXZqADUQDhWbWfRYLv9q9AxNl1fKBvEVxPaz0/279L6ThtTzwYz gooQT2VmrJndyyty/FE1 =X/qJ -----END PGP SIGNATURE----- Merge tag 'mmc-v4.4-rc1' of git://git.linaro.org/people/ulf.hansson/mmc Pull MMC fixes from Ulf Hansson: "Here are some mmc fixes intended for v4.4 rc2. It's based on a commit prior rc1 as I wanted to get them a bit more tested in next before sending you the pull request. MMC core: - Improve reliability when selecting HS200 mode - Improve reliability when selecting HS400 mode - mmc: remove bondage between REQ_META and reliable write MMC host: - pxamci: Fix read-only gpio detection polarity - mtk-sd: Preinitialize delay_phase to fix the case when delay is zero - android-goldfish: Fix build dependency by adding HAS_DMA - dw_mmc: Remove Seungwon Jeon from MAINTAINERS" * tag 'mmc-v4.4-rc1' of git://git.linaro.org/people/ulf.hansson/mmc: mmc: remove bondage between REQ_META and reliable write mmc: MMC_GOLDFISH should depend on HAS_DMA mmc: mediatek: Preinitialize delay_phase in get_best_delay() MAINTAINERS: mmc: Remove Seungwon Jeon from dw_mmc mmc: mmc: Improve reliability of mmc_select_hs400() mmc: mmc: Move mmc_switch_status() mmc: mmc: Fix HS setting in mmc_select_hs400() mmc: mmc: Improve reliability of mmc_select_hs200() mmc: pxamci: fix read-only gpio detection polarity
This commit is contained in:
commit
1282ac407c
6 changed files with 119 additions and 79 deletions
|
@ -9315,7 +9315,6 @@ F: drivers/i2c/busses/i2c-designware-*
|
|||
F: include/linux/platform_data/i2c-designware.h
|
||||
|
||||
SYNOPSYS DESIGNWARE MMC/SD/SDIO DRIVER
|
||||
M: Seungwon Jeon <tgih.jun@samsung.com>
|
||||
M: Jaehoon Chung <jh80.chung@samsung.com>
|
||||
L: linux-mmc@vger.kernel.org
|
||||
S: Maintained
|
||||
|
|
|
@ -65,8 +65,7 @@ MODULE_ALIAS("mmc:block");
|
|||
#define MMC_SANITIZE_REQ_TIMEOUT 240000
|
||||
#define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16)
|
||||
|
||||
#define mmc_req_rel_wr(req) (((req->cmd_flags & REQ_FUA) || \
|
||||
(req->cmd_flags & REQ_META)) && \
|
||||
#define mmc_req_rel_wr(req) ((req->cmd_flags & REQ_FUA) && \
|
||||
(rq_data_dir(req) == WRITE))
|
||||
#define PACKED_CMD_VER 0x01
|
||||
#define PACKED_CMD_WR 0x02
|
||||
|
@ -1467,13 +1466,9 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
|
|||
|
||||
/*
|
||||
* Reliable writes are used to implement Forced Unit Access and
|
||||
* REQ_META accesses, and are supported only on MMCs.
|
||||
*
|
||||
* XXX: this really needs a good explanation of why REQ_META
|
||||
* is treated special.
|
||||
* are supported only on MMCs.
|
||||
*/
|
||||
bool do_rel_wr = ((req->cmd_flags & REQ_FUA) ||
|
||||
(req->cmd_flags & REQ_META)) &&
|
||||
bool do_rel_wr = (req->cmd_flags & REQ_FUA) &&
|
||||
(rq_data_dir(req) == WRITE) &&
|
||||
(md->flags & MMC_BLK_REL_WR);
|
||||
|
||||
|
|
|
@ -1040,71 +1040,6 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int mmc_select_hs400(struct mmc_card *card)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
int err = 0;
|
||||
u8 val;
|
||||
|
||||
/*
|
||||
* HS400 mode requires 8-bit bus width
|
||||
*/
|
||||
if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
|
||||
host->ios.bus_width == MMC_BUS_WIDTH_8))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Before switching to dual data rate operation for HS400,
|
||||
* it is required to convert from HS200 mode to HS mode.
|
||||
*/
|
||||
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
|
||||
mmc_set_bus_speed(card);
|
||||
|
||||
val = EXT_CSD_TIMING_HS |
|
||||
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, true, true);
|
||||
if (err) {
|
||||
pr_err("%s: switch to high-speed from hs200 failed, err:%d\n",
|
||||
mmc_hostname(host), err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_BUS_WIDTH,
|
||||
EXT_CSD_DDR_BUS_WIDTH_8,
|
||||
card->ext_csd.generic_cmd6_time);
|
||||
if (err) {
|
||||
pr_err("%s: switch to bus width for hs400 failed, err:%d\n",
|
||||
mmc_hostname(host), err);
|
||||
return err;
|
||||
}
|
||||
|
||||
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, true, true);
|
||||
if (err) {
|
||||
pr_err("%s: switch to hs400 failed, err:%d\n",
|
||||
mmc_hostname(host), err);
|
||||
return err;
|
||||
}
|
||||
|
||||
mmc_set_timing(host, MMC_TIMING_MMC_HS400);
|
||||
mmc_set_bus_speed(card);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmc_hs200_to_hs400(struct mmc_card *card)
|
||||
{
|
||||
return mmc_select_hs400(card);
|
||||
}
|
||||
|
||||
/* Caller must hold re-tuning */
|
||||
static int mmc_switch_status(struct mmc_card *card)
|
||||
{
|
||||
|
@ -1118,6 +1053,97 @@ static int mmc_switch_status(struct mmc_card *card)
|
|||
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;
|
||||
|
||||
/*
|
||||
* HS400 mode requires 8-bit bus width
|
||||
*/
|
||||
if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
|
||||
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 |
|
||||
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);
|
||||
if (err) {
|
||||
pr_err("%s: switch to high-speed from hs200 failed, err:%d\n",
|
||||
mmc_hostname(host), err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Switch card to DDR */
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_BUS_WIDTH,
|
||||
EXT_CSD_DDR_BUS_WIDTH_8,
|
||||
card->ext_csd.generic_cmd6_time);
|
||||
if (err) {
|
||||
pr_err("%s: switch to bus width for hs400 failed, err:%d\n",
|
||||
mmc_hostname(host), err);
|
||||
return 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, send_status, true);
|
||||
if (err) {
|
||||
pr_err("%s: switch to hs400 failed, err:%d\n",
|
||||
mmc_hostname(host), err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Set host controller to HS400 timing and frequency */
|
||||
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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
|
||||
__func__, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
int mmc_hs200_to_hs400(struct mmc_card *card)
|
||||
{
|
||||
return mmc_select_hs400(card);
|
||||
}
|
||||
|
||||
int mmc_hs400_to_hs200(struct mmc_card *card)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
|
@ -1219,6 +1245,8 @@ 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;
|
||||
int err = -EINVAL;
|
||||
u8 val;
|
||||
|
||||
|
@ -1234,6 +1262,9 @@ 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.
|
||||
|
@ -1245,11 +1276,25 @@ static int mmc_select_hs200(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, true, true);
|
||||
if (!err)
|
||||
mmc_set_timing(host, MMC_TIMING_MMC_HS200);
|
||||
true, send_status, 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:
|
||||
if (err)
|
||||
pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
|
||||
__func__, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -473,6 +473,7 @@ config MMC_DAVINCI
|
|||
|
||||
config MMC_GOLDFISH
|
||||
tristate "goldfish qemu Multimedia Card Interface support"
|
||||
depends on HAS_DMA
|
||||
depends on GOLDFISH || COMPILE_TEST
|
||||
help
|
||||
This selects the Goldfish Multimedia card Interface emulation
|
||||
|
|
|
@ -1276,7 +1276,7 @@ static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay)
|
|||
int start = 0, len = 0;
|
||||
int start_final = 0, len_final = 0;
|
||||
u8 final_phase = 0xff;
|
||||
struct msdc_delay_phase delay_phase;
|
||||
struct msdc_delay_phase delay_phase = { 0, };
|
||||
|
||||
if (delay == 0) {
|
||||
dev_err(host->dev, "phase error: [map:%x]\n", delay);
|
||||
|
|
|
@ -805,7 +805,7 @@ static int pxamci_probe(struct platform_device *pdev)
|
|||
goto out;
|
||||
} else {
|
||||
mmc->caps |= host->pdata->gpio_card_ro_invert ?
|
||||
MMC_CAP2_RO_ACTIVE_HIGH : 0;
|
||||
0 : MMC_CAP2_RO_ACTIVE_HIGH;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(gpio_cd))
|
||||
|
|
Loading…
Reference in a new issue