1 /***********************license start***********************************
2 * Copyright (c) 2003-2017 Cavium Inc. ([email protected]). All rights
3 * reserved.
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * * Neither the name of Cavium Inc. nor the names of
19 * its contributors may be used to endorse or promote products
20 * derived from this software without specific prior written
21 * permission.
22 *
23 * This Software, including technical data, may be subject to U.S. export
24 * control laws, including the U.S. Export Administration Act and its
25 * associated regulations, and may be subject to export or import
26 * regulations in other countries.
27 *
28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT
31 * TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
32 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
33 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
34 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
35 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT,
36 * QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK
37 * ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38 ***********************license end**************************************/
39 #include <bdk.h>
40 #include "libbdk-arch/bdk-csrs-ecam.h"
41 #include "libbdk-arch/bdk-csrs-gser.h"
42 #include "libbdk-arch/bdk-csrs-pccpf.h"
43 #include "libbdk-arch/bdk-csrs-pem.h"
44 #include "libbdk-hal/device/bdk-device.h"
45 #include "libbdk-hal/bdk-ecam.h"
46
47 #if 1 /* Support CN88XX pass 1.0 */
48 /*******************************************************************
49 *******************************************************************
50 These functions are related to CN88XX pass 1.0 errata and do not
51 apply to any other chip
52 *******************************************************************
53 *******************************************************************/
54
55 /**
56 * Errata (ECAM-22630) ECAM function accesses can fault
57 * For some errata workaround we need a check to tell if a ECAM access is to a
58 * valid intenral device. This function decodes a pcc_dev_con_e enumeration and
59 * checks if the supplied arguments match it. This should only
60 * ever be called on CN88XX pass 1.0.
61 *
62 * @param ecam ECAM to check
63 * @param bus ECAM bus number
64 * @param dev Device to check
65 * @param fn sub function of device
66 * @param dev_con Enumeration to match against
67 *
68 * @return Non zero if the device matches
69 */
is_internal_cn88xxp1_0(const bdk_device_t * device,int dev_con)70 static int is_internal_cn88xxp1_0(const bdk_device_t *device, int dev_con)
71 {
72 union bdk_pcc_dev_con_s d = { .u = dev_con };
73 return (d.cn8.ecam == device->ecam) && (d.s.bus == device->bus) && (d.s.func == ((device->dev<<3)|device->func));
74 }
75
76 /**
77 * Errata (ECAM-22630) ECAM function accesses can fault
78 * This is a companion to the function above to determine if the ECAM device is
79 * any of the valid internal devices. This should only ever be
80 * called on CN88XX pass 1.0.
81 *
82 * @param ecam ECAM to check
83 * @param bus ECAM bus number
84 * @param dev Device to check
85 * @param fn sub function of device
86 *
87 * @return Non zero if the device matches
88 */
is_any_internal_cn88xxp1_0(const bdk_device_t * device)89 static int is_any_internal_cn88xxp1_0(const bdk_device_t *device)
90 {
91 /* Errata (ECAM-22630) ECAM function accesses can fault
92 CN88XXP1.0: The ECAM has a bug where accessing a non-existent
93 device causes an exception. This is a list of all valid devices
94 for CN88XX pass 1.0 */
95 static const uint32_t INTERNAL_DEVICES_CN88XXP1_0[] = {
96 BDK_PCC_DEV_CON_E_BGXX(0),
97 BDK_PCC_DEV_CON_E_BGXX(1),
98 BDK_PCC_DEV_CON_E_DAP,
99 BDK_PCC_DEV_CON_E_DFA,
100 BDK_PCC_DEV_CON_E_FUSF,
101 BDK_PCC_DEV_CON_E_GIC_CN8,
102 BDK_PCC_DEV_CON_E_GPIO_CN8,
103 BDK_PCC_DEV_CON_E_GSERX(0),
104 BDK_PCC_DEV_CON_E_GSERX(1),
105 BDK_PCC_DEV_CON_E_GSERX(10),
106 BDK_PCC_DEV_CON_E_GSERX(11),
107 BDK_PCC_DEV_CON_E_GSERX(12),
108 BDK_PCC_DEV_CON_E_GSERX(13),
109 BDK_PCC_DEV_CON_E_GSERX(2),
110 BDK_PCC_DEV_CON_E_GSERX(3),
111 BDK_PCC_DEV_CON_E_GSERX(4),
112 BDK_PCC_DEV_CON_E_GSERX(5),
113 BDK_PCC_DEV_CON_E_GSERX(6),
114 BDK_PCC_DEV_CON_E_GSERX(7),
115 BDK_PCC_DEV_CON_E_GSERX(8),
116 BDK_PCC_DEV_CON_E_GSERX(9),
117 BDK_PCC_DEV_CON_E_GTI_CN8,
118 BDK_PCC_DEV_CON_E_IOBNX(0),
119 BDK_PCC_DEV_CON_E_IOBNX(1),
120 BDK_PCC_DEV_CON_E_KEY,
121 BDK_PCC_DEV_CON_E_L2C,
122 BDK_PCC_DEV_CON_E_L2C_CBCX(0),
123 BDK_PCC_DEV_CON_E_L2C_CBCX(1),
124 BDK_PCC_DEV_CON_E_L2C_CBCX(2),
125 BDK_PCC_DEV_CON_E_L2C_CBCX(3),
126 BDK_PCC_DEV_CON_E_L2C_MCIX(0),
127 BDK_PCC_DEV_CON_E_L2C_MCIX(1),
128 BDK_PCC_DEV_CON_E_L2C_MCIX(2),
129 BDK_PCC_DEV_CON_E_L2C_MCIX(3),
130 BDK_PCC_DEV_CON_E_L2C_TADX(0),
131 BDK_PCC_DEV_CON_E_L2C_TADX(1),
132 BDK_PCC_DEV_CON_E_L2C_TADX(2),
133 BDK_PCC_DEV_CON_E_L2C_TADX(3),
134 BDK_PCC_DEV_CON_E_L2C_TADX(4),
135 BDK_PCC_DEV_CON_E_L2C_TADX(5),
136 BDK_PCC_DEV_CON_E_L2C_TADX(6),
137 BDK_PCC_DEV_CON_E_L2C_TADX(7),
138 BDK_PCC_DEV_CON_E_LMCX(0),
139 BDK_PCC_DEV_CON_E_LMCX(1),
140 BDK_PCC_DEV_CON_E_LMCX(2),
141 BDK_PCC_DEV_CON_E_LMCX(3),
142 BDK_PCC_DEV_CON_E_MIO_BOOT,
143 BDK_PCC_DEV_CON_E_MIO_EMM,
144 BDK_PCC_DEV_CON_E_MIO_FUS,
145 BDK_PCC_DEV_CON_E_MIO_PTP,
146 BDK_PCC_DEV_CON_E_MIO_TWSX(0),
147 BDK_PCC_DEV_CON_E_MIO_TWSX(1),
148 BDK_PCC_DEV_CON_E_MIO_TWSX(2),
149 BDK_PCC_DEV_CON_E_MIO_TWSX(3),
150 BDK_PCC_DEV_CON_E_MIO_TWSX(4),
151 BDK_PCC_DEV_CON_E_MIO_TWSX(5),
152 BDK_PCC_DEV_CON_E_MPI,
153 BDK_PCC_DEV_CON_E_MRML,
154 BDK_PCC_DEV_CON_E_NCSI,
155 BDK_PCC_DEV_CON_E_NIC_CN88XX,
156 BDK_PCC_DEV_CON_E_OCLAX_CN8(0),
157 BDK_PCC_DEV_CON_E_OCLAX_CN8(1),
158 BDK_PCC_DEV_CON_E_OCLAX_CN8(2),
159 BDK_PCC_DEV_CON_E_OCLAX_CN8(3),
160 BDK_PCC_DEV_CON_E_OCLAX_CN8(4),
161 BDK_PCC_DEV_CON_E_OCX,
162 BDK_PCC_DEV_CON_E_PCCBR_DFA,
163 BDK_PCC_DEV_CON_E_PCCBR_MRML,
164 BDK_PCC_DEV_CON_E_PCCBR_NIC_CN88XX,
165 BDK_PCC_DEV_CON_E_PCCBR_RAD_CN88XX,
166 BDK_PCC_DEV_CON_E_PCCBR_ZIP_CN88XX,
167 BDK_PCC_DEV_CON_E_PCIERC0_CN88XX,
168 BDK_PCC_DEV_CON_E_PCIERC1_CN88XX,
169 BDK_PCC_DEV_CON_E_PCIERC2_CN88XX,
170 BDK_PCC_DEV_CON_E_PCIERC3_CN88XX,
171 BDK_PCC_DEV_CON_E_PCIERC4,
172 BDK_PCC_DEV_CON_E_PCIERC5,
173 BDK_PCC_DEV_CON_E_PEMX(0),
174 BDK_PCC_DEV_CON_E_PEMX(1),
175 BDK_PCC_DEV_CON_E_PEMX(2),
176 BDK_PCC_DEV_CON_E_PEMX(3),
177 BDK_PCC_DEV_CON_E_PEMX(4),
178 BDK_PCC_DEV_CON_E_PEMX(5),
179 BDK_PCC_DEV_CON_E_RAD_CN88XX,
180 BDK_PCC_DEV_CON_E_RNM_CN88XX,
181 BDK_PCC_DEV_CON_E_RST,
182 BDK_PCC_DEV_CON_E_SATA0_CN88XX,
183 BDK_PCC_DEV_CON_E_SATA1_CN88XX,
184 BDK_PCC_DEV_CON_E_SATA10,
185 BDK_PCC_DEV_CON_E_SATA11,
186 BDK_PCC_DEV_CON_E_SATA12,
187 BDK_PCC_DEV_CON_E_SATA13,
188 BDK_PCC_DEV_CON_E_SATA14,
189 BDK_PCC_DEV_CON_E_SATA15,
190 BDK_PCC_DEV_CON_E_SATA2,
191 BDK_PCC_DEV_CON_E_SATA3,
192 BDK_PCC_DEV_CON_E_SATA4,
193 BDK_PCC_DEV_CON_E_SATA5,
194 BDK_PCC_DEV_CON_E_SATA6,
195 BDK_PCC_DEV_CON_E_SATA7,
196 BDK_PCC_DEV_CON_E_SATA8,
197 BDK_PCC_DEV_CON_E_SATA9,
198 BDK_PCC_DEV_CON_E_SGP,
199 BDK_PCC_DEV_CON_E_SLI0_CN88XX,
200 BDK_PCC_DEV_CON_E_SLI1,
201 BDK_PCC_DEV_CON_E_SMI,
202 BDK_PCC_DEV_CON_E_SMMU0_CN8,
203 BDK_PCC_DEV_CON_E_SMMU1,
204 BDK_PCC_DEV_CON_E_SMMU2,
205 BDK_PCC_DEV_CON_E_SMMU3,
206 BDK_PCC_DEV_CON_E_TNS,
207 BDK_PCC_DEV_CON_E_UAAX_CN8(0),
208 BDK_PCC_DEV_CON_E_UAAX_CN8(1),
209 BDK_PCC_DEV_CON_E_USBHX(0),
210 BDK_PCC_DEV_CON_E_USBHX(1),
211 BDK_PCC_DEV_CON_E_VRMX(0),
212 BDK_PCC_DEV_CON_E_VRMX(1),
213 BDK_PCC_DEV_CON_E_ZIP_CN88XX,
214 0,
215 };
216
217 int loc = 0;
218 while (INTERNAL_DEVICES_CN88XXP1_0[loc])
219 {
220 if (is_internal_cn88xxp1_0(device, INTERNAL_DEVICES_CN88XXP1_0[loc]))
221 return 1;
222 loc++;
223 }
224 return 0;
225 }
226
is_accessable_cn88xxp1_0(const bdk_device_t * device)227 static int is_accessable_cn88xxp1_0(const bdk_device_t *device)
228 {
229 /* Errata (ECAM-22630) ECAM function accesses can fault */
230 /* Skip internal devices that don't exists */
231 if (!is_any_internal_cn88xxp1_0(device))
232 return 0;
233
234 /* Errata (ECAM-23020) PCIERC transactions fault unless PEM is
235 out of reset. The PCIe ports don't work until the PEM is
236 turned on. Check for one of the PCIe ports */
237 int pem = -1;
238 if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_PCIERC0_CN88XX))
239 pem = 0;
240 if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_PCIERC1_CN88XX))
241 pem = 1;
242 if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_PCIERC2_CN88XX))
243 pem = 2;
244 if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_PCIERC3_CN88XX))
245 pem = 3;
246 if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_PCIERC4))
247 pem = 4;
248 if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_PCIERC5))
249 pem = 5;
250 if (pem != -1)
251 {
252 BDK_CSR_INIT(pem_on, device->node, BDK_PEMX_ON(pem));
253 if (!pem_on.s.pemon || !pem_on.s.pemoor)
254 return 0;
255 }
256
257 {
258 /* SATA ports should be hidden if they aren't configured at the QLM */
259 int qlm = -1;
260 if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA0_CN88XX) ||
261 is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA1_CN88XX) ||
262 is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA2) ||
263 is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA3))
264 qlm = 2;
265 if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA4) ||
266 is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA5) ||
267 is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA6) ||
268 is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA7))
269 qlm = 3;
270 if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA8) ||
271 is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA9) ||
272 is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA10) ||
273 is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA11))
274 qlm = 6;
275 if (is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA12) ||
276 is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA13) ||
277 is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA14) ||
278 is_internal_cn88xxp1_0(device, BDK_PCC_DEV_CON_E_SATA15))
279 qlm = 7;
280 if (qlm != -1)
281 {
282 BDK_CSR_INIT(cfg, device->node, BDK_GSERX_CFG(qlm));
283 if (!cfg.s.sata)
284 return 0;
285 }
286 }
287 return 1;
288 }
289
290 #endif /* Support CN88XX pass 1.0 */
291
292 /**
293 * Build an ECAM config space request address for a device
294 *
295 * @param device Device being accessed
296 * @param reg Register to access
297 *
298 * @return 64bit IO address
299 */
__bdk_ecam_build_address(const bdk_device_t * device,int reg)300 uint64_t __bdk_ecam_build_address(const bdk_device_t *device, int reg)
301 {
302 /* CN88XX pass 1.0 had a plethora of errata related to ECAM access. This
303 checks to make sure we're allowed to access this location based on
304 the various errata */
305 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_0) && !is_accessable_cn88xxp1_0(device))
306 return 0;
307
308 if (CAVIUM_IS_MODEL(CAVIUM_CN8XXX))
309 {
310 /* Build the address */
311 union bdk_ecam_cfg_addr_s address;
312 address.u = BDK_ECAM_BAR_E_ECAMX_PF_BAR2(device->ecam);
313 address.s.node = device->node;
314 address.s.bus = device->bus;
315 address.s.func = device->dev << 3 | device->func;
316 address.s.addr = reg;
317 return address.u;
318 }
319 else
320 {
321 /* Build the address. The architects decided to make it different
322 from CN8XXX for no obvious reason */
323 union bdk_ecam_cfg_addr_s address;
324 address.u = BDK_ECAM_BAR_E_ECAMX_PF_BAR2(0);
325 address.s.node = device->node;
326 address.s.dmn = device->ecam;
327 address.s.bus = device->bus;
328 address.s.func = device->dev << 3 | device->func;
329 address.s.addr = reg;
330 return address.u;
331 }
332 }
333
334 /**
335 * Read from an ECAM
336 *
337 * @param device Device to read from
338 * @param reg Register to read
339 *
340 * @return Result of the read of -1 on failure
341 */
bdk_ecam_read32(const bdk_device_t * device,int reg)342 uint32_t bdk_ecam_read32(const bdk_device_t *device, int reg)
343 {
344 uint64_t address = __bdk_ecam_build_address(device, reg);
345 uint32_t result;
346 if (address)
347 result = bdk_le32_to_cpu(bdk_read64_uint32(address));
348 else
349 result = 0xffffffff;
350
351 /* Errata ECAM-22630: CN88XX pass 1.x, except pass 1.0, will return zero
352 for non-existent devices instead of ones. We look for this special case
353 for 32bit reads for reg=0 so we can scan device properly */
354 if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X) && (reg == 0) && (result == 0))
355 result = 0xffffffff;
356
357 return result;
358 }
359
360 /**
361 * Write to an ECAM register
362 *
363 * @param device Device to write to
364 * @param reg Register to write
365 * @param value Value to write
366 */
bdk_ecam_write32(const bdk_device_t * device,int reg,uint32_t value)367 void bdk_ecam_write32(const bdk_device_t *device, int reg, uint32_t value)
368 {
369 uint64_t address = __bdk_ecam_build_address(device, reg);
370 if (address)
371 bdk_write64_uint32(address, bdk_cpu_to_le32(value));
372 }
373
374