All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jorge Ramirez-Ortiz <jorge.ramirez@oss.qualcomm.com>
To: jorge.ramirez@oss.qualcomm.com, trini@konsulko.com,
	jens.wiklander@linaro.org, ilias.apalodimas@linaro.org,
	neil.armstrong@linaro.org, bhupesh.linux@gmail.com,
	n-francis@ti.com, marek.vasut+renesas@mailbox.org,
	igor.belwon@mentallysanemainliners.org, shawn.lin@rock-chips.com,
	yoshihiro.shimoda.uh@renesas.com, alchark@gmail.com,
	tuyen.dang.xa@renesas.com, macpaul.lin@mediatek.com,
	padmarao.begari@amd.com, jstephan@baylibre.com, bb@ti.com,
	j-mcarthur@ti.com, venkyada@qti.qualcomm.com,
	hayashi.kunihiko@socionext.com
Cc: u-boot@lists.denx.de, sumit.garg@kernel.org
Subject: [PATCH v1 2/7] ufs: add RPMB transport over SCSI SECURITY PROTOCOL
Date: Mon, 20 Jul 2026 10:51:42 +0200	[thread overview]
Message-ID: <20260720085202.537019-3-jorge.ramirez@oss.qualcomm.com> (raw)
In-Reply-To: <20260720085202.537019-1-jorge.ramirez@oss.qualcomm.com>

Add a UFS RPMB transport that moves fully-formed JEDEC RPMB frames to and
from the RPMB Well-Known LUN using SCSI SECURITY PROTOCOL IN/OUT commands,
exposed through ufs_rpmb_route_frames() for the OP-TEE RPMB supplicant and
guarded by CONFIG_SUPPORT_UFS_RPMB.

Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez@oss.qualcomm.com>
---
 drivers/ufs/Kconfig      |  13 ++++
 drivers/ufs/Makefile     |   1 +
 drivers/ufs/ufs-rpmb.c   | 146 +++++++++++++++++++++++++++++++++++++++
 drivers/ufs/ufs-uclass.c |   6 ++
 drivers/ufs/ufs.h        |  13 ++++
 include/ufs.h            |   8 +++
 6 files changed, 187 insertions(+)
 create mode 100644 drivers/ufs/ufs-rpmb.c

diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig
index 49472933de3..d39fcda42dc 100644
--- a/drivers/ufs/Kconfig
+++ b/drivers/ufs/Kconfig
@@ -92,4 +92,17 @@ config UFS_TI_J721E
 	  This selects the glue layer driver for Cadence controller
 	  present on TI's J721E devices.
 
+config SUPPORT_UFS_RPMB
+	bool "Enable UFS RPMB (Replay Protected Memory Block) support"
+	depends on UFS && OPTEE && !SUPPORT_EMMC_RPMB
+	select BLAKE2
+	help
+	  Route OP-TEE RPMB requests to the UFS RPMB Well-Known LUN using
+	  SCSI SECURITY PROTOCOL IN/OUT commands. Required for OP-TEE secure
+	  storage (CFG_RPMB_FS) on UFS-based platforms that have no eMMC.
+	  BLAKE2 is used to derive the fixed-length RPMB CID that matches the
+	  Linux kernel UFS device_id ABI. The OP-TEE supplicant handles a
+	  single RPMB transport, so this is mutually exclusive with the eMMC
+	  RPMB supplicant (SUPPORT_EMMC_RPMB).
+
 endmenu
diff --git a/drivers/ufs/Makefile b/drivers/ufs/Makefile
index e7f3c1d30c4..d60440ca119 100644
--- a/drivers/ufs/Makefile
+++ b/drivers/ufs/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_UFS_RENESAS) += ufs-renesas.o
 obj-$(CONFIG_UFS_RENESAS_GEN5) += ufs-renesas-rcar-gen5.o
 obj-$(CONFIG_UFS_ROCKCHIP) += ufs-rockchip.o
 obj-$(CONFIG_UFS_TI_J721E) += ti-j721e-ufs.o
