diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/card/Kconfig | 7 | ||||
-rw-r--r-- | drivers/mmc/card/Makefile | 4 | ||||
-rw-r--r-- | drivers/mmc/card/block.c | 118 | ||||
-rw-r--r-- | drivers/mmc/card/cprmdrv_samsung.c | 35 | ||||
-rw-r--r-- | drivers/mmc/card/cprmdrv_samsung.h | 14 | ||||
-rw-r--r-- | drivers/mmc/core/mmc.c | 74 | ||||
-rw-r--r-- | drivers/mmc/core/mmc_ops.c | 60 |
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); |