soc/qualcomm/x1p42100: Add USB Type-A Host support

Add support for HS-PHY/SS-PHY and DWC3 USB controllers
for USB Type A Host support.

TEST = Ensure that pipe/utmi clocks are ON and check
port link status to confirm USB connect.

Change-Id: Ife08801062da5a8f87491b020b3828c246aadea8
Signed-off-by: Hari L <haril@qualcomm.corp-partner.google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/89132
Reviewed-by: Kapil Porwal <kapilporwal@google.com>
Reviewed-by: Subrata Banik <subratabanik@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Hari L 2025-09-10 17:57:07 +05:30 committed by Subrata Banik
commit 96eb6a3ac1
8 changed files with 1338 additions and 5 deletions

View file

@ -43,6 +43,9 @@ ramstage-y += soc.c
ramstage-y += cbmem.c
ramstage-y += ../common/mmu.c
ramstage-$(CONFIG_DRIVERS_UART) += ../common/qupv3_uart.c
ramstage-y += usb/usb.c
ramstage-y += usb/snps_usb_phy.c
ramstage-y += usb/qmpv4_usb_phy.c
ramstage-$(CONFIG_PCI) += ../common/pcie_common.c
ramstage-y += ../common/spmi.c
ramstage-$(CONFIG_PCI) += pcie.c

View file

@ -31,9 +31,7 @@
#define GPIO_FUNC_QSPI_DATA_1 GPIO129_FUNC_QSPI0_DATA_1
#define GPIO_FUNC_QSPI_CLK GPIO127_FUNC_QSPI0_CLK
/*
* QUP SERIAL ENGINE BASE ADDRESSES
*/
/* QUP SERIAL ENGINE BASE ADDRESSES */
/* QUPV3_0 */
#define QUP_SERIAL0_BASE 0x00B80000
#define QUP_SERIAL1_BASE 0x00B84000
@ -70,6 +68,22 @@
#define QUP_WRAP2_BASE 0x008C0000
#define QUP_2_GSI_BASE 0x00804000
/* USB BASE ADDRESSES */
#define HS_USB_MP0_PHY_BASE 0x088e1000
#define HS_USB_MP1_PHY_BASE 0x088E2000
#define QMP_PHY_MP0_QSERDES_COM_REG_BASE 0x088E3000
#define QMP_PHY_MP0_QSERDES_TX_REG_BASE 0x088E3E00
#define QMP_PHY_MP0_QSERDES_RX_REG_BASE 0x088E4000
#define QMP_PHY_MP0_PCS_REG_BASE 0x088E3200
#define QMP_PHY_MP0_PCS_USB3_REG_BASE 0x088E4200
#define USB_HOST_DWC3_BASE 0x0a40c100
#define QMP_PHY_MP1_QSERDES_COM_REG_BASE 0x088E5000
#define QMP_PHY_MP1_QSERDES_TX_REG_BASE 0x088E5E00
#define QMP_PHY_MP1_QSERDES_RX_REG_BASE 0x088E6000
#define QMP_PHY_MP1_PCS_REG_BASE 0x088E5200
#define QMP_PHY_MP1_PCS_USB3_REG_BASE 0x088E6200
/* PCIE 6A */
#define PCIE6A_PCIE_PARF 0x01BF8000
#define PCIE6A_GEN1X4_PCIE_DBI 0x70000000
@ -110,8 +124,23 @@
#define PCIE6A_BQPHY_PCS_PCIE_LANE1 0x01BFFE00
/* TCSR */
#define TCSR_GCC_PCIE_4L_CLKREF_EN_PCIE_ENABLE ((void *)0x1FD512C)
#define TCSR_PCIE_CTRL_4LN_CONFIG_SEL ((void *)0x1FDA000)
#define TCSR_GCC_PCIE_4L_CLKREF_EN_PCIE_ENABLE ((void *)0x1FD512C)
#define TCSR_PCIE_CTRL_4LN_CONFIG_SEL ((void *)0x1FDA000)
#define TCSR_GCC_CXO_1_REFGEN_BIAS_SEL__SEL_REFGEN_ADDR ((void *)0x1FD511C)
#define TCSR_GCC_CXO_0_REFGEN_BIAS_SEL__SEL_REFGEN_ADDR ((void *)0x1FD5134)
#define TCSR_QREFS_CXO_0_RPT3_CONFIG_ADDR ((void *)0x1FD5014)
#define TCSR_QREFS_CXO_0_RPT4_CONFIG_ADDR ((void *)0x1FD5018)
#define TCSR_QREFS_CXO_1_RPT0_CONFIG_ADDR ((void *)0x1FD5000)
#define TCSR_QREFS_CXO_1_RX3_CONFIG_ADDR ((void *)0x1FD502C)
#define TCSR_QREFS_CXO_1_RX0_CONFIG_ADDR ((void *)0x1FD5020)
#define TCSR_QREFS_CXO_0_RX3_CONFIG_ADDR ((void *)0x1FD5030)
#define TCSR_QREFS_CXO_0_RX4_CONFIG_ADDR ((void *)0x1FD5034)
#define TCSR_GCC_USB3_MP0_CLKREF_EN_ADDR ((void *)0x1FD510C)
#define TCSR_GCC_USB3_MP1_CLKREF_EN_ADDR ((void *)0x1FD5110)
#define USB3_CLKREF_ENABLE_VALUE 0x1
/* SPMI PMIC ARB */
#define SPMI_PMIC_ARB_CORE_BASE 0x0C400000

View file

@ -0,0 +1,36 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <device/mmio.h>
/* USB3PHY_PCIE_USB3_PCS_PCS_STATUS bit */
#define USB3_PCS_PHYSTATUS BIT(6)
/* Define qmp_phy_init_tbl to use offsets instead of absolute addresses.
This makes the tables generic and reusable */
typedef struct qmp_phy_init_tbl {
u32 offset; // Offset from the base address of the register block
u32 val;
} qmp_phy_init_tbl_t;
/* Structure to encapsulate base addresses and configuration tables for a specific PHY instance */
struct ss_usb_phy_reg {
void *com_base;
void *tx_base;
void *rx_base;
void *pcs_base;
void *pcs_usb3_base;
const char *name;
/* Init sequence for QMP PHY blocks - serdes, tx, rx, pcs */
const qmp_phy_init_tbl_t *serdes_tbl;
int serdes_tbl_num;
const qmp_phy_init_tbl_t *tx_tbl;
int tx_tbl_num;
const qmp_phy_init_tbl_t *rx_tbl;
int rx_tbl_num;
const qmp_phy_init_tbl_t *pcs_tbl;
int pcs_tbl_num;
const qmp_phy_init_tbl_t *pcs_usb3_tbl;
int pcs_usb3_tbl_num;
};
/* Initialize a specific QMP USB3 PHY instance */
bool ss_qmp_phy_init(u32 phy_idx);

View file

