You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (75 commits) mmc: core: eMMC bus width may not work on all platforms mmc: sdhci: Auto-CMD23 fixes. mmc: sdhci: Auto-CMD23 support. mmc: core: Block CMD23 support for UHS104/SDXC cards. mmc: sdhci: Implement MMC_CAP_CMD23 for SDHCI. mmc: core: Use CMD23 for multiblock transfers when we can. mmc: quirks: Add/remove quirks conditional support. mmc: Add new VUB300 USB-to-SD/SDIO/MMC driver mmc: sdhci-pxa: Add quirks for DMA/ADMA to match h/w mmc: core: duplicated trial with same freq in mmc_rescan_try_freq() mmc: core: add support for eMMC Dual Data Rate mmc: core: eMMC signal voltage does not use CMD11 mmc: sdhci-pxa: add platform code for UHS signaling mmc: sdhci: add hooks for setting UHS in platform specific code mmc: core: clear MMC_PM_KEEP_POWER flag on resume mmc: dw_mmc: fixed wrong regulator_enable in suspend/resume mmc: sdhi: allow powering down controller with no card inserted mmc: tmio: runtime suspend the controller, where possible mmc: sdhi: support up to 3 interrupt sources mmc: sdhi: print physical base address and clock rate ...
This commit is contained in:
@@ -304,6 +304,7 @@ Code Seq#(hex) Include File Comments
|
||||
0xB0 all RATIO devices in development:
|
||||
<mailto:vgo@ratio.de>
|
||||
0xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca>
|
||||
0xB3 00 linux/mmc/ioctl.h
|
||||
0xC0 00-0F linux/usb/iowarrior.h
|
||||
0xCB 00-1F CBM serial IEC bus in development:
|
||||
<mailto:michael.klein@puffin.lb.shuttle.de>
|
||||
|
||||
@@ -2,3 +2,5 @@
|
||||
- this file
|
||||
mmc-dev-attrs.txt
|
||||
- info on SD and MMC device attributes
|
||||
mmc-dev-parts.txt
|
||||
- info on SD and MMC device partitions
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
SD and MMC Block Device Attributes
|
||||
==================================
|
||||
|
||||
These attributes are defined for the block devices associated with the
|
||||
SD or MMC device.
|
||||
|
||||
The following attributes are read/write.
|
||||
|
||||
force_ro Enforce read-only access even if write protect switch is off.
|
||||
|
||||
SD and MMC Device Attributes
|
||||
============================
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
SD and MMC Device Partitions
|
||||
============================
|
||||
|
||||
Device partitions are additional logical block devices present on the
|
||||
SD/MMC device.
|
||||
|
||||
As of this writing, MMC boot partitions as supported and exposed as
|
||||
/dev/mmcblkXboot0 and /dev/mmcblkXboot1, where X is the index of the
|
||||
parent /dev/mmcblkX.
|
||||
|
||||
MMC Boot Partitions
|
||||
===================
|
||||
|
||||
Read and write access is provided to the two MMC boot partitions. Due to
|
||||
the sensitive nature of the boot partition contents, which often store
|
||||
a bootloader or bootloader configuration tables crucial to booting the
|
||||
platform, write access is disabled by default to reduce the chance of
|
||||
accidental bricking.
|
||||
|
||||
To enable write access to /dev/mmcblkXbootY, disable the forced read-only
|
||||
access with:
|
||||
|
||||
echo 0 > /sys/block/mmcblkXbootY/force_ro
|
||||
|
||||
To re-enable read-only access:
|
||||
|
||||
echo 1 > /sys/block/mmcblkXbootY/force_ro
|
||||
@@ -6800,6 +6800,13 @@ L: lm-sensors@lm-sensors.org
|
||||
S: Maintained
|
||||
F: drivers/hwmon/vt8231.c
|
||||
|
||||
VUB300 USB to SDIO/SD/MMC bridge chip
|
||||
M: Tony Olech <tony.olech@elandigitalsystems.com>
|
||||
L: linux-mmc@vger.kernel.org
|
||||
L: linux-usb@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/mmc/host/vub300.c
|
||||
|
||||
W1 DALLAS'S 1-WIRE BUS
|
||||
M: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
|
||||
S: Maintained
|
||||
|
||||
@@ -24,6 +24,7 @@ struct tegra_sdhci_platform_data {
|
||||
int wp_gpio;
|
||||
int power_gpio;
|
||||
int is_8bit;
|
||||
int pm_flags;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+650
-70
File diff suppressed because it is too large
Load Diff
+57
-59
@@ -212,7 +212,7 @@ static int mmc_test_busy(struct mmc_command *cmd)
|
||||
static int mmc_test_wait_busy(struct mmc_test_card *test)
|
||||
{
|
||||
int ret, busy;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
|
||||
busy = 0;
|
||||
do {
|
||||
@@ -246,18 +246,13 @@ static int mmc_test_buffer_transfer(struct mmc_test_card *test,
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct mmc_request mrq;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command stop;
|
||||
struct mmc_data data;
|
||||
struct mmc_request mrq = {0};
|
||||
struct mmc_command cmd = {0};
|
||||
struct mmc_command stop = {0};
|
||||
struct mmc_data data = {0};
|
||||
|
||||
struct scatterlist sg;
|
||||
|
||||
memset(&mrq, 0, sizeof(struct mmc_request));
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
memset(&stop, 0, sizeof(struct mmc_command));
|
||||
|
||||
mrq.cmd = &cmd;
|
||||
mrq.data = &data;
|
||||
mrq.stop = &stop;
|
||||
@@ -731,15 +726,10 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test,
|
||||
struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
|
||||
unsigned blocks, unsigned blksz, int write)
|
||||
{
|
||||
struct mmc_request mrq;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command stop;
|
||||
struct mmc_data data;
|
||||
|
||||
memset(&mrq, 0, sizeof(struct mmc_request));
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
memset(&stop, 0, sizeof(struct mmc_command));
|
||||
struct mmc_request mrq = {0};
|
||||
struct mmc_command cmd = {0};
|
||||
struct mmc_command stop = {0};
|
||||
struct mmc_data data = {0};
|
||||
|
||||
mrq.cmd = &cmd;
|
||||
mrq.data = &data;
|
||||
@@ -761,18 +751,13 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test,
|
||||
static int mmc_test_broken_transfer(struct mmc_test_card *test,
|
||||
unsigned blocks, unsigned blksz, int write)
|
||||
{
|
||||
struct mmc_request mrq;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command stop;
|
||||
struct mmc_data data;
|
||||
struct mmc_request mrq = {0};
|
||||
struct mmc_command cmd = {0};
|
||||
struct mmc_command stop = {0};
|
||||
struct mmc_data data = {0};
|
||||
|
||||
struct scatterlist sg;
|
||||
|
||||
memset(&mrq, 0, sizeof(struct mmc_request));
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
memset(&stop, 0, sizeof(struct mmc_command));
|
||||
|
||||
mrq.cmd = &cmd;
|
||||
mrq.data = &data;
|
||||
mrq.stop = &stop;
|
||||
@@ -1401,8 +1386,9 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
|
||||
*/
|
||||
static int mmc_test_area_fill(struct mmc_test_card *test)
|
||||
{
|
||||
return mmc_test_area_io(test, test->area.max_tfr, test->area.dev_addr,
|
||||
1, 0, 0);
|
||||
struct mmc_test_area *t = &test->area;
|
||||
|
||||
return mmc_test_area_io(test, t->max_tfr, t->dev_addr, 1, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1415,7 +1401,7 @@ static int mmc_test_area_erase(struct mmc_test_card *test)
|
||||
if (!mmc_can_erase(test->card))
|
||||
return 0;
|
||||
|
||||
return mmc_erase(test->card, t->dev_addr, test->area.max_sz >> 9,
|
||||
return mmc_erase(test->card, t->dev_addr, t->max_sz >> 9,
|
||||
MMC_ERASE_ARG);
|
||||
}
|
||||
|
||||
@@ -1542,8 +1528,10 @@ static int mmc_test_area_prepare_fill(struct mmc_test_card *test)
|
||||
static int mmc_test_best_performance(struct mmc_test_card *test, int write,
|
||||
int max_scatter)
|
||||
{
|
||||
return mmc_test_area_io(test, test->area.max_tfr, test->area.dev_addr,
|
||||
write, max_scatter, 1);
|
||||
struct mmc_test_area *t = &test->area;
|
||||
|
||||
return mmc_test_area_io(test, t->max_tfr, t->dev_addr, write,
|
||||
max_scatter, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1583,18 +1571,19 @@ static int mmc_test_best_write_perf_max_scatter(struct mmc_test_card *test)
|
||||
*/
|
||||
static int mmc_test_profile_read_perf(struct mmc_test_card *test)
|
||||
{
|
||||
struct mmc_test_area *t = &test->area;
|
||||
unsigned long sz;
|
||||
unsigned int dev_addr;
|
||||
int ret;
|
||||
|
||||
for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
|
||||
dev_addr = test->area.dev_addr + (sz >> 9);
|
||||
for (sz = 512; sz < t->max_tfr; sz <<= 1) {
|
||||
dev_addr = t->dev_addr + (sz >> 9);
|
||||
ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
sz = test->area.max_tfr;
|
||||
dev_addr = test->area.dev_addr;
|
||||
sz = t->max_tfr;
|
||||
dev_addr = t->dev_addr;
|
||||
return mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
|
||||
}
|
||||
|
||||
@@ -1603,6 +1592,7 @@ static int mmc_test_profile_read_perf(struct mmc_test_card *test)
|
||||
*/
|
||||
static int mmc_test_profile_write_perf(struct mmc_test_card *test)
|
||||
{
|
||||
struct mmc_test_area *t = &test->area;
|
||||
unsigned long sz;
|
||||
unsigned int dev_addr;
|
||||
int ret;
|
||||
@@ -1610,8 +1600,8 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
|
||||
ret = mmc_test_area_erase(test);
|
||||
if (ret)
|
||||
return ret;
|
||||
for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
|
||||
dev_addr = test->area.dev_addr + (sz >> 9);
|
||||
for (sz = 512; sz < t->max_tfr; sz <<= 1) {
|
||||
dev_addr = t->dev_addr + (sz >> 9);
|
||||
ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1619,8 +1609,8 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
|
||||
ret = mmc_test_area_erase(test);
|
||||
if (ret)
|
||||
return ret;
|
||||
sz = test->area.max_tfr;
|
||||
dev_addr = test->area.dev_addr;
|
||||
sz = t->max_tfr;
|
||||
dev_addr = t->dev_addr;
|
||||
return mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
|
||||
}
|
||||
|
||||
@@ -1629,6 +1619,7 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
|
||||
*/
|
||||
static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
|
||||
{
|
||||
struct mmc_test_area *t = &test->area;
|
||||
unsigned long sz;
|
||||
unsigned int dev_addr;
|
||||
struct timespec ts1, ts2;
|
||||
@@ -1640,8 +1631,8 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
|
||||
if (!mmc_can_erase(test->card))
|
||||
return RESULT_UNSUP_HOST;
|
||||
|
||||
for (sz = 512; sz < test->area.max_sz; sz <<= 1) {
|
||||
dev_addr = test->area.dev_addr + (sz >> 9);
|
||||
for (sz = 512; sz < t->max_sz; sz <<= 1) {
|
||||
dev_addr = t->dev_addr + (sz >> 9);
|
||||
getnstimeofday(&ts1);
|
||||
ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG);
|
||||
if (ret)
|
||||
@@ -1649,7 +1640,7 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
|
||||
getnstimeofday(&ts2);
|
||||
mmc_test_print_rate(test, sz, &ts1, &ts2);
|
||||
}
|
||||
dev_addr = test->area.dev_addr;
|
||||
dev_addr = t->dev_addr;
|
||||
getnstimeofday(&ts1);
|
||||
ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG);
|
||||
if (ret)
|
||||
@@ -1661,12 +1652,13 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
|
||||
|
||||
static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz)
|
||||
{
|
||||
struct mmc_test_area *t = &test->area;
|
||||
unsigned int dev_addr, i, cnt;
|
||||
struct timespec ts1, ts2;
|
||||
int ret;
|
||||
|
||||
cnt = test->area.max_sz / sz;
|
||||
dev_addr = test->area.dev_addr;
|
||||
cnt = t->max_sz / sz;
|
||||
dev_addr = t->dev_addr;
|
||||
getnstimeofday(&ts1);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0);
|
||||
@@ -1684,20 +1676,22 @@ static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz)
|
||||
*/
|
||||
static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
|
||||
{
|
||||
struct mmc_test_area *t = &test->area;
|
||||
unsigned long sz;
|
||||
int ret;
|
||||
|
||||
for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
|
||||
for (sz = 512; sz < t->max_tfr; sz <<= 1) {
|
||||
ret = mmc_test_seq_read_perf(test, sz);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
sz = test->area.max_tfr;
|
||||
sz = t->max_tfr;
|
||||
return mmc_test_seq_read_perf(test, sz);
|
||||
}
|
||||
|
||||
static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
|
||||
{
|
||||
struct mmc_test_area *t = &test->area;
|
||||
unsigned int dev_addr, i, cnt;
|
||||
struct timespec ts1, ts2;
|
||||
int ret;
|
||||
@@ -1705,8 +1699,8 @@ static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
|
||||
ret = mmc_test_area_erase(test);
|
||||
if (ret)
|
||||
return ret;
|
||||
cnt = test->area.max_sz / sz;
|
||||
dev_addr = test->area.dev_addr;
|
||||
cnt = t->max_sz / sz;
|
||||
dev_addr = t->dev_addr;
|
||||
getnstimeofday(&ts1);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0);
|
||||
@@ -1724,15 +1718,16 @@ static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
|
||||
*/
|
||||
static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
|
||||
{
|
||||
struct mmc_test_area *t = &test->area;
|
||||
unsigned long sz;
|
||||
int ret;
|
||||
|
||||
for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
|
||||
for (sz = 512; sz < t->max_tfr; sz <<= 1) {
|
||||
ret = mmc_test_seq_write_perf(test, sz);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
sz = test->area.max_tfr;
|
||||
sz = t->max_tfr;
|
||||
return mmc_test_seq_write_perf(test, sz);
|
||||
}
|
||||
|
||||
@@ -1741,6 +1736,7 @@ static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
|
||||
*/
|
||||
static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test)
|
||||
{
|
||||
struct mmc_test_area *t = &test->area;
|
||||
unsigned long sz;
|
||||
unsigned int dev_addr, i, cnt;
|
||||
struct timespec ts1, ts2;
|
||||
@@ -1752,15 +1748,15 @@ static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test)
|
||||
if (!mmc_can_erase(test->card))
|
||||
return RESULT_UNSUP_HOST;
|
||||
|
||||
for (sz = 512; sz <= test->area.max_sz; sz <<= 1) {
|
||||
for (sz = 512; sz <= t->max_sz; sz <<= 1) {
|
||||
ret = mmc_test_area_erase(test);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = mmc_test_area_fill(test);
|
||||
if (ret)
|
||||
return ret;
|
||||
cnt = test->area.max_sz / sz;
|
||||
dev_addr = test->area.dev_addr;
|
||||
cnt = t->max_sz / sz;
|
||||
dev_addr = t->dev_addr;
|
||||
getnstimeofday(&ts1);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
ret = mmc_erase(test->card, dev_addr, sz >> 9,
|
||||
@@ -1823,11 +1819,12 @@ static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print,
|
||||
|
||||
static int mmc_test_random_perf(struct mmc_test_card *test, int write)
|
||||
{
|
||||
struct mmc_test_area *t = &test->area;
|
||||
unsigned int next;
|
||||
unsigned long sz;
|
||||
int ret;
|
||||
|
||||
for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
|
||||
for (sz = 512; sz < t->max_tfr; sz <<= 1) {
|
||||
/*
|
||||
* When writing, try to get more consistent results by running
|
||||
* the test twice with exactly the same I/O but outputting the
|
||||
@@ -1844,7 +1841,7 @@ static int mmc_test_random_perf(struct mmc_test_card *test, int write)
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
sz = test->area.max_tfr;
|
||||
sz = t->max_tfr;
|
||||
if (write) {
|
||||
next = rnd_next;
|
||||
ret = mmc_test_rnd_perf(test, write, 0, sz);
|
||||
@@ -1874,17 +1871,18 @@ static int mmc_test_random_write_perf(struct mmc_test_card *test)
|
||||
static int mmc_test_seq_perf(struct mmc_test_card *test, int write,
|
||||
unsigned int tot_sz, int max_scatter)
|
||||
{
|
||||
struct mmc_test_area *t = &test->area;
|
||||
unsigned int dev_addr, i, cnt, sz, ssz;
|
||||
struct timespec ts1, ts2;
|
||||
int ret;
|
||||
|
||||
sz = test->area.max_tfr;
|
||||
sz = t->max_tfr;
|
||||
|
||||
/*
|
||||
* In the case of a maximally scattered transfer, the maximum transfer
|
||||
* size is further limited by using PAGE_SIZE segments.
|
||||
*/
|
||||
if (max_scatter) {
|
||||
struct mmc_test_area *t = &test->area;
|
||||
unsigned long max_tfr;
|
||||
|
||||
if (t->max_seg_sz >= PAGE_SIZE)
|
||||
|
||||
@@ -343,18 +343,14 @@ unsigned int mmc_queue_map_sg(struct mmc_queue *mq)
|
||||
*/
|
||||
void mmc_queue_bounce_pre(struct mmc_queue *mq)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!mq->bounce_buf)
|
||||
return;
|
||||
|
||||
if (rq_data_dir(mq->req) != WRITE)
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
sg_copy_to_buffer(mq->bounce_sg, mq->bounce_sg_len,
|
||||
mq->bounce_buf, mq->sg[0].length);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -363,17 +359,13 @@ void mmc_queue_bounce_pre(struct mmc_queue *mq)
|
||||
*/
|
||||
void mmc_queue_bounce_post(struct mmc_queue *mq)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!mq->bounce_buf)
|
||||
return;
|
||||
|
||||
if (rq_data_dir(mq->req) != READ)
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
sg_copy_from_buffer(mq->bounce_sg, mq->bounce_sg_len,
|
||||
mq->bounce_buf, mq->sg[0].length);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
|
||||
@@ -274,8 +274,12 @@ int mmc_add_card(struct mmc_card *card)
|
||||
break;
|
||||
case MMC_TYPE_SD:
|
||||
type = "SD";
|
||||
if (mmc_card_blockaddr(card))
|
||||
type = "SDHC";
|
||||
if (mmc_card_blockaddr(card)) {
|
||||
if (mmc_card_ext_capacity(card))
|
||||
type = "SDXC";
|
||||
else
|
||||
type = "SDHC";
|
||||
}
|
||||
break;
|
||||
case MMC_TYPE_SDIO:
|
||||
type = "SDIO";
|
||||
@@ -299,7 +303,8 @@ int mmc_add_card(struct mmc_card *card)
|
||||
} else {
|
||||
printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
|
||||
mmc_hostname(card->host),
|
||||
mmc_card_highspeed(card) ? "high speed " : "",
|
||||
mmc_sd_card_uhs(card) ? "ultra high speed " :
|
||||
(mmc_card_highspeed(card) ? "high speed " : ""),
|
||||
mmc_card_ddr_mode(card) ? "DDR " : "",
|
||||
type, card->rca);
|
||||
}
|
||||
|
||||
+71
-40
@@ -236,12 +236,10 @@ EXPORT_SYMBOL(mmc_wait_for_req);
|
||||
*/
|
||||
int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
|
||||
{
|
||||
struct mmc_request mrq;
|
||||
struct mmc_request mrq = {0};
|
||||
|
||||
WARN_ON(!host->claimed);
|
||||
|
||||
memset(&mrq, 0, sizeof(struct mmc_request));
|
||||
|
||||
memset(cmd->resp, 0, sizeof(cmd->resp));
|
||||
cmd->retries = retries;
|
||||
|
||||
@@ -719,23 +717,13 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
|
||||
mmc_set_ios(host);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change data bus width and DDR mode of a host.
|
||||
*/
|
||||
void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
|
||||
unsigned int ddr)
|
||||
{
|
||||
host->ios.bus_width = width;
|
||||
host->ios.ddr = ddr;
|
||||
mmc_set_ios(host);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change data bus width of a host.
|
||||
*/
|
||||
void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
|
||||
{
|
||||
mmc_set_bus_width_ddr(host, width, MMC_SDR_MODE);
|
||||
host->ios.bus_width = width;
|
||||
mmc_set_ios(host);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -944,6 +932,38 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
|
||||
return ocr;
|
||||
}
|
||||
|
||||
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11)
|
||||
{
|
||||
struct mmc_command cmd = {0};
|
||||
int err = 0;
|
||||
|
||||
BUG_ON(!host);
|
||||
|
||||
/*
|
||||
* Send CMD11 only if the request is to switch the card to
|
||||
* 1.8V signalling.
|
||||
*/
|
||||
if ((signal_voltage != MMC_SIGNAL_VOLTAGE_330) && cmd11) {
|
||||
cmd.opcode = SD_SWITCH_VOLTAGE;
|
||||
cmd.arg = 0;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
|
||||
|
||||
err = mmc_wait_for_cmd(host, &cmd, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
host->ios.signal_voltage = signal_voltage;
|
||||
|
||||
if (host->ops->start_signal_voltage_switch)
|
||||
err = host->ops->start_signal_voltage_switch(host, &host->ios);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select timing parameters for host.
|
||||
*/
|
||||
@@ -953,6 +973,15 @@ void mmc_set_timing(struct mmc_host *host, unsigned int timing)
|
||||
mmc_set_ios(host);
|
||||
}
|
||||
|
||||
/*
|
||||
* Select appropriate driver type for host.
|
||||
*/
|
||||
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
|
||||
{
|
||||
host->ios.drv_type = drv_type;
|
||||
mmc_set_ios(host);
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply power to the MMC stack. This is a two-stage process.
|
||||
* First, we enable power to the card without the clock running.
|
||||
@@ -1187,9 +1216,8 @@ void mmc_init_erase(struct mmc_card *card)
|
||||
}
|
||||
}
|
||||
|
||||
static void mmc_set_mmc_erase_timeout(struct mmc_card *card,
|
||||
struct mmc_command *cmd,
|
||||
unsigned int arg, unsigned int qty)
|
||||
static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
|
||||
unsigned int arg, unsigned int qty)
|
||||
{
|
||||
unsigned int erase_timeout;
|
||||
|
||||
@@ -1246,44 +1274,48 @@ static void mmc_set_mmc_erase_timeout(struct mmc_card *card,
|
||||
if (mmc_host_is_spi(card->host) && erase_timeout < 1000)
|
||||
erase_timeout = 1000;
|
||||
|
||||
cmd->erase_timeout = erase_timeout;
|
||||
return erase_timeout;
|
||||
}
|
||||
|
||||
static void mmc_set_sd_erase_timeout(struct mmc_card *card,
|
||||
struct mmc_command *cmd, unsigned int arg,
|
||||
unsigned int qty)
|
||||
static unsigned int mmc_sd_erase_timeout(struct mmc_card *card,
|
||||
unsigned int arg,
|
||||
unsigned int qty)
|
||||
{
|
||||
unsigned int erase_timeout;
|
||||
|
||||
if (card->ssr.erase_timeout) {
|
||||
/* Erase timeout specified in SD Status Register (SSR) */
|
||||
cmd->erase_timeout = card->ssr.erase_timeout * qty +
|
||||
card->ssr.erase_offset;
|
||||
erase_timeout = card->ssr.erase_timeout * qty +
|
||||
card->ssr.erase_offset;
|
||||
} else {
|
||||
/*
|
||||
* Erase timeout not specified in SD Status Register (SSR) so
|
||||
* use 250ms per write block.
|
||||
*/
|
||||
cmd->erase_timeout = 250 * qty;
|
||||
erase_timeout = 250 * qty;
|
||||
}
|
||||
|
||||
/* Must not be less than 1 second */
|
||||
if (cmd->erase_timeout < 1000)
|
||||
cmd->erase_timeout = 1000;
|
||||
if (erase_timeout < 1000)
|
||||
erase_timeout = 1000;
|
||||
|
||||
return erase_timeout;
|
||||
}
|
||||
|
||||
static void mmc_set_erase_timeout(struct mmc_card *card,
|
||||
struct mmc_command *cmd, unsigned int arg,
|
||||
unsigned int qty)
|
||||
static unsigned int mmc_erase_timeout(struct mmc_card *card,
|
||||
unsigned int arg,
|
||||
unsigned int qty)
|
||||
{
|
||||
if (mmc_card_sd(card))
|
||||
mmc_set_sd_erase_timeout(card, cmd, arg, qty);
|
||||
return mmc_sd_erase_timeout(card, arg, qty);
|
||||
else
|
||||
mmc_set_mmc_erase_timeout(card, cmd, arg, qty);
|
||||
return mmc_mmc_erase_timeout(card, arg, qty);
|
||||
}
|
||||
|
||||
static int mmc_do_erase(struct mmc_card *card, unsigned int from,
|
||||
unsigned int to, unsigned int arg)
|
||||
{
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
unsigned int qty = 0;
|
||||
int err;
|
||||
|
||||
@@ -1317,7 +1349,6 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
|
||||
to <<= 9;
|
||||
}
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
if (mmc_card_sd(card))
|
||||
cmd.opcode = SD_ERASE_WR_BLK_START;
|
||||
else
|
||||
@@ -1351,7 +1382,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
|
||||
cmd.opcode = MMC_ERASE;
|
||||
cmd.arg = arg;
|
||||
cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
|
||||
mmc_set_erase_timeout(card, &cmd, arg, qty);
|
||||
cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty);
|
||||
err = mmc_wait_for_cmd(card->host, &cmd, 0);
|
||||
if (err) {
|
||||
printk(KERN_ERR "mmc_erase: erase error %d, status %#x\n",
|
||||
@@ -1487,12 +1518,11 @@ EXPORT_SYMBOL(mmc_erase_group_aligned);
|
||||
|
||||
int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
|
||||
{
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
|
||||
if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
|
||||
return 0;
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
cmd.opcode = MMC_SET_BLOCKLEN;
|
||||
cmd.arg = blocklen;
|
||||
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
|
||||
@@ -1578,7 +1608,7 @@ void mmc_rescan(struct work_struct *work)
|
||||
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
|
||||
if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
|
||||
break;
|
||||
if (freqs[i] < host->f_min)
|
||||
if (freqs[i] <= host->f_min)
|
||||
break;
|
||||
}
|
||||
mmc_release_host(host);
|
||||
@@ -1746,7 +1776,7 @@ int mmc_suspend_host(struct mmc_host *host)
|
||||
}
|
||||
mmc_bus_put(host);
|
||||
|
||||
if (!err && !(host->pm_flags & MMC_PM_KEEP_POWER))
|
||||
if (!err && !mmc_card_keep_power(host))
|
||||
mmc_power_off(host);
|
||||
|
||||
return err;
|
||||
@@ -1764,7 +1794,7 @@ int mmc_resume_host(struct mmc_host *host)
|
||||
|
||||
mmc_bus_get(host);
|
||||
if (host->bus_ops && !host->bus_dead) {
|
||||
if (!(host->pm_flags & MMC_PM_KEEP_POWER)) {
|
||||
if (!mmc_card_keep_power(host)) {
|
||||
mmc_power_up(host);
|
||||
mmc_select_voltage(host, host->ocr);
|
||||
/*
|
||||
@@ -1789,6 +1819,7 @@ int mmc_resume_host(struct mmc_host *host)
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
host->pm_flags &= ~MMC_PM_KEEP_POWER;
|
||||
mmc_bus_put(host);
|
||||
|
||||
return err;
|
||||
|
||||
@@ -38,10 +38,11 @@ void mmc_ungate_clock(struct mmc_host *host);
|
||||
void mmc_set_ungated(struct mmc_host *host);
|
||||
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
|
||||
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
|
||||
void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
|
||||
unsigned int ddr);
|
||||
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
|
||||
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage,
|
||||
bool cmd11);
|
||||
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
|
||||
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
|
||||
|
||||
static inline void mmc_delay(unsigned int ms)
|
||||
{
|
||||
@@ -61,8 +62,6 @@ int mmc_attach_mmc(struct mmc_host *host);
|
||||
int mmc_attach_sd(struct mmc_host *host);
|
||||
int mmc_attach_sdio(struct mmc_host *host);
|
||||
|
||||
void mmc_fixup_device(struct mmc_card *card);
|
||||
|
||||
/* Module parameters */
|
||||
extern int use_spi_crc;
|
||||
|
||||
|
||||
@@ -325,12 +325,12 @@ int mmc_add_host(struct mmc_host *host)
|
||||
WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
|
||||
!host->ops->enable_sdio_irq);
|
||||
|
||||
led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
|
||||
|
||||
err = device_add(&host->class_dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
mmc_add_host_debugfs(host);
|
||||
#endif
|
||||
|
||||
+167
-21
@@ -20,6 +20,7 @@
|
||||
#include "core.h"
|
||||
#include "bus.h"
|
||||
#include "mmc_ops.h"
|
||||
#include "sd_ops.h"
|
||||
|
||||
static const unsigned int tran_exp[] = {
|
||||
10000, 100000, 1000000, 10000000,
|
||||
@@ -173,14 +174,17 @@ static int mmc_decode_csd(struct mmc_card *card)
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and decode extended CSD.
|
||||
* Read extended CSD.
|
||||
*/
|
||||
static int mmc_read_ext_csd(struct mmc_card *card)
|
||||
static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
|
||||
{
|
||||
int err;
|
||||
u8 *ext_csd;
|
||||
|
||||
BUG_ON(!card);
|
||||
BUG_ON(!new_ext_csd);
|
||||
|
||||
*new_ext_csd = NULL;
|
||||
|
||||
if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
|
||||
return 0;
|
||||
@@ -198,12 +202,15 @@ static int mmc_read_ext_csd(struct mmc_card *card)
|
||||
|
||||
err = mmc_send_ext_csd(card, ext_csd);
|
||||
if (err) {
|
||||
kfree(ext_csd);
|
||||
*new_ext_csd = NULL;
|
||||
|
||||
/* If the host or the card can't do the switch,
|
||||
* fail more gracefully. */
|
||||
if ((err != -EINVAL)
|
||||
&& (err != -ENOSYS)
|
||||
&& (err != -EFAULT))
|
||||
goto out;
|
||||
return err;
|
||||
|
||||
/*
|
||||
* High capacity cards should have this "magic" size
|
||||
@@ -221,9 +228,23 @@ static int mmc_read_ext_csd(struct mmc_card *card)
|
||||
mmc_hostname(card->host));
|
||||
err = 0;
|
||||
}
|
||||
} else
|
||||
*new_ext_csd = ext_csd;
|
||||
|
||||
goto out;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode extended CSD.
|
||||
*/
|
||||
static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
BUG_ON(!card);
|
||||
|
||||
if (!ext_csd)
|
||||
return 0;
|
||||
|
||||
/* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
|
||||
if (card->csd.structure == 3) {
|
||||
@@ -288,6 +309,10 @@ static int mmc_read_ext_csd(struct mmc_card *card)
|
||||
|
||||
if (card->ext_csd.rev >= 3) {
|
||||
u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
|
||||
card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG];
|
||||
|
||||
/* EXT_CSD value is in units of 10ms, but we store in ms */
|
||||
card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME];
|
||||
|
||||
/* Sleep / awake timeout in 100ns units */
|
||||
if (sa_shift > 0 && sa_shift <= 0x17)
|
||||
@@ -299,6 +324,14 @@ static int mmc_read_ext_csd(struct mmc_card *card)
|
||||
ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
|
||||
card->ext_csd.hc_erase_size =
|
||||
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10;
|
||||
|
||||
card->ext_csd.rel_sectors = ext_csd[EXT_CSD_REL_WR_SEC_C];
|
||||
|
||||
/*
|
||||
* There are two boot regions of equal size, defined in
|
||||
* multiples of 128K.
|
||||
*/
|
||||
card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;
|
||||
}
|
||||
|
||||
if (card->ext_csd.rev >= 4) {
|
||||
@@ -350,14 +383,78 @@ static int mmc_read_ext_csd(struct mmc_card *card)
|
||||
ext_csd[EXT_CSD_TRIM_MULT];
|
||||
}
|
||||
|
||||
if (card->ext_csd.rev >= 5)
|
||||
card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
|
||||
|
||||
if (ext_csd[EXT_CSD_ERASED_MEM_CONT])
|
||||
card->erased_byte = 0xFF;
|
||||
else
|
||||
card->erased_byte = 0x0;
|
||||
|
||||
out:
|
||||
kfree(ext_csd);
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void mmc_free_ext_csd(u8 *ext_csd)
|
||||
{
|
||||
kfree(ext_csd);
|
||||
}
|
||||
|
||||
|
||||
static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd,
|
||||
unsigned bus_width)
|
||||
{
|
||||
u8 *bw_ext_csd;
|
||||
int err;
|
||||
|
||||
err = mmc_get_ext_csd(card, &bw_ext_csd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((ext_csd == NULL || bw_ext_csd == NULL)) {
|
||||
if (bus_width != MMC_BUS_WIDTH_1)
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bus_width == MMC_BUS_WIDTH_1)
|
||||
goto out;
|
||||
|
||||
/* only compare read only fields */
|
||||
err = (!(ext_csd[EXT_CSD_PARTITION_SUPPORT] ==
|
||||
bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
|
||||
(ext_csd[EXT_CSD_ERASED_MEM_CONT] ==
|
||||
bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
|
||||
(ext_csd[EXT_CSD_REV] ==
|
||||
bw_ext_csd[EXT_CSD_REV]) &&
|
||||
(ext_csd[EXT_CSD_STRUCTURE] ==
|
||||
bw_ext_csd[EXT_CSD_STRUCTURE]) &&
|
||||
(ext_csd[EXT_CSD_CARD_TYPE] ==
|
||||
bw_ext_csd[EXT_CSD_CARD_TYPE]) &&
|
||||
(ext_csd[EXT_CSD_S_A_TIMEOUT] ==
|
||||
bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) &&
|
||||
(ext_csd[EXT_CSD_HC_WP_GRP_SIZE] ==
|
||||
bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
|
||||
(ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] ==
|
||||
bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) &&
|
||||
(ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] ==
|
||||
bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
|
||||
(ext_csd[EXT_CSD_SEC_TRIM_MULT] ==
|
||||
bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) &&
|
||||
(ext_csd[EXT_CSD_SEC_ERASE_MULT] ==
|
||||
bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) &&
|
||||
(ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] ==
|
||||
bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) &&
|
||||
(ext_csd[EXT_CSD_TRIM_MULT] ==
|
||||
bw_ext_csd[EXT_CSD_TRIM_MULT]) &&
|
||||
memcmp(&ext_csd[EXT_CSD_SEC_CNT],
|
||||
&bw_ext_csd[EXT_CSD_SEC_CNT],
|
||||
4) != 0);
|
||||
if (err)
|
||||
err = -EINVAL;
|
||||
|
||||
out:
|
||||
mmc_free_ext_csd(bw_ext_csd);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -422,6 +519,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
u32 cid[4];
|
||||
unsigned int max_dtr;
|
||||
u32 rocr;
|
||||
u8 *ext_csd = NULL;
|
||||
|
||||
BUG_ON(!host);
|
||||
WARN_ON(!host->claimed);
|
||||
@@ -520,7 +618,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
/*
|
||||
* Fetch and process extended CSD.
|
||||
*/
|
||||
err = mmc_read_ext_csd(card);
|
||||
|
||||
err = mmc_get_ext_csd(card, &ext_csd);
|
||||
if (err)
|
||||
goto free_card;
|
||||
err = mmc_read_ext_csd(card, ext_csd);
|
||||
if (err)
|
||||
goto free_card;
|
||||
|
||||
@@ -542,7 +644,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
*/
|
||||
if (card->ext_csd.enhanced_area_en) {
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_ERASE_GROUP_DEF, 1);
|
||||
EXT_CSD_ERASE_GROUP_DEF, 1, 0);
|
||||
|
||||
if (err && err != -EBADMSG)
|
||||
goto free_card;
|
||||
@@ -567,13 +669,25 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure eMMC user default partition is enabled
|
||||
*/
|
||||
if (card->ext_csd.part_config & EXT_CSD_PART_CONFIG_ACC_MASK) {
|
||||
card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG,
|
||||
card->ext_csd.part_config,
|
||||
card->ext_csd.part_time);
|
||||
if (err && err != -EBADMSG)
|
||||
goto free_card;
|
||||
}
|
||||
|
||||
/*
|
||||
* Activate high speed (if supported)
|
||||
*/
|
||||
if ((card->ext_csd.hs_max_dtr != 0) &&
|
||||
(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HS_TIMING, 1);
|
||||
EXT_CSD_HS_TIMING, 1, 0);
|
||||
if (err && err != -EBADMSG)
|
||||
goto free_card;
|
||||
|
||||
@@ -606,10 +720,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
*/
|
||||
if (mmc_card_highspeed(card)) {
|
||||
if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
|
||||
&& (host->caps & (MMC_CAP_1_8V_DDR)))
|
||||
&& ((host->caps & (MMC_CAP_1_8V_DDR |
|
||||
MMC_CAP_UHS_DDR50))
|
||||
== (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50)))
|
||||
ddr = MMC_1_8V_DDR_MODE;
|
||||
else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
|
||||
&& (host->caps & (MMC_CAP_1_2V_DDR)))
|
||||
&& ((host->caps & (MMC_CAP_1_2V_DDR |
|
||||
MMC_CAP_UHS_DDR50))
|
||||
== (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50)))
|
||||
ddr = MMC_1_2V_DDR_MODE;
|
||||
}
|
||||
|
||||
@@ -640,18 +758,22 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
ddr = 0; /* no DDR for 1-bit width */
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_BUS_WIDTH,
|
||||
ext_csd_bits[idx][0]);
|
||||
ext_csd_bits[idx][0],
|
||||
0);
|
||||
if (!err) {
|
||||
mmc_set_bus_width_ddr(card->host,
|
||||
bus_width, MMC_SDR_MODE);
|
||||
mmc_set_bus_width(card->host, bus_width);
|
||||
|
||||
/*
|
||||
* If controller can't handle bus width test,
|
||||
* use the highest bus width to maintain
|
||||
* compatibility with previous MMC behavior.
|
||||
* compare ext_csd previously read in 1 bit mode
|
||||
* against ext_csd at new bus width
|
||||
*/
|
||||
if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
|
||||
break;
|
||||
err = mmc_bus_test(card, bus_width);
|
||||
err = mmc_compare_ext_csds(card,
|
||||
ext_csd,
|
||||
bus_width);
|
||||
else
|
||||
err = mmc_bus_test(card, bus_width);
|
||||
if (!err)
|
||||
break;
|
||||
}
|
||||
@@ -659,8 +781,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
|
||||
if (!err && ddr) {
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_BUS_WIDTH,
|
||||
ext_csd_bits[idx][1]);
|
||||
EXT_CSD_BUS_WIDTH,
|
||||
ext_csd_bits[idx][1],
|
||||
0);
|
||||
}
|
||||
if (err) {
|
||||
printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
|
||||
@@ -668,20 +791,43 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
1 << bus_width, ddr);
|
||||
goto free_card;
|
||||
} else if (ddr) {
|
||||
/*
|
||||
* eMMC cards can support 3.3V to 1.2V i/o (vccq)
|
||||
* signaling.
|
||||
*
|
||||
* EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
|
||||
*
|
||||
* 1.8V vccq at 3.3V core voltage (vcc) is not required
|
||||
* in the JEDEC spec for DDR.
|
||||
*
|
||||
* Do not force change in vccq since we are obviously
|
||||
* working and no change to vccq is needed.
|
||||
*
|
||||
* WARNING: eMMC rules are NOT the same as SD DDR
|
||||
*/
|
||||
if (ddr == EXT_CSD_CARD_TYPE_DDR_1_2V) {
|
||||
err = mmc_set_signal_voltage(host,
|
||||
MMC_SIGNAL_VOLTAGE_120, 0);
|
||||
if (err)
|
||||
goto err;
|
||||
}
|
||||
mmc_card_set_ddr_mode(card);
|
||||
mmc_set_bus_width_ddr(card->host, bus_width, ddr);
|
||||
mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
|
||||
mmc_set_bus_width(card->host, bus_width);
|
||||
}
|
||||
}
|
||||
|
||||
if (!oldcard)
|
||||
host->card = card;
|
||||
|
||||
mmc_free_ext_csd(ext_csd);
|
||||
return 0;
|
||||
|
||||
free_card:
|
||||
if (!oldcard)
|
||||
mmc_remove_card(card);
|
||||
err:
|
||||
mmc_free_ext_csd(ext_csd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
+32
-48
@@ -23,12 +23,10 @@
|
||||
static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
|
||||
{
|
||||
int err;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
|
||||
BUG_ON(!host);
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = MMC_SELECT_CARD;
|
||||
|
||||
if (card) {
|
||||
@@ -60,15 +58,13 @@ int mmc_deselect_cards(struct mmc_host *host)
|
||||
|
||||
int mmc_card_sleepawake(struct mmc_host *host, int sleep)
|
||||
{
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
struct mmc_card *card = host->card;
|
||||
int err;
|
||||
|
||||
if (sleep)
|
||||
mmc_deselect_cards(host);
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = MMC_SLEEP_AWAKE;
|
||||
cmd.arg = card->rca << 16;
|
||||
if (sleep)
|
||||
@@ -97,7 +93,7 @@ int mmc_card_sleepawake(struct mmc_host *host, int sleep)
|
||||
int mmc_go_idle(struct mmc_host *host)
|
||||
{
|
||||
int err;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
|
||||
/*
|
||||
* Non-SPI hosts need to prevent chipselect going active during
|
||||
@@ -113,8 +109,6 @@ int mmc_go_idle(struct mmc_host *host)
|
||||
mmc_delay(1);
|
||||
}
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = MMC_GO_IDLE_STATE;
|
||||
cmd.arg = 0;
|
||||
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
|
||||
@@ -135,13 +129,11 @@ int mmc_go_idle(struct mmc_host *host)
|
||||
|
||||
int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
|
||||
{
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
int i, err = 0;
|
||||
|
||||
BUG_ON(!host);
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = MMC_SEND_OP_COND;
|
||||
cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
|
||||
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
|
||||
@@ -178,13 +170,11 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
|
||||
int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
|
||||
{
|
||||
int err;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
|
||||
BUG_ON(!host);
|
||||
BUG_ON(!cid);
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = MMC_ALL_SEND_CID;
|
||||
cmd.arg = 0;
|
||||
cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
|
||||
@@ -201,13 +191,11 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
|
||||
int mmc_set_relative_addr(struct mmc_card *card)
|
||||
{
|
||||
int err;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
|
||||
BUG_ON(!card);
|
||||
BUG_ON(!card->host);
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = MMC_SET_RELATIVE_ADDR;
|
||||
cmd.arg = card->rca << 16;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
|
||||
@@ -223,13 +211,11 @@ static int
|
||||
mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
|
||||
{
|
||||
int err;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
|
||||
BUG_ON(!host);
|
||||
BUG_ON(!cxd);
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = opcode;
|
||||
cmd.arg = arg;
|
||||
cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
|
||||
@@ -247,9 +233,9 @@ static int
|
||||
mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
|
||||
u32 opcode, void *buf, unsigned len)
|
||||
{
|
||||
struct mmc_request mrq;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_data data;
|
||||
struct mmc_request mrq = {0};
|
||||
struct mmc_command cmd = {0};
|
||||
struct mmc_data data = {0};
|
||||
struct scatterlist sg;
|
||||
void *data_buf;
|
||||
|
||||
@@ -260,10 +246,6 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
|
||||
if (data_buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(&mrq, 0, sizeof(struct mmc_request));
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
|
||||
mrq.cmd = &cmd;
|
||||
mrq.data = &data;
|
||||
|
||||
@@ -355,11 +337,9 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
|
||||
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
|
||||
{
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
int err;
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = MMC_SPI_READ_OCR;
|
||||
cmd.arg = highcap ? (1 << 30) : 0;
|
||||
cmd.flags = MMC_RSP_SPI_R3;
|
||||
@@ -372,11 +352,9 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
|
||||
|
||||
int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
|
||||
{
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
int err;
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = MMC_SPI_CRC_ON_OFF;
|
||||
cmd.flags = MMC_RSP_SPI_R1;
|
||||
cmd.arg = use_crc;
|
||||
@@ -387,23 +365,34 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
|
||||
return err;
|
||||
}
|
||||
|
||||
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
|
||||
/**
|
||||
* mmc_switch - modify EXT_CSD register
|
||||
* @card: the MMC card associated with the data transfer
|
||||
* @set: cmd set values
|
||||
* @index: EXT_CSD register index
|
||||
* @value: value to program into EXT_CSD register
|
||||
* @timeout_ms: timeout (ms) for operation performed by register write,
|
||||
* timeout of zero implies maximum possible timeout
|
||||
*
|
||||
* Modifies the EXT_CSD register for selected card.
|
||||
*/
|
||||
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
|
||||
unsigned int timeout_ms)
|
||||
{
|
||||
int err;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
u32 status;
|
||||
|
||||
BUG_ON(!card);
|
||||
BUG_ON(!card->host);
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = MMC_SWITCH;
|
||||
cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
|
||||
(index << 16) |
|
||||
(value << 8) |
|
||||
set;
|
||||
cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
|
||||
cmd.cmd_timeout_ms = timeout_ms;
|
||||
|
||||
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
|
||||
if (err)
|
||||
@@ -433,17 +422,16 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_switch);
|
||||
|
||||
int mmc_send_status(struct mmc_card *card, u32 *status)
|
||||
{
|
||||
int err;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
|
||||
BUG_ON(!card);
|
||||
BUG_ON(!card->host);
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = MMC_SEND_STATUS;
|
||||
if (!mmc_host_is_spi(card->host))
|
||||
cmd.arg = card->rca << 16;
|
||||
@@ -466,9 +454,9 @@ static int
|
||||
mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
|
||||
u8 len)
|
||||
{
|
||||
struct mmc_request mrq;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_data data;
|
||||
struct mmc_request mrq = {0};
|
||||
struct mmc_command cmd = {0};
|
||||
struct mmc_data data = {0};
|
||||
struct scatterlist sg;
|
||||
u8 *data_buf;
|
||||
u8 *test_buf;
|
||||
@@ -497,10 +485,6 @@ mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
|
||||
if (opcode == MMC_BUS_TEST_W)
|
||||
memcpy(data_buf, test_buf, len);
|
||||
|
||||
memset(&mrq, 0, sizeof(struct mmc_request));
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
|
||||
mrq.cmd = &cmd;
|
||||
mrq.data = &data;
|
||||
cmd.opcode = opcode;
|
||||
|
||||
@@ -20,7 +20,6 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
|
||||
int mmc_set_relative_addr(struct mmc_card *card);
|
||||
int mmc_send_csd(struct mmc_card *card, u32 *csd);
|
||||
int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
|
||||
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
|
||||
int mmc_send_status(struct mmc_card *card, u32 *status);
|
||||
int mmc_send_cid(struct mmc_host *host, u32 *cid);
|
||||
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
|
||||
|
||||
+42
-47
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* This file contains work-arounds for many known sdio hardware
|
||||
* bugs.
|
||||
* This file contains work-arounds for many known SD/MMC
|
||||
* and SDIO hardware bugs.
|
||||
*
|
||||
* Copyright (c) 2011 Andrei Warkentin <andreiw@motorola.com>
|
||||
* Copyright (c) 2011 Pierre Tardy <tardyp@gmail.com>
|
||||
* Inspired from pci fixup code:
|
||||
* Copyright (c) 1999 Martin Mares <mj@ucw.cz>
|
||||
@@ -11,34 +12,14 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
||||
/*
|
||||
* The world is not perfect and supplies us with broken mmc/sdio devices.
|
||||
* For at least a part of these bugs we need a work-around
|
||||
*/
|
||||
#ifndef SDIO_VENDOR_ID_TI
|
||||
#define SDIO_VENDOR_ID_TI 0x0097
|
||||
#endif
|
||||
|
||||
struct mmc_fixup {
|
||||
u16 vendor, device; /* You can use SDIO_ANY_ID here of course */
|
||||
void (*vendor_fixup)(struct mmc_card *card, int data);
|
||||
int data;
|
||||
};
|
||||
|
||||
/*
|
||||
* This hook just adds a quirk unconditionnally
|
||||
*/
|
||||
static void __maybe_unused add_quirk(struct mmc_card *card, int data)
|
||||
{
|
||||
card->quirks |= data;
|
||||
}
|
||||
|
||||
/*
|
||||
* This hook just removes a quirk unconditionnally
|
||||
*/
|
||||
static void __maybe_unused remove_quirk(struct mmc_card *card, int data)
|
||||
{
|
||||
card->quirks &= ~data;
|
||||
}
|
||||
#ifndef SDIO_DEVICE_ID_TI_WL1271
|
||||
#define SDIO_DEVICE_ID_TI_WL1271 0x4076
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This hook just adds a quirk for all sdio devices
|
||||
@@ -49,33 +30,47 @@ static void add_quirk_for_sdio_devices(struct mmc_card *card, int data)
|
||||
card->quirks |= data;
|
||||
}
|
||||
|
||||
#ifndef SDIO_VENDOR_ID_TI
|
||||
#define SDIO_VENDOR_ID_TI 0x0097
|
||||
#endif
|
||||
|
||||
#ifndef SDIO_DEVICE_ID_TI_WL1271
|
||||
#define SDIO_DEVICE_ID_TI_WL1271 0x4076
|
||||
#endif
|
||||
|
||||
static const struct mmc_fixup mmc_fixup_methods[] = {
|
||||
/* by default sdio devices are considered CLK_GATING broken */
|
||||
/* good cards will be whitelisted as they are tested */
|
||||
{ SDIO_ANY_ID, SDIO_ANY_ID,
|
||||
add_quirk_for_sdio_devices, MMC_QUIRK_BROKEN_CLK_GATING },
|
||||
{ SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
|
||||
remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING },
|
||||
{ 0 }
|
||||
SDIO_FIXUP(SDIO_ANY_ID, SDIO_ANY_ID,
|
||||
add_quirk_for_sdio_devices,
|
||||
MMC_QUIRK_BROKEN_CLK_GATING),
|
||||
|
||||
SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
|
||||
remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
|
||||
|
||||
SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
|
||||
add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
|
||||
|
||||
SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
|
||||
add_quirk, MMC_QUIRK_DISABLE_CD),
|
||||
|
||||
END_FIXUP
|
||||
};
|
||||
|
||||
void mmc_fixup_device(struct mmc_card *card)
|
||||
void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
|
||||
{
|
||||
const struct mmc_fixup *f;
|
||||
u64 rev = cid_rev_card(card);
|
||||
|
||||
for (f = mmc_fixup_methods; f->vendor_fixup; f++) {
|
||||
if ((f->vendor == card->cis.vendor
|
||||
|| f->vendor == (u16) SDIO_ANY_ID) &&
|
||||
(f->device == card->cis.device
|
||||
|| f->device == (u16) SDIO_ANY_ID)) {
|
||||
/* Non-core specific workarounds. */
|
||||
if (!table)
|
||||
table = mmc_fixup_methods;
|
||||
|
||||
for (f = table; f->vendor_fixup; f++) {
|
||||
if ((f->manfid == CID_MANFID_ANY ||
|
||||
f->manfid == card->cid.manfid) &&
|
||||
(f->oemid == CID_OEMID_ANY ||
|
||||
f->oemid == card->cid.oemid) &&
|
||||
(f->name == CID_NAME_ANY ||
|
||||
!strncmp(f->name, card->cid.prod_name,
|
||||
sizeof(card->cid.prod_name))) &&
|
||||
(f->cis_vendor == card->cis.vendor ||
|
||||
f->cis_vendor == (u16) SDIO_ANY_ID) &&
|
||||
(f->cis_device == card->cis.device ||
|
||||
f->cis_device == (u16) SDIO_ANY_ID) &&
|
||||
rev >= f->rev_start && rev <= f->rev_end) {
|
||||
dev_dbg(&card->dev, "calling %pF\n", f->vendor_fixup);
|
||||
f->vendor_fixup(card, f->data);
|
||||
}
|
||||
|
||||
+371
-36
@@ -130,7 +130,7 @@ static int mmc_decode_csd(struct mmc_card *card)
|
||||
break;
|
||||
case 1:
|
||||
/*
|
||||
* This is a block-addressed SDHC card. Most
|
||||
* This is a block-addressed SDHC or SDXC card. Most
|
||||
* interesting fields are unused and have fixed
|
||||
* values. To avoid getting tripped by buggy cards,
|
||||
* we assume those fixed values ourselves.
|
||||
@@ -144,6 +144,11 @@ static int mmc_decode_csd(struct mmc_card *card)
|
||||
e = UNSTUFF_BITS(resp, 96, 3);
|
||||
csd->max_dtr = tran_exp[e] * tran_mant[m];
|
||||
csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
|
||||
csd->c_size = UNSTUFF_BITS(resp, 48, 22);
|
||||
|
||||
/* SDXC cards have a minimum C_SIZE of 0x00FFFF */
|
||||
if (csd->c_size >= 0xFFFF)
|
||||
mmc_card_set_ext_capacity(card);
|
||||
|
||||
m = UNSTUFF_BITS(resp, 48, 22);
|
||||
csd->capacity = (1 + m) << 10;
|
||||
@@ -189,12 +194,17 @@ static int mmc_decode_scr(struct mmc_card *card)
|
||||
|
||||
scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
|
||||
scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
|
||||
if (scr->sda_vsn == SCR_SPEC_VER_2)
|
||||
/* Check if Physical Layer Spec v3.0 is supported */
|
||||
scr->sda_spec3 = UNSTUFF_BITS(resp, 47, 1);
|
||||
|
||||
if (UNSTUFF_BITS(resp, 55, 1))
|
||||
card->erased_byte = 0xFF;
|
||||
else
|
||||
card->erased_byte = 0x0;
|
||||
|
||||
if (scr->sda_spec3)
|
||||
scr->cmds = UNSTUFF_BITS(resp, 32, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -274,29 +284,74 @@ static int mmc_read_switch(struct mmc_card *card)
|
||||
status = kmalloc(64, GFP_KERNEL);
|
||||
if (!status) {
|
||||
printk(KERN_ERR "%s: could not allocate a buffer for "
|
||||
"switch capabilities.\n", mmc_hostname(card->host));
|
||||
"switch capabilities.\n",
|
||||
mmc_hostname(card->host));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Find out the supported Bus Speed Modes. */
|
||||
err = mmc_sd_switch(card, 0, 0, 1, status);
|
||||
if (err) {
|
||||
/* If the host or the card can't do the switch,
|
||||
* fail more gracefully. */
|
||||
if ((err != -EINVAL)
|
||||
&& (err != -ENOSYS)
|
||||
&& (err != -EFAULT))
|
||||
/*
|
||||
* If the host or the card can't do the switch,
|
||||
* fail more gracefully.
|
||||
*/
|
||||
if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
|
||||
goto out;
|
||||
|
||||
printk(KERN_WARNING "%s: problem reading switch "
|
||||
"capabilities, performance might suffer.\n",
|
||||
printk(KERN_WARNING "%s: problem reading Bus Speed modes.\n",
|
||||
mmc_hostname(card->host));
|
||||
err = 0;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (status[13] & 0x02)
|
||||
card->sw_caps.hs_max_dtr = 50000000;
|
||||
if (card->scr.sda_spec3) {
|
||||
card->sw_caps.sd3_bus_mode = status[13];
|
||||
|
||||
/* Find out Driver Strengths supported by the card */
|
||||
err = mmc_sd_switch(card, 0, 2, 1, status);
|
||||
if (err) {
|
||||
/*
|
||||
* If the host or the card can't do the switch,
|
||||
* fail more gracefully.
|
||||
*/
|
||||
if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
|
||||
goto out;
|
||||
|
||||
printk(KERN_WARNING "%s: problem reading "
|
||||
"Driver Strength.\n",
|
||||
mmc_hostname(card->host));
|
||||
err = 0;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
card->sw_caps.sd3_drv_type = status[9];
|
||||
|
||||
/* Find out Current Limits supported by the card */
|
||||
err = mmc_sd_switch(card, 0, 3, 1, status);
|
||||
if (err) {
|
||||
/*
|
||||
* If the host or the card can't do the switch,
|
||||
* fail more gracefully.
|
||||
*/
|
||||
if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
|
||||
goto out;
|
||||
|
||||
printk(KERN_WARNING "%s: problem reading "
|
||||
"Current Limit.\n",
|
||||
mmc_hostname(card->host));
|
||||
err = 0;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
card->sw_caps.sd3_curr_limit = status[7];
|
||||
} else {
|
||||
if (status[13] & 0x02)
|
||||
card->sw_caps.hs_max_dtr = 50000000;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(status);
|
||||
@@ -352,6 +407,232 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int sd_select_driver_type(struct mmc_card *card, u8 *status)
|
||||
{
|
||||
int host_drv_type = 0, card_drv_type = 0;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* If the host doesn't support any of the Driver Types A,C or D,
|
||||
* default Driver Type B is used.
|
||||
*/
|
||||
if (!(card->host->caps & (MMC_CAP_DRIVER_TYPE_A | MMC_CAP_DRIVER_TYPE_C
|
||||
| MMC_CAP_DRIVER_TYPE_D)))
|
||||
return 0;
|
||||
|
||||
if (card->host->caps & MMC_CAP_DRIVER_TYPE_A) {
|
||||
host_drv_type = MMC_SET_DRIVER_TYPE_A;
|
||||
if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A)
|
||||
card_drv_type = MMC_SET_DRIVER_TYPE_A;
|
||||
else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B)
|
||||
card_drv_type = MMC_SET_DRIVER_TYPE_B;
|
||||
else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
|
||||
card_drv_type = MMC_SET_DRIVER_TYPE_C;
|
||||
} else if (card->host->caps & MMC_CAP_DRIVER_TYPE_C) {
|
||||
host_drv_type = MMC_SET_DRIVER_TYPE_C;
|
||||
if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
|
||||
card_drv_type = MMC_SET_DRIVER_TYPE_C;
|
||||
} else if (!(card->host->caps & MMC_CAP_DRIVER_TYPE_D)) {
|
||||
/*
|
||||
* If we are here, that means only the default driver type
|
||||
* B is supported by the host.
|
||||
*/
|
||||
host_drv_type = MMC_SET_DRIVER_TYPE_B;
|
||||
if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B)
|
||||
card_drv_type = MMC_SET_DRIVER_TYPE_B;
|
||||
else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
|
||||
card_drv_type = MMC_SET_DRIVER_TYPE_C;
|
||||
}
|
||||
|
||||
err = mmc_sd_switch(card, 1, 2, card_drv_type, status);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((status[15] & 0xF) != card_drv_type) {
|
||||
printk(KERN_WARNING "%s: Problem setting driver strength!\n",
|
||||
mmc_hostname(card->host));
|
||||
return 0;
|
||||
}
|
||||
|
||||
mmc_set_driver_type(card->host, host_drv_type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
|
||||
{
|
||||
unsigned int bus_speed = 0, timing = 0;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* If the host doesn't support any of the UHS-I modes, fallback on
|
||||
* default speed.
|
||||
*/
|
||||
if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)))
|
||||
return 0;
|
||||
|
||||
if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
|
||||
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
|
||||
bus_speed = UHS_SDR104_BUS_SPEED;
|
||||
timing = MMC_TIMING_UHS_SDR104;
|
||||
card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
|
||||
} else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
|
||||
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
|
||||
bus_speed = UHS_DDR50_BUS_SPEED;
|
||||
timing = MMC_TIMING_UHS_DDR50;
|
||||
card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
|
||||
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
|
||||
MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
|
||||
SD_MODE_UHS_SDR50)) {
|
||||
bus_speed = UHS_SDR50_BUS_SPEED;
|
||||
timing = MMC_TIMING_UHS_SDR50;
|
||||
card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
|
||||
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
|
||||
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
|
||||
bus_speed = UHS_SDR25_BUS_SPEED;
|
||||
timing = MMC_TIMING_UHS_SDR25;
|
||||
card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
|
||||
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
|
||||
MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
|
||||
SD_MODE_UHS_SDR12)) {
|
||||
bus_speed = UHS_SDR12_BUS_SPEED;
|
||||
timing = MMC_TIMING_UHS_SDR12;
|
||||
card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
|
||||
}
|
||||
|
||||
card->sd_bus_speed = bus_speed;
|
||||
err = mmc_sd_switch(card, 1, 0, bus_speed, status);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((status[16] & 0xF) != bus_speed)
|
||||
printk(KERN_WARNING "%s: Problem setting bus speed mode!\n",
|
||||
mmc_hostname(card->host));
|
||||
else {
|
||||
mmc_set_timing(card->host, timing);
|
||||
mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd_set_current_limit(struct mmc_card *card, u8 *status)
|
||||
{
|
||||
int current_limit = 0;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Current limit switch is only defined for SDR50, SDR104, and DDR50
|
||||
* bus speed modes. For other bus speed modes, we set the default
|
||||
* current limit of 200mA.
|
||||
*/
|
||||
if ((card->sd_bus_speed == UHS_SDR50_BUS_SPEED) ||
|
||||
(card->sd_bus_speed == UHS_SDR104_BUS_SPEED) ||
|
||||
(card->sd_bus_speed == UHS_DDR50_BUS_SPEED)) {
|
||||
if (card->host->caps & MMC_CAP_MAX_CURRENT_800) {
|
||||
if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_800;
|
||||
else if (card->sw_caps.sd3_curr_limit &
|
||||
SD_MAX_CURRENT_600)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_600;
|
||||
else if (card->sw_caps.sd3_curr_limit &
|
||||
SD_MAX_CURRENT_400)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_400;
|
||||
else if (card->sw_caps.sd3_curr_limit &
|
||||
SD_MAX_CURRENT_200)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_200;
|
||||
} else if (card->host->caps & MMC_CAP_MAX_CURRENT_600) {
|
||||
if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_600;
|
||||
else if (card->sw_caps.sd3_curr_limit &
|
||||
SD_MAX_CURRENT_400)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_400;
|
||||
else if (card->sw_caps.sd3_curr_limit &
|
||||
SD_MAX_CURRENT_200)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_200;
|
||||
} else if (card->host->caps & MMC_CAP_MAX_CURRENT_400) {
|
||||
if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_400;
|
||||
else if (card->sw_caps.sd3_curr_limit &
|
||||
SD_MAX_CURRENT_200)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_200;
|
||||
} else if (card->host->caps & MMC_CAP_MAX_CURRENT_200) {
|
||||
if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200)
|
||||
current_limit = SD_SET_CURRENT_LIMIT_200;
|
||||
}
|
||||
} else
|
||||
current_limit = SD_SET_CURRENT_LIMIT_200;
|
||||
|
||||
err = mmc_sd_switch(card, 1, 3, current_limit, status);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (((status[15] >> 4) & 0x0F) != current_limit)
|
||||
printk(KERN_WARNING "%s: Problem setting current limit!\n",
|
||||
mmc_hostname(card->host));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* UHS-I specific initialization procedure
|
||||
*/
|
||||
static int mmc_sd_init_uhs_card(struct mmc_card *card)
|
||||
{
|
||||
int err;
|
||||
u8 *status;
|
||||
|
||||
if (!card->scr.sda_spec3)
|
||||
return 0;
|
||||
|
||||
if (!(card->csd.cmdclass & CCC_SWITCH))
|
||||
return 0;
|
||||
|
||||
status = kmalloc(64, GFP_KERNEL);
|
||||
if (!status) {
|
||||
printk(KERN_ERR "%s: could not allocate a buffer for "
|
||||
"switch capabilities.\n", mmc_hostname(card->host));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Set 4-bit bus width */
|
||||
if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
|
||||
(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
|
||||
err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
|
||||
}
|
||||
|
||||
/* Set the driver strength for the card */
|
||||
err = sd_select_driver_type(card, status);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Set bus speed mode of the card */
|
||||
err = sd_set_bus_speed_mode(card, status);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Set current limit for the card */
|
||||
err = sd_set_current_limit(card, status);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* SPI mode doesn't define CMD19 */
|
||||
if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
|
||||
err = card->host->ops->execute_tuning(card->host);
|
||||
|
||||
out:
|
||||
kfree(status);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
|
||||
card->raw_cid[2], card->raw_cid[3]);
|
||||
MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
|
||||
@@ -400,7 +681,7 @@ struct device_type sd_type = {
|
||||
/*
|
||||
* Fetch CID from card.
|
||||
*/
|
||||
int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid)
|
||||
int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
|
||||
{
|
||||
int err;
|
||||
|
||||
@@ -420,12 +701,39 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid)
|
||||
*/
|
||||
err = mmc_send_if_cond(host, ocr);
|
||||
if (!err)
|
||||
ocr |= 1 << 30;
|
||||
ocr |= SD_OCR_CCS;
|
||||
|
||||
err = mmc_send_app_op_cond(host, ocr, NULL);
|
||||
/*
|
||||
* If the host supports one of UHS-I modes, request the card
|
||||
* to switch to 1.8V signaling level.
|
||||
*/
|
||||
if (host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))
|
||||
ocr |= SD_OCR_S18R;
|
||||
|
||||
/* If the host can supply more than 150mA, XPC should be set to 1. */
|
||||
if (host->caps & (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
|
||||
MMC_CAP_SET_XPC_180))
|
||||
ocr |= SD_OCR_XPC;
|
||||
|
||||
try_again:
|
||||
err = mmc_send_app_op_cond(host, ocr, rocr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* In case CCS and S18A in the response is set, start Signal Voltage
|
||||
* Switch procedure. SPI mode doesn't support CMD11.
|
||||
*/
|
||||
if (!mmc_host_is_spi(host) && rocr &&
|
||||
((*rocr & 0x41000000) == 0x41000000)) {
|
||||
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, true);
|
||||
if (err) {
|
||||
ocr &= ~SD_OCR_S18R;
|
||||
goto try_again;
|
||||
}
|
||||
}
|
||||
|
||||
if (mmc_host_is_spi(host))
|
||||
err = mmc_send_cid(host, cid);
|
||||
else
|
||||
@@ -553,11 +861,12 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
|
||||
struct mmc_card *card;
|
||||
int err;
|
||||
u32 cid[4];
|
||||
u32 rocr = 0;
|
||||
|
||||
BUG_ON(!host);
|
||||
WARN_ON(!host->claimed);
|
||||
|
||||
err = mmc_sd_get_cid(host, ocr, cid);
|
||||
err = mmc_sd_get_cid(host, ocr, cid, &rocr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -610,30 +919,47 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
|
||||
if (err)
|
||||
goto free_card;
|
||||
|
||||
/*
|
||||
* Attempt to change to high-speed (if supported)
|
||||
*/
|
||||
err = mmc_sd_switch_hs(card);
|
||||
if (err > 0)
|
||||
mmc_sd_go_highspeed(card);
|
||||
else if (err)
|
||||
goto free_card;
|
||||
|
||||
/*
|
||||
* Set bus speed.
|
||||
*/
|
||||
mmc_set_clock(host, mmc_sd_get_max_clock(card));
|
||||
|
||||
/*
|
||||
* Switch to wider bus (if supported).
|
||||
*/
|
||||
if ((host->caps & MMC_CAP_4_BIT_DATA) &&
|
||||
(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
|
||||
err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
|
||||
/* Initialization sequence for UHS-I cards */
|
||||
if (rocr & SD_ROCR_S18A) {
|
||||
err = mmc_sd_init_uhs_card(card);
|
||||
if (err)
|
||||
goto free_card;
|
||||
|
||||
mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
|
||||
/* Card is an ultra-high-speed card */
|
||||
mmc_sd_card_set_uhs(card);
|
||||
|
||||
/*
|
||||
* Since initialization is now complete, enable preset
|
||||
* value registers for UHS-I cards.
|
||||
*/
|
||||
if (host->ops->enable_preset_value)
|
||||
host->ops->enable_preset_value(host, true);
|
||||
} else {
|
||||
/*
|
||||
* Attempt to change to high-speed (if supported)
|
||||
*/
|
||||
err = mmc_sd_switch_hs(card);
|
||||
if (err > 0)
|
||||
mmc_sd_go_highspeed(card);
|
||||
else if (err)
|
||||
goto free_card;
|
||||
|
||||
/*
|
||||
* Set bus speed.
|
||||
*/
|
||||
mmc_set_clock(host, mmc_sd_get_max_clock(card));
|
||||
|
||||
/*
|
||||
* Switch to wider bus (if supported).
|
||||
*/
|
||||
if ((host->caps & MMC_CAP_4_BIT_DATA) &&
|
||||
(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
|
||||
err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
|
||||
if (err)
|
||||
goto free_card;
|
||||
|
||||
mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
|
||||
}
|
||||
}
|
||||
|
||||
host->card = card;
|
||||
@@ -773,6 +1099,15 @@ int mmc_attach_sd(struct mmc_host *host)
|
||||
BUG_ON(!host);
|
||||
WARN_ON(!host->claimed);
|
||||
|
||||
/* Make sure we are at 3.3V signalling voltage */
|
||||
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Disable preset value enable if already set since last time */
|
||||
if (host->ops->enable_preset_value)
|
||||
host->ops->enable_preset_value(host, false);
|
||||
|
||||
err = mmc_send_app_op_cond(host, 0, &ocr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
extern struct device_type sd_type;
|
||||
|
||||
int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid);
|
||||
int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr);
|
||||
int mmc_sd_get_csd(struct mmc_host *host, struct mmc_card *card);
|
||||
void mmc_decode_cid(struct mmc_card *card);
|
||||
int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
|
||||
|
||||
+17
-34
@@ -21,10 +21,10 @@
|
||||
#include "core.h"
|
||||
#include "sd_ops.h"
|
||||
|
||||
static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
|
||||
int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
|
||||
{
|
||||
int err;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
|
||||
BUG_ON(!host);
|
||||
BUG_ON(card && (card->host != host));
|
||||
@@ -49,6 +49,7 @@ static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_app_cmd);
|
||||
|
||||
/**
|
||||
* mmc_wait_for_app_cmd - start an application command and wait for
|
||||
@@ -66,7 +67,7 @@ static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
|
||||
int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
|
||||
struct mmc_command *cmd, int retries)
|
||||
{
|
||||
struct mmc_request mrq;
|
||||
struct mmc_request mrq = {0};
|
||||
|
||||
int i, err;
|
||||
|
||||
@@ -119,13 +120,11 @@ EXPORT_SYMBOL(mmc_wait_for_app_cmd);
|
||||
int mmc_app_set_bus_width(struct mmc_card *card, int width)
|
||||
{
|
||||
int err;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
|
||||
BUG_ON(!card);
|
||||
BUG_ON(!card->host);
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = SD_APP_SET_BUS_WIDTH;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
|
||||
|
||||
@@ -149,13 +148,11 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width)
|
||||
|
||||
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
|
||||
{
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
int i, err = 0;
|
||||
|
||||
BUG_ON(!host);
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = SD_APP_OP_COND;
|
||||
if (mmc_host_is_spi(host))
|
||||
cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */
|
||||
@@ -194,7 +191,7 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
|
||||
|
||||
int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
|
||||
{
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
int err;
|
||||
static const u8 test_pattern = 0xAA;
|
||||
u8 result_pattern;
|
||||
@@ -226,13 +223,11 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
|
||||
int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
|
||||
{
|
||||
int err;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_command cmd = {0};
|
||||
|
||||
BUG_ON(!host);
|
||||
BUG_ON(!rca);
|
||||
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
|
||||
cmd.opcode = SD_SEND_RELATIVE_ADDR;
|
||||
cmd.arg = 0;
|
||||
cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
|
||||
@@ -249,9 +244,9 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
|
||||
int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
|
||||
{
|
||||
int err;
|
||||
struct mmc_request mrq;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_data data;
|
||||
struct mmc_request mrq = {0};
|
||||
struct mmc_command cmd = {0};
|
||||
struct mmc_data data = {0};
|
||||
struct scatterlist sg;
|
||||
void *data_buf;
|
||||
|
||||
@@ -272,10 +267,6 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
|
||||
if (data_buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(&mrq, 0, sizeof(struct mmc_request));
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
|
||||
mrq.cmd = &cmd;
|
||||
mrq.data = &data;
|
||||
|
||||
@@ -312,9 +303,9 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
|
||||
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
|
||||
u8 value, u8 *resp)
|
||||
{
|
||||
struct mmc_request mrq;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_data data;
|
||||
struct mmc_request mrq = {0};
|
||||
struct mmc_command cmd = {0};
|
||||
struct mmc_data data = {0};
|
||||
struct scatterlist sg;
|
||||
|
||||
BUG_ON(!card);
|
||||
@@ -325,10 +316,6 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
|
||||
mode = !!mode;
|
||||
value &= 0xF;
|
||||
|
||||
memset(&mrq, 0, sizeof(struct mmc_request));
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
|
||||
mrq.cmd = &cmd;
|
||||
mrq.data = &data;
|
||||
|
||||
@@ -361,9 +348,9 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
|
||||
int mmc_app_sd_status(struct mmc_card *card, void *ssr)
|
||||
{
|
||||
int err;
|
||||
struct mmc_request mrq;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_data data;
|
||||
struct mmc_request mrq = {0};
|
||||
struct mmc_command cmd = {0};
|
||||
struct mmc_data data = {0};
|
||||
struct scatterlist sg;
|
||||
|
||||
BUG_ON(!card);
|
||||
@@ -376,10 +363,6 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
memset(&mrq, 0, sizeof(struct mmc_request));
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
|
||||
mrq.cmd = &cmd;
|
||||
mrq.data = &data;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user