Sandeep Maheswaram | 6c2b860 | 2021-07-05 11:11:48 +0530 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | |
| 3 | #include <soc/usb/qusb_phy.h> |
| 4 | #include <soc/efuse.h> |
| 5 | #include <timer.h> |
| 6 | #include <soc/usb/usb_common.h> |
| 7 | |
| 8 | static struct qfprom_corr * const qfprom_corr_efuse = (void *)QFPROM_BASE; |
| 9 | |
| 10 | struct hs_usb_phy_reg qusb_phy = { |
| 11 | .phy_pll = (void *)QUSB_PRIM_PHY_BASE, |
| 12 | |
| 13 | .phy_dig = (void *)QUSB_PRIM_PHY_DIG_BASE, |
| 14 | |
| 15 | .efuse_offset = 25, |
| 16 | }; |
| 17 | |
| 18 | static void qusb2_phy_override_phy_params(struct hs_usb_phy_reg *hs_phy_reg) |
| 19 | { |
| 20 | /* Override preemphasis value */ |
| 21 | write32(&hs_phy_reg->phy_dig->tune1, |
| 22 | hs_phy_reg->board_data->port_tune1); |
| 23 | |
| 24 | /* Override BIAS_CTRL_2 to reduce the TX swing overshooting. */ |
| 25 | write32(&hs_phy_reg->phy_pll->bias_ctrl_2, |
| 26 | hs_phy_reg->board_data->pll_bias_control_2); |
| 27 | |
| 28 | /* Override IMP_RES_OFFSET value */ |
| 29 | write32(&hs_phy_reg->phy_dig->imp_ctrl1, |
| 30 | hs_phy_reg->board_data->imp_ctrl1); |
| 31 | } |
| 32 | |
| 33 | /* |
| 34 | * Fetches HS Tx tuning value from efuse register and sets the |
| 35 | * QUSB2PHY_PORT_TUNE1/2 register. |
| 36 | * For error case, skip setting the value and use the default value. |
| 37 | */ |
| 38 | |
| 39 | static void qusb2_phy_set_tune_param(struct hs_usb_phy_reg *hs_phy_reg) |
| 40 | { |
| 41 | /* |
| 42 | * Efuse registers 3 bit value specifies tuning for HSTX |
| 43 | * output current in TUNE1 Register. Hence Extract 3 bits from |
| 44 | * EFUSE at correct position. |
| 45 | */ |
| 46 | |
| 47 | const int efuse_bits = 3; |
| 48 | int bit_pos = hs_phy_reg->efuse_offset; |
| 49 | |
| 50 | u32 bit_mask = (1 << efuse_bits) - 1; |
| 51 | u32 tune_val = |
| 52 | (read32(&qfprom_corr_efuse->qusb_hstx_trim_lsb) >> bit_pos) |
| 53 | & bit_mask; |
| 54 | /* |
| 55 | * if efuse reg is updated (i.e non-zero) then use it to program |
| 56 | * tune parameters. |
| 57 | */ |
| 58 | if (tune_val) |
| 59 | clrsetbits32(&hs_phy_reg->phy_dig->tune1, |
| 60 | PORT_TUNE1_MASK, tune_val << 4); |
| 61 | } |
| 62 | |
| 63 | static void tune_phy(struct hs_usb_phy_reg *hs_phy_reg) |
| 64 | { |
| 65 | write32(&hs_phy_reg->phy_dig->pwr_ctrl2, QUSB2PHY_PWR_CTRL2); |
| 66 | /* IMP_CTRL1: Control the impedance reduction */ |
| 67 | write32(&hs_phy_reg->phy_dig->imp_ctrl1, QUSB2PHY_IMP_CTRL1); |
| 68 | /* IMP_CTRL2: Impedance offset/mapping slope */ |
| 69 | write32(&hs_phy_reg->phy_dig->imp_ctrl2, QUSB2PHY_IMP_CTRL1); |
| 70 | write32(&hs_phy_reg->phy_dig->chg_ctrl2, QUSB2PHY_IMP_CTRL2); |
| 71 | /* |
| 72 | * TUNE1: Sets HS Impedance to approx 45 ohms |
| 73 | * then override with efuse value. |
| 74 | */ |
| 75 | write32(&hs_phy_reg->phy_dig->tune1, QUSB2PHY_PORT_TUNE1); |
| 76 | /* TUNE2: Tuning for HS Disconnect Level */ |
| 77 | write32(&hs_phy_reg->phy_dig->tune2, QUSB2PHY_PORT_TUNE2); |
| 78 | /* TUNE3: Tune squelch range */ |
| 79 | write32(&hs_phy_reg->phy_dig->tune3, QUSB2PHY_PORT_TUNE3); |
| 80 | /* TUNE4: Sets EOP_DLY(Squelch rising edge to linestate falling edge) */ |
| 81 | write32(&hs_phy_reg->phy_dig->tune4, QUSB2PHY_PORT_TUNE4); |
| 82 | write32(&hs_phy_reg->phy_dig->tune5, QUSB2PHY_PORT_TUNE5); |
| 83 | |
| 84 | if (hs_phy_reg->board_data) { |
| 85 | /* Override board specific PHY tuning values */ |
| 86 | qusb2_phy_override_phy_params(hs_phy_reg); |
| 87 | |
| 88 | /* Set efuse value for tuning the PHY */ |
| 89 | qusb2_phy_set_tune_param(hs_phy_reg); |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | void hs_usb_phy_init(void *board_data) |
| 94 | { |
| 95 | struct hs_usb_phy_reg *hs_phy_reg; |
| 96 | |
| 97 | hs_phy_reg = &qusb_phy; |
| 98 | |
| 99 | hs_phy_reg->board_data = (struct usb_board_data *) board_data; |
| 100 | |
| 101 | /* PWR_CTRL: set the power down bit to disable the PHY */ |
| 102 | |
| 103 | setbits32(&hs_phy_reg->phy_dig->pwr_ctrl1, POWER_DOWN); |
| 104 | |
| 105 | write32(&hs_phy_reg->phy_pll->analog_controls_two, |
| 106 | QUSB2PHY_PLL_ANALOG_CONTROLS_TWO); |
| 107 | write32(&hs_phy_reg->phy_pll->clock_inverters, |
| 108 | QUSB2PHY_PLL_CLOCK_INVERTERS); |
| 109 | write32(&hs_phy_reg->phy_pll->cmode, |
| 110 | QUSB2PHY_PLL_CMODE); |
| 111 | write32(&hs_phy_reg->phy_pll->lock_delay, |
| 112 | QUSB2PHY_PLL_LOCK_DELAY); |
| 113 | write32(&hs_phy_reg->phy_pll->dig_tim, |
| 114 | QUSB2PHY_PLL_DIGITAL_TIMERS_TWO); |
| 115 | write32(&hs_phy_reg->phy_pll->bias_ctrl_1, |
| 116 | QUSB2PHY_PLL_BIAS_CONTROL_1); |
| 117 | write32(&hs_phy_reg->phy_pll->bias_ctrl_2, |
| 118 | QUSB2PHY_PLL_BIAS_CONTROL_2); |
| 119 | |
| 120 | tune_phy(hs_phy_reg); |
| 121 | |
| 122 | /* PWR_CTRL1: Clear the power down bit to enable the PHY */ |
| 123 | clrbits32(&hs_phy_reg->phy_dig->pwr_ctrl1, POWER_DOWN); |
| 124 | |
| 125 | write32(&hs_phy_reg->phy_dig->debug_ctrl2, |
| 126 | DEBUG_CTRL2_MUX_PLL_LOCK_STATUS); |
| 127 | |
| 128 | /* |
| 129 | * DEBUG_STAT5: wait for 160uS for PLL lock; |
| 130 | * vstatus[0] changes from 0 to 1. |
| 131 | */ |
| 132 | long lock_us = wait_us(160, read32(&hs_phy_reg->phy_dig->debug_stat5) & |
| 133 | VSTATUS_PLL_LOCK_STATUS_MASK); |
| 134 | if (!lock_us) |
Julius Werner | e966595 | 2022-01-21 17:06:20 -0800 | [diff] [blame^] | 135 | printk(BIOS_ERR, "QUSB PHY PLL LOCK fails\n"); |
Sandeep Maheswaram | 6c2b860 | 2021-07-05 11:11:48 +0530 | [diff] [blame] | 136 | else |
| 137 | printk(BIOS_DEBUG, "QUSB PHY initialized and locked in %ldus\n", |
| 138 | lock_us); |
| 139 | } |