mmc: core: implemented RPMB partition support
authorChuanxiao Dong <chuanxiao.dong@intel.com>
Thu, 22 Dec 2011 08:07:40 +0000 (16:07 +0800)
committerbuildbot <buildbot@intel.com>
Wed, 28 Dec 2011 02:53:12 +0000 (18:53 -0800)
BZ: 18193

eMMC card has RPMB partition, which is used for user to store some security
data. Right now Chabbi will use this partition and need MMC driver to support
this.

This patch implements the RPMB support from driver level

Change-Id: I04c0a3aed3adb99205eb3ec61ce6e24a78d4d908
Signed-off-by: Chuanxiao Dong <chuanxiao.dong@intel.com>
Reviewed-on: http://android.intel.com:8080/29703
Tested-by: Sun, Jianhua <jianhua.sun@intel.com>
Reviewed-by: Tang, Richard <richard.tang@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
arch/x86/platform/mrst/mrst.c
drivers/mmc/card/block.c
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
include/linux/mmc/card.h
include/linux/mmc/core.h
include/linux/mmc/mmc.h

index 45f25db..33722cc 100644 (file)
 #include <linux/atomisp_platform.h>
 #include <media/v4l2-subdev.h>
 
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/blkdev.h>
+
 #include <asm/setup.h>
 #include <asm/mpspec_def.h>
 #include <asm/hw_irq.h>
@@ -2471,3 +2475,27 @@ void mfld_hsu_disable_wakeup(int index, struct device *dev)
        }
 }
 
