1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2021-2025, NVIDIA CORPORATION. All rights reserved
4 *
5 * The driver handles Error's from Control Backbone(CBB) version 2.0.
6 * generated due to illegal accesses. The driver prints debug information
7 * about failed transaction on receiving interrupt from Error Notifier.
8 * Error types supported by CBB2.0 are:
9 * UNSUPPORTED_ERR, PWRDOWN_ERR, TIMEOUT_ERR, FIREWALL_ERR, DECODE_ERR,
10 * TARGET_ERR
11 */
12
13 #include <linux/acpi.h>
14 #include <linux/clk.h>
15 #include <linux/cpufeature.h>
16 #include <linux/debugfs.h>
17 #include <linux/module.h>
18 #include <linux/of.h>
19 #include <linux/platform_device.h>
20 #include <linux/device.h>
21 #include <linux/io.h>
22 #include <linux/interrupt.h>
23 #include <linux/ioport.h>
24 #include <soc/tegra/fuse.h>
25 #include <soc/tegra/tegra-cbb.h>
26
27 #define FABRIC_EN_CFG_INTERRUPT_ENABLE_0_0 0x0
28 #define FABRIC_EN_CFG_STATUS_0_0 0x40
29 #define FABRIC_EN_CFG_ADDR_INDEX_0_0 0x60
30 #define FABRIC_EN_CFG_ADDR_LOW_0 0x80
31 #define FABRIC_EN_CFG_ADDR_HI_0 0x84
32
33 #define FABRIC_EN_CFG_TARGET_NODE_ADDR_INDEX_0_0 0x100
34 #define FABRIC_EN_CFG_TARGET_NODE_ADDR_LOW_0 0x140
35 #define FABRIC_EN_CFG_TARGET_NODE_ADDR_HI_0 0x144
36
37 #define FABRIC_MN_INITIATOR_ERR_EN_0 0x200
38 #define FABRIC_MN_INITIATOR_ERR_FORCE_0 0x204
39 #define FABRIC_MN_INITIATOR_ERR_STATUS_0 0x208
40 #define FABRIC_MN_INITIATOR_ERR_OVERFLOW_STATUS_0 0x20c
41
42 #define FABRIC_MN_INITIATOR_LOG_ERR_STATUS_0 0x300
43 #define FABRIC_MN_INITIATOR_LOG_ADDR_LOW_0 0x304
44 #define FABRIC_MN_INITIATOR_LOG_ADDR_HIGH_0 0x308
45 #define FABRIC_MN_INITIATOR_LOG_ATTRIBUTES0_0 0x30c
46 #define FABRIC_MN_INITIATOR_LOG_ATTRIBUTES1_0 0x310
47 #define FABRIC_MN_INITIATOR_LOG_ATTRIBUTES2_0 0x314
48 #define FABRIC_MN_INITIATOR_LOG_USER_BITS0_0 0x318
49
50 #define AXI_SLV_TIMEOUT_STATUS_0_0 0x8
51 #define APB_BLOCK_TMO_STATUS_0 0xc00
52 #define APB_BLOCK_NUM_TMO_OFFSET 0x20
53
54 #define FAB_EM_EL_MSTRID GENMASK(29, 24)
55 #define FAB_EM_EL_VQC GENMASK(17, 16)
56 #define FAB_EM_EL_GRPSEC GENMASK(14, 8)
57 #define FAB_EM_EL_FALCONSEC GENMASK(1, 0)
58
59 #define FAB_EM_EL_FABID GENMASK(20, 16)
60 #define FAB_EM_EL_TARGETID GENMASK(7, 0)
61
62 #define FAB_EM_EL_ACCESSID GENMASK(7, 0)
63
64 #define FAB_EM_EL_AXCACHE GENMASK(27, 24)
65 #define FAB_EM_EL_AXPROT GENMASK(22, 20)
66 #define FAB_EM_EL_BURSTLENGTH GENMASK(19, 12)
67 #define FAB_EM_EL_BURSTTYPE GENMASK(9, 8)
68 #define FAB_EM_EL_BEATSIZE GENMASK(6, 4)
69 #define FAB_EM_EL_ACCESSTYPE GENMASK(0, 0)
70
71 #define USRBITS_MSTR_ID GENMASK(29, 24)
72
73 #define REQ_SOCKET_ID GENMASK(27, 24)
74
75 #define CCPLEX_MSTRID 0x1
76 #define FIREWALL_APERTURE_SZ 0x10000
77 /* Write firewall check enable */
78 #define WEN 0x20000
79
80 enum tegra234_cbb_fabric_ids {
81 T234_CBB_FABRIC_ID,
82 T234_SCE_FABRIC_ID,
83 T234_RCE_FABRIC_ID,
84 T234_DCE_FABRIC_ID,
85 T234_AON_FABRIC_ID,
86 T234_PSC_FABRIC_ID,
87 T234_BPMP_FABRIC_ID,
88 T234_FSI_FABRIC_ID,
89 T234_MAX_FABRIC_ID,
90 };
91
92 enum tegra264_cbb_fabric_ids {
93 T264_SYSTEM_CBB_FABRIC_ID,
94 T264_TOP_0_CBB_FABRIC_ID,
95 T264_VISION_CBB_FABRIC_ID,
96 T264_DISP_USB_CBB_FABRIC_ID,
97 T264_UPHY0_CBB_FABRIC_ID,
98 T264_RSVD0_FABRIC_ID,
99 T264_RSVD1_FABRIC_ID,
100 T264_RSVD2_FABRIC_ID,
101 T264_RSVD3_FABRIC_ID,
102 T264_RSVD4_FABRIC_ID,
103 T264_RSVD5_FABRIC_ID,
104 T264_AON_FABRIC_ID,
105 T264_PSC_FABRIC_ID,
106 T264_OESP_FABRIC_ID,
107 T264_APE_FABRIC_ID,
108 T264_BPMP_FABRIC_ID,
109 T264_RCE_0_FABRIC_ID,
110 T264_RCE_1_FABRIC_ID,
111 T264_RSVD6_FABRIC_ID,
112 T264_DCE_FABRIC_ID,
113 T264_FSI_FABRIC_ID,
114 T264_ISC_FABRIC_ID,
115 T264_SB_FABRIC_ID,
116 T264_ISC_CPU_FABRIC_ID,
117 T264_RSVD7_FABRIC_ID,
118 };
119
120 enum t254_cbb_fabric_ids {
121 T254_DCE_FABRIC_ID = 19,
122 T254_DISP_CLUSTER_FABRIC_ID = 25,
123 T254_C2C_FABRIC_ID = 26,
124 T254_GPU_FABRIC_ID = 27,
125 T254_DISP_CLUSTER_1_FABRIC_ID = 28,
126 T254_MAX_FABRIC_ID,
127 };
128
129 struct tegra234_target_lookup {
130 const char *name;
131 unsigned int offset;
132 };
133
134 struct tegra234_fabric_lookup {
135 const char *name;
136 bool is_lookup;
137 const struct tegra234_target_lookup *target_map;
138 const int max_targets;
139 };
140
141 struct tegra234_cbb_fabric {
142 int fab_id;
143 phys_addr_t off_mask_erd;
144 phys_addr_t firewall_base;
145 unsigned int firewall_ctl;
146 unsigned int firewall_wr_ctl;
147 const char * const *initiator_id;
148 unsigned int notifier_offset;
149 const struct tegra_cbb_error *errors;
150 const int max_errors;
151 const struct tegra234_fabric_lookup *fab_list;
152 const u32 err_intr_enbl;
153 const u32 err_status_clr;
154 };
155
156 struct tegra234_cbb {
157 struct tegra_cbb base;
158
159 const struct tegra234_cbb_fabric *fabric;
160 struct resource *res;
161 void __iomem *regs;
162
163 int num_intr;
164 int sec_irq;
165
166 /* record */
167 void __iomem *mon;
168 unsigned int type;
169 u32 mask;
170 u64 access;
171 u32 mn_attr0;
172 u32 mn_attr1;
173 u32 mn_attr2;
174 u32 mn_user_bits;
175 };
176
to_tegra234_cbb(struct tegra_cbb * cbb)177 static inline struct tegra234_cbb *to_tegra234_cbb(struct tegra_cbb *cbb)
178 {
179 return container_of(cbb, struct tegra234_cbb, base);
180 }
181
182 static LIST_HEAD(cbb_list);
183 static DEFINE_SPINLOCK(cbb_lock);
184
185 static bool
tegra234_cbb_write_access_allowed(struct platform_device * pdev,struct tegra234_cbb * cbb)186 tegra234_cbb_write_access_allowed(struct platform_device *pdev, struct tegra234_cbb *cbb)
187 {
188 u32 val;
189
190 if (!cbb->fabric->firewall_base ||
191 !cbb->fabric->firewall_ctl ||
192 !cbb->fabric->firewall_wr_ctl) {
193 dev_info(&pdev->dev, "SoC data missing for firewall\n");
194 return false;
195 }
196
197 if ((cbb->fabric->firewall_ctl > FIREWALL_APERTURE_SZ) ||
198 (cbb->fabric->firewall_wr_ctl > FIREWALL_APERTURE_SZ)) {
199 dev_err(&pdev->dev, "wrong firewall offset value\n");
200 return false;
201 }
202
203 val = readl(cbb->regs + cbb->fabric->firewall_base + cbb->fabric->firewall_ctl);
204 /*
205 * If the firewall check feature for allowing or blocking the
206 * write accesses through the firewall of a fabric is disabled
207 * then CCPLEX can write to the registers of that fabric.
208 */
209 if (!(val & WEN))
210 return true;
211
212 /*
213 * If the firewall check is enabled then check whether CCPLEX
214 * has write access to the fabric's error notifier registers
215 */
216 val = readl(cbb->regs + cbb->fabric->firewall_base + cbb->fabric->firewall_wr_ctl);
217 if (val & (BIT(CCPLEX_MSTRID)))
218 return true;
219
220 return false;
221 }
222
tegra234_cbb_fault_enable(struct tegra_cbb * cbb)223 static void tegra234_cbb_fault_enable(struct tegra_cbb *cbb)
224 {
225 struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
226 void __iomem *addr;
227
228 addr = priv->regs + priv->fabric->notifier_offset;
229 writel(priv->fabric->err_intr_enbl, addr + FABRIC_EN_CFG_INTERRUPT_ENABLE_0_0);
230 dsb(sy);
231 }
232
tegra234_cbb_error_clear(struct tegra_cbb * cbb)233 static void tegra234_cbb_error_clear(struct tegra_cbb *cbb)
234 {
235 struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
236
237 writel(0, priv->mon + FABRIC_MN_INITIATOR_ERR_FORCE_0);
238
239 writel(priv->fabric->err_status_clr, priv->mon + FABRIC_MN_INITIATOR_ERR_STATUS_0);
240 dsb(sy);
241 }
242
tegra234_cbb_get_status(struct tegra_cbb * cbb)243 static u32 tegra234_cbb_get_status(struct tegra_cbb *cbb)
244 {
245 struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
246 void __iomem *addr;
247 u32 value;
248
249 addr = priv->regs + priv->fabric->notifier_offset;
250 value = readl(addr + FABRIC_EN_CFG_STATUS_0_0);
251 dsb(sy);
252
253 return value;
254 }
255
tegra234_cbb_mask_serror(struct tegra234_cbb * cbb)256 static void tegra234_cbb_mask_serror(struct tegra234_cbb *cbb)
257 {
258 writel(0x1, cbb->regs + cbb->fabric->off_mask_erd);
259 dsb(sy);
260 }
261
tegra234_cbb_get_tmo_slv(void __iomem * addr)262 static u32 tegra234_cbb_get_tmo_slv(void __iomem *addr)
263 {
264 u32 timeout;
265
266 timeout = readl(addr);
267 return timeout;
268 }
269
tegra234_cbb_tmo_slv(struct seq_file * file,const char * target,void __iomem * addr,u32 status)270 static void tegra234_cbb_tmo_slv(struct seq_file *file, const char *target, void __iomem *addr,
271 u32 status)
272 {
273 tegra_cbb_print_err(file, "\t %s : %#x\n", target, status);
274 }
275
tegra234_cbb_lookup_apbslv(struct seq_file * file,const char * target,void __iomem * base)276 static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *target,
277 void __iomem *base)
278 {
279 unsigned int block = 0;
280 void __iomem *addr;
281 char name[64];
282 u32 status;
283
284 status = tegra234_cbb_get_tmo_slv(base);
285 if (status)
286 tegra_cbb_print_err(file, "\t %s_BLOCK_TMO_STATUS : %#x\n", target, status);
287
288 while (status) {
289 if (status & BIT(0)) {
290 u32 timeout, clients, client = 0;
291
292 addr = base + APB_BLOCK_NUM_TMO_OFFSET + (block * 4);
293 timeout = tegra234_cbb_get_tmo_slv(addr);
294 clients = timeout;
295
296 while (timeout) {
297 if (timeout & BIT(0)) {
298 if (clients != 0xffffffff)
299 clients &= BIT(client);
300
301 sprintf(name, "%s_BLOCK%d_TMO", target, block);
302
303 tegra234_cbb_tmo_slv(file, name, addr, clients);
304 }
305
306 timeout >>= 1;
307 client++;
308 }
309 }
310
311 status >>= 1;
312 block++;
313 }
314 }
315
tegra234_sw_lookup_target_timeout(struct seq_file * file,struct tegra234_cbb * cbb,u8 target_id,u8 fab_id)316 static void tegra234_sw_lookup_target_timeout(struct seq_file *file, struct tegra234_cbb *cbb,
317 u8 target_id, u8 fab_id)
318 {
319 const struct tegra234_target_lookup *map = cbb->fabric->fab_list[fab_id].target_map;
320 void __iomem *addr;
321
322 if (target_id >= cbb->fabric->fab_list[fab_id].max_targets) {
323 tegra_cbb_print_err(file, "\t Invalid target_id:%d\n", target_id);
324 return;
325 }
326
327 /*
328 * 1) Get target node name and address mapping using target_id.
329 * 2) Check if the timed out target node is APB or AXI.
330 * 3) If AXI, then print timeout register and reset axi target
331 * using <FABRIC>_SN_<>_SLV_TIMEOUT_STATUS_0_0 register.
332 * 4) If APB, then perform an additional lookup to find the client
333 * which timed out.
334 * a) Get block number from the index of set bit in
335 * <FABRIC>_SN_AXI2APB_<>_BLOCK_TMO_STATUS_0 register.
336 * b) Get address of register respective to block number i.e.
337 * <FABRIC>_SN_AXI2APB_<>_BLOCK<index-set-bit>_TMO_0.
338 * c) Read the register in above step to get client_id which
339 * timed out as per the set bits.
340 * d) Reset the timedout client and print details.
341 * e) Goto step-a till all bits are set.
342 */
343
344 addr = cbb->regs + map[target_id].offset;
345
346 if (strstr(map[target_id].name, "AXI2APB")) {
347 addr += APB_BLOCK_TMO_STATUS_0;
348
349 tegra234_cbb_lookup_apbslv(file, map[target_id].name, addr);
350 } else {
351 char name[64];
352 u32 status;
353
354 addr += AXI_SLV_TIMEOUT_STATUS_0_0;
355
356 status = tegra234_cbb_get_tmo_slv(addr);
357 if (status) {
358 sprintf(name, "%s_SLV_TIMEOUT_STATUS", map[target_id].name);
359 tegra234_cbb_tmo_slv(file, name, addr, status);
360 }
361 }
362 }
363
tegra234_hw_lookup_target_timeout(struct seq_file * file,struct tegra234_cbb * cbb,u8 target_id,u8 fab_id)364 static void tegra234_hw_lookup_target_timeout(struct seq_file *file, struct tegra234_cbb *cbb,
365 u8 target_id, u8 fab_id)
366 {
367 unsigned int notifier = cbb->fabric->notifier_offset;
368 u32 hi, lo;
369 u64 addr;
370
371 writel(target_id, cbb->regs + notifier + FABRIC_EN_CFG_TARGET_NODE_ADDR_INDEX_0_0);
372
373 hi = readl(cbb->regs + notifier + FABRIC_EN_CFG_TARGET_NODE_ADDR_HI_0);
374 lo = readl(cbb->regs + notifier + FABRIC_EN_CFG_TARGET_NODE_ADDR_LOW_0);
375
376 addr = (u64)hi << 32 | lo;
377
378 tegra_cbb_print_err(file, "\t Target Node Addr : %#llx\n", addr);
379 }
380
tegra234_cbb_print_error(struct seq_file * file,struct tegra234_cbb * cbb,u32 status,u32 overflow)381 static void tegra234_cbb_print_error(struct seq_file *file, struct tegra234_cbb *cbb, u32 status,
382 u32 overflow)
383 {
384 unsigned int type = 0;
385
386 if (status & (status - 1))
387 tegra_cbb_print_err(file, "\t Multiple type of errors reported\n");
388
389 while (status) {
390 if (type >= cbb->fabric->max_errors) {
391 tegra_cbb_print_err(file, "\t Wrong type index:%u, status:%u\n",
392 type, status);
393 return;
394 }
395
396 if (status & 0x1)
397 tegra_cbb_print_err(file, "\t Error Code\t\t: %s\n",
398 cbb->fabric->errors[type].code);
399
400 status >>= 1;
401 type++;
402 }
403
404 type = 0;
405
406 while (overflow) {
407 if (type >= cbb->fabric->max_errors) {
408 tegra_cbb_print_err(file, "\t Wrong type index:%u, overflow:%u\n",
409 type, overflow);
410 return;
411 }
412
413 if (overflow & 0x1)
414 tegra_cbb_print_err(file, "\t Overflow\t\t: Multiple %s\n",
415 cbb->fabric->errors[type].code);
416
417 overflow >>= 1;
418 type++;
419 }
420 }
421
print_errlog_err(struct seq_file * file,struct tegra234_cbb * cbb)422 static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb)
423 {
424 u8 cache_type, prot_type, burst_length, mstr_id, grpsec, vqc, falconsec, beat_size;
425 u8 access_type, access_id, requester_socket_id, local_socket_id, target_id, fab_id;
426 bool is_numa = false;
427 u8 burst_type;
428
429 if (num_possible_nodes() > 1)
430 is_numa = true;
431
432 mstr_id = FIELD_GET(FAB_EM_EL_MSTRID, cbb->mn_user_bits);
433 vqc = FIELD_GET(FAB_EM_EL_VQC, cbb->mn_user_bits);
434 grpsec = FIELD_GET(FAB_EM_EL_GRPSEC, cbb->mn_user_bits);
435 falconsec = FIELD_GET(FAB_EM_EL_FALCONSEC, cbb->mn_user_bits);
436
437 /*
438 * For SOC with multiple NUMA nodes, print cross socket access
439 * errors only if initiator_id is CCPLEX, CPMU or GPU.
440 */
441 if (is_numa) {
442 local_socket_id = numa_node_id();
443 requester_socket_id = FIELD_GET(REQ_SOCKET_ID, cbb->mn_attr2);
444
445 if (requester_socket_id != local_socket_id) {
446 if ((mstr_id != 0x1) && (mstr_id != 0x2) && (mstr_id != 0xB))
447 return;
448 }
449 }
450
451 fab_id = FIELD_GET(FAB_EM_EL_FABID, cbb->mn_attr2);
452 target_id = FIELD_GET(FAB_EM_EL_TARGETID, cbb->mn_attr2);
453
454 access_id = FIELD_GET(FAB_EM_EL_ACCESSID, cbb->mn_attr1);
455
456 cache_type = FIELD_GET(FAB_EM_EL_AXCACHE, cbb->mn_attr0);
457 prot_type = FIELD_GET(FAB_EM_EL_AXPROT, cbb->mn_attr0);
458 burst_length = FIELD_GET(FAB_EM_EL_BURSTLENGTH, cbb->mn_attr0);
459 burst_type = FIELD_GET(FAB_EM_EL_BURSTTYPE, cbb->mn_attr0);
460 beat_size = FIELD_GET(FAB_EM_EL_BEATSIZE, cbb->mn_attr0);
461 access_type = FIELD_GET(FAB_EM_EL_ACCESSTYPE, cbb->mn_attr0);
462
463 tegra_cbb_print_err(file, "\n");
464 if (cbb->type < cbb->fabric->max_errors)
465 tegra_cbb_print_err(file, "\t Error Code\t\t: %s\n",
466 cbb->fabric->errors[cbb->type].code);
467 else
468 tegra_cbb_print_err(file, "\t Wrong type index:%u\n", cbb->type);
469
470 tegra_cbb_print_err(file, "\t Initiator_Id\t\t: %#x\n", mstr_id);
471 if (cbb->fabric->initiator_id)
472 tegra_cbb_print_err(file, "\t Initiator\t\t: %s\n",
473 cbb->fabric->initiator_id[mstr_id]);
474
475 tegra_cbb_print_err(file, "\t Address\t\t: %#llx\n", cbb->access);
476
477 tegra_cbb_print_cache(file, cache_type);
478 tegra_cbb_print_prot(file, prot_type);
479
480 tegra_cbb_print_err(file, "\t Access_Type\t\t: %s", (access_type) ? "Write\n" : "Read\n");
481 tegra_cbb_print_err(file, "\t Access_ID\t\t: %#x\n", access_id);
482
483 if (is_numa) {
484 tegra_cbb_print_err(file, "\t Requester_Socket_Id\t: %#x\n",
485 requester_socket_id);
486 tegra_cbb_print_err(file, "\t Local_Socket_Id\t: %#x\n",
487 local_socket_id);
488 tegra_cbb_print_err(file, "\t No. of NUMA_NODES\t: %#x\n",
489 num_possible_nodes());
490 }
491
492 tegra_cbb_print_err(file, "\t Fabric\t\t: %s (id:%#x)\n",
493 cbb->fabric->fab_list[fab_id].name, fab_id);
494
495 if (of_machine_is_compatible("nvidia,tegra264") && fab_id == T264_UPHY0_CBB_FABRIC_ID) {
496 /*
497 * In T264, AON Fabric ID value is incorrectly same as UPHY0 fabric ID.
498 * For 'ID = 0x4', we must check for the address which caused the error
499 * to find the correct fabric which returned error.
500 */
501 tegra_cbb_print_err(file, "\t or Fabric\t\t: %s\n",
502 cbb->fabric->fab_list[T264_AON_FABRIC_ID].name);
503 tegra_cbb_print_err(file, "\t Please use Address to determine correct fabric.\n");
504 }
505
506 tegra_cbb_print_err(file, "\t Target_Id\t\t: %#x\n", target_id);
507 tegra_cbb_print_err(file, "\t Burst_length\t\t: %#x\n", burst_length);
508 tegra_cbb_print_err(file, "\t Burst_type\t\t: %#x\n", burst_type);
509 tegra_cbb_print_err(file, "\t Beat_size\t\t: %#x\n", beat_size);
510 tegra_cbb_print_err(file, "\t VQC\t\t\t: %#x\n", vqc);
511 tegra_cbb_print_err(file, "\t GRPSEC\t\t: %#x\n", grpsec);
512 tegra_cbb_print_err(file, "\t FALCONSEC\t\t: %#x\n", falconsec);
513
514 if (!cbb->fabric->fab_list[fab_id].is_lookup)
515 return;
516
517 /*
518 * If is_lookup field is set in fabric_lookup table of soc data, it
519 * means that address lookup of target is supported for Timeout errors.
520 * If is_lookup is set and the target_map is not populated making
521 * max_targets as zero, then it means HW lookup is to be performed.
522 */
523 if (!strcmp(cbb->fabric->errors[cbb->type].code, "TIMEOUT_ERR")) {
524 if (cbb->fabric->fab_list[fab_id].max_targets)
525 tegra234_sw_lookup_target_timeout(file, cbb, target_id, fab_id);
526 else
527 tegra234_hw_lookup_target_timeout(file, cbb, target_id, fab_id);
528 }
529
530 return;
531 }
532
print_errmonX_info(struct seq_file * file,struct tegra234_cbb * cbb)533 static int print_errmonX_info(struct seq_file *file, struct tegra234_cbb *cbb)
534 {
535 u32 overflow, status, error;
536
537 status = readl(cbb->mon + FABRIC_MN_INITIATOR_ERR_STATUS_0);
538 if (!status) {
539 pr_err("Error Notifier received a spurious notification\n");
540 return -ENODATA;
541 }
542
543 if (status == 0xffffffff) {
544 pr_err("CBB registers returning all 1's which is invalid\n");
545 return -EINVAL;
546 }
547
548 overflow = readl(cbb->mon + FABRIC_MN_INITIATOR_ERR_OVERFLOW_STATUS_0);
549
550 tegra234_cbb_print_error(file, cbb, status, overflow);
551
552 error = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ERR_STATUS_0);
553 if (!error) {
554 pr_info("Error Monitor doesn't have Error Logger\n");
555 return -EINVAL;
556 }
557
558 cbb->type = 0;
559
560 while (error) {
561 if (error & BIT(0)) {
562 u32 hi, lo;
563
564 hi = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ADDR_HIGH_0);
565 lo = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ADDR_LOW_0);
566
567 cbb->access = (u64)hi << 32 | lo;
568
569 cbb->mn_attr0 = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ATTRIBUTES0_0);
570 cbb->mn_attr1 = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ATTRIBUTES1_0);
571 cbb->mn_attr2 = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ATTRIBUTES2_0);
572 cbb->mn_user_bits = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_USER_BITS0_0);
573
574 print_errlog_err(file, cbb);
575 }
576
577 cbb->type++;
578 error >>= 1;
579 }
580
581 return 0;
582 }
583
print_err_notifier(struct seq_file * file,struct tegra234_cbb * cbb,u32 status)584 static int print_err_notifier(struct seq_file *file, struct tegra234_cbb *cbb, u32 status)
585 {
586 unsigned int index = 0;
587 int err;
588
589 pr_crit("**************************************\n");
590 pr_crit("CPU:%d, Error:%s, Errmon:%d\n", smp_processor_id(),
591 cbb->fabric->fab_list[cbb->fabric->fab_id].name, status);
592
593 while (status) {
594 if (status & BIT(0)) {
595 unsigned int notifier = cbb->fabric->notifier_offset;
596 u32 hi, lo, mask = BIT(index);
597 phys_addr_t addr;
598 u64 offset;
599
600 writel(mask, cbb->regs + notifier + FABRIC_EN_CFG_ADDR_INDEX_0_0);
601 hi = readl(cbb->regs + notifier + FABRIC_EN_CFG_ADDR_HI_0);
602 lo = readl(cbb->regs + notifier + FABRIC_EN_CFG_ADDR_LOW_0);
603
604 addr = (u64)hi << 32 | lo;
605
606 offset = addr - cbb->res->start;
607 cbb->mon = cbb->regs + offset;
608 cbb->mask = BIT(index);
609
610 err = print_errmonX_info(file, cbb);
611 tegra234_cbb_error_clear(&cbb->base);
612 if (err)
613 return err;
614 tegra_cbb_print_err(file, "\t**************************************\n");
615 }
616
617 status >>= 1;
618 index++;
619 }
620
621 return 0;
622 }
623
624 #ifdef CONFIG_DEBUG_FS
625 static DEFINE_MUTEX(cbb_debugfs_mutex);
626
tegra234_cbb_debugfs_show(struct tegra_cbb * cbb,struct seq_file * file,void * data)627 static int tegra234_cbb_debugfs_show(struct tegra_cbb *cbb, struct seq_file *file, void *data)
628 {
629 int err = 0;
630
631 mutex_lock(&cbb_debugfs_mutex);
632
633 list_for_each_entry(cbb, &cbb_list, node) {
634 struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
635 u32 status;
636
637 status = tegra_cbb_get_status(&priv->base);
638 if (status) {
639 err = print_err_notifier(file, priv, status);
640 if (err)
641 break;
642 }
643 }
644
645 mutex_unlock(&cbb_debugfs_mutex);
646 return err;
647 }
648 #endif
649
650 /*
651 * Handler for CBB errors
652 */
tegra234_cbb_isr(int irq,void * data)653 static irqreturn_t tegra234_cbb_isr(int irq, void *data)
654 {
655 bool is_inband_err = false;
656 struct tegra_cbb *cbb;
657 unsigned long flags;
658 u8 mstr_id;
659 int err;
660
661 spin_lock_irqsave(&cbb_lock, flags);
662
663 list_for_each_entry(cbb, &cbb_list, node) {
664 struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
665 u32 status = tegra_cbb_get_status(cbb);
666
667 if (status && (irq == priv->sec_irq)) {
668 tegra_cbb_print_err(NULL, "CPU:%d, Error: %s@0x%llx, irq=%d\n",
669 smp_processor_id(),
670 priv->fabric->fab_list[priv->fabric->fab_id].name,
671 priv->res->start, irq);
672
673 err = print_err_notifier(NULL, priv, status);
674 if (err)
675 goto unlock;
676
677 /*
678 * If illegal request is from CCPLEX(id:0x1) initiator then call WARN()
679 */
680 if (priv->fabric->off_mask_erd) {
681 mstr_id = FIELD_GET(USRBITS_MSTR_ID, priv->mn_user_bits);
682 if (mstr_id == CCPLEX_MSTRID)
683 is_inband_err = 1;
684 }
685 }
686 }
687
688 unlock:
689 spin_unlock_irqrestore(&cbb_lock, flags);
690 WARN_ON(is_inband_err);
691 return IRQ_HANDLED;
692 }
693
694 /*
695 * Register handler for CBB_SECURE interrupt for reporting errors
696 */
tegra234_cbb_interrupt_enable(struct tegra_cbb * cbb)697 static int tegra234_cbb_interrupt_enable(struct tegra_cbb *cbb)
698 {
699 struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
700
701 if (priv->sec_irq) {
702 int err = devm_request_irq(cbb->dev, priv->sec_irq, tegra234_cbb_isr, 0,
703 dev_name(cbb->dev), priv);
704 if (err) {
705 dev_err(cbb->dev, "failed to register interrupt %u: %d\n", priv->sec_irq,
706 err);
707 return err;
708 }
709 }
710
711 return 0;
712 }
713
tegra234_cbb_error_enable(struct tegra_cbb * cbb)714 static void tegra234_cbb_error_enable(struct tegra_cbb *cbb)
715 {
716 tegra_cbb_fault_enable(cbb);
717 }
718
719 static const struct tegra_cbb_ops tegra234_cbb_ops = {
720 .get_status = tegra234_cbb_get_status,
721 .error_clear = tegra234_cbb_error_clear,
722 .fault_enable = tegra234_cbb_fault_enable,
723 .error_enable = tegra234_cbb_error_enable,
724 .interrupt_enable = tegra234_cbb_interrupt_enable,
725 #ifdef CONFIG_DEBUG_FS
726 .debugfs_show = tegra234_cbb_debugfs_show,
727 #endif
728 };
729
730 static const char * const tegra234_initiator_id[] = {
731 [0x00] = "TZ",
732 [0x01] = "CCPLEX",
733 [0x02] = "CCPMU",
734 [0x03] = "BPMP_FW",
735 [0x04] = "AON",
736 [0x05] = "SCE",
737 [0x06] = "GPCDMA_P",
738 [0x07] = "TSECA_NONSECURE",
739 [0x08] = "TSECA_LIGHTSECURE",
740 [0x09] = "TSECA_HEAVYSECURE",
741 [0x0a] = "CORESIGHT",
742 [0x0b] = "APE",
743 [0x0c] = "PEATRANS",
744 [0x0d] = "JTAGM_DFT",
745 [0x0e] = "RCE",
746 [0x0f] = "DCE",
747 [0x10] = "PSC_FW_USER",
748 [0x11] = "PSC_FW_SUPERVISOR",
749 [0x12] = "PSC_FW_MACHINE",
750 [0x13] = "PSC_BOOT",
751 [0x14] = "BPMP_BOOT",
752 [0x15] = "NVDEC_NONSECURE",
753 [0x16] = "NVDEC_LIGHTSECURE",
754 [0x17] = "NVDEC_HEAVYSECURE",
755 [0x18] = "CBB_INTERNAL",
756 [0x19] = "RSVD"
757 };
758
759 static const struct tegra_cbb_error tegra234_cbb_errors[] = {
760 {
761 .code = "TARGET_ERR",
762 .desc = "Target being accessed responded with an error"
763 }, {
764 .code = "DECODE_ERR",
765 .desc = "Attempt to access an address hole"
766 }, {
767 .code = "FIREWALL_ERR",
768 .desc = "Attempt to access a region which is firewall protected"
769 }, {
770 .code = "TIMEOUT_ERR",
771 .desc = "No response returned by target"
772 }, {
773 .code = "PWRDOWN_ERR",
774 .desc = "Attempt to access a portion of fabric that is powered down"
775 }, {
776 .code = "UNSUPPORTED_ERR",
777 .desc = "Attempt to access a target through an unsupported access"
778 }
779 };
780
781 static const struct tegra234_target_lookup tegra234_aon_target_map[] = {
782 { "AXI2APB", 0x00000 },
783 { "AST", 0x14000 },
784 { "CBB", 0x15000 },
785 { "CPU", 0x16000 },
786 };
787
788 static const struct tegra234_target_lookup tegra234_bpmp_target_map[] = {
789 { "AXI2APB", 0x00000 },
790 { "AST0", 0x15000 },
791 { "AST1", 0x16000 },
792 { "CBB", 0x17000 },
793 { "CPU", 0x18000 },
794 };
795
796 static const struct tegra234_target_lookup tegra234_common_target_map[] = {
797 { "AXI2APB", 0x00000 },
798 { "AST0", 0x15000 },
799 { "AST1", 0x16000 },
800 { "CBB", 0x17000 },
801 { "RSVD", 0x00000 },
802 { "CPU", 0x18000 },
803 };
804
805 static const struct tegra234_target_lookup tegra234_cbb_target_map[] = {
806 { "AON", 0x40000 },
807 { "BPMP", 0x41000 },
808 { "CBB", 0x42000 },
809 { "HOST1X", 0x43000 },
810 { "STM", 0x44000 },
811 { "FSI", 0x45000 },
812 { "PSC", 0x46000 },
813 { "PCIE_C1", 0x47000 },
814 { "PCIE_C2", 0x48000 },
815 { "PCIE_C3", 0x49000 },
816 { "PCIE_C0", 0x4a000 },
817 { "PCIE_C4", 0x4b000 },
818 { "GPU", 0x4c000 },
819 { "SMMU0", 0x4d000 },
820 { "SMMU1", 0x4e000 },
821 { "SMMU2", 0x4f000 },
822 { "SMMU3", 0x50000 },
823 { "SMMU4", 0x51000 },
824 { "PCIE_C10", 0x52000 },
825 { "PCIE_C7", 0x53000 },
826 { "PCIE_C8", 0x54000 },
827 { "PCIE_C9", 0x55000 },
828 { "PCIE_C5", 0x56000 },
829 { "PCIE_C6", 0x57000 },
830 { "DCE", 0x58000 },
831 { "RCE", 0x59000 },
832 { "SCE", 0x5a000 },
833 { "AXI2APB_1", 0x70000 },
834 { "AXI2APB_10", 0x71000 },
835 { "AXI2APB_11", 0x72000 },
836 { "AXI2APB_12", 0x73000 },
837 { "AXI2APB_13", 0x74000 },
838 { "AXI2APB_14", 0x75000 },
839 { "AXI2APB_15", 0x76000 },
840 { "AXI2APB_16", 0x77000 },
841 { "AXI2APB_17", 0x78000 },
842 { "AXI2APB_18", 0x79000 },
843 { "AXI2APB_19", 0x7a000 },
844 { "AXI2APB_2", 0x7b000 },
845 { "AXI2APB_20", 0x7c000 },
846 { "AXI2APB_21", 0x7d000 },
847 { "AXI2APB_22", 0x7e000 },
848 { "AXI2APB_23", 0x7f000 },
849 { "AXI2APB_25", 0x80000 },
850 { "AXI2APB_26", 0x81000 },
851 { "AXI2APB_27", 0x82000 },
852 { "AXI2APB_28", 0x83000 },
853 { "AXI2APB_29", 0x84000 },
854 { "AXI2APB_30", 0x85000 },
855 { "AXI2APB_31", 0x86000 },
856 { "AXI2APB_32", 0x87000 },
857 { "AXI2APB_33", 0x88000 },
858 { "AXI2APB_34", 0x89000 },
859 { "AXI2APB_35", 0x92000 },
860 { "AXI2APB_4", 0x8b000 },
861 { "AXI2APB_5", 0x8c000 },
862 { "AXI2APB_6", 0x8d000 },
863 { "AXI2APB_7", 0x8e000 },
864 { "AXI2APB_8", 0x8f000 },
865 { "AXI2APB_9", 0x90000 },
866 { "AXI2APB_3", 0x91000 },
867 };
868
869 static const struct tegra234_fabric_lookup tegra234_cbb_fab_list[] = {
870 [T234_CBB_FABRIC_ID] = { "cbb-fabric", true,
871 tegra234_cbb_target_map,
872 ARRAY_SIZE(tegra234_cbb_target_map) },
873 [T234_SCE_FABRIC_ID] = { "sce-fabric", true,
874 tegra234_common_target_map,
875 ARRAY_SIZE(tegra234_common_target_map) },
876 [T234_RCE_FABRIC_ID] = { "rce-fabric", true,
877 tegra234_common_target_map,
878 ARRAY_SIZE(tegra234_common_target_map) },
879 [T234_DCE_FABRIC_ID] = { "dce-fabric", true,
880 tegra234_common_target_map,
881 ARRAY_SIZE(tegra234_common_target_map) },
882 [T234_AON_FABRIC_ID] = { "aon-fabric", true,
883 tegra234_aon_target_map,
884 ARRAY_SIZE(tegra234_bpmp_target_map) },
885 [T234_PSC_FABRIC_ID] = { "psc-fabric" },
886 [T234_BPMP_FABRIC_ID] = { "bpmp-fabric", true,
887 tegra234_bpmp_target_map,
888 ARRAY_SIZE(tegra234_bpmp_target_map) },
889 [T234_FSI_FABRIC_ID] = { "fsi-fabric" },
890 };
891
892 static const struct tegra234_cbb_fabric tegra234_aon_fabric = {
893 .fab_id = T234_AON_FABRIC_ID,
894 .fab_list = tegra234_cbb_fab_list,
895 .initiator_id = tegra234_initiator_id,
896 .errors = tegra234_cbb_errors,
897 .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
898 .err_intr_enbl = 0x7,
899 .err_status_clr = 0x3f,
900 .notifier_offset = 0x17000,
901 .firewall_base = 0x30000,
902 .firewall_ctl = 0x8d0,
903 .firewall_wr_ctl = 0x8c8,
904 };
905
906 static const struct tegra234_cbb_fabric tegra234_bpmp_fabric = {
907 .fab_id = T234_BPMP_FABRIC_ID,
908 .fab_list = tegra234_cbb_fab_list,
909 .initiator_id = tegra234_initiator_id,
910 .errors = tegra234_cbb_errors,
911 .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
912 .err_intr_enbl = 0xf,
913 .err_status_clr = 0x3f,
914 .notifier_offset = 0x19000,
915 .firewall_base = 0x30000,
916 .firewall_ctl = 0x8f0,
917 .firewall_wr_ctl = 0x8e8,
918 };
919
920 static const struct tegra234_cbb_fabric tegra234_cbb_fabric = {
921 .fab_id = T234_CBB_FABRIC_ID,
922 .fab_list = tegra234_cbb_fab_list,
923 .initiator_id = tegra234_initiator_id,
924 .errors = tegra234_cbb_errors,
925 .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
926 .err_intr_enbl = 0x7f,
927 .err_status_clr = 0x3f,
928 .notifier_offset = 0x60000,
929 .off_mask_erd = 0x3a004,
930 .firewall_base = 0x10000,
931 .firewall_ctl = 0x23f0,
932 .firewall_wr_ctl = 0x23e8,
933 };
934
935 static const struct tegra234_cbb_fabric tegra234_dce_fabric = {
936 .fab_id = T234_DCE_FABRIC_ID,
937 .fab_list = tegra234_cbb_fab_list,
938 .initiator_id = tegra234_initiator_id,
939 .errors = tegra234_cbb_errors,
940 .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
941 .err_intr_enbl = 0xf,
942 .err_status_clr = 0x3f,
943 .notifier_offset = 0x19000,
944 .firewall_base = 0x30000,
945 .firewall_ctl = 0x290,
946 .firewall_wr_ctl = 0x288,
947 };
948
949 static const struct tegra234_cbb_fabric tegra234_rce_fabric = {
950 .fab_id = T234_RCE_FABRIC_ID,
951 .fab_list = tegra234_cbb_fab_list,
952 .initiator_id = tegra234_initiator_id,
953 .errors = tegra234_cbb_errors,
954 .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
955 .err_intr_enbl = 0xf,
956 .err_status_clr = 0x3f,
957 .notifier_offset = 0x19000,
958 .firewall_base = 0x30000,
959 .firewall_ctl = 0x290,
960 .firewall_wr_ctl = 0x288,
961 };
962
963 static const struct tegra234_cbb_fabric tegra234_sce_fabric = {
964 .fab_id = T234_SCE_FABRIC_ID,
965 .fab_list = tegra234_cbb_fab_list,
966 .initiator_id = tegra234_initiator_id,
967 .errors = tegra234_cbb_errors,
968 .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
969 .err_intr_enbl = 0xf,
970 .err_status_clr = 0x3f,
971 .notifier_offset = 0x19000,
972 .firewall_base = 0x30000,
973 .firewall_ctl = 0x290,
974 .firewall_wr_ctl = 0x288,
975 };
976
977 static const char * const tegra241_initiator_id[] = {
978 [0x0] = "TZ",
979 [0x1] = "CCPLEX",
980 [0x2] = "CCPMU",
981 [0x3] = "BPMP_FW",
982 [0x4] = "PSC_FW_USER",
983 [0x5] = "PSC_FW_SUPERVISOR",
984 [0x6] = "PSC_FW_MACHINE",
985 [0x7] = "PSC_BOOT",
986 [0x8] = "BPMP_BOOT",
987 [0x9] = "JTAGM_DFT",
988 [0xa] = "CORESIGHT",
989 [0xb] = "GPU",
990 [0xc] = "PEATRANS",
991 [0xd ... 0x3f] = "RSVD"
992 };
993
994 /*
995 * Possible causes for Target and Timeout errors.
996 * TARGET_ERR:
997 * Target being accessed responded with an error. Target could return
998 * an error for various cases :
999 * Unsupported access, clamp setting when power gated, register
1000 * level firewall(SCR), address hole within the target, etc
1001 *
1002 * TIMEOUT_ERR:
1003 * No response returned by target. Can be due to target being clock
1004 * gated, under reset, powered down or target inability to respond
1005 * for an internal target issue
1006 */
1007 static const struct tegra_cbb_error tegra241_cbb_errors[] = {
1008 {
1009 .code = "TARGET_ERR",
1010 .desc = "Target being accessed responded with an error."
1011 }, {
1012 .code = "DECODE_ERR",
1013 .desc = "Attempt to access an address hole or Reserved region of memory."
1014 }, {
1015 .code = "FIREWALL_ERR",
1016 .desc = "Attempt to access a region which is firewalled."
1017 }, {
1018 .code = "TIMEOUT_ERR",
1019 .desc = "No response returned by target."
1020 }, {
1021 .code = "PWRDOWN_ERR",
1022 .desc = "Attempt to access a portion of the fabric that is powered down."
1023 }, {
1024 .code = "UNSUPPORTED_ERR",
1025 .desc = "Attempt to access a target through an unsupported access."
1026 }, {
1027 .code = "POISON_ERR",
1028 .desc = "Target responds with poison error to indicate error in data."
1029 }, {
1030 .code = "RSVD"
1031 }, {
1032 .code = "RSVD"
1033 }, {
1034 .code = "RSVD"
1035 }, {
1036 .code = "RSVD"
1037 }, {
1038 .code = "RSVD"
1039 }, {
1040 .code = "RSVD"
1041 }, {
1042 .code = "RSVD"
1043 }, {
1044 .code = "RSVD"
1045 }, {
1046 .code = "RSVD"
1047 }, {
1048 .code = "NO_SUCH_ADDRESS_ERR",
1049 .desc = "The address belongs to the pri_target range but there is no register "
1050 "implemented at the address."
1051 }, {
1052 .code = "TASK_ERR",
1053 .desc = "Attempt to update a PRI task when the current task has still not "
1054 "completed."
1055 }, {
1056 .code = "EXTERNAL_ERR",
1057 .desc = "Indicates that an external PRI register access met with an error due to "
1058 "any issue in the unit."
1059 }, {
1060 .code = "INDEX_ERR",
1061 .desc = "Applicable to PRI index aperture pair, when the programmed index is "
1062 "outside the range defined in the manual."
1063 }, {
1064 .code = "RESET_ERR",
1065 .desc = "Target in Reset Error: Attempt to access a SubPri or external PRI "
1066 "register but they are in reset."
1067 }, {
1068 .code = "REGISTER_RST_ERR",
1069 .desc = "Attempt to access a PRI register but the register is partial or "
1070 "completely in reset."
1071 }, {
1072 .code = "POWER_GATED_ERR",
1073 .desc = "Returned by external PRI client when the external access goes to a power "
1074 "gated domain."
1075 }, {
1076 .code = "SUBPRI_FS_ERR",
1077 .desc = "Subpri is floorswept: Attempt to access a subpri through the main pri "
1078 "target but subPri logic is floorswept."
1079 }, {
1080 .code = "SUBPRI_CLK_OFF_ERR",
1081 .desc = "Subpri clock is off: Attempt to access a subpri through the main pri "
1082 "target but subPris clock is gated/off."
1083 },
1084 };
1085
1086 static const struct tegra234_target_lookup tegra241_bpmp_target_map[] = {
1087 { "RSVD", 0x00000 },
1088 { "RSVD", 0x00000 },
1089 { "RSVD", 0x00000 },
1090 { "CBB", 0x15000 },
1091 { "CPU", 0x16000 },
1092 { "AXI2APB", 0x00000 },
1093 { "DBB0", 0x17000 },
1094 { "DBB1", 0x18000 },
1095 };
1096
1097 static const struct tegra234_target_lookup tegra241_cbb_target_map[] = {
1098 { "RSVD", 0x00000 },
1099 { "PCIE_C8", 0x51000 },
1100 { "PCIE_C9", 0x52000 },
1101 { "RSVD", 0x00000 },
1102 { "RSVD", 0x00000 },
1103 { "RSVD", 0x00000 },
1104 { "RSVD", 0x00000 },
1105 { "RSVD", 0x00000 },
1106 { "RSVD", 0x00000 },
1107 { "RSVD", 0x00000 },
1108 { "RSVD", 0x00000 },
1109 { "AON", 0x5b000 },
1110 { "BPMP", 0x5c000 },
1111 { "RSVD", 0x00000 },
1112 { "RSVD", 0x00000 },
1113 { "PSC", 0x5d000 },
1114 { "STM", 0x5e000 },
1115 { "AXI2APB_1", 0x70000 },
1116 { "AXI2APB_10", 0x71000 },
1117 { "AXI2APB_11", 0x72000 },
1118 { "AXI2APB_12", 0x73000 },
1119 { "AXI2APB_13", 0x74000 },
1120 { "AXI2APB_14", 0x75000 },
1121 { "AXI2APB_15", 0x76000 },
1122 { "AXI2APB_16", 0x77000 },
1123 { "AXI2APB_17", 0x78000 },
1124 { "AXI2APB_18", 0x79000 },
1125 { "AXI2APB_19", 0x7a000 },
1126 { "AXI2APB_2", 0x7b000 },
1127 { "AXI2APB_20", 0x7c000 },
1128 { "AXI2APB_4", 0x87000 },
1129 { "AXI2APB_5", 0x88000 },
1130 { "AXI2APB_6", 0x89000 },
1131 { "AXI2APB_7", 0x8a000 },
1132 { "AXI2APB_8", 0x8b000 },
1133 { "AXI2APB_9", 0x8c000 },
1134 { "AXI2APB_3", 0x8d000 },
1135 { "AXI2APB_21", 0x7d000 },
1136 { "AXI2APB_22", 0x7e000 },
1137 { "AXI2APB_23", 0x7f000 },
1138 { "AXI2APB_24", 0x80000 },
1139 { "AXI2APB_25", 0x81000 },
1140 { "AXI2APB_26", 0x82000 },
1141 { "AXI2APB_27", 0x83000 },
1142 { "AXI2APB_28", 0x84000 },
1143 { "PCIE_C4", 0x53000 },
1144 { "PCIE_C5", 0x54000 },
1145 { "PCIE_C6", 0x55000 },
1146 { "PCIE_C7", 0x56000 },
1147 { "PCIE_C2", 0x57000 },
1148 { "PCIE_C3", 0x58000 },
1149 { "PCIE_C0", 0x59000 },
1150 { "PCIE_C1", 0x5a000 },
1151 { "CCPLEX", 0x50000 },
1152 { "AXI2APB_29", 0x85000 },
1153 { "AXI2APB_30", 0x86000 },
1154 { "CBB_CENTRAL", 0x00000 },
1155 { "AXI2APB_31", 0x8E000 },
1156 { "AXI2APB_32", 0x8F000 },
1157 };
1158
1159 static const struct tegra234_fabric_lookup tegra241_cbb_fab_list[] = {
1160 [T234_CBB_FABRIC_ID] = { "cbb-fabric", true,
1161 tegra241_cbb_target_map, ARRAY_SIZE(tegra241_cbb_target_map) },
1162 [T234_BPMP_FABRIC_ID] = { "bpmp-fabric", true,
1163 tegra241_bpmp_target_map, ARRAY_SIZE(tegra241_cbb_target_map) },
1164 };
1165 static const struct tegra234_cbb_fabric tegra241_cbb_fabric = {
1166 .fab_id = T234_CBB_FABRIC_ID,
1167 .fab_list = tegra241_cbb_fab_list,
1168 .initiator_id = tegra241_initiator_id,
1169 .errors = tegra241_cbb_errors,
1170 .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
1171 .err_intr_enbl = 0x7,
1172 .err_status_clr = 0x1ff007f,
1173 .notifier_offset = 0x60000,
1174 .off_mask_erd = 0x40004,
1175 .firewall_base = 0x20000,
1176 .firewall_ctl = 0x2370,
1177 .firewall_wr_ctl = 0x2368,
1178 };
1179
1180 static const struct tegra234_cbb_fabric tegra241_bpmp_fabric = {
1181 .fab_id = T234_BPMP_FABRIC_ID,
1182 .fab_list = tegra241_cbb_fab_list,
1183 .initiator_id = tegra241_initiator_id,
1184 .errors = tegra241_cbb_errors,
1185 .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
1186 .err_intr_enbl = 0xf,
1187 .err_status_clr = 0x1ff007f,
1188 .notifier_offset = 0x19000,
1189 .firewall_base = 0x30000,
1190 .firewall_ctl = 0x8f0,
1191 .firewall_wr_ctl = 0x8e8,
1192 };
1193
1194 static const char * const tegra264_initiator_id[] = {
1195 [0x0] = "TZ",
1196 [0x1] = "CCPLEX",
1197 [0x2] = "ISC",
1198 [0x3] = "BPMP_FW",
1199 [0x4] = "AON",
1200 [0x5] = "MSS_SEQ",
1201 [0x6] = "GPCDMA_P",
1202 [0x7] = "TSECA_NONSECURE",
1203 [0x8] = "TSECA_LIGHTSECURE",
1204 [0x9] = "TSECA_HEAVYSECURE",
1205 [0xa] = "CORESIGHT",
1206 [0xb] = "APE_0",
1207 [0xc] = "APE_1",
1208 [0xd] = "PEATRANS",
1209 [0xe] = "JTAGM_DFT",
1210 [0xf] = "RCE",
1211 [0x10] = "DCE",
1212 [0x11] = "PSC_FW_USER",
1213 [0x12] = "PSC_FW_SUPERVISOR",
1214 [0x13] = "PSC_FW_MACHINE",
1215 [0x14] = "PSC_BOOT",
1216 [0x15] = "BPMP_BOOT",
1217 [0x16] = "GPU_0",
1218 [0x17] = "GPU_1",
1219 [0x18] = "GPU_2",
1220 [0x19] = "GPU_3",
1221 [0x1a] = "GPU_4",
1222 [0x1b] = "PSC_EXT_BOOT",
1223 [0x1c] = "PSC_EXT_RUNTIME",
1224 [0x1d] = "OESP_EXT",
1225 [0x1e] = "SB_EXT",
1226 [0x1f] = "FSI_SAFETY_0",
1227 [0x20] = "FSI_SAFETY_1",
1228 [0x21] = "FSI_SAFETY_2",
1229 [0x22] = "FSI_SAFETY_3",
1230 [0x23] = "FSI_CHSM",
1231 [0x24] = "RCE_1",
1232 [0x25] = "BPMP_OEM_FW",
1233 [0x26 ... 0x3d] = "RSVD",
1234 [0x3e] = "CBB_SMN",
1235 [0x3f] = "CBB_RSVD"
1236 };
1237
1238 static const struct tegra234_target_lookup tegra264_top0_cbb_target_map[] = {
1239 { "RSVD", 0x000000 },
1240 { "CBB_CENTRAL", 0xC020000 },
1241 { "AXI2APB_1", 0x80000 },
1242 { "AXI2APB_10", 0x81000 },
1243 { "AXI2APB_11", 0x82000 },
1244 { "RSVD", 0x00000 },
1245 { "RSVD", 0x00000 },
1246 { "AXI2APB_14", 0x83000 },
1247 { "AXI2APB_15", 0x84000 },
1248 { "AXI2APB_16", 0x85000 },
1249 { "AXI2APB_17", 0x86000 },
1250 { "AXI2APB_2", 0x87000 },
1251 { "AXI2APB_3", 0x88000 },
1252 { "RSVD", 0x00000 },
1253 { "AXI2APB_5", 0x8A000 },
1254 { "AXI2APB_6", 0x8B000 },
1255 { "AXI2APB_7", 0x8C000 },
1256 { "AXI2APB_8", 0x8D000 },
1257 { "AXI2APB_9", 0x8E000 },
1258 { "FSI_SLAVE", 0x64000 },
1259 { "DISP_USB_CBB_T", 0x65000 },
1260 { "SYSTEM_CBB_T", 0x66000 },
1261 { "UPHY0_CBB_T", 0x67000 },
1262 { "VISION_CBB_T", 0x68000 },
1263 { "CCPLEX_SLAVE", 0x69000 },
1264 { "PCIE_C0", 0x6A000 },
1265 { "SMN_UCF_RX_0", 0x6B000 },
1266 { "SMN_UCF_RX_1", 0x6C000 },
1267 { "AXI2APB_4", 0x89000 },
1268 };
1269
1270 static const struct tegra234_target_lookup tegra264_sys_cbb_target_map[] = {
1271 { "RSVD", 0x00000 },
1272 { "AXI2APB_1", 0xE1000 },
1273 { "RSVD", 0x00000 },
1274 { "AON_SLAVE", 0x79000 },
1275 { "APE_SLAVE", 0x73000 },
1276 { "BPMP_SLAVE", 0x74000 },
1277 { "OESP_SLAVE", 0x75000 },
1278 { "PSC_SLAVE", 0x76000 },
1279 { "SB_SLAVE", 0x7A000 },
1280 { "SMN_SYSTEM_RX", 0x7B000 },
1281 { "STM", 0x77000 },
1282 { "RSVD", 0x00000 },
1283 { "AXI2APB_3", 0xE3000 },
1284 { "TOP_CBB_T", 0x7C000 },
1285 { "AXI2APB_2", 0xE4000 },
1286 { "AXI2APB_4", 0xE5000 },
1287 { "AXI2APB_5", 0xE6000 },
1288 };
1289
1290 static const struct tegra234_target_lookup tegra264_uphy0_cbb_target_map[] = {
1291 [0 ... 20] = { "RSVD", 0x00000 },
1292 { "AXI2APB_1", 0x71000 },
1293 { "RSVD", 0x00000 },
1294 { "AXI2APB_3", 0x75000 },
1295 { "SMN_UPHY0_RX", 0x53000 },
1296 { "RSVD", 0x00000 },
1297 { "RSVD", 0x00000 },
1298 { "RSVD", 0x00000 },
1299 { "RSVD", 0x00000 },
1300 { "PCIE_C4", 0x4B000 },
1301 { "AXI2APB_2", 0x74000 },
1302 { "AXI2APB_4", 0x76000 },
1303 { "AXI2APB_5", 0x77000 },
1304 { "RSVD", 0x00000 },
1305 { "AXI2APB_7", 0x79000 },
1306 { "PCIE_C2", 0x56000 },
1307 { "RSVD", 0x00000 },
1308 { "RSVD", 0x00000 },
1309 { "PCIE_C1", 0x55000 },
1310 { "RSVD", 0x00000 },
1311 { "AXI2APB_10", 0x72000 },
1312 { "AXI2APB_11", 0x7C000 },
1313 { "AXI2APB_8", 0x7A000 },
1314 { "AXI2APB_9", 0x7B000 },
1315 { "RSVD", 0x00000 },
1316 { "RSVD", 0x00000 },
1317 { "PCIE_C5", 0x4E000 },
1318 { "PCIE_C3", 0x58000 },
1319 { "RSVD", 0x00000 },
1320 { "ISC_SLAVE", 0x54000 },
1321 { "TOP_CBB_T", 0x57000 },
1322 { "AXI2APB_12", 0x7D000 },
1323 { "AXI2APB_13", 0x70000 },
1324 { "AXI2APB_6", 0x7E000 },
1325 };
1326
1327 static const struct tegra234_target_lookup tegra264_vision_cbb_target_map[] = {
1328 [0 ... 5] = { "RSVD", 0x0 },
1329 { "HOST1X", 0x45000 },
1330 { "RSVD", 0x00000 },
1331 { "RSVD", 0x00000 },
1332 { "AXI2APB_2", 0x71000 },
1333 { "RSVD", 0x00000 },
1334 { "RSVD", 0x00000 },
1335 { "SMN_VISION_RX", 0x47000 },
1336 [13 ... 19] = { "RSVD", 0x0 },
1337 { "RCE_0_SLAVE", 0x4B000 },
1338 { "RCE_1_SLAVE", 0x4C000 },
1339 { "AXI2APB_1", 0x72000 },
1340 { "AXI2APB_3", 0x73000 },
1341 { "TOP_CBB_T", 0x4D000 },
1342
1343 };
1344
1345 static const struct tegra234_fabric_lookup tegra264_cbb_fab_list[] = {
1346 [T264_SYSTEM_CBB_FABRIC_ID] = { "system-cbb-fabric", true,
1347 tegra264_sys_cbb_target_map,
1348 ARRAY_SIZE(tegra264_sys_cbb_target_map) },
1349 [T264_TOP_0_CBB_FABRIC_ID] = { "top0-cbb-fabric", true,
1350 tegra264_top0_cbb_target_map,
1351 ARRAY_SIZE(tegra264_top0_cbb_target_map) },
1352 [T264_VISION_CBB_FABRIC_ID] = { "vision-cbb-fabric", true,
1353 tegra264_vision_cbb_target_map,
1354 ARRAY_SIZE(tegra264_vision_cbb_target_map) },
1355 [T264_DISP_USB_CBB_FABRIC_ID] = { "disp-usb-cbb-fabric" },
1356 [T264_UPHY0_CBB_FABRIC_ID] = { "uphy0-cbb-fabric", true,
1357 tegra264_uphy0_cbb_target_map,
1358 ARRAY_SIZE(tegra264_uphy0_cbb_target_map) },
1359 [T264_AON_FABRIC_ID] = { "aon-fabric" },
1360 [T264_PSC_FABRIC_ID] = { "psc-fabric" },
1361 [T264_OESP_FABRIC_ID] = { "oesp-fabric" },
1362 [T264_APE_FABRIC_ID] = { "ape-fabirc" },
1363 [T264_BPMP_FABRIC_ID] = { "bpmp-fabric" },
1364 [T264_RCE_0_FABRIC_ID] = { "rce0-fabric" },
1365 [T264_RCE_1_FABRIC_ID] = { "rce1-fabric" },
1366 [T264_DCE_FABRIC_ID] = { "dce-fabric" },
1367 [T264_FSI_FABRIC_ID] = { "fsi-fabric" },
1368 [T264_ISC_FABRIC_ID] = { "isc-fabric" },
1369 [T264_SB_FABRIC_ID] = { "sb-fabric" },
1370 [T264_ISC_CPU_FABRIC_ID] = { "isc-cpu-fabric" },
1371 };
1372
1373 static const struct tegra234_cbb_fabric tegra264_top0_cbb_fabric = {
1374 .fab_id = T264_TOP_0_CBB_FABRIC_ID,
1375 .fab_list = tegra264_cbb_fab_list,
1376 .initiator_id = tegra264_initiator_id,
1377 .errors = tegra241_cbb_errors,
1378 .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
1379 .err_intr_enbl = 0x7,
1380 .err_status_clr = 0x1ff007f,
1381 .notifier_offset = 0x90000,
1382 .off_mask_erd = 0x4a004,
1383 .firewall_base = 0x3c0000,
1384 .firewall_ctl = 0x5b0,
1385 .firewall_wr_ctl = 0x5a8,
1386 };
1387
1388 static const struct tegra234_cbb_fabric tegra264_sys_cbb_fabric = {
1389 .fab_id = T264_SYSTEM_CBB_FABRIC_ID,
1390 .fab_list = tegra264_cbb_fab_list,
1391 .initiator_id = tegra264_initiator_id,
1392 .errors = tegra241_cbb_errors,
1393 .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
1394 .err_intr_enbl = 0xf,
1395 .err_status_clr = 0x1ff007f,
1396 .notifier_offset = 0x40000,
1397 .firewall_base = 0x29c000,
1398 .firewall_ctl = 0x170,
1399 .firewall_wr_ctl = 0x168,
1400 };
1401
1402 static const struct tegra234_cbb_fabric tegra264_uphy0_cbb_fabric = {
1403 .fab_id = T264_UPHY0_CBB_FABRIC_ID,
1404 .fab_list = tegra264_cbb_fab_list,
1405 .initiator_id = tegra264_initiator_id,
1406 .errors = tegra241_cbb_errors,
1407 .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
1408 .err_intr_enbl = 0x1,
1409 .err_status_clr = 0x1ff007f,
1410 .notifier_offset = 0x80000,
1411 .firewall_base = 0x360000,
1412 .firewall_ctl = 0x590,
1413 .firewall_wr_ctl = 0x588,
1414 };
1415
1416 static const struct tegra234_cbb_fabric tegra264_vision_cbb_fabric = {
1417 .fab_id = T264_VISION_CBB_FABRIC_ID,
1418 .fab_list = tegra264_cbb_fab_list,
1419 .initiator_id = tegra264_initiator_id,
1420 .errors = tegra241_cbb_errors,
1421 .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
1422 .err_intr_enbl = 0x1,
1423 .err_status_clr = 0x1ff007f,
1424 .notifier_offset = 0x80000,
1425 .firewall_base = 0x290000,
1426 .firewall_ctl = 0x5d0,
1427 .firewall_wr_ctl = 0x5c8,
1428 };
1429
1430 static const struct tegra234_fabric_lookup t254_cbb_fab_list[] = {
1431 [T254_C2C_FABRIC_ID] = { "c2c-fabric", true },
1432 [T254_DISP_CLUSTER_FABRIC_ID] = { "display-cluster-fabric", true },
1433 [T254_GPU_FABRIC_ID] = { "gpu-fabric", true },
1434 };
1435
1436 static const struct tegra234_cbb_fabric t254_c2c_fabric = {
1437 .fab_id = T254_C2C_FABRIC_ID,
1438 .fab_list = t254_cbb_fab_list,
1439 .errors = tegra241_cbb_errors,
1440 .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
1441 .err_intr_enbl = 0xf,
1442 .err_status_clr = 0x1ff007f,
1443 .notifier_offset = 0x50000,
1444 .off_mask_erd = 0x14004,
1445 .firewall_base = 0x40000,
1446 .firewall_ctl = 0x9b0,
1447 .firewall_wr_ctl = 0x9a8,
1448 };
1449
1450 static const struct tegra234_cbb_fabric t254_disp_fabric = {
1451 .fab_id = T254_DISP_CLUSTER_FABRIC_ID,
1452 .fab_list = t254_cbb_fab_list,
1453 .errors = tegra241_cbb_errors,
1454 .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
1455 .err_intr_enbl = 0x1,
1456 .err_status_clr = 0x1ff007f,
1457 .notifier_offset = 0x50000,
1458 .firewall_base = 0x30000,
1459 .firewall_ctl = 0x810,
1460 .firewall_wr_ctl = 0x808,
1461 };
1462
1463 static const struct tegra234_cbb_fabric t254_gpu_fabric = {
1464 .fab_id = T254_GPU_FABRIC_ID,
1465 .fab_list = t254_cbb_fab_list,
1466 .errors = tegra241_cbb_errors,
1467 .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
1468 .err_intr_enbl = 0x1f,
1469 .err_status_clr = 0x1ff007f,
1470 .notifier_offset = 0x50000,
1471 .firewall_base = 0x30000,
1472 .firewall_ctl = 0x930,
1473 .firewall_wr_ctl = 0x928,
1474 };
1475
1476 static const struct of_device_id tegra234_cbb_dt_ids[] = {
1477 { .compatible = "nvidia,tegra234-cbb-fabric", .data = &tegra234_cbb_fabric },
1478 { .compatible = "nvidia,tegra234-aon-fabric", .data = &tegra234_aon_fabric },
1479 { .compatible = "nvidia,tegra234-bpmp-fabric", .data = &tegra234_bpmp_fabric },
1480 { .compatible = "nvidia,tegra234-dce-fabric", .data = &tegra234_dce_fabric },
1481 { .compatible = "nvidia,tegra234-rce-fabric", .data = &tegra234_rce_fabric },
1482 { .compatible = "nvidia,tegra234-sce-fabric", .data = &tegra234_sce_fabric },
1483 { .compatible = "nvidia,tegra264-sys-cbb-fabric", .data = &tegra264_sys_cbb_fabric },
1484 { .compatible = "nvidia,tegra264-top0-cbb-fabric", .data = &tegra264_top0_cbb_fabric },
1485 { .compatible = "nvidia,tegra264-uphy0-cbb-fabric", .data = &tegra264_uphy0_cbb_fabric },
1486 { .compatible = "nvidia,tegra264-vision-cbb-fabric", .data = &tegra264_vision_cbb_fabric },
1487 { /* sentinel */ },
1488 };
1489 MODULE_DEVICE_TABLE(of, tegra234_cbb_dt_ids);
1490
1491 struct tegra234_cbb_acpi_uid {
1492 const char *hid;
1493 const char *uid;
1494 const struct tegra234_cbb_fabric *fabric;
1495 };
1496
1497 static const struct tegra234_cbb_acpi_uid tegra234_cbb_acpi_uids[] = {
1498 { "NVDA1070", "1", &tegra241_cbb_fabric },
1499 { "NVDA1070", "2", &tegra241_bpmp_fabric },
1500 { "NVDA1070", "3", &t254_c2c_fabric },
1501 { "NVDA1070", "4", &t254_disp_fabric },
1502 { "NVDA1070", "5", &t254_gpu_fabric },
1503 { },
1504 };
1505
1506 static const struct
tegra234_cbb_acpi_get_fabric(struct acpi_device * adev)1507 tegra234_cbb_fabric *tegra234_cbb_acpi_get_fabric(struct acpi_device *adev)
1508 {
1509 const struct tegra234_cbb_acpi_uid *entry;
1510
1511 for (entry = tegra234_cbb_acpi_uids; entry->hid; entry++) {
1512 if (acpi_dev_hid_uid_match(adev, entry->hid, entry->uid))
1513 return entry->fabric;
1514 }
1515
1516 return NULL;
1517 }
1518
1519 static const struct acpi_device_id tegra241_cbb_acpi_ids[] = {
1520 { "NVDA1070" },
1521 { },
1522 };
1523 MODULE_DEVICE_TABLE(acpi, tegra241_cbb_acpi_ids);
1524
tegra234_cbb_probe(struct platform_device * pdev)1525 static int tegra234_cbb_probe(struct platform_device *pdev)
1526 {
1527 const struct tegra234_cbb_fabric *fabric;
1528 struct tegra234_cbb *cbb;
1529 unsigned long flags = 0;
1530 int err;
1531
1532 if (pdev->dev.of_node) {
1533 fabric = of_device_get_match_data(&pdev->dev);
1534 } else {
1535 struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
1536 if (!device)
1537 return -ENODEV;
1538
1539 fabric = tegra234_cbb_acpi_get_fabric(device);
1540 if (!fabric) {
1541 dev_err(&pdev->dev, "no device match found\n");
1542 return -ENODEV;
1543 }
1544 }
1545
1546 cbb = devm_kzalloc(&pdev->dev, sizeof(*cbb), GFP_KERNEL);
1547 if (!cbb)
1548 return -ENOMEM;
1549
1550 INIT_LIST_HEAD(&cbb->base.node);
1551 cbb->base.ops = &tegra234_cbb_ops;
1552 cbb->base.dev = &pdev->dev;
1553 cbb->fabric = fabric;
1554
1555 cbb->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &cbb->res);
1556 if (IS_ERR(cbb->regs))
1557 return PTR_ERR(cbb->regs);
1558
1559 err = tegra_cbb_get_irq(pdev, NULL, &cbb->sec_irq);
1560 if (err)
1561 return err;
1562
1563 platform_set_drvdata(pdev, cbb);
1564
1565 /*
1566 * Don't enable error reporting for a Fabric if write to it's registers
1567 * is blocked by CBB firewall.
1568 */
1569 if (!tegra234_cbb_write_access_allowed(pdev, cbb)) {
1570 dev_info(&pdev->dev, "error reporting not enabled due to firewall\n");
1571 return 0;
1572 }
1573
1574 spin_lock_irqsave(&cbb_lock, flags);
1575 list_add(&cbb->base.node, &cbb_list);
1576 spin_unlock_irqrestore(&cbb_lock, flags);
1577
1578 /* set ERD bit to mask SError and generate interrupt to report error */
1579 if (cbb->fabric->off_mask_erd)
1580 tegra234_cbb_mask_serror(cbb);
1581
1582 return tegra_cbb_register(&cbb->base);
1583 }
1584
tegra234_cbb_resume_noirq(struct device * dev)1585 static int __maybe_unused tegra234_cbb_resume_noirq(struct device *dev)
1586 {
1587 struct tegra234_cbb *cbb = dev_get_drvdata(dev);
1588
1589 tegra234_cbb_error_enable(&cbb->base);
1590
1591 dev_dbg(dev, "%s resumed\n", cbb->fabric->fab_list[cbb->fabric->fab_id].name);
1592
1593 return 0;
1594 }
1595
1596 static const struct dev_pm_ops tegra234_cbb_pm = {
1597 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, tegra234_cbb_resume_noirq)
1598 };
1599
1600 static struct platform_driver tegra234_cbb_driver = {
1601 .probe = tegra234_cbb_probe,
1602 .driver = {
1603 .name = "tegra234-cbb",
1604 .of_match_table = tegra234_cbb_dt_ids,
1605 .acpi_match_table = tegra241_cbb_acpi_ids,
1606 .pm = &tegra234_cbb_pm,
1607 },
1608 };
1609
tegra234_cbb_init(void)1610 static int __init tegra234_cbb_init(void)
1611 {
1612 return platform_driver_register(&tegra234_cbb_driver);
1613 }
1614 pure_initcall(tegra234_cbb_init);
1615
tegra234_cbb_exit(void)1616 static void __exit tegra234_cbb_exit(void)
1617 {
1618 platform_driver_unregister(&tegra234_cbb_driver);
1619 }
1620 module_exit(tegra234_cbb_exit);
1621
1622 MODULE_DESCRIPTION("Control Backbone 2.0 error handling driver for Tegra234");
1623