+obj-$(CONFIG_SUPPORT_UFS_RPMB) += ufs-rpmb.o
diff --git a/drivers/ufs/ufs-rpmb.c b/drivers/ufs/ufs-rpmb.c
new file mode 100644
index 00000000000..636ccb6e74f
--- /dev/null
+++ b/drivers/ufs/ufs-rpmb.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <dm.h>
+#include <log.h>
+#include <scsi.h>
+#include <ufs.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include "ufs.h"
+
+#define RPMB_REQ_KEY		1
+#define RPMB_REQ_WCOUNTER	2
+#define RPMB_REQ_WRITE_DATA	3
+#define RPMB_REQ_READ_DATA	4
+#define RPMB_REQ_STATUS		5
+
+#define RPMB_FRAME_REQ_OFFSET	510
+
+static u16 rpmb_frame_request(const void *frame)
+{
+	const u8 *p = frame;
+
+	return ((u16)p[RPMB_FRAME_REQ_OFFSET] << 8) |
+		p[RPMB_FRAME_REQ_OFFSET + 1];
+}
+
+static int ufs_rpmb_secprot(struct udevice *scsi_dev, unsigned int region,
+			    u8 opcode, void *buf, unsigned int nframes,
+			    enum dma_data_direction dir)
+{
+	struct scsi_cmd pccb;
+	u32 len = nframes * RPMB_FRAME_SIZE;
+	u16 spsp = (region << 8) | UFS_RPMB_SEC_PROTOCOL_ID;
+
+	memset(&pccb, 0, sizeof(pccb));
+	pccb.lun = UFS_UPIU_RPMB_WLUN;
+	pccb.cmd[0] = opcode;
+	pccb.cmd[1] = SEC_PROTOCOL_UFS;
+	pccb.cmd[2] = (spsp >> 8) & 0xff;
+	pccb.cmd[3] = spsp & 0xff;
+	pccb.cmd[4] = 0;
+	pccb.cmd[5] = 0;
+	pccb.cmd[6] = (len >> 24) & 0xff;
+	pccb.cmd[7] = (len >> 16) & 0xff;
+	pccb.cmd[8] = (len >> 8) & 0xff;
+	pccb.cmd[9] = len & 0xff;
+	pccb.cmd[10] = 0;
+	pccb.cmd[11] = 0;
+	pccb.cmdlen = 12;
+	pccb.pdata = buf;
+	pccb.datalen = len;
+	pccb.dma_dir = dir;
+
+	return scsi_exec(scsi_dev, &pccb);
+}
+
+static int ufs_rpmb_send(struct udevice *scsi_dev, unsigned int region,
+			 void *frames, unsigned int nframes)
+{
+	return ufs_rpmb_secprot(scsi_dev, region, SECURITY_PROTOCOL_OUT,
+				frames, nframes, DMA_TO_DEVICE);
+}
+
+static int ufs_rpmb_recv(struct udevice *scsi_dev, unsigned int region,
+			 void *frames, unsigned int nframes)
+{
+	return ufs_rpmb_secprot(scsi_dev, region, SECURITY_PROTOCOL_IN,
+				frames, nframes, DMA_FROM_DEVICE);
+}
+
+int ufs_rpmb_route_frames(struct udevice *scsi_dev, unsigned int region,
+			  void *req, unsigned long reqlen, void *rsp,
+			  unsigned long rsplen)
+{
+	unsigned int n_req = reqlen / RPMB_FRAME_SIZE;
+	unsigned int n_rsp = rsplen / RPMB_FRAME_SIZE;
+	u16 request;
+	int ret;
+
+	if (!scsi_dev || reqlen % RPMB_FRAME_SIZE ||
+	    rsplen % RPMB_FRAME_SIZE || !n_req)
+		return -EINVAL;
+
+	request = rpmb_frame_request(req);
+
+	switch (request) {
+	case RPMB_REQ_KEY:
+	case RPMB_REQ_WRITE_DATA: {
+		u8 status_frame[RPMB_FRAME_SIZE];
+
+		ret = ufs_rpmb_send(scsi_dev, region, req, n_req);
+		if (ret)
+			return ret;
+
+		memset(status_frame, 0, sizeof(status_frame));
+		status_frame[RPMB_FRAME_REQ_OFFSET] = RPMB_REQ_STATUS >> 8;
+		status_frame[RPMB_FRAME_REQ_OFFSET + 1] = RPMB_REQ_STATUS & 0xff;
+		ret = ufs_rpmb_send(scsi_dev, region, status_frame, 1);
+		if (ret)
+			return ret;
+
+		if (n_rsp < 1)
+			return -EINVAL;
+		return ufs_rpmb_recv(scsi_dev, region, rsp, 1);
+	}
+	case RPMB_REQ_WCOUNTER:
+	case RPMB_REQ_READ_DATA:
+		ret = ufs_rpmb_send(scsi_dev, region, req, 1);
+		if (ret)
+			return ret;
+		if (n_rsp < 1)
+			return -EINVAL;
+		return ufs_rpmb_recv(scsi_dev, region, rsp, n_rsp);
+	default:
+		debug("ufs-rpmb: unsupported request 0x%x\n", request);
+		return -EINVAL;
+	}
+}
+
+struct udevice *ufs_rpmb_get_scsi_dev(int dev_id)
+{
+	struct udevice *scsi_dev;
+	int ret;
+
+	ret = uclass_get_device(UCLASS_SCSI, dev_id, &scsi_dev);
+	if (ret) {
+		debug("ufs-rpmb: no SCSI device for dev_id %d: %d\n",
+		      dev_id, ret);
+		return NULL;
+	}
+	return scsi_dev;
+}
+
+int ufs_rpmb_read_geometry(struct udevice *scsi_dev, u8 *rpmb_rw_size)
+{
+	struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent);
+	u8 desc[QUERY_DESC_GEOMETRY_DEF_SIZE];
+	int ret;
+
+	ret = ufshcd_read_descriptor(hba, QUERY_DESC_IDN_GEOMETRY, 0,
+				     desc, sizeof(desc));
+	if (ret)
+		return ret;
+
+	*rpmb_rw_size = desc[GEOMETRY_DESC_RPMB_RW_SIZE];
+	return 0;
+}
diff --git a/drivers/ufs/ufs-uclass.c b/drivers/ufs/ufs-uclass.c
index 4d10e0b11fe..962b6093762 100644
--- a/drivers/ufs/ufs-uclass.c
+++ b/drivers/ufs/ufs-uclass.c
@@ -1712,6 +1712,12 @@ static inline int ufshcd_read_desc(struct ufs_hba *hba, enum desc_idn desc_id,
 	return ufshcd_read_desc_param(hba, desc_id, desc_index, 0, buf, size);
 }
 
