xref: /linux/drivers/soc/tegra/cbb/tegra234-cbb.c (revision 84b9b44b)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2021-2022, 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  *   SLAVE_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/of_device.h>
20 #include <linux/platform_device.h>
21 #include <linux/device.h>
22 #include <linux/io.h>
23 #include <linux/of_irq.h>
24 #include <linux/of_address.h>
25 #include <linux/interrupt.h>
26 #include <linux/ioport.h>
27 #include <soc/tegra/fuse.h>
28 #include <soc/tegra/tegra-cbb.h>
29 
30 #define FABRIC_EN_CFG_INTERRUPT_ENABLE_0_0	0x0
31 #define FABRIC_EN_CFG_STATUS_0_0		0x40
32 #define FABRIC_EN_CFG_ADDR_INDEX_0_0		0x60
33 #define FABRIC_EN_CFG_ADDR_LOW_0		0x80
34 #define FABRIC_EN_CFG_ADDR_HI_0			0x84
35 
36 #define FABRIC_MN_MASTER_ERR_EN_0		0x200
37 #define FABRIC_MN_MASTER_ERR_FORCE_0		0x204
38 #define FABRIC_MN_MASTER_ERR_STATUS_0		0x208
39 #define FABRIC_MN_MASTER_ERR_OVERFLOW_STATUS_0	0x20c
40 
41 #define FABRIC_MN_MASTER_LOG_ERR_STATUS_0	0x300
42 #define FABRIC_MN_MASTER_LOG_ADDR_LOW_0		0x304
43 #define FABRIC_MN_MASTER_LOG_ADDR_HIGH_0	0x308
44 #define FABRIC_MN_MASTER_LOG_ATTRIBUTES0_0	0x30c
45 #define FABRIC_MN_MASTER_LOG_ATTRIBUTES1_0	0x310
46 #define FABRIC_MN_MASTER_LOG_ATTRIBUTES2_0	0x314
47 #define FABRIC_MN_MASTER_LOG_USER_BITS0_0	0x318
48 
49 #define AXI_SLV_TIMEOUT_STATUS_0_0		0x8
50 #define APB_BLOCK_TMO_STATUS_0			0xc00
51 #define APB_BLOCK_NUM_TMO_OFFSET		0x20
52 
53 #define FAB_EM_EL_MSTRID		GENMASK(29, 24)
54 #define FAB_EM_EL_VQC			GENMASK(17, 16)
55 #define FAB_EM_EL_GRPSEC		GENMASK(14, 8)
56 #define FAB_EM_EL_FALCONSEC		GENMASK(1, 0)
57 
58 #define FAB_EM_EL_FABID			GENMASK(20, 16)
59 #define FAB_EM_EL_SLAVEID		GENMASK(7, 0)
60 
61 #define FAB_EM_EL_ACCESSID		GENMASK(7, 0)
62 
63 #define FAB_EM_EL_AXCACHE		GENMASK(27, 24)
64 #define FAB_EM_EL_AXPROT		GENMASK(22, 20)
65 #define FAB_EM_EL_BURSTLENGTH		GENMASK(19, 12)
66 #define FAB_EM_EL_BURSTTYPE		GENMASK(9, 8)
67 #define FAB_EM_EL_BEATSIZE		GENMASK(6, 4)
68 #define FAB_EM_EL_ACCESSTYPE		GENMASK(0, 0)
69 
70 #define USRBITS_MSTR_ID			GENMASK(29, 24)
71 
72 #define REQ_SOCKET_ID			GENMASK(27, 24)
73 
74 #define CCPLEX_MSTRID			0x1
75 #define FIREWALL_APERTURE_SZ		0x10000
76 /* Write firewall check enable */
77 #define WEN				0x20000
78 
79 enum tegra234_cbb_fabric_ids {
80 	CBB_FAB_ID,
81 	SCE_FAB_ID,
82 	RCE_FAB_ID,
83 	DCE_FAB_ID,
84 	AON_FAB_ID,
85 	PSC_FAB_ID,
86 	BPMP_FAB_ID,
87 	FSI_FAB_ID,
88 	MAX_FAB_ID,
89 };
90 
91 struct tegra234_slave_lookup {
92 	const char *name;
93 	unsigned int offset;
94 };
95 
96 struct tegra234_cbb_fabric {
97 	const char *name;
98 	phys_addr_t off_mask_erd;
99 	phys_addr_t firewall_base;
100 	unsigned int firewall_ctl;
101 	unsigned int firewall_wr_ctl;
102 	const char * const *master_id;
103 	unsigned int notifier_offset;
104 	const struct tegra_cbb_error *errors;
105 	const int max_errors;
106 	const struct tegra234_slave_lookup *slave_map;
107 	const int max_slaves;
108 };
109 
110 struct tegra234_cbb {
111 	struct tegra_cbb base;
112 
113 	const struct tegra234_cbb_fabric *fabric;
114 	struct resource *res;
115 	void __iomem *regs;
116 
117 	int num_intr;
118 	int sec_irq;
119 
120 	/* record */
121 	void __iomem *mon;
122 	unsigned int type;
123 	u32 mask;
124 	u64 access;
125 	u32 mn_attr0;
126 	u32 mn_attr1;
127 	u32 mn_attr2;
128 	u32 mn_user_bits;
129 };
130 
131 static inline struct tegra234_cbb *to_tegra234_cbb(struct tegra_cbb *cbb)
132 {
133 	return container_of(cbb, struct tegra234_cbb, base);
134 }
135 
136 static LIST_HEAD(cbb_list);
137 static DEFINE_SPINLOCK(cbb_lock);
138 
139 static bool
140 tegra234_cbb_write_access_allowed(struct platform_device *pdev, struct tegra234_cbb *cbb)
141 {
142 	u32 val;
143 
144 	if (!cbb->fabric->firewall_base ||
145 	    !cbb->fabric->firewall_ctl ||
146 	    !cbb->fabric->firewall_wr_ctl) {
147 		dev_info(&pdev->dev, "SoC data missing for firewall\n");
148 		return false;
149 	}
150 
151 	if ((cbb->fabric->firewall_ctl > FIREWALL_APERTURE_SZ) ||
152 	    (cbb->fabric->firewall_wr_ctl > FIREWALL_APERTURE_SZ)) {
153 		dev_err(&pdev->dev, "wrong firewall offset value\n");
154 		return false;
155 	}
156 
157 	val = readl(cbb->regs + cbb->fabric->firewall_base + cbb->fabric->firewall_ctl);
158 	/*
159 	 * If the firewall check feature for allowing or blocking the
160 	 * write accesses through the firewall of a fabric is disabled
161 	 * then CCPLEX can write to the registers of that fabric.
162 	 */
163 	if (!(val & WEN))
164 		return true;
165 
166 	/*
167 	 * If the firewall check is enabled then check whether CCPLEX
168 	 * has write access to the fabric's error notifier registers
169 	 */
170 	val = readl(cbb->regs + cbb->fabric->firewall_base + cbb->fabric->firewall_wr_ctl);
171 	if (val & (BIT(CCPLEX_MSTRID)))
172 		return true;
173 
174 	return false;
175 }
176 
177 static void tegra234_cbb_fault_enable(struct tegra_cbb *cbb)
178 {
179 	struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
180 	void __iomem *addr;
181 
182 	addr = priv->regs + priv->fabric->notifier_offset;
183 	writel(0x1ff, addr + FABRIC_EN_CFG_INTERRUPT_ENABLE_0_0);
184 	dsb(sy);
185 }
186 
187 static void tegra234_cbb_error_clear(struct tegra_cbb *cbb)
188 {
189 	struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
190 
191 	writel(0x3f, priv->mon + FABRIC_MN_MASTER_ERR_STATUS_0);
192 	dsb(sy);
193 }
194 
195 static u32 tegra234_cbb_get_status(struct tegra_cbb *cbb)
196 {
197 	struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
198 	void __iomem *addr;
199 	u32 value;
200 
201 	addr = priv->regs + priv->fabric->notifier_offset;
202 	value = readl(addr + FABRIC_EN_CFG_STATUS_0_0);
203 	dsb(sy);
204 
205 	return value;
206 }
207 
208 static void tegra234_cbb_mask_serror(struct tegra234_cbb *cbb)
209 {
210 	writel(0x1, cbb->regs + cbb->fabric->off_mask_erd);
211 	dsb(sy);
212 }
213 
214 static u32 tegra234_cbb_get_tmo_slv(void __iomem *addr)
215 {
216 	u32 timeout;
217 
218 	timeout = readl(addr);
219 	return timeout;
220 }
221 
222 static void tegra234_cbb_tmo_slv(struct seq_file *file, const char *slave, void __iomem *addr,
223 				 u32 status)
224 {
225 	tegra_cbb_print_err(file, "\t  %s : %#x\n", slave, status);
226 }
227 
228 static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *slave,
229 				       void __iomem *base)
230 {
231 	unsigned int block = 0;
232 	void __iomem *addr;
233 	char name[64];
234 	u32 status;
235 
236 	status = tegra234_cbb_get_tmo_slv(base);
237 	if (status)
238 		tegra_cbb_print_err(file, "\t  %s_BLOCK_TMO_STATUS : %#x\n", slave, status);
239 
240 	while (status) {
241 		if (status & BIT(0)) {
242 			u32 timeout, clients, client = 0;
243 
244 			addr = base + APB_BLOCK_NUM_TMO_OFFSET + (block * 4);
245 			timeout = tegra234_cbb_get_tmo_slv(addr);
246 			clients = timeout;
247 
248 			while (timeout) {
249 				if (timeout & BIT(0)) {
250 					if (clients != 0xffffffff)
251 						clients &= BIT(client);
252 
253 					sprintf(name, "%s_BLOCK%d_TMO", slave, block);
254 
255 					tegra234_cbb_tmo_slv(file, name, addr, clients);
256 				}
257 
258 				timeout >>= 1;
259 				client++;
260 			}
261 		}
262 
263 		status >>= 1;
264 		block++;
265 	}
266 }
267 
268 static void tegra234_lookup_slave_timeout(struct seq_file *file, struct tegra234_cbb *cbb,
269 					  u8 slave_id, u8 fab_id)
270 {
271 	const struct tegra234_slave_lookup *map = cbb->fabric->slave_map;
272 	void __iomem *addr;
273 
274 	/*
275 	 * 1) Get slave node name and address mapping using slave_id.
276 	 * 2) Check if the timed out slave node is APB or AXI.
277 	 * 3) If AXI, then print timeout register and reset axi slave
278 	 *    using <FABRIC>_SN_<>_SLV_TIMEOUT_STATUS_0_0 register.
279 	 * 4) If APB, then perform an additional lookup to find the client
280 	 *    which timed out.
281 	 *	a) Get block number from the index of set bit in
282 	 *	   <FABRIC>_SN_AXI2APB_<>_BLOCK_TMO_STATUS_0 register.
283 	 *	b) Get address of register repective to block number i.e.
284 	 *	   <FABRIC>_SN_AXI2APB_<>_BLOCK<index-set-bit>_TMO_0.
285 	 *	c) Read the register in above step to get client_id which
286 	 *	   timed out as per the set bits.
287 	 *      d) Reset the timedout client and print details.
288 	 *	e) Goto step-a till all bits are set.
289 	 */
290 
291 	addr = cbb->regs + map[slave_id].offset;
292 
293 	if (strstr(map[slave_id].name, "AXI2APB")) {
294 		addr += APB_BLOCK_TMO_STATUS_0;
295 
296 		tegra234_cbb_lookup_apbslv(file, map[slave_id].name, addr);
297 	} else {
298 		char name[64];
299 		u32 status;
300 
301 		addr += AXI_SLV_TIMEOUT_STATUS_0_0;
302 
303 		status = tegra234_cbb_get_tmo_slv(addr);
304 		if (status) {
305 			sprintf(name, "%s_SLV_TIMEOUT_STATUS", map[slave_id].name);
306 			tegra234_cbb_tmo_slv(file, name, addr, status);
307 		}
308 	}
309 }
310 
311 static void tegra234_cbb_print_error(struct seq_file *file, struct tegra234_cbb *cbb, u32 status,
312 				     u32 overflow)
313 {
314 	unsigned int type = 0;
315 
316 	if (status & (status - 1))
317 		tegra_cbb_print_err(file, "\t  Multiple type of errors reported\n");
318 
319 	while (status) {
320 		if (type >= cbb->fabric->max_errors) {
321 			tegra_cbb_print_err(file, "\t  Wrong type index:%u, status:%u\n",
322 					    type, status);
323 			return;
324 		}
325 
326 		if (status & 0x1)
327 			tegra_cbb_print_err(file, "\t  Error Code\t\t: %s\n",
328 					    cbb->fabric->errors[type].code);
329 
330 		status >>= 1;
331 		type++;
332 	}
333 
334 	type = 0;
335 
336 	while (overflow) {
337 		if (type >= cbb->fabric->max_errors) {
338 			tegra_cbb_print_err(file, "\t  Wrong type index:%u, overflow:%u\n",
339 					    type, overflow);
340 			return;
341 		}
342 
343 		if (overflow & 0x1)
344 			tegra_cbb_print_err(file, "\t  Overflow\t\t: Multiple %s\n",
345 					    cbb->fabric->errors[type].code);
346 
347 		overflow >>= 1;
348 		type++;
349 	}
350 }
351 
352 static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb)
353 {
354 	u8 cache_type, prot_type, burst_length, mstr_id, grpsec, vqc, falconsec, beat_size;
355 	u8 access_type, access_id, requester_socket_id, local_socket_id, slave_id, fab_id;
356 	char fabric_name[20];
357 	bool is_numa = false;
358 	u8 burst_type;
359 
360 	if (num_possible_nodes() > 1)
361 		is_numa = true;
362 
363 	mstr_id = FIELD_GET(FAB_EM_EL_MSTRID, cbb->mn_user_bits);
364 	vqc = FIELD_GET(FAB_EM_EL_VQC, cbb->mn_user_bits);
365 	grpsec = FIELD_GET(FAB_EM_EL_GRPSEC, cbb->mn_user_bits);
366 	falconsec = FIELD_GET(FAB_EM_EL_FALCONSEC, cbb->mn_user_bits);
367 
368 	/*
369 	 * For SOC with multiple NUMA nodes, print cross socket access
370 	 * errors only if initiator/master_id is CCPLEX, CPMU or GPU.
371 	 */
372 	if (is_numa) {
373 		local_socket_id = numa_node_id();
374 		requester_socket_id = FIELD_GET(REQ_SOCKET_ID, cbb->mn_attr2);
375 
376 		if (requester_socket_id != local_socket_id) {
377 			if ((mstr_id != 0x1) && (mstr_id != 0x2) && (mstr_id != 0xB))
378 				return;
379 		}
380 	}
381 
382 	fab_id = FIELD_GET(FAB_EM_EL_FABID, cbb->mn_attr2);
383 	slave_id = FIELD_GET(FAB_EM_EL_SLAVEID, cbb->mn_attr2);
384 
385 	access_id = FIELD_GET(FAB_EM_EL_ACCESSID, cbb->mn_attr1);
386 
387 	cache_type = FIELD_GET(FAB_EM_EL_AXCACHE, cbb->mn_attr0);
388 	prot_type = FIELD_GET(FAB_EM_EL_AXPROT, cbb->mn_attr0);
389 	burst_length = FIELD_GET(FAB_EM_EL_BURSTLENGTH, cbb->mn_attr0);
390 	burst_type = FIELD_GET(FAB_EM_EL_BURSTTYPE, cbb->mn_attr0);
391 	beat_size = FIELD_GET(FAB_EM_EL_BEATSIZE, cbb->mn_attr0);
392 	access_type = FIELD_GET(FAB_EM_EL_ACCESSTYPE, cbb->mn_attr0);
393 
394 	tegra_cbb_print_err(file, "\n");
395 	if (cbb->type < cbb->fabric->max_errors)
396 		tegra_cbb_print_err(file, "\t  Error Code\t\t: %s\n",
397 				    cbb->fabric->errors[cbb->type].code);
398 	else
399 		tegra_cbb_print_err(file, "\t  Wrong type index:%u\n", cbb->type);
400 
401 	tegra_cbb_print_err(file, "\t  MASTER_ID\t\t: %s\n", cbb->fabric->master_id[mstr_id]);
402 	tegra_cbb_print_err(file, "\t  Address\t\t: %#llx\n", cbb->access);
403 
404 	tegra_cbb_print_cache(file, cache_type);
405 	tegra_cbb_print_prot(file, prot_type);
406 
407 	tegra_cbb_print_err(file, "\t  Access_Type\t\t: %s", (access_type) ? "Write\n" : "Read\n");
408 	tegra_cbb_print_err(file, "\t  Access_ID\t\t: %#x", access_id);
409 
410 	if (fab_id == PSC_FAB_ID)
411 		strcpy(fabric_name, "psc-fabric");
412 	else if (fab_id == FSI_FAB_ID)
413 		strcpy(fabric_name, "fsi-fabric");
414 	else
415 		strcpy(fabric_name, cbb->fabric->name);
416 
417 	if (is_numa) {
418 		tegra_cbb_print_err(file, "\t  Requester_Socket_Id\t: %#x\n",
419 				    requester_socket_id);
420 		tegra_cbb_print_err(file, "\t  Local_Socket_Id\t: %#x\n",
421 				    local_socket_id);
422 		tegra_cbb_print_err(file, "\t  No. of NUMA_NODES\t: %#x\n",
423 				    num_possible_nodes());
424 	}
425 
426 	tegra_cbb_print_err(file, "\t  Fabric\t\t: %s\n", fabric_name);
427 	tegra_cbb_print_err(file, "\t  Slave_Id\t\t: %#x\n", slave_id);
428 	tegra_cbb_print_err(file, "\t  Burst_length\t\t: %#x\n", burst_length);
429 	tegra_cbb_print_err(file, "\t  Burst_type\t\t: %#x\n", burst_type);
430 	tegra_cbb_print_err(file, "\t  Beat_size\t\t: %#x\n", beat_size);
431 	tegra_cbb_print_err(file, "\t  VQC\t\t\t: %#x\n", vqc);
432 	tegra_cbb_print_err(file, "\t  GRPSEC\t\t: %#x\n", grpsec);
433 	tegra_cbb_print_err(file, "\t  FALCONSEC\t\t: %#x\n", falconsec);
434 
435 	if ((fab_id == PSC_FAB_ID) || (fab_id == FSI_FAB_ID))
436 		return;
437 
438 	if (slave_id >= cbb->fabric->max_slaves) {
439 		tegra_cbb_print_err(file, "\t  Invalid slave_id:%d\n", slave_id);
440 		return;
441 	}
442 
443 	if (!strcmp(cbb->fabric->errors[cbb->type].code, "TIMEOUT_ERR")) {
444 		tegra234_lookup_slave_timeout(file, cbb, slave_id, fab_id);
445 		return;
446 	}
447 
448 	tegra_cbb_print_err(file, "\t  Slave\t\t\t: %s\n", cbb->fabric->slave_map[slave_id].name);
449 }
450 
451 static int print_errmonX_info(struct seq_file *file, struct tegra234_cbb *cbb)
452 {
453 	u32 overflow, status, error;
454 
455 	status = readl(cbb->mon + FABRIC_MN_MASTER_ERR_STATUS_0);
456 	if (!status) {
457 		pr_err("Error Notifier received a spurious notification\n");
458 		return -ENODATA;
459 	}
460 
461 	if (status == 0xffffffff) {
462 		pr_err("CBB registers returning all 1's which is invalid\n");
463 		return -EINVAL;
464 	}
465 
466 	overflow = readl(cbb->mon + FABRIC_MN_MASTER_ERR_OVERFLOW_STATUS_0);
467 
468 	tegra234_cbb_print_error(file, cbb, status, overflow);
469 
470 	error = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ERR_STATUS_0);
471 	if (!error) {
472 		pr_info("Error Monitor doesn't have Error Logger\n");
473 		return -EINVAL;
474 	}
475 
476 	cbb->type = 0;
477 
478 	while (error) {
479 		if (error & BIT(0)) {
480 			u32 hi, lo;
481 
482 			hi = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ADDR_HIGH_0);
483 			lo = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ADDR_LOW_0);
484 
485 			cbb->access = (u64)hi << 32 | lo;
486 
487 			cbb->mn_attr0 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES0_0);
488 			cbb->mn_attr1 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES1_0);
489 			cbb->mn_attr2 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES2_0);
490 			cbb->mn_user_bits = readl(cbb->mon + FABRIC_MN_MASTER_LOG_USER_BITS0_0);
491 
492 			print_errlog_err(file, cbb);
493 		}
494 
495 		cbb->type++;
496 		error >>= 1;
497 	}
498 
499 	return 0;
500 }
501 
502 static int print_err_notifier(struct seq_file *file, struct tegra234_cbb *cbb, u32 status)
503 {
504 	unsigned int index = 0;
505 	int err;
506 
507 	pr_crit("**************************************\n");
508 	pr_crit("CPU:%d, Error:%s, Errmon:%d\n", smp_processor_id(),
509 		cbb->fabric->name, status);
510 
511 	while (status) {
512 		if (status & BIT(0)) {
513 			unsigned int notifier = cbb->fabric->notifier_offset;
514 			u32 hi, lo, mask = BIT(index);
515 			phys_addr_t addr;
516 			u64 offset;
517 
518 			writel(mask, cbb->regs + notifier + FABRIC_EN_CFG_ADDR_INDEX_0_0);
519 			hi = readl(cbb->regs + notifier + FABRIC_EN_CFG_ADDR_HI_0);
520 			lo = readl(cbb->regs + notifier + FABRIC_EN_CFG_ADDR_LOW_0);
521 
522 			addr = (u64)hi << 32 | lo;
523 
524 			offset = addr - cbb->res->start;
525 			cbb->mon = cbb->regs + offset;
526 			cbb->mask = BIT(index);
527 
528 			err = print_errmonX_info(file, cbb);
529 			tegra234_cbb_error_clear(&cbb->base);
530 			if (err)
531 				return err;
532 		}
533 
534 		status >>= 1;
535 		index++;
536 	}
537 
538 	tegra_cbb_print_err(file, "\t**************************************\n");
539 	return 0;
540 }
541 
542 #ifdef CONFIG_DEBUG_FS
543 static DEFINE_MUTEX(cbb_debugfs_mutex);
544 
545 static int tegra234_cbb_debugfs_show(struct tegra_cbb *cbb, struct seq_file *file, void *data)
546 {
547 	int err = 0;
548 
549 	mutex_lock(&cbb_debugfs_mutex);
550 
551 	list_for_each_entry(cbb, &cbb_list, node) {
552 		struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
553 		u32 status;
554 
555 		status = tegra_cbb_get_status(&priv->base);
556 		if (status) {
557 			err = print_err_notifier(file, priv, status);
558 			if (err)
559 				break;
560 		}
561 	}
562 
563 	mutex_unlock(&cbb_debugfs_mutex);
564 	return err;
565 }
566 #endif
567 
568 /*
569  * Handler for CBB errors
570  */
571 static irqreturn_t tegra234_cbb_isr(int irq, void *data)
572 {
573 	bool is_inband_err = false;
574 	struct tegra_cbb *cbb;
575 	unsigned long flags;
576 	u8 mstr_id;
577 	int err;
578 
579 	spin_lock_irqsave(&cbb_lock, flags);
580 
581 	list_for_each_entry(cbb, &cbb_list, node) {
582 		struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
583 		u32 status = tegra_cbb_get_status(cbb);
584 
585 		if (status && (irq == priv->sec_irq)) {
586 			tegra_cbb_print_err(NULL, "CPU:%d, Error: %s@0x%llx, irq=%d\n",
587 					    smp_processor_id(), priv->fabric->name,
588 					    priv->res->start, irq);
589 
590 			err = print_err_notifier(NULL, priv, status);
591 			if (err)
592 				goto unlock;
593 
594 			/*
595 			 * If illegal request is from CCPLEX(id:0x1) master then call WARN()
596 			 */
597 			if (priv->fabric->off_mask_erd) {
598 				mstr_id =  FIELD_GET(USRBITS_MSTR_ID, priv->mn_user_bits);
599 				if (mstr_id == CCPLEX_MSTRID)
600 					is_inband_err = 1;
601 			}
602 		}
603 	}
604 
605 unlock:
606 	spin_unlock_irqrestore(&cbb_lock, flags);
607 	WARN_ON(is_inband_err);
608 	return IRQ_HANDLED;
609 }
610 
611 /*
612  * Register handler for CBB_SECURE interrupt for reporting errors
613  */
614 static int tegra234_cbb_interrupt_enable(struct tegra_cbb *cbb)
615 {
616 	struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
617 
618 	if (priv->sec_irq) {
619 		int err = devm_request_irq(cbb->dev, priv->sec_irq, tegra234_cbb_isr, 0,
620 					   dev_name(cbb->dev), priv);
621 		if (err) {
622 			dev_err(cbb->dev, "failed to register interrupt %u: %d\n", priv->sec_irq,
623 				err);
624 			return err;
625 		}
626 	}
627 
628 	return 0;
629 }
630 
631 static void tegra234_cbb_error_enable(struct tegra_cbb *cbb)
632 {
633 	tegra_cbb_fault_enable(cbb);
634 }
635 
636 static const struct tegra_cbb_ops tegra234_cbb_ops = {
637 	.get_status = tegra234_cbb_get_status,
638 	.error_clear = tegra234_cbb_error_clear,
639 	.fault_enable = tegra234_cbb_fault_enable,
640 	.error_enable = tegra234_cbb_error_enable,
641 	.interrupt_enable = tegra234_cbb_interrupt_enable,
642 #ifdef CONFIG_DEBUG_FS
643 	.debugfs_show = tegra234_cbb_debugfs_show,
644 #endif
645 };
646 
647 static const char * const tegra234_master_id[] = {
648 	[0x00] = "TZ",
649 	[0x01] = "CCPLEX",
650 	[0x02] = "CCPMU",
651 	[0x03] = "BPMP_FW",
652 	[0x04] = "AON",
653 	[0x05] = "SCE",
654 	[0x06] = "GPCDMA_P",
655 	[0x07] = "TSECA_NONSECURE",
656 	[0x08] = "TSECA_LIGHTSECURE",
657 	[0x09] = "TSECA_HEAVYSECURE",
658 	[0x0a] = "CORESIGHT",
659 	[0x0b] = "APE",
660 	[0x0c] = "PEATRANS",
661 	[0x0d] = "JTAGM_DFT",
662 	[0x0e] = "RCE",
663 	[0x0f] = "DCE",
664 	[0x10] = "PSC_FW_USER",
665 	[0x11] = "PSC_FW_SUPERVISOR",
666 	[0x12] = "PSC_FW_MACHINE",
667 	[0x13] = "PSC_BOOT",
668 	[0x14] = "BPMP_BOOT",
669 	[0x15] = "NVDEC_NONSECURE",
670 	[0x16] = "NVDEC_LIGHTSECURE",
671 	[0x17] = "NVDEC_HEAVYSECURE",
672 	[0x18] = "CBB_INTERNAL",
673 	[0x19] = "RSVD"
674 };
675 
676 static const struct tegra_cbb_error tegra234_cbb_errors[] = {
677 	{
678 		.code = "SLAVE_ERR",
679 		.desc = "Slave being accessed responded with an error"
680 	}, {
681 		.code = "DECODE_ERR",
682 		.desc = "Attempt to access an address hole"
683 	}, {
684 		.code = "FIREWALL_ERR",
685 		.desc = "Attempt to access a region which is firewall protected"
686 	}, {
687 		.code = "TIMEOUT_ERR",
688 		.desc = "No response returned by slave"
689 	}, {
690 		.code = "PWRDOWN_ERR",
691 		.desc = "Attempt to access a portion of fabric that is powered down"
692 	}, {
693 		.code = "UNSUPPORTED_ERR",
694 		.desc = "Attempt to access a slave through an unsupported access"
695 	}
696 };
697 
698 static const struct tegra234_slave_lookup tegra234_aon_slave_map[] = {
699 	{ "AXI2APB", 0x00000 },
700 	{ "AST",     0x14000 },
701 	{ "CBB",     0x15000 },
702 	{ "CPU",     0x16000 },
703 };
704 
705 static const struct tegra234_cbb_fabric tegra234_aon_fabric = {
706 	.name = "aon-fabric",
707 	.master_id = tegra234_master_id,
708 	.slave_map = tegra234_aon_slave_map,
709 	.max_slaves = ARRAY_SIZE(tegra234_aon_slave_map),
710 	.errors = tegra234_cbb_errors,
711 	.max_errors = ARRAY_SIZE(tegra234_cbb_errors),
712 	.notifier_offset = 0x17000,
713 	.firewall_base = 0x30000,
714 	.firewall_ctl = 0x8d0,
715 	.firewall_wr_ctl = 0x8c8,
716 };
717 
718 static const struct tegra234_slave_lookup tegra234_bpmp_slave_map[] = {
719 	{ "AXI2APB", 0x00000 },
720 	{ "AST0",    0x15000 },
721 	{ "AST1",    0x16000 },
722 	{ "CBB",     0x17000 },
723 	{ "CPU",     0x18000 },
724 };
725 
726 static const struct tegra234_cbb_fabric tegra234_bpmp_fabric = {
727 	.name = "bpmp-fabric",
728 	.master_id = tegra234_master_id,
729 	.slave_map = tegra234_bpmp_slave_map,
730 	.max_slaves = ARRAY_SIZE(tegra234_bpmp_slave_map),
731 	.errors = tegra234_cbb_errors,
732 	.max_errors = ARRAY_SIZE(tegra234_cbb_errors),
733 	.notifier_offset = 0x19000,
734 	.firewall_base = 0x30000,
735 	.firewall_ctl = 0x8f0,
736 	.firewall_wr_ctl = 0x8e8,
737 };
738 
739 static const struct tegra234_slave_lookup tegra234_cbb_slave_map[] = {
740 	{ "AON",        0x40000 },
741 	{ "BPMP",       0x41000 },
742 	{ "CBB",        0x42000 },
743 	{ "HOST1X",     0x43000 },
744 	{ "STM",        0x44000 },
745 	{ "FSI",        0x45000 },
746 	{ "PSC",        0x46000 },
747 	{ "PCIE_C1",    0x47000 },
748 	{ "PCIE_C2",    0x48000 },
749 	{ "PCIE_C3",    0x49000 },
750 	{ "PCIE_C0",    0x4a000 },
751 	{ "PCIE_C4",    0x4b000 },
752 	{ "GPU",        0x4c000 },
753 	{ "SMMU0",      0x4d000 },
754 	{ "SMMU1",      0x4e000 },
755 	{ "SMMU2",      0x4f000 },
756 	{ "SMMU3",      0x50000 },
757 	{ "SMMU4",      0x51000 },
758 	{ "PCIE_C10",   0x52000 },
759 	{ "PCIE_C7",    0x53000 },
760 	{ "PCIE_C8",    0x54000 },
761 	{ "PCIE_C9",    0x55000 },
762 	{ "PCIE_C5",    0x56000 },
763 	{ "PCIE_C6",    0x57000 },
764 	{ "DCE",        0x58000 },
765 	{ "RCE",        0x59000 },
766 	{ "SCE",        0x5a000 },
767 	{ "AXI2APB_1",  0x70000 },
768 	{ "AXI2APB_10", 0x71000 },
769 	{ "AXI2APB_11", 0x72000 },
770 	{ "AXI2APB_12", 0x73000 },
771 	{ "AXI2APB_13", 0x74000 },
772 	{ "AXI2APB_14", 0x75000 },
773 	{ "AXI2APB_15", 0x76000 },
774 	{ "AXI2APB_16", 0x77000 },
775 	{ "AXI2APB_17", 0x78000 },
776 	{ "AXI2APB_18", 0x79000 },
777 	{ "AXI2APB_19", 0x7a000 },
778 	{ "AXI2APB_2",  0x7b000 },
779 	{ "AXI2APB_20", 0x7c000 },
780 	{ "AXI2APB_21", 0x7d000 },
781 	{ "AXI2APB_22", 0x7e000 },
782 	{ "AXI2APB_23", 0x7f000 },
783 	{ "AXI2APB_25", 0x80000 },
784 	{ "AXI2APB_26", 0x81000 },
785 	{ "AXI2APB_27", 0x82000 },
786 	{ "AXI2APB_28", 0x83000 },
787 	{ "AXI2APB_29", 0x84000 },
788 	{ "AXI2APB_30", 0x85000 },
789 	{ "AXI2APB_31", 0x86000 },
790 	{ "AXI2APB_32", 0x87000 },
791 	{ "AXI2APB_33", 0x88000 },
792 	{ "AXI2APB_34", 0x89000 },
793 	{ "AXI2APB_35", 0x92000 },
794 	{ "AXI2APB_4",  0x8b000 },
795 	{ "AXI2APB_5",  0x8c000 },
796 	{ "AXI2APB_6",  0x8d000 },
797 	{ "AXI2APB_7",  0x8e000 },
798 	{ "AXI2APB_8",  0x8f000 },
799 	{ "AXI2APB_9",  0x90000 },
800 	{ "AXI2APB_3",  0x91000 },
801 };
802 
803 static const struct tegra234_cbb_fabric tegra234_cbb_fabric = {
804 	.name = "cbb-fabric",
805 	.master_id = tegra234_master_id,
806 	.slave_map = tegra234_cbb_slave_map,
807 	.max_slaves = ARRAY_SIZE(tegra234_cbb_slave_map),
808 	.errors = tegra234_cbb_errors,
809 	.max_errors = ARRAY_SIZE(tegra234_cbb_errors),
810 	.notifier_offset = 0x60000,
811 	.off_mask_erd = 0x3a004,
812 	.firewall_base = 0x10000,
813 	.firewall_ctl = 0x23f0,
814 	.firewall_wr_ctl = 0x23e8,
815 };
816 
817 static const struct tegra234_slave_lookup tegra234_common_slave_map[] = {
818 	{ "AXI2APB", 0x00000 },
819 	{ "AST0",    0x15000 },
820 	{ "AST1",    0x16000 },
821 	{ "CBB",     0x17000 },
822 	{ "RSVD",    0x00000 },
823 	{ "CPU",     0x18000 },
824 };
825 
826 static const struct tegra234_cbb_fabric tegra234_dce_fabric = {
827 	.name = "dce-fabric",
828 	.master_id = tegra234_master_id,
829 	.slave_map = tegra234_common_slave_map,
830 	.max_slaves = ARRAY_SIZE(tegra234_common_slave_map),
831 	.errors = tegra234_cbb_errors,
832 	.max_errors = ARRAY_SIZE(tegra234_cbb_errors),
833 	.notifier_offset = 0x19000,
834 	.firewall_base = 0x30000,
835 	.firewall_ctl = 0x290,
836 	.firewall_wr_ctl = 0x288,
837 };
838 
839 static const struct tegra234_cbb_fabric tegra234_rce_fabric = {
840 	.name = "rce-fabric",
841 	.master_id = tegra234_master_id,
842 	.slave_map = tegra234_common_slave_map,
843 	.max_slaves = ARRAY_SIZE(tegra234_common_slave_map),
844 	.errors = tegra234_cbb_errors,
845 	.max_errors = ARRAY_SIZE(tegra234_cbb_errors),
846 	.notifier_offset = 0x19000,
847 	.firewall_base = 0x30000,
848 	.firewall_ctl = 0x290,
849 	.firewall_wr_ctl = 0x288,
850 };
851 
852 static const struct tegra234_cbb_fabric tegra234_sce_fabric = {
853 	.name = "sce-fabric",
854 	.master_id = tegra234_master_id,
855 	.slave_map = tegra234_common_slave_map,
856 	.max_slaves = ARRAY_SIZE(tegra234_common_slave_map),
857 	.errors = tegra234_cbb_errors,
858 	.max_errors = ARRAY_SIZE(tegra234_cbb_errors),
859 	.notifier_offset = 0x19000,
860 	.firewall_base = 0x30000,
861 	.firewall_ctl = 0x290,
862 	.firewall_wr_ctl = 0x288,
863 };
864 
865 static const char * const tegra241_master_id[] = {
866 	[0x0] = "TZ",
867 	[0x1] = "CCPLEX",
868 	[0x2] = "CCPMU",
869 	[0x3] = "BPMP_FW",
870 	[0x4] = "PSC_FW_USER",
871 	[0x5] = "PSC_FW_SUPERVISOR",
872 	[0x6] = "PSC_FW_MACHINE",
873 	[0x7] = "PSC_BOOT",
874 	[0x8] = "BPMP_BOOT",
875 	[0x9] = "JTAGM_DFT",
876 	[0xa] = "CORESIGHT",
877 	[0xb] = "GPU",
878 	[0xc] = "PEATRANS",
879 	[0xd ... 0x3f] = "RSVD"
880 };
881 
882 /*
883  * Possible causes for Slave and Timeout errors.
884  * SLAVE_ERR:
885  * Slave being accessed responded with an error. Slave could return
886  * an error for various cases :
887  *   Unsupported access, clamp setting when power gated, register
888  *   level firewall(SCR), address hole within the slave, etc
889  *
890  * TIMEOUT_ERR:
891  * No response returned by slave. Can be due to slave being clock
892  * gated, under reset, powered down or slave inability to respond
893  * for an internal slave issue
894  */
895 static const struct tegra_cbb_error tegra241_cbb_errors[] = {
896 	{
897 		.code = "SLAVE_ERR",
898 		.desc = "Slave being accessed responded with an error."
899 	}, {
900 		.code = "DECODE_ERR",
901 		.desc = "Attempt to access an address hole or Reserved region of memory."
902 	}, {
903 		.code = "FIREWALL_ERR",
904 		.desc = "Attempt to access a region which is firewalled."
905 	}, {
906 		.code = "TIMEOUT_ERR",
907 		.desc = "No response returned by slave."
908 	}, {
909 		.code = "PWRDOWN_ERR",
910 		.desc = "Attempt to access a portion of the fabric that is powered down."
911 	}, {
912 		.code = "UNSUPPORTED_ERR",
913 		.desc = "Attempt to access a slave through an unsupported access."
914 	}, {
915 		.code = "POISON_ERR",
916 		.desc = "Slave responds with poison error to indicate error in data."
917 	}, {
918 		.code = "RSVD"
919 	}, {
920 		.code = "RSVD"
921 	}, {
922 		.code = "RSVD"
923 	}, {
924 		.code = "RSVD"
925 	}, {
926 		.code = "RSVD"
927 	}, {
928 		.code = "RSVD"
929 	}, {
930 		.code = "RSVD"
931 	}, {
932 		.code = "RSVD"
933 	}, {
934 		.code = "RSVD"
935 	}, {
936 		.code = "NO_SUCH_ADDRESS_ERR",
937 		.desc = "The address belongs to the pri_target range but there is no register "
938 			"implemented at the address."
939 	}, {
940 		.code = "TASK_ERR",
941 		.desc = "Attempt to update a PRI task when the current task has still not "
942 			"completed."
943 	}, {
944 		.code = "EXTERNAL_ERR",
945 		.desc = "Indicates that an external PRI register access met with an error due to "
946 			"any issue in the unit."
947 	}, {
948 		.code = "INDEX_ERR",
949 		.desc = "Applicable to PRI index aperture pair, when the programmed index is "
950 			"outside the range defined in the manual."
951 	}, {
952 		.code = "RESET_ERR",
953 		.desc = "Target in Reset Error: Attempt to access a SubPri or external PRI "
954 			"register but they are in reset."
955 	}, {
956 		.code = "REGISTER_RST_ERR",
957 		.desc = "Attempt to access a PRI register but the register is partial or "
958 			"completely in reset."
959 	}, {
960 		.code = "POWER_GATED_ERR",
961 		.desc = "Returned by external PRI client when the external access goes to a power "
962 			"gated domain."
963 	}, {
964 		.code = "SUBPRI_FS_ERR",
965 		.desc = "Subpri is floorswept: Attempt to access a subpri through the main pri "
966 			"target but subPri logic is floorswept."
967 	}, {
968 		.code = "SUBPRI_CLK_OFF_ERR",
969 		.desc = "Subpri clock is off: Attempt to access a subpri through the main pri "
970 			"target but subPris clock is gated/off."
971 	},
972 };
973 
974 static const struct tegra234_slave_lookup tegra241_cbb_slave_map[] = {
975 	{ "RSVD",       0x00000 },
976 	{ "PCIE_C8",    0x51000 },
977 	{ "PCIE_C9",    0x52000 },
978 	{ "RSVD",       0x00000 },
979 	{ "RSVD",       0x00000 },
980 	{ "RSVD",       0x00000 },
981 	{ "RSVD",       0x00000 },
982 	{ "RSVD",       0x00000 },
983 	{ "RSVD",       0x00000 },
984 	{ "RSVD",       0x00000 },
985 	{ "RSVD",       0x00000 },
986 	{ "AON",        0x5b000 },
987 	{ "BPMP",       0x5c000 },
988 	{ "RSVD",       0x00000 },
989 	{ "RSVD",       0x00000 },
990 	{ "PSC",        0x5d000 },
991 	{ "STM",        0x5e000 },
992 	{ "AXI2APB_1",  0x70000 },
993 	{ "AXI2APB_10", 0x71000 },
994 	{ "AXI2APB_11", 0x72000 },
995 	{ "AXI2APB_12", 0x73000 },
996 	{ "AXI2APB_13", 0x74000 },
997 	{ "AXI2APB_14", 0x75000 },
998 	{ "AXI2APB_15", 0x76000 },
999 	{ "AXI2APB_16", 0x77000 },
1000 	{ "AXI2APB_17", 0x78000 },
1001 	{ "AXI2APB_18", 0x79000 },
1002 	{ "AXI2APB_19", 0x7a000 },
1003 	{ "AXI2APB_2",  0x7b000 },
1004 	{ "AXI2APB_20", 0x7c000 },
1005 	{ "AXI2APB_4",  0x87000 },
1006 	{ "AXI2APB_5",  0x88000 },
1007 	{ "AXI2APB_6",  0x89000 },
1008 	{ "AXI2APB_7",  0x8a000 },
1009 	{ "AXI2APB_8",  0x8b000 },
1010 	{ "AXI2APB_9",  0x8c000 },
1011 	{ "AXI2APB_3",  0x8d000 },
1012 	{ "AXI2APB_21", 0x7d000 },
1013 	{ "AXI2APB_22", 0x7e000 },
1014 	{ "AXI2APB_23", 0x7f000 },
1015 	{ "AXI2APB_24", 0x80000 },
1016 	{ "AXI2APB_25", 0x81000 },
1017 	{ "AXI2APB_26", 0x82000 },
1018 	{ "AXI2APB_27", 0x83000 },
1019 	{ "AXI2APB_28", 0x84000 },
1020 	{ "PCIE_C4",    0x53000 },
1021 	{ "PCIE_C5",    0x54000 },
1022 	{ "PCIE_C6",    0x55000 },
1023 	{ "PCIE_C7",    0x56000 },
1024 	{ "PCIE_C2",    0x57000 },
1025 	{ "PCIE_C3",    0x58000 },
1026 	{ "PCIE_C0",    0x59000 },
1027 	{ "PCIE_C1",    0x5a000 },
1028 	{ "CCPLEX",     0x50000 },
1029 	{ "AXI2APB_29", 0x85000 },
1030 	{ "AXI2APB_30", 0x86000 },
1031 	{ "CBB_CENTRAL", 0x00000 },
1032 	{ "AXI2APB_31", 0x8E000 },
1033 	{ "AXI2APB_32", 0x8F000 },
1034 };
1035 
1036 static const struct tegra234_cbb_fabric tegra241_cbb_fabric = {
1037 	.name = "cbb-fabric",
1038 	.master_id = tegra241_master_id,
1039 	.slave_map = tegra241_cbb_slave_map,
1040 	.max_slaves = ARRAY_SIZE(tegra241_cbb_slave_map),
1041 	.errors = tegra241_cbb_errors,
1042 	.max_errors = ARRAY_SIZE(tegra241_cbb_errors),
1043 	.notifier_offset = 0x60000,
1044 	.off_mask_erd = 0x40004,
1045 	.firewall_base = 0x20000,
1046 	.firewall_ctl = 0x2370,
1047 	.firewall_wr_ctl = 0x2368,
1048 };
1049 
1050 static const struct tegra234_slave_lookup tegra241_bpmp_slave_map[] = {
1051 	{ "RSVD",    0x00000 },
1052 	{ "RSVD",    0x00000 },
1053 	{ "RSVD",    0x00000 },
1054 	{ "CBB",     0x15000 },
1055 	{ "CPU",     0x16000 },
1056 	{ "AXI2APB", 0x00000 },
1057 	{ "DBB0",    0x17000 },
1058 	{ "DBB1",    0x18000 },
1059 };
1060 
1061 static const struct tegra234_cbb_fabric tegra241_bpmp_fabric = {
1062 	.name = "bpmp-fabric",
1063 	.master_id = tegra241_master_id,
1064 	.slave_map = tegra241_bpmp_slave_map,
1065 	.max_slaves = ARRAY_SIZE(tegra241_bpmp_slave_map),
1066 	.errors = tegra241_cbb_errors,
1067 	.max_errors = ARRAY_SIZE(tegra241_cbb_errors),
1068 	.notifier_offset = 0x19000,
1069 	.firewall_base = 0x30000,
1070 	.firewall_ctl = 0x8f0,
1071 	.firewall_wr_ctl = 0x8e8,
1072 };
1073 
1074 static const struct of_device_id tegra234_cbb_dt_ids[] = {
1075 	{ .compatible = "nvidia,tegra234-cbb-fabric", .data = &tegra234_cbb_fabric },
1076 	{ .compatible = "nvidia,tegra234-aon-fabric", .data = &tegra234_aon_fabric },
1077 	{ .compatible = "nvidia,tegra234-bpmp-fabric", .data = &tegra234_bpmp_fabric },
1078 	{ .compatible = "nvidia,tegra234-dce-fabric", .data = &tegra234_dce_fabric },
1079 	{ .compatible = "nvidia,tegra234-rce-fabric", .data = &tegra234_rce_fabric },
1080 	{ .compatible = "nvidia,tegra234-sce-fabric", .data = &tegra234_sce_fabric },
1081 	{ /* sentinel */ },
1082 };
1083 MODULE_DEVICE_TABLE(of, tegra234_cbb_dt_ids);
1084 
1085 struct tegra234_cbb_acpi_uid {
1086 	const char *hid;
1087 	const char *uid;
1088 	const struct tegra234_cbb_fabric *fabric;
1089 };
1090 
1091 static const struct tegra234_cbb_acpi_uid tegra234_cbb_acpi_uids[] = {
1092 	{ "NVDA1070", "1", &tegra241_cbb_fabric },
1093 	{ "NVDA1070", "2", &tegra241_bpmp_fabric },
1094 	{ },
1095 };
1096 
1097 static const struct
1098 tegra234_cbb_fabric *tegra234_cbb_acpi_get_fabric(struct acpi_device *adev)
1099 {
1100 	const struct tegra234_cbb_acpi_uid *entry;
1101 
1102 	for (entry = tegra234_cbb_acpi_uids; entry->hid; entry++) {
1103 		if (acpi_dev_hid_uid_match(adev, entry->hid, entry->uid))
1104 			return entry->fabric;
1105 	}
1106 
1107 	return NULL;
1108 }
1109 
1110 static const struct acpi_device_id tegra241_cbb_acpi_ids[] = {
1111 	{ "NVDA1070" },
1112 	{ },
1113 };
1114 MODULE_DEVICE_TABLE(acpi, tegra241_cbb_acpi_ids);
1115 
1116 static int tegra234_cbb_probe(struct platform_device *pdev)
1117 {
1118 	const struct tegra234_cbb_fabric *fabric;
1119 	struct tegra234_cbb *cbb;
1120 	unsigned long flags = 0;
1121 	int err;
1122 
1123 	if (pdev->dev.of_node) {
1124 		fabric = of_device_get_match_data(&pdev->dev);
1125 	} else {
1126 		struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
1127 		if (!device)
1128 			return -ENODEV;
1129 
1130 		fabric = tegra234_cbb_acpi_get_fabric(device);
1131 		if (!fabric) {
1132 			dev_err(&pdev->dev, "no device match found\n");
1133 			return -ENODEV;
1134 		}
1135 	}
1136 
1137 	cbb = devm_kzalloc(&pdev->dev, sizeof(*cbb), GFP_KERNEL);
1138 	if (!cbb)
1139 		return -ENOMEM;
1140 
1141 	INIT_LIST_HEAD(&cbb->base.node);
1142 	cbb->base.ops = &tegra234_cbb_ops;
1143 	cbb->base.dev = &pdev->dev;
1144 	cbb->fabric = fabric;
1145 
1146 	cbb->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &cbb->res);
1147 	if (IS_ERR(cbb->regs))
1148 		return PTR_ERR(cbb->regs);
1149 
1150 	err = tegra_cbb_get_irq(pdev, NULL, &cbb->sec_irq);
1151 	if (err)
1152 		return err;
1153 
1154 	platform_set_drvdata(pdev, cbb);
1155 
1156 	/*
1157 	 * Don't enable error reporting for a Fabric if write to it's registers
1158 	 * is blocked by CBB firewall.
1159 	 */
1160 	if (!tegra234_cbb_write_access_allowed(pdev, cbb)) {
1161 		dev_info(&pdev->dev, "error reporting not enabled due to firewall\n");
1162 		return 0;
1163 	}
1164 
1165 	spin_lock_irqsave(&cbb_lock, flags);
1166 	list_add(&cbb->base.node, &cbb_list);
1167 	spin_unlock_irqrestore(&cbb_lock, flags);
1168 
1169 	/* set ERD bit to mask SError and generate interrupt to report error */
1170 	if (cbb->fabric->off_mask_erd)
1171 		tegra234_cbb_mask_serror(cbb);
1172 
1173 	return tegra_cbb_register(&cbb->base);
1174 }
1175 
1176 static int __maybe_unused tegra234_cbb_resume_noirq(struct device *dev)
1177 {
1178 	struct tegra234_cbb *cbb = dev_get_drvdata(dev);
1179 
1180 	tegra234_cbb_error_enable(&cbb->base);
1181 
1182 	dev_dbg(dev, "%s resumed\n", cbb->fabric->name);
1183 
1184 	return 0;
1185 }
1186 
1187 static const struct dev_pm_ops tegra234_cbb_pm = {
1188 	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, tegra234_cbb_resume_noirq)
1189 };
1190 
1191 static struct platform_driver tegra234_cbb_driver = {
1192 	.probe = tegra234_cbb_probe,
1193 	.driver = {
1194 		.name = "tegra234-cbb",
1195 		.of_match_table = tegra234_cbb_dt_ids,
1196 		.acpi_match_table = tegra241_cbb_acpi_ids,
1197 		.pm = &tegra234_cbb_pm,
1198 	},
1199 };
1200 
1201 static int __init tegra234_cbb_init(void)
1202 {
1203 	return platform_driver_register(&tegra234_cbb_driver);
1204 }
1205 pure_initcall(tegra234_cbb_init);
1206 
1207 static void __exit tegra234_cbb_exit(void)
1208 {
1209 	platform_driver_unregister(&tegra234_cbb_driver);
1210 }
1211 module_exit(tegra234_cbb_exit);
1212 
1213 MODULE_DESCRIPTION("Control Backbone 2.0 error handling driver for Tegra234");
1214