@ -0,0 +1,125 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <device/mmio.h>
struct hs_usb_phy_reg {
/* Revision ID registers */
u32 usb_phy_revision_id0; /* 0x000 */
u32 usb_phy_revision_id1; /* 0x004 */
u32 usb_phy_revision_id2; /* 0x008 */
u32 usb_phy_revision_id3; /* 0x00c */
/* Debug bus status registers */
u32 usb_phy_debug_bus_stat0; /* 0x010 */
u32 usb_phy_debug_bus_stat1; /* 0x014 */
u32 usb_phy_debug_bus_stat2; /* 0x018 */
u32 usb_phy_debug_bus_stat3; /* 0x01c */
/* Test and status registers */
u32 usb_phy_hs_rx_tester_out_1; /* 0x020 */
u32 usb_phy_charging_det_output; /* 0x024 */
u32 usb_phy_hs_phy_test_out_1; /* 0x028 */
u32 usb_phy_refclk_rxtap_test_status; /* 0x02c */
/* UTMI RX status registers */
u32 usb_phy_utmi_rx_datal_status; /* 0x030 */
u32 usb_phy_utmi_rx_datah_status; /* 0x034 */
u32 usb_phy_utmi_rx_port_status; /* 0x038 */
/* Original UTMI control registers */
u32 utmi_ctrl0; /* 0x03c */
u32 utmi_ctrl1; /* 0x040 */
/* Extended UTMI control registers */
u32 utmi_ctrl2; /* 0x044 */
u32 utmi_ctrl3; /* 0x048 */
u32 utmi_ctrl4; /* 0x04c */
u32 utmi_ctrl5; /* 0x050 */
/* HS PHY control registers */
u32 hs_phy_ctrl_common0; /* 0x054 */
/* Configuration control registers */
u32 cfg_ctrl_1; /* 0x058 */
u32 cfg_ctrl_2; /* 0x05c */
u32 cfg_ctrl_3; /* 0x060 */
u32 hs_phy_ctrl2; /* 0x064 */
u32 cfg_ctrl_4; /* 0x068 */
/* Additional configuration control registers */
u32 cfg_ctrl_5; /* 0x06c */
u32 cfg_ctrl_6; /* 0x070 */
u32 cfg_ctrl_7; /* 0x074 */
u32 cfg_ctrl_8; /* 0x078 */
u32 cfg_ctrl_9; /* 0x07c */
u32 cfg_ctrl_10; /* 0x080 */
u32 hs_phy_test1; /* 0x084 */
u32 rx_tester_1_reg0; /* 0x088 */
u32 rx_tester_1_reg1; /* 0x08c */
u32 rx_tester_1_reg2; /* 0x090 */
/* Original cfg0 register */
u32 cfg0; /* 0x094 */
/* Common control registers */
u32 utmi_phy_cmn_ctrl0; /* 0x098 */
u32 utmi_phy_cmn_ctrl1; /* 0x09c */
/* Original refclk_ctrl register */
u32 refclk_ctrl; /* 0x0a0 */
/* Power and reset control registers */
u32 usb_phy_pwrdown_ctrl; /* 0x0a4 */
u32 usb_phy_test_debug_ctrl; /* 0x0a8 */
u32 usb_phy_reset_ctrl; /* 0x0ac */
u32 usb_phy_ac_en; /* 0x0b0 */
u32 cfg_ctrl_11; /* 0x0b4 */
u32 usb_phy_fsel_sel; /* 0x0b8 */
/* Skitter control registers */
u32 usb_phy_skitter_ctrl_1; /* 0x0bc */
u32 usb_phy_skitter_ctrl_2; /* 0x0c0 */
u32 usb_phy_skitter_ctrl_3; /* 0x0c4 */
u32 usb_phy_skitter_sticky_no_lsb; /* 0x0c8 */
u32 usb_phy_skitter_sticky_no_msb; /* 0x0cc */
u32 usb_phy_skitter_calib_counter_lsb; /* 0x0d0 */
u32 usb_phy_skitter_calib_counter_msb; /* 0x0d4 */
u32 usb_phy_skitter_mul_cons_lsb; /* 0x0d8 */
u32 usb_phy_skitter_mul_cons_msb; /* 0x0dc */
u32 usb_phy_skitter_mfs_misc_1; /* 0x0e0 */
u32 usb_phy_skitter_mfs_misc_2; /* 0x0e4 */
u32 usb_phy_skitter_spread_detect_range; /* 0x0e8 */
u32 usb_phy_skitter_jitter_thrhold; /* 0x0ec */
u32 usb_phy_skitter_status; /* 0x0f0 */
u32 usb_phy_inv_dly_lsb; /* 0x0f4 */
u32 usb_phy_inv_dly_msb; /* 0x0f8 */
u32 usb_phy_eud_connected; /* 0x0fc */
u32 usb_phy_skitter_jitter; /* 0x100 */
u32 usb_phy_test_debug_ctrl_2; /* 0x104 */
u32 eud_present_sel; /* 0x108 */
u32 usb_phy_skitter_tie_jitter_lsb; /* 0x10c */
u32 usb_phy_skitter_tie_jitter_msb; /* 0x110 */
u32 usb_phy_skitter_calib_rodly_1; /* 0x114 */
u32 usb_phy_skitter_calib_rodly_2; /* 0x118 */
u32 usb_phy_skitter_calib_rodly_3; /* 0x11c */
/* Reserved registers */
u32 usb_phy_reserved_0; /* 0x120 */
u32 usb_phy_reserved_1; /* 0x124 */
u32 usb_phy_reserved_2; /* 0x128 */
u32 usb_phy_reserved_3; /* 0x12c */
/* APB access registers */
u32 usb_phy_apb_access_cmd; /* 0x130 */
u32 usb_phy_apb_access_status; /* 0x134 */
u32 usb_phy_apb_address; /* 0x138 */
u32 usb_phy_apb_wrdata_lsb; /* 0x13c */
u32 usb_phy_apb_wrdata_msb; /* 0x140 */
u32 usb_phy_apb_rddata_lsb; /* 0x144 */
u32 usb_phy_apb_rddata_msb; /* 0x148 */
/* Final skitter registers */
u32 usb_phy_skitter_insertion_dly_corr; /* 0x14c */
u32 usb_phy_skitter_pos_edge_corr1; /* 0x150 */
};

View file

@ -0,0 +1,76 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include "qmp_usb_phy.h"
/* QSCRATCH_GENERAL_CFG register bit offset */
#define PIPE_UTMI_CLK_SEL BIT(0)
#define PIPE3_PHYSTATUS_SW BIT(3)
#define PIPE_UTMI_CLK_DIS BIT(8)
/* Global USB3 Control Registers */
#define DWC3_GUSB3PIPECTL_DELAYP1TRANS BIT(18)
#define DWC3_GUSB3PIPECTL_PHYSOFTRS BIT(31)
#define DWC3_GUSB3PIPECTL_UX_EXIT_IN_PX BIT(27)
#define DWC3_GUSB3PIPECTL_P3EXSIGP2 BIT(10)
#define DWC3_GCTL_PRTCAPDIR(n) ((n) << 12)
#define DWC3_GCTL_PRTCAP_OTG 3
#define DWC3_GCTL_PRTCAP_HOST 1
/* Global USB2 PHY Configuration Register */
#define DWC3_GUSB2PHYCFG_USBTRDTIM(n) ((n) << 10)
#define DWC3_GUSB2PHYCFG_USB2TRDTIM_MASK DWC3_GUSB2PHYCFG_USBTRDTIM(0xf)
#define DWC3_GUSB2PHYCFG_PHYIF(n) ((n) << 3)
#define DWC3_GUSB2PHYCFG_PHYIF_MASK DWC3_GUSB2PHYCFG_PHYIF(1)
#define USBTRDTIM_UTMI_8_BIT 9
#define UTMI_PHYIF_8_BIT 0
#define DWC3_GUSB2PHYCFG_ENBLSLPM_MASK (0x1 << 0x8)
#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4)
#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
#define DWC3_GCTL_DISSCRAMBLE (1 << 3)
#define DWC3_GCTL_U2EXIT_LFPS (1 << 2)
#define DWC3_GCTL_DSBLCLKGTNG (1 << 0)
#define UTMI_CLK_DIS_0 (1 << 8)
#define UTMI_CLK_SEL_0 (1 << 0)
#define PIPE3_PHYSTATUS_SW_0 (1 << 3)
#define PIPE3_SET_PHYSTATUS_SW_0 (1 << 9)
#define USB3_MP_CGCTL_REG_ADDR ((void *)0x0A4F8828)
#define USB3_MP_DBM_FSM_EN_BIT (1 << 1)
#define USB3_MP_LINK_REGS_1_LU3LFPSRXTIM_ADDR ((void *)0X0A40D090)
#define USB3_MP_LINK_REGS_0_LU3LFPSRXTIM_ADDR ((void *)0X0A40D010)
#define GEN2_U3_EXIT_RSP_RX_CLK_MASK (0xFF << 16)
#define GEN1_U3_EXIT_RSP_RX_CLK_MASK (0xFF << 0)
#define GEN2_U3_EXIT_RSP_RX_CLK_VALUE (0x06 << 16)
#define GEN1_U3_EXIT_RSP_RX_CLK_VALUE (0x05 << 0)
#define LFPS_RSP_RX_CLK_CLR_MASK (GEN2_U3_EXIT_RSP_RX_CLK_MASK | GEN1_U3_EXIT_RSP_RX_CLK_MASK)
#define LFPS_RSP_RX_CLK_SET_MASK (GEN2_U3_EXIT_RSP_RX_CLK_VALUE | GEN1_U3_EXIT_RSP_RX_CLK_VALUE)
#define DWC3_GUCTL1_CLR_MASK (BIT(31) | BIT(24) | (0x7 << 21))
#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24)
#define DWC3_GUCTL1_IP_GAP_ADD_ON(val) ((val & 0x7) << 21)
#define DWC3_GUCTL1_DEV_DECOUPLE_L1L2_EVT BIT(31)
#define DWC3_GUCTL1_SET_MASK (DWC3_GUCTL1_DEV_L1_EXIT_BY_HW | \
DWC3_GUCTL1_IP_GAP_ADD_ON(0x3) | \
DWC3_GUCTL1_DEV_DECOUPLE_L1L2_EVT)
#define USB_HOST_DWC3_GENERAL_CFG_ADDR 0X0A4F8808
#define USB3_MP_GUSB2PHYCFG_REGS_1_ADDR ((void *)0x0A40C204)
#define GUSB2PHYCFG_ENBLSLPM_BIT BIT(8)
#define USB3_MP_GUSB2PHYCFG_REGS_0_ADDR ((void *)0x0A40C200)
#define USB3_MP_PORTSC_20_REGS_0_ADDR ((void *)0x0A400420)
#define USB3_MP_PORTSC_20_REGS_1_ADDR ((void *)0x0A400430)
#define USB3_MP_PORTSC_30_REGS_0_ADDR ((void *)0x0A400440)
#define USB3_MP_PORTSC_30_REGS_1_ADDR ((void *)0x0A400450)
#define USB3_PORTSC_WCE_BIT BIT(25)
/* Initializes a specific HS PHY instance */
void hs_usb_phy_init(int index);
/* Initializes and configures the USB HOST0 controller */
void setup_usb_host0(void);
/* Enable USB GDSC/Clocks */
int qcom_enable_usb_clk(void);
/* Enable TCSR REFGEN */
void enable_clock_tcsr(void);

View file