+#define EMMC_BLK_NAME  "mmcblk0"
+static int emmc_match(struct device *dev, void *data)
+{
+       if (strcmp(dev_name(dev), "mmcblk0") == 0)
+               return 1;
+       return 0;
+}
+int mmc_blk_rpmb_req_handle(struct mmc_rpmb_req *req)
+{
+       struct device *emmc = NULL;
+
+       if (!req)
+               return -EINVAL;
+
+       emmc = class_find_device(&block_class, NULL, EMMC_BLK_NAME, emmc_match);
+       if (!emmc) {
+               pr_err("%s: eMMC card is not registered yet. Try it later\n",
+                               __func__);
+               return -ENODEV;
+       }
+
+       return mmc_rpmb_req_handle(emmc, req);
+}
+EXPORT_SYMBOL_GPL(mmc_blk_rpmb_req_handle);
index aa2fd3a..c33b084 100644 (file)
@@ -99,6 +99,7 @@ struct mmc_blk_data {
 #define MMC_BLK_WRITE          BIT(1)
 #define MMC_BLK_DISCARD                BIT(2)
 #define MMC_BLK_SECDISCARD     BIT(3)
+#define MMC_BLK_RPMB           BIT(4)
 
        /*
         * Only set in main mmc_blk_data associated
@@ -417,6 +418,7 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
        int ret = -EINVAL;
        if (cmd == MMC_IOC_CMD)
                ret = mmc_blk_ioctl_cmd(bdev, (struct mmc_ioc_cmd __user *)arg);
+
        return ret;
 }
 
@@ -746,6 +748,111 @@ static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type)
        md->reset_done &= ~type;
 }
 
+int mmc_rpmb_req_handle(struct device *emmc, struct mmc_rpmb_req *req)
+{
+       int ret = 0;
+       struct gendisk *disk    = NULL;
+       struct mmc_card *card   = NULL;
+       struct mmc_blk_data *md = NULL;
+       unsigned int            part_curr;
+
+       if (!emmc)
+               return -ENODEV;
+
+       if (!req)
+               return -EINVAL;
+
+       disk = dev_to_disk(emmc);
+       if (!disk) {
+               pr_err("%s: NO eMMC disk found. Try it later\n",
+                               __func__);
+               return -ENODEV;
+       }
+
+       md = mmc_blk_get(disk);
+       if (!md) {
+               pr_err("%s: NO eMMC block data. Try it later\n",
+                               __func__);
+               return -ENODEV;
+       }
+       if (!(md->flags & MMC_BLK_CMD23)) {
+               pr_err("%s: CMD23 is not supported by host or device\n",
+                               mmc_hostname(card->host));
+               ret = -EOPNOTSUPP;
+               goto err;
+       }
+
+       card = mmc_dev_to_card(disk->driverfs_dev);
+       if (IS_ERR(card)) {
+               ret = PTR_ERR(card);
+               pr_err("%s: encounter error when getting eMMC card\n",
+                               __func__);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       if (!mmc_card_mmc(card) || !card->ext_csd.rpmb_size) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       /* check request */
+       ret = mmc_rpmb_pre_frame(req, card);
+       if (ret) {
+               pr_err("%s: prepare frame failed\n", mmc_hostname(card->host));
+               goto err;
+       }
+
+       mmc_claim_host(card->host);
+
+       /* * before start, let's change to RPMB partition first
+        */
+       part_curr = md->part_type;
+       md->part_type = EXT_CSD_PART_CONFIG_RPMB;
+       ret = mmc_blk_part_switch(card, md);
+       if (ret) {
+               pr_err("%s: Invalid RPMB partition switch (%d)!\n",
+                               mmc_hostname(card->host), ret);
+               /*
+                * In case partition is not in user data area, make
+                * a force partition switch
+                */
+               goto out;
+       }
+
+       ret = mmc_rpmb_partition_ops(req, card);
+       if (ret)
+               pr_err("%s: failed (%d) to handle RPMB request type (%d)!\n",
+                               mmc_hostname(card->host), ret, req->type);
+out:
+       /*
+        * switch back
+        */
+       md->part_type = part_curr;
+       if (mmc_blk_part_switch(card, md)) {
+               int err;
+               /*
+                * we need reset eMMC card at here
+                */
+               err = mmc_blk_reset(md, card->host, MMC_BLK_RPMB);
+               if (!err)
+                       mmc_blk_reset_success(md, MMC_BLK_RPMB);
+               else {
+                       pr_err("%s: eMMC card reset failed (%d)\n",
+                                       mmc_hostname(card->host), err);
+                       if (!ret)
+                               ret = err;
+               }
+       }
+       mmc_release_host(card->host);
+       mmc_rpmb_post_frame(req);
+err:
+       mmc_blk_put(md);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(mmc_rpmb_req_handle);
+
 static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
 {
        struct mmc_blk_data *md = mq->data;
index 14d9b32..809356c 100644 (file)
@@ -334,6 +334,9 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
                card->ext_csd.hc_erase_size =
                        ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10;
 
+               card->ext_csd.rpmb_size = 128 * ext_csd[EXT_CSD_RPMB_SIZE_MULT];
+               card->ext_csd.rpmb_size <<= 2; /* Unit: half sector */
+
                card->ext_csd.rel_sectors = ext_csd[EXT_CSD_REL_WR_SEC_C];
 
                /*
@@ -433,7 +436,17 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
                card->erased_byte = 0xFF;
        else
                card->erased_byte = 0x0;
-
+       /*
+        * If use legacy relaible write, then the blk counts must not
+        * big than the relaible write sectors
+        */
+       if (!(card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN)) {
+               if (card->ext_csd.rel_sectors < RPMB_AVALIABLE_SECTORS)
+                       card->rpmb_max_req = card->ext_csd.rel_sectors;
+               else
+                       card->rpmb_max_req = RPMB_AVALIABLE_SECTORS;
+       } else
+                       card->rpmb_max_req = RPMB_AVALIABLE_SECTORS;
 out:
        return err;
 }
@@ -528,6 +541,7 @@ MMC_DEV_ATTR(hpi_command, "%d\n", card->ext_csd.hpi_cmd);
 MMC_DEV_ATTR(hw_reset_support, "%d\n", card->ext_csd.rst_n_function);
 MMC_DEV_ATTR(bkops_support, "%d\n", card->ext_csd.bkops);
 MMC_DEV_ATTR(bkops_enable, "%d\n", card->ext_csd.bkops_en);
+MMC_DEV_ATTR(rpmb_size, "%d\n", card->ext_csd.rpmb_size);
 
 static struct attribute *mmc_std_attrs[] = {
        &dev_attr_cid.attr,
@@ -549,6 +563,7 @@ static struct attribute *mmc_std_attrs[] = {
        &dev_attr_hw_reset_support.attr,
        &dev_attr_bkops_support.attr,
        &dev_attr_bkops_enable.attr,
+       &dev_attr_rpmb_size.attr,
        NULL,
 };
 
index a780d7a..b96ea8c 100644 (file)
@@ -578,3 +578,402 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
 
        return 0;
 }
+
+static int mmc_rpmb_send_command(struct mmc_card *card, u8 *buf, __u16 blks,
+               __u16 type, u8 req_type)
+{
+       struct mmc_request mrq = {NULL};
+       struct mmc_command cmd = {0};
+       struct mmc_command sbc = {0};
+       struct mmc_data data = {0};
+       struct scatterlist sg;
+       u8 *transfer_buf = NULL;
+
+       mrq.sbc = &sbc;
+       mrq.cmd = &cmd;
+       mrq.data = &data;
+       mrq.stop = NULL;
+       transfer_buf = kzalloc(512 * blks, GFP_KERNEL);
+       if (!transfer_buf)
+               return -ENOMEM;
+
+       /*
+        * set CMD23
+        */
+       sbc.opcode = MMC_SET_BLOCK_COUNT;
+       sbc.arg = blks;
+       if ((req_type == RPMB_REQ) && (type == RPMB_WRITE_DATA ||
+                       type == RPMB_PROGRAM_KEY))
+               sbc.arg |= 1 << 31;
+       sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+       /*
+        * set CMD25/18
+        */
+       sg_init_one(&sg, transfer_buf, 512 * blks);
+       if (req_type == RPMB_REQ) {
+               cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK;
+               sg_copy_from_buffer(&sg, 1, buf, 512 * blks);
+               data.flags |= MMC_DATA_WRITE;
+       } else {
+               cmd.opcode = MMC_READ_MULTIPLE_BLOCK;
+               data.flags |= MMC_DATA_READ;
+       }
+       cmd.arg = 0;
+       cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+       data.blksz = 512;
+       data.blocks = blks;
+       data.sg = &sg;
+       data.sg_len = 1;
+
+       mmc_set_data_timeout(&data, card);
+
+       mmc_wait_for_req(card->host, &mrq);
+
+       if (req_type != RPMB_REQ)
+               sg_copy_to_buffer(&sg, 1, buf, 512 * blks);
+
+       kfree(transfer_buf);
+
+       if (cmd.error)
+               return cmd.error;
+       if (data.error)
+               return data.error;
+       return 0;
+}
+
+void mmc_rpmb_post_frame(struct mmc_rpmb_req *p_req)
+{
+       int i;
+       __u8 *ptr, *buf_frame = p_req->frame;
+
+       if (!p_req->ready || !buf_frame)
+               return;
+       /*
+        * Regarding to the check rules, here is the post
+        * rules
+        * All will return result.
+        * GET_WRITE_COUNTER:
+        *              must: write counter, nonce
+        *              optional: MAC
+        * WRITE_DATA:
+        *              must: MAC, write counter
+        * READ_DATA:
+        *              must: nonce, data
+        *              optional: MAC
+        * PROGRAM_KEY:
+        *              must: Nothing
+        *
+        * Except READ_DATA, all of these operations only need to parse
+        * one frame. READ_DATA needs blks frames to get DATA
+        */
+
+       memcpy(p_req->result, buf_frame + RPMB_RES_BEG, 2);
+       *p_req->result = be16_to_cpup(p_req->result);
+
+       if (p_req->type == RPMB_PROGRAM_KEY)
+               goto out;
+
+       if (p_req->type == RPMB_GET_WRITE_COUNTER ||
+                       p_req->type == RPMB_WRITE_DATA) {
+               memcpy(p_req->wc, buf_frame + RPMB_WCOUNTER_BEG, 4);
+               *p_req->wc = be32_to_cpup(p_req->wc);
+       }
+
+       if (p_req->type == RPMB_GET_WRITE_COUNTER ||
+                       p_req->type == RPMB_READ_DATA) {
+               /* nonce copy */
+               ptr = buf_frame + RPMB_NONCE_END;
+               for (i = 0; i < 16; i++, ptr--)
+                       p_req->nonce[i] = *ptr;
+       }
+       /*
+        * Take MAC within the last package
+        */
+       if (p_req->type == RPMB_READ_DATA) {
+               int j;
+               __u8 *data = p_req->data;
+               for (i = 0; i < p_req->blk_cnt; i++) {
+                       ptr = buf_frame + i * 512 + RPMB_DATA_END;
+                       for (j = 0; j < 256; j++, ptr--, data++)
+                               *data = *ptr;
+               }
+               /*
+                * MAC stored in the last package
+                */
+               if (p_req->mac) {
+                       ptr = buf_frame + 512 * i + RPMB_MAC_END;
+                       for (i = 0; i < 32; i++, ptr--)
+                               p_req->mac[i] = *ptr;
+               }
+       } else if (p_req->mac) {
+               ptr = buf_frame + RPMB_MAC_END;
+               for (i = 0; i < 32; i++, ptr--)
+                       p_req->mac[i] = *ptr;
+       }
+out:
+       kfree(buf_frame);
+       p_req->frame = NULL;
+       return;
+}
+EXPORT_SYMBOL_GPL(mmc_rpmb_post_frame);
+
+static int mmc_rpmb_request_check(struct mmc_card *card,
+               struct mmc_rpmb_req *p_req)
+{
+       /*
+        * Some paramter is a must for the operation. Different
+        * operation expect different paramters. Below code is
+        * used for checking this.
+        *
+        * All operations will need result.
+        * GET_WRITE_COUNTER:
+        *              must: write counter, nonce
+        *              optional: MAC
+        * WRITE_DATA:
+        *              must: MAC, data, write counter
+        * READ_DATA:
+        *              must: nonce, data
+        *              optional: MAC
+        * PROGRAM_KEY:
+        *              must: MAC
+        *
+        * So here, we only check the 'must' paramters
+        */
+       if (!p_req->result) {
+               pr_err("%s: Type %d has NULL pointer for result\n",
+                               mmc_hostname(card->host), p_req->type);
+               return -EINVAL;
+       }
+
+       if (p_req->type == RPMB_GET_WRITE_COUNTER) {
+               if (!p_req->nonce || !p_req->wc) {
+                       pr_err("%s: Type %d has NULL pointer for nonce/wc\n",
+                                       mmc_hostname(card->host), p_req->type);
+                       return -EINVAL;
+               }
+               p_req->blk_cnt = 1;
+       } else if (p_req->type == RPMB_WRITE_DATA ||
+                       p_req->type == RPMB_READ_DATA) {
+               if ((__u32)(p_req->addr + p_req->blk_cnt) >
+                               card->ext_csd.rpmb_size) {
+                       pr_err("%s Type %d: beyond the RPMB partition rang "
+                                       "addr %d, blk_cnt %d, rpmb_size %d\n",
+                                       mmc_hostname(card->host),
+                                       p_req->type,
+                                       p_req->addr,
+                                       p_req->blk_cnt,
+                                       card->ext_csd.rpmb_size);
+                       return -EINVAL;
+               }
+               if (!p_req->data) {
+                       pr_err("%s: Type %d has NULL pointer for data\n",
+                                       mmc_hostname(card->host), p_req->type);
+                       return -EINVAL;
+               }
+               if (p_req->type == RPMB_WRITE_DATA) {
+                       if (!p_req->wc || !p_req->mac) {
+                               pr_err("%s: Type %d has NULL pointer for"
+                                               " write counter/MAC\n",
+                                               mmc_hostname(card->host),
+                                               p_req->type);
+                               return -EINVAL;
+                       }
+               } else {
+                       if (!p_req->nonce) {
+                               pr_err("%s: Type %d has NULL pointer for"
+                                               " nonce\n",
+                                               mmc_hostname(card->host),
+                                               p_req->type);
+                               return -EINVAL;
+                       }
+               }
+       } else if (p_req->type == RPMB_PROGRAM_KEY) {
+               if (!p_req->mac) {
+                       pr_err("%s: Type %d has NULL pointer for MAC\n",
+                                       mmc_hostname(card->host), p_req->type);
+                       return -EINVAL;
+               }
+               p_req->blk_cnt = 1;
+       } else
+               return -EOPNOTSUPP;
+
+       if (p_req->blk_cnt == 0) {
+               pr_err("%s: Type %d has zero block count\n",
+                               mmc_hostname(card->host), p_req->blk_cnt);
+               return -EINVAL;
+       }
+
+       if (p_req->blk_cnt > card->rpmb_max_req) {
+               pr_err("%s: Type %d has invalid block count, "
+                               "cannot large than %d\n",
+                               mmc_hostname(card->host),
+                               p_req->blk_cnt,
+                               card->rpmb_max_req);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * prepare the request of RPMB frame
+ * RPMB frame is MSB first
+ * convert needed bytes
+ * return how many frames will be prepared
+ */
+int mmc_rpmb_pre_frame(struct mmc_rpmb_req *p_req,
+               struct mmc_card *card)
+{
+       int i, j, ret;
+       __u8 *ptr = NULL, *buf_frame;
+       __u8 *data = p_req->data;
+       __u16 blk_cnt, addr, type;
+       __u32 w_counter;
+
+       /*
+        * make sure these two items are clear
+        */
+       p_req->ready = 0;
+       p_req->frame = NULL;
+
+       ret = mmc_rpmb_request_check(card, p_req);
+       if (ret)
+               return ret;
+
+       buf_frame = kzalloc(512 * p_req->blk_cnt, GFP_KERNEL);
+       if (!buf_frame) {
+               pr_err("%s: cannot allocate frame for type %d\n",
+                               mmc_hostname(card->host), p_req->type);
+               return -ENOMEM;
+       }
+
+       type = cpu_to_be16p(&p_req->type);
+       if (p_req->type == RPMB_GET_WRITE_COUNTER ||
+                       p_req->type == RPMB_READ_DATA) {
+               /*
+                * One package prepared
+                * This request needs Nonce and type
+                * If is data read, then also need addr
+                */
+               memcpy(buf_frame + RPMB_TYPE_BEG, &type, 2);
+               if (p_req->type == RPMB_READ_DATA) {
+                       addr = cpu_to_be16p(&p_req->addr);
+                       memcpy(buf_frame + RPMB_ADDR_BEG, &addr, 2);
+               }
+               /* convert Nonce code */
+               ptr = buf_frame + RPMB_NONCE_END;
+               for (i = 0; i < 16; i++, ptr--)
+                       *ptr = p_req->nonce[i];
+       } else if (p_req->type == RPMB_WRITE_DATA) {
+               /*
+                * multiple package prepared
+                * This request nees blk_cnt, addr, write_counter,
+                * data and mac
+                */
+               blk_cnt = cpu_to_be16p(&p_req->blk_cnt);
+               addr = cpu_to_be16p(&p_req->addr);
+               w_counter = cpu_to_be32p(p_req->wc);
+               for (i = 0; i < p_req->blk_cnt; i++) {
+                       memcpy(buf_frame + i * 512 + RPMB_TYPE_BEG,
+                                       &type, 2);
+                       memcpy(buf_frame + i * 512 + RPMB_BLKS_BEG,
+                                       &blk_cnt, 2);
+                       memcpy(buf_frame + i * 512 + RPMB_ADDR_BEG,
+                                       &addr, 2);
+                       memcpy(buf_frame + i * 512 + RPMB_WCOUNTER_BEG,
+                                       &w_counter, 4);
+                       ptr = buf_frame + i * 512 + RPMB_DATA_END;
+                       for (j = 0; j < 256; j++, ptr--, data++)
+                               *ptr = *data;
+               }
+               ptr = buf_frame + 512 * (i - 1) + RPMB_MAC_END;
+               /* convert MAC code */
+               for (i = 0; i < 32; i++, ptr--)
+                       *ptr = p_req->mac[i];
+       } else if (p_req->type == RPMB_PROGRAM_KEY) {
+               /*
+                * One package prepared
+                * This request only need mac
+                */
+               memcpy(buf_frame + RPMB_TYPE_BEG, &type, 2);
+               ptr = buf_frame + RPMB_MAC_END;
+               /* convert MAC code */
+               for (i = 0; i < 32; i++, ptr--)
+                       *ptr = p_req->mac[i];
+       } else {
+               pr_err("%s: We shouldn't be here\n", mmc_hostname(card->host));
+               kfree(buf_frame);
+               return -EINVAL;
+       }
+       p_req->ready = 1;
+       p_req->frame = buf_frame;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mmc_rpmb_pre_frame);
+
+int mmc_rpmb_partition_ops(struct mmc_rpmb_req *p_req,
+               struct mmc_card *card)
+{
+       int err = 0;
+       __u16 type, blks;
+       __u8 *buf_frame = p_req->frame;
+
+       if (!p_req->ready || !buf_frame) {
+               pr_err("%s: mmc_rpmb_req is not prepared\n",
+                               mmc_hostname(card->host));
+               return -EINVAL;
+       }
+
+       type = p_req->type;
+       blks = p_req->blk_cnt;
+
+       /*
+        * STEP 1: send request to RPMB partition
+        */
+       if (type == RPMB_READ_DATA)
+               err = mmc_rpmb_send_command(card, buf_frame, 1, type, RPMB_REQ);
+       else
+               err = mmc_rpmb_send_command(card, buf_frame,
+                               blks, type, RPMB_REQ);
+       if (err) {
+               pr_err("%s: request write counter failed (%d)\n",
+                       mmc_hostname(card->host), err);
+               goto out;
+       }
+
+       memset(buf_frame, 0, 512 * blks);
+       /*
+        * STEP 2: check write result
+        * Only for WRITE_DATA or Program key
+        */
+       if (type == RPMB_WRITE_DATA ||
+                       type == RPMB_PROGRAM_KEY) {
+               buf_frame[RPMB_TYPE_BEG + 1] = RPMB_RESULT_READ;
+               err = mmc_rpmb_send_command(card, buf_frame, 1,
+                               RPMB_RESULT_READ, RPMB_REQ);
+               if (err) {
+                       pr_err("%s: request write counter failed (%d)\n",
+                               mmc_hostname(card->host), err);
+                       goto out;
+               }
+       }
+
+       /*
+        * STEP 3: get response from RPMB partition
+        */
+
+       if (type == RPMB_READ_DATA)
+               err = mmc_rpmb_send_command(card, buf_frame,
+                               blks, type, RPMB_RESP);
+       else
+               err = mmc_rpmb_send_command(card, buf_frame,
+                               1, type, RPMB_RESP);
+       if (err) {
+               pr_err("%s: response write counter failed (%d)\n",
+                       mmc_hostname(card->host), err);
+       }
+out:
+       return err;
+}
+EXPORT_SYMBOL_GPL(mmc_rpmb_partition_ops);
index 9ede2a7..44d0504 100644 (file)
@@ -70,6 +70,7 @@ struct mmc_ext_csd {
        unsigned int            hpi_cmd;                /* cmd used as HPI */
        bool                    bkops;                  /* BKOPS support bit */
        bool                    bkops_en;               /* BKOPS enable bit */
+       unsigned int            rpmb_size;              /* Units: half sector */
        u8                      raw_partition_support;  /* 160 */
        u8                      raw_erased_mem_count;   /* 181 */
        u8                      raw_ext_csd_structure;  /* 194 */
@@ -228,6 +229,8 @@ struct mmc_card {
        unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
 
        struct dentry           *debugfs_root;
+
+       unsigned int            rpmb_max_req;
 };
 
 /*
@@ -426,4 +429,6 @@ extern void mmc_unregister_driver(struct mmc_driver *);
 extern void mmc_fixup_device(struct mmc_card *card,
                             const struct mmc_fixup *table);
 
+extern int mmc_rpmb_req_handle(struct device *emmc, struct mmc_rpmb_req *req);
+
 #endif /* LINUX_MMC_CARD_H */
index 49f8705..584f4f2 100644 (file)
@@ -131,6 +131,40 @@ struct mmc_request {
        void                    (*done)(struct mmc_request *);/* completion function */
 };
 
+/*
+ * RPMB frame structure
+ */
+struct mmc_rpmb_req {
+       __u16 type;                     /* RPMB request type */
+       __u16 *result;                  /* response or request result */
+       __u16 blk_cnt;                  /* Number of blocks(half sector 256B) */
+       __u16 addr;                     /* data address */
+       __u32 *wc;                      /* write counter */
+       __u8 *nonce;                    /* Ramdom number */
+       __u8 *data;                     /* Buffer of the user data */
+       __u8 *mac;                      /* Message Authentication Code */
+       __u8 *frame;
+       bool ready;
+};
+
+#define RPMB_PROGRAM_KEY       1       /* Program RPMB Authentication Key */
+#define RPMB_GET_WRITE_COUNTER 2       /* Read RPMB write counter */
+#define RPMB_WRITE_DATA                3       /* Write data to RPMB partition */
+#define RPMB_READ_DATA         4       /* Read data from RPMB partition */
+#define RPMB_RESULT_READ       5       /* Read result request */
+#define RPMB_REQ               1       /* RPMB request mark */
+#define RPMB_RESP              (1 << 1)/* RPMB response mark */
+#define RPMB_AVALIABLE_SECTORS 8       /* 4K page size */
+
+#define RPMB_TYPE_BEG          510
+#define RPMB_RES_BEG           508
+#define RPMB_BLKS_BEG          506
+#define RPMB_ADDR_BEG          504
+#define RPMB_WCOUNTER_BEG      500
+#define RPMB_NONCE_END         499
+#define RPMB_DATA_END          483
+#define RPMB_MAC_END           227
+
 struct mmc_host;
 struct mmc_card;
 struct mmc_async_req;
@@ -144,6 +178,11 @@ extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
        struct mmc_command *, int);
 extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
 
+extern int mmc_rpmb_partition_ops(struct mmc_rpmb_req *,
+               struct mmc_card *);
+extern int mmc_rpmb_pre_frame(struct mmc_rpmb_req *, struct mmc_card *);
+extern void mmc_rpmb_post_frame(struct mmc_rpmb_req *);
+
 #define MMC_ERASE_ARG          0x00000000
 #define MMC_SECURE_ERASE_ARG   0x80000000
 #define MMC_TRIM_ARG           0x00000001
index 964a7c9..3ee73fb 100644 (file)
@@ -278,6 +278,7 @@ struct _mmc_csd {
 #define EXT_CSD_BKOPS_EN               163     /* R/W */
 #define EXT_CSD_BKOPS_START            164     /* W */
 #define EXT_CSD_WR_REL_PARAM           166     /* RO */
+#define EXT_CSD_RPMB_SIZE_MULT         168     /* R */
 #define EXT_CSD_ERASE_GROUP_DEF                175     /* R/W */
 #define EXT_CSD_PART_CONFIG            179     /* R/W */
 #define EXT_CSD_ERASED_MEM_CONT                181     /* RO */
@@ -311,6 +312,7 @@ struct _mmc_csd {
 #define EXT_CSD_PART_CONFIG_ACC_MASK   (0x7)
 #define EXT_CSD_PART_CONFIG_ACC_BOOT0  (0x1)
 #define EXT_CSD_PART_CONFIG_ACC_BOOT1  (0x2)
+#define EXT_CSD_PART_CONFIG_RPMB       (0x3)
 
 #define EXT_CSD_CMD_SET_NORMAL         (1<<0)
 #define EXT_CSD_CMD_SET_SECURE         (1<<1)