xref: /aosp_15_r20/external/coreboot/src/vendorcode/cavium/bdk/libbdk-hal/bdk-ecam.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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 <string.h>
41 #include "libbdk-arch/bdk-csrs-ecam.h"
42 #include "libbdk-arch/bdk-csrs-pccbr.h"
43 #include "libbdk-arch/bdk-csrs-pccpf.h"
44 #include "libbdk-arch/bdk-csrs-rvu.h"
45 #include "libbdk-hal/device/bdk-device.h"
46 #include "libbdk-hal/bdk-ecam.h"
47 
48 /* This code is an optional part of the BDK. It is only linked in
49     if BDK_REQUIRE() needs it */
50 BDK_REQUIRE_DEFINE(ECAM);
51 
52 /**
53  * Walk an ECAM finding all internal devices. Each internal
54  * device is then added to the list of device maintained by
55  * bdk-device.
56  *
57  * @param node   Node to walk
58  * @param ecam   Ecam to walk
59  * @param bus    Zero on first call. Will be non-zero when sub busses are walked
60  */
ecam_walk_internal_bus(bdk_node_t node,int ecam,int bus)61 static void ecam_walk_internal_bus(bdk_node_t node, int ecam, int bus)
62 {
63     /* Create a fake bdk-device to pass around until we create the
64        real device */
65     bdk_device_t device;
66     memset(&device, 0, sizeof(device));
67     device.node = node;
68     device.ecam = ecam;
69     device.bus = bus;
70 
71     /* Scan all possible device IDs on the bus */
72     for (int dev = 0; dev < 32; dev++)
73     {
74         /* Update the current scan location */
75         device.dev = dev;
76         device.func = 0;
77 
78         uint32_t device_id = bdk_ecam_read32(&device, BDK_PCCPF_XXX_ID);
79 
80         /* Only add devices that exist. Our internal devices can have function
81            zero missing. The all ones we get back matches the multi-function
82            check, but not a bridge. This means the later code works fine */
83         if (device_id != (uint32_t)-1)
84             bdk_device_add(device.node, device.ecam, device.bus, device.dev, device.func);
85 
86         /* Check for Multi function and Bridge devices */
87         BDK_CSR_DEFINE(clsize, BDK_PCCPF_XXX_CLSIZE);
88         clsize.u = bdk_ecam_read32(&device, BDK_PCCPF_XXX_CLSIZE);
89         int ismultifunction = (clsize.s.hdrtype & 0x80);
90         int isbridge = (clsize.s.hdrtype & 0x7f) == 1;
91 
92         if (ismultifunction)
93         {
94             /* Scan for other functions on multifunction devices */
95             for (int func = 1; func < 8; func++)
96             {
97                 /* Check if we're past all functions */
98                 device.func = func;
99                 device_id = bdk_ecam_read32(&device, BDK_PCCPF_XXX_ID);
100                 if (device_id != (uint32_t)-1)
101                     bdk_device_add(device.node, device.ecam, device.bus, device.dev, device.func);
102             }
103             device.func = 0;
104         }
105         if (isbridge)
106         {
107             /* Internal bus numbers are hard coded. Read the bus ID */
108             bdk_pccbr_xxx_bus_t ibus;
109             ibus.u = bdk_ecam_read32(&device, BDK_PCCBR_XXX_BUS);
110             /* Asim used to have a bug where bus number were zero, report errors
111                for those */
112             if (ibus.s.sbnum == 0)
113             {
114                 bdk_error("N%d:E%d:%d:%d.%d: Secondary bus number is zero\n",
115                     device.node, device.ecam, device.bus, device.dev, device.func);
116             }
117             /* Real PCIe external device use high bus numbers, so skip them */
118             else if (ibus.s.sbnum < 16)
119             {
120                 ecam_walk_internal_bus(node, ecam, ibus.s.sbnum);
121             }
122         }
123     }
124 }
125 
126 /**
127  * Return the number of internal ECAMS on a node.
128  *
129  * @param node   Node to query
130  *
131  * @return Number of ECAMs available
132  */
bdk_ecam_get_num(bdk_node_t node)133 int bdk_ecam_get_num(bdk_node_t node)
134 {
135     /* CN88XX lacks the ECAM_CONST for finding the number of ECAMs */
136     if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
137         return 4;
138     else if (CAVIUM_IS_MODEL(CAVIUM_CN93XX))
139         return 3; /* Map ECAMs to the first 3 domains */
140     else
141     {
142         BDK_CSR_INIT(ecam_const, node, BDK_ECAMX_CONST(0));
143         if (ecam_const.s.ecams == 0)
144         {
145             bdk_error("N%d.ECAM: Number of ecams incorrect in ECAMX_CONST\n", node);
146             return 1;
147         }
148         return ecam_const.s.ecams;
149     }
150 }
151 
152 /**
153  * Initialize RVU functions for use by the BDK. This doesn't setup the hardware
154  * behind RVU, juse allows register access to it. The BDK uses a static RVU
155  * configuration where everything is accessable from RVU PF0.
156  *
157  * @param node   Node to initialize
158  *
159  * @return Zero on success, negative on failure
160  */
__bdk_ecam_rvu_init(bdk_node_t node)161 static int __bdk_ecam_rvu_init(bdk_node_t node)
162 {
163     const int rvu_pf = 0;
164     /* Enable PF access to all blocks */
165     BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_CPTX_CFG(rvu_pf, 0),
166         c.s.num_lfs = 1); // FIXME: How many LFs?
167     BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_INT_CFG(rvu_pf),
168         c.s.msix_offset = 0);
169     BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_MSIX_CFG(rvu_pf),
170         c.s.pf_msixt_offset = 0;
171         c.s.pf_msixt_sizem1 = 0;
172         c.s.vf_msixt_offset = 0;
173         c.s.vf_msixt_sizem1 = 0);
174     BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_NIXX_CFG(rvu_pf, 0),
175         c.s.has_lf = 1);
176     BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_NPA_CFG(rvu_pf),
177         c.s.has_lf = 1);
178     BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_SSO_CFG(rvu_pf),
179         c.s.num_lfs = 1); // FIXME: How many LFs?
180     BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_SSOW_CFG(rvu_pf),
181         c.s.num_lfs = 1); // FIXME: How many LFs?
182     BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_TIM_CFG(rvu_pf),
183         c.s.num_lfs = 1); // FIXME: How many LFs?
184     /* Enable RVU with full access */
185     BDK_CSR_MODIFY(c, node, BDK_RVU_PRIV_PFX_CFG(rvu_pf),
186         c.s.me_flr_ena = 1;
187         c.s.af_ena = 1;
188         c.s.ena = 1;
189         c.s.nvf = 0;
190         c.s.first_hwvf = 0);
191     return 0;
192 }
193 
194 /**
195  * Scan all ECAMs for devices and add them to bdk-device
196  *
197  * @param node   Node to scan
198  *
199  * @return Zero on success, negative on failure
200  */
bdk_ecam_scan_all(bdk_node_t node)201 int bdk_ecam_scan_all(bdk_node_t node)
202 {
203     /* RVU must be setup before we scan the bus otherwise it doesn't
204        show up */
205     if (CAVIUM_IS_MODEL(CAVIUM_CN9XXX))
206         __bdk_ecam_rvu_init(node);
207 
208     int num_ecams = bdk_ecam_get_num(node);
209     for (int ecam = 0; ecam < num_ecams; ecam++)
210         ecam_walk_internal_bus(node, ecam, 0);
211 
212     bdk_device_init();
213 
214     return 0;
215 }
216 
217