@ -0,0 +1,498 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <console/console.h>
#include <timer.h>
#include <delay.h>
#include <soc/usb/qmp_usb_phy.h>
#include <soc/addressmap.h>
/* Only for QMP V4 PHY - QSERDES COM registers */
struct usb3_phy_qserdes_com_reg_layout {
u32 com_ssc_step_size1_mode1;
u32 com_ssc_step_size2_mode1;
u32 com_ssc_step_size3_mode1;
u32 com_clk_ep_div_mode1;
u32 com_cp_ctrl_mode1;
u32 com_pll_rctrl_mode1;
u32 com_pll_cctrl_mode1;
u32 com_coreclk_div_mode1;
u32 com_lock_cmp1_mode1;
u32 com_lock_cmp2_mode1;
u32 com_dec_start_mode1;
u32 com_dec_start_msb_mode1;
u32 com_div_frac_start1_mode1;
u32 com_div_frac_start2_mode1;
u32 com_div_frac_start3_mode1;
u32 com_hsclk_sel_1;
u32 com_integloop_gain0_mode1;
u32 com_integloop_gain1_mode1;
u32 com_vco_tune1_mode1;
u32 com_vco_tune2_mode1;
u32 com_bin_vcocal_cmp_code1_mode1;
u32 com_bin_vcocal_cmp_code2_mode1;
u32 com_bin_vcocal_cmp_code1_mode0;
u32 com_bin_vcocal_cmp_code2_mode0;
u32 com_ssc_step_size1_mode0;
u32 com_ssc_step_size2_mode0;
u32 com_ssc_step_size3_mode0;
u32 com_clk_ep_div_mode0;
u32 com_cp_ctrl_mode0;
u32 com_pll_rctrl_mode0;
u32 com_pll_cctrl_mode0;
u32 com_coreclk_div_mode0;
u32 com_lock_cmp1_mode0;
u32 com_lock_cmp2_mode0;
u32 com_dec_start_mode0;
u32 com_dec_start_msb_mode0;
u32 com_div_frac_start1_mode0;
u32 com_div_frac_start2_mode0;
u32 com_div_frac_start3_mode0;
u32 com_hsclk_hs_switch_sel_1;
u32 com_integloop_gain0_mode0;
u32 com_integloop_gain1_mode0;
u32 com_vco_tune1_mode0;
u32 com_vco_tune2_mode0;
u32 com_atb_sel1;
u32 com_atb_sel2;
u32 com_freq_update;
u32 com_bg_timer;
u32 com_ssc_en_center;
u32 com_ssc_adj_per1;
u32 com_ssc_adj_per2;
u32 com_ssc_per1;
u32 com_ssc_per2;
u8 _reserved1[20];
u32 com_sysclk_buf_enable;
u8 _reserved2[36];
u32 com_sysclk_en_sel;
u8 _reserved3[16];
u32 com_lock_cmp_cfg;
u8 _reserved4[24];
u32 com_vco_tune_map;
u8 _reserved5[44];
u32 com_core_clk_en;
u32 com_cmn_config_1;
u8 _reserved6[44];
u32 com_auto_gain_adj_ctrl_1;
u32 com_auto_gain_adj_ctrl_2;
u32 com_auto_gain_adj_ctrl_3;
u32 com_auto_gain_adj_ctrl_4;
u32 com_additional_misc;
};
check_member(usb3_phy_qserdes_com_reg_layout, com_ssc_step_size1_mode1, 0x00);
check_member(usb3_phy_qserdes_com_reg_layout, com_sysclk_buf_enable, 0xe8);
check_member(usb3_phy_qserdes_com_reg_layout, com_sysclk_en_sel, 0x110);
check_member(usb3_phy_qserdes_com_reg_layout, com_lock_cmp_cfg, 0x124);
check_member(usb3_phy_qserdes_com_reg_layout, com_integloop_gain0_mode0, 0x0a0);
check_member(usb3_phy_qserdes_com_reg_layout, com_vco_tune_map, 0x0140);
check_member(usb3_phy_qserdes_com_reg_layout, com_core_clk_en, 0x170);
check_member(usb3_phy_qserdes_com_reg_layout, com_auto_gain_adj_ctrl_1, 0x1a4);
/* Only for QMP V4 PHY - TX registers */
struct usb3_phy_qserdes_tx_reg_layout {
u8 _reserved1[52];
u32 tx_res_code_lane_tx;
u32 tx_res_code_lane_rx;
u32 tx_res_code_lane_offset_tx;
u32 tx_res_code_lane_offset_rx;
u8 _reserved2[64];
u32 tx_lane_mode_1;
u32 tx_lane_mode_2;
u32 tx_lane_mode_3;
u32 tx_lane_mode_4;
u32 tx_lane_mode_5;
u8 _reserved3[12];
u32 tx_rcv_detect_lvl_2;
u8 _reserved4[60];
u32 tx_pi_qec_ctrl;
};
check_member(usb3_phy_qserdes_tx_reg_layout, tx_res_code_lane_tx, 0x034);
check_member(usb3_phy_qserdes_tx_reg_layout, tx_lane_mode_1, 0x084);
check_member(usb3_phy_qserdes_tx_reg_layout, tx_rcv_detect_lvl_2, 0x0a4);
check_member(usb3_phy_qserdes_tx_reg_layout, tx_pi_qec_ctrl, 0x0e4);
/* Only for QMP V4 PHY - RX registers */
struct usb3_phy_qserdes_rx_reg_layout {
u8 _reserved1[8];
u32 rx_ucdr_fo_gain;
u8 _reserved2[8];
u32 rx_ucdr_so_gain;
u8 _reserved3[24];
u32 rx_ucdr_fastlock_fo_gain;
u32 rx_ucdr_so_saturation_and_enable;
u32 rx_ucdr_fo_to_so_delay;
u32 rx_ucdr_fastlock_count_low;
u32 rx_ucdr_fastlock_count_high;
u32 rx_ucdr_pi_controls;
u32 rx_ucdr_pi_ctrl2;
u32 rx_ucdr_sb2_thresh1;
u32 rx_ucdr_sb2_thresh2;
u32 rx_ucdr_sb2_gain1;
u32 rx_ucdr_sb2_gain2;
u32 rx_aux_control;
u32 rx_aux_data_tcoarse_tfine;
u8 _reserved4[112];
u32 rx_vga_cal_cntrl1;
u32 rx_vga_cal_cntrl2;
u32 rx_gm_cal;
u8 _reserved5[12];
u32 rx_rx_equ_adaptor_cntrl2;
u32 rx_rx_equ_adaptor_cntrl3;
u32 rx_rx_equ_adaptor_cntrl4;
u32 rx_rx_idac_tsettle_low;
u32 rx_rx_idac_tsettle_high;
u8 _reserved6[16];
u32 rx_rx_eq_offset_adaptor_cntrl1;
u32 rx_rx_offset_adaptor_cntrl2;
u32 rx_sigdet_enables;
u32 rx_sigdet_cntrl;
u32 rx_sigdet_lvl;
u32 rx_sigdet_deglitch_cntrl;
u8 _reserved7[52];
u32 rx_rx_mode_00_low;
u32 rx_rx_mode_00_high;
u32 rx_rx_mode_00_high2;
u32 rx_rx_mode_00_high3;
u32 rx_rx_mode_00_high4;
u32 rx_rx_mode_01_low;
u32 rx_rx_mode_01_high;
u32 rx_rx_mode_01_high2;
u32 rx_rx_mode_01_high3;
u32 rx_rx_mode_01_high4;
u32 rx_rx_mode_10_low;
u32 rx_rx_mode_10_high;
u32 rx_rx_mode_10_high2;
u32 rx_rx_mode_10_high3;
u32 rx_rx_mode_10_high4;
u8 _reserved8[8];
u32 rx_dfe_en_timer;
u32 rx_dfe_ctle_post_cal_offset;
u32 rx_dcc_ctrl1;
u32 rx_dcc_ctrl2;
u32 rx_vth_code;
u8 _reserved9[48];
u32 rx_sigdet_cal_ctrl1;
u8 _reserved10[16];
u32 rx_sigdet_cal_trim;
};
check_member(usb3_phy_qserdes_rx_reg_layout, rx_ucdr_so_gain, 0x014);
check_member(usb3_phy_qserdes_rx_reg_layout, rx_ucdr_fastlock_fo_gain, 0x030);
check_member(usb3_phy_qserdes_rx_reg_layout, rx_vga_cal_cntrl1, 0x0d4);
check_member(usb3_phy_qserdes_rx_reg_layout, rx_rx_equ_adaptor_cntrl2, 0x0ec);
check_member(usb3_phy_qserdes_rx_reg_layout, rx_rx_equ_adaptor_cntrl3, 0x0f0);
check_member(usb3_phy_qserdes_rx_reg_layout, rx_rx_equ_adaptor_cntrl4, 0x0f4);
check_member(usb3_phy_qserdes_rx_reg_layout, rx_rx_eq_offset_adaptor_cntrl1, 0x110);
check_member(usb3_phy_qserdes_rx_reg_layout, rx_sigdet_cntrl, 0x11c);
check_member(usb3_phy_qserdes_rx_reg_layout, rx_rx_mode_00_low, 0x15c);
check_member(usb3_phy_qserdes_rx_reg_layout, rx_dfe_en_timer, 0x1a0);
check_member(usb3_phy_qserdes_rx_reg_layout, rx_dcc_ctrl1, 0x1a8);
check_member(usb3_phy_qserdes_rx_reg_layout, rx_vth_code, 0x1b0);
check_member(usb3_phy_qserdes_rx_reg_layout, rx_sigdet_cal_trim, 0x1f8);
/* Only for QMP V4 PHY - PCS registers */
struct usb3_phy_pcs_reg_layout {
u32 pcs_sw_reset;
u8 _reserved1[16];
u32 pcs_pcs_status1;
u8 _reserved2[40];
u32 pcs_power_down_control;
u32 pcs_start_control;
u8 _reserved3[124];
u32 pcs_lock_detect_config1;
u32 pcs_lock_detect_config2;
u32 pcs_lock_detect_config3;
u8 _reserved4[8];
u32 pcs_lock_detect_config6;
u32 pcs_refgen_req_config1;
u8 _reserved5[168];
u32 pcs_rx_sigdet_lvl;
u8 _reserved6[4];
u32 pcs_rcvr_dtct_dly_p1u2_l;
u32 pcs_rcvr_dtct_dly_p1u2_h;
u8 _reserved7[24];
u32 pcs_cdr_reset_time;
u8 _reserved8[12];
u32 pcs_align_detect_config1;
u32 pcs_align_detect_config2;
u8 _reserved9[8];
u32 pcs_pcs_tx_rx_config;
u8 _reserved10[8];
u32 pcs_eq_config1;
u8 _reserved11[12];
u32 pcs_eq_config5;
};
check_member(usb3_phy_pcs_reg_layout, pcs_pcs_status1, 0x014);
check_member(usb3_phy_pcs_reg_layout, pcs_power_down_control, 0x040);
check_member(usb3_phy_pcs_reg_layout, pcs_lock_detect_config1, 0x0c4);
check_member(usb3_phy_pcs_reg_layout, pcs_lock_detect_config6, 0x0d8);
check_member(usb3_phy_pcs_reg_layout, pcs_rx_sigdet_lvl, 0x188);
check_member(usb3_phy_pcs_reg_layout, pcs_cdr_reset_time, 0x1b0);
check_member(usb3_phy_pcs_reg_layout, pcs_align_detect_config1, 0x1c0);
check_member(usb3_phy_pcs_reg_layout, pcs_pcs_tx_rx_config, 0x1d0);
check_member(usb3_phy_pcs_reg_layout, pcs_eq_config1, 0x1dc);
check_member(usb3_phy_pcs_reg_layout, pcs_eq_config5, 0x1ec);
struct usb3_phy_pcs_usb3_reg_layout {
u32 reserved[6];
u32 pcs_usb3_lfps_det_high_count_val;
u32 reserved1[8];
u32 pcs_usb3_rxeqtraining_dfe_time_s2;
u32 pcs_usb3_rcvr_dtct_dly_u3_l;
u32 pcs_usb3_rcvr_dtct_dly_u3_h;
};
/* Definition of the shared initialization tables using offsets */
static const qmp_phy_init_tbl_t qmp_v4_usb3_serdes_tbl[] = {
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_ssc_step_size1_mode1), 0xc0},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_ssc_step_size2_mode1), 0x01},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_cp_ctrl_mode1), 0x02},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_pll_rctrl_mode1), 0x16},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_pll_cctrl_mode1), 0x36},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_coreclk_div_mode1), 0x04},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_lock_cmp1_mode1), 0x16},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_lock_cmp2_mode1), 0x41},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_dec_start_mode1), 0x41},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_div_frac_start1_mode1), 0x55},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_div_frac_start2_mode1), 0x75},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_div_frac_start3_mode1), 0x01},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_hsclk_sel_1), 0x01},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_vco_tune1_mode1), 0x25},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_vco_tune2_mode1), 0x02},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_bin_vcocal_cmp_code1_mode1), 0x5c},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_bin_vcocal_cmp_code2_mode1), 0x0f},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_bin_vcocal_cmp_code1_mode0), 0x5c},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_bin_vcocal_cmp_code2_mode0), 0x0f},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_ssc_step_size1_mode0), 0xc0},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_ssc_step_size2_mode0), 0x01},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_cp_ctrl_mode0), 0x02},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_pll_rctrl_mode0), 0x16},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_pll_cctrl_mode0), 0x36},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_lock_cmp1_mode0), 0x08},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_lock_cmp2_mode0), 0x1a},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_dec_start_mode0), 0x41},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_div_frac_start1_mode0), 0x55},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_div_frac_start2_mode0), 0x75},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_div_frac_start3_mode0), 0x01},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_vco_tune1_mode0), 0x25},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_vco_tune2_mode0), 0x02},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_bg_timer), 0x0a},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_ssc_en_center), 0x01},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_ssc_per1), 0x62},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_ssc_per2), 0x02},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_sysclk_buf_enable), 0x0a},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_sysclk_en_sel), 0x1a},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_lock_cmp_cfg), 0x14},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_vco_tune_map), 0x04},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_core_clk_en), 0x20},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_cmn_config_1), 0x16},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_auto_gain_adj_ctrl_1), 0xb6},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_auto_gain_adj_ctrl_2), 0x4b},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_auto_gain_adj_ctrl_3), 0x37},
{(u32)offsetof(struct usb3_phy_qserdes_com_reg_layout, com_additional_misc), 0x0c},
};
static const qmp_phy_init_tbl_t qmp_v4_usb3_tx_tbl[] = {
{(u32)offsetof(struct usb3_phy_qserdes_tx_reg_layout, tx_res_code_lane_tx), 0x00},
{(u32)offsetof(struct usb3_phy_qserdes_tx_reg_layout, tx_res_code_lane_rx), 0x00},
{(u32)offsetof(struct usb3_phy_qserdes_tx_reg_layout, tx_res_code_lane_offset_tx), 0x1f},
{(u32)offsetof(struct usb3_phy_qserdes_tx_reg_layout, tx_res_code_lane_offset_rx), 0x09},
{(u32)offsetof(struct usb3_phy_qserdes_tx_reg_layout, tx_lane_mode_1), 0xf5},
{(u32)offsetof(struct usb3_phy_qserdes_tx_reg_layout, tx_lane_mode_3), 0x3f},
{(u32)offsetof(struct usb3_phy_qserdes_tx_reg_layout, tx_lane_mode_4), 0x3f},
{(u32)offsetof(struct usb3_phy_qserdes_tx_reg_layout, tx_lane_mode_5), 0x5f},
{(u32)offsetof(struct usb3_phy_qserdes_tx_reg_layout, tx_rcv_detect_lvl_2), 0x12},
{(u32)offsetof(struct usb3_phy_qserdes_tx_reg_layout, tx_pi_qec_ctrl), 0x21},
};
static const qmp_phy_init_tbl_t qmp_v4_usb3_rx_tbl[] = {
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_ucdr_fo_gain), 0x0a},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_ucdr_so_gain), 0x06},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_ucdr_fastlock_fo_gain), 0x2f},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_ucdr_so_saturation_and_enable), 0x7f},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_ucdr_fastlock_count_low), 0xff},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_ucdr_fastlock_count_high), 0x0f},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_ucdr_pi_controls), 0x99},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_ucdr_sb2_thresh1), 0x08},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_ucdr_sb2_thresh2), 0x08},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_ucdr_sb2_gain1), 0x00},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_ucdr_sb2_gain2), 0x0a},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_aux_data_tcoarse_tfine), 0xa0},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_vga_cal_cntrl1), 0x54},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_vga_cal_cntrl2), 0x0f},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_gm_cal), 0x13},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_rx_equ_adaptor_cntrl2), 0x0f},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_rx_equ_adaptor_cntrl3), 0x4a},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_rx_equ_adaptor_cntrl4), 0x0a},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_rx_idac_tsettle_low), 0x07},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_rx_idac_tsettle_high), 0x00},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_rx_eq_offset_adaptor_cntrl1), 0x47},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_sigdet_cntrl), 0x04},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_sigdet_deglitch_cntrl), 0x0e},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_rx_mode_00_low), 0x3f},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_rx_mode_00_high), 0xbf},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_rx_mode_00_high2), 0xff},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_rx_mode_00_high3), 0xdf},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_rx_mode_00_high4), 0xed},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_rx_mode_01_low), 0xdc},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_rx_mode_01_high), 0x5c},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_rx_mode_01_high2), 0x9c},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_rx_mode_01_high3), 0x1d},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_rx_mode_01_high4), 0x09},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_dfe_en_timer), 0x04},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_dfe_ctle_post_cal_offset), 0x38},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_dcc_ctrl1), 0x0c},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_vth_code), 0x10},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_sigdet_cal_ctrl1), 0x14},
{(u32)offsetof(struct usb3_phy_qserdes_rx_reg_layout, rx_sigdet_cal_trim), 0x08},
};
static const qmp_phy_init_tbl_t qmp_v4_usb3_pcs_tbl[] = {
{(u32)offsetof(struct usb3_phy_pcs_reg_layout, pcs_lock_detect_config1), 0xc4},
{(u32)offsetof(struct usb3_phy_pcs_reg_layout, pcs_lock_detect_config2), 0x89},
{(u32)offsetof(struct usb3_phy_pcs_reg_layout, pcs_lock_detect_config3), 0x20},
{(u32)offsetof(struct usb3_phy_pcs_reg_layout, pcs_lock_detect_config6), 0x13},
{(u32)offsetof(struct usb3_phy_pcs_reg_layout, pcs_refgen_req_config1), 0x21},
{(u32)offsetof(struct usb3_phy_pcs_reg_layout, pcs_rx_sigdet_lvl), 0xaa},
{(u32)offsetof(struct usb3_phy_pcs_reg_layout, pcs_rcvr_dtct_dly_p1u2_l), 0xe7},
{(u32)offsetof(struct usb3_phy_pcs_reg_layout, pcs_rcvr_dtct_dly_p1u2_h), 0x03},
{(u32)offsetof(struct usb3_phy_pcs_reg_layout, pcs_cdr_reset_time), 0x0a},
{(u32)offsetof(struct usb3_phy_pcs_reg_layout, pcs_align_detect_config1), 0x88},
{(u32)offsetof(struct usb3_phy_pcs_reg_layout, pcs_align_detect_config2), 0x13},
{(u32)offsetof(struct usb3_phy_pcs_reg_layout, pcs_pcs_tx_rx_config), 0x0c},
{(u32)offsetof(struct usb3_phy_pcs_reg_layout, pcs_eq_config1), 0x4b},
{(u32)offsetof(struct usb3_phy_pcs_reg_layout, pcs_eq_config5), 0x10},
};
static const qmp_phy_init_tbl_t qmp_v4_usb3_pcs_usb3_tbl[] = {
{(u32)offsetof(struct usb3_phy_pcs_usb3_reg_layout, pcs_usb3_lfps_det_high_count_val), 0xf8},
{(u32)offsetof(struct usb3_phy_pcs_usb3_reg_layout, pcs_usb3_rxeqtraining_dfe_time_s2), 0x07},
{(u32)offsetof(struct usb3_phy_pcs_usb3_reg_layout, pcs_usb3_rcvr_dtct_dly_u3_l), 0x40},
{(u32)offsetof(struct usb3_phy_pcs_usb3_reg_layout, pcs_usb3_rcvr_dtct_dly_u3_h), 0x00},
};
/* Global instances of PHY data with their respective configuration tables */
static const struct ss_usb_phy_reg qmp_phy_instances[] = {
{
.com_base = (void *)QMP_PHY_MP0_QSERDES_COM_REG_BASE,
.tx_base = (void *)QMP_PHY_MP0_QSERDES_TX_REG_BASE,
.rx_base = (void *)QMP_PHY_MP0_QSERDES_RX_REG_BASE,
.pcs_base = (void *)QMP_PHY_MP0_PCS_REG_BASE,
.pcs_usb3_base = (void *)QMP_PHY_MP0_PCS_USB3_REG_BASE,
.name = "MP0",
.serdes_tbl = qmp_v4_usb3_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(qmp_v4_usb3_serdes_tbl),
.tx_tbl = qmp_v4_usb3_tx_tbl,
.tx_tbl_num = ARRAY_SIZE(qmp_v4_usb3_tx_tbl),
.rx_tbl = qmp_v4_usb3_rx_tbl,
.rx_tbl_num = ARRAY_SIZE(qmp_v4_usb3_rx_tbl),
.pcs_tbl = qmp_v4_usb3_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(qmp_v4_usb3_pcs_tbl),
.pcs_usb3_tbl = qmp_v4_usb3_pcs_usb3_tbl,
.pcs_usb3_tbl_num = ARRAY_SIZE(qmp_v4_usb3_pcs_usb3_tbl),
},
{
.com_base = (void *)QMP_PHY_MP1_QSERDES_COM_REG_BASE,
.tx_base = (void *)QMP_PHY_MP1_QSERDES_TX_REG_BASE,
.rx_base = (void *)QMP_PHY_MP1_QSERDES_RX_REG_BASE,
.pcs_base = (void *)QMP_PHY_MP1_PCS_REG_BASE,
.pcs_usb3_base = (void *)QMP_PHY_MP1_PCS_USB3_REG_BASE,
.name = "MP1",
.serdes_tbl = qmp_v4_usb3_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(qmp_v4_usb3_serdes_tbl),
.tx_tbl = qmp_v4_usb3_tx_tbl,
.tx_tbl_num = ARRAY_SIZE(qmp_v4_usb3_tx_tbl),
.rx_tbl = qmp_v4_usb3_rx_tbl,
.rx_tbl_num = ARRAY_SIZE(qmp_v4_usb3_rx_tbl),
.pcs_tbl = qmp_v4_usb3_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(qmp_v4_usb3_pcs_tbl),
.pcs_usb3_tbl = qmp_v4_usb3_pcs_usb3_tbl,
.pcs_usb3_tbl_num = ARRAY_SIZE(qmp_v4_usb3_pcs_usb3_tbl),
},
};
/* Modified configure function to accept a base address for the current block */
static void qcom_qmp_phy_configure(void *base_addr, const qmp_phy_init_tbl_t tbl[], unsigned int num)
{
int i;
const qmp_phy_init_tbl_t *t = tbl;
if (!t)
return;
for (i = 0; i < num; i++, t++)
write32((void *)((unsigned long)base_addr + t->offset), t->val);
}
/* Unified PHY initialization function that takes PHY instance data */
static bool ss_qmp_phy_init_common(const struct ss_usb_phy_reg *ss_phy_reg)
{
bool ret = true;
/* Use the PCS base address from ss_phy_reg to cast to the PCS register layout */
struct usb3_phy_pcs_reg_layout *current_pcs_reg = (struct usb3_phy_pcs_reg_layout *)ss_phy_reg->pcs_base;
printk(BIOS_DEBUG, "QMP PHY %s init\n", ss_phy_reg->name);
/* power up USB3 PHY */
write32(&current_pcs_reg->pcs_power_down_control, 0x01);
/* Serdes configuration */
qcom_qmp_phy_configure(ss_phy_reg->com_base, ss_phy_reg->serdes_tbl,
ss_phy_reg->serdes_tbl_num);
/* Tx, Rx, and PCS configurations */
qcom_qmp_phy_configure(ss_phy_reg->pcs_base, ss_phy_reg->pcs_tbl,
ss_phy_reg->pcs_tbl_num);
qcom_qmp_phy_configure(ss_phy_reg->tx_base, ss_phy_reg->tx_tbl,
ss_phy_reg->tx_tbl_num);
qcom_qmp_phy_configure(ss_phy_reg->rx_base, ss_phy_reg->rx_tbl,
ss_phy_reg->rx_tbl_num);
qcom_qmp_phy_configure(ss_phy_reg->pcs_usb3_base, ss_phy_reg->pcs_usb3_tbl,
ss_phy_reg->pcs_usb3_tbl_num);
udelay(100);
/* perform software reset of PCS/Serdes */
write32(&current_pcs_reg->pcs_sw_reset, 0x00);
/* start PCS/Serdes to operation mode */
write32(&current_pcs_reg->pcs_start_control, 0x03);
udelay(100);
/*
* Wait for PHY initialization to be done
* PCS_STATUS: wait for 1ms for PHY STATUS;
* SW can continuously check for PHYSTATUS = 1.b0.
*/
long lock_us = wait_us(10000,
!(read32(&current_pcs_reg->pcs_pcs_status1)&
USB3_PCS_PHYSTATUS));
if (!lock_us) {
ret = false;
printk(BIOS_ERR, "QMP PHY %s PLL LOCK fails:\n", ss_phy_reg->name);
} else {
printk(BIOS_DEBUG, "QMP PHY %s initialized and locked in %ldus\n",
ss_phy_reg->name, lock_us);
}
return ret;
}
/* Unified ss_qmp_phy_init function to initialize a specific PHY instance
Pass 0 for MP0, or 1 for MP1. */
bool ss_qmp_phy_init(u32 phy_idx)
{
bool ret = true;
/* Ensure the provided index is valid */
if (phy_idx >= ARRAY_SIZE(qmp_phy_instances)) {
printk(BIOS_ERR, "Invalid PHY index provided: %u\n", phy_idx);
return false;
}
if (!ss_qmp_phy_init_common(&qmp_phy_instances[phy_idx])) {
ret = false;
}
return ret;
}

