aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/core/mmc.c24
-rw-r--r--drivers/mmc/core/mmc_ops.c201
-rw-r--r--include/linux/mmc/card.h1
-rw-r--r--include/linux/mmc/core.h2
4 files changed, 228 insertions, 0 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index f2d185c..0d4631c 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -19,6 +19,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
+#include <linux/string.h>
#include "core.h"
#include "host.h"
@@ -1973,6 +1974,15 @@ static int _mmc_resume(struct mmc_host *host)
mmc_power_up(host, host->card->ocr);
err = mmc_init_card(host, host->card->ocr, host->card);
+
+ if (host->card->movi_ops == 0x2) {
+ err = mmc_start_movi_operation(host->card);
+ if (err) {
+ pr_warning("%s: movi operation is failed\n",
+ mmc_hostname(host));
+ }
+ }
+
mmc_card_clr_suspended(host->card);
out:
@@ -2145,6 +2155,20 @@ int mmc_attach_mmc(struct mmc_host *host)
goto remove_card;
mmc_claim_host(host);
+ if (!strncmp(host->card->cid.prod_name, "VTU00M", 6) &&
+ (host->card->cid.prv == 0xf1) &&
+ (mmc_start_movi_smart(host->card) == 0x2))
+ host->card->movi_ops = 0x2;
+
+ if (host->card->movi_ops == 0x2) {
+ err = mmc_start_movi_operation(host->card);
+ if (err) {
+ pr_warning("%s: movi operation is failed\n",
+ mmc_hostname(host));
+ goto remove_card;
+ }
+ }
+
return 0;
remove_card:
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index ad6e979..4490f50 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -759,6 +759,207 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width)
return mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width);
}
+static int mmc_send_cmd(struct mmc_host *host,
+ u32 opcode, u32 arg, unsigned int flags, u32 *resp)
+{
+ int err;
+ struct mmc_command cmd;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = opcode;
+ cmd.arg = arg;
+ cmd.flags = flags;
+ *resp = 0;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (!err)
+ *resp = cmd.resp[0];
+ else
+ printk(KERN_ERR "[CMD%d] FAILED!!\n", cmd.opcode);
+
+ return err;
+}
+
+static int mmc_movi_cmd(struct mmc_host *host, u32 arg)
+{
+ int err;
+ u32 resp;
+
+ err = mmc_send_cmd(host, 62, arg,
+ MMC_RSP_R1B | MMC_CMD_AC, &resp);
+ mdelay(10);
+
+ if (!err)
+ do {
+ err = mmc_send_cmd(host, MMC_SEND_STATUS,
+ host->card->rca << 16,
+ MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC,
+ &resp);
+ if (err) {
+ printk(KERN_ERR "CMD13(VC) failed\n");
+ break;
+ }
+ /*wait until READY_FOR_DATA*/
+ } while (!(resp & 1<<8));
+
+ return err;
+}
+
+static int mmc_movi_erase_cmd(struct mmc_host *host, u32 arg1, u32 arg2)
+{
+ int err;
+ u32 resp;
+
+ err = mmc_send_cmd(host, MMC_ERASE_GROUP_START, arg1,
+ MMC_RSP_R1 | MMC_CMD_AC, &resp);
+ if (err)
+ return err;
+
+ err = mmc_send_cmd(host, MMC_ERASE_GROUP_END, arg2,
+ MMC_RSP_R1 | MMC_CMD_AC, &resp);
+ if (err)
+ return err;
+
+ err = mmc_send_cmd(host, MMC_ERASE, 0,
+ MMC_RSP_R1B | MMC_CMD_AC, &resp);
+ if (!err)
+ do {
+ err = mmc_send_cmd(host, MMC_SEND_STATUS,
+ host->card->rca << 16,
+ MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC,
+ &resp);
+ if (err) {
+ printk(KERN_ERR "CMD13(VC) failed\n");
+ break;
+ }
+ /*wait until READY_FOR_DATA*/
+ } while (!(resp & 1<<8));
+
+ return err;
+}
+
+
+static int mmc_movi_read_req(struct mmc_card *card,
+ void *data_buf, u32 arg, u32 blocks)
+{
+ struct mmc_request mrq = {0};
+ struct mmc_command cmd = {0};
+ struct mmc_data data = {0};
+ struct scatterlist sg;
+
+ /*send request*/
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ if (blocks > 1)
+ cmd.opcode = MMC_READ_MULTIPLE_BLOCK;
+ else
+ cmd.opcode = MMC_READ_SINGLE_BLOCK;
+ cmd.arg = arg;
+
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ data.blksz = 512;
+ data.blocks = blocks;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ sg_init_one(&sg, data_buf, data.blksz * data.blocks);
+
+ mmc_set_data_timeout(&data, card);
+
+ mmc_wait_for_req(card->host, &mrq);
+
+ if (cmd.error)
+ return cmd.error;
+
+ if (data.error)
+ return data.error;
+
+ return 0;
+}
+
+int mmc_start_movi_smart(struct mmc_card *card)
+{
+ int err;
+ u8 data_buf[512];
+ u32 date = 0;
+
+ err = mmc_movi_cmd(card->host, 0xEFAC62EC);
+ if (err)
+ return err;
+
+ err = mmc_movi_cmd(card->host, 0x0000CCEE);
+ if (err)
+ return err;
+
+ err = mmc_movi_read_req(card, (void *)data_buf, 0x1000, 1);
+ if (err)
+ return err;
+
+ err = mmc_movi_cmd(card->host, 0xEFAC62EC);
+ if (err)
+ return err;
+
+ err = mmc_movi_cmd(card->host, 0x00DECCEE);
+ if (err)
+ return err;
+
+ date = ((data_buf[327] << 24) | (data_buf[326] << 16) |
+ (data_buf[325] << 8) | data_buf[324]);
+
+ if (date != 0x20120413) {
+ err = -1;
+ return err;
+ }
+
+ return 0x2;
+}
+EXPORT_SYMBOL_GPL(mmc_start_movi_smart);
+
+int mmc_start_movi_operation(struct mmc_card *card)
+{
+ int err = 0;
+
+ err = mmc_movi_cmd(card->host, 0xEFAC62EC);
+ if (err)
+ return err;
+ err = mmc_movi_cmd(card->host, 0x10210000);
+ if (err)
+ return err;
+
+ err = mmc_movi_erase_cmd(card->host, 0x00040300, 0x4A03B510);
+ if (err)
+ return err;
+ err = mmc_movi_erase_cmd(card->host, 0x00040304, 0x28004790);
+ if (err)
+ return err;
+ err = mmc_movi_erase_cmd(card->host, 0x00040308, 0xE7FED100);
+ if (err)
+ return err;
+ err = mmc_movi_erase_cmd(card->host, 0x0004030C, 0x0000BD10);
+ if (err)
+ return err;
+ err = mmc_movi_erase_cmd(card->host, 0x00040310, 0x00059D73);
+ if (err)
+ return err;
+ err = mmc_movi_erase_cmd(card->host, 0x0005C7EA, 0xFD89F7E3);
+ if (err)
+ return err;
+
+ err = mmc_movi_cmd(card->host, 0xEFAC62EC);
+ if (err)
+ return err;
+ err = mmc_movi_cmd(card->host, 0x00DECCEE);
+ if (err)
+ return err;
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(mmc_start_movi_operation);
+
int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
{
struct mmc_command cmd = {0};
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index d8673ca..97582be 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -315,6 +315,7 @@ struct mmc_card {
struct dentry *debugfs_root;
struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
unsigned int nr_parts;
+ unsigned int movi_ops;
};
/*
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index b01e77d..954d3be 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -154,6 +154,8 @@ extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
+extern int mmc_start_movi_smart(struct mmc_card *card);
+extern int mmc_start_movi_operation(struct mmc_card *card);
#define MMC_ERASE_ARG 0x00000000
#define MMC_SECURE_ERASE_ARG 0x80000000