xref: /arm-trusted-firmware/plat/brcm/board/stingray/src/sr_paxb_phy.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
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 					&reg_d230);
624*91f16700Schasinglulu 			paxb_pmi_read(core_idx,
625*91f16700Schasinglulu 					PMI_ADDR_LANE0(DSC_SM_CTL22),
626*91f16700Schasinglulu 					&reg_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 					&reg_d230);
643*91f16700Schasinglulu 			paxb_pmi_read(core_idx,
644*91f16700Schasinglulu 					PMI_ADDR_LANE1(DSC_SM_CTL22),
645*91f16700Schasinglulu 					&reg_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