zynqmp: pm_service: Add support for resetting ULPI transceiver

To make ULPI transceiver work, a HIGH - LOW - HIGH pulse needs
to be given to resetb pin of ULPI chip. In ZYNQMP, this resetb
pin is being driven by BOOT MODE PIN 1. The BOOT MODE PIN's
are controlled by BOOT_PIN_CTRL register present in CRL_APB
address region. Since CRL_APB can be resticted to secure access,
this pin should be controlled by ATF.

This patch adds the support for the same.

Signed-off-by: Anurag Kumar Vulisha <anuragku@xilinx.com>
Signed-off-by: Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c
index cdbb515..1791833 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c
@@ -472,6 +472,40 @@
 }
 
 /**
+ * pm_ioctl_ulpi_reset() - Ioctl function for performing ULPI reset
+ *
+ * This function peerforms the ULPI reset sequence for resetting
+ * the ULPI transceiver.
+ *
+ * @return      Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_ulpi_reset(void)
+{
+	enum pm_ret_status ret;
+
+	ret = pm_mmio_write(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOT_PIN_MASK,
+			    ZYNQMP_ULPI_RESET_VAL_HIGH);
+	if (ret != PM_RET_SUCCESS)
+		return ret;
+
+	/* Drive ULPI assert for atleast 1ms */
+	mdelay(1);
+
+	ret = pm_mmio_write(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOT_PIN_MASK,
+			    ZYNQMP_ULPI_RESET_VAL_LOW);
+	if (ret != PM_RET_SUCCESS)
+		return ret;
+
+	/* Drive ULPI de-assert for atleast 1ms */
+	mdelay(1);
+
+	ret = pm_mmio_write(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOT_PIN_MASK,
+			    ZYNQMP_ULPI_RESET_VAL_HIGH);
+
+	return ret;
+}
+
+/**
  * pm_api_ioctl() -  PM IOCTL API for device control and configs
  * @node_id	Node ID of the device
  * @ioctl_id	ID of the requested IOCTL
@@ -540,6 +574,9 @@
 	case IOCTL_READ_PGGS:
 		ret = pm_ioctl_read_pggs(arg1, value);
 		break;
+	case IOCTL_ULPI_RESET:
+		ret = pm_ioctl_ulpi_reset();
+		break;
 	default:
 		ret = PM_RET_ERROR_NOTSUPPORTED;
 		break;
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h
index 081259f..bf17117 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h
@@ -32,6 +32,8 @@
 	IOCTL_READ_GGS,
 	IOCTL_WRITE_PGGS,
 	IOCTL_READ_PGGS,
+	/* IOCTL for ULPI reset */
+	IOCTL_ULPI_RESET,
 };
 
 //RPU operation mode
diff --git a/plat/xilinx/zynqmp/zynqmp_def.h b/plat/xilinx/zynqmp/zynqmp_def.h
index 22256eb..dd26c6c 100644
--- a/plat/xilinx/zynqmp/zynqmp_def.h
+++ b/plat/xilinx/zynqmp/zynqmp_def.h
@@ -48,6 +48,7 @@
 #define CRL_APB_BOOT_MODE_USER		(CRL_APB_BASE + 0x200)
 #define CRL_APB_RESET_CTRL		(CRL_APB_BASE + 0x218)
 #define CRL_APB_RST_LPD_TOP		(CRL_APB_BASE + 0x23C)
+#define CRL_APB_BOOT_PIN_CTRL		(CRL_APB_BASE + U(0x250))
 #define CRL_APB_CLK_BASE		U(0xFF5E0020)
 
 #define CRL_APB_RPU_AMBA_RESET		(U(1) << 2)
@@ -56,7 +57,15 @@
 #define CRL_APB_RESET_CTRL_SOFT_RESET	(U(1) << 4)
 
 #define CRL_APB_BOOT_MODE_MASK		(U(0xf) << 0)
+#define CRL_APB_BOOT_PIN_MASK		(U(0xf0f) << 0)
+#define CRL_APB_BOOT_DRIVE_PIN_1_SHIFT	U(9)
+#define CRL_APB_BOOT_ENABLE_PIN_1_SHIFT	U(1)
+#define CRL_APB_BOOT_ENABLE_PIN_1	(U(0x1) << CRL_APB_BOOT_ENABLE_PIN_1_SHIFT)
+#define CRL_APB_BOOT_DRIVE_PIN_1	(U(0x1) << CRL_APB_BOOT_DRIVE_PIN_1_SHIFT)
 #define ZYNQMP_BOOTMODE_JTAG		U(0)
+#define ZYNQMP_ULPI_RESET_VAL_HIGH	(CRL_APB_BOOT_ENABLE_PIN_1 | \
+					 CRL_APB_BOOT_DRIVE_PIN_1)
+#define ZYNQMP_ULPI_RESET_VAL_LOW	CRL_APB_BOOT_ENABLE_PIN_1
 
 /* system counter registers and bitfields */
 #define IOU_SCNTRS_BASE			0xFF260000