View file

@ -0,0 +1,239 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <console/console.h>
#include <soc/usb/snps_usb_phy.h>
#include <soc/addressmap.h>
#include <commonlib/helpers.h>
#include <soc/usb/usb.h>
#include <delay.h>
#define SLEEPM BIT(0)
#define TERMSEL BIT(5)
#define POR BIT(1)
/* Updated FSEL_MASK based on the table feedback (GENMASK(6,4) for 38.4MHz) */
#define FSEL_MASK GENMASK(6, 4)
#define FSEL_DEFAULT (0x3 << 4) /* Original value, may not be used directly */
#define VBUSVLDEXTSEL0 BIT(4)
#define PLLBTUNE BIT(5)
#define VREGBYPASS BIT(0)
#define VBUSVLDEXT0 BIT(0)
/* Updated macros for clarity as per feedback */
#define USB2_SUSPEND_N_BIT BIT(2)
#define USB2_SUSPEND_N_SEL_BIT BIT(3)
#define UTMI_PHY_CMN_CTRL_OVERRIDE_EN BIT(1)
#define REFCLK_SEL_MASK GENMASK(1, 0)
#define REFCLK_SEL_DEFAULT (0x2 << 0)
#define PARAM_OVRD_MASK 0xFF
/* Streamlined macros for common control bits (from previous feedback) */
#define USB_PHY_ENABLE_BIT BIT(0)
#define USB_PHY_RETENABLEN_BIT BIT(3)
#define APB_LOGIC_RESET_BIT BIT(2)
#define TESTBURNIN_BIT BIT(6)
#define FSEL_SEL_BIT BIT(0)
/* New macros from table requirements (to be used in sequence) */
#define FSEL_38_4_MHZ_VAL (0x4 << 4) /* 3'b100 for bits 6:4 -> 0x4, shifted by 4 */
#define SIDDQ_SEL_BIT BIT(1)
#define SIDDQ_DISABLE_BIT BIT(2) /* SIDDQ is set to 0, means power up analog blocks */
#define CFG_CTRL_2_VALUE 0xC8 /* For phy_cfg_pll_fb_div_7_0 */
#define CFG_CTRL_3_FB_DIV_MASK GENMASK(3, 0)
#define CFG_CTRL_3_FB_DIV_VALUE 0x0 /* 4'b0000 */
#define CFG_CTRL_3_REF_DIV_MASK GENMASK(7, 4)
#define CFG_CTRL_3_REF_DIV_VALUE (0x0 << 4) /* 4'b0000 shifted to bits 7:4 */
#define CFG_CTRL_1_PLL_CPBIAS_MASK GENMASK(7, 1)
#define CFG_CTRL_1_PLL_CPBIAS_VALUE (0x0 << 1) /* 7'b0000000 shifted to bits 7:1 */
#define CFG_CTRL_4_PLL_VCO_GAIN_MASK GENMASK(1, 0)
#define CFG_CTRL_4_PLL_VCO_GAIN_VALUE 0x1 /* 2'b01 */
#define CFG_CTRL_4_PLL_INT_GAIN_MASK GENMASK(7, 2)
#define CFG_CTRL_4_PLL_INT_GAIN_VALUE (0x8 << 2) /* 6'b001000 shifted to bits 7:2 */
#define CFG_CTRL_5_PLL_PROP_GAIN_MASK GENMASK(5, 0)
#define CFG_CTRL_5_PLL_PROP_GAIN_VALUE 0x10 /* 6'b010000 */
#define CFG_CTRL_6_PLL_VCO_CFG_MASK GENMASK(2, 0)
#define CFG_CTRL_6_PLL_VCO_CFG_VALUE 0x0 /* 3'b000 */
#define CFG_CTRL_5_PLL_VREF_TUNE_MASK GENMASK(7, 6)
#define CFG_CTRL_5_PLL_VREF_TUNE_VALUE (0x1 << 6) /* 2'b01 shifted to bits 7:6 */
#define VBUS_DET_EXT_SEL_BIT BIT(4)
#define VBUS_VALID_EXT_BIT BIT(0)
#define CFG_CTRL_9_TX_PREEMP_MASK GENMASK(2, 0)
#define CFG_CTRL_9_TX_PREEMP_VALUE 0x0 /* 3'b000 */
#define CFG_CTRL_8_TX_HS_VREF_MASK GENMASK(5, 3)
#define CFG_CTRL_8_TX_HS_VREF_VALUE (0x3 << 3) /* 3'b011 shifted to bits 5:3 */
#define CFG_CTRL_9_TX_RISE_TUNE_MASK GENMASK(6, 5)
#define CFG_CTRL_9_TX_RISE_TUNE_VALUE (0x2 << 5) /* 2'b10 shifted to bits 6:5 */
#define CFG_CTRL_8_TX_HS_XV_TUNE_MASK GENMASK(7, 6)
#define CFG_CTRL_8_TX_HS_XV_TUNE_VALUE (0x0 << 6) /* 2'b00 shifted to bits 7:6 */
#define CFG_CTRL_9_TX_RES_TUNE_MASK GENMASK(4, 3)
#define CFG_CTRL_9_TX_RES_TUNE_VALUE (0x1 << 3) /* 2'b01 shifted to bits 4:3 */
struct hs_usb_phy_reg *hs_phy_reg = NULL;
void hs_usb_phy_init(int index)
{
if (index == 0)
hs_phy_reg = (void *)HS_USB_MP0_PHY_BASE;
else
hs_phy_reg = (void *)HS_USB_MP1_PHY_BASE;
/*
* This sequence initializes the USB HS PHY.
*/
/* Step 1: USB_PHY_CFG0[1] = 1'b1 (UTMI_PHY_CMN_CNTRL_OVERRIDE_EN=1) */
/* This is a MUX select signal to enable software override of UTMI PHY common control. */
clrsetbits32(&hs_phy_reg->cfg0, UTMI_PHY_CMN_CTRL_OVERRIDE_EN,
UTMI_PHY_CMN_CTRL_OVERRIDE_EN);
/* Step 2: USB_PHY_UTMI_CTRL5[1] = 1'b1 (POR asserted) */
/* Assert the PHY reset. This reset must be held for at least 10us after all supplies ramp up. */
clrsetbits32(&hs_phy_reg->utmi_ctrl5, POR, POR);
udelay(10); /* Hold POR for 10us */
/* Step 3: USB_PHY_HS_PHY_CTRL_COMMON0[0] = 1'b1 (phy_enable='1') */
/* Asynchronous enable for the PHY. If low during POR de-assertion, PHY remains inactive. */
clrsetbits32(&hs_phy_reg->hs_phy_ctrl_common0, USB_PHY_ENABLE_BIT, USB_PHY_ENABLE_BIT);
/* Step 4: USB_PHY_HS_PHY_CTRL_COMMON0[3] = 1'b1 (Retention Mode Enable) */
/* Set retenable_n = 1'b1. This signal must be high when VDD supply is powered. */
clrsetbits32(&hs_phy_reg->hs_phy_ctrl_common0, USB_PHY_RETENABLEN_BIT, USB_PHY_RETENABLEN_BIT);
/* Step 5: USB_PHY_APB_ACCESS_CMD[2] = 1'b1 (APB Logic Reset) */
/* Reset all APB related logic, including SNPS APB FSM but not the APB registers. */
clrsetbits32(&hs_phy_reg->usb_phy_apb_access_cmd, APB_LOGIC_RESET_BIT, APB_LOGIC_RESET_BIT);
/* Step 6: UTMI_PHY_CMN_CTRL0[6] = 1'b0 (Burn-in Test Enable - clear the bit) */
/* De-assert test_burnin. If asserted, PHY performs power-on-reset and enters HS Loopback mode. */
clrsetbits32(&hs_phy_reg->utmi_phy_cmn_ctrl0, TESTBURNIN_BIT, 0);
/* Step 7: USB_PHY_FSEL_SEL = 1'b1 (FSEL MUX select for SW override) */
/* Select software override for frequency selection. */
clrsetbits32(&hs_phy_reg->usb_phy_fsel_sel, FSEL_SEL_BIT, FSEL_SEL_BIT);
/* Step 8: USB_PHY_HS_PHY_CTRL_COMMON0[6:4] = 3'b100 (Sets refclk frequency to 38.4 MHz) */
/* Configure the reference clock frequency. */
clrsetbits32(&hs_phy_reg->hs_phy_ctrl_common0, FSEL_MASK, FSEL_38_4_MHZ_VAL);
/* Step 9: USB_PHY_CFG_CTRL_2[7:0] = 8'b11001000 (Control of the feedback multiplication ratio) */
/* Configure phy_cfg_pll_fb_div_7_0. */
clrsetbits32(&hs_phy_reg->cfg_ctrl_2, 0xFF, CFG_CTRL_2_VALUE); /* Using 0xFF for full 8-bit mask */
/* Step 10: USB_PHY_CFG_CTRL_3[3:0] = 4'b0000 (Control of the feedback multiplication ratio) */
/* Configure phy_cfg_pll_fb_div_11_8. */
clrsetbits32(&hs_phy_reg->cfg_ctrl_3, CFG_CTRL_3_FB_DIV_MASK, CFG_CTRL_3_FB_DIV_VALUE);
/* Step 11: USB_PHY_CFG_CTRL_3[7:4] = 4'b0000 (Control of the input frequency division ratio) */
/* Configure phy_cfg_pll_ref_div. */
clrsetbits32(&hs_phy_reg->cfg_ctrl_3, CFG_CTRL_3_REF_DIV_MASK, CFG_CTRL_3_REF_DIV_VALUE);
/* Step 12: USB_PHY_CFG_CTRL_1[7:1] = 7'b0000000 (PLL loop bias configuration) */
/* Configure phy_cfg_pll_cpbias_cntrl. */
clrsetbits32(&hs_phy_reg->cfg_ctrl_1, CFG_CTRL_1_PLL_CPBIAS_MASK, CFG_CTRL_1_PLL_CPBIAS_VALUE);
/* Step 13: USB_PHY_CFG_CTRL_4[1:0] = 2'b01 (PLL vco source gain) */
/* Configure phy_cfg_pll_gmp_cntrl. */
clrsetbits32(&hs_phy_reg->cfg_ctrl_4, CFG_CTRL_4_PLL_VCO_GAIN_MASK, CFG_CTRL_4_PLL_VCO_GAIN_VALUE);
/* Step 14: USB_PHY_CFG_CTRL_4[7:2] = 6'b001000 (Gain of PLL Integral Charge Pump) */
/* Configure phy_cfg_pll_int_cntrl. */
clrsetbits32(&hs_phy_reg->cfg_ctrl_4, CFG_CTRL_4_PLL_INT_GAIN_MASK, CFG_CTRL_4_PLL_INT_GAIN_VALUE);
/* Step 15: USB_PHY_CFG_CTRL_5[5:0] = 6'b010000 (Gain of PLL Proportional Charge Pump) */
/* Configure phy_cfg_pll_prop_cntrl. */
clrsetbits32(&hs_phy_reg->cfg_ctrl_5, CFG_CTRL_5_PLL_PROP_GAIN_MASK, CFG_CTRL_5_PLL_PROP_GAIN_VALUE);
/* Step 16: USB_PHY_CFG_CTRL_6[2:0] = 3'b000 (PLL VCO configuration) */
/* Configure phy_cfg_pll_vco_cntrl. */
clrsetbits32(&hs_phy_reg->cfg_ctrl_6, CFG_CTRL_6_PLL_VCO_CFG_MASK, CFG_CTRL_6_PLL_VCO_CFG_VALUE);
/* Step 17: USB_PHY_CFG_CTRL_5[7:6] = 2'b01 (Configuration for PLL voltage reference level) */
/* Configure phy_cfg_pll_vref_tune. */
clrsetbits32(&hs_phy_reg->cfg_ctrl_5, CFG_CTRL_5_PLL_VREF_TUNE_MASK, CFG_CTRL_5_PLL_VREF_TUNE_VALUE);
/* Step 18: Selects UTMI data bus width. Wordinterface<#> = 0; for 8 bits interface (60 MHz)
* No register control, tied at chip top.
*/
/* Step 19: USB_PHY_HS_PHY_CTRL2[4] = 1'b1 (VBUS MUX Selection) */
/* Select software control for VBUS detection. */
clrsetbits32(&hs_phy_reg->hs_phy_ctrl2, VBUS_DET_EXT_SEL_BIT, VBUS_DET_EXT_SEL_BIT);
/* Step 20: USB_PHY_HS_PHY_CTRL2[0] = 1'b1 (VBUS valid indication) */
/* Software writes this bit to indicate VBUS status. */
clrsetbits32(&hs_phy_reg->hs_phy_ctrl2, VBUS_VALID_EXT_BIT, VBUS_VALID_EXT_BIT);
/* Step 21: USB_PHY_CFG_CTRL_9[2:0] = 3'b000 (HS Transmitter Pre-Emphasis Control) */
/* Set HS Transmitter pre-emphasis to off (design default). */
clrsetbits32(&hs_phy_reg->cfg_ctrl_9, CFG_CTRL_9_TX_PREEMP_MASK, CFG_CTRL_9_TX_PREEMP_VALUE);
/* Step 22: USB_PHY_CFG_CTRL_8[5:3] = 3'b011 (HS DC Voltage Level Adjustment) */
/* Set HS DC Voltage Level to default (increased). */
clrsetbits32(&hs_phy_reg->cfg_ctrl_8, CFG_CTRL_8_TX_HS_VREF_MASK, CFG_CTRL_8_TX_HS_VREF_VALUE);
/* Step 23: USB_PHY_CFG_CTRL_9[6:5] = 2'b10 (HS Transmitter Rise/Fall Time Adjustment) */
/* Set HS Transmitter Rise/Fall Time Adjustment to default. */
clrsetbits32(&hs_phy_reg->cfg_ctrl_9, CFG_CTRL_9_TX_RISE_TUNE_MASK, CFG_CTRL_9_TX_RISE_TUNE_VALUE);
/* Step 24: USB_PHY_CFG_CTRL_8[7:6] = 2'b00 (Transmitter High-Speed Crossover Adjustment) */
/* Set Transmitter High-Speed Crossover Adjustment to default (0V). */
clrsetbits32(&hs_phy_reg->cfg_ctrl_8, CFG_CTRL_8_TX_HS_XV_TUNE_MASK, CFG_CTRL_8_TX_HS_XV_TUNE_VALUE);
/* Step 25: USB_PHY_CFG_CTRL_9[4:3] = 2'b01 (USB Source Impedance Adjustment) */
/* Set USB Source Impedance Adjustment to default. */
clrsetbits32(&hs_phy_reg->cfg_ctrl_9, CFG_CTRL_9_TX_RES_TUNE_MASK, CFG_CTRL_9_TX_RES_TUNE_VALUE);
/* Step 26: USB_PHY_HS_PHY_CTRL2[3] = 1'b1 (USB2_SUSPEND_N_SEL) */
/* Select SW option for suspend_n signal. */
clrsetbits32(&hs_phy_reg->hs_phy_ctrl2, USB2_SUSPEND_N_SEL_BIT, USB2_SUSPEND_N_SEL_BIT);
/* Step 27: USB_PHY_HS_PHY_CTRL2[2] = 1'b1 (USB2_SUSPEND_N) */
/* Assert USB2_SUSPEND_N. */
clrsetbits32(&hs_phy_reg->hs_phy_ctrl2, USB2_SUSPEND_N_BIT, USB2_SUSPEND_N_BIT);
/* Step 28: USB_PHY_UTMI_CTRL0[0] = 1'b1 (SLEEPM) */
/* Set sleepm = 1; until PHYCLOCK is available. */
clrsetbits32(&hs_phy_reg->utmi_ctrl0, SLEEPM, SLEEPM);
/* Step 29: USB_PHY_HS_PHY_CTRL_COMMON0[1] = 1'b1 (SIDDQ MUX Selection) */
/* Select internal CSR register (SIDDQ) for SIDDQ control. */
clrsetbits32(&hs_phy_reg->hs_phy_ctrl_common0, SIDDQ_SEL_BIT, SIDDQ_SEL_BIT);
/* Step 30: USB_PHY_HS_PHY_CTRL_COMMON0[2] = 1'b0 (SIDDQ set to 0) */
/* Power up the analog blocks by setting SIDDQ to 0. */
clrsetbits32(&hs_phy_reg->hs_phy_ctrl_common0, SIDDQ_DISABLE_BIT, 0);
/* Step 31: USB_PHY_UTMI_CTRL5[1] = 1'b0 (POR release) */
/* Release the POR from high to low. */
clrsetbits32(&hs_phy_reg->utmi_ctrl5, POR, 0);
/* Step 32: USB_PHY_HS_PHY_CTRL2[3] = 1'b0 (USB2_SUSPEND_N_SEL de-selects SW override) */
/* De-select SW override for suspend_n, allowing HW control. */
clrsetbits32(&hs_phy_reg->hs_phy_ctrl2, USB2_SUSPEND_N_SEL_BIT, 0);
udelay(20);
printk(BIOS_DEBUG, "USB HS PHY initialized for index %d\n", index);
}

