summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbelgin <belginstirbu@hotmail.com>2021-06-29 20:31:12 +0300
committerbelgin <belginstirbu@hotmail.com>2021-06-29 20:31:12 +0300
commit5d027b8f5c1df9320956bcf5021c7cfb7cc0ef0a (patch)
tree252691de1e6e3b2aa45f32e0a2a8af7fbace8601
parentdc4bef8cf8fa37eb0c581ba4c32a73cf27818e9d (diff)
downloadkernel_replicant_linux-5d027b8f5c1df9320956bcf5021c7cfb7cc0ef0a.tar.gz
kernel_replicant_linux-5d027b8f5c1df9320956bcf5021c7cfb7cc0ef0a.tar.bz2
kernel_replicant_linux-5d027b8f5c1df9320956bcf5021c7cfb7cc0ef0a.zip
added emmc bug workaround for midasemmc-fix
-rw-r--r--drivers/mmc/core/mmc.c17
-rw-r--r--drivers/mmc/core/mmc_ops.c206
-rw-r--r--include/linux/mmc/card.h1
-rw-r--r--include/linux/mmc/core.h3
4 files changed, 227 insertions, 0 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index ff3063ce2acd..6c091793bd76 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1888,6 +1888,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (!oldcard)
host->card = card;
+ err = mmc_start_movi_operation(host->card);
+ if (err) {
+ pr_warn("%s: movi operation failed\n", mmc_hostname(host));
+ goto free_card;
+ }
+
return 0;
free_card:
@@ -2260,6 +2266,17 @@ int mmc_attach_mmc(struct mmc_host *host)
if (err)
goto remove_card;
+ 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;
+
+ err = mmc_start_movi_operation(host->card);
+ if (err) {
+ pr_warn("%s: movi operation failed\n", mmc_hostname(host));
+ goto remove_card;
+ }
+
mmc_claim_host(host);
return 0;
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index baa6314f69b4..5e2ad5e08dcf 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -829,6 +829,212 @@ 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;
+
+ if (card->movi_ops != 0x2)
+ return 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);
+
+
static int mmc_send_hpi_cmd(struct mmc_card *card)
{
unsigned int busy_timeout_ms = card->ext_csd.out_of_int_time;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 42df06c6b19c..4dc435dbe8ee 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -313,6 +313,7 @@ struct mmc_card {
unsigned int bouncesz; /* Bounce buffer size */
struct workqueue_struct *complete_wq; /* Private workqueue */
+ unsigned int movi_ops;
};
static inline bool mmc_large_sector(struct mmc_card *card)
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 29aa50711626..80cbc1aaf49c 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -174,4 +174,7 @@ int mmc_hw_reset(struct mmc_host *host);
int mmc_sw_reset(struct mmc_host *host);
void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card);
+int mmc_start_movi_smart(struct mmc_card *card);
+int mmc_start_movi_operation(struct mmc_card *card);
+
#endif /* LINUX_MMC_CORE_H */