1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2019-2020, Broadcom 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <errno.h> 8*91f16700Schasinglulu #include <stdbool.h> 9*91f16700Schasinglulu 10*91f16700Schasinglulu #include <common/debug.h> 11*91f16700Schasinglulu #include <drivers/delay_timer.h> 12*91f16700Schasinglulu #include <lib/mmio.h> 13*91f16700Schasinglulu 14*91f16700Schasinglulu #include <paxb.h> 15*91f16700Schasinglulu #include <sr_def.h> 16*91f16700Schasinglulu #include <sr_utils.h> 17*91f16700Schasinglulu 18*91f16700Schasinglulu /* total number of PCIe Phys */ 19*91f16700Schasinglulu #define NUM_OF_PCIE_SERDES 8 20*91f16700Schasinglulu 21*91f16700Schasinglulu #define CFG_RC_PMI_ADDR 0x1130 22*91f16700Schasinglulu #define PMI_RX_TERM_SEQ ((0x1 << 27) | (0x1ff << 16) | (0xd090)) 23*91f16700Schasinglulu #define PMI_RX_TERM_VAL 0x4c00 24*91f16700Schasinglulu #define PMI_PLL_CTRL_4 0xd0b4 25*91f16700Schasinglulu #define PMI_SERDES_CLK_ENABLE (1 << 12) 26*91f16700Schasinglulu 27*91f16700Schasinglulu #define WAR_PLX_PRESET_PARITY_FAIL 28*91f16700Schasinglulu 29*91f16700Schasinglulu #define CFG_RC_REG_PHY_CTL_10 0x1838 30*91f16700Schasinglulu #define PHY_CTL_10_GEN3_MATCH_PARITY (1 << 15) 31*91f16700Schasinglulu 32*91f16700Schasinglulu #define PMI_X8_CORE0_7_PATCH_SEQ ((0x1 << 27) | (0x1ff << 16) | (0xd2a5)) 33*91f16700Schasinglulu #define PMI_X8_CORE0_7_PATCH_VAL 0xd864 34*91f16700Schasinglulu 35*91f16700Schasinglulu #define PMI_ADDR_BCAST(addr) ((0x1 << 27) | (0x1ff << 16) | (addr)) 36*91f16700Schasinglulu #define PMI_ADDR_LANE0(addr) ((0x1 << 27) | (addr)) 37*91f16700Schasinglulu #define PMI_ADDR_LANE1(addr) ((0x1 << 27) | (0x1 << 16) | (addr)) 38*91f16700Schasinglulu 39*91f16700Schasinglulu #define MERLIN16_PCIE_BLK2_PWRMGMT_7 ((0x1 << 27) | (0x1ff << 16) | 0x1208) 40*91f16700Schasinglulu #define MERLIN16_PCIE_BLK2_PWRMGMT_8 ((0x1 << 27) | (0x1ff << 16) | 0x1209) 41*91f16700Schasinglulu #define MERLIN16_AMS_TX_CTRL_5 ((0x1 << 27) | (0x1ff << 16) | 0xd0a5) 42*91f16700Schasinglulu #define MERLIN16_AMS_TX_CTRL_5_VAL \ 43*91f16700Schasinglulu ((1 << 13) | (1 << 12) | (1 << 11) | (1 << 10)) 44*91f16700Schasinglulu #define MERLIN16_PCIE_BLK2_PWRMGMT_7_VAL 0x96 45*91f16700Schasinglulu #define MERLIN16_PCIE_BLK2_PWRMGMT_8_VAL 0x12c 46*91f16700Schasinglulu 47*91f16700Schasinglulu #define CFG_RC_PMI_WDATA 0x1134 48*91f16700Schasinglulu #define CFG_RC_WCMD_SHIFT 31 49*91f16700Schasinglulu #define CFG_RC_WCMD_MASK ((uint32_t)1U << CFG_RC_WCMD_SHIFT) 50*91f16700Schasinglulu #define CFG_RC_RCMD_SHIFT 30 51*91f16700Schasinglulu #define CFG_RC_RCMD_MASK ((uint32_t)1U << CFG_RC_RCMD_SHIFT) 52*91f16700Schasinglulu #define CFG_RC_RWCMD_MASK (CFG_RC_RCMD_MASK | CFG_RC_WCMD_MASK) 53*91f16700Schasinglulu #define CFG_RC_PMI_RDATA 0x1138 54*91f16700Schasinglulu #define CFG_RC_RACK_SHIFT 31 55*91f16700Schasinglulu #define CFG_RC_RACK_MASK ((uint32_t)1U << CFG_RC_RACK_SHIFT) 56*91f16700Schasinglulu 57*91f16700Schasinglulu /* allow up to 5 ms for PMI write to finish */ 58*91f16700Schasinglulu #define PMI_TIMEOUT_MS 5 59*91f16700Schasinglulu 60*91f16700Schasinglulu /* in 2x8 RC mode, one needs to patch up Serdes 3 and 7 for link to come up */ 61*91f16700Schasinglulu #define SERDES_PATCH_PIPEMUX_INDEX 0x3 62*91f16700Schasinglulu #define SERDES_PATCH_INDEX 0x8 63*91f16700Schasinglulu 64*91f16700Schasinglulu #define DSC_UC_CTRL 0xd00d 65*91f16700Schasinglulu #define DSC_UC_CTRL_RDY_CMD (1 << 7) 66*91f16700Schasinglulu #define LANE_DBG_RST_CTRL 0xd164 67*91f16700Schasinglulu #define UC_A_CLK_CTRL0 0xd200 68*91f16700Schasinglulu #define UC_A_RST_CTRL0 0xd201 69*91f16700Schasinglulu #define UC_A_AHB_CTRL0 0xd202 70*91f16700Schasinglulu #define UC_A_AHB_STAT0 0xd203 71*91f16700Schasinglulu #define UC_A_AHB_WADDR_LSW 0xd204 72*91f16700Schasinglulu #define UC_A_AHB_WADDR_MSW 0xd205 73*91f16700Schasinglulu #define UC_A_AHB_WDATA_LSW 0xd206 74*91f16700Schasinglulu #define UC_A_AHB_WDATA_MSW 0xd207 75*91f16700Schasinglulu #define UC_A_AHB_RADDR_LSW 0xd208 76*91f16700Schasinglulu #define UC_A_AHB_RADDR_MSW 0xd209 77*91f16700Schasinglulu #define UC_A_AHB_RDATA_LSW 0xd20a 78*91f16700Schasinglulu #define UC_A_AHB_RDATA_MSW 0xd20b 79*91f16700Schasinglulu #define UC_VERSION_NUM 0xd230 80*91f16700Schasinglulu #define DSC_SM_CTL22 0xd267 81*91f16700Schasinglulu #define UC_DBG1 0xd251 82*91f16700Schasinglulu 83*91f16700Schasinglulu #define LOAD_UC_CHECK 0 84*91f16700Schasinglulu #define UC_RAM_INIT_TIMEOUT 100 85*91f16700Schasinglulu #define UC_RAM_CONTROL 0xd225 86*91f16700Schasinglulu #define UC_INIT_TIMEOUT 100 87*91f16700Schasinglulu #define SIZE_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) 88*91f16700Schasinglulu #define SZ_4 4 89*91f16700Schasinglulu #define GET_2_BYTES(p, i) ((uint16_t)p[i] | (uint16_t)p[i+1] << 8) 90*91f16700Schasinglulu 91*91f16700Schasinglulu /* 92*91f16700Schasinglulu * List of PCIe LCPLL related registers 93*91f16700Schasinglulu * 94*91f16700Schasinglulu * LCPLL channel 0 provides the Serdes pad clock when running in RC mode 95*91f16700Schasinglulu */ 96*91f16700Schasinglulu #define PCIE_LCPLL_BASE 0x40000000 97*91f16700Schasinglulu 98*91f16700Schasinglulu #define PCIE_LCPLL_CTRL0_OFFSET 0x00 99*91f16700Schasinglulu #define PCIE_LCPLL_RESETB_SHIFT 31 100*91f16700Schasinglulu #define PCIE_LCPLL_RESETB_MASK BIT(PCIE_LCPLL_RESETB_SHIFT) 101*91f16700Schasinglulu #define PCIE_LCPLL_P_RESETB_SHIFT 30 102*91f16700Schasinglulu #define PCIE_LCPLL_P_RESETB_MASK BIT(PCIE_LCPLL_P_RESETB_SHIFT) 103*91f16700Schasinglulu 104*91f16700Schasinglulu #define PCIE_LCPLL_CTRL3_OFFSET 0x0c 105*91f16700Schasinglulu #define PCIE_LCPLL_EN_CTRL_SHIFT 16 106*91f16700Schasinglulu #define PCIE_LCPLL_CM_ENA 0x1a 107*91f16700Schasinglulu #define PCIE_LCPLL_CM_BUF_ENA 0x18 108*91f16700Schasinglulu #define PCIE_LCPLL_D2C2_ENA 0x2 109*91f16700Schasinglulu #define PCIE_LCPLL_REF_CLK_SHIFT 1 110*91f16700Schasinglulu #define PCIE_LCPLL_REF_CLK_MASK BIT(PCIE_LCPLL_REF_CLK_SHIFT) 111*91f16700Schasinglulu #define PCIE_LCPLL_CTRL13_OFFSET 0x34 112*91f16700Schasinglulu #define PCIE_LCPLL_D2C2_CTRL_SHIFT 16 113*91f16700Schasinglulu #define PCIE_LCPLL_D2C2_TERM_DISC 0xe0 114*91f16700Schasinglulu 115*91f16700Schasinglulu #define PCIE_LCPLL_STATUS_OFFSET 0x40 116*91f16700Schasinglulu #define PCIE_LCPLL_LOCK_SHIFT 12 117*91f16700Schasinglulu #define PCIE_LCPLL_LOCK_MASK BIT(PCIE_LCPLL_LOCK_SHIFT) 118*91f16700Schasinglulu 119*91f16700Schasinglulu #define PCIE_PIPE_MUX_RC_MODE_OVERRIDE_CFG 0x114 120*91f16700Schasinglulu #define PCIE_TX_CLKMASTER_CTRL_OVERRIDE_CFG 0x11c 121*91f16700Schasinglulu 122*91f16700Schasinglulu /* wait 500 microseconds for PCIe LCPLL to power up */ 123*91f16700Schasinglulu #define PCIE_LCPLL_DELAY_US 500 124*91f16700Schasinglulu 125*91f16700Schasinglulu /* allow up to 5 ms for PCIe LCPLL VCO to lock */ 126*91f16700Schasinglulu #define PCIE_LCPLL_TIMEOUT_MS 5 127*91f16700Schasinglulu 128*91f16700Schasinglulu #define PCIE_PIPE_MUX_CONFIGURATION_CFG 0x4000010c 129*91f16700Schasinglulu 130*91f16700Schasinglulu #define PCIE_PIPEMUX_SHIFT 19 131*91f16700Schasinglulu #define PCIE_PIPEMUX_MASK 0xf 132*91f16700Schasinglulu 133*91f16700Schasinglulu /* keep track of PIPEMUX index to use */ 134*91f16700Schasinglulu static unsigned int pipemux_idx; 135*91f16700Schasinglulu 136*91f16700Schasinglulu /* 137*91f16700Schasinglulu * PCIe PIPEMUX lookup table 138*91f16700Schasinglulu * 139*91f16700Schasinglulu * Each array index represents a PIPEMUX strap setting 140*91f16700Schasinglulu * The array element represents a bitmap where a set bit means the PCIe core 141*91f16700Schasinglulu * needs to be enabled as RC 142*91f16700Schasinglulu */ 143*91f16700Schasinglulu static uint8_t pipemux_table[] = { 144*91f16700Schasinglulu /* PIPEMUX = 0, EP 1x16 */ 145*91f16700Schasinglulu 0x00, 146*91f16700Schasinglulu /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */ 147*91f16700Schasinglulu 0x80, 148*91f16700Schasinglulu /* PIPEMUX = 2, EP 4x4 */ 149*91f16700Schasinglulu 0x00, 150*91f16700Schasinglulu /* PIPEMUX = 3, RC 2x8, cores 0, 7 */ 151*91f16700Schasinglulu 0x81, 152*91f16700Schasinglulu /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */ 153*91f16700Schasinglulu 0xc3, 154*91f16700Schasinglulu /* PIPEMUX = 5, RC 8x2, all 8 cores */ 155*91f16700Schasinglulu 0xff, 156*91f16700Schasinglulu /* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */ 157*91f16700Schasinglulu 0xcd, 158*91f16700Schasinglulu /* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */ 159*91f16700Schasinglulu 0xfd, 160*91f16700Schasinglulu /* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */ 161*91f16700Schasinglulu 0xf0, 162*91f16700Schasinglulu /* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */ 163*91f16700Schasinglulu 0xc0, 164*91f16700Schasinglulu /* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */ 165*91f16700Schasinglulu 0x42, 166*91f16700Schasinglulu /* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */ 167*91f16700Schasinglulu 0x3c, 168*91f16700Schasinglulu /* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */ 169*91f16700Schasinglulu 0xfc, 170*91f16700Schasinglulu /* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */ 171*91f16700Schasinglulu 0x4c, 172*91f16700Schasinglulu }; 173*91f16700Schasinglulu 174*91f16700Schasinglulu /* 175*91f16700Schasinglulu * Return 1 if pipemux strap is supported 176*91f16700Schasinglulu */ 177*91f16700Schasinglulu static int pipemux_strap_is_valid(uint32_t pipemux) 178*91f16700Schasinglulu { 179*91f16700Schasinglulu if (pipemux < ARRAY_SIZE(pipemux_table)) 180*91f16700Schasinglulu return 1; 181*91f16700Schasinglulu else 182*91f16700Schasinglulu return 0; 183*91f16700Schasinglulu } 184*91f16700Schasinglulu 185*91f16700Schasinglulu /* 186*91f16700Schasinglulu * Read the PCIe PIPEMUX from strap 187*91f16700Schasinglulu */ 188*91f16700Schasinglulu static uint32_t pipemux_strap_read(void) 189*91f16700Schasinglulu { 190*91f16700Schasinglulu uint32_t pipemux; 191*91f16700Schasinglulu 192*91f16700Schasinglulu pipemux = mmio_read_32(PCIE_PIPE_MUX_CONFIGURATION_CFG); 193*91f16700Schasinglulu pipemux &= PCIE_PIPEMUX_MASK; 194*91f16700Schasinglulu if (pipemux == PCIE_PIPEMUX_MASK) { 195*91f16700Schasinglulu /* read the PCIe PIPEMUX strap setting */ 196*91f16700Schasinglulu pipemux = mmio_read_32(CDRU_CHIP_STRAP_DATA_LSW); 197*91f16700Schasinglulu pipemux >>= PCIE_PIPEMUX_SHIFT; 198*91f16700Schasinglulu pipemux &= PCIE_PIPEMUX_MASK; 199*91f16700Schasinglulu } 200*91f16700Schasinglulu 201*91f16700Schasinglulu return pipemux; 202*91f16700Schasinglulu } 203*91f16700Schasinglulu 204*91f16700Schasinglulu /* 205*91f16700Schasinglulu * Store the PIPEMUX index (set for each boot) 206*91f16700Schasinglulu */ 207*91f16700Schasinglulu static void pipemux_save_index(unsigned int idx) 208*91f16700Schasinglulu { 209*91f16700Schasinglulu pipemux_idx = idx; 210*91f16700Schasinglulu } 211*91f16700Schasinglulu 212*91f16700Schasinglulu static int paxb_sr_core_needs_enable(unsigned int core_idx) 213*91f16700Schasinglulu { 214*91f16700Schasinglulu return !!((pipemux_table[pipemux_idx] >> core_idx) & 0x1); 215*91f16700Schasinglulu } 216*91f16700Schasinglulu 217*91f16700Schasinglulu static int pipemux_sr_init(void) 218*91f16700Schasinglulu { 219*91f16700Schasinglulu uint32_t pipemux; 220*91f16700Schasinglulu 221*91f16700Schasinglulu /* read the PCIe PIPEMUX strap setting */ 222*91f16700Schasinglulu pipemux = pipemux_strap_read(); 223*91f16700Schasinglulu if (!pipemux_strap_is_valid(pipemux)) { 224*91f16700Schasinglulu ERROR("Invalid PCIe PIPEMUX strap %u\n", pipemux); 225*91f16700Schasinglulu return -EIO; 226*91f16700Schasinglulu } 227*91f16700Schasinglulu 228*91f16700Schasinglulu /* no PCIe RC is needed */ 229*91f16700Schasinglulu if (!pipemux_table[pipemux]) { 230*91f16700Schasinglulu WARN("PIPEMUX indicates no PCIe RC required\n"); 231*91f16700Schasinglulu return -ENODEV; 232*91f16700Schasinglulu } 233*91f16700Schasinglulu 234*91f16700Schasinglulu /* save the PIPEMUX strap */ 235*91f16700Schasinglulu pipemux_save_index(pipemux); 236*91f16700Schasinglulu 237*91f16700Schasinglulu return 0; 238*91f16700Schasinglulu } 239*91f16700Schasinglulu 240*91f16700Schasinglulu /* 241*91f16700Schasinglulu * PCIe RC serdes link width 242*91f16700Schasinglulu * 243*91f16700Schasinglulu * The array is first organized in rows as indexed by the PIPEMUX setting. 244*91f16700Schasinglulu * Within each row, eight lane width entries are specified -- one entry 245*91f16700Schasinglulu * per PCIe core, from 0 to 7. 246*91f16700Schasinglulu * 247*91f16700Schasinglulu * Note: The EP lanes/cores are not mapped in this table! EP cores are 248*91f16700Schasinglulu * controlled and thus configured by Nitro. 249*91f16700Schasinglulu */ 250*91f16700Schasinglulu static uint8_t link_width_table[][NUM_OF_SR_PCIE_CORES] = { 251*91f16700Schasinglulu /* PIPEMUX = 0, EP 1x16 */ 252*91f16700Schasinglulu {0, 0, 0, 0, 0, 0, 0, 0}, 253*91f16700Schasinglulu /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */ 254*91f16700Schasinglulu {0, 0, 0, 0, 0, 0, 0, 8}, 255*91f16700Schasinglulu /* PIPEMUX = 2, EP 4x4 */ 256*91f16700Schasinglulu {0, 0, 0, 0, 0, 0, 0, 0}, 257*91f16700Schasinglulu /* PIPEMUX = 3, RC 2x8, cores 0, 7 */ 258*91f16700Schasinglulu {8, 0, 0, 0, 0, 0, 0, 8}, 259*91f16700Schasinglulu /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */ 260*91f16700Schasinglulu {4, 4, 0, 0, 0, 0, 4, 4}, 261*91f16700Schasinglulu /* PIPEMUX = 5, RC 8x2, all 8 cores */ 262*91f16700Schasinglulu {2, 2, 2, 2, 2, 2, 2, 2}, 263*91f16700Schasinglulu /* PIPEMUX = 6, RC 3x4 (cores 0, 6, 7), RC 2x2 (cores 2, 3) */ 264*91f16700Schasinglulu {4, 0, 2, 2, 0, 0, 4, 4}, 265*91f16700Schasinglulu /* PIPEMUX = 7, RC 1x4 (core 0), RC 6x2 (cores 2, 3, 4, 5, 6, 7 */ 266*91f16700Schasinglulu {4, 0, 2, 2, 2, 2, 2, 2}, 267*91f16700Schasinglulu /* PIPEMUX = 8, EP 1x8 + RC 4x2 (cores 4, 5, 6, 7) */ 268*91f16700Schasinglulu {0, 0, 0, 0, 2, 2, 2, 2}, 269*91f16700Schasinglulu /* PIPEMUX = 9, EP 1x8 + RC 2x4 (cores 6, 7) */ 270*91f16700Schasinglulu {0, 0, 0, 0, 0, 0, 4, 4}, 271*91f16700Schasinglulu /* PIPEMUX = 10, EP 2x4 + RC 2x4 (cores 1, 6) */ 272*91f16700Schasinglulu {0, 4, 0, 0, 0, 0, 4, 0}, 273*91f16700Schasinglulu /* PIPEMUX = 11, EP 2x4 + RC 4x2 (cores 2, 3, 4, 5) */ 274*91f16700Schasinglulu {0, 0, 2, 2, 2, 2, 0, 0}, 275*91f16700Schasinglulu /* PIPEMUX = 12, EP 1x4 + RC 6x2 (cores 2, 3, 4, 5, 6, 7) */ 276*91f16700Schasinglulu {0, 0, 2, 2, 2, 2, 2, 2}, 277*91f16700Schasinglulu /* PIPEMUX = 13, EP 2x4 + RC 1x4 (core 6) + RC 2x2 (cores 2, 3) */ 278*91f16700Schasinglulu {0, 0, 2, 2, 0, 0, 4, 0} 279*91f16700Schasinglulu }; 280*91f16700Schasinglulu 281*91f16700Schasinglulu /* 282*91f16700Schasinglulu * function for writes to the Serdes registers through the PMI interface 283*91f16700Schasinglulu */ 284*91f16700Schasinglulu static int paxb_pmi_write(unsigned int core_idx, uint32_t pmi, uint32_t val) 285*91f16700Schasinglulu { 286*91f16700Schasinglulu uint32_t status; 287*91f16700Schasinglulu unsigned int timeout = PMI_TIMEOUT_MS; 288*91f16700Schasinglulu 289*91f16700Schasinglulu paxb_rc_cfg_write(core_idx, CFG_RC_PMI_ADDR, pmi); 290*91f16700Schasinglulu 291*91f16700Schasinglulu val &= ~CFG_RC_RWCMD_MASK; 292*91f16700Schasinglulu val |= CFG_RC_WCMD_MASK; 293*91f16700Schasinglulu paxb_rc_cfg_write(core_idx, CFG_RC_PMI_WDATA, val); 294*91f16700Schasinglulu 295*91f16700Schasinglulu do { 296*91f16700Schasinglulu status = paxb_rc_cfg_read(core_idx, CFG_RC_PMI_WDATA); 297*91f16700Schasinglulu 298*91f16700Schasinglulu /* wait for write command bit to clear */ 299*91f16700Schasinglulu if ((status & CFG_RC_WCMD_MASK) == 0) 300*91f16700Schasinglulu return 0; 301*91f16700Schasinglulu } while (--timeout); 302*91f16700Schasinglulu 303*91f16700Schasinglulu return -EIO; 304*91f16700Schasinglulu } 305*91f16700Schasinglulu 306*91f16700Schasinglulu /* 307*91f16700Schasinglulu * function for reads from the Serdes registers through the PMI interface 308*91f16700Schasinglulu */ 309*91f16700Schasinglulu static int paxb_pmi_read(unsigned int core_idx, uint32_t pmi, uint32_t *val) 310*91f16700Schasinglulu { 311*91f16700Schasinglulu uint32_t status; 312*91f16700Schasinglulu unsigned int timeout = PMI_TIMEOUT_MS; 313*91f16700Schasinglulu 314*91f16700Schasinglulu paxb_rc_cfg_write(core_idx, CFG_RC_PMI_ADDR, pmi); 315*91f16700Schasinglulu 316*91f16700Schasinglulu paxb_rc_cfg_write(core_idx, CFG_RC_PMI_WDATA, CFG_RC_RCMD_MASK); 317*91f16700Schasinglulu 318*91f16700Schasinglulu do { 319*91f16700Schasinglulu status = paxb_rc_cfg_read(core_idx, CFG_RC_PMI_RDATA); 320*91f16700Schasinglulu 321*91f16700Schasinglulu /* wait for read ack bit set */ 322*91f16700Schasinglulu if ((status & CFG_RC_RACK_MASK)) { 323*91f16700Schasinglulu *val = paxb_rc_cfg_read(core_idx, CFG_RC_PMI_RDATA); 324*91f16700Schasinglulu return 0; 325*91f16700Schasinglulu } 326*91f16700Schasinglulu } while (--timeout); 327*91f16700Schasinglulu 328*91f16700Schasinglulu return -EIO; 329*91f16700Schasinglulu } 330*91f16700Schasinglulu 331*91f16700Schasinglulu 332*91f16700Schasinglulu #ifndef BOARD_PCIE_EXT_CLK 333*91f16700Schasinglulu /* 334*91f16700Schasinglulu * PCIe Override clock lookup table 335*91f16700Schasinglulu * 336*91f16700Schasinglulu * Each array index represents pcie override clock has been done 337*91f16700Schasinglulu * by CFW or not. 338*91f16700Schasinglulu */ 339*91f16700Schasinglulu static uint8_t pcie_override_clk_table[] = { 340*91f16700Schasinglulu /* PIPEMUX = 0, EP 1x16 */ 341*91f16700Schasinglulu 0x0, 342*91f16700Schasinglulu /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */ 343*91f16700Schasinglulu 0x1, 344*91f16700Schasinglulu /* PIPEMUX = 2, EP 4x4 */ 345*91f16700Schasinglulu 0x0, 346*91f16700Schasinglulu /* PIPEMUX = 3, RC 2x8, cores 0, 7 */ 347*91f16700Schasinglulu 0x0, 348*91f16700Schasinglulu /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */ 349*91f16700Schasinglulu 0x0, 350*91f16700Schasinglulu /* PIPEMUX = 5, RC 8x2, all 8 cores */ 351*91f16700Schasinglulu 0x0, 352*91f16700Schasinglulu /* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */ 353*91f16700Schasinglulu 0x0, 354*91f16700Schasinglulu /* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */ 355*91f16700Schasinglulu 0x0, 356*91f16700Schasinglulu /* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */ 357*91f16700Schasinglulu 0x0, 358*91f16700Schasinglulu /* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */ 359*91f16700Schasinglulu 0x0, 360*91f16700Schasinglulu /* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */ 361*91f16700Schasinglulu 0x0, 362*91f16700Schasinglulu /* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */ 363*91f16700Schasinglulu 0x0, 364*91f16700Schasinglulu /* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */ 365*91f16700Schasinglulu 0x0, 366*91f16700Schasinglulu /* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */ 367*91f16700Schasinglulu 0x0, 368*91f16700Schasinglulu }; 369*91f16700Schasinglulu 370*91f16700Schasinglulu /* 371*91f16700Schasinglulu * Bring up LCPLL channel 0 reference clock for PCIe serdes used in RC mode 372*91f16700Schasinglulu */ 373*91f16700Schasinglulu static int pcie_lcpll_init(void) 374*91f16700Schasinglulu { 375*91f16700Schasinglulu uintptr_t reg; 376*91f16700Schasinglulu unsigned int timeout = PCIE_LCPLL_TIMEOUT_MS; 377*91f16700Schasinglulu uint32_t val; 378*91f16700Schasinglulu 379*91f16700Schasinglulu if (pcie_override_clk_table[pipemux_idx]) { 380*91f16700Schasinglulu /* 381*91f16700Schasinglulu * Check rc_mode_override again to avoid halt 382*91f16700Schasinglulu * because of cfw uninitialized lcpll. 383*91f16700Schasinglulu */ 384*91f16700Schasinglulu reg = (uintptr_t)(PCIE_LCPLL_BASE + 385*91f16700Schasinglulu PCIE_PIPE_MUX_RC_MODE_OVERRIDE_CFG); 386*91f16700Schasinglulu val = mmio_read_32(reg); 387*91f16700Schasinglulu if (val & 0x1) 388*91f16700Schasinglulu return 0; 389*91f16700Schasinglulu else 390*91f16700Schasinglulu return -ENODEV; 391*91f16700Schasinglulu } 392*91f16700Schasinglulu 393*91f16700Schasinglulu /* power on PCIe LCPLL and its LDO */ 394*91f16700Schasinglulu reg = (uintptr_t)CRMU_AON_CTRL1; 395*91f16700Schasinglulu mmio_setbits_32(reg, CRMU_PCIE_LCPLL_PWR_ON_MASK | 396*91f16700Schasinglulu CRMU_PCIE_LCPLL_PWRON_LDO_MASK); 397*91f16700Schasinglulu udelay(PCIE_LCPLL_DELAY_US); 398*91f16700Schasinglulu 399*91f16700Schasinglulu /* remove isolation */ 400*91f16700Schasinglulu mmio_clrbits_32(reg, CRMU_PCIE_LCPLL_ISO_IN_MASK); 401*91f16700Schasinglulu udelay(PCIE_LCPLL_DELAY_US); 402*91f16700Schasinglulu 403*91f16700Schasinglulu /* disconnect termination */ 404*91f16700Schasinglulu reg = (uintptr_t)(PCIE_LCPLL_BASE + PCIE_LCPLL_CTRL13_OFFSET); 405*91f16700Schasinglulu mmio_setbits_32(reg, PCIE_LCPLL_D2C2_TERM_DISC << 406*91f16700Schasinglulu PCIE_LCPLL_D2C2_CTRL_SHIFT); 407*91f16700Schasinglulu 408*91f16700Schasinglulu /* enable CML buf1/2 and D2C2 */ 409*91f16700Schasinglulu reg = (uintptr_t)(PCIE_LCPLL_BASE + PCIE_LCPLL_CTRL3_OFFSET); 410*91f16700Schasinglulu mmio_setbits_32(reg, PCIE_LCPLL_CM_ENA << PCIE_LCPLL_EN_CTRL_SHIFT); 411*91f16700Schasinglulu 412*91f16700Schasinglulu /* select diff clock mux out as ref clock */ 413*91f16700Schasinglulu mmio_clrbits_32(reg, PCIE_LCPLL_REF_CLK_MASK); 414*91f16700Schasinglulu 415*91f16700Schasinglulu /* delay for 500 microseconds per ASIC spec for PCIe LCPLL */ 416*91f16700Schasinglulu udelay(PCIE_LCPLL_DELAY_US); 417*91f16700Schasinglulu 418*91f16700Schasinglulu /* now bring PCIe LCPLL out of reset */ 419*91f16700Schasinglulu reg = (uintptr_t)(PCIE_LCPLL_BASE + PCIE_LCPLL_CTRL0_OFFSET); 420*91f16700Schasinglulu mmio_setbits_32(reg, PCIE_LCPLL_RESETB_MASK); 421*91f16700Schasinglulu 422*91f16700Schasinglulu /* wait for PLL to lock */ 423*91f16700Schasinglulu reg = (uintptr_t)(PCIE_LCPLL_BASE + PCIE_LCPLL_STATUS_OFFSET); 424*91f16700Schasinglulu do { 425*91f16700Schasinglulu val = mmio_read_32(reg); 426*91f16700Schasinglulu if ((val & PCIE_LCPLL_LOCK_MASK) == PCIE_LCPLL_LOCK_MASK) { 427*91f16700Schasinglulu /* now bring the post divider out of reset */ 428*91f16700Schasinglulu reg = (uintptr_t)(PCIE_LCPLL_BASE + 429*91f16700Schasinglulu PCIE_LCPLL_CTRL0_OFFSET); 430*91f16700Schasinglulu mmio_setbits_32(reg, PCIE_LCPLL_P_RESETB_MASK); 431*91f16700Schasinglulu VERBOSE("PCIe LCPLL locked\n"); 432*91f16700Schasinglulu return 0; 433*91f16700Schasinglulu } 434*91f16700Schasinglulu mdelay(1); 435*91f16700Schasinglulu } while (--timeout); 436*91f16700Schasinglulu 437*91f16700Schasinglulu ERROR("PCIe LCPLL failed to lock\n"); 438*91f16700Schasinglulu return -EIO; 439*91f16700Schasinglulu } 440*91f16700Schasinglulu #else 441*91f16700Schasinglulu /* 442*91f16700Schasinglulu * Bring up EXT CLK reference clock for PCIe serdes used in RC mode 443*91f16700Schasinglulu * XTAL_BYPASS (3 << 0) 444*91f16700Schasinglulu * INTR_LC_REF (5 << 0) 445*91f16700Schasinglulu * PD_CML_LC_REF_OUT (1 << 4) 446*91f16700Schasinglulu * PD_CML_REF_CH_OUT (1 << 8) 447*91f16700Schasinglulu * CLK_MASTER_SEL (1 << 11) 448*91f16700Schasinglulu * CLK_MASTER_CTRL_A (1 << 12) 449*91f16700Schasinglulu * CLK_MASTER_CTRL_B (2 << 14) 450*91f16700Schasinglulu */ 451*91f16700Schasinglulu static const uint16_t pcie_ext_clk[][NUM_OF_PCIE_SERDES] = { 452*91f16700Schasinglulu /* PIPEMUX = 0, EP 1x16 */ 453*91f16700Schasinglulu {0}, 454*91f16700Schasinglulu /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */ 455*91f16700Schasinglulu {0}, 456*91f16700Schasinglulu /* PIPEMUX = 2, EP 4x4 */ 457*91f16700Schasinglulu {0}, 458*91f16700Schasinglulu /* PIPEMUX = 3, RC 2x8, cores 0, 7 */ 459*91f16700Schasinglulu {0x8803, 0x9115, 0x9115, 0x1115, 0x8803, 0x9115, 0x9115, 0x1115}, 460*91f16700Schasinglulu /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */ 461*91f16700Schasinglulu {0x8803, 0x1115, 0x8915, 0x1115, 0x8803, 0x1115, 0x8915, 0x1115,}, 462*91f16700Schasinglulu /* PIPEMUX = 5, RC 8x2, all 8 cores */ 463*91f16700Schasinglulu {0x0803, 0x0915, 0x0915, 0x0915, 0x0803, 0x0915, 0x0915, 0x0915,}, 464*91f16700Schasinglulu /* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */ 465*91f16700Schasinglulu {0}, 466*91f16700Schasinglulu /* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */ 467*91f16700Schasinglulu {0}, 468*91f16700Schasinglulu /* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */ 469*91f16700Schasinglulu {0}, 470*91f16700Schasinglulu /* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */ 471*91f16700Schasinglulu {0}, 472*91f16700Schasinglulu /* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */ 473*91f16700Schasinglulu {0}, 474*91f16700Schasinglulu /* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */ 475*91f16700Schasinglulu {0}, 476*91f16700Schasinglulu /* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */ 477*91f16700Schasinglulu {0}, 478*91f16700Schasinglulu /* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */ 479*91f16700Schasinglulu {0}, 480*91f16700Schasinglulu }; 481*91f16700Schasinglulu 482*91f16700Schasinglulu static void pcie_ext_clk_init(void) 483*91f16700Schasinglulu { 484*91f16700Schasinglulu unsigned int serdes; 485*91f16700Schasinglulu uint32_t val; 486*91f16700Schasinglulu 487*91f16700Schasinglulu for (serdes = 0; serdes < NUM_OF_PCIE_SERDES; serdes++) { 488*91f16700Schasinglulu val = pcie_ext_clk[pipemux_idx][serdes]; 489*91f16700Schasinglulu if (!val) 490*91f16700Schasinglulu return; 491*91f16700Schasinglulu mmio_write_32(PCIE_CORE_RESERVED_CFG + 492*91f16700Schasinglulu serdes * PCIE_CORE_PWR_OFFSET, val); 493*91f16700Schasinglulu } 494*91f16700Schasinglulu /* disable CML buf1/2 and enable D2C2 */ 495*91f16700Schasinglulu mmio_clrsetbits_32((PCIE_LCPLL_BASE + PCIE_LCPLL_CTRL3_OFFSET), 496*91f16700Schasinglulu PCIE_LCPLL_CM_BUF_ENA << PCIE_LCPLL_EN_CTRL_SHIFT, 497*91f16700Schasinglulu PCIE_LCPLL_D2C2_ENA << PCIE_LCPLL_EN_CTRL_SHIFT); 498*91f16700Schasinglulu mmio_write_32(PCIE_LCPLL_BASE + PCIE_TX_CLKMASTER_CTRL_OVERRIDE_CFG, 1); 499*91f16700Schasinglulu INFO("Overriding Clocking - using REF clock from PAD...\n"); 500*91f16700Schasinglulu } 501*91f16700Schasinglulu #endif 502*91f16700Schasinglulu 503*91f16700Schasinglulu static int load_uc(unsigned int core_idx) 504*91f16700Schasinglulu { 505*91f16700Schasinglulu return 0; 506*91f16700Schasinglulu } 507*91f16700Schasinglulu 508*91f16700Schasinglulu static int paxb_serdes_gate_clock(unsigned int core_idx, int gate_clk) 509*91f16700Schasinglulu { 510*91f16700Schasinglulu unsigned int link_width, serdes, nr_serdes; 511*91f16700Schasinglulu uintptr_t pmi_base; 512*91f16700Schasinglulu unsigned int rdata; 513*91f16700Schasinglulu uint32_t core_offset = core_idx * PCIE_CORE_PWR_OFFSET; 514*91f16700Schasinglulu 515*91f16700Schasinglulu link_width = paxb->get_link_width(core_idx); 516*91f16700Schasinglulu if (!link_width) { 517*91f16700Schasinglulu ERROR("Unsupported PIPEMUX\n"); 518*91f16700Schasinglulu return -EOPNOTSUPP; 519*91f16700Schasinglulu } 520*91f16700Schasinglulu 521*91f16700Schasinglulu nr_serdes = link_width / 2; 522*91f16700Schasinglulu pmi_base = (uintptr_t)(PCIE_CORE_PMI_CFG_BASE + core_offset); 523*91f16700Schasinglulu 524*91f16700Schasinglulu for (serdes = 0; serdes < nr_serdes; serdes++) { 525*91f16700Schasinglulu mmio_write_32(pmi_base, serdes); 526*91f16700Schasinglulu paxb_pmi_read(core_idx, PMI_ADDR_LANE0(PMI_PLL_CTRL_4), &rdata); 527*91f16700Schasinglulu if (!gate_clk) 528*91f16700Schasinglulu rdata |= PMI_SERDES_CLK_ENABLE; 529*91f16700Schasinglulu else 530*91f16700Schasinglulu rdata &= ~PMI_SERDES_CLK_ENABLE; 531*91f16700Schasinglulu paxb_pmi_write(core_idx, PMI_ADDR_BCAST(PMI_PLL_CTRL_4), rdata); 532*91f16700Schasinglulu } 533*91f16700Schasinglulu return 0; 534*91f16700Schasinglulu } 535*91f16700Schasinglulu 536*91f16700Schasinglulu static int paxb_gen3_serdes_init(unsigned int core_idx, uint32_t nSerdes) 537*91f16700Schasinglulu { 538*91f16700Schasinglulu uint32_t rdata; 539*91f16700Schasinglulu int serdes; 540*91f16700Schasinglulu uintptr_t pmi_base; 541*91f16700Schasinglulu unsigned int timeout; 542*91f16700Schasinglulu unsigned int reg_d230, reg_d267; 543*91f16700Schasinglulu 544*91f16700Schasinglulu 545*91f16700Schasinglulu pmi_base = (uintptr_t)(PCIE_CORE_PMI_CFG_BASE + 546*91f16700Schasinglulu (core_idx * PCIE_CORE_PWR_OFFSET)); 547*91f16700Schasinglulu 548*91f16700Schasinglulu for (serdes = 0; serdes < nSerdes; serdes++) { 549*91f16700Schasinglulu /* select the PMI interface */ 550*91f16700Schasinglulu mmio_write_32(pmi_base, serdes); 551*91f16700Schasinglulu 552*91f16700Schasinglulu /* Clock enable */ 553*91f16700Schasinglulu paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_CLK_CTRL0), 554*91f16700Schasinglulu 0x3); 555*91f16700Schasinglulu 556*91f16700Schasinglulu /* Release reset of master */ 557*91f16700Schasinglulu paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_RST_CTRL0), 558*91f16700Schasinglulu 0x1); 559*91f16700Schasinglulu 560*91f16700Schasinglulu /* clearing PRAM memory */ 561*91f16700Schasinglulu paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_AHB_CTRL0), 562*91f16700Schasinglulu 0x100); 563*91f16700Schasinglulu 564*91f16700Schasinglulu timeout = UC_RAM_INIT_TIMEOUT; 565*91f16700Schasinglulu do { 566*91f16700Schasinglulu paxb_pmi_read(core_idx, 567*91f16700Schasinglulu PMI_ADDR_LANE0(UC_A_AHB_STAT0), 568*91f16700Schasinglulu &rdata); 569*91f16700Schasinglulu } while ((rdata & 0x01) == 0 && timeout--); 570*91f16700Schasinglulu 571*91f16700Schasinglulu if (!timeout) 572*91f16700Schasinglulu return -EIO; 573*91f16700Schasinglulu 574*91f16700Schasinglulu timeout = UC_RAM_INIT_TIMEOUT; 575*91f16700Schasinglulu do { 576*91f16700Schasinglulu paxb_pmi_read(core_idx, 577*91f16700Schasinglulu PMI_ADDR_LANE1(UC_A_AHB_STAT0), 578*91f16700Schasinglulu &rdata); 579*91f16700Schasinglulu } while ((rdata & 0x01) == 0 && timeout--); 580*91f16700Schasinglulu 581*91f16700Schasinglulu if (!timeout) 582*91f16700Schasinglulu return -EIO; 583*91f16700Schasinglulu 584*91f16700Schasinglulu /* clearing PRAM memory */ 585*91f16700Schasinglulu paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_AHB_CTRL0), 586*91f16700Schasinglulu 0); 587*91f16700Schasinglulu 588*91f16700Schasinglulu /* to identify 2 lane serdes */ 589*91f16700Schasinglulu paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_DBG1), 0x1); 590*91f16700Schasinglulu 591*91f16700Schasinglulu /* De-Assert Pram & master resets */ 592*91f16700Schasinglulu paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_RST_CTRL0), 593*91f16700Schasinglulu 0x9); 594*91f16700Schasinglulu 595*91f16700Schasinglulu if (load_uc(core_idx)) 596*91f16700Schasinglulu return -EIO; 597*91f16700Schasinglulu 598*91f16700Schasinglulu /* UC UC ready for command */ 599*91f16700Schasinglulu paxb_pmi_read(core_idx, PMI_ADDR_LANE0(DSC_UC_CTRL), 600*91f16700Schasinglulu &rdata); 601*91f16700Schasinglulu rdata |= DSC_UC_CTRL_RDY_CMD; 602*91f16700Schasinglulu paxb_pmi_write(core_idx, PMI_ADDR_LANE0(DSC_UC_CTRL), 603*91f16700Schasinglulu rdata); 604*91f16700Schasinglulu 605*91f16700Schasinglulu paxb_pmi_read(core_idx, PMI_ADDR_LANE1(DSC_UC_CTRL), 606*91f16700Schasinglulu &rdata); 607*91f16700Schasinglulu rdata |= DSC_UC_CTRL_RDY_CMD; 608*91f16700Schasinglulu paxb_pmi_write(core_idx, PMI_ADDR_LANE1(DSC_UC_CTRL), 609*91f16700Schasinglulu rdata); 610*91f16700Schasinglulu 611*91f16700Schasinglulu /* Lane reset */ 612*91f16700Schasinglulu paxb_pmi_write(core_idx, 613*91f16700Schasinglulu PMI_ADDR_BCAST(LANE_DBG_RST_CTRL), 0x3); 614*91f16700Schasinglulu 615*91f16700Schasinglulu /* De-Assert Core and Master resets */ 616*91f16700Schasinglulu paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_RST_CTRL0), 617*91f16700Schasinglulu 0x3); 618*91f16700Schasinglulu 619*91f16700Schasinglulu timeout = UC_INIT_TIMEOUT; 620*91f16700Schasinglulu while (timeout--) { 621*91f16700Schasinglulu paxb_pmi_read(core_idx, 622*91f16700Schasinglulu PMI_ADDR_LANE0(UC_VERSION_NUM), 623*91f16700Schasinglulu ®_d230); 624*91f16700Schasinglulu paxb_pmi_read(core_idx, 625*91f16700Schasinglulu PMI_ADDR_LANE0(DSC_SM_CTL22), 626*91f16700Schasinglulu ®_d267); 627*91f16700Schasinglulu 628*91f16700Schasinglulu if (((reg_d230 & 0xffff) != 0) & 629*91f16700Schasinglulu ((reg_d267 & 0xc000) == 0xc000)) { 630*91f16700Schasinglulu break; 631*91f16700Schasinglulu } 632*91f16700Schasinglulu mdelay(1); 633*91f16700Schasinglulu } 634*91f16700Schasinglulu 635*91f16700Schasinglulu if (!timeout) 636*91f16700Schasinglulu return -EIO; 637*91f16700Schasinglulu 638*91f16700Schasinglulu timeout = UC_INIT_TIMEOUT; 639*91f16700Schasinglulu while (timeout--) { 640*91f16700Schasinglulu paxb_pmi_read(core_idx, 641*91f16700Schasinglulu PMI_ADDR_LANE1(UC_VERSION_NUM), 642*91f16700Schasinglulu ®_d230); 643*91f16700Schasinglulu paxb_pmi_read(core_idx, 644*91f16700Schasinglulu PMI_ADDR_LANE1(DSC_SM_CTL22), 645*91f16700Schasinglulu ®_d267); 646*91f16700Schasinglulu 647*91f16700Schasinglulu if (((reg_d230 & 0xffff) != 0) & 648*91f16700Schasinglulu ((reg_d267 & 0xc000) == 0xc000)) { 649*91f16700Schasinglulu break; 650*91f16700Schasinglulu } 651*91f16700Schasinglulu mdelay(1); 652*91f16700Schasinglulu } 653*91f16700Schasinglulu 654*91f16700Schasinglulu if (!timeout) 655*91f16700Schasinglulu return -EIO; 656*91f16700Schasinglulu } 657*91f16700Schasinglulu return 0; 658*91f16700Schasinglulu } 659*91f16700Schasinglulu 660*91f16700Schasinglulu static int pcie_serdes_requires_patch(unsigned int serdes_idx) 661*91f16700Schasinglulu { 662*91f16700Schasinglulu if (pipemux_idx != SERDES_PATCH_PIPEMUX_INDEX) 663*91f16700Schasinglulu return 0; 664*91f16700Schasinglulu 665*91f16700Schasinglulu return !!((SERDES_PATCH_INDEX >> serdes_idx) & 0x1); 666*91f16700Schasinglulu } 667*91f16700Schasinglulu 668*91f16700Schasinglulu static void pcie_tx_coeff_p7(unsigned int core_idx) 669*91f16700Schasinglulu { 670*91f16700Schasinglulu paxb_pmi_write(core_idx, PMI_ADDR_BCAST(0xd11b), 0x00aa); 671*91f16700Schasinglulu paxb_pmi_write(core_idx, PMI_ADDR_BCAST(0xd11c), 0x1155); 672*91f16700Schasinglulu paxb_pmi_write(core_idx, PMI_ADDR_BCAST(0xd11d), 0x2449); 673*91f16700Schasinglulu paxb_pmi_write(core_idx, PMI_ADDR_BCAST(0xd11e), 0x000f); 674*91f16700Schasinglulu paxb_pmi_write(core_idx, PMI_ADDR_BCAST(0xd307), 0x0001); 675*91f16700Schasinglulu } 676*91f16700Schasinglulu 677*91f16700Schasinglulu 678*91f16700Schasinglulu static unsigned int paxb_sr_get_rc_link_width(unsigned int core_idx) 679*91f16700Schasinglulu { 680*91f16700Schasinglulu return link_width_table[pipemux_idx][core_idx]; 681*91f16700Schasinglulu } 682*91f16700Schasinglulu 683*91f16700Schasinglulu static uint32_t paxb_sr_get_rc_link_speed(void) 684*91f16700Schasinglulu { 685*91f16700Schasinglulu return GEN3_LINK_SPEED; 686*91f16700Schasinglulu } 687*91f16700Schasinglulu 688*91f16700Schasinglulu 689*91f16700Schasinglulu static int paxb_serdes_init(unsigned int core_idx, unsigned int nr_serdes) 690*91f16700Schasinglulu { 691*91f16700Schasinglulu uint32_t core_offset = core_idx * PCIE_CORE_PWR_OFFSET; 692*91f16700Schasinglulu unsigned int serdes; 693*91f16700Schasinglulu uintptr_t pmi_base; 694*91f16700Schasinglulu int ret; 695*91f16700Schasinglulu 696*91f16700Schasinglulu /* 697*91f16700Schasinglulu * Each serdes has a x2 link width 698*91f16700Schasinglulu * 699*91f16700Schasinglulu * Use PAXB to patch the serdes for proper RX termination through the 700*91f16700Schasinglulu * PMI interface 701*91f16700Schasinglulu */ 702*91f16700Schasinglulu pmi_base = (uintptr_t)(PCIE_CORE_PMI_CFG_BASE + core_offset); 703*91f16700Schasinglulu for (serdes = 0; serdes < nr_serdes; serdes++) { 704*91f16700Schasinglulu /* select the PMI interface */ 705*91f16700Schasinglulu mmio_write_32(pmi_base, serdes); 706*91f16700Schasinglulu 707*91f16700Schasinglulu /* patch Serdes for RX termination */ 708*91f16700Schasinglulu ret = paxb_pmi_write(core_idx, PMI_RX_TERM_SEQ, 709*91f16700Schasinglulu PMI_RX_TERM_VAL); 710*91f16700Schasinglulu if (ret) 711*91f16700Schasinglulu goto err_pmi; 712*91f16700Schasinglulu 713*91f16700Schasinglulu ret = paxb_pmi_write(core_idx, MERLIN16_PCIE_BLK2_PWRMGMT_7, 714*91f16700Schasinglulu MERLIN16_PCIE_BLK2_PWRMGMT_7_VAL); 715*91f16700Schasinglulu if (ret) 716*91f16700Schasinglulu goto err_pmi; 717*91f16700Schasinglulu 718*91f16700Schasinglulu ret = paxb_pmi_write(core_idx, MERLIN16_PCIE_BLK2_PWRMGMT_8, 719*91f16700Schasinglulu MERLIN16_PCIE_BLK2_PWRMGMT_8_VAL); 720*91f16700Schasinglulu if (ret) 721*91f16700Schasinglulu goto err_pmi; 722*91f16700Schasinglulu 723*91f16700Schasinglulu ret = paxb_pmi_write(core_idx, MERLIN16_AMS_TX_CTRL_5, 724*91f16700Schasinglulu MERLIN16_AMS_TX_CTRL_5_VAL); 725*91f16700Schasinglulu if (ret) 726*91f16700Schasinglulu goto err_pmi; 727*91f16700Schasinglulu 728*91f16700Schasinglulu pcie_tx_coeff_p7(core_idx); 729*91f16700Schasinglulu 730*91f16700Schasinglulu if (pcie_serdes_requires_patch(serdes)) { 731*91f16700Schasinglulu if (((core_idx == 0) || (core_idx == 7))) { 732*91f16700Schasinglulu ret = paxb_pmi_write(core_idx, 733*91f16700Schasinglulu PMI_X8_CORE0_7_PATCH_SEQ, 734*91f16700Schasinglulu PMI_X8_CORE0_7_PATCH_VAL); 735*91f16700Schasinglulu if (ret) 736*91f16700Schasinglulu goto err_pmi; 737*91f16700Schasinglulu } 738*91f16700Schasinglulu } 739*91f16700Schasinglulu } 740*91f16700Schasinglulu 741*91f16700Schasinglulu return 0; 742*91f16700Schasinglulu 743*91f16700Schasinglulu err_pmi: 744*91f16700Schasinglulu ERROR("PCIe PMI write failed\n"); 745*91f16700Schasinglulu return ret; 746*91f16700Schasinglulu } 747*91f16700Schasinglulu 748*91f16700Schasinglulu static int paxb_sr_phy_init(void) 749*91f16700Schasinglulu { 750*91f16700Schasinglulu int ret; 751*91f16700Schasinglulu unsigned int core_idx; 752*91f16700Schasinglulu 753*91f16700Schasinglulu #ifndef BOARD_PCIE_EXT_CLK 754*91f16700Schasinglulu ret = pcie_lcpll_init(); 755*91f16700Schasinglulu if (ret) 756*91f16700Schasinglulu return ret; 757*91f16700Schasinglulu #else 758*91f16700Schasinglulu pcie_ext_clk_init(); 759*91f16700Schasinglulu #endif 760*91f16700Schasinglulu 761*91f16700Schasinglulu for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) { 762*91f16700Schasinglulu if (!pcie_core_needs_enable(core_idx)) 763*91f16700Schasinglulu continue; 764*91f16700Schasinglulu unsigned int link_width; 765*91f16700Schasinglulu 766*91f16700Schasinglulu paxb_serdes_gate_clock(core_idx, 0); 767*91f16700Schasinglulu 768*91f16700Schasinglulu link_width = paxb->get_link_width(core_idx); 769*91f16700Schasinglulu if (!link_width) { 770*91f16700Schasinglulu ERROR("Unsupported PIPEMUX\n"); 771*91f16700Schasinglulu return -EOPNOTSUPP; 772*91f16700Schasinglulu } 773*91f16700Schasinglulu 774*91f16700Schasinglulu ret = paxb_serdes_init(core_idx, link_width / 2); 775*91f16700Schasinglulu if (ret) { 776*91f16700Schasinglulu ERROR("PCIe serdes initialization failed for core %u\n", 777*91f16700Schasinglulu core_idx); 778*91f16700Schasinglulu return ret; 779*91f16700Schasinglulu } 780*91f16700Schasinglulu 781*91f16700Schasinglulu 782*91f16700Schasinglulu ret = paxb_gen3_serdes_init(core_idx, link_width / 2); 783*91f16700Schasinglulu if (ret) { 784*91f16700Schasinglulu ERROR("PCIe GEN3 serdes initialization failed\n"); 785*91f16700Schasinglulu return ret; 786*91f16700Schasinglulu } 787*91f16700Schasinglulu 788*91f16700Schasinglulu } 789*91f16700Schasinglulu return 0; 790*91f16700Schasinglulu } 791*91f16700Schasinglulu 792*91f16700Schasinglulu const paxb_cfg sr_paxb_cfg = { 793*91f16700Schasinglulu .type = PAXB_SR, 794*91f16700Schasinglulu .device_id = SR_B0_DEVICE_ID, 795*91f16700Schasinglulu .pipemux_init = pipemux_sr_init, 796*91f16700Schasinglulu .phy_init = paxb_sr_phy_init, 797*91f16700Schasinglulu .core_needs_enable = paxb_sr_core_needs_enable, 798*91f16700Schasinglulu .num_cores = NUM_OF_SR_PCIE_CORES, 799*91f16700Schasinglulu .get_link_width = paxb_sr_get_rc_link_width, 800*91f16700Schasinglulu .get_link_speed = paxb_sr_get_rc_link_speed, 801*91f16700Schasinglulu }; 802*91f16700Schasinglulu 803*91f16700Schasinglulu const paxb_cfg *paxb_get_sr_config(void) 804*91f16700Schasinglulu { 805*91f16700Schasinglulu return &sr_paxb_cfg; 806*91f16700Schasinglulu } 807