All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e
@ 2019-09-09  8:19 Faiz Abbas
  2019-09-09  8:19 ` [U-Boot] [PATCH 01/10] scsi: Simplify scsi_read()/_write() Faiz Abbas
                   ` (10 more replies)
  0 siblings, 11 replies; 20+ messages in thread
From: Faiz Abbas @ 2019-09-09  8:19 UTC (permalink / raw)
  To: u-boot

The following patches add support for the Universal Flash Storage (UFS)
subsystem and its implementation on TI's J721e platform.

The UFS Application Layer (UAP) uses SCSI SAM-4 command set for
communication with the device. Therefore, the first 4 patches prepare
the scsi layer for compatibility with UFS. Patch 9 also adds support for
initializing and configuring the device from the U-boot command line.

The UFS Transport Protocol Layer (UTP) and UFS Interconnect Layer (UIC)
are implemented with patch 5. This series only adds support for
detect and read/write operations to the LUNs present in the remote
device. Task Management operations and configuration of LUNs will be
added in a future series.

Patches 6 through 10 add platform driver, device tree and config support
for TI's J721E devices.

Log: https://pastebin.ubuntu.com/p/fTPZsxNjZM/

Tested on top of Lokesh's tree:
https://github.com/lokeshvutla/u-boot
Branch: j721e-full-boot

References:

[1] JESD220D UFS 3.0:
	https://www.jedec.org/standards-documents/docs/jesd220c
[2] JESD223D UFS Host Controller Interface (UFSHCI) version 3.0:
	https://www.jedec.org/standards-documents/docs/jesd223c

Faiz Abbas (10):
  scsi: Simplify scsi_read()/_write()
  scsi: Add max_bytes to scsi_platdata
  scsi: Retry inquiry 3 times to overcome Unit Attention condition
  scsi: Add dma direction member to command structure
  ufs: Add Initial Support for UFS subsystem
  ufs: Add Support for Cadence platform UFS driver
  ufs: Add glue layer driver for TI J721E devices
  arm: dts: k3-j721e-main: Add UFS nodes
  cmd: Add Support for UFS commands
  configs: j721e_evm_a72: Enable configs for UFS

 arch/arm/dts/k3-j721e-main.dtsi |   25 +
 cmd/Kconfig                     |    7 +
 cmd/Makefile                    |    2 +-
 cmd/ufs.c                       |   28 +
 configs/j721e_evm_a72_defconfig |    7 +-
 drivers/Kconfig                 |    2 +
 drivers/Makefile                |    1 +
 drivers/scsi/scsi.c             |   83 +-
 drivers/ufs/Kconfig             |   23 +
 drivers/ufs/Makefile            |    8 +
 drivers/ufs/cdns-platform.c     |  122 ++
 drivers/ufs/ti-j721e-ufs.c      |   75 ++
 drivers/ufs/ufs-uclass.c        |   16 +
 drivers/ufs/ufs.c               | 1973 +++++++++++++++++++++++++++++++
 drivers/ufs/ufs.h               |  918 ++++++++++++++
 drivers/ufs/unipro.h            |  270 +++++
 include/dm/uclass-id.h          |    1 +
 include/scsi.h                  |    4 +
 include/ufs.h                   |    7 +
 19 files changed, 3526 insertions(+), 46 deletions(-)
 create mode 100644 cmd/ufs.c
 create mode 100644 drivers/ufs/Kconfig
 create mode 100644 drivers/ufs/Makefile
 create mode 100644 drivers/ufs/cdns-platform.c
 create mode 100644 drivers/ufs/ti-j721e-ufs.c
 create mode 100644 drivers/ufs/ufs-uclass.c
 create mode 100644 drivers/ufs/ufs.c
 create mode 100644 drivers/ufs/ufs.h
 create mode 100644 drivers/ufs/unipro.h
 create mode 100644 include/ufs.h

-- 
2.19.2

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 01/10] scsi: Simplify scsi_read()/_write()
  2019-09-09  8:19 [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e Faiz Abbas
@ 2019-09-09  8:19 ` Faiz Abbas
  2019-09-09  8:19 ` [U-Boot] [PATCH 02/10] scsi: Add max_bytes to scsi_platdata Faiz Abbas
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Faiz Abbas @ 2019-09-09  8:19 UTC (permalink / raw)
  To: u-boot

With no non-DM driver using scsi_read()/_write() APIs, remove
the legacy implementations.

Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
---
 drivers/scsi/scsi.c | 22 ----------------------
 1 file changed, 22 deletions(-)

diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 75900d8228..82a0bf7cc6 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -140,20 +140,11 @@ static void scsi_setup_inquiry(struct scsi_cmd *pccb)
 	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
 }
 
-#ifdef CONFIG_BLK
 static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
 		       void *buffer)
-#else
-static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr,
-		       lbaint_t blkcnt, void *buffer)
-#endif
 {
-#ifdef CONFIG_BLK
 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
 	struct udevice *bdev = dev->parent;
-#else
-	struct udevice *bdev = NULL;
-#endif
 	lbaint_t start, blks;
 	uintptr_t buf_addr;
 	unsigned short smallblks = 0;
@@ -216,20 +207,11 @@ static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr,
 /* Almost the maximum amount of the scsi_ext command.. */
 #define SCSI_MAX_WRITE_BLK 0xFFFF
 
-#ifdef CONFIG_BLK
 static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
 			const void *buffer)
-#else
-static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr,
-			lbaint_t blkcnt, const void *buffer)
-#endif
 {
-#ifdef CONFIG_BLK
 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
 	struct udevice *bdev = dev->parent;
-#else
-	struct udevice *bdev = NULL;
-#endif
 	lbaint_t start, blks;
 	uintptr_t buf_addr;
 	unsigned short smallblks;
@@ -449,10 +431,6 @@ static void scsi_init_dev_desc_priv(struct blk_desc *dev_desc)
 	dev_desc->product[0] = 0;
 	dev_desc->revision[0] = 0;
 	dev_desc->removable = false;
-#if !CONFIG_IS_ENABLED(BLK)
-	dev_desc->block_read = scsi_read;
-	dev_desc->block_write = scsi_write;
-#endif
 }
 
 #if !defined(CONFIG_DM_SCSI)
-- 
2.19.2

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 02/10] scsi: Add max_bytes to scsi_platdata
  2019-09-09  8:19 [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e Faiz Abbas
  2019-09-09  8:19 ` [U-Boot] [PATCH 01/10] scsi: Simplify scsi_read()/_write() Faiz Abbas
@ 2019-09-09  8:19 ` Faiz Abbas
  2019-09-10  3:46   ` Vignesh Raghavendra
  2019-09-09  8:19 ` [U-Boot] [PATCH 03/10] scsi: Retry inquiry 3 times to overcome Unit Attention condition Faiz Abbas
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: Faiz Abbas @ 2019-09-09  8:19 UTC (permalink / raw)
  To: u-boot

Add max_platdata to scsi_platdata to enable the host driver to limit the
number of bytes that can be read/written per request.

Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
---
 drivers/scsi/scsi.c | 45 ++++++++++++++++++++++++++-------------------
 include/scsi.h      |  1 +
 2 files changed, 27 insertions(+), 19 deletions(-)

diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 82a0bf7cc6..fd1b4b776d 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -44,7 +44,7 @@ static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE];
 #endif
 
 /* almost the maximum amount of the scsi_ext command.. */
-#define SCSI_MAX_READ_BLK 0xFFFF
+#define SCSI_MAX_BLK 0xFFFF
 #define SCSI_LBA48_READ	0xFFFFFFF
 
 static void scsi_print_error(struct scsi_cmd *pccb)
