1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0
2edb47025SStefan Roese /*
3edb47025SStefan Roese * Copyright (C) Marvell International Ltd. and its affiliates
4edb47025SStefan Roese */
5edb47025SStefan Roese
6edb47025SStefan Roese #include <common.h>
7edb47025SStefan Roese #include <spl.h>
8edb47025SStefan Roese #include <asm/io.h>
9edb47025SStefan Roese #include <asm/arch/cpu.h>
10edb47025SStefan Roese #include <asm/arch/soc.h>
11edb47025SStefan Roese
12edb47025SStefan Roese #include "ctrl_pex.h"
13edb47025SStefan Roese #include "sys_env_lib.h"
14edb47025SStefan Roese
board_pex_config(void)152ad43094SMario Six __weak void board_pex_config(void)
162ad43094SMario Six {
172ad43094SMario Six /* nothing in this weak default implementation */
182ad43094SMario Six }
192ad43094SMario Six
hws_pex_config(const struct serdes_map * serdes_map,u8 count)20490753acSKevin Smith int hws_pex_config(const struct serdes_map *serdes_map, u8 count)
21edb47025SStefan Roese {
22edb47025SStefan Roese u32 pex_idx, tmp, next_busno, first_busno, temp_pex_reg,
23edb47025SStefan Roese temp_reg, addr, dev_id, ctrl_mode;
24edb47025SStefan Roese enum serdes_type serdes_type;
25490753acSKevin Smith u32 idx;
26edb47025SStefan Roese
27edb47025SStefan Roese DEBUG_INIT_FULL_S("\n### hws_pex_config ###\n");
28edb47025SStefan Roese
29490753acSKevin Smith for (idx = 0; idx < count; idx++) {
30edb47025SStefan Roese serdes_type = serdes_map[idx].serdes_type;
31edb47025SStefan Roese /* configuration for PEX only */
32edb47025SStefan Roese if ((serdes_type != PEX0) && (serdes_type != PEX1) &&
33edb47025SStefan Roese (serdes_type != PEX2) && (serdes_type != PEX3))
34edb47025SStefan Roese continue;
35edb47025SStefan Roese
36edb47025SStefan Roese if ((serdes_type != PEX0) &&
37edb47025SStefan Roese ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
38edb47025SStefan Roese (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
39edb47025SStefan Roese /* for PEX by4 - relevant for the first port only */
40edb47025SStefan Roese continue;
41edb47025SStefan Roese }
42edb47025SStefan Roese
43edb47025SStefan Roese pex_idx = serdes_type - PEX0;
44edb47025SStefan Roese tmp = reg_read(PEX_CAPABILITIES_REG(pex_idx));
45edb47025SStefan Roese tmp &= ~(0xf << 20);
46edb47025SStefan Roese tmp |= (0x4 << 20);
47edb47025SStefan Roese reg_write(PEX_CAPABILITIES_REG(pex_idx), tmp);
48edb47025SStefan Roese }
49edb47025SStefan Roese
50edb47025SStefan Roese tmp = reg_read(SOC_CTRL_REG);
51edb47025SStefan Roese tmp &= ~0x03;
52edb47025SStefan Roese
53490753acSKevin Smith for (idx = 0; idx < count; idx++) {
54edb47025SStefan Roese serdes_type = serdes_map[idx].serdes_type;
55edb47025SStefan Roese if ((serdes_type != PEX0) &&
56edb47025SStefan Roese ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
57edb47025SStefan Roese (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
58edb47025SStefan Roese /* for PEX by4 - relevant for the first port only */
59edb47025SStefan Roese continue;
60edb47025SStefan Roese }
61edb47025SStefan Roese
62edb47025SStefan Roese switch (serdes_type) {
63edb47025SStefan Roese case PEX0:
64edb47025SStefan Roese tmp |= 0x1 << PCIE0_ENABLE_OFFS;
65edb47025SStefan Roese break;
66edb47025SStefan Roese case PEX1:
67edb47025SStefan Roese tmp |= 0x1 << PCIE1_ENABLE_OFFS;
68edb47025SStefan Roese break;
69edb47025SStefan Roese case PEX2:
70edb47025SStefan Roese tmp |= 0x1 << PCIE2_ENABLE_OFFS;
71edb47025SStefan Roese break;
72edb47025SStefan Roese case PEX3:
73edb47025SStefan Roese tmp |= 0x1 << PCIE3_ENABLE_OFFS;
74edb47025SStefan Roese break;
75edb47025SStefan Roese default:
76edb47025SStefan Roese break;
77edb47025SStefan Roese }
78edb47025SStefan Roese }
79edb47025SStefan Roese
80edb47025SStefan Roese reg_write(SOC_CTRL_REG, tmp);
81edb47025SStefan Roese
82edb47025SStefan Roese /* Support gen1/gen2 */
83edb47025SStefan Roese DEBUG_INIT_FULL_S("Support gen1/gen2\n");
842ad43094SMario Six
852ad43094SMario Six board_pex_config();
862ad43094SMario Six
87edb47025SStefan Roese next_busno = 0;
88edb47025SStefan Roese mdelay(150);
89edb47025SStefan Roese
90490753acSKevin Smith for (idx = 0; idx < count; idx++) {
91edb47025SStefan Roese serdes_type = serdes_map[idx].serdes_type;
92edb47025SStefan Roese DEBUG_INIT_FULL_S(" serdes_type=0x");
93edb47025SStefan Roese DEBUG_INIT_FULL_D(serdes_type, 8);
94edb47025SStefan Roese DEBUG_INIT_FULL_S("\n");
95edb47025SStefan Roese DEBUG_INIT_FULL_S(" idx=0x");
96edb47025SStefan Roese DEBUG_INIT_FULL_D(idx, 8);
97edb47025SStefan Roese DEBUG_INIT_FULL_S("\n");
98edb47025SStefan Roese
99edb47025SStefan Roese /* Configuration for PEX only */
100edb47025SStefan Roese if ((serdes_type != PEX0) && (serdes_type != PEX1) &&
101edb47025SStefan Roese (serdes_type != PEX2) && (serdes_type != PEX3))
102edb47025SStefan Roese continue;
103edb47025SStefan Roese
104edb47025SStefan Roese if ((serdes_type != PEX0) &&
105edb47025SStefan Roese ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
106edb47025SStefan Roese (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
107edb47025SStefan Roese /* for PEX by4 - relevant for the first port only */
108edb47025SStefan Roese continue;
109edb47025SStefan Roese }
110edb47025SStefan Roese
111edb47025SStefan Roese pex_idx = serdes_type - PEX0;
112edb47025SStefan Roese tmp = reg_read(PEX_DBG_STATUS_REG(pex_idx));
113edb47025SStefan Roese
114edb47025SStefan Roese first_busno = next_busno;
115edb47025SStefan Roese if ((tmp & 0x7f) != 0x7e) {
116edb47025SStefan Roese DEBUG_INIT_S("PCIe, Idx ");
117edb47025SStefan Roese DEBUG_INIT_D(pex_idx, 1);
118edb47025SStefan Roese DEBUG_INIT_S(": detected no link\n");
119edb47025SStefan Roese continue;
120edb47025SStefan Roese }
121edb47025SStefan Roese
122edb47025SStefan Roese next_busno++;
123edb47025SStefan Roese temp_pex_reg = reg_read((PEX_CFG_DIRECT_ACCESS
124edb47025SStefan Roese (pex_idx, PEX_LINK_CAPABILITY_REG)));
125edb47025SStefan Roese temp_pex_reg &= 0xf;
126edb47025SStefan Roese if (temp_pex_reg != 0x2)
127edb47025SStefan Roese continue;
128edb47025SStefan Roese
129edb47025SStefan Roese temp_reg = (reg_read(PEX_CFG_DIRECT_ACCESS(
130edb47025SStefan Roese pex_idx,
131edb47025SStefan Roese PEX_LINK_CTRL_STAT_REG)) &
132edb47025SStefan Roese 0xf0000) >> 16;
133edb47025SStefan Roese
134edb47025SStefan Roese /* Check if the link established is GEN1 */
135edb47025SStefan Roese DEBUG_INIT_FULL_S
136edb47025SStefan Roese ("Checking if the link established is gen1\n");
137edb47025SStefan Roese if (temp_reg != 0x1)
138edb47025SStefan Roese continue;
139edb47025SStefan Roese
140edb47025SStefan Roese pex_local_bus_num_set(pex_idx, first_busno);
141edb47025SStefan Roese pex_local_dev_num_set(pex_idx, 1);
142edb47025SStefan Roese DEBUG_INIT_FULL_S("PCIe, Idx ");
143edb47025SStefan Roese DEBUG_INIT_FULL_D(pex_idx, 1);
144edb47025SStefan Roese
145edb47025SStefan Roese DEBUG_INIT_S(":** Link is Gen1, check the EP capability\n");
146edb47025SStefan Roese /* link is Gen1, check the EP capability */
147edb47025SStefan Roese addr = pex_config_read(pex_idx, first_busno, 0, 0, 0x34) & 0xff;
148edb47025SStefan Roese DEBUG_INIT_FULL_C("pex_config_read: return addr=0x%x", addr, 4);
149edb47025SStefan Roese if (addr == 0xff) {
150edb47025SStefan Roese DEBUG_INIT_FULL_C
151edb47025SStefan Roese ("pex_config_read: return 0xff -->PCIe (%d): Detected No Link.",
152edb47025SStefan Roese pex_idx, 1);
153edb47025SStefan Roese continue;
154edb47025SStefan Roese }
155edb47025SStefan Roese
156edb47025SStefan Roese while ((pex_config_read(pex_idx, first_busno, 0, 0, addr)
157edb47025SStefan Roese & 0xff) != 0x10) {
158edb47025SStefan Roese addr = (pex_config_read(pex_idx, first_busno, 0,
159edb47025SStefan Roese 0, addr) & 0xff00) >> 8;
160edb47025SStefan Roese }
161edb47025SStefan Roese
162edb47025SStefan Roese /* Check for Gen2 and above */
163edb47025SStefan Roese if ((pex_config_read(pex_idx, first_busno, 0, 0,
164edb47025SStefan Roese addr + 0xc) & 0xf) < 0x2) {
165edb47025SStefan Roese DEBUG_INIT_S("PCIe, Idx ");
166edb47025SStefan Roese DEBUG_INIT_D(pex_idx, 1);
167edb47025SStefan Roese DEBUG_INIT_S(": remains Gen1\n");
168edb47025SStefan Roese continue;
169edb47025SStefan Roese }
170edb47025SStefan Roese
171edb47025SStefan Roese tmp = reg_read(PEX_LINK_CTRL_STATUS2_REG(pex_idx));
172edb47025SStefan Roese DEBUG_RD_REG(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp);
173edb47025SStefan Roese tmp &= ~(BIT(0) | BIT(1));
174edb47025SStefan Roese tmp |= BIT(1);
175edb47025SStefan Roese tmp |= BIT(6); /* Select Deemphasize (-3.5d_b) */
176edb47025SStefan Roese reg_write(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp);
177edb47025SStefan Roese DEBUG_WR_REG(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp);
178edb47025SStefan Roese
179edb47025SStefan Roese tmp = reg_read(PEX_CTRL_REG(pex_idx));
180edb47025SStefan Roese DEBUG_RD_REG(PEX_CTRL_REG(pex_idx), tmp);
181edb47025SStefan Roese tmp |= BIT(10);
182edb47025SStefan Roese reg_write(PEX_CTRL_REG(pex_idx), tmp);
183edb47025SStefan Roese DEBUG_WR_REG(PEX_CTRL_REG(pex_idx), tmp);
184edb47025SStefan Roese
185edb47025SStefan Roese /*
186edb47025SStefan Roese * We need to wait 10ms before reading the PEX_DBG_STATUS_REG
187edb47025SStefan Roese * in order not to read the status of the former state
188edb47025SStefan Roese */
189edb47025SStefan Roese mdelay(10);
190edb47025SStefan Roese
191edb47025SStefan Roese DEBUG_INIT_S("PCIe, Idx ");
192edb47025SStefan Roese DEBUG_INIT_D(pex_idx, 1);
193edb47025SStefan Roese DEBUG_INIT_S
194c90d7ab6SChris Packham (": Link upgraded to Gen2 based on client capabilities\n");
195edb47025SStefan Roese }
196edb47025SStefan Roese
197edb47025SStefan Roese /* Update pex DEVICE ID */
198edb47025SStefan Roese ctrl_mode = sys_env_model_get();
199edb47025SStefan Roese
200490753acSKevin Smith for (idx = 0; idx < count; idx++) {
201edb47025SStefan Roese serdes_type = serdes_map[idx].serdes_type;
202edb47025SStefan Roese /* configuration for PEX only */
203edb47025SStefan Roese if ((serdes_type != PEX0) && (serdes_type != PEX1) &&
204edb47025SStefan Roese (serdes_type != PEX2) && (serdes_type != PEX3))
205edb47025SStefan Roese continue;
206edb47025SStefan Roese
207edb47025SStefan Roese if ((serdes_type != PEX0) &&
208edb47025SStefan Roese ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
209edb47025SStefan Roese (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
210edb47025SStefan Roese /* for PEX by4 - relevant for the first port only */
211edb47025SStefan Roese continue;
212edb47025SStefan Roese }
213edb47025SStefan Roese
214edb47025SStefan Roese pex_idx = serdes_type - PEX0;
215edb47025SStefan Roese dev_id = reg_read(PEX_CFG_DIRECT_ACCESS
216edb47025SStefan Roese (pex_idx, PEX_DEVICE_AND_VENDOR_ID));
217edb47025SStefan Roese dev_id &= 0xffff;
218edb47025SStefan Roese dev_id |= ((ctrl_mode << 16) & 0xffff0000);
219edb47025SStefan Roese reg_write(PEX_CFG_DIRECT_ACCESS
220edb47025SStefan Roese (pex_idx, PEX_DEVICE_AND_VENDOR_ID), dev_id);
221edb47025SStefan Roese }
222edb47025SStefan Roese DEBUG_INIT_FULL_C("Update PEX Device ID ", ctrl_mode, 4);
223edb47025SStefan Roese
224edb47025SStefan Roese return MV_OK;
225edb47025SStefan Roese }
226edb47025SStefan Roese
pex_local_bus_num_set(u32 pex_if,u32 bus_num)227edb47025SStefan Roese int pex_local_bus_num_set(u32 pex_if, u32 bus_num)
228edb47025SStefan Roese {
229edb47025SStefan Roese u32 pex_status;
230edb47025SStefan Roese
231edb47025SStefan Roese DEBUG_INIT_FULL_S("\n### pex_local_bus_num_set ###\n");
232edb47025SStefan Roese
233edb47025SStefan Roese if (bus_num >= MAX_PEX_BUSSES) {
234edb47025SStefan Roese DEBUG_INIT_C("pex_local_bus_num_set: Illegal bus number %d\n",
235edb47025SStefan Roese bus_num, 4);
236edb47025SStefan Roese return MV_BAD_PARAM;
237edb47025SStefan Roese }
238edb47025SStefan Roese
239edb47025SStefan Roese pex_status = reg_read(PEX_STATUS_REG(pex_if));
240edb47025SStefan Roese pex_status &= ~PXSR_PEX_BUS_NUM_MASK;
241edb47025SStefan Roese pex_status |=
242edb47025SStefan Roese (bus_num << PXSR_PEX_BUS_NUM_OFFS) & PXSR_PEX_BUS_NUM_MASK;
243edb47025SStefan Roese reg_write(PEX_STATUS_REG(pex_if), pex_status);
244edb47025SStefan Roese
245edb47025SStefan Roese return MV_OK;
246edb47025SStefan Roese }
247edb47025SStefan Roese
pex_local_dev_num_set(u32 pex_if,u32 dev_num)248edb47025SStefan Roese int pex_local_dev_num_set(u32 pex_if, u32 dev_num)
249edb47025SStefan Roese {
250edb47025SStefan Roese u32 pex_status;
251edb47025SStefan Roese
252edb47025SStefan Roese DEBUG_INIT_FULL_S("\n### pex_local_dev_num_set ###\n");
253edb47025SStefan Roese
254edb47025SStefan Roese pex_status = reg_read(PEX_STATUS_REG(pex_if));
255edb47025SStefan Roese pex_status &= ~PXSR_PEX_DEV_NUM_MASK;
256edb47025SStefan Roese pex_status |=
257edb47025SStefan Roese (dev_num << PXSR_PEX_DEV_NUM_OFFS) & PXSR_PEX_DEV_NUM_MASK;
258edb47025SStefan Roese reg_write(PEX_STATUS_REG(pex_if), pex_status);
259edb47025SStefan Roese
260edb47025SStefan Roese return MV_OK;
261edb47025SStefan Roese }
262edb47025SStefan Roese
263edb47025SStefan Roese /*
264edb47025SStefan Roese * pex_config_read - Read from configuration space
265edb47025SStefan Roese *
266edb47025SStefan Roese * DESCRIPTION:
267edb47025SStefan Roese * This function performs a 32 bit read from PEX configuration space.
268edb47025SStefan Roese * It supports both type 0 and type 1 of Configuration Transactions
269edb47025SStefan Roese * (local and over bridge). In order to read from local bus segment, use
270edb47025SStefan Roese * bus number retrieved from pex_local_bus_num_get(). Other bus numbers
271edb47025SStefan Roese * will result configuration transaction of type 1 (over bridge).
272edb47025SStefan Roese *
273edb47025SStefan Roese * INPUT:
274edb47025SStefan Roese * pex_if - PEX interface number.
275edb47025SStefan Roese * bus - PEX segment bus number.
276edb47025SStefan Roese * dev - PEX device number.
277edb47025SStefan Roese * func - Function number.
278edb47025SStefan Roese * reg_offs - Register offset.
279edb47025SStefan Roese *
280edb47025SStefan Roese * OUTPUT:
281edb47025SStefan Roese * None.
282edb47025SStefan Roese *
283edb47025SStefan Roese * RETURN:
284edb47025SStefan Roese * 32bit register data, 0xffffffff on error
285edb47025SStefan Roese */
pex_config_read(u32 pex_if,u32 bus,u32 dev,u32 func,u32 reg_off)286edb47025SStefan Roese u32 pex_config_read(u32 pex_if, u32 bus, u32 dev, u32 func, u32 reg_off)
287edb47025SStefan Roese {
288edb47025SStefan Roese u32 pex_data = 0;
289edb47025SStefan Roese u32 local_dev, local_bus;
290edb47025SStefan Roese u32 pex_status;
291edb47025SStefan Roese
292edb47025SStefan Roese pex_status = reg_read(PEX_STATUS_REG(pex_if));
293edb47025SStefan Roese local_dev =
294edb47025SStefan Roese ((pex_status & PXSR_PEX_DEV_NUM_MASK) >> PXSR_PEX_DEV_NUM_OFFS);
295edb47025SStefan Roese local_bus =
296edb47025SStefan Roese ((pex_status & PXSR_PEX_BUS_NUM_MASK) >> PXSR_PEX_BUS_NUM_OFFS);
297edb47025SStefan Roese
298edb47025SStefan Roese /*
299edb47025SStefan Roese * In PCI Express we have only one device number
300edb47025SStefan Roese * and this number is the first number we encounter
301edb47025SStefan Roese * else that the local_dev
302edb47025SStefan Roese * spec pex define return on config read/write on any device
303edb47025SStefan Roese */
304edb47025SStefan Roese if (bus == local_bus) {
305edb47025SStefan Roese if (local_dev == 0) {
306edb47025SStefan Roese /*
307edb47025SStefan Roese * if local dev is 0 then the first number we encounter
308edb47025SStefan Roese * after 0 is 1
309edb47025SStefan Roese */
310edb47025SStefan Roese if ((dev != 1) && (dev != local_dev))
311edb47025SStefan Roese return MV_ERROR;
312edb47025SStefan Roese } else {
313edb47025SStefan Roese /*
314edb47025SStefan Roese * if local dev is not 0 then the first number we
315edb47025SStefan Roese * encounter is 0
316edb47025SStefan Roese */
317edb47025SStefan Roese if ((dev != 0) && (dev != local_dev))
318edb47025SStefan Roese return MV_ERROR;
319edb47025SStefan Roese }
320edb47025SStefan Roese }
321edb47025SStefan Roese
322edb47025SStefan Roese /* Creating PEX address to be passed */
323edb47025SStefan Roese pex_data = (bus << PXCAR_BUS_NUM_OFFS);
324edb47025SStefan Roese pex_data |= (dev << PXCAR_DEVICE_NUM_OFFS);
325edb47025SStefan Roese pex_data |= (func << PXCAR_FUNC_NUM_OFFS);
326edb47025SStefan Roese /* Legacy register space */
327edb47025SStefan Roese pex_data |= (reg_off & PXCAR_REG_NUM_MASK);
328edb47025SStefan Roese /* Extended register space */
329edb47025SStefan Roese pex_data |= (((reg_off & PXCAR_REAL_EXT_REG_NUM_MASK) >>
330edb47025SStefan Roese PXCAR_REAL_EXT_REG_NUM_OFFS) << PXCAR_EXT_REG_NUM_OFFS);
331edb47025SStefan Roese pex_data |= PXCAR_CONFIG_EN;
332edb47025SStefan Roese
333edb47025SStefan Roese /* Write the address to the PEX configuration address register */
334edb47025SStefan Roese reg_write(PEX_CFG_ADDR_REG(pex_if), pex_data);
335edb47025SStefan Roese
336edb47025SStefan Roese /*
337edb47025SStefan Roese * In order to let the PEX controller absorbed the address
338edb47025SStefan Roese * of the read transaction we perform a validity check that
339edb47025SStefan Roese * the address was written
340edb47025SStefan Roese */
341edb47025SStefan Roese if (pex_data != reg_read(PEX_CFG_ADDR_REG(pex_if)))
342edb47025SStefan Roese return MV_ERROR;
343edb47025SStefan Roese
344edb47025SStefan Roese /* Cleaning Master Abort */
345edb47025SStefan Roese reg_bit_set(PEX_CFG_DIRECT_ACCESS(pex_if, PEX_STATUS_AND_COMMAND),
346edb47025SStefan Roese PXSAC_MABORT);
347edb47025SStefan Roese /* Read the Data returned in the PEX Data register */
348edb47025SStefan Roese pex_data = reg_read(PEX_CFG_DATA_REG(pex_if));
349edb47025SStefan Roese
350edb47025SStefan Roese DEBUG_INIT_FULL_C(" --> ", pex_data, 4);
351edb47025SStefan Roese
352edb47025SStefan Roese return pex_data;
353edb47025SStefan Roese }
354