aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/card/Kconfig7
-rw-r--r--drivers/mmc/card/Makefile4
-rw-r--r--drivers/mmc/card/block.c118
-rw-r--r--drivers/mmc/card/cprmdrv_samsung.c35
-rw-r--r--drivers/mmc/card/cprmdrv_samsung.h14
-rw-r--r--drivers/mmc/core/mmc.c74
-rw-r--r--drivers/mmc/core/mmc_ops.c60
7 files changed, 252 insertions, 60 deletions
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index 4283bc2..2320c98 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -81,3 +81,10 @@ config MMC_SELECTIVE_PACKED_CMD_POLICY
tristate "Change the condition of Pakced command"
help
Say Y here to change packed_cmd policy
+
+config MMC_CPRM
+ bool "Japan only CPRM MMC driver"
+ depends on MMC_BLOCK
+ default n
+ help
+ Japan only feature of CPRM MMC driver. \ No newline at end of file
diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile
index a6efd4d..fad6e00 100644
--- a/drivers/mmc/card/Makefile
+++ b/drivers/mmc/card/Makefile
@@ -1,10 +1,6 @@
#
# Makefile for MMC/SD card drivers
#
-ifeq ($(CONFIG_MMC_CPRM),y)
-EXTRA_CFLAGS += -I$(src)/cprm/softcprm
-EXTRA_CFLAGS += -I$(src)/cprm/include
-endif
obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
mmc_block-objs := block.o queue.o
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 7027962..f49e92c 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -60,6 +60,9 @@ MODULE_ALIAS("mmc:block");
#define MMC_IOCTL_GET_SECTOR_COUNT _IOR(MMC_IOCTL_BASE, 100, int)
#define MMC_IOCTL_GET_SECTOR_SIZE _IOR(MMC_IOCTL_BASE, 101, int)
#define MMC_IOCTL_GET_BLOCK_SIZE _IOR(MMC_IOCTL_BASE, 102, int)
+#define MMC_IOCTL_SET_RETRY_AKE_PROCESS _IOR(MMC_IOCTL_BASE, 104, int)
+
+static int cprm_ake_retry_flag;
#endif
#ifdef MOVI_DEBUG
@@ -329,6 +332,47 @@ out:
return ERR_PTR(err);
}
+struct scatterlist *mmc_blk_get_sg(struct mmc_card *card,
+ unsigned char *buf, int *sg_len, int size)
+{
+ struct scatterlist *sg;
+ struct scatterlist *sl;
+ int total_sec_cnt, sec_cnt;
+ int max_seg_size, len;
+
+ sl = kmalloc(sizeof(struct scatterlist) * card->host->max_segs, GFP_KERNEL);
+ if (!sl) {
+ return NULL;
+ }
+
+ sg = (struct scatterlist *)sl;
+ sg_init_table(sg, card->host->max_segs);
+
+ total_sec_cnt = size;
+ max_seg_size = card->host->max_seg_size;
+
+ len = 0;
+ while (total_sec_cnt) {
+ if (total_sec_cnt < max_seg_size)
+ sec_cnt = total_sec_cnt;
+ else
+ sec_cnt = max_seg_size;
+ sg_set_page(sg, virt_to_page(buf), sec_cnt, offset_in_page(buf));
+ buf = buf + sec_cnt;
+ total_sec_cnt = total_sec_cnt - sec_cnt;
+ len++;
+ if (total_sec_cnt == 0)
+ break;
+ sg = sg_next(sg);
+ }
+
+ if (sg)
+ sg_mark_end(sg);
+
+ *sg_len = len;
+
+ return sl;
+}
static int mmc_blk_ioctl_cmd(struct block_device *bdev,
struct mmc_ioc_cmd __user *ic_ptr)
{
@@ -338,7 +382,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
struct mmc_command cmd = {0};
struct mmc_data data = {0};
struct mmc_request mrq = {0};
- struct scatterlist sg;
+ struct scatterlist *sg = 0;
int err = 0;
/*
@@ -369,13 +413,22 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
cmd.arg = idata->ic.arg;
cmd.flags = idata->ic.flags;
+ if( cmd.opcode == MMC_IOC_CLOCK )
+ {
+ mmc_set_clock(card->host, cmd.arg);
+ err = 0;
+ goto cmd_done;
+ }
+
if (idata->buf_bytes) {
- data.sg = &sg;
- data.sg_len = 1;
+ int len;
data.blksz = idata->ic.blksz;
data.blocks = idata->ic.blocks;
- sg_init_one(data.sg, idata->buf, idata->buf_bytes);
+ sg = mmc_blk_get_sg(card, idata->buf, &len, idata->buf_bytes);
+
+ data.sg = sg;
+ data.sg_len = len;
if (idata->ic.write_flag)
data.flags = MMC_DATA_WRITE;
@@ -456,6 +509,9 @@ cmd_rel_host:
cmd_done:
if (md)
mmc_blk_put(md);
+ if (sg)
+ kfree(sg);
+
kfree(idata->buf);
kfree(idata);
return err;
@@ -467,6 +523,8 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
#ifdef MMC_ENABLE_CPRM
struct mmc_blk_data *md = bdev->bd_disk->private_data;
struct mmc_card *card = md->queue.card;
+ static int i;
+ static unsigned long temp_arg[16] = {0};
#endif
int ret = -EINVAL;
if (cmd == MMC_IOC_CMD)
@@ -476,6 +534,10 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
printk(KERN_DEBUG " %s ], %x ", __func__, cmd);
switch (cmd) {
+ case MMC_IOCTL_SET_RETRY_AKE_PROCESS:
+ cprm_ake_retry_flag = 1;
+ ret = 0;
+ break;
case MMC_IOCTL_GET_SECTOR_COUNT: {
int size = 0;
@@ -498,9 +560,54 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
struct cprm_request *req = (struct cprm_request *)arg;
printk(KERN_DEBUG "[%s]: cmd [%x]\n", __func__, cmd);
+ if (cmd == ACMD43) {
+ printk(KERN_DEBUG"storing acmd43 arg[%d] = %ul\n"
+ , i, (unsigned int)req->arg);
+ temp_arg[i] = req->arg;
+ i++;
+ if(i >= 16){
+ printk(KERN_DEBUG"reset acmd43 i = %d\n",
+ i);
+ i = 0;
+ }
+ }
+
+
+ if (cmd == ACMD45 && cprm_ake_retry_flag == 1) {
+ cprm_ake_retry_flag = 0;
+ printk(KERN_DEBUG"ACMD45.. I'll call ACMD43 and ACMD44 first\n");
+
+ for (i = 0; i < 16; i++) {
+ printk(KERN_DEBUG"calling ACMD43 with arg[%d] = %ul\n",
+ i, (unsigned int)temp_arg[i]);
+ if (stub_sendcmd(card,
+ ACMD43, temp_arg[i],
+ 512, NULL) < 0) {
+
+ printk(KERN_DEBUG"error ACMD43 %d\n", i);
+ return -EINVAL;
+ }
+ }
+
+
+ printk(KERN_DEBUG"calling ACMD44\n");
+ if (stub_sendcmd(card, ACMD44, 0, 8, NULL) < 0)
+ {
+
+ printk(KERN_DEBUG"error in ACMD44 %d\n",
+ i);
+ return -EINVAL;
+ }
+
+ }
return stub_sendcmd(card, req->cmd, req->arg, \
req->len, req->buff);
}
+ break;
+
+ default:
+ printk(KERN_DEBUG"%s: Invalid ioctl command\n", __func__);
+ break;
}
#endif
return ret;
@@ -2372,9 +2479,6 @@ static int mmc_blk_probe(struct mmc_card *card)
md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
cap_str, md->read_only ? "(ro)" : "");
- if (mmc_blk_alloc_parts(card, md))
- goto out;
-
mmc_set_drvdata(card, md);
mmc_fixup_device(card, blk_fixups);
diff --git a/drivers/mmc/card/cprmdrv_samsung.c b/drivers/mmc/card/cprmdrv_samsung.c
index 6f64a7f..81b430c 100644
--- a/drivers/mmc/card/cprmdrv_samsung.c
+++ b/drivers/mmc/card/cprmdrv_samsung.c
@@ -1,4 +1,17 @@
-
+/* drivers/mmc/cprmdrv_samsung.c
+ *
+ * Copyright 2010 Samsung Electronics Co.Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
#include <linux/mmc/core.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -54,7 +67,6 @@ static int CPRM_CMD_SecureRW(struct mmc_card *card,
struct mmc_command cmd;
struct mmc_command stop;
struct mmc_data data;
- unsigned int timeout_us;
struct scatterlist sg;
@@ -91,17 +103,8 @@ static int CPRM_CMD_SecureRW(struct mmc_card *card,
memset(&data, 0, sizeof(struct mmc_data));
- data.timeout_ns = card->csd.tacc_ns * 100;
- data.timeout_clks = card->csd.tacc_clks * 100;
-
- timeout_us = data.timeout_ns / 1000;
- timeout_us += data.timeout_clks * 1000 /
- (card->host->ios.clock / 1000);
-
- if (timeout_us > 100000) {
data.timeout_ns = 100000000;
data.timeout_clks = 0;
- }
#if defined(CONFIG_TARGET_LOCALE_NTT)
data.timeout_ns = 100000000;
@@ -178,7 +181,6 @@ static int CPRM_CMD_SecureMultiRW(struct mmc_card *card,
struct mmc_command cmd;
struct mmc_command stop;
struct mmc_data data;
- unsigned int timeout_us;
unsigned long flags;
struct scatterlist sg;
@@ -212,17 +214,8 @@ static int CPRM_CMD_SecureMultiRW(struct mmc_card *card,
memset(&data, 0, sizeof(struct mmc_data));
- data.timeout_ns = card->csd.tacc_ns * 100;
- data.timeout_clks = card->csd.tacc_clks * 100;
-
- timeout_us = data.timeout_ns / 1000;
- timeout_us += data.timeout_clks * 1000 /
- (card->host->ios.clock / 1000);
-
- if (timeout_us > 100000) {
data.timeout_ns = 100000000;
data.timeout_clks = 0;
- }
#if defined(CONFIG_TARGET_LOCALE_NTT)
data.timeout_ns = 100000000;
diff --git a/drivers/mmc/card/cprmdrv_samsung.h b/drivers/mmc/card/cprmdrv_samsung.h
index b07dd6e..68fc7cb 100644
--- a/drivers/mmc/card/cprmdrv_samsung.h
+++ b/drivers/mmc/card/cprmdrv_samsung.h
@@ -1,3 +1,17 @@
+/* drivers/mmc/cprmdrv_samsung.h
+ *
+ * Copyright 2010 Samsung Electronics Co.Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
#ifndef __CPRM_API_SAMSUNG
#define __CPRM_API_SAMSUNG
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 3403f53..506a4e3 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -35,6 +35,27 @@
#endif
#endif
+/*
+ * If moviNAND VHX 4.41 device
+ * enable PON to force.
+ */
+#define CHECK_MOVI_VHX4_41 \
+ (card->ext_csd.rev == 5 && card->movi_fwver >= 0x1C)
+
+/*
+ * If moviNAND VHX 4.5 device
+ * enable PON to force.
+ */
+#define CHECK_MOVI_VHX4_5 \
+ (card->ext_csd.rev == 6 && card->movi_fwver >= 0x0A)
+
+#define CHECK_MOVI_PON_SUPPORT \
+ (card->cid.manfid == 0x15 && \
+ ext_csd[EXT_CSD_VENDOR_SPECIFIC_FIELD] & 0x2)
+
+#define CHECK_PON_ENABLE \
+ (card->ext_csd.feature_support & MMC_POWEROFF_NOTIFY_FEATURE)
+
static const unsigned int tran_exp[] = {
10000, 100000, 1000000, 10000000,
0, 0, 0, 0
@@ -333,6 +354,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
{
int err = 0;
+ int movi_ver_check = 0;
BUG_ON(!card);
@@ -581,11 +603,49 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
}
if (card->ext_csd.rev >= 5) {
- /* enable discard feature if emmc is 4.41+ */
+ /* If moviNAND, run smart report */
+ if (card->cid.manfid == 0x15) {
+ card->host->card = card;
+ movi_ver_check = mmc_start_movi_smart(card);
+ }
+
+ /* enable discard feature if emmc is 4.41+ moviNand */
if ((ext_csd[EXT_CSD_VENDOR_SPECIFIC_FIELD + 0] & 0x1) &&
(card->cid.manfid == 0x15))
card->ext_csd.feature_support |= MMC_DISCARD_FEATURE;
+ /* enable PON feature if moviNAND VHX/VMX devices */
+ if (CHECK_MOVI_PON_SUPPORT) {
+ if ((movi_ver_check & MMC_MOVI_VER_VHX0) &&
+ (CHECK_MOVI_VHX4_41 ||
+ CHECK_MOVI_VHX4_5)) {
+ card->ext_csd.feature_support |=
+ MMC_POWEROFF_NOTIFY_FEATURE;
+ card->ext_csd.generic_cmd6_time = 100;
+ card->ext_csd.power_off_longtime = 600;
+ }
+ if (movi_ver_check & MMC_MOVI_VER_VMX0) {
+ card->ext_csd.feature_support |=
+ MMC_POWEROFF_NOTIFY_FEATURE;
+ }
+ pr_info("%s : %s PON feature : "
+ "%02x : %02x(%02x) : %08x\n",
+ mmc_hostname(card->host),
+ card->ext_csd.feature_support & MMC_POWEROFF_NOTIFY_FEATURE ?
+ "enable" : "disable",
+ movi_ver_check,
+ card->movi_fwver, ext_csd[82],
+ card->movi_fwdate);
+ }
+
+ /*
+ * enable discard feature if emmc is 4.41+ Toshiba eMMC 19nm
+ * Normally, emmc 4.5 use EXT_CSD[501]
+ */
+ if ((ext_csd[EXT_CSD_MAX_PACKED_READS] & 0x3F) &&
+ (card->cid.manfid == 0x11))
+ card->ext_csd.feature_support |= MMC_DISCARD_FEATURE;
+
/* check whether the eMMC card supports HPI */
if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
card->ext_csd.hpi = 1;
@@ -717,6 +777,7 @@ MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
card->ext_csd.enhanced_area_offset);
MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
+MMC_DEV_ATTR(fwver, "%02x : %x\n", card->movi_fwver, card->movi_fwdate);
static struct attribute *mmc_std_attrs[] = {
&dev_attr_cid.attr,
@@ -732,6 +793,7 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_serial.attr,
&dev_attr_enhanced_area_offset.attr,
&dev_attr_enhanced_area_size.attr,
+ &dev_attr_fwver.attr,
NULL,
};
@@ -1111,22 +1173,20 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
* set the notification byte in the ext_csd register of device
*/
if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) &&
- (card->ext_csd.rev >= 6)) {
+ ((card->ext_csd.rev >= 5) && CHECK_PON_ENABLE)) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_POWER_OFF_NOTIFICATION,
EXT_CSD_POWER_ON,
card->ext_csd.generic_cmd6_time);
if (err && err != -EBADMSG)
goto free_card;
- }
-
- if (!err && (host->caps2 & MMC_CAP2_POWEROFF_NOTIFY))
/*
* The err can be -EBADMSG or 0,
* so check for success and update the flag
*/
if (!err)
card->poweroff_notify_state = MMC_POWERED_ON;
+ }
/*
* Activate high speed (if supported)
@@ -1656,10 +1716,10 @@ int mmc_attach_mmc(struct mmc_host *host)
if (!strncmp(host->card->cid.prod_name, "VTU00M", 6) &&
(host->card->cid.prod_rev == 0xf1) &&
- (mmc_start_movi_smart(host->card) == 0x2))
+ (host->card->movi_fwdate == 0x20120413)) {
+ /* It needs host work-around codes */
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",
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 90085a3..3cec450 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -677,41 +677,59 @@ static int mmc_movi_read_req(struct mmc_card *card,
return 0;
}
+#define MOVI_CONT_VHX0 0x56485830
+#define MOVI_CONT_VMX0 0x564D5830
+
int mmc_start_movi_smart(struct mmc_card *card)
{
- int err;
+ int ret;
u8 data_buf[512];
u32 date = 0;
+ u32 old_date = 0;
+ u32 movi_ver = 0;
- err = mmc_movi_cmd(card->host, 0xEFAC62EC);
- if (err)
- return err;
+ ret = mmc_movi_cmd(card->host, 0xEFAC62EC);
+ if (ret)
+ return ret;
- err = mmc_movi_cmd(card->host, 0x0000CCEE);
- if (err)
- return err;
+ ret = mmc_movi_cmd(card->host, 0x0000CCEE);
+ if (ret)
+ return ret;
- err = mmc_movi_read_req(card, (void *)data_buf, 0x1000, 1);
- if (err)
- return err;
+ ret = mmc_movi_read_req(card, (void *)data_buf, 0x1000, 1);
+ if (ret)
+ return ret;
- err = mmc_movi_cmd(card->host, 0xEFAC62EC);
- if (err)
- return err;
+ ret = mmc_movi_cmd(card->host, 0xEFAC62EC);
+ if (ret)
+ return ret;
- err = mmc_movi_cmd(card->host, 0x00DECCEE);
- if (err)
- return err;
+ ret = mmc_movi_cmd(card->host, 0x00DECCEE);
+ if (ret)
+ return ret;
+
+ movi_ver = ((data_buf[312] << 24) | (data_buf[313] << 16) |
+ (data_buf[314] << 8) | data_buf[315]);
+ if (movi_ver == MOVI_CONT_VMX0)
+ ret = MMC_MOVI_VER_VMX0;
+ else if (movi_ver == MOVI_CONT_VHX0)
+ ret = MMC_MOVI_VER_VHX0;
+ else
+ ret = 0x0;
date = ((data_buf[327] << 24) | (data_buf[326] << 16) |
(data_buf[325] << 8) | data_buf[324]);
- if (date != 0x20120413) {
- err = -1;
- return err;
- }
+ card->movi_fwver = data_buf[320];
+ card->movi_fwdate = date;
+
+ old_date = ((data_buf[351] << 24) | (data_buf[350] << 16) |
+ (data_buf[349] << 8) | data_buf[348]);
+
+ pr_info("%s : %02x : %02x : %08x : %x.\n", mmc_hostname(card->host),
+ ret, card->movi_fwver, card->movi_fwdate, old_date);
- return 0x2;
+ return ret;
}
EXPORT_SYMBOL_GPL(mmc_start_movi_smart);