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