diff options
author | Prasad Malisetty <pmaliset@codeaurora.org> | 2021-05-01 21:39:03 +0530 |
---|---|---|
committer | Shelley Chen <shchen@google.com> | 2022-07-31 18:19:19 +0000 |
commit | b66675d4338fc935e481bb5f77c6bf4f27aedefd (patch) | |
tree | f608ee73f9be186d53ffb78fea4d45b646c8990e /src/soc/qualcomm/common | |
parent | 37bf8c6dd5906bbfed8ccfc543d81cfe483da9f7 (diff) |
soc/qualcomm: Add PCIe support
Add PCIe platform driver for Qualcomm platforms.
Reference:
- linux/drivers/pci/controller/dwc/pcie-qcom.c
- Linux driver base commit: 82a823833f4e3769e82cdb4df1bc2234bc65b16c
BUG=b:182963902,b:216686574,b:181098581
TEST=Verified on Qualcomm sc7280 development board with NVMe card
(Koixa NVMe, Model-KBG40ZPZ256G with FW AEGA0102). Confirmed NVMe is
getting detected in response to 'storage init' command in depthcharge
CLI prompt.
Output logs:
->dpch: storage init
Initializing NVMe controller 1e0f:0001
Identified NVMe model KBG40ZPZ256G TOSHIBA MEMORY
Added NVMe drive "NVMe Namespace 1" lbasize:512, count:0x1dcf32b0
* 0: NVMe Namespace 1
1 devices total
Also verified NVMe boot path, that is depthcharge is able to load the
kernel image from NVMe storage.
Change-Id: Iccf60aa56541f5230fa9c3f821d7709615c36631
Signed-off-by: Prasad Malisetty <quic_pmaliset@quicinc.com>
Signed-off-by: Veerabhadrarao Badiganti <quic_vbadigan@quicinc.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/53902
Reviewed-by: Shelley Chen <shchen@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/soc/qualcomm/common')
-rw-r--r-- | src/soc/qualcomm/common/include/soc/pcie.h | 225 | ||||
-rw-r--r-- | src/soc/qualcomm/common/include/soc/qcom_qmp_phy.h | 272 | ||||
-rw-r--r-- | src/soc/qualcomm/common/pcie_common.c | 459 |
3 files changed, 956 insertions, 0 deletions
diff --git a/src/soc/qualcomm/common/include/soc/pcie.h b/src/soc/qualcomm/common/include/soc/pcie.h new file mode 100644 index 0000000000..09ea6712dc --- /dev/null +++ b/src/soc/qualcomm/common/include/soc/pcie.h @@ -0,0 +1,225 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _PCIE_H_ +#define _PCIE_H_ + +#include <types.h> +#include <device/device.h> +#include <soc/gpio.h> + +/* + * Config, IO and MMIO space offsets relative to controller base and sizes. + * + * EP config space starts at 1MB offset from controller base. + * EP config space size would be 4KB for each endpoint. + * IO space starts at 2MB offset from controller base and its of 1MB size. + * MMIO space starts from 3MB offset from controller base and it can be up to + * end of space reserved for PCIe. + */ +#define PCIE_EP_CONF_OFFSET 0x100000 +#define PCIE_EP_CONF_SIZE 0x1000 +#define PCIE_IO_SPACE_OFFSET 0x200000 +#define PCIE_IO_SPACE_SIZE 0x100000 +#define PCIE_MMIO_SPACE_OFFSET 0x300000 + +/* Parf Registers */ +#define PCIE_PARF_SYS_CTRL 0x00 +#define MAC_PHY_PWRDOWN_MUX_EN BIT(29) +#define PCIE_PARF_PHY_CTRL 0x40 +#define PHY_PWR_DOWN BIT(0) +#define PCIE_PARF_MHI_CLOCK_RESET_CTRL 0x174 +#define MHI_BYPASS BIT(4) +#define PCIE_PARF_LTSSM 0x1B0 +#define LTSSM_EN BIT(8) +#define PCIE_PARF_DBI_BASE_ADDR 0x350 +#define PCIE_PARF_DEVICE_TYPE 0x1000 +#define DEVICE_TYPE_RC 0x4 +#define PCIE_PARF_BDF_TO_SID_CFG 0x2C00 +#define BDF_TO_SID_BYPASS BIT(0) + +/* ELBI */ +#define PCIE3X2_ELBI_SYS_STTS 0x08 +#define XMLH_LINK_UP 0x400 + +/* DBI Registers */ +#define PCIE_LINK_CAPABILITY 0x7c +#define PCIE_LINK_CTL_2 0xa0 +#define TARGET_LINK_SPEED_MASK 0xf +#define LINK_SPEED_GEN_1 0x1 +#define LINK_SPEED_GEN_2 0x2 +#define LINK_SPEED_GEN_3 0x3 +#define PCIE_LINK_UP_MS 100 +#define LINK_WAIT_MAX_RETRIES 10 + +#define COMMAND_MASK 0xffff + +#define TYPE1_HDR_BUS_NUM_MASK 0xffffff +#define RC_PRI_BUS_NUM 0x0 +#define RC_SEC_BUS_NUM 0x1 +#define RC_SUB_BUS_NUM 0xff +#define ROOT_PORT_BUS_NUM ((RC_SUB_BUS_NUM << 16) | \ + (RC_SEC_BUS_NUM << 8) | \ + RC_PRI_BUS_NUM) + +/* Synopsys-specific PCIe configuration registers */ +#define PCIE_DBI_MISC_CONTROL_1_OFF 0x8BC +#define PCIE_DBI_RO_WR_EN BIT(0) + +#define PCIE_3x2_NUM_LANES 2 +#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C +#define PORT_LOGIC_LINK_WIDTH_MASK (0x1f << 8) +#define PORT_LOGIC_LINK_WIDTH_1_LANES (0x1 << 8) +#define PORT_LOGIC_LINK_WIDTH_2_LANES (0x2 << 8) +#define PORT_LOGIC_LINK_WIDTH_4_LANES (0x4 << 8) +#define PORT_LOGIC_LINK_WIDTH_8_LANES (0x8 << 8) + +#define PCIE_PORT_LINK_CONTROL 0x710 +#define PORT_LINK_MODE_MASK (0x3f << 16) +#define PORT_LINK_MODE_1_LANES (0x1 << 16) +#define PORT_LINK_MODE_2_LANES (0x3 << 16) +#define PORT_LINK_MODE_4_LANES (0x7 << 16) +#define PORT_LINK_MODE_8_LANES (0xf << 16) + +/* + * iATU Unroll-specific register definitions + * From DesignWare PCIe core v4.80, the address translation + * will be made by unroll + */ +#define PCIE_ATU_REGION_INDEX1 0x1 +#define PCIE_ATU_REGION_INDEX0 0x0 +#define PCIE_ATU_TYPE_MEM 0x0 +#define PCIE_ATU_TYPE_CFG0 0x4 +#define PCIE_ATU_TYPE_CFG1 0x5 +#define PCIE_ATU_ENABLE BIT(31) +#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24) +#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19) +#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16) + +#define PCIE_ATU_UNR_REGION_CTRL1 0x00 +#define PCIE_ATU_UNR_REGION_CTRL2 0x04 +#define PCIE_ATU_UNR_LOWER_BASE 0x08 +#define PCIE_ATU_UNR_UPPER_BASE 0x0C +#define PCIE_ATU_UNR_LIMIT 0x10 +#define PCIE_ATU_UNR_LOWER_TARGET 0x14 +#define PCIE_ATU_UNR_UPPER_TARGET 0x18 + +#define LINK_WAIT_MAX_IATU_RETRIES 5 +#define LINK_WAIT_IATU 1000 + +/* PHY Specific fields */ +#define QPHY_SW_RESET 0x00 +#define SW_RESET BIT(0) +#define QPHY_PCS_STATUS 0x14 +#define PHY_STATUS BIT(6) +#define QPHY_PCS_PWR_DWN_CNTRL 0x40 +#define SW_PWRDN BIT(0) +#define REFCLK_DRV_DSBL BIT(1) +#define QPHY_START_CTRL 0x44 +#define SERDES_START BIT(0) +#define PCS_START BIT(1) + +/* Register address builder */ +#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) ((region) << 9) +#define lower_32_bits(n) ((u32)(n)) +#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16)) + +#define QMP_PHY_INIT_CFG(o, v) \ + { \ + .offset = o, \ + .val = v, \ + .lane_mask = 0xff, \ + } + +typedef uint64_t pci_addr_t; +typedef uint64_t pci_size_t; + +struct qcom_qmp_phy_init_tbl { + unsigned int offset; + uint32_t val; + unsigned short lane_mask; +}; + +struct pcie_region { + pci_addr_t bus_start; /* BDF */ + uint64_t phys_start; /* Start in physical address space */ + pci_size_t size; /* Size */ +}; + +/** + * struct pcie_cntlr_cfg_t - QCOM DW PCIe Controller state + * + * @lanes : Number of lanes + * @cfg_size : The size of the configuration space + * @cfg_base : The base address of config space + * @dbi_base : The base address of dbi register space + * @atu_base : The base address of address translation unit + * @parf : The base address of PARF register space + * @elbi : The base address of ELBI space + * @phy : Base address of the PHY controller + * @pcie_bcr : address of the block controller register + * @reset : PERST gpio + * @io : Base address of the IO region + * @mem : Base address of memory region + */ +typedef struct { + unsigned int lanes; + unsigned int cfg_size; + void *cfg_base; + void *dbi_base; + void *atu_base; + void *parf; + void *elbi; + void *pcie_bcr; + void *qmp_phy_bcr; + gpio_t perst; + /* IO and MEM PCI regions */ + struct pcie_region io; + struct pcie_region mem; +} pcie_cntlr_cfg_t; + +typedef struct { + void *qmp_phy_base; + void *serdes; + void *tx0; + void *rx0; + void *pcs; + void *tx1; + void *rx1; + void *pcs_misc; + + /* Init sequence for PHY blocks - serdes, tx, rx, pcs */ + const struct qcom_qmp_phy_init_tbl *serdes_tbl; + unsigned int serdes_tbl_num; + const struct qcom_qmp_phy_init_tbl *serdes_tbl_sec; + unsigned int serdes_tbl_num_sec; + const struct qcom_qmp_phy_init_tbl *tx_tbl; + unsigned int tx_tbl_num; + const struct qcom_qmp_phy_init_tbl *tx_tbl_sec; + unsigned int tx_tbl_num_sec; + const struct qcom_qmp_phy_init_tbl *rx_tbl; + unsigned int rx_tbl_num; + const struct qcom_qmp_phy_init_tbl *rx_tbl_sec; + unsigned int rx_tbl_num_sec; + const struct qcom_qmp_phy_init_tbl *pcs_tbl; + unsigned int pcs_tbl_num; + const struct qcom_qmp_phy_init_tbl *pcs_tbl_sec; + unsigned int pcs_tbl_num_sec; + const struct qcom_qmp_phy_init_tbl *pcs_misc_tbl; + unsigned int pcs_misc_tbl_num; + const struct qcom_qmp_phy_init_tbl *pcs_misc_tbl_sec; + unsigned int pcs_misc_tbl_num_sec; +} pcie_qmp_phy_cfg_t; + +struct qcom_pcie_cntlr_t { + pcie_cntlr_cfg_t *cntlr_cfg; + pcie_qmp_phy_cfg_t *qmp_phy_cfg; +}; + +int qcom_dw_pcie_enable_clock(void); +int qcom_dw_pcie_enable_pipe_clock(void); +void gcom_pcie_power_on_ep(void); +void gcom_pcie_get_config(struct qcom_pcie_cntlr_t *host_cfg); +void qcom_pci_domain_read_resources(struct device *dev); +void qcom_setup_pcie_host(struct device *dev); + +#endif diff --git a/src/soc/qualcomm/common/include/soc/qcom_qmp_phy.h b/src/soc/qualcomm/common/include/soc/qcom_qmp_phy.h new file mode 100644 index 0000000000..ec4ac3465b --- /dev/null +++ b/src/soc/qualcomm/common/include/soc/qcom_qmp_phy.h @@ -0,0 +1,272 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef QCOM_PHY_QMP_H_ +#define QCOM_PHY_QMP_H_ + +/* Only for QMP V4 PHY - QSERDES COM registers */ +#define QSERDES_V4_COM_SSC_EN_CENTER 0x010 +#define QSERDES_V4_COM_SSC_PER1 0x01c +#define QSERDES_V4_COM_SSC_PER2 0x020 +#define QSERDES_V4_COM_SSC_STEP_SIZE1_MODE0 0x024 +#define QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0 0x028 +#define QSERDES_V4_COM_SSC_STEP_SIZE1_MODE1 0x030 +#define QSERDES_V4_COM_SSC_STEP_SIZE2_MODE1 0x034 +#define QSERDES_V4_COM_CLK_ENABLE1 0x048 +#define QSERDES_V4_COM_SYSCLK_BUF_ENABLE 0x050 +#define QSERDES_V4_COM_PLL_IVCO 0x058 +#define QSERDES_V4_COM_CMN_IPTRIM 0x060 +#define QSERDES_V4_COM_CP_CTRL_MODE0 0x074 +#define QSERDES_V4_COM_CP_CTRL_MODE1 0x078 +#define QSERDES_V4_COM_PLL_RCTRL_MODE0 0x07c +#define QSERDES_V4_COM_PLL_RCTRL_MODE1 0x080 +#define QSERDES_V4_COM_PLL_CCTRL_MODE0 0x084 +#define QSERDES_V4_COM_PLL_CCTRL_MODE1 0x088 +#define QSERDES_V4_COM_SYSCLK_EN_SEL 0x094 +#define QSERDES_V4_COM_LOCK_CMP_EN 0x0a4 +#define QSERDES_V4_COM_LOCK_CMP1_MODE0 0x0ac +#define QSERDES_V4_COM_LOCK_CMP2_MODE0 0x0b0 +#define QSERDES_V4_COM_LOCK_CMP1_MODE1 0x0b4 +#define QSERDES_V4_COM_DEC_START_MODE0 0x0bc +#define QSERDES_V4_COM_LOCK_CMP2_MODE1 0x0b8 +#define QSERDES_V4_COM_DEC_START_MODE1 0x0c4 +#define QSERDES_V4_COM_DIV_FRAC_START1_MODE0 0x0cc +#define QSERDES_V4_COM_DIV_FRAC_START2_MODE0 0x0d0 +#define QSERDES_V4_COM_DIV_FRAC_START3_MODE0 0x0d4 +#define QSERDES_V4_COM_DIV_FRAC_START1_MODE1 0x0d8 +#define QSERDES_V4_COM_DIV_FRAC_START2_MODE1 0x0dc +#define QSERDES_V4_COM_DIV_FRAC_START3_MODE1 0x0e0 +#define QSERDES_V4_COM_VCO_TUNE_MAP 0x10c +#define QSERDES_V4_COM_VCO_TUNE1_MODE0 0x110 +#define QSERDES_V4_COM_VCO_TUNE2_MODE0 0x114 +#define QSERDES_V4_COM_VCO_TUNE1_MODE1 0x118 +#define QSERDES_V4_COM_VCO_TUNE2_MODE1 0x11c +#define QSERDES_V4_COM_VCO_TUNE_INITVAL2 0x124 +#define QSERDES_V4_COM_CLK_SELECT 0x154 +#define QSERDES_V4_COM_HSCLK_SEL 0x158 +#define QSERDES_V4_COM_HSCLK_HS_SWITCH_SEL 0x15c +#define QSERDES_V4_COM_CORECLK_DIV_MODE1 0x16c +#define QSERDES_V4_COM_SVS_MODE_CLK_SEL 0x184 +#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0 0x1ac +#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0 0x1b0 +#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1 0x1b4 +#define QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL 0x1bc +#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1 0x1b8 + +/* Only for QMP V4 PHY - TX registers */ +#define QSERDES_V4_TX_RES_CODE_LANE_TX 0x34 +#define QSERDES_V4_TX_RES_CODE_LANE_RX 0x38 +#define QSERDES_V4_TX_RES_CODE_LANE_OFFSET_TX 0x3c +#define QSERDES_V4_TX_RES_CODE_LANE_OFFSET_RX 0x40 +#define QSERDES_V4_TX_LANE_MODE_1 0x84 +#define QSERDES_V4_TX_LANE_MODE_2 0x88 +#define QSERDES_V4_TX_RCV_DETECT_LVL_2 0x9c +#define QSERDES_V4_TX_PWM_GEAR_1_DIVIDER_BAND0_1 0xd8 +#define QSERDES_V4_TX_PWM_GEAR_2_DIVIDER_BAND0_1 0xdC +#define QSERDES_V4_TX_PWM_GEAR_3_DIVIDER_BAND0_1 0xe0 +#define QSERDES_V4_TX_PWM_GEAR_4_DIVIDER_BAND0_1 0xe4 +#define QSERDES_V4_TX_TRAN_DRVR_EMP_EN 0xb8 +#define QSERDES_V4_TX_PI_QEC_CTRL 0x104 + +/* Only for QMP V4 PHY - RX registers */ +#define QSERDES_V4_RX_UCDR_FO_GAIN 0x008 +#define QSERDES_V4_RX_UCDR_SO_GAIN 0x014 +#define QSERDES_V4_RX_UCDR_FASTLOCK_FO_GAIN 0x030 +#define QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034 +#define QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_LOW 0x03c +#define QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_HIGH 0x040 +#define QSERDES_V4_RX_UCDR_PI_CONTROLS 0x044 +#define QSERDES_V4_RX_UCDR_PI_CTRL2 0x048 +#define QSERDES_V4_RX_UCDR_SB2_THRESH1 0x04c +#define QSERDES_V4_RX_UCDR_SB2_THRESH2 0x050 +#define QSERDES_V4_RX_UCDR_SB2_GAIN1 0x054 +#define QSERDES_V4_RX_UCDR_SB2_GAIN2 0x058 +#define QSERDES_V4_RX_AUX_DATA_TCOARSE_TFINE 0x060 +#define QSERDES_V4_RX_RCLK_AUXDATA_SEL 0x064 +#define QSERDES_V4_RX_AC_JTAG_ENABLE 0x068 +#define QSERDES_V4_RX_AC_JTAG_MODE 0x078 +#define QSERDES_V4_RX_RX_TERM_BW 0x080 +#define QSERDES_V4_RX_VGA_CAL_CNTRL1 0x0d4 +#define QSERDES_V4_RX_VGA_CAL_CNTRL2 0x0d8 +#define QSERDES_V4_RX_GM_CAL 0x0dc +#define QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL1 0x0e8 +#define QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2 0x0ec +#define QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3 0x0f0 +#define QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4 0x0f4 +#define QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW 0x0f8 +#define QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH 0x0fc +#define QSERDES_V4_RX_RX_IDAC_MEASURE_TIME 0x100 +#define QSERDES_V4_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x110 +#define QSERDES_V4_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x114 +#define QSERDES_V4_RX_SIGDET_ENABLES 0x118 +#define QSERDES_V4_RX_SIGDET_CNTRL 0x11c +#define QSERDES_V4_RX_SIGDET_LVL 0x120 +#define QSERDES_V4_RX_SIGDET_DEGLITCH_CNTRL 0x124 +#define QSERDES_V4_RX_RX_BAND 0x128 +#define QSERDES_V4_RX_RX_MODE_00_LOW 0x170 +#define QSERDES_V4_RX_RX_MODE_00_HIGH 0x174 +#define QSERDES_V4_RX_RX_MODE_00_HIGH2 0x178 +#define QSERDES_V4_RX_RX_MODE_00_HIGH3 0x17c +#define QSERDES_V4_RX_RX_MODE_00_HIGH4 0x180 +#define QSERDES_V4_RX_RX_MODE_01_LOW 0x184 +#define QSERDES_V4_RX_RX_MODE_01_HIGH 0x188 +#define QSERDES_V4_RX_RX_MODE_01_HIGH2 0x18c +#define QSERDES_V4_RX_RX_MODE_01_HIGH3 0x190 +#define QSERDES_V4_RX_RX_MODE_01_HIGH4 0x194 +#define QSERDES_V4_RX_RX_MODE_10_LOW 0x198 +#define QSERDES_V4_RX_RX_MODE_10_HIGH 0x19c +#define QSERDES_V4_RX_RX_MODE_10_HIGH2 0x1a0 +#define QSERDES_V4_RX_RX_MODE_10_HIGH3 0x1a4 +#define QSERDES_V4_RX_RX_MODE_10_HIGH4 0x1a8 +#define QSERDES_V4_RX_DFE_EN_TIMER 0x1b4 +#define QSERDES_V4_RX_DFE_CTLE_POST_CAL_OFFSET 0x1b8 +#define QSERDES_V4_RX_DCC_CTRL1 0x1bc +#define QSERDES_V4_RX_VTH_CODE 0x1c4 + +/* Only for QMP V4 PHY - PCIe PCS registers */ +#define QPHY_V4_PCS_SW_RESET 0x000 +#define QPHY_V4_PCS_REVISION_ID0 0x004 +#define QPHY_V4_PCS_REVISION_ID1 0x008 +#define QPHY_V4_PCS_REVISION_ID2 0x00c +#define QPHY_V4_PCS_REVISION_ID3 0x010 +#define QPHY_V4_PCS_PCS_STATUS1 0x014 +#define QPHY_V4_PCS_PCS_STATUS2 0x018 +#define QPHY_V4_PCS_PCS_STATUS3 0x01c +#define QPHY_V4_PCS_PCS_STATUS4 0x020 +#define QPHY_V4_PCS_PCS_STATUS5 0x024 +#define QPHY_V4_PCS_PCS_STATUS6 0x028 +#define QPHY_V4_PCS_PCS_STATUS7 0x02c +#define QPHY_V4_PCS_DEBUG_BUS_0_STATUS 0x030 +#define QPHY_V4_PCS_DEBUG_BUS_1_STATUS 0x034 +#define QPHY_V4_PCS_DEBUG_BUS_2_STATUS 0x038 +#define QPHY_V4_PCS_DEBUG_BUS_3_STATUS 0x03c +#define QPHY_V4_PCS_POWER_DOWN_CONTROL 0x040 +#define QPHY_V4_PCS_START_CONTROL 0x044 +#define QPHY_V4_PCS_INSIG_SW_CTRL1 0x048 +#define QPHY_V4_PCS_INSIG_SW_CTRL2 0x04c +#define QPHY_V4_PCS_INSIG_SW_CTRL3 0x050 +#define QPHY_V4_PCS_INSIG_SW_CTRL4 0x054 +#define QPHY_V4_PCS_INSIG_SW_CTRL5 0x058 +#define QPHY_V4_PCS_INSIG_SW_CTRL6 0x05c +#define QPHY_V4_PCS_INSIG_SW_CTRL7 0x060 +#define QPHY_V4_PCS_INSIG_SW_CTRL8 0x064 +#define QPHY_V4_PCS_INSIG_MX_CTRL1 0x068 +#define QPHY_V4_PCS_INSIG_MX_CTRL2 0x06c +#define QPHY_V4_PCS_INSIG_MX_CTRL3 0x070 +#define QPHY_V4_PCS_INSIG_MX_CTRL4 0x074 +#define QPHY_V4_PCS_INSIG_MX_CTRL5 0x078 +#define QPHY_V4_PCS_INSIG_MX_CTRL7 0x07c +#define QPHY_V4_PCS_INSIG_MX_CTRL8 0x080 +#define QPHY_V4_PCS_OUTSIG_SW_CTRL1 0x084 +#define QPHY_V4_PCS_OUTSIG_MX_CTRL1 0x088 +#define QPHY_V4_PCS_CLAMP_ENABLE 0x08c +#define QPHY_V4_PCS_POWER_STATE_CONFIG1 0x090 +#define QPHY_V4_PCS_POWER_STATE_CONFIG2 0x094 +#define QPHY_V4_PCS_FLL_CNTRL1 0x098 +#define QPHY_V4_PCS_FLL_CNTRL2 0x09c +#define QPHY_V4_PCS_FLL_CNT_VAL_L 0x0a0 +#define QPHY_V4_PCS_FLL_CNT_VAL_H_TOL 0x0a4 +#define QPHY_V4_PCS_FLL_MAN_CODE 0x0a8 +#define QPHY_V4_PCS_TEST_CONTROL1 0x0ac +#define QPHY_V4_PCS_TEST_CONTROL2 0x0b0 +#define QPHY_V4_PCS_TEST_CONTROL3 0x0b4 +#define QPHY_V4_PCS_TEST_CONTROL4 0x0b8 +#define QPHY_V4_PCS_TEST_CONTROL5 0x0bc +#define QPHY_V4_PCS_TEST_CONTROL6 0x0c0 +#define QPHY_V4_PCS_LOCK_DETECT_CONFIG1 0x0c4 +#define QPHY_V4_PCS_LOCK_DETECT_CONFIG2 0x0c8 +#define QPHY_V4_PCS_LOCK_DETECT_CONFIG3 0x0cc +#define QPHY_V4_PCS_LOCK_DETECT_CONFIG4 0x0d0 +#define QPHY_V4_PCS_LOCK_DETECT_CONFIG5 0x0d4 +#define QPHY_V4_PCS_LOCK_DETECT_CONFIG6 0x0d8 +#define QPHY_V4_PCS_REFGEN_REQ_CONFIG1 0x0dc +#define QPHY_V4_PCS_REFGEN_REQ_CONFIG2 0x0e0 +#define QPHY_V4_PCS_REFGEN_REQ_CONFIG3 0x0e4 +#define QPHY_V4_PCS_BIST_CTRL 0x0e8 +#define QPHY_V4_PCS_PRBS_POLY0 0x0ec +#define QPHY_V4_PCS_PRBS_POLY1 0x0f0 +#define QPHY_V4_PCS_FIXED_PAT0 0x0f4 +#define QPHY_V4_PCS_FIXED_PAT1 0x0f8 +#define QPHY_V4_PCS_FIXED_PAT2 0x0fc +#define QPHY_V4_PCS_FIXED_PAT3 0x100 +#define QPHY_V4_PCS_FIXED_PAT4 0x104 +#define QPHY_V4_PCS_FIXED_PAT5 0x108 +#define QPHY_V4_PCS_FIXED_PAT6 0x10c +#define QPHY_V4_PCS_FIXED_PAT7 0x110 +#define QPHY_V4_PCS_FIXED_PAT8 0x114 +#define QPHY_V4_PCS_FIXED_PAT9 0x118 +#define QPHY_V4_PCS_FIXED_PAT10 0x11c +#define QPHY_V4_PCS_FIXED_PAT11 0x120 +#define QPHY_V4_PCS_FIXED_PAT12 0x124 +#define QPHY_V4_PCS_FIXED_PAT13 0x128 +#define QPHY_V4_PCS_FIXED_PAT14 0x12c +#define QPHY_V4_PCS_FIXED_PAT15 0x130 +#define QPHY_V4_PCS_TXMGN_CONFIG 0x134 +#define QPHY_V4_PCS_G12S1_TXMGN_V0 0x138 +#define QPHY_V4_PCS_G12S1_TXMGN_V1 0x13c +#define QPHY_V4_PCS_G12S1_TXMGN_V2 0x140 +#define QPHY_V4_PCS_G12S1_TXMGN_V3 0x144 +#define QPHY_V4_PCS_G12S1_TXMGN_V4 0x148 +#define QPHY_V4_PCS_G12S1_TXMGN_V0_RS 0x14c +#define QPHY_V4_PCS_G12S1_TXMGN_V1_RS 0x150 +#define QPHY_V4_PCS_G12S1_TXMGN_V2_RS 0x154 +#define QPHY_V4_PCS_G12S1_TXMGN_V3_RS 0x158 +#define QPHY_V4_PCS_G12S1_TXMGN_V4_RS 0x15c +#define QPHY_V4_PCS_G3S2_TXMGN_MAIN 0x160 +#define QPHY_V4_PCS_G3S2_TXMGN_MAIN_RS 0x164 +#define QPHY_V4_PCS_G12S1_TXDEEMPH_M6DB 0x168 +#define QPHY_V4_PCS_G12S1_TXDEEMPH_M3P5DB 0x16c +#define QPHY_V4_PCS_G3S2_PRE_GAIN 0x170 +#define QPHY_V4_PCS_G3S2_POST_GAIN 0x174 +#define QPHY_V4_PCS_G3S2_PRE_POST_OFFSET 0x178 +#define QPHY_V4_PCS_G3S2_PRE_GAIN_RS 0x17c +#define QPHY_V4_PCS_G3S2_POST_GAIN_RS 0x180 +#define QPHY_V4_PCS_G3S2_PRE_POST_OFFSET_RS 0x184 +#define QPHY_V4_PCS_RX_SIGDET_LVL 0x188 +#define QPHY_V4_PCS_RX_SIGDET_DTCT_CNTRL 0x18c +#define QPHY_V4_PCS_RCVR_DTCT_DLY_P1U2_L 0x190 +#define QPHY_V4_PCS_RCVR_DTCT_DLY_P1U2_H 0x194 +#define QPHY_V4_PCS_RATE_SLEW_CNTRL1 0x198 +#define QPHY_V4_PCS_RATE_SLEW_CNTRL2 0x19c +#define QPHY_V4_PCS_PWRUP_RESET_DLY_TIME_AUXCLK 0x1a0 +#define QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_L 0x1a4 +#define QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_H 0x1a8 +#define QPHY_V4_PCS_TSYNC_RSYNC_TIME 0x1ac +#define QPHY_V4_PCS_CDR_RESET_TIME 0x1b0 +#define QPHY_V4_PCS_TSYNC_DLY_TIME 0x1b4 +#define QPHY_V4_PCS_ELECIDLE_DLY_SEL 0x1b8 +#define QPHY_V4_PCS_CMN_ACK_OUT_SEL 0x1bc +#define QPHY_V4_PCS_ALIGN_DETECT_CONFIG1 0x1c0 +#define QPHY_V4_PCS_ALIGN_DETECT_CONFIG2 0x1c4 +#define QPHY_V4_PCS_ALIGN_DETECT_CONFIG3 0x1c8 +#define QPHY_V4_PCS_ALIGN_DETECT_CONFIG4 0x1cc +#define QPHY_V4_PCS_PCS_TX_RX_CONFIG 0x1d0 +#define QPHY_V4_PCS_RX_IDLE_DTCT_CNTRL 0x1d4 +#define QPHY_V4_PCS_RX_DCC_CAL_CONFIG 0x1d8 +#define QPHY_V4_PCS_EQ_CONFIG1 0x1dc +#define QPHY_V4_PCS_EQ_CONFIG2 0x1e0 +#define QPHY_V4_PCS_EQ_CONFIG3 0x1e4 +#define QPHY_V4_PCS_EQ_CONFIG4 0x1e8 +#define QPHY_V4_PCS_EQ_CONFIG5 0x1ec + +/* Only for QMP V4 PHY - PCS_MISC registers */ +#define QPHY_V4_PCS_MISC_TYPEC_CTRL 0x00 +#define QPHY_V4_PCS_MISC_TYPEC_PWRDN_CTRL 0x04 +#define QPHY_V4_PCS_MISC_PCS_MISC_CONFIG1 0x08 +#define QPHY_V4_PCS_MISC_CLAMP_ENABLE 0x0c +#define QPHY_V4_PCS_MISC_TYPEC_STATUS 0x10 +#define QPHY_V4_PCS_MISC_PLACEHOLDER_STATUS 0x14 + +/* Only for QMP V4 PHY - PCS_PCIE registers */ +#define QPHY_V4_PCS_PCIE_POWER_STATE_CONFIG2 0x0c +#define QPHY_V4_PCS_PCIE_POWER_STATE_CONFIG4 0x14 +#define QPHY_V4_PCS_PCIE_ENDPOINT_REFCLK_DRIVE 0x1c +#define QPHY_V4_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L 0x40 +#define QPHY_V4_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_L 0x48 +#define QPHY_V4_PCS_PCIE_INT_AUX_CLK_CONFIG1 0x50 +#define QPHY_V4_PCS_PCIE_OSC_DTCT_ACTIONS 0x90 +#define QPHY_V4_PCS_PCIE_EQ_CONFIG2 0xa4 +#define QPHY_V4_PCS_PCIE_PRESET_P6_P7_PRE 0xb4 +#define QPHY_V4_PCS_PCIE_PRESET_P10_PRE 0xbc +#define QPHY_V4_PCS_PCIE_PRESET_P10_POST 0xe0 + +#endif diff --git a/src/soc/qualcomm/common/pcie_common.c b/src/soc/qualcomm/common/pcie_common.c new file mode 100644 index 0000000000..67f6282875 --- /dev/null +++ b/src/soc/qualcomm/common/pcie_common.c @@ -0,0 +1,459 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <boot/coreboot_tables.h> +#include <console/console.h> +#include <delay.h> +#include <device/device.h> +#include <device/mmio.h> +#include <device/pci.h> +#include <device/pci_def.h> +#include <device/pci_ids.h> +#include <gpio.h> +#include <soc/clock.h> +#include <soc/gpio.h> +#include <soc/qcom_qmp_phy.h> +#include <soc/pcie.h> +#include <timer.h> + +#define ROOT_PORT_BDF 0x0 +#define ATU_CTRL2 PCIE_ATU_UNR_REGION_CTRL2 + +static struct qcom_pcie_cntlr_t qcom_pcie_cfg; + +static inline void dw_pcie_dbi_rd_wr(bool enable) +{ + uint32_t val; + pcie_cntlr_cfg_t *pcierc = qcom_pcie_cfg.cntlr_cfg; + + val = read32(pcierc->dbi_base + PCIE_DBI_MISC_CONTROL_1_OFF); + + if (enable) + val |= PCIE_DBI_RO_WR_EN; + else + val &= ~PCIE_DBI_RO_WR_EN; + + write32(pcierc->dbi_base + PCIE_DBI_MISC_CONTROL_1_OFF, val); +} + +static void dw_pcie_writel_iatu(unsigned int index, uint32_t reg, uint32_t val) +{ + pcie_cntlr_cfg_t *pcierc = qcom_pcie_cfg.cntlr_cfg; + unsigned int offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); + + write32(pcierc->atu_base + offset + reg, val); +} + +static uint32_t dw_pcie_readl_iatu(unsigned int index, uint32_t reg) +{ + pcie_cntlr_cfg_t *pcierc = qcom_pcie_cfg.cntlr_cfg; + unsigned int offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); + + return read32(pcierc->atu_base + offset + reg); +} + +static void qcom_dw_pcie_prog_outbound_atu(unsigned int index, + unsigned int type, uint64_t cpu_addr, + uint64_t pcie_addr, uint32_t size) +{ + dw_pcie_writel_iatu(index, PCIE_ATU_UNR_LOWER_BASE, lower_32_bits(cpu_addr)); + dw_pcie_writel_iatu(index, PCIE_ATU_UNR_UPPER_BASE, upper_32_bits(cpu_addr)); + dw_pcie_writel_iatu(index, PCIE_ATU_UNR_LIMIT, lower_32_bits(cpu_addr + size - 1)); + dw_pcie_writel_iatu(index, PCIE_ATU_UNR_LOWER_TARGET, lower_32_bits(pcie_addr)); + dw_pcie_writel_iatu(index, PCIE_ATU_UNR_UPPER_TARGET, upper_32_bits(pcie_addr)); + dw_pcie_writel_iatu(index, PCIE_ATU_UNR_REGION_CTRL1, type); + dw_pcie_writel_iatu(index, PCIE_ATU_UNR_REGION_CTRL2, PCIE_ATU_ENABLE); + + /* Ensure ATU enable takes effect before any subsequent config access */ + if (retry(LINK_WAIT_MAX_IATU_RETRIES, + (dw_pcie_readl_iatu(index, ATU_CTRL2) & PCIE_ATU_ENABLE), + udelay(LINK_WAIT_IATU))) + return; + + printk(BIOS_ERR, "PCIe o/b iATU couldn't be enabled after 5ms\n"); +} + +static void qcom_pcie_configure_gpios(pcie_cntlr_cfg_t *cfg) +{ + gpio_configure(cfg->perst, 0, GPIO_NO_PULL, GPIO_16MA, GPIO_OUTPUT); +} + +/** + * qcom_dw_pcie_configure() - Configure link capabilities and speed + * + * Configure the link capabilities and speed in the PCIe root complex. + */ +static void qcom_dw_pcie_configure(uint32_t cap_speed) +{ + pcie_cntlr_cfg_t *pcierc = qcom_pcie_cfg.cntlr_cfg; + + dw_pcie_dbi_rd_wr(true); + + clrsetbits32(pcierc->dbi_base + PCIE_LINK_CAPABILITY, + TARGET_LINK_SPEED_MASK, cap_speed); + + clrsetbits32(pcierc->dbi_base + PCIE_LINK_CTL_2, + TARGET_LINK_SPEED_MASK, cap_speed); + + dw_pcie_dbi_rd_wr(false); + printk(BIOS_INFO, "PCIe Link speed configured in Gen %d\n", cap_speed); +} + +/** + * is_pcie_link_up() - Return the link state + * + * Return: true for active link and false for no link + */ +static bool is_pcie_link_up(struct qcom_pcie_cntlr_t *pci) +{ + /* Read link status register */ + return !!(read32(pci->cntlr_cfg->elbi + PCIE3X2_ELBI_SYS_STTS) & XMLH_LINK_UP); +} + +/** + * wait_link_up() - Wait for the link to come up + * + * Return: true for active line and false for no link (timeout) + */ +static bool wait_link_up(struct qcom_pcie_cntlr_t *pci) +{ + /* Check if the link is up or not */ + if (retry(LINK_WAIT_MAX_RETRIES, is_pcie_link_up(pci), mdelay(PCIE_LINK_UP_MS))) + return true; + + printk(BIOS_ERR, "PCIe link is not up even after 1sec\n"); + return false; +} + +static enum cb_err qcom_pcie_dw_link_up(struct qcom_pcie_cntlr_t *pcie) +{ + if (is_pcie_link_up(pcie)) { + printk(BIOS_INFO, "PCIe Link is already up\n"); + return CB_SUCCESS; + } + + /* DW pre link configurations */ + qcom_dw_pcie_configure(LINK_SPEED_GEN_2); + + /* enable link training */ + setbits32(pcie->cntlr_cfg->parf + PCIE_PARF_LTSSM, LTSSM_EN); + + /* Check that link was established */ + if (wait_link_up(pcie)) { + printk(BIOS_INFO, "PCIe link is up\n"); + return CB_SUCCESS; + } + + /* + * Link can be established in Gen 1 as it failed to establish in Gen2. + * So allow some time to do it. + */ + udelay(100); + + return CB_ERR; +} + +/** + * Returns root port config space address or endpoint config space address. + * For endpoint config address, mapping would be done with ATU. + */ +static void *qcom_dw_pcie_get_config_addr(struct qcom_pcie_cntlr_t *pcierc, + pci_devfn_t dev) +{ + unsigned int atu_type, cfg_size; + void *cfg_address; + uint32_t bus, busdev, devfn; + pcie_cntlr_cfg_t *cntlr = pcierc->cntlr_cfg; + bus = PCI_DEV2SEGBUS(dev); + devfn = PCI_DEV2DEVFN(dev); + + busdev = PCIE_ATU_BUS(bus) | + PCIE_ATU_DEV(PCI_SLOT(devfn)) | + PCIE_ATU_FUNC(PCI_FUNC(devfn)); + + /* Accessing root port configuration space */ + if (!bus && !devfn) { + cfg_address = pcierc->cntlr_cfg->dbi_base; + return cfg_address; + } + + /* For local bus use CFG0 type */ + atu_type = (bus == 1) ? PCIE_ATU_TYPE_CFG0 : PCIE_ATU_TYPE_CFG1; + + cfg_address = cntlr->cfg_base + (cntlr->cfg_size * devfn); + cfg_size = cntlr->cfg_size; + + qcom_dw_pcie_prog_outbound_atu(PCIE_ATU_REGION_INDEX1, atu_type, + (uint64_t)cfg_address, busdev, cfg_size); + return cfg_address; +} + +static void qcom_dw_pcie_setup_rc(struct qcom_pcie_cntlr_t *pcie) +{ + uint32_t val; + pcie_cntlr_cfg_t *pcierc = pcie->cntlr_cfg; + /* + * Enable DBI read-only registers for writing/updating configuration. + * Write permission gets disabled towards the end of this function. + */ + dw_pcie_dbi_rd_wr(true); + + val = read32(pcierc->dbi_base + PCIE_PORT_LINK_CONTROL); + /* Set the number of lanes */ + val &= ~PORT_LINK_MODE_MASK; + + switch (pcierc->lanes) { + case 1: + val |= PORT_LINK_MODE_1_LANES; + break; + case 2: + val |= PORT_LINK_MODE_2_LANES; + break; + case 4: + val |= PORT_LINK_MODE_4_LANES; + break; + case 8: + val |= PORT_LINK_MODE_8_LANES; + break; + default: + printk(BIOS_INFO, "PCIe num-lanes %u: invalid value\n", + pcierc->lanes); + return; + } + + write32(pcierc->dbi_base + PCIE_PORT_LINK_CONTROL, val); + + /* Set link width speed control register */ + val = read32(pcierc->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + val &= ~PORT_LOGIC_LINK_WIDTH_MASK; + + switch (pcierc->lanes) { + case 1: + val |= PORT_LOGIC_LINK_WIDTH_1_LANES; + break; + case 2: + val |= PORT_LOGIC_LINK_WIDTH_2_LANES; + break; + case 4: + val |= PORT_LOGIC_LINK_WIDTH_4_LANES; + break; + case 8: + val |= PORT_LOGIC_LINK_WIDTH_8_LANES; + break; + default: + printk(BIOS_INFO, "PCIe invalid lanes option\n"); + return; + } + + write32(pcierc->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL, val); + + /* Setup bus numbers */ + clrsetbits32(pcierc->dbi_base + PCI_PRIMARY_BUS, TYPE1_HDR_BUS_NUM_MASK, + ROOT_PORT_BUS_NUM); + + /* Disable SMMU */ + write32(pcierc->parf + PCIE_PARF_BDF_TO_SID_CFG, BDF_TO_SID_BYPASS); + + /* Configure ATU for outbound accesses */ + qcom_dw_pcie_prog_outbound_atu(PCIE_ATU_REGION_INDEX0, + PCIE_ATU_TYPE_MEM, + pcierc->mem.phys_start, + ROOT_PORT_BDF, pcierc->mem.size); + + /* Program correct class for RC */ + write16(pcierc->dbi_base + PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI); + + /* Disable write permission right after the update */ + dw_pcie_dbi_rd_wr(false); +} + +static void qcom_qmp_phy_config_lane(void *base, const struct qcom_qmp_phy_init_tbl tbl[], + unsigned int num, uint8_t ln_mask) +{ + unsigned int i; + const struct qcom_qmp_phy_init_tbl *t = tbl; + + for (i = 0; i < num; i++, t++) { + if (!(t->lane_mask & ln_mask)) + continue; + write32(base + t->offset, t->val); + } +} + +static void qcom_qmp_phy_configure(void *base, const struct qcom_qmp_phy_init_tbl tbl[], + unsigned int num) +{ + qcom_qmp_phy_config_lane(base, tbl, num, 0xff); +} + +static enum cb_err qcom_qmp_phy_power_on(pcie_qmp_phy_cfg_t *qphy) +{ + uint64_t lock_us; + + /* Release powerdown mode and allow endpoint refclk drive */ + write32(qphy->pcs + QPHY_PCS_PWR_DWN_CNTRL, SW_PWRDN | REFCLK_DRV_DSBL); + + /* Serdes configuration */ + qcom_qmp_phy_configure(qphy->serdes, qphy->serdes_tbl, qphy->serdes_tbl_num); + + /* Tx, Rx, and PCS configurations */ + qcom_qmp_phy_config_lane(qphy->tx0, qphy->tx_tbl, qphy->tx_tbl_num, 1); + qcom_qmp_phy_config_lane(qphy->tx0, qphy->tx_tbl_sec, qphy->tx_tbl_num_sec, 1); + qcom_qmp_phy_config_lane(qphy->tx1, qphy->tx_tbl, qphy->tx_tbl_num, 2); + qcom_qmp_phy_config_lane(qphy->tx1, qphy->tx_tbl_sec, qphy->tx_tbl_num_sec, 2); + qcom_qmp_phy_config_lane(qphy->rx0, qphy->rx_tbl, qphy->rx_tbl_num, 1); + qcom_qmp_phy_config_lane(qphy->rx0, qphy->rx_tbl_sec, qphy->rx_tbl_num_sec, 1); + qcom_qmp_phy_config_lane(qphy->rx1, qphy->rx_tbl, qphy->rx_tbl_num, 2); + qcom_qmp_phy_config_lane(qphy->rx1, qphy->rx_tbl_sec, qphy->rx_tbl_num_sec, 2); + qcom_qmp_phy_configure(qphy->pcs, qphy->pcs_tbl, qphy->pcs_tbl_num); + qcom_qmp_phy_configure(qphy->pcs, qphy->pcs_tbl_sec, qphy->pcs_tbl_num_sec); + qcom_qmp_phy_configure(qphy->pcs_misc, qphy->pcs_misc_tbl, qphy->pcs_misc_tbl_num); + qcom_qmp_phy_configure(qphy->pcs_misc, qphy->pcs_misc_tbl_sec, qphy->pcs_tbl_num_sec); + + /* Release software reset of PCS/Serdes */ + clrbits32(qphy->pcs + QPHY_SW_RESET, SW_RESET); + + /* start PCS/Serdes to operation mode */ + write32(qphy->pcs + QPHY_START_CTRL, PCS_START | SERDES_START); + + /* + * Wait for PHY initialization to be done + * PCS_STATUS: wait for 1ms for PHY STATUS bit to be set + */ + lock_us = wait_us(1000, !(read32(qphy->qmp_phy_base + QPHY_PCS_STATUS) & PHY_STATUS)); + if (!lock_us) { + printk(BIOS_ERR, "PCIe QMP PHY PLL failed to lock in 1ms\n"); + return CB_ERR; + } + + printk(BIOS_DEBUG, "PCIe QPHY Initialized took %lldus\n", lock_us); + + qcom_dw_pcie_enable_pipe_clock(); + + return CB_SUCCESS; +} + +/* + * Reset the PCIe PHY core. + * Allow 100us delay to ensure reset is asserted. + */ +static void qcom_qmp_reset_phy(struct qcom_pcie_cntlr_t *pcie) +{ + clock_reset_bcr(pcie->cntlr_cfg->qmp_phy_bcr, 1); + udelay(100); + clock_reset_bcr(pcie->cntlr_cfg->qmp_phy_bcr, 0); +} + +/* + * Reset the PCIe controller core. + * Allow 100us delay to ensure reset is asserted. + */ +static void qcom_dw_pcie_reset_core(struct qcom_pcie_cntlr_t *pcie) +{ + clock_reset_bcr(pcie->cntlr_cfg->pcie_bcr, 1); + udelay(100); + clock_reset_bcr(pcie->cntlr_cfg->pcie_bcr, 0); +} + +static enum cb_err qcom_dw_pcie_enable(struct qcom_pcie_cntlr_t *pcie) +{ + int ret; + + pcie_cntlr_cfg_t *pcierc = pcie->cntlr_cfg; + pcie_qmp_phy_cfg_t *qmp_phy = pcie->qmp_phy_cfg; + + /* assert PCIe reset link to keep EP in reset */ + gpio_set(pcierc->perst, 0); + + /* Enable PCIe controller and SoC specific clocks */ + ret = qcom_dw_pcie_enable_clock(); + if (ret) { + printk(BIOS_ERR, "Enable PCIe clocks failed\n"); + return ret; + } + + /* Reset the controller */ + qcom_dw_pcie_reset_core(pcie); + + /* configure PCIe to RC mode */ + write32(pcierc->parf + PCIE_PARF_DEVICE_TYPE, DEVICE_TYPE_RC); + + /* Power on the PHY */ + clrbits32(pcierc->parf + PCIE_PARF_PHY_CTRL, PHY_PWR_DOWN); + + /* MAC PHY_POWERDOWN MUX DISABLE */ + clrbits32(pcierc->parf + PCIE_PARF_SYS_CTRL, MAC_PHY_PWRDOWN_MUX_EN); + + /* Bypass MHI as its not needed */ + setbits32(pcierc->parf + PCIE_PARF_MHI_CLOCK_RESET_CTRL, MHI_BYPASS); + + qcom_qmp_reset_phy(pcie); + + /* Initialize QMP PHY */ + ret = qcom_qmp_phy_power_on(qmp_phy); + if (ret) { + printk(BIOS_ERR, "PCIe PHY init failed\n"); + return ret; + } + + qcom_dw_pcie_setup_rc(pcie); + + /* de-assert PCIe reset link to bring EP out of reset */ + gpio_set(pcierc->perst, 1); + + /* establisth the link */ + ret = qcom_pcie_dw_link_up(pcie); + if (ret) { + printk(BIOS_ERR, "PCIe Link init failed\n"); + return ret; + } + + return CB_SUCCESS; +} + +/* map_bus function for mapping pcie_s_{read/write}_configXX() functions */ +volatile union pci_bank *pci_map_bus(pci_devfn_t dev) +{ + void *config_addr = NULL; + + config_addr = qcom_dw_pcie_get_config_addr(&qcom_pcie_cfg, dev); + return (void *)config_addr; +} + +/* PCI domain ops read_resources callback */ +void qcom_pci_domain_read_resources(struct device *dev) +{ + struct resource *res; + pcie_cntlr_cfg_t *pcierc = qcom_pcie_cfg.cntlr_cfg; + + /* Initialize the system-wide I/O space constraints. */ + res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0)); + res->base = pcierc->io.phys_start; + res->limit = pcierc->io.size - 1; + res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; + + /* Initialize the system-wide memory resources constraints. */ + res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0)); + res->base = pcierc->mem.phys_start; + res->limit = pcierc->mem.size - 1; + res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; +} + +/* PCI domain ops enable callback */ +void qcom_setup_pcie_host(struct device *dev) +{ + gcom_pcie_get_config(&qcom_pcie_cfg); + + /* Ensure PCIe endpoints are powered-on before initiating PCIe link training */ + gcom_pcie_power_on_ep(); + + printk(BIOS_INFO, "Setup PCIe in RC mode\n"); + + /* Configure PERST gpio */ + qcom_pcie_configure_gpios(qcom_pcie_cfg.cntlr_cfg); + + if (!qcom_dw_pcie_enable(&qcom_pcie_cfg)) + printk(BIOS_NOTICE, "PCIe enumerated succussfully..\n"); + else + printk(BIOS_EMERG, "Failed to enable PCIe\n"); + +} |