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