@@ -145,7 +145,8 @@ static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
 {
 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
 	struct udevice *bdev = dev->parent;
-	lbaint_t start, blks;
+	struct scsi_platdata *uc_plat = dev_get_uclass_platdata(bdev);
+	lbaint_t start, blks, max_blks;
 	uintptr_t buf_addr;
 	unsigned short smallblks = 0;
 	struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;
@@ -156,6 +157,11 @@ static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
 	buf_addr = (unsigned long)buffer;
 	start = blknr;
 	blks = blkcnt;
+	if (uc_plat->max_bytes)
+		max_blks = uc_plat->max_bytes / block_dev->blksz;
+	else
+		max_blks = SCSI_MAX_BLK;
+
 	debug("\nscsi_read: dev %d startblk " LBAF
 	      ", blccnt " LBAF " buffer %lx\n",
 	      block_dev->devnum, start, blks, (unsigned long)buffer);
@@ -164,20 +170,19 @@ static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
 #ifdef CONFIG_SYS_64BIT_LBA
 		if (start > SCSI_LBA48_READ) {
 			unsigned long blocks;
-			blocks = min_t(lbaint_t, blks, SCSI_MAX_READ_BLK);
+			blocks = min_t(lbaint_t, blks, max_blks);
 			pccb->datalen = block_dev->blksz * blocks;
 			scsi_setup_read16(pccb, start, blocks);
 			start += blocks;
 			blks -= blocks;
 		} else
 #endif
-		if (blks > SCSI_MAX_READ_BLK) {
-			pccb->datalen = block_dev->blksz *
-				SCSI_MAX_READ_BLK;
-			smallblks = SCSI_MAX_READ_BLK;
+		if (blks > max_blks) {
+			pccb->datalen = block_dev->blksz * max_blks;
+			smallblks = max_blks;
 			scsi_setup_read_ext(pccb, start, smallblks);
-			start += SCSI_MAX_READ_BLK;
-			blks -= SCSI_MAX_READ_BLK;
+			start += max_blks;
+			blks -= max_blks;
 		} else {
 			pccb->datalen = block_dev->blksz * blks;
 			smallblks = (unsigned short)blks;
@@ -204,15 +209,13 @@ static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
  * scsi_write
  */
 
-/* Almost the maximum amount of the scsi_ext command.. */
-#define SCSI_MAX_WRITE_BLK 0xFFFF
-
 static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
 			const void *buffer)
 {
 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
 	struct udevice *bdev = dev->parent;
-	lbaint_t start, blks;
+	struct scsi_platdata *uc_plat = dev_get_uclass_priv(bdev);
+	lbaint_t start, blks, max_blks;
 	uintptr_t buf_addr;
 	unsigned short smallblks;
 	struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;
@@ -223,17 +226,21 @@ static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
 	buf_addr = (unsigned long)buffer;
 	start = blknr;
 	blks = blkcnt;
+	if (uc_plat->max_bytes)
+		max_blks = uc_plat->max_bytes / block_dev->blksz;
+	else
+		max_blks = SCSI_MAX_BLK;
+
 	debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
 	      __func__, block_dev->devnum, start, blks, (unsigned long)buffer);
 	do {
 		pccb->pdata = (unsigned char *)buf_addr;
-		if (blks > SCSI_MAX_WRITE_BLK) {
-			pccb->datalen = (block_dev->blksz *
-					 SCSI_MAX_WRITE_BLK);
-			smallblks = SCSI_MAX_WRITE_BLK;
+		if (blks > SCSI_MAX_BLK) {
+			pccb->datalen = block_dev->blksz * max_blks;
+			smallblks = max_blks;
 			scsi_setup_write_ext(pccb, start, smallblks);
-			start += SCSI_MAX_WRITE_BLK;
-			blks -= SCSI_MAX_WRITE_BLK;
+			start += max_blks;
+			blks -= max_blks;
 		} else {
 			pccb->datalen = block_dev->blksz * blks;
 			smallblks = (unsigned short)blks;
diff --git a/include/scsi.h b/include/scsi.h
index 81ab43c842..076bdbc6a0 100644
--- a/include/scsi.h
+++ b/include/scsi.h
@@ -168,6 +168,7 @@ struct scsi_platdata {
 	unsigned long base;
 	unsigned long max_lun;
 	unsigned long max_id;
+	unsigned long max_bytes;
 };
 
 /* Operations for SCSI */
-- 
2.19.2

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 03/10] scsi: Retry inquiry 3 times to overcome Unit Attention condition
  2019-09-09  8:19 [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e Faiz Abbas
  2019-09-09  8:19 ` [U-Boot] [PATCH 01/10] scsi: Simplify scsi_read()/_write() Faiz Abbas
  2019-09-09  8:19 ` [U-Boot] [PATCH 02/10] scsi: Add max_bytes to scsi_platdata Faiz Abbas
@ 2019-09-09  8:19 ` Faiz Abbas
  2019-09-09  8:19 ` [U-Boot] [PATCH 04/10] scsi: Add dma direction member to command structure Faiz Abbas
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Faiz Abbas @ 2019-09-09  8:19 UTC (permalink / raw)
  To: u-boot

The UFS SCSI device LUNs are observed to return failure the first time a
unit ready inquiry is sent and pass on the second try. Send this
inquiry 3 times to make sure device is ready.

Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
---
 drivers/scsi/scsi.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index fd1b4b776d..7b7d388557 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -478,6 +478,7 @@ static int scsi_detect_dev(struct udevice *dev, int target, int lun,
 	lbaint_t capacity;
 	unsigned long blksz;
 	struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;
+	int count, err;
 
 	pccb->target = target;
 	pccb->lun = lun;
@@ -513,9 +514,14 @@ static int scsi_detect_dev(struct udevice *dev, int target, int lun,
 	dev_desc->target = pccb->target;
 	dev_desc->lun = pccb->lun;
 
-	pccb->datalen = 0;
-	scsi_setup_test_unit_ready(pccb);
-	if (scsi_exec(dev, pccb)) {
+	for (count = 0; count < 3; count++) {
+		pccb->datalen = 0;
+		scsi_setup_test_unit_ready(pccb);
+		err = scsi_exec(dev, pccb);
+		if (!err)
+			break;
+	}
+	if (err) {
 		if (dev_desc->removable) {
 			dev_desc->type = perq;
 			goto removable;
-- 
2.19.2

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 04/10] scsi: Add dma direction member to command structure
  2019-09-09  8:19 [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e Faiz Abbas
                   ` (2 preceding siblings ...)
  2019-09-09  8:19 ` [U-Boot] [PATCH 03/10] scsi: Retry inquiry 3 times to overcome Unit Attention condition Faiz Abbas
@ 2019-09-09  8:19 ` Faiz Abbas
  2019-09-09  8:19 ` [U-Boot] [PATCH 05/10] ufs: Add Initial Support for UFS subsystem Faiz Abbas
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Faiz Abbas @ 2019-09-09  8:19 UTC (permalink / raw)
  To: u-boot

Some SCSI devices like UFS use DMA for executing scsi commands and hence
need to know the direction of transfer of the dma. Add a dma_dir element
to the command structure to facilitate this.

Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
---
 drivers/scsi/scsi.c | 4 ++++
 include/scsi.h      | 3 +++
 2 files changed, 7 insertions(+)

diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 7b7d388557..719e0fbfe6 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -167,6 +167,7 @@ static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
 	      block_dev->devnum, start, blks, (unsigned long)buffer);
 	do {
 		pccb->pdata = (unsigned char *)buf_addr;
+		pccb->dma_dir = DMA_FROM_DEVICE;
 #ifdef CONFIG_SYS_64BIT_LBA
 		if (start > SCSI_LBA48_READ) {
 			unsigned long blocks;
@@ -235,6 +236,7 @@ static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
 	      __func__, block_dev->devnum, start, blks, (unsigned long)buffer);
 	do {
 		pccb->pdata = (unsigned char *)buf_addr;
+		pccb->dma_dir = DMA_TO_DEVICE;
 		if (blks > SCSI_MAX_BLK) {
 			pccb->datalen = block_dev->blksz * max_blks;
 			smallblks = max_blks;
@@ -382,6 +384,7 @@ static int scsi_read_capacity(struct udevice *dev, struct scsi_cmd *pccb,
 	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
 
 	pccb->datalen = 16;
+	pccb->dma_dir = DMA_FROM_DEVICE;
 	if (scsi_exec(dev, pccb))
 		return 1;
 
@@ -484,6 +487,7 @@ static int scsi_detect_dev(struct udevice *dev, int target, int lun,
 	pccb->lun = lun;
 	pccb->pdata = (unsigned char *)&tempbuff;
 	pccb->datalen = 512;
+	pccb->dma_dir = DMA_FROM_DEVICE;
 	scsi_setup_inquiry(pccb);
 	if (scsi_exec(dev, pccb)) {
 		if (pccb->contr_stat == SCSI_SEL_TIME_OUT) {
diff --git a/include/scsi.h b/include/scsi.h
index 076bdbc6a0..7bb2d3ac0f 100644
--- a/include/scsi.h
+++ b/include/scsi.h
@@ -6,6 +6,8 @@
  #ifndef _SCSI_H
  #define _SCSI_H
 
+#include <linux/dma-direction.h>
+
 struct scsi_cmd {
 	unsigned char		cmd[16];					/* command				   */
 	/* for request sense */
@@ -26,6 +28,7 @@ struct scsi_cmd {
 	unsigned long		trans_bytes;			/* tranfered bytes		*/
 
 	unsigned int		priv;
+	enum dma_data_direction	dma_dir;
 };
 
 /*-----------------------------------------------------------
-- 
2.19.2

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 05/10] ufs: Add Initial Support for UFS subsystem
  2019-09-09  8:19 [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e Faiz Abbas
                   ` (3 preceding siblings ...)
  2019-09-09  8:19 ` [U-Boot] [PATCH 04/10] scsi: Add dma direction member to command structure Faiz Abbas
@ 2019-09-09  8:19 ` Faiz Abbas
  2019-09-10  3:48   ` Vignesh Raghavendra
  2019-09-09  8:19 ` [U-Boot] [PATCH 06/10] ufs: Add Support for Cadence platform UFS driver Faiz Abbas
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: Faiz Abbas @ 2019-09-09  8:19 UTC (permalink / raw)
  To: u-boot

Add Support for UFS Host Controller Interface (UFSHCI) for communicating
with Universal Flash Storage (UFS) devices. The steps to initialize the
host controller interface are the following:

- Initiate the Host Controller Initialization process by writing to the
Host controller enable register.
- Configure the Host Controller base address registers by allocating a
host memory space and related data structures.
- Unipro link startup procedure
- Check for connected device
- Configure UFS host controller to process requests

Also register this host controller as a SCSI host controller.

Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
---
 MAINTAINERS              |    5 +
 drivers/Kconfig          |    2 +
 drivers/Makefile         |    1 +
 drivers/ufs/Kconfig      |    9 +
 drivers/ufs/Makefile     |    6 +
 drivers/ufs/ufs-uclass.c |   16 +
 drivers/ufs/ufs.c        | 1973 ++++++++++++++++++++++++++++++++++++++
 drivers/ufs/ufs.h        |  918 ++++++++++++++++++
 drivers/ufs/unipro.h     |  270 ++++++
 include/dm/uclass-id.h   |    1 +
 include/ufs.h            |    7 +
 11 files changed, 3208 insertions(+)
 create mode 100644 drivers/ufs/Kconfig
 create mode 100644 drivers/ufs/Makefile
 create mode 100644 drivers/ufs/ufs-uclass.c
 create mode 100644 drivers/ufs/ufs.c
 create mode 100644 drivers/ufs/ufs.h
 create mode 100644 drivers/ufs/unipro.h
 create mode 100644 include/ufs.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 36625795a4..ed3a4c352c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -772,6 +772,11 @@ S:	Maintained
 T:	git git://git.denx.de/u-boot-ubi.git
 F:	drivers/mtd/ubi/
 
+UFS
+M:	Faiz Abbas <faiz_abbas@ti.com>
+S:	Maintained
+F:	drivers/ufs/
+
 USB
 M:	Marek Vasut <marex@denx.de>
 S:	Maintained
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 96ff4f566a..61bbe88d6c 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -118,6 +118,8 @@ source "drivers/tpm/Kconfig"
 
 source "drivers/usb/Kconfig"
 
+source "drivers/ufs/Kconfig"
+
 source "drivers/video/Kconfig"
 
 source "drivers/virtio/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 6635dabd2c..2794bef18a 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -111,6 +111,7 @@ obj-y += soc/
 obj-y += thermal/
 obj-$(CONFIG_TEE) += tee/
 obj-y += axi/
+obj-y += ufs/
 obj-$(CONFIG_W1) += w1/
 obj-$(CONFIG_W1_EEPROM) += w1-eeprom/
 
diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig
new file mode 100644
index 0000000000..538aad8cd9
--- /dev/null
+++ b/drivers/ufs/Kconfig
@@ -0,0 +1,9 @@
+menu "UFS Host Controller Support"
+
+config UFS
+	bool "Support UFS controllers"
+	select DM_SCSI
+	help
+	  This selects support for Universal Flash Subsystem (UFS).
+	  Say Y here if you want UFS Support.
+endmenu
diff --git a/drivers/ufs/Makefile b/drivers/ufs/Makefile
new file mode 100644
index 0000000000..b8df759f66
--- /dev/null
+++ b/drivers/ufs/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
+#
+
+obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o
diff --git a/drivers/ufs/ufs-uclass.c b/drivers/ufs/ufs-uclass.c
new file mode 100644
index 0000000000..920bfa64e1
--- /dev/null
+++ b/drivers/ufs/ufs-uclass.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * ufs-uclass.c - Universal Flash Subsystem (UFS) Uclass driver
+ *
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
+ */
+
+#include <common.h>
+#include "ufs.h"
+#include <dm.h>
+
+UCLASS_DRIVER(ufs) = {
+	.id	= UCLASS_UFS,
+	.name	= "ufs",
+	.per_device_auto_alloc_size = sizeof(struct ufs_hba),
+};
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
new file mode 100644
index 0000000000..88c3e15d78
--- /dev/null
+++ b/drivers/ufs/ufs.c
@@ -0,0 +1,1973 @@
+// SPDX-License-Identifier: GPL-2.0+
+/**
+ * ufs.c - Universal Flash Subsystem (UFS) driver
+ *
+ * Taken from Linux Kernel v5.2 (drivers/scsi/ufs/ufshcd.c) and ported
+ * to u-boot.
+ *
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
+ */
+
+#include <charset.h>
+#include <common.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include <malloc.h>
+#include <hexdump.h>
+#include <scsi.h>
+
+#include <asm/dma-mapping.h>
+
+#include "ufs.h"
+
+#define UFSHCD_ENABLE_INTRS	(UTP_TRANSFER_REQ_COMPL |\
+				 UTP_TASK_REQ_COMPL |\
+				 UFSHCD_ERROR_MASK)
+/* maximum number of link-startup retries */
+#define DME_LINKSTARTUP_RETRIES 3
+
+/* maximum number of retries for a general UIC command  */
+#define UFS_UIC_COMMAND_RETRIES 3
+
+/* Query request retries */
+#define QUERY_REQ_RETRIES 3
+/* Query request timeout */
+#define QUERY_REQ_TIMEOUT 1500 /* 1.5 seconds */
+
+/* maximum timeout in ms for a general UIC command */
+#define UFS_UIC_CMD_TIMEOUT	1000
+/* NOP OUT retries waiting for NOP IN response */
+#define NOP_OUT_RETRIES    10
+/* Timeout after 30 msecs if NOP OUT hangs without response */
+#define NOP_OUT_TIMEOUT    30 /* msecs */
+
+/* Only use one Task Tag for all requests */
+#define TASK_TAG	0
+
+/* Expose the flag value from utp_upiu_query.value */
+#define MASK_QUERY_UPIU_FLAG_LOC 0xFF
+
+#define MAX_PRDT_ENTRY	262144
+
+/* maximum bytes per request */
+#define UFS_MAX_BYTES	(128 * 256 * 1024)
+
+static inline bool ufshcd_is_hba_active(struct ufs_hba *hba);
+static inline void ufshcd_hba_stop(struct ufs_hba *hba);
+static int ufshcd_hba_enable(struct ufs_hba *hba);
+
+/*
+ * ufshcd_wait_for_register - wait for register value to change
+ */
+static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
+				    u32 val, unsigned long timeout_ms)
+{
+	int err = 0;
+	unsigned long start = get_timer(0);
+
+	/* ignore bits that we don't intend to wait on */
+	val = val & mask;
+
+	while ((ufshcd_readl(hba, reg) & mask) != val) {
+		if (get_timer(start) > timeout_ms) {
+			if ((ufshcd_readl(hba, reg) & mask) != val)
+				err = -ETIMEDOUT;
+			break;
+		}
+	}
+
+	return err;
+}
+
+/**
+ * ufshcd_init_pwr_info - setting the POR (power on reset)
+ * values in hba power info
+ */
+static void ufshcd_init_pwr_info(struct ufs_hba *hba)
+{
+	hba->pwr_info.gear_rx = UFS_PWM_G1;
+	hba->pwr_info.gear_tx = UFS_PWM_G1;
+	hba->pwr_info.lane_rx = 1;
+	hba->pwr_info.lane_tx = 1;
+	hba->pwr_info.pwr_rx = SLOWAUTO_MODE;
+	hba->pwr_info.pwr_tx = SLOWAUTO_MODE;
+	hba->pwr_info.hs_rate = 0;
+}
+
+/**
+ * ufshcd_print_pwr_info - print power params as saved in hba
+ * power info
+ */
+static void ufshcd_print_pwr_info(struct ufs_hba *hba)
+{
+	static const char * const names[] = {
+		"INVALID MODE",
+		"FAST MODE",
+		"SLOW_MODE",
+		"INVALID MODE",
+		"FASTAUTO_MODE",
+		"SLOWAUTO_MODE",
+		"INVALID MODE",
+	};
+
+	dev_err(hba->dev, "%s:[RX, TX]: gear=[%d, %d], lane[%d, %d], pwr[%s, %s], rate = %d\n",
+		__func__,
+		hba->pwr_info.gear_rx, hba->pwr_info.gear_tx,
+		hba->pwr_info.lane_rx, hba->pwr_info.lane_tx,
+		names[hba->pwr_info.pwr_rx],
+		names[hba->pwr_info.pwr_tx],
+		hba->pwr_info.hs_rate);
+}
+
+/**
+ * ufshcd_ready_for_uic_cmd - Check if controller is ready
+ *                            to accept UIC commands
+ */
+static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba)
+{
+	if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY)
+		return true;
+	else
+		return false;
+}
+
+/**
+ * ufshcd_get_uic_cmd_result - Get the UIC command result
+ */
+static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
+{
+	return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) &
+	       MASK_UIC_COMMAND_RESULT;
+}
+
+/**
+ * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC command
+ */
+static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba)
+{
+	return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3);
+}
+
+/**
+ * ufshcd_is_device_present - Check if any device connected to
+ *			      the host controller
+ */
+static inline bool ufshcd_is_device_present(struct ufs_hba *hba)
+{
+	return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
+						DEVICE_PRESENT) ? true : false;
+}
+
+/**
+ * ufshcd_send_uic_cmd - UFS Interconnect layer command API
+ *
+ */
+static int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+	unsigned long start = 0;
+	u32 intr_status;
+	u32 enabled_intr_status;
+
+	if (!ufshcd_ready_for_uic_cmd(hba)) {
+		dev_err(hba->dev,
+			"Controller not ready to accept UIC commands\n");
+		return -EIO;
+	}
+
+	debug("sending uic command:%d\n", uic_cmd->command);
+
+	/* Write Args */
+	ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1);
+	ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2);
+	ufshcd_writel(hba, uic_cmd->argument3, REG_UIC_COMMAND_ARG_3);
+
+	/* Write UIC Cmd */
+	ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK,
+		      REG_UIC_COMMAND);
+
+	start = get_timer(0);
+	do {
+		intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
+		enabled_intr_status = intr_status & hba->intr_mask;
+		ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+
+		if (get_timer(start) > UFS_UIC_CMD_TIMEOUT) {
+			dev_err(hba->dev,
+				"Timedout waiting for UIC response\n");
+
+			return -ETIMEDOUT;
+		}
+
+		if (enabled_intr_status & UFSHCD_ERROR_MASK) {
+			dev_err(hba->dev, "Error in status:%08x\n",
+				enabled_intr_status);
+
+			return -1;
+		}
+	} while (!(enabled_intr_status & UFSHCD_UIC_MASK));
+
+	uic_cmd->argument2 = ufshcd_get_uic_cmd_result(hba);
+	uic_cmd->argument3 = ufshcd_get_dme_attr_val(hba);
+
+	debug("Sent successfully\n");
+
+	return 0;
+}
+
+/**
+ * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET
+ *
+ */
+int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, u8 attr_set,
+			u32 mib_val, u8 peer)
+{
+	struct uic_command uic_cmd = {0};
+	static const char *const action[] = {
+		"dme-set",
+		"dme-peer-set"
+	};
+	const char *set = action[!!peer];
+	int ret;
+	int retries = UFS_UIC_COMMAND_RETRIES;
+
+	uic_cmd.command = peer ?
+		UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET;
+	uic_cmd.argument1 = attr_sel;
+	uic_cmd.argument2 = UIC_ARG_ATTR_TYPE(attr_set);
+	uic_cmd.argument3 = mib_val;
+
+	do {
+		/* for peer attributes we retry upon failure */
+		ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+		if (ret)
+			dev_dbg(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n",
+				set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret);
+	} while (ret && peer && --retries);
+
+	if (ret)
+		dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x failed %d retries\n",
+			set, UIC_GET_ATTR_ID(attr_sel), mib_val,
+			UFS_UIC_COMMAND_RETRIES - retries);
+
+	return ret;
+}
+
+/**
+ * ufshcd_dme_get_attr - UIC command for DME_GET, DME_PEER_GET
+ *
+ */
+int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
+			u32 *mib_val, u8 peer)
+{
+	struct uic_command uic_cmd = {0};
+	static const char *const action[] = {
+		"dme-get",
+		"dme-peer-get"
+	};
+	const char *get = action[!!peer];
+	int ret;
+	int retries = UFS_UIC_COMMAND_RETRIES;
+
+	uic_cmd.command = peer ?
+		UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET;
+	uic_cmd.argument1 = attr_sel;
+
+	do {
+		/* for peer attributes we retry upon failure */
+		ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+		if (ret)
+			dev_dbg(hba->dev, "%s: attr-id 0x%x error code %d\n",
+				get, UIC_GET_ATTR_ID(attr_sel), ret);
+	} while (ret && peer && --retries);
+
+	if (ret)
+		dev_err(hba->dev, "%s: attr-id 0x%x failed %d retries\n",
+			get, UIC_GET_ATTR_ID(attr_sel),
+			UFS_UIC_COMMAND_RETRIES - retries);
+
+	if (mib_val && !ret)
+		*mib_val = uic_cmd.argument3;
+
+	return ret;
+}
+
+static int ufshcd_disable_tx_lcc(struct ufs_hba *hba, bool peer)
+{
+	u32 tx_lanes, i, err = 0;
+
+	if (!peer)
+		ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
+			       &tx_lanes);
+	else
+		ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
+				    &tx_lanes);
+	for (i = 0; i < tx_lanes; i++) {
+		if (!peer)
+			err = ufshcd_dme_set(hba,
+					     UIC_ARG_MIB_SEL(TX_LCC_ENABLE,
+					     UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i)),
+					     0);
+		else
+			err = ufshcd_dme_peer_set(hba,
+					UIC_ARG_MIB_SEL(TX_LCC_ENABLE,
+					UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i)),
+					0);
+		if (err) {
+			dev_err(hba->dev, "%s: TX LCC Disable failed, peer = %d, lane = %d, err = %d",
+				__func__, peer, i, err);
+			break;
+		}
+	}
+
+	return err;
+}
+
+static inline int ufshcd_disable_device_tx_lcc(struct ufs_hba *hba)
+{
+	return ufshcd_disable_tx_lcc(hba, true);
+}
+
+/**
+ * ufshcd_dme_link_startup - Notify Unipro to perform link startup
+ *
+ */
+static int ufshcd_dme_link_startup(struct ufs_hba *hba)
+{
+	struct uic_command uic_cmd = {0};
+	int ret;
+
+	uic_cmd.command = UIC_CMD_DME_LINK_STARTUP;
+
+	ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+	if (ret)
+		dev_dbg(hba->dev,
+			"dme-link-startup: error code %d\n", ret);
+	return ret;
+}
+
+/**
+ * ufshcd_disable_intr_aggr - Disables interrupt aggregation.
+ *
+ */
+static inline void ufshcd_disable_intr_aggr(struct ufs_hba *hba)
+{
+	ufshcd_writel(hba, 0, REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
+}
+
+/**
+ * ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY
+ */
+static inline int ufshcd_get_lists_status(u32 reg)
+{
+	return !((reg & UFSHCD_STATUS_READY) == UFSHCD_STATUS_READY);
+}
+
+/**
+ * ufshcd_enable_run_stop_reg - Enable run-stop registers,
+ *			When run-stop registers are set to 1, it indicates the
+ *			host controller that it can process the requests
+ */
+static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
+{
+	ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT,
+		      REG_UTP_TASK_REQ_LIST_RUN_STOP);
+	ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
+		      REG_UTP_TRANSFER_REQ_LIST_RUN_STOP);
+}
+
+/**
+ * ufshcd_enable_intr - enable interrupts
+ */
+static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs)
+{
+	u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+	u32 rw;
+
+	if (hba->version == UFSHCI_VERSION_10) {
+		rw = set & INTERRUPT_MASK_RW_VER_10;
+		set = rw | ((set ^ intrs) & intrs);
+	} else {
+		set |= intrs;
+	}
+
+	ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
+
+	hba->intr_mask = set;
+}
+
+/**
+ * ufshcd_make_hba_operational - Make UFS controller operational
+ *
+ * To bring UFS host controller to operational state,
+ * 1. Enable required interrupts
+ * 2. Configure interrupt aggregation
+ * 3. Program UTRL and UTMRL base address
+ * 4. Configure run-stop-registers
+ *
+ */
+static int ufshcd_make_hba_operational(struct ufs_hba *hba)
+{
+	int err = 0;
+	u32 reg;
+
+	/* Enable required interrupts */
+	ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
+
+	/* Disable interrupt aggregation */
+	ufshcd_disable_intr_aggr(hba);
+
+	/* Configure UTRL and UTMRL base address registers */
+	ufshcd_writel(hba, lower_32_bits((dma_addr_t)hba->utrdl),
+		      REG_UTP_TRANSFER_REQ_LIST_BASE_L);
+	ufshcd_writel(hba, upper_32_bits((dma_addr_t)hba->utrdl),
+		      REG_UTP_TRANSFER_REQ_LIST_BASE_H);
+	ufshcd_writel(hba, lower_32_bits((dma_addr_t)hba->utmrdl),
+		      REG_UTP_TASK_REQ_LIST_BASE_L);
+	ufshcd_writel(hba, upper_32_bits((dma_addr_t)hba->utmrdl),
+		      REG_UTP_TASK_REQ_LIST_BASE_H);
+
+	/*
+	 * UCRDY, UTMRLDY and UTRLRDY bits must be 1
+	 */
+	reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS);
+	if (!(ufshcd_get_lists_status(reg))) {
+		ufshcd_enable_run_stop_reg(hba);
+	} else {
+		dev_err(hba->dev,
+			"Host controller not ready to process requests");
+		err = -EIO;
+		goto out;
+	}
+
+out:
+	return err;
+}
+
+/**
+ * ufshcd_link_startup - Initialize unipro link startup
+ */
+static int ufshcd_link_startup(struct ufs_hba *hba)
+{
+	int ret;
+	int retries = DME_LINKSTARTUP_RETRIES;
+	bool link_startup_again = true;
+
+link_startup:
+	do {
+		ufshcd_ops_link_startup_notify(hba, PRE_CHANGE);
+
+		ret = ufshcd_dme_link_startup(hba);
+
+		/* check if device is detected by inter-connect layer */
+		if (!ret && !ufshcd_is_device_present(hba)) {
+			dev_err(hba->dev, "%s: Device not present\n", __func__);
+			ret = -ENXIO;
+			goto out;
+		}
+
+		/*
+		 * DME link lost indication is only received when link is up,
+		 * but we can't be sure if the link is up until link startup
+		 * succeeds. So reset the local Uni-Pro and try again.
+		 */
+		if (ret && ufshcd_hba_enable(hba))
+			goto out;
+	} while (ret && retries--);
+
+	if (ret)
+		/* failed to get the link up... retire */
+		goto out;
+
+	if (link_startup_again) {
+		link_startup_again = false;
+		retries = DME_LINKSTARTUP_RETRIES;
+		goto link_startup;
+	}
+
+	/* Mark that link is up in PWM-G1, 1-lane, SLOW-AUTO mode */
+	ufshcd_init_pwr_info(hba);
+	ufshcd_print_pwr_info(hba);
+
+	if (hba->quirks & UFSHCD_QUIRK_BROKEN_LCC) {
+		ret = ufshcd_disable_device_tx_lcc(hba);
+		if (ret)
+			goto out;
+	}
+
+	/* Include any host controller configuration via UIC commands */
+	ret = ufshcd_ops_link_startup_notify(hba, POST_CHANGE);
+	if (ret)
+		goto out;
+
+	ret = ufshcd_make_hba_operational(hba);
+out:
+	if (ret)
+		dev_err(hba->dev, "link startup failed %d\n", ret);
+
+	return ret;
+}
+
+/**
+ * ufshcd_hba_stop - Send controller to reset state
+ */
+static inline void ufshcd_hba_stop(struct ufs_hba *hba)
+{
+	int err;
+
+	ufshcd_writel(hba, CONTROLLER_DISABLE,  REG_CONTROLLER_ENABLE);
+	err = ufshcd_wait_for_register(hba, REG_CONTROLLER_ENABLE,
+				       CONTROLLER_ENABLE, CONTROLLER_DISABLE,
+				       10);
+	if (err)
+		dev_err(hba->dev, "%s: Controller disable failed\n", __func__);
+}
+
+/**
+ * ufshcd_is_hba_active - Get controller state
+ */
+static inline bool ufshcd_is_hba_active(struct ufs_hba *hba)
+{
+	return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & CONTROLLER_ENABLE)
+		? false : true;
+}
+
+/**
+ * ufshcd_hba_start - Start controller initialization sequence
+ */
+static inline void ufshcd_hba_start(struct ufs_hba *hba)
+{
+	ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE);
+}
+
+/**
+ * ufshcd_hba_enable - initialize the controller
+ */
+static int ufshcd_hba_enable(struct ufs_hba *hba)
+{
+	int retry;
+
+	if (!ufshcd_is_hba_active(hba))
+		/* change controller state to "reset state" */
+		ufshcd_hba_stop(hba);
+
+	ufshcd_ops_hce_enable_notify(hba, PRE_CHANGE);
+
+	/* start controller initialization sequence */
+	ufshcd_hba_start(hba);
+
+	/*
+	 * To initialize a UFS host controller HCE bit must be set to 1.
+	 * During initialization the HCE bit value changes from 1->0->1.
+	 * When the host controller completes initialization sequence
+	 * it sets the value of HCE bit to 1. The same HCE bit is read back
+	 * to check if the controller has completed initialization sequence.
+	 * So without this delay the value HCE = 1, set in the previous
+	 * instruction might be read back.
+	 * This delay can be changed based on the controller.
+	 */
+	mdelay(1);
+
+	/* wait for the host controller to complete initialization */
+	retry = 10;
+	while (ufshcd_is_hba_active(hba)) {
+		if (retry) {
+			retry--;
+		} else {
+			dev_err(hba->dev, "Controller enable failed\n");
+			return -EIO;
+		}
+		mdelay(5);
+	}
+
+	/* enable UIC related interrupts */
+	ufshcd_enable_intr(hba, UFSHCD_UIC_MASK);
+
+	ufshcd_ops_hce_enable_notify(hba, POST_CHANGE);
+
+	return 0;
+}
+
+/**
+ * ufshcd_host_memory_configure - configure local reference block with
+ *				memory offsets
+ */
+static void ufshcd_host_memory_configure(struct ufs_hba *hba)
+{
+	struct utp_transfer_req_desc *utrdlp;
+	dma_addr_t cmd_desc_dma_addr;
+	u16 response_offset;
+	u16 prdt_offset;
+
+	utrdlp = hba->utrdl;
+	cmd_desc_dma_addr = (dma_addr_t)hba->ucdl;
+
+	utrdlp->command_desc_base_addr_lo =
+				cpu_to_le32(lower_32_bits(cmd_desc_dma_addr));
+	utrdlp->command_desc_base_addr_hi =
+				cpu_to_le32(upper_32_bits(cmd_desc_dma_addr));
+
+	response_offset = offsetof(struct utp_transfer_cmd_desc, response_upiu);
+	prdt_offset = offsetof(struct utp_transfer_cmd_desc, prd_table);
+
+	utrdlp->response_upiu_offset = cpu_to_le16(response_offset >> 2);
+	utrdlp->prd_table_offset = cpu_to_le16(prdt_offset >> 2);
+	utrdlp->response_upiu_length = cpu_to_le16(ALIGNED_UPIU_SIZE >> 2);
+
+	hba->ucd_req_ptr = (struct utp_upiu_req *)hba->ucdl;
+	hba->ucd_rsp_ptr =
+		(struct utp_upiu_rsp *)&hba->ucdl->response_upiu;
+	hba->ucd_prdt_ptr =
+		(struct ufshcd_sg_entry *)&hba->ucdl->prd_table;
+}
+
+/**
+ * ufshcd_memory_alloc - allocate memory for host memory space data structures
+ */
+static int ufshcd_memory_alloc(struct ufs_hba *hba)
+{
+	/* Allocate one Transfer Request Descriptor
+	 * Should be aligned to 1k boundary.
+	 */
+	hba->utrdl = memalign(1024, sizeof(struct utp_transfer_req_desc));
+	if (!hba->utrdl) {
+		dev_err(hba->dev, "Transfer Descriptor memory allocation failed\n");
+		return -ENOMEM;
+	}
+
+	/* Allocate one Command Descriptor
+	 * Should be aligned to 1k boundary.
+	 */
+	hba->ucdl = memalign(1024, sizeof(struct utp_transfer_cmd_desc));
+	if (!hba->ucdl) {
+		dev_err(hba->dev, "Command descriptor memory allocation failed\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/**
+ * ufshcd_get_intr_mask - Get the interrupt bit mask
+ */
+static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba)
+{
+	u32 intr_mask = 0;
+
+	switch (hba->version) {
+	case UFSHCI_VERSION_10:
+		intr_mask = INTERRUPT_MASK_ALL_VER_10;
+		break;
+	case UFSHCI_VERSION_11:
+	case UFSHCI_VERSION_20:
+		intr_mask = INTERRUPT_MASK_ALL_VER_11;
+		break;
+	case UFSHCI_VERSION_21:
+	default:
+		intr_mask = INTERRUPT_MASK_ALL_VER_21;
+		break;
+	}
+
+	return intr_mask;
+}
+
+/**
+ * ufshcd_get_ufs_version - Get the UFS version supported by the HBA
+ */
+static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
+{
+	return ufshcd_readl(hba, REG_UFS_VERSION);
+}
+
+/**
+ * ufshcd_get_upmcrs - Get the power mode change request status
+ */
+static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
+{
+	return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7;
+}
+
+/**
+ * ufshcd_prepare_req_desc_hdr() - Fills the requests header
+ * descriptor according to request
+ */
+static void ufshcd_prepare_req_desc_hdr(struct utp_transfer_req_desc *req_desc,
+					u32 *upiu_flags,
+					enum dma_data_direction cmd_dir)
+{
+	u32 data_direction;
+	u32 dword_0;
+
+	if (cmd_dir == DMA_FROM_DEVICE) {
+		data_direction = UTP_DEVICE_TO_HOST;
+		*upiu_flags = UPIU_CMD_FLAGS_READ;
+	} else if (cmd_dir == DMA_TO_DEVICE) {
+		data_direction = UTP_HOST_TO_DEVICE;
+		*upiu_flags = UPIU_CMD_FLAGS_WRITE;
+	} else {
+		data_direction = UTP_NO_DATA_TRANSFER;
+		*upiu_flags = UPIU_CMD_FLAGS_NONE;
+	}
+
+	dword_0 = data_direction | (0x1 << UPIU_COMMAND_TYPE_OFFSET);
+
+	/* Enable Interrupt for command */
+	dword_0 |= UTP_REQ_DESC_INT_CMD;
+
+	/* Transfer request descriptor header fields */
+	req_desc->header.dword_0 = cpu_to_le32(dword_0);
+	/* dword_1 is reserved, hence it is set to 0 */
+	req_desc->header.dword_1 = 0;
+	/*
+	 * assigning invalid value for command status. Controller
+	 * updates OCS on command completion, with the command
+	 * status
+	 */
+	req_desc->header.dword_2 =
+		cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
+	/* dword_3 is reserved, hence it is set to 0 */
+	req_desc->header.dword_3 = 0;
+
+	req_desc->prd_table_length = 0;
+}
+
+static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
+					      u32 upiu_flags)
+{
+	struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr;
+	struct ufs_query *query = &hba->dev_cmd.query;
+	u16 len = be16_to_cpu(query->request.upiu_req.length);
+
+	/* Query request header */
+	ucd_req_ptr->header.dword_0 =
+				UPIU_HEADER_DWORD(UPIU_TRANSACTION_QUERY_REQ,
+						  upiu_flags, 0, TASK_TAG);
+	ucd_req_ptr->header.dword_1 =
+				UPIU_HEADER_DWORD(0, query->request.query_func,
+						  0, 0);
+
+	/* Data segment length only need for WRITE_DESC */
+	if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC)
+		ucd_req_ptr->header.dword_2 =
+				UPIU_HEADER_DWORD(0, 0, (len >> 8), (u8)len);
+	else
+		ucd_req_ptr->header.dword_2 = 0;
+
+	/* Copy the Query Request buffer as is */
+	memcpy(&ucd_req_ptr->qr, &query->request.upiu_req, QUERY_OSF_SIZE);
+
+	/* Copy the Descriptor */
+	if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC)
+		memcpy(ucd_req_ptr + 1, query->descriptor, len);
+
+	memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
+}
+
+static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba)
+{
+	struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr;
+
+	memset(ucd_req_ptr, 0, sizeof(struct utp_upiu_req));
+
+	/* command descriptor fields */
+	ucd_req_ptr->header.dword_0 =
+			UPIU_HEADER_DWORD(UPIU_TRANSACTION_NOP_OUT, 0, 0, 0x1f);
+	/* clear rest of the fields of basic header */
+	ucd_req_ptr->header.dword_1 = 0;
+	ucd_req_ptr->header.dword_2 = 0;
+
+	memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
+}
+
+/**
+ * ufshcd_comp_devman_upiu - UFS Protocol Information Unit(UPIU)
+ *			     for Device Management Purposes
+ */
+static int ufshcd_comp_devman_upiu(struct ufs_hba *hba,
+				   enum dev_cmd_type cmd_type)
+{
+	u32 upiu_flags;
+	int ret = 0;
+	struct utp_transfer_req_desc *req_desc = hba->utrdl;
+
+	hba->dev_cmd.type = cmd_type;
+
+	ufshcd_prepare_req_desc_hdr(req_desc, &upiu_flags, DMA_NONE);
+	switch (cmd_type) {
+	case DEV_CMD_TYPE_QUERY:
+		ufshcd_prepare_utp_query_req_upiu(hba, upiu_flags);
+		break;
+	case DEV_CMD_TYPE_NOP:
+		ufshcd_prepare_utp_nop_upiu(hba);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
+{
+	unsigned long start;
+	u32 intr_status;
+	u32 enabled_intr_status;
+
+	ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
+
+	start = get_timer(0);
+	do {
+		intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
+		enabled_intr_status = intr_status & hba->intr_mask;
+		ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+
+		if (get_timer(start) > QUERY_REQ_TIMEOUT) {
+			dev_err(hba->dev,
+				"Timedout waiting for UTP response\n");
+
+			return -ETIMEDOUT;
+		}
+
+		if (enabled_intr_status & UFSHCD_ERROR_MASK) {
+			dev_err(hba->dev, "Error in status:%08x\n",
+				enabled_intr_status);
+
+			return -1;
+		}
+	} while (!(enabled_intr_status & UTP_TRANSFER_REQ_COMPL));
+
+	return 0;
+}
+
+/**
+ * ufshcd_get_req_rsp - returns the TR response transaction type
+ */
+static inline int ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
+{
+	return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24;
+}
+
+/**
+ * ufshcd_get_tr_ocs - Get the UTRD Overall Command Status
+ *
+ */
+static inline int ufshcd_get_tr_ocs(struct ufs_hba *hba)
+{
+	return le32_to_cpu(hba->utrdl->header.dword_2) & MASK_OCS;
+}
+
+static inline int ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp *ucd_rsp_ptr)
+{
+	return be32_to_cpu(ucd_rsp_ptr->header.dword_1) & MASK_RSP_UPIU_RESULT;
+}
+
+static int ufshcd_check_query_response(struct ufs_hba *hba)
+{
+	struct ufs_query_res *query_res = &hba->dev_cmd.query.response;
+
+	/* Get the UPIU response */
+	query_res->response = ufshcd_get_rsp_upiu_result(hba->ucd_rsp_ptr) >>
+				UPIU_RSP_CODE_OFFSET;
+	return query_res->response;
+}
+
+/**
+ * ufshcd_copy_query_response() - Copy the Query Response and the data
+ * descriptor
+ */
+static int ufshcd_copy_query_response(struct ufs_hba *hba)
+{
+	struct ufs_query_res *query_res = &hba->dev_cmd.query.response;
+
+	memcpy(&query_res->upiu_res, &hba->ucd_rsp_ptr->qr, QUERY_OSF_SIZE);
+
+	/* Get the descriptor */
+	if (hba->dev_cmd.query.descriptor &&
+	    hba->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) {
+		u8 *descp = (u8 *)hba->ucd_rsp_ptr +
+				GENERAL_UPIU_REQUEST_SIZE;
+		u16 resp_len;
+		u16 buf_len;
+
+		/* data segment length */
+		resp_len = be32_to_cpu(hba->ucd_rsp_ptr->header.dword_2) &
+						MASK_QUERY_DATA_SEG_LEN;
+		buf_len =
+			be16_to_cpu(hba->dev_cmd.query.request.upiu_req.length);
+		if (likely(buf_len >= resp_len)) {
+			memcpy(hba->dev_cmd.query.descriptor, descp, resp_len);
+		} else {
+			dev_warn(hba->dev,
+				 "%s: Response size is bigger than buffer",
+				 __func__);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * ufshcd_exec_dev_cmd - API for sending device management requests
+ */
+static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, enum dev_cmd_type cmd_type,
+			       int timeout)
+{
+	int err;
+	int resp;
+
+	err = ufshcd_comp_devman_upiu(hba, cmd_type);
+	if (err)
+		return err;
+
+	err = ufshcd_send_command(hba, TASK_TAG);
+	if (err)
+		return err;
+
+	err = ufshcd_get_tr_ocs(hba);
+	if (err) {
+		dev_err(hba->dev, "Error in OCS:%d\n", err);
+		return -EINVAL;
+	}
+
+	resp = ufshcd_get_req_rsp(hba->ucd_rsp_ptr);
+	switch (resp) {
+	case UPIU_TRANSACTION_NOP_IN:
+		break;
+	case UPIU_TRANSACTION_QUERY_RSP:
+		err = ufshcd_check_query_response(hba);
+		if (!err)
+			err = ufshcd_copy_query_response(hba);
+		break;
+	case UPIU_TRANSACTION_REJECT_UPIU:
+		/* TODO: handle Reject UPIU Response */
+		err = -EPERM;
+		dev_err(hba->dev, "%s: Reject UPIU not fully implemented\n",
+			__func__);
+		break;
+	default:
+		err = -EINVAL;
+		dev_err(hba->dev, "%s: Invalid device management cmd response: %x\n",
+			__func__, resp);
+	}
+
+	return err;
+}
+
+/**
+ * ufshcd_init_query() - init the query response and request parameters
+ */
+static inline void ufshcd_init_query(struct ufs_hba *hba,
+				     struct ufs_query_req **request,
+				     struct ufs_query_res **response,
+				     enum query_opcode opcode,
+				     u8 idn, u8 index, u8 selector)
+{
+	*request = &hba->dev_cmd.query.request;
+	*response = &hba->dev_cmd.query.response;
+	memset(*request, 0, sizeof(struct ufs_query_req));
+	memset(*response, 0, sizeof(struct ufs_query_res));
+	(*request)->upiu_req.opcode = opcode;
+	(*request)->upiu_req.idn = idn;
+	(*request)->upiu_req.index = index;
+	(*request)->upiu_req.selector = selector;
+}
+
+/**
+ * ufshcd_query_flag() - API function for sending flag query requests
+ */
+int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
+		      enum flag_idn idn, bool *flag_res)
+{
+	struct ufs_query_req *request = NULL;
+	struct ufs_query_res *response = NULL;
+	int err, index = 0, selector = 0;
+	int timeout = QUERY_REQ_TIMEOUT;
+
+	ufshcd_init_query(hba, &request, &response, opcode, idn, index,
+			  selector);
+
+	switch (opcode) {
+	case UPIU_QUERY_OPCODE_SET_FLAG:
+	case UPIU_QUERY_OPCODE_CLEAR_FLAG:
+	case UPIU_QUERY_OPCODE_TOGGLE_FLAG:
+		request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
+		break;
+	case UPIU_QUERY_OPCODE_READ_FLAG:
+		request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
+		if (!flag_res) {
+			/* No dummy reads */
+			dev_err(hba->dev, "%s: Invalid argument for read request\n",
+				__func__);
+			err = -EINVAL;
+			goto out;
+		}
+		break;
+	default:
+		dev_err(hba->dev,
+			"%s: Expected query flag opcode but got = %d\n",
+			__func__, opcode);
+		err = -EINVAL;
+		goto out;
+	}
+
+	err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, timeout);
+
+	if (err) {
+		dev_err(hba->dev,
+			"%s: Sending flag query for idn %d failed, err = %d\n",
+			__func__, idn, err);
+		goto out;
+	}
+
+	if (flag_res)
+		*flag_res = (be32_to_cpu(response->upiu_res.value) &
+				MASK_QUERY_UPIU_FLAG_LOC) & 0x1;
+
+out:
+	return err;
+}
+
+static int ufshcd_query_flag_retry(struct ufs_hba *hba,
+				   enum query_opcode opcode,
+				   enum flag_idn idn, bool *flag_res)
+{
+	int ret;
+	int retries;
+
+	for (retries = 0; retries < QUERY_REQ_RETRIES; retries++) {
+		ret = ufshcd_query_flag(hba, opcode, idn, flag_res);
+		if (ret)
+			dev_dbg(hba->dev,
+				"%s: failed with error %d, retries %d\n",
+				__func__, ret, retries);
+		else
+			break;
+	}
+
+	if (ret)
+		dev_err(hba->dev,
+			"%s: query attribute, opcode %d, idn %d, failed with error %d after %d retires\n",
+			__func__, opcode, idn, ret, retries);
+	return ret;
+}
+
+static int __ufshcd_query_descriptor(struct ufs_hba *hba,
+				     enum query_opcode opcode,
+				     enum desc_idn idn, u8 index, u8 selector,
+				     u8 *desc_buf, int *buf_len)
+{
+	struct ufs_query_req *request = NULL;
+	struct ufs_query_res *response = NULL;
+	int err;
+
+	if (!desc_buf) {
+		dev_err(hba->dev, "%s: descriptor buffer required for opcode 0x%x\n",
+			__func__, opcode);
+		err = -EINVAL;
+		goto out;
+	}
+
+	if (*buf_len < QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) {
+		dev_err(hba->dev, "%s: descriptor buffer size (%d) is out of range\n",
+			__func__, *buf_len);
+		err = -EINVAL;
+		goto out;
+	}
+
+	ufshcd_init_query(hba, &request, &response, opcode, idn, index,
+			  selector);
+	hba->dev_cmd.query.descriptor = desc_buf;
+	request->upiu_req.length = cpu_to_be16(*buf_len);
+
+	switch (opcode) {
+	case UPIU_QUERY_OPCODE_WRITE_DESC:
+		request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
+		break;
+	case UPIU_QUERY_OPCODE_READ_DESC:
+		request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
+		break;
+	default:
+		dev_err(hba->dev, "%s: Expected query descriptor opcode but got = 0x%.2x\n",
+			__func__, opcode);
+		err = -EINVAL;
+		goto out;
+	}
+
+	err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT);
+
+	if (err) {
+		dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, index %d, err = %d\n",
+			__func__, opcode, idn, index, err);
+		goto out;
+	}
+
+	hba->dev_cmd.query.descriptor = NULL;
+	*buf_len = be16_to_cpu(response->upiu_res.length);
+
+out:
+	return err;
+}
+
+/**
+ * ufshcd_query_descriptor_retry - API function for sending descriptor requests
+ */
+int ufshcd_query_descriptor_retry(struct ufs_hba *hba, enum query_opcode opcode,
+				  enum desc_idn idn, u8 index, u8 selector,
+				  u8 *desc_buf, int *buf_len)
+{
+	int err;
+	int retries;
+
+	for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+		err = __ufshcd_query_descriptor(hba, opcode, idn, index,
+						selector, desc_buf, buf_len);
+		if (!err || err == -EINVAL)
+			break;
+	}
+
+	return err;
+}
+
+/**
+ * ufshcd_read_desc_length - read the specified descriptor length from header
+ */
+static int ufshcd_read_desc_length(struct ufs_hba *hba, enum desc_idn desc_id,
+				   int desc_index, int *desc_length)
+{
+	int ret;
+	u8 header[QUERY_DESC_HDR_SIZE];
+	int header_len = QUERY_DESC_HDR_SIZE;
+
+	if (desc_id >= QUERY_DESC_IDN_MAX)
+		return -EINVAL;
+
+	ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC,
+					    desc_id, desc_index, 0, header,
+					    &header_len);
+
+	if (ret) {
+		dev_err(hba->dev, "%s: Failed to get descriptor header id %d",
+			__func__, desc_id);
+		return ret;
+	} else if (desc_id != header[QUERY_DESC_DESC_TYPE_OFFSET]) {
+		dev_warn(hba->dev, "%s: descriptor header id %d and desc_id %d mismatch",
+			 __func__, header[QUERY_DESC_DESC_TYPE_OFFSET],
+			 desc_id);
+		ret = -EINVAL;
+	}
+
+	*desc_length = header[QUERY_DESC_LENGTH_OFFSET];
+
+	return ret;
+}
+
+static void ufshcd_init_desc_sizes(struct ufs_hba *hba)
+{
+	int err;
+
+	err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_DEVICE, 0,
+				      &hba->desc_size.dev_desc);
+	if (err)
+		hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE;
+
+	err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_POWER, 0,
+				      &hba->desc_size.pwr_desc);
+	if (err)
+		hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE;
+
+	err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_INTERCONNECT, 0,
+				      &hba->desc_size.interc_desc);
+	if (err)
+		hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE;
+
+	err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_CONFIGURATION, 0,
+				      &hba->desc_size.conf_desc);
+	if (err)
+		hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE;
+
+	err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_UNIT, 0,
+				      &hba->desc_size.unit_desc);
+	if (err)
+		hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE;
+
+	err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_GEOMETRY, 0,
+				      &hba->desc_size.geom_desc);
+	if (err)
+		hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE;
+
+	err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_HEALTH, 0,
+				      &hba->desc_size.hlth_desc);
+	if (err)
+		hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE;
+}
+
+/**
+ * ufshcd_map_desc_id_to_length - map descriptor IDN to its length
+ *
+ */
+int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id,
+				 int *desc_len)
+{
+	switch (desc_id) {
+	case QUERY_DESC_IDN_DEVICE:
+		*desc_len = hba->desc_size.dev_desc;
+		break;
+	case QUERY_DESC_IDN_POWER:
+		*desc_len = hba->desc_size.pwr_desc;
+		break;
+	case QUERY_DESC_IDN_GEOMETRY:
+		*desc_len = hba->desc_size.geom_desc;
+		break;
+	case QUERY_DESC_IDN_CONFIGURATION:
+		*desc_len = hba->desc_size.conf_desc;
+		break;
+	case QUERY_DESC_IDN_UNIT:
+		*desc_len = hba->desc_size.unit_desc;
+		break;
+	case QUERY_DESC_IDN_INTERCONNECT:
+		*desc_len = hba->desc_size.interc_desc;
+		break;
+	case QUERY_DESC_IDN_STRING:
+		*desc_len = QUERY_DESC_MAX_SIZE;
+		break;
+	case QUERY_DESC_IDN_HEALTH:
+		*desc_len = hba->desc_size.hlth_desc;
+		break;
+	case QUERY_DESC_IDN_RFU_0:
+	case QUERY_DESC_IDN_RFU_1:
+		*desc_len = 0;
+		break;
+	default:
+		*desc_len = 0;
+		return -EINVAL;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(ufshcd_map_desc_id_to_length);
+
+/**
+ * ufshcd_read_desc_param - read the specified descriptor parameter
+ *
+ */
+int ufshcd_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id,
+			   int desc_index, u8 param_offset, u8 *param_read_buf,
+			   u8 param_size)
+{
+	int ret;
+	u8 *desc_buf;
+	int buff_len;
+	bool is_kmalloc = true;
+
+	/* Safety check */
+	if (desc_id >= QUERY_DESC_IDN_MAX || !param_size)
+		return -EINVAL;
+
+	/* Get the max length of descriptor from structure filled up at probe
+	 * time.
+	 */
+	ret = ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len);
+
+	/* Sanity checks */
+	if (ret || !buff_len) {
+		dev_err(hba->dev, "%s: Failed to get full descriptor length",
+			__func__);
+		return ret;
+	}
+
+	/* Check whether we need temp memory */
+	if (param_offset != 0 || param_size < buff_len) {
+		desc_buf = kmalloc(buff_len, GFP_KERNEL);
+		if (!desc_buf)
+			return -ENOMEM;
+	} else {
+		desc_buf = param_read_buf;
+		is_kmalloc = false;
+	}
+
+	/* Request for full descriptor */
+	ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC,
+					    desc_id, desc_index, 0, desc_buf,
+					    &buff_len);
+
+	if (ret) {
+		dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d",
+			__func__, desc_id, desc_index, param_offset, ret);
+		goto out;
+	}
+
+	/* Sanity check */
+	if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) {
+		dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header",
+			__func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* Check wherher we will not copy more data, than available */
+	if (is_kmalloc && param_size > buff_len)
+		param_size = buff_len;
+
+	if (is_kmalloc)
+		memcpy(param_read_buf, &desc_buf[param_offset], param_size);
+out:
+	if (is_kmalloc)
+		kfree(desc_buf);
+	return ret;
+}
+
+/* replace non-printable or non-ASCII characters with spaces */
+static inline void ufshcd_remove_non_printable(uint8_t *val)
+{
+	if (!val)
+		return;
+
+	if (*val < 0x20 || *val > 0x7e)
+		*val = ' ';
+}
+
+/**
+ * ufshcd_uic_pwr_ctrl - executes UIC commands (which affects the link power
+ * state) and waits for it to take effect.
+ *
+ */
+static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
+{
+	unsigned long start = 0;
+	u8 status;
+	int ret;
+
+	ret = ufshcd_send_uic_cmd(hba, cmd);
+	if (ret) {
+		dev_err(hba->dev,
+			"pwr ctrl cmd 0x%x with mode 0x%x uic error %d\n",
+			cmd->command, cmd->argument3, ret);
+
+		return ret;
+	}
+
+	start = get_timer(0);
+	do {
+		status = ufshcd_get_upmcrs(hba);
+		if (get_timer(start) > UFS_UIC_CMD_TIMEOUT) {
+			dev_err(hba->dev,
+				"pwr ctrl cmd 0x%x failed, host upmcrs:0x%x\n",
+				cmd->command, status);
+			ret = (status != PWR_OK) ? status : -1;
+			break;
+		}
+	} while (status != PWR_LOCAL);
+
+	return ret;
+}
+
+/**
+ * ufshcd_uic_change_pwr_mode - Perform the UIC power mode change
+ *				using DME_SET primitives.
+ */
+static int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode)
+{
+	struct uic_command uic_cmd = {0};
+	int ret;
+
+	uic_cmd.command = UIC_CMD_DME_SET;
+	uic_cmd.argument1 = UIC_ARG_MIB(PA_PWRMODE);
+	uic_cmd.argument3 = mode;
+	ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd);
+
+	return ret;
+}
+
+static
+void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufs_hba *hba,
+				      struct scsi_cmd *pccb, u32 upiu_flags)
+{
+	struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr;
+	unsigned int cdb_len;
+
+	/* command descriptor fields */
+	ucd_req_ptr->header.dword_0 =
+			UPIU_HEADER_DWORD(UPIU_TRANSACTION_COMMAND, upiu_flags,
+					  pccb->lun, TASK_TAG);
+	ucd_req_ptr->header.dword_1 =
+			UPIU_HEADER_DWORD(UPIU_COMMAND_SET_TYPE_SCSI, 0, 0, 0);
+
+	/* Total EHS length and Data segment length will be zero */
+	ucd_req_ptr->header.dword_2 = 0;
+
+	ucd_req_ptr->sc.exp_data_transfer_len = cpu_to_be32(pccb->datalen);
+
+	cdb_len = min_t(unsigned short, pccb->cmdlen, UFS_CDB_SIZE);
+	memset(ucd_req_ptr->sc.cdb, 0, UFS_CDB_SIZE);
+	memcpy(ucd_req_ptr->sc.cdb, pccb->cmd, cdb_len);
+
+	memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
+}
+
+static inline void prepare_prdt_desc(struct ufshcd_sg_entry *entry,
+				     unsigned char *buf, ulong len)
+{
+	entry->size = cpu_to_le32(len) | GENMASK(1, 0);
+	entry->base_addr = cpu_to_le32(lower_32_bits((unsigned long)buf));
+	entry->upper_addr = cpu_to_le32(upper_32_bits((unsigned long)buf));
+}
+
+static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb)
+{
+	struct utp_transfer_req_desc *req_desc = hba->utrdl;
+	struct ufshcd_sg_entry *prd_table = hba->ucd_prdt_ptr;
+	ulong datalen = pccb->datalen;
+	int table_length;
+	u8 *buf;
+	int i;
+
+	if (!datalen) {
+		req_desc->prd_table_length = 0;
+		return;
+	}
+
+	table_length = DIV_ROUND_UP(pccb->datalen, MAX_PRDT_ENTRY);
+	buf = pccb->pdata;
+	i = table_length;
+	while (--i) {
+		prepare_prdt_desc(&prd_table[table_length - i - 1], buf,
+				  MAX_PRDT_ENTRY - 1);
+		buf += MAX_PRDT_ENTRY;
+		datalen -= MAX_PRDT_ENTRY;
+	}
+
+	prepare_prdt_desc(&prd_table[table_length - i - 1], buf, datalen - 1);
+
+	req_desc->prd_table_length = table_length;
+}
+
+static int ufs_scsi_exec(struct udevice *scsi_dev, struct scsi_cmd *pccb)
+{
+	struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent);
+	struct utp_transfer_req_desc *req_desc = hba->utrdl;
+	u32 upiu_flags;
+	int ocs, result = 0;
+	u8 scsi_status;
+
+	ufshcd_prepare_req_desc_hdr(req_desc, &upiu_flags, pccb->dma_dir);
+	ufshcd_prepare_utp_scsi_cmd_upiu(hba, pccb, upiu_flags);
+	prepare_prdt_table(hba, pccb);
+
+	ufshcd_send_command(hba, TASK_TAG);
+
+	ocs = ufshcd_get_tr_ocs(hba);
+	switch (ocs) {
+	case OCS_SUCCESS:
+		result = ufshcd_get_req_rsp(hba->ucd_rsp_ptr);
+		switch (result) {
+		case UPIU_TRANSACTION_RESPONSE:
+			result = ufshcd_get_rsp_upiu_result(hba->ucd_rsp_ptr);
+
+			scsi_status = result & MASK_SCSI_STATUS;
+			if (scsi_status)
+				return -EINVAL;
+
+			break;
+		case UPIU_TRANSACTION_REJECT_UPIU:
+			/* TODO: handle Reject UPIU Response */
+			dev_err(hba->dev,
+				"Reject UPIU not fully implemented\n");
+			return -EINVAL;
+		default:
+			dev_err(hba->dev,
+				"Unexpected request response code = %x\n",
+				result);
+			return -EINVAL;
+		}
+		break;
+	default:
+		dev_err(hba->dev, "OCS error from controller = %x\n", ocs);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static inline int ufshcd_read_desc(struct ufs_hba *hba, enum desc_idn desc_id,
+				   int desc_index, u8 *buf, u32 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);
+}
+
+/**
+ * ufshcd_read_string_desc - read string descriptor
+ *
+ */
+int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index,
+			    u8 *buf, u32 size, bool ascii)
+{
+	int err = 0;
+
+	err = ufshcd_read_desc(hba, QUERY_DESC_IDN_STRING, desc_index, buf,
+			       size);
+
+	if (err) {
+		dev_err(hba->dev, "%s: reading String Desc failed after %d retries. err = %d\n",
+			__func__, QUERY_REQ_RETRIES, err);
+		goto out;
+	}
+
+	if (ascii) {
+		int desc_len;
+		int ascii_len;
+		int i;
+		u8 *buff_ascii;
+
+		desc_len = buf[0];
+		/* remove header and divide by 2 to move from UTF16 to UTF8 */
+		ascii_len = (desc_len - QUERY_DESC_HDR_SIZE) / 2 + 1;
+		if (size < ascii_len + QUERY_DESC_HDR_SIZE) {
+			dev_err(hba->dev, "%s: buffer allocated size is too small\n",
+				__func__);
+			err = -ENOMEM;
+			goto out;
+		}
+
+		buff_ascii = kmalloc(ascii_len, GFP_KERNEL);
+		if (!buff_ascii) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		/*
+		 * the descriptor contains string in UTF16 format
+		 * we need to convert to utf-8 so it can be displayed
+		 */
+		utf16_to_utf8(buff_ascii,
+			      (uint16_t *)&buf[QUERY_DESC_HDR_SIZE], ascii_len);
+
+		/* replace non-printable or non-ASCII characters with spaces */
+		for (i = 0; i < ascii_len; i++)
+			ufshcd_remove_non_printable(&buff_ascii[i]);
+
+		memset(buf + QUERY_DESC_HDR_SIZE, 0,
+		       size - QUERY_DESC_HDR_SIZE);
+		memcpy(buf + QUERY_DESC_HDR_SIZE, buff_ascii, ascii_len);
+		buf[QUERY_DESC_LENGTH_OFFSET] = ascii_len + QUERY_DESC_HDR_SIZE;
+		kfree(buff_ascii);
+	}
+out:
+	return err;
+}
+
+static int ufs_get_device_desc(struct ufs_hba *hba,
+			       struct ufs_dev_desc *dev_desc)
+{
+	int err;
+	size_t buff_len;
+	u8 model_index;
+	u8 *desc_buf;
+
+	buff_len = max_t(size_t, hba->desc_size.dev_desc,
+			 QUERY_DESC_MAX_SIZE + 1);
+	desc_buf = kmalloc(buff_len, GFP_KERNEL);
+	if (!desc_buf) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	err = ufshcd_read_device_desc(hba, desc_buf, hba->desc_size.dev_desc);
+	if (err) {
+		dev_err(hba->dev, "%s: Failed reading Device Desc. err = %d\n",
+			__func__, err);
+		goto out;
+	}
+
+	/*
+	 * getting vendor (manufacturerID) and Bank Index in big endian
+	 * format
+	 */
+	dev_desc->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 |
+				     desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1];
+
+	model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
+
+	/* Zero-pad entire buffer for string termination. */
+	memset(desc_buf, 0, buff_len);
+
+	err = ufshcd_read_string_desc(hba, model_index, desc_buf,
+				      QUERY_DESC_MAX_SIZE, true/*ASCII*/);
+	if (err) {
+		dev_err(hba->dev, "%s: Failed reading Product Name. err = %d\n",
+			__func__, err);
+		goto out;
+	}
+
+	desc_buf[QUERY_DESC_MAX_SIZE] = '\0';
+	strlcpy(dev_desc->model, (char *)(desc_buf + QUERY_DESC_HDR_SIZE),
+		min_t(u8, desc_buf[QUERY_DESC_LENGTH_OFFSET],
+		      MAX_MODEL_LEN));
+
+	/* Null terminate the model string */
+	dev_desc->model[MAX_MODEL_LEN] = '\0';
+
+out:
+	kfree(desc_buf);
+	return err;
+}
+
+/**
+ * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device
+ */
+static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
+{
+	struct ufs_pa_layer_attr *pwr_info = &hba->max_pwr_info.info;
+
+	if (hba->max_pwr_info.is_valid)
+		return 0;
+
+	pwr_info->pwr_tx = FAST_MODE;
+	pwr_info->pwr_rx = FAST_MODE;
+	pwr_info->hs_rate = PA_HS_MODE_B;
+
+	/* Get the connected lane count */
+	ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES),
+		       &pwr_info->lane_rx);
+	ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
+		       &pwr_info->lane_tx);
+
+	if (!pwr_info->lane_rx || !pwr_info->lane_tx) {
+		dev_err(hba->dev, "%s: invalid connected lanes value. rx=%d, tx=%d\n",
+			__func__, pwr_info->lane_rx, pwr_info->lane_tx);
+		return -EINVAL;
+	}
+
+	/*
+	 * First, get the maximum gears of HS speed.
+	 * If a zero value, it means there is no HSGEAR capability.
+	 * Then, get the maximum gears of PWM speed.
+	 */
+	ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &pwr_info->gear_rx);
+	if (!pwr_info->gear_rx) {
+		ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
+			       &pwr_info->gear_rx);
+		if (!pwr_info->gear_rx) {
+			dev_err(hba->dev, "%s: invalid max pwm rx gear read = %d\n",
+				__func__, pwr_info->gear_rx);
+			return -EINVAL;
+		}
+		pwr_info->pwr_rx = SLOW_MODE;
+	}
+
+	ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR),
+			    &pwr_info->gear_tx);
+	if (!pwr_info->gear_tx) {
+		ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
+				    &pwr_info->gear_tx);
+		if (!pwr_info->gear_tx) {
+			dev_err(hba->dev, "%s: invalid max pwm tx gear read = %d\n",
+				__func__, pwr_info->gear_tx);
+			return -EINVAL;
+		}
+		pwr_info->pwr_tx = SLOW_MODE;
+	}
+
+	hba->max_pwr_info.is_valid = true;
+	return 0;
+}
+
+static int ufshcd_change_power_mode(struct ufs_hba *hba,
+				    struct ufs_pa_layer_attr *pwr_mode)
+{
+	int ret;
+
+	/* if already configured to the requested pwr_mode */
+	if (pwr_mode->gear_rx == hba->pwr_info.gear_rx &&
+	    pwr_mode->gear_tx == hba->pwr_info.gear_tx &&
+	    pwr_mode->lane_rx == hba->pwr_info.lane_rx &&
+	    pwr_mode->lane_tx == hba->pwr_info.lane_tx &&
+	    pwr_mode->pwr_rx == hba->pwr_info.pwr_rx &&
+	    pwr_mode->pwr_tx == hba->pwr_info.pwr_tx &&
+	    pwr_mode->hs_rate == hba->pwr_info.hs_rate) {
+		dev_dbg(hba->dev, "%s: power already configured\n", __func__);
+		return 0;
+	}
+
+	/*
+	 * Configure attributes for power mode change with below.
+	 * - PA_RXGEAR, PA_ACTIVERXDATALANES, PA_RXTERMINATION,
+	 * - PA_TXGEAR, PA_ACTIVETXDATALANES, PA_TXTERMINATION,
+	 * - PA_HSSERIES
+	 */
+	ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR), pwr_mode->gear_rx);
+	ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES),
+		       pwr_mode->lane_rx);
+	if (pwr_mode->pwr_rx == FASTAUTO_MODE || pwr_mode->pwr_rx == FAST_MODE)
+		ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), TRUE);
+	else
+		ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), FALSE);
+
+	ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), pwr_mode->gear_tx);
+	ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES),
+		       pwr_mode->lane_tx);
+	if (pwr_mode->pwr_tx == FASTAUTO_MODE || pwr_mode->pwr_tx == FAST_MODE)
+		ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), TRUE);
+	else
+		ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), FALSE);
+
+	if (pwr_mode->pwr_rx == FASTAUTO_MODE ||
+	    pwr_mode->pwr_tx == FASTAUTO_MODE ||
+	    pwr_mode->pwr_rx == FAST_MODE ||
+	    pwr_mode->pwr_tx == FAST_MODE)
+		ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES),
+			       pwr_mode->hs_rate);
+
+	ret = ufshcd_uic_change_pwr_mode(hba, pwr_mode->pwr_rx << 4 |
+					 pwr_mode->pwr_tx);
+
+	if (ret) {
+		dev_err(hba->dev,
+			"%s: power mode change failed %d\n", __func__, ret);
+
+		return ret;
+	}
+
+	/* Copy new Power Mode to power info */
+	memcpy(&hba->pwr_info, pwr_mode, sizeof(struct ufs_pa_layer_attr));
+
+	return ret;
+}
+
+/**
+ * ufshcd_verify_dev_init() - Verify device initialization
+ *
+ */
+static int ufshcd_verify_dev_init(struct ufs_hba *hba)
+{
+	int retries;
+	int err;
+
+	for (retries = NOP_OUT_RETRIES; retries > 0; retries--) {
+		err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_NOP,
+					  NOP_OUT_TIMEOUT);
+		if (!err || err == -ETIMEDOUT)
+			break;
+
+		dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
+	}
+
+	if (err)
+		dev_err(hba->dev, "%s: NOP OUT failed %d\n", __func__, err);
+
+	return err;
+}
+
+/**
+ * ufshcd_complete_dev_init() - checks device readiness
+ */
+static int ufshcd_complete_dev_init(struct ufs_hba *hba)
+{
+	int i;
+	int err;
+	bool flag_res = 1;
+
+	err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG,
+				      QUERY_FLAG_IDN_FDEVICEINIT, NULL);
+	if (err) {
+		dev_err(hba->dev,
+			"%s setting fDeviceInit flag failed with error %d\n",
+			__func__, err);
+		goto out;
+	}
+
+	/* poll for max. 1000 iterations for fDeviceInit flag to clear */
+	for (i = 0; i < 1000 && !err && flag_res; i++)
+		err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG,
+					      QUERY_FLAG_IDN_FDEVICEINIT,
+					      &flag_res);
+
+	if (err)
+		dev_err(hba->dev,
+			"%s reading fDeviceInit flag failed with error %d\n",
+			__func__, err);
+	else if (flag_res)
+		dev_err(hba->dev,
+			"%s fDeviceInit was not cleared by the device\n",
+			__func__);
+
+out:
+	return err;
+}
+
+static void ufshcd_def_desc_sizes(struct ufs_hba *hba)
+{
+	hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE;
+	hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE;
+	hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE;
+	hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE;
+	hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE;
+	hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE;
+	hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE;
+}
+
+int ufs_start(struct ufs_hba *hba)
+{
+	struct ufs_dev_desc card = {0};
+	int ret;
+
+	ret = ufshcd_link_startup(hba);
+	if (ret)
+		return ret;
+
+	ret = ufshcd_verify_dev_init(hba);
+	if (ret)
+		return ret;
+
+	ret = ufshcd_complete_dev_init(hba);
+	if (ret)
+		return ret;
+
+	/* Init check for device descriptor sizes */
+	ufshcd_init_desc_sizes(hba);
+
+	ret = ufs_get_device_desc(hba, &card);
+	if (ret) {
+		dev_err(hba->dev, "%s: Failed getting device info. err = %d\n",
+			__func__, ret);
+
+		return ret;
+	}
+
+	if (ufshcd_get_max_pwr_mode(hba)) {
+		dev_err(hba->dev,
+			"%s: Failed getting max supported power mode\n",
+			__func__);
+	} else {
+		ret = ufshcd_change_power_mode(hba, &hba->max_pwr_info.info);
+		if (ret) {
+			dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n",
+				__func__, ret);
+
+			return ret;
+		}
+
+		ufshcd_print_pwr_info(hba);
+	}
+
+	return 0;
+}
+
+int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops)
+{
+	struct ufs_hba *hba = dev_get_uclass_priv(ufs_dev);
+	struct scsi_platdata *scsi_plat;
+	struct udevice *scsi_dev;
+	int err;
+
+	device_find_first_child(ufs_dev, &scsi_dev);
+	if (!scsi_dev)
+		return -ENODEV;
+
+	scsi_plat = dev_get_uclass_platdata(scsi_dev);
+	scsi_plat->max_id = UFSHCD_MAX_ID;
+	scsi_plat->max_lun = UFS_MAX_LUNS;
+	scsi_plat->max_bytes = UFS_MAX_BYTES;
+
+	hba->dev = ufs_dev;
+	hba->ops = hba_ops;
+	hba->mmio_base = (void *)dev_read_addr(ufs_dev);
+
+	/* Set descriptor lengths to specification defaults */
+	ufshcd_def_desc_sizes(hba);
+
+	ufshcd_ops_init(hba);
+
+	/* Read capabilties registers */
+	hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
+
+	/* Get UFS version supported by the controller */
+	hba->version = ufshcd_get_ufs_version(hba);
+	if (hba->version != UFSHCI_VERSION_10 &&
+	    hba->version != UFSHCI_VERSION_11 &&
+	    hba->version != UFSHCI_VERSION_20 &&
+	    hba->version != UFSHCI_VERSION_21)
+		dev_err(hba->dev, "invalid UFS version 0x%x\n",
+			hba->version);
+
+	/* Get Interrupt bit mask per version */
+	hba->intr_mask = ufshcd_get_intr_mask(hba);
+
+	/* Allocate memory for host memory space */
+	err = ufshcd_memory_alloc(hba);
+	if (err) {
+		dev_err(hba->dev, "Memory allocation failed\n");
+		return err;
+	}
+
+	/* Configure Local data structures */
+	ufshcd_host_memory_configure(hba);
+
+	/*
+	 * In order to avoid any spurious interrupt immediately after
+	 * registering UFS controller interrupt handler, clear any pending UFS
+	 * interrupt status and disable all the UFS interrupts.
+	 */
+	ufshcd_writel(hba, ufshcd_readl(hba, REG_INTERRUPT_STATUS),
+		      REG_INTERRUPT_STATUS);
+	ufshcd_writel(hba, 0, REG_INTERRUPT_ENABLE);
+
+	err = ufshcd_hba_enable(hba);
+	if (err) {
+		dev_err(hba->dev, "Host controller enable failed\n");
+		return err;
+	}
+
+	err = ufs_start(hba);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+int ufs_scsi_bind(struct udevice *ufs_dev, struct udevice **scsi_devp)
+{
+	int ret = device_bind_driver(ufs_dev, "ufs_scsi", "ufs_scsi",
+				     scsi_devp);
+
+	return ret;
+}
+
+static struct scsi_ops ufs_ops = {
+	.exec		= ufs_scsi_exec,
+};
+
+int ufs_probe(void)
+{
+	struct uclass *uc;
+	struct udevice *dev;
+	int ret, i;
+
+	ret = uclass_get(UCLASS_UFS, &uc);
+	if (ret)
+		return ret;
+
+	for (i = 0;; i++) {
+		ret = uclass_get_device_by_seq(UCLASS_UFS, i, &dev);
+		if (ret == -ENODEV)
+			break;
+	}
+
+	uclass_foreach_dev(dev, uc) {
+		ret = device_probe(dev);
+		if (ret)
+			pr_err("%s - probe failed %d\n", dev->name, ret);
+	}
+
+	return 0;
+}
+
+U_BOOT_DRIVER(ufs_scsi) = {
+	.id = UCLASS_SCSI,
+	.name = "ufs_scsi",
+	.ops = &ufs_ops,
+};
diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h
new file mode 100644
index 0000000000..e0bde93776
--- /dev/null
+++ b/drivers/ufs/ufs.h
@@ -0,0 +1,918 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#ifndef __UFS_H
+#define __UFS_H
+
+#include <asm/io.h>
+#include <dm.h>
+
+#include "unipro.h"
+
+#define UFS_CDB_SIZE	16
+#define UPIU_TRANSACTION_UIC_CMD 0x1F
+#define UIC_CMD_SIZE (sizeof(u32) * 4)
+#define RESPONSE_UPIU_SENSE_DATA_LENGTH	18
+#define UFS_MAX_LUNS		0x7F
+
+enum {
+	TASK_REQ_UPIU_SIZE_DWORDS	= 8,
+	TASK_RSP_UPIU_SIZE_DWORDS	= 8,
+	ALIGNED_UPIU_SIZE		= 512,
+};
+
+/* UFS device power modes */
+enum ufs_dev_pwr_mode {
+	UFS_ACTIVE_PWR_MODE	= 1,
+	UFS_SLEEP_PWR_MODE	= 2,
+	UFS_POWERDOWN_PWR_MODE	= 3,
+};
+
+enum ufs_notify_change_status {
+	PRE_CHANGE,
+	POST_CHANGE,
+};
+
+struct ufs_pa_layer_attr {
+	u32 gear_rx;
+	u32 gear_tx;
+	u32 lane_rx;
+	u32 lane_tx;
+	u32 pwr_rx;
+	u32 pwr_tx;
+	u32 hs_rate;
+};
+
+struct ufs_pwr_mode_info {
+	bool is_valid;
+	struct ufs_pa_layer_attr info;
+};
+
+enum ufs_desc_def_size {
+	QUERY_DESC_DEVICE_DEF_SIZE		= 0x40,
+	QUERY_DESC_CONFIGURATION_DEF_SIZE	= 0x90,
+	QUERY_DESC_UNIT_DEF_SIZE		= 0x23,
+	QUERY_DESC_INTERCONNECT_DEF_SIZE	= 0x06,
+	QUERY_DESC_GEOMETRY_DEF_SIZE		= 0x48,
+	QUERY_DESC_POWER_DEF_SIZE		= 0x62,
+	QUERY_DESC_HEALTH_DEF_SIZE		= 0x25,
+};
+
+struct ufs_desc_size {
+	int dev_desc;
+	int pwr_desc;
+	int geom_desc;
+	int interc_desc;
+	int unit_desc;
+	int conf_desc;
+	int hlth_desc;
+};
+
+/*
+ * Request Descriptor Definitions
+ */
+
+/* Transfer request command type */
+enum {
+	UTP_CMD_TYPE_SCSI		= 0x0,
+	UTP_CMD_TYPE_UFS		= 0x1,
+	UTP_CMD_TYPE_DEV_MANAGE		= 0x2,
+};
+
+/* UTP Transfer Request Command Offset */
+#define UPIU_COMMAND_TYPE_OFFSET	28
+
+/* Offset of the response code in the UPIU header */
+#define UPIU_RSP_CODE_OFFSET		8
+
+/* To accommodate UFS2.0 required Command type */
+enum {
+	UTP_CMD_TYPE_UFS_STORAGE	= 0x1,
+};
+
+enum {
+	UTP_SCSI_COMMAND		= 0x00000000,
+	UTP_NATIVE_UFS_COMMAND		= 0x10000000,
+	UTP_DEVICE_MANAGEMENT_FUNCTION	= 0x20000000,
+	UTP_REQ_DESC_INT_CMD		= 0x01000000,
+};
+
+/* UTP Transfer Request Data Direction (DD) */
+enum {
+	UTP_NO_DATA_TRANSFER	= 0x00000000,
+	UTP_HOST_TO_DEVICE	= 0x02000000,
+	UTP_DEVICE_TO_HOST	= 0x04000000,
+};
+
+/* Overall command status values */
+enum {
+	OCS_SUCCESS			= 0x0,
+	OCS_INVALID_CMD_TABLE_ATTR	= 0x1,
+	OCS_INVALID_PRDT_ATTR		= 0x2,
+	OCS_MISMATCH_DATA_BUF_SIZE	= 0x3,
+	OCS_MISMATCH_RESP_UPIU_SIZE	= 0x4,
+	OCS_PEER_COMM_FAILURE		= 0x5,
+	OCS_ABORTED			= 0x6,
+	OCS_FATAL_ERROR			= 0x7,
+	OCS_INVALID_COMMAND_STATUS	= 0x0F,
+	MASK_OCS			= 0x0F,
+};
+
+/* The maximum length of the data byte count field in the PRDT is 256KB */
+#define PRDT_DATA_BYTE_COUNT_MAX	(256 * 1024)
+/* The granularity of the data byte count field in the PRDT is 32-bit */
+#define PRDT_DATA_BYTE_COUNT_PAD	4
+
+#define GENERAL_UPIU_REQUEST_SIZE (sizeof(struct utp_upiu_req))
+#define QUERY_DESC_MAX_SIZE       255
+#define QUERY_DESC_MIN_SIZE       2
+#define QUERY_DESC_HDR_SIZE       2
+#define QUERY_OSF_SIZE            (GENERAL_UPIU_REQUEST_SIZE - \
+					(sizeof(struct utp_upiu_header)))
+#define RESPONSE_UPIU_SENSE_DATA_LENGTH	18
+#define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
+			cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
+			 (byte1 << 8) | (byte0))
+/*
+ * UFS Protocol Information Unit related definitions
+ */
+
+/* Task management functions */
+enum {
+	UFS_ABORT_TASK		= 0x01,
+	UFS_ABORT_TASK_SET	= 0x02,
+	UFS_CLEAR_TASK_SET	= 0x04,
+	UFS_LOGICAL_RESET	= 0x08,
+	UFS_QUERY_TASK		= 0x80,
+	UFS_QUERY_TASK_SET	= 0x81,
+};
+
+/* UTP UPIU Transaction Codes Initiator to Target */
+enum {
+	UPIU_TRANSACTION_NOP_OUT	= 0x00,
+	UPIU_TRANSACTION_COMMAND	= 0x01,
+	UPIU_TRANSACTION_DATA_OUT	= 0x02,
+	UPIU_TRANSACTION_TASK_REQ	= 0x04,
+	UPIU_TRANSACTION_QUERY_REQ	= 0x16,
+};
+
+/* UTP UPIU Transaction Codes Target to Initiator */
+enum {
+	UPIU_TRANSACTION_NOP_IN		= 0x20,
+	UPIU_TRANSACTION_RESPONSE	= 0x21,
+	UPIU_TRANSACTION_DATA_IN	= 0x22,
+	UPIU_TRANSACTION_TASK_RSP	= 0x24,
+	UPIU_TRANSACTION_READY_XFER	= 0x31,
+	UPIU_TRANSACTION_QUERY_RSP	= 0x36,
+	UPIU_TRANSACTION_REJECT_UPIU	= 0x3F,
+};
+
+/* UPIU Read/Write flags */
+enum {
+	UPIU_CMD_FLAGS_NONE	= 0x00,
+	UPIU_CMD_FLAGS_WRITE	= 0x20,
+	UPIU_CMD_FLAGS_READ	= 0x40,
+};
+
+/* UPIU Task Attributes */
+enum {
+	UPIU_TASK_ATTR_SIMPLE	= 0x00,
+	UPIU_TASK_ATTR_ORDERED	= 0x01,
+	UPIU_TASK_ATTR_HEADQ	= 0x02,
+	UPIU_TASK_ATTR_ACA	= 0x03,
+};
+
+/* UPIU Query request function */
+enum {
+	UPIU_QUERY_FUNC_STANDARD_READ_REQUEST           = 0x01,
+	UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST          = 0x81,
+};
+
+/* Offset of the response code in the UPIU header */
+#define UPIU_RSP_CODE_OFFSET		8
+
+enum {
+	MASK_SCSI_STATUS		= 0xFF,
+	MASK_TASK_RESPONSE              = 0xFF00,
+	MASK_RSP_UPIU_RESULT            = 0xFFFF,
+	MASK_QUERY_DATA_SEG_LEN         = 0xFFFF,
+	MASK_RSP_UPIU_DATA_SEG_LEN	= 0xFFFF,
+	MASK_RSP_EXCEPTION_EVENT        = 0x10000,
+	MASK_TM_SERVICE_RESP		= 0xFF,
+	MASK_TM_FUNC			= 0xFF,
+};
+
+/* UTP QUERY Transaction Specific Fields OpCode */
+enum query_opcode {
+	UPIU_QUERY_OPCODE_NOP		= 0x0,
+	UPIU_QUERY_OPCODE_READ_DESC	= 0x1,
+	UPIU_QUERY_OPCODE_WRITE_DESC	= 0x2,
+	UPIU_QUERY_OPCODE_READ_ATTR	= 0x3,
+	UPIU_QUERY_OPCODE_WRITE_ATTR	= 0x4,
+	UPIU_QUERY_OPCODE_READ_FLAG	= 0x5,
+	UPIU_QUERY_OPCODE_SET_FLAG	= 0x6,
+	UPIU_QUERY_OPCODE_CLEAR_FLAG	= 0x7,
+	UPIU_QUERY_OPCODE_TOGGLE_FLAG	= 0x8,
+};
+
+/* Query response result code */
+enum {
+	QUERY_RESULT_SUCCESS                    = 0x00,
+	QUERY_RESULT_NOT_READABLE               = 0xF6,
+	QUERY_RESULT_NOT_WRITEABLE              = 0xF7,
+	QUERY_RESULT_ALREADY_WRITTEN            = 0xF8,
+	QUERY_RESULT_INVALID_LENGTH             = 0xF9,
+	QUERY_RESULT_INVALID_VALUE              = 0xFA,
+	QUERY_RESULT_INVALID_SELECTOR           = 0xFB,
+	QUERY_RESULT_INVALID_INDEX              = 0xFC,
+	QUERY_RESULT_INVALID_IDN                = 0xFD,
+	QUERY_RESULT_INVALID_OPCODE             = 0xFE,
+	QUERY_RESULT_GENERAL_FAILURE            = 0xFF,
+};
+
+enum {
+	UPIU_COMMAND_SET_TYPE_SCSI	= 0x0,
+	UPIU_COMMAND_SET_TYPE_UFS	= 0x1,
+	UPIU_COMMAND_SET_TYPE_QUERY	= 0x2,
+};
+
+/* Flag idn for Query Requests*/
+enum flag_idn {
+	QUERY_FLAG_IDN_FDEVICEINIT			= 0x01,
+	QUERY_FLAG_IDN_PERMANENT_WPE			= 0x02,
+	QUERY_FLAG_IDN_PWR_ON_WPE			= 0x03,
+	QUERY_FLAG_IDN_BKOPS_EN				= 0x04,
+	QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE		= 0x05,
+	QUERY_FLAG_IDN_PURGE_ENABLE			= 0x06,
+	QUERY_FLAG_IDN_RESERVED2			= 0x07,
+	QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL		= 0x08,
+	QUERY_FLAG_IDN_BUSY_RTC				= 0x09,
+	QUERY_FLAG_IDN_RESERVED3			= 0x0A,
+	QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE	= 0x0B,
+};
+
+/* Attribute idn for Query requests */
+enum attr_idn {
+	QUERY_ATTR_IDN_BOOT_LU_EN		= 0x00,
+	QUERY_ATTR_IDN_RESERVED			= 0x01,
+	QUERY_ATTR_IDN_POWER_MODE		= 0x02,
+	QUERY_ATTR_IDN_ACTIVE_ICC_LVL		= 0x03,
+	QUERY_ATTR_IDN_OOO_DATA_EN		= 0x04,
+	QUERY_ATTR_IDN_BKOPS_STATUS		= 0x05,
+	QUERY_ATTR_IDN_PURGE_STATUS		= 0x06,
+	QUERY_ATTR_IDN_MAX_DATA_IN		= 0x07,
+	QUERY_ATTR_IDN_MAX_DATA_OUT		= 0x08,
+	QUERY_ATTR_IDN_DYN_CAP_NEEDED		= 0x09,
+	QUERY_ATTR_IDN_REF_CLK_FREQ		= 0x0A,
+	QUERY_ATTR_IDN_CONF_DESC_LOCK		= 0x0B,
+	QUERY_ATTR_IDN_MAX_NUM_OF_RTT		= 0x0C,
+	QUERY_ATTR_IDN_EE_CONTROL		= 0x0D,
+	QUERY_ATTR_IDN_EE_STATUS		= 0x0E,
+	QUERY_ATTR_IDN_SECONDS_PASSED		= 0x0F,
+	QUERY_ATTR_IDN_CNTX_CONF		= 0x10,
+	QUERY_ATTR_IDN_CORR_PRG_BLK_NUM		= 0x11,
+	QUERY_ATTR_IDN_RESERVED2		= 0x12,
+	QUERY_ATTR_IDN_RESERVED3		= 0x13,
+	QUERY_ATTR_IDN_FFU_STATUS		= 0x14,
+	QUERY_ATTR_IDN_PSA_STATE		= 0x15,
+	QUERY_ATTR_IDN_PSA_DATA_SIZE		= 0x16,
+};
+
+/* Descriptor idn for Query requests */
+enum desc_idn {
+	QUERY_DESC_IDN_DEVICE		= 0x0,
+	QUERY_DESC_IDN_CONFIGURATION	= 0x1,
+	QUERY_DESC_IDN_UNIT		= 0x2,
+	QUERY_DESC_IDN_RFU_0		= 0x3,
+	QUERY_DESC_IDN_INTERCONNECT	= 0x4,
+	QUERY_DESC_IDN_STRING		= 0x5,
+	QUERY_DESC_IDN_RFU_1		= 0x6,
+	QUERY_DESC_IDN_GEOMETRY		= 0x7,
+	QUERY_DESC_IDN_POWER		= 0x8,
+	QUERY_DESC_IDN_HEALTH           = 0x9,
+	QUERY_DESC_IDN_MAX,
+};
+
+enum desc_header_offset {
+	QUERY_DESC_LENGTH_OFFSET	= 0x00,
+	QUERY_DESC_DESC_TYPE_OFFSET	= 0x01,
+};
+
+struct ufshcd_sg_entry {
+	__le32    base_addr;
+	__le32    upper_addr;
+	__le32    reserved;
+	__le32    size;
+};
+
+#define MAX_BUFF	128
+/**
+ * struct utp_transfer_cmd_desc - UFS Command Descriptor structure
+ * @command_upiu: Command UPIU Frame address
+ * @response_upiu: Response UPIU Frame address
+ * @prd_table: Physical Region Descriptor
+ */
+struct utp_transfer_cmd_desc {
+	u8 command_upiu[ALIGNED_UPIU_SIZE];
+	u8 response_upiu[ALIGNED_UPIU_SIZE];
+	struct ufshcd_sg_entry    prd_table[MAX_BUFF];
+};
+
+/**
+ * struct request_desc_header - Descriptor Header common to both UTRD and UTMRD
+ * @dword0: Descriptor Header DW0
+ * @dword1: Descriptor Header DW1
+ * @dword2: Descriptor Header DW2
+ * @dword3: Descriptor Header DW3
+ */
+struct request_desc_header {
+	__le32 dword_0;
+	__le32 dword_1;
+	__le32 dword_2;
+	__le32 dword_3;
+};
+
+/**
+ * struct utp_transfer_req_desc - UTRD structure
+ * @header: UTRD header DW-0 to DW-3
+ * @command_desc_base_addr_lo: UCD base address low DW-4
+ * @command_desc_base_addr_hi: UCD base address high DW-5
+ * @response_upiu_length: response UPIU length DW-6
+ * @response_upiu_offset: response UPIU offset DW-6
+ * @prd_table_length: Physical region descriptor length DW-7
+ * @prd_table_offset: Physical region descriptor offset DW-7
+ */
+struct utp_transfer_req_desc {
+	/* DW 0-3 */
+	struct request_desc_header header;
+
+	/* DW 4-5*/
+	__le32  command_desc_base_addr_lo;
+	__le32  command_desc_base_addr_hi;
+
+	/* DW 6 */
+	__le16  response_upiu_length;
+	__le16  response_upiu_offset;
+
+	/* DW 7 */
+	__le16  prd_table_length;
+	__le16  prd_table_offset;
+};
+
+/**
+ * struct utp_upiu_header - UPIU header structure
+ * @dword_0: UPIU header DW-0
+ * @dword_1: UPIU header DW-1
+ * @dword_2: UPIU header DW-2
+ */
+struct utp_upiu_header {
+	__be32 dword_0;
+	__be32 dword_1;
+	__be32 dword_2;
+};
+
+/**
+ * struct utp_upiu_query - upiu request buffer structure for
+ * query request.
+ * @opcode: command to perform B-0
+ * @idn: a value that indicates the particular type of data B-1
+ * @index: Index to further identify data B-2
+ * @selector: Index to further identify data B-3
+ * @reserved_osf: spec reserved field B-4,5
+ * @length: number of descriptor bytes to read/write B-6,7
+ * @value: Attribute value to be written DW-5
+ * @reserved: spec reserved DW-6,7
+ */
+struct utp_upiu_query {
+	__u8 opcode;
+	__u8 idn;
+	__u8 index;
+	__u8 selector;
+	__be16 reserved_osf;
+	__be16 length;
+	__be32 value;
+	__be32 reserved[2];
+};
+
+/**
+ * struct utp_upiu_cmd - Command UPIU structure
+ * @data_transfer_len: Data Transfer Length DW-3
+ * @cdb: Command Descriptor Block CDB DW-4 to DW-7
+ */
+struct utp_upiu_cmd {
+	__be32 exp_data_transfer_len;
+	u8 cdb[UFS_CDB_SIZE];
+};
+
+/*
+ * UTMRD structure.
+ */
+struct utp_task_req_desc {
+	/* DW 0-3 */
+	struct request_desc_header header;
+
+	/* DW 4-11 - Task request UPIU structure */
+	struct utp_upiu_header	req_header;
+	__be32			input_param1;
+	__be32			input_param2;
+	__be32			input_param3;
+	__be32			__reserved1[2];
+
+	/* DW 12-19 - Task Management Response UPIU structure */
+	struct utp_upiu_header	rsp_header;
+	__be32			output_param1;
+	__be32			output_param2;
+	__be32			__reserved2[3];
+};
+
+/**
+ * struct utp_upiu_req - general upiu request structure
+ * @header:UPIU header structure DW-0 to DW-2
+ * @sc: fields structure for scsi command DW-3 to DW-7
+ * @qr: fields structure for query request DW-3 to DW-7
+ */
+struct utp_upiu_req {
+	struct utp_upiu_header header;
+	union {
+		struct utp_upiu_cmd		sc;
+		struct utp_upiu_query		qr;
+		struct utp_upiu_query		tr;
+		/* use utp_upiu_query to host the 4 dwords of uic command */
+		struct utp_upiu_query		uc;
+	};
+};
+
+/**
+ * struct utp_cmd_rsp - Response UPIU structure
+ * @residual_transfer_count: Residual transfer count DW-3
+ * @reserved: Reserved double words DW-4 to DW-7
+ * @sense_data_len: Sense data length DW-8 U16
+ * @sense_data: Sense data field DW-8 to DW-12
+ */
+struct utp_cmd_rsp {
+	__be32 residual_transfer_count;
+	__be32 reserved[4];
+	__be16 sense_data_len;
+	u8 sense_data[RESPONSE_UPIU_SENSE_DATA_LENGTH];
+};
+
+/**
+ * struct utp_upiu_rsp - general upiu response structure
+ * @header: UPIU header structure DW-0 to DW-2
+ * @sr: fields structure for scsi command DW-3 to DW-12
+ * @qr: fields structure for query request DW-3 to DW-7
+ */
+struct utp_upiu_rsp {
+	struct utp_upiu_header header;
+	union {
+		struct utp_cmd_rsp sr;
+		struct utp_upiu_query qr;
+	};
+};
+
+#define MAX_MODEL_LEN 16
+/**
+ * ufs_dev_desc - ufs device details from the device descriptor
+ *
+ * @wmanufacturerid: card details
+ * @model: card model
+ */
+struct ufs_dev_desc {
+	u16 wmanufacturerid;
+	char model[MAX_MODEL_LEN + 1];
+};
+
+/* Device descriptor parameters offsets in bytes*/
+enum device_desc_param {
+	DEVICE_DESC_PARAM_LEN			= 0x0,
+	DEVICE_DESC_PARAM_TYPE			= 0x1,
+	DEVICE_DESC_PARAM_DEVICE_TYPE		= 0x2,
+	DEVICE_DESC_PARAM_DEVICE_CLASS		= 0x3,
+	DEVICE_DESC_PARAM_DEVICE_SUB_CLASS	= 0x4,
+	DEVICE_DESC_PARAM_PRTCL			= 0x5,
+	DEVICE_DESC_PARAM_NUM_LU		= 0x6,
+	DEVICE_DESC_PARAM_NUM_WLU		= 0x7,
+	DEVICE_DESC_PARAM_BOOT_ENBL		= 0x8,
+	DEVICE_DESC_PARAM_DESC_ACCSS_ENBL	= 0x9,
+	DEVICE_DESC_PARAM_INIT_PWR_MODE		= 0xA,
+	DEVICE_DESC_PARAM_HIGH_PR_LUN		= 0xB,
+	DEVICE_DESC_PARAM_SEC_RMV_TYPE		= 0xC,
+	DEVICE_DESC_PARAM_SEC_LU		= 0xD,
+	DEVICE_DESC_PARAM_BKOP_TERM_LT		= 0xE,
+	DEVICE_DESC_PARAM_ACTVE_ICC_LVL		= 0xF,
+	DEVICE_DESC_PARAM_SPEC_VER		= 0x10,
+	DEVICE_DESC_PARAM_MANF_DATE		= 0x12,
+	DEVICE_DESC_PARAM_MANF_NAME		= 0x14,
+	DEVICE_DESC_PARAM_PRDCT_NAME		= 0x15,
+	DEVICE_DESC_PARAM_SN			= 0x16,
+	DEVICE_DESC_PARAM_OEM_ID		= 0x17,
+	DEVICE_DESC_PARAM_MANF_ID		= 0x18,
+	DEVICE_DESC_PARAM_UD_OFFSET		= 0x1A,
+	DEVICE_DESC_PARAM_UD_LEN		= 0x1B,
+	DEVICE_DESC_PARAM_RTT_CAP		= 0x1C,
+	DEVICE_DESC_PARAM_FRQ_RTC		= 0x1D,
+	DEVICE_DESC_PARAM_UFS_FEAT		= 0x1F,
+	DEVICE_DESC_PARAM_FFU_TMT		= 0x20,
+	DEVICE_DESC_PARAM_Q_DPTH		= 0x21,
+	DEVICE_DESC_PARAM_DEV_VER		= 0x22,
+	DEVICE_DESC_PARAM_NUM_SEC_WPA		= 0x24,
+	DEVICE_DESC_PARAM_PSA_MAX_DATA		= 0x25,
+	DEVICE_DESC_PARAM_PSA_TMT		= 0x29,
+	DEVICE_DESC_PARAM_PRDCT_REV		= 0x2A,
+};
+
+struct ufs_hba;
+
+enum {
+	UFSHCD_MAX_CHANNEL	= 0,
+	UFSHCD_MAX_ID		= 1,
+};
+
+enum dev_cmd_type {
+	DEV_CMD_TYPE_NOP		= 0x0,
+	DEV_CMD_TYPE_QUERY		= 0x1,
+};
+
+/**
+ * struct uic_command - UIC command structure
+ * @command: UIC command
+ * @argument1: UIC command argument 1
+ * @argument2: UIC command argument 2
+ * @argument3: UIC command argument 3
+ * @cmd_active: Indicate if UIC command is outstanding
+ * @result: UIC command result
+ * @done: UIC command completion
+ */
+struct uic_command {
+	u32 command;
+	u32 argument1;
+	u32 argument2;
+	u32 argument3;
+	int cmd_active;
+	int result;
+};
+
+/* GenSelectorIndex calculation macros for M-PHY attributes */
+#define UIC_ARG_MPHY_TX_GEN_SEL_INDEX(lane) (lane)
+#define UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane) (PA_MAXDATALANES + (lane))
+
+#define UIC_ARG_MIB_SEL(attr, sel)	((((attr) & 0xFFFF) << 16) |\
+					 ((sel) & 0xFFFF))
+#define UIC_ARG_MIB(attr)		UIC_ARG_MIB_SEL(attr, 0)
+#define UIC_ARG_ATTR_TYPE(t)		(((t) & 0xFF) << 16)
+#define UIC_GET_ATTR_ID(v)		(((v) >> 16) & 0xFFFF)
+
+/* Link Status*/
+enum link_status {
+	UFSHCD_LINK_IS_DOWN	= 1,
+	UFSHCD_LINK_IS_UP	= 2,
+};
+
+#define UIC_ARG_MIB_SEL(attr, sel)	((((attr) & 0xFFFF) << 16) |\
+					 ((sel) & 0xFFFF))
+#define UIC_ARG_MIB(attr)		UIC_ARG_MIB_SEL(attr, 0)
+#define UIC_ARG_ATTR_TYPE(t)		(((t) & 0xFF) << 16)
+#define UIC_GET_ATTR_ID(v)		(((v) >> 16) & 0xFFFF)
+
+/* UIC Commands */
+enum uic_cmd_dme {
+	UIC_CMD_DME_GET			= 0x01,
+	UIC_CMD_DME_SET			= 0x02,
+	UIC_CMD_DME_PEER_GET		= 0x03,
+	UIC_CMD_DME_PEER_SET		= 0x04,
+	UIC_CMD_DME_POWERON		= 0x10,
+	UIC_CMD_DME_POWEROFF		= 0x11,
+	UIC_CMD_DME_ENABLE		= 0x12,
+	UIC_CMD_DME_RESET		= 0x14,
+	UIC_CMD_DME_END_PT_RST		= 0x15,
+	UIC_CMD_DME_LINK_STARTUP	= 0x16,
+	UIC_CMD_DME_HIBER_ENTER		= 0x17,
+	UIC_CMD_DME_HIBER_EXIT		= 0x18,
+	UIC_CMD_DME_TEST_MODE		= 0x1A,
+};
+
+/* UIC Config result code / Generic error code */
+enum {
+	UIC_CMD_RESULT_SUCCESS			= 0x00,
+	UIC_CMD_RESULT_INVALID_ATTR		= 0x01,
+	UIC_CMD_RESULT_FAILURE			= 0x01,
+	UIC_CMD_RESULT_INVALID_ATTR_VALUE	= 0x02,
+	UIC_CMD_RESULT_READ_ONLY_ATTR		= 0x03,
+	UIC_CMD_RESULT_WRITE_ONLY_ATTR		= 0x04,
+	UIC_CMD_RESULT_BAD_INDEX		= 0x05,
+	UIC_CMD_RESULT_LOCKED_ATTR		= 0x06,
+	UIC_CMD_RESULT_BAD_TEST_FEATURE_INDEX	= 0x07,
+	UIC_CMD_RESULT_PEER_COMM_FAILURE	= 0x08,
+	UIC_CMD_RESULT_BUSY			= 0x09,
+	UIC_CMD_RESULT_DME_FAILURE		= 0x0A,
+};
+
+#define MASK_UIC_COMMAND_RESULT			0xFF
+
+/* Host <-> Device UniPro Link state */
+enum uic_link_state {
+	UIC_LINK_OFF_STATE	= 0, /* Link powered down or disabled */
+	UIC_LINK_ACTIVE_STATE	= 1, /* Link is in Fast/Slow/Sleep state */
+	UIC_LINK_HIBERN8_STATE	= 2, /* Link is in Hibernate state */
+};
+
+/* UIC command interfaces for DME primitives */
+#define DME_LOCAL	0
+#define DME_PEER	1
+#define ATTR_SET_NOR	0	/* NORMAL */
+#define ATTR_SET_ST	1	/* STATIC */
+
+int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
+			u8 attr_set, u32 mib_val, u8 peer);
+int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
+			u32 *mib_val, u8 peer);
+
+static inline int ufshcd_dme_set(struct ufs_hba *hba, u32 attr_sel,
+				 u32 mib_val)
+{
+	return ufshcd_dme_set_attr(hba, attr_sel, ATTR_SET_NOR,
+				   mib_val, DME_LOCAL);
+}
+
+static inline int ufshcd_dme_get(struct ufs_hba *hba,
+				 u32 attr_sel, u32 *mib_val)
+{
+	return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_LOCAL);
+}
+
+static inline int ufshcd_dme_peer_get(struct ufs_hba *hba,
+				      u32 attr_sel, u32 *mib_val)
+{
+	return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_PEER);
+}
+
+static inline int ufshcd_dme_peer_set(struct ufs_hba *hba, u32 attr_sel,
+				      u32 mib_val)
+{
+	return ufshcd_dme_set_attr(hba, attr_sel, ATTR_SET_NOR,
+				   mib_val, DME_PEER);
+}
+
+/**
+ * struct ufs_query_req - parameters for building a query request
+ * @query_func: UPIU header query function
+ * @upiu_req: the query request data
+ */
+struct ufs_query_req {
+	u8 query_func;
+	struct utp_upiu_query upiu_req;
+};
+
+/**
+ * struct ufs_query_resp - UPIU QUERY
+ * @response: device response code
+ * @upiu_res: query response data
+ */
+struct ufs_query_res {
+	u8 response;
+	struct utp_upiu_query upiu_res;
+};
+
+/**
+ * struct ufs_query - holds relevant data structures for query request
+ * @request: request upiu and function
+ * @descriptor: buffer for sending/receiving descriptor
+ * @response: response upiu and response
+ */
+struct ufs_query {
+	struct ufs_query_req request;
+	u8 *descriptor;
+	struct ufs_query_res response;
+};
+
+/**
+ * struct ufs_dev_cmd - all assosiated fields with device management commands
+ * @type: device management command type - Query, NOP OUT
+ * @tag_wq: wait queue until free command slot is available
+ */
+struct ufs_dev_cmd {
+	enum dev_cmd_type type;
+	struct ufs_query query;
+};
+
+struct ufs_hba_ops {
+	int (*init)(struct ufs_hba *hba);
+	int (*hce_enable_notify)(struct ufs_hba *hba,
+				 enum ufs_notify_change_status);
+	int (*link_startup_notify)(struct ufs_hba *hba,
+				   enum ufs_notify_change_status);
+	int (*phy_initialization)(struct ufs_hba *hba);
+};
+
+struct ufs_hba {
+	struct			udevice *dev;
+	void __iomem		*mmio_base;
+	struct ufs_hba_ops	*ops;
+	struct ufs_desc_size	desc_size;
+	u32			capabilities;
+	u32			version;
+	u32			intr_mask;
+	u32			quirks;
+/*
+ * If UFS host controller is having issue in processing LCC (Line
+ * Control Command) coming from device then enable this quirk.
+ * When this quirk is enabled, host controller driver should disable
+ * the LCC transmission on UFS device (by clearing TX_LCC_ENABLE
+ * attribute of device to 0).
+ */
+#define UFSHCD_QUIRK_BROKEN_LCC				0x1
+
+	/* Virtual memory reference */
+	struct utp_transfer_cmd_desc *ucdl;
+	struct utp_transfer_req_desc *utrdl;
+	/* TODO: Add Task Manegement Support */
+	struct utp_task_req_desc *utmrdl;
+
+	struct utp_upiu_req *ucd_req_ptr;
+	struct utp_upiu_rsp *ucd_rsp_ptr;
+	struct ufshcd_sg_entry *ucd_prdt_ptr;
+
+	/* Power Mode information */
+	enum ufs_dev_pwr_mode curr_dev_pwr_mode;
+	struct ufs_pa_layer_attr pwr_info;
+	struct ufs_pwr_mode_info max_pwr_info;
+
+	struct ufs_dev_cmd dev_cmd;
+};
+
+static inline int ufshcd_ops_init(struct ufs_hba *hba)
+{
+	if (hba->ops && hba->ops->init)
+		return hba->ops->init(hba);
+
+	return 0;
+}
+
+static inline int ufshcd_ops_hce_enable_notify(struct ufs_hba *hba,
+						bool status)
+{
+	if (hba->ops && hba->ops->hce_enable_notify)
+		return hba->ops->hce_enable_notify(hba, status);
+
+	return 0;
+}
+
+static inline int ufshcd_ops_link_startup_notify(struct ufs_hba *hba,
+						 bool status)
+{
+	if (hba->ops && hba->ops->link_startup_notify)
+		return hba->ops->link_startup_notify(hba, status);
+
+	return 0;
+}
+
+/* Controller UFSHCI version */
+enum {
+	UFSHCI_VERSION_10 = 0x00010000, /* 1.0 */
+	UFSHCI_VERSION_11 = 0x00010100, /* 1.1 */
+	UFSHCI_VERSION_20 = 0x00000200, /* 2.0 */
+	UFSHCI_VERSION_21 = 0x00000210, /* 2.1 */
+};
+
+/* Interrupt disable masks */
+enum {
+	/* Interrupt disable mask for UFSHCI v1.0 */
+	INTERRUPT_MASK_ALL_VER_10	= 0x30FFF,
+	INTERRUPT_MASK_RW_VER_10	= 0x30000,
+
+	/* Interrupt disable mask for UFSHCI v1.1 */
+	INTERRUPT_MASK_ALL_VER_11	= 0x31FFF,
+
+	/* Interrupt disable mask for UFSHCI v2.1 */
+	INTERRUPT_MASK_ALL_VER_21	= 0x71FFF,
+};
+
+/* UFSHCI Registers */
+enum {
+	REG_CONTROLLER_CAPABILITIES		= 0x00,
+	REG_UFS_VERSION				= 0x08,
+	REG_CONTROLLER_DEV_ID			= 0x10,
+	REG_CONTROLLER_PROD_ID			= 0x14,
+	REG_AUTO_HIBERNATE_IDLE_TIMER		= 0x18,
+	REG_INTERRUPT_STATUS			= 0x20,
+	REG_INTERRUPT_ENABLE			= 0x24,
+	REG_CONTROLLER_STATUS			= 0x30,
+	REG_CONTROLLER_ENABLE			= 0x34,
+	REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER	= 0x38,
+	REG_UIC_ERROR_CODE_DATA_LINK_LAYER	= 0x3C,
+	REG_UIC_ERROR_CODE_NETWORK_LAYER	= 0x40,
+	REG_UIC_ERROR_CODE_TRANSPORT_LAYER	= 0x44,
+	REG_UIC_ERROR_CODE_DME			= 0x48,
+	REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL	= 0x4C,
+	REG_UTP_TRANSFER_REQ_LIST_BASE_L	= 0x50,
+	REG_UTP_TRANSFER_REQ_LIST_BASE_H	= 0x54,
+	REG_UTP_TRANSFER_REQ_DOOR_BELL		= 0x58,
+	REG_UTP_TRANSFER_REQ_LIST_CLEAR		= 0x5C,
+	REG_UTP_TRANSFER_REQ_LIST_RUN_STOP	= 0x60,
+	REG_UTP_TASK_REQ_LIST_BASE_L		= 0x70,
+	REG_UTP_TASK_REQ_LIST_BASE_H		= 0x74,
+	REG_UTP_TASK_REQ_DOOR_BELL		= 0x78,
+	REG_UTP_TASK_REQ_LIST_CLEAR		= 0x7C,
+	REG_UTP_TASK_REQ_LIST_RUN_STOP		= 0x80,
+	REG_UIC_COMMAND				= 0x90,
+	REG_UIC_COMMAND_ARG_1			= 0x94,
+	REG_UIC_COMMAND_ARG_2			= 0x98,
+	REG_UIC_COMMAND_ARG_3			= 0x9C,
+
+	UFSHCI_REG_SPACE_SIZE			= 0xA0,
+
+	REG_UFS_CCAP				= 0x100,
+	REG_UFS_CRYPTOCAP			= 0x104,
+
+	UFSHCI_CRYPTO_REG_SPACE_SIZE		= 0x400,
+};
+
+/* Controller capability masks */
+enum {
+	MASK_TRANSFER_REQUESTS_SLOTS		= 0x0000001F,
+	MASK_TASK_MANAGEMENT_REQUEST_SLOTS	= 0x00070000,
+	MASK_AUTO_HIBERN8_SUPPORT		= 0x00800000,
+	MASK_64_ADDRESSING_SUPPORT		= 0x01000000,
+	MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT	= 0x02000000,
+	MASK_UIC_DME_TEST_MODE_SUPPORT		= 0x04000000,
+};
+
+/* Interrupt Status 20h */
+#define UTP_TRANSFER_REQ_COMPL			0x1
+#define UIC_DME_END_PT_RESET			0x2
+#define UIC_ERROR				0x4
+#define UIC_TEST_MODE				0x8
+#define UIC_POWER_MODE				0x10
+#define UIC_HIBERNATE_EXIT			0x20
+#define UIC_HIBERNATE_ENTER			0x40
+#define UIC_LINK_LOST				0x80
+#define UIC_LINK_STARTUP			0x100
+#define UTP_TASK_REQ_COMPL			0x200
+#define UIC_COMMAND_COMPL			0x400
+#define DEVICE_FATAL_ERROR			0x800
+#define CONTROLLER_FATAL_ERROR			0x10000
+#define SYSTEM_BUS_FATAL_ERROR			0x20000
+
+#define UFSHCD_UIC_PWR_MASK	(UIC_HIBERNATE_ENTER |\
+				UIC_HIBERNATE_EXIT |\
+				UIC_POWER_MODE)
+
+#define UFSHCD_UIC_MASK		(UIC_COMMAND_COMPL | UIC_POWER_MODE)
+
+#define UFSHCD_ERROR_MASK	(UIC_ERROR |\
+				DEVICE_FATAL_ERROR |\
+				CONTROLLER_FATAL_ERROR |\
+				SYSTEM_BUS_FATAL_ERROR)
+
+#define INT_FATAL_ERRORS	(DEVICE_FATAL_ERROR |\
+				CONTROLLER_FATAL_ERROR |\
+				SYSTEM_BUS_FATAL_ERROR)
+
+/* Host Controller Enable 0x34h */
+#define CONTROLLER_ENABLE	0x1
+#define CONTROLLER_DISABLE	0x0
+/* HCS - Host Controller Status 30h */
+#define DEVICE_PRESENT				0x1
+#define UTP_TRANSFER_REQ_LIST_READY		0x2
+#define UTP_TASK_REQ_LIST_READY			0x4
+#define UIC_COMMAND_READY			0x8
+#define HOST_ERROR_INDICATOR			0x10
+#define DEVICE_ERROR_INDICATOR			0x20
+#define UIC_POWER_MODE_CHANGE_REQ_STATUS_MASK	UFS_MASK(0x7, 8)
+
+#define UFSHCD_STATUS_READY	(UTP_TRANSFER_REQ_LIST_READY |\
+				UTP_TASK_REQ_LIST_READY |\
+				UIC_COMMAND_READY)
+
+enum {
+	PWR_OK		= 0x0,
+	PWR_LOCAL	= 0x01,
+	PWR_REMOTE	= 0x02,
+	PWR_BUSY	= 0x03,
+	PWR_ERROR_CAP	= 0x04,
+	PWR_FATAL_ERROR	= 0x05,
+};
+
+/* UICCMD - UIC Command */
+#define COMMAND_OPCODE_MASK		0xFF
+#define GEN_SELECTOR_INDEX_MASK		0xFFFF
+
+#define MIB_ATTRIBUTE_MASK		UFS_MASK(0xFFFF, 16)
+#define RESET_LEVEL			0xFF
+
+#define ATTR_SET_TYPE_MASK		UFS_MASK(0xFF, 16)
+#define CONFIG_RESULT_CODE_MASK		0xFF
+#define GENERIC_ERROR_CODE_MASK		0xFF
+
+#define ufshcd_writel(hba, val, reg)   \
+	writel((val), (hba)->mmio_base + (reg))
+#define ufshcd_readl(hba, reg) \
+	readl((hba)->mmio_base + (reg))
+
+/* UTRLRSR - UTP Transfer Request Run-Stop Register 60h */
+#define UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT	0x1
+
+/* UTMRLRSR - UTP Task Management Request Run-Stop Register 80h */
+#define UTP_TASK_REQ_LIST_RUN_STOP_BIT		0x1
+
+int ufshcd_probe(struct udevice *dev, struct ufs_hba_ops *hba_ops);
+
+#endif
diff --git a/drivers/ufs/unipro.h b/drivers/ufs/unipro.h
new file mode 100644
index 0000000000..b30b17fa5a
--- /dev/null
+++ b/drivers/ufs/unipro.h
@@ -0,0 +1,270 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#ifndef _UNIPRO_H_
+#define _UNIPRO_H_
+
+/*
+ * M-TX Configuration Attributes
+ */
+#define TX_HIBERN8TIME_CAPABILITY		0x000F
+#define TX_MODE					0x0021
+#define TX_HSRATE_SERIES			0x0022
+#define TX_HSGEAR				0x0023
+#define TX_PWMGEAR				0x0024
+#define TX_AMPLITUDE				0x0025
+#define TX_HS_SLEWRATE				0x0026
+#define TX_SYNC_SOURCE				0x0027
+#define TX_HS_SYNC_LENGTH			0x0028
+#define TX_HS_PREPARE_LENGTH			0x0029
+#define TX_LS_PREPARE_LENGTH			0x002A
+#define TX_HIBERN8_CONTROL			0x002B
+#define TX_LCC_ENABLE				0x002C
+#define TX_PWM_BURST_CLOSURE_EXTENSION		0x002D
+#define TX_BYPASS_8B10B_ENABLE			0x002E
+#define TX_DRIVER_POLARITY			0x002F
+#define TX_HS_UNTERMINATED_LINE_DRIVE_ENABLE	0x0030
+#define TX_LS_TERMINATED_LINE_DRIVE_ENABLE	0x0031
+#define TX_LCC_SEQUENCER			0x0032
+#define TX_MIN_ACTIVATETIME			0x0033
+#define TX_PWM_G6_G7_SYNC_LENGTH		0x0034
+#define TX_REFCLKFREQ				0x00EB
+#define TX_CFGCLKFREQVAL			0x00EC
+#define	CFGEXTRATTR				0x00F0
+#define DITHERCTRL2				0x00F1
+
+/*
+ * M-RX Configuration Attributes
+ */
+#define RX_MODE					0x00A1
+#define RX_HSRATE_SERIES			0x00A2
+#define RX_HSGEAR				0x00A3
+#define RX_PWMGEAR				0x00A4
+#define RX_LS_TERMINATED_ENABLE			0x00A5
+#define RX_HS_UNTERMINATED_ENABLE		0x00A6
+#define RX_ENTER_HIBERN8			0x00A7
+#define RX_BYPASS_8B10B_ENABLE			0x00A8
+#define RX_TERMINATION_FORCE_ENABLE		0x0089
+#define RX_MIN_ACTIVATETIME_CAPABILITY		0x008F
+#define RX_HIBERN8TIME_CAPABILITY		0x0092
+#define RX_REFCLKFREQ				0x00EB
+#define	RX_CFGCLKFREQVAL			0x00EC
+#define CFGWIDEINLN				0x00F0
+#define CFGRXCDR8				0x00BA
+#define ENARXDIRECTCFG4				0x00F2
+#define CFGRXOVR8				0x00BD
+#define RXDIRECTCTRL2				0x00C7
+#define ENARXDIRECTCFG3				0x00F3
+#define RXCALCTRL				0x00B4
+#define ENARXDIRECTCFG2				0x00F4
+#define CFGRXOVR4				0x00E9
+#define RXSQCTRL				0x00B5
+#define CFGRXOVR6				0x00BF
+
+#define is_mphy_tx_attr(attr)			(attr < RX_MODE)
+#define RX_MIN_ACTIVATETIME_UNIT_US		100
+#define HIBERN8TIME_UNIT_US			100
+
+/*
+ * Common Block Attributes
+ */
+#define TX_GLOBALHIBERNATE			UNIPRO_CB_OFFSET(0x002B)
+#define REFCLKMODE				UNIPRO_CB_OFFSET(0x00BF)
+#define DIRECTCTRL19				UNIPRO_CB_OFFSET(0x00CD)
+#define DIRECTCTRL10				UNIPRO_CB_OFFSET(0x00E6)
+#define CDIRECTCTRL6				UNIPRO_CB_OFFSET(0x00EA)
+#define RTOBSERVESELECT				UNIPRO_CB_OFFSET(0x00F0)
+#define CBDIVFACTOR				UNIPRO_CB_OFFSET(0x00F1)
+#define CBDCOCTRL5				UNIPRO_CB_OFFSET(0x00F3)
+#define CBPRGPLL2				UNIPRO_CB_OFFSET(0x00F8)
+#define CBPRGTUNING				UNIPRO_CB_OFFSET(0x00FB)
+
+#define UNIPRO_CB_OFFSET(x)			(0x8000 | x)
+
+/*
+ * PHY Adpater attributes
+ */
+#define PA_ACTIVETXDATALANES	0x1560
+#define PA_ACTIVERXDATALANES	0x1580
+#define PA_TXTRAILINGCLOCKS	0x1564
+#define PA_PHY_TYPE		0x1500
+#define PA_AVAILTXDATALANES	0x1520
+#define PA_AVAILRXDATALANES	0x1540
+#define PA_MINRXTRAILINGCLOCKS	0x1543
+#define PA_TXPWRSTATUS		0x1567
+#define PA_RXPWRSTATUS		0x1582
+#define PA_TXFORCECLOCK		0x1562
+#define PA_TXPWRMODE		0x1563
+#define PA_LEGACYDPHYESCDL	0x1570
+#define PA_MAXTXSPEEDFAST	0x1521
+#define PA_MAXTXSPEEDSLOW	0x1522
+#define PA_MAXRXSPEEDFAST	0x1541
+#define PA_MAXRXSPEEDSLOW	0x1542
+#define PA_TXLINKSTARTUPHS	0x1544
+#define PA_LOCAL_TX_LCC_ENABLE	0x155E
+#define PA_TXSPEEDFAST		0x1565
+#define PA_TXSPEEDSLOW		0x1566
+#define PA_REMOTEVERINFO	0x15A0
+#define PA_TXGEAR		0x1568
+#define PA_TXTERMINATION	0x1569
+#define PA_HSSERIES		0x156A
+#define PA_PWRMODE		0x1571
+#define PA_RXGEAR		0x1583
+#define PA_RXTERMINATION	0x1584
+#define PA_MAXRXPWMGEAR		0x1586
+#define PA_MAXRXHSGEAR		0x1587
+#define PA_RXHSUNTERMCAP	0x15A5
+#define PA_RXLSTERMCAP		0x15A6
+#define PA_GRANULARITY		0x15AA
+#define PA_PACPREQTIMEOUT	0x1590
+#define PA_PACPREQEOBTIMEOUT	0x1591
+#define PA_HIBERN8TIME		0x15A7
+#define PA_LOCALVERINFO		0x15A9
+#define PA_TACTIVATE		0x15A8
+#define PA_PACPFRAMECOUNT	0x15C0
+#define PA_PACPERRORCOUNT	0x15C1
+#define PA_PHYTESTCONTROL	0x15C2
+#define PA_PWRMODEUSERDATA0	0x15B0
+#define PA_PWRMODEUSERDATA1	0x15B1
+#define PA_PWRMODEUSERDATA2	0x15B2
+#define PA_PWRMODEUSERDATA3	0x15B3
+#define PA_PWRMODEUSERDATA4	0x15B4
+#define PA_PWRMODEUSERDATA5	0x15B5
+#define PA_PWRMODEUSERDATA6	0x15B6
+#define PA_PWRMODEUSERDATA7	0x15B7
+#define PA_PWRMODEUSERDATA8	0x15B8
+#define PA_PWRMODEUSERDATA9	0x15B9
+#define PA_PWRMODEUSERDATA10	0x15BA
+#define PA_PWRMODEUSERDATA11	0x15BB
+#define PA_CONNECTEDTXDATALANES	0x1561
+#define PA_CONNECTEDRXDATALANES	0x1581
+#define PA_LOGICALLANEMAP	0x15A1
+#define PA_SLEEPNOCONFIGTIME	0x15A2
+#define PA_STALLNOCONFIGTIME	0x15A3
+#define PA_SAVECONFIGTIME	0x15A4
+
+#define PA_TACTIVATE_TIME_UNIT_US	10
+#define PA_HIBERN8_TIME_UNIT_US		100
+
+/*Other attributes*/
+#define VS_MPHYCFGUPDT		0xD085
+#define VS_DEBUGOMC		0xD09E
+#define VS_POWERSTATE		0xD083
+
+#define PA_GRANULARITY_MIN_VAL	1
+#define PA_GRANULARITY_MAX_VAL	6
+
+/* PHY Adapter Protocol Constants */
+#define PA_MAXDATALANES	4
+
+/* PA power modes */
+enum {
+	FAST_MODE	= 1,
+	SLOW_MODE	= 2,
+	FASTAUTO_MODE	= 4,
+	SLOWAUTO_MODE	= 5,
+	UNCHANGED	= 7,
+};
+
+/* PA TX/RX Frequency Series */
+enum {
+	PA_HS_MODE_A	= 1,
+	PA_HS_MODE_B	= 2,
+};
+
+enum ufs_pwm_gear_tag {
+	UFS_PWM_DONT_CHANGE,	/* Don't change Gear */
+	UFS_PWM_G1,		/* PWM Gear 1 (default for reset) */
+	UFS_PWM_G2,		/* PWM Gear 2 */
+	UFS_PWM_G3,		/* PWM Gear 3 */
+	UFS_PWM_G4,		/* PWM Gear 4 */
+	UFS_PWM_G5,		/* PWM Gear 5 */
+	UFS_PWM_G6,		/* PWM Gear 6 */
+	UFS_PWM_G7,		/* PWM Gear 7 */
+};
+
+enum ufs_hs_gear_tag {
+	UFS_HS_DONT_CHANGE,	/* Don't change Gear */
+	UFS_HS_G1,		/* HS Gear 1 (default for reset) */
+	UFS_HS_G2,		/* HS Gear 2 */
+	UFS_HS_G3,		/* HS Gear 3 */
+};
+
+enum ufs_unipro_ver {
+	UFS_UNIPRO_VER_RESERVED = 0,
+	UFS_UNIPRO_VER_1_40 = 1, /* UniPro version 1.40 */
+	UFS_UNIPRO_VER_1_41 = 2, /* UniPro version 1.41 */
+	UFS_UNIPRO_VER_1_6 = 3,  /* UniPro version 1.6 */
+	UFS_UNIPRO_VER_MAX = 4,  /* UniPro unsupported version */
+	/* UniPro version field mask in PA_LOCALVERINFO */
+	UFS_UNIPRO_VER_MASK = 0xF,
+};
+
+/*
+ * Data Link Layer Attributes
+ */
+#define DL_TC0TXFCTHRESHOLD	0x2040
+#define DL_FC0PROTTIMEOUTVAL	0x2041
+#define DL_TC0REPLAYTIMEOUTVAL	0x2042
+#define DL_AFC0REQTIMEOUTVAL	0x2043
+#define DL_AFC0CREDITTHRESHOLD	0x2044
+#define DL_TC0OUTACKTHRESHOLD	0x2045
+#define DL_TC1TXFCTHRESHOLD	0x2060
+#define DL_FC1PROTTIMEOUTVAL	0x2061
+#define DL_TC1REPLAYTIMEOUTVAL	0x2062
+#define DL_AFC1REQTIMEOUTVAL	0x2063
+#define DL_AFC1CREDITTHRESHOLD	0x2064
+#define DL_TC1OUTACKTHRESHOLD	0x2065
+#define DL_TXPREEMPTIONCAP	0x2000
+#define DL_TC0TXMAXSDUSIZE	0x2001
+#define DL_TC0RXINITCREDITVAL	0x2002
+#define DL_TC0TXBUFFERSIZE	0x2005
+#define DL_PEERTC0PRESENT	0x2046
+#define DL_PEERTC0RXINITCREVAL	0x2047
+#define DL_TC1TXMAXSDUSIZE	0x2003
+#define DL_TC1RXINITCREDITVAL	0x2004
+#define DL_TC1TXBUFFERSIZE	0x2006
+#define DL_PEERTC1PRESENT	0x2066
+#define DL_PEERTC1RXINITCREVAL	0x2067
+
+/*
+ * Network Layer Attributes
+ */
+#define N_DEVICEID		0x3000
+#define N_DEVICEID_VALID	0x3001
+#define N_TC0TXMAXSDUSIZE	0x3020
+#define N_TC1TXMAXSDUSIZE	0x3021
+
+/*
+ * Transport Layer Attributes
+ */
+#define T_NUMCPORTS		0x4000
+#define T_NUMTESTFEATURES	0x4001
+#define T_CONNECTIONSTATE	0x4020
+#define T_PEERDEVICEID		0x4021
+#define T_PEERCPORTID		0x4022
+#define T_TRAFFICCLASS		0x4023
+#define T_PROTOCOLID		0x4024
+#define T_CPORTFLAGS		0x4025
+#define T_TXTOKENVALUE		0x4026
+#define T_RXTOKENVALUE		0x4027
+#define T_LOCALBUFFERSPACE	0x4028
+#define T_PEERBUFFERSPACE	0x4029
+#define T_CREDITSTOSEND		0x402A
+#define T_CPORTMODE		0x402B
+#define T_TC0TXMAXSDUSIZE	0x4060
+#define T_TC1TXMAXSDUSIZE	0x4061
+
+#ifdef FALSE
+#undef FALSE
+#endif
+
+#ifdef TRUE
+#undef TRUE
+#endif
+
+/* Boolean attribute values */
+enum {
+	FALSE = 0,
+	TRUE,
+};
+
+#endif /* _UNIPRO_H_ */
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 09e0ad5391..a606b8c41b 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -96,6 +96,7 @@ enum uclass_id {
 	UCLASS_THERMAL,		/* Thermal sensor */
 	UCLASS_TIMER,		/* Timer device */
 	UCLASS_TPM,		/* Trusted Platform Module TIS interface */
+	UCLASS_UFS,		/* Universale Flash Storage */
 	UCLASS_USB,		/* USB bus */
 	UCLASS_USB_DEV_GENERIC,	/* USB generic device */
 	UCLASS_USB_HUB,		/* USB hub */
diff --git a/include/ufs.h b/include/ufs.h
new file mode 100644
index 0000000000..2245838b3c
--- /dev/null
+++ b/include/ufs.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#ifndef _UFS_H
+#define _UFS_H
+
+int ufs_probe(void);
+int ufs_scsi_bind(struct udevice *scsi_dev, struct udevice **devp);
+#endif
-- 
2.19.2

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 06/10] ufs: Add Support for Cadence platform UFS driver
  2019-09-09  8:19 [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e Faiz Abbas
                   ` (4 preceding siblings ...)
  2019-09-09  8:19 ` [U-Boot] [PATCH 05/10] ufs: Add Initial Support for UFS subsystem Faiz Abbas
@ 2019-09-09  8:19 ` Faiz Abbas
  2019-09-09  8:19 ` [U-Boot] [PATCH 07/10] ufs: Add glue layer driver for TI J721E devices Faiz Abbas
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Faiz Abbas @ 2019-09-09  8:19 UTC (permalink / raw)
  To: u-boot

Add Support for the platform driver for the Cadence device present on
TI's J721e device.

Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
---
 drivers/ufs/Kconfig         |   8 +++
 drivers/ufs/Makefile        |   1 +
 drivers/ufs/cdns-platform.c | 122 ++++++++++++++++++++++++++++++++++++
 3 files changed, 131 insertions(+)
 create mode 100644 drivers/ufs/cdns-platform.c

diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig
index 538aad8cd9..a320b4561f 100644
--- a/drivers/ufs/Kconfig
+++ b/drivers/ufs/Kconfig
@@ -6,4 +6,12 @@ config UFS
 	help
 	  This selects support for Universal Flash Subsystem (UFS).
 	  Say Y here if you want UFS Support.
+
+config CADENCE_UFS
+	bool "Cadence platform driver for UFS"
+	depends on UFS
+        help
+	  This selects the platform driver for the Cadence UFS host
+	  controller present on present TI's J721e devices.
+
 endmenu
diff --git a/drivers/ufs/Makefile b/drivers/ufs/Makefile
index b8df759f66..9262bd6cd0 100644
--- a/drivers/ufs/Makefile
+++ b/drivers/ufs/Makefile
@@ -4,3 +4,4 @@
 #
 
 obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o
+obj-$(CONFIG_CADENCE_UFS) += cdns-platform.o
diff --git a/drivers/ufs/cdns-platform.c b/drivers/ufs/cdns-platform.c
new file mode 100644
index 0000000000..c80f4253e4
--- /dev/null
+++ b/drivers/ufs/cdns-platform.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0+
+/**
+ * cdns-platform.c - Platform driver for Cadence UFSHCI device
+ *
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <ufs.h>
+
+#include "ufs.h"
+
+#define USEC_PER_SEC	1000000L
+
+#define CDNS_UFS_REG_HCLKDIV	0xFC
+#define CDNS_UFS_REG_PHY_XCFGD1	0x113C
+
+static int cdns_ufs_link_startup_notify(struct ufs_hba *hba,
+					enum ufs_notify_change_status status)
+{
+	hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;
+	switch (status) {
+	case PRE_CHANGE:
+		return ufshcd_dme_set(hba,
+				      UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE),
+				      0);
+	case POST_CHANGE:
+	;
+	}
+
+	return 0;
+}
+
+static int cdns_ufs_set_hclkdiv(struct ufs_hba *hba)
+{
+	struct clk clk;
+	unsigned long core_clk_rate = 0;
+	u32 core_clk_div = 0;
+	int ret;
+
+	ret = clk_get_by_name(hba->dev, "core_clk", &clk);
+	if (ret) {
+		dev_err(hba->dev, "failed to get core_clk clock\n");
+		return ret;
+	}
+
+	core_clk_rate = clk_get_rate(&clk);
+	if (IS_ERR_VALUE(core_clk_rate)) {
+		dev_err(hba->dev, "%s: unable to find core_clk rate\n",
+			__func__);
+		return core_clk_rate;
+	}
+
+	core_clk_div = core_clk_rate / USEC_PER_SEC;
+	ufshcd_writel(hba, core_clk_div, CDNS_UFS_REG_HCLKDIV);
+
+	return 0;
+}
+
+static int cdns_ufs_hce_enable_notify(struct ufs_hba *hba,
+				      enum ufs_notify_change_status status)
+{
+	switch (status) {
+	case PRE_CHANGE:
+		return cdns_ufs_set_hclkdiv(hba);
+	case POST_CHANGE:
+	;
+	}
+
+	return 0;
+}
+
+static int cdns_ufs_init(struct ufs_hba *hba)
+{
+	u32 data;
+
+	/* Increase RX_Advanced_Min_ActivateTime_Capability */
+	data = ufshcd_readl(hba, CDNS_UFS_REG_PHY_XCFGD1);
+	data |= BIT(24);
+	ufshcd_writel(hba, data, CDNS_UFS_REG_PHY_XCFGD1);
+
+	return 0;
+}
+
+static struct ufs_hba_ops cdns_pltfm_hba_ops = {
+	.init = cdns_ufs_init,
+	.hce_enable_notify = cdns_ufs_hce_enable_notify,
+	.link_startup_notify = cdns_ufs_link_startup_notify,
+};
+
+static int cdns_ufs_pltfm_probe(struct udevice *dev)
+{
+	int err = ufshcd_probe(dev, &cdns_pltfm_hba_ops);
+	if (err)
+		dev_err(dev, "ufshcd_probe() failed %d\n", err);
+
+	return err;
+}
+
+static int cdns_ufs_pltfm_bind(struct udevice *dev)
+{
+	struct udevice *scsi_dev;
+
+	return ufs_scsi_bind(dev, &scsi_dev);
+}
+
+static const struct udevice_id cdns_ufs_pltfm_ids[] = {
+	{
+		.compatible = "cdns,ufshc-m31-16nm",
+	},
+	{},
+};
+
+U_BOOT_DRIVER(cdns_ufs_pltfm) = {
+	.name		= "cdns-ufs-pltfm",
+	.id		=  UCLASS_UFS,
+	.of_match	= cdns_ufs_pltfm_ids,
+	.probe		= cdns_ufs_pltfm_probe,
+	.bind		= cdns_ufs_pltfm_bind,
+};
-- 
2.19.2

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 07/10] ufs: Add glue layer driver for TI J721E devices
  2019-09-09  8:19 [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e Faiz Abbas
                   ` (5 preceding siblings ...)
  2019-09-09  8:19 ` [U-Boot] [PATCH 06/10] ufs: Add Support for Cadence platform UFS driver Faiz Abbas
@ 2019-09-09  8:19 ` Faiz Abbas
  2019-09-10  3:48   ` Vignesh Raghavendra
  2019-09-09  8:19 ` [U-Boot] [PATCH 08/10] arm: dts: k3-j721e-main: Add UFS nodes Faiz Abbas
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 20+ messages in thread
From: Faiz Abbas @ 2019-09-09  8:19 UTC (permalink / raw)
  To: u-boot

Add glue layer driver for the controller present on TI's J721E devices.

Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
---
 drivers/ufs/Kconfig        |  6 +++
 drivers/ufs/Makefile       |  1 +
 drivers/ufs/ti-j721e-ufs.c | 75 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+)
 create mode 100644 drivers/ufs/ti-j721e-ufs.c

diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig
index a320b4561f..4875e9448e 100644
--- a/drivers/ufs/Kconfig
+++ b/drivers/ufs/Kconfig
@@ -14,4 +14,10 @@ config CADENCE_UFS
 	  This selects the platform driver for the Cadence UFS host
 	  controller present on present TI's J721e devices.
 
+config TI_J721E_UFS
+	bool "Glue Layer driver for UFS on TI J721E devices"
+	help
+	  This selects the glue layer driver for Cadence controller
+	  present on TI's J721E devices.
+
 endmenu
diff --git a/drivers/ufs/Makefile b/drivers/ufs/Makefile
index 9262bd6cd0..62ed016608 100644
--- a/drivers/ufs/Makefile
+++ b/drivers/ufs/Makefile
@@ -5,3 +5,4 @@
 
 obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o
 obj-$(CONFIG_CADENCE_UFS) += cdns-platform.o
+obj-$(CONFIG_TI_J721E_UFS) += ti-j721e-ufs.o
diff --git a/drivers/ufs/ti-j721e-ufs.c b/drivers/ufs/ti-j721e-ufs.c
new file mode 100644
index 0000000000..249d3796c0
--- /dev/null
+++ b/drivers/ufs/ti-j721e-ufs.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm/device.h>
+#include <dm/read.h>
+#include <power-domain.h>
+#include <regmap.h>
+
+#define UFS_SS_CTRL             0x4
+#define UFS_SS_RST_N_PCS        BIT(0)
+#define UFS_SS_CLK_26MHZ        BIT(4)
+
+static int ti_j721e_ufs_probe(struct udevice *dev)
+{
+	struct power_domain ufs_pwrdmn;
+	struct regmap *map;
+	unsigned int clock;
+	struct clk clk;
+	u32 reg = 0;
+	int ret;
+
+	ret = power_domain_get(dev, &ufs_pwrdmn);
+	if (ret) {
+		dev_err(dev, "failed to get power domain %d\n", ret);
+		return ret;
+	}
+
+	ret = power_domain_on(&ufs_pwrdmn);
+	if (ret) {
+		dev_err(dev, "Power domain on failed\n");
+		return ret;
+	}
+
+	ret = regmap_init_mem(dev_ofnode(dev), &map);
+	if (ret)
+		return ret;
+
+	ret = clk_get_by_index(dev, 0, &clk);
+	if (ret) {
+		dev_err(dev, "failed to get M-PHY clock\n");
+		return ret;
+	}
+
+	clock = clk_get_rate(&clk);
+	if (IS_ERR_VALUE(clock)) {
+		dev_err(dev, "failed to get rate\n");
+		return ret;
+	}
+
+	if (clock == 26000000)
+		reg |= UFS_SS_CLK_26MHZ;
+	/* Take UFS slave device out of reset */
+	reg |= UFS_SS_RST_N_PCS;
+	regmap_write(map, UFS_SS_CTRL, reg);
+
+	return dm_scan_fdt_dev(dev);
+}
+
+static const struct udevice_id ti_j721e_ufs_ids[] = {
+	{
+		.compatible = "ti,j721e-ufs",
+	},
+	{},
+};
+
+U_BOOT_DRIVER(ti_j721e_ufs) = {
+	.name			= "ti-j721e-ufs",
+	.id			= UCLASS_UFS,
+	.of_match		= ti_j721e_ufs_ids,
+	.probe			= ti_j721e_ufs_probe,
+};
-- 
2.19.2

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 08/10] arm: dts: k3-j721e-main: Add UFS nodes
  2019-09-09  8:19 [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e Faiz Abbas
                   ` (6 preceding siblings ...)
  2019-09-09  8:19 ` [U-Boot] [PATCH 07/10] ufs: Add glue layer driver for TI J721E devices Faiz Abbas
@ 2019-09-09  8:19 ` Faiz Abbas
  2019-09-09  8:19 ` [U-Boot] [PATCH 09/10] cmd: Add Support for UFS commands Faiz Abbas
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Faiz Abbas @ 2019-09-09  8:19 UTC (permalink / raw)
  To: u-boot

Add TI UFS glue layer and Cadence UFS Host controller DT nodes.

Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
---
 arch/arm/dts/k3-j721e-main.dtsi | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/arch/arm/dts/k3-j721e-main.dtsi b/arch/arm/dts/k3-j721e-main.dtsi
index 3445784293..23a7cb9d3a 100644
--- a/arch/arm/dts/k3-j721e-main.dtsi
+++ b/arch/arm/dts/k3-j721e-main.dtsi
@@ -228,4 +228,29 @@
 		ti,trm-icp = <0x8>;
 		dma-coherent;
 	};
+
+	ufs_wrapper: ufs-wrapper at 4e80000 {
+		compatible = "ti,j721e-ufs";
+		reg = <0x0 0x4e80000 0x0 0x100>;
+		power-domains = <&k3_pds 277 TI_SCI_PD_EXCLUSIVE>;
+		clocks = <&k3_clks 277 1>;
+		assigned-clocks = <&k3_clks 277 1>;
+		assigned-clock-parents = <&k3_clks 277 4>;
+		ranges;
+		#address-cells = <2>;
+		#size-cells = <2>;
+
+		ufs at 4e84000 {
+			compatible = "cdns,ufshc-m31-16nm", "jedec,ufs-2.0";
+			reg = <0x0 0x4e84000 0x0 0x10000>;
+			interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+			power-domains = <&k3_pds 277 TI_SCI_PD_EXCLUSIVE>;
+			freq-table-hz = <0 0>, <0 0>;
+			clocks = <&k3_clks 277 0>, <&k3_clks 277 1>;
+			clock-names = "core_clk", "phy_clk";
+			assigned-clocks = <&k3_clks 277 1>;
+			assigned-clock-parents = <&k3_clks 277 4>;
+			dma-coherent;
+		};
+	};
 };
-- 
2.19.2

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 09/10] cmd: Add Support for UFS commands
  2019-09-09  8:19 [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e Faiz Abbas
                   ` (7 preceding siblings ...)
  2019-09-09  8:19 ` [U-Boot] [PATCH 08/10] arm: dts: k3-j721e-main: Add UFS nodes Faiz Abbas
@ 2019-09-09  8:19 ` Faiz Abbas
  2019-09-09  8:19 ` [U-Boot] [PATCH 10/10] configs: j721e_evm_a72: Enable configs for UFS Faiz Abbas
  2019-09-09 14:52 ` [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e Tom Rini
  10 siblings, 0 replies; 20+ messages in thread
From: Faiz Abbas @ 2019-09-09  8:19 UTC (permalink / raw)
  To: u-boot

Add Support for commands to initialize and configure UFS devices.

TODO: Add Support for commands to resize and reconfigure LUNs
Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
---
 cmd/Kconfig  |  7 +++++++
 cmd/Makefile |  2 +-
 cmd/ufs.c    | 28 ++++++++++++++++++++++++++++
 3 files changed, 36 insertions(+), 1 deletion(-)
 create mode 100644 cmd/ufs.c

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 0badcb3fe0..e0c78c6b52 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1070,6 +1070,13 @@ config CMD_TSI148
 	  This provides various sub-commands to initialise and configure the
 	  Turndra tsi148 device. See the command help for full details.
 
+config CMD_UFS
+	bool "Enable UFS - Universal Flash Subsystem commands"
+	depends on UFS
+	help
+	  "This provides commands to initialise and configure universal flash
+	   subsystem commands"
+
 config CMD_UNIVERSE
 	bool "universe - Command to set up the Turndra Universe controller"
 	help
diff --git a/cmd/Makefile b/cmd/Makefile
index f982564ab9..dc7869a35a 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -143,7 +143,7 @@ obj-$(CONFIG_CMD_UNZIP) += unzip.o
 obj-$(CONFIG_CMD_VIRTIO) += virtio.o
 obj-$(CONFIG_CMD_WDT) += wdt.o
 obj-$(CONFIG_CMD_LZMADEC) += lzmadec.o
-
+obj-$(CONFIG_CMD_UFS) += ufs.o
 obj-$(CONFIG_CMD_USB) += usb.o disk.o
 obj-$(CONFIG_CMD_FASTBOOT) += fastboot.o
 obj-$(CONFIG_CMD_FS_UUID) += fs_uuid.o
diff --git a/cmd/ufs.c b/cmd/ufs.c
new file mode 100644
index 0000000000..7e5bbf97d9
--- /dev/null
+++ b/cmd/ufs.c
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0+
+/**
+ * ufs.c - UFS specific U-boot commands
+ *
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
+ *
+ */
+#include <common.h>
+#include <command.h>
+#include <ufs.h>
+
+static int do_ufs(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	if (argc >= 2) {
+		if (!strcmp(argv[1], "init")) {
+			ufs_probe();
+
+			return CMD_RET_SUCCESS;
+		}
+	}
+
+	return CMD_RET_USAGE;
+}
+
+U_BOOT_CMD(ufs, 2, 1, do_ufs,
+	   "UFS  sub system",
+	   "init - init UFS subsystem\n"
+);
-- 
2.19.2

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 10/10] configs: j721e_evm_a72: Enable configs for UFS
  2019-09-09  8:19 [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e Faiz Abbas
                   ` (8 preceding siblings ...)
  2019-09-09  8:19 ` [U-Boot] [PATCH 09/10] cmd: Add Support for UFS commands Faiz Abbas
@ 2019-09-09  8:19 ` Faiz Abbas
  2019-09-09 14:52 ` [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e Tom Rini
  10 siblings, 0 replies; 20+ messages in thread
From: Faiz Abbas @ 2019-09-09  8:19 UTC (permalink / raw)
  To: u-boot

Enable SCSI and UFS related configs.

Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
---
 configs/j721e_evm_a72_defconfig | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/configs/j721e_evm_a72_defconfig b/configs/j721e_evm_a72_defconfig
index 237dc6b601..4c7d1173b4 100644
--- a/configs/j721e_evm_a72_defconfig
+++ b/configs/j721e_evm_a72_defconfig
@@ -36,11 +36,12 @@ CONFIG_CMD_ASKENV=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_SF=y
+CONFIG_CMD_UFS=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_CMD_EXT4_WRITE=y
 # CONFIG_ISO_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
+# CONFIG_SPL_PARTITION_UUIDS is not set
 CONFIG_OF_CONTROL=y
 CONFIG_SPL_OF_CONTROL=y
 CONFIG_DEFAULT_DEVICE_TREE="k3-j721e-common-proc-board"
@@ -76,6 +77,7 @@ CONFIG_TI_SCI_POWER_DOMAIN=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
 CONFIG_DM_RESET=y
 CONFIG_RESET_TI_SCI=y
+CONFIG_SCSI=y
 CONFIG_DM_SERIAL=y
 CONFIG_SPI=y
 CONFIG_DM_SPI=y
@@ -83,4 +85,7 @@ CONFIG_CADENCE_QSPI=y
 CONFIG_SYSRESET=y
 CONFIG_SPL_SYSRESET=y
 CONFIG_SYSRESET_TI_SCI=y
+CONFIG_UFS=y
+CONFIG_CADENCE_UFS=y
+CONFIG_TI_J721E_UFS=y
 CONFIG_OF_LIBFDT_OVERLAY=y
-- 
2.19.2

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e
  2019-09-09  8:19 [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e Faiz Abbas
                   ` (9 preceding siblings ...)
  2019-09-09  8:19 ` [U-Boot] [PATCH 10/10] configs: j721e_evm_a72: Enable configs for UFS Faiz Abbas
@ 2019-09-09 14:52 ` Tom Rini
  2019-09-09 14:57   ` Faiz Abbas
  10 siblings, 1 reply; 20+ messages in thread
From: Tom Rini @ 2019-09-09 14:52 UTC (permalink / raw)
  To: u-boot

On Mon, Sep 09, 2019 at 01:49:49PM +0530, Faiz Abbas wrote:
> The following patches add support for the Universal Flash Storage (UFS)
> subsystem and its implementation on TI's J721e platform.
> 
> The UFS Application Layer (UAP) uses SCSI SAM-4 command set for
> communication with the device. Therefore, the first 4 patches prepare
> the scsi layer for compatibility with UFS. Patch 9 also adds support for
> initializing and configuring the device from the U-boot command line.
> 
> The UFS Transport Protocol Layer (UTP) and UFS Interconnect Layer (UIC)
> are implemented with patch 5. This series only adds support for
> detect and read/write operations to the LUNs present in the remote
> device. Task Management operations and configuration of LUNs will be
> added in a future series.
> 
> Patches 6 through 10 add platform driver, device tree and config support
> for TI's J721E devices.
> 
> Log: https://pastebin.ubuntu.com/p/fTPZsxNjZM/
> 
> Tested on top of Lokesh's tree:
> https://github.com/lokeshvutla/u-boot
> Branch: j721e-full-boot
> 
> References:
> 
> [1] JESD220D UFS 3.0:
> 	https://www.jedec.org/standards-documents/docs/jesd220c
> [2] JESD223D UFS Host Controller Interface (UFSHCI) version 3.0:
> 	https://www.jedec.org/standards-documents/docs/jesd223c
> 
> Faiz Abbas (10):
>   scsi: Simplify scsi_read()/_write()
>   scsi: Add max_bytes to scsi_platdata
>   scsi: Retry inquiry 3 times to overcome Unit Attention condition
>   scsi: Add dma direction member to command structure
>   ufs: Add Initial Support for UFS subsystem
>   ufs: Add Support for Cadence platform UFS driver
>   ufs: Add glue layer driver for TI J721E devices
>   arm: dts: k3-j721e-main: Add UFS nodes
>   cmd: Add Support for UFS commands
>   configs: j721e_evm_a72: Enable configs for UFS
> 
>  arch/arm/dts/k3-j721e-main.dtsi |   25 +
>  cmd/Kconfig                     |    7 +
>  cmd/Makefile                    |    2 +-
>  cmd/ufs.c                       |   28 +
>  configs/j721e_evm_a72_defconfig |    7 +-
>  drivers/Kconfig                 |    2 +
>  drivers/Makefile                |    1 +
>  drivers/scsi/scsi.c             |   83 +-
>  drivers/ufs/Kconfig             |   23 +
>  drivers/ufs/Makefile            |    8 +
>  drivers/ufs/cdns-platform.c     |  122 ++
>  drivers/ufs/ti-j721e-ufs.c      |   75 ++
>  drivers/ufs/ufs-uclass.c        |   16 +
>  drivers/ufs/ufs.c               | 1973 +++++++++++++++++++++++++++++++
>  drivers/ufs/ufs.h               |  918 ++++++++++++++
>  drivers/ufs/unipro.h            |  270 +++++
>  include/dm/uclass-id.h          |    1 +
>  include/scsi.h                  |    4 +
>  include/ufs.h                   |    7 +
>  19 files changed, 3526 insertions(+), 46 deletions(-)
>  create mode 100644 cmd/ufs.c
>  create mode 100644 drivers/ufs/Kconfig
>  create mode 100644 drivers/ufs/Makefile
>  create mode 100644 drivers/ufs/cdns-platform.c
>  create mode 100644 drivers/ufs/ti-j721e-ufs.c
>  create mode 100644 drivers/ufs/ufs-uclass.c
>  create mode 100644 drivers/ufs/ufs.c
>  create mode 100644 drivers/ufs/ufs.h
>  create mode 100644 drivers/ufs/unipro.h
>  create mode 100644 include/ufs.h

I'm glad to see this support coming, it's something we need.  Would you
be willing to list yourself as the maintainer in the top-level
MAINTAINER file for drivers/ufs at least?  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20190909/85647c9d/attachment.sig>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e
  2019-09-09 14:52 ` [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e Tom Rini
@ 2019-09-09 14:57   ` Faiz Abbas
  2019-09-09 15:01     ` Tom Rini
  0 siblings, 1 reply; 20+ messages in thread
From: Faiz Abbas @ 2019-09-09 14:57 UTC (permalink / raw)
  To: u-boot

Hi Tom,

On 09/09/19 8:22 PM, Tom Rini wrote:
> On Mon, Sep 09, 2019 at 01:49:49PM +0530, Faiz Abbas wrote:
>> The following patches add support for the Universal Flash Storage (UFS)
>> subsystem and its implementation on TI's J721e platform.
>>
>> The UFS Application Layer (UAP) uses SCSI SAM-4 command set for
>> communication with the device. Therefore, the first 4 patches prepare
>> the scsi layer for compatibility with UFS. Patch 9 also adds support for
>> initializing and configuring the device from the U-boot command line.
>>
>> The UFS Transport Protocol Layer (UTP) and UFS Interconnect Layer (UIC)
>> are implemented with patch 5. This series only adds support for
>> detect and read/write operations to the LUNs present in the remote
>> device. Task Management operations and configuration of LUNs will be
>> added in a future series.
>>
>> Patches 6 through 10 add platform driver, device tree and config support
>> for TI's J721E devices.
>>
>> Log: https://pastebin.ubuntu.com/p/fTPZsxNjZM/
>>
>> Tested on top of Lokesh's tree:
>> https://github.com/lokeshvutla/u-boot
>> Branch: j721e-full-boot
>>
>> References:
>>
>> [1] JESD220D UFS 3.0:
>> 	https://www.jedec.org/standards-documents/docs/jesd220c
>> [2] JESD223D UFS Host Controller Interface (UFSHCI) version 3.0:
>> 	https://www.jedec.org/standards-documents/docs/jesd223c
>>
>> Faiz Abbas (10):
>>   scsi: Simplify scsi_read()/_write()
>>   scsi: Add max_bytes to scsi_platdata
>>   scsi: Retry inquiry 3 times to overcome Unit Attention condition
>>   scsi: Add dma direction member to command structure
>>   ufs: Add Initial Support for UFS subsystem
>>   ufs: Add Support for Cadence platform UFS driver
>>   ufs: Add glue layer driver for TI J721E devices
>>   arm: dts: k3-j721e-main: Add UFS nodes
>>   cmd: Add Support for UFS commands
>>   configs: j721e_evm_a72: Enable configs for UFS
>>
>>  arch/arm/dts/k3-j721e-main.dtsi |   25 +
>>  cmd/Kconfig                     |    7 +
>>  cmd/Makefile                    |    2 +-
>>  cmd/ufs.c                       |   28 +
>>  configs/j721e_evm_a72_defconfig |    7 +-
>>  drivers/Kconfig                 |    2 +
>>  drivers/Makefile                |    1 +
>>  drivers/scsi/scsi.c             |   83 +-
>>  drivers/ufs/Kconfig             |   23 +
>>  drivers/ufs/Makefile            |    8 +
>>  drivers/ufs/cdns-platform.c     |  122 ++
>>  drivers/ufs/ti-j721e-ufs.c      |   75 ++
>>  drivers/ufs/ufs-uclass.c        |   16 +
>>  drivers/ufs/ufs.c               | 1973 +++++++++++++++++++++++++++++++
>>  drivers/ufs/ufs.h               |  918 ++++++++++++++
>>  drivers/ufs/unipro.h            |  270 +++++
>>  include/dm/uclass-id.h          |    1 +
>>  include/scsi.h                  |    4 +
>>  include/ufs.h                   |    7 +
>>  19 files changed, 3526 insertions(+), 46 deletions(-)
>>  create mode 100644 cmd/ufs.c
>>  create mode 100644 drivers/ufs/Kconfig
>>  create mode 100644 drivers/ufs/Makefile
>>  create mode 100644 drivers/ufs/cdns-platform.c
>>  create mode 100644 drivers/ufs/ti-j721e-ufs.c
>>  create mode 100644 drivers/ufs/ufs-uclass.c
>>  create mode 100644 drivers/ufs/ufs.c
>>  create mode 100644 drivers/ufs/ufs.h
>>  create mode 100644 drivers/ufs/unipro.h
>>  create mode 100644 include/ufs.h
> 
> I'm glad to see this support coming, it's something we need.  Would you
> be willing to list yourself as the maintainer in the top-level
> MAINTAINER file for drivers/ufs at least?  Thanks!
> 

I did add to the MAINTAINER file in patch 5. Was that supposed to be a
separate patch?

Thanks,
Faiz

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e
  2019-09-09 14:57   ` Faiz Abbas
@ 2019-09-09 15:01     ` Tom Rini
  0 siblings, 0 replies; 20+ messages in thread
From: Tom Rini @ 2019-09-09 15:01 UTC (permalink / raw)
  To: u-boot

On Mon, Sep 09, 2019 at 08:27:23PM +0530, Faiz Abbas wrote:
> Hi Tom,
> 
> On 09/09/19 8:22 PM, Tom Rini wrote:
> > On Mon, Sep 09, 2019 at 01:49:49PM +0530, Faiz Abbas wrote:
> >> The following patches add support for the Universal Flash Storage (UFS)
> >> subsystem and its implementation on TI's J721e platform.
> >>
> >> The UFS Application Layer (UAP) uses SCSI SAM-4 command set for
> >> communication with the device. Therefore, the first 4 patches prepare
> >> the scsi layer for compatibility with UFS. Patch 9 also adds support for
> >> initializing and configuring the device from the U-boot command line.
> >>
> >> The UFS Transport Protocol Layer (UTP) and UFS Interconnect Layer (UIC)
> >> are implemented with patch 5. This series only adds support for
> >> detect and read/write operations to the LUNs present in the remote
> >> device. Task Management operations and configuration of LUNs will be
> >> added in a future series.
> >>
> >> Patches 6 through 10 add platform driver, device tree and config support
> >> for TI's J721E devices.
> >>
> >> Log: https://pastebin.ubuntu.com/p/fTPZsxNjZM/
> >>
> >> Tested on top of Lokesh's tree:
> >> https://github.com/lokeshvutla/u-boot
> >> Branch: j721e-full-boot
> >>
> >> References:
> >>
> >> [1] JESD220D UFS 3.0:
> >> 	https://www.jedec.org/standards-documents/docs/jesd220c
> >> [2] JESD223D UFS Host Controller Interface (UFSHCI) version 3.0:
> >> 	https://www.jedec.org/standards-documents/docs/jesd223c
> >>
> >> Faiz Abbas (10):
> >>   scsi: Simplify scsi_read()/_write()
> >>   scsi: Add max_bytes to scsi_platdata
> >>   scsi: Retry inquiry 3 times to overcome Unit Attention condition
> >>   scsi: Add dma direction member to command structure
> >>   ufs: Add Initial Support for UFS subsystem
> >>   ufs: Add Support for Cadence platform UFS driver
> >>   ufs: Add glue layer driver for TI J721E devices
> >>   arm: dts: k3-j721e-main: Add UFS nodes
> >>   cmd: Add Support for UFS commands
> >>   configs: j721e_evm_a72: Enable configs for UFS
> >>
> >>  arch/arm/dts/k3-j721e-main.dtsi |   25 +
> >>  cmd/Kconfig                     |    7 +
> >>  cmd/Makefile                    |    2 +-
> >>  cmd/ufs.c                       |   28 +
> >>  configs/j721e_evm_a72_defconfig |    7 +-
> >>  drivers/Kconfig                 |    2 +
> >>  drivers/Makefile                |    1 +
> >>  drivers/scsi/scsi.c             |   83 +-
> >>  drivers/ufs/Kconfig             |   23 +
> >>  drivers/ufs/Makefile            |    8 +
> >>  drivers/ufs/cdns-platform.c     |  122 ++
> >>  drivers/ufs/ti-j721e-ufs.c      |   75 ++
> >>  drivers/ufs/ufs-uclass.c        |   16 +
> >>  drivers/ufs/ufs.c               | 1973 +++++++++++++++++++++++++++++++
> >>  drivers/ufs/ufs.h               |  918 ++++++++++++++
> >>  drivers/ufs/unipro.h            |  270 +++++
> >>  include/dm/uclass-id.h          |    1 +
> >>  include/scsi.h                  |    4 +
> >>  include/ufs.h                   |    7 +
> >>  19 files changed, 3526 insertions(+), 46 deletions(-)
> >>  create mode 100644 cmd/ufs.c
> >>  create mode 100644 drivers/ufs/Kconfig
> >>  create mode 100644 drivers/ufs/Makefile
> >>  create mode 100644 drivers/ufs/cdns-platform.c
> >>  create mode 100644 drivers/ufs/ti-j721e-ufs.c
> >>  create mode 100644 drivers/ufs/ufs-uclass.c
> >>  create mode 100644 drivers/ufs/ufs.c
> >>  create mode 100644 drivers/ufs/ufs.h
> >>  create mode 100644 drivers/ufs/unipro.h
> >>  create mode 100644 include/ufs.h
> > 
> > I'm glad to see this support coming, it's something we need.  Would you
> > be willing to list yourself as the maintainer in the top-level
> > MAINTAINER file for drivers/ufs at least?  Thanks!
> > 
> 
> I did add to the MAINTAINER file in patch 5. Was that supposed to be a
> separate patch?

Ah, funny enough it's not in the diffstat here :)  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20190909/06a57da4/attachment.sig>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 02/10] scsi: Add max_bytes to scsi_platdata
  2019-09-09  8:19 ` [U-Boot] [PATCH 02/10] scsi: Add max_bytes to scsi_platdata Faiz Abbas
@ 2019-09-10  3:46   ` Vignesh Raghavendra
  2019-09-11  7:55     ` Faiz Abbas
  0 siblings, 1 reply; 20+ messages in thread
From: Vignesh Raghavendra @ 2019-09-10  3:46 UTC (permalink / raw)
  To: u-boot



On 09/09/19 1:49 PM, Faiz Abbas wrote:
> diff --git a/include/scsi.h b/include/scsi.h
> index 81ab43c842..076bdbc6a0 100644
> --- a/include/scsi.h
> +++ b/include/scsi.h
> @@ -168,6 +168,7 @@ struct scsi_platdata {
>  	unsigned long base;
>  	unsigned long max_lun;
>  	unsigned long max_id;
> +	unsigned long max_bytes;

Please add description of the new field. Also, could the name be bit
more specific like max_bytes_per_req?


-- 
Regards
Vignesh

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 05/10] ufs: Add Initial Support for UFS subsystem
  2019-09-09  8:19 ` [U-Boot] [PATCH 05/10] ufs: Add Initial Support for UFS subsystem Faiz Abbas
@ 2019-09-10  3:48   ` Vignesh Raghavendra
  2019-09-11  8:06     ` Faiz Abbas
  0 siblings, 1 reply; 20+ messages in thread
From: Vignesh Raghavendra @ 2019-09-10  3:48 UTC (permalink / raw)
  To: u-boot



On 09/09/19 1:49 PM, Faiz Abbas wrote:
> Add Support for UFS Host Controller Interface (UFSHCI) for communicating
> with Universal Flash Storage (UFS) devices. The steps to initialize the
> host controller interface are the following:
> 
> - Initiate the Host Controller Initialization process by writing to the
> Host controller enable register.
> - Configure the Host Controller base address registers by allocating a
> host memory space and related data structures.
> - Unipro link startup procedure
> - Check for connected device
> - Configure UFS host controller to process requests
> 

I am guessing code is derived from Linux kernel? Could you add kernel
version from which this code is borrowed from?

> Also register this host controller as a SCSI host controller.
> 
> Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
> ---
>  MAINTAINERS              |    5 +
>  drivers/Kconfig          |    2 +
>  drivers/Makefile         |    1 +
>  drivers/ufs/Kconfig      |    9 +
>  drivers/ufs/Makefile     |    6 +
>  drivers/ufs/ufs-uclass.c |   16 +
>  drivers/ufs/ufs.c        | 1973 ++++++++++++++++++++++++++++++++++++++
>  drivers/ufs/ufs.h        |  918 ++++++++++++++++++
>  drivers/ufs/unipro.h     |  270 ++++++

Should UFS reside under SCSI framework given that UFS follows SAM?
driver/scsi/ufs?

Regards
Vignesh

>  include/dm/uclass-id.h   |    1 +
>  include/ufs.h            |    7 +
>  11 files changed, 3208 insertions(+)
>  create mode 100644 drivers/ufs/Kconfig
>  create mode 100644 drivers/ufs/Makefile
>  create mode 100644 drivers/ufs/ufs-uclass.c
>  create mode 100644 drivers/ufs/ufs.c
>  create mode 100644 drivers/ufs/ufs.h
>  create mode 100644 drivers/ufs/unipro.h
>  create mode 100644 include/ufs.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 36625795a4..ed3a4c352c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -772,6 +772,11 @@ S:	Maintained
>  T:	git git://git.denx.de/u-boot-ubi.git
>  F:	drivers/mtd/ubi/
>  
> +UFS
> +M:	Faiz Abbas <faiz_abbas@ti.com>
> +S:	Maintained
> +F:	drivers/ufs/
> +
>  USB
>  M:	Marek Vasut <marex@denx.de>
>  S:	Maintained
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index 96ff4f566a..61bbe88d6c 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -118,6 +118,8 @@ source "drivers/tpm/Kconfig"
>  
>  source "drivers/usb/Kconfig"
>  
> +source "drivers/ufs/Kconfig"
> +
>  source "drivers/video/Kconfig"
>  
>  source "drivers/virtio/Kconfig"
> diff --git a/drivers/Makefile b/drivers/Makefile
> index 6635dabd2c..2794bef18a 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -111,6 +111,7 @@ obj-y += soc/
>  obj-y += thermal/
>  obj-$(CONFIG_TEE) += tee/
>  obj-y += axi/
> +obj-y += ufs/
>  obj-$(CONFIG_W1) += w1/
>  obj-$(CONFIG_W1_EEPROM) += w1-eeprom/
>  
> diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig
> new file mode 100644
> index 0000000000..538aad8cd9
> --- /dev/null
> +++ b/drivers/ufs/Kconfig
> @@ -0,0 +1,9 @@
> +menu "UFS Host Controller Support"
> +
> +config UFS
> +	bool "Support UFS controllers"
> +	select DM_SCSI

DM_SCSI has further dependencies, so its preferred not to use select

	depends on DM_SCSI

Also if this is moved under drivers/scsi/ then this Kconfig file can be
sourced conditionally

> +	help
> +	  This selects support for Universal Flash Subsystem (UFS).
> +	  Say Y here if you want UFS Support.
> +endmenu
> diff --git a/drivers/ufs/Makefile b/drivers/ufs/Makefile
> new file mode 100644
> index 0000000000..b8df759f66
> --- /dev/null
> +++ b/drivers/ufs/Makefile
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
> +#
> +
> +obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o
> diff --git a/drivers/ufs/ufs-uclass.c b/drivers/ufs/ufs-uclass.c
> new file mode 100644
> index 0000000000..920bfa64e1
> --- /dev/null
> +++ b/drivers/ufs/ufs-uclass.c
> @@ -0,0 +1,16 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/**
> + * ufs-uclass.c - Universal Flash Subsystem (UFS) Uclass driver
> + *
> + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
> + */
> +
> +#include <common.h>
> +#include "ufs.h"
> +#include <dm.h>
> +
> +UCLASS_DRIVER(ufs) = {
> +	.id	= UCLASS_UFS,
> +	.name	= "ufs",
> +	.per_device_auto_alloc_size = sizeof(struct ufs_hba),
> +};

[...]

> +#endif /* _UNIPRO_H_ */
> diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
> index 09e0ad5391..a606b8c41b 100644
> --- a/include/dm/uclass-id.h
> +++ b/include/dm/uclass-id.h
> @@ -96,6 +96,7 @@ enum uclass_id {
>  	UCLASS_THERMAL,		/* Thermal sensor */
>  	UCLASS_TIMER,		/* Timer device */
>  	UCLASS_TPM,		/* Trusted Platform Module TIS interface */
> +	UCLASS_UFS,		/* Universale Flash Storage */

s/Universale/Universal

>  	UCLASS_USB,		/* USB bus */
>  	UCLASS_USB_DEV_GENERIC,	/* USB generic device */
>  	UCLASS_USB_HUB,		/* USB hub */
> diff --git a/include/ufs.h b/include/ufs.h
> new file mode 100644
> index 0000000000..2245838b3c
> --- /dev/null
> +++ b/include/ufs.h
> @@ -0,0 +1,7 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +#ifndef _UFS_H
> +#define _UFS_H
> +
> +int ufs_probe(void);

This is fine, but you may want to provide helper to initialize a single
instance of controller so that we don't end up in a situation like MMC
where all the instances are initialized always.
Probably modify ufs_probe() to take an int arg that indicates instance
to be probed and -1 to probe all instances.
Irrespective of this, please add API documentation before the function
declaration

> +int ufs_scsi_bind(struct udevice *scsi_dev, struct udevice **devp);

Please document the API

> +#endif
> 

-- 
Regards
Vignesh

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 07/10] ufs: Add glue layer driver for TI J721E devices
  2019-09-09  8:19 ` [U-Boot] [PATCH 07/10] ufs: Add glue layer driver for TI J721E devices Faiz Abbas
@ 2019-09-10  3:48   ` Vignesh Raghavendra
  2019-09-11 13:45     ` Faiz Abbas
  0 siblings, 1 reply; 20+ messages in thread
From: Vignesh Raghavendra @ 2019-09-10  3:48 UTC (permalink / raw)
  To: u-boot



On 09/09/19 1:49 PM, Faiz Abbas wrote:
> Add glue layer driver for the controller present on TI's J721E devices.
> 
> Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
> ---
>  drivers/ufs/Kconfig        |  6 +++
>  drivers/ufs/Makefile       |  1 +
>  drivers/ufs/ti-j721e-ufs.c | 75 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 82 insertions(+)
>  create mode 100644 drivers/ufs/ti-j721e-ufs.c
> 
> diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig
> index a320b4561f..4875e9448e 100644
> --- a/drivers/ufs/Kconfig
> +++ b/drivers/ufs/Kconfig
> @@ -14,4 +14,10 @@ config CADENCE_UFS
>  	  This selects the platform driver for the Cadence UFS host
>  	  controller present on present TI's J721e devices.
>  
> +config TI_J721E_UFS
> +	bool "Glue Layer driver for UFS on TI J721E devices"
> +	help
> +	  This selects the glue layer driver for Cadence controller
> +	  present on TI's J721E devices.
> +
>  endmenu
> diff --git a/drivers/ufs/Makefile b/drivers/ufs/Makefile
> index 9262bd6cd0..62ed016608 100644
> --- a/drivers/ufs/Makefile
> +++ b/drivers/ufs/Makefile
> @@ -5,3 +5,4 @@
>  
>  obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o
>  obj-$(CONFIG_CADENCE_UFS) += cdns-platform.o
> +obj-$(CONFIG_TI_J721E_UFS) += ti-j721e-ufs.o
> diff --git a/drivers/ufs/ti-j721e-ufs.c b/drivers/ufs/ti-j721e-ufs.c
> new file mode 100644
> index 0000000000..249d3796c0
> --- /dev/null
> +++ b/drivers/ufs/ti-j721e-ufs.c
> @@ -0,0 +1,75 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
> + */
> +
> +#include <clk.h>
> +#include <common.h>
> +#include <dm/device.h>
> +#include <dm/read.h>

#include <dm.h>

should be sufficient instead of two includes.

> +#include <power-domain.h>
> +#include <regmap.h>
> +
> +#define UFS_SS_CTRL             0x4
> +#define UFS_SS_RST_N_PCS        BIT(0)
> +#define UFS_SS_CLK_26MHZ        BIT(4)
> +
> +static int ti_j721e_ufs_probe(struct udevice *dev)
> +{
> +	struct power_domain ufs_pwrdmn;
> +	struct regmap *map;
> +	unsigned int clock;
> +	struct clk clk;
> +	u32 reg = 0;
> +	int ret;
> +
> +	ret = power_domain_get(dev, &ufs_pwrdmn);
> +	if (ret) {
> +		dev_err(dev, "failed to get power domain %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = power_domain_on(&ufs_pwrdmn);
> +	if (ret) {
> +		dev_err(dev, "Power domain on failed\n");
> +		return ret;
> +	}

Core takes care of enabling power domain before calling probe. So this
can be dropped

> +
> +	ret = regmap_init_mem(dev_ofnode(dev), &map);
> +	if (ret)
> +		return ret;
> +


I think regmap is an overkill here.. We are just accessing a single
register and within dedicated wrapper space. Just use regular IO accessors.



> +	ret = clk_get_by_index(dev, 0, &clk);
> +	if (ret) {
> +		dev_err(dev, "failed to get M-PHY clock\n");
> +		return ret;
> +	}
> +
> +	clock = clk_get_rate(&clk);
> +	if (IS_ERR_VALUE(clock)) {
> +		dev_err(dev, "failed to get rate\n");
> +		return ret;
> +	}
> +
> +	if (clock == 26000000)
> +		reg |= UFS_SS_CLK_26MHZ;
> +	/* Take UFS slave device out of reset */
> +	reg |= UFS_SS_RST_N_PCS;
> +	regmap_write(map, UFS_SS_CTRL, reg);
> +

To be safe, put the slave back to reset before jumping to kernel so that
card does not see any glitches when kernel is doing any
re-initialization of clocks etc.
This can be done in driver remove callback (and needs DM_FLAG_OS_PREPARE
flag to be set in driver declaration)

> +	return dm_scan_fdt_dev(dev);
> +}
> +
> +static const struct udevice_id ti_j721e_ufs_ids[] = {
> +	{
> +		.compatible = "ti,j721e-ufs",
> +	},
> +	{},
> +};
> +
> +U_BOOT_DRIVER(ti_j721e_ufs) = {
> +	.name			= "ti-j721e-ufs",
> +	.id			= UCLASS_UFS,
> +	.of_match		= ti_j721e_ufs_ids,
> +	.probe			= ti_j721e_ufs_probe,
> +};
> 

-- 
Regards
Vignesh

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 02/10] scsi: Add max_bytes to scsi_platdata
  2019-09-10  3:46   ` Vignesh Raghavendra
@ 2019-09-11  7:55     ` Faiz Abbas
  0 siblings, 0 replies; 20+ messages in thread
From: Faiz Abbas @ 2019-09-11  7:55 UTC (permalink / raw)
  To: u-boot

Vignesh,

On 10/09/19 9:16 AM, Vignesh Raghavendra wrote:
> 
> 
> On 09/09/19 1:49 PM, Faiz Abbas wrote:
>> diff --git a/include/scsi.h b/include/scsi.h
>> index 81ab43c842..076bdbc6a0 100644
>> --- a/include/scsi.h
>> +++ b/include/scsi.h
>> @@ -168,6 +168,7 @@ struct scsi_platdata {
>>  	unsigned long base;
>>  	unsigned long max_lun;
>>  	unsigned long max_id;
>> +	unsigned long max_bytes;
> 
> Please add description of the new field. Also, could the name be bit
> more specific like max_bytes_per_req?
> 

Sounds good.

Thanks,
Faiz

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 05/10] ufs: Add Initial Support for UFS subsystem
  2019-09-10  3:48   ` Vignesh Raghavendra
@ 2019-09-11  8:06     ` Faiz Abbas
  0 siblings, 0 replies; 20+ messages in thread
From: Faiz Abbas @ 2019-09-11  8:06 UTC (permalink / raw)
  To: u-boot

Hi Vignesh,

On 10/09/19 9:18 AM, Vignesh Raghavendra wrote:
> 
> 
> On 09/09/19 1:49 PM, Faiz Abbas wrote:
>> Add Support for UFS Host Controller Interface (UFSHCI) for communicating
>> with Universal Flash Storage (UFS) devices. The steps to initialize the
>> host controller interface are the following:
>>
>> - Initiate the Host Controller Initialization process by writing to the
>> Host controller enable register.
>> - Configure the Host Controller base address registers by allocating a
>> host memory space and related data structures.
>> - Unipro link startup procedure
>> - Check for connected device
>> - Configure UFS host controller to process requests
>>
> 
> I am guessing code is derived from Linux kernel? Could you add kernel
> version from which this code is borrowed from?

I did write that in the ufs.c file description. Will also add it here.

> 
>> Also register this host controller as a SCSI host controller.
>>
>> Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
>> ---
>>  MAINTAINERS              |    5 +
>>  drivers/Kconfig          |    2 +
>>  drivers/Makefile         |    1 +
>>  drivers/ufs/Kconfig      |    9 +
>>  drivers/ufs/Makefile     |    6 +
>>  drivers/ufs/ufs-uclass.c |   16 +
>>  drivers/ufs/ufs.c        | 1973 ++++++++++++++++++++++++++++++++++++++
>>  drivers/ufs/ufs.h        |  918 ++++++++++++++++++
>>  drivers/ufs/unipro.h     |  270 ++++++
> 
> Should UFS reside under SCSI framework given that UFS follows SAM?
> driver/scsi/ufs?

Other scsi implementations (like ahci) have their own folders so I'm
just following that convention.

> 
> Regards
> Vignesh
> 
>>  include/dm/uclass-id.h   |    1 +
>>  include/ufs.h            |    7 +
>>  11 files changed, 3208 insertions(+)
>>  create mode 100644 drivers/ufs/Kconfig
>>  create mode 100644 drivers/ufs/Makefile
>>  create mode 100644 drivers/ufs/ufs-uclass.c
>>  create mode 100644 drivers/ufs/ufs.c
>>  create mode 100644 drivers/ufs/ufs.h
>>  create mode 100644 drivers/ufs/unipro.h
>>  create mode 100644 include/ufs.h
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 36625795a4..ed3a4c352c 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -772,6 +772,11 @@ S:	Maintained
>>  T:	git git://git.denx.de/u-boot-ubi.git
>>  F:	drivers/mtd/ubi/
>>  
>> +UFS
>> +M:	Faiz Abbas <faiz_abbas@ti.com>
>> +S:	Maintained
>> +F:	drivers/ufs/
>> +
>>  USB
>>  M:	Marek Vasut <marex@denx.de>
>>  S:	Maintained
>> diff --git a/drivers/Kconfig b/drivers/Kconfig
>> index 96ff4f566a..61bbe88d6c 100644
>> --- a/drivers/Kconfig
>> +++ b/drivers/Kconfig
>> @@ -118,6 +118,8 @@ source "drivers/tpm/Kconfig"
>>  
>>  source "drivers/usb/Kconfig"
>>  
>> +source "drivers/ufs/Kconfig"
>> +
>>  source "drivers/video/Kconfig"
>>  
>>  source "drivers/virtio/Kconfig"
>> diff --git a/drivers/Makefile b/drivers/Makefile
>> index 6635dabd2c..2794bef18a 100644
>> --- a/drivers/Makefile
>> +++ b/drivers/Makefile
>> @@ -111,6 +111,7 @@ obj-y += soc/
>>  obj-y += thermal/
>>  obj-$(CONFIG_TEE) += tee/
>>  obj-y += axi/
>> +obj-y += ufs/
>>  obj-$(CONFIG_W1) += w1/
>>  obj-$(CONFIG_W1_EEPROM) += w1-eeprom/
>>  
>> diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig
>> new file mode 100644
>> index 0000000000..538aad8cd9
>> --- /dev/null
>> +++ b/drivers/ufs/Kconfig
>> @@ -0,0 +1,9 @@
>> +menu "UFS Host Controller Support"
>> +
>> +config UFS
>> +	bool "Support UFS controllers"
>> +	select DM_SCSI
> 
> DM_SCSI has further dependencies, so its preferred not to use select
> 
> 	depends on DM_SCSI
> 
> Also if this is moved under drivers/scsi/ then this Kconfig file can be
> sourced conditionally
> 
>> +	help
>> +	  This selects support for Universal Flash Subsystem (UFS).
>> +	  Say Y here if you want UFS Support.
>> +endmenu
>> diff --git a/drivers/ufs/Makefile b/drivers/ufs/Makefile
>> new file mode 100644
>> index 0000000000..b8df759f66
>> --- /dev/null
>> +++ b/drivers/ufs/Makefile
>> @@ -0,0 +1,6 @@
>> +# SPDX-License-Identifier: GPL-2.0
>> +#
>> +# Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
>> +#
>> +
>> +obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o
>> diff --git a/drivers/ufs/ufs-uclass.c b/drivers/ufs/ufs-uclass.c
>> new file mode 100644
>> index 0000000000..920bfa64e1
>> --- /dev/null
>> +++ b/drivers/ufs/ufs-uclass.c
>> @@ -0,0 +1,16 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/**
>> + * ufs-uclass.c - Universal Flash Subsystem (UFS) Uclass driver
>> + *
>> + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
>> + */
>> +
>> +#include <common.h>
>> +#include "ufs.h"
>> +#include <dm.h>
>> +
>> +UCLASS_DRIVER(ufs) = {
>> +	.id	= UCLASS_UFS,
>> +	.name	= "ufs",
>> +	.per_device_auto_alloc_size = sizeof(struct ufs_hba),
>> +};
> 
> [...]
> 
>> +#endif /* _UNIPRO_H_ */
>> diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
>> index 09e0ad5391..a606b8c41b 100644
>> --- a/include/dm/uclass-id.h
>> +++ b/include/dm/uclass-id.h
>> @@ -96,6 +96,7 @@ enum uclass_id {
>>  	UCLASS_THERMAL,		/* Thermal sensor */
>>  	UCLASS_TIMER,		/* Timer device */
>>  	UCLASS_TPM,		/* Trusted Platform Module TIS interface */
>> +	UCLASS_UFS,		/* Universale Flash Storage */
> 
> s/Universale/Universal
> 
>>  	UCLASS_USB,		/* USB bus */
>>  	UCLASS_USB_DEV_GENERIC,	/* USB generic device */
>>  	UCLASS_USB_HUB,		/* USB hub */
>> diff --git a/include/ufs.h b/include/ufs.h
>> new file mode 100644
>> index 0000000000..2245838b3c
>> --- /dev/null
>> +++ b/include/ufs.h
>> @@ -0,0 +1,7 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +#ifndef _UFS_H
>> +#define _UFS_H
>> +
>> +int ufs_probe(void);
> 
> This is fine, but you may want to provide helper to initialize a single
> instance of controller so that we don't end up in a situation like MMC
> where all the instances are initialized always.
> Probably modify ufs_probe() to take an int arg that indicates instance
> to be probed and -1 to probe all instances.

Makes sense. Will modify the API.

> Irrespective of this, please add API documentation before the function
> declaration
> 
>> +int ufs_scsi_bind(struct udevice *scsi_dev, struct udevice **devp);
> 
> Please document the API

Ok.

Thanks,
Faiz

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [U-Boot] [PATCH 07/10] ufs: Add glue layer driver for TI J721E devices
  2019-09-10  3:48   ` Vignesh Raghavendra
@ 2019-09-11 13:45     ` Faiz Abbas
  0 siblings, 0 replies; 20+ messages in thread
From: Faiz Abbas @ 2019-09-11 13:45 UTC (permalink / raw)
  To: u-boot

Vignesh,

On 10/09/19 9:18 AM, Vignesh Raghavendra wrote:
> 
> 
> On 09/09/19 1:49 PM, Faiz Abbas wrote:
>> Add glue layer driver for the controller present on TI's J721E devices.
>>
>> Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
>> ---
>>  drivers/ufs/Kconfig        |  6 +++
>>  drivers/ufs/Makefile       |  1 +
>>  drivers/ufs/ti-j721e-ufs.c | 75 ++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 82 insertions(+)
>>  create mode 100644 drivers/ufs/ti-j721e-ufs.c
>>
>> diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig
>> index a320b4561f..4875e9448e 100644
>> --- a/drivers/ufs/Kconfig
>> +++ b/drivers/ufs/Kconfig
>> @@ -14,4 +14,10 @@ config CADENCE_UFS
>>  	  This selects the platform driver for the Cadence UFS host
>>  	  controller present on present TI's J721e devices.
>>  
>> +config TI_J721E_UFS
>> +	bool "Glue Layer driver for UFS on TI J721E devices"
>> +	help
>> +	  This selects the glue layer driver for Cadence controller
>> +	  present on TI's J721E devices.
>> +
>>  endmenu
>> diff --git a/drivers/ufs/Makefile b/drivers/ufs/Makefile
>> index 9262bd6cd0..62ed016608 100644
>> --- a/drivers/ufs/Makefile
>> +++ b/drivers/ufs/Makefile
>> @@ -5,3 +5,4 @@
>>  
>>  obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o
>>  obj-$(CONFIG_CADENCE_UFS) += cdns-platform.o
>> +obj-$(CONFIG_TI_J721E_UFS) += ti-j721e-ufs.o
>> diff --git a/drivers/ufs/ti-j721e-ufs.c b/drivers/ufs/ti-j721e-ufs.c
>> new file mode 100644
>> index 0000000000..249d3796c0
>> --- /dev/null
>> +++ b/drivers/ufs/ti-j721e-ufs.c
>> @@ -0,0 +1,75 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
>> + */
>> +
>> +#include <clk.h>
>> +#include <common.h>
>> +#include <dm/device.h>
>> +#include <dm/read.h>
> 
> #include <dm.h>
> 
> should be sufficient instead of two includes.

Replaced it.

> 
>> +#include <power-domain.h>
>> +#include <regmap.h>
>> +
>> +#define UFS_SS_CTRL             0x4
>> +#define UFS_SS_RST_N_PCS        BIT(0)
>> +#define UFS_SS_CLK_26MHZ        BIT(4)
>> +
>> +static int ti_j721e_ufs_probe(struct udevice *dev)
>> +{
>> +	struct power_domain ufs_pwrdmn;
>> +	struct regmap *map;
>> +	unsigned int clock;
>> +	struct clk clk;
>> +	u32 reg = 0;
>> +	int ret;
>> +
>> +	ret = power_domain_get(dev, &ufs_pwrdmn);
>> +	if (ret) {
>> +		dev_err(dev, "failed to get power domain %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	ret = power_domain_on(&ufs_pwrdmn);
>> +	if (ret) {
>> +		dev_err(dev, "Power domain on failed\n");
>> +		return ret;
>> +	}
> 
> Core takes care of enabling power domain before calling probe. So this
> can be dropped

Ok.

> 
>> +
>> +	ret = regmap_init_mem(dev_ofnode(dev), &map);
>> +	if (ret)
>> +		return ret;
>> +
> 
> 
> I think regmap is an overkill here.. We are just accessing a single
> register and within dedicated wrapper space. Just use regular IO accessors.

Ok. Going back to writel/readl calls.

> 
> 
> 
>> +	ret = clk_get_by_index(dev, 0, &clk);
>> +	if (ret) {
>> +		dev_err(dev, "failed to get M-PHY clock\n");
>> +		return ret;
>> +	}
>> +
>> +	clock = clk_get_rate(&clk);
>> +	if (IS_ERR_VALUE(clock)) {
>> +		dev_err(dev, "failed to get rate\n");
>> +		return ret;
>> +	}
>> +
>> +	if (clock == 26000000)
>> +		reg |= UFS_SS_CLK_26MHZ;
>> +	/* Take UFS slave device out of reset */
>> +	reg |= UFS_SS_RST_N_PCS;
>> +	regmap_write(map, UFS_SS_CTRL, reg);
>> +
> 
> To be safe, put the slave back to reset before jumping to kernel so that
> card does not see any glitches when kernel is doing any
> re-initialization of clocks etc.
> This can be done in driver remove callback (and needs DM_FLAG_OS_PREPARE
> flag to be set in driver declaration)

Implemented this for v2. Thanks.

Regards,
Faiz

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2019-09-11 13:45 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-09  8:19 [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e Faiz Abbas
2019-09-09  8:19 ` [U-Boot] [PATCH 01/10] scsi: Simplify scsi_read()/_write() Faiz Abbas
2019-09-09  8:19 ` [U-Boot] [PATCH 02/10] scsi: Add max_bytes to scsi_platdata Faiz Abbas
2019-09-10  3:46   ` Vignesh Raghavendra
2019-09-11  7:55     ` Faiz Abbas
2019-09-09  8:19 ` [U-Boot] [PATCH 03/10] scsi: Retry inquiry 3 times to overcome Unit Attention condition Faiz Abbas
2019-09-09  8:19 ` [U-Boot] [PATCH 04/10] scsi: Add dma direction member to command structure Faiz Abbas
2019-09-09  8:19 ` [U-Boot] [PATCH 05/10] ufs: Add Initial Support for UFS subsystem Faiz Abbas
2019-09-10  3:48   ` Vignesh Raghavendra
2019-09-11  8:06     ` Faiz Abbas
2019-09-09  8:19 ` [U-Boot] [PATCH 06/10] ufs: Add Support for Cadence platform UFS driver Faiz Abbas
2019-09-09  8:19 ` [U-Boot] [PATCH 07/10] ufs: Add glue layer driver for TI J721E devices Faiz Abbas
2019-09-10  3:48   ` Vignesh Raghavendra
2019-09-11 13:45     ` Faiz Abbas
2019-09-09  8:19 ` [U-Boot] [PATCH 08/10] arm: dts: k3-j721e-main: Add UFS nodes Faiz Abbas
2019-09-09  8:19 ` [U-Boot] [PATCH 09/10] cmd: Add Support for UFS commands Faiz Abbas
2019-09-09  8:19 ` [U-Boot] [PATCH 10/10] configs: j721e_evm_a72: Enable configs for UFS Faiz Abbas
2019-09-09 14:52 ` [U-Boot] [PATCH 00/10] Add Support for UFS subsystem for TI's J721e Tom Rini
2019-09-09 14:57   ` Faiz Abbas
2019-09-09 15:01     ` Tom Rini

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.