dm: core: Create a new header file for 'compat' features
[oweals/u-boot.git] / drivers / tee / optee / rpmb.c
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2018 Linaro Limited
4  */
5
6 #include <common.h>
7 #include <dm.h>
8 #include <log.h>
9 #include <tee.h>
10 #include <mmc.h>
11 #include <dm/device_compat.h>
12
13 #include "optee_msg.h"
14 #include "optee_private.h"
15
16 /*
17  * Request and response definitions must be in sync with the secure side of
18  * OP-TEE.
19  */
20
21 /* Request */
22 struct rpmb_req {
23         u16 cmd;
24 #define RPMB_CMD_DATA_REQ      0x00
25 #define RPMB_CMD_GET_DEV_INFO  0x01
26         u16 dev_id;
27         u16 block_count;
28         /* Optional data frames (rpmb_data_frame) follow */
29 };
30
31 #define RPMB_REQ_DATA(req) ((void *)((struct rpmb_req *)(req) + 1))
32
33 /* Response to device info request */
34 struct rpmb_dev_info {
35         u8 cid[16];
36         u8 rpmb_size_mult;      /* EXT CSD-slice 168: RPMB Size */
37         u8 rel_wr_sec_c;        /* EXT CSD-slice 222: Reliable Write Sector */
38                                 /*                    Count */
39         u8 ret_code;
40 #define RPMB_CMD_GET_DEV_INFO_RET_OK     0x00
41 #define RPMB_CMD_GET_DEV_INFO_RET_ERROR  0x01
42 };
43
44 static void release_mmc(struct optee_private *priv)
45 {
46         int rc;
47
48         if (!priv->rpmb_mmc)
49                 return;
50
51         rc = blk_select_hwpart_devnum(IF_TYPE_MMC, priv->rpmb_dev_id,
52                                       priv->rpmb_original_part);
53         if (rc)
54                 debug("%s: blk_select_hwpart_devnum() failed: %d\n",
55                       __func__, rc);
56
57         priv->rpmb_mmc = NULL;
58 }
59
60 static struct mmc *get_mmc(struct optee_private *priv, int dev_id)
61 {
62         struct mmc *mmc;
63         int rc;
64
65         if (priv->rpmb_mmc && priv->rpmb_dev_id == dev_id)
66                 return priv->rpmb_mmc;
67
68         release_mmc(priv);
69
70         mmc = find_mmc_device(dev_id);
71         if (!mmc) {
72                 debug("Cannot find RPMB device\n");
73                 return NULL;
74         }
75         if (!(mmc->version & MMC_VERSION_MMC)) {
76                 debug("Device id %d is not an eMMC device\n", dev_id);
77                 return NULL;
78         }
79         if (mmc->version < MMC_VERSION_4_41) {
80                 debug("Device id %d: RPMB not supported before version 4.41\n",
81                       dev_id);
82                 return NULL;
83         }
84
85         priv->rpmb_original_part = mmc_get_blk_desc(mmc)->hwpart;
86
87         rc = blk_select_hwpart_devnum(IF_TYPE_MMC, dev_id, MMC_PART_RPMB);
88         if (rc) {
89                 debug("Device id %d: cannot select RPMB partition: %d\n",
90                       dev_id, rc);
91                 return NULL;
92         }
93
94         priv->rpmb_mmc = mmc;
95         priv->rpmb_dev_id = dev_id;
96         return mmc;
97 }
98
99 static u32 rpmb_get_dev_info(u16 dev_id, struct rpmb_dev_info *info)
100 {
101         struct mmc *mmc = find_mmc_device(dev_id);
102         int i;
103
104         if (!mmc)
105                 return TEE_ERROR_ITEM_NOT_FOUND;
106
107         if (!mmc->ext_csd)
108                 return TEE_ERROR_GENERIC;
109
110         for (i = 0; i < ARRAY_SIZE(mmc->cid); i++)
111                 ((u32 *) info->cid)[i] = cpu_to_be32(mmc->cid[i]);
112
113         info->rel_wr_sec_c = mmc->ext_csd[222];
114         info->rpmb_size_mult = mmc->ext_csd[168];
115         info->ret_code = RPMB_CMD_GET_DEV_INFO_RET_OK;
116
117         return TEE_SUCCESS;
118 }
119
120 static u32 rpmb_process_request(struct optee_private *priv, void *req,
121                                 ulong req_size, void *rsp, ulong rsp_size)
122 {
123         struct rpmb_req *sreq = req;
124         struct mmc *mmc;
125
126         if (req_size < sizeof(*sreq))
127                 return TEE_ERROR_BAD_PARAMETERS;
128
129         switch (sreq->cmd) {
130         case RPMB_CMD_DATA_REQ:
131                 mmc = get_mmc(priv, sreq->dev_id);
132                 if (!mmc)
133                         return TEE_ERROR_ITEM_NOT_FOUND;
134                 if (mmc_rpmb_route_frames(mmc, RPMB_REQ_DATA(req),
135                                           req_size - sizeof(struct rpmb_req),
136                                           rsp, rsp_size))
137                         return TEE_ERROR_BAD_PARAMETERS;
138                 return TEE_SUCCESS;
139
140         case RPMB_CMD_GET_DEV_INFO:
141                 if (req_size != sizeof(struct rpmb_req) ||
142                     rsp_size != sizeof(struct rpmb_dev_info)) {
143                         debug("Invalid req/rsp size\n");
144                         return TEE_ERROR_BAD_PARAMETERS;
145                 }
146                 return rpmb_get_dev_info(sreq->dev_id, rsp);
147
148         default:
149                 debug("Unsupported RPMB command: %d\n", sreq->cmd);
150                 return TEE_ERROR_BAD_PARAMETERS;
151         }
152 }
153
154 void optee_suppl_cmd_rpmb(struct udevice *dev, struct optee_msg_arg *arg)
155 {
156         struct tee_shm *req_shm;
157         struct tee_shm *rsp_shm;
158         void *req_buf;
159         void *rsp_buf;
160         ulong req_size;
161         ulong rsp_size;
162
163         if (arg->num_params != 2 ||
164             arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_RMEM_INPUT ||
165             arg->params[1].attr != OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT) {
166                 arg->ret = TEE_ERROR_BAD_PARAMETERS;
167                 return;
168         }
169
170         req_shm = (struct tee_shm *)(ulong)arg->params[0].u.rmem.shm_ref;
171         req_buf = (u8 *)req_shm->addr + arg->params[0].u.rmem.offs;
172         req_size = arg->params[0].u.rmem.size;
173
174         rsp_shm = (struct tee_shm *)(ulong)arg->params[1].u.rmem.shm_ref;
175         rsp_buf = (u8 *)rsp_shm->addr + arg->params[1].u.rmem.offs;
176         rsp_size = arg->params[1].u.rmem.size;
177
178         arg->ret = rpmb_process_request(dev_get_priv(dev), req_buf, req_size,
179                                         rsp_buf, rsp_size);
180 }
181
182 void optee_suppl_rpmb_release(struct udevice *dev)
183 {
184         release_mmc(dev_get_priv(dev));
185 }