View file

@ -0,0 +1,327 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <console/console.h>
#include <device/mmio.h>
#include <soc/usb/usb.h>
#include <soc/addressmap.h>
#include <soc/clock.h>
#include <delay.h>
#include <gpio.h>
struct usb_dwc3 {
u32 sbuscfg0;
u32 sbuscfg1;
u32 txthrcfg;
u32 rxthrcfg;
u32 ctl;
u32 pmsts;
u32 sts;
u32 uctl1;
u32 snpsid;
u32 gpio;
u32 uid;
u32 uctl;
u64 buserraddr;
u64 prtbimap;
u8 reserved1[32];
u32 dbgfifospace;
u32 dbgltssm;
u32 dbglnmcc;
u32 dbgbmu;
u32 dbglspmux;
u32 dbglsp;
u32 dbgepinfo0;
u32 dbgepinfo1;
u64 prtbimap_hs;
u64 prtbimap_fs;
u8 reserved2[112];
u32 usb2phycfg;
u32 usb2phycfg_mp1;
u8 reserved3[120];
u32 usb2phyacc;
u8 reserved4[60];
u32 usb3pipectl;
u32 usb3pipectl_mp1;
u8 reserved5[56];
};
check_member(usb_dwc3, usb2phycfg_mp1, 0x104);
check_member(usb_dwc3, usb3pipectl_mp1, 0x1c4);
struct usb_dwc3_cfg {
struct usb_dwc3 *usb_host_dwc3;
u32 *usb3_bcr;
u32 *qusb2phy_bcr;
u32 *qusb2phy1_bcr;
u32 *gcc_usb3phy_bcr_reg;
u32 *gcc_qmpphy_bcr_reg;
u32 *gcc_usb3phy1_bcr_reg;
u32 *gcc_qmpphy1_bcr_reg;
u32 *qusb2secphy_bcr;
u32 *gcc_usb3secphy_bcr_reg;
u32 *gcc_qmpsecphy_bcr_reg;
};
static struct usb_dwc3_cfg usb_port0 = {
.usb_host_dwc3 = (void *)USB_HOST_DWC3_BASE,
.usb3_bcr = &gcc->gcc_usb30_mp_bcr,
.qusb2phy_bcr = &gcc->qusb2phy_hs0_mp_bcr,
.gcc_usb3phy_bcr_reg = &gcc->usb3uniphy_phy_mp0_bcr,
.gcc_qmpphy_bcr_reg = &gcc->usb3_uniphy_mp0_bcr,
.qusb2phy1_bcr = &gcc->qusb2phy_hs1_mp_bcr,
.gcc_usb3phy1_bcr_reg = &gcc->usb3uniphy_phy_mp1_bcr,
.gcc_qmpphy1_bcr_reg = &gcc->usb3_uniphy_mp1_bcr,
};
bool hs_speed_only = false;
u32 *usb3_general_cfg_addr = (void *)USB_HOST_DWC3_GENERAL_CFG_ADDR;
/* Enables Repeaters /Refgen blocks for USB */
void enable_clock_tcsr(void)
{
write32(TCSR_GCC_CXO_1_REFGEN_BIAS_SEL__SEL_REFGEN_ADDR, 0x00000001);
write32(TCSR_GCC_CXO_0_REFGEN_BIAS_SEL__SEL_REFGEN_ADDR, 0x00000001);
write32(TCSR_QREFS_CXO_0_RPT3_CONFIG_ADDR, 0x3);
write32(TCSR_QREFS_CXO_0_RPT4_CONFIG_ADDR, 0x3);
write32(TCSR_QREFS_CXO_1_RPT0_CONFIG_ADDR, 0x3);
write32(TCSR_QREFS_CXO_1_RX3_CONFIG_ADDR, 0x3);
write32(TCSR_QREFS_CXO_1_RX0_CONFIG_ADDR, 0x3);
write32(TCSR_QREFS_CXO_0_RX3_CONFIG_ADDR, 0x3);
write32(TCSR_QREFS_CXO_0_RX4_CONFIG_ADDR, 0x3);
}
/*
* qcom_enable_usb_clk - Enables USB clocks and GDSCs for Qualcomm SoCs.
* @return 0 on success, or a negative error code on failure.
*/
int32_t qcom_enable_usb_clk(void)
{
int32_t ret, clk, gdsc;
/* Enable USB GDSCs before enabling USB clocks */
for (gdsc = USB30_MP_GDSC; gdsc < MAX_USB_GDSC; gdsc++) {
ret = clock_enable_usb_gdsc(gdsc);
if (ret) {
printk(BIOS_ERR, "Failed to enable USB GDSC %d\n", gdsc);
return ret;
}
}
clock_configure_usb();
/* Set USB3 PHY PIPE 0 clock source to X0 */
if (usb_clock_configure_mux(USB3_PHY_PIPE_0, USB_PHY_XO_SRC_SEL)) {
printk(BIOS_ERR, "%s(): USB3 PHY PIPE 0 clock enable failed\n", __func__);
return -1;
}
if (usb_clock_configure_mux(USB3_PHY_PIPE_1, USB_PHY_XO_SRC_SEL)) {
printk(BIOS_ERR, "%s(): USB3 PHY PIPE 0 clock enable failed\n", __func__);
return -1;
}
/* Enable USB MP clocks */
for (clk = USB30_MP_MASTER_CBCR; clk < USB_CLK_COUNT; clk++) {
ret = usb_clock_enable(clk);
if (ret) {
printk(BIOS_ERR, "Failed to enable %d clock\n", clk);
return ret;
}
}
write32(TCSR_GCC_USB3_MP0_CLKREF_EN_ADDR, USB3_CLKREF_ENABLE_VALUE);
write32(TCSR_GCC_USB3_MP1_CLKREF_EN_ADDR, USB3_CLKREF_ENABLE_VALUE);
/* Set USB3 PHY PIPE 1 clock source to USB PHY */
if (usb_clock_configure_mux(USB3_PHY_PIPE_0, USB_PHY_PIPE_SRC_SEL)) {
printk(BIOS_ERR, "%s(): USB3 PHY PIPE 1 clock enable failed\n", __func__);
return -1;
}
if (usb_clock_configure_mux(USB3_PHY_PIPE_1, USB_PHY_PIPE_SRC_SEL)) {
printk(BIOS_ERR, "%s(): USB3 PHY PIPE 1 clock enable failed\n", __func__);
return -1;
}
return ret;
}
/*
* setup_dwc3 - Configures the DWC3 USB controller.
* @dwc3: Pointer to the USB DWC3 configuration structure.
* Handles high-speed operation, power management, and sets to host mode.
*/
static void setup_dwc3(struct usb_dwc3 *dwc3)
{
u32 *reg = usb3_general_cfg_addr;
if (hs_speed_only) {
/* Set UTMI_CLK_DIS_0 */
setbits32(reg, UTMI_CLK_DIS_0);
udelay(10);
/* Set UTMI_CLK_SEL_0 */
setbits32(reg, UTMI_CLK_SEL_0);
/* Set PIPE3_PHYSTATUS_SW_0 */
setbits32(reg, PIPE3_PHYSTATUS_SW_0);
/* Clear PIPE3_SET_PHYSTATUS_SW_0 */
clrbits32(reg, PIPE3_SET_PHYSTATUS_SW_0);
udelay(10);
/* Clear UTMI_CLK_DIS_0 */
clrbits32(reg, UTMI_CLK_DIS_0);
} else {
/* core exits U1/U2/U3 only in PHY power state P1/P2/P3 respectively */
clrsetbits32(&dwc3->usb3pipectl,
DWC3_GUSB3PIPECTL_DELAYP1TRANS,
DWC3_GUSB3PIPECTL_UX_EXIT_IN_PX);
clrsetbits32(&dwc3->usb3pipectl_mp1,
DWC3_GUSB3PIPECTL_DELAYP1TRANS,
DWC3_GUSB3PIPECTL_UX_EXIT_IN_PX);
}
/*
* Configure USB phy interface of DWC3 core.
* 1. Select UTMI+ PHY with 16-bit interface.
* 2. Set USBTRDTIM to the corresponding value
* according to the UTMI+ PHY interface.
*/
clrsetbits32(&dwc3->usb2phycfg,
(DWC3_GUSB2PHYCFG_USB2TRDTIM_MASK |
DWC3_GUSB2PHYCFG_PHYIF_MASK |
DWC3_GUSB2PHYCFG_ENBLSLPM_MASK),
(DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) |
DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT)));
clrsetbits32(&dwc3->usb2phycfg_mp1,
(DWC3_GUSB2PHYCFG_USB2TRDTIM_MASK |
DWC3_GUSB2PHYCFG_PHYIF_MASK |
DWC3_GUSB2PHYCFG_ENBLSLPM_MASK),
(DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) |
DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT)));
/*
To save power, enable the hardware-based clock gating (not relevant for PBL):
a. usb30_reg_cgctl[DBM_FSM_EN] = 0x1
*/
setbits32(USB3_MP_CGCTL_REG_ADDR, USB3_MP_DBM_FSM_EN_BIT);
//Disable clock gating: DWC_USB3_GCTL.DSBLCLKGTNG = 1
clrsetbits32(&dwc3->ctl, (DWC3_GCTL_SCALEDOWN_MASK |
DWC3_GCTL_DISSCRAMBLE),
DWC3_GCTL_U2EXIT_LFPS | DWC3_GCTL_DSBLCLKGTNG);
//Allow PHY to transition to P2 from suspend (P3) state.
setbits32(&dwc3->usb3pipectl,
(DWC3_GUSB3PIPECTL_P3EXSIGP2|
DWC3_GUSB3PIPECTL_UX_EXIT_IN_PX));
setbits32(&dwc3->usb3pipectl_mp1,
(DWC3_GUSB3PIPECTL_P3EXSIGP2|
DWC3_GUSB3PIPECTL_UX_EXIT_IN_PX));
// Reduce U3 exit handshake timer to 300ns
clrsetbits32(USB3_MP_LINK_REGS_0_LU3LFPSRXTIM_ADDR,
LFPS_RSP_RX_CLK_CLR_MASK, LFPS_RSP_RX_CLK_SET_MASK);
clrsetbits32(USB3_MP_LINK_REGS_1_LU3LFPSRXTIM_ADDR,
LFPS_RSP_RX_CLK_CLR_MASK, LFPS_RSP_RX_CLK_SET_MASK);
clrsetbits32(&dwc3->uctl1,
DWC3_GUCTL1_CLR_MASK, // Clear L1 exit and IP gap bits
DWC3_GUCTL1_SET_MASK);
clrbits32(USB3_MP_GUSB2PHYCFG_REGS_0_ADDR, GUSB2PHYCFG_ENBLSLPM_BIT);
clrbits32(USB3_MP_GUSB2PHYCFG_REGS_1_ADDR, GUSB2PHYCFG_ENBLSLPM_BIT);
/* configure controller in Host mode */
clrsetbits32(&dwc3->ctl, (DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)),
DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_HOST));
printk(BIOS_SPEW, "Configure USB in Host mode\n");
setbits32(USB3_MP_PORTSC_20_REGS_0_ADDR, USB3_PORTSC_WCE_BIT);
setbits32(USB3_MP_PORTSC_20_REGS_1_ADDR, USB3_PORTSC_WCE_BIT);
setbits32(USB3_MP_PORTSC_30_REGS_0_ADDR, USB3_PORTSC_WCE_BIT);
setbits32(USB3_MP_PORTSC_30_REGS_1_ADDR, USB3_PORTSC_WCE_BIT);
}
/* Initialization of DWC3 Core and PHY */
static void setup_usb_host(struct usb_dwc3_cfg *dwc3)
{
/* Call Clock Enable */
qcom_enable_usb_clk();
enable_clock_tcsr();
/* Clear core reset. */
clock_reset_bcr(dwc3->usb3_bcr, 1);
udelay(10);
clock_reset_bcr(dwc3->usb3_bcr, 0);
udelay(10);
/* Repeater enable MP0*/
gpio_output(GPIO(6), 0x1);
/* Repeater enable MP1*/
gpio_output(GPIO(184), 0x1);
/* Clear QUSB PHY reset. */
clock_reset_bcr(dwc3->qusb2phy_bcr, 1);
clock_reset_bcr(dwc3->qusb2phy1_bcr, 1);
udelay(10);
clock_reset_bcr(dwc3->qusb2phy_bcr, 0);
clock_reset_bcr(dwc3->qusb2phy1_bcr, 0);
/* Initialize HS PHY */
hs_usb_phy_init(0);
hs_usb_phy_init(1);
/* Clear QMP PHY resets. */
usb_clock_reset(USB3_MP_PHY_PIPE_0_CBCR, 1);
usb_clock_reset(USB3_MP_PHY_PIPE_1_CBCR, 1);
udelay(10);
usb_clock_reset(USB30_MP_MASTER_CBCR, 1);
usb_clock_reset(USB30_MP_MASTER_CBCR, 0);
udelay(10);
clock_reset_bcr(dwc3->gcc_usb3phy_bcr_reg, 1);
clock_reset_bcr(dwc3->gcc_qmpphy_bcr_reg, 1);
clock_reset_bcr(dwc3->gcc_usb3phy1_bcr_reg, 1);
clock_reset_bcr(dwc3->gcc_qmpphy1_bcr_reg, 1);
udelay(10);
clock_reset_bcr(dwc3->gcc_usb3phy_bcr_reg, 0);
clock_reset_bcr(dwc3->gcc_qmpphy_bcr_reg, 0);
clock_reset_bcr(dwc3->gcc_usb3phy1_bcr_reg, 0);
clock_reset_bcr(dwc3->gcc_qmpphy1_bcr_reg, 0);
udelay(10);
usb_clock_reset(USB3_MP_PHY_PIPE_0_CBCR, 0);
usb_clock_reset(USB3_MP_PHY_PIPE_1_CBCR, 0);
/* Initialize QMP PHY */
bool ret0 = ss_qmp_phy_init(0);
bool ret1 = ss_qmp_phy_init(1);
/* If SS PHY init fails fall back to HS speed */
if (!ret0 || !ret1)
hs_speed_only = true;
setup_dwc3(dwc3->usb_host_dwc3);
printk(BIOS_INFO, "DWC3 and PHY setup finished\n");
}
/*
* setup_usb_host0 - Sets up USB HOST0 controller.
* Initializes and configures the USB HOST0 controller, including clocks,
* PHY resets, and DWC3 core for host mode.
*/
void setup_usb_host0(void)
{
printk(BIOS_INFO, "Setting up USB HOST0 controller.\n");
setup_usb_host(&usb_port0);
}