+int ufshcd_read_descriptor(struct ufs_hba *hba, enum desc_idn desc_id,
+			   int desc_index, u8 *buf, u8 size)
+{
+	return ufshcd_read_desc_param(hba, desc_id, desc_index, 0, buf, size);
+}
+
 static int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size)
 {
 	return ufshcd_read_desc(hba, QUERY_DESC_IDN_DEVICE, 0, buf, size);
diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h
index 0f6c93fbce7..e66d2c5f533 100644
--- a/drivers/ufs/ufs.h
+++ b/drivers/ufs/ufs.h
@@ -10,6 +10,16 @@
 struct udevice;
 
 #define UFS_CDB_SIZE	16
+
+#define UFS_UPIU_RPMB_WLUN		0xC4
+#define RPMB_FRAME_SIZE			512
+
+#define SECURITY_PROTOCOL_IN		0xA2
+#define SECURITY_PROTOCOL_OUT		0xB5
+#define SEC_PROTOCOL_UFS		0xEC
+#define UFS_RPMB_SEC_PROTOCOL_ID	0x01
+
+#define GEOMETRY_DESC_RPMB_RW_SIZE	0x17
 #define UPIU_TRANSACTION_UIC_CMD 0x1F
 #define UIC_CMD_SIZE (sizeof(u32) * 4)
 #define RESPONSE_UPIU_SENSE_DATA_LENGTH	18
@@ -809,4 +819,7 @@ static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg)
 
 int ufshcd_probe(struct udevice *dev, struct ufs_hba_ops *hba_ops);
 
