USB: dwc3: msm: Perform SSPHY register read twice

CR protocol interface is used for reading and writing SSPHY registers.
CR protocol may be performed incorrectly since both the acknowledge
and data are synchronized, and the exact delay of the synchronizers
is uncertain. Due to this hardware bug, first read of SSPHY register
may be incorrect. Hence SW should perform SSPHY register read twice
and use only second read. This is not applicable to SSPHY register
write.

CRs-Fixed: 499129
Change-Id: I5d17cf2f6da997845fa63460d3159213d6bb24ac
Signed-off-by: Vijayavardhan Vennapusa <vvreddy@codeaurora.org>
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 6aeb26e..f31481f 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -381,15 +381,29 @@
  */
 static u32 dwc3_msm_ssusb_read_phycreg(void *base, u32 addr)
 {
+	bool first_read = true;
+
 	iowrite32(addr, base + SS_CR_PROTOCOL_DATA_IN_REG);
 	iowrite32(0x1, base + SS_CR_PROTOCOL_CAP_ADDR_REG);
 	while (ioread32(base + SS_CR_PROTOCOL_CAP_ADDR_REG))
 		cpu_relax();
 
+	/*
+	 * Due to hardware bug, first read of SSPHY register might be
+	 * incorrect. Hence as workaround, SW should perform SSPHY register
+	 * read twice, but use only second read and ignore first read.
+	 */
+retry:
 	iowrite32(0x1, base + SS_CR_PROTOCOL_READ_REG);
 	while (ioread32(base + SS_CR_PROTOCOL_READ_REG))
 		cpu_relax();
 
+	if (first_read) {
+		ioread32(base + SS_CR_PROTOCOL_DATA_OUT_REG);
+		first_read = false;
+		goto retry;
+	}
+
 	return ioread32(base + SS_CR_PROTOCOL_DATA_OUT_REG);
 }