soc/qualcomm/common/usb: Add support for common USB driver

Add common USB driver for qualcomm soc sc7180 and sc7280.

This includes dwc3 controller, qmp ss phy, qusb hs phy and snsp hs phy.

BUG=b:182963902
TEST=Validated USB enumeration on qcom sc7180 and
sc7280 development board

Signed-off-by: Sandeep Maheswaram <sanm@codeaurora.org>
Change-Id: I1013ded22855286220cfa747cb25418070fe85a7
Reviewed-on: https://review.coreboot.org/c/coreboot/+/56091
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
diff --git a/src/soc/qualcomm/common/usb/qusb_phy.c b/src/soc/qualcomm/common/usb/qusb_phy.c
new file mode 100644
index 0000000..c8a56b0
--- /dev/null
+++ b/src/soc/qualcomm/common/usb/qusb_phy.c
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <soc/usb/qusb_phy.h>
+#include <soc/efuse.h>
+#include <timer.h>
+#include <soc/usb/usb_common.h>
+
+static struct qfprom_corr * const qfprom_corr_efuse = (void *)QFPROM_BASE;
+
+struct hs_usb_phy_reg qusb_phy = {
+	.phy_pll = (void *)QUSB_PRIM_PHY_BASE,
+
+	.phy_dig = (void *)QUSB_PRIM_PHY_DIG_BASE,
+
+	.efuse_offset = 25,
+};
+
+static void qusb2_phy_override_phy_params(struct hs_usb_phy_reg *hs_phy_reg)
+{
+	/* Override preemphasis value */
+	write32(&hs_phy_reg->phy_dig->tune1,
+		hs_phy_reg->board_data->port_tune1);
+
+	/* Override BIAS_CTRL_2 to reduce the TX swing overshooting. */
+	write32(&hs_phy_reg->phy_pll->bias_ctrl_2,
+		hs_phy_reg->board_data->pll_bias_control_2);
+
+	/* Override IMP_RES_OFFSET value */
+	write32(&hs_phy_reg->phy_dig->imp_ctrl1,
+		hs_phy_reg->board_data->imp_ctrl1);
+}
+
+/*
+ * Fetches HS Tx tuning value from efuse register and sets the
+ * QUSB2PHY_PORT_TUNE1/2 register.
+ * For error case, skip setting the value and use the default value.
+ */
+
+static void qusb2_phy_set_tune_param(struct hs_usb_phy_reg *hs_phy_reg)
+{
+	/*
+	 * Efuse registers 3 bit value specifies tuning for HSTX
+	 * output current in TUNE1 Register. Hence Extract 3 bits from
+	 * EFUSE at correct position.
+	 */
+
+	const int efuse_bits = 3;
+	int bit_pos = hs_phy_reg->efuse_offset;
+
+	u32 bit_mask = (1 << efuse_bits) - 1;
+	u32 tune_val =
+		(read32(&qfprom_corr_efuse->qusb_hstx_trim_lsb) >> bit_pos)
+		& bit_mask;
+	/*
+	 * if efuse reg is updated (i.e non-zero) then use it to program
+	 * tune parameters.
+	 */
+	if (tune_val)
+		clrsetbits32(&hs_phy_reg->phy_dig->tune1,
+				PORT_TUNE1_MASK, tune_val << 4);
+}
+
+static void tune_phy(struct hs_usb_phy_reg *hs_phy_reg)
+{
+	write32(&hs_phy_reg->phy_dig->pwr_ctrl2, QUSB2PHY_PWR_CTRL2);
+	/* IMP_CTRL1: Control the impedance reduction */
+	write32(&hs_phy_reg->phy_dig->imp_ctrl1, QUSB2PHY_IMP_CTRL1);
+	/* IMP_CTRL2: Impedance offset/mapping slope */
+	write32(&hs_phy_reg->phy_dig->imp_ctrl2, QUSB2PHY_IMP_CTRL1);
+	write32(&hs_phy_reg->phy_dig->chg_ctrl2, QUSB2PHY_IMP_CTRL2);
+	/*
+	 * TUNE1: Sets HS Impedance to approx 45 ohms
+	 * then override with efuse value.
+	 */
+	write32(&hs_phy_reg->phy_dig->tune1, QUSB2PHY_PORT_TUNE1);
+	/* TUNE2: Tuning for HS Disconnect Level */
+	write32(&hs_phy_reg->phy_dig->tune2, QUSB2PHY_PORT_TUNE2);
+	/* TUNE3: Tune squelch range */
+	write32(&hs_phy_reg->phy_dig->tune3, QUSB2PHY_PORT_TUNE3);
+	/* TUNE4: Sets EOP_DLY(Squelch rising edge to linestate falling edge) */
+	write32(&hs_phy_reg->phy_dig->tune4, QUSB2PHY_PORT_TUNE4);
+	write32(&hs_phy_reg->phy_dig->tune5, QUSB2PHY_PORT_TUNE5);
+
+	if (hs_phy_reg->board_data) {
+		/* Override board specific PHY tuning values */
+		qusb2_phy_override_phy_params(hs_phy_reg);
+
+		/* Set efuse value for tuning the PHY */
+		qusb2_phy_set_tune_param(hs_phy_reg);
+	}
+}
+
+void hs_usb_phy_init(void *board_data)
+{
+	struct hs_usb_phy_reg *hs_phy_reg;
+
+	hs_phy_reg = &qusb_phy;
+
+	hs_phy_reg->board_data = (struct usb_board_data *) board_data;
+
+	/* PWR_CTRL: set the power down bit to disable the PHY */
+
+	setbits32(&hs_phy_reg->phy_dig->pwr_ctrl1, POWER_DOWN);
+
+	write32(&hs_phy_reg->phy_pll->analog_controls_two,
+			QUSB2PHY_PLL_ANALOG_CONTROLS_TWO);
+	write32(&hs_phy_reg->phy_pll->clock_inverters,
+			QUSB2PHY_PLL_CLOCK_INVERTERS);
+	write32(&hs_phy_reg->phy_pll->cmode,
+			QUSB2PHY_PLL_CMODE);
+	write32(&hs_phy_reg->phy_pll->lock_delay,
+			QUSB2PHY_PLL_LOCK_DELAY);
+	write32(&hs_phy_reg->phy_pll->dig_tim,
+			QUSB2PHY_PLL_DIGITAL_TIMERS_TWO);
+	write32(&hs_phy_reg->phy_pll->bias_ctrl_1,
+			QUSB2PHY_PLL_BIAS_CONTROL_1);
+	write32(&hs_phy_reg->phy_pll->bias_ctrl_2,
+			QUSB2PHY_PLL_BIAS_CONTROL_2);
+
+	tune_phy(hs_phy_reg);
+
+	/* PWR_CTRL1: Clear the power down bit to enable the PHY */
+	clrbits32(&hs_phy_reg->phy_dig->pwr_ctrl1, POWER_DOWN);
+
+	write32(&hs_phy_reg->phy_dig->debug_ctrl2,
+				DEBUG_CTRL2_MUX_PLL_LOCK_STATUS);
+
+	/*
+	 * DEBUG_STAT5: wait for 160uS for PLL lock;
+	 * vstatus[0] changes from 0 to 1.
+	 */
+	long lock_us = wait_us(160, read32(&hs_phy_reg->phy_dig->debug_stat5) &
+						VSTATUS_PLL_LOCK_STATUS_MASK);
+	if (!lock_us)
+		printk(BIOS_ERR, "ERROR: QUSB PHY PLL LOCK fails\n");
+	else
+		printk(BIOS_DEBUG, "QUSB PHY initialized and locked in %ldus\n",
+				lock_us);
+}