183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
291fdabc6SPierre Aubert /*
391fdabc6SPierre Aubert * Copyright 2014, Staubli Faverges
491fdabc6SPierre Aubert * Pierre Aubert
591fdabc6SPierre Aubert *
691fdabc6SPierre Aubert * eMMC- Replay Protected Memory Block
791fdabc6SPierre Aubert * According to JEDEC Standard No. 84-A441
891fdabc6SPierre Aubert */
991fdabc6SPierre Aubert
1091fdabc6SPierre Aubert #include <config.h>
1191fdabc6SPierre Aubert #include <common.h>
12cf92e05cSSimon Glass #include <memalign.h>
1391fdabc6SPierre Aubert #include <mmc.h>
142b9912e6SJeroen Hofstee #include <u-boot/sha256.h>
1591fdabc6SPierre Aubert #include "mmc_private.h"
1691fdabc6SPierre Aubert
1791fdabc6SPierre Aubert /* Request codes */
1891fdabc6SPierre Aubert #define RPMB_REQ_KEY 1
1991fdabc6SPierre Aubert #define RPMB_REQ_WCOUNTER 2
2091fdabc6SPierre Aubert #define RPMB_REQ_WRITE_DATA 3
2191fdabc6SPierre Aubert #define RPMB_REQ_READ_DATA 4
2291fdabc6SPierre Aubert #define RPMB_REQ_STATUS 5
2391fdabc6SPierre Aubert
2491fdabc6SPierre Aubert /* Response code */
2591fdabc6SPierre Aubert #define RPMB_RESP_KEY 0x0100
2691fdabc6SPierre Aubert #define RPMB_RESP_WCOUNTER 0x0200
2791fdabc6SPierre Aubert #define RPMB_RESP_WRITE_DATA 0x0300
2891fdabc6SPierre Aubert #define RPMB_RESP_READ_DATA 0x0400
2991fdabc6SPierre Aubert
3091fdabc6SPierre Aubert /* Error codes */
3191fdabc6SPierre Aubert #define RPMB_OK 0
3291fdabc6SPierre Aubert #define RPMB_ERR_GENERAL 1
3391fdabc6SPierre Aubert #define RPMB_ERR_AUTH 2
3491fdabc6SPierre Aubert #define RPMB_ERR_COUNTER 3
3591fdabc6SPierre Aubert #define RPMB_ERR_ADDRESS 4
3691fdabc6SPierre Aubert #define RPMB_ERR_WRITE 5
3791fdabc6SPierre Aubert #define RPMB_ERR_READ 6
3891fdabc6SPierre Aubert #define RPMB_ERR_KEY 7
3991fdabc6SPierre Aubert #define RPMB_ERR_CNT_EXPIRED 0x80
4091fdabc6SPierre Aubert #define RPMB_ERR_MSK 0x7
4191fdabc6SPierre Aubert
4291fdabc6SPierre Aubert /* Sizes of RPMB data frame */
4391fdabc6SPierre Aubert #define RPMB_SZ_STUFF 196
4491fdabc6SPierre Aubert #define RPMB_SZ_MAC 32
4591fdabc6SPierre Aubert #define RPMB_SZ_DATA 256
4691fdabc6SPierre Aubert #define RPMB_SZ_NONCE 16
4791fdabc6SPierre Aubert
4891fdabc6SPierre Aubert #define SHA256_BLOCK_SIZE 64
4991fdabc6SPierre Aubert
5091fdabc6SPierre Aubert /* Error messages */
5191fdabc6SPierre Aubert static const char * const rpmb_err_msg[] = {
5291fdabc6SPierre Aubert "",
5391fdabc6SPierre Aubert "General failure",
5491fdabc6SPierre Aubert "Authentication failure",
5591fdabc6SPierre Aubert "Counter failure",
5691fdabc6SPierre Aubert "Address failure",
5791fdabc6SPierre Aubert "Write failure",
5891fdabc6SPierre Aubert "Read failure",
5991fdabc6SPierre Aubert "Authentication key not yet programmed",
6091fdabc6SPierre Aubert };
6191fdabc6SPierre Aubert
6291fdabc6SPierre Aubert
6391fdabc6SPierre Aubert /* Structure of RPMB data frame. */
6491fdabc6SPierre Aubert struct s_rpmb {
6591fdabc6SPierre Aubert unsigned char stuff[RPMB_SZ_STUFF];
6691fdabc6SPierre Aubert unsigned char mac[RPMB_SZ_MAC];
6791fdabc6SPierre Aubert unsigned char data[RPMB_SZ_DATA];
6891fdabc6SPierre Aubert unsigned char nonce[RPMB_SZ_NONCE];
69343749c4SKever Yang unsigned int write_counter;
7091fdabc6SPierre Aubert unsigned short address;
7191fdabc6SPierre Aubert unsigned short block_count;
7291fdabc6SPierre Aubert unsigned short result;
7391fdabc6SPierre Aubert unsigned short request;
7491fdabc6SPierre Aubert };
7591fdabc6SPierre Aubert
mmc_set_blockcount(struct mmc * mmc,unsigned int blockcount,bool is_rel_write)7691fdabc6SPierre Aubert static int mmc_set_blockcount(struct mmc *mmc, unsigned int blockcount,
7791fdabc6SPierre Aubert bool is_rel_write)
7891fdabc6SPierre Aubert {
7991fdabc6SPierre Aubert struct mmc_cmd cmd = {0};
8091fdabc6SPierre Aubert
8191fdabc6SPierre Aubert cmd.cmdidx = MMC_CMD_SET_BLOCK_COUNT;
8291fdabc6SPierre Aubert cmd.cmdarg = blockcount & 0x0000FFFF;
8391fdabc6SPierre Aubert if (is_rel_write)
8491fdabc6SPierre Aubert cmd.cmdarg |= 1 << 31;
8591fdabc6SPierre Aubert cmd.resp_type = MMC_RSP_R1;
8691fdabc6SPierre Aubert
8791fdabc6SPierre Aubert return mmc_send_cmd(mmc, &cmd, NULL);
8891fdabc6SPierre Aubert }
mmc_rpmb_request(struct mmc * mmc,const struct s_rpmb * s,unsigned int count,bool is_rel_write)8991fdabc6SPierre Aubert static int mmc_rpmb_request(struct mmc *mmc, const struct s_rpmb *s,
9091fdabc6SPierre Aubert unsigned int count, bool is_rel_write)
9191fdabc6SPierre Aubert {
9291fdabc6SPierre Aubert struct mmc_cmd cmd = {0};
9391fdabc6SPierre Aubert struct mmc_data data;
9491fdabc6SPierre Aubert int ret;
9591fdabc6SPierre Aubert
9691fdabc6SPierre Aubert ret = mmc_set_blockcount(mmc, count, is_rel_write);
9791fdabc6SPierre Aubert if (ret) {
9891fdabc6SPierre Aubert #ifdef CONFIG_MMC_RPMB_TRACE
9991fdabc6SPierre Aubert printf("%s:mmc_set_blockcount-> %d\n", __func__, ret);
10091fdabc6SPierre Aubert #endif
10191fdabc6SPierre Aubert return 1;
10291fdabc6SPierre Aubert }
10391fdabc6SPierre Aubert
10491fdabc6SPierre Aubert cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
10591fdabc6SPierre Aubert cmd.cmdarg = 0;
10691fdabc6SPierre Aubert cmd.resp_type = MMC_RSP_R1b;
10791fdabc6SPierre Aubert
10891fdabc6SPierre Aubert data.src = (const char *)s;
10991fdabc6SPierre Aubert data.blocks = 1;
11091fdabc6SPierre Aubert data.blocksize = MMC_MAX_BLOCK_LEN;
11191fdabc6SPierre Aubert data.flags = MMC_DATA_WRITE;
11291fdabc6SPierre Aubert
11391fdabc6SPierre Aubert ret = mmc_send_cmd(mmc, &cmd, &data);
11491fdabc6SPierre Aubert if (ret) {
11591fdabc6SPierre Aubert #ifdef CONFIG_MMC_RPMB_TRACE
11691fdabc6SPierre Aubert printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
11791fdabc6SPierre Aubert #endif
11891fdabc6SPierre Aubert return 1;
11991fdabc6SPierre Aubert }
12091fdabc6SPierre Aubert return 0;
12191fdabc6SPierre Aubert }
mmc_rpmb_response(struct mmc * mmc,struct s_rpmb * s,unsigned short expected)12291fdabc6SPierre Aubert static int mmc_rpmb_response(struct mmc *mmc, struct s_rpmb *s,
12391fdabc6SPierre Aubert unsigned short expected)
12491fdabc6SPierre Aubert {
12591fdabc6SPierre Aubert struct mmc_cmd cmd = {0};
12691fdabc6SPierre Aubert struct mmc_data data;
12791fdabc6SPierre Aubert int ret;
12891fdabc6SPierre Aubert
12991fdabc6SPierre Aubert ret = mmc_set_blockcount(mmc, 1, false);
13091fdabc6SPierre Aubert if (ret) {
13191fdabc6SPierre Aubert #ifdef CONFIG_MMC_RPMB_TRACE
13291fdabc6SPierre Aubert printf("%s:mmc_set_blockcount-> %d\n", __func__, ret);
13391fdabc6SPierre Aubert #endif
13491fdabc6SPierre Aubert return -1;
13591fdabc6SPierre Aubert }
13691fdabc6SPierre Aubert cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
13791fdabc6SPierre Aubert cmd.cmdarg = 0;
13891fdabc6SPierre Aubert cmd.resp_type = MMC_RSP_R1;
13991fdabc6SPierre Aubert
14091fdabc6SPierre Aubert data.dest = (char *)s;
14191fdabc6SPierre Aubert data.blocks = 1;
14291fdabc6SPierre Aubert data.blocksize = MMC_MAX_BLOCK_LEN;
14391fdabc6SPierre Aubert data.flags = MMC_DATA_READ;
14491fdabc6SPierre Aubert
14591fdabc6SPierre Aubert ret = mmc_send_cmd(mmc, &cmd, &data);
14691fdabc6SPierre Aubert if (ret) {
14791fdabc6SPierre Aubert #ifdef CONFIG_MMC_RPMB_TRACE
14891fdabc6SPierre Aubert printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
14991fdabc6SPierre Aubert #endif
15091fdabc6SPierre Aubert return -1;
15191fdabc6SPierre Aubert }
15291fdabc6SPierre Aubert /* Check the response and the status */
15391fdabc6SPierre Aubert if (be16_to_cpu(s->request) != expected) {
15491fdabc6SPierre Aubert #ifdef CONFIG_MMC_RPMB_TRACE
15591fdabc6SPierre Aubert printf("%s:response= %x\n", __func__,
15691fdabc6SPierre Aubert be16_to_cpu(s->request));
15791fdabc6SPierre Aubert #endif
15891fdabc6SPierre Aubert return -1;
15991fdabc6SPierre Aubert }
16091fdabc6SPierre Aubert ret = be16_to_cpu(s->result);
16191fdabc6SPierre Aubert if (ret) {
16291fdabc6SPierre Aubert printf("%s %s\n", rpmb_err_msg[ret & RPMB_ERR_MSK],
16391fdabc6SPierre Aubert (ret & RPMB_ERR_CNT_EXPIRED) ?
16491fdabc6SPierre Aubert "Write counter has expired" : "");
16591fdabc6SPierre Aubert }
16691fdabc6SPierre Aubert
16791fdabc6SPierre Aubert /* Return the status of the command */
16891fdabc6SPierre Aubert return ret;
16991fdabc6SPierre Aubert }
mmc_rpmb_status(struct mmc * mmc,unsigned short expected)17091fdabc6SPierre Aubert static int mmc_rpmb_status(struct mmc *mmc, unsigned short expected)
17191fdabc6SPierre Aubert {
17291fdabc6SPierre Aubert ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
17391fdabc6SPierre Aubert
17491fdabc6SPierre Aubert memset(rpmb_frame, 0, sizeof(struct s_rpmb));
17591fdabc6SPierre Aubert rpmb_frame->request = cpu_to_be16(RPMB_REQ_STATUS);
17691fdabc6SPierre Aubert if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
17791fdabc6SPierre Aubert return -1;
17891fdabc6SPierre Aubert
17991fdabc6SPierre Aubert /* Read the result */
18091fdabc6SPierre Aubert return mmc_rpmb_response(mmc, rpmb_frame, expected);
18191fdabc6SPierre Aubert }
rpmb_hmac(unsigned char * key,unsigned char * buff,int len,unsigned char * output)18291fdabc6SPierre Aubert static void rpmb_hmac(unsigned char *key, unsigned char *buff, int len,
18391fdabc6SPierre Aubert unsigned char *output)
18491fdabc6SPierre Aubert {
18591fdabc6SPierre Aubert sha256_context ctx;
18691fdabc6SPierre Aubert int i;
18791fdabc6SPierre Aubert unsigned char k_ipad[SHA256_BLOCK_SIZE];
18891fdabc6SPierre Aubert unsigned char k_opad[SHA256_BLOCK_SIZE];
18991fdabc6SPierre Aubert
19091fdabc6SPierre Aubert sha256_starts(&ctx);
19191fdabc6SPierre Aubert
19291fdabc6SPierre Aubert /* According to RFC 4634, the HMAC transform looks like:
19391fdabc6SPierre Aubert SHA(K XOR opad, SHA(K XOR ipad, text))
19491fdabc6SPierre Aubert
19591fdabc6SPierre Aubert where K is an n byte key.
19691fdabc6SPierre Aubert ipad is the byte 0x36 repeated blocksize times
19791fdabc6SPierre Aubert opad is the byte 0x5c repeated blocksize times
19891fdabc6SPierre Aubert and text is the data being protected.
19991fdabc6SPierre Aubert */
20091fdabc6SPierre Aubert
20191fdabc6SPierre Aubert for (i = 0; i < RPMB_SZ_MAC; i++) {
20291fdabc6SPierre Aubert k_ipad[i] = key[i] ^ 0x36;
20391fdabc6SPierre Aubert k_opad[i] = key[i] ^ 0x5c;
20491fdabc6SPierre Aubert }
20591fdabc6SPierre Aubert /* remaining pad bytes are '\0' XOR'd with ipad and opad values */
20691fdabc6SPierre Aubert for ( ; i < SHA256_BLOCK_SIZE; i++) {
20791fdabc6SPierre Aubert k_ipad[i] = 0x36;
20891fdabc6SPierre Aubert k_opad[i] = 0x5c;
20991fdabc6SPierre Aubert }
21091fdabc6SPierre Aubert sha256_update(&ctx, k_ipad, SHA256_BLOCK_SIZE);
21191fdabc6SPierre Aubert sha256_update(&ctx, buff, len);
21291fdabc6SPierre Aubert sha256_finish(&ctx, output);
21391fdabc6SPierre Aubert
21491fdabc6SPierre Aubert /* Init context for second pass */
21591fdabc6SPierre Aubert sha256_starts(&ctx);
21691fdabc6SPierre Aubert
21791fdabc6SPierre Aubert /* start with outer pad */
21891fdabc6SPierre Aubert sha256_update(&ctx, k_opad, SHA256_BLOCK_SIZE);
21991fdabc6SPierre Aubert
22091fdabc6SPierre Aubert /* then results of 1st hash */
22191fdabc6SPierre Aubert sha256_update(&ctx, output, RPMB_SZ_MAC);
22291fdabc6SPierre Aubert
22391fdabc6SPierre Aubert /* finish up 2nd pass */
22491fdabc6SPierre Aubert sha256_finish(&ctx, output);
22591fdabc6SPierre Aubert }
mmc_rpmb_get_counter(struct mmc * mmc,unsigned long * pcounter)22691fdabc6SPierre Aubert int mmc_rpmb_get_counter(struct mmc *mmc, unsigned long *pcounter)
22791fdabc6SPierre Aubert {
22891fdabc6SPierre Aubert int ret;
22991fdabc6SPierre Aubert ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
23091fdabc6SPierre Aubert
23191fdabc6SPierre Aubert /* Fill the request */
23291fdabc6SPierre Aubert memset(rpmb_frame, 0, sizeof(struct s_rpmb));
23391fdabc6SPierre Aubert rpmb_frame->request = cpu_to_be16(RPMB_REQ_WCOUNTER);
23491fdabc6SPierre Aubert if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
23591fdabc6SPierre Aubert return -1;
23691fdabc6SPierre Aubert
23791fdabc6SPierre Aubert /* Read the result */
23891fdabc6SPierre Aubert ret = mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_WCOUNTER);
23991fdabc6SPierre Aubert if (ret)
24091fdabc6SPierre Aubert return ret;
24191fdabc6SPierre Aubert
24291fdabc6SPierre Aubert *pcounter = be32_to_cpu(rpmb_frame->write_counter);
24391fdabc6SPierre Aubert return 0;
24491fdabc6SPierre Aubert }
mmc_rpmb_set_key(struct mmc * mmc,void * key)24591fdabc6SPierre Aubert int mmc_rpmb_set_key(struct mmc *mmc, void *key)
24691fdabc6SPierre Aubert {
24791fdabc6SPierre Aubert ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
24891fdabc6SPierre Aubert /* Fill the request */
24991fdabc6SPierre Aubert memset(rpmb_frame, 0, sizeof(struct s_rpmb));
25091fdabc6SPierre Aubert rpmb_frame->request = cpu_to_be16(RPMB_REQ_KEY);
25191fdabc6SPierre Aubert memcpy(rpmb_frame->mac, key, RPMB_SZ_MAC);
25291fdabc6SPierre Aubert
25391fdabc6SPierre Aubert if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
25491fdabc6SPierre Aubert return -1;
25591fdabc6SPierre Aubert
25691fdabc6SPierre Aubert /* read the operation status */
25791fdabc6SPierre Aubert return mmc_rpmb_status(mmc, RPMB_RESP_KEY);
25891fdabc6SPierre Aubert }
mmc_rpmb_read(struct mmc * mmc,void * addr,unsigned short blk,unsigned short cnt,unsigned char * key)25991fdabc6SPierre Aubert int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk,
26091fdabc6SPierre Aubert unsigned short cnt, unsigned char *key)
26191fdabc6SPierre Aubert {
26291fdabc6SPierre Aubert ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
26391fdabc6SPierre Aubert int i;
26491fdabc6SPierre Aubert
26591fdabc6SPierre Aubert for (i = 0; i < cnt; i++) {
26691fdabc6SPierre Aubert /* Fill the request */
26791fdabc6SPierre Aubert memset(rpmb_frame, 0, sizeof(struct s_rpmb));
26891fdabc6SPierre Aubert rpmb_frame->address = cpu_to_be16(blk + i);
26991fdabc6SPierre Aubert rpmb_frame->request = cpu_to_be16(RPMB_REQ_READ_DATA);
27091fdabc6SPierre Aubert if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
27191fdabc6SPierre Aubert break;
27291fdabc6SPierre Aubert
27391fdabc6SPierre Aubert /* Read the result */
27491fdabc6SPierre Aubert if (mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_READ_DATA))
27591fdabc6SPierre Aubert break;
27691fdabc6SPierre Aubert
27791fdabc6SPierre Aubert /* Check the HMAC if key is provided */
27891fdabc6SPierre Aubert if (key) {
27991fdabc6SPierre Aubert unsigned char ret_hmac[RPMB_SZ_MAC];
28091fdabc6SPierre Aubert
28191fdabc6SPierre Aubert rpmb_hmac(key, rpmb_frame->data, 284, ret_hmac);
28291fdabc6SPierre Aubert if (memcmp(ret_hmac, rpmb_frame->mac, RPMB_SZ_MAC)) {
28391fdabc6SPierre Aubert printf("MAC error on block #%d\n", i);
28491fdabc6SPierre Aubert break;
28591fdabc6SPierre Aubert }
28691fdabc6SPierre Aubert }
28791fdabc6SPierre Aubert /* Copy data */
28891fdabc6SPierre Aubert memcpy(addr + i * RPMB_SZ_DATA, rpmb_frame->data, RPMB_SZ_DATA);
28991fdabc6SPierre Aubert }
29091fdabc6SPierre Aubert return i;
29191fdabc6SPierre Aubert }
mmc_rpmb_write(struct mmc * mmc,void * addr,unsigned short blk,unsigned short cnt,unsigned char * key)29291fdabc6SPierre Aubert int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk,
29391fdabc6SPierre Aubert unsigned short cnt, unsigned char *key)
29491fdabc6SPierre Aubert {
29591fdabc6SPierre Aubert ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
29691fdabc6SPierre Aubert unsigned long wcount;
29791fdabc6SPierre Aubert int i;
29891fdabc6SPierre Aubert
29991fdabc6SPierre Aubert for (i = 0; i < cnt; i++) {
30091fdabc6SPierre Aubert if (mmc_rpmb_get_counter(mmc, &wcount)) {
30191fdabc6SPierre Aubert printf("Cannot read RPMB write counter\n");
30291fdabc6SPierre Aubert break;
30391fdabc6SPierre Aubert }
30491fdabc6SPierre Aubert
30591fdabc6SPierre Aubert /* Fill the request */
30691fdabc6SPierre Aubert memset(rpmb_frame, 0, sizeof(struct s_rpmb));
30791fdabc6SPierre Aubert memcpy(rpmb_frame->data, addr + i * RPMB_SZ_DATA, RPMB_SZ_DATA);
30891fdabc6SPierre Aubert rpmb_frame->address = cpu_to_be16(blk + i);
30991fdabc6SPierre Aubert rpmb_frame->block_count = cpu_to_be16(1);
31091fdabc6SPierre Aubert rpmb_frame->write_counter = cpu_to_be32(wcount);
31191fdabc6SPierre Aubert rpmb_frame->request = cpu_to_be16(RPMB_REQ_WRITE_DATA);
31291fdabc6SPierre Aubert /* Computes HMAC */
31391fdabc6SPierre Aubert rpmb_hmac(key, rpmb_frame->data, 284, rpmb_frame->mac);
31491fdabc6SPierre Aubert
31591fdabc6SPierre Aubert if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
31691fdabc6SPierre Aubert break;
31791fdabc6SPierre Aubert
31891fdabc6SPierre Aubert /* Get status */
31991fdabc6SPierre Aubert if (mmc_rpmb_status(mmc, RPMB_RESP_WRITE_DATA))
32091fdabc6SPierre Aubert break;
32191fdabc6SPierre Aubert }
32291fdabc6SPierre Aubert return i;
32391fdabc6SPierre Aubert }
324*4853ad3eSJens Wiklander
send_write_mult_block(struct mmc * mmc,const struct s_rpmb * frm,unsigned short cnt)325*4853ad3eSJens Wiklander static int send_write_mult_block(struct mmc *mmc, const struct s_rpmb *frm,
326*4853ad3eSJens Wiklander unsigned short cnt)
327*4853ad3eSJens Wiklander {
328*4853ad3eSJens Wiklander struct mmc_cmd cmd = {
329*4853ad3eSJens Wiklander .cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK,
330*4853ad3eSJens Wiklander .resp_type = MMC_RSP_R1b,
331*4853ad3eSJens Wiklander };
332*4853ad3eSJens Wiklander struct mmc_data data = {
333*4853ad3eSJens Wiklander .src = (const void *)frm,
334*4853ad3eSJens Wiklander .blocks = cnt,
335*4853ad3eSJens Wiklander .blocksize = sizeof(*frm),
336*4853ad3eSJens Wiklander .flags = MMC_DATA_WRITE,
337*4853ad3eSJens Wiklander };
338*4853ad3eSJens Wiklander
339*4853ad3eSJens Wiklander return mmc_send_cmd(mmc, &cmd, &data);
340*4853ad3eSJens Wiklander }
341*4853ad3eSJens Wiklander
send_read_mult_block(struct mmc * mmc,struct s_rpmb * frm,unsigned short cnt)342*4853ad3eSJens Wiklander static int send_read_mult_block(struct mmc *mmc, struct s_rpmb *frm,
343*4853ad3eSJens Wiklander unsigned short cnt)
344*4853ad3eSJens Wiklander {
345*4853ad3eSJens Wiklander struct mmc_cmd cmd = {
346*4853ad3eSJens Wiklander .cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK,
347*4853ad3eSJens Wiklander .resp_type = MMC_RSP_R1,
348*4853ad3eSJens Wiklander };
349*4853ad3eSJens Wiklander struct mmc_data data = {
350*4853ad3eSJens Wiklander .dest = (void *)frm,
351*4853ad3eSJens Wiklander .blocks = cnt,
352*4853ad3eSJens Wiklander .blocksize = sizeof(*frm),
353*4853ad3eSJens Wiklander .flags = MMC_DATA_READ,
354*4853ad3eSJens Wiklander };
355*4853ad3eSJens Wiklander
356*4853ad3eSJens Wiklander return mmc_send_cmd(mmc, &cmd, &data);
357*4853ad3eSJens Wiklander }
358*4853ad3eSJens Wiklander
rpmb_route_write_req(struct mmc * mmc,struct s_rpmb * req,unsigned short req_cnt,struct s_rpmb * rsp,unsigned short rsp_cnt)359*4853ad3eSJens Wiklander static int rpmb_route_write_req(struct mmc *mmc, struct s_rpmb *req,
360*4853ad3eSJens Wiklander unsigned short req_cnt, struct s_rpmb *rsp,
361*4853ad3eSJens Wiklander unsigned short rsp_cnt)
362*4853ad3eSJens Wiklander {
363*4853ad3eSJens Wiklander int ret;
364*4853ad3eSJens Wiklander
365*4853ad3eSJens Wiklander /*
366*4853ad3eSJens Wiklander * Send the write request.
367*4853ad3eSJens Wiklander */
368*4853ad3eSJens Wiklander ret = mmc_set_blockcount(mmc, req_cnt, true);
369*4853ad3eSJens Wiklander if (ret)
370*4853ad3eSJens Wiklander return ret;
371*4853ad3eSJens Wiklander
372*4853ad3eSJens Wiklander ret = send_write_mult_block(mmc, req, req_cnt);
373*4853ad3eSJens Wiklander if (ret)
374*4853ad3eSJens Wiklander return ret;
375*4853ad3eSJens Wiklander
376*4853ad3eSJens Wiklander /*
377*4853ad3eSJens Wiklander * Read the result of the request.
378*4853ad3eSJens Wiklander */
379*4853ad3eSJens Wiklander ret = mmc_set_blockcount(mmc, 1, false);
380*4853ad3eSJens Wiklander if (ret)
381*4853ad3eSJens Wiklander return ret;
382*4853ad3eSJens Wiklander
383*4853ad3eSJens Wiklander memset(rsp, 0, sizeof(*rsp));
384*4853ad3eSJens Wiklander rsp->request = cpu_to_be16(RPMB_REQ_STATUS);
385*4853ad3eSJens Wiklander ret = send_write_mult_block(mmc, rsp, 1);
386*4853ad3eSJens Wiklander if (ret)
387*4853ad3eSJens Wiklander return ret;
388*4853ad3eSJens Wiklander
389*4853ad3eSJens Wiklander ret = mmc_set_blockcount(mmc, 1, false);
390*4853ad3eSJens Wiklander if (ret)
391*4853ad3eSJens Wiklander return ret;
392*4853ad3eSJens Wiklander
393*4853ad3eSJens Wiklander return send_read_mult_block(mmc, rsp, 1);
394*4853ad3eSJens Wiklander }
395*4853ad3eSJens Wiklander
rpmb_route_read_req(struct mmc * mmc,struct s_rpmb * req,unsigned short req_cnt,struct s_rpmb * rsp,unsigned short rsp_cnt)396*4853ad3eSJens Wiklander static int rpmb_route_read_req(struct mmc *mmc, struct s_rpmb *req,
397*4853ad3eSJens Wiklander unsigned short req_cnt, struct s_rpmb *rsp,
398*4853ad3eSJens Wiklander unsigned short rsp_cnt)
399*4853ad3eSJens Wiklander {
400*4853ad3eSJens Wiklander int ret;
401*4853ad3eSJens Wiklander
402*4853ad3eSJens Wiklander /*
403*4853ad3eSJens Wiklander * Send the read request.
404*4853ad3eSJens Wiklander */
405*4853ad3eSJens Wiklander ret = mmc_set_blockcount(mmc, 1, false);
406*4853ad3eSJens Wiklander if (ret)
407*4853ad3eSJens Wiklander return ret;
408*4853ad3eSJens Wiklander
409*4853ad3eSJens Wiklander ret = send_write_mult_block(mmc, req, 1);
410*4853ad3eSJens Wiklander if (ret)
411*4853ad3eSJens Wiklander return ret;
412*4853ad3eSJens Wiklander
413*4853ad3eSJens Wiklander /*
414*4853ad3eSJens Wiklander * Read the result of the request.
415*4853ad3eSJens Wiklander */
416*4853ad3eSJens Wiklander
417*4853ad3eSJens Wiklander ret = mmc_set_blockcount(mmc, rsp_cnt, false);
418*4853ad3eSJens Wiklander if (ret)
419*4853ad3eSJens Wiklander return ret;
420*4853ad3eSJens Wiklander
421*4853ad3eSJens Wiklander return send_read_mult_block(mmc, rsp, rsp_cnt);
422*4853ad3eSJens Wiklander }
423*4853ad3eSJens Wiklander
rpmb_route_frames(struct mmc * mmc,struct s_rpmb * req,unsigned short req_cnt,struct s_rpmb * rsp,unsigned short rsp_cnt)424*4853ad3eSJens Wiklander static int rpmb_route_frames(struct mmc *mmc, struct s_rpmb *req,
425*4853ad3eSJens Wiklander unsigned short req_cnt, struct s_rpmb *rsp,
426*4853ad3eSJens Wiklander unsigned short rsp_cnt)
427*4853ad3eSJens Wiklander {
428*4853ad3eSJens Wiklander unsigned short n;
429*4853ad3eSJens Wiklander
430*4853ad3eSJens Wiklander /*
431*4853ad3eSJens Wiklander * If multiple request frames are provided, make sure that all are
432*4853ad3eSJens Wiklander * of the same type.
433*4853ad3eSJens Wiklander */
434*4853ad3eSJens Wiklander for (n = 1; n < req_cnt; n++)
435*4853ad3eSJens Wiklander if (req[n].request != req->request)
436*4853ad3eSJens Wiklander return -EINVAL;
437*4853ad3eSJens Wiklander
438*4853ad3eSJens Wiklander switch (be16_to_cpu(req->request)) {
439*4853ad3eSJens Wiklander case RPMB_REQ_KEY:
440*4853ad3eSJens Wiklander if (req_cnt != 1 || rsp_cnt != 1)
441*4853ad3eSJens Wiklander return -EINVAL;
442*4853ad3eSJens Wiklander return rpmb_route_write_req(mmc, req, req_cnt, rsp, rsp_cnt);
443*4853ad3eSJens Wiklander
444*4853ad3eSJens Wiklander case RPMB_REQ_WRITE_DATA:
445*4853ad3eSJens Wiklander if (!req_cnt || rsp_cnt != 1)
446*4853ad3eSJens Wiklander return -EINVAL;
447*4853ad3eSJens Wiklander return rpmb_route_write_req(mmc, req, req_cnt, rsp, rsp_cnt);
448*4853ad3eSJens Wiklander
449*4853ad3eSJens Wiklander case RPMB_REQ_WCOUNTER:
450*4853ad3eSJens Wiklander if (req_cnt != 1 || rsp_cnt != 1)
451*4853ad3eSJens Wiklander return -EINVAL;
452*4853ad3eSJens Wiklander return rpmb_route_read_req(mmc, req, req_cnt, rsp, rsp_cnt);
453*4853ad3eSJens Wiklander
454*4853ad3eSJens Wiklander case RPMB_REQ_READ_DATA:
455*4853ad3eSJens Wiklander if (req_cnt != 1 || !req_cnt)
456*4853ad3eSJens Wiklander return -EINVAL;
457*4853ad3eSJens Wiklander return rpmb_route_read_req(mmc, req, req_cnt, rsp, rsp_cnt);
458*4853ad3eSJens Wiklander
459*4853ad3eSJens Wiklander default:
460*4853ad3eSJens Wiklander debug("Unsupported message type: %d\n",
461*4853ad3eSJens Wiklander be16_to_cpu(req->request));
462*4853ad3eSJens Wiklander return -EINVAL;
463*4853ad3eSJens Wiklander }
464*4853ad3eSJens Wiklander }
465*4853ad3eSJens Wiklander
mmc_rpmb_route_frames(struct mmc * mmc,void * req,unsigned long reqlen,void * rsp,unsigned long rsplen)466*4853ad3eSJens Wiklander int mmc_rpmb_route_frames(struct mmc *mmc, void *req, unsigned long reqlen,
467*4853ad3eSJens Wiklander void *rsp, unsigned long rsplen)
468*4853ad3eSJens Wiklander {
469*4853ad3eSJens Wiklander /*
470*4853ad3eSJens Wiklander * Whoever crafted the data supplied to this function knows how to
471*4853ad3eSJens Wiklander * format the PRMB frames and which response is expected. If
472*4853ad3eSJens Wiklander * there's some unexpected mismatch it's more helpful to report an
473*4853ad3eSJens Wiklander * error immediately than trying to guess what was the intention
474*4853ad3eSJens Wiklander * and possibly just delay an eventual error which will be harder
475*4853ad3eSJens Wiklander * to track down.
476*4853ad3eSJens Wiklander */
477*4853ad3eSJens Wiklander
478*4853ad3eSJens Wiklander if (reqlen % sizeof(struct s_rpmb) || rsplen % sizeof(struct s_rpmb))
479*4853ad3eSJens Wiklander return -EINVAL;
480*4853ad3eSJens Wiklander
481*4853ad3eSJens Wiklander return rpmb_route_frames(mmc, req, reqlen / sizeof(struct s_rpmb),
482*4853ad3eSJens Wiklander rsp, rsplen / sizeof(struct s_rpmb));
483*4853ad3eSJens Wiklander }
484