+int ufshcd_read_descriptor(struct ufs_hba *hba, enum desc_idn desc_id,
+			   int desc_index, u8 *buf, u8 size);
+
 #endif
diff --git a/include/ufs.h b/include/ufs.h
index f6e27d90e43..90c6aebcec1 100644
--- a/include/ufs.h
+++ b/include/ufs.h
@@ -20,4 +20,12 @@ int ufs_probe(void);
  */
 int ufs_probe_dev(int index);
 
+struct udevice *ufs_rpmb_get_scsi_dev(int dev_id);
+
+int ufs_rpmb_route_frames(struct udevice *scsi_dev, unsigned int region,
+			  void *req, unsigned long reqlen, void *rsp,
+			  unsigned long rsplen);
+
+int ufs_rpmb_read_geometry(struct udevice *scsi_dev, u8 *rpmb_rw_size);
+
 #endif
-- 
2.54.0


  parent reply	other threads:[~2026-07-20  8:52 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-20  8:51 [PATCH v1 0/7] ufs: rpmb: route OP-TEE RPMB secure storage over UFS Jorge Ramirez-Ortiz
2026-07-20  8:51 ` [PATCH v1 1/7] ufs: decode string descriptors as UTF-16 big-endian Jorge Ramirez-Ortiz
2026-07-20  8:51 ` Jorge Ramirez-Ortiz [this message]
2026-07-20  8:51 ` [PATCH v1 3/7] ufs: rpmb: derive the per-region RPMB CID and size for OP-TEE Jorge Ramirez-Ortiz
2026-07-20  8:51 ` [PATCH v1 4/7] ufs: rpmb: retry SECURITY PROTOCOL on power-on UNIT ATTENTION Jorge Ramirez-Ortiz
2026-07-20  8:51 ` [PATCH v1 5/7] ufs: rpmb: bounce unaligned frames through a DMA-aligned buffer Jorge Ramirez-Ortiz
2026-07-20  8:51 ` [PATCH v1 6/7] optee: rename rpmb.c to rpmb_legacy.c Jorge Ramirez-Ortiz
2026-07-20  8:51 ` [PATCH v1 7/7] optee: implement the RPMB subsystem interface for UFS Jorge Ramirez-Ortiz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260720085202.537019-3-jorge.ramirez@oss.qualcomm.com \
    --to=jorge.ramirez@oss.qualcomm.com \
    --cc=alchark@gmail.com \
    --cc=bb@ti.com \
    --cc=bhupesh.linux@gmail.com \
    --cc=hayashi.kunihiko@socionext.com \
    --cc=igor.belwon@mentallysanemainliners.org \
    --cc=ilias.apalodimas@linaro.org \
    --cc=j-mcarthur@ti.com \
    --cc=jens.wiklander@linaro.org \
    --cc=jstephan@baylibre.com \
    --cc=macpaul.lin@mediatek.com \
    --cc=marek.vasut+renesas@mailbox.org \
    --cc=n-francis@ti.com \
    --cc=neil.armstrong@linaro.org \
    --cc=padmarao.begari@amd.com \
    --cc=shawn.lin@rock-chips.com \
    --cc=sumit.garg@kernel.org \
    --cc=trini@konsulko.com \
    --cc=tuyen.dang.xa@renesas.com \
    --cc=u-boot@lists.denx.de \
    --cc=venkyada@qti.qualcomm.com \
    --cc=yoshihiro.shimoda.uh@renesas.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.