xref: /aosp_15_r20/external/coreboot/src/vendorcode/cavium/bdk/libbdk-arch/bdk-csr.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 "libbdk-arch/bdk-csrs-pccpf.h"
41 #include "libbdk-arch/bdk-csrs-pem.h"
42 #include "libbdk-arch/bdk-csrs-rst.h"
43 #include "libbdk-hal/bdk-pcie.h"
44 
45 #ifndef BDK_BUILD_HOST
46 
47 /**
48  * Read a slow CSR, not RSL or NCB.
49  *
50  * @param type    Bus type the CSR is on
51  * @param busnum  Bus number the CSR is on
52  * @param size    Width of the CSR in bytes
53  * @param address The address of the CSR
54  *
55  * @return The value of the CSR
56  */
__bdk_csr_read_slow(bdk_node_t node,bdk_csr_type_t type,int busnum,int size,uint64_t address)57 uint64_t __bdk_csr_read_slow(bdk_node_t node, bdk_csr_type_t type, int busnum, int size, uint64_t address)
58 {
59     switch (type)
60     {
61         case BDK_CSR_TYPE_DAB:
62         case BDK_CSR_TYPE_DAB32b:
63         case BDK_CSR_TYPE_NCB:
64         case BDK_CSR_TYPE_NCB32b:
65         case BDK_CSR_TYPE_PEXP_NCB:
66         case BDK_CSR_TYPE_RSL:
67         case BDK_CSR_TYPE_RSL32b:
68         case BDK_CSR_TYPE_RVU_PF_BAR0:
69         case BDK_CSR_TYPE_RVU_PF_BAR2:
70         case BDK_CSR_TYPE_RVU_PFVF_BAR2:
71         case BDK_CSR_TYPE_RVU_VF_BAR2:
72             /* Handled by inline code, we should never get here */
73             bdk_error("%s: Passed type that should be handled inline\n", __func__);
74             break;
75 
76         case BDK_CSR_TYPE_PCCBR:
77         case BDK_CSR_TYPE_PCCPF:
78         case BDK_CSR_TYPE_PCCVF:
79         case BDK_CSR_TYPE_PEXP:
80         case BDK_CSR_TYPE_MDSB:
81         case BDK_CSR_TYPE_PCICONFIGEP_SHADOW:
82         case BDK_CSR_TYPE_PCICONFIGEPVF:
83             bdk_error("%s: Register not supported\n", __func__);
84             break;
85 
86         case BDK_CSR_TYPE_SYSREG:
87             return bdk_sysreg_read(node, bdk_get_core_num(), address);
88 
89         case BDK_CSR_TYPE_PCICONFIGRC:
90         {
91             union bdk_pcc_dev_con_s dev_con;
92             switch (busnum)
93             {
94                 case 0:
95                     if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
96                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC0_CN88XX;
97                     else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
98                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC0_CN83XX;
99                     else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
100                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC0_CN81XX;
101                     else
102                         bdk_fatal("Update PCICONFIG in %s\n", __func__);
103                     break;
104                 case 1:
105                     if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
106                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC1_CN88XX;
107                     else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
108                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC1_CN83XX;
109                     else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
110                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC1_CN81XX;
111                     else
112                         bdk_fatal("Update PCICONFIG in %s\n", __func__);
113                     break;
114                 case 2:
115                     if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
116                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC2_CN88XX;
117                     else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
118                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC2_CN83XX;
119                     else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
120                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC2_CN81XX;
121                     else
122                         bdk_fatal("Update PCICONFIG in %s\n", __func__);
123                     break;
124                 case 3:
125                     if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
126                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC3_CN88XX;
127                     else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
128                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC3_CN83XX;
129                     else
130                         bdk_fatal("Update PCICONFIG in %s\n", __func__);
131                     break;
132                 case 4:
133                     dev_con.u = BDK_PCC_DEV_CON_E_PCIERC4;
134                     break;
135                 case 5:
136                     dev_con.u = BDK_PCC_DEV_CON_E_PCIERC5;
137                     break;
138                 default:
139                     bdk_error("%s: Illegal PCIe bus number\n", __func__);
140                     return -1;
141             }
142             return bdk_pcie_config_read32(node, 100 + dev_con.cn8.ecam, dev_con.s.bus, dev_con.s.func >> 3, dev_con.s.func & 7, address);
143         }
144         case BDK_CSR_TYPE_PCICONFIGEP:
145         {
146             BDK_CSR_DEFINE(cfg_rd, BDK_PEMX_CFG_RD(busnum));
147             cfg_rd.u = 0;
148             cfg_rd.s.addr = address;
149             BDK_CSR_WRITE(node, BDK_PEMX_CFG_RD(busnum), cfg_rd.u);
150             cfg_rd.u = BDK_CSR_READ(node, BDK_PEMX_CFG_RD(busnum));
151             return cfg_rd.s.data;
152         }
153     }
154     return -1; /* Return -1 as this looks invalid in register dumps. Zero is too common as a good value */
155 }
156 
157 
158 /**
159  * Write a value to a slow CSR, not RSL or NCB.
160  *
161  * @param type    Bus type the CSR is on
162  * @param busnum  Bus number the CSR is on
163  * @param size    Width of the CSR in bytes
164  * @param address The address of the CSR
165  * @param value   Value to write to the CSR
166  */
__bdk_csr_write_slow(bdk_node_t node,bdk_csr_type_t type,int busnum,int size,uint64_t address,uint64_t value)167 void __bdk_csr_write_slow(bdk_node_t node, bdk_csr_type_t type, int busnum, int size, uint64_t address, uint64_t value)
168 {
169     switch (type)
170     {
171         case BDK_CSR_TYPE_DAB:
172         case BDK_CSR_TYPE_DAB32b:
173         case BDK_CSR_TYPE_NCB:
174         case BDK_CSR_TYPE_NCB32b:
175         case BDK_CSR_TYPE_PEXP_NCB:
176         case BDK_CSR_TYPE_RSL:
177         case BDK_CSR_TYPE_RSL32b:
178         case BDK_CSR_TYPE_RVU_PF_BAR0:
179         case BDK_CSR_TYPE_RVU_PF_BAR2:
180         case BDK_CSR_TYPE_RVU_PFVF_BAR2:
181         case BDK_CSR_TYPE_RVU_VF_BAR2:
182             /* Handled by inline code, we should never get here */
183             bdk_error("%s: Passed type that should be handled inline\n", __func__);
184             break;
185 
186         case BDK_CSR_TYPE_PCCBR:
187         case BDK_CSR_TYPE_PCCPF:
188         case BDK_CSR_TYPE_PCCVF:
189         case BDK_CSR_TYPE_PEXP:
190         case BDK_CSR_TYPE_MDSB:
191         case BDK_CSR_TYPE_PCICONFIGEP_SHADOW:
192         case BDK_CSR_TYPE_PCICONFIGEPVF:
193             bdk_error("%s: Register not supported\n", __func__);
194             break;
195 
196         case BDK_CSR_TYPE_SYSREG:
197             bdk_sysreg_write(node, bdk_get_core_num(), address, value);
198             break;
199 
200         case BDK_CSR_TYPE_PCICONFIGRC:
201         {
202             union bdk_pcc_dev_con_s dev_con;
203             switch (busnum)
204             {
205                 case 0:
206                     if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
207                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC0_CN88XX;
208                     else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
209                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC0_CN83XX;
210                     else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
211                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC0_CN81XX;
212                     else
213                         bdk_fatal("Update PCICONFIG in %s\n", __func__);
214                     break;
215                 case 1:
216                     if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
217                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC1_CN88XX;
218                     else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
219                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC1_CN83XX;
220                     else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
221                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC1_CN81XX;
222                     else
223                         bdk_fatal("Update PCICONFIG in %s\n", __func__);
224                     break;
225                 case 2:
226                     if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
227                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC2_CN88XX;
228                     else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
229                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC2_CN83XX;
230                     else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
231                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC2_CN81XX;
232                     else
233                         bdk_fatal("Update PCICONFIG in %s\n", __func__);
234                     break;
235                 case 3:
236                     if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
237                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC3_CN88XX;
238                     else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
239                         dev_con.u = BDK_PCC_DEV_CON_E_PCIERC3_CN83XX;
240                     else
241                         bdk_fatal("Update PCICONFIG in %s\n", __func__);
242                     break;
243                 case 4:
244                     dev_con.u = BDK_PCC_DEV_CON_E_PCIERC4;
245                     break;
246                 case 5:
247                     dev_con.u = BDK_PCC_DEV_CON_E_PCIERC5;
248                     break;
249                 default:
250                     bdk_error("%s: Illegal PCIe bus number\n", __func__);
251                     return;
252             }
253             bdk_pcie_config_write32(node, 100 + dev_con.cn8.ecam, dev_con.s.bus, dev_con.s.func >> 3, dev_con.s.func & 7, address, value);
254             break;
255         }
256         case BDK_CSR_TYPE_PCICONFIGEP:
257         {
258             BDK_CSR_DEFINE(cfg_wr, BDK_PEMX_CFG_WR(busnum));
259             cfg_wr.u = 0;
260             cfg_wr.s.addr = address;
261             cfg_wr.s.data = value;
262             BDK_CSR_WRITE(node, BDK_PEMX_CFG_WR(busnum), cfg_wr.u);
263             break;
264         }
265     }
266 }
267 
268 #endif
269 
__bdk_csr_fatal(const char * name,int num_args,unsigned long arg1,unsigned long arg2,unsigned long arg3,unsigned long arg4)270 void __bdk_csr_fatal(const char *name, int num_args, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4)
271 {
272     switch (num_args)
273     {
274         case 0:
275             bdk_fatal("%s is invalid on this chip\n", name);
276         case 1:
277             bdk_fatal("%s(%lu) is invalid on this chip\n", name, arg1);
278         case 2:
279             bdk_fatal("%s(%lu,%lu) is invalid on this chip\n", name, arg1, arg2);
280         case 3:
281             bdk_fatal("%s(%lu,%lu,%lu) is invalid on this chip\n", name, arg1, arg2, arg3);
282         default:
283             bdk_fatal("%s(%lu,%lu,%lu,%lu) is invalid on this chip\n", name, arg1, arg2, arg3, arg4);
284     }
285 }
286 
287 /**
288  * Read a core system register from a different node or core
289  *
290  * @param node   Node to read from
291  * @param core   Core to read
292  * @param regnum Register to read in MRS encoding
293  *
294  * @return Register value
295  */
bdk_sysreg_read(int node,int core,uint64_t regnum)296 uint64_t bdk_sysreg_read(int node, int core, uint64_t regnum)
297 {
298     BDK_CSR_INIT(pp_reset, node, BDK_RST_PP_RESET);
299     if (pp_reset.u & (1ull<<core))
300     {
301         bdk_error("Attempt to read system register for core in reset\n");
302         return -1;
303     }
304 
305     /* Addresses indicate selects as follows:
306         select 3,4,14,2,3
307      == 0x03040e020300
308            | | | | |^--- 1 if is E2H duplicated register
309            | | | |^^-- fifth select
310            | | |^^-- fourth select
311            | |^^-- third select
312            |^^-- second select
313           ^^-- first select */
314     uint64_t first = (regnum >> 40) & 0xff;
315     uint64_t second = (regnum >> 32) & 0xff;
316     uint64_t third = (regnum >> 24) & 0xff;
317     uint64_t fourth = (regnum >> 16) & 0xff;
318     uint64_t fifth = (regnum >> 8) & 0xff;
319     uint64_t regid = ((first & 3) << 14) | (second << 11) | (third << 7) | (fourth << 3) | fifth;
320 
321     /* Note this requires DAP_IMP_DAR[caben] = 1 */
322     uint64_t address = 1ull<<47;
323     address |= 0x7Bull << 36;
324     address |= core << 19;
325     address |= regid << 3;
326     address = bdk_numa_get_address(node, address);
327     return bdk_read64_uint64(address);
328 }
329 
330 /**
331  * Write a system register for a different node or core
332  *
333  * @param node   Node to write too
334  * @param core   Core to write
335  * @param regnum Register to write in MSR encoding
336  * @param value  Value to write
337  */
bdk_sysreg_write(int node,int core,uint64_t regnum,uint64_t value)338 void bdk_sysreg_write(int node, int core, uint64_t regnum, uint64_t value)
339 {
340     BDK_CSR_INIT(pp_reset, node, BDK_RST_PP_RESET);
341     if (pp_reset.u & (1ull<<core))
342     {
343         bdk_error("Attempt to write system register for core in reset\n");
344         return;
345     }
346 
347     /* Addresses indicate selects as follows:
348         select 3,4,14,2,3
349      == 0x03040e020300
350            | | | | |^--- 1 if is E2H duplicated register
351            | | | |^^-- fifth select
352            | | |^^-- fourth select
353            | |^^-- third select
354            |^^-- second select
355           ^^-- first select */
356     uint64_t first = (regnum >> 40) & 0xff;
357     uint64_t second = (regnum >> 32) & 0xff;
358     uint64_t third = (regnum >> 24) & 0xff;
359     uint64_t fourth = (regnum >> 16) & 0xff;
360     uint64_t fifth = (regnum >> 8) & 0xff;
361     uint64_t regid = ((first & 3) << 14) | (second << 11) | (third << 7) | (fourth << 3) | fifth;
362 
363     /* Note this requires DAP_IMP_DAR[caben] = 1 */
364     uint64_t address = 1ull<<47;
365     address |= 0x7Bull << 36;
366     address |= core << 19;
367     address |= regid << 3;
368     address = bdk_numa_get_address(node, address);
369     bdk_write64_uint64(address, value);
